gfx/thebes/gfxMatrix.h

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

michael@0 1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
michael@0 2 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #ifndef GFX_MATRIX_H
michael@0 7 #define GFX_MATRIX_H
michael@0 8
michael@0 9 #include "gfxPoint.h"
michael@0 10 #include "gfxTypes.h"
michael@0 11 #include "gfxRect.h"
michael@0 12
michael@0 13 // XX - I don't think this class should use gfxFloat at all,
michael@0 14 // but should use 'double' and be called gfxDoubleMatrix;
michael@0 15 // we can then typedef that to gfxMatrix where we typedef
michael@0 16 // double to be gfxFloat.
michael@0 17
michael@0 18 /**
michael@0 19 * A matrix that represents an affine transformation. Projective
michael@0 20 * transformations are not supported. This matrix looks like:
michael@0 21 *
michael@0 22 * / a b 0 \
michael@0 23 * | c d 0 |
michael@0 24 * \ tx ty 1 /
michael@0 25 *
michael@0 26 * So, transforming a point (x, y) results in:
michael@0 27 *
michael@0 28 * / a b 0 \ / a * x + c * y + tx \ T
michael@0 29 * (x y 1) * | c d 0 | = | b * x + d * y + ty |
michael@0 30 * \ tx ty 1 / \ 1 /
michael@0 31 *
michael@0 32 */
michael@0 33 struct gfxMatrix {
michael@0 34 double xx; double yx;
michael@0 35 double xy; double yy;
michael@0 36 double x0; double y0;
michael@0 37
michael@0 38 public:
michael@0 39 /**
michael@0 40 * Initializes this matrix as the identity matrix.
michael@0 41 */
michael@0 42 gfxMatrix() { Reset(); }
michael@0 43
michael@0 44 /**
michael@0 45 * Initializes the matrix from individual components. See the class
michael@0 46 * description for the layout of the matrix.
michael@0 47 */
michael@0 48 gfxMatrix(gfxFloat a, gfxFloat b, gfxFloat c, gfxFloat d, gfxFloat tx, gfxFloat ty) :
michael@0 49 xx(a), yx(b),
michael@0 50 xy(c), yy(d),
michael@0 51 x0(tx), y0(ty) { }
michael@0 52
michael@0 53 /**
michael@0 54 * Post-multiplies m onto the matrix.
michael@0 55 */
michael@0 56 const gfxMatrix& operator *= (const gfxMatrix& m) {
michael@0 57 return Multiply(m);
michael@0 58 }
michael@0 59
michael@0 60 /**
michael@0 61 * Multiplies *this with m and returns the result.
michael@0 62 */
michael@0 63 gfxMatrix operator * (const gfxMatrix& m) const {
michael@0 64 return gfxMatrix(*this).Multiply(m);
michael@0 65 }
michael@0 66
michael@0 67 /* Returns true if the other matrix is fuzzy-equal to this matrix.
michael@0 68 * Note that this isn't a cheap comparison!
michael@0 69 */
michael@0 70 bool operator==(const gfxMatrix& other) const
michael@0 71 {
michael@0 72 return FuzzyEqual(xx, other.xx) && FuzzyEqual(yx, other.yx) &&
michael@0 73 FuzzyEqual(xy, other.xy) && FuzzyEqual(yy, other.yy) &&
michael@0 74 FuzzyEqual(x0, other.x0) && FuzzyEqual(y0, other.y0);
michael@0 75 }
michael@0 76
michael@0 77 bool operator!=(const gfxMatrix& other) const
michael@0 78 {
michael@0 79 return !(*this == other);
michael@0 80 }
michael@0 81
michael@0 82 // matrix operations
michael@0 83 /**
michael@0 84 * Resets this matrix to the identity matrix.
michael@0 85 */
michael@0 86 const gfxMatrix& Reset();
michael@0 87
michael@0 88 bool IsIdentity() const {
michael@0 89 return xx == 1.0 && yx == 0.0 &&
michael@0 90 xy == 0.0 && yy == 1.0 &&
michael@0 91 x0 == 0.0 && y0 == 0.0;
michael@0 92 }
michael@0 93
michael@0 94 /**
michael@0 95 * Inverts this matrix, if possible. Otherwise, the matrix is left
michael@0 96 * unchanged.
michael@0 97 *
michael@0 98 * XXX should this do something with the return value of
michael@0 99 * cairo_matrix_invert?
michael@0 100 */
michael@0 101 const gfxMatrix& Invert();
michael@0 102
michael@0 103 /**
michael@0 104 * Check if matrix is singular (no inverse exists).
michael@0 105 */
michael@0 106 bool IsSingular() const {
michael@0 107 // if the determinant (ad - bc) is zero it's singular
michael@0 108 return (xx * yy) == (yx * xy);
michael@0 109 }
michael@0 110
michael@0 111 /**
michael@0 112 * Scales this matrix. The scale is pre-multiplied onto this matrix,
michael@0 113 * i.e. the scaling takes place before the other transformations.
michael@0 114 */
michael@0 115 const gfxMatrix& Scale(gfxFloat x, gfxFloat y);
michael@0 116
michael@0 117 /**
michael@0 118 * Translates this matrix. The translation is pre-multiplied onto this matrix,
michael@0 119 * i.e. the translation takes place before the other transformations.
michael@0 120 */
michael@0 121 const gfxMatrix& Translate(const gfxPoint& pt);
michael@0 122
michael@0 123 /**
michael@0 124 * Rotates this matrix. The rotation is pre-multiplied onto this matrix,
michael@0 125 * i.e. the translation takes place after the other transformations.
michael@0 126 *
michael@0 127 * @param radians Angle in radians.
michael@0 128 */
michael@0 129 const gfxMatrix& Rotate(gfxFloat radians);
michael@0 130
michael@0 131 /**
michael@0 132 * Multiplies the current matrix with m.
michael@0 133 * This is a post-multiplication, i.e. the transformations of m are
michael@0 134 * applied _after_ the existing transformations.
michael@0 135 *
michael@0 136 * XXX is that difference (compared to Rotate etc) a good thing?
michael@0 137 */
michael@0 138 const gfxMatrix& Multiply(const gfxMatrix& m);
michael@0 139
michael@0 140 /**
michael@0 141 * Multiplies the current matrix with m.
michael@0 142 * This is a pre-multiplication, i.e. the transformations of m are
michael@0 143 * applied _before_ the existing transformations.
michael@0 144 */
michael@0 145 const gfxMatrix& PreMultiply(const gfxMatrix& m);
michael@0 146
michael@0 147 /**
michael@0 148 * Transforms a point according to this matrix.
michael@0 149 */
michael@0 150 gfxPoint Transform(const gfxPoint& point) const;
michael@0 151
michael@0 152
michael@0 153 /**
michael@0 154 * Transform a distance according to this matrix. This does not apply
michael@0 155 * any translation components.
michael@0 156 */
michael@0 157 gfxSize Transform(const gfxSize& size) const;
michael@0 158
michael@0 159 /**
michael@0 160 * Transforms both the point and distance according to this matrix.
michael@0 161 */
michael@0 162 gfxRect Transform(const gfxRect& rect) const;
michael@0 163
michael@0 164 gfxRect TransformBounds(const gfxRect& rect) const;
michael@0 165
michael@0 166 /**
michael@0 167 * Returns the translation component of this matrix.
michael@0 168 */
michael@0 169 gfxPoint GetTranslation() const {
michael@0 170 return gfxPoint(x0, y0);
michael@0 171 }
michael@0 172
michael@0 173 /**
michael@0 174 * Returns true if the matrix is anything other than a straight
michael@0 175 * translation by integers.
michael@0 176 */
michael@0 177 bool HasNonIntegerTranslation() const {
michael@0 178 return HasNonTranslation() ||
michael@0 179 !FuzzyEqual(x0, floor(x0 + 0.5)) ||
michael@0 180 !FuzzyEqual(y0, floor(y0 + 0.5));
michael@0 181 }
michael@0 182
michael@0 183 /**
michael@0 184 * Returns true if the matrix has any transform other
michael@0 185 * than a straight translation
michael@0 186 */
michael@0 187 bool HasNonTranslation() const {
michael@0 188 return !FuzzyEqual(xx, 1.0) || !FuzzyEqual(yy, 1.0) ||
michael@0 189 !FuzzyEqual(xy, 0.0) || !FuzzyEqual(yx, 0.0);
michael@0 190 }
michael@0 191
michael@0 192 /**
michael@0 193 * Returns true if the matrix only has an integer translation.
michael@0 194 */
michael@0 195 bool HasOnlyIntegerTranslation() const {
michael@0 196 return !HasNonIntegerTranslation();
michael@0 197 }
michael@0 198
michael@0 199 /**
michael@0 200 * Returns true if the matrix has any transform other
michael@0 201 * than a translation or a -1 y scale (y axis flip)
michael@0 202 */
michael@0 203 bool HasNonTranslationOrFlip() const {
michael@0 204 return !FuzzyEqual(xx, 1.0) ||
michael@0 205 (!FuzzyEqual(yy, 1.0) && !FuzzyEqual(yy, -1.0)) ||
michael@0 206 !FuzzyEqual(xy, 0.0) || !FuzzyEqual(yx, 0.0);
michael@0 207 }
michael@0 208
michael@0 209 /**
michael@0 210 * Returns true if the matrix has any transform other
michael@0 211 * than a translation or scale; this is, if there is
michael@0 212 * no rotation.
michael@0 213 */
michael@0 214 bool HasNonAxisAlignedTransform() const {
michael@0 215 return !FuzzyEqual(xy, 0.0) || !FuzzyEqual(yx, 0.0);
michael@0 216 }
michael@0 217
michael@0 218 /**
michael@0 219 * Computes the determinant of this matrix.
michael@0 220 */
michael@0 221 double Determinant() const {
michael@0 222 return xx*yy - yx*xy;
michael@0 223 }
michael@0 224
michael@0 225 /* Computes the scale factors of this matrix; that is,
michael@0 226 * the amounts each basis vector is scaled by.
michael@0 227 * The xMajor parameter indicates if the larger scale is
michael@0 228 * to be assumed to be in the X direction or not.
michael@0 229 */
michael@0 230 gfxSize ScaleFactors(bool xMajor) const {
michael@0 231 double det = Determinant();
michael@0 232
michael@0 233 if (det == 0.0)
michael@0 234 return gfxSize(0.0, 0.0);
michael@0 235
michael@0 236 gfxSize sz = xMajor ? gfxSize(1.0, 0.0) : gfxSize(0.0, 1.0);
michael@0 237 sz = Transform(sz);
michael@0 238
michael@0 239 double major = sqrt(sz.width * sz.width + sz.height * sz.height);
michael@0 240 double minor = 0.0;
michael@0 241
michael@0 242 // ignore mirroring
michael@0 243 if (det < 0.0)
michael@0 244 det = - det;
michael@0 245
michael@0 246 if (major)
michael@0 247 minor = det / major;
michael@0 248
michael@0 249 if (xMajor)
michael@0 250 return gfxSize(major, minor);
michael@0 251
michael@0 252 return gfxSize(minor, major);
michael@0 253 }
michael@0 254
michael@0 255 /**
michael@0 256 * Snap matrix components that are close to integers
michael@0 257 * to integers. In particular, components that are integral when
michael@0 258 * converted to single precision are set to those integers.
michael@0 259 */
michael@0 260 void NudgeToIntegers(void);
michael@0 261
michael@0 262 /**
michael@0 263 * Returns true if matrix is multiple of 90 degrees rotation with flipping,
michael@0 264 * scaling and translation.
michael@0 265 */
michael@0 266 bool PreservesAxisAlignedRectangles() const {
michael@0 267 return ((FuzzyEqual(xx, 0.0) && FuzzyEqual(yy, 0.0))
michael@0 268 || (FuzzyEqual(xy, 0.0) && FuzzyEqual(yx, 0.0)));
michael@0 269 }
michael@0 270
michael@0 271 /**
michael@0 272 * Returns true if the matrix has non-integer scale
michael@0 273 */
michael@0 274 bool HasNonIntegerScale() const {
michael@0 275 return !FuzzyEqual(xx, floor(xx + 0.5)) ||
michael@0 276 !FuzzyEqual(yy, floor(yy + 0.5));
michael@0 277 }
michael@0 278
michael@0 279 private:
michael@0 280 static bool FuzzyEqual(gfxFloat aV1, gfxFloat aV2) {
michael@0 281 return fabs(aV2 - aV1) < 1e-6;
michael@0 282 }
michael@0 283 };
michael@0 284
michael@0 285 #endif /* GFX_MATRIX_H */

mercurial