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