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