• 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 #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:
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_Point = CFX_PTemplate<int32_t>;
59 using CFX_PointF = CFX_PTemplate<float>;
60 
61 template <class BaseType>
62 class CFX_STemplate {
63  public:
CFX_STemplate()64   CFX_STemplate() : width(0), height(0) {}
65 
CFX_STemplate(BaseType new_width,BaseType new_height)66   CFX_STemplate(BaseType new_width, BaseType new_height)
67       : width(new_width), height(new_height) {}
68 
CFX_STemplate(const CFX_STemplate & other)69   CFX_STemplate(const CFX_STemplate& other)
70       : width(other.width), height(other.height) {}
71 
72   template <typename OtherType>
As()73   CFX_STemplate<OtherType> As() const {
74     return CFX_STemplate<OtherType>(static_cast<OtherType>(width),
75                                     static_cast<OtherType>(height));
76   }
77 
clear()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 
CFX_VTemplate()140   CFX_VTemplate() : CFX_PTemplate<BaseType>() {}
CFX_VTemplate(BaseType new_x,BaseType new_y)141   CFX_VTemplate(BaseType new_x, BaseType new_y)
142       : CFX_PTemplate<BaseType>(new_x, new_y) {}
143 
CFX_VTemplate(const CFX_VTemplate & other)144   CFX_VTemplate(const CFX_VTemplate& other) : CFX_PTemplate<BaseType>(other) {}
145 
CFX_VTemplate(const CFX_PTemplate<BaseType> & point1,const CFX_PTemplate<BaseType> & point2)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 
Length()150   float Length() const { return sqrt(x * x + y * y); }
Normalize()151   void Normalize() {
152     float fLen = Length();
153     if (fLen < 0.0001f)
154       return;
155 
156     x /= fLen;
157     y /= fLen;
158   }
Translate(BaseType dx,BaseType dy)159   void Translate(BaseType dx, BaseType dy) {
160     x += dx;
161     y += dy;
162   }
Scale(BaseType sx,BaseType sy)163   void Scale(BaseType sx, BaseType sy) {
164     x *= sx;
165     y *= sy;
166   }
Rotate(float fRadian)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 {
FX_RECTFX_RECT182   FX_RECT() : left(0), top(0), right(0), bottom(0) {}
FX_RECTFX_RECT183   FX_RECT(int l, int t, int r, int b) : left(l), top(t), right(r), bottom(b) {}
184 
WidthFX_RECT185   int Width() const { return right - left; }
HeightFX_RECT186   int Height() const { return bottom - top; }
IsEmptyFX_RECT187   bool IsEmpty() const { return right <= left || bottom <= top; }
188 
ValidFX_RECT189   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);
IntersectFX_RECT200   void Intersect(int l, int t, int r, int b) { Intersect(FX_RECT(l, t, r, b)); }
201 
OffsetFX_RECT202   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 
ContainsFX_RECT214   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:
CFX_FloatRect()227   CFX_FloatRect() : CFX_FloatRect(0.0f, 0.0f, 0.0f, 0.0f) {}
CFX_FloatRect(float l,float b,float r,float t)228   CFX_FloatRect(float l, float b, float r, float t)
229       : left(l), bottom(b), right(r), top(t) {}
230 
CFX_FloatRect(const float * pArray)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 
IsEmpty()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 
InitRect(const CFX_PointF & point)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 
Width()274   float Width() const { return right - left; }
Height()275   float Height() const { return top - bottom; }
276 
Inflate(float x,float y)277   void Inflate(float x, float y) {
278     Normalize();
279     left -= x;
280     right += x;
281     bottom -= y;
282     top += y;
283   }
284 
Inflate(float other_left,float other_bottom,float other_right,float other_top)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 
Inflate(const CFX_FloatRect & rt)296   void Inflate(const CFX_FloatRect& rt) {
297     Inflate(rt.left, rt.bottom, rt.right, rt.top);
298   }
299 
Deflate(float x,float y)300   void Deflate(float x, float y) {
301     Normalize();
302     left += x;
303     right -= x;
304     bottom += y;
305     top -= y;
306   }
307 
Deflate(float other_left,float other_bottom,float other_right,float other_top)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 
Deflate(const CFX_FloatRect & rt)319   void Deflate(const CFX_FloatRect& rt) {
320     Deflate(rt.left, rt.bottom, rt.right, rt.top);
321   }
322 
GetDeflated(float x,float y)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 
Translate(float e,float f)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 
CFX_RTemplate()373   CFX_RTemplate() : left(0), top(0), width(0), height(0) {}
CFX_RTemplate(BaseType dst_left,BaseType dst_top,BaseType dst_width,BaseType dst_height)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) {}
CFX_RTemplate(BaseType dst_left,BaseType dst_top,const SizeType & dst_size)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) {}
CFX_RTemplate(const PointType & p,BaseType dst_width,BaseType dst_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) {}
CFX_RTemplate(const PointType & p1,const SizeType & s2)386   CFX_RTemplate(const PointType& p1, const SizeType& s2)
387       : left(p1.x), top(p1.y), width(s2.width), height(s2.height) {}
CFX_RTemplate(const PointType & p1,const PointType & p2)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   }
CFX_RTemplate(const PointType & p,const VectorType & v)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 
CFX_RTemplate(const CFX_FloatRect & r)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)
CFX_RTemplate(const RectType & other)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>
As()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 
Reset()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   }
right()436   BaseType right() const { return left + width; }
bottom()437   BaseType bottom() const { return top + height; }
Normalize()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   }
Offset(BaseType dx,BaseType dy)448   void Offset(BaseType dx, BaseType dy) {
449     left += dx;
450     top += dy;
451   }
Inflate(BaseType x,BaseType y)452   void Inflate(BaseType x, BaseType y) {
453     left -= x;
454     width += x * 2;
455     top -= y;
456     height += y * 2;
457   }
Inflate(const PointType & p)458   void Inflate(const PointType& p) { Inflate(p.x, p.y); }
Inflate(BaseType off_left,BaseType off_top,BaseType off_right,BaseType off_bottom)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   }
Inflate(const RectType & rt)468   void Inflate(const RectType& rt) {
469     Inflate(rt.left, rt.top, rt.left + rt.width, rt.top + rt.height);
470   }
Deflate(BaseType x,BaseType y)471   void Deflate(BaseType x, BaseType y) {
472     left += x;
473     width -= x * 2;
474     top += y;
475     height -= y * 2;
476   }
Deflate(const PointType & p)477   void Deflate(const PointType& p) { Deflate(p.x, p.y); }
Deflate(BaseType off_left,BaseType off_top,BaseType off_right,BaseType off_bottom)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   }
Deflate(const RectType & rt)487   void Deflate(const RectType& rt) {
488     Deflate(rt.left, rt.top, rt.top + rt.width, rt.top + rt.height);
489   }
IsEmpty()490   bool IsEmpty() const { return width <= 0 || height <= 0; }
IsEmpty(float fEpsilon)491   bool IsEmpty(float fEpsilon) const {
492     return width <= fEpsilon || height <= fEpsilon;
493   }
Empty()494   void Empty() { width = height = 0; }
Contains(const PointType & p)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   }
Contains(const RectType & rt)499   bool Contains(const RectType& rt) const {
500     return rt.left >= left && rt.right() <= right() && rt.top >= top &&
501            rt.bottom() <= bottom();
502   }
Width()503   BaseType Width() const { return width; }
Height()504   BaseType Height() const { return height; }
Size()505   SizeType Size() const { return SizeType(width, height); }
TopLeft()506   PointType TopLeft() const { return PointType(left, top); }
TopRight()507   PointType TopRight() const { return PointType(left + width, top); }
BottomLeft()508   PointType BottomLeft() const { return PointType(left, top + height); }
BottomRight()509   PointType BottomRight() const {
510     return PointType(left + width, top + height);
511   }
Center()512   PointType Center() const {
513     return PointType(left + width / 2, top + height / 2);
514   }
Union(BaseType x,BaseType y)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   }
Union(const PointType & p)527   void Union(const PointType& p) { Union(p.x, p.y); }
Union(const RectType & rt)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   }
Intersect(const RectType & rt)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   }
IntersectWith(const RectType & rt)552   bool IntersectWith(const RectType& rt) const {
553     RectType rect = rt;
554     rect.Intersect(*this);
555     return !rect.IsEmpty();
556   }
IntersectWith(const RectType & rt,float fEpsilon)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 
ToFloatRect()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:
CFX_Matrix()592   CFX_Matrix() { SetIdentity(); }
593 
CFX_Matrix(const float n[6])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 
CFX_Matrix(float a1,float b1,float c1,float d1,float e1,float f1)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 
SetIdentity()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 
IsIdentity()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;
WillScale()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