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