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"
Normalize()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 }
Intersect(const FX_RECT & src)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 }
Union(const FX_RECT & other_rect)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 }
GetIntersection(FX_FLOAT low1,FX_FLOAT high1,FX_FLOAT low2,FX_FLOAT high2,FX_FLOAT & interlow,FX_FLOAT & interhigh)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 }
FXSYS_round(FX_FLOAT d)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 }
CFX_FloatRect(const FX_RECT & rect)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 }
Normalize()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 }
Intersect(const CFX_FloatRect & other_rect)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 }
Union(const CFX_FloatRect & other_rect)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 }
Transform(const CFX_Matrix * pMatrix)110 void CFX_FloatRect::Transform(const CFX_Matrix* pMatrix)
111 {
112     pMatrix->TransformRect(left, right, top, bottom);
113 }
Substract4(CFX_FloatRect & s,CFX_FloatRect * pRects)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 }
GetOutterRect() const157 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 }
GetInnerRect() const168 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 }
_MatchFloatRange(FX_FLOAT f1,FX_FLOAT f2,int & i1,int & i2)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 }
GetClosestRect() const189 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 }
Contains(const CFX_FloatRect & other_rect) const198 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 }
Contains(FX_FLOAT x,FX_FLOAT y) const209 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 }
UpdateRect(FX_FLOAT x,FX_FLOAT y)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 }
GetBBox(const CFX_FloatPoint * pPoints,int nPoints)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 }
Set(FX_FLOAT a,FX_FLOAT b,FX_FLOAT c,FX_FLOAT d,FX_FLOAT e,FX_FLOAT f)252 void CFX_Matrix::Set(FX_FLOAT a, FX_FLOAT b, FX_FLOAT c, FX_FLOAT d, FX_FLOAT e, FX_FLOAT f)
253 {
254     this->a = a;
255     this->b = b;
256     this->c = c;
257     this->d = d;
258     this->e = e;
259     this->f = f;
260 }
Set(const FX_FLOAT n[6])261 void CFX_Matrix::Set(const FX_FLOAT n[6])
262 {
263     this->a = n[0];
264     this->b = n[1];
265     this->c = n[2];
266     this->d = n[3];
267     this->e = n[4];
268     this->f = n[5];
269 }
SetReverse(const CFX_Matrix & m)270 void CFX_Matrix::SetReverse(const CFX_Matrix &m)
271 {
272     FX_FLOAT i = m.a * m.d - m.b * m.c;
273     if (FXSYS_fabs(i) == 0) {
274         return;
275     }
276     FX_FLOAT j = -i;
277     a = m.d / i;
278     b = m.b / j;
279     c = m.c / j;
280     d = m.a / i;
281     e = (m.c * m.f - m.d * m.e) / i;
282     f = (m.a * m.f - m.b * m.e) / j;
283 }
FXCRT_Matrix_Concat(CFX_Matrix & m,const CFX_Matrix & m1,const CFX_Matrix & m2)284 static void FXCRT_Matrix_Concat(CFX_Matrix &m, const CFX_Matrix &m1, const CFX_Matrix &m2)
285 {
286     FX_FLOAT aa = m1.a * m2.a + m1.b * m2.c;
287     FX_FLOAT bb = m1.a * m2.b + m1.b * m2.d;
288     FX_FLOAT cc = m1.c * m2.a + m1.d * m2.c;
289     FX_FLOAT dd = m1.c * m2.b + m1.d * m2.d;
290     FX_FLOAT ee = m1.e * m2.a + m1.f * m2.c + m2.e;
291     FX_FLOAT ff = m1.e * m2.b + m1.f * m2.d + m2.f;
292     m.a = aa, m.b = bb, m.c = cc, m.d = dd, m.e = ee, m.f = ff;
293 }
Concat(FX_FLOAT a,FX_FLOAT b,FX_FLOAT c,FX_FLOAT d,FX_FLOAT e,FX_FLOAT f,FX_BOOL bPrepended)294 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)
295 {
296     CFX_Matrix m;
297     m.Set(a, b, c, d, e, f);
298     Concat(m, bPrepended);
299 }
Concat(const CFX_Matrix & m,FX_BOOL bPrepended)300 void CFX_Matrix::Concat(const CFX_Matrix &m, FX_BOOL bPrepended)
301 {
302     if (bPrepended) {
303         FXCRT_Matrix_Concat(*this, m, *this);
304     } else {
305         FXCRT_Matrix_Concat(*this, *this, m);
306     }
307 }
ConcatInverse(const CFX_Matrix & src,FX_BOOL bPrepended)308 void CFX_Matrix::ConcatInverse(const CFX_Matrix& src, FX_BOOL bPrepended)
309 {
310     CFX_Matrix m;
311     m.SetReverse(src);
312     Concat(m, bPrepended);
313 }
IsInvertible() const314 FX_BOOL CFX_Matrix::IsInvertible() const
315 {
316     return FXSYS_fabs(a * d - b * c) >= 0.0001f;
317 }
Is90Rotated() const318 FX_BOOL CFX_Matrix::Is90Rotated() const
319 {
320     return FXSYS_fabs(a * 1000) < FXSYS_fabs(b) && FXSYS_fabs(d * 1000) < FXSYS_fabs(c);
321 }
IsScaled() const322 FX_BOOL CFX_Matrix::IsScaled() const
323 {
324     return FXSYS_fabs(b * 1000) < FXSYS_fabs(a) && FXSYS_fabs(c * 1000) < FXSYS_fabs(d);
325 }
Translate(FX_FLOAT x,FX_FLOAT y,FX_BOOL bPrepended)326 void CFX_Matrix::Translate(FX_FLOAT x, FX_FLOAT y, FX_BOOL bPrepended)
327 {
328     if (bPrepended) {
329         e += x * a + y * c;
330         f += y * d + x * b;
331     } else {
332         e += x, f += y;
333     }
334 }
Scale(FX_FLOAT sx,FX_FLOAT sy,FX_BOOL bPrepended)335 void CFX_Matrix::Scale(FX_FLOAT sx, FX_FLOAT sy, FX_BOOL bPrepended)
336 {
337     a *= sx, d *= sy;
338     if (bPrepended) {
339         b *= sx;
340         c *= sy;
341     } else {
342         b *= sy;
343         c *= sx;
344         e *= sx;
345         f *= sy;
346     }
347 }
Rotate(FX_FLOAT fRadian,FX_BOOL bPrepended)348 void CFX_Matrix::Rotate(FX_FLOAT fRadian, FX_BOOL bPrepended)
349 {
350     FX_FLOAT cosValue = FXSYS_cos(fRadian);
351     FX_FLOAT sinValue = FXSYS_sin(fRadian);
352     CFX_Matrix m;
353     m.Set(cosValue, sinValue, -sinValue, cosValue, 0, 0);
354     if (bPrepended) {
355         FXCRT_Matrix_Concat(*this, m, *this);
356     } else {
357         FXCRT_Matrix_Concat(*this, *this, m);
358     }
359 }
RotateAt(FX_FLOAT fRadian,FX_FLOAT dx,FX_FLOAT dy,FX_BOOL bPrepended)360 void CFX_Matrix::RotateAt(FX_FLOAT fRadian, FX_FLOAT dx, FX_FLOAT dy, FX_BOOL bPrepended)
361 {
362     Translate(dx, dy, bPrepended);
363     Rotate(fRadian, bPrepended);
364     Translate(-dx, -dy, bPrepended);
365 }
Shear(FX_FLOAT fAlphaRadian,FX_FLOAT fBetaRadian,FX_BOOL bPrepended)366 void CFX_Matrix::Shear(FX_FLOAT fAlphaRadian, FX_FLOAT fBetaRadian, FX_BOOL bPrepended)
367 {
368     CFX_Matrix m;
369     m.Set(1, FXSYS_tan(fAlphaRadian), FXSYS_tan(fBetaRadian), 1, 0, 0);
370     if (bPrepended) {
371         FXCRT_Matrix_Concat(*this, m, *this);
372     } else {
373         FXCRT_Matrix_Concat(*this, *this, m);
374     }
375 }
MatchRect(const CFX_FloatRect & dest,const CFX_FloatRect & src)376 void CFX_Matrix::MatchRect(const CFX_FloatRect& dest, const CFX_FloatRect& src)
377 {
378     FX_FLOAT fDiff = src.left - src.right;
379     a = FXSYS_fabs(fDiff) < 0.001f ? 1 : (dest.left - dest.right) / fDiff;
380     fDiff = src.bottom - src.top;
381     d = FXSYS_fabs(fDiff) < 0.001f ? 1 : (dest.bottom - dest.top) / fDiff;
382     e = dest.left - src.left * a;
383     f = dest.bottom - src.bottom * d;
384     b = 0;
385     c = 0;
386 }
GetXUnit() const387 FX_FLOAT CFX_Matrix::GetXUnit() const
388 {
389     if (b == 0) {
390         return (a > 0 ? a : -a);
391     }
392     if (a == 0) {
393         return (b > 0 ? b : -b);
394     }
395     return FXSYS_sqrt(a * a + b * b);
396 }
GetYUnit() const397 FX_FLOAT CFX_Matrix::GetYUnit() const
398 {
399     if (c == 0) {
400         return (d > 0 ? d : -d);
401     }
402     if (d == 0) {
403         return (c > 0 ? c : -c);
404     }
405     return FXSYS_sqrt(c * c + d * d);
406 }
GetUnitRect(CFX_RectF & rect) const407 void CFX_Matrix::GetUnitRect(CFX_RectF &rect) const
408 {
409     rect.left = rect.top = 0;
410     rect.width = rect.height = 1;
411     TransformRect(rect);
412 }
GetUnitRect() const413 CFX_FloatRect CFX_Matrix::GetUnitRect() const
414 {
415     CFX_FloatRect rect(0, 0, 1, 1);
416     rect.Transform((const CFX_Matrix*)this);
417     return rect;
418 }
GetUnitArea() const419 FX_FLOAT CFX_Matrix::GetUnitArea() const
420 {
421     FX_FLOAT A = FXSYS_sqrt(a * a + b * b);
422     FX_FLOAT B = FXSYS_sqrt(c * c + d * d);
423     FX_FLOAT ac = a + c, bd = b + d;
424     FX_FLOAT C = FXSYS_sqrt(ac * ac + bd * bd);
425     FX_FLOAT P = (A + B + C ) / 2;
426     return FXSYS_sqrt(P * (P - A) * (P - B) * (P - C)) * 2;
427 }
TransformXDistance(FX_FLOAT dx) const428 FX_FLOAT CFX_Matrix::TransformXDistance(FX_FLOAT dx) const
429 {
430     FX_FLOAT fx = a * dx, fy = b * dx;
431     return FXSYS_sqrt(fx * fx + fy * fy);
432 }
TransformXDistance(FX_INT32 dx) const433 FX_INT32 CFX_Matrix::TransformXDistance(FX_INT32 dx) const
434 {
435     FX_FLOAT fx = a * dx, fy = b * dx;
436     return FXSYS_round(FXSYS_sqrt(fx * fx + fy * fy));
437 }
TransformYDistance(FX_FLOAT dy) const438 FX_FLOAT CFX_Matrix::TransformYDistance(FX_FLOAT dy) const
439 {
440     FX_FLOAT fx = c * dy, fy = d * dy;
441     return FXSYS_sqrt(fx * fx + fy * fy);
442 }
TransformYDistance(FX_INT32 dy) const443 FX_INT32 CFX_Matrix::TransformYDistance(FX_INT32 dy) const
444 {
445     FX_FLOAT fx = c * dy, fy = d * dy;
446     return FXSYS_round(FXSYS_sqrt(fx * fx + fy * fy));
447 }
TransformDistance(FX_FLOAT dx,FX_FLOAT dy) const448 FX_FLOAT CFX_Matrix::TransformDistance(FX_FLOAT dx, FX_FLOAT dy) const
449 {
450     FX_FLOAT fx = a * dx + c * dy, fy = b * dx + d * dy;
451     return FXSYS_sqrt(fx * fx + fy * fy);
452 }
TransformDistance(FX_INT32 dx,FX_INT32 dy) const453 FX_INT32 CFX_Matrix::TransformDistance(FX_INT32 dx, FX_INT32 dy) const
454 {
455     FX_FLOAT fx = a * dx + c * dy, fy = b * dx + d * dy;
456     return FXSYS_round(FXSYS_sqrt(fx * fx + fy * fy));
457 }
TransformDistance(FX_FLOAT distance) const458 FX_FLOAT CFX_Matrix::TransformDistance(FX_FLOAT distance) const
459 {
460     return distance * (GetXUnit() + GetYUnit()) / 2;
461 }
TransformVector(CFX_VectorF & v) const462 void CFX_Matrix::TransformVector(CFX_VectorF &v) const
463 {
464     FX_FLOAT fx = a * v.x + c * v.y;
465     FX_FLOAT fy = b * v.x + d * v.y;
466     v.x = fx, v.y = fy;
467 }
TransformVector(CFX_Vector & v) const468 void CFX_Matrix::TransformVector(CFX_Vector &v) const
469 {
470     FX_FLOAT fx = a * v.x + c * v.y;
471     FX_FLOAT fy = b * v.x + d * v.y;
472     v.x = FXSYS_round(fx);
473     v.y = FXSYS_round(fy);
474 }
TransformPoints(CFX_Point * points,FX_INT32 iCount) const475 void CFX_Matrix::TransformPoints(CFX_Point *points, FX_INT32 iCount) const
476 {
477     FXSYS_assert(iCount > 0);
478     FX_FLOAT fx, fy;
479     for (FX_INT32 i = 0; i < iCount; i ++) {
480         fx = a * points->x + c * points->y + e;
481         fy = b * points->x + d * points->y + f;
482         points->x = FXSYS_round(fx);
483         points->y = FXSYS_round(fy);
484         points ++;
485     }
486 }
TransformPoints(CFX_PointF * points,FX_INT32 iCount) const487 void CFX_Matrix::TransformPoints(CFX_PointF *points, FX_INT32 iCount) const
488 {
489     FXSYS_assert(iCount > 0);
490     FX_FLOAT fx, fy;
491     for (FX_INT32 i = 0; i < iCount; i ++) {
492         fx = a * points->x + c * points->y + e;
493         fy = b * points->x + d * points->y + f;
494         points->x = fx, points->y = fy;
495         points ++;
496     }
497 }
TransformPoint(FX_FLOAT & x,FX_FLOAT & y) const498 void CFX_Matrix::TransformPoint(FX_FLOAT &x, FX_FLOAT &y) const
499 {
500     FX_FLOAT fx = a * x + c * y + e;
501     FX_FLOAT fy = b * x + d * y + f;
502     x = fx, y = fy;
503 }
TransformPoint(FX_INT32 & x,FX_INT32 & y) const504 void CFX_Matrix::TransformPoint(FX_INT32 &x, FX_INT32 &y) const
505 {
506     FX_FLOAT fx = a * x + c * y + e;
507     FX_FLOAT fy = b * x + d * y + f;
508     x = FXSYS_round(fx);
509     y = FXSYS_round(fy);
510 }
TransformRect(CFX_RectF & rect) const511 void CFX_Matrix::TransformRect(CFX_RectF &rect) const
512 {
513     FX_FLOAT right = rect.right(), bottom = rect.bottom();
514     TransformRect(rect.left, right, bottom, rect.top);
515     rect.width = right - rect.left;
516     rect.height = bottom - rect.top;
517 }
TransformRect(CFX_Rect & rect) const518 void CFX_Matrix::TransformRect(CFX_Rect &rect) const
519 {
520     FX_FLOAT left = (FX_FLOAT)rect.left;
521     FX_FLOAT top = (FX_FLOAT)rect.bottom();
522     FX_FLOAT right = (FX_FLOAT)rect.right();
523     FX_FLOAT bottom = (FX_FLOAT)rect.top;
524     TransformRect(left, right, top, bottom);
525     rect.left = FXSYS_round(left);
526     rect.top = FXSYS_round(bottom);
527     rect.width = FXSYS_round(right - left);
528     rect.height = FXSYS_round(top - bottom);
529 }
TransformRect(FX_FLOAT & left,FX_FLOAT & right,FX_FLOAT & top,FX_FLOAT & bottom) const530 void CFX_Matrix::TransformRect(FX_FLOAT& left, FX_FLOAT& right, FX_FLOAT& top, FX_FLOAT& bottom) const
531 {
532     FX_FLOAT x[4], y[4];
533     x[0] = left;
534     y[0] = top;
535     x[1] = left;
536     y[1] = bottom;
537     x[2] = right;
538     y[2] = top;
539     x[3] = right;
540     y[3] = bottom;
541     int i;
542     for (i = 0; i < 4; i ++) {
543         Transform(x[i], y[i], x[i], y[i]);
544     }
545     right = left = x[0];
546     top = bottom = y[0];
547     for (i = 1; i < 4; i ++) {
548         if (right < x[i]) {
549             right = x[i];
550         }
551         if (left > x[i]) {
552             left = x[i];
553         }
554         if (top < y[i]) {
555             top = y[i];
556         }
557         if (bottom > y[i]) {
558             bottom = y[i];
559         }
560     }
561 }
562