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 #include "core/fxcrt/fx_coordinates.h"
8 
9 #include <utility>
10 
11 #include "build/build_config.h"
12 #include "core/fxcrt/fx_extension.h"
13 #include "core/fxcrt/fx_safe_types.h"
14 #include "third_party/base/stl_util.h"
15 
16 namespace {
17 
MatchFloatRange(float f1,float f2,int * i1,int * i2)18 void MatchFloatRange(float f1, float f2, int* i1, int* i2) {
19   float length = ceilf(f2 - f1);
20   float f1_floor = floorf(f1);
21   float f1_ceil = ceilf(f1);
22   float error1 = f1 - f1_floor + fabsf(f2 - f1_floor - length);
23   float error2 = f1_ceil - f1 + fabsf(f2 - f1_ceil - length);
24   float start = error1 > error2 ? f1_ceil : f1_floor;
25   FX_SAFE_INT32 safe1 = start;
26   FX_SAFE_INT32 safe2 = start + length;
27   if (safe1.IsValid() && safe2.IsValid()) {
28     *i1 = safe1.ValueOrDie();
29     *i2 = safe2.ValueOrDie();
30   } else {
31     *i1 = 0;
32     *i2 = 0;
33   }
34 }
35 
36 #if defined(OS_WIN)
37 static_assert(sizeof(FX_RECT) == sizeof(RECT), "FX_RECT vs. RECT mismatch");
38 static_assert(offsetof(FX_RECT, left) == offsetof(RECT, left),
39               "FX_RECT vs. RECT mismatch");
40 static_assert(offsetof(FX_RECT, top) == offsetof(RECT, top),
41               "FX_RECT vs. RECT mismatch");
42 static_assert(offsetof(FX_RECT, right) == offsetof(RECT, right),
43               "FX_RECT vs. RECT mismatch");
44 static_assert(offsetof(FX_RECT, bottom) == offsetof(RECT, bottom),
45               "FX_RECT vs. RECT mismatch");
46 static_assert(sizeof(FX_RECT::left) == sizeof(RECT::left),
47               "FX_RECT vs. RECT mismatch");
48 static_assert(sizeof(FX_RECT::top) == sizeof(RECT::top),
49               "FX_RECT vs. RECT mismatch");
50 static_assert(sizeof(FX_RECT::right) == sizeof(RECT::right),
51               "FX_RECT vs. RECT mismatch");
52 static_assert(sizeof(FX_RECT::bottom) == sizeof(RECT::bottom),
53               "FX_RECT vs. RECT mismatch");
54 #endif
55 
56 }  // namespace
57 
Valid() const58 bool FX_RECT::Valid() const {
59   FX_SAFE_INT32 w = right;
60   FX_SAFE_INT32 h = bottom;
61   w -= left;
62   h -= top;
63   return w.IsValid() && h.IsValid();
64 }
65 
Normalize()66 void FX_RECT::Normalize() {
67   if (left > right)
68     std::swap(left, right);
69   if (top > bottom)
70     std::swap(top, bottom);
71 }
72 
Intersect(const FX_RECT & src)73 void FX_RECT::Intersect(const FX_RECT& src) {
74   FX_RECT src_n = src;
75   src_n.Normalize();
76   Normalize();
77   left = std::max(left, src_n.left);
78   top = std::max(top, src_n.top);
79   right = std::min(right, src_n.right);
80   bottom = std::min(bottom, src_n.bottom);
81   if (left > right || top > bottom) {
82     left = top = right = bottom = 0;
83   }
84 }
85 
86 // Y-axis runs the opposite way in FX_RECT.
CFX_FloatRect(const FX_RECT & rect)87 CFX_FloatRect::CFX_FloatRect(const FX_RECT& rect)
88     : left(rect.left), bottom(rect.top), right(rect.right), top(rect.bottom) {}
89 
90 // static
GetBBox(const CFX_PointF * pPoints,int nPoints)91 CFX_FloatRect CFX_FloatRect::GetBBox(const CFX_PointF* pPoints, int nPoints) {
92   if (nPoints == 0)
93     return CFX_FloatRect();
94 
95   float min_x = pPoints->x;
96   float max_x = pPoints->x;
97   float min_y = pPoints->y;
98   float max_y = pPoints->y;
99   for (int i = 1; i < nPoints; i++) {
100     min_x = std::min(min_x, pPoints[i].x);
101     max_x = std::max(max_x, pPoints[i].x);
102     min_y = std::min(min_y, pPoints[i].y);
103     max_y = std::max(max_y, pPoints[i].y);
104   }
105   return CFX_FloatRect(min_x, min_y, max_x, max_y);
106 }
107 
Normalize()108 void CFX_FloatRect::Normalize() {
109   if (left > right)
110     std::swap(left, right);
111   if (bottom > top)
112     std::swap(top, bottom);
113 }
114 
Intersect(const CFX_FloatRect & other_rect)115 void CFX_FloatRect::Intersect(const CFX_FloatRect& other_rect) {
116   Normalize();
117   CFX_FloatRect other = other_rect;
118   other.Normalize();
119   left = std::max(left, other.left);
120   bottom = std::max(bottom, other.bottom);
121   right = std::min(right, other.right);
122   top = std::min(top, other.top);
123   if (left > right || bottom > top)
124     *this = CFX_FloatRect();
125 }
126 
Union(const CFX_FloatRect & other_rect)127 void CFX_FloatRect::Union(const CFX_FloatRect& other_rect) {
128   Normalize();
129   CFX_FloatRect other = other_rect;
130   other.Normalize();
131   left = std::min(left, other.left);
132   bottom = std::min(bottom, other.bottom);
133   right = std::max(right, other.right);
134   top = std::max(top, other.top);
135 }
136 
GetOuterRect() const137 FX_RECT CFX_FloatRect::GetOuterRect() const {
138   FX_RECT rect;
139   rect.left = pdfium::base::saturated_cast<int>(floor(left));
140   rect.bottom = pdfium::base::saturated_cast<int>(ceil(top));
141   rect.right = pdfium::base::saturated_cast<int>(ceil(right));
142   rect.top = pdfium::base::saturated_cast<int>(floor(bottom));
143   rect.Normalize();
144   return rect;
145 }
146 
GetInnerRect() const147 FX_RECT CFX_FloatRect::GetInnerRect() const {
148   FX_RECT rect;
149   rect.left = pdfium::base::saturated_cast<int>(ceil(left));
150   rect.bottom = pdfium::base::saturated_cast<int>(floor(top));
151   rect.right = pdfium::base::saturated_cast<int>(floor(right));
152   rect.top = pdfium::base::saturated_cast<int>(ceil(bottom));
153   rect.Normalize();
154   return rect;
155 }
156 
GetClosestRect() const157 FX_RECT CFX_FloatRect::GetClosestRect() const {
158   FX_RECT rect;
159   MatchFloatRange(left, right, &rect.left, &rect.right);
160   MatchFloatRange(bottom, top, &rect.top, &rect.bottom);
161   rect.Normalize();
162   return rect;
163 }
164 
GetCenterSquare() const165 CFX_FloatRect CFX_FloatRect::GetCenterSquare() const {
166   float fWidth = Width();
167   float fHeight = Height();
168   float fHalfWidth = (fWidth > fHeight) ? fHeight / 2 : fWidth / 2;
169 
170   float fCenterX = (left + right) / 2.0f;
171   float fCenterY = (top + bottom) / 2.0f;
172   return CFX_FloatRect(fCenterX - fHalfWidth, fCenterY - fHalfWidth,
173                        fCenterX + fHalfWidth, fCenterY + fHalfWidth);
174 }
175 
Contains(const CFX_PointF & point) const176 bool CFX_FloatRect::Contains(const CFX_PointF& point) const {
177   CFX_FloatRect n1(*this);
178   n1.Normalize();
179   return point.x <= n1.right && point.x >= n1.left && point.y <= n1.top &&
180          point.y >= n1.bottom;
181 }
182 
Contains(const CFX_FloatRect & other_rect) const183 bool CFX_FloatRect::Contains(const CFX_FloatRect& other_rect) const {
184   CFX_FloatRect n1(*this);
185   CFX_FloatRect n2(other_rect);
186   n1.Normalize();
187   n2.Normalize();
188   return n2.left >= n1.left && n2.right <= n1.right && n2.bottom >= n1.bottom &&
189          n2.top <= n1.top;
190 }
191 
UpdateRect(const CFX_PointF & point)192 void CFX_FloatRect::UpdateRect(const CFX_PointF& point) {
193   left = std::min(left, point.x);
194   bottom = std::min(bottom, point.y);
195   right = std::max(right, point.x);
196   top = std::max(top, point.y);
197 }
198 
Inflate(float x,float y)199 void CFX_FloatRect::Inflate(float x, float y) {
200   Inflate(x, y, x, y);
201 }
202 
Inflate(float other_left,float other_bottom,float other_right,float other_top)203 void CFX_FloatRect::Inflate(float other_left,
204                             float other_bottom,
205                             float other_right,
206                             float other_top) {
207   Normalize();
208   left -= other_left;
209   bottom -= other_bottom;
210   right += other_right;
211   top += other_top;
212 }
213 
Inflate(const CFX_FloatRect & rt)214 void CFX_FloatRect::Inflate(const CFX_FloatRect& rt) {
215   Inflate(rt.left, rt.bottom, rt.right, rt.top);
216 }
217 
Deflate(float x,float y)218 void CFX_FloatRect::Deflate(float x, float y) {
219   Deflate(x, y, x, y);
220 }
221 
Deflate(float other_left,float other_bottom,float other_right,float other_top)222 void CFX_FloatRect::Deflate(float other_left,
223                             float other_bottom,
224                             float other_right,
225                             float other_top) {
226   Inflate(-other_left, -other_bottom, -other_right, -other_top);
227 }
228 
Deflate(const CFX_FloatRect & rt)229 void CFX_FloatRect::Deflate(const CFX_FloatRect& rt) {
230   Deflate(rt.left, rt.bottom, rt.right, rt.top);
231 }
232 
GetDeflated(float x,float y) const233 CFX_FloatRect CFX_FloatRect::GetDeflated(float x, float y) const {
234   if (IsEmpty())
235     return CFX_FloatRect();
236 
237   CFX_FloatRect that = *this;
238   that.Deflate(x, y);
239   that.Normalize();
240   return that;
241 }
242 
Translate(float e,float f)243 void CFX_FloatRect::Translate(float e, float f) {
244   left += e;
245   right += e;
246   top += f;
247   bottom += f;
248 }
249 
Scale(float fScale)250 void CFX_FloatRect::Scale(float fScale) {
251   left *= fScale;
252   bottom *= fScale;
253   right *= fScale;
254   top *= fScale;
255 }
256 
ScaleFromCenterPoint(float fScale)257 void CFX_FloatRect::ScaleFromCenterPoint(float fScale) {
258   float fHalfWidth = (right - left) / 2.0f;
259   float fHalfHeight = (top - bottom) / 2.0f;
260 
261   float center_x = (left + right) / 2;
262   float center_y = (top + bottom) / 2;
263 
264   left = center_x - fHalfWidth * fScale;
265   bottom = center_y - fHalfHeight * fScale;
266   right = center_x + fHalfWidth * fScale;
267   top = center_y + fHalfHeight * fScale;
268 }
269 
ToFxRect() const270 FX_RECT CFX_FloatRect::ToFxRect() const {
271   return FX_RECT(static_cast<int>(left), static_cast<int>(top),
272                  static_cast<int>(right), static_cast<int>(bottom));
273 }
274 
ToRoundedFxRect() const275 FX_RECT CFX_FloatRect::ToRoundedFxRect() const {
276   return FX_RECT(FXSYS_roundf(left), FXSYS_roundf(top), FXSYS_roundf(right),
277                  FXSYS_roundf(bottom));
278 }
279 
GetOuterRect() const280 FX_RECT CFX_RectF::GetOuterRect() const {
281   return FX_RECT(static_cast<int32_t>(floor(left)),
282                  static_cast<int32_t>(floor(top)),
283                  static_cast<int32_t>(ceil(right())),
284                  static_cast<int32_t>(ceil(bottom())));
285 }
286 
287 #ifndef NDEBUG
operator <<(std::ostream & os,const CFX_FloatRect & rect)288 std::ostream& operator<<(std::ostream& os, const CFX_FloatRect& rect) {
289   os << "rect[w " << rect.Width() << " x h " << rect.Height() << " (left "
290      << rect.left << ", bot " << rect.bottom << ")]";
291   return os;
292 }
293 
operator <<(std::ostream & os,const CFX_RectF & rect)294 std::ostream& operator<<(std::ostream& os, const CFX_RectF& rect) {
295   os << "rect[w " << rect.Width() << " x h " << rect.Height() << " (left "
296      << rect.left << ", top " << rect.top << ")]";
297   return os;
298 }
299 #endif  // NDEBUG
300 
GetInverse() const301 CFX_Matrix CFX_Matrix::GetInverse() const {
302   CFX_Matrix inverse;
303   float i = a * d - b * c;
304   if (fabs(i) == 0)
305     return inverse;
306 
307   float j = -i;
308   inverse.a = d / i;
309   inverse.b = b / j;
310   inverse.c = c / j;
311   inverse.d = a / i;
312   inverse.e = (c * f - d * e) / i;
313   inverse.f = (a * f - b * e) / j;
314   return inverse;
315 }
316 
Is90Rotated() const317 bool CFX_Matrix::Is90Rotated() const {
318   return fabs(a * 1000) < fabs(b) && fabs(d * 1000) < fabs(c);
319 }
320 
IsScaled() const321 bool CFX_Matrix::IsScaled() const {
322   return fabs(b * 1000) < fabs(a) && fabs(c * 1000) < fabs(d);
323 }
324 
Translate(float x,float y)325 void CFX_Matrix::Translate(float x, float y) {
326   e += x;
327   f += y;
328 }
329 
TranslatePrepend(float x,float y)330 void CFX_Matrix::TranslatePrepend(float x, float y) {
331   e += x * a + y * c;
332   f += y * d + x * b;
333 }
334 
Scale(float sx,float sy)335 void CFX_Matrix::Scale(float sx, float sy) {
336   a *= sx;
337   b *= sy;
338   c *= sx;
339   d *= sy;
340   e *= sx;
341   f *= sy;
342 }
343 
Rotate(float fRadian)344 void CFX_Matrix::Rotate(float fRadian) {
345   float cosValue = cos(fRadian);
346   float sinValue = sin(fRadian);
347   Concat(CFX_Matrix(cosValue, sinValue, -sinValue, cosValue, 0, 0));
348 }
349 
MatchRect(const CFX_FloatRect & dest,const CFX_FloatRect & src)350 void CFX_Matrix::MatchRect(const CFX_FloatRect& dest,
351                            const CFX_FloatRect& src) {
352   float fDiff = src.left - src.right;
353   a = fabs(fDiff) < 0.001f ? 1 : (dest.left - dest.right) / fDiff;
354 
355   fDiff = src.bottom - src.top;
356   d = fabs(fDiff) < 0.001f ? 1 : (dest.bottom - dest.top) / fDiff;
357   e = dest.left - src.left * a;
358   f = dest.bottom - src.bottom * d;
359   b = 0;
360   c = 0;
361 }
362 
GetXUnit() const363 float CFX_Matrix::GetXUnit() const {
364   if (b == 0)
365     return (a > 0 ? a : -a);
366   if (a == 0)
367     return (b > 0 ? b : -b);
368   return sqrt(a * a + b * b);
369 }
370 
GetYUnit() const371 float CFX_Matrix::GetYUnit() const {
372   if (c == 0)
373     return (d > 0 ? d : -d);
374   if (d == 0)
375     return (c > 0 ? c : -c);
376   return sqrt(c * c + d * d);
377 }
378 
GetUnitRect() const379 CFX_FloatRect CFX_Matrix::GetUnitRect() const {
380   return TransformRect(CFX_FloatRect(0.f, 0.f, 1.f, 1.f));
381 }
382 
TransformXDistance(float dx) const383 float CFX_Matrix::TransformXDistance(float dx) const {
384   float fx = a * dx;
385   float fy = b * dx;
386   return sqrt(fx * fx + fy * fy);
387 }
388 
TransformDistance(float distance) const389 float CFX_Matrix::TransformDistance(float distance) const {
390   return distance * (GetXUnit() + GetYUnit()) / 2;
391 }
392 
Transform(const CFX_PointF & point) const393 CFX_PointF CFX_Matrix::Transform(const CFX_PointF& point) const {
394   return CFX_PointF(a * point.x + c * point.y + e,
395                     b * point.x + d * point.y + f);
396 }
397 
TransformRect(const CFX_RectF & rect) const398 CFX_RectF CFX_Matrix::TransformRect(const CFX_RectF& rect) const {
399   CFX_FloatRect result_rect = TransformRect(rect.ToFloatRect());
400   return CFX_RectF(result_rect.left, result_rect.bottom, result_rect.Width(),
401                    result_rect.Height());
402 }
403 
TransformRect(const CFX_FloatRect & rect) const404 CFX_FloatRect CFX_Matrix::TransformRect(const CFX_FloatRect& rect) const {
405   CFX_PointF points[] = {{rect.left, rect.top},
406                          {rect.left, rect.bottom},
407                          {rect.right, rect.top},
408                          {rect.right, rect.bottom}};
409   for (CFX_PointF& point : points)
410     point = Transform(point);
411 
412   float new_right = points[0].x;
413   float new_left = points[0].x;
414   float new_top = points[0].y;
415   float new_bottom = points[0].y;
416   for (size_t i = 1; i < pdfium::size(points); i++) {
417     new_right = std::max(new_right, points[i].x);
418     new_left = std::min(new_left, points[i].x);
419     new_top = std::max(new_top, points[i].y);
420     new_bottom = std::min(new_bottom, points[i].y);
421   }
422 
423   return CFX_FloatRect(new_left, new_bottom, new_right, new_top);
424 }
425