| Flutter Impeller |

dl_unittests.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <array>
6 #include <cmath>
7 #include <memory>
8 #include <vector>
9
10 #include "flutter/display_list/dl_blend_mode.h"
11 #include "flutter/display_list/dl_builder.h"
12 #include "flutter/display_list/dl_color.h"
13 #include "flutter/display_list/dl_paint.h"
14 #include "flutter/display_list/dl_tile_mode.h"
15 #include "flutter/display_list/effects/dl_color_filter.h"
16 #include "flutter/display_list/effects/dl_color_source.h"
17 #include "flutter/display_list/effects/dl_image_filters.h"
18 #include "flutter/display_list/effects/dl_mask_filter.h"
19 #include "flutter/testing/testing.h"
20 #include "gtest/gtest.h"
21 #include "impeller/display_list/aiks_context.h"
22 #include "impeller/display_list/dl_dispatcher.h"
23 #include "impeller/display_list/dl_image_impeller.h"
24 #include "impeller/display_list/dl_playground.h"
25 #include "impeller/entity/contents/clip_contents.h"
26 #include "impeller/entity/contents/solid_color_contents.h"
27 #include "impeller/entity/contents/solid_rrect_blur_contents.h"
28 #include "impeller/geometry/constants.h"
29 #include "impeller/geometry/point.h"
30 #include "impeller/geometry/scalar.h"
31 #include "impeller/playground/widgets.h"
32 #include "third_party/imgui/imgui.h"
33
34 namespace impeller {
35 namespace testing {
36
37 flutter::DlColor toColor(const float* components) {
38 return flutter::DlColor(Color::ToIColor(
39 Color(components[0], components[1], components[2], components[3])));
40 }
41
42 using DisplayListTest = DlPlayground;
43 INSTANTIATE_PLAYGROUND_SUITE(DisplayListTest);
44
45 TEST_P(DisplayListTest, CanDrawRect) {
46 flutter::DisplayListBuilder builder;
47 builder.DrawRect(DlRect::MakeXYWH(10, 10, 100, 100),
48 flutter::DlPaint(flutter::DlColor::kBlue()));
49 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
50 }
51
52 TEST_P(DisplayListTest, CanDrawTextBlob) {
53 flutter::DisplayListBuilder builder;
54 builder.DrawTextBlob(SkTextBlob::MakeFromString("Hello", CreateTestFont()),
55 100, 100, flutter::DlPaint(flutter::DlColor::kBlue()));
56 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
57 }
58
59 TEST_P(DisplayListTest, CanDrawTextBlobWithGradient) {
60 flutter::DisplayListBuilder builder;
61
62 std::vector<flutter::DlColor> colors = {flutter::DlColor::kBlue(),
63 flutter::DlColor::kRed()};
64 const float stops[2] = {0.0, 1.0};
65
66 auto linear = flutter::DlColorSource::MakeLinear({0.0, 0.0}, {300.0, 300.0},
67 2, colors.data(), stops,
68 flutter::DlTileMode::kClamp);
69 flutter::DlPaint paint;
70 paint.setColorSource(linear);
71
72 builder.DrawTextBlob(
73 SkTextBlob::MakeFromString("Hello World", CreateTestFont()), 100, 100,
74 paint);
75 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
76 }
77
78 TEST_P(DisplayListTest, CanDrawTextWithSaveLayer) {
79 flutter::DisplayListBuilder builder;
80 builder.DrawTextBlob(SkTextBlob::MakeFromString("Hello", CreateTestFont()),
81 100, 100, flutter::DlPaint(flutter::DlColor::kRed()));
82
83 flutter::DlPaint save_paint;
84 float alpha = 0.5;
85 save_paint.setAlpha(static_cast<uint8_t>(255 * alpha));
86 builder.SaveLayer(std::nullopt, &save_paint);
87 builder.DrawTextBlob(SkTextBlob::MakeFromString("Hello with half alpha",
88 CreateTestFontOfSize(100)),
89 100, 300, flutter::DlPaint(flutter::DlColor::kRed()));
90 builder.Restore();
91 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
92 }
93
94 TEST_P(DisplayListTest, CanDrawImage) {
95 auto texture = CreateTextureForFixture("embarcadero.jpg");
96 flutter::DisplayListBuilder builder;
97 builder.DrawImage(DlImageImpeller::Make(texture), DlPoint(100, 100),
98 flutter::DlImageSampling::kNearestNeighbor, nullptr);
99 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
100 }
101
102 TEST_P(DisplayListTest, CanDrawCapsAndJoins) {
103 flutter::DisplayListBuilder builder;
104 flutter::DlPaint paint;
105
106 paint.setDrawStyle(flutter::DlDrawStyle::kStroke);
107 paint.setStrokeWidth(30);
108 paint.setColor(flutter::DlColor::kRed());
109
110 flutter::DlPathBuilder path_builder;
111 path_builder.MoveTo(DlPoint(-50, 0));
112 path_builder.LineTo(DlPoint(0, -50));
113 path_builder.LineTo(DlPoint(50, 0));
114 flutter::DlPath path(path_builder);
115
116 builder.Translate(100, 100);
117 {
118 paint.setStrokeCap(flutter::DlStrokeCap::kButt);
119 paint.setStrokeJoin(flutter::DlStrokeJoin::kMiter);
120 paint.setStrokeMiter(4);
121 builder.DrawPath(path, paint);
122 }
123
124 {
125 builder.Save();
126 builder.Translate(0, 100);
127 // The joint in the path is 45 degrees. A miter length of 1 convert to a
128 // bevel in this case.
129 paint.setStrokeMiter(1);
130 builder.DrawPath(path, paint);
131 builder.Restore();
132 }
133
134 builder.Translate(150, 0);
135 {
136 paint.setStrokeCap(flutter::DlStrokeCap::kSquare);
137 paint.setStrokeJoin(flutter::DlStrokeJoin::kBevel);
138 builder.DrawPath(path, paint);
139 }
140
141 builder.Translate(150, 0);
142 {
143 paint.setStrokeCap(flutter::DlStrokeCap::kRound);
144 paint.setStrokeJoin(flutter::DlStrokeJoin::kRound);
145 builder.DrawPath(path, paint);
146 }
147
148 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
149 }
150
151 TEST_P(DisplayListTest, CanDrawArc) {
152 auto callback = [&]() {
153 static float start_angle = 45;
154 static float sweep_angle = 270;
155 static float stroke_width = 10;
156 static bool use_center = true;
157
158 static int selected_cap = 0;
159 const char* cap_names[] = {"Butt", "Round", "Square"};
160 flutter::DlStrokeCap cap;
161
162 ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
163 ImGui::SliderFloat("Start angle", &start_angle, -360, 360);
164 ImGui::SliderFloat("Sweep angle", &sweep_angle, -360, 360);
165 ImGui::SliderFloat("Stroke width", &stroke_width, 0, 300);
166 ImGui::Combo("Cap", &selected_cap, cap_names,
167 sizeof(cap_names) / sizeof(char*));
168 ImGui::Checkbox("Use center", &use_center);
169 ImGui::End();
170
171 switch (selected_cap) {
172 case 0:
173 cap = flutter::DlStrokeCap::kButt;
174 break;
175 case 1:
176 cap = flutter::DlStrokeCap::kRound;
177 break;
178 case 2:
179 cap = flutter::DlStrokeCap::kSquare;
180 break;
181 default:
182 cap = flutter::DlStrokeCap::kButt;
183 break;
184 }
185
186 static PlaygroundPoint point_a(Point(200, 200), 20, Color::White());
187 static PlaygroundPoint point_b(Point(400, 400), 20, Color::White());
188 auto [p1, p2] = DrawPlaygroundLine(point_a, point_b);
189
190 flutter::DisplayListBuilder builder;
191 flutter::DlPaint paint;
192
193 Vector2 scale = GetContentScale();
194 builder.Scale(scale.x, scale.y);
195 paint.setDrawStyle(flutter::DlDrawStyle::kStroke);
196 paint.setStrokeCap(cap);
197 paint.setStrokeJoin(flutter::DlStrokeJoin::kMiter);
198 paint.setStrokeMiter(10);
199 auto rect = DlRect::MakeLTRB(p1.x, p1.y, p2.x, p2.y);
200 paint.setColor(flutter::DlColor::kGreen());
201 paint.setStrokeWidth(2);
202 builder.DrawRect(rect, paint);
203 paint.setColor(flutter::DlColor::kRed());
204 paint.setStrokeWidth(stroke_width);
205 builder.DrawArc(rect, start_angle, sweep_angle, use_center, paint);
206
207 return builder.Build();
208 };
209 ASSERT_TRUE(OpenPlaygroundHere(callback));
210 }
211
212 TEST_P(DisplayListTest, StrokedPathsDrawCorrectly) {
213 auto callback = [&]() {
214 flutter::DisplayListBuilder builder;
215 flutter::DlPaint paint;
216
217 paint.setColor(flutter::DlColor::kRed());
218 paint.setDrawStyle(flutter::DlDrawStyle::kStroke);
219
220 static float stroke_width = 10.0f;
221 static int selected_stroke_type = 0;
222 static int selected_join_type = 0;
223 const char* stroke_types[] = {"Butte", "Round", "Square"};
224 const char* join_type[] = {"kMiter", "Round", "kBevel"};
225
226 ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
227 ImGui::Combo("Cap", &selected_stroke_type, stroke_types,
228 sizeof(stroke_types) / sizeof(char*));
229 ImGui::Combo("Join", &selected_join_type, join_type,
230 sizeof(join_type) / sizeof(char*));
231 ImGui::SliderFloat("Stroke Width", &stroke_width, 10.0f, 50.0f);
232 ImGui::End();
233
234 flutter::DlStrokeCap cap;
235 flutter::DlStrokeJoin join;
236 switch (selected_stroke_type) {
237 case 0:
238 cap = flutter::DlStrokeCap::kButt;
239 break;
240 case 1:
241 cap = flutter::DlStrokeCap::kRound;
242 break;
243 case 2:
244 cap = flutter::DlStrokeCap::kSquare;
245 break;
246 default:
247 cap = flutter::DlStrokeCap::kButt;
248 break;
249 }
250 switch (selected_join_type) {
251 case 0:
252 join = flutter::DlStrokeJoin::kMiter;
253 break;
254 case 1:
255 join = flutter::DlStrokeJoin::kRound;
256 break;
257 case 2:
258 join = flutter::DlStrokeJoin::kBevel;
259 break;
260 default:
261 join = flutter::DlStrokeJoin::kMiter;
262 break;
263 }
264 paint.setStrokeCap(cap);
265 paint.setStrokeJoin(join);
266 paint.setStrokeWidth(stroke_width);
267
268 // Make rendering better to watch.
269 builder.Scale(1.5f, 1.5f);
270
271 // Rectangle
272 builder.Translate(100, 100);
273 builder.DrawRect(DlRect::MakeWH(100, 100), paint);
274
275 // Rounded rectangle
276 builder.Translate(150, 0);
277 builder.DrawRoundRect(
278 DlRoundRect::MakeRectXY(DlRect::MakeWH(100, 50), 10, 10), paint);
279
280 // Double rounded rectangle
281 builder.Translate(150, 0);
282 builder.DrawDiffRoundRect(
283 DlRoundRect::MakeRectXY(DlRect::MakeWH(100, 50), 10, 10),
284 DlRoundRect::MakeRectXY(DlRect::MakeXYWH(10, 10, 80, 30), 10, 10),
285 paint);
286
287 // Contour with duplicate join points
288 {
289 builder.Translate(150, 0);
290 flutter::DlPathBuilder path_builder;
291 path_builder.MoveTo(DlPoint(0, 0));
292 path_builder.LineTo(DlPoint(0, 0));
293 path_builder.LineTo(DlPoint(100, 0));
294 path_builder.LineTo(DlPoint(100, 0));
295 path_builder.LineTo(DlPoint(100, 100));
296 builder.DrawPath(DlPath(path_builder), paint);
297 }
298
299 // Contour with duplicate start and end points
300
301 // Line.
302 builder.Translate(200, 0);
303 {
304 builder.Save();
305
306 flutter::DlPathBuilder line_path_builder;
307 line_path_builder.MoveTo(DlPoint(0, 0));
308 line_path_builder.MoveTo(DlPoint(0, 0));
309 line_path_builder.LineTo(DlPoint(0, 0));
310 line_path_builder.LineTo(DlPoint(0, 0));
311 line_path_builder.LineTo(DlPoint(50, 50));
312 line_path_builder.LineTo(DlPoint(50, 50));
313 line_path_builder.LineTo(DlPoint(100, 0));
314 line_path_builder.LineTo(DlPoint(100, 0));
315 DlPath line_path(line_path_builder);
316 builder.DrawPath(line_path, paint);
317
318 builder.Translate(0, 100);
319 builder.DrawPath(line_path, paint);
320
321 builder.Translate(0, 100);
322 flutter::DlPathBuilder line_path_builder2;
323 line_path_builder2.MoveTo(DlPoint(0, 0));
324 line_path_builder2.LineTo(DlPoint(0, 0));
325 line_path_builder2.LineTo(DlPoint(0, 0));
326 builder.DrawPath(DlPath(line_path_builder2), paint);
327
328 builder.Restore();
329 }
330
331 // Cubic.
332 builder.Translate(150, 0);
333 {
334 builder.Save();
335
336 flutter::DlPathBuilder cubic_path;
337 cubic_path.MoveTo(DlPoint(0, 0));
338 cubic_path.CubicCurveTo(DlPoint(0, 0), //
339 DlPoint(140.0, 100.0), //
340 DlPoint(140, 20));
341 builder.DrawPath(DlPath(cubic_path), paint);
342
343 builder.Translate(0, 100);
344 flutter::DlPathBuilder cubic_path2;
345 cubic_path2.MoveTo(DlPoint(0, 0));
346 cubic_path2.CubicCurveTo(DlPoint(0, 0), //
347 DlPoint(0, 0), //
348 DlPoint(150, 150));
349 builder.DrawPath(DlPath(cubic_path2), paint);
350
351 builder.Translate(0, 100);
352 flutter::DlPathBuilder cubic_path3;
353 cubic_path3.MoveTo(DlPoint(0, 0));
354 cubic_path3.CubicCurveTo(DlPoint(0, 0), //
355 DlPoint(0, 0), //
356 DlPoint(0, 0));
357 builder.DrawPath(DlPath(cubic_path3), paint);
358
359 builder.Restore();
360 }
361
362 // Quad.
363 builder.Translate(200, 0);
364 {
365 builder.Save();
366
367 flutter::DlPathBuilder quad_path;
368 quad_path.MoveTo(DlPoint(0, 0));
369 quad_path.MoveTo(DlPoint(0, 0));
370 quad_path.QuadraticCurveTo(DlPoint(100, 40), DlPoint(50, 80));
371 builder.DrawPath(DlPath(quad_path), paint);
372
373 builder.Translate(0, 150);
374 flutter::DlPathBuilder quad_path2;
375 quad_path2.MoveTo(DlPoint(0, 0));
376 quad_path2.MoveTo(DlPoint(0, 0));
377 quad_path2.QuadraticCurveTo(DlPoint(0, 0), DlPoint(100, 100));
378 builder.DrawPath(DlPath(quad_path2), paint);
379
380 builder.Translate(0, 100);
381 flutter::DlPathBuilder quad_path3;
382 quad_path3.MoveTo(DlPoint(0, 0));
383 quad_path3.QuadraticCurveTo(DlPoint(0, 0), DlPoint(0, 0));
384 builder.DrawPath(DlPath(quad_path3), paint);
385
386 builder.Restore();
387 }
388 return builder.Build();
389 };
390 ASSERT_TRUE(OpenPlaygroundHere(callback));
391 }
392
393 TEST_P(DisplayListTest, CanDrawWithOddPathWinding) {
394 flutter::DisplayListBuilder builder;
395 flutter::DlPaint paint;
396
397 paint.setColor(flutter::DlColor::kRed());
398 paint.setDrawStyle(flutter::DlDrawStyle::kFill);
399
400 builder.Translate(300, 300);
401 flutter::DlPathBuilder path_builder;
402 path_builder.AddCircle(DlPoint(0, 0), 100);
403 path_builder.AddCircle(DlPoint(0, 0), 50);
404 builder.DrawPath(DlPath(path_builder, flutter::DlPathFillType::kOdd), paint);
405
406 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
407 }
408
409 // Regression test for https://github.com/flutter/flutter/issues/134816.
410 //
411 // It should be possible to draw 3 lines, and not have an implicit close path.
412 TEST_P(DisplayListTest, CanDrawAnOpenPath) {
413 flutter::DisplayListBuilder builder;
414 flutter::DlPaint paint;
415
416 paint.setColor(flutter::DlColor::kRed());
417 paint.setDrawStyle(flutter::DlDrawStyle::kStroke);
418 paint.setStrokeWidth(10);
419
420 builder.Translate(300, 300);
421
422 // Move to (50, 50) and draw lines from:
423 // 1. (50, height)
424 // 2. (width, height)
425 // 3. (width, 50)
426 flutter::DlPathBuilder path_builder;
427 path_builder.MoveTo(DlPoint(50, 50));
428 path_builder.LineTo(DlPoint(50, 100));
429 path_builder.LineTo(DlPoint(100, 100));
430 path_builder.LineTo(DlPoint(100, 50));
431 builder.DrawPath(DlPath(path_builder), paint);
432
433 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
434 }
435
436 TEST_P(DisplayListTest, CanDrawWithMaskBlur) {
437 auto texture = CreateTextureForFixture("embarcadero.jpg");
438 flutter::DisplayListBuilder builder;
439 flutter::DlPaint paint;
440
441 // Mask blurred image.
442 {
443 auto filter =
444 flutter::DlBlurMaskFilter(flutter::DlBlurStyle::kNormal, 10.0f);
445 paint.setMaskFilter(&filter);
446 builder.DrawImage(DlImageImpeller::Make(texture), DlPoint(100, 100),
447 flutter::DlImageSampling::kNearestNeighbor, &paint);
448 }
449
450 // Mask blurred filled path.
451 {
452 paint.setColor(flutter::DlColor::kYellow());
453 auto filter =
454 flutter::DlBlurMaskFilter(flutter::DlBlurStyle::kOuter, 10.0f);
455 paint.setMaskFilter(&filter);
456 builder.DrawArc(DlRect::MakeXYWH(410, 110, 100, 100), 45, 270, true, paint);
457 }
458
459 // Mask blurred text.
460 {
461 auto filter =
462 flutter::DlBlurMaskFilter(flutter::DlBlurStyle::kSolid, 10.0f);
463 paint.setMaskFilter(&filter);
464 builder.DrawTextBlob(
465 SkTextBlob::MakeFromString("Testing", CreateTestFont()), 220, 170,
466 paint);
467 }
468
469 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
470 }
471
472 TEST_P(DisplayListTest, CanDrawStrokedText) {
473 flutter::DisplayListBuilder builder;
474 flutter::DlPaint paint;
475
476 paint.setDrawStyle(flutter::DlDrawStyle::kStroke);
477 paint.setColor(flutter::DlColor::kRed());
478 builder.DrawTextBlob(
479 SkTextBlob::MakeFromString("stoked about stroked text", CreateTestFont()),
480 250, 250, paint);
481
482 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
483 }
484
485 // Regression test for https://github.com/flutter/flutter/issues/133157.
486 TEST_P(DisplayListTest, StrokedTextNotOffsetFromNormalText) {
487 flutter::DisplayListBuilder builder;
488 flutter::DlPaint paint;
489 auto const& text_blob = SkTextBlob::MakeFromString("00000", CreateTestFont());
490
491 // https://api.flutter.dev/flutter/material/Colors/blue-constant.html.
492 auto const& mat_blue = flutter::DlColor(0xFF2196f3);
493
494 // Draw a blue filled rectangle so the text is easier to see.
495 paint.setDrawStyle(flutter::DlDrawStyle::kFill);
496 paint.setColor(mat_blue);
497 builder.DrawRect(DlRect::MakeXYWH(0, 0, 500, 500), paint);
498
499 // Draw stacked text, with stroked text on top.
500 paint.setDrawStyle(flutter::DlDrawStyle::kFill);
501 paint.setColor(flutter::DlColor::kWhite());
502 builder.DrawTextBlob(text_blob, 250, 250, paint);
503
504 paint.setDrawStyle(flutter::DlDrawStyle::kStroke);
505 paint.setColor(flutter::DlColor::kBlack());
506 builder.DrawTextBlob(text_blob, 250, 250, paint);
507
508 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
509 }
510
511 TEST_P(DisplayListTest, IgnoreMaskFilterWhenSavingLayer) {
512 auto texture = CreateTextureForFixture("embarcadero.jpg");
513 flutter::DisplayListBuilder builder;
514 auto filter = flutter::DlBlurMaskFilter(flutter::DlBlurStyle::kNormal, 10.0f);
515 flutter::DlPaint paint;
516 paint.setMaskFilter(&filter);
517 builder.SaveLayer(std::nullopt, &paint);
518 builder.DrawImage(DlImageImpeller::Make(texture), DlPoint(100, 100),
519 flutter::DlImageSampling::kNearestNeighbor);
520 builder.Restore();
521 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
522 }
523
524 TEST_P(DisplayListTest, CanDrawWithBlendColorFilter) {
525 auto texture = CreateTextureForFixture("embarcadero.jpg");
526 flutter::DisplayListBuilder builder;
527 flutter::DlPaint paint;
528
529 // Pipeline blended image.
530 {
531 auto filter = flutter::DlColorFilter::MakeBlend(
532 flutter::DlColor::kYellow(), flutter::DlBlendMode::kModulate);
533 paint.setColorFilter(filter);
534 builder.DrawImage(DlImageImpeller::Make(texture), DlPoint(100, 100),
535 flutter::DlImageSampling::kNearestNeighbor, &paint);
536 }
537
538 // Advanced blended image.
539 {
540 auto filter = flutter::DlColorFilter::MakeBlend(
541 flutter::DlColor::kRed(), flutter::DlBlendMode::kScreen);
542 paint.setColorFilter(filter);
543 builder.DrawImage(DlImageImpeller::Make(texture), DlPoint(250, 250),
544 flutter::DlImageSampling::kNearestNeighbor, &paint);
545 }
546
547 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
548 }
549
550 TEST_P(DisplayListTest, CanDrawWithColorFilterImageFilter) {
551 const float invert_color_matrix[20] = {
552 -1, 0, 0, 0, 1, //
553 0, -1, 0, 0, 1, //
554 0, 0, -1, 0, 1, //
555 0, 0, 0, 1, 0, //
556 };
557 auto texture = CreateTextureForFixture("boston.jpg");
558 flutter::DisplayListBuilder builder;
559 flutter::DlPaint paint;
560
561 auto color_filter = flutter::DlColorFilter::MakeMatrix(invert_color_matrix);
562 auto image_filter = flutter::DlImageFilter::MakeColorFilter(color_filter);
563
564 paint.setImageFilter(image_filter);
565 builder.DrawImage(DlImageImpeller::Make(texture), DlPoint(100, 100),
566 flutter::DlImageSampling::kNearestNeighbor, &paint);
567
568 builder.Translate(0, 700);
569 paint.setColorFilter(color_filter);
570 builder.DrawImage(DlImageImpeller::Make(texture), DlPoint(100, 100),
571 flutter::DlImageSampling::kNearestNeighbor, &paint);
572 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
573 }
574
575 TEST_P(DisplayListTest, CanDrawWithImageBlurFilter) {
576 auto texture = CreateTextureForFixture("embarcadero.jpg");
577
578 auto callback = [&]() {
579 static float sigma[] = {10, 10};
580
581 ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
582 ImGui::SliderFloat2("Sigma", sigma, 0, 100);
583 ImGui::End();
584
585 flutter::DisplayListBuilder builder;
586 flutter::DlPaint paint;
587
588 auto filter = flutter::DlBlurImageFilter(sigma[0], sigma[1],
589 flutter::DlTileMode::kClamp);
590 paint.setImageFilter(&filter);
591 builder.DrawImage(DlImageImpeller::Make(texture), DlPoint(200, 200),
592 flutter::DlImageSampling::kNearestNeighbor, &paint);
593
594 return builder.Build();
595 };
596
597 ASSERT_TRUE(OpenPlaygroundHere(callback));
598 }
599
600 TEST_P(DisplayListTest, CanDrawWithComposeImageFilter) {
601 auto texture = CreateTextureForFixture("boston.jpg");
602 flutter::DisplayListBuilder builder;
603 flutter::DlPaint paint;
604
605 auto dilate = std::make_shared<flutter::DlDilateImageFilter>(10.0, 10.0);
606 auto erode = std::make_shared<flutter::DlErodeImageFilter>(10.0, 10.0);
607 auto open = std::make_shared<flutter::DlComposeImageFilter>(dilate, erode);
608 auto close = std::make_shared<flutter::DlComposeImageFilter>(erode, dilate);
609
610 paint.setImageFilter(open.get());
611 builder.DrawImage(DlImageImpeller::Make(texture), DlPoint(100, 100),
612 flutter::DlImageSampling::kNearestNeighbor, &paint);
613 builder.Translate(0, 700);
614 paint.setImageFilter(close.get());
615 builder.DrawImage(DlImageImpeller::Make(texture), DlPoint(100, 100),
616 flutter::DlImageSampling::kNearestNeighbor, &paint);
617 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
618 }
619
620 TEST_P(DisplayListTest, CanClampTheResultingColorOfColorMatrixFilter) {
621 auto texture = CreateTextureForFixture("boston.jpg");
622 const float inner_color_matrix[20] = {
623 1, 0, 0, 0, 0, //
624 0, 1, 0, 0, 0, //
625 0, 0, 1, 0, 0, //
626 0, 0, 0, 2, 0, //
627 };
628 const float outer_color_matrix[20] = {
629 1, 0, 0, 0, 0, //
630 0, 1, 0, 0, 0, //
631 0, 0, 1, 0, 0, //
632 0, 0, 0, 0.5, 0, //
633 };
634 auto inner_color_filter =
635 flutter::DlColorFilter::MakeMatrix(inner_color_matrix);
636 auto outer_color_filter =
637 flutter::DlColorFilter::MakeMatrix(outer_color_matrix);
638 auto inner = flutter::DlImageFilter::MakeColorFilter(inner_color_filter);
639 auto outer = flutter::DlImageFilter::MakeColorFilter(outer_color_filter);
640 auto compose = std::make_shared<flutter::DlComposeImageFilter>(outer, inner);
641
642 flutter::DisplayListBuilder builder;
643 flutter::DlPaint paint;
644 paint.setImageFilter(compose.get());
645 builder.DrawImage(DlImageImpeller::Make(texture), DlPoint(100, 100),
646 flutter::DlImageSampling::kNearestNeighbor, &paint);
647 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
648 }
649
650 TEST_P(DisplayListTest, CanDrawBackdropFilter) {
651 auto texture = CreateTextureForFixture("embarcadero.jpg");
652
653 auto callback = [&]() {
654 static float sigma[] = {10, 10};
655 static float ctm_scale = 1;
656 static bool use_bounds = true;
657 static bool draw_circle = true;
658 static bool add_clip = true;
659
660 ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
661 ImGui::SliderFloat2("Sigma", sigma, 0, 100);
662 ImGui::SliderFloat("Scale", &ctm_scale, 0, 10);
663 ImGui::NewLine();
664 ImGui::TextWrapped(
665 "If everything is working correctly, none of the options below should "
666 "impact the filter's appearance.");
667 ImGui::Checkbox("Use SaveLayer bounds", &use_bounds);
668 ImGui::Checkbox("Draw child element", &draw_circle);
669 ImGui::Checkbox("Add pre-clip", &add_clip);
670 ImGui::End();
671
672 flutter::DisplayListBuilder builder;
673
674 Vector2 scale = ctm_scale * GetContentScale();
675 builder.Scale(scale.x, scale.y);
676
677 auto filter = flutter::DlBlurImageFilter(sigma[0], sigma[1],
678 flutter::DlTileMode::kClamp);
679
680 std::optional<DlRect> bounds;
681 if (use_bounds) {
682 static PlaygroundPoint point_a(Point(350, 150), 20, Color::White());
683 static PlaygroundPoint point_b(Point(800, 600), 20, Color::White());
684 auto [p1, p2] = DrawPlaygroundLine(point_a, point_b);
685 bounds = DlRect::MakeLTRB(p1.x, p1.y, p2.x, p2.y);
686 }
687
688 // Insert a clip to test that the backdrop filter handles stencil depths > 0
689 // correctly.
690 if (add_clip) {
691 builder.ClipRect(DlRect::MakeLTRB(0, 0, 99999, 99999),
692 flutter::DlClipOp::kIntersect, true);
693 }
694
695 builder.DrawImage(DlImageImpeller::Make(texture), DlPoint(200, 200),
696 flutter::DlImageSampling::kNearestNeighbor, nullptr);
697 builder.SaveLayer(bounds, nullptr, &filter);
698
699 if (draw_circle) {
700 static PlaygroundPoint center_point(Point(500, 400), 20, Color::Red());
701 auto circle_center = DrawPlaygroundPoint(center_point);
702
703 flutter::DlPaint paint;
704 paint.setDrawStyle(flutter::DlDrawStyle::kStroke);
705 paint.setStrokeCap(flutter::DlStrokeCap::kButt);
706 paint.setStrokeJoin(flutter::DlStrokeJoin::kBevel);
707 paint.setStrokeWidth(10);
708 paint.setColor(flutter::DlColor::kRed().withAlpha(100));
709 builder.DrawCircle(DlPoint(circle_center.x, circle_center.y), 100, paint);
710 }
711
712 return builder.Build();
713 };
714
715 ASSERT_TRUE(OpenPlaygroundHere(callback));
716 }
717
718 TEST_P(DisplayListTest, CanDrawNinePatchImage) {
719 // Image is drawn with corners to scale and center pieces stretched to fit.
720 auto texture = CreateTextureForFixture("embarcadero.jpg");
721 flutter::DisplayListBuilder builder;
722 auto size = texture->GetSize();
723 builder.DrawImageNine(
724 DlImageImpeller::Make(texture),
725 DlIRect::MakeLTRB(size.width / 4, size.height / 4, size.width * 3 / 4,
726 size.height * 3 / 4),
727 DlRect::MakeLTRB(0, 0, size.width * 2, size.height * 2),
728 flutter::DlFilterMode::kNearest, nullptr);
729 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
730 }
731
732 TEST_P(DisplayListTest, CanDrawNinePatchImageCenterWidthBiggerThanDest) {
733 // Edge case, the width of the corners does not leave any room for the
734 // center slice. The center (across the vertical axis) is folded out of the
735 // resulting image.
736 auto texture = CreateTextureForFixture("embarcadero.jpg");
737 flutter::DisplayListBuilder builder;
738 auto size = texture->GetSize();
739 builder.DrawImageNine(
740 DlImageImpeller::Make(texture),
741 DlIRect::MakeLTRB(size.width / 4, size.height / 4, size.width * 3 / 4,
742 size.height * 3 / 4),
743 DlRect::MakeLTRB(0, 0, size.width / 2, size.height),
744 flutter::DlFilterMode::kNearest, nullptr);
745 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
746 }
747
748 TEST_P(DisplayListTest, CanDrawNinePatchImageCenterHeightBiggerThanDest) {
749 // Edge case, the height of the corners does not leave any room for the
750 // center slice. The center (across the horizontal axis) is folded out of the
751 // resulting image.
752 auto texture = CreateTextureForFixture("embarcadero.jpg");
753 flutter::DisplayListBuilder builder;
754 auto size = texture->GetSize();
755 builder.DrawImageNine(
756 DlImageImpeller::Make(texture),
757 DlIRect::MakeLTRB(size.width / 4, size.height / 4, size.width * 3 / 4,
758 size.height * 3 / 4),
759 DlRect::MakeLTRB(0, 0, size.width, size.height / 2),
760 flutter::DlFilterMode::kNearest, nullptr);
761 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
762 }
763
764 TEST_P(DisplayListTest, CanDrawNinePatchImageCenterBiggerThanDest) {
765 // Edge case, the width and height of the corners does not leave any
766 // room for the center slices. Only the corners are displayed.
767 auto texture = CreateTextureForFixture("embarcadero.jpg");
768 flutter::DisplayListBuilder builder;
769 auto size = texture->GetSize();
770 builder.DrawImageNine(
771 DlImageImpeller::Make(texture),
772 DlIRect::MakeLTRB(size.width / 4, size.height / 4, size.width * 3 / 4,
773 size.height * 3 / 4),
774 DlRect::MakeLTRB(0, 0, size.width / 2, size.height / 2),
775 flutter::DlFilterMode::kNearest, nullptr);
776 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
777 }
778
779 TEST_P(DisplayListTest, CanDrawNinePatchImageCornersScaledDown) {
780 // Edge case, there is not enough room for the corners to be drawn
781 // without scaling them down.
782 auto texture = CreateTextureForFixture("embarcadero.jpg");
783 flutter::DisplayListBuilder builder;
784 auto size = texture->GetSize();
785 builder.DrawImageNine(
786 DlImageImpeller::Make(texture),
787 DlIRect::MakeLTRB(size.width / 4, size.height / 4, size.width * 3 / 4,
788 size.height * 3 / 4),
789 DlRect::MakeLTRB(0, 0, size.width / 4, size.height / 4),
790 flutter::DlFilterMode::kNearest, nullptr);
791 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
792 }
793
794 TEST_P(DisplayListTest, NinePatchImagePrecision) {
795 // Draw a nine patch image with colored corners and verify that the corner
796 // color does not leak outside the intended region.
797 auto texture = CreateTextureForFixture("nine_patch_corners.png");
798 flutter::DisplayListBuilder builder;
799 builder.DrawImageNine(DlImageImpeller::Make(texture),
800 DlIRect::MakeXYWH(10, 10, 1, 1),
801 DlRect::MakeXYWH(0, 0, 200, 100),
802 flutter::DlFilterMode::kNearest, nullptr);
803 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
804 }
805
806 TEST_P(DisplayListTest, CanDrawPoints) {
807 flutter::DisplayListBuilder builder;
808 DlPoint points[7] = {
809 {0, 0}, //
810 {100, 100}, //
811 {100, 0}, //
812 {0, 100}, //
813 {0, 0}, //
814 {48, 48}, //
815 {52, 52}, //
816 };
817 std::vector<flutter::DlStrokeCap> caps = {
818 flutter::DlStrokeCap::kButt,
819 flutter::DlStrokeCap::kRound,
820 flutter::DlStrokeCap::kSquare,
821 };
822 flutter::DlPaint paint =
823 flutter::DlPaint() //
824 .setColor(flutter::DlColor::kYellow().withAlpha(127)) //
825 .setStrokeWidth(20);
826 builder.Translate(50, 50);
827 for (auto cap : caps) {
828 paint.setStrokeCap(cap);
829 builder.Save();
830 builder.DrawPoints(flutter::DlPointMode::kPoints, 7, points, paint);
831 builder.Translate(150, 0);
832 builder.DrawPoints(flutter::DlPointMode::kLines, 5, points, paint);
833 builder.Translate(150, 0);
834 builder.DrawPoints(flutter::DlPointMode::kPolygon, 5, points, paint);
835 builder.Restore();
836 builder.Translate(0, 150);
837 }
838 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
839 }
840
841 TEST_P(DisplayListTest, CanDrawZeroLengthLine) {
842 flutter::DisplayListBuilder builder;
843 std::vector<flutter::DlStrokeCap> caps = {
844 flutter::DlStrokeCap::kButt,
845 flutter::DlStrokeCap::kRound,
846 flutter::DlStrokeCap::kSquare,
847 };
848 flutter::DlPaint paint =
849 flutter::DlPaint() //
850 .setColor(flutter::DlColor::kYellow().withAlpha(127)) //
851 .setDrawStyle(flutter::DlDrawStyle::kStroke) //
852 .setStrokeCap(flutter::DlStrokeCap::kButt) //
853 .setStrokeWidth(20);
854 DlPath path = DlPath::MakeLine({150, 50}, {150, 50});
855 for (auto cap : caps) {
856 paint.setStrokeCap(cap);
857 builder.DrawLine(DlPoint(50, 50), DlPoint(50, 50), paint);
858 builder.DrawPath(path, paint);
859 builder.Translate(0, 150);
860 }
861 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
862 }
863
864 TEST_P(DisplayListTest, CanDrawShadow) {
865 flutter::DisplayListBuilder builder;
866 flutter::DlPaint paint;
867
868 auto content_scale = GetContentScale() * 0.8;
869 builder.Scale(content_scale.x, content_scale.y);
870
871 constexpr size_t star_spikes = 5;
872 constexpr DlScalar half_spike_rotation = kPi / star_spikes;
873 constexpr DlScalar radius = 40;
874 constexpr DlScalar spike_size = 10;
875 constexpr DlScalar outer_radius = radius + spike_size;
876 constexpr DlScalar inner_radius = radius - spike_size;
877 std::array<DlPoint, star_spikes * 2> star;
878 for (size_t i = 0; i < star_spikes; i++) {
879 const DlScalar rotation = half_spike_rotation * i * 2;
880 star[i * 2] = DlPoint(50 + std::sin(rotation) * outer_radius,
881 50 - std::cos(rotation) * outer_radius);
882 star[i * 2 + 1] =
883 DlPoint(50 + std::sin(rotation + half_spike_rotation) * inner_radius,
884 50 - std::cos(rotation + half_spike_rotation) * inner_radius);
885 }
886
887 std::array<DlPath, 4> paths = {
888 DlPath::MakeRect(DlRect::MakeXYWH(0, 0, 200, 100)),
889 DlPath::MakeRoundRectXY(DlRect::MakeXYWH(20, 0, 200, 100), 30, 30),
890 DlPath::MakeCircle(DlPoint(100, 50), 50),
891 DlPath::MakePoly(star.data(), star.size(), true),
892 };
893 paint.setColor(flutter::DlColor::kWhite());
894 builder.DrawPaint(paint);
895 paint.setColor(flutter::DlColor::kCyan());
896 builder.Translate(100, 50);
897 for (size_t x = 0; x < paths.size(); x++) {
898 builder.Save();
899 for (size_t y = 0; y < 6; y++) {
900 builder.DrawShadow(paths[x], flutter::DlColor::kBlack(), 3 + y * 8, false,
901 1);
902 builder.DrawPath(paths[x], paint);
903 builder.Translate(0, 150);
904 }
905 builder.Restore();
906 builder.Translate(250, 0);
907 }
908
909 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
910 }
911
912 TEST_P(DisplayListTest, CanDrawZeroWidthLine) {
913 flutter::DisplayListBuilder builder;
914 std::vector<flutter::DlStrokeCap> caps = {
915 flutter::DlStrokeCap::kButt,
916 flutter::DlStrokeCap::kRound,
917 flutter::DlStrokeCap::kSquare,
918 };
919 flutter::DlPaint paint = //
920 flutter::DlPaint() //
921 .setColor(flutter::DlColor::kWhite()) //
922 .setDrawStyle(flutter::DlDrawStyle::kStroke) //
923 .setStrokeWidth(0);
924 flutter::DlPaint outline_paint = //
925 flutter::DlPaint() //
926 .setColor(flutter::DlColor::kYellow()) //
927 .setDrawStyle(flutter::DlDrawStyle::kStroke) //
928 .setStrokeCap(flutter::DlStrokeCap::kSquare) //
929 .setStrokeWidth(1);
930 DlPath path = DlPath::MakeLine({150, 50}, {160, 50});
931 for (auto cap : caps) {
932 paint.setStrokeCap(cap);
933 builder.DrawLine(DlPoint(50, 50), DlPoint(60, 50), paint);
934 builder.DrawRect(DlRect::MakeLTRB(45, 45, 65, 55), outline_paint);
935 builder.DrawLine(DlPoint{100, 50}, DlPoint{100, 50}, paint);
936 if (cap != flutter::DlStrokeCap::kButt) {
937 builder.DrawRect(DlRect::MakeLTRB(95, 45, 105, 55), outline_paint);
938 }
939 builder.DrawPath(path, paint);
940 builder.DrawRect(path.GetBounds().Expand(5, 5), outline_paint);
941 builder.Translate(0, 150);
942 }
943 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
944 }
945
946 TEST_P(DisplayListTest, CanDrawWithMatrixFilter) {
947 auto boston = CreateTextureForFixture("boston.jpg");
948
949 auto callback = [&]() {
950 static int selected_matrix_type = 0;
951 const char* matrix_type_names[] = {"Matrix", "Local Matrix"};
952
953 static float ctm_translation[2] = {200, 200};
954 static float ctm_scale[2] = {0.65, 0.65};
955 static float ctm_skew[2] = {0, 0};
956
957 static bool enable = true;
958 static float translation[2] = {100, 100};
959 static float scale[2] = {0.8, 0.8};
960 static float skew[2] = {0.2, 0.2};
961
962 static bool enable_savelayer = true;
963
964 ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
965 {
966 ImGui::Combo("Filter type", &selected_matrix_type, matrix_type_names,
967 sizeof(matrix_type_names) / sizeof(char*));
968
969 ImGui::TextWrapped("Current Transform");
970 ImGui::SliderFloat2("CTM Translation", ctm_translation, 0, 1000);
971 ImGui::SliderFloat2("CTM Scale", ctm_scale, 0, 3);
972 ImGui::SliderFloat2("CTM Skew", ctm_skew, -3, 3);
973
974 ImGui::TextWrapped(
975 "MatrixFilter and LocalMatrixFilter modify the CTM in the same way. "
976 "The only difference is that MatrixFilter doesn't affect the effect "
977 "transform, whereas LocalMatrixFilter does.");
978 // Note: See this behavior in:
979 // https://fiddle.skia.org/c/6cbb551ab36d06f163db8693972be954
980 ImGui::Checkbox("Enable", &enable);
981 ImGui::SliderFloat2("Filter Translation", translation, 0, 1000);
982 ImGui::SliderFloat2("Filter Scale", scale, 0, 3);
983 ImGui::SliderFloat2("Filter Skew", skew, -3, 3);
984
985 ImGui::TextWrapped(
986 "Rendering the filtered image within a layer can expose bounds "
987 "issues. If the rendered image gets cut off when this setting is "
988 "enabled, there's a coverage bug in the filter.");
989 ImGui::Checkbox("Render in layer", &enable_savelayer);
990 }
991 ImGui::End();
992
993 flutter::DisplayListBuilder builder;
994 flutter::DlPaint paint;
995
996 if (enable_savelayer) {
997 builder.SaveLayer(std::nullopt, nullptr);
998 }
999 {
1000 auto content_scale = GetContentScale();
1001 builder.Scale(content_scale.x, content_scale.y);
1002
1003 // Set the current transform
1004 auto ctm_matrix = Matrix::MakeRow(
1005 ctm_scale[0], ctm_skew[0], 0.0f, ctm_translation[0], //
1006 ctm_skew[1], ctm_scale[1], 0.0f, ctm_translation[1], //
1007 0, 0, 1, 0, //
1008 0, 0, 0, 1);
1009 builder.Transform(ctm_matrix);
1010
1011 // Set the matrix filter
1012 auto filter_matrix =
1013 Matrix::MakeRow(scale[0], skew[0], 0.0f, translation[0], //
1014 skew[1], scale[1], 0.0f, translation[1], //
1015 0.0f, 0.0f, 1.0f, 0.0f, //
1016 0.0f, 0.0f, 0.0f, 1.0f);
1017
1018 if (enable) {
1019 switch (selected_matrix_type) {
1020 case 0: {
1021 auto filter = flutter::DlMatrixImageFilter(
1022 filter_matrix, flutter::DlImageSampling::kLinear);
1023 paint.setImageFilter(&filter);
1024 break;
1025 }
1026 case 1: {
1027 auto internal_filter =
1028 flutter::DlBlurImageFilter(10, 10, flutter::DlTileMode::kDecal)
1029 .shared();
1030 auto filter = flutter::DlLocalMatrixImageFilter(filter_matrix,
1031 internal_filter);
1032 paint.setImageFilter(&filter);
1033 break;
1034 }
1035 }
1036 }
1037
1038 builder.DrawImage(DlImageImpeller::Make(boston), DlPoint(),
1039 flutter::DlImageSampling::kLinear, &paint);
1040 }
1041 if (enable_savelayer) {
1042 builder.Restore();
1043 }
1044
1045 return builder.Build();
1046 };
1047
1048 ASSERT_TRUE(OpenPlaygroundHere(callback));
1049 }
1050
1051 TEST_P(DisplayListTest, CanDrawWithMatrixFilterWhenSavingLayer) {
1052 auto callback = [&]() {
1053 static float translation[2] = {0, 0};
1054 static bool enable_save_layer = true;
1055
1056 ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
1057 ImGui::SliderFloat2("Translation", translation, -130, 130);
1058 ImGui::Checkbox("Enable save layer", &enable_save_layer);
1059 ImGui::End();
1060
1061 flutter::DisplayListBuilder builder;
1062 builder.Save();
1063 builder.Scale(2.0, 2.0);
1064 flutter::DlPaint paint;
1065 paint.setColor(flutter::DlColor::kYellow());
1066 builder.DrawRect(DlRect::MakeWH(300, 300), paint);
1067 paint.setStrokeWidth(1.0);
1068 paint.setDrawStyle(flutter::DlDrawStyle::kStroke);
1069 paint.setColor(flutter::DlColor::kBlack().withAlpha(0x80));
1070 builder.DrawLine(DlPoint(150, 0), DlPoint(150, 300), paint);
1071 builder.DrawLine(DlPoint(0, 150), DlPoint(300, 150), paint);
1072
1073 flutter::DlPaint save_paint;
1074 DlRect bounds = DlRect::MakeXYWH(100, 100, 100, 100);
1075 Matrix translate_matrix =
1076 Matrix::MakeTranslation({translation[0], translation[1]});
1077 if (enable_save_layer) {
1078 auto filter = flutter::DlMatrixImageFilter(
1079 translate_matrix, flutter::DlImageSampling::kNearestNeighbor);
1080 save_paint.setImageFilter(filter.shared());
1081 builder.SaveLayer(bounds, &save_paint);
1082 } else {
1083 builder.Save();
1084 builder.Transform(translate_matrix);
1085 }
1086
1087 Matrix filter_matrix;
1088 filter_matrix.Translate({150, 150});
1089 filter_matrix.Scale({0.2f, 0.2f});
1090 filter_matrix.Translate({-150, -150});
1091 auto filter = flutter::DlMatrixImageFilter(
1092 filter_matrix, flutter::DlImageSampling::kNearestNeighbor);
1093
1094 save_paint.setImageFilter(filter.shared());
1095
1096 builder.SaveLayer(bounds, &save_paint);
1097 flutter::DlPaint paint2;
1098 paint2.setColor(flutter::DlColor::kBlue());
1099 builder.DrawRect(bounds, paint2);
1100 builder.Restore();
1101 builder.Restore();
1102 return builder.Build();
1103 };
1104
1105 ASSERT_TRUE(OpenPlaygroundHere(callback));
1106 }
1107
1108 TEST_P(DisplayListTest, CanDrawRectWithLinearToSrgbColorFilter) {
1109 flutter::DlPaint paint;
1110 paint.setColor(flutter::DlColor(0xFF2196F3).withAlpha(128));
1111 flutter::DisplayListBuilder builder;
1112 paint.setColorFilter(flutter::DlColorFilter::MakeLinearToSrgbGamma());
1113 builder.DrawRect(DlRect::MakeXYWH(0, 0, 200, 200), paint);
1114 builder.Translate(0, 200);
1115
1116 paint.setColorFilter(flutter::DlColorFilter::MakeSrgbToLinearGamma());
1117 builder.DrawRect(DlRect::MakeXYWH(0, 0, 200, 200), paint);
1118
1119 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1120 }
1121
1122 TEST_P(DisplayListTest, CanDrawPaintWithColorSource) {
1123 const flutter::DlColor colors[2] = {
1124 flutter::DlColor(0xFFF44336),
1125 flutter::DlColor(0xFF2196F3),
1126 };
1127 const float stops[2] = {0.0, 1.0};
1128 flutter::DlPaint paint;
1129 flutter::DisplayListBuilder builder;
1130 auto clip_bounds = DlRect::MakeWH(300.0, 300.0);
1131 builder.Save();
1132 builder.Translate(100, 100);
1133 builder.ClipRect(clip_bounds, flutter::DlClipOp::kIntersect, false);
1134 auto linear =
1135 flutter::DlColorSource::MakeLinear({0.0, 0.0}, {100.0, 100.0}, 2, colors,
1136 stops, flutter::DlTileMode::kRepeat);
1137 paint.setColorSource(linear);
1138 builder.DrawPaint(paint);
1139 builder.Restore();
1140
1141 builder.Save();
1142 builder.Translate(500, 100);
1143 builder.ClipRect(clip_bounds, flutter::DlClipOp::kIntersect, false);
1144 auto radial = flutter::DlColorSource::MakeRadial(
1145 {100.0, 100.0}, 100.0, 2, colors, stops, flutter::DlTileMode::kRepeat);
1146 paint.setColorSource(radial);
1147 builder.DrawPaint(paint);
1148 builder.Restore();
1149
1150 builder.Save();
1151 builder.Translate(100, 500);
1152 builder.ClipRect(clip_bounds, flutter::DlClipOp::kIntersect, false);
1153 auto sweep =
1154 flutter::DlColorSource::MakeSweep({100.0, 100.0}, 180.0, 270.0, 2, colors,
1155 stops, flutter::DlTileMode::kRepeat);
1156 paint.setColorSource(sweep);
1157 builder.DrawPaint(paint);
1158 builder.Restore();
1159
1160 builder.Save();
1161 builder.Translate(500, 500);
1162 builder.ClipRect(clip_bounds, flutter::DlClipOp::kIntersect, false);
1163 auto texture = CreateTextureForFixture("table_mountain_nx.png");
1164 auto image = flutter::DlColorSource::MakeImage(DlImageImpeller::Make(texture),
1165 flutter::DlTileMode::kRepeat,
1166 flutter::DlTileMode::kRepeat);
1167 paint.setColorSource(image);
1168 builder.DrawPaint(paint);
1169 builder.Restore();
1170
1171 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1172 }
1173
1174 TEST_P(DisplayListTest, CanBlendDstOverAndDstCorrectly) {
1175 flutter::DisplayListBuilder builder;
1176
1177 {
1178 builder.SaveLayer(std::nullopt, nullptr);
1179 builder.Translate(100, 100);
1180 flutter::DlPaint paint;
1181 paint.setColor(flutter::DlColor::kRed());
1182 builder.DrawRect(DlRect::MakeWH(200, 200), paint);
1183 paint.setColor(flutter::DlColor::kBlue().withAlpha(127));
1184 paint.setBlendMode(flutter::DlBlendMode::kSrcOver);
1185 builder.DrawRect(DlRect::MakeWH(200, 200), paint);
1186 builder.Restore();
1187 }
1188 {
1189 builder.SaveLayer(std::nullopt, nullptr);
1190 builder.Translate(300, 100);
1191 flutter::DlPaint paint;
1192 paint.setColor(flutter::DlColor::kBlue().withAlpha(127));
1193 builder.DrawRect(DlRect::MakeWH(200, 200), paint);
1194 paint.setColor(flutter::DlColor::kRed());
1195 paint.setBlendMode(flutter::DlBlendMode::kDstOver);
1196 builder.DrawRect(DlRect::MakeWH(200, 200), paint);
1197 builder.Restore();
1198 }
1199 {
1200 builder.SaveLayer(std::nullopt, nullptr);
1201 builder.Translate(100, 300);
1202 flutter::DlPaint paint;
1203 paint.setColor(flutter::DlColor::kRed());
1204 builder.DrawRect(DlRect::MakeWH(200, 200), paint);
1205 paint.setColor(flutter::DlColor::kBlue().withAlpha(127));
1206 paint.setBlendMode(flutter::DlBlendMode::kSrc);
1207 builder.DrawRect(DlRect::MakeWH(200, 200), paint);
1208 builder.Restore();
1209 }
1210 {
1211 builder.SaveLayer(std::nullopt, nullptr);
1212 builder.Translate(300, 300);
1213 flutter::DlPaint paint;
1214 paint.setColor(flutter::DlColor::kBlue().withAlpha(127));
1215 builder.DrawRect(DlRect::MakeWH(200, 200), paint);
1216 paint.setColor(flutter::DlColor::kRed());
1217 paint.setBlendMode(flutter::DlBlendMode::kDst);
1218 builder.DrawRect(DlRect::MakeWH(200, 200), paint);
1219 builder.Restore();
1220 }
1221
1222 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1223 }
1224
1225 TEST_P(DisplayListTest, CanDrawCorrectlyWithColorFilterAndImageFilter) {
1226 flutter::DisplayListBuilder builder;
1227 const float green_color_matrix[20] = {
1228 0, 0, 0, 0, 0, //
1229 0, 0, 0, 0, 1, //
1230 0, 0, 0, 0, 0, //
1231 0, 0, 0, 1, 0, //
1232 };
1233 const float blue_color_matrix[20] = {
1234 0, 0, 0, 0, 0, //
1235 0, 0, 0, 0, 0, //
1236 0, 0, 0, 0, 1, //
1237 0, 0, 0, 1, 0, //
1238 };
1239 auto green_color_filter =
1240 flutter::DlColorFilter::MakeMatrix(green_color_matrix);
1241 auto blue_color_filter =
1242 flutter::DlColorFilter::MakeMatrix(blue_color_matrix);
1243 auto blue_image_filter =
1244 flutter::DlImageFilter::MakeColorFilter(blue_color_filter);
1245
1246 flutter::DlPaint paint;
1247 paint.setColor(flutter::DlColor::kRed());
1248 paint.setColorFilter(green_color_filter);
1249 paint.setImageFilter(blue_image_filter);
1250 builder.DrawRect(DlRect::MakeLTRB(100, 100, 500, 500), paint);
1251 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1252 }
1253
1254 TEST_P(DisplayListTest, MaskBlursApplyCorrectlyToColorSources) {
1255 auto blur_filter = std::make_shared<flutter::DlBlurMaskFilter>(
1256 flutter::DlBlurStyle::kNormal, 10);
1257
1258 flutter::DisplayListBuilder builder;
1259
1260 std::array<flutter::DlColor, 2> colors = {flutter::DlColor::kBlue(),
1261 flutter::DlColor::kGreen()};
1262 std::array<float, 2> stops = {0, 1};
1263 auto texture = CreateTextureForFixture("airplane.jpg");
1264 auto matrix = flutter::DlMatrix::MakeTranslation({-300, -110});
1265 std::array<std::shared_ptr<flutter::DlColorSource>, 2> color_sources = {
1266 flutter::DlColorSource::MakeImage(
1267 DlImageImpeller::Make(texture), flutter::DlTileMode::kRepeat,
1268 flutter::DlTileMode::kRepeat, flutter::DlImageSampling::kLinear,
1269 &matrix),
1270 flutter::DlColorSource::MakeLinear(
1271 flutter::DlPoint(0, 0), flutter::DlPoint(100, 50), 2, colors.data(),
1272 stops.data(), flutter::DlTileMode::kClamp),
1273 };
1274
1275 builder.Save();
1276 builder.Translate(0, 100);
1277 for (const auto& color_source : color_sources) {
1278 flutter::DlPaint paint;
1279 paint.setColorSource(color_source);
1280 paint.setMaskFilter(blur_filter);
1281
1282 builder.Save();
1283 builder.Translate(100, 0);
1284 paint.setDrawStyle(flutter::DlDrawStyle::kFill);
1285 builder.DrawRoundRect(
1286 DlRoundRect::MakeRectXY(DlRect::MakeWH(100, 50), 30, 30), paint);
1287
1288 paint.setDrawStyle(flutter::DlDrawStyle::kStroke);
1289 paint.setStrokeWidth(10);
1290 builder.Translate(200, 0);
1291 builder.DrawRoundRect(
1292 DlRoundRect::MakeRectXY(DlRect::MakeWH(100, 50), 30, 30), paint);
1293
1294 builder.Restore();
1295 builder.Translate(0, 100);
1296 }
1297 builder.Restore();
1298
1299 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1300 }
1301
1302 TEST_P(DisplayListTest, DrawShapes) {
1303 flutter::DisplayListBuilder builder;
1304 std::vector<flutter::DlStrokeJoin> joins = {
1305 flutter::DlStrokeJoin::kBevel,
1306 flutter::DlStrokeJoin::kRound,
1307 flutter::DlStrokeJoin::kMiter,
1308 };
1309 flutter::DlPaint paint = //
1310 flutter::DlPaint() //
1311 .setColor(flutter::DlColor::kWhite()) //
1312 .setDrawStyle(flutter::DlDrawStyle::kFill) //
1313 .setStrokeWidth(10);
1314 flutter::DlPaint stroke_paint = //
1315 flutter::DlPaint() //
1316 .setColor(flutter::DlColor::kWhite()) //
1317 .setDrawStyle(flutter::DlDrawStyle::kStroke) //
1318 .setStrokeWidth(10);
1319 DlPath path = DlPath::MakeLine({150, 50}, {160, 50});
1320
1321 builder.Translate(300, 50);
1322 builder.Scale(0.8, 0.8);
1323 for (auto join : joins) {
1324 paint.setStrokeJoin(join);
1325 stroke_paint.setStrokeJoin(join);
1326 builder.DrawRect(DlRect::MakeXYWH(0, 0, 100, 100), paint);
1327 builder.DrawRect(DlRect::MakeXYWH(0, 150, 100, 100), stroke_paint);
1328 builder.DrawRoundRect(
1329 DlRoundRect::MakeRectXY(DlRect::MakeXYWH(150, 0, 100, 100), 30, 30),
1330 paint);
1331 builder.DrawRoundRect(
1332 DlRoundRect::MakeRectXY(DlRect::MakeXYWH(150, 150, 100, 100), 30, 30),
1333 stroke_paint);
1334 builder.DrawCircle(DlPoint(350, 50), 50, paint);
1335 builder.DrawCircle(DlPoint(350, 200), 50, stroke_paint);
1336 builder.Translate(0, 300);
1337 }
1338 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1339 }
1340
1341 TEST_P(DisplayListTest, ClipDrawRRectWithNonCircularRadii) {
1342 flutter::DisplayListBuilder builder;
1343
1344 flutter::DlPaint fill_paint = //
1345 flutter::DlPaint() //
1346 .setColor(flutter::DlColor::kBlue()) //
1347 .setDrawStyle(flutter::DlDrawStyle::kFill) //
1348 .setStrokeWidth(10);
1349 flutter::DlPaint stroke_paint = //
1350 flutter::DlPaint() //
1351 .setColor(flutter::DlColor::kGreen()) //
1352 .setDrawStyle(flutter::DlDrawStyle::kStroke) //
1353 .setStrokeWidth(10);
1354
1355 builder.DrawRoundRect(
1356 DlRoundRect::MakeRectXY(DlRect::MakeXYWH(500, 100, 300, 300), 120, 40),
1357 fill_paint);
1358 builder.DrawRoundRect(
1359 DlRoundRect::MakeRectXY(DlRect::MakeXYWH(500, 100, 300, 300), 120, 40),
1360 stroke_paint);
1361
1362 builder.DrawRoundRect(
1363 DlRoundRect::MakeRectXY(DlRect::MakeXYWH(100, 500, 300, 300), 40, 120),
1364 fill_paint);
1365 builder.DrawRoundRect(
1366 DlRoundRect::MakeRectXY(DlRect::MakeXYWH(100, 500, 300, 300), 40, 120),
1367 stroke_paint);
1368
1369 flutter::DlPaint reference_paint = //
1370 flutter::DlPaint() //
1371 .setColor(flutter::DlColor::kMidGrey()) //
1372 .setDrawStyle(flutter::DlDrawStyle::kFill) //
1373 .setStrokeWidth(10);
1374
1375 builder.DrawRoundRect(
1376 DlRoundRect::MakeRectXY(DlRect::MakeXYWH(500, 500, 300, 300), 40, 40),
1377 reference_paint);
1378 builder.DrawRoundRect(
1379 DlRoundRect::MakeRectXY(DlRect::MakeXYWH(100, 100, 300, 300), 120, 120),
1380 reference_paint);
1381
1382 flutter::DlPaint clip_fill_paint = //
1383 flutter::DlPaint() //
1384 .setColor(flutter::DlColor::kCyan()) //
1385 .setDrawStyle(flutter::DlDrawStyle::kFill) //
1386 .setStrokeWidth(10);
1387
1388 builder.Save();
1389 builder.ClipRoundRect(
1390 DlRoundRect::MakeRectXY(DlRect::MakeXYWH(900, 100, 300, 300), 120, 40));
1391 builder.DrawPaint(clip_fill_paint);
1392 builder.Restore();
1393
1394 builder.Save();
1395 builder.ClipRoundRect(
1396 DlRoundRect::MakeRectXY(DlRect::MakeXYWH(100, 900, 300, 300), 40, 120));
1397 builder.DrawPaint(clip_fill_paint);
1398 builder.Restore();
1399
1400 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1401 }
1402
1403 TEST_P(DisplayListTest, DrawVerticesBlendModes) {
1404 std::vector<const char*> blend_mode_names;
1405 std::vector<flutter::DlBlendMode> blend_mode_values;
1406 {
1407 const std::vector<std::tuple<const char*, flutter::DlBlendMode>> blends = {
1408 // Pipeline blends (Porter-Duff alpha compositing)
1409 {"Clear", flutter::DlBlendMode::kClear},
1410 {"Source", flutter::DlBlendMode::kSrc},
1411 {"Destination", flutter::DlBlendMode::kDst},
1412 {"SourceOver", flutter::DlBlendMode::kSrcOver},
1413 {"DestinationOver", flutter::DlBlendMode::kDstOver},
1414 {"SourceIn", flutter::DlBlendMode::kSrcIn},
1415 {"DestinationIn", flutter::DlBlendMode::kDstIn},
1416 {"SourceOut", flutter::DlBlendMode::kSrcOut},
1417 {"DestinationOut", flutter::DlBlendMode::kDstOut},
1418 {"SourceATop", flutter::DlBlendMode::kSrcATop},
1419 {"DestinationATop", flutter::DlBlendMode::kDstATop},
1420 {"Xor", flutter::DlBlendMode::kXor},
1421 {"Plus", flutter::DlBlendMode::kPlus},
1422 {"Modulate", flutter::DlBlendMode::kModulate},
1423 // Advanced blends (color component blends)
1424 {"Screen", flutter::DlBlendMode::kScreen},
1425 {"Overlay", flutter::DlBlendMode::kOverlay},
1426 {"Darken", flutter::DlBlendMode::kDarken},
1427 {"Lighten", flutter::DlBlendMode::kLighten},
1428 {"ColorDodge", flutter::DlBlendMode::kColorDodge},
1429 {"ColorBurn", flutter::DlBlendMode::kColorBurn},
1430 {"HardLight", flutter::DlBlendMode::kHardLight},
1431 {"SoftLight", flutter::DlBlendMode::kSoftLight},
1432 {"Difference", flutter::DlBlendMode::kDifference},
1433 {"Exclusion", flutter::DlBlendMode::kExclusion},
1434 {"Multiply", flutter::DlBlendMode::kMultiply},
1435 {"Hue", flutter::DlBlendMode::kHue},
1436 {"Saturation", flutter::DlBlendMode::kSaturation},
1437 {"Color", flutter::DlBlendMode::kColor},
1438 {"Luminosity", flutter::DlBlendMode::kLuminosity},
1439 };
1440 assert(blends.size() ==
1441 static_cast<size_t>(flutter::DlBlendMode::kLastMode) + 1);
1442 for (const auto& [name, mode] : blends) {
1443 blend_mode_names.push_back(name);
1444 blend_mode_values.push_back(mode);
1445 }
1446 }
1447
1448 auto callback = [&]() {
1449 static int current_blend_index = 3;
1450 static float dst_alpha = 1;
1451 static float src_alpha = 1;
1452 static float color0[4] = {1.0f, 0.0f, 0.0f, 1.0f};
1453 static float color1[4] = {0.0f, 1.0f, 0.0f, 1.0f};
1454 static float color2[4] = {0.0f, 0.0f, 1.0f, 1.0f};
1455 static float src_color[4] = {1.0f, 1.0f, 1.0f, 1.0f};
1456
1457 ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
1458 {
1459 ImGui::ListBox("Blending mode", &current_blend_index,
1460 blend_mode_names.data(), blend_mode_names.size());
1461 ImGui::SliderFloat("Source alpha", &src_alpha, 0, 1);
1462 ImGui::ColorEdit4("Color A", color0);
1463 ImGui::ColorEdit4("Color B", color1);
1464 ImGui::ColorEdit4("Color C", color2);
1465 ImGui::ColorEdit4("Source Color", src_color);
1466 ImGui::SliderFloat("Destination alpha", &dst_alpha, 0, 1);
1467 }
1468 ImGui::End();
1469
1470 std::vector<DlPoint> positions = {DlPoint(100, 300), //
1471 DlPoint(200, 100), //
1472 DlPoint(300, 300)};
1473 std::vector<flutter::DlColor> colors = {
1474 toColor(color0).modulateOpacity(dst_alpha),
1475 toColor(color1).modulateOpacity(dst_alpha),
1476 toColor(color2).modulateOpacity(dst_alpha)};
1477
1478 auto vertices = flutter::DlVertices::Make(
1479 flutter::DlVertexMode::kTriangles, 3, positions.data(),
1480 /*texture_coordinates=*/nullptr, colors.data());
1481
1482 flutter::DisplayListBuilder builder;
1483 flutter::DlPaint paint;
1484
1485 paint.setColor(toColor(src_color).modulateOpacity(src_alpha));
1486 builder.DrawVertices(vertices, blend_mode_values[current_blend_index],
1487 paint);
1488 return builder.Build();
1489 };
1490
1491 ASSERT_TRUE(OpenPlaygroundHere(callback));
1492 }
1493
1494 TEST_P(DisplayListTest, DrawPaintIgnoresMaskFilter) {
1495 flutter::DisplayListBuilder builder;
1496 builder.DrawPaint(flutter::DlPaint().setColor(flutter::DlColor::kWhite()));
1497
1498 auto filter = flutter::DlBlurMaskFilter(flutter::DlBlurStyle::kNormal, 10.0f);
1499 builder.DrawCircle(DlPoint(300, 300), 200,
1500 flutter::DlPaint().setMaskFilter(&filter));
1501
1502 std::vector<flutter::DlColor> colors = {flutter::DlColor::kGreen(),
1503 flutter::DlColor::kGreen()};
1504 const float stops[2] = {0.0, 1.0};
1505 auto linear = flutter::DlColorSource::MakeLinear(
1506 {100.0, 100.0}, {300.0, 300.0}, 2, colors.data(), stops,
1507 flutter::DlTileMode::kRepeat);
1508 flutter::DlPaint blend_paint =
1509 flutter::DlPaint() //
1510 .setColorSource(linear) //
1511 .setBlendMode(flutter::DlBlendMode::kScreen);
1512 builder.DrawPaint(blend_paint);
1513
1514 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1515 }
1516
1517 TEST_P(DisplayListTest, DrawMaskBlursThatMightUseSaveLayers) {
1518 flutter::DisplayListBuilder builder;
1519 builder.DrawColor(flutter::DlColor::kWhite(), flutter::DlBlendMode::kSrc);
1520 Vector2 scale = GetContentScale();
1521 builder.Scale(scale.x, scale.y);
1522
1523 builder.Save();
1524 // We need a small transform op to avoid a deferred save
1525 builder.Translate(1.0f, 1.0f);
1526 auto solid_filter =
1527 flutter::DlBlurMaskFilter::Make(flutter::DlBlurStyle::kSolid, 5.0f);
1528 flutter::DlPaint solid_alpha_paint =
1529 flutter::DlPaint() //
1530 .setMaskFilter(solid_filter) //
1531 .setColor(flutter::DlColor::kBlue()) //
1532 .setAlpha(0x7f);
1533 for (int x = 1; x <= 4; x++) {
1534 for (int y = 1; y <= 4; y++) {
1535 builder.DrawRect(DlRect::MakeXYWH(x * 100, y * 100, 80, 80),
1536 solid_alpha_paint);
1537 }
1538 }
1539 builder.Restore();
1540
1541 builder.Save();
1542 builder.Translate(500.0f, 0.0f);
1543 auto normal_filter =
1544 flutter::DlBlurMaskFilter::Make(flutter::DlBlurStyle::kNormal, 5.0f);
1545 auto rotate_if = flutter::DlMatrixImageFilter::Make(
1546 Matrix::MakeRotationZ(Degrees(10)), flutter::DlImageSampling::kLinear);
1547 flutter::DlPaint normal_if_paint =
1548 flutter::DlPaint() //
1549 .setMaskFilter(solid_filter) //
1550 .setImageFilter(rotate_if) //
1551 .setColor(flutter::DlColor::kGreen()) //
1552 .setAlpha(0x7f);
1553 for (int x = 1; x <= 4; x++) {
1554 for (int y = 1; y <= 4; y++) {
1555 builder.DrawRect(DlRect::MakeXYWH(x * 100, y * 100, 80, 80),
1556 normal_if_paint);
1557 }
1558 }
1559 builder.Restore();
1560
1561 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1562 }
1563
1564 } // namespace testing
1565 } // namespace impeller
aiks_context.h
impeller::DlImageImpeller::Make
static sk_sp< DlImageImpeller > Make(std::shared_ptr< Texture > texture, OwningContext owning_context=OwningContext::kIO)
Definition: dl_image_impeller.cc:23
impeller::DlPlayground
Definition: dl_playground.h:16
clip_contents.h
dl_dispatcher.h
x
int32_t x
Definition: dl_golden_unittests.cc:458
dl_image_impeller.h
dl_playground.h
constants.h
impeller::testing::TEST_P
TEST_P(AiksTest, DrawAtlasNoColor)
Definition: aiks_dl_atlas_unittests.cc:60
impeller::testing::toColor
flutter::DlColor toColor(const float *components)
Definition: dl_unittests.cc:37
impeller::testing::INSTANTIATE_PLAYGROUND_SUITE
INSTANTIATE_PLAYGROUND_SUITE(AiksTest)
impeller
Definition: allocation.cc:12
impeller::DlRect
flutter::DlRect DlRect
Definition: dl_dispatcher.h:25
impeller::kPi
constexpr float kPi
Definition: constants.h:26
impeller::DrawPlaygroundPoint
Point DrawPlaygroundPoint(PlaygroundPoint &point)
Definition: widgets.cc:9
impeller::DrawPlaygroundLine
std::tuple< Point, Point > DrawPlaygroundLine(PlaygroundPoint &point_a, PlaygroundPoint &point_b)
Definition: widgets.cc:50
impeller::Point
TPoint< Scalar > Point
Definition: point.h:327
impeller::DlPoint
flutter::DlPoint DlPoint
Definition: dl_dispatcher.h:24
impeller::DlPath
flutter::DlPath DlPath
Definition: dl_dispatcher.h:29
impeller::DlScalar
flutter::DlScalar DlScalar
Definition: dl_dispatcher.h:23
point.h
scalar.h
solid_color_contents.h
solid_rrect_blur_contents.h
stroke_width
const Scalar stroke_width
Definition: stroke_path_geometry.cc:315
scale
const Scalar scale
Definition: stroke_path_geometry.cc:319
impeller::Color
Definition: color.h:124
impeller::Color::ToIColor
static constexpr uint32_t ToIColor(Color color)
Convert this color to a 32-bit representation.
Definition: color.h:159
impeller::Color::White
static constexpr Color White()
Definition: color.h:264
impeller::Color::Red
static constexpr Color Red()
Definition: color.h:272
impeller::Degrees
Definition: scalar.h:51
impeller::Matrix
A 4x4 matrix using column-major storage.
Definition: matrix.h:37
impeller::Matrix::MakeTranslation
static constexpr Matrix MakeTranslation(const Vector3 &t)
Definition: matrix.h:95
impeller::Matrix::Translate
constexpr Matrix Translate(const Vector3 &t) const
Definition: matrix.h:263
impeller::Matrix::MakeRow
static constexpr Matrix MakeRow(Scalar m0, Scalar m1, Scalar m2, Scalar m3, Scalar m4, Scalar m5, Scalar m6, Scalar m7, Scalar m8, Scalar m9, Scalar m10, Scalar m11, Scalar m12, Scalar m13, Scalar m14, Scalar m15)
Definition: matrix.h:83
impeller::Matrix::Scale
constexpr Matrix Scale(const Vector3 &s) const
Definition: matrix.h:275
impeller::Matrix::MakeRotationZ
static Matrix MakeRotationZ(Radians r)
Definition: matrix.h:223
impeller::PlaygroundPoint
Definition: widgets.h:17
impeller::TPoint< Scalar >
widgets.h