Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
display_list_unittests.cc
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <memory>
6#include <string>
7#include <unordered_set>
8#include <utility>
9#include <vector>
10
11#include "flutter/display_list/display_list.h"
12#include "flutter/display_list/dl_blend_mode.h"
13#include "flutter/display_list/dl_builder.h"
14#include "flutter/display_list/dl_paint.h"
15#include "flutter/display_list/geometry/dl_rtree.h"
16#include "flutter/display_list/skia/dl_sk_dispatcher.h"
17#include "flutter/display_list/testing/dl_test_snippets.h"
18#include "flutter/display_list/utils/dl_receiver_utils.h"
19#include "flutter/fml/logging.h"
20#include "flutter/fml/math.h"
21#include "flutter/testing/assertions_skia.h"
22#include "flutter/testing/display_list_testing.h"
23#include "flutter/testing/testing.h"
24
30
31namespace flutter {
32
34 return builder.asReceiver();
35}
36
38 return builder.CurrentAttributes();
39}
40
41namespace testing {
42
43static std::vector<testing::DisplayListInvocationGroup> allGroups =
45
48
49template <typename BaseT>
50class DisplayListTestBase : public BaseT {
51 public:
53
57
59 DisplayListBuilder builder;
60 invocation.Invoke(ToReceiver(builder));
61 return builder.Build();
62 }
63
64 static sk_sp<DisplayList> Build(size_t g_index, size_t v_index) {
65 DisplayListBuilder builder;
66 DlOpReceiver& receiver =
68 uint32_t op_count = 0u;
69 size_t byte_count = 0u;
70 uint32_t depth = 0u;
71 uint32_t render_op_depth_cost = 1u;
72 for (size_t i = 0; i < allGroups.size(); i++) {
74 size_t j = (i == g_index ? v_index : 0);
75 if (j >= group.variants.size()) {
76 continue;
77 }
78 DisplayListInvocation& invocation = group.variants[j];
79 op_count += invocation.op_count();
80 byte_count += invocation.raw_byte_count();
81 depth += invocation.depth_accumulated(render_op_depth_cost);
82 invocation.Invoke(receiver);
83 render_op_depth_cost =
84 invocation.adjust_render_op_depth_cost(render_op_depth_cost);
85 }
86 sk_sp<DisplayList> dl = builder.Build();
87 std::string name;
88 if (g_index >= allGroups.size()) {
89 name = "Default";
90 } else {
91 name = allGroups[g_index].op_name;
92 if (v_index >= allGroups[g_index].variants.size()) {
93 name += " skipped";
94 } else {
95 name += " variant " + std::to_string(v_index + 1);
96 }
97 }
98 EXPECT_EQ(dl->op_count(false), op_count) << name;
99 EXPECT_EQ(dl->bytes(false), byte_count + sizeof(DisplayList)) << name;
100 EXPECT_EQ(dl->total_depth(), depth) << name;
101 return dl;
102 }
103
104 static void check_defaults(
105 DisplayListBuilder& builder,
106 const SkRect& cull_rect = DisplayListBuilder::kMaxCullRect) {
107 DlPaint builder_paint = DisplayListBuilderTestingAttributes(builder);
108 DlPaint defaults;
109
110 EXPECT_EQ(builder_paint.isAntiAlias(), defaults.isAntiAlias());
111 EXPECT_EQ(builder_paint.isInvertColors(), defaults.isInvertColors());
112 EXPECT_EQ(builder_paint.getColor(), defaults.getColor());
113 EXPECT_EQ(builder_paint.getBlendMode(), defaults.getBlendMode());
114 EXPECT_EQ(builder_paint.getDrawStyle(), defaults.getDrawStyle());
115 EXPECT_EQ(builder_paint.getStrokeWidth(), defaults.getStrokeWidth());
116 EXPECT_EQ(builder_paint.getStrokeMiter(), defaults.getStrokeMiter());
117 EXPECT_EQ(builder_paint.getStrokeCap(), defaults.getStrokeCap());
118 EXPECT_EQ(builder_paint.getStrokeJoin(), defaults.getStrokeJoin());
119 EXPECT_EQ(builder_paint.getColorSource(), defaults.getColorSource());
120 EXPECT_EQ(builder_paint.getColorFilter(), defaults.getColorFilter());
121 EXPECT_EQ(builder_paint.getImageFilter(), defaults.getImageFilter());
122 EXPECT_EQ(builder_paint.getMaskFilter(), defaults.getMaskFilter());
123 EXPECT_EQ(builder_paint.getPathEffect(), defaults.getPathEffect());
124 EXPECT_EQ(builder_paint, defaults);
125 EXPECT_TRUE(builder_paint.isDefault());
126
127 EXPECT_EQ(builder.GetTransform(), SkMatrix());
128 EXPECT_EQ(builder.GetTransformFullPerspective(), SkM44());
129
130 EXPECT_EQ(builder.GetLocalClipBounds(), cull_rect);
131 EXPECT_EQ(builder.GetDestinationClipBounds(), cull_rect);
132
133 EXPECT_EQ(builder.GetSaveCount(), 1);
134 }
135
136 typedef const std::function<void(DlCanvas&)> DlSetup;
137 typedef const std::function<void(DlCanvas&, DlPaint&, SkRect& rect)>
139
141 DlRenderer& renderer,
143 SkRect render_rect,
144 SkRect expected_bounds,
145 const std::string& desc) {
146 DisplayListBuilder builder;
147 setup(builder);
148 renderer(builder, paint, render_rect);
149 auto dl = builder.Build();
150 EXPECT_EQ(dl->op_count(), 1u) << desc;
151 EXPECT_EQ(dl->bounds(), expected_bounds) << desc;
152 }
153
154 static void check_inverted_bounds(DlRenderer& renderer,
155 const std::string& desc) {
156 SkRect rect = SkRect::MakeLTRB(0.0f, 0.0f, 10.0f, 10.0f);
157 SkRect invertedLR = SkRect::MakeLTRB(rect.fRight, rect.fTop, //
158 rect.fLeft, rect.fBottom);
159 SkRect invertedTB = SkRect::MakeLTRB(rect.fLeft, rect.fBottom, //
160 rect.fRight, rect.fTop);
161 SkRect invertedLTRB = SkRect::MakeLTRB(rect.fRight, rect.fBottom, //
162 rect.fLeft, rect.fTop);
163 auto empty_setup = [](DlCanvas&) {};
164
165 ASSERT_TRUE(rect.fLeft < rect.fRight);
166 ASSERT_TRUE(rect.fTop < rect.fBottom);
167 ASSERT_FALSE(rect.isEmpty());
168 ASSERT_TRUE(invertedLR.fLeft > invertedLR.fRight);
169 ASSERT_TRUE(invertedLR.isEmpty());
170 ASSERT_TRUE(invertedTB.fTop > invertedTB.fBottom);
171 ASSERT_TRUE(invertedTB.isEmpty());
172 ASSERT_TRUE(invertedLTRB.fLeft > invertedLTRB.fRight);
173 ASSERT_TRUE(invertedLTRB.fTop > invertedLTRB.fBottom);
174 ASSERT_TRUE(invertedLTRB.isEmpty());
175
176 DlPaint ref_paint = DlPaint();
177 SkRect ref_bounds = rect;
178 verify_inverted_bounds(empty_setup, renderer, ref_paint, invertedLR,
179 ref_bounds, desc + " LR swapped");
180 verify_inverted_bounds(empty_setup, renderer, ref_paint, invertedTB,
181 ref_bounds, desc + " TB swapped");
182 verify_inverted_bounds(empty_setup, renderer, ref_paint, invertedLTRB,
183 ref_bounds, desc + " LR&TB swapped");
184
185 // Round joins are used because miter joins greatly pad the bounds,
186 // but only on paths. So we use round joins for consistency there.
187 // We aren't fully testing all stroke-related bounds computations here,
188 // those are more fully tested in the render tests. We are simply
189 // checking that they are applied to the ordered bounds.
190 DlPaint stroke_paint = DlPaint() //
193 .setStrokeWidth(2.0f);
194 SkRect stroke_bounds = rect.makeOutset(1.0f, 1.0f);
195 verify_inverted_bounds(empty_setup, renderer, stroke_paint, invertedLR,
196 stroke_bounds, desc + " LR swapped, sw 2");
197 verify_inverted_bounds(empty_setup, renderer, stroke_paint, invertedTB,
198 stroke_bounds, desc + " TB swapped, sw 2");
199 verify_inverted_bounds(empty_setup, renderer, stroke_paint, invertedLTRB,
200 stroke_bounds, desc + " LR&TB swapped, sw 2");
201
202 DlBlurMaskFilter mask_filter(DlBlurStyle::kNormal, 2.0f);
203 DlPaint maskblur_paint = DlPaint() //
204 .setMaskFilter(&mask_filter);
205 SkRect maskblur_bounds = rect.makeOutset(6.0f, 6.0f);
206 verify_inverted_bounds(empty_setup, renderer, maskblur_paint, invertedLR,
207 maskblur_bounds, desc + " LR swapped, mask 2");
208 verify_inverted_bounds(empty_setup, renderer, maskblur_paint, invertedTB,
209 maskblur_bounds, desc + " TB swapped, mask 2");
210 verify_inverted_bounds(empty_setup, renderer, maskblur_paint, invertedLTRB,
211 maskblur_bounds, desc + " LR&TB swapped, mask 2");
212
213 DlErodeImageFilter erode_filter(2.0f, 2.0f);
214 DlPaint erode_paint = DlPaint() //
215 .setImageFilter(&erode_filter);
216 SkRect erode_bounds = rect.makeInset(2.0f, 2.0f);
217 verify_inverted_bounds(empty_setup, renderer, erode_paint, invertedLR,
218 erode_bounds, desc + " LR swapped, erode 2");
219 verify_inverted_bounds(empty_setup, renderer, erode_paint, invertedTB,
220 erode_bounds, desc + " TB swapped, erode 2");
221 verify_inverted_bounds(empty_setup, renderer, erode_paint, invertedLTRB,
222 erode_bounds, desc + " LR&TB swapped, erode 2");
223 }
224
225 private:
227};
229
231 DisplayListBuilder builder;
232 check_defaults(builder);
233}
234
236 DisplayListBuilder builder;
237 auto dl = builder.Build();
238 EXPECT_EQ(dl->op_count(), 0u);
239 EXPECT_EQ(dl->bytes(), sizeof(DisplayList));
240 EXPECT_EQ(dl->total_depth(), 0u);
241}
242
243TEST_F(DisplayListTest, EmptyRebuild) {
244 DisplayListBuilder builder;
245 auto dl1 = builder.Build();
246 auto dl2 = builder.Build();
247 auto dl3 = builder.Build();
248 ASSERT_TRUE(dl1->Equals(dl2));
249 ASSERT_TRUE(dl2->Equals(dl3));
250}
251
252TEST_F(DisplayListTest, BuilderCanBeReused) {
254 builder.DrawRect(kTestBounds, DlPaint());
255 auto dl = builder.Build();
256 builder.DrawRect(kTestBounds, DlPaint());
257 auto dl2 = builder.Build();
258 ASSERT_TRUE(dl->Equals(dl2));
259}
260
261TEST_F(DisplayListTest, SaveRestoreRestoresTransform) {
262 SkRect cull_rect = SkRect::MakeLTRB(-10.0f, -10.0f, 500.0f, 500.0f);
263 DisplayListBuilder builder(cull_rect);
264
265 builder.Save();
266 builder.Translate(10.0f, 10.0f);
267 builder.Restore();
268 check_defaults(builder, cull_rect);
269
270 builder.Save();
271 builder.Scale(10.0f, 10.0f);
272 builder.Restore();
273 check_defaults(builder, cull_rect);
274
275 builder.Save();
276 builder.Skew(0.1f, 0.1f);
277 builder.Restore();
278 check_defaults(builder, cull_rect);
279
280 builder.Save();
281 builder.Rotate(45.0f);
282 builder.Restore();
283 check_defaults(builder, cull_rect);
284
285 builder.Save();
286 builder.Transform(SkMatrix::Scale(10.0f, 10.0f));
287 builder.Restore();
288 check_defaults(builder, cull_rect);
289
290 builder.Save();
291 builder.Transform2DAffine(1.0f, 0.0f, 12.0f, //
292 0.0f, 1.0f, 35.0f);
293 builder.Restore();
294 check_defaults(builder, cull_rect);
295
296 builder.Save();
297 builder.Transform(SkM44(SkMatrix::Scale(10.0f, 10.0f)));
298 builder.Restore();
299 check_defaults(builder, cull_rect);
300
301 builder.Save();
302 builder.TransformFullPerspective(1.0f, 0.0f, 0.0f, 12.0f, //
303 0.0f, 1.0f, 0.0f, 35.0f, //
304 0.0f, 0.0f, 1.0f, 5.0f, //
305 0.0f, 0.0f, 0.0f, 1.0f);
306 builder.Restore();
307 check_defaults(builder, cull_rect);
308}
309
310TEST_F(DisplayListTest, BuildRestoresTransform) {
311 SkRect cull_rect = SkRect::MakeLTRB(-10.0f, -10.0f, 500.0f, 500.0f);
312 DisplayListBuilder builder(cull_rect);
313
314 builder.Translate(10.0f, 10.0f);
315 builder.Build();
316 check_defaults(builder, cull_rect);
317
318 builder.Scale(10.0f, 10.0f);
319 builder.Build();
320 check_defaults(builder, cull_rect);
321
322 builder.Skew(0.1f, 0.1f);
323 builder.Build();
324 check_defaults(builder, cull_rect);
325
326 builder.Rotate(45.0f);
327 builder.Build();
328 check_defaults(builder, cull_rect);
329
330 builder.Transform(SkMatrix::Scale(10.0f, 10.0f));
331 builder.Build();
332 check_defaults(builder, cull_rect);
333
334 builder.Transform2DAffine(1.0f, 0.0f, 12.0f, //
335 0.0f, 1.0f, 35.0f);
336 builder.Build();
337 check_defaults(builder, cull_rect);
338
339 builder.Transform(SkM44(SkMatrix::Scale(10.0f, 10.0f)));
340 builder.Build();
341 check_defaults(builder, cull_rect);
342
343 builder.TransformFullPerspective(1.0f, 0.0f, 0.0f, 12.0f, //
344 0.0f, 1.0f, 0.0f, 35.0f, //
345 0.0f, 0.0f, 1.0f, 5.0f, //
346 0.0f, 0.0f, 0.0f, 1.0f);
347 builder.Build();
348 check_defaults(builder, cull_rect);
349}
350
351TEST_F(DisplayListTest, SaveRestoreRestoresClip) {
352 SkRect cull_rect = SkRect::MakeLTRB(-10.0f, -10.0f, 500.0f, 500.0f);
353 DisplayListBuilder builder(cull_rect);
354
355 builder.Save();
356 builder.ClipRect({0.0f, 0.0f, 10.0f, 10.0f});
357 builder.Restore();
358 check_defaults(builder, cull_rect);
359
360 builder.Save();
361 builder.ClipRRect(SkRRect::MakeRectXY({0.0f, 0.0f, 5.0f, 5.0f}, 2.0f, 2.0f));
362 builder.Restore();
363 check_defaults(builder, cull_rect);
364
365 builder.Save();
366 builder.ClipPath(SkPath().addOval({0.0f, 0.0f, 10.0f, 10.0f}));
367 builder.Restore();
368 check_defaults(builder, cull_rect);
369}
370
371TEST_F(DisplayListTest, BuildRestoresClip) {
372 SkRect cull_rect = SkRect::MakeLTRB(-10.0f, -10.0f, 500.0f, 500.0f);
373 DisplayListBuilder builder(cull_rect);
374
375 builder.ClipRect({0.0f, 0.0f, 10.0f, 10.0f});
376 builder.Build();
377 check_defaults(builder, cull_rect);
378
379 builder.ClipRRect(SkRRect::MakeRectXY({0.0f, 0.0f, 5.0f, 5.0f}, 2.0f, 2.0f));
380 builder.Build();
381 check_defaults(builder, cull_rect);
382
383 builder.ClipPath(SkPath().addOval({0.0f, 0.0f, 10.0f, 10.0f}));
384 builder.Build();
385 check_defaults(builder, cull_rect);
386}
387
388TEST_F(DisplayListTest, BuildRestoresAttributes) {
389 SkRect cull_rect = SkRect::MakeLTRB(-10.0f, -10.0f, 500.0f, 500.0f);
390 DisplayListBuilder builder(cull_rect);
391 DlOpReceiver& receiver = ToReceiver(builder);
392
393 receiver.setAntiAlias(true);
394 builder.Build();
395 check_defaults(builder, cull_rect);
396
397 receiver.setInvertColors(true);
398 builder.Build();
399 check_defaults(builder, cull_rect);
400
401 receiver.setColor(DlColor::kRed());
402 builder.Build();
403 check_defaults(builder, cull_rect);
404
406 builder.Build();
407 check_defaults(builder, cull_rect);
408
410 builder.Build();
411 check_defaults(builder, cull_rect);
412
413 receiver.setStrokeWidth(300.0f);
414 builder.Build();
415 check_defaults(builder, cull_rect);
416
417 receiver.setStrokeMiter(300.0f);
418 builder.Build();
419 check_defaults(builder, cull_rect);
420
422 builder.Build();
423 check_defaults(builder, cull_rect);
424
426 builder.Build();
427 check_defaults(builder, cull_rect);
428
429 receiver.setColorSource(&kTestSource1);
430 builder.Build();
431 check_defaults(builder, cull_rect);
432
434 builder.Build();
435 check_defaults(builder, cull_rect);
436
438 builder.Build();
439 check_defaults(builder, cull_rect);
440
442 builder.Build();
443 check_defaults(builder, cull_rect);
444
445 receiver.setPathEffect(kTestPathEffect1.get());
446 builder.Build();
447 check_defaults(builder, cull_rect);
448}
449
450TEST_F(DisplayListTest, BuilderBoundsTransformComparedToSkia) {
451 const SkRect frame_rect = SkRect::MakeLTRB(10, 10, 100, 100);
452 DisplayListBuilder builder(frame_rect);
453 SkPictureRecorder recorder;
454 SkCanvas* canvas = recorder.beginRecording(frame_rect);
455 ASSERT_EQ(builder.GetDestinationClipBounds(),
457 ASSERT_EQ(builder.GetLocalClipBounds().makeOutset(1, 1),
458 canvas->getLocalClipBounds());
459 ASSERT_EQ(builder.GetTransform(), canvas->getTotalMatrix());
460}
461
462TEST_F(DisplayListTest, BuilderInitialClipBounds) {
463 SkRect cull_rect = SkRect::MakeWH(100, 100);
464 SkRect clip_bounds = SkRect::MakeWH(100, 100);
465 DisplayListBuilder builder(cull_rect);
466 ASSERT_EQ(builder.GetDestinationClipBounds(), clip_bounds);
467}
468
469TEST_F(DisplayListTest, BuilderInitialClipBoundsNaN) {
471 SkRect clip_bounds = SkRect::MakeEmpty();
472 DisplayListBuilder builder(cull_rect);
473 ASSERT_EQ(builder.GetDestinationClipBounds(), clip_bounds);
474}
475
476TEST_F(DisplayListTest, BuilderClipBoundsAfterClipRect) {
477 SkRect cull_rect = SkRect::MakeWH(100, 100);
478 SkRect clip_rect = SkRect::MakeLTRB(10, 10, 20, 20);
479 SkRect clip_bounds = SkRect::MakeLTRB(10, 10, 20, 20);
480 DisplayListBuilder builder(cull_rect);
481 builder.ClipRect(clip_rect, ClipOp::kIntersect, false);
482 ASSERT_EQ(builder.GetDestinationClipBounds(), clip_bounds);
483}
484
485TEST_F(DisplayListTest, BuilderClipBoundsAfterClipRRect) {
486 SkRect cull_rect = SkRect::MakeWH(100, 100);
487 SkRect clip_rect = SkRect::MakeLTRB(10, 10, 20, 20);
488 SkRRect clip_rrect = SkRRect::MakeRectXY(clip_rect, 2, 2);
489 SkRect clip_bounds = SkRect::MakeLTRB(10, 10, 20, 20);
490 DisplayListBuilder builder(cull_rect);
491 builder.ClipRRect(clip_rrect, ClipOp::kIntersect, false);
492 ASSERT_EQ(builder.GetDestinationClipBounds(), clip_bounds);
493}
494
495TEST_F(DisplayListTest, BuilderClipBoundsAfterClipPath) {
496 SkRect cull_rect = SkRect::MakeWH(100, 100);
497 SkPath clip_path = SkPath().addRect(10, 10, 15, 15).addRect(15, 15, 20, 20);
498 SkRect clip_bounds = SkRect::MakeLTRB(10, 10, 20, 20);
499 DisplayListBuilder builder(cull_rect);
500 builder.ClipPath(clip_path, ClipOp::kIntersect, false);
501 ASSERT_EQ(builder.GetDestinationClipBounds(), clip_bounds);
502}
503
504TEST_F(DisplayListTest, BuilderInitialClipBoundsNonZero) {
505 SkRect cull_rect = SkRect::MakeLTRB(10, 10, 100, 100);
506 SkRect clip_bounds = SkRect::MakeLTRB(10, 10, 100, 100);
507 DisplayListBuilder builder(cull_rect);
508 ASSERT_EQ(builder.GetDestinationClipBounds(), clip_bounds);
509}
510
511TEST_F(DisplayListTest, UnclippedSaveLayerContentAccountsForFilter) {
512 SkRect cull_rect = SkRect::MakeLTRB(0.0f, 0.0f, 300.0f, 300.0f);
513 SkRect clip_rect = SkRect::MakeLTRB(100.0f, 100.0f, 200.0f, 200.0f);
514 SkRect draw_rect = SkRect::MakeLTRB(50.0f, 140.0f, 101.0f, 160.0f);
515 auto filter = DlBlurImageFilter::Make(10.0f, 10.0f, DlTileMode::kDecal);
516 DlPaint layer_paint = DlPaint().setImageFilter(filter);
517
518 ASSERT_TRUE(clip_rect.intersects(draw_rect));
519 ASSERT_TRUE(cull_rect.contains(clip_rect));
520 ASSERT_TRUE(cull_rect.contains(draw_rect));
521
522 DisplayListBuilder builder;
523 builder.Save();
524 {
525 builder.ClipRect(clip_rect, ClipOp::kIntersect, false);
526 builder.SaveLayer(&cull_rect, &layer_paint);
527 { //
528 builder.DrawRect(draw_rect, DlPaint());
529 }
530 builder.Restore();
531 }
532 builder.Restore();
533 auto display_list = builder.Build();
534
535 ASSERT_EQ(display_list->op_count(), 6u);
536 EXPECT_EQ(display_list->total_depth(), 2u);
537
538 SkRect result_rect = draw_rect.makeOutset(30.0f, 30.0f);
539 ASSERT_TRUE(result_rect.intersect(clip_rect));
540 ASSERT_EQ(result_rect, SkRect::MakeLTRB(100.0f, 110.0f, 131.0f, 190.0f));
541 ASSERT_EQ(display_list->bounds(), result_rect);
542}
543
544TEST_F(DisplayListTest, ClippedSaveLayerContentAccountsForFilter) {
545 SkRect cull_rect = SkRect::MakeLTRB(0.0f, 0.0f, 300.0f, 300.0f);
546 SkRect clip_rect = SkRect::MakeLTRB(100.0f, 100.0f, 200.0f, 200.0f);
547 SkRect draw_rect = SkRect::MakeLTRB(50.0f, 140.0f, 99.0f, 160.0f);
548 auto filter = DlBlurImageFilter::Make(10.0f, 10.0f, DlTileMode::kDecal);
549 DlPaint layer_paint = DlPaint().setImageFilter(filter);
550
551 ASSERT_FALSE(clip_rect.intersects(draw_rect));
552 ASSERT_TRUE(cull_rect.contains(clip_rect));
553 ASSERT_TRUE(cull_rect.contains(draw_rect));
554
555 DisplayListBuilder builder;
556 builder.Save();
557 {
558 builder.ClipRect(clip_rect, ClipOp::kIntersect, false);
559 builder.SaveLayer(&cull_rect, &layer_paint);
560 { //
561 builder.DrawRect(draw_rect, DlPaint());
562 }
563 builder.Restore();
564 }
565 builder.Restore();
566 auto display_list = builder.Build();
567
568 ASSERT_EQ(display_list->op_count(), 6u);
569 EXPECT_EQ(display_list->total_depth(), 2u);
570
571 SkRect result_rect = draw_rect.makeOutset(30.0f, 30.0f);
572 ASSERT_TRUE(result_rect.intersect(clip_rect));
573 ASSERT_EQ(result_rect, SkRect::MakeLTRB(100.0f, 110.0f, 129.0f, 190.0f));
574 ASSERT_EQ(display_list->bounds(), result_rect);
575}
576
577TEST_F(DisplayListTest, SingleOpSizes) {
578 for (auto& group : allGroups) {
579 for (size_t i = 0; i < group.variants.size(); i++) {
580 auto& invocation = group.variants[i];
581 sk_sp<DisplayList> dl = Build(invocation);
582 auto desc = group.op_name + "(variant " + std::to_string(i + 1) + ")";
583 ASSERT_EQ(dl->op_count(false), invocation.op_count()) << desc;
584 ASSERT_EQ(dl->bytes(false), invocation.byte_count()) << desc;
585 EXPECT_EQ(dl->total_depth(), invocation.depth_accumulated()) << desc;
586 }
587 }
588}
589
590TEST_F(DisplayListTest, SingleOpDisplayListsNotEqualEmpty) {
592 for (auto& group : allGroups) {
593 for (size_t i = 0; i < group.variants.size(); i++) {
594 sk_sp<DisplayList> dl = Build(group.variants[i]);
595 auto desc =
596 group.op_name + "(variant " + std::to_string(i + 1) + " != empty)";
597 if (group.variants[i].is_empty()) {
598 ASSERT_TRUE(DisplayListsEQ_Verbose(dl, empty));
599 ASSERT_TRUE(empty->Equals(*dl)) << desc;
600 } else {
601 ASSERT_TRUE(DisplayListsNE_Verbose(dl, empty));
602 ASSERT_FALSE(empty->Equals(*dl)) << desc;
603 }
604 }
605 }
606}
607
608TEST_F(DisplayListTest, SingleOpDisplayListsRecapturedAreEqual) {
609 for (auto& group : allGroups) {
610 for (size_t i = 0; i < group.variants.size(); i++) {
611 sk_sp<DisplayList> dl = Build(group.variants[i]);
612 // Verify recapturing the replay of the display list is Equals()
613 // when dispatching directly from the DL to another builder
614 DisplayListBuilder copy_builder;
615 DlOpReceiver& r = ToReceiver(copy_builder);
616 dl->Dispatch(r);
617 sk_sp<DisplayList> copy = copy_builder.Build();
618 auto desc =
619 group.op_name + "(variant " + std::to_string(i + 1) + " == copy)";
620 ASSERT_EQ(copy->op_count(false), dl->op_count(false)) << desc;
621 ASSERT_EQ(copy->bytes(false), dl->bytes(false)) << desc;
622 ASSERT_EQ(copy->op_count(true), dl->op_count(true)) << desc;
623 ASSERT_EQ(copy->bytes(true), dl->bytes(true)) << desc;
624 EXPECT_EQ(copy->total_depth(), dl->total_depth()) << desc;
625 ASSERT_EQ(copy->bounds(), dl->bounds()) << desc;
626 ASSERT_TRUE(copy->Equals(*dl)) << desc;
627 ASSERT_TRUE(dl->Equals(*copy)) << desc;
628 }
629 }
630}
631
632TEST_F(DisplayListTest, SingleOpDisplayListsCompareToEachOther) {
633 for (auto& group : allGroups) {
634 std::vector<sk_sp<DisplayList>> lists_a;
635 std::vector<sk_sp<DisplayList>> lists_b;
636 for (size_t i = 0; i < group.variants.size(); i++) {
637 lists_a.push_back(Build(group.variants[i]));
638 lists_b.push_back(Build(group.variants[i]));
639 }
640
641 for (size_t i = 0; i < lists_a.size(); i++) {
642 sk_sp<DisplayList> listA = lists_a[i];
643 for (size_t j = 0; j < lists_b.size(); j++) {
644 sk_sp<DisplayList> listB = lists_b[j];
645 auto desc = group.op_name + "(variant " + std::to_string(i + 1) +
646 " ==? variant " + std::to_string(j + 1) + ")";
647 if (i == j ||
648 (group.variants[i].is_empty() && group.variants[j].is_empty())) {
649 // They are the same variant, or both variants are NOPs
650 ASSERT_EQ(listA->op_count(false), listB->op_count(false)) << desc;
651 ASSERT_EQ(listA->bytes(false), listB->bytes(false)) << desc;
652 ASSERT_EQ(listA->op_count(true), listB->op_count(true)) << desc;
653 ASSERT_EQ(listA->bytes(true), listB->bytes(true)) << desc;
654 EXPECT_EQ(listA->total_depth(), listB->total_depth()) << desc;
655 ASSERT_EQ(listA->bounds(), listB->bounds()) << desc;
656 ASSERT_TRUE(listA->Equals(*listB)) << desc;
657 ASSERT_TRUE(listB->Equals(*listA)) << desc;
658 } else {
659 // No assertion on op/byte counts or bounds
660 // they may or may not be equal between variants
661 ASSERT_FALSE(listA->Equals(*listB)) << desc;
662 ASSERT_FALSE(listB->Equals(*listA)) << desc;
663 }
664 }
665 }
666 }
667}
668
669TEST_F(DisplayListTest, SingleOpDisplayListsAreEqualWithOrWithoutRtree) {
670 for (auto& group : allGroups) {
671 for (size_t i = 0; i < group.variants.size(); i++) {
672 DisplayListBuilder builder1(/*prepare_rtree=*/false);
673 DisplayListBuilder builder2(/*prepare_rtree=*/true);
674 group.variants[i].Invoke(ToReceiver(builder1));
675 group.variants[i].Invoke(ToReceiver(builder2));
676 sk_sp<DisplayList> dl1 = builder1.Build();
677 sk_sp<DisplayList> dl2 = builder2.Build();
678
679 auto desc = group.op_name + "(variant " + std::to_string(i + 1) + " )";
680 ASSERT_EQ(dl1->op_count(false), dl2->op_count(false)) << desc;
681 ASSERT_EQ(dl1->bytes(false), dl2->bytes(false)) << desc;
682 ASSERT_EQ(dl1->op_count(true), dl2->op_count(true)) << desc;
683 ASSERT_EQ(dl1->bytes(true), dl2->bytes(true)) << desc;
684 EXPECT_EQ(dl1->total_depth(), dl2->total_depth()) << desc;
685 ASSERT_EQ(dl1->bounds(), dl2->bounds()) << desc;
686 ASSERT_EQ(dl1->total_depth(), dl2->total_depth()) << desc;
687 ASSERT_TRUE(DisplayListsEQ_Verbose(dl1, dl2)) << desc;
688 ASSERT_TRUE(DisplayListsEQ_Verbose(dl2, dl2)) << desc;
689 ASSERT_EQ(dl1->rtree().get(), nullptr) << desc;
690 ASSERT_NE(dl2->rtree().get(), nullptr) << desc;
691 }
692 }
693}
694
695TEST_F(DisplayListTest, FullRotationsAreNop) {
696 DisplayListBuilder builder;
697 DlOpReceiver& receiver = ToReceiver(builder);
698 receiver.rotate(0);
699 receiver.rotate(360);
700 receiver.rotate(720);
701 receiver.rotate(1080);
702 receiver.rotate(1440);
703 sk_sp<DisplayList> dl = builder.Build();
704 ASSERT_EQ(dl->bytes(false), sizeof(DisplayList));
705 ASSERT_EQ(dl->bytes(true), sizeof(DisplayList));
706 ASSERT_EQ(dl->op_count(false), 0u);
707 ASSERT_EQ(dl->op_count(true), 0u);
708 EXPECT_EQ(dl->total_depth(), 0u);
709}
710
711TEST_F(DisplayListTest, AllBlendModeNops) {
712 DisplayListBuilder builder;
713 DlOpReceiver& receiver = ToReceiver(builder);
715 sk_sp<DisplayList> dl = builder.Build();
716 ASSERT_EQ(dl->bytes(false), sizeof(DisplayList));
717 ASSERT_EQ(dl->bytes(true), sizeof(DisplayList));
718 ASSERT_EQ(dl->op_count(false), 0u);
719 ASSERT_EQ(dl->op_count(true), 0u);
720 EXPECT_EQ(dl->total_depth(), 0u);
721}
722
723TEST_F(DisplayListTest, DisplayListsWithVaryingOpComparisons) {
724 sk_sp<DisplayList> default_dl = Build(allGroups.size(), 0);
725 ASSERT_TRUE(default_dl->Equals(*default_dl)) << "Default == itself";
726 for (size_t gi = 0; gi < allGroups.size(); gi++) {
728 sk_sp<DisplayList> missing_dl = Build(gi, group.variants.size());
729 auto desc = "[Group " + group.op_name + " omitted]";
730 ASSERT_TRUE(missing_dl->Equals(*missing_dl)) << desc << " == itself";
731 ASSERT_FALSE(missing_dl->Equals(*default_dl)) << desc << " != Default";
732 ASSERT_FALSE(default_dl->Equals(*missing_dl)) << "Default != " << desc;
733 for (size_t vi = 0; vi < group.variants.size(); vi++) {
734 auto desc = "[Group " + group.op_name + " variant " +
735 std::to_string(vi + 1) + "]";
736 sk_sp<DisplayList> variant_dl = Build(gi, vi);
737 ASSERT_TRUE(variant_dl->Equals(*variant_dl)) << desc << " == itself";
738 if (vi == 0) {
739 ASSERT_TRUE(variant_dl->Equals(*default_dl)) << desc << " == Default";
740 ASSERT_TRUE(default_dl->Equals(*variant_dl)) << "Default == " << desc;
741 } else {
742 ASSERT_FALSE(variant_dl->Equals(*default_dl)) << desc << " != Default";
743 ASSERT_FALSE(default_dl->Equals(*variant_dl)) << "Default != " << desc;
744 }
745 if (group.variants[vi].is_empty()) {
746 ASSERT_TRUE(variant_dl->Equals(*missing_dl)) << desc << " != omitted";
747 ASSERT_TRUE(missing_dl->Equals(*variant_dl)) << "omitted != " << desc;
748 } else {
749 ASSERT_FALSE(variant_dl->Equals(*missing_dl)) << desc << " != omitted";
750 ASSERT_FALSE(missing_dl->Equals(*variant_dl)) << "omitted != " << desc;
751 }
752 }
753 }
754}
755
756TEST_F(DisplayListTest, DisplayListSaveLayerBoundsWithAlphaFilter) {
757 SkRect build_bounds = SkRect::MakeLTRB(-100, -100, 200, 200);
758 SkRect save_bounds = SkRect::MakeWH(100, 100);
759 SkRect rect = SkRect::MakeLTRB(30, 30, 70, 70);
760 // clang-format off
761 const float color_matrix[] = {
762 0, 0, 0, 0, 0,
763 0, 1, 0, 0, 0,
764 0, 0, 1, 0, 0,
765 0, 0, 0, 1, 0,
766 };
767 // clang-format on
768 DlMatrixColorFilter base_color_filter(color_matrix);
769 // clang-format off
770 const float alpha_matrix[] = {
771 0, 0, 0, 0, 0,
772 0, 1, 0, 0, 0,
773 0, 0, 1, 0, 0,
774 0, 0, 0, 0, 1,
775 };
776 // clang-format on
777 DlMatrixColorFilter alpha_color_filter(alpha_matrix);
778 sk_sp<SkColorFilter> sk_alpha_color_filter =
779 SkColorFilters::Matrix(alpha_matrix);
780
781 {
782 // No tricky stuff, just verifying drawing a rect produces rect bounds
783 DisplayListBuilder builder(build_bounds);
784 DlOpReceiver& receiver = ToReceiver(builder);
785 receiver.saveLayer(&save_bounds, SaveLayerOptions::kWithAttributes);
786 receiver.drawRect(rect);
787 receiver.restore();
788 sk_sp<DisplayList> display_list = builder.Build();
789 ASSERT_EQ(display_list->bounds(), rect);
790 }
791
792 {
793 // Now checking that a normal color filter still produces rect bounds
794 DisplayListBuilder builder(build_bounds);
795 DlOpReceiver& receiver = ToReceiver(builder);
796 receiver.setColorFilter(&base_color_filter);
797 receiver.saveLayer(&save_bounds, SaveLayerOptions::kWithAttributes);
798 receiver.setColorFilter(nullptr);
799 receiver.drawRect(rect);
800 receiver.restore();
801 sk_sp<DisplayList> display_list = builder.Build();
802 ASSERT_EQ(display_list->bounds(), rect);
803 }
804
805 {
806 // Now checking how SkPictureRecorder deals with a color filter
807 // that modifies alpha channels (save layer bounds are meaningless
808 // under those circumstances)
809 SkPictureRecorder recorder;
810 SkRTreeFactory rtree_factory;
811 SkCanvas* canvas = recorder.beginRecording(build_bounds, &rtree_factory);
812 SkPaint p1;
813 p1.setColorFilter(sk_alpha_color_filter);
814 canvas->saveLayer(save_bounds, &p1);
815 SkPaint p2;
816 canvas->drawRect(rect, p2);
817 canvas->restore();
818 sk_sp<SkPicture> picture = recorder.finishRecordingAsPicture();
819 ASSERT_EQ(picture->cullRect(), build_bounds);
820 }
821
822 {
823 // Now checking that DisplayList has the same behavior that we
824 // saw in the SkPictureRecorder example above - returning the
825 // cull rect of the DisplayListBuilder when it encounters a
826 // save layer that modifies an unbounded region
827 DisplayListBuilder builder(build_bounds);
828 DlOpReceiver& receiver = ToReceiver(builder);
829 receiver.setColorFilter(&alpha_color_filter);
830 receiver.saveLayer(&save_bounds, SaveLayerOptions::kWithAttributes);
831 receiver.setColorFilter(nullptr);
832 receiver.drawRect(rect);
833 receiver.restore();
834 sk_sp<DisplayList> display_list = builder.Build();
835 ASSERT_EQ(display_list->bounds(), build_bounds);
836 }
837
838 {
839 // Verifying that the save layer bounds are not relevant
840 // to the behavior in the previous example
841 DisplayListBuilder builder(build_bounds);
842 DlOpReceiver& receiver = ToReceiver(builder);
843 receiver.setColorFilter(&alpha_color_filter);
845 receiver.setColorFilter(nullptr);
846 receiver.drawRect(rect);
847 receiver.restore();
848 sk_sp<DisplayList> display_list = builder.Build();
849 ASSERT_EQ(display_list->bounds(), build_bounds);
850 }
851
852 {
853 // Making sure hiding a ColorFilter as an ImageFilter will
854 // generate the same behavior as setting it as a ColorFilter
855 DisplayListBuilder builder(build_bounds);
856 DlOpReceiver& receiver = ToReceiver(builder);
857 DlColorFilterImageFilter color_filter_image_filter(base_color_filter);
858 receiver.setImageFilter(&color_filter_image_filter);
859 receiver.saveLayer(&save_bounds, SaveLayerOptions::kWithAttributes);
860 receiver.setImageFilter(nullptr);
861 receiver.drawRect(rect);
862 receiver.restore();
863 sk_sp<DisplayList> display_list = builder.Build();
864 ASSERT_EQ(display_list->bounds(), rect);
865 }
866
867 {
868 // Making sure hiding a problematic ColorFilter as an ImageFilter
869 // will generate the same behavior as setting it as a ColorFilter
870 DisplayListBuilder builder(build_bounds);
871 DlOpReceiver& receiver = ToReceiver(builder);
872 DlColorFilterImageFilter color_filter_image_filter(alpha_color_filter);
873 receiver.setImageFilter(&color_filter_image_filter);
874 receiver.saveLayer(&save_bounds, SaveLayerOptions::kWithAttributes);
875 receiver.setImageFilter(nullptr);
876 receiver.drawRect(rect);
877 receiver.restore();
878 sk_sp<DisplayList> display_list = builder.Build();
879 ASSERT_EQ(display_list->bounds(), build_bounds);
880 }
881
882 {
883 // Same as above (ImageFilter hiding ColorFilter) with no save bounds
884 DisplayListBuilder builder(build_bounds);
885 DlOpReceiver& receiver = ToReceiver(builder);
886 DlColorFilterImageFilter color_filter_image_filter(alpha_color_filter);
887 receiver.setImageFilter(&color_filter_image_filter);
889 receiver.setImageFilter(nullptr);
890 receiver.drawRect(rect);
891 receiver.restore();
892 sk_sp<DisplayList> display_list = builder.Build();
893 ASSERT_EQ(display_list->bounds(), build_bounds);
894 }
895
896 {
897 // Testing behavior with an unboundable blend mode
898 DisplayListBuilder builder(build_bounds);
899 DlOpReceiver& receiver = ToReceiver(builder);
901 receiver.saveLayer(&save_bounds, SaveLayerOptions::kWithAttributes);
903 receiver.drawRect(rect);
904 receiver.restore();
905 sk_sp<DisplayList> display_list = builder.Build();
906 ASSERT_EQ(display_list->bounds(), build_bounds);
907 }
908
909 {
910 // Same as previous with no save bounds
911 DisplayListBuilder builder(build_bounds);
912 DlOpReceiver& receiver = ToReceiver(builder);
916 receiver.drawRect(rect);
917 receiver.restore();
918 sk_sp<DisplayList> display_list = builder.Build();
919 ASSERT_EQ(display_list->bounds(), build_bounds);
920 }
921}
922
923TEST_F(DisplayListTest, NestedOpCountMetricsSameAsSkPicture) {
924 SkPictureRecorder recorder;
925 recorder.beginRecording(SkRect::MakeWH(150, 100));
926 SkCanvas* canvas = recorder.getRecordingCanvas();
928 for (int y = 10; y <= 60; y += 10) {
929 for (int x = 10; x <= 60; x += 10) {
930 paint.setColor(((x + y) % 20) == 10 ? SK_ColorRED : SK_ColorBLUE);
931 canvas->drawRect(SkRect::MakeXYWH(x, y, 80, 80), paint);
932 }
933 }
934 SkPictureRecorder outer_recorder;
935 outer_recorder.beginRecording(SkRect::MakeWH(150, 100));
936 canvas = outer_recorder.getRecordingCanvas();
937 canvas->drawPicture(recorder.finishRecordingAsPicture());
938
939 auto picture = outer_recorder.finishRecordingAsPicture();
940 ASSERT_EQ(picture->approximateOpCount(), 1);
941 ASSERT_EQ(picture->approximateOpCount(true), 36);
942
943 DisplayListBuilder builder(SkRect::MakeWH(150, 100));
944 DlOpReceiver& receiver = ToReceiver(builder);
945 for (int y = 10; y <= 60; y += 10) {
946 for (int x = 10; x <= 60; x += 10) {
947 receiver.setColor(((x + y) % 20) == 10 ? DlColor(SK_ColorRED)
949 receiver.drawRect(SkRect::MakeXYWH(x, y, 80, 80));
950 }
951 }
952
953 DisplayListBuilder outer_builder(SkRect::MakeWH(150, 100));
954 DlOpReceiver& outer_receiver = ToReceiver(outer_builder);
955 outer_receiver.drawDisplayList(builder.Build());
956 auto display_list = outer_builder.Build();
957
958 ASSERT_EQ(display_list->op_count(), 1u);
959 ASSERT_EQ(display_list->op_count(true), 36u);
960 EXPECT_EQ(display_list->total_depth(), 37u);
961
962 ASSERT_EQ(picture->approximateOpCount(),
963 static_cast<int>(display_list->op_count()));
964 ASSERT_EQ(picture->approximateOpCount(true),
965 static_cast<int>(display_list->op_count(true)));
966}
967
968TEST_F(DisplayListTest, DisplayListFullPerspectiveTransformHandling) {
969 // SkM44 constructor takes row-major order
971 // clang-format off
972 1, 2, 3, 4,
973 5, 6, 7, 8,
974 9, 10, 11, 12,
975 13, 14, 15, 16
976 // clang-format on
977 );
978
979 { // First test ==
980 DisplayListBuilder builder;
981 DlOpReceiver& receiver = ToReceiver(builder);
982 // receiver.transformFullPerspective takes row-major order
984 // clang-format off
985 1, 2, 3, 4,
986 5, 6, 7, 8,
987 9, 10, 11, 12,
988 13, 14, 15, 16
989 // clang-format on
990 );
991 sk_sp<DisplayList> display_list = builder.Build();
994 SkCanvas* canvas = surface->getCanvas();
995 // We can't use DlSkCanvas.DrawDisplayList as that method protects
996 // the canvas against mutations from the display list being drawn.
997 auto dispatcher = DlSkCanvasDispatcher(surface->getCanvas());
998 display_list->Dispatch(dispatcher);
999 SkM44 dl_matrix = canvas->getLocalToDevice();
1000 ASSERT_EQ(sk_matrix, dl_matrix);
1001 }
1002 { // Next test !=
1003 DisplayListBuilder builder;
1004 DlOpReceiver& receiver = ToReceiver(builder);
1005 // receiver.transformFullPerspective takes row-major order
1006 receiver.transformFullPerspective(
1007 // clang-format off
1008 1, 5, 9, 13,
1009 2, 6, 7, 11,
1010 3, 7, 11, 15,
1011 4, 8, 12, 16
1012 // clang-format on
1013 );
1014 sk_sp<DisplayList> display_list = builder.Build();
1017 SkCanvas* canvas = surface->getCanvas();
1018 // We can't use DlSkCanvas.DrawDisplayList as that method protects
1019 // the canvas against mutations from the display list being drawn.
1020 auto dispatcher = DlSkCanvasDispatcher(surface->getCanvas());
1021 display_list->Dispatch(dispatcher);
1022 SkM44 dl_matrix = canvas->getLocalToDevice();
1023 ASSERT_NE(sk_matrix, dl_matrix);
1024 }
1025}
1026
1027TEST_F(DisplayListTest, DisplayListTransformResetHandling) {
1028 DisplayListBuilder builder;
1029 DlOpReceiver& receiver = ToReceiver(builder);
1030 receiver.scale(20.0, 20.0);
1031 receiver.transformReset();
1032 auto display_list = builder.Build();
1033 ASSERT_NE(display_list, nullptr);
1036 SkCanvas* canvas = surface->getCanvas();
1037 // We can't use DlSkCanvas.DrawDisplayList as that method protects
1038 // the canvas against mutations from the display list being drawn.
1039 auto dispatcher = DlSkCanvasDispatcher(surface->getCanvas());
1040 display_list->Dispatch(dispatcher);
1041 ASSERT_TRUE(canvas->getTotalMatrix().isIdentity());
1042}
1043
1044TEST_F(DisplayListTest, SingleOpsMightSupportGroupOpacityBlendMode) {
1045 auto run_tests = [](const std::string& name,
1046 void build(DlOpReceiver & receiver), bool expect_for_op,
1047 bool expect_with_kSrc) {
1048 {
1049 // First test is the draw op, by itself
1050 // (usually supports group opacity)
1051 DisplayListBuilder builder;
1052 DlOpReceiver& receiver = ToReceiver(builder);
1053 build(receiver);
1054 auto display_list = builder.Build();
1055 EXPECT_EQ(display_list->can_apply_group_opacity(), expect_for_op)
1056 << "{" << std::endl
1057 << " " << name << std::endl
1058 << "}";
1059 }
1060 {
1061 // Second test i the draw op with kSrc,
1062 // (usually fails group opacity)
1063 DisplayListBuilder builder;
1064 DlOpReceiver& receiver = ToReceiver(builder);
1066 build(receiver);
1067 auto display_list = builder.Build();
1068 EXPECT_EQ(display_list->can_apply_group_opacity(), expect_with_kSrc)
1069 << "{" << std::endl
1070 << " receiver.setBlendMode(kSrc);" << std::endl
1071 << " " << name << std::endl
1072 << "}";
1073 }
1074 };
1075
1076#define RUN_TESTS(body) \
1077 run_tests(#body, [](DlOpReceiver& receiver) { body }, true, false)
1078#define RUN_TESTS2(body, expect) \
1079 run_tests(#body, [](DlOpReceiver& receiver) { body }, expect, expect)
1080
1081 RUN_TESTS(receiver.drawPaint(););
1083 , true);
1085 , false);
1086 RUN_TESTS(receiver.drawLine({0, 0}, {10, 10}););
1087 RUN_TESTS(receiver.drawRect({0, 0, 10, 10}););
1088 RUN_TESTS(receiver.drawOval({0, 0, 10, 10}););
1089 RUN_TESTS(receiver.drawCircle({10, 10}, 5););
1090 RUN_TESTS(receiver.drawRRect(SkRRect::MakeRectXY({0, 0, 10, 10}, 2, 2)););
1091 RUN_TESTS(receiver.drawDRRect(SkRRect::MakeRectXY({0, 0, 10, 10}, 2, 2),
1092 SkRRect::MakeRectXY({2, 2, 8, 8}, 2, 2)););
1093 RUN_TESTS(receiver.drawPath(
1094 SkPath().addOval({0, 0, 10, 10}).addOval({5, 5, 15, 15})););
1095 RUN_TESTS(receiver.drawArc({0, 0, 10, 10}, 0, math::kPi, true););
1096 RUN_TESTS2(
1097 receiver.drawPoints(PointMode::kPoints, TestPointCount, kTestPoints);
1098 , false);
1100 , false);
1101 RUN_TESTS(receiver.drawImage(TestImage1, {0, 0}, kLinearSampling, true););
1102 RUN_TESTS2(receiver.drawImage(TestImage1, {0, 0}, kLinearSampling, false);
1103 , true);
1104 RUN_TESTS(receiver.drawImageRect(TestImage1, {10, 10, 20, 20}, {0, 0, 10, 10},
1105 kNearestSampling, true,
1107 RUN_TESTS2(receiver.drawImageRect(TestImage1, {10, 10, 20, 20},
1108 {0, 0, 10, 10}, kNearestSampling, false,
1110 , true);
1111 RUN_TESTS(receiver.drawImageNine(TestImage2, {20, 20, 30, 30}, {0, 0, 20, 20},
1112 DlFilterMode::kLinear, true););
1113 RUN_TESTS2(
1114 receiver.drawImageNine(TestImage2, {20, 20, 30, 30}, {0, 0, 20, 20},
1115 DlFilterMode::kLinear, false);
1116 , true);
1117 static SkRSXform xforms[] = {{1, 0, 0, 0}, {0, 1, 0, 0}};
1118 static SkRect texs[] = {{10, 10, 20, 20}, {20, 20, 30, 30}};
1119 RUN_TESTS2(
1120 receiver.drawAtlas(TestImage1, xforms, texs, nullptr, 2,
1121 DlBlendMode::kSrcIn, kNearestSampling, nullptr, true);
1122 , false);
1123 RUN_TESTS2(
1124 receiver.drawAtlas(TestImage1, xforms, texs, nullptr, 2,
1125 DlBlendMode::kSrcIn, kNearestSampling, nullptr, false);
1126 , false);
1127 EXPECT_TRUE(TestDisplayList1->can_apply_group_opacity());
1129 {
1130 static DisplayListBuilder builder;
1131 builder.DrawRect({0, 0, 10, 10}, DlPaint());
1132 builder.DrawRect({5, 5, 15, 15}, DlPaint());
1133 static auto display_list = builder.Build();
1134 RUN_TESTS2(receiver.drawDisplayList(display_list);, false);
1135 }
1136 RUN_TESTS2(receiver.drawTextBlob(GetTestTextBlob(1), 0, 0);, false);
1137 RUN_TESTS2(
1138 receiver.drawShadow(kTestPath1, DlColor(SK_ColorBLACK), 1.0, false, 1.0);
1139 , false);
1140
1141#undef RUN_TESTS2
1142#undef RUN_TESTS
1143}
1144
1145TEST_F(DisplayListTest, OverlappingOpsDoNotSupportGroupOpacity) {
1146 DisplayListBuilder builder;
1147 DlOpReceiver& receiver = ToReceiver(builder);
1148 for (int i = 0; i < 10; i++) {
1149 receiver.drawRect(SkRect::MakeXYWH(i * 10, 0, 30, 30));
1150 }
1151 auto display_list = builder.Build();
1152 EXPECT_FALSE(display_list->can_apply_group_opacity());
1153}
1154
1155TEST_F(DisplayListTest, SaveLayerFalseSupportsGroupOpacityOverlappingChidren) {
1156 DisplayListBuilder builder;
1157 DlOpReceiver& receiver = ToReceiver(builder);
1158 receiver.saveLayer(nullptr, SaveLayerOptions::kNoAttributes);
1159 for (int i = 0; i < 10; i++) {
1160 receiver.drawRect(SkRect::MakeXYWH(i * 10, 0, 30, 30));
1161 }
1162 receiver.restore();
1163 auto display_list = builder.Build();
1164 EXPECT_TRUE(display_list->can_apply_group_opacity());
1165}
1166
1167TEST_F(DisplayListTest, SaveLayerTrueSupportsGroupOpacityOverlappingChidren) {
1168 DisplayListBuilder builder;
1169 DlOpReceiver& receiver = ToReceiver(builder);
1171 for (int i = 0; i < 10; i++) {
1172 receiver.drawRect(SkRect::MakeXYWH(i * 10, 0, 30, 30));
1173 }
1174 receiver.restore();
1175 auto display_list = builder.Build();
1176 EXPECT_TRUE(display_list->can_apply_group_opacity());
1177}
1178
1179TEST_F(DisplayListTest, SaveLayerFalseWithSrcBlendSupportsGroupOpacity) {
1180 DisplayListBuilder builder;
1181 DlOpReceiver& receiver = ToReceiver(builder);
1183 receiver.saveLayer(nullptr, SaveLayerOptions::kNoAttributes);
1184 receiver.drawRect({0, 0, 10, 10});
1185 receiver.restore();
1186 auto display_list = builder.Build();
1187 EXPECT_TRUE(display_list->can_apply_group_opacity());
1188}
1189
1190TEST_F(DisplayListTest, SaveLayerTrueWithSrcBlendDoesNotSupportGroupOpacity) {
1191 DisplayListBuilder builder;
1192 DlOpReceiver& receiver = ToReceiver(builder);
1195 receiver.drawRect({0, 0, 10, 10});
1196 receiver.restore();
1197 auto display_list = builder.Build();
1198 EXPECT_FALSE(display_list->can_apply_group_opacity());
1199}
1200
1201TEST_F(DisplayListTest, SaveLayerFalseSupportsGroupOpacityWithChildSrcBlend) {
1202 DisplayListBuilder builder;
1203 DlOpReceiver& receiver = ToReceiver(builder);
1204 receiver.saveLayer(nullptr, SaveLayerOptions::kNoAttributes);
1206 receiver.drawRect({0, 0, 10, 10});
1207 receiver.restore();
1208 auto display_list = builder.Build();
1209 EXPECT_TRUE(display_list->can_apply_group_opacity());
1210}
1211
1212TEST_F(DisplayListTest, SaveLayerTrueSupportsGroupOpacityWithChildSrcBlend) {
1213 DisplayListBuilder builder;
1214 DlOpReceiver& receiver = ToReceiver(builder);
1217 receiver.drawRect({0, 0, 10, 10});
1218 receiver.restore();
1219 auto display_list = builder.Build();
1220 EXPECT_TRUE(display_list->can_apply_group_opacity());
1221}
1222
1223TEST_F(DisplayListTest, SaveLayerBoundsSnapshotsImageFilter) {
1224 DisplayListBuilder builder;
1225 DlOpReceiver& receiver = ToReceiver(builder);
1227 receiver.drawRect({50, 50, 100, 100});
1228 // This image filter should be ignored since it was not set before saveLayer
1230 receiver.restore();
1231 SkRect bounds = builder.Build()->bounds();
1232 EXPECT_EQ(bounds, SkRect::MakeLTRB(50, 50, 100, 100));
1233}
1234
1240 public:
1241 explicit SaveLayerOptionsExpector(const SaveLayerOptions& expected) {
1242 expected_.push_back(expected);
1243 }
1244
1245 explicit SaveLayerOptionsExpector(std::vector<SaveLayerOptions> expected)
1246 : expected_(std::move(expected)) {}
1247
1248 void saveLayer(const SkRect& bounds,
1250 const DlImageFilter* backdrop) override {
1251 EXPECT_EQ(options, expected_[save_layer_count_]);
1252 save_layer_count_++;
1253 }
1254
1255 int save_layer_count() { return save_layer_count_; }
1256
1257 private:
1258 std::vector<SaveLayerOptions> expected_;
1259 int save_layer_count_ = 0;
1260};
1261
1262TEST_F(DisplayListTest, SaveLayerOneSimpleOpInheritsOpacity) {
1263 SaveLayerOptions expected =
1265 SaveLayerOptionsExpector expector(expected);
1266
1267 DisplayListBuilder builder;
1268 DlOpReceiver& receiver = ToReceiver(builder);
1269 receiver.setColor(DlColor(SkColorSetARGB(127, 255, 255, 255)));
1271 receiver.drawRect({10, 10, 20, 20});
1272 receiver.restore();
1273
1274 builder.Build()->Dispatch(expector);
1275 EXPECT_EQ(expector.save_layer_count(), 1);
1276}
1277
1278TEST_F(DisplayListTest, SaveLayerNoAttributesInheritsOpacity) {
1279 SaveLayerOptions expected =
1281 SaveLayerOptionsExpector expector(expected);
1282
1283 DisplayListBuilder builder;
1284 DlOpReceiver& receiver = ToReceiver(builder);
1285 receiver.saveLayer(nullptr, SaveLayerOptions::kNoAttributes);
1286 receiver.drawRect({10, 10, 20, 20});
1287 receiver.restore();
1288
1289 builder.Build()->Dispatch(expector);
1290 EXPECT_EQ(expector.save_layer_count(), 1);
1291}
1292
1293TEST_F(DisplayListTest, SaveLayerTwoOverlappingOpsDoesNotInheritOpacity) {
1295 SaveLayerOptionsExpector expector(expected);
1296
1297 DisplayListBuilder builder;
1298 DlOpReceiver& receiver = ToReceiver(builder);
1299 receiver.setColor(DlColor(SkColorSetARGB(127, 255, 255, 255)));
1301 receiver.drawRect({10, 10, 20, 20});
1302 receiver.drawRect({15, 15, 25, 25});
1303 receiver.restore();
1304
1305 builder.Build()->Dispatch(expector);
1306 EXPECT_EQ(expector.save_layer_count(), 1);
1307}
1308
1309TEST_F(DisplayListTest, NestedSaveLayersMightInheritOpacity) {
1310 SaveLayerOptions expected1 =
1313 SaveLayerOptions expected3 =
1315 SaveLayerOptionsExpector expector({expected1, expected2, expected3});
1316
1317 DisplayListBuilder builder;
1318 DlOpReceiver& receiver = ToReceiver(builder);
1319 receiver.setColor(DlColor(SkColorSetARGB(127, 255, 255, 255)));
1322 receiver.drawRect({10, 10, 20, 20});
1324 receiver.drawRect({15, 15, 25, 25});
1325 receiver.restore();
1326 receiver.restore();
1327 receiver.restore();
1328
1329 builder.Build()->Dispatch(expector);
1330 EXPECT_EQ(expector.save_layer_count(), 3);
1331}
1332
1333TEST_F(DisplayListTest, NestedSaveLayersCanBothSupportOpacityOptimization) {
1334 SaveLayerOptions expected1 =
1336 SaveLayerOptions expected2 =
1338 SaveLayerOptionsExpector expector({expected1, expected2});
1339
1340 DisplayListBuilder builder;
1341 DlOpReceiver& receiver = ToReceiver(builder);
1342 receiver.setColor(DlColor(SkColorSetARGB(127, 255, 255, 255)));
1344 receiver.saveLayer(nullptr, SaveLayerOptions::kNoAttributes);
1345 receiver.drawRect({10, 10, 20, 20});
1346 receiver.restore();
1347 receiver.restore();
1348
1349 builder.Build()->Dispatch(expector);
1350 EXPECT_EQ(expector.save_layer_count(), 2);
1351}
1352
1353TEST_F(DisplayListTest, SaveLayerImageFilterDoesNotInheritOpacity) {
1355 SaveLayerOptionsExpector expector(expected);
1356
1357 DisplayListBuilder builder;
1358 DlOpReceiver& receiver = ToReceiver(builder);
1359 receiver.setColor(DlColor(SkColorSetARGB(127, 255, 255, 255)));
1362 receiver.setImageFilter(nullptr);
1363 receiver.drawRect({10, 10, 20, 20});
1364 receiver.restore();
1365
1366 builder.Build()->Dispatch(expector);
1367 EXPECT_EQ(expector.save_layer_count(), 1);
1368}
1369
1370TEST_F(DisplayListTest, SaveLayerColorFilterDoesNotInheritOpacity) {
1372 SaveLayerOptionsExpector expector(expected);
1373
1374 DisplayListBuilder builder;
1375 DlOpReceiver& receiver = ToReceiver(builder);
1376 receiver.setColor(DlColor(SkColorSetARGB(127, 255, 255, 255)));
1379 receiver.setColorFilter(nullptr);
1380 receiver.drawRect({10, 10, 20, 20});
1381 receiver.restore();
1382
1383 builder.Build()->Dispatch(expector);
1384 EXPECT_EQ(expector.save_layer_count(), 1);
1385}
1386
1387TEST_F(DisplayListTest, SaveLayerSrcBlendDoesNotInheritOpacity) {
1389 SaveLayerOptionsExpector expector(expected);
1390
1391 DisplayListBuilder builder;
1392 DlOpReceiver& receiver = ToReceiver(builder);
1393 receiver.setColor(DlColor(SkColorSetARGB(127, 255, 255, 255)));
1397 receiver.drawRect({10, 10, 20, 20});
1398 receiver.restore();
1399
1400 builder.Build()->Dispatch(expector);
1401 EXPECT_EQ(expector.save_layer_count(), 1);
1402}
1403
1404TEST_F(DisplayListTest, SaveLayerImageFilterOnChildInheritsOpacity) {
1405 SaveLayerOptions expected =
1407 SaveLayerOptionsExpector expector(expected);
1408
1409 DisplayListBuilder builder;
1410 DlOpReceiver& receiver = ToReceiver(builder);
1411 receiver.setColor(DlColor(SkColorSetARGB(127, 255, 255, 255)));
1414 receiver.drawRect({10, 10, 20, 20});
1415 receiver.restore();
1416
1417 builder.Build()->Dispatch(expector);
1418 EXPECT_EQ(expector.save_layer_count(), 1);
1419}
1420
1421TEST_F(DisplayListTest, SaveLayerColorFilterOnChildDoesNotInheritOpacity) {
1423 SaveLayerOptionsExpector expector(expected);
1424
1425 DisplayListBuilder builder;
1426 DlOpReceiver& receiver = ToReceiver(builder);
1427 receiver.setColor(DlColor(SkColorSetARGB(127, 255, 255, 255)));
1430 receiver.drawRect({10, 10, 20, 20});
1431 receiver.restore();
1432
1433 builder.Build()->Dispatch(expector);
1434 EXPECT_EQ(expector.save_layer_count(), 1);
1435}
1436
1437TEST_F(DisplayListTest, SaveLayerSrcBlendOnChildDoesNotInheritOpacity) {
1439 SaveLayerOptionsExpector expector(expected);
1440
1441 DisplayListBuilder builder;
1442 DlOpReceiver& receiver = ToReceiver(builder);
1443 receiver.setColor(DlColor(SkColorSetARGB(127, 255, 255, 255)));
1446 receiver.drawRect({10, 10, 20, 20});
1447 receiver.restore();
1448
1449 builder.Build()->Dispatch(expector);
1450 EXPECT_EQ(expector.save_layer_count(), 1);
1451}
1452
1453TEST_F(DisplayListTest, FlutterSvgIssue661BoundsWereEmpty) {
1454 // See https://github.com/dnfield/flutter_svg/issues/661
1455
1456 SkPath path1;
1458 path1.moveTo(25.54f, 37.52f);
1459 path1.cubicTo(20.91f, 37.52f, 16.54f, 33.39f, 13.62f, 30.58f);
1460 path1.lineTo(13, 30);
1461 path1.lineTo(12.45f, 29.42f);
1462 path1.cubicTo(8.39f, 25.15f, 1.61f, 18, 8.37f, 11.27f);
1463 path1.cubicTo(10.18f, 9.46f, 12.37f, 9.58f, 14.49f, 11.58f);
1464 path1.cubicTo(15.67f, 12.71f, 17.05f, 14.69f, 17.07f, 16.58f);
1465 path1.cubicTo(17.0968f, 17.458f, 16.7603f, 18.3081f, 16.14f, 18.93f);
1466 path1.cubicTo(15.8168f, 19.239f, 15.4653f, 19.5169f, 15.09f, 19.76f);
1467 path1.cubicTo(14.27f, 20.33f, 14.21f, 20.44f, 14.27f, 20.62f);
1468 path1.cubicTo(15.1672f, 22.3493f, 16.3239f, 23.9309f, 17.7f, 25.31f);
1469 path1.cubicTo(19.0791f, 26.6861f, 20.6607f, 27.8428f, 22.39f, 28.74f);
1470 path1.cubicTo(22.57f, 28.8f, 22.69f, 28.74f, 23.25f, 27.92f);
1471 path1.cubicTo(23.5f, 27.566f, 23.778f, 27.231f, 24.08f, 26.92f);
1472 path1.cubicTo(24.7045f, 26.3048f, 25.5538f, 25.9723f, 26.43f, 26);
1473 path1.cubicTo(28.29f, 26, 30.27f, 27.4f, 31.43f, 28.58f);
1474 path1.cubicTo(33.43f, 30.67f, 33.55f, 32.9f, 31.74f, 34.7f);
1475 path1.cubicTo(30.1477f, 36.4508f, 27.906f, 37.4704f, 25.54f, 37.52f);
1476 path1.close();
1477 path1.moveTo(11.17f, 12.23f);
1478 path1.cubicTo(10.6946f, 12.2571f, 10.2522f, 12.4819f, 9.95f, 12.85f);
1479 path1.cubicTo(5.12f, 17.67f, 8.95f, 22.5f, 14.05f, 27.85f);
1480 path1.lineTo(14.62f, 28.45f);
1481 path1.lineTo(15.16f, 28.96f);
1482 path1.cubicTo(20.52f, 34.06f, 25.35f, 37.89f, 30.16f, 33.06f);
1483 path1.cubicTo(30.83f, 32.39f, 31.25f, 31.56f, 29.81f, 30.06f);
1484 path1.cubicTo(28.9247f, 29.07f, 27.7359f, 28.4018f, 26.43f, 28.16f);
1485 path1.cubicTo(26.1476f, 28.1284f, 25.8676f, 28.2367f, 25.68f, 28.45f);
1486 path1.cubicTo(25.4633f, 28.6774f, 25.269f, 28.9252f, 25.1f, 29.19f);
1487 path1.cubicTo(24.53f, 30.01f, 23.47f, 31.54f, 21.54f, 30.79f);
1488 path1.lineTo(21.41f, 30.72f);
1489 path1.cubicTo(19.4601f, 29.7156f, 17.6787f, 28.4133f, 16.13f, 26.86f);
1490 path1.cubicTo(14.5748f, 25.3106f, 13.2693f, 23.5295f, 12.26f, 21.58f);
1491 path1.lineTo(12.2f, 21.44f);
1492 path1.cubicTo(11.45f, 19.51f, 12.97f, 18.44f, 13.8f, 17.88f);
1493 path1.cubicTo(14.061f, 17.706f, 14.308f, 17.512f, 14.54f, 17.3f);
1494 path1.cubicTo(14.7379f, 17.1067f, 14.8404f, 16.8359f, 14.82f, 16.56f);
1495 path1.cubicTo(14.5978f, 15.268f, 13.9585f, 14.0843f, 13, 13.19f);
1496 path1.cubicTo(12.5398f, 12.642f, 11.8824f, 12.2971f, 11.17f, 12.23f);
1497 path1.lineTo(11.17f, 12.23f);
1498 path1.close();
1499 path1.moveTo(27, 19.34f);
1500 path1.lineTo(24.74f, 19.34f);
1501 path1.cubicTo(24.7319f, 18.758f, 24.262f, 18.2881f, 23.68f, 18.28f);
1502 path1.lineTo(23.68f, 16.05f);
1503 path1.lineTo(23.7f, 16.05f);
1504 path1.cubicTo(25.5153f, 16.0582f, 26.9863f, 17.5248f, 27, 19.34f);
1505 path1.lineTo(27, 19.34f);
1506 path1.close();
1507 path1.moveTo(32.3f, 19.34f);
1508 path1.lineTo(30.07f, 19.34f);
1509 path1.cubicTo(30.037f, 15.859f, 27.171f, 13.011f, 23.69f, 13);
1510 path1.lineTo(23.69f, 10.72f);
1511 path1.cubicTo(28.415f, 10.725f, 32.3f, 14.615f, 32.3f, 19.34f);
1512 path1.close();
1513
1514 SkPath path2;
1516 path2.moveTo(37.5f, 19.33f);
1517 path2.lineTo(35.27f, 19.33f);
1518 path2.cubicTo(35.265f, 12.979f, 30.041f, 7.755f, 23.69f, 7.75f);
1519 path2.lineTo(23.69f, 5.52f);
1520 path2.cubicTo(31.264f, 5.525f, 37.495f, 11.756f, 37.5f, 19.33f);
1521 path2.close();
1522
1523 DisplayListBuilder builder;
1525 {
1526 builder.Save();
1527 builder.ClipRect({0, 0, 100, 100}, ClipOp::kIntersect, true);
1528 {
1529 builder.Save();
1530 builder.Transform2DAffine(2.17391, 0, -2547.83, //
1531 0, 2.04082, -500);
1532 {
1533 builder.Save();
1534 builder.ClipRect({1172, 245, 1218, 294}, ClipOp::kIntersect, true);
1535 {
1536 builder.SaveLayer(nullptr, nullptr, nullptr);
1537 {
1538 builder.Save();
1539 builder.Transform2DAffine(1.4375, 0, 1164.09, //
1540 0, 1.53125, 236.548);
1541 builder.DrawPath(path1, paint);
1542 builder.Restore();
1543 }
1544 {
1545 builder.Save();
1546 builder.Transform2DAffine(1.4375, 0, 1164.09, //
1547 0, 1.53125, 236.548);
1548 builder.DrawPath(path2, paint);
1549 builder.Restore();
1550 }
1551 builder.Restore();
1552 }
1553 builder.Restore();
1554 }
1555 builder.Restore();
1556 }
1557 builder.Restore();
1558 }
1559 sk_sp<DisplayList> display_list = builder.Build();
1560 // Prior to the fix, the bounds were empty.
1561 EXPECT_FALSE(display_list->bounds().isEmpty());
1562 // These are just inside and outside of the expected bounds, but
1563 // testing float values can be flaky wrt minor changes in the bounds
1564 // calculations. If these lines have to be revised too often as the DL
1565 // implementation is improved and maintained, then we can eliminate
1566 // this test and just rely on the "rounded out" bounds test that follows.
1567 SkRect min_bounds = SkRect::MakeLTRB(0, 0.00191, 99.983, 100);
1568 SkRect max_bounds = SkRect::MakeLTRB(0, 0.00189, 99.985, 100);
1569 ASSERT_TRUE(max_bounds.contains(min_bounds));
1570 EXPECT_TRUE(max_bounds.contains(display_list->bounds()));
1571 EXPECT_TRUE(display_list->bounds().contains(min_bounds));
1572
1573 // This is the more practical result. The bounds are "almost" 0,0,100x100
1574 EXPECT_EQ(display_list->bounds().roundOut(), SkIRect::MakeWH(100, 100));
1575 EXPECT_EQ(display_list->op_count(), 19u);
1576 EXPECT_EQ(display_list->bytes(), sizeof(DisplayList) + 400u);
1577 EXPECT_EQ(display_list->total_depth(), 3u);
1578}
1579
1580TEST_F(DisplayListTest, TranslateAffectsCurrentTransform) {
1581 DisplayListBuilder builder;
1582 DlOpReceiver& receiver = ToReceiver(builder);
1583 receiver.translate(12.3, 14.5);
1584 SkMatrix matrix = SkMatrix::Translate(12.3, 14.5);
1585 SkM44 m44 = SkM44(matrix);
1586 SkM44 cur_m44 = builder.GetTransformFullPerspective();
1587 SkMatrix cur_matrix = builder.GetTransform();
1588 ASSERT_EQ(cur_m44, m44);
1589 ASSERT_EQ(cur_matrix, matrix);
1590 receiver.translate(10, 10);
1591 // CurrentTransform has changed
1592 ASSERT_NE(builder.GetTransformFullPerspective(), m44);
1593 ASSERT_NE(builder.GetTransform(), cur_matrix);
1594 // Previous return values have not
1595 ASSERT_EQ(cur_m44, m44);
1596 ASSERT_EQ(cur_matrix, matrix);
1597}
1598
1599TEST_F(DisplayListTest, ScaleAffectsCurrentTransform) {
1600 DisplayListBuilder builder;
1601 DlOpReceiver& receiver = ToReceiver(builder);
1602 receiver.scale(12.3, 14.5);
1603 SkMatrix matrix = SkMatrix::Scale(12.3, 14.5);
1604 SkM44 m44 = SkM44(matrix);
1605 SkM44 cur_m44 = builder.GetTransformFullPerspective();
1606 SkMatrix cur_matrix = builder.GetTransform();
1607 ASSERT_EQ(cur_m44, m44);
1608 ASSERT_EQ(cur_matrix, matrix);
1609 receiver.translate(10, 10);
1610 // CurrentTransform has changed
1611 ASSERT_NE(builder.GetTransformFullPerspective(), m44);
1612 ASSERT_NE(builder.GetTransform(), cur_matrix);
1613 // Previous return values have not
1614 ASSERT_EQ(cur_m44, m44);
1615 ASSERT_EQ(cur_matrix, matrix);
1616}
1617
1618TEST_F(DisplayListTest, RotateAffectsCurrentTransform) {
1619 DisplayListBuilder builder;
1620 DlOpReceiver& receiver = ToReceiver(builder);
1621 receiver.rotate(12.3);
1622 SkMatrix matrix = SkMatrix::RotateDeg(12.3);
1623 SkM44 m44 = SkM44(matrix);
1624 SkM44 cur_m44 = builder.GetTransformFullPerspective();
1625 SkMatrix cur_matrix = builder.GetTransform();
1626 ASSERT_EQ(cur_m44, m44);
1627 ASSERT_EQ(cur_matrix, matrix);
1628 receiver.translate(10, 10);
1629 // CurrentTransform has changed
1630 ASSERT_NE(builder.GetTransformFullPerspective(), m44);
1631 ASSERT_NE(builder.GetTransform(), cur_matrix);
1632 // Previous return values have not
1633 ASSERT_EQ(cur_m44, m44);
1634 ASSERT_EQ(cur_matrix, matrix);
1635}
1636
1637TEST_F(DisplayListTest, SkewAffectsCurrentTransform) {
1638 DisplayListBuilder builder;
1639 DlOpReceiver& receiver = ToReceiver(builder);
1640 receiver.skew(12.3, 14.5);
1641 SkMatrix matrix = SkMatrix::Skew(12.3, 14.5);
1642 SkM44 m44 = SkM44(matrix);
1643 SkM44 cur_m44 = builder.GetTransformFullPerspective();
1644 SkMatrix cur_matrix = builder.GetTransform();
1645 ASSERT_EQ(cur_m44, m44);
1646 ASSERT_EQ(cur_matrix, matrix);
1647 receiver.translate(10, 10);
1648 // CurrentTransform has changed
1649 ASSERT_NE(builder.GetTransformFullPerspective(), m44);
1650 ASSERT_NE(builder.GetTransform(), cur_matrix);
1651 // Previous return values have not
1652 ASSERT_EQ(cur_m44, m44);
1653 ASSERT_EQ(cur_matrix, matrix);
1654}
1655
1656TEST_F(DisplayListTest, TransformAffectsCurrentTransform) {
1657 DisplayListBuilder builder;
1658 DlOpReceiver& receiver = ToReceiver(builder);
1659 receiver.transform2DAffine(3, 0, 12.3, //
1660 1, 5, 14.5);
1661 SkMatrix matrix = SkMatrix::MakeAll(3, 0, 12.3, //
1662 1, 5, 14.5, //
1663 0, 0, 1);
1664 SkM44 m44 = SkM44(matrix);
1665 SkM44 cur_m44 = builder.GetTransformFullPerspective();
1666 SkMatrix cur_matrix = builder.GetTransform();
1667 ASSERT_EQ(cur_m44, m44);
1668 ASSERT_EQ(cur_matrix, matrix);
1669 receiver.translate(10, 10);
1670 // CurrentTransform has changed
1671 ASSERT_NE(builder.GetTransformFullPerspective(), m44);
1672 ASSERT_NE(builder.GetTransform(), cur_matrix);
1673 // Previous return values have not
1674 ASSERT_EQ(cur_m44, m44);
1675 ASSERT_EQ(cur_matrix, matrix);
1676}
1677
1678TEST_F(DisplayListTest, FullTransformAffectsCurrentTransform) {
1679 DisplayListBuilder builder;
1680 DlOpReceiver& receiver = ToReceiver(builder);
1681 receiver.transformFullPerspective(3, 0, 4, 12.3, //
1682 1, 5, 3, 14.5, //
1683 0, 0, 7, 16.2, //
1684 0, 0, 0, 1);
1685 SkMatrix matrix = SkMatrix::MakeAll(3, 0, 12.3, //
1686 1, 5, 14.5, //
1687 0, 0, 1);
1688 SkM44 m44 = SkM44(3, 0, 4, 12.3, //
1689 1, 5, 3, 14.5, //
1690 0, 0, 7, 16.2, //
1691 0, 0, 0, 1);
1692 SkM44 cur_m44 = builder.GetTransformFullPerspective();
1693 SkMatrix cur_matrix = builder.GetTransform();
1694 ASSERT_EQ(cur_m44, m44);
1695 ASSERT_EQ(cur_matrix, matrix);
1696 receiver.translate(10, 10);
1697 // CurrentTransform has changed
1698 ASSERT_NE(builder.GetTransformFullPerspective(), m44);
1699 ASSERT_NE(builder.GetTransform(), cur_matrix);
1700 // Previous return values have not
1701 ASSERT_EQ(cur_m44, m44);
1702 ASSERT_EQ(cur_matrix, matrix);
1703}
1704
1705TEST_F(DisplayListTest, ClipRectAffectsClipBounds) {
1706 DisplayListBuilder builder;
1707 DlOpReceiver& receiver = ToReceiver(builder);
1708 SkRect clip_bounds = SkRect::MakeLTRB(10.2, 11.3, 20.4, 25.7);
1709 receiver.clipRect(clip_bounds, ClipOp::kIntersect, false);
1710
1711 // Save initial return values for testing restored values
1712 SkRect initial_local_bounds = builder.GetLocalClipBounds();
1713 SkRect initial_destination_bounds = builder.GetDestinationClipBounds();
1714 ASSERT_EQ(initial_local_bounds, clip_bounds);
1715 ASSERT_EQ(initial_destination_bounds, clip_bounds);
1716
1717 receiver.save();
1718 receiver.clipRect({0, 0, 15, 15}, ClipOp::kIntersect, false);
1719 // Both clip bounds have changed
1720 ASSERT_NE(builder.GetLocalClipBounds(), clip_bounds);
1721 ASSERT_NE(builder.GetDestinationClipBounds(), clip_bounds);
1722 // Previous return values have not changed
1723 ASSERT_EQ(initial_local_bounds, clip_bounds);
1724 ASSERT_EQ(initial_destination_bounds, clip_bounds);
1725 receiver.restore();
1726
1727 // save/restore returned the values to their original values
1728 ASSERT_EQ(builder.GetLocalClipBounds(), initial_local_bounds);
1729 ASSERT_EQ(builder.GetDestinationClipBounds(), initial_destination_bounds);
1730
1731 receiver.save();
1732 receiver.scale(2, 2);
1733 SkRect scaled_clip_bounds = SkRect::MakeLTRB(5.1, 5.65, 10.2, 12.85);
1734 ASSERT_EQ(builder.GetLocalClipBounds(), scaled_clip_bounds);
1735 // Destination bounds are unaffected by transform
1736 ASSERT_EQ(builder.GetDestinationClipBounds(), clip_bounds);
1737 receiver.restore();
1738
1739 // save/restore returned the values to their original values
1740 ASSERT_EQ(builder.GetLocalClipBounds(), initial_local_bounds);
1741 ASSERT_EQ(builder.GetDestinationClipBounds(), initial_destination_bounds);
1742}
1743
1744TEST_F(DisplayListTest, ClipRectDoAAAffectsClipBounds) {
1745 DisplayListBuilder builder;
1746 DlOpReceiver& receiver = ToReceiver(builder);
1747 SkRect clip_bounds = SkRect::MakeLTRB(10.2, 11.3, 20.4, 25.7);
1748 SkRect clip_expanded_bounds = SkRect::MakeLTRB(10, 11, 21, 26);
1749 receiver.clipRect(clip_bounds, ClipOp::kIntersect, true);
1750
1751 // Save initial return values for testing restored values
1752 SkRect initial_local_bounds = builder.GetLocalClipBounds();
1753 SkRect initial_destination_bounds = builder.GetDestinationClipBounds();
1754 ASSERT_EQ(initial_local_bounds, clip_expanded_bounds);
1755 ASSERT_EQ(initial_destination_bounds, clip_expanded_bounds);
1756
1757 receiver.save();
1758 receiver.clipRect({0, 0, 15, 15}, ClipOp::kIntersect, true);
1759 // Both clip bounds have changed
1760 ASSERT_NE(builder.GetLocalClipBounds(), clip_expanded_bounds);
1761 ASSERT_NE(builder.GetDestinationClipBounds(), clip_expanded_bounds);
1762 // Previous return values have not changed
1763 ASSERT_EQ(initial_local_bounds, clip_expanded_bounds);
1764 ASSERT_EQ(initial_destination_bounds, clip_expanded_bounds);
1765 receiver.restore();
1766
1767 // save/restore returned the values to their original values
1768 ASSERT_EQ(builder.GetLocalClipBounds(), initial_local_bounds);
1769 ASSERT_EQ(builder.GetDestinationClipBounds(), initial_destination_bounds);
1770
1771 receiver.save();
1772 receiver.scale(2, 2);
1773 SkRect scaled_expanded_bounds = SkRect::MakeLTRB(5, 5.5, 10.5, 13);
1774 ASSERT_EQ(builder.GetLocalClipBounds(), scaled_expanded_bounds);
1775 // Destination bounds are unaffected by transform
1776 ASSERT_EQ(builder.GetDestinationClipBounds(), clip_expanded_bounds);
1777 receiver.restore();
1778
1779 // save/restore returned the values to their original values
1780 ASSERT_EQ(builder.GetLocalClipBounds(), initial_local_bounds);
1781 ASSERT_EQ(builder.GetDestinationClipBounds(), initial_destination_bounds);
1782}
1783
1784TEST_F(DisplayListTest, ClipRectAffectsClipBoundsWithMatrix) {
1785 DisplayListBuilder builder;
1786 DlOpReceiver& receiver = ToReceiver(builder);
1787 SkRect clip_bounds_1 = SkRect::MakeLTRB(0, 0, 10, 10);
1788 SkRect clip_bounds_2 = SkRect::MakeLTRB(10, 10, 20, 20);
1789 receiver.save();
1790 receiver.clipRect(clip_bounds_1, ClipOp::kIntersect, false);
1791 receiver.translate(10, 0);
1792 receiver.clipRect(clip_bounds_1, ClipOp::kIntersect, false);
1793 ASSERT_TRUE(builder.GetDestinationClipBounds().isEmpty());
1794 receiver.restore();
1795
1796 receiver.save();
1797 receiver.clipRect(clip_bounds_1, ClipOp::kIntersect, false);
1798 receiver.translate(-10, -10);
1799 receiver.clipRect(clip_bounds_2, ClipOp::kIntersect, false);
1800 ASSERT_EQ(builder.GetDestinationClipBounds(), clip_bounds_1);
1801 receiver.restore();
1802}
1803
1804TEST_F(DisplayListTest, ClipRRectAffectsClipBounds) {
1805 DisplayListBuilder builder;
1806 DlOpReceiver& receiver = ToReceiver(builder);
1807 SkRect clip_bounds = SkRect::MakeLTRB(10.2, 11.3, 20.4, 25.7);
1808 SkRRect clip = SkRRect::MakeRectXY(clip_bounds, 3, 2);
1809 receiver.clipRRect(clip, ClipOp::kIntersect, false);
1810
1811 // Save initial return values for testing restored values
1812 SkRect initial_local_bounds = builder.GetLocalClipBounds();
1813 SkRect initial_destination_bounds = builder.GetDestinationClipBounds();
1814 ASSERT_EQ(initial_local_bounds, clip_bounds);
1815 ASSERT_EQ(initial_destination_bounds, clip_bounds);
1816
1817 receiver.save();
1818 receiver.clipRect({0, 0, 15, 15}, ClipOp::kIntersect, false);
1819 // Both clip bounds have changed
1820 ASSERT_NE(builder.GetLocalClipBounds(), clip_bounds);
1821 ASSERT_NE(builder.GetDestinationClipBounds(), clip_bounds);
1822 // Previous return values have not changed
1823 ASSERT_EQ(initial_local_bounds, clip_bounds);
1824 ASSERT_EQ(initial_destination_bounds, clip_bounds);
1825 receiver.restore();
1826
1827 // save/restore returned the values to their original values
1828 ASSERT_EQ(builder.GetLocalClipBounds(), initial_local_bounds);
1829 ASSERT_EQ(builder.GetDestinationClipBounds(), initial_destination_bounds);
1830
1831 receiver.save();
1832 receiver.scale(2, 2);
1833 SkRect scaled_clip_bounds = SkRect::MakeLTRB(5.1, 5.65, 10.2, 12.85);
1834 ASSERT_EQ(builder.GetLocalClipBounds(), scaled_clip_bounds);
1835 // Destination bounds are unaffected by transform
1836 ASSERT_EQ(builder.GetDestinationClipBounds(), clip_bounds);
1837 receiver.restore();
1838
1839 // save/restore returned the values to their original values
1840 ASSERT_EQ(builder.GetLocalClipBounds(), initial_local_bounds);
1841 ASSERT_EQ(builder.GetDestinationClipBounds(), initial_destination_bounds);
1842}
1843
1844TEST_F(DisplayListTest, ClipRRectDoAAAffectsClipBounds) {
1845 DisplayListBuilder builder;
1846 DlOpReceiver& receiver = ToReceiver(builder);
1847 SkRect clip_bounds = SkRect::MakeLTRB(10.2, 11.3, 20.4, 25.7);
1848 SkRect clip_expanded_bounds = SkRect::MakeLTRB(10, 11, 21, 26);
1849 SkRRect clip = SkRRect::MakeRectXY(clip_bounds, 3, 2);
1850 receiver.clipRRect(clip, ClipOp::kIntersect, true);
1851
1852 // Save initial return values for testing restored values
1853 SkRect initial_local_bounds = builder.GetLocalClipBounds();
1854 SkRect initial_destination_bounds = builder.GetDestinationClipBounds();
1855 ASSERT_EQ(initial_local_bounds, clip_expanded_bounds);
1856 ASSERT_EQ(initial_destination_bounds, clip_expanded_bounds);
1857
1858 receiver.save();
1859 receiver.clipRect({0, 0, 15, 15}, ClipOp::kIntersect, true);
1860 // Both clip bounds have changed
1861 ASSERT_NE(builder.GetLocalClipBounds(), clip_expanded_bounds);
1862 ASSERT_NE(builder.GetDestinationClipBounds(), clip_expanded_bounds);
1863 // Previous return values have not changed
1864 ASSERT_EQ(initial_local_bounds, clip_expanded_bounds);
1865 ASSERT_EQ(initial_destination_bounds, clip_expanded_bounds);
1866 receiver.restore();
1867
1868 // save/restore returned the values to their original values
1869 ASSERT_EQ(builder.GetLocalClipBounds(), initial_local_bounds);
1870 ASSERT_EQ(builder.GetDestinationClipBounds(), initial_destination_bounds);
1871
1872 receiver.save();
1873 receiver.scale(2, 2);
1874 SkRect scaled_expanded_bounds = SkRect::MakeLTRB(5, 5.5, 10.5, 13);
1875 ASSERT_EQ(builder.GetLocalClipBounds(), scaled_expanded_bounds);
1876 // Destination bounds are unaffected by transform
1877 ASSERT_EQ(builder.GetDestinationClipBounds(), clip_expanded_bounds);
1878 receiver.restore();
1879
1880 // save/restore returned the values to their original values
1881 ASSERT_EQ(builder.GetLocalClipBounds(), initial_local_bounds);
1882 ASSERT_EQ(builder.GetDestinationClipBounds(), initial_destination_bounds);
1883}
1884
1885TEST_F(DisplayListTest, ClipRRectAffectsClipBoundsWithMatrix) {
1886 DisplayListBuilder builder;
1887 DlOpReceiver& receiver = ToReceiver(builder);
1888 SkRect clip_bounds_1 = SkRect::MakeLTRB(0, 0, 10, 10);
1889 SkRect clip_bounds_2 = SkRect::MakeLTRB(10, 10, 20, 20);
1890 SkRRect clip1 = SkRRect::MakeRectXY(clip_bounds_1, 3, 2);
1891 SkRRect clip2 = SkRRect::MakeRectXY(clip_bounds_2, 3, 2);
1892
1893 receiver.save();
1894 receiver.clipRRect(clip1, ClipOp::kIntersect, false);
1895 receiver.translate(10, 0);
1896 receiver.clipRRect(clip1, ClipOp::kIntersect, false);
1897 ASSERT_TRUE(builder.GetDestinationClipBounds().isEmpty());
1898 receiver.restore();
1899
1900 receiver.save();
1901 receiver.clipRRect(clip1, ClipOp::kIntersect, false);
1902 receiver.translate(-10, -10);
1903 receiver.clipRRect(clip2, ClipOp::kIntersect, false);
1904 ASSERT_EQ(builder.GetDestinationClipBounds(), clip_bounds_1);
1905 receiver.restore();
1906}
1907
1908TEST_F(DisplayListTest, ClipPathAffectsClipBounds) {
1909 DisplayListBuilder builder;
1910 DlOpReceiver& receiver = ToReceiver(builder);
1911 SkPath clip = SkPath().addCircle(10.2, 11.3, 2).addCircle(20.4, 25.7, 2);
1912 SkRect clip_bounds = SkRect::MakeLTRB(8.2, 9.3, 22.4, 27.7);
1913 receiver.clipPath(clip, ClipOp::kIntersect, false);
1914
1915 // Save initial return values for testing restored values
1916 SkRect initial_local_bounds = builder.GetLocalClipBounds();
1917 SkRect initial_destination_bounds = builder.GetDestinationClipBounds();
1918 ASSERT_EQ(initial_local_bounds, clip_bounds);
1919 ASSERT_EQ(initial_destination_bounds, clip_bounds);
1920
1921 receiver.save();
1922 receiver.clipRect({0, 0, 15, 15}, ClipOp::kIntersect, false);
1923 // Both clip bounds have changed
1924 ASSERT_NE(builder.GetLocalClipBounds(), clip_bounds);
1925 ASSERT_NE(builder.GetDestinationClipBounds(), clip_bounds);
1926 // Previous return values have not changed
1927 ASSERT_EQ(initial_local_bounds, clip_bounds);
1928 ASSERT_EQ(initial_destination_bounds, clip_bounds);
1929 receiver.restore();
1930
1931 // save/restore returned the values to their original values
1932 ASSERT_EQ(builder.GetLocalClipBounds(), initial_local_bounds);
1933 ASSERT_EQ(builder.GetDestinationClipBounds(), initial_destination_bounds);
1934
1935 receiver.save();
1936 receiver.scale(2, 2);
1937 SkRect scaled_clip_bounds = SkRect::MakeLTRB(4.1, 4.65, 11.2, 13.85);
1938 ASSERT_EQ(builder.GetLocalClipBounds(), scaled_clip_bounds);
1939 // Destination bounds are unaffected by transform
1940 ASSERT_EQ(builder.GetDestinationClipBounds(), clip_bounds);
1941 receiver.restore();
1942
1943 // save/restore returned the values to their original values
1944 ASSERT_EQ(builder.GetLocalClipBounds(), initial_local_bounds);
1945 ASSERT_EQ(builder.GetDestinationClipBounds(), initial_destination_bounds);
1946}
1947
1948TEST_F(DisplayListTest, ClipPathDoAAAffectsClipBounds) {
1949 DisplayListBuilder builder;
1950 DlOpReceiver& receiver = ToReceiver(builder);
1951 SkPath clip = SkPath().addCircle(10.2, 11.3, 2).addCircle(20.4, 25.7, 2);
1952 SkRect clip_expanded_bounds = SkRect::MakeLTRB(8, 9, 23, 28);
1953 receiver.clipPath(clip, ClipOp::kIntersect, true);
1954
1955 // Save initial return values for testing restored values
1956 SkRect initial_local_bounds = builder.GetLocalClipBounds();
1957 SkRect initial_destination_bounds = builder.GetDestinationClipBounds();
1958 ASSERT_EQ(initial_local_bounds, clip_expanded_bounds);
1959 ASSERT_EQ(initial_destination_bounds, clip_expanded_bounds);
1960
1961 receiver.save();
1962 receiver.clipRect({0, 0, 15, 15}, ClipOp::kIntersect, true);
1963 // Both clip bounds have changed
1964 ASSERT_NE(builder.GetLocalClipBounds(), clip_expanded_bounds);
1965 ASSERT_NE(builder.GetDestinationClipBounds(), clip_expanded_bounds);
1966 // Previous return values have not changed
1967 ASSERT_EQ(initial_local_bounds, clip_expanded_bounds);
1968 ASSERT_EQ(initial_destination_bounds, clip_expanded_bounds);
1969 receiver.restore();
1970
1971 // save/restore returned the values to their original values
1972 ASSERT_EQ(builder.GetLocalClipBounds(), initial_local_bounds);
1973 ASSERT_EQ(builder.GetDestinationClipBounds(), initial_destination_bounds);
1974
1975 receiver.save();
1976 receiver.scale(2, 2);
1977 SkRect scaled_expanded_bounds = SkRect::MakeLTRB(4, 4.5, 11.5, 14);
1978 ASSERT_EQ(builder.GetLocalClipBounds(), scaled_expanded_bounds);
1979 // Destination bounds are unaffected by transform
1980 ASSERT_EQ(builder.GetDestinationClipBounds(), clip_expanded_bounds);
1981 receiver.restore();
1982
1983 // save/restore returned the values to their original values
1984 ASSERT_EQ(builder.GetLocalClipBounds(), initial_local_bounds);
1985 ASSERT_EQ(builder.GetDestinationClipBounds(), initial_destination_bounds);
1986}
1987
1988TEST_F(DisplayListTest, ClipPathAffectsClipBoundsWithMatrix) {
1989 DisplayListBuilder builder;
1990 DlOpReceiver& receiver = ToReceiver(builder);
1991 SkRect clip_bounds = SkRect::MakeLTRB(0, 0, 10, 10);
1992 SkPath clip1 = SkPath().addCircle(2.5, 2.5, 2.5).addCircle(7.5, 7.5, 2.5);
1993 SkPath clip2 = SkPath().addCircle(12.5, 12.5, 2.5).addCircle(17.5, 17.5, 2.5);
1994
1995 receiver.save();
1996 receiver.clipPath(clip1, ClipOp::kIntersect, false);
1997 receiver.translate(10, 0);
1998 receiver.clipPath(clip1, ClipOp::kIntersect, false);
1999 ASSERT_TRUE(builder.GetDestinationClipBounds().isEmpty());
2000 receiver.restore();
2001
2002 receiver.save();
2003 receiver.clipPath(clip1, ClipOp::kIntersect, false);
2004 receiver.translate(-10, -10);
2005 receiver.clipPath(clip2, ClipOp::kIntersect, false);
2006 ASSERT_EQ(builder.GetDestinationClipBounds(), clip_bounds);
2007 receiver.restore();
2008}
2009
2010TEST_F(DisplayListTest, DiffClipRectDoesNotAffectClipBounds) {
2011 DisplayListBuilder builder;
2012 DlOpReceiver& receiver = ToReceiver(builder);
2013 SkRect diff_clip = SkRect::MakeLTRB(0, 0, 15, 15);
2014 SkRect clip_bounds = SkRect::MakeLTRB(10.2, 11.3, 20.4, 25.7);
2015 receiver.clipRect(clip_bounds, ClipOp::kIntersect, false);
2016
2017 // Save initial return values for testing after kDifference clip
2018 SkRect initial_local_bounds = builder.GetLocalClipBounds();
2019 SkRect initial_destination_bounds = builder.GetDestinationClipBounds();
2020 ASSERT_EQ(initial_local_bounds, clip_bounds);
2021 ASSERT_EQ(initial_destination_bounds, clip_bounds);
2022
2023 receiver.clipRect(diff_clip, ClipOp::kDifference, false);
2024 ASSERT_EQ(builder.GetLocalClipBounds(), initial_local_bounds);
2025 ASSERT_EQ(builder.GetDestinationClipBounds(), initial_destination_bounds);
2026}
2027
2028TEST_F(DisplayListTest, DiffClipRRectDoesNotAffectClipBounds) {
2029 DisplayListBuilder builder;
2030 DlOpReceiver& receiver = ToReceiver(builder);
2031 SkRRect diff_clip = SkRRect::MakeRectXY({0, 0, 15, 15}, 1, 1);
2032 SkRect clip_bounds = SkRect::MakeLTRB(10.2, 11.3, 20.4, 25.7);
2033 SkRRect clip = SkRRect::MakeRectXY({10.2, 11.3, 20.4, 25.7}, 3, 2);
2034 receiver.clipRRect(clip, ClipOp::kIntersect, false);
2035
2036 // Save initial return values for testing after kDifference clip
2037 SkRect initial_local_bounds = builder.GetLocalClipBounds();
2038 SkRect initial_destination_bounds = builder.GetDestinationClipBounds();
2039 ASSERT_EQ(initial_local_bounds, clip_bounds);
2040 ASSERT_EQ(initial_destination_bounds, clip_bounds);
2041
2042 receiver.clipRRect(diff_clip, ClipOp::kDifference, false);
2043 ASSERT_EQ(builder.GetLocalClipBounds(), initial_local_bounds);
2044 ASSERT_EQ(builder.GetDestinationClipBounds(), initial_destination_bounds);
2045}
2046
2047TEST_F(DisplayListTest, DiffClipPathDoesNotAffectClipBounds) {
2048 DisplayListBuilder builder;
2049 DlOpReceiver& receiver = ToReceiver(builder);
2050 SkPath diff_clip = SkPath().addRect({0, 0, 15, 15});
2051 SkPath clip = SkPath().addCircle(10.2, 11.3, 2).addCircle(20.4, 25.7, 2);
2052 SkRect clip_bounds = SkRect::MakeLTRB(8.2, 9.3, 22.4, 27.7);
2053 receiver.clipPath(clip, ClipOp::kIntersect, false);
2054
2055 // Save initial return values for testing after kDifference clip
2056 SkRect initial_local_bounds = builder.GetLocalClipBounds();
2057 SkRect initial_destination_bounds = builder.GetDestinationClipBounds();
2058 ASSERT_EQ(initial_local_bounds, clip_bounds);
2059 ASSERT_EQ(initial_destination_bounds, clip_bounds);
2060
2061 receiver.clipPath(diff_clip, ClipOp::kDifference, false);
2062 ASSERT_EQ(builder.GetLocalClipBounds(), initial_local_bounds);
2063 ASSERT_EQ(builder.GetDestinationClipBounds(), initial_destination_bounds);
2064}
2065
2066TEST_F(DisplayListTest, ClipPathWithInvertFillTypeDoesNotAffectClipBounds) {
2067 SkRect cull_rect = SkRect::MakeLTRB(0, 0, 100.0, 100.0);
2068 DisplayListBuilder builder(cull_rect);
2069 DlOpReceiver& receiver = ToReceiver(builder);
2070 SkPath clip = SkPath().addCircle(10.2, 11.3, 2).addCircle(20.4, 25.7, 2);
2072 receiver.clipPath(clip, ClipOp::kIntersect, false);
2073
2074 ASSERT_EQ(builder.GetLocalClipBounds(), cull_rect);
2075 ASSERT_EQ(builder.GetDestinationClipBounds(), cull_rect);
2076}
2077
2078TEST_F(DisplayListTest, DiffClipPathWithInvertFillTypeAffectsClipBounds) {
2079 SkRect cull_rect = SkRect::MakeLTRB(0, 0, 100.0, 100.0);
2080 DisplayListBuilder builder(cull_rect);
2081 DlOpReceiver& receiver = ToReceiver(builder);
2082 SkPath clip = SkPath().addCircle(10.2, 11.3, 2).addCircle(20.4, 25.7, 2);
2084 SkRect clip_bounds = SkRect::MakeLTRB(8.2, 9.3, 22.4, 27.7);
2085 receiver.clipPath(clip, ClipOp::kDifference, false);
2086
2087 ASSERT_EQ(builder.GetLocalClipBounds(), clip_bounds);
2088 ASSERT_EQ(builder.GetDestinationClipBounds(), clip_bounds);
2089}
2090
2091TEST_F(DisplayListTest, FlatDrawPointsProducesBounds) {
2092 SkPoint horizontal_points[2] = {{10, 10}, {20, 10}};
2093 SkPoint vertical_points[2] = {{10, 10}, {10, 20}};
2094 {
2095 DisplayListBuilder builder;
2096 DlOpReceiver& receiver = ToReceiver(builder);
2097 receiver.drawPoints(PointMode::kPolygon, 2, horizontal_points);
2098 SkRect bounds = builder.Build()->bounds();
2099 EXPECT_TRUE(bounds.contains(10, 10));
2100 EXPECT_TRUE(bounds.contains(20, 10));
2101 EXPECT_GE(bounds.width(), 10);
2102 }
2103 {
2104 DisplayListBuilder builder;
2105 DlOpReceiver& receiver = ToReceiver(builder);
2106 receiver.drawPoints(PointMode::kPolygon, 2, vertical_points);
2107 SkRect bounds = builder.Build()->bounds();
2108 EXPECT_TRUE(bounds.contains(10, 10));
2109 EXPECT_TRUE(bounds.contains(10, 20));
2110 EXPECT_GE(bounds.height(), 10);
2111 }
2112 {
2113 DisplayListBuilder builder;
2114 DlOpReceiver& receiver = ToReceiver(builder);
2115 receiver.drawPoints(PointMode::kPoints, 1, horizontal_points);
2116 SkRect bounds = builder.Build()->bounds();
2117 EXPECT_TRUE(bounds.contains(10, 10));
2118 }
2119 {
2120 DisplayListBuilder builder;
2121 DlOpReceiver& receiver = ToReceiver(builder);
2122 receiver.setStrokeWidth(2);
2123 receiver.drawPoints(PointMode::kPolygon, 2, horizontal_points);
2124 SkRect bounds = builder.Build()->bounds();
2125 EXPECT_TRUE(bounds.contains(10, 10));
2126 EXPECT_TRUE(bounds.contains(20, 10));
2127 EXPECT_EQ(bounds, SkRect::MakeLTRB(9, 9, 21, 11));
2128 }
2129 {
2130 DisplayListBuilder builder;
2131 DlOpReceiver& receiver = ToReceiver(builder);
2132 receiver.setStrokeWidth(2);
2133 receiver.drawPoints(PointMode::kPolygon, 2, vertical_points);
2134 SkRect bounds = builder.Build()->bounds();
2135 EXPECT_TRUE(bounds.contains(10, 10));
2136 EXPECT_TRUE(bounds.contains(10, 20));
2137 EXPECT_EQ(bounds, SkRect::MakeLTRB(9, 9, 11, 21));
2138 }
2139 {
2140 DisplayListBuilder builder;
2141 DlOpReceiver& receiver = ToReceiver(builder);
2142 receiver.setStrokeWidth(2);
2143 receiver.drawPoints(PointMode::kPoints, 1, horizontal_points);
2144 SkRect bounds = builder.Build()->bounds();
2145 EXPECT_TRUE(bounds.contains(10, 10));
2146 EXPECT_EQ(bounds, SkRect::MakeLTRB(9, 9, 11, 11));
2147 }
2148}
2149
2150static void test_rtree(const sk_sp<const DlRTree>& rtree,
2151 const SkRect& query,
2152 std::vector<SkRect> expected_rects,
2153 const std::vector<int>& expected_indices) {
2154 std::vector<int> indices;
2155 rtree->search(query, &indices);
2156 EXPECT_EQ(indices, expected_indices);
2157 EXPECT_EQ(indices.size(), expected_indices.size());
2158 std::list<SkRect> rects = rtree->searchAndConsolidateRects(query);
2159 // ASSERT_EQ(rects.size(), expected_indices.size());
2160 auto iterator = rects.cbegin();
2161 for (int i : expected_indices) {
2162 EXPECT_TRUE(iterator != rects.cend());
2163 EXPECT_EQ(*iterator++, expected_rects[i]);
2164 }
2165}
2166
2167TEST_F(DisplayListTest, RTreeOfSimpleScene) {
2168 DisplayListBuilder builder(/*prepare_rtree=*/true);
2169 DlOpReceiver& receiver = ToReceiver(builder);
2170 receiver.drawRect({10, 10, 20, 20});
2171 receiver.drawRect({50, 50, 60, 60});
2172 auto display_list = builder.Build();
2173 auto rtree = display_list->rtree();
2174 std::vector<SkRect> rects = {
2175 {10, 10, 20, 20},
2176 {50, 50, 60, 60},
2177 };
2178
2179 // Missing all drawRect calls
2180 test_rtree(rtree, {5, 5, 10, 10}, rects, {});
2181 test_rtree(rtree, {20, 20, 25, 25}, rects, {});
2182 test_rtree(rtree, {45, 45, 50, 50}, rects, {});
2183 test_rtree(rtree, {60, 60, 65, 65}, rects, {});
2184
2185 // Hitting just 1 of the drawRects
2186 test_rtree(rtree, {5, 5, 11, 11}, rects, {0});
2187 test_rtree(rtree, {19, 19, 25, 25}, rects, {0});
2188 test_rtree(rtree, {45, 45, 51, 51}, rects, {1});
2189 test_rtree(rtree, {59, 59, 65, 65}, rects, {1});
2190
2191 // Hitting both drawRect calls
2192 test_rtree(rtree, {19, 19, 51, 51}, rects, {0, 1});
2193}
2194
2195TEST_F(DisplayListTest, RTreeOfSaveRestoreScene) {
2196 DisplayListBuilder builder(/*prepare_rtree=*/true);
2197 DlOpReceiver& receiver = ToReceiver(builder);
2198 receiver.drawRect({10, 10, 20, 20});
2199 receiver.save();
2200 receiver.drawRect({50, 50, 60, 60});
2201 receiver.restore();
2202 auto display_list = builder.Build();
2203 auto rtree = display_list->rtree();
2204 std::vector<SkRect> rects = {
2205 {10, 10, 20, 20},
2206 {50, 50, 60, 60},
2207 };
2208
2209 // Missing all drawRect calls
2210 test_rtree(rtree, {5, 5, 10, 10}, rects, {});
2211 test_rtree(rtree, {20, 20, 25, 25}, rects, {});
2212 test_rtree(rtree, {45, 45, 50, 50}, rects, {});
2213 test_rtree(rtree, {60, 60, 65, 65}, rects, {});
2214
2215 // Hitting just 1 of the drawRects
2216 test_rtree(rtree, {5, 5, 11, 11}, rects, {0});
2217 test_rtree(rtree, {19, 19, 25, 25}, rects, {0});
2218 test_rtree(rtree, {45, 45, 51, 51}, rects, {1});
2219 test_rtree(rtree, {59, 59, 65, 65}, rects, {1});
2220
2221 // Hitting both drawRect calls
2222 test_rtree(rtree, {19, 19, 51, 51}, rects, {0, 1});
2223}
2224
2225TEST_F(DisplayListTest, RTreeOfSaveLayerFilterScene) {
2226 DisplayListBuilder builder(/*prepare_rtree=*/true);
2227 // blur filter with sigma=1 expands by 3 on all sides
2228 auto filter = DlBlurImageFilter(1.0, 1.0, DlTileMode::kClamp);
2229 DlPaint default_paint = DlPaint();
2230 DlPaint filter_paint = DlPaint().setImageFilter(&filter);
2231 builder.DrawRect({10, 10, 20, 20}, default_paint);
2232 builder.SaveLayer(nullptr, &filter_paint);
2233 // the following rectangle will be expanded to 50,50,60,60
2234 // by the saveLayer filter during the restore operation
2235 builder.DrawRect({53, 53, 57, 57}, default_paint);
2236 builder.Restore();
2237 auto display_list = builder.Build();
2238 auto rtree = display_list->rtree();
2239 std::vector<SkRect> rects = {
2240 {10, 10, 20, 20},
2241 {50, 50, 60, 60},
2242 };
2243
2244 // Missing all drawRect calls
2245 test_rtree(rtree, {5, 5, 10, 10}, rects, {});
2246 test_rtree(rtree, {20, 20, 25, 25}, rects, {});
2247 test_rtree(rtree, {45, 45, 50, 50}, rects, {});
2248 test_rtree(rtree, {60, 60, 65, 65}, rects, {});
2249
2250 // Hitting just 1 of the drawRects
2251 test_rtree(rtree, {5, 5, 11, 11}, rects, {0});
2252 test_rtree(rtree, {19, 19, 25, 25}, rects, {0});
2253 test_rtree(rtree, {45, 45, 51, 51}, rects, {1});
2254 test_rtree(rtree, {59, 59, 65, 65}, rects, {1});
2255
2256 // Hitting both drawRect calls
2257 test_rtree(rtree, {19, 19, 51, 51}, rects, {0, 1});
2258}
2259
2260TEST_F(DisplayListTest, NestedDisplayListRTreesAreSparse) {
2261 DisplayListBuilder nested_dl_builder(/**prepare_rtree=*/true);
2262 DlOpReceiver& nested_dl_receiver = ToReceiver(nested_dl_builder);
2263 nested_dl_receiver.drawRect({10, 10, 20, 20});
2264 nested_dl_receiver.drawRect({50, 50, 60, 60});
2265 auto nested_display_list = nested_dl_builder.Build();
2266
2267 DisplayListBuilder builder(/**prepare_rtree=*/true);
2268 DlOpReceiver& receiver = ToReceiver(builder);
2269 receiver.drawDisplayList(nested_display_list);
2270 auto display_list = builder.Build();
2271
2272 auto rtree = display_list->rtree();
2273 std::vector<SkRect> rects = {
2274 {10, 10, 20, 20},
2275 {50, 50, 60, 60},
2276 };
2277
2278 // Hitting both sub-dl drawRect calls
2279 test_rtree(rtree, {19, 19, 51, 51}, rects, {0, 1});
2280}
2281
2282TEST_F(DisplayListTest, RemoveUnnecessarySaveRestorePairs) {
2283 {
2284 DisplayListBuilder builder;
2285 DlOpReceiver& receiver = ToReceiver(builder);
2286 receiver.drawRect({10, 10, 20, 20});
2287 receiver.save(); // This save op is unnecessary
2288 receiver.drawRect({50, 50, 60, 60});
2289 receiver.restore();
2290
2291 DisplayListBuilder builder2;
2292 DlOpReceiver& receiver2 = ToReceiver(builder2);
2293 receiver2.drawRect({10, 10, 20, 20});
2294 receiver2.drawRect({50, 50, 60, 60});
2295 ASSERT_TRUE(DisplayListsEQ_Verbose(builder.Build(), builder2.Build()));
2296 }
2297
2298 {
2299 DisplayListBuilder builder;
2300 DlOpReceiver& receiver = ToReceiver(builder);
2301 receiver.drawRect({10, 10, 20, 20});
2302 receiver.save();
2303 receiver.translate(1.0, 1.0);
2304 {
2305 receiver.save(); // unnecessary
2306 receiver.drawRect({50, 50, 60, 60});
2307 receiver.restore();
2308 }
2309
2310 receiver.restore();
2311
2312 DisplayListBuilder builder2;
2313 DlOpReceiver& receiver2 = ToReceiver(builder2);
2314 receiver2.drawRect({10, 10, 20, 20});
2315 receiver2.save();
2316 receiver2.translate(1.0, 1.0);
2317 { receiver2.drawRect({50, 50, 60, 60}); }
2318 receiver2.restore();
2319 ASSERT_TRUE(DisplayListsEQ_Verbose(builder.Build(), builder2.Build()));
2320 }
2321}
2322
2323TEST_F(DisplayListTest, CollapseMultipleNestedSaveRestore) {
2324 DisplayListBuilder builder1;
2325 DlOpReceiver& receiver1 = ToReceiver(builder1);
2326 receiver1.save();
2327 receiver1.save();
2328 receiver1.save();
2329 receiver1.translate(10, 10);
2330 receiver1.scale(2, 2);
2331 receiver1.clipRect({10, 10, 20, 20}, ClipOp::kIntersect, false);
2332 receiver1.drawRect({0, 0, 100, 100});
2333 receiver1.restore();
2334 receiver1.restore();
2335 receiver1.restore();
2336 auto display_list1 = builder1.Build();
2337
2338 DisplayListBuilder builder2;
2339 DlOpReceiver& receiver2 = ToReceiver(builder2);
2340 receiver2.save();
2341 receiver2.translate(10, 10);
2342 receiver2.scale(2, 2);
2343 receiver2.clipRect({10, 10, 20, 20}, ClipOp::kIntersect, false);
2344 receiver2.drawRect({0, 0, 100, 100});
2345 receiver2.restore();
2346 auto display_list2 = builder2.Build();
2347
2348 ASSERT_TRUE(DisplayListsEQ_Verbose(display_list1, display_list2));
2349}
2350
2351TEST_F(DisplayListTest, CollapseNestedSaveAndSaveLayerRestore) {
2352 DisplayListBuilder builder1;
2353 DlOpReceiver& receiver1 = ToReceiver(builder1);
2354 receiver1.save();
2355 receiver1.saveLayer(nullptr, SaveLayerOptions::kNoAttributes);
2356 receiver1.drawRect({0, 0, 100, 100});
2357 receiver1.scale(2, 2);
2358 receiver1.restore();
2359 receiver1.restore();
2360 auto display_list1 = builder1.Build();
2361
2362 DisplayListBuilder builder2;
2363 DlOpReceiver& receiver2 = ToReceiver(builder2);
2364 receiver2.saveLayer(nullptr, SaveLayerOptions::kNoAttributes);
2365 receiver2.drawRect({0, 0, 100, 100});
2366 receiver2.scale(2, 2);
2367 receiver2.restore();
2368 auto display_list2 = builder2.Build();
2369
2370 ASSERT_TRUE(DisplayListsEQ_Verbose(display_list1, display_list2));
2371}
2372
2373TEST_F(DisplayListTest, RemoveUnnecessarySaveRestorePairsInSetPaint) {
2374 SkRect build_bounds = SkRect::MakeLTRB(-100, -100, 200, 200);
2375 SkRect rect = SkRect::MakeLTRB(30, 30, 70, 70);
2376 // clang-format off
2377 const float alpha_matrix[] = {
2378 0, 0, 0, 0, 0,
2379 0, 1, 0, 0, 0,
2380 0, 0, 1, 0, 0,
2381 0, 0, 0, 0, 1,
2382 };
2383 // clang-format on
2384 DlMatrixColorFilter alpha_color_filter(alpha_matrix);
2385 // Making sure hiding a problematic ColorFilter as an ImageFilter
2386 // will generate the same behavior as setting it as a ColorFilter
2387
2388 DlColorFilterImageFilter color_filter_image_filter(alpha_color_filter);
2389 {
2390 DisplayListBuilder builder(build_bounds);
2391 builder.Save();
2392 DlPaint paint;
2393 paint.setImageFilter(&color_filter_image_filter);
2394 builder.DrawRect(rect, paint);
2395 builder.Restore();
2396 sk_sp<DisplayList> display_list1 = builder.Build();
2397
2398 DisplayListBuilder builder2(build_bounds);
2399 DlPaint paint2;
2400 paint2.setImageFilter(&color_filter_image_filter);
2401 builder2.DrawRect(rect, paint2);
2402 sk_sp<DisplayList> display_list2 = builder2.Build();
2403 ASSERT_TRUE(DisplayListsEQ_Verbose(display_list1, display_list2));
2404 }
2405
2406 {
2407 DisplayListBuilder builder(build_bounds);
2408 builder.Save();
2409 builder.SaveLayer(&build_bounds);
2410 DlPaint paint;
2411 paint.setImageFilter(&color_filter_image_filter);
2412 builder.DrawRect(rect, paint);
2413 builder.Restore();
2414 builder.Restore();
2415 sk_sp<DisplayList> display_list1 = builder.Build();
2416
2417 DisplayListBuilder builder2(build_bounds);
2418 builder2.SaveLayer(&build_bounds);
2419 DlPaint paint2;
2420 paint2.setImageFilter(&color_filter_image_filter);
2421 builder2.DrawRect(rect, paint2);
2422 builder2.Restore();
2423 sk_sp<DisplayList> display_list2 = builder2.Build();
2424 ASSERT_TRUE(DisplayListsEQ_Verbose(display_list1, display_list2));
2425 }
2426}
2427
2428TEST_F(DisplayListTest, TransformTriggersDeferredSave) {
2429 DisplayListBuilder builder1;
2430 DlOpReceiver& receiver1 = ToReceiver(builder1);
2431 receiver1.save();
2432 receiver1.save();
2433 receiver1.transformFullPerspective(1, 0, 0, 10, //
2434 0, 1, 0, 100, //
2435 0, 0, 1, 0, //
2436 0, 0, 0, 1);
2437 receiver1.drawRect({0, 0, 100, 100});
2438 receiver1.restore();
2439 receiver1.transformFullPerspective(1, 0, 0, 10, //
2440 0, 1, 0, 100, //
2441 0, 0, 1, 0, //
2442 0, 0, 0, 1);
2443 receiver1.drawRect({0, 0, 100, 100});
2444 receiver1.restore();
2445 auto display_list1 = builder1.Build();
2446
2447 DisplayListBuilder builder2;
2448 DlOpReceiver& receiver2 = ToReceiver(builder2);
2449 receiver2.save();
2450 receiver2.transformFullPerspective(1, 0, 0, 10, //
2451 0, 1, 0, 100, //
2452 0, 0, 1, 0, //
2453 0, 0, 0, 1);
2454 receiver2.drawRect({0, 0, 100, 100});
2455 receiver2.restore();
2456 receiver2.save();
2457 receiver2.transformFullPerspective(1, 0, 0, 10, //
2458 0, 1, 0, 100, //
2459 0, 0, 1, 0, //
2460 0, 0, 0, 1);
2461 receiver2.drawRect({0, 0, 100, 100});
2462 receiver2.restore();
2463 auto display_list2 = builder2.Build();
2464
2465 ASSERT_TRUE(DisplayListsEQ_Verbose(display_list1, display_list2));
2466}
2467
2468TEST_F(DisplayListTest, Transform2DTriggersDeferredSave) {
2469 DisplayListBuilder builder1;
2470 DlOpReceiver& receiver1 = ToReceiver(builder1);
2471 receiver1.save();
2472 receiver1.save();
2473 receiver1.transform2DAffine(0, 1, 12, 1, 0, 33);
2474 receiver1.drawRect({0, 0, 100, 100});
2475 receiver1.restore();
2476 receiver1.restore();
2477 auto display_list1 = builder1.Build();
2478
2479 DisplayListBuilder builder2;
2480 DlOpReceiver& receiver2 = ToReceiver(builder2);
2481 receiver2.save();
2482 receiver2.transform2DAffine(0, 1, 12, 1, 0, 33);
2483 receiver2.drawRect({0, 0, 100, 100});
2484 receiver2.restore();
2485 auto display_list2 = builder2.Build();
2486
2487 ASSERT_TRUE(DisplayListsEQ_Verbose(display_list1, display_list2));
2488}
2489
2490TEST_F(DisplayListTest, TransformPerspectiveTriggersDeferredSave) {
2491 DisplayListBuilder builder1;
2492 DlOpReceiver& receiver1 = ToReceiver(builder1);
2493 receiver1.save();
2494 receiver1.save();
2495 receiver1.transformFullPerspective(0, 1, 0, 12, //
2496 1, 0, 0, 33, //
2497 3, 2, 5, 29, //
2498 0, 0, 0, 12);
2499 receiver1.drawRect({0, 0, 100, 100});
2500 receiver1.restore();
2501 receiver1.restore();
2502 auto display_list1 = builder1.Build();
2503
2504 DisplayListBuilder builder2;
2505 DlOpReceiver& receiver2 = ToReceiver(builder2);
2506 receiver2.save();
2507 receiver2.transformFullPerspective(0, 1, 0, 12, //
2508 1, 0, 0, 33, //
2509 3, 2, 5, 29, //
2510 0, 0, 0, 12);
2511 receiver2.drawRect({0, 0, 100, 100});
2512 receiver2.restore();
2513 auto display_list2 = builder2.Build();
2514
2515 ASSERT_TRUE(DisplayListsEQ_Verbose(display_list1, display_list2));
2516}
2517
2518TEST_F(DisplayListTest, ResetTransformTriggersDeferredSave) {
2519 DisplayListBuilder builder1;
2520 DlOpReceiver& receiver1 = ToReceiver(builder1);
2521 receiver1.save();
2522 receiver1.save();
2523 receiver1.transformReset();
2524 receiver1.drawRect({0, 0, 100, 100});
2525 receiver1.restore();
2526 receiver1.restore();
2527 auto display_list1 = builder1.Build();
2528
2529 DisplayListBuilder builder2;
2530 DlOpReceiver& receiver2 = ToReceiver(builder2);
2531 receiver2.save();
2532 receiver2.transformReset();
2533 receiver2.drawRect({0, 0, 100, 100});
2534 receiver2.restore();
2535 auto display_list2 = builder2.Build();
2536
2537 ASSERT_TRUE(DisplayListsEQ_Verbose(display_list1, display_list2));
2538}
2539
2540TEST_F(DisplayListTest, SkewTriggersDeferredSave) {
2541 DisplayListBuilder builder1;
2542 DlOpReceiver& receiver1 = ToReceiver(builder1);
2543 receiver1.save();
2544 receiver1.save();
2545 receiver1.skew(10, 10);
2546 receiver1.drawRect({0, 0, 100, 100});
2547 receiver1.restore();
2548 receiver1.restore();
2549 auto display_list1 = builder1.Build();
2550
2551 DisplayListBuilder builder2;
2552 DlOpReceiver& receiver2 = ToReceiver(builder2);
2553 receiver2.save();
2554 receiver2.skew(10, 10);
2555 receiver2.drawRect({0, 0, 100, 100});
2556 receiver2.restore();
2557 auto display_list2 = builder2.Build();
2558
2559 ASSERT_TRUE(DisplayListsEQ_Verbose(display_list1, display_list2));
2560}
2561
2562TEST_F(DisplayListTest, TranslateTriggersDeferredSave) {
2563 DisplayListBuilder builder1;
2564 DlOpReceiver& receiver1 = ToReceiver(builder1);
2565 receiver1.save();
2566 receiver1.save();
2567 receiver1.translate(10, 10);
2568 receiver1.drawRect({0, 0, 100, 100});
2569 receiver1.restore();
2570 receiver1.restore();
2571 auto display_list1 = builder1.Build();
2572
2573 DisplayListBuilder builder2;
2574 DlOpReceiver& receiver2 = ToReceiver(builder2);
2575 receiver2.save();
2576 receiver2.translate(10, 10);
2577 receiver2.drawRect({0, 0, 100, 100});
2578 receiver2.restore();
2579 auto display_list2 = builder2.Build();
2580
2581 ASSERT_TRUE(DisplayListsEQ_Verbose(display_list1, display_list2));
2582}
2583
2584TEST_F(DisplayListTest, ScaleTriggersDeferredSave) {
2585 DisplayListBuilder builder1;
2586 DlOpReceiver& receiver1 = ToReceiver(builder1);
2587 receiver1.save();
2588 receiver1.save();
2589 receiver1.scale(0.5, 0.5);
2590 receiver1.drawRect({0, 0, 100, 100});
2591 receiver1.restore();
2592 receiver1.restore();
2593 auto display_list1 = builder1.Build();
2594
2595 DisplayListBuilder builder2;
2596 DlOpReceiver& receiver2 = ToReceiver(builder2);
2597 receiver2.save();
2598 receiver2.scale(0.5, 0.5);
2599 receiver2.drawRect({0, 0, 100, 100});
2600 receiver2.restore();
2601 auto display_list2 = builder2.Build();
2602
2603 ASSERT_TRUE(DisplayListsEQ_Verbose(display_list1, display_list2));
2604}
2605
2606TEST_F(DisplayListTest, ClipRectTriggersDeferredSave) {
2607 DisplayListBuilder builder1;
2608 DlOpReceiver& receiver1 = ToReceiver(builder1);
2609 receiver1.save();
2610 receiver1.save();
2611 receiver1.clipRect(SkRect::MakeLTRB(0, 0, 100, 100), ClipOp::kIntersect,
2612 true);
2613 receiver1.drawRect({0, 0, 100, 100});
2614 receiver1.restore();
2615 receiver1.transformFullPerspective(1, 0, 0, 0, //
2616 0, 1, 0, 0, //
2617 0, 0, 1, 0, //
2618 0, 0, 0, 1);
2619 receiver1.drawRect({0, 0, 100, 100});
2620 receiver1.restore();
2621 auto display_list1 = builder1.Build();
2622
2623 DisplayListBuilder builder2;
2624 DlOpReceiver& receiver2 = ToReceiver(builder2);
2625 receiver2.save();
2626 receiver2.clipRect(SkRect::MakeLTRB(0, 0, 100, 100), ClipOp::kIntersect,
2627 true);
2628 receiver2.drawRect({0, 0, 100, 100});
2629 receiver2.restore();
2630 receiver2.transformFullPerspective(1, 0, 0, 0, //
2631 0, 1, 0, 0, //
2632 0, 0, 1, 0, //
2633 0, 0, 0, 1);
2634 receiver2.drawRect({0, 0, 100, 100});
2635 auto display_list2 = builder2.Build();
2636
2637 ASSERT_TRUE(DisplayListsEQ_Verbose(display_list1, display_list2));
2638}
2639
2640TEST_F(DisplayListTest, ClipRRectTriggersDeferredSave) {
2641 DisplayListBuilder builder1;
2642 DlOpReceiver& receiver1 = ToReceiver(builder1);
2643 receiver1.save();
2644 receiver1.save();
2645 receiver1.clipRRect(kTestRRect, ClipOp::kIntersect, true);
2646
2647 receiver1.drawRect({0, 0, 100, 100});
2648 receiver1.restore();
2649 receiver1.transformFullPerspective(1, 0, 0, 0, //
2650 0, 1, 0, 0, //
2651 0, 0, 1, 0, //
2652 0, 0, 0, 1);
2653 receiver1.drawRect({0, 0, 100, 100});
2654 receiver1.restore();
2655 auto display_list1 = builder1.Build();
2656
2657 DisplayListBuilder builder2;
2658 DlOpReceiver& receiver2 = ToReceiver(builder2);
2659 receiver2.save();
2660 receiver2.clipRRect(kTestRRect, ClipOp::kIntersect, true);
2661
2662 receiver2.drawRect({0, 0, 100, 100});
2663 receiver2.restore();
2664 receiver2.transformFullPerspective(1, 0, 0, 0, //
2665 0, 1, 0, 0, //
2666 0, 0, 1, 0, //
2667 0, 0, 0, 1);
2668 receiver2.drawRect({0, 0, 100, 100});
2669 auto display_list2 = builder2.Build();
2670
2671 ASSERT_TRUE(DisplayListsEQ_Verbose(display_list1, display_list2));
2672}
2673
2674TEST_F(DisplayListTest, ClipPathTriggersDeferredSave) {
2675 DisplayListBuilder builder1;
2676 DlOpReceiver& receiver1 = ToReceiver(builder1);
2677 receiver1.save();
2678 receiver1.save();
2679 receiver1.clipPath(kTestPath1, ClipOp::kIntersect, true);
2680 receiver1.drawRect({0, 0, 100, 100});
2681 receiver1.restore();
2682 receiver1.transformFullPerspective(1, 0, 0, 0, //
2683 0, 1, 0, 0, //
2684 0, 0, 1, 0, //
2685 0, 0, 0, 1);
2686 receiver1.drawRect({0, 0, 100, 100});
2687 receiver1.restore();
2688 auto display_list1 = builder1.Build();
2689
2690 DisplayListBuilder builder2;
2691 DlOpReceiver& receiver2 = ToReceiver(builder2);
2692 receiver2.save();
2693 receiver2.clipPath(kTestPath1, ClipOp::kIntersect, true);
2694 receiver2.drawRect({0, 0, 100, 100});
2695 receiver2.restore();
2696 receiver2.transformFullPerspective(1, 0, 0, 0, //
2697 0, 1, 0, 0, //
2698 0, 0, 1, 0, //
2699 0, 0, 0, 1);
2700 receiver2.drawRect({0, 0, 100, 100});
2701 auto display_list2 = builder2.Build();
2702
2703 ASSERT_TRUE(DisplayListsEQ_Verbose(display_list1, display_list2));
2704}
2705
2706TEST_F(DisplayListTest, NOPTranslateDoesNotTriggerDeferredSave) {
2707 DisplayListBuilder builder1;
2708 DlOpReceiver& receiver1 = ToReceiver(builder1);
2709 receiver1.save();
2710 receiver1.save();
2711 receiver1.translate(0, 0);
2712 receiver1.drawRect({0, 0, 100, 100});
2713 receiver1.restore();
2714 receiver1.drawRect({0, 0, 100, 100});
2715 receiver1.restore();
2716 auto display_list1 = builder1.Build();
2717
2718 DisplayListBuilder builder2;
2719 DlOpReceiver& receiver2 = ToReceiver(builder2);
2720 receiver2.drawRect({0, 0, 100, 100});
2721 receiver2.drawRect({0, 0, 100, 100});
2722 auto display_list2 = builder2.Build();
2723
2724 ASSERT_TRUE(DisplayListsEQ_Verbose(display_list1, display_list2));
2725}
2726
2727TEST_F(DisplayListTest, NOPScaleDoesNotTriggerDeferredSave) {
2728 DisplayListBuilder builder1;
2729 DlOpReceiver& receiver1 = ToReceiver(builder1);
2730 receiver1.save();
2731 receiver1.save();
2732 receiver1.scale(1.0, 1.0);
2733 receiver1.drawRect({0, 0, 100, 100});
2734 receiver1.restore();
2735 receiver1.drawRect({0, 0, 100, 100});
2736 receiver1.restore();
2737 auto display_list1 = builder1.Build();
2738
2739 DisplayListBuilder builder2;
2740 DlOpReceiver& receiver2 = ToReceiver(builder2);
2741 receiver2.drawRect({0, 0, 100, 100});
2742 receiver2.drawRect({0, 0, 100, 100});
2743 auto display_list2 = builder2.Build();
2744
2745 ASSERT_TRUE(DisplayListsEQ_Verbose(display_list1, display_list2));
2746}
2747
2748TEST_F(DisplayListTest, NOPRotationDoesNotTriggerDeferredSave) {
2749 DisplayListBuilder builder1;
2750 DlOpReceiver& receiver1 = ToReceiver(builder1);
2751 receiver1.save();
2752 receiver1.save();
2753 receiver1.rotate(360);
2754 receiver1.drawRect({0, 0, 100, 100});
2755 receiver1.restore();
2756 receiver1.drawRect({0, 0, 100, 100});
2757 receiver1.restore();
2758 auto display_list1 = builder1.Build();
2759
2760 DisplayListBuilder builder2;
2761 DlOpReceiver& receiver2 = ToReceiver(builder2);
2762 receiver2.drawRect({0, 0, 100, 100});
2763 receiver2.drawRect({0, 0, 100, 100});
2764 auto display_list2 = builder2.Build();
2765
2766 ASSERT_TRUE(DisplayListsEQ_Verbose(display_list1, display_list2));
2767}
2768
2769TEST_F(DisplayListTest, NOPSkewDoesNotTriggerDeferredSave) {
2770 DisplayListBuilder builder1;
2771 DlOpReceiver& receiver1 = ToReceiver(builder1);
2772 receiver1.save();
2773 receiver1.save();
2774 receiver1.skew(0, 0);
2775 receiver1.drawRect({0, 0, 100, 100});
2776 receiver1.restore();
2777 receiver1.drawRect({0, 0, 100, 100});
2778 receiver1.restore();
2779 auto display_list1 = builder1.Build();
2780
2781 DisplayListBuilder builder2;
2782 DlOpReceiver& receiver2 = ToReceiver(builder2);
2783 receiver2.drawRect({0, 0, 100, 100});
2784 receiver2.drawRect({0, 0, 100, 100});
2785 auto display_list2 = builder2.Build();
2786
2787 ASSERT_TRUE(DisplayListsEQ_Verbose(display_list1, display_list2));
2788}
2789
2790TEST_F(DisplayListTest, NOPTransformDoesNotTriggerDeferredSave) {
2791 DisplayListBuilder builder1;
2792 DlOpReceiver& receiver1 = ToReceiver(builder1);
2793 receiver1.save();
2794 receiver1.save();
2795 receiver1.transformFullPerspective(1, 0, 0, 0, //
2796 0, 1, 0, 0, //
2797 0, 0, 1, 0, //
2798 0, 0, 0, 1);
2799 receiver1.drawRect({0, 0, 100, 100});
2800 receiver1.restore();
2801 receiver1.transformFullPerspective(1, 0, 0, 0, //
2802 0, 1, 0, 0, //
2803 0, 0, 1, 0, //
2804 0, 0, 0, 1);
2805 receiver1.drawRect({0, 0, 100, 100});
2806 receiver1.restore();
2807 auto display_list1 = builder1.Build();
2808
2809 DisplayListBuilder builder2;
2810 DlOpReceiver& receiver2 = ToReceiver(builder2);
2811 receiver2.drawRect({0, 0, 100, 100});
2812 receiver2.drawRect({0, 0, 100, 100});
2813 auto display_list2 = builder2.Build();
2814
2815 ASSERT_TRUE(DisplayListsEQ_Verbose(display_list1, display_list2));
2816}
2817
2818TEST_F(DisplayListTest, NOPTransform2DDoesNotTriggerDeferredSave) {
2819 DisplayListBuilder builder1;
2820 DlOpReceiver& receiver1 = ToReceiver(builder1);
2821 receiver1.save();
2822 receiver1.save();
2823 receiver1.transform2DAffine(1, 0, 0, 0, 1, 0);
2824 receiver1.drawRect({0, 0, 100, 100});
2825 receiver1.restore();
2826 receiver1.drawRect({0, 0, 100, 100});
2827 receiver1.restore();
2828 auto display_list1 = builder1.Build();
2829
2830 DisplayListBuilder builder2;
2831 DlOpReceiver& receiver2 = ToReceiver(builder2);
2832 receiver2.drawRect({0, 0, 100, 100});
2833 receiver2.drawRect({0, 0, 100, 100});
2834 auto display_list2 = builder2.Build();
2835
2836 ASSERT_TRUE(DisplayListsEQ_Verbose(display_list1, display_list2));
2837}
2838
2839TEST_F(DisplayListTest, NOPTransformFullPerspectiveDoesNotTriggerDeferredSave) {
2840 {
2841 DisplayListBuilder builder1;
2842 DlOpReceiver& receiver1 = ToReceiver(builder1);
2843 receiver1.save();
2844 receiver1.save();
2845 receiver1.transformFullPerspective(1, 0, 0, 0, //
2846 0, 1, 0, 0, //
2847 0, 0, 1, 0, //
2848 0, 0, 0, 1);
2849 receiver1.drawRect({0, 0, 100, 100});
2850 receiver1.restore();
2851 receiver1.drawRect({0, 0, 100, 100});
2852 receiver1.restore();
2853 auto display_list1 = builder1.Build();
2854
2855 DisplayListBuilder builder2;
2856 DlOpReceiver& receiver2 = ToReceiver(builder2);
2857 receiver2.drawRect({0, 0, 100, 100});
2858 receiver2.drawRect({0, 0, 100, 100});
2859 auto display_list2 = builder2.Build();
2860
2861 ASSERT_TRUE(DisplayListsEQ_Verbose(display_list1, display_list2));
2862 }
2863
2864 {
2865 DisplayListBuilder builder1;
2866 DlOpReceiver& receiver1 = ToReceiver(builder1);
2867 receiver1.save();
2868 receiver1.save();
2869 receiver1.transformFullPerspective(1, 0, 0, 0, //
2870 0, 1, 0, 0, //
2871 0, 0, 1, 0, //
2872 0, 0, 0, 1);
2873 receiver1.transformReset();
2874 receiver1.drawRect({0, 0, 100, 100});
2875 receiver1.restore();
2876 receiver1.drawRect({0, 0, 100, 100});
2877 receiver1.restore();
2878 auto display_list1 = builder1.Build();
2879
2880 DisplayListBuilder builder2;
2881 DlOpReceiver& receiver2 = ToReceiver(builder2);
2882 receiver2.save();
2883 receiver2.transformReset();
2884 receiver2.drawRect({0, 0, 100, 100});
2885 receiver2.restore();
2886 receiver2.drawRect({0, 0, 100, 100});
2887
2888 auto display_list2 = builder2.Build();
2889
2890 ASSERT_TRUE(DisplayListsEQ_Verbose(display_list1, display_list2));
2891 }
2892}
2893
2894TEST_F(DisplayListTest, NOPClipDoesNotTriggerDeferredSave) {
2895 DisplayListBuilder builder1;
2896 DlOpReceiver& receiver1 = ToReceiver(builder1);
2897 receiver1.save();
2898 receiver1.save();
2900 ClipOp::kIntersect, true);
2901 receiver1.drawRect({0, 0, 100, 100});
2902 receiver1.restore();
2903 receiver1.drawRect({0, 0, 100, 100});
2904 receiver1.restore();
2905 auto display_list1 = builder1.Build();
2906
2907 DisplayListBuilder builder2;
2908 DlOpReceiver& receiver2 = ToReceiver(builder2);
2909 receiver2.drawRect({0, 0, 100, 100});
2910 receiver2.drawRect({0, 0, 100, 100});
2911 auto display_list2 = builder2.Build();
2912
2913 ASSERT_TRUE(DisplayListsEQ_Verbose(display_list1, display_list2));
2914}
2915
2916TEST_F(DisplayListTest, RTreeOfClippedSaveLayerFilterScene) {
2917 DisplayListBuilder builder(/*prepare_rtree=*/true);
2918 // blur filter with sigma=1 expands by 30 on all sides
2919 auto filter = DlBlurImageFilter(10.0, 10.0, DlTileMode::kClamp);
2920 DlPaint default_paint = DlPaint();
2921 DlPaint filter_paint = DlPaint().setImageFilter(&filter);
2922 builder.DrawRect({10, 10, 20, 20}, default_paint);
2923 builder.ClipRect({50, 50, 60, 60}, ClipOp::kIntersect, false);
2924 builder.SaveLayer(nullptr, &filter_paint);
2925 // the following rectangle will be expanded to 23,23,87,87
2926 // by the saveLayer filter during the restore operation
2927 // but it will then be clipped to 50,50,60,60
2928 builder.DrawRect({53, 53, 57, 57}, default_paint);
2929 builder.Restore();
2930 auto display_list = builder.Build();
2931 auto rtree = display_list->rtree();
2932 std::vector<SkRect> rects = {
2933 {10, 10, 20, 20},
2934 {50, 50, 60, 60},
2935 };
2936
2937 // Missing all drawRect calls
2938 test_rtree(rtree, {5, 5, 10, 10}, rects, {});
2939 test_rtree(rtree, {20, 20, 25, 25}, rects, {});
2940 test_rtree(rtree, {45, 45, 50, 50}, rects, {});
2941 test_rtree(rtree, {60, 60, 65, 65}, rects, {});
2942
2943 // Hitting just 1 of the drawRects
2944 test_rtree(rtree, {5, 5, 11, 11}, rects, {0});
2945 test_rtree(rtree, {19, 19, 25, 25}, rects, {0});
2946 test_rtree(rtree, {45, 45, 51, 51}, rects, {1});
2947 test_rtree(rtree, {59, 59, 65, 65}, rects, {1});
2948
2949 // Hitting both drawRect calls
2950 test_rtree(rtree, {19, 19, 51, 51}, rects, {0, 1});
2951}
2952
2953TEST_F(DisplayListTest, RTreeRenderCulling) {
2954 DisplayListBuilder main_builder(true);
2955 DlOpReceiver& main_receiver = ToReceiver(main_builder);
2956 main_receiver.drawRect({0, 0, 10, 10});
2957 main_receiver.drawRect({20, 0, 30, 10});
2958 main_receiver.drawRect({0, 20, 10, 30});
2959 main_receiver.drawRect({20, 20, 30, 30});
2960 auto main = main_builder.Build();
2961
2962 auto test = [main](SkIRect cull_rect, const sk_sp<DisplayList>& expected) {
2963 { // Test SkIRect culling
2964 DisplayListBuilder culling_builder;
2965 main->Dispatch(ToReceiver(culling_builder), cull_rect);
2966
2967 EXPECT_TRUE(DisplayListsEQ_Verbose(culling_builder.Build(), expected));
2968 }
2969
2970 { // Test SkRect culling
2971 DisplayListBuilder culling_builder;
2972 main->Dispatch(ToReceiver(culling_builder), SkRect::Make(cull_rect));
2973
2974 EXPECT_TRUE(DisplayListsEQ_Verbose(culling_builder.Build(), expected));
2975 }
2976 };
2977
2978 { // No rects
2979 SkIRect cull_rect = {11, 11, 19, 19};
2980
2981 DisplayListBuilder expected_builder;
2982 auto expected = expected_builder.Build();
2983
2984 test(cull_rect, expected);
2985 }
2986
2987 { // Rect 1
2988 SkIRect cull_rect = {9, 9, 19, 19};
2989
2990 DisplayListBuilder expected_builder;
2991 DlOpReceiver& expected_receiver = ToReceiver(expected_builder);
2992 expected_receiver.drawRect({0, 0, 10, 10});
2993 auto expected = expected_builder.Build();
2994
2995 test(cull_rect, expected);
2996 }
2997
2998 { // Rect 2
2999 SkIRect cull_rect = {11, 9, 21, 19};
3000
3001 DisplayListBuilder expected_builder;
3002 DlOpReceiver& expected_receiver = ToReceiver(expected_builder);
3003 expected_receiver.drawRect({20, 0, 30, 10});
3004 auto expected = expected_builder.Build();
3005
3006 test(cull_rect, expected);
3007 }
3008
3009 { // Rect 3
3010 SkIRect cull_rect = {9, 11, 19, 21};
3011
3012 DisplayListBuilder expected_builder;
3013 DlOpReceiver& expected_receiver = ToReceiver(expected_builder);
3014 expected_receiver.drawRect({0, 20, 10, 30});
3015 auto expected = expected_builder.Build();
3016
3017 test(cull_rect, expected);
3018 }
3019
3020 { // Rect 4
3021 SkIRect cull_rect = {11, 11, 21, 21};
3022
3023 DisplayListBuilder expected_builder;
3024 DlOpReceiver& expected_receiver = ToReceiver(expected_builder);
3025 expected_receiver.drawRect({20, 20, 30, 30});
3026 auto expected = expected_builder.Build();
3027
3028 test(cull_rect, expected);
3029 }
3030
3031 { // All 4 rects
3032 SkIRect cull_rect = {9, 9, 21, 21};
3033
3034 test(cull_rect, main);
3035 }
3036}
3037
3038TEST_F(DisplayListTest, DrawSaveDrawCannotInheritOpacity) {
3039 DisplayListBuilder builder;
3040 builder.DrawCircle({10, 10}, 5, DlPaint());
3041 builder.Save();
3042 builder.ClipRect({0, 0, 20, 20}, DlCanvas::ClipOp::kIntersect, false);
3043 builder.DrawRect({5, 5, 15, 15}, DlPaint());
3044 builder.Restore();
3045 auto display_list = builder.Build();
3046
3047 ASSERT_FALSE(display_list->can_apply_group_opacity());
3048}
3049
3050TEST_F(DisplayListTest, DrawUnorderedRect) {
3051 auto renderer = [](DlCanvas& canvas, DlPaint& paint, SkRect& rect) {
3052 canvas.DrawRect(rect, paint);
3053 };
3054 check_inverted_bounds(renderer, "DrawRect");
3055}
3056
3057TEST_F(DisplayListTest, DrawUnorderedRoundRect) {
3058 auto renderer = [](DlCanvas& canvas, DlPaint& paint, SkRect& rect) {
3059 canvas.DrawRRect(SkRRect::MakeRectXY(rect, 2.0f, 2.0f), paint);
3060 };
3061 check_inverted_bounds(renderer, "DrawRoundRect");
3062}
3063
3064TEST_F(DisplayListTest, DrawUnorderedOval) {
3065 auto renderer = [](DlCanvas& canvas, DlPaint& paint, SkRect& rect) {
3066 canvas.DrawOval(rect, paint);
3067 };
3068 check_inverted_bounds(renderer, "DrawOval");
3069}
3070
3071TEST_F(DisplayListTest, DrawUnorderedRectangularPath) {
3072 auto renderer = [](DlCanvas& canvas, DlPaint& paint, SkRect& rect) {
3073 canvas.DrawPath(SkPath().addRect(rect), paint);
3074 };
3075 check_inverted_bounds(renderer, "DrawRectangularPath");
3076}
3077
3078TEST_F(DisplayListTest, DrawUnorderedOvalPath) {
3079 auto renderer = [](DlCanvas& canvas, DlPaint& paint, SkRect& rect) {
3080 canvas.DrawPath(SkPath().addOval(rect), paint);
3081 };
3082 check_inverted_bounds(renderer, "DrawOvalPath");
3083}
3084
3085TEST_F(DisplayListTest, DrawUnorderedRoundRectPathCW) {
3086 auto renderer = [](DlCanvas& canvas, DlPaint& paint, SkRect& rect) {
3087 SkPath path = SkPath() //
3088 .addRoundRect(rect, 2.0f, 2.0f, SkPathDirection::kCW);
3089 canvas.DrawPath(path, paint);
3090 };
3091 check_inverted_bounds(renderer, "DrawRoundRectPath Clockwise");
3092}
3093
3094TEST_F(DisplayListTest, DrawUnorderedRoundRectPathCCW) {
3095 auto renderer = [](DlCanvas& canvas, DlPaint& paint, SkRect& rect) {
3096 SkPath path = SkPath() //
3097 .addRoundRect(rect, 2.0f, 2.0f, SkPathDirection::kCCW);
3098 canvas.DrawPath(path, paint);
3099 };
3100 check_inverted_bounds(renderer, "DrawRoundRectPath Counter-Clockwise");
3101}
3102
3103TEST_F(DisplayListTest, NopOperationsOmittedFromRecords) {
3104 auto run_tests = [](const std::string& name,
3105 void init(DisplayListBuilder & builder, DlPaint & paint),
3106 uint32_t expected_op_count = 0u,
3107 uint32_t expected_total_depth = 0u) {
3108 auto run_one_test =
3109 [init](const std::string& name,
3110 void build(DisplayListBuilder & builder, DlPaint & paint),
3111 uint32_t expected_op_count = 0u,
3112 uint32_t expected_total_depth = 0u) {
3113 DisplayListBuilder builder;
3114 DlPaint paint;
3115 init(builder, paint);
3116 build(builder, paint);
3117 auto list = builder.Build();
3118 if (list->op_count() != expected_op_count) {
3119 FML_LOG(ERROR) << *list;
3120 }
3121 ASSERT_EQ(list->op_count(), expected_op_count) << name;
3122 EXPECT_EQ(list->total_depth(), expected_total_depth) << name;
3123 ASSERT_TRUE(list->bounds().isEmpty()) << name;
3124 };
3125 run_one_test(
3126 name + " DrawColor",
3127 [](DisplayListBuilder& builder, DlPaint& paint) {
3128 builder.DrawColor(paint.getColor(), paint.getBlendMode());
3129 },
3130 expected_op_count, expected_total_depth);
3131 run_one_test(
3132 name + " DrawPaint",
3133 [](DisplayListBuilder& builder, DlPaint& paint) {
3134 builder.DrawPaint(paint);
3135 },
3136 expected_op_count, expected_total_depth);
3137 run_one_test(
3138 name + " DrawRect",
3139 [](DisplayListBuilder& builder, DlPaint& paint) {
3140 builder.DrawRect({10, 10, 20, 20}, paint);
3141 },
3142 expected_op_count, expected_total_depth);
3143 run_one_test(
3144 name + " Other Draw Ops",
3145 [](DisplayListBuilder& builder, DlPaint& paint) {
3146 builder.DrawLine({10, 10}, {20, 20}, paint);
3147 builder.DrawOval({10, 10, 20, 20}, paint);
3148 builder.DrawCircle({50, 50}, 20, paint);
3149 builder.DrawRRect(SkRRect::MakeRectXY({10, 10, 20, 20}, 5, 5), paint);
3150 builder.DrawDRRect(SkRRect::MakeRectXY({5, 5, 100, 100}, 5, 5),
3151 SkRRect::MakeRectXY({10, 10, 20, 20}, 5, 5),
3152 paint);
3153 builder.DrawPath(kTestPath1, paint);
3154 builder.DrawArc({10, 10, 20, 20}, 45, 90, true, paint);
3155 SkPoint pts[] = {{10, 10}, {20, 20}};
3156 builder.DrawPoints(PointMode::kLines, 2, pts, paint);
3157 builder.DrawVertices(TestVertices1, DlBlendMode::kSrcOver, paint);
3158 builder.DrawImage(TestImage1, {10, 10}, DlImageSampling::kLinear,
3159 &paint);
3160 builder.DrawImageRect(TestImage1, SkRect{0.0f, 0.0f, 10.0f, 10.0f},
3161 SkRect{10.0f, 10.0f, 25.0f, 25.0f},
3163 builder.DrawImageNine(TestImage1, {10, 10, 20, 20},
3164 {10, 10, 100, 100}, DlFilterMode::kLinear,
3165 &paint);
3166 SkRSXform xforms[] = {{1, 0, 10, 10}, {0, 1, 10, 10}};
3167 SkRect rects[] = {{10, 10, 20, 20}, {10, 20, 30, 20}};
3168 builder.DrawAtlas(TestImage1, xforms, rects, nullptr, 2,
3170 nullptr, &paint);
3171 builder.DrawTextBlob(GetTestTextBlob(1), 10, 10, paint);
3172
3173 // Dst mode eliminates most rendering ops except for
3174 // the following two, so we'll prune those manually...
3175 if (paint.getBlendMode() != DlBlendMode::kDst) {
3176 builder.DrawDisplayList(TestDisplayList1, paint.getOpacity());
3177 builder.DrawShadow(kTestPath1, paint.getColor(), 1, true, 1);
3178 }
3179 },
3180 expected_op_count, expected_total_depth);
3181 run_one_test(
3182 name + " SaveLayer",
3183 [](DisplayListBuilder& builder, DlPaint& paint) {
3184 builder.SaveLayer(nullptr, &paint, nullptr);
3185 builder.DrawRect({10, 10, 20, 20}, DlPaint());
3186 builder.Restore();
3187 },
3188 expected_op_count, expected_total_depth);
3189 run_one_test(
3190 name + " inside Save",
3191 [](DisplayListBuilder& builder, DlPaint& paint) {
3192 builder.Save();
3193 builder.DrawRect({10, 10, 20, 20}, paint);
3194 builder.Restore();
3195 },
3196 expected_op_count, expected_total_depth);
3197 };
3198 run_tests("transparent color", //
3199 [](DisplayListBuilder& builder, DlPaint& paint) {
3200 paint.setColor(DlColor::kTransparent());
3201 });
3202 run_tests("0 alpha", //
3203 [](DisplayListBuilder& builder, DlPaint& paint) {
3204 // The transparent test above already tested transparent
3205 // black (all 0s), we set White color here so we can test
3206 // the case of all 1s with a 0 alpha
3207 paint.setColor(DlColor::kWhite());
3208 paint.setAlpha(0);
3209 });
3210 run_tests("BlendMode::kDst", //
3211 [](DisplayListBuilder& builder, DlPaint& paint) {
3212 paint.setBlendMode(DlBlendMode::kDst);
3213 });
3214 run_tests("Empty rect clip", //
3215 [](DisplayListBuilder& builder, DlPaint& paint) {
3216 builder.ClipRect(SkRect::MakeEmpty(), ClipOp::kIntersect, false);
3217 });
3218 run_tests("Empty rrect clip", //
3219 [](DisplayListBuilder& builder, DlPaint& paint) {
3220 builder.ClipRRect(SkRRect::MakeEmpty(), ClipOp::kIntersect,
3221 false);
3222 });
3223 run_tests("Empty path clip", //
3224 [](DisplayListBuilder& builder, DlPaint& paint) {
3225 builder.ClipPath(SkPath(), ClipOp::kIntersect, false);
3226 });
3227 run_tests("Transparent SaveLayer", //
3228 [](DisplayListBuilder& builder, DlPaint& paint) {
3229 DlPaint save_paint;
3230 save_paint.setColor(DlColor::kTransparent());
3231 builder.SaveLayer(nullptr, &save_paint);
3232 });
3233 run_tests("0 alpha SaveLayer", //
3234 [](DisplayListBuilder& builder, DlPaint& paint) {
3235 DlPaint save_paint;
3236 // The transparent test above already tested transparent
3237 // black (all 0s), we set White color here so we can test
3238 // the case of all 1s with a 0 alpha
3239 save_paint.setColor(DlColor::kWhite());
3240 save_paint.setAlpha(0);
3241 builder.SaveLayer(nullptr, &save_paint);
3242 });
3243 run_tests("Dst blended SaveLayer", //
3244 [](DisplayListBuilder& builder, DlPaint& paint) {
3245 DlPaint save_paint;
3246 save_paint.setBlendMode(DlBlendMode::kDst);
3247 builder.SaveLayer(nullptr, &save_paint);
3248 });
3249 run_tests(
3250 "Nop inside SaveLayer",
3251 [](DisplayListBuilder& builder, DlPaint& paint) {
3252 builder.SaveLayer(nullptr, nullptr);
3253 paint.setBlendMode(DlBlendMode::kDst);
3254 },
3255 2u, 1u);
3256 run_tests("DrawImage inside Culled SaveLayer", //
3257 [](DisplayListBuilder& builder, DlPaint& paint) {
3258 DlPaint save_paint;
3259 save_paint.setColor(DlColor::kTransparent());
3260 builder.SaveLayer(nullptr, &save_paint);
3261 builder.DrawImage(TestImage1, {10, 10}, DlImageSampling::kLinear);
3262 });
3263}
3264
3265TEST_F(DisplayListTest, ImpellerPathPreferenceIsHonored) {
3266 class Tester : virtual public DlOpReceiver,
3271 public:
3272 explicit Tester(bool prefer_impeller_paths)
3273 : prefer_impeller_paths_(prefer_impeller_paths) {}
3274
3275 bool PrefersImpellerPaths() const override {
3276 return prefer_impeller_paths_;
3277 }
3278
3279 void drawPath(const SkPath& path) override { skia_draw_path_calls_++; }
3280
3281 void drawPath(const CacheablePath& cache) override {
3282 impeller_draw_path_calls_++;
3283 }
3284
3285 void clipPath(const SkPath& path, ClipOp op, bool is_aa) override {
3286 skia_clip_path_calls_++;
3287 }
3288
3289 void clipPath(const CacheablePath& cache, ClipOp op, bool is_aa) override {
3290 impeller_clip_path_calls_++;
3291 }
3292
3293 virtual void drawShadow(const SkPath& sk_path,
3294 const DlColor color,
3295 const SkScalar elevation,
3296 bool transparent_occluder,
3297 SkScalar dpr) override {
3298 skia_draw_shadow_calls_++;
3299 }
3300
3301 virtual void drawShadow(const CacheablePath& cache,
3302 const DlColor color,
3303 const SkScalar elevation,
3304 bool transparent_occluder,
3305 SkScalar dpr) override {
3306 impeller_draw_shadow_calls_++;
3307 }
3308
3309 int skia_draw_path_calls() const { return skia_draw_path_calls_; }
3310 int skia_clip_path_calls() const { return skia_draw_path_calls_; }
3311 int skia_draw_shadow_calls() const { return skia_draw_path_calls_; }
3312 int impeller_draw_path_calls() const { return impeller_draw_path_calls_; }
3313 int impeller_clip_path_calls() const { return impeller_draw_path_calls_; }
3314 int impeller_draw_shadow_calls() const { return impeller_draw_path_calls_; }
3315
3316 private:
3317 const bool prefer_impeller_paths_;
3318 int skia_draw_path_calls_ = 0;
3319 int skia_clip_path_calls_ = 0;
3320 int skia_draw_shadow_calls_ = 0;
3321 int impeller_draw_path_calls_ = 0;
3322 int impeller_clip_path_calls_ = 0;
3323 int impeller_draw_shadow_calls_ = 0;
3324 };
3325
3326 DisplayListBuilder builder;
3327 builder.DrawPath(SkPath::Rect(SkRect::MakeLTRB(0, 0, 100, 100)), DlPaint());
3328 builder.ClipPath(SkPath::Rect(SkRect::MakeLTRB(0, 0, 100, 100)),
3329 ClipOp::kIntersect, true);
3330 builder.DrawShadow(SkPath::Rect(SkRect::MakeLTRB(20, 20, 80, 80)),
3331 DlColor::kBlue(), 1.0f, true, 1.0f);
3332 auto display_list = builder.Build();
3333
3334 {
3335 Tester skia_tester(false);
3336 display_list->Dispatch(skia_tester);
3337 EXPECT_EQ(skia_tester.skia_draw_path_calls(), 1);
3338 EXPECT_EQ(skia_tester.skia_clip_path_calls(), 1);
3339 EXPECT_EQ(skia_tester.skia_draw_shadow_calls(), 1);
3340 EXPECT_EQ(skia_tester.impeller_draw_path_calls(), 0);
3341 EXPECT_EQ(skia_tester.impeller_clip_path_calls(), 0);
3342 EXPECT_EQ(skia_tester.impeller_draw_shadow_calls(), 0);
3343 }
3344
3345 {
3346 Tester impeller_tester(true);
3347 display_list->Dispatch(impeller_tester);
3348 EXPECT_EQ(impeller_tester.skia_draw_path_calls(), 0);
3349 EXPECT_EQ(impeller_tester.skia_clip_path_calls(), 0);
3350 EXPECT_EQ(impeller_tester.skia_draw_shadow_calls(), 0);
3351 EXPECT_EQ(impeller_tester.impeller_draw_path_calls(), 1);
3352 EXPECT_EQ(impeller_tester.impeller_clip_path_calls(), 1);
3353 EXPECT_EQ(impeller_tester.impeller_draw_shadow_calls(), 1);
3354 }
3355}
3356
3362 public:
3364
3366 expected_.emplace_back(BoundsExpectation{
3367 .bounds = bounds,
3368 .options = SaveLayerOptions(),
3369 });
3370 return *this;
3371 }
3372
3374 bool clipped = false) {
3377 if (clipped) {
3379 }
3380 expected_.emplace_back(BoundsExpectation{
3381 .bounds = bounds,
3382 .options = options,
3383 });
3384 return *this;
3385 }
3386
3387 void saveLayer(const SkRect& bounds,
3389 const DlImageFilter* backdrop) override {
3390 ASSERT_LT(save_layer_count_, expected_.size());
3391 auto expected = expected_[save_layer_count_];
3392 EXPECT_EQ(options.bounds_from_caller(),
3393 expected.options.bounds_from_caller())
3394 << "expected bounds index " << save_layer_count_;
3395 EXPECT_EQ(options.content_is_clipped(),
3396 expected.options.content_is_clipped())
3397 << "expected bounds index " << save_layer_count_;
3398 if (!SkScalarNearlyEqual(bounds.fLeft, expected.bounds.fLeft) ||
3399 !SkScalarNearlyEqual(bounds.fTop, expected.bounds.fTop) ||
3400 !SkScalarNearlyEqual(bounds.fRight, expected.bounds.fRight) ||
3401 !SkScalarNearlyEqual(bounds.fBottom, expected.bounds.fBottom)) {
3402 EXPECT_EQ(bounds, expected.bounds)
3403 << "expected bounds index " << save_layer_count_;
3404 }
3405 save_layer_count_++;
3406 }
3407
3408 bool all_bounds_checked() const {
3409 return save_layer_count_ == expected_.size();
3410 }
3411
3412 private:
3413 struct BoundsExpectation {
3414 const SkRect bounds;
3415 const SaveLayerOptions options;
3416 };
3417
3418 std::vector<BoundsExpectation> expected_;
3419 size_t save_layer_count_ = 0;
3420};
3421
3422TEST_F(DisplayListTest, SaveLayerBoundsComputationOfSimpleRect) {
3423 SkRect rect = SkRect::MakeLTRB(100.0f, 100.0f, 200.0f, 200.0f);
3424
3425 DisplayListBuilder builder;
3426 builder.SaveLayer(nullptr, nullptr);
3427 { //
3428 builder.DrawRect(rect, DlPaint());
3429 }
3430 builder.Restore();
3431 auto display_list = builder.Build();
3432
3433 SaveLayerBoundsExpector expector;
3434 expector.addComputedExpectation(rect);
3435 display_list->Dispatch(expector);
3436 EXPECT_TRUE(expector.all_bounds_checked());
3437}
3438
3439TEST_F(DisplayListTest, SaveLayerBoundsComputationOfMaskBlurredRect) {
3440 SkRect rect = SkRect::MakeLTRB(100.0f, 100.0f, 200.0f, 200.0f);
3442 auto mask_filter = DlBlurMaskFilter::Make(DlBlurStyle::kNormal, 2.0f);
3443 draw_paint.setMaskFilter(mask_filter);
3444
3445 DisplayListBuilder builder;
3446 builder.SaveLayer(nullptr, nullptr);
3447 { //
3448 builder.DrawRect(rect, draw_paint);
3449 }
3450 builder.Restore();
3451 auto display_list = builder.Build();
3452
3453 SaveLayerBoundsExpector expector;
3454 expector.addComputedExpectation(rect.makeOutset(6.0f, 6.0f));
3455 display_list->Dispatch(expector);
3456 EXPECT_TRUE(expector.all_bounds_checked());
3457}
3458
3459TEST_F(DisplayListTest, SaveLayerBoundsComputationOfImageBlurredRect) {
3460 SkRect rect = SkRect::MakeLTRB(100.0f, 100.0f, 200.0f, 200.0f);
3462 auto image_filter = DlBlurImageFilter::Make(2.0f, 3.0f, DlTileMode::kDecal);
3463 draw_paint.setImageFilter(image_filter);
3464
3465 DisplayListBuilder builder;
3466 builder.SaveLayer(nullptr, nullptr);
3467 { //
3468 builder.DrawRect(rect, draw_paint);
3469 }
3470 builder.Restore();
3471 auto display_list = builder.Build();
3472
3473 SaveLayerBoundsExpector expector;
3474 expector.addComputedExpectation(rect.makeOutset(6.0f, 9.0f));
3475 display_list->Dispatch(expector);
3476 EXPECT_TRUE(expector.all_bounds_checked());
3477}
3478
3479TEST_F(DisplayListTest, SaveLayerBoundsComputationOfStrokedRect) {
3480 SkRect rect = SkRect::MakeLTRB(100.0f, 100.0f, 200.0f, 200.0f);
3484
3485 DisplayListBuilder builder;
3486 builder.SaveLayer(nullptr, nullptr);
3487 { //
3488 builder.DrawRect(rect, draw_paint);
3489 }
3490 builder.Restore();
3491 auto display_list = builder.Build();
3492
3493 SaveLayerBoundsExpector expector;
3494 expector.addComputedExpectation(rect.makeOutset(2.5f, 2.5f));
3495 display_list->Dispatch(expector);
3496 EXPECT_TRUE(expector.all_bounds_checked());
3497}
3498
3499TEST_F(DisplayListTest, TranslatedSaveLayerBoundsComputationOfSimpleRect) {
3500 SkRect rect = SkRect::MakeLTRB(100.0f, 100.0f, 200.0f, 200.0f);
3501
3502 DisplayListBuilder builder;
3503 builder.Translate(10.0f, 10.0f);
3504 builder.SaveLayer(nullptr, nullptr);
3505 { //
3506 builder.DrawRect(rect, DlPaint());
3507 }
3508 builder.Restore();
3509 auto display_list = builder.Build();
3510
3511 SaveLayerBoundsExpector expector;
3512 expector.addComputedExpectation(rect);
3513 display_list->Dispatch(expector);
3514 EXPECT_TRUE(expector.all_bounds_checked());
3515}
3516
3517TEST_F(DisplayListTest, ScaledSaveLayerBoundsComputationOfSimpleRect) {
3518 SkRect rect = SkRect::MakeLTRB(100.0f, 100.0f, 200.0f, 200.0f);
3519
3520 DisplayListBuilder builder;
3521 builder.Scale(10.0f, 10.0f);
3522 builder.SaveLayer(nullptr, nullptr);
3523 { //
3524 builder.DrawRect(rect, DlPaint());
3525 }
3526 builder.Restore();
3527 auto display_list = builder.Build();
3528
3529 SaveLayerBoundsExpector expector;
3530 expector.addComputedExpectation(rect);
3531 display_list->Dispatch(expector);
3532 EXPECT_TRUE(expector.all_bounds_checked());
3533}
3534
3535TEST_F(DisplayListTest, RotatedSaveLayerBoundsComputationOfSimpleRect) {
3536 SkRect rect = SkRect::MakeLTRB(100.0f, 100.0f, 200.0f, 200.0f);
3537
3538 DisplayListBuilder builder;
3539 builder.Rotate(45.0f);
3540 builder.SaveLayer(nullptr, nullptr);
3541 { //
3542 builder.DrawRect(rect, DlPaint());
3543 }
3544 builder.Restore();
3545 auto display_list = builder.Build();
3546
3547 SaveLayerBoundsExpector expector;
3548 expector.addComputedExpectation(rect);
3549 display_list->Dispatch(expector);
3550 EXPECT_TRUE(expector.all_bounds_checked());
3551}
3552
3553TEST_F(DisplayListTest, TransformResetSaveLayerBoundsComputationOfSimpleRect) {
3554 SkRect rect = SkRect::MakeLTRB(100.0f, 100.0f, 200.0f, 200.0f);
3555 SkRect rect_doubled = SkMatrix::Scale(2.0f, 2.0f).mapRect(rect);
3556
3557 DisplayListBuilder builder;
3558 builder.Scale(10.0f, 10.0f);
3559 builder.SaveLayer(nullptr, nullptr);
3560 builder.TransformReset();
3561 builder.Scale(20.0f, 20.0f);
3562 // Net local transform for saveLayer is Scale(2, 2)
3563 { //
3564 builder.DrawRect(rect, DlPaint());
3565 }
3566 builder.Restore();
3567 auto display_list = builder.Build();
3568
3569 SaveLayerBoundsExpector expector;
3570 expector.addComputedExpectation(rect_doubled);
3571 display_list->Dispatch(expector);
3572 EXPECT_TRUE(expector.all_bounds_checked());
3573}
3574
3575TEST_F(DisplayListTest, SaveLayerBoundsComputationOfTranslatedSimpleRect) {
3576 SkRect rect = SkRect::MakeLTRB(100.0f, 100.0f, 200.0f, 200.0f);
3577
3578 DisplayListBuilder builder;
3579 builder.SaveLayer(nullptr, nullptr);
3580 { //
3581 builder.Translate(10.0f, 10.0f);
3582 builder.DrawRect(rect, DlPaint());
3583 }
3584 builder.Restore();
3585 auto display_list = builder.Build();
3586
3587 SaveLayerBoundsExpector expector;
3588 expector.addComputedExpectation(rect.makeOffset(10.0f, 10.0f));
3589 display_list->Dispatch(expector);
3590 EXPECT_TRUE(expector.all_bounds_checked());
3591}
3592
3593TEST_F(DisplayListTest, SaveLayerBoundsComputationOfScaledSimpleRect) {
3594 SkRect rect = SkRect::MakeLTRB(100.0f, 100.0f, 200.0f, 200.0f);
3595
3596 DisplayListBuilder builder;
3597 builder.SaveLayer(nullptr, nullptr);
3598 { //
3599 builder.Scale(10.0f, 10.0f);
3600 builder.DrawRect(rect, DlPaint());
3601 }
3602 builder.Restore();
3603 auto display_list = builder.Build();
3604
3605 SaveLayerBoundsExpector expector;
3606 expector.addComputedExpectation(
3607 SkRect::MakeLTRB(1000.0f, 1000.0f, 2000.0f, 2000.0f));
3608 display_list->Dispatch(expector);
3609 EXPECT_TRUE(expector.all_bounds_checked());
3610}
3611
3612TEST_F(DisplayListTest, SaveLayerBoundsComputationOfRotatedSimpleRect) {
3613 SkRect rect = SkRect::MakeLTRB(100.0f, 100.0f, 200.0f, 200.0f);
3614
3615 DisplayListBuilder builder;
3616 builder.SaveLayer(nullptr, nullptr);
3617 { //
3618 builder.Rotate(45.0f);
3619 builder.DrawRect(rect, DlPaint());
3620 }
3621 builder.Restore();
3622 auto display_list = builder.Build();
3623
3624 SkMatrix matrix = SkMatrix::RotateDeg(45.0f);
3625 SaveLayerBoundsExpector expector;
3626 expector.addComputedExpectation(matrix.mapRect(rect));
3627 display_list->Dispatch(expector);
3628 EXPECT_TRUE(expector.all_bounds_checked());
3629}
3630
3631TEST_F(DisplayListTest, SaveLayerBoundsComputationOfNestedSimpleRect) {
3632 SkRect rect = SkRect::MakeLTRB(100.0f, 100.0f, 200.0f, 200.0f);
3633
3634 DisplayListBuilder builder;
3635 builder.SaveLayer(nullptr, nullptr);
3636 { //
3637 builder.SaveLayer(nullptr, nullptr);
3638 { //
3639 builder.DrawRect(rect, DlPaint());
3640 }
3641 builder.Restore();
3642 }
3643 builder.Restore();
3644 auto display_list = builder.Build();
3645
3646 SaveLayerBoundsExpector expector;
3647 expector.addComputedExpectation(rect);
3648 expector.addComputedExpectation(rect);
3649 display_list->Dispatch(expector);
3650 EXPECT_TRUE(expector.all_bounds_checked());
3651}
3652
3653TEST_F(DisplayListTest, FloodingSaveLayerBoundsComputationOfSimpleRect) {
3654 SkRect rect = SkRect::MakeLTRB(100.0f, 100.0f, 200.0f, 200.0f);
3655 DlPaint save_paint;
3656 auto color_filter =
3658 ASSERT_TRUE(color_filter->modifies_transparent_black());
3659 save_paint.setColorFilter(color_filter);
3660 SkRect clip_rect = rect.makeOutset(100.0f, 100.0f);
3661 ASSERT_NE(clip_rect, rect);
3662 ASSERT_TRUE(clip_rect.contains(rect));
3663
3664 DisplayListBuilder builder;
3665 builder.ClipRect(clip_rect);
3666 builder.SaveLayer(nullptr, &save_paint);
3667 { //
3668 builder.DrawRect(rect, DlPaint());
3669 }
3670 builder.Restore();
3671 auto display_list = builder.Build();
3672
3673 SaveLayerBoundsExpector expector;
3674 expector.addComputedExpectation(rect);
3675 display_list->Dispatch(expector);
3676 EXPECT_TRUE(expector.all_bounds_checked());
3677}
3678
3679TEST_F(DisplayListTest, NestedFloodingSaveLayerBoundsComputationOfSimpleRect) {
3680 SkRect rect = SkRect::MakeLTRB(100.0f, 100.0f, 200.0f, 200.0f);
3681 DlPaint save_paint;
3682 auto color_filter =
3684 ASSERT_TRUE(color_filter->modifies_transparent_black());
3685 save_paint.setColorFilter(color_filter);
3686 SkRect clip_rect = rect.makeOutset(100.0f, 100.0f);
3687 ASSERT_NE(clip_rect, rect);
3688 ASSERT_TRUE(clip_rect.contains(rect));
3689
3690 DisplayListBuilder builder;
3691 builder.ClipRect(clip_rect);
3692 builder.SaveLayer(nullptr, nullptr);
3693 {
3694 builder.SaveLayer(nullptr, &save_paint);
3695 { //
3696 builder.DrawRect(rect, DlPaint());
3697 }
3698 builder.Restore();
3699 }
3700 builder.Restore();
3701 auto display_list = builder.Build();
3702
3703 SaveLayerBoundsExpector expector;
3704 expector.addComputedExpectation(clip_rect);
3705 expector.addComputedExpectation(rect);
3706 display_list->Dispatch(expector);
3707 EXPECT_TRUE(expector.all_bounds_checked());
3708}
3709
3710TEST_F(DisplayListTest, SaveLayerBoundsComputationOfFloodingImageFilter) {
3711 SkRect rect = SkRect::MakeLTRB(100.0f, 100.0f, 200.0f, 200.0f);
3713 auto color_filter =
3715 ASSERT_TRUE(color_filter->modifies_transparent_black());
3716 auto image_filter = DlColorFilterImageFilter::Make(color_filter);
3717 draw_paint.setImageFilter(image_filter);
3718 SkRect clip_rect = rect.makeOutset(100.0f, 100.0f);
3719 ASSERT_NE(clip_rect, rect);
3720 ASSERT_TRUE(clip_rect.contains(rect));
3721
3722 DisplayListBuilder builder;
3723 builder.ClipRect(clip_rect);
3724 builder.SaveLayer(nullptr, nullptr);
3725 { //
3726 builder.DrawRect(rect, draw_paint);
3727 }
3728 builder.Restore();
3729 auto display_list = builder.Build();
3730
3731 SaveLayerBoundsExpector expector;
3732 expector.addComputedExpectation(clip_rect);
3733 display_list->Dispatch(expector);
3734 EXPECT_TRUE(expector.all_bounds_checked());
3735}
3736
3737TEST_F(DisplayListTest, SaveLayerBoundsComputationOfFloodingColorFilter) {
3738 SkRect rect = SkRect::MakeLTRB(100.0f, 100.0f, 200.0f, 200.0f);
3740 auto color_filter =
3742 ASSERT_TRUE(color_filter->modifies_transparent_black());
3743 draw_paint.setColorFilter(color_filter);
3744 SkRect clip_rect = rect.makeOutset(100.0f, 100.0f);
3745 ASSERT_NE(clip_rect, rect);
3746 ASSERT_TRUE(clip_rect.contains(rect));
3747
3748 DisplayListBuilder builder;
3749 builder.ClipRect(clip_rect);
3750 builder.SaveLayer(nullptr, nullptr);
3751 { //
3752 builder.DrawRect(rect, draw_paint);
3753 }
3754 builder.Restore();
3755 auto display_list = builder.Build();
3756
3757 // A color filter is implicitly clipped to the draw bounds so the layer
3758 // bounds will be the same as the draw bounds.
3759 SaveLayerBoundsExpector expector;
3760 expector.addComputedExpectation(rect);
3761 display_list->Dispatch(expector);
3762 EXPECT_TRUE(expector.all_bounds_checked());
3763}
3764
3765TEST_F(DisplayListTest, SaveLayerBoundsClipDetectionSimpleUnclippedRect) {
3766 SkRect rect = SkRect::MakeLTRB(100.0f, 100.0f, 200.0f, 200.0f);
3767 SkRect save_rect = SkRect::MakeLTRB(50.0f, 50.0f, 250.0f, 250.0f);
3768
3769 DisplayListBuilder builder;
3770 builder.SaveLayer(&save_rect, nullptr);
3771 { //
3772 builder.DrawRect(rect, DlPaint());
3773 }
3774 builder.Restore();
3775 auto display_list = builder.Build();
3776
3777 // A color filter is implicitly clipped to the draw bounds so the layer
3778 // bounds will be the same as the draw bounds.
3779 SaveLayerBoundsExpector expector;
3780 expector.addSuppliedExpectation(rect);
3781 display_list->Dispatch(expector);
3782 EXPECT_TRUE(expector.all_bounds_checked());
3783}
3784
3785TEST_F(DisplayListTest, SaveLayerBoundsClipDetectionSimpleClippedRect) {
3786 SkRect rect = SkRect::MakeLTRB(100.0f, 100.0f, 200.0f, 200.0f);
3787 SkRect save_rect = SkRect::MakeLTRB(50.0f, 50.0f, 110.0f, 110.0f);
3788 SkRect content_rect = SkRect::MakeLTRB(100.0f, 100.0f, 110.0f, 110.0f);
3789
3790 DisplayListBuilder builder;
3791 builder.SaveLayer(&save_rect, nullptr);
3792 { //
3793 builder.DrawRect(rect, DlPaint());
3794 }
3795 builder.Restore();
3796 auto display_list = builder.Build();
3797
3798 // A color filter is implicitly clipped to the draw bounds so the layer
3799 // bounds will be the same as the draw bounds.
3800 SaveLayerBoundsExpector expector;
3801 expector.addSuppliedExpectation(content_rect, true);
3802 display_list->Dispatch(expector);
3803 EXPECT_TRUE(expector.all_bounds_checked());
3804}
3805
3806class DepthExpector : public virtual DlOpReceiver,
3810 virtual IgnoreDrawDispatchHelper {
3811 public:
3812 explicit DepthExpector(std::vector<uint32_t> expectations)
3813 : depth_expectations_(std::move(expectations)) {}
3814
3815 void save() override {
3816 // This method should not be called since we override the variant with
3817 // the total_content_depth parameter.
3818 FAIL() << "save(no depth parameter) method should not be called";
3819 }
3820
3821 void save(uint32_t total_content_depth) override {
3822 ASSERT_LT(index_, depth_expectations_.size());
3823 EXPECT_EQ(depth_expectations_[index_], total_content_depth)
3824 << "at index " << index_;
3825 index_++;
3826 }
3827
3828 void saveLayer(const SkRect& bounds,
3830 const DlImageFilter* backdrop) override {
3831 // This method should not be called since we override the variant with
3832 // the total_content_depth parameter.
3833 FAIL() << "saveLayer(no depth parameter) method should not be called";
3834 }
3835
3836 void saveLayer(const SkRect& bounds,
3838 uint32_t total_content_depth,
3839 const DlImageFilter* backdrop) override {
3840 ASSERT_LT(index_, depth_expectations_.size());
3841 EXPECT_EQ(depth_expectations_[index_], total_content_depth)
3842 << "at index " << index_;
3843 index_++;
3844 }
3845
3846 private:
3847 size_t index_ = 0;
3848 std::vector<uint32_t> depth_expectations_;
3849};
3850
3851TEST_F(DisplayListTest, SaveContentDepthTest) {
3852 DisplayListBuilder child_builder;
3853 child_builder.DrawRect({10, 10, 20, 20}, DlPaint()); // depth 1
3854 auto child = child_builder.Build();
3855
3856 DisplayListBuilder builder;
3857 builder.DrawRect({10, 10, 20, 20}, DlPaint()); // depth 1
3858
3859 builder.Save(); // covers depth 1->9
3860 {
3861 builder.Translate(5, 5);
3862 builder.DrawRect({10, 10, 20, 20}, DlPaint()); // depth 2
3863
3864 builder.DrawDisplayList(child, 1.0f); // depth 3 (content) + 4 (self)
3865
3866 builder.SaveLayer(nullptr, nullptr); // covers depth 5->6
3867 {
3868 builder.DrawRect({12, 12, 22, 22}, DlPaint()); // depth 5
3869 builder.DrawRect({14, 14, 24, 24}, DlPaint()); // depth 6
3870 }
3871 builder.Restore(); // layer is restored with depth 7
3872
3873 builder.DrawRect({16, 16, 26, 26}, DlPaint()); // depth 8
3874 builder.DrawRect({18, 18, 28, 28}, DlPaint()); // depth 9
3875 }
3876 builder.Restore();
3877
3878 builder.DrawRect({16, 16, 26, 26}, DlPaint()); // depth 10
3879 builder.DrawRect({18, 18, 28, 28}, DlPaint()); // depth 11
3880 auto display_list = builder.Build();
3881
3882 EXPECT_EQ(display_list->total_depth(), 11u);
3883
3884 DepthExpector expector({8, 2});
3885 display_list->Dispatch(expector);
3886}
3887
3888} // namespace testing
3889} // namespace flutter
const char * options
#define test(name)
SkColor4f color
static SkPath path1()
static SkPath path2()
constexpr SkColor SK_ColorBLUE
Definition SkColor.h:135
constexpr SkColor SK_ColorRED
Definition SkColor.h:126
static constexpr SkColor SkColorSetARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b)
Definition SkColor.h:49
constexpr SkColor SK_ColorBLACK
Definition SkColor.h:103
static sk_sp< SkImage > color_filter(const SkImage *image, SkColorFilter *colorFilter)
static SkPath clip(const SkPath &path, const SkHalfPlane &plane)
Definition SkPath.cpp:3824
static bool SkScalarNearlyEqual(SkScalar x, SkScalar y, SkScalar tolerance=SK_ScalarNearlyZero)
Definition SkScalar.h:107
#define SK_ScalarNaN
Definition SkScalar.h:28
int saveLayer(const SkRect *bounds, const SkPaint *paint)
Definition SkCanvas.cpp:500
void drawRect(const SkRect &rect, const SkPaint &paint)
void restore()
Definition SkCanvas.cpp:465
SkRect getLocalClipBounds() const
SkM44 getLocalToDevice() const
SkMatrix getTotalMatrix() const
SkIRect getDeviceClipBounds() const
void drawPicture(const SkPicture *picture)
Definition SkCanvas.h:1961
static sk_sp< SkColorFilter > Matrix(const SkColorMatrix &)
Definition SkM44.h:150
static SkMatrix Scale(SkScalar sx, SkScalar sy)
Definition SkMatrix.h:75
static SkMatrix RotateDeg(SkScalar deg)
Definition SkMatrix.h:104
static SkMatrix Translate(SkScalar dx, SkScalar dy)
Definition SkMatrix.h:91
static SkMatrix MakeAll(SkScalar scaleX, SkScalar skewX, SkScalar transX, SkScalar skewY, SkScalar scaleY, SkScalar transY, SkScalar pers0, SkScalar pers1, SkScalar pers2)
Definition SkMatrix.h:179
static SkMatrix Skew(SkScalar kx, SkScalar ky)
Definition SkMatrix.h:124
bool mapRect(SkRect *dst, const SkRect &src, SkApplyPerspectiveClip pc=SkApplyPerspectiveClip::kYes) const
bool isIdentity() const
Definition SkMatrix.h:223
void setColorFilter(sk_sp< SkColorFilter > colorFilter)
static SkPath Rect(const SkRect &, SkPathDirection=SkPathDirection::kCW, unsigned startIndex=0)
Definition SkPath.cpp:3518
SkPath & addCircle(SkScalar x, SkScalar y, SkScalar radius, SkPathDirection dir=SkPathDirection::kCW)
Definition SkPath.cpp:1149
SkPath & moveTo(SkScalar x, SkScalar y)
Definition SkPath.cpp:678
void setFillType(SkPathFillType ft)
Definition SkPath.h:235
SkPath & lineTo(SkScalar x, SkScalar y)
Definition SkPath.cpp:718
SkPath & addRoundRect(const SkRect &rect, SkScalar rx, SkScalar ry, SkPathDirection dir=SkPathDirection::kCW)
Definition SkPath.cpp:1088
SkPath & addOval(const SkRect &oval, SkPathDirection dir=SkPathDirection::kCW)
Definition SkPath.cpp:1101
SkPath & cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar x3, SkScalar y3)
Definition SkPath.cpp:789
SkPath & close()
Definition SkPath.cpp:813
SkPath & addRect(const SkRect &rect, SkPathDirection dir, unsigned start)
Definition SkPath.cpp:854
SkCanvas * beginRecording(const SkRect &bounds, sk_sp< SkBBoxHierarchy > bbh)
SkCanvas * getRecordingCanvas()
sk_sp< SkPicture > finishRecordingAsPicture()
virtual SkRect cullRect() const =0
virtual int approximateOpCount(bool nested=false) const =0
static SkRRect MakeRectXY(const SkRect &rect, SkScalar xRad, SkScalar yRad)
Definition SkRRect.h:180
static SkRRect MakeEmpty()
Definition SkRRect.h:142
static constexpr SkRect kMaxCullRect
Definition dl_builder.h:32
void DrawRect(const SkRect &rect, const DlPaint &paint) override
void SaveLayer(const SkRect *bounds, const DlPaint *paint=nullptr, const DlImageFilter *backdrop=nullptr) override
sk_sp< DisplayList > Build()
Definition dl_builder.cc:67
static std::shared_ptr< DlColorFilter > Make(DlColor color, DlBlendMode mode)
static std::shared_ptr< DlImageFilter > Make(SkScalar sigma_x, SkScalar sigma_y, DlTileMode tile_mode)
static std::shared_ptr< DlMaskFilter > Make(DlBlurStyle style, SkScalar sigma, bool respect_ctm=true)
Developer-facing API for rendering anything within the engine.
Definition dl_canvas.h:37
virtual void DrawRect(const SkRect &rect, const DlPaint &paint)=0
virtual void DrawRRect(const SkRRect &rrect, const DlPaint &paint)=0
virtual void DrawOval(const SkRect &bounds, const DlPaint &paint)=0
virtual void DrawPath(const SkPath &path, const DlPaint &paint)=0
static std::shared_ptr< DlImageFilter > Make(const std::shared_ptr< const DlColorFilter > &filter)
Internal API for rendering recorded display lists to backends.
virtual void drawImageRect(const sk_sp< DlImage > image, const SkRect &src, const SkRect &dst, DlImageSampling sampling, bool render_with_attributes, SrcRectConstraint constraint=SrcRectConstraint::kFast)=0
virtual void save()=0
virtual void drawArc(const SkRect &oval_bounds, SkScalar start_degrees, SkScalar sweep_degrees, bool use_center)=0
virtual void saveLayer(const SkRect &bounds, const SaveLayerOptions options, const DlImageFilter *backdrop=nullptr)=0
virtual void drawRect(const SkRect &rect)=0
virtual void setStrokeMiter(float limit)=0
virtual void clipRect(const SkRect &rect, ClipOp clip_op, bool is_aa)=0
virtual void transformReset()=0
virtual void drawImage(const sk_sp< DlImage > image, const SkPoint point, DlImageSampling sampling, bool render_with_attributes)=0
virtual void drawCircle(const SkPoint &center, SkScalar radius)=0
virtual void drawVertices(const DlVertices *vertices, DlBlendMode mode)=0
virtual void restore()=0
virtual void drawPath(const CacheablePath &cache)
virtual void drawPoints(PointMode mode, uint32_t count, const SkPoint points[])=0
virtual void skew(SkScalar sx, SkScalar sy)=0
virtual void drawOval(const SkRect &bounds)=0
virtual void drawRRect(const SkRRect &rrect)=0
virtual void drawDisplayList(const sk_sp< DisplayList > display_list, SkScalar opacity=SK_Scalar1)=0
virtual void setStrokeWidth(float width)=0
virtual void setMaskFilter(const DlMaskFilter *filter)=0
virtual void drawDRRect(const SkRRect &outer, const SkRRect &inner)=0
virtual void setColorFilter(const DlColorFilter *filter)=0
virtual void drawImageNine(const sk_sp< DlImage > image, const SkIRect &center, const SkRect &dst, DlFilterMode filter, bool render_with_attributes)=0
virtual void setAntiAlias(bool aa)=0
virtual void clipRRect(const SkRRect &rrect, ClipOp clip_op, bool is_aa)=0
virtual void drawColor(DlColor color, DlBlendMode mode)=0
virtual void drawAtlas(const sk_sp< DlImage > atlas, const SkRSXform xform[], const SkRect tex[], const DlColor colors[], int count, DlBlendMode mode, DlImageSampling sampling, const SkRect *cull_rect, bool render_with_attributes)=0
virtual void transform2DAffine(SkScalar mxx, SkScalar mxy, SkScalar mxt, SkScalar myx, SkScalar myy, SkScalar myt)=0
virtual void translate(SkScalar tx, SkScalar ty)=0
virtual void clipPath(const CacheablePath &cache, ClipOp clip_op, bool is_aa)
virtual void scale(SkScalar sx, SkScalar sy)=0
virtual void setStrokeJoin(DlStrokeJoin join)=0
virtual void drawShadow(const CacheablePath &cache, const DlColor color, const SkScalar elevation, bool transparent_occluder, SkScalar dpr)
virtual void drawLine(const SkPoint &p0, const SkPoint &p1)=0
virtual void setImageFilter(const DlImageFilter *filter)=0
virtual void setColorSource(const DlColorSource *source)=0
virtual void rotate(SkScalar degrees)=0
virtual void drawPaint()=0
virtual void setDrawStyle(DlDrawStyle style)=0
virtual void drawTextBlob(const sk_sp< SkTextBlob > blob, SkScalar x, SkScalar y)=0
virtual void setPathEffect(const DlPathEffect *effect)=0
virtual void setBlendMode(DlBlendMode mode)=0
virtual void transformFullPerspective(SkScalar mxx, SkScalar mxy, SkScalar mxz, SkScalar mxt, SkScalar myx, SkScalar myy, SkScalar myz, SkScalar myt, SkScalar mzx, SkScalar mzy, SkScalar mzz, SkScalar mzt, SkScalar mwx, SkScalar mwy, SkScalar mwz, SkScalar mwt)=0
virtual void setColor(DlColor color)=0
virtual void setInvertColors(bool invert)=0
virtual void setStrokeCap(DlStrokeCap cap)=0
bool isAntiAlias() const
Definition dl_paint.h:58
DlStrokeCap getStrokeCap() const
Definition dl_paint.h:100
bool isDefault() const
Definition dl_paint.h:193
DlColor getColor() const
Definition dl_paint.h:70
DlPaint & setColor(DlColor color)
Definition dl_paint.h:71
DlPaint & setAntiAlias(bool isAntiAlias)
Definition dl_paint.h:59
DlBlendMode getBlendMode() const
Definition dl_paint.h:84
DlPaint & setColorFilter(const std::shared_ptr< const DlColorFilter > &filter)
Definition dl_paint.h:145
DlPaint & setMaskFilter(const std::shared_ptr< DlMaskFilter > &filter)
Definition dl_paint.h:171
float getStrokeMiter() const
Definition dl_paint.h:122
std::shared_ptr< const DlPathEffect > getPathEffect() const
Definition dl_paint.h:180
std::shared_ptr< const DlColorSource > getColorSource() const
Definition dl_paint.h:128
DlStrokeJoin getStrokeJoin() const
Definition dl_paint.h:108
DlPaint & setStrokeWidth(float width)
Definition dl_paint.h:117
DlPaint & setAlpha(uint8_t alpha)
Definition dl_paint.h:77
DlPaint & setBlendMode(DlBlendMode mode)
Definition dl_paint.h:87
DlDrawStyle getDrawStyle() const
Definition dl_paint.h:92
std::shared_ptr< const DlMaskFilter > getMaskFilter() const
Definition dl_paint.h:167
std::shared_ptr< const DlColorFilter > getColorFilter() const
Definition dl_paint.h:141
DlPaint & setImageFilter(const std::shared_ptr< const DlImageFilter > &filter)
Definition dl_paint.h:158
float getStrokeWidth() const
Definition dl_paint.h:116
std::shared_ptr< const DlImageFilter > getImageFilter() const
Definition dl_paint.h:154
DlPaint & setDrawStyle(DlDrawStyle style)
Definition dl_paint.h:95
DlPaint & setStrokeJoin(DlStrokeJoin join)
Definition dl_paint.h:111
bool isInvertColors() const
Definition dl_paint.h:64
Backend implementation of |DlOpReceiver| for |SkCanvas|.
static const SaveLayerOptions kNoAttributes
SaveLayerOptions with_can_distribute_opacity() const
SaveLayerOptions with_bounds_from_caller() const
static const SaveLayerOptions kWithAttributes
SaveLayerOptions with_content_is_clipped() const
void saveLayer(const SkRect &bounds, const SaveLayerOptions &options, uint32_t total_content_depth, const DlImageFilter *backdrop) override
void saveLayer(const SkRect &bounds, SaveLayerOptions options, const DlImageFilter *backdrop) override
void save(uint32_t total_content_depth) override
DepthExpector(std::vector< uint32_t > expectations)
static DlOpReceiver & ToReceiver(DisplayListBuilder &builder)
static void check_inverted_bounds(DlRenderer &renderer, const std::string &desc)
const std::function< void(DlCanvas &, DlPaint &, SkRect &rect)> DlRenderer
const std::function< void(DlCanvas &)> DlSetup
static void check_defaults(DisplayListBuilder &builder, const SkRect &cull_rect=DisplayListBuilder::kMaxCullRect)
static sk_sp< DisplayList > Build(size_t g_index, size_t v_index)
static void verify_inverted_bounds(DlSetup &setup, DlRenderer &renderer, DlPaint paint, SkRect render_rect, SkRect expected_bounds, const std::string &desc)
static sk_sp< DisplayList > Build(DisplayListInvocation &invocation)
SaveLayerBoundsExpector & addSuppliedExpectation(const SkRect &bounds, bool clipped=false)
SaveLayerBoundsExpector & addComputedExpectation(const SkRect &bounds)
void saveLayer(const SkRect &bounds, const SaveLayerOptions options, const DlImageFilter *backdrop) override
SaveLayerOptionsExpector(const SaveLayerOptions &expected)
void saveLayer(const SkRect &bounds, const SaveLayerOptions options, const DlImageFilter *backdrop) override
SaveLayerOptionsExpector(std::vector< SaveLayerOptions > expected)
T * get() const
Definition SkRefCnt.h:303
const Paint & paint
#define RUN_TESTS2(body, expect)
#define RUN_TESTS(body)
#define TestPointCount
SkMatrix sk_matrix
static void draw_paint(SkCanvas *canvas, const SkRect &r, sk_sp< SkImageFilter > imf)
#define FAIL(name, result)
VkSurfaceKHR surface
Definition main.cc:49
float SkScalar
Definition extension.cpp:12
EMSCRIPTEN_KEEPALIVE void empty()
#define FML_LOG(severity)
Definition logging.h:82
#define FML_DISALLOW_COPY_AND_ASSIGN(TypeName)
Definition macros.h:27
static void draw_rect(SkCanvas *canvas, SkImage *, const SkRect &r, sk_sp< SkImageFilter > imf)
static void drawPath(SkPath &path, SkCanvas *canvas, SkColor color, const SkRect &clip, SkPaint::Cap cap, SkPaint::Join join, SkPaint::Style style, SkPathFillType fill, SkScalar strokeWidth)
Definition linepaths.cpp:22
double y
double x
SK_API sk_sp< SkSurface > Raster(const SkImageInfo &imageInfo, size_t rowBytes, const SkSurfaceProps *surfaceProps)
Definition build.py:1
Definition copy.py:1
constexpr float kPi
Definition math.h:27
TEST_F(DisplayListTest, Defaults)
constexpr SkRect kTestBounds
static const DlBlurMaskFilter kTestMaskFilter1(DlBlurStyle::kNormal, 3.0)
bool DisplayListsNE_Verbose(const DisplayList *a, const DisplayList *b)
static const SkPath kTestPath1
static const DlImageColorSource kTestSource1(TestImage1, DlTileMode::kClamp, DlTileMode::kMirror, kLinearSampling)
static std::vector< testing::DisplayListInvocationGroup > allGroups
static constexpr SkPoint kTestPoints[2]
static const SkRRect kTestRRect
static void test_rtree(const sk_sp< const DlRTree > &rtree, const SkRect &query, std::vector< SkRect > expected_rects, const std::vector< int > &expected_indices)
static auto TestImage1
static const std::shared_ptr< DlPathEffect > kTestPathEffect1
static const DlMatrixColorFilter kTestMatrixColorFilter1(kRotateColorMatrix)
static DlImageSampling kLinearSampling
static std::shared_ptr< const DlVertices > TestVertices1
bool DisplayListsEQ_Verbose(const DisplayList *a, const DisplayList *b)
static DlImageSampling kNearestSampling
sk_sp< SkTextBlob > GetTestTextBlob(int index)
static const DlBlurImageFilter kTestBlurImageFilter1(5.0, 5.0, DlTileMode::kClamp)
static auto TestImage2
std::vector< DisplayListInvocationGroup > CreateAllGroups()
static sk_sp< DisplayList > TestDisplayList1
DlPaint DisplayListBuilderTestingAttributes(DisplayListBuilder &builder)
@ kRound
adds circle
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace Enable an endless trace buffer The default is a ring buffer This is useful when very old events need to viewed For during application launch Memory usage will continue to grow indefinitely however Start app with an specific route defined on the framework flutter assets Path to the Flutter assets directory enable service port Allow the VM service to fallback to automatic port selection if binding to a specified port fails trace Trace early application lifecycle Automatically switches to an endless trace buffer trace skia Filters out all Skia trace event categories except those that are specified in this comma separated list dump skp on shader Automatically dump the skp that triggers new shader compilations This is useful for writing custom ShaderWarmUp to reduce jank By this is not enabled to reduce the overhead purge persistent cache
Definition switches.h:191
DlOpReceiver & DisplayListBuilderTestingAccessor(DisplayListBuilder &builder)
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition switches.h:57
DEF_SWITCHES_START aot vmservice shared library name
Definition switches.h:32
@ kStrokeAndFill
both strokes and fills shapes
@ kStroke
strokes boundary of shapes
@ kNormal
fuzzy inside and outside
@ kColorBurn
darken destination to reflect source
@ kSrcOver
r = s + (1-sa)*d
Definition main.py:1
Definition setup.py:1
Definition ref_ptr.h:256
static constexpr SkIRect MakeWH(int32_t w, int32_t h)
Definition SkRect.h:56
static SkImageInfo MakeN32Premul(int width, int height)
static SkRect Make(const SkISize &size)
Definition SkRect.h:669
static constexpr SkRect MakeEmpty()
Definition SkRect.h:595
SkScalar fBottom
larger y-axis bounds
Definition extension.cpp:17
bool intersect(const SkRect &r)
Definition SkRect.cpp:114
SkScalar fLeft
smaller x-axis bounds
Definition extension.cpp:14
SkRect makeOutset(float dx, float dy) const
Definition SkRect.h:1002
static constexpr SkRect MakeXYWH(float x, float y, float w, float h)
Definition SkRect.h:659
bool intersects(const SkRect &r) const
Definition SkRect.h:1121
SkScalar fRight
larger x-axis bounds
Definition extension.cpp:16
bool contains(SkScalar x, SkScalar y) const
Definition extension.cpp:19
bool isEmpty() const
Definition SkRect.h:693
static constexpr SkRect MakeWH(float w, float h)
Definition SkRect.h:609
static constexpr SkRect MakeLTRB(float l, float t, float r, float b)
Definition SkRect.h:646
SkScalar fTop
smaller y-axis bounds
Definition extension.cpp:15
static constexpr DlColor kWhite()
Definition dl_color.h:23
static constexpr DlColor kBlue()
Definition dl_color.h:26
static constexpr DlColor kTransparent()
Definition dl_color.h:21
static constexpr DlColor kRed()
Definition dl_color.h:24
uint32_t adjust_render_op_depth_cost(uint32_t previous_cost)
uint32_t depth_accumulated(uint32_t depth_scale=1u)
#define ERROR(message)
#define EXPECT_TRUE(handle)
Definition unit_test.h:685