From 610916bb519ffe827be9e1bc7170ae1cf38ded19 Mon Sep 17 00:00:00 2001 From: Hixie Date: Tue, 15 Mar 2016 16:17:43 -0700 Subject: [PATCH] Some Paint dartdocs (and style tweaks) --- sky/engine/core/dart/painting.dart | 46 ++++--- sky/engine/core/painting/FilterQuality.dart | 8 +- sky/engine/core/painting/Paint.cpp | 38 +++--- sky/engine/core/painting/Paint.dart | 140 +++++++++++++++----- sky/engine/core/painting/PaintingStyle.dart | 21 ++- sky/engine/core/painting/TransferMode.dart | 22 ++- 6 files changed, 194 insertions(+), 81 deletions(-) diff --git a/sky/engine/core/dart/painting.dart b/sky/engine/core/dart/painting.dart index 4087e459cdc..0430441c8df 100644 --- a/sky/engine/core/dart/painting.dart +++ b/sky/engine/core/dart/painting.dart @@ -73,8 +73,10 @@ class Path extends NativeFieldWrapperClass2 { Path shift(Offset offset) native "Path_shift"; } -/// Blur styles. These mirror SkBlurStyle and must be kept in sync. +/// Styles to use for blurs in [MaskFilter] objects. enum BlurStyle { + // These mirror SkBlurStyle and must be kept in sync. + /// Fuzzy inside and outside. normal, @@ -88,24 +90,29 @@ enum BlurStyle { inner, } -// Convert constructor parameters to the SkBlurMaskFilter::BlurFlags type. -int _makeBlurFlags(bool ignoreTransform, bool highQuality) { - int flags = 0; - if (ignoreTransform) - flags |= 0x01; - if (highQuality) - flags |= 0x02; - return flags; -} - class MaskFilter extends NativeFieldWrapperClass2 { - MaskFilter.blur(BlurStyle style, double sigma, - {bool ignoreTransform: false, bool highQuality: false}) { + MaskFilter.blur(BlurStyle style, double sigma, { + bool ignoreTransform: false, + bool highQuality: false + }) { _constructor(style.index, sigma, _makeBlurFlags(ignoreTransform, highQuality)); } void _constructor(int style, double sigma, int flags) native "MaskFilter_constructor"; + + // Convert constructor parameters to the SkBlurMaskFilter::BlurFlags type. + static int _makeBlurFlags(bool ignoreTransform, bool highQuality) { + int flags = 0; + if (ignoreTransform) + flags |= 0x01; + if (highQuality) + flags |= 0x02; + return flags; + } } +/// A description of a filter to apply when drawing with a particular [Paint]. +/// +/// See [Paint.colorFilter]. class ColorFilter extends NativeFieldWrapperClass2 { ColorFilter.mode(Color color, TransferMode transferMode) { _constructor(color, transferMode); @@ -113,6 +120,8 @@ class ColorFilter extends NativeFieldWrapperClass2 { void _constructor(Color color, TransferMode transferMode) native "ColorFilter_constructor"; } +/// Base class for objects such as [Gradient] and [ImageShader] which +/// correspond to shaders. abstract class Shader extends NativeFieldWrapperClass2 { } /// Defines what happens at the edge of the gradient. @@ -125,12 +134,6 @@ enum TileMode { mirror } -void _validateColorStops(List colors, List colorStops) { - if (colorStops != null && (colors == null || colors.length != colorStops.length)) { - throw new ArgumentError("[colors] and [colorStops] parameters must be equal length."); - } -} - class Gradient extends Shader { /// Creates a Gradient object that is not initialized. /// @@ -169,6 +172,11 @@ class Gradient extends Shader { _initRadial(center, radius, colors, colorStops, tileMode.index); } void _initRadial(Point center, double radius, List colors, List colorStops, int tileMode) native "Gradient_initRadial"; + + static void _validateColorStops(List colors, List colorStops) { + if (colorStops != null && (colors == null || colors.length != colorStops.length)) + throw new ArgumentError("[colors] and [colorStops] parameters must be equal length."); + } } class ImageShader extends Shader { diff --git a/sky/engine/core/painting/FilterQuality.dart b/sky/engine/core/painting/FilterQuality.dart index 65c3268e1ba..97290012fa1 100644 --- a/sky/engine/core/painting/FilterQuality.dart +++ b/sky/engine/core/painting/FilterQuality.dart @@ -4,8 +4,12 @@ part of dart_ui; -/// List of predefined filter quality modes. This list comes from Skia's -/// SkFitlerQuality.h and the values (order) should be kept in sync. +// List of predefined filter quality modes. This list comes from Skia's +// SkFilterQuality.h and the values (order) should be kept in sync. + +/// Quality levels for image filters. +/// +/// See [Paint.filterQuality]. enum FilterQuality { none, low, diff --git a/sky/engine/core/painting/Paint.cpp b/sky/engine/core/painting/Paint.cpp index 067e021da56..f9bb4265250 100644 --- a/sky/engine/core/painting/Paint.cpp +++ b/sky/engine/core/painting/Paint.cpp @@ -22,17 +22,18 @@ namespace blink { namespace { +// Must match Paint._value getter in Paint.dart. enum PaintFields { + kStyle, kStrokeWidth, + kStrokeCap, kIsAntiAlias, kColor, - kColorFilter, - kFilterQuality, - kMaskFilter, - kShader, - kStyle, kTransferMode, - kStrokeCap, + kColorFilter, + kMaskFilter, + kFilterQuality, + kShader, // kNumberOfPaintFields must be last. kNumberOfPaintFields, @@ -73,26 +74,27 @@ Paint DartConverter::FromDart(Dart_Handle dart_paint) { } SkPaint& paint = result.sk_paint; + + if (!Dart_IsNull(values[kStyle])) + paint.setStyle(DartConverter::FromDart(values[kStyle])); if (!Dart_IsNull(values[kStrokeWidth])) paint.setStrokeWidth(DartConverter::FromDart(values[kStrokeWidth])); + if (!Dart_IsNull(values[kStrokeCap])) + paint.setStrokeCap(DartConverter::FromDart(values[kStrokeCap])); if (!Dart_IsNull(values[kIsAntiAlias])) paint.setAntiAlias(DartConverter::FromDart(values[kIsAntiAlias])); if (!Dart_IsNull(values[kColor])) paint.setColor(DartConverter::FromDart(values[kColor])); - if (!Dart_IsNull(values[kColorFilter])) - paint.setColorFilter(DartConverter::FromDart(values[kColorFilter])->filter()); - if (!Dart_IsNull(values[kFilterQuality])) - paint.setFilterQuality(DartConverter::FromDart(values[kFilterQuality])); - if (!Dart_IsNull(values[kMaskFilter])) - paint.setMaskFilter(DartConverter::FromDart(values[kMaskFilter])->filter()); - if (!Dart_IsNull(values[kShader])) - paint.setShader(DartConverter::FromDart(values[kShader])->shader()); - if (!Dart_IsNull(values[kStyle])) - paint.setStyle(DartConverter::FromDart(values[kStyle])); if (!Dart_IsNull(values[kTransferMode])) paint.setXfermodeMode(DartConverter::FromDart(values[kTransferMode])); - if (!Dart_IsNull(values[kStrokeCap])) - paint.setStrokeCap(DartConverter::FromDart(values[kStrokeCap])); + if (!Dart_IsNull(values[kColorFilter])) + paint.setColorFilter(DartConverter::FromDart(values[kColorFilter])->filter()); + if (!Dart_IsNull(values[kMaskFilter])) + paint.setMaskFilter(DartConverter::FromDart(values[kMaskFilter])->filter()); + if (!Dart_IsNull(values[kFilterQuality])) + paint.setFilterQuality(DartConverter::FromDart(values[kFilterQuality])); + if (!Dart_IsNull(values[kShader])) + paint.setShader(DartConverter::FromDart(values[kShader])->shader()); result.is_null = false; return result; diff --git a/sky/engine/core/painting/Paint.dart b/sky/engine/core/painting/Paint.dart index e2ef9959285..f2c2890fc99 100644 --- a/sky/engine/core/painting/Paint.dart +++ b/sky/engine/core/painting/Paint.dart @@ -4,70 +4,142 @@ part of dart_ui; +/// Styles to use for line endings. +/// +/// See [Paint.strokeCap]. enum StrokeCap { - /// Begin/end contours with no extension. + /// Begin and end contours with a flat edge and no extension. butt, - /// Begin/end contours with a semi-circle extension. + /// Begin and end contours with a semi-circle extension. round, - /// Begin/end contours with a half square extension. + /// Begin and end contours with a half square extension. This is + /// similar to extending each contour by half the stroke width (as + /// given by [Paint.strokeWidth]). square, } +/// A description of the style to use when drawing on a [Canvas]. +/// +/// Most APIs on [Canvas] take a [Paint] object to describe the style +/// to use for that operation. class Paint { - double strokeWidth; - bool isAntiAlias = true; - Color color = const Color(0xFF000000); - ColorFilter colorFilter; - FilterQuality filterQuality; - MaskFilter maskFilter; - Shader shader; + /// Whether to paint inside shapes, the edges of shapes, or both. + /// + /// If null, defaults to [PaintingStyle.fill]. PaintingStyle style; - TransferMode transferMode; + + /// How wide to make edges drawn when [style] is set to + /// [PaintingStyle.stroke] or [PaintingStyle.strokeAndFill]. The + /// width is given in logical pixels measured in the direction + /// orthogonal to the direction of the path. + /// + /// The values null and 0.0 correspond to a hairline width. + double strokeWidth; + + /// The kind of finish to place on the end of lines drawn when + /// [style] is set to [PaintingStyle.stroke] or + /// [PaintingStyle.strokeAndFill]. + /// + /// If null, defaults to [StrokeCap.butt], i.e. no caps. StrokeCap strokeCap; + /// Whether to apply anti-aliasing to lines and images drawn on the + /// canvas. + /// + /// Defaults to true. The value null is treated as false. + bool isAntiAlias = true; + + Color color = _kDefaultPaintColor; + static const Color _kDefaultPaintColor = const Color(0xFF000000); + + TransferMode transferMode; + + ColorFilter colorFilter; + + MaskFilter maskFilter; + + FilterQuality filterQuality; + + Shader shader; + // Must match PaintFields enum in Paint.cpp. dynamic get _value { // The most common usage is a Paint with no options besides a color and // anti-aliasing. In this case, save time by just returning the color // as an int. - if (color != null && - strokeWidth == null && + if ((style == null || style == PaintingStyle.fill) && + (strokeWidth == null || strokeWidth == 0.0) && + (strokeCap == null || strokeCap == StrokeCap.butt) && isAntiAlias && - colorFilter == null && - filterQuality == null && - maskFilter == null && - shader == null && - style == null && + color != null && transferMode == null && - strokeCap == null) { + colorFilter == null && + maskFilter == null && + filterQuality == null && + shader == null) { return color.value; } - return [ + return [ + style, strokeWidth, + strokeCap, isAntiAlias, color, - colorFilter, - filterQuality, - maskFilter, - shader, - style, transferMode, - strokeCap, + colorFilter, + maskFilter, + filterQuality, + shader, ]; } String toString() { - String result = 'Paint(color:$color'; + StringBuffer result = new StringBuffer(); + String semicolon = ''; + result.write('Paint('); + if (style == PaintingStyle.stroke || style == PaintingStyle.strokeAndFill) { + result.write('$style'); + if (strokeWidth != null && strokeWidth != 0.0) + result.write(' $strokeWidth'); + else + result.write(' hairline'); + if (strokeCap != null && strokeCap != StrokeCap.butt) + result.write(' $strokeCap'); + semicolon = '; '; + } + if (isAntiAlias != true) { + result.write('${semicolon}antialias off'); + semicolon = '; '; + } + if (color != _kDefaultPaintColor) { + if (color != null) + result.write('$semicolon$color'); + else + result.write('${semicolon}no color'); + semicolon = '; '; + } + if (transferMode != null) { + result.write('$semicolon$transferMode'); + semicolon = '; '; + } + if (colorFilter != null) { + result.write('${semicolon}colorFilter: $colorFilter'); + semicolon = '; '; + } + if (maskFilter != null) { + result.write('${semicolon}maskFilter: $maskFilter'); + semicolon = '; '; + } + if (filterQuality != null) { + result.write('${semicolon}filterQuality: $filterQuality'); + semicolon = '; '; + } if (shader != null) - result += ', shader: $shader'; - if (colorFilter != null) - result += ', colorFilter: $colorFilter'; - if (maskFilter != null) - result += ', maskFilter: $maskFilter'; - result += ')'; - return result; + result.write('${semicolon}shader: $shader'); + result.write(')'); + return result.toString(); } } diff --git a/sky/engine/core/painting/PaintingStyle.dart b/sky/engine/core/painting/PaintingStyle.dart index b12826bb13f..3e24ebd70e1 100644 --- a/sky/engine/core/painting/PaintingStyle.dart +++ b/sky/engine/core/painting/PaintingStyle.dart @@ -4,10 +4,27 @@ part of dart_ui; -/// List of predefined painting styles. This list comes from Skia's -/// SkPaint.h and the values (order) should be kept in sync. +// List of predefined painting styles. This list comes from Skia's +// SkPaint.h and the values (order) should be kept in sync. + +/// Strategies for painting shapes and paths on a canvas. +/// +/// See [Paint.style]. enum PaintingStyle { + /// Apply the [Paint] to the inside of the shape. For example, when + /// applied to the [Paint.drawCircle] call, this results in a disc + /// of the given size being painted. fill, + + /// Apply the [Paint] to the edge of the shape. For example, when + /// applied to the [Paint.drawCircle] call, this results is a hoop + /// of the given size being painted. The line drawn on the edge will + /// be the width given by the [Paint.strokeWidth] property. stroke, + + /// Apply the [Paint] to the inside of the shape and the edge of the + /// shape at the same time. The resulting drawing is similar to what + /// would be achieved by inflating the shape by half the stroke + /// width (as given by [Paint.strokeWidth]), and then using [fill]. strokeAndFill, } diff --git a/sky/engine/core/painting/TransferMode.dart b/sky/engine/core/painting/TransferMode.dart index ae87beaff92..9fd48d43920 100644 --- a/sky/engine/core/painting/TransferMode.dart +++ b/sky/engine/core/painting/TransferMode.dart @@ -4,10 +4,19 @@ part of dart_ui; -/// List of predefined color transfer modes. This list comes from Skia's -/// SkXfermode.h and the values (order) should be kept in sync. -/// See [https://skia.org/user/api/skpaint#SkXfermode] for how these -/// transfer modes behave. +// List of predefined color transfer modes. This list comes from Skia's +// SkXfermode.h and the values (order) should be kept in sync. +// See: https://skia.org/user/api/skpaint#SkXfermode + +/// Algorithms to use when painting on the canvas. +/// +/// When drawing a shape or image onto a canvas, different algorithms +/// can be used to blend the pixels. The image below shows the effects +/// of these modes. +/// +/// [![Open Skia fiddle to view image.](https://fiddle.skia.org/i/871ab434ce53a611e5eb2b662c69d154_raster.png)](https://fiddle.skia.org/c/871ab434ce53a611e5eb2b662c69d154) +/// +/// See [Paint.transferMode]. enum TransferMode { clear, src, @@ -25,7 +34,8 @@ enum TransferMode { modulate, // Following blend modes are defined in the CSS Compositing standard. - screen, /// The last coeff mode. + + screen, // The last coeff mode. overlay, darken, @@ -36,7 +46,7 @@ enum TransferMode { softLight, difference, exclusion, - multiply, /// The last separable mode. + multiply, // The last separable mode. hue, saturation,