Bug 772726. Part 3: Optimize DrawTargetD2D::GetClippedGeometry for the case where all clips are rectangles, to work around a D2D geometry-intersection bug. r=bas
☠☠ backed out by 3bead0b0dd75 ☠ ☠
authorRobert O'Callahan <robert@ocallahan.org>
Fri, 10 Aug 2012 23:18:36 +1200
changeset 104040 5d77941eba281fe5ced799d78e5f65367227f133
parent 104039 df597d36bcbb0766b9a03553330b99bb5e5af5ea
child 104041 3d93599ccd6b0fe40e26f545027bd9ccc6c3840f
push id37
push usershu@rfrn.org
push dateThu, 16 Aug 2012 01:15:22 +0000
reviewersbas
bugs772726
milestone17.0a1
Bug 772726. Part 3: Optimize DrawTargetD2D::GetClippedGeometry for the case where all clips are rectangles, to work around a D2D geometry-intersection bug. r=bas
gfx/2d/DrawTargetD2D.cpp
gfx/2d/DrawTargetD2D.h
--- a/gfx/2d/DrawTargetD2D.cpp
+++ b/gfx/2d/DrawTargetD2D.cpp
@@ -1574,62 +1574,93 @@ DrawTargetD2D::FinalizeRTForOperation(Co
   }
 
   mDevice->OMSetBlendState(GetBlendStateForOperator(aOperator), NULL, 0xffffffff);
   
   mDevice->Draw(4, 0);
 }
 
 TemporaryRef<ID2D1Geometry>
+DrawTargetD2D::ConvertRectToGeometry(const D2D1_RECT_F& aRect)
+{
+  RefPtr<ID2D1RectangleGeometry> rectGeom;
+  factory()->CreateRectangleGeometry(&aRect, byRef(rectGeom));
+  return rectGeom.forget();
+}
+
+static D2D1_RECT_F
+IntersectRect(const D2D1_RECT_F& aRect1, const D2D1_RECT_F& aRect2)
+{
+  D2D1_RECT_F result;
+  result.left = max(aRect1.left, aRect2.left);
+  result.top = max(aRect1.top, aRect2.top);
+  result.right = min(aRect1.right, aRect2.right);
+  result.bottom = min(aRect1.bottom, aRect2.bottom);
+  return result;
+}
+
+TemporaryRef<ID2D1Geometry>
 DrawTargetD2D::GetClippedGeometry()
 {
   if (mCurrentClippedGeometry) {
     return mCurrentClippedGeometry;
   }
 
-  RefPtr<ID2D1GeometrySink> currentSink;
-
-  factory()->CreatePathGeometry(byRef(mCurrentClippedGeometry));
-  mCurrentClippedGeometry->Open(byRef(currentSink));
-      
+  // if pathGeom is null then pathRect represents the path.
+  RefPtr<ID2D1Geometry> pathGeom;
+  D2D1_RECT_F pathRect;
   std::vector<DrawTargetD2D::PushedClip>::iterator iter = mPushedClips.begin();
-
   if (iter->mPath) {
+    RefPtr<ID2D1PathGeometry> tmpGeometry;
+    factory()->CreatePathGeometry(byRef(tmpGeometry));
+    RefPtr<ID2D1GeometrySink> currentSink;
+    tmpGeometry->Open(byRef(currentSink));
     iter->mPath->GetGeometry()->Simplify(D2D1_GEOMETRY_SIMPLIFICATION_OPTION_CUBICS_AND_LINES,
                                          iter->mTransform, currentSink);
+    currentSink->Close();
+    pathGeom = tmpGeometry.forget();
   } else {
-    RefPtr<ID2D1RectangleGeometry> rectGeom;
-    factory()->CreateRectangleGeometry(iter->mBounds, byRef(rectGeom));
-    rectGeom->Simplify(D2D1_GEOMETRY_SIMPLIFICATION_OPTION_CUBICS_AND_LINES,
-                       D2D1::IdentityMatrix(), currentSink);
+    pathRect = iter->mBounds;
   }
-  currentSink->Close();
 
   iter++;
   for (;iter != mPushedClips.end(); iter++) {
+    if (!pathGeom) {
+      if (iter->mPath) {
+        pathGeom = ConvertRectToGeometry(pathRect);
+      } else {
+        pathRect = IntersectRect(pathRect, iter->mBounds);
+        continue;
+      }
+    }
+
     RefPtr<ID2D1PathGeometry> newGeom;
     factory()->CreatePathGeometry(byRef(newGeom));
 
+    RefPtr<ID2D1GeometrySink> currentSink;
     newGeom->Open(byRef(currentSink));
 
     if (iter->mPath) {
-      mCurrentClippedGeometry->CombineWithGeometry(iter->mPath->GetGeometry(), D2D1_COMBINE_MODE_INTERSECT,
-                                           iter->mTransform, currentSink);
+      pathGeom->CombineWithGeometry(iter->mPath->GetGeometry(), D2D1_COMBINE_MODE_INTERSECT,
+                                    iter->mTransform, currentSink);
     } else {
-      RefPtr<ID2D1RectangleGeometry> rectGeom;
-      factory()->CreateRectangleGeometry(iter->mBounds, byRef(rectGeom));
-      mCurrentClippedGeometry->CombineWithGeometry(rectGeom, D2D1_COMBINE_MODE_INTERSECT,
-                                                   D2D1::IdentityMatrix(), currentSink);
+      RefPtr<ID2D1Geometry> rectGeom = ConvertRectToGeometry(iter->mBounds);
+      pathGeom->CombineWithGeometry(rectGeom, D2D1_COMBINE_MODE_INTERSECT,
+                                    D2D1::IdentityMatrix(), currentSink);
     }
 
     currentSink->Close();
 
-    mCurrentClippedGeometry = newGeom;
+    pathGeom = newGeom.forget();
   }
 
+  if (!pathGeom) {
+    pathGeom = ConvertRectToGeometry(pathRect);
+  }
+  mCurrentClippedGeometry = pathGeom.forget();
   return mCurrentClippedGeometry;
 }
 
 TemporaryRef<ID2D1RenderTarget>
 DrawTargetD2D::CreateRTForTexture(ID3D10Texture2D *aTexture, SurfaceFormat aFormat)
 {
   HRESULT hr;
 
--- a/gfx/2d/DrawTargetD2D.h
+++ b/gfx/2d/DrawTargetD2D.h
@@ -177,16 +177,17 @@ private:
 
   bool FillGlyphsManual(ScaledFontDWrite *aFont,
                         const GlyphBuffer &aBuffer,
                         const Color &aColor,
                         IDWriteRenderingParams *aParams,
                         const DrawOptions &aOptions = DrawOptions());
 
   TemporaryRef<ID2D1RenderTarget> CreateRTForTexture(ID3D10Texture2D *aTexture, SurfaceFormat aFormat);
+  TemporaryRef<ID2D1Geometry> ConvertRectToGeometry(const D2D1_RECT_F& aRect);
   TemporaryRef<ID2D1Geometry> GetClippedGeometry();
 
   TemporaryRef<ID2D1Brush> CreateBrushForPattern(const Pattern &aPattern, Float aAlpha = 1.0f);
 
   TemporaryRef<ID3D10Texture2D> CreateGradientTexture(const GradientStopsD2D *aStops);
   TemporaryRef<ID3D10Texture2D> CreateTextureForAnalysis(IDWriteGlyphRunAnalysis *aAnalysis, const IntRect &aBounds);
 
   // This creates a (partially) uploaded bitmap for a DataSourceSurface. It
@@ -200,17 +201,17 @@ private:
 
   static const uint32_t test = 4;
 
   IntSize mSize;
 
   RefPtr<ID3D10Device1> mDevice;
   RefPtr<ID3D10Texture2D> mTexture;
   RefPtr<ID3D10Texture2D> mCurrentClipMaskTexture;
-  RefPtr<ID2D1PathGeometry> mCurrentClippedGeometry;
+  RefPtr<ID2D1Geometry> mCurrentClippedGeometry;
   mutable RefPtr<ID2D1RenderTarget> mRT;
 
   // We store this to prevent excessive SetTextRenderingParams calls.
   RefPtr<IDWriteRenderingParams> mTextRenderingParams;
 
   // Temporary texture and render target used for supporting alternative operators.
   RefPtr<ID3D10Texture2D> mTempTexture;
   RefPtr<ID3D10RenderTargetView> mRTView;