Skip to content

Commit 887e052

Browse files
authored
Refactor ColorFilter to have a native wrapper (flutter#9668)
1 parent 75387db commit 887e052

File tree

8 files changed

+326
-128
lines changed

8 files changed

+326
-128
lines changed

ci/licenses_golden/licenses_flutter

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,8 @@ FILE: ../../../flutter/lib/ui/painting/canvas.cc
332332
FILE: ../../../flutter/lib/ui/painting/canvas.h
333333
FILE: ../../../flutter/lib/ui/painting/codec.cc
334334
FILE: ../../../flutter/lib/ui/painting/codec.h
335+
FILE: ../../../flutter/lib/ui/painting/color_filter.cc
336+
FILE: ../../../flutter/lib/ui/painting/color_filter.h
335337
FILE: ../../../flutter/lib/ui/painting/engine_layer.cc
336338
FILE: ../../../flutter/lib/ui/painting/engine_layer.h
337339
FILE: ../../../flutter/lib/ui/painting/frame_info.cc

lib/ui/BUILD.gn

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ source_set("ui") {
2424
"painting/canvas.h",
2525
"painting/codec.cc",
2626
"painting/codec.h",
27+
"painting/color_filter.cc",
28+
"painting/color_filter.h",
2729
"painting/engine_layer.cc",
2830
"painting/engine_layer.h",
2931
"painting/frame_info.cc",

lib/ui/dart_ui.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "flutter/lib/ui/isolate_name_server/isolate_name_server_natives.h"
1212
#include "flutter/lib/ui/painting/canvas.h"
1313
#include "flutter/lib/ui/painting/codec.h"
14+
#include "flutter/lib/ui/painting/color_filter.h"
1415
#include "flutter/lib/ui/painting/engine_layer.h"
1516
#include "flutter/lib/ui/painting/frame_info.h"
1617
#include "flutter/lib/ui/painting/gradient.h"
@@ -75,6 +76,7 @@ void DartUI::InitForGlobal() {
7576
CanvasPath::RegisterNatives(g_natives);
7677
CanvasPathMeasure::RegisterNatives(g_natives);
7778
Codec::RegisterNatives(g_natives);
79+
ColorFilter::RegisterNatives(g_natives);
7880
DartRuntimeHooks::RegisterNatives(g_natives);
7981
EngineLayer::RegisterNatives(g_natives);
8082
FontCollection::RegisterNatives(g_natives);

lib/ui/painting.dart

Lines changed: 81 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1056,13 +1056,10 @@ class Paint {
10561056
static const int _kStrokeJoinIndex = 6;
10571057
static const int _kStrokeMiterLimitIndex = 7;
10581058
static const int _kFilterQualityIndex = 8;
1059-
static const int _kColorFilterIndex = 9;
1060-
static const int _kColorFilterColorIndex = 10;
1061-
static const int _kColorFilterBlendModeIndex = 11;
1062-
static const int _kMaskFilterIndex = 12;
1063-
static const int _kMaskFilterBlurStyleIndex = 13;
1064-
static const int _kMaskFilterSigmaIndex = 14;
1065-
static const int _kInvertColorIndex = 15;
1059+
static const int _kMaskFilterIndex = 9;
1060+
static const int _kMaskFilterBlurStyleIndex = 10;
1061+
static const int _kMaskFilterSigmaIndex = 11;
1062+
static const int _kInvertColorIndex = 12;
10661063

10671064
static const int _kIsAntiAliasOffset = _kIsAntiAliasIndex << 2;
10681065
static const int _kColorOffset = _kColorIndex << 2;
@@ -1073,20 +1070,17 @@ class Paint {
10731070
static const int _kStrokeJoinOffset = _kStrokeJoinIndex << 2;
10741071
static const int _kStrokeMiterLimitOffset = _kStrokeMiterLimitIndex << 2;
10751072
static const int _kFilterQualityOffset = _kFilterQualityIndex << 2;
1076-
static const int _kColorFilterOffset = _kColorFilterIndex << 2;
1077-
static const int _kColorFilterColorOffset = _kColorFilterColorIndex << 2;
1078-
static const int _kColorFilterBlendModeOffset = _kColorFilterBlendModeIndex << 2;
10791073
static const int _kMaskFilterOffset = _kMaskFilterIndex << 2;
10801074
static const int _kMaskFilterBlurStyleOffset = _kMaskFilterBlurStyleIndex << 2;
10811075
static const int _kMaskFilterSigmaOffset = _kMaskFilterSigmaIndex << 2;
10821076
static const int _kInvertColorOffset = _kInvertColorIndex << 2;
10831077
// If you add more fields, remember to update _kDataByteCount.
1084-
static const int _kDataByteCount = 75;
1078+
static const int _kDataByteCount = 52;
10851079

10861080
// Binary format must match the deserialization code in paint.cc.
10871081
List<dynamic> _objects;
10881082
static const int _kShaderIndex = 0;
1089-
static const int _kColorFilterMatrixIndex = 1;
1083+
static const int _kColorFilterIndex = 1;
10901084
static const int _kImageFilterIndex = 2;
10911085
static const int _kObjectCount = 3; // Must be one larger than the largest index.
10921086

@@ -1342,48 +1336,23 @@ class Paint {
13421336
///
13431337
/// When a shape is being drawn, [colorFilter] overrides [color] and [shader].
13441338
ColorFilter get colorFilter {
1345-
switch (_data.getInt32(_kColorFilterOffset, _kFakeHostEndian)) {
1346-
case ColorFilter._TypeNone:
1347-
return null;
1348-
case ColorFilter._TypeMode:
1349-
return ColorFilter.mode(
1350-
Color(_data.getInt32(_kColorFilterColorOffset, _kFakeHostEndian)),
1351-
BlendMode.values[_data.getInt32(_kColorFilterBlendModeOffset, _kFakeHostEndian)],
1352-
);
1353-
case ColorFilter._TypeMatrix:
1354-
return ColorFilter.matrix(_objects[_kColorFilterMatrixIndex]);
1355-
case ColorFilter._TypeLinearToSrgbGamma:
1356-
return const ColorFilter.linearToSrgbGamma();
1357-
case ColorFilter._TypeSrgbToLinearGamma:
1358-
return const ColorFilter.srgbToLinearGamma();
1339+
if (_objects == null || _objects[_kColorFilterIndex] == null) {
1340+
return null;
13591341
}
1360-
1361-
return null;
1342+
return _objects[_kColorFilterIndex].creator;
13621343
}
13631344

13641345
set colorFilter(ColorFilter value) {
13651346
if (value == null) {
1366-
_data.setInt32(_kColorFilterOffset, ColorFilter._TypeNone, _kFakeHostEndian);
1367-
_data.setInt32(_kColorFilterColorOffset, 0, _kFakeHostEndian);
1368-
_data.setInt32(_kColorFilterBlendModeOffset, 0, _kFakeHostEndian);
1369-
13701347
if (_objects != null) {
1371-
_objects[_kColorFilterMatrixIndex] = null;
1348+
_objects[_kColorFilterIndex] = null;
13721349
}
13731350
} else {
1374-
_data.setInt32(_kColorFilterOffset, value._type, _kFakeHostEndian);
1375-
1376-
if (value._type == ColorFilter._TypeMode) {
1377-
assert(value._color != null);
1378-
assert(value._blendMode != null);
1379-
1380-
_data.setInt32(_kColorFilterColorOffset, value._color.value, _kFakeHostEndian);
1381-
_data.setInt32(_kColorFilterBlendModeOffset, value._blendMode.index, _kFakeHostEndian);
1382-
} else if (value._type == ColorFilter._TypeMatrix) {
1383-
assert(value._matrix != null);
1384-
1385-
_objects ??= List<dynamic>(_kObjectCount);
1386-
_objects[_kColorFilterMatrixIndex] = Float32List.fromList(value._matrix);
1351+
if (_objects == null) {
1352+
_objects = List<dynamic>(_kObjectCount);
1353+
_objects[_kColorFilterIndex] = value._toNativeColorFilter();
1354+
} else if (_objects[_kColorFilterIndex]?.creator != value) {
1355+
_objects[_kColorFilterIndex] = value._toNativeColorFilter();
13871356
}
13881357
}
13891358
}
@@ -2520,7 +2489,9 @@ class ColorFilter {
25202489
/// to the [Paint.blendMode], using the output of this filter as the source
25212490
/// and the background as the destination.
25222491
const ColorFilter.mode(Color color, BlendMode blendMode)
2523-
: _color = color,
2492+
: assert(color != null),
2493+
assert(blendMode != null),
2494+
_color = color,
25242495
_blendMode = blendMode,
25252496
_matrix = null,
25262497
_type = _TypeMode;
@@ -2529,7 +2500,9 @@ class ColorFilter {
25292500
/// matrix is in row-major order and the translation column is specified in
25302501
/// unnormalized, 0...255, space.
25312502
const ColorFilter.matrix(List<double> matrix)
2532-
: _color = null,
2503+
: assert(matrix != null),
2504+
assert(matrix.length == 20),
2505+
_color = null,
25332506
_blendMode = null,
25342507
_matrix = matrix,
25352508
_type = _TypeMatrix;
@@ -2580,6 +2553,21 @@ class ColorFilter {
25802553
return _color == typedOther._color && _blendMode == typedOther._blendMode;
25812554
}
25822555

2556+
_ColorFilter _toNativeColorFilter() {
2557+
switch (_type) {
2558+
case _TypeMode:
2559+
return _ColorFilter.mode(this);
2560+
case _TypeMatrix:
2561+
return _ColorFilter.matrix(this);
2562+
case _TypeLinearToSrgbGamma:
2563+
return _ColorFilter.linearToSrgbGamma(this);
2564+
case _TypeSrgbToLinearGamma:
2565+
return _ColorFilter.srgbToLinearGamma(this);
2566+
default:
2567+
throw StateError('Unknown mode $_type for ColorFilter.');
2568+
}
2569+
}
2570+
25832571
@override
25842572
int get hashCode => hashValues(_color, _blendMode, hashList(_matrix), _type);
25852573

@@ -2600,6 +2588,51 @@ class ColorFilter {
26002588
}
26012589
}
26022590

2591+
/// A [ColorFilter] that is backed by a native SkColorFilter.
2592+
///
2593+
/// This is a private class, rather than being the implementation of the public
2594+
/// ColorFilter, because we want ColorFilter to be const constructible and
2595+
/// efficiently comparable, so that widgets can check for ColorFilter equality to
2596+
// avoid repainting.
2597+
class _ColorFilter extends NativeFieldWrapperClass2 {
2598+
_ColorFilter.mode(this.creator)
2599+
: assert(creator != null),
2600+
assert(creator._type == ColorFilter._TypeMode) {
2601+
_constructor();
2602+
_initMode(creator._color.value, creator._blendMode.index);
2603+
}
2604+
2605+
_ColorFilter.matrix(this.creator)
2606+
: assert(creator != null),
2607+
assert(creator._type == ColorFilter._TypeMatrix) {
2608+
_constructor();
2609+
_initMatrix(Float32List.fromList(creator._matrix));
2610+
}
2611+
_ColorFilter.linearToSrgbGamma(this.creator)
2612+
: assert(creator != null),
2613+
assert(creator._type == ColorFilter._TypeLinearToSrgbGamma) {
2614+
_constructor();
2615+
_initLinearToSrgbGamma();
2616+
}
2617+
2618+
_ColorFilter.srgbToLinearGamma(this.creator)
2619+
: assert(creator != null),
2620+
assert(creator._type == ColorFilter._TypeSrgbToLinearGamma) {
2621+
_constructor();
2622+
_initSrgbToLinearGamma();
2623+
}
2624+
2625+
/// The original Dart object that created the native wrapper, which retains
2626+
/// the values used for the filter.
2627+
final ColorFilter creator;
2628+
2629+
void _constructor() native 'ColorFilter_constructor';
2630+
void _initMode(int color, int blendMode) native 'ColorFilter_initMode';
2631+
void _initMatrix(Float32List matrix) native 'ColorFilter_initMatrix';
2632+
void _initLinearToSrgbGamma() native 'ColorFilter_initLinearToSrgbGamma';
2633+
void _initSrgbToLinearGamma() native 'ColorFilter_initSrgbToLinearGamma';
2634+
}
2635+
26032636
/// A filter operation to apply to a raster image.
26042637
///
26052638
/// See also:

lib/ui/painting/color_filter.cc

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#include "flutter/lib/ui/painting/color_filter.h"
6+
7+
#include "third_party/tonic/converter/dart_converter.h"
8+
#include "third_party/tonic/dart_args.h"
9+
#include "third_party/tonic/dart_binding_macros.h"
10+
#include "third_party/tonic/dart_library_natives.h"
11+
12+
namespace flutter {
13+
14+
static void ColorFilter_constructor(Dart_NativeArguments args) {
15+
DartCallConstructor(&ColorFilter::Create, args);
16+
}
17+
18+
IMPLEMENT_WRAPPERTYPEINFO(ui, ColorFilter);
19+
20+
#define FOR_EACH_BINDING(V) \
21+
V(ColorFilter, initMode) \
22+
V(ColorFilter, initMatrix) \
23+
V(ColorFilter, initSrgbToLinearGamma) \
24+
V(ColorFilter, initLinearToSrgbGamma)
25+
26+
FOR_EACH_BINDING(DART_NATIVE_CALLBACK)
27+
28+
void ColorFilter::RegisterNatives(tonic::DartLibraryNatives* natives) {
29+
natives->Register(
30+
{{"ColorFilter_constructor", ColorFilter_constructor, 1, true},
31+
FOR_EACH_BINDING(DART_REGISTER_NATIVE)});
32+
}
33+
34+
fml::RefPtr<ColorFilter> ColorFilter::Create() {
35+
return fml::MakeRefCounted<ColorFilter>();
36+
}
37+
38+
void ColorFilter::initMode(int color, int blend_mode) {
39+
filter_ = SkColorFilters::Blend(static_cast<SkColor>(color),
40+
static_cast<SkBlendMode>(blend_mode));
41+
}
42+
43+
sk_sp<SkColorFilter> ColorFilter::MakeColorMatrixFilter255(
44+
const float array[20]) {
45+
float tmp[20];
46+
memcpy(tmp, array, sizeof(tmp));
47+
tmp[4] *= 1.0f / 255;
48+
tmp[9] *= 1.0f / 255;
49+
tmp[14] *= 1.0f / 255;
50+
tmp[19] *= 1.0f / 255;
51+
return SkColorFilters::Matrix(tmp);
52+
}
53+
54+
void ColorFilter::initMatrix(const tonic::Float32List& color_matrix) {
55+
FML_CHECK(color_matrix.num_elements() == 20);
56+
57+
filter_ = MakeColorMatrixFilter255(color_matrix.data());
58+
}
59+
60+
void ColorFilter::initLinearToSrgbGamma() {
61+
filter_ = SkColorFilters::LinearToSRGBGamma();
62+
}
63+
64+
void ColorFilter::initSrgbToLinearGamma() {
65+
filter_ = SkColorFilters::SRGBToLinearGamma();
66+
}
67+
68+
ColorFilter::~ColorFilter() = default;
69+
70+
} // namespace flutter

lib/ui/painting/color_filter.h

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#ifndef FLUTTER_LIB_UI_COLOR_FILTER_H_
6+
#define FLUTTER_LIB_UI_COLOR_FILTER_H_
7+
8+
#include "flutter/lib/ui/dart_wrapper.h"
9+
#include "third_party/skia/include/core/SkColorFilter.h"
10+
#include "third_party/tonic/typed_data/typed_list.h"
11+
12+
using tonic::DartPersistentValue;
13+
14+
namespace tonic {
15+
class DartLibraryNatives;
16+
} // namespace tonic
17+
18+
namespace flutter {
19+
20+
// A handle to an SkCodec object.
21+
//
22+
// Doesn't mirror SkCodec's API but provides a simple sequential access API.
23+
class ColorFilter : public RefCountedDartWrappable<ColorFilter> {
24+
DEFINE_WRAPPERTYPEINFO();
25+
FML_FRIEND_MAKE_REF_COUNTED(ColorFilter);
26+
27+
public:
28+
static fml::RefPtr<ColorFilter> Create();
29+
30+
// Flutter still defines the matrix to be biased by 255 in the last column
31+
// (translate). skia is normalized, treating the last column as 0...1, so we
32+
// post-scale here before calling the skia factory.
33+
static sk_sp<SkColorFilter> MakeColorMatrixFilter255(const float array[20]);
34+
35+
void initMode(int color, int blend_mode);
36+
void initMatrix(const tonic::Float32List& color_matrix);
37+
void initSrgbToLinearGamma();
38+
void initLinearToSrgbGamma();
39+
40+
~ColorFilter() override;
41+
42+
sk_sp<SkColorFilter> filter() const { return filter_; }
43+
44+
static void RegisterNatives(tonic::DartLibraryNatives* natives);
45+
46+
private:
47+
sk_sp<SkColorFilter> filter_;
48+
};
49+
50+
} // namespace flutter
51+
52+
#endif // FLUTTER_LIB_UI_COLOR_FILTER_H_

0 commit comments

Comments
 (0)