Title: [89314] trunk
Revision
89314
Author
[email protected]
Date
2011-06-20 16:51:54 -0700 (Mon, 20 Jun 2011)

Log Message

2011-05-03  Martin Robinson  <[email protected]>

        Reviewed by Dirk Schulze.

        REGRESSION: [CAIRO] wrong drawing of Gradients and Patterns on texts
        https://bugs.webkit.org/show_bug.cgi?id=31507

        Unskip a test which is now passing and update pixel results with correct
        output.

        * platform/gtk/Skipped:
        * platform/gtk/fast/canvas/canvas-text-alignment-expected.png:
        * platform/gtk/svg/W3C-SVG-1.1/pservers-grad-11-b-expected.png:
        * platform/gtk/svg/W3C-SVG-1.1/pservers-pattern-01-b-expected.png:
        * platform/gtk/svg/batik/text/textDecoration-expected.png:
        * platform/gtk/svg/batik/text/textEffect-expected.png:
        * platform/gtk/svg/batik/text/textEffect3-expected.png:
        * platform/gtk/svg/css/composite-shadow-text-expected.png:
        * platform/gtk/svg/css/text-gradient-shadow-expected.png:
        * platform/gtk/svg/custom/js-late-gradient-and-object-creation-expected.png:
        * platform/gtk/svg/custom/js-late-gradient-creation-expected.png:
        * platform/gtk/svg/custom/js-late-pattern-and-object-creation-expected.png:
        * platform/gtk/svg/custom/js-late-pattern-creation-expected.png:
        * platform/gtk/svg/custom/pattern-with-transformation-expected.png:
        * platform/gtk/svg/text/text-align-03-b-expected.png:
        * platform/gtk/svg/transforms/text-with-pattern-with-svg-transform-expected.png:
2011-05-03  Martin Robinson  <[email protected]>

        Reviewed by Dirk Schulze.

        REGRESSION: [CAIRO] wrong drawing of Gradients and Patterns on texts
        https://bugs.webkit.org/show_bug.cgi?id=31507

        When painting text, be sure to set the pattern fill or gradient before modifying the Cairo
        context CTM. This ensures that gradients and patterns are scaled and positioned properly in
        the coordinate system of the page. Abstract out the fill preparation to avoid repeating this
        logic and perform a bit of cleanup.

        * platform/graphics/cairo/FontCairo.cpp:
        (WebCore::prepareContextForGlyphDrawing): Now set the x and y position of the text using the glyph
        offsets. This avoids having to set a transformation matrix when there is no synthetic oblique.
        (WebCore::drawGlyphsToContext): Add a newline as part of cleanup. Call prepareContextForGlyphDrawing from here
        and restor the original CTM when exiting.
        (WebCore::drawGlyphsShadow): Use drawGlyphsToContext here to ensure that all glyph drawing goes through
        the same path.
        (WebCore::Font::drawGlyphs): Fix a C-style cast and use the glyph offsets to position the glyphs instead
        of adjusting the transformation matrix. Use GC::prepareForFilling and GC::prepareForStroking instead of
        setting up the fill and stroke manually.
        * platform/graphics/cairo/GraphicsContextCairo.cpp:
        (WebCore::fillRectWithColor): Renamed fillRectSourceOver to fillRectWithColor to make it clearer
        why this is different than the slower fill method. Moved the no transparency early return here.
        (WebCore::drawPathShadow): Instead of calling setPlatformFill, just perform a cheap fill and stroke
        with red color. Since the shadow is used as a mask, the actual fill shouldn't matter.
        (WebCore::reduceSourceByAlpha): Added this helper.
        (WebCore::GraphicsContext::prepareForFilling): Added this method adapted from setPlatformFill, which
        correctly handles the transformation matrix.
        (WebCore::GraphicsContext::prepareForStroking): Ditto for stroking.
        (WebCore::shadowAndFillCurrentCairoPath): Adapted from fillCurrentCairoPath, but renamed to clarify
        what it does and no uses prepareForFilling.
        (WebCore::shadowAndStrokeCurrentCairoPath): Ditto for stroking.
        (WebCore::GraphicsContext::drawRect): Update for new method names.
        (WebCore::GraphicsContext::drawLine): Ditto.
        (WebCore::GraphicsContext::fillPath): Ditto.
        (WebCore::GraphicsContext::strokePath): Ditto.
        (WebCore::GraphicsContext::fillRect): Ditto. Remove the unnecessary save/restore pair here.
        (WebCore::GraphicsContext::strokeRect): Update to reflect new method names.
        * platform/graphics/cairo/PlatformContextCairo.cpp:
        (WebCore::reduceSourceByAlpha): Added this helper.
        (WebCore::GraphicsContext::prepareForFilling): Added this method adapted from setPlatformFill, which
        correctly handles the transformation matrix.
        (WebCore::GraphicsContext::prepareForStroking): Ditto for stroking.
        (WebCore::reduceSourceByAlpha):
        * platform/graphics/cairo/PlatformContextCairo.h: Added new method declarations.

Modified Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (89313 => 89314)


--- trunk/LayoutTests/ChangeLog	2011-06-20 23:44:19 UTC (rev 89313)
+++ trunk/LayoutTests/ChangeLog	2011-06-20 23:51:54 UTC (rev 89314)
@@ -1,3 +1,30 @@
+2011-05-03  Martin Robinson  <[email protected]>
+
+        Reviewed by Dirk Schulze.
+
+        REGRESSION: [CAIRO] wrong drawing of Gradients and Patterns on texts
+        https://bugs.webkit.org/show_bug.cgi?id=31507
+
+        Unskip a test which is now passing and update pixel results with correct
+        output.
+
+        * platform/gtk/Skipped:
+        * platform/gtk/fast/canvas/canvas-text-alignment-expected.png:
+        * platform/gtk/svg/W3C-SVG-1.1/pservers-grad-11-b-expected.png:
+        * platform/gtk/svg/W3C-SVG-1.1/pservers-pattern-01-b-expected.png:
+        * platform/gtk/svg/batik/text/textDecoration-expected.png:
+        * platform/gtk/svg/batik/text/textEffect-expected.png:
+        * platform/gtk/svg/batik/text/textEffect3-expected.png:
+        * platform/gtk/svg/css/composite-shadow-text-expected.png:
+        * platform/gtk/svg/css/text-gradient-shadow-expected.png:
+        * platform/gtk/svg/custom/js-late-gradient-and-object-creation-expected.png:
+        * platform/gtk/svg/custom/js-late-gradient-creation-expected.png:
+        * platform/gtk/svg/custom/js-late-pattern-and-object-creation-expected.png:
+        * platform/gtk/svg/custom/js-late-pattern-creation-expected.png:
+        * platform/gtk/svg/custom/pattern-with-transformation-expected.png:
+        * platform/gtk/svg/text/text-align-03-b-expected.png:
+        * platform/gtk/svg/transforms/text-with-pattern-with-svg-transform-expected.png:
+
 2011-06-20  Tim Horton  <[email protected]>
 
         Reviewed by Darin Adler.

Modified: trunk/LayoutTests/platform/gtk/Skipped (89313 => 89314)


--- trunk/LayoutTests/platform/gtk/Skipped	2011-06-20 23:44:19 UTC (rev 89313)
+++ trunk/LayoutTests/platform/gtk/Skipped	2011-06-20 23:51:54 UTC (rev 89314)
@@ -1081,8 +1081,6 @@
 # The middle circle on both rectangles is missing in the pixel output.
 svg/custom/circular-marker-reference-2.svg
 svg/custom/non-circular-marker-reference.svg
-# The gradient is missing on the first line of text
-svg/custom/js-late-gradient-and-object-creation.svg
 
 # The following  canvas test cases from http://philip.html5.org/tests/canvas/suite/tests/
 # fail for Mac and can likely be removed from this Skipped list when they are removed from

Modified: trunk/LayoutTests/platform/gtk/fast/canvas/canvas-text-alignment-expected.png


(Binary files differ)

Modified: trunk/LayoutTests/platform/gtk/svg/W3C-SVG-1.1/filters-comptran-01-b-expected.png


(Binary files differ)

Modified: trunk/LayoutTests/platform/gtk/svg/W3C-SVG-1.1/filters-felem-01-b-expected.png


(Binary files differ)

Modified: trunk/LayoutTests/platform/gtk/svg/W3C-SVG-1.1/pservers-grad-08-b-expected.png


(Binary files differ)

Modified: trunk/LayoutTests/platform/gtk/svg/W3C-SVG-1.1/pservers-grad-11-b-expected.png


(Binary files differ)

Modified: trunk/LayoutTests/platform/gtk/svg/W3C-SVG-1.1/pservers-pattern-01-b-expected.png


(Binary files differ)

Modified: trunk/LayoutTests/platform/gtk/svg/W3C-SVG-1.1/struct-image-07-t-expected.png


(Binary files differ)

Modified: trunk/LayoutTests/platform/gtk/svg/W3C-SVG-1.1/text-altglyph-01-b-expected.png


(Binary files differ)

Modified: trunk/LayoutTests/platform/gtk/svg/batik/text/textDecoration-expected.png


(Binary files differ)

Modified: trunk/LayoutTests/platform/gtk/svg/batik/text/textEffect-expected.png


(Binary files differ)

Modified: trunk/LayoutTests/platform/gtk/svg/batik/text/textEffect3-expected.png


(Binary files differ)

Modified: trunk/LayoutTests/platform/gtk/svg/css/composite-shadow-text-expected.png


(Binary files differ)

Modified: trunk/LayoutTests/platform/gtk/svg/css/text-gradient-shadow-expected.png


(Binary files differ)

Modified: trunk/LayoutTests/platform/gtk/svg/custom/js-late-gradient-and-object-creation-expected.png


(Binary files differ)

Modified: trunk/LayoutTests/platform/gtk/svg/custom/js-late-gradient-creation-expected.png


(Binary files differ)

Modified: trunk/LayoutTests/platform/gtk/svg/custom/js-late-pattern-and-object-creation-expected.png


(Binary files differ)

Modified: trunk/LayoutTests/platform/gtk/svg/custom/js-late-pattern-creation-expected.png


(Binary files differ)

Modified: trunk/LayoutTests/platform/gtk/svg/custom/pattern-with-transformation-expected.png


(Binary files differ)

Modified: trunk/LayoutTests/platform/gtk/svg/text/text-align-03-b-expected.png


(Binary files differ)

Modified: trunk/LayoutTests/platform/gtk/svg/transforms/text-with-pattern-with-svg-transform-expected.png


(Binary files differ)

Modified: trunk/Source/WebCore/ChangeLog (89313 => 89314)


--- trunk/Source/WebCore/ChangeLog	2011-06-20 23:44:19 UTC (rev 89313)
+++ trunk/Source/WebCore/ChangeLog	2011-06-20 23:51:54 UTC (rev 89314)
@@ -1,3 +1,51 @@
+2011-05-03  Martin Robinson  <[email protected]>
+
+        Reviewed by Dirk Schulze.
+
+        REGRESSION: [CAIRO] wrong drawing of Gradients and Patterns on texts
+        https://bugs.webkit.org/show_bug.cgi?id=31507
+
+        When painting text, be sure to set the pattern fill or gradient before modifying the Cairo
+        context CTM. This ensures that gradients and patterns are scaled and positioned properly in
+        the coordinate system of the page. Abstract out the fill preparation to avoid repeating this
+        logic and perform a bit of cleanup.
+
+        * platform/graphics/cairo/FontCairo.cpp:
+        (WebCore::prepareContextForGlyphDrawing): Now set the x and y position of the text using the glyph
+        offsets. This avoids having to set a transformation matrix when there is no synthetic oblique.
+        (WebCore::drawGlyphsToContext): Add a newline as part of cleanup. Call prepareContextForGlyphDrawing from here
+        and restor the original CTM when exiting.
+        (WebCore::drawGlyphsShadow): Use drawGlyphsToContext here to ensure that all glyph drawing goes through
+        the same path.
+        (WebCore::Font::drawGlyphs): Fix a C-style cast and use the glyph offsets to position the glyphs instead
+        of adjusting the transformation matrix. Use GC::prepareForFilling and GC::prepareForStroking instead of
+        setting up the fill and stroke manually.
+        * platform/graphics/cairo/GraphicsContextCairo.cpp:
+        (WebCore::fillRectWithColor): Renamed fillRectSourceOver to fillRectWithColor to make it clearer
+        why this is different than the slower fill method. Moved the no transparency early return here.
+        (WebCore::drawPathShadow): Instead of calling setPlatformFill, just perform a cheap fill and stroke
+        with red color. Since the shadow is used as a mask, the actual fill shouldn't matter.
+        (WebCore::reduceSourceByAlpha): Added this helper.
+        (WebCore::GraphicsContext::prepareForFilling): Added this method adapted from setPlatformFill, which
+        correctly handles the transformation matrix.
+        (WebCore::GraphicsContext::prepareForStroking): Ditto for stroking.
+        (WebCore::shadowAndFillCurrentCairoPath): Adapted from fillCurrentCairoPath, but renamed to clarify
+        what it does and no uses prepareForFilling.
+        (WebCore::shadowAndStrokeCurrentCairoPath): Ditto for stroking.
+        (WebCore::GraphicsContext::drawRect): Update for new method names.
+        (WebCore::GraphicsContext::drawLine): Ditto.
+        (WebCore::GraphicsContext::fillPath): Ditto.
+        (WebCore::GraphicsContext::strokePath): Ditto.
+        (WebCore::GraphicsContext::fillRect): Ditto. Remove the unnecessary save/restore pair here.
+        (WebCore::GraphicsContext::strokeRect): Update to reflect new method names.
+        * platform/graphics/cairo/PlatformContextCairo.cpp:
+        (WebCore::reduceSourceByAlpha): Added this helper.
+        (WebCore::GraphicsContext::prepareForFilling): Added this method adapted from setPlatformFill, which
+        correctly handles the transformation matrix.
+        (WebCore::GraphicsContext::prepareForStroking): Ditto for stroking.
+        (WebCore::reduceSourceByAlpha):
+        * platform/graphics/cairo/PlatformContextCairo.h: Added new method declarations.
+
 2011-06-20  Tim Horton  <[email protected]>
 
         Reviewed by Darin Adler.

Modified: trunk/Source/WebCore/platform/graphics/cairo/FontCairo.cpp (89313 => 89314)


--- trunk/Source/WebCore/platform/graphics/cairo/FontCairo.cpp	2011-06-20 23:44:19 UTC (rev 89313)
+++ trunk/Source/WebCore/platform/graphics/cairo/FontCairo.cpp	2011-06-20 23:51:54 UTC (rev 89314)
@@ -43,26 +43,35 @@
 
 namespace WebCore {
 
-static void prepareContextForGlyphDrawing(cairo_t* context, const SimpleFontData* font, const FloatPoint& point)
+static const float gSyntheticObliqueSkew = -tanf(14 * acosf(0) / 90);
+
+static void prepareContextForGlyphDrawing(cairo_t* context, const SimpleFontData* font)
 {
-    static const float syntheticObliqueSkew = -tanf(14 * acosf(0) / 90);
     cairo_set_scaled_font(context, font->platformData().scaledFont());
+
     if (font->platformData().syntheticOblique()) {
-        cairo_matrix_t mat = {1, 0, syntheticObliqueSkew, 1, point.x(), point.y()};
+        cairo_matrix_t mat = {1, 0, gSyntheticObliqueSkew, 1, 0, 0};
         cairo_transform(context, &mat);
-    } else
-        cairo_translate(context, point.x(), point.y());
+    }
 }
 
 static void drawGlyphsToContext(cairo_t* context, const SimpleFontData* font, GlyphBufferGlyph* glyphs, int numGlyphs)
 {
+    cairo_matrix_t originalTransform;
+    float syntheticBoldOffset = font->syntheticBoldOffset();
+    if (font->platformData().syntheticOblique() || syntheticBoldOffset)
+        cairo_get_matrix(context, &originalTransform);
+
+    prepareContextForGlyphDrawing(context, font);
     cairo_show_glyphs(context, glyphs, numGlyphs);
-    if (font->syntheticBoldOffset()) {
-        // We could use cairo_save/cairo_restore here, but two translations are likely faster.
-        cairo_translate(context, font->syntheticBoldOffset(), 0);
+
+    if (syntheticBoldOffset) {
+        cairo_translate(context, syntheticBoldOffset, 0);
         cairo_show_glyphs(context, glyphs, numGlyphs);
-        cairo_translate(context, -font->syntheticBoldOffset(), 0);
     }
+
+    if (font->platformData().syntheticOblique() || syntheticBoldOffset)
+        cairo_set_matrix(context, &originalTransform);
 }
 
 static void drawGlyphsShadow(GraphicsContext* graphicsContext, const FloatPoint& point, const SimpleFontData* font, GlyphBufferGlyph* glyphs, int numGlyphs)
@@ -79,8 +88,7 @@
         cairo_save(context);
         cairo_translate(context, shadow->m_offset.width(), shadow->m_offset.height());
         setSourceRGBAFromColor(context, shadow->m_color);
-        prepareContextForGlyphDrawing(context, font, point);
-        cairo_show_glyphs(context, glyphs, numGlyphs);
+        drawGlyphsToContext(context, font, glyphs, numGlyphs);
         cairo_restore(context);
         return;
     }
@@ -90,7 +98,6 @@
     FloatRect fontExtentsRect(point.x(), point.y() - extents.height, extents.width, extents.height);
     cairo_t* shadowContext = shadow->beginShadowLayer(graphicsContext, fontExtentsRect);
     if (shadowContext) {
-        prepareContextForGlyphDrawing(shadowContext, font, point);
         drawGlyphsToContext(shadowContext, font, glyphs, numGlyphs);
         shadow->endShadowLayer(graphicsContext);
     }
@@ -104,10 +111,10 @@
 
     GlyphBufferGlyph* glyphs = const_cast<GlyphBufferGlyph*>(glyphBuffer.glyphs(from));
 
-    float offset = 0.0f;
+    float offset = point.x();
     for (int i = 0; i < numGlyphs; i++) {
         glyphs[i].x = offset;
-        glyphs[i].y = 0.0f;
+        glyphs[i].y = point.y();
         offset += glyphBuffer.advanceAt(from + i);
     }
 
@@ -117,32 +124,8 @@
     cairo_t* cr = platformContext->cr();
     cairo_save(cr);
 
-    float globalAlpha = platformContext->globalAlpha();
-
-    prepareContextForGlyphDrawing(cr, font, point);
     if (context->textDrawingMode() & TextModeFill) {
-        if (context->fillGradient()) {
-            cairo_set_source(cr, context->fillGradient()->platformGradient());
-            if (globalAlpha < 1) {
-                cairo_push_group(cr);
-                cairo_paint_with_alpha(cr, globalAlpha);
-                cairo_pop_group_to_source(cr);
-            }
-        } else if (context->fillPattern()) {
-            AffineTransform affine;
-            cairo_pattern_t* pattern = context->fillPattern()->createPlatformPattern(affine);
-            cairo_set_source(cr, pattern);
-            if (globalAlpha < 1) {
-                cairo_push_group(cr);
-                cairo_paint_with_alpha(cr, globalAlpha);
-                cairo_pop_group_to_source(cr);
-            }
-            cairo_pattern_destroy(pattern);
-        } else {
-            float red, green, blue, alpha;
-            context->fillColor().getRGBA(red, green, blue, alpha);
-            cairo_set_source_rgba(cr, red, green, blue, alpha * globalAlpha);
-        }
+        platformContext->prepareForFilling(context->state(), PlatformContextCairo::AdjustPatternForGlobalAlpha);
         drawGlyphsToContext(cr, font, glyphs, numGlyphs);
     }
 
@@ -151,30 +134,12 @@
     // the text as even one single stroke would cover the full wdth of the text.
     //  See https://bugs.webkit.org/show_bug.cgi?id=33759.
     if (context->textDrawingMode() & TextModeStroke && context->strokeThickness() < 2 * offset) {
-        if (context->strokeGradient()) {
-            cairo_set_source(cr, context->strokeGradient()->platformGradient());
-            if (globalAlpha < 1) {
-                cairo_push_group(cr);
-                cairo_paint_with_alpha(cr, globalAlpha);
-                cairo_pop_group_to_source(cr);
-            }
-        } else if (context->strokePattern()) {
-            AffineTransform affine;
-            cairo_pattern_t* pattern = context->strokePattern()->createPlatformPattern(affine);
-            cairo_set_source(cr, pattern);
-            if (globalAlpha < 1) {
-                cairo_push_group(cr);
-                cairo_paint_with_alpha(cr, globalAlpha);
-                cairo_pop_group_to_source(cr);
-            }
-            cairo_pattern_destroy(pattern);
-        } else {
-            float red, green, blue, alpha;
-            context->strokeColor().getRGBA(red, green, blue, alpha);
-            cairo_set_source_rgba(cr, red, green, blue, alpha * globalAlpha);
-        }
-        cairo_glyph_path(cr, glyphs, numGlyphs);
+        platformContext->prepareForStroking(context->state());
         cairo_set_line_width(cr, context->strokeThickness());
+
+        // This may disturb the CTM, but we are going to call cairo_restore soon after.
+        prepareContextForGlyphDrawing(cr, font);
+        cairo_glyph_path(cr, glyphs, numGlyphs);
         cairo_stroke(cr);
     }
 

Modified: trunk/Source/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp (89313 => 89314)


--- trunk/Source/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp	2011-06-20 23:44:19 UTC (rev 89313)
+++ trunk/Source/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp	2011-06-20 23:51:54 UTC (rev 89314)
@@ -70,59 +70,12 @@
 
 namespace WebCore {
 
-static inline void setPlatformFill(GraphicsContext* context, cairo_t* cr)
+// A helper which quickly fills a rectangle with a simple color fill.
+static inline void fillRectWithColor(cairo_t* cr, const FloatRect& rect, const Color& color)
 {
-    cairo_pattern_t* pattern = 0;
-    cairo_save(cr);
-    
-    const GraphicsContextState& state = context->state();
-    if (state.fillPattern) {
-        AffineTransform affine;
-        pattern = state.fillPattern->createPlatformPattern(affine);
-        cairo_set_source(cr, pattern);
-    } else if (state.fillGradient)
-        cairo_set_source(cr, state.fillGradient->platformGradient());
-    else
-        setSourceRGBAFromColor(cr, context->fillColor());
-    cairo_clip_preserve(cr);
-    cairo_paint_with_alpha(cr, context->platformContext()->globalAlpha());
-    cairo_restore(cr);
-    if (pattern)
-        cairo_pattern_destroy(pattern);
-}
-
-static inline void setPlatformStroke(GraphicsContext* context, cairo_t* cr)
-{
-    float globalAlpha = context->platformContext()->globalAlpha();
-    cairo_pattern_t* pattern = 0;
-    cairo_save(cr);
-    
-    const GraphicsContextState& state = context->state();
-    if (state.strokePattern) {
-        AffineTransform affine;
-        pattern = state.strokePattern->createPlatformPattern(affine);
-        cairo_set_source(cr, pattern);
-    } else if (state.strokeGradient)
-        cairo_set_source(cr, state.strokeGradient->platformGradient());
-    else  {
-        Color strokeColor = colorWithOverrideAlpha(context->strokeColor().rgb(), context->strokeColor().alpha() / 255.f * globalAlpha);
-        setSourceRGBAFromColor(cr, strokeColor);
-    }
-    if (globalAlpha < 1.0f && (state.strokePattern || state.strokeGradient)) {
-        cairo_push_group(cr);
-        cairo_paint_with_alpha(cr, globalAlpha);
-        cairo_pop_group_to_source(cr);
-    }
-    cairo_stroke_preserve(cr);
-    cairo_restore(cr);
-    if (pattern)
-        cairo_pattern_destroy(pattern);
-}
-
-// A fillRect helper
-static inline void fillRectSourceOver(cairo_t* cr, const FloatRect& rect, const Color& col)
-{
-    setSourceRGBAFromColor(cr, col);
+    if (!color.alpha())
+        return;
+    setSourceRGBAFromColor(cr, color);
     cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height());
     cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
     cairo_fill(cr);
@@ -175,30 +128,37 @@
     // It's important to copy the context properties to the new shadow
     // context to preserve things such as the fill rule and stroke width.
     copyContextProperties(cairoContext, shadowContext);
+
     cairo_append_path(shadowContext, path.get());
 
+    // The color of the shadow doesn't matter, since it's simply used as a mask.
+    cairo_set_source_rgb(shadowContext, 1, 0, 0);
     if (drawingStyle & Fill)
-        setPlatformFill(context, shadowContext);
+        cairo_fill_preserve(shadowContext);
     if (drawingStyle & Stroke)
-        setPlatformStroke(context, shadowContext);
-
+        cairo_stroke_preserve(shadowContext);
     shadow->endShadowLayer(context);
 }
 
-static void fillCurrentCairoPath(GraphicsContext* context, cairo_t* cairoContext)
+static inline void shadowAndFillCurrentCairoPath(GraphicsContext* context)
 {
-    cairo_set_fill_rule(cairoContext, context->fillRule() == RULE_EVENODD ? CAIRO_FILL_RULE_EVEN_ODD : CAIRO_FILL_RULE_WINDING);
+    cairo_t* cr = context->platformContext()->cr();
+    cairo_save(cr);
+
+    context->platformContext()->prepareForFilling(context->state(), PlatformContextCairo::NoAdjustment);
+
     drawPathShadow(context, Fill);
 
-    setPlatformFill(context, cairoContext);
-    cairo_new_path(cairoContext);
+    cairo_clip(cr);
+    cairo_paint_with_alpha(cr, context->platformContext()->globalAlpha());
+    cairo_restore(cr);
 }
 
-static void strokeCurrentCairoPath(GraphicsContext* context,  cairo_t* cairoContext)
+static inline void shadowAndStrokeCurrentCairoPath(GraphicsContext* context)
 {
     drawPathShadow(context, Stroke);
-    setPlatformStroke(context, cairoContext);
-    cairo_new_path(cairoContext);
+    context->platformContext()->prepareForStroking(context->state());
+    cairo_stroke(context->platformContext()->cr());
 }
 
 GraphicsContext::GraphicsContext(cairo_t* cr)
@@ -263,8 +223,7 @@
     cairo_t* cr = platformContext()->cr();
     cairo_save(cr);
 
-    if (fillColor().alpha())
-        fillRectSourceOver(cr, rect, fillColor());
+    fillRectWithColor(cr, rect, fillColor());
 
     if (strokeStyle() != NoStroke) {
         setSourceRGBAFromColor(cr, strokeColor());
@@ -340,8 +299,8 @@
             firstRect.move(-strokeThickness, -strokeThickness / 2);
             secondRect.move(0, -strokeThickness / 2);
         }
-        fillRectSourceOver(context, firstRect, strokeColor);
-        fillRectSourceOver(context, secondRect, strokeColor);
+        fillRectWithColor(context, firstRect, strokeColor);
+        fillRectWithColor(context, secondRect, strokeColor);
 
         int distance = (isVerticalLine ? (point2.y() - point1.y()) : (point2.x() - point1.x())) - 2 * strokeThickness;
         double patternOffset = calculateStrokePatternOffset(distance, patternWidth);
@@ -513,7 +472,7 @@
 
     cairo_t* cr = platformContext()->cr();
     setPathOnCairoContext(cr, path.platformPath()->context());
-    fillCurrentCairoPath(this, cr);
+    shadowAndFillCurrentCairoPath(this);
 }
 
 void GraphicsContext::strokePath(const Path& path)
@@ -523,7 +482,7 @@
 
     cairo_t* cr = platformContext()->cr();
     setPathOnCairoContext(cr, path.platformPath()->context());
-    strokeCurrentCairoPath(this, cr);
+    shadowAndStrokeCurrentCairoPath(this);
 }
 
 void GraphicsContext::fillRect(const FloatRect& rect)
@@ -532,10 +491,8 @@
         return;
 
     cairo_t* cr = platformContext()->cr();
-    cairo_save(cr);
     cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height());
-    fillCurrentCairoPath(this, cr);
-    cairo_restore(cr);
+    shadowAndFillCurrentCairoPath(this);
 }
 
 void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace)
@@ -546,8 +503,7 @@
     if (hasShadow())
         m_data->shadow.drawRectShadow(this, enclosingIntRect(rect));
 
-    if (color.alpha())
-        fillRectSourceOver(platformContext()->cr(), rect, color);
+    fillRectWithColor(platformContext()->cr(), rect, color);
 }
 
 void GraphicsContext::clip(const FloatRect& rect)
@@ -952,7 +908,7 @@
     cairo_save(cr);
     cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height());
     cairo_set_line_width(cr, width);
-    strokeCurrentCairoPath(this, cr);
+    shadowAndStrokeCurrentCairoPath(this);
     cairo_restore(cr);
 }
 

Modified: trunk/Source/WebCore/platform/graphics/cairo/PlatformContextCairo.cpp (89313 => 89314)


--- trunk/Source/WebCore/platform/graphics/cairo/PlatformContextCairo.cpp	2011-06-20 23:44:19 UTC (rev 89313)
+++ trunk/Source/WebCore/platform/graphics/cairo/PlatformContextCairo.cpp	2011-06-20 23:51:54 UTC (rev 89314)
@@ -28,6 +28,10 @@
 #include "PlatformContextCairo.h"
 
 #include "GraphicsContext.h"
+#include "CairoUtilities.h"
+#include "Gradient.h"
+#include "GraphicsContext.h"
+#include "Pattern.h"
 #include <cairo.h>
 
 namespace WebCore {
@@ -193,4 +197,53 @@
     m_state->m_globalAlpha = globalAlpha;
 }
 
+static inline void reduceSourceByAlpha(cairo_t* cr, float alpha)
+{
+    if (alpha >= 1)
+        return;
+    cairo_push_group(cr);
+    cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
+    cairo_paint_with_alpha(cr, alpha);
+    cairo_pop_group_to_source(cr);
+}
+
+static void prepareCairoContextSource(cairo_t* cr, Pattern* pattern, Gradient* gradient, const Color& color, float globalAlpha)
+{
+    if (pattern) {
+        RefPtr<cairo_pattern_t> cairoPattern(adoptRef(pattern->createPlatformPattern(AffineTransform())));
+        cairo_set_source(cr, cairoPattern.get());
+        reduceSourceByAlpha(cr, globalAlpha);
+    } else if (gradient) {
+        cairo_set_source(cr, gradient->platformGradient());
+
+        // FIXME: It would be faster to simply recreate the Cairo gradient and multiply the
+        // color stops by the global alpha.
+        reduceSourceByAlpha(cr, globalAlpha);
+    } else { // Solid color source.
+        if (globalAlpha < 1)
+            setSourceRGBAFromColor(cr, colorWithOverrideAlpha(color.rgb(), color.alpha() / 255.f * globalAlpha));
+        else
+            setSourceRGBAFromColor(cr, color);
+    }
+}
+
+void PlatformContextCairo::prepareForFilling(const GraphicsContextState& state, PatternAdjustment patternAdjustment)
+{
+    cairo_set_fill_rule(m_cr.get(), state.fillRule == RULE_EVENODD ?  CAIRO_FILL_RULE_EVEN_ODD : CAIRO_FILL_RULE_WINDING);
+    prepareCairoContextSource(m_cr.get(),
+                              state.fillPattern.get(),
+                              state.fillGradient.get(),
+                              state.fillColor,
+                              patternAdjustment == AdjustPatternForGlobalAlpha ? globalAlpha() : 1);
+}
+
+void PlatformContextCairo::prepareForStroking(const GraphicsContextState& state)
+{
+    prepareCairoContextSource(m_cr.get(),
+                              state.strokePattern.get(),
+                              state.strokeGradient.get(),
+                              state.strokeColor,
+                              globalAlpha());
+}
+
 } // namespace WebCore

Modified: trunk/Source/WebCore/platform/graphics/cairo/PlatformContextCairo.h (89313 => 89314)


--- trunk/Source/WebCore/platform/graphics/cairo/PlatformContextCairo.h	2011-06-20 23:44:19 UTC (rev 89313)
+++ trunk/Source/WebCore/platform/graphics/cairo/PlatformContextCairo.h	2011-06-20 23:51:54 UTC (rev 89314)
@@ -32,6 +32,8 @@
 
 namespace WebCore {
 
+class GraphicsContextState;
+
 // Much like PlatformContextSkia in the Skia port, this class holds information that
 // would normally be private to GraphicsContext, except that we want to allow access
 // to it in Font and Image code. This allows us to separate the concerns of Cairo-specific
@@ -57,6 +59,10 @@
     void setImageInterpolationQuality(InterpolationQuality quality) { m_imageInterpolationQuality = quality; }
     InterpolationQuality imageInterpolationQuality() const { return m_imageInterpolationQuality; }
 
+    enum PatternAdjustment { NoAdjustment, AdjustPatternForGlobalAlpha };
+    void prepareForFilling(const GraphicsContextState&, PatternAdjustment);
+    void prepareForStroking(const GraphicsContextState&);
+
 private:
     RefPtr<cairo_t> m_cr;
 
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to