Skip to content

Commit

Permalink
Exposing ColorFilter to ImageFilter conversion and Compose() (flutter…
Browse files Browse the repository at this point in the history
  • Loading branch information
LongCatIsLooong authored Nov 12, 2020
1 parent 47f9e13 commit e872177
Show file tree
Hide file tree
Showing 15 changed files with 797 additions and 321 deletions.
268 changes: 182 additions & 86 deletions lib/ui/painting.dart

Large diffs are not rendered by default.

23 changes: 18 additions & 5 deletions lib/ui/painting/image_filter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include "flutter/lib/ui/painting/matrix.h"
#include "third_party/skia/include/effects/SkBlurImageFilter.h"
#include "third_party/skia/include/effects/SkImageFilters.h"
#include "third_party/skia/include/effects/SkImageSource.h"
#include "third_party/skia/include/effects/SkPictureImageFilter.h"
#include "third_party/tonic/converter/dart_converter.h"
Expand All @@ -22,11 +23,13 @@ static void ImageFilter_constructor(Dart_NativeArguments args) {

IMPLEMENT_WRAPPERTYPEINFO(ui, ImageFilter);

#define FOR_EACH_BINDING(V) \
V(ImageFilter, initImage) \
V(ImageFilter, initPicture) \
V(ImageFilter, initBlur) \
V(ImageFilter, initMatrix)
#define FOR_EACH_BINDING(V) \
V(ImageFilter, initImage) \
V(ImageFilter, initPicture) \
V(ImageFilter, initBlur) \
V(ImageFilter, initMatrix) \
V(ImageFilter, initColorFilter) \
V(ImageFilter, initComposeFilter)

FOR_EACH_BINDING(DART_NATIVE_CALLBACK)

Expand Down Expand Up @@ -64,4 +67,14 @@ void ImageFilter::initMatrix(const tonic::Float64List& matrix4,
nullptr);
}

void ImageFilter::initColorFilter(ColorFilter* colorFilter) {
filter_ = SkImageFilters::ColorFilter(
colorFilter ? colorFilter->filter() : nullptr, nullptr);
}

void ImageFilter::initComposeFilter(ImageFilter* outer, ImageFilter* inner) {
filter_ = SkImageFilters::Compose(outer ? outer->filter() : nullptr,
inner ? inner->filter() : nullptr);
}

} // namespace flutter
3 changes: 3 additions & 0 deletions lib/ui/painting/image_filter.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#define FLUTTER_LIB_UI_PAINTING_IMAGE_FILTER_H_

#include "flutter/lib/ui/dart_wrapper.h"
#include "flutter/lib/ui/painting/color_filter.h"
#include "flutter/lib/ui/painting/image.h"
#include "flutter/lib/ui/painting/picture.h"
#include "third_party/skia/include/core/SkImageFilter.h"
Expand All @@ -25,6 +26,8 @@ class ImageFilter : public RefCountedDartWrappable<ImageFilter> {
void initPicture(Picture*);
void initBlur(double sigma_x, double sigma_y);
void initMatrix(const tonic::Float64List& matrix4, int filter_quality);
void initColorFilter(ColorFilter* colorFilter);
void initComposeFilter(ImageFilter* outer, ImageFilter* inner);

const sk_sp<SkImageFilter>& filter() const { return filter_; }

Expand Down
22 changes: 10 additions & 12 deletions lib/web_ui/lib/src/engine/bitmap_canvas.dart
Original file line number Diff line number Diff line change
Expand Up @@ -573,15 +573,10 @@ class BitmapCanvas extends EngineCanvas {
ui.Image image, ui.Offset p, SurfacePaintData paint) {
final HtmlImage htmlImage = image as HtmlImage;
final ui.BlendMode? blendMode = paint.blendMode;
final EngineColorFilter? colorFilter =
paint.colorFilter as EngineColorFilter?;
final ui.BlendMode? colorFilterBlendMode = colorFilter?._blendMode;
final EngineColorFilter? colorFilter = paint.colorFilter as EngineColorFilter?;
html.HtmlElement imgElement;
if (colorFilterBlendMode == null) {
// No Blending, create an image by cloning original loaded image.
imgElement = _reuseOrCreateImage(htmlImage);
} else {
switch (colorFilterBlendMode) {
if (colorFilter is _CkBlendModeColorFilter) {
switch (colorFilter.blendMode) {
case ui.BlendMode.colorBurn:
case ui.BlendMode.colorDodge:
case ui.BlendMode.hue:
Expand All @@ -595,14 +590,17 @@ class BitmapCanvas extends EngineCanvas {
case ui.BlendMode.color:
case ui.BlendMode.luminosity:
case ui.BlendMode.xor:
imgElement = _createImageElementWithSvgFilter(
image, colorFilter!._color, colorFilterBlendMode, paint);
imgElement = _createImageElementWithSvgFilter(image,
colorFilter.color, colorFilter.blendMode, paint);
break;
default:
imgElement = _createBackgroundImageWithBlend(
image, colorFilter!._color, colorFilterBlendMode, paint);
imgElement = _createBackgroundImageWithBlend(image,
colorFilter.color, colorFilter.blendMode, paint);
break;
}
} else {
// No Blending, create an image by cloning original loaded image.
imgElement = _reuseOrCreateImage(htmlImage);
}
imgElement.style.mixBlendMode = _stringForBlendMode(blendMode) ?? '';
if (_canvasPool.isClipped) {
Expand Down
4 changes: 2 additions & 2 deletions lib/web_ui/lib/src/engine/canvaskit/canvas.dart
Original file line number Diff line number Diff line change
Expand Up @@ -241,11 +241,11 @@ class CkCanvas {
}

void saveLayerWithFilter(ui.Rect bounds, ui.ImageFilter filter) {
final CkImageFilter skImageFilter = filter as CkImageFilter;
final _CkManagedSkImageFilterConvertible convertible = filter as _CkManagedSkImageFilterConvertible;
return skCanvas.saveLayer(
null,
toSkRect(bounds),
skImageFilter.skiaObject,
convertible._imageFilter.skiaObject,
0,
);
}
Expand Down
10 changes: 10 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 @@ -823,6 +823,16 @@ class SkImageFilterNamespace {
SkFilterQuality filterQuality,
Null input, // we don't use this yet
);

external SkImageFilter MakeColorFilter(
SkColorFilter colorFilter,
Null input, // we don't use this yet
);

external SkImageFilter MakeCompose(
SkImageFilter outer,
SkImageFilter inner,
);
}

@JS()
Expand Down
181 changes: 133 additions & 48 deletions lib/web_ui/lib/src/engine/canvaskit/color_filter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,62 +5,147 @@
// @dart = 2.10
part of engine;

/// A [ui.ColorFilter] backed by Skia's [CkColorFilter].
class CkColorFilter extends ManagedSkiaObject<SkColorFilter> {
final EngineColorFilter _engineFilter;

CkColorFilter.mode(EngineColorFilter filter) : _engineFilter = filter;

CkColorFilter.matrix(EngineColorFilter filter) : _engineFilter = filter;

CkColorFilter.linearToSrgbGamma(EngineColorFilter filter)
: _engineFilter = filter;

CkColorFilter.srgbToLinearGamma(EngineColorFilter filter)
: _engineFilter = filter;

SkColorFilter _createSkiaObjectFromFilter() {
SkColorFilter skColorFilter;
switch (_engineFilter._type) {
case EngineColorFilter._TypeMode:
skColorFilter = canvasKit.SkColorFilter.MakeBlend(
toSharedSkColor1(_engineFilter._color!),
toSkBlendMode(_engineFilter._blendMode!),
);
break;
case EngineColorFilter._TypeMatrix:
final Float32List colorMatrix = Float32List(20);
final List<double> matrix = _engineFilter._matrix!;
for (int i = 0; i < 20; i++) {
colorMatrix[i] = matrix[i];
}
skColorFilter = canvasKit.SkColorFilter.MakeMatrix(colorMatrix);
break;
case EngineColorFilter._TypeLinearToSrgbGamma:
skColorFilter = canvasKit.SkColorFilter.MakeLinearToSRGBGamma();
break;
case EngineColorFilter._TypeSrgbToLinearGamma:
skColorFilter = canvasKit.SkColorFilter.MakeSRGBToLinearGamma();
break;
default:
throw StateError(
'Unknown mode ${_engineFilter._type} for ColorFilter.');
}
return skColorFilter;
/// A concrete [ManagedSkiaObject] subclass that owns a [SkColorFilter] and
/// manages its lifecycle.
///
/// Seealso:
///
/// * [CkPaint.colorFilter], which uses a [_ManagedSkColorFilter] to manage
/// the lifecycle of its [SkColorFilter].
class _ManagedSkColorFilter extends ManagedSkiaObject<SkColorFilter> {
_ManagedSkColorFilter(CkColorFilter ckColorFilter)
: this.ckColorFilter = ckColorFilter;

final CkColorFilter ckColorFilter;

@override
SkColorFilter createDefault() => ckColorFilter._initRawColorFilter();

@override
SkColorFilter resurrect() => ckColorFilter._initRawColorFilter();

@override
void delete() {
rawSkiaObject?.delete();
}

@override
SkColorFilter createDefault() {
return _createSkiaObjectFromFilter();
int get hashCode => ckColorFilter.hashCode;

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

@override
SkColorFilter resurrect() {
return _createSkiaObjectFromFilter();
String toString() => ckColorFilter.toString();
}

/// A [ui.ColorFilter] backed by Skia's [SkColorFilter].
///
/// Additionally, this class provides the interface for converting itself to a
/// [ManagedSkiaObject] that manages a skia image filter.
abstract class CkColorFilter implements _CkManagedSkImageFilterConvertible<SkImageFilter>, EngineColorFilter {
const CkColorFilter();

/// Called by [ManagedSkiaObject.createDefault] and
/// [ManagedSkiaObject.resurrect] to create a new [SKImageFilter], when this
/// filter is used as an [ImageFilter].
SkImageFilter _initRawImageFilter() => canvasKit.SkImageFilter.MakeColorFilter(_initRawColorFilter(), null);

/// Called by [ManagedSkiaObject.createDefault] and
/// [ManagedSkiaObject.resurrect] to create a new [SKColorFilter], when this
/// filter is used as a [ColorFilter].
SkColorFilter _initRawColorFilter();

ManagedSkiaObject<SkImageFilter> get _imageFilter => _CkColorFilterImageFilter(colorFilter: this);
}

class _CkBlendModeColorFilter extends CkColorFilter {
const _CkBlendModeColorFilter(this.color, this.blendMode);

final ui.Color color;
final ui.BlendMode blendMode;

@override
SkColorFilter _initRawColorFilter() {
return canvasKit.SkColorFilter.MakeBlend(
toSharedSkColor1(color),
toSkBlendMode(blendMode),
);
}

@override
void delete() {
rawSkiaObject?.delete();
int get hashCode => ui.hashValues(color, blendMode);

@override
bool operator ==(Object other) {
if (runtimeType != other.runtimeType)
return false;
return other is _CkBlendModeColorFilter
&& other.color == color
&& other.blendMode == blendMode;
}

@override
String toString() => 'ColorFilter.mode($color, $blendMode)';
}

class _CkMatrixColorFilter extends CkColorFilter {
const _CkMatrixColorFilter(this.matrix);

final List<double> matrix;

@override
SkColorFilter _initRawColorFilter() {
assert(this.matrix.length == 20, 'Color Matrix must have 20 entries.');
final List<double> matrix = this.matrix;
if (matrix is Float32List)
return canvasKit.SkColorFilter.MakeMatrix(matrix);
final Float32List float32Matrix = Float32List(20);
for (int i = 0; i < 20; i++) {
float32Matrix[i] = matrix[i];
}
return canvasKit.SkColorFilter.MakeMatrix(float32Matrix);
}

@override
int get hashCode => ui.hashList(matrix);

@override
bool operator ==(Object other) {
return runtimeType == other.runtimeType
&& other is _CkMatrixColorFilter
&& _listEquals<double>(matrix, other.matrix);
}

@override
String toString() => 'ColorFilter.matrix($matrix)';
}

class _CkLinearToSrgbGammaColorFilter extends CkColorFilter {
const _CkLinearToSrgbGammaColorFilter();
@override
SkColorFilter _initRawColorFilter() => canvasKit.SkColorFilter.MakeLinearToSRGBGamma();

@override
bool operator ==(Object other) => runtimeType == other.runtimeType;

@override
String toString() => 'ColorFilter.linearToSrgbGamma()';
}

class _CkSrgbToLinearGammaColorFilter extends CkColorFilter {
const _CkSrgbToLinearGammaColorFilter();
@override
SkColorFilter _initRawColorFilter() => canvasKit.SkColorFilter.MakeSRGBToLinearGamma();

@override
bool operator ==(Object other) => runtimeType == other.runtimeType;

@override
String toString() => 'ColorFilter.srgbToLinearGamma()';
}
Loading

0 comments on commit e872177

Please sign in to comment.