Skip to content

Commit 9b3117a

Browse files
authored
Create ImageFilter.dilate/ImageFilter.erode (flutter#32334)
1 parent e7e7ca1 commit 9b3117a

File tree

11 files changed

+502
-1
lines changed

11 files changed

+502
-1
lines changed

display_list/display_list_builder.cc

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,20 @@ void DisplayListBuilder::onSetImageFilter(const DlImageFilter* filter) {
193193
new (pod) DlBlurImageFilter(blur_filter);
194194
break;
195195
}
196+
case DlImageFilterType::kDilate: {
197+
const DlDilateImageFilter* dilate_filter = filter->asDilate();
198+
FML_DCHECK(dilate_filter);
199+
void* pod = Push<SetPodImageFilterOp>(dilate_filter->size(), 0);
200+
new (pod) DlDilateImageFilter(dilate_filter);
201+
break;
202+
}
203+
case DlImageFilterType::kErode: {
204+
const DlErodeImageFilter* erode_filter = filter->asErode();
205+
FML_DCHECK(erode_filter);
206+
void* pod = Push<SetPodImageFilterOp>(erode_filter->size(), 0);
207+
new (pod) DlErodeImageFilter(erode_filter);
208+
break;
209+
}
196210
case DlImageFilterType::kMatrix: {
197211
const DlMatrixImageFilter* matrix_filter = filter->asMatrix();
198212
FML_DCHECK(matrix_filter);

display_list/display_list_canvas_unittests.cc

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1121,6 +1121,65 @@ class CanvasCompareTester {
11211121
}
11221122
}
11231123

1124+
{
1125+
// Being able to see a dilate requires some non-default attributes,
1126+
// like a non-trivial stroke width and a shader rather than a color
1127+
// (for drawPaint) so we create a new environment for these tests.
1128+
RenderEnvironment dilate_env = RenderEnvironment::MakeN32();
1129+
CvSetup cv_dilate_setup = [=](SkCanvas*, SkPaint& p) {
1130+
p.setShader(testImageColorSource.skia_object());
1131+
p.setStrokeWidth(5.0);
1132+
};
1133+
DlRenderer dl_dilate_setup = [=](DisplayListBuilder& b) {
1134+
b.setColorSource(&testImageColorSource);
1135+
b.setStrokeWidth(5.0);
1136+
};
1137+
dilate_env.init_ref(cv_dilate_setup, testP.cv_renderer(),
1138+
dl_dilate_setup);
1139+
DlDilateImageFilter filter_5(5.0, 5.0);
1140+
RenderWith(testP, dilate_env, tolerance,
1141+
CaseParameters(
1142+
"ImageFilter == Dilate 5",
1143+
[=](SkCanvas* cv, SkPaint& p) {
1144+
cv_dilate_setup(cv, p);
1145+
p.setImageFilter(filter_5.skia_object());
1146+
},
1147+
[=](DisplayListBuilder& b) {
1148+
dl_dilate_setup(b);
1149+
b.setImageFilter(&filter_5);
1150+
}));
1151+
}
1152+
1153+
{
1154+
// Being able to see an erode requires some non-default attributes,
1155+
// like a non-trivial stroke width and a shader rather than a color
1156+
// (for drawPaint) so we create a new environment for these tests.
1157+
RenderEnvironment erode_env = RenderEnvironment::MakeN32();
1158+
CvSetup cv_erode_setup = [=](SkCanvas*, SkPaint& p) {
1159+
p.setShader(testImageColorSource.skia_object());
1160+
p.setStrokeWidth(6.0);
1161+
};
1162+
DlRenderer dl_erode_setup = [=](DisplayListBuilder& b) {
1163+
b.setColorSource(&testImageColorSource);
1164+
b.setStrokeWidth(6.0);
1165+
};
1166+
erode_env.init_ref(cv_erode_setup, testP.cv_renderer(), dl_erode_setup);
1167+
// do not erode too much, because some tests assert there are enough
1168+
// pixels that are changed.
1169+
DlErodeImageFilter filter_1(1.0, 1.0);
1170+
RenderWith(testP, erode_env, tolerance,
1171+
CaseParameters(
1172+
"ImageFilter == Erode 1",
1173+
[=](SkCanvas* cv, SkPaint& p) {
1174+
cv_erode_setup(cv, p);
1175+
p.setImageFilter(filter_1.skia_object());
1176+
},
1177+
[=](DisplayListBuilder& b) {
1178+
dl_erode_setup(b);
1179+
b.setImageFilter(&filter_1);
1180+
}));
1181+
}
1182+
11241183
{
11251184
// clang-format off
11261185
constexpr float rotate_color_matrix[20] = {

display_list/display_list_image_filter.h

Lines changed: 133 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,17 @@ namespace flutter {
2828
// provided as a fallback.
2929
enum class DlImageFilterType {
3030
kBlur,
31+
kDilate,
32+
kErode,
3133
kMatrix,
3234
kComposeFilter,
3335
kColorFilter,
3436
kUnknown
3537
};
3638

3739
class DlBlurImageFilter;
40+
class DlDilateImageFilter;
41+
class DlErodeImageFilter;
3842
class DlMatrixImageFilter;
3943
class DlComposeImageFilter;
4044
class DlColorFilterImageFilter;
@@ -64,6 +68,14 @@ class DlImageFilter
6468
// type of ImageFilter, otherwise return nullptr.
6569
virtual const DlBlurImageFilter* asBlur() const { return nullptr; }
6670

71+
// Return a DlDilateImageFilter pointer to this object iff it is a Dilate
72+
// type of ImageFilter, otherwise return nullptr.
73+
virtual const DlDilateImageFilter* asDilate() const { return nullptr; }
74+
75+
// Return a DlErodeImageFilter pointer to this object iff it is an Erode
76+
// type of ImageFilter, otherwise return nullptr.
77+
virtual const DlErodeImageFilter* asErode() const { return nullptr; }
78+
6779
// Return a DlMatrixImageFilter pointer to this object iff it is a Matrix
6880
// type of ImageFilter, otherwise return nullptr.
6981
virtual const DlMatrixImageFilter* asMatrix() const { return nullptr; }
@@ -140,7 +152,7 @@ class DlBlurImageFilter final : public DlImageFilter {
140152
SkIRect* map_device_bounds(const SkIRect& input_bounds,
141153
const SkMatrix& ctm,
142154
SkIRect& output_bounds) const override {
143-
SkVector device_sigma = ctm.mapVector(sigma_x_, sigma_y_);
155+
SkVector device_sigma = ctm.mapVector(sigma_x_ * 3, sigma_y_ * 3);
144156
if (!SkScalarIsFinite(device_sigma.fX)) {
145157
device_sigma.fX = 0;
146158
}
@@ -174,6 +186,126 @@ class DlBlurImageFilter final : public DlImageFilter {
174186
DlTileMode tile_mode_;
175187
};
176188

189+
class DlDilateImageFilter final : public DlImageFilter {
190+
public:
191+
DlDilateImageFilter(SkScalar radius_x, SkScalar radius_y)
192+
: radius_x_(radius_x), radius_y_(radius_y) {}
193+
explicit DlDilateImageFilter(const DlDilateImageFilter* filter)
194+
: DlDilateImageFilter(filter->radius_x_, filter->radius_y_) {}
195+
explicit DlDilateImageFilter(const DlDilateImageFilter& filter)
196+
: DlDilateImageFilter(&filter) {}
197+
198+
std::shared_ptr<DlImageFilter> shared() const override {
199+
return std::make_shared<DlDilateImageFilter>(this);
200+
}
201+
202+
DlImageFilterType type() const override { return DlImageFilterType::kDilate; }
203+
size_t size() const override { return sizeof(*this); }
204+
205+
const DlDilateImageFilter* asDilate() const override { return this; }
206+
207+
bool modifies_transparent_black() const override { return false; }
208+
209+
SkRect* map_local_bounds(const SkRect& input_bounds,
210+
SkRect& output_bounds) const override {
211+
output_bounds = input_bounds.makeOutset(radius_x_, radius_y_);
212+
return &output_bounds;
213+
}
214+
215+
SkIRect* map_device_bounds(const SkIRect& input_bounds,
216+
const SkMatrix& ctm,
217+
SkIRect& output_bounds) const override {
218+
SkVector device_radius = ctm.mapVector(radius_x_, radius_y_);
219+
if (!SkScalarIsFinite(device_radius.fX)) {
220+
device_radius.fX = 0;
221+
}
222+
if (!SkScalarIsFinite(device_radius.fY)) {
223+
device_radius.fY = 0;
224+
}
225+
output_bounds = input_bounds.makeOutset(ceil(abs(device_radius.fX)),
226+
ceil(abs(device_radius.fY)));
227+
return &output_bounds;
228+
}
229+
230+
SkScalar radius_x() const { return radius_x_; }
231+
SkScalar radius_y() const { return radius_y_; }
232+
233+
sk_sp<SkImageFilter> skia_object() const override {
234+
return SkImageFilters::Dilate(radius_x_, radius_y_, nullptr);
235+
}
236+
237+
protected:
238+
bool equals_(const DlImageFilter& other) const override {
239+
FML_DCHECK(other.type() == DlImageFilterType::kDilate);
240+
auto that = static_cast<const DlDilateImageFilter*>(&other);
241+
return (radius_x_ == that->radius_x_ && radius_y_ == that->radius_y_);
242+
}
243+
244+
private:
245+
SkScalar radius_x_;
246+
SkScalar radius_y_;
247+
};
248+
249+
class DlErodeImageFilter final : public DlImageFilter {
250+
public:
251+
DlErodeImageFilter(SkScalar radius_x, SkScalar radius_y)
252+
: radius_x_(radius_x), radius_y_(radius_y) {}
253+
explicit DlErodeImageFilter(const DlErodeImageFilter* filter)
254+
: DlErodeImageFilter(filter->radius_x_, filter->radius_y_) {}
255+
explicit DlErodeImageFilter(const DlErodeImageFilter& filter)
256+
: DlErodeImageFilter(&filter) {}
257+
258+
std::shared_ptr<DlImageFilter> shared() const override {
259+
return std::make_shared<DlErodeImageFilter>(this);
260+
}
261+
262+
DlImageFilterType type() const override { return DlImageFilterType::kErode; }
263+
size_t size() const override { return sizeof(*this); }
264+
265+
const DlErodeImageFilter* asErode() const override { return this; }
266+
267+
bool modifies_transparent_black() const override { return false; }
268+
269+
SkRect* map_local_bounds(const SkRect& input_bounds,
270+
SkRect& output_bounds) const override {
271+
output_bounds = input_bounds.makeOutset(radius_x_, radius_y_);
272+
return &output_bounds;
273+
}
274+
275+
SkIRect* map_device_bounds(const SkIRect& input_bounds,
276+
const SkMatrix& ctm,
277+
SkIRect& output_bounds) const override {
278+
SkVector device_radius = ctm.mapVector(radius_x_, radius_y_);
279+
if (!SkScalarIsFinite(device_radius.fX)) {
280+
device_radius.fX = 0;
281+
}
282+
if (!SkScalarIsFinite(device_radius.fY)) {
283+
device_radius.fY = 0;
284+
}
285+
output_bounds = input_bounds.makeOutset(ceil(abs(device_radius.fX)),
286+
ceil(abs(device_radius.fY)));
287+
return &output_bounds;
288+
}
289+
290+
SkScalar radius_x() const { return radius_x_; }
291+
SkScalar radius_y() const { return radius_y_; }
292+
293+
sk_sp<SkImageFilter> skia_object() const override {
294+
return SkImageFilters::Erode(radius_x_, radius_y_, nullptr);
295+
}
296+
297+
protected:
298+
bool equals_(const DlImageFilter& other) const override {
299+
FML_DCHECK(other.type() == DlImageFilterType::kErode);
300+
auto that = static_cast<const DlErodeImageFilter*>(&other);
301+
return (radius_x_ == that->radius_x_ && radius_y_ == that->radius_y_);
302+
}
303+
304+
private:
305+
SkScalar radius_x_;
306+
SkScalar radius_y_;
307+
};
308+
177309
class DlMatrixImageFilter final : public DlImageFilter {
178310
public:
179311
DlMatrixImageFilter(const SkMatrix& matrix, const SkSamplingOptions& sampling)

0 commit comments

Comments
 (0)