DisplayList DlMaskFilter objects (flutter/engine#31535)

This commit is contained in:
Jim Graham 2022-02-18 09:19:09 -08:00 committed by GitHub
parent 10a516124b
commit 3b5ec940af
20 changed files with 664 additions and 249 deletions

2
DEPS
View File

@ -110,7 +110,7 @@ deps = {
'src': 'https://github.com/flutter/buildroot.git' + '@' + '79643299bd052c53631b8b200bb582e8badb2708',
'src/flutter/impeller':
Var('github_git') + '/flutter/impeller' + '@' + '78bc2a026c554c444b2e67b36fd44cd548341a51',
Var('github_git') + '/flutter/impeller' + '@' + '2793516e27224b16e572138cb7cb18cc6b22adc7',
# Fuchsia compatibility
#

View File

@ -55,6 +55,7 @@ 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_comparable.h
FILE: ../../../flutter/display_list/display_list_complexity.cc
FILE: ../../../flutter/display_list/display_list_complexity.h
FILE: ../../../flutter/display_list/display_list_complexity_gl.cc
@ -67,6 +68,9 @@ FILE: ../../../flutter/display_list/display_list_dispatcher.cc
FILE: ../../../flutter/display_list/display_list_dispatcher.h
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
FILE: ../../../flutter/display_list/display_list_mask_filter.h
FILE: ../../../flutter/display_list/display_list_mask_filter_unittests.cc
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

View File

@ -26,6 +26,8 @@ source_set("display_list") {
"display_list_dispatcher.h",
"display_list_flags.cc",
"display_list_flags.h",
"display_list_mask_filter.cc",
"display_list_mask_filter.h",
"display_list_ops.cc",
"display_list_ops.h",
"display_list_utils.cc",
@ -48,6 +50,7 @@ source_set("unittests") {
"display_list_canvas_unittests.cc",
"display_list_color_filter_unittests.cc",
"display_list_complexity_unittests.cc",
"display_list_mask_filter_unittests.cc",
"display_list_test_utils.cc",
"display_list_test_utils.h",
"display_list_unittests.cc",

View File

@ -87,10 +87,7 @@ namespace flutter {
\
V(ClearMaskFilter) \
V(SetMaskFilter) \
V(SetMaskBlurFilterNormal) \
V(SetMaskBlurFilterSolid) \
V(SetMaskBlurFilterOuter) \
V(SetMaskBlurFilterInner) \
V(SetSkMaskFilter) \
\
V(Save) \
V(SaveLayer) \

View File

@ -136,15 +136,9 @@ void DisplayListBuilder::onSetImageFilter(sk_sp<SkImageFilter> filter) {
}
void DisplayListBuilder::onSetColorFilter(const DlColorFilter* filter) {
if (filter == nullptr) {
if (!current_color_filter_) {
return;
}
current_color_filter_ = nullptr;
Push<ClearColorFilterOp>(0, 0);
} else {
if (current_color_filter_ && *current_color_filter_ == *filter) {
return;
}
current_color_filter_ = filter->shared();
switch (filter->type()) {
case DlColorFilter::kBlend: {
@ -172,8 +166,7 @@ void DisplayListBuilder::onSetColorFilter(const DlColorFilter* filter) {
break;
}
case DlColorFilter::kUnknown: {
const sk_sp<SkColorFilter> sk_filter = filter->sk_filter();
Push<SetSkColorFilterOp>(0, 0, sk_filter);
Push<SetSkColorFilterOp>(0, 0, filter->sk_filter());
break;
}
}
@ -185,32 +178,24 @@ void DisplayListBuilder::onSetPathEffect(sk_sp<SkPathEffect> effect) {
? Push<SetPathEffectOp>(0, 0, std::move(effect))
: Push<ClearPathEffectOp>(0, 0);
}
void DisplayListBuilder::onSetMaskFilter(sk_sp<SkMaskFilter> filter) {
current_mask_sigma_ = kInvalidSigma;
(current_mask_filter_ = filter) //
? Push<SetMaskFilterOp>(0, 0, std::move(filter))
: Push<ClearMaskFilterOp>(0, 0);
}
void DisplayListBuilder::onSetMaskBlurFilter(SkBlurStyle style,
SkScalar sigma) {
// Valid sigma is checked by setMaskBlurFilter
FML_DCHECK(mask_sigma_valid(sigma));
current_mask_filter_ = nullptr;
current_mask_style_ = style;
current_mask_sigma_ = sigma;
switch (style) {
case kNormal_SkBlurStyle:
Push<SetMaskBlurFilterNormalOp>(0, 0, sigma);
break;
case kSolid_SkBlurStyle:
Push<SetMaskBlurFilterSolidOp>(0, 0, sigma);
break;
case kOuter_SkBlurStyle:
Push<SetMaskBlurFilterOuterOp>(0, 0, sigma);
break;
case kInner_SkBlurStyle:
Push<SetMaskBlurFilterInnerOp>(0, 0, sigma);
break;
void DisplayListBuilder::onSetMaskFilter(const DlMaskFilter* filter) {
if (filter == nullptr) {
current_mask_filter_ = nullptr;
Push<ClearMaskFilterOp>(0, 0);
} else {
current_mask_filter_ = filter->shared();
switch (filter->type()) {
case DlMaskFilter::kBlur: {
const DlBlurMaskFilter* blur_filter = filter->asBlur();
FML_DCHECK(blur_filter);
void* pod = Push<SetMaskFilterOp>(blur_filter->size(), 0);
new (pod) DlBlurMaskFilter(blur_filter);
break;
}
case DlMaskFilter::kUnknown:
Push<SetSkMaskFilterOp>(0, 0, filter->sk_filter());
break;
}
}
}
@ -252,11 +237,7 @@ void DisplayListBuilder::setAttributesFromPaint(
// that is composed with the paint's color filter.
setInvertColors(false);
SkColorFilter* color_filter = paint.getColorFilter();
if (color_filter) {
setColorFilter(DlColorFilter::From(color_filter).get());
} else {
setColorFilter(nullptr);
}
setColorFilter(DlColorFilter::From(color_filter).get());
}
if (flags.applies_image_filter()) {
setImageFilter(sk_ref_sp(paint.getImageFilter()));
@ -265,7 +246,8 @@ void DisplayListBuilder::setAttributesFromPaint(
setPathEffect(sk_ref_sp(paint.getPathEffect()));
}
if (flags.applies_mask_filter()) {
setMaskFilter(sk_ref_sp(paint.getMaskFilter()));
SkMaskFilter* mask_filter = paint.getMaskFilter();
setMaskFilter(DlMaskFilter::From(mask_filter).get());
}
}

View File

@ -6,6 +6,7 @@
#define FLUTTER_DISPLAY_LIST_DISPLAY_LIST_BUILDER_H_
#include "flutter/display_list/display_list.h"
#include "flutter/display_list/display_list_comparable.h"
#include "flutter/display_list/display_list_dispatcher.h"
#include "flutter/display_list/display_list_flags.h"
#include "flutter/display_list/types.h"
@ -94,27 +95,18 @@ class DisplayListBuilder final : public virtual Dispatcher,
}
}
void setColorFilter(const DlColorFilter* filter) override {
// onSetColorFilter will deal with whether the filter is new
onSetColorFilter(filter);
if (NotEquals(current_color_filter_, filter)) {
onSetColorFilter(filter);
}
}
void setPathEffect(sk_sp<SkPathEffect> effect) override {
if (current_path_effect_ != effect) {
onSetPathEffect(std::move(effect));
}
}
void setMaskFilter(sk_sp<SkMaskFilter> filter) override {
if (mask_sigma_valid(current_mask_sigma_) ||
current_mask_filter_ != filter) {
onSetMaskFilter(std::move(filter));
}
}
void setMaskBlurFilter(SkBlurStyle style, SkScalar sigma) override {
if (!mask_sigma_valid(sigma)) {
// SkMastFilter::MakeBlur(invalid sigma) returns a nullptr, so we
// reset the mask filter here rather than recording the invalid values.
setMaskFilter(nullptr);
} else if (current_mask_style_ != style || current_mask_sigma_ != sigma) {
onSetMaskBlurFilter(style, sigma);
void setMaskFilter(const DlMaskFilter* filter) override {
if (NotEquals(current_mask_filter_, filter)) {
onSetMaskFilter(filter);
}
}
@ -127,8 +119,8 @@ class DisplayListBuilder final : public virtual Dispatcher,
SkPaint::Cap getStrokeCap() const { return current_stroke_cap_; }
SkPaint::Join getStrokeJoin() const { return current_stroke_join_; }
sk_sp<SkShader> getShader() const { return current_shader_; }
sk_sp<SkColorFilter> getColorFilter() const {
return current_color_filter_->sk_filter();
std::shared_ptr<const DlColorFilter> getColorFilter() const {
return current_color_filter_;
}
bool isInvertColors() const { return current_invert_colors_; }
std::optional<SkBlendMode> getBlendMode() const {
@ -143,14 +135,9 @@ class DisplayListBuilder final : public virtual Dispatcher,
: SkBlender::Mode(current_blend_mode_);
}
sk_sp<SkPathEffect> getPathEffect() const { return current_path_effect_; }
sk_sp<SkMaskFilter> getMaskFilter() const {
return mask_sigma_valid(current_mask_sigma_)
? SkMaskFilter::MakeBlur(current_mask_style_,
current_mask_sigma_)
: current_mask_filter_;
std::shared_ptr<const DlMaskFilter> getMaskFilter() const {
return current_mask_filter_;
}
// No utility getter for the utility setter:
// void setMaskBlurFilter (SkBlurStyle style, SkScalar sigma)
sk_sp<SkImageFilter> getImageFilter() const { return current_image_filter_; }
void save() override;
@ -393,7 +380,7 @@ class DisplayListBuilder final : public virtual Dispatcher,
void onSetImageFilter(sk_sp<SkImageFilter> filter);
void onSetColorFilter(const DlColorFilter* filter);
void onSetPathEffect(sk_sp<SkPathEffect> effect);
void onSetMaskFilter(sk_sp<SkMaskFilter> filter);
void onSetMaskFilter(const DlMaskFilter* filter);
void onSetMaskBlurFilter(SkBlurStyle style, SkScalar sigma);
// These values should match the defaults of the Dart Paint object.
@ -413,9 +400,7 @@ class DisplayListBuilder final : public virtual Dispatcher,
std::shared_ptr<const DlColorFilter> current_color_filter_;
sk_sp<SkImageFilter> current_image_filter_;
sk_sp<SkPathEffect> current_path_effect_;
sk_sp<SkMaskFilter> current_mask_filter_;
SkBlurStyle current_mask_style_;
SkScalar current_mask_sigma_ = kInvalidSigma;
std::shared_ptr<const DlMaskFilter> current_mask_filter_;
};
} // namespace flutter

View File

@ -1237,8 +1237,7 @@ class CanvasCompareTester {
}
{
sk_sp<SkMaskFilter> filter =
SkMaskFilter::MakeBlur(kNormal_SkBlurStyle, 5.0);
const DlBlurMaskFilter filter(kNormal_SkBlurStyle, 5.0);
BoundsTolerance blur5Tolerance = tolerance.addBoundsPadding(4, 4);
{
// Stroked primitives need some non-trivial stroke size to be blurred
@ -1247,30 +1246,13 @@ class CanvasCompareTester {
"MaskFilter == Blur 5",
[=](SkCanvas*, SkPaint& p) {
p.setStrokeWidth(5.0);
p.setMaskFilter(filter);
p.setMaskFilter(filter.sk_filter());
},
[=](DisplayListBuilder& b) {
b.setStrokeWidth(5.0);
b.setMaskFilter(filter);
b.setMaskFilter(&filter);
}));
}
EXPECT_TRUE(testP.is_draw_text_blob() || filter->unique())
<< "MaskFilter == Blur 5 Cleanup";
{
RenderWith(testP, env, blur5Tolerance,
CaseParameters(
"MaskFilter == Blur(Normal, 5.0)",
[=](SkCanvas*, SkPaint& p) {
p.setStrokeWidth(5.0);
p.setMaskFilter(filter);
},
[=](DisplayListBuilder& b) {
b.setStrokeWidth(5.0);
b.setMaskBlurFilter(kNormal_SkBlurStyle, 5.0);
}));
}
EXPECT_TRUE(testP.is_draw_text_blob() || filter->unique())
<< "MaskFilter == Blur(Normal, 5.0) Cleanup";
}
{

View File

@ -111,12 +111,6 @@ class DlColorFilter {
// pixels non-transparent and therefore expand the bounds.
virtual bool modifies_transparent_black() const = 0;
// Return a shared version of a DlColorFilter pointer, or nullptr if the
// pointer is null.
static std::shared_ptr<DlColorFilter> Shared(const DlColorFilter* filter) {
return filter == nullptr ? nullptr : filter->shared();
}
// Return a shared version of |this| ColorFilter. The |shared_ptr| returned
// will reference a copy of this object so that the lifetime of the shared
// version is not tied to the storage of this particular instance.

View File

@ -19,6 +19,7 @@ static const float matrix[20] = {
TEST(DisplayListColorFilter, FromSkiaNullFilter) {
std::shared_ptr<DlColorFilter> filter = DlColorFilter::From(nullptr);
ASSERT_EQ(filter, nullptr);
ASSERT_EQ(filter.get(), nullptr);
}
TEST(DisplayListColorFilter, FromSkiaBlendFilter) {
@ -75,6 +76,7 @@ TEST(DisplayListColorFilter, FromSkiaUnrecognizedFilter) {
ASSERT_EQ(filter->type(), DlColorFilter::kUnknown);
ASSERT_EQ(filter->asBlend(), nullptr);
ASSERT_EQ(filter->asMatrix(), nullptr);
ASSERT_EQ(filter->sk_filter(), sk_filter);
}
TEST(DisplayListColorFilter, BlendConstructor) {
@ -88,8 +90,7 @@ TEST(DisplayListColorFilter, BlendShared) {
}
TEST(DisplayListColorFilter, BlendAsBlend) {
DlBlendColorFilter filter =
DlBlendColorFilter(SK_ColorRED, SkBlendMode::kDstATop);
DlBlendColorFilter filter(SK_ColorRED, SkBlendMode::kDstATop);
ASSERT_NE(filter.asBlend(), nullptr);
ASSERT_EQ(filter.asBlend(), &filter);
}

View File

@ -0,0 +1,84 @@
// 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_COMPARABLE_H_
#define FLUTTER_DISPLAY_LIST_DISPLAY_LIST_COMPARABLE_H_
#include "flutter/display_list/types.h"
namespace flutter {
// These templates implement deep pointer comparisons that compare not
// just the pointers to the objects, but also their contents (provided
// that the <T> class implements the == operator override).
// Any combination of shared_ptr<T> or T* are supported and null pointers
// are not equal to anything but another null pointer.
template <class T>
bool Equals(const T* a, const T* b) {
if (a == b) {
return true;
}
if (!a || !b) {
return false;
}
return *a == *b;
}
template <class T>
bool Equals(std::shared_ptr<const T> a, const T* b) {
if (!a) {
return !b;
}
if (!b) {
return false;
}
if (a.get() == b) {
return true;
}
return *a.get() == *b;
}
template <class T>
bool Equals(const T* a, std::shared_ptr<const T> b) {
return Equals(b, a);
}
template <class T>
bool Equals(std::shared_ptr<const T> a, std::shared_ptr<const T> b) {
if (!a) {
return !b;
}
if (!b) {
return false;
}
if (a.get() == b.get()) {
return true;
}
return *a.get() == *b.get();
}
template <class T>
bool NotEquals(const T* a, const T* b) {
return !Equals<T>(a, b);
}
template <class T>
bool NotEquals(std::shared_ptr<const T> a, const T* b) {
return !Equals<T>(a, b);
}
template <class T>
bool NotEquals(const T* a, std::shared_ptr<const T> b) {
return !Equals<T>(b, a);
}
template <class T>
bool NotEquals(std::shared_ptr<const T> a, std::shared_ptr<const T> b) {
return !Equals(a, b);
}
} // namespace flutter
#endif // FLUTTER_DISPLAY_LIST_DISPLAY_LIST_COMPARABLE_H_

View File

@ -115,8 +115,7 @@ class ComplexityCalculatorHelper
void setImageFilter(sk_sp<SkImageFilter> filter) override {}
void setColorFilter(const DlColorFilter* filter) override {}
void setPathEffect(sk_sp<SkPathEffect> effect) override {}
void setMaskFilter(sk_sp<SkMaskFilter> filter) override {}
void setMaskBlurFilter(SkBlurStyle style, SkScalar sigma) override {}
void setMaskFilter(const DlMaskFilter* filter) override {}
void save() override {}
// We accumulate the cost of restoring a saveLayer() in saveLayer()

View File

@ -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_mask_filter.h"
namespace flutter {
@ -46,12 +47,7 @@ class Dispatcher {
virtual void setBlendMode(SkBlendMode mode) = 0;
virtual void setBlender(sk_sp<SkBlender> blender) = 0;
virtual void setPathEffect(sk_sp<SkPathEffect> effect) = 0;
virtual void setMaskFilter(sk_sp<SkMaskFilter> filter) = 0;
// setMaskBlurFilter is a quick way to set the parameters for a
// mask blur filter without constructing an SkMaskFilter object.
// It is equivalent to setMaskFilter(SkMaskFilter::MakeBlur(style, sigma)).
// To reset the filter use setMaskFilter(nullptr).
virtual void setMaskBlurFilter(SkBlurStyle style, SkScalar sigma) = 0;
virtual void setMaskFilter(const DlMaskFilter* filter) = 0;
virtual void setImageFilter(sk_sp<SkImageFilter> filter) = 0;
// All of the following methods are nearly 1:1 with their counterparts

View File

@ -0,0 +1,18 @@
// 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_mask_filter.h"
namespace flutter {
std::shared_ptr<DlMaskFilter> DlMaskFilter::From(SkMaskFilter* sk_filter) {
if (sk_filter == nullptr) {
return nullptr;
}
// There are no inspection methods for SkMaskFilter so we cannot break
// the Skia filter down into a specific subclass (i.e. Blur).
return std::make_shared<DlUnknownMaskFilter>(sk_ref_sp(sk_filter));
}
} // namespace flutter

View File

@ -0,0 +1,212 @@
// 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_MASK_FILTER_H_
#define FLUTTER_DISPLAY_LIST_DISPLAY_LIST_MASK_FILTER_H_
#include "flutter/display_list/types.h"
#include "flutter/fml/logging.h"
namespace flutter {
class DlBlurMaskFilter;
// The DisplayList MaskFilter class. This class was designed to be:
//
// - Typed:
// Even though most references and pointers are passed around as the
// base class, a DlMaskFilter::Type can be queried using the |type|
// method to determine which type of MaskFilter is being used.
//
// - Inspectable:
// Any parameters required to full specify the filtering operations are
// provided on the specific base classes.
//
// - Safely Downcast:
// For the subclasses that have specific data to query, methods |asBlur|
// are provided to safely downcast the reference for inspection.
//
// - Skiafiable:
// The classes override an |sk_filter| method to easily obtain a Skia
// version of the filter on demand.
//
// - Immutable:
// Neither the base class or any of the subclasses specify any mutation
// methods. Instances are often passed around as const as a reminder,
// but the classes have no mutation methods anyway.
//
// - Flat and Embeddable:
// Bulk freed + bulk compared + zero memory fragmentation.
//
// All of these classes are designed to be stored in the DisplayList
// buffer allocated in-line with the rest of the data to avoid dangling
// pointers that require explicit freeing when the DisplayList goes
// away, or that fragment the memory needed to read the operations in
// the DisplayList. Furthermore, the data in the classes can be bulk
// compared using a |memcmp| when performing a |DisplayList::Equals|.
//
// - Passed by Pointer:
// The data shared via the |Dispatcher::setMaskFilter| call is stored
// in the buffer itself and so its lifetime is controlled by the
// DisplayList. That memory cannot be shared as by a |shared_ptr|
// because the memory may be freed outside the control of the shared
// pointer. Creating a shared version of the object would require a
// new instantiation which we'd like to avoid on every dispatch call,
// so a raw (const) pointer is shared instead with all of the
// responsibilities of non-ownership in the called method.
//
// But, for methods that need to keep a copy of the data...
//
// - Shared_Ptr-able:
// The classes support a method to return a |std::shared_ptr| version of
// themselves, safely instantiating a new copy of the object into a
// shared_ptr using |std::make_shared|. For those dispatcher objects
// that may want to hold on to the contents of the object (typically
// in a |current_mask_filter_| field), they can obtain a shared_ptr
// copy safely and easily using the |shared| method.
class DlMaskFilter {
public:
// An enumerated type for the recognized MaskFilter operations.
// If a custom MaskFilter outside of the recognized types is needed
// then a |kUnknown| type that simply defers to an SkMaskFilter is
// provided as a fallback.
enum Type { kBlur, kUnknown };
// Return a shared_ptr holding a DlMaskFilter representing the indicated
// Skia SkMaskFilter pointer.
//
// Since there is no public SkBlurMaskFilter and since the SkMaskFilter
// class provides no |asABlur| style type inference methods, we cannot
// infer any specific data from the SkMaskFilter. As a result, the return
// value in this case will always be nullptr or DlUnknownMaskFilter.
static std::shared_ptr<DlMaskFilter> From(SkMaskFilter* sk_filter);
// Return a shared_ptr holding a DlMaskFilter representing the indicated
// Skia SkMaskFilter pointer.
//
// Since there is no public SkBlurMaskFilter and since the SkMaskFilter
// class provides no |asABlur| style type inference methods, we cannot
// infer any specific data from the SkMaskFilter. As a result, the return
// value in this case will always be nullptr or DlUnknownMaskFilter.
static std::shared_ptr<DlMaskFilter> From(sk_sp<SkMaskFilter> sk_filter) {
return From(sk_filter.get());
}
// Return the recognized type of the MaskFilter operation.
virtual Type type() const = 0;
// Return the size of the instantiated data (typically used to allocate)
// storage in the DisplayList buffer.
virtual size_t size() const = 0;
// Return a shared version of |this| MaskFilter. The |shared_ptr| returned
// will reference a copy of this object so that the lifetime of the shared
// version is not tied to the storage of this particular instance.
virtual std::shared_ptr<DlMaskFilter> shared() const = 0;
// Return an equivalent |SkMaskFilter| version of this object.
virtual sk_sp<SkMaskFilter> sk_filter() const = 0;
// Return a DlBlurMaskFilter pointer to this object iff it is a Blur
// type of MaskFilter, otherwise return nullptr.
virtual const DlBlurMaskFilter* asBlur() const { return nullptr; }
// Perform a content aware |==| comparison of the MaskFilter.
bool operator==(DlMaskFilter const& other) const {
return type() == other.type() && equals_(other);
}
// Perform a content aware |!=| comparison of the ColorFilter.
bool operator!=(DlMaskFilter const& other) const { return !(*this == other); }
virtual ~DlMaskFilter() = default;
protected:
// Virtual comparison method to support |==| and |!=|.
virtual bool equals_(DlMaskFilter const& other) const = 0;
};
// The Blur type of MaskFilter which specifies modifying the
// colors as if the color specified in the Blur filter is the
// source color and the color drawn by the rendering operation
// is the destination color. The mode parameter of the Blur
// filter is then used to combine those colors.
class DlBlurMaskFilter final : public DlMaskFilter {
public:
DlBlurMaskFilter(SkBlurStyle style, SkScalar sigma)
: style_(style), sigma_(sigma) {}
DlBlurMaskFilter(const DlBlurMaskFilter& filter)
: DlBlurMaskFilter(filter.style_, filter.sigma_) {}
DlBlurMaskFilter(const DlBlurMaskFilter* filter)
: DlBlurMaskFilter(filter->style_, filter->sigma_) {}
Type type() const override { return kBlur; }
size_t size() const override { return sizeof(*this); }
std::shared_ptr<DlMaskFilter> shared() const override {
return std::make_shared<DlBlurMaskFilter>(this);
}
sk_sp<SkMaskFilter> sk_filter() const override {
return SkMaskFilter::MakeBlur(style_, sigma_);
}
const DlBlurMaskFilter* asBlur() const override { return this; }
SkBlurStyle style() const { return style_; }
SkScalar sigma() const { return sigma_; }
protected:
bool equals_(DlMaskFilter const& other) const override {
FML_DCHECK(other.type() == kBlur);
auto that = static_cast<DlBlurMaskFilter const&>(other);
return style_ == that.style_ && sigma_ == that.sigma_;
}
private:
SkBlurStyle style_;
SkScalar sigma_;
};
// A wrapper class for a Skia MaskFilter of unknown type. The above 4 types
// are the only types that can be constructed by Flutter using the
// ui.MaskFilter class so this class should be rarely used. The main use
// would come from the |DisplayListCanvasRecorder| recording Skia rendering
// calls that originated outside of the Flutter dart code. This would
// primarily happen in the Paragraph code that renders the text using the
// SkCanvas interface which we capture into DisplayList data structures.
class DlUnknownMaskFilter final : public DlMaskFilter {
public:
DlUnknownMaskFilter(sk_sp<SkMaskFilter> sk_filter)
: sk_filter_(std::move(sk_filter)) {}
DlUnknownMaskFilter(const DlUnknownMaskFilter& filter)
: DlUnknownMaskFilter(filter.sk_filter_) {}
DlUnknownMaskFilter(const DlUnknownMaskFilter* filter)
: DlUnknownMaskFilter(filter->sk_filter_) {}
Type type() const override { return kUnknown; }
size_t size() const override { return sizeof(*this); }
std::shared_ptr<DlMaskFilter> shared() const override {
return std::make_shared<DlUnknownMaskFilter>(this);
}
sk_sp<SkMaskFilter> sk_filter() const override { return sk_filter_; }
virtual ~DlUnknownMaskFilter() = default;
protected:
bool equals_(const DlMaskFilter& other) const override {
FML_DCHECK(other.type() == kUnknown);
auto that = static_cast<DlUnknownMaskFilter const&>(other);
return sk_filter_ == that.sk_filter_;
}
private:
sk_sp<SkMaskFilter> sk_filter_;
};
} // namespace flutter
#endif // FLUTTER_DISPLAY_LIST_DISPLAY_LIST_MASK_FILTER_H_

View File

@ -0,0 +1,223 @@
// 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_comparable.h"
#include "flutter/display_list/display_list_mask_filter.h"
#include "flutter/display_list/types.h"
#include "gtest/gtest.h"
namespace flutter {
namespace testing {
TEST(DisplayListMaskFilter, FromSkiaNullFilter) {
std::shared_ptr<DlMaskFilter> filter = DlMaskFilter::From(nullptr);
ASSERT_EQ(filter, nullptr);
ASSERT_EQ(filter.get(), nullptr);
}
TEST(DisplayListMaskFilter, FromSkiaBlurFilter) {
sk_sp<SkMaskFilter> sk_filter =
SkMaskFilter::MakeBlur(SkBlurStyle::kNormal_SkBlurStyle, 5.0);
std::shared_ptr<DlMaskFilter> filter = DlMaskFilter::From(sk_filter);
ASSERT_EQ(filter->type(), DlMaskFilter::kUnknown);
ASSERT_EQ(filter->asBlur(), nullptr);
ASSERT_EQ(filter->sk_filter(), sk_filter);
}
TEST(DisplayListMaskFilter, BlurConstructor) {
DlBlurMaskFilter filter(SkBlurStyle::kNormal_SkBlurStyle, 5.0);
}
TEST(DisplayListMaskFilter, BlurShared) {
DlBlurMaskFilter filter(SkBlurStyle::kNormal_SkBlurStyle, 5.0);
ASSERT_NE(filter.shared().get(), &filter);
ASSERT_EQ(*filter.shared(), filter);
}
TEST(DisplayListMaskFilter, BlurAsBlur) {
DlBlurMaskFilter filter(SkBlurStyle::kNormal_SkBlurStyle, 5.0);
ASSERT_NE(filter.asBlur(), nullptr);
ASSERT_EQ(filter.asBlur(), &filter);
}
TEST(DisplayListMaskFilter, BlurContents) {
DlBlurMaskFilter filter(SkBlurStyle::kNormal_SkBlurStyle, 5.0);
ASSERT_EQ(filter.style(), SkBlurStyle::kNormal_SkBlurStyle);
ASSERT_EQ(filter.sigma(), 5.0);
}
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);
}
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);
}
TEST(DisplayListMaskFilter, UnknownConstructor) {
DlUnknownMaskFilter filter(
SkMaskFilter::MakeBlur(SkBlurStyle::kNormal_SkBlurStyle, 5.0));
}
TEST(DisplayListMaskFilter, UnknownShared) {
DlUnknownMaskFilter filter(
SkMaskFilter::MakeBlur(SkBlurStyle::kNormal_SkBlurStyle, 5.0));
ASSERT_NE(filter.shared().get(), &filter);
ASSERT_EQ(*filter.shared(), filter);
}
TEST(DisplayListMaskFilter, UnknownContents) {
sk_sp<SkMaskFilter> sk_filter =
SkMaskFilter::MakeBlur(SkBlurStyle::kNormal_SkBlurStyle, 5.0);
DlUnknownMaskFilter filter(sk_filter);
ASSERT_EQ(filter.sk_filter(), sk_filter);
ASSERT_EQ(filter.sk_filter().get(), sk_filter.get());
}
TEST(DisplayListMaskFilter, UnknownEquals) {
sk_sp<SkMaskFilter> sk_filter =
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);
}
TEST(DisplayListMaskFilter, UnknownNotEquals) {
// Even though the filter is the same, it is a different instance
// and we cannot currently tell them apart because the Skia
// MaskFilter objects do not implement ==
DlUnknownMaskFilter filter1(
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);
}
void testEquals(DlMaskFilter* a, DlMaskFilter* b) {
// a and b have the same nullness or values
ASSERT_TRUE(Equals(a, b));
ASSERT_FALSE(NotEquals(a, b));
ASSERT_TRUE(Equals(b, a));
ASSERT_FALSE(NotEquals(b, a));
}
void testNotEquals(DlMaskFilter* a, DlMaskFilter* b) {
// a and b do not have the same nullness or values
ASSERT_FALSE(Equals(a, b));
ASSERT_TRUE(NotEquals(a, b));
ASSERT_FALSE(Equals(b, a));
ASSERT_TRUE(NotEquals(b, a));
}
void testEquals(std::shared_ptr<const DlMaskFilter> a, DlMaskFilter* b) {
// a and b have the same nullness or values
ASSERT_TRUE(Equals(a, b));
ASSERT_FALSE(NotEquals(a, b));
ASSERT_TRUE(Equals(b, a));
ASSERT_FALSE(NotEquals(b, a));
}
void testNotEquals(std::shared_ptr<const DlMaskFilter> a, DlMaskFilter* b) {
// a and b do not have the same nullness or values
ASSERT_FALSE(Equals(a, b));
ASSERT_TRUE(NotEquals(a, b));
ASSERT_FALSE(Equals(b, a));
ASSERT_TRUE(NotEquals(b, a));
}
void testEquals(std::shared_ptr<const DlMaskFilter> a,
std::shared_ptr<const DlMaskFilter> b) {
// a and b have the same nullness or values
ASSERT_TRUE(Equals(a, b));
ASSERT_FALSE(NotEquals(a, b));
ASSERT_TRUE(Equals(b, a));
ASSERT_FALSE(NotEquals(b, a));
}
void testNotEquals(std::shared_ptr<const DlMaskFilter> a,
std::shared_ptr<const DlMaskFilter> b) {
// a and b do not have the same nullness or values
ASSERT_FALSE(Equals(a, b));
ASSERT_TRUE(NotEquals(a, b));
ASSERT_FALSE(Equals(b, a));
ASSERT_TRUE(NotEquals(b, a));
}
TEST(DisplayListMaskFilter, ComparableTemplates) {
DlBlurMaskFilter filter1a(SkBlurStyle::kNormal_SkBlurStyle, 3.0);
DlBlurMaskFilter filter1b(SkBlurStyle::kNormal_SkBlurStyle, 3.0);
DlBlurMaskFilter filter2(SkBlurStyle::kNormal_SkBlurStyle, 5.0);
std::shared_ptr<DlMaskFilter> shared_null;
// null to null
testEquals(nullptr, nullptr);
testEquals(shared_null, nullptr);
testEquals(shared_null, shared_null);
// ptr to null
testNotEquals(&filter1a, nullptr);
testNotEquals(&filter1b, nullptr);
testNotEquals(&filter2, nullptr);
// shared_ptr to null and shared_null to ptr
testNotEquals(filter1a.shared(), nullptr);
testNotEquals(filter1b.shared(), nullptr);
testNotEquals(filter2.shared(), nullptr);
testNotEquals(shared_null, &filter1a);
testNotEquals(shared_null, &filter1b);
testNotEquals(shared_null, &filter2);
// ptr to ptr
testEquals(&filter1a, &filter1a);
testEquals(&filter1a, &filter1b);
testEquals(&filter1b, &filter1b);
testEquals(&filter2, &filter2);
testNotEquals(&filter1a, &filter2);
// shared_ptr to ptr
testEquals(filter1a.shared(), &filter1a);
testEquals(filter1a.shared(), &filter1b);
testEquals(filter1b.shared(), &filter1b);
testEquals(filter2.shared(), &filter2);
testNotEquals(filter1a.shared(), &filter2);
testNotEquals(filter1b.shared(), &filter2);
testNotEquals(filter2.shared(), &filter1a);
testNotEquals(filter2.shared(), &filter1b);
// shared_ptr to shared_ptr
testEquals(filter1a.shared(), filter1a.shared());
testEquals(filter1a.shared(), filter1b.shared());
testEquals(filter1b.shared(), filter1b.shared());
testEquals(filter2.shared(), filter2.shared());
testNotEquals(filter1a.shared(), filter2.shared());
testNotEquals(filter1b.shared(), filter2.shared());
testNotEquals(filter2.shared(), filter1a.shared());
testNotEquals(filter2.shared(), filter1b.shared());
}
} // namespace testing
} // namespace flutter

View File

@ -177,65 +177,53 @@ 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(MaskFilter, filter)
DEFINE_SET_CLEAR_SKREF_OP(PathEffect, effect)
#undef DEFINE_SET_CLEAR_SKREF_OP
struct ClearColorFilterOp final : DLOp {
static const auto kType = DisplayListOpType::kClearColorFilter;
ClearColorFilterOp() {}
void dispatch(Dispatcher& dispatcher) const {
dispatcher.setColorFilter(nullptr);
}
};
struct SetColorFilterOp final : DLOp {
static const auto kType = DisplayListOpType::kSetColorFilter;
SetColorFilterOp() {}
void dispatch(Dispatcher& dispatcher) const {
const DlColorFilter* filter =
reinterpret_cast<const DlColorFilter*>(this + 1);
dispatcher.setColorFilter(filter);
}
};
struct SetSkColorFilterOp final : DLOp {
static const auto kType = DisplayListOpType::kSetSkColorFilter;
SetSkColorFilterOp(sk_sp<SkColorFilter> filter) : filter(filter) {}
sk_sp<SkColorFilter> filter;
void dispatch(Dispatcher& dispatcher) const {
DlUnknownColorFilter dl_filter(filter);
dispatcher.setColorFilter(&dl_filter);
}
};
// 4 byte header + 4 byte payload packs into minimum 8 bytes
// Note that the "blur style" is packed into the OpType to prevent
// needing an additional 8 bytes for a 4-value enum.
#define DEFINE_MASK_BLUR_FILTER_OP(name, style) \
struct SetMaskBlurFilter##name##Op final : DLOp { \
static const auto kType = DisplayListOpType::kSetMaskBlurFilter##name; \
\
explicit SetMaskBlurFilter##name##Op(SkScalar sigma) : sigma(sigma) {} \
\
SkScalar sigma; \
\
void dispatch(Dispatcher& dispatcher) const { \
dispatcher.setMaskBlurFilter(style, sigma); \
} \
// Clear: 4 byte header + unused 4 byte payload uses 8 bytes
// (4 bytes unused)
// Set: 4 byte header + unused 4 byte struct padding + Dl<name>
// instance copied to the memory following the record
// yields a size and efficiency that has somewhere between
// 4 and 8 bytes unused
// 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) \
struct Clear##name##Op final : DLOp { \
static const auto kType = DisplayListOpType::kClear##name; \
\
Clear##name##Op() {} \
\
void dispatch(Dispatcher& dispatcher) const { \
dispatcher.set##name(nullptr); \
} \
}; \
struct Set##name##Op final : DLOp { \
static const auto kType = DisplayListOpType::kSet##name; \
\
Set##name##Op() {} \
\
void dispatch(Dispatcher& dispatcher) const { \
const Dl##name* filter = reinterpret_cast<const Dl##name*>(this + 1); \
dispatcher.set##name(filter); \
} \
}; \
struct SetSk##name##Op final : DLOp { \
static const auto kType = DisplayListOpType::kSetSk##name; \
\
SetSk##name##Op(sk_sp<Sk##name> field) : field(field) {} \
\
sk_sp<Sk##name> field; \
\
void dispatch(Dispatcher& dispatcher) const { \
DlUnknown##name dl_filter(field); \
dispatcher.set##name(&dl_filter); \
} \
};
DEFINE_MASK_BLUR_FILTER_OP(Normal, kNormal_SkBlurStyle)
DEFINE_MASK_BLUR_FILTER_OP(Solid, kSolid_SkBlurStyle)
DEFINE_MASK_BLUR_FILTER_OP(Inner, kInner_SkBlurStyle)
DEFINE_MASK_BLUR_FILTER_OP(Outer, kOuter_SkBlurStyle)
#undef DEFINE_MASK_BLUR_FILTER_OP
DEFINE_SET_CLEAR_DLATTR_OP(ColorFilter, filter)
DEFINE_SET_CLEAR_DLATTR_OP(MaskFilter, filter)
#undef DEFINE_SET_CLEAR_DLATTR_OP
// 4 byte header + no payload uses minimum 8 bytes (4 bytes unused)
struct SaveOp final : DLOp {

View File

@ -108,8 +108,11 @@ static const sk_sp<SkPathEffect> TestPathEffect1 =
SkDashPathEffect::Make(TestDashes1, 2, 0.0f);
static const sk_sp<SkPathEffect> TestPathEffect2 =
SkDashPathEffect::Make(TestDashes2, 2, 0.0f);
static const sk_sp<SkMaskFilter> TestMaskFilter =
SkMaskFilter::MakeBlur(kNormal_SkBlurStyle, 5.0);
static const DlBlurMaskFilter TestMaskFilter1(kNormal_SkBlurStyle, 3.0);
static const DlBlurMaskFilter TestMaskFilter2(kNormal_SkBlurStyle, 5.0);
static const DlBlurMaskFilter TestMaskFilter3(kSolid_SkBlurStyle, 3.0);
static const DlBlurMaskFilter TestMaskFilter4(kInner_SkBlurStyle, 3.0);
static const DlBlurMaskFilter TestMaskFilter5(kOuter_SkBlurStyle, 3.0);
constexpr SkRect TestBounds = SkRect::MakeLTRB(10, 10, 50, 60);
static const SkRRect TestRRect = SkRRect::MakeRectXY(TestBounds, 5, 5);
static const SkRRect TestRRectRect = SkRRect::MakeRect(TestBounds);
@ -364,12 +367,11 @@ std::vector<DisplayListInvocationGroup> allGroups = {
}
},
{ "SetMaskFilter", {
{0, 16, 0, 0, [](DisplayListBuilder& b) {b.setMaskFilter(TestMaskFilter);}},
{0, 8, 0, 0, [](DisplayListBuilder& b) {b.setMaskBlurFilter(kNormal_SkBlurStyle, 3.0);}},
{0, 8, 0, 0, [](DisplayListBuilder& b) {b.setMaskBlurFilter(kNormal_SkBlurStyle, 5.0);}},
{0, 8, 0, 0, [](DisplayListBuilder& b) {b.setMaskBlurFilter(kSolid_SkBlurStyle, 3.0);}},
{0, 8, 0, 0, [](DisplayListBuilder& b) {b.setMaskBlurFilter(kInner_SkBlurStyle, 3.0);}},
{0, 8, 0, 0, [](DisplayListBuilder& b) {b.setMaskBlurFilter(kOuter_SkBlurStyle, 3.0);}},
{0, 24, 0, 0, [](DisplayListBuilder& b) {b.setMaskFilter(&TestMaskFilter1);}},
{0, 24, 0, 0, [](DisplayListBuilder& b) {b.setMaskFilter(&TestMaskFilter2);}},
{0, 24, 0, 0, [](DisplayListBuilder& b) {b.setMaskFilter(&TestMaskFilter3);}},
{0, 24, 0, 0, [](DisplayListBuilder& b) {b.setMaskFilter(&TestMaskFilter4);}},
{0, 24, 0, 0, [](DisplayListBuilder& b) {b.setMaskFilter(&TestMaskFilter5);}},
{0, 0, 0, 0, [](DisplayListBuilder& b) {b.setMaskFilter(nullptr);}},
}
},
@ -1264,27 +1266,6 @@ TEST(DisplayList, DisplayListImageFilterRefHandling) {
ASSERT_TRUE(tester.ref_is_unique());
}
TEST(DisplayList, DisplayListMaskFilterRefHandling) {
class MaskFilterRefTester : public virtual AttributeRefTester {
public:
void setRefToPaint(SkPaint& paint) const override {
paint.setMaskFilter(mask_filter);
}
void setRefToDisplayList(DisplayListBuilder& builder) const override {
builder.setMaskFilter(mask_filter);
}
bool ref_is_unique() const override { return mask_filter->unique(); }
private:
sk_sp<SkMaskFilter> mask_filter =
SkMaskFilter::MakeBlur(SkBlurStyle::kNormal_SkBlurStyle, 2.0);
};
MaskFilterRefTester tester;
tester.test();
ASSERT_TRUE(tester.ref_is_unique());
}
TEST(DisplayList, DisplayListBlenderRefHandling) {
class BlenderRefTester : public virtual AttributeRefTester {
public:
@ -1396,30 +1377,6 @@ TEST(DisplayList, DisplayListFullPerspectiveTransformHandling) {
}
}
TEST(DisplayList, SetMaskBlurSigmaZeroResetsMaskFilter) {
DisplayListBuilder builder;
builder.setMaskBlurFilter(SkBlurStyle::kNormal_SkBlurStyle, 2.0);
builder.drawRect({10, 10, 20, 20});
builder.setMaskBlurFilter(SkBlurStyle::kNormal_SkBlurStyle, 0.0);
EXPECT_EQ(builder.getMaskFilter(), nullptr);
builder.drawRect({30, 30, 40, 40});
sk_sp<DisplayList> display_list = builder.Build();
ASSERT_EQ(display_list->op_count(), 2u);
ASSERT_EQ(display_list->bytes(), sizeof(DisplayList) + 8u + 24u + 8u + 24u);
}
TEST(DisplayList, SetMaskFilterNullResetsMaskFilter) {
DisplayListBuilder builder;
builder.setMaskBlurFilter(SkBlurStyle::kNormal_SkBlurStyle, 2.0);
builder.drawRect({10, 10, 20, 20});
builder.setMaskFilter(nullptr);
EXPECT_EQ(builder.getMaskFilter(), nullptr);
builder.drawRect({30, 30, 40, 40});
sk_sp<DisplayList> display_list = builder.Build();
ASSERT_EQ(display_list->op_count(), 2u);
ASSERT_EQ(display_list->bytes(), sizeof(DisplayList) + 8u + 24u + 8u + 24u);
}
TEST(DisplayList, SingleOpsMightSupportGroupOpacityWithOrWithoutBlendMode) {
auto run_tests = [](std::string name,
void build(DisplayListBuilder & builder),

View File

@ -86,12 +86,8 @@ void SkPaintDispatchHelper::setColorFilter(const DlColorFilter* filter) {
void SkPaintDispatchHelper::setPathEffect(sk_sp<SkPathEffect> effect) {
paint_.setPathEffect(effect);
}
void SkPaintDispatchHelper::setMaskFilter(sk_sp<SkMaskFilter> filter) {
paint_.setMaskFilter(filter);
}
void SkPaintDispatchHelper::setMaskBlurFilter(SkBlurStyle style,
SkScalar sigma) {
paint_.setMaskFilter(SkMaskFilter::MakeBlur(style, sigma));
void SkPaintDispatchHelper::setMaskFilter(const DlMaskFilter* filter) {
paint_.setMaskFilter(filter ? filter->sk_filter() : nullptr);
}
sk_sp<SkColorFilter> SkPaintDispatchHelper::makeColorFilter() const {
@ -272,14 +268,8 @@ void DisplayListBoundsCalculator::setColorFilter(const DlColorFilter* filter) {
void DisplayListBoundsCalculator::setPathEffect(sk_sp<SkPathEffect> effect) {
path_effect_ = std::move(effect);
}
void DisplayListBoundsCalculator::setMaskFilter(sk_sp<SkMaskFilter> filter) {
mask_filter_ = std::move(filter);
mask_sigma_pad_ = 0.0f;
}
void DisplayListBoundsCalculator::setMaskBlurFilter(SkBlurStyle style,
SkScalar sigma) {
mask_sigma_pad_ = std::max(3.0f * sigma, 0.0f);
mask_filter_ = nullptr;
void DisplayListBoundsCalculator::setMaskFilter(const DlMaskFilter* filter) {
mask_filter_ = filter ? filter->shared() : nullptr;
}
void DisplayListBoundsCalculator::save() {
SkMatrixDispatchHelper::save();
@ -601,15 +591,18 @@ bool DisplayListBoundsCalculator::AdjustBoundsForPaint(
if (flags.applies_mask_filter()) {
if (mask_filter_) {
SkPaint p;
p.setMaskFilter(mask_filter_);
if (!p.canComputeFastBounds()) {
return false;
const DlBlurMaskFilter* blur_filter = mask_filter_->asBlur();
if (blur_filter) {
SkScalar mask_sigma_pad = blur_filter->sigma() * 3.0;
bounds.outset(mask_sigma_pad, mask_sigma_pad);
} else {
SkPaint p;
p.setMaskFilter(mask_filter_->sk_filter());
if (!p.canComputeFastBounds()) {
return false;
}
bounds = p.computeFastBounds(bounds, &bounds);
}
bounds = p.computeFastBounds(bounds, &bounds);
}
if (mask_sigma_pad_ > 0.0f) {
bounds.outset(mask_sigma_pad_, mask_sigma_pad_);
}
}

View File

@ -58,8 +58,7 @@ class IgnoreAttributeDispatchHelper : public virtual Dispatcher {
void setImageFilter(sk_sp<SkImageFilter> filter) override {}
void setColorFilter(const DlColorFilter* filter) override {}
void setPathEffect(sk_sp<SkPathEffect> effect) override {}
void setMaskFilter(sk_sp<SkMaskFilter> filter) override {}
void setMaskBlurFilter(SkBlurStyle style, SkScalar sigma) override {}
void setMaskFilter(const DlMaskFilter* filter) override {}
};
// A utility class that will ignore all Dispatcher methods relating
@ -184,8 +183,7 @@ class SkPaintDispatchHelper : public virtual Dispatcher {
void setBlendMode(SkBlendMode mode) override;
void setBlender(sk_sp<SkBlender> blender) override;
void setPathEffect(sk_sp<SkPathEffect> effect) override;
void setMaskFilter(sk_sp<SkMaskFilter> filter) override;
void setMaskBlurFilter(SkBlurStyle style, SkScalar sigma) override;
void setMaskFilter(const DlMaskFilter* filter) override;
void setImageFilter(sk_sp<SkImageFilter> filter) override;
const SkPaint& paint() { return paint_; }
@ -402,8 +400,7 @@ class DisplayListBoundsCalculator final
void setImageFilter(sk_sp<SkImageFilter> filter) override;
void setColorFilter(const DlColorFilter* filter) override;
void setPathEffect(sk_sp<SkPathEffect> effect) override;
void setMaskFilter(sk_sp<SkMaskFilter> filter) override;
void setMaskBlurFilter(SkBlurStyle style, SkScalar sigma) override;
void setMaskFilter(const DlMaskFilter* filter) override;
void save() override;
void saveLayer(const SkRect* bounds, const SaveLayerOptions options) override;
@ -580,8 +577,7 @@ class DisplayListBoundsCalculator final
bool cap_is_square_ = false;
sk_sp<SkImageFilter> image_filter_;
sk_sp<SkPathEffect> path_effect_;
sk_sp<SkMaskFilter> mask_filter_;
SkScalar mask_sigma_pad_ = 0.0;
std::shared_ptr<const DlMaskFilter> mask_filter_;
bool paint_nops_on_transparency();

View File

@ -301,7 +301,8 @@ bool Paint::sync_to(DisplayListBuilder* builder,
SkBlurStyle blur_style =
static_cast<SkBlurStyle>(uint_data[kMaskFilterBlurStyleIndex]);
double sigma = float_data[kMaskFilterSigmaIndex];
builder->setMaskBlurFilter(blur_style, sigma);
DlBlurMaskFilter dl_filter(blur_style, sigma);
builder->setMaskFilter(&dl_filter);
break;
}
}