diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index e2fe0521a6ac7..af08b848cf910 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -1065,6 +1065,7 @@ class Paint { static const int _kMaskFilterIndex = 12; static const int _kMaskFilterBlurStyleIndex = 13; static const int _kMaskFilterSigmaIndex = 14; + static const int _kInvertColorIndex = 15; static const int _kIsAntiAliasOffset = _kIsAntiAliasIndex << 2; static const int _kColorOffset = _kColorIndex << 2; @@ -1081,6 +1082,7 @@ class Paint { static const int _kMaskFilterOffset = _kMaskFilterIndex << 2; static const int _kMaskFilterBlurStyleOffset = _kMaskFilterBlurStyleIndex << 2; static const int _kMaskFilterSigmaOffset = _kMaskFilterSigmaIndex << 2; + static const int _kInvertColorOffset = _kInvertColorIndex << 2; // If you add more fields, remember to update _kDataByteCount. static const int _kDataByteCount = 75; @@ -1363,6 +1365,18 @@ class Paint { } } + /// Whether the colors of the image are inverted when drawn. + /// + /// inverting the colors of an image applies a new color filter that will + /// be composed with any user provided color filters. This is primarily + /// used for implementing smart invert on iOS. + bool get invertColors { + return _data.getInt32(_kInvertColorOffset, _kFakeHostEndian) == 1; + } + set invertColors(bool value) { + _data.setInt32(_kInvertColorOffset, value ? 1 : 0, _kFakeHostEndian); + } + @override String toString() { final StringBuffer result = new StringBuffer(); @@ -1411,8 +1425,12 @@ class Paint { result.write('${semicolon}filterQuality: $filterQuality'); semicolon = '; '; } - if (shader != null) + if (shader != null) { result.write('${semicolon}shader: $shader'); + semicolon = '; '; + } + if (invertColors) + result.write('${semicolon}invert: $invertColors'); result.write(')'); return result.toString(); } diff --git a/lib/ui/painting/paint.cc b/lib/ui/painting/paint.cc index 00631451549ee..9b876542a61a7 100644 --- a/lib/ui/painting/paint.cc +++ b/lib/ui/painting/paint.cc @@ -30,6 +30,7 @@ constexpr int kColorFilterBlendModeIndex = 11; constexpr int kMaskFilterIndex = 12; constexpr int kMaskFilterBlurStyleIndex = 13; constexpr int kMaskFilterSigmaIndex = 14; +constexpr int kInvertColorIndex = 15; constexpr size_t kDataByteCount = 75; // 4 * (last index + 1) // Indices for objects. @@ -47,6 +48,16 @@ constexpr uint32_t kBlendModeDefault = // default SkPaintDefaults_MiterLimit in Skia (which is not in a public header). constexpr double kStrokeMiterLimitDefault = 4.0; +// A color matrix which inverts colors. +// clang-format off +constexpr SkScalar invert_colors[20] = { + -1.0, 0, 0, 1.0, 0, + 0, -1.0, 0, 1.0, 0, + 0, 0, -1.0, 1.0, 0, + 1.0, 1.0, 1.0, 1.0, 0 +}; +// clang-format on + // Must be kept in sync with the MaskFilter private constants in painting.dart. enum MaskFilterType { Null, Blur }; @@ -116,7 +127,19 @@ Paint::Paint(Dart_Handle paint_objects, Dart_Handle paint_data) { if (filter_quality) paint_.setFilterQuality(static_cast(filter_quality)); - if (uint_data[kColorFilterIndex]) { + 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)); + } 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]);