• 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 #include "core/fxcrt/fx_coordinates.h"
8 
9 #include <math.h>
10 
11 #include <algorithm>
12 #include <array>
13 #include <iterator>
14 #include <utility>
15 
16 #include "build/build_config.h"
17 #include "core/fxcrt/fx_extension.h"
18 #include "core/fxcrt/fx_safe_types.h"
19 #include "core/fxcrt/fx_system.h"
20 
21 namespace {
22 
MatchFloatRange(float f1,float f2,int * i1,int * i2)23 void MatchFloatRange(float f1, float f2, int* i1, int* i2) {
24   float length = ceilf(f2 - f1);
25   float f1_floor = floorf(f1);
26   float f1_ceil = ceilf(f1);
27   float error1 = f1 - f1_floor + fabsf(f2 - f1_floor - length);
28   float error2 = f1_ceil - f1 + fabsf(f2 - f1_ceil - length);
29   float start = error1 > error2 ? f1_ceil : f1_floor;
30   FX_SAFE_INT32 safe1 = start;
31   FX_SAFE_INT32 safe2 = start + length;
32   if (safe1.IsValid() && safe2.IsValid()) {
33     *i1 = safe1.ValueOrDie();
34     *i2 = safe2.ValueOrDie();
35   } else {
36     *i1 = 0;
37     *i2 = 0;
38   }
39 }
40 
41 #if BUILDFLAG(IS_WIN)
42 static_assert(sizeof(FX_RECT) == sizeof(RECT), "FX_RECT vs. RECT mismatch");
43 static_assert(offsetof(FX_RECT, left) == offsetof(RECT, left),
44               "FX_RECT vs. RECT mismatch");
45 static_assert(offsetof(FX_RECT, top) == offsetof(RECT, top),
46               "FX_RECT vs. RECT mismatch");
47 static_assert(offsetof(FX_RECT, right) == offsetof(RECT, right),
48               "FX_RECT vs. RECT mismatch");
49 static_assert(offsetof(FX_RECT, bottom) == offsetof(RECT, bottom),
50               "FX_RECT vs. RECT mismatch");
51 static_assert(sizeof(FX_RECT::left) == sizeof(RECT::left),
52               "FX_RECT vs. RECT mismatch");
53 static_assert(sizeof(FX_RECT::top) == sizeof(RECT::top),
54               "FX_RECT vs. RECT mismatch");
55 static_assert(sizeof(FX_RECT::right) == sizeof(RECT::right),
56               "FX_RECT vs. RECT mismatch");
57 static_assert(sizeof(FX_RECT::bottom) == sizeof(RECT::bottom),
58               "FX_RECT vs. RECT mismatch");
59 #endif
60 
61 }  // namespace
62 
63 template <>
Length() const64 float CFX_VTemplate<float>::Length() const {
65   return hypotf(x, y);
66 }
67 
68 template <>
Normalize()69 void CFX_VTemplate<float>::Normalize() {
70   float fLen = Length();
71   if (fLen < 0.0001f)
72     return;
73 
74   x /= fLen;
75   y /= fLen;
76 }
77 
Valid() const78 bool FX_RECT::Valid() const {
79   FX_SAFE_INT32 w = right;
80   FX_SAFE_INT32 h = bottom;
81   w -= left;
82   h -= top;
83   return w.IsValid() && h.IsValid();
84 }
85 
Normalize()86 void FX_RECT::Normalize() {
87   if (left > right)
88     std::swap(left, right);
89   if (top > bottom)
90     std::swap(top, bottom);
91 }
92 
Intersect(const FX_RECT & src)93 void FX_RECT::Intersect(const FX_RECT& src) {
94   FX_RECT src_n = src;
95   src_n.Normalize();
96   Normalize();
97   left = std::max(left, src_n.left);
98   top = std::max(top, src_n.top);
99   right = std::min(right, src_n.right);
100   bottom = std::min(bottom, src_n.bottom);
101   if (left > right || top > bottom) {
102     left = top = right = bottom = 0;
103   }
104 }
105 
SwappedClipBox(int width,int height,bool bFlipX,bool bFlipY) const106 FX_RECT FX_RECT::SwappedClipBox(int width,
107                                 int height,
108                                 bool bFlipX,
109                                 bool bFlipY) const {
110   FX_RECT rect;
111   if (bFlipY) {
112     rect.left = height - top;
113     rect.right = height - bottom;
114   } else {
115     rect.left = top;
116     rect.right = bottom;
117   }
118   if (bFlipX) {
119     rect.top = width - left;
120     rect.bottom = width - right;
121   } else {
122     rect.top = left;
123     rect.bottom = right;
124   }
125   rect.Normalize();
126   return rect;
127 }
128 
129 // Y-axis runs the opposite way in FX_RECT.
CFX_FloatRect(const FX_RECT & rect)130 CFX_FloatRect::CFX_FloatRect(const FX_RECT& rect)
131     : left(rect.left), bottom(rect.top), right(rect.right), top(rect.bottom) {}
132 
CFX_FloatRect(const CFX_PointF & point)133 CFX_FloatRect::CFX_FloatRect(const CFX_PointF& point)
134     : left(point.x), bottom(point.y), right(point.x), top(point.y) {}
135 
136 // static
GetBBox(pdfium::span<const CFX_PointF> pPoints)137 CFX_FloatRect CFX_FloatRect::GetBBox(pdfium::span<const CFX_PointF> pPoints) {
138   if (pPoints.empty())
139     return CFX_FloatRect();
140 
141   float min_x = pPoints.front().x;
142   float max_x = pPoints.front().x;
143   float min_y = pPoints.front().y;
144   float max_y = pPoints.front().y;
145   for (const auto& point : pPoints.subspan(1)) {
146     min_x = std::min(min_x, point.x);
147     max_x = std::max(max_x, point.x);
148     min_y = std::min(min_y, point.y);
149     max_y = std::max(max_y, point.y);
150   }
151   return CFX_FloatRect(min_x, min_y, max_x, max_y);
152 }
153 
Normalize()154 void CFX_FloatRect::Normalize() {
155   if (left > right)
156     std::swap(left, right);
157   if (bottom > top)
158     std::swap(top, bottom);
159 }
160 
Intersect(const CFX_FloatRect & other_rect)161 void CFX_FloatRect::Intersect(const CFX_FloatRect& other_rect) {
162   Normalize();
163   CFX_FloatRect other = other_rect;
164   other.Normalize();
165   left = std::max(left, other.left);
166   bottom = std::max(bottom, other.bottom);
167   right = std::min(right, other.right);
168   top = std::min(top, other.top);
169   if (left > right || bottom > top)
170     *this = CFX_FloatRect();
171 }
172 
Union(const CFX_FloatRect & other_rect)173 void CFX_FloatRect::Union(const CFX_FloatRect& other_rect) {
174   Normalize();
175   CFX_FloatRect other = other_rect;
176   other.Normalize();
177   left = std::min(left, other.left);
178   bottom = std::min(bottom, other.bottom);
179   right = std::max(right, other.right);
180   top = std::max(top, other.top);
181 }
182 
GetOuterRect() const183 FX_RECT CFX_FloatRect::GetOuterRect() const {
184   FX_RECT rect;
185   rect.left = pdfium::saturated_cast<int>(floor(left));
186   rect.bottom = pdfium::saturated_cast<int>(ceil(top));
187   rect.right = pdfium::saturated_cast<int>(ceil(right));
188   rect.top = pdfium::saturated_cast<int>(floor(bottom));
189   rect.Normalize();
190   return rect;
191 }
192 
GetInnerRect() const193 FX_RECT CFX_FloatRect::GetInnerRect() const {
194   FX_RECT rect;
195   rect.left = pdfium::saturated_cast<int>(ceil(left));
196   rect.bottom = pdfium::saturated_cast<int>(floor(top));
197   rect.right = pdfium::saturated_cast<int>(floor(right));
198   rect.top = pdfium::saturated_cast<int>(ceil(bottom));
199   rect.Normalize();
200   return rect;
201 }
202 
GetClosestRect() const203 FX_RECT CFX_FloatRect::GetClosestRect() const {
204   FX_RECT rect;
205   MatchFloatRange(left, right, &rect.left, &rect.right);
206   MatchFloatRange(bottom, top, &rect.top, &rect.bottom);
207   rect.Normalize();
208   return rect;
209 }
210 
GetCenterSquare() const211 CFX_FloatRect CFX_FloatRect::GetCenterSquare() const {
212   float fWidth = Width();
213   float fHeight = Height();
214   float fHalfWidth = (fWidth > fHeight) ? fHeight / 2 : fWidth / 2;
215 
216   float fCenterX = (left + right) / 2.0f;
217   float fCenterY = (top + bottom) / 2.0f;
218   return CFX_FloatRect(fCenterX - fHalfWidth, fCenterY - fHalfWidth,
219                        fCenterX + fHalfWidth, fCenterY + fHalfWidth);
220 }
221 
Contains(const CFX_PointF & point) const222 bool CFX_FloatRect::Contains(const CFX_PointF& point) const {
223   CFX_FloatRect n1(*this);
224   n1.Normalize();
225   return point.x <= n1.right && point.x >= n1.left && point.y <= n1.top &&
226          point.y >= n1.bottom;
227 }
228 
Contains(const CFX_FloatRect & other_rect) const229 bool CFX_FloatRect::Contains(const CFX_FloatRect& other_rect) const {
230   CFX_FloatRect n1(*this);
231   CFX_FloatRect n2(other_rect);
232   n1.Normalize();
233   n2.Normalize();
234   return n2.left >= n1.left && n2.right <= n1.right && n2.bottom >= n1.bottom &&
235          n2.top <= n1.top;
236 }
237 
UpdateRect(const CFX_PointF & point)238 void CFX_FloatRect::UpdateRect(const CFX_PointF& point) {
239   left = std::min(left, point.x);
240   bottom = std::min(bottom, point.y);
241   right = std::max(right, point.x);
242   top = std::max(top, point.y);
243 }
244 
Inflate(float x,float y)245 void CFX_FloatRect::Inflate(float x, float y) {
246   Inflate(x, y, x, y);
247 }
248 
Inflate(float other_left,float other_bottom,float other_right,float other_top)249 void CFX_FloatRect::Inflate(float other_left,
250                             float other_bottom,
251                             float other_right,
252                             float other_top) {
253   Normalize();
254   left -= other_left;
255   bottom -= other_bottom;
256   right += other_right;
257   top += other_top;
258 }
259 
Inflate(const CFX_FloatRect & rt)260 void CFX_FloatRect::Inflate(const CFX_FloatRect& rt) {
261   Inflate(rt.left, rt.bottom, rt.right, rt.top);
262 }
263 
Deflate(float x,float y)264 void CFX_FloatRect::Deflate(float x, float y) {
265   Deflate(x, y, x, y);
266 }
267 
Deflate(float other_left,float other_bottom,float other_right,float other_top)268 void CFX_FloatRect::Deflate(float other_left,
269                             float other_bottom,
270                             float other_right,
271                             float other_top) {
272   Inflate(-other_left, -other_bottom, -other_right, -other_top);
273 }
274 
Deflate(const CFX_FloatRect & rt)275 void CFX_FloatRect::Deflate(const CFX_FloatRect& rt) {
276   Deflate(rt.left, rt.bottom, rt.right, rt.top);
277 }
278 
GetDeflated(float x,float y) const279 CFX_FloatRect CFX_FloatRect::GetDeflated(float x, float y) const {
280   if (IsEmpty())
281     return CFX_FloatRect();
282 
283   CFX_FloatRect that = *this;
284   that.Deflate(x, y);
285   that.Normalize();
286   return that;
287 }
288 
Translate(float e,float f)289 void CFX_FloatRect::Translate(float e, float f) {
290   left += e;
291   right += e;
292   top += f;
293   bottom += f;
294 }
295 
Scale(float fScale)296 void CFX_FloatRect::Scale(float fScale) {
297   left *= fScale;
298   bottom *= fScale;
299   right *= fScale;
300   top *= fScale;
301 }
302 
ScaleFromCenterPoint(float fScale)303 void CFX_FloatRect::ScaleFromCenterPoint(float fScale) {
304   float fHalfWidth = (right - left) / 2.0f;
305   float fHalfHeight = (top - bottom) / 2.0f;
306 
307   float center_x = (left + right) / 2;
308   float center_y = (top + bottom) / 2;
309 
310   left = center_x - fHalfWidth * fScale;
311   bottom = center_y - fHalfHeight * fScale;
312   right = center_x + fHalfWidth * fScale;
313   top = center_y + fHalfHeight * fScale;
314 }
315 
ToFxRect() const316 FX_RECT CFX_FloatRect::ToFxRect() const {
317   return FX_RECT(static_cast<int>(left), static_cast<int>(top),
318                  static_cast<int>(right), static_cast<int>(bottom));
319 }
320 
ToRoundedFxRect() const321 FX_RECT CFX_FloatRect::ToRoundedFxRect() const {
322   return FX_RECT(FXSYS_roundf(left), FXSYS_roundf(top), FXSYS_roundf(right),
323                  FXSYS_roundf(bottom));
324 }
325 
Union(float x,float y)326 void CFX_RectF::Union(float x, float y) {
327   float r = right();
328   float b = bottom();
329 
330   left = std::min(left, x);
331   top = std::min(top, y);
332   r = std::max(r, x);
333   b = std::max(b, y);
334 
335   width = r - left;
336   height = b - top;
337 }
338 
Union(const CFX_RectF & rt)339 void CFX_RectF::Union(const CFX_RectF& rt) {
340   float r = right();
341   float b = bottom();
342 
343   left = std::min(left, rt.left);
344   top = std::min(top, rt.top);
345   r = std::max(r, rt.right());
346   b = std::max(b, rt.bottom());
347 
348   width = r - left;
349   height = b - top;
350 }
351 
Intersect(const CFX_RectF & rt)352 void CFX_RectF::Intersect(const CFX_RectF& rt) {
353   float r = right();
354   float b = bottom();
355 
356   left = std::max(left, rt.left);
357   top = std::max(top, rt.top);
358   r = std::min(r, rt.right());
359   b = std::min(b, rt.bottom());
360 
361   width = r - left;
362   height = b - top;
363 }
364 
GetOuterRect() const365 FX_RECT CFX_RectF::GetOuterRect() const {
366   return FX_RECT(static_cast<int32_t>(floor(left)),
367                  static_cast<int32_t>(floor(top)),
368                  static_cast<int32_t>(ceil(right())),
369                  static_cast<int32_t>(ceil(bottom())));
370 }
371 
GetInverse() const372 CFX_Matrix CFX_Matrix::GetInverse() const {
373   CFX_Matrix inverse;
374   float i = a * d - b * c;
375   if (fabs(i) == 0)
376     return inverse;
377 
378   float j = -i;
379   inverse.a = d / i;
380   inverse.b = b / j;
381   inverse.c = c / j;
382   inverse.d = a / i;
383   inverse.e = (c * f - d * e) / i;
384   inverse.f = (a * f - b * e) / j;
385   return inverse;
386 }
387 
Is90Rotated() const388 bool CFX_Matrix::Is90Rotated() const {
389   return fabs(a * 1000) < fabs(b) && fabs(d * 1000) < fabs(c);
390 }
391 
IsScaled() const392 bool CFX_Matrix::IsScaled() const {
393   return fabs(b * 1000) < fabs(a) && fabs(c * 1000) < fabs(d);
394 }
395 
Translate(float x,float y)396 void CFX_Matrix::Translate(float x, float y) {
397   e += x;
398   f += y;
399 }
400 
TranslatePrepend(float x,float y)401 void CFX_Matrix::TranslatePrepend(float x, float y) {
402   e += x * a + y * c;
403   f += y * d + x * b;
404 }
405 
Scale(float sx,float sy)406 void CFX_Matrix::Scale(float sx, float sy) {
407   a *= sx;
408   b *= sy;
409   c *= sx;
410   d *= sy;
411   e *= sx;
412   f *= sy;
413 }
414 
Rotate(float fRadian)415 void CFX_Matrix::Rotate(float fRadian) {
416   float cosValue = cos(fRadian);
417   float sinValue = sin(fRadian);
418   Concat(CFX_Matrix(cosValue, sinValue, -sinValue, cosValue, 0, 0));
419 }
420 
MatchRect(const CFX_FloatRect & dest,const CFX_FloatRect & src)421 void CFX_Matrix::MatchRect(const CFX_FloatRect& dest,
422                            const CFX_FloatRect& src) {
423   float fDiff = src.left - src.right;
424   a = fabs(fDiff) < 0.001f ? 1 : (dest.left - dest.right) / fDiff;
425 
426   fDiff = src.bottom - src.top;
427   d = fabs(fDiff) < 0.001f ? 1 : (dest.bottom - dest.top) / fDiff;
428   e = dest.left - src.left * a;
429   f = dest.bottom - src.bottom * d;
430   b = 0;
431   c = 0;
432 }
433 
GetXUnit() const434 float CFX_Matrix::GetXUnit() const {
435   if (b == 0)
436     return (a > 0 ? a : -a);
437   if (a == 0)
438     return (b > 0 ? b : -b);
439   return hypotf(a, b);
440 }
441 
GetYUnit() const442 float CFX_Matrix::GetYUnit() const {
443   if (c == 0)
444     return (d > 0 ? d : -d);
445   if (d == 0)
446     return (c > 0 ? c : -c);
447   return hypotf(c, d);
448 }
449 
GetUnitRect() const450 CFX_FloatRect CFX_Matrix::GetUnitRect() const {
451   return TransformRect(CFX_FloatRect(0.f, 0.f, 1.f, 1.f));
452 }
453 
TransformXDistance(float dx) const454 float CFX_Matrix::TransformXDistance(float dx) const {
455   float fx = a * dx;
456   float fy = b * dx;
457   return hypotf(fx, fy);
458 }
459 
TransformDistance(float distance) const460 float CFX_Matrix::TransformDistance(float distance) const {
461   return distance * (GetXUnit() + GetYUnit()) / 2;
462 }
463 
Transform(const CFX_PointF & point) const464 CFX_PointF CFX_Matrix::Transform(const CFX_PointF& point) const {
465   return CFX_PointF(a * point.x + c * point.y + e,
466                     b * point.x + d * point.y + f);
467 }
468 
TransformRect(const CFX_RectF & rect) const469 CFX_RectF CFX_Matrix::TransformRect(const CFX_RectF& rect) const {
470   CFX_FloatRect result_rect = TransformRect(rect.ToFloatRect());
471   return CFX_RectF(result_rect.left, result_rect.bottom, result_rect.Width(),
472                    result_rect.Height());
473 }
474 
TransformRect(const CFX_FloatRect & rect) const475 CFX_FloatRect CFX_Matrix::TransformRect(const CFX_FloatRect& rect) const {
476   std::array<CFX_PointF, 4> points = {{{rect.left, rect.top},
477                                        {rect.left, rect.bottom},
478                                        {rect.right, rect.top},
479                                        {rect.right, rect.bottom}}};
480   for (CFX_PointF& point : points) {
481     point = Transform(point);
482   }
483   float new_right = points[0].x;
484   float new_left = points[0].x;
485   float new_top = points[0].y;
486   float new_bottom = points[0].y;
487   for (size_t i = 1; i < points.size(); i++) {
488     new_right = std::max(new_right, points[i].x);
489     new_left = std::min(new_left, points[i].x);
490     new_top = std::max(new_top, points[i].y);
491     new_bottom = std::min(new_bottom, points[i].y);
492   }
493 
494   return CFX_FloatRect(new_left, new_bottom, new_right, new_top);
495 }
496