mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1018497 - Implementation of DOMMatrix. r=roc,bz
This commit is contained in:
parent
8a23d2f4a9
commit
5d9f208b1b
650
content/base/src/DOMMatrix.cpp
Normal file
650
content/base/src/DOMMatrix.cpp
Normal file
@ -0,0 +1,650 @@
|
||||
/* -*- Mode: C++; tab-width: 2; 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 "mozilla/dom/BindingUtils.h"
|
||||
#include "mozilla/dom/DOMMatrixBinding.h"
|
||||
#include "mozilla/dom/DOMPointBinding.h"
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
#include "mozilla/dom/ToJSValue.h"
|
||||
|
||||
#include "mozilla/dom/DOMPoint.h"
|
||||
#include "mozilla/dom/DOMMatrix.h"
|
||||
|
||||
#include "SVGTransformListParser.h"
|
||||
#include "SVGTransform.h"
|
||||
|
||||
#include "nsAutoPtr.h"
|
||||
#include <math.h>
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
static const double radPerDegree = 2.0 * M_PI / 360.0;
|
||||
|
||||
already_AddRefed<DOMMatrix>
|
||||
DOMMatrixReadOnly::Translate(double aTx,
|
||||
double aTy,
|
||||
double aTz) const
|
||||
{
|
||||
nsRefPtr<DOMMatrix> retval = new DOMMatrix(mParent, *this);
|
||||
retval->TranslateSelf(aTx, aTy, aTz);
|
||||
|
||||
return retval.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<DOMMatrix>
|
||||
DOMMatrixReadOnly::Scale(double aScale,
|
||||
double aOriginX,
|
||||
double aOriginY) const
|
||||
{
|
||||
nsRefPtr<DOMMatrix> retval = new DOMMatrix(mParent, *this);
|
||||
retval->ScaleSelf(aScale, aOriginX, aOriginY);
|
||||
|
||||
return retval.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<DOMMatrix>
|
||||
DOMMatrixReadOnly::Scale3d(double aScale,
|
||||
double aOriginX,
|
||||
double aOriginY,
|
||||
double aOriginZ) const
|
||||
{
|
||||
nsRefPtr<DOMMatrix> retval = new DOMMatrix(mParent, *this);
|
||||
retval->Scale3dSelf(aScale, aOriginX, aOriginY, aOriginZ);
|
||||
|
||||
return retval.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<DOMMatrix>
|
||||
DOMMatrixReadOnly::ScaleNonUniform(double aScaleX,
|
||||
double aScaleY,
|
||||
double aScaleZ,
|
||||
double aOriginX,
|
||||
double aOriginY,
|
||||
double aOriginZ) const
|
||||
{
|
||||
nsRefPtr<DOMMatrix> retval = new DOMMatrix(mParent, *this);
|
||||
retval->ScaleNonUniformSelf(aScaleX, aScaleY, aScaleZ, aOriginX, aOriginY, aOriginZ);
|
||||
|
||||
return retval.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<DOMMatrix>
|
||||
DOMMatrixReadOnly::Rotate(double aAngle,
|
||||
double aOriginX ,
|
||||
double aOriginY) const
|
||||
{
|
||||
nsRefPtr<DOMMatrix> retval = new DOMMatrix(mParent, *this);
|
||||
retval->RotateSelf(aAngle, aOriginX, aOriginY);
|
||||
|
||||
return retval.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<DOMMatrix>
|
||||
DOMMatrixReadOnly::RotateFromVector(double x,
|
||||
double y) const
|
||||
{
|
||||
nsRefPtr<DOMMatrix> retval = new DOMMatrix(mParent, *this);
|
||||
retval->RotateFromVectorSelf(x, y);
|
||||
|
||||
return retval.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<DOMMatrix>
|
||||
DOMMatrixReadOnly::RotateAxisAngle(double aX,
|
||||
double aY,
|
||||
double aZ,
|
||||
double aAngle) const
|
||||
{
|
||||
nsRefPtr<DOMMatrix> retval = new DOMMatrix(mParent, *this);
|
||||
retval->RotateAxisAngleSelf(aX, aY, aZ, aAngle);
|
||||
|
||||
return retval.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<DOMMatrix>
|
||||
DOMMatrixReadOnly::SkewX(double aSx) const
|
||||
{
|
||||
nsRefPtr<DOMMatrix> retval = new DOMMatrix(mParent, *this);
|
||||
retval->SkewXSelf(aSx);
|
||||
|
||||
return retval.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<DOMMatrix>
|
||||
DOMMatrixReadOnly::SkewY(double aSy) const
|
||||
{
|
||||
nsRefPtr<DOMMatrix> retval = new DOMMatrix(mParent, *this);
|
||||
retval->SkewYSelf(aSy);
|
||||
|
||||
return retval.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<DOMMatrix>
|
||||
DOMMatrixReadOnly::Multiply(const DOMMatrix& other) const
|
||||
{
|
||||
nsRefPtr<DOMMatrix> retval = new DOMMatrix(mParent, *this);
|
||||
retval->MultiplySelf(other);
|
||||
|
||||
return retval.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<DOMMatrix>
|
||||
DOMMatrixReadOnly::FlipX() const
|
||||
{
|
||||
nsRefPtr<DOMMatrix> retval = new DOMMatrix(mParent, *this);
|
||||
if (mMatrix3D) {
|
||||
gfx::Matrix4x4 m;
|
||||
m._11 = -1;
|
||||
retval->mMatrix3D = new gfx::Matrix4x4(m * *mMatrix3D);
|
||||
} else {
|
||||
gfx::Matrix m;
|
||||
m._11 = -1;
|
||||
retval->mMatrix2D = new gfx::Matrix(mMatrix2D ? m * *mMatrix2D : m);
|
||||
}
|
||||
|
||||
return retval.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<DOMMatrix>
|
||||
DOMMatrixReadOnly::FlipY() const
|
||||
{
|
||||
nsRefPtr<DOMMatrix> retval = new DOMMatrix(mParent, *this);
|
||||
if (mMatrix3D) {
|
||||
gfx::Matrix4x4 m;
|
||||
m._22 = -1;
|
||||
retval->mMatrix3D = new gfx::Matrix4x4(m * *mMatrix3D);
|
||||
} else {
|
||||
gfx::Matrix m;
|
||||
m._22 = -1;
|
||||
retval->mMatrix2D = new gfx::Matrix(mMatrix2D ? m * *mMatrix2D : m);
|
||||
}
|
||||
|
||||
return retval.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<DOMMatrix>
|
||||
DOMMatrixReadOnly::Inverse() const
|
||||
{
|
||||
nsRefPtr<DOMMatrix> retval = new DOMMatrix(mParent, *this);
|
||||
retval->InvertSelf();
|
||||
|
||||
return retval.forget();
|
||||
}
|
||||
|
||||
bool
|
||||
DOMMatrixReadOnly::Is2D() const
|
||||
{
|
||||
return !mMatrix3D;
|
||||
}
|
||||
|
||||
bool
|
||||
DOMMatrixReadOnly::Identity() const
|
||||
{
|
||||
if (mMatrix3D) {
|
||||
return mMatrix3D->IsIdentity();
|
||||
}
|
||||
|
||||
return mMatrix2D->IsIdentity();
|
||||
}
|
||||
|
||||
already_AddRefed<DOMPoint>
|
||||
DOMMatrixReadOnly::TransformPoint(const DOMPointInit& point) const
|
||||
{
|
||||
nsRefPtr<DOMPoint> retval = new DOMPoint(mParent);
|
||||
|
||||
if (mMatrix3D) {
|
||||
gfx::Point4D transformedPoint;
|
||||
transformedPoint.x = point.mX;
|
||||
transformedPoint.y = point.mY;
|
||||
transformedPoint.z = point.mZ;
|
||||
transformedPoint.w = point.mW;
|
||||
|
||||
transformedPoint = *mMatrix3D * transformedPoint;
|
||||
|
||||
retval->SetX(transformedPoint.x);
|
||||
retval->SetY(transformedPoint.y);
|
||||
retval->SetZ(transformedPoint.z);
|
||||
retval->SetW(transformedPoint.w);
|
||||
} else if (point.mZ != 0 || point.mW != 1.0) {
|
||||
gfx::Matrix4x4 tempMatrix(gfx::Matrix4x4::From2D(*mMatrix2D));
|
||||
|
||||
gfx::Point4D transformedPoint;
|
||||
transformedPoint.x = point.mX;
|
||||
transformedPoint.y = point.mY;
|
||||
transformedPoint.z = point.mZ;
|
||||
transformedPoint.w = point.mW;
|
||||
|
||||
transformedPoint = tempMatrix * transformedPoint;
|
||||
|
||||
retval->SetX(transformedPoint.x);
|
||||
retval->SetY(transformedPoint.y);
|
||||
retval->SetZ(transformedPoint.z);
|
||||
retval->SetW(transformedPoint.w);
|
||||
} else {
|
||||
gfx::Point transformedPoint;
|
||||
transformedPoint.x = point.mX;
|
||||
transformedPoint.y = point.mY;
|
||||
|
||||
transformedPoint = *mMatrix2D * transformedPoint;
|
||||
|
||||
retval->SetX(transformedPoint.x);
|
||||
retval->SetY(transformedPoint.y);
|
||||
retval->SetZ(point.mZ);
|
||||
retval->SetW(point.mW);
|
||||
}
|
||||
return retval.forget();
|
||||
}
|
||||
|
||||
template <typename T> void GetDataFromMatrix(const DOMMatrixReadOnly* aMatrix, T* aData)
|
||||
{
|
||||
aData[0] = static_cast<T>(aMatrix->M11());
|
||||
aData[1] = static_cast<T>(aMatrix->M12());
|
||||
aData[2] = static_cast<T>(aMatrix->M13());
|
||||
aData[3] = static_cast<T>(aMatrix->M14());
|
||||
aData[4] = static_cast<T>(aMatrix->M21());
|
||||
aData[5] = static_cast<T>(aMatrix->M22());
|
||||
aData[6] = static_cast<T>(aMatrix->M23());
|
||||
aData[7] = static_cast<T>(aMatrix->M24());
|
||||
aData[8] = static_cast<T>(aMatrix->M31());
|
||||
aData[9] = static_cast<T>(aMatrix->M32());
|
||||
aData[10] = static_cast<T>(aMatrix->M33());
|
||||
aData[11] = static_cast<T>(aMatrix->M34());
|
||||
aData[12] = static_cast<T>(aMatrix->M41());
|
||||
aData[13] = static_cast<T>(aMatrix->M42());
|
||||
aData[14] = static_cast<T>(aMatrix->M43());
|
||||
aData[15] = static_cast<T>(aMatrix->M44());
|
||||
}
|
||||
|
||||
void
|
||||
DOMMatrixReadOnly::ToFloat32Array(JSContext* aCx, JS::MutableHandle<JSObject*> aResult, ErrorResult& aRv) const
|
||||
{
|
||||
nsAutoTArray<float, 16> arr;
|
||||
arr.SetLength(16);
|
||||
GetDataFromMatrix(this, arr.Elements());
|
||||
JS::Rooted<JS::Value> value(aCx);
|
||||
if (!ToJSValue(aCx, TypedArrayCreator<Float32Array>(arr), &value)) {
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return;
|
||||
}
|
||||
aResult.set(&value.toObject());
|
||||
}
|
||||
|
||||
void
|
||||
DOMMatrixReadOnly::ToFloat64Array(JSContext* aCx, JS::MutableHandle<JSObject*> aResult, ErrorResult& aRv) const
|
||||
{
|
||||
nsAutoTArray<double, 16> arr;
|
||||
arr.SetLength(16);
|
||||
GetDataFromMatrix(this, arr.Elements());
|
||||
JS::Rooted<JS::Value> value(aCx);
|
||||
if (!ToJSValue(aCx, TypedArrayCreator<Float64Array>(arr), &value)) {
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return;
|
||||
}
|
||||
aResult.set(&value.toObject());
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DOMMatrix, mParent)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(DOMMatrix, AddRef)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(DOMMatrix, Release)
|
||||
|
||||
already_AddRefed<DOMMatrix>
|
||||
DOMMatrix::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv)
|
||||
{
|
||||
nsRefPtr<DOMMatrix> obj = new DOMMatrix(aGlobal.GetAsSupports());
|
||||
return obj.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<DOMMatrix>
|
||||
DOMMatrix::Constructor(const GlobalObject& aGlobal, const nsAString& aTransformList, ErrorResult& aRv)
|
||||
{
|
||||
nsRefPtr<DOMMatrix> obj = new DOMMatrix(aGlobal.GetAsSupports());
|
||||
|
||||
obj = obj->SetMatrixValue(aTransformList, aRv);
|
||||
return obj.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<DOMMatrix>
|
||||
DOMMatrix::Constructor(const GlobalObject& aGlobal, const DOMMatrixReadOnly& aOther, ErrorResult& aRv)
|
||||
{
|
||||
nsRefPtr<DOMMatrix> obj = new DOMMatrix(aGlobal.GetAsSupports(), aOther);
|
||||
return obj.forget();
|
||||
}
|
||||
|
||||
template <typename T> void SetDataInMatrix(DOMMatrix* aMatrix, const T* aData, int aLength, ErrorResult& aRv)
|
||||
{
|
||||
if (aLength == 16) {
|
||||
aMatrix->SetM11(aData[0]);
|
||||
aMatrix->SetM12(aData[1]);
|
||||
aMatrix->SetM13(aData[2]);
|
||||
aMatrix->SetM14(aData[3]);
|
||||
aMatrix->SetM21(aData[4]);
|
||||
aMatrix->SetM22(aData[5]);
|
||||
aMatrix->SetM23(aData[6]);
|
||||
aMatrix->SetM24(aData[7]);
|
||||
aMatrix->SetM31(aData[8]);
|
||||
aMatrix->SetM32(aData[9]);
|
||||
aMatrix->SetM33(aData[10]);
|
||||
aMatrix->SetM34(aData[11]);
|
||||
aMatrix->SetM41(aData[12]);
|
||||
aMatrix->SetM42(aData[13]);
|
||||
aMatrix->SetM43(aData[14]);
|
||||
aMatrix->SetM44(aData[15]);
|
||||
} else if (aLength == 6) {
|
||||
aMatrix->SetA(aData[0]);
|
||||
aMatrix->SetB(aData[1]);
|
||||
aMatrix->SetC(aData[2]);
|
||||
aMatrix->SetD(aData[3]);
|
||||
aMatrix->SetE(aData[4]);
|
||||
aMatrix->SetF(aData[5]);
|
||||
} else {
|
||||
aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<DOMMatrix>
|
||||
DOMMatrix::Constructor(const GlobalObject& aGlobal, const Float32Array& aArray32, ErrorResult& aRv)
|
||||
{
|
||||
nsRefPtr<DOMMatrix> obj = new DOMMatrix(aGlobal.GetAsSupports());
|
||||
aArray32.ComputeLengthAndData();
|
||||
SetDataInMatrix(obj, aArray32.Data(), aArray32.Length(), aRv);
|
||||
|
||||
return obj.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<DOMMatrix>
|
||||
DOMMatrix::Constructor(const GlobalObject& aGlobal, const Float64Array& aArray64, ErrorResult& aRv)
|
||||
{
|
||||
nsRefPtr<DOMMatrix> obj = new DOMMatrix(aGlobal.GetAsSupports());
|
||||
aArray64.ComputeLengthAndData();
|
||||
SetDataInMatrix(obj, aArray64.Data(), aArray64.Length(), aRv);
|
||||
|
||||
return obj.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<DOMMatrix>
|
||||
DOMMatrix::Constructor(const GlobalObject& aGlobal, const Sequence<double>& aNumberSequence, ErrorResult& aRv)
|
||||
{
|
||||
nsRefPtr<DOMMatrix> obj = new DOMMatrix(aGlobal.GetAsSupports());
|
||||
SetDataInMatrix(obj, aNumberSequence.Elements(), aNumberSequence.Length(), aRv);
|
||||
|
||||
return obj.forget();
|
||||
}
|
||||
|
||||
void DOMMatrix::Ensure3DMatrix()
|
||||
{
|
||||
if (!mMatrix3D) {
|
||||
mMatrix3D = new gfx::Matrix4x4(gfx::Matrix4x4::From2D(*mMatrix2D));
|
||||
mMatrix2D = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
DOMMatrix*
|
||||
DOMMatrix::MultiplySelf(const DOMMatrix& aOther)
|
||||
{
|
||||
if (aOther.Identity()) {
|
||||
return this;
|
||||
}
|
||||
|
||||
if (aOther.Is2D()) {
|
||||
if (mMatrix3D) {
|
||||
*mMatrix3D = gfx::Matrix4x4::From2D(*aOther.mMatrix2D) * *mMatrix3D;
|
||||
} else {
|
||||
*mMatrix2D = *aOther.mMatrix2D * *mMatrix2D;
|
||||
}
|
||||
} else {
|
||||
Ensure3DMatrix();
|
||||
*mMatrix3D = *aOther.mMatrix3D * *mMatrix3D;
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
DOMMatrix*
|
||||
DOMMatrix::PreMultiplySelf(const DOMMatrix& aOther)
|
||||
{
|
||||
if (aOther.Identity()) {
|
||||
return this;
|
||||
}
|
||||
|
||||
if (aOther.Is2D()) {
|
||||
if (mMatrix3D) {
|
||||
*mMatrix3D = *mMatrix3D * gfx::Matrix4x4::From2D(*aOther.mMatrix2D);
|
||||
} else {
|
||||
*mMatrix2D = *mMatrix2D * *aOther.mMatrix2D;
|
||||
}
|
||||
} else {
|
||||
Ensure3DMatrix();
|
||||
*mMatrix3D = *mMatrix3D * *aOther.mMatrix3D;
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
DOMMatrix*
|
||||
DOMMatrix::TranslateSelf(double aTx,
|
||||
double aTy,
|
||||
double aTz)
|
||||
{
|
||||
if (aTx == 0 && aTy == 0 && aTz == 0) {
|
||||
return this;
|
||||
}
|
||||
|
||||
if (mMatrix3D || aTz != 0) {
|
||||
Ensure3DMatrix();
|
||||
mMatrix3D->Translate(aTx, aTy, aTz);
|
||||
} else {
|
||||
mMatrix2D->Translate(aTx, aTy);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
DOMMatrix*
|
||||
DOMMatrix::ScaleSelf(double aScale, double aOriginX, double aOriginY)
|
||||
{
|
||||
ScaleNonUniformSelf(aScale, aScale, 1.0, aOriginX, aOriginY, 0);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
DOMMatrix*
|
||||
DOMMatrix::Scale3dSelf(double aScale, double aOriginX,
|
||||
double aOriginY, double aOriginZ)
|
||||
{
|
||||
ScaleNonUniformSelf(aScale, aScale, aScale, aOriginX, aOriginY, aOriginZ);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
DOMMatrix*
|
||||
DOMMatrix::ScaleNonUniformSelf(double aScaleX,
|
||||
double aScaleY,
|
||||
double aScaleZ,
|
||||
double aOriginX,
|
||||
double aOriginY,
|
||||
double aOriginZ)
|
||||
{
|
||||
if (aScaleX == 1.0 && aScaleY == 1.0 && aScaleZ == 1.0) {
|
||||
return this;
|
||||
}
|
||||
|
||||
TranslateSelf(aOriginX, aOriginY, aOriginZ);
|
||||
|
||||
if (mMatrix3D || aScaleZ != 1.0 || aOriginZ != 0) {
|
||||
Ensure3DMatrix();
|
||||
gfx::Matrix4x4 m;
|
||||
m._11 = aScaleX;
|
||||
m._22 = aScaleY;
|
||||
m._33 = aScaleZ;
|
||||
*mMatrix3D = m * *mMatrix3D;
|
||||
} else {
|
||||
gfx::Matrix m;
|
||||
m._11 = aScaleX;
|
||||
m._22 = aScaleY;
|
||||
*mMatrix2D = m * *mMatrix2D;
|
||||
}
|
||||
|
||||
TranslateSelf(-aOriginX, -aOriginY, -aOriginZ);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
DOMMatrix*
|
||||
DOMMatrix::RotateFromVectorSelf(double aX, double aY)
|
||||
{
|
||||
if (aX == 0.0 || aY == 0.0) {
|
||||
return this;
|
||||
}
|
||||
|
||||
RotateSelf(atan2(aY, aX) / radPerDegree);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
DOMMatrix*
|
||||
DOMMatrix::RotateSelf(double aAngle, double aOriginX, double aOriginY)
|
||||
{
|
||||
if (fmod(aAngle, 360) == 0) {
|
||||
return this;
|
||||
}
|
||||
|
||||
TranslateSelf(aOriginX, aOriginY);
|
||||
|
||||
if (mMatrix3D) {
|
||||
RotateAxisAngleSelf(0, 0, 1, aAngle);
|
||||
} else {
|
||||
*mMatrix2D = mMatrix2D->Rotate(aAngle * radPerDegree);
|
||||
}
|
||||
|
||||
TranslateSelf(-aOriginX, -aOriginY);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
DOMMatrix*
|
||||
DOMMatrix::RotateAxisAngleSelf(double aX, double aY,
|
||||
double aZ, double aAngle)
|
||||
{
|
||||
if (fmod(aAngle, 360) == 0) {
|
||||
return this;
|
||||
}
|
||||
|
||||
aAngle *= radPerDegree;
|
||||
// sin(aAngle / 2) * cos(aAngle / 2)
|
||||
double sc = sin(aAngle) / 2;
|
||||
// pow(sin(aAngle / 2), 2)
|
||||
double sq = (1 - cos(aAngle)) / 2;
|
||||
|
||||
Ensure3DMatrix();
|
||||
gfx::Matrix4x4 m;
|
||||
m._11 = 1 - 2 * (aY * aY + aZ * aZ) * sq;
|
||||
m._12 = 2 * (aX * aY * sq + aZ * sc);
|
||||
m._13 = 2 * (aX * aZ * sq - aY * sc);
|
||||
m._21 = 2 * (aX * aY * sq - aZ * sc);
|
||||
m._22 = 1 - 2 * (aX * aX + aZ * aZ) * sq;
|
||||
m._23 = 2 * (aY * aZ * sq + aX * sc);
|
||||
m._31 = 2 * (aX * aZ * sq + aY * sc);
|
||||
m._32 = 2 * (aY * aZ * sq - aX * sc);
|
||||
m._33 = 1 - 2 * (aX * aX + aY * aY) * sq;
|
||||
|
||||
*mMatrix3D = m * *mMatrix3D;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
DOMMatrix*
|
||||
DOMMatrix::SkewXSelf(double aSx)
|
||||
{
|
||||
if (fmod(aSx, 360) == 0) {
|
||||
return this;
|
||||
}
|
||||
|
||||
if (mMatrix3D) {
|
||||
gfx::Matrix4x4 m;
|
||||
m._21 = tan(aSx * radPerDegree);
|
||||
*mMatrix3D = m * *mMatrix3D;
|
||||
} else {
|
||||
gfx::Matrix m;
|
||||
m._21 = tan(aSx * radPerDegree);
|
||||
*mMatrix2D = m * *mMatrix2D;
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
DOMMatrix*
|
||||
DOMMatrix::SkewYSelf(double aSy)
|
||||
{
|
||||
if (fmod(aSy, 360) == 0) {
|
||||
return this;
|
||||
}
|
||||
|
||||
if (mMatrix3D) {
|
||||
gfx::Matrix4x4 m;
|
||||
m._12 = tan(aSy * radPerDegree);
|
||||
*mMatrix3D = m * *mMatrix3D;
|
||||
} else {
|
||||
gfx::Matrix m;
|
||||
m._12 = tan(aSy * radPerDegree);
|
||||
*mMatrix2D = m * *mMatrix2D;
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
DOMMatrix*
|
||||
DOMMatrix::InvertSelf()
|
||||
{
|
||||
if (mMatrix3D) {
|
||||
if (!mMatrix3D->Invert()) {
|
||||
mMatrix3D->SetNAN();
|
||||
}
|
||||
} else if (!mMatrix2D->Invert()) {
|
||||
mMatrix2D = nullptr;
|
||||
|
||||
mMatrix3D = new gfx::Matrix4x4();
|
||||
mMatrix3D->SetNAN();
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
DOMMatrix*
|
||||
DOMMatrix::SetMatrixValue(const nsAString& aTransformList, ErrorResult& aRv)
|
||||
{
|
||||
SVGTransformListParser parser(aTransformList);
|
||||
if (!parser.Parse()) {
|
||||
aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
|
||||
} else {
|
||||
mMatrix3D = nullptr;
|
||||
mMatrix2D = new gfx::Matrix();
|
||||
gfxMatrix result;
|
||||
const nsTArray<nsSVGTransform>& mItems = parser.GetTransformList();
|
||||
|
||||
for (uint32_t i = 0; i < mItems.Length(); ++i) {
|
||||
result.PreMultiply(mItems[i].GetMatrix());
|
||||
}
|
||||
|
||||
SetA(result._11);
|
||||
SetB(result._12);
|
||||
SetC(result._21);
|
||||
SetD(result._22);
|
||||
SetE(result._31);
|
||||
SetF(result._32);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
DOMMatrix::WrapObject(JSContext* aCx)
|
||||
{
|
||||
return DOMMatrixBinding::Wrap(aCx, this);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
256
content/base/src/DOMMatrix.h
Normal file
256
content/base/src/DOMMatrix.h
Normal file
@ -0,0 +1,256 @@
|
||||
/* -*- Mode: C++; tab-width: 2; 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/. */
|
||||
|
||||
#ifndef MOZILLA_DOM_DOMMATRIX_H_
|
||||
#define MOZILLA_DOM_DOMMATRIX_H_
|
||||
|
||||
#include "nsWrapperCache.h"
|
||||
#include "nsISupports.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
#include "mozilla/dom/TypedArray.h"
|
||||
#include "mozilla/gfx/Matrix.h" // for Matrix4x4
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class GlobalObject;
|
||||
class DOMMatrix;
|
||||
|
||||
class DOMMatrixReadOnly : public nsWrapperCache
|
||||
{
|
||||
public:
|
||||
DOMMatrixReadOnly(nsISupports* aParent)
|
||||
: mParent(aParent), mMatrix2D(new gfx::Matrix())
|
||||
{
|
||||
SetIsDOMBinding();
|
||||
}
|
||||
|
||||
DOMMatrixReadOnly(nsISupports* aParent, const DOMMatrixReadOnly& other)
|
||||
: mParent(aParent)
|
||||
{
|
||||
if (other.mMatrix2D) {
|
||||
mMatrix2D = new gfx::Matrix(*other.mMatrix2D);
|
||||
} else {
|
||||
mMatrix3D = new gfx::Matrix4x4(*other.mMatrix3D);
|
||||
}
|
||||
|
||||
SetIsDOMBinding();
|
||||
}
|
||||
|
||||
~DOMMatrixReadOnly()
|
||||
{
|
||||
}
|
||||
|
||||
#define GetMatrixMember(entry2D, entry3D, default) \
|
||||
{ \
|
||||
if (mMatrix3D) { \
|
||||
return mMatrix3D->entry3D; \
|
||||
} \
|
||||
return mMatrix2D->entry2D; \
|
||||
}
|
||||
|
||||
#define Get3DMatrixMember(entry3D, default) \
|
||||
{ \
|
||||
if (mMatrix3D) { \
|
||||
return mMatrix3D->entry3D; \
|
||||
} \
|
||||
return default; \
|
||||
}
|
||||
|
||||
double A() const GetMatrixMember(_11, _11, 1.0)
|
||||
double B() const GetMatrixMember(_12, _12, 0)
|
||||
double C() const GetMatrixMember(_21, _21, 0)
|
||||
double D() const GetMatrixMember(_22, _22, 1.0)
|
||||
double E() const GetMatrixMember(_31, _41, 0)
|
||||
double F() const GetMatrixMember(_32, _42, 0)
|
||||
|
||||
double M11() const GetMatrixMember(_11, _11, 1.0)
|
||||
double M12() const GetMatrixMember(_12, _12, 0)
|
||||
double M13() const Get3DMatrixMember(_13, 0)
|
||||
double M14() const Get3DMatrixMember(_14, 0)
|
||||
double M21() const GetMatrixMember(_21, _21, 0)
|
||||
double M22() const GetMatrixMember(_22, _22, 1.0)
|
||||
double M23() const Get3DMatrixMember(_23, 0)
|
||||
double M24() const Get3DMatrixMember(_24, 0)
|
||||
double M31() const Get3DMatrixMember(_31, 0)
|
||||
double M32() const Get3DMatrixMember(_32, 0)
|
||||
double M33() const Get3DMatrixMember(_33, 1.0)
|
||||
double M34() const Get3DMatrixMember(_34, 0)
|
||||
double M41() const GetMatrixMember(_31, _41, 0)
|
||||
double M42() const GetMatrixMember(_32, _42, 0)
|
||||
double M43() const Get3DMatrixMember(_43, 0)
|
||||
double M44() const Get3DMatrixMember(_44, 1.0)
|
||||
|
||||
#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;
|
||||
protected:
|
||||
nsCOMPtr<nsISupports> mParent;
|
||||
nsAutoPtr<gfx::Matrix> mMatrix2D;
|
||||
nsAutoPtr<gfx::Matrix4x4> mMatrix3D;
|
||||
private:
|
||||
DOMMatrixReadOnly() MOZ_DELETE;
|
||||
DOMMatrixReadOnly(const DOMMatrixReadOnly&) MOZ_DELETE;
|
||||
DOMMatrixReadOnly& operator=(const DOMMatrixReadOnly&) MOZ_DELETE;
|
||||
};
|
||||
|
||||
class DOMMatrix MOZ_FINAL : public DOMMatrixReadOnly
|
||||
{
|
||||
public:
|
||||
DOMMatrix(nsISupports* aParent)
|
||||
: DOMMatrixReadOnly(aParent)
|
||||
{}
|
||||
|
||||
DOMMatrix(nsISupports* aParent, const DOMMatrixReadOnly& other)
|
||||
: DOMMatrixReadOnly(aParent, other)
|
||||
{}
|
||||
|
||||
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(DOMMatrix)
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(DOMMatrix)
|
||||
|
||||
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) MOZ_OVERRIDE;
|
||||
|
||||
#define Set2DMatrixMember(entry2D, entry3D) \
|
||||
{ \
|
||||
if (mMatrix3D) { \
|
||||
mMatrix3D->entry3D = v; \
|
||||
} else { \
|
||||
mMatrix2D->entry2D = v; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define Set3DMatrixMember(entry3D, default) \
|
||||
{ \
|
||||
if (mMatrix3D || (v != default)) { \
|
||||
Ensure3DMatrix(); \
|
||||
mMatrix3D->entry3D = v; \
|
||||
} \
|
||||
}
|
||||
|
||||
void SetA(double v) Set2DMatrixMember(_11, _11)
|
||||
void SetB(double v) Set2DMatrixMember(_12, _12)
|
||||
void SetC(double v) Set2DMatrixMember(_21, _21)
|
||||
void SetD(double v) Set2DMatrixMember(_22, _22)
|
||||
void SetE(double v) Set2DMatrixMember(_31, _41)
|
||||
void SetF(double v) Set2DMatrixMember(_32, _42)
|
||||
|
||||
void SetM11(double v) Set2DMatrixMember(_11, _11)
|
||||
void SetM12(double v) Set2DMatrixMember(_12, _12)
|
||||
void SetM13(double v) Set3DMatrixMember(_13, 0)
|
||||
void SetM14(double v) Set3DMatrixMember(_14, 0)
|
||||
void SetM21(double v) Set2DMatrixMember(_21, _21)
|
||||
void SetM22(double v) Set2DMatrixMember(_22, _22)
|
||||
void SetM23(double v) Set3DMatrixMember(_23, 0)
|
||||
void SetM24(double v) Set3DMatrixMember(_24, 0)
|
||||
void SetM31(double v) Set3DMatrixMember(_31, 0)
|
||||
void SetM32(double v) Set3DMatrixMember(_32, 0)
|
||||
void SetM33(double v) Set3DMatrixMember(_33, 1.0)
|
||||
void SetM34(double v) Set3DMatrixMember(_34, 0)
|
||||
void SetM41(double v) Set2DMatrixMember(_31, _41)
|
||||
void SetM42(double v) Set2DMatrixMember(_32, _42)
|
||||
void SetM43(double v) Set3DMatrixMember(_43, 0)
|
||||
void SetM44(double v) Set3DMatrixMember(_44, 1.0)
|
||||
|
||||
#undef Set2DMatrixMember
|
||||
#undef Set3DMatrixMember
|
||||
|
||||
DOMMatrix* MultiplySelf(const DOMMatrix& aOther);
|
||||
DOMMatrix* PreMultiplySelf(const DOMMatrix& aOther);
|
||||
DOMMatrix* TranslateSelf(double aTx,
|
||||
double aTy,
|
||||
double aTz = 0);
|
||||
DOMMatrix* ScaleSelf(double aScale,
|
||||
double aOriginX = 0,
|
||||
double aOriginY = 0);
|
||||
DOMMatrix* Scale3dSelf(double aScale,
|
||||
double aOriginX = 0,
|
||||
double aOriginY = 0,
|
||||
double aOriginZ = 0);
|
||||
DOMMatrix* ScaleNonUniformSelf(double aScaleX,
|
||||
double aScaleY = 1,
|
||||
double aScaleZ = 1,
|
||||
double aOriginX = 0,
|
||||
double aOriginY = 0,
|
||||
double aOriginZ = 0);
|
||||
DOMMatrix* RotateSelf(double aAngle,
|
||||
double aOriginX = 0,
|
||||
double aOriginY = 0);
|
||||
DOMMatrix* RotateFromVectorSelf(double aX,
|
||||
double aY);
|
||||
DOMMatrix* RotateAxisAngleSelf(double aX,
|
||||
double aY,
|
||||
double aZ,
|
||||
double aAngle);
|
||||
DOMMatrix* SkewXSelf(double aSx);
|
||||
DOMMatrix* SkewYSelf(double aSy);
|
||||
DOMMatrix* InvertSelf();
|
||||
DOMMatrix* SetMatrixValue(const nsAString& aTransformList, ErrorResult& aRv);
|
||||
private:
|
||||
void Ensure3DMatrix();
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /*MOZILLA_DOM_DOMMATRIX_H_*/
|
@ -65,6 +65,7 @@ EXPORTS.mozilla.dom += [
|
||||
'DocumentFragment.h',
|
||||
'DocumentType.h',
|
||||
'DOMImplementation.h',
|
||||
'DOMMatrix.h',
|
||||
'DOMParser.h',
|
||||
'DOMPoint.h',
|
||||
'DOMQuad.h',
|
||||
@ -89,6 +90,7 @@ UNIFIED_SOURCES += [
|
||||
'DocumentFragment.cpp',
|
||||
'DocumentType.cpp',
|
||||
'DOMImplementation.cpp',
|
||||
'DOMMatrix.cpp',
|
||||
'DOMParser.cpp',
|
||||
'DOMPoint.cpp',
|
||||
'DOMQuad.cpp',
|
||||
|
@ -352,6 +352,11 @@ DOMInterfaces = {
|
||||
},
|
||||
},
|
||||
|
||||
'DOMMatrixReadOnly': {
|
||||
'headerFile': 'mozilla/dom/DOMMatrix.h',
|
||||
'concrete': False,
|
||||
},
|
||||
|
||||
'DOMPointReadOnly': {
|
||||
'headerFile': 'mozilla/dom/DOMPoint.h',
|
||||
'concrete': False,
|
||||
|
@ -29,6 +29,7 @@ skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop spec
|
||||
[test_clipboard_events.html]
|
||||
skip-if = buildapp == 'b2g' # b2g(clipboard undefined) b2g-debug(clipboard undefined) b2g-desktop(clipboard undefined)
|
||||
[test_consoleAPI.html]
|
||||
[test_DOMMatrix.html]
|
||||
[test_domWindowUtils.html]
|
||||
[test_domWindowUtils_scrollXY.html]
|
||||
[test_domWindowUtils_scrollbarSize.html]
|
||||
|
714
dom/tests/mochitest/general/test_DOMMatrix.html
Normal file
714
dom/tests/mochitest/general/test_DOMMatrix.html
Normal file
@ -0,0 +1,714 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test DOMMatrix behavior</title>
|
||||
<scriptsrc="/MochiKit/packed.js"></script>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css">
|
||||
</head>
|
||||
<script>
|
||||
function createMatrix(a, b, c, d, e, f)
|
||||
{
|
||||
var m = new DOMMatrix();
|
||||
m.a = a;
|
||||
m.b = b;
|
||||
m.c = c;
|
||||
m.d = d;
|
||||
m.e = e;
|
||||
m.f = f;
|
||||
return m;
|
||||
}
|
||||
|
||||
function create3DMatrix(a, b, c, d, e, f)
|
||||
{
|
||||
var m = new DOMMatrix();
|
||||
m.a = a;
|
||||
m.b = b;
|
||||
m.c = c;
|
||||
m.d = d;
|
||||
m.e = e;
|
||||
m.f = f;
|
||||
m.m13 = 0;
|
||||
return m;
|
||||
}
|
||||
|
||||
function cmpMatrix(a, b, msg)
|
||||
{
|
||||
if (Array.isArray(a))
|
||||
a = new DOMMatrix(a);
|
||||
if (Array.isArray(b))
|
||||
b = new DOMMatrix(b);
|
||||
|
||||
ok(CompareDOMMatrix(a, b),
|
||||
msg + " - got " + formatMatrix(a)
|
||||
+ ", expected " + formatMatrix(b));
|
||||
}
|
||||
|
||||
function roughCmpMatrix(a, b, msg)
|
||||
{
|
||||
if (Array.isArray(a))
|
||||
a = new DOMMatrix(a);
|
||||
if (Array.isArray(b))
|
||||
b = new DOMMatrix(b);
|
||||
|
||||
ok(RoughCompareDOMMatrix(a, b),
|
||||
msg + " - got " + formatMatrix(a)
|
||||
+ ", expected " + formatMatrix(b));
|
||||
}
|
||||
|
||||
function formatMatrix(m)
|
||||
{
|
||||
m = new DOMMatrix(m);
|
||||
|
||||
if (m.is2D)
|
||||
return "(" + [m.a, m.b, m.c, m.d, m.e, m.f].join(', ') + ")";
|
||||
else
|
||||
return "(" + [m.m11, m.m12, m.m13, m.m14,
|
||||
m.m21, m.m22, m.m23, m.m24,
|
||||
m.m31, m.m32, m.m33, m.m34,
|
||||
m.m41, m.m42, m.m43, m.m44,].join(', ') + ")";
|
||||
}
|
||||
|
||||
function CompareMatrix(dm, m)
|
||||
{
|
||||
var ma = m.toFloat32Array();
|
||||
for (var x = 0; x < ma.length; x++) {
|
||||
if (Math.abs(ma[x] - dm.m[x]) > 0.000001)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function CompareDOMMatrix(dm1, dm2)
|
||||
{
|
||||
var m1 = dm1.toFloat32Array();
|
||||
var m2 = dm2.toFloat32Array();
|
||||
|
||||
if (m1.length != m2.length)
|
||||
return false;
|
||||
|
||||
for (var x = 0; x < m1.length; x++) {
|
||||
if (Math.abs(m1[x] - m2[x]) > 0.000001)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function RoughCompareDOMMatrix(dm1, dm2)
|
||||
{
|
||||
var m1 = dm1.toFloat32Array();
|
||||
var m2 = dm2.toFloat32Array();
|
||||
|
||||
if (m1.length != m2.length)
|
||||
return false;
|
||||
|
||||
const tolerance = 1 / 65535;
|
||||
for (var x = 0; x < m1.length; x++) {
|
||||
if (Math.abs(m1[x] - m2[x]) > tolerance)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function main()
|
||||
{
|
||||
var tests = [
|
||||
testCreateMatrix,
|
||||
testMultiply,
|
||||
testInverse,
|
||||
testTranslate,
|
||||
testScale,
|
||||
testScaleNonUniform,
|
||||
testRotate,
|
||||
testRotateFromVector,
|
||||
testFlipX,
|
||||
testFlipY,
|
||||
testSkewX,
|
||||
testSkewY,
|
||||
testMultiplyInPlace,
|
||||
testInverseInPlace,
|
||||
testTranslateInPlace,
|
||||
testScaleInPlace,
|
||||
testScaleNonUniformInPlace,
|
||||
testRotateInPlace,
|
||||
testRotateFromVectorInPlace,
|
||||
testSkewXInPlace,
|
||||
testSkewYInPlace,
|
||||
testCreateMatrix3D,
|
||||
testMultiply3D,
|
||||
testInverse3D,
|
||||
testTranslate3D,
|
||||
testScale3D,
|
||||
test3D,
|
||||
testParsing
|
||||
];
|
||||
for (var i = 0; i < tests.length; i++) {
|
||||
try{
|
||||
tests[i]();
|
||||
} catch (e) {
|
||||
ok(false, "uncaught exception in test " + i + ": " + e.name);
|
||||
}
|
||||
}
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
function testCreateMatrix()
|
||||
{
|
||||
var m = new DOMMatrix();
|
||||
|
||||
// Should be initialised to identity
|
||||
cmpMatrix(m, [1, 0, 0, 1, 0, 0],
|
||||
"DOMMatrix should produce identity matrix");
|
||||
|
||||
m = new DOMMatrix([1,2,3,4,5,6]);
|
||||
cmpMatrix(m, [1,2,3,4,5,6],
|
||||
"DOMMatrix should produce the same matrix");
|
||||
ok(m.is2D, "Failed to mark matrix as 2D.");
|
||||
|
||||
m = new DOMMatrix([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]);
|
||||
cmpMatrix(m, [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16],
|
||||
"DOMMatrix should produce the same matrix");
|
||||
ok(!m.is2D, "Failed to mark matrix as 3D.");
|
||||
|
||||
var n = new DOMMatrix(m.toFloat32Array());
|
||||
cmpMatrix(n, [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16],
|
||||
"DOMMatrix should produce the same matrix with float32array constructor");
|
||||
ok(!n.is2D, "Failed to mark matrix as 3D.");
|
||||
|
||||
var n = new DOMMatrix(m.toFloat64Array());
|
||||
cmpMatrix(n, [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16],
|
||||
"DOMMatrix should produce the same matrix with float64array constructor");
|
||||
ok(!n.is2D, "Failed to mark matrix as 3D.");
|
||||
|
||||
var exn = null;
|
||||
try {
|
||||
m = new DOMMatrix([0]);
|
||||
} catch (e) {
|
||||
exn = e;
|
||||
}
|
||||
ok(exn, "did throw exception with bad DOMMatrix constructor with 1 parameter");
|
||||
|
||||
exn = null;
|
||||
try {
|
||||
m = new DOMMatrix([1,2,3,4,5,6,7,8,9]);
|
||||
} catch (e) {
|
||||
exn = e;
|
||||
}
|
||||
ok(exn, "did throw exception with bad DOMMatrix constructor with 9 parameters");
|
||||
|
||||
exn = null;
|
||||
try {
|
||||
m = new DOMMatrix([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17]);
|
||||
} catch (e) {
|
||||
exn = e;
|
||||
}
|
||||
ok(exn, "did throw exception with bad DOMMatrix constructor with 17 parameters");
|
||||
}
|
||||
|
||||
// DOMMatrix multiply(in DOMMatrix secondMatrix);
|
||||
function testMultiply()
|
||||
{
|
||||
var m1 = createMatrix(1, 0, 0, 1, 50, 90);
|
||||
var m2 = createMatrix(Math.SQRT1_2, -Math.SQRT1_2, Math.SQRT1_2, Math.SQRT1_2, 0, 0);
|
||||
var m3 = createMatrix(1, 0, 0, 1, 130, 160);
|
||||
var result = m1.multiply(m2).multiply(m3);
|
||||
roughCmpMatrix(result, [Math.SQRT1_2, -Math.SQRT1_2, Math.SQRT1_2, Math.SQRT1_2, 255.060974, 111.213203],
|
||||
"Unexpected result after multiplying matrices");
|
||||
|
||||
// Check orig matrices are unchanged
|
||||
cmpMatrix(m1, [1, 0, 0, 1, 50, 90], "Matrix changed after multiplication");
|
||||
roughCmpMatrix(m2, [Math.SQRT1_2, -Math.SQRT1_2, Math.SQRT1_2, Math.SQRT1_2, 0, 0],
|
||||
"Matrix changed after multiplication");
|
||||
cmpMatrix(m3, [1, 0, 0, 1, 130, 160], "Matrix changed after multiplication");
|
||||
}
|
||||
|
||||
// DOMMatrix inverse() raises(SVGException);
|
||||
function testInverse()
|
||||
{
|
||||
// Test inversion
|
||||
var m = createMatrix(2, 0, 0, 4, 110, -50);
|
||||
roughCmpMatrix(m.inverse(), [0.5, 0, 0, 0.25, -55, 12.5],
|
||||
"Unexpected result after inverting matrix");
|
||||
|
||||
// Test non-invertable
|
||||
m = createMatrix(0, 0, 1, 0, 0, 0);
|
||||
m = m.inverse();
|
||||
ok(isNaN(m.a), "Failed to invalidate inverted singular matrix, got " + m.a);
|
||||
ok(!m.is2D, "Failed to mark invalidated inverted singular matrix as 3D.");
|
||||
}
|
||||
|
||||
// DOMMatrix translate(in float x, in float y);
|
||||
function testTranslate()
|
||||
{
|
||||
var m = createMatrix(2, 0, 0, 1, 120, 100);
|
||||
roughCmpMatrix(m.translate(100, -50), [2, 0, 0, 1, 320, 50],
|
||||
"Unexpected result after translate");
|
||||
}
|
||||
|
||||
// DOMMatrix scale(in float scaleFactor);
|
||||
function testScale()
|
||||
{
|
||||
var m = createMatrix(2, 0, 0, 1, 120, 100);
|
||||
roughCmpMatrix(m.scale(0.5), [1, 0, 0, 0.5, 120, 100],
|
||||
"Unexpected result after scale");
|
||||
}
|
||||
|
||||
// DOMMatrix scaleNonUniform(in float scaleFactorX, in float scaleFactorY);
|
||||
function testScaleNonUniform()
|
||||
{
|
||||
var m = createMatrix(2, 0, 0, 1, 120, 100);
|
||||
roughCmpMatrix(m.scaleNonUniform(0.5, -3), [1, 0, 0, -3, 120, 100],
|
||||
"Unexpected result after scaleNonUniform");
|
||||
}
|
||||
|
||||
// DOMMatrix rotate(in float angle);
|
||||
function testRotate()
|
||||
{
|
||||
var m = createMatrix(2, 0, 0, 1, 120, 100);
|
||||
roughCmpMatrix(m.rotate(45),
|
||||
[2*Math.cos(Math.PI/4), Math.sin(Math.PI/4),
|
||||
2*-Math.sin(Math.PI/4), Math.cos(Math.PI/4),
|
||||
120, 100],
|
||||
"Unexpected result after rotate");
|
||||
}
|
||||
|
||||
// DOMMatrix rotateFromVector(in float x, in float y) raises(SVGException);
|
||||
function testRotateFromVector()
|
||||
{
|
||||
var m = createMatrix(2, 0, 0, 1, 120, 100);
|
||||
// Make a 150 degree angle
|
||||
var result = m.rotateFromVector(-2, 1.1547);
|
||||
roughCmpMatrix(result,
|
||||
[2*Math.cos(5*Math.PI/6), Math.sin(5*Math.PI/6),
|
||||
2*-Math.sin(5*Math.PI/6), Math.cos(5*Math.PI/6),
|
||||
120, 100],
|
||||
"Unexpected result after rotateFromVector");
|
||||
|
||||
// Test bad input (1)
|
||||
var exn = null;
|
||||
try {
|
||||
m.rotateFromVector(1, 0);
|
||||
} catch (e) {
|
||||
exn = e;
|
||||
}
|
||||
ise(exn, null, "did not throw exception with zero coord for rotateFromVector");
|
||||
|
||||
// Test bad input (2)
|
||||
exn = null;
|
||||
try {
|
||||
m.rotateFromVector(0, 1);
|
||||
} catch (e) {
|
||||
exn = e;
|
||||
}
|
||||
ise(exn, null, "did not throw exception with zero coord for rotateFromVector");
|
||||
}
|
||||
|
||||
// DOMMatrix flipX();
|
||||
function testFlipX()
|
||||
{
|
||||
var m = createMatrix(1, 2, 3, 4, 5, 6);
|
||||
cmpMatrix(m.flipX(), [-1, -2, 3, 4, 5, 6], "Unexpected result after flipX");
|
||||
}
|
||||
|
||||
// DOMMatrix flipY();
|
||||
function testFlipY()
|
||||
{
|
||||
var m = createMatrix(1, 2, 3, 4, 5, 6);
|
||||
cmpMatrix(m.flipY(), [1, 2, -3, -4, 5, 6], "Unexpected result after flipY");
|
||||
}
|
||||
|
||||
// DOMMatrix skewX(in float angle);
|
||||
function testSkewX()
|
||||
{
|
||||
var m = createMatrix(2, 0, 0, 1, 120, 100);
|
||||
roughCmpMatrix(m.skewX(30), [2, 0, 2*Math.tan(Math.PI/6), 1, 120, 100],
|
||||
"Unexpected result after skewX");
|
||||
}
|
||||
|
||||
// DOMMatrix skewY(in float angle);
|
||||
function testSkewY()
|
||||
{
|
||||
var m = createMatrix(2, 0, 0, 1, 120, 100);
|
||||
roughCmpMatrix(m.skewY(30), [2, Math.tan(Math.PI/6), 0, 1, 120, 100],
|
||||
"Unexpected result after skewY");
|
||||
}
|
||||
|
||||
// DOMMatrix multiply(in DOMMatrix secondMatrix);
|
||||
function testMultiplyInPlace()
|
||||
{
|
||||
var m1 = createMatrix(1, 0, 0, 1, 50, 90);
|
||||
var m2 = createMatrix(Math.SQRT1_2, -Math.SQRT1_2, Math.SQRT1_2, Math.SQRT1_2, 0, 0);
|
||||
var m3 = createMatrix(1, 0, 0, 1, 130, 160);
|
||||
m1.multiplySelf(m2).multiplySelf(m3);
|
||||
roughCmpMatrix(m1, [Math.SQRT1_2, -Math.SQRT1_2, Math.SQRT1_2, Math.SQRT1_2, 255.060974, 111.213203],
|
||||
"Unexpected result after multiplying matrices");
|
||||
|
||||
// Check orig matrices are unchanged
|
||||
roughCmpMatrix(m2, [Math.SQRT1_2, -Math.SQRT1_2, Math.SQRT1_2, Math.SQRT1_2, 0, 0],
|
||||
"Matrix changed after multiplication");
|
||||
cmpMatrix(m3, [1, 0, 0, 1, 130, 160], "Matrix changed after multiplication");
|
||||
}
|
||||
|
||||
// DOMMatrix inverse() raises(SVGException);
|
||||
function testInverseInPlace()
|
||||
{
|
||||
// Test inversion
|
||||
var m = createMatrix(2, 0, 0, 4, 110, -50);
|
||||
m.invertSelf();
|
||||
roughCmpMatrix(m, [0.5, 0, 0, 0.25, -55, 12.5],
|
||||
"Unexpected result after inverting matrix");
|
||||
|
||||
// Test non-invertable
|
||||
m = createMatrix(0, 0, 1, 0, 0, 0);
|
||||
m.invertSelf();
|
||||
ok(isNaN(m.a), "Failed to invalidate inverted singular matrix, got " + m.a);
|
||||
ok(!m.is2D, "Failed to mark invalidated inverted singular matrix as 3D.");
|
||||
}
|
||||
|
||||
// DOMMatrix translate(in float x, in float y);
|
||||
function testTranslateInPlace()
|
||||
{
|
||||
var m = createMatrix(2, 0, 0, 1, 120, 100);
|
||||
m.translateSelf(100, -50)
|
||||
roughCmpMatrix(m, [2, 0, 0, 1, 320, 50],
|
||||
"Unexpected result after translate");
|
||||
}
|
||||
|
||||
// DOMMatrix scale(in float scaleFactor);
|
||||
function testScaleInPlace()
|
||||
{
|
||||
var m = createMatrix(2, 0, 0, 1, 120, 100);
|
||||
m.scaleSelf(0.5);
|
||||
roughCmpMatrix(m, [1, 0, 0, 0.5, 120, 100],
|
||||
"Unexpected result after scale");
|
||||
}
|
||||
|
||||
// DOMMatrix scaleNonUniform(in float scaleFactorX, in float scaleFactorY);
|
||||
function testScaleNonUniformInPlace()
|
||||
{
|
||||
var m = createMatrix(2, 0, 0, 1, 120, 100);
|
||||
m.scaleNonUniformSelf(0.5, -3);
|
||||
roughCmpMatrix(m, [1, 0, 0, -3, 120, 100],
|
||||
"Unexpected result after scaleNonUniform");
|
||||
}
|
||||
|
||||
// DOMMatrix rotate(in float angle);
|
||||
function testRotateInPlace()
|
||||
{
|
||||
var m = createMatrix(2, 0, 0, 1, 120, 100);
|
||||
m.rotateSelf(45);
|
||||
roughCmpMatrix(m,
|
||||
[2*Math.cos(Math.PI/4), Math.sin(Math.PI/4),
|
||||
2*-Math.sin(Math.PI/4), Math.cos(Math.PI/4),
|
||||
120, 100],
|
||||
"Unexpected result after rotate");
|
||||
}
|
||||
|
||||
// DOMMatrix rotateFromVector(in float x, in float y) raises(SVGException);
|
||||
function testRotateFromVectorInPlace()
|
||||
{
|
||||
var m = createMatrix(2, 0, 0, 1, 120, 100);
|
||||
// Make a 150 degree angle
|
||||
m.rotateFromVectorSelf(-2, 1.1547);
|
||||
roughCmpMatrix(m,
|
||||
[2*Math.cos(5*Math.PI/6), Math.sin(5*Math.PI/6),
|
||||
2*-Math.sin(5*Math.PI/6), Math.cos(5*Math.PI/6),
|
||||
120, 100],
|
||||
"Unexpected result after rotateFromVector");
|
||||
|
||||
// Test bad input (1)
|
||||
try {
|
||||
m.rotateFromVectorSelf(1, 0);
|
||||
ok(true, "did not throw exception with zero coord for rotateFromVector");
|
||||
} catch (e) {
|
||||
ok(false,
|
||||
"Got unexpected exception " + e + ", expected NotSupportedError");
|
||||
}
|
||||
|
||||
// Test bad input (2)
|
||||
try {
|
||||
m.rotateFromVectorSelf(0, 1);
|
||||
ok(true, "did not throw exception with zero coord for rotateFromVector");
|
||||
} catch (e) { }
|
||||
}
|
||||
|
||||
// DOMMatrix skewX(in float angle);
|
||||
function testSkewXInPlace()
|
||||
{
|
||||
var m = createMatrix(2, 0, 0, 1, 120, 100);
|
||||
m.skewXSelf(30);
|
||||
roughCmpMatrix(m, [2, 0, 2*Math.tan(Math.PI/6), 1, 120, 100],
|
||||
"Unexpected result after skewX");
|
||||
}
|
||||
|
||||
// DOMMatrix skewY(in float angle);
|
||||
function testSkewYInPlace()
|
||||
{
|
||||
var m = createMatrix(2, 0, 0, 1, 120, 100);
|
||||
m.skewYSelf(30);
|
||||
roughCmpMatrix(m, [2, Math.tan(Math.PI/6), 0, 1, 120, 100],
|
||||
"Unexpected result after skewY");
|
||||
}
|
||||
|
||||
function testCreateMatrix3D()
|
||||
{
|
||||
var m = new DOMMatrix([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]);
|
||||
|
||||
// Should be initialised to identity
|
||||
cmpMatrix(m, [1, 0, 0, 1, 0, 0],
|
||||
"DOMMatrix should produce identity matrix");
|
||||
is(m.is2D, true, "should not produce 3d matrix");
|
||||
|
||||
m = new DOMMatrix([1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0]);
|
||||
|
||||
// Should be initialised to identity
|
||||
cmpMatrix(m, [1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0],
|
||||
"DOMMatrix should produce identity matrix");
|
||||
ise(m.is2D, false, "should produce 3d matrix");
|
||||
}
|
||||
|
||||
// DOMMatrix multiply(in DOMMatrix secondMatrix);
|
||||
function testMultiply3D()
|
||||
{
|
||||
var m1 = createMatrix(1, 0, 0, 1, 50, 90);
|
||||
var m2 = create3DMatrix(Math.SQRT1_2, -Math.SQRT1_2, Math.SQRT1_2, Math.SQRT1_2, 0, 0);
|
||||
var m3 = create3DMatrix(1, 0, 0, 1, 130, 160);
|
||||
var result = m1.multiply(m2).multiply(m3);
|
||||
ok(m1.is2D == true, "should produce 3d matrix");
|
||||
roughCmpMatrix(result, [Math.SQRT1_2, -Math.SQRT1_2, Math.SQRT1_2, Math.SQRT1_2, 255.060974, 111.213203],
|
||||
"Unexpected result after multiplying matrices");
|
||||
|
||||
// Check orig matrices are unchanged
|
||||
cmpMatrix(m1, [1, 0, 0, 1, 50, 90], "Matrix changed after multiplication");
|
||||
roughCmpMatrix(m2, [Math.SQRT1_2, -Math.SQRT1_2, Math.SQRT1_2, Math.SQRT1_2, 0, 0],
|
||||
"Matrix changed after multiplication");
|
||||
cmpMatrix(m3, [1, 0, 0, 1, 130, 160], "Matrix changed after multiplication");
|
||||
}
|
||||
|
||||
// DOMMatrix inverse() raises(SVGException);
|
||||
function testInverse3D()
|
||||
{
|
||||
// Test inversion
|
||||
var m = create3DMatrix(2, 0, 0, 4, 110, -50);
|
||||
roughCmpMatrix(m.inverse(), [0.5, 0, 0, 0.25, -55, 12.5],
|
||||
"Unexpected result after inverting matrix");
|
||||
|
||||
// Test non-invertable
|
||||
m = createMatrix(0, 0, 1, 0, 0, 0);
|
||||
m = m.inverse();
|
||||
ok(isNaN(m.a), "Failed to invalidate inverted singular matrix, got " + m.a);
|
||||
ok(!m.is2D, "Failed to mark invalidated inverted singular matrix as 3D.");
|
||||
}
|
||||
|
||||
// DOMMatrix translate(in float x, in float y);
|
||||
function testTranslate3D()
|
||||
{
|
||||
var m = create3DMatrix(2, 0, 0, 1, 120, 100);
|
||||
roughCmpMatrix(m.translate(100, -50), [2, 0, 0, 1, 320, 50],
|
||||
"Unexpected result after translate");
|
||||
}
|
||||
|
||||
// DOMMatrix scale(in float scaleFactor);
|
||||
function testScale3D()
|
||||
{
|
||||
var m = create3DMatrix(2, 0, 0, 1, 120, 100);
|
||||
roughCmpMatrix(m.scale(0.5), [1, 0, 0, 0.5, 120, 100],
|
||||
"Unexpected result after scale");
|
||||
}
|
||||
|
||||
function Matrix3D() {
|
||||
this.m = new Float32Array([
|
||||
1, 0, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 0, 1
|
||||
]);
|
||||
}
|
||||
|
||||
Matrix3D.prototype = {
|
||||
translate: function(x, y, z, result) {
|
||||
result = result || new Matrix3D();
|
||||
var m = result.m;
|
||||
|
||||
m[0] = 1;
|
||||
m[1] = 0;
|
||||
m[2] = 0;
|
||||
m[3] = x;
|
||||
|
||||
m[4] = 0;
|
||||
m[5] = 1;
|
||||
m[6] = 0;
|
||||
m[7] = y;
|
||||
|
||||
m[8] = 0;
|
||||
m[9] = 0;
|
||||
m[10] = 1;
|
||||
m[11] = z;
|
||||
|
||||
m[12] = 0;
|
||||
m[13] = 0;
|
||||
m[14] = 0;
|
||||
m[15] = 1;
|
||||
|
||||
return result;
|
||||
},
|
||||
inverse: function(matrix, result) {
|
||||
result = result || new Matrix3D();
|
||||
var m = matrix.m, r = result.m;
|
||||
|
||||
r[0] = m[5]*m[10]*m[15] - m[5]*m[14]*m[11] - m[6]*m[9]*m[15] + m[6]*m[13]*m[11] + m[7]*m[9]*m[14] - m[7]*m[13]*m[10];
|
||||
r[1] = -m[1]*m[10]*m[15] + m[1]*m[14]*m[11] + m[2]*m[9]*m[15] - m[2]*m[13]*m[11] - m[3]*m[9]*m[14] + m[3]*m[13]*m[10];
|
||||
r[2] = m[1]*m[6]*m[15] - m[1]*m[14]*m[7] - m[2]*m[5]*m[15] + m[2]*m[13]*m[7] + m[3]*m[5]*m[14] - m[3]*m[13]*m[6];
|
||||
r[3] = -m[1]*m[6]*m[11] + m[1]*m[10]*m[7] + m[2]*m[5]*m[11] - m[2]*m[9]*m[7] - m[3]*m[5]*m[10] + m[3]*m[9]*m[6];
|
||||
|
||||
r[4] = -m[4]*m[10]*m[15] + m[4]*m[14]*m[11] + m[6]*m[8]*m[15] - m[6]*m[12]*m[11] - m[7]*m[8]*m[14] + m[7]*m[12]*m[10];
|
||||
r[5] = m[0]*m[10]*m[15] - m[0]*m[14]*m[11] - m[2]*m[8]*m[15] + m[2]*m[12]*m[11] + m[3]*m[8]*m[14] - m[3]*m[12]*m[10];
|
||||
r[6] = -m[0]*m[6]*m[15] + m[0]*m[14]*m[7] + m[2]*m[4]*m[15] - m[2]*m[12]*m[7] - m[3]*m[4]*m[14] + m[3]*m[12]*m[6];
|
||||
r[7] = m[0]*m[6]*m[11] - m[0]*m[10]*m[7] - m[2]*m[4]*m[11] + m[2]*m[8]*m[7] + m[3]*m[4]*m[10] - m[3]*m[8]*m[6];
|
||||
|
||||
r[8] = m[4]*m[9]*m[15] - m[4]*m[13]*m[11] - m[5]*m[8]*m[15] + m[5]*m[12]*m[11] + m[7]*m[8]*m[13] - m[7]*m[12]*m[9];
|
||||
r[9] = -m[0]*m[9]*m[15] + m[0]*m[13]*m[11] + m[1]*m[8]*m[15] - m[1]*m[12]*m[11] - m[3]*m[8]*m[13] + m[3]*m[12]*m[9];
|
||||
r[10] = m[0]*m[5]*m[15] - m[0]*m[13]*m[7] - m[1]*m[4]*m[15] + m[1]*m[12]*m[7] + m[3]*m[4]*m[13] - m[3]*m[12]*m[5];
|
||||
r[11] = -m[0]*m[5]*m[11] + m[0]*m[9]*m[7] + m[1]*m[4]*m[11] - m[1]*m[8]*m[7] - m[3]*m[4]*m[9] + m[3]*m[8]*m[5];
|
||||
|
||||
r[12] = -m[4]*m[9]*m[14] + m[4]*m[13]*m[10] + m[5]*m[8]*m[14] - m[5]*m[12]*m[10] - m[6]*m[8]*m[13] + m[6]*m[12]*m[9];
|
||||
r[13] = m[0]*m[9]*m[14] - m[0]*m[13]*m[10] - m[1]*m[8]*m[14] + m[1]*m[12]*m[10] + m[2]*m[8]*m[13] - m[2]*m[12]*m[9];
|
||||
r[14] = -m[0]*m[5]*m[14] + m[0]*m[13]*m[6] + m[1]*m[4]*m[14] - m[1]*m[12]*m[6] - m[2]*m[4]*m[13] + m[2]*m[12]*m[5];
|
||||
r[15] = m[0]*m[5]*m[10] - m[0]*m[9]*m[6] - m[1]*m[4]*m[10] + m[1]*m[8]*m[6] + m[2]*m[4]*m[9] - m[2]*m[8]*m[5];
|
||||
|
||||
var det = m[0]*r[0] + m[1]*r[4] + m[2]*r[8] + m[3]*r[12];
|
||||
for (var i = 0; i < 16; i++) r[i] /= det;
|
||||
return result;
|
||||
},
|
||||
multiply: function(left, result) {
|
||||
result = result || new Matrix3D();
|
||||
var a = this.m, b = left.m, r = result.m;
|
||||
|
||||
r[0] = a[0] * b[0] + a[1] * b[4] + a[2] * b[8] + a[3] * b[12];
|
||||
r[1] = a[0] * b[1] + a[1] * b[5] + a[2] * b[9] + a[3] * b[13];
|
||||
r[2] = a[0] * b[2] + a[1] * b[6] + a[2] * b[10] + a[3] * b[14];
|
||||
r[3] = a[0] * b[3] + a[1] * b[7] + a[2] * b[11] + a[3] * b[15];
|
||||
|
||||
r[4] = a[4] * b[0] + a[5] * b[4] + a[6] * b[8] + a[7] * b[12];
|
||||
r[5] = a[4] * b[1] + a[5] * b[5] + a[6] * b[9] + a[7] * b[13];
|
||||
r[6] = a[4] * b[2] + a[5] * b[6] + a[6] * b[10] + a[7] * b[14];
|
||||
r[7] = a[4] * b[3] + a[5] * b[7] + a[6] * b[11] + a[7] * b[15];
|
||||
|
||||
r[8] = a[8] * b[0] + a[9] * b[4] + a[10] * b[8] + a[11] * b[12];
|
||||
r[9] = a[8] * b[1] + a[9] * b[5] + a[10] * b[9] + a[11] * b[13];
|
||||
r[10] = a[8] * b[2] + a[9] * b[6] + a[10] * b[10] + a[11] * b[14];
|
||||
r[11] = a[8] * b[3] + a[9] * b[7] + a[10] * b[11] + a[11] * b[15];
|
||||
|
||||
r[12] = a[12] * b[0] + a[13] * b[4] + a[14] * b[8] + a[15] * b[12];
|
||||
r[13] = a[12] * b[1] + a[13] * b[5] + a[14] * b[9] + a[15] * b[13];
|
||||
r[14] = a[12] * b[2] + a[13] * b[6] + a[14] * b[10] + a[15] * b[14];
|
||||
r[15] = a[12] * b[3] + a[13] * b[7] + a[14] * b[11] + a[15] * b[15];
|
||||
|
||||
return result;
|
||||
},
|
||||
scale: function(x, y, z, result) {
|
||||
result = result || new Matrix3D();
|
||||
var m = result.m;
|
||||
|
||||
m[0] = x;
|
||||
m[1] = 0;
|
||||
m[2] = 0;
|
||||
m[3] = 0;
|
||||
|
||||
m[4] = 0;
|
||||
m[5] = y;
|
||||
m[6] = 0;
|
||||
m[7] = 0;
|
||||
|
||||
m[8] = 0;
|
||||
m[9] = 0;
|
||||
m[10] = z;
|
||||
m[11] = 0;
|
||||
|
||||
m[12] = 0;
|
||||
m[13] = 0;
|
||||
m[14] = 0;
|
||||
m[15] = 1;
|
||||
|
||||
return result;
|
||||
},
|
||||
rotate: function(a, x, y, z, result) {
|
||||
result = result || new Matrix3D();
|
||||
var m = result.m;
|
||||
|
||||
var d = Math.sqrt(x*x + y*y + z*z);
|
||||
a *= Math.PI / 180; x /= d; y /= d; z /= d;
|
||||
var c = Math.cos(a), s = Math.sin(a), t = 1 - c;
|
||||
|
||||
m[0] = x * x * t + c;
|
||||
m[1] = x * y * t - z * s;
|
||||
m[2] = x * z * t + y * s;
|
||||
m[3] = 0;
|
||||
|
||||
m[4] = y * x * t + z * s;
|
||||
m[5] = y * y * t + c;
|
||||
m[6] = y * z * t - x * s;
|
||||
m[7] = 0;
|
||||
|
||||
m[8] = z * x * t - y * s;
|
||||
m[9] = z * y * t + x * s;
|
||||
m[10] = z * z * t + c;
|
||||
m[11] = 0;
|
||||
|
||||
m[12] = 0;
|
||||
m[13] = 0;
|
||||
m[14] = 0;
|
||||
m[15] = 1;
|
||||
|
||||
return result;
|
||||
},
|
||||
swap: function(result) {
|
||||
result = result || new Matrix3D();
|
||||
for (var x = 0; x < 16; x++)
|
||||
result.m[x] = this.m[Math.floor(x/4) + (x%4)*4];
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
function test3D()
|
||||
{
|
||||
var m = new DOMMatrix()
|
||||
var m2 = new Matrix3D();
|
||||
|
||||
m.translateSelf(2,3,4).scaleNonUniformSelf(1.2, 2.3, 3.4, 0, 0, 0);
|
||||
m2 = m2.multiply(m2.translate(2,3,4)).multiply(m2.scale(1.2, 2.3, 3.4)).swap();
|
||||
|
||||
ok(CompareMatrix(m2, m), "translate + scale in 3d didn't match, expected: " + formatMatrix(m2.m) + ", got: " + formatMatrix(m));
|
||||
|
||||
m.invertSelf();
|
||||
m2 = new Matrix3D();
|
||||
m2 = m2.multiply(m2.translate(2,3,4)).multiply(m2.scale(1.2, 2.3, 3.4));
|
||||
m2 = m2.inverse(m2).swap();
|
||||
ok(CompareMatrix(m2, m), "translate + scale in inverted 3d didn't match, expected: " + formatMatrix(m2.m) + ", got: " + formatMatrix(m));
|
||||
}
|
||||
|
||||
function testParsing()
|
||||
{
|
||||
var m = new DOMMatrix("translate(10, 20) scale(.5, 2) rotate(45)");
|
||||
var m2 = new DOMMatrix();
|
||||
m2.translateSelf(10, 20).scaleNonUniformSelf(.5,2).rotateSelf(45);
|
||||
ok(CompareDOMMatrix(m2, m), "string parsing didn't match");
|
||||
|
||||
m = new DOMMatrix();
|
||||
m.setMatrixValue("translate(10, 20) scale(.5, 2) rotate(45)");
|
||||
ok(CompareDOMMatrix(m2, m), "string parsing didn't match");
|
||||
}
|
||||
|
||||
window.addEventListener("load", main, false);
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -311,6 +311,10 @@ var interfaceNamesInGlobalScope =
|
||||
"DOMException",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"DOMImplementation",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"DOMMatrix",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"DOMMatrixReadOnly",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "DOMMMIError", b2g: true, pref: "dom.mobileconnection.enabled"},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
|
148
dom/webidl/DOMMatrix.webidl
Normal file
148
dom/webidl/DOMMatrix.webidl
Normal file
@ -0,0 +1,148 @@
|
||||
/* -*- Mode: IDL; tab-width: 2; 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 origin of this IDL file is
|
||||
* http://dev.w3.org/fxtf/geometry/
|
||||
*
|
||||
* Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
|
||||
* liability, trademark and document use rules apply.
|
||||
*/
|
||||
|
||||
[Pref="layout.css.DOMMatrix.enabled"]
|
||||
interface DOMMatrixReadOnly {
|
||||
// These attributes are simple aliases for certain elements of the 4x4 matrix
|
||||
readonly attribute unrestricted double a;
|
||||
readonly attribute unrestricted double b;
|
||||
readonly attribute unrestricted double c;
|
||||
readonly attribute unrestricted double d;
|
||||
readonly attribute unrestricted double e;
|
||||
readonly attribute unrestricted double f;
|
||||
|
||||
readonly attribute unrestricted double m11;
|
||||
readonly attribute unrestricted double m12;
|
||||
readonly attribute unrestricted double m13;
|
||||
readonly attribute unrestricted double m14;
|
||||
readonly attribute unrestricted double m21;
|
||||
readonly attribute unrestricted double m22;
|
||||
readonly attribute unrestricted double m23;
|
||||
readonly attribute unrestricted double m24;
|
||||
readonly attribute unrestricted double m31;
|
||||
readonly attribute unrestricted double m32;
|
||||
readonly attribute unrestricted double m33;
|
||||
readonly attribute unrestricted double m34;
|
||||
readonly attribute unrestricted double m41;
|
||||
readonly attribute unrestricted double m42;
|
||||
readonly attribute unrestricted double m43;
|
||||
readonly attribute unrestricted double m44;
|
||||
|
||||
// Immutable transform methods
|
||||
DOMMatrix translate(unrestricted double tx,
|
||||
unrestricted double ty,
|
||||
optional unrestricted double tz = 0);
|
||||
DOMMatrix scale(unrestricted double scale,
|
||||
optional unrestricted double originX = 0,
|
||||
optional unrestricted double originY = 0);
|
||||
DOMMatrix scale3d(unrestricted double scale,
|
||||
optional unrestricted double originX = 0,
|
||||
optional unrestricted double originY = 0,
|
||||
optional unrestricted double originZ = 0);
|
||||
DOMMatrix scaleNonUniform(unrestricted double scaleX,
|
||||
optional unrestricted double scaleY = 1,
|
||||
optional unrestricted double scaleZ = 1,
|
||||
optional unrestricted double originX = 0,
|
||||
optional unrestricted double originY = 0,
|
||||
optional unrestricted double originZ = 0);
|
||||
DOMMatrix rotate(unrestricted double angle,
|
||||
optional unrestricted double originX = 0,
|
||||
optional unrestricted double originY = 0);
|
||||
DOMMatrix rotateFromVector(unrestricted double x,
|
||||
unrestricted double y);
|
||||
DOMMatrix rotateAxisAngle(unrestricted double x,
|
||||
unrestricted double y,
|
||||
unrestricted double z,
|
||||
unrestricted double angle);
|
||||
DOMMatrix skewX(unrestricted double sx);
|
||||
DOMMatrix skewY(unrestricted double sy);
|
||||
DOMMatrix multiply(DOMMatrix other);
|
||||
DOMMatrix flipX();
|
||||
DOMMatrix flipY();
|
||||
DOMMatrix inverse();
|
||||
|
||||
// Helper methods
|
||||
readonly attribute boolean is2D;
|
||||
readonly attribute boolean identity;
|
||||
DOMPoint transformPoint(optional DOMPointInit point);
|
||||
[Throws] Float32Array toFloat32Array();
|
||||
[Throws] Float64Array toFloat64Array();
|
||||
stringifier;
|
||||
};
|
||||
|
||||
[Pref="layout.css.DOMMatrix.enabled",
|
||||
Constructor,
|
||||
Constructor(DOMString transformList),
|
||||
Constructor(DOMMatrixReadOnly other),
|
||||
Constructor(Float32Array array32),
|
||||
Constructor(Float64Array array64),
|
||||
Constructor(sequence<unrestricted double> numberSequence)]
|
||||
interface DOMMatrix : DOMMatrixReadOnly {
|
||||
// These attributes are simple aliases for certain elements of the 4x4 matrix
|
||||
inherit attribute unrestricted double a;
|
||||
inherit attribute unrestricted double b;
|
||||
inherit attribute unrestricted double c;
|
||||
inherit attribute unrestricted double d;
|
||||
inherit attribute unrestricted double e;
|
||||
inherit attribute unrestricted double f;
|
||||
|
||||
inherit attribute unrestricted double m11;
|
||||
inherit attribute unrestricted double m12;
|
||||
inherit attribute unrestricted double m13;
|
||||
inherit attribute unrestricted double m14;
|
||||
inherit attribute unrestricted double m21;
|
||||
inherit attribute unrestricted double m22;
|
||||
inherit attribute unrestricted double m23;
|
||||
inherit attribute unrestricted double m24;
|
||||
inherit attribute unrestricted double m31;
|
||||
inherit attribute unrestricted double m32;
|
||||
inherit attribute unrestricted double m33;
|
||||
inherit attribute unrestricted double m34;
|
||||
inherit attribute unrestricted double m41;
|
||||
inherit attribute unrestricted double m42;
|
||||
inherit attribute unrestricted double m43;
|
||||
inherit attribute unrestricted double m44;
|
||||
|
||||
// Mutable transform methods
|
||||
DOMMatrix multiplySelf(DOMMatrix other);
|
||||
DOMMatrix preMultiplySelf(DOMMatrix other);
|
||||
DOMMatrix translateSelf(unrestricted double tx,
|
||||
unrestricted double ty,
|
||||
optional unrestricted double tz = 0);
|
||||
DOMMatrix scaleSelf(unrestricted double scale,
|
||||
optional unrestricted double originX = 0,
|
||||
optional unrestricted double originY = 0);
|
||||
DOMMatrix scale3dSelf(unrestricted double scale,
|
||||
optional unrestricted double originX = 0,
|
||||
optional unrestricted double originY = 0,
|
||||
optional unrestricted double originZ = 0);
|
||||
DOMMatrix scaleNonUniformSelf(unrestricted double scaleX,
|
||||
optional unrestricted double scaleY = 1,
|
||||
optional unrestricted double scaleZ = 1,
|
||||
optional unrestricted double originX = 0,
|
||||
optional unrestricted double originY = 0,
|
||||
optional unrestricted double originZ = 0);
|
||||
DOMMatrix rotateSelf(unrestricted double angle,
|
||||
optional unrestricted double originX = 0,
|
||||
optional unrestricted double originY = 0);
|
||||
DOMMatrix rotateFromVectorSelf(unrestricted double x,
|
||||
unrestricted double y);
|
||||
DOMMatrix rotateAxisAngleSelf(unrestricted double x,
|
||||
unrestricted double y,
|
||||
unrestricted double z,
|
||||
unrestricted double angle);
|
||||
DOMMatrix skewXSelf(unrestricted double sx);
|
||||
DOMMatrix skewYSelf(unrestricted double sy);
|
||||
DOMMatrix invertSelf();
|
||||
[Throws] DOMMatrix setMatrixValue(DOMString transformList);
|
||||
};
|
||||
|
@ -88,6 +88,7 @@ WEBIDL_FILES = [
|
||||
'DOMError.webidl',
|
||||
'DOMException.webidl',
|
||||
'DOMImplementation.webidl',
|
||||
'DOMMatrix.webidl',
|
||||
'DOMMobileMessageError.webidl',
|
||||
'DOMParser.webidl',
|
||||
'DOMPoint.webidl',
|
||||
|
@ -7,6 +7,8 @@
|
||||
#include "Tools.h"
|
||||
#include <math.h>
|
||||
|
||||
#include "mozilla/FloatingPoint.h" // for UnspecifiedNaN
|
||||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
|
||||
@ -102,5 +104,73 @@ Matrix4x4::TransformBounds(const Rect& aRect) const
|
||||
return Rect(min_x, min_y, max_x - min_x, max_y - min_y);
|
||||
}
|
||||
|
||||
bool
|
||||
Matrix4x4::Invert()
|
||||
{
|
||||
Float det = Determinant();
|
||||
if (!det) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Matrix4x4 result;
|
||||
result._11 = _23 * _34 * _42 - _24 * _33 * _42 + _24 * _32 * _43 - _22 * _34 * _43 - _23 * _32 * _44 + _22 * _33 * _44;
|
||||
result._12 = _14 * _33 * _42 - _13 * _34 * _42 - _14 * _32 * _43 + _12 * _34 * _43 + _13 * _32 * _44 - _12 * _33 * _44;
|
||||
result._13 = _13 * _24 * _42 - _14 * _23 * _42 + _14 * _22 * _43 - _12 * _24 * _43 - _13 * _22 * _44 + _12 * _23 * _44;
|
||||
result._14 = _14 * _23 * _32 - _13 * _24 * _32 - _14 * _22 * _33 + _12 * _24 * _33 + _13 * _22 * _34 - _12 * _23 * _34;
|
||||
result._21 = _24 * _33 * _41 - _23 * _34 * _41 - _24 * _31 * _43 + _21 * _34 * _43 + _23 * _31 * _44 - _21 * _33 * _44;
|
||||
result._22 = _13 * _34 * _41 - _14 * _33 * _41 + _14 * _31 * _43 - _11 * _34 * _43 - _13 * _31 * _44 + _11 * _33 * _44;
|
||||
result._23 = _14 * _23 * _41 - _13 * _24 * _41 - _14 * _21 * _43 + _11 * _24 * _43 + _13 * _21 * _44 - _11 * _23 * _44;
|
||||
result._24 = _13 * _24 * _31 - _14 * _23 * _31 + _14 * _21 * _33 - _11 * _24 * _33 - _13 * _21 * _34 + _11 * _23 * _34;
|
||||
result._31 = _22 * _34 * _41 - _24 * _32 * _41 + _24 * _31 * _42 - _21 * _34 * _42 - _22 * _31 * _44 + _21 * _32 * _44;
|
||||
result._32 = _14 * _32 * _41 - _12 * _34 * _41 - _14 * _31 * _42 + _11 * _34 * _42 + _12 * _31 * _44 - _11 * _32 * _44;
|
||||
result._33 = _12 * _24 * _41 - _14 * _22 * _41 + _14 * _21 * _42 - _11 * _24 * _42 - _12 * _21 * _44 + _11 * _22 * _44;
|
||||
result._34 = _14 * _22 * _31 - _12 * _24 * _31 - _14 * _21 * _32 + _11 * _24 * _32 + _12 * _21 * _34 - _11 * _22 * _34;
|
||||
result._41 = _23 * _32 * _41 - _22 * _33 * _41 - _23 * _31 * _42 + _21 * _33 * _42 + _22 * _31 * _43 - _21 * _32 * _43;
|
||||
result._42 = _12 * _33 * _41 - _13 * _32 * _41 + _13 * _31 * _42 - _11 * _33 * _42 - _12 * _31 * _43 + _11 * _32 * _43;
|
||||
result._43 = _13 * _22 * _41 - _12 * _23 * _41 - _13 * _21 * _42 + _11 * _23 * _42 + _12 * _21 * _43 - _11 * _22 * _43;
|
||||
result._44 = _12 * _23 * _31 - _13 * _22 * _31 + _13 * _21 * _32 - _11 * _23 * _32 - _12 * _21 * _33 + _11 * _22 * _33;
|
||||
|
||||
result._11 /= det;
|
||||
result._12 /= det;
|
||||
result._13 /= det;
|
||||
result._14 /= det;
|
||||
result._21 /= det;
|
||||
result._22 /= det;
|
||||
result._23 /= det;
|
||||
result._24 /= det;
|
||||
result._31 /= det;
|
||||
result._32 /= det;
|
||||
result._33 /= det;
|
||||
result._34 /= det;
|
||||
result._41 /= det;
|
||||
result._42 /= det;
|
||||
result._43 /= det;
|
||||
result._44 /= det;
|
||||
*this = result;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
Matrix4x4::SetNAN()
|
||||
{
|
||||
_11 = UnspecifiedNaN<Float>();
|
||||
_21 = UnspecifiedNaN<Float>();
|
||||
_31 = UnspecifiedNaN<Float>();
|
||||
_41 = UnspecifiedNaN<Float>();
|
||||
_12 = UnspecifiedNaN<Float>();
|
||||
_22 = UnspecifiedNaN<Float>();
|
||||
_32 = UnspecifiedNaN<Float>();
|
||||
_42 = UnspecifiedNaN<Float>();
|
||||
_13 = UnspecifiedNaN<Float>();
|
||||
_23 = UnspecifiedNaN<Float>();
|
||||
_33 = UnspecifiedNaN<Float>();
|
||||
_43 = UnspecifiedNaN<Float>();
|
||||
_14 = UnspecifiedNaN<Float>();
|
||||
_24 = UnspecifiedNaN<Float>();
|
||||
_34 = UnspecifiedNaN<Float>();
|
||||
_44 = UnspecifiedNaN<Float>();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -508,6 +508,10 @@ public:
|
||||
+ _11 * _22 * _33 * _44;
|
||||
}
|
||||
|
||||
bool Invert();
|
||||
|
||||
// Set all the members of the matrix to NaN
|
||||
void SetNAN();
|
||||
};
|
||||
|
||||
class Matrix5x4
|
||||
|
@ -1889,6 +1889,9 @@ 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?
|
||||
#ifdef RELEASE_BUILD
|
||||
pref("layout.css.getBoxQuads.enabled", false);
|
||||
|
Loading…
Reference in New Issue
Block a user