Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1493,6 +1493,18 @@ extension SkImageFilterNamespaceExtension on SkImageFilterNamespace {
SkImageFilter outer,
SkImageFilter inner,
);

external SkImageFilter MakeDilate(
double radiusX,
double radiusY,
void input, // we don't use this yet
);

external SkImageFilter MakeErode(
double radiusX,
double radiusY,
void input, // we don't use this yet
);
}

@JS()
Expand Down
95 changes: 90 additions & 5 deletions lib/web_ui/lib/src/engine/canvaskit/image_filter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ abstract class CkImageFilter implements CkManagedSkImageFilterConvertible {
factory CkImageFilter.matrix(
{required Float64List matrix,
required ui.FilterQuality filterQuality}) = _CkMatrixImageFilter;
factory CkImageFilter.dilate(
{required double radiusX,
required double radiusY}) = _CkDilateImageFilter;
factory CkImageFilter.erode(
{required double radiusX, required double radiusY}) = _CkErodeImageFilter;
factory CkImageFilter.compose(
{required CkImageFilter outer,
required CkImageFilter inner}) = _CkComposeImageFilter;
Expand Down Expand Up @@ -94,10 +99,9 @@ class _CkBlurImageFilter extends CkImageFilter {
final SkImageFilter skImageFilter;
if (sigmaX == 0 && sigmaY == 0) {
skImageFilter = canvasKit.ImageFilter.MakeMatrixTransform(
toSkMatrixFromFloat32(Matrix4.identity().storage),
toSkFilterOptions(ui.FilterQuality.none),
null
);
toSkMatrixFromFloat32(Matrix4.identity().storage),
toSkFilterOptions(ui.FilterQuality.none),
null);
} else {
skImageFilter = canvasKit.ImageFilter.MakeBlur(
sigmaX,
Expand Down Expand Up @@ -146,7 +150,8 @@ class _CkMatrixImageFilter extends CkImageFilter {
: matrix = Float64List.fromList(matrix),
_transform = Matrix4.fromFloat32List(toMatrix32(matrix)),
super._() {
final SkImageFilter skImageFilter = canvasKit.ImageFilter.MakeMatrixTransform(
final SkImageFilter skImageFilter =
canvasKit.ImageFilter.MakeMatrixTransform(
toSkMatrixFromFloat64(matrix),
toSkFilterOptions(filterQuality),
null,
Expand Down Expand Up @@ -185,6 +190,86 @@ class _CkMatrixImageFilter extends CkImageFilter {
Matrix4 get transform => _transform;
}

class _CkDilateImageFilter extends CkImageFilter {
_CkDilateImageFilter({required this.radiusX, required this.radiusY})
: super._() {
final SkImageFilter skImageFilter = canvasKit.ImageFilter.MakeDilate(
radiusX,
radiusY,
null,
);
_ref = UniqueRef<SkImageFilter>(this, skImageFilter, 'ImageFilter.dilate');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Who is responsible for calling _ref.dispose()? Or do we leak these and let GC handle the clean-up?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We let GC handle it. Like ui.Paint, ui.ImageFilter can be created by the user and doesn't have a dispose method. There are no places in the engine where we create a temporary ImageFilter to make use of explicit disposal.

}

final double radiusX;
final double radiusY;

late final UniqueRef<SkImageFilter> _ref;

@override
void imageFilter(SkImageFilterBorrow borrow) {
borrow(_ref.nativeObject);
}

@override
bool operator ==(Object other) {
if (runtimeType != other.runtimeType) {
return false;
}
return other is _CkDilateImageFilter &&
other.radiusX == radiusX &&
other.radiusY == radiusY;
}

@override
int get hashCode => Object.hash(radiusX, radiusY);

@override
String toString() {
return 'ImageFilter.dilate($radiusX, $radiusY)';
}
}

class _CkErodeImageFilter extends CkImageFilter {
_CkErodeImageFilter({required this.radiusX, required this.radiusY})
: super._() {
final SkImageFilter skImageFilter = canvasKit.ImageFilter.MakeErode(
radiusX,
radiusY,
null,
);
_ref = UniqueRef<SkImageFilter>(this, skImageFilter, 'ImageFilter.erode');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same question about disposal here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same answer.

}

final double radiusX;
final double radiusY;

late final UniqueRef<SkImageFilter> _ref;

@override
void imageFilter(SkImageFilterBorrow borrow) {
borrow(_ref.nativeObject);
}

@override
bool operator ==(Object other) {
if (runtimeType != other.runtimeType) {
return false;
}
return other is _CkErodeImageFilter &&
other.radiusX == radiusX &&
other.radiusY == radiusY;
}

@override
int get hashCode => Object.hash(radiusX, radiusY);

@override
String toString() {
return 'ImageFilter.erode($radiusX, $radiusY)';
}
}

class _CkComposeImageFilter extends CkImageFilter {
_CkComposeImageFilter({required this.outer, required this.inner})
: super._() {
Expand Down
14 changes: 4 additions & 10 deletions lib/web_ui/lib/src/engine/canvaskit/renderer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -188,19 +188,13 @@ class CanvasKitRenderer implements Renderer {

@override
ui.ImageFilter createDilateImageFilter(
{double radiusX = 0.0, double radiusY = 0.0}) {
// TODO(fzyzcjy): implement dilate. https://github.com/flutter/flutter/issues/101085
throw UnimplementedError(
'ImageFilter.dilate not implemented for CanvasKit.');
}
{double radiusX = 0.0, double radiusY = 0.0}) =>
CkImageFilter.dilate(radiusX: radiusX, radiusY: radiusY);

@override
ui.ImageFilter createErodeImageFilter(
{double radiusX = 0.0, double radiusY = 0.0}) {
// TODO(fzyzcjy): implement erode. https://github.com/flutter/flutter/issues/101085
throw UnimplementedError(
'ImageFilter.erode not implemented for CanvasKit.');
}
{double radiusX = 0.0, double radiusY = 0.0}) =>
CkImageFilter.erode(radiusX: radiusX, radiusY: radiusY);

@override
ui.ImageFilter createMatrixImageFilter(Float64List matrix4,
Expand Down
14 changes: 14 additions & 0 deletions lib/web_ui/test/canvaskit/canvaskit_api_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -529,6 +529,20 @@ void _imageFilterTests() {
isNotNull,
);
});

test('MakeDilate', () {
expect(
canvasKit.ImageFilter.MakeDilate(1, 2, null),
isNotNull,
);
});

test('MakeErode', () {
expect(
canvasKit.ImageFilter.MakeErode(1, 2, null),
isNotNull,
);
});
}

void _mallocTests() {
Expand Down
2 changes: 2 additions & 0 deletions lib/web_ui/test/canvaskit/filter_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ void testMain() {
CkImageFilter.blur(sigmaX: 5, sigmaY: 6, tileMode: ui.TileMode.clamp),
CkImageFilter.blur(sigmaX: 6, sigmaY: 5, tileMode: ui.TileMode.clamp),
CkImageFilter.blur(sigmaX: 6, sigmaY: 5, tileMode: ui.TileMode.decal),
CkImageFilter.dilate(radiusX: 5, radiusY: 6),
CkImageFilter.erode(radiusX: 7, radiusY: 8),
for (final CkColorFilter colorFilter in createColorFilters()) CkImageFilter.color(colorFilter: colorFilter),
];
filters.add(CkImageFilter.compose(outer: filters[0], inner: filters[1]));
Expand Down
4 changes: 2 additions & 2 deletions lib/web_ui/test/ui/filters_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,15 @@ Future<void> testMain() async {
radiusY: 5.0,
));
await matchGoldenFile('ui_filter_dilate_imagefilter.png', region: region);
}, skip: !isSkwasm); // Only skwasm supports dilate filter right now
}, skip: isHtml); // HTML renderer does not support the dilate filter

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

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