[Cairo] Avoid clipping when painting more often
authormrobinson@webkit.org <mrobinson@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 10 Nov 2011 03:10:09 +0000 (03:10 +0000)
committermrobinson@webkit.org <mrobinson@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 10 Nov 2011 03:10:09 +0000 (03:10 +0000)
https://bugs.webkit.org/show_bug.cgi?id=71179

Reviewed by Xan Lopez.

No new tests. These changes are covered by existing tests.

* platform/graphics/Gradient.h: Add a Cairo-specific method
that gets the platform gradient with a particular alpha value.
* platform/graphics/cairo/GradientCairo.cpp: Now cache the alpha
value of the last created platform gradient.
(WebCore::Gradient::platformGradient): If the cached platform gradient
has a different alpha value than the one requested, destroy it and start
over.
* platform/graphics/cairo/GraphicsContextCairo.cpp:
(WebCore::drawPathShadow): Adjust the source to avoid calling
cairo_clip/cairo_paint_with_alpha and just do a fill.
(WebCore::shadowAndFillCurrentCairoPath): No need to clip here. Just
call cairo_fill.
* platform/graphics/cairo/PlatformContextCairo.cpp:
(WebCore::drawPatternToCairoContext): If we have a >= 1 alpha value
we can simply fill and avoid calling cairo_clip here.
(WebCore::prepareCairoContextSource): Remove TODO about recreating the
gradient. No longer need to reduce the gradient source.

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

Source/WebCore/ChangeLog
Source/WebCore/platform/graphics/Gradient.h
Source/WebCore/platform/graphics/cairo/GradientCairo.cpp
Source/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp
Source/WebCore/platform/graphics/cairo/PlatformContextCairo.cpp

index f3ac791..4749c4a 100755 (executable)
@@ -1,3 +1,30 @@
+2011-11-09  Martin Robinson  <mrobinson@igalia.com>
+
+        [Cairo] Avoid clipping when painting more often
+        https://bugs.webkit.org/show_bug.cgi?id=71179
+
+        Reviewed by Xan Lopez.
+
+        No new tests. These changes are covered by existing tests.
+
+        * platform/graphics/Gradient.h: Add a Cairo-specific method
+        that gets the platform gradient with a particular alpha value.
+        * platform/graphics/cairo/GradientCairo.cpp: Now cache the alpha
+        value of the last created platform gradient.
+        (WebCore::Gradient::platformGradient): If the cached platform gradient
+        has a different alpha value than the one requested, destroy it and start
+        over.
+        * platform/graphics/cairo/GraphicsContextCairo.cpp:
+        (WebCore::drawPathShadow): Adjust the source to avoid calling
+        cairo_clip/cairo_paint_with_alpha and just do a fill.
+        (WebCore::shadowAndFillCurrentCairoPath): No need to clip here. Just
+        call cairo_fill.
+        * platform/graphics/cairo/PlatformContextCairo.cpp:
+        (WebCore::drawPatternToCairoContext): If we have a >= 1 alpha value
+        we can simply fill and avoid calling cairo_clip here.
+        (WebCore::prepareCairoContextSource): Remove TODO about recreating the
+        gradient. No longer need to reduce the gradient source.
+
 2011-11-09  Alexey Proskuryakov  <ap@apple.com>
 
         <rdar://problem/10423024> WebProcess doesn't use AuthBrokerAgent for proxy credentials
index 1ff346d..01e497d 100644 (file)
@@ -138,6 +138,8 @@ namespace WebCore {
 #if USE(CG)
         void paint(CGContextRef);
         void paint(GraphicsContext*);
+#elif USE(CAIRO)
+        PlatformGradient platformGradient(float globalAlpha);
 #endif
 
     private:
@@ -163,6 +165,11 @@ namespace WebCore {
         AffineTransform m_gradientSpaceTransformation;
 
         PlatformGradient m_gradient;
+
+#if USE(CAIRO)
+        float m_platformGradientAlpha;
+#endif
+
     };
 
 } //namespace
index 225046a..f76bb6d 100644 (file)
@@ -44,9 +44,17 @@ void Gradient::platformDestroy()
 
 cairo_pattern_t* Gradient::platformGradient()
 {
-    if (m_gradient)
+    return platformGradient(1);
+}
+
+cairo_pattern_t* Gradient::platformGradient(float globalAlpha)
+{
+    if (m_gradient && m_platformGradientAlpha == globalAlpha)
         return m_gradient;
 
+    platformDestroy();
+    m_platformGradientAlpha = globalAlpha;
+
     if (m_radial)
         m_gradient = cairo_pattern_create_radial(m_p0.x(), m_p0.y(), m_r0, m_p1.x(), m_p1.y(), m_r1);
     else
@@ -54,7 +62,9 @@ cairo_pattern_t* Gradient::platformGradient()
 
     Vector<ColorStop>::iterator stopIterator = m_stops.begin();
     while (stopIterator != m_stops.end()) {
-        cairo_pattern_add_color_stop_rgba(m_gradient, stopIterator->stop, stopIterator->red, stopIterator->green, stopIterator->blue, stopIterator->alpha);
+        cairo_pattern_add_color_stop_rgba(m_gradient, stopIterator->stop,
+                                          stopIterator->red, stopIterator->green, stopIterator->blue,
+                                          stopIterator->alpha * globalAlpha);
         ++stopIterator;
     }
 
index 00429d7..4c3447b 100644 (file)
@@ -134,8 +134,7 @@ static inline void drawPathShadow(GraphicsContext* context, PathDrawingStyle dra
         cairo_save(cairoShadowContext);
         cairo_append_path(cairoShadowContext, path.get());
         shadowContext->platformContext()->prepareForFilling(context->state(), PlatformContextCairo::NoAdjustment);
-        cairo_clip(cairoShadowContext);
-        cairo_paint(cairoShadowContext);
+        cairo_fill(cairoShadowContext);
         cairo_restore(cairoShadowContext);
     }
 
@@ -157,12 +156,11 @@ static inline void shadowAndFillCurrentCairoPath(GraphicsContext* context)
     cairo_t* cr = context->platformContext()->cr();
     cairo_save(cr);
 
-    context->platformContext()->prepareForFilling(context->state(), PlatformContextCairo::NoAdjustment);
-
     drawPathShadow(context, Fill);
 
-    cairo_clip(cr);
-    cairo_paint_with_alpha(cr, context->platformContext()->globalAlpha());
+    context->platformContext()->prepareForFilling(context->state(), PlatformContextCairo::AdjustPatternForGlobalAlpha);
+    cairo_fill(cr);
+
     cairo_restore(cr);
 }
 
index 52dc0f3..f2dd2b9 100644 (file)
@@ -143,8 +143,12 @@ static void drawPatternToCairoContext(cairo_t* cr, cairo_pattern_t* pattern, con
     cairo_translate(cr, destRect.x(), destRect.y());
     cairo_set_source(cr, pattern);
     cairo_rectangle(cr, 0, 0, destRect.width(), destRect.height());
-    cairo_clip(cr);
-    cairo_paint_with_alpha(cr, alpha);
+
+    if (alpha < 1) {
+        cairo_clip(cr);
+        cairo_paint_with_alpha(cr, alpha);
+    } else
+        cairo_fill(cr);
 }
 
 void PlatformContextCairo::drawSurfaceToContext(cairo_surface_t* surface, const FloatRect& destRect, const FloatRect& srcRect, GraphicsContext* context)
@@ -213,13 +217,9 @@ static void prepareCairoContextSource(cairo_t* cr, Pattern* pattern, Gradient* g
         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.
+    } else if (gradient)
+        cairo_set_source(cr, gradient->platformGradient(globalAlpha));
+    else { // Solid color source.
         if (globalAlpha < 1)
             setSourceRGBAFromColor(cr, colorWithOverrideAlpha(color.rgb(), color.alpha() / 255.f * globalAlpha));
         else