From d6cc556cbd228bac85e91cfdfee33b2f6962f870 Mon Sep 17 00:00:00 2001 From: Razvan Cristian Lung Date: Mon, 14 Jan 2019 00:35:49 +0200 Subject: [PATCH 1/7] add ColorFilter matrix support --- lib/ui/painting.dart | 120 ++++++++++++++++++++++++++++++++------- lib/ui/painting/paint.cc | 64 ++++++++++++++++----- lib/ui/text.dart | 6 +- 3 files changed, 152 insertions(+), 38 deletions(-) diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index ee71d37bdd123..350f91b922185 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -1082,7 +1082,8 @@ class Paint { // Binary format must match the deserialization code in paint.cc. List _objects; static const int _kShaderIndex = 0; - static const int _kObjectCount = 1; // Must be one larger than the largest index. + static const int _kColorFilterMatrixIndex = 1; + static const int _kObjectCount = 2; // Must be one larger than the largest index. /// Whether to apply anti-aliasing to lines and images drawn on the /// canvas. @@ -1336,25 +1337,49 @@ class Paint { /// /// When a shape is being drawn, [colorFilter] overrides [color] and [shader]. ColorFilter get colorFilter { - final bool isNull = _data.getInt32(_kColorFilterOffset, _kFakeHostEndian) == 0; - if (isNull) - return null; - return new ColorFilter.mode( - new Color(_data.getInt32(_kColorFilterColorOffset, _kFakeHostEndian)), - BlendMode.values[_data.getInt32(_kColorFilterBlendModeOffset, _kFakeHostEndian)] - ); + switch (_data.getInt32(_kColorFilterOffset, _kFakeHostEndian)) { + case ColorFilter._TypeNone: + return null; + case ColorFilter._TypeMode: + return new ColorFilter.mode( + new Color(_data.getInt32(_kColorFilterColorOffset, _kFakeHostEndian)), + BlendMode.values[_data.getInt32(_kColorFilterBlendModeOffset, _kFakeHostEndian)], + ); + case ColorFilter._TypeMatrix: + return new ColorFilter.matrix(_objects[_kColorFilterMatrixIndex]); + case ColorFilter._TypeLinearToSrgbGamma: + return const ColorFilter.linearToSrgbGamma(); + case ColorFilter._TypeSrgbToLinearGamma: + return const ColorFilter.srgbToLinearGamma(); + } + + return null; } + set colorFilter(ColorFilter value) { if (value == null) { - _data.setInt32(_kColorFilterOffset, 0, _kFakeHostEndian); + _data.setInt32(_kColorFilterOffset, ColorFilter._TypeNone, _kFakeHostEndian); _data.setInt32(_kColorFilterColorOffset, 0, _kFakeHostEndian); _data.setInt32(_kColorFilterBlendModeOffset, 0, _kFakeHostEndian); + + if (_objects != null) { + _objects[_kColorFilterMatrixIndex] = null; + } } else { - assert(value._color != null); - assert(value._blendMode != null); - _data.setInt32(_kColorFilterOffset, 1, _kFakeHostEndian); - _data.setInt32(_kColorFilterColorOffset, value._color.value, _kFakeHostEndian); - _data.setInt32(_kColorFilterBlendModeOffset, value._blendMode.index, _kFakeHostEndian); + _data.setInt32(_kColorFilterOffset, value._type, _kFakeHostEndian); + + if (value._type == ColorFilter._TypeMode) { + assert(value._color != null); + assert(value._blendMode != null); + + _data.setInt32(_kColorFilterColorOffset, value._color.value, _kFakeHostEndian); + _data.setInt32(_kColorFilterBlendModeOffset, value._blendMode.index, _kFakeHostEndian); + } else if (value._type == ColorFilter._TypeMatrix) { + assert(value._matrix != null); + + _objects ??= new List(_kObjectCount); + _objects[_kColorFilterMatrixIndex] = Float32List.fromList(value._matrix); + } } } @@ -2378,25 +2403,78 @@ class ColorFilter { /// to the [Paint.blendMode], using the output of this filter as the source /// and the background as the destination. const ColorFilter.mode(Color color, BlendMode blendMode) - : _color = color, _blendMode = blendMode; + : _color = color, + _blendMode = blendMode, + _matrix = null, + _type = _TypeMode; + + /// Construct a color filter that transforms a color by a 4x5 matrix. The + /// matrix is in row-major order and the translation column is specified in + /// unnormalized, 0...255, space. + const ColorFilter.matrix(List matrix) + : _color = null, + _blendMode = null, + _matrix = matrix, + _type = _TypeMatrix; + + /// Construct a color filter that applies the srgb gamma curve to the RGB + /// channels. + const ColorFilter.linearToSrgbGamma() + : _color = null, + _blendMode = null, + _matrix = null, + _type = _TypeLinearToSrgbGamma; + + /// Creates a color filter that applies the inverse of the srgb gamma curve + /// to the RGB channels. + const ColorFilter.srgbToLinearGamma() + : _color = null, + _blendMode = null, + _matrix = null, + _type = _TypeSrgbToLinearGamma; final Color _color; final BlendMode _blendMode; + final List _matrix; + final int _type; + + // The type of SkColorFilter class to create for Skia. + // These constants must be kept in sync with ColorFilterType in paint.cc. + static const int _TypeNone = 0; // null + static const int _TypeMode = 1; // MakeModeFilter + static const int _TypeMatrix = 2; // MakeMatrixFilterRowMajor255 + static const int _TypeLinearToSrgbGamma = 3; // MakeLinearToSRGBGamma + static const int _TypeSrgbToLinearGamma = 4; // MakeSRGBToLinearGamma @override bool operator ==(dynamic other) { - if (other is! ColorFilter) - return false; + if (other is! ColorFilter) return false; final ColorFilter typedOther = other; - return _color == typedOther._color && - _blendMode == typedOther._blendMode; + + if (_type != typedOther._type) return false; + if(!listEquals(_matrix, typedOther._matrix)) return false; + + return _color == typedOther._color && _blendMode == typedOther._blendMode; } @override - int get hashCode => hashValues(_color, _blendMode); + int get hashCode => hashValues(_color, _blendMode, hashList(_matrix), _type); @override - String toString() => 'ColorFilter($_color, $_blendMode)'; + String toString() { + switch (_type) { + case _TypeMode: + return 'ColorFilter.mode($_color, $_blendMode)'; + case _TypeMatrix: + return 'ColorFilter.matrix($_matrix)'; + case _TypeLinearToSrgbGamma: + return 'ColorFilter.linearToSrgbGamma()'; + case _TypeSrgbToLinearGamma: + return 'ColorFilter.srgbToLinearGamma()'; + default: + throw StateError('ColorFilter should have one of its values not null.'); + } + } } /// A filter operation to apply to a raster image. diff --git a/lib/ui/painting/paint.cc b/lib/ui/painting/paint.cc index 16e953933732b..27407677c73e1 100644 --- a/lib/ui/painting/paint.cc +++ b/lib/ui/painting/paint.cc @@ -11,6 +11,7 @@ #include "third_party/skia/include/core/SkShader.h" #include "third_party/skia/include/core/SkString.h" #include "third_party/tonic/typed_data/dart_byte_data.h" +#include "third_party/tonic/typed_data/float32_list.h" namespace blink { @@ -35,7 +36,8 @@ constexpr size_t kDataByteCount = 75; // 4 * (last index + 1) // Indices for objects. constexpr int kShaderIndex = 0; -constexpr int kObjectCount = 1; // One larger than largest object index. +constexpr int kColorFilterMatrixIndex = 1; +constexpr int kObjectCount = 2; // One larger than largest object index. // Must be kept in sync with the default in painting.dart. constexpr uint32_t kColorDefault = 0xFF000000; @@ -61,18 +63,54 @@ constexpr SkScalar invert_colors[20] = { // Must be kept in sync with the MaskFilter private constants in painting.dart. enum MaskFilterType { Null, Blur }; +// Must be kept in sync with the ColorFilter private constants in painting.dart. +enum ColorFilterType { None, Mode, Matrix, LinearToSRGBGamma, SRGBToLinearGamma }; + +sk_sp extract_color_filter(const uint32_t *uint_data, Dart_Handle values[]) { + switch (uint_data[kColorFilterIndex]) { + case Mode: { + SkColor color = uint_data[kColorFilterColorIndex]; + SkBlendMode blend_mode = + static_cast(uint_data[kColorFilterBlendModeIndex]); + return SkColorFilter::MakeModeFilter(color, blend_mode); + } + case Matrix: { + Dart_Handle matrixHandle = values[kColorFilterMatrixIndex]; + if (!Dart_IsNull(matrixHandle)) { + FML_DCHECK(Dart_IsList(matrixHandle)); + intptr_t length = 0; + Dart_ListLength(matrixHandle, &length); + + FML_CHECK(length == 20); + + tonic::Float32List decoded(matrixHandle); + return SkColorFilter::MakeMatrixFilterRowMajor255(decoded.data()); + } + return nullptr; + } + case LinearToSRGBGamma: { + return SkColorFilter::MakeLinearToSRGBGamma(); + } + case SRGBToLinearGamma: { + return SkColorFilter::MakeSRGBToLinearGamma(); + } + default: + return nullptr; + } +} + Paint::Paint(Dart_Handle paint_objects, Dart_Handle paint_data) { is_null_ = Dart_IsNull(paint_data); if (is_null_) return; + Dart_Handle values[kObjectCount]; if (!Dart_IsNull(paint_objects)) { FML_DCHECK(Dart_IsList(paint_objects)); intptr_t length = 0; Dart_ListLength(paint_objects, &length); FML_CHECK(length == kObjectCount); - Dart_Handle values[kObjectCount]; if (Dart_IsError(Dart_ListGetRange(paint_objects, 0, kObjectCount, values))) return; @@ -128,22 +166,20 @@ Paint::Paint(Dart_Handle paint_objects, Dart_Handle paint_data) { paint_.setFilterQuality(static_cast(filter_quality)); if (uint_data[kColorFilterIndex] && uint_data[kInvertColorIndex]) { - SkColor color = uint_data[kColorFilterColorIndex]; - SkBlendMode blend_mode = - static_cast(uint_data[kColorFilterBlendModeIndex]); - sk_sp color_filter = - SkColorFilter::MakeModeFilter(color, blend_mode); - sk_sp invert_filter = - SkColorFilter::MakeMatrixFilterRowMajor255(invert_colors); - paint_.setColorFilter(invert_filter->makeComposed(color_filter)); + sk_sp color_filter = extract_color_filter(uint_data, values); + if (color_filter) { + sk_sp invert_filter = + SkColorFilter::MakeMatrixFilterRowMajor255(invert_colors); + paint_.setColorFilter(invert_filter->makeComposed(color_filter)); + } } else if (uint_data[kInvertColorIndex]) { paint_.setColorFilter( SkColorFilter::MakeMatrixFilterRowMajor255(invert_colors)); } else if (uint_data[kColorFilterIndex]) { - SkColor color = uint_data[kColorFilterColorIndex]; - SkBlendMode blend_mode = - static_cast(uint_data[kColorFilterBlendModeIndex]); - paint_.setColorFilter(SkColorFilter::MakeModeFilter(color, blend_mode)); + sk_sp color_filter = extract_color_filter(uint_data, values); + if (color_filter) { + paint_.setColorFilter(color_filter); + } } switch (uint_data[kMaskFilterIndex]) { diff --git a/lib/ui/text.dart b/lib/ui/text.dart index 74fdcd3de8539..9be99477e4a2d 100644 --- a/lib/ui/text.dart +++ b/lib/ui/text.dart @@ -223,7 +223,7 @@ enum TextDecorationStyle { /// Returns true if the lists are both null, or if they are both non-null, have /// the same length, and contain the same elements in the same order. Returns /// false otherwise. -bool _listEquals(List a, List b) { +bool listEquals(List a, List b) { if (a == null) return b == null; if (b == null || a.length != b.length) @@ -458,9 +458,9 @@ class TextStyle { if (_encoded[index] != typedOther._encoded[index]) return false; } - if (!_listEquals(_shadows, typedOther._shadows)) + if (!listEquals(_shadows, typedOther._shadows)) return false; - if (!_listEquals(_fontFamilyFallback, typedOther._fontFamilyFallback)) + if (!listEquals(_fontFamilyFallback, typedOther._fontFamilyFallback)) return false; return true; } From fec66e7c3272e78840be948366346a2f062b344b Mon Sep 17 00:00:00 2001 From: Razvan Cristian Lung Date: Mon, 14 Jan 2019 00:51:51 +0200 Subject: [PATCH 2/7] fix formatting error --- lib/ui/painting/paint.cc | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/ui/painting/paint.cc b/lib/ui/painting/paint.cc index 27407677c73e1..196929778cdfd 100644 --- a/lib/ui/painting/paint.cc +++ b/lib/ui/painting/paint.cc @@ -64,14 +64,22 @@ constexpr SkScalar invert_colors[20] = { enum MaskFilterType { Null, Blur }; // Must be kept in sync with the ColorFilter private constants in painting.dart. -enum ColorFilterType { None, Mode, Matrix, LinearToSRGBGamma, SRGBToLinearGamma }; +enum ColorFilterType { + None, + Mode, + Matrix, + LinearToSRGBGamma, + SRGBToLinearGamma +}; -sk_sp extract_color_filter(const uint32_t *uint_data, Dart_Handle values[]) { +sk_sp extract_color_filter(const uint32_t* uint_data, + Dart_Handle values[]) { switch (uint_data[kColorFilterIndex]) { case Mode: { SkColor color = uint_data[kColorFilterColorIndex]; SkBlendMode blend_mode = static_cast(uint_data[kColorFilterBlendModeIndex]); + return SkColorFilter::MakeModeFilter(color, blend_mode); } case Matrix: { From f8753f26cba71cefccc17c33c3be968304947f9f Mon Sep 17 00:00:00 2001 From: Razvan Cristian Lung Date: Mon, 14 Jan 2019 01:02:14 +0200 Subject: [PATCH 3/7] fix formatting error --- lib/ui/painting.dart | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index 350f91b922185..4a682cff9233a 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -2448,11 +2448,17 @@ class ColorFilter { @override bool operator ==(dynamic other) { - if (other is! ColorFilter) return false; + if (other is! ColorFilter) { + return false; + } final ColorFilter typedOther = other; - if (_type != typedOther._type) return false; - if(!listEquals(_matrix, typedOther._matrix)) return false; + if (_type != typedOther._type) { + return false; + } + if (!listEquals(_matrix, typedOther._matrix)) { + return false; + } return _color == typedOther._color && _blendMode == typedOther._blendMode; } From 1cd9c3d7fca0d08b8b5f55b8606610ece7fcc6fe Mon Sep 17 00:00:00 2001 From: Razvan Cristian Lung Date: Mon, 14 Jan 2019 13:42:42 +0200 Subject: [PATCH 4/7] * log when kColorFilterIndex is out of range * remake `_listEquals` private --- lib/ui/painting.dart | 5 +++-- lib/ui/painting/paint.cc | 1 + lib/ui/text.dart | 6 +++--- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index 4a682cff9233a..434e5c532bb3b 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -2456,7 +2456,8 @@ class ColorFilter { if (_type != typedOther._type) { return false; } - if (!listEquals(_matrix, typedOther._matrix)) { + + if (!_listEquals(_matrix, typedOther._matrix)) { return false; } @@ -2478,7 +2479,7 @@ class ColorFilter { case _TypeSrgbToLinearGamma: return 'ColorFilter.srgbToLinearGamma()'; default: - throw StateError('ColorFilter should have one of its values not null.'); + return 'Unknown ColorFilter type. This is an error. If you\'re seeing this, please file an issue at https://github.com/flutter/flutter/issues/new.'; } } } diff --git a/lib/ui/painting/paint.cc b/lib/ui/painting/paint.cc index 196929778cdfd..25a5576107d4a 100644 --- a/lib/ui/painting/paint.cc +++ b/lib/ui/painting/paint.cc @@ -103,6 +103,7 @@ sk_sp extract_color_filter(const uint32_t* uint_data, return SkColorFilter::MakeSRGBToLinearGamma(); } default: + FML_DLOG(ERROR) << "Out of range value received for kColorFilterIndex."; return nullptr; } } diff --git a/lib/ui/text.dart b/lib/ui/text.dart index 9be99477e4a2d..74fdcd3de8539 100644 --- a/lib/ui/text.dart +++ b/lib/ui/text.dart @@ -223,7 +223,7 @@ enum TextDecorationStyle { /// Returns true if the lists are both null, or if they are both non-null, have /// the same length, and contain the same elements in the same order. Returns /// false otherwise. -bool listEquals(List a, List b) { +bool _listEquals(List a, List b) { if (a == null) return b == null; if (b == null || a.length != b.length) @@ -458,9 +458,9 @@ class TextStyle { if (_encoded[index] != typedOther._encoded[index]) return false; } - if (!listEquals(_shadows, typedOther._shadows)) + if (!_listEquals(_shadows, typedOther._shadows)) return false; - if (!listEquals(_fontFamilyFallback, typedOther._fontFamilyFallback)) + if (!_listEquals(_fontFamilyFallback, typedOther._fontFamilyFallback)) return false; return true; } From 63397c95f9fcded9cf5a1324f9c476086815c7e6 Mon Sep 17 00:00:00 2001 From: Razvan Cristian Lung Date: Mon, 14 Jan 2019 13:52:27 +0200 Subject: [PATCH 5/7] fix formatting error --- lib/ui/painting.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index 434e5c532bb3b..0a2c1a503061f 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -2456,7 +2456,6 @@ class ColorFilter { if (_type != typedOther._type) { return false; } - if (!_listEquals(_matrix, typedOther._matrix)) { return false; } From 37fd49e5f9f7455117519ef9bdbcdc3503d994ea Mon Sep 17 00:00:00 2001 From: Razvan Cristian Lung Date: Mon, 14 Jan 2019 20:29:05 +0200 Subject: [PATCH 6/7] rename extract_color_filter to ExtractColorFilter --- lib/ui/painting/paint.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/ui/painting/paint.cc b/lib/ui/painting/paint.cc index 25a5576107d4a..3e44f5a8619d1 100644 --- a/lib/ui/painting/paint.cc +++ b/lib/ui/painting/paint.cc @@ -72,8 +72,8 @@ enum ColorFilterType { SRGBToLinearGamma }; -sk_sp extract_color_filter(const uint32_t* uint_data, - Dart_Handle values[]) { +sk_sp ExtractColorFilter(const uint32_t *uint_data, + Dart_Handle *values) { switch (uint_data[kColorFilterIndex]) { case Mode: { SkColor color = uint_data[kColorFilterColorIndex]; @@ -175,7 +175,7 @@ Paint::Paint(Dart_Handle paint_objects, Dart_Handle paint_data) { paint_.setFilterQuality(static_cast(filter_quality)); if (uint_data[kColorFilterIndex] && uint_data[kInvertColorIndex]) { - sk_sp color_filter = extract_color_filter(uint_data, values); + sk_sp color_filter = ExtractColorFilter(uint_data, values); if (color_filter) { sk_sp invert_filter = SkColorFilter::MakeMatrixFilterRowMajor255(invert_colors); @@ -185,7 +185,7 @@ Paint::Paint(Dart_Handle paint_objects, Dart_Handle paint_data) { paint_.setColorFilter( SkColorFilter::MakeMatrixFilterRowMajor255(invert_colors)); } else if (uint_data[kColorFilterIndex]) { - sk_sp color_filter = extract_color_filter(uint_data, values); + sk_sp color_filter = ExtractColorFilter(uint_data, values); if (color_filter) { paint_.setColorFilter(color_filter); } From 9794bfbba3eb2e6c04735654b76a285087a403e2 Mon Sep 17 00:00:00 2001 From: Razvan Cristian Lung Date: Mon, 14 Jan 2019 20:31:56 +0200 Subject: [PATCH 7/7] fix formatting issues --- lib/ui/painting/paint.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ui/painting/paint.cc b/lib/ui/painting/paint.cc index 3e44f5a8619d1..4e67a48916eb1 100644 --- a/lib/ui/painting/paint.cc +++ b/lib/ui/painting/paint.cc @@ -72,8 +72,8 @@ enum ColorFilterType { SRGBToLinearGamma }; -sk_sp ExtractColorFilter(const uint32_t *uint_data, - Dart_Handle *values) { +sk_sp ExtractColorFilter(const uint32_t* uint_data, + Dart_Handle* values) { switch (uint_data[kColorFilterIndex]) { case Mode: { SkColor color = uint_data[kColorFilterColorIndex];