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