diff options
-rw-r--r-- | dom/base/DOMMatrix.cpp | 177 | ||||
-rw-r--r-- | dom/base/DOMMatrix.h | 23 | ||||
-rw-r--r-- | dom/base/WebKitCSSMatrix.cpp | 4 | ||||
-rw-r--r-- | dom/base/WebKitCSSMatrix.h | 3 | ||||
-rw-r--r-- | dom/bindings/Errors.msg | 2 | ||||
-rw-r--r-- | dom/webidl/DOMMatrix.webidl | 38 | ||||
-rw-r--r-- | dom/webidl/WebKitCSSMatrix.webidl | 3 |
7 files changed, 226 insertions, 24 deletions
diff --git a/dom/base/DOMMatrix.cpp b/dom/base/DOMMatrix.cpp index 0045e17d84..09c186e77e 100644 --- a/dom/base/DOMMatrix.cpp +++ b/dom/base/DOMMatrix.cpp @@ -17,6 +17,8 @@ #include <math.h> +#include "js/Equality.h" // JS::SameValueZero + namespace mozilla { namespace dom { @@ -37,6 +39,130 @@ DOMMatrixReadOnly::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) return DOMMatrixReadOnlyBinding::Wrap(aCx, this, aGivenProto); } +// https://drafts.fxtf.org/geometry/#matrix-validate-and-fixup-2d +static bool +ValidateAndFixupMatrix2DInit(DOMMatrix2DInit& aMatrixInit, ErrorResult& aRv) +{ +#define ValidateAliases(field, alias, fieldName, aliasName) \ + if ((field).WasPassed() && (alias).WasPassed() && \ + !JS::SameValueZero((field).Value(), (alias).Value())) { \ + aRv.ThrowTypeError<MSG_MATRIX_INIT_CONFLICTING_VALUE>((fieldName), \ + (aliasName)); \ + return false; \ + } +#define SetFromAliasOrDefault(field, alias, defaultValue) \ + if (!(field).WasPassed()) { \ + if ((alias).WasPassed()) { \ + (field).Construct((alias).Value()); \ + } else { \ + (field).Construct(defaultValue); \ + } \ + } +#define ValidateAndSet(field, alias, fieldName, aliasName, defaultValue) \ + ValidateAliases((field), (alias), NS_LITERAL_STRING(fieldName), \ + NS_LITERAL_STRING(aliasName)); \ + SetFromAliasOrDefault((field), (alias), (defaultValue)); + + ValidateAndSet(aMatrixInit.mM11, aMatrixInit.mA, "m11", "a", 1); + ValidateAndSet(aMatrixInit.mM12, aMatrixInit.mB, "m12", "b", 0); + ValidateAndSet(aMatrixInit.mM21, aMatrixInit.mC, "m21", "c", 0); + ValidateAndSet(aMatrixInit.mM22, aMatrixInit.mD, "m22", "d", 1); + ValidateAndSet(aMatrixInit.mM41, aMatrixInit.mE, "m41", "e", 0); + ValidateAndSet(aMatrixInit.mM42, aMatrixInit.mF, "m42", "f", 0); + + return true; + +#undef ValidateAliases +#undef SetFromAliasOrDefault +#undef ValidateAndSet +} + +// https://drafts.fxtf.org/geometry/#matrix-validate-and-fixup +static bool +ValidateAndFixupMatrixInit(DOMMatrixInit& aMatrixInit, ErrorResult& aRv) +{ +#define Check3DField(field, fieldName, defaultValue) \ + if ((field) != (defaultValue)) { \ + if (!aMatrixInit.mIs2D.WasPassed()) { \ + aMatrixInit.mIs2D.Construct(false); \ + return true; \ + } \ + if (aMatrixInit.mIs2D.Value()) { \ + aRv.ThrowTypeError<MSG_MATRIX_INIT_EXCEEDS_2D>( \ + NS_LITERAL_STRING(fieldName)); \ + return false; \ + } \ + } + + if (!ValidateAndFixupMatrix2DInit(aMatrixInit, aRv)) { + return false; + } + + Check3DField(aMatrixInit.mM13, "m13", 0); + Check3DField(aMatrixInit.mM14, "m14", 0); + Check3DField(aMatrixInit.mM23, "m23", 0); + Check3DField(aMatrixInit.mM24, "m24", 0); + Check3DField(aMatrixInit.mM31, "m31", 0); + Check3DField(aMatrixInit.mM32, "m32", 0); + Check3DField(aMatrixInit.mM34, "m34", 0); + Check3DField(aMatrixInit.mM43, "m43", 0); + Check3DField(aMatrixInit.mM33, "m33", 1); + Check3DField(aMatrixInit.mM44, "m44", 1); + + if (!aMatrixInit.mIs2D.WasPassed()) { + aMatrixInit.mIs2D.Construct(true); + } + return true; + +#undef Check3DField +} + +void +DOMMatrixReadOnly::SetDataFromMatrixInit(DOMMatrixInit& aMatrixInit) +{ + const bool is2D = aMatrixInit.mIs2D.Value(); + MOZ_ASSERT(is2D == Is2D()); + if (is2D) { + mMatrix2D->_11 = aMatrixInit.mM11.Value(); + mMatrix2D->_12 = aMatrixInit.mM12.Value(); + mMatrix2D->_21 = aMatrixInit.mM21.Value(); + mMatrix2D->_22 = aMatrixInit.mM22.Value(); + mMatrix2D->_31 = aMatrixInit.mM41.Value(); + mMatrix2D->_32 = aMatrixInit.mM42.Value(); + } else { + mMatrix3D->_11 = aMatrixInit.mM11.Value(); + mMatrix3D->_12 = aMatrixInit.mM12.Value(); + mMatrix3D->_13 = aMatrixInit.mM13; + mMatrix3D->_14 = aMatrixInit.mM14; + mMatrix3D->_21 = aMatrixInit.mM21.Value(); + mMatrix3D->_22 = aMatrixInit.mM22.Value(); + mMatrix3D->_23 = aMatrixInit.mM23; + mMatrix3D->_24 = aMatrixInit.mM24; + mMatrix3D->_31 = aMatrixInit.mM31; + mMatrix3D->_32 = aMatrixInit.mM32; + mMatrix3D->_33 = aMatrixInit.mM33; + mMatrix3D->_34 = aMatrixInit.mM34; + mMatrix3D->_41 = aMatrixInit.mM41.Value(); + mMatrix3D->_42 = aMatrixInit.mM42.Value(); + mMatrix3D->_43 = aMatrixInit.mM43; + mMatrix3D->_44 = aMatrixInit.mM44; + } +} + +already_AddRefed<DOMMatrixReadOnly> +DOMMatrixReadOnly::FromMatrix(const GlobalObject& aGlobal, const DOMMatrixInit& aMatrixInit, ErrorResult& aRv) +{ + DOMMatrixInit matrixInit(aMatrixInit); + if (!ValidateAndFixupMatrixInit(matrixInit, aRv)) { + return nullptr; + }; + + RefPtr<DOMMatrixReadOnly> rval = + new DOMMatrixReadOnly(aGlobal.GetAsSupports(), matrixInit.mIs2D.Value()); + rval->SetDataFromMatrixInit(matrixInit); + return rval.forget(); +} + already_AddRefed<DOMMatrixReadOnly> DOMMatrixReadOnly::Constructor( const GlobalObject& aGlobal, @@ -182,10 +308,10 @@ DOMMatrixReadOnly::SkewY(double aSy) const } already_AddRefed<DOMMatrix> -DOMMatrixReadOnly::Multiply(const DOMMatrix& other) const +DOMMatrixReadOnly::Multiply(const DOMMatrixInit& other, ErrorResult& aRv) const { RefPtr<DOMMatrix> retval = new DOMMatrix(mParent, *this); - retval->MultiplySelf(other); + retval->MultiplySelf(other, aRv); return retval.forget(); } @@ -427,6 +553,27 @@ DOMMatrixReadOnly::ReadStructuredCloneElements(JSStructuredCloneReader* aReader, } already_AddRefed<DOMMatrix> +DOMMatrix::FromMatrix(nsISupports* aParent, const DOMMatrixInit& aMatrixInit, ErrorResult& aRv) +{ + DOMMatrixInit matrixInit(aMatrixInit); + if (!ValidateAndFixupMatrixInit(matrixInit, aRv)) { + return nullptr; + }; + + RefPtr<DOMMatrix> matrix = new DOMMatrix(aParent, matrixInit.mIs2D.Value()); + matrix->SetDataFromMatrixInit(matrixInit); + return matrix.forget(); +} + +already_AddRefed<DOMMatrix> +DOMMatrix::FromMatrix(const GlobalObject& aGlobal, const DOMMatrixInit& aMatrixInit, ErrorResult& aRv) +{ + RefPtr<DOMMatrix> matrix = + FromMatrix(aGlobal.GetAsSupports(), aMatrixInit, aRv); + return matrix.forget(); +} + +already_AddRefed<DOMMatrix> DOMMatrix::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv) { RefPtr<DOMMatrix> obj = new DOMMatrix(aGlobal.GetAsSupports()); @@ -546,42 +693,44 @@ DOMMatrixReadOnly::Ensure3DMatrix() } DOMMatrix* -DOMMatrix::MultiplySelf(const DOMMatrix& aOther) +DOMMatrix::MultiplySelf(const DOMMatrixInit& aOtherInit, ErrorResult& aRv) { - if (aOther.Identity()) { + RefPtr<DOMMatrix> other = FromMatrix(mParent, aOtherInit, aRv); + if (other->Identity()) { return this; } - if (aOther.Is2D()) { + if (other->Is2D()) { if (mMatrix3D) { - *mMatrix3D = gfx::Matrix4x4::From2D(*aOther.mMatrix2D) * *mMatrix3D; + *mMatrix3D = gfx::Matrix4x4::From2D(*other->mMatrix2D) * *mMatrix3D; } else { - *mMatrix2D = *aOther.mMatrix2D * *mMatrix2D; + *mMatrix2D = *other->mMatrix2D * *mMatrix2D; } } else { Ensure3DMatrix(); - *mMatrix3D = *aOther.mMatrix3D * *mMatrix3D; + *mMatrix3D = *other->mMatrix3D * *mMatrix3D; } return this; } DOMMatrix* -DOMMatrix::PreMultiplySelf(const DOMMatrix& aOther) +DOMMatrix::PreMultiplySelf(const DOMMatrixInit& aOtherInit, ErrorResult& aRv) { - if (aOther.Identity()) { + RefPtr<DOMMatrix> other = FromMatrix(mParent, aOtherInit, aRv); + if (other->Identity()) { return this; } - if (aOther.Is2D()) { + if (other->Is2D()) { if (mMatrix3D) { - *mMatrix3D = *mMatrix3D * gfx::Matrix4x4::From2D(*aOther.mMatrix2D); + *mMatrix3D = *mMatrix3D * gfx::Matrix4x4::From2D(*other->mMatrix2D); } else { - *mMatrix2D = *mMatrix2D * *aOther.mMatrix2D; + *mMatrix2D = *mMatrix2D * *other->mMatrix2D; } } else { Ensure3DMatrix(); - *mMatrix3D = *mMatrix3D * *aOther.mMatrix3D; + *mMatrix3D = *mMatrix3D * *other->mMatrix3D; } return this; diff --git a/dom/base/DOMMatrix.h b/dom/base/DOMMatrix.h index fe1325c594..9bbdef688f 100644 --- a/dom/base/DOMMatrix.h +++ b/dom/base/DOMMatrix.h @@ -25,6 +25,7 @@ class DOMMatrix; class DOMPoint; class StringOrUnrestrictedDoubleSequence; struct DOMPointInit; +struct DOMMatrixInit; class DOMMatrixReadOnly : public nsWrapperCache { @@ -57,6 +58,9 @@ public: virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> aGivenProto) override; static already_AddRefed<DOMMatrixReadOnly> + FromMatrix(const GlobalObject& aGlobal, const DOMMatrixInit& aMatrixInit, ErrorResult& aRv); + + static already_AddRefed<DOMMatrixReadOnly> Constructor(const GlobalObject& aGlobal, const Optional<StringOrUnrestrictedDoubleSequence>& aArg, ErrorResult& aRv); static already_AddRefed<DOMMatrixReadOnly> @@ -180,7 +184,8 @@ public: double aAngle) const; already_AddRefed<DOMMatrix> SkewX(double aSx) const; already_AddRefed<DOMMatrix> SkewY(double aSy) const; - already_AddRefed<DOMMatrix> Multiply(const DOMMatrix& aOther) const; + already_AddRefed<DOMMatrix> Multiply(const DOMMatrixInit& aOther, + ErrorResult& aRv) const; already_AddRefed<DOMMatrix> FlipX() const; already_AddRefed<DOMMatrix> FlipY() const; already_AddRefed<DOMMatrix> Inverse() const; @@ -204,6 +209,13 @@ protected: virtual ~DOMMatrixReadOnly() {} + /** + * Sets data from a fully validated and fixed-up matrix init, + * where all of its members are properly defined. + * The init dictionary's dimension must match the matrix one. + */ + void SetDataFromMatrixInit(DOMMatrixInit& aMatrixInit); + DOMMatrixReadOnly* SetMatrixValue(const nsAString& aTransformList, ErrorResult& aRv); void Ensure3DMatrix(); @@ -237,6 +249,11 @@ public: {} static already_AddRefed<DOMMatrix> + FromMatrix(nsISupports* aParent, const DOMMatrixInit& aMatrixInit, ErrorResult& aRv); + static already_AddRefed<DOMMatrix> + FromMatrix(const GlobalObject& aGlobal, const DOMMatrixInit& aMatrixInit, ErrorResult& aRv); + + static already_AddRefed<DOMMatrix> Constructor(const GlobalObject& aGlobal, ErrorResult& aRv); static already_AddRefed<DOMMatrix> Constructor(const GlobalObject& aGlobal, const nsAString& aTransformList, ErrorResult& aRv); @@ -254,8 +271,8 @@ public: virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override; - DOMMatrix* MultiplySelf(const DOMMatrix& aOther); - DOMMatrix* PreMultiplySelf(const DOMMatrix& aOther); + DOMMatrix* MultiplySelf(const DOMMatrixInit& aOther, ErrorResult& aRv); + DOMMatrix* PreMultiplySelf(const DOMMatrixInit& aOther, ErrorResult& aRv); DOMMatrix* TranslateSelf(double aTx, double aTy, double aTz = 0); diff --git a/dom/base/WebKitCSSMatrix.cpp b/dom/base/WebKitCSSMatrix.cpp index fe26b74554..003fdfea30 100644 --- a/dom/base/WebKitCSSMatrix.cpp +++ b/dom/base/WebKitCSSMatrix.cpp @@ -115,10 +115,10 @@ WebKitCSSMatrix::SetMatrixValue(const nsAString& aTransformList, } already_AddRefed<WebKitCSSMatrix> -WebKitCSSMatrix::Multiply(const WebKitCSSMatrix& other) const +WebKitCSSMatrix::Multiply(const DOMMatrixInit& aOtherInit, ErrorResult& aRv) const { RefPtr<WebKitCSSMatrix> retval = new WebKitCSSMatrix(mParent, *this); - retval->MultiplySelf(other); + retval->MultiplySelf(aOtherInit, aRv); return retval.forget(); } diff --git a/dom/base/WebKitCSSMatrix.h b/dom/base/WebKitCSSMatrix.h index e50c617260..590548b767 100644 --- a/dom/base/WebKitCSSMatrix.h +++ b/dom/base/WebKitCSSMatrix.h @@ -40,7 +40,8 @@ public: WebKitCSSMatrix* SetMatrixValue(const nsAString& aTransformList, ErrorResult& aRv); - already_AddRefed<WebKitCSSMatrix> Multiply(const WebKitCSSMatrix& aOther) const; + already_AddRefed<WebKitCSSMatrix> Multiply(const DOMMatrixInit& aOtherInit, + ErrorResult& aRv) const; already_AddRefed<WebKitCSSMatrix> Inverse(ErrorResult& aRv) const; already_AddRefed<WebKitCSSMatrix> Translate(double aTx, double aTy, diff --git a/dom/bindings/Errors.msg b/dom/bindings/Errors.msg index b40dc239d5..d22ef2c27f 100644 --- a/dom/bindings/Errors.msg +++ b/dom/bindings/Errors.msg @@ -100,6 +100,8 @@ MSG_DEF(MSG_TIME_VALUE_OUT_OF_RANGE, 1, JSEXN_TYPEERR, "{0} is outside the suppo 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_CACHE_OPEN_FAILED, 0, JSEXN_TYPEERR, "CacheStorage.open() failed to access the storage system.") +MSG_DEF(MSG_MATRIX_INIT_CONFLICTING_VALUE, 2, JSEXN_TYPEERR, "Matrix init unexpectedly got different values for '{0}' and '{1}'.") +MSG_DEF(MSG_MATRIX_INIT_EXCEEDS_2D, 1, JSEXN_TYPEERR, "Matrix init has an unexpected 3D element '{0}' which cannot coexist with 'is2D: true'.") MSG_DEF(MSG_MATRIX_INIT_LENGTH_WRONG, 1, JSEXN_TYPEERR, "Matrix init sequence must have a length of 6 or 16 (actual value: {0})") MSG_DEF(MSG_NO_NEGATIVE_ATTR, 1, JSEXN_TYPEERR, "Given attribute {0} cannot be negative.") MSG_DEF(MSG_PMO_NO_SEPARATE_ENDMARK, 0, JSEXN_TYPEERR, "Cannot provide separate endMark argument if PerformanceMeasureOptions argument is given.") diff --git a/dom/webidl/DOMMatrix.webidl b/dom/webidl/DOMMatrix.webidl index 68c70507b7..bf65da35a9 100644 --- a/dom/webidl/DOMMatrix.webidl +++ b/dom/webidl/DOMMatrix.webidl @@ -13,6 +13,8 @@ [Constructor(optional (DOMString or sequence<unrestricted double>) init), Exposed=(Window,Worker)] interface DOMMatrixReadOnly { + [NewObject, Throws] static DOMMatrixReadOnly fromMatrix(optional DOMMatrixInit other); + // These attributes are simple aliases for certain elements of the 4x4 matrix readonly attribute unrestricted double a; readonly attribute unrestricted double b; @@ -66,7 +68,7 @@ interface DOMMatrixReadOnly { unrestricted double angle); DOMMatrix skewX(unrestricted double sx); DOMMatrix skewY(unrestricted double sy); - DOMMatrix multiply(DOMMatrix other); + [NewObject, Throws] DOMMatrix multiply(optional DOMMatrixInit other); DOMMatrix flipX(); DOMMatrix flipY(); DOMMatrix inverse(); @@ -88,6 +90,8 @@ interface DOMMatrixReadOnly { Constructor(sequence<unrestricted double> numberSequence), Exposed=(Window,Worker)] interface DOMMatrix : DOMMatrixReadOnly { + [NewObject, Throws] static DOMMatrix fromMatrix(optional DOMMatrixInit other); + // These attributes are simple aliases for certain elements of the 4x4 matrix inherit attribute unrestricted double a; inherit attribute unrestricted double b; @@ -114,8 +118,8 @@ interface DOMMatrix : DOMMatrixReadOnly { inherit attribute unrestricted double m44; // Mutable transform methods - DOMMatrix multiplySelf(DOMMatrix other); - DOMMatrix preMultiplySelf(DOMMatrix other); + [Throws] DOMMatrix multiplySelf(optional DOMMatrixInit other); + [Throws] DOMMatrix preMultiplySelf(optional DOMMatrixInit other); DOMMatrix translateSelf(unrestricted double tx, unrestricted double ty, optional unrestricted double tz = 0); @@ -147,3 +151,31 @@ interface DOMMatrix : DOMMatrixReadOnly { [Exposed=Window, 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; +}; diff --git a/dom/webidl/WebKitCSSMatrix.webidl b/dom/webidl/WebKitCSSMatrix.webidl index 8115711a33..e939d37acf 100644 --- a/dom/webidl/WebKitCSSMatrix.webidl +++ b/dom/webidl/WebKitCSSMatrix.webidl @@ -18,7 +18,8 @@ interface WebKitCSSMatrix : DOMMatrix { WebKitCSSMatrix setMatrixValue(DOMString transformList); // Immutable transform methods - WebKitCSSMatrix multiply(WebKitCSSMatrix other); + [Throws] + WebKitCSSMatrix multiply(optional DOMMatrixInit other); [Throws] WebKitCSSMatrix inverse(); WebKitCSSMatrix translate(optional unrestricted double tx = 0, |