TestRect.cpp (27937B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 #include <limits> 7 8 #include "gtest/gtest.h" 9 10 #include "gfxTypes.h" 11 #include "nsRect.h" 12 #include "nsRectAbsolute.h" 13 #include "gfxRect.h" 14 #include "mozilla/gfx/Point.h" 15 #include "mozilla/gfx/Rect.h" 16 #include "mozilla/gfx/RectAbsolute.h" 17 #include "mozilla/WritingModes.h" 18 #ifdef XP_WIN 19 # include <windows.h> 20 #endif 21 22 using mozilla::CSSCoord; 23 using mozilla::CSSIntCoord; 24 using mozilla::CSSIntSize; 25 using mozilla::ScreenIntCoord; 26 using mozilla::gfx::IntPoint; 27 using mozilla::gfx::IntRect; 28 using mozilla::gfx::IntRectAbsolute; 29 using mozilla::gfx::Rect; 30 31 static_assert(std::is_constructible_v<CSSIntSize, CSSIntCoord, CSSIntCoord>); 32 static_assert( 33 !std::is_constructible_v<CSSIntSize, ScreenIntCoord, ScreenIntCoord>); 34 static_assert(std::is_constructible_v<CSSIntSize, int, int>); 35 static_assert(!std::is_constructible_v<CSSIntSize, float, float>); 36 37 static_assert(std::is_same_v<CSSIntCoord, decltype(CSSIntCoord() * 42)>); 38 static_assert(std::is_same_v<CSSCoord, decltype(CSSCoord() * 42)>); 39 static_assert(std::is_same_v<CSSCoord, decltype(CSSIntCoord() * 42.f)>); 40 static_assert(std::is_same_v<CSSCoord, decltype(CSSCoord() * 42.f)>); 41 42 template <class RectType> 43 static bool TestConstructors() { 44 // Create a rectangle 45 RectType rect1(10, 20, 30, 40); 46 47 // Make sure the rectangle was properly initialized 48 EXPECT_TRUE(rect1.IsEqualRect(10, 20, 30, 40) && rect1.IsEqualXY(10, 20) && 49 rect1.IsEqualSize(30, 40)) 50 << "[1] Make sure the rectangle was properly initialized with " 51 "constructor"; 52 53 // Create a second rect using the copy constructor 54 RectType rect2(rect1); 55 56 // Make sure the rectangle was properly initialized 57 EXPECT_TRUE(rect2.IsEqualEdges(rect1) && 58 rect2.IsEqualXY(rect1.X(), rect1.Y()) && 59 rect2.IsEqualSize(rect1.Width(), rect1.Height())) 60 << "[2] Make sure the rectangle was properly initialized with copy " 61 "constructor"; 62 63 EXPECT_TRUE(!rect1.IsEmpty() && !rect1.IsZeroArea() && rect1.IsFinite() && 64 !rect2.IsEmpty() && !rect2.IsZeroArea() && rect2.IsFinite()) 65 << "[3] These rectangles are not empty and are finite"; 66 67 rect1.SetRect(1, 2, 30, 40); 68 EXPECT_TRUE(rect1.X() == 1 && rect1.Y() == 2 && rect1.Width() == 30 && 69 rect1.Height() == 40 && rect1.XMost() == 31 && 70 rect1.YMost() == 42); 71 72 rect1.SetRectX(11, 50); 73 EXPECT_TRUE(rect1.X() == 11 && rect1.Y() == 2 && rect1.Width() == 50 && 74 rect1.Height() == 40 && rect1.XMost() == 61 && 75 rect1.YMost() == 42); 76 77 rect1.SetRectY(22, 60); 78 EXPECT_TRUE(rect1.X() == 11 && rect1.Y() == 22 && rect1.Width() == 50 && 79 rect1.Height() == 60 && rect1.XMost() == 61 && 80 rect1.YMost() == 82); 81 82 rect1.SetBox(1, 2, 31, 42); 83 EXPECT_TRUE(rect1.X() == 1 && rect1.Y() == 2 && rect1.Width() == 30 && 84 rect1.Height() == 40 && rect1.XMost() == 31 && 85 rect1.YMost() == 42); 86 87 rect1.SetBoxX(11, 61); 88 EXPECT_TRUE(rect1.X() == 11 && rect1.Y() == 2 && rect1.Width() == 50 && 89 rect1.Height() == 40 && rect1.XMost() == 61 && 90 rect1.YMost() == 42); 91 92 rect1.SetBoxY(22, 82); 93 EXPECT_TRUE(rect1.X() == 11 && rect1.Y() == 22 && rect1.Width() == 50 && 94 rect1.Height() == 60 && rect1.XMost() == 61 && 95 rect1.YMost() == 82); 96 97 rect1.SetRect(1, 2, 30, 40); 98 EXPECT_TRUE(rect1.X() == 1 && rect1.Y() == 2 && rect1.Width() == 30 && 99 rect1.Height() == 40 && rect1.XMost() == 31 && 100 rect1.YMost() == 42); 101 102 rect1.MoveByX(10); 103 EXPECT_TRUE(rect1.X() == 11 && rect1.Y() == 2 && rect1.Width() == 30 && 104 rect1.Height() == 40 && rect1.XMost() == 41 && 105 rect1.YMost() == 42); 106 107 rect1.MoveByY(20); 108 EXPECT_TRUE(rect1.X() == 11 && rect1.Y() == 22 && rect1.Width() == 30 && 109 rect1.Height() == 40 && rect1.XMost() == 41 && 110 rect1.YMost() == 62); 111 112 return true; 113 } 114 115 template <class RectType> 116 static bool TestEqualityOperator() { 117 RectType rect1(10, 20, 30, 40); 118 RectType rect2(rect1); 119 120 // Test the equality operator 121 EXPECT_TRUE(rect1 == rect2) << "[1] Test the equality operator"; 122 123 EXPECT_FALSE(!rect1.IsEqualInterior(rect2)) 124 << "[2] Test the inequality operator"; 125 126 // Make sure that two empty rects are equal 127 rect1.SetEmpty(); 128 rect2.SetEmpty(); 129 EXPECT_TRUE(rect1 == rect2) << "[3] Make sure that two empty rects are equal"; 130 131 return true; 132 } 133 134 template <class RectType, class UnitType> 135 static bool TestContainment() { 136 RectType rect1(10, 10, 50, 50); 137 138 // Test the point containment methods 139 // 140 141 // Basic test of a point in the middle of the rect 142 EXPECT_TRUE(rect1.Contains(rect1.Center()) && 143 rect1.ContainsX(rect1.Center().x) && 144 rect1.ContainsY(rect1.Center().y)) 145 << "[1] Basic test of a point in the middle of the rect"; 146 147 // Test against a point at the left/top edges 148 EXPECT_TRUE(rect1.Contains(rect1.X(), rect1.Y()) && 149 rect1.ContainsX(rect1.X()) && rect1.ContainsY(rect1.Y())) 150 << "[2] Test against a point at the left/top edges"; 151 152 // Test against a point at the right/bottom extents 153 EXPECT_FALSE(rect1.Contains(rect1.XMost(), rect1.YMost()) || 154 rect1.ContainsX(rect1.XMost()) || rect1.ContainsY(rect1.YMost())) 155 << "[3] Test against a point at the right/bottom extents"; 156 157 // Test the rect containment methods 158 // 159 RectType rect2(rect1); 160 161 // Test against a rect that's the same as rect1 162 EXPECT_FALSE(!rect1.Contains(rect2)) 163 << "[4] Test against a rect that's the same as rect1"; 164 165 // Test against a rect whose left edge (only) is outside of rect1 166 rect2.MoveByX(-1); 167 EXPECT_FALSE(rect1.Contains(rect2)) 168 << "[5] Test against a rect whose left edge (only) is outside of rect1"; 169 rect2.MoveByX(1); 170 171 // Test against a rect whose top edge (only) is outside of rect1 172 rect2.MoveByY(-1); 173 EXPECT_FALSE(rect1.Contains(rect2)) 174 << "[6] Test against a rect whose top edge (only) is outside of rect1"; 175 rect2.MoveByY(1); 176 177 // Test against a rect whose right edge (only) is outside of rect1 178 rect2.MoveByX(1); 179 EXPECT_FALSE(rect1.Contains(rect2)) 180 << "[7] Test against a rect whose right edge (only) is outside of rect1"; 181 rect2.MoveByX(-1); 182 183 // Test against a rect whose bottom edge (only) is outside of rect1 184 rect2.MoveByY(1); 185 EXPECT_FALSE(rect1.Contains(rect2)) 186 << "[8] Test against a rect whose bottom edge (only) is outside of rect1"; 187 rect2.MoveByY(-1); 188 189 // Test rects approaching numeric limits can contain rects 190 RectType rectLarge(10, 10, std::numeric_limits<UnitType>::max(), 191 std::numeric_limits<UnitType>::max()); 192 EXPECT_TRUE(rectLarge.Contains(rect2)) 193 << "[9] Test rect at numeric limits against a smaller rect"; 194 195 return true; 196 } 197 198 // Test the method that returns a boolean result but doesn't return a 199 // a rectangle 200 template <class RectType> 201 static bool TestIntersects() { 202 RectType rect1(10, 10, 50, 50); 203 RectType rect2(rect1); 204 205 // Test against a rect that's the same as rect1 206 EXPECT_FALSE(!rect1.Intersects(rect2)) 207 << "[1] Test against a rect that's the same as rect1"; 208 209 // Test against a rect that's enclosed by rect1 210 rect2.Inflate(-1, -1); 211 EXPECT_FALSE(!rect1.Contains(rect2) || !rect1.Intersects(rect2)) 212 << "[2] Test against a rect that's enclosed by rect1"; 213 rect2.Inflate(1, 1); 214 215 // Make sure inflate and deflate worked correctly 216 EXPECT_TRUE(rect1.IsEqualInterior(rect2)) 217 << "[3] Make sure inflate and deflate worked correctly"; 218 219 // Test against a rect that overlaps the left edge of rect1 220 rect2.MoveByX(-1); 221 EXPECT_FALSE(!rect1.Intersects(rect2)) 222 << "[4] Test against a rect that overlaps the left edge of rect1"; 223 rect2.MoveByX(1); 224 225 // Test against a rect that's outside of rect1 on the left 226 rect2.MoveByX(-rect2.Width()); 227 EXPECT_FALSE(rect1.Intersects(rect2)) 228 << "[5] Test against a rect that's outside of rect1 on the left"; 229 rect2.MoveByX(rect2.Width()); 230 231 // Test against a rect that overlaps the top edge of rect1 232 rect2.MoveByY(-1); 233 EXPECT_FALSE(!rect1.Intersects(rect2)) 234 << "[6] Test against a rect that overlaps the top edge of rect1"; 235 rect2.MoveByY(1); 236 237 // Test against a rect that's outside of rect1 on the top 238 rect2.MoveByY(-rect2.Height()); 239 EXPECT_FALSE(rect1.Intersects(rect2)) 240 << "[7] Test against a rect that's outside of rect1 on the top"; 241 rect2.MoveByY(rect2.Height()); 242 243 // Test against a rect that overlaps the right edge of rect1 244 rect2.MoveByX(1); 245 EXPECT_FALSE(!rect1.Intersects(rect2)) 246 << "[8] Test against a rect that overlaps the right edge of rect1"; 247 rect2.MoveByX(-1); 248 249 // Test against a rect that's outside of rect1 on the right 250 rect2.MoveByX(rect2.Width()); 251 EXPECT_FALSE(rect1.Intersects(rect2)) 252 << "[9] Test against a rect that's outside of rect1 on the right"; 253 rect2.MoveByX(-rect2.Width()); 254 255 // Test against a rect that overlaps the bottom edge of rect1 256 rect2.MoveByY(1); 257 EXPECT_FALSE(!rect1.Intersects(rect2)) 258 << "[10] Test against a rect that overlaps the bottom edge of rect1"; 259 rect2.MoveByY(-1); 260 261 // Test against a rect that's outside of rect1 on the bottom 262 rect2.MoveByY(rect2.Height()); 263 EXPECT_FALSE(rect1.Intersects(rect2)) 264 << "[11] Test against a rect that's outside of rect1 on the bottom"; 265 rect2.MoveByY(-rect2.Height()); 266 267 return true; 268 } 269 270 // Test the method that returns a boolean result and an intersection rect 271 template <class RectType> 272 static bool TestIntersection() { 273 RectType rect1(10, 10, 50, 50); 274 RectType rect2(rect1); 275 RectType dest; 276 277 // Test against a rect that's the same as rect1 278 EXPECT_FALSE(!dest.IntersectRect(rect1, rect2) || 279 !(dest.IsEqualInterior(rect1))) 280 << "[1] Test against a rect that's the same as rect1"; 281 282 // Test against a rect that's enclosed by rect1 283 rect2.Inflate(-1, -1); 284 EXPECT_FALSE(!dest.IntersectRect(rect1, rect2) || 285 !(dest.IsEqualInterior(rect2))) 286 << "[2] Test against a rect that's enclosed by rect1"; 287 rect2.Inflate(1, 1); 288 289 // Test against a rect that overlaps the left edge of rect1 290 rect2.MoveByX(-1); 291 EXPECT_FALSE(!dest.IntersectRect(rect1, rect2) || 292 !(dest.IsEqualInterior(RectType( 293 rect1.X(), rect1.Y(), rect1.Width() - 1, rect1.Height())))) 294 << "[3] Test against a rect that overlaps the left edge of rect1"; 295 rect2.MoveByX(1); 296 297 // Test against a rect that's outside of rect1 on the left 298 rect2.MoveByX(-rect2.Width()); 299 EXPECT_FALSE(dest.IntersectRect(rect1, rect2)) 300 << "[4] Test against a rect that's outside of rect1 on the left"; 301 // Make sure an empty rect is returned 302 EXPECT_TRUE(dest.IsEmpty() && dest.IsZeroArea()) 303 << "[4] Make sure an empty rect is returned"; 304 EXPECT_TRUE(dest.IsFinite()) << "[4b] Should be finite"; 305 rect2.MoveByX(rect2.Width()); 306 307 // Test against a rect that overlaps the top edge of rect1 308 rect2.MoveByY(-1); 309 EXPECT_FALSE(!dest.IntersectRect(rect1, rect2) || 310 !(dest.IsEqualInterior(RectType( 311 rect1.X(), rect1.Y(), rect1.Width(), rect1.Height() - 1)))) 312 << "[5] Test against a rect that overlaps the top edge of rect1"; 313 EXPECT_TRUE(dest.IsFinite()) << "[5b] Should be finite"; 314 rect2.MoveByY(1); 315 316 // Test against a rect that's outside of rect1 on the top 317 rect2.MoveByY(-rect2.Height()); 318 EXPECT_FALSE(dest.IntersectRect(rect1, rect2)) 319 << "[6] Test against a rect that's outside of rect1 on the top"; 320 // Make sure an empty rect is returned 321 EXPECT_TRUE(dest.IsEmpty() && dest.IsZeroArea()) 322 << "[6] Make sure an empty rect is returned"; 323 EXPECT_TRUE(dest.IsFinite()) << "[6b] Should be finite"; 324 rect2.MoveByY(rect2.Height()); 325 326 // Test against a rect that overlaps the right edge of rect1 327 rect2.MoveByX(1); 328 EXPECT_FALSE( 329 !dest.IntersectRect(rect1, rect2) || 330 !(dest.IsEqualInterior(RectType(rect1.X() + 1, rect1.Y(), 331 rect1.Width() - 1, rect1.Height())))) 332 << "[7] Test against a rect that overlaps the right edge of rect1"; 333 rect2.MoveByX(-1); 334 335 // Test against a rect that's outside of rect1 on the right 336 rect2.MoveByX(rect2.Width()); 337 EXPECT_FALSE(dest.IntersectRect(rect1, rect2)) 338 << "[8] Test against a rect that's outside of rect1 on the right"; 339 // Make sure an empty rect is returned 340 EXPECT_TRUE(dest.IsEmpty() && dest.IsZeroArea()) 341 << "[8] Make sure an empty rect is returned"; 342 EXPECT_TRUE(dest.IsFinite()) << "[8b] Should be finite"; 343 rect2.MoveByX(-rect2.Width()); 344 345 // Test against a rect that overlaps the bottom edge of rect1 346 rect2.MoveByY(1); 347 EXPECT_FALSE( 348 !dest.IntersectRect(rect1, rect2) || 349 !(dest.IsEqualInterior(RectType(rect1.X(), rect1.Y() + 1, rect1.Width(), 350 rect1.Height() - 1)))) 351 << "[9] Test against a rect that overlaps the bottom edge of rect1"; 352 EXPECT_TRUE(dest.IsFinite()) << "[9b] Should be finite"; 353 rect2.MoveByY(-1); 354 355 // Test against a rect that's outside of rect1 on the bottom 356 rect2.MoveByY(rect2.Height()); 357 EXPECT_FALSE(dest.IntersectRect(rect1, rect2)) 358 << "[10] Test against a rect that's outside of rect1 on the bottom"; 359 // Make sure an empty rect is returned 360 EXPECT_TRUE(dest.IsEmpty() && dest.IsZeroArea()) 361 << "[10] Make sure an empty rect is returned"; 362 EXPECT_TRUE(dest.IsFinite()) << "[10b] Should be finite"; 363 rect2.MoveByY(-rect2.Height()); 364 365 // Test against a rect with zero width or height 366 rect1.SetRect(100, 100, 100, 100); 367 rect2.SetRect(150, 100, 0, 100); 368 EXPECT_TRUE(!dest.IntersectRect(rect1, rect2) && dest.IsEmpty() && 369 dest.IsZeroArea()) 370 << "[11] Intersection of rects with zero width or height should be empty"; 371 EXPECT_TRUE(dest.IsFinite()) << "[11b] Should be finite"; 372 373 // Tests against a rect with negative width or height 374 // 375 376 // Test against a rect with negative width 377 rect1.SetRect(100, 100, 100, 100); 378 rect2.SetRect(100, 100, -100, 100); 379 EXPECT_TRUE(!dest.IntersectRect(rect1, rect2) && dest.IsEmpty() && 380 dest.IsZeroArea()) 381 << "[12] Intersection of rects with negative width or height should be " 382 "empty"; 383 EXPECT_TRUE(dest.IsFinite()) << "[12b] Should be finite"; 384 385 // Those two rects exactly overlap in some way... 386 // but we still want to return an empty rect 387 rect1.SetRect(100, 100, 100, 100); 388 rect2.SetRect(200, 200, -100, -100); 389 EXPECT_TRUE(!dest.IntersectRect(rect1, rect2) && dest.IsEmpty() && 390 dest.IsZeroArea()) 391 << "[13] Intersection of rects with negative width or height should be " 392 "empty"; 393 EXPECT_TRUE(dest.IsFinite()) << "[13b] Should be finite"; 394 395 // Test against two identical rects with negative height 396 rect1.SetRect(100, 100, 100, -100); 397 rect2.SetRect(100, 100, 100, -100); 398 EXPECT_TRUE(!dest.IntersectRect(rect1, rect2) && dest.IsEmpty() && 399 dest.IsZeroArea()) 400 << "[14] Intersection of rects with negative width or height should be " 401 "empty"; 402 EXPECT_TRUE(dest.IsFinite()) << "[14b] Should be finite"; 403 404 return true; 405 } 406 407 template <class RectType> 408 static bool TestUnion() { 409 RectType rect1; 410 RectType rect2(10, 10, 50, 50); 411 RectType dest; 412 413 // Check the case where the receiver is an empty rect 414 rect1.SetEmpty(); 415 dest.UnionRect(rect1, rect2); 416 EXPECT_TRUE(!dest.IsEmpty() && !dest.IsZeroArea() && 417 dest.IsEqualInterior(rect2)) 418 << "[1] Check the case where the receiver is an empty rect"; 419 EXPECT_TRUE(dest.IsFinite()) << "[1b] Should be finite"; 420 421 // Check the case where the source rect is an empty rect 422 rect1 = rect2; 423 rect2.SetEmpty(); 424 dest.UnionRect(rect1, rect2); 425 EXPECT_TRUE(!dest.IsEmpty() && !dest.IsZeroArea() && 426 dest.IsEqualInterior(rect1)) 427 << "[2] Check the case where the source rect is an empty rect"; 428 EXPECT_TRUE(dest.IsFinite()) << "[2b] Should be finite"; 429 430 // Test the case where both rects are empty 431 rect1.SetEmpty(); 432 rect2.SetEmpty(); 433 dest.UnionRect(rect1, rect2); 434 EXPECT_TRUE(dest.IsEmpty() && dest.IsZeroArea()) 435 << "[3] Test the case where both rects are empty"; 436 EXPECT_TRUE(dest.IsFinite()) << "[3b] Should be finite"; 437 438 // Test union case where the two rects don't overlap at all 439 rect1.SetRect(10, 10, 50, 50); 440 rect2.SetRect(100, 100, 50, 50); 441 dest.UnionRect(rect1, rect2); 442 EXPECT_TRUE(!dest.IsEmpty() && !dest.IsZeroArea() && 443 (dest.IsEqualInterior(RectType(rect1.X(), rect1.Y(), 444 rect2.XMost() - rect1.X(), 445 rect2.YMost() - rect1.Y())))) 446 << "[4] Test union case where the two rects don't overlap at all"; 447 EXPECT_TRUE(dest.IsFinite()) << "[4b] Should be finite"; 448 449 // Test union case where the two rects overlap 450 rect1.SetRect(30, 30, 50, 50); 451 rect2.SetRect(10, 10, 50, 50); 452 dest.UnionRect(rect1, rect2); 453 EXPECT_TRUE(!dest.IsEmpty() && !dest.IsZeroArea() && 454 (dest.IsEqualInterior(RectType(rect2.X(), rect2.Y(), 455 rect1.XMost() - rect2.X(), 456 rect1.YMost() - rect2.Y())))) 457 << "[5] Test union case where the two rects overlap"; 458 EXPECT_TRUE(dest.IsFinite()) << "[5b] Should be finite"; 459 460 return true; 461 } 462 463 template <class RectType> 464 static void TestUnionEmptyRects() { 465 RectType rect1(10, 10, 0, 50); 466 RectType rect2(5, 5, 40, 0); 467 EXPECT_TRUE(rect1.IsEmpty() && rect2.IsEmpty()); 468 469 RectType dest = rect1.Union(rect2); 470 EXPECT_TRUE(dest.IsEmpty() && dest.IsEqualEdges(rect2)) 471 << "Test the case where both rects are empty, and the result is the " 472 "same value passing into Union()"; 473 } 474 475 static bool TestFiniteGfx() { 476 float posInf = std::numeric_limits<float>::infinity(); 477 float negInf = -std::numeric_limits<float>::infinity(); 478 float justNaN = std::numeric_limits<float>::quiet_NaN(); 479 480 gfxFloat values[4] = {5.0, 10.0, 15.0, 20.0}; 481 482 // Try the "non-finite" values for x, y, width, height, one at a time 483 for (int i = 0; i < 4; i += 1) { 484 values[i] = posInf; 485 gfxRect rectPosInf(values[0], values[1], values[2], values[3]); 486 EXPECT_FALSE(rectPosInf.IsFinite()) 487 << "For +inf (" << values[0] << "," << values[1] << "," << values[2] 488 << "," << values[3] << ")"; 489 490 values[i] = negInf; 491 gfxRect rectNegInf(values[0], values[1], values[2], values[3]); 492 EXPECT_FALSE(rectNegInf.IsFinite()) 493 << "For -inf (" << values[0] << "," << values[1] << "," << values[2] 494 << "," << values[3] << ")"; 495 496 values[i] = justNaN; 497 gfxRect rectNaN(values[0], values[1], values[2], values[3]); 498 EXPECT_FALSE(rectNaN.IsFinite()) 499 << "For NaN (" << values[0] << "," << values[1] << "," << values[2] 500 << "," << values[3] << ")"; 501 502 // Reset to a finite value... 503 values[i] = 5.0 * i; 504 } 505 506 return true; 507 } 508 509 // We want to test nsRect values that are still in range but where 510 // the implementation is at risk of overflowing 511 template <class RectType> 512 static bool TestBug1135677() { 513 RectType rect1(1073741344, 1073741344, 1073756696, 1073819936); 514 RectType rect2(1073741820, 1073741820, 14400, 77640); 515 RectType dest; 516 517 dest = rect1.Intersect(rect2); 518 519 EXPECT_TRUE(dest.IsEqualRect(1073741820, 1073741820, 14400, 77640)) 520 << "[1] Operation should not overflow internally."; 521 522 return true; 523 } 524 525 template <class RectType> 526 static bool TestSetWH() { 527 RectType rect(1, 2, 3, 4); 528 EXPECT_TRUE(rect.IsEqualRect(1, 2, 3, 4)); 529 rect.SetWidth(13); 530 EXPECT_TRUE(rect.IsEqualRect(1, 2, 13, 4)); 531 rect.SetHeight(14); 532 EXPECT_TRUE(rect.IsEqualRect(1, 2, 13, 14)); 533 rect.SizeTo(23, 24); 534 EXPECT_TRUE(rect.IsEqualRect(1, 2, 23, 24)); 535 return true; 536 } 537 538 template <class RectType> 539 static bool TestSwap() { 540 RectType rect(1, 2, 3, 4); 541 EXPECT_TRUE(rect.IsEqualRect(1, 2, 3, 4)); 542 rect.Swap(); 543 EXPECT_TRUE(rect.IsEqualRect(2, 1, 4, 3)); 544 return true; 545 } 546 547 static void TestIntersectionLogicalHelper(nscoord x1, nscoord y1, nscoord w1, 548 nscoord h1, nscoord x2, nscoord y2, 549 nscoord w2, nscoord h2, nscoord xR, 550 nscoord yR, nscoord wR, nscoord hR, 551 bool isNonEmpty) { 552 nsRect rect1(x1, y1, w1, h1); 553 nsRect rect2(x2, y2, w2, h2); 554 nsRect rectDebug; 555 EXPECT_TRUE(isNonEmpty == rectDebug.IntersectRect(rect1, rect2)); 556 EXPECT_TRUE(rectDebug.IsEqualEdges(nsRect(xR, yR, wR, hR))); 557 558 mozilla::LogicalRect r1(mozilla::WritingMode(), rect1.X(), rect1.Y(), 559 rect1.Width(), rect1.Height()); 560 mozilla::LogicalRect r2(mozilla::WritingMode(), rect2.X(), rect2.Y(), 561 rect2.Width(), rect2.Height()); 562 EXPECT_TRUE(isNonEmpty == r1.IntersectRect(r1, r2)); 563 EXPECT_TRUE(rectDebug.IsEqualEdges(nsRect( 564 r1.IStart(mozilla::WritingMode()), r1.BStart(mozilla::WritingMode()), 565 r1.ISize(mozilla::WritingMode()), r1.BSize(mozilla::WritingMode())))); 566 567 mozilla::LogicalRect r3(mozilla::WritingMode(), rect1.X(), rect1.Y(), 568 rect1.Width(), rect1.Height()); 569 mozilla::LogicalRect r4(mozilla::WritingMode(), rect2.X(), rect2.Y(), 570 rect2.Width(), rect2.Height()); 571 EXPECT_TRUE(isNonEmpty == r4.IntersectRect(r3, r4)); 572 EXPECT_TRUE(rectDebug.IsEqualEdges(nsRect( 573 r4.IStart(mozilla::WritingMode()), r4.BStart(mozilla::WritingMode()), 574 r4.ISize(mozilla::WritingMode()), r4.BSize(mozilla::WritingMode())))); 575 576 mozilla::LogicalRect r5(mozilla::WritingMode(), rect1.X(), rect1.Y(), 577 rect1.Width(), rect1.Height()); 578 mozilla::LogicalRect r6(mozilla::WritingMode(), rect2.X(), rect2.Y(), 579 rect2.Width(), rect2.Height()); 580 mozilla::LogicalRect r7(mozilla::WritingMode(), 0, 0, 1, 1); 581 EXPECT_TRUE(isNonEmpty == r7.IntersectRect(r5, r6)); 582 EXPECT_TRUE(rectDebug.IsEqualEdges(nsRect( 583 r7.IStart(mozilla::WritingMode()), r7.BStart(mozilla::WritingMode()), 584 r7.ISize(mozilla::WritingMode()), r7.BSize(mozilla::WritingMode())))); 585 } 586 587 static void TestIntersectionLogical(nscoord x1, nscoord y1, nscoord w1, 588 nscoord h1, nscoord x2, nscoord y2, 589 nscoord w2, nscoord h2, nscoord xR, 590 nscoord yR, nscoord wR, nscoord hR, 591 bool isNonEmpty) { 592 TestIntersectionLogicalHelper(x1, y1, w1, h1, x2, y2, w2, h2, xR, yR, wR, hR, 593 isNonEmpty); 594 TestIntersectionLogicalHelper(x2, y2, w2, h2, x1, y1, w1, h1, xR, yR, wR, hR, 595 isNonEmpty); 596 } 597 598 TEST(Gfx, Logical) 599 { 600 TestIntersectionLogical(578, 0, 2650, 1152, 1036, 0, 2312, 1, 1036, 0, 2192, 601 1, true); 602 TestIntersectionLogical(0, 0, 1000, 1000, 500, 500, 1000, 1000, 500, 500, 500, 603 500, true); 604 TestIntersectionLogical(100, 200, 300, 400, 50, 250, 100, 100, 100, 250, 50, 605 100, true); 606 TestIntersectionLogical(0, 100, 200, 300, 300, 100, 100, 300, 300, 100, 0, 0, 607 false); 608 } 609 610 TEST(Gfx, nsRect) 611 { 612 TestConstructors<nsRect>(); 613 TestEqualityOperator<nsRect>(); 614 TestContainment<nsRect, nscoord>(); 615 TestIntersects<nsRect>(); 616 TestIntersection<nsRect>(); 617 TestUnion<nsRect>(); 618 TestUnionEmptyRects<nsRect>(); 619 TestBug1135677<nsRect>(); 620 TestSetWH<nsRect>(); 621 TestSwap<nsRect>(); 622 } 623 624 TEST(Gfx, nsIntRect) 625 { 626 TestConstructors<nsIntRect>(); 627 TestEqualityOperator<nsIntRect>(); 628 TestContainment<nsIntRect, int32_t>(); 629 TestIntersects<nsIntRect>(); 630 TestIntersection<nsIntRect>(); 631 TestUnion<nsIntRect>(); 632 TestUnionEmptyRects<nsIntRect>(); 633 TestBug1135677<nsIntRect>(); 634 TestSetWH<nsIntRect>(); 635 TestSwap<nsIntRect>(); 636 } 637 638 TEST(Gfx, gfxRect) 639 { 640 TestConstructors<gfxRect>(); 641 // Skip TestEqualityOperator<gfxRect>(); as gfxRect::operator== is private 642 TestContainment<gfxRect, double>(); 643 TestIntersects<gfxRect>(); 644 TestIntersection<gfxRect>(); 645 TestUnion<gfxRect>(); 646 TestUnionEmptyRects<gfxRect>(); 647 TestBug1135677<gfxRect>(); 648 TestFiniteGfx(); 649 TestSetWH<gfxRect>(); 650 TestSwap<gfxRect>(); 651 } 652 653 TEST(Gfx, nsRectAbsolute) 654 { 655 TestUnionEmptyRects<nsRectAbsolute>(); 656 } 657 658 TEST(Gfx, IntRectAbsolute) 659 { 660 TestUnionEmptyRects<IntRectAbsolute>(); 661 } 662 663 static void TestMoveInsideAndClamp(IntRect aSrc, IntRect aTarget, 664 IntRect aExpected) { 665 // Test the implementation in BaseRect (x/y/width/height representation) 666 IntRect result = aSrc.MoveInsideAndClamp(aTarget); 667 EXPECT_TRUE(result.IsEqualEdges(aExpected)) 668 << "Source " << aSrc << " Target " << aTarget << " Expected " << aExpected 669 << " Actual " << result; 670 671 // Also test the implementation in RectAbsolute (left/top/right/bottom 672 // representation) 673 IntRectAbsolute absSrc = IntRectAbsolute::FromRect(aSrc); 674 IntRectAbsolute absTarget = IntRectAbsolute::FromRect(aTarget); 675 IntRectAbsolute absExpected = IntRectAbsolute::FromRect(aExpected); 676 677 IntRectAbsolute absResult = absSrc.MoveInsideAndClamp(absTarget); 678 EXPECT_TRUE(absResult.IsEqualEdges(absExpected)) 679 << "AbsSource " << absSrc << " AbsTarget " << absTarget << " AbsExpected " 680 << absExpected << " AbsActual " << absResult; 681 } 682 683 TEST(Gfx, MoveInsideAndClamp) 684 { 685 TestMoveInsideAndClamp(IntRect(0, 0, 10, 10), IntRect(1, -1, 10, 10), 686 IntRect(1, -1, 10, 10)); 687 TestMoveInsideAndClamp(IntRect(0, 0, 10, 10), IntRect(-1, -1, 12, 5), 688 IntRect(0, -1, 10, 5)); 689 TestMoveInsideAndClamp(IntRect(0, 0, 10, 10), IntRect(10, 11, 10, 0), 690 IntRect(10, 11, 10, 0)); 691 TestMoveInsideAndClamp(IntRect(0, 0, 10, 10), IntRect(-10, -1, 10, 0), 692 IntRect(-10, -1, 10, 0)); 693 TestMoveInsideAndClamp(IntRect(0, 0, 0, 0), IntRect(10, -10, 10, 10), 694 IntRect(10, 0, 0, 0)); 695 } 696 697 TEST(Gfx, ClampPoint) 698 { 699 /* Various bounds */ 700 IntRect Square(0, 0, 10, 10); 701 EXPECT_EQ(Square.ClampPoint(IntPoint(-5, -5)), IntPoint(0, 0)); 702 EXPECT_EQ(Square.ClampPoint(IntPoint(-5, 5)), IntPoint(0, 5)); 703 EXPECT_EQ(Square.ClampPoint(IntPoint(-5, 15)), IntPoint(0, 10)); 704 705 EXPECT_EQ(Square.ClampPoint(IntPoint(5, -5)), IntPoint(5, 0)); 706 EXPECT_EQ(Square.ClampPoint(IntPoint(5, 5)), IntPoint(5, 5)); 707 EXPECT_EQ(Square.ClampPoint(IntPoint(5, 15)), IntPoint(5, 10)); 708 709 EXPECT_EQ(Square.ClampPoint(IntPoint(15, -5)), IntPoint(10, 0)); 710 EXPECT_EQ(Square.ClampPoint(IntPoint(15, 5)), IntPoint(10, 5)); 711 EXPECT_EQ(Square.ClampPoint(IntPoint(15, 15)), IntPoint(10, 10)); 712 713 /* Special case of empty rect */ 714 IntRect Empty(0, 0, -1, -1); 715 EXPECT_TRUE(Empty.IsEmpty()); 716 EXPECT_EQ(Empty.ClampPoint(IntPoint(-1, -1)), IntPoint(0, 0)); 717 EXPECT_EQ(Empty.ClampPoint(IntPoint(-1, 1)), IntPoint(0, 0)); 718 EXPECT_EQ(Empty.ClampPoint(IntPoint(1, -1)), IntPoint(0, 0)); 719 EXPECT_EQ(Empty.ClampPoint(IntPoint(1, 1)), IntPoint(0, 0)); 720 } 721 722 TEST(Gfx, SafeMoveBy) 723 { 724 IntRect intRect(0, 0, 10, 10); 725 intRect.SafeMoveByX(10); 726 intRect.SafeMoveByY(10); 727 EXPECT_EQ(intRect, IntRect(10, 10, 10, 10)); 728 729 intRect = IntRect(0, 0, 10, 10); 730 intRect.SafeMoveByX(-10); 731 intRect.SafeMoveByY(-10); 732 EXPECT_EQ(intRect, IntRect(-10, -10, 10, 10)); 733 734 Rect rect(0, 0, 10, 10); 735 rect.SafeMoveByX(10); 736 rect.SafeMoveByY(10); 737 EXPECT_EQ(rect, Rect(10, 10, 10, 10)); 738 739 rect = Rect(0, 0, 10, 10); 740 rect.SafeMoveByX(-10); 741 rect.SafeMoveByY(-10); 742 EXPECT_EQ(rect, Rect(-10, -10, 10, 10)); 743 }