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