7 #include "display_list/display_list.h"
8 #include "display_list/dl_sampling_options.h"
9 #include "display_list/dl_tile_mode.h"
10 #include "display_list/effects/dl_color_filter.h"
11 #include "display_list/effects/dl_color_source.h"
12 #include "display_list/effects/dl_mask_filter.h"
15 #include "flutter/display_list/dl_blend_mode.h"
16 #include "flutter/display_list/dl_builder.h"
17 #include "flutter/display_list/dl_color.h"
18 #include "flutter/display_list/dl_paint.h"
25 #include "impeller/renderer/testing/mocks.h"
26 #include "include/core/SkMatrix.h"
38 #define BLEND_MODE_TUPLE(blend_mode) {#blend_mode, BlendMode::k##blend_mode},
46 std::vector<const char*> blend_mode_names;
47 std::vector<BlendMode> blend_mode_values;
49 const std::vector<std::tuple<const char*, BlendMode>> blends = {
51 assert(blends.size() ==
53 for (
const auto& [name, mode] : blends) {
54 blend_mode_names.push_back(name);
55 blend_mode_values.push_back(mode);
59 return {blend_mode_names, blend_mode_values};
63 DisplayListBuilder builder;
65 SkRect layer_rect = SkRect::MakeXYWH(0, 0, 500, 500);
66 builder.ClipRect(layer_rect);
69 save_paint.setColorFilter(DlBlendColorFilter::Make(
70 DlColor::RGBA(0, 1, 0, 0.5), DlBlendMode::kDifference));
71 builder.SaveLayer(&layer_rect, &save_paint);
74 paint.setColor(DlColor::kBlack());
75 builder.DrawPaint(paint);
76 paint.setColor(DlColor::kWhite());
77 builder.DrawRect(SkRect::MakeXYWH(100, 100, 300, 300), paint);
80 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
84 DisplayListBuilder builder;
87 paint.setColor(DlColor::kRed());
88 builder.DrawPaint(paint);
90 paint.setBlendMode(DlBlendMode::kSrcOver);
91 builder.SaveLayer(
nullptr, &paint);
93 paint.setColor(DlColor::kWhite());
94 builder.DrawRect(SkRect::MakeXYWH(100, 100, 400, 400), paint);
96 paint.setBlendMode(DlBlendMode::kSrc);
97 builder.SaveLayer(
nullptr, &paint);
99 paint.setColor(DlColor::kBlue());
100 builder.DrawRect(SkRect::MakeXYWH(200, 200, 200, 200), paint);
105 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
109 DisplayListBuilder builder;
111 builder.Scale(0.2, 0.2);
113 paint.setColor(DlColor::RGBA(
116 builder.DrawPaint(paint);
120 paint.setBlendMode(DlBlendMode::kHue);
121 builder.DrawPaint(paint);
123 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
128 paint.setColor(DlColor::kBlack());
129 paint.setMaskFilter(DlBlurMaskFilter::Make(DlBlurStyle::kNormal, 60));
131 DisplayListBuilder builder;
132 paint.setColor(DlColor::kWhite());
133 builder.DrawPaint(paint);
134 paint.setColor(DlColor::kBlack());
135 builder.DrawCircle({300, 300}, 200, paint);
136 paint.setColor(DlColor::kGreen());
137 paint.setBlendMode(DlBlendMode::kScreen);
138 builder.DrawPaint(paint);
140 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
144 DisplayListBuilder builder;
147 draw_paint.setColor(DlColor::kBlue());
148 builder.DrawPaint(draw_paint);
150 builder.ClipRect(SkRect::MakeLTRB(0, 0, 200, 200));
152 std::vector<DlColor> colors = {DlColor::RGBA(0.9568, 0.2627, 0.2118, 1.0),
153 DlColor::RGBA(0.1294, 0.5882, 0.9529, 1.0)};
154 std::vector<Scalar> stops = {0.0, 1.0};
157 SkMatrix matrix = SkMatrix::Scale(0.3, 0.3);
158 paint.setColorSource(DlColorSource::MakeLinear(
167 paint.setBlendMode(DlBlendMode::kLighten);
169 builder.DrawCircle({100, 100}, 100, paint);
170 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
175 DisplayListBuilder builder;
178 paint.setColor(DlColor::RGBA(1, 0, 0, 0.5));
179 builder.DrawCircle({150, 200}, 100, paint);
181 paint.setColor(DlColor::RGBA(0, 1, 0, 0.5));
182 builder.DrawCircle({250, 200}, 100, paint);
184 paint.setBlendMode(DlBlendMode::kPlus);
186 paint.setColor(DlColor::kRed());
187 builder.DrawCircle({450, 250}, 100, paint);
189 paint.setColor(DlColor::kGreen());
190 builder.DrawCircle({550, 250}, 100, paint);
192 paint.setColor(DlColor::kBlue());
193 builder.DrawCircle({500, 150}, 100, paint);
195 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
200 bool has_color_filter =
true;
201 auto callback = [&]() -> sk_sp<DisplayList> {
203 ImGuiWindowFlags_AlwaysAutoResize)) {
204 ImGui::Checkbox(
"has color filter", &has_color_filter);
208 DisplayListBuilder builder;
209 builder.Scale(GetContentScale().x, GetContentScale().y);
216 std::vector<DlBlendMode> blend_modes = {
217 DlBlendMode::kSrc, DlBlendMode::kSrcATop, DlBlendMode::kSrcOver,
218 DlBlendMode::kSrcIn, DlBlendMode::kSrcOut, DlBlendMode::kDst,
219 DlBlendMode::kDstATop, DlBlendMode::kDstOver, DlBlendMode::kDstIn,
220 DlBlendMode::kDstOut, DlBlendMode::kClear, DlBlendMode::kXor};
222 for (uint32_t i = 0; i < blend_modes.size(); ++i) {
224 builder.Translate((i % 5) * 200, (i / 5) * 200);
225 builder.Scale(0.4, 0.4);
228 builder.DrawImage(dst_image, {0, 0}, DlImageSampling::kMipmapLinear,
233 srcPaint.setBlendMode(blend_modes[i]);
234 if (has_color_filter) {
235 std::shared_ptr<const DlColorFilter> color_filter =
236 DlBlendColorFilter::Make(DlColor::RGBA(0.9, 0.5, 0.0, 1.0),
237 DlBlendMode::kSrcIn);
238 srcPaint.setColorFilter(color_filter);
240 builder.DrawImage(src_image, {0, 0}, DlImageSampling::kMipmapLinear,
245 return builder.Build();
247 ASSERT_TRUE(OpenPlaygroundHere(callback));
252 bool has_color_filter =
true;
253 auto callback = [&]() -> sk_sp<DisplayList> {
255 ImGuiWindowFlags_AlwaysAutoResize)) {
256 ImGui::Checkbox(
"has color filter", &has_color_filter);
260 DisplayListBuilder builder;
261 builder.Scale(GetContentScale().x, GetContentScale().y);
268 std::vector<DlBlendMode> blend_modes = {
269 DlBlendMode::kScreen, DlBlendMode::kOverlay,
270 DlBlendMode::kDarken, DlBlendMode::kLighten,
271 DlBlendMode::kColorDodge, DlBlendMode::kColorBurn,
272 DlBlendMode::kHardLight, DlBlendMode::kSoftLight,
273 DlBlendMode::kDifference, DlBlendMode::kExclusion,
274 DlBlendMode::kMultiply, DlBlendMode::kHue,
275 DlBlendMode::kSaturation, DlBlendMode::kColor,
276 DlBlendMode::kLuminosity,
279 for (uint32_t i = 0; i < blend_modes.size(); ++i) {
281 builder.Translate((i % 5) * 200, (i / 5) * 200);
282 builder.Scale(0.4, 0.4);
285 builder.DrawImage(dst_image, {0, 0}, DlImageSampling::kMipmapLinear,
290 srcPaint.setBlendMode(blend_modes[i]);
291 if (has_color_filter) {
292 std::shared_ptr<const DlColorFilter> color_filter =
293 DlBlendColorFilter::Make(DlColor::RGBA(0.9, 0.5, 0.0, 1.0),
294 DlBlendMode::kSrcIn);
295 srcPaint.setColorFilter(color_filter);
297 builder.DrawImage(src_image, {0, 0}, DlImageSampling::kMipmapLinear,
302 return builder.Build();
304 ASSERT_TRUE(OpenPlaygroundHere(callback));
313 <<
"This backend doesn't yet support setting device capabilities.";
315 if (!WillRenderSomething()) {
316 GTEST_SKIP() <<
"This test requires playgrounds.";
319 std::shared_ptr<const Capabilities> old_capabilities =
320 GetContext()->GetCapabilities();
321 auto mock_capabilities = std::make_shared<MockCapabilities>();
322 EXPECT_CALL(*mock_capabilities, SupportsFramebufferFetch())
323 .Times(::testing::AtLeast(1))
324 .WillRepeatedly(::testing::Return(
false));
325 FLT_FORWARD(mock_capabilities, old_capabilities, GetDefaultColorFormat);
326 FLT_FORWARD(mock_capabilities, old_capabilities, GetDefaultStencilFormat);
327 FLT_FORWARD(mock_capabilities, old_capabilities,
328 GetDefaultDepthStencilFormat);
329 FLT_FORWARD(mock_capabilities, old_capabilities, SupportsOffscreenMSAA);
330 FLT_FORWARD(mock_capabilities, old_capabilities,
331 SupportsImplicitResolvingMSAA);
332 FLT_FORWARD(mock_capabilities, old_capabilities, SupportsReadFromResolve);
333 FLT_FORWARD(mock_capabilities, old_capabilities, SupportsSSBO);
334 FLT_FORWARD(mock_capabilities, old_capabilities, SupportsCompute);
335 FLT_FORWARD(mock_capabilities, old_capabilities,
336 SupportsTextureToTextureBlits);
337 FLT_FORWARD(mock_capabilities, old_capabilities, GetDefaultGlyphAtlasFormat);
338 FLT_FORWARD(mock_capabilities, old_capabilities, SupportsTriangleFan);
339 FLT_FORWARD(mock_capabilities, old_capabilities,
340 SupportsDecalSamplerAddressMode);
341 ASSERT_TRUE(SetCapabilities(mock_capabilities).ok());
343 bool has_color_filter =
true;
344 auto callback = [&]() -> sk_sp<DisplayList> {
346 ImGuiWindowFlags_AlwaysAutoResize)) {
347 ImGui::Checkbox(
"has color filter", &has_color_filter);
351 DisplayListBuilder builder;
352 builder.Scale(GetContentScale().x, GetContentScale().y);
359 std::vector<DlBlendMode> blend_modes = {
360 DlBlendMode::kScreen, DlBlendMode::kOverlay,
361 DlBlendMode::kDarken, DlBlendMode::kLighten,
362 DlBlendMode::kColorDodge, DlBlendMode::kColorBurn,
363 DlBlendMode::kHardLight, DlBlendMode::kSoftLight,
364 DlBlendMode::kDifference, DlBlendMode::kExclusion,
365 DlBlendMode::kMultiply, DlBlendMode::kHue,
366 DlBlendMode::kSaturation, DlBlendMode::kColor,
367 DlBlendMode::kLuminosity,
370 for (uint32_t i = 0; i < blend_modes.size(); ++i) {
372 builder.Translate((i % 5) * 200, (i / 5) * 200);
373 builder.Scale(0.4, 0.4);
376 builder.DrawImage(dst_image, {0, 0}, DlImageSampling::kMipmapLinear,
381 srcPaint.setBlendMode(blend_modes[i]);
382 if (has_color_filter) {
383 std::shared_ptr<const DlColorFilter> color_filter =
384 DlBlendColorFilter::Make(DlColor::RGBA(0.9, 0.5, 0.0, 1.0),
385 DlBlendMode::kMultiply);
386 srcPaint.setColorFilter(color_filter);
388 builder.DrawImage(src_image, {0, 0}, DlImageSampling::kMipmapLinear,
393 return builder.Build();
395 ASSERT_TRUE(OpenPlaygroundHere(callback));
400 EXPECT_EQ(GetContext()->GetCapabilities()->GetDefaultColorFormat(),
402 auto texture = CreateTextureForFixture(
"airplane.jpg",
405 DisplayListBuilder builder;
407 builder.Scale(GetContentScale().x, GetContentScale().y);
409 paint.setColor(DlColor::RGBA(0.9, 1, 0.9, 1.0));
410 builder.DrawPaint(paint);
411 builder.SaveLayer(
nullptr);
413 paint.setBlendMode(DlBlendMode::kPlus);
414 paint.setColor(DlColor::kRed());
416 builder.DrawRect(SkRect::MakeXYWH(100, 100, 400, 400), paint);
417 paint.setColor(DlColor::kWhite());
420 builder.DrawImageRect(
423 SkSize::Make(texture->GetSize().width, texture->GetSize().height)),
424 SkRect::MakeLTRB(rect.GetLeft(), rect.GetTop(), rect.GetRight(),
426 DlImageSampling::kMipmapLinear, &paint);
428 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
433 EXPECT_EQ(GetContext()->GetCapabilities()->GetDefaultColorFormat(),
435 auto texture = CreateTextureForFixture(
"airplane.jpg",
438 DisplayListBuilder builder;
439 builder.Scale(GetContentScale().x, GetContentScale().y);
442 paint.setColor(DlColor::RGBA(0.1, 0.2, 0.1, 1.0));
443 builder.DrawPaint(paint);
446 save_paint.setColorFilter(
447 DlBlendColorFilter::Make(DlColor::RGBA(1, 0, 0, 1), DlBlendMode::kPlus));
448 builder.SaveLayer(
nullptr, &save_paint);
450 paint.setColor(DlColor::kRed());
451 builder.DrawRect(SkRect::MakeXYWH(100, 100, 400, 400), paint);
453 paint.setColor(DlColor::kWhite());
456 builder.DrawImageRect(
459 SkSize::Make(texture->GetSize().width, texture->GetSize().height)),
460 SkRect::MakeLTRB(rect.GetLeft(), rect.GetTop(), rect.GetRight(),
462 DlImageSampling::kMipmapLinear, &paint);
465 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
469 DisplayListBuilder builder;
472 save_paint.setColorFilter(
473 DlBlendColorFilter::Make(DlColor::kRed(), DlBlendMode::kColorDodge));
474 builder.SaveLayer(
nullptr, &save_paint);
476 builder.Translate(500, 300);
480 paint.setColor(DlColor::kBlue());
481 builder.DrawRect(SkRect::MakeXYWH(100, 100, 200, 200), paint);
483 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
487 DisplayListBuilder builder;
490 blue.setColor(DlColor::kBlue());
491 builder.DrawRect(SkRect::MakeXYWH(0, 0, 600.0, 600.0), blue);
494 clear.setBlendMode(DlBlendMode::kClear);
496 builder.DrawCircle({300.0, 300.0}, 200.0, clear);
498 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
503 const sk_sp<DlImageImpeller>& src_image,
504 const sk_sp<DlImageImpeller>& dst_image,
507 ImGuiWindowFlags_AlwaysAutoResize)) {
508 ImGui::SliderFloat(
"Source alpha", &src_alpha, 0, 1);
517 DisplayListBuilder builder;
520 paint.setColor(DlColor::kBlack());
521 builder.DrawPaint(paint);
532 for (
const auto&
color : source_colors) {
535 builder.ClipRect(SkRect::MakeXYWH(25, 25, 100, 100));
539 builder.SaveLayer({});
543 DlColor::RGBA(destination_color.
red, destination_color.
green,
544 destination_color.
blue, destination_color.
alpha));
545 builder.DrawPaint(draw_paint);
550 save_paint.setBlendMode(
static_cast<DlBlendMode
>(blend_mode));
551 builder.SaveLayer(
nullptr, &save_paint);
556 builder.DrawRect(SkRect::MakeXYWH(25, 25, 100, 100), paint);
563 builder.Translate(100, 0);
565 builder.RestoreToCount(0);
572 builder.Translate(0, 100);
575 builder.SaveLayer({});
576 for (
const auto&
color : source_colors) {
579 auto dest = destination_color.
Blend(
color, blend_mode);
580 paint.setColor(DlColor::RGBA(dest.red, dest.green, dest.blue, dest.alpha));
581 paint.setBlendMode(DlBlendMode::kSrcOver);
582 builder.DrawRect(SkRect::MakeXYWH(25, 25, 100, 100), paint);
583 builder.Translate(100, 0);
595 builder.Translate(0, 250);
600 paint.setColor(DlColor::RGBA(41 / 255.0, 41 / 255.0, 41 / 255.0, 1));
601 builder.DrawRect(SkRect::MakeLTRB(0, 0, 800, 400), paint);
604 DlPaint square_paint;
605 square_paint.setColor(DlColor::RGBA(15 / 255.0, 15 / 255.0, 15 / 255.0, 1));
606 for (
int y = 0; y < 400 / 8; y++) {
607 for (
int x = 0; x < 800 / 16; x++) {
608 builder.DrawRect(SkRect::MakeXYWH(x * 16 + (y % 2) * 8, y * 8, 8, 8),
615 paint.setBlendMode(DlBlendMode::kSrcOver);
617 builder.SaveLayer(
nullptr, &paint);
619 builder.DrawImage(dst_image, {0, 0}, DlImageSampling::kMipmapLinear,
622 paint.setColor(DlColor::kWhite().withAlpha(src_alpha * 255));
623 paint.setBlendMode(
static_cast<DlBlendMode
>(blend_mode));
624 builder.DrawImage(src_image, {0, 0}, DlImageSampling::kMipmapLinear,
634 builder.SaveLayer(
nullptr, &save_paint);
636 builder.DrawImage(dst_image, {400, 0}, DlImageSampling::kMipmapLinear,
640 save_paint.setColor(DlColor::kWhite().withAlpha(src_alpha * 255));
641 save_paint.setBlendMode(
static_cast<DlBlendMode
>(blend_mode));
642 builder.SaveLayer(
nullptr, &save_paint);
644 builder.DrawImage(src_image, {400, 0}, DlImageSampling::kMipmapLinear,
652 return builder.Build();
655 #define BLEND_MODE_TEST(blend_mode) \
656 TEST_P(AiksTest, BlendMode##blend_mode) { \
658 DlImageImpeller::Make(CreateTextureForFixture("blend_mode_src.png")); \
660 DlImageImpeller::Make(CreateTextureForFixture("blend_mode_dst.png")); \
661 auto callback = [&]() -> sk_sp<DisplayList> { \
662 return BlendModeTest(GetContentScale(), BlendMode::k##blend_mode, \
663 src_image, dst_image, 1.0); \
665 OpenPlaygroundHere(callback); \
669 #define BLEND_MODE_SRC_ALPHA_TEST(blend_mode) \
670 TEST_P(AiksTest, BlendModeSrcAlpha##blend_mode) { \
672 DlImageImpeller::Make(CreateTextureForFixture("blend_mode_src.png")); \
674 DlImageImpeller::Make(CreateTextureForFixture("blend_mode_dst.png")); \
675 auto callback = [&]() -> sk_sp<DisplayList> { \
676 return BlendModeTest(GetContentScale(), BlendMode::k##blend_mode, \
677 src_image, dst_image, 0.5); \
679 OpenPlaygroundHere(callback); \
686 auto callback = [&]() -> sk_sp<DisplayList> {
688 static Color foreground = Color::Color::OrangeRed().
WithAlpha(0.5);
689 static int current_blend_index = 3;
692 ImGuiWindowFlags_AlwaysAutoResize)) {
693 ImGui::ColorEdit4(
"Background",
reinterpret_cast<float*
>(&background));
694 ImGui::ColorEdit4(
"Foreground",
reinterpret_cast<float*
>(&foreground));
695 ImGui::ListBox(
"Blend mode", ¤t_blend_index,
696 modes.blend_mode_names.data(),
697 modes.blend_mode_names.size());
701 DisplayListBuilder builder;
702 builder.Scale(0.2, 0.2);
704 paint.setColor(DlColor(background.
ToARGB()));
705 builder.DrawPaint(paint);
707 paint.setColor(DlColor(foreground.
ToARGB()));
708 paint.setBlendMode(
static_cast<DlBlendMode
>(current_blend_index));
709 builder.DrawPaint(paint);
710 return builder.Build();
712 ASSERT_TRUE(OpenPlaygroundHere(callback));
716 auto texture = CreateTextureForFixture(
"airplane.jpg",
719 DisplayListBuilder builder;
723 image_paint.setColorFilter(DlBlendColorFilter::Make(
724 DlColor::RGBA(255.0f / 255.0f, 165.0f / 255.0f, 0.0f / 255.0f, 1.0f),
725 DlBlendMode::kSrcIn));
728 DlImageSampling::kMipmapLinear, &image_paint);
730 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
734 auto texture = CreateTextureForFixture(
"airplane.jpg",
737 DisplayListBuilder builder;
741 image_paint.setColorFilter(DlBlendColorFilter::Make(
742 DlColor::RGBA(255.0f / 255.0f, 165.0f / 255.0f, 0.0f / 255.0f, 1.0f),
743 DlBlendMode::kColorDodge));
746 DlImageSampling::kMipmapLinear, &image_paint);
748 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
752 auto texture = CreateTextureForFixture(
"airplane.jpg",
757 DisplayListBuilder builder;
761 DlColor::RGBA(169.0f / 255.0f, 169.0f / 255.0f, 169.0f / 255.0f, 1.0f));
762 builder.DrawPaint(paint);
763 builder.Scale(0.4, 0.4);
766 image_paint.setBlendMode(DlBlendMode::kMultiply);
769 DlImageSampling::kMipmapLinear, &image_paint);
771 ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
779 auto draw_color_wheel = [](DisplayListBuilder& builder) ->
void {
782 auto color_wheel_sampler = [](
Radians r) {
786 auto color_cycle = [](
Scalar x) {
787 Scalar cycle = std::fmod(x, 6.0f);
788 return std::max(0.0f, std::min(1.0f, 2 - std::abs(2 - cycle)));
790 return Color(color_cycle(6 * x + 1),
791 color_cycle(6 * x - 1),
792 color_cycle(6 * x - 3),
797 paint.setBlendMode(DlBlendMode::kSrcOver);
801 const int max_dist = 900;
802 for (
int i = 0; i <= 900; i++) {
805 Scalar normalized_distance =
static_cast<Scalar>(i) / max_dist;
807 auto color = color_wheel_sampler(r).WithAlpha(1.0f - normalized_distance);
813 builder.DrawCircle(position, 9 + normalized_distance * 3, paint);
817 auto callback = [&]() -> sk_sp<DisplayList> {
819 static bool cache_the_wheel =
true;
820 static int current_blend_index = 3;
821 static float dst_alpha = 1;
822 static float src_alpha = 1;
823 static DlColor color0 = DlColor::kRed();
824 static DlColor color1 = DlColor::kGreen();
825 static DlColor color2 = DlColor::kBlue();
828 ImGuiWindowFlags_AlwaysAutoResize)) {
829 ImGui::Checkbox(
"Cache the wheel", &cache_the_wheel);
830 ImGui::ListBox(
"Blending mode", ¤t_blend_index,
833 ImGui::SliderFloat(
"Source alpha", &src_alpha, 0, 1);
834 ImGui::ColorEdit4(
"Color A",
reinterpret_cast<float*
>(&color0));
835 ImGui::ColorEdit4(
"Color B",
reinterpret_cast<float*
>(&color1));
836 ImGui::ColorEdit4(
"Color C",
reinterpret_cast<float*
>(&color2));
837 ImGui::SliderFloat(
"Destination alpha", &dst_alpha, 0, 1);
841 DisplayListBuilder builder;
844 paint.setColor(DlColor::kWhite().withAlpha(dst_alpha * 255));
845 paint.setBlendMode(DlBlendMode::kSrc);
846 builder.SaveLayer(
nullptr, &paint);
849 paint.setColor(DlColor::kWhite());
850 builder.DrawPaint(paint);
852 builder.SaveLayer(
nullptr,
nullptr);
853 builder.Scale(GetContentScale().x, GetContentScale().y);
854 builder.Translate(500, 400);
856 draw_color_wheel(builder);
861 builder.Scale(GetContentScale().x, GetContentScale().y);
862 builder.Translate(500, 400);
867 save_paint.setColor(DlColor::kWhite().withAlpha(src_alpha * 255));
868 save_paint.setBlendMode(
static_cast<DlBlendMode
>(
870 builder.SaveLayer(
nullptr, &save_paint);
873 paint.setBlendMode(DlBlendMode::kPlus);
876 paint.setColor(color0);
877 builder.DrawCircle(SkPoint::Make(-x * 45, y * 45), 65, paint);
878 paint.setColor(color1);
879 builder.DrawCircle(SkPoint::Make(0, -45), 65, paint);
880 paint.setColor(color2);
881 builder.DrawCircle(SkPoint::Make(x * 45, y * 45), 65, paint);
885 return builder.Build();
888 ASSERT_TRUE(OpenPlaygroundHere(callback));