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 #ifndef CORE_FXCRT_FX_COORDINATES_H_ 8 #define CORE_FXCRT_FX_COORDINATES_H_ 9 10 #include <algorithm> 11 12 #include "core/fxcrt/fx_system.h" 13 #include "third_party/base/numerics/safe_math.h" 14 15 #ifndef NDEBUG 16 #include <ostream> 17 #endif 18 19 template <class BaseType> 20 class CFX_PTemplate { 21 public: CFX_PTemplate()22 CFX_PTemplate() : x(0), y(0) {} CFX_PTemplate(BaseType new_x,BaseType new_y)23 CFX_PTemplate(BaseType new_x, BaseType new_y) : x(new_x), y(new_y) {} CFX_PTemplate(const CFX_PTemplate & other)24 CFX_PTemplate(const CFX_PTemplate& other) : x(other.x), y(other.y) {} 25 26 CFX_PTemplate& operator=(const CFX_PTemplate& other) { 27 if (this != &other) { 28 x = other.x; 29 y = other.y; 30 } 31 return *this; 32 } 33 bool operator==(const CFX_PTemplate& other) const { 34 return x == other.x && y == other.y; 35 } 36 bool operator!=(const CFX_PTemplate& other) const { 37 return !(*this == other); 38 } 39 CFX_PTemplate& operator+=(const CFX_PTemplate<BaseType>& obj) { 40 x += obj.x; 41 y += obj.y; 42 return *this; 43 } 44 CFX_PTemplate& operator-=(const CFX_PTemplate<BaseType>& obj) { 45 x -= obj.x; 46 y -= obj.y; 47 return *this; 48 } 49 CFX_PTemplate operator+(const CFX_PTemplate& other) const { 50 return CFX_PTemplate(x + other.x, y + other.y); 51 } 52 CFX_PTemplate operator-(const CFX_PTemplate& other) const { 53 return CFX_PTemplate(x - other.x, y - other.y); 54 } 55 56 BaseType x; 57 BaseType y; 58 }; 59 using CFX_Point = CFX_PTemplate<int32_t>; 60 using CFX_PointF = CFX_PTemplate<float>; 61 62 template <class BaseType> 63 class CFX_STemplate { 64 public: CFX_STemplate()65 CFX_STemplate() : width(0), height(0) {} 66 CFX_STemplate(BaseType new_width,BaseType new_height)67 CFX_STemplate(BaseType new_width, BaseType new_height) 68 : width(new_width), height(new_height) {} 69 CFX_STemplate(const CFX_STemplate & other)70 CFX_STemplate(const CFX_STemplate& other) 71 : width(other.width), height(other.height) {} 72 73 template <typename OtherType> As()74 CFX_STemplate<OtherType> As() const { 75 return CFX_STemplate<OtherType>(static_cast<OtherType>(width), 76 static_cast<OtherType>(height)); 77 } 78 clear()79 void clear() { 80 width = 0; 81 height = 0; 82 } 83 CFX_STemplate& operator=(const CFX_STemplate& other) { 84 if (this != &other) { 85 width = other.width; 86 height = other.height; 87 } 88 return *this; 89 } 90 bool operator==(const CFX_STemplate& other) const { 91 return width == other.width && height == other.height; 92 } 93 bool operator!=(const CFX_STemplate& other) const { 94 return !(*this == other); 95 } 96 CFX_STemplate& operator+=(const CFX_STemplate<BaseType>& obj) { 97 width += obj.width; 98 height += obj.height; 99 return *this; 100 } 101 CFX_STemplate& operator-=(const CFX_STemplate<BaseType>& obj) { 102 width -= obj.width; 103 height -= obj.height; 104 return *this; 105 } 106 CFX_STemplate& operator*=(BaseType factor) { 107 width *= factor; 108 height *= factor; 109 return *this; 110 } 111 CFX_STemplate& operator/=(BaseType divisor) { 112 width /= divisor; 113 height /= divisor; 114 return *this; 115 } 116 CFX_STemplate operator+(const CFX_STemplate& other) const { 117 return CFX_STemplate(width + other.width, height + other.height); 118 } 119 CFX_STemplate operator-(const CFX_STemplate& other) const { 120 return CFX_STemplate(width - other.width, height - other.height); 121 } 122 CFX_STemplate operator*(BaseType factor) const { 123 return CFX_STemplate(width * factor, height * factor); 124 } 125 CFX_STemplate operator/(BaseType divisor) const { 126 return CFX_STemplate(width / divisor, height / divisor); 127 } 128 129 BaseType width; 130 BaseType height; 131 }; 132 using CFX_Size = CFX_STemplate<int32_t>; 133 using CFX_SizeF = CFX_STemplate<float>; 134 135 template <class BaseType> 136 class CFX_VTemplate final : public CFX_PTemplate<BaseType> { 137 public: 138 using CFX_PTemplate<BaseType>::x; 139 using CFX_PTemplate<BaseType>::y; 140 CFX_VTemplate()141 CFX_VTemplate() : CFX_PTemplate<BaseType>() {} CFX_VTemplate(BaseType new_x,BaseType new_y)142 CFX_VTemplate(BaseType new_x, BaseType new_y) 143 : CFX_PTemplate<BaseType>(new_x, new_y) {} 144 CFX_VTemplate(const CFX_VTemplate & other)145 CFX_VTemplate(const CFX_VTemplate& other) : CFX_PTemplate<BaseType>(other) {} 146 CFX_VTemplate(const CFX_PTemplate<BaseType> & point1,const CFX_PTemplate<BaseType> & point2)147 CFX_VTemplate(const CFX_PTemplate<BaseType>& point1, 148 const CFX_PTemplate<BaseType>& point2) 149 : CFX_PTemplate<BaseType>(point2.x - point1.x, point2.y - point1.y) {} 150 Length()151 float Length() const { return sqrt(x * x + y * y); } Normalize()152 void Normalize() { 153 float fLen = Length(); 154 if (fLen < 0.0001f) 155 return; 156 157 x /= fLen; 158 y /= fLen; 159 } Translate(BaseType dx,BaseType dy)160 void Translate(BaseType dx, BaseType dy) { 161 x += dx; 162 y += dy; 163 } Scale(BaseType sx,BaseType sy)164 void Scale(BaseType sx, BaseType sy) { 165 x *= sx; 166 y *= sy; 167 } Rotate(float fRadian)168 void Rotate(float fRadian) { 169 float cosValue = cos(fRadian); 170 float sinValue = sin(fRadian); 171 x = x * cosValue - y * sinValue; 172 y = x * sinValue + y * cosValue; 173 } 174 }; 175 using CFX_Vector = CFX_VTemplate<int32_t>; 176 using CFX_VectorF = CFX_VTemplate<float>; 177 178 // Rectangles. 179 // TODO(tsepez): Consolidate all these different rectangle classes. 180 181 // LTRB rectangles (y-axis runs downwards). 182 // Struct layout is compatible with win32 RECT. 183 struct FX_RECT { 184 FX_RECT() = default; FX_RECTFX_RECT185 FX_RECT(int l, int t, int r, int b) : left(l), top(t), right(r), bottom(b) {} 186 WidthFX_RECT187 int Width() const { return right - left; } HeightFX_RECT188 int Height() const { return bottom - top; } IsEmptyFX_RECT189 bool IsEmpty() const { return right <= left || bottom <= top; } 190 ValidFX_RECT191 bool Valid() const { 192 pdfium::base::CheckedNumeric<int> w = right; 193 pdfium::base::CheckedNumeric<int> h = bottom; 194 w -= left; 195 h -= top; 196 return w.IsValid() && h.IsValid(); 197 } 198 199 void Normalize(); 200 void Intersect(const FX_RECT& src); IntersectFX_RECT201 void Intersect(int l, int t, int r, int b) { Intersect(FX_RECT(l, t, r, b)); } 202 OffsetFX_RECT203 void Offset(int dx, int dy) { 204 left += dx; 205 right += dx; 206 top += dy; 207 bottom += dy; 208 } 209 210 bool operator==(const FX_RECT& src) const { 211 return left == src.left && right == src.right && top == src.top && 212 bottom == src.bottom; 213 } 214 ContainsFX_RECT215 bool Contains(int x, int y) const { 216 return x >= left && x < right && y >= top && y < bottom; 217 } 218 219 int32_t left = 0; 220 int32_t top = 0; 221 int32_t right = 0; 222 int32_t bottom = 0; 223 }; 224 225 // LTRB rectangles (y-axis runs upwards). 226 class CFX_FloatRect { 227 public: 228 constexpr CFX_FloatRect() = default; CFX_FloatRect(float l,float b,float r,float t)229 constexpr CFX_FloatRect(float l, float b, float r, float t) 230 : left(l), bottom(b), right(r), top(t) {} 231 CFX_FloatRect(const float * pArray)232 explicit CFX_FloatRect(const float* pArray) 233 : CFX_FloatRect(pArray[0], pArray[1], pArray[2], pArray[3]) {} 234 235 explicit CFX_FloatRect(const FX_RECT& rect); 236 237 static CFX_FloatRect GetBBox(const CFX_PointF* pPoints, int nPoints); 238 239 void Normalize(); 240 IsEmpty()241 bool IsEmpty() const { return left >= right || bottom >= top; } 242 bool Contains(const CFX_PointF& point) const; 243 bool Contains(const CFX_FloatRect& other_rect) const; 244 245 void Intersect(const CFX_FloatRect& other_rect); 246 void Union(const CFX_FloatRect& other_rect); 247 248 // These may be better at rounding than ToFxRect() and friends. 249 // 250 // Returned rect has bounds rounded up/down such that it is contained in the 251 // original. 252 FX_RECT GetInnerRect() const; 253 254 // Returned rect has bounds rounded up/down such that the original is 255 // contained in it. 256 FX_RECT GetOuterRect() const; 257 258 // Returned rect has bounds rounded up/down such that the dimensions are 259 // rounded up and the sum of the error in the bounds is minimized. 260 FX_RECT GetClosestRect() const; 261 262 CFX_FloatRect GetCenterSquare() const; 263 InitRect(const CFX_PointF & point)264 void InitRect(const CFX_PointF& point) { 265 left = point.x; 266 right = point.x; 267 bottom = point.y; 268 top = point.y; 269 } 270 void UpdateRect(const CFX_PointF& point); 271 Width()272 float Width() const { return right - left; } Height()273 float Height() const { return top - bottom; } Left()274 float Left() const { return left; } Bottom()275 float Bottom() const { return bottom; } Right()276 float Right() const { return right; } Top()277 float Top() const { return top; } 278 279 void Inflate(float x, float y); 280 void Inflate(float other_left, 281 float other_bottom, 282 float other_right, 283 float other_top); 284 void Inflate(const CFX_FloatRect& rt); 285 286 void Deflate(float x, float y); 287 void Deflate(float other_left, 288 float other_bottom, 289 float other_right, 290 float other_top); 291 void Deflate(const CFX_FloatRect& rt); 292 293 CFX_FloatRect GetDeflated(float x, float y) const; 294 295 void Translate(float e, float f); 296 297 void Scale(float fScale); 298 void ScaleFromCenterPoint(float fScale); 299 300 // GetInnerRect() and friends may be better at rounding than these methods. 301 // Unlike the methods above, these two blindly floor / round the LBRT values. 302 // Doing so may introduce rounding errors that are visible to users as 303 // off-by-one pixels/lines. 304 // 305 // Floors LBRT values. 306 FX_RECT ToFxRect() const; 307 308 // Rounds LBRT values. 309 FX_RECT ToRoundedFxRect() const; 310 311 float left = 0.0f; 312 float bottom = 0.0f; 313 float right = 0.0f; 314 float top = 0.0f; 315 }; 316 317 #ifndef NDEBUG 318 std::ostream& operator<<(std::ostream& os, const CFX_FloatRect& rect); 319 #endif 320 321 // LTWH rectangles (y-axis runs downwards). 322 class CFX_RectF { 323 public: 324 using PointType = CFX_PointF; 325 using SizeType = CFX_SizeF; 326 327 CFX_RectF() = default; CFX_RectF(float dst_left,float dst_top,float dst_width,float dst_height)328 CFX_RectF(float dst_left, float dst_top, float dst_width, float dst_height) 329 : left(dst_left), top(dst_top), width(dst_width), height(dst_height) {} CFX_RectF(float dst_left,float dst_top,const SizeType & dst_size)330 CFX_RectF(float dst_left, float dst_top, const SizeType& dst_size) 331 : left(dst_left), 332 top(dst_top), 333 width(dst_size.width), 334 height(dst_size.height) {} CFX_RectF(const PointType & p,float dst_width,float dst_height)335 CFX_RectF(const PointType& p, float dst_width, float dst_height) 336 : left(p.x), top(p.y), width(dst_width), height(dst_height) {} CFX_RectF(const PointType & p1,const SizeType & s2)337 CFX_RectF(const PointType& p1, const SizeType& s2) 338 : left(p1.x), top(p1.y), width(s2.width), height(s2.height) {} CFX_RectF(const FX_RECT & that)339 explicit CFX_RectF(const FX_RECT& that) 340 : left(static_cast<float>(that.left)), 341 top(static_cast<float>(that.top)), 342 width(static_cast<float>(that.Width())), 343 height(static_cast<float>(that.Height())) {} 344 345 // NOLINTNEXTLINE(runtime/explicit) 346 CFX_RectF(const CFX_RectF& other) = default; 347 348 CFX_RectF& operator+=(const PointType& p) { 349 left += p.x; 350 top += p.y; 351 return *this; 352 } 353 CFX_RectF& operator-=(const PointType& p) { 354 left -= p.x; 355 top -= p.y; 356 return *this; 357 } right()358 float right() const { return left + width; } bottom()359 float bottom() const { return top + height; } Normalize()360 void Normalize() { 361 if (width < 0) { 362 left += width; 363 width = -width; 364 } 365 if (height < 0) { 366 top += height; 367 height = -height; 368 } 369 } Offset(float dx,float dy)370 void Offset(float dx, float dy) { 371 left += dx; 372 top += dy; 373 } Inflate(float x,float y)374 void Inflate(float x, float y) { 375 left -= x; 376 width += x * 2; 377 top -= y; 378 height += y * 2; 379 } Inflate(const PointType & p)380 void Inflate(const PointType& p) { Inflate(p.x, p.y); } Inflate(float off_left,float off_top,float off_right,float off_bottom)381 void Inflate(float off_left, 382 float off_top, 383 float off_right, 384 float off_bottom) { 385 left -= off_left; 386 top -= off_top; 387 width += off_left + off_right; 388 height += off_top + off_bottom; 389 } Inflate(const CFX_RectF & rt)390 void Inflate(const CFX_RectF& rt) { 391 Inflate(rt.left, rt.top, rt.left + rt.width, rt.top + rt.height); 392 } Deflate(float x,float y)393 void Deflate(float x, float y) { 394 left += x; 395 width -= x * 2; 396 top += y; 397 height -= y * 2; 398 } Deflate(const PointType & p)399 void Deflate(const PointType& p) { Deflate(p.x, p.y); } Deflate(float off_left,float off_top,float off_right,float off_bottom)400 void Deflate(float off_left, 401 float off_top, 402 float off_right, 403 float off_bottom) { 404 left += off_left; 405 top += off_top; 406 width -= off_left + off_right; 407 height -= off_top + off_bottom; 408 } Deflate(const CFX_RectF & rt)409 void Deflate(const CFX_RectF& rt) { 410 Deflate(rt.left, rt.top, rt.top + rt.width, rt.top + rt.height); 411 } IsEmpty()412 bool IsEmpty() const { return width <= 0 || height <= 0; } IsEmpty(float fEpsilon)413 bool IsEmpty(float fEpsilon) const { 414 return width <= fEpsilon || height <= fEpsilon; 415 } Empty()416 void Empty() { width = height = 0; } Contains(const PointType & p)417 bool Contains(const PointType& p) const { 418 return p.x >= left && p.x < left + width && p.y >= top && 419 p.y < top + height; 420 } Contains(const CFX_RectF & rt)421 bool Contains(const CFX_RectF& rt) const { 422 return rt.left >= left && rt.right() <= right() && rt.top >= top && 423 rt.bottom() <= bottom(); 424 } Left()425 float Left() const { return left; } Top()426 float Top() const { return top; } Width()427 float Width() const { return width; } Height()428 float Height() const { return height; } Size()429 SizeType Size() const { return SizeType(width, height); } TopLeft()430 PointType TopLeft() const { return PointType(left, top); } TopRight()431 PointType TopRight() const { return PointType(left + width, top); } BottomLeft()432 PointType BottomLeft() const { return PointType(left, top + height); } BottomRight()433 PointType BottomRight() const { 434 return PointType(left + width, top + height); 435 } Center()436 PointType Center() const { 437 return PointType(left + width / 2, top + height / 2); 438 } Union(float x,float y)439 void Union(float x, float y) { 440 float r = right(); 441 float b = bottom(); 442 443 left = std::min(left, x); 444 top = std::min(top, y); 445 r = std::max(r, x); 446 b = std::max(b, y); 447 448 width = r - left; 449 height = b - top; 450 } Union(const PointType & p)451 void Union(const PointType& p) { Union(p.x, p.y); } Union(const CFX_RectF & rt)452 void Union(const CFX_RectF& rt) { 453 float r = right(); 454 float b = bottom(); 455 456 left = std::min(left, rt.left); 457 top = std::min(top, rt.top); 458 r = std::max(r, rt.right()); 459 b = std::max(b, rt.bottom()); 460 461 width = r - left; 462 height = b - top; 463 } Intersect(const CFX_RectF & rt)464 void Intersect(const CFX_RectF& rt) { 465 float r = right(); 466 float b = bottom(); 467 468 left = std::max(left, rt.left); 469 top = std::max(top, rt.top); 470 r = std::min(r, rt.right()); 471 b = std::min(b, rt.bottom()); 472 473 width = r - left; 474 height = b - top; 475 } IntersectWith(const CFX_RectF & rt)476 bool IntersectWith(const CFX_RectF& rt) const { 477 CFX_RectF rect = rt; 478 rect.Intersect(*this); 479 return !rect.IsEmpty(); 480 } IntersectWith(const CFX_RectF & rt,float fEpsilon)481 bool IntersectWith(const CFX_RectF& rt, float fEpsilon) const { 482 CFX_RectF rect = rt; 483 rect.Intersect(*this); 484 return !rect.IsEmpty(fEpsilon); 485 } 486 friend bool operator==(const CFX_RectF& rc1, const CFX_RectF& rc2) { 487 return rc1.left == rc2.left && rc1.top == rc2.top && 488 rc1.width == rc2.width && rc1.height == rc2.height; 489 } 490 friend bool operator!=(const CFX_RectF& rc1, const CFX_RectF& rc2) { 491 return !(rc1 == rc2); 492 } 493 ToFloatRect()494 CFX_FloatRect ToFloatRect() const { 495 // Note, we flip top/bottom here because the CFX_FloatRect has the 496 // y-axis running in the opposite direction. 497 return CFX_FloatRect(left, top, right(), bottom()); 498 } 499 500 // Returned rect has bounds rounded up/down such that the original is 501 // contained in it. 502 FX_RECT GetOuterRect() const; 503 504 float left = 0.0f; 505 float top = 0.0f; 506 float width = 0.0f; 507 float height = 0.0f; 508 }; 509 510 #ifndef NDEBUG 511 std::ostream& operator<<(std::ostream& os, const CFX_RectF& rect); 512 #endif // NDEBUG 513 514 // The matrix is of the form: 515 // | a b 0 | 516 // | c d 0 | 517 // | e f 1 | 518 // See PDF spec 1.7 Section 4.2.3. 519 // 520 class CFX_Matrix { 521 public: 522 CFX_Matrix() = default; 523 CFX_Matrix(const float n[6])524 explicit CFX_Matrix(const float n[6]) 525 : a(n[0]), b(n[1]), c(n[2]), d(n[3]), e(n[4]), f(n[5]) {} 526 CFX_Matrix(float a1,float b1,float c1,float d1,float e1,float f1)527 CFX_Matrix(float a1, float b1, float c1, float d1, float e1, float f1) 528 : a(a1), b(b1), c(c1), d(d1), e(e1), f(f1) {} 529 530 CFX_Matrix(const CFX_Matrix& other) = default; 531 532 CFX_Matrix& operator=(const CFX_Matrix& other) = default; 533 534 bool operator==(const CFX_Matrix& other) const { 535 return a == other.a && b == other.b && c == other.c && d == other.d && 536 e == other.e && f == other.f; 537 } 538 bool operator!=(const CFX_Matrix& other) const { return !(*this == other); } 539 540 CFX_Matrix operator*(const CFX_Matrix& right) const { 541 return CFX_Matrix(a * right.a + b * right.c, a * right.b + b * right.d, 542 c * right.a + d * right.c, c * right.b + d * right.d, 543 e * right.a + f * right.c + right.e, 544 e * right.b + f * right.d + right.f); 545 } 546 CFX_Matrix& operator*=(const CFX_Matrix& other) { 547 *this = *this * other; 548 return *this; 549 } 550 IsIdentity()551 bool IsIdentity() const { return *this == CFX_Matrix(); } 552 CFX_Matrix GetInverse() const; 553 554 bool Is90Rotated() const; 555 bool IsScaled() const; WillScale()556 bool WillScale() const { return a != 1.0f || b != 0 || c != 0 || d != 1.0f; } 557 Concat(const CFX_Matrix & right)558 void Concat(const CFX_Matrix& right) { *this *= right; } 559 void Translate(float x, float y); 560 void TranslatePrepend(float x, float y); Translate(int32_t x,int32_t y)561 void Translate(int32_t x, int32_t y) { 562 Translate(static_cast<float>(x), static_cast<float>(y)); 563 } TranslatePrepend(int32_t x,int32_t y)564 void TranslatePrepend(int32_t x, int32_t y) { 565 TranslatePrepend(static_cast<float>(x), static_cast<float>(y)); 566 } 567 568 void Scale(float sx, float sy); 569 void Rotate(float fRadian); 570 571 void MatchRect(const CFX_FloatRect& dest, const CFX_FloatRect& src); 572 573 float GetXUnit() const; 574 float GetYUnit() const; 575 CFX_FloatRect GetUnitRect() const; 576 577 float TransformXDistance(float dx) const; 578 float TransformDistance(float distance) const; 579 580 CFX_PointF Transform(const CFX_PointF& point) const; 581 582 CFX_RectF TransformRect(const CFX_RectF& rect) const; 583 CFX_FloatRect TransformRect(const CFX_FloatRect& rect) const; 584 585 float a = 1.0f; 586 float b = 0.0f; 587 float c = 0.0f; 588 float d = 1.0f; 589 float e = 0.0f; 590 float f = 0.0f; 591 }; 592 593 #endif // CORE_FXCRT_FX_COORDINATES_H_ 594