Home | History | Annotate | Download | only in fxcrt
      1 // Copyright 2014 PDFium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
      6 
      7 #ifndef CORE_FXCRT_FX_COORDINATES_H_
      8 #define CORE_FXCRT_FX_COORDINATES_H_
      9 
     10 #include "core/fxcrt/fx_basic.h"
     11 
     12 class CFX_Matrix;
     13 
     14 template <class BaseType>
     15 class CFX_PTemplate {
     16  public:
     17   CFX_PTemplate() : x(0), y(0) {}
     18   CFX_PTemplate(BaseType new_x, BaseType new_y) : x(new_x), y(new_y) {}
     19   CFX_PTemplate(const CFX_PTemplate& other) : x(other.x), y(other.y) {}
     20   void clear() {
     21     x = 0;
     22     y = 0;
     23   }
     24   CFX_PTemplate operator=(const CFX_PTemplate& other) {
     25     if (this != &other) {
     26       x = other.x;
     27       y = other.y;
     28     }
     29     return *this;
     30   }
     31   bool operator==(const CFX_PTemplate& other) const {
     32     return x == other.x && y == other.y;
     33   }
     34   bool operator!=(const CFX_PTemplate& other) const {
     35     return !(*this == other);
     36   }
     37   CFX_PTemplate& operator+=(const CFX_PTemplate<BaseType>& obj) {
     38     x += obj.x;
     39     y += obj.y;
     40     return *this;
     41   }
     42   CFX_PTemplate& operator-=(const CFX_PTemplate<BaseType>& obj) {
     43     x -= obj.x;
     44     y -= obj.y;
     45     return *this;
     46   }
     47   CFX_PTemplate& operator*=(BaseType factor) {
     48     x *= factor;
     49     y *= factor;
     50     return *this;
     51   }
     52   CFX_PTemplate& operator/=(BaseType divisor) {
     53     x /= divisor;
     54     y /= divisor;
     55     return *this;
     56   }
     57   CFX_PTemplate operator+(const CFX_PTemplate& other) const {
     58     return CFX_PTemplate(x + other.x, y + other.y);
     59   }
     60   CFX_PTemplate operator-(const CFX_PTemplate& other) const {
     61     return CFX_PTemplate(x - other.x, y - other.y);
     62   }
     63   CFX_PTemplate operator*(BaseType factor) const {
     64     return CFX_PTemplate(x * factor, y * factor);
     65   }
     66   CFX_PTemplate operator/(BaseType divisor) const {
     67     return CFX_PTemplate(x / divisor, y / divisor);
     68   }
     69 
     70   BaseType x;
     71   BaseType y;
     72 };
     73 using CFX_Point = CFX_PTemplate<int32_t>;
     74 using CFX_PointF = CFX_PTemplate<FX_FLOAT>;
     75 
     76 template <class BaseType>
     77 class CFX_STemplate {
     78  public:
     79   CFX_STemplate() : width(0), height(0) {}
     80 
     81   CFX_STemplate(BaseType new_width, BaseType new_height)
     82       : width(new_width), height(new_height) {}
     83 
     84   CFX_STemplate(const CFX_STemplate& other)
     85       : width(other.width), height(other.height) {}
     86 
     87   template <typename OtherType>
     88   CFX_STemplate<OtherType> As() const {
     89     return CFX_STemplate<OtherType>(static_cast<OtherType>(width),
     90                                     static_cast<OtherType>(height));
     91   }
     92 
     93   void clear() {
     94     width = 0;
     95     height = 0;
     96   }
     97   CFX_STemplate operator=(const CFX_STemplate& other) {
     98     if (this != &other) {
     99       width = other.width;
    100       height = other.height;
    101     }
    102     return *this;
    103   }
    104   bool operator==(const CFX_STemplate& other) const {
    105     return width == other.width && height == other.height;
    106   }
    107   bool operator!=(const CFX_STemplate& other) const {
    108     return !(*this == other);
    109   }
    110   CFX_STemplate& operator+=(const CFX_STemplate<BaseType>& obj) {
    111     width += obj.width;
    112     height += obj.height;
    113     return *this;
    114   }
    115   CFX_STemplate& operator-=(const CFX_STemplate<BaseType>& obj) {
    116     width -= obj.width;
    117     height -= obj.height;
    118     return *this;
    119   }
    120   CFX_STemplate& operator*=(BaseType factor) {
    121     width *= factor;
    122     height *= factor;
    123     return *this;
    124   }
    125   CFX_STemplate& operator/=(BaseType divisor) {
    126     width /= divisor;
    127     height /= divisor;
    128     return *this;
    129   }
    130   CFX_STemplate operator+(const CFX_STemplate& other) const {
    131     return CFX_STemplate(width + other.width, height + other.height);
    132   }
    133   CFX_STemplate operator-(const CFX_STemplate& other) const {
    134     return CFX_STemplate(width - other.width, height - other.height);
    135   }
    136   CFX_STemplate operator*(BaseType factor) const {
    137     return CFX_STemplate(width * factor, height * factor);
    138   }
    139   CFX_STemplate operator/(BaseType divisor) const {
    140     return CFX_STemplate(width / divisor, height / divisor);
    141   }
    142 
    143   BaseType width;
    144   BaseType height;
    145 };
    146 using CFX_Size = CFX_STemplate<int32_t>;
    147 using CFX_SizeF = CFX_STemplate<FX_FLOAT>;
    148 
    149 template <class BaseType>
    150 class CFX_VTemplate : public CFX_PTemplate<BaseType> {
    151  public:
    152   using CFX_PTemplate<BaseType>::x;
    153   using CFX_PTemplate<BaseType>::y;
    154 
    155   CFX_VTemplate() : CFX_PTemplate<BaseType>() {}
    156   CFX_VTemplate(BaseType new_x, BaseType new_y)
    157       : CFX_PTemplate<BaseType>(new_x, new_y) {}
    158 
    159   CFX_VTemplate(const CFX_VTemplate& other) : CFX_PTemplate<BaseType>(other) {}
    160 
    161   CFX_VTemplate(const CFX_PTemplate<BaseType>& point1,
    162                 const CFX_PTemplate<BaseType>& point2)
    163       : CFX_PTemplate<BaseType>(point2.x - point1.x, point2.y - point1.y) {}
    164 
    165   FX_FLOAT Length() const { return FXSYS_sqrt(x * x + y * y); }
    166   void Normalize() {
    167     FX_FLOAT fLen = Length();
    168     if (fLen < 0.0001f)
    169       return;
    170 
    171     x /= fLen;
    172     y /= fLen;
    173   }
    174   void Translate(BaseType dx, BaseType dy) {
    175     x += dx;
    176     y += dy;
    177   }
    178   void Scale(BaseType sx, BaseType sy) {
    179     x *= sx;
    180     y *= sy;
    181   }
    182   void Rotate(FX_FLOAT fRadian) {
    183     FX_FLOAT cosValue = FXSYS_cos(fRadian);
    184     FX_FLOAT sinValue = FXSYS_sin(fRadian);
    185     x = x * cosValue - y * sinValue;
    186     y = x * sinValue + y * cosValue;
    187   }
    188 };
    189 using CFX_Vector = CFX_VTemplate<int32_t>;
    190 using CFX_VectorF = CFX_VTemplate<FX_FLOAT>;
    191 
    192 // Rectangles.
    193 // TODO(tsepez): Consolidate all these different rectangle classes.
    194 
    195 // LTWH rectangles (y-axis runs downwards).
    196 template <class BaseType>
    197 class CFX_RTemplate {
    198  public:
    199   using PointType = CFX_PTemplate<BaseType>;
    200   using SizeType = CFX_STemplate<BaseType>;
    201   using VectorType = CFX_VTemplate<BaseType>;
    202   using RectType = CFX_RTemplate<BaseType>;
    203 
    204   CFX_RTemplate() : left(0), top(0), width(0), height(0) {}
    205   CFX_RTemplate(BaseType dst_left,
    206                 BaseType dst_top,
    207                 BaseType dst_width,
    208                 BaseType dst_height)
    209       : left(dst_left), top(dst_top), width(dst_width), height(dst_height) {}
    210   CFX_RTemplate(BaseType dst_left, BaseType dst_top, const SizeType& dst_size)
    211       : left(dst_left),
    212         top(dst_top),
    213         width(dst_size.width),
    214         height(dst_size.height) {}
    215   CFX_RTemplate(const PointType& p, BaseType dst_width, BaseType dst_height)
    216       : left(p.x), top(p.y), width(dst_width), height(dst_height) {}
    217   CFX_RTemplate(const PointType& p1, const SizeType& s2)
    218       : left(p1.x), top(p1.y), width(s2.width), height(s2.height) {}
    219   CFX_RTemplate(const PointType& p1, const PointType& p2)
    220       : left(p1.x),
    221         top(p1.y),
    222         width(p2.width - p1.width),
    223         height(p2.height - p1.height) {
    224     Normalize();
    225   }
    226   CFX_RTemplate(const PointType& p, const VectorType& v)
    227       : left(p.x), top(p.y), width(v.x), height(v.y) {
    228     Normalize();
    229   }
    230 
    231   // NOLINTNEXTLINE(runtime/explicit)
    232   CFX_RTemplate(const RectType& other)
    233       : left(other.left),
    234         top(other.top),
    235         width(other.width),
    236         height(other.height) {}
    237 
    238   template <typename OtherType>
    239   CFX_RTemplate<OtherType> As() const {
    240     return CFX_RTemplate<OtherType>(
    241         static_cast<OtherType>(left), static_cast<OtherType>(top),
    242         static_cast<OtherType>(width), static_cast<OtherType>(height));
    243   }
    244 
    245   void Reset() {
    246     left = 0;
    247     top = 0;
    248     width = 0;
    249     height = 0;
    250   }
    251   RectType& operator+=(const PointType& p) {
    252     left += p.x;
    253     top += p.y;
    254     return *this;
    255   }
    256   RectType& operator-=(const PointType& p) {
    257     left -= p.x;
    258     top -= p.y;
    259     return *this;
    260   }
    261   BaseType right() const { return left + width; }
    262   BaseType bottom() const { return top + height; }
    263   void Normalize() {
    264     if (width < 0) {
    265       left += width;
    266       width = -width;
    267     }
    268     if (height < 0) {
    269       top += height;
    270       height = -height;
    271     }
    272   }
    273   void Offset(BaseType dx, BaseType dy) {
    274     left += dx;
    275     top += dy;
    276   }
    277   void Inflate(BaseType x, BaseType y) {
    278     left -= x;
    279     width += x * 2;
    280     top -= y;
    281     height += y * 2;
    282   }
    283   void Inflate(const PointType& p) { Inflate(p.x, p.y); }
    284   void Inflate(BaseType off_left,
    285                BaseType off_top,
    286                BaseType off_right,
    287                BaseType off_bottom) {
    288     left -= off_left;
    289     top -= off_top;
    290     width += off_left + off_right;
    291     height += off_top + off_bottom;
    292   }
    293   void Inflate(const RectType& rt) {
    294     Inflate(rt.left, rt.top, rt.left + rt.width, rt.top + rt.height);
    295   }
    296   void Deflate(BaseType x, BaseType y) {
    297     left += x;
    298     width -= x * 2;
    299     top += y;
    300     height -= y * 2;
    301   }
    302   void Deflate(const PointType& p) { Deflate(p.x, p.y); }
    303   void Deflate(BaseType off_left,
    304                BaseType off_top,
    305                BaseType off_right,
    306                BaseType off_bottom) {
    307     left += off_left;
    308     top += off_top;
    309     width -= off_left + off_right;
    310     height -= off_top + off_bottom;
    311   }
    312   void Deflate(const RectType& rt) {
    313     Deflate(rt.left, rt.top, rt.top + rt.width, rt.top + rt.height);
    314   }
    315   bool IsEmpty() const { return width <= 0 || height <= 0; }
    316   bool IsEmpty(FX_FLOAT fEpsilon) const {
    317     return width <= fEpsilon || height <= fEpsilon;
    318   }
    319   void Empty() { width = height = 0; }
    320   bool Contains(const PointType& p) const {
    321     return p.x >= left && p.x < left + width && p.y >= top &&
    322            p.y < top + height;
    323   }
    324   bool Contains(const RectType& rt) const {
    325     return rt.left >= left && rt.right() <= right() && rt.top >= top &&
    326            rt.bottom() <= bottom();
    327   }
    328   BaseType Width() const { return width; }
    329   BaseType Height() const { return height; }
    330   SizeType Size() const { return SizeType(width, height); }
    331   PointType TopLeft() const { return PointType(left, top); }
    332   PointType TopRight() const { return PointType(left + width, top); }
    333   PointType BottomLeft() const { return PointType(left, top + height); }
    334   PointType BottomRight() const {
    335     return PointType(left + width, top + height);
    336   }
    337   PointType Center() const {
    338     return PointType(left + width / 2, top + height / 2);
    339   }
    340   void Union(BaseType x, BaseType y) {
    341     BaseType r = right();
    342     BaseType b = bottom();
    343     if (left > x)
    344       left = x;
    345     if (r < x)
    346       r = x;
    347     if (top > y)
    348       top = y;
    349     if (b < y)
    350       b = y;
    351     width = r - left;
    352     height = b - top;
    353   }
    354   void Union(const PointType& p) { Union(p.x, p.y); }
    355   void Union(const RectType& rt) {
    356     BaseType r = right();
    357     BaseType b = bottom();
    358     if (left > rt.left)
    359       left = rt.left;
    360     if (r < rt.right())
    361       r = rt.right();
    362     if (top > rt.top)
    363       top = rt.top;
    364     if (b < rt.bottom())
    365       b = rt.bottom();
    366     width = r - left;
    367     height = b - top;
    368   }
    369   void Intersect(const RectType& rt) {
    370     BaseType r = right();
    371     BaseType b = bottom();
    372     if (left < rt.left)
    373       left = rt.left;
    374     if (r > rt.right())
    375       r = rt.right();
    376     if (top < rt.top)
    377       top = rt.top;
    378     if (b > rt.bottom())
    379       b = rt.bottom();
    380     width = r - left;
    381     height = b - top;
    382   }
    383   bool IntersectWith(const RectType& rt) const {
    384     RectType rect = rt;
    385     rect.Intersect(*this);
    386     return !rect.IsEmpty();
    387   }
    388   bool IntersectWith(const RectType& rt, FX_FLOAT fEpsilon) const {
    389     RectType rect = rt;
    390     rect.Intersect(*this);
    391     return !rect.IsEmpty(fEpsilon);
    392   }
    393   friend bool operator==(const RectType& rc1, const RectType& rc2) {
    394     return rc1.left == rc2.left && rc1.top == rc2.top &&
    395            rc1.width == rc2.width && rc1.height == rc2.height;
    396   }
    397   friend bool operator!=(const RectType& rc1, const RectType& rc2) {
    398     return !(rc1 == rc2);
    399   }
    400 
    401   BaseType left;
    402   BaseType top;
    403   BaseType width;
    404   BaseType height;
    405 };
    406 using CFX_Rect = CFX_RTemplate<int32_t>;
    407 using CFX_RectF = CFX_RTemplate<FX_FLOAT>;
    408 
    409 // LTRB rectangles (y-axis runs downwards).
    410 struct FX_RECT {
    411   FX_RECT() : left(0), top(0), right(0), bottom(0) {}
    412   FX_RECT(int l, int t, int r, int b) : left(l), top(t), right(r), bottom(b) {}
    413 
    414   int Width() const { return right - left; }
    415   int Height() const { return bottom - top; }
    416   bool IsEmpty() const { return right <= left || bottom <= top; }
    417 
    418   bool Valid() const {
    419     pdfium::base::CheckedNumeric<int> w = right;
    420     pdfium::base::CheckedNumeric<int> h = bottom;
    421     w -= left;
    422     h -= top;
    423     return w.IsValid() && h.IsValid();
    424   }
    425 
    426   void Normalize();
    427 
    428   void Intersect(const FX_RECT& src);
    429   void Intersect(int l, int t, int r, int b) { Intersect(FX_RECT(l, t, r, b)); }
    430 
    431   void Offset(int dx, int dy) {
    432     left += dx;
    433     right += dx;
    434     top += dy;
    435     bottom += dy;
    436   }
    437 
    438   bool operator==(const FX_RECT& src) const {
    439     return left == src.left && right == src.right && top == src.top &&
    440            bottom == src.bottom;
    441   }
    442 
    443   bool Contains(int x, int y) const {
    444     return x >= left && x < right && y >= top && y < bottom;
    445   }
    446 
    447   int32_t left;
    448   int32_t top;
    449   int32_t right;
    450   int32_t bottom;
    451 };
    452 
    453 // LTRB rectangles (y-axis runs upwards).
    454 class CFX_FloatRect {
    455  public:
    456   CFX_FloatRect() : CFX_FloatRect(0.0f, 0.0f, 0.0f, 0.0f) {}
    457   CFX_FloatRect(FX_FLOAT l, FX_FLOAT b, FX_FLOAT r, FX_FLOAT t)
    458       : left(l), bottom(b), right(r), top(t) {}
    459 
    460   explicit CFX_FloatRect(const FX_FLOAT* pArray)
    461       : CFX_FloatRect(pArray[0], pArray[1], pArray[2], pArray[3]) {}
    462 
    463   explicit CFX_FloatRect(const FX_RECT& rect);
    464 
    465   void Normalize();
    466 
    467   void Reset() {
    468     left = 0.0f;
    469     right = 0.0f;
    470     bottom = 0.0f;
    471     top = 0.0f;
    472   }
    473 
    474   bool IsEmpty() const { return left >= right || bottom >= top; }
    475 
    476   bool Contains(const CFX_PointF& point) const;
    477   bool Contains(const CFX_FloatRect& other_rect) const;
    478 
    479   void Intersect(const CFX_FloatRect& other_rect);
    480   void Union(const CFX_FloatRect& other_rect);
    481 
    482   FX_RECT GetInnerRect() const;
    483   FX_RECT GetOuterRect() const;
    484   FX_RECT GetClosestRect() const;
    485 
    486   int Substract4(CFX_FloatRect& substract_rect, CFX_FloatRect* pRects);
    487 
    488   void InitRect(FX_FLOAT x, FX_FLOAT y) {
    489     left = x;
    490     right = x;
    491     bottom = y;
    492     top = y;
    493   }
    494   void UpdateRect(FX_FLOAT x, FX_FLOAT y);
    495 
    496   FX_FLOAT Width() const { return right - left; }
    497   FX_FLOAT Height() const { return top - bottom; }
    498 
    499   void Inflate(FX_FLOAT x, FX_FLOAT y) {
    500     Normalize();
    501     left -= x;
    502     right += x;
    503     bottom -= y;
    504     top += y;
    505   }
    506 
    507   void Inflate(FX_FLOAT other_left,
    508                FX_FLOAT other_bottom,
    509                FX_FLOAT other_right,
    510                FX_FLOAT other_top) {
    511     Normalize();
    512     left -= other_left;
    513     bottom -= other_bottom;
    514     right += other_right;
    515     top += other_top;
    516   }
    517 
    518   void Inflate(const CFX_FloatRect& rt) {
    519     Inflate(rt.left, rt.bottom, rt.right, rt.top);
    520   }
    521 
    522   void Deflate(FX_FLOAT x, FX_FLOAT y) {
    523     Normalize();
    524     left += x;
    525     right -= x;
    526     bottom += y;
    527     top -= y;
    528   }
    529 
    530   void Deflate(FX_FLOAT other_left,
    531                FX_FLOAT other_bottom,
    532                FX_FLOAT other_right,
    533                FX_FLOAT other_top) {
    534     Normalize();
    535     left += other_left;
    536     bottom += other_bottom;
    537     right -= other_right;
    538     top -= other_top;
    539   }
    540 
    541   void Deflate(const CFX_FloatRect& rt) {
    542     Deflate(rt.left, rt.bottom, rt.right, rt.top);
    543   }
    544 
    545   void Translate(FX_FLOAT e, FX_FLOAT f) {
    546     left += e;
    547     right += e;
    548     top += f;
    549     bottom += f;
    550   }
    551 
    552   static CFX_FloatRect GetBBox(const CFX_PointF* pPoints, int nPoints);
    553 
    554   FX_RECT ToFxRect() const {
    555     return FX_RECT(static_cast<int32_t>(left), static_cast<int32_t>(top),
    556                    static_cast<int32_t>(right), static_cast<int32_t>(bottom));
    557   }
    558 
    559   static CFX_FloatRect FromCFXRectF(const CFX_RectF& rect) {
    560     return CFX_FloatRect(rect.left, rect.top, rect.right(), rect.bottom());
    561   }
    562 
    563   FX_FLOAT left;
    564   FX_FLOAT bottom;
    565   FX_FLOAT right;
    566   FX_FLOAT top;
    567 };
    568 
    569 class CFX_Matrix {
    570  public:
    571   CFX_Matrix() { SetIdentity(); }
    572 
    573   explicit CFX_Matrix(const FX_FLOAT n[6])
    574       : a(n[0]), b(n[1]), c(n[2]), d(n[3]), e(n[4]), f(n[5]) {}
    575 
    576   CFX_Matrix(const CFX_Matrix& other)
    577       : a(other.a),
    578         b(other.b),
    579         c(other.c),
    580         d(other.d),
    581         e(other.e),
    582         f(other.f) {}
    583 
    584   CFX_Matrix(FX_FLOAT a1,
    585              FX_FLOAT b1,
    586              FX_FLOAT c1,
    587              FX_FLOAT d1,
    588              FX_FLOAT e1,
    589              FX_FLOAT f1)
    590       : a(a1), b(b1), c(c1), d(d1), e(e1), f(f1) {}
    591 
    592   void operator=(const CFX_Matrix& other) {
    593     a = other.a;
    594     b = other.b;
    595     c = other.c;
    596     d = other.d;
    597     e = other.e;
    598     f = other.f;
    599   }
    600 
    601   void SetIdentity() {
    602     a = 1;
    603     b = 0;
    604     c = 0;
    605     d = 1;
    606     e = 0;
    607     f = 0;
    608   }
    609 
    610   void SetReverse(const CFX_Matrix& m);
    611 
    612   void Concat(const CFX_Matrix& m, bool bPrepended = false);
    613   void ConcatInverse(const CFX_Matrix& m, bool bPrepended = false);
    614 
    615   bool IsIdentity() const {
    616     return a == 1 && b == 0 && c == 0 && d == 1 && e == 0 && f == 0;
    617   }
    618 
    619   bool Is90Rotated() const;
    620   bool IsScaled() const;
    621   bool WillScale() const { return a != 1.0f || b != 0 || c != 0 || d != 1.0f; }
    622 
    623   void Translate(FX_FLOAT x, FX_FLOAT y, bool bPrepended = false);
    624   void Translate(int32_t x, int32_t y, bool bPrepended = false) {
    625     Translate(static_cast<FX_FLOAT>(x), static_cast<FX_FLOAT>(y), bPrepended);
    626   }
    627 
    628   void Scale(FX_FLOAT sx, FX_FLOAT sy, bool bPrepended = false);
    629   void Rotate(FX_FLOAT fRadian, bool bPrepended = false);
    630   void RotateAt(FX_FLOAT fRadian,
    631                 FX_FLOAT x,
    632                 FX_FLOAT y,
    633                 bool bPrepended = false);
    634 
    635   void Shear(FX_FLOAT fAlphaRadian,
    636              FX_FLOAT fBetaRadian,
    637              bool bPrepended = false);
    638 
    639   void MatchRect(const CFX_FloatRect& dest, const CFX_FloatRect& src);
    640 
    641   FX_FLOAT GetXUnit() const;
    642   FX_FLOAT GetYUnit() const;
    643   CFX_FloatRect GetUnitRect() const;
    644 
    645   FX_FLOAT TransformXDistance(FX_FLOAT dx) const;
    646   FX_FLOAT TransformDistance(FX_FLOAT dx, FX_FLOAT dy) const;
    647   FX_FLOAT TransformDistance(FX_FLOAT distance) const;
    648 
    649   CFX_PointF Transform(const CFX_PointF& point) const;
    650 
    651   void TransformRect(CFX_RectF& rect) const;
    652   void TransformRect(FX_FLOAT& left,
    653                      FX_FLOAT& right,
    654                      FX_FLOAT& top,
    655                      FX_FLOAT& bottom) const;
    656   void TransformRect(CFX_FloatRect& rect) const {
    657     TransformRect(rect.left, rect.right, rect.top, rect.bottom);
    658   }
    659 
    660   FX_FLOAT a;
    661   FX_FLOAT b;
    662   FX_FLOAT c;
    663   FX_FLOAT d;
    664   FX_FLOAT e;
    665   FX_FLOAT f;
    666 
    667  private:
    668   void ConcatInternal(const CFX_Matrix& other, bool prepend);
    669 };
    670 
    671 #endif  // CORE_FXCRT_FX_COORDINATES_H_
    672