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