Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 0b495fe

Browse files
[canvaskit] Add dilate and erode imagefilters (#48553)
Adds `dilate` and `erode` ImageFilters. Fixes flutter/flutter#101085 ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide] and the [C++, Objective-C, Java style guides]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I added new tests to check the change I am making or feature I am adding, or the PR is [test-exempt]. See [testing the engine] for instructions on writing and running engine tests. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I signed the [CLA]. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/wiki/Tree-hygiene#overview [Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene [test-exempt]: https://github.com/flutter/flutter/wiki/Tree-hygiene#tests [Flutter Style Guide]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo [C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style [testing the engine]: https://github.com/flutter/flutter/wiki/Testing-the-engine [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/wiki/Chat
1 parent 986333c commit 0b495fe

File tree

6 files changed

+124
-17
lines changed

6 files changed

+124
-17
lines changed

lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1493,6 +1493,18 @@ extension SkImageFilterNamespaceExtension on SkImageFilterNamespace {
14931493
SkImageFilter outer,
14941494
SkImageFilter inner,
14951495
);
1496+
1497+
external SkImageFilter MakeDilate(
1498+
double radiusX,
1499+
double radiusY,
1500+
void input, // we don't use this yet
1501+
);
1502+
1503+
external SkImageFilter MakeErode(
1504+
double radiusX,
1505+
double radiusY,
1506+
void input, // we don't use this yet
1507+
);
14961508
}
14971509

14981510
@JS()

lib/web_ui/lib/src/engine/canvaskit/image_filter.dart

Lines changed: 90 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ abstract class CkImageFilter implements CkManagedSkImageFilterConvertible {
4040
factory CkImageFilter.matrix(
4141
{required Float64List matrix,
4242
required ui.FilterQuality filterQuality}) = _CkMatrixImageFilter;
43+
factory CkImageFilter.dilate(
44+
{required double radiusX,
45+
required double radiusY}) = _CkDilateImageFilter;
46+
factory CkImageFilter.erode(
47+
{required double radiusX, required double radiusY}) = _CkErodeImageFilter;
4348
factory CkImageFilter.compose(
4449
{required CkImageFilter outer,
4550
required CkImageFilter inner}) = _CkComposeImageFilter;
@@ -94,10 +99,9 @@ class _CkBlurImageFilter extends CkImageFilter {
9499
final SkImageFilter skImageFilter;
95100
if (sigmaX == 0 && sigmaY == 0) {
96101
skImageFilter = canvasKit.ImageFilter.MakeMatrixTransform(
97-
toSkMatrixFromFloat32(Matrix4.identity().storage),
98-
toSkFilterOptions(ui.FilterQuality.none),
99-
null
100-
);
102+
toSkMatrixFromFloat32(Matrix4.identity().storage),
103+
toSkFilterOptions(ui.FilterQuality.none),
104+
null);
101105
} else {
102106
skImageFilter = canvasKit.ImageFilter.MakeBlur(
103107
sigmaX,
@@ -146,7 +150,8 @@ class _CkMatrixImageFilter extends CkImageFilter {
146150
: matrix = Float64List.fromList(matrix),
147151
_transform = Matrix4.fromFloat32List(toMatrix32(matrix)),
148152
super._() {
149-
final SkImageFilter skImageFilter = canvasKit.ImageFilter.MakeMatrixTransform(
153+
final SkImageFilter skImageFilter =
154+
canvasKit.ImageFilter.MakeMatrixTransform(
150155
toSkMatrixFromFloat64(matrix),
151156
toSkFilterOptions(filterQuality),
152157
null,
@@ -185,6 +190,86 @@ class _CkMatrixImageFilter extends CkImageFilter {
185190
Matrix4 get transform => _transform;
186191
}
187192

193+
class _CkDilateImageFilter extends CkImageFilter {
194+
_CkDilateImageFilter({required this.radiusX, required this.radiusY})
195+
: super._() {
196+
final SkImageFilter skImageFilter = canvasKit.ImageFilter.MakeDilate(
197+
radiusX,
198+
radiusY,
199+
null,
200+
);
201+
_ref = UniqueRef<SkImageFilter>(this, skImageFilter, 'ImageFilter.dilate');
202+
}
203+
204+
final double radiusX;
205+
final double radiusY;
206+
207+
late final UniqueRef<SkImageFilter> _ref;
208+
209+
@override
210+
void imageFilter(SkImageFilterBorrow borrow) {
211+
borrow(_ref.nativeObject);
212+
}
213+
214+
@override
215+
bool operator ==(Object other) {
216+
if (runtimeType != other.runtimeType) {
217+
return false;
218+
}
219+
return other is _CkDilateImageFilter &&
220+
other.radiusX == radiusX &&
221+
other.radiusY == radiusY;
222+
}
223+
224+
@override
225+
int get hashCode => Object.hash(radiusX, radiusY);
226+
227+
@override
228+
String toString() {
229+
return 'ImageFilter.dilate($radiusX, $radiusY)';
230+
}
231+
}
232+
233+
class _CkErodeImageFilter extends CkImageFilter {
234+
_CkErodeImageFilter({required this.radiusX, required this.radiusY})
235+
: super._() {
236+
final SkImageFilter skImageFilter = canvasKit.ImageFilter.MakeErode(
237+
radiusX,
238+
radiusY,
239+
null,
240+
);
241+
_ref = UniqueRef<SkImageFilter>(this, skImageFilter, 'ImageFilter.erode');
242+
}
243+
244+
final double radiusX;
245+
final double radiusY;
246+
247+
late final UniqueRef<SkImageFilter> _ref;
248+
249+
@override
250+
void imageFilter(SkImageFilterBorrow borrow) {
251+
borrow(_ref.nativeObject);
252+
}
253+
254+
@override
255+
bool operator ==(Object other) {
256+
if (runtimeType != other.runtimeType) {
257+
return false;
258+
}
259+
return other is _CkErodeImageFilter &&
260+
other.radiusX == radiusX &&
261+
other.radiusY == radiusY;
262+
}
263+
264+
@override
265+
int get hashCode => Object.hash(radiusX, radiusY);
266+
267+
@override
268+
String toString() {
269+
return 'ImageFilter.erode($radiusX, $radiusY)';
270+
}
271+
}
272+
188273
class _CkComposeImageFilter extends CkImageFilter {
189274
_CkComposeImageFilter({required this.outer, required this.inner})
190275
: super._() {

lib/web_ui/lib/src/engine/canvaskit/renderer.dart

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -188,19 +188,13 @@ class CanvasKitRenderer implements Renderer {
188188

189189
@override
190190
ui.ImageFilter createDilateImageFilter(
191-
{double radiusX = 0.0, double radiusY = 0.0}) {
192-
// TODO(fzyzcjy): implement dilate. https://github.com/flutter/flutter/issues/101085
193-
throw UnimplementedError(
194-
'ImageFilter.dilate not implemented for CanvasKit.');
195-
}
191+
{double radiusX = 0.0, double radiusY = 0.0}) =>
192+
CkImageFilter.dilate(radiusX: radiusX, radiusY: radiusY);
196193

197194
@override
198195
ui.ImageFilter createErodeImageFilter(
199-
{double radiusX = 0.0, double radiusY = 0.0}) {
200-
// TODO(fzyzcjy): implement erode. https://github.com/flutter/flutter/issues/101085
201-
throw UnimplementedError(
202-
'ImageFilter.erode not implemented for CanvasKit.');
203-
}
196+
{double radiusX = 0.0, double radiusY = 0.0}) =>
197+
CkImageFilter.erode(radiusX: radiusX, radiusY: radiusY);
204198

205199
@override
206200
ui.ImageFilter createMatrixImageFilter(Float64List matrix4,

lib/web_ui/test/canvaskit/canvaskit_api_test.dart

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -529,6 +529,20 @@ void _imageFilterTests() {
529529
isNotNull,
530530
);
531531
});
532+
533+
test('MakeDilate', () {
534+
expect(
535+
canvasKit.ImageFilter.MakeDilate(1, 2, null),
536+
isNotNull,
537+
);
538+
});
539+
540+
test('MakeErode', () {
541+
expect(
542+
canvasKit.ImageFilter.MakeErode(1, 2, null),
543+
isNotNull,
544+
);
545+
});
532546
}
533547

534548
void _mallocTests() {

lib/web_ui/test/canvaskit/filter_test.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ void testMain() {
4242
CkImageFilter.blur(sigmaX: 5, sigmaY: 6, tileMode: ui.TileMode.clamp),
4343
CkImageFilter.blur(sigmaX: 6, sigmaY: 5, tileMode: ui.TileMode.clamp),
4444
CkImageFilter.blur(sigmaX: 6, sigmaY: 5, tileMode: ui.TileMode.decal),
45+
CkImageFilter.dilate(radiusX: 5, radiusY: 6),
46+
CkImageFilter.erode(radiusX: 7, radiusY: 8),
4547
for (final CkColorFilter colorFilter in createColorFilters()) CkImageFilter.color(colorFilter: colorFilter),
4648
];
4749
filters.add(CkImageFilter.compose(outer: filters[0], inner: filters[1]));

lib/web_ui/test/ui/filters_test.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,15 +61,15 @@ Future<void> testMain() async {
6161
radiusY: 5.0,
6262
));
6363
await matchGoldenFile('ui_filter_dilate_imagefilter.png', region: region);
64-
}, skip: !isSkwasm); // Only skwasm supports dilate filter right now
64+
}, skip: isHtml); // HTML renderer does not support the dilate filter
6565

6666
test('erode filter', () async {
6767
await drawTestImageWithPaint(ui.Paint()..imageFilter = ui.ImageFilter.erode(
6868
radiusX: 5.0,
6969
radiusY: 5.0,
7070
));
7171
await matchGoldenFile('ui_filter_erode_imagefilter.png', region: region);
72-
}, skip: !isSkwasm); // Only skwasm supports erode filter
72+
}, skip: isHtml); // HTML renderer does not support the erode filter
7373

7474
test('matrix filter', () async {
7575
await drawTestImageWithPaint(ui.Paint()..imageFilter = ui.ImageFilter.matrix(

0 commit comments

Comments
 (0)