gfx/thebes/gfxMatrix.h

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial