• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "third_party/base/numerics/safe_math.h"
14 
15 #ifndef NDEBUG
16 #include <ostream>
17 #endif
18 
19 template <class BaseType>
20 class CFX_PTemplate {
21  public:
CFX_PTemplate()22   CFX_PTemplate() : x(0), y(0) {}
CFX_PTemplate(BaseType new_x,BaseType new_y)23   CFX_PTemplate(BaseType new_x, BaseType new_y) : x(new_x), y(new_y) {}
CFX_PTemplate(const CFX_PTemplate & other)24   CFX_PTemplate(const CFX_PTemplate& other) : x(other.x), y(other.y) {}
25 
26   CFX_PTemplate& operator=(const CFX_PTemplate& other) {
27     if (this != &other) {
28       x = other.x;
29       y = other.y;
30     }
31     return *this;
32   }
33   bool operator==(const CFX_PTemplate& other) const {
34     return x == other.x && y == other.y;
35   }
36   bool operator!=(const CFX_PTemplate& other) const {
37     return !(*this == other);
38   }
39   CFX_PTemplate& operator+=(const CFX_PTemplate<BaseType>& obj) {
40     x += obj.x;
41     y += obj.y;
42     return *this;
43   }
44   CFX_PTemplate& operator-=(const CFX_PTemplate<BaseType>& obj) {
45     x -= obj.x;
46     y -= obj.y;
47     return *this;
48   }
49   CFX_PTemplate operator+(const CFX_PTemplate& other) const {
50     return CFX_PTemplate(x + other.x, y + other.y);
51   }
52   CFX_PTemplate operator-(const CFX_PTemplate& other) const {
53     return CFX_PTemplate(x - other.x, y - other.y);
54   }
55 
56   BaseType x;
57   BaseType y;
58 };
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 
ValidFX_RECT191   bool Valid() const {
192     pdfium::base::CheckedNumeric<int> w = right;
193     pdfium::base::CheckedNumeric<int> h = bottom;
194     w -= left;
195     h -= top;
196     return w.IsValid() && h.IsValid();
197   }
198 
199   void Normalize();
200   void Intersect(const FX_RECT& src);
IntersectFX_RECT201   void Intersect(int l, int t, int r, int b) { Intersect(FX_RECT(l, t, r, b)); }
202 
OffsetFX_RECT203   void Offset(int dx, int dy) {
204     left += dx;
205     right += dx;
206     top += dy;
207     bottom += dy;
208   }
209 
210   bool operator==(const FX_RECT& src) const {
211     return left == src.left && right == src.right && top == src.top &&
212            bottom == src.bottom;
213   }
214 
ContainsFX_RECT215   bool Contains(int x, int y) const {
216     return x >= left && x < right && y >= top && y < bottom;
217   }
218 
219   int32_t left = 0;
220   int32_t top = 0;
221   int32_t right = 0;
222   int32_t bottom = 0;
223 };
224 
225 // LTRB rectangles (y-axis runs upwards).
226 class CFX_FloatRect {
227  public:
228   constexpr CFX_FloatRect() = default;
CFX_FloatRect(float l,float b,float r,float t)229   constexpr CFX_FloatRect(float l, float b, float r, float t)
230       : left(l), bottom(b), right(r), top(t) {}
231 
CFX_FloatRect(const float * pArray)232   explicit CFX_FloatRect(const float* pArray)
233       : CFX_FloatRect(pArray[0], pArray[1], pArray[2], pArray[3]) {}
234 
235   explicit CFX_FloatRect(const FX_RECT& rect);
236 
237   static CFX_FloatRect GetBBox(const CFX_PointF* pPoints, int nPoints);
238 
239   void Normalize();
240 
IsEmpty()241   bool IsEmpty() const { return left >= right || bottom >= top; }
242   bool Contains(const CFX_PointF& point) const;
243   bool Contains(const CFX_FloatRect& other_rect) const;
244 
245   void Intersect(const CFX_FloatRect& other_rect);
246   void Union(const CFX_FloatRect& other_rect);
247 
248   // These may be better at rounding than ToFxRect() and friends.
249   //
250   // Returned rect has bounds rounded up/down such that it is contained in the
251   // original.
252   FX_RECT GetInnerRect() const;
253 
254   // Returned rect has bounds rounded up/down such that the original is
255   // contained in it.
256   FX_RECT GetOuterRect() const;
257 
258   // Returned rect has bounds rounded up/down such that the dimensions are
259   // rounded up and the sum of the error in the bounds is minimized.
260   FX_RECT GetClosestRect() const;
261 
262   CFX_FloatRect GetCenterSquare() const;
263 
InitRect(const CFX_PointF & point)264   void InitRect(const CFX_PointF& point) {
265     left = point.x;
266     right = point.x;
267     bottom = point.y;
268     top = point.y;
269   }
270   void UpdateRect(const CFX_PointF& point);
271 
Width()272   float Width() const { return right - left; }
Height()273   float Height() const { return top - bottom; }
Left()274   float Left() const { return left; }
Bottom()275   float Bottom() const { return bottom; }
Right()276   float Right() const { return right; }
Top()277   float Top() const { return top; }
278 
279   void Inflate(float x, float y);
280   void Inflate(float other_left,
281                float other_bottom,
282                float other_right,
283                float other_top);
284   void Inflate(const CFX_FloatRect& rt);
285 
286   void Deflate(float x, float y);
287   void Deflate(float other_left,
288                float other_bottom,
289                float other_right,
290                float other_top);
291   void Deflate(const CFX_FloatRect& rt);
292 
293   CFX_FloatRect GetDeflated(float x, float y) const;
294 
295   void Translate(float e, float f);
296 
297   void Scale(float fScale);
298   void ScaleFromCenterPoint(float fScale);
299 
300   // GetInnerRect() and friends may be better at rounding than these methods.
301   // Unlike the methods above, these two blindly floor / round the LBRT values.
302   // Doing so may introduce rounding errors that are visible to users as
303   // off-by-one pixels/lines.
304   //
305   // Floors LBRT values.
306   FX_RECT ToFxRect() const;
307 
308   // Rounds LBRT values.
309   FX_RECT ToRoundedFxRect() const;
310 
311   float left = 0.0f;
312   float bottom = 0.0f;
313   float right = 0.0f;
314   float top = 0.0f;
315 };
316 
317 #ifndef NDEBUG
318 std::ostream& operator<<(std::ostream& os, const CFX_FloatRect& rect);
319 #endif
320 
321 // LTWH rectangles (y-axis runs downwards).
322 class CFX_RectF {
323  public:
324   using PointType = CFX_PointF;
325   using SizeType = CFX_SizeF;
326 
327   CFX_RectF() = default;
CFX_RectF(float dst_left,float dst_top,float dst_width,float dst_height)328   CFX_RectF(float dst_left, float dst_top, float dst_width, float dst_height)
329       : left(dst_left), top(dst_top), width(dst_width), height(dst_height) {}
CFX_RectF(float dst_left,float dst_top,const SizeType & dst_size)330   CFX_RectF(float dst_left, float dst_top, const SizeType& dst_size)
331       : left(dst_left),
332         top(dst_top),
333         width(dst_size.width),
334         height(dst_size.height) {}
CFX_RectF(const PointType & p,float dst_width,float dst_height)335   CFX_RectF(const PointType& p, float dst_width, float dst_height)
336       : left(p.x), top(p.y), width(dst_width), height(dst_height) {}
CFX_RectF(const PointType & p1,const SizeType & s2)337   CFX_RectF(const PointType& p1, const SizeType& s2)
338       : left(p1.x), top(p1.y), width(s2.width), height(s2.height) {}
CFX_RectF(const FX_RECT & that)339   explicit CFX_RectF(const FX_RECT& that)
340       : left(static_cast<float>(that.left)),
341         top(static_cast<float>(that.top)),
342         width(static_cast<float>(that.Width())),
343         height(static_cast<float>(that.Height())) {}
344 
345   // NOLINTNEXTLINE(runtime/explicit)
346   CFX_RectF(const CFX_RectF& other) = default;
347 
348   CFX_RectF& operator+=(const PointType& p) {
349     left += p.x;
350     top += p.y;
351     return *this;
352   }
353   CFX_RectF& operator-=(const PointType& p) {
354     left -= p.x;
355     top -= p.y;
356     return *this;
357   }
right()358   float right() const { return left + width; }
bottom()359   float bottom() const { return top + height; }
Normalize()360   void Normalize() {
361     if (width < 0) {
362       left += width;
363       width = -width;
364     }
365     if (height < 0) {
366       top += height;
367       height = -height;
368     }
369   }
Offset(float dx,float dy)370   void Offset(float dx, float dy) {
371     left += dx;
372     top += dy;
373   }
Inflate(float x,float y)374   void Inflate(float x, float y) {
375     left -= x;
376     width += x * 2;
377     top -= y;
378     height += y * 2;
379   }
Inflate(const PointType & p)380   void Inflate(const PointType& p) { Inflate(p.x, p.y); }
Inflate(float off_left,float off_top,float off_right,float off_bottom)381   void Inflate(float off_left,
382                float off_top,
383                float off_right,
384                float off_bottom) {
385     left -= off_left;
386     top -= off_top;
387     width += off_left + off_right;
388     height += off_top + off_bottom;
389   }
Inflate(const CFX_RectF & rt)390   void Inflate(const CFX_RectF& rt) {
391     Inflate(rt.left, rt.top, rt.left + rt.width, rt.top + rt.height);
392   }
Deflate(float x,float y)393   void Deflate(float x, float y) {
394     left += x;
395     width -= x * 2;
396     top += y;
397     height -= y * 2;
398   }
Deflate(const PointType & p)399   void Deflate(const PointType& p) { Deflate(p.x, p.y); }
Deflate(float off_left,float off_top,float off_right,float off_bottom)400   void Deflate(float off_left,
401                float off_top,
402                float off_right,
403                float off_bottom) {
404     left += off_left;
405     top += off_top;
406     width -= off_left + off_right;
407     height -= off_top + off_bottom;
408   }
Deflate(const CFX_RectF & rt)409   void Deflate(const CFX_RectF& rt) {
410     Deflate(rt.left, rt.top, rt.top + rt.width, rt.top + rt.height);
411   }
IsEmpty()412   bool IsEmpty() const { return width <= 0 || height <= 0; }
IsEmpty(float fEpsilon)413   bool IsEmpty(float fEpsilon) const {
414     return width <= fEpsilon || height <= fEpsilon;
415   }
Empty()416   void Empty() { width = height = 0; }
Contains(const PointType & p)417   bool Contains(const PointType& p) const {
418     return p.x >= left && p.x < left + width && p.y >= top &&
419            p.y < top + height;
420   }
Contains(const CFX_RectF & rt)421   bool Contains(const CFX_RectF& rt) const {
422     return rt.left >= left && rt.right() <= right() && rt.top >= top &&
423            rt.bottom() <= bottom();
424   }
Left()425   float Left() const { return left; }
Top()426   float Top() const { return top; }
Width()427   float Width() const { return width; }
Height()428   float Height() const { return height; }
Size()429   SizeType Size() const { return SizeType(width, height); }
TopLeft()430   PointType TopLeft() const { return PointType(left, top); }
TopRight()431   PointType TopRight() const { return PointType(left + width, top); }
BottomLeft()432   PointType BottomLeft() const { return PointType(left, top + height); }
BottomRight()433   PointType BottomRight() const {
434     return PointType(left + width, top + height);
435   }
Center()436   PointType Center() const {
437     return PointType(left + width / 2, top + height / 2);
438   }
Union(float x,float y)439   void Union(float x, float y) {
440     float r = right();
441     float b = bottom();
442 
443     left = std::min(left, x);
444     top = std::min(top, y);
445     r = std::max(r, x);
446     b = std::max(b, y);
447 
448     width = r - left;
449     height = b - top;
450   }
Union(const PointType & p)451   void Union(const PointType& p) { Union(p.x, p.y); }
Union(const CFX_RectF & rt)452   void Union(const CFX_RectF& rt) {
453     float r = right();
454     float b = bottom();
455 
456     left = std::min(left, rt.left);
457     top = std::min(top, rt.top);
458     r = std::max(r, rt.right());
459     b = std::max(b, rt.bottom());
460 
461     width = r - left;
462     height = b - top;
463   }
Intersect(const CFX_RectF & rt)464   void Intersect(const CFX_RectF& rt) {
465     float r = right();
466     float b = bottom();
467 
468     left = std::max(left, rt.left);
469     top = std::max(top, rt.top);
470     r = std::min(r, rt.right());
471     b = std::min(b, rt.bottom());
472 
473     width = r - left;
474     height = b - top;
475   }
IntersectWith(const CFX_RectF & rt)476   bool IntersectWith(const CFX_RectF& rt) const {
477     CFX_RectF rect = rt;
478     rect.Intersect(*this);
479     return !rect.IsEmpty();
480   }
IntersectWith(const CFX_RectF & rt,float fEpsilon)481   bool IntersectWith(const CFX_RectF& rt, float fEpsilon) const {
482     CFX_RectF rect = rt;
483     rect.Intersect(*this);
484     return !rect.IsEmpty(fEpsilon);
485   }
486   friend bool operator==(const CFX_RectF& rc1, const CFX_RectF& rc2) {
487     return rc1.left == rc2.left && rc1.top == rc2.top &&
488            rc1.width == rc2.width && rc1.height == rc2.height;
489   }
490   friend bool operator!=(const CFX_RectF& rc1, const CFX_RectF& rc2) {
491     return !(rc1 == rc2);
492   }
493 
ToFloatRect()494   CFX_FloatRect ToFloatRect() const {
495     // Note, we flip top/bottom here because the CFX_FloatRect has the
496     // y-axis running in the opposite direction.
497     return CFX_FloatRect(left, top, right(), bottom());
498   }
499 
500   // Returned rect has bounds rounded up/down such that the original is
501   // contained in it.
502   FX_RECT GetOuterRect() const;
503 
504   float left = 0.0f;
505   float top = 0.0f;
506   float width = 0.0f;
507   float height = 0.0f;
508 };
509 
510 #ifndef NDEBUG
511 std::ostream& operator<<(std::ostream& os, const CFX_RectF& rect);
512 #endif  // NDEBUG
513 
514 // The matrix is of the form:
515 // | a  b  0 |
516 // | c  d  0 |
517 // | e  f  1 |
518 // See PDF spec 1.7 Section 4.2.3.
519 //
520 class CFX_Matrix {
521  public:
522   CFX_Matrix() = default;
523 
CFX_Matrix(const float n[6])524   explicit CFX_Matrix(const float n[6])
525       : a(n[0]), b(n[1]), c(n[2]), d(n[3]), e(n[4]), f(n[5]) {}
526 
CFX_Matrix(float a1,float b1,float c1,float d1,float e1,float f1)527   CFX_Matrix(float a1, float b1, float c1, float d1, float e1, float f1)
528       : a(a1), b(b1), c(c1), d(d1), e(e1), f(f1) {}
529 
530   CFX_Matrix(const CFX_Matrix& other) = default;
531 
532   CFX_Matrix& operator=(const CFX_Matrix& other) = default;
533 
534   bool operator==(const CFX_Matrix& other) const {
535     return a == other.a && b == other.b && c == other.c && d == other.d &&
536            e == other.e && f == other.f;
537   }
538   bool operator!=(const CFX_Matrix& other) const { return !(*this == other); }
539 
540   CFX_Matrix operator*(const CFX_Matrix& right) const {
541     return CFX_Matrix(a * right.a + b * right.c, a * right.b + b * right.d,
542                       c * right.a + d * right.c, c * right.b + d * right.d,
543                       e * right.a + f * right.c + right.e,
544                       e * right.b + f * right.d + right.f);
545   }
546   CFX_Matrix& operator*=(const CFX_Matrix& other) {
547     *this = *this * other;
548     return *this;
549   }
550 
IsIdentity()551   bool IsIdentity() const { return *this == CFX_Matrix(); }
552   CFX_Matrix GetInverse() const;
553 
554   bool Is90Rotated() const;
555   bool IsScaled() const;
WillScale()556   bool WillScale() const { return a != 1.0f || b != 0 || c != 0 || d != 1.0f; }
557 
Concat(const CFX_Matrix & right)558   void Concat(const CFX_Matrix& right) { *this *= right; }
559   void Translate(float x, float y);
560   void TranslatePrepend(float x, float y);
Translate(int32_t x,int32_t y)561   void Translate(int32_t x, int32_t y) {
562     Translate(static_cast<float>(x), static_cast<float>(y));
563   }
TranslatePrepend(int32_t x,int32_t y)564   void TranslatePrepend(int32_t x, int32_t y) {
565     TranslatePrepend(static_cast<float>(x), static_cast<float>(y));
566   }
567 
568   void Scale(float sx, float sy);
569   void Rotate(float fRadian);
570 
571   void MatchRect(const CFX_FloatRect& dest, const CFX_FloatRect& src);
572 
573   float GetXUnit() const;
574   float GetYUnit() const;
575   CFX_FloatRect GetUnitRect() const;
576 
577   float TransformXDistance(float dx) const;
578   float TransformDistance(float distance) const;
579 
580   CFX_PointF Transform(const CFX_PointF& point) const;
581 
582   CFX_RectF TransformRect(const CFX_RectF& rect) const;
583   CFX_FloatRect TransformRect(const CFX_FloatRect& rect) const;
584 
585   float a = 1.0f;
586   float b = 0.0f;
587   float c = 0.0f;
588   float d = 1.0f;
589   float e = 0.0f;
590   float f = 0.0f;
591 };
592 
593 #endif  // CORE_FXCRT_FX_COORDINATES_H_
594