RecordingCanvasTests.cpp revision 388e43f4193bd2f1fd3687fada6bddab623f9a8c
1/* 2 * Copyright (C) 2015 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#include <gtest/gtest.h> 18 19#include <RecordedOp.h> 20#include <RecordingCanvas.h> 21#include <tests/common/TestUtils.h> 22#include <utils/Color.h> 23 24namespace android { 25namespace uirenderer { 26 27static void playbackOps(const DisplayList& displayList, 28 std::function<void(const RecordedOp&)> opReceiver) { 29 for (auto& chunk : displayList.getChunks()) { 30 for (size_t opIndex = chunk.beginOpIndex; opIndex < chunk.endOpIndex; opIndex++) { 31 RecordedOp* op = displayList.getOps()[opIndex]; 32 opReceiver(*op); 33 } 34 } 35} 36 37TEST(RecordingCanvas, emptyPlayback) { 38 auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) { 39 canvas.save(SaveFlags::MatrixClip); 40 canvas.restore(); 41 }); 42 playbackOps(*dl, [](const RecordedOp& op) { ADD_FAILURE(); }); 43} 44 45TEST(RecordingCanvas, clipRect) { 46 auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 100, [](RecordingCanvas& canvas) { 47 canvas.save(SaveFlags::MatrixClip); 48 canvas.clipRect(0, 0, 100, 100, SkRegion::kIntersect_Op); 49 canvas.drawRect(0, 0, 50, 50, SkPaint()); 50 canvas.drawRect(50, 50, 100, 100, SkPaint()); 51 canvas.restore(); 52 }); 53 54 ASSERT_EQ(2u, dl->getOps().size()) << "Must be exactly two ops"; 55 EXPECT_CLIP_RECT(Rect(100, 100), dl->getOps()[0]->localClip); 56 EXPECT_CLIP_RECT(Rect(100, 100), dl->getOps()[1]->localClip); 57 EXPECT_EQ(dl->getOps()[0]->localClip, dl->getOps()[1]->localClip) 58 << "Clip should be serialized once"; 59} 60 61TEST(RecordingCanvas, drawArc) { 62 auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) { 63 canvas.drawArc(0, 0, 200, 200, 0, 180, true, SkPaint()); 64 canvas.drawArc(0, 0, 100, 100, 0, 360, true, SkPaint()); 65 }); 66 67 auto&& ops = dl->getOps(); 68 ASSERT_EQ(2u, ops.size()) << "Must be exactly two ops"; 69 EXPECT_EQ(RecordedOpId::ArcOp, ops[0]->opId); 70 EXPECT_EQ(Rect(200, 200), ops[0]->unmappedBounds); 71 72 EXPECT_EQ(RecordedOpId::OvalOp, ops[1]->opId) 73 << "Circular arcs should be converted to ovals"; 74 EXPECT_EQ(Rect(100, 100), ops[1]->unmappedBounds); 75} 76 77TEST(RecordingCanvas, drawLines) { 78 auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) { 79 SkPaint paint; 80 paint.setStrokeWidth(20); // doesn't affect recorded bounds - would be resolved at bake time 81 float points[] = { 0, 0, 20, 10, 30, 40, 90 }; // NB: only 1 valid line 82 canvas.drawLines(&points[0], 7, paint); 83 }); 84 85 ASSERT_EQ(1u, dl->getOps().size()) << "Must be exactly one op"; 86 auto op = dl->getOps()[0]; 87 ASSERT_EQ(RecordedOpId::LinesOp, op->opId); 88 EXPECT_EQ(4, ((LinesOp*)op)->floatCount) 89 << "float count must be rounded down to closest multiple of 4"; 90 EXPECT_EQ(Rect(20, 10), op->unmappedBounds) 91 << "unmapped bounds must be size of line, and not outset for stroke width"; 92} 93 94TEST(RecordingCanvas, drawRect) { 95 auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) { 96 canvas.drawRect(10, 20, 90, 180, SkPaint()); 97 }); 98 99 ASSERT_EQ(1u, dl->getOps().size()) << "Must be exactly one op"; 100 auto op = *(dl->getOps()[0]); 101 ASSERT_EQ(RecordedOpId::RectOp, op.opId); 102 EXPECT_EQ(nullptr, op.localClip); 103 EXPECT_EQ(Rect(10, 20, 90, 180), op.unmappedBounds); 104} 105 106TEST(RecordingCanvas, drawText) { 107 auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) { 108 SkPaint paint; 109 paint.setAntiAlias(true); 110 paint.setTextSize(20); 111 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); 112 TestUtils::drawTextToCanvas(&canvas, "test text", paint, 25, 25); 113 }); 114 115 int count = 0; 116 playbackOps(*dl, [&count](const RecordedOp& op) { 117 count++; 118 ASSERT_EQ(RecordedOpId::TextOp, op.opId); 119 EXPECT_EQ(nullptr, op.localClip); 120 EXPECT_TRUE(op.localMatrix.isIdentity()); 121 EXPECT_TRUE(op.unmappedBounds.contains(25, 15, 50, 25)) 122 << "Op expected to be 25+ pixels wide, 10+ pixels tall"; 123 }); 124 ASSERT_EQ(1, count); 125} 126 127TEST(RecordingCanvas, drawText_strikeThruAndUnderline) { 128 auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) { 129 SkPaint paint; 130 paint.setAntiAlias(true); 131 paint.setTextSize(20); 132 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); 133 for (int i = 0; i < 2; i++) { 134 for (int j = 0; j < 2; j++) { 135 paint.setUnderlineText(i != 0); 136 paint.setStrikeThruText(j != 0); 137 TestUtils::drawTextToCanvas(&canvas, "test text", paint, 25, 25); 138 } 139 } 140 }); 141 142 auto ops = dl->getOps(); 143 ASSERT_EQ(8u, ops.size()); 144 145 int index = 0; 146 EXPECT_EQ(RecordedOpId::TextOp, ops[index++]->opId); // no underline or strikethrough 147 148 EXPECT_EQ(RecordedOpId::TextOp, ops[index++]->opId); 149 EXPECT_EQ(RecordedOpId::RectOp, ops[index++]->opId); // strikethrough only 150 151 EXPECT_EQ(RecordedOpId::TextOp, ops[index++]->opId); 152 EXPECT_EQ(RecordedOpId::RectOp, ops[index++]->opId); // underline only 153 154 EXPECT_EQ(RecordedOpId::TextOp, ops[index++]->opId); 155 EXPECT_EQ(RecordedOpId::RectOp, ops[index++]->opId); // underline 156 EXPECT_EQ(RecordedOpId::RectOp, ops[index++]->opId); // strikethrough 157} 158 159TEST(RecordingCanvas, drawText_forceAlignLeft) { 160 auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) { 161 SkPaint paint; 162 paint.setAntiAlias(true); 163 paint.setTextSize(20); 164 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); 165 paint.setTextAlign(SkPaint::kLeft_Align); 166 TestUtils::drawTextToCanvas(&canvas, "test text", paint, 25, 25); 167 paint.setTextAlign(SkPaint::kCenter_Align); 168 TestUtils::drawTextToCanvas(&canvas, "test text", paint, 25, 25); 169 paint.setTextAlign(SkPaint::kRight_Align); 170 TestUtils::drawTextToCanvas(&canvas, "test text", paint, 25, 25); 171 }); 172 173 int count = 0; 174 float lastX = FLT_MAX; 175 playbackOps(*dl, [&count, &lastX](const RecordedOp& op) { 176 count++; 177 ASSERT_EQ(RecordedOpId::TextOp, op.opId); 178 EXPECT_EQ(SkPaint::kLeft_Align, op.paint->getTextAlign()) 179 << "recorded drawText commands must force kLeft_Align on their paint"; 180 181 // verify TestUtils alignment offsetting (TODO: move asserts to Canvas base class) 182 EXPECT_GT(lastX, ((const TextOp&)op).x) 183 << "x coordinate should reduce across each of the draw commands, from alignment"; 184 lastX = ((const TextOp&)op).x; 185 }); 186 ASSERT_EQ(3, count); 187} 188 189TEST(RecordingCanvas, drawColor) { 190 auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) { 191 canvas.drawColor(Color::Black, SkXfermode::kSrcOver_Mode); 192 }); 193 194 ASSERT_EQ(1u, dl->getOps().size()) << "Must be exactly one op"; 195 auto op = *(dl->getOps()[0]); 196 EXPECT_EQ(RecordedOpId::RectOp, op.opId); 197 EXPECT_EQ(nullptr, op.localClip); 198 EXPECT_TRUE(op.unmappedBounds.contains(Rect(-1000, -1000, 1000, 1000))) 199 << "no clip, unmappedBounds should resolve to be much larger than DL bounds"; 200} 201 202TEST(RecordingCanvas, backgroundAndImage) { 203 auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) { 204 SkBitmap bitmap; 205 bitmap.setInfo(SkImageInfo::MakeUnknown(25, 25)); 206 SkPaint paint; 207 paint.setColor(SK_ColorBLUE); 208 209 canvas.save(SaveFlags::MatrixClip); 210 { 211 // a background! 212 canvas.save(SaveFlags::MatrixClip); 213 canvas.drawRect(0, 0, 100, 200, paint); 214 canvas.restore(); 215 } 216 { 217 // an image! 218 canvas.save(SaveFlags::MatrixClip); 219 canvas.translate(25, 25); 220 canvas.scale(2, 2); 221 canvas.drawBitmap(bitmap, 0, 0, nullptr); 222 canvas.restore(); 223 } 224 canvas.restore(); 225 }); 226 227 int count = 0; 228 playbackOps(*dl, [&count](const RecordedOp& op) { 229 if (count == 0) { 230 ASSERT_EQ(RecordedOpId::RectOp, op.opId); 231 ASSERT_NE(nullptr, op.paint); 232 EXPECT_EQ(SK_ColorBLUE, op.paint->getColor()); 233 EXPECT_EQ(Rect(100, 200), op.unmappedBounds); 234 EXPECT_EQ(nullptr, op.localClip); 235 236 Matrix4 expectedMatrix; 237 expectedMatrix.loadIdentity(); 238 EXPECT_MATRIX_APPROX_EQ(expectedMatrix, op.localMatrix); 239 } else { 240 ASSERT_EQ(RecordedOpId::BitmapOp, op.opId); 241 EXPECT_EQ(nullptr, op.paint); 242 EXPECT_EQ(Rect(25, 25), op.unmappedBounds); 243 EXPECT_EQ(nullptr, op.localClip); 244 245 Matrix4 expectedMatrix; 246 expectedMatrix.loadTranslate(25, 25, 0); 247 expectedMatrix.scale(2, 2, 1); 248 EXPECT_MATRIX_APPROX_EQ(expectedMatrix, op.localMatrix); 249 } 250 count++; 251 }); 252 ASSERT_EQ(2, count); 253} 254 255TEST(RecordingCanvas, saveLayer_simple) { 256 auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) { 257 canvas.saveLayerAlpha(10, 20, 190, 180, 128, SaveFlags::ClipToLayer); 258 canvas.drawRect(10, 20, 190, 180, SkPaint()); 259 canvas.restore(); 260 }); 261 int count = 0; 262 playbackOps(*dl, [&count](const RecordedOp& op) { 263 Matrix4 expectedMatrix; 264 switch(count++) { 265 case 0: 266 EXPECT_EQ(RecordedOpId::BeginLayerOp, op.opId); 267 EXPECT_EQ(Rect(10, 20, 190, 180), op.unmappedBounds); 268 EXPECT_EQ(nullptr, op.localClip); 269 EXPECT_TRUE(op.localMatrix.isIdentity()); 270 break; 271 case 1: 272 EXPECT_EQ(RecordedOpId::RectOp, op.opId); 273 EXPECT_CLIP_RECT(Rect(180, 160), op.localClip); 274 EXPECT_EQ(Rect(10, 20, 190, 180), op.unmappedBounds); 275 expectedMatrix.loadTranslate(-10, -20, 0); 276 EXPECT_MATRIX_APPROX_EQ(expectedMatrix, op.localMatrix); 277 break; 278 case 2: 279 EXPECT_EQ(RecordedOpId::EndLayerOp, op.opId); 280 // Don't bother asserting recording state data - it's not used 281 break; 282 default: 283 ADD_FAILURE(); 284 } 285 }); 286 EXPECT_EQ(3, count); 287} 288 289TEST(RecordingCanvas, saveLayer_missingRestore) { 290 auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) { 291 canvas.saveLayerAlpha(0, 0, 200, 200, 128, SaveFlags::ClipToLayer); 292 canvas.drawRect(0, 0, 200, 200, SkPaint()); 293 // Note: restore omitted, shouldn't result in unmatched save 294 }); 295 int count = 0; 296 playbackOps(*dl, [&count](const RecordedOp& op) { 297 if (count++ == 2) { 298 EXPECT_EQ(RecordedOpId::EndLayerOp, op.opId); 299 } 300 }); 301 EXPECT_EQ(3, count) << "Missing a restore shouldn't result in an unmatched saveLayer"; 302} 303 304TEST(RecordingCanvas, saveLayer_simpleUnclipped) { 305 auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) { 306 canvas.saveLayerAlpha(10, 20, 190, 180, 128, (SaveFlags::Flags)0); // unclipped 307 canvas.drawRect(10, 20, 190, 180, SkPaint()); 308 canvas.restore(); 309 }); 310 int count = 0; 311 playbackOps(*dl, [&count](const RecordedOp& op) { 312 switch(count++) { 313 case 0: 314 EXPECT_EQ(RecordedOpId::BeginUnclippedLayerOp, op.opId); 315 EXPECT_EQ(Rect(10, 20, 190, 180), op.unmappedBounds); 316 EXPECT_EQ(nullptr, op.localClip); 317 EXPECT_TRUE(op.localMatrix.isIdentity()); 318 break; 319 case 1: 320 EXPECT_EQ(RecordedOpId::RectOp, op.opId); 321 EXPECT_EQ(nullptr, op.localClip); 322 EXPECT_EQ(Rect(10, 20, 190, 180), op.unmappedBounds); 323 EXPECT_TRUE(op.localMatrix.isIdentity()); 324 break; 325 case 2: 326 EXPECT_EQ(RecordedOpId::EndUnclippedLayerOp, op.opId); 327 // Don't bother asserting recording state data - it's not used 328 break; 329 default: 330 ADD_FAILURE(); 331 } 332 }); 333 EXPECT_EQ(3, count); 334} 335 336TEST(RecordingCanvas, saveLayer_addClipFlag) { 337 auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) { 338 canvas.save(SaveFlags::MatrixClip); 339 canvas.clipRect(10, 20, 190, 180, SkRegion::kIntersect_Op); 340 canvas.saveLayerAlpha(10, 20, 190, 180, 128, (SaveFlags::Flags)0); // unclipped 341 canvas.drawRect(10, 20, 190, 180, SkPaint()); 342 canvas.restore(); 343 canvas.restore(); 344 }); 345 int count = 0; 346 playbackOps(*dl, [&count](const RecordedOp& op) { 347 if (count++ == 0) { 348 EXPECT_EQ(RecordedOpId::BeginLayerOp, op.opId) 349 << "Clip + unclipped saveLayer should result in a clipped layer"; 350 } 351 }); 352 EXPECT_EQ(3, count); 353} 354 355TEST(RecordingCanvas, saveLayer_viewportCrop) { 356 auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) { 357 // shouldn't matter, since saveLayer will clip to its bounds 358 canvas.clipRect(-1000, -1000, 1000, 1000, SkRegion::kReplace_Op); 359 360 canvas.saveLayerAlpha(100, 100, 300, 300, 128, SaveFlags::ClipToLayer); 361 canvas.drawRect(0, 0, 400, 400, SkPaint()); 362 canvas.restore(); 363 }); 364 int count = 0; 365 playbackOps(*dl, [&count](const RecordedOp& op) { 366 if (count++ == 1) { 367 Matrix4 expectedMatrix; 368 EXPECT_EQ(RecordedOpId::RectOp, op.opId); 369 EXPECT_CLIP_RECT(Rect(100, 100), op.localClip) // Recorded clip rect should be 370 // intersection of viewport and saveLayer bounds, in layer space; 371 EXPECT_EQ(Rect(400, 400), op.unmappedBounds); 372 expectedMatrix.loadTranslate(-100, -100, 0); 373 EXPECT_MATRIX_APPROX_EQ(expectedMatrix, op.localMatrix); 374 } 375 }); 376 EXPECT_EQ(3, count); 377} 378 379TEST(RecordingCanvas, saveLayer_rotateUnclipped) { 380 auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) { 381 canvas.save(SaveFlags::MatrixClip); 382 canvas.translate(100, 100); 383 canvas.rotate(45); 384 canvas.translate(-50, -50); 385 386 canvas.saveLayerAlpha(0, 0, 100, 100, 128, SaveFlags::ClipToLayer); 387 canvas.drawRect(0, 0, 100, 100, SkPaint()); 388 canvas.restore(); 389 390 canvas.restore(); 391 }); 392 int count = 0; 393 playbackOps(*dl, [&count](const RecordedOp& op) { 394 if (count++ == 1) { 395 EXPECT_EQ(RecordedOpId::RectOp, op.opId); 396 EXPECT_CLIP_RECT(Rect(100, 100), op.localClip); 397 EXPECT_EQ(Rect(100, 100), op.unmappedBounds); 398 EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), op.localMatrix) 399 << "Recorded op shouldn't see any canvas transform before the saveLayer"; 400 } 401 }); 402 EXPECT_EQ(3, count); 403} 404 405TEST(RecordingCanvas, saveLayer_rotateClipped) { 406 auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) { 407 canvas.save(SaveFlags::MatrixClip); 408 canvas.translate(100, 100); 409 canvas.rotate(45); 410 canvas.translate(-200, -200); 411 412 // area of saveLayer will be clipped to parent viewport, so we ask for 400x400... 413 canvas.saveLayerAlpha(0, 0, 400, 400, 128, SaveFlags::ClipToLayer); 414 canvas.drawRect(0, 0, 400, 400, SkPaint()); 415 canvas.restore(); 416 417 canvas.restore(); 418 }); 419 int count = 0; 420 playbackOps(*dl, [&count](const RecordedOp& op) { 421 if (count++ == 1) { 422 Matrix4 expectedMatrix; 423 EXPECT_EQ(RecordedOpId::RectOp, op.opId); 424 425 // ...and get about 58.6, 58.6, 341.4 341.4, because the bounds are clipped by 426 // the parent 200x200 viewport, but prior to rotation 427 ASSERT_NE(nullptr, op.localClip); 428 ASSERT_EQ(ClipMode::Rectangle, op.localClip->mode); 429 // NOTE: this check relies on saveLayer altering the clip post-viewport init. This 430 // causes the clip to be recorded by contained draw commands, though it's not necessary 431 // since the same clip will be computed at draw time. If such a change is made, this 432 // check could be done at record time by querying the clip, or the clip could be altered 433 // slightly so that it is serialized. 434 EXPECT_RECT_APPROX_EQ(Rect(58.57864, 58.57864, 341.42136, 341.42136), 435 (reinterpret_cast<const ClipRect*>(op.localClip))->rect); 436 437 EXPECT_EQ(Rect(400, 400), op.unmappedBounds); 438 expectedMatrix.loadIdentity(); 439 EXPECT_MATRIX_APPROX_EQ(expectedMatrix, op.localMatrix); 440 } 441 }); 442 EXPECT_EQ(3, count); 443} 444 445TEST(RecordingCanvas, drawRenderNode_projection) { 446 sp<RenderNode> background = TestUtils::createNode(50, 50, 150, 150, 447 [](RenderProperties& props, RecordingCanvas& canvas) { 448 SkPaint paint; 449 paint.setColor(SK_ColorWHITE); 450 canvas.drawRect(0, 0, 100, 100, paint); 451 }); 452 { 453 background->mutateStagingProperties().setProjectionReceiver(false); 454 455 // NO RECEIVER PRESENT 456 auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, 457 [&background](RecordingCanvas& canvas) { 458 canvas.drawRect(0, 0, 100, 100, SkPaint()); 459 canvas.drawRenderNode(background.get()); 460 canvas.drawRect(0, 0, 100, 100, SkPaint()); 461 }); 462 EXPECT_EQ(-1, dl->projectionReceiveIndex) 463 << "no projection receiver should have been observed"; 464 } 465 { 466 background->mutateStagingProperties().setProjectionReceiver(true); 467 468 // RECEIVER PRESENT 469 auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, 470 [&background](RecordingCanvas& canvas) { 471 canvas.drawRect(0, 0, 100, 100, SkPaint()); 472 canvas.drawRenderNode(background.get()); 473 canvas.drawRect(0, 0, 100, 100, SkPaint()); 474 }); 475 476 ASSERT_EQ(3u, dl->getOps().size()) << "Must be three ops"; 477 auto op = dl->getOps()[1]; 478 EXPECT_EQ(RecordedOpId::RenderNodeOp, op->opId); 479 EXPECT_EQ(1, dl->projectionReceiveIndex) 480 << "correct projection receiver not identified"; 481 482 // verify the behavior works even though projection receiver hasn't been sync'd yet 483 EXPECT_TRUE(background->stagingProperties().isProjectionReceiver()); 484 EXPECT_FALSE(background->properties().isProjectionReceiver()); 485 } 486} 487 488TEST(RecordingCanvas, firstClipWillReplace) { 489 auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) { 490 canvas.save(SaveFlags::MatrixClip); 491 // since no explicit clip set on canvas, this should be the one observed on op: 492 canvas.clipRect(-100, -100, 300, 300, SkRegion::kIntersect_Op); 493 494 SkPaint paint; 495 paint.setColor(SK_ColorWHITE); 496 canvas.drawRect(0, 0, 100, 100, paint); 497 498 canvas.restore(); 499 }); 500 ASSERT_EQ(1u, dl->getOps().size()) << "Must have one op"; 501 // first clip must be preserved, even if it extends beyond canvas bounds 502 EXPECT_CLIP_RECT(Rect(-100, -100, 300, 300), dl->getOps()[0]->localClip); 503} 504 505TEST(RecordingCanvas, insertReorderBarrier) { 506 auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) { 507 canvas.drawRect(0, 0, 400, 400, SkPaint()); 508 canvas.insertReorderBarrier(true); 509 canvas.insertReorderBarrier(false); 510 canvas.insertReorderBarrier(false); 511 canvas.insertReorderBarrier(true); 512 canvas.drawRect(0, 0, 400, 400, SkPaint()); 513 canvas.insertReorderBarrier(false); 514 }); 515 516 auto chunks = dl->getChunks(); 517 EXPECT_EQ(0u, chunks[0].beginOpIndex); 518 EXPECT_EQ(1u, chunks[0].endOpIndex); 519 EXPECT_FALSE(chunks[0].reorderChildren); 520 521 EXPECT_EQ(1u, chunks[1].beginOpIndex); 522 EXPECT_EQ(2u, chunks[1].endOpIndex); 523 EXPECT_TRUE(chunks[1].reorderChildren); 524} 525 526TEST(RecordingCanvas, refPaint) { 527 SkPaint paint; 528 paint.setAntiAlias(true); 529 paint.setTextSize(20); 530 paint.setTextAlign(SkPaint::kLeft_Align); 531 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); 532 533 auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [&paint](RecordingCanvas& canvas) { 534 paint.setColor(SK_ColorBLUE); 535 // first three should use same paint 536 canvas.drawRect(0, 0, 200, 10, paint); 537 SkPaint paintCopy(paint); 538 canvas.drawRect(0, 10, 200, 20, paintCopy); 539 TestUtils::drawTextToCanvas(&canvas, "helloworld", paint, 50, 25); 540 541 // only here do we use different paint ptr 542 paint.setColor(SK_ColorRED); 543 canvas.drawRect(0, 20, 200, 30, paint); 544 }); 545 auto ops = dl->getOps(); 546 ASSERT_EQ(4u, ops.size()); 547 548 // first three are the same 549 EXPECT_NE(nullptr, ops[0]->paint); 550 EXPECT_NE(&paint, ops[0]->paint); 551 EXPECT_EQ(ops[0]->paint, ops[1]->paint); 552 EXPECT_EQ(ops[0]->paint, ops[2]->paint); 553 554 // last is different, but still copied / non-null 555 EXPECT_NE(nullptr, ops[3]->paint); 556 EXPECT_NE(ops[0]->paint, ops[3]->paint); 557 EXPECT_NE(&paint, ops[3]->paint); 558} 559 560} // namespace uirenderer 561} // namespace android 562