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

Commit badb3d7

Browse files
committed
colorFilter as imageFilter
1 parent 0564989 commit badb3d7

21 files changed

+527
-116
lines changed

lib/web_ui/lib/painting.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,7 @@ abstract class Image {
359359
String toString() => '[$width\u00D7$height]';
360360
}
361361

362-
abstract class ColorFilter {
362+
class ColorFilter implements ImageFilter {
363363
const factory ColorFilter.mode(Color color, BlendMode blendMode) = engine.EngineColorFilter.mode;
364364
const factory ColorFilter.matrix(List<double> matrix) = engine.EngineColorFilter.matrix;
365365
const factory ColorFilter.linearToSrgbGamma() = engine.EngineColorFilter.linearToSrgbGamma;

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

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import 'dart:typed_data';
77

88
import 'package:ui/ui.dart' as ui;
99

10+
import '../color_filter.dart';
1011
import 'canvaskit_api.dart';
1112
import 'image.dart';
1213
import 'image_filter.dart';
@@ -290,8 +291,15 @@ class CkCanvas {
290291

291292
void saveLayerWithFilter(ui.Rect bounds, ui.ImageFilter filter,
292293
[CkPaint? paint]) {
293-
final CkManagedSkImageFilterConvertible convertible =
294-
filter as CkManagedSkImageFilterConvertible;
294+
final CkManagedSkImageFilterConvertible convertible;
295+
if (filter is ui.ColorFilter) {
296+
convertible =
297+
(filter as EngineColorFilter).toRendererColorFilter() as CkManagedSkImageFilterConvertible;
298+
}
299+
else {
300+
convertible =
301+
filter as CkManagedSkImageFilterConvertible;
302+
}
295303
return skCanvas.saveLayer(
296304
paint?.skiaObject,
297305
toSkRect(bounds),

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

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import 'dart:typed_data';
66

77
import 'package:ui/ui.dart' as ui;
88

9-
import '../color_filter.dart';
109
import '../util.dart';
1110
import 'canvaskit_api.dart';
1211
import 'image_filter.dart';
@@ -56,8 +55,8 @@ class ManagedSkColorFilter extends ManagedSkiaObject<SkColorFilter> {
5655
/// Additionally, this class provides the interface for converting itself to a
5756
/// [ManagedSkiaObject] that manages a skia image filter.
5857
abstract class CkColorFilter
59-
implements CkManagedSkImageFilterConvertible, EngineColorFilter {
60-
const CkColorFilter();
58+
implements CkManagedSkImageFilterConvertible {
59+
const CkColorFilter(this.creator);
6160

6261
/// Called by [ManagedSkiaObject.createDefault] and
6362
/// [ManagedSkiaObject.resurrect] to create a new [SkImageFilter], when this
@@ -73,10 +72,14 @@ abstract class CkColorFilter
7372
@override
7473
ManagedSkiaObject<SkImageFilter> get imageFilter =>
7574
CkColorFilterImageFilter(colorFilter: this);
75+
76+
/// Convert the CkColorFilter back into a ui.ColorFilter
77+
/// Used in [CkPaint]
78+
final ui.ColorFilter creator;
7679
}
7780

7881
class CkBlendModeColorFilter extends CkColorFilter {
79-
const CkBlendModeColorFilter(this.color, this.blendMode);
82+
const CkBlendModeColorFilter(super.creator, this.color, this.blendMode);
8083

8184
final ui.Color color;
8285
final ui.BlendMode blendMode;
@@ -129,7 +132,7 @@ class CkBlendModeColorFilter extends CkColorFilter {
129132
}
130133

131134
class CkMatrixColorFilter extends CkColorFilter {
132-
const CkMatrixColorFilter(this.matrix);
135+
const CkMatrixColorFilter(super.creator, this.matrix);
133136

134137
final List<double> matrix;
135138

@@ -172,7 +175,7 @@ class CkMatrixColorFilter extends CkColorFilter {
172175
}
173176

174177
class CkLinearToSrgbGammaColorFilter extends CkColorFilter {
175-
const CkLinearToSrgbGammaColorFilter();
178+
const CkLinearToSrgbGammaColorFilter(super.creator);
176179
@override
177180
SkColorFilter _initRawColorFilter() =>
178181
canvasKit.ColorFilter.MakeLinearToSRGBGamma();
@@ -188,7 +191,7 @@ class CkLinearToSrgbGammaColorFilter extends CkColorFilter {
188191
}
189192

190193
class CkSrgbToLinearGammaColorFilter extends CkColorFilter {
191-
const CkSrgbToLinearGammaColorFilter();
194+
const CkSrgbToLinearGammaColorFilter(super.creator);
192195
@override
193196
SkColorFilter _initRawColorFilter() =>
194197
canvasKit.ColorFilter.MakeSRGBToLinearGamma();
@@ -204,7 +207,7 @@ class CkSrgbToLinearGammaColorFilter extends CkColorFilter {
204207
}
205208

206209
class CkComposeColorFilter extends CkColorFilter {
207-
const CkComposeColorFilter(this.outer, this.inner);
210+
const CkComposeColorFilter(super.creator, this.outer, this.inner);
208211
final ManagedSkColorFilter? outer;
209212
final ManagedSkColorFilter inner;
210213

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

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import 'dart:typed_data';
77

88
import 'package:ui/ui.dart' as ui;
99

10+
import '../color_filter.dart';
1011
import 'canvaskit_api.dart';
1112
import 'color_filter.dart';
1213
import 'image_filter.dart';
@@ -131,7 +132,12 @@ class CkPaint extends ManagedSkiaObject<SkPaint> implements ui.Paint {
131132
_effectiveColorFilter = _invertColorFilter;
132133
} else {
133134
_effectiveColorFilter = ManagedSkColorFilter(
134-
CkComposeColorFilter(_invertColorFilter, _effectiveColorFilter!));
135+
CkComposeColorFilter(
136+
_effectiveColorFilter!.colorFilter.creator,
137+
_invertColorFilter,
138+
_effectiveColorFilter!
139+
)
140+
);
135141
}
136142
}
137143
skiaObject.setColorFilter(_effectiveColorFilter?.skiaObject);
@@ -203,7 +209,9 @@ class CkPaint extends ManagedSkiaObject<SkPaint> implements ui.Paint {
203209
ui.FilterQuality _filterQuality = ui.FilterQuality.none;
204210

205211
@override
206-
ui.ColorFilter? get colorFilter => _effectiveColorFilter?.colorFilter;
212+
ui.ColorFilter? get colorFilter {
213+
return _effectiveColorFilter?.colorFilter.creator;
214+
}
207215
@override
208216
set colorFilter(ui.ColorFilter? value) {
209217
if (colorFilter == value) {
@@ -214,7 +222,8 @@ class CkPaint extends ManagedSkiaObject<SkPaint> implements ui.Paint {
214222
if (value == null) {
215223
_effectiveColorFilter = null;
216224
} else {
217-
_effectiveColorFilter = ManagedSkColorFilter(value as CkColorFilter);
225+
final CkColorFilter ckColorFilter = (value as EngineColorFilter).toRendererColorFilter() as CkColorFilter;
226+
_effectiveColorFilter = ManagedSkColorFilter(ckColorFilter);
218227
}
219228

220229
if (invertColors) {
@@ -223,7 +232,12 @@ class CkPaint extends ManagedSkiaObject<SkPaint> implements ui.Paint {
223232
_effectiveColorFilter = _invertColorFilter;
224233
} else {
225234
_effectiveColorFilter = ManagedSkColorFilter(
226-
CkComposeColorFilter(_invertColorFilter, _effectiveColorFilter!));
235+
CkComposeColorFilter(
236+
_effectiveColorFilter!.colorFilter.creator,
237+
_invertColorFilter,
238+
_effectiveColorFilter!
239+
)
240+
);
227241
}
228242
}
229243

@@ -255,8 +269,12 @@ class CkPaint extends ManagedSkiaObject<SkPaint> implements ui.Paint {
255269
if (_imageFilter == value) {
256270
return;
257271
}
258-
259-
_imageFilter = value as CkManagedSkImageFilterConvertible?;
272+
if (value is ui.ColorFilter) {
273+
_imageFilter = (value as EngineColorFilter).toRendererColorFilter() as CkManagedSkImageFilterConvertible?;
274+
}
275+
else {
276+
_imageFilter = value as CkManagedSkImageFilterConvertible?;
277+
}
260278
_managedImageFilter = _imageFilter?.imageFilter;
261279
skiaObject.setImageFilter(_managedImageFilter?.skiaObject);
262280
}
@@ -305,8 +323,12 @@ final Float32List _invertColorMatrix = Float32List.fromList(const <double>[
305323
1.0, 1.0, 1.0, 1.0, 0
306324
]);
307325

308-
final ManagedSkColorFilter _invertColorFilter =
309-
ManagedSkColorFilter(CkMatrixColorFilter(_invertColorMatrix));
326+
final ManagedSkColorFilter _invertColorFilter = createInvertedColorFilter(_invertColorMatrix);
327+
328+
ManagedSkColorFilter createInvertedColorFilter(Float32List invertColorMatrix) {
329+
final ui.ColorFilter creator = ui.ColorFilter.matrix(invertColorMatrix);
330+
return ManagedSkColorFilter(CkMatrixColorFilter(creator, invertColorMatrix));
331+
}
310332

311333
class UniformData {
312334
const UniformData({

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import '../profiler.dart';
1616
import '../renderer.dart';
1717
import 'canvaskit_api.dart';
1818
import 'canvaskit_canvas.dart';
19+
import 'color_filter.dart';
1920
import 'fonts.dart';
2021
import 'image.dart';
2122
import 'image_filter.dart';
@@ -194,6 +195,27 @@ class CanvasKitRenderer implements Renderer {
194195
throw UnimplementedError('ImageFilter.compose not implemented for CanvasKit.');
195196
}
196197

198+
@override
199+
CkMatrixColorFilter createMatrixColorFilter(
200+
ui.ColorFilter creator,
201+
List<double> matrix
202+
) => CkMatrixColorFilter(creator, matrix);
203+
204+
@override
205+
CkBlendModeColorFilter createModeColorFilter(
206+
ui.ColorFilter creator,
207+
ui.Color color,
208+
ui.BlendMode blendMode
209+
) => CkBlendModeColorFilter(creator, color, blendMode);
210+
211+
@override
212+
CkLinearToSrgbGammaColorFilter createLinearToSrgbGammaColorFilter(ui.ColorFilter creator) =>
213+
CkLinearToSrgbGammaColorFilter(creator);
214+
215+
@override
216+
CkSrgbToLinearGammaColorFilter createSrgbToLinearGammaColorFilter(ui.ColorFilter creator) =>
217+
CkSrgbToLinearGammaColorFilter(creator);
218+
197219
@override
198220
Future<ui.Codec> instantiateImageCodec(
199221
Uint8List list, {

lib/web_ui/lib/src/engine/color_filter.dart

Lines changed: 72 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,15 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5+
import 'package:ui/src/engine/renderer.dart';
56
import 'package:ui/ui.dart' as ui;
67

7-
import 'canvaskit/color_filter.dart';
8+
enum ColorFilterType {
9+
mode,
10+
matrix,
11+
linearToSrgbGamma,
12+
srgbToLinearGamma,
13+
}
814

915
/// A description of a color filter to apply when drawing a shape or compositing
1016
/// a layer with a particular [Paint]. A color filter is a function that takes
@@ -22,8 +28,11 @@ class EngineColorFilter implements ui.ColorFilter {
2228
/// The output of this filter is then composited into the background according
2329
/// to the [Paint.blendMode], using the output of this filter as the source
2430
/// and the background as the destination.
25-
const factory EngineColorFilter.mode(ui.Color color, ui.BlendMode blendMode) =
26-
CkBlendModeColorFilter;
31+
const EngineColorFilter.mode(ui.Color color, ui.BlendMode blendMode)
32+
: _color = color,
33+
_blendMode = blendMode,
34+
_matrix = null,
35+
_type = ColorFilterType.mode;
2736

2837
/// Construct a color filter that transforms a color by a 5x5 matrix, where
2938
/// the fifth row is implicitly added in an identity configuration.
@@ -85,16 +94,70 @@ class EngineColorFilter implements ui.ColorFilter {
8594
/// 0, 0, 0, 1, 0,
8695
/// ]);
8796
/// ```
88-
const factory EngineColorFilter.matrix(List<double> matrix) =
89-
CkMatrixColorFilter;
97+
const EngineColorFilter.matrix(List<double> matrix)
98+
: _color = null,
99+
_blendMode = null,
100+
_matrix = matrix,
101+
_type = ColorFilterType.matrix;
90102

91103
/// Construct a color filter that applies the sRGB gamma curve to the RGB
92104
/// channels.
93-
const factory EngineColorFilter.linearToSrgbGamma() =
94-
CkLinearToSrgbGammaColorFilter;
105+
const EngineColorFilter.linearToSrgbGamma()
106+
: _color = null,
107+
_blendMode = null,
108+
_matrix = null,
109+
_type = ColorFilterType.linearToSrgbGamma;
95110

96111
/// Creates a color filter that applies the inverse of the sRGB gamma curve
97112
/// to the RGB channels.
98-
const factory EngineColorFilter.srgbToLinearGamma() =
99-
CkSrgbToLinearGammaColorFilter;
113+
const EngineColorFilter.srgbToLinearGamma()
114+
: _color = null,
115+
_blendMode = null,
116+
_matrix = null,
117+
_type = ColorFilterType.srgbToLinearGamma;
118+
119+
final ui.Color? _color;
120+
final ui.BlendMode? _blendMode;
121+
final List<double>? _matrix;
122+
final ColorFilterType _type;
123+
124+
/// Convert the current [ColorFilter] to either a [CkColorFilter] or [HtmlEngineColorFilter]
125+
/// depending on the renderer.
126+
///
127+
/// After calling this function and getting the renderer specific ColorFilter,
128+
/// cast the correct type on the converted ColorFilter based on the renderer backend:
129+
///
130+
/// canvaskit: [CkColorFilter]
131+
/// Html: [HtmlEngineColorFilter]
132+
///
133+
/// ## Example uses:
134+
/// ```
135+
/// CkColorFilter ckColorFilter =
136+
/// (ColorFilter.mode(Color color, BlendMode blendMode) as EngineColorFilter).toRendererColorFilter() as CkColorFilter;
137+
/// ```
138+
///
139+
/// This workaround allows ColorFilter to be const constructbile and
140+
/// efficiently comparable, so that widgets can check for ColorFilter equality to
141+
/// avoid repainting.
142+
dynamic toRendererColorFilter() {
143+
switch (_type) {
144+
case ColorFilterType.mode:
145+
if (_color == null || _blendMode == null) {
146+
return null;
147+
}
148+
return renderer.createModeColorFilter(this, _color!, _blendMode!);
149+
case ColorFilterType.matrix:
150+
if (_matrix == null) {
151+
return null;
152+
}
153+
assert(_matrix!.length == 20, 'Color Matrix must have 20 entries.');
154+
return renderer.createMatrixColorFilter(this, _matrix!);
155+
case ColorFilterType.linearToSrgbGamma:
156+
return renderer.createLinearToSrgbGammaColorFilter(this);
157+
case ColorFilterType.srgbToLinearGamma:
158+
return renderer.createSrgbToLinearGammaColorFilter(this);
159+
default:
160+
throw StateError('Unknown mode $_type for ColorFilter.');
161+
}
162+
}
100163
}

0 commit comments

Comments
 (0)