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 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 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 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 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 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 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 81 void CFX_FloatRect::Reset() { 82 left = 0.0f; 83 right = 0.0f; 84 bottom = 0.0f; 85 top = 0.0f; 86 } 87 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 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 110 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 120 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 130 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 138 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 149 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 156 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 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 172 void CFX_FloatRect::Scale(float fScale) { 173 left *= fScale; 174 bottom *= fScale; 175 right *= fScale; 176 top *= fScale; 177 } 178 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 192 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 197 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 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 210 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 226 void CFX_Matrix::Concat(const CFX_Matrix& m, bool bPrepended) { 227 ConcatInternal(m, bPrepended); 228 } 229 230 void CFX_Matrix::ConcatInverse(const CFX_Matrix& src, bool bPrepended) { 231 Concat(src.GetInverse(), bPrepended); 232 } 233 234 bool CFX_Matrix::Is90Rotated() const { 235 return fabs(a * 1000) < fabs(b) && fabs(d * 1000) < fabs(c); 236 } 237 238 bool CFX_Matrix::IsScaled() const { 239 return fabs(b * 1000) < fabs(a) && fabs(c * 1000) < fabs(d); 240 } 241 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 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 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 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 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 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 298 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 306 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 314 CFX_FloatRect CFX_Matrix::GetUnitRect() const { 315 return TransformRect(CFX_FloatRect(0.f, 0.f, 1.f, 1.f)); 316 } 317 318 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 324 float CFX_Matrix::TransformDistance(float distance) const { 325 return distance * (GetXUnit() + GetYUnit()) / 2; 326 } 327 328 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 } 332 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 355 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 365 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 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