Flutter Impeller
dl_golden_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 
6 
7 #include "flutter/display_list/dl_builder.h"
9 #include "flutter/testing/testing.h"
10 #include "gtest/gtest.h"
11 
12 namespace flutter {
13 namespace testing {
14 
15 using impeller::Degrees;
18 using impeller::Point;
19 using impeller::Radians;
20 using impeller::Scalar;
21 
23 
24 TEST_P(DlGoldenTest, CanDrawPaint) {
25  auto draw = [](DlCanvas* canvas,
26  const std::vector<std::unique_ptr<DlImage>>& images) {
27  canvas->Scale(0.2, 0.2);
28  DlPaint paint;
29  paint.setColor(DlColor::kCyan());
30  canvas->DrawPaint(paint);
31  };
32 
33  DisplayListBuilder builder;
34  draw(&builder, /*images=*/{});
35 
36  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
37 }
38 
39 TEST_P(DlGoldenTest, CanRenderImage) {
40  auto draw = [](DlCanvas* canvas, const std::vector<sk_sp<DlImage>>& images) {
41  FML_CHECK(images.size() >= 1);
42  DlPaint paint;
43  paint.setColor(DlColor::kRed());
44  canvas->DrawImage(images[0], SkPoint::Make(100.0, 100.0),
45  DlImageSampling::kLinear, &paint);
46  };
47 
48  DisplayListBuilder builder;
49  std::vector<sk_sp<DlImage>> images;
50  images.emplace_back(CreateDlImageForFixture("kalimba.jpg"));
51  draw(&builder, images);
52 
53  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
54 }
55 
56 // Asserts that subpass rendering of MatrixImageFilters works.
57 // https://github.com/flutter/flutter/issues/147807
58 TEST_P(DlGoldenTest, Bug147807) {
59  Point content_scale = GetContentScale();
60  auto draw = [content_scale](DlCanvas* canvas,
61  const std::vector<sk_sp<DlImage>>& images) {
62  canvas->Scale(content_scale.x, content_scale.y);
63  DlPaint paint;
64  paint.setColor(DlColor(0xfffef7ff));
65  canvas->DrawRect(SkRect::MakeLTRB(0, 0, 375, 667), paint);
66  paint.setColor(DlColor(0xffff9800));
67  canvas->DrawRect(SkRect::MakeLTRB(0, 0, 187.5, 333.5), paint);
68  paint.setColor(DlColor(0xff9c27b0));
69  canvas->DrawRect(SkRect::MakeLTRB(187.5, 0, 375, 333.5), paint);
70  paint.setColor(DlColor(0xff4caf50));
71  canvas->DrawRect(SkRect::MakeLTRB(0, 333.5, 187.5, 667), paint);
72  paint.setColor(DlColor(0xfff44336));
73  canvas->DrawRect(SkRect::MakeLTRB(187.5, 333.5, 375, 667), paint);
74 
75  canvas->Save();
76  {
77  canvas->ClipRRect(
78  SkRRect::MakeOval(SkRect::MakeLTRB(201.25, 10, 361.25, 170)),
79  DlCanvas::ClipOp::kIntersect, true);
80  SkRect save_layer_bounds = SkRect::MakeLTRB(201.25, 10, 361.25, 170);
81  DlMatrixImageFilter backdrop(SkMatrix::MakeAll(3, 0, -280, //
82  0, 3, -920, //
83  0, 0, 1),
84  DlImageSampling::kLinear);
85  canvas->SaveLayer(&save_layer_bounds, /*paint=*/nullptr, &backdrop);
86  {
87  canvas->Translate(201.25, 10);
88  auto paint = DlPaint()
89  .setAntiAlias(true)
90  .setColor(DlColor(0xff2196f3))
91  .setStrokeWidth(5)
92  .setDrawStyle(DlDrawStyle::kStroke);
93  canvas->DrawCircle(SkPoint::Make(80, 80), 80, paint);
94  }
95  canvas->Restore();
96  }
97  canvas->Restore();
98  };
99 
100  DisplayListBuilder builder;
101  std::vector<sk_sp<DlImage>> images;
102  draw(&builder, images);
103 
104  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
105 }
106 
107 namespace {
108 void DrawBlurGrid(DlCanvas* canvas) {
109  DlPaint paint;
110  paint.setColor(DlColor(0xfffef7ff));
111  Scalar width = 150;
112  Scalar height = 150;
113  Scalar gap = 80;
114  std::vector<Scalar> blur_radii = {10, 30, 50};
115  for (size_t i = 0; i < blur_radii.size(); ++i) {
116  Scalar blur_radius = blur_radii[i];
117  auto blur_filter = std::make_shared<flutter::DlBlurMaskFilter>(
118  flutter::DlBlurStyle::kNormal, blur_radius);
119  paint.setMaskFilter(blur_filter);
120  SkRRect rrect;
121  Scalar yval = gap + i * (gap + height);
122  rrect.setNinePatch(SkRect::MakeXYWH(gap, yval, width, height), 10, 10, 10,
123  10);
124  canvas->DrawRRect(rrect, paint);
125  rrect.setNinePatch(SkRect::MakeXYWH(2.0 * gap + width, yval, width, height),
126  9, 10, 10, 10);
127  canvas->DrawRRect(rrect, paint);
128  }
129 }
130 } // namespace
131 
132 TEST_P(DlGoldenTest, GaussianVsRRectBlur) {
133  Point content_scale = GetContentScale();
134  auto draw = [content_scale](DlCanvas* canvas,
135  const std::vector<sk_sp<DlImage>>& images) {
136  canvas->Scale(content_scale.x, content_scale.y);
137  canvas->DrawPaint(DlPaint().setColor(DlColor(0xff112233)));
138  DrawBlurGrid(canvas);
139  };
140 
141  DisplayListBuilder builder;
142  std::vector<sk_sp<DlImage>> images;
143  draw(&builder, images);
144 
145  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
146 }
147 
148 TEST_P(DlGoldenTest, GaussianVsRRectBlurScaled) {
149  Point content_scale = GetContentScale();
150  auto draw = [content_scale](DlCanvas* canvas,
151  const std::vector<sk_sp<DlImage>>& images) {
152  canvas->Scale(content_scale.x, content_scale.y);
153  canvas->DrawPaint(DlPaint().setColor(DlColor(0xff112233)));
154  canvas->Scale(0.33, 0.33);
155  DrawBlurGrid(canvas);
156  };
157 
158  DisplayListBuilder builder;
159  std::vector<sk_sp<DlImage>> images;
160  draw(&builder, images);
161 
162  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
163 }
164 
165 TEST_P(DlGoldenTest, GaussianVsRRectBlurScaledRotated) {
166  Point content_scale = GetContentScale();
167  auto draw = [content_scale](DlCanvas* canvas,
168  const std::vector<sk_sp<DlImage>>& images) {
169  canvas->Scale(content_scale.x, content_scale.y);
170  canvas->Translate(200, 200);
171  canvas->DrawPaint(DlPaint().setColor(DlColor(0xff112233)));
172  canvas->Scale(0.33, 0.33);
173  canvas->Translate(300, 300);
174  canvas->Rotate(45);
175  canvas->Translate(-300, -300);
176  DrawBlurGrid(canvas);
177  };
178 
179  DisplayListBuilder builder;
180  std::vector<sk_sp<DlImage>> images;
181  draw(&builder, images);
182 
183  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
184 }
185 
186 TEST_P(DlGoldenTest, FastVsGeneralGaussianMaskBlur) {
187  DisplayListBuilder builder;
188  builder.Scale(GetContentScale().x, GetContentScale().y);
189  builder.DrawColor(DlColor::kWhite(), DlBlendMode::kSrc);
190 
191  auto blur_sigmas = std::array{5.0f, 10.0f, 20.0f};
192  auto blur_colors = std::array{
193  DlColor::kBlue(),
194  DlColor::kGreen(),
195  DlColor::kMaroon(),
196  };
197 
198  auto make_rrect_path = [](const SkRect& rect, DlScalar rx,
199  DlScalar ry) -> SkPath {
200  auto add_corner = [](SkPath& path, SkPoint rCorner, SkPoint rEnd) {
201  static const auto magic = impeller::PathBuilder::kArcApproximationMagic;
202  path.rCubicTo(rCorner.fX * (1.0f - magic), rCorner.fY * (1.0f - magic),
203  rCorner.fX + rEnd.fX * magic, rCorner.fY + rEnd.fY * magic,
204  rCorner.fX + rEnd.fX, rCorner.fY + rEnd.fY);
205  };
206 
207  SkPath path;
208  path.moveTo(rect.fRight - rx, rect.fTop);
209  add_corner(path, {rx, 0.0f}, {0.0f, ry});
210  path.lineTo(rect.fRight, rect.fBottom - ry);
211  add_corner(path, {0.0f, ry}, {-rx, 0.0f});
212  path.lineTo(rect.fLeft + rx, rect.fBottom);
213  add_corner(path, {-rx, 0.0f}, {0.0f, -ry});
214  path.lineTo(rect.fLeft, rect.fTop + ry);
215  add_corner(path, {0.0f, -ry}, {rx, 0.0f});
216  path.close();
217  return path;
218  };
219 
220  for (size_t i = 0; i < blur_sigmas.size(); i++) {
221  auto rect = SkRect::MakeXYWH(i * 320.0f + 50.0f, 50.0f, 100.0f, 100.0f);
222  DlPaint paint = DlPaint() //
223  .setColor(blur_colors[i])
224  .setMaskFilter(DlBlurMaskFilter::Make(
225  DlBlurStyle::kNormal, blur_sigmas[i]));
226 
227  builder.DrawRRect(SkRRect::MakeRectXY(rect, 10.0f, 10.0f), paint);
228  rect = rect.makeOffset(150.0f, 0.0f);
229  builder.DrawPath(make_rrect_path(rect, 10.0f, 10.0f), paint);
230  rect = rect.makeOffset(-150.0f, 0.0f);
231 
232  rect = rect.makeOffset(0.0f, 200.0f);
233  builder.DrawRRect(SkRRect::MakeRectXY(rect, 10.0f, 30.0f), paint);
234  rect = rect.makeOffset(150.0f, 0.0f);
235  builder.DrawPath(make_rrect_path(rect, 10.0f, 20.0f), paint);
236  rect = rect.makeOffset(-150.0f, 0.0f);
237 
238  rect = rect.makeOffset(0.0f, 200.0f);
239  builder.DrawRRect(SkRRect::MakeRectXY(rect, 30.0f, 10.0f), paint);
240  rect = rect.makeOffset(150.0f, 0.0f);
241  builder.DrawPath(make_rrect_path(rect, 20.0f, 10.0f), paint);
242  rect = rect.makeOffset(-150.0f, 0.0f);
243  }
244 
245  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
246 }
247 
248 TEST_P(DlGoldenTest, DashedLinesTest) {
249  Point content_scale = GetContentScale();
250  auto draw = [content_scale](DlCanvas* canvas,
251  const std::vector<sk_sp<DlImage>>& images) {
252  canvas->Scale(content_scale.x, content_scale.y);
253  canvas->DrawPaint(DlPaint().setColor(DlColor::kWhite()));
254 
255  auto draw_one = [canvas](DlStrokeCap cap, Scalar x, Scalar y,
256  Scalar dash_on, Scalar dash_off) {
257  Point center = Point(x, y);
258  Scalar inner = 20.0f;
259  Scalar outer = 100.0f;
260  DlPaint thick_paint = DlPaint()
261  .setColor(DlColor::kBlue())
262  .setStrokeCap(cap)
263  .setStrokeWidth(8.0f);
264  DlPaint middle_paint = DlPaint()
265  .setColor(DlColor::kGreen())
266  .setStrokeCap(cap)
267  .setStrokeWidth(5.0f);
268  DlPaint thin_paint = DlPaint()
269  .setColor(DlColor::kMagenta())
270  .setStrokeCap(cap)
271  .setStrokeWidth(2.0f);
272  for (int degrees = 0; degrees < 360; degrees += 30) {
273  Point delta = Point(1.0f, 0.0f).Rotate(Degrees(degrees));
274  canvas->DrawDashedLine(center + inner * delta, center + outer * delta,
275  dash_on, dash_off, thick_paint);
276  canvas->DrawDashedLine(center + inner * delta, center + outer * delta,
277  dash_on, dash_off, middle_paint);
278  canvas->DrawDashedLine(center + inner * delta, center + outer * delta,
279  dash_on, dash_off, thin_paint);
280  }
281  };
282 
283  draw_one(DlStrokeCap::kButt, 150.0f, 150.0f, 15.0f, 10.0f);
284  draw_one(DlStrokeCap::kSquare, 400.0f, 150.0f, 15.0f, 10.0f);
285  draw_one(DlStrokeCap::kRound, 150.0f, 400.0f, 15.0f, 10.0f);
286  draw_one(DlStrokeCap::kRound, 400.0f, 400.0f, 0.0f, 11.0f);
287 
288  // Make sure the rendering op responds appropriately to clipping
289  canvas->Save();
290  SkPath clip_path = SkPath();
291  clip_path.moveTo(275.0f, 225.0f);
292  clip_path.lineTo(325.0f, 275.0f);
293  clip_path.lineTo(275.0f, 325.0f);
294  clip_path.lineTo(225.0f, 275.0f);
295  canvas->ClipPath(clip_path);
296  canvas->DrawColor(DlColor::kYellow());
297  draw_one(DlStrokeCap::kRound, 275.0f, 275.0f, 15.0f, 10.0f);
298  canvas->Restore();
299  };
300 
301  DisplayListBuilder builder;
302  std::vector<sk_sp<DlImage>> images;
303  draw(&builder, images);
304 
305  ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
306 }
307 
308 } // namespace testing
309 } // namespace flutter
impeller::Scalar
float Scalar
Definition: scalar.h:18
path_builder.h
impeller::PlaygroundBackend
PlaygroundBackend
Definition: playground.h:26
impeller::PathBuilder::kArcApproximationMagic
constexpr static const Scalar kArcApproximationMagic
Definition: path_builder.h:23
flutter::testing::TEST_P
TEST_P(DlGoldenTest, TextBlurMaskFilterRespectCTM)
Definition: dl_golden_blur_unittests.cc:60
dl_golden_unittests.h
impeller::Point
TPoint< Scalar > Point
Definition: point.h:327
impeller::Radians
Definition: scalar.h:43
flutter
Definition: dl_golden_blur_unittests.cc:15
blur_radius
Vector2 blur_radius
Blur radius in source pixels based on scaled_sigma.
Definition: gaussian_blur_filter_contents.cc:83
impeller::Degrees
Definition: scalar.h:51
impeller::TPoint::Rotate
constexpr TPoint Rotate(const Radians &angle) const
Definition: point.h:226
impeller::PlaygroundTest
Definition: playground_test.h:21
impeller::DlScalar
flutter::DlScalar DlScalar
Definition: dl_dispatcher.h:21
flutter::testing::DlGoldenTest
impeller::DlPlayground DlGoldenTest
Definition: dl_golden_unittests.h:17
flutter::testing::INSTANTIATE_PLAYGROUND_SUITE
INSTANTIATE_PLAYGROUND_SUITE(DlGoldenTest)
impeller::DlPlayground
Definition: dl_playground.h:16