Host GraphicsContext's CTM inside GraphicsContextState
authormmaxfield@apple.com <mmaxfield@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 19 Oct 2015 17:28:41 +0000 (17:28 +0000)
committermmaxfield@apple.com <mmaxfield@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 19 Oct 2015 17:28:41 +0000 (17:28 +0000)
https://bugs.webkit.org/show_bug.cgi?id=150146

Reviewed by Simon Fraser.

There are 6 operations which interact with CTMs:
- Get
- Set
- Concatenate
- Scale
- Rotate
- Translate

This patch modifies all these operations so that these operations shadow the
platform's CTM inside GraphicsContextState. This way, we don't have to consult
with the underlying graphics context in order to know the current CTM.

There are currently many places in the Core Graphics ports where we will change
the platform's CTM out from under the GraphicsContext. This patch migrates
those users to going through GraphicsContext, thereby preserving the integrity
of the shadowed state.

No new tests because there is no behavior change.

* platform/graphics/GraphicsContext.cpp: Setters deletate to platform calls.
The getter can just consult with the shadowed state.
(WebCore::GraphicsContext::concatCTM):
(WebCore::GraphicsContext::scale):
(WebCore::GraphicsContext::rotate):
(WebCore::GraphicsContext::translate):
(WebCore::GraphicsContext::setCTM):
(WebCore::GraphicsContext::getCTM):
(WebCore::GraphicsContext::beginTransparencyLayer):
(WebCore::GraphicsContext::applyDeviceScaleFactor):
* platform/graphics/GraphicsContext.h:
(WebCore::GraphicsContext::scale):
(WebCore::GraphicsContext::checkCTMInvariants): Make sure the shadowed state
matches the platform graphics context's state.
* platform/graphics/cairo/GraphicsContextCairo.cpp: Renaming functions.
(WebCore::GraphicsContext::resetPlatformCTM):
(WebCore::GraphicsContext::getPlatformCTM):
(WebCore::GraphicsContext::translatePlatformCTM):
(WebCore::GraphicsContext::concatPlatformCTM):
(WebCore::GraphicsContext::setPlatformCTM):
(WebCore::GraphicsContext::rotatePlatformCTM):
(WebCore::GraphicsContext::scalePlatformCTM):
(WebCore::GraphicsContext::getCTM): Deleted.
(WebCore::GraphicsContext::translate): Deleted.
(WebCore::GraphicsContext::concatCTM): Deleted.
(WebCore::GraphicsContext::setCTM): Deleted.
(WebCore::GraphicsContext::rotate): Deleted.
(WebCore::GraphicsContext::scale): Deleted.
* platform/graphics/cg/GraphicsContextCG.cpp: Renaming functions. Also,
migrate CTM setters to go through GraphicsContext.
(WebCore::GraphicsContext::resetPlatformCTM):
(WebCore::GraphicsContext::platformInit):
(WebCore::GraphicsContext::drawNativeImage):
(WebCore::drawPatternCallback):
(WebCore::GraphicsContext::drawPattern):
(WebCore::GraphicsContext::fillPath):
(WebCore::GraphicsContext::strokePath):
(WebCore::GraphicsContext::fillRect):
(WebCore::GraphicsContext::strokeRect):
(WebCore::GraphicsContext::scalePlatformCTM):
(WebCore::GraphicsContext::rotatePlatformCTM):
(WebCore::GraphicsContext::translatePlatformCTM):
(WebCore::GraphicsContext::concatPlatformCTM):
(WebCore::GraphicsContext::setPlatformCTM):
(WebCore::GraphicsContext::getPlatformCTM):
(WebCore::GraphicsContext::scale): Deleted.
(WebCore::GraphicsContext::rotate): Deleted.
(WebCore::GraphicsContext::translate): Deleted.
(WebCore::GraphicsContext::concatCTM): Deleted.
(WebCore::GraphicsContext::setCTM): Deleted.
(WebCore::GraphicsContext::getCTM): Deleted.
* platform/graphics/cg/GraphicsContextPlatformPrivateCG.h:
(WebCore::GraphicsContextPlatformPrivate::save):
(WebCore::GraphicsContextPlatformPrivate::restore):
(WebCore::GraphicsContextPlatformPrivate::flush):
(WebCore::GraphicsContextPlatformPrivate::clip):
(WebCore::GraphicsContextPlatformPrivate::scale):
(WebCore::GraphicsContextPlatformPrivate::rotate):
(WebCore::GraphicsContextPlatformPrivate::translate):
(WebCore::GraphicsContextPlatformPrivate::concatCTM):
(WebCore::GraphicsContextPlatformPrivate::setCTM):
* platform/graphics/transforms/AffineTransform.h:
(WebCore::AffineTransform::isEssentiallyEqualTo): Equality comparison on floats
is not a good idea. Instead, this function is more valuable. (However, note that
it is expected for values in a CTM to hold values close to 0, which means that
this function might erroneously return false (similar to operator=()).
* platform/graphics/win/GraphicsContextWin.cpp:
(WebCore::GraphicsContextPlatformPrivate::scale):
(WebCore::GraphicsContextPlatformPrivate::concatPlatformCTM):
(WebCore::GraphicsContextPlatformPrivate::setPlatformCTM):
(WebCore::GraphicsContextPlatformPrivate::concatCTM): Deleted.
(WebCore::GraphicsContextPlatformPrivate::setCTM): Deleted.
* platform/mac/DragImageMac.mm:
(WebCore::drawAtPoint):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@191295 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebCore/ChangeLog
Source/WebCore/platform/graphics/GraphicsContext.cpp
Source/WebCore/platform/graphics/GraphicsContext.h
Source/WebCore/platform/graphics/Image.h
Source/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp
Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp
Source/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h
Source/WebCore/platform/graphics/transforms/AffineTransform.h
Source/WebCore/platform/graphics/win/GraphicsContextWin.cpp
Source/WebCore/platform/mac/DragImageMac.mm
Source/WebCore/platform/spi/cg/CoreGraphicsSPI.h

index 87ef3b0..5f365b2 100644 (file)
@@ -1,3 +1,104 @@
+2015-10-19  Myles C. Maxfield  <mmaxfield@apple.com>
+
+        Host GraphicsContext's CTM inside GraphicsContextState
+        https://bugs.webkit.org/show_bug.cgi?id=150146
+
+        Reviewed by Simon Fraser.
+
+        There are 6 operations which interact with CTMs:
+        - Get
+        - Set
+        - Concatenate
+        - Scale
+        - Rotate
+        - Translate
+
+        This patch modifies all these operations so that these operations shadow the
+        platform's CTM inside GraphicsContextState. This way, we don't have to consult
+        with the underlying graphics context in order to know the current CTM.
+
+        There are currently many places in the Core Graphics ports where we will change
+        the platform's CTM out from under the GraphicsContext. This patch migrates
+        those users to going through GraphicsContext, thereby preserving the integrity
+        of the shadowed state.
+
+        No new tests because there is no behavior change.
+
+        * platform/graphics/GraphicsContext.cpp: Setters deletate to platform calls.
+        The getter can just consult with the shadowed state.
+        (WebCore::GraphicsContext::concatCTM):
+        (WebCore::GraphicsContext::scale):
+        (WebCore::GraphicsContext::rotate):
+        (WebCore::GraphicsContext::translate):
+        (WebCore::GraphicsContext::setCTM):
+        (WebCore::GraphicsContext::getCTM):
+        (WebCore::GraphicsContext::beginTransparencyLayer):
+        (WebCore::GraphicsContext::applyDeviceScaleFactor):
+        * platform/graphics/GraphicsContext.h:
+        (WebCore::GraphicsContext::scale):
+        (WebCore::GraphicsContext::checkCTMInvariants): Make sure the shadowed state
+        matches the platform graphics context's state.
+        * platform/graphics/cairo/GraphicsContextCairo.cpp: Renaming functions.
+        (WebCore::GraphicsContext::resetPlatformCTM):
+        (WebCore::GraphicsContext::getPlatformCTM):
+        (WebCore::GraphicsContext::translatePlatformCTM):
+        (WebCore::GraphicsContext::concatPlatformCTM):
+        (WebCore::GraphicsContext::setPlatformCTM):
+        (WebCore::GraphicsContext::rotatePlatformCTM):
+        (WebCore::GraphicsContext::scalePlatformCTM):
+        (WebCore::GraphicsContext::getCTM): Deleted.
+        (WebCore::GraphicsContext::translate): Deleted.
+        (WebCore::GraphicsContext::concatCTM): Deleted.
+        (WebCore::GraphicsContext::setCTM): Deleted.
+        (WebCore::GraphicsContext::rotate): Deleted.
+        (WebCore::GraphicsContext::scale): Deleted.
+        * platform/graphics/cg/GraphicsContextCG.cpp: Renaming functions. Also,
+        migrate CTM setters to go through GraphicsContext.
+        (WebCore::GraphicsContext::resetPlatformCTM):
+        (WebCore::GraphicsContext::platformInit):
+        (WebCore::GraphicsContext::drawNativeImage):
+        (WebCore::drawPatternCallback):
+        (WebCore::GraphicsContext::drawPattern):
+        (WebCore::GraphicsContext::fillPath):
+        (WebCore::GraphicsContext::strokePath):
+        (WebCore::GraphicsContext::fillRect):
+        (WebCore::GraphicsContext::strokeRect):
+        (WebCore::GraphicsContext::scalePlatformCTM):
+        (WebCore::GraphicsContext::rotatePlatformCTM):
+        (WebCore::GraphicsContext::translatePlatformCTM):
+        (WebCore::GraphicsContext::concatPlatformCTM):
+        (WebCore::GraphicsContext::setPlatformCTM):
+        (WebCore::GraphicsContext::getPlatformCTM):
+        (WebCore::GraphicsContext::scale): Deleted.
+        (WebCore::GraphicsContext::rotate): Deleted.
+        (WebCore::GraphicsContext::translate): Deleted.
+        (WebCore::GraphicsContext::concatCTM): Deleted.
+        (WebCore::GraphicsContext::setCTM): Deleted.
+        (WebCore::GraphicsContext::getCTM): Deleted.
+        * platform/graphics/cg/GraphicsContextPlatformPrivateCG.h:
+        (WebCore::GraphicsContextPlatformPrivate::save):
+        (WebCore::GraphicsContextPlatformPrivate::restore):
+        (WebCore::GraphicsContextPlatformPrivate::flush):
+        (WebCore::GraphicsContextPlatformPrivate::clip):
+        (WebCore::GraphicsContextPlatformPrivate::scale):
+        (WebCore::GraphicsContextPlatformPrivate::rotate):
+        (WebCore::GraphicsContextPlatformPrivate::translate):
+        (WebCore::GraphicsContextPlatformPrivate::concatCTM):
+        (WebCore::GraphicsContextPlatformPrivate::setCTM):
+        * platform/graphics/transforms/AffineTransform.h:
+        (WebCore::AffineTransform::isEssentiallyEqualTo): Equality comparison on floats
+        is not a good idea. Instead, this function is more valuable. (However, note that
+        it is expected for values in a CTM to hold values close to 0, which means that
+        this function might erroneously return false (similar to operator=()).
+        * platform/graphics/win/GraphicsContextWin.cpp:
+        (WebCore::GraphicsContextPlatformPrivate::scale):
+        (WebCore::GraphicsContextPlatformPrivate::concatPlatformCTM):
+        (WebCore::GraphicsContextPlatformPrivate::setPlatformCTM):
+        (WebCore::GraphicsContextPlatformPrivate::concatCTM): Deleted.
+        (WebCore::GraphicsContextPlatformPrivate::setCTM): Deleted.
+        * platform/mac/DragImageMac.mm:
+        (WebCore::drawAtPoint):
+
 2015-10-19  Chris Dumez  <cdumez@apple.com>
 
         Null dereference loading Blink layout test fast/forms/color/input-color-onchange-event.html
index 2b4a2f7..a8e49ba 100644 (file)
@@ -142,6 +142,87 @@ void GraphicsContext::restore()
     restorePlatformState();
 }
 
+void GraphicsContext::concatCTM(const AffineTransform& other)
+{
+    if (paintingDisabled())
+        return;
+
+    checkCTMInvariants();
+
+    m_state.ctm *= other;
+    concatPlatformCTM(other);
+
+    checkCTMInvariants();
+}
+
+void GraphicsContext::scale(float x, float y)
+{
+    if (paintingDisabled())
+        return;
+
+    checkCTMInvariants();
+
+    m_state.ctm.scale(x, y);
+    scalePlatformCTM(x, y);
+
+    checkCTMInvariants();
+}
+
+void GraphicsContext::rotate(float angle)
+{
+    if (paintingDisabled())
+        return;
+
+    checkCTMInvariants();
+
+    m_state.ctm.rotate(rad2deg(angle));
+    rotatePlatformCTM(angle);
+
+    checkCTMInvariants();
+}
+
+void GraphicsContext::translate(float x, float y)
+{
+    if (paintingDisabled())
+        return;
+
+    checkCTMInvariants();
+
+    m_state.ctm.translate(x, y);
+    translatePlatformCTM(x, y);
+
+    checkCTMInvariants();
+}
+
+void GraphicsContext::setCTM(const AffineTransform& other)
+{
+    if (paintingDisabled())
+        return;
+
+    checkCTMInvariants();
+
+    m_state.ctm = other;
+    setPlatformCTM(other);
+
+    checkCTMInvariants();
+}
+
+AffineTransform GraphicsContext::getCTM(IncludeDeviceScale includeScale) const
+{
+    if (paintingDisabled())
+        return AffineTransform();
+
+    AffineTransform result;
+    if (includeScale == DefinitelyIncludeDeviceScale)
+        result = m_state.userToDeviceSpaceCTM * m_state.ctm;
+    else
+        result = m_state.ctm;
+
+    ASSERT(result.isEssentiallyEqualTo(getPlatformCTM(includeScale)));
+
+    return result;
+}
+
 void GraphicsContext::drawRaisedEllipse(const FloatRect& rect, const Color& ellipseColor, ColorSpace ellipseColorSpace, const Color& shadowColor, ColorSpace shadowColorSpace)
 {
     if (paintingDisabled())
@@ -295,6 +376,8 @@ void GraphicsContext::beginTransparencyLayer(float opacity)
 {
     beginPlatformTransparencyLayer(opacity);
     ++m_transparencyCount;
+
+    resetPlatformCTM();
 }
 
 void GraphicsContext::endTransparencyLayer()
@@ -654,7 +737,8 @@ void GraphicsContext::platformApplyDeviceScaleFactor(float)
 
 void GraphicsContext::applyDeviceScaleFactor(float deviceScaleFactor)
 {
-    scale(FloatSize(deviceScaleFactor, deviceScaleFactor));
+    scale(deviceScaleFactor, deviceScaleFactor);
+
     platformApplyDeviceScaleFactor(deviceScaleFactor);
 }
 
index 1a9f995..78afb07 100644 (file)
@@ -156,6 +156,9 @@ struct GraphicsContextState {
     CompositeOperator compositeOperator { CompositeSourceOver };
     BlendMode blendMode { BlendModeNormal };
 
+    AffineTransform userToDeviceSpaceCTM;
+    AffineTransform ctm;
+
     bool shouldAntialias : 1;
     bool shouldSmoothFonts : 1;
     bool antialiasedFontDilationEnabled : 1;
@@ -420,18 +423,25 @@ public:
     void canvasClip(const Path&, WindRule = RULE_EVENODD);
     void clipOut(const Path&);
 
-    WEBCORE_EXPORT void scale(const FloatSize&);
+    WEBCORE_EXPORT void scale(const FloatSize& size) { scale(size.width(), size.height()); }
     void rotate(float angleInRadians);
     void translate(const FloatSize& size) { translate(size.width(), size.height()); }
+    WEBCORE_EXPORT void scale(float x, float y);
     WEBCORE_EXPORT void translate(float x, float y);
 
     void setURLForRect(const URL&, const IntRect&);
 
+    void checkCTMInvariants() const
+    {
+        ASSERT(getCTM(DefinitelyIncludeDeviceScale).isEssentiallyEqualTo(getPlatformCTM(DefinitelyIncludeDeviceScale)));
+        ASSERT(getCTM(PossiblyIncludeDeviceScale).isEssentiallyEqualTo(getPlatformCTM(PossiblyIncludeDeviceScale)));
+    }
     void concatCTM(const AffineTransform&);
     void setCTM(const AffineTransform&);
+    void resetPlatformCTM();
 
     enum IncludeDeviceScale { DefinitelyIncludeDeviceScale, PossiblyIncludeDeviceScale };
-    AffineTransform getCTM(IncludeDeviceScale includeScale = PossiblyIncludeDeviceScale) const;
+    AffineTransform getCTM(IncludeDeviceScale = PossiblyIncludeDeviceScale) const;
 
 #if ENABLE(3D_TRANSFORMS) && USE(TEXTURE_MAPPER)
     // This is needed when using accelerated-compositing in software mode, like in TextureMapper.
@@ -545,6 +555,13 @@ private:
     void setPlatformAlpha(float);
     void setPlatformCompositeOperation(CompositeOperator, BlendMode = BlendModeNormal);
 
+    void concatPlatformCTM(const AffineTransform&);
+    void scalePlatformCTM(float x, float y);
+    void rotatePlatformCTM(float);
+    void translatePlatformCTM(float, float);
+    void setPlatformCTM(const AffineTransform&);
+    AffineTransform getPlatformCTM(IncludeDeviceScale = PossiblyIncludeDeviceScale) const; // This is only computed to ASSERT() that the GraphicsContextState agrees with the underlying platform.
+
     void beginPlatformTransparencyLayer(float opacity);
     void endPlatformTransparencyLayer();
     static bool supportsTransparencyLayers();
index 1db775c..002a09f 100644 (file)
@@ -133,7 +133,7 @@ public:
 
     enum TileRule { StretchTile, RoundTile, SpaceTile, RepeatTile };
 
-    virtual PassNativeImagePtr nativeImageForCurrentFrame() { return 0; }
+    virtual PassNativeImagePtr nativeImageForCurrentFrame() { return nullptr; }
     virtual ImageOrientation orientationForCurrentFrame() { return ImageOrientation(); }
 
     // Accessors for native image formats.
index 93fb30c..ca99e55 100644 (file)
@@ -194,7 +194,15 @@ void GraphicsContext::platformDestroy()
     delete m_data;
 }
 
-AffineTransform GraphicsContext::getCTM(IncludeDeviceScale) const
+void GraphicsContext::resetPlatformCTM()
+{
+    if (platformContext())
+        m_state.ctm = getPlatformCTM();
+    else
+        m_state.ctm.makeIdentity();
+}
+
+AffineTransform GraphicsContext::getPlatformCTM(IncludeDeviceScale) const
 {
     if (paintingDisabled())
         return AffineTransform();
@@ -711,7 +719,7 @@ FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect, RoundingM
     return result;
 }
 
-void GraphicsContext::translate(float x, float y)
+void GraphicsContext::translatePlatformCTM(float x, float y)
 {
     if (paintingDisabled())
         return;
@@ -773,7 +781,7 @@ void GraphicsContext::setURLForRect(const URL&, const IntRect&)
     notImplemented();
 }
 
-void GraphicsContext::concatCTM(const AffineTransform& transform)
+void GraphicsContext::concatPlatformCTM(const AffineTransform& transform)
 {
     if (paintingDisabled())
         return;
@@ -784,7 +792,7 @@ void GraphicsContext::concatCTM(const AffineTransform& transform)
     m_data->concatCTM(transform);
 }
 
-void GraphicsContext::setCTM(const AffineTransform& transform)
+void GraphicsContext::setPlatformCTM(const AffineTransform& transform)
 {
     if (paintingDisabled())
         return;
@@ -1003,7 +1011,7 @@ void GraphicsContext::clipOut(const Path& path)
     cairo_set_fill_rule(cr, savedFillRule);
 }
 
-void GraphicsContext::rotate(float radians)
+void GraphicsContext::rotatePlatformCTM(float radians)
 {
     if (paintingDisabled())
         return;
@@ -1012,13 +1020,13 @@ void GraphicsContext::rotate(float radians)
     m_data->rotate(radians);
 }
 
-void GraphicsContext::scale(const FloatSize& size)
+void GraphicsContext::scalePlatformCTM(float x, float y)
 {
     if (paintingDisabled())
         return;
 
-    cairo_scale(platformContext()->cr(), size.width(), size.height());
-    m_data->scale(size);
+    cairo_scale(platformContext()->cr(), x, y);
+    m_data->scale(FloatSize(x, y));
 }
 
 void GraphicsContext::clipOut(const FloatRect& r)
index 836e96e..7907051 100644 (file)
@@ -104,6 +104,16 @@ CGColorSpaceRef linearRGBColorSpaceRef()
 }
 #endif
 
+void GraphicsContext::resetPlatformCTM()
+{
+    m_state.ctm = CGContextGetCTM(platformContext());
+#if PLATFORM(WIN)
+    m_state.userToDeviceSpaceCTM = static_cast<AffineTransform>(CGContextGetUserSpaceToDeviceSpaceTransform(platformContext())) * m_state.ctm.inverse();
+#else
+    m_state.userToDeviceSpaceCTM = CGContextGetDefaultUserSpaceToDeviceSpaceTransform(platformContext());
+#endif
+}
+
 void GraphicsContext::platformInit(CGContextRef cgContext)
 {
     m_data = new GraphicsContextPlatformPrivate(cgContext);
@@ -113,6 +123,7 @@ void GraphicsContext::platformInit(CGContextRef cgContext)
         setPlatformFillColor(fillColor(), fillColorSpace());
         setPlatformStrokeColor(strokeColor(), strokeColorSpace());
         setPlatformStrokeThickness(strokeThickness());
+        resetPlatformCTM();
     }
 }
 
@@ -154,7 +165,7 @@ void GraphicsContext::drawNativeImage(PassNativeImagePtr imagePtr, const FloatSi
         return;
 
     CGContextRef context = platformContext();
-    CGContextStateSaver stateSaver(context);
+    GraphicsContextStateSaver stateSaver(*this);
 
 #if PLATFORM(IOS)
     // Anti-aliasing is on by default on the iPhone. Need to turn it off when drawing images.
@@ -268,7 +279,7 @@ void GraphicsContext::drawPattern(Image& image, const FloatRect& tileRect, const
         return;
 
     CGContextRef context = platformContext();
-    CGContextStateSaver stateSaver(context);
+    GraphicsContextStateSaver stateSaver(*this);
     CGContextClipToRect(context, destRect);
 
     setPlatformCompositeOperation(op, blendMode);
@@ -670,7 +681,7 @@ void GraphicsContext::fillPath(const Path& path)
             FloatRect rect = path.fastBoundingRect();
             FloatSize layerSize = getCTM().mapSize(rect.size());
 
-            CGLayerRef layer = CGLayerCreateWithContext(context, layerSize, 0);
+            CGLayerRef layer = CGLayerCreateWithContext(context, layerSize, nullptr);
             CGContextRef layerContext = CGLayerGetContext(layer);
 
             CGContextScaleCTM(layerContext, layerSize.width() / rect.width(), layerSize.height() / rect.height());
@@ -1253,52 +1264,52 @@ void GraphicsContext::clipOut(const Path& path)
     CGContextEOClip(platformContext());
 }
 
-void GraphicsContext::scale(const FloatSize& size)
+void GraphicsContext::scalePlatformCTM(float x, float y)
 {
     if (paintingDisabled())
         return;
-    CGContextScaleCTM(platformContext(), size.width(), size.height());
-    m_data->scale(size);
+    CGContextScaleCTM(platformContext(), x, y);
+    m_data->scalePlatformCTM(x, y);
     m_data->m_userToDeviceTransformKnownToBeIdentity = false;
 }
 
-void GraphicsContext::rotate(float angle)
+void GraphicsContext::rotatePlatformCTM(float angle)
 {
     if (paintingDisabled())
         return;
     CGContextRotateCTM(platformContext(), angle);
-    m_data->rotate(angle);
+    m_data->rotatePlatformCTM(angle);
     m_data->m_userToDeviceTransformKnownToBeIdentity = false;
 }
 
-void GraphicsContext::translate(float x, float y)
+void GraphicsContext::translatePlatformCTM(float x, float y)
 {
     if (paintingDisabled())
         return;
     CGContextTranslateCTM(platformContext(), x, y);
-    m_data->translate(x, y);
+    m_data->translatePlatformCTM(x, y);
     m_data->m_userToDeviceTransformKnownToBeIdentity = false;
 }
 
-void GraphicsContext::concatCTM(const AffineTransform& transform)
+void GraphicsContext::concatPlatformCTM(const AffineTransform& transform)
 {
     if (paintingDisabled())
         return;
     CGContextConcatCTM(platformContext(), transform);
-    m_data->concatCTM(transform);
+    m_data->concatPlatformCTM(transform);
     m_data->m_userToDeviceTransformKnownToBeIdentity = false;
 }
 
-void GraphicsContext::setCTM(const AffineTransform& transform)
+void GraphicsContext::setPlatformCTM(const AffineTransform& transform)
 {
     if (paintingDisabled())
         return;
     CGContextSetCTM(platformContext(), transform);
-    m_data->setCTM(transform);
+    m_data->setPlatformCTM(transform);
     m_data->m_userToDeviceTransformKnownToBeIdentity = false;
 }
 
-AffineTransform GraphicsContext::getCTM(IncludeDeviceScale includeScale) const
+AffineTransform GraphicsContext::getPlatformCTM(IncludeDeviceScale includeScale) const
 {
     if (paintingDisabled())
         return AffineTransform();
index 8a5e287..9dab495 100644 (file)
@@ -53,16 +53,16 @@ public:
 
 #if PLATFORM(COCOA)
     // These methods do nothing on Mac.
-    void save() {}
-    void restore() {}
-    void flush() {}
-    void clip(const FloatRect&) {}
-    void clip(const Path&) {}
-    void scale(const FloatSize&) {}
-    void rotate(float) {}
-    void translate(float, float) {}
-    void concatCTM(const AffineTransform&) {}
-    void setCTM(const AffineTransform&) {}
+    void save() { }
+    void restore() { }
+    void flush() { }
+    void clip(const FloatRect&) { }
+    void clip(const Path&) { }
+    void scalePlatformCTM(float, float) { }
+    void rotatePlatformCTM(float) { }
+    void translatePlatformCTM(float, float) { }
+    void concatPlatformCTM(const AffineTransform&) { }
+    void setPlatformCTM(const AffineTransform&) { }
 #endif
 
 #if PLATFORM(WIN)
@@ -72,11 +72,11 @@ public:
     void flush();
     void clip(const FloatRect&);
     void clip(const Path&);
-    void scale(const FloatSize&);
-    void rotate(float);
-    void translate(float, float);
-    void concatCTM(const AffineTransform&);
-    void setCTM(const AffineTransform&);
+    void scalePlatformCTM(float x, float y);
+    void rotatePlatformCTM(float);
+    void translatePlatformCTM(float, float);
+    void concatPlatformCTM(const AffineTransform&);
+    void setPlatformCTM(const AffineTransform&);
 
     HDC m_hdc;
     bool m_shouldIncludeChildWindows;
index fab562d..7bd3169 100644 (file)
@@ -30,6 +30,7 @@
 #include "PlatformExportMacros.h"
 #include <array>
 #include <wtf/FastMalloc.h>
+#include <wtf/MathExtras.h>
 
 #if USE(CG)
 typedef struct CGAffineTransform CGAffineTransform;
@@ -140,6 +141,7 @@ public:
         return (m_transform[1] == 0 && m_transform[2] == 0) || (m_transform[0] == 0 && m_transform[3] == 0);
     }
 
+    // FIXME: If you compare floats for equality, you're gonna have a bad time. We should delete this.
     bool operator== (const AffineTransform& m2) const
     {
         return (m_transform[0] == m2.m_transform[0]
@@ -152,6 +154,21 @@ public:
 
     bool operator!=(const AffineTransform& other) const { return !(*this == other); }
 
+    bool isEssentiallyEqualTo(const AffineTransform& m2, double epsilon = 0.0001) const
+    {
+        // WTF::areEssentiallyEqual() doesn't work well in this case. That function is designed to allow for error
+        // which scales proportionately to the values. However, AffineTransforms are often rotated by pi/2, which
+        // are not exactly representable. This results in AffineTransform components which are close to, but not
+        // exactly equal to, zero. In this case, the error and the value are approximately equal, which leads to
+        // a false negative return.
+        return std::abs(m_transform[0] - m2.m_transform[0]) < epsilon
+            && std::abs(m_transform[1] - m2.m_transform[1]) < epsilon
+            && std::abs(m_transform[2] - m2.m_transform[2]) < epsilon
+            && std::abs(m_transform[3] - m2.m_transform[3]) < epsilon
+            && std::abs(m_transform[4] - m2.m_transform[4]) < epsilon
+            && std::abs(m_transform[5] - m2.m_transform[5]) < epsilon;
+    }
+
     // *this = *this * t (i.e., a multRight)
     AffineTransform& operator*=(const AffineTransform& t)
     {
index 54cba34..35a792a 100644 (file)
@@ -171,24 +171,24 @@ void GraphicsContextPlatformPrivate::clip(const Path&)
     notImplemented();
 }
 
-void GraphicsContextPlatformPrivate::scale(const FloatSize& size)
+void GraphicsContextPlatformPrivate::scalePlatformCTM(float x, float y)
 {
     if (!m_hdc)
         return;
 
-    XFORM xform = TransformationMatrix().scaleNonUniform(size.width(), size.height());
+    XFORM xform = TransformationMatrix().scaleNonUniform(x, y);
     ModifyWorldTransform(m_hdc, &xform, MWT_LEFTMULTIPLY);
 }
 
 static const double deg2rad = 0.017453292519943295769; // pi/180
 
-void GraphicsContextPlatformPrivate::rotate(float degreesAngle)
+void GraphicsContextPlatformPrivate::rotatePlatformCTM(float degreesAngle)
 {
     XFORM xform = TransformationMatrix().rotate(degreesAngle);
     ModifyWorldTransform(m_hdc, &xform, MWT_LEFTMULTIPLY);
 }
 
-void GraphicsContextPlatformPrivate::translate(float x , float y)
+void GraphicsContextPlatformPrivate::translatePlatformCTM(float x , float y)
 {
     if (!m_hdc)
         return;
@@ -197,7 +197,7 @@ void GraphicsContextPlatformPrivate::translate(float x , float y)
     ModifyWorldTransform(m_hdc, &xform, MWT_LEFTMULTIPLY);
 }
 
-void GraphicsContextPlatformPrivate::concatCTM(const AffineTransform& transform)
+void GraphicsContextPlatformPrivate::concatPlatformCTM(const AffineTransform& transform)
 {
     if (!m_hdc)
         return;
@@ -206,7 +206,7 @@ void GraphicsContextPlatformPrivate::concatCTM(const AffineTransform& transform)
     ModifyWorldTransform(m_hdc, &xform, MWT_LEFTMULTIPLY);
 }
 
-void GraphicsContextPlatformPrivate::setCTM(const AffineTransform& transform)
+void GraphicsContextPlatformPrivate::setPlatformCTM(const AffineTransform& transform)
 {
     if (!m_hdc)
         return;
index 5fb052d..3eb9e77 100644 (file)
@@ -216,12 +216,13 @@ static void drawAtPoint(NSString *string, NSPoint point, NSFont *font, NSColor *
         
         NSGraphicsContext *nsContext = [NSGraphicsContext currentContext];
         CGContextRef cgContext = static_cast<CGContextRef>([nsContext graphicsPort]);
-        GraphicsContext graphicsContext(cgContext);    
         
         // Safari doesn't flip the NSGraphicsContext before calling WebKit, yet WebCore requires a flipped graphics context.
         BOOL flipped = [nsContext isFlipped];
         if (!flipped)
             CGContextScaleCTM(cgContext, 1, -1);
+
+        GraphicsContext graphicsContext(cgContext);
             
         FontCascade webCoreFont(FontPlatformData(toCTFont(font), [font pointSize]), Antialiased);
         TextRun run(StringView(buffer.data(), length));
index 9e0397c..f14de0d 100644 (file)
@@ -143,6 +143,8 @@ void CGContextSetCTM(CGContextRef, CGAffineTransform);
 void CGContextSetCompositeOperation(CGContextRef, CGCompositeOperation);
 void CGContextSetShouldAntialiasFonts(CGContextRef, bool shouldAntialiasFonts);
 void CGContextResetClip(CGContextRef);
+CGAffineTransform CGContextGetUserSpaceToDeviceSpaceTransform(CGContextRef);
+CGAffineTransform CGContextGetDefaultUserSpaceToDeviceSpaceTransform(CGContextRef);
 #if PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101100
 void CGContextSetFontDilation(CGContextRef, CGSize);
 void CGContextSetFontRenderingStyle(CGContextRef, CGFontRenderingStyle);