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/numerics/safe_conversions.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
Normalize()58 void FX_RECT::Normalize() {
59 if (left > right)
60 std::swap(left, right);
61 if (top > bottom)
62 std::swap(top, bottom);
63 }
64
Intersect(const FX_RECT & src)65 void FX_RECT::Intersect(const FX_RECT& src) {
66 FX_RECT src_n = src;
67 src_n.Normalize();
68 Normalize();
69 left = std::max(left, src_n.left);
70 top = std::max(top, src_n.top);
71 right = std::min(right, src_n.right);
72 bottom = std::min(bottom, src_n.bottom);
73 if (left > right || top > bottom) {
74 left = top = right = bottom = 0;
75 }
76 }
77
78 // Y-axis runs the opposite way in FX_RECT.
CFX_FloatRect(const FX_RECT & rect)79 CFX_FloatRect::CFX_FloatRect(const FX_RECT& rect)
80 : left(rect.left), bottom(rect.top), right(rect.right), top(rect.bottom) {}
81
82 // static
GetBBox(const CFX_PointF * pPoints,int nPoints)83 CFX_FloatRect CFX_FloatRect::GetBBox(const CFX_PointF* pPoints, int nPoints) {
84 if (nPoints == 0)
85 return CFX_FloatRect();
86
87 float min_x = pPoints->x;
88 float max_x = pPoints->x;
89 float min_y = pPoints->y;
90 float max_y = pPoints->y;
91 for (int i = 1; i < nPoints; i++) {
92 min_x = std::min(min_x, pPoints[i].x);
93 max_x = std::max(max_x, pPoints[i].x);
94 min_y = std::min(min_y, pPoints[i].y);
95 max_y = std::max(max_y, pPoints[i].y);
96 }
97 return CFX_FloatRect(min_x, min_y, max_x, max_y);
98 }
99
Normalize()100 void CFX_FloatRect::Normalize() {
101 if (left > right)
102 std::swap(left, right);
103 if (bottom > top)
104 std::swap(top, bottom);
105 }
106
Intersect(const CFX_FloatRect & other_rect)107 void CFX_FloatRect::Intersect(const CFX_FloatRect& other_rect) {
108 Normalize();
109 CFX_FloatRect other = other_rect;
110 other.Normalize();
111 left = std::max(left, other.left);
112 bottom = std::max(bottom, other.bottom);
113 right = std::min(right, other.right);
114 top = std::min(top, other.top);
115 if (left > right || bottom > top)
116 *this = CFX_FloatRect();
117 }
118
Union(const CFX_FloatRect & other_rect)119 void CFX_FloatRect::Union(const CFX_FloatRect& other_rect) {
120 Normalize();
121 CFX_FloatRect other = other_rect;
122 other.Normalize();
123 left = std::min(left, other.left);
124 bottom = std::min(bottom, other.bottom);
125 right = std::max(right, other.right);
126 top = std::max(top, other.top);
127 }
128
GetOuterRect() const129 FX_RECT CFX_FloatRect::GetOuterRect() const {
130 FX_RECT rect;
131 rect.left = pdfium::base::saturated_cast<int>(floor(left));
132 rect.bottom = pdfium::base::saturated_cast<int>(ceil(top));
133 rect.right = pdfium::base::saturated_cast<int>(ceil(right));
134 rect.top = pdfium::base::saturated_cast<int>(floor(bottom));
135 rect.Normalize();
136 return rect;
137 }
138
GetInnerRect() const139 FX_RECT CFX_FloatRect::GetInnerRect() const {
140 FX_RECT rect;
141 rect.left = pdfium::base::saturated_cast<int>(ceil(left));
142 rect.bottom = pdfium::base::saturated_cast<int>(floor(top));
143 rect.right = pdfium::base::saturated_cast<int>(floor(right));
144 rect.top = pdfium::base::saturated_cast<int>(ceil(bottom));
145 rect.Normalize();
146 return rect;
147 }
148
GetClosestRect() const149 FX_RECT CFX_FloatRect::GetClosestRect() const {
150 FX_RECT rect;
151 MatchFloatRange(left, right, &rect.left, &rect.right);
152 MatchFloatRange(bottom, top, &rect.top, &rect.bottom);
153 rect.Normalize();
154 return rect;
155 }
156
GetCenterSquare() const157 CFX_FloatRect CFX_FloatRect::GetCenterSquare() const {
158 float fWidth = Width();
159 float fHeight = Height();
160 float fHalfWidth = (fWidth > fHeight) ? fHeight / 2 : fWidth / 2;
161
162 float fCenterX = (left + right) / 2.0f;
163 float fCenterY = (top + bottom) / 2.0f;
164 return CFX_FloatRect(fCenterX - fHalfWidth, fCenterY - fHalfWidth,
165 fCenterX + fHalfWidth, fCenterY + fHalfWidth);
166 }
167
Contains(const CFX_PointF & point) const168 bool CFX_FloatRect::Contains(const CFX_PointF& point) const {
169 CFX_FloatRect n1(*this);
170 n1.Normalize();
171 return point.x <= n1.right && point.x >= n1.left && point.y <= n1.top &&
172 point.y >= n1.bottom;
173 }
174
Contains(const CFX_FloatRect & other_rect) const175 bool CFX_FloatRect::Contains(const CFX_FloatRect& other_rect) const {
176 CFX_FloatRect n1(*this);
177 CFX_FloatRect n2(other_rect);
178 n1.Normalize();
179 n2.Normalize();
180 return n2.left >= n1.left && n2.right <= n1.right && n2.bottom >= n1.bottom &&
181 n2.top <= n1.top;
182 }
183
UpdateRect(const CFX_PointF & point)184 void CFX_FloatRect::UpdateRect(const CFX_PointF& point) {
185 left = std::min(left, point.x);
186 bottom = std::min(bottom, point.y);
187 right = std::max(right, point.x);
188 top = std::max(top, point.y);
189 }
190
Inflate(float x,float y)191 void CFX_FloatRect::Inflate(float x, float y) {
192 Inflate(x, y, x, y);
193 }
194
Inflate(float other_left,float other_bottom,float other_right,float other_top)195 void CFX_FloatRect::Inflate(float other_left,
196 float other_bottom,
197 float other_right,
198 float other_top) {
199 Normalize();
200 left -= other_left;
201 bottom -= other_bottom;
202 right += other_right;
203 top += other_top;
204 }
205
Inflate(const CFX_FloatRect & rt)206 void CFX_FloatRect::Inflate(const CFX_FloatRect& rt) {
207 Inflate(rt.left, rt.bottom, rt.right, rt.top);
208 }
209
Deflate(float x,float y)210 void CFX_FloatRect::Deflate(float x, float y) {
211 Deflate(x, y, x, y);
212 }
213
Deflate(float other_left,float other_bottom,float other_right,float other_top)214 void CFX_FloatRect::Deflate(float other_left,
215 float other_bottom,
216 float other_right,
217 float other_top) {
218 Inflate(-other_left, -other_bottom, -other_right, -other_top);
219 }
220
Deflate(const CFX_FloatRect & rt)221 void CFX_FloatRect::Deflate(const CFX_FloatRect& rt) {
222 Deflate(rt.left, rt.bottom, rt.right, rt.top);
223 }
224
GetDeflated(float x,float y) const225 CFX_FloatRect CFX_FloatRect::GetDeflated(float x, float y) const {
226 if (IsEmpty())
227 return CFX_FloatRect();
228
229 CFX_FloatRect that = *this;
230 that.Deflate(x, y);
231 that.Normalize();
232 return that;
233 }
234
Translate(float e,float f)235 void CFX_FloatRect::Translate(float e, float f) {
236 left += e;
237 right += e;
238 top += f;
239 bottom += f;
240 }
241
Scale(float fScale)242 void CFX_FloatRect::Scale(float fScale) {
243 left *= fScale;
244 bottom *= fScale;
245 right *= fScale;
246 top *= fScale;
247 }
248
ScaleFromCenterPoint(float fScale)249 void CFX_FloatRect::ScaleFromCenterPoint(float fScale) {
250 float fHalfWidth = (right - left) / 2.0f;
251 float fHalfHeight = (top - bottom) / 2.0f;
252
253 float center_x = (left + right) / 2;
254 float center_y = (top + bottom) / 2;
255
256 left = center_x - fHalfWidth * fScale;
257 bottom = center_y - fHalfHeight * fScale;
258 right = center_x + fHalfWidth * fScale;
259 top = center_y + fHalfHeight * fScale;
260 }
261
ToFxRect() const262 FX_RECT CFX_FloatRect::ToFxRect() const {
263 return FX_RECT(static_cast<int>(left), static_cast<int>(top),
264 static_cast<int>(right), static_cast<int>(bottom));
265 }
266
ToRoundedFxRect() const267 FX_RECT CFX_FloatRect::ToRoundedFxRect() const {
268 return FX_RECT(FXSYS_roundf(left), FXSYS_roundf(top), FXSYS_roundf(right),
269 FXSYS_roundf(bottom));
270 }
271
GetOuterRect() const272 FX_RECT CFX_RectF::GetOuterRect() const {
273 return FX_RECT(static_cast<int32_t>(floor(left)),
274 static_cast<int32_t>(floor(top)),
275 static_cast<int32_t>(ceil(right())),
276 static_cast<int32_t>(ceil(bottom())));
277 }
278
279 #ifndef NDEBUG
operator <<(std::ostream & os,const CFX_FloatRect & rect)280 std::ostream& operator<<(std::ostream& os, const CFX_FloatRect& rect) {
281 os << "rect[w " << rect.Width() << " x h " << rect.Height() << " (left "
282 << rect.left << ", bot " << rect.bottom << ")]";
283 return os;
284 }
285
operator <<(std::ostream & os,const CFX_RectF & rect)286 std::ostream& operator<<(std::ostream& os, const CFX_RectF& rect) {
287 os << "rect[w " << rect.Width() << " x h " << rect.Height() << " (left "
288 << rect.left << ", top " << rect.top << ")]";
289 return os;
290 }
291 #endif // NDEBUG
292
GetInverse() const293 CFX_Matrix CFX_Matrix::GetInverse() const {
294 CFX_Matrix inverse;
295 float i = a * d - b * c;
296 if (fabs(i) == 0)
297 return inverse;
298
299 float j = -i;
300 inverse.a = d / i;
301 inverse.b = b / j;
302 inverse.c = c / j;
303 inverse.d = a / i;
304 inverse.e = (c * f - d * e) / i;
305 inverse.f = (a * f - b * e) / j;
306 return inverse;
307 }
308
Is90Rotated() const309 bool CFX_Matrix::Is90Rotated() const {
310 return fabs(a * 1000) < fabs(b) && fabs(d * 1000) < fabs(c);
311 }
312
IsScaled() const313 bool CFX_Matrix::IsScaled() const {
314 return fabs(b * 1000) < fabs(a) && fabs(c * 1000) < fabs(d);
315 }
316
Translate(float x,float y)317 void CFX_Matrix::Translate(float x, float y) {
318 e += x;
319 f += y;
320 }
321
TranslatePrepend(float x,float y)322 void CFX_Matrix::TranslatePrepend(float x, float y) {
323 e += x * a + y * c;
324 f += y * d + x * b;
325 }
326
Scale(float sx,float sy)327 void CFX_Matrix::Scale(float sx, float sy) {
328 a *= sx;
329 b *= sy;
330 c *= sx;
331 d *= sy;
332 e *= sx;
333 f *= sy;
334 }
335
Rotate(float fRadian)336 void CFX_Matrix::Rotate(float fRadian) {
337 float cosValue = cos(fRadian);
338 float sinValue = sin(fRadian);
339 Concat(CFX_Matrix(cosValue, sinValue, -sinValue, cosValue, 0, 0));
340 }
341
MatchRect(const CFX_FloatRect & dest,const CFX_FloatRect & src)342 void CFX_Matrix::MatchRect(const CFX_FloatRect& dest,
343 const CFX_FloatRect& src) {
344 float fDiff = src.left - src.right;
345 a = fabs(fDiff) < 0.001f ? 1 : (dest.left - dest.right) / fDiff;
346
347 fDiff = src.bottom - src.top;
348 d = fabs(fDiff) < 0.001f ? 1 : (dest.bottom - dest.top) / fDiff;
349 e = dest.left - src.left * a;
350 f = dest.bottom - src.bottom * d;
351 b = 0;
352 c = 0;
353 }
354
GetXUnit() const355 float CFX_Matrix::GetXUnit() const {
356 if (b == 0)
357 return (a > 0 ? a : -a);
358 if (a == 0)
359 return (b > 0 ? b : -b);
360 return sqrt(a * a + b * b);
361 }
362
GetYUnit() const363 float CFX_Matrix::GetYUnit() const {
364 if (c == 0)
365 return (d > 0 ? d : -d);
366 if (d == 0)
367 return (c > 0 ? c : -c);
368 return sqrt(c * c + d * d);
369 }
370
GetUnitRect() const371 CFX_FloatRect CFX_Matrix::GetUnitRect() const {
372 return TransformRect(CFX_FloatRect(0.f, 0.f, 1.f, 1.f));
373 }
374
TransformXDistance(float dx) const375 float CFX_Matrix::TransformXDistance(float dx) const {
376 float fx = a * dx;
377 float fy = b * dx;
378 return sqrt(fx * fx + fy * fy);
379 }
380
TransformDistance(float distance) const381 float CFX_Matrix::TransformDistance(float distance) const {
382 return distance * (GetXUnit() + GetYUnit()) / 2;
383 }
384
Transform(const CFX_PointF & point) const385 CFX_PointF CFX_Matrix::Transform(const CFX_PointF& point) const {
386 return CFX_PointF(a * point.x + c * point.y + e,
387 b * point.x + d * point.y + f);
388 }
389
TransformRect(const CFX_RectF & rect) const390 CFX_RectF CFX_Matrix::TransformRect(const CFX_RectF& rect) const {
391 CFX_FloatRect result_rect = TransformRect(rect.ToFloatRect());
392 return CFX_RectF(result_rect.left, result_rect.bottom, result_rect.Width(),
393 result_rect.Height());
394 }
395
TransformRect(const CFX_FloatRect & rect) const396 CFX_FloatRect CFX_Matrix::TransformRect(const CFX_FloatRect& rect) const {
397 CFX_PointF points[] = {{rect.left, rect.top},
398 {rect.left, rect.bottom},
399 {rect.right, rect.top},
400 {rect.right, rect.bottom}};
401 for (CFX_PointF& point : points)
402 point = Transform(point);
403
404 float new_right = points[0].x;
405 float new_left = points[0].x;
406 float new_top = points[0].y;
407 float new_bottom = points[0].y;
408 for (size_t i = 1; i < FX_ArraySize(points); i++) {
409 new_right = std::max(new_right, points[i].x);
410 new_left = std::min(new_left, points[i].x);
411 new_top = std::max(new_top, points[i].y);
412 new_bottom = std::min(new_bottom, points[i].y);
413 }
414
415 return CFX_FloatRect(new_left, new_bottom, new_right, new_top);
416 }
417