| Flutter Impeller |

aiks_blend_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 "flutter/impeller/aiks/aiks_unittests.h"
6
7 #include "flutter/testing/testing.h"
8 #include "impeller/aiks/canvas.h"
9 #include "impeller/aiks/color_filter.h"
10 #include "impeller/geometry/color.h"
11 #include "impeller/geometry/scalar.h"
12
13 ////////////////////////////////////////////////////////////////////////////////
14 // This is for tests of Canvas that are interested the results of rendering
15 // blends.
16 ////////////////////////////////////////////////////////////////////////////////
17
18 namespace impeller {
19 namespace testing {
20
21 TEST_P(AiksTest, CanRenderAdvancedBlendColorFilterWithSaveLayer) {
22 Canvas canvas;
23
24 Rect layer_rect = Rect::MakeXYWH(0, 0, 500, 500);
25 canvas.ClipRect(layer_rect);
26
27 canvas.SaveLayer(
28 {
29 .color_filter = ColorFilter::MakeBlend(BlendMode::kDifference,
30 Color(0, 1, 0, 0.5)),
31 },
32 layer_rect);
33
34 Paint paint;
35 canvas.DrawPaint({.color = Color::Black()});
36 canvas.DrawRect(Rect::MakeXYWH(100, 100, 300, 300),
37 {.color = Color::White()});
38 canvas.Restore();
39
40 ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
41 }
42
43 TEST_P(AiksTest, BlendModeShouldCoverWholeScreen) {
44 Canvas canvas;
45 Paint paint;
46
47 paint.color = Color::Red();
48 canvas.DrawPaint(paint);
49
50 paint.blend_mode = BlendMode::kSourceOver;
51 canvas.SaveLayer(paint);
52
53 paint.color = Color::White();
54 canvas.DrawRect(Rect::MakeXYWH(100, 100, 400, 400), paint);
55
56 paint.blend_mode = BlendMode::kSource;
57 canvas.SaveLayer(paint);
58
59 paint.color = Color::Blue();
60 canvas.DrawRect(Rect::MakeXYWH(200, 200, 200, 200), paint);
61
62 canvas.Restore();
63 canvas.Restore();
64
65 ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
66 }
67
68 TEST_P(AiksTest, CanDrawPaintWithAdvancedBlend) {
69 Canvas canvas;
70 canvas.Scale(Vector2(0.2, 0.2));
71 canvas.DrawPaint({.color = Color::MediumTurquoise()});
72 canvas.DrawPaint({.color = Color::Color::OrangeRed().WithAlpha(0.5),
73 .blend_mode = BlendMode::kHue});
74 ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
75 }
76
77 TEST_P(AiksTest, DrawPaintWithAdvancedBlendOverFilter) {
78 Paint filtered = {
79 .color = Color::Black(),
80 .mask_blur_descriptor =
81 Paint::MaskBlurDescriptor{
82 .style = FilterContents::BlurStyle::kNormal,
83 .sigma = Sigma(60),
84 },
85 };
86
87 Canvas canvas;
88 canvas.DrawPaint({.color = Color::White()});
89 canvas.DrawCircle({300, 300}, 200, filtered);
90 canvas.DrawPaint({.color = Color::Green(), .blend_mode = BlendMode::kScreen});
91 ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
92 }
93
94 TEST_P(AiksTest, DrawAdvancedBlendPartlyOffscreen) {
95 std::vector<Color> colors = {Color{0.9568, 0.2627, 0.2118, 1.0},
96 Color{0.1294, 0.5882, 0.9529, 1.0}};
97 std::vector<Scalar> stops = {0.0, 1.0};
98
99 Paint paint = {
100 .color_source = ColorSource::MakeLinearGradient(
101 {0, 0}, {100, 100}, std::move(colors), std::move(stops),
102 Entity::TileMode::kRepeat, Matrix::MakeScale(Vector3(0.3, 0.3, 0.3))),
103 .blend_mode = BlendMode::kLighten,
104 };
105
106 Canvas canvas;
107 canvas.DrawPaint({.color = Color::Blue()});
108 canvas.Scale(Vector2(2, 2));
109 canvas.ClipRect(Rect::MakeLTRB(0, 0, 200, 200));
110 canvas.DrawCircle({100, 100}, 100, paint);
111 ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
112 }
113
114 TEST_P(AiksTest, PaintBlendModeIsRespected) {
115 Paint paint;
116 Canvas canvas;
117 // Default is kSourceOver.
118 paint.color = Color(1, 0, 0, 0.5);
119 canvas.DrawCircle(Point(150, 200), 100, paint);
120 paint.color = Color(0, 1, 0, 0.5);
121 canvas.DrawCircle(Point(250, 200), 100, paint);
122
123 paint.blend_mode = BlendMode::kPlus;
124 paint.color = Color::Red();
125 canvas.DrawCircle(Point(450, 250), 100, paint);
126 paint.color = Color::Green();
127 canvas.DrawCircle(Point(550, 250), 100, paint);
128 paint.color = Color::Blue();
129 canvas.DrawCircle(Point(500, 150), 100, paint);
130 ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
131 }
132
133 // Bug: https://github.com/flutter/flutter/issues/142549
134 TEST_P(AiksTest, BlendModePlusAlphaWideGamut) {
135 EXPECT_EQ(GetContext()->GetCapabilities()->GetDefaultColorFormat(),
136 PixelFormat::kB10G10R10A10XR);
137 auto texture = CreateTextureForFixture("airplane.jpg",
138 /*enable_mipmapping=*/true);
139
140 Canvas canvas;
141 canvas.Scale(GetContentScale());
142 canvas.DrawPaint({.color = Color(0.9, 1.0, 0.9, 1.0)});
143 canvas.SaveLayer({});
144 Paint paint;
145 paint.blend_mode = BlendMode::kPlus;
146 paint.color = Color::Red();
147 canvas.DrawRect(Rect::MakeXYWH(100, 100, 400, 400), paint);
148 paint.color = Color::White();
149 canvas.DrawImageRect(
150 std::make_shared<Image>(texture), Rect::MakeSize(texture->GetSize()),
151 Rect::MakeXYWH(100, 100, 400, 400).Expand(-100, -100), paint);
152 canvas.Restore();
153 ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
154 }
155
156 // Bug: https://github.com/flutter/flutter/issues/142549
157 TEST_P(AiksTest, BlendModePlusAlphaColorFilterWideGamut) {
158 EXPECT_EQ(GetContext()->GetCapabilities()->GetDefaultColorFormat(),
159 PixelFormat::kB10G10R10A10XR);
160 auto texture = CreateTextureForFixture("airplane.jpg",
161 /*enable_mipmapping=*/true);
162
163 Canvas canvas;
164 canvas.Scale(GetContentScale());
165 canvas.DrawPaint({.color = Color(0.1, 0.2, 0.1, 1.0)});
166 canvas.SaveLayer({
167 .color_filter =
168 ColorFilter::MakeBlend(BlendMode::kPlus, Color(Vector4{1, 0, 0, 1})),
169 });
170 Paint paint;
171 paint.color = Color::Red();
172 canvas.DrawRect(Rect::MakeXYWH(100, 100, 400, 400), paint);
173 paint.color = Color::White();
174 canvas.DrawImageRect(
175 std::make_shared<Image>(texture), Rect::MakeSize(texture->GetSize()),
176 Rect::MakeXYWH(100, 100, 400, 400).Expand(-100, -100), paint);
177 canvas.Restore();
178 ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
179 }
180
181 #define BLEND_MODE_TUPLE(blend_mode) {#blend_mode, BlendMode::k##blend_mode},
182
183 struct BlendModeSelection {
184 std::vector<const char*> blend_mode_names;
185 std::vector<BlendMode> blend_mode_values;
186 };
187
188 static BlendModeSelection GetBlendModeSelection() {
189 std::vector<const char*> blend_mode_names;
190 std::vector<BlendMode> blend_mode_values;
191 {
192 const std::vector<std::tuple<const char*, BlendMode>> blends = {
193 IMPELLER_FOR_EACH_BLEND_MODE(BLEND_MODE_TUPLE)};
194 assert(blends.size() ==
195 static_cast<size_t>(Entity::kLastAdvancedBlendMode) + 1);
196 for (const auto& [name, mode] : blends) {
197 blend_mode_names.push_back(name);
198 blend_mode_values.push_back(mode);
199 }
200 }
201
202 return {blend_mode_names, blend_mode_values};
203 }
204
205 TEST_P(AiksTest, ColorWheel) {
206 // Compare with https://fiddle.skia.org/c/@BlendModes
207
208 BlendModeSelection blend_modes = GetBlendModeSelection();
209
210 auto draw_color_wheel = [](Canvas& canvas) {
211 /// color_wheel_sampler: r=0 -> fuchsia, r=2pi/3 -> yellow, r=4pi/3 ->
212 /// cyan domain: r >= 0 (because modulo used is non euclidean)
213 auto color_wheel_sampler = [](Radians r) {
214 Scalar x = r.radians / k2Pi + 1;
215
216 // https://www.desmos.com/calculator/6nhjelyoaj
217 auto color_cycle = [](Scalar x) {
218 Scalar cycle = std::fmod(x, 6.0f);
219 return std::max(0.0f, std::min(1.0f, 2 - std::abs(2 - cycle)));
220 };
221 return Color(color_cycle(6 * x + 1), //
222 color_cycle(6 * x - 1), //
223 color_cycle(6 * x - 3), //
224 1);
225 };
226
227 Paint paint;
228 paint.blend_mode = BlendMode::kSourceOver;
229
230 // Draw a fancy color wheel for the backdrop.
231 // https://www.desmos.com/calculator/xw7kafthwd
232 const int max_dist = 900;
233 for (int i = 0; i <= 900; i++) {
234 Radians r(kPhi / k2Pi * i);
235 Scalar distance = r.radians / std::powf(4.12, 0.0026 * r.radians);
236 Scalar normalized_distance = static_cast<Scalar>(i) / max_dist;
237
238 paint.color =
239 color_wheel_sampler(r).WithAlpha(1.0f - normalized_distance);
240 Point position(distance * std::sin(r.radians),
241 -distance * std::cos(r.radians));
242
243 canvas.DrawCircle(position, 9 + normalized_distance * 3, paint);
244 }
245 };
246
247 std::shared_ptr<Image> color_wheel_image;
248 Matrix color_wheel_transform;
249
250 auto callback = [&](AiksContext& renderer) -> std::optional<Picture> {
251 // UI state.
252 static bool cache_the_wheel = true;
253 static int current_blend_index = 3;
254 static float dst_alpha = 1;
255 static float src_alpha = 1;
256 static Color color0 = Color::Red();
257 static Color color1 = Color::Green();
258 static Color color2 = Color::Blue();
259
260 if (AiksTest::ImGuiBegin("Controls", nullptr,
261 ImGuiWindowFlags_AlwaysAutoResize)) {
262 ImGui::Checkbox("Cache the wheel", &cache_the_wheel);
263 ImGui::ListBox("Blending mode", &current_blend_index,
264 blend_modes.blend_mode_names.data(),
265 blend_modes.blend_mode_names.size());
266 ImGui::SliderFloat("Source alpha", &src_alpha, 0, 1);
267 ImGui::ColorEdit4("Color A", reinterpret_cast<float*>(&color0));
268 ImGui::ColorEdit4("Color B", reinterpret_cast<float*>(&color1));
269 ImGui::ColorEdit4("Color C", reinterpret_cast<float*>(&color2));
270 ImGui::SliderFloat("Destination alpha", &dst_alpha, 0, 1);
271 ImGui::End();
272 }
273
274 static Point content_scale;
275 Point new_content_scale = GetContentScale();
276
277 if (!cache_the_wheel || new_content_scale != content_scale) {
278 content_scale = new_content_scale;
279
280 // Render the color wheel to an image.
281
282 Canvas canvas;
283 canvas.Scale(content_scale);
284
285 canvas.Translate(Vector2(500, 400));
286 canvas.Scale(Vector2(3, 3));
287
288 draw_color_wheel(canvas);
289 auto color_wheel_picture = canvas.EndRecordingAsPicture();
290 auto snapshot = color_wheel_picture.Snapshot(renderer);
291 if (!snapshot.has_value() || !snapshot->texture) {
292 return std::nullopt;
293 }
294 color_wheel_image = std::make_shared<Image>(snapshot->texture);
295 color_wheel_transform = snapshot->transform;
296 }
297
298 Canvas canvas;
299
300 // Blit the color wheel backdrop to the screen with managed alpha.
301 canvas.SaveLayer({.color = Color::White().WithAlpha(dst_alpha),
302 .blend_mode = BlendMode::kSource});
303 {
304 canvas.DrawPaint({.color = Color::White()});
305
306 canvas.Save();
307 canvas.Transform(color_wheel_transform);
308 canvas.DrawImage(color_wheel_image, Point(), Paint());
309 canvas.Restore();
310 }
311 canvas.Restore();
312
313 canvas.Scale(content_scale);
314 canvas.Translate(Vector2(500, 400));
315 canvas.Scale(Vector2(3, 3));
316
317 // Draw 3 circles to a subpass and blend it in.
318 canvas.SaveLayer(
319 {.color = Color::White().WithAlpha(src_alpha),
320 .blend_mode = blend_modes.blend_mode_values[current_blend_index]});
321 {
322 Paint paint;
323 paint.blend_mode = BlendMode::kPlus;
324 const Scalar x = std::sin(k2Pi / 3);
325 const Scalar y = -std::cos(k2Pi / 3);
326 paint.color = color0;
327 canvas.DrawCircle(Point(-x, y) * 45, 65, paint);
328 paint.color = color1;
329 canvas.DrawCircle(Point(0, -1) * 45, 65, paint);
330 paint.color = color2;
331 canvas.DrawCircle(Point(x, y) * 45, 65, paint);
332 }
333 canvas.Restore();
334
335 return canvas.EndRecordingAsPicture();
336 };
337
338 ASSERT_TRUE(OpenPlaygroundHere(callback));
339 }
340
341 TEST_P(AiksTest, ForegroundBlendSubpassCollapseOptimization) {
342 Canvas canvas;
343
344 canvas.SaveLayer({
345 .color_filter =
346 ColorFilter::MakeBlend(BlendMode::kColorDodge, Color::Red()),
347 });
348
349 canvas.Translate({500, 300, 0});
350 canvas.Rotate(Radians(2 * kPi / 3));
351 canvas.DrawRect(Rect::MakeXYWH(100, 100, 200, 200), {.color = Color::Blue()});
352
353 ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
354 }
355
356 TEST_P(AiksTest, ClearBlend) {
357 Canvas canvas;
358 Paint white;
359 white.color = Color::Blue();
360 canvas.DrawRect(Rect::MakeXYWH(0, 0, 600.0, 600.0), white);
361
362 Paint clear;
363 clear.blend_mode = BlendMode::kClear;
364
365 canvas.DrawCircle(Point::MakeXY(300.0, 300.0), 200.0, clear);
366 }
367
368 static Picture BlendModeTest(Vector2 content_scale,
369 BlendMode blend_mode,
370 const std::shared_ptr<Image>& src_image,
371 const std::shared_ptr<Image>& dst_image,
372 Scalar src_alpha) {
373 if (AiksTest::ImGuiBegin("Controls", nullptr,
374 ImGuiWindowFlags_AlwaysAutoResize)) {
375 ImGui::SliderFloat("Source alpha", &src_alpha, 0, 1);
376 ImGui::End();
377 }
378
379 Color destination_color = Color::CornflowerBlue().WithAlpha(0.75);
380 auto source_colors = std::vector<Color>({Color::White().WithAlpha(0.75),
381 Color::LimeGreen().WithAlpha(0.75),
382 Color::Black().WithAlpha(0.75)});
383
384 Canvas canvas;
385 canvas.DrawPaint({.color = Color::Black()});
386 // TODO(bdero): Why does this cause the left image to double scale on high DPI
387 // displays.
388 // canvas.Scale(content_scale);
389
390 //----------------------------------------------------------------------------
391 /// 1. Save layer blending (top squares).
392 ///
393
394 canvas.Save();
395 for (const auto& color : source_colors) {
396 canvas.Save();
397 {
398 canvas.ClipRect(Rect::MakeXYWH(25, 25, 100, 100));
399 // Perform the blend in a SaveLayer so that the initial backdrop color is
400 // fully transparent black. SourceOver blend the result onto the parent
401 // pass.
402 canvas.SaveLayer({});
403 {
404 canvas.DrawPaint({.color = destination_color});
405 // Draw the source color in an offscreen pass and blend it to the parent
406 // pass.
407 canvas.SaveLayer({.blend_mode = blend_mode});
408 { //
409 canvas.DrawRect(Rect::MakeXYWH(25, 25, 100, 100), {.color = color});
410 }
411 canvas.Restore();
412 }
413 canvas.Restore();
414 }
415 canvas.Restore();
416 canvas.Translate(Vector2(100, 0));
417 }
418 canvas.RestoreToCount(0);
419
420 //----------------------------------------------------------------------------
421 /// 2. CPU blend modes (bottom squares).
422 ///
423
424 canvas.Save();
425 canvas.Translate({0, 100});
426 // Perform the blend in a SaveLayer so that the initial backdrop color is
427 // fully transparent black. SourceOver blend the result onto the parent pass.
428 canvas.SaveLayer({});
429 for (const auto& color : source_colors) {
430 // Simply write the CPU blended color to the pass.
431 canvas.DrawRect(Rect::MakeXYWH(25, 25, 100, 100),
432 {.color = destination_color.Blend(color, blend_mode),
433 .blend_mode = BlendMode::kSourceOver});
434 canvas.Translate(Vector2(100, 0));
435 }
436 canvas.Restore();
437 canvas.Restore();
438
439 //----------------------------------------------------------------------------
440 /// 3. Image blending (bottom images).
441 ///
442 /// Compare these results with the images in the Flutter blend mode
443 /// documentation: https://api.flutter.dev/flutter/dart-ui/BlendMode.html
444 ///
445
446 canvas.Translate({0, 250});
447
448 // Draw grid behind the images.
449 canvas.DrawRect(Rect::MakeLTRB(0, 0, 800, 400),
450 {.color = Color::MakeRGBA8(41, 41, 41, 255)});
451 Paint square_paint = {.color = Color::MakeRGBA8(15, 15, 15, 255)};
452 for (int y = 0; y < 400 / 8; y++) {
453 for (int x = 0; x < 800 / 16; x++) {
454 canvas.DrawRect(Rect::MakeXYWH(x * 16 + (y % 2) * 8, y * 8, 8, 8),
455 square_paint);
456 }
457 }
458
459 // Uploaded image source (left image).
460 canvas.Save();
461 canvas.SaveLayer({.blend_mode = BlendMode::kSourceOver});
462 {
463 canvas.DrawImage(dst_image, {0, 0},
464 {
465 .blend_mode = BlendMode::kSourceOver,
466 });
467 canvas.DrawImage(src_image, {0, 0},
468 {
469 .color = Color::White().WithAlpha(src_alpha),
470 .blend_mode = blend_mode,
471 });
472 }
473 canvas.Restore();
474 canvas.Restore();
475
476 // Rendered image source (right image).
477 canvas.Save();
478 canvas.SaveLayer({.blend_mode = BlendMode::kSourceOver});
479 {
480 canvas.DrawImage(dst_image, {400, 0},
481 {.blend_mode = BlendMode::kSourceOver});
482 canvas.SaveLayer({.color = Color::White().WithAlpha(src_alpha),
483 .blend_mode = blend_mode});
484 {
485 canvas.DrawImage(src_image, {400, 0},
486 {.blend_mode = BlendMode::kSourceOver});
487 }
488 canvas.Restore();
489 }
490 canvas.Restore();
491 canvas.Restore();
492
493 return canvas.EndRecordingAsPicture();
494 }
495
496 #define BLEND_MODE_TEST(blend_mode) \
497 TEST_P(AiksTest, BlendMode##blend_mode) { \
498 auto src_image = std::make_shared<Image>( \
499 CreateTextureForFixture("blend_mode_src.png")); \
500 auto dst_image = std::make_shared<Image>( \
501 CreateTextureForFixture("blend_mode_dst.png")); \
502 auto callback = [&](AiksContext& renderer) -> std::optional<Picture> { \
503 return BlendModeTest(GetContentScale(), BlendMode::k##blend_mode, \
504 src_image, dst_image, /*src_alpha=*/1.0); \
505 }; \
506 OpenPlaygroundHere(callback); \
507 }
508 IMPELLER_FOR_EACH_BLEND_MODE(BLEND_MODE_TEST)
509
510 #define BLEND_MODE_SRC_ALPHA_TEST(blend_mode) \
511 TEST_P(AiksTest, BlendModeSrcAlpha##blend_mode) { \
512 auto src_image = std::make_shared<Image>( \
513 CreateTextureForFixture("blend_mode_src.png")); \
514 auto dst_image = std::make_shared<Image>( \
515 CreateTextureForFixture("blend_mode_dst.png")); \
516 auto callback = [&](AiksContext& renderer) -> std::optional<Picture> { \
517 return BlendModeTest(GetContentScale(), BlendMode::k##blend_mode, \
518 src_image, dst_image, /*src_alpha=*/0.5); \
519 }; \
520 OpenPlaygroundHere(callback); \
521 }
522 IMPELLER_FOR_EACH_BLEND_MODE(BLEND_MODE_SRC_ALPHA_TEST)
523
524 TEST_P(AiksTest, CanDrawPaintMultipleTimesInteractive) {
525 auto modes = GetBlendModeSelection();
526
527 auto callback = [&](AiksContext& renderer) -> std::optional<Picture> {
528 static Color background = Color::MediumTurquoise();
529 static Color foreground = Color::Color::OrangeRed().WithAlpha(0.5);
530 static int current_blend_index = 3;
531
532 if (AiksTest::ImGuiBegin("Controls", nullptr,
533 ImGuiWindowFlags_AlwaysAutoResize)) {
534 ImGui::ColorEdit4("Background", reinterpret_cast<float*>(&background));
535 ImGui::ColorEdit4("Foreground", reinterpret_cast<float*>(&foreground));
536 ImGui::ListBox("Blend mode", &current_blend_index,
537 modes.blend_mode_names.data(),
538 modes.blend_mode_names.size());
539 ImGui::End();
540 }
541
542 Canvas canvas;
543 canvas.Scale(Vector2(0.2, 0.2));
544 canvas.DrawPaint({.color = background});
545 canvas.DrawPaint(
546 {.color = foreground,
547 .blend_mode = static_cast<BlendMode>(current_blend_index)});
548 return canvas.EndRecordingAsPicture();
549 };
550 ASSERT_TRUE(OpenPlaygroundHere(callback));
551 }
552
553 TEST_P(AiksTest, ForegroundPipelineBlendAppliesTransformCorrectly) {
554 auto texture = CreateTextureForFixture("airplane.jpg",
555 /*enable_mipmapping=*/true);
556
557 Canvas canvas;
558 canvas.Rotate(Degrees(30));
559 canvas.DrawImage(std::make_shared<Image>(texture), {200, 200},
560 {.color_filter = ColorFilter::MakeBlend(BlendMode::kSourceIn,
561 Color::Orange())});
562
563 ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
564 }
565
566 TEST_P(AiksTest, ForegroundAdvancedBlendAppliesTransformCorrectly) {
567 auto texture = CreateTextureForFixture("airplane.jpg",
568 /*enable_mipmapping=*/true);
569
570 Canvas canvas;
571 canvas.Rotate(Degrees(30));
572 canvas.DrawImage(std::make_shared<Image>(texture), {200, 200},
573 {.color_filter = ColorFilter::MakeBlend(
574 BlendMode::kColorDodge, Color::Orange())});
575
576 ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
577 }
578
579 TEST_P(AiksTest, FramebufferAdvancedBlendCoverage) {
580 auto texture = CreateTextureForFixture("airplane.jpg",
581 /*enable_mipmapping=*/true);
582
583 // Draw with an advanced blend that can use FramebufferBlendContents and
584 // verify that the scale transform is correctly applied to the image.
585 Canvas canvas;
586 canvas.DrawPaint({.color = Color::DarkGray()});
587 canvas.Scale(Vector2(0.4, 0.4));
588 canvas.DrawImage(std::make_shared<Image>(texture), {20, 20},
589 {.blend_mode = BlendMode::kMultiply});
590
591 ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
592 }
593
594 } // namespace testing
595 } // namespace impeller
impeller::Color::Blue
static constexpr Color Blue()
Definition: color.h:278
impeller::AiksPlayground
Definition: aiks_playground.h:17
impeller::Canvas::EndRecordingAsPicture
Picture EndRecordingAsPicture()
Definition: canvas.cc:804
impeller::Scalar
float Scalar
Definition: scalar.h:18
impeller::AiksContext
Definition: aiks_context.h:19
impeller::Canvas::DrawImageRect
void DrawImageRect(const std::shared_ptr< Image > &image, Rect source, Rect dest, const Paint &paint, SamplerDescriptor sampler={}, SourceRectConstraint src_rect_constraint=SourceRectConstraint::kFast)
Definition: canvas.cc:766
BLEND_MODE_TEST
#define BLEND_MODE_TEST(blend_mode)
Definition: aiks_blend_unittests.cc:496
impeller::Color::DarkGray
static constexpr Color DarkGray()
Definition: color.h:372
impeller::PixelFormat::kB10G10R10A10XR
@ kB10G10R10A10XR
impeller::Color::Red
static constexpr Color Red()
Definition: color.h:274
aiks_unittests.h
impeller::ColorSource::MakeLinearGradient
static ColorSource MakeLinearGradient(Point start_point, Point end_point, std::vector< Color > colors, std::vector< Scalar > stops, Entity::TileMode tile_mode, Matrix effect_transform)
Definition: color_source.cc:166
impeller::Paint
Definition: paint.h:23
impeller::TRect< Scalar >::MakeXYWH
constexpr static TRect MakeXYWH(Type x, Type y, Type width, Type height)
Definition: rect.h:136
impeller::BlendMode
BlendMode
Definition: color.h:59
impeller::Color::MakeRGBA8
static constexpr Color MakeRGBA8(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
Definition: color.h:154
impeller::Color
Definition: color.h:124
impeller::Vector4
Definition: vector.h:232
impeller::Paint::color
Color color
Definition: paint.h:68
impeller::BlendMode::kSource
@ kSource
impeller::BlendMode::kColorDodge
@ kColorDodge
impeller::Canvas
Definition: canvas.h:60
impeller::Paint::MaskBlurDescriptor::style
FilterContents::BlurStyle style
Definition: paint.h:49
impeller::Vector2
Point Vector2
Definition: point.h:326
impeller::kPi
constexpr float kPi
Definition: constants.h:26
impeller::BlendMode::kPlus
@ kPlus
impeller::Paint::MaskBlurDescriptor
Definition: paint.h:48
impeller::Color::CornflowerBlue
static constexpr Color CornflowerBlue()
Definition: color.h:344
impeller::Radians::radians
Scalar radians
Definition: scalar.h:39
impeller::FilterContents::BlurStyle::kNormal
@ kNormal
Blurred inside and outside.
impeller::Entity::TileMode::kRepeat
@ kRepeat
impeller::Canvas::DrawRect
void DrawRect(const Rect &rect, const Paint &paint)
Definition: canvas.cc:495
impeller::testing::BlendModeTest
static Picture BlendModeTest(Vector2 content_scale, BlendMode blend_mode, const std::shared_ptr< Image > &src_image, const std::shared_ptr< Image > &dst_image, Scalar src_alpha)
Definition: aiks_blend_unittests.cc:368
impeller::Canvas::DrawImage
void DrawImage(const std::shared_ptr< Image > &image, Point offset, const Paint &paint, SamplerDescriptor sampler={})
Definition: canvas.cc:752
impeller::testing::TEST_P
TEST_P(AiksTest, CanRenderAdvancedBlendColorFilterWithSaveLayer)
Definition: aiks_blend_unittests.cc:21
impeller::BlendMode::kDifference
@ kDifference
impeller::kPhi
constexpr float kPhi
Definition: constants.h:53
impeller::saturated::distance
SI distance
Definition: saturated_math.h:57
impeller::BlendMode::kLighten
@ kLighten
impeller::Picture
Definition: picture.h:17
impeller::Point
TPoint< Scalar > Point
Definition: point.h:322
impeller::k2Pi
constexpr float k2Pi
Definition: constants.h:29
BLEND_MODE_TUPLE
#define BLEND_MODE_TUPLE(blend_mode)
Definition: aiks_blend_unittests.cc:181
impeller::Canvas::Scale
void Scale(const Vector2 &scale)
Definition: canvas.cc:315
impeller::ColorFilter::MakeBlend
static std::shared_ptr< ColorFilter > MakeBlend(BlendMode blend_mode, Color color)
Definition: color_filter.cc:23
impeller::testing::GetBlendModeSelection
static BlendModeSelection GetBlendModeSelection()
Definition: aiks_blend_unittests.cc:188
impeller::Picture::Snapshot
std::optional< Snapshot > Snapshot(AiksContext &context)
Definition: picture.cc:17
impeller::BlendMode::kClear
@ kClear
impeller::Color::WithAlpha
constexpr Color WithAlpha(Scalar new_alpha) const
Definition: color.h:280
impeller::Entity::kLastAdvancedBlendMode
static constexpr BlendMode kLastAdvancedBlendMode
Definition: entity.h:23
impeller::Canvas::DrawCircle
void DrawCircle(const Point &center, Scalar radius, const Paint &paint)
Definition: canvas.cc:566
impeller::Color::White
static constexpr Color White()
Definition: color.h:266
impeller::Sigma
In filters that use Gaussian distributions, "sigma" is a size of one standard deviation in terms of t...
Definition: sigma.h:32
impeller::Canvas::Restore
virtual bool Restore()
Definition: canvas.cc:257
impeller::Radians
Definition: scalar.h:38
canvas.h
impeller::Color::Green
static constexpr Color Green()
Definition: color.h:276
impeller::Canvas::DrawPaint
void DrawPaint(const Paint &paint)
Definition: canvas.cc:352
impeller::testing::BlendModeSelection
Definition: aiks_blend_unittests.cc:183
IMPELLER_FOR_EACH_BLEND_MODE
#define IMPELLER_FOR_EACH_BLEND_MODE(V)
Definition: color.h:19
scalar.h
impeller::Color::MediumTurquoise
static constexpr Color MediumTurquoise()
Definition: color.h:648
impeller::Canvas::Rotate
void Rotate(Radians radians)
Definition: canvas.cc:327
impeller::Color::Orange
static constexpr Color Orange()
Definition: color.h:692
impeller::TRect< Scalar >::MakeSize
constexpr static TRect MakeSize(const TSize< U > &size)
Definition: rect.h:146
impeller::TPoint< Scalar >
impeller::Canvas::Transform
void Transform(const Matrix &transform)
Definition: canvas.cc:294
impeller::Color::Black
static constexpr Color Black()
Definition: color.h:268
impeller::Canvas::Save
virtual void Save(uint32_t total_content_depth=kMaxDepth)
Definition: canvas.cc:184
impeller::BlendMode::kSourceIn
@ kSourceIn
impeller::testing::BlendModeSelection::blend_mode_values
std::vector< BlendMode > blend_mode_values
Definition: aiks_blend_unittests.cc:185
impeller::BlendMode::kScreen
@ kScreen
paint
const Paint & paint
Definition: color_source.cc:38
impeller::AiksPlayground::ImGuiBegin
static bool ImGuiBegin(const char *name, bool *p_open, ImGuiWindowFlags flags)
Definition: aiks_playground.cc:69
impeller::Degrees
Definition: scalar.h:46
color.h
impeller::Color::LimeGreen
static constexpr Color LimeGreen()
Definition: color.h:604
color_filter.h
color
DlColor color
Definition: dl_golden_blur_unittests.cc:23
impeller::BlendMode::kHue
@ kHue
impeller::Canvas::ClipRect
void ClipRect(const Rect &rect, Entity::ClipOperation clip_op=Entity::ClipOperation::kIntersect)
Definition: canvas.cc:599
impeller::TRect< Scalar >::MakeLTRB
constexpr static TRect MakeLTRB(Type left, Type top, Type right, Type bottom)
Definition: rect.h:129
impeller::testing::BlendModeSelection::blend_mode_names
std::vector< const char * > blend_mode_names
Definition: aiks_blend_unittests.cc:184
impeller
Definition: aiks_blend_unittests.cc:18
BLEND_MODE_SRC_ALPHA_TEST
#define BLEND_MODE_SRC_ALPHA_TEST(blend_mode)
Definition: aiks_blend_unittests.cc:510
impeller::Matrix::MakeScale
static constexpr Matrix MakeScale(const Vector3 &s)
Definition: matrix.h:104
impeller::BlendMode::kMultiply
@ kMultiply
impeller::Canvas::SaveLayer
virtual void SaveLayer(const Paint &paint, std::optional< Rect > bounds=std::nullopt, const std::shared_ptr< ImageFilter > &backdrop_filter=nullptr, ContentBoundsPromise bounds_promise=ContentBoundsPromise::kUnknown, uint32_t total_content_depth=kMaxDepth, bool can_distribute_opacity=false)
Definition: canvas.cc:842
impeller::TRect
Definition: rect.h:122
impeller::Matrix
A 4x4 matrix using column-major storage.
Definition: matrix.h:37
impeller::Vector3
Definition: vector.h:20
impeller::BlendMode::kSourceOver
@ kSourceOver
impeller::Paint::blend_mode
BlendMode blend_mode
Definition: paint.h:76
impeller::TRect::Expand
constexpr TRect< T > Expand(T left, T top, T right, T bottom) const
Returns a rectangle with expanded edges. Negative expansion results in shrinking.
Definition: rect.h:605
impeller::TPoint< Scalar >::MakeXY
static constexpr TPoint< Type > MakeXY(Type x, Type y)
Definition: point.h:46
impeller::Canvas::Translate
void Translate(const Vector3 &offset)
Definition: canvas.cc:311
impeller::Color::Blend
Color Blend(Color source, BlendMode blend_mode) const
Blends an unpremultiplied destination color into a given unpremultiplied source color to form a new u...
Definition: color.cc:234