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