diff options
Diffstat (limited to 'dom')
27 files changed, 1183 insertions, 324 deletions
diff --git a/dom/base/DOMMatrix.cpp b/dom/base/DOMMatrix.cpp index 72c8d9b76b..f0358125f8 100644 --- a/dom/base/DOMMatrix.cpp +++ b/dom/base/DOMMatrix.cpp @@ -17,9 +17,15 @@ #include <math.h> +#include "js/Equality.h" // JS::SameValueZero + namespace mozilla { namespace dom { +template <typename T> +static void +SetDataInMatrix(DOMMatrixReadOnly* aMatrix, const T* aData, int aLength, ErrorResult& aRv); + static const double radPerDegree = 2.0 * M_PI / 360.0; NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DOMMatrixReadOnly, mParent) @@ -27,6 +33,210 @@ NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DOMMatrixReadOnly, mParent) NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(DOMMatrixReadOnly, AddRef) NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(DOMMatrixReadOnly, Release) +JSObject* +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::FromFloat32Array(const GlobalObject& aGlobal, const Float32Array& aArray32, ErrorResult& aRv) +{ + aArray32.ComputeLengthAndData(); + + const int length = aArray32.Length(); + const bool is2D = length == 6; + RefPtr<DOMMatrixReadOnly> obj = + new DOMMatrixReadOnly(aGlobal.GetAsSupports(), is2D); + SetDataInMatrix(obj, aArray32.Data(), length, aRv); + + return obj.forget(); +} + +already_AddRefed<DOMMatrixReadOnly> +DOMMatrixReadOnly::FromFloat64Array(const GlobalObject& aGlobal, const Float64Array& aArray64, ErrorResult& aRv) +{ + aArray64.ComputeLengthAndData(); + + const int length = aArray64.Length(); + const bool is2D = length == 6; + RefPtr<DOMMatrixReadOnly> obj = + new DOMMatrixReadOnly(aGlobal.GetAsSupports(), is2D); + SetDataInMatrix(obj, aArray64.Data(), length, aRv); + + return obj.forget(); +} + +already_AddRefed<DOMMatrixReadOnly> +DOMMatrixReadOnly::Constructor( + const GlobalObject& aGlobal, + const Optional<StringOrUnrestrictedDoubleSequence>& aArg, + ErrorResult& aRv) +{ + RefPtr<DOMMatrixReadOnly> rval = new DOMMatrixReadOnly(aGlobal.GetAsSupports()); + if (!aArg.WasPassed()) { + return rval.forget(); + } + + const auto& arg = aArg.Value(); + if (arg.IsString()) { + nsCOMPtr<nsPIDOMWindowInner> win = do_QueryInterface(aGlobal.GetAsSupports()); + if (!win) { + aRv.ThrowTypeError<MSG_ILLEGAL_CONSTRUCTOR>(); + return nullptr; + } + rval->SetMatrixValue(arg.GetAsString(), aRv); + } else { + const auto& sequence = arg.GetAsUnrestrictedDoubleSequence(); + SetDataInMatrix(rval, sequence.Elements(), sequence.Length(), aRv); + } + + return rval.forget(); +} + +already_AddRefed<DOMMatrixReadOnly> +DOMMatrixReadOnly::ReadStructuredClone(nsISupports* aParent, JSStructuredCloneReader* aReader) +{ + uint8_t is2D; + + if (!JS_ReadBytes(aReader, &is2D, 1)) { + return nullptr; + } + + RefPtr<DOMMatrixReadOnly> rval = new DOMMatrixReadOnly(aParent, is2D); + + if (!ReadStructuredCloneElements(aReader, rval)) { + return nullptr; + }; + + return rval.forget(); +} + already_AddRefed<DOMMatrix> DOMMatrixReadOnly::Translate(double aTx, double aTy, @@ -127,10 +337,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(); } @@ -307,6 +517,117 @@ DOMMatrixReadOnly::Stringify(nsAString& aResult) aResult = matrixStr; } +// https://drafts.fxtf.org/geometry/#structured-serialization +bool +DOMMatrixReadOnly::WriteStructuredClone(JSStructuredCloneWriter* aWriter) const +{ +#define WriteFloatPair(f1, f2) \ + JS_WriteUint32Pair(aWriter, BitwiseCast<uint32_t>(f1), \ + BitwiseCast<uint32_t>(f2)) + + const uint8_t is2D = Is2D(); + + if (!JS_WriteBytes(aWriter, &is2D, 1)) { + return false; + } + + if (is2D == 1) { + return WriteFloatPair(mMatrix2D->_11, mMatrix2D->_12) && + WriteFloatPair(mMatrix2D->_21, mMatrix2D->_22) && + WriteFloatPair(mMatrix2D->_31, mMatrix2D->_32); + } + + return WriteFloatPair(mMatrix3D->_11, mMatrix3D->_12) && + WriteFloatPair(mMatrix3D->_13, mMatrix3D->_14) && + WriteFloatPair(mMatrix3D->_21, mMatrix3D->_22) && + WriteFloatPair(mMatrix3D->_23, mMatrix3D->_24) && + WriteFloatPair(mMatrix3D->_31, mMatrix3D->_32) && + WriteFloatPair(mMatrix3D->_33, mMatrix3D->_34) && + WriteFloatPair(mMatrix3D->_41, mMatrix3D->_42) && + WriteFloatPair(mMatrix3D->_43, mMatrix3D->_44); +#undef WriteFloatPair +} + +bool +DOMMatrixReadOnly::ReadStructuredCloneElements(JSStructuredCloneReader* aReader, DOMMatrixReadOnly* matrix) +{ + uint32_t high; + uint32_t low; + +#define ReadFloatPair(f1, f2) \ + if (!JS_ReadUint32Pair(aReader, &high, &low)) { \ + return false; \ + } \ + (*(f1) = BitwiseCast<float>(high)); \ + (*(f2) = BitwiseCast<float>(low)); + + if (matrix->Is2D() == 1) { + ReadFloatPair(&(matrix->mMatrix2D->_11), &(matrix->mMatrix2D->_12)); + ReadFloatPair(&(matrix->mMatrix2D->_21), &(matrix->mMatrix2D->_22)); + ReadFloatPair(&(matrix->mMatrix2D->_31), &(matrix->mMatrix2D->_32)); + } else { + ReadFloatPair(&(matrix->mMatrix3D->_11), &(matrix->mMatrix3D->_12)); + ReadFloatPair(&(matrix->mMatrix3D->_13), &(matrix->mMatrix3D->_14)); + ReadFloatPair(&(matrix->mMatrix3D->_21), &(matrix->mMatrix3D->_22)); + ReadFloatPair(&(matrix->mMatrix3D->_23), &(matrix->mMatrix3D->_24)); + ReadFloatPair(&(matrix->mMatrix3D->_31), &(matrix->mMatrix3D->_32)); + ReadFloatPair(&(matrix->mMatrix3D->_33), &(matrix->mMatrix3D->_34)); + ReadFloatPair(&(matrix->mMatrix3D->_41), &(matrix->mMatrix3D->_42)); + ReadFloatPair(&(matrix->mMatrix3D->_43), &(matrix->mMatrix3D->_44)); + } + + return true; + +#undef ReadFloatPair +} + +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::FromFloat32Array(const GlobalObject& aGlobal, const Float32Array& aArray32, ErrorResult& aRv) +{ + aArray32.ComputeLengthAndData(); + + const int length = aArray32.Length(); + const bool is2D = length == 6; + RefPtr<DOMMatrix> obj = new DOMMatrix(aGlobal.GetAsSupports(), is2D); + SetDataInMatrix(obj, aArray32.Data(), length, aRv); + + return obj.forget(); +} + +already_AddRefed<DOMMatrix> +DOMMatrix::FromFloat64Array(const GlobalObject& aGlobal, const Float64Array& aArray64, ErrorResult& aRv) +{ + aArray64.ComputeLengthAndData(); + + const int length = aArray64.Length(); + const bool is2D = length == 6; + RefPtr<DOMMatrix> obj = new DOMMatrix(aGlobal.GetAsSupports(), is2D); + SetDataInMatrix(obj, aArray64.Data(), length, aRv); + + return obj.forget(); +} + already_AddRefed<DOMMatrix> DOMMatrix::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv) { @@ -317,6 +638,11 @@ DOMMatrix::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv) already_AddRefed<DOMMatrix> DOMMatrix::Constructor(const GlobalObject& aGlobal, const nsAString& aTransformList, ErrorResult& aRv) { + nsCOMPtr<nsPIDOMWindowInner> win = do_QueryInterface(aGlobal.GetAsSupports()); + if (!win) { + aRv.ThrowTypeError<MSG_ILLEGAL_CONSTRUCTOR>(); + return nullptr; + } RefPtr<DOMMatrix> obj = new DOMMatrix(aGlobal.GetAsSupports()); obj = obj->SetMatrixValue(aTransformList, aRv); @@ -330,7 +656,9 @@ DOMMatrix::Constructor(const GlobalObject& aGlobal, const DOMMatrixReadOnly& aOt return obj.forget(); } -template <typename T> void SetDataInMatrix(DOMMatrix* aMatrix, const T* aData, int aLength, ErrorResult& aRv) +template <typename T> +static void +SetDataInMatrix(DOMMatrixReadOnly* aMatrix, const T* aData, int aLength, ErrorResult& aRv) { if (aLength == 16) { aMatrix->SetM11(aData[0]); @@ -357,28 +685,22 @@ template <typename T> void SetDataInMatrix(DOMMatrix* aMatrix, const T* aData, i aMatrix->SetE(aData[4]); aMatrix->SetF(aData[5]); } else { - aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR); + nsAutoString lengthStr; + lengthStr.AppendInt(aLength); + aRv.ThrowTypeError<MSG_MATRIX_INIT_LENGTH_WRONG>(lengthStr); } } already_AddRefed<DOMMatrix> DOMMatrix::Constructor(const GlobalObject& aGlobal, const Float32Array& aArray32, ErrorResult& aRv) { - RefPtr<DOMMatrix> obj = new DOMMatrix(aGlobal.GetAsSupports()); - aArray32.ComputeLengthAndData(); - SetDataInMatrix(obj, aArray32.Data(), aArray32.Length(), aRv); - - return obj.forget(); + return FromFloat32Array(aGlobal, aArray32, aRv); } already_AddRefed<DOMMatrix> DOMMatrix::Constructor(const GlobalObject& aGlobal, const Float64Array& aArray64, ErrorResult& aRv) { - RefPtr<DOMMatrix> obj = new DOMMatrix(aGlobal.GetAsSupports()); - aArray64.ComputeLengthAndData(); - SetDataInMatrix(obj, aArray64.Data(), aArray64.Length(), aRv); - - return obj.forget(); + return FromFloat64Array(aGlobal, aArray64, aRv); } already_AddRefed<DOMMatrix> @@ -390,7 +712,26 @@ DOMMatrix::Constructor(const GlobalObject& aGlobal, const Sequence<double>& aNum return obj.forget(); } -void DOMMatrix::Ensure3DMatrix() +already_AddRefed<DOMMatrix> +DOMMatrix::ReadStructuredClone(nsISupports* aParent, JSStructuredCloneReader* aReader) +{ + uint8_t is2D; + + if (!JS_ReadBytes(aReader, &is2D, 1)) { + return nullptr; + } + + RefPtr<DOMMatrix> rval = new DOMMatrix(aParent, is2D); + + if (!ReadStructuredCloneElements(aReader, rval)) { + return nullptr; + }; + + return rval.forget(); +} + +void +DOMMatrixReadOnly::Ensure3DMatrix() { if (!mMatrix3D) { mMatrix3D = new gfx::Matrix4x4(gfx::Matrix4x4::From2D(*mMatrix2D)); @@ -399,42 +740,44 @@ void DOMMatrix::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; @@ -617,8 +960,8 @@ DOMMatrix::InvertSelf() return this; } -DOMMatrix* -DOMMatrix::SetMatrixValue(const nsAString& aTransformList, ErrorResult& aRv) +DOMMatrixReadOnly* +DOMMatrixReadOnly::SetMatrixValue(const nsAString& aTransformList, ErrorResult& aRv) { SVGTransformListParser parser(aTransformList); if (!parser.Parse()) { @@ -644,6 +987,13 @@ DOMMatrix::SetMatrixValue(const nsAString& aTransformList, ErrorResult& aRv) return this; } +DOMMatrix* +DOMMatrix::SetMatrixValue(const nsAString& aTransformList, ErrorResult& aRv) +{ + DOMMatrixReadOnly::SetMatrixValue(aTransformList, aRv); + return this; +} + JSObject* DOMMatrix::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) { diff --git a/dom/base/DOMMatrix.h b/dom/base/DOMMatrix.h index a9c52fa8c3..99e7714add 100644 --- a/dom/base/DOMMatrix.h +++ b/dom/base/DOMMatrix.h @@ -6,6 +6,7 @@ #ifndef MOZILLA_DOM_DOMMATRIX_H_ #define MOZILLA_DOM_DOMMATRIX_H_ +#include "js/StructuredClone.h" #include "nsWrapperCache.h" #include "nsISupports.h" #include "nsCycleCollectionParticipant.h" @@ -22,7 +23,9 @@ namespace dom { class GlobalObject; class DOMMatrix; class DOMPoint; +class StringOrUnrestrictedDoubleSequence; struct DOMPointInit; +struct DOMMatrixInit; class DOMMatrixReadOnly : public nsWrapperCache { @@ -42,9 +45,36 @@ public: } } + DOMMatrixReadOnly(nsISupports* aParent, const gfx::Matrix4x4& aMatrix) + : mParent(aParent) + { + mMatrix3D = new gfx::Matrix4x4(aMatrix); + } + NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(DOMMatrixReadOnly) NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(DOMMatrixReadOnly) + nsISupports* GetParentObject() const { return mParent; } + 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> + FromFloat32Array(const GlobalObject& aGlobal, const Float32Array& aArray32, ErrorResult& aRv); + + static already_AddRefed<DOMMatrixReadOnly> + FromFloat64Array(const GlobalObject& aGlobal, const Float64Array& aArray64, ErrorResult& aRv); + + static already_AddRefed<DOMMatrixReadOnly> + Constructor(const GlobalObject& aGlobal, const Optional<StringOrUnrestrictedDoubleSequence>& aArg, ErrorResult& aRv); + + static already_AddRefed<DOMMatrixReadOnly> + ReadStructuredClone(nsISupports* aParent, JSStructuredCloneReader* aReader); + + static bool + ReadStructuredCloneElements(JSStructuredCloneReader* aReader, DOMMatrixReadOnly* matrix); + #define GetMatrixMember(entry2D, entry3D, default) \ { \ if (mMatrix3D) { \ @@ -88,6 +118,51 @@ public: #undef GetMatrixMember #undef Get3DMatrixMember + // Defined here so we can construct DOMMatrixReadOnly objects. +#define Set2DMatrixMember(entry2D, entry3D) \ +{ \ + if (mMatrix3D) { \ + mMatrix3D->entry3D = v; \ + } else { \ + mMatrix2D->entry2D = v; \ + } \ +} + +#define Set3DMatrixMember(entry3D, default) \ +{ \ + if (mMatrix3D || (v != default)) { \ + Ensure3DMatrix(); \ + mMatrix3D->entry3D = v; \ + } \ +} + + void SetA(double v) Set2DMatrixMember(_11, _11) + void SetB(double v) Set2DMatrixMember(_12, _12) + void SetC(double v) Set2DMatrixMember(_21, _21) + void SetD(double v) Set2DMatrixMember(_22, _22) + void SetE(double v) Set2DMatrixMember(_31, _41) + void SetF(double v) Set2DMatrixMember(_32, _42) + + void SetM11(double v) Set2DMatrixMember(_11, _11) + void SetM12(double v) Set2DMatrixMember(_12, _12) + void SetM13(double v) Set3DMatrixMember(_13, 0) + void SetM14(double v) Set3DMatrixMember(_14, 0) + void SetM21(double v) Set2DMatrixMember(_21, _21) + void SetM22(double v) Set2DMatrixMember(_22, _22) + void SetM23(double v) Set3DMatrixMember(_23, 0) + void SetM24(double v) Set3DMatrixMember(_24, 0) + void SetM31(double v) Set3DMatrixMember(_31, 0) + void SetM32(double v) Set3DMatrixMember(_32, 0) + void SetM33(double v) Set3DMatrixMember(_33, 1.0) + void SetM34(double v) Set3DMatrixMember(_34, 0) + void SetM41(double v) Set2DMatrixMember(_31, _41) + void SetM42(double v) Set2DMatrixMember(_32, _42) + void SetM43(double v) Set3DMatrixMember(_43, 0) + void SetM44(double v) Set3DMatrixMember(_44, 1.0) + +#undef Set2DMatrixMember +#undef Set3DMatrixMember + already_AddRefed<DOMMatrix> Translate(double aTx, double aTy, double aTz = 0) const; @@ -115,7 +190,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; @@ -130,6 +206,8 @@ public: JS::MutableHandle<JSObject*> aResult, ErrorResult& aRv) const; void Stringify(nsAString& aResult); + bool WriteStructuredClone(JSStructuredCloneWriter* aWriter) const; + protected: nsCOMPtr<nsISupports> mParent; nsAutoPtr<gfx::Matrix> mMatrix2D; @@ -137,6 +215,24 @@ 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(); + + DOMMatrixReadOnly(nsISupports* aParent, bool is2D) : mParent(aParent) { + if (is2D) { + mMatrix2D = new gfx::Matrix(); + } else { + mMatrix3D = new gfx::Matrix4x4(); + } + } + private: DOMMatrixReadOnly() = delete; DOMMatrixReadOnly(const DOMMatrixReadOnly&) = delete; @@ -154,6 +250,21 @@ public: : DOMMatrixReadOnly(aParent, other) {} + DOMMatrix(nsISupports* aParent, const gfx::Matrix4x4& aMatrix) + : DOMMatrixReadOnly(aParent, aMatrix) + {} + + 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> + FromFloat32Array(const GlobalObject& aGlobal, const Float32Array& aArray32, ErrorResult& aRv); + + static already_AddRefed<DOMMatrix> + FromFloat64Array(const GlobalObject& aGlobal, const Float64Array& aArray64, ErrorResult& aRv); + static already_AddRefed<DOMMatrix> Constructor(const GlobalObject& aGlobal, ErrorResult& aRv); static already_AddRefed<DOMMatrix> @@ -167,55 +278,13 @@ public: static already_AddRefed<DOMMatrix> Constructor(const GlobalObject& aGlobal, const Sequence<double>& aNumberSequence, ErrorResult& aRv); - nsISupports* GetParentObject() const { return mParent; } - virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override; - -#define Set2DMatrixMember(entry2D, entry3D) \ -{ \ - if (mMatrix3D) { \ - mMatrix3D->entry3D = v; \ - } else { \ - mMatrix2D->entry2D = v; \ - } \ -} - -#define Set3DMatrixMember(entry3D, default) \ -{ \ - if (mMatrix3D || (v != default)) { \ - Ensure3DMatrix(); \ - mMatrix3D->entry3D = v; \ - } \ -} - - void SetA(double v) Set2DMatrixMember(_11, _11) - void SetB(double v) Set2DMatrixMember(_12, _12) - void SetC(double v) Set2DMatrixMember(_21, _21) - void SetD(double v) Set2DMatrixMember(_22, _22) - void SetE(double v) Set2DMatrixMember(_31, _41) - void SetF(double v) Set2DMatrixMember(_32, _42) - - void SetM11(double v) Set2DMatrixMember(_11, _11) - void SetM12(double v) Set2DMatrixMember(_12, _12) - void SetM13(double v) Set3DMatrixMember(_13, 0) - void SetM14(double v) Set3DMatrixMember(_14, 0) - void SetM21(double v) Set2DMatrixMember(_21, _21) - void SetM22(double v) Set2DMatrixMember(_22, _22) - void SetM23(double v) Set3DMatrixMember(_23, 0) - void SetM24(double v) Set3DMatrixMember(_24, 0) - void SetM31(double v) Set3DMatrixMember(_31, 0) - void SetM32(double v) Set3DMatrixMember(_32, 0) - void SetM33(double v) Set3DMatrixMember(_33, 1.0) - void SetM34(double v) Set3DMatrixMember(_34, 0) - void SetM41(double v) Set2DMatrixMember(_31, _41) - void SetM42(double v) Set2DMatrixMember(_32, _42) - void SetM43(double v) Set3DMatrixMember(_43, 0) - void SetM44(double v) Set3DMatrixMember(_44, 1.0) + static already_AddRefed<DOMMatrix> + ReadStructuredClone(nsISupports* aParent, JSStructuredCloneReader* aReader); -#undef Set2DMatrixMember -#undef Set3DMatrixMember + 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); @@ -245,10 +314,12 @@ public: DOMMatrix* SkewYSelf(double aSy); DOMMatrix* InvertSelf(); DOMMatrix* SetMatrixValue(const nsAString& aTransformList, ErrorResult& aRv); -protected: - void Ensure3DMatrix(); virtual ~DOMMatrix() {} + + private: + DOMMatrix(nsISupports* aParent, bool is2D) + : DOMMatrixReadOnly(aParent, is2D) {} }; } // namespace dom diff --git a/dom/base/DOMPoint.cpp b/dom/base/DOMPoint.cpp index 97eec9e766..7174a0cb1b 100644 --- a/dom/base/DOMPoint.cpp +++ b/dom/base/DOMPoint.cpp @@ -16,9 +16,68 @@ NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DOMPointReadOnly, mParent) NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(DOMPointReadOnly, AddRef) NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(DOMPointReadOnly, Release) +already_AddRefed<DOMPointReadOnly> +DOMPointReadOnly::FromPoint(const GlobalObject& aGlobal, const DOMPointInit& aParams) +{ + RefPtr<DOMPointReadOnly> obj = + new DOMPointReadOnly(aGlobal.GetAsSupports(), aParams.mX, aParams.mY, + aParams.mZ, aParams.mW); + return obj.forget(); +} + +already_AddRefed<DOMPointReadOnly> +DOMPointReadOnly::Constructor(const GlobalObject& aGlobal, double aX, double aY, + double aZ, double aW, ErrorResult& aRV) +{ + RefPtr<DOMPointReadOnly> obj = + new DOMPointReadOnly(aGlobal.GetAsSupports(), aX, aY, aZ, aW); + return obj.forget(); +} + +JSObject* +DOMPointReadOnly::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) +{ + return DOMPointReadOnlyBinding::Wrap(aCx, this, aGivenProto); +} + +// https://drafts.fxtf.org/geometry/#structured-serialization +bool +DOMPointReadOnly::WriteStructuredClone(JSStructuredCloneWriter* aWriter) const +{ +#define WriteDouble(d) \ + JS_WriteUint32Pair(aWriter, (BitwiseCast<uint64_t>(d) >> 32) & 0xffffffff, \ + BitwiseCast<uint64_t>(d) & 0xffffffff) + + return WriteDouble(mX) && WriteDouble(mY) && WriteDouble(mZ) && + WriteDouble(mW); + +#undef WriteDouble +} + +bool +DOMPointReadOnly::ReadStructuredClone(JSStructuredCloneReader* aReader) +{ + uint32_t high; + uint32_t low; + +#define ReadDouble(d) \ + if (!JS_ReadUint32Pair(aReader, &high, &low)) { \ + return false; \ + } \ + (*(d) = BitwiseCast<double>(static_cast<uint64_t>(high) << 32 | low)) + + ReadDouble(&mX); + ReadDouble(&mY); + ReadDouble(&mZ); + ReadDouble(&mW); + + return true; + +#undef ReadDouble +} + already_AddRefed<DOMPoint> -DOMPoint::Constructor(const GlobalObject& aGlobal, const DOMPointInit& aParams, - ErrorResult& aRV) +DOMPoint::FromPoint(const GlobalObject& aGlobal, const DOMPointInit& aParams) { RefPtr<DOMPoint> obj = new DOMPoint(aGlobal.GetAsSupports(), aParams.mX, aParams.mY, diff --git a/dom/base/DOMPoint.h b/dom/base/DOMPoint.h index 1a85982cc7..f460ea725c 100644 --- a/dom/base/DOMPoint.h +++ b/dom/base/DOMPoint.h @@ -6,6 +6,7 @@ #ifndef MOZILLA_DOMPOINT_H_ #define MOZILLA_DOMPOINT_H_ +#include "js/StructuredClone.h" #include "nsWrapperCache.h" #include "nsISupports.h" #include "nsCycleCollectionParticipant.h" @@ -23,8 +24,8 @@ struct DOMPointInit; class DOMPointReadOnly : public nsWrapperCache { public: - DOMPointReadOnly(nsISupports* aParent, double aX, double aY, - double aZ, double aW) + explicit DOMPointReadOnly(nsISupports* aParent, double aX = 0.0, + double aY = 0.0, double aZ = 0.0, double aW = 1.0) : mParent(aParent) , mX(aX) , mY(aY) @@ -33,6 +34,12 @@ public: { } + static already_AddRefed<DOMPointReadOnly> + FromPoint(const GlobalObject& aGlobal, const DOMPointInit& aParams); + static already_AddRefed<DOMPointReadOnly> + Constructor(const GlobalObject& aGlobal, double aX, double aY, + double aZ, double aW, ErrorResult& aRV); + NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(DOMPointReadOnly) NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(DOMPointReadOnly) @@ -41,6 +48,13 @@ public: double Z() const { return mZ; } double W() const { return mW; } + nsISupports* GetParentObject() const { return mParent; } + virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override; + + bool WriteStructuredClone(JSStructuredCloneWriter* aWriter) const; + + bool ReadStructuredClone(JSStructuredCloneReader* aReader); + protected: virtual ~DOMPointReadOnly() {} @@ -57,13 +71,11 @@ public: {} static already_AddRefed<DOMPoint> - Constructor(const GlobalObject& aGlobal, const DOMPointInit& aParams, - ErrorResult& aRV); + FromPoint(const GlobalObject& aGlobal, const DOMPointInit& aParams); static already_AddRefed<DOMPoint> Constructor(const GlobalObject& aGlobal, double aX, double aY, double aZ, double aW, ErrorResult& aRV); - nsISupports* GetParentObject() const { return mParent; } virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override; void SetX(double aX) { mX = aX; } diff --git a/dom/base/DOMQuad.cpp b/dom/base/DOMQuad.cpp index 9da70c043d..258bfc1bfd 100644 --- a/dom/base/DOMQuad.cpp +++ b/dom/base/DOMQuad.cpp @@ -44,6 +44,32 @@ DOMQuad::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) } already_AddRefed<DOMQuad> +DOMQuad::FromRect(const GlobalObject& aGlobal, const DOMRectInit& aInit) +{ + nsISupports* parent = aGlobal.GetAsSupports(); + RefPtr<DOMQuad> obj = new DOMQuad(parent); + obj->mPoints[0] = new DOMPoint(parent, aInit.mX, aInit.mY, 0, 1); + obj->mPoints[1] = + new DOMPoint(parent, aInit.mX + aInit.mWidth, aInit.mY, 0, 1); + obj->mPoints[2] = new DOMPoint(parent, aInit.mX + aInit.mWidth, + aInit.mY + aInit.mHeight, 0, 1); + obj->mPoints[3] = + new DOMPoint(parent, aInit.mX, aInit.mY + aInit.mHeight, 0, 1); + return obj.forget(); +} + +already_AddRefed<DOMQuad> +DOMQuad::FromQuad(const GlobalObject& aGlobal, const DOMQuadInit& aInit) +{ + RefPtr<DOMQuad> obj = new DOMQuad(aGlobal.GetAsSupports()); + obj->mPoints[0] = DOMPoint::FromPoint(aGlobal, aInit.mP1); + obj->mPoints[1] = DOMPoint::FromPoint(aGlobal, aInit.mP2); + obj->mPoints[2] = DOMPoint::FromPoint(aGlobal, aInit.mP3); + obj->mPoints[3] = DOMPoint::FromPoint(aGlobal, aInit.mP4); + return obj.forget(); +} + +already_AddRefed<DOMQuad> DOMQuad::Constructor(const GlobalObject& aGlobal, const DOMPointInit& aP1, const DOMPointInit& aP2, @@ -52,10 +78,10 @@ DOMQuad::Constructor(const GlobalObject& aGlobal, ErrorResult& aRV) { RefPtr<DOMQuad> obj = new DOMQuad(aGlobal.GetAsSupports()); - obj->mPoints[0] = DOMPoint::Constructor(aGlobal, aP1, aRV); - obj->mPoints[1] = DOMPoint::Constructor(aGlobal, aP2, aRV); - obj->mPoints[2] = DOMPoint::Constructor(aGlobal, aP3, aRV); - obj->mPoints[3] = DOMPoint::Constructor(aGlobal, aP4, aRV); + obj->mPoints[0] = DOMPoint::FromPoint(aGlobal, aP1); + obj->mPoints[1] = DOMPoint::FromPoint(aGlobal, aP2); + obj->mPoints[2] = DOMPoint::FromPoint(aGlobal, aP3); + obj->mPoints[3] = DOMPoint::FromPoint(aGlobal, aP4); return obj.forget(); } @@ -73,87 +99,86 @@ DOMQuad::Constructor(const GlobalObject& aGlobal, const DOMRectReadOnly& aRect, return obj.forget(); } -class DOMQuad::QuadBounds final : public DOMRectReadOnly +void +DOMQuad::GetHorizontalMinMax(double* aX1, double* aX2) const { -public: - explicit QuadBounds(DOMQuad* aQuad) - : DOMRectReadOnly(aQuad->GetParentObject()) - , mQuad(aQuad) - {} - - NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(QuadBounds, DOMRectReadOnly) - NS_DECL_ISUPPORTS_INHERITED - - virtual double X() const override - { - double x1, x2; - GetHorizontalMinMax(&x1, &x2); - return x1; - } - virtual double Y() const override - { - double y1, y2; - GetVerticalMinMax(&y1, &y2); - return y1; - } - virtual double Width() const override - { - double x1, x2; - GetHorizontalMinMax(&x1, &x2); - return x2 - x1; - } - virtual double Height() const override - { - double y1, y2; - GetVerticalMinMax(&y1, &y2); - return y2 - y1; + double x1, x2; + x1 = x2 = Point(0)->X(); + for (uint32_t i = 1; i < 4; ++i) { + double x = Point(i)->X(); + x1 = std::min(x1, x); + x2 = std::max(x2, x); } + *aX1 = x1; + *aX2 = x2; +} - void GetHorizontalMinMax(double* aX1, double* aX2) const - { - double x1, x2; - x1 = x2 = mQuad->Point(0)->X(); - for (uint32_t i = 1; i < 4; ++i) { - double x = mQuad->Point(i)->X(); - x1 = std::min(x1, x); - x2 = std::max(x2, x); - } - *aX1 = x1; - *aX2 = x2; +void +DOMQuad::GetVerticalMinMax(double* aY1, double* aY2) const +{ + double y1, y2; + y1 = y2 = Point(0)->Y(); + for (uint32_t i = 1; i < 4; ++i) { + double y = Point(i)->Y(); + y1 = std::min(y1, y); + y2 = std::max(y2, y); } + *aY1 = y1; + *aY2 = y2; +} - void GetVerticalMinMax(double* aY1, double* aY2) const - { - double y1, y2; - y1 = y2 = mQuad->Point(0)->Y(); - for (uint32_t i = 1; i < 4; ++i) { - double y = mQuad->Point(i)->Y(); - y1 = std::min(y1, y); - y2 = std::max(y2, y); - } - *aY1 = y1; - *aY2 = y2; +DOMRectReadOnly* +DOMQuad::Bounds() +{ + if (!mBounds) { + mBounds = GetBounds(); } + return mBounds; +} -protected: - virtual ~QuadBounds() {} +already_AddRefed<DOMRectReadOnly> +DOMQuad::GetBounds() const +{ + double x1, x2; + double y1, y2; - RefPtr<DOMQuad> mQuad; -}; + GetHorizontalMinMax(&x1, &x2); + GetVerticalMinMax(&y1, &y2); -NS_IMPL_CYCLE_COLLECTION_INHERITED(DOMQuad::QuadBounds, DOMRectReadOnly, mQuad) + RefPtr<DOMRectReadOnly> rval = new DOMRectReadOnly(GetParentObject(), + x1, y1, x2 - x1, y2 - y1); + return rval.forget(); +} -NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(DOMQuad::QuadBounds) -NS_INTERFACE_MAP_END_INHERITING(DOMRectReadOnly) +void +DOMQuad::ToJSON(DOMQuadJSON& aInit) +{ + aInit.mP1.Construct(RefPtr<DOMPoint>(P1()).forget()); + aInit.mP2.Construct(RefPtr<DOMPoint>(P2()).forget()); + aInit.mP3.Construct(RefPtr<DOMPoint>(P3()).forget()); + aInit.mP4.Construct(RefPtr<DOMPoint>(P4()).forget()); +} -NS_IMPL_ADDREF_INHERITED(DOMQuad::QuadBounds, DOMRectReadOnly) -NS_IMPL_RELEASE_INHERITED(DOMQuad::QuadBounds, DOMRectReadOnly) +// https://drafts.fxtf.org/geometry/#structured-serialization +bool +DOMQuad::WriteStructuredClone(JSStructuredCloneWriter* aWriter) const +{ + for (const auto& point : mPoints) { + if (!point->WriteStructuredClone(aWriter)) { + return false; + } + } + return true; +} -DOMRectReadOnly* -DOMQuad::Bounds() const +bool +DOMQuad::ReadStructuredClone(JSStructuredCloneReader* aReader) { - if (!mBounds) { - mBounds = new QuadBounds(const_cast<DOMQuad*>(this)); + for (auto& point : mPoints) { + point = new DOMPoint(mParent); + if (!point->ReadStructuredClone(aReader)) { + return false; + } } - return mBounds; + return true; } diff --git a/dom/base/DOMQuad.h b/dom/base/DOMQuad.h index 89d258a106..e32aea26f8 100644 --- a/dom/base/DOMQuad.h +++ b/dom/base/DOMQuad.h @@ -6,6 +6,7 @@ #ifndef MOZILLA_DOMQUAD_H_ #define MOZILLA_DOMQUAD_H_ +#include "js/StructuredClone.h" #include "nsWrapperCache.h" #include "nsISupports.h" #include "nsCycleCollectionParticipant.h" @@ -20,7 +21,10 @@ namespace dom { class DOMRectReadOnly; class DOMPoint; +struct DOMQuadJSON; struct DOMPointInit; +struct DOMQuadInit; +struct DOMRectInit; class DOMQuad final : public nsWrapperCache { @@ -37,6 +41,12 @@ public: virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override; static already_AddRefed<DOMQuad> + FromRect(const GlobalObject& aGlobal, const DOMRectInit& aInit); + + static already_AddRefed<DOMQuad> + FromQuad(const GlobalObject& aGlobal, const DOMQuadInit& aInit); + + static already_AddRefed<DOMQuad> Constructor(const GlobalObject& aGlobal, const DOMPointInit& aP1, const DOMPointInit& aP2, @@ -47,20 +57,28 @@ public: Constructor(const GlobalObject& aGlobal, const DOMRectReadOnly& aRect, ErrorResult& aRV); - DOMRectReadOnly* Bounds() const; + DOMRectReadOnly* Bounds(); + already_AddRefed<DOMRectReadOnly> GetBounds() const; DOMPoint* P1() const { return mPoints[0]; } DOMPoint* P2() const { return mPoints[1]; } DOMPoint* P3() const { return mPoints[2]; } DOMPoint* P4() const { return mPoints[3]; } - DOMPoint* Point(uint32_t aIndex) { return mPoints[aIndex]; } + DOMPoint* Point(uint32_t aIndex) const { return mPoints[aIndex]; } + + void ToJSON(DOMQuadJSON& aInit); + + bool WriteStructuredClone(JSStructuredCloneWriter* aWriter) const; + + bool ReadStructuredClone(JSStructuredCloneReader* aReader); protected: - class QuadBounds; + void GetHorizontalMinMax(double* aX1, double* aX2) const; + void GetVerticalMinMax(double* aY1, double* aY2) const; nsCOMPtr<nsISupports> mParent; RefPtr<DOMPoint> mPoints[4]; - mutable RefPtr<QuadBounds> mBounds; // allocated lazily + RefPtr<DOMRectReadOnly> mBounds; }; } // namespace dom diff --git a/dom/base/DOMRect.cpp b/dom/base/DOMRect.cpp index 3728ea7a7c..8dd634b547 100644 --- a/dom/base/DOMRect.cpp +++ b/dom/base/DOMRect.cpp @@ -27,6 +27,59 @@ DOMRectReadOnly::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) return DOMRectReadOnlyBinding::Wrap(aCx, this, aGivenProto); } +already_AddRefed<DOMRectReadOnly> +DOMRectReadOnly::FromRect(const GlobalObject& aGlobal, const DOMRectInit& aInit) +{ + RefPtr<DOMRectReadOnly> obj = new DOMRectReadOnly( + aGlobal.GetAsSupports(), aInit.mX, aInit.mY, aInit.mWidth, aInit.mHeight); + return obj.forget(); +} + +already_AddRefed<DOMRectReadOnly> +DOMRectReadOnly::Constructor(const GlobalObject& aGlobal, double aX, double aY, + double aWidth, double aHeight, ErrorResult& aRv) +{ + RefPtr<DOMRectReadOnly> obj = + new DOMRectReadOnly(aGlobal.GetAsSupports(), aX, aY, aWidth, aHeight); + return obj.forget(); +} + +// https://drafts.fxtf.org/geometry/#structured-serialization +bool +DOMRectReadOnly::WriteStructuredClone(JSStructuredCloneWriter* aWriter) const +{ +#define WriteDouble(d) \ + JS_WriteUint32Pair(aWriter, (BitwiseCast<uint64_t>(d) >> 32) & 0xffffffff, \ + BitwiseCast<uint64_t>(d) & 0xffffffff) + + return WriteDouble(mX) && WriteDouble(mY) && WriteDouble(mWidth) && + WriteDouble(mHeight); + +#undef WriteDouble +} + +bool +DOMRectReadOnly::ReadStructuredClone(JSStructuredCloneReader* aReader) +{ + uint32_t high; + uint32_t low; + +#define ReadDouble(d) \ + if (!JS_ReadUint32Pair(aReader, &high, &low)) { \ + return false; \ + } \ + (*(d) = BitwiseCast<double>(static_cast<uint64_t>(high) << 32 | low)) + + ReadDouble(&mX); + ReadDouble(&mY); + ReadDouble(&mWidth); + ReadDouble(&mHeight); + + return true; + +#undef ReadDouble +} + // ----------------------------------------------------------------------------- NS_IMPL_ISUPPORTS_INHERITED(DOMRect, DOMRectReadOnly, nsIDOMClientRect) @@ -54,16 +107,16 @@ DOMRect::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) } already_AddRefed<DOMRect> -DOMRect::Constructor(const GlobalObject& aGlobal, ErrorResult& aRV) +DOMRect::FromRect(const GlobalObject& aGlobal, const DOMRectInit& aInit) { - RefPtr<DOMRect> obj = - new DOMRect(aGlobal.GetAsSupports(), 0.0, 0.0, 0.0, 0.0); + RefPtr<DOMRect> obj = new DOMRect(aGlobal.GetAsSupports(), aInit.mX, aInit.mY, + aInit.mWidth, aInit.mHeight); return obj.forget(); } already_AddRefed<DOMRect> DOMRect::Constructor(const GlobalObject& aGlobal, double aX, double aY, - double aWidth, double aHeight, ErrorResult& aRV) + double aWidth, double aHeight, ErrorResult& aRv) { RefPtr<DOMRect> obj = new DOMRect(aGlobal.GetAsSupports(), aX, aY, aWidth, aHeight); diff --git a/dom/base/DOMRect.h b/dom/base/DOMRect.h index da3162be0c..541ff02539 100644 --- a/dom/base/DOMRect.h +++ b/dom/base/DOMRect.h @@ -6,6 +6,7 @@ #ifndef MOZILLA_DOMRECT_H_ #define MOZILLA_DOMRECT_H_ +#include "js/StructuredClone.h" #include "nsIDOMClientRect.h" #include "nsIDOMClientRectList.h" #include "nsTArray.h" @@ -22,6 +23,8 @@ struct nsRect; namespace mozilla { namespace dom { +struct DOMRectInit; + class DOMRectReadOnly : public nsISupports , public nsWrapperCache { @@ -32,8 +35,13 @@ public: NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(DOMRectReadOnly) - explicit DOMRectReadOnly(nsISupports* aParent) + explicit DOMRectReadOnly(nsISupports* aParent, double aX = 0, double aY = 0, + double aWidth = 0, double aHeight = 0) : mParent(aParent) + , mX(aX) + , mY(aY) + , mWidth(aWidth) + , mHeight(aHeight) { } @@ -44,10 +52,29 @@ public: } virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override; - virtual double X() const = 0; - virtual double Y() const = 0; - virtual double Width() const = 0; - virtual double Height() const = 0; + static already_AddRefed<DOMRectReadOnly> + FromRect(const GlobalObject& aGlobal, const DOMRectInit& aInit); + + static already_AddRefed<DOMRectReadOnly> + Constructor(const GlobalObject& aGlobal, double aX, double aY, + double aWidth, double aHeight, ErrorResult& aRv); + + double X() const + { + return mX; + } + double Y() const + { + return mY; + } + double Width() const + { + return mWidth; + } + double Height() const + { + return mHeight; + } double Left() const { @@ -70,8 +97,13 @@ public: return std::max(y, y + h); } + bool WriteStructuredClone(JSStructuredCloneWriter* aWriter) const; + + bool ReadStructuredClone(JSStructuredCloneReader* aReader); + protected: nsCOMPtr<nsISupports> mParent; + double mX, mY, mWidth, mHeight; }; class DOMRect final : public DOMRectReadOnly @@ -80,22 +112,19 @@ class DOMRect final : public DOMRectReadOnly public: explicit DOMRect(nsISupports* aParent, double aX = 0, double aY = 0, double aWidth = 0, double aHeight = 0) - : DOMRectReadOnly(aParent) - , mX(aX) - , mY(aY) - , mWidth(aWidth) - , mHeight(aHeight) + : DOMRectReadOnly(aParent, aX, aY, aWidth, aHeight) { } - + NS_DECL_ISUPPORTS_INHERITED NS_DECL_NSIDOMCLIENTRECT static already_AddRefed<DOMRect> - Constructor(const GlobalObject& aGlobal, ErrorResult& aRV); + FromRect(const GlobalObject& aGlobal, const DOMRectInit& aInit); + static already_AddRefed<DOMRect> Constructor(const GlobalObject& aGlobal, double aX, double aY, - double aWidth, double aHeight, ErrorResult& aRV); + double aWidth, double aHeight, ErrorResult& aRv); virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override; @@ -104,23 +133,6 @@ public: } void SetLayoutRect(const nsRect& aLayoutRect); - virtual double X() const override - { - return mX; - } - virtual double Y() const override - { - return mY; - } - virtual double Width() const override - { - return mWidth; - } - virtual double Height() const override - { - return mHeight; - } - void SetX(double aX) { mX = aX; @@ -138,11 +150,8 @@ public: mHeight = aHeight; } -protected: - double mX, mY, mWidth, mHeight; - private: - ~DOMRect() {}; + ~DOMRect() {} }; class DOMRectList final : public nsIDOMClientRectList, diff --git a/dom/base/StructuredCloneHolder.cpp b/dom/base/StructuredCloneHolder.cpp index 5ad8ebb688..71eab63138 100644 --- a/dom/base/StructuredCloneHolder.cpp +++ b/dom/base/StructuredCloneHolder.cpp @@ -11,6 +11,14 @@ #include "mozilla/dom/CryptoKey.h" #include "mozilla/dom/Directory.h" #include "mozilla/dom/DirectoryBinding.h" +#include "mozilla/dom/DOMMatrix.h" +#include "mozilla/dom/DOMMatrixBinding.h" +#include "mozilla/dom/DOMPoint.h" +#include "mozilla/dom/DOMPointBinding.h" +#include "mozilla/dom/DOMQuad.h" +#include "mozilla/dom/DOMQuadBinding.h" +#include "mozilla/dom/DOMRect.h" +#include "mozilla/dom/DOMRectBinding.h" #include "mozilla/dom/File.h" #include "mozilla/dom/FileList.h" #include "mozilla/dom/FileListBinding.h" @@ -355,7 +363,11 @@ StructuredCloneHolder::ReadFullySerializableObjects(JSContext* aCx, return ReadStructuredCloneImageData(aCx, aReader); } - if (aTag == SCTAG_DOM_WEBCRYPTO_KEY || aTag == SCTAG_DOM_URLSEARCHPARAMS) { + if (aTag == SCTAG_DOM_WEBCRYPTO_KEY || aTag == SCTAG_DOM_URLSEARCHPARAMS || + aTag == SCTAG_DOM_DOMPOINT || aTag == SCTAG_DOM_DOMPOINT_READONLY || + aTag == SCTAG_DOM_DOMRECT || aTag == SCTAG_DOM_DOMRECT_READONLY || + aTag == SCTAG_DOM_DOMQUAD || aTag == SCTAG_DOM_DOMMATRIX || + aTag == SCTAG_DOM_DOMMATRIX_READONLY) { nsIGlobalObject *global = xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx)); if (!global) { return nullptr; @@ -378,6 +390,57 @@ StructuredCloneHolder::ReadFullySerializableObjects(JSContext* aCx, } else { result = usp->WrapObject(aCx, nullptr); } + } else if (aTag == SCTAG_DOM_DOMPOINT) { + RefPtr<DOMPoint> domPoint = new DOMPoint(global); + if (!domPoint->ReadStructuredClone(aReader)) { + result = nullptr; + } else { + result = domPoint->WrapObject(aCx, nullptr); + } + } else if (aTag == SCTAG_DOM_DOMPOINT_READONLY) { + RefPtr<DOMPointReadOnly> domPoint = new DOMPointReadOnly(global); + if (!domPoint->ReadStructuredClone(aReader)) { + result = nullptr; + } else { + result = domPoint->WrapObject(aCx, nullptr); + } + } else if (aTag == SCTAG_DOM_DOMRECT) { + RefPtr<DOMRect> domRect = new DOMRect(global); + if (!domRect->ReadStructuredClone(aReader)) { + result = nullptr; + } else { + result = domRect->WrapObject(aCx, nullptr); + } + } else if (aTag == SCTAG_DOM_DOMRECT_READONLY) { + RefPtr<DOMRectReadOnly> domRect = new DOMRectReadOnly(global); + if (!domRect->ReadStructuredClone(aReader)) { + result = nullptr; + } else { + result = domRect->WrapObject(aCx, nullptr); + } + } else if (aTag == SCTAG_DOM_DOMQUAD) { + RefPtr<DOMQuad> domQuad = new DOMQuad(global); + if (!domQuad->ReadStructuredClone(aReader)) { + result = nullptr; + } else { + result = domQuad->WrapObject(aCx, nullptr); + } + } else if (aTag == SCTAG_DOM_DOMMATRIX) { + RefPtr<DOMMatrix> domMatrix = + DOMMatrix::ReadStructuredClone(global, aReader); + if (!domMatrix) { + result = nullptr; + } else { + result = domMatrix->WrapObject(aCx, nullptr); + } + } else if (aTag == SCTAG_DOM_DOMMATRIX_READONLY) { + RefPtr<DOMMatrixReadOnly> domMatrix = + DOMMatrixReadOnly::ReadStructuredClone(global, aReader); + if (!domMatrix) { + result = nullptr; + } else { + result = domMatrix->WrapObject(aCx, nullptr); + } } } return result; @@ -483,6 +546,75 @@ StructuredCloneHolder::WriteFullySerializableObjects(JSContext* aCx, } #endif + // Handle DOMPoint cloning + // Should be done before DOMPointeReadOnly check + // because every DOMPoint is also a DOMPointReadOnly + { + DOMPoint* domPoint = nullptr; + if (NS_SUCCEEDED(UNWRAP_OBJECT(DOMPoint, &obj, domPoint))) { + return JS_WriteUint32Pair(aWriter, SCTAG_DOM_DOMPOINT, 0) && + domPoint->WriteStructuredClone(aWriter); + } + } + + // Handle DOMPointReadOnly cloning + { + DOMPointReadOnly* domPoint = nullptr; + if (NS_SUCCEEDED(UNWRAP_OBJECT(DOMPointReadOnly, &obj, domPoint))) { + return JS_WriteUint32Pair(aWriter, SCTAG_DOM_DOMPOINT_READONLY, 0) && + domPoint->WriteStructuredClone(aWriter); + } + } + + // Handle DOMRect cloning + // Should be done before DOMRecteReadOnly check + // because every DOMRect is also a DOMRectReadOnly + { + DOMRect* domRect = nullptr; + if (NS_SUCCEEDED(UNWRAP_OBJECT(DOMRect, &obj, domRect))) { + return JS_WriteUint32Pair(aWriter, SCTAG_DOM_DOMRECT, 0) && + domRect->WriteStructuredClone(aWriter); + } + } + + // Handle DOMRectReadOnly cloning + { + DOMRectReadOnly* domRect = nullptr; + if (NS_SUCCEEDED(UNWRAP_OBJECT(DOMRectReadOnly, &obj, domRect))) { + return JS_WriteUint32Pair(aWriter, SCTAG_DOM_DOMRECT_READONLY, 0) && + domRect->WriteStructuredClone(aWriter); + } + } + + // Handle DOMQuad cloning + { + DOMQuad* domQuad = nullptr; + if (NS_SUCCEEDED(UNWRAP_OBJECT(DOMQuad, &obj, domQuad))) { + return JS_WriteUint32Pair(aWriter, SCTAG_DOM_DOMQUAD, 0) && + domQuad->WriteStructuredClone(aWriter); + } + } + + // Handle DOMMatrix cloning + // Should be done before DOMMatrixeReadOnly check + // because every DOMMatrix is also a DOMMatrixReadOnly + { + DOMMatrix* domMatrix = nullptr; + if (NS_SUCCEEDED(UNWRAP_OBJECT(DOMMatrix, &obj, domMatrix))) { + return JS_WriteUint32Pair(aWriter, SCTAG_DOM_DOMMATRIX, 0) && + domMatrix->WriteStructuredClone(aWriter); + } + } + + // Handle DOMMatrixReadOnly cloning + { + DOMMatrixReadOnly* domMatrix = nullptr; + if (NS_SUCCEEDED(UNWRAP_OBJECT(DOMMatrixReadOnly, &obj, domMatrix))) { + return JS_WriteUint32Pair(aWriter, SCTAG_DOM_DOMMATRIX_READONLY, 0) && + domMatrix->WriteStructuredClone(aWriter); + } + } + if (NS_IsMainThread() && xpc::IsReflector(obj)) { nsCOMPtr<nsISupports> base = xpc::UnwrapReflectorToISupports(obj); nsCOMPtr<nsIPrincipal> principal = do_QueryInterface(base); diff --git a/dom/base/StructuredCloneTags.h b/dom/base/StructuredCloneTags.h index 8766d8e4ad..09b91f7afb 100644 --- a/dom/base/StructuredCloneTags.h +++ b/dom/base/StructuredCloneTags.h @@ -30,6 +30,15 @@ enum StructuredCloneTags { // New IDB tags go here! + // Tags for Geometry interfaces. + SCTAG_DOM_DOMPOINT, + SCTAG_DOM_DOMPOINT_READONLY, + SCTAG_DOM_DOMQUAD, + SCTAG_DOM_DOMRECT, + SCTAG_DOM_DOMRECT_READONLY, + SCTAG_DOM_DOMMATRIX, + SCTAG_DOM_DOMMATRIX_READONLY, + // These tags are used for both main thread and workers. SCTAG_DOM_IMAGEDATA, SCTAG_DOM_MAP_MESSAGEPORT, diff --git a/dom/base/WebKitCSSMatrix.cpp b/dom/base/WebKitCSSMatrix.cpp index fe26b74554..15ca6ba776 100644 --- a/dom/base/WebKitCSSMatrix.cpp +++ b/dom/base/WebKitCSSMatrix.cpp @@ -20,8 +20,7 @@ static const double sRadPerDegree = 2.0 * M_PI / 360.0; bool WebKitCSSMatrix::FeatureEnabled(JSContext* aCx, JSObject* aObj) { - return Preferences::GetBool("layout.css.DOMMatrix.enabled", false) && - Preferences::GetBool("layout.css.prefixes.webkit", false); + return Preferences::GetBool("layout.css.prefixes.webkit", false); } already_AddRefed<WebKitCSSMatrix> @@ -115,10 +114,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/base/nsDeprecatedOperationList.h b/dom/base/nsDeprecatedOperationList.h index 0bae2d6211..bb9d8fd3b1 100644 --- a/dom/base/nsDeprecatedOperationList.h +++ b/dom/base/nsDeprecatedOperationList.h @@ -47,3 +47,4 @@ DEPRECATED_OPERATION(PrefixedFullscreenAPI) DEPRECATED_OPERATION(LenientSetter) DEPRECATED_OPERATION(FileLastModifiedDate) DEPRECATED_OPERATION(ImageBitmapRenderingContext_TransferImageBitmap) +DEPRECATED_OPERATION(DOMQuadBoundsAttr) diff --git a/dom/bindings/Bindings.conf b/dom/bindings/Bindings.conf index 8b13babdbb..a12a294766 100644 --- a/dom/bindings/Bindings.conf +++ b/dom/bindings/Bindings.conf @@ -236,12 +236,10 @@ DOMInterfaces = { 'DOMMatrixReadOnly': { 'headerFile': 'mozilla/dom/DOMMatrix.h', - 'concrete': False, }, 'DOMPointReadOnly': { 'headerFile': 'mozilla/dom/DOMPoint.h', - 'concrete': False, }, 'DOMRectList': { diff --git a/dom/bindings/Errors.msg b/dom/bindings/Errors.msg index c894c6c7b4..d22ef2c27f 100644 --- a/dom/bindings/Errors.msg +++ b/dom/bindings/Errors.msg @@ -100,6 +100,9 @@ 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.") MSG_DEF(MSG_PMO_MISSING_STARTENDMARK, 0, JSEXN_TYPEERR, "PerformanceMeasureOptions must have start and/or end member.") diff --git a/dom/filesystem/GetDirectoryListingTask.cpp b/dom/filesystem/GetDirectoryListingTask.cpp index 1d4f77b3b8..8fdfb4a5bb 100644 --- a/dom/filesystem/GetDirectoryListingTask.cpp +++ b/dom/filesystem/GetDirectoryListingTask.cpp @@ -340,9 +340,14 @@ GetDirectoryListingTaskParent::IOWork() nsCOMPtr<nsIFile> currFile = do_QueryInterface(supp); MOZ_ASSERT(currFile); - bool isSpecial, isFile; - if (NS_WARN_IF(NS_FAILED(currFile->IsSpecial(&isSpecial))) || - isSpecial) { + bool isLink, isSpecial, isFile; + if (NS_WARN_IF(NS_FAILED(currFile->IsSymlink(&isLink)) || + NS_FAILED(currFile->IsSpecial(&isSpecial))) || + // Although we allow explicit individual selection of symlinks via the + // file picker, we do not process symlinks in directory traversal. Our + // specific policy decision is documented at + // https://bugzilla.mozilla.org/show_bug.cgi?id=1813299#c20 + isLink || isSpecial) { continue; } if (NS_WARN_IF(NS_FAILED(currFile->IsFile(&isFile)) || diff --git a/dom/filesystem/GetFilesHelper.cpp b/dom/filesystem/GetFilesHelper.cpp index 563ef60b4a..fb3cf7a24d 100644 --- a/dom/filesystem/GetFilesHelper.cpp +++ b/dom/filesystem/GetFilesHelper.cpp @@ -333,13 +333,8 @@ GetFilesHelperBase::ExploreDirectory(const nsAString& aDOMPath, nsIFile* aFile) return NS_OK; } - nsresult rv = AddExploredDirectory(aFile); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - nsCOMPtr<nsISimpleEnumerator> entries; - rv = aFile->GetDirectoryEntries(getter_AddRefs(entries)); + nsresult rv = aFile->GetDirectoryEntries(getter_AddRefs(entries)); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } @@ -361,7 +356,12 @@ GetFilesHelperBase::ExploreDirectory(const nsAString& aDOMPath, nsIFile* aFile) bool isLink, isSpecial, isFile, isDir; if (NS_WARN_IF(NS_FAILED(currFile->IsSymlink(&isLink)) || NS_FAILED(currFile->IsSpecial(&isSpecial))) || - isSpecial) { + isSpecial || + // Although we allow explicit individual selection of symlinks via the + // file picker, we do not process symlinks in directory traversal. Our + // specific policy decision is documented at + // https://bugzilla.mozilla.org/show_bug.cgi?id=1813299#c20 + isLink) { continue; } @@ -371,11 +371,6 @@ GetFilesHelperBase::ExploreDirectory(const nsAString& aDOMPath, nsIFile* aFile) continue; } - // We don't want to explore loops of links. - if (isDir && isLink && !ShouldFollowSymLink(currFile)) { - continue; - } - // The new domPath nsAutoString domPath; domPath.Assign(aDOMPath); @@ -415,69 +410,6 @@ GetFilesHelperBase::ExploreDirectory(const nsAString& aDOMPath, nsIFile* aFile) return NS_OK; } -nsresult -GetFilesHelperBase::AddExploredDirectory(nsIFile* aDir) -{ - nsresult rv; - -#ifdef DEBUG - bool isDir; - rv = aDir->IsDirectory(&isDir); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - MOZ_ASSERT(isDir, "Why are we here?"); -#endif - - bool isLink; - rv = aDir->IsSymlink(&isLink); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - nsAutoCString path; - - if (!isLink) { - nsAutoString path16; - rv = aDir->GetPath(path16); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - path = NS_ConvertUTF16toUTF8(path16); - } else { - rv = aDir->GetNativeTarget(path); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - } - - mExploredDirectories.PutEntry(path); - return NS_OK; -} - -bool -GetFilesHelperBase::ShouldFollowSymLink(nsIFile* aDir) -{ -#ifdef DEBUG - bool isLink, isDir; - if (NS_WARN_IF(NS_FAILED(aDir->IsSymlink(&isLink)) || - NS_FAILED(aDir->IsDirectory(&isDir)))) { - return false; - } - - MOZ_ASSERT(isLink && isDir, "Why are we here?"); -#endif - - nsAutoCString targetPath; - if (NS_WARN_IF(NS_FAILED(aDir->GetNativeTarget(targetPath)))) { - return false; - } - - return !mExploredDirectories.Contains(targetPath); -} - void GetFilesHelper::ResolveOrRejectPromise(Promise* aPromise) { diff --git a/dom/filesystem/GetFilesHelper.h b/dom/filesystem/GetFilesHelper.h index 4afd41d7e0..b6c58ef396 100644 --- a/dom/filesystem/GetFilesHelper.h +++ b/dom/filesystem/GetFilesHelper.h @@ -9,10 +9,8 @@ #include "mozilla/Mutex.h" #include "mozilla/RefPtr.h" #include "mozilla/dom/File.h" -#include "nsClassHashtable.h" #include "nsCycleCollectionTraversalCallback.h" #include "nsTArray.h" -#include "nsTHashtable.h" #include "nsThreadUtils.h" class nsIGlobalObject; @@ -57,17 +55,10 @@ protected: nsresult ExploreDirectory(const nsAString& aDOMPath, nsIFile* aFile); - nsresult - AddExploredDirectory(nsIFile* aDirectory); - - bool - ShouldFollowSymLink(nsIFile* aDirectory); - bool mRecursiveFlag; // We populate this array in the I/O thread with the BlobImpl. FallibleTArray<RefPtr<BlobImpl>> mTargetBlobImplArray; - nsTHashtable<nsCStringHashKey> mExploredDirectories; }; // Retrieving the list of files can be very time/IO consuming. We use this diff --git a/dom/filesystem/tests/filesystem_commons.js b/dom/filesystem/tests/filesystem_commons.js index 4f7234121e..c8bd9ac9fc 100644 --- a/dom/filesystem/tests/filesystem_commons.js +++ b/dom/filesystem/tests/filesystem_commons.js @@ -38,6 +38,10 @@ function test_getFilesAndDirectories(aDirectory, aRecursive, aNext) { if (data[i] instanceof File) { is(data[i].webkitRelativePath, createRelativePath(dir, data[i]), "File.webkitRelativePath should be called: parentdir.path + '/' + file.name: " + data[i].webkitRelativePath); } + ok( + !data[i].webkitRelativePath.endsWith("symlink.txt"), + "We should never see a path ending with symlink.txt, our symlink sentinel." + ); } } ); diff --git a/dom/filesystem/tests/script_fileList.js b/dom/filesystem/tests/script_fileList.js index 89fd04cabe..dedc61a448 100644 --- a/dom/filesystem/tests/script_fileList.js +++ b/dom/filesystem/tests/script_fileList.js @@ -36,6 +36,15 @@ function createTreeFile(depth, parent) { if (depth == 0) { nextFile.append('file.txt'); nextFile.create(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0o600); + +#ifdef XP_UNIX + // It's not possible to create symlinks on windows by default or on our + // Android platforms, so we can't create the symlink file there. Our + // callers that care are aware of this. + var linkFile = parent.clone(); + linkFile.append("symlink.txt"); + createSymLink(nextFile.path, linkFile.path); +#endif } else { nextFile.append('subdir' + depth); nextFile.createUnique(Components.interfaces.nsIFile.DIRECTORY_TYPE, 0o700); @@ -84,6 +93,15 @@ function createTestFile() { file2.append('bar.txt'); file2.create(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0o600); +#ifdef XP_UNIX + // It's not possible to create symlinks on windows by default or on our + // Android platforms, so we can't create the symlink file there. Our + // callers that care are aware of this. + var linkFile = dir.clone(); + linkFile.append("symlink.txt"); + createSymLink(file1.path, linkFile.path); +#endif + return tmpFile; } @@ -127,3 +145,14 @@ addMessageListener("file.open", function (e) { file: File.createFromNsIFile(testFile) }); }); + +addMessageListener("symlink.open", function (e) { + let testDir = createTestFile(); + let testFile = testDir.clone(); + testFile.append("subdir"); + testFile.append("symlink.txt"); + + File.createFromNsIFile(testFile).then(function (file) { + sendAsyncMessage("symlink.opened", { dir: testDir.path, file }); + }); +}); diff --git a/dom/filesystem/tests/test_webkitdirectory.html b/dom/filesystem/tests/test_webkitdirectory.html index 591619e45b..46c728718f 100644 --- a/dom/filesystem/tests/test_webkitdirectory.html +++ b/dom/filesystem/tests/test_webkitdirectory.html @@ -9,11 +9,26 @@ <body> <input id="inputFileWebkitDirectory" type="file" webkitdirectory></input> <input id="inputFileWebkitDirectoryAndDirectory" type="file" webkitdirectory allowdirs></input> +<input id="inputFileWebkitFile" type="file"></input> <input id="inputFileDirectory" type="file" allowdirs></input> <input id="inputFileDirectoryChange" type="file" webkitdirectory></input> <script type="application/javascript;version=1.7"> +// Populate the given input type=file `aInputFile`'s `files` attribute by: +// - loading `script_fileList.js` in the parent process +// - telling it to generate the "test" template directory pattern which will +// create "foo.txt", "subdir/bar.txt", and if symlinks are available on the +// platform, "symlink.txt" which will be a symlink to "foo.txt". (Note that +// we explicitly expect the symlink to be filtered out if generated, and +// during the enhancement of the test we verified the file was created on +// linux by running the test before fixing the GetFilesHelper logic to filter +// the symlink out and verifying the subsequent `test_fileList` check failed.) +// - Triggering the mock file picker with the base directory of the "test" +// template directory. +// +// It's expected that `test_fileList` will be used after this step completes in +// order to validate the results. function populateInputFile(aInputFile) { var url = SimpleTest.getTestFileURL("script_fileList.js"); var script = SpecialPowers.loadChromeScript(url); @@ -52,6 +67,8 @@ function checkFile(file, fileList, dirName) { ok(false, "File not found."); } +// Validate the contents of the given input type=file `aInputFile`'s' `files` +// property against the expected list of files `aWhat`. function test_fileList(aInputFile, aWhat) { var input = document.getElementById(aInputFile); var fileList = input.files; @@ -70,6 +87,65 @@ function test_fileList(aInputFile, aWhat) { next(); } +// Verify that we can explicitly select a symlink and it will not be filtered +// out. This is really a verification that GetFileHelper's file-handling logic +// https://searchfox.org/mozilla-central/rev/065102493dfc49234120c37fc6a334a5b1d86d9e/dom/filesystem/GetFilesHelper.cpp#81-86 +// does not proactively take an action to filter out a selected symlink. +// +// This is a glass box test that is not entirely realistic for our actual system +// file pickers but does reflect what will happen in the drag-and-drop case +// for `HTMLInputElement::MozSetDndFilesAndDirectories` and this helps ensure +// that future implementation changes will behave as expected. Specifically, +// the presence of webkitdirectory will result in the file picker using +// `modeGetFolder` which will only allow selection of a directory and forbid +// file selection. +// +// This test explicitly does not validate HTMLInputElement's non-webkitdirectory +// file selection mechanism because it does not involve GetFileHelper. +async function test_individualSymlink(aInputFile) { + const input = document.getElementById(aInputFile); + + // -- Create the symlink and get a `File` instance pointing at it. + const url = SimpleTest.getTestFileURL("script_fileList.js"); + const script = SpecialPowers.loadChromeScript(url); + + let opened = new Promise(resolve => script.addMessageListener("symlink.opened", resolve)); + script.sendAsyncMessage("symlink.open", {}); + let { dir, file: symlinkFile } = await opened; + info(`symlink.open provided dir: ${dir}`) + + // -- Have the picker pick it + var MockFilePicker = SpecialPowers.MockFilePicker; + MockFilePicker.init(window, "A Mock File Picker", SpecialPowers.Ci.nsIFilePicker.modeOpen); + + MockFilePicker.displayDirectory = dir; + let pickerShown = new Promise(resolve => { + MockFilePicker.showCallback = function() { + // This is where we are diverging from a realistic scenario in order to get + // the expected coverage. + MockFilePicker.setFiles([symlinkFile]); + resolve(); + } + }); + MockFilePicker.returnValue = MockFilePicker.returnOK; + + let changeEvent = waitForEvent(input, "change"); + + input.click(); + + await pickerShown; + await changeEvent; + + MockFilePicker.cleanup(); + script.destroy(); + + // -- Verify that we see the symlink. + let fileList = input.files; + is(fileList.length, 1, "There should be 1 file."); + is(fileList[0].name, "symlink.txt", "The file should be the symlink."); + next(); +} + function test_webkitdirectory_attribute() { var a = document.createElement("input"); a.setAttribute("type", "file"); @@ -169,6 +245,16 @@ var tests = [ function() { test_fileList('inputFileWebkitDirectory', testDirData) }, function() { test_fileList('inputFileWebkitDirectoryAndDirectory', testDirData) }, function() { test_fileList('inputFileDirectory', null); }, + + function() { +#ifdef XP_WIN // Symlinks are not available on Windows and so will not be created. + info("Skipping individual symlink check on Windows and Android."); + next(); + return; +#endif + test_individualSymlink("inputFileWebkitFile").catch(err => ok(false, `Problem in symlink case: ${err}`)); + }, + test_webkitdirectory_attribute, diff --git a/dom/locales/en-US/chrome/dom/dom.properties b/dom/locales/en-US/chrome/dom/dom.properties index 60104a63ad..27b4eebf12 100644 --- a/dom/locales/en-US/chrome/dom/dom.properties +++ b/dom/locales/en-US/chrome/dom/dom.properties @@ -320,3 +320,4 @@ LargeAllocationNonE10S=A Large-Allocation header was ignored due to the document PushStateFloodingPrevented=Call to pushState or replaceState ignored due to excessive calls within a short timeframe. # LOCALIZATION NOTE: Do not translate "Reload" ReloadFloodingPrevented=Call to Reload ignored due to excessive calls within a short timeframe. +DOMQuadBoundsAttrWarning=DOMQuad.bounds is deprecated in favor of DOMQuad.getBounds() diff --git a/dom/webidl/DOMMatrix.webidl b/dom/webidl/DOMMatrix.webidl index 6b236ae666..f5c9f99406 100644 --- a/dom/webidl/DOMMatrix.webidl +++ b/dom/webidl/DOMMatrix.webidl @@ -4,14 +4,19 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * The origin of this IDL file is - * http://dev.w3.org/fxtf/geometry/ + * https://drafts.fxtf.org/geometry/ * * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C * liability, trademark and document use rules apply. */ -[Pref="layout.css.DOMMatrix.enabled"] +[Constructor(optional (DOMString or sequence<unrestricted double>) init), + Exposed=(Window,Worker)] interface DOMMatrixReadOnly { + [NewObject, Throws] static DOMMatrixReadOnly fromMatrix(optional DOMMatrixInit other); + [NewObject, Throws] static DOMMatrixReadOnly fromFloat32Array(Float32Array array32); + [NewObject, Throws] static DOMMatrixReadOnly fromFloat64Array(Float64Array array64); + // These attributes are simple aliases for certain elements of the 4x4 matrix readonly attribute unrestricted double a; readonly attribute unrestricted double b; @@ -65,7 +70,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(); @@ -76,17 +81,21 @@ interface DOMMatrixReadOnly { DOMPoint transformPoint(optional DOMPointInit point); [Throws] Float32Array toFloat32Array(); [Throws] Float64Array toFloat64Array(); - stringifier; + [Exposed=Window] stringifier; }; -[Pref="layout.css.DOMMatrix.enabled", - Constructor, +[Constructor, Constructor(DOMString transformList), Constructor(DOMMatrixReadOnly other), Constructor(Float32Array array32), Constructor(Float64Array array64), - Constructor(sequence<unrestricted double> numberSequence)] + Constructor(sequence<unrestricted double> numberSequence), + Exposed=(Window,Worker)] interface DOMMatrix : DOMMatrixReadOnly { + [NewObject, Throws] static DOMMatrix fromMatrix(optional DOMMatrixInit other); + [NewObject, Throws] static DOMMatrix fromFloat32Array(Float32Array array32); + [NewObject, Throws] static DOMMatrix fromFloat64Array(Float64Array array64); + // These attributes are simple aliases for certain elements of the 4x4 matrix inherit attribute unrestricted double a; inherit attribute unrestricted double b; @@ -113,8 +122,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); @@ -143,6 +152,34 @@ interface DOMMatrix : DOMMatrixReadOnly { DOMMatrix skewXSelf(unrestricted double sx); DOMMatrix skewYSelf(unrestricted double sy); DOMMatrix invertSelf(); - [Throws] DOMMatrix setMatrixValue(DOMString transformList); + [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/DOMPoint.webidl b/dom/webidl/DOMPoint.webidl index d092d900f5..313a51bc53 100644 --- a/dom/webidl/DOMPoint.webidl +++ b/dom/webidl/DOMPoint.webidl @@ -4,25 +4,30 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * The origin of this IDL file is - * http://dev.w3.org/fxtf/geometry/ + * https://drafts.fxtf.org/geometry/ * * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C * liability, trademark and document use rules apply. */ -[Pref="layout.css.DOMPoint.enabled"] +[Constructor(optional unrestricted double x = 0, optional unrestricted double y = 0, + optional unrestricted double z = 0, optional unrestricted double w = 1), + Exposed=(Window,Worker)] interface DOMPointReadOnly { + [NewObject] static DOMPointReadOnly fromPoint(optional DOMPointInit other); + readonly attribute unrestricted double x; readonly attribute unrestricted double y; readonly attribute unrestricted double z; readonly attribute unrestricted double w; }; -[Pref="layout.css.DOMPoint.enabled", - Constructor(optional DOMPointInit point), - Constructor(unrestricted double x, unrestricted double y, - optional unrestricted double z = 0, optional unrestricted double w = 1)] +[Constructor(optional unrestricted double x = 0, optional unrestricted double y = 0, + optional unrestricted double z = 0, optional unrestricted double w = 1), + Exposed=(Window,Worker)] interface DOMPoint : DOMPointReadOnly { + [NewObject] static DOMPoint fromPoint(optional DOMPointInit other); + inherit attribute unrestricted double x; inherit attribute unrestricted double y; inherit attribute unrestricted double z; @@ -34,4 +39,4 @@ dictionary DOMPointInit { unrestricted double y = 0; unrestricted double z = 0; unrestricted double w = 1; -};
\ No newline at end of file +}; diff --git a/dom/webidl/DOMQuad.webidl b/dom/webidl/DOMQuad.webidl index b933987d59..05b611a5e3 100644 --- a/dom/webidl/DOMQuad.webidl +++ b/dom/webidl/DOMQuad.webidl @@ -4,20 +4,41 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * The origin of this IDL file is - * http://dev.w3.org/fxtf/geometry/ + * https://drafts.fxtf.org/geometry/ * * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C * liability, trademark and document use rules apply. */ -[Pref="layout.css.DOMQuad.enabled", - Constructor(optional DOMPointInit p1, optional DOMPointInit p2, +[Constructor(optional DOMPointInit p1, optional DOMPointInit p2, optional DOMPointInit p3, optional DOMPointInit p4), - Constructor(DOMRectReadOnly rect)] + Constructor(DOMRectReadOnly rect), + Exposed=(Window,Worker)] interface DOMQuad { + [NewObject] static DOMQuad fromRect(optional DOMRectInit other); + [NewObject] static DOMQuad fromQuad(optional DOMQuadInit other); + [SameObject] readonly attribute DOMPoint p1; [SameObject] readonly attribute DOMPoint p2; [SameObject] readonly attribute DOMPoint p3; [SameObject] readonly attribute DOMPoint p4; - [SameObject] readonly attribute DOMRectReadOnly bounds; -};
\ No newline at end of file + [NewObject] DOMRectReadOnly getBounds(); + + [SameObject, Deprecated=DOMQuadBoundsAttr] readonly attribute DOMRectReadOnly bounds; + + DOMQuadJSON toJSON(); +}; + +dictionary DOMQuadJSON { + DOMPoint p1; + DOMPoint p2; + DOMPoint p3; + DOMPoint p4; +}; + +dictionary DOMQuadInit { + DOMPointInit p1 = null; + DOMPointInit p2 = null; + DOMPointInit p3 = null; + DOMPointInit p4 = null; +}; diff --git a/dom/webidl/DOMRect.webidl b/dom/webidl/DOMRect.webidl index 24a07900c5..baf7ce2456 100644 --- a/dom/webidl/DOMRect.webidl +++ b/dom/webidl/DOMRect.webidl @@ -4,23 +4,30 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * The origin of this IDL file is - * http://dev.w3.org/fxtf/geometry/ + * https://drafts.fxtf.org/geometry/ * * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C * liability, trademark and document use rules apply. */ -[Constructor, - Constructor(unrestricted double x, unrestricted double y, - unrestricted double width, unrestricted double height)] +[Constructor(optional unrestricted double x = 0, optional unrestricted double y = 0, + optional unrestricted double width = 0, optional unrestricted double height = 0), + Exposed=(Window,Worker)] interface DOMRect : DOMRectReadOnly { + [NewObject] static DOMRect fromRect(optional DOMRectInit other); + inherit attribute unrestricted double x; inherit attribute unrestricted double y; inherit attribute unrestricted double width; inherit attribute unrestricted double height; }; +[Constructor(optional unrestricted double x = 0, optional unrestricted double y = 0, + optional unrestricted double width = 0, optional unrestricted double height = 0), + Exposed=(Window,Worker)] interface DOMRectReadOnly { + [NewObject] static DOMRectReadOnly fromRect(optional DOMRectInit other); + readonly attribute unrestricted double x; readonly attribute unrestricted double y; readonly attribute unrestricted double width; 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, |