Bug 985801 - Add implementation for Path2D::AddPath. r=roc, r=bz
authorRik Cabanier <cabanier@adobe.com>
Mon, 25 Aug 2014 09:03:00 -0400
changeset 223081 bbafd7462ab4d48934d7d7e3a83823b20e1b7210
parent 223066 48b9cbcdbc5a34b32652650beeba6c4f79ffad70
child 223082 19a6cce2810772571e8db1f479a4999a99858c0a
push id3979
push userraliiev@mozilla.com
push dateMon, 13 Oct 2014 16:35:44 +0000
treeherdermozilla-beta@30f2cc610691 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc, bz
bugs985801
milestone34.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 985801 - Add implementation for Path2D::AddPath. r=roc, r=bz
dom/canvas/CanvasRenderingContext2D.cpp
dom/canvas/CanvasRenderingContext2D.h
dom/canvas/test/test_canvas_path.html
dom/webidl/CanvasRenderingContext2D.webidl
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -86,16 +86,17 @@
 #include "mozilla/Preferences.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/unused.h"
 #include "nsCCUncollectableMarker.h"
 #include "nsWrapperCacheInlines.h"
 #include "mozilla/dom/CanvasRenderingContext2DBinding.h"
 #include "mozilla/dom/HTMLImageElement.h"
 #include "mozilla/dom/HTMLVideoElement.h"
+#include "mozilla/dom/SVGMatrix.h"
 #include "mozilla/dom/TextMetrics.h"
 #include "mozilla/dom/UnionTypes.h"
 #include "mozilla/dom/SVGMatrix.h"
 #include "nsGlobalWindow.h"
 #include "GLContext.h"
 #include "GLContextProvider.h"
 #include "SVGContentUtils.h"
 #include "SVGImageContext.h"
@@ -4589,16 +4590,35 @@ CanvasPath::BezierTo(const gfx::Point& a
                      const gfx::Point& aCP2,
                      const gfx::Point& aCP3)
 {
   EnsurePathBuilder();
 
   mPathBuilder->BezierTo(aCP1, aCP2, aCP3);
 }
 
+void
+CanvasPath::AddPath(CanvasPath& aCanvasPath, const Optional<NonNull<SVGMatrix>>& aMatrix)
+{
+  RefPtr<gfx::Path> tempPath = aCanvasPath.GetPath(CanvasWindingRule::Nonzero,
+                                                   gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget());
+
+  if (aMatrix.WasPassed()) {
+    const SVGMatrix& m = aMatrix.Value();
+    Matrix transform(m.A(), m.B(), m.C(), m.D(), m.E(), m.F());
+
+    if (!transform.IsIdentity()) {
+      RefPtr<PathBuilder> tempBuilder = tempPath->TransformedCopyToBuilder(transform, FillRule::FILL_WINDING);
+      tempPath = tempBuilder->Finish();
+    }
+  }
+
+  tempPath->StreamToSink(mPathBuilder);
+}
+
 TemporaryRef<gfx::Path>
 CanvasPath::GetPath(const CanvasWindingRule& winding, const DrawTarget* aTarget) const
 {
   FillRule fillRule = FillRule::FILL_WINDING;
   if (winding == CanvasWindingRule::Evenodd) {
     fillRule = FillRule::FILL_EVEN_ODD;
   }
 
--- a/dom/canvas/CanvasRenderingContext2D.h
+++ b/dom/canvas/CanvasRenderingContext2D.h
@@ -36,16 +36,17 @@ class SurfaceStream;
 }
 
 namespace dom {
 class HTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement;
 class ImageData;
 class StringOrCanvasGradientOrCanvasPattern;
 class OwningStringOrCanvasGradientOrCanvasPattern;
 class TextMetrics;
+class SVGMatrix;
 
 extern const mozilla::gfx::Float SIGMA_MAX;
 
 template<typename T> class Optional;
 
 class CanvasPath MOZ_FINAL :
   public nsWrapperCache
 {
@@ -89,16 +90,19 @@ public:
                                   const gfx::DrawTarget* aTarget) const;
 
   explicit CanvasPath(nsISupports* aParent);
   // TemporaryRef arg because the return value from Path::CopyToBuilder() is
   // passed directly and we can't drop the only ref to have a raw pointer.
   CanvasPath(nsISupports* aParent,
              TemporaryRef<gfx::PathBuilder> aPathBuilder);
 
+  void AddPath(CanvasPath& aCanvasPath,
+               const Optional<NonNull<SVGMatrix>>& aMatrix);
+
 private:
   virtual ~CanvasPath() {}
 
   nsCOMPtr<nsISupports> mParent;
   static gfx::Float ToFloat(double aValue) { return gfx::Float(aValue); }
 
   mutable RefPtr<gfx::Path> mPath;
   mutable RefPtr<gfx::PathBuilder> mPathBuilder;
--- a/dom/canvas/test/test_canvas_path.html
+++ b/dom/canvas/test/test_canvas_path.html
@@ -332,60 +332,110 @@ function test_pathconstructor_canvas() {
 
   // copy constructor. This should not crash.
   var p1 = new Path2D();
   var _p2 = new Path2D(p1);
   p1.arcTo(0, 0, 1, 1, 2);
 }
 </script>
 
+<p>Canvas test: test_addpath_canvas</p>
+<canvas id="c8" class="output" width="200" height="200">+
+</canvas>
+<script type="text/javascript">
+
+function test_addpath_canvas() {
+  var c = document.getElementById("c8");
+  var ctx = c.getContext("2d");
+  ctx.beginPath();
+  var p1 = new Path2D();
+  p1.rect(0,0,100,100);
+  var p2 = new Path2D();
+  p2.rect(0,100,100,100);
+  var m = ctx.currentTransform;
+  p1.addPath(p2, m);
+  ctx.fillStyle = 'yellow';
+  ctx.fill(p1);
+  isPixel(ctx, 0, 100, [255, 255, 0, 255], 0);
+
+  ctx.clearRect(0,0,200,200);
+
+  ctx.beginPath();
+  var p3 = new Path2D();
+  p3.rect(0,0,100,100);
+  var p4 = new Path2D();
+  p4.rect(0,100,100,100);
+  var m = document.createElementNS("http://www.w3.org/2000/svg", "svg").createSVGMatrix();
+  m.a = 1; m.b = 0;
+  m.c = 0; m.d = 1;
+  m.e = 100; m.f = -100;
+  p3.addPath(p4, m);
+  ctx.fillStyle = 'yellow';
+  ctx.fill(p3);
+  isPixel(ctx, 50, 50, [255, 255, 0, 255], 0);
+  isPixel(ctx, 150, 150, [0, 0, 0, 0], 0);
+
+  var p5 = new Path2D();
+  p5.rect(0,0,100,100);
+  shouldThrow(ctx, "p5.addPath(null, m)");
+  shouldThrow(ctx, "p5.addPath([], m)");
+  shouldThrow(ctx, "p5.addPath({}, m)");
+}
+</script>
+
 <script>
 
 function runTests() {
  try {
   test_drawClipPath_canvas();
  } catch(e) {
+  ok(false, "unexpected exception thrown in: test_drawClipPath_canvas");
   throw e;
-  ok(false, "unexpected exception thrown in: test_drawClipPath_canvas");
  }
  try {
   test_drawFillPath_canvas();
  } catch(e) {
+  ok(false, "unexpected exception thrown in: test_drawFillPath_canvas");
   throw e;
-  ok(false, "unexpected exception thrown in: test_drawFillPath_canvas");
  }
  try {
   test_drawStrokePath_canvas();
  } catch(e) {
+  ok(false, "unexpected exception thrown in: test_drawStrokePath_canvas");
   throw e;
-  ok(false, "unexpected exception thrown in: test_drawStrokePath_canvas");
  }
  try {
   test_large_canvas();
  } catch(e) {
+  ok(false, "unexpected exception thrown in: test_large_canvas");
   throw e;
-  ok(false, "unexpected exception thrown in: test_large_canvas");
  }
  try {
   test_isPointInPath_canvas();
  } catch(e) {
+  ok(false, "unexpected exception thrown in: test_isPointInPath_canvas");
   throw e;
-  ok(false, "unexpected exception thrown in: test_isPointInPath_canvas");
  }
  try {
   test_isPointInStroke_canvas();
  } catch(e) {
+  ok(false, "unexpected exception thrown in: test_isPointInStroke_canvas");
   throw e;
-  ok(false, "unexpected exception thrown in: test_isPointInStroke_canvas");
  }
  try {
   test_pathconstructor_canvas();
  } catch(e) {
+  ok(false, "unexpected exception thrown in: test_pathconstructor_canvas");
   throw e;
-  ok(false, "unexpected exception thrown in: test_pathconstructor_canvas");
+ }
+ try {
+  test_addpath_canvas();
+ } catch(e) {
+  ok(false, "unexpected exception thrown in: test_addpath_canvas");
+  throw e;
  }
  SpecialPowers.setBoolPref("canvas.path.enabled", false);
  SimpleTest.finish();
 }
 
 addLoadEvent(runTests);
 
 // Don't leak the world via the Path2D reference to its window.
--- a/dom/webidl/CanvasRenderingContext2D.webidl
+++ b/dom/webidl/CanvasRenderingContext2D.webidl
@@ -318,10 +318,12 @@ interface TextMetrics {
 
 };
 
 [Pref="canvas.path.enabled",
  Constructor,
  Constructor(Path2D other),
  Constructor(DOMString pathString)]
 interface Path2D
-{};
+{
+  void addPath(Path2D path, optional SVGMatrix transformation);
+};
 Path2D implements CanvasPathMethods;