Bug 928123 - Avoid PushGroup during simple FillRect. r=Bas
authorBenoit Girard <b56girard@gmail.com>
Thu, 17 Oct 2013 19:08:20 -0400
changeset 165200 fc7cc3c1dccfb9892e14b5639ccb533aba270156
parent 165199 5861a2de43d355d16b1581466d689667ff29027e
child 165201 a46ff1a56160ed32a98ad1bc55b4d7ff6dd31522
push id3066
push userakeybl@mozilla.com
push dateMon, 09 Dec 2013 19:58:46 +0000
treeherdermozilla-beta@a31a0dce83aa [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersBas
bugs928123
milestone27.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 928123 - Avoid PushGroup during simple FillRect. r=Bas
gfx/2d/DrawTargetCairo.cpp
gfx/2d/DrawTargetCairo.h
--- a/gfx/2d/DrawTargetCairo.cpp
+++ b/gfx/2d/DrawTargetCairo.cpp
@@ -588,31 +588,32 @@ DrawTargetCairo::DrawSurfaceWithShadow(S
 
   cairo_restore(mContext);
 }
 
 void
 DrawTargetCairo::DrawPattern(const Pattern& aPattern,
                              const StrokeOptions& aStrokeOptions,
                              const DrawOptions& aOptions,
-                             DrawPatternType aDrawType)
+                             DrawPatternType aDrawType,
+                             bool aPathBoundsClip)
 {
   if (!PatternIsCompatible(aPattern)) {
     return;
   }
   
   AutoClearDeviceOffset clear(aPattern);
 
   cairo_pattern_t* pat = GfxPatternToCairoPattern(aPattern, aOptions.mAlpha);
   cairo_set_source(mContext, pat);
 
   cairo_set_antialias(mContext, GfxAntialiasToCairoAntialias(aOptions.mAntialiasMode));
 
   if (NeedIntermediateSurface(aPattern, aOptions) ||
-      !IsOperatorBoundByMask(aOptions.mCompositionOp)) {
+      (!IsOperatorBoundByMask(aOptions.mCompositionOp) && !aPathBoundsClip)) {
     cairo_push_group_with_content(mContext, CAIRO_CONTENT_COLOR_ALPHA);
 
     ClearSurfaceForUnboundedSource(aOptions.mCompositionOp);
 
     // Don't want operators to be applied twice
     cairo_set_operator(mContext, CAIRO_OPERATOR_OVER);
 
     if (aDrawType == DRAW_STROKE) {
@@ -647,17 +648,29 @@ DrawTargetCairo::FillRect(const Rect &aR
                           const Pattern &aPattern,
                           const DrawOptions &aOptions)
 {
   AutoPrepareForDrawing prep(this, mContext);
 
   cairo_new_path(mContext);
   cairo_rectangle(mContext, aRect.x, aRect.y, aRect.Width(), aRect.Height());
 
-  DrawPattern(aPattern, StrokeOptions(), aOptions, DRAW_FILL);
+  bool pathBoundsClip = false;
+
+  double cexts[4];
+  cairo_clip_extents(mContext, &cexts[0], &cexts[1], &cexts[2], &cexts[3]);
+  Rect clipRect(cexts[0], cexts[1], cexts[2] - cexts[0], cexts[3] - cexts[1]);
+  double pexts[4];
+  cairo_path_extents(mContext, &pexts[0], &pexts[1], &pexts[2], &pexts[3]);
+  Rect pathRect(pexts[0], pexts[1], pexts[2] - pexts[0], pexts[3] - pexts[1]);
+  if (pathRect.Contains(clipRect)) {
+    pathBoundsClip = true;
+  }
+
+  DrawPattern(aPattern, StrokeOptions(), aOptions, DRAW_FILL, pathBoundsClip);
 }
 
 void
 DrawTargetCairo::CopySurfaceInternal(cairo_surface_t* aSurface,
                                      const IntRect &aSource,
                                      const IntPoint &aDest)
 {
   cairo_identity_matrix(mContext);
--- a/gfx/2d/DrawTargetCairo.h
+++ b/gfx/2d/DrawTargetCairo.h
@@ -156,17 +156,18 @@ public:
 private: // methods
   // Init cairo surface without doing a cairo_surface_reference() call.
   bool InitAlreadyReferenced(cairo_surface_t* aSurface, const IntSize& aSize);
 
   enum DrawPatternType { DRAW_FILL, DRAW_STROKE };
   void DrawPattern(const Pattern& aPattern,
                    const StrokeOptions& aStrokeOptions,
                    const DrawOptions& aOptions,
-                   DrawPatternType aDrawType);
+                   DrawPatternType aDrawType,
+                   bool aPathBoundsClip = false);
 
   void CopySurfaceInternal(cairo_surface_t* aSurface,
                            const IntRect& aSource,
                            const IntPoint& aDest);
 
   // Call before you make any changes to the backing surface with which this
   // context is associated. Pass the path you're going to be using if you have
   // one.