1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.graphics.cts; 18 19 import static org.junit.Assert.assertArrayEquals; 20 import static org.junit.Assert.assertEquals; 21 import static org.junit.Assert.assertFalse; 22 import static org.junit.Assert.assertTrue; 23 24 import android.graphics.Bitmap; 25 import android.graphics.Canvas; 26 import android.graphics.Color; 27 import android.graphics.Matrix; 28 import android.graphics.Paint; 29 import android.graphics.Path; 30 import android.graphics.RectF; 31 32 import androidx.test.filters.SmallTest; 33 import androidx.test.runner.AndroidJUnit4; 34 35 import org.junit.Test; 36 import org.junit.runner.RunWith; 37 38 @SmallTest 39 @RunWith(AndroidJUnit4.class) 40 public class PathTest { 41 42 // Test constants 43 private static final float LEFT = 10.0f; 44 private static final float RIGHT = 50.0f; 45 private static final float TOP = 10.0f; 46 private static final float BOTTOM = 50.0f; 47 private static final float XCOORD = 40.0f; 48 private static final float YCOORD = 40.0f; 49 50 @Test 51 public void testConstructor() { 52 // new the Path instance 53 new Path(); 54 55 // another the Path instance with different params 56 new Path(new Path()); 57 } 58 59 @Test 60 public void testAddRect1() { 61 Path path = new Path(); 62 assertTrue(path.isEmpty()); 63 RectF rect = new RectF(LEFT, TOP, RIGHT, BOTTOM); 64 path.addRect(rect, Path.Direction.CW); 65 assertFalse(path.isEmpty()); 66 } 67 68 @Test 69 public void testAddRect2() { 70 Path path = new Path(); 71 assertTrue(path.isEmpty()); 72 path.addRect(LEFT, TOP, RIGHT, BOTTOM, Path.Direction.CW); 73 assertFalse(path.isEmpty()); 74 } 75 76 @Test 77 public void testMoveTo() { 78 Path path = new Path(); 79 path.moveTo(10.0f, 10.0f); 80 } 81 82 @Test 83 public void testSet() { 84 Path path = new Path(); 85 assertTrue(path.isEmpty()); 86 Path path1 = new Path(); 87 addRectToPath(path1); 88 path.set(path1); 89 verifyPathsAreEquivalent(path, path1); 90 } 91 92 @Test 93 public void testSetCleanOld() { 94 Path path = new Path(); 95 addRectToPath(path); 96 path.addRect(new RectF(0, 0, 10, 10), Path.Direction.CW); 97 Path path1 = new Path(); 98 path1.addRect(new RectF(10, 10, 20, 20), Path.Direction.CW); 99 path.set(path1); 100 verifyPathsAreEquivalent(path, path1); 101 } 102 103 @Test 104 public void testSetEmptyPath() { 105 Path path = new Path(); 106 addRectToPath(path); 107 Path path1 = new Path(); 108 path.set(path1); 109 verifyPathsAreEquivalent(path, path1); 110 } 111 112 @Test 113 public void testAccessFillType() { 114 // set the expected value 115 Path.FillType expected1 = Path.FillType.EVEN_ODD; 116 Path.FillType expected2 = Path.FillType.INVERSE_EVEN_ODD; 117 Path.FillType expected3 = Path.FillType.INVERSE_WINDING; 118 Path.FillType expected4 = Path.FillType.WINDING; 119 120 // new the Path instance 121 Path path = new Path(); 122 // set FillType by {@link Path#setFillType(FillType)} 123 path.setFillType(Path.FillType.EVEN_ODD); 124 assertEquals(expected1, path.getFillType()); 125 path.setFillType(Path.FillType.INVERSE_EVEN_ODD); 126 assertEquals(expected2, path.getFillType()); 127 path.setFillType(Path.FillType.INVERSE_WINDING); 128 assertEquals(expected3, path.getFillType()); 129 path.setFillType(Path.FillType.WINDING); 130 assertEquals(expected4, path.getFillType()); 131 } 132 133 @Test 134 public void testRQuadTo() { 135 Path path = new Path(); 136 assertTrue(path.isEmpty()); 137 path.rQuadTo(5.0f, 5.0f, 10.0f, 10.0f); 138 assertFalse(path.isEmpty()); 139 } 140 141 @Test 142 public void testTransform1() { 143 Path path = new Path(); 144 assertTrue(path.isEmpty()); 145 Path dst = new Path(); 146 addRectToPath(path); 147 path.transform(new Matrix(), dst); 148 assertFalse(dst.isEmpty()); 149 } 150 151 @Test 152 public void testLineTo() { 153 Path path = new Path(); 154 assertTrue(path.isEmpty()); 155 path.lineTo(XCOORD, YCOORD); 156 assertFalse(path.isEmpty()); 157 } 158 159 @Test 160 public void testClose() { 161 Path path = new Path(); 162 assertTrue(path.isEmpty()); 163 addRectToPath(path); 164 path.close(); 165 } 166 167 @Test 168 public void testQuadTo() { 169 Path path = new Path(); 170 assertTrue(path.isEmpty()); 171 path.quadTo(20.0f, 20.0f, 40.0f, 40.0f); 172 assertFalse(path.isEmpty()); 173 } 174 175 @Test 176 public void testAddCircle() { 177 // new the Path instance 178 Path path = new Path(); 179 assertTrue(path.isEmpty()); 180 path.addCircle(XCOORD, YCOORD, 10.0f, Path.Direction.CW); 181 assertFalse(path.isEmpty()); 182 } 183 184 @Test 185 public void testArcTo1() { 186 Path path = new Path(); 187 assertTrue(path.isEmpty()); 188 RectF oval = new RectF(LEFT, TOP, RIGHT, BOTTOM); 189 path.arcTo(oval, 0.0f, 30.0f, true); 190 assertFalse(path.isEmpty()); 191 } 192 193 @Test 194 public void testArcTo2() { 195 Path path = new Path(); 196 assertTrue(path.isEmpty()); 197 RectF oval = new RectF(LEFT, TOP, RIGHT, BOTTOM); 198 path.arcTo(oval, 0.0f, 30.0f); 199 assertFalse(path.isEmpty()); 200 } 201 202 @Test 203 public void testComputeBounds1() { 204 RectF expected = new RectF(0.0f, 0.0f, 0.0f, 0.0f); 205 Path path = new Path(); 206 assertTrue(path.isEmpty()); 207 RectF bounds = new RectF(); 208 path.computeBounds(bounds, true); 209 assertEquals(expected.width(), bounds.width(), 0.0f); 210 assertEquals(expected.height(), bounds.height(), 0.0f); 211 path.computeBounds(bounds, false); 212 assertEquals(expected.width(), bounds.width(), 0.0f); 213 assertEquals(expected.height(), bounds.height(), 0.0f); 214 } 215 216 @Test 217 public void testComputeBounds2() { 218 RectF expected = new RectF(LEFT, TOP, RIGHT, BOTTOM); 219 Path path = new Path(); 220 assertTrue(path.isEmpty()); 221 RectF bounds = new RectF(LEFT, TOP, RIGHT, BOTTOM); 222 path.addRect(bounds, Path.Direction.CW); 223 path.computeBounds(bounds, true); 224 assertEquals(expected.width(), bounds.width(), 0.0f); 225 assertEquals(expected.height(), bounds.height(), 0.0f); 226 path.computeBounds(bounds, false); 227 assertEquals(expected.width(), bounds.width(), 0.0f); 228 assertEquals(expected.height(), bounds.height(), 0.0f); 229 } 230 231 @Test 232 public void testSetLastPoint() { 233 Path path = new Path(); 234 path.setLastPoint(10.0f, 10.0f); 235 } 236 237 @Test 238 public void testRLineTo() { 239 Path path = new Path(); 240 assertTrue(path.isEmpty()); 241 path.rLineTo(10.0f, 10.0f); 242 assertFalse(path.isEmpty()); 243 } 244 245 @Test 246 public void testIsEmpty() { 247 248 Path path = new Path(); 249 assertTrue(path.isEmpty()); 250 addRectToPath(path); 251 assertFalse(path.isEmpty()); 252 } 253 254 @Test 255 public void testRewind() { 256 Path.FillType expected = Path.FillType.EVEN_ODD; 257 258 Path path = new Path(); 259 assertTrue(path.isEmpty()); 260 addRectToPath(path); 261 path.rewind(); 262 path.setFillType(Path.FillType.EVEN_ODD); 263 assertTrue(path.isEmpty()); 264 assertEquals(expected, path.getFillType()); 265 } 266 267 @Test 268 public void testAddOval() { 269 Path path = new Path(); 270 assertTrue(path.isEmpty()); 271 RectF oval = new RectF(LEFT, TOP, RIGHT, BOTTOM); 272 path.addOval(oval, Path.Direction.CW); 273 assertFalse(path.isEmpty()); 274 } 275 276 @Test 277 public void testIsRect() { 278 Path path = new Path(); 279 assertTrue(path.isEmpty()); 280 addRectToPath(path); 281 } 282 283 @Test 284 public void testAddPath1() { 285 Path path = new Path(); 286 assertTrue(path.isEmpty()); 287 Path src = new Path(); 288 addRectToPath(src); 289 path.addPath(src, 10.0f, 10.0f); 290 assertFalse(path.isEmpty()); 291 } 292 293 @Test 294 public void testAddPath2() { 295 Path path = new Path(); 296 assertTrue(path.isEmpty()); 297 Path src = new Path(); 298 addRectToPath(src); 299 path.addPath(src); 300 assertFalse(path.isEmpty()); 301 } 302 303 @Test 304 public void testAddPath3() { 305 Path path = new Path(); 306 assertTrue(path.isEmpty()); 307 Path src = new Path(); 308 addRectToPath(src); 309 Matrix matrix = new Matrix(); 310 path.addPath(src, matrix); 311 assertFalse(path.isEmpty()); 312 } 313 314 @Test 315 public void testAddRoundRect1() { 316 Path path = new Path(); 317 assertTrue(path.isEmpty()); 318 RectF rect = new RectF(LEFT, TOP, RIGHT, BOTTOM); 319 path.addRoundRect(rect, XCOORD, YCOORD, Path.Direction.CW); 320 assertFalse(path.isEmpty()); 321 } 322 323 @Test 324 public void testAddRoundRect2() { 325 Path path = new Path(); 326 assertTrue(path.isEmpty()); 327 RectF rect = new RectF(LEFT, TOP, RIGHT, BOTTOM); 328 float[] radii = new float[8]; 329 for (int i = 0; i < 8; i++) { 330 radii[i] = 10.0f + i * 5.0f; 331 } 332 path.addRoundRect(rect, radii, Path.Direction.CW); 333 assertFalse(path.isEmpty()); 334 } 335 336 @Test 337 public void testIsConvex1() { 338 Path path = new Path(); 339 path.addRect(0, 0, 100, 10, Path.Direction.CW); 340 assertTrue(path.isConvex()); 341 342 path.addRect(0, 0, 10, 100, Path.Direction.CW); 343 assertFalse(path.isConvex()); // path is concave 344 } 345 346 @Test 347 public void testIsConvex2() { 348 Path path = new Path(); 349 path.addRect(0, 0, 40, 40, Path.Direction.CW); 350 assertTrue(path.isConvex()); 351 352 path.addRect(10, 10, 30, 30, Path.Direction.CCW); 353 assertFalse(path.isConvex()); // path has hole, isn't convex 354 } 355 356 @Test 357 public void testIsConvex3() { 358 Path path = new Path(); 359 path.addRect(0, 0, 10, 10, Path.Direction.CW); 360 assertTrue(path.isConvex()); 361 362 path.addRect(0, 20, 10, 10, Path.Direction.CW); 363 assertFalse(path.isConvex()); // path isn't one convex shape 364 } 365 366 @Test 367 public void testIsInverseFillType() { 368 Path path = new Path(); 369 assertFalse(path.isInverseFillType()); 370 path.setFillType(Path.FillType.INVERSE_EVEN_ODD); 371 assertTrue(path.isInverseFillType()); 372 } 373 374 @Test 375 public void testOffset1() { 376 Path path = new Path(); 377 assertTrue(path.isEmpty()); 378 addRectToPath(path); 379 Path dst = new Path(); 380 path.offset(XCOORD, YCOORD, dst); 381 assertFalse(dst.isEmpty()); 382 } 383 384 @Test 385 public void testCubicTo() { 386 Path path = new Path(); 387 assertTrue(path.isEmpty()); 388 path.cubicTo(10.0f, 10.0f, 20.0f, 20.0f, 30.0f, 30.0f); 389 assertFalse(path.isEmpty()); 390 } 391 392 @Test 393 public void testReset() { 394 Path path = new Path(); 395 assertTrue(path.isEmpty()); 396 Path path1 = new Path(); 397 addRectToPath(path1); 398 path.set(path1); 399 assertFalse(path.isEmpty()); 400 path.reset(); 401 assertTrue(path.isEmpty()); 402 } 403 404 @Test 405 public void testToggleInverseFillType() { 406 Path path = new Path(); 407 assertTrue(path.isEmpty()); 408 path.toggleInverseFillType(); 409 assertTrue(path.isInverseFillType()); 410 } 411 412 @Test 413 public void testAddArc() { 414 Path path = new Path(); 415 assertTrue(path.isEmpty()); 416 RectF oval = new RectF(LEFT, TOP, RIGHT, BOTTOM); 417 path.addArc(oval, 0.0f, 30.0f); 418 assertFalse(path.isEmpty()); 419 } 420 421 @Test 422 public void testRCubicTo() { 423 Path path = new Path(); 424 assertTrue(path.isEmpty()); 425 path.rCubicTo(10.0f, 10.0f, 11.0f, 11.0f, 12.0f, 12.0f); 426 assertFalse(path.isEmpty()); 427 } 428 429 @Test 430 public void testOffsetTextPath() { 431 Paint paint = new Paint(); 432 Path path = new Path(); 433 paint.setTextSize(20); 434 String text = "abc"; 435 paint.getTextPath(text, 0, text.length() - 1, 0, 0, path); 436 RectF expectedRect = new RectF(); 437 path.computeBounds(expectedRect, false); 438 assertFalse(expectedRect.isEmpty()); 439 int offset = 10; 440 expectedRect.offset(offset, offset); 441 442 path.offset(offset, offset); 443 RectF offsettedRect = new RectF(); 444 path.computeBounds(offsettedRect, false); 445 assertEquals(expectedRect, offsettedRect); 446 } 447 448 @Test(expected=IllegalArgumentException.class) 449 public void testApproximate_lowError() { 450 new Path().approximate(-0.1f); 451 } 452 453 @Test 454 public void testApproximate_rect_cw() { 455 Path path = new Path(); 456 path.addRect(0, 0, 100, 100, Path.Direction.CW); 457 assertArrayEquals(new float[] { 458 0, 0, 0, 459 0.25f, 100, 0, 460 0.50f, 100, 100, 461 0.75f, 0, 100, 462 1, 0, 0, 463 }, path.approximate(1f), 0); 464 } 465 466 @Test 467 public void testApproximate_rect_ccw() { 468 Path path = new Path(); 469 path.addRect(0, 0, 100, 100, Path.Direction.CCW); 470 assertArrayEquals(new float[] { 471 0, 0, 0, 472 0.25f, 0, 100, 473 0.50f, 100, 100, 474 0.75f, 100, 0, 475 1, 0, 0, 476 }, path.approximate(1f), 0); 477 } 478 479 @Test 480 public void testApproximate_empty() { 481 Path path = new Path(); 482 assertArrayEquals(new float[] { 483 0, 0, 0, 484 1, 0, 0, 485 }, path.approximate(0.5f), 0); 486 } 487 488 @Test 489 public void testApproximate_circle() { 490 Path path = new Path(); 491 path.addCircle(0, 0, 50, Path.Direction.CW); 492 assertTrue(path.approximate(0.25f).length > 20); 493 } 494 495 /** This test just ensures the process doesn't crash. The actual output is not interesting 496 * hence the lack of asserts, as the only behavior that's being asserted is that it 497 * doesn't crash. 498 */ 499 @Test 500 public void testUseAfterFinalize() throws Throwable { 501 PathAbuser pathAbuser = new PathAbuser(); 502 503 // Basic test that we created a path successfully 504 assertTrue(pathAbuser.isEmpty()); 505 addRectToPath(pathAbuser); 506 assertTrue(pathAbuser.isRect(null)); 507 assertFalse(pathAbuser.isEmpty()); 508 509 // Now use-after-finalize. 510 pathAbuser.destroy(); 511 pathAbuser.isEmpty(); 512 pathAbuser.isRect(null); 513 pathAbuser.destroy(); 514 pathAbuser.isEmpty(); 515 pathAbuser.isRect(null); 516 pathAbuser.destroy(); 517 } 518 519 private static final class PathAbuser extends Path { 520 public void destroy() throws Throwable { 521 finalize(); 522 } 523 } 524 525 private static void verifyPathsAreEquivalent(Path actual, Path expected) { 526 Bitmap actualBitmap = drawAndGetBitmap(actual); 527 Bitmap expectedBitmap = drawAndGetBitmap(expected); 528 assertTrue(actualBitmap.sameAs(expectedBitmap)); 529 } 530 531 private static final int WIDTH = 100; 532 private static final int HEIGHT = 100; 533 534 private static Bitmap drawAndGetBitmap(Path path) { 535 Bitmap bitmap = Bitmap.createBitmap(WIDTH, HEIGHT, Bitmap.Config.ARGB_8888); 536 bitmap.eraseColor(Color.BLACK); 537 Paint paint = new Paint(); 538 paint.setColor(Color.RED); 539 Canvas canvas = new Canvas(bitmap); 540 canvas.drawPath(path, paint); 541 return bitmap; 542 } 543 544 private void addRectToPath(Path path) { 545 RectF rect = new RectF(LEFT, TOP, RIGHT, BOTTOM); 546 path.addRect(rect, Path.Direction.CW); 547 } 548 } 549