diff --git a/DEPS b/DEPS index a733e5eccc6bb..497b39c181383 100644 --- a/DEPS +++ b/DEPS @@ -110,7 +110,7 @@ deps = { 'src': 'https://github.com/flutter/buildroot.git' + '@' + '8cbf38af7d48cc298ae86e614533b4b2d0dc6758', 'src/flutter/impeller': - Var('github_git') + '/flutter/impeller' + '@' + 'c54ddfab21691cf5693c15a4f84d9156fb7d8cfb', + Var('github_git') + '/flutter/impeller' + '@' + 'c1572a3335c4a533dacc28b86cbebdf08b5a57ed', # Fuchsia compatibility # diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 125d1df923d3d..ec97bcaaab02e 100755 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -37,6 +37,7 @@ FILE: ../../../flutter/common/task_runners.h FILE: ../../../flutter/display_list/display_list.cc FILE: ../../../flutter/display_list/display_list.h FILE: ../../../flutter/display_list/display_list_attributes.h +FILE: ../../../flutter/display_list/display_list_attributes_testing.h FILE: ../../../flutter/display_list/display_list_benchmarks.cc FILE: ../../../flutter/display_list/display_list_benchmarks.h FILE: ../../../flutter/display_list/display_list_benchmarks_canvas_provider.h @@ -56,6 +57,9 @@ FILE: ../../../flutter/display_list/display_list_canvas_unittests.cc FILE: ../../../flutter/display_list/display_list_color_filter.cc FILE: ../../../flutter/display_list/display_list_color_filter.h FILE: ../../../flutter/display_list/display_list_color_filter_unittests.cc +FILE: ../../../flutter/display_list/display_list_color_source.cc +FILE: ../../../flutter/display_list/display_list_color_source.h +FILE: ../../../flutter/display_list/display_list_color_source_unittests.cc FILE: ../../../flutter/display_list/display_list_comparable.h FILE: ../../../flutter/display_list/display_list_complexity.cc FILE: ../../../flutter/display_list/display_list_complexity.h @@ -67,6 +71,7 @@ FILE: ../../../flutter/display_list/display_list_complexity_metal.h FILE: ../../../flutter/display_list/display_list_complexity_unittests.cc FILE: ../../../flutter/display_list/display_list_dispatcher.cc FILE: ../../../flutter/display_list/display_list_dispatcher.h +FILE: ../../../flutter/display_list/display_list_enum_unittests.cc FILE: ../../../flutter/display_list/display_list_flags.cc FILE: ../../../flutter/display_list/display_list_flags.h FILE: ../../../flutter/display_list/display_list_mask_filter.cc @@ -76,6 +81,7 @@ FILE: ../../../flutter/display_list/display_list_ops.cc FILE: ../../../flutter/display_list/display_list_ops.h FILE: ../../../flutter/display_list/display_list_test_utils.cc FILE: ../../../flutter/display_list/display_list_test_utils.h +FILE: ../../../flutter/display_list/display_list_tile_mode.h FILE: ../../../flutter/display_list/display_list_unittests.cc FILE: ../../../flutter/display_list/display_list_utils.cc FILE: ../../../flutter/display_list/display_list_utils.h diff --git a/display_list/BUILD.gn b/display_list/BUILD.gn index 3ee2f2abed4bb..599719068a3a4 100644 --- a/display_list/BUILD.gn +++ b/display_list/BUILD.gn @@ -17,6 +17,8 @@ source_set("display_list") { "display_list_canvas_recorder.h", "display_list_color_filter.cc", "display_list_color_filter.h", + "display_list_color_source.cc", + "display_list_color_source.h", "display_list_complexity.cc", "display_list_complexity.h", "display_list_complexity_gl.cc", @@ -31,6 +33,7 @@ source_set("display_list") { "display_list_mask_filter.h", "display_list_ops.cc", "display_list_ops.h", + "display_list_tile_mode.h", "display_list_utils.cc", "display_list_utils.h", "types.h", @@ -48,9 +51,12 @@ source_set("unittests") { testonly = true sources = [ + "display_list_attributes_testing.h", "display_list_canvas_unittests.cc", "display_list_color_filter_unittests.cc", + "display_list_color_source_unittests.cc", "display_list_complexity_unittests.cc", + "display_list_enum_unittests.cc", "display_list_mask_filter_unittests.cc", "display_list_test_utils.cc", "display_list_test_utils.h", diff --git a/display_list/display_list.h b/display_list/display_list.h index a2d426548f7bd..713f3000c0fe5 100644 --- a/display_list/display_list.h +++ b/display_list/display_list.h @@ -74,19 +74,22 @@ namespace flutter { \ V(SetBlender) \ V(ClearBlender) \ - V(SetShader) \ - V(ClearShader) \ V(SetImageFilter) \ V(ClearImageFilter) \ V(SetPathEffect) \ V(ClearPathEffect) \ \ V(ClearColorFilter) \ - V(SetColorFilter) \ + V(SetPodColorFilter) \ V(SetSkColorFilter) \ \ + V(ClearColorSource) \ + V(SetPodColorSource) \ + V(SetSkColorSource) \ + V(SetImageColorSource) \ + \ V(ClearMaskFilter) \ - V(SetMaskFilter) \ + V(SetPodMaskFilter) \ V(SetSkMaskFilter) \ \ V(Save) \ diff --git a/display_list/display_list_attributes_testing.h b/display_list/display_list_attributes_testing.h new file mode 100644 index 0000000000000..b025a607e6a07 --- /dev/null +++ b/display_list/display_list_attributes_testing.h @@ -0,0 +1,42 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_DISPLAY_LIST_DISPLAY_LIST_ATTRIBUTES_TESTING_H_ +#define FLUTTER_DISPLAY_LIST_DISPLAY_LIST_ATTRIBUTES_TESTING_H_ + +#include "flutter/display_list/display_list_attributes.h" +#include "flutter/display_list/display_list_comparable.h" +#include "gtest/gtest.h" + +namespace flutter { +namespace testing { + +template +static void TestEquals(T& source1, T& source2) { + ASSERT_TRUE(source1 == source2); + ASSERT_TRUE(source2 == source1); + ASSERT_FALSE(source1 != source2); + ASSERT_FALSE(source2 != source1); + ASSERT_EQ(source1, source2); + ASSERT_EQ(source2, source1); + ASSERT_TRUE(Equals(&source1, &source2)); + ASSERT_TRUE(Equals(source1.shared(), source2.shared())); +} + +template +static void TestNotEquals(T& source1, T& source2, std::string label) { + ASSERT_FALSE(source1 == source2) << label; + ASSERT_FALSE(source2 == source1) << label; + ASSERT_TRUE(source1 != source2) << label; + ASSERT_TRUE(source2 != source1) << label; + ASSERT_NE(source1, source2) << label; + ASSERT_NE(source2, source1) << label; + ASSERT_TRUE(NotEquals(&source1, &source2)); + ASSERT_TRUE(NotEquals(source1.shared(), source2.shared())); +} + +} // namespace testing +} // namespace flutter + +#endif // FLUTTER_DISPLAY_LIST_DISPLAY_LIST_ATTRIBUTES_TESTING_H_ diff --git a/display_list/display_list_builder.cc b/display_list/display_list_builder.cc index 79fe3450b71ff..0a1c4fb123d1b 100644 --- a/display_list/display_list_builder.cc +++ b/display_list/display_list_builder.cc @@ -124,10 +124,59 @@ void DisplayListBuilder::onSetBlender(sk_sp blender) { UpdateCurrentOpacityCompatibility(); } } -void DisplayListBuilder::onSetShader(sk_sp shader) { - (current_shader_ = shader) // - ? Push(0, 0, std::move(shader)) - : Push(0, 0); +void DisplayListBuilder::onSetColorSource(const DlColorSource* source) { + if (source == nullptr) { + current_color_source_ = nullptr; + Push(0, 0); + } else { + current_color_source_ = source->shared(); + switch (source->type()) { + case DlColorSourceType::kColor: { + const DlColorColorSource* color_source = source->asColor(); + current_color_source_ = nullptr; + setColor(color_source->color()); + break; + } + case DlColorSourceType::kImage: { + const DlImageColorSource* image_source = source->asImage(); + FML_DCHECK(image_source); + Push(0, 0, image_source); + break; + } + case DlColorSourceType::kLinearGradient: { + const DlLinearGradientColorSource* linear = source->asLinearGradient(); + FML_DCHECK(linear); + void* pod = Push(linear->size(), 0); + new (pod) DlLinearGradientColorSource(linear); + break; + } + case DlColorSourceType::kRadialGradient: { + const DlRadialGradientColorSource* radial = source->asRadialGradient(); + FML_DCHECK(radial); + void* pod = Push(radial->size(), 0); + new (pod) DlRadialGradientColorSource(radial); + break; + } + case DlColorSourceType::kConicalGradient: { + const DlConicalGradientColorSource* conical = + source->asConicalGradient(); + FML_DCHECK(conical); + void* pod = Push(conical->size(), 0); + new (pod) DlConicalGradientColorSource(conical); + break; + } + case DlColorSourceType::kSweepGradient: { + const DlSweepGradientColorSource* sweep = source->asSweepGradient(); + FML_DCHECK(sweep); + void* pod = Push(sweep->size(), 0); + new (pod) DlSweepGradientColorSource(sweep); + break; + } + case DlColorSourceType::kUnknown: + Push(0, 0, source->skia_object()); + break; + } + } } void DisplayListBuilder::onSetImageFilter(sk_sp filter) { (current_image_filter_ = filter) // @@ -144,24 +193,24 @@ void DisplayListBuilder::onSetColorFilter(const DlColorFilter* filter) { case DlColorFilterType::kBlend: { const DlBlendColorFilter* blend_filter = filter->asBlend(); FML_DCHECK(blend_filter); - void* pod = Push(blend_filter->size(), 0); + void* pod = Push(blend_filter->size(), 0); new (pod) DlBlendColorFilter(blend_filter); break; } case DlColorFilterType::kMatrix: { const DlMatrixColorFilter* matrix_filter = filter->asMatrix(); FML_DCHECK(matrix_filter); - void* pod = Push(matrix_filter->size(), 0); + void* pod = Push(matrix_filter->size(), 0); new (pod) DlMatrixColorFilter(matrix_filter); break; } case DlColorFilterType::kSrgbToLinearGamma: { - void* pod = Push(filter->size(), 0); + void* pod = Push(filter->size(), 0); new (pod) DlSrgbToLinearGammaColorFilter(); break; } case DlColorFilterType::kLinearToSrgbGamma: { - void* pod = Push(filter->size(), 0); + void* pod = Push(filter->size(), 0); new (pod) DlLinearToSrgbGammaColorFilter(); break; } @@ -188,7 +237,7 @@ void DisplayListBuilder::onSetMaskFilter(const DlMaskFilter* filter) { case DlMaskFilterType::kBlur: { const DlBlurMaskFilter* blur_filter = filter->asBlur(); FML_DCHECK(blur_filter); - void* pod = Push(blur_filter->size(), 0); + void* pod = Push(blur_filter->size(), 0); new (pod) DlBlurMaskFilter(blur_filter); break; } @@ -229,7 +278,8 @@ void DisplayListBuilder::setAttributesFromPaint( setStrokeJoin(paint.getStrokeJoin()); } if (flags.applies_shader()) { - setShader(sk_ref_sp(paint.getShader())); + SkShader* shader = paint.getShader(); + setColorSource(DlColorSource::From(shader).get()); } if (flags.applies_color_filter()) { // invert colors is a Flutter::Paint thing, not an SkPaint thing diff --git a/display_list/display_list_builder.h b/display_list/display_list_builder.h index a3c3f8ba559b6..6f0590424b303 100644 --- a/display_list/display_list_builder.h +++ b/display_list/display_list_builder.h @@ -84,9 +84,9 @@ class DisplayListBuilder final : public virtual Dispatcher, onSetBlender(std::move(blender)); } } - void setShader(sk_sp shader) override { - if (current_shader_ != shader) { - onSetShader(std::move(shader)); + void setColorSource(const DlColorSource* source) override { + if (NotEquals(current_color_source_, source)) { + onSetColorSource(source); } } void setImageFilter(sk_sp filter) override { @@ -118,7 +118,9 @@ class DisplayListBuilder final : public virtual Dispatcher, SkScalar getStrokeMiter() const { return current_stroke_miter_; } SkPaint::Cap getStrokeCap() const { return current_stroke_cap_; } SkPaint::Join getStrokeJoin() const { return current_stroke_join_; } - sk_sp getShader() const { return current_shader_; } + std::shared_ptr getColorSource() const { + return current_color_source_; + } std::shared_ptr getColorFilter() const { return current_color_filter_; } @@ -376,7 +378,7 @@ class DisplayListBuilder final : public virtual Dispatcher, void onSetColor(SkColor color); void onSetBlendMode(SkBlendMode mode); void onSetBlender(sk_sp blender); - void onSetShader(sk_sp shader); + void onSetColorSource(const DlColorSource* source); void onSetImageFilter(sk_sp filter); void onSetColorFilter(const DlColorFilter* filter); void onSetPathEffect(sk_sp effect); @@ -396,7 +398,7 @@ class DisplayListBuilder final : public virtual Dispatcher, // If |current_blender_| is set then |current_blend_mode_| should be ignored SkBlendMode current_blend_mode_ = SkBlendMode::kSrcOver; sk_sp current_blender_; - sk_sp current_shader_; + std::shared_ptr current_color_source_; std::shared_ptr current_color_filter_; sk_sp current_image_filter_; sk_sp current_path_effect_; diff --git a/display_list/display_list_canvas_unittests.cc b/display_list/display_list_canvas_unittests.cc index 390d6005cc2b3..5d3cfeb5a6269 100644 --- a/display_list/display_list_canvas_unittests.cc +++ b/display_list/display_list_canvas_unittests.cc @@ -5,6 +5,7 @@ #include "flutter/display_list/display_list.h" #include "flutter/display_list/display_list_canvas_dispatcher.h" #include "flutter/display_list/display_list_canvas_recorder.h" +#include "flutter/display_list/display_list_comparable.h" #include "flutter/display_list/display_list_flags.h" #include "flutter/fml/math.h" #include "flutter/testing/testing.h" @@ -286,23 +287,27 @@ class RenderEnvironment { } void init_ref(CvRenderer& cv_renderer, SkColor bg = SK_ColorTRANSPARENT) { - init_ref([=](SkCanvas*, SkPaint&) {}, cv_renderer, bg); + init_ref([=](SkCanvas*, SkPaint&) {}, cv_renderer, + [=](DisplayListBuilder&) {}, bg); } void init_ref(CvSetup& cv_setup, CvRenderer& cv_renderer, + DlRenderer& dl_setup, SkColor bg = SK_ColorTRANSPARENT) { ref_canvas()->clear(bg); - cv_setup(ref_canvas(), ref_paint_); + dl_setup(ref_attr_); + SkPaint paint; + cv_setup(ref_canvas(), paint); ref_matrix_ = ref_canvas()->getTotalMatrix(); ref_clip_ = ref_canvas()->getDeviceClipBounds(); - cv_renderer(ref_canvas(), ref_paint_); + cv_renderer(ref_canvas(), paint); ref_pixmap_ = ref_surface_->pixmap(); } const SkImageInfo& info() const { return info_; } SkCanvas* ref_canvas() { return ref_surface_->canvas(); } - const SkPaint& ref_paint() const { return ref_paint_; } + const DisplayListBuilder& ref_attr() const { return ref_attr_; } const SkMatrix& ref_matrix() const { return ref_matrix_; } const SkIRect& ref_clip_bounds() const { return ref_clip_; } const SkPixmap* ref_pixmap() const { return ref_pixmap_; } @@ -314,7 +319,7 @@ class RenderEnvironment { const SkImageInfo info_; - SkPaint ref_paint_; + DisplayListBuilder ref_attr_; SkMatrix ref_matrix_; SkIRect ref_clip_; std::unique_ptr ref_surface_; @@ -331,7 +336,7 @@ class TestParameters { bool uses_paint() const { return !flags_.ignores_paint(); } bool should_match(const RenderEnvironment& env, - const SkPaint& paint, + const DisplayListBuilder& attr, const SkMatrix& matrix, const SkIRect& device_clip, bool has_diff_clip, @@ -348,49 +353,46 @@ class TestParameters { if (flags_.ignores_paint()) { return true; } - const SkPaint& ref_paint = env.ref_paint(); + const DisplayListBuilder& ref_attr = env.ref_attr(); if (flags_.applies_anti_alias() && // - ref_paint.isAntiAlias() != paint.isAntiAlias()) { + ref_attr.isAntiAlias() != attr.isAntiAlias()) { return false; } if (flags_.applies_dither() && // - ref_paint.isDither() != paint.isDither()) { + ref_attr.isDither() != attr.isDither()) { return false; } if (flags_.applies_color() && // - ref_paint.getColor() != paint.getColor()) { - return false; - } - if (flags_.applies_alpha() && // - ref_paint.getAlpha() != paint.getAlpha()) { + ref_attr.getColor() != attr.getColor()) { return false; } if (flags_.applies_blend() && // - ref_paint.getBlender() != paint.getBlender()) { + ref_attr.getBlender() != attr.getBlender()) { return false; } if (flags_.applies_color_filter() && // - ref_paint.getColorFilter() != paint.getColorFilter()) { + (ref_attr.isInvertColors() != attr.isInvertColors() || + NotEquals(ref_attr.getColorFilter(), attr.getColorFilter()))) { return false; } if (flags_.applies_mask_filter() && // - ref_paint.getMaskFilter() != paint.getMaskFilter()) { + NotEquals(ref_attr.getMaskFilter(), attr.getMaskFilter())) { return false; } if (flags_.applies_image_filter() && // - ref_paint.getImageFilter() != paint.getImageFilter()) { + ref_attr.getImageFilter() != attr.getImageFilter()) { return false; } if (flags_.applies_shader() && // - ref_paint.getShader() != paint.getShader()) { + NotEquals(ref_attr.getColorSource(), attr.getColorSource())) { return false; } DisplayListSpecialGeometryFlags geo_flags = - flags_.WithPathEffect(paint.refPathEffect()); + flags_.WithPathEffect(attr.getPathEffect()); if (flags_.applies_path_effect() && // - ref_paint.getPathEffect() != paint.getPathEffect()) { + ref_attr.getPathEffect() != attr.getPathEffect()) { SkPathEffect::DashInfo info; - if (paint.getPathEffect()->asADash(&info) != + if (attr.getPathEffect()->asADash(&info) != SkPathEffect::kDash_DashType) { return false; } @@ -398,27 +400,27 @@ class TestParameters { return false; } } - bool is_stroked = flags_.is_stroked(ref_paint.getStyle()); - if (flags_.is_stroked(paint.getStyle()) != is_stroked) { + bool is_stroked = flags_.is_stroked(ref_attr.getStyle()); + if (flags_.is_stroked(attr.getStyle()) != is_stroked) { return false; } if (!is_stroked) { return true; } - if (ref_paint.getStrokeWidth() != paint.getStrokeWidth()) { + if (ref_attr.getStrokeWidth() != attr.getStrokeWidth()) { return false; } if (geo_flags.may_have_end_caps() && // - getCap(ref_paint, geo_flags) != getCap(paint, geo_flags)) { + getCap(ref_attr, geo_flags) != getCap(attr, geo_flags)) { return false; } if (geo_flags.may_have_joins()) { - if (ref_paint.getStrokeJoin() != paint.getStrokeJoin()) { + if (ref_attr.getStrokeJoin() != attr.getStrokeJoin()) { return false; } - if (ref_paint.getStrokeJoin() == SkPaint::kMiter_Join) { - SkScalar ref_miter = ref_paint.getStrokeMiter(); - SkScalar test_miter = paint.getStrokeMiter(); + if (ref_attr.getStrokeJoin() == SkPaint::kMiter_Join) { + SkScalar ref_miter = ref_attr.getStrokeMiter(); + SkScalar test_miter = attr.getStrokeMiter(); // miter limit < 1.4 affects right angles if (geo_flags.may_have_acute_joins() || // ref_miter < 1.4 || test_miter < 1.4) { @@ -431,9 +433,9 @@ class TestParameters { return true; } - SkPaint::Cap getCap(const SkPaint& paint, + SkPaint::Cap getCap(const DisplayListBuilder& attr, DisplayListSpecialGeometryFlags geo_flags) const { - SkPaint::Cap cap = paint.getStrokeCap(); + SkPaint::Cap cap = attr.getStrokeCap(); if (geo_flags.butt_cap_becomes_square() && cap == SkPaint::kButt_Cap) { return SkPaint::kSquare_Cap; } @@ -940,7 +942,7 @@ class CanvasCompareTester { b.translate(0.1, 0.1); b.setStrokeWidth(5.0); }; - aa_env.init_ref(cv_aa_setup, testP.cv_renderer()); + aa_env.init_ref(cv_aa_setup, testP.cv_renderer(), dl_aa_setup); RenderWith(testP, aa_env, aa_tolerance, CaseParameters( "AntiAlias == True", @@ -974,16 +976,17 @@ class CanvasCompareTester { RenderEnvironment dither_env = RenderEnvironment::Make565(); SkColor dither_bg = SK_ColorBLACK; CvSetup cv_dither_setup = [=](SkCanvas*, SkPaint& p) { - p.setShader(testImageShader); + p.setShader(testImageColorSource.skia_object()); p.setAlpha(0xf0); p.setStrokeWidth(5.0); }; DlRenderer dl_dither_setup = [=](DisplayListBuilder& b) { - b.setShader(testImageShader); + b.setColorSource(&testImageColorSource); b.setColor(SkColor(0xf0000000)); b.setStrokeWidth(5.0); }; - dither_env.init_ref(cv_dither_setup, testP.cv_renderer(), dither_bg); + dither_env.init_ref(cv_dither_setup, testP.cv_renderer(), // + dl_dither_setup, dither_bg); RenderWith(testP, dither_env, tolerance, CaseParameters( "Dither == True", @@ -1009,7 +1012,6 @@ class CanvasCompareTester { }) .with_bg(dither_bg)); } - EXPECT_TRUE(testImageShader->unique()) << "Dither Cleanup"; RenderWith(testP, env, tolerance, CaseParameters( @@ -1083,14 +1085,14 @@ class CanvasCompareTester { // (for drawPaint) so we create a new environment for these tests. RenderEnvironment blur_env = RenderEnvironment::MakeN32(); CvSetup cv_blur_setup = [=](SkCanvas*, SkPaint& p) { - p.setShader(testImageShader); + p.setShader(testImageColorSource.skia_object()); p.setStrokeWidth(5.0); }; DlRenderer dl_blur_setup = [=](DisplayListBuilder& b) { - b.setShader(testImageShader); + b.setColorSource(&testImageColorSource); b.setStrokeWidth(5.0); }; - blur_env.init_ref(cv_blur_setup, testP.cv_renderer()); + blur_env.init_ref(cv_blur_setup, testP.cv_renderer(), dl_blur_setup); sk_sp filter = SkImageFilters::Blur(5.0, 5.0, SkTileMode::kDecal, nullptr, nullptr); BoundsTolerance blur5Tolerance = tolerance.addBoundsPadding(4, 4); @@ -1270,16 +1272,19 @@ class CanvasCompareTester { 0.5, 1.0, }; - sk_sp shader = SkGradientShader::MakeLinear( - end_points, colors, stops, 3, SkTileMode::kMirror, 0, nullptr); + std::shared_ptr source = DlColorSource::MakeLinear( + end_points[0], end_points[1], 3, colors, stops, DlTileMode::kMirror); { RenderWith(testP, env, tolerance, CaseParameters( "LinearGradient GYB", - [=](SkCanvas*, SkPaint& p) { p.setShader(shader); }, - [=](DisplayListBuilder& b) { b.setShader(shader); })); + [=](SkCanvas*, SkPaint& p) { + p.setShader(source->skia_object()); + }, + [=](DisplayListBuilder& b) { + b.setColorSource(source.get()); + })); } - EXPECT_TRUE(shader->unique()) << "LinearGradient GYB Cleanup"; } } @@ -1327,7 +1332,12 @@ class CanvasCompareTester { p.setStyle(SkPaint::kStroke_Style); p.setStrokeWidth(5.0); }; - stroke_base_env.init_ref(cv_stroke_setup, testP.cv_renderer()); + DlRenderer dl_stroke_setup = [=](DisplayListBuilder& b) { + b.setStyle(SkPaint::kStroke_Style); + b.setStrokeWidth(5.0); + }; + stroke_base_env.init_ref(cv_stroke_setup, testP.cv_renderer(), + dl_stroke_setup); RenderWith(testP, stroke_base_env, tolerance, CaseParameters( @@ -1692,7 +1702,9 @@ class CanvasCompareTester { ASSERT_EQ(sk_pixels->info().bytesPerPixel(), 4) << info; checkPixels(sk_pixels, sk_bounds, info + " (Skia reference)", bg); - if (testP.should_match(env, sk_paint, sk_matrix, sk_clip, + DisplayListBuilder dl_attr; + caseP.dl_setup()(dl_attr); + if (testP.should_match(env, dl_attr, sk_matrix, sk_clip, caseP.has_diff_clip(), caseP.has_mutating_save_layer())) { quickCompareToReference(env.ref_pixmap(), sk_pixels, true, @@ -1937,7 +1949,7 @@ class CanvasCompareTester { bool fuzzyCompares = false, int width = TestWidth, int height = TestHeight, - bool printMismatches = true) { + bool printMismatches = false) { SkPMColor untouched = SkPreMultiplyColor(bg); ASSERT_EQ(test_pixels->width(), width) << info; ASSERT_EQ(test_pixels->height(), height) << info; @@ -2064,7 +2076,7 @@ class CanvasCompareTester { return surface->makeImageSnapshot(); } - static const sk_sp testImageShader; + static const DlImageColorSource testImageColorSource; static sk_sp MakeTextBlob(std::string string, SkScalar font_height) { @@ -2079,10 +2091,11 @@ BoundsTolerance CanvasCompareTester::DefaultTolerance = BoundsTolerance().addAbsolutePadding(1, 1); const sk_sp CanvasCompareTester::testImage = makeTestImage(); -const sk_sp CanvasCompareTester::testImageShader = - makeTestImage()->makeShader(SkTileMode::kRepeat, - SkTileMode::kRepeat, - SkSamplingOptions()); +const DlImageColorSource CanvasCompareTester::testImageColorSource( + testImage, + DlTileMode::kRepeat, + DlTileMode::kRepeat, + SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kNone)); // Eventually this bare bones testing::Test fixture will subsume the // CanvasCompareTester and the TestParameters could then become just @@ -2533,14 +2546,16 @@ TEST_F(DisplayListCanvas, DrawVerticesWithImage) { [=](SkCanvas* canvas, const SkPaint& paint) { // SkPaint v_paint = paint; if (v_paint.getShader() == nullptr) { - v_paint.setShader(CanvasCompareTester::testImageShader); + v_paint.setShader( + CanvasCompareTester::testImageColorSource.skia_object()); } canvas->drawVertices(vertices.get(), SkBlendMode::kSrcOver, v_paint); }, [=](DisplayListBuilder& builder) { // - if (builder.getShader() == nullptr) { - builder.setShader(CanvasCompareTester::testImageShader); + if (builder.getColorSource() == nullptr) { + builder.setColorSource( + &CanvasCompareTester::testImageColorSource); } builder.drawVertices(vertices, SkBlendMode::kSrcOver); }, @@ -2548,7 +2563,6 @@ TEST_F(DisplayListCanvas, DrawVerticesWithImage) { .set_draw_vertices()); EXPECT_TRUE(vertices->unique()); - EXPECT_TRUE(CanvasCompareTester::testImageShader->unique()); } TEST_F(DisplayListCanvas, DrawImageNearest) { diff --git a/display_list/display_list_color_filter.h b/display_list/display_list_color_filter.h index 5f9bd6052fd7a..cfffde786b571 100644 --- a/display_list/display_list_color_filter.h +++ b/display_list/display_list_color_filter.h @@ -107,8 +107,8 @@ class DlBlendColorFilter final : public DlColorFilter { protected: bool equals_(DlColorFilter const& other) const override { FML_DCHECK(other.type() == DlColorFilterType::kBlend); - auto that = static_cast(other); - return color_ == that.color_ && mode_ == that.mode_; + auto that = static_cast(&other); + return color_ == that->color_ && mode_ == that->mode_; } private: @@ -166,8 +166,8 @@ class DlMatrixColorFilter final : public DlColorFilter { protected: bool equals_(const DlColorFilter& other) const override { FML_DCHECK(other.type() == DlColorFilterType::kMatrix); - auto that = static_cast(other); - return memcmp(matrix_, that.matrix_, sizeof(matrix_)) == 0; + auto that = static_cast(&other); + return memcmp(matrix_, that->matrix_, sizeof(matrix_)) == 0; } private: @@ -273,8 +273,8 @@ class DlUnknownColorFilter final : public DlColorFilter { protected: bool equals_(const DlColorFilter& other) const override { FML_DCHECK(other.type() == DlColorFilterType::kUnknown); - auto that = static_cast(other); - return sk_filter_ == that.sk_filter_; + auto that = static_cast(&other); + return sk_filter_ == that->sk_filter_; } private: diff --git a/display_list/display_list_color_filter_unittests.cc b/display_list/display_list_color_filter_unittests.cc index 680e45631e5ca..3be733ca67c84 100644 --- a/display_list/display_list_color_filter_unittests.cc +++ b/display_list/display_list_color_filter_unittests.cc @@ -2,9 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "flutter/display_list/display_list_attributes_testing.h" +#include "flutter/display_list/display_list_builder.h" #include "flutter/display_list/display_list_color_filter.h" #include "flutter/display_list/types.h" -#include "gtest/gtest.h" namespace flutter { namespace testing { @@ -16,6 +17,18 @@ static const float matrix[20] = { 16, 17, 18, 19, 20, // }; +TEST(DisplayListColorFilter, BuilderSetGet) { + DlBlendColorFilter filter(SK_ColorRED, SkBlendMode::kDstATop); + DisplayListBuilder builder; + ASSERT_EQ(builder.getColorFilter(), nullptr); + builder.setColorFilter(&filter); + ASSERT_NE(builder.getColorFilter(), nullptr); + ASSERT_TRUE( + Equals(builder.getColorFilter(), static_cast(&filter))); + builder.setColorFilter(nullptr); + ASSERT_EQ(builder.getColorFilter(), nullptr); +} + TEST(DisplayListColorFilter, FromSkiaNullFilter) { std::shared_ptr filter = DlColorFilter::From(nullptr); ASSERT_EQ(filter, nullptr); @@ -28,11 +41,11 @@ TEST(DisplayListColorFilter, FromSkiaBlendFilter) { std::shared_ptr filter = DlColorFilter::From(sk_filter); DlBlendColorFilter dl_filter(SK_ColorRED, SkBlendMode::kDstATop); ASSERT_EQ(filter->type(), DlColorFilterType::kBlend); - ASSERT_NE(filter->asBlend(), nullptr); - ASSERT_EQ(filter->asMatrix(), nullptr); ASSERT_EQ(*filter->asBlend(), dl_filter); ASSERT_EQ(filter->asBlend()->color(), SK_ColorRED); ASSERT_EQ(filter->asBlend()->mode(), SkBlendMode::kDstATop); + + ASSERT_EQ(filter->asMatrix(), nullptr); } TEST(DisplayListColorFilter, FromSkiaMatrixFilter) { @@ -40,19 +53,20 @@ TEST(DisplayListColorFilter, FromSkiaMatrixFilter) { std::shared_ptr filter = DlColorFilter::From(sk_filter); DlMatrixColorFilter dl_filter(matrix); ASSERT_EQ(filter->type(), DlColorFilterType::kMatrix); - ASSERT_EQ(filter->asBlend(), nullptr); - ASSERT_NE(filter->asMatrix(), nullptr); ASSERT_EQ(*filter->asMatrix(), dl_filter); const DlMatrixColorFilter* matrix_filter = filter->asMatrix(); for (int i = 0; i < 20; i++) { ASSERT_EQ((*matrix_filter)[i], matrix[i]); } + + ASSERT_EQ(filter->asBlend(), nullptr); } TEST(DisplayListColorFilter, FromSkiaSrgbToLinearFilter) { sk_sp sk_filter = SkColorFilters::SRGBToLinearGamma(); std::shared_ptr filter = DlColorFilter::From(sk_filter); ASSERT_EQ(filter->type(), DlColorFilterType::kSrgbToLinearGamma); + ASSERT_EQ(filter->asBlend(), nullptr); ASSERT_EQ(filter->asMatrix(), nullptr); } @@ -61,6 +75,7 @@ TEST(DisplayListColorFilter, FromSkiaLinearToSrgbFilter) { sk_sp sk_filter = SkColorFilters::LinearToSRGBGamma(); std::shared_ptr filter = DlColorFilter::From(sk_filter); ASSERT_EQ(filter->type(), DlColorFilterType::kLinearToSrgbGamma); + ASSERT_EQ(filter->asBlend(), nullptr); ASSERT_EQ(filter->asMatrix(), nullptr); } @@ -74,9 +89,10 @@ TEST(DisplayListColorFilter, FromSkiaUnrecognizedFilter) { SkColorFilters::Compose(sk_inputA, sk_inputB); std::shared_ptr filter = DlColorFilter::From(sk_filter); ASSERT_EQ(filter->type(), DlColorFilterType::kUnknown); + ASSERT_EQ(filter->skia_object(), sk_filter); + ASSERT_EQ(filter->asBlend(), nullptr); ASSERT_EQ(filter->asMatrix(), nullptr); - ASSERT_EQ(filter->skia_object(), sk_filter); } TEST(DisplayListColorFilter, BlendConstructor) { @@ -104,24 +120,15 @@ TEST(DisplayListColorFilter, BlendContents) { TEST(DisplayListColorFilter, BlendEquals) { DlBlendColorFilter filter1(SK_ColorRED, SkBlendMode::kDstATop); DlBlendColorFilter filter2(SK_ColorRED, SkBlendMode::kDstATop); - ASSERT_TRUE(filter1 == filter2); - ASSERT_TRUE(filter2 == filter1); - ASSERT_FALSE(filter1 != filter2); - ASSERT_FALSE(filter2 != filter1); - ASSERT_EQ(filter1, filter2); + TestEquals(filter1, filter2); } TEST(DisplayListColorFilter, BlendNotEquals) { DlBlendColorFilter filter1(SK_ColorRED, SkBlendMode::kDstATop); DlBlendColorFilter filter2(SK_ColorBLUE, SkBlendMode::kDstATop); DlBlendColorFilter filter3(SK_ColorRED, SkBlendMode::kDstIn); - ASSERT_FALSE(filter1 == filter2); - ASSERT_FALSE(filter2 == filter1); - ASSERT_TRUE(filter1 != filter2); - ASSERT_TRUE(filter2 != filter1); - ASSERT_NE(filter1, filter2); - ASSERT_NE(filter2, filter3); - ASSERT_NE(filter3, filter1); + TestNotEquals(filter1, filter2, "Color differs"); + TestNotEquals(filter1, filter3, "Blend mode differs"); } TEST(DisplayListColorFilter, NopBlendShouldNotCrash) { @@ -171,7 +178,7 @@ TEST(DisplayListColorFilter, MatrixContents) { TEST(DisplayListColorFilter, MatrixEquals) { DlMatrixColorFilter filter1(matrix); DlMatrixColorFilter filter2(matrix); - ASSERT_EQ(filter1, filter2); + TestEquals(filter1, filter2); } TEST(DisplayListColorFilter, MatrixNotEquals) { @@ -180,7 +187,7 @@ TEST(DisplayListColorFilter, MatrixNotEquals) { DlMatrixColorFilter filter1(matrix_); matrix_[4] += 101; DlMatrixColorFilter filter2(matrix_); - ASSERT_NE(filter1, filter2); + TestNotEquals(filter1, filter2, "Matrix differs"); } TEST(DisplayListColorFilter, NopMatrixShouldNotCrash) { @@ -207,12 +214,8 @@ TEST(DisplayListColorFilter, SrgbToLinearShared) { TEST(DisplayListColorFilter, SrgbToLinearEquals) { DlSrgbToLinearGammaColorFilter filter1; DlSrgbToLinearGammaColorFilter filter2; - ASSERT_TRUE(filter1 == filter2); - ASSERT_TRUE(filter2 == filter1); - ASSERT_FALSE(filter1 != filter2); - ASSERT_FALSE(filter2 != filter1); - ASSERT_EQ(filter1, filter2); - ASSERT_EQ(filter1, *DlSrgbToLinearGammaColorFilter::instance); + TestEquals(filter1, filter2); + TestEquals(filter1, *DlSrgbToLinearGammaColorFilter::instance); } TEST(DisplayListColorFilter, LinearToSrgbConstructor) { @@ -228,12 +231,8 @@ TEST(DisplayListColorFilter, LinearToSrgbShared) { TEST(DisplayListColorFilter, LinearToSrgbEquals) { DlLinearToSrgbGammaColorFilter filter1; DlLinearToSrgbGammaColorFilter filter2; - ASSERT_TRUE(filter1 == filter2); - ASSERT_TRUE(filter2 == filter1); - ASSERT_FALSE(filter1 != filter2); - ASSERT_FALSE(filter2 != filter1); - ASSERT_EQ(filter1, filter2); - ASSERT_EQ(filter1, *DlLinearToSrgbGammaColorFilter::instance); + TestEquals(filter1, filter2); + TestEquals(filter1, *DlLinearToSrgbGammaColorFilter::instance); } TEST(DisplayListColorFilter, UnknownConstructor) { @@ -257,11 +256,7 @@ TEST(DisplayListColorFilter, UnknownEquals) { sk_sp sk_filter = SkColorFilters::LinearToSRGBGamma(); DlUnknownColorFilter filter1(sk_filter); DlUnknownColorFilter filter2(sk_filter); - ASSERT_TRUE(filter1 == filter2); - ASSERT_TRUE(filter2 == filter1); - ASSERT_FALSE(filter1 != filter2); - ASSERT_FALSE(filter2 != filter1); - ASSERT_EQ(filter1, filter2); + TestEquals(filter1, filter2); } TEST(DisplayListColorFilter, UnknownNotEquals) { @@ -272,11 +267,7 @@ TEST(DisplayListColorFilter, UnknownNotEquals) { SkColorFilters::Blend(SK_ColorRED, SkBlendMode::kDstATop)); DlUnknownColorFilter filter2( SkColorFilters::Blend(SK_ColorRED, SkBlendMode::kDstATop)); - ASSERT_TRUE(filter1 != filter2); - ASSERT_TRUE(filter2 != filter1); - ASSERT_FALSE(filter1 == filter2); - ASSERT_FALSE(filter2 == filter1); - ASSERT_NE(filter1, filter2); + TestNotEquals(filter1, filter2, "SkColorFilter instance differs"); } } // namespace testing diff --git a/display_list/display_list_color_source.cc b/display_list/display_list_color_source.cc new file mode 100644 index 0000000000000..1a59463bb0561 --- /dev/null +++ b/display_list/display_list_color_source.cc @@ -0,0 +1,167 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/display_list/display_list_color_source.h" + +namespace flutter { + +static constexpr int kGradientStaticRecaptureCount = 24; + +std::shared_ptr DlColorSource::From(SkShader* sk_shader) { + if (sk_shader == nullptr) { + return nullptr; + } + { + SkMatrix local_matrix; + SkTileMode xy[2]; + SkImage* image = sk_shader->isAImage(&local_matrix, xy); + if (image) { + return std::make_shared( + sk_ref_sp(image), ToDl(xy[0]), ToDl(xy[1]), + DisplayList::LinearSampling, &local_matrix); + } + } + // Skia provides |SkShader->asAGradient(&info)| method to access the + // parameters of a gradient, but the info object being filled has a number + // of parameters which are missing, including the local matrix in every + // gradient, and the sweep angles in the sweep gradients. + // + // Since the matrix is a rarely used property and since most sweep + // gradients swing full circle, we will simply assume an Identity matrix + // and 0,360 for the Sweep gradient. + // Possibly the most likely "missing attribute" that might be different + // would be the sweep gradients which might be a full circle, but might + // have their starting angle in a custom direction. + SkColor colors[kGradientStaticRecaptureCount]; + SkScalar stops[kGradientStaticRecaptureCount]; + SkShader::GradientInfo info = {}; + info.fColorCount = kGradientStaticRecaptureCount; + info.fColors = colors; + info.fColorOffsets = stops; + SkShader::GradientType type = sk_shader->asAGradient(&info); + if (type != SkShader::kNone_GradientType && + info.fColorCount > kGradientStaticRecaptureCount) { + int count = info.fColorCount; + info.fColors = new SkColor[count]; + info.fColorOffsets = new SkScalar[count]; + sk_shader->asAGradient(&info); + FML_DCHECK(count == info.fColorCount); + } + DlTileMode mode = ToDl(info.fTileMode); + std::shared_ptr source; + switch (type) { + case SkShader::kNone_GradientType: + source = std::make_shared(sk_ref_sp(sk_shader)); + break; + case SkShader::kColor_GradientType: + source = std::make_shared(info.fColors[0]); + break; + case SkShader::kLinear_GradientType: + source = MakeLinear(info.fPoint[0], info.fPoint[1], info.fColorCount, + info.fColors, info.fColorOffsets, mode); + break; + case SkShader::kRadial_GradientType: + source = MakeRadial(info.fPoint[0], info.fRadius[0], info.fColorCount, + info.fColors, info.fColorOffsets, mode); + break; + case SkShader::kConical_GradientType: + source = MakeConical(info.fPoint[0], info.fRadius[0], info.fPoint[1], + info.fRadius[1], info.fColorCount, info.fColors, + info.fColorOffsets, mode); + break; + case SkShader::kSweep_GradientType: + source = MakeSweep(info.fPoint[0], 0, 360, info.fColorCount, info.fColors, + info.fColorOffsets, mode); + break; + } + if (info.fColors != colors) { + delete info.fColors; + } + if (info.fColorOffsets != stops) { + delete info.fColorOffsets; + } + return source; +} + +std::shared_ptr DlColorSource::MakeLinear( + const SkPoint start_point, + const SkPoint end_point, + uint32_t stop_count, + const uint32_t* colors, + const float* stops, + DlTileMode tile_mode, + const SkMatrix* matrix) { + size_t needed = sizeof(DlLinearGradientColorSource) + + (stop_count * (sizeof(uint32_t) + sizeof(float))); + + void* storage = ::operator new(needed); + + std::shared_ptr ret; + ret.reset(new (storage) DlLinearGradientColorSource( + start_point, end_point, stop_count, colors, stops, tile_mode, matrix)); + return std::move(ret); +} + +std::shared_ptr DlColorSource::MakeRadial( + SkPoint center, + SkScalar radius, + uint32_t stop_count, + const uint32_t* colors, + const float* stops, + DlTileMode tile_mode, + const SkMatrix* matrix) { + size_t needed = sizeof(DlRadialGradientColorSource) + + (stop_count * (sizeof(uint32_t) + sizeof(float))); + + void* storage = ::operator new(needed); + + std::shared_ptr ret; + ret.reset(new (storage) DlRadialGradientColorSource( + center, radius, stop_count, colors, stops, tile_mode, matrix)); + return std::move(ret); +} + +std::shared_ptr DlColorSource::MakeConical( + SkPoint start_center, + SkScalar start_radius, + SkPoint end_center, + SkScalar end_radius, + uint32_t stop_count, + const uint32_t* colors, + const float* stops, + DlTileMode tile_mode, + const SkMatrix* matrix) { + size_t needed = sizeof(DlConicalGradientColorSource) + + (stop_count * (sizeof(uint32_t) + sizeof(float))); + + void* storage = ::operator new(needed); + + std::shared_ptr ret; + ret.reset(new (storage) DlConicalGradientColorSource( + start_center, start_radius, end_center, end_radius, stop_count, colors, + stops, tile_mode, matrix)); + return std::move(ret); +} + +std::shared_ptr DlColorSource::MakeSweep( + SkPoint center, + SkScalar start, + SkScalar end, + uint32_t stop_count, + const uint32_t* colors, + const float* stops, + DlTileMode tile_mode, + const SkMatrix* matrix) { + size_t needed = sizeof(DlSweepGradientColorSource) + + (stop_count * (sizeof(uint32_t) + sizeof(float))); + + void* storage = ::operator new(needed); + + std::shared_ptr ret; + ret.reset(new (storage) DlSweepGradientColorSource( + center, start, end, stop_count, colors, stops, tile_mode, matrix)); + return std::move(ret); +} + +} // namespace flutter diff --git a/display_list/display_list_color_source.h b/display_list/display_list_color_source.h new file mode 100644 index 0000000000000..6dd1912c04284 --- /dev/null +++ b/display_list/display_list_color_source.h @@ -0,0 +1,660 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_DISPLAY_LIST_DISPLAY_LIST_COLOR_SOURCE_H_ +#define FLUTTER_DISPLAY_LIST_DISPLAY_LIST_COLOR_SOURCE_H_ + +#include "flutter/display_list/display_list.h" +#include "flutter/display_list/display_list_attributes.h" +#include "flutter/display_list/display_list_tile_mode.h" +#include "flutter/display_list/types.h" +#include "flutter/fml/logging.h" +#include "third_party/skia/include/core/SkShader.h" +#include "third_party/skia/include/effects/SkGradientShader.h" + +namespace flutter { + +class DlColorColorSource; +class DlImageColorSource; +class DlLinearGradientColorSource; +class DlRadialGradientColorSource; +class DlConicalGradientColorSource; +class DlSweepGradientColorSource; +class DlUnknownColorSource; + +// The DisplayList ColorSource class. This class implements all of the +// facilities and adheres to the design goals of the |DlAttribute| base +// class. +// +// The role of the DlColorSource is to provide color information for +// the pixels of a rendering operation. The object is essentially the +// origin of all color being rendered, though its output may be +// modified or transformed by geometric coverage data, the filter +// attributes, and the final blend with the pixels in the destination. + +enum class DlColorSourceType { + kColor, + kImage, + kLinearGradient, + kRadialGradient, + kConicalGradient, + kSweepGradient, + kUnknown +}; + +class DlColorSource + : public DlAttribute { + public: + // Return a shared_ptr holding a DlColorSource representing the indicated + // Skia SkShader pointer. + // + // This method can detect each of the 4 recognized types from an analogous + // SkShader. + static std::shared_ptr From(SkShader* sk_filter); + + // Return a shared_ptr holding a DlColorFilter representing the indicated + // Skia SkShader pointer. + // + // This method can detect each of the 4 recognized types from an analogous + // SkShader. + static std::shared_ptr From(sk_sp sk_filter) { + return From(sk_filter.get()); + } + + static std::shared_ptr MakeLinear( + const SkPoint start_point, + const SkPoint end_point, + uint32_t stop_count, + const uint32_t* colors, + const float* stops, + DlTileMode tile_mode, + const SkMatrix* matrix = nullptr); + + static std::shared_ptr MakeRadial( + SkPoint center, + SkScalar radius, + uint32_t stop_count, + const uint32_t* colors, + const float* stops, + DlTileMode tile_mode, + const SkMatrix* matrix = nullptr); + + static std::shared_ptr MakeConical( + SkPoint start_center, + SkScalar start_radius, + SkPoint end_center, + SkScalar end_radius, + uint32_t stop_count, + const uint32_t* colors, + const float* stops, + DlTileMode tile_mode, + const SkMatrix* matrix = nullptr); + + static std::shared_ptr MakeSweep( + SkPoint center, + SkScalar start, + SkScalar end, + uint32_t stop_count, + const uint32_t* colors, + const float* stops, + DlTileMode tile_mode, + const SkMatrix* matrix = nullptr); + + virtual bool is_opaque() const = 0; + + virtual std::shared_ptr with_sampling( + const SkSamplingOptions& options) const { + return shared(); + } + + // Return a DlColorColorSource pointer to this object iff it is an Color + // type of ColorSource, otherwise return nullptr. + virtual const DlColorColorSource* asColor() const { return nullptr; } + + // Return a DlImageColorSource pointer to this object iff it is an Image + // type of ColorSource, otherwise return nullptr. + virtual const DlImageColorSource* asImage() const { return nullptr; } + + // Return a DlLinearGradientColorSource pointer to this object iff it is a + // Linear Gradient type of ColorSource, otherwise return nullptr. + virtual const DlLinearGradientColorSource* asLinearGradient() const { + return nullptr; + } + + // Return a DlRadialGradientColorSource pointer to this object iff it is a + // Radial Gradient type of ColorSource, otherwise return nullptr. + virtual const DlRadialGradientColorSource* asRadialGradient() const { + return nullptr; + } + + // Return a DlConicalGradientColorSource pointer to this object iff it is a + // Conical Gradient type of ColorSource, otherwise return nullptr. + virtual const DlConicalGradientColorSource* asConicalGradient() const { + return nullptr; + } + + // Return a DlSweepGradientColorSource pointer to this object iff it is a + // Sweep Gradient type of ColorSource, otherwise return nullptr. + virtual const DlSweepGradientColorSource* asSweepGradient() const { + return nullptr; + } + + protected: + DlColorSource() = default; + + private: + FML_DISALLOW_COPY_ASSIGN_AND_MOVE(DlColorSource); +}; + +class DlColorColorSource final : public DlColorSource { + public: + DlColorColorSource(uint32_t color) : color_(color) {} + + std::shared_ptr shared() const override { + return std::make_shared(color_); + } + + const DlColorColorSource* asColor() const override { return this; } + + DlColorSourceType type() const override { return DlColorSourceType::kColor; } + size_t size() const override { return sizeof(*this); } + + bool is_opaque() const override { return (color_ >> 24) == 255; } + + uint32_t color() const { return color_; } + + sk_sp skia_object() const override { + return SkShaders::Color(color_); + } + + protected: + bool equals_(DlColorSource const& other) const override { + FML_DCHECK(other.type() == DlColorSourceType::kColor); + auto that = static_cast(&other); + return color_ == that->color_; + } + + private: + uint32_t color_; + + FML_DISALLOW_COPY_ASSIGN_AND_MOVE(DlColorColorSource); +}; + +class DlMatrixColorSourceBase : public DlColorSource { + public: + const SkMatrix& matrix() const { return matrix_; } + const SkMatrix* matrix_ptr() const { + return matrix_.isIdentity() ? nullptr : &matrix_; + } + + protected: + DlMatrixColorSourceBase(const SkMatrix* matrix) + : matrix_(matrix ? *matrix : SkMatrix::I()) {} + + private: + const SkMatrix matrix_; +}; + +class DlImageColorSource final : public SkRefCnt, + public DlMatrixColorSourceBase { + public: + DlImageColorSource(sk_sp image, + DlTileMode horizontal_tile_mode, + DlTileMode vertical_tile_mode, + SkSamplingOptions sampling = DisplayList::LinearSampling, + const SkMatrix* matrix = nullptr) + : DlMatrixColorSourceBase(matrix), + sk_image_(image), + horizontal_tile_mode_(horizontal_tile_mode), + vertical_tile_mode_(vertical_tile_mode), + sampling_(sampling) {} + + const DlImageColorSource* asImage() const override { return this; } + + std::shared_ptr shared() const override { + return with_sampling(sampling_); + } + + std::shared_ptr with_sampling( + const SkSamplingOptions& sampling) const override { + return std::make_shared( + sk_image_, horizontal_tile_mode_, vertical_tile_mode_, sampling, + matrix_ptr()); + } + + DlColorSourceType type() const override { return DlColorSourceType::kImage; } + size_t size() const override { return sizeof(*this); } + + bool is_opaque() const override { return sk_image_->isOpaque(); } + + sk_sp image() const { return sk_image_; } + DlTileMode horizontal_tile_mode() const { return horizontal_tile_mode_; } + DlTileMode vertical_tile_mode() const { return vertical_tile_mode_; } + SkSamplingOptions sampling() const { return sampling_; } + + virtual sk_sp skia_object() const override { + return sk_image_->makeShader(ToSk(horizontal_tile_mode_), + ToSk(vertical_tile_mode_), sampling_, + matrix_ptr()); + } + + protected: + bool equals_(DlColorSource const& other) const override { + FML_DCHECK(other.type() == DlColorSourceType::kImage); + auto that = static_cast(&other); + return (sk_image_ == that->sk_image_ && matrix() == that->matrix() && + horizontal_tile_mode_ == that->horizontal_tile_mode_ && + vertical_tile_mode_ == that->vertical_tile_mode_ && + sampling_ == that->sampling_); + } + + private: + sk_sp sk_image_; + DlTileMode horizontal_tile_mode_; + DlTileMode vertical_tile_mode_; + SkSamplingOptions sampling_; + + FML_DISALLOW_COPY_ASSIGN_AND_MOVE(DlImageColorSource); +}; + +class DlGradientColorSourceBase : public DlMatrixColorSourceBase { + public: + bool is_opaque() const override { + if (mode_ == DlTileMode::kDecal) { + return false; + } + const uint32_t* my_colors = colors(); + for (uint32_t i = 0; i < stop_count_; i++) { + if ((my_colors[i] >> 24) < 255) { + return false; + } + } + return true; + } + + DlTileMode tile_mode() const { return mode_; } + int stop_count() const { return stop_count_; } + const uint32_t* colors() const { + return reinterpret_cast(pod()); + } + const float* stops() const { + return reinterpret_cast(colors() + stop_count()); + } + + protected: + DlGradientColorSourceBase(uint32_t stop_count, + DlTileMode tile_mode, + const SkMatrix* matrix = nullptr) + : DlMatrixColorSourceBase(matrix), + mode_(tile_mode), + stop_count_(stop_count) {} + + size_t vector_sizes() const { + return stop_count_ * (sizeof(uint32_t) + sizeof(float)); + } + + virtual const void* pod() const = 0; + + bool base_equals_(DlGradientColorSourceBase const* other_base) const { + if (mode_ != other_base->mode_ || matrix() != other_base->matrix() || + stop_count_ != other_base->stop_count_) { + return false; + } + const uint32_t* my_colors = colors(); + const float* my_stops = stops(); + const uint32_t* other_colors = other_base->colors(); + const float* other_stops = other_base->stops(); + for (uint32_t i = 0; i < stop_count_; i++) { + if (my_colors[i] != other_colors[i] || my_stops[i] != other_stops[i]) { + return false; + } + } + return true; + } + + void store_color_stops(void* pod, + const uint32_t* color_data, + const float* stop_data) { + uint32_t* color_storage = reinterpret_cast(pod); + memcpy(color_storage, color_data, stop_count_ * sizeof(*color_data)); + float* stop_storage = reinterpret_cast(color_storage + stop_count_); + if (stop_data) { + memcpy(stop_storage, stop_data, stop_count_ * sizeof(*stop_data)); + } else { + float div = stop_count_ - 1; + if (div <= 0) { + div = 1; + } + for (uint32_t i = 0; i < stop_count_; i++) { + stop_storage[i] = i / div; + } + } + } + + private: + DlTileMode mode_; + uint32_t stop_count_; + + FML_DISALLOW_COPY_ASSIGN_AND_MOVE(DlGradientColorSourceBase); +}; + +class DlLinearGradientColorSource final : public DlGradientColorSourceBase { + public: + const DlLinearGradientColorSource* asLinearGradient() const override { + return this; + } + + DlColorSourceType type() const override { + return DlColorSourceType::kLinearGradient; + } + size_t size() const override { return sizeof(*this) + vector_sizes(); } + + std::shared_ptr shared() const override { + return MakeLinear(start_point_, end_point_, stop_count(), colors(), stops(), + tile_mode(), matrix_ptr()); + } + + const SkPoint& start_point() const { return start_point_; } + const SkPoint& end_point() const { return end_point_; } + + sk_sp skia_object() const override { + SkPoint pts[] = {start_point_, end_point_}; + return SkGradientShader::MakeLinear(pts, colors(), stops(), stop_count(), + ToSk(tile_mode()), 0, matrix_ptr()); + } + + protected: + virtual const void* pod() const override { return this + 1; } + + bool equals_(DlColorSource const& other) const override { + FML_DCHECK(other.type() == DlColorSourceType::kLinearGradient); + auto that = static_cast(&other); + return (start_point_ == that->start_point_ && + end_point_ == that->end_point_ && base_equals_(that)); + } + + private: + DlLinearGradientColorSource(const SkPoint start_point, + const SkPoint end_point, + uint32_t stop_count, + const uint32_t* colors, + const float* stops, + DlTileMode tile_mode, + const SkMatrix* matrix = nullptr) + : DlGradientColorSourceBase(stop_count, tile_mode, matrix), + start_point_(start_point), + end_point_(end_point) { + store_color_stops(this + 1, colors, stops); + } + + DlLinearGradientColorSource(const DlLinearGradientColorSource* source) + : DlGradientColorSourceBase(source->stop_count(), + source->tile_mode(), + source->matrix_ptr()), + start_point_(source->start_point()), + end_point_(source->end_point()) { + store_color_stops(this + 1, source->colors(), source->stops()); + } + + SkPoint start_point_; + SkPoint end_point_; + + friend class DlColorSource; + friend class DisplayListBuilder; + + FML_DISALLOW_COPY_ASSIGN_AND_MOVE(DlLinearGradientColorSource); +}; + +class DlRadialGradientColorSource final : public DlGradientColorSourceBase { + public: + const DlRadialGradientColorSource* asRadialGradient() const override { + return this; + } + + std::shared_ptr shared() const override { + return MakeRadial(center_, radius_, stop_count(), colors(), stops(), + tile_mode(), matrix_ptr()); + } + + DlColorSourceType type() const override { + return DlColorSourceType::kRadialGradient; + } + size_t size() const override { return sizeof(*this) + vector_sizes(); } + + SkPoint center() const { return center_; } + SkScalar radius() const { return radius_; } + + sk_sp skia_object() const override { + return SkGradientShader::MakeRadial(center_, radius_, colors(), stops(), + stop_count(), ToSk(tile_mode()), 0, + matrix_ptr()); + } + + protected: + virtual const void* pod() const override { return this + 1; } + + bool equals_(DlColorSource const& other) const override { + FML_DCHECK(other.type() == DlColorSourceType::kRadialGradient); + auto that = static_cast(&other); + return (center_ == that->center_ && radius_ == that->radius_ && + base_equals_(that)); + } + + private: + DlRadialGradientColorSource(SkPoint center, + SkScalar radius, + uint32_t stop_count, + const uint32_t* colors, + const float* stops, + DlTileMode tile_mode, + const SkMatrix* matrix = nullptr) + : DlGradientColorSourceBase(stop_count, tile_mode, matrix), + center_(center), + radius_(radius) { + store_color_stops(this + 1, colors, stops); + } + + DlRadialGradientColorSource(const DlRadialGradientColorSource* source) + : DlGradientColorSourceBase(source->stop_count(), + source->tile_mode(), + source->matrix_ptr()), + center_(source->center()), + radius_(source->radius()) { + store_color_stops(this + 1, source->colors(), source->stops()); + } + + SkPoint center_; + SkScalar radius_; + + friend class DlColorSource; + friend class DisplayListBuilder; + + FML_DISALLOW_COPY_ASSIGN_AND_MOVE(DlRadialGradientColorSource); +}; + +class DlConicalGradientColorSource final : public DlGradientColorSourceBase { + public: + const DlConicalGradientColorSource* asConicalGradient() const override { + return this; + } + + std::shared_ptr shared() const override { + return MakeConical(start_center_, start_radius_, end_center_, end_radius_, + stop_count(), colors(), stops(), tile_mode(), + matrix_ptr()); + } + + DlColorSourceType type() const override { + return DlColorSourceType::kConicalGradient; + } + size_t size() const override { return sizeof(*this) + vector_sizes(); } + + SkPoint start_center() const { return start_center_; } + SkScalar start_radius() const { return start_radius_; } + SkPoint end_center() const { return end_center_; } + SkScalar end_radius() const { return end_radius_; } + + sk_sp skia_object() const override { + return SkGradientShader::MakeTwoPointConical( + start_center_, start_radius_, end_center_, end_radius_, colors(), + stops(), stop_count(), ToSk(tile_mode()), 0, matrix_ptr()); + } + + protected: + virtual const void* pod() const override { return this + 1; } + + bool equals_(DlColorSource const& other) const override { + FML_DCHECK(other.type() == DlColorSourceType::kConicalGradient); + auto that = static_cast(&other); + return (start_center_ == that->start_center_ && + start_radius_ == that->start_radius_ && + end_center_ == that->end_center_ && + end_radius_ == that->end_radius_ && base_equals_(that)); + } + + private: + DlConicalGradientColorSource(SkPoint start_center, + SkScalar start_radius, + SkPoint end_center, + SkScalar end_radius, + uint32_t stop_count, + const uint32_t* colors, + const float* stops, + DlTileMode tile_mode, + const SkMatrix* matrix = nullptr) + : DlGradientColorSourceBase(stop_count, tile_mode, matrix), + start_center_(start_center), + start_radius_(start_radius), + end_center_(end_center), + end_radius_(end_radius) { + store_color_stops(this + 1, colors, stops); + } + + DlConicalGradientColorSource(const DlConicalGradientColorSource* source) + : DlGradientColorSourceBase(source->stop_count(), + source->tile_mode(), + source->matrix_ptr()), + start_center_(source->start_center()), + start_radius_(source->start_radius()), + end_center_(source->end_center()), + end_radius_(source->end_radius()) { + store_color_stops(this + 1, source->colors(), source->stops()); + } + + SkPoint start_center_; + SkScalar start_radius_; + SkPoint end_center_; + SkScalar end_radius_; + + friend class DlColorSource; + friend class DisplayListBuilder; + + FML_DISALLOW_COPY_ASSIGN_AND_MOVE(DlConicalGradientColorSource); +}; + +class DlSweepGradientColorSource final : public DlGradientColorSourceBase { + public: + const DlSweepGradientColorSource* asSweepGradient() const override { + return this; + } + + std::shared_ptr shared() const override { + return MakeSweep(center_, start_, end_, stop_count(), colors(), stops(), + tile_mode(), matrix_ptr()); + } + + DlColorSourceType type() const override { + return DlColorSourceType::kSweepGradient; + } + size_t size() const override { return sizeof(*this) + vector_sizes(); } + + SkPoint center() const { return center_; } + SkScalar start() const { return start_; } + SkScalar end() const { return end_; } + + sk_sp skia_object() const override { + return SkGradientShader::MakeSweep(center_.x(), center_.y(), colors(), + stops(), stop_count(), ToSk(tile_mode()), + start_, end_, 0, matrix_ptr()); + } + + protected: + virtual const void* pod() const override { return this + 1; } + + bool equals_(DlColorSource const& other) const override { + FML_DCHECK(other.type() == DlColorSourceType::kSweepGradient); + auto that = static_cast(&other); + return (center_ == that->center_ && start_ == that->start_ && + end_ == that->end_ && base_equals_(that)); + } + + private: + DlSweepGradientColorSource(SkPoint center, + SkScalar start, + SkScalar end, + uint32_t stop_count, + const uint32_t* colors, + const float* stops, + DlTileMode tile_mode, + const SkMatrix* matrix = nullptr) + : DlGradientColorSourceBase(stop_count, tile_mode, matrix), + center_(center), + start_(start), + end_(end) { + store_color_stops(this + 1, colors, stops); + } + + DlSweepGradientColorSource(const DlSweepGradientColorSource* source) + : DlGradientColorSourceBase(source->stop_count(), + source->tile_mode(), + source->matrix_ptr()), + center_(source->center()), + start_(source->start()), + end_(source->end()) { + store_color_stops(this + 1, source->colors(), source->stops()); + } + + SkPoint center_; + SkScalar start_; + SkScalar end_; + + friend class DlColorSource; + friend class DisplayListBuilder; + + FML_DISALLOW_COPY_ASSIGN_AND_MOVE(DlSweepGradientColorSource); +}; + +class DlUnknownColorSource final : public DlColorSource { + public: + DlUnknownColorSource(sk_sp shader) : sk_shader_(shader) {} + + std::shared_ptr shared() const override { + return std::make_shared(sk_shader_); + } + + DlColorSourceType type() const override { + return DlColorSourceType::kUnknown; + } + size_t size() const override { return sizeof(*this); } + + bool is_opaque() const override { return sk_shader_->isOpaque(); } + + sk_sp skia_object() const override { return sk_shader_; } + + protected: + bool equals_(DlColorSource const& other) const override { + FML_DCHECK(other.type() == DlColorSourceType::kUnknown); + auto that = static_cast(&other); + return (sk_shader_ == that->sk_shader_); + } + + private: + sk_sp sk_shader_; + + FML_DISALLOW_COPY_ASSIGN_AND_MOVE(DlUnknownColorSource); +}; + +} // namespace flutter + +#endif // FLUTTER_DISPLAY_LIST_DISPLAY_LIST_COLOR_SOURCE_H_ diff --git a/display_list/display_list_color_source_unittests.cc b/display_list/display_list_color_source_unittests.cc new file mode 100644 index 0000000000000..642e70e96e449 --- /dev/null +++ b/display_list/display_list_color_source_unittests.cc @@ -0,0 +1,954 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/display_list/display_list_attributes_testing.h" +#include "flutter/display_list/display_list_builder.h" +#include "flutter/display_list/display_list_color_source.h" +#include "flutter/display_list/types.h" +#include "third_party/skia/include/core/SkSurface.h" + +namespace flutter { +namespace testing { + +static sk_sp MakeTestImage(int w, int h, SkColor color) { + sk_sp surface; + if (SkColorGetA(color) < 255) { + surface = SkSurface::MakeRasterN32Premul(w, h); + } else { + SkImageInfo info = + SkImageInfo::MakeN32(w, h, SkAlphaType::kOpaque_SkAlphaType); + surface = SkSurface::MakeRaster(info); + } + SkCanvas* canvas = surface->getCanvas(); + canvas->drawColor(color); + return surface->makeImageSnapshot(); +} + +static const sk_sp TestImage1 = MakeTestImage(10, 10, SK_ColorGREEN); +static const sk_sp TestAlphaImage1 = + MakeTestImage(10, 10, SK_ColorTRANSPARENT); +// clang-format off +static const SkMatrix TestMatrix1 = + SkMatrix::MakeAll(2, 0, 10, + 0, 3, 12, + 0, 0, 1); +static const SkMatrix TestMatrix2 = + SkMatrix::MakeAll(4, 0, 15, + 0, 7, 17, + 0, 0, 1); +// clang-format on +static constexpr int kTestStopCount = 3; +static constexpr SkColor TestColors[kTestStopCount] = { + SK_ColorRED, + SK_ColorGREEN, + SK_ColorBLUE, +}; +static constexpr SkColor TestAlphaColors[kTestStopCount] = { + SkColorSetA(SK_ColorBLUE, 0x7f), + SkColorSetA(SK_ColorRED, 0x2f), + SkColorSetA(SK_ColorGREEN, 0xcf), +}; +static constexpr float TestStops[kTestStopCount] = { + 0.0f, + 0.7f, + 1.0f, +}; +static constexpr float TestStops2[kTestStopCount] = { + 0.0f, + 0.3f, + 1.0f, +}; +static constexpr SkPoint TestPoints[2] = { + SkPoint::Make(5, 15), + SkPoint::Make(7, 18), +}; +static constexpr SkPoint TestPoints2[2] = { + SkPoint::Make(100, 115), + SkPoint::Make(107, 118), +}; +static const sk_sp shaderA = SkShaders::Color(SK_ColorRED); +static const sk_sp shaderB = SkShaders::Color(SK_ColorBLUE); +static const sk_sp TestUnknownShader = + SkShaders::Blend(SkBlendMode::kOverlay, shaderA, shaderB); +static const sk_sp TestAlphaUnknownShader = + SkShaders::Blend(SkBlendMode::kDstOut, shaderA, shaderB); + +TEST(DisplayListColorSource, BuilderSetGet) { + DlImageColorSource source(TestImage1, DlTileMode::kClamp, DlTileMode::kClamp, + DisplayList::LinearSampling, &TestMatrix1); + DisplayListBuilder builder; + ASSERT_EQ(builder.getColorSource(), nullptr); + builder.setColorSource(&source); + ASSERT_NE(builder.getColorSource(), nullptr); + ASSERT_TRUE( + Equals(builder.getColorSource(), static_cast(&source))); + builder.setColorSource(nullptr); + ASSERT_EQ(builder.getColorSource(), nullptr); +} + +TEST(DisplayListColorSource, FromSkiaNullShader) { + std::shared_ptr source = DlColorSource::From(nullptr); + ASSERT_EQ(source, nullptr); + ASSERT_EQ(source.get(), nullptr); +} + +TEST(DisplayListColorSource, FromSkiaColorShader) { + sk_sp shader = SkShaders::Color(SK_ColorBLUE); + std::shared_ptr source = DlColorSource::From(shader); + DlColorColorSource dl_source(SK_ColorBLUE); + ASSERT_EQ(source->type(), DlColorSourceType::kColor); + ASSERT_EQ(*source->asColor(), dl_source); + ASSERT_EQ(source->asColor()->color(), SK_ColorBLUE); + + ASSERT_EQ(source->asImage(), nullptr); + ASSERT_EQ(source->asLinearGradient(), nullptr); + ASSERT_EQ(source->asRadialGradient(), nullptr); + ASSERT_EQ(source->asConicalGradient(), nullptr); + ASSERT_EQ(source->asSweepGradient(), nullptr); +} + +TEST(DisplayListColorSource, FromSkiaImageShader) { + sk_sp shader = + TestImage1->makeShader(DisplayList::LinearSampling, &TestMatrix1); + std::shared_ptr source = DlColorSource::From(shader); + DlImageColorSource dl_source(TestImage1, DlTileMode::kClamp, + DlTileMode::kClamp, DisplayList::LinearSampling, + &TestMatrix1); + ASSERT_EQ(source->type(), DlColorSourceType::kImage); + ASSERT_EQ(*source->asImage(), dl_source); + ASSERT_EQ(source->asImage()->image(), TestImage1); + ASSERT_EQ(source->asImage()->matrix(), TestMatrix1); + ASSERT_EQ(source->asImage()->horizontal_tile_mode(), DlTileMode::kClamp); + ASSERT_EQ(source->asImage()->vertical_tile_mode(), DlTileMode::kClamp); + ASSERT_EQ(source->asImage()->sampling(), DisplayList::LinearSampling); + + ASSERT_EQ(source->asColor(), nullptr); + ASSERT_EQ(source->asLinearGradient(), nullptr); + ASSERT_EQ(source->asRadialGradient(), nullptr); + ASSERT_EQ(source->asConicalGradient(), nullptr); + ASSERT_EQ(source->asSweepGradient(), nullptr); +} + +TEST(DisplayListColorSource, FromSkiaLinearGradient) { + // We can read back all of the parameters of a Linear gradient + // except for matrix. + sk_sp shader = SkGradientShader::MakeLinear( + TestPoints, TestColors, TestStops, kTestStopCount, SkTileMode::kClamp); + std::shared_ptr source = DlColorSource::From(shader); + std::shared_ptr dl_source = + DlColorSource::MakeLinear(TestPoints[0], TestPoints[1], kTestStopCount, + TestColors, TestStops, DlTileMode::kClamp); + ASSERT_EQ(source->type(), DlColorSourceType::kLinearGradient); + EXPECT_TRUE(*source->asLinearGradient() == *dl_source->asLinearGradient()); + ASSERT_EQ(*source->asLinearGradient(), *dl_source->asLinearGradient()); + ASSERT_EQ(source->asLinearGradient()->start_point(), TestPoints[0]); + ASSERT_EQ(source->asLinearGradient()->end_point(), TestPoints[1]); + ASSERT_EQ(source->asLinearGradient()->stop_count(), kTestStopCount); + for (int i = 0; i < kTestStopCount; i++) { + ASSERT_EQ(source->asLinearGradient()->colors()[i], TestColors[i]); + ASSERT_EQ(source->asLinearGradient()->stops()[i], TestStops[i]); + } + ASSERT_EQ(source->asLinearGradient()->tile_mode(), DlTileMode::kClamp); + ASSERT_EQ(source->asLinearGradient()->matrix(), SkMatrix::I()); + + ASSERT_EQ(source->asColor(), nullptr); + ASSERT_EQ(source->asImage(), nullptr); + ASSERT_EQ(source->asRadialGradient(), nullptr); + ASSERT_EQ(source->asConicalGradient(), nullptr); + ASSERT_EQ(source->asSweepGradient(), nullptr); +} + +TEST(DisplayListColorSource, FromSkiaRadialGradient) { + // We can read back all of the parameters of a Radial gradient + // except for matrix. + sk_sp shader = + SkGradientShader::MakeRadial(TestPoints[0], 10.0, TestColors, TestStops, + kTestStopCount, SkTileMode::kClamp); + std::shared_ptr source = DlColorSource::From(shader); + std::shared_ptr dl_source = + DlColorSource::MakeRadial(TestPoints[0], 10.0, kTestStopCount, TestColors, + TestStops, DlTileMode::kClamp); + ASSERT_EQ(source->type(), DlColorSourceType::kRadialGradient); + EXPECT_TRUE(*source->asRadialGradient() == *dl_source->asRadialGradient()); + ASSERT_EQ(*source->asRadialGradient(), *dl_source->asRadialGradient()); + ASSERT_EQ(source->asRadialGradient()->center(), TestPoints[0]); + ASSERT_EQ(source->asRadialGradient()->radius(), 10.0); + ASSERT_EQ(source->asRadialGradient()->stop_count(), kTestStopCount); + for (int i = 0; i < kTestStopCount; i++) { + ASSERT_EQ(source->asRadialGradient()->colors()[i], TestColors[i]); + ASSERT_EQ(source->asRadialGradient()->stops()[i], TestStops[i]); + } + ASSERT_EQ(source->asRadialGradient()->tile_mode(), DlTileMode::kClamp); + ASSERT_EQ(source->asRadialGradient()->matrix(), SkMatrix::I()); + + ASSERT_EQ(source->asColor(), nullptr); + ASSERT_EQ(source->asImage(), nullptr); + ASSERT_EQ(source->asLinearGradient(), nullptr); + ASSERT_EQ(source->asConicalGradient(), nullptr); + ASSERT_EQ(source->asSweepGradient(), nullptr); +} + +TEST(DisplayListColorSource, FromSkiaConicalGradient) { + // We can read back all of the parameters of a Conical gradient + // except for matrix. + sk_sp shader = SkGradientShader::MakeTwoPointConical( + TestPoints[0], 10.0, TestPoints[1], 20.0, TestColors, TestStops, + kTestStopCount, SkTileMode::kClamp); + std::shared_ptr source = DlColorSource::From(shader); + std::shared_ptr dl_source = DlColorSource::MakeConical( + TestPoints[0], 10.0, TestPoints[1], 20.0, kTestStopCount, TestColors, + TestStops, DlTileMode::kClamp); + ASSERT_EQ(source->type(), DlColorSourceType::kConicalGradient); + EXPECT_TRUE(*source->asConicalGradient() == *dl_source->asConicalGradient()); + ASSERT_EQ(*source->asConicalGradient(), *dl_source->asConicalGradient()); + ASSERT_EQ(source->asConicalGradient()->start_center(), TestPoints[0]); + ASSERT_EQ(source->asConicalGradient()->start_radius(), 10.0); + ASSERT_EQ(source->asConicalGradient()->end_center(), TestPoints[1]); + ASSERT_EQ(source->asConicalGradient()->end_radius(), 20.0); + ASSERT_EQ(source->asConicalGradient()->stop_count(), kTestStopCount); + for (int i = 0; i < kTestStopCount; i++) { + ASSERT_EQ(source->asConicalGradient()->colors()[i], TestColors[i]); + ASSERT_EQ(source->asConicalGradient()->stops()[i], TestStops[i]); + } + ASSERT_EQ(source->asConicalGradient()->tile_mode(), DlTileMode::kClamp); + ASSERT_EQ(source->asConicalGradient()->matrix(), SkMatrix::I()); + + ASSERT_EQ(source->asColor(), nullptr); + ASSERT_EQ(source->asImage(), nullptr); + ASSERT_EQ(source->asLinearGradient(), nullptr); + ASSERT_EQ(source->asRadialGradient(), nullptr); + ASSERT_EQ(source->asSweepGradient(), nullptr); +} + +TEST(DisplayListColorSource, FromSkiaSweepGradient) { + // We can read back all of the parameters of a Sweep gradient + // except for matrix and the start/stop angles. + sk_sp shader = + SkGradientShader::MakeSweep(TestPoints[0].fX, TestPoints[0].fY, + TestColors, TestStops, kTestStopCount); + std::shared_ptr source = DlColorSource::From(shader); + std::shared_ptr dl_source = + DlColorSource::MakeSweep(TestPoints[0], 0, 360, kTestStopCount, + TestColors, TestStops, DlTileMode::kClamp); + ASSERT_EQ(source->type(), DlColorSourceType::kSweepGradient); + EXPECT_TRUE(*source->asSweepGradient() == *dl_source->asSweepGradient()); + ASSERT_EQ(*source->asSweepGradient(), *dl_source->asSweepGradient()); + ASSERT_EQ(source->asSweepGradient()->center(), TestPoints[0]); + ASSERT_EQ(source->asSweepGradient()->start(), 0); + ASSERT_EQ(source->asSweepGradient()->end(), 360); + ASSERT_EQ(source->asSweepGradient()->stop_count(), kTestStopCount); + for (int i = 0; i < kTestStopCount; i++) { + ASSERT_EQ(source->asSweepGradient()->colors()[i], TestColors[i]); + ASSERT_EQ(source->asSweepGradient()->stops()[i], TestStops[i]); + } + ASSERT_EQ(source->asSweepGradient()->tile_mode(), DlTileMode::kClamp); + ASSERT_EQ(source->asSweepGradient()->matrix(), SkMatrix::I()); + + ASSERT_EQ(source->asColor(), nullptr); + ASSERT_EQ(source->asImage(), nullptr); + ASSERT_EQ(source->asLinearGradient(), nullptr); + ASSERT_EQ(source->asRadialGradient(), nullptr); + ASSERT_EQ(source->asConicalGradient(), nullptr); + ASSERT_NE(source->asSweepGradient(), nullptr); +} + +TEST(DisplayListColorSource, FromSkiaUnrecognizedShader) { + std::shared_ptr source = + DlColorSource::From(TestUnknownShader); + ASSERT_EQ(source->type(), DlColorSourceType::kUnknown); + ASSERT_EQ(source->skia_object(), TestUnknownShader); + + ASSERT_EQ(source->asColor(), nullptr); + ASSERT_EQ(source->asImage(), nullptr); + ASSERT_EQ(source->asLinearGradient(), nullptr); + ASSERT_EQ(source->asRadialGradient(), nullptr); + ASSERT_EQ(source->asConicalGradient(), nullptr); + ASSERT_EQ(source->asSweepGradient(), nullptr); +} + +TEST(DisplayListColorSource, ColorConstructor) { + DlColorColorSource source(SK_ColorRED); +} + +TEST(DisplayListColorSource, ColorShared) { + DlColorColorSource source(SK_ColorRED); + ASSERT_NE(source.shared().get(), &source); + ASSERT_EQ(*source.shared(), source); +} + +TEST(DisplayListColorSource, ColorAsColor) { + DlColorColorSource source(SK_ColorRED); + ASSERT_NE(source.asColor(), nullptr); + ASSERT_EQ(source.asColor(), &source); + + ASSERT_EQ(source.asImage(), nullptr); + ASSERT_EQ(source.asLinearGradient(), nullptr); + ASSERT_EQ(source.asRadialGradient(), nullptr); + ASSERT_EQ(source.asConicalGradient(), nullptr); + ASSERT_EQ(source.asSweepGradient(), nullptr); +} + +TEST(DisplayListColorSource, ColorContents) { + DlColorColorSource source(SK_ColorRED); + ASSERT_EQ(source.color(), SK_ColorRED); + ASSERT_EQ(source.is_opaque(), true); + for (int i = 0; i < 255; i++) { + SkColor alpha_color = SkColorSetA(SK_ColorRED, i); + DlColorColorSource alpha_source(alpha_color); + ASSERT_EQ(alpha_source.color(), alpha_color); + ASSERT_EQ(alpha_source.is_opaque(), false); + } +} + +TEST(DisplayListColorSource, ColorEquals) { + DlColorColorSource source1(SK_ColorRED); + DlColorColorSource source2(SK_ColorRED); + TestEquals(source1, source2); +} + +TEST(DisplayListColorSource, ColorNotEquals) { + DlColorColorSource source1(SK_ColorRED); + DlColorColorSource source2(SK_ColorBLUE); + TestNotEquals(source1, source2, "Color differs"); +} + +TEST(DisplayListColorSource, ImageConstructor) { + DlImageColorSource source(TestImage1, DlTileMode::kClamp, DlTileMode::kClamp, + DisplayList::LinearSampling, &TestMatrix1); +} + +TEST(DisplayListColorSource, ImageShared) { + DlImageColorSource source(TestImage1, DlTileMode::kClamp, DlTileMode::kClamp, + DisplayList::LinearSampling, &TestMatrix1); + ASSERT_NE(source.shared().get(), &source); + ASSERT_EQ(*source.shared(), source); +} + +TEST(DisplayListColorSource, ImageAsImage) { + DlImageColorSource source(TestImage1, DlTileMode::kClamp, DlTileMode::kClamp, + DisplayList::LinearSampling, &TestMatrix1); + ASSERT_NE(source.asImage(), nullptr); + ASSERT_EQ(source.asImage(), &source); + + ASSERT_EQ(source.asColor(), nullptr); + ASSERT_EQ(source.asLinearGradient(), nullptr); + ASSERT_EQ(source.asRadialGradient(), nullptr); + ASSERT_EQ(source.asConicalGradient(), nullptr); + ASSERT_EQ(source.asSweepGradient(), nullptr); +} + +TEST(DisplayListColorSource, ImageContents) { + DlImageColorSource source(TestImage1, DlTileMode::kRepeat, + DlTileMode::kMirror, DisplayList::LinearSampling, + &TestMatrix1); + ASSERT_EQ(source.image(), TestImage1); + ASSERT_EQ(source.horizontal_tile_mode(), DlTileMode::kRepeat); + ASSERT_EQ(source.vertical_tile_mode(), DlTileMode::kMirror); + ASSERT_EQ(source.sampling(), DisplayList::LinearSampling); + ASSERT_EQ(source.matrix(), TestMatrix1); + ASSERT_EQ(source.is_opaque(), true); +} + +TEST(DisplayListColorSource, AlphaImageContents) { + DlImageColorSource source(TestAlphaImage1, DlTileMode::kRepeat, + DlTileMode::kMirror, DisplayList::LinearSampling, + &TestMatrix1); + ASSERT_EQ(source.image(), TestAlphaImage1); + ASSERT_EQ(source.horizontal_tile_mode(), DlTileMode::kRepeat); + ASSERT_EQ(source.vertical_tile_mode(), DlTileMode::kMirror); + ASSERT_EQ(source.sampling(), DisplayList::LinearSampling); + ASSERT_EQ(source.matrix(), TestMatrix1); + ASSERT_EQ(source.is_opaque(), false); +} + +TEST(DisplayListColorSource, ImageEquals) { + DlImageColorSource source1(TestImage1, DlTileMode::kClamp, + DlTileMode::kMirror, DisplayList::LinearSampling, + &TestMatrix1); + DlImageColorSource source2(TestImage1, DlTileMode::kClamp, + DlTileMode::kMirror, DisplayList::LinearSampling, + &TestMatrix1); + TestEquals(source1, source2); +} + +TEST(DisplayListColorSource, ImageNotEquals) { + DlImageColorSource source1(TestImage1, DlTileMode::kClamp, + DlTileMode::kMirror, DisplayList::LinearSampling, + &TestMatrix1); + { + DlImageColorSource source2(TestAlphaImage1, DlTileMode::kClamp, + DlTileMode::kMirror, DisplayList::LinearSampling, + &TestMatrix1); + TestNotEquals(source1, source2, "Image differs"); + } + { + DlImageColorSource source2(TestImage1, DlTileMode::kRepeat, + DlTileMode::kMirror, DisplayList::LinearSampling, + &TestMatrix1); + TestNotEquals(source1, source2, "hTileMode differs"); + } + { + DlImageColorSource source2(TestImage1, DlTileMode::kClamp, + DlTileMode::kRepeat, DisplayList::LinearSampling, + &TestMatrix1); + TestNotEquals(source1, source2, "vTileMode differs"); + } + { + DlImageColorSource source2(TestImage1, DlTileMode::kClamp, + DlTileMode::kMirror, DisplayList::CubicSampling, + &TestMatrix1); + TestNotEquals(source1, source2, "Sampling differs"); + } + { + DlImageColorSource source2(TestImage1, DlTileMode::kClamp, + DlTileMode::kMirror, DisplayList::LinearSampling, + &TestMatrix2); + TestNotEquals(source1, source2, "Matrix differs"); + } +} + +TEST(DisplayListColorSource, LinearGradientConstructor) { + std::shared_ptr source = DlColorSource::MakeLinear( + TestPoints[0], TestPoints[1], kTestStopCount, TestColors, TestStops, + DlTileMode::kClamp, &TestMatrix1); +} + +TEST(DisplayListColorSource, LinearGradientShared) { + std::shared_ptr source = DlColorSource::MakeLinear( + TestPoints[0], TestPoints[1], kTestStopCount, TestColors, TestStops, + DlTileMode::kClamp, &TestMatrix1); + ASSERT_NE(source->shared().get(), source.get()); + ASSERT_EQ(*source->shared().get(), *source.get()); +} + +TEST(DisplayListColorSource, LinearGradientAsLinear) { + std::shared_ptr source = DlColorSource::MakeLinear( + TestPoints[0], TestPoints[1], kTestStopCount, TestColors, TestStops, + DlTileMode::kClamp, &TestMatrix1); + ASSERT_NE(source->asLinearGradient(), nullptr); + ASSERT_EQ(source->asLinearGradient(), source.get()); + + ASSERT_EQ(source->asColor(), nullptr); + ASSERT_EQ(source->asImage(), nullptr); + ASSERT_EQ(source->asRadialGradient(), nullptr); + ASSERT_EQ(source->asConicalGradient(), nullptr); + ASSERT_EQ(source->asSweepGradient(), nullptr); +} + +TEST(DisplayListColorSource, LinearGradientContents) { + std::shared_ptr source = DlColorSource::MakeLinear( + TestPoints[0], TestPoints[1], kTestStopCount, TestColors, TestStops, + DlTileMode::kClamp, &TestMatrix1); + ASSERT_EQ(source->asLinearGradient()->start_point(), TestPoints[0]); + ASSERT_EQ(source->asLinearGradient()->end_point(), TestPoints[1]); + ASSERT_EQ(source->asLinearGradient()->stop_count(), kTestStopCount); + for (int i = 0; i < kTestStopCount; i++) { + ASSERT_EQ(source->asLinearGradient()->colors()[i], TestColors[i]); + ASSERT_EQ(source->asLinearGradient()->stops()[i], TestStops[i]); + } + ASSERT_EQ(source->asLinearGradient()->tile_mode(), DlTileMode::kClamp); + ASSERT_EQ(source->asLinearGradient()->matrix(), TestMatrix1); + ASSERT_EQ(source->is_opaque(), true); +} + +TEST(DisplayListColorSource, AlphaLinearGradientContents) { + std::shared_ptr source = DlColorSource::MakeLinear( + TestPoints[0], TestPoints[1], kTestStopCount, TestAlphaColors, TestStops, + DlTileMode::kClamp, &TestMatrix1); + ASSERT_EQ(source->asLinearGradient()->start_point(), TestPoints[0]); + ASSERT_EQ(source->asLinearGradient()->end_point(), TestPoints[1]); + ASSERT_EQ(source->asLinearGradient()->stop_count(), kTestStopCount); + for (int i = 0; i < kTestStopCount; i++) { + ASSERT_EQ(source->asLinearGradient()->colors()[i], TestAlphaColors[i]); + ASSERT_EQ(source->asLinearGradient()->stops()[i], TestStops[i]); + } + ASSERT_EQ(source->asLinearGradient()->tile_mode(), DlTileMode::kClamp); + ASSERT_EQ(source->asLinearGradient()->matrix(), TestMatrix1); + ASSERT_EQ(source->is_opaque(), false); +} + +TEST(DisplayListColorSource, LinearGradientEquals) { + std::shared_ptr source1 = DlColorSource::MakeLinear( + TestPoints[0], TestPoints[1], kTestStopCount, TestColors, TestStops, + DlTileMode::kClamp, &TestMatrix1); + std::shared_ptr source2 = DlColorSource::MakeLinear( + TestPoints[0], TestPoints[1], kTestStopCount, TestColors, TestStops, + DlTileMode::kClamp, &TestMatrix1); + TestEquals(*source1, *source2); +} + +TEST(DisplayListColorSource, LinearGradientNotEquals) { + std::shared_ptr source1 = DlColorSource::MakeLinear( + TestPoints[0], TestPoints[1], kTestStopCount, TestColors, TestStops, + DlTileMode::kClamp, &TestMatrix1); + { + std::shared_ptr source2 = DlColorSource::MakeLinear( + TestPoints2[0], TestPoints[1], kTestStopCount, TestColors, TestStops, + DlTileMode::kClamp, &TestMatrix1); + TestNotEquals(*source1, *source2, "Point 0 differs"); + } + { + std::shared_ptr source2 = DlColorSource::MakeLinear( + TestPoints[0], TestPoints2[1], kTestStopCount, TestColors, TestStops, + DlTileMode::kClamp, &TestMatrix1); + TestNotEquals(*source1, *source2, "Point 1 differs"); + } + { + std::shared_ptr source2 = DlColorSource::MakeLinear( + TestPoints[0], TestPoints[1], 2, TestColors, TestStops, // + DlTileMode::kClamp, &TestMatrix1); + TestNotEquals(*source1, *source2, "Stop count differs"); + } + { + std::shared_ptr source2 = DlColorSource::MakeLinear( + TestPoints[0], TestPoints[1], kTestStopCount, TestAlphaColors, + TestStops, DlTileMode::kClamp, &TestMatrix1); + TestNotEquals(*source1, *source2, "Colors differ"); + } + { + std::shared_ptr source2 = DlColorSource::MakeLinear( + TestPoints[0], TestPoints[1], kTestStopCount, TestColors, TestStops2, + DlTileMode::kClamp, &TestMatrix1); + TestNotEquals(*source1, *source2, "Stops differ"); + } + { + std::shared_ptr source2 = DlColorSource::MakeLinear( + TestPoints[0], TestPoints[1], kTestStopCount, TestColors, TestStops, + DlTileMode::kMirror, &TestMatrix1); + TestNotEquals(*source1, *source2, "Tile Mode differs"); + } + { + std::shared_ptr source2 = DlColorSource::MakeLinear( + TestPoints[0], TestPoints[1], kTestStopCount, TestColors, TestStops, + DlTileMode::kClamp, &TestMatrix2); + TestNotEquals(*source1, *source2, "Matrix differs"); + } +} + +TEST(DisplayListColorSource, RadialGradientConstructor) { + std::shared_ptr source = + DlColorSource::MakeRadial(TestPoints[0], 10.0, kTestStopCount, TestColors, + TestStops, DlTileMode::kClamp, &TestMatrix1); +} + +TEST(DisplayListColorSource, RadialGradientShared) { + std::shared_ptr source = + DlColorSource::MakeRadial(TestPoints[0], 10.0, kTestStopCount, TestColors, + TestStops, DlTileMode::kClamp, &TestMatrix1); + ASSERT_NE(source->shared().get(), source.get()); + ASSERT_EQ(*source->shared().get(), *source.get()); +} + +TEST(DisplayListColorSource, RadialGradientAsRadial) { + std::shared_ptr source = + DlColorSource::MakeRadial(TestPoints[0], 10.0, kTestStopCount, TestColors, + TestStops, DlTileMode::kClamp, &TestMatrix1); + ASSERT_NE(source->asRadialGradient(), nullptr); + ASSERT_EQ(source->asRadialGradient(), source.get()); + + ASSERT_EQ(source->asColor(), nullptr); + ASSERT_EQ(source->asImage(), nullptr); + ASSERT_EQ(source->asLinearGradient(), nullptr); + ASSERT_EQ(source->asConicalGradient(), nullptr); + ASSERT_EQ(source->asSweepGradient(), nullptr); +} + +TEST(DisplayListColorSource, RadialGradientContents) { + std::shared_ptr source = + DlColorSource::MakeRadial(TestPoints[0], 10.0, kTestStopCount, TestColors, + TestStops, DlTileMode::kClamp, &TestMatrix1); + ASSERT_EQ(source->asRadialGradient()->center(), TestPoints[0]); + ASSERT_EQ(source->asRadialGradient()->radius(), 10.0); + ASSERT_EQ(source->asRadialGradient()->stop_count(), kTestStopCount); + for (int i = 0; i < kTestStopCount; i++) { + ASSERT_EQ(source->asRadialGradient()->colors()[i], TestColors[i]); + ASSERT_EQ(source->asRadialGradient()->stops()[i], TestStops[i]); + } + ASSERT_EQ(source->asRadialGradient()->tile_mode(), DlTileMode::kClamp); + ASSERT_EQ(source->asRadialGradient()->matrix(), TestMatrix1); + ASSERT_EQ(source->is_opaque(), true); +} + +TEST(DisplayListColorSource, AlphaRadialGradientContents) { + std::shared_ptr source = DlColorSource::MakeRadial( + TestPoints[0], 10.0, kTestStopCount, TestAlphaColors, TestStops, + DlTileMode::kClamp, &TestMatrix1); + ASSERT_EQ(source->asRadialGradient()->center(), TestPoints[0]); + ASSERT_EQ(source->asRadialGradient()->radius(), 10.0); + ASSERT_EQ(source->asRadialGradient()->stop_count(), kTestStopCount); + for (int i = 0; i < kTestStopCount; i++) { + ASSERT_EQ(source->asRadialGradient()->colors()[i], TestAlphaColors[i]); + ASSERT_EQ(source->asRadialGradient()->stops()[i], TestStops[i]); + } + ASSERT_EQ(source->asRadialGradient()->tile_mode(), DlTileMode::kClamp); + ASSERT_EQ(source->asRadialGradient()->matrix(), TestMatrix1); + ASSERT_EQ(source->is_opaque(), false); +} + +TEST(DisplayListColorSource, RadialGradientEquals) { + std::shared_ptr source1 = + DlColorSource::MakeRadial(TestPoints[0], 10.0, kTestStopCount, TestColors, + TestStops, DlTileMode::kClamp, &TestMatrix1); + std::shared_ptr source2 = + DlColorSource::MakeRadial(TestPoints[0], 10.0, kTestStopCount, TestColors, + TestStops, DlTileMode::kClamp, &TestMatrix1); + TestEquals(*source1, *source2); +} + +TEST(DisplayListColorSource, RadialGradientNotEquals) { + std::shared_ptr source1 = + DlColorSource::MakeRadial(TestPoints[0], 10.0, kTestStopCount, TestColors, + TestStops, DlTileMode::kClamp, &TestMatrix1); + { + std::shared_ptr source2 = DlColorSource::MakeRadial( + TestPoints2[0], 10.0, kTestStopCount, TestColors, TestStops, + DlTileMode::kClamp, &TestMatrix1); + TestNotEquals(*source1, *source2, "Center differs"); + } + { + std::shared_ptr source2 = DlColorSource::MakeRadial( + TestPoints[0], 20.0, kTestStopCount, TestColors, TestStops, + DlTileMode::kClamp, &TestMatrix1); + TestNotEquals(*source1, *source2, "Radius differs"); + } + { + std::shared_ptr source2 = DlColorSource::MakeRadial( + TestPoints[0], 10.0, 2, TestColors, TestStops, // + DlTileMode::kClamp, &TestMatrix1); + TestNotEquals(*source1, *source2, "Stop count differs"); + } + { + std::shared_ptr source2 = DlColorSource::MakeRadial( + TestPoints[0], 10.0, kTestStopCount, TestAlphaColors, TestStops, + DlTileMode::kClamp, &TestMatrix1); + TestNotEquals(*source1, *source2, "Colors differ"); + } + { + std::shared_ptr source2 = DlColorSource::MakeRadial( + TestPoints[0], 10.0, kTestStopCount, TestColors, TestStops2, + DlTileMode::kClamp, &TestMatrix1); + TestNotEquals(*source1, *source2, "Stops differ"); + } + { + std::shared_ptr source2 = DlColorSource::MakeRadial( + TestPoints[0], 10.0, kTestStopCount, TestColors, TestStops, + DlTileMode::kMirror, &TestMatrix1); + TestNotEquals(*source1, *source2, "Tile Mode differs"); + } + { + std::shared_ptr source2 = DlColorSource::MakeRadial( + TestPoints[0], 10.0, kTestStopCount, TestColors, TestStops, + DlTileMode::kClamp, &TestMatrix2); + TestNotEquals(*source1, *source2, "Matrix differs"); + } +} + +TEST(DisplayListColorSource, ConicalGradientConstructor) { + std::shared_ptr source = DlColorSource::MakeConical( + TestPoints[0], 10.0, TestPoints[1], 20.0, kTestStopCount, TestColors, + TestStops, DlTileMode::kClamp, &TestMatrix1); +} + +TEST(DisplayListColorSource, ConicalGradientShared) { + std::shared_ptr source = DlColorSource::MakeConical( + TestPoints[0], 10.0, TestPoints[1], 20.0, kTestStopCount, TestColors, + TestStops, DlTileMode::kClamp, &TestMatrix1); + ASSERT_NE(source->shared().get(), source.get()); + ASSERT_EQ(*source->shared().get(), *source.get()); +} + +TEST(DisplayListColorSource, ConicalGradientAsConical) { + std::shared_ptr source = DlColorSource::MakeConical( + TestPoints[0], 10.0, TestPoints[1], 20.0, kTestStopCount, TestColors, + TestStops, DlTileMode::kClamp, &TestMatrix1); + ASSERT_NE(source->asConicalGradient(), nullptr); + ASSERT_EQ(source->asConicalGradient(), source.get()); + + ASSERT_EQ(source->asColor(), nullptr); + ASSERT_EQ(source->asImage(), nullptr); + ASSERT_EQ(source->asLinearGradient(), nullptr); + ASSERT_EQ(source->asRadialGradient(), nullptr); + ASSERT_EQ(source->asSweepGradient(), nullptr); +} + +TEST(DisplayListColorSource, ConicalGradientContents) { + std::shared_ptr source = DlColorSource::MakeConical( + TestPoints[0], 10.0, TestPoints[1], 20.0, kTestStopCount, TestColors, + TestStops, DlTileMode::kClamp, &TestMatrix1); + ASSERT_EQ(source->asConicalGradient()->start_center(), TestPoints[0]); + ASSERT_EQ(source->asConicalGradient()->start_radius(), 10.0); + ASSERT_EQ(source->asConicalGradient()->end_center(), TestPoints[1]); + ASSERT_EQ(source->asConicalGradient()->end_radius(), 20.0); + ASSERT_EQ(source->asConicalGradient()->stop_count(), kTestStopCount); + for (int i = 0; i < kTestStopCount; i++) { + ASSERT_EQ(source->asConicalGradient()->colors()[i], TestColors[i]); + ASSERT_EQ(source->asConicalGradient()->stops()[i], TestStops[i]); + } + ASSERT_EQ(source->asConicalGradient()->tile_mode(), DlTileMode::kClamp); + ASSERT_EQ(source->asConicalGradient()->matrix(), TestMatrix1); + ASSERT_EQ(source->is_opaque(), true); +} + +TEST(DisplayListColorSource, AlphaConicalGradientContents) { + std::shared_ptr source = DlColorSource::MakeConical( + TestPoints[0], 10.0, TestPoints[1], 20.0, kTestStopCount, TestAlphaColors, + TestStops, DlTileMode::kClamp, &TestMatrix1); + ASSERT_EQ(source->asConicalGradient()->start_center(), TestPoints[0]); + ASSERT_EQ(source->asConicalGradient()->start_radius(), 10.0); + ASSERT_EQ(source->asConicalGradient()->end_center(), TestPoints[1]); + ASSERT_EQ(source->asConicalGradient()->end_radius(), 20.0); + ASSERT_EQ(source->asConicalGradient()->stop_count(), kTestStopCount); + for (int i = 0; i < kTestStopCount; i++) { + ASSERT_EQ(source->asConicalGradient()->colors()[i], TestAlphaColors[i]); + ASSERT_EQ(source->asConicalGradient()->stops()[i], TestStops[i]); + } + ASSERT_EQ(source->asConicalGradient()->tile_mode(), DlTileMode::kClamp); + ASSERT_EQ(source->asConicalGradient()->matrix(), TestMatrix1); + ASSERT_EQ(source->is_opaque(), false); +} + +TEST(DisplayListColorSource, ConicalGradientEquals) { + std::shared_ptr source1 = DlColorSource::MakeConical( + TestPoints[0], 10.0, TestPoints[1], 20.0, kTestStopCount, TestColors, + TestStops, DlTileMode::kClamp, &TestMatrix1); + std::shared_ptr source2 = DlColorSource::MakeConical( + TestPoints[0], 10.0, TestPoints[1], 20.0, kTestStopCount, TestColors, + TestStops, DlTileMode::kClamp, &TestMatrix1); + TestEquals(*source1, *source2); +} + +TEST(DisplayListColorSource, ConicalGradientNotEquals) { + std::shared_ptr source1 = DlColorSource::MakeConical( + TestPoints[0], 10.0, TestPoints[1], 20.0, kTestStopCount, TestColors, + TestStops, DlTileMode::kClamp, &TestMatrix1); + { + std::shared_ptr source2 = DlColorSource::MakeConical( + TestPoints2[0], 10.0, TestPoints[1], 20.0, kTestStopCount, TestColors, + TestStops, DlTileMode::kClamp, &TestMatrix1); + TestNotEquals(*source1, *source2, "Start Center differs"); + } + { + std::shared_ptr source2 = DlColorSource::MakeConical( + TestPoints[0], 15.0, TestPoints[1], 20.0, kTestStopCount, TestColors, + TestStops, DlTileMode::kClamp, &TestMatrix1); + TestNotEquals(*source1, *source2, "Start Radius differs"); + } + { + std::shared_ptr source2 = DlColorSource::MakeConical( + TestPoints[0], 10.0, TestPoints2[1], 20.0, kTestStopCount, TestColors, + TestStops, DlTileMode::kClamp, &TestMatrix1); + TestNotEquals(*source1, *source2, "End Center differs"); + } + { + std::shared_ptr source2 = DlColorSource::MakeConical( + TestPoints[0], 10.0, TestPoints[1], 25.0, kTestStopCount, TestColors, + TestStops, DlTileMode::kClamp, &TestMatrix1); + TestNotEquals(*source1, *source2, "End Radius differs"); + } + { + std::shared_ptr source2 = DlColorSource::MakeConical( + TestPoints[0], 10.0, TestPoints[1], 20.0, 2, TestColors, TestStops, + DlTileMode::kClamp, &TestMatrix1); + TestNotEquals(*source1, *source2, "Stop count differs"); + } + { + std::shared_ptr source2 = DlColorSource::MakeConical( + TestPoints[0], 10.0, TestPoints[1], 20.0, kTestStopCount, + TestAlphaColors, TestStops, DlTileMode::kClamp, &TestMatrix1); + TestNotEquals(*source1, *source2, "Colors differ"); + } + { + std::shared_ptr source2 = DlColorSource::MakeConical( + TestPoints[0], 10.0, TestPoints[1], 20.0, kTestStopCount, TestColors, + TestStops2, DlTileMode::kClamp, &TestMatrix1); + TestNotEquals(*source1, *source2, "Stops differ"); + } + { + std::shared_ptr source2 = DlColorSource::MakeConical( + TestPoints[0], 10.0, TestPoints[1], 20.0, kTestStopCount, TestColors, + TestStops, DlTileMode::kMirror, &TestMatrix1); + TestNotEquals(*source1, *source2, "Tile Mode differs"); + } + { + std::shared_ptr source2 = DlColorSource::MakeConical( + TestPoints[0], 10.0, TestPoints[1], 20.0, kTestStopCount, TestColors, + TestStops, DlTileMode::kClamp, &TestMatrix2); + TestNotEquals(*source1, *source2, "Matrix differs"); + } +} + +TEST(DisplayListColorSource, SweepGradientConstructor) { + std::shared_ptr source = DlColorSource::MakeSweep( + TestPoints[0], 10.0, 20.0, kTestStopCount, TestColors, TestStops, + DlTileMode::kClamp, &TestMatrix1); +} + +TEST(DisplayListColorSource, SweepGradientShared) { + std::shared_ptr source = DlColorSource::MakeSweep( + TestPoints[0], 10.0, 20.0, kTestStopCount, TestColors, TestStops, + DlTileMode::kClamp, &TestMatrix1); + ASSERT_NE(source->shared().get(), source.get()); + ASSERT_EQ(*source->shared().get(), *source.get()); +} + +TEST(DisplayListColorSource, SweepGradientAsSweep) { + std::shared_ptr source = DlColorSource::MakeSweep( + TestPoints[0], 10.0, 20.0, kTestStopCount, TestColors, TestStops, + DlTileMode::kClamp, &TestMatrix1); + ASSERT_NE(source->asSweepGradient(), nullptr); + ASSERT_EQ(source->asSweepGradient(), source.get()); + + ASSERT_EQ(source->asColor(), nullptr); + ASSERT_EQ(source->asImage(), nullptr); + ASSERT_EQ(source->asLinearGradient(), nullptr); + ASSERT_EQ(source->asRadialGradient(), nullptr); + ASSERT_EQ(source->asConicalGradient(), nullptr); +} + +TEST(DisplayListColorSource, SweepGradientContents) { + std::shared_ptr source = DlColorSource::MakeSweep( + TestPoints[0], 10.0, 20.0, kTestStopCount, TestColors, TestStops, + DlTileMode::kClamp, &TestMatrix1); + ASSERT_EQ(source->asSweepGradient()->center(), TestPoints[0]); + ASSERT_EQ(source->asSweepGradient()->start(), 10.0); + ASSERT_EQ(source->asSweepGradient()->end(), 20.0); + ASSERT_EQ(source->asSweepGradient()->stop_count(), kTestStopCount); + for (int i = 0; i < kTestStopCount; i++) { + ASSERT_EQ(source->asSweepGradient()->colors()[i], TestColors[i]); + ASSERT_EQ(source->asSweepGradient()->stops()[i], TestStops[i]); + } + ASSERT_EQ(source->asSweepGradient()->tile_mode(), DlTileMode::kClamp); + ASSERT_EQ(source->asSweepGradient()->matrix(), TestMatrix1); + ASSERT_EQ(source->is_opaque(), true); +} + +TEST(DisplayListColorSource, AlphaSweepGradientContents) { + std::shared_ptr source = DlColorSource::MakeSweep( + TestPoints[0], 10.0, 20.0, kTestStopCount, TestAlphaColors, TestStops, + DlTileMode::kClamp, &TestMatrix1); + ASSERT_EQ(source->asSweepGradient()->center(), TestPoints[0]); + ASSERT_EQ(source->asSweepGradient()->start(), 10.0); + ASSERT_EQ(source->asSweepGradient()->end(), 20.0); + ASSERT_EQ(source->asSweepGradient()->stop_count(), kTestStopCount); + for (int i = 0; i < kTestStopCount; i++) { + ASSERT_EQ(source->asSweepGradient()->colors()[i], TestAlphaColors[i]); + ASSERT_EQ(source->asSweepGradient()->stops()[i], TestStops[i]); + } + ASSERT_EQ(source->asSweepGradient()->tile_mode(), DlTileMode::kClamp); + ASSERT_EQ(source->asSweepGradient()->matrix(), TestMatrix1); + ASSERT_EQ(source->is_opaque(), false); +} + +TEST(DisplayListColorSource, SweepGradientEquals) { + std::shared_ptr source1 = DlColorSource::MakeSweep( + TestPoints[0], 10.0, 20.0, kTestStopCount, TestColors, TestStops, + DlTileMode::kClamp, &TestMatrix1); + std::shared_ptr source2 = DlColorSource::MakeSweep( + TestPoints[0], 10.0, 20.0, kTestStopCount, TestColors, TestStops, + DlTileMode::kClamp, &TestMatrix1); + TestEquals(*source1, *source2); +} + +TEST(DisplayListColorSource, SweepGradientNotEquals) { + std::shared_ptr source1 = DlColorSource::MakeSweep( + TestPoints[0], 10.0, 20.0, kTestStopCount, TestColors, TestStops, + DlTileMode::kClamp, &TestMatrix1); + { + std::shared_ptr source2 = DlColorSource::MakeSweep( + TestPoints2[0], 10.0, 20.0, kTestStopCount, TestColors, TestStops, + DlTileMode::kClamp, &TestMatrix1); + TestNotEquals(*source1, *source2, "Center differs"); + } + { + std::shared_ptr source2 = DlColorSource::MakeSweep( + TestPoints[0], 15.0, 20.0, kTestStopCount, TestColors, TestStops, + DlTileMode::kClamp, &TestMatrix1); + TestNotEquals(*source1, *source2, "Start Angle differs"); + } + { + std::shared_ptr source2 = DlColorSource::MakeSweep( + TestPoints[0], 10.0, 25.0, kTestStopCount, TestColors, TestStops, + DlTileMode::kClamp, &TestMatrix1); + TestNotEquals(*source1, *source2, "End Angle differs"); + } + { + std::shared_ptr source2 = DlColorSource::MakeSweep( + TestPoints[0], 10.0, 20.0, 2, TestColors, TestStops, // + DlTileMode::kClamp, &TestMatrix1); + TestNotEquals(*source1, *source2, "Stop count differs"); + } + { + std::shared_ptr source2 = DlColorSource::MakeSweep( + TestPoints[0], 10.0, 20.0, kTestStopCount, TestAlphaColors, TestStops, + DlTileMode::kClamp, &TestMatrix1); + TestNotEquals(*source1, *source2, "Colors differ"); + } + { + std::shared_ptr source2 = DlColorSource::MakeSweep( + TestPoints[0], 10.0, 20.0, kTestStopCount, TestColors, TestStops2, + DlTileMode::kClamp, &TestMatrix1); + TestNotEquals(*source1, *source2, "Stops differ"); + } + { + std::shared_ptr source2 = DlColorSource::MakeSweep( + TestPoints[0], 10.0, 20.0, kTestStopCount, TestColors, TestStops, + DlTileMode::kMirror, &TestMatrix1); + TestNotEquals(*source1, *source2, "Tile Mode differs"); + } + { + std::shared_ptr source2 = DlColorSource::MakeSweep( + TestPoints[0], 10.0, 20.0, kTestStopCount, TestColors, TestStops, + DlTileMode::kClamp, &TestMatrix2); + TestNotEquals(*source1, *source2, "Matrix differs"); + } +} + +TEST(DisplayListColorSource, UnknownConstructor) { + DlUnknownColorSource source(TestUnknownShader); +} + +TEST(DisplayListColorSource, UnknownShared) { + DlUnknownColorSource source(TestUnknownShader); + ASSERT_NE(source.shared().get(), &source); + ASSERT_EQ(*source.shared(), source); +} + +TEST(DisplayListColorSource, UnknownAsNone) { + DlUnknownColorSource source(TestUnknownShader); + ASSERT_EQ(source.asColor(), nullptr); + ASSERT_EQ(source.asImage(), nullptr); + ASSERT_EQ(source.asLinearGradient(), nullptr); + ASSERT_EQ(source.asRadialGradient(), nullptr); + ASSERT_EQ(source.asConicalGradient(), nullptr); + ASSERT_EQ(source.asSweepGradient(), nullptr); +} + +TEST(DisplayListColorSource, UnknownContents) { + DlUnknownColorSource source(TestUnknownShader); + ASSERT_EQ(source.skia_object(), TestUnknownShader); + // Blend shaders always return false for is_opaque. + // See: https://bugs.chromium.org/p/skia/issues/detail?id=13046 + ASSERT_EQ(source.is_opaque(), false); +} + +TEST(DisplayListColorSource, AlphaUnknownContents) { + DlUnknownColorSource source(TestAlphaUnknownShader); + ASSERT_EQ(source.skia_object(), TestAlphaUnknownShader); + ASSERT_EQ(source.is_opaque(), false); +} + +TEST(DisplayListColorSource, UnknownEquals) { + DlUnknownColorSource source1(TestUnknownShader); + DlUnknownColorSource source2(TestUnknownShader); + TestEquals(source1, source2); +} + +TEST(DisplayListColorSource, UnknownNotEquals) { + DlUnknownColorSource source1(TestUnknownShader); + DlUnknownColorSource source2(TestAlphaUnknownShader); + TestNotEquals(source1, source2, "SkShader differs"); +} + +} // namespace testing +} // namespace flutter diff --git a/display_list/display_list_comparable.h b/display_list/display_list_comparable.h index d88b2e5d21ea0..5d3c6e99d3f7d 100644 --- a/display_list/display_list_comparable.h +++ b/display_list/display_list_comparable.h @@ -28,35 +28,42 @@ bool Equals(const T* a, const T* b) { template bool Equals(std::shared_ptr a, const T* b) { - if (!a) { - return !b; - } - if (!b) { - return false; - } - if (a.get() == b) { - return true; - } - return *a.get() == *b; + return Equals(a.get(), b); +} + +template +bool Equals(std::shared_ptr a, const T* b) { + return Equals(a.get(), b); } template bool Equals(const T* a, std::shared_ptr b) { - return Equals(b, a); + return Equals(a, b.get()); +} + +template +bool Equals(const T* a, std::shared_ptr b) { + return Equals(a, b.get()); } template bool Equals(std::shared_ptr a, std::shared_ptr b) { - if (!a) { - return !b; - } - if (!b) { - return false; - } - if (a.get() == b.get()) { - return true; - } - return *a.get() == *b.get(); + return Equals(a.get(), b.get()); +} + +template +bool Equals(std::shared_ptr a, std::shared_ptr b) { + return Equals(a.get(), b.get()); +} + +template +bool Equals(std::shared_ptr a, std::shared_ptr b) { + return Equals(a.get(), b.get()); +} + +template +bool Equals(std::shared_ptr a, std::shared_ptr b) { + return Equals(a.get(), b.get()); } template @@ -66,17 +73,42 @@ bool NotEquals(const T* a, const T* b) { template bool NotEquals(std::shared_ptr a, const T* b) { - return !Equals(a, b); + return !Equals(a.get(), b); +} + +template +bool NotEquals(std::shared_ptr a, const T* b) { + return !Equals(a.get(), b); } template bool NotEquals(const T* a, std::shared_ptr b) { - return !Equals(b, a); + return !Equals(a, b.get()); +} + +template +bool NotEquals(const T* a, std::shared_ptr b) { + return !Equals(a, b.get()); } template bool NotEquals(std::shared_ptr a, std::shared_ptr b) { - return !Equals(a, b); + return !Equals(a.get(), b.get()); +} + +template +bool NotEquals(std::shared_ptr a, std::shared_ptr b) { + return !Equals(a.get(), b.get()); +} + +template +bool NotEquals(std::shared_ptr a, std::shared_ptr b) { + return !Equals(a.get(), b.get()); +} + +template +bool NotEquals(std::shared_ptr a, std::shared_ptr b) { + return !Equals(a.get(), b.get()); } } // namespace flutter diff --git a/display_list/display_list_complexity_helper.h b/display_list/display_list_complexity_helper.h index 1a37d6188c27d..4e34b62bc1faa 100644 --- a/display_list/display_list_complexity_helper.h +++ b/display_list/display_list_complexity_helper.h @@ -108,7 +108,7 @@ class ComplexityCalculatorHelper void setColor(SkColor color) override {} void setBlendMode(SkBlendMode mode) override {} void setBlender(sk_sp blender) override {} - void setShader(sk_sp shader) override {} + void setColorSource(const DlColorSource* source) override {} void setImageFilter(sk_sp filter) override {} void setColorFilter(const DlColorFilter* filter) override {} void setPathEffect(sk_sp effect) override {} diff --git a/display_list/display_list_dispatcher.h b/display_list/display_list_dispatcher.h index c0f99ff090c44..1166c84acb39f 100644 --- a/display_list/display_list_dispatcher.h +++ b/display_list/display_list_dispatcher.h @@ -7,6 +7,7 @@ #include "flutter/display_list/display_list.h" #include "flutter/display_list/display_list_color_filter.h" +#include "flutter/display_list/display_list_color_source.h" #include "flutter/display_list/display_list_mask_filter.h" namespace flutter { @@ -37,7 +38,7 @@ class Dispatcher { virtual void setStrokeMiter(SkScalar limit) = 0; virtual void setStrokeCap(SkPaint::Cap cap) = 0; virtual void setStrokeJoin(SkPaint::Join join) = 0; - virtual void setShader(sk_sp shader) = 0; + virtual void setColorSource(const DlColorSource* source) = 0; virtual void setColorFilter(const DlColorFilter* filter) = 0; // setInvertColors does not exist in SkPaint, but is a quick way to set // a ColorFilter that inverts the rgb values of all rendered colors. diff --git a/display_list/display_list_enum_unittests.cc b/display_list/display_list_enum_unittests.cc new file mode 100644 index 0000000000000..a45542b0f05b4 --- /dev/null +++ b/display_list/display_list_enum_unittests.cc @@ -0,0 +1,27 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/display_list/display_list_tile_mode.h" +#include "flutter/display_list/types.h" +#include "gtest/gtest.h" + +namespace flutter { +namespace testing { + +TEST(DisplayListEnum, ToDlTileMode) { + ASSERT_EQ(ToDl(SkTileMode::kClamp), DlTileMode::kClamp); + ASSERT_EQ(ToDl(SkTileMode::kRepeat), DlTileMode::kRepeat); + ASSERT_EQ(ToDl(SkTileMode::kMirror), DlTileMode::kMirror); + ASSERT_EQ(ToDl(SkTileMode::kDecal), DlTileMode::kDecal); +} + +TEST(DisplayListEnum, ToSkTileMode) { + ASSERT_EQ(ToSk(DlTileMode::kClamp), SkTileMode::kClamp); + ASSERT_EQ(ToSk(DlTileMode::kRepeat), SkTileMode::kRepeat); + ASSERT_EQ(ToSk(DlTileMode::kMirror), SkTileMode::kMirror); + ASSERT_EQ(ToSk(DlTileMode::kDecal), SkTileMode::kDecal); +} + +} // namespace testing +} // namespace flutter diff --git a/display_list/display_list_mask_filter.h b/display_list/display_list_mask_filter.h index ff0afa7d60d33..56233421a9638 100644 --- a/display_list/display_list_mask_filter.h +++ b/display_list/display_list_mask_filter.h @@ -84,8 +84,8 @@ class DlBlurMaskFilter final : public DlMaskFilter { protected: bool equals_(DlMaskFilter const& other) const override { FML_DCHECK(other.type() == DlMaskFilterType::kBlur); - auto that = static_cast(other); - return style_ == that.style_ && sigma_ == that.sigma_; + auto that = static_cast(&other); + return style_ == that->style_ && sigma_ == that->sigma_; } private: diff --git a/display_list/display_list_mask_filter_unittests.cc b/display_list/display_list_mask_filter_unittests.cc index a0389621e8325..ea79eee36fb6f 100644 --- a/display_list/display_list_mask_filter_unittests.cc +++ b/display_list/display_list_mask_filter_unittests.cc @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "flutter/display_list/display_list_attributes_testing.h" +#include "flutter/display_list/display_list_builder.h" #include "flutter/display_list/display_list_comparable.h" #include "flutter/display_list/display_list_mask_filter.h" #include "flutter/display_list/types.h" @@ -10,6 +12,18 @@ namespace flutter { namespace testing { +TEST(DisplayListMaskFilter, BuilderSetGet) { + DlBlurMaskFilter filter(SkBlurStyle::kNormal_SkBlurStyle, 5.0); + DisplayListBuilder builder; + ASSERT_EQ(builder.getMaskFilter(), nullptr); + builder.setMaskFilter(&filter); + ASSERT_NE(builder.getMaskFilter(), nullptr); + ASSERT_TRUE( + Equals(builder.getMaskFilter(), static_cast(&filter))); + builder.setMaskFilter(nullptr); + ASSERT_EQ(builder.getMaskFilter(), nullptr); +} + TEST(DisplayListMaskFilter, FromSkiaNullFilter) { std::shared_ptr filter = DlMaskFilter::From(nullptr); ASSERT_EQ(filter, nullptr); @@ -21,6 +35,7 @@ TEST(DisplayListMaskFilter, FromSkiaBlurFilter) { SkMaskFilter::MakeBlur(SkBlurStyle::kNormal_SkBlurStyle, 5.0); std::shared_ptr filter = DlMaskFilter::From(sk_filter); ASSERT_EQ(filter->type(), DlMaskFilterType::kUnknown); + // We cannot recapture the blur parameters from an SkBlurMaskFilter ASSERT_EQ(filter->asBlur(), nullptr); ASSERT_EQ(filter->skia_object(), sk_filter); } @@ -50,24 +65,15 @@ TEST(DisplayListMaskFilter, BlurContents) { TEST(DisplayListMaskFilter, BlurEquals) { DlBlurMaskFilter filter1(SkBlurStyle::kNormal_SkBlurStyle, 5.0); DlBlurMaskFilter filter2(SkBlurStyle::kNormal_SkBlurStyle, 5.0); - ASSERT_TRUE(filter1 == filter2); - ASSERT_TRUE(filter2 == filter1); - ASSERT_FALSE(filter1 != filter2); - ASSERT_FALSE(filter2 != filter1); - ASSERT_EQ(filter1, filter2); + TestEquals(filter1, filter2); } TEST(DisplayListMaskFilter, BlurNotEquals) { DlBlurMaskFilter filter1(SkBlurStyle::kNormal_SkBlurStyle, 5.0); DlBlurMaskFilter filter2(SkBlurStyle::kInner_SkBlurStyle, 5.0); DlBlurMaskFilter filter3(SkBlurStyle::kNormal_SkBlurStyle, 6.0); - ASSERT_FALSE(filter1 == filter2); - ASSERT_FALSE(filter2 == filter1); - ASSERT_TRUE(filter1 != filter2); - ASSERT_TRUE(filter2 != filter1); - ASSERT_NE(filter1, filter2); - ASSERT_NE(filter2, filter3); - ASSERT_NE(filter3, filter1); + TestNotEquals(filter1, filter2, "Blur style differs"); + TestNotEquals(filter1, filter3, "blur radius differs"); } TEST(DisplayListMaskFilter, UnknownConstructor) { @@ -95,11 +101,7 @@ TEST(DisplayListMaskFilter, UnknownEquals) { SkMaskFilter::MakeBlur(SkBlurStyle::kNormal_SkBlurStyle, 5.0); DlUnknownMaskFilter filter1(sk_filter); DlUnknownMaskFilter filter2(sk_filter); - ASSERT_TRUE(filter1 == filter2); - ASSERT_TRUE(filter2 == filter1); - ASSERT_FALSE(filter1 != filter2); - ASSERT_FALSE(filter2 != filter1); - ASSERT_EQ(filter1, filter2); + TestEquals(filter1, filter2); } TEST(DisplayListMaskFilter, UnknownNotEquals) { @@ -110,11 +112,7 @@ TEST(DisplayListMaskFilter, UnknownNotEquals) { SkMaskFilter::MakeBlur(SkBlurStyle::kNormal_SkBlurStyle, 5.0)); DlUnknownMaskFilter filter2( SkMaskFilter::MakeBlur(SkBlurStyle::kNormal_SkBlurStyle, 5.0)); - ASSERT_TRUE(filter1 != filter2); - ASSERT_TRUE(filter2 != filter1); - ASSERT_FALSE(filter1 == filter2); - ASSERT_FALSE(filter2 == filter1); - ASSERT_NE(filter1, filter2); + TestNotEquals(filter1, filter2, "SkMaskFilter instance differs"); } void testEquals(DlMaskFilter* a, DlMaskFilter* b) { diff --git a/display_list/display_list_ops.h b/display_list/display_list_ops.h index e077790b7b7fd..c0afd30d3df35 100644 --- a/display_list/display_list_ops.h +++ b/display_list/display_list_ops.h @@ -175,7 +175,6 @@ struct SetBlendModeOp final : DLOp { } \ }; DEFINE_SET_CLEAR_SKREF_OP(Blender, blender) -DEFINE_SET_CLEAR_SKREF_OP(Shader, shader) DEFINE_SET_CLEAR_SKREF_OP(ImageFilter, filter) DEFINE_SET_CLEAR_SKREF_OP(PathEffect, effect) #undef DEFINE_SET_CLEAR_SKREF_OP @@ -189,7 +188,7 @@ DEFINE_SET_CLEAR_SKREF_OP(PathEffect, effect) // SetSk: 4 byte header + an sk_sp (ptr) uses 16 bytes due to the // alignment of the ptr. // (4 bytes unused) -#define DEFINE_SET_CLEAR_DLATTR_OP(name, field) \ +#define DEFINE_SET_CLEAR_DLATTR_OP(name, sk_name, field) \ struct Clear##name##Op final : DLOp { \ static const auto kType = DisplayListOpType::kClear##name; \ \ @@ -199,10 +198,10 @@ DEFINE_SET_CLEAR_SKREF_OP(PathEffect, effect) dispatcher.set##name(nullptr); \ } \ }; \ - struct Set##name##Op final : DLOp { \ - static const auto kType = DisplayListOpType::kSet##name; \ + struct SetPod##name##Op final : DLOp { \ + static const auto kType = DisplayListOpType::kSetPod##name; \ \ - Set##name##Op() {} \ + SetPod##name##Op() {} \ \ void dispatch(Dispatcher& dispatcher) const { \ const Dl##name* filter = reinterpret_cast(this + 1); \ @@ -212,19 +211,39 @@ DEFINE_SET_CLEAR_SKREF_OP(PathEffect, effect) struct SetSk##name##Op final : DLOp { \ static const auto kType = DisplayListOpType::kSetSk##name; \ \ - SetSk##name##Op(sk_sp field) : field(field) {} \ + SetSk##name##Op(sk_sp field) : field(field) {} \ \ - sk_sp field; \ + sk_sp field; \ \ void dispatch(Dispatcher& dispatcher) const { \ DlUnknown##name dl_filter(field); \ dispatcher.set##name(&dl_filter); \ } \ }; -DEFINE_SET_CLEAR_DLATTR_OP(ColorFilter, filter) -DEFINE_SET_CLEAR_DLATTR_OP(MaskFilter, filter) +DEFINE_SET_CLEAR_DLATTR_OP(ColorFilter, ColorFilter, filter) +DEFINE_SET_CLEAR_DLATTR_OP(MaskFilter, MaskFilter, filter) +DEFINE_SET_CLEAR_DLATTR_OP(ColorSource, Shader, source) #undef DEFINE_SET_CLEAR_DLATTR_OP +// 4 byte header + 80 bytes for the embedded DlImageColorSource +// uses 84 total bytes (4 bytes unused) +struct SetImageColorSourceOp : DLOp { + static const auto kType = DisplayListOpType::kSetImageColorSource; + + SetImageColorSourceOp(const DlImageColorSource* source) + : source(source->image(), + source->horizontal_tile_mode(), + source->vertical_tile_mode(), + source->sampling(), + source->matrix_ptr()) {} + + const DlImageColorSource source; + + void dispatch(Dispatcher& dispatcher) const { + dispatcher.setColorSource(&source); + } +}; + // 4 byte header + no payload uses minimum 8 bytes (4 bytes unused) struct SaveOp final : DLOp { static const auto kType = DisplayListOpType::kSave; diff --git a/display_list/display_list_tile_mode.h b/display_list/display_list_tile_mode.h new file mode 100644 index 0000000000000..0be9b54ae307d --- /dev/null +++ b/display_list/display_list_tile_mode.h @@ -0,0 +1,43 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_DISPLAY_LIST_DISPLAY_LIST_TILE_MODE_H_ +#define FLUTTER_DISPLAY_LIST_DISPLAY_LIST_TILE_MODE_H_ + +#include "third_party/skia/include/core/SkTileMode.h" + +namespace flutter { + +// An enum to define how to repeat, fold, or omit colors outside of the +// typically defined range of the source of the colors (such as the +// bounds of an image or the defining geoetry of a gradient). +enum class DlTileMode { + // Replicate the edge color if the |DlColorSource| draws outside of the + // defined bounds. + kClamp, + + // Repeat the |DlColorSource|'s defined colors both horizontally and + // vertically (or both along and perpendicular to a gradient's geometry). + kRepeat, + + // Repeat the |DlColorSource|'s colors horizontally and vertically, + // alternating mirror images so that adjacent images always seam. + kMirror, + + // Only draw within the original domain, return transparent-black everywhere + // else. + kDecal, +}; + +inline DlTileMode ToDl(SkTileMode sk_mode) { + return static_cast(sk_mode); +} + +inline SkTileMode ToSk(DlTileMode dl_mode) { + return static_cast(dl_mode); +} + +} // namespace flutter + +#endif // FLUTTER_DISPLAY_LIST_DISPLAY_LIST_TILE_MODE_H_ diff --git a/display_list/display_list_unittests.cc b/display_list/display_list_unittests.cc index dbef1917449fb..2b6b090de6bd4 100644 --- a/display_list/display_list_unittests.cc +++ b/display_list/display_list_unittests.cc @@ -32,6 +32,8 @@ constexpr float stops[] = { 0.5, 1.0, }; +std::vector color_vector(colors, colors + 3); +std::vector stops_vector(stops, stops + 3); // clang-format off constexpr float rotate_color_matrix[20] = { @@ -59,39 +61,69 @@ constexpr SkPoint TestPoints[] = { }; #define TestPointCount sizeof(TestPoints) / (sizeof(TestPoints[0])) +static sk_sp MakeTestImage(int w, int h, int checker_size) { + sk_sp surface = SkSurface::MakeRasterN32Premul(w, h); + SkCanvas* canvas = surface->getCanvas(); + SkPaint p0, p1; + p0.setStyle(SkPaint::kFill_Style); + p0.setColor(SK_ColorGREEN); + p1.setStyle(SkPaint::kFill_Style); + p1.setColor(SK_ColorBLUE); + p1.setAlpha(128); + for (int y = 0; y < w; y += checker_size) { + for (int x = 0; x < h; x += checker_size) { + SkPaint& cellp = ((x + y) & 1) == 0 ? p0 : p1; + canvas->drawRect(SkRect::MakeXYWH(x, y, checker_size, checker_size), + cellp); + } + } + return surface->makeImageSnapshot(); +} + +static sk_sp TestImage1 = MakeTestImage(40, 40, 5); +static sk_sp TestImage2 = MakeTestImage(50, 50, 5); + static const sk_sp TestBlender1 = SkBlenders::Arithmetic(0.2, 0.2, 0.2, 0.2, false); static const sk_sp TestBlender2 = SkBlenders::Arithmetic(0.2, 0.2, 0.2, 0.2, true); static const sk_sp TestBlender3 = SkBlenders::Arithmetic(0.3, 0.3, 0.3, 0.3, true); -static const sk_sp TestShader1 = - SkGradientShader::MakeLinear(end_points, - colors, - stops, - 3, - SkTileMode::kMirror, - 0, - nullptr); -// TestShader2 is identical to TestShader1 and points out that we cannot -// perform a deep compare over our various sk_sp objects because the -// DisplayLists constructed with the two do not compare == below. -static const sk_sp TestShader2 = - SkGradientShader::MakeLinear(end_points, - colors, - stops, - 3, - SkTileMode::kMirror, - 0, - nullptr); -static const sk_sp TestShader3 = - SkGradientShader::MakeLinear(end_points, - colors, - stops, - 3, - SkTileMode::kDecal, - 0, - nullptr); +static const DlImageColorSource TestSource1(TestImage1, + DlTileMode::kClamp, + DlTileMode::kMirror, + DisplayList::LinearSampling); +static const std::shared_ptr TestSource2 = + DlColorSource::MakeLinear(end_points[0], + end_points[1], + 3, + colors, + stops, + DlTileMode::kMirror); +static const std::shared_ptr TestSource3 = + DlColorSource::MakeRadial(end_points[0], + 10.0, + 3, + colors, + stops, + DlTileMode::kMirror); +static const std::shared_ptr TestSource4 = + DlColorSource::MakeConical(end_points[0], + 10.0, + end_points[1], + 200.0, + 3, + colors, + stops, + DlTileMode::kDecal); +static const std::shared_ptr TestSource5 = + DlColorSource::MakeSweep(end_points[0], + 0.0, + 360.0, + 3, + colors, + stops, + DlTileMode::kDecal); static const sk_sp TestImageFilter1 = SkImageFilters::Blur(5.0, 5.0, SkTileMode::kDecal, nullptr, nullptr); static const sk_sp TestImageFilter2 = @@ -129,27 +161,6 @@ static const SkPath TestPath3 = static const SkMatrix TestMatrix1 = SkMatrix::Scale(2, 2); static const SkMatrix TestMatrix2 = SkMatrix::RotateDeg(45); -static sk_sp MakeTestImage(int w, int h, int checker_size) { - sk_sp surface = SkSurface::MakeRasterN32Premul(w, h); - SkCanvas* canvas = surface->getCanvas(); - SkPaint p0, p1; - p0.setStyle(SkPaint::kFill_Style); - p0.setColor(SK_ColorGREEN); - p1.setStyle(SkPaint::kFill_Style); - p1.setColor(SK_ColorBLUE); - p1.setAlpha(128); - for (int y = 0; y < w; y += checker_size) { - for (int x = 0; x < h; x += checker_size) { - SkPaint& cellp = ((x + y) & 1) == 0 ? p0 : p1; - canvas->drawRect(SkRect::MakeXYWH(x, y, checker_size, checker_size), - cellp); - } - } - return surface->makeImageSnapshot(); -} -static sk_sp TestImage1 = MakeTestImage(40, 40, 5); -static sk_sp TestImage2 = MakeTestImage(50, 50, 5); - static sk_sp TestVertices1 = SkVertices::MakeCopy(SkVertices::kTriangles_VertexMode, 3, @@ -336,11 +347,13 @@ std::vector allGroups = { {0, 0, 0, 0, [](DisplayListBuilder& b) {b.setBlender(nullptr);}}, } }, - { "SetShader", { - {0, 16, 0, 0, [](DisplayListBuilder& b) {b.setShader(TestShader1);}}, - {0, 16, 0, 0, [](DisplayListBuilder& b) {b.setShader(TestShader2);}}, - {0, 16, 0, 0, [](DisplayListBuilder& b) {b.setShader(TestShader3);}}, - {0, 0, 0, 0, [](DisplayListBuilder& b) {b.setShader(nullptr);}}, + { "SetColorSource", { + {0, 112, 0, 0, [](DisplayListBuilder& b) {b.setColorSource(&TestSource1);}}, + {0, 80 + 6 * 4, 0, 0, [](DisplayListBuilder& b) {b.setColorSource(TestSource2.get());}}, + {0, 80 + 6 * 4, 0, 0, [](DisplayListBuilder& b) {b.setColorSource(TestSource3.get());}}, + {0, 88 + 6 * 4, 0, 0, [](DisplayListBuilder& b) {b.setColorSource(TestSource4.get());}}, + {0, 80 + 6 * 4, 0, 0, [](DisplayListBuilder& b) {b.setColorSource(TestSource5.get());}}, + {0, 0, 0, 0, [](DisplayListBuilder& b) {b.setColorSource(nullptr);}}, } }, { "SetImageFilter", { @@ -1287,26 +1300,6 @@ TEST(DisplayList, DisplayListBlenderRefHandling) { ASSERT_TRUE(tester.ref_is_unique()); } -TEST(DisplayList, DisplayListShaderRefHandling) { - class ShaderRefTester : public virtual AttributeRefTester { - public: - void setRefToPaint(SkPaint& paint) const override { - paint.setShader(shader); - } - void setRefToDisplayList(DisplayListBuilder& builder) const override { - builder.setShader(shader); - } - bool ref_is_unique() const override { return shader->unique(); } - - private: - sk_sp shader = SkShaders::Color(SK_ColorBLUE); - }; - - ShaderRefTester tester; - tester.test(); - ASSERT_TRUE(tester.ref_is_unique()); -} - TEST(DisplayList, DisplayListPathEffectRefHandling) { class PathEffectRefTester : public virtual AttributeRefTester { public: diff --git a/display_list/display_list_utils.cc b/display_list/display_list_utils.cc index e6a293fe4a0dc..1674d2de57823 100644 --- a/display_list/display_list_utils.cc +++ b/display_list/display_list_utils.cc @@ -73,8 +73,8 @@ void SkPaintDispatchHelper::setBlendMode(SkBlendMode mode) { void SkPaintDispatchHelper::setBlender(sk_sp blender) { paint_.setBlender(blender); } -void SkPaintDispatchHelper::setShader(sk_sp shader) { - paint_.setShader(shader); +void SkPaintDispatchHelper::setColorSource(const DlColorSource* source) { + paint_.setShader(source ? source->skia_object() : nullptr); } void SkPaintDispatchHelper::setImageFilter(sk_sp filter) { paint_.setImageFilter(filter); diff --git a/display_list/display_list_utils.h b/display_list/display_list_utils.h index 3bf3b1dee7365..643b8e1e73676 100644 --- a/display_list/display_list_utils.h +++ b/display_list/display_list_utils.h @@ -54,7 +54,7 @@ class IgnoreAttributeDispatchHelper : public virtual Dispatcher { void setColor(SkColor color) override {} void setBlendMode(SkBlendMode mode) override {} void setBlender(sk_sp blender) override {} - void setShader(sk_sp shader) override {} + void setColorSource(const DlColorSource* source) override {} void setImageFilter(sk_sp filter) override {} void setColorFilter(const DlColorFilter* filter) override {} void setPathEffect(sk_sp effect) override {} @@ -177,7 +177,7 @@ class SkPaintDispatchHelper : public virtual Dispatcher { void setStrokeMiter(SkScalar limit) override; void setStrokeCap(SkPaint::Cap cap) override; void setStrokeJoin(SkPaint::Join join) override; - void setShader(sk_sp shader) override; + void setColorSource(const DlColorSource* source) override; void setColorFilter(const DlColorFilter* filter) override; void setInvertColors(bool invert) override; void setBlendMode(SkBlendMode mode) override; diff --git a/lib/ui/compositing/scene_builder.cc b/lib/ui/compositing/scene_builder.cc index a791a93d775e2..d3a4cb3e81fc8 100644 --- a/lib/ui/compositing/scene_builder.cc +++ b/lib/ui/compositing/scene_builder.cc @@ -226,7 +226,8 @@ void SceneBuilder::pushShaderMask(Dart_Handle layer_handle, maskRectBottom); auto sampling = ImageFilter::SamplingFromIndex(filterQualityIndex); auto layer = std::make_shared( - shader->shader(sampling), rect, static_cast(blendMode)); + shader->shader(sampling)->skia_object(), rect, + static_cast(blendMode)); PushLayer(layer); EngineLayer::MakeRetained(layer_handle, layer); diff --git a/lib/ui/painting/fragment_program.cc b/lib/ui/painting/fragment_program.cc index 9156302789ea8..5e476bb85f41d 100644 --- a/lib/ui/painting/fragment_program.cc +++ b/lib/ui/painting/fragment_program.cc @@ -72,11 +72,12 @@ fml::RefPtr FragmentProgram::shader( uniforms.Release(); std::vector> sk_samplers(sampler_shaders.size()); for (size_t i = 0; i < sampler_shaders.size(); i++) { + SkSamplingOptions sampling; ImageShader* image_shader = sampler_shaders[i]; // The default value for SkSamplingOptions is used because ImageShader // uses a cached value set by the user in the Dart constructor. // Users are instructed to make use of this in the Dart docs. - sk_samplers[i] = image_shader->shader(SkSamplingOptions()); + sk_samplers[i] = image_shader->shader(sampling)->skia_object(); uniform_floats[uniform_count + 2 * i] = image_shader->width(); uniform_floats[uniform_count + 2 * i + 1] = image_shader->height(); } diff --git a/lib/ui/painting/fragment_shader.cc b/lib/ui/painting/fragment_shader.cc index c72460f54fc00..f40ce89eefa52 100644 --- a/lib/ui/painting/fragment_shader.cc +++ b/lib/ui/painting/fragment_shader.cc @@ -33,10 +33,11 @@ void FragmentShader::RegisterNatives(tonic::DartLibraryNatives* natives) { natives->Register({}); } -sk_sp FragmentShader::shader(SkSamplingOptions sampling) { +std::shared_ptr FragmentShader::shader( + SkSamplingOptions& sampling) { // Sampling options are ignored, since sampling options don't make sense for // generative shaders. - return shader_; + return source_; } fml::RefPtr FragmentShader::Create(Dart_Handle dart_handle, @@ -47,7 +48,7 @@ fml::RefPtr FragmentShader::Create(Dart_Handle dart_handle, } FragmentShader::FragmentShader(sk_sp shader) - : shader_(std::move(shader)) {} + : source_(DlColorSource::From(shader)) {} FragmentShader::~FragmentShader() = default; diff --git a/lib/ui/painting/fragment_shader.h b/lib/ui/painting/fragment_shader.h index 446116a2edf7a..c3ff8851256bf 100644 --- a/lib/ui/painting/fragment_shader.h +++ b/lib/ui/painting/fragment_shader.h @@ -32,14 +32,14 @@ class FragmentShader : public Shader { static fml::RefPtr Create(Dart_Handle dart_handle, sk_sp shader); - sk_sp shader(SkSamplingOptions) override; + std::shared_ptr shader(SkSamplingOptions&) override; static void RegisterNatives(tonic::DartLibraryNatives* natives); private: explicit FragmentShader(sk_sp shader); - sk_sp shader_; + std::shared_ptr source_; }; } // namespace flutter diff --git a/lib/ui/painting/gradient.cc b/lib/ui/painting/gradient.cc index 0d2d2fc3ddb96..7c7fce84afbb1 100644 --- a/lib/ui/painting/gradient.cc +++ b/lib/ui/painting/gradient.cc @@ -58,10 +58,14 @@ void CanvasGradient::initLinear(const tonic::Float32List& end_points, sk_matrix = ToSkMatrix(matrix4); } - sk_shader_ = UIDartState::CreateGPUObject(SkGradientShader::MakeLinear( - reinterpret_cast(end_points.data()), - reinterpret_cast(colors.data()), color_stops.data(), - colors.num_elements(), tile_mode, 0, has_matrix ? &sk_matrix : nullptr)); + SkPoint p0 = SkPoint::Make(end_points[0], end_points[1]); + SkPoint p1 = SkPoint::Make(end_points[2], end_points[3]); + const uint32_t* colors_array = + reinterpret_cast(colors.data()); + + dl_shader_ = DlColorSource::MakeLinear( + p0, p1, colors.num_elements(), colors_array, color_stops.data(), + ToDl(tile_mode), has_matrix ? &sk_matrix : nullptr); } void CanvasGradient::initRadial(double center_x, @@ -83,10 +87,13 @@ void CanvasGradient::initRadial(double center_x, sk_matrix = ToSkMatrix(matrix4); } - sk_shader_ = UIDartState::CreateGPUObject(SkGradientShader::MakeRadial( - SkPoint::Make(center_x, center_y), radius, - reinterpret_cast(colors.data()), color_stops.data(), - colors.num_elements(), tile_mode, 0, has_matrix ? &sk_matrix : nullptr)); + const uint32_t* colors_array = + reinterpret_cast(colors.data()); + + dl_shader_ = DlColorSource::MakeRadial( + SkPoint::Make(center_x, center_y), radius, colors.num_elements(), + colors_array, color_stops.data(), ToDl(tile_mode), + has_matrix ? &sk_matrix : nullptr); } void CanvasGradient::initSweep(double center_x, @@ -109,11 +116,13 @@ void CanvasGradient::initSweep(double center_x, sk_matrix = ToSkMatrix(matrix4); } - sk_shader_ = UIDartState::CreateGPUObject(SkGradientShader::MakeSweep( - center_x, center_y, reinterpret_cast(colors.data()), - color_stops.data(), colors.num_elements(), tile_mode, - start_angle * 180.0 / M_PI, end_angle * 180.0 / M_PI, 0, - has_matrix ? &sk_matrix : nullptr)); + const uint32_t* colors_array = + reinterpret_cast(colors.data()); + + dl_shader_ = DlColorSource::MakeSweep( + SkPoint::Make(center_x, center_y), start_angle * 180.0 / M_PI, + end_angle * 180.0 / M_PI, colors.num_elements(), colors_array, + color_stops.data(), ToDl(tile_mode), has_matrix ? &sk_matrix : nullptr); } void CanvasGradient::initTwoPointConical(double start_x, @@ -138,13 +147,14 @@ void CanvasGradient::initTwoPointConical(double start_x, sk_matrix = ToSkMatrix(matrix4); } - sk_shader_ = - UIDartState::CreateGPUObject(SkGradientShader::MakeTwoPointConical( - SkPoint::Make(start_x, start_y), start_radius, - SkPoint::Make(end_x, end_y), end_radius, - reinterpret_cast(colors.data()), color_stops.data(), - colors.num_elements(), tile_mode, 0, - has_matrix ? &sk_matrix : nullptr)); + const uint32_t* colors_array = + reinterpret_cast(colors.data()); + + dl_shader_ = DlColorSource::MakeConical( + SkPoint::Make(start_x, start_y), start_radius, // + SkPoint::Make(end_x, end_y), end_radius, // + colors.num_elements(), colors_array, color_stops.data(), // + ToDl(tile_mode), has_matrix ? &sk_matrix : nullptr); } CanvasGradient::CanvasGradient() = default; diff --git a/lib/ui/painting/gradient.h b/lib/ui/painting/gradient.h index cc0a0cf27d590..a50048d48e2b4 100644 --- a/lib/ui/painting/gradient.h +++ b/lib/ui/painting/gradient.h @@ -5,10 +5,9 @@ #ifndef FLUTTER_LIB_UI_PAINTING_GRADIENT_H_ #define FLUTTER_LIB_UI_PAINTING_GRADIENT_H_ -#include "flutter/lib/ui/dart_wrapper.h" +#include "flutter/display_list/display_list_color_source.h" #include "flutter/lib/ui/painting/matrix.h" #include "flutter/lib/ui/painting/shader.h" -#include "third_party/skia/include/effects/SkGradientShader.h" #include "third_party/tonic/typed_data/typed_list.h" namespace tonic { @@ -62,15 +61,15 @@ class CanvasGradient : public Shader { SkTileMode tile_mode, const tonic::Float64List& matrix4); - sk_sp shader(SkSamplingOptions) override { - return sk_shader_.skia_object(); + std::shared_ptr shader(SkSamplingOptions& sampling) override { + return dl_shader_->with_sampling(sampling); } static void RegisterNatives(tonic::DartLibraryNatives* natives); private: CanvasGradient(); - flutter::SkiaGPUObject sk_shader_; + std::shared_ptr dl_shader_; }; } // namespace flutter diff --git a/lib/ui/painting/image_shader.cc b/lib/ui/painting/image_shader.cc index 60d08af12a8c9..59cde339b5d4f 100644 --- a/lib/ui/painting/image_shader.cc +++ b/lib/ui/painting/image_shader.cc @@ -46,28 +46,29 @@ void ImageShader::initWithImage(CanvasImage* image, return; } sk_image_ = UIDartState::CreateGPUObject(image->image()); - tmx_ = tmx; - tmy_ = tmy; - local_matrix_ = ToSkMatrix(matrix4); - if (filter_quality_index >= 0) { - cached_sampling_ = ImageFilter::SamplingFromIndex(filter_quality_index); - sampling_is_locked_ = true; - } else { - sampling_is_locked_ = false; - } + SkMatrix local_matrix = ToSkMatrix(matrix4); + sampling_is_locked_ = filter_quality_index >= 0; + SkSamplingOptions sampling = + sampling_is_locked_ ? ImageFilter::SamplingFromIndex(filter_quality_index) + : DisplayList::LinearSampling; + cached_shader_ = UIDartState::CreateGPUObject(sk_make_sp( + sk_image_.skia_object(), ToDl(tmx), ToDl(tmy), sampling, &local_matrix)); } -sk_sp ImageShader::shader(SkSamplingOptions sampling) { +std::shared_ptr ImageShader::shader( + SkSamplingOptions& sampling) { if (sampling_is_locked_) { - sampling = cached_sampling_; - } - if (!cached_shader_.skia_object() || cached_sampling_ != sampling) { - cached_sampling_ = sampling; - cached_shader_ = - UIDartState::CreateGPUObject(sk_image_.skia_object()->makeShader( - tmx_, tmy_, sampling, &local_matrix_)); + sampling = cached_shader_.skia_object()->sampling(); } - return cached_shader_.skia_object(); + // It might seem that if the sampling is locked we can just return the + // cached version, but since we need to hold the cached shader in a + // Skia GPU wrapper, and that wrapper requires an sk_sp<>, we are holding + // an sk_sp<> version of the shared object and we need a shared_ptr version. + // So, either way, we need the with_sampling() method to shared_ptr'ify + // our copy. + // If we can get rid of the need for the GPU unref queue, then this can all + // be simplified down to just a shared_ptr. + return cached_shader_.skia_object()->with_sampling(sampling); } int ImageShader::width() { diff --git a/lib/ui/painting/image_shader.h b/lib/ui/painting/image_shader.h index 6383f5ebce4de..cc54419f4a374 100644 --- a/lib/ui/painting/image_shader.h +++ b/lib/ui/painting/image_shader.h @@ -34,7 +34,7 @@ class ImageShader : public Shader { int filter_quality_index, const tonic::Float64List& matrix4); - sk_sp shader(SkSamplingOptions) override; + std::shared_ptr shader(SkSamplingOptions&) override; static void RegisterNatives(tonic::DartLibraryNatives* natives); @@ -45,13 +45,9 @@ class ImageShader : public Shader { ImageShader(); flutter::SkiaGPUObject sk_image_; - SkTileMode tmx_; - SkTileMode tmy_; - SkMatrix local_matrix_; bool sampling_is_locked_; - SkSamplingOptions cached_sampling_; - flutter::SkiaGPUObject cached_shader_; + flutter::SkiaGPUObject cached_shader_; }; } // namespace flutter diff --git a/lib/ui/painting/paint.cc b/lib/ui/painting/paint.cc index ffe7b58c4be96..4aa339bf5ea13 100644 --- a/lib/ui/painting/paint.cc +++ b/lib/ui/painting/paint.cc @@ -98,7 +98,7 @@ const SkPaint* Paint::paint(SkPaint& paint) const { Shader* decoded = tonic::DartConverter::FromDart(shader); auto sampling = ImageFilter::SamplingFromIndex(uint_data[kFilterQualityIndex]); - paint.setShader(decoded->shader(sampling)); + paint.setShader(decoded->shader(sampling)->skia_object()); } Dart_Handle color_filter = values[kColorFilterIndex]; @@ -196,7 +196,7 @@ bool Paint::sync_to(DisplayListBuilder* builder, Dart_Handle values[kObjectCount]; if (Dart_IsNull(paint_objects_)) { if (flags.applies_shader()) { - builder->setShader(nullptr); + builder->setColorSource(nullptr); } if (flags.applies_color_filter()) { builder->setColorFilter(nullptr); @@ -218,12 +218,12 @@ bool Paint::sync_to(DisplayListBuilder* builder, if (flags.applies_shader()) { Dart_Handle shader = values[kShaderIndex]; if (Dart_IsNull(shader)) { - builder->setShader(nullptr); + builder->setColorSource(nullptr); } else { Shader* decoded = tonic::DartConverter::FromDart(shader); auto sampling = ImageFilter::SamplingFromIndex(uint_data[kFilterQualityIndex]); - builder->setShader(decoded->shader(sampling)); + builder->setColorSource(decoded->shader(sampling).get()); } } diff --git a/lib/ui/painting/shader.h b/lib/ui/painting/shader.h index 25c1d7aed550a..8fefefbedc9bb 100644 --- a/lib/ui/painting/shader.h +++ b/lib/ui/painting/shader.h @@ -5,10 +5,8 @@ #ifndef FLUTTER_LIB_UI_PAINTING_SHADER_H_ #define FLUTTER_LIB_UI_PAINTING_SHADER_H_ -#include "flutter/flow/skia_gpu_object.h" -#include "flutter/lib/ui/dart_wrapper.h" +#include "flutter/display_list/display_list_color_source.h" #include "flutter/lib/ui/ui_dart_state.h" -#include "third_party/skia/include/core/SkShader.h" namespace flutter { @@ -19,13 +17,10 @@ class Shader : public RefCountedDartWrappable { public: ~Shader() override; - virtual sk_sp shader(SkSamplingOptions) = 0; + virtual std::shared_ptr shader(SkSamplingOptions&) = 0; protected: Shader() {} - - private: - // flutter::SkiaGPUObject shader_; }; } // namespace flutter