1 /*
2 * Copyright (C) 2020 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 <canvas/CanvasFrontend.h>
20 #include <canvas/CanvasOpBuffer.h>
21 #include <canvas/CanvasOps.h>
22 #include <canvas/CanvasOpRasterizer.h>
23
24 #include <tests/common/CallCountingCanvas.h>
25
26 #include "SkPictureRecorder.h"
27 #include "SkColor.h"
28 #include "SkLatticeIter.h"
29 #include "pipeline/skia/AnimatedDrawables.h"
30 #include <SkNoDrawCanvas.h>
31
32 using namespace android;
33 using namespace android::uirenderer;
34 using namespace android::uirenderer::skiapipeline;
35 using namespace android::uirenderer::test;
36
37 // We lazy
38 using Op = CanvasOpType;
39
40 class CanvasOpCountingReceiver {
41 public:
42 template <CanvasOpType T>
push_container(CanvasOpContainer<T> && op)43 void push_container(CanvasOpContainer<T>&& op) {
44 mOpCounts[static_cast<size_t>(T)] += 1;
45 }
46
operator [](CanvasOpType op) const47 int operator[](CanvasOpType op) const {
48 return mOpCounts[static_cast<size_t>(op)];
49 }
50
51 private:
52 std::array<int, static_cast<size_t>(CanvasOpType::COUNT)> mOpCounts;
53 };
54
55 template<typename T>
countItems(const T & t)56 static int countItems(const T& t) {
57 int count = 0;
58 t.for_each([&](auto i) {
59 count++;
60 });
61 return count;
62 }
63
TEST(CanvasOp,verifyConst)64 TEST(CanvasOp, verifyConst) {
65 CanvasOpBuffer buffer;
66 buffer.push<Op::DrawColor>({
67 .color = SkColors::kBlack,
68 .mode = SkBlendMode::kSrcOver,
69 });
70 buffer.for_each([](auto op) {
71 static_assert(std::is_const_v<std::remove_reference_t<decltype(*op)>>,
72 "Expected container to be const");
73 static_assert(std::is_const_v<std::remove_reference_t<decltype(op->op())>>,
74 "Expected op to be const");
75 });
76 }
77
TEST(CanvasOp,simplePush)78 TEST(CanvasOp, simplePush) {
79 CanvasOpBuffer buffer;
80 EXPECT_EQ(buffer.size(), 0);
81 buffer.push<Op::Save>({});
82 buffer.push<Op::Save>({});
83 buffer.push<Op::Restore>({});
84 EXPECT_GT(buffer.size(), 0);
85
86 int saveCount = 0;
87 int restoreCount = 0;
88 int otherCount = 0;
89
90 buffer.for_each([&](auto op) {
91 switch (op->type()) {
92 case Op::Save:
93 saveCount++;
94 break;
95 case Op::Restore:
96 restoreCount++;
97 break;
98 default:
99 otherCount++;
100 break;
101 }
102 });
103
104 EXPECT_EQ(saveCount, 2);
105 EXPECT_EQ(restoreCount, 1);
106 EXPECT_EQ(otherCount, 0);
107
108 buffer.clear();
109 int itemCount = 0;
110 buffer.for_each([&](auto op) {
111 itemCount++;
112 });
113 EXPECT_EQ(itemCount, 0);
114 buffer.resize(0);
115 EXPECT_EQ(buffer.size(), 0);
116 }
117
TEST(CanvasOp,simpleDrawPaint)118 TEST(CanvasOp, simpleDrawPaint) {
119 CanvasOpBuffer buffer;
120 EXPECT_EQ(buffer.size(), 0);
121 buffer.push<Op::DrawColor> ({
122 .color = SkColor4f{1, 1, 1, 1},
123 .mode = SkBlendMode::kSrcIn
124 });
125
126 CallCountingCanvas canvas;
127 EXPECT_EQ(0, canvas.sumTotalDrawCalls());
128 rasterizeCanvasBuffer(buffer, &canvas);
129 EXPECT_EQ(1, canvas.drawPaintCount);
130 EXPECT_EQ(1, canvas.sumTotalDrawCalls());
131 }
132
TEST(CanvasOp,simpleDrawPoint)133 TEST(CanvasOp, simpleDrawPoint) {
134 CanvasOpBuffer buffer;
135 EXPECT_EQ(buffer.size(), 0);
136 buffer.push<Op::DrawPoint> ({
137 .x = 12,
138 .y = 42,
139 .paint = SkPaint{}
140 });
141
142 CallCountingCanvas canvas;
143 EXPECT_EQ(0, canvas.sumTotalDrawCalls());
144 rasterizeCanvasBuffer(buffer, &canvas);
145 EXPECT_EQ(1, canvas.drawPoints);
146 EXPECT_EQ(1, canvas.sumTotalDrawCalls());
147 }
148
TEST(CanvasOp,simpleDrawPoints)149 TEST(CanvasOp, simpleDrawPoints) {
150 CanvasOpBuffer buffer;
151 EXPECT_EQ(buffer.size(), 0);
152 size_t numPts = 3;
153 auto pts = sk_sp<Points>(
154 new Points({
155 {32, 16},
156 {48, 48},
157 {16, 32}
158 })
159 );
160
161 buffer.push(CanvasOp<Op::DrawPoints> {
162 .count = numPts,
163 .paint = SkPaint{},
164 .points = pts
165 });
166
167 CallCountingCanvas canvas;
168 EXPECT_EQ(0, canvas.sumTotalDrawCalls());
169 rasterizeCanvasBuffer(buffer, &canvas);
170 EXPECT_EQ(1, canvas.drawPoints);
171 EXPECT_EQ(1, canvas.sumTotalDrawCalls());
172 }
173
TEST(CanvasOp,simpleDrawLine)174 TEST(CanvasOp, simpleDrawLine) {
175 CanvasOpBuffer buffer;
176 EXPECT_EQ(buffer.size(), 0);
177 buffer.push<Op::DrawLine> ({
178 .startX = 16,
179 .startY = 28,
180 .endX = 12,
181 .endY = 30,
182 .paint = SkPaint{}
183 });
184
185 CallCountingCanvas canvas;
186 EXPECT_EQ(0, canvas.sumTotalDrawCalls());
187 rasterizeCanvasBuffer(buffer, &canvas);
188 EXPECT_EQ(1, canvas.drawPoints);
189 EXPECT_EQ(1, canvas.sumTotalDrawCalls());
190 }
191
TEST(CanvasOp,simpleDrawLines)192 TEST(CanvasOp, simpleDrawLines) {
193 CanvasOpBuffer buffer;
194 EXPECT_EQ(buffer.size(), 0);
195 size_t numPts = 3;
196 auto pts = sk_sp<Points>(
197 new Points({
198 {32, 16},
199 {48, 48},
200 {16, 32}
201 })
202 );
203 buffer.push(CanvasOp<Op::DrawLines> {
204 .count = numPts,
205 .paint = SkPaint{},
206 .points = pts
207 });
208
209 CallCountingCanvas canvas;
210 EXPECT_EQ(0, canvas.sumTotalDrawCalls());
211 rasterizeCanvasBuffer(buffer, &canvas);
212 EXPECT_EQ(1, canvas.drawPoints);
213 EXPECT_EQ(1, canvas.sumTotalDrawCalls());
214 }
215
TEST(CanvasOp,simpleDrawRect)216 TEST(CanvasOp, simpleDrawRect) {
217 CanvasOpBuffer buffer;
218 EXPECT_EQ(buffer.size(), 0);
219 buffer.push<Op::DrawRect> ({
220 .paint = SkPaint{},
221 .rect = SkRect::MakeEmpty()
222 });
223
224 CallCountingCanvas canvas;
225 EXPECT_EQ(0, canvas.sumTotalDrawCalls());
226 rasterizeCanvasBuffer(buffer, &canvas);
227 EXPECT_EQ(1, canvas.drawRectCount);
228 EXPECT_EQ(1, canvas.sumTotalDrawCalls());
229 }
230
TEST(CanvasOp,simpleDrawRegionRect)231 TEST(CanvasOp, simpleDrawRegionRect) {
232 CanvasOpBuffer buffer;
233 EXPECT_EQ(buffer.size(), 0);
234 SkRegion region;
235 region.setRect(SkIRect::MakeWH(12, 50));
236 buffer.push<Op::DrawRegion> ({
237 .paint = SkPaint{},
238 .region = region
239 });
240
241 CallCountingCanvas canvas;
242 EXPECT_EQ(0, canvas.sumTotalDrawCalls());
243 rasterizeCanvasBuffer(buffer, &canvas);
244 // If the region is a rectangle, drawRegion calls into drawRect as a fast path
245 EXPECT_EQ(1, canvas.drawRectCount);
246 EXPECT_EQ(1, canvas.sumTotalDrawCalls());
247 }
248
TEST(CanvasOp,simpleDrawRegionPath)249 TEST(CanvasOp, simpleDrawRegionPath) {
250 CanvasOpBuffer buffer;
251 EXPECT_EQ(buffer.size(), 0);
252 SkPath path;
253 path.addCircle(50, 50, 50);
254 SkRegion clip;
255 clip.setRect(SkIRect::MakeWH(100, 100));
256 SkRegion region;
257 region.setPath(path, clip);
258 buffer.push<Op::DrawRegion> ({
259 .paint = SkPaint{},
260 .region = region
261 });
262
263 CallCountingCanvas canvas;
264 EXPECT_EQ(0, canvas.sumTotalDrawCalls());
265 rasterizeCanvasBuffer(buffer, &canvas);
266 EXPECT_EQ(1, canvas.drawRegionCount);
267 EXPECT_EQ(1, canvas.sumTotalDrawCalls());
268 }
269
TEST(CanvasOp,simpleDrawRoundRect)270 TEST(CanvasOp, simpleDrawRoundRect) {
271 CanvasOpBuffer buffer;
272 EXPECT_EQ(buffer.size(), 0);
273 buffer.push<Op::DrawRoundRect> ({
274 .paint = SkPaint{},
275 .rect = SkRect::MakeEmpty(),
276 .rx = 10,
277 .ry = 10
278 });
279
280 CallCountingCanvas canvas;
281 EXPECT_EQ(0, canvas.sumTotalDrawCalls());
282 rasterizeCanvasBuffer(buffer, &canvas);
283 EXPECT_EQ(1, canvas.drawRRectCount);
284 EXPECT_EQ(1, canvas.sumTotalDrawCalls());
285 }
286
TEST(CanvasOp,simpleDrawDoubleRoundRect)287 TEST(CanvasOp, simpleDrawDoubleRoundRect) {
288 CanvasOpBuffer buffer;
289 EXPECT_EQ(buffer.size(), 0);
290 SkRect outer = SkRect::MakeLTRB(0, 0, 100, 100);
291 SkRect inner = SkRect::MakeLTRB(20, 20, 80, 80);
292
293 const int numPts = 4;
294 SkRRect outerRRect;
295
296 auto outerPts = std::make_unique<SkVector[]>(numPts);
297 outerPts[0].set(32, 16);
298 outerPts[1].set(48, 48);
299 outerPts[2].set(16, 32);
300 outerPts[3].set(20, 20);
301 outerRRect.setRectRadii(outer, outerPts.get());
302 outerRRect.setRect(outer);
303
304 SkRRect innerRRect;
305 auto innerPts = std::make_unique<SkVector[]>(numPts);
306 innerPts[0].set(16, 8);
307 innerPts[1].set(24, 24);
308 innerPts[2].set(8, 16);
309 innerPts[3].set(10, 10);
310 innerRRect.setRectRadii(inner, innerPts.get());
311
312 buffer.push<Op::DrawDoubleRoundRect> ({
313 .outer = outerRRect,
314 .inner = innerRRect,
315 .paint = SkPaint{}
316 });
317
318 CallCountingCanvas canvas;
319 EXPECT_EQ(0, canvas.sumTotalDrawCalls());
320 rasterizeCanvasBuffer(buffer, &canvas);
321 EXPECT_EQ(1, canvas.drawDRRectCount);
322 EXPECT_EQ(1, canvas.sumTotalDrawCalls());
323 }
324
TEST(CanvasOp,simpleDrawCircle)325 TEST(CanvasOp, simpleDrawCircle) {
326 CanvasOpBuffer buffer;
327 EXPECT_EQ(buffer.size(), 0);
328 buffer.push<Op::DrawCircle>({
329 .cx = 5,
330 .cy = 7,
331 .radius = 10,
332 .paint = SkPaint{}
333 });
334
335 CallCountingCanvas canvas;
336 EXPECT_EQ(0, canvas.sumTotalDrawCalls());
337 rasterizeCanvasBuffer(buffer, &canvas);
338 EXPECT_EQ(1, canvas.drawOvalCount);
339 EXPECT_EQ(1, canvas.sumTotalDrawCalls());
340 }
341
TEST(CanvasOp,simpleDrawOval)342 TEST(CanvasOp, simpleDrawOval) {
343 CanvasOpBuffer buffer;
344 EXPECT_EQ(buffer.size(), 0);
345 buffer.push<Op::DrawOval> ({
346 .oval = SkRect::MakeEmpty(),
347 .paint = SkPaint{}
348 });
349
350 CallCountingCanvas canvas;
351 EXPECT_EQ(0, canvas.sumTotalDrawCalls());
352 rasterizeCanvasBuffer(buffer, &canvas);
353 EXPECT_EQ(1, canvas.drawOvalCount);
354 EXPECT_EQ(1, canvas.sumTotalDrawCalls());
355 }
356
TEST(CanvasOp,simpleDrawArc)357 TEST(CanvasOp, simpleDrawArc) {
358 CanvasOpBuffer buffer;
359 EXPECT_EQ(buffer.size(), 0);
360 buffer.push<Op::DrawArc>({
361 .oval = SkRect::MakeWH(100, 100),
362 .startAngle = 120,
363 .sweepAngle = 70,
364 .useCenter = true,
365 .paint = SkPaint{}
366 });
367
368 CallCountingCanvas canvas;
369 EXPECT_EQ(0, canvas.sumTotalDrawCalls());
370 rasterizeCanvasBuffer(buffer, &canvas);
371 EXPECT_EQ(1, canvas.drawArcCount);
372 EXPECT_EQ(1, canvas.sumTotalDrawCalls());
373 }
374
TEST(CanvasOp,simpleDrawPath)375 TEST(CanvasOp, simpleDrawPath) {
376 CanvasOpBuffer buffer;
377 EXPECT_EQ(buffer.size(), 0);
378 SkPath path;
379 path.addCircle(50, 50, 30);
380 buffer.push<Op::DrawPath> ({
381 .path = path,
382 .paint = SkPaint{}
383 });
384
385 CallCountingCanvas canvas;
386 EXPECT_EQ(0, canvas.sumTotalDrawCalls());
387 rasterizeCanvasBuffer(buffer, &canvas);
388 EXPECT_EQ(1, canvas.drawPathCount);
389 EXPECT_EQ(1, canvas.sumTotalDrawCalls());
390 }
391
TEST(CanvasOp,simpleDrawRoundRectProperty)392 TEST(CanvasOp, simpleDrawRoundRectProperty) {
393 CanvasOpBuffer buffer;
394 EXPECT_EQ(buffer.size(), 0);
395
396 auto left = sp<CanvasPropertyPrimitive>(new uirenderer::CanvasPropertyPrimitive(1));
397 auto top = sp<CanvasPropertyPrimitive>(new uirenderer::CanvasPropertyPrimitive(2));
398 auto right = sp<CanvasPropertyPrimitive>(new uirenderer::CanvasPropertyPrimitive(3));
399 auto bottom = sp<CanvasPropertyPrimitive>(new uirenderer::CanvasPropertyPrimitive(4));
400 auto radiusX = sp<CanvasPropertyPrimitive>(new uirenderer::CanvasPropertyPrimitive(5));
401 auto radiusY = sp<CanvasPropertyPrimitive>(new uirenderer::CanvasPropertyPrimitive(6));
402 auto propertyPaint =
403 sp<uirenderer::CanvasPropertyPaint>(new uirenderer::CanvasPropertyPaint(SkPaint{}));
404
405 buffer.push<Op::DrawRoundRectProperty> ({
406 .left = left,
407 .top = top,
408 .right = right,
409 .bottom = bottom,
410 .rx = radiusX,
411 .ry = radiusY,
412 .paint = propertyPaint
413 });
414
415 CallCountingCanvas canvas;
416 EXPECT_EQ(0, canvas.sumTotalDrawCalls());
417 rasterizeCanvasBuffer(buffer, &canvas);
418 EXPECT_EQ(1, canvas.drawRRectCount);
419 EXPECT_EQ(1, canvas.sumTotalDrawCalls());
420 }
421
TEST(CanvasOp,simpleDrawCircleProperty)422 TEST(CanvasOp, simpleDrawCircleProperty) {
423 CanvasOpBuffer buffer;
424 EXPECT_EQ(buffer.size(), 0);
425
426 auto x = sp<CanvasPropertyPrimitive>(new uirenderer::CanvasPropertyPrimitive(1));
427 auto y = sp<CanvasPropertyPrimitive>(new uirenderer::CanvasPropertyPrimitive(2));
428 auto radius = sp<CanvasPropertyPrimitive>(new uirenderer::CanvasPropertyPrimitive(5));
429 auto propertyPaint =
430 sp<uirenderer::CanvasPropertyPaint>(new uirenderer::CanvasPropertyPaint(SkPaint{}));
431
432 buffer.push<Op::DrawCircleProperty> ({
433 .x = x,
434 .y = y,
435 .radius = radius,
436 .paint = propertyPaint
437 });
438
439 CallCountingCanvas canvas;
440 EXPECT_EQ(0, canvas.sumTotalDrawCalls());
441 rasterizeCanvasBuffer(buffer, &canvas);
442 EXPECT_EQ(1, canvas.drawOvalCount);
443 EXPECT_EQ(1, canvas.sumTotalDrawCalls());
444 }
445
TEST(CanvasOp,simpleDrawVertices)446 TEST(CanvasOp, simpleDrawVertices) {
447 CanvasOpBuffer buffer;
448 EXPECT_EQ(buffer.size(), 0);
449
450 SkPoint pts[3] = {{64, 32}, {0, 224}, {128, 224}};
451 SkColor colors[3] = {SK_ColorRED, SK_ColorBLUE, SK_ColorGREEN};
452 sk_sp<SkVertices> vertices = SkVertices::MakeCopy(SkVertices::kTriangles_VertexMode, 3, pts,
453 nullptr, colors);
454 buffer.push<Op::DrawVertices> ({
455 .vertices = vertices,
456 .mode = SkBlendMode::kSrcOver,
457 .paint = SkPaint{}
458 });
459
460 CallCountingCanvas canvas;
461 EXPECT_EQ(0, canvas.sumTotalDrawCalls());
462 rasterizeCanvasBuffer(buffer, &canvas);
463 EXPECT_EQ(1, canvas.drawVerticesCount);
464 EXPECT_EQ(1, canvas.sumTotalDrawCalls());
465 }
466
TEST(CanvasOp,simpleDrawImage)467 TEST(CanvasOp, simpleDrawImage) {
468 CanvasOpBuffer buffer;
469 EXPECT_EQ(buffer.size(), 0);
470
471 SkImageInfo info =SkImageInfo::Make(5, 1,
472 kGray_8_SkColorType, kOpaque_SkAlphaType);
473 sk_sp<Bitmap> bitmap = Bitmap::allocateHeapBitmap(info);
474 buffer.push<Op::DrawImage> ({
475 bitmap,
476 7,
477 19,
478 SkFilterMode::kNearest,
479 SkPaint{}
480 }
481 );
482
483 CallCountingCanvas canvas;
484 EXPECT_EQ(0, canvas.sumTotalDrawCalls());
485 rasterizeCanvasBuffer(buffer, &canvas);
486 EXPECT_EQ(1, canvas.drawImageCount);
487 EXPECT_EQ(1, canvas.sumTotalDrawCalls());
488 }
489
TEST(CanvasOp,simpleDrawImageRect)490 TEST(CanvasOp, simpleDrawImageRect) {
491 CanvasOpBuffer buffer;
492 EXPECT_EQ(buffer.size(), 0);
493
494 SkImageInfo info = SkImageInfo::Make(5, 1,
495 kGray_8_SkColorType, kOpaque_SkAlphaType);
496
497 sk_sp<Bitmap> bitmap = Bitmap::allocateHeapBitmap(info);
498 buffer.push<Op::DrawImageRect> ({
499 bitmap, SkRect::MakeWH(100, 100),
500 SkRect::MakeLTRB(120, 110, 220, 210),
501 SkFilterMode::kNearest, SkPaint{}
502 }
503 );
504
505 CallCountingCanvas canvas;
506 EXPECT_EQ(0, canvas.sumTotalDrawCalls());
507 rasterizeCanvasBuffer(buffer, &canvas);
508 EXPECT_EQ(1, canvas.drawImageRectCount);
509 EXPECT_EQ(1, canvas.sumTotalDrawCalls());
510 }
511
TEST(CanvasOp,simpleDrawImageLattice)512 TEST(CanvasOp, simpleDrawImageLattice) {
513 CanvasOpBuffer buffer;
514 EXPECT_EQ(buffer.size(), 0);
515
516 SkBitmap skBitmap;
517 skBitmap.allocPixels(SkImageInfo::MakeN32Premul(60, 60));
518
519 const int xDivs[] = { 20, 50 };
520 const int yDivs[] = { 10, 40 };
521 SkCanvas::Lattice::RectType fillTypes[3][3];
522 memset(fillTypes, 0, sizeof(fillTypes));
523 fillTypes[1][1] = SkCanvas::Lattice::kTransparent;
524 SkColor colors[9];
525 SkCanvas::Lattice lattice = { xDivs, yDivs, fillTypes[0], 2,
526 2, nullptr, colors };
527 sk_sp<Bitmap> bitmap = Bitmap::allocateHeapBitmap(&skBitmap);
528 buffer.push<Op::DrawImageLattice>(
529 {
530 bitmap,
531 SkRect::MakeWH(5, 1),
532 lattice,
533 SkFilterMode::kNearest,
534 SkPaint{}
535 }
536 );
537
538 CallCountingCanvas canvas;
539 EXPECT_EQ(0, canvas.sumTotalDrawCalls());
540 rasterizeCanvasBuffer(buffer, &canvas);
541 EXPECT_EQ(1, canvas.drawImageLatticeCount);
542 EXPECT_EQ(1, canvas.sumTotalDrawCalls());
543 }
544
TEST(CanvasOp,simpleDrawPicture)545 TEST(CanvasOp, simpleDrawPicture) {
546 CanvasOpBuffer buffer;
547 EXPECT_EQ(buffer.size(), 0);
548
549 SkPictureRecorder recorder;
550 SkCanvas* pictureCanvas = recorder.beginRecording({64, 64, 192, 192});
551 SkPaint paint;
552 pictureCanvas->drawRect(SkRect::MakeWH(200, 200), paint);
553 paint.setColor(SK_ColorWHITE);
554 pictureCanvas->drawRect(SkRect::MakeLTRB(20, 20, 180, 180), paint);
555 sk_sp<SkPicture> picture = recorder.finishRecordingAsPicture();
556 buffer.push<Op::DrawPicture> ({
557 .picture = picture
558 });
559
560 CallCountingCanvas canvas;
561 EXPECT_EQ(0, canvas.sumTotalDrawCalls());
562 rasterizeCanvasBuffer(buffer, &canvas);
563 // Note because we are explicitly issuing 2 drawRect calls
564 // in the picture recorder above, when it is played back into
565 // CallCountingCanvas we will see 2 calls to drawRect instead of 1
566 // call to drawPicture.
567 // This is because SkiaCanvas::drawPicture uses picture.playback(canvas)
568 // instead of canvas->drawPicture.
569 EXPECT_EQ(2, canvas.drawRectCount);
570 EXPECT_EQ(2, canvas.sumTotalDrawCalls());
571 }
572
TEST(CanvasOp,simpleDrawRipple)573 TEST(CanvasOp, simpleDrawRipple) {
574 CanvasOpBuffer buffer;
575 EXPECT_EQ(buffer.size(), 0);
576
577 const char* sksl =
578 "half4 main(float2 coord) {"
579 " return half4(1.);"
580 "}";
581 auto [effect, error] = SkRuntimeEffect::MakeForShader(SkString(sksl));
582 auto params = RippleDrawableParams{
583 .x = sp<CanvasPropertyPrimitive>(new CanvasPropertyPrimitive(100)),
584 .y = sp<CanvasPropertyPrimitive>(new CanvasPropertyPrimitive(200)),
585 .radius = sp<CanvasPropertyPrimitive>(new CanvasPropertyPrimitive(50)),
586 .progress = sp<CanvasPropertyPrimitive>(new CanvasPropertyPrimitive(0.5)),
587 .turbulencePhase = sp<CanvasPropertyPrimitive>(new CanvasPropertyPrimitive(1)),
588 .color = 0xff00ff,
589 .paint = sp<CanvasPropertyPaint>(new CanvasPropertyPaint(SkPaint{})),
590 .effectBuilder = SkRuntimeShaderBuilder(effect)};
591 buffer.push<Op::DrawRippleDrawable>({.params = params});
592
593 CallCountingCanvas canvas;
594 EXPECT_EQ(0, canvas.sumTotalDrawCalls());
595 rasterizeCanvasBuffer(buffer, &canvas);
596 EXPECT_EQ(1, canvas.drawOvalCount);
597 EXPECT_EQ(1, canvas.sumTotalDrawCalls());
598 }
599
TEST(CanvasOp,immediateRendering)600 TEST(CanvasOp, immediateRendering) {
601 auto canvas = std::make_shared<CallCountingCanvas>();
602
603 EXPECT_EQ(0, canvas->sumTotalDrawCalls());
604 ImmediateModeRasterizer rasterizer{canvas};
605 auto op = CanvasOp<Op::DrawRect> {
606 .paint = SkPaint{},
607 .rect = SkRect::MakeEmpty()
608 };
609 EXPECT_TRUE(CanvasOpTraits::can_draw<decltype(op)>);
610 rasterizer.draw(op);
611 EXPECT_EQ(1, canvas->drawRectCount);
612 EXPECT_EQ(1, canvas->sumTotalDrawCalls());
613 }
614
TEST(CanvasOp,frontendSaveCount)615 TEST(CanvasOp, frontendSaveCount) {
616 SkNoDrawCanvas skiaCanvas(100, 100);
617 CanvasFrontend<CanvasOpCountingReceiver> opCanvas(100, 100);
618 const auto& receiver = opCanvas.receiver();
619
620 EXPECT_EQ(1, skiaCanvas.getSaveCount());
621 EXPECT_EQ(1, opCanvas.saveCount());
622
623 skiaCanvas.save();
624 opCanvas.save(SaveFlags::MatrixClip);
625 EXPECT_EQ(2, skiaCanvas.getSaveCount());
626 EXPECT_EQ(2, opCanvas.saveCount());
627
628 skiaCanvas.restore();
629 opCanvas.restore();
630 EXPECT_EQ(1, skiaCanvas.getSaveCount());
631 EXPECT_EQ(1, opCanvas.saveCount());
632
633 skiaCanvas.restore();
634 opCanvas.restore();
635 EXPECT_EQ(1, skiaCanvas.getSaveCount());
636 EXPECT_EQ(1, opCanvas.saveCount());
637
638 EXPECT_EQ(1, receiver[Op::Save]);
639 EXPECT_EQ(1, receiver[Op::Restore]);
640 }
641