blob: 2cf87d6cf92441424dac1ce76fcdde1bf1b9e13c [file] [log] [blame]
kumarashishg826308d2023-06-23 13:21:22 +00001// Copyright 2014 The PDFium Authors
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -07002// 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
kumarashishg826308d2023-06-23 13:21:22 +00009#include <math.h>
10
11#include <algorithm>
12#include <iterator>
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -070013#include <utility>
14
Haibo Huang49cc9302020-04-27 16:14:24 -070015#include "build/build_config.h"
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -070016#include "core/fxcrt/fx_extension.h"
Haibo Huang49cc9302020-04-27 16:14:24 -070017#include "core/fxcrt/fx_safe_types.h"
kumarashishg826308d2023-06-23 13:21:22 +000018#include "core/fxcrt/fx_system.h"
19
20#ifndef NDEBUG
21#include <ostream>
22#endif
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -070023
24namespace {
25
26void MatchFloatRange(float f1, float f2, int* i1, int* i2) {
Haibo Huang49cc9302020-04-27 16:14:24 -070027 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 }
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -070042}
43
kumarashishg826308d2023-06-23 13:21:22 +000044#if BUILDFLAG(IS_WIN)
Haibo Huang49cc9302020-04-27 16:14:24 -070045static_assert(sizeof(FX_RECT) == sizeof(RECT), "FX_RECT vs. RECT mismatch");
46static_assert(offsetof(FX_RECT, left) == offsetof(RECT, left),
47 "FX_RECT vs. RECT mismatch");
48static_assert(offsetof(FX_RECT, top) == offsetof(RECT, top),
49 "FX_RECT vs. RECT mismatch");
50static_assert(offsetof(FX_RECT, right) == offsetof(RECT, right),
51 "FX_RECT vs. RECT mismatch");
52static_assert(offsetof(FX_RECT, bottom) == offsetof(RECT, bottom),
53 "FX_RECT vs. RECT mismatch");
54static_assert(sizeof(FX_RECT::left) == sizeof(RECT::left),
55 "FX_RECT vs. RECT mismatch");
56static_assert(sizeof(FX_RECT::top) == sizeof(RECT::top),
57 "FX_RECT vs. RECT mismatch");
58static_assert(sizeof(FX_RECT::right) == sizeof(RECT::right),
59 "FX_RECT vs. RECT mismatch");
60static_assert(sizeof(FX_RECT::bottom) == sizeof(RECT::bottom),
61 "FX_RECT vs. RECT mismatch");
62#endif
63
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -070064} // namespace
65
kumarashishg826308d2023-06-23 13:21:22 +000066template <>
67float CFX_VTemplate<float>::Length() const {
68 return FXSYS_sqrt2(x, y);
69}
70
71template <>
72void CFX_VTemplate<float>::Normalize() {
73 float fLen = Length();
74 if (fLen < 0.0001f)
75 return;
76
77 x /= fLen;
78 y /= fLen;
79}
80
81bool 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
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -070089void FX_RECT::Normalize() {
90 if (left > right)
91 std::swap(left, right);
92 if (top > bottom)
93 std::swap(top, bottom);
94}
95
96void 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
kumarashishg826308d2023-06-23 13:21:22 +0000109FX_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
Haibo Huang49cc9302020-04-27 16:14:24 -0700132// Y-axis runs the opposite way in FX_RECT.
133CFX_FloatRect::CFX_FloatRect(const FX_RECT& rect)
134 : left(rect.left), bottom(rect.top), right(rect.right), top(rect.bottom) {}
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -0700135
kumarashishg826308d2023-06-23 13:21:22 +0000136CFX_FloatRect::CFX_FloatRect(const CFX_PointF& point)
137 : left(point.x), bottom(point.y), right(point.x), top(point.y) {}
138
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -0700139// static
kumarashishg826308d2023-06-23 13:21:22 +0000140CFX_FloatRect CFX_FloatRect::GetBBox(pdfium::span<const CFX_PointF> pPoints) {
141 if (pPoints.empty())
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -0700142 return CFX_FloatRect();
143
kumarashishg826308d2023-06-23 13:21:22 +0000144 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);
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -0700153 }
154 return CFX_FloatRect(min_x, min_y, max_x, max_y);
155}
156
157void CFX_FloatRect::Normalize() {
158 if (left > right)
159 std::swap(left, right);
160 if (bottom > top)
161 std::swap(top, bottom);
162}
163
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -0700164void 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)
Haibo Huang49cc9302020-04-27 16:14:24 -0700173 *this = CFX_FloatRect();
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -0700174}
175
176void 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
186FX_RECT CFX_FloatRect::GetOuterRect() const {
187 FX_RECT rect;
Haibo Huang49cc9302020-04-27 16:14:24 -0700188 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));
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -0700192 rect.Normalize();
193 return rect;
194}
195
196FX_RECT CFX_FloatRect::GetInnerRect() const {
197 FX_RECT rect;
Haibo Huang49cc9302020-04-27 16:14:24 -0700198 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));
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -0700202 rect.Normalize();
203 return rect;
204}
205
206FX_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
214CFX_FloatRect CFX_FloatRect::GetCenterSquare() const {
Haibo Huang49cc9302020-04-27 16:14:24 -0700215 float fWidth = Width();
216 float fHeight = Height();
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -0700217 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
225bool 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
232bool 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
241void 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
Haibo Huang49cc9302020-04-27 16:14:24 -0700248void CFX_FloatRect::Inflate(float x, float y) {
249 Inflate(x, y, x, y);
250}
251
252void 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
263void CFX_FloatRect::Inflate(const CFX_FloatRect& rt) {
264 Inflate(rt.left, rt.bottom, rt.right, rt.top);
265}
266
267void CFX_FloatRect::Deflate(float x, float y) {
268 Deflate(x, y, x, y);
269}
270
271void 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
278void CFX_FloatRect::Deflate(const CFX_FloatRect& rt) {
279 Deflate(rt.left, rt.bottom, rt.right, rt.top);
280}
281
282CFX_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
292void CFX_FloatRect::Translate(float e, float f) {
293 left += e;
294 right += e;
295 top += f;
296 bottom += f;
297}
298
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -0700299void CFX_FloatRect::Scale(float fScale) {
300 left *= fScale;
301 bottom *= fScale;
302 right *= fScale;
303 top *= fScale;
304}
305
306void 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
319FX_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
324FX_RECT CFX_FloatRect::ToRoundedFxRect() const {
Haibo Huang49cc9302020-04-27 16:14:24 -0700325 return FX_RECT(FXSYS_roundf(left), FXSYS_roundf(top), FXSYS_roundf(right),
326 FXSYS_roundf(bottom));
327}
328
kumarashishg826308d2023-06-23 13:21:22 +0000329void 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
342void 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
355void 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
Haibo Huang49cc9302020-04-27 16:14:24 -0700368FX_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())));
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -0700373}
374
375#ifndef NDEBUG
376std::ostream& operator<<(std::ostream& os, const CFX_FloatRect& rect) {
Haibo Huang49cc9302020-04-27 16:14:24 -0700377 os << "rect[w " << rect.Width() << " x h " << rect.Height() << " (left "
378 << rect.left << ", bot " << rect.bottom << ")]";
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -0700379 return os;
380}
Haibo Huang49cc9302020-04-27 16:14:24 -0700381
382std::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
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -0700388
389CFX_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
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -0700405bool CFX_Matrix::Is90Rotated() const {
406 return fabs(a * 1000) < fabs(b) && fabs(d * 1000) < fabs(c);
407}
408
409bool CFX_Matrix::IsScaled() const {
410 return fabs(b * 1000) < fabs(a) && fabs(c * 1000) < fabs(d);
411}
412
Haibo Huang49cc9302020-04-27 16:14:24 -0700413void CFX_Matrix::Translate(float x, float y) {
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -0700414 e += x;
415 f += y;
416}
417
Haibo Huang49cc9302020-04-27 16:14:24 -0700418void CFX_Matrix::TranslatePrepend(float x, float y) {
419 e += x * a + y * c;
420 f += y * d + x * b;
421}
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -0700422
Haibo Huang49cc9302020-04-27 16:14:24 -0700423void CFX_Matrix::Scale(float sx, float sy) {
424 a *= sx;
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -0700425 b *= sy;
426 c *= sx;
Haibo Huang49cc9302020-04-27 16:14:24 -0700427 d *= sy;
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -0700428 e *= sx;
429 f *= sy;
430}
431
Haibo Huang49cc9302020-04-27 16:14:24 -0700432void CFX_Matrix::Rotate(float fRadian) {
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -0700433 float cosValue = cos(fRadian);
434 float sinValue = sin(fRadian);
Haibo Huang49cc9302020-04-27 16:14:24 -0700435 Concat(CFX_Matrix(cosValue, sinValue, -sinValue, cosValue, 0, 0));
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -0700436}
437
438void 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
451float CFX_Matrix::GetXUnit() const {
452 if (b == 0)
453 return (a > 0 ? a : -a);
454 if (a == 0)
455 return (b > 0 ? b : -b);
kumarashishg826308d2023-06-23 13:21:22 +0000456 return FXSYS_sqrt2(a, b);
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -0700457}
458
459float CFX_Matrix::GetYUnit() const {
460 if (c == 0)
461 return (d > 0 ? d : -d);
462 if (d == 0)
463 return (c > 0 ? c : -c);
kumarashishg826308d2023-06-23 13:21:22 +0000464 return FXSYS_sqrt2(c, d);
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -0700465}
466
467CFX_FloatRect CFX_Matrix::GetUnitRect() const {
468 return TransformRect(CFX_FloatRect(0.f, 0.f, 1.f, 1.f));
469}
470
471float CFX_Matrix::TransformXDistance(float dx) const {
472 float fx = a * dx;
473 float fy = b * dx;
kumarashishg826308d2023-06-23 13:21:22 +0000474 return FXSYS_sqrt2(fx, fy);
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -0700475}
476
477float CFX_Matrix::TransformDistance(float distance) const {
478 return distance * (GetXUnit() + GetYUnit()) / 2;
479}
480
481CFX_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}
Haibo Huang49cc9302020-04-27 16:14:24 -0700485
486CFX_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
492CFX_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);
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -0700499
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;
kumarashishg826308d2023-06-23 13:21:22 +0000504 for (size_t i = 1; i < std::size(points); i++) {
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -0700505 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 }
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -0700510
Haibo Huang49cc9302020-04-27 16:14:24 -0700511 return CFX_FloatRect(new_left, new_bottom, new_right, new_top);
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -0700512}