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 <limits.h>
8
9 #include <algorithm>
10
11 #include "core/fxcrt/fx_coordinates.h"
12 #include "core/fxcrt/fx_ext.h"
13
14 namespace {
15
MatchFloatRange(FX_FLOAT f1,FX_FLOAT f2,int * i1,int * i2)16 void MatchFloatRange(FX_FLOAT f1, FX_FLOAT f2, int* i1, int* i2) {
17 int length = static_cast<int>(FXSYS_ceil(f2 - f1));
18 int i1_1 = static_cast<int>(FXSYS_floor(f1));
19 int i1_2 = static_cast<int>(FXSYS_ceil(f1));
20 FX_FLOAT error1 = f1 - i1_1 + (FX_FLOAT)FXSYS_fabs(f2 - i1_1 - length);
21 FX_FLOAT error2 = i1_2 - f1 + (FX_FLOAT)FXSYS_fabs(f2 - i1_2 - length);
22
23 *i1 = (error1 > error2) ? i1_2 : i1_1;
24 *i2 = *i1 + length;
25 }
26
27 } // namespace
28
Normalize()29 void FX_RECT::Normalize() {
30 if (left > right) {
31 int temp = left;
32 left = right;
33 right = temp;
34 }
35 if (top > bottom) {
36 int temp = top;
37 top = bottom;
38 bottom = temp;
39 }
40 }
Intersect(const FX_RECT & src)41 void FX_RECT::Intersect(const FX_RECT& src) {
42 FX_RECT src_n = src;
43 src_n.Normalize();
44 Normalize();
45 left = left > src_n.left ? left : src_n.left;
46 top = top > src_n.top ? top : src_n.top;
47 right = right < src_n.right ? right : src_n.right;
48 bottom = bottom < src_n.bottom ? bottom : src_n.bottom;
49 if (left > right || top > bottom) {
50 left = top = right = bottom = 0;
51 }
52 }
53
GetIntersection(FX_FLOAT low1,FX_FLOAT high1,FX_FLOAT low2,FX_FLOAT high2,FX_FLOAT & interlow,FX_FLOAT & interhigh)54 bool GetIntersection(FX_FLOAT low1,
55 FX_FLOAT high1,
56 FX_FLOAT low2,
57 FX_FLOAT high2,
58 FX_FLOAT& interlow,
59 FX_FLOAT& interhigh) {
60 if (low1 >= high2 || low2 >= high1) {
61 return false;
62 }
63 interlow = low1 > low2 ? low1 : low2;
64 interhigh = high1 > high2 ? high2 : high1;
65 return true;
66 }
FXSYS_round(FX_FLOAT d)67 extern "C" int FXSYS_round(FX_FLOAT d) {
68 if (d < (FX_FLOAT)INT_MIN) {
69 return INT_MIN;
70 }
71 if (d > (FX_FLOAT)INT_MAX) {
72 return INT_MAX;
73 }
74
75 return (int)round(d);
76 }
CFX_FloatRect(const FX_RECT & rect)77 CFX_FloatRect::CFX_FloatRect(const FX_RECT& rect) {
78 left = (FX_FLOAT)(rect.left);
79 right = (FX_FLOAT)(rect.right);
80 bottom = (FX_FLOAT)(rect.top);
81 top = (FX_FLOAT)(rect.bottom);
82 }
Normalize()83 void CFX_FloatRect::Normalize() {
84 FX_FLOAT temp;
85 if (left > right) {
86 temp = left;
87 left = right;
88 right = temp;
89 }
90 if (bottom > top) {
91 temp = top;
92 top = bottom;
93 bottom = temp;
94 }
95 }
Intersect(const CFX_FloatRect & other_rect)96 void CFX_FloatRect::Intersect(const CFX_FloatRect& other_rect) {
97 Normalize();
98 CFX_FloatRect other = other_rect;
99 other.Normalize();
100 left = left > other.left ? left : other.left;
101 right = right < other.right ? right : other.right;
102 bottom = bottom > other.bottom ? bottom : other.bottom;
103 top = top < other.top ? top : other.top;
104 if (left > right || bottom > top) {
105 left = right = bottom = top = 0;
106 }
107 }
Union(const CFX_FloatRect & other_rect)108 void CFX_FloatRect::Union(const CFX_FloatRect& other_rect) {
109 Normalize();
110 CFX_FloatRect other = other_rect;
111 other.Normalize();
112 left = left < other.left ? left : other.left;
113 right = right > other.right ? right : other.right;
114 bottom = bottom < other.bottom ? bottom : other.bottom;
115 top = top > other.top ? top : other.top;
116 }
117
Substract4(CFX_FloatRect & s,CFX_FloatRect * pRects)118 int CFX_FloatRect::Substract4(CFX_FloatRect& s, CFX_FloatRect* pRects) {
119 Normalize();
120 s.Normalize();
121 int nRects = 0;
122 CFX_FloatRect rects[4];
123 if (left < s.left) {
124 rects[nRects].left = left;
125 rects[nRects].right = s.left;
126 rects[nRects].bottom = bottom;
127 rects[nRects].top = top;
128 nRects++;
129 }
130 if (s.left < right && s.top < top) {
131 rects[nRects].left = s.left;
132 rects[nRects].right = right;
133 rects[nRects].bottom = s.top;
134 rects[nRects].top = top;
135 nRects++;
136 }
137 if (s.top > bottom && s.right < right) {
138 rects[nRects].left = s.right;
139 rects[nRects].right = right;
140 rects[nRects].bottom = bottom;
141 rects[nRects].top = s.top;
142 nRects++;
143 }
144 if (s.bottom > bottom) {
145 rects[nRects].left = s.left;
146 rects[nRects].right = s.right;
147 rects[nRects].bottom = bottom;
148 rects[nRects].top = s.bottom;
149 nRects++;
150 }
151 if (nRects == 0) {
152 return 0;
153 }
154 for (int i = 0; i < nRects; i++) {
155 pRects[i] = rects[i];
156 pRects[i].Intersect(*this);
157 }
158 return nRects;
159 }
160
GetOuterRect() const161 FX_RECT CFX_FloatRect::GetOuterRect() const {
162 CFX_FloatRect rect1 = *this;
163 FX_RECT rect;
164 rect.left = (int)FXSYS_floor(rect1.left);
165 rect.right = (int)FXSYS_ceil(rect1.right);
166 rect.top = (int)FXSYS_floor(rect1.bottom);
167 rect.bottom = (int)FXSYS_ceil(rect1.top);
168 rect.Normalize();
169 return rect;
170 }
171
GetInnerRect() const172 FX_RECT CFX_FloatRect::GetInnerRect() const {
173 CFX_FloatRect rect1 = *this;
174 FX_RECT rect;
175 rect.left = (int)FXSYS_ceil(rect1.left);
176 rect.right = (int)FXSYS_floor(rect1.right);
177 rect.top = (int)FXSYS_ceil(rect1.bottom);
178 rect.bottom = (int)FXSYS_floor(rect1.top);
179 rect.Normalize();
180 return rect;
181 }
182
GetClosestRect() const183 FX_RECT CFX_FloatRect::GetClosestRect() const {
184 CFX_FloatRect rect1 = *this;
185 FX_RECT rect;
186 MatchFloatRange(rect1.left, rect1.right, &rect.left, &rect.right);
187 MatchFloatRange(rect1.bottom, rect1.top, &rect.top, &rect.bottom);
188 rect.Normalize();
189 return rect;
190 }
191
Contains(const CFX_PointF & point) const192 bool CFX_FloatRect::Contains(const CFX_PointF& point) const {
193 CFX_FloatRect n1(*this);
194 n1.Normalize();
195 return point.x <= n1.right && point.x >= n1.left && point.y <= n1.top &&
196 point.y >= n1.bottom;
197 }
198
Contains(const CFX_FloatRect & other_rect) const199 bool CFX_FloatRect::Contains(const CFX_FloatRect& other_rect) const {
200 CFX_FloatRect n1(*this);
201 CFX_FloatRect n2(other_rect);
202 n1.Normalize();
203 n2.Normalize();
204 return n2.left >= n1.left && n2.right <= n1.right && n2.bottom >= n1.bottom &&
205 n2.top <= n1.top;
206 }
207
UpdateRect(FX_FLOAT x,FX_FLOAT y)208 void CFX_FloatRect::UpdateRect(FX_FLOAT x, FX_FLOAT y) {
209 left = std::min(left, x);
210 right = std::max(right, x);
211 bottom = std::min(bottom, y);
212 top = std::max(top, y);
213 }
214
GetBBox(const CFX_PointF * pPoints,int nPoints)215 CFX_FloatRect CFX_FloatRect::GetBBox(const CFX_PointF* pPoints, int nPoints) {
216 if (nPoints == 0)
217 return CFX_FloatRect();
218
219 FX_FLOAT min_x = pPoints->x;
220 FX_FLOAT max_x = pPoints->x;
221 FX_FLOAT min_y = pPoints->y;
222 FX_FLOAT max_y = pPoints->y;
223 for (int i = 1; i < nPoints; i++) {
224 min_x = std::min(min_x, pPoints[i].x);
225 max_x = std::max(max_x, pPoints[i].x);
226 min_y = std::min(min_y, pPoints[i].y);
227 max_y = std::max(max_y, pPoints[i].y);
228 }
229 return CFX_FloatRect(min_x, min_y, max_x, max_y);
230 }
231
SetReverse(const CFX_Matrix & m)232 void CFX_Matrix::SetReverse(const CFX_Matrix& m) {
233 FX_FLOAT i = m.a * m.d - m.b * m.c;
234 if (FXSYS_fabs(i) == 0)
235 return;
236
237 FX_FLOAT j = -i;
238 a = m.d / i;
239 b = m.b / j;
240 c = m.c / j;
241 d = m.a / i;
242 e = (m.c * m.f - m.d * m.e) / i;
243 f = (m.a * m.f - m.b * m.e) / j;
244 }
245
Concat(const CFX_Matrix & m,bool bPrepended)246 void CFX_Matrix::Concat(const CFX_Matrix& m, bool bPrepended) {
247 ConcatInternal(m, bPrepended);
248 }
249
ConcatInverse(const CFX_Matrix & src,bool bPrepended)250 void CFX_Matrix::ConcatInverse(const CFX_Matrix& src, bool bPrepended) {
251 CFX_Matrix m;
252 m.SetReverse(src);
253 Concat(m, bPrepended);
254 }
255
Is90Rotated() const256 bool CFX_Matrix::Is90Rotated() const {
257 return FXSYS_fabs(a * 1000) < FXSYS_fabs(b) &&
258 FXSYS_fabs(d * 1000) < FXSYS_fabs(c);
259 }
260
IsScaled() const261 bool CFX_Matrix::IsScaled() const {
262 return FXSYS_fabs(b * 1000) < FXSYS_fabs(a) &&
263 FXSYS_fabs(c * 1000) < FXSYS_fabs(d);
264 }
265
Translate(FX_FLOAT x,FX_FLOAT y,bool bPrepended)266 void CFX_Matrix::Translate(FX_FLOAT x, FX_FLOAT y, bool bPrepended) {
267 if (bPrepended) {
268 e += x * a + y * c;
269 f += y * d + x * b;
270 return;
271 }
272 e += x;
273 f += y;
274 }
275
Scale(FX_FLOAT sx,FX_FLOAT sy,bool bPrepended)276 void CFX_Matrix::Scale(FX_FLOAT sx, FX_FLOAT sy, bool bPrepended) {
277 a *= sx;
278 d *= sy;
279 if (bPrepended) {
280 b *= sx;
281 c *= sy;
282 return;
283 }
284
285 b *= sy;
286 c *= sx;
287 e *= sx;
288 f *= sy;
289 }
290
Rotate(FX_FLOAT fRadian,bool bPrepended)291 void CFX_Matrix::Rotate(FX_FLOAT fRadian, bool bPrepended) {
292 FX_FLOAT cosValue = FXSYS_cos(fRadian);
293 FX_FLOAT sinValue = FXSYS_sin(fRadian);
294 ConcatInternal(CFX_Matrix(cosValue, sinValue, -sinValue, cosValue, 0, 0),
295 bPrepended);
296 }
297
RotateAt(FX_FLOAT fRadian,FX_FLOAT dx,FX_FLOAT dy,bool bPrepended)298 void CFX_Matrix::RotateAt(FX_FLOAT fRadian,
299 FX_FLOAT dx,
300 FX_FLOAT dy,
301 bool bPrepended) {
302 Translate(dx, dy, bPrepended);
303 Rotate(fRadian, bPrepended);
304 Translate(-dx, -dy, bPrepended);
305 }
306
Shear(FX_FLOAT fAlphaRadian,FX_FLOAT fBetaRadian,bool bPrepended)307 void CFX_Matrix::Shear(FX_FLOAT fAlphaRadian,
308 FX_FLOAT fBetaRadian,
309 bool bPrepended) {
310 ConcatInternal(
311 CFX_Matrix(1, FXSYS_tan(fAlphaRadian), FXSYS_tan(fBetaRadian), 1, 0, 0),
312 bPrepended);
313 }
314
MatchRect(const CFX_FloatRect & dest,const CFX_FloatRect & src)315 void CFX_Matrix::MatchRect(const CFX_FloatRect& dest,
316 const CFX_FloatRect& src) {
317 FX_FLOAT fDiff = src.left - src.right;
318 a = FXSYS_fabs(fDiff) < 0.001f ? 1 : (dest.left - dest.right) / fDiff;
319
320 fDiff = src.bottom - src.top;
321 d = FXSYS_fabs(fDiff) < 0.001f ? 1 : (dest.bottom - dest.top) / fDiff;
322 e = dest.left - src.left * a;
323 f = dest.bottom - src.bottom * d;
324 b = 0;
325 c = 0;
326 }
327
GetXUnit() const328 FX_FLOAT CFX_Matrix::GetXUnit() const {
329 if (b == 0)
330 return (a > 0 ? a : -a);
331 if (a == 0)
332 return (b > 0 ? b : -b);
333 return FXSYS_sqrt(a * a + b * b);
334 }
335
GetYUnit() const336 FX_FLOAT CFX_Matrix::GetYUnit() const {
337 if (c == 0)
338 return (d > 0 ? d : -d);
339 if (d == 0)
340 return (c > 0 ? c : -c);
341 return FXSYS_sqrt(c * c + d * d);
342 }
343
GetUnitRect() const344 CFX_FloatRect CFX_Matrix::GetUnitRect() const {
345 CFX_FloatRect rect(0, 0, 1, 1);
346 TransformRect(rect);
347 return rect;
348 }
349
TransformXDistance(FX_FLOAT dx) const350 FX_FLOAT CFX_Matrix::TransformXDistance(FX_FLOAT dx) const {
351 FX_FLOAT fx = a * dx;
352 FX_FLOAT fy = b * dx;
353 return FXSYS_sqrt(fx * fx + fy * fy);
354 }
355
TransformDistance(FX_FLOAT dx,FX_FLOAT dy) const356 FX_FLOAT CFX_Matrix::TransformDistance(FX_FLOAT dx, FX_FLOAT dy) const {
357 FX_FLOAT fx = a * dx + c * dy;
358 FX_FLOAT fy = b * dx + d * dy;
359 return FXSYS_sqrt(fx * fx + fy * fy);
360 }
361
TransformDistance(FX_FLOAT distance) const362 FX_FLOAT CFX_Matrix::TransformDistance(FX_FLOAT distance) const {
363 return distance * (GetXUnit() + GetYUnit()) / 2;
364 }
365
Transform(const CFX_PointF & point) const366 CFX_PointF CFX_Matrix::Transform(const CFX_PointF& point) const {
367 return CFX_PointF(a * point.x + c * point.y + e,
368 b * point.x + d * point.y + f);
369 }
370
TransformRect(CFX_RectF & rect) const371 void CFX_Matrix::TransformRect(CFX_RectF& rect) const {
372 FX_FLOAT right = rect.right(), bottom = rect.bottom();
373 TransformRect(rect.left, right, bottom, rect.top);
374 rect.width = right - rect.left;
375 rect.height = bottom - rect.top;
376 }
377
TransformRect(FX_FLOAT & left,FX_FLOAT & right,FX_FLOAT & top,FX_FLOAT & bottom) const378 void CFX_Matrix::TransformRect(FX_FLOAT& left,
379 FX_FLOAT& right,
380 FX_FLOAT& top,
381 FX_FLOAT& bottom) const {
382 CFX_PointF points[] = {
383 {left, top}, {left, bottom}, {right, top}, {right, bottom}};
384 for (int i = 0; i < 4; i++)
385 points[i] = Transform(points[i]);
386
387 right = points[0].x;
388 left = points[0].x;
389 top = points[0].y;
390 bottom = points[0].y;
391 for (int i = 1; i < 4; i++) {
392 right = std::max(right, points[i].x);
393 left = std::min(left, points[i].x);
394 top = std::max(top, points[i].y);
395 bottom = std::min(bottom, points[i].y);
396 }
397 }
398
ConcatInternal(const CFX_Matrix & other,bool prepend)399 void CFX_Matrix::ConcatInternal(const CFX_Matrix& other, bool prepend) {
400 CFX_Matrix left;
401 CFX_Matrix right;
402 if (prepend) {
403 left = other;
404 right = *this;
405 } else {
406 left = *this;
407 right = other;
408 }
409
410 a = left.a * right.a + left.b * right.c;
411 b = left.a * right.b + left.b * right.d;
412 c = left.c * right.a + left.d * right.c;
413 d = left.c * right.b + left.d * right.d;
414 e = left.e * right.a + left.f * right.c + right.e;
415 f = left.e * right.b + left.f * right.d + right.f;
416 }
417