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