652f62c71ca1d2650635caaa4e66924486fa46bc
[pdfium.git] / core / src / fxcrt / fx_basic_coords.cpp
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 #include "../../include/fxcrt/fx_ext.h"
9 void FX_RECT::Normalize()
10 {
11     if (left > right) {
12         int temp = left;
13         left = right;
14         right = temp;
15     }
16     if (top > bottom) {
17         int temp = top;
18         top = bottom;
19         bottom = temp;
20     }
21 }
22 void FX_RECT::Intersect(const FX_RECT& src)
23 {
24     FX_RECT src_n = src;
25     src_n.Normalize();
26     Normalize();
27     left = left > src_n.left ? left : src_n.left;
28     top = top > src_n.top ? top : src_n.top;
29     right = right < src_n.right ? right : src_n.right;
30     bottom = bottom < src_n.bottom ? bottom : src_n.bottom;
31     if (left > right || top > bottom) {
32         left = top = right = bottom = 0;
33     }
34 }
35 void FX_RECT::Union(const FX_RECT& other_rect)
36 {
37     Normalize();
38     FX_RECT other = other_rect;
39     other.Normalize();
40     left = left < other.left ? left : other.left;
41     right = right > other.right ? right : other.right;
42     bottom = bottom > other.bottom ? bottom : other.bottom;
43     top = top < other.top ? top : other.top;
44 }
45 FX_BOOL GetIntersection(FX_FLOAT low1, FX_FLOAT high1, FX_FLOAT low2, FX_FLOAT high2,
46                         FX_FLOAT& interlow, FX_FLOAT& interhigh)
47 {
48     if (low1 >= high2 || low2 >= high1) {
49         return FALSE;
50     }
51     interlow = low1 > low2 ? low1 : low2;
52     interhigh = high1 > high2 ? high2 : high1;
53     return TRUE;
54 }
55 extern "C" int FXSYS_round(FX_FLOAT d)
56 {
57     if (d < (FX_FLOAT)INT_MIN) {
58         return INT_MIN;
59     }
60     if (d > (FX_FLOAT)INT_MAX) {
61         return INT_MAX;
62     }
63
64     return (int)round(d);
65 }
66 CFX_FloatRect::CFX_FloatRect(const FX_RECT& rect)
67 {
68     left = (FX_FLOAT)(rect.left);
69     right = (FX_FLOAT)(rect.right);
70     bottom = (FX_FLOAT)(rect.top);
71     top = (FX_FLOAT)(rect.bottom);
72 }
73 void CFX_FloatRect::Normalize()
74 {
75     FX_FLOAT temp;
76     if (left > right) {
77         temp = left;
78         left = right;
79         right = temp;
80     }
81     if (bottom > top) {
82         temp = top;
83         top = bottom;
84         bottom = temp;
85     }
86 }
87 void CFX_FloatRect::Intersect(const CFX_FloatRect& other_rect)
88 {
89     Normalize();
90     CFX_FloatRect other = other_rect;
91     other.Normalize();
92     left = left > other.left ? left : other.left;
93     right = right < other.right ? right : other.right;
94     bottom = bottom > other.bottom ? bottom : other.bottom;
95     top = top < other.top ? top : other.top;
96     if (left > right || bottom > top) {
97         left = right = bottom = top = 0;
98     }
99 }
100 void CFX_FloatRect::Union(const CFX_FloatRect& other_rect)
101 {
102     Normalize();
103     CFX_FloatRect other = other_rect;
104     other.Normalize();
105     left = left < other.left ? left : other.left;
106     right = right > other.right ? right : other.right;
107     bottom = bottom < other.bottom ? bottom : other.bottom;
108     top = top > other.top ? top : other.top;
109 }
110 void CFX_FloatRect::Transform(const CFX_Matrix* pMatrix)
111 {
112     pMatrix->TransformRect(left, right, top, bottom);
113 }
114 int CFX_FloatRect::Substract4(CFX_FloatRect& s, CFX_FloatRect* pRects)
115 {
116     Normalize();
117     s.Normalize();
118     int nRects = 0;
119     CFX_FloatRect rects[4];
120     if (left < s.left) {
121         rects[nRects].left = left;
122         rects[nRects].right = s.left;
123         rects[nRects].bottom = bottom;
124         rects[nRects].top = top;
125         nRects ++;
126     }
127     if (s.left < right && s.top < top) {
128         rects[nRects].left = s.left;
129         rects[nRects].right = right;
130         rects[nRects].bottom = s.top;
131         rects[nRects].top = top;
132         nRects ++;
133     }
134     if (s.top > bottom && s.right < right) {
135         rects[nRects].left = s.right;
136         rects[nRects].right = right;
137         rects[nRects].bottom = bottom;
138         rects[nRects].top = s.top;
139         nRects ++;
140     }
141     if (s.bottom > bottom) {
142         rects[nRects].left = s.left;
143         rects[nRects].right = s.right;
144         rects[nRects].bottom = bottom;
145         rects[nRects].top = s.bottom;
146         nRects ++;
147     }
148     if (nRects == 0) {
149         return 0;
150     }
151     for (int i = 0; i < nRects; i ++) {
152         pRects[i] = rects[i];
153         pRects[i].Intersect(*this);
154     }
155     return nRects;
156 }
157 FX_RECT CFX_FloatRect::GetOutterRect() const
158 {
159     CFX_FloatRect rect1 = *this;
160     FX_RECT rect;
161     rect.left = (int)FXSYS_floor(rect1.left);
162     rect.right = (int)FXSYS_ceil(rect1.right);
163     rect.top = (int)FXSYS_floor(rect1.bottom);
164     rect.bottom = (int)FXSYS_ceil(rect1.top);
165     rect.Normalize();
166     return rect;
167 }
168 FX_RECT CFX_FloatRect::GetInnerRect() const
169 {
170     CFX_FloatRect rect1 = *this;
171     FX_RECT rect;
172     rect.left = (int)FXSYS_ceil(rect1.left);
173     rect.right = (int)FXSYS_floor(rect1.right);
174     rect.top = (int)FXSYS_ceil(rect1.bottom);
175     rect.bottom = (int)FXSYS_floor(rect1.top);
176     rect.Normalize();
177     return rect;
178 }
179 static void _MatchFloatRange(FX_FLOAT f1, FX_FLOAT f2, int& i1, int& i2)
180 {
181     int length = (int)FXSYS_ceil(f2 - f1);
182     int i1_1 = (int)FXSYS_floor(f1);
183     int i1_2 = (int)FXSYS_ceil(f1);
184     FX_FLOAT error1 = f1 - i1_1 + (FX_FLOAT)FXSYS_fabs(f2 - i1_1 - length);
185     FX_FLOAT error2 = i1_2 - f1 + (FX_FLOAT)FXSYS_fabs(f2 - i1_2 - length);
186     i1 = (error1 > error2) ? i1_2 : i1_1;
187     i2 = i1 + length;
188 }
189 FX_RECT CFX_FloatRect::GetClosestRect() const
190 {
191     CFX_FloatRect rect1 = *this;
192     FX_RECT rect;
193     _MatchFloatRange(rect1.left, rect1.right, rect.left, rect.right);
194     _MatchFloatRange(rect1.bottom, rect1.top, rect.top, rect.bottom);
195     rect.Normalize();
196     return rect;
197 }
198 FX_BOOL CFX_FloatRect::Contains(const CFX_FloatRect& other_rect) const
199 {
200     CFX_FloatRect n1 = *this;
201     n1.Normalize();
202     CFX_FloatRect n2 = other_rect;
203     n2.Normalize();
204     if (n2.left >= n1.left && n2.right <= n1.right && n2.bottom >= n1.bottom && n2.top <= n1.top) {
205         return TRUE;
206     }
207     return FALSE;
208 }
209 FX_BOOL CFX_FloatRect::Contains(FX_FLOAT x, FX_FLOAT y) const
210 {
211     CFX_FloatRect n1 = *this;
212     n1.Normalize();
213     return x <= n1.right && x >= n1.left && y <= n1.top && y >= n1.bottom;
214 }
215 void CFX_FloatRect::UpdateRect(FX_FLOAT x, FX_FLOAT y)
216 {
217     if (left > x) {
218         left = x;
219     }
220     if (right < x) {
221         right = x;
222     }
223     if (bottom > y) {
224         bottom = y;
225     }
226     if (top < y) {
227         top = y;
228     }
229 }
230 CFX_FloatRect CFX_FloatRect::GetBBox(const CFX_FloatPoint* pPoints, int nPoints)
231 {
232     if (nPoints == 0) {
233         return CFX_FloatRect();
234     }
235     FX_FLOAT min_x = pPoints->x, max_x = pPoints->x, min_y = pPoints->y, max_y = pPoints->y;
236     for (int i = 1; i < nPoints; i ++) {
237         if (min_x > pPoints[i].x) {
238             min_x = pPoints[i].x;
239         }
240         if (max_x < pPoints[i].x) {
241             max_x = pPoints[i].x;
242         }
243         if (min_y > pPoints[i].y) {
244             min_y = pPoints[i].y;
245         }
246         if (max_y < pPoints[i].y) {
247             max_y = pPoints[i].y;
248         }
249     }
250     return CFX_FloatRect(min_x, min_y, max_x, max_y);
251 }
252 void CFX_Matrix::Set(FX_FLOAT other_a,
253                      FX_FLOAT other_b,
254                      FX_FLOAT other_c,
255                      FX_FLOAT other_d,
256                      FX_FLOAT other_e,
257                      FX_FLOAT other_f)
258 {
259     a = other_a;
260     b = other_b;
261     c = other_c;
262     d = other_d;
263     e = other_e;
264     f = other_f;
265 }
266 void CFX_Matrix::Set(const FX_FLOAT n[6])
267 {
268     a = n[0];
269     b = n[1];
270     c = n[2];
271     d = n[3];
272     e = n[4];
273     f = n[5];
274 }
275 void CFX_Matrix::SetReverse(const CFX_Matrix &m)
276 {
277     FX_FLOAT i = m.a * m.d - m.b * m.c;
278     if (FXSYS_fabs(i) == 0) {
279         return;
280     }
281     FX_FLOAT j = -i;
282     a = m.d / i;
283     b = m.b / j;
284     c = m.c / j;
285     d = m.a / i;
286     e = (m.c * m.f - m.d * m.e) / i;
287     f = (m.a * m.f - m.b * m.e) / j;
288 }
289 static void FXCRT_Matrix_Concat(CFX_Matrix &m, const CFX_Matrix &m1, const CFX_Matrix &m2)
290 {
291     FX_FLOAT aa = m1.a * m2.a + m1.b * m2.c;
292     FX_FLOAT bb = m1.a * m2.b + m1.b * m2.d;
293     FX_FLOAT cc = m1.c * m2.a + m1.d * m2.c;
294     FX_FLOAT dd = m1.c * m2.b + m1.d * m2.d;
295     FX_FLOAT ee = m1.e * m2.a + m1.f * m2.c + m2.e;
296     FX_FLOAT ff = m1.e * m2.b + m1.f * m2.d + m2.f;
297     m.a = aa, m.b = bb, m.c = cc, m.d = dd, m.e = ee, m.f = ff;
298 }
299 void CFX_Matrix::Concat(FX_FLOAT a, FX_FLOAT b, FX_FLOAT c, FX_FLOAT d, FX_FLOAT e, FX_FLOAT f, FX_BOOL bPrepended)
300 {
301     CFX_Matrix m;
302     m.Set(a, b, c, d, e, f);
303     Concat(m, bPrepended);
304 }
305 void CFX_Matrix::Concat(const CFX_Matrix &m, FX_BOOL bPrepended)
306 {
307     if (bPrepended) {
308         FXCRT_Matrix_Concat(*this, m, *this);
309     } else {
310         FXCRT_Matrix_Concat(*this, *this, m);
311     }
312 }
313 void CFX_Matrix::ConcatInverse(const CFX_Matrix& src, FX_BOOL bPrepended)
314 {
315     CFX_Matrix m;
316     m.SetReverse(src);
317     Concat(m, bPrepended);
318 }
319 FX_BOOL CFX_Matrix::IsInvertible() const
320 {
321     return FXSYS_fabs(a * d - b * c) >= 0.0001f;
322 }
323 FX_BOOL CFX_Matrix::Is90Rotated() const
324 {
325     return FXSYS_fabs(a * 1000) < FXSYS_fabs(b) && FXSYS_fabs(d * 1000) < FXSYS_fabs(c);
326 }
327 FX_BOOL CFX_Matrix::IsScaled() const
328 {
329     return FXSYS_fabs(b * 1000) < FXSYS_fabs(a) && FXSYS_fabs(c * 1000) < FXSYS_fabs(d);
330 }
331 void CFX_Matrix::Translate(FX_FLOAT x, FX_FLOAT y, FX_BOOL bPrepended)
332 {
333     if (bPrepended) {
334         e += x * a + y * c;
335         f += y * d + x * b;
336     } else {
337         e += x, f += y;
338     }
339 }
340 void CFX_Matrix::Scale(FX_FLOAT sx, FX_FLOAT sy, FX_BOOL bPrepended)
341 {
342     a *= sx, d *= sy;
343     if (bPrepended) {
344         b *= sx;
345         c *= sy;
346     } else {
347         b *= sy;
348         c *= sx;
349         e *= sx;
350         f *= sy;
351     }
352 }
353 void CFX_Matrix::Rotate(FX_FLOAT fRadian, FX_BOOL bPrepended)
354 {
355     FX_FLOAT cosValue = FXSYS_cos(fRadian);
356     FX_FLOAT sinValue = FXSYS_sin(fRadian);
357     CFX_Matrix m;
358     m.Set(cosValue, sinValue, -sinValue, cosValue, 0, 0);
359     if (bPrepended) {
360         FXCRT_Matrix_Concat(*this, m, *this);
361     } else {
362         FXCRT_Matrix_Concat(*this, *this, m);
363     }
364 }
365 void CFX_Matrix::RotateAt(FX_FLOAT fRadian, FX_FLOAT dx, FX_FLOAT dy, FX_BOOL bPrepended)
366 {
367     Translate(dx, dy, bPrepended);
368     Rotate(fRadian, bPrepended);
369     Translate(-dx, -dy, bPrepended);
370 }
371 void CFX_Matrix::Shear(FX_FLOAT fAlphaRadian, FX_FLOAT fBetaRadian, FX_BOOL bPrepended)
372 {
373     CFX_Matrix m;
374     m.Set(1, FXSYS_tan(fAlphaRadian), FXSYS_tan(fBetaRadian), 1, 0, 0);
375     if (bPrepended) {
376         FXCRT_Matrix_Concat(*this, m, *this);
377     } else {
378         FXCRT_Matrix_Concat(*this, *this, m);
379     }
380 }
381 void CFX_Matrix::MatchRect(const CFX_FloatRect& dest, const CFX_FloatRect& src)
382 {
383     FX_FLOAT fDiff = src.left - src.right;
384     a = FXSYS_fabs(fDiff) < 0.001f ? 1 : (dest.left - dest.right) / fDiff;
385     fDiff = src.bottom - src.top;
386     d = FXSYS_fabs(fDiff) < 0.001f ? 1 : (dest.bottom - dest.top) / fDiff;
387     e = dest.left - src.left * a;
388     f = dest.bottom - src.bottom * d;
389     b = 0;
390     c = 0;
391 }
392 FX_FLOAT CFX_Matrix::GetXUnit() const
393 {
394     if (b == 0) {
395         return (a > 0 ? a : -a);
396     }
397     if (a == 0) {
398         return (b > 0 ? b : -b);
399     }
400     return FXSYS_sqrt(a * a + b * b);
401 }
402 FX_FLOAT CFX_Matrix::GetYUnit() const
403 {
404     if (c == 0) {
405         return (d > 0 ? d : -d);
406     }
407     if (d == 0) {
408         return (c > 0 ? c : -c);
409     }
410     return FXSYS_sqrt(c * c + d * d);
411 }
412 void CFX_Matrix::GetUnitRect(CFX_RectF &rect) const
413 {
414     rect.left = rect.top = 0;
415     rect.width = rect.height = 1;
416     TransformRect(rect);
417 }
418 CFX_FloatRect CFX_Matrix::GetUnitRect() const
419 {
420     CFX_FloatRect rect(0, 0, 1, 1);
421     rect.Transform((const CFX_Matrix*)this);
422     return rect;
423 }
424 FX_FLOAT CFX_Matrix::GetUnitArea() const
425 {
426     FX_FLOAT A = FXSYS_sqrt(a * a + b * b);
427     FX_FLOAT B = FXSYS_sqrt(c * c + d * d);
428     FX_FLOAT ac = a + c, bd = b + d;
429     FX_FLOAT C = FXSYS_sqrt(ac * ac + bd * bd);
430     FX_FLOAT P = (A + B + C ) / 2;
431     return FXSYS_sqrt(P * (P - A) * (P - B) * (P - C)) * 2;
432 }
433 FX_FLOAT CFX_Matrix::TransformXDistance(FX_FLOAT dx) const
434 {
435     FX_FLOAT fx = a * dx, fy = b * dx;
436     return FXSYS_sqrt(fx * fx + fy * fy);
437 }
438 int32_t CFX_Matrix::TransformXDistance(int32_t dx) const
439 {
440     FX_FLOAT fx = a * dx, fy = b * dx;
441     return FXSYS_round(FXSYS_sqrt(fx * fx + fy * fy));
442 }
443 FX_FLOAT CFX_Matrix::TransformYDistance(FX_FLOAT dy) const
444 {
445     FX_FLOAT fx = c * dy, fy = d * dy;
446     return FXSYS_sqrt(fx * fx + fy * fy);
447 }
448 int32_t CFX_Matrix::TransformYDistance(int32_t dy) const
449 {
450     FX_FLOAT fx = c * dy, fy = d * dy;
451     return FXSYS_round(FXSYS_sqrt(fx * fx + fy * fy));
452 }
453 FX_FLOAT CFX_Matrix::TransformDistance(FX_FLOAT dx, FX_FLOAT dy) const
454 {
455     FX_FLOAT fx = a * dx + c * dy, fy = b * dx + d * dy;
456     return FXSYS_sqrt(fx * fx + fy * fy);
457 }
458 int32_t CFX_Matrix::TransformDistance(int32_t dx, int32_t dy) const
459 {
460     FX_FLOAT fx = a * dx + c * dy, fy = b * dx + d * dy;
461     return FXSYS_round(FXSYS_sqrt(fx * fx + fy * fy));
462 }
463 FX_FLOAT CFX_Matrix::TransformDistance(FX_FLOAT distance) const
464 {
465     return distance * (GetXUnit() + GetYUnit()) / 2;
466 }
467 void CFX_Matrix::TransformVector(CFX_VectorF &v) const
468 {
469     FX_FLOAT fx = a * v.x + c * v.y;
470     FX_FLOAT fy = b * v.x + d * v.y;
471     v.x = fx, v.y = fy;
472 }
473 void CFX_Matrix::TransformVector(CFX_Vector &v) const
474 {
475     FX_FLOAT fx = a * v.x + c * v.y;
476     FX_FLOAT fy = b * v.x + d * v.y;
477     v.x = FXSYS_round(fx);
478     v.y = FXSYS_round(fy);
479 }
480 void CFX_Matrix::TransformPoints(CFX_Point *points, int32_t iCount) const
481 {
482     FXSYS_assert(iCount > 0);
483     FX_FLOAT fx, fy;
484     for (int32_t i = 0; i < iCount; i ++) {
485         fx = a * points->x + c * points->y + e;
486         fy = b * points->x + d * points->y + f;
487         points->x = FXSYS_round(fx);
488         points->y = FXSYS_round(fy);
489         points ++;
490     }
491 }
492 void CFX_Matrix::TransformPoints(CFX_PointF *points, int32_t iCount) const
493 {
494     FXSYS_assert(iCount > 0);
495     FX_FLOAT fx, fy;
496     for (int32_t i = 0; i < iCount; i ++) {
497         fx = a * points->x + c * points->y + e;
498         fy = b * points->x + d * points->y + f;
499         points->x = fx, points->y = fy;
500         points ++;
501     }
502 }
503 void CFX_Matrix::TransformPoint(FX_FLOAT &x, FX_FLOAT &y) const
504 {
505     FX_FLOAT fx = a * x + c * y + e;
506     FX_FLOAT fy = b * x + d * y + f;
507     x = fx, y = fy;
508 }
509 void CFX_Matrix::TransformPoint(int32_t &x, int32_t &y) const
510 {
511     FX_FLOAT fx = a * x + c * y + e;
512     FX_FLOAT fy = b * x + d * y + f;
513     x = FXSYS_round(fx);
514     y = FXSYS_round(fy);
515 }
516 void CFX_Matrix::TransformRect(CFX_RectF &rect) const
517 {
518     FX_FLOAT right = rect.right(), bottom = rect.bottom();
519     TransformRect(rect.left, right, bottom, rect.top);
520     rect.width = right - rect.left;
521     rect.height = bottom - rect.top;
522 }
523 void CFX_Matrix::TransformRect(CFX_Rect &rect) const
524 {
525     FX_FLOAT left = (FX_FLOAT)rect.left;
526     FX_FLOAT top = (FX_FLOAT)rect.bottom();
527     FX_FLOAT right = (FX_FLOAT)rect.right();
528     FX_FLOAT bottom = (FX_FLOAT)rect.top;
529     TransformRect(left, right, top, bottom);
530     rect.left = FXSYS_round(left);
531     rect.top = FXSYS_round(bottom);
532     rect.width = FXSYS_round(right - left);
533     rect.height = FXSYS_round(top - bottom);
534 }
535 void CFX_Matrix::TransformRect(FX_FLOAT& left, FX_FLOAT& right, FX_FLOAT& top, FX_FLOAT& bottom) const
536 {
537     FX_FLOAT x[4], y[4];
538     x[0] = left;
539     y[0] = top;
540     x[1] = left;
541     y[1] = bottom;
542     x[2] = right;
543     y[2] = top;
544     x[3] = right;
545     y[3] = bottom;
546     int i;
547     for (i = 0; i < 4; i ++) {
548         Transform(x[i], y[i], x[i], y[i]);
549     }
550     right = left = x[0];
551     top = bottom = y[0];
552     for (i = 1; i < 4; i ++) {
553         if (right < x[i]) {
554             right = x[i];
555         }
556         if (left > x[i]) {
557             left = x[i];
558         }
559         if (top < y[i]) {
560             top = y[i];
561         }
562         if (bottom > y[i]) {
563             bottom = y[i];
564         }
565     }
566 }