Merge remote-tracking branch 'origin/tracking' into custom

This commit is contained in:
roytam1 2023-05-15 09:19:37 +08:00
commit a7a525c65e
49 changed files with 1519 additions and 539 deletions

View file

@ -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);

View file

@ -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.

View file

@ -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;

View file

@ -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;

View file

@ -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;
}

View file

@ -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;

View file

@ -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;
});
}
/**

View file

@ -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
}
});
}

View file

@ -17,9 +17,15 @@
#include <math.h>
#include "js/Equality.h" // JS::SameValueZero
namespace mozilla {
namespace dom {
template <typename T>
static void
SetDataInMatrix(DOMMatrixReadOnly* aMatrix, const T* aData, int aLength, ErrorResult& aRv);
static const double radPerDegree = 2.0 * M_PI / 360.0;
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DOMMatrixReadOnly, mParent)
@ -27,6 +33,210 @@ NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DOMMatrixReadOnly, mParent)
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(DOMMatrixReadOnly, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(DOMMatrixReadOnly, Release)
JSObject*
DOMMatrixReadOnly::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
return DOMMatrixReadOnlyBinding::Wrap(aCx, this, aGivenProto);
}
// https://drafts.fxtf.org/geometry/#matrix-validate-and-fixup-2d
static bool
ValidateAndFixupMatrix2DInit(DOMMatrix2DInit& aMatrixInit, ErrorResult& aRv)
{
#define ValidateAliases(field, alias, fieldName, aliasName) \
if ((field).WasPassed() && (alias).WasPassed() && \
!JS::SameValueZero((field).Value(), (alias).Value())) { \
aRv.ThrowTypeError<MSG_MATRIX_INIT_CONFLICTING_VALUE>((fieldName), \
(aliasName)); \
return false; \
}
#define SetFromAliasOrDefault(field, alias, defaultValue) \
if (!(field).WasPassed()) { \
if ((alias).WasPassed()) { \
(field).Construct((alias).Value()); \
} else { \
(field).Construct(defaultValue); \
} \
}
#define ValidateAndSet(field, alias, fieldName, aliasName, defaultValue) \
ValidateAliases((field), (alias), NS_LITERAL_STRING(fieldName), \
NS_LITERAL_STRING(aliasName)); \
SetFromAliasOrDefault((field), (alias), (defaultValue));
ValidateAndSet(aMatrixInit.mM11, aMatrixInit.mA, "m11", "a", 1);
ValidateAndSet(aMatrixInit.mM12, aMatrixInit.mB, "m12", "b", 0);
ValidateAndSet(aMatrixInit.mM21, aMatrixInit.mC, "m21", "c", 0);
ValidateAndSet(aMatrixInit.mM22, aMatrixInit.mD, "m22", "d", 1);
ValidateAndSet(aMatrixInit.mM41, aMatrixInit.mE, "m41", "e", 0);
ValidateAndSet(aMatrixInit.mM42, aMatrixInit.mF, "m42", "f", 0);
return true;
#undef ValidateAliases
#undef SetFromAliasOrDefault
#undef ValidateAndSet
}
// https://drafts.fxtf.org/geometry/#matrix-validate-and-fixup
static bool
ValidateAndFixupMatrixInit(DOMMatrixInit& aMatrixInit, ErrorResult& aRv)
{
#define Check3DField(field, fieldName, defaultValue) \
if ((field) != (defaultValue)) { \
if (!aMatrixInit.mIs2D.WasPassed()) { \
aMatrixInit.mIs2D.Construct(false); \
return true; \
} \
if (aMatrixInit.mIs2D.Value()) { \
aRv.ThrowTypeError<MSG_MATRIX_INIT_EXCEEDS_2D>( \
NS_LITERAL_STRING(fieldName)); \
return false; \
} \
}
if (!ValidateAndFixupMatrix2DInit(aMatrixInit, aRv)) {
return false;
}
Check3DField(aMatrixInit.mM13, "m13", 0);
Check3DField(aMatrixInit.mM14, "m14", 0);
Check3DField(aMatrixInit.mM23, "m23", 0);
Check3DField(aMatrixInit.mM24, "m24", 0);
Check3DField(aMatrixInit.mM31, "m31", 0);
Check3DField(aMatrixInit.mM32, "m32", 0);
Check3DField(aMatrixInit.mM34, "m34", 0);
Check3DField(aMatrixInit.mM43, "m43", 0);
Check3DField(aMatrixInit.mM33, "m33", 1);
Check3DField(aMatrixInit.mM44, "m44", 1);
if (!aMatrixInit.mIs2D.WasPassed()) {
aMatrixInit.mIs2D.Construct(true);
}
return true;
#undef Check3DField
}
void
DOMMatrixReadOnly::SetDataFromMatrixInit(DOMMatrixInit& aMatrixInit)
{
const bool is2D = aMatrixInit.mIs2D.Value();
MOZ_ASSERT(is2D == Is2D());
if (is2D) {
mMatrix2D->_11 = aMatrixInit.mM11.Value();
mMatrix2D->_12 = aMatrixInit.mM12.Value();
mMatrix2D->_21 = aMatrixInit.mM21.Value();
mMatrix2D->_22 = aMatrixInit.mM22.Value();
mMatrix2D->_31 = aMatrixInit.mM41.Value();
mMatrix2D->_32 = aMatrixInit.mM42.Value();
} else {
mMatrix3D->_11 = aMatrixInit.mM11.Value();
mMatrix3D->_12 = aMatrixInit.mM12.Value();
mMatrix3D->_13 = aMatrixInit.mM13;
mMatrix3D->_14 = aMatrixInit.mM14;
mMatrix3D->_21 = aMatrixInit.mM21.Value();
mMatrix3D->_22 = aMatrixInit.mM22.Value();
mMatrix3D->_23 = aMatrixInit.mM23;
mMatrix3D->_24 = aMatrixInit.mM24;
mMatrix3D->_31 = aMatrixInit.mM31;
mMatrix3D->_32 = aMatrixInit.mM32;
mMatrix3D->_33 = aMatrixInit.mM33;
mMatrix3D->_34 = aMatrixInit.mM34;
mMatrix3D->_41 = aMatrixInit.mM41.Value();
mMatrix3D->_42 = aMatrixInit.mM42.Value();
mMatrix3D->_43 = aMatrixInit.mM43;
mMatrix3D->_44 = aMatrixInit.mM44;
}
}
already_AddRefed<DOMMatrixReadOnly>
DOMMatrixReadOnly::FromMatrix(const GlobalObject& aGlobal, const DOMMatrixInit& aMatrixInit, ErrorResult& aRv)
{
DOMMatrixInit matrixInit(aMatrixInit);
if (!ValidateAndFixupMatrixInit(matrixInit, aRv)) {
return nullptr;
};
RefPtr<DOMMatrixReadOnly> rval =
new DOMMatrixReadOnly(aGlobal.GetAsSupports(), matrixInit.mIs2D.Value());
rval->SetDataFromMatrixInit(matrixInit);
return rval.forget();
}
already_AddRefed<DOMMatrixReadOnly>
DOMMatrixReadOnly::FromFloat32Array(const GlobalObject& aGlobal, const Float32Array& aArray32, ErrorResult& aRv)
{
aArray32.ComputeLengthAndData();
const int length = aArray32.Length();
const bool is2D = length == 6;
RefPtr<DOMMatrixReadOnly> obj =
new DOMMatrixReadOnly(aGlobal.GetAsSupports(), is2D);
SetDataInMatrix(obj, aArray32.Data(), length, aRv);
return obj.forget();
}
already_AddRefed<DOMMatrixReadOnly>
DOMMatrixReadOnly::FromFloat64Array(const GlobalObject& aGlobal, const Float64Array& aArray64, ErrorResult& aRv)
{
aArray64.ComputeLengthAndData();
const int length = aArray64.Length();
const bool is2D = length == 6;
RefPtr<DOMMatrixReadOnly> obj =
new DOMMatrixReadOnly(aGlobal.GetAsSupports(), is2D);
SetDataInMatrix(obj, aArray64.Data(), length, aRv);
return obj.forget();
}
already_AddRefed<DOMMatrixReadOnly>
DOMMatrixReadOnly::Constructor(
const GlobalObject& aGlobal,
const Optional<StringOrUnrestrictedDoubleSequence>& aArg,
ErrorResult& aRv)
{
RefPtr<DOMMatrixReadOnly> rval = new DOMMatrixReadOnly(aGlobal.GetAsSupports());
if (!aArg.WasPassed()) {
return rval.forget();
}
const auto& arg = aArg.Value();
if (arg.IsString()) {
nsCOMPtr<nsPIDOMWindowInner> win = do_QueryInterface(aGlobal.GetAsSupports());
if (!win) {
aRv.ThrowTypeError<MSG_ILLEGAL_CONSTRUCTOR>();
return nullptr;
}
rval->SetMatrixValue(arg.GetAsString(), aRv);
} else {
const auto& sequence = arg.GetAsUnrestrictedDoubleSequence();
SetDataInMatrix(rval, sequence.Elements(), sequence.Length(), aRv);
}
return rval.forget();
}
already_AddRefed<DOMMatrixReadOnly>
DOMMatrixReadOnly::ReadStructuredClone(nsISupports* aParent, JSStructuredCloneReader* aReader)
{
uint8_t is2D;
if (!JS_ReadBytes(aReader, &is2D, 1)) {
return nullptr;
}
RefPtr<DOMMatrixReadOnly> rval = new DOMMatrixReadOnly(aParent, is2D);
if (!ReadStructuredCloneElements(aReader, rval)) {
return nullptr;
};
return rval.forget();
}
already_AddRefed<DOMMatrix>
DOMMatrixReadOnly::Translate(double aTx,
double aTy,
@ -127,10 +337,10 @@ DOMMatrixReadOnly::SkewY(double aSy) const
}
already_AddRefed<DOMMatrix>
DOMMatrixReadOnly::Multiply(const DOMMatrix& other) const
DOMMatrixReadOnly::Multiply(const DOMMatrixInit& other, ErrorResult& aRv) const
{
RefPtr<DOMMatrix> retval = new DOMMatrix(mParent, *this);
retval->MultiplySelf(other);
retval->MultiplySelf(other, aRv);
return retval.forget();
}
@ -307,6 +517,117 @@ DOMMatrixReadOnly::Stringify(nsAString& aResult)
aResult = matrixStr;
}
// https://drafts.fxtf.org/geometry/#structured-serialization
bool
DOMMatrixReadOnly::WriteStructuredClone(JSStructuredCloneWriter* aWriter) const
{
#define WriteFloatPair(f1, f2) \
JS_WriteUint32Pair(aWriter, BitwiseCast<uint32_t>(f1), \
BitwiseCast<uint32_t>(f2))
const uint8_t is2D = Is2D();
if (!JS_WriteBytes(aWriter, &is2D, 1)) {
return false;
}
if (is2D == 1) {
return WriteFloatPair(mMatrix2D->_11, mMatrix2D->_12) &&
WriteFloatPair(mMatrix2D->_21, mMatrix2D->_22) &&
WriteFloatPair(mMatrix2D->_31, mMatrix2D->_32);
}
return WriteFloatPair(mMatrix3D->_11, mMatrix3D->_12) &&
WriteFloatPair(mMatrix3D->_13, mMatrix3D->_14) &&
WriteFloatPair(mMatrix3D->_21, mMatrix3D->_22) &&
WriteFloatPair(mMatrix3D->_23, mMatrix3D->_24) &&
WriteFloatPair(mMatrix3D->_31, mMatrix3D->_32) &&
WriteFloatPair(mMatrix3D->_33, mMatrix3D->_34) &&
WriteFloatPair(mMatrix3D->_41, mMatrix3D->_42) &&
WriteFloatPair(mMatrix3D->_43, mMatrix3D->_44);
#undef WriteFloatPair
}
bool
DOMMatrixReadOnly::ReadStructuredCloneElements(JSStructuredCloneReader* aReader, DOMMatrixReadOnly* matrix)
{
uint32_t high;
uint32_t low;
#define ReadFloatPair(f1, f2) \
if (!JS_ReadUint32Pair(aReader, &high, &low)) { \
return false; \
} \
(*(f1) = BitwiseCast<float>(high)); \
(*(f2) = BitwiseCast<float>(low));
if (matrix->Is2D() == 1) {
ReadFloatPair(&(matrix->mMatrix2D->_11), &(matrix->mMatrix2D->_12));
ReadFloatPair(&(matrix->mMatrix2D->_21), &(matrix->mMatrix2D->_22));
ReadFloatPair(&(matrix->mMatrix2D->_31), &(matrix->mMatrix2D->_32));
} else {
ReadFloatPair(&(matrix->mMatrix3D->_11), &(matrix->mMatrix3D->_12));
ReadFloatPair(&(matrix->mMatrix3D->_13), &(matrix->mMatrix3D->_14));
ReadFloatPair(&(matrix->mMatrix3D->_21), &(matrix->mMatrix3D->_22));
ReadFloatPair(&(matrix->mMatrix3D->_23), &(matrix->mMatrix3D->_24));
ReadFloatPair(&(matrix->mMatrix3D->_31), &(matrix->mMatrix3D->_32));
ReadFloatPair(&(matrix->mMatrix3D->_33), &(matrix->mMatrix3D->_34));
ReadFloatPair(&(matrix->mMatrix3D->_41), &(matrix->mMatrix3D->_42));
ReadFloatPair(&(matrix->mMatrix3D->_43), &(matrix->mMatrix3D->_44));
}
return true;
#undef ReadFloatPair
}
already_AddRefed<DOMMatrix>
DOMMatrix::FromMatrix(nsISupports* aParent, const DOMMatrixInit& aMatrixInit, ErrorResult& aRv)
{
DOMMatrixInit matrixInit(aMatrixInit);
if (!ValidateAndFixupMatrixInit(matrixInit, aRv)) {
return nullptr;
};
RefPtr<DOMMatrix> matrix = new DOMMatrix(aParent, matrixInit.mIs2D.Value());
matrix->SetDataFromMatrixInit(matrixInit);
return matrix.forget();
}
already_AddRefed<DOMMatrix>
DOMMatrix::FromMatrix(const GlobalObject& aGlobal, const DOMMatrixInit& aMatrixInit, ErrorResult& aRv)
{
RefPtr<DOMMatrix> matrix =
FromMatrix(aGlobal.GetAsSupports(), aMatrixInit, aRv);
return matrix.forget();
}
already_AddRefed<DOMMatrix>
DOMMatrix::FromFloat32Array(const GlobalObject& aGlobal, const Float32Array& aArray32, ErrorResult& aRv)
{
aArray32.ComputeLengthAndData();
const int length = aArray32.Length();
const bool is2D = length == 6;
RefPtr<DOMMatrix> obj = new DOMMatrix(aGlobal.GetAsSupports(), is2D);
SetDataInMatrix(obj, aArray32.Data(), length, aRv);
return obj.forget();
}
already_AddRefed<DOMMatrix>
DOMMatrix::FromFloat64Array(const GlobalObject& aGlobal, const Float64Array& aArray64, ErrorResult& aRv)
{
aArray64.ComputeLengthAndData();
const int length = aArray64.Length();
const bool is2D = length == 6;
RefPtr<DOMMatrix> obj = new DOMMatrix(aGlobal.GetAsSupports(), is2D);
SetDataInMatrix(obj, aArray64.Data(), length, aRv);
return obj.forget();
}
already_AddRefed<DOMMatrix>
DOMMatrix::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv)
{
@ -317,6 +638,11 @@ DOMMatrix::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv)
already_AddRefed<DOMMatrix>
DOMMatrix::Constructor(const GlobalObject& aGlobal, const nsAString& aTransformList, ErrorResult& aRv)
{
nsCOMPtr<nsPIDOMWindowInner> win = do_QueryInterface(aGlobal.GetAsSupports());
if (!win) {
aRv.ThrowTypeError<MSG_ILLEGAL_CONSTRUCTOR>();
return nullptr;
}
RefPtr<DOMMatrix> obj = new DOMMatrix(aGlobal.GetAsSupports());
obj = obj->SetMatrixValue(aTransformList, aRv);
@ -330,7 +656,9 @@ DOMMatrix::Constructor(const GlobalObject& aGlobal, const DOMMatrixReadOnly& aOt
return obj.forget();
}
template <typename T> void SetDataInMatrix(DOMMatrix* aMatrix, const T* aData, int aLength, ErrorResult& aRv)
template <typename T>
static void
SetDataInMatrix(DOMMatrixReadOnly* aMatrix, const T* aData, int aLength, ErrorResult& aRv)
{
if (aLength == 16) {
aMatrix->SetM11(aData[0]);
@ -357,28 +685,22 @@ template <typename T> void SetDataInMatrix(DOMMatrix* aMatrix, const T* aData, i
aMatrix->SetE(aData[4]);
aMatrix->SetF(aData[5]);
} else {
aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
nsAutoString lengthStr;
lengthStr.AppendInt(aLength);
aRv.ThrowTypeError<MSG_MATRIX_INIT_LENGTH_WRONG>(lengthStr);
}
}
already_AddRefed<DOMMatrix>
DOMMatrix::Constructor(const GlobalObject& aGlobal, const Float32Array& aArray32, ErrorResult& aRv)
{
RefPtr<DOMMatrix> obj = new DOMMatrix(aGlobal.GetAsSupports());
aArray32.ComputeLengthAndData();
SetDataInMatrix(obj, aArray32.Data(), aArray32.Length(), aRv);
return obj.forget();
return FromFloat32Array(aGlobal, aArray32, aRv);
}
already_AddRefed<DOMMatrix>
DOMMatrix::Constructor(const GlobalObject& aGlobal, const Float64Array& aArray64, ErrorResult& aRv)
{
RefPtr<DOMMatrix> obj = new DOMMatrix(aGlobal.GetAsSupports());
aArray64.ComputeLengthAndData();
SetDataInMatrix(obj, aArray64.Data(), aArray64.Length(), aRv);
return obj.forget();
return FromFloat64Array(aGlobal, aArray64, aRv);
}
already_AddRefed<DOMMatrix>
@ -390,7 +712,26 @@ DOMMatrix::Constructor(const GlobalObject& aGlobal, const Sequence<double>& aNum
return obj.forget();
}
void DOMMatrix::Ensure3DMatrix()
already_AddRefed<DOMMatrix>
DOMMatrix::ReadStructuredClone(nsISupports* aParent, JSStructuredCloneReader* aReader)
{
uint8_t is2D;
if (!JS_ReadBytes(aReader, &is2D, 1)) {
return nullptr;
}
RefPtr<DOMMatrix> rval = new DOMMatrix(aParent, is2D);
if (!ReadStructuredCloneElements(aReader, rval)) {
return nullptr;
};
return rval.forget();
}
void
DOMMatrixReadOnly::Ensure3DMatrix()
{
if (!mMatrix3D) {
mMatrix3D = new gfx::Matrix4x4(gfx::Matrix4x4::From2D(*mMatrix2D));
@ -399,42 +740,44 @@ void DOMMatrix::Ensure3DMatrix()
}
DOMMatrix*
DOMMatrix::MultiplySelf(const DOMMatrix& aOther)
DOMMatrix::MultiplySelf(const DOMMatrixInit& aOtherInit, ErrorResult& aRv)
{
if (aOther.Identity()) {
RefPtr<DOMMatrix> other = FromMatrix(mParent, aOtherInit, aRv);
if (other->Identity()) {
return this;
}
if (aOther.Is2D()) {
if (other->Is2D()) {
if (mMatrix3D) {
*mMatrix3D = gfx::Matrix4x4::From2D(*aOther.mMatrix2D) * *mMatrix3D;
*mMatrix3D = gfx::Matrix4x4::From2D(*other->mMatrix2D) * *mMatrix3D;
} else {
*mMatrix2D = *aOther.mMatrix2D * *mMatrix2D;
*mMatrix2D = *other->mMatrix2D * *mMatrix2D;
}
} else {
Ensure3DMatrix();
*mMatrix3D = *aOther.mMatrix3D * *mMatrix3D;
*mMatrix3D = *other->mMatrix3D * *mMatrix3D;
}
return this;
}
DOMMatrix*
DOMMatrix::PreMultiplySelf(const DOMMatrix& aOther)
DOMMatrix::PreMultiplySelf(const DOMMatrixInit& aOtherInit, ErrorResult& aRv)
{
if (aOther.Identity()) {
RefPtr<DOMMatrix> other = FromMatrix(mParent, aOtherInit, aRv);
if (other->Identity()) {
return this;
}
if (aOther.Is2D()) {
if (other->Is2D()) {
if (mMatrix3D) {
*mMatrix3D = *mMatrix3D * gfx::Matrix4x4::From2D(*aOther.mMatrix2D);
*mMatrix3D = *mMatrix3D * gfx::Matrix4x4::From2D(*other->mMatrix2D);
} else {
*mMatrix2D = *mMatrix2D * *aOther.mMatrix2D;
*mMatrix2D = *mMatrix2D * *other->mMatrix2D;
}
} else {
Ensure3DMatrix();
*mMatrix3D = *mMatrix3D * *aOther.mMatrix3D;
*mMatrix3D = *mMatrix3D * *other->mMatrix3D;
}
return this;
@ -617,8 +960,8 @@ DOMMatrix::InvertSelf()
return this;
}
DOMMatrix*
DOMMatrix::SetMatrixValue(const nsAString& aTransformList, ErrorResult& aRv)
DOMMatrixReadOnly*
DOMMatrixReadOnly::SetMatrixValue(const nsAString& aTransformList, ErrorResult& aRv)
{
SVGTransformListParser parser(aTransformList);
if (!parser.Parse()) {
@ -644,6 +987,13 @@ DOMMatrix::SetMatrixValue(const nsAString& aTransformList, ErrorResult& aRv)
return this;
}
DOMMatrix*
DOMMatrix::SetMatrixValue(const nsAString& aTransformList, ErrorResult& aRv)
{
DOMMatrixReadOnly::SetMatrixValue(aTransformList, aRv);
return this;
}
JSObject*
DOMMatrix::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{

View file

@ -6,6 +6,7 @@
#ifndef MOZILLA_DOM_DOMMATRIX_H_
#define MOZILLA_DOM_DOMMATRIX_H_
#include "js/StructuredClone.h"
#include "nsWrapperCache.h"
#include "nsISupports.h"
#include "nsCycleCollectionParticipant.h"
@ -22,7 +23,9 @@ namespace dom {
class GlobalObject;
class DOMMatrix;
class DOMPoint;
class StringOrUnrestrictedDoubleSequence;
struct DOMPointInit;
struct DOMMatrixInit;
class DOMMatrixReadOnly : public nsWrapperCache
{
@ -42,9 +45,36 @@ public:
}
}
DOMMatrixReadOnly(nsISupports* aParent, const gfx::Matrix4x4& aMatrix)
: mParent(aParent)
{
mMatrix3D = new gfx::Matrix4x4(aMatrix);
}
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(DOMMatrixReadOnly)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(DOMMatrixReadOnly)
nsISupports* GetParentObject() const { return mParent; }
virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> aGivenProto) override;
static already_AddRefed<DOMMatrixReadOnly>
FromMatrix(const GlobalObject& aGlobal, const DOMMatrixInit& aMatrixInit, ErrorResult& aRv);
static already_AddRefed<DOMMatrixReadOnly>
FromFloat32Array(const GlobalObject& aGlobal, const Float32Array& aArray32, ErrorResult& aRv);
static already_AddRefed<DOMMatrixReadOnly>
FromFloat64Array(const GlobalObject& aGlobal, const Float64Array& aArray64, ErrorResult& aRv);
static already_AddRefed<DOMMatrixReadOnly>
Constructor(const GlobalObject& aGlobal, const Optional<StringOrUnrestrictedDoubleSequence>& aArg, ErrorResult& aRv);
static already_AddRefed<DOMMatrixReadOnly>
ReadStructuredClone(nsISupports* aParent, JSStructuredCloneReader* aReader);
static bool
ReadStructuredCloneElements(JSStructuredCloneReader* aReader, DOMMatrixReadOnly* matrix);
#define GetMatrixMember(entry2D, entry3D, default) \
{ \
if (mMatrix3D) { \
@ -88,88 +118,7 @@ public:
#undef GetMatrixMember
#undef Get3DMatrixMember
already_AddRefed<DOMMatrix> Translate(double aTx,
double aTy,
double aTz = 0) const;
already_AddRefed<DOMMatrix> Scale(double aScale,
double aOriginX = 0,
double aOriginY = 0) const;
already_AddRefed<DOMMatrix> Scale3d(double aScale,
double aOriginX = 0,
double aOriginY = 0,
double aOriginZ = 0) const;
already_AddRefed<DOMMatrix> ScaleNonUniform(double aScaleX,
double aScaleY = 1.0,
double aScaleZ = 1.0,
double aOriginX = 0,
double aOriginY = 0,
double aOriginZ = 0) const;
already_AddRefed<DOMMatrix> Rotate(double aAngle,
double aOriginX = 0,
double aOriginY = 0) const;
already_AddRefed<DOMMatrix> RotateFromVector(double aX,
double aY) const;
already_AddRefed<DOMMatrix> RotateAxisAngle(double aX,
double aY,
double aZ,
double aAngle) const;
already_AddRefed<DOMMatrix> SkewX(double aSx) const;
already_AddRefed<DOMMatrix> SkewY(double aSy) const;
already_AddRefed<DOMMatrix> Multiply(const DOMMatrix& aOther) const;
already_AddRefed<DOMMatrix> FlipX() const;
already_AddRefed<DOMMatrix> FlipY() const;
already_AddRefed<DOMMatrix> Inverse() const;
bool Is2D() const;
bool Identity() const;
already_AddRefed<DOMPoint> TransformPoint(const DOMPointInit& aPoint) const;
void ToFloat32Array(JSContext* aCx,
JS::MutableHandle<JSObject*> aResult,
ErrorResult& aRv) const;
void ToFloat64Array(JSContext* aCx,
JS::MutableHandle<JSObject*> aResult,
ErrorResult& aRv) const;
void Stringify(nsAString& aResult);
protected:
nsCOMPtr<nsISupports> mParent;
nsAutoPtr<gfx::Matrix> mMatrix2D;
nsAutoPtr<gfx::Matrix4x4> 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<DOMMatrix>
Constructor(const GlobalObject& aGlobal, ErrorResult& aRv);
static already_AddRefed<DOMMatrix>
Constructor(const GlobalObject& aGlobal, const nsAString& aTransformList, ErrorResult& aRv);
static already_AddRefed<DOMMatrix>
Constructor(const GlobalObject& aGlobal, const DOMMatrixReadOnly& aOther, ErrorResult& aRv);
static already_AddRefed<DOMMatrix>
Constructor(const GlobalObject& aGlobal, const Float32Array& aArray32, ErrorResult& aRv);
static already_AddRefed<DOMMatrix>
Constructor(const GlobalObject& aGlobal, const Float64Array& aArray64, ErrorResult& aRv);
static already_AddRefed<DOMMatrix>
Constructor(const GlobalObject& aGlobal, const Sequence<double>& aNumberSequence, ErrorResult& aRv);
nsISupports* GetParentObject() const { return mParent; }
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
// 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<DOMMatrix> Translate(double aTx,
double aTy,
double aTz = 0) const;
already_AddRefed<DOMMatrix> Scale(double aScale,
double aOriginX = 0,
double aOriginY = 0) const;
already_AddRefed<DOMMatrix> Scale3d(double aScale,
double aOriginX = 0,
double aOriginY = 0,
double aOriginZ = 0) const;
already_AddRefed<DOMMatrix> ScaleNonUniform(double aScaleX,
double aScaleY = 1.0,
double aScaleZ = 1.0,
double aOriginX = 0,
double aOriginY = 0,
double aOriginZ = 0) const;
already_AddRefed<DOMMatrix> Rotate(double aAngle,
double aOriginX = 0,
double aOriginY = 0) const;
already_AddRefed<DOMMatrix> RotateFromVector(double aX,
double aY) const;
already_AddRefed<DOMMatrix> RotateAxisAngle(double aX,
double aY,
double aZ,
double aAngle) const;
already_AddRefed<DOMMatrix> SkewX(double aSx) const;
already_AddRefed<DOMMatrix> SkewY(double aSy) const;
already_AddRefed<DOMMatrix> Multiply(const DOMMatrixInit& aOther,
ErrorResult& aRv) const;
already_AddRefed<DOMMatrix> FlipX() const;
already_AddRefed<DOMMatrix> FlipY() const;
already_AddRefed<DOMMatrix> Inverse() const;
bool Is2D() const;
bool Identity() const;
already_AddRefed<DOMPoint> TransformPoint(const DOMPointInit& aPoint) const;
void ToFloat32Array(JSContext* aCx,
JS::MutableHandle<JSObject*> aResult,
ErrorResult& aRv) const;
void ToFloat64Array(JSContext* aCx,
JS::MutableHandle<JSObject*> aResult,
ErrorResult& aRv) const;
void Stringify(nsAString& aResult);
bool WriteStructuredClone(JSStructuredCloneWriter* aWriter) const;
protected:
nsCOMPtr<nsISupports> mParent;
nsAutoPtr<gfx::Matrix> mMatrix2D;
nsAutoPtr<gfx::Matrix4x4> 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<DOMMatrix>
FromMatrix(nsISupports* aParent, const DOMMatrixInit& aMatrixInit, ErrorResult& aRv);
static already_AddRefed<DOMMatrix>
FromMatrix(const GlobalObject& aGlobal, const DOMMatrixInit& aMatrixInit, ErrorResult& aRv);
static already_AddRefed<DOMMatrix>
FromFloat32Array(const GlobalObject& aGlobal, const Float32Array& aArray32, ErrorResult& aRv);
static already_AddRefed<DOMMatrix>
FromFloat64Array(const GlobalObject& aGlobal, const Float64Array& aArray64, ErrorResult& aRv);
static already_AddRefed<DOMMatrix>
Constructor(const GlobalObject& aGlobal, ErrorResult& aRv);
static already_AddRefed<DOMMatrix>
Constructor(const GlobalObject& aGlobal, const nsAString& aTransformList, ErrorResult& aRv);
static already_AddRefed<DOMMatrix>
Constructor(const GlobalObject& aGlobal, const DOMMatrixReadOnly& aOther, ErrorResult& aRv);
static already_AddRefed<DOMMatrix>
Constructor(const GlobalObject& aGlobal, const Float32Array& aArray32, ErrorResult& aRv);
static already_AddRefed<DOMMatrix>
Constructor(const GlobalObject& aGlobal, const Float64Array& aArray64, ErrorResult& aRv);
static already_AddRefed<DOMMatrix>
Constructor(const GlobalObject& aGlobal, const Sequence<double>& aNumberSequence, ErrorResult& aRv);
static already_AddRefed<DOMMatrix>
ReadStructuredClone(nsISupports* aParent, JSStructuredCloneReader* aReader);
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> 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

View file

@ -16,9 +16,68 @@ NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DOMPointReadOnly, mParent)
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(DOMPointReadOnly, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(DOMPointReadOnly, Release)
already_AddRefed<DOMPointReadOnly>
DOMPointReadOnly::FromPoint(const GlobalObject& aGlobal, const DOMPointInit& aParams)
{
RefPtr<DOMPointReadOnly> obj =
new DOMPointReadOnly(aGlobal.GetAsSupports(), aParams.mX, aParams.mY,
aParams.mZ, aParams.mW);
return obj.forget();
}
already_AddRefed<DOMPointReadOnly>
DOMPointReadOnly::Constructor(const GlobalObject& aGlobal, double aX, double aY,
double aZ, double aW, ErrorResult& aRV)
{
RefPtr<DOMPointReadOnly> obj =
new DOMPointReadOnly(aGlobal.GetAsSupports(), aX, aY, aZ, aW);
return obj.forget();
}
JSObject*
DOMPointReadOnly::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
return DOMPointReadOnlyBinding::Wrap(aCx, this, aGivenProto);
}
// https://drafts.fxtf.org/geometry/#structured-serialization
bool
DOMPointReadOnly::WriteStructuredClone(JSStructuredCloneWriter* aWriter) const
{
#define WriteDouble(d) \
JS_WriteUint32Pair(aWriter, (BitwiseCast<uint64_t>(d) >> 32) & 0xffffffff, \
BitwiseCast<uint64_t>(d) & 0xffffffff)
return WriteDouble(mX) && WriteDouble(mY) && WriteDouble(mZ) &&
WriteDouble(mW);
#undef WriteDouble
}
bool
DOMPointReadOnly::ReadStructuredClone(JSStructuredCloneReader* aReader)
{
uint32_t high;
uint32_t low;
#define ReadDouble(d) \
if (!JS_ReadUint32Pair(aReader, &high, &low)) { \
return false; \
} \
(*(d) = BitwiseCast<double>(static_cast<uint64_t>(high) << 32 | low))
ReadDouble(&mX);
ReadDouble(&mY);
ReadDouble(&mZ);
ReadDouble(&mW);
return true;
#undef ReadDouble
}
already_AddRefed<DOMPoint>
DOMPoint::Constructor(const GlobalObject& aGlobal, const DOMPointInit& aParams,
ErrorResult& aRV)
DOMPoint::FromPoint(const GlobalObject& aGlobal, const DOMPointInit& aParams)
{
RefPtr<DOMPoint> obj =
new DOMPoint(aGlobal.GetAsSupports(), aParams.mX, aParams.mY,

View file

@ -6,6 +6,7 @@
#ifndef MOZILLA_DOMPOINT_H_
#define MOZILLA_DOMPOINT_H_
#include "js/StructuredClone.h"
#include "nsWrapperCache.h"
#include "nsISupports.h"
#include "nsCycleCollectionParticipant.h"
@ -23,8 +24,8 @@ struct DOMPointInit;
class DOMPointReadOnly : public nsWrapperCache
{
public:
DOMPointReadOnly(nsISupports* aParent, double aX, double aY,
double aZ, double aW)
explicit DOMPointReadOnly(nsISupports* aParent, double aX = 0.0,
double aY = 0.0, double aZ = 0.0, double aW = 1.0)
: mParent(aParent)
, mX(aX)
, mY(aY)
@ -33,6 +34,12 @@ public:
{
}
static already_AddRefed<DOMPointReadOnly>
FromPoint(const GlobalObject& aGlobal, const DOMPointInit& aParams);
static already_AddRefed<DOMPointReadOnly>
Constructor(const GlobalObject& aGlobal, double aX, double aY,
double aZ, double aW, ErrorResult& aRV);
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(DOMPointReadOnly)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(DOMPointReadOnly)
@ -41,6 +48,13 @@ public:
double Z() const { return mZ; }
double W() const { return mW; }
nsISupports* GetParentObject() const { return mParent; }
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
bool WriteStructuredClone(JSStructuredCloneWriter* aWriter) const;
bool ReadStructuredClone(JSStructuredCloneReader* aReader);
protected:
virtual ~DOMPointReadOnly() {}
@ -57,13 +71,11 @@ public:
{}
static already_AddRefed<DOMPoint>
Constructor(const GlobalObject& aGlobal, const DOMPointInit& aParams,
ErrorResult& aRV);
FromPoint(const GlobalObject& aGlobal, const DOMPointInit& aParams);
static already_AddRefed<DOMPoint>
Constructor(const GlobalObject& aGlobal, double aX, double aY,
double aZ, double aW, ErrorResult& aRV);
nsISupports* GetParentObject() const { return mParent; }
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
void SetX(double aX) { mX = aX; }

View file

@ -43,6 +43,32 @@ DOMQuad::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
return DOMQuadBinding::Wrap(aCx, this, aGivenProto);
}
already_AddRefed<DOMQuad>
DOMQuad::FromRect(const GlobalObject& aGlobal, const DOMRectInit& aInit)
{
nsISupports* parent = aGlobal.GetAsSupports();
RefPtr<DOMQuad> obj = new DOMQuad(parent);
obj->mPoints[0] = new DOMPoint(parent, aInit.mX, aInit.mY, 0, 1);
obj->mPoints[1] =
new DOMPoint(parent, aInit.mX + aInit.mWidth, aInit.mY, 0, 1);
obj->mPoints[2] = new DOMPoint(parent, aInit.mX + aInit.mWidth,
aInit.mY + aInit.mHeight, 0, 1);
obj->mPoints[3] =
new DOMPoint(parent, aInit.mX, aInit.mY + aInit.mHeight, 0, 1);
return obj.forget();
}
already_AddRefed<DOMQuad>
DOMQuad::FromQuad(const GlobalObject& aGlobal, const DOMQuadInit& aInit)
{
RefPtr<DOMQuad> obj = new DOMQuad(aGlobal.GetAsSupports());
obj->mPoints[0] = DOMPoint::FromPoint(aGlobal, aInit.mP1);
obj->mPoints[1] = DOMPoint::FromPoint(aGlobal, aInit.mP2);
obj->mPoints[2] = DOMPoint::FromPoint(aGlobal, aInit.mP3);
obj->mPoints[3] = DOMPoint::FromPoint(aGlobal, aInit.mP4);
return obj.forget();
}
already_AddRefed<DOMQuad>
DOMQuad::Constructor(const GlobalObject& aGlobal,
const DOMPointInit& aP1,
@ -52,10 +78,10 @@ DOMQuad::Constructor(const GlobalObject& aGlobal,
ErrorResult& aRV)
{
RefPtr<DOMQuad> obj = new DOMQuad(aGlobal.GetAsSupports());
obj->mPoints[0] = DOMPoint::Constructor(aGlobal, aP1, aRV);
obj->mPoints[1] = DOMPoint::Constructor(aGlobal, aP2, aRV);
obj->mPoints[2] = DOMPoint::Constructor(aGlobal, aP3, aRV);
obj->mPoints[3] = DOMPoint::Constructor(aGlobal, aP4, aRV);
obj->mPoints[0] = DOMPoint::FromPoint(aGlobal, aP1);
obj->mPoints[1] = DOMPoint::FromPoint(aGlobal, aP2);
obj->mPoints[2] = DOMPoint::FromPoint(aGlobal, aP3);
obj->mPoints[3] = DOMPoint::FromPoint(aGlobal, aP4);
return obj.forget();
}
@ -73,87 +99,86 @@ DOMQuad::Constructor(const GlobalObject& aGlobal, const DOMRectReadOnly& aRect,
return obj.forget();
}
class DOMQuad::QuadBounds final : public DOMRectReadOnly
void
DOMQuad::GetHorizontalMinMax(double* aX1, double* aX2) const
{
public:
explicit QuadBounds(DOMQuad* aQuad)
: DOMRectReadOnly(aQuad->GetParentObject())
, mQuad(aQuad)
{}
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(QuadBounds, DOMRectReadOnly)
NS_DECL_ISUPPORTS_INHERITED
virtual double X() const override
{
double x1, x2;
GetHorizontalMinMax(&x1, &x2);
return x1;
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<DOMQuad> 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<DOMQuad*>(this));
mBounds = GetBounds();
}
return mBounds;
}
already_AddRefed<DOMRectReadOnly>
DOMQuad::GetBounds() const
{
double x1, x2;
double y1, y2;
GetHorizontalMinMax(&x1, &x2);
GetVerticalMinMax(&y1, &y2);
RefPtr<DOMRectReadOnly> rval = new DOMRectReadOnly(GetParentObject(),
x1, y1, x2 - x1, y2 - y1);
return rval.forget();
}
void
DOMQuad::ToJSON(DOMQuadJSON& aInit)
{
aInit.mP1.Construct(RefPtr<DOMPoint>(P1()).forget());
aInit.mP2.Construct(RefPtr<DOMPoint>(P2()).forget());
aInit.mP3.Construct(RefPtr<DOMPoint>(P3()).forget());
aInit.mP4.Construct(RefPtr<DOMPoint>(P4()).forget());
}
// 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;
}

View file

@ -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<JSObject*> aGivenProto) override;
static already_AddRefed<DOMQuad>
FromRect(const GlobalObject& aGlobal, const DOMRectInit& aInit);
static already_AddRefed<DOMQuad>
FromQuad(const GlobalObject& aGlobal, const DOMQuadInit& aInit);
static already_AddRefed<DOMQuad>
Constructor(const GlobalObject& aGlobal,
const DOMPointInit& aP1,
@ -47,20 +57,28 @@ public:
Constructor(const GlobalObject& aGlobal, const DOMRectReadOnly& aRect,
ErrorResult& aRV);
DOMRectReadOnly* Bounds() const;
DOMRectReadOnly* Bounds();
already_AddRefed<DOMRectReadOnly> GetBounds() const;
DOMPoint* P1() const { return mPoints[0]; }
DOMPoint* P2() const { return mPoints[1]; }
DOMPoint* P3() const { return mPoints[2]; }
DOMPoint* P4() const { return mPoints[3]; }
DOMPoint* Point(uint32_t aIndex) { return mPoints[aIndex]; }
DOMPoint* Point(uint32_t aIndex) const { return mPoints[aIndex]; }
void ToJSON(DOMQuadJSON& aInit);
bool WriteStructuredClone(JSStructuredCloneWriter* aWriter) const;
bool ReadStructuredClone(JSStructuredCloneReader* aReader);
protected:
class QuadBounds;
void GetHorizontalMinMax(double* aX1, double* aX2) const;
void GetVerticalMinMax(double* aY1, double* aY2) const;
nsCOMPtr<nsISupports> mParent;
RefPtr<DOMPoint> mPoints[4];
mutable RefPtr<QuadBounds> mBounds; // allocated lazily
RefPtr<DOMRectReadOnly> mBounds;
};
} // namespace dom

View file

@ -27,6 +27,59 @@ DOMRectReadOnly::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
return DOMRectReadOnlyBinding::Wrap(aCx, this, aGivenProto);
}
already_AddRefed<DOMRectReadOnly>
DOMRectReadOnly::FromRect(const GlobalObject& aGlobal, const DOMRectInit& aInit)
{
RefPtr<DOMRectReadOnly> obj = new DOMRectReadOnly(
aGlobal.GetAsSupports(), aInit.mX, aInit.mY, aInit.mWidth, aInit.mHeight);
return obj.forget();
}
already_AddRefed<DOMRectReadOnly>
DOMRectReadOnly::Constructor(const GlobalObject& aGlobal, double aX, double aY,
double aWidth, double aHeight, ErrorResult& aRv)
{
RefPtr<DOMRectReadOnly> obj =
new DOMRectReadOnly(aGlobal.GetAsSupports(), aX, aY, aWidth, aHeight);
return obj.forget();
}
// https://drafts.fxtf.org/geometry/#structured-serialization
bool
DOMRectReadOnly::WriteStructuredClone(JSStructuredCloneWriter* aWriter) const
{
#define WriteDouble(d) \
JS_WriteUint32Pair(aWriter, (BitwiseCast<uint64_t>(d) >> 32) & 0xffffffff, \
BitwiseCast<uint64_t>(d) & 0xffffffff)
return WriteDouble(mX) && WriteDouble(mY) && WriteDouble(mWidth) &&
WriteDouble(mHeight);
#undef WriteDouble
}
bool
DOMRectReadOnly::ReadStructuredClone(JSStructuredCloneReader* aReader)
{
uint32_t high;
uint32_t low;
#define ReadDouble(d) \
if (!JS_ReadUint32Pair(aReader, &high, &low)) { \
return false; \
} \
(*(d) = BitwiseCast<double>(static_cast<uint64_t>(high) << 32 | low))
ReadDouble(&mX);
ReadDouble(&mY);
ReadDouble(&mWidth);
ReadDouble(&mHeight);
return true;
#undef ReadDouble
}
// -----------------------------------------------------------------------------
NS_IMPL_ISUPPORTS_INHERITED(DOMRect, DOMRectReadOnly, nsIDOMClientRect)
@ -54,16 +107,16 @@ DOMRect::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
}
already_AddRefed<DOMRect>
DOMRect::Constructor(const GlobalObject& aGlobal, ErrorResult& aRV)
DOMRect::FromRect(const GlobalObject& aGlobal, const DOMRectInit& aInit)
{
RefPtr<DOMRect> obj =
new DOMRect(aGlobal.GetAsSupports(), 0.0, 0.0, 0.0, 0.0);
RefPtr<DOMRect> obj = new DOMRect(aGlobal.GetAsSupports(), aInit.mX, aInit.mY,
aInit.mWidth, aInit.mHeight);
return obj.forget();
}
already_AddRefed<DOMRect>
DOMRect::Constructor(const GlobalObject& aGlobal, double aX, double aY,
double aWidth, double aHeight, ErrorResult& aRV)
double aWidth, double aHeight, ErrorResult& aRv)
{
RefPtr<DOMRect> obj =
new DOMRect(aGlobal.GetAsSupports(), aX, aY, aWidth, aHeight);

View file

@ -6,6 +6,7 @@
#ifndef MOZILLA_DOMRECT_H_
#define MOZILLA_DOMRECT_H_
#include "js/StructuredClone.h"
#include "nsIDOMClientRect.h"
#include "nsIDOMClientRectList.h"
#include "nsTArray.h"
@ -22,6 +23,8 @@ struct nsRect;
namespace mozilla {
namespace dom {
struct DOMRectInit;
class DOMRectReadOnly : public nsISupports
, public nsWrapperCache
{
@ -32,8 +35,13 @@ public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(DOMRectReadOnly)
explicit DOMRectReadOnly(nsISupports* aParent)
explicit DOMRectReadOnly(nsISupports* aParent, double aX = 0, double aY = 0,
double aWidth = 0, double aHeight = 0)
: mParent(aParent)
, mX(aX)
, mY(aY)
, mWidth(aWidth)
, mHeight(aHeight)
{
}
@ -44,10 +52,29 @@ public:
}
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
virtual double X() const = 0;
virtual double Y() const = 0;
virtual double Width() const = 0;
virtual double Height() const = 0;
static already_AddRefed<DOMRectReadOnly>
FromRect(const GlobalObject& aGlobal, const DOMRectInit& aInit);
static already_AddRefed<DOMRectReadOnly>
Constructor(const GlobalObject& aGlobal, double aX, double aY,
double aWidth, double aHeight, ErrorResult& aRv);
double X() const
{
return mX;
}
double Y() const
{
return mY;
}
double Width() const
{
return mWidth;
}
double Height() const
{
return mHeight;
}
double Left() const
{
@ -70,8 +97,13 @@ public:
return std::max(y, y + h);
}
bool WriteStructuredClone(JSStructuredCloneWriter* aWriter) const;
bool ReadStructuredClone(JSStructuredCloneReader* aReader);
protected:
nsCOMPtr<nsISupports> mParent;
double mX, mY, mWidth, mHeight;
};
class DOMRect final : public DOMRectReadOnly
@ -80,22 +112,19 @@ class DOMRect final : public DOMRectReadOnly
public:
explicit DOMRect(nsISupports* aParent, double aX = 0, double aY = 0,
double aWidth = 0, double aHeight = 0)
: DOMRectReadOnly(aParent)
, mX(aX)
, mY(aY)
, mWidth(aWidth)
, mHeight(aHeight)
: DOMRectReadOnly(aParent, aX, aY, aWidth, aHeight)
{
}
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIDOMCLIENTRECT
static already_AddRefed<DOMRect>
Constructor(const GlobalObject& aGlobal, ErrorResult& aRV);
FromRect(const GlobalObject& aGlobal, const DOMRectInit& aInit);
static already_AddRefed<DOMRect>
Constructor(const GlobalObject& aGlobal, double aX, double aY,
double aWidth, double aHeight, ErrorResult& aRV);
double aWidth, double aHeight, ErrorResult& aRv);
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
@ -104,23 +133,6 @@ public:
}
void SetLayoutRect(const nsRect& aLayoutRect);
virtual double X() const override
{
return mX;
}
virtual double Y() const override
{
return mY;
}
virtual double Width() const override
{
return mWidth;
}
virtual double Height() const override
{
return mHeight;
}
void SetX(double aX)
{
mX = aX;
@ -138,11 +150,8 @@ public:
mHeight = aHeight;
}
protected:
double mX, mY, mWidth, mHeight;
private:
~DOMRect() {};
~DOMRect() {}
};
class DOMRectList final : public nsIDOMClientRectList,

View file

@ -11,6 +11,14 @@
#include "mozilla/dom/CryptoKey.h"
#include "mozilla/dom/Directory.h"
#include "mozilla/dom/DirectoryBinding.h"
#include "mozilla/dom/DOMMatrix.h"
#include "mozilla/dom/DOMMatrixBinding.h"
#include "mozilla/dom/DOMPoint.h"
#include "mozilla/dom/DOMPointBinding.h"
#include "mozilla/dom/DOMQuad.h"
#include "mozilla/dom/DOMQuadBinding.h"
#include "mozilla/dom/DOMRect.h"
#include "mozilla/dom/DOMRectBinding.h"
#include "mozilla/dom/File.h"
#include "mozilla/dom/FileList.h"
#include "mozilla/dom/FileListBinding.h"
@ -355,7 +363,11 @@ StructuredCloneHolder::ReadFullySerializableObjects(JSContext* aCx,
return ReadStructuredCloneImageData(aCx, aReader);
}
if (aTag == SCTAG_DOM_WEBCRYPTO_KEY || aTag == SCTAG_DOM_URLSEARCHPARAMS) {
if (aTag == SCTAG_DOM_WEBCRYPTO_KEY || aTag == SCTAG_DOM_URLSEARCHPARAMS ||
aTag == SCTAG_DOM_DOMPOINT || aTag == SCTAG_DOM_DOMPOINT_READONLY ||
aTag == SCTAG_DOM_DOMRECT || aTag == SCTAG_DOM_DOMRECT_READONLY ||
aTag == SCTAG_DOM_DOMQUAD || aTag == SCTAG_DOM_DOMMATRIX ||
aTag == SCTAG_DOM_DOMMATRIX_READONLY) {
nsIGlobalObject *global = xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx));
if (!global) {
return nullptr;
@ -378,6 +390,57 @@ StructuredCloneHolder::ReadFullySerializableObjects(JSContext* aCx,
} else {
result = usp->WrapObject(aCx, nullptr);
}
} else if (aTag == SCTAG_DOM_DOMPOINT) {
RefPtr<DOMPoint> domPoint = new DOMPoint(global);
if (!domPoint->ReadStructuredClone(aReader)) {
result = nullptr;
} else {
result = domPoint->WrapObject(aCx, nullptr);
}
} else if (aTag == SCTAG_DOM_DOMPOINT_READONLY) {
RefPtr<DOMPointReadOnly> domPoint = new DOMPointReadOnly(global);
if (!domPoint->ReadStructuredClone(aReader)) {
result = nullptr;
} else {
result = domPoint->WrapObject(aCx, nullptr);
}
} else if (aTag == SCTAG_DOM_DOMRECT) {
RefPtr<DOMRect> domRect = new DOMRect(global);
if (!domRect->ReadStructuredClone(aReader)) {
result = nullptr;
} else {
result = domRect->WrapObject(aCx, nullptr);
}
} else if (aTag == SCTAG_DOM_DOMRECT_READONLY) {
RefPtr<DOMRectReadOnly> domRect = new DOMRectReadOnly(global);
if (!domRect->ReadStructuredClone(aReader)) {
result = nullptr;
} else {
result = domRect->WrapObject(aCx, nullptr);
}
} else if (aTag == SCTAG_DOM_DOMQUAD) {
RefPtr<DOMQuad> domQuad = new DOMQuad(global);
if (!domQuad->ReadStructuredClone(aReader)) {
result = nullptr;
} else {
result = domQuad->WrapObject(aCx, nullptr);
}
} else if (aTag == SCTAG_DOM_DOMMATRIX) {
RefPtr<DOMMatrix> domMatrix =
DOMMatrix::ReadStructuredClone(global, aReader);
if (!domMatrix) {
result = nullptr;
} else {
result = domMatrix->WrapObject(aCx, nullptr);
}
} else if (aTag == SCTAG_DOM_DOMMATRIX_READONLY) {
RefPtr<DOMMatrixReadOnly> domMatrix =
DOMMatrixReadOnly::ReadStructuredClone(global, aReader);
if (!domMatrix) {
result = nullptr;
} else {
result = domMatrix->WrapObject(aCx, nullptr);
}
}
}
return result;
@ -483,6 +546,75 @@ StructuredCloneHolder::WriteFullySerializableObjects(JSContext* aCx,
}
#endif
// Handle DOMPoint cloning
// Should be done before DOMPointeReadOnly check
// because every DOMPoint is also a DOMPointReadOnly
{
DOMPoint* domPoint = nullptr;
if (NS_SUCCEEDED(UNWRAP_OBJECT(DOMPoint, &obj, domPoint))) {
return JS_WriteUint32Pair(aWriter, SCTAG_DOM_DOMPOINT, 0) &&
domPoint->WriteStructuredClone(aWriter);
}
}
// Handle DOMPointReadOnly cloning
{
DOMPointReadOnly* domPoint = nullptr;
if (NS_SUCCEEDED(UNWRAP_OBJECT(DOMPointReadOnly, &obj, domPoint))) {
return JS_WriteUint32Pair(aWriter, SCTAG_DOM_DOMPOINT_READONLY, 0) &&
domPoint->WriteStructuredClone(aWriter);
}
}
// Handle DOMRect cloning
// Should be done before DOMRecteReadOnly check
// because every DOMRect is also a DOMRectReadOnly
{
DOMRect* domRect = nullptr;
if (NS_SUCCEEDED(UNWRAP_OBJECT(DOMRect, &obj, domRect))) {
return JS_WriteUint32Pair(aWriter, SCTAG_DOM_DOMRECT, 0) &&
domRect->WriteStructuredClone(aWriter);
}
}
// Handle DOMRectReadOnly cloning
{
DOMRectReadOnly* domRect = nullptr;
if (NS_SUCCEEDED(UNWRAP_OBJECT(DOMRectReadOnly, &obj, domRect))) {
return JS_WriteUint32Pair(aWriter, SCTAG_DOM_DOMRECT_READONLY, 0) &&
domRect->WriteStructuredClone(aWriter);
}
}
// Handle DOMQuad cloning
{
DOMQuad* domQuad = nullptr;
if (NS_SUCCEEDED(UNWRAP_OBJECT(DOMQuad, &obj, domQuad))) {
return JS_WriteUint32Pair(aWriter, SCTAG_DOM_DOMQUAD, 0) &&
domQuad->WriteStructuredClone(aWriter);
}
}
// Handle DOMMatrix cloning
// Should be done before DOMMatrixeReadOnly check
// because every DOMMatrix is also a DOMMatrixReadOnly
{
DOMMatrix* domMatrix = nullptr;
if (NS_SUCCEEDED(UNWRAP_OBJECT(DOMMatrix, &obj, domMatrix))) {
return JS_WriteUint32Pair(aWriter, SCTAG_DOM_DOMMATRIX, 0) &&
domMatrix->WriteStructuredClone(aWriter);
}
}
// Handle DOMMatrixReadOnly cloning
{
DOMMatrixReadOnly* domMatrix = nullptr;
if (NS_SUCCEEDED(UNWRAP_OBJECT(DOMMatrixReadOnly, &obj, domMatrix))) {
return JS_WriteUint32Pair(aWriter, SCTAG_DOM_DOMMATRIX_READONLY, 0) &&
domMatrix->WriteStructuredClone(aWriter);
}
}
if (NS_IsMainThread() && xpc::IsReflector(obj)) {
nsCOMPtr<nsISupports> base = xpc::UnwrapReflectorToISupports(obj);
nsCOMPtr<nsIPrincipal> principal = do_QueryInterface(base);

View file

@ -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,

View file

@ -20,8 +20,7 @@ static const double sRadPerDegree = 2.0 * M_PI / 360.0;
bool
WebKitCSSMatrix::FeatureEnabled(JSContext* aCx, JSObject* aObj)
{
return Preferences::GetBool("layout.css.DOMMatrix.enabled", false) &&
Preferences::GetBool("layout.css.prefixes.webkit", false);
return Preferences::GetBool("layout.css.prefixes.webkit", false);
}
already_AddRefed<WebKitCSSMatrix>
@ -115,10 +114,10 @@ WebKitCSSMatrix::SetMatrixValue(const nsAString& aTransformList,
}
already_AddRefed<WebKitCSSMatrix>
WebKitCSSMatrix::Multiply(const WebKitCSSMatrix& other) const
WebKitCSSMatrix::Multiply(const DOMMatrixInit& aOtherInit, ErrorResult& aRv) const
{
RefPtr<WebKitCSSMatrix> retval = new WebKitCSSMatrix(mParent, *this);
retval->MultiplySelf(other);
retval->MultiplySelf(aOtherInit, aRv);
return retval.forget();
}

View file

@ -40,7 +40,8 @@ public:
WebKitCSSMatrix* SetMatrixValue(const nsAString& aTransformList,
ErrorResult& aRv);
already_AddRefed<WebKitCSSMatrix> Multiply(const WebKitCSSMatrix& aOther) const;
already_AddRefed<WebKitCSSMatrix> Multiply(const DOMMatrixInit& aOtherInit,
ErrorResult& aRv) const;
already_AddRefed<WebKitCSSMatrix> Inverse(ErrorResult& aRv) const;
already_AddRefed<WebKitCSSMatrix> Translate(double aTx,
double aTy,

View file

@ -47,3 +47,4 @@ DEPRECATED_OPERATION(PrefixedFullscreenAPI)
DEPRECATED_OPERATION(LenientSetter)
DEPRECATED_OPERATION(FileLastModifiedDate)
DEPRECATED_OPERATION(ImageBitmapRenderingContext_TransferImageBitmap)
DEPRECATED_OPERATION(DOMQuadBoundsAttr)

View file

@ -253,12 +253,10 @@ DOMInterfaces = {
'DOMMatrixReadOnly': {
'headerFile': 'mozilla/dom/DOMMatrix.h',
'concrete': False,
},
'DOMPointReadOnly': {
'headerFile': 'mozilla/dom/DOMPoint.h',
'concrete': False,
},
'DOMRectList': {

View file

@ -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.")

View file

@ -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()

View file

@ -4,14 +4,19 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* The origin of this IDL file is
* http://dev.w3.org/fxtf/geometry/
* https://drafts.fxtf.org/geometry/
*
* Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
* liability, trademark and document use rules apply.
*/
[Pref="layout.css.DOMMatrix.enabled"]
[Constructor(optional (DOMString or sequence<unrestricted double>) init),
Exposed=(Window,Worker)]
interface DOMMatrixReadOnly {
[NewObject, Throws] static DOMMatrixReadOnly fromMatrix(optional DOMMatrixInit other);
[NewObject, Throws] static DOMMatrixReadOnly fromFloat32Array(Float32Array array32);
[NewObject, Throws] static DOMMatrixReadOnly fromFloat64Array(Float64Array array64);
// These attributes are simple aliases for certain elements of the 4x4 matrix
readonly attribute unrestricted double a;
readonly attribute unrestricted double b;
@ -65,7 +70,7 @@ interface DOMMatrixReadOnly {
unrestricted double angle);
DOMMatrix skewX(unrestricted double sx);
DOMMatrix skewY(unrestricted double sy);
DOMMatrix multiply(DOMMatrix other);
[NewObject, Throws] DOMMatrix multiply(optional DOMMatrixInit other);
DOMMatrix flipX();
DOMMatrix flipY();
DOMMatrix inverse();
@ -76,17 +81,21 @@ interface DOMMatrixReadOnly {
DOMPoint transformPoint(optional DOMPointInit point);
[Throws] Float32Array toFloat32Array();
[Throws] Float64Array toFloat64Array();
stringifier;
[Exposed=Window] stringifier;
};
[Pref="layout.css.DOMMatrix.enabled",
Constructor,
[Constructor,
Constructor(DOMString transformList),
Constructor(DOMMatrixReadOnly other),
Constructor(Float32Array array32),
Constructor(Float64Array array64),
Constructor(sequence<unrestricted double> numberSequence)]
Constructor(sequence<unrestricted double> numberSequence),
Exposed=(Window,Worker)]
interface DOMMatrix : DOMMatrixReadOnly {
[NewObject, Throws] static DOMMatrix fromMatrix(optional DOMMatrixInit other);
[NewObject, Throws] static DOMMatrix fromFloat32Array(Float32Array array32);
[NewObject, Throws] static DOMMatrix fromFloat64Array(Float64Array array64);
// These attributes are simple aliases for certain elements of the 4x4 matrix
inherit attribute unrestricted double a;
inherit attribute unrestricted double b;
@ -113,8 +122,8 @@ interface DOMMatrix : DOMMatrixReadOnly {
inherit attribute unrestricted double m44;
// Mutable transform methods
DOMMatrix multiplySelf(DOMMatrix other);
DOMMatrix preMultiplySelf(DOMMatrix other);
[Throws] DOMMatrix multiplySelf(optional DOMMatrixInit other);
[Throws] DOMMatrix preMultiplySelf(optional DOMMatrixInit other);
DOMMatrix translateSelf(unrestricted double tx,
unrestricted double ty,
optional unrestricted double tz = 0);
@ -143,6 +152,34 @@ interface DOMMatrix : DOMMatrixReadOnly {
DOMMatrix skewXSelf(unrestricted double sx);
DOMMatrix skewYSelf(unrestricted double sy);
DOMMatrix invertSelf();
[Throws] DOMMatrix setMatrixValue(DOMString transformList);
[Exposed=Window, Throws] DOMMatrix setMatrixValue(DOMString transformList);
};
dictionary DOMMatrix2DInit {
unrestricted double a;
unrestricted double b;
unrestricted double c;
unrestricted double d;
unrestricted double e;
unrestricted double f;
unrestricted double m11;
unrestricted double m12;
unrestricted double m21;
unrestricted double m22;
unrestricted double m41;
unrestricted double m42;
};
dictionary DOMMatrixInit : DOMMatrix2DInit {
unrestricted double m13 = 0;
unrestricted double m14 = 0;
unrestricted double m23 = 0;
unrestricted double m24 = 0;
unrestricted double m31 = 0;
unrestricted double m32 = 0;
unrestricted double m33 = 1;
unrestricted double m34 = 0;
unrestricted double m43 = 0;
unrestricted double m44 = 1;
boolean is2D;
};

View file

@ -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;
};
};

View file

@ -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;
};
[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;
};

View file

@ -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;

View file

@ -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,

68
js/public/Equality.h Normal file
View file

@ -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<JS::Value> v1, JS::Handle<JS::Value> 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<JS::Value> v1, JS::Handle<JS::Value> 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<JS::Value> v1, JS::Handle<JS::Value> 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 */

View file

@ -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"

View file

@ -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"

View file

@ -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"

View file

@ -5,6 +5,8 @@
#include <limits>
#include <math.h>
#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;
}
};

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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)
{

View file

@ -959,15 +959,6 @@ InformalValueTypeName(const JS::Value& v);
} /* namespace JS */
extern JS_PUBLIC_API(bool)
JS_StrictlyEqual(JSContext* cx, JS::Handle<JS::Value> v1, JS::Handle<JS::Value> v2, bool* equal);
extern JS_PUBLIC_API(bool)
JS_LooselyEqual(JSContext* cx, JS::Handle<JS::Value> v1, JS::Handle<JS::Value> v2, bool* equal);
extern JS_PUBLIC_API(bool)
JS_SameValue(JSContext* cx, JS::Handle<JS::Value> v1, JS::Handle<JS::Value> v2, bool* same);
/** True iff fun is the global eval function. */
extern JS_PUBLIC_API(bool)
JS_IsBuiltinEvalFunction(JSFunction* fun);

View file

@ -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',

View file

@ -7,6 +7,8 @@
#include "jsapi.h"
#include "vm/EqualityOperations.h" // js::SameValue
#include "jsobjinlines.h"
#include "vm/NativeObject-inl.h"

View file

@ -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;

View file

@ -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<Value> value1, Handle<Value> 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<Value> value1, Handle<Value> 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<Value> value1, Handle<Value> value2, bool* same)
{
js::AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
js::assertSameCompartment(cx, value1, value2);
MOZ_ASSERT(same);
return js::SameValue(cx, value1, value2, same);
}

View file

@ -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

View file

@ -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)
{

View file

@ -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);

View file

@ -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"

View file

@ -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<typename ComponentType>
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) { // <number>
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) { // <number>
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<char> aSeparator)
{
@ -7119,18 +7152,16 @@ CSSParserImpl::ParseColorComponent(uint8_t& aComponent, Maybe<char> 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<char> 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();
// <angle>
@ -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(')');

View file

@ -396,6 +396,20 @@ NumbersAreIdentical(T aValue1, T aValue2)
return BitwiseCast<Bits>(aValue1) == BitwiseCast<Bits>(aValue2);
}
/**
* Return true if |aValue| and |aValue2| are equal (ignoring sign if both are
* zero) or both NaN.
*/
template <typename T>
static inline bool
EqualOrBothNaN(T aValue1, T aValue2)
{
if (IsNaN(aValue1)) {
return IsNaN(aValue2);
}
return aValue1 == aValue2;
}
namespace detail {
template<typename T>

View file

@ -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);