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