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