Bug 988088 - Cache path objects in Path2D implementation. r=bas
authorRik Cabanier <cabanier@adobe.com>
Mon, 31 Mar 2014 08:55:00 +0200 (2014-03-31)
changeset 176487 9204362c5122a603be768c4df295cecc75fbfeee
parent 176486 05a2d06d232fb63503b964d3f678ab74f8903c9d
child 176488 aa6cc6b2ef8f6e12d4443f0c98ca5e170fa224e2
push id26524
push userryanvm@gmail.com
push dateTue, 01 Apr 2014 20:44:18 +0000 (2014-04-01)
treeherdermozilla-central@0ff6afce0133 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbas
bugs988088
milestone31.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 988088 - Cache path objects in Path2D implementation. r=bas
content/canvas/src/CanvasRenderingContext2D.cpp
content/canvas/src/CanvasRenderingContext2D.h
--- a/content/canvas/src/CanvasRenderingContext2D.cpp
+++ b/content/canvas/src/CanvasRenderingContext2D.cpp
@@ -4400,34 +4400,42 @@ CanvasPath::Constructor(const GlobalObje
 
   nsRefPtr<CanvasPath> path = new CanvasPath(aGlobal.GetAsSupports(), tempPath->CopyToBuilder());
   return path.forget();
 }
 
 void
 CanvasPath::ClosePath()
 {
+  EnsurePathBuilder();
+
   mPathBuilder->Close();
 }
 
 void
 CanvasPath::MoveTo(double x, double y)
 {
+  EnsurePathBuilder();
+
   mPathBuilder->MoveTo(Point(ToFloat(x), ToFloat(y)));
 }
 
 void
 CanvasPath::LineTo(double x, double y)
 {
+  EnsurePathBuilder();
+
   mPathBuilder->LineTo(Point(ToFloat(x), ToFloat(y)));
 }
 
 void
 CanvasPath::QuadraticCurveTo(double cpx, double cpy, double x, double y)
 {
+  EnsurePathBuilder();
+
   mPathBuilder->QuadraticBezierTo(gfx::Point(ToFloat(cpx), ToFloat(cpy)),
                                   gfx::Point(ToFloat(x), ToFloat(y)));
 }
 
 void
 CanvasPath::BezierCurveTo(double cp1x, double cp1y,
                           double cp2x, double cp2y,
                           double x, double y)
@@ -4522,48 +4530,75 @@ CanvasPath::Arc(double x, double y, doub
   }
 
   ArcToBezier(this, Point(x, y), Size(radius, radius), startAngle, endAngle, anticlockwise);
 }
 
 void
 CanvasPath::LineTo(const gfx::Point& aPoint)
 {
+  EnsurePathBuilder();
+
   mPathBuilder->LineTo(aPoint);
 }
 
 void
 CanvasPath::BezierTo(const gfx::Point& aCP1,
                      const gfx::Point& aCP2,
                      const gfx::Point& aCP3)
 {
+  EnsurePathBuilder();
+
   mPathBuilder->BezierTo(aCP1, aCP2, aCP3);
 }
 
 RefPtr<gfx::Path>
 CanvasPath::GetPath(const CanvasWindingRule& winding, const mozilla::RefPtr<mozilla::gfx::DrawTarget>& mTarget) const
 {
   FillRule fillRule = FillRule::FILL_WINDING;
   if (winding == CanvasWindingRule::Evenodd) {
     fillRule = FillRule::FILL_EVEN_ODD;
   }
 
-  RefPtr<Path> mTempPath = mPathBuilder->Finish();
-  if (!mTempPath)
-    return mTempPath;
+  if (mPath &&
+      (mPath->GetBackendType() == mTarget->GetType()) &&
+      (mPath->GetFillRule() == fillRule)) {
+    return mPath;
+  }
+
+  if (!mPath) {
+    // if there is no path, there must be a pathbuilder
+    MOZ_ASSERT(mPathBuilder);
+    mPath = mPathBuilder->Finish();
+    if (!mPath)
+      return mPath;
+
+    mPathBuilder = nullptr;
+  }
 
   // retarget our backend if we're used with a different backend
-  if (mTempPath->GetBackendType() != mTarget->GetType()) {
-    mPathBuilder = mTarget->CreatePathBuilder(fillRule);
-    mTempPath->StreamToSink(mPathBuilder);
-    mTempPath = mPathBuilder->Finish();
-  } else if (mTempPath->GetFillRule() != fillRule) {
-    mPathBuilder = mTempPath->CopyToBuilder(fillRule);
-    mTempPath = mPathBuilder->Finish();
-  }
-
-  mPathBuilder = mTempPath->CopyToBuilder();
-
-  return mTempPath;
+  if (mPath->GetBackendType() != mTarget->GetType()) {
+    RefPtr<PathBuilder> tmpPathBuilder = mTarget->CreatePathBuilder(fillRule);
+    mPath->StreamToSink(tmpPathBuilder);
+    mPath = tmpPathBuilder->Finish();
+  } else if (mPath->GetFillRule() != fillRule) {
+    RefPtr<PathBuilder> tmpPathBuilder = mPath->CopyToBuilder(fillRule);
+    mPath = tmpPathBuilder->Finish();
+  }
+
+  return mPath;
+}
+
+void
+CanvasPath::EnsurePathBuilder() const
+{
+  if (mPathBuilder) {
+    return;
+  }
+
+  // if there is not pathbuilder, there must be a path
+  MOZ_ASSERT(mPath);
+  mPathBuilder = mPath->CopyToBuilder();
+  mPath = nullptr;
 }
 
 }
 }
--- a/content/canvas/src/CanvasRenderingContext2D.h
+++ b/content/canvas/src/CanvasRenderingContext2D.h
@@ -91,17 +91,20 @@ public:
   CanvasPath(nsCOMPtr<nsISupports> aParent, RefPtr<gfx::PathBuilder> mPathBuilder);
   virtual ~CanvasPath() {}
 
 private:
 
   nsCOMPtr<nsISupports> mParent;
   static gfx::Float ToFloat(double aValue) { return gfx::Float(aValue); }
 
+  mutable RefPtr<gfx::Path> mPath;
   mutable RefPtr<gfx::PathBuilder> mPathBuilder;
+
+  void EnsurePathBuilder() const;
 };
 
 struct CanvasBidiProcessor;
 class CanvasRenderingContext2DUserData;
 
 /**
  ** CanvasRenderingContext2D
  **/