blob: 4e7d8e203fc4d1dedb29e8edf6755d42150186d1 [file] [log] [blame]
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:ui/ui.dart' as ui;
import 'canvaskit_api.dart';
import 'color_filter.dart';
import 'image_filter.dart';
import 'mask_filter.dart';
import 'shader.dart';
import 'skia_object_cache.dart';
/// The implementation of [ui.Paint] used by the CanvasKit backend.
///
/// This class is backed by a Skia object that must be explicitly
/// deleted to avoid a memory leak. This is done by extending [SkiaObject].
class CkPaint extends ManagedSkiaObject<SkPaint> implements ui.Paint {
CkPaint();
static const ui.Color _defaultPaintColor = ui.Color(0xFF000000);
@override
ui.BlendMode get blendMode => _blendMode;
@override
set blendMode(ui.BlendMode value) {
if (_blendMode == value) {
return;
}
_blendMode = value;
skiaObject.setBlendMode(toSkBlendMode(value));
}
ui.BlendMode _blendMode = ui.BlendMode.srcOver;
@override
ui.PaintingStyle get style => _style;
@override
set style(ui.PaintingStyle value) {
if (_style == value) {
return;
}
_style = value;
skiaObject.setStyle(toSkPaintStyle(value));
}
ui.PaintingStyle _style = ui.PaintingStyle.fill;
@override
double get strokeWidth => _strokeWidth;
@override
set strokeWidth(double value) {
if (_strokeWidth == value) {
return;
}
_strokeWidth = value;
skiaObject.setStrokeWidth(value);
}
double _strokeWidth = 0.0;
@override
ui.StrokeCap get strokeCap => _strokeCap;
@override
set strokeCap(ui.StrokeCap value) {
if (_strokeCap == value) {
return;
}
_strokeCap = value;
skiaObject.setStrokeCap(toSkStrokeCap(value));
}
ui.StrokeCap _strokeCap = ui.StrokeCap.butt;
@override
ui.StrokeJoin get strokeJoin => _strokeJoin;
@override
set strokeJoin(ui.StrokeJoin value) {
if (_strokeJoin == value) {
return;
}
_strokeJoin = value;
skiaObject.setStrokeJoin(toSkStrokeJoin(value));
}
ui.StrokeJoin _strokeJoin = ui.StrokeJoin.miter;
@override
bool get isAntiAlias => _isAntiAlias;
@override
set isAntiAlias(bool value) {
if (_isAntiAlias == value) {
return;
}
_isAntiAlias = value;
skiaObject.setAntiAlias(value);
}
bool _isAntiAlias = true;
@override
ui.Color get color => _color;
@override
set color(ui.Color value) {
if (_color == value) {
return;
}
_color = value;
skiaObject.setColorInt(value.value);
}
ui.Color _color = _defaultPaintColor;
// TODO(yjbanov): implement
@override
bool get invertColors => _invertColors;
@override
set invertColors(bool value) {
_invertColors = value;
}
bool _invertColors = false;
@override
ui.Shader? get shader => _shader;
@override
set shader(ui.Shader? value) {
if (_shader == value) {
return;
}
_shader = value as CkShader?;
skiaObject.setShader(_shader?.withQuality(_filterQuality));
}
CkShader? _shader;
@override
ui.MaskFilter? get maskFilter => _maskFilter;
@override
set maskFilter(ui.MaskFilter? value) {
if (value == _maskFilter) {
return;
}
_maskFilter = value;
if (value != null) {
// CanvasKit returns `null` if the sigma is `0` or infinite.
if (!(value.webOnlySigma.isFinite && value.webOnlySigma > 0)) {
// Don't create a [CkMaskFilter].
_ckMaskFilter = null;
} else {
_ckMaskFilter = CkMaskFilter.blur(
value.webOnlyBlurStyle,
value.webOnlySigma,
);
}
} else {
_ckMaskFilter = null;
}
skiaObject.setMaskFilter(_ckMaskFilter?.skiaObject);
}
ui.MaskFilter? _maskFilter;
CkMaskFilter? _ckMaskFilter;
@override
ui.FilterQuality get filterQuality => _filterQuality;
@override
set filterQuality(ui.FilterQuality value) {
if (_filterQuality == value) {
return;
}
_filterQuality = value;
skiaObject.setShader(_shader?.withQuality(value));
}
ui.FilterQuality _filterQuality = ui.FilterQuality.none;
@override
ui.ColorFilter? get colorFilter => _managedColorFilter?.colorFilter;
@override
set colorFilter(ui.ColorFilter? value) {
if (colorFilter == value) {
return;
}
if (value == null) {
_managedColorFilter = null;
} else {
_managedColorFilter = ManagedSkColorFilter(value as CkColorFilter);
}
skiaObject.setColorFilter(_managedColorFilter?.skiaObject);
}
ManagedSkColorFilter? _managedColorFilter;
@override
double get strokeMiterLimit => _strokeMiterLimit;
@override
set strokeMiterLimit(double value) {
if (_strokeMiterLimit == value) {
return;
}
_strokeMiterLimit = value;
skiaObject.setStrokeMiter(value);
}
double _strokeMiterLimit = 0.0;
@override
ui.ImageFilter? get imageFilter => _imageFilter;
@override
set imageFilter(ui.ImageFilter? value) {
if (_imageFilter == value) {
return;
}
_imageFilter = value as CkManagedSkImageFilterConvertible?;
_managedImageFilter = _imageFilter?.imageFilter;
skiaObject.setImageFilter(_managedImageFilter?.skiaObject);
}
CkManagedSkImageFilterConvertible? _imageFilter;
ManagedSkiaObject<SkImageFilter>? _managedImageFilter;
@override
SkPaint createDefault() {
final SkPaint paint = SkPaint();
paint.setAntiAlias(_isAntiAlias);
paint.setColorInt(_color.value);
return paint;
}
@override
SkPaint resurrect() {
final SkPaint paint = SkPaint();
paint.setBlendMode(toSkBlendMode(_blendMode));
paint.setStyle(toSkPaintStyle(_style));
paint.setStrokeWidth(_strokeWidth);
paint.setAntiAlias(_isAntiAlias);
paint.setColorInt(_color.value);
paint.setShader(_shader?.withQuality(_filterQuality));
paint.setMaskFilter(_ckMaskFilter?.skiaObject);
paint.setColorFilter(_managedColorFilter?.skiaObject);
paint.setImageFilter(_managedImageFilter?.skiaObject);
paint.setStrokeCap(toSkStrokeCap(_strokeCap));
paint.setStrokeJoin(toSkStrokeJoin(_strokeJoin));
paint.setStrokeMiter(_strokeMiterLimit);
return paint;
}
@override
void delete() {
rawSkiaObject?.delete();
}
}