• 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 "core/fxcrt/fx_coordinates.h"
8 
9 #include <algorithm>
10 #include <utility>
11 
12 #include "core/fxcrt/fx_extension.h"
13 
14 namespace {
15 
MatchFloatRange(float f1,float f2,int * i1,int * i2)16 void MatchFloatRange(float f1, float f2, int* i1, int* i2) {
17   int length = static_cast<int>(ceil(f2 - f1));
18   int i1_1 = static_cast<int>(floor(f1));
19   int i1_2 = static_cast<int>(ceil(f1));
20   float error1 = f1 - i1_1 + fabsf(f2 - i1_1 - length);
21   float error2 = i1_2 - f1 + fabsf(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     std::swap(left, right);
32   if (top > bottom)
33     std::swap(top, bottom);
34 }
35 
Intersect(const FX_RECT & src)36 void FX_RECT::Intersect(const FX_RECT& src) {
37   FX_RECT src_n = src;
38   src_n.Normalize();
39   Normalize();
40   left = std::max(left, src_n.left);
41   top = std::max(top, src_n.top);
42   right = std::min(right, src_n.right);
43   bottom = std::min(bottom, src_n.bottom);
44   if (left > right || top > bottom) {
45     left = top = right = bottom = 0;
46   }
47 }
48 
CFX_FloatRect(const FX_RECT & rect)49 CFX_FloatRect::CFX_FloatRect(const FX_RECT& rect) {
50   left = rect.left;
51   top = rect.bottom;
52   right = rect.right;
53   bottom = rect.top;
54 }
55 
56 // static
GetBBox(const CFX_PointF * pPoints,int nPoints)57 CFX_FloatRect CFX_FloatRect::GetBBox(const CFX_PointF* pPoints, int nPoints) {
58   if (nPoints == 0)
59     return CFX_FloatRect();
60 
61   float min_x = pPoints->x;
62   float max_x = pPoints->x;
63   float min_y = pPoints->y;
64   float max_y = pPoints->y;
65   for (int i = 1; i < nPoints; i++) {
66     min_x = std::min(min_x, pPoints[i].x);
67     max_x = std::max(max_x, pPoints[i].x);
68     min_y = std::min(min_y, pPoints[i].y);
69     max_y = std::max(max_y, pPoints[i].y);
70   }
71   return CFX_FloatRect(min_x, min_y, max_x, max_y);
72 }
73 
Normalize()74 void CFX_FloatRect::Normalize() {
75   if (left > right)
76     std::swap(left, right);
77   if (bottom > top)
78     std::swap(top, bottom);
79 }
80 
Reset()81 void CFX_FloatRect::Reset() {
82   left = 0.0f;
83   right = 0.0f;
84   bottom = 0.0f;
85   top = 0.0f;
86 }
87 
Intersect(const CFX_FloatRect & other_rect)88 void CFX_FloatRect::Intersect(const CFX_FloatRect& other_rect) {
89   Normalize();
90   CFX_FloatRect other = other_rect;
91   other.Normalize();
92   left = std::max(left, other.left);
93   bottom = std::max(bottom, other.bottom);
94   right = std::min(right, other.right);
95   top = std::min(top, other.top);
96   if (left > right || bottom > top)
97     Reset();
98 }
99 
Union(const CFX_FloatRect & other_rect)100 void CFX_FloatRect::Union(const CFX_FloatRect& other_rect) {
101   Normalize();
102   CFX_FloatRect other = other_rect;
103   other.Normalize();
104   left = std::min(left, other.left);
105   bottom = std::min(bottom, other.bottom);
106   right = std::max(right, other.right);
107   top = std::max(top, other.top);
108 }
109 
GetOuterRect() const110 FX_RECT CFX_FloatRect::GetOuterRect() const {
111   FX_RECT rect;
112   rect.left = static_cast<int>(floor(left));
113   rect.bottom = static_cast<int>(ceil(top));
114   rect.right = static_cast<int>(ceil(right));
115   rect.top = static_cast<int>(floor(bottom));
116   rect.Normalize();
117   return rect;
118 }
119 
GetInnerRect() const120 FX_RECT CFX_FloatRect::GetInnerRect() const {
121   FX_RECT rect;
122   rect.left = static_cast<int>(ceil(left));
123   rect.bottom = static_cast<int>(floor(top));
124   rect.right = static_cast<int>(floor(right));
125   rect.top = static_cast<int>(ceil(bottom));
126   rect.Normalize();
127   return rect;
128 }
129 
GetClosestRect() const130 FX_RECT CFX_FloatRect::GetClosestRect() const {
131   FX_RECT rect;
132   MatchFloatRange(left, right, &rect.left, &rect.right);
133   MatchFloatRange(bottom, top, &rect.top, &rect.bottom);
134   rect.Normalize();
135   return rect;
136 }
137 
GetCenterSquare() const138 CFX_FloatRect CFX_FloatRect::GetCenterSquare() const {
139   float fWidth = right - left;
140   float fHeight = top - bottom;
141   float fHalfWidth = (fWidth > fHeight) ? fHeight / 2 : fWidth / 2;
142 
143   float fCenterX = (left + right) / 2.0f;
144   float fCenterY = (top + bottom) / 2.0f;
145   return CFX_FloatRect(fCenterX - fHalfWidth, fCenterY - fHalfWidth,
146                        fCenterX + fHalfWidth, fCenterY + fHalfWidth);
147 }
148 
Contains(const CFX_PointF & point) const149 bool CFX_FloatRect::Contains(const CFX_PointF& point) const {
150   CFX_FloatRect n1(*this);
151   n1.Normalize();
152   return point.x <= n1.right && point.x >= n1.left && point.y <= n1.top &&
153          point.y >= n1.bottom;
154 }
155 
Contains(const CFX_FloatRect & other_rect) const156 bool CFX_FloatRect::Contains(const CFX_FloatRect& other_rect) const {
157   CFX_FloatRect n1(*this);
158   CFX_FloatRect n2(other_rect);
159   n1.Normalize();
160   n2.Normalize();
161   return n2.left >= n1.left && n2.right <= n1.right && n2.bottom >= n1.bottom &&
162          n2.top <= n1.top;
163 }
164 
UpdateRect(const CFX_PointF & point)165 void CFX_FloatRect::UpdateRect(const CFX_PointF& point) {
166   left = std::min(left, point.x);
167   bottom = std::min(bottom, point.y);
168   right = std::max(right, point.x);
169   top = std::max(top, point.y);
170 }
171 
Scale(float fScale)172 void CFX_FloatRect::Scale(float fScale) {
173   left *= fScale;
174   bottom *= fScale;
175   right *= fScale;
176   top *= fScale;
177 }
178 
ScaleFromCenterPoint(float fScale)179 void CFX_FloatRect::ScaleFromCenterPoint(float fScale) {
180   float fHalfWidth = (right - left) / 2.0f;
181   float fHalfHeight = (top - bottom) / 2.0f;
182 
183   float center_x = (left + right) / 2;
184   float center_y = (top + bottom) / 2;
185 
186   left = center_x - fHalfWidth * fScale;
187   bottom = center_y - fHalfHeight * fScale;
188   right = center_x + fHalfWidth * fScale;
189   top = center_y + fHalfHeight * fScale;
190 }
191 
ToFxRect() const192 FX_RECT CFX_FloatRect::ToFxRect() const {
193   return FX_RECT(static_cast<int>(left), static_cast<int>(top),
194                  static_cast<int>(right), static_cast<int>(bottom));
195 }
196 
ToRoundedFxRect() const197 FX_RECT CFX_FloatRect::ToRoundedFxRect() const {
198   return FX_RECT(FXSYS_round(left), FXSYS_round(top), FXSYS_round(right),
199                  FXSYS_round(bottom));
200 }
201 
202 #ifndef NDEBUG
operator <<(std::ostream & os,const CFX_FloatRect & rect)203 std::ostream& operator<<(std::ostream& os, const CFX_FloatRect& rect) {
204   os << "rect[" << rect.Width() << "x" << rect.Height() << " (" << rect.left
205      << ", " << rect.bottom << ")]";
206   return os;
207 }
208 #endif
209 
GetInverse() const210 CFX_Matrix CFX_Matrix::GetInverse() const {
211   CFX_Matrix inverse;
212   float i = a * d - b * c;
213   if (fabs(i) == 0)
214     return inverse;
215 
216   float j = -i;
217   inverse.a = d / i;
218   inverse.b = b / j;
219   inverse.c = c / j;
220   inverse.d = a / i;
221   inverse.e = (c * f - d * e) / i;
222   inverse.f = (a * f - b * e) / j;
223   return inverse;
224 }
225 
Concat(const CFX_Matrix & m,bool bPrepended)226 void CFX_Matrix::Concat(const CFX_Matrix& m, bool bPrepended) {
227   ConcatInternal(m, bPrepended);
228 }
229 
ConcatInverse(const CFX_Matrix & src,bool bPrepended)230 void CFX_Matrix::ConcatInverse(const CFX_Matrix& src, bool bPrepended) {
231   Concat(src.GetInverse(), bPrepended);
232 }
233 
Is90Rotated() const234 bool CFX_Matrix::Is90Rotated() const {
235   return fabs(a * 1000) < fabs(b) && fabs(d * 1000) < fabs(c);
236 }
237 
IsScaled() const238 bool CFX_Matrix::IsScaled() const {
239   return fabs(b * 1000) < fabs(a) && fabs(c * 1000) < fabs(d);
240 }
241 
Translate(float x,float y,bool bPrepended)242 void CFX_Matrix::Translate(float x, float y, bool bPrepended) {
243   if (bPrepended) {
244     e += x * a + y * c;
245     f += y * d + x * b;
246     return;
247   }
248   e += x;
249   f += y;
250 }
251 
Scale(float sx,float sy,bool bPrepended)252 void CFX_Matrix::Scale(float sx, float sy, bool bPrepended) {
253   a *= sx;
254   d *= sy;
255   if (bPrepended) {
256     b *= sx;
257     c *= sy;
258     return;
259   }
260 
261   b *= sy;
262   c *= sx;
263   e *= sx;
264   f *= sy;
265 }
266 
Rotate(float fRadian,bool bPrepended)267 void CFX_Matrix::Rotate(float fRadian, bool bPrepended) {
268   float cosValue = cos(fRadian);
269   float sinValue = sin(fRadian);
270   ConcatInternal(CFX_Matrix(cosValue, sinValue, -sinValue, cosValue, 0, 0),
271                  bPrepended);
272 }
273 
RotateAt(float fRadian,float dx,float dy,bool bPrepended)274 void CFX_Matrix::RotateAt(float fRadian, float dx, float dy, bool bPrepended) {
275   Translate(dx, dy, bPrepended);
276   Rotate(fRadian, bPrepended);
277   Translate(-dx, -dy, bPrepended);
278 }
279 
Shear(float fAlphaRadian,float fBetaRadian,bool bPrepended)280 void CFX_Matrix::Shear(float fAlphaRadian, float fBetaRadian, bool bPrepended) {
281   ConcatInternal(CFX_Matrix(1, tan(fAlphaRadian), tan(fBetaRadian), 1, 0, 0),
282                  bPrepended);
283 }
284 
MatchRect(const CFX_FloatRect & dest,const CFX_FloatRect & src)285 void CFX_Matrix::MatchRect(const CFX_FloatRect& dest,
286                            const CFX_FloatRect& src) {
287   float fDiff = src.left - src.right;
288   a = fabs(fDiff) < 0.001f ? 1 : (dest.left - dest.right) / fDiff;
289 
290   fDiff = src.bottom - src.top;
291   d = fabs(fDiff) < 0.001f ? 1 : (dest.bottom - dest.top) / fDiff;
292   e = dest.left - src.left * a;
293   f = dest.bottom - src.bottom * d;
294   b = 0;
295   c = 0;
296 }
297 
GetXUnit() const298 float CFX_Matrix::GetXUnit() const {
299   if (b == 0)
300     return (a > 0 ? a : -a);
301   if (a == 0)
302     return (b > 0 ? b : -b);
303   return sqrt(a * a + b * b);
304 }
305 
GetYUnit() const306 float CFX_Matrix::GetYUnit() const {
307   if (c == 0)
308     return (d > 0 ? d : -d);
309   if (d == 0)
310     return (c > 0 ? c : -c);
311   return sqrt(c * c + d * d);
312 }
313 
GetUnitRect() const314 CFX_FloatRect CFX_Matrix::GetUnitRect() const {
315   return TransformRect(CFX_FloatRect(0.f, 0.f, 1.f, 1.f));
316 }
317 
TransformXDistance(float dx) const318 float CFX_Matrix::TransformXDistance(float dx) const {
319   float fx = a * dx;
320   float fy = b * dx;
321   return sqrt(fx * fx + fy * fy);
322 }
323 
TransformDistance(float distance) const324 float CFX_Matrix::TransformDistance(float distance) const {
325   return distance * (GetXUnit() + GetYUnit()) / 2;
326 }
327 
Transform(const CFX_PointF & point) const328 CFX_PointF CFX_Matrix::Transform(const CFX_PointF& point) const {
329   return CFX_PointF(a * point.x + c * point.y + e,
330                     b * point.x + d * point.y + f);
331 }
TransformRect(const float & left,const float & right,const float & top,const float & bottom) const332 std::tuple<float, float, float, float> CFX_Matrix::TransformRect(
333     const float& left,
334     const float& right,
335     const float& top,
336     const float& bottom) const {
337   CFX_PointF points[] = {
338       {left, top}, {left, bottom}, {right, top}, {right, bottom}};
339   for (int i = 0; i < 4; i++)
340     points[i] = Transform(points[i]);
341 
342   float new_right = points[0].x;
343   float new_left = points[0].x;
344   float new_top = points[0].y;
345   float new_bottom = points[0].y;
346   for (int i = 1; i < 4; i++) {
347     new_right = std::max(new_right, points[i].x);
348     new_left = std::min(new_left, points[i].x);
349     new_top = std::max(new_top, points[i].y);
350     new_bottom = std::min(new_bottom, points[i].y);
351   }
352   return std::make_tuple(new_left, new_right, new_top, new_bottom);
353 }
354 
TransformRect(const CFX_RectF & rect) const355 CFX_RectF CFX_Matrix::TransformRect(const CFX_RectF& rect) const {
356   float left;
357   float right;
358   float bottom;
359   float top;
360   std::tie(left, right, bottom, top) =
361       TransformRect(rect.left, rect.right(), rect.bottom(), rect.top);
362   return CFX_RectF(left, top, right - left, bottom - top);
363 }
364 
TransformRect(const CFX_FloatRect & rect) const365 CFX_FloatRect CFX_Matrix::TransformRect(const CFX_FloatRect& rect) const {
366   float left;
367   float right;
368   float top;
369   float bottom;
370   std::tie(left, right, top, bottom) =
371       TransformRect(rect.left, rect.right, rect.top, rect.bottom);
372   return CFX_FloatRect(left, bottom, right, top);
373 }
374 
ConcatInternal(const CFX_Matrix & other,bool prepend)375 void CFX_Matrix::ConcatInternal(const CFX_Matrix& other, bool prepend) {
376   CFX_Matrix left;
377   CFX_Matrix right;
378   if (prepend) {
379     left = other;
380     right = *this;
381   } else {
382     left = *this;
383     right = other;
384   }
385 
386   a = left.a * right.a + left.b * right.c;
387   b = left.a * right.b + left.b * right.d;
388   c = left.c * right.a + left.d * right.c;
389   d = left.c * right.b + left.d * right.d;
390   e = left.e * right.a + left.f * right.c + right.e;
391   f = left.e * right.b + left.f * right.d + right.f;
392 }
393