• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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