Bug 928150 - Implement CanvasRenderingContext2D.{get|set}Transform behind the canvas.transform_extensions.enabled preference, and update CanvasPath.addPath and CanvasPattern.setTransform to accept DOMMatrix2DInit rather than just SVGMatrix (including the updated relevant web platform tests from WPT master branch); r?bz draft
authorThomas Wisniewski <wisniewskit@gmail.com>
Thu, 19 Oct 2017 21:11:39 -0400
changeset 683734 9a412538b0741fa993e3a0d3d00ca8d177362eb1
parent 683733 03e7ae178bc3dfd267d20b75006e40713c06b2b3
child 736714 682af5e8178b5cb16c1c254541c0f9f532f7f06a
push id85450
push userwisniewskit@gmail.com
push dateFri, 20 Oct 2017 04:13:07 +0000
reviewersbz
bugs928150
milestone58.0a1
Bug 928150 - Implement CanvasRenderingContext2D.{get|set}Transform behind the canvas.transform_extensions.enabled preference, and update CanvasPath.addPath and CanvasPattern.setTransform to accept DOMMatrix2DInit rather than just SVGMatrix (including the updated relevant web platform tests from WPT master branch); r?bz MozReview-Commit-ID: 4z9VJIs9PZ4
dom/base/DOMMatrix.cpp
dom/base/DOMMatrix.h
dom/bindings/Errors.msg
dom/canvas/BasicRenderingContext2D.h
dom/canvas/CanvasPath.h
dom/canvas/CanvasPattern.h
dom/canvas/CanvasRenderingContext2D.cpp
dom/canvas/CanvasRenderingContext2D.h
dom/webidl/CanvasRenderingContext2D.webidl
dom/webidl/DOMMatrix.webidl
modules/libpref/init/all.js
testing/web-platform/meta/css/geometry-1/DOMMatrix2DInit-validate-fixup.html.ini
testing/web-platform/meta/html/dom/interfaces.html.ini
testing/web-platform/tests/2dcontext/conformance-requirements/2d.missingargs.html
testing/web-platform/tests/css/geometry-1/DOMMatrix2DInit-validate-fixup.html
testing/web-platform/tests/html/dom/interfaces.html
--- a/dom/base/DOMMatrix.cpp
+++ b/dom/base/DOMMatrix.cpp
@@ -680,10 +680,70 @@ DOMMatrix::SetMatrixValue(const nsAStrin
 }
 
 JSObject*
 DOMMatrix::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return DOMMatrixBinding::Wrap(aCx, this, aGivenProto);
 }
 
+#define SAMEVALUEZERO(a, b)\
+  ((a == b) || (mozilla::IsNaN(a) && mozilla::IsNaN(b)) ||\
+   (a == -0 && b == 0) || (a == 0 && b == -0))
+
+#define SET_DOMMATRIXINIT_DICTIONARY_MEMBER(dict, m, dflt, fallback)\
+  if (!dict.m.WasPassed()) {                                        \
+    if (dict.dflt.WasPassed()) {                                    \
+      dict.m.Construct(dict.dflt.Value());                          \
+    } else {                                                        \
+      dict.m.Construct(fallback);                                   \
+    }                                                               \
+  }
+
+#define THROW_ON_DOMMATRIXINIT_MEMBER_MISMATCH(dict, a, b, aStr, bStr, err)\
+  if (dict.a.WasPassed() && dict.b.WasPassed() &&                          \
+      !SAMEVALUEZERO(dict.a.Value(), dict.b.Value())) {                    \
+    err.ThrowTypeError<MSG_MISMATCHED_MATRIX_MEMBERS>(                     \
+      NS_LITERAL_STRING(aStr), NS_LITERAL_STRING(bStr));                   \
+    return;                                                                \
+  }
+
+void
+ValidateAndFixupDOMMatrix2DInit(DOMMatrix2DInit& aInit, ErrorResult& aError)
+{
+  // Step 1
+  THROW_ON_DOMMATRIXINIT_MEMBER_MISMATCH(aInit, mA, mM11, "a", "m11", aError);
+  THROW_ON_DOMMATRIXINIT_MEMBER_MISMATCH(aInit, mB, mM12, "b", "m12", aError);
+  THROW_ON_DOMMATRIXINIT_MEMBER_MISMATCH(aInit, mC, mM21, "c", "m21", aError);
+  THROW_ON_DOMMATRIXINIT_MEMBER_MISMATCH(aInit, mD, mM22, "d", "m22", aError);
+  THROW_ON_DOMMATRIXINIT_MEMBER_MISMATCH(aInit, mE, mM41, "e", "m41", aError);
+  THROW_ON_DOMMATRIXINIT_MEMBER_MISMATCH(aInit, mF, mM42, "f", "m42", aError);
+
+  // Steps 2-7
+  SET_DOMMATRIXINIT_DICTIONARY_MEMBER(aInit, mM11, mA, 1.0);
+  SET_DOMMATRIXINIT_DICTIONARY_MEMBER(aInit, mM12, mB, 0.0);
+  SET_DOMMATRIXINIT_DICTIONARY_MEMBER(aInit, mM21, mC, 0.0);
+  SET_DOMMATRIXINIT_DICTIONARY_MEMBER(aInit, mM22, mD, 1.0);
+  SET_DOMMATRIXINIT_DICTIONARY_MEMBER(aInit, mM41, mE, 0.0);
+  SET_DOMMATRIXINIT_DICTIONARY_MEMBER(aInit, mM42, mF, 0.0);
+}
+
+bool
+InitMatrixFromDOMMatrix2DInit(const DOMMatrix2DInit& aInit,
+                              gfx::Matrix& aMatrix,
+                              ErrorResult& aError)
+{
+  DOMMatrix2DInit fixed(aInit);
+  ValidateAndFixupDOMMatrix2DInit(fixed, aError);
+  if (aError.Failed()) {
+    return false;
+  }
+  aMatrix._11 = fixed.mM11.Value();
+  aMatrix._12 = fixed.mM12.Value();
+  aMatrix._21 = fixed.mM21.Value();
+  aMatrix._22 = fixed.mM22.Value();
+  aMatrix._31 = fixed.mM41.Value();
+  aMatrix._32 = fixed.mM42.Value();
+  return true;
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/base/DOMMatrix.h
+++ b/dom/base/DOMMatrix.h
@@ -9,16 +9,17 @@
 
 #include "nsWrapperCache.h"
 #include "nsISupports.h"
 #include "nsCycleCollectionParticipant.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/ErrorResult.h"
 #include "nsCOMPtr.h"
 #include "mozilla/dom/BindingDeclarations.h"
+#include "mozilla/dom/DOMMatrixBinding.h"
 #include "mozilla/dom/TypedArray.h"
 #include "mozilla/gfx/Matrix.h" // for Matrix4x4
 
 namespace mozilla {
 namespace dom {
 
 class GlobalObject;
 class DOMMatrix;
@@ -257,12 +258,16 @@ public:
   DOMMatrix* InvertSelf();
   DOMMatrix* SetMatrixValue(const nsAString& aTransformList, ErrorResult& aRv);
 protected:
   void Ensure3DMatrix();
 
   virtual ~DOMMatrix() {}
 };
 
+bool InitMatrixFromDOMMatrix2DInit(const DOMMatrix2DInit& aInit,
+                                   gfx::Matrix& aMatrix,
+                                   ErrorResult& aError);
+
 } // namespace dom
 } // namespace mozilla
 
 #endif /*MOZILLA_DOM_DOMMATRIX_H_*/
--- a/dom/bindings/Errors.msg
+++ b/dom/bindings/Errors.msg
@@ -98,8 +98,9 @@ MSG_DEF(MSG_INVALID_EASING_ERROR, 1, JSE
 MSG_DEF(MSG_USELESS_SETTIMEOUT, 1, JSEXN_TYPEERR, "Useless {0} call (missing quotes around argument?)")
 MSG_DEF(MSG_TOKENLIST_NO_SUPPORTED_TOKENS, 2, JSEXN_TYPEERR, "{0} attribute of <{1}> does not define any supported tokens")
 MSG_DEF(MSG_CACHE_STREAM_CLOSED, 0, JSEXN_TYPEERR, "Response body is a cache file stream that has already been closed.")
 MSG_DEF(MSG_TIME_VALUE_OUT_OF_RANGE, 1, JSEXN_TYPEERR, "{0} is outside the supported range for time values.")
 MSG_DEF(MSG_ONLY_IF_CACHED_WITHOUT_SAME_ORIGIN, 1, JSEXN_TYPEERR, "Request mode '{0}' was used, but request cache mode 'only-if-cached' can only be used with request mode 'same-origin'.")
 MSG_DEF(MSG_THRESHOLD_RANGE_ERROR, 0, JSEXN_RANGEERR, "Threshold values must all be in the range [0, 1].")
 MSG_DEF(MSG_WORKER_THREAD_SHUTTING_DOWN, 0, JSEXN_TYPEERR, "The Worker thread is shutting down.")
 MSG_DEF(MSG_CACHE_OPEN_FAILED, 0, JSEXN_TYPEERR, "CacheStorage.open() failed to access the storage system.")
+MSG_DEF(MSG_MISMATCHED_MATRIX_MEMBERS, 2, JSEXN_TYPEERR, "{0} and {1} must match if both are set.")
--- a/dom/canvas/BasicRenderingContext2D.h
+++ b/dom/canvas/BasicRenderingContext2D.h
@@ -1,16 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef BasicRenderingContext2D_h
 #define BasicRenderingContext2D_h
 
 #include "mozilla/dom/CanvasRenderingContext2DBinding.h"
+#include "DOMMatrix.h"
 
 namespace mozilla {
 namespace dom {
 
 class HTMLImageElementOrSVGImageElementOrHTMLCanvasElementOrHTMLVideoElementOrImageBitmap;
 typedef HTMLImageElementOrSVGImageElementOrHTMLCanvasElementOrHTMLVideoElementOrImageBitmap
   CanvasImageSource;
 
@@ -43,16 +44,18 @@ public:
                          mozilla::ErrorResult& aError) = 0;
   virtual void SetTransform(double aM11,
                             double aM12,
                             double aM21,
                             double aM22,
                             double aDx,
                             double aDy,
                             mozilla::ErrorResult& aError) = 0;
+  virtual void SetTransform(const DOMMatrix2DInit& aTransform,
+                            mozilla::ErrorResult& aError) = 0;
   virtual void ResetTransform(mozilla::ErrorResult& aError) = 0;
 
   //
   // CanvasCompositing
   //
   virtual double GlobalAlpha() = 0;
   virtual void SetGlobalAlpha(double aGlobalAlpha) = 0;
   virtual void GetGlobalCompositeOperation(nsAString& aOp,
--- a/dom/canvas/CanvasPath.h
+++ b/dom/canvas/CanvasPath.h
@@ -5,16 +5,17 @@
 #ifndef CanvasPath_h
 #define CanvasPath_h
 
 #include "mozilla/Attributes.h"
 #include "mozilla/RefPtr.h"
 #include "nsWrapperCache.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/dom/BindingDeclarations.h"
+#include "mozilla/dom/DOMMatrix.h"
 #include "mozilla/ErrorResult.h"
 
 namespace mozilla {
 namespace dom {
 
 enum class CanvasWindingRule : uint8_t;
 class SVGMatrix;
 
@@ -65,17 +66,18 @@ public:
 
   explicit CanvasPath(nsISupports* aParent);
   // already_AddRefed 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,
              already_AddRefed<gfx::PathBuilder> aPathBuilder);
 
   void AddPath(CanvasPath& aCanvasPath,
-               const Optional<NonNull<SVGMatrix>>& aMatrix);
+               const DOMMatrix2DInit& aTransform,
+               ErrorResult& aError);
 
 private:
   virtual ~CanvasPath() {}
 
   nsCOMPtr<nsISupports> mParent;
   static gfx::Float ToFloat(double aValue) { return gfx::Float(aValue); }
 
   mutable RefPtr<gfx::Path> mPath;
--- a/dom/canvas/CanvasPattern.h
+++ b/dom/canvas/CanvasPattern.h
@@ -58,17 +58,17 @@ public:
   }
 
   CanvasRenderingContext2D* GetParentObject()
   {
     return mContext;
   }
 
   // WebIDL
-  void SetTransform(SVGMatrix& matrix);
+  void SetTransform(const DOMMatrix2DInit& aTransform, ErrorResult& aError);
 
   RefPtr<CanvasRenderingContext2D> mContext;
   RefPtr<gfx::SourceSurface> mSurface;
   nsCOMPtr<nsIPrincipal> mPrincipal;
   mozilla::gfx::Matrix mTransform;
   const bool mForceWriteOnly;
   const bool mCORSUsed;
   const RepeatMode mRepeat;
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -100,16 +100,17 @@
 #include "mozilla/Telemetry.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/Unused.h"
 #include "nsCCUncollectableMarker.h"
 #include "nsWrapperCacheInlines.h"
 #include "mozilla/dom/CanvasRenderingContext2DBinding.h"
 #include "mozilla/dom/CanvasPath.h"
+#include "mozilla/dom/DOMMatrix.h"
 #include "mozilla/dom/HTMLImageElement.h"
 #include "mozilla/dom/HTMLVideoElement.h"
 #include "mozilla/dom/SVGImageElement.h"
 #include "mozilla/dom/SVGMatrix.h"
 #include "mozilla/dom/TextMetrics.h"
 #include "mozilla/dom/SVGMatrix.h"
 #include "mozilla/FloatingPoint.h"
 #include "nsGlobalWindow.h"
@@ -728,19 +729,24 @@ private:
   }
 
   RefPtr<DrawTarget> mTarget;
   UniquePtr<AdjustedTargetForShadow> mShadowTarget;
   UniquePtr<AdjustedTargetForFilter> mFilterTarget;
 };
 
 void
-CanvasPattern::SetTransform(SVGMatrix& aMatrix)
-{
-  mTransform = ToMatrix(aMatrix.GetMatrix());
+CanvasPattern::SetTransform(const DOMMatrix2DInit& aTransform,
+                            ErrorResult& aError)
+{
+  Matrix transform;
+  if (!InitMatrixFromDOMMatrix2DInit(aTransform, transform, aError)) {
+    return;
+  }
+  mTransform = transform;
 }
 
 void
 CanvasGradient::AddColorStop(float aOffset, const nsAString& aColorstr, ErrorResult& aRv)
 {
   if (aOffset < 0.0 || aOffset > 1.0) {
     aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
     return;
@@ -2266,16 +2272,58 @@ CanvasRenderingContext2D::Transform(doub
   }
 
   Matrix newMatrix(aM11, aM12, aM21, aM22, aDx, aDy);
   newMatrix *= mTarget->GetTransform();
 
   SetTransformInternal(newMatrix);
 }
 
+already_AddRefed<DOMMatrix>
+CanvasRenderingContext2D::GetTransform()
+{
+  TransformWillUpdate();
+  RefPtr<DOMMatrix> matrix;
+  matrix = new DOMMatrix(GetParentObject());
+  if (IsTargetValid()) {
+    Matrix currentMatrix = mTarget->GetTransform();
+    matrix->SetA(currentMatrix._11);
+    matrix->SetB(currentMatrix._12);
+    matrix->SetC(currentMatrix._21);
+    matrix->SetD(currentMatrix._22);
+    matrix->SetE(currentMatrix._31);
+    matrix->SetF(currentMatrix._32);
+  }
+  return matrix.forget();
+}
+
+void
+CanvasRenderingContext2D::SetTransform(const DOMMatrix2DInit& aTransform,
+                                       ErrorResult& aError)
+{
+  if (!Preferences::GetBool("canvas.transform_extensions.enabled")) {
+    aError.ThrowTypeError<MSG_MISSING_ARGUMENTS>(
+      NS_LITERAL_STRING("CanvasRenderingContext2D.setTransform"));
+    return;
+  }
+
+  Matrix transform;
+  if (!InitMatrixFromDOMMatrix2DInit(aTransform, transform, aError)) {
+    return;
+  }
+
+  TransformWillUpdate();
+  if (!IsTargetValid()) {
+    aError.Throw(NS_ERROR_FAILURE);
+    return;
+  }
+
+  SetTransformInternal(transform);
+}
+
 void
 CanvasRenderingContext2D::SetTransform(double aM11, double aM12,
                                        double aM21, double aM22,
                                        double aDx, double aDy,
                                        ErrorResult& aError)
 {
   TransformWillUpdate();
   if (!IsTargetValid()) {
@@ -6503,30 +6551,31 @@ CanvasPath::BezierTo(const gfx::Point& a
                      const gfx::Point& aCP3)
 {
   EnsurePathBuilder();
 
   mPathBuilder->BezierTo(aCP1, aCP2, aCP3);
 }
 
 void
-CanvasPath::AddPath(CanvasPath& aCanvasPath, const Optional<NonNull<SVGMatrix>>& aMatrix)
-{
+CanvasPath::AddPath(CanvasPath& aCanvasPath, const DOMMatrix2DInit& aTransform,
+                    ErrorResult& aError)
+{
+  Matrix transform;
+  if (!InitMatrixFromDOMMatrix2DInit(aTransform, transform, aError)) {
+    return;
+  }
+
   RefPtr<gfx::Path> tempPath = aCanvasPath.GetPath(
     CanvasWindingRule::Nonzero,
     gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget().get());
 
-  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();
-    }
+  if (!transform.IsIdentity()) {
+    RefPtr<PathBuilder> tempBuilder = tempPath->TransformedCopyToBuilder(transform, FillRule::FILL_WINDING);
+    tempPath = tempBuilder->Finish();
   }
 
   EnsurePathBuilder(); // in case a path is added to itself
   tempPath->StreamToSink(mPathBuilder);
 }
 
 already_AddRefed<gfx::Path>
 CanvasPath::GetPath(const CanvasWindingRule& aWinding, const DrawTarget* aTarget) const
--- a/dom/canvas/CanvasRenderingContext2D.h
+++ b/dom/canvas/CanvasRenderingContext2D.h
@@ -85,16 +85,19 @@ public:
 
   void Save() override;
   void Restore() override;
   void Scale(double aX, double aY, mozilla::ErrorResult& aError) override;
   void Rotate(double aAngle, mozilla::ErrorResult& aError) override;
   void Translate(double aX, double aY, mozilla::ErrorResult& aError) override;
   void Transform(double aM11, double aM12, double aM21, double aM22,
                  double aDx, double aDy, mozilla::ErrorResult& aError) override;
+  already_AddRefed<DOMMatrix> GetTransform();
+  void SetTransform(const DOMMatrix2DInit& aTransform,
+                    mozilla::ErrorResult& aError) override;
   void SetTransform(double aM11, double aM12, double aM21, double aM22,
                     double aDx, double aDy, mozilla::ErrorResult& aError) override;
   void ResetTransform(mozilla::ErrorResult& aError) override;
 
   double GlobalAlpha() override
   {
     return CurrentState().globalAlpha;
   }
--- a/dom/webidl/CanvasRenderingContext2D.webidl
+++ b/dom/webidl/CanvasRenderingContext2D.webidl
@@ -146,25 +146,28 @@ interface CanvasState {
   // state
   void save(); // push state on state stack
   void restore(); // pop state stack and restore state
 };
 
 [NoInterfaceObject]
 interface CanvasTransform {
   // transformations (default transform is the identity matrix)
-// NOT IMPLEMENTED           attribute SVGMatrix currentTransform;
   [Throws, LenientFloat]
   void scale(double x, double y);
   [Throws, LenientFloat]
   void rotate(double angle);
   [Throws, LenientFloat]
   void translate(double x, double y);
   [Throws, LenientFloat]
   void transform(double a, double b, double c, double d, double e, double f);
+  [NewObject, Pref="layout.css.DOMMatrix.enabled"]
+  DOMMatrix getTransform();
+  [Throws, LenientFloat]
+  void setTransform(optional DOMMatrix2DInit transform);
   [Throws, LenientFloat]
   void setTransform(double a, double b, double c, double d, double e, double f);
   [Throws]
   void resetTransform();
 };
 
 [NoInterfaceObject]
 interface CanvasCompositing {
@@ -348,21 +351,18 @@ interface CanvasGradient {
   // opaque object
   [Throws]
   // addColorStop should take a double
   void addColorStop(float offset, DOMString color);
 };
 
 interface CanvasPattern {
   // opaque object
-  // [Throws, LenientFloat] - could not do this overload because of bug 1020975
-  // void setTransform(double a, double b, double c, double d, double e, double f);
-
-  // No throw necessary here - SVGMatrix is always good.
-  void setTransform(SVGMatrix matrix);
+  [Throws]
+  void setTransform(optional DOMMatrix2DInit transform);
 };
 
 interface TextMetrics {
 
   // x-direction
   readonly attribute double width; // advance width
 
   /*
@@ -386,11 +386,12 @@ interface TextMetrics {
 };
 
 [Pref="canvas.path.enabled",
  Constructor,
  Constructor(Path2D other),
  Constructor(DOMString pathString)]
 interface Path2D
 {
-  void addPath(Path2D path, optional SVGMatrix transformation);
+  [Throws]
+  void addPath(Path2D path, optional DOMMatrix2DInit transformation);
 };
 Path2D implements CanvasPathMethods;
--- a/dom/webidl/DOMMatrix.webidl
+++ b/dom/webidl/DOMMatrix.webidl
@@ -141,8 +141,36 @@ interface DOMMatrix : DOMMatrixReadOnly 
                                   unrestricted double z,
                                   unrestricted double angle);
     DOMMatrix skewXSelf(unrestricted double sx);
     DOMMatrix skewYSelf(unrestricted double sy);
     DOMMatrix invertSelf();
     [Throws] DOMMatrix setMatrixValue(DOMString transformList);
 };
 
+dictionary DOMMatrix2DInit {
+    unrestricted double a;
+    unrestricted double b;
+    unrestricted double c;
+    unrestricted double d;
+    unrestricted double e;
+    unrestricted double f;
+    unrestricted double m11;
+    unrestricted double m12;
+    unrestricted double m21;
+    unrestricted double m22;
+    unrestricted double m41;
+    unrestricted double m42;
+};
+
+dictionary DOMMatrixInit : DOMMatrix2DInit {
+    unrestricted double m13 = 0;
+    unrestricted double m14 = 0;
+    unrestricted double m23 = 0;
+    unrestricted double m24 = 0;
+    unrestricted double m31 = 0;
+    unrestricted double m32 = 0;
+    unrestricted double m33 = 1;
+    unrestricted double m34 = 0;
+    unrestricted double m43 = 0;
+    unrestricted double m44 = 1;
+    boolean is2D;
+};
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -928,16 +928,17 @@ pref("ui.scrollToClick", 0);
 // provide ability to turn on support for canvas focus rings
 pref("canvas.focusring.enabled", true);
 pref("canvas.customfocusring.enabled", false);
 pref("canvas.hitregions.enabled", false);
 pref("canvas.filters.enabled", true);
 // Add support for canvas path objects
 pref("canvas.path.enabled", true);
 pref("canvas.capturestream.enabled", true);
+pref("canvas.transform_extensions.enabled", true);
 
 // Disable the ImageBitmap-extensions for now.
 pref("canvas.imagebitmap_extensions.enabled", false);
 
 // We want the ability to forcibly disable platform a11y, because
 // some non-a11y-related components attempt to bring it up.  See bug
 // 538530 for details about Windows; we have a pref here that allows it
 // to be disabled for performance and testing resons.
--- a/testing/web-platform/meta/css/geometry-1/DOMMatrix2DInit-validate-fixup.html.ini
+++ b/testing/web-platform/meta/css/geometry-1/DOMMatrix2DInit-validate-fixup.html.ini
@@ -1,260 +1,3 @@
 [DOMMatrix2DInit-validate-fixup.html]
   type: testharness
-  [Sanity check without dictionary]
-    expected: FAIL
-
-  [{m13: 1, is2D: true}]
-    expected: FAIL
-
-  [{m14: 1, is2D: true}]
-    expected: FAIL
-
-  [{m23: 1, is2D: true}]
-    expected: FAIL
-
-  [{m24: 1, is2D: true}]
-    expected: FAIL
-
-  [{m31: 1, is2D: true}]
-    expected: FAIL
-
-  [{m32: 1, is2D: true}]
-    expected: FAIL
-
-  [{m33: 0, is2D: true}]
-    expected: FAIL
-
-  [{m33: -0, is2D: true}]
-    expected: FAIL
-
-  [{m33: -1, is2D: true}]
-    expected: FAIL
-
-  [{m34: 1, is2D: true}]
-    expected: FAIL
-
-  [{m43: 1, is2D: true}]
-    expected: FAIL
-
-  [{m44: 0, is2D: true}]
-    expected: FAIL
-
-  [{}]
-    expected: FAIL
-
-  [{is2D: undefined}]
-    expected: FAIL
-
-  [{a: 1, m11: 1}]
-    expected: FAIL
-
-  [{b: 0, m12: undefined}]
-    expected: FAIL
-
-  [{c: 0, m21: 0}]
-    expected: FAIL
-
-  [{c: 0, m21: -0}]
-    expected: FAIL
-
-  [{c: -0, m21: 0}]
-    expected: FAIL
-
-  [{c: -0, m21: -0}]
-    expected: FAIL
-
-  [{d: Infinity, m22: Infinity}]
-    expected: FAIL
-
-  [{e: -Infinity, m41: -Infinity}]
-    expected: FAIL
-
-  [{f: NaN, m42: NaN}]
-    expected: FAIL
-
-  [{f: NaN, m42: NaN, is2D: true}]
-    expected: FAIL
-
-  [{f: 0, m42: null}]
-    expected: FAIL
-
-  [{f: -0, m42: null}]
-    expected: FAIL
-
-  [{a: 2}]
-    expected: FAIL
-
-  [{b: 2}]
-    expected: FAIL
-
-  [{c: 2}]
-    expected: FAIL
-
-  [{d: 2}]
-    expected: FAIL
-
-  [{e: 2}]
-    expected: FAIL
-
-  [{f: 2}]
-    expected: FAIL
-
-  [{a: -0, b: -0, c: -0, d: -0, e: -0, f: -0}]
-    expected: FAIL
-
-  [{a: -0, b: -0, c: -0, d: -0, e: -0, f: -0, is2D: true}]
-    expected: FAIL
-
-  [{m11: 2}]
-    expected: FAIL
-
-  [{m12: 2}]
-    expected: FAIL
-
-  [{m21: 2}]
-    expected: FAIL
-
-  [{m22: 2}]
-    expected: FAIL
-
-  [{m41: 2}]
-    expected: FAIL
-
-  [{m42: 2}]
-    expected: FAIL
-
-  [{m11: -0, m12: -0, m21: -0, m22: -0, m41: -0, m42: -0}]
-    expected: FAIL
-
-  [{m11: -0, m12: -0, m21: -0, m22: -0, m41: -0, m42: -0, is2D: true}]
-    expected: FAIL
-
-  [{m13: 0, is2D: true}]
-    expected: FAIL
-
-  [{m13: -0, is2D: true}]
-    expected: FAIL
-
-  [{m14: 0, is2D: true}]
-    expected: FAIL
-
-  [{m14: -0, is2D: true}]
-    expected: FAIL
-
-  [{m23: 0, is2D: true}]
-    expected: FAIL
-
-  [{m23: -0, is2D: true}]
-    expected: FAIL
-
-  [{m24: 0, is2D: true}]
-    expected: FAIL
-
-  [{m24: -0, is2D: true}]
-    expected: FAIL
-
-  [{m31: 0, is2D: true}]
-    expected: FAIL
-
-  [{m31: -0, is2D: true}]
-    expected: FAIL
-
-  [{m32: 0, is2D: true}]
-    expected: FAIL
-
-  [{m32: -0, is2D: true}]
-    expected: FAIL
-
-  [{m33: 1, is2D: true}]
-    expected: FAIL
-
-  [{m34: 0, is2D: true}]
-    expected: FAIL
-
-  [{m34: -0, is2D: true}]
-    expected: FAIL
-
-  [{m43: 0, is2D: true}]
-    expected: FAIL
-
-  [{m43: -0, is2D: true}]
-    expected: FAIL
-
-  [{m44: 1, is2D: true}]
-    expected: FAIL
-
-  [{is2D: true}]
-    expected: FAIL
-
-  [{m13: 1, is2D: false}]
-    expected: FAIL
-
-  [{m14: 1, is2D: false}]
-    expected: FAIL
-
-  [{m23: 1, is2D: false}]
-    expected: FAIL
-
-  [{m24: 1, is2D: false}]
-    expected: FAIL
-
-  [{m31: 1, is2D: false}]
-    expected: FAIL
-
-  [{m32: 1, is2D: false}]
-    expected: FAIL
-
-  [{m33: 0, is2D: false}]
-    expected: FAIL
-
-  [{m33: -0, is2D: false}]
-    expected: FAIL
-
-  [{m33: -1, is2D: false}]
-    expected: FAIL
-
-  [{m34: 1, is2D: false}]
-    expected: FAIL
-
-  [{m43: 1, is2D: false}]
-    expected: FAIL
-
-  [{m44: 0, is2D: false}]
-    expected: FAIL
-
-  [{m13: 1}]
-    expected: FAIL
-
-  [{m14: 1}]
-    expected: FAIL
-
-  [{m23: 1}]
-    expected: FAIL
-
-  [{m24: 1}]
-    expected: FAIL
-
-  [{m31: 1}]
-    expected: FAIL
-
-  [{m32: 1}]
-    expected: FAIL
-
-  [{m33: 0}]
-    expected: FAIL
-
-  [{m34: 1}]
-    expected: FAIL
-
-  [{m43: 1}]
-    expected: FAIL
-
-  [{m44: 0}]
-    expected: FAIL
-
-  [{is2D: false}]
-    expected: FAIL
-
-  [{is2D: null}]
-    expected: FAIL
-
+  prefs: [canvas.transform_extensions.enabled:true]
--- a/testing/web-platform/meta/html/dom/interfaces.html.ini
+++ b/testing/web-platform/meta/html/dom/interfaces.html.ini
@@ -2186,37 +2186,16 @@
     expected: FAIL
 
   [Document interface: new Document() must inherit property "onmousewheel" with the proper type (135)]
     expected: FAIL
 
   [Document interface: new Document() must inherit property "onsort" with the proper type (148)]
     expected: FAIL
 
-  [HTMLSlotElement interface: existence and properties of interface object]
-    expected: FAIL
-
-  [HTMLSlotElement interface object length]
-    expected: FAIL
-
-  [HTMLSlotElement interface object name]
-    expected: FAIL
-
-  [HTMLSlotElement interface: existence and properties of interface prototype object]
-    expected: FAIL
-
-  [HTMLSlotElement interface: existence and properties of interface prototype object's "constructor" property]
-    expected: FAIL
-
-  [HTMLSlotElement interface: attribute name]
-    expected: FAIL
-
-  [HTMLSlotElement interface: operation assignedNodes(AssignedNodesOptions)]
-    expected: FAIL
-
   [HTMLSlotElement must be primary interface of document.createElement("slot")]
     expected: FAIL
 
   [Stringification of document.createElement("slot")]
     expected: FAIL
 
   [HTMLSlotElement interface: document.createElement("slot") must inherit property "name" with the proper type (0)]
     expected: FAIL
@@ -2696,34 +2675,22 @@
     expected: FAIL
 
   [HTMLMediaElement interface: new Audio() must inherit property "audioTracks" with the proper type (38)]
     expected: FAIL
 
   [HTMLMediaElement interface: new Audio() must inherit property "videoTracks" with the proper type (39)]
     expected: FAIL
 
-  [CanvasRenderingContext2D interface: operation getTransform()]
-    expected: FAIL
-
-  [CanvasRenderingContext2D interface: operation setTransform(unrestricted double,unrestricted double,unrestricted double,unrestricted double,unrestricted double,unrestricted double)]
-    expected: FAIL
-
-  [CanvasRenderingContext2D interface: operation setTransform(DOMMatrixInit)]
-    expected: FAIL
-
   [CanvasRenderingContext2D interface: attribute imageSmoothingQuality]
     expected: FAIL
 
   [CanvasRenderingContext2D interface: operation clearHitRegions()]
     expected: FAIL
 
-  [CanvasRenderingContext2D interface: document.createElement("canvas").getContext("2d") must inherit property "getTransform" with the proper type (7)]
-    expected: FAIL
-
   [CanvasRenderingContext2D interface: document.createElement("canvas").getContext("2d") must inherit property "imageSmoothingQuality" with the proper type (14)]
     expected: FAIL
 
   [CanvasRenderingContext2D interface: document.createElement("canvas").getContext("2d") must inherit property "resetClip" with the proper type (35)]
     expected: FAIL
 
   [CanvasRenderingContext2D interface: document.createElement("canvas").getContext("2d") must inherit property "scrollPathIntoView" with the proper type (42)]
     expected: FAIL
@@ -2738,19 +2705,16 @@
     expected: FAIL
 
   [CanvasRenderingContext2D interface: document.createElement("canvas").getContext("2d") must inherit property "clearHitRegions" with the proper type (52)]
     expected: FAIL
 
   [CanvasRenderingContext2D interface: document.createElement("canvas").getContext("2d") must inherit property "direction" with the proper type (68)]
     expected: FAIL
 
-  [CanvasPattern interface: operation setTransform(DOMMatrixInit)]
-    expected: FAIL
-
   [Window interface: window must inherit property "oncancel" with the proper type (40)]
     expected: FAIL
 
   [Window interface: window must inherit property "oncuechange" with the proper type (47)]
     expected: FAIL
 
   [Window interface: window must inherit property "onmousewheel" with the proper type (78)]
     expected: FAIL
@@ -3899,43 +3863,31 @@
     expected: FAIL
 
   [HTMLCanvasElement interface: operation transferControlToOffscreen()]
     expected: FAIL
 
   [HTMLCanvasElement interface: document.createElement("canvas") must inherit property "transferControlToOffscreen()" with the proper type]
     expected: FAIL
 
-  [CanvasRenderingContext2D interface: operation setTransform(unrestricted double, unrestricted double, unrestricted double, unrestricted double, unrestricted double, unrestricted double)]
-    expected: FAIL
-
-  [CanvasRenderingContext2D interface: operation setTransform(DOMMatrix2DInit)]
-    expected: FAIL
-
-  [CanvasRenderingContext2D interface: document.createElement("canvas").getContext("2d") must inherit property "getTransform()" with the proper type]
-    expected: FAIL
-
   [CanvasRenderingContext2D interface: document.createElement("canvas").getContext("2d") must inherit property "imageSmoothingQuality" with the proper type]
     expected: FAIL
 
   [CanvasRenderingContext2D interface: document.createElement("canvas").getContext("2d") must inherit property "resetClip()" with the proper type]
     expected: FAIL
 
   [CanvasRenderingContext2D interface: document.createElement("canvas").getContext("2d") must inherit property "scrollPathIntoView()" with the proper type]
     expected: FAIL
 
   [CanvasRenderingContext2D interface: document.createElement("canvas").getContext("2d") must inherit property "scrollPathIntoView(Path2D)" with the proper type]
     expected: FAIL
 
   [CanvasRenderingContext2D interface: document.createElement("canvas").getContext("2d") must inherit property "direction" with the proper type]
     expected: FAIL
 
-  [CanvasPattern interface: operation setTransform(DOMMatrix2DInit)]
-    expected: FAIL
-
   [ImageBitmapRenderingContext interface: attribute canvas]
     expected: FAIL
 
   [OffscreenCanvas interface: existence and properties of interface object]
     expected: FAIL
 
   [OffscreenCanvas interface object length]
     expected: FAIL
@@ -4349,11 +4301,8 @@
     expected: FAIL
 
   [HTMLFrameSetElement interface: document.createElement("frameset") must inherit property "onrejectionhandled" with the proper type]
     expected: FAIL
 
   [HTMLFrameSetElement interface: document.createElement("frameset") must inherit property "onunhandledrejection" with the proper type]
     expected: FAIL
 
-  [Test driver]
-    expected: FAIL
-
--- a/testing/web-platform/tests/2dcontext/conformance-requirements/2d.missingargs.html
+++ b/testing/web-platform/tests/2dcontext/conformance-requirements/2d.missingargs.html
@@ -28,17 +28,16 @@ if (ctx.transform) { // (avoid spurious 
     assert_throws(new TypeError(), function() { ctx.transform(); });
     assert_throws(new TypeError(), function() { ctx.transform(1); });
     assert_throws(new TypeError(), function() { ctx.transform(1, 0); });
     assert_throws(new TypeError(), function() { ctx.transform(1, 0, 0); });
     assert_throws(new TypeError(), function() { ctx.transform(1, 0, 0, 1); });
     assert_throws(new TypeError(), function() { ctx.transform(1, 0, 0, 1, 0); });
 }
 if (ctx.setTransform) {
-    assert_throws(new TypeError(), function() { ctx.setTransform(); });
     assert_throws(new TypeError(), function() { ctx.setTransform(1); });
     assert_throws(new TypeError(), function() { ctx.setTransform(1, 0); });
     assert_throws(new TypeError(), function() { ctx.setTransform(1, 0, 0); });
     assert_throws(new TypeError(), function() { ctx.setTransform(1, 0, 0, 1); });
     assert_throws(new TypeError(), function() { ctx.setTransform(1, 0, 0, 1, 0); });
 }
 assert_throws(new TypeError(), function() { ctx.createLinearGradient(); });
 assert_throws(new TypeError(), function() { ctx.createLinearGradient(0); });
--- a/testing/web-platform/tests/css/geometry-1/DOMMatrix2DInit-validate-fixup.html
+++ b/testing/web-platform/tests/css/geometry-1/DOMMatrix2DInit-validate-fixup.html
@@ -5,38 +5,76 @@
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="support/dommatrix-test-util.js"></script>
 <canvas id=canvas hidden></canvas>
 <script>
 setup(() => {
   window.canvas = document.getElementById('canvas');
   window.ctx = canvas.getContext('2d');
+  window.ctx.fillStyle = '#000';
 });
 
+function clearCanvas(ctx) {
+  ctx.resetTransform();
+  ctx.clearRect(0, 0, window.canvas.width, window.canvas.height);
+}
+
+function drawRectWithSetTransform(ctx, transform) {
+  clearCanvas(ctx);
+  ctx.setTransform(transform);
+  ctx.fillRect(20, 20, 30, 30);
+  return window.canvas.toDataURL();
+}
+
+function drawRectWithAddPathTransform(ctx, transform) {
+  clearCanvas(ctx);
+  var path = new Path2D();
+  path.rect(20, 20, 30, 30);
+  var transformedPath = new Path2D();
+  if (transform === undefined) {
+    transformedPath.addPath(path);
+  } else {
+    transformedPath.addPath(path, transform);
+  }
+  ctx.fill(transformedPath);
+  return window.canvas.toDataURL();
+}
+
 [
   {a: 1, m11: 2},
   {b: 0, m12: -1},
   {c: Infinity, m21: -Infinity},
   {d: 0, m22: NaN},
   {e: 1, m41: 1.00000001},
   {f: 0, m42: Number.MIN_VALUE},
 ].forEach(dict => {
   test(() => {
     ctx.resetTransform();
     assert_throws(new TypeError(), () => ctx.setTransform(dict));
-  }, `${format_dict(dict)} (invalid)`);
+  }, `setTransform(${format_dict(dict)}) (invalid)`);
+
+  test(() => {
+    assert_throws(new TypeError(), () => drawRectWithAddPathTransform(ctx, dict));
+  }, `addPath(${format_dict(dict)}) (invalid)`);
 });
 
 test(() => {
   ctx.resetTransform();
   ctx.setTransform(1, 2, 3, 4, 5, 6);
   const matrix = ctx.getTransform();
   checkMatrix(matrix, matrix2D({m11: 1, m12: 2, m21: 3, m22: 4, m41: 5, m42: 6}));
-}, `Sanity check without dictionary`);
+}, `setTransform (Sanity check without dictionary)`);
+
+test(() => {
+  var ident = matrix2D({});
+  var expectedResultURL = drawRectWithSetTransform(ctx, ident);
+  var actualResultURL = drawRectWithAddPathTransform(ctx);
+  assert_equals(actualResultURL, expectedResultURL);
+}, `addPath (Sanity check without second parameter)`);
 
 [
   // Input dict that would throw if ignore3D was false
   [{m13: 1, is2D: true},           matrix2D({})],
   [{m14: 1, is2D: true},           matrix2D({})],
   [{m23: 1, is2D: true},           matrix2D({})],
   [{m24: 1, is2D: true},           matrix2D({})],
   [{m31: 1, is2D: true},           matrix2D({})],
@@ -52,20 +90,20 @@ test(() => {
   [{},                             matrix2D({})],
   [{is2D: undefined},              matrix2D({})],
   [{a: 1, m11: 1},                 matrix2D({m11: 1})],
   [{b: 0, m12: undefined},         matrix2D({m12: 0})],
   [{c: 0, m21: 0},                 matrix2D({m21: 0})],
   [{c: 0, m21: -0},                matrix2D({m21: -0})],
   [{c: -0, m21: 0},                matrix2D({m21: 0})],
   [{c: -0, m21: -0},               matrix2D({m21: -0})],
-  [{d: Infinity, m22: Infinity},   matrix2D({m22: Infinity})],
-  [{e: -Infinity, m41: -Infinity}, matrix2D({m41: -Infinity})],
-  [{f: NaN, m42: NaN},             matrix2D({m42: NaN})],
-  [{f: NaN, m42: NaN, is2D: true}, matrix2D({m42: NaN})],
+  [{d: Infinity, m22: Infinity},   matrix2D({})], // should be silently ignored
+  [{e: -Infinity, m41: -Infinity}, matrix2D({})], // should be silently ignored
+  [{f: NaN, m42: NaN},             matrix2D({})], // should be silently ignored
+  [{f: NaN, m42: NaN, is2D: true}, matrix2D({})], // should be silently ignored
   [{f: 0, m42: null},              matrix2D({m42: 0})], // null is converted to 0
   [{f: -0, m42: null},             matrix2D({m42: 0})], // null is converted to 0
   [{a: 2},                         matrix2D({m11: 2})],
   [{b: 2},                         matrix2D({m12: 2})],
   [{c: 2},                         matrix2D({m21: 2})],
   [{d: 2},                         matrix2D({m22: 2})],
   [{e: 2},                         matrix2D({m41: 2})],
   [{f: 2},                         matrix2D({m42: 2})],
@@ -129,11 +167,17 @@ test(() => {
   [{is2D: false},                  matrix2D({})],
   [{is2D: null},                   matrix2D({})],
 ].forEach(([dict, expected]) => {
   test(() => {
     ctx.resetTransform();
     ctx.setTransform(dict);
     const matrix = ctx.getTransform();
     checkMatrix(matrix, expected);
-  }, `${format_dict(dict)}`);
-});
+  }, `setTransform(${format_dict(dict)})`);
+
+  test(() => {
+    var expectedResultURL = drawRectWithSetTransform(ctx, expected);
+    var actualResultURL = drawRectWithAddPathTransform(ctx, expected);
+    assert_equals(actualResultURL, expectedResultURL);
+  }, `addPath(${format_dict(dict)})`);
+ });
 </script>
--- a/testing/web-platform/tests/html/dom/interfaces.html
+++ b/testing/web-platform/tests/html/dom/interfaces.html
@@ -27,17 +27,18 @@ setup(function() {
 function createInput(type) {
   var input = document.createElement('input');
   input.type = type;
   return input;
 }
 
 function doTest([html, dom, cssom, uievents, touchevents]) {
   var idlArray = new IdlArray();
-  idlArray.add_untested_idls(dom + cssom + uievents + touchevents);
+  var svg = "interface SVGElement : Element {};";
+  idlArray.add_untested_idls(dom + svg + cssom + uievents + touchevents);
   idlArray.add_idls(html);
 
   idlArray.add_objects({
     NodeList: ['document.getElementsByName("name")'],
     HTMLAllCollection: ['document.all'],
     HTMLFormControlsCollection: ['document.createElement("form").elements'],
     RadioNodeList: [],
     HTMLOptionsCollection: ['document.createElement("select").options'],