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 EXPECT_EQ(GetContext()->GetCapabilities()->GetDefaultColorFormat(),
1914}
1915
1916TEST_P(AiksTest, FormatSRGB) {
1917 PixelFormat pixel_format =
1918 GetContext()->GetCapabilities()->GetDefaultColorFormat();
1919 EXPECT_TRUE(pixel_format == PixelFormat::kR8G8B8A8UNormInt ||
1920 pixel_format == PixelFormat::kB8G8R8A8UNormInt)
1921 << "pixel format: " << PixelFormatToString(pixel_format);
1922}
1923
1924TEST_P(AiksTest, CoordinateConversionsAreCorrect) {
1925 DisplayListBuilder builder;
1926
1927 // Render a texture directly.
1928 {
1929 auto image = DlImageImpeller::Make(CreateTextureForFixture("kalimba.jpg"));
1930
1931 builder.Save();
1932 builder.Translate(100, 200);
1933 builder.Scale(0.5, 0.5);
1934 builder.DrawImage(image, DlPoint(100.0, 100.0),
1935 DlImageSampling::kNearestNeighbor);
1936 builder.Restore();
1937 }
1938
1939 // Render an offscreen rendered texture.
1940 {
1941 DlPaint alpha;
1942 alpha.setColor(DlColor::kRed().modulateOpacity(0.5));
1943
1944 builder.SaveLayer(std::nullopt, &alpha);
1945
1946 DlPaint paint;
1947 paint.setColor(DlColor::kRed());
1948 builder.DrawRect(DlRect::MakeXYWH(000, 000, 100, 100), paint);
1949 paint.setColor(DlColor::kGreen());
1950 builder.DrawRect(DlRect::MakeXYWH(020, 020, 100, 100), paint);
1951 paint.setColor(DlColor::kBlue());
1952 builder.DrawRect(DlRect::MakeXYWH(040, 040, 100, 100), paint);
1953
1954 builder.Restore();
1955 }
1956
1957 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1958}
1959
1960TEST_P(AiksTest, CanPerformFullScreenMSAA) {
1961 DisplayListBuilder builder;
1962
1963 DlPaint paint;
1964 paint.setColor(DlColor::kRed());
1965 builder.DrawCircle(DlPoint(250, 250), 125, paint);
1966
1967 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1968}
1969
1970TEST_P(AiksTest, CanPerformSkew) {
1971 DisplayListBuilder builder;
1972
1973 DlPaint red;
1974 red.setColor(DlColor::kRed());
1975 builder.Skew(2, 5);
1976 builder.DrawRect(DlRect::MakeXYWH(0, 0, 100, 100), red);
1977
1978 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1979}
1980
1981TEST_P(AiksTest, CanPerformSaveLayerWithBounds) {
1982 DisplayListBuilder builder;
1983
1984 DlPaint save;
1985 save.setColor(DlColor::kBlack());
1986
1987 DlRect save_bounds = DlRect::MakeXYWH(0, 0, 50, 50);
1988 builder.SaveLayer(save_bounds, &save);
1989
1990 DlPaint paint;
1991 paint.setColor(DlColor::kRed());
1992 builder.DrawRect(DlRect::MakeXYWH(0, 0, 100, 100), paint);
1993 paint.setColor(DlColor::kGreen());
1994 builder.DrawRect(DlRect::MakeXYWH(10, 10, 100, 100), paint);
1995 paint.setColor(DlColor::kBlue());
1996 builder.DrawRect(DlRect::MakeXYWH(20, 20, 100, 100), paint);
1997
1998 builder.Restore();
1999
2000 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
2001}
2002
2003TEST_P(AiksTest, FilledRoundRectPathsRenderCorrectly) {
2004 DisplayListBuilder builder;
2005 builder.Scale(GetContentScale().x, GetContentScale().y);
2006
2007 DlPaint paint;
2008 const int color_count = 3;
2009 DlColor colors[color_count] = {
2012 DlColor::ARGB(1.0, 220.0f / 255.0f, 20.0f / 255.0f, 60.0f / 255.0f),
2013 };
2014
2015 paint.setColor(DlColor::kWhite());
2016 builder.DrawPaint(paint);
2017
2018 auto draw_rrect_as_path = [&builder](const DlRect& rect, Scalar x, Scalar y,
2019 const DlPaint& paint) {
2020 builder.DrawPath(DlPath::MakeRoundRectXY(rect, x, y), paint);
2021 };
2022
2023 int c_index = 0;
2024 for (int i = 0; i < 4; i++) {
2025 for (int j = 0; j < 4; j++) {
2026 paint.setColor(colors[(c_index++) % color_count]);
2027 draw_rrect_as_path(DlRect::MakeXYWH(i * 100 + 10, j * 100 + 20, 80, 80),
2028 i * 5 + 10, j * 5 + 10, paint);
2029 }
2030 }
2031 paint.setColor(colors[(c_index++) % color_count]);
2032 draw_rrect_as_path(DlRect::MakeXYWH(10, 420, 380, 80), 40, 40, paint);
2033 paint.setColor(colors[(c_index++) % color_count]);
2034 draw_rrect_as_path(DlRect::MakeXYWH(410, 20, 80, 380), 40, 40, paint);
2035
2036 std::vector<DlColor> gradient_colors = {
2037 DlColor::RGBA(0x1f / 255.0, 0.0, 0x5c / 255.0, 1.0),
2038 DlColor::RGBA(0x5b / 255.0, 0.0, 0x60 / 255.0, 1.0),
2039 DlColor::RGBA(0x87 / 255.0, 0x01 / 255.0, 0x60 / 255.0, 1.0),
2040 DlColor::RGBA(0xac / 255.0, 0x25 / 255.0, 0x53 / 255.0, 1.0),
2041 DlColor::RGBA(0xe1 / 255.0, 0x6b / 255.0, 0x5c / 255.0, 1.0),
2042 DlColor::RGBA(0xf3 / 255.0, 0x90 / 255.0, 0x60 / 255.0, 1.0),
2043 DlColor::RGBA(0xff / 255.0, 0xb5 / 255.0, 0x6b / 250.0, 1.0)};
2044 std::vector<Scalar> stops = {
2045 0.0,
2046 (1.0 / 6.0) * 1,
2047 (1.0 / 6.0) * 2,
2048 (1.0 / 6.0) * 3,
2049 (1.0 / 6.0) * 4,
2050 (1.0 / 6.0) * 5,
2051 1.0,
2052 };
2054 CreateTextureForFixture("airplane.jpg",
2055 /*enable_mipmapping=*/true));
2056
2057 paint.setColor(DlColor::kWhite().modulateOpacity(0.1));
2059 /*center=*/DlPoint(550, 550),
2060 /*radius=*/75,
2061 /*stop_count=*/gradient_colors.size(),
2062 /*colors=*/gradient_colors.data(),
2063 /*stops=*/stops.data(),
2064 /*tile_mode=*/DlTileMode::kMirror));
2065 for (int i = 1; i <= 10; i++) {
2066 int j = 11 - i;
2067 draw_rrect_as_path(DlRect::MakeLTRB(550 - i * 20, 550 - j * 20, //
2068 550 + i * 20, 550 + j * 20),
2069 i * 10, j * 10, paint);
2070 }
2071 paint.setColor(DlColor::kWhite().modulateOpacity(0.5));
2073 /*center=*/DlPoint(200, 650),
2074 /*radius=*/75,
2075 /*stop_count=*/gradient_colors.size(),
2076 /*colors=*/gradient_colors.data(),
2077 /*stops=*/stops.data(),
2078 /*tile_mode=*/DlTileMode::kMirror));
2079 draw_rrect_as_path(DlRect::MakeLTRB(100, 610, 300, 690), 40, 40, paint);
2080 draw_rrect_as_path(DlRect::MakeLTRB(160, 550, 240, 750), 40, 40, paint);
2081
2082 auto matrix = DlMatrix::MakeTranslation({520, 20});
2083 paint.setColor(DlColor::kWhite().modulateOpacity(0.1));
2085 texture, DlTileMode::kRepeat, DlTileMode::kRepeat,
2086 DlImageSampling::kMipmapLinear, &matrix));
2087 for (int i = 1; i <= 10; i++) {
2088 int j = 11 - i;
2089 draw_rrect_as_path(DlRect::MakeLTRB(720 - i * 20, 220 - j * 20, //
2090 720 + i * 20, 220 + j * 20),
2091 i * 10, j * 10, paint);
2092 }
2093 matrix = DlMatrix::MakeTranslation({800, 300});
2094 paint.setColor(DlColor::kWhite().modulateOpacity(0.5));
2096 texture, DlTileMode::kRepeat, DlTileMode::kRepeat,
2097 DlImageSampling::kMipmapLinear, &matrix));
2098
2099 draw_rrect_as_path(DlRect::MakeLTRB(800, 410, 1000, 490), 40, 40, paint);
2100 draw_rrect_as_path(DlRect::MakeLTRB(860, 350, 940, 550), 40, 40, paint);
2101
2102 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
2103}
2104
2105TEST_P(AiksTest, CoverageOriginShouldBeAccountedForInSubpasses) {
2106 auto callback = [&]() -> sk_sp<DisplayList> {
2107 DisplayListBuilder builder;
2108 builder.Scale(GetContentScale().x, GetContentScale().y);
2109
2110 DlPaint alpha;
2112
2113 auto current = Point{25, 25};
2114 const auto offset = Point{25, 25};
2115 const auto size = Size(100, 100);
2116
2117 static PlaygroundPoint point_a(Point(40, 40), 10, Color::White());
2118 static PlaygroundPoint point_b(Point(160, 160), 10, Color::White());
2119 auto [b0, b1] = DrawPlaygroundLine(point_a, point_b);
2120 DlRect bounds = DlRect::MakeLTRB(b0.x, b0.y, b1.x, b1.y);
2121
2122 DlPaint stroke_paint;
2123 stroke_paint.setColor(DlColor::kYellow());
2124 stroke_paint.setStrokeWidth(5);
2125 stroke_paint.setDrawStyle(DlDrawStyle::kStroke);
2126 builder.DrawRect(bounds, stroke_paint);
2127
2128 builder.SaveLayer(bounds, &alpha);
2129
2130 DlPaint paint;
2131 paint.setColor(DlColor::kRed());
2132 builder.DrawRect(
2133 DlRect::MakeXYWH(current.x, current.y, size.width, size.height), paint);
2134
2135 paint.setColor(DlColor::kGreen());
2136 current += offset;
2137 builder.DrawRect(
2138 DlRect::MakeXYWH(current.x, current.y, size.width, size.height), paint);
2139
2140 paint.setColor(DlColor::kBlue());
2141 current += offset;
2142 builder.DrawRect(
2143 DlRect::MakeXYWH(current.x, current.y, size.width, size.height), paint);
2144
2145 builder.Restore();
2146
2147 return builder.Build();
2148 };
2149
2150 ASSERT_TRUE(OpenPlaygroundHere(callback));
2151}
2152
2153TEST_P(AiksTest, SaveLayerDrawsBehindSubsequentEntities) {
2154 // Compare with https://fiddle.skia.org/c/9e03de8567ffb49e7e83f53b64bcf636
2155 DisplayListBuilder builder;
2156 DlPaint paint;
2157
2158 paint.setColor(DlColor::kBlack());
2159 DlRect rect = DlRect::MakeXYWH(25, 25, 25, 25);
2160 builder.DrawRect(rect, paint);
2161
2162 builder.Translate(10, 10);
2163
2164 DlPaint save_paint;
2165 builder.SaveLayer(std::nullopt, &save_paint);
2166
2167 paint.setColor(DlColor::kGreen());
2168 builder.DrawRect(rect, paint);
2169
2170 builder.Restore();
2171
2172 builder.Translate(10, 10);
2173 paint.setColor(DlColor::kRed());
2174 builder.DrawRect(rect, paint);
2175
2176 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
2177}
2178
2179TEST_P(AiksTest, SiblingSaveLayerBoundsAreRespected) {
2180 DisplayListBuilder builder;
2181 DlPaint paint;
2182 DlRect rect = DlRect::MakeXYWH(0, 0, 1000, 1000);
2183
2184 // Black, green, and red squares offset by [10, 10].
2185 {
2186 DlPaint save_paint;
2187 DlRect bounds = DlRect::MakeXYWH(25, 25, 25, 25);
2188 builder.SaveLayer(bounds, &save_paint);
2189 paint.setColor(DlColor::kBlack());
2190 builder.DrawRect(rect, paint);
2191 builder.Restore();
2192 }
2193
2194 {
2195 DlPaint save_paint;
2196 DlRect bounds = DlRect::MakeXYWH(35, 35, 25, 25);
2197 builder.SaveLayer(bounds, &save_paint);
2198 paint.setColor(DlColor::kGreen());
2199 builder.DrawRect(rect, paint);
2200 builder.Restore();
2201 }
2202
2203 {
2204 DlPaint save_paint;
2205 DlRect bounds = DlRect::MakeXYWH(45, 45, 25, 25);
2206 builder.SaveLayer(bounds, &save_paint);
2207 paint.setColor(DlColor::kRed());
2208 builder.DrawRect(rect, paint);
2209 builder.Restore();
2210 }
2211
2212 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
2213}
2214
2215TEST_P(AiksTest, CanRenderClippedLayers) {
2216 DisplayListBuilder builder;
2217
2218 DlPaint paint;
2219 paint.setColor(DlColor::kWhite());
2220 builder.DrawPaint(paint);
2221
2222 // Draw a green circle on the screen.
2223 {
2224 // Increase the clip depth for the savelayer to contend with.
2225 DlPath path = DlPath::MakeCircle(DlPoint(100, 100), 50);
2226 builder.ClipPath(path);
2227
2228 DlRect bounds = DlRect::MakeXYWH(50, 50, 100, 100);
2229 DlPaint save_paint;
2230 builder.SaveLayer(bounds, &save_paint);
2231
2232 // Fill the layer with white.
2233 paint.setColor(DlColor::kWhite());
2234 builder.DrawRect(DlRect::MakeSize(DlSize(400, 400)), paint);
2235 // Fill the layer with green, but do so with a color blend that can't be
2236 // collapsed into the parent pass.
2237 paint.setColor(DlColor::kGreen());
2238 paint.setBlendMode(DlBlendMode::kHardLight);
2239 builder.DrawRect(DlRect::MakeSize(DlSize(400, 400)), paint);
2240 }
2241
2242 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
2243}
2244
2245TEST_P(AiksTest, SaveLayerFiltersScaleWithTransform) {
2246 DisplayListBuilder builder;
2247
2248 builder.Scale(GetContentScale().x, GetContentScale().y);
2249 builder.Translate(100, 100);
2250
2251 auto texture = DlImageImpeller::Make(CreateTextureForFixture("boston.jpg"));
2252 auto draw_image_layer = [&builder, &texture](const DlPaint& paint) {
2253 builder.SaveLayer(std::nullopt, &paint);
2254 builder.DrawImage(texture, DlPoint(), DlImageSampling::kLinear);
2255 builder.Restore();
2256 };
2257
2258 DlPaint effect_paint;
2259 effect_paint.setMaskFilter(DlBlurMaskFilter::Make(DlBlurStyle::kNormal, 6));
2260 draw_image_layer(effect_paint);
2261
2262 builder.Translate(300, 300);
2263 builder.Scale(3, 3);
2264 draw_image_layer(effect_paint);
2265
2266 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
2267}
2268
2269TEST_P(AiksTest, FastEllipticalRRectMaskBlursRenderCorrectly) {
2270 DisplayListBuilder builder;
2271
2272 builder.Scale(GetContentScale().x, GetContentScale().y);
2273 DlPaint paint;
2274 paint.setMaskFilter(DlBlurMaskFilter::Make(DlBlurStyle::kNormal, 1));
2275
2276 DlPaint save_paint;
2277 save_paint.setColor(DlColor::kWhite());
2278 builder.DrawPaint(save_paint);
2279
2280 paint.setColor(DlColor::kBlue());
2281 for (int i = 0; i < 5; i++) {
2282 Scalar y = i * 125;
2283 Scalar y_radius = i * 15;
2284 for (int j = 0; j < 5; j++) {
2285 Scalar x = j * 125;
2286 Scalar x_radius = j * 15;
2287 builder.DrawRoundRect(
2289 DlRect::MakeXYWH(x + 50, y + 50, 100.0f, 100.0f), //
2290 x_radius, y_radius),
2291 paint);
2292 }
2293 }
2294
2295 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
2296}
2297
2298TEST_P(AiksTest, PipelineBlendSingleParameter) {
2299 DisplayListBuilder builder;
2300
2301 // Should render a green square in the middle of a blue circle.
2302 DlPaint paint;
2303 builder.SaveLayer(std::nullopt, &paint);
2304 {
2305 builder.Translate(100, 100);
2306 paint.setColor(DlColor::kBlue());
2307 builder.DrawCircle(DlPoint(200, 200), 200, paint);
2308 builder.ClipRect(DlRect::MakeXYWH(100, 100, 200, 200));
2309
2310 paint.setColor(DlColor::kGreen());
2311 paint.setBlendMode(DlBlendMode::kSrcOver);
2313 DlColorFilter::MakeBlend(DlColor::kWhite(), DlBlendMode::kDst)));
2314 builder.DrawCircle(DlPoint(200, 200), 200, paint);
2315 builder.Restore();
2316 }
2317
2318 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
2319}
2320
2321// Creates an image matrix filter that scales large content such that it would
2322// exceed the max texture size. See
2323// https://github.com/flutter/flutter/issues/128912
2324TEST_P(AiksTest, MassiveScalingMatrixImageFilter) {
2325 if (GetBackend() == PlaygroundBackend::kVulkan) {
2326 GTEST_SKIP() << "Swiftshader is running out of memory on this example.";
2327 }
2328 DisplayListBuilder builder(DlRect::MakeSize(DlSize(1000, 1000)));
2329
2330 auto filter = DlImageFilter::MakeMatrix(
2331 DlMatrix::MakeScale({0.001, 0.001, 1}), DlImageSampling::kLinear);
2332
2333 DlPaint paint;
2334 paint.setImageFilter(filter);
2335 builder.SaveLayer(std::nullopt, &paint);
2336 {
2337 DlPaint paint;
2338 paint.setColor(DlColor::kRed());
2339 builder.DrawRect(DlRect::MakeLTRB(0, 0, 100000, 100000), paint);
2340 }
2341 builder.Restore();
2342
2343 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
2344}
2345
2346TEST_P(AiksTest, NoDimplesInRRectPath) {
2347 Scalar width = 200.f;
2348 Scalar height = 60.f;
2349 Scalar corner = 1.f;
2350 bool stroked = true;
2351 auto callback = [&]() -> sk_sp<DisplayList> {
2352 if (AiksTest::ImGuiBegin("Controls", nullptr,
2353 ImGuiWindowFlags_AlwaysAutoResize)) {
2354 ImGui::SliderFloat("width", &width, 0, 200);
2355 ImGui::SliderFloat("height", &height, 0, 200);
2356 ImGui::SliderFloat("corner", &corner, 0, 1);
2357 ImGui::Checkbox("stroked", &stroked);
2358 ImGui::End();
2359 }
2360
2361 DisplayListBuilder builder;
2362 builder.Scale(GetContentScale().x, GetContentScale().y);
2363
2364 DlPaint background_paint;
2365 background_paint.setColor(DlColor(1, 0.1, 0.1, 0.1, DlColorSpace::kSRGB));
2366 builder.DrawPaint(background_paint);
2367
2368 std::vector<DlColor> colors = {DlColor::kRed(), DlColor::kBlue()};
2369 std::vector<Scalar> stops = {0.0, 1.0};
2370
2371 DlPaint paint;
2372 auto gradient = DlColorSource::MakeLinear(DlPoint(0, 0), DlPoint(200, 200),
2373 2, colors.data(), stops.data(),
2374 DlTileMode::kClamp);
2375 paint.setColorSource(gradient);
2376 paint.setColor(DlColor::kWhite());
2377 if (stroked) {
2378 paint.setDrawStyle(DlDrawStyle::kStroke);
2379 paint.setStrokeWidth(20);
2380 } else {
2381 paint.setDrawStyle(DlDrawStyle::kFill);
2382 }
2383
2384 builder.Save();
2385 builder.Translate(100, 100);
2386
2387 Scalar corner_x = ((1 - corner) * 50) + 50;
2388 Scalar corner_y = corner * 50 + 50;
2390 DlRect::MakeXYWH(0, 0, width, height), corner_x, corner_y);
2391 builder.DrawRoundRect(rrect, paint);
2392 builder.Restore();
2393 return builder.Build();
2394 };
2395 ASSERT_TRUE(OpenPlaygroundHere(callback));
2396}
2397
2398TEST_P(AiksTest, BackdropFilterOverUnclosedClip) {
2399 DisplayListBuilder builder;
2400
2401 builder.DrawPaint(DlPaint().setColor(DlColor::kWhite()));
2402 builder.Save();
2403 {
2404 builder.ClipRect(DlRect::MakeLTRB(100, 100, 800, 800));
2405
2406 builder.Save();
2407 {
2408 builder.ClipRect(DlRect::MakeLTRB(600, 600, 800, 800));
2409 builder.DrawPaint(DlPaint().setColor(DlColor::kRed()));
2410 builder.DrawPaint(DlPaint().setColor(DlColor::kBlue().withAlphaF(0.5)));
2411 builder.ClipRect(DlRect::MakeLTRB(700, 700, 750, 800));
2412 builder.DrawPaint(DlPaint().setColor(DlColor::kRed().withAlphaF(0.5)));
2413 }
2414 builder.Restore();
2415
2416 auto image_filter = DlImageFilter::MakeBlur(10, 10, DlTileMode::kDecal);
2417 builder.SaveLayer(std::nullopt, nullptr, image_filter.get());
2418 }
2419 builder.Restore();
2420 builder.DrawCircle(DlPoint(100, 100), 100,
2421 DlPaint().setColor(DlColor::kAqua()));
2422
2423 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
2424}
2425
2426TEST_P(AiksTest, PerspectiveRectangle) {
2427 int perspective = 58;
2428 bool use_clip = true;
2429 bool diff_clip = false;
2430
2431 auto callback = [&]() -> sk_sp<DisplayList> {
2432 if (AiksTest::ImGuiBegin("Controls", nullptr,
2433 ImGuiWindowFlags_AlwaysAutoResize)) {
2434 ImGui::SliderInt("perspective%", &perspective, 0, 100);
2435 ImGui::Checkbox("use clip", &use_clip);
2436 if (use_clip) {
2437 ImGui::Checkbox("diff clip", &diff_clip);
2438 }
2439 ImGui::SetWindowPos("Controls", ImVec2(500, 100));
2440 ImGui::End();
2441 }
2442
2443 DisplayListBuilder builder;
2444
2445 Scalar val = perspective * -0.00005f;
2447 // clang-format off
2448 1.0f, 0.0f, 0.0f, 400.0f,
2449 0.0f, 1.0f, 0.0f, 400.0f,
2450 0.0f, 0.0f, 1.0f, 0.0f,
2451 0.0f, val, 0.0f, 2.2f
2452 // clang-format on
2453 );
2454
2455 if (use_clip) {
2456 Rect clip = DlRect::MakeLTRB(0, 0, 400, 800);
2457 DlClipOp clip_op = DlClipOp::kIntersect;
2458 if (diff_clip) {
2459 clip = clip.Expand(-20);
2460 clip_op = DlClipOp::kDifference;
2461 }
2462 builder.ClipRect(clip, clip_op);
2463 }
2464
2465 DlPaint paint;
2466 paint.setColor(DlColor::kBlue());
2467 builder.DrawRect(DlRect::MakeLTRB(0, 0, 400, 800), paint);
2468
2469 builder.DrawColor(DlColor::kWhite().withAlphaF(0.5f),
2470 DlBlendMode::kSrcOver);
2471
2472 return builder.Build();
2473 };
2474 ASSERT_TRUE(OpenPlaygroundHere(callback));
2475}
2476
2477TEST_P(AiksTest, CanRenderFilledRoundSuperellipses) {
2478 DisplayListBuilder builder;
2479 builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc);
2480 DlPaint paint;
2481 paint.setColor(DlColor::kBlue());
2482
2483 // Square
2484 builder.DrawRoundSuperellipse(
2486 /*rect=*/DlRect::MakeXYWH(50, 50, 100, 100), /*radius=*/20),
2487 paint);
2488 // Tall
2489 builder.DrawRoundSuperellipse(
2491 /*rect=*/DlRect::MakeXYWH(200, 50, 60, 140), /*radius=*/20),
2492 paint);
2493 // Wide
2494 builder.DrawRoundSuperellipse(
2496 /*rect=*/DlRect::MakeXYWH(310, 50, 140, 60), /*radius=*/20),
2497 paint);
2498
2499 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
2500}
2501
2502TEST_P(AiksTest, CanRenderStrokedRoundSuperellipses) {
2503 DisplayListBuilder builder;
2504 builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc);
2505 DlPaint paint;
2506 paint.setColor(DlColor::kBlue());
2507 paint.setDrawStyle(DlDrawStyle::kStroke);
2508 paint.setStrokeWidth(5.0f);
2509
2510 // Square
2511 builder.DrawRoundSuperellipse(
2513 /*rect=*/DlRect::MakeXYWH(50, 50, 100, 100), /*radius=*/20),
2514 paint);
2515 // Tall
2516 builder.DrawRoundSuperellipse(
2518 /*rect=*/DlRect::MakeXYWH(200, 50, 60, 140), /*radius=*/20),
2519 paint);
2520 // Wide
2521 builder.DrawRoundSuperellipse(
2523 /*rect=*/DlRect::MakeXYWH(310, 50, 140, 60), /*radius=*/20),
2524 paint);
2525
2526 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
2527}
2528
2529TEST_P(AiksTest, CanRenderSmallRadiusRoundSuperellipses) {
2530 DisplayListBuilder builder;
2531 builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc);
2532 DlPaint paint;
2533 paint.setColor(DlColor::kBlue());
2534
2535 // Square
2536 builder.DrawRoundSuperellipse(
2538 /*rect=*/DlRect::MakeXYWH(50, 50, 100, 100), /*radius=*/2),
2539 paint);
2540 // Tall
2541 builder.DrawRoundSuperellipse(
2543 /*rect=*/DlRect::MakeXYWH(200, 50, 60, 140), /*radius=*/2),
2544 paint);
2545 // Wide
2546 builder.DrawRoundSuperellipse(
2548 /*rect=*/DlRect::MakeXYWH(310, 50, 140, 60), /*radius=*/2),
2549 paint);
2550
2551 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
2552}
2553
2554TEST_P(AiksTest, CanRenderThickStrokedRoundSuperellipses) {
2555 DisplayListBuilder builder;
2556 builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc);
2557 DlPaint paint;
2558 paint.setColor(DlColor::kBlue().withAlphaF(0.5));
2559 paint.setDrawStyle(DlDrawStyle::kStroke);
2560 paint.setStrokeWidth(40.0f);
2561
2562 // Square
2563 builder.DrawRoundSuperellipse(
2565 /*rect=*/DlRect::MakeXYWH(50, 50, 100, 100), /*radius=*/30),
2566 paint);
2567 // Tall
2568 builder.DrawRoundSuperellipse(
2570 /*rect=*/DlRect::MakeXYWH(200, 50, 60, 140), /*radius=*/30),
2571 paint);
2572 // Wide
2573 builder.DrawRoundSuperellipse(
2575 /*rect=*/DlRect::MakeXYWH(310, 50, 140, 60), /*radius=*/30),
2576 paint);
2577
2578 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
2579}
2580
2581TEST_P(AiksTest, CanRenderRoundSuperellipseGrid) {
2582 DisplayListBuilder builder;
2583 builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc);
2584 DlPaint paint;
2585 paint.setColor(DlColor::kBlue());
2586
2587 DlScalar radii[] = {10.0f, 30.0f, 50.0f};
2588
2589 for (int row = 0; row < 3; row++) {
2590 DlScalar y = 50.0f + row * 170.0f;
2591 DlScalar radius = radii[row];
2592
2593 // Square
2594 builder.DrawRoundSuperellipse(
2596 /*rect=*/DlRect::MakeXYWH(50, y, 100, 100), /*radius=*/radius),
2597 paint);
2598 // Tall
2599 builder.DrawRoundSuperellipse(
2601 /*rect=*/DlRect::MakeXYWH(200, y, 60, 140), /*radius=*/radius),
2602 paint);
2603 // Wide
2604 builder.DrawRoundSuperellipse(
2606 /*rect=*/DlRect::MakeXYWH(310, y, 140, 60), /*radius=*/radius),
2607 paint);
2608 }
2609
2610 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
2611}
2612
2613TEST_P(AiksTest, CanRenderTransformedRoundSuperellipse) {
2614 DisplayListBuilder builder;
2615 builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc);
2616
2617 builder.Save();
2618 builder.Translate(200, 200);
2619 builder.Rotate(45.0f);
2620 builder.Scale(1.5f, 0.8f);
2621
2622 DlPaint paint;
2623 paint.setColor(DlColor::kBlue());
2624 builder.DrawRoundSuperellipse(
2626 /*rect=*/DlRect::MakeXYWH(-70, -30, 140, 60), /*radius=*/20),
2627 paint);
2628 builder.Restore();
2629
2630 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
2631}
2632
2633TEST_P(AiksTest, CompareAntiAliasAndNonAntiAlias) {
2634 DisplayListBuilder builder;
2635 builder.DrawColor(DlColor::kBlack(), DlBlendMode::kSrc);
2636
2637 DlPaint paint;
2638 paint.setColor(DlColor::kWhite());
2639
2640 DlRect bounds = DlRect::MakeXYWH(75, 75, 50, 50);
2641
2642 // --- Left Half: Zoom-in on the top-left corner WITH anti-aliasing (SDF) ---
2643 DlPaint layer_paint_left;
2645 DlMatrix::MakeTranslation({200, 300}) * DlMatrix::MakeScale({8, 8, 1}) *
2646 DlMatrix::MakeTranslation({-100, -100}),
2647 DlImageSampling::kNearestNeighbor));
2648 builder.SaveLayer(bounds, &layer_paint_left);
2649
2650 paint.setAntiAlias(true);
2651 builder.DrawRoundRect(
2652 DlRoundRect::MakeRectRadius(DlRect::MakeXYWH(100, 100, 200, 200), 50.0f),
2653 paint);
2654 builder.Restore();
2655
2656 // --- Right Half: Zoom-in on the top-left corner WITHOUT anti-aliasing ---
2657 DlPaint layer_paint_right;
2658 layer_paint_right.setImageFilter(DlImageFilter::MakeMatrix(
2659 DlMatrix::MakeTranslation({600, 300}) * DlMatrix::MakeScale({8, 8, 1}) *
2660 DlMatrix::MakeTranslation({-100, -100}),
2661 DlImageSampling::kNearestNeighbor));
2662 builder.SaveLayer(bounds, &layer_paint_right);
2663
2664 paint.setAntiAlias(false);
2665 builder.DrawRoundRect(
2666 DlRoundRect::MakeRectRadius(DlRect::MakeXYWH(100, 100, 200, 200), 50.0f),
2667 paint);
2668 builder.Restore();
2669
2670 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
2671}
2672
2673TEST_P(AiksTest, CompareDiffRoundRectAndRoundRect) {
2674 DisplayListBuilder builder;
2675 builder.DrawColor(DlColor::kBlack(), DlBlendMode::kSrc);
2676
2677 DlRect outer_rect = DlRect::MakeXYWH(0, 0, 100, 100);
2678 DlRoundingRadii outer_radii = {.top_left = DlSize(5.0f),
2679 .top_right = DlSize(10.0f),
2680 .bottom_left = DlSize(20.0f),
2681 .bottom_right = DlSize(50.0f)};
2682 DlRoundRect outer_rrect = DlRoundRect::MakeRectRadii(outer_rect, outer_radii);
2683
2684 DlScalar inner_inset = 5.0f;
2685 DlRect inner_rect = outer_rect.Expand(-inner_inset);
2686 DlRoundingRadii inner_radii = {
2687 .top_left = DlSize(outer_radii.top_left.width - inner_inset),
2688 .top_right = DlSize(outer_radii.top_right.width - inner_inset),
2689 .bottom_left = DlSize(outer_radii.bottom_left.width - inner_inset),
2690 .bottom_right = DlSize(outer_radii.bottom_right.width - inner_inset)};
2691 DlRoundRect inner_rrect = DlRoundRect::MakeRectRadii(inner_rect, inner_radii);
2692
2693 builder.Translate(50, 50);
2694
2695 // Draw DiffRoundRect.
2696 builder.DrawDiffRoundRect(outer_rrect, inner_rrect,
2697 DlPaint().setColor(DlColor::kSkyBlue()));
2698
2699 // Draw simalated DiffRoundRect by drawing the outer RoundRect and clearing
2700 // the inner RoundRect.
2701 builder.Translate(200, 0);
2702 builder.DrawRoundRect(outer_rrect, DlPaint().setColor(DlColor::kSkyBlue()));
2703 builder.DrawRoundRect(inner_rrect,
2704 DlPaint().setBlendMode(DlBlendMode::kClear));
2705
2706 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
2707}
2708
2709} // namespace testing
2710} // 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:141
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 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