Issue #2241 - Part 6: Implement DOMMatrix.fromMatrix.

Also fixes .multiply() to use DOMMatrixInit.

Backported from Mozilla bug 1560462.
This commit is contained in:
Job Bautista 2023-05-12 15:42:46 +08:00 committed by roytam1
commit 10bdcb7e5f
7 changed files with 226 additions and 24 deletions

View file

@ -17,6 +17,8 @@
#include <math.h>
#include "js/Equality.h" // JS::SameValueZero
namespace mozilla {
namespace dom {
@ -37,6 +39,130 @@ DOMMatrixReadOnly::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
return DOMMatrixReadOnlyBinding::Wrap(aCx, this, aGivenProto);
}
// https://drafts.fxtf.org/geometry/#matrix-validate-and-fixup-2d
static bool
ValidateAndFixupMatrix2DInit(DOMMatrix2DInit& aMatrixInit, ErrorResult& aRv)
{
#define ValidateAliases(field, alias, fieldName, aliasName) \
if ((field).WasPassed() && (alias).WasPassed() && \
!JS::SameValueZero((field).Value(), (alias).Value())) { \
aRv.ThrowTypeError<MSG_MATRIX_INIT_CONFLICTING_VALUE>((fieldName), \
(aliasName)); \
return false; \
}
#define SetFromAliasOrDefault(field, alias, defaultValue) \
if (!(field).WasPassed()) { \
if ((alias).WasPassed()) { \
(field).Construct((alias).Value()); \
} else { \
(field).Construct(defaultValue); \
} \
}
#define ValidateAndSet(field, alias, fieldName, aliasName, defaultValue) \
ValidateAliases((field), (alias), NS_LITERAL_STRING(fieldName), \
NS_LITERAL_STRING(aliasName)); \
SetFromAliasOrDefault((field), (alias), (defaultValue));
ValidateAndSet(aMatrixInit.mM11, aMatrixInit.mA, "m11", "a", 1);
ValidateAndSet(aMatrixInit.mM12, aMatrixInit.mB, "m12", "b", 0);
ValidateAndSet(aMatrixInit.mM21, aMatrixInit.mC, "m21", "c", 0);
ValidateAndSet(aMatrixInit.mM22, aMatrixInit.mD, "m22", "d", 1);
ValidateAndSet(aMatrixInit.mM41, aMatrixInit.mE, "m41", "e", 0);
ValidateAndSet(aMatrixInit.mM42, aMatrixInit.mF, "m42", "f", 0);
return true;
#undef ValidateAliases
#undef SetFromAliasOrDefault
#undef ValidateAndSet
}
// https://drafts.fxtf.org/geometry/#matrix-validate-and-fixup
static bool
ValidateAndFixupMatrixInit(DOMMatrixInit& aMatrixInit, ErrorResult& aRv)
{
#define Check3DField(field, fieldName, defaultValue) \
if ((field) != (defaultValue)) { \
if (!aMatrixInit.mIs2D.WasPassed()) { \
aMatrixInit.mIs2D.Construct(false); \
return true; \
} \
if (aMatrixInit.mIs2D.Value()) { \
aRv.ThrowTypeError<MSG_MATRIX_INIT_EXCEEDS_2D>( \
NS_LITERAL_STRING(fieldName)); \
return false; \
} \
}
if (!ValidateAndFixupMatrix2DInit(aMatrixInit, aRv)) {
return false;
}
Check3DField(aMatrixInit.mM13, "m13", 0);
Check3DField(aMatrixInit.mM14, "m14", 0);
Check3DField(aMatrixInit.mM23, "m23", 0);
Check3DField(aMatrixInit.mM24, "m24", 0);
Check3DField(aMatrixInit.mM31, "m31", 0);
Check3DField(aMatrixInit.mM32, "m32", 0);
Check3DField(aMatrixInit.mM34, "m34", 0);
Check3DField(aMatrixInit.mM43, "m43", 0);
Check3DField(aMatrixInit.mM33, "m33", 1);
Check3DField(aMatrixInit.mM44, "m44", 1);
if (!aMatrixInit.mIs2D.WasPassed()) {
aMatrixInit.mIs2D.Construct(true);
}
return true;
#undef Check3DField
}
void
DOMMatrixReadOnly::SetDataFromMatrixInit(DOMMatrixInit& aMatrixInit)
{
const bool is2D = aMatrixInit.mIs2D.Value();
MOZ_ASSERT(is2D == Is2D());
if (is2D) {
mMatrix2D->_11 = aMatrixInit.mM11.Value();
mMatrix2D->_12 = aMatrixInit.mM12.Value();
mMatrix2D->_21 = aMatrixInit.mM21.Value();
mMatrix2D->_22 = aMatrixInit.mM22.Value();
mMatrix2D->_31 = aMatrixInit.mM41.Value();
mMatrix2D->_32 = aMatrixInit.mM42.Value();
} else {
mMatrix3D->_11 = aMatrixInit.mM11.Value();
mMatrix3D->_12 = aMatrixInit.mM12.Value();
mMatrix3D->_13 = aMatrixInit.mM13;
mMatrix3D->_14 = aMatrixInit.mM14;
mMatrix3D->_21 = aMatrixInit.mM21.Value();
mMatrix3D->_22 = aMatrixInit.mM22.Value();
mMatrix3D->_23 = aMatrixInit.mM23;
mMatrix3D->_24 = aMatrixInit.mM24;
mMatrix3D->_31 = aMatrixInit.mM31;
mMatrix3D->_32 = aMatrixInit.mM32;
mMatrix3D->_33 = aMatrixInit.mM33;
mMatrix3D->_34 = aMatrixInit.mM34;
mMatrix3D->_41 = aMatrixInit.mM41.Value();
mMatrix3D->_42 = aMatrixInit.mM42.Value();
mMatrix3D->_43 = aMatrixInit.mM43;
mMatrix3D->_44 = aMatrixInit.mM44;
}
}
already_AddRefed<DOMMatrixReadOnly>
DOMMatrixReadOnly::FromMatrix(const GlobalObject& aGlobal, const DOMMatrixInit& aMatrixInit, ErrorResult& aRv)
{
DOMMatrixInit matrixInit(aMatrixInit);
if (!ValidateAndFixupMatrixInit(matrixInit, aRv)) {
return nullptr;
};
RefPtr<DOMMatrixReadOnly> rval =
new DOMMatrixReadOnly(aGlobal.GetAsSupports(), matrixInit.mIs2D.Value());
rval->SetDataFromMatrixInit(matrixInit);
return rval.forget();
}
already_AddRefed<DOMMatrixReadOnly>
DOMMatrixReadOnly::Constructor(
const GlobalObject& aGlobal,
@ -182,10 +308,10 @@ DOMMatrixReadOnly::SkewY(double aSy) const
}
already_AddRefed<DOMMatrix>
DOMMatrixReadOnly::Multiply(const DOMMatrix& other) const
DOMMatrixReadOnly::Multiply(const DOMMatrixInit& other, ErrorResult& aRv) const
{
RefPtr<DOMMatrix> retval = new DOMMatrix(mParent, *this);
retval->MultiplySelf(other);
retval->MultiplySelf(other, aRv);
return retval.forget();
}
@ -426,6 +552,27 @@ DOMMatrixReadOnly::ReadStructuredCloneElements(JSStructuredCloneReader* aReader,
#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::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv)
{
@ -546,42 +693,44 @@ DOMMatrixReadOnly::Ensure3DMatrix()
}
DOMMatrix*
DOMMatrix::MultiplySelf(const DOMMatrix& aOther)
DOMMatrix::MultiplySelf(const DOMMatrixInit& aOtherInit, ErrorResult& aRv)
{
if (aOther.Identity()) {
RefPtr<DOMMatrix> other = FromMatrix(mParent, aOtherInit, aRv);
if (other->Identity()) {
return this;
}
if (aOther.Is2D()) {
if (other->Is2D()) {
if (mMatrix3D) {
*mMatrix3D = gfx::Matrix4x4::From2D(*aOther.mMatrix2D) * *mMatrix3D;
*mMatrix3D = gfx::Matrix4x4::From2D(*other->mMatrix2D) * *mMatrix3D;
} else {
*mMatrix2D = *aOther.mMatrix2D * *mMatrix2D;
*mMatrix2D = *other->mMatrix2D * *mMatrix2D;
}
} else {
Ensure3DMatrix();
*mMatrix3D = *aOther.mMatrix3D * *mMatrix3D;
*mMatrix3D = *other->mMatrix3D * *mMatrix3D;
}
return this;
}
DOMMatrix*
DOMMatrix::PreMultiplySelf(const DOMMatrix& aOther)
DOMMatrix::PreMultiplySelf(const DOMMatrixInit& aOtherInit, ErrorResult& aRv)
{
if (aOther.Identity()) {
RefPtr<DOMMatrix> other = FromMatrix(mParent, aOtherInit, aRv);
if (other->Identity()) {
return this;
}
if (aOther.Is2D()) {
if (other->Is2D()) {
if (mMatrix3D) {
*mMatrix3D = *mMatrix3D * gfx::Matrix4x4::From2D(*aOther.mMatrix2D);
*mMatrix3D = *mMatrix3D * gfx::Matrix4x4::From2D(*other->mMatrix2D);
} else {
*mMatrix2D = *mMatrix2D * *aOther.mMatrix2D;
*mMatrix2D = *mMatrix2D * *other->mMatrix2D;
}
} else {
Ensure3DMatrix();
*mMatrix3D = *mMatrix3D * *aOther.mMatrix3D;
*mMatrix3D = *mMatrix3D * *other->mMatrix3D;
}
return this;