diff --git a/devtools/client/inspector/rules/test/browser_rules_completion-new-property_multiline.js b/devtools/client/inspector/rules/test/browser_rules_completion-new-property_multiline.js index f29de54a44..a4fafa2c1b 100644 --- a/devtools/client/inspector/rules/test/browser_rules_completion-new-property_multiline.js +++ b/devtools/client/inspector/rules/test/browser_rules_completion-new-property_multiline.js @@ -39,14 +39,14 @@ add_task(function* () { // Calculate offsets to click in the middle of the first box quad. let rect = prop.editor.valueSpan.getBoundingClientRect(); - let firstQuad = prop.editor.valueSpan.getBoxQuads()[0]; + let firstQuadBounds = prop.editor.valueSpan.getBoxQuads()[0].getBounds(); // For a multiline value, the first quad left edge is not aligned with the // bounding rect left edge. The offsets expected by focusEditableField are // relative to the bouding rectangle, so we need to translate the x-offset. - let x = firstQuad.bounds.left - rect.left + firstQuad.bounds.width / 2; + let x = firstQuadBounds.left - rect.left + firstQuadBounds.width / 2; // The first quad top edge is aligned with the bounding top edge, no // translation needed here. - let y = firstQuad.bounds.height / 2; + let y = firstQuadBounds.height / 2; info("Focusing the css property editable value"); let editor = yield focusEditableField(view, prop.editor.valueSpan, x, y); diff --git a/devtools/client/shared/autocomplete-popup.js b/devtools/client/shared/autocomplete-popup.js index b22de4d992..e848f6c1fd 100644 --- a/devtools/client/shared/autocomplete-popup.js +++ b/devtools/client/shared/autocomplete-popup.js @@ -283,7 +283,7 @@ AutocompletePopup.prototype = { return; } - let {top, height} = quads[0].bounds; + let {top, height} = quads[0].getBounds(); let containerHeight = this._tooltip.panel.getBoundingClientRect().height; if (top < 0) { // Element is above container. diff --git a/devtools/client/shared/test/browser_html_tooltip_arrow-01.js b/devtools/client/shared/test/browser_html_tooltip_arrow-01.js index a20c67529a..4c3b332d26 100644 --- a/devtools/client/shared/test/browser_html_tooltip_arrow-01.js +++ b/devtools/client/shared/test/browser_html_tooltip_arrow-01.js @@ -85,9 +85,9 @@ function* runTests(doc) { ok(arrow, "Tooltip has an arrow"); // Get the geometry of the anchor, the tooltip panel & arrow. - let arrowBounds = arrow.getBoxQuads({relativeTo: doc})[0].bounds; - let panelBounds = tooltip.panel.getBoxQuads({relativeTo: doc})[0].bounds; - let anchorBounds = el.getBoxQuads({relativeTo: doc})[0].bounds; + let arrowBounds = arrow.getBoxQuads({relativeTo: doc})[0].getBounds(); + let panelBounds = tooltip.panel.getBoxQuads({relativeTo: doc})[0].getBounds(); + let anchorBounds = el.getBoxQuads({relativeTo: doc})[0].getBounds(); let intersects = arrowBounds.left <= anchorBounds.right && arrowBounds.right >= anchorBounds.left; diff --git a/devtools/client/shared/test/browser_html_tooltip_arrow-02.js b/devtools/client/shared/test/browser_html_tooltip_arrow-02.js index 098f1ac7bf..5bf13e911e 100644 --- a/devtools/client/shared/test/browser_html_tooltip_arrow-02.js +++ b/devtools/client/shared/test/browser_html_tooltip_arrow-02.js @@ -78,9 +78,9 @@ function* runTests(doc) { ok(arrow, "Tooltip has an arrow"); // Get the geometry of the anchor, the tooltip panel & arrow. - let arrowBounds = arrow.getBoxQuads({relativeTo: doc})[0].bounds; - let panelBounds = tooltip.panel.getBoxQuads({relativeTo: doc})[0].bounds; - let anchorBounds = el.getBoxQuads({relativeTo: doc})[0].bounds; + let arrowBounds = arrow.getBoxQuads({relativeTo: doc})[0].getBounds(); + let panelBounds = tooltip.panel.getBoxQuads({relativeTo: doc})[0].getBounds(); + let anchorBounds = el.getBoxQuads({relativeTo: doc})[0].getBounds(); let intersects = arrowBounds.left <= anchorBounds.right && arrowBounds.right >= anchorBounds.left; diff --git a/devtools/client/shared/test/browser_inplace-editor_autocomplete_offset.js b/devtools/client/shared/test/browser_inplace-editor_autocomplete_offset.js index 2734125bd1..e5ce45b280 100644 --- a/devtools/client/shared/test/browser_inplace-editor_autocomplete_offset.js +++ b/devtools/client/shared/test/browser_inplace-editor_autocomplete_offset.js @@ -114,5 +114,5 @@ let runAutocompletionTest = Task.async(function* (editor) { */ function getPopupOffset({popup, input}) { let popupQuads = popup._panel.getBoxQuads({relativeTo: input}); - return popupQuads[0].bounds.left; + return popupQuads[0].getBounds().left; } diff --git a/devtools/client/shared/widgets/tooltip/HTMLTooltip.js b/devtools/client/shared/widgets/tooltip/HTMLTooltip.js index 9eb7910303..6cc12a53a4 100644 --- a/devtools/client/shared/widgets/tooltip/HTMLTooltip.js +++ b/devtools/client/shared/widgets/tooltip/HTMLTooltip.js @@ -176,9 +176,9 @@ const getRelativeRect = function (node, relativeTo) { // Width and Height can be taken from the rect. let {width, height} = node.getBoundingClientRect(); - let quads = node.getBoxQuads({relativeTo}); - let top = quads[0].bounds.top; - let left = quads[0].bounds.left; + let quadBounds = node.getBoxQuads({relativeTo})[0].getBounds(); + let top = quadBounds.top; + let left = quadBounds.left; // Compute right and bottom coordinates using the rest of the data. let right = left + width; diff --git a/devtools/server/actors/inspector.js b/devtools/server/actors/inspector.js index 883809b6cf..ba9393de58 100644 --- a/devtools/server/actors/inspector.js +++ b/devtools/server/actors/inspector.js @@ -3071,7 +3071,10 @@ function nodeHasSize(node) { } let quads = node.getBoxQuads(); - return quads.length && quads.some(quad => quad.bounds.width && quad.bounds.height); + return quads.some(quad => { + let bounds = quad.getBounds(); + return bounds.width && bounds.height; + }); } /** diff --git a/devtools/shared/layout/utils.js b/devtools/shared/layout/utils.js index 1e6ab5075a..bbe6df4c85 100644 --- a/devtools/shared/layout/utils.js +++ b/devtools/shared/layout/utils.js @@ -175,6 +175,11 @@ exports.getFrameOffsets = getFrameOffsets; /** * Get box quads adjusted for iframes and zoom level. * + * Warning: this function returns things that look like DOMQuad objects but + * aren't (they resemble an old version of the spec). Unlike the return value + * of node.getBoxQuads, they have a .bounds property and not a .getBounds() + * method. + * * @param {DOMWindow} boundaryWindow * The window where to stop to iterate. If `null` is given, the top * window is used. @@ -206,6 +211,7 @@ function getAdjustedQuads(boundaryWindow, node, region) { let adjustedQuads = []; for (let quad of quads) { + let bounds = quad.getBounds(); adjustedQuads.push({ p1: { w: quad.p1.w * scale, @@ -232,14 +238,14 @@ function getAdjustedQuads(boundaryWindow, node, region) { z: quad.p4.z * scale }, bounds: { - bottom: quad.bounds.bottom * scale + yOffset, - height: quad.bounds.height * scale, - left: quad.bounds.left * scale + xOffset, - right: quad.bounds.right * scale + xOffset, - top: quad.bounds.top * scale + yOffset, - width: quad.bounds.width * scale, - x: quad.bounds.x * scale + xOffset, - y: quad.bounds.y * scale + yOffset + bottom: bounds.bottom * scale + yOffset, + height: bounds.height * scale, + left: bounds.left * scale + xOffset, + right: bounds.right * scale + xOffset, + top: bounds.top * scale + yOffset, + width: bounds.width * scale, + x: bounds.x * scale + xOffset, + y: bounds.y * scale + yOffset } }); } 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 +#include "js/Equality.h" // JS::SameValueZero + namespace mozilla { namespace dom { +template +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 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((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( \ + 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::FromMatrix(const GlobalObject& aGlobal, const DOMMatrixInit& aMatrixInit, ErrorResult& aRv) +{ + DOMMatrixInit matrixInit(aMatrixInit); + if (!ValidateAndFixupMatrixInit(matrixInit, aRv)) { + return nullptr; + }; + + RefPtr rval = + new DOMMatrixReadOnly(aGlobal.GetAsSupports(), matrixInit.mIs2D.Value()); + rval->SetDataFromMatrixInit(matrixInit); + return rval.forget(); +} + + +already_AddRefed +DOMMatrixReadOnly::FromFloat32Array(const GlobalObject& aGlobal, const Float32Array& aArray32, ErrorResult& aRv) +{ + aArray32.ComputeLengthAndData(); + + const int length = aArray32.Length(); + const bool is2D = length == 6; + RefPtr obj = + new DOMMatrixReadOnly(aGlobal.GetAsSupports(), is2D); + SetDataInMatrix(obj, aArray32.Data(), length, aRv); + + return obj.forget(); +} + +already_AddRefed +DOMMatrixReadOnly::FromFloat64Array(const GlobalObject& aGlobal, const Float64Array& aArray64, ErrorResult& aRv) +{ + aArray64.ComputeLengthAndData(); + + const int length = aArray64.Length(); + const bool is2D = length == 6; + RefPtr obj = + new DOMMatrixReadOnly(aGlobal.GetAsSupports(), is2D); + SetDataInMatrix(obj, aArray64.Data(), length, aRv); + + return obj.forget(); +} + +already_AddRefed +DOMMatrixReadOnly::Constructor( + const GlobalObject& aGlobal, + const Optional& aArg, + ErrorResult& aRv) +{ + RefPtr rval = new DOMMatrixReadOnly(aGlobal.GetAsSupports()); + if (!aArg.WasPassed()) { + return rval.forget(); + } + + const auto& arg = aArg.Value(); + if (arg.IsString()) { + nsCOMPtr win = do_QueryInterface(aGlobal.GetAsSupports()); + if (!win) { + aRv.ThrowTypeError(); + 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::ReadStructuredClone(nsISupports* aParent, JSStructuredCloneReader* aReader) +{ + uint8_t is2D; + + if (!JS_ReadBytes(aReader, &is2D, 1)) { + return nullptr; + } + + RefPtr rval = new DOMMatrixReadOnly(aParent, is2D); + + if (!ReadStructuredCloneElements(aReader, rval)) { + return nullptr; + }; + + return rval.forget(); +} + already_AddRefed DOMMatrixReadOnly::Translate(double aTx, double aTy, @@ -127,10 +337,10 @@ DOMMatrixReadOnly::SkewY(double aSy) const } already_AddRefed -DOMMatrixReadOnly::Multiply(const DOMMatrix& other) const +DOMMatrixReadOnly::Multiply(const DOMMatrixInit& other, ErrorResult& aRv) const { RefPtr 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(f1), \ + BitwiseCast(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(high)); \ + (*(f2) = BitwiseCast(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::FromMatrix(nsISupports* aParent, const DOMMatrixInit& aMatrixInit, ErrorResult& aRv) +{ + DOMMatrixInit matrixInit(aMatrixInit); + if (!ValidateAndFixupMatrixInit(matrixInit, aRv)) { + return nullptr; + }; + + RefPtr matrix = new DOMMatrix(aParent, matrixInit.mIs2D.Value()); + matrix->SetDataFromMatrixInit(matrixInit); + return matrix.forget(); +} + +already_AddRefed +DOMMatrix::FromMatrix(const GlobalObject& aGlobal, const DOMMatrixInit& aMatrixInit, ErrorResult& aRv) +{ + RefPtr matrix = + FromMatrix(aGlobal.GetAsSupports(), aMatrixInit, aRv); + return matrix.forget(); +} + +already_AddRefed +DOMMatrix::FromFloat32Array(const GlobalObject& aGlobal, const Float32Array& aArray32, ErrorResult& aRv) +{ + aArray32.ComputeLengthAndData(); + + const int length = aArray32.Length(); + const bool is2D = length == 6; + RefPtr obj = new DOMMatrix(aGlobal.GetAsSupports(), is2D); + SetDataInMatrix(obj, aArray32.Data(), length, aRv); + + return obj.forget(); +} + +already_AddRefed +DOMMatrix::FromFloat64Array(const GlobalObject& aGlobal, const Float64Array& aArray64, ErrorResult& aRv) +{ + aArray64.ComputeLengthAndData(); + + const int length = aArray64.Length(); + const bool is2D = length == 6; + RefPtr obj = new DOMMatrix(aGlobal.GetAsSupports(), is2D); + SetDataInMatrix(obj, aArray64.Data(), length, aRv); + + return obj.forget(); +} + already_AddRefed DOMMatrix::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv) { @@ -317,6 +638,11 @@ DOMMatrix::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv) already_AddRefed DOMMatrix::Constructor(const GlobalObject& aGlobal, const nsAString& aTransformList, ErrorResult& aRv) { + nsCOMPtr win = do_QueryInterface(aGlobal.GetAsSupports()); + if (!win) { + aRv.ThrowTypeError(); + return nullptr; + } RefPtr 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 void SetDataInMatrix(DOMMatrix* aMatrix, const T* aData, int aLength, ErrorResult& aRv) +template +static void +SetDataInMatrix(DOMMatrixReadOnly* aMatrix, const T* aData, int aLength, ErrorResult& aRv) { if (aLength == 16) { aMatrix->SetM11(aData[0]); @@ -357,28 +685,22 @@ template 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(lengthStr); } } already_AddRefed DOMMatrix::Constructor(const GlobalObject& aGlobal, const Float32Array& aArray32, ErrorResult& aRv) { - RefPtr 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::Constructor(const GlobalObject& aGlobal, const Float64Array& aArray64, ErrorResult& aRv) { - RefPtr obj = new DOMMatrix(aGlobal.GetAsSupports()); - aArray64.ComputeLengthAndData(); - SetDataInMatrix(obj, aArray64.Data(), aArray64.Length(), aRv); - - return obj.forget(); + return FromFloat64Array(aGlobal, aArray64, aRv); } already_AddRefed @@ -390,7 +712,26 @@ DOMMatrix::Constructor(const GlobalObject& aGlobal, const Sequence& aNum return obj.forget(); } -void DOMMatrix::Ensure3DMatrix() +already_AddRefed +DOMMatrix::ReadStructuredClone(nsISupports* aParent, JSStructuredCloneReader* aReader) +{ + uint8_t is2D; + + if (!JS_ReadBytes(aReader, &is2D, 1)) { + return nullptr; + } + + RefPtr 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 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 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 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 aGivenProto) override; + + static already_AddRefed + FromMatrix(const GlobalObject& aGlobal, const DOMMatrixInit& aMatrixInit, ErrorResult& aRv); + + static already_AddRefed + FromFloat32Array(const GlobalObject& aGlobal, const Float32Array& aArray32, ErrorResult& aRv); + + static already_AddRefed + FromFloat64Array(const GlobalObject& aGlobal, const Float64Array& aArray64, ErrorResult& aRv); + + static already_AddRefed + Constructor(const GlobalObject& aGlobal, const Optional& aArg, ErrorResult& aRv); + + static already_AddRefed + ReadStructuredClone(nsISupports* aParent, JSStructuredCloneReader* aReader); + + static bool + ReadStructuredCloneElements(JSStructuredCloneReader* aReader, DOMMatrixReadOnly* matrix); + #define GetMatrixMember(entry2D, entry3D, default) \ { \ if (mMatrix3D) { \ @@ -88,88 +118,7 @@ public: #undef GetMatrixMember #undef Get3DMatrixMember - already_AddRefed Translate(double aTx, - double aTy, - double aTz = 0) const; - already_AddRefed Scale(double aScale, - double aOriginX = 0, - double aOriginY = 0) const; - already_AddRefed Scale3d(double aScale, - double aOriginX = 0, - double aOriginY = 0, - double aOriginZ = 0) const; - already_AddRefed ScaleNonUniform(double aScaleX, - double aScaleY = 1.0, - double aScaleZ = 1.0, - double aOriginX = 0, - double aOriginY = 0, - double aOriginZ = 0) const; - already_AddRefed Rotate(double aAngle, - double aOriginX = 0, - double aOriginY = 0) const; - already_AddRefed RotateFromVector(double aX, - double aY) const; - already_AddRefed RotateAxisAngle(double aX, - double aY, - double aZ, - double aAngle) const; - already_AddRefed SkewX(double aSx) const; - already_AddRefed SkewY(double aSy) const; - already_AddRefed Multiply(const DOMMatrix& aOther) const; - already_AddRefed FlipX() const; - already_AddRefed FlipY() const; - already_AddRefed Inverse() const; - - bool Is2D() const; - bool Identity() const; - already_AddRefed TransformPoint(const DOMPointInit& aPoint) const; - void ToFloat32Array(JSContext* aCx, - JS::MutableHandle aResult, - ErrorResult& aRv) const; - void ToFloat64Array(JSContext* aCx, - JS::MutableHandle aResult, - ErrorResult& aRv) const; - void Stringify(nsAString& aResult); -protected: - nsCOMPtr mParent; - nsAutoPtr mMatrix2D; - nsAutoPtr mMatrix3D; - - virtual ~DOMMatrixReadOnly() {} - -private: - DOMMatrixReadOnly() = delete; - DOMMatrixReadOnly(const DOMMatrixReadOnly&) = delete; - DOMMatrixReadOnly& operator=(const DOMMatrixReadOnly&) = delete; -}; - -class DOMMatrix : public DOMMatrixReadOnly -{ -public: - explicit DOMMatrix(nsISupports* aParent) - : DOMMatrixReadOnly(aParent) - {} - - DOMMatrix(nsISupports* aParent, const DOMMatrixReadOnly& other) - : DOMMatrixReadOnly(aParent, other) - {} - - static already_AddRefed - Constructor(const GlobalObject& aGlobal, ErrorResult& aRv); - static already_AddRefed - Constructor(const GlobalObject& aGlobal, const nsAString& aTransformList, ErrorResult& aRv); - static already_AddRefed - Constructor(const GlobalObject& aGlobal, const DOMMatrixReadOnly& aOther, ErrorResult& aRv); - static already_AddRefed - Constructor(const GlobalObject& aGlobal, const Float32Array& aArray32, ErrorResult& aRv); - static already_AddRefed - Constructor(const GlobalObject& aGlobal, const Float64Array& aArray64, ErrorResult& aRv); - static already_AddRefed - Constructor(const GlobalObject& aGlobal, const Sequence& aNumberSequence, ErrorResult& aRv); - - nsISupports* GetParentObject() const { return mParent; } - virtual JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; - + // Defined here so we can construct DOMMatrixReadOnly objects. #define Set2DMatrixMember(entry2D, entry3D) \ { \ if (mMatrix3D) { \ @@ -214,8 +163,128 @@ public: #undef Set2DMatrixMember #undef Set3DMatrixMember - DOMMatrix* MultiplySelf(const DOMMatrix& aOther); - DOMMatrix* PreMultiplySelf(const DOMMatrix& aOther); + already_AddRefed Translate(double aTx, + double aTy, + double aTz = 0) const; + already_AddRefed Scale(double aScale, + double aOriginX = 0, + double aOriginY = 0) const; + already_AddRefed Scale3d(double aScale, + double aOriginX = 0, + double aOriginY = 0, + double aOriginZ = 0) const; + already_AddRefed ScaleNonUniform(double aScaleX, + double aScaleY = 1.0, + double aScaleZ = 1.0, + double aOriginX = 0, + double aOriginY = 0, + double aOriginZ = 0) const; + already_AddRefed Rotate(double aAngle, + double aOriginX = 0, + double aOriginY = 0) const; + already_AddRefed RotateFromVector(double aX, + double aY) const; + already_AddRefed RotateAxisAngle(double aX, + double aY, + double aZ, + double aAngle) const; + already_AddRefed SkewX(double aSx) const; + already_AddRefed SkewY(double aSy) const; + already_AddRefed Multiply(const DOMMatrixInit& aOther, + ErrorResult& aRv) const; + already_AddRefed FlipX() const; + already_AddRefed FlipY() const; + already_AddRefed Inverse() const; + + bool Is2D() const; + bool Identity() const; + already_AddRefed TransformPoint(const DOMPointInit& aPoint) const; + void ToFloat32Array(JSContext* aCx, + JS::MutableHandle aResult, + ErrorResult& aRv) const; + void ToFloat64Array(JSContext* aCx, + JS::MutableHandle aResult, + ErrorResult& aRv) const; + void Stringify(nsAString& aResult); + bool WriteStructuredClone(JSStructuredCloneWriter* aWriter) const; + +protected: + nsCOMPtr mParent; + nsAutoPtr mMatrix2D; + nsAutoPtr mMatrix3D; + + 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; + DOMMatrixReadOnly& operator=(const DOMMatrixReadOnly&) = delete; +}; + +class DOMMatrix : public DOMMatrixReadOnly +{ +public: + explicit DOMMatrix(nsISupports* aParent) + : DOMMatrixReadOnly(aParent) + {} + + DOMMatrix(nsISupports* aParent, const DOMMatrixReadOnly& other) + : DOMMatrixReadOnly(aParent, other) + {} + + DOMMatrix(nsISupports* aParent, const gfx::Matrix4x4& aMatrix) + : DOMMatrixReadOnly(aParent, aMatrix) + {} + + static already_AddRefed + FromMatrix(nsISupports* aParent, const DOMMatrixInit& aMatrixInit, ErrorResult& aRv); + static already_AddRefed + FromMatrix(const GlobalObject& aGlobal, const DOMMatrixInit& aMatrixInit, ErrorResult& aRv); + + static already_AddRefed + FromFloat32Array(const GlobalObject& aGlobal, const Float32Array& aArray32, ErrorResult& aRv); + + static already_AddRefed + FromFloat64Array(const GlobalObject& aGlobal, const Float64Array& aArray64, ErrorResult& aRv); + + static already_AddRefed + Constructor(const GlobalObject& aGlobal, ErrorResult& aRv); + static already_AddRefed + Constructor(const GlobalObject& aGlobal, const nsAString& aTransformList, ErrorResult& aRv); + static already_AddRefed + Constructor(const GlobalObject& aGlobal, const DOMMatrixReadOnly& aOther, ErrorResult& aRv); + static already_AddRefed + Constructor(const GlobalObject& aGlobal, const Float32Array& aArray32, ErrorResult& aRv); + static already_AddRefed + Constructor(const GlobalObject& aGlobal, const Float64Array& aArray64, ErrorResult& aRv); + static already_AddRefed + Constructor(const GlobalObject& aGlobal, const Sequence& aNumberSequence, ErrorResult& aRv); + + static already_AddRefed + ReadStructuredClone(nsISupports* aParent, JSStructuredCloneReader* aReader); + + virtual JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; + + 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::FromPoint(const GlobalObject& aGlobal, const DOMPointInit& aParams) +{ + RefPtr obj = + new DOMPointReadOnly(aGlobal.GetAsSupports(), aParams.mX, aParams.mY, + aParams.mZ, aParams.mW); + return obj.forget(); +} + +already_AddRefed +DOMPointReadOnly::Constructor(const GlobalObject& aGlobal, double aX, double aY, + double aZ, double aW, ErrorResult& aRV) +{ + RefPtr obj = + new DOMPointReadOnly(aGlobal.GetAsSupports(), aX, aY, aZ, aW); + return obj.forget(); +} + +JSObject* +DOMPointReadOnly::WrapObject(JSContext* aCx, JS::Handle 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(d) >> 32) & 0xffffffff, \ + BitwiseCast(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(static_cast(high) << 32 | low)) + + ReadDouble(&mX); + ReadDouble(&mY); + ReadDouble(&mZ); + ReadDouble(&mW); + + return true; + +#undef ReadDouble +} + already_AddRefed -DOMPoint::Constructor(const GlobalObject& aGlobal, const DOMPointInit& aParams, - ErrorResult& aRV) +DOMPoint::FromPoint(const GlobalObject& aGlobal, const DOMPointInit& aParams) { RefPtr 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 + FromPoint(const GlobalObject& aGlobal, const DOMPointInit& aParams); + static already_AddRefed + 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 aGivenProto) override; + + bool WriteStructuredClone(JSStructuredCloneWriter* aWriter) const; + + bool ReadStructuredClone(JSStructuredCloneReader* aReader); + protected: virtual ~DOMPointReadOnly() {} @@ -57,13 +71,11 @@ public: {} static already_AddRefed - Constructor(const GlobalObject& aGlobal, const DOMPointInit& aParams, - ErrorResult& aRV); + FromPoint(const GlobalObject& aGlobal, const DOMPointInit& aParams); static already_AddRefed 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 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 @@ -43,6 +43,32 @@ DOMQuad::WrapObject(JSContext* aCx, JS::Handle aGivenProto) return DOMQuadBinding::Wrap(aCx, this, aGivenProto); } +already_AddRefed +DOMQuad::FromRect(const GlobalObject& aGlobal, const DOMRectInit& aInit) +{ + nsISupports* parent = aGlobal.GetAsSupports(); + RefPtr 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::FromQuad(const GlobalObject& aGlobal, const DOMQuadInit& aInit) +{ + RefPtr 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::Constructor(const GlobalObject& aGlobal, const DOMPointInit& aP1, @@ -52,10 +78,10 @@ DOMQuad::Constructor(const GlobalObject& aGlobal, ErrorResult& aRV) { RefPtr 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; + 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); } - virtual double Y() const override - { - double y1, y2; - GetVerticalMinMax(&y1, &y2); - return y1; + *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); } - 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; - } - - 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 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; - } - -protected: - virtual ~QuadBounds() {} - - RefPtr mQuad; -}; - -NS_IMPL_CYCLE_COLLECTION_INHERITED(DOMQuad::QuadBounds, DOMRectReadOnly, mQuad) - -NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(DOMQuad::QuadBounds) -NS_INTERFACE_MAP_END_INHERITING(DOMRectReadOnly) - -NS_IMPL_ADDREF_INHERITED(DOMQuad::QuadBounds, DOMRectReadOnly) -NS_IMPL_RELEASE_INHERITED(DOMQuad::QuadBounds, DOMRectReadOnly) + *aY1 = y1; + *aY2 = y2; +} DOMRectReadOnly* -DOMQuad::Bounds() const +DOMQuad::Bounds() { if (!mBounds) { - mBounds = new QuadBounds(const_cast(this)); + mBounds = GetBounds(); } return mBounds; } + +already_AddRefed +DOMQuad::GetBounds() const +{ + double x1, x2; + double y1, y2; + + GetHorizontalMinMax(&x1, &x2); + GetVerticalMinMax(&y1, &y2); + + RefPtr rval = new DOMRectReadOnly(GetParentObject(), + x1, y1, x2 - x1, y2 - y1); + return rval.forget(); +} + +void +DOMQuad::ToJSON(DOMQuadJSON& aInit) +{ + aInit.mP1.Construct(RefPtr(P1()).forget()); + aInit.mP2.Construct(RefPtr(P2()).forget()); + aInit.mP3.Construct(RefPtr(P3()).forget()); + aInit.mP4.Construct(RefPtr(P4()).forget()); +} + +// 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; +} + +bool +DOMQuad::ReadStructuredClone(JSStructuredCloneReader* aReader) +{ + for (auto& point : mPoints) { + point = new DOMPoint(mParent); + if (!point->ReadStructuredClone(aReader)) { + return false; + } + } + 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 { @@ -36,6 +40,12 @@ public: nsISupports* GetParentObject() const { return mParent; } virtual JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; + static already_AddRefed + FromRect(const GlobalObject& aGlobal, const DOMRectInit& aInit); + + static already_AddRefed + FromQuad(const GlobalObject& aGlobal, const DOMQuadInit& aInit); + static already_AddRefed Constructor(const GlobalObject& aGlobal, const DOMPointInit& aP1, @@ -47,20 +57,28 @@ public: Constructor(const GlobalObject& aGlobal, const DOMRectReadOnly& aRect, ErrorResult& aRV); - DOMRectReadOnly* Bounds() const; + DOMRectReadOnly* Bounds(); + already_AddRefed 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 mParent; RefPtr mPoints[4]; - mutable RefPtr mBounds; // allocated lazily + RefPtr 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 aGivenProto) return DOMRectReadOnlyBinding::Wrap(aCx, this, aGivenProto); } +already_AddRefed +DOMRectReadOnly::FromRect(const GlobalObject& aGlobal, const DOMRectInit& aInit) +{ + RefPtr obj = new DOMRectReadOnly( + aGlobal.GetAsSupports(), aInit.mX, aInit.mY, aInit.mWidth, aInit.mHeight); + return obj.forget(); +} + +already_AddRefed +DOMRectReadOnly::Constructor(const GlobalObject& aGlobal, double aX, double aY, + double aWidth, double aHeight, ErrorResult& aRv) +{ + RefPtr 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(d) >> 32) & 0xffffffff, \ + BitwiseCast(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(static_cast(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 aGivenProto) } already_AddRefed -DOMRect::Constructor(const GlobalObject& aGlobal, ErrorResult& aRV) +DOMRect::FromRect(const GlobalObject& aGlobal, const DOMRectInit& aInit) { - RefPtr obj = - new DOMRect(aGlobal.GetAsSupports(), 0.0, 0.0, 0.0, 0.0); + RefPtr obj = new DOMRect(aGlobal.GetAsSupports(), aInit.mX, aInit.mY, + aInit.mWidth, aInit.mHeight); return obj.forget(); } already_AddRefed DOMRect::Constructor(const GlobalObject& aGlobal, double aX, double aY, - double aWidth, double aHeight, ErrorResult& aRV) + double aWidth, double aHeight, ErrorResult& aRv) { RefPtr 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 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 + FromRect(const GlobalObject& aGlobal, const DOMRectInit& aInit); + + static already_AddRefed + 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 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 - Constructor(const GlobalObject& aGlobal, ErrorResult& aRV); + FromRect(const GlobalObject& aGlobal, const DOMRectInit& aInit); + static already_AddRefed 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 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 = new DOMPoint(global); + if (!domPoint->ReadStructuredClone(aReader)) { + result = nullptr; + } else { + result = domPoint->WrapObject(aCx, nullptr); + } + } else if (aTag == SCTAG_DOM_DOMPOINT_READONLY) { + RefPtr domPoint = new DOMPointReadOnly(global); + if (!domPoint->ReadStructuredClone(aReader)) { + result = nullptr; + } else { + result = domPoint->WrapObject(aCx, nullptr); + } + } else if (aTag == SCTAG_DOM_DOMRECT) { + RefPtr domRect = new DOMRect(global); + if (!domRect->ReadStructuredClone(aReader)) { + result = nullptr; + } else { + result = domRect->WrapObject(aCx, nullptr); + } + } else if (aTag == SCTAG_DOM_DOMRECT_READONLY) { + RefPtr domRect = new DOMRectReadOnly(global); + if (!domRect->ReadStructuredClone(aReader)) { + result = nullptr; + } else { + result = domRect->WrapObject(aCx, nullptr); + } + } else if (aTag == SCTAG_DOM_DOMQUAD) { + RefPtr 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::ReadStructuredClone(global, aReader); + if (!domMatrix) { + result = nullptr; + } else { + result = domMatrix->WrapObject(aCx, nullptr); + } + } else if (aTag == SCTAG_DOM_DOMMATRIX_READONLY) { + RefPtr 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 base = xpc::UnwrapReflectorToISupports(obj); nsCOMPtr 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 @@ -115,10 +114,10 @@ WebKitCSSMatrix::SetMatrixValue(const nsAString& aTransformList, } already_AddRefed -WebKitCSSMatrix::Multiply(const WebKitCSSMatrix& other) const +WebKitCSSMatrix::Multiply(const DOMMatrixInit& aOtherInit, ErrorResult& aRv) const { RefPtr 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 Multiply(const WebKitCSSMatrix& aOther) const; + already_AddRefed Multiply(const DOMMatrixInit& aOtherInit, + ErrorResult& aRv) const; already_AddRefed Inverse(ErrorResult& aRv) const; already_AddRefed 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 5f6a9083dd..e1560bfa3f 100644 --- a/dom/bindings/Bindings.conf +++ b/dom/bindings/Bindings.conf @@ -253,12 +253,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/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) 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 numberSequence)] + Constructor(sequence 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, diff --git a/js/public/Equality.h b/js/public/Equality.h new file mode 100644 index 0000000000..6d2db50fa9 --- /dev/null +++ b/js/public/Equality.h @@ -0,0 +1,68 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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/. */ + +/* Equality operations. */ + +#ifndef js_Equality_h +#define js_Equality_h + +#include "mozilla/FloatingPoint.h" + +#include "jstypes.h" // JS_PUBLIC_API + +#include "js/RootingAPI.h" // JS::Handle +#include "js/Value.h" // JS::Value + +struct JSContext; + +namespace JS { + +/** + * Store |v1 === v2| to |*equal| -- strict equality, which performs no + * conversions on |v1| or |v2| before comparing. + * + * This operation can fail only if an internal error occurs (e.g. OOM while + * linearizing a string value). + */ +extern JS_PUBLIC_API(bool) +StrictlyEqual(JSContext* cx, JS::Handle v1, JS::Handle v2, bool* equal); + +/** + * Store |v1 == v2| to |*equal| -- loose equality, which may perform + * user-modifiable conversions on |v1| or |v2|. + * + * This operation can fail if a user-modifiable conversion fails *or* if an + * internal error occurs. (e.g. OOM while linearizing a string value). + */ +extern JS_PUBLIC_API(bool) +LooselyEqual(JSContext* cx, JS::Handle v1, JS::Handle v2, bool* equal); + +/** + * Stores |SameValue(v1, v2)| to |*equal| -- using the SameValue operation + * defined in ECMAScript, initially exposed to script as |Object.is|. SameValue + * behaves identically to strict equality, except that it equates two NaN values + * and does not equate differently-signed zeroes. It performs no conversions on + * |v1| or |v2| before comparing. + * + * This operation can fail only if an internal error occurs (e.g. OOM while + * linearizing a string value). + */ +extern JS_PUBLIC_API(bool) +SameValue(JSContext* cx, JS::Handle v1, JS::Handle v2, bool* same); + +/** + * Implements |SameValueZero(v1, v2)| for Number values |v1| and |v2|. + * SameValueZero equates NaNs, equal nonzero values, and zeroes without respect + * to their signs. + */ +static inline bool +SameValueZero(double v1, double v2) +{ + return mozilla::EqualOrBothNaN(v1, v2); +} + +} // namespace JS + +#endif /* js_Equality_h */ diff --git a/js/src/builtin/MapObject.cpp b/js/src/builtin/MapObject.cpp index 9d17acbf8a..893e0448a4 100644 --- a/js/src/builtin/MapObject.cpp +++ b/js/src/builtin/MapObject.cpp @@ -12,6 +12,7 @@ #include "ds/OrderedHashTable.h" #include "gc/Marking.h" #include "js/Utility.h" +#include "vm/EqualityOperations.h" // js::SameValue #include "vm/GlobalObject.h" #include "vm/Interpreter.h" #include "vm/SelfHosting.h" diff --git a/js/src/builtin/Object.cpp b/js/src/builtin/Object.cpp index d661a222e5..70a21079c0 100644 --- a/js/src/builtin/Object.cpp +++ b/js/src/builtin/Object.cpp @@ -15,6 +15,7 @@ #include "jit/InlinableNatives.h" #include "js/UniquePtr.h" #include "vm/AsyncFunction.h" +#include "vm/EqualityOperations.h" // js::SameValue #include "vm/StringBuffer.h" #include "jsobjinlines.h" diff --git a/js/src/jit/VMFunctions.cpp b/js/src/jit/VMFunctions.cpp index f191ce7d6d..6e5676f153 100644 --- a/js/src/jit/VMFunctions.cpp +++ b/js/src/jit/VMFunctions.cpp @@ -17,6 +17,7 @@ #include "jit/mips64/Simulator-mips64.h" #include "vm/ArrayObject.h" #include "vm/Debugger.h" +#include "vm/EqualityOperations.h" // js::StrictlyEqual #include "vm/Interpreter.h" #include "vm/TraceLogging.h" diff --git a/js/src/jsapi-tests/testLooselyEqual.cpp b/js/src/jsapi-tests/testLooselyEqual.cpp index 70f5cf8964..5c017497c9 100644 --- a/js/src/jsapi-tests/testLooselyEqual.cpp +++ b/js/src/jsapi-tests/testLooselyEqual.cpp @@ -5,6 +5,8 @@ #include #include +#include "js/Equality.h" // JS::LooselyEqual + #include "jsapi-tests/tests.h" using namespace std; @@ -15,15 +17,15 @@ struct LooseEqualityFixture : public JSAPITest bool leq(JS::HandleValue x, JS::HandleValue y) { bool equal; - CHECK(JS_LooselyEqual(cx, x, y, &equal) && equal); - CHECK(JS_LooselyEqual(cx, y, x, &equal) && equal); + CHECK(JS::LooselyEqual(cx, x, y, &equal) && equal); + CHECK(JS::LooselyEqual(cx, y, x, &equal) && equal); return true; } bool nleq(JS::HandleValue x, JS::HandleValue y) { bool equal; - CHECK(JS_LooselyEqual(cx, x, y, &equal) && !equal); - CHECK(JS_LooselyEqual(cx, y, x, &equal) && !equal); + CHECK(JS::LooselyEqual(cx, x, y, &equal) && !equal); + CHECK(JS::LooselyEqual(cx, y, x, &equal) && !equal); return true; } }; diff --git a/js/src/jsapi-tests/testSameValue.cpp b/js/src/jsapi-tests/testSameValue.cpp index 666da40360..50d2208d86 100644 --- a/js/src/jsapi-tests/testSameValue.cpp +++ b/js/src/jsapi-tests/testSameValue.cpp @@ -4,6 +4,7 @@ * 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/. */ +#include "js/Equality.h" // JS::SameValue #include "jsapi-tests/tests.h" BEGIN_TEST(testSameValue) @@ -11,7 +12,7 @@ BEGIN_TEST(testSameValue) /* * NB: passing a double that fits in an integer jsval is API misuse. As a - * matter of defense in depth, however, JS_SameValue should return the + * matter of defense in depth, however, JS::SameValue should return the * correct result comparing a positive-zero double to a negative-zero * double, and this is believed to be the only way to make such a * comparison possible. @@ -19,7 +20,7 @@ BEGIN_TEST(testSameValue) JS::RootedValue v1(cx, JS::DoubleValue(0.0)); JS::RootedValue v2(cx, JS::DoubleValue(-0.0)); bool same; - CHECK(JS_SameValue(cx, v1, v2, &same)); + CHECK(JS::SameValue(cx, v1, v2, &same)); CHECK(!same); return true; } diff --git a/js/src/jsapi-tests/tests.h b/js/src/jsapi-tests/tests.h index 4d30ba8c85..dfb9f49887 100644 --- a/js/src/jsapi-tests/tests.h +++ b/js/src/jsapi-tests/tests.h @@ -18,6 +18,7 @@ #include "jscntxt.h" #include "jsgc.h" +#include "js/Equality.h" // JS::SameValue #include "js/Vector.h" /* Note: Aborts on OOM. */ @@ -201,9 +202,9 @@ class JSAPITest const char* filename, int lineno) { bool same; JS::RootedValue actual(cx, actualArg), expected(cx, expectedArg); - return (JS_SameValue(cx, actual, expected, &same) && same) || - fail(JSAPITestString("CHECK_SAME failed: expected JS_SameValue(cx, ") + - actualExpr + ", " + expectedExpr + "), got !JS_SameValue(cx, " + + return (JS::SameValue(cx, actual, expected, &same) && same) || + fail(JSAPITestString("CHECK_SAME failed: expected JS::SameValue(cx, ") + + actualExpr + ", " + expectedExpr + "), got !JS::SameValue(cx, " + jsvalToSource(actual) + ", " + jsvalToSource(expected) + ")", filename, lineno); } diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 50e3442ae8..9e5853b454 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -391,36 +391,6 @@ JS_TypeOfValue(JSContext* cx, HandleValue value) return TypeOfValue(value); } -JS_PUBLIC_API(bool) -JS_StrictlyEqual(JSContext* cx, HandleValue value1, HandleValue value2, bool* equal) -{ - AssertHeapIsIdle(cx); - CHECK_REQUEST(cx); - assertSameCompartment(cx, value1, value2); - MOZ_ASSERT(equal); - return StrictlyEqual(cx, value1, value2, equal); -} - -JS_PUBLIC_API(bool) -JS_LooselyEqual(JSContext* cx, HandleValue value1, HandleValue value2, bool* equal) -{ - AssertHeapIsIdle(cx); - CHECK_REQUEST(cx); - assertSameCompartment(cx, value1, value2); - MOZ_ASSERT(equal); - return LooselyEqual(cx, value1, value2, equal); -} - -JS_PUBLIC_API(bool) -JS_SameValue(JSContext* cx, HandleValue value1, HandleValue value2, bool* same) -{ - AssertHeapIsIdle(cx); - CHECK_REQUEST(cx); - assertSameCompartment(cx, value1, value2); - MOZ_ASSERT(same); - return SameValue(cx, value1, value2, same); -} - JS_PUBLIC_API(bool) JS_IsBuiltinEvalFunction(JSFunction* fun) { diff --git a/js/src/jsapi.h b/js/src/jsapi.h index a6a5429cf5..923aa2bb05 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -959,15 +959,6 @@ InformalValueTypeName(const JS::Value& v); } /* namespace JS */ -extern JS_PUBLIC_API(bool) -JS_StrictlyEqual(JSContext* cx, JS::Handle v1, JS::Handle v2, bool* equal); - -extern JS_PUBLIC_API(bool) -JS_LooselyEqual(JSContext* cx, JS::Handle v1, JS::Handle v2, bool* equal); - -extern JS_PUBLIC_API(bool) -JS_SameValue(JSContext* cx, JS::Handle v1, JS::Handle v2, bool* same); - /** True iff fun is the global eval function. */ extern JS_PUBLIC_API(bool) JS_IsBuiltinEvalFunction(JSFunction* fun); diff --git a/js/src/moz.build b/js/src/moz.build index b12d0a90cc..0f1302bb93 100644 --- a/js/src/moz.build +++ b/js/src/moz.build @@ -70,6 +70,7 @@ EXPORTS.js += [ '../public/Conversions.h', '../public/Date.h', '../public/Debug.h', + '../public/Equality.h', '../public/GCAnnotations.h', '../public/GCAPI.h', '../public/GCHashTable.h', @@ -293,6 +294,7 @@ main_deunified_sources = [ 'vm/Debugger.cpp', 'vm/DebuggerMemory.cpp', 'vm/EnvironmentObject.cpp', + 'vm/EqualityOperations.cpp', 'vm/ErrorObject.cpp', 'vm/ForOfIterator.cpp', 'vm/GeneratorObject.cpp', diff --git a/js/src/proxy/ScriptedProxyHandler.cpp b/js/src/proxy/ScriptedProxyHandler.cpp index adb98edbdd..d396b7805c 100644 --- a/js/src/proxy/ScriptedProxyHandler.cpp +++ b/js/src/proxy/ScriptedProxyHandler.cpp @@ -7,6 +7,8 @@ #include "jsapi.h" +#include "vm/EqualityOperations.h" // js::SameValue + #include "jsobjinlines.h" #include "vm/NativeObject-inl.h" diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index bab5cbb0b5..eaac23b537 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -71,6 +71,7 @@ #include "jit/JitcodeMap.h" #include "jit/OptimizationTracking.h" #include "js/Debug.h" +#include "js/Equality.h" // JS::SameValue #include "js/GCAPI.h" #include "js/Initialization.h" #include "js/StructuredClone.h" @@ -2286,7 +2287,7 @@ AssertEq(JSContext* cx, unsigned argc, Value* vp) } bool same; - if (!JS_SameValue(cx, args[0], args[1], &same)) + if (!JS::SameValue(cx, args[0], args[1], &same)) return false; if (!same) { JSAutoByteString bytes0, bytes1; diff --git a/js/src/vm/EqualityOperations.cpp b/js/src/vm/EqualityOperations.cpp new file mode 100644 index 0000000000..6f90450b49 --- /dev/null +++ b/js/src/vm/EqualityOperations.cpp @@ -0,0 +1,215 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * 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/. */ + +#include "vm/EqualityOperations.h" // js::LooselyEqual, js::StrictlyEqual, js::SameValue + +#include "mozilla/Assertions.h" // MOZ_ASSERT, MOZ_ASSERT_IF + +#include "jsapi.h" // js::AssertHeapIsIdle, CHECK_REQUEST +#include "jsnum.h" // js::StringToNumber +#include "jsobj.h" // js::ToPrimitive +#include "jsstr.h" // js::EqualStrings +#include "jstypes.h" // JS_PUBLIC_API + +#include "js/Equality.h" // JS::LooselyEqual, JS::StrictlyEqual, JS::SameValue +#include "js/RootingAPI.h" // JS::Rooted, JS::Handle +#include "js/Value.h" // JS::Int32Value, JS::SameType, JS::Value + +#include "jsboolinlines.h" // js::EmulatesUndefined +#include "jscntxtinlines.h" // js::assertSameCompartment + +static inline bool +EqualGivenSameType(JSContext* cx, JS::HandleValue lval, JS::HandleValue rval, bool* equal) +{ + MOZ_ASSERT(SameType(lval, rval)); + + if (lval.isString()) + return EqualStrings(cx, lval.toString(), rval.toString(), equal); + if (lval.isDouble()) { + *equal = (lval.toDouble() == rval.toDouble()); + return true; + } + if (lval.isGCThing()) { // objects or symbols + *equal = (lval.toGCThing() == rval.toGCThing()); + return true; + } + *equal = lval.get().payloadAsRawUint32() == rval.get().payloadAsRawUint32(); + MOZ_ASSERT_IF(lval.isUndefined() || lval.isNull(), *equal); + return true; +} + +static inline bool +LooselyEqualBooleanAndOther(JSContext* cx, JS::HandleValue lval, JS::HandleValue rval, bool* result) +{ + MOZ_ASSERT(!rval.isBoolean()); + JS::RootedValue lvalue(cx, JS::Int32Value(lval.toBoolean() ? 1 : 0)); + + // The tail-call would end up in Step 3. + if (rval.isNumber()) { + *result = (lvalue.toNumber() == rval.toNumber()); + return true; + } + // The tail-call would end up in Step 6. + if (rval.isString()) { + double num; + if (!StringToNumber(cx, rval.toString(), &num)) + return false; + *result = (lvalue.toNumber() == num); + return true; + } + + return js::LooselyEqual(cx, lvalue, rval, result); +} + +// ES6 draft rev32 7.2.12 Abstract Equality Comparison +bool +js::LooselyEqual(JSContext* cx, JS::HandleValue lval, JS::HandleValue rval, bool* result) +{ + // Step 3. + if (SameType(lval, rval)) + return EqualGivenSameType(cx, lval, rval, result); + + // Handle int32 x double. + if (lval.isNumber() && rval.isNumber()) { + *result = (lval.toNumber() == rval.toNumber()); + return true; + } + + // Step 4. This a bit more complex, because of the undefined emulating object. + if (lval.isNullOrUndefined()) { + // We can return early here, because null | undefined is only equal to the same set. + *result = rval.isNullOrUndefined() || + (rval.isObject() && EmulatesUndefined(&rval.toObject())); + return true; + } + + // Step 5. + if (rval.isNullOrUndefined()) { + MOZ_ASSERT(!lval.isNullOrUndefined()); + *result = lval.isObject() && EmulatesUndefined(&lval.toObject()); + return true; + } + + // Step 6. + if (lval.isNumber() && rval.isString()) { + double num; + if (!StringToNumber(cx, rval.toString(), &num)) + return false; + *result = (lval.toNumber() == num); + return true; + } + + // Step 7. + if (lval.isString() && rval.isNumber()) { + double num; + if (!StringToNumber(cx, lval.toString(), &num)) + return false; + *result = (num == rval.toNumber()); + return true; + } + + // Step 8. + if (lval.isBoolean()) + return LooselyEqualBooleanAndOther(cx, lval, rval, result); + + // Step 9. + if (rval.isBoolean()) + return LooselyEqualBooleanAndOther(cx, rval, lval, result); + + // Step 10. + if ((lval.isString() || lval.isNumber() || lval.isSymbol()) && rval.isObject()) { + JS::RootedValue rvalue(cx, rval); + if (!ToPrimitive(cx, &rvalue)) + return false; + return js::LooselyEqual(cx, lval, rvalue, result); + } + + // Step 11. + if (lval.isObject() && (rval.isString() || rval.isNumber() || rval.isSymbol())) { + JS::RootedValue lvalue(cx, lval); + if (!ToPrimitive(cx, &lvalue)) + return false; + return js::LooselyEqual(cx, lvalue, rval, result); + } + + // Step 12. + *result = false; + return true; +} + +JS_PUBLIC_API(bool) +JS::LooselyEqual(JSContext* cx, Handle value1, Handle value2, bool* equal) +{ + js::AssertHeapIsIdle(cx); + CHECK_REQUEST(cx); + js::assertSameCompartment(cx, value1, value2); + MOZ_ASSERT(equal); + return js::LooselyEqual(cx, value1, value2, equal); +} + +bool +js::StrictlyEqual(JSContext* cx, JS::HandleValue lval, JS::HandleValue rval, bool* equal) +{ + if (SameType(lval, rval)) + return EqualGivenSameType(cx, lval, rval, equal); + + if (lval.isNumber() && rval.isNumber()) { + *equal = (lval.toNumber() == rval.toNumber()); + return true; + } + + *equal = false; + return true; +} + +JS_PUBLIC_API(bool) +JS::StrictlyEqual(JSContext* cx, Handle value1, Handle value2, bool* equal) +{ + js::AssertHeapIsIdle(cx); + CHECK_REQUEST(cx); + js::assertSameCompartment(cx, value1, value2); + MOZ_ASSERT(equal); + return js::StrictlyEqual(cx, value1, value2, equal); +} + +static inline bool +IsNegativeZero(const JS::Value& v) +{ + return v.isDouble() && mozilla::IsNegativeZero(v.toDouble()); +} + +static inline bool +IsNaN(const JS::Value& v) +{ + return v.isDouble() && mozilla::IsNaN(v.toDouble()); +} + +bool +js::SameValue(JSContext* cx, JS::HandleValue v1, JS::HandleValue v2, bool* same) +{ + if (IsNegativeZero(v1)) { + *same = IsNegativeZero(v2); + return true; + } + if (IsNegativeZero(v2)) { + *same = false; + return true; + } + if (IsNaN(v1) && IsNaN(v2)) { + *same = true; + return true; + } + return js::StrictlyEqual(cx, v1, v2, same); +} + +JS_PUBLIC_API(bool) +JS::SameValue(JSContext* cx, Handle value1, Handle value2, bool* same) +{ + js::AssertHeapIsIdle(cx); + CHECK_REQUEST(cx); + js::assertSameCompartment(cx, value1, value2); + MOZ_ASSERT(same); + return js::SameValue(cx, value1, value2, same); +} diff --git a/js/src/vm/EqualityOperations.h b/js/src/vm/EqualityOperations.h new file mode 100644 index 0000000000..13cae70b16 --- /dev/null +++ b/js/src/vm/EqualityOperations.h @@ -0,0 +1,44 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * 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/. */ + +/* + * The equality comparisons of js/Equality.h, but with extra efficiency for + * SpiderMonkey-internal callers. + * + * These functions, assuming they're passed C++-valid arguments, are identical + * to the same-named JS::-namespaced functions -- just with hidden linkage (so + * they're more efficient to call), and without various external-caller-focused + * JSAPI-usage assertions performed that SpiderMonkey users never come close to + * failing. + */ + +#ifndef vm_EqualityOperations_h +#define vm_EqualityOperations_h + +#include "js/RootingAPI.h" // JS::Handle +#include "js/Value.h" // JS::Value + +struct JSContext; + +namespace js { + +/** Computes |lval === rval|. */ +extern bool +StrictlyEqual(JSContext* cx, JS::HandleValue lval, JS::HandleValue rval, bool* equal); + +/** Computes |lval == rval|. */ +extern bool +LooselyEqual(JSContext* cx, JS::HandleValue lval, JS::HandleValue rval, bool* result); + +/** + * Computes |SameValue(v1, v2)| -- strict equality except that NaNs are + * considered equal and opposite-signed zeroes are considered unequal. + */ +extern bool +SameValue(JSContext* cx, JS::HandleValue v1, JS::HandleValue v2, bool* same); + +} // namespace js + +#endif // vm_EqualityOperations_h diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index b17c762eae..d7c1b8e84a 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -41,6 +41,7 @@ #include "vm/AsyncFunction.h" #include "vm/AsyncIteration.h" #include "vm/Debugger.h" +#include "vm/EqualityOperations.h" // js::StrictlyEqual #include "vm/GeneratorObject.h" #include "vm/Opcodes.h" #include "vm/Scope.h" @@ -786,170 +787,6 @@ js::HasInstance(JSContext* cx, HandleObject obj, HandleValue v, bool* bp) return JS::InstanceofOperator(cx, obj, local, bp); } -static inline bool -EqualGivenSameType(JSContext* cx, HandleValue lval, HandleValue rval, bool* equal) -{ - MOZ_ASSERT(SameType(lval, rval)); - - if (lval.isString()) - return EqualStrings(cx, lval.toString(), rval.toString(), equal); - if (lval.isDouble()) { - *equal = (lval.toDouble() == rval.toDouble()); - return true; - } - if (lval.isGCThing()) { // objects or symbols - *equal = (lval.toGCThing() == rval.toGCThing()); - return true; - } - *equal = lval.get().payloadAsRawUint32() == rval.get().payloadAsRawUint32(); - MOZ_ASSERT_IF(lval.isUndefined() || lval.isNull(), *equal); - return true; -} - -static inline bool -LooselyEqualBooleanAndOther(JSContext* cx, HandleValue lval, HandleValue rval, bool* result) -{ - MOZ_ASSERT(!rval.isBoolean()); - RootedValue lvalue(cx, Int32Value(lval.toBoolean() ? 1 : 0)); - - // The tail-call would end up in Step 3. - if (rval.isNumber()) { - *result = (lvalue.toNumber() == rval.toNumber()); - return true; - } - // The tail-call would end up in Step 6. - if (rval.isString()) { - double num; - if (!StringToNumber(cx, rval.toString(), &num)) - return false; - *result = (lvalue.toNumber() == num); - return true; - } - - return LooselyEqual(cx, lvalue, rval, result); -} - -// ES6 draft rev32 7.2.12 Abstract Equality Comparison -bool -js::LooselyEqual(JSContext* cx, HandleValue lval, HandleValue rval, bool* result) -{ - // Step 3. - if (SameType(lval, rval)) - return EqualGivenSameType(cx, lval, rval, result); - - // Handle int32 x double. - if (lval.isNumber() && rval.isNumber()) { - *result = (lval.toNumber() == rval.toNumber()); - return true; - } - - // Step 4. This a bit more complex, because of the undefined emulating object. - if (lval.isNullOrUndefined()) { - // We can return early here, because null | undefined is only equal to the same set. - *result = rval.isNullOrUndefined() || - (rval.isObject() && EmulatesUndefined(&rval.toObject())); - return true; - } - - // Step 5. - if (rval.isNullOrUndefined()) { - MOZ_ASSERT(!lval.isNullOrUndefined()); - *result = lval.isObject() && EmulatesUndefined(&lval.toObject()); - return true; - } - - // Step 6. - if (lval.isNumber() && rval.isString()) { - double num; - if (!StringToNumber(cx, rval.toString(), &num)) - return false; - *result = (lval.toNumber() == num); - return true; - } - - // Step 7. - if (lval.isString() && rval.isNumber()) { - double num; - if (!StringToNumber(cx, lval.toString(), &num)) - return false; - *result = (num == rval.toNumber()); - return true; - } - - // Step 8. - if (lval.isBoolean()) - return LooselyEqualBooleanAndOther(cx, lval, rval, result); - - // Step 9. - if (rval.isBoolean()) - return LooselyEqualBooleanAndOther(cx, rval, lval, result); - - // Step 10. - if ((lval.isString() || lval.isNumber() || lval.isSymbol()) && rval.isObject()) { - RootedValue rvalue(cx, rval); - if (!ToPrimitive(cx, &rvalue)) - return false; - return LooselyEqual(cx, lval, rvalue, result); - } - - // Step 11. - if (lval.isObject() && (rval.isString() || rval.isNumber() || rval.isSymbol())) { - RootedValue lvalue(cx, lval); - if (!ToPrimitive(cx, &lvalue)) - return false; - return LooselyEqual(cx, lvalue, rval, result); - } - - // Step 12. - *result = false; - return true; -} - -bool -js::StrictlyEqual(JSContext* cx, HandleValue lval, HandleValue rval, bool* equal) -{ - if (SameType(lval, rval)) - return EqualGivenSameType(cx, lval, rval, equal); - - if (lval.isNumber() && rval.isNumber()) { - *equal = (lval.toNumber() == rval.toNumber()); - return true; - } - - *equal = false; - return true; -} - -static inline bool -IsNegativeZero(const Value& v) -{ - return v.isDouble() && mozilla::IsNegativeZero(v.toDouble()); -} - -static inline bool -IsNaN(const Value& v) -{ - return v.isDouble() && mozilla::IsNaN(v.toDouble()); -} - -bool -js::SameValue(JSContext* cx, HandleValue v1, HandleValue v2, bool* same) -{ - if (IsNegativeZero(v1)) { - *same = IsNegativeZero(v2); - return true; - } - if (IsNegativeZero(v2)) { - *same = false; - return true; - } - if (IsNaN(v1) && IsNaN(v2)) { - *same = true; - return true; - } - return StrictlyEqual(cx, v1, v2, same); -} - JSType js::TypeOfObject(JSObject* obj) { diff --git a/js/src/vm/Interpreter.h b/js/src/vm/Interpreter.h index df9368e71c..1927e8cc7f 100644 --- a/js/src/vm/Interpreter.h +++ b/js/src/vm/Interpreter.h @@ -305,16 +305,6 @@ class InvokeState final : public RunState extern bool RunScript(JSContext* cx, RunState& state); -extern bool -StrictlyEqual(JSContext* cx, HandleValue lval, HandleValue rval, bool* equal); - -extern bool -LooselyEqual(JSContext* cx, HandleValue lval, HandleValue rval, bool* equal); - -/* === except that NaN is the same as NaN and -0 is not the same as +0. */ -extern bool -SameValue(JSContext* cx, HandleValue v1, HandleValue v2, bool* same); - extern JSType TypeOfObject(JSObject* obj); diff --git a/js/src/vm/NativeObject.cpp b/js/src/vm/NativeObject.cpp index 91b7cacb4d..a6bb9826ee 100644 --- a/js/src/vm/NativeObject.cpp +++ b/js/src/vm/NativeObject.cpp @@ -11,6 +11,7 @@ #include "gc/Marking.h" #include "js/Value.h" #include "vm/Debugger.h" +#include "vm/EqualityOperations.h" // js::SameValue #include "vm/TypedArrayCommon.h" #include "jsobjinlines.h" diff --git a/layout/style/nsCSSParser.cpp b/layout/style/nsCSSParser.cpp index e7fa3f8d8b..494d8f6aa6 100644 --- a/layout/style/nsCSSParser.cpp +++ b/layout/style/nsCSSParser.cpp @@ -137,6 +137,22 @@ struct CSSParserInputState { bool mHavePushBack; }; +struct ReduceNumberCalcOps : public mozilla::css::BasicFloatCalcOps, + public mozilla::css::CSSValueInputCalcOps +{ + result_type ComputeLeafValue(const nsCSSValue& aValue) + { + // FIXME: Restore this assertion once ParseColor no longer uses this class. + //MOZ_ASSERT(aValue.GetUnit() == eCSSUnit_Number, "unexpected unit"); + return aValue.GetFloatValue(); + } + + float ComputeNumber(const nsCSSValue& aValue) + { + return mozilla::css::ComputeCalc(aValue, *this); + } +}; + static_assert(css::eAuthorSheetFeatures == 0 && css::eUserSheetFeatures == 1 && css::eAgentSheetFeatures == 2, @@ -659,6 +675,11 @@ protected: bool SkipAtRule(bool aInsideBlock); bool SkipDeclaration(bool aCheckForBraces); + // Returns true when the target token type is found, and false for the + // end of declaration, start of !important flag, end of declaration + // block, or EOF. + bool LookForTokenType(nsCSSTokenType aType); + void PushGroup(css::GroupRule* aRule); void PopGroup(); @@ -896,6 +917,7 @@ protected: }; bool IsFunctionTokenValidForImageLayerImage(const nsCSSToken& aToken) const; + bool IsCalcFunctionToken(const nsCSSToken& aToken) const; bool ParseImageLayersItem(ImageLayersShorthandParseState& aState, const nsCSSPropertyID aTable[]); @@ -1178,14 +1200,6 @@ protected: CSSParseResult ParseColor(nsCSSValue& aValue); -static bool -IsCSSTokenCalcFunction(const nsCSSToken& aToken) -{ - return aToken.mType == eCSSToken_Function && - (aToken.mIdent.LowerCaseEqualsLiteral("calc") || - aToken.mIdent.LowerCaseEqualsLiteral("-moz-calc")); -} - template bool ParseRGBColor(ComponentType& aR, ComponentType& aG, @@ -5404,6 +5418,32 @@ CSSParserImpl::SkipDeclaration(bool aCheckForBraces) return true; } +bool +CSSParserImpl::LookForTokenType(nsCSSTokenType aType) { + bool rv = false; + CSSParserInputState stateBeforeValue; + SaveInputState(stateBeforeValue); + + const char16_t stopChars[] = { ';', '!', '}', 0 }; + nsDependentString stopSymbolChars(stopChars); + while (GetToken(true)) { + if (mToken.mType == aType) { + rv = true; + break; + } + // Stop looking if we're at the end of the declaration, encountered an + // !important flag, or at the end of the declaration block. + if (mToken.mType == eCSSToken_Symbol && + stopSymbolChars.FindChar(mToken.mSymbol) != -1) { + rv = false; + break; + } + } + + RestoreSavedInputState(stateBeforeValue); + return rv; +} + void CSSParserImpl::SkipRuleSet(bool aInsideBraces) { @@ -6996,7 +7036,15 @@ CSSParserImpl::ParseColor(nsCSSValue& aValue) if (GetToken(true)) { UngetToken(); } - if (mToken.mType == eCSSToken_Number || mToken.mType == eCSSToken_Function) { // + + bool isNumber = mToken.mType == eCSSToken_Number; + + // Check first if we have percentage values inside the function. + if (mToken.mType == eCSSToken_Function) { + isNumber = !LookForTokenType(eCSSToken_Percentage); + } + + if (isNumber) { // uint8_t r, g, b, a; if (ParseRGBColor(r, g, b, a)) { @@ -7095,21 +7143,6 @@ CSSParserImpl::ParseColor(nsCSSValue& aValue) return CSSParseResult::NotFound; } -struct ReduceNumberCalcOps : public mozilla::css::BasicFloatCalcOps, - public mozilla::css::CSSValueInputCalcOps -{ - result_type ComputeLeafValue(const nsCSSValue& aValue) - { - MOZ_ASSERT(aValue.GetUnit() == eCSSUnit_Number, "unexpected unit"); - return aValue.GetFloatValue(); - } - - float ComputeNumber(const nsCSSValue& aValue) - { - return mozilla::css::ComputeCalc(aValue, *this); - } -}; - bool CSSParserImpl::ParseColorComponent(uint8_t& aComponent, Maybe aSeparator) { @@ -7119,18 +7152,16 @@ CSSParserImpl::ParseColorComponent(uint8_t& aComponent, Maybe aSeparator) } float value; - - if (mToken.mType == eCSSToken_Number) + if (mToken.mType == eCSSToken_Number) { value = mToken.mNumber; - else if (IsCSSTokenCalcFunction(mToken)) { + } else if (IsCalcFunctionToken(mToken)) { nsCSSValue aValue; if (!ParseCalc(aValue, VARIANT_LPN | VARIANT_CALC)) { return false; } ReduceNumberCalcOps ops; value = mozilla::css::ComputeCalc(aValue, ops); - } - else { + } else { REPORT_UNEXPECTED_TOKEN(PEExpectedNumber); UngetToken(); return false; @@ -7157,18 +7188,16 @@ CSSParserImpl::ParseColorComponent(float& aComponent, Maybe aSeparator) } float value; - - if (mToken.mType == eCSSToken_Percentage) + if (mToken.mType == eCSSToken_Percentage) { value = mToken.mNumber; - else if (IsCSSTokenCalcFunction(mToken)) { + } else if (IsCalcFunctionToken(mToken)) { nsCSSValue aValue; if (!ParseCalc(aValue, VARIANT_LPN | VARIANT_CALC)) { return false; } ReduceNumberCalcOps ops; value = mozilla::css::ComputeCalc(aValue, ops); - } - else { + } else { REPORT_UNEXPECTED_TOKEN(PEExpectedPercent); UngetToken(); return false; @@ -7199,17 +7228,6 @@ CSSParserImpl::ParseHue(float& aAngle) aAngle = mToken.mNumber; return true; } - - if (IsCSSTokenCalcFunction(mToken)) { - nsCSSValue aValue; - if (!ParseCalc(aValue, VARIANT_LPN | VARIANT_CALC)) { - return false; - } - ReduceNumberCalcOps ops; - aAngle = mozilla::css::ComputeCalc(aValue, ops); - return true; - } - UngetToken(); // @@ -8227,7 +8245,7 @@ CSSParserImpl::ParseVariant(nsCSSValue& aValue, } } if ((aVariantMask & VARIANT_CALC) && - IsCSSTokenCalcFunction(*tk)) { + IsCalcFunctionToken(*tk)) { // calc() currently allows only lengths and percents and number inside it. // And note that in current implementation, number cannot be mixed with // length and percent. @@ -12476,6 +12494,14 @@ CSSParserImpl::IsFunctionTokenValidForImageLayerImage( funcName.LowerCaseEqualsLiteral("-webkit-repeating-radial-gradient"))); } +bool +CSSParserImpl::IsCalcFunctionToken(const nsCSSToken& aToken) const +{ + return aToken.mType == eCSSToken_Function && + (aToken.mIdent.LowerCaseEqualsLiteral("calc") || + aToken.mIdent.LowerCaseEqualsLiteral("-moz-calc")); +} + // Parse one item of the background shorthand property. bool CSSParserImpl::ParseImageLayersItem( @@ -13988,7 +14014,7 @@ CSSParserImpl::ParseCalcTerm(nsCSSValue& aValue, uint32_t& aVariantMask) // Either an additive expression in parentheses... if (mToken.IsSymbol('(') || // Treat nested calc() as plain parenthesis. - IsCSSTokenCalcFunction(mToken)) { + IsCalcFunctionToken(mToken)) { if (!ParseCalcAdditiveExpression(aValue, aVariantMask) || !ExpectSymbol(')', true)) { SkipUntil(')'); diff --git a/mfbt/FloatingPoint.h b/mfbt/FloatingPoint.h index 6a0e454ae7..7d73d7e848 100644 --- a/mfbt/FloatingPoint.h +++ b/mfbt/FloatingPoint.h @@ -396,6 +396,20 @@ NumbersAreIdentical(T aValue1, T aValue2) return BitwiseCast(aValue1) == BitwiseCast(aValue2); } +/** + * Return true if |aValue| and |aValue2| are equal (ignoring sign if both are + * zero) or both NaN. + */ +template +static inline bool +EqualOrBothNaN(T aValue1, T aValue2) +{ + if (IsNaN(aValue1)) { + return IsNaN(aValue2); + } + return aValue1 == aValue2; +} + namespace detail { template diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 31f0411f72..9dc0b7ff54 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -2506,15 +2506,6 @@ pref("layout.css.scroll-snap.prediction-sensitivity", "0.750"); // Is support for basic shapes in clip-path enabled? pref("layout.css.clip-path-shapes.enabled", true); -// Is support for DOMPoint enabled? -pref("layout.css.DOMPoint.enabled", true); - -// Is support for DOMQuad enabled? -pref("layout.css.DOMQuad.enabled", true); - -// Is support for DOMMatrix enabled? -pref("layout.css.DOMMatrix.enabled", true); - // Is support for GeometryUtils.getBoxQuads enabled? pref("layout.css.getBoxQuads.enabled", true);