--- a/gfx/2d/Matrix.cpp
+++ b/gfx/2d/Matrix.cpp
@@ -70,53 +70,54 @@ Matrix::Rotation(Float aAngle)
newMatrix._11 = c;
newMatrix._12 = s;
newMatrix._21 = -s;
newMatrix._22 = c;
return newMatrix;
}
-template<> Rect
-Matrix::TransformBounds(const Rect &aRect) const
+template<> MatrixDouble
+MatrixDouble::Rotation(Double aAngle)
{
- int i;
- Point quad[4];
- Float min_x, max_x;
- Float min_y, max_y;
-
- quad[0] = TransformPoint(aRect.TopLeft());
- quad[1] = TransformPoint(aRect.TopRight());
- quad[2] = TransformPoint(aRect.BottomLeft());
- quad[3] = TransformPoint(aRect.BottomRight());
+ MatrixDouble newMatrix;
- min_x = max_x = quad[0].x;
- min_y = max_y = quad[0].y;
+ Double s = sin(aAngle);
+ Double c = cos(aAngle);
- for (i = 1; i < 4; i++) {
- if (quad[i].x < min_x)
- min_x = quad[i].x;
- if (quad[i].x > max_x)
- max_x = quad[i].x;
+ newMatrix._11 = c;
+ newMatrix._12 = s;
+ newMatrix._21 = -s;
+ newMatrix._22 = c;
- if (quad[i].y < min_y)
- min_y = quad[i].y;
- if (quad[i].y > max_y)
- max_y = quad[i].y;
- }
-
- return Rect(min_x, min_y, max_x - min_x, max_y - min_y);
+ return newMatrix;
}
-template<> Matrix&
-Matrix::NudgeToIntegers()
+template<> Matrix4x4
+MatrixDouble::operator*(const Matrix4x4& aMatrix) const
{
- NudgeToInteger(&_11);
- NudgeToInteger(&_12);
- NudgeToInteger(&_21);
- NudgeToInteger(&_22);
- NudgeToInteger(&_31);
- NudgeToInteger(&_32);
- return *this;
+ Matrix4x4 resultMatrix;
+
+ resultMatrix._11 = this->_11 * aMatrix._11 + this->_12 * aMatrix._21;
+ resultMatrix._12 = this->_11 * aMatrix._12 + this->_12 * aMatrix._22;
+ resultMatrix._13 = this->_11 * aMatrix._13 + this->_12 * aMatrix._23;
+ resultMatrix._14 = this->_11 * aMatrix._14 + this->_12 * aMatrix._24;
+
+ resultMatrix._21 = this->_21 * aMatrix._11 + this->_22 * aMatrix._21;
+ resultMatrix._22 = this->_21 * aMatrix._12 + this->_22 * aMatrix._22;
+ resultMatrix._23 = this->_21 * aMatrix._13 + this->_22 * aMatrix._23;
+ resultMatrix._24 = this->_21 * aMatrix._14 + this->_22 * aMatrix._24;
+
+ resultMatrix._31 = aMatrix._31;
+ resultMatrix._32 = aMatrix._32;
+ resultMatrix._33 = aMatrix._33;
+ resultMatrix._34 = aMatrix._34;
+
+ resultMatrix._41 = this->_31 * aMatrix._11 + this->_32 * aMatrix._21 + aMatrix._41;
+ resultMatrix._42 = this->_31 * aMatrix._12 + this->_32 * aMatrix._22 + aMatrix._42;
+ resultMatrix._43 = this->_31 * aMatrix._13 + this->_32 * aMatrix._23 + aMatrix._43;
+ resultMatrix._44 = this->_31 * aMatrix._14 + this->_32 * aMatrix._24 + aMatrix._44;
+
+ return resultMatrix;
}
} // namespace gfx
} // namespace mozilla
--- a/gfx/2d/Matrix.h
+++ b/gfx/2d/Matrix.h
@@ -23,16 +23,23 @@ namespace gfx {
static inline bool FuzzyEqual(Float aV1, Float aV2) {
// XXX - Check if fabs does the smart thing and just negates the sign bit.
return fabs(aV2 - aV1) < 1e-6;
}
template<class T>
class BaseMatrix
{
+ // Alias that maps to either Point or PointDouble depending on whether T is a
+ // float or a double.
+ typedef PointTyped<UnknownUnits, T> MatrixPoint;
+ // Same for size and rect
+ typedef SizeTyped<UnknownUnits, T> MatrixSize;
+ typedef RectTyped<UnknownUnits, T> MatrixRect;
+
public:
BaseMatrix()
: _11(1.0f), _12(0)
, _21(0), _22(1.0f)
, _31(0), _32(0)
{}
BaseMatrix(T a11, T a12, T a21, T a22, T a31, T a32)
: _11(a11), _12(a12)
@@ -59,44 +66,72 @@ public:
<< " " << aMatrix._12
<< "; " << aMatrix._21
<< " " << aMatrix._22
<< "; " << aMatrix._31
<< " " << aMatrix._32
<< "; ]";
}
- Point TransformPoint(const Point &aPoint) const
+ MatrixPoint TransformPoint(const MatrixPoint &aPoint) const
{
- Point retPoint;
+ MatrixPoint retPoint;
retPoint.x = aPoint.x * _11 + aPoint.y * _21 + _31;
retPoint.y = aPoint.x * _12 + aPoint.y * _22 + _32;
return retPoint;
}
- Size TransformSize(const Size &aSize) const
+ MatrixSize TransformSize(const MatrixSize &aSize) const
{
- Size retSize;
+ MatrixSize retSize;
retSize.width = aSize.width * _11 + aSize.height * _21;
retSize.height = aSize.width * _12 + aSize.height * _22;
return retSize;
}
- GFX2D_API Rect TransformBounds(const Rect& aRect) const;
+ GFX2D_API MatrixRect TransformBounds(const MatrixRect& aRect) const
+ {
+ int i;
+ MatrixPoint quad[4];
+ T min_x, max_x;
+ T min_y, max_y;
+
+ quad[0] = TransformPoint(aRect.TopLeft());
+ quad[1] = TransformPoint(aRect.TopRight());
+ quad[2] = TransformPoint(aRect.BottomLeft());
+ quad[3] = TransformPoint(aRect.BottomRight());
+
+ min_x = max_x = quad[0].x;
+ min_y = max_y = quad[0].y;
+
+ for (i = 1; i < 4; i++) {
+ if (quad[i].x < min_x)
+ min_x = quad[i].x;
+ if (quad[i].x > max_x)
+ max_x = quad[i].x;
+
+ if (quad[i].y < min_y)
+ min_y = quad[i].y;
+ if (quad[i].y > max_y)
+ max_y = quad[i].y;
+ }
+
+ return MatrixRect(min_x, min_y, max_x - min_x, max_y - min_y);
+ }
static BaseMatrix<T> Translation(T aX, T aY)
{
return BaseMatrix<T>(1.0f, 0.0f, 0.0f, 1.0f, aX, aY);
}
- static BaseMatrix<T> Translation(Point aPoint)
+ static BaseMatrix<T> Translation(MatrixPoint aPoint)
{
return Translation(aPoint.x, aPoint.y);
}
/**
* Apply a translation to this matrix.
*
* The "Pre" in this method's name means that the translation is applied
@@ -118,17 +153,17 @@ public:
BaseMatrix<T> &PreTranslate(T aX, T aY)
{
_31 += _11 * aX + _21 * aY;
_32 += _12 * aX + _22 * aY;
return *this;
}
- BaseMatrix<T> &PreTranslate(const Point &aPoint)
+ BaseMatrix<T> &PreTranslate(const MatrixPoint &aPoint)
{
return PreTranslate(aPoint.x, aPoint.y);
}
/**
* Similar to PreTranslate, but the translation is applied -after- this
* matrix's existing transformation instead of before it.
*
@@ -142,17 +177,17 @@ public:
*/
BaseMatrix<T> &PostTranslate(T aX, T aY)
{
_31 += aX;
_32 += aY;
return *this;
}
- BaseMatrix<T> &PostTranslate(const Point &aPoint)
+ BaseMatrix<T> &PostTranslate(const MatrixPoint &aPoint)
{
return PostTranslate(aPoint.x, aPoint.y);
}
static BaseMatrix<T> Scaling(T aScaleX, T aScaleY)
{
return BaseMatrix<T>(aScaleX, 0.0f, 0.0f, aScaleY, 0.0f, 0.0f);
}
@@ -252,16 +287,21 @@ public:
BaseMatrix<T>& operator*=(const BaseMatrix<T> &aMatrix)
{
*this = *this * aMatrix;
return *this;
}
/**
+ * Multiplies *this with aMatrix and returns the result.
+ */
+ Matrix4x4 operator*(const Matrix4x4& aMatrix) const;
+
+ /**
* Multiplies in the opposite order to operator=*.
*/
BaseMatrix<T> &PreMultiply(const BaseMatrix<T> &aMatrix)
{
*this = aMatrix * *this;
return *this;
}
@@ -356,17 +396,26 @@ public:
/* Returns true if the matrix is singular.
*/
bool IsSingular() const
{
T det = Determinant();
return !mozilla::IsFinite(det) || det == 0;
}
- GFX2D_API BaseMatrix<T> &NudgeToIntegers();
+ GFX2D_API BaseMatrix<T>& NudgeToIntegers()
+ {
+ NudgeToInteger(&_11);
+ NudgeToInteger(&_12);
+ NudgeToInteger(&_21);
+ NudgeToInteger(&_22);
+ NudgeToInteger(&_31);
+ NudgeToInteger(&_32);
+ return *this;
+ }
bool IsTranslation() const
{
return FuzzyEqual(_11, 1.0f) && FuzzyEqual(_12, 0.0f) &&
FuzzyEqual(_21, 0.0f) && FuzzyEqual(_22, 1.0f);
}
static bool FuzzyIsInteger(T aValue)
@@ -381,18 +430,18 @@ public:
bool IsAllIntegers() const
{
return FuzzyIsInteger(_11) && FuzzyIsInteger(_12) &&
FuzzyIsInteger(_21) && FuzzyIsInteger(_22) &&
FuzzyIsInteger(_31) && FuzzyIsInteger(_32);
}
- Point GetTranslation() const {
- return Point(_31, _32);
+ MatrixPoint GetTranslation() const {
+ return MatrixPoint(_31, _32);
}
/**
* Returns true if matrix is multiple of 90 degrees rotation with flipping,
* scaling and translation.
*/
bool PreservesAxisAlignedRectangles() const {
return ((FuzzyEqual(_11, 0.0) && FuzzyEqual(_22, 0.0))
@@ -409,19 +458,55 @@ public:
}
/**
* Returns true if the matrix has negative scaling (i.e. flip).
*/
bool HasNegativeScaling() const {
return (_11 < 0.0) || (_22 < 0.0);
}
+
+ /**
+ * Computes the scale factors of this matrix; that is,
+ * the amounts each basis vector is scaled by.
+ * The xMajor parameter indicates if the larger scale is
+ * to be assumed to be in the X direction or not.
+ */
+ MatrixSize ScaleFactors(bool xMajor) const {
+ T det = Determinant();
+
+ if (det == 0.0) {
+ return MatrixSize(0.0, 0.0);
+ }
+
+ MatrixSize sz = xMajor ? MatrixSize(1.0, 0.0) : MatrixSize(0.0, 1.0);
+ sz = TransformSize(sz);
+
+ T major = sqrt(sz.width * sz.width + sz.height * sz.height);
+ T minor = 0.0;
+
+ // ignore mirroring
+ if (det < 0.0) {
+ det = - det;
+ }
+
+ if (major) {
+ minor = det / major;
+ }
+
+ if (xMajor) {
+ return MatrixSize(major, minor);
+ }
+
+ return MatrixSize(minor, major);
+ }
};
typedef BaseMatrix<Float> Matrix;
+typedef BaseMatrix<Double> MatrixDouble;
// Helper functions used by Matrix4x4Typed defined in Matrix.cpp
double
SafeTangent(double aTheta);
double
FlushToZero(double aVal);
template<class Units, class F>