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;