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