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