1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/2d/Matrix.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,544 @@ 1.4 +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- 1.5 + * This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#ifndef MOZILLA_GFX_MATRIX_H_ 1.10 +#define MOZILLA_GFX_MATRIX_H_ 1.11 + 1.12 +#include "Types.h" 1.13 +#include "Rect.h" 1.14 +#include "Point.h" 1.15 +#include <math.h> 1.16 + 1.17 +namespace mozilla { 1.18 +namespace gfx { 1.19 + 1.20 +class Matrix 1.21 +{ 1.22 +public: 1.23 + Matrix() 1.24 + : _11(1.0f), _12(0) 1.25 + , _21(0), _22(1.0f) 1.26 + , _31(0), _32(0) 1.27 + {} 1.28 + Matrix(Float a11, Float a12, Float a21, Float a22, Float a31, Float a32) 1.29 + : _11(a11), _12(a12) 1.30 + , _21(a21), _22(a22) 1.31 + , _31(a31), _32(a32) 1.32 + {} 1.33 + Float _11, _12; 1.34 + Float _21, _22; 1.35 + Float _31, _32; 1.36 + 1.37 + Point operator *(const Point &aPoint) const 1.38 + { 1.39 + Point retPoint; 1.40 + 1.41 + retPoint.x = aPoint.x * _11 + aPoint.y * _21 + _31; 1.42 + retPoint.y = aPoint.x * _12 + aPoint.y * _22 + _32; 1.43 + 1.44 + return retPoint; 1.45 + } 1.46 + 1.47 + Size operator *(const Size &aSize) const 1.48 + { 1.49 + Size retSize; 1.50 + 1.51 + retSize.width = aSize.width * _11 + aSize.height * _21; 1.52 + retSize.height = aSize.width * _12 + aSize.height * _22; 1.53 + 1.54 + return retSize; 1.55 + } 1.56 + 1.57 + GFX2D_API Rect TransformBounds(const Rect& rect) const; 1.58 + 1.59 + // Apply a scale to this matrix. This scale will be applied -before- the 1.60 + // existing transformation of the matrix. 1.61 + Matrix &Scale(Float aX, Float aY) 1.62 + { 1.63 + _11 *= aX; 1.64 + _12 *= aX; 1.65 + _21 *= aY; 1.66 + _22 *= aY; 1.67 + 1.68 + return *this; 1.69 + } 1.70 + 1.71 + Matrix &Translate(Float aX, Float aY) 1.72 + { 1.73 + _31 += _11 * aX + _21 * aY; 1.74 + _32 += _12 * aX + _22 * aY; 1.75 + 1.76 + return *this; 1.77 + } 1.78 + 1.79 + Matrix &PostTranslate(Float aX, Float aY) 1.80 + { 1.81 + _31 += aX; 1.82 + _32 += aY; 1.83 + return *this; 1.84 + } 1.85 + 1.86 + Matrix &Rotate(Float aAngle) 1.87 + { 1.88 + return *this = Matrix::Rotation(aAngle) * *this; 1.89 + } 1.90 + 1.91 + bool Invert() 1.92 + { 1.93 + // Compute co-factors. 1.94 + Float A = _22; 1.95 + Float B = -_21; 1.96 + Float C = _21 * _32 - _22 * _31; 1.97 + Float D = -_12; 1.98 + Float E = _11; 1.99 + Float F = _31 * _12 - _11 * _32; 1.100 + 1.101 + Float det = Determinant(); 1.102 + 1.103 + if (!det) { 1.104 + return false; 1.105 + } 1.106 + 1.107 + Float inv_det = 1 / det; 1.108 + 1.109 + _11 = inv_det * A; 1.110 + _12 = inv_det * D; 1.111 + _21 = inv_det * B; 1.112 + _22 = inv_det * E; 1.113 + _31 = inv_det * C; 1.114 + _32 = inv_det * F; 1.115 + 1.116 + return true; 1.117 + } 1.118 + 1.119 + Float Determinant() const 1.120 + { 1.121 + return _11 * _22 - _12 * _21; 1.122 + } 1.123 + 1.124 + static Matrix Translation(Float aX, Float aY) 1.125 + { 1.126 + return Matrix(1.0f, 0.0f, 0.0f, 1.0f, aX, aY); 1.127 + } 1.128 + 1.129 + static Matrix Translation(Point aPoint) 1.130 + { 1.131 + return Translation(aPoint.x, aPoint.y); 1.132 + } 1.133 + 1.134 + GFX2D_API static Matrix Rotation(Float aAngle); 1.135 + 1.136 + static Matrix Scaling(Float aX, Float aY) 1.137 + { 1.138 + return Matrix(aX, 0.0f, 0.0f, aY, 0.0f, 0.0f); 1.139 + } 1.140 + 1.141 + Matrix operator*(const Matrix &aMatrix) const 1.142 + { 1.143 + Matrix resultMatrix; 1.144 + 1.145 + resultMatrix._11 = this->_11 * aMatrix._11 + this->_12 * aMatrix._21; 1.146 + resultMatrix._12 = this->_11 * aMatrix._12 + this->_12 * aMatrix._22; 1.147 + resultMatrix._21 = this->_21 * aMatrix._11 + this->_22 * aMatrix._21; 1.148 + resultMatrix._22 = this->_21 * aMatrix._12 + this->_22 * aMatrix._22; 1.149 + resultMatrix._31 = this->_31 * aMatrix._11 + this->_32 * aMatrix._21 + aMatrix._31; 1.150 + resultMatrix._32 = this->_31 * aMatrix._12 + this->_32 * aMatrix._22 + aMatrix._32; 1.151 + 1.152 + return resultMatrix; 1.153 + } 1.154 + 1.155 + Matrix& operator*=(const Matrix &aMatrix) 1.156 + { 1.157 + Matrix resultMatrix = *this * aMatrix; 1.158 + return *this = resultMatrix; 1.159 + } 1.160 + 1.161 + /* Returns true if the other matrix is fuzzy-equal to this matrix. 1.162 + * Note that this isn't a cheap comparison! 1.163 + */ 1.164 + bool operator==(const Matrix& other) const 1.165 + { 1.166 + return FuzzyEqual(_11, other._11) && FuzzyEqual(_12, other._12) && 1.167 + FuzzyEqual(_21, other._21) && FuzzyEqual(_22, other._22) && 1.168 + FuzzyEqual(_31, other._31) && FuzzyEqual(_32, other._32); 1.169 + } 1.170 + 1.171 + bool operator!=(const Matrix& other) const 1.172 + { 1.173 + return !(*this == other); 1.174 + } 1.175 + 1.176 + /* Returns true if the matrix is a rectilinear transformation (i.e. 1.177 + * grid-aligned rectangles are transformed to grid-aligned rectangles) 1.178 + */ 1.179 + bool IsRectilinear() const { 1.180 + if (FuzzyEqual(_12, 0) && FuzzyEqual(_21, 0)) { 1.181 + return true; 1.182 + } else if (FuzzyEqual(_22, 0) && FuzzyEqual(_11, 0)) { 1.183 + return true; 1.184 + } 1.185 + 1.186 + return false; 1.187 + } 1.188 + 1.189 + /** 1.190 + * Returns true if the matrix is anything other than a straight 1.191 + * translation by integers. 1.192 + */ 1.193 + bool HasNonIntegerTranslation() const { 1.194 + return HasNonTranslation() || 1.195 + !FuzzyEqual(_31, floor(_31 + 0.5)) || 1.196 + !FuzzyEqual(_32, floor(_32 + 0.5)); 1.197 + } 1.198 + 1.199 + /** 1.200 + * Returns true if the matrix has any transform other 1.201 + * than a straight translation. 1.202 + */ 1.203 + bool HasNonTranslation() const { 1.204 + return !FuzzyEqual(_11, 1.0) || !FuzzyEqual(_22, 1.0) || 1.205 + !FuzzyEqual(_12, 0.0) || !FuzzyEqual(_21, 0.0); 1.206 + } 1.207 + 1.208 + /* Returns true if the matrix is an identity matrix. 1.209 + */ 1.210 + bool IsIdentity() const 1.211 + { 1.212 + return _11 == 1.0f && _12 == 0.0f && 1.213 + _21 == 0.0f && _22 == 1.0f && 1.214 + _31 == 0.0f && _32 == 0.0f; 1.215 + } 1.216 + 1.217 + /* Returns true if the matrix is singular. 1.218 + */ 1.219 + bool IsSingular() const 1.220 + { 1.221 + return Determinant() == 0; 1.222 + } 1.223 + 1.224 + GFX2D_API void NudgeToIntegers(); 1.225 + 1.226 + bool IsTranslation() const 1.227 + { 1.228 + return FuzzyEqual(_11, 1.0f) && FuzzyEqual(_12, 0.0f) && 1.229 + FuzzyEqual(_21, 0.0f) && FuzzyEqual(_22, 1.0f); 1.230 + } 1.231 + 1.232 + bool IsIntegerTranslation() const 1.233 + { 1.234 + return IsTranslation() && 1.235 + FuzzyEqual(_31, floorf(_31 + 0.5f)) && 1.236 + FuzzyEqual(_32, floorf(_32 + 0.5f)); 1.237 + } 1.238 + 1.239 + Point GetTranslation() const { 1.240 + return Point(_31, _32); 1.241 + } 1.242 + 1.243 + /** 1.244 + * Returns true if matrix is multiple of 90 degrees rotation with flipping, 1.245 + * scaling and translation. 1.246 + */ 1.247 + bool PreservesAxisAlignedRectangles() const { 1.248 + return ((FuzzyEqual(_11, 0.0) && FuzzyEqual(_22, 0.0)) 1.249 + || (FuzzyEqual(_12, 0.0) && FuzzyEqual(_21, 0.0))); 1.250 + } 1.251 + 1.252 + /** 1.253 + * Returns true if the matrix has any transform other 1.254 + * than a translation or scale; this is, if there is 1.255 + * no rotation. 1.256 + */ 1.257 + bool HasNonAxisAlignedTransform() const { 1.258 + return !FuzzyEqual(_21, 0.0) || !FuzzyEqual(_12, 0.0); 1.259 + } 1.260 + 1.261 + /** 1.262 + * Returns true if the matrix has non-integer scale 1.263 + */ 1.264 + bool HasNonIntegerScale() const { 1.265 + return !FuzzyEqual(_11, floor(_11 + 0.5)) || 1.266 + !FuzzyEqual(_22, floor(_22 + 0.5)); 1.267 + } 1.268 + 1.269 +private: 1.270 + static bool FuzzyEqual(Float aV1, Float aV2) { 1.271 + // XXX - Check if fabs does the smart thing and just negates the sign bit. 1.272 + return fabs(aV2 - aV1) < 1e-6; 1.273 + } 1.274 +}; 1.275 + 1.276 +class Matrix4x4 1.277 +{ 1.278 +public: 1.279 + Matrix4x4() 1.280 + : _11(1.0f), _12(0.0f), _13(0.0f), _14(0.0f) 1.281 + , _21(0.0f), _22(1.0f), _23(0.0f), _24(0.0f) 1.282 + , _31(0.0f), _32(0.0f), _33(1.0f), _34(0.0f) 1.283 + , _41(0.0f), _42(0.0f), _43(0.0f), _44(1.0f) 1.284 + {} 1.285 + 1.286 + Float _11, _12, _13, _14; 1.287 + Float _21, _22, _23, _24; 1.288 + Float _31, _32, _33, _34; 1.289 + Float _41, _42, _43, _44; 1.290 + 1.291 + /** 1.292 + * Returns true if the matrix is isomorphic to a 2D affine transformation. 1.293 + */ 1.294 + bool Is2D() const 1.295 + { 1.296 + if (_13 != 0.0f || _14 != 0.0f || 1.297 + _23 != 0.0f || _24 != 0.0f || 1.298 + _31 != 0.0f || _32 != 0.0f || _33 != 1.0f || _34 != 0.0f || 1.299 + _43 != 0.0f || _44 != 1.0f) { 1.300 + return false; 1.301 + } 1.302 + return true; 1.303 + } 1.304 + 1.305 + bool Is2D(Matrix* aMatrix) const { 1.306 + if (!Is2D()) { 1.307 + return false; 1.308 + } 1.309 + if (aMatrix) { 1.310 + aMatrix->_11 = _11; 1.311 + aMatrix->_12 = _12; 1.312 + aMatrix->_21 = _21; 1.313 + aMatrix->_22 = _22; 1.314 + aMatrix->_31 = _41; 1.315 + aMatrix->_32 = _42; 1.316 + } 1.317 + return true; 1.318 + } 1.319 + 1.320 + Matrix As2D() const 1.321 + { 1.322 + MOZ_ASSERT(Is2D(), "Matrix is not a 2D affine transform"); 1.323 + 1.324 + return Matrix(_11, _12, _21, _22, _41, _42); 1.325 + } 1.326 + 1.327 + bool CanDraw2D(Matrix* aMatrix = nullptr) const { 1.328 + if (_14 != 0.0f || 1.329 + _24 != 0.0f || 1.330 + _44 != 1.0f) { 1.331 + return false; 1.332 + } 1.333 + if (aMatrix) { 1.334 + aMatrix->_11 = _11; 1.335 + aMatrix->_12 = _12; 1.336 + aMatrix->_21 = _21; 1.337 + aMatrix->_22 = _22; 1.338 + aMatrix->_31 = _41; 1.339 + aMatrix->_32 = _42; 1.340 + } 1.341 + return true; 1.342 + } 1.343 + 1.344 + Matrix4x4& ProjectTo2D() { 1.345 + _31 = 0.0f; 1.346 + _32 = 0.0f; 1.347 + _13 = 0.0f; 1.348 + _23 = 0.0f; 1.349 + _33 = 1.0f; 1.350 + _43 = 0.0f; 1.351 + _34 = 0.0f; 1.352 + return *this; 1.353 + } 1.354 + 1.355 + static Matrix4x4 From2D(const Matrix &aMatrix) { 1.356 + Matrix4x4 matrix; 1.357 + matrix._11 = aMatrix._11; 1.358 + matrix._12 = aMatrix._12; 1.359 + matrix._21 = aMatrix._21; 1.360 + matrix._22 = aMatrix._22; 1.361 + matrix._41 = aMatrix._31; 1.362 + matrix._42 = aMatrix._32; 1.363 + return matrix; 1.364 + } 1.365 + 1.366 + bool Is2DIntegerTranslation() const 1.367 + { 1.368 + return Is2D() && As2D().IsIntegerTranslation(); 1.369 + } 1.370 + 1.371 + Point4D operator *(const Point4D& aPoint) const 1.372 + { 1.373 + Point4D retPoint; 1.374 + 1.375 + retPoint.x = aPoint.x * _11 + aPoint.y * _21 + aPoint.z * _31 + _41; 1.376 + retPoint.y = aPoint.x * _12 + aPoint.y * _22 + aPoint.z * _32 + _42; 1.377 + retPoint.z = aPoint.x * _13 + aPoint.y * _23 + aPoint.z * _33 + _43; 1.378 + retPoint.w = aPoint.x * _14 + aPoint.y * _24 + aPoint.z * _34 + _44; 1.379 + 1.380 + return retPoint; 1.381 + } 1.382 + 1.383 + Point3D operator *(const Point3D& aPoint) const 1.384 + { 1.385 + Point4D temp(aPoint.x, aPoint.y, aPoint.z, 1); 1.386 + 1.387 + temp = *this * temp; 1.388 + temp /= temp.w; 1.389 + 1.390 + return Point3D(temp.x, temp.y, temp.z); 1.391 + } 1.392 + 1.393 + Point operator *(const Point &aPoint) const 1.394 + { 1.395 + Point4D temp(aPoint.x, aPoint.y, 0, 1); 1.396 + 1.397 + temp = *this * temp; 1.398 + temp /= temp.w; 1.399 + 1.400 + return Point(temp.x, temp.y); 1.401 + } 1.402 + 1.403 + GFX2D_API Rect TransformBounds(const Rect& rect) const; 1.404 + 1.405 + // Apply a scale to this matrix. This scale will be applied -before- the 1.406 + // existing transformation of the matrix. 1.407 + Matrix4x4 &Scale(Float aX, Float aY, Float aZ) 1.408 + { 1.409 + _11 *= aX; 1.410 + _12 *= aX; 1.411 + _13 *= aX; 1.412 + _21 *= aY; 1.413 + _22 *= aY; 1.414 + _23 *= aY; 1.415 + _31 *= aZ; 1.416 + _32 *= aZ; 1.417 + _33 *= aZ; 1.418 + 1.419 + return *this; 1.420 + } 1.421 + 1.422 + Matrix4x4 &Translate(Float aX, Float aY, Float aZ) 1.423 + { 1.424 + _41 += aX * _11 + aY * _21 + aZ * _31; 1.425 + _42 += aX * _12 + aY * _22 + aZ * _32; 1.426 + _43 += aX * _13 + aY * _23 + aZ * _33; 1.427 + _44 += aX * _14 + aY * _24 + aZ * _34; 1.428 + 1.429 + return *this; 1.430 + } 1.431 + 1.432 + bool operator==(const Matrix4x4& o) const 1.433 + { 1.434 + // XXX would be nice to memcmp here, but that breaks IEEE 754 semantics 1.435 + return _11 == o._11 && _12 == o._12 && _13 == o._13 && _14 == o._14 && 1.436 + _21 == o._21 && _22 == o._22 && _23 == o._23 && _24 == o._24 && 1.437 + _31 == o._31 && _32 == o._32 && _33 == o._33 && _34 == o._34 && 1.438 + _41 == o._41 && _42 == o._42 && _43 == o._43 && _44 == o._44; 1.439 + } 1.440 + 1.441 + bool operator!=(const Matrix4x4& o) const 1.442 + { 1.443 + return !((*this) == o); 1.444 + } 1.445 + 1.446 + Matrix4x4 operator*(const Matrix4x4 &aMatrix) const 1.447 + { 1.448 + Matrix4x4 matrix; 1.449 + 1.450 + matrix._11 = _11 * aMatrix._11 + _12 * aMatrix._21 + _13 * aMatrix._31 + _14 * aMatrix._41; 1.451 + matrix._21 = _21 * aMatrix._11 + _22 * aMatrix._21 + _23 * aMatrix._31 + _24 * aMatrix._41; 1.452 + matrix._31 = _31 * aMatrix._11 + _32 * aMatrix._21 + _33 * aMatrix._31 + _34 * aMatrix._41; 1.453 + matrix._41 = _41 * aMatrix._11 + _42 * aMatrix._21 + _43 * aMatrix._31 + _44 * aMatrix._41; 1.454 + matrix._12 = _11 * aMatrix._12 + _12 * aMatrix._22 + _13 * aMatrix._32 + _14 * aMatrix._42; 1.455 + matrix._22 = _21 * aMatrix._12 + _22 * aMatrix._22 + _23 * aMatrix._32 + _24 * aMatrix._42; 1.456 + matrix._32 = _31 * aMatrix._12 + _32 * aMatrix._22 + _33 * aMatrix._32 + _34 * aMatrix._42; 1.457 + matrix._42 = _41 * aMatrix._12 + _42 * aMatrix._22 + _43 * aMatrix._32 + _44 * aMatrix._42; 1.458 + matrix._13 = _11 * aMatrix._13 + _12 * aMatrix._23 + _13 * aMatrix._33 + _14 * aMatrix._43; 1.459 + matrix._23 = _21 * aMatrix._13 + _22 * aMatrix._23 + _23 * aMatrix._33 + _24 * aMatrix._43; 1.460 + matrix._33 = _31 * aMatrix._13 + _32 * aMatrix._23 + _33 * aMatrix._33 + _34 * aMatrix._43; 1.461 + matrix._43 = _41 * aMatrix._13 + _42 * aMatrix._23 + _43 * aMatrix._33 + _44 * aMatrix._43; 1.462 + matrix._14 = _11 * aMatrix._14 + _12 * aMatrix._24 + _13 * aMatrix._34 + _14 * aMatrix._44; 1.463 + matrix._24 = _21 * aMatrix._14 + _22 * aMatrix._24 + _23 * aMatrix._34 + _24 * aMatrix._44; 1.464 + matrix._34 = _31 * aMatrix._14 + _32 * aMatrix._24 + _33 * aMatrix._34 + _34 * aMatrix._44; 1.465 + matrix._44 = _41 * aMatrix._14 + _42 * aMatrix._24 + _43 * aMatrix._34 + _44 * aMatrix._44; 1.466 + 1.467 + return matrix; 1.468 + } 1.469 + 1.470 + 1.471 + /* Returns true if the matrix is an identity matrix. 1.472 + */ 1.473 + bool IsIdentity() const 1.474 + { 1.475 + return _11 == 1.0f && _12 == 0.0f && _13 == 0.0f && _14 == 0.0f && 1.476 + _21 == 0.0f && _22 == 1.0f && _23 == 0.0f && _24 == 0.0f && 1.477 + _31 == 0.0f && _32 == 0.0f && _33 == 1.0f && _34 == 0.0f && 1.478 + _41 == 0.0f && _42 == 0.0f && _43 == 0.0f && _44 == 1.0f; 1.479 + } 1.480 + 1.481 + bool IsSingular() const 1.482 + { 1.483 + return Determinant() == 0.0; 1.484 + } 1.485 + 1.486 + Float Determinant() const 1.487 + { 1.488 + return _14 * _23 * _32 * _41 1.489 + - _13 * _24 * _32 * _41 1.490 + - _14 * _22 * _33 * _41 1.491 + + _12 * _24 * _33 * _41 1.492 + + _13 * _22 * _34 * _41 1.493 + - _12 * _23 * _34 * _41 1.494 + - _14 * _23 * _31 * _42 1.495 + + _13 * _24 * _31 * _42 1.496 + + _14 * _21 * _33 * _42 1.497 + - _11 * _24 * _33 * _42 1.498 + - _13 * _21 * _34 * _42 1.499 + + _11 * _23 * _34 * _42 1.500 + + _14 * _22 * _31 * _43 1.501 + - _12 * _24 * _31 * _43 1.502 + - _14 * _21 * _32 * _43 1.503 + + _11 * _24 * _32 * _43 1.504 + + _12 * _21 * _34 * _43 1.505 + - _11 * _22 * _34 * _43 1.506 + - _13 * _22 * _31 * _44 1.507 + + _12 * _23 * _31 * _44 1.508 + + _13 * _21 * _32 * _44 1.509 + - _11 * _23 * _32 * _44 1.510 + - _12 * _21 * _33 * _44 1.511 + + _11 * _22 * _33 * _44; 1.512 + } 1.513 + 1.514 +}; 1.515 + 1.516 +class Matrix5x4 1.517 +{ 1.518 +public: 1.519 + Matrix5x4() 1.520 + : _11(1.0f), _12(0), _13(0), _14(0) 1.521 + , _21(0), _22(1.0f), _23(0), _24(0) 1.522 + , _31(0), _32(0), _33(1.0f), _34(0) 1.523 + , _41(0), _42(0), _43(0), _44(1.0f) 1.524 + , _51(0), _52(0), _53(0), _54(0) 1.525 + {} 1.526 + Matrix5x4(Float a11, Float a12, Float a13, Float a14, 1.527 + Float a21, Float a22, Float a23, Float a24, 1.528 + Float a31, Float a32, Float a33, Float a34, 1.529 + Float a41, Float a42, Float a43, Float a44, 1.530 + Float a51, Float a52, Float a53, Float a54) 1.531 + : _11(a11), _12(a12), _13(a13), _14(a14) 1.532 + , _21(a21), _22(a22), _23(a23), _24(a24) 1.533 + , _31(a31), _32(a32), _33(a33), _34(a34) 1.534 + , _41(a41), _42(a42), _43(a43), _44(a44) 1.535 + , _51(a51), _52(a52), _53(a53), _54(a54) 1.536 + {} 1.537 + Float _11, _12, _13, _14; 1.538 + Float _21, _22, _23, _24; 1.539 + Float _31, _32, _33, _34; 1.540 + Float _41, _42, _43, _44; 1.541 + Float _51, _52, _53, _54; 1.542 +}; 1.543 + 1.544 +} 1.545 +} 1.546 + 1.547 +#endif /* MOZILLA_GFX_MATRIX_H_ */