Flutter Impeller
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 
5 #include "display_list/display_list.h"
6 #include "display_list/dl_sampling_options.h"
7 #include "display_list/dl_tile_mode.h"
8 #include "display_list/effects/dl_color_filter.h"
9 #include "display_list/effects/dl_color_source.h"
10 #include "display_list/effects/dl_image_filter.h"
11 #include "display_list/effects/dl_mask_filter.h"
13 
14 #include "flutter/display_list/dl_blend_mode.h"
15 #include "flutter/display_list/dl_builder.h"
16 #include "flutter/display_list/dl_color.h"
17 #include "flutter/display_list/dl_paint.h"
18 #include "flutter/display_list/geometry/dl_path_builder.h"
21 #include "flutter/testing/display_list_testing.h"
22 #include "flutter/testing/testing.h"
24 
25 namespace impeller {
26 namespace testing {
27 
28 using namespace flutter;
29 
30 TEST_P(AiksTest, CanRenderColoredRect) {
31  DisplayListBuilder builder;
32  DlPaint paint;
33  paint.setColor(DlColor::kBlue());
34  builder.DrawPath(DlPath::MakeRectXYWH(100.0f, 100.0f, 100.0f, 100.0f), paint);
35  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
36 }
37 
38 namespace {
39 using DrawRectProc =
40  std::function<void(DisplayListBuilder&, const DlRect&, const DlPaint&)>;
41 
42 sk_sp<DisplayList> MakeWideStrokedRects(Point scale,
43  const DrawRectProc& draw_rect) {
44  DisplayListBuilder builder;
45  builder.Scale(scale.x, scale.y);
46  builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc);
47 
48  DlPaint paint;
49  paint.setColor(DlColor::kBlue().withAlphaF(0.5));
50  paint.setDrawStyle(DlDrawStyle::kStroke);
51  paint.setStrokeWidth(30.0f);
52 
53  // Each of these 3 sets of rects includes (with different join types):
54  // - One rectangle with a gap in the middle
55  // - One rectangle with no gap because it is too narrow
56  // - One rectangle with no gap because it is too short
57  paint.setStrokeJoin(DlStrokeJoin::kBevel);
58  draw_rect(builder, DlRect::MakeXYWH(100.0f, 100.0f, 100.0f, 100.0f), paint);
59  draw_rect(builder, DlRect::MakeXYWH(250.0f, 100.0f, 10.0f, 100.0f), paint);
60  draw_rect(builder, DlRect::MakeXYWH(100.0f, 250.0f, 100.0f, 10.0f), paint);
61 
62  paint.setStrokeJoin(DlStrokeJoin::kRound);
63  draw_rect(builder, DlRect::MakeXYWH(350.0f, 100.0f, 100.0f, 100.0f), paint);
64  draw_rect(builder, DlRect::MakeXYWH(500.0f, 100.0f, 10.0f, 100.0f), paint);
65  draw_rect(builder, DlRect::MakeXYWH(350.0f, 250.0f, 100.0f, 10.0f), paint);
66 
67  paint.setStrokeJoin(DlStrokeJoin::kMiter);
68  draw_rect(builder, DlRect::MakeXYWH(600.0f, 100.0f, 100.0f, 100.0f), paint);
69  draw_rect(builder, DlRect::MakeXYWH(750.0f, 100.0f, 10.0f, 100.0f), paint);
70  draw_rect(builder, DlRect::MakeXYWH(600.0f, 250.0f, 100.0f, 10.0f), paint);
71 
72  // And now draw 3 rectangles with a stroke width so large that that it
73  // overlaps in the middle in both directions (horizontal/vertical).
74  paint.setStrokeWidth(110.0f);
75 
76  paint.setStrokeJoin(DlStrokeJoin::kBevel);
77  draw_rect(builder, DlRect::MakeXYWH(100.0f, 400.0f, 100.0f, 100.0f), paint);
78 
79  paint.setStrokeJoin(DlStrokeJoin::kRound);
80  draw_rect(builder, DlRect::MakeXYWH(350.0f, 400.0f, 100.0f, 100.0f), paint);
81 
82  paint.setStrokeJoin(DlStrokeJoin::kMiter);
83  draw_rect(builder, DlRect::MakeXYWH(600.0f, 400.0f, 100.0f, 100.0f), paint);
84 
85  return builder.Build();
86 }
87 } // namespace
88 
89 TEST_P(AiksTest, CanRenderWideStrokedRectWithoutOverlap) {
90  ASSERT_TRUE(OpenPlaygroundHere(MakeWideStrokedRects(
91  GetContentScale(), [](DisplayListBuilder& builder, const DlRect& rect,
92  const DlPaint& paint) {
93  // Draw the rect directly
94  builder.DrawRect(rect, paint);
95  })));
96 }
97 
98 TEST_P(AiksTest, CanRenderWideStrokedRectPathWithoutOverlap) {
99  ASSERT_TRUE(OpenPlaygroundHere(MakeWideStrokedRects(
100  GetContentScale(), [](DisplayListBuilder& builder, const DlRect& rect,
101  const DlPaint& paint) {
102  // Draw the rect as a Path
103  builder.DrawPath(DlPath::MakeRect(rect), paint);
104  })));
105 }
106 
107 TEST_P(AiksTest, CanRenderImage) {
108  DisplayListBuilder builder;
109  DlPaint paint;
110  paint.setColor(DlColor::kRed());
111  auto image = DlImageImpeller::Make(CreateTextureForFixture("kalimba.jpg"));
112  builder.DrawImage(image, DlPoint(100.0, 100.0),
113  DlImageSampling::kNearestNeighbor, &paint);
114  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
115 }
116 
117 TEST_P(AiksTest, CanRenderInvertedImageWithColorFilter) {
118  DisplayListBuilder builder;
119  DlPaint paint;
120  paint.setColor(DlColor::kRed());
121  paint.setColorFilter(
122  DlColorFilter::MakeBlend(DlColor::kYellow(), DlBlendMode::kSrcOver));
123  paint.setInvertColors(true);
124  auto image = DlImageImpeller::Make(CreateTextureForFixture("kalimba.jpg"));
125 
126  builder.DrawImage(image, DlPoint(100.0, 100.0),
127  DlImageSampling::kNearestNeighbor, &paint);
128  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
129 }
130 
131 TEST_P(AiksTest, CanRenderColorFilterWithInvertColors) {
132  DisplayListBuilder builder;
133  DlPaint paint;
134  paint.setColor(DlColor::kRed());
135  paint.setColorFilter(
136  DlColorFilter::MakeBlend(DlColor::kYellow(), DlBlendMode::kSrcOver));
137  paint.setInvertColors(true);
138 
139  builder.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100), paint);
140  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
141 }
142 
143 TEST_P(AiksTest, CanRenderColorFilterWithInvertColorsDrawPaint) {
144  DisplayListBuilder builder;
145  DlPaint paint;
146  paint.setColor(DlColor::kRed());
147  paint.setColorFilter(
148  DlColorFilter::MakeBlend(DlColor::kYellow(), DlBlendMode::kSrcOver));
149  paint.setInvertColors(true);
150 
151  builder.DrawPaint(paint);
152  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
153 }
154 
155 namespace {
156 bool GenerateMipmap(const std::shared_ptr<Context>& context,
157  std::shared_ptr<Texture> texture,
158  std::string_view label) {
159  auto buffer = context->CreateCommandBuffer();
160  if (!buffer) {
161  return false;
162  }
163  auto pass = buffer->CreateBlitPass();
164  if (!pass) {
165  return false;
166  }
167  pass->GenerateMipmap(std::move(texture), label);
168 
169  pass->EncodeCommands();
170  return context->GetCommandQueue()->Submit({buffer}).ok();
171 }
172 
173 void CanRenderTiledTexture(AiksTest* aiks_test,
174  DlTileMode tile_mode,
175  Matrix local_matrix = {}) {
176  auto context = aiks_test->GetContext();
177  ASSERT_TRUE(context);
178  auto texture = aiks_test->CreateTextureForFixture("table_mountain_nx.png",
179  /*enable_mipmapping=*/true);
180  GenerateMipmap(context, texture, "table_mountain_nx");
181  auto image = DlImageImpeller::Make(texture);
182  auto color_source = DlColorSource::MakeImage(
183  image, tile_mode, tile_mode, DlImageSampling::kNearestNeighbor,
184  &local_matrix);
185 
186  DisplayListBuilder builder;
187  DlPaint paint;
188  paint.setColor(DlColor::kWhite());
189  paint.setColorSource(color_source);
190 
191  builder.Scale(aiks_test->GetContentScale().x, aiks_test->GetContentScale().y);
192  builder.Translate(100.0f, 100.0f);
193  builder.DrawRect(DlRect::MakeXYWH(0, 0, 600, 600), paint);
194 
195  // Should not change the image.
196  constexpr auto stroke_width = 64;
197  paint.setDrawStyle(DlDrawStyle::kStroke);
198  paint.setStrokeWidth(stroke_width);
199  if (tile_mode == DlTileMode::kDecal) {
200  builder.DrawRect(DlRect::MakeXYWH(stroke_width, stroke_width, 600, 600),
201  paint);
202  } else {
203  builder.DrawRect(DlRect::MakeXYWH(0, 0, 600, 600), paint);
204  }
205 
206  {
207  // Should not change the image.
208  DlPathBuilder path_builder;
209  path_builder.AddCircle(DlPoint(150, 150), 150);
210  path_builder.AddRoundRect(
211  RoundRect::MakeRectXY(DlRect::MakeLTRB(300, 300, 600, 600), 10, 10));
212  DlPath path = path_builder.TakePath();
213 
214  // Make sure path cannot be simplified...
215  EXPECT_FALSE(path.IsRect(nullptr));
216  EXPECT_FALSE(path.IsOval(nullptr));
217  EXPECT_FALSE(path.IsRoundRect(nullptr));
218 
219  // Make sure path will not trigger the optimal convex code
220  EXPECT_FALSE(path.IsConvex());
221 
222  paint.setDrawStyle(DlDrawStyle::kFill);
223  builder.DrawPath(path, paint);
224  }
225 
226  {
227  // Should not change the image. Tests the Convex short-cut code.
228 
229  // To avoid simplification, construct an explicit circle using conics.
230  constexpr float kConicWeight = 0.707106781f; // sqrt(2)/2
231  const DlPath path = DlPathBuilder()
232  .MoveTo({150, 300})
233  .ConicCurveTo({300, 300}, {300, 450}, kConicWeight)
234  .ConicCurveTo({300, 600}, {150, 600}, kConicWeight)
235  .ConicCurveTo({0, 600}, {0, 450}, kConicWeight)
236  .ConicCurveTo({0, 300}, {150, 300}, kConicWeight)
237  .Close()
238  .TakePath();
239 
240  // Make sure path cannot be simplified...
241  EXPECT_FALSE(path.IsRect(nullptr));
242  EXPECT_FALSE(path.IsOval(nullptr));
243  EXPECT_FALSE(path.IsRoundRect(nullptr));
244 
245  // But check that we will trigger the optimal convex code
246  EXPECT_TRUE(path.IsConvex());
247 
248  paint.setDrawStyle(DlDrawStyle::kFill);
249  builder.DrawPath(path, paint);
250  }
251 
252  ASSERT_TRUE(aiks_test->OpenPlaygroundHere(builder.Build()));
253 }
254 } // namespace
255 
256 TEST_P(AiksTest, CanRenderTiledTextureClamp) {
257  CanRenderTiledTexture(this, DlTileMode::kClamp);
258 }
259 
260 TEST_P(AiksTest, CanRenderTiledTextureRepeat) {
261  CanRenderTiledTexture(this, DlTileMode::kRepeat);
262 }
263 
264 TEST_P(AiksTest, CanRenderTiledTextureMirror) {
265  CanRenderTiledTexture(this, DlTileMode::kMirror);
266 }
267 
268 TEST_P(AiksTest, CanRenderTiledTextureDecal) {
269  CanRenderTiledTexture(this, DlTileMode::kDecal);
270 }
271 
272 TEST_P(AiksTest, CanRenderTiledTextureClampWithTranslate) {
273  CanRenderTiledTexture(this, DlTileMode::kClamp,
274  Matrix::MakeTranslation({172.f, 172.f, 0.f}));
275 }
276 
277 TEST_P(AiksTest, CanRenderImageRect) {
278  DisplayListBuilder builder;
279  auto image = DlImageImpeller::Make(CreateTextureForFixture("kalimba.jpg"));
280 
281  DlISize image_half_size =
282  DlISize(image->GetSize().width * 0.5f, image->GetSize().height * 0.5f);
283 
284  // Render the bottom right quarter of the source image in a stretched rect.
285  auto source_rect = DlRect::MakeSize(image_half_size);
286  source_rect =
287  source_rect.Shift(image_half_size.width, image_half_size.height);
288 
289  builder.DrawImageRect(image, source_rect,
290  DlRect::MakeXYWH(100, 100, 600, 600),
291  DlImageSampling::kNearestNeighbor);
292  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
293 }
294 
295 TEST_P(AiksTest, DrawImageRectSrcOutsideBounds) {
296  DisplayListBuilder builder;
297  auto image = DlImageImpeller::Make(CreateTextureForFixture("kalimba.jpg"));
298 
299  // Use a source rect that is partially outside the bounds of the image.
300  auto source_rect = DlRect::MakeXYWH(
301  image->GetSize().width * 0.25f, image->GetSize().height * 0.4f,
302  image->GetSize().width, image->GetSize().height);
303 
304  auto dest_rect = DlRect::MakeXYWH(100, 100, 600, 600);
305 
306  DlPaint paint;
307  paint.setColor(DlColor::kMidGrey());
308  builder.DrawRect(dest_rect, paint);
309 
310  builder.DrawImageRect(image, source_rect, dest_rect,
311  DlImageSampling::kNearestNeighbor);
312  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
313 }
314 
315 TEST_P(AiksTest, CanRenderSimpleClips) {
316  DisplayListBuilder builder;
317  builder.Scale(GetContentScale().x, GetContentScale().y);
318  DlPaint paint;
319 
320  paint.setColor(DlColor::kWhite());
321  builder.DrawPaint(paint);
322 
323  auto draw = [&builder](const DlPaint& paint, Scalar x, Scalar y) {
324  builder.Save();
325  builder.Translate(x, y);
326  {
327  builder.Save();
328  builder.ClipRect(DlRect::MakeLTRB(50, 50, 150, 150));
329  builder.DrawPaint(paint);
330  builder.Restore();
331  }
332  {
333  builder.Save();
334  builder.ClipOval(DlRect::MakeLTRB(200, 50, 300, 150));
335  builder.DrawPaint(paint);
336  builder.Restore();
337  }
338  {
339  builder.Save();
340  builder.ClipRoundRect(
341  DlRoundRect::MakeRectXY(DlRect::MakeLTRB(50, 200, 150, 300), 20, 20));
342  builder.DrawPaint(paint);
343  builder.Restore();
344  }
345  {
346  builder.Save();
347  builder.ClipRoundRect(DlRoundRect::MakeRectXY(
348  DlRect::MakeLTRB(200, 230, 300, 270), 20, 20));
349  builder.DrawPaint(paint);
350  builder.Restore();
351  }
352  {
353  builder.Save();
354  builder.ClipRoundRect(DlRoundRect::MakeRectXY(
355  DlRect::MakeLTRB(230, 200, 270, 300), 20, 20));
356  builder.DrawPaint(paint);
357  builder.Restore();
358  }
359  builder.Restore();
360  };
361 
362  paint.setColor(DlColor::kBlue());
363  draw(paint, 0, 0);
364 
365  DlColor gradient_colors[7] = {
366  DlColor::RGBA(0x1f / 255.0, 0.0, 0x5c / 255.0, 1.0),
367  DlColor::RGBA(0x5b / 255.0, 0.0, 0x60 / 255.0, 1.0),
368  DlColor::RGBA(0x87 / 255.0, 0x01 / 255.0, 0x60 / 255.0, 1.0),
369  DlColor::RGBA(0xac / 255.0, 0x25 / 255.0, 0x53 / 255.0, 1.0),
370  DlColor::RGBA(0xe1 / 255.0, 0x6b / 255.0, 0x5c / 255.0, 1.0),
371  DlColor::RGBA(0xf3 / 255.0, 0x90 / 255.0, 0x60 / 255.0, 1.0),
372  DlColor::RGBA(0xff / 255.0, 0xb5 / 255.0, 0x6b / 250.0, 1.0),
373  };
374  Scalar stops[7] = {
375  0.0,
376  (1.0 / 6.0) * 1,
377  (1.0 / 6.0) * 2,
378  (1.0 / 6.0) * 3,
379  (1.0 / 6.0) * 4,
380  (1.0 / 6.0) * 5,
381  1.0,
382  };
383  auto texture = CreateTextureForFixture("airplane.jpg",
384  /*enable_mipmapping=*/true);
385  auto image = DlImageImpeller::Make(texture);
386 
387  paint.setColorSource(DlColorSource::MakeRadial(
388  DlPoint(500, 600), 75, 7, gradient_colors, stops, DlTileMode::kMirror));
389  draw(paint, 0, 300);
390 
391  paint.setColorSource(
392  DlColorSource::MakeImage(image, DlTileMode::kRepeat, DlTileMode::kRepeat,
393  DlImageSampling::kNearestNeighbor));
394  draw(paint, 300, 0);
395 
396  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
397 }
398 
399 TEST_P(AiksTest, CanSaveLayerStandalone) {
400  DisplayListBuilder builder;
401 
402  DlPaint red;
403  red.setColor(DlColor::kRed());
404 
405  DlPaint alpha;
406  alpha.setColor(DlColor::kRed().modulateOpacity(0.5));
407 
408  builder.SaveLayer(std::nullopt, &alpha);
409 
410  builder.DrawCircle(DlPoint(125, 125), 125, red);
411 
412  builder.Restore();
413 
414  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
415 }
416 
417 TEST_P(AiksTest, CanRenderDifferentShapesWithSameColorSource) {
418  DisplayListBuilder builder;
419  DlPaint paint;
420 
421  DlColor colors[2] = {
422  DlColor::RGBA(0.9568, 0.2627, 0.2118, 1.0),
423  DlColor::RGBA(0.1294, 0.5882, 0.9529, 1.0),
424  };
425  DlScalar stops[2] = {
426  0.0,
427  1.0,
428  };
429 
430  paint.setColorSource(DlColorSource::MakeLinear(
431  /*start_point=*/DlPoint(0, 0), //
432  /*end_point=*/DlPoint(100, 100), //
433  /*stop_count=*/2, //
434  /*colors=*/colors, //
435  /*stops=*/stops, //
436  /*tile_mode=*/DlTileMode::kRepeat //
437  ));
438 
439  builder.Save();
440  builder.Translate(100, 100);
441  builder.DrawRect(DlRect::MakeXYWH(0, 0, 200, 200), paint);
442  builder.Restore();
443 
444  builder.Save();
445  builder.Translate(100, 400);
446  builder.DrawCircle(DlPoint(100, 100), 100, paint);
447  builder.Restore();
448  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
449 }
450 
451 TEST_P(AiksTest, CanRenderRoundedRectWithNonUniformRadii) {
452  DisplayListBuilder builder;
453  DlPaint paint;
454  paint.setColor(DlColor::kRed());
455 
456  RoundingRadii radii = {
457  .top_left = DlSize(50, 25),
458  .top_right = DlSize(25, 50),
459  .bottom_left = DlSize(25, 50),
460  .bottom_right = DlSize(50, 25),
461  };
462  DlRoundRect rrect =
463  DlRoundRect::MakeRectRadii(DlRect::MakeXYWH(100, 100, 500, 500), radii);
464 
465  builder.DrawRoundRect(rrect, paint);
466 
467  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
468 }
469 
470 TEST_P(AiksTest, CanDrawPaint) {
471  auto medium_turquoise =
472  DlColor::RGBA(72.0f / 255.0f, 209.0f / 255.0f, 204.0f / 255.0f, 1.0f);
473 
474  DisplayListBuilder builder;
475  builder.Scale(0.2, 0.2);
476  builder.DrawPaint(DlPaint().setColor(medium_turquoise));
477  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
478 }
479 
480 TEST_P(AiksTest, CanDrawPaintMultipleTimes) {
481  auto medium_turquoise =
482  DlColor::RGBA(72.0f / 255.0f, 209.0f / 255.0f, 204.0f / 255.0f, 1.0f);
483  auto orange_red =
484  DlColor::RGBA(255.0f / 255.0f, 69.0f / 255.0f, 0.0f / 255.0f, 1.0f);
485 
486  DisplayListBuilder builder;
487  builder.Scale(0.2, 0.2);
488  builder.DrawPaint(DlPaint().setColor(medium_turquoise));
489  builder.DrawPaint(DlPaint().setColor(orange_red.modulateOpacity(0.5f)));
490  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
491 }
492 
493 TEST_P(AiksTest, StrokedRectsRenderCorrectly) {
494  DisplayListBuilder builder;
495  builder.Scale(GetContentScale().x, GetContentScale().y);
496 
497  DlPaint paint;
498  paint.setColor(DlColor::kPurple());
499  paint.setDrawStyle(DlDrawStyle::kStroke);
500  paint.setStrokeWidth(20.0f);
501 
502  DlPaint thin_paint = paint;
503  thin_paint.setColor(DlColor::kYellow());
504  thin_paint.setStrokeWidth(0.0f);
505 
506  DlRect rect = DlRect::MakeLTRB(10, 10, 90, 90);
507  DlRect thin_tall_rect = DlRect::MakeLTRB(120, 10, 120, 90);
508  DlRect thin_wide_rect = DlRect::MakeLTRB(10, 120, 90, 120);
509  DlRect empty_rect = DlRect::MakeLTRB(120, 120, 120, 120);
510 
511  // We draw the following sets of rectangles:
512  //
513  // A E X
514  // X
515  // B F X
516  // X
517  // C D G H X
518  //
519  // Purple A,B,C,D are all drawn with stroke width 20 (non-overflowing).
520  // Each of those sets has 4 rectangles of dimension 80x80, 80x0, 0x80,
521  // and 0,0 to demonstrate the basic behavior and also the behavior of
522  // empty dimensions.
523  //
524  // Blue E,F,G,H are the same 80x80 rectangles, but with an overflowing
525  // stroke width of 120 to show the behavior with degenerately large
526  // stroke widths.
527  //
528  // A,E are drawn with Bevel joins.
529  // B,F are drawn with Round joins.
530  // C,G are drawn with Miter joins and a large enough miter limit.
531  // D,H are drawn with Miter joins and a too small miter limit (== Bevel).
532  //
533  // All orange X rectangles are drawn with round joins and increasing stroke
534  // widths to demonstrate fidelity of the rounding code at various arc sizes.
535  // These X rectangles also help test that the variable sizing estimates in
536  // the round join code are accurate.
537 
538  // rects (A)
539  paint.setStrokeJoin(DlStrokeJoin::kBevel);
540  builder.DrawRect(rect.Shift({100, 100}), paint);
541  builder.DrawRect(rect.Shift({100, 100}), thin_paint);
542  builder.DrawRect(thin_tall_rect.Shift({100, 100}), paint);
543  builder.DrawRect(thin_tall_rect.Shift({100, 100}), thin_paint);
544  builder.DrawRect(thin_wide_rect.Shift({100, 100}), paint);
545  builder.DrawRect(thin_wide_rect.Shift({100, 100}), thin_paint);
546  builder.DrawRect(empty_rect.Shift({100, 100}), paint);
547  builder.DrawRect(empty_rect.Shift({100, 100}), thin_paint);
548 
549  // rects (B)
550  paint.setStrokeJoin(DlStrokeJoin::kRound);
551  builder.DrawRect(rect.Shift({100, 300}), paint);
552  builder.DrawRect(rect.Shift({100, 300}), thin_paint);
553  builder.DrawRect(thin_tall_rect.Shift({100, 300}), paint);
554  builder.DrawRect(thin_tall_rect.Shift({100, 300}), thin_paint);
555  builder.DrawRect(thin_wide_rect.Shift({100, 300}), paint);
556  builder.DrawRect(thin_wide_rect.Shift({100, 300}), thin_paint);
557  builder.DrawRect(empty_rect.Shift({100, 300}), paint);
558  builder.DrawRect(empty_rect.Shift({100, 300}), thin_paint);
559 
560  // rects (C)
561  paint.setStrokeJoin(DlStrokeJoin::kMiter);
562  paint.setStrokeMiter(kSqrt2 + flutter::kEhCloseEnough);
563  builder.DrawRect(rect.Shift({100, 500}), paint);
564  builder.DrawRect(rect.Shift({100, 500}), thin_paint);
565  builder.DrawRect(thin_tall_rect.Shift({100, 500}), paint);
566  builder.DrawRect(thin_tall_rect.Shift({100, 500}), thin_paint);
567  builder.DrawRect(thin_wide_rect.Shift({100, 500}), paint);
568  builder.DrawRect(thin_wide_rect.Shift({100, 500}), thin_paint);
569  builder.DrawRect(empty_rect.Shift({100, 500}), paint);
570  builder.DrawRect(empty_rect.Shift({100, 500}), thin_paint);
571 
572  // rects (D)
573  paint.setStrokeJoin(DlStrokeJoin::kMiter);
574  paint.setStrokeMiter(kSqrt2 - flutter::kEhCloseEnough);
575  builder.DrawRect(rect.Shift({300, 500}), paint);
576  builder.DrawRect(rect.Shift({300, 500}), thin_paint);
577  builder.DrawRect(thin_tall_rect.Shift({300, 500}), paint);
578  builder.DrawRect(thin_tall_rect.Shift({300, 500}), thin_paint);
579  builder.DrawRect(thin_wide_rect.Shift({300, 500}), paint);
580  builder.DrawRect(thin_wide_rect.Shift({300, 500}), thin_paint);
581  builder.DrawRect(empty_rect.Shift({300, 500}), paint);
582  builder.DrawRect(empty_rect.Shift({300, 500}), thin_paint);
583 
584  paint.setStrokeWidth(120.0f);
585  paint.setColor(DlColor::kBlue());
586  rect = rect.Expand(-20);
587 
588  // rect (E)
589  paint.setStrokeJoin(DlStrokeJoin::kBevel);
590  builder.DrawRect(rect.Shift({500, 100}), paint);
591  builder.DrawRect(rect.Shift({500, 100}), thin_paint);
592 
593  // rect (F)
594  paint.setStrokeJoin(DlStrokeJoin::kRound);
595  builder.DrawRect(rect.Shift({500, 300}), paint);
596  builder.DrawRect(rect.Shift({500, 300}), thin_paint);
597 
598  // rect (G)
599  paint.setStrokeJoin(DlStrokeJoin::kMiter);
600  paint.setStrokeMiter(kSqrt2 + flutter::kEhCloseEnough);
601  builder.DrawRect(rect.Shift({500, 500}), paint);
602  builder.DrawRect(rect.Shift({500, 500}), thin_paint);
603 
604  // rect (H)
605  paint.setStrokeJoin(DlStrokeJoin::kMiter);
606  paint.setStrokeMiter(kSqrt2 - flutter::kEhCloseEnough);
607  builder.DrawRect(rect.Shift({700, 500}), paint);
608  builder.DrawRect(rect.Shift({700, 500}), thin_paint);
609 
610  DlPaint round_mock_paint;
611  round_mock_paint.setColor(DlColor::kGreen());
612  round_mock_paint.setDrawStyle(DlDrawStyle::kFill);
613 
614  // array of rects (X)
615  Scalar x = 900;
616  Scalar y = 50;
617  for (int i = 0; i < 15; i++) {
618  paint.setStrokeWidth(i);
619  paint.setColor(DlColor::kOrange());
620  paint.setStrokeJoin(DlStrokeJoin::kRound);
621  builder.DrawRect(DlRect::MakeXYWH(x, y, 30, 30), paint);
622  y += 32 + i;
623  }
624 
625  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
626 }
627 
628 TEST_P(AiksTest, FilledCirclesRenderCorrectly) {
629  DisplayListBuilder builder;
630  builder.Scale(GetContentScale().x, GetContentScale().y);
631  DlPaint paint;
632  const int color_count = 3;
633  DlColor colors[color_count] = {
634  DlColor::kBlue(),
635  DlColor::kGreen(),
636  DlColor::RGBA(220.0f / 255.0f, 20.0f / 255.0f, 60.0f / 255.0f, 1.0f),
637  };
638 
639  paint.setColor(DlColor::kWhite());
640  builder.DrawPaint(paint);
641 
642  int c_index = 0;
643  int radius = 600;
644  while (radius > 0) {
645  paint.setColor(colors[(c_index++) % color_count]);
646  builder.DrawCircle(DlPoint(10, 10), radius, paint);
647  if (radius > 30) {
648  radius -= 10;
649  } else {
650  radius -= 2;
651  }
652  }
653 
654  DlColor gradient_colors[7] = {
655  DlColor::RGBA(0x1f / 255.0, 0.0, 0x5c / 255.0, 1.0),
656  DlColor::RGBA(0x5b / 255.0, 0.0, 0x60 / 255.0, 1.0),
657  DlColor::RGBA(0x87 / 255.0, 0x01 / 255.0, 0x60 / 255.0, 1.0),
658  DlColor::RGBA(0xac / 255.0, 0x25 / 255.0, 0x53 / 255.0, 1.0),
659  DlColor::RGBA(0xe1 / 255.0, 0x6b / 255.0, 0x5c / 255.0, 1.0),
660  DlColor::RGBA(0xf3 / 255.0, 0x90 / 255.0, 0x60 / 255.0, 1.0),
661  DlColor::RGBA(0xff / 255.0, 0xb5 / 255.0, 0x6b / 250.0, 1.0),
662  };
663  DlScalar stops[7] = {
664  0.0,
665  (1.0 / 6.0) * 1,
666  (1.0 / 6.0) * 2,
667  (1.0 / 6.0) * 3,
668  (1.0 / 6.0) * 4,
669  (1.0 / 6.0) * 5,
670  1.0,
671  };
672  auto texture = CreateTextureForFixture("airplane.jpg",
673  /*enable_mipmapping=*/true);
674  auto image = DlImageImpeller::Make(texture);
675 
676  paint.setColorSource(DlColorSource::MakeRadial(
677  DlPoint(500, 600), 75, 7, gradient_colors, stops, DlTileMode::kMirror));
678  builder.DrawCircle(DlPoint(500, 600), 100, paint);
679 
680  DlMatrix local_matrix = DlMatrix::MakeTranslation({700, 200});
681  paint.setColorSource(DlColorSource::MakeImage(
682  image, DlTileMode::kRepeat, DlTileMode::kRepeat,
683  DlImageSampling::kNearestNeighbor, &local_matrix));
684  builder.DrawCircle(DlPoint(800, 300), 100, paint);
685 
686  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
687 }
688 
689 TEST_P(AiksTest, StrokedCirclesRenderCorrectly) {
690  DisplayListBuilder builder;
691  builder.Scale(GetContentScale().x, GetContentScale().y);
692  DlPaint paint;
693  const int color_count = 3;
694  DlColor colors[color_count] = {
695  DlColor::kBlue(),
696  DlColor::kGreen(),
697  DlColor::RGBA(220.0f / 255.0f, 20.0f / 255.0f, 60.0f / 255.0f, 1.0f),
698  };
699 
700  paint.setColor(DlColor::kWhite());
701  builder.DrawPaint(paint);
702 
703  int c_index = 0;
704 
705  auto draw = [&paint, &colors, &c_index](DlCanvas& canvas, DlPoint center,
706  Scalar r, Scalar dr, int n) {
707  for (int i = 0; i < n; i++) {
708  paint.setColor(colors[(c_index++) % color_count]);
709  canvas.DrawCircle(center, r, paint);
710  r += dr;
711  }
712  };
713 
714  paint.setDrawStyle(DlDrawStyle::kStroke);
715  paint.setStrokeWidth(1);
716  draw(builder, DlPoint(10, 10), 2, 2, 14); // r = [2, 28], covers [1,29]
717  paint.setStrokeWidth(5);
718  draw(builder, DlPoint(10, 10), 35, 10, 56); // r = [35, 585], covers [30,590]
719 
720  DlColor gradient_colors[7] = {
721  DlColor::RGBA(0x1f / 255.0, 0.0, 0x5c / 255.0, 1.0),
722  DlColor::RGBA(0x5b / 255.0, 0.0, 0x60 / 255.0, 1.0),
723  DlColor::RGBA(0x87 / 255.0, 0x01 / 255.0, 0x60 / 255.0, 1.0),
724  DlColor::RGBA(0xac / 255.0, 0x25 / 255.0, 0x53 / 255.0, 1.0),
725  DlColor::RGBA(0xe1 / 255.0, 0x6b / 255.0, 0x5c / 255.0, 1.0),
726  DlColor::RGBA(0xf3 / 255.0, 0x90 / 255.0, 0x60 / 255.0, 1.0),
727  DlColor::RGBA(0xff / 255.0, 0xb5 / 255.0, 0x6b / 250.0, 1.0),
728  };
729  DlScalar stops[7] = {
730  0.0,
731  (1.0 / 6.0) * 1,
732  (1.0 / 6.0) * 2,
733  (1.0 / 6.0) * 3,
734  (1.0 / 6.0) * 4,
735  (1.0 / 6.0) * 5,
736  1.0,
737  };
738  auto texture = CreateTextureForFixture("airplane.jpg",
739  /*enable_mipmapping=*/true);
740  auto image = DlImageImpeller::Make(texture);
741 
742  paint.setColorSource(DlColorSource::MakeRadial(
743  DlPoint(500, 600), 75, 7, gradient_colors, stops, DlTileMode::kMirror));
744  draw(builder, DlPoint(500, 600), 5, 10, 10);
745 
746  DlMatrix local_matrix = DlMatrix::MakeTranslation({700, 200});
747  paint.setColorSource(DlColorSource::MakeImage(
748  image, DlTileMode::kRepeat, DlTileMode::kRepeat,
749  DlImageSampling::kNearestNeighbor, &local_matrix));
750  draw(builder, DlPoint(800, 300), 5, 10, 10);
751 
752  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
753 }
754 
755 TEST_P(AiksTest, FilledEllipsesRenderCorrectly) {
756  DisplayListBuilder builder;
757  builder.Scale(GetContentScale().x, GetContentScale().y);
758  DlPaint paint;
759  const int color_count = 3;
760  DlColor colors[color_count] = {
761  DlColor::kBlue(),
762  DlColor::kGreen(),
763  DlColor::RGBA(220.0f / 255.0f, 20.0f / 255.0f, 60.0f / 255.0f, 1.0f),
764  };
765 
766  paint.setColor(DlColor::kWhite());
767  builder.DrawPaint(paint);
768 
769  int c_index = 0;
770  int long_radius = 600;
771  int short_radius = 600;
772  while (long_radius > 0 && short_radius > 0) {
773  paint.setColor(colors[(c_index++) % color_count]);
774  builder.DrawOval(DlRect::MakeXYWH(10 - long_radius, 10 - short_radius,
775  long_radius * 2, short_radius * 2),
776  paint);
777  builder.DrawOval(DlRect::MakeXYWH(1000 - short_radius, 750 - long_radius,
778  short_radius * 2, long_radius * 2),
779  paint);
780  if (short_radius > 30) {
781  short_radius -= 10;
782  long_radius -= 5;
783  } else {
784  short_radius -= 2;
785  long_radius -= 1;
786  }
787  }
788 
789  DlColor gradient_colors[7] = {
790  DlColor::RGBA(0x1f / 255.0, 0.0, 0x5c / 255.0, 1.0),
791  DlColor::RGBA(0x5b / 255.0, 0.0, 0x60 / 255.0, 1.0),
792  DlColor::RGBA(0x87 / 255.0, 0x01 / 255.0, 0x60 / 255.0, 1.0),
793  DlColor::RGBA(0xac / 255.0, 0x25 / 255.0, 0x53 / 255.0, 1.0),
794  DlColor::RGBA(0xe1 / 255.0, 0x6b / 255.0, 0x5c / 255.0, 1.0),
795  DlColor::RGBA(0xf3 / 255.0, 0x90 / 255.0, 0x60 / 255.0, 1.0),
796  DlColor::RGBA(0xff / 255.0, 0xb5 / 255.0, 0x6b / 250.0, 1.0),
797  };
798  DlScalar stops[7] = {
799  0.0,
800  (1.0 / 6.0) * 1,
801  (1.0 / 6.0) * 2,
802  (1.0 / 6.0) * 3,
803  (1.0 / 6.0) * 4,
804  (1.0 / 6.0) * 5,
805  1.0,
806  };
807  auto texture = CreateTextureForFixture("airplane.jpg",
808  /*enable_mipmapping=*/true);
809  auto image = DlImageImpeller::Make(texture);
810 
811  paint.setColor(DlColor::kWhite().modulateOpacity(0.5));
812 
813  paint.setColorSource(DlColorSource::MakeRadial(
814  DlPoint(300, 650), 75, 7, gradient_colors, stops, DlTileMode::kMirror));
815  builder.DrawOval(DlRect::MakeXYWH(200, 625, 200, 50), paint);
816  builder.DrawOval(DlRect::MakeXYWH(275, 550, 50, 200), paint);
817 
818  DlMatrix local_matrix = DlMatrix::MakeTranslation({610, 15});
819  paint.setColorSource(DlColorSource::MakeImage(
820  image, DlTileMode::kRepeat, DlTileMode::kRepeat,
821  DlImageSampling::kNearestNeighbor, &local_matrix));
822  builder.DrawOval(DlRect::MakeXYWH(610, 90, 200, 50), paint);
823  builder.DrawOval(DlRect::MakeXYWH(685, 15, 50, 200), paint);
824 
825  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
826 }
827 
828 namespace {
829 struct ArcFarmOptions {
830  bool use_center = false;
831  bool full_circles = false;
832  bool sweeps_over_360 = false;
834 };
835 
836 void RenderArcFarm(DisplayListBuilder& builder,
837  const DlPaint& paint,
838  const ArcFarmOptions& opts) {
839  builder.Save();
840  builder.Translate(50, 50);
841  const Rect arc_bounds = Rect::MakeLTRB(0, 0, 42, 42 * opts.vertical_scale);
842  const int sweep_limit = opts.sweeps_over_360 ? 420 : 360;
843  for (int start = 0; start <= 360; start += 30) {
844  builder.Save();
845  for (int sweep = 30; sweep <= sweep_limit; sweep += 30) {
846  builder.DrawArc(arc_bounds, start, opts.full_circles ? 360 : sweep,
847  opts.use_center, paint);
848  builder.Translate(50, 0);
849  }
850  builder.Restore();
851  builder.Translate(0, 50);
852  }
853  builder.Restore();
854 }
855 } // namespace
856 
857 TEST_P(AiksTest, FilledArcsRenderCorrectly) {
858  DisplayListBuilder builder;
859  builder.Scale(GetContentScale().x, GetContentScale().y);
860  builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc);
861 
862  DlPaint paint;
863  paint.setColor(DlColor::kBlue());
864 
865  RenderArcFarm(builder, paint,
866  {
867  .use_center = false,
868  .full_circles = false,
869  });
870 
871  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
872 }
873 
874 TEST_P(AiksTest, FilledArcsRenderCorrectlyWithCenter) {
875  DisplayListBuilder builder;
876  builder.Scale(GetContentScale().x, GetContentScale().y);
877  builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc);
878 
879  DlPaint paint;
880  paint.setColor(DlColor::kBlue());
881 
882  RenderArcFarm(builder, paint,
883  {
884  .use_center = true,
885  .full_circles = false,
886  });
887 
888  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
889 }
890 
891 TEST_P(AiksTest, NonSquareFilledArcsRenderCorrectly) {
892  DisplayListBuilder builder;
893  builder.Scale(GetContentScale().x, GetContentScale().y);
894  builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc);
895 
896  DlPaint paint;
897  paint.setColor(DlColor::kBlue());
898 
899  RenderArcFarm(builder, paint,
900  {
901  .use_center = false,
902  .full_circles = false,
903  .vertical_scale = 0.8f,
904  });
905 
906  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
907 }
908 
909 TEST_P(AiksTest, NonSquareFilledArcsRenderCorrectlyWithCenter) {
910  DisplayListBuilder builder;
911  builder.Scale(GetContentScale().x, GetContentScale().y);
912  builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc);
913 
914  DlPaint paint;
915  paint.setColor(DlColor::kBlue());
916 
917  RenderArcFarm(builder, paint,
918  {
919  .use_center = true,
920  .full_circles = false,
921  .vertical_scale = 0.8f,
922  });
923 
924  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
925 }
926 
927 TEST_P(AiksTest, StrokedArcsRenderCorrectlyWithButtEnds) {
928  DisplayListBuilder builder;
929  builder.Scale(GetContentScale().x, GetContentScale().y);
930  builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc);
931 
932  DlPaint paint;
933  paint.setDrawStyle(DlDrawStyle::kStroke);
934  paint.setStrokeWidth(6.0f);
935  paint.setStrokeCap(DlStrokeCap::kButt);
936  paint.setColor(DlColor::kBlue());
937 
938  RenderArcFarm(builder, paint,
939  {
940  .use_center = false,
941  .full_circles = false,
942  });
943 
944  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
945 }
946 
947 TEST_P(AiksTest, StrokedArcsRenderCorrectlyWithSquareEnds) {
948  DisplayListBuilder builder;
949  builder.Scale(GetContentScale().x, GetContentScale().y);
950  builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc);
951 
952  DlPaint paint;
953  paint.setDrawStyle(DlDrawStyle::kStroke);
954  paint.setStrokeWidth(6.0f);
955  paint.setStrokeCap(DlStrokeCap::kSquare);
956  paint.setColor(DlColor::kBlue());
957 
958  RenderArcFarm(builder, paint,
959  {
960  .use_center = false,
961  .full_circles = false,
962  });
963 
964  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
965 }
966 
967 TEST_P(AiksTest, StrokedArcsRenderCorrectlyWithRoundEnds) {
968  DisplayListBuilder builder;
969  builder.Scale(GetContentScale().x, GetContentScale().y);
970  builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc);
971 
972  DlPaint paint;
973  paint.setDrawStyle(DlDrawStyle::kStroke);
974  paint.setStrokeWidth(6.0f);
975  paint.setStrokeCap(DlStrokeCap::kRound);
976  paint.setColor(DlColor::kBlue());
977 
978  RenderArcFarm(builder, paint,
979  {
980  .use_center = false,
981  .full_circles = false,
982  });
983 
984  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
985 }
986 
987 TEST_P(AiksTest, StrokedArcsRenderCorrectlyWithBevelJoinsAndCenter) {
988  DisplayListBuilder builder;
989  builder.Scale(GetContentScale().x, GetContentScale().y);
990  builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc);
991 
992  DlPaint paint;
993  paint.setDrawStyle(DlDrawStyle::kStroke);
994  paint.setStrokeWidth(6.0f);
995  paint.setStrokeJoin(DlStrokeJoin::kBevel);
996  paint.setColor(DlColor::kBlue());
997 
998  RenderArcFarm(builder, paint,
999  {
1000  .use_center = true,
1001  .full_circles = false,
1002  .sweeps_over_360 = true,
1003  });
1004 
1005  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1006 }
1007 
1008 TEST_P(AiksTest, StrokedArcsRenderCorrectlyWithMiterJoinsAndCenter) {
1009  DisplayListBuilder builder;
1010  builder.Scale(GetContentScale().x, GetContentScale().y);
1011  builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc);
1012 
1013  DlPaint paint;
1014  paint.setDrawStyle(DlDrawStyle::kStroke);
1015  paint.setStrokeWidth(6.0f);
1016  paint.setStrokeJoin(DlStrokeJoin::kMiter);
1017  // Default miter of 4.0 does a miter on all of the centers, but
1018  // using 3.0 will show some bevels on the widest interior angles...
1019  paint.setStrokeMiter(3.0f);
1020  paint.setColor(DlColor::kBlue());
1021 
1022  RenderArcFarm(builder, paint,
1023  {
1024  .use_center = true,
1025  .full_circles = false,
1026  .sweeps_over_360 = true,
1027  });
1028 
1029  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1030 }
1031 
1032 TEST_P(AiksTest, StrokedArcsRenderCorrectlyWithRoundJoinsAndCenter) {
1033  DisplayListBuilder builder;
1034  builder.Scale(GetContentScale().x, GetContentScale().y);
1035  builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc);
1036 
1037  DlPaint paint;
1038  paint.setDrawStyle(DlDrawStyle::kStroke);
1039  paint.setStrokeWidth(6.0f);
1040  paint.setStrokeJoin(DlStrokeJoin::kRound);
1041  paint.setColor(DlColor::kBlue());
1042 
1043  RenderArcFarm(builder, paint,
1044  {
1045  .use_center = true,
1046  .full_circles = false,
1047  .sweeps_over_360 = true,
1048  });
1049 
1050  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1051 }
1052 
1053 TEST_P(AiksTest, StrokedArcsRenderCorrectlyWithSquareAndButtEnds) {
1054  DisplayListBuilder builder;
1055  builder.Scale(GetContentScale().x, GetContentScale().y);
1056  builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc);
1057 
1058  DlPaint paint;
1059  paint.setDrawStyle(DlDrawStyle::kStroke);
1060  paint.setStrokeWidth(8.0f);
1061  paint.setStrokeCap(DlStrokeCap::kSquare);
1062  paint.setColor(DlColor::kRed());
1063 
1064  RenderArcFarm(builder, paint,
1065  {
1066  .use_center = false,
1067  .full_circles = false,
1068  });
1069 
1070  paint.setStrokeCap(DlStrokeCap::kButt);
1071  paint.setColor(DlColor::kBlue());
1072 
1073  RenderArcFarm(builder, paint,
1074  {
1075  .use_center = false,
1076  .full_circles = false,
1077  });
1078 
1079  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1080 }
1081 
1082 TEST_P(AiksTest, StrokedArcsRenderCorrectlyWithSquareAndButtAndRoundEnds) {
1083  DisplayListBuilder builder;
1084  builder.Scale(GetContentScale().x, GetContentScale().y);
1085  builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc);
1086 
1087  DlPaint paint;
1088  paint.setDrawStyle(DlDrawStyle::kStroke);
1089  paint.setStrokeWidth(8.0f);
1090  paint.setStrokeCap(DlStrokeCap::kSquare);
1091  paint.setColor(DlColor::kRed());
1092 
1093  RenderArcFarm(builder, paint,
1094  {
1095  .use_center = false,
1096  .full_circles = false,
1097  });
1098 
1099  paint.setStrokeCap(DlStrokeCap::kRound);
1100  paint.setColor(DlColor::kGreen());
1101 
1102  RenderArcFarm(builder, paint,
1103  {
1104  .use_center = false,
1105  .full_circles = false,
1106  });
1107 
1108  paint.setStrokeCap(DlStrokeCap::kButt);
1109  paint.setColor(DlColor::kBlue());
1110 
1111  RenderArcFarm(builder, paint,
1112  {
1113  .use_center = false,
1114  .full_circles = false,
1115  });
1116 
1117  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1118 }
1119 
1120 TEST_P(AiksTest, StrokedArcsCoverFullArcWithButtEnds) {
1121  // This test compares the rendering of a full circle arc against a partial
1122  // arc by drawing a one over the other in high contrast. If the partial
1123  // arc misses any pixels that were drawn by the full arc, there will be
1124  // some "pixel dirt" around the missing "erased" parts of the arcs. This
1125  // case arises while rendering a CircularProgressIndicator with a background
1126  // color where we want the rendering of the background full arc to hit the
1127  // same pixels around the edges as the partial arc that covers it.
1128  //
1129  // In this case we draw a full blue circle and then draw a partial arc
1130  // over it in the background color (white).
1131 
1132  DisplayListBuilder builder;
1133  builder.Scale(GetContentScale().x, GetContentScale().y);
1134  builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc);
1135 
1136  DlPaint paint;
1137  paint.setDrawStyle(DlDrawStyle::kStroke);
1138  paint.setStrokeWidth(6.0f);
1139  paint.setStrokeCap(DlStrokeCap::kButt);
1140  paint.setColor(DlColor::kBlue());
1141 
1142  // First draw full circles in blue to establish the pixels to be erased
1143  RenderArcFarm(builder, paint,
1144  {
1145  .use_center = false,
1146  .full_circles = true,
1147  });
1148 
1149  paint.setColor(DlColor::kWhite());
1150 
1151  // Then draw partial arcs in white over the circles to "erase" them
1152  RenderArcFarm(builder, paint,
1153  {
1154  .use_center = false,
1155  .full_circles = false,
1156  });
1157 
1158  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1159 }
1160 
1161 TEST_P(AiksTest, FilledRoundRectsRenderCorrectly) {
1162  DisplayListBuilder builder;
1163  builder.Scale(GetContentScale().x, GetContentScale().y);
1164  DlPaint paint;
1165  const int color_count = 3;
1166  DlColor colors[color_count] = {
1167  DlColor::kBlue(),
1168  DlColor::kGreen(),
1169  DlColor::RGBA(220.0f / 255.0f, 20.0f / 255.0f, 60.0f / 255.0f, 1.0f),
1170  };
1171 
1172  paint.setColor(DlColor::kWhite());
1173  builder.DrawPaint(paint);
1174 
1175  int c_index = 0;
1176  for (int i = 0; i < 4; i++) {
1177  for (int j = 0; j < 4; j++) {
1178  paint.setColor(colors[(c_index++) % color_count]);
1179  builder.DrawRoundRect(
1180  DlRoundRect::MakeRectXY(
1181  DlRect::MakeXYWH(i * 100 + 10, j * 100 + 20, 80, 80), //
1182  i * 5 + 10, j * 5 + 10),
1183  paint);
1184  }
1185  }
1186  paint.setColor(colors[(c_index++) % color_count]);
1187  builder.DrawRoundRect(
1188  DlRoundRect::MakeRectXY(DlRect::MakeXYWH(10, 420, 380, 80), 40, 40),
1189  paint);
1190  paint.setColor(colors[(c_index++) % color_count]);
1191  builder.DrawRoundRect(
1192  DlRoundRect::MakeRectXY(DlRect::MakeXYWH(410, 20, 80, 380), 40, 40),
1193  paint);
1194 
1195  DlColor gradient_colors[7] = {
1196  DlColor::RGBA(0x1f / 255.0, 0.0, 0x5c / 255.0, 1.0),
1197  DlColor::RGBA(0x5b / 255.0, 0.0, 0x60 / 255.0, 1.0),
1198  DlColor::RGBA(0x87 / 255.0, 0x01 / 255.0, 0x60 / 255.0, 1.0),
1199  DlColor::RGBA(0xac / 255.0, 0x25 / 255.0, 0x53 / 255.0, 1.0),
1200  DlColor::RGBA(0xe1 / 255.0, 0x6b / 255.0, 0x5c / 255.0, 1.0),
1201  DlColor::RGBA(0xf3 / 255.0, 0x90 / 255.0, 0x60 / 255.0, 1.0),
1202  DlColor::RGBA(0xff / 255.0, 0xb5 / 255.0, 0x6b / 250.0, 1.0),
1203  };
1204  DlScalar stops[7] = {
1205  0.0,
1206  (1.0 / 6.0) * 1,
1207  (1.0 / 6.0) * 2,
1208  (1.0 / 6.0) * 3,
1209  (1.0 / 6.0) * 4,
1210  (1.0 / 6.0) * 5,
1211  1.0,
1212  };
1213  auto texture = CreateTextureForFixture("airplane.jpg",
1214  /*enable_mipmapping=*/true);
1215  auto image = DlImageImpeller::Make(texture);
1216 
1217  paint.setColor(DlColor::kWhite().modulateOpacity(0.1));
1218  paint.setColorSource(DlColorSource::MakeRadial(
1219  DlPoint(550, 550), 75, 7, gradient_colors, stops, DlTileMode::kMirror));
1220  for (int i = 1; i <= 10; i++) {
1221  int j = 11 - i;
1222  builder.DrawRoundRect(
1223  DlRoundRect::MakeRectXY(DlRect::MakeLTRB(550 - i * 20, 550 - j * 20, //
1224  550 + i * 20, 550 + j * 20),
1225  i * 10, j * 10),
1226  paint);
1227  }
1228 
1229  paint.setColor(DlColor::kWhite().modulateOpacity(0.5));
1230  paint.setColorSource(DlColorSource::MakeRadial(
1231  DlPoint(200, 650), 75, 7, gradient_colors, stops, DlTileMode::kMirror));
1232  paint.setColor(DlColor::kWhite().modulateOpacity(0.5));
1233  builder.DrawRoundRect(
1234  DlRoundRect::MakeRectXY(DlRect::MakeLTRB(100, 610, 300, 690), 40, 40),
1235  paint);
1236  builder.DrawRoundRect(
1237  DlRoundRect::MakeRectXY(DlRect::MakeLTRB(160, 550, 240, 750), 40, 40),
1238  paint);
1239 
1240  paint.setColor(DlColor::kWhite().modulateOpacity(0.1));
1241  DlMatrix local_matrix = DlMatrix::MakeTranslation({520, 20});
1242  paint.setColorSource(DlColorSource::MakeImage(
1243  image, DlTileMode::kRepeat, DlTileMode::kRepeat,
1244  DlImageSampling::kNearestNeighbor, &local_matrix));
1245  for (int i = 1; i <= 10; i++) {
1246  int j = 11 - i;
1247  builder.DrawRoundRect(
1248  DlRoundRect::MakeRectXY(DlRect::MakeLTRB(720 - i * 20, 220 - j * 20, //
1249  720 + i * 20, 220 + j * 20),
1250  i * 10, j * 10),
1251  paint);
1252  }
1253 
1254  paint.setColor(DlColor::kWhite().modulateOpacity(0.5));
1255  local_matrix = DlMatrix::MakeTranslation({800, 300});
1256  paint.setColorSource(DlColorSource::MakeImage(
1257  image, DlTileMode::kRepeat, DlTileMode::kRepeat,
1258  DlImageSampling::kNearestNeighbor, &local_matrix));
1259  builder.DrawRoundRect(
1260  DlRoundRect::MakeRectXY(DlRect::MakeLTRB(800, 410, 1000, 490), 40, 40),
1261  paint);
1262  builder.DrawRoundRect(
1263  DlRoundRect::MakeRectXY(DlRect::MakeLTRB(860, 350, 940, 550), 40, 40),
1264  paint);
1265 
1266  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1267 }
1268 
1269 TEST_P(AiksTest, SolidColorCirclesOvalsRRectsMaskBlurCorrectly) {
1270  DisplayListBuilder builder;
1271  builder.Scale(GetContentScale().x, GetContentScale().y);
1272  DlPaint paint;
1273  paint.setMaskFilter(DlBlurMaskFilter::Make(DlBlurStyle::kNormal, 1.0f));
1274 
1275  builder.DrawPaint(DlPaint().setColor(DlColor::kWhite()));
1276 
1277  paint.setColor(
1278  DlColor::RGBA(220.0f / 255.0f, 20.0f / 255.0f, 60.0f / 255.0f, 1.0f));
1279  Scalar y = 100.0f;
1280  for (int i = 0; i < 5; i++) {
1281  Scalar x = (i + 1) * 100;
1282  Scalar radius = x / 10.0f;
1283  builder.DrawRect(DlRect::MakeXYWH(x + 25 - radius / 2, y + radius / 2, //
1284  radius, 60.0f - radius),
1285  paint);
1286  }
1287 
1288  paint.setColor(DlColor::kBlue());
1289  y += 100.0f;
1290  for (int i = 0; i < 5; i++) {
1291  Scalar x = (i + 1) * 100;
1292  Scalar radius = x / 10.0f;
1293  builder.DrawCircle(DlPoint(x + 25, y + 25), radius, paint);
1294  }
1295 
1296  paint.setColor(DlColor::kGreen());
1297  y += 100.0f;
1298  for (int i = 0; i < 5; i++) {
1299  Scalar x = (i + 1) * 100;
1300  Scalar radius = x / 10.0f;
1301  builder.DrawOval(DlRect::MakeXYWH(x + 25 - radius / 2, y + radius / 2, //
1302  radius, 60.0f - radius),
1303  paint);
1304  }
1305 
1306  paint.setColor(
1307  DlColor::RGBA(128.0f / 255.0f, 0.0f / 255.0f, 128.0f / 255.0f, 1.0f));
1308  y += 100.0f;
1309  for (int i = 0; i < 5; i++) {
1310  Scalar x = (i + 1) * 100;
1311  Scalar radius = x / 20.0f;
1312  builder.DrawRoundRect(
1313  DlRoundRect::MakeRectXY(DlRect::MakeXYWH(x, y, 60.0f, 60.0f), //
1314  radius, radius),
1315  paint);
1316  }
1317 
1318  paint.setColor(
1319  DlColor::RGBA(255.0f / 255.0f, 165.0f / 255.0f, 0.0f / 255.0f, 1.0f));
1320  y += 100.0f;
1321  for (int i = 0; i < 5; i++) {
1322  Scalar x = (i + 1) * 100;
1323  Scalar radius = x / 20.0f;
1324  builder.DrawRoundRect(
1325  DlRoundRect::MakeRectXY(DlRect::MakeXYWH(x, y, 60.0f, 60.0f), //
1326  radius, 5.0f),
1327  paint);
1328  }
1329 
1330  auto dl = builder.Build();
1331  ASSERT_TRUE(OpenPlaygroundHere(dl));
1332 }
1333 
1334 TEST_P(AiksTest, CanRenderClippedBackdropFilter) {
1335  DisplayListBuilder builder;
1336 
1337  builder.Scale(GetContentScale().x, GetContentScale().y);
1338 
1339  // Draw something interesting in the background.
1340  std::vector<DlColor> colors = {DlColor::RGBA(0.9568, 0.2627, 0.2118, 1.0),
1341  DlColor::RGBA(0.1294, 0.5882, 0.9529, 1.0)};
1342  std::vector<Scalar> stops = {
1343  0.0,
1344  1.0,
1345  };
1346  DlPaint paint;
1347  paint.setColorSource(DlColorSource::MakeLinear(
1348  /*start_point=*/DlPoint(0, 0), //
1349  /*end_point=*/DlPoint(100, 100), //
1350  /*stop_count=*/2, //
1351  /*colors=*/colors.data(), //
1352  /*stops=*/stops.data(), //
1353  /*tile_mode=*/DlTileMode::kRepeat //
1354  ));
1355 
1356  builder.DrawPaint(paint);
1357 
1358  DlRect clip_rect = DlRect::MakeLTRB(50, 50, 400, 300);
1359  DlRoundRect clip_rrect = DlRoundRect::MakeRectXY(clip_rect, 100, 100);
1360 
1361  // Draw a clipped SaveLayer, where the clip coverage and SaveLayer size are
1362  // the same.
1363  builder.ClipRoundRect(clip_rrect, DlClipOp::kIntersect);
1364 
1365  DlPaint save_paint;
1366  auto backdrop_filter = DlImageFilter::MakeColorFilter(
1367  DlColorFilter::MakeBlend(DlColor::kRed(), DlBlendMode::kExclusion));
1368  builder.SaveLayer(clip_rect, &save_paint, backdrop_filter.get());
1369 
1370  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1371 }
1372 
1373 TEST_P(AiksTest, CanDrawPerspectiveTransformWithClips) {
1374  // Avoiding `GetSecondsElapsed()` to reduce risk of golden flakiness.
1375  int time = 0;
1376  auto callback = [&]() -> sk_sp<DisplayList> {
1377  DisplayListBuilder builder;
1378 
1379  builder.Save();
1380  {
1381  builder.Translate(300, 300);
1382 
1383  // 1. Draw/restore a clip before drawing the image, which will get drawn
1384  // to the depth buffer behind the image.
1385  builder.Save();
1386  {
1387  DlPaint paint;
1388  paint.setColor(DlColor::kGreen());
1389  builder.DrawPaint(paint);
1390  builder.ClipRect(DlRect::MakeLTRB(-180, -180, 180, 180),
1391  DlClipOp::kDifference);
1392 
1393  paint.setColor(DlColor::kBlack());
1394  builder.DrawPaint(paint);
1395  }
1396  builder.Restore(); // Restore rectangle difference clip.
1397 
1398  builder.Save();
1399  {
1400  // 2. Draw an oval clip that applies to the image, which will get drawn
1401  // in front of the image on the depth buffer.
1402  builder.ClipOval(DlRect::MakeLTRB(-200, -200, 200, 200));
1403 
1404  Matrix result =
1405  Matrix(1.0, 0.0, 0.0, 0.0, //
1406  0.0, 1.0, 0.0, 0.0, //
1407  0.0, 0.0, 1.0, 0.003, //
1408  0.0, 0.0, 0.0, 1.0) *
1409  Matrix::MakeRotationY({Radians{-1.0f + (time++ / 60.0f)}});
1410 
1411  // 3. Draw the rotating image with a perspective transform.
1412  builder.Transform(result);
1413 
1414  auto image =
1415  DlImageImpeller::Make(CreateTextureForFixture("airplane.jpg"));
1416  auto position =
1417  -DlPoint(image->GetSize().width, image->GetSize().height) * 0.5;
1418  builder.DrawImage(image, position, {});
1419  }
1420  builder.Restore(); // Restore oval intersect clip.
1421 
1422  // 4. Draw a semi-translucent blue circle atop all previous draws.
1423  DlPaint paint;
1424  paint.setColor(DlColor::kBlue().modulateOpacity(0.4));
1425  builder.DrawCircle(DlPoint(), 230, paint);
1426  }
1427  builder.Restore(); // Restore translation.
1428 
1429  return builder.Build();
1430  };
1431  ASSERT_TRUE(OpenPlaygroundHere(callback));
1432 }
1433 
1434 TEST_P(AiksTest, ImageColorSourceEffectTransform) {
1435  // Compare with https://fiddle.skia.org/c/6cdc5aefb291fda3833b806ca347a885
1436 
1437  DisplayListBuilder builder;
1438  auto texture = DlImageImpeller::Make(CreateTextureForFixture("monkey.png"));
1439 
1440  DlPaint paint;
1441  paint.setColor(DlColor::kWhite());
1442  builder.DrawPaint(paint);
1443 
1444  // Translation
1445  {
1446  DlMatrix matrix = DlMatrix::MakeTranslation({50, 50});
1447  DlPaint paint;
1448  paint.setColorSource(DlColorSource::MakeImage(
1449  texture, DlTileMode::kRepeat, DlTileMode::kRepeat,
1450  DlImageSampling::kNearestNeighbor, &matrix));
1451 
1452  builder.DrawRect(DlRect::MakeLTRB(0, 0, 100, 100), paint);
1453  }
1454 
1455  // Rotation/skew
1456  {
1457  builder.Save();
1458  builder.Rotate(45);
1459  DlPaint paint;
1460 
1461  Matrix matrix(1, -1, 0, 0, //
1462  1, 1, 0, 0, //
1463  0, 0, 1, 0, //
1464  0, 0, 0, 1);
1465  paint.setColorSource(DlColorSource::MakeImage(
1466  texture, DlTileMode::kRepeat, DlTileMode::kRepeat,
1467  DlImageSampling::kNearestNeighbor, &matrix));
1468  builder.DrawRect(DlRect::MakeLTRB(100, 0, 200, 100), paint);
1469  builder.Restore();
1470  }
1471 
1472  // Scale
1473  {
1474  builder.Save();
1475  builder.Translate(100, 0);
1476  builder.Scale(100, 100);
1477  DlPaint paint;
1478 
1479  DlMatrix matrix = DlMatrix::MakeScale({0.005, 0.005, 1});
1480  paint.setColorSource(DlColorSource::MakeImage(
1481  texture, DlTileMode::kRepeat, DlTileMode::kRepeat,
1482  DlImageSampling::kNearestNeighbor, &matrix));
1483 
1484  builder.DrawRect(DlRect::MakeLTRB(0, 0, 1, 1), paint);
1485  builder.Restore();
1486  }
1487 
1488  // Perspective
1489  {
1490  builder.Save();
1491  builder.Translate(150, 150);
1492  DlPaint paint;
1493 
1494  DlMatrix matrix =
1495  DlMatrix::MakePerspective(Radians{0.5}, ISize{200, 200}, 0.05, 1);
1496  paint.setColorSource(DlColorSource::MakeImage(
1497  texture, DlTileMode::kRepeat, DlTileMode::kRepeat,
1498  DlImageSampling::kNearestNeighbor, &matrix));
1499 
1500  builder.DrawRect(DlRect::MakeLTRB(0, 0, 200, 200), paint);
1501  builder.Restore();
1502  }
1503 
1504  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1505 }
1506 
1507 TEST_P(AiksTest, SubpassWithClearColorOptimization) {
1508  DisplayListBuilder builder;
1509 
1510  // Use a non-srcOver blend mode to ensure that we don't detect this as an
1511  // opacity peephole optimization.
1512  DlPaint paint;
1513  paint.setColor(DlColor::kBlue().modulateOpacity(0.5));
1514  paint.setBlendMode(DlBlendMode::kSrc);
1515 
1516  DlRect bounds = DlRect::MakeLTRB(0, 0, 200, 200);
1517  builder.SaveLayer(bounds, &paint);
1518 
1519  paint.setColor(DlColor::kTransparent());
1520  paint.setBlendMode(DlBlendMode::kSrc);
1521  builder.DrawPaint(paint);
1522  builder.Restore();
1523 
1524  paint.setColor(DlColor::kBlue());
1525  paint.setBlendMode(DlBlendMode::kDstOver);
1526  builder.SaveLayer(std::nullopt, &paint);
1527  builder.Restore();
1528 
1529  // This playground should appear blank on CI since we are only drawing
1530  // transparent black. If the clear color optimization is broken, the texture
1531  // will be filled with NaNs and may produce a magenta texture on macOS or iOS.
1532  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1533 }
1534 
1535 // Render a white circle at the top left corner of the screen.
1536 TEST_P(AiksTest, MatrixImageFilterDoesntCullWhenTranslatedFromOffscreen) {
1537  DisplayListBuilder builder;
1538  builder.Scale(GetContentScale().x, GetContentScale().y);
1539  builder.Translate(100, 100);
1540  // Draw a circle in a SaveLayer at -300, but move it back on-screen with a
1541  // +300 translation applied by a SaveLayer image filter.
1542  DlPaint paint;
1543  DlMatrix translate = DlMatrix::MakeTranslation({300, 0});
1544  paint.setImageFilter(
1545  DlImageFilter::MakeMatrix(translate, DlImageSampling::kLinear));
1546  builder.SaveLayer(std::nullopt, &paint);
1547 
1548  DlPaint circle_paint;
1549  circle_paint.setColor(DlColor::kGreen());
1550  builder.DrawCircle(DlPoint(-300, 0), 100, circle_paint);
1551  builder.Restore();
1552 
1553  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1554 }
1555 
1556 // Render a white circle at the top left corner of the screen.
1558  MatrixImageFilterDoesntCullWhenScaledAndTranslatedFromOffscreen) {
1559  DisplayListBuilder builder;
1560  builder.Scale(GetContentScale().x, GetContentScale().y);
1561  builder.Translate(100, 100);
1562  // Draw a circle in a SaveLayer at -300, but move it back on-screen with a
1563  // +300 translation applied by a SaveLayer image filter.
1564 
1565  DlPaint paint;
1566  paint.setImageFilter(DlImageFilter::MakeMatrix(
1567  DlMatrix::MakeTranslation({300, 0}) * DlMatrix::MakeScale({2, 2, 1}),
1568  DlImageSampling::kNearestNeighbor));
1569  builder.SaveLayer(std::nullopt, &paint);
1570 
1571  DlPaint circle_paint;
1572  circle_paint.setColor(DlColor::kGreen());
1573  builder.DrawCircle(DlPoint(-150, 0), 50, circle_paint);
1574  builder.Restore();
1575 
1576  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1577 }
1578 
1579 // This should be solid red, if you see a little red box this is broken.
1580 TEST_P(AiksTest, ClearColorOptimizationWhenSubpassIsBiggerThanParentPass) {
1581  SetWindowSize({400, 400});
1582  DisplayListBuilder builder;
1583 
1584  builder.Scale(GetContentScale().x, GetContentScale().y);
1585 
1586  DlPaint paint;
1587  paint.setColor(DlColor::kRed());
1588  builder.DrawRect(DlRect::MakeLTRB(200, 200, 300, 300), paint);
1589 
1590  paint.setImageFilter(DlImageFilter::MakeMatrix(DlMatrix::MakeScale({2, 2, 1}),
1591  DlImageSampling::kLinear));
1592  builder.SaveLayer(std::nullopt, &paint);
1593  // Draw a rectangle that would fully cover the parent pass size, but not
1594  // the subpass that it is rendered in.
1595  paint.setColor(DlColor::kGreen());
1596  builder.DrawRect(DlRect::MakeLTRB(0, 0, 400, 400), paint);
1597  // Draw a bigger rectangle to force the subpass to be bigger.
1598 
1599  paint.setColor(DlColor::kRed());
1600  builder.DrawRect(DlRect::MakeLTRB(0, 0, 800, 800), paint);
1601  builder.Restore();
1602 
1603  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1604 }
1605 
1606 TEST_P(AiksTest, EmptySaveLayerIgnoresPaint) {
1607  DisplayListBuilder builder;
1608  builder.Scale(GetContentScale().x, GetContentScale().y);
1609 
1610  DlPaint paint;
1611  paint.setColor(DlColor::kRed());
1612  builder.DrawPaint(paint);
1613  builder.ClipRect(DlRect::MakeXYWH(100, 100, 200, 200));
1614  paint.setColor(DlColor::kBlue());
1615  builder.SaveLayer(std::nullopt, &paint);
1616  builder.Restore();
1617 
1618  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1619 }
1620 
1621 TEST_P(AiksTest, EmptySaveLayerRendersWithClear) {
1622  DisplayListBuilder builder;
1623  builder.Scale(GetContentScale().x, GetContentScale().y);
1624  auto image = DlImageImpeller::Make(CreateTextureForFixture("airplane.jpg"));
1625  builder.DrawImage(image, DlPoint(10, 10), {});
1626  builder.ClipRect(DlRect::MakeXYWH(100, 100, 200, 200));
1627 
1628  DlPaint paint;
1629  paint.setBlendMode(DlBlendMode::kClear);
1630  builder.SaveLayer(std::nullopt, &paint);
1631  builder.Restore();
1632 
1633  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1634 }
1635 
1637  CanPerformSaveLayerWithBoundsAndLargerIntermediateIsNotAllocated) {
1638  DisplayListBuilder builder;
1639 
1640  DlPaint red;
1641  red.setColor(DlColor::kRed());
1642 
1643  DlPaint green;
1644  green.setColor(DlColor::kGreen());
1645 
1646  DlPaint blue;
1647  blue.setColor(DlColor::kBlue());
1648 
1649  DlPaint save;
1650  save.setColor(DlColor::kBlack().modulateOpacity(0.5));
1651 
1652  DlRect huge_bounds = DlRect::MakeXYWH(0, 0, 100000, 100000);
1653  builder.SaveLayer(huge_bounds, &save);
1654 
1655  builder.DrawRect(DlRect::MakeXYWH(0, 0, 100, 100), red);
1656  builder.DrawRect(DlRect::MakeXYWH(10, 10, 100, 100), green);
1657  builder.DrawRect(DlRect::MakeXYWH(20, 20, 100, 100), blue);
1658 
1659  builder.Restore();
1660 
1661  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1662 }
1663 
1664 // This makes sure the WideGamut named tests use 16bit float pixel format.
1665 TEST_P(AiksTest, FormatWideGamut) {
1666  EXPECT_EQ(GetContext()->GetCapabilities()->GetDefaultColorFormat(),
1668 }
1669 
1670 TEST_P(AiksTest, FormatSRGB) {
1671  PixelFormat pixel_format =
1672  GetContext()->GetCapabilities()->GetDefaultColorFormat();
1673  EXPECT_TRUE(pixel_format == PixelFormat::kR8G8B8A8UNormInt ||
1674  pixel_format == PixelFormat::kB8G8R8A8UNormInt)
1675  << "pixel format: " << PixelFormatToString(pixel_format);
1676 }
1677 
1678 TEST_P(AiksTest, CoordinateConversionsAreCorrect) {
1679  DisplayListBuilder builder;
1680 
1681  // Render a texture directly.
1682  {
1683  auto image = DlImageImpeller::Make(CreateTextureForFixture("kalimba.jpg"));
1684 
1685  builder.Save();
1686  builder.Translate(100, 200);
1687  builder.Scale(0.5, 0.5);
1688  builder.DrawImage(image, DlPoint(100.0, 100.0),
1689  DlImageSampling::kNearestNeighbor);
1690  builder.Restore();
1691  }
1692 
1693  // Render an offscreen rendered texture.
1694  {
1695  DlPaint alpha;
1696  alpha.setColor(DlColor::kRed().modulateOpacity(0.5));
1697 
1698  builder.SaveLayer(std::nullopt, &alpha);
1699 
1700  DlPaint paint;
1701  paint.setColor(DlColor::kRed());
1702  builder.DrawRect(DlRect::MakeXYWH(000, 000, 100, 100), paint);
1703  paint.setColor(DlColor::kGreen());
1704  builder.DrawRect(DlRect::MakeXYWH(020, 020, 100, 100), paint);
1705  paint.setColor(DlColor::kBlue());
1706  builder.DrawRect(DlRect::MakeXYWH(040, 040, 100, 100), paint);
1707 
1708  builder.Restore();
1709  }
1710 
1711  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1712 }
1713 
1714 TEST_P(AiksTest, CanPerformFullScreenMSAA) {
1715  DisplayListBuilder builder;
1716 
1717  DlPaint paint;
1718  paint.setColor(DlColor::kRed());
1719  builder.DrawCircle(DlPoint(250, 250), 125, paint);
1720 
1721  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1722 }
1723 
1724 TEST_P(AiksTest, CanPerformSkew) {
1725  DisplayListBuilder builder;
1726 
1727  DlPaint red;
1728  red.setColor(DlColor::kRed());
1729  builder.Skew(2, 5);
1730  builder.DrawRect(DlRect::MakeXYWH(0, 0, 100, 100), red);
1731 
1732  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1733 }
1734 
1735 TEST_P(AiksTest, CanPerformSaveLayerWithBounds) {
1736  DisplayListBuilder builder;
1737 
1738  DlPaint save;
1739  save.setColor(DlColor::kBlack());
1740 
1741  DlRect save_bounds = DlRect::MakeXYWH(0, 0, 50, 50);
1742  builder.SaveLayer(save_bounds, &save);
1743 
1744  DlPaint paint;
1745  paint.setColor(DlColor::kRed());
1746  builder.DrawRect(DlRect::MakeXYWH(0, 0, 100, 100), paint);
1747  paint.setColor(DlColor::kGreen());
1748  builder.DrawRect(DlRect::MakeXYWH(10, 10, 100, 100), paint);
1749  paint.setColor(DlColor::kBlue());
1750  builder.DrawRect(DlRect::MakeXYWH(20, 20, 100, 100), paint);
1751 
1752  builder.Restore();
1753 
1754  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1755 }
1756 
1757 TEST_P(AiksTest, FilledRoundRectPathsRenderCorrectly) {
1758  DisplayListBuilder builder;
1759  builder.Scale(GetContentScale().x, GetContentScale().y);
1760 
1761  DlPaint paint;
1762  const int color_count = 3;
1763  DlColor colors[color_count] = {
1764  DlColor::kBlue(),
1765  DlColor::kGreen(),
1766  DlColor::ARGB(1.0, 220.0f / 255.0f, 20.0f / 255.0f, 60.0f / 255.0f),
1767  };
1768 
1769  paint.setColor(DlColor::kWhite());
1770  builder.DrawPaint(paint);
1771 
1772  auto draw_rrect_as_path = [&builder](const DlRect& rect, Scalar x, Scalar y,
1773  const DlPaint& paint) {
1774  builder.DrawPath(DlPath::MakeRoundRectXY(rect, x, y), paint);
1775  };
1776 
1777  int c_index = 0;
1778  for (int i = 0; i < 4; i++) {
1779  for (int j = 0; j < 4; j++) {
1780  paint.setColor(colors[(c_index++) % color_count]);
1781  draw_rrect_as_path(DlRect::MakeXYWH(i * 100 + 10, j * 100 + 20, 80, 80),
1782  i * 5 + 10, j * 5 + 10, paint);
1783  }
1784  }
1785  paint.setColor(colors[(c_index++) % color_count]);
1786  draw_rrect_as_path(DlRect::MakeXYWH(10, 420, 380, 80), 40, 40, paint);
1787  paint.setColor(colors[(c_index++) % color_count]);
1788  draw_rrect_as_path(DlRect::MakeXYWH(410, 20, 80, 380), 40, 40, paint);
1789 
1790  std::vector<DlColor> gradient_colors = {
1791  DlColor::RGBA(0x1f / 255.0, 0.0, 0x5c / 255.0, 1.0),
1792  DlColor::RGBA(0x5b / 255.0, 0.0, 0x60 / 255.0, 1.0),
1793  DlColor::RGBA(0x87 / 255.0, 0x01 / 255.0, 0x60 / 255.0, 1.0),
1794  DlColor::RGBA(0xac / 255.0, 0x25 / 255.0, 0x53 / 255.0, 1.0),
1795  DlColor::RGBA(0xe1 / 255.0, 0x6b / 255.0, 0x5c / 255.0, 1.0),
1796  DlColor::RGBA(0xf3 / 255.0, 0x90 / 255.0, 0x60 / 255.0, 1.0),
1797  DlColor::RGBA(0xff / 255.0, 0xb5 / 255.0, 0x6b / 250.0, 1.0)};
1798  std::vector<Scalar> stops = {
1799  0.0,
1800  (1.0 / 6.0) * 1,
1801  (1.0 / 6.0) * 2,
1802  (1.0 / 6.0) * 3,
1803  (1.0 / 6.0) * 4,
1804  (1.0 / 6.0) * 5,
1805  1.0,
1806  };
1807  auto texture = DlImageImpeller::Make(
1808  CreateTextureForFixture("airplane.jpg",
1809  /*enable_mipmapping=*/true));
1810 
1811  paint.setColor(DlColor::kWhite().modulateOpacity(0.1));
1812  paint.setColorSource(DlColorSource::MakeRadial(
1813  /*center=*/DlPoint(550, 550),
1814  /*radius=*/75,
1815  /*stop_count=*/gradient_colors.size(),
1816  /*colors=*/gradient_colors.data(),
1817  /*stops=*/stops.data(),
1818  /*tile_mode=*/DlTileMode::kMirror));
1819  for (int i = 1; i <= 10; i++) {
1820  int j = 11 - i;
1821  draw_rrect_as_path(DlRect::MakeLTRB(550 - i * 20, 550 - j * 20, //
1822  550 + i * 20, 550 + j * 20),
1823  i * 10, j * 10, paint);
1824  }
1825  paint.setColor(DlColor::kWhite().modulateOpacity(0.5));
1826  paint.setColorSource(DlColorSource::MakeRadial(
1827  /*center=*/DlPoint(200, 650),
1828  /*radius=*/75,
1829  /*stop_count=*/gradient_colors.size(),
1830  /*colors=*/gradient_colors.data(),
1831  /*stops=*/stops.data(),
1832  /*tile_mode=*/DlTileMode::kMirror));
1833  draw_rrect_as_path(DlRect::MakeLTRB(100, 610, 300, 690), 40, 40, paint);
1834  draw_rrect_as_path(DlRect::MakeLTRB(160, 550, 240, 750), 40, 40, paint);
1835 
1836  auto matrix = DlMatrix::MakeTranslation({520, 20});
1837  paint.setColor(DlColor::kWhite().modulateOpacity(0.1));
1838  paint.setColorSource(DlColorSource::MakeImage(
1839  texture, DlTileMode::kRepeat, DlTileMode::kRepeat,
1840  DlImageSampling::kMipmapLinear, &matrix));
1841  for (int i = 1; i <= 10; i++) {
1842  int j = 11 - i;
1843  draw_rrect_as_path(DlRect::MakeLTRB(720 - i * 20, 220 - j * 20, //
1844  720 + i * 20, 220 + j * 20),
1845  i * 10, j * 10, paint);
1846  }
1847  matrix = DlMatrix::MakeTranslation({800, 300});
1848  paint.setColor(DlColor::kWhite().modulateOpacity(0.5));
1849  paint.setColorSource(DlColorSource::MakeImage(
1850  texture, DlTileMode::kRepeat, DlTileMode::kRepeat,
1851  DlImageSampling::kMipmapLinear, &matrix));
1852 
1853  draw_rrect_as_path(DlRect::MakeLTRB(800, 410, 1000, 490), 40, 40, paint);
1854  draw_rrect_as_path(DlRect::MakeLTRB(860, 350, 940, 550), 40, 40, paint);
1855 
1856  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1857 }
1858 
1859 TEST_P(AiksTest, CoverageOriginShouldBeAccountedForInSubpasses) {
1860  auto callback = [&]() -> sk_sp<DisplayList> {
1861  DisplayListBuilder builder;
1862  builder.Scale(GetContentScale().x, GetContentScale().y);
1863 
1864  DlPaint alpha;
1865  alpha.setColor(DlColor::kRed().modulateOpacity(0.5));
1866 
1867  auto current = Point{25, 25};
1868  const auto offset = Point{25, 25};
1869  const auto size = Size(100, 100);
1870 
1871  static PlaygroundPoint point_a(Point(40, 40), 10, Color::White());
1872  static PlaygroundPoint point_b(Point(160, 160), 10, Color::White());
1873  auto [b0, b1] = DrawPlaygroundLine(point_a, point_b);
1874  DlRect bounds = DlRect::MakeLTRB(b0.x, b0.y, b1.x, b1.y);
1875 
1876  DlPaint stroke_paint;
1877  stroke_paint.setColor(DlColor::kYellow());
1878  stroke_paint.setStrokeWidth(5);
1879  stroke_paint.setDrawStyle(DlDrawStyle::kStroke);
1880  builder.DrawRect(bounds, stroke_paint);
1881 
1882  builder.SaveLayer(bounds, &alpha);
1883 
1884  DlPaint paint;
1885  paint.setColor(DlColor::kRed());
1886  builder.DrawRect(
1887  DlRect::MakeXYWH(current.x, current.y, size.width, size.height), paint);
1888 
1889  paint.setColor(DlColor::kGreen());
1890  current += offset;
1891  builder.DrawRect(
1892  DlRect::MakeXYWH(current.x, current.y, size.width, size.height), paint);
1893 
1894  paint.setColor(DlColor::kBlue());
1895  current += offset;
1896  builder.DrawRect(
1897  DlRect::MakeXYWH(current.x, current.y, size.width, size.height), paint);
1898 
1899  builder.Restore();
1900 
1901  return builder.Build();
1902  };
1903 
1904  ASSERT_TRUE(OpenPlaygroundHere(callback));
1905 }
1906 
1907 TEST_P(AiksTest, SaveLayerDrawsBehindSubsequentEntities) {
1908  // Compare with https://fiddle.skia.org/c/9e03de8567ffb49e7e83f53b64bcf636
1909  DisplayListBuilder builder;
1910  DlPaint paint;
1911 
1912  paint.setColor(DlColor::kBlack());
1913  DlRect rect = DlRect::MakeXYWH(25, 25, 25, 25);
1914  builder.DrawRect(rect, paint);
1915 
1916  builder.Translate(10, 10);
1917 
1918  DlPaint save_paint;
1919  builder.SaveLayer(std::nullopt, &save_paint);
1920 
1921  paint.setColor(DlColor::kGreen());
1922  builder.DrawRect(rect, paint);
1923 
1924  builder.Restore();
1925 
1926  builder.Translate(10, 10);
1927  paint.setColor(DlColor::kRed());
1928  builder.DrawRect(rect, paint);
1929 
1930  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1931 }
1932 
1933 TEST_P(AiksTest, SiblingSaveLayerBoundsAreRespected) {
1934  DisplayListBuilder builder;
1935  DlPaint paint;
1936  DlRect rect = DlRect::MakeXYWH(0, 0, 1000, 1000);
1937 
1938  // Black, green, and red squares offset by [10, 10].
1939  {
1940  DlPaint save_paint;
1941  DlRect bounds = DlRect::MakeXYWH(25, 25, 25, 25);
1942  builder.SaveLayer(bounds, &save_paint);
1943  paint.setColor(DlColor::kBlack());
1944  builder.DrawRect(rect, paint);
1945  builder.Restore();
1946  }
1947 
1948  {
1949  DlPaint save_paint;
1950  DlRect bounds = DlRect::MakeXYWH(35, 35, 25, 25);
1951  builder.SaveLayer(bounds, &save_paint);
1952  paint.setColor(DlColor::kGreen());
1953  builder.DrawRect(rect, paint);
1954  builder.Restore();
1955  }
1956 
1957  {
1958  DlPaint save_paint;
1959  DlRect bounds = DlRect::MakeXYWH(45, 45, 25, 25);
1960  builder.SaveLayer(bounds, &save_paint);
1961  paint.setColor(DlColor::kRed());
1962  builder.DrawRect(rect, paint);
1963  builder.Restore();
1964  }
1965 
1966  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1967 }
1968 
1969 TEST_P(AiksTest, CanRenderClippedLayers) {
1970  DisplayListBuilder builder;
1971 
1972  DlPaint paint;
1973  paint.setColor(DlColor::kWhite());
1974  builder.DrawPaint(paint);
1975 
1976  // Draw a green circle on the screen.
1977  {
1978  // Increase the clip depth for the savelayer to contend with.
1979  DlPath path = DlPath::MakeCircle(DlPoint(100, 100), 50);
1980  builder.ClipPath(path);
1981 
1982  DlRect bounds = DlRect::MakeXYWH(50, 50, 100, 100);
1983  DlPaint save_paint;
1984  builder.SaveLayer(bounds, &save_paint);
1985 
1986  // Fill the layer with white.
1987  paint.setColor(DlColor::kWhite());
1988  builder.DrawRect(DlRect::MakeSize(DlSize(400, 400)), paint);
1989  // Fill the layer with green, but do so with a color blend that can't be
1990  // collapsed into the parent pass.
1991  paint.setColor(DlColor::kGreen());
1992  paint.setBlendMode(DlBlendMode::kHardLight);
1993  builder.DrawRect(DlRect::MakeSize(DlSize(400, 400)), paint);
1994  }
1995 
1996  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
1997 }
1998 
1999 TEST_P(AiksTest, SaveLayerFiltersScaleWithTransform) {
2000  DisplayListBuilder builder;
2001 
2002  builder.Scale(GetContentScale().x, GetContentScale().y);
2003  builder.Translate(100, 100);
2004 
2005  auto texture = DlImageImpeller::Make(CreateTextureForFixture("boston.jpg"));
2006  auto draw_image_layer = [&builder, &texture](const DlPaint& paint) {
2007  builder.SaveLayer(std::nullopt, &paint);
2008  builder.DrawImage(texture, DlPoint(), DlImageSampling::kLinear);
2009  builder.Restore();
2010  };
2011 
2012  DlPaint effect_paint;
2013  effect_paint.setMaskFilter(DlBlurMaskFilter::Make(DlBlurStyle::kNormal, 6));
2014  draw_image_layer(effect_paint);
2015 
2016  builder.Translate(300, 300);
2017  builder.Scale(3, 3);
2018  draw_image_layer(effect_paint);
2019 
2020  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
2021 }
2022 
2023 TEST_P(AiksTest, FastEllipticalRRectMaskBlursRenderCorrectly) {
2024  DisplayListBuilder builder;
2025 
2026  builder.Scale(GetContentScale().x, GetContentScale().y);
2027  DlPaint paint;
2028  paint.setMaskFilter(DlBlurMaskFilter::Make(DlBlurStyle::kNormal, 1));
2029 
2030  DlPaint save_paint;
2031  save_paint.setColor(DlColor::kWhite());
2032  builder.DrawPaint(save_paint);
2033 
2034  paint.setColor(DlColor::kBlue());
2035  for (int i = 0; i < 5; i++) {
2036  Scalar y = i * 125;
2037  Scalar y_radius = i * 15;
2038  for (int j = 0; j < 5; j++) {
2039  Scalar x = j * 125;
2040  Scalar x_radius = j * 15;
2041  builder.DrawRoundRect(
2042  DlRoundRect::MakeRectXY(
2043  DlRect::MakeXYWH(x + 50, y + 50, 100.0f, 100.0f), //
2044  x_radius, y_radius),
2045  paint);
2046  }
2047  }
2048 
2049  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
2050 }
2051 
2052 TEST_P(AiksTest, PipelineBlendSingleParameter) {
2053  DisplayListBuilder builder;
2054 
2055  // Should render a green square in the middle of a blue circle.
2056  DlPaint paint;
2057  builder.SaveLayer(std::nullopt, &paint);
2058  {
2059  builder.Translate(100, 100);
2060  paint.setColor(DlColor::kBlue());
2061  builder.DrawCircle(DlPoint(200, 200), 200, paint);
2062  builder.ClipRect(DlRect::MakeXYWH(100, 100, 200, 200));
2063 
2064  paint.setColor(DlColor::kGreen());
2065  paint.setBlendMode(DlBlendMode::kSrcOver);
2066  paint.setImageFilter(DlImageFilter::MakeColorFilter(
2067  DlColorFilter::MakeBlend(DlColor::kWhite(), DlBlendMode::kDst)));
2068  builder.DrawCircle(DlPoint(200, 200), 200, paint);
2069  builder.Restore();
2070  }
2071 
2072  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
2073 }
2074 
2075 // Creates an image matrix filter that scales large content such that it would
2076 // exceed the max texture size. See
2077 // https://github.com/flutter/flutter/issues/128912
2078 TEST_P(AiksTest, MassiveScalingMatrixImageFilter) {
2079  if (GetBackend() == PlaygroundBackend::kVulkan) {
2080  GTEST_SKIP() << "Swiftshader is running out of memory on this example.";
2081  }
2082  DisplayListBuilder builder(DlRect::MakeSize(DlSize(1000, 1000)));
2083 
2084  auto filter = DlImageFilter::MakeMatrix(
2085  DlMatrix::MakeScale({0.001, 0.001, 1}), DlImageSampling::kLinear);
2086 
2087  DlPaint paint;
2088  paint.setImageFilter(filter);
2089  builder.SaveLayer(std::nullopt, &paint);
2090  {
2091  DlPaint paint;
2092  paint.setColor(DlColor::kRed());
2093  builder.DrawRect(DlRect::MakeLTRB(0, 0, 100000, 100000), paint);
2094  }
2095  builder.Restore();
2096 
2097  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
2098 }
2099 
2100 TEST_P(AiksTest, NoDimplesInRRectPath) {
2101  Scalar width = 200.f;
2102  Scalar height = 60.f;
2103  Scalar corner = 1.f;
2104  auto callback = [&]() -> sk_sp<DisplayList> {
2105  if (AiksTest::ImGuiBegin("Controls", nullptr,
2106  ImGuiWindowFlags_AlwaysAutoResize)) {
2107  ImGui::SliderFloat("width", &width, 0, 200);
2108  ImGui::SliderFloat("height", &height, 0, 200);
2109  ImGui::SliderFloat("corner", &corner, 0, 1);
2110  ImGui::End();
2111  }
2112 
2113  DisplayListBuilder builder;
2114  builder.Scale(GetContentScale().x, GetContentScale().y);
2115 
2116  DlPaint background_paint;
2117  background_paint.setColor(DlColor(1, 0.1, 0.1, 0.1, DlColorSpace::kSRGB));
2118  builder.DrawPaint(background_paint);
2119 
2120  std::vector<DlColor> colors = {DlColor::kRed(), DlColor::kBlue()};
2121  std::vector<Scalar> stops = {0.0, 1.0};
2122 
2123  DlPaint paint;
2124  auto gradient = DlColorSource::MakeLinear(DlPoint(0, 0), DlPoint(200, 200),
2125  2, colors.data(), stops.data(),
2126  DlTileMode::kClamp);
2127  paint.setColorSource(gradient);
2128  paint.setColor(DlColor::kWhite());
2129  paint.setDrawStyle(DlDrawStyle::kStroke);
2130  paint.setStrokeWidth(20);
2131 
2132  builder.Save();
2133  builder.Translate(100, 100);
2134 
2135  Scalar corner_x = ((1 - corner) * 50) + 50;
2136  Scalar corner_y = corner * 50 + 50;
2137  DlRoundRect rrect = DlRoundRect::MakeRectXY(
2138  DlRect::MakeXYWH(0, 0, width, height), corner_x, corner_y);
2139  builder.DrawRoundRect(rrect, paint);
2140  builder.Restore();
2141  return builder.Build();
2142  };
2143  ASSERT_TRUE(OpenPlaygroundHere(callback));
2144 }
2145 
2146 TEST_P(AiksTest, BackdropFilterOverUnclosedClip) {
2147  DisplayListBuilder builder;
2148 
2149  builder.DrawPaint(DlPaint().setColor(DlColor::kWhite()));
2150  builder.Save();
2151  {
2152  builder.ClipRect(DlRect::MakeLTRB(100, 100, 800, 800));
2153 
2154  builder.Save();
2155  {
2156  builder.ClipRect(DlRect::MakeLTRB(600, 600, 800, 800));
2157  builder.DrawPaint(DlPaint().setColor(DlColor::kRed()));
2158  builder.DrawPaint(DlPaint().setColor(DlColor::kBlue().withAlphaF(0.5)));
2159  builder.ClipRect(DlRect::MakeLTRB(700, 700, 750, 800));
2160  builder.DrawPaint(DlPaint().setColor(DlColor::kRed().withAlphaF(0.5)));
2161  }
2162  builder.Restore();
2163 
2164  auto image_filter = DlImageFilter::MakeBlur(10, 10, DlTileMode::kDecal);
2165  builder.SaveLayer(std::nullopt, nullptr, image_filter.get());
2166  }
2167  builder.Restore();
2168  builder.DrawCircle(DlPoint(100, 100), 100,
2169  DlPaint().setColor(DlColor::kAqua()));
2170 
2171  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
2172 }
2173 
2174 } // namespace testing
2175 } // namespace impeller
bool full_circles
Scalar vertical_scale
bool sweeps_over_360
bool use_center
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
AiksPlayground AiksTest
TEST_P(AiksTest, DrawAtlasNoColor)
flutter::DlRect DlRect
Definition: dl_dispatcher.h:25
float Scalar
Definition: scalar.h:19
std::tuple< Point, Point > DrawPlaygroundLine(PlaygroundPoint &point_a, PlaygroundPoint &point_b)
Definition: widgets.cc:51
constexpr float kEhCloseEnough
Definition: constants.h:57
flutter::DlRoundRect DlRoundRect
Definition: dl_dispatcher.h:27
TRect< Scalar > Rect
Definition: rect.h:788
TPoint< Scalar > Point
Definition: point.h:327
PixelFormat
The Pixel formats supported by Impeller. The naming convention denotes the usage of the component,...
Definition: formats.h:99
flutter::DlPoint DlPoint
Definition: dl_dispatcher.h:24
flutter::DlPath DlPath
Definition: dl_dispatcher.h:29
TSize< Scalar > Size
Definition: size.h:159
constexpr float kSqrt2
Definition: constants.h:47
constexpr const char * PixelFormatToString(PixelFormat format)
Definition: formats.h:140
flutter::DlScalar DlScalar
Definition: dl_dispatcher.h:23
void Close(PathBuilder *builder)
Definition: tessellator.cc:38
static constexpr Color White()
Definition: color.h:264
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
constexpr Quad Transform(const Quad &quad) const
Definition: matrix.h:623
static RoundRect MakeRectXY(const Rect &rect, Scalar x_radius, Scalar y_radius)
Definition: round_rect.h:31
constexpr static TRect MakeLTRB(Type left, Type top, Type right, Type bottom)
Definition: rect.h:129
const size_t start