Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
Loading...
Searching...
No Matches
aiks_dl_basic_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
14
24#include "imgui.h"
26
27namespace impeller {
28namespace testing {
29
30using namespace flutter;
31
32TEST_P(AiksTest, CanRenderColoredRect) {
33 DisplayListBuilder builder;
34 DlPaint paint;
35 paint.setColor(DlColor::kBlue());
36 builder.DrawPath(DlPath::MakeRectXYWH(100.0f, 100.0f, 100.0f, 100.0f), paint);
37 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
38}
39
40TEST_P(AiksTest, CanRenderColoredRectPrimitive) {
41 DisplayListBuilder builder;
42 DlPaint paint;
43 paint.setColor(DlColor::kBlue());
44 builder.DrawRect(DlRect::MakeXYWH(100.f, 100.f, 100.f, 100.f), paint);
45 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
46}
47
48namespace {
49using DrawRectProc =
50 std::function<void(DisplayListBuilder&, const DlRect&, const DlPaint&)>;
51
52sk_sp<DisplayList> MakeWideStrokedRects(Point scale,
53 const DrawRectProc& draw_rect) {
54 DisplayListBuilder builder;
55 builder.Scale(scale.x, scale.y);
56 builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc);
57
58 DlPaint paint;
59 paint.setColor(DlColor::kBlue().withAlphaF(0.5));
60 paint.setDrawStyle(DlDrawStyle::kStroke);
61 paint.setStrokeWidth(30.0f);
62
63 // Each of these 3 sets of rects includes (with different join types):
64 // - One rectangle with a gap in the middle
65 // - One rectangle with no gap because it is too narrow
66 // - One rectangle with no gap because it is too short
67 paint.setStrokeJoin(DlStrokeJoin::kBevel);
68 draw_rect(builder, DlRect::MakeXYWH(100.0f, 100.0f, 100.0f, 100.0f), paint);
69 draw_rect(builder, DlRect::MakeXYWH(250.0f, 100.0f, 10.0f, 100.0f), paint);
70 draw_rect(builder, DlRect::MakeXYWH(100.0f, 250.0f, 100.0f, 10.0f), paint);
71
72 paint.setStrokeJoin(DlStrokeJoin::kRound);
73 draw_rect(builder, DlRect::MakeXYWH(350.0f, 100.0f, 100.0f, 100.0f), paint);
74 draw_rect(builder, DlRect::MakeXYWH(500.0f, 100.0f, 10.0f, 100.0f), paint);
75 draw_rect(builder, DlRect::MakeXYWH(350.0f, 250.0f, 100.0f, 10.0f), paint);
76
77 paint.setStrokeJoin(DlStrokeJoin::kMiter);
78 draw_rect(builder, DlRect::MakeXYWH(600.0f, 100.0f, 100.0f, 100.0f), paint);
79 draw_rect(builder, DlRect::MakeXYWH(750.0f, 100.0f, 10.0f, 100.0f), paint);
80 draw_rect(builder, DlRect::MakeXYWH(600.0f, 250.0f, 100.0f, 10.0f), paint);
81
82 // And now draw 3 rectangles with a stroke width so large that that it
83 // overlaps in the middle in both directions (horizontal/vertical).
84 paint.setStrokeWidth(110.0f);
85
86 paint.setStrokeJoin(DlStrokeJoin::kBevel);
87 draw_rect(builder, DlRect::MakeXYWH(100.0f, 400.0f, 100.0f, 100.0f), paint);
88
89 paint.setStrokeJoin(DlStrokeJoin::kRound);
90 draw_rect(builder, DlRect::MakeXYWH(350.0f, 400.0f, 100.0f, 100.0f), paint);
91
92 paint.setStrokeJoin(DlStrokeJoin::kMiter);
93 draw_rect(builder, DlRect::MakeXYWH(600.0f, 400.0f, 100.0f, 100.0f), paint);
94
95 return builder.Build();
96}
97} // namespace
98
99TEST_P(AiksTest, CanRenderWideStrokedRectWithoutOverlap) {
100 ASSERT_TRUE(OpenPlaygroundHere(MakeWideStrokedRects(
101 GetContentScale(), [](DisplayListBuilder& builder, const DlRect& rect,
102 const DlPaint& paint) {
103 // Draw the rect directly
104 builder.DrawRect(rect, paint);
105 })));
106}
107
108TEST_P(AiksTest, CanRenderWideStrokedRectPathWithoutOverlap) {
109 ASSERT_TRUE(OpenPlaygroundHere(MakeWideStrokedRects(
110 GetContentScale(), [](DisplayListBuilder& builder, const DlRect& rect,
111 const DlPaint& paint) {
112 // Draw the rect as a Path
113 builder.DrawPath(DlPath::MakeRect(rect), paint);
114 })));
115}
116
117TEST_P(AiksTest, CanRenderImage) {
118 DisplayListBuilder builder;
119 DlPaint paint;
120 paint.setColor(DlColor::kRed());
121 auto image = DlImageImpeller::Make(CreateTextureForFixture("kalimba.jpg"));
122 builder.DrawImage(image, DlPoint(100.0, 100.0),
123 DlImageSampling::kNearestNeighbor, &paint);
124 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
125}
126
127TEST_P(AiksTest, CanRenderInvertedImageWithColorFilter) {
128 DisplayListBuilder builder;
129 DlPaint paint;
130 paint.setColor(DlColor::kRed());
131 paint.setColorFilter(
132 DlColorFilter::MakeBlend(DlColor::kYellow(), DlBlendMode::kSrcOver));
133 paint.setInvertColors(true);
134 auto image = DlImageImpeller::Make(CreateTextureForFixture("kalimba.jpg"));
135
136 builder.DrawImage(image, DlPoint(100.0, 100.0),
137 DlImageSampling::kNearestNeighbor, &paint);
138 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
139}
140
141TEST_P(AiksTest, CanRenderColorFilterWithInvertColors) {
142 DisplayListBuilder builder;
143 DlPaint paint;
144 paint.setColor(DlColor::kRed());
145 paint.setColorFilter(
146 DlColorFilter::MakeBlend(DlColor::kYellow(), DlBlendMode::kSrcOver));
147 paint.setInvertColors(true);
148
149 builder.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100), paint);
150 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
151}
152
153TEST_P(AiksTest, CanRenderColorFilterWithInvertColorsDrawPaint) {
154 DisplayListBuilder builder;
155 DlPaint paint;
156 paint.setColor(DlColor::kRed());
157 paint.setColorFilter(
158 DlColorFilter::MakeBlend(DlColor::kYellow(), DlBlendMode::kSrcOver));
159 paint.setInvertColors(true);
160
161 builder.DrawPaint(paint);
162 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
163}
164
165namespace {
166bool GenerateMipmap(const std::shared_ptr<Context>& context,
167 std::shared_ptr<Texture> texture,
168 std::string_view label) {
169 auto buffer = context->CreateCommandBuffer();
170 if (!buffer) {
171 return false;
172 }
173 auto pass = buffer->CreateBlitPass();
174 if (!pass) {
175 return false;
176 }
177 pass->GenerateMipmap(std::move(texture), label);
178
179 pass->EncodeCommands();
180 return context->GetCommandQueue()->Submit({buffer}).ok();
181}
182
183void CanRenderTiledTexture(AiksTest* aiks_test,
184 DlTileMode tile_mode,
185 Matrix local_matrix = {}) {
186 auto context = aiks_test->GetContext();
187 ASSERT_TRUE(context);
188 auto texture = aiks_test->CreateTextureForFixture("table_mountain_nx.png",
189 /*enable_mipmapping=*/true);
190 GenerateMipmap(context, texture, "table_mountain_nx");
192 auto color_source = DlColorSource::MakeImage(
193 image, tile_mode, tile_mode, DlImageSampling::kNearestNeighbor,
194 &local_matrix);
195
196 DisplayListBuilder builder;
197 DlPaint paint;
198 paint.setColor(DlColor::kWhite());
199 paint.setColorSource(color_source);
200
201 builder.Scale(aiks_test->GetContentScale().x, aiks_test->GetContentScale().y);
202 builder.Translate(100.0f, 100.0f);
203 builder.DrawRect(DlRect::MakeXYWH(0, 0, 600, 600), paint);
204
205 // Should not change the image.
206 constexpr auto stroke_width = 64;
207 paint.setDrawStyle(DlDrawStyle::kStroke);
208 paint.setStrokeWidth(stroke_width);
209 if (tile_mode == DlTileMode::kDecal) {
210 builder.DrawRect(DlRect::MakeXYWH(stroke_width, stroke_width, 600, 600),
211 paint);
212 } else {
213 builder.DrawRect(DlRect::MakeXYWH(0, 0, 600, 600), paint);
214 }
215
216 {
217 // Should not change the image.
218 DlPathBuilder path_builder;
219 path_builder.AddCircle(DlPoint(150, 150), 150);
220 path_builder.AddRoundRect(
221 RoundRect::MakeRectXY(DlRect::MakeLTRB(300, 300, 600, 600), 10, 10));
222 DlPath path = path_builder.TakePath();
223
224 // Make sure path cannot be simplified...
225 EXPECT_FALSE(path.IsRect(nullptr));
226 EXPECT_FALSE(path.IsOval(nullptr));
227 EXPECT_FALSE(path.IsRoundRect(nullptr));
228
229 // Make sure path will not trigger the optimal convex code
230 EXPECT_FALSE(path.IsConvex());
231
232 paint.setDrawStyle(DlDrawStyle::kFill);
233 builder.DrawPath(path, paint);
234 }
235
236 {
237 // Should not change the image. Tests the Convex short-cut code.
238
239 // To avoid simplification, construct an explicit circle using conics.
240 constexpr float kConicWeight = 0.707106781f; // sqrt(2)/2
241 const DlPath path = DlPathBuilder()
242 .MoveTo({150, 300})
243 .ConicCurveTo({300, 300}, {300, 450}, kConicWeight)
244 .ConicCurveTo({300, 600}, {150, 600}, kConicWeight)
245 .ConicCurveTo({0, 600}, {0, 450}, kConicWeight)
246 .ConicCurveTo({0, 300}, {150, 300}, kConicWeight)
247 .Close()
248 .TakePath();
249
250 // Make sure path cannot be simplified...
251 EXPECT_FALSE(path.IsRect(nullptr));
252 EXPECT_FALSE(path.IsOval(nullptr));
253 EXPECT_FALSE(path.IsRoundRect(nullptr));
254
255 // But check that we will trigger the optimal convex code
256 EXPECT_TRUE(path.IsConvex());
257
258 paint.setDrawStyle(DlDrawStyle::kFill);
259 builder.DrawPath(path, paint);
260 }
261
262 ASSERT_TRUE(aiks_test->OpenPlaygroundHere(builder.Build()));
263}
264} // namespace
265
266TEST_P(AiksTest, CanRenderTiledTextureClamp) {
267 CanRenderTiledTexture(this, DlTileMode::kClamp);
268}
269
270TEST_P(AiksTest, CanRenderTiledTextureRepeat) {
271 CanRenderTiledTexture(this, DlTileMode::kRepeat);
272}
273
274TEST_P(AiksTest, CanRenderTiledTextureMirror) {
275 CanRenderTiledTexture(this, DlTileMode::kMirror);
276}
277
278TEST_P(AiksTest, CanRenderTiledTextureDecal) {
279 CanRenderTiledTexture(this, DlTileMode::kDecal);
280}
281
282TEST_P(AiksTest, CanRenderTiledTextureClampWithTranslate) {
283 CanRenderTiledTexture(this, DlTileMode::kClamp,
284 Matrix::MakeTranslation({172.f, 172.f, 0.f}));
285}
286
287TEST_P(AiksTest, CanRenderImageRect) {
288 DisplayListBuilder builder;
289 auto image = DlImageImpeller::Make(CreateTextureForFixture("kalimba.jpg"));
290
291 DlISize image_half_size =
292 DlISize(image->GetSize().width * 0.5f, image->GetSize().height * 0.5f);
293
294 // Render the bottom right quarter of the source image in a stretched rect.
295 auto source_rect = DlRect::MakeSize(image_half_size);
296 source_rect =
297 source_rect.Shift(image_half_size.width, image_half_size.height);
298
299 builder.DrawImageRect(image, source_rect,
300 DlRect::MakeXYWH(100, 100, 600, 600),
301 DlImageSampling::kNearestNeighbor);
302 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
303}
304
305TEST_P(AiksTest, DrawImageRectSrcOutsideBounds) {
306 DisplayListBuilder builder;
307 auto image = DlImageImpeller::Make(CreateTextureForFixture("kalimba.jpg"));
308
309 // Use a source rect that is partially outside the bounds of the image.
310 auto source_rect = DlRect::MakeXYWH(
311 image->GetSize().width * 0.25f, image->GetSize().height * 0.4f,
312 image->GetSize().width, image->GetSize().height);
313
314 auto dest_rect = DlRect::MakeXYWH(100, 100, 600, 600);
315
316 DlPaint paint;
318 builder.DrawRect(dest_rect, paint);
319
320 builder.DrawImageRect(image, source_rect, dest_rect,
321 DlImageSampling::kNearestNeighbor);
322 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
323}
324
325TEST_P(AiksTest, CanRenderSimpleClips) {
326 DisplayListBuilder builder;
327 builder.Scale(GetContentScale().x, GetContentScale().y);
328 DlPaint paint;
329
330 paint.setColor(DlColor::kWhite());
331 builder.DrawPaint(paint);
332
333 auto draw = [&builder](const DlPaint& paint, Scalar x, Scalar y) {
334 builder.Save();
335 builder.Translate(x, y);
336 {
337 builder.Save();
338 builder.ClipRect(DlRect::MakeLTRB(50, 50, 150, 150));
339 builder.DrawPaint(paint);
340 builder.Restore();
341 }
342 {
343 builder.Save();
344 builder.ClipOval(DlRect::MakeLTRB(200, 50, 300, 150));
345 builder.DrawPaint(paint);
346 builder.Restore();
347 }
348 {
349 builder.Save();
350 builder.ClipRoundRect(
351 DlRoundRect::MakeRectXY(DlRect::MakeLTRB(50, 200, 150, 300), 20, 20));
352 builder.DrawPaint(paint);
353 builder.Restore();
354 }
355 {
356 builder.Save();
358 DlRect::MakeLTRB(200, 230, 300, 270), 20, 20));
359 builder.DrawPaint(paint);
360 builder.Restore();
361 }
362 {
363 builder.Save();
365 DlRect::MakeLTRB(230, 200, 270, 300), 20, 20));
366 builder.DrawPaint(paint);
367 builder.Restore();
368 }
369 builder.Restore();
370 };
371
372 paint.setColor(DlColor::kBlue());
373 draw(paint, 0, 0);
374
375 DlColor gradient_colors[7] = {
376 DlColor::RGBA(0x1f / 255.0, 0.0, 0x5c / 255.0, 1.0),
377 DlColor::RGBA(0x5b / 255.0, 0.0, 0x60 / 255.0, 1.0),
378 DlColor::RGBA(0x87 / 255.0, 0x01 / 255.0, 0x60 / 255.0, 1.0),
379 DlColor::RGBA(0xac / 255.0, 0x25 / 255.0, 0x53 / 255.0, 1.0),
380 DlColor::RGBA(0xe1 / 255.0, 0x6b / 255.0, 0x5c / 255.0, 1.0),
381 DlColor::RGBA(0xf3 / 255.0, 0x90 / 255.0, 0x60 / 255.0, 1.0),
382 DlColor::RGBA(0xff / 255.0, 0xb5 / 255.0, 0x6b / 250.0, 1.0),
383 };
384 Scalar stops[7] = {
385 0.0,
386 (1.0 / 6.0) * 1,
387 (1.0 / 6.0) * 2,
388 (1.0 / 6.0) * 3,
389 (1.0 / 6.0) * 4,
390 (1.0 / 6.0) * 5,
391 1.0,
392 };
393 auto texture = CreateTextureForFixture("airplane.jpg",
394 /*enable_mipmapping=*/true);
396
398 DlPoint(500, 600), 75, 7, gradient_colors, stops, DlTileMode::kMirror));
399 draw(paint, 0, 300);
400
401 paint.setColorSource(
402 DlColorSource::MakeImage(image, DlTileMode::kRepeat, DlTileMode::kRepeat,
403 DlImageSampling::kNearestNeighbor));
404 draw(paint, 300, 0);
405
406 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
407}
408
409TEST_P(AiksTest, CanSaveLayerStandalone) {
410 DisplayListBuilder builder;
411
412 DlPaint red;
413 red.setColor(DlColor::kRed());
414
415 DlPaint alpha;
416 alpha.setColor(DlColor::kRed().modulateOpacity(0.5));
417
418 builder.SaveLayer(std::nullopt, &alpha);
419
420 builder.DrawCircle(DlPoint(125, 125), 125, red);
421
422 builder.Restore();
423
424 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
425}
426
427TEST_P(AiksTest, CanRenderDifferentShapesWithSameColorSource) {
428 DisplayListBuilder builder;
429 DlPaint paint;
430
431 DlColor colors[2] = {
432 DlColor::RGBA(0.9568, 0.2627, 0.2118, 1.0),
433 DlColor::RGBA(0.1294, 0.5882, 0.9529, 1.0),
434 };
435 DlScalar stops[2] = {
436 0.0,
437 1.0,
438 };
439
441 /*start_point=*/DlPoint(0, 0), //
442 /*end_point=*/DlPoint(100, 100), //
443 /*stop_count=*/2, //
444 /*colors=*/colors, //
445 /*stops=*/stops, //
446 /*tile_mode=*/DlTileMode::kRepeat //
447 ));
448
449 builder.Save();
450 builder.Translate(100, 100);
451 builder.DrawRect(DlRect::MakeXYWH(0, 0, 200, 200), paint);
452 builder.Restore();
453
454 builder.Save();
455 builder.Translate(100, 400);
456 builder.DrawCircle(DlPoint(100, 100), 100, paint);
457 builder.Restore();
458 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
459}
460
461TEST_P(AiksTest, CanRenderRoundedRectWithNonUniformRadii) {
462 DisplayListBuilder builder;
463 DlPaint paint;
464 paint.setColor(DlColor::kRed());
465
466 RoundingRadii radii = {
467 .top_left = DlSize(50, 25),
468 .top_right = DlSize(25, 50),
469 .bottom_left = DlSize(25, 50),
470 .bottom_right = DlSize(50, 25),
471 };
472 DlRoundRect rrect =
473 DlRoundRect::MakeRectRadii(DlRect::MakeXYWH(100, 100, 500, 500), radii);
474
475 builder.DrawRoundRect(rrect, paint);
476
477 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
478}
479
480TEST_P(AiksTest, CanRenderRoundedRectWithUniformRadii) {
481 Scalar top_left = 20.f;
482 Scalar top_right = 40.f;
483 Scalar bottom_left = 60.f;
484 Scalar bottom_right = 80.f;
485 auto callback = [&]() -> sk_sp<DisplayList> {
486 if (IsPlaygroundEnabled()) {
487 ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
488 ImGui::SliderFloat("top_left", &top_left, 0, 250);
489 ImGui::SliderFloat("top_right", &top_right, 0, 250);
490 ImGui::SliderFloat("bottom_left", &bottom_left, 0, 250);
491 ImGui::SliderFloat("bottom_right", &bottom_right, 0, 250);
492 ImGui::End();
493 }
494
495 DisplayListBuilder builder;
496 DlPaint paint;
497 paint.setColor(DlColor::kRed());
498
499 RoundingRadii radii = {
500 .top_left = DlSize(top_left, top_left),
501 .top_right = DlSize(top_right, top_right),
502 .bottom_left = DlSize(bottom_left, bottom_left),
503 .bottom_right = DlSize(bottom_right, bottom_right),
504 };
505 DlRoundRect rrect =
506 DlRoundRect::MakeRectRadii(DlRect::MakeXYWH(100, 100, 500, 500), radii);
507
508 builder.DrawRoundRect(rrect, paint);
509 return builder.Build();
510 };
511
512 ASSERT_TRUE(OpenPlaygroundHere(callback));
513}
514
515TEST_P(AiksTest, CanDrawPaint) {
516 auto medium_turquoise =
517 DlColor::RGBA(72.0f / 255.0f, 209.0f / 255.0f, 204.0f / 255.0f, 1.0f);
518
519 DisplayListBuilder builder;
520 builder.Scale(0.2, 0.2);
521 builder.DrawPaint(DlPaint().setColor(medium_turquoise));
522 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
523}
524
525TEST_P(AiksTest, CanDrawPaintMultipleTimes) {
526 auto medium_turquoise =
527 DlColor::RGBA(72.0f / 255.0f, 209.0f / 255.0f, 204.0f / 255.0f, 1.0f);
528 auto orange_red =
529 DlColor::RGBA(255.0f / 255.0f, 69.0f / 255.0f, 0.0f / 255.0f, 1.0f);
530
531 DisplayListBuilder builder;
532 builder.Scale(0.2, 0.2);
533 builder.DrawPaint(DlPaint().setColor(medium_turquoise));
534 builder.DrawPaint(DlPaint().setColor(orange_red.modulateOpacity(0.5f)));
535 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
536}
537
538TEST_P(AiksTest, StrokedRectsRenderCorrectly) {
539 DisplayListBuilder builder;
540 builder.Scale(GetContentScale().x, GetContentScale().y);
541
542 DlPaint paint;
543 paint.setColor(DlColor::kPurple());
544 paint.setDrawStyle(DlDrawStyle::kStroke);
545 paint.setStrokeWidth(20.0f);
546
547 DlPaint thin_paint = paint;
548 thin_paint.setColor(DlColor::kYellow());
549 thin_paint.setStrokeWidth(0.0f);
550
551 DlRect rect = DlRect::MakeLTRB(10, 10, 90, 90);
552 DlRect thin_tall_rect = DlRect::MakeLTRB(120, 10, 120, 90);
553 DlRect thin_wide_rect = DlRect::MakeLTRB(10, 120, 90, 120);
554 DlRect empty_rect = DlRect::MakeLTRB(120, 120, 120, 120);
555
556 // We draw the following sets of rectangles:
557 //
558 // A E X
559 // X
560 // B F X
561 // X
562 // C D G H X
563 //
564 // Purple A,B,C,D are all drawn with stroke width 20 (non-overflowing).
565 // Each of those sets has 4 rectangles of dimension 80x80, 80x0, 0x80,
566 // and 0,0 to demonstrate the basic behavior and also the behavior of
567 // empty dimensions.
568 //
569 // Blue E,F,G,H are the same 80x80 rectangles, but with an overflowing
570 // stroke width of 120 to show the behavior with degenerately large
571 // stroke widths.
572 //
573 // A,E are drawn with Bevel joins.
574 // B,F are drawn with Round joins.
575 // C,G are drawn with Miter joins and a large enough miter limit.
576 // D,H are drawn with Miter joins and a too small miter limit (== Bevel).
577 //
578 // All orange X rectangles are drawn with round joins and increasing stroke
579 // widths to demonstrate fidelity of the rounding code at various arc sizes.
580 // These X rectangles also help test that the variable sizing estimates in
581 // the round join code are accurate.
582
583 // rects (A)
584 paint.setStrokeJoin(DlStrokeJoin::kBevel);
585 builder.DrawRect(rect.Shift({100, 100}), paint);
586 builder.DrawRect(rect.Shift({100, 100}), thin_paint);
587 builder.DrawRect(thin_tall_rect.Shift({100, 100}), paint);
588 builder.DrawRect(thin_tall_rect.Shift({100, 100}), thin_paint);
589 builder.DrawRect(thin_wide_rect.Shift({100, 100}), paint);
590 builder.DrawRect(thin_wide_rect.Shift({100, 100}), thin_paint);
591 builder.DrawRect(empty_rect.Shift({100, 100}), paint);
592 builder.DrawRect(empty_rect.Shift({100, 100}), thin_paint);
593
594 // rects (B)
595 paint.setStrokeJoin(DlStrokeJoin::kRound);
596 builder.DrawRect(rect.Shift({100, 300}), paint);
597 builder.DrawRect(rect.Shift({100, 300}), thin_paint);
598 builder.DrawRect(thin_tall_rect.Shift({100, 300}), paint);
599 builder.DrawRect(thin_tall_rect.Shift({100, 300}), thin_paint);
600 builder.DrawRect(thin_wide_rect.Shift({100, 300}), paint);
601 builder.DrawRect(thin_wide_rect.Shift({100, 300}), thin_paint);
602 builder.DrawRect(empty_rect.Shift({100, 300}), paint);
603 builder.DrawRect(empty_rect.Shift({100, 300}), thin_paint);
604
605 // rects (C)
606 paint.setStrokeJoin(DlStrokeJoin::kMiter);
608 builder.DrawRect(rect.Shift({100, 500}), paint);
609 builder.DrawRect(rect.Shift({100, 500}), thin_paint);
610 builder.DrawRect(thin_tall_rect.Shift({100, 500}), paint);
611 builder.DrawRect(thin_tall_rect.Shift({100, 500}), thin_paint);
612 builder.DrawRect(thin_wide_rect.Shift({100, 500}), paint);
613 builder.DrawRect(thin_wide_rect.Shift({100, 500}), thin_paint);
614 builder.DrawRect(empty_rect.Shift({100, 500}), paint);
615 builder.DrawRect(empty_rect.Shift({100, 500}), thin_paint);
616
617 // rects (D)
618 paint.setStrokeJoin(DlStrokeJoin::kMiter);
620 builder.DrawRect(rect.Shift({300, 500}), paint);
621 builder.DrawRect(rect.Shift({300, 500}), thin_paint);
622 builder.DrawRect(thin_tall_rect.Shift({300, 500}), paint);
623 builder.DrawRect(thin_tall_rect.Shift({300, 500}), thin_paint);
624 builder.DrawRect(thin_wide_rect.Shift({300, 500}), paint);
625 builder.DrawRect(thin_wide_rect.Shift({300, 500}), thin_paint);
626 builder.DrawRect(empty_rect.Shift({300, 500}), paint);
627 builder.DrawRect(empty_rect.Shift({300, 500}), thin_paint);
628
629 paint.setStrokeWidth(120.0f);
630 paint.setColor(DlColor::kBlue());
631 rect = rect.Expand(-20);
632
633 // rect (E)
634 paint.setStrokeJoin(DlStrokeJoin::kBevel);
635 builder.DrawRect(rect.Shift({500, 100}), paint);
636 builder.DrawRect(rect.Shift({500, 100}), thin_paint);
637
638 // rect (F)
639 paint.setStrokeJoin(DlStrokeJoin::kRound);
640 builder.DrawRect(rect.Shift({500, 300}), paint);
641 builder.DrawRect(rect.Shift({500, 300}), thin_paint);
642
643 // rect (G)
644 paint.setStrokeJoin(DlStrokeJoin::kMiter);
646 builder.DrawRect(rect.Shift({500, 500}), paint);
647 builder.DrawRect(rect.Shift({500, 500}), thin_paint);
648
649 // rect (H)
650 paint.setStrokeJoin(DlStrokeJoin::kMiter);
652 builder.DrawRect(rect.Shift({700, 500}), paint);
653 builder.DrawRect(rect.Shift({700, 500}), thin_paint);
654
655 DlPaint round_mock_paint;
656 round_mock_paint.setColor(DlColor::kGreen());
657 round_mock_paint.setDrawStyle(DlDrawStyle::kFill);
658
659 // array of rects (X)
660 Scalar x = 900;
661 Scalar y = 50;
662 for (int i = 0; i < 15; i++) {
663 paint.setStrokeWidth(i);
664 paint.setColor(DlColor::kOrange());
665 paint.setStrokeJoin(DlStrokeJoin::kRound);
666 builder.DrawRect(DlRect::MakeXYWH(x, y, 30, 30), paint);
667 y += 32 + i;
668 }
669
670 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
671}
672
673TEST_P(AiksTest, FilledCirclesRenderCorrectly) {
674 DisplayListBuilder builder;
675 builder.Scale(GetContentScale().x, GetContentScale().y);
676 DlPaint paint;
677 const int color_count = 3;
678 DlColor colors[color_count] = {
681 DlColor::RGBA(220.0f / 255.0f, 20.0f / 255.0f, 60.0f / 255.0f, 1.0f),
682 };
683
684 paint.setColor(DlColor::kWhite());
685 builder.DrawPaint(paint);
686
687 int c_index = 0;
688 int radius = 600;
689 while (radius > 0) {
690 paint.setColor(colors[(c_index++) % color_count]);
691 builder.DrawCircle(DlPoint(10, 10), radius, paint);
692 if (radius > 30) {
693 radius -= 10;
694 } else {
695 radius -= 2;
696 }
697 }
698
699 DlColor gradient_colors[7] = {
700 DlColor::RGBA(0x1f / 255.0, 0.0, 0x5c / 255.0, 1.0),
701 DlColor::RGBA(0x5b / 255.0, 0.0, 0x60 / 255.0, 1.0),
702 DlColor::RGBA(0x87 / 255.0, 0x01 / 255.0, 0x60 / 255.0, 1.0),
703 DlColor::RGBA(0xac / 255.0, 0x25 / 255.0, 0x53 / 255.0, 1.0),
704 DlColor::RGBA(0xe1 / 255.0, 0x6b / 255.0, 0x5c / 255.0, 1.0),
705 DlColor::RGBA(0xf3 / 255.0, 0x90 / 255.0, 0x60 / 255.0, 1.0),
706 DlColor::RGBA(0xff / 255.0, 0xb5 / 255.0, 0x6b / 250.0, 1.0),
707 };
708 DlScalar stops[7] = {
709 0.0,
710 (1.0 / 6.0) * 1,
711 (1.0 / 6.0) * 2,
712 (1.0 / 6.0) * 3,
713 (1.0 / 6.0) * 4,
714 (1.0 / 6.0) * 5,
715 1.0,
716 };
717 auto texture = CreateTextureForFixture("airplane.jpg",
718 /*enable_mipmapping=*/true);
720
722 DlPoint(500, 600), 75, 7, gradient_colors, stops, DlTileMode::kMirror));
723 builder.DrawCircle(DlPoint(500, 600), 100, paint);
724
725 DlMatrix local_matrix = DlMatrix::MakeTranslation({700, 200});
727 image, DlTileMode::kRepeat, DlTileMode::kRepeat,
728 DlImageSampling::kNearestNeighbor, &local_matrix));
729 builder.DrawCircle(DlPoint(800, 300), 100, paint);
730
731 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
732}
733
734TEST_P(AiksTest, DrawThinStrokedCircle) {
735 auto callback = [&]() {
736 static float stroked_radius = 100.0;
737 static float stroke_width = 0.0;
738 static float stroke_width_fine = 2.0;
739 static float stroked_alpha = 255.0;
740 static float stroked_scale[2] = {1.0, 1.0};
741
742 if (IsPlaygroundEnabled()) {
743 ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
744 ImGui::SliderFloat("Stroked Radius", &stroked_radius, 0, 500);
745 ImGui::SliderFloat("Stroked Width", &stroke_width, 0, 500);
746 ImGui::SliderFloat("Stroked Width Fine", &stroke_width_fine, 0, 5);
747 ImGui::SliderFloat("Stroked Alpha", &stroked_alpha, 0, 10.0);
748 ImGui::SliderFloat2("Stroked Scale", stroked_scale, 0, 10.0);
749 ImGui::End();
750 }
751
753
754 DlPaint background_paint;
755 background_paint.setColor(DlColor(1, 0.1, 0.1, 0.1, DlColorSpace::kSRGB));
756 builder.DrawPaint(background_paint);
757
758 flutter::DlPaint paint;
759
760 paint.setColor(flutter::DlColor::kRed().withAlpha(stroked_alpha));
762 paint.setStrokeWidth(stroke_width + stroke_width_fine);
763 builder.Save();
764 builder.Translate(250, 250);
765 builder.Scale(stroked_scale[0], stroked_scale[1]);
766 builder.Translate(-250, -250);
767 builder.DrawCircle(DlPoint(250, 250), stroked_radius, paint);
768 builder.Restore();
769 return builder.Build();
770 };
771
772 ASSERT_TRUE(OpenPlaygroundHere(callback));
773}
774
775TEST_P(AiksTest, StrokedCirclesRenderCorrectly) {
776 DisplayListBuilder builder;
777 builder.Scale(GetContentScale().x, GetContentScale().y);
778 DlPaint paint;
779 const int color_count = 3;
780 DlColor colors[color_count] = {
783 DlColor::RGBA(220.0f / 255.0f, 20.0f / 255.0f, 60.0f / 255.0f, 1.0f),
784 };
785
786 paint.setColor(DlColor::kWhite());
787 builder.DrawPaint(paint);
788
789 int c_index = 0;
790
791 auto draw = [&paint, &colors, &c_index](DlCanvas& canvas, DlPoint center,
792 Scalar r, Scalar dr, int n) {
793 for (int i = 0; i < n; i++) {
794 paint.setColor(colors[(c_index++) % color_count]);
795 canvas.DrawCircle(center, r, paint);
796 r += dr;
797 }
798 };
799
800 paint.setDrawStyle(DlDrawStyle::kStroke);
801 paint.setStrokeWidth(1);
802 draw(builder, DlPoint(10, 10), 2, 2, 14); // r = [2, 28], covers [1,29]
803 paint.setStrokeWidth(5);
804 draw(builder, DlPoint(10, 10), 35, 10, 56); // r = [35, 585], covers [30,590]
805
806 DlColor gradient_colors[7] = {
807 DlColor::RGBA(0x1f / 255.0, 0.0, 0x5c / 255.0, 1.0),
808 DlColor::RGBA(0x5b / 255.0, 0.0, 0x60 / 255.0, 1.0),
809 DlColor::RGBA(0x87 / 255.0, 0x01 / 255.0, 0x60 / 255.0, 1.0),
810 DlColor::RGBA(0xac / 255.0, 0x25 / 255.0, 0x53 / 255.0, 1.0),
811 DlColor::RGBA(0xe1 / 255.0, 0x6b / 255.0, 0x5c / 255.0, 1.0),
812 DlColor::RGBA(0xf3 / 255.0, 0x90 / 255.0, 0x60 / 255.0, 1.0),
813 DlColor::RGBA(0xff / 255.0, 0xb5 / 255.0, 0x6b / 250.0, 1.0),
814 };
815 DlScalar stops[7] = {
816 0.0,
817 (1.0 / 6.0) * 1,
818 (1.0 / 6.0) * 2,
819 (1.0 / 6.0) * 3,
820 (1.0 / 6.0) * 4,
821 (1.0 / 6.0) * 5,
822 1.0,
823 };
824 auto texture = CreateTextureForFixture("airplane.jpg",
825 /*enable_mipmapping=*/true);
827
829 DlPoint(500, 600), 75, 7, gradient_colors, stops, DlTileMode::kMirror));
830 draw(builder, DlPoint(500, 600), 5, 10, 10);
831
832 DlMatrix local_matrix = DlMatrix::MakeTranslation({700, 200});
834 image, DlTileMode::kRepeat, DlTileMode::kRepeat,
835 DlImageSampling::kNearestNeighbor, &local_matrix));
836 draw(builder, DlPoint(800, 300), 5, 10, 10);
837
838 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
839}
840
841namespace {
842DlPath ManuallyConstructCirclePath(Scalar radius) {
843 DlPathBuilder path_builder;
844 // Circle as 4 cubic bezier segments (standard circle approximation)
845 // Using kappa = 0.5522847498 for circular arc approximation
846 const Scalar k = 0.5522847498f;
847
848 path_builder.MoveTo(DlPoint(0.0f, -radius)); // Top
849 // Top to Right
850 path_builder.CubicCurveTo(DlPoint(radius * k, -radius), //
851 DlPoint(radius, -radius * k), //
852 DlPoint(radius, 0.0f));
853 // Right to Bottom
854 path_builder.CubicCurveTo(DlPoint(radius, radius * k), //
855 DlPoint(radius * k, radius), //
856 DlPoint(0.0f, radius));
857 // Bottom to Left
858 path_builder.CubicCurveTo(DlPoint(-radius * k, radius), //
859 DlPoint(-radius, radius * k), //
860 DlPoint(-radius, 0.0f));
861 // Left to Top
862 path_builder.CubicCurveTo(DlPoint(-radius, -radius * k), //
863 DlPoint(-radius * k, -radius), //
864 DlPoint(0.0f, -radius));
865 path_builder.Close();
866 return path_builder.TakePath();
867}
868
869void DrawStrokedAndFilledCirclesWithZoom(AiksTest* test,
870 Scalar zoom,
871 Scalar radius,
872 Scalar stroke_width) {
873 DisplayListBuilder builder;
874 builder.Scale(test->GetContentScale().x, test->GetContentScale().y);
875 builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc);
876
877 DlPaint fill_paint;
878 fill_paint.setColor(DlColor::kBlue());
879
880 DlPaint stroke_paint;
881 stroke_paint.setColor(DlColor::kGreen());
882 stroke_paint.setDrawStyle(DlDrawStyle::kStroke);
883 stroke_paint.setStrokeWidth(stroke_width);
884
885 DlPath path = ManuallyConstructCirclePath(radius);
886
887 constexpr Scalar kLeftX = 300.0f;
888 constexpr Scalar kRightX = 680.0f;
889 constexpr Scalar kTopY = 200.0f;
890 constexpr Scalar kBottomY = 580.0f;
891
892 // Upper left quadrant is fill + stroke
893 builder.Save();
894 builder.Translate(kLeftX, kTopY);
895 builder.Scale(zoom, zoom);
896 builder.DrawPath(path, fill_paint);
897 builder.DrawPath(path, stroke_paint);
898 builder.Restore();
899
900 // Upper right quadrant is fill only
901 builder.Save();
902 builder.Translate(kRightX, kTopY);
903 builder.Scale(zoom, zoom);
904 builder.DrawPath(path, fill_paint);
905 builder.Restore();
906
907 // Lower left quadrant is stroke only
908 builder.Save();
909 builder.Translate(kLeftX, kBottomY);
910 builder.Scale(zoom, zoom);
911 builder.DrawPath(path, stroke_paint);
912 builder.Restore();
913
914 // Lower right quadrant is a filled circle the size of the radius and
915 // the stroke combined for comparison to the stroked outlines.
916 builder.Save();
917 builder.Translate(kRightX, kBottomY);
918 builder.Scale(zoom, zoom);
919 builder.DrawCircle({}, radius + stroke_width * 0.5f, fill_paint);
920 builder.Restore();
921
922 ASSERT_TRUE(test->OpenPlaygroundHere(builder.Build()));
923}
924} // namespace
925
926TEST_P(AiksTest, ZoomedStrokedPathRendersCorrectly) {
927 DrawStrokedAndFilledCirclesWithZoom(this, /*zoom=*/80.0f, /*radius=*/2.0f,
928 /*stroke_width=*/0.05f);
929}
930
931TEST_P(AiksTest, StrokedPathWithLargeStrokeWidthRendersCorrectly) {
932 DrawStrokedAndFilledCirclesWithZoom(this, /*zoom=*/1.0f, /*radius=*/1.0f,
933 /*stroke_width=*/5.0f);
934}
935
936TEST_P(AiksTest, FilledEllipsesRenderCorrectly) {
937 DisplayListBuilder builder;
938 builder.Scale(GetContentScale().x, GetContentScale().y);
939 DlPaint paint;
940 const int color_count = 3;
941 DlColor colors[color_count] = {
944 DlColor::RGBA(220.0f / 255.0f, 20.0f / 255.0f, 60.0f / 255.0f, 1.0f),
945 };
946
947 paint.setColor(DlColor::kWhite());
948 builder.DrawPaint(paint);
949
950 int c_index = 0;
951 int long_radius = 600;
952 int short_radius = 600;
953 while (long_radius > 0 && short_radius > 0) {
954 paint.setColor(colors[(c_index++) % color_count]);
955 builder.DrawOval(
956 DlRect::MakeEllipseBounds({10, 10}, Size(long_radius, short_radius)),
957 paint);
958 builder.DrawOval(
959 DlRect::MakeEllipseBounds({1000, 750}, Size(short_radius, long_radius)),
960 paint);
961 if (short_radius > 30) {
962 short_radius -= 10;
963 long_radius -= 5;
964 } else {
965 short_radius -= 2;
966 long_radius -= 1;
967 }
968 }
969
970 DlColor gradient_colors[7] = {
971 DlColor::RGBA(0x1f / 255.0, 0.0, 0x5c / 255.0, 1.0),
972 DlColor::RGBA(0x5b / 255.0, 0.0, 0x60 / 255.0, 1.0),
973 DlColor::RGBA(0x87 / 255.0, 0x01 / 255.0, 0x60 / 255.0, 1.0),
974 DlColor::RGBA(0xac / 255.0, 0x25 / 255.0, 0x53 / 255.0, 1.0),
975 DlColor::RGBA(0xe1 / 255.0, 0x6b / 255.0, 0x5c / 255.0, 1.0),
976 DlColor::RGBA(0xf3 / 255.0, 0x90 / 255.0, 0x60 / 255.0, 1.0),
977 DlColor::RGBA(0xff / 255.0, 0xb5 / 255.0, 0x6b / 250.0, 1.0),
978 };
979 DlScalar stops[7] = {
980 0.0,
981 (1.0 / 6.0) * 1,
982 (1.0 / 6.0) * 2,
983 (1.0 / 6.0) * 3,
984 (1.0 / 6.0) * 4,
985 (1.0 / 6.0) * 5,
986 1.0,
987 };
988 auto texture = CreateTextureForFixture("airplane.jpg",
989 /*enable_mipmapping=*/true);
991
992 paint.setColor(DlColor::kWhite().modulateOpacity(0.5));
993
995 DlPoint(300, 650), 75, 7, gradient_colors, stops, DlTileMode::kMirror));
996 builder.DrawOval(DlRect::MakeXYWH(200, 625, 200, 50), paint);
997 builder.DrawOval(DlRect::MakeXYWH(275, 550, 50, 200), paint);
998
999 DlMatrix local_matrix = DlMatrix::MakeTranslation({610, 15});
1001 image, DlTileMode::kRepeat, DlTileMode::kRepeat,
1002 DlImageSampling::kNearestNeighbor, &local_matrix));
1003 builder.DrawOval(DlRect::MakeXYWH(610, 90, 200, 50), paint);
1004 builder.DrawOval(DlRect::MakeXYWH(685, 15, 50, 200), paint);
1005
1006 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1007}
1008
1009namespace {
1010struct ArcFarmOptions {
1011 bool use_center = false;
1012 bool full_circles = false;
1013 bool sweeps_over_360 = false;
1015};
1016
1017void RenderArcFarm(DisplayListBuilder& builder,
1018 const DlPaint& paint,
1019 const ArcFarmOptions& opts) {
1020 builder.Save();
1021 builder.Translate(50, 50);
1022 const Rect arc_bounds = Rect::MakeLTRB(0, 0, 42, 42 * opts.vertical_scale);
1023 const int sweep_limit = opts.sweeps_over_360 ? 420 : 360;
1024 for (int start = 0; start <= 360; start += 30) {
1025 builder.Save();
1026 for (int sweep = 30; sweep <= sweep_limit; sweep += 30) {
1027 builder.DrawArc(arc_bounds, start, opts.full_circles ? 360 : sweep,
1028 opts.use_center, paint);
1029 builder.Translate(50, 0);
1030 }
1031 builder.Restore();
1032 builder.Translate(0, 50);
1033 }
1034 builder.Restore();
1035}
1036
1037void RenderArcFarmForOverlappingCapsTest(DisplayListBuilder& builder,
1038 const DlPaint& paint) {
1039 builder.Save();
1040 builder.Translate(40, 30);
1041 const Rect arc_bounds = Rect::MakeLTRB(0, 0, 40, 40);
1042 for (int stroke_width = 10; stroke_width <= 40; stroke_width += 3) {
1043 DlPaint modified_paint = DlPaint(paint);
1044 modified_paint.setStrokeWidth(stroke_width);
1045 builder.Save();
1046 for (int sweep = 160; sweep <= 360; sweep += 20) {
1047 builder.DrawArc(arc_bounds, 0, sweep, false, modified_paint);
1048 builder.Translate(84, 0);
1049 }
1050 builder.Restore();
1051 builder.Translate(0, 44 + stroke_width);
1052 }
1053 builder.Restore();
1054}
1055} // namespace
1056
1057TEST_P(AiksTest, FilledArcsRenderCorrectly) {
1058 DisplayListBuilder builder;
1059 builder.Scale(GetContentScale().x, GetContentScale().y);
1060 builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc);
1061
1062 DlPaint paint;
1063 paint.setColor(DlColor::kBlue());
1064
1065 RenderArcFarm(builder, paint,
1066 {
1067 .use_center = false,
1068 .full_circles = false,
1069 });
1070
1071 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1072}
1073
1074TEST_P(AiksTest, TranslucentFilledArcsRenderCorrectly) {
1075 DisplayListBuilder builder;
1076 builder.Scale(GetContentScale().x, GetContentScale().y);
1077 builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc);
1078
1079 DlPaint paint;
1080 paint.setColor(DlColor::kBlue().modulateOpacity(0.5));
1081
1082 RenderArcFarm(builder, paint,
1083 {
1084 .use_center = false,
1085 .full_circles = false,
1086 });
1087
1088 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1089}
1090
1091TEST_P(AiksTest, FilledArcsRenderCorrectlyWithCenter) {
1092 DisplayListBuilder builder;
1093 builder.Scale(GetContentScale().x, GetContentScale().y);
1094 builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc);
1095
1096 DlPaint paint;
1097 paint.setColor(DlColor::kBlue());
1098
1099 RenderArcFarm(builder, paint,
1100 {
1101 .use_center = true,
1102 .full_circles = false,
1103 });
1104
1105 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1106}
1107
1108TEST_P(AiksTest, NonSquareFilledArcsRenderCorrectly) {
1109 DisplayListBuilder builder;
1110 builder.Scale(GetContentScale().x, GetContentScale().y);
1111 builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc);
1112
1113 DlPaint paint;
1114 paint.setColor(DlColor::kBlue());
1115
1116 RenderArcFarm(builder, paint,
1117 {
1118 .use_center = false,
1119 .full_circles = false,
1120 .vertical_scale = 0.8f,
1121 });
1122
1123 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1124}
1125
1126TEST_P(AiksTest, NonSquareFilledArcsRenderCorrectlyWithCenter) {
1127 DisplayListBuilder builder;
1128 builder.Scale(GetContentScale().x, GetContentScale().y);
1129 builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc);
1130
1131 DlPaint paint;
1132 paint.setColor(DlColor::kBlue());
1133
1134 RenderArcFarm(builder, paint,
1135 {
1136 .use_center = true,
1137 .full_circles = false,
1138 .vertical_scale = 0.8f,
1139 });
1140
1141 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1142}
1143
1144TEST_P(AiksTest, StrokedArcsRenderCorrectlyWithButtEnds) {
1145 DisplayListBuilder builder;
1146 builder.Scale(GetContentScale().x, GetContentScale().y);
1147 builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc);
1148
1149 DlPaint paint;
1150 paint.setDrawStyle(DlDrawStyle::kStroke);
1151 paint.setStrokeWidth(6.0f);
1152 paint.setStrokeCap(DlStrokeCap::kButt);
1153 paint.setColor(DlColor::kBlue());
1154
1155 RenderArcFarm(builder, paint,
1156 {
1157 .use_center = false,
1158 .full_circles = false,
1159 });
1160
1161 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1162}
1163
1164TEST_P(AiksTest, StrokedArcsRenderCorrectlyWithSquareEnds) {
1165 DisplayListBuilder builder;
1166 builder.Scale(GetContentScale().x, GetContentScale().y);
1167 builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc);
1168
1169 DlPaint paint;
1170 paint.setDrawStyle(DlDrawStyle::kStroke);
1171 paint.setStrokeWidth(6.0f);
1172 paint.setStrokeCap(DlStrokeCap::kSquare);
1173 paint.setColor(DlColor::kBlue());
1174
1175 RenderArcFarm(builder, paint,
1176 {
1177 .use_center = false,
1178 .full_circles = false,
1179 });
1180
1181 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1182}
1183
1184TEST_P(AiksTest, StrokedArcsRenderCorrectlyWithTranslucencyAndSquareEnds) {
1185 DisplayListBuilder builder;
1186 builder.Scale(GetContentScale().x, GetContentScale().y);
1187 builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc);
1188
1189 DlPaint paint;
1190 paint.setDrawStyle(DlDrawStyle::kStroke);
1191 paint.setStrokeCap(DlStrokeCap::kSquare);
1192 paint.setColor(DlColor::kBlue().modulateOpacity(0.5));
1193
1194 RenderArcFarmForOverlappingCapsTest(builder, paint);
1195
1196 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1197}
1198
1199TEST_P(AiksTest, StrokedArcsRenderCorrectlyWithRoundEnds) {
1200 DisplayListBuilder builder;
1201 builder.Scale(GetContentScale().x, GetContentScale().y);
1202 builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc);
1203
1204 DlPaint paint;
1205 paint.setDrawStyle(DlDrawStyle::kStroke);
1206 paint.setStrokeWidth(6.0f);
1207 paint.setStrokeCap(DlStrokeCap::kRound);
1208 paint.setColor(DlColor::kBlue());
1209
1210 RenderArcFarm(builder, paint,
1211 {
1212 .use_center = false,
1213 .full_circles = false,
1214 });
1215
1216 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1217}
1218
1219TEST_P(AiksTest, StrokedArcsRenderCorrectlyWithTranslucencyAndRoundEnds) {
1220 DisplayListBuilder builder;
1221 builder.Scale(GetContentScale().x, GetContentScale().y);
1222 builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc);
1223
1224 DlPaint paint;
1225 paint.setDrawStyle(DlDrawStyle::kStroke);
1226 paint.setStrokeCap(DlStrokeCap::kRound);
1227 paint.setColor(DlColor::kBlue().modulateOpacity(0.5));
1228
1229 RenderArcFarmForOverlappingCapsTest(builder, paint);
1230
1231 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1232}
1233
1234TEST_P(AiksTest, StrokedArcsRenderCorrectlyWithBevelJoinsAndCenter) {
1235 DisplayListBuilder builder;
1236 builder.Scale(GetContentScale().x, GetContentScale().y);
1237 builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc);
1238
1239 DlPaint paint;
1240 paint.setDrawStyle(DlDrawStyle::kStroke);
1241 paint.setStrokeWidth(6.0f);
1242 paint.setStrokeJoin(DlStrokeJoin::kBevel);
1243 paint.setColor(DlColor::kBlue());
1244
1245 RenderArcFarm(builder, paint,
1246 {
1247 .use_center = true,
1248 .full_circles = false,
1249 .sweeps_over_360 = true,
1250 });
1251
1252 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1253}
1254
1255TEST_P(AiksTest, StrokedArcsRenderCorrectlyWithMiterJoinsAndCenter) {
1256 DisplayListBuilder builder;
1257 builder.Scale(GetContentScale().x, GetContentScale().y);
1258 builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc);
1259
1260 DlPaint paint;
1261 paint.setDrawStyle(DlDrawStyle::kStroke);
1262 paint.setStrokeWidth(6.0f);
1263 paint.setStrokeJoin(DlStrokeJoin::kMiter);
1264 // Default miter of 4.0 does a miter on all of the centers, but
1265 // using 3.0 will show some bevels on the widest interior angles...
1266 paint.setStrokeMiter(3.0f);
1267 paint.setColor(DlColor::kBlue());
1268
1269 RenderArcFarm(builder, paint,
1270 {
1271 .use_center = true,
1272 .full_circles = false,
1273 .sweeps_over_360 = true,
1274 });
1275
1276 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1277}
1278
1279TEST_P(AiksTest, StrokedArcsRenderCorrectlyWithRoundJoinsAndCenter) {
1280 DisplayListBuilder builder;
1281 builder.Scale(GetContentScale().x, GetContentScale().y);
1282 builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc);
1283
1284 DlPaint paint;
1285 paint.setDrawStyle(DlDrawStyle::kStroke);
1286 paint.setStrokeWidth(6.0f);
1287 paint.setStrokeJoin(DlStrokeJoin::kRound);
1288 paint.setColor(DlColor::kBlue());
1289
1290 RenderArcFarm(builder, paint,
1291 {
1292 .use_center = true,
1293 .full_circles = false,
1294 .sweeps_over_360 = true,
1295 });
1296
1297 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1298}
1299
1300TEST_P(AiksTest, StrokedArcsRenderCorrectlyWithSquareAndButtEnds) {
1301 DisplayListBuilder builder;
1302 builder.Scale(GetContentScale().x, GetContentScale().y);
1303 builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc);
1304
1305 DlPaint paint;
1306 paint.setDrawStyle(DlDrawStyle::kStroke);
1307 paint.setStrokeWidth(8.0f);
1308 paint.setStrokeCap(DlStrokeCap::kSquare);
1309 paint.setColor(DlColor::kRed());
1310
1311 RenderArcFarm(builder, paint,
1312 {
1313 .use_center = false,
1314 .full_circles = false,
1315 });
1316
1317 paint.setStrokeCap(DlStrokeCap::kButt);
1318 paint.setColor(DlColor::kBlue());
1319
1320 RenderArcFarm(builder, paint,
1321 {
1322 .use_center = false,
1323 .full_circles = false,
1324 });
1325
1326 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1327}
1328
1329TEST_P(AiksTest, StrokedArcsRenderCorrectlyWithSquareAndButtAndRoundEnds) {
1330 DisplayListBuilder builder;
1331 builder.Scale(GetContentScale().x, GetContentScale().y);
1332 builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc);
1333
1334 DlPaint paint;
1335 paint.setDrawStyle(DlDrawStyle::kStroke);
1336 paint.setStrokeWidth(8.0f);
1337 paint.setStrokeCap(DlStrokeCap::kSquare);
1338 paint.setColor(DlColor::kRed());
1339
1340 RenderArcFarm(builder, paint,
1341 {
1342 .use_center = false,
1343 .full_circles = false,
1344 });
1345
1346 paint.setStrokeCap(DlStrokeCap::kRound);
1347 paint.setColor(DlColor::kGreen());
1348
1349 RenderArcFarm(builder, paint,
1350 {
1351 .use_center = false,
1352 .full_circles = false,
1353 });
1354
1355 paint.setStrokeCap(DlStrokeCap::kButt);
1356 paint.setColor(DlColor::kBlue());
1357
1358 RenderArcFarm(builder, paint,
1359 {
1360 .use_center = false,
1361 .full_circles = false,
1362 });
1363
1364 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1365}
1366
1367TEST_P(AiksTest, StrokedArcsCoverFullArcWithButtEnds) {
1368 // This test compares the rendering of a full circle arc against a partial
1369 // arc by drawing a one over the other in high contrast. If the partial
1370 // arc misses any pixels that were drawn by the full arc, there will be
1371 // some "pixel dirt" around the missing "erased" parts of the arcs. This
1372 // case arises while rendering a CircularProgressIndicator with a background
1373 // color where we want the rendering of the background full arc to hit the
1374 // same pixels around the edges as the partial arc that covers it.
1375 //
1376 // In this case we draw a full blue circle and then draw a partial arc
1377 // over it in the background color (white).
1378
1379 DisplayListBuilder builder;
1380 builder.Scale(GetContentScale().x, GetContentScale().y);
1381 builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc);
1382
1383 DlPaint paint;
1384 paint.setDrawStyle(DlDrawStyle::kStroke);
1385 paint.setStrokeWidth(6.0f);
1386 paint.setStrokeCap(DlStrokeCap::kButt);
1387 paint.setColor(DlColor::kBlue());
1388
1389 // First draw full circles in blue to establish the pixels to be erased
1390 RenderArcFarm(builder, paint,
1391 {
1392 .use_center = false,
1393 .full_circles = true,
1394 });
1395
1396 paint.setColor(DlColor::kWhite());
1397
1398 // Then draw partial arcs in white over the circles to "erase" them
1399 RenderArcFarm(builder, paint,
1400 {
1401 .use_center = false,
1402 .full_circles = false,
1403 });
1404
1405 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1406}
1407
1408TEST_P(AiksTest, FilledRoundRectsRenderCorrectly) {
1409 DisplayListBuilder builder;
1410 builder.Scale(GetContentScale().x, GetContentScale().y);
1411 DlPaint paint;
1412 const int color_count = 3;
1413 DlColor colors[color_count] = {
1416 DlColor::RGBA(220.0f / 255.0f, 20.0f / 255.0f, 60.0f / 255.0f, 1.0f),
1417 };
1418
1419 paint.setColor(DlColor::kWhite());
1420 builder.DrawPaint(paint);
1421
1422 int c_index = 0;
1423 for (int i = 0; i < 4; i++) {
1424 for (int j = 0; j < 4; j++) {
1425 paint.setColor(colors[(c_index++) % color_count]);
1426 builder.DrawRoundRect(
1428 DlRect::MakeXYWH(i * 100 + 10, j * 100 + 20, 80, 80), //
1429 i * 5 + 10, j * 5 + 10),
1430 paint);
1431 }
1432 }
1433 paint.setColor(colors[(c_index++) % color_count]);
1434 builder.DrawRoundRect(
1435 DlRoundRect::MakeRectXY(DlRect::MakeXYWH(10, 420, 380, 80), 40, 40),
1436 paint);
1437 paint.setColor(colors[(c_index++) % color_count]);
1438 builder.DrawRoundRect(
1439 DlRoundRect::MakeRectXY(DlRect::MakeXYWH(410, 20, 80, 380), 40, 40),
1440 paint);
1441
1442 DlColor gradient_colors[7] = {
1443 DlColor::RGBA(0x1f / 255.0, 0.0, 0x5c / 255.0, 1.0),
1444 DlColor::RGBA(0x5b / 255.0, 0.0, 0x60 / 255.0, 1.0),
1445 DlColor::RGBA(0x87 / 255.0, 0x01 / 255.0, 0x60 / 255.0, 1.0),
1446 DlColor::RGBA(0xac / 255.0, 0x25 / 255.0, 0x53 / 255.0, 1.0),
1447 DlColor::RGBA(0xe1 / 255.0, 0x6b / 255.0, 0x5c / 255.0, 1.0),
1448 DlColor::RGBA(0xf3 / 255.0, 0x90 / 255.0, 0x60 / 255.0, 1.0),
1449 DlColor::RGBA(0xff / 255.0, 0xb5 / 255.0, 0x6b / 250.0, 1.0),
1450 };
1451 DlScalar stops[7] = {
1452 0.0,
1453 (1.0 / 6.0) * 1,
1454 (1.0 / 6.0) * 2,
1455 (1.0 / 6.0) * 3,
1456 (1.0 / 6.0) * 4,
1457 (1.0 / 6.0) * 5,
1458 1.0,
1459 };
1460 auto texture = CreateTextureForFixture("airplane.jpg",
1461 /*enable_mipmapping=*/true);
1463
1464 paint.setColor(DlColor::kWhite().modulateOpacity(0.1));
1466 DlPoint(550, 550), 75, 7, gradient_colors, stops, DlTileMode::kMirror));
1467 for (int i = 1; i <= 10; i++) {
1468 int j = 11 - i;
1469 builder.DrawRoundRect(
1470 DlRoundRect::MakeRectXY(DlRect::MakeLTRB(550 - i * 20, 550 - j * 20, //
1471 550 + i * 20, 550 + j * 20),
1472 i * 10, j * 10),
1473 paint);
1474 }
1475
1476 paint.setColor(DlColor::kWhite().modulateOpacity(0.5));
1478 DlPoint(200, 650), 75, 7, gradient_colors, stops, DlTileMode::kMirror));
1479 paint.setColor(DlColor::kWhite().modulateOpacity(0.5));
1480 builder.DrawRoundRect(
1481 DlRoundRect::MakeRectXY(DlRect::MakeLTRB(100, 610, 300, 690), 40, 40),
1482 paint);
1483 builder.DrawRoundRect(
1484 DlRoundRect::MakeRectXY(DlRect::MakeLTRB(160, 550, 240, 750), 40, 40),
1485 paint);
1486
1487 paint.setColor(DlColor::kWhite().modulateOpacity(0.1));
1488 DlMatrix local_matrix = DlMatrix::MakeTranslation({520, 20});
1490 image, DlTileMode::kRepeat, DlTileMode::kRepeat,
1491 DlImageSampling::kNearestNeighbor, &local_matrix));
1492 for (int i = 1; i <= 10; i++) {
1493 int j = 11 - i;
1494 builder.DrawRoundRect(
1495 DlRoundRect::MakeRectXY(DlRect::MakeLTRB(720 - i * 20, 220 - j * 20, //
1496 720 + i * 20, 220 + j * 20),
1497 i * 10, j * 10),
1498 paint);
1499 }
1500
1501 paint.setColor(DlColor::kWhite().modulateOpacity(0.5));
1502 local_matrix = DlMatrix::MakeTranslation({800, 300});
1504 image, DlTileMode::kRepeat, DlTileMode::kRepeat,
1505 DlImageSampling::kNearestNeighbor, &local_matrix));
1506 builder.DrawRoundRect(
1507 DlRoundRect::MakeRectXY(DlRect::MakeLTRB(800, 410, 1000, 490), 40, 40),
1508 paint);
1509 builder.DrawRoundRect(
1510 DlRoundRect::MakeRectXY(DlRect::MakeLTRB(860, 350, 940, 550), 40, 40),
1511 paint);
1512
1513 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1514}
1515
1516TEST_P(AiksTest, SolidColorCirclesOvalsRRectsMaskBlurCorrectly) {
1517 DisplayListBuilder builder;
1518 builder.Scale(GetContentScale().x, GetContentScale().y);
1519 DlPaint paint;
1520 paint.setMaskFilter(DlBlurMaskFilter::Make(DlBlurStyle::kNormal, 1.0f));
1521
1522 builder.DrawPaint(DlPaint().setColor(DlColor::kWhite()));
1523
1524 paint.setColor(
1525 DlColor::RGBA(220.0f / 255.0f, 20.0f / 255.0f, 60.0f / 255.0f, 1.0f));
1526 Scalar y = 100.0f;
1527 for (int i = 0; i < 5; i++) {
1528 Scalar x = (i + 1) * 100;
1529 Scalar radius = x / 10.0f;
1530 builder.DrawRect(DlRect::MakeXYWH(x + 25 - radius / 2, y + radius / 2, //
1531 radius, 60.0f - radius),
1532 paint);
1533 }
1534
1535 paint.setColor(DlColor::kBlue());
1536 y += 100.0f;
1537 for (int i = 0; i < 5; i++) {
1538 Scalar x = (i + 1) * 100;
1539 Scalar radius = x / 10.0f;
1540 builder.DrawCircle(DlPoint(x + 25, y + 25), radius, paint);
1541 }
1542
1543 paint.setColor(DlColor::kGreen());
1544 y += 100.0f;
1545 for (int i = 0; i < 5; i++) {
1546 Scalar x = (i + 1) * 100;
1547 Scalar radius = x / 10.0f;
1548 builder.DrawOval(DlRect::MakeXYWH(x + 25 - radius / 2, y + radius / 2, //
1549 radius, 60.0f - radius),
1550 paint);
1551 }
1552
1553 paint.setColor(
1554 DlColor::RGBA(128.0f / 255.0f, 0.0f / 255.0f, 128.0f / 255.0f, 1.0f));
1555 y += 100.0f;
1556 for (int i = 0; i < 5; i++) {
1557 Scalar x = (i + 1) * 100;
1558 Scalar radius = x / 20.0f;
1559 builder.DrawRoundRect(
1560 DlRoundRect::MakeRectXY(DlRect::MakeXYWH(x, y, 60.0f, 60.0f), //
1561 radius, radius),
1562 paint);
1563 }
1564
1565 paint.setColor(
1566 DlColor::RGBA(255.0f / 255.0f, 165.0f / 255.0f, 0.0f / 255.0f, 1.0f));
1567 y += 100.0f;
1568 for (int i = 0; i < 5; i++) {
1569 Scalar x = (i + 1) * 100;
1570 Scalar radius = x / 20.0f;
1571 builder.DrawRoundRect(
1572 DlRoundRect::MakeRectXY(DlRect::MakeXYWH(x, y, 60.0f, 60.0f), //
1573 radius, 5.0f),
1574 paint);
1575 }
1576
1577 auto dl = builder.Build();
1578 ASSERT_TRUE(OpenPlaygroundHere(dl));
1579}
1580
1581TEST_P(AiksTest, CanRenderClippedBackdropFilter) {
1582 DisplayListBuilder builder;
1583
1584 builder.Scale(GetContentScale().x, GetContentScale().y);
1585
1586 // Draw something interesting in the background.
1587 std::vector<DlColor> colors = {DlColor::RGBA(0.9568, 0.2627, 0.2118, 1.0),
1588 DlColor::RGBA(0.1294, 0.5882, 0.9529, 1.0)};
1589 std::vector<Scalar> stops = {
1590 0.0,
1591 1.0,
1592 };
1593 DlPaint paint;
1595 /*start_point=*/DlPoint(0, 0), //
1596 /*end_point=*/DlPoint(100, 100), //
1597 /*stop_count=*/2, //
1598 /*colors=*/colors.data(), //
1599 /*stops=*/stops.data(), //
1600 /*tile_mode=*/DlTileMode::kRepeat //
1601 ));
1602
1603 builder.DrawPaint(paint);
1604
1605 DlRect clip_rect = DlRect::MakeLTRB(50, 50, 400, 300);
1606 DlRoundRect clip_rrect = DlRoundRect::MakeRectXY(clip_rect, 100, 100);
1607
1608 // Draw a clipped SaveLayer, where the clip coverage and SaveLayer size are
1609 // the same.
1610 builder.ClipRoundRect(clip_rrect, DlClipOp::kIntersect);
1611
1612 DlPaint save_paint;
1613 auto backdrop_filter = DlImageFilter::MakeColorFilter(
1614 DlColorFilter::MakeBlend(DlColor::kRed(), DlBlendMode::kExclusion));
1615 builder.SaveLayer(clip_rect, &save_paint, backdrop_filter.get());
1616
1617 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1618}
1619
1620TEST_P(AiksTest, CanDrawPerspectiveTransformWithClips) {
1621 // Avoiding `GetSecondsElapsed()` to reduce risk of golden flakiness.
1622 int time = 0;
1623 auto callback = [&]() -> sk_sp<DisplayList> {
1624 DisplayListBuilder builder;
1625
1626 builder.Save();
1627 {
1628 builder.Translate(300, 300);
1629
1630 // 1. Draw/restore a clip before drawing the image, which will get drawn
1631 // to the depth buffer behind the image.
1632 builder.Save();
1633 {
1634 DlPaint paint;
1635 paint.setColor(DlColor::kGreen());
1636 builder.DrawPaint(paint);
1637 builder.ClipRect(DlRect::MakeLTRB(-180, -180, 180, 180),
1638 DlClipOp::kDifference);
1639
1640 paint.setColor(DlColor::kBlack());
1641 builder.DrawPaint(paint);
1642 }
1643 builder.Restore(); // Restore rectangle difference clip.
1644
1645 builder.Save();
1646 {
1647 // 2. Draw an oval clip that applies to the image, which will get drawn
1648 // in front of the image on the depth buffer.
1649 builder.ClipOval(DlRect::MakeLTRB(-200, -200, 200, 200));
1650
1651 Matrix result =
1652 Matrix(1.0, 0.0, 0.0, 0.0, //
1653 0.0, 1.0, 0.0, 0.0, //
1654 0.0, 0.0, 1.0, 0.003, //
1655 0.0, 0.0, 0.0, 1.0) *
1656 Matrix::MakeRotationY({Radians{-1.0f + (time++ / 60.0f)}});
1657
1658 // 3. Draw the rotating image with a perspective transform.
1659 builder.Transform(result);
1660
1661 auto image =
1662 DlImageImpeller::Make(CreateTextureForFixture("airplane.jpg"));
1663 auto position =
1664 -DlPoint(image->GetSize().width, image->GetSize().height) * 0.5;
1665 builder.DrawImage(image, position, {});
1666 }
1667 builder.Restore(); // Restore oval intersect clip.
1668
1669 // 4. Draw a semi-translucent blue circle atop all previous draws.
1670 DlPaint paint;
1671 paint.setColor(DlColor::kBlue().modulateOpacity(0.4));
1672 builder.DrawCircle(DlPoint(), 230, paint);
1673 }
1674 builder.Restore(); // Restore translation.
1675
1676 return builder.Build();
1677 };
1678 ASSERT_TRUE(OpenPlaygroundHere(callback));
1679}
1680
1681TEST_P(AiksTest, ImageColorSourceEffectTransform) {
1682 // Compare with https://fiddle.skia.org/c/6cdc5aefb291fda3833b806ca347a885
1683
1684 DisplayListBuilder builder;
1685 auto texture = DlImageImpeller::Make(CreateTextureForFixture("monkey.png"));
1686
1687 DlPaint paint;
1688 paint.setColor(DlColor::kWhite());
1689 builder.DrawPaint(paint);
1690
1691 // Translation
1692 {
1693 DlMatrix matrix = DlMatrix::MakeTranslation({50, 50});
1694 DlPaint paint;
1696 texture, DlTileMode::kRepeat, DlTileMode::kRepeat,
1697 DlImageSampling::kNearestNeighbor, &matrix));
1698
1699 builder.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100), paint);
1700 }
1701
1702 // Rotation/skew
1703 {
1704 builder.Save();
1705 builder.Rotate(45);
1706 DlPaint paint;
1707
1708 Matrix matrix(1, -1, 0, 0, //
1709 1, 1, 0, 0, //
1710 0, 0, 1, 0, //
1711 0, 0, 0, 1);
1713 texture, DlTileMode::kRepeat, DlTileMode::kRepeat,
1714 DlImageSampling::kNearestNeighbor, &matrix));
1715 builder.DrawRect(DlRect::MakeLTRB(100, 0, 200, 100), paint);
1716 builder.Restore();
1717 }
1718
1719 // Scale
1720 {
1721 builder.Save();
1722 builder.Translate(100, 0);
1723 builder.Scale(100, 100);
1724 DlPaint paint;
1725
1726 DlMatrix matrix = DlMatrix::MakeScale({0.005, 0.005, 1});
1728 texture, DlTileMode::kRepeat, DlTileMode::kRepeat,
1729 DlImageSampling::kNearestNeighbor, &matrix));
1730
1731 builder.DrawRect(DlRect::MakeLTRB(0, 0, 1, 1), paint);
1732 builder.Restore();
1733 }
1734
1735 // Perspective
1736 {
1737 builder.Save();
1738 builder.Translate(150, 150);
1739 DlPaint paint;
1740
1741 DlMatrix matrix =
1742 DlMatrix::MakePerspective(Radians{0.5}, ISize{200, 200}, 0.05, 1);
1744 texture, DlTileMode::kRepeat, DlTileMode::kRepeat,
1745 DlImageSampling::kNearestNeighbor, &matrix));
1746
1747 builder.DrawRect(DlRect::MakeLTRB(0, 0, 200, 200), paint);
1748 builder.Restore();
1749 }
1750
1751 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1752}
1753
1754TEST_P(AiksTest, SubpassWithClearColorOptimization) {
1755 DisplayListBuilder builder;
1756
1757 // Use a non-srcOver blend mode to ensure that we don't detect this as an
1758 // opacity peephole optimization.
1759 DlPaint paint;
1760 paint.setColor(DlColor::kBlue().modulateOpacity(0.5));
1761 paint.setBlendMode(DlBlendMode::kSrc);
1762
1763 DlRect bounds = DlRect::MakeLTRB(0, 0, 200, 200);
1764 builder.SaveLayer(bounds, &paint);
1765
1767 paint.setBlendMode(DlBlendMode::kSrc);
1768 builder.DrawPaint(paint);
1769 builder.Restore();
1770
1771 paint.setColor(DlColor::kBlue());
1772 paint.setBlendMode(DlBlendMode::kDstOver);
1773 builder.SaveLayer(std::nullopt, &paint);
1774 builder.Restore();
1775
1776 // This playground should appear blank on CI since we are only drawing
1777 // transparent black. If the clear color optimization is broken, the texture
1778 // will be filled with NaNs and may produce a magenta texture on macOS or iOS.
1779 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1780}
1781
1782// Render a white circle at the top left corner of the screen.
1783TEST_P(AiksTest, MatrixImageFilterDoesntCullWhenTranslatedFromOffscreen) {
1784 DisplayListBuilder builder;
1785 builder.Scale(GetContentScale().x, GetContentScale().y);
1786 builder.Translate(100, 100);
1787 // Draw a circle in a SaveLayer at -300, but move it back on-screen with a
1788 // +300 translation applied by a SaveLayer image filter.
1789 DlPaint paint;
1790 DlMatrix translate = DlMatrix::MakeTranslation({300, 0});
1791 paint.setImageFilter(
1792 DlImageFilter::MakeMatrix(translate, DlImageSampling::kLinear));
1793 builder.SaveLayer(std::nullopt, &paint);
1794
1795 DlPaint circle_paint;
1796 circle_paint.setColor(DlColor::kGreen());
1797 builder.DrawCircle(DlPoint(-300, 0), 100, circle_paint);
1798 builder.Restore();
1799
1800 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1801}
1802
1803// Render a white circle at the top left corner of the screen.
1805 MatrixImageFilterDoesntCullWhenScaledAndTranslatedFromOffscreen) {
1806 DisplayListBuilder builder;
1807 builder.Scale(GetContentScale().x, GetContentScale().y);
1808 builder.Translate(100, 100);
1809 // Draw a circle in a SaveLayer at -300, but move it back on-screen with a
1810 // +300 translation applied by a SaveLayer image filter.
1811
1812 DlPaint paint;
1814 DlMatrix::MakeTranslation({300, 0}) * DlMatrix::MakeScale({2, 2, 1}),
1815 DlImageSampling::kNearestNeighbor));
1816 builder.SaveLayer(std::nullopt, &paint);
1817
1818 DlPaint circle_paint;
1819 circle_paint.setColor(DlColor::kGreen());
1820 builder.DrawCircle(DlPoint(-150, 0), 50, circle_paint);
1821 builder.Restore();
1822
1823 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1824}
1825
1826// This should be solid red, if you see a little red box this is broken.
1827TEST_P(AiksTest, ClearColorOptimizationWhenSubpassIsBiggerThanParentPass) {
1828 SetWindowSize({400, 400});
1829 DisplayListBuilder builder;
1830
1831 builder.Scale(GetContentScale().x, GetContentScale().y);
1832
1833 DlPaint paint;
1834 paint.setColor(DlColor::kRed());
1835 builder.DrawRect(DlRect::MakeLTRB(200, 200, 300, 300), paint);
1836
1838 DlImageSampling::kLinear));
1839 builder.SaveLayer(std::nullopt, &paint);
1840 // Draw a rectangle that would fully cover the parent pass size, but not
1841 // the subpass that it is rendered in.
1842 paint.setColor(DlColor::kGreen());
1843 builder.DrawRect(DlRect::MakeLTRB(0, 0, 400, 400), paint);
1844 // Draw a bigger rectangle to force the subpass to be bigger.
1845
1846 paint.setColor(DlColor::kRed());
1847 builder.DrawRect(DlRect::MakeLTRB(0, 0, 800, 800), paint);
1848 builder.Restore();
1849
1850 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1851}
1852
1853TEST_P(AiksTest, EmptySaveLayerIgnoresPaint) {
1854 DisplayListBuilder builder;
1855 builder.Scale(GetContentScale().x, GetContentScale().y);
1856
1857 DlPaint paint;
1858 paint.setColor(DlColor::kRed());
1859 builder.DrawPaint(paint);
1860 builder.ClipRect(DlRect::MakeXYWH(100, 100, 200, 200));
1861 paint.setColor(DlColor::kBlue());
1862 builder.SaveLayer(std::nullopt, &paint);
1863 builder.Restore();
1864
1865 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1866}
1867
1868TEST_P(AiksTest, EmptySaveLayerRendersWithClear) {
1869 DisplayListBuilder builder;
1870 builder.Scale(GetContentScale().x, GetContentScale().y);
1871 auto image = DlImageImpeller::Make(CreateTextureForFixture("airplane.jpg"));
1872 builder.DrawImage(image, DlPoint(10, 10), {});
1873 builder.ClipRect(DlRect::MakeXYWH(100, 100, 200, 200));
1874
1875 DlPaint paint;
1876 paint.setBlendMode(DlBlendMode::kClear);
1877 builder.SaveLayer(std::nullopt, &paint);
1878 builder.Restore();
1879
1880 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1881}
1882
1884 CanPerformSaveLayerWithBoundsAndLargerIntermediateIsNotAllocated) {
1885 DisplayListBuilder builder;
1886
1887 DlPaint red;
1888 red.setColor(DlColor::kRed());
1889
1890 DlPaint green;
1891 green.setColor(DlColor::kGreen());
1892
1893 DlPaint blue;
1894 blue.setColor(DlColor::kBlue());
1895
1896 DlPaint save;
1897 save.setColor(DlColor::kBlack().modulateOpacity(0.5));
1898
1899 DlRect huge_bounds = DlRect::MakeXYWH(0, 0, 100000, 100000);
1900 builder.SaveLayer(huge_bounds, &save);
1901
1902 builder.DrawRect(DlRect::MakeXYWH(0, 0, 100, 100), red);
1903 builder.DrawRect(DlRect::MakeXYWH(10, 10, 100, 100), green);
1904 builder.DrawRect(DlRect::MakeXYWH(20, 20, 100, 100), blue);
1905
1906 builder.Restore();
1907
1908 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1909}
1910
1911// This makes sure the WideGamut named tests use 10-bit wide gamut pixel format.
1912TEST_P(AiksTest, FormatWideGamut) {
1913 // Must be called before any methods that use the context to ensure that
1914 // this test is always run with wide gamut support.
1915 if (!EnsureContextSupportsWideGamut()) {
1916 GTEST_SKIP() << "This backend doesn't yet support wide gamut.";
1917 }
1918
1919 EXPECT_EQ(GetContext()->GetCapabilities()->GetDefaultColorFormat(),
1921}
1922
1923TEST_P(AiksTest, FormatSRGB) {
1924 PixelFormat pixel_format =
1925 GetContext()->GetCapabilities()->GetDefaultColorFormat();
1926 EXPECT_TRUE(pixel_format == PixelFormat::kR8G8B8A8UNormInt ||
1927 pixel_format == PixelFormat::kB8G8R8A8UNormInt)
1928 << "pixel format: " << PixelFormatToString(pixel_format);
1929}
1930
1931TEST_P(AiksTest, CoordinateConversionsAreCorrect) {
1932 DisplayListBuilder builder;
1933
1934 // Render a texture directly.
1935 {
1936 auto image = DlImageImpeller::Make(CreateTextureForFixture("kalimba.jpg"));
1937
1938 builder.Save();
1939 builder.Translate(100, 200);
1940 builder.Scale(0.5, 0.5);
1941 builder.DrawImage(image, DlPoint(100.0, 100.0),
1942 DlImageSampling::kNearestNeighbor);
1943 builder.Restore();
1944 }
1945
1946 // Render an offscreen rendered texture.
1947 {
1948 DlPaint alpha;
1949 alpha.setColor(DlColor::kRed().modulateOpacity(0.5));
1950
1951 builder.SaveLayer(std::nullopt, &alpha);
1952
1953 DlPaint paint;
1954 paint.setColor(DlColor::kRed());
1955 builder.DrawRect(DlRect::MakeXYWH(000, 000, 100, 100), paint);
1956 paint.setColor(DlColor::kGreen());
1957 builder.DrawRect(DlRect::MakeXYWH(020, 020, 100, 100), paint);
1958 paint.setColor(DlColor::kBlue());
1959 builder.DrawRect(DlRect::MakeXYWH(040, 040, 100, 100), paint);
1960
1961 builder.Restore();
1962 }
1963
1964 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1965}
1966
1967TEST_P(AiksTest, CanPerformFullScreenMSAA) {
1968 DisplayListBuilder builder;
1969
1970 DlPaint paint;
1971 paint.setColor(DlColor::kRed());
1972 builder.DrawCircle(DlPoint(250, 250), 125, paint);
1973
1974 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1975}
1976
1977TEST_P(AiksTest, CanPerformSkew) {
1978 DisplayListBuilder builder;
1979
1980 DlPaint red;
1981 red.setColor(DlColor::kRed());
1982 builder.Skew(2, 5);
1983 builder.DrawRect(DlRect::MakeXYWH(0, 0, 100, 100), red);
1984
1985 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1986}
1987
1988TEST_P(AiksTest, CanPerformSaveLayerWithBounds) {
1989 DisplayListBuilder builder;
1990
1991 DlPaint save;
1992 save.setColor(DlColor::kBlack());
1993
1994 DlRect save_bounds = DlRect::MakeXYWH(0, 0, 50, 50);
1995 builder.SaveLayer(save_bounds, &save);
1996
1997 DlPaint paint;
1998 paint.setColor(DlColor::kRed());
1999 builder.DrawRect(DlRect::MakeXYWH(0, 0, 100, 100), paint);
2000 paint.setColor(DlColor::kGreen());
2001 builder.DrawRect(DlRect::MakeXYWH(10, 10, 100, 100), paint);
2002 paint.setColor(DlColor::kBlue());
2003 builder.DrawRect(DlRect::MakeXYWH(20, 20, 100, 100), paint);
2004
2005 builder.Restore();
2006
2007 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
2008}
2009
2010TEST_P(AiksTest, FilledRoundRectPathsRenderCorrectly) {
2011 DisplayListBuilder builder;
2012 builder.Scale(GetContentScale().x, GetContentScale().y);
2013
2014 DlPaint paint;
2015 const int color_count = 3;
2016 DlColor colors[color_count] = {
2019 DlColor::ARGB(1.0, 220.0f / 255.0f, 20.0f / 255.0f, 60.0f / 255.0f),
2020 };
2021
2022 paint.setColor(DlColor::kWhite());
2023 builder.DrawPaint(paint);
2024
2025 auto draw_rrect_as_path = [&builder](const DlRect& rect, Scalar x, Scalar y,
2026 const DlPaint& paint) {
2027 builder.DrawPath(DlPath::MakeRoundRectXY(rect, x, y), paint);
2028 };
2029
2030 int c_index = 0;
2031 for (int i = 0; i < 4; i++) {
2032 for (int j = 0; j < 4; j++) {
2033 paint.setColor(colors[(c_index++) % color_count]);
2034 draw_rrect_as_path(DlRect::MakeXYWH(i * 100 + 10, j * 100 + 20, 80, 80),
2035 i * 5 + 10, j * 5 + 10, paint);
2036 }
2037 }
2038 paint.setColor(colors[(c_index++) % color_count]);
2039 draw_rrect_as_path(DlRect::MakeXYWH(10, 420, 380, 80), 40, 40, paint);
2040 paint.setColor(colors[(c_index++) % color_count]);
2041 draw_rrect_as_path(DlRect::MakeXYWH(410, 20, 80, 380), 40, 40, paint);
2042
2043 std::vector<DlColor> gradient_colors = {
2044 DlColor::RGBA(0x1f / 255.0, 0.0, 0x5c / 255.0, 1.0),
2045 DlColor::RGBA(0x5b / 255.0, 0.0, 0x60 / 255.0, 1.0),
2046 DlColor::RGBA(0x87 / 255.0, 0x01 / 255.0, 0x60 / 255.0, 1.0),
2047 DlColor::RGBA(0xac / 255.0, 0x25 / 255.0, 0x53 / 255.0, 1.0),
2048 DlColor::RGBA(0xe1 / 255.0, 0x6b / 255.0, 0x5c / 255.0, 1.0),
2049 DlColor::RGBA(0xf3 / 255.0, 0x90 / 255.0, 0x60 / 255.0, 1.0),
2050 DlColor::RGBA(0xff / 255.0, 0xb5 / 255.0, 0x6b / 250.0, 1.0)};
2051 std::vector<Scalar> stops = {
2052 0.0,
2053 (1.0 / 6.0) * 1,
2054 (1.0 / 6.0) * 2,
2055 (1.0 / 6.0) * 3,
2056 (1.0 / 6.0) * 4,
2057 (1.0 / 6.0) * 5,
2058 1.0,
2059 };
2061 CreateTextureForFixture("airplane.jpg",
2062 /*enable_mipmapping=*/true));
2063
2064 paint.setColor(DlColor::kWhite().modulateOpacity(0.1));
2066 /*center=*/DlPoint(550, 550),
2067 /*radius=*/75,
2068 /*stop_count=*/gradient_colors.size(),
2069 /*colors=*/gradient_colors.data(),
2070 /*stops=*/stops.data(),
2071 /*tile_mode=*/DlTileMode::kMirror));
2072 for (int i = 1; i <= 10; i++) {
2073 int j = 11 - i;
2074 draw_rrect_as_path(DlRect::MakeLTRB(550 - i * 20, 550 - j * 20, //
2075 550 + i * 20, 550 + j * 20),
2076 i * 10, j * 10, paint);
2077 }
2078 paint.setColor(DlColor::kWhite().modulateOpacity(0.5));
2080 /*center=*/DlPoint(200, 650),
2081 /*radius=*/75,
2082 /*stop_count=*/gradient_colors.size(),
2083 /*colors=*/gradient_colors.data(),
2084 /*stops=*/stops.data(),
2085 /*tile_mode=*/DlTileMode::kMirror));
2086 draw_rrect_as_path(DlRect::MakeLTRB(100, 610, 300, 690), 40, 40, paint);
2087 draw_rrect_as_path(DlRect::MakeLTRB(160, 550, 240, 750), 40, 40, paint);
2088
2089 auto matrix = DlMatrix::MakeTranslation({520, 20});
2090 paint.setColor(DlColor::kWhite().modulateOpacity(0.1));
2092 texture, DlTileMode::kRepeat, DlTileMode::kRepeat,
2093 DlImageSampling::kMipmapLinear, &matrix));
2094 for (int i = 1; i <= 10; i++) {
2095 int j = 11 - i;
2096 draw_rrect_as_path(DlRect::MakeLTRB(720 - i * 20, 220 - j * 20, //
2097 720 + i * 20, 220 + j * 20),
2098 i * 10, j * 10, paint);
2099 }
2100 matrix = DlMatrix::MakeTranslation({800, 300});
2101 paint.setColor(DlColor::kWhite().modulateOpacity(0.5));
2103 texture, DlTileMode::kRepeat, DlTileMode::kRepeat,
2104 DlImageSampling::kMipmapLinear, &matrix));
2105
2106 draw_rrect_as_path(DlRect::MakeLTRB(800, 410, 1000, 490), 40, 40, paint);
2107 draw_rrect_as_path(DlRect::MakeLTRB(860, 350, 940, 550), 40, 40, paint);
2108
2109 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
2110}
2111
2112TEST_P(AiksTest, CoverageOriginShouldBeAccountedForInSubpasses) {
2113 auto callback = [&]() -> sk_sp<DisplayList> {
2114 DisplayListBuilder builder;
2115 builder.Scale(GetContentScale().x, GetContentScale().y);
2116
2117 DlPaint alpha;
2119
2120 auto current = Point{25, 25};
2121 const auto offset = Point{25, 25};
2122 const auto size = Size(100, 100);
2123
2124 static PlaygroundPoint point_a(Point(40, 40), 10, Color::White());
2125 static PlaygroundPoint point_b(Point(160, 160), 10, Color::White());
2126 auto [b0, b1] = DrawPlaygroundLine(point_a, point_b);
2127 DlRect bounds = DlRect::MakeLTRB(b0.x, b0.y, b1.x, b1.y);
2128
2129 DlPaint stroke_paint;
2130 stroke_paint.setColor(DlColor::kYellow());
2131 stroke_paint.setStrokeWidth(5);
2132 stroke_paint.setDrawStyle(DlDrawStyle::kStroke);
2133 builder.DrawRect(bounds, stroke_paint);
2134
2135 builder.SaveLayer(bounds, &alpha);
2136
2137 DlPaint paint;
2138 paint.setColor(DlColor::kRed());
2139 builder.DrawRect(
2140 DlRect::MakeXYWH(current.x, current.y, size.width, size.height), paint);
2141
2142 paint.setColor(DlColor::kGreen());
2143 current += offset;
2144 builder.DrawRect(
2145 DlRect::MakeXYWH(current.x, current.y, size.width, size.height), paint);
2146
2147 paint.setColor(DlColor::kBlue());
2148 current += offset;
2149 builder.DrawRect(
2150 DlRect::MakeXYWH(current.x, current.y, size.width, size.height), paint);
2151
2152 builder.Restore();
2153
2154 return builder.Build();
2155 };
2156
2157 ASSERT_TRUE(OpenPlaygroundHere(callback));
2158}
2159
2160TEST_P(AiksTest, SaveLayerDrawsBehindSubsequentEntities) {
2161 // Compare with https://fiddle.skia.org/c/9e03de8567ffb49e7e83f53b64bcf636
2162 DisplayListBuilder builder;
2163 DlPaint paint;
2164
2165 paint.setColor(DlColor::kBlack());
2166 DlRect rect = DlRect::MakeXYWH(25, 25, 25, 25);
2167 builder.DrawRect(rect, paint);
2168
2169 builder.Translate(10, 10);
2170
2171 DlPaint save_paint;
2172 builder.SaveLayer(std::nullopt, &save_paint);
2173
2174 paint.setColor(DlColor::kGreen());
2175 builder.DrawRect(rect, paint);
2176
2177 builder.Restore();
2178
2179 builder.Translate(10, 10);
2180 paint.setColor(DlColor::kRed());
2181 builder.DrawRect(rect, paint);
2182
2183 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
2184}
2185
2186TEST_P(AiksTest, SiblingSaveLayerBoundsAreRespected) {
2187 DisplayListBuilder builder;
2188 DlPaint paint;
2189 DlRect rect = DlRect::MakeXYWH(0, 0, 1000, 1000);
2190
2191 // Black, green, and red squares offset by [10, 10].
2192 {
2193 DlPaint save_paint;
2194 DlRect bounds = DlRect::MakeXYWH(25, 25, 25, 25);
2195 builder.SaveLayer(bounds, &save_paint);
2196 paint.setColor(DlColor::kBlack());
2197 builder.DrawRect(rect, paint);
2198 builder.Restore();
2199 }
2200
2201 {
2202 DlPaint save_paint;
2203 DlRect bounds = DlRect::MakeXYWH(35, 35, 25, 25);
2204 builder.SaveLayer(bounds, &save_paint);
2205 paint.setColor(DlColor::kGreen());
2206 builder.DrawRect(rect, paint);
2207 builder.Restore();
2208 }
2209
2210 {
2211 DlPaint save_paint;
2212 DlRect bounds = DlRect::MakeXYWH(45, 45, 25, 25);
2213 builder.SaveLayer(bounds, &save_paint);
2214 paint.setColor(DlColor::kRed());
2215 builder.DrawRect(rect, paint);
2216 builder.Restore();
2217 }
2218
2219 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
2220}
2221
2222TEST_P(AiksTest, CanRenderClippedLayers) {
2223 DisplayListBuilder builder;
2224
2225 DlPaint paint;
2226 paint.setColor(DlColor::kWhite());
2227 builder.DrawPaint(paint);
2228
2229 // Draw a green circle on the screen.
2230 {
2231 // Increase the clip depth for the savelayer to contend with.
2232 DlPath path = DlPath::MakeCircle(DlPoint(100, 100), 50);
2233 builder.ClipPath(path);
2234
2235 DlRect bounds = DlRect::MakeXYWH(50, 50, 100, 100);
2236 DlPaint save_paint;
2237 builder.SaveLayer(bounds, &save_paint);
2238
2239 // Fill the layer with white.
2240 paint.setColor(DlColor::kWhite());
2241 builder.DrawRect(DlRect::MakeSize(DlSize(400, 400)), paint);
2242 // Fill the layer with green, but do so with a color blend that can't be
2243 // collapsed into the parent pass.
2244 paint.setColor(DlColor::kGreen());
2245 paint.setBlendMode(DlBlendMode::kHardLight);
2246 builder.DrawRect(DlRect::MakeSize(DlSize(400, 400)), paint);
2247 }
2248
2249 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
2250}
2251
2252TEST_P(AiksTest, SaveLayerFiltersScaleWithTransform) {
2253 DisplayListBuilder builder;
2254
2255 builder.Scale(GetContentScale().x, GetContentScale().y);
2256 builder.Translate(100, 100);
2257
2258 auto texture = DlImageImpeller::Make(CreateTextureForFixture("boston.jpg"));
2259 auto draw_image_layer = [&builder, &texture](const DlPaint& paint) {
2260 builder.SaveLayer(std::nullopt, &paint);
2261 builder.DrawImage(texture, DlPoint(), DlImageSampling::kLinear);
2262 builder.Restore();
2263 };
2264
2265 DlPaint effect_paint;
2266 effect_paint.setMaskFilter(DlBlurMaskFilter::Make(DlBlurStyle::kNormal, 6));
2267 draw_image_layer(effect_paint);
2268
2269 builder.Translate(300, 300);
2270 builder.Scale(3, 3);
2271 draw_image_layer(effect_paint);
2272
2273 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
2274}
2275
2276TEST_P(AiksTest, FastEllipticalRRectMaskBlursRenderCorrectly) {
2277 DisplayListBuilder builder;
2278
2279 builder.Scale(GetContentScale().x, GetContentScale().y);
2280 DlPaint paint;
2281 paint.setMaskFilter(DlBlurMaskFilter::Make(DlBlurStyle::kNormal, 1));
2282
2283 DlPaint save_paint;
2284 save_paint.setColor(DlColor::kWhite());
2285 builder.DrawPaint(save_paint);
2286
2287 paint.setColor(DlColor::kBlue());
2288 for (int i = 0; i < 5; i++) {
2289 Scalar y = i * 125;
2290 Scalar y_radius = i * 15;
2291 for (int j = 0; j < 5; j++) {
2292 Scalar x = j * 125;
2293 Scalar x_radius = j * 15;
2294 builder.DrawRoundRect(
2296 DlRect::MakeXYWH(x + 50, y + 50, 100.0f, 100.0f), //
2297 x_radius, y_radius),
2298 paint);
2299 }
2300 }
2301
2302 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
2303}
2304
2305TEST_P(AiksTest, PipelineBlendSingleParameter) {
2306 DisplayListBuilder builder;
2307
2308 // Should render a green square in the middle of a blue circle.
2309 DlPaint paint;
2310 builder.SaveLayer(std::nullopt, &paint);
2311 {
2312 builder.Translate(100, 100);
2313 paint.setColor(DlColor::kBlue());
2314 builder.DrawCircle(DlPoint(200, 200), 200, paint);
2315 builder.ClipRect(DlRect::MakeXYWH(100, 100, 200, 200));
2316
2317 paint.setColor(DlColor::kGreen());
2318 paint.setBlendMode(DlBlendMode::kSrcOver);
2320 DlColorFilter::MakeBlend(DlColor::kWhite(), DlBlendMode::kDst)));
2321 builder.DrawCircle(DlPoint(200, 200), 200, paint);
2322 builder.Restore();
2323 }
2324
2325 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
2326}
2327
2328// Creates an image matrix filter that scales large content such that it would
2329// exceed the max texture size. See
2330// https://github.com/flutter/flutter/issues/128912
2331TEST_P(AiksTest, MassiveScalingMatrixImageFilter) {
2332 switch (GetBackend()) {
2335 break;
2339 GTEST_SKIP() << "Platform is running out of memory on this example "
2340 << "(see https://github.com/flutter/flutter/issues/189286).";
2341 }
2342
2343 DisplayListBuilder builder(DlRect::MakeSize(DlSize(1000, 1000)));
2344
2345 auto filter = DlImageFilter::MakeMatrix(
2346 DlMatrix::MakeScale({0.001, 0.001, 1}), DlImageSampling::kLinear);
2347
2348 DlPaint paint;
2349 paint.setImageFilter(filter);
2350 builder.SaveLayer(std::nullopt, &paint);
2351 {
2352 DlPaint paint;
2353 paint.setColor(DlColor::kRed());
2354 builder.DrawRect(DlRect::MakeLTRB(0, 0, 100000, 100000), paint);
2355 }
2356 builder.Restore();
2357
2358 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
2359}
2360
2361TEST_P(AiksTest, NoDimplesInRRectPath) {
2362 Scalar width = 200.f;
2363 Scalar height = 60.f;
2364 Scalar corner = 1.f;
2365 bool stroked = true;
2366 auto callback = [&]() -> sk_sp<DisplayList> {
2367 if (IsPlaygroundEnabled()) {
2368 ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
2369 ImGui::SliderFloat("width", &width, 0, 200);
2370 ImGui::SliderFloat("height", &height, 0, 200);
2371 ImGui::SliderFloat("corner", &corner, 0, 1);
2372 ImGui::Checkbox("stroked", &stroked);
2373 ImGui::End();
2374 }
2375
2376 DisplayListBuilder builder;
2377 builder.Scale(GetContentScale().x, GetContentScale().y);
2378
2379 DlPaint background_paint;
2380 background_paint.setColor(DlColor(1, 0.1, 0.1, 0.1, DlColorSpace::kSRGB));
2381 builder.DrawPaint(background_paint);
2382
2383 std::vector<DlColor> colors = {DlColor::kRed(), DlColor::kBlue()};
2384 std::vector<Scalar> stops = {0.0, 1.0};
2385
2386 DlPaint paint;
2387 auto gradient = DlColorSource::MakeLinear(DlPoint(0, 0), DlPoint(200, 200),
2388 2, colors.data(), stops.data(),
2389 DlTileMode::kClamp);
2390 paint.setColorSource(gradient);
2391 paint.setColor(DlColor::kWhite());
2392 if (stroked) {
2393 paint.setDrawStyle(DlDrawStyle::kStroke);
2394 paint.setStrokeWidth(20);
2395 } else {
2396 paint.setDrawStyle(DlDrawStyle::kFill);
2397 }
2398
2399 builder.Save();
2400 builder.Translate(100, 100);
2401
2402 Scalar corner_x = ((1 - corner) * 50) + 50;
2403 Scalar corner_y = corner * 50 + 50;
2405 DlRect::MakeXYWH(0, 0, width, height), corner_x, corner_y);
2406 builder.DrawRoundRect(rrect, paint);
2407 builder.Restore();
2408 return builder.Build();
2409 };
2410 ASSERT_TRUE(OpenPlaygroundHere(callback));
2411}
2412
2413TEST_P(AiksTest, BackdropFilterOverUnclosedClip) {
2414 DisplayListBuilder builder;
2415
2416 builder.DrawPaint(DlPaint().setColor(DlColor::kWhite()));
2417 builder.Save();
2418 {
2419 builder.ClipRect(DlRect::MakeLTRB(100, 100, 800, 800));
2420
2421 builder.Save();
2422 {
2423 builder.ClipRect(DlRect::MakeLTRB(600, 600, 800, 800));
2424 builder.DrawPaint(DlPaint().setColor(DlColor::kRed()));
2425 builder.DrawPaint(DlPaint().setColor(DlColor::kBlue().withAlphaF(0.5)));
2426 builder.ClipRect(DlRect::MakeLTRB(700, 700, 750, 800));
2427 builder.DrawPaint(DlPaint().setColor(DlColor::kRed().withAlphaF(0.5)));
2428 }
2429 builder.Restore();
2430
2431 auto image_filter = DlImageFilter::MakeBlur(10, 10, DlTileMode::kDecal);
2432 builder.SaveLayer(std::nullopt, nullptr, image_filter.get());
2433 }
2434 builder.Restore();
2435 builder.DrawCircle(DlPoint(100, 100), 100,
2436 DlPaint().setColor(DlColor::kAqua()));
2437
2438 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
2439}
2440
2441TEST_P(AiksTest, PerspectiveRectangle) {
2442 int perspective = 58;
2443 bool use_clip = true;
2444 bool diff_clip = false;
2445
2446 auto callback = [&]() -> sk_sp<DisplayList> {
2447 if (IsPlaygroundEnabled()) {
2448 ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
2449 ImGui::SliderInt("perspective%", &perspective, 0, 100);
2450 ImGui::Checkbox("use clip", &use_clip);
2451 if (use_clip) {
2452 ImGui::Checkbox("diff clip", &diff_clip);
2453 }
2454 ImGui::SetWindowPos("Controls", ImVec2(500, 100));
2455 ImGui::End();
2456 }
2457
2458 DisplayListBuilder builder;
2459
2460 Scalar val = perspective * -0.00005f;
2462 // clang-format off
2463 1.0f, 0.0f, 0.0f, 400.0f,
2464 0.0f, 1.0f, 0.0f, 400.0f,
2465 0.0f, 0.0f, 1.0f, 0.0f,
2466 0.0f, val, 0.0f, 2.2f
2467 // clang-format on
2468 );
2469
2470 if (use_clip) {
2471 Rect clip = DlRect::MakeLTRB(0, 0, 400, 800);
2472 DlClipOp clip_op = DlClipOp::kIntersect;
2473 if (diff_clip) {
2474 clip = clip.Expand(-20);
2475 clip_op = DlClipOp::kDifference;
2476 }
2477 builder.ClipRect(clip, clip_op);
2478 }
2479
2480 DlPaint paint;
2481 paint.setColor(DlColor::kBlue());
2482 builder.DrawRect(DlRect::MakeLTRB(0, 0, 400, 800), paint);
2483
2484 builder.DrawColor(DlColor::kWhite().withAlphaF(0.5f),
2485 DlBlendMode::kSrcOver);
2486
2487 return builder.Build();
2488 };
2489 ASSERT_TRUE(OpenPlaygroundHere(callback));
2490}
2491
2492TEST_P(AiksTest, CanRenderFilledRoundSuperellipses) {
2493 DisplayListBuilder builder;
2494 builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc);
2495 DlPaint paint;
2496 paint.setColor(DlColor::kBlue());
2497
2498 // Square
2499 builder.DrawRoundSuperellipse(
2501 /*rect=*/DlRect::MakeXYWH(50, 50, 100, 100), /*radius=*/20),
2502 paint);
2503 // Tall
2504 builder.DrawRoundSuperellipse(
2506 /*rect=*/DlRect::MakeXYWH(200, 50, 60, 140), /*radius=*/20),
2507 paint);
2508 // Wide
2509 builder.DrawRoundSuperellipse(
2511 /*rect=*/DlRect::MakeXYWH(310, 50, 140, 60), /*radius=*/20),
2512 paint);
2513
2514 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
2515}
2516
2517TEST_P(AiksTest, CanRenderAsymmetricRoundSuperellipses) {
2518 DisplayListBuilder builder;
2519 builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc);
2520 DlPaint paint;
2521 paint.setColor(DlColor::kBlue());
2522
2523 builder.DrawRoundSuperellipse(
2525 /*rect=*/DlRect::MakeXYWH(50, 50, 440, 440), /*radii=*/
2526 {
2527 .top_left = Size(60.0f, 240.0f),
2528 .top_right = Size(200.0f, 40.0f),
2529 .bottom_left = Size(180.0f, 20.0f),
2530 .bottom_right = Size(40.0f, 200.0f),
2531 }),
2532 paint);
2533
2534 builder.DrawRoundSuperellipse(
2536 /*rect=*/DlRect::MakeXYWH(550, 50, 440, 440), /*radii=*/
2537 {
2538 .top_left = Size(240.0f, 40.0f),
2539 .top_right = Size(40.0f, 240.0f),
2540 .bottom_left = Size(40.0f, 240.0f),
2541 .bottom_right = Size(240.0f, 40.0f),
2542 }),
2543 paint);
2544
2545 builder.DrawRoundSuperellipse(
2547 /*rect=*/DlRect::MakeXYWH(50, 550, 400, 400), /*radii=*/
2548 {
2549 .top_left = Size(240.0f, 240.0f),
2550 .top_right = Size(40.0f, 40.0f),
2551 .bottom_left = Size(40.0f, 40.0f),
2552 .bottom_right = Size(40.0f, 40.0f),
2553 }),
2554 paint);
2555
2556 builder.DrawRoundSuperellipse(
2558 /*rect=*/DlRect::MakeXYWH(550, 550, 400, 400), /*radii=*/
2559 {
2560 .top_left = Size(240.0f, 240.0f),
2561 .top_right = Size(40.0f, 40.0f),
2562 .bottom_left = Size(40.0f, 40.0f),
2563 .bottom_right = Size(240.0f, 240.0f),
2564 }),
2565 paint);
2566
2567 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
2568}
2569
2570TEST_P(AiksTest, CanRenderStrokedRoundSuperellipses) {
2571 DisplayListBuilder builder;
2572 builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc);
2573 DlPaint paint;
2574 paint.setColor(DlColor::kBlue());
2575 paint.setDrawStyle(DlDrawStyle::kStroke);
2576 paint.setStrokeWidth(5.0f);
2577
2578 // Square
2579 builder.DrawRoundSuperellipse(
2581 /*rect=*/DlRect::MakeXYWH(50, 50, 100, 100), /*radius=*/20),
2582 paint);
2583 // Tall
2584 builder.DrawRoundSuperellipse(
2586 /*rect=*/DlRect::MakeXYWH(200, 50, 60, 140), /*radius=*/20),
2587 paint);
2588 // Wide
2589 builder.DrawRoundSuperellipse(
2591 /*rect=*/DlRect::MakeXYWH(310, 50, 140, 60), /*radius=*/20),
2592 paint);
2593
2594 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
2595}
2596
2597TEST_P(AiksTest, CanRenderSmallRadiusRoundSuperellipses) {
2598 DisplayListBuilder builder;
2599 builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc);
2600 DlPaint paint;
2601 paint.setColor(DlColor::kBlue());
2602
2603 // Square
2604 builder.DrawRoundSuperellipse(
2606 /*rect=*/DlRect::MakeXYWH(50, 50, 100, 100), /*radius=*/2),
2607 paint);
2608 // Tall
2609 builder.DrawRoundSuperellipse(
2611 /*rect=*/DlRect::MakeXYWH(200, 50, 60, 140), /*radius=*/2),
2612 paint);
2613 // Wide
2614 builder.DrawRoundSuperellipse(
2616 /*rect=*/DlRect::MakeXYWH(310, 50, 140, 60), /*radius=*/2),
2617 paint);
2618
2619 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
2620}
2621
2622TEST_P(AiksTest, CanRenderThickStrokedRoundSuperellipses) {
2623 DisplayListBuilder builder;
2624 builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc);
2625 DlPaint paint;
2626 paint.setColor(DlColor::kBlue().withAlphaF(0.5));
2627 paint.setDrawStyle(DlDrawStyle::kStroke);
2628 paint.setStrokeWidth(40.0f);
2629
2630 // Square
2631 builder.DrawRoundSuperellipse(
2633 /*rect=*/DlRect::MakeXYWH(50, 50, 100, 100), /*radius=*/30),
2634 paint);
2635 // Tall
2636 builder.DrawRoundSuperellipse(
2638 /*rect=*/DlRect::MakeXYWH(200, 50, 60, 140), /*radius=*/30),
2639 paint);
2640 // Wide
2641 builder.DrawRoundSuperellipse(
2643 /*rect=*/DlRect::MakeXYWH(310, 50, 140, 60), /*radius=*/30),
2644 paint);
2645
2646 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
2647}
2648
2649TEST_P(AiksTest, CanRenderRoundSuperellipseGrid) {
2650 DisplayListBuilder builder;
2651 builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc);
2652 DlPaint paint;
2653 paint.setColor(DlColor::kBlue());
2654
2655 DlScalar radii[] = {10.0f, 30.0f, 50.0f};
2656
2657 for (int row = 0; row < 3; row++) {
2658 DlScalar y = 50.0f + row * 170.0f;
2659 DlScalar radius = radii[row];
2660
2661 // Square
2662 builder.DrawRoundSuperellipse(
2664 /*rect=*/DlRect::MakeXYWH(50, y, 100, 100), /*radius=*/radius),
2665 paint);
2666 // Tall
2667 builder.DrawRoundSuperellipse(
2669 /*rect=*/DlRect::MakeXYWH(200, y, 60, 140), /*radius=*/radius),
2670 paint);
2671 // Wide
2672 builder.DrawRoundSuperellipse(
2674 /*rect=*/DlRect::MakeXYWH(310, y, 140, 60), /*radius=*/radius),
2675 paint);
2676 }
2677
2678 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
2679}
2680
2681TEST_P(AiksTest, CanRenderTransformedRoundSuperellipse) {
2682 DisplayListBuilder builder;
2683 builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc);
2684
2685 builder.Save();
2686 builder.Translate(200, 200);
2687 builder.Rotate(45.0f);
2688 builder.Scale(1.5f, 0.8f);
2689
2690 DlPaint paint;
2691 paint.setColor(DlColor::kBlue());
2692 builder.DrawRoundSuperellipse(
2694 /*rect=*/DlRect::MakeXYWH(-70, -30, 140, 60), /*radius=*/20),
2695 paint);
2696 builder.Restore();
2697
2698 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
2699}
2700
2701TEST_P(AiksTest, CompareAntiAliasAndNonAntiAlias) {
2702 DisplayListBuilder builder;
2703 builder.DrawColor(DlColor::kBlack(), DlBlendMode::kSrc);
2704
2705 DlPaint paint;
2706 paint.setColor(DlColor::kWhite());
2707
2708 DlRect bounds = DlRect::MakeXYWH(75, 75, 50, 50);
2709
2710 // --- Left Half: Zoom-in on the top-left corner WITH anti-aliasing (SDF) ---
2711 DlPaint layer_paint_left;
2713 DlMatrix::MakeTranslation({200, 300}) * DlMatrix::MakeScale({8, 8, 1}) *
2714 DlMatrix::MakeTranslation({-100, -100}),
2715 DlImageSampling::kNearestNeighbor));
2716 builder.SaveLayer(bounds, &layer_paint_left);
2717
2718 paint.setAntiAlias(true);
2719 builder.DrawRoundRect(
2720 DlRoundRect::MakeRectRadius(DlRect::MakeXYWH(100, 100, 200, 200), 50.0f),
2721 paint);
2722 builder.Restore();
2723
2724 // --- Right Half: Zoom-in on the top-left corner WITHOUT anti-aliasing ---
2725 DlPaint layer_paint_right;
2726 layer_paint_right.setImageFilter(DlImageFilter::MakeMatrix(
2727 DlMatrix::MakeTranslation({600, 300}) * DlMatrix::MakeScale({8, 8, 1}) *
2728 DlMatrix::MakeTranslation({-100, -100}),
2729 DlImageSampling::kNearestNeighbor));
2730 builder.SaveLayer(bounds, &layer_paint_right);
2731
2732 paint.setAntiAlias(false);
2733 builder.DrawRoundRect(
2734 DlRoundRect::MakeRectRadius(DlRect::MakeXYWH(100, 100, 200, 200), 50.0f),
2735 paint);
2736 builder.Restore();
2737
2738 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
2739}
2740
2741TEST_P(AiksTest, CompareDiffRoundRectAndRoundRect) {
2742 DisplayListBuilder builder;
2743 builder.DrawColor(DlColor::kBlack(), DlBlendMode::kSrc);
2744
2745 DlRect outer_rect = DlRect::MakeXYWH(0, 0, 100, 100);
2746 DlRoundingRadii outer_radii = {.top_left = DlSize(5.0f),
2747 .top_right = DlSize(10.0f),
2748 .bottom_left = DlSize(20.0f),
2749 .bottom_right = DlSize(50.0f)};
2750 DlRoundRect outer_rrect = DlRoundRect::MakeRectRadii(outer_rect, outer_radii);
2751
2752 DlScalar inner_inset = 5.0f;
2753 DlRect inner_rect = outer_rect.Expand(-inner_inset);
2754 DlRoundingRadii inner_radii = {
2755 .top_left = DlSize(outer_radii.top_left.width - inner_inset),
2756 .top_right = DlSize(outer_radii.top_right.width - inner_inset),
2757 .bottom_left = DlSize(outer_radii.bottom_left.width - inner_inset),
2758 .bottom_right = DlSize(outer_radii.bottom_right.width - inner_inset)};
2759 DlRoundRect inner_rrect = DlRoundRect::MakeRectRadii(inner_rect, inner_radii);
2760
2761 builder.Translate(50, 50);
2762
2763 // Draw DiffRoundRect.
2764 builder.DrawDiffRoundRect(outer_rrect, inner_rrect,
2765 DlPaint().setColor(DlColor::kSkyBlue()));
2766
2767 // Draw simalated DiffRoundRect by drawing the outer RoundRect and clearing
2768 // the inner RoundRect.
2769 builder.Translate(200, 0);
2770 builder.DrawRoundRect(outer_rrect, DlPaint().setColor(DlColor::kSkyBlue()));
2771 builder.DrawRoundRect(inner_rrect,
2772 DlPaint().setBlendMode(DlBlendMode::kClear));
2773
2774 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
2775}
2776
2777TEST_P(AiksTest, CanRenderLinesWithCapsAnglesAndAlphas) {
2778 DisplayListBuilder builder;
2779 builder.Scale(GetContentScale().x, GetContentScale().y);
2780 builder.DrawColor(DlColor::kBlack(), DlBlendMode::kSrc);
2781
2782 const float line_length = 30.0f;
2783 const float stroke_width = 10.0f;
2784 const float spacing = 50.0f;
2785
2786 const std::vector<flutter::DlStrokeCap> caps = {
2790 };
2791 const std::vector<float> alphas = {1.0f, 0.75f, 0.5f, 0.25f};
2792 const std::vector<Radians> angles = {
2793 Degrees(0.0f), Degrees(3.0f), Degrees(30.0f), Degrees(45.0f),
2794 Degrees(60.0f), Degrees(87.0f), Degrees(90.0f),
2795 };
2796
2797 DlPaint paint;
2798 paint.setDrawStyle(DlDrawStyle::kStroke);
2799 paint.setStrokeWidth(stroke_width);
2800
2801 for (const DlStrokeCap cap : caps) {
2802 builder.Translate(spacing, 0.0f);
2803 paint.setStrokeCap(cap);
2804
2805 for (const float alpha : alphas) {
2806 builder.Translate(spacing, 0.0f);
2807 paint.setColor(DlColor::kWhite().withAlphaF(alpha));
2808
2809 builder.Save();
2810 for (const Radians angle : angles) {
2811 builder.Translate(0.0f, spacing);
2812 builder.DrawLine(DlPoint(0.0f, 0.0f),
2813 DlPoint(cos(angle.radians) * line_length,
2814 sin(angle.radians) * line_length),
2815 paint);
2816 }
2817 builder.Restore();
2818 }
2819 }
2820
2821 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
2822}
2823
2824} // namespace testing
2825} // namespace impeller
Scalar vertical_scale
bool sweeps_over_360
void DrawOval(const DlRect &bounds, const DlPaint &paint) override
void ClipRect(const DlRect &rect, DlClipOp clip_op=DlClipOp::kIntersect, bool is_aa=false) override
void DrawImageRect(const sk_sp< DlImage > &image, const DlRect &src, const DlRect &dst, DlImageSampling sampling, const DlPaint *paint=nullptr, DlSrcRectConstraint constraint=DlSrcRectConstraint::kFast) override
void DrawRoundRect(const DlRoundRect &rrect, const DlPaint &paint) override
void DrawArc(const DlRect &bounds, DlScalar start, DlScalar sweep, bool useCenter, const DlPaint &paint) override
void DrawImage(const sk_sp< DlImage > &image, const DlPoint &point, DlImageSampling sampling, const DlPaint *paint=nullptr) override
void DrawColor(DlColor color, DlBlendMode mode) override
void DrawCircle(const DlPoint &center, DlScalar radius, const DlPaint &paint) override
void SaveLayer(const std::optional< DlRect > &bounds, const DlPaint *paint=nullptr, const DlImageFilter *backdrop=nullptr, std::optional< int64_t > backdrop_id=std::nullopt) override
void DrawLine(const DlPoint &p0, const DlPoint &p1, const DlPaint &paint) override
void ClipRoundRect(const DlRoundRect &rrect, DlClipOp clip_op=DlClipOp::kIntersect, bool is_aa=false) override
void Rotate(DlScalar degrees) override
void DrawRoundSuperellipse(const DlRoundSuperellipse &rse, const DlPaint &paint) override
void Scale(DlScalar sx, DlScalar sy) override
void Skew(DlScalar sx, DlScalar sy) override
void Translate(DlScalar tx, DlScalar ty) override
void DrawPaint(const DlPaint &paint) override
sk_sp< DisplayList > Build()
void DrawPath(const DlPath &path, const DlPaint &paint) override
void ClipPath(const DlPath &path, DlClipOp clip_op=DlClipOp::kIntersect, bool is_aa=false) override
void ClipOval(const DlRect &bounds, DlClipOp clip_op=DlClipOp::kIntersect, bool is_aa=false) override
void TransformFullPerspective(DlScalar mxx, DlScalar mxy, DlScalar mxz, DlScalar mxt, DlScalar myx, DlScalar myy, DlScalar myz, DlScalar myt, DlScalar mzx, DlScalar mzy, DlScalar mzz, DlScalar mzt, DlScalar mwx, DlScalar mwy, DlScalar mwz, DlScalar mwt) override
void DrawDiffRoundRect(const DlRoundRect &outer, const DlRoundRect &inner, const DlPaint &paint) override
void Transform(const DlMatrix &matrix) override
void DrawRect(const DlRect &rect, const DlPaint &paint) override
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:32
static std::shared_ptr< const DlColorFilter > MakeBlend(DlColor color, DlBlendMode mode)
static std::shared_ptr< DlColorSource > MakeImage(const sk_sp< const DlImage > &image, DlTileMode horizontal_tile_mode, DlTileMode vertical_tile_mode, DlImageSampling sampling=DlImageSampling::kLinear, const DlMatrix *matrix=nullptr)
static std::shared_ptr< DlColorSource > MakeLinear(const DlPoint start_point, const DlPoint end_point, uint32_t stop_count, const DlColor *colors, const float *stops, DlTileMode tile_mode, const DlMatrix *matrix=nullptr)
static std::shared_ptr< DlColorSource > MakeRadial(DlPoint center, DlScalar radius, uint32_t stop_count, const DlColor *colors, const float *stops, DlTileMode tile_mode, const DlMatrix *matrix=nullptr)
static std::shared_ptr< DlImageFilter > MakeBlur(DlScalar sigma_x, DlScalar sigma_y, DlTileMode tile_mode)
static std::shared_ptr< DlImageFilter > MakeColorFilter(const std::shared_ptr< const DlColorFilter > &filter)
static std::shared_ptr< DlImageFilter > MakeMatrix(const DlMatrix &matrix, DlImageSampling sampling)
DlPaint & setColor(DlColor color)
Definition dl_paint.h:70
DlPaint & setAntiAlias(bool isAntiAlias)
Definition dl_paint.h:58
DlPaint & setInvertColors(bool isInvertColors)
Definition dl_paint.h:64
DlPaint & setStrokeCap(DlStrokeCap cap)
Definition dl_paint.h:101
DlPaint & setStrokeWidth(float width)
Definition dl_paint.h:115
DlPaint & setStrokeMiter(float miter)
Definition dl_paint.h:121
DlPaint & setBlendMode(DlBlendMode mode)
Definition dl_paint.h:85
DlPaint & setImageFilter(std::nullptr_t filter)
Definition dl_paint.h:167
DlPaint & setMaskFilter(std::nullptr_t filter)
Definition dl_paint.h:185
DlPaint & setDrawStyle(DlDrawStyle style)
Definition dl_paint.h:93
DlPaint & setStrokeJoin(DlStrokeJoin join)
Definition dl_paint.h:109
DlPaint & setColorFilter(std::nullptr_t filter)
Definition dl_paint.h:149
DlPaint & setColorSource(std::nullptr_t source)
Definition dl_paint.h:131
DlPathBuilder & MoveTo(DlPoint p2)
Start a new contour that will originate at the indicated point p2.
const DlPath TakePath()
Returns the path constructed by this path builder and resets its internal state to the default state ...
DlPathBuilder & AddCircle(DlPoint center, DlScalar radius)
Append a closed circular contour to the path centered on the provided point at the provided radius.
DlPathBuilder & AddRoundRect(const DlRoundRect &round_rect)
Append a closed rounded rect contour to the path.
DlPathBuilder & Close()
The path is closed back to the location of the most recent MoveTo call. Contours that are filled are ...
DlPathBuilder & CubicCurveTo(DlPoint cp1, DlPoint cp2, DlPoint p2)
Draw a cubic bezier curve from the current point to the indicated point p2, using the indicated point...
static DlPath MakeCircle(const DlPoint center, DlScalar radius)
Definition dl_path.cc:68
static DlPath MakeRectXYWH(DlScalar x, DlScalar y, DlScalar width, DlScalar height)
Definition dl_path.cc:50
static DlPath MakeRect(const DlRect &rect)
Definition dl_path.cc:39
static DlPath MakeRoundRectXY(const DlRect &rect, DlScalar x_radius, DlScalar y_radius, bool counter_clock_wise=false)
Definition dl_path.cc:76
double width() const
Definition geometry.h:44
static sk_sp< DlImageImpeller > Make(std::shared_ptr< Texture > texture, OwningContext owning_context=OwningContext::kIO)
int32_t x
FlutterVulkanImage * image
FlutterDesktopBinaryReply callback
FlTexture * texture
double y
impeller::Scalar DlScalar
DlStrokeCap
Definition dl_paint.h:28
@ kRound
adds circle
@ kButt
no stroke extension
@ kSquare
adds square
impeller::ISize32 DlISize
it will be possible to load the file into Perfetto s trace viewer use test Running tests that layout and measure text will not yield consistent results across various platforms Enabling this option will make font resolution default to the Ahem test font on all disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
impeller::Size DlSize
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 switch_defs.h:52
@ kStroke
strokes boundary of shapes
static constexpr DlScalar kEhCloseEnough
impeller::Point DlPoint
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 disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set profile Make the profiler discard new samples once the profiler sample buffer is full When this flag is not the profiler sample buffer is used as a ring buffer
Definition switch_defs.h:98
TEST_P(AiksTest, DrawAtlasNoColor)
AiksPlaygroundWithGoldens AiksTest
float Scalar
Definition scalar.h:19
std::tuple< Point, Point > DrawPlaygroundLine(PlaygroundPoint &point_a, PlaygroundPoint &point_b)
Definition widgets.cc:51
PixelFormat
The Pixel formats supported by Impeller. The naming convention denotes the usage of the component,...
Definition formats.h:99
constexpr float kSqrt2
Definition constants.h:47
void Close(PathBuilder *builder)
constexpr const char * PixelFormatToString(PixelFormat format)
Definition formats.h:292
std::shared_ptr< ContextGLES > context
int32_t height
int32_t width
static constexpr DlColor kWhite()
Definition dl_color.h:70
static constexpr DlColor kBlue()
Definition dl_color.h:73
static constexpr DlColor RGBA(DlScalar r, DlScalar g, DlScalar b, DlScalar a)
Construct a 32 bit color from floating point R, G, B, and A color channels.
Definition dl_color.h:48
static constexpr DlColor kBlack()
Definition dl_color.h:69
static constexpr DlColor ARGB(DlScalar a, DlScalar r, DlScalar g, DlScalar b)
Construct a 32 bit color from floating point A, R, G, and B color channels.
Definition dl_color.h:57
static constexpr DlColor kAqua()
Definition dl_color.h:86
static constexpr DlColor kYellow()
Definition dl_color.h:76
static constexpr DlColor kPurple()
Definition dl_color.h:88
static constexpr DlColor kMidGrey()
Definition dl_color.h:78
constexpr DlColor withAlphaF(float alpha) const
Definition dl_color.h:132
static constexpr DlColor kTransparent()
Definition dl_color.h:68
static constexpr DlColor kRed()
Definition dl_color.h:71
static constexpr DlColor kGreen()
Definition dl_color.h:72
static constexpr DlColor kOrange()
Definition dl_color.h:87
static constexpr DlColor kSkyBlue()
Definition dl_color.h:83
constexpr DlColor modulateOpacity(DlScalar opacity) const
Definition dl_color.h:150
static constexpr Color White()
Definition color.h:269
A 4x4 matrix using column-major storage.
Definition matrix.h:37
static constexpr Matrix MakeTranslation(const Vector3 &t)
Definition matrix.h:95
static Matrix MakeRotationY(Radians r)
Definition matrix.h:208
static Matrix MakePerspective(Radians fov_y, Scalar aspect_ratio, Scalar z_near, Scalar z_far)
Definition matrix.h:650
static constexpr Matrix MakeScale(const Vector3 &s)
Definition matrix.h:104
static RoundRect MakeRectRadius(const Rect &rect, Scalar radius)
Definition round_rect.h:27
static RoundRect MakeRectRadii(const Rect &rect, const RoundingRadii &radii)
Definition round_rect.cc:9
static RoundRect MakeRectXY(const Rect &rect, Scalar x_radius, Scalar y_radius)
Definition round_rect.h:31
static RoundSuperellipse MakeRectRadii(const Rect &rect, const RoundingRadii &radii)
static RoundSuperellipse MakeRectRadius(const Rect &rect, Scalar radius)
static constexpr TRect MakeEllipseBounds(const TPoint< Type > &center, const TSize< Type > &radii)
Definition rect.h:164
static constexpr TRect MakeXYWH(Type x, Type y, Type width, Type height)
Definition rect.h:136
static constexpr TRect MakeSize(const TSize< U > &size)
Definition rect.h:150
constexpr TRect< T > Expand(T left, T top, T right, T bottom) const
Returns a rectangle with expanded edges. Negative expansion results in shrinking.
Definition rect.h:652
constexpr TRect< T > Shift(T dx, T dy) const
Returns a new rectangle translated by the given offset.
Definition rect.h:636
static constexpr TRect MakeLTRB(Type left, Type top, Type right, Type bottom)
Definition rect.h:129
Type height
Definition size.h:29
Type width
Definition size.h:28
const size_t start