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