Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
212 changes: 179 additions & 33 deletions sky/engine/core/dart/painting.dart

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions sky/engine/core/painting/Color.dart
Original file line number Diff line number Diff line change
Expand Up @@ -99,14 +99,17 @@ class Color {
);
}

@override
bool operator ==(dynamic other) {
if (other is! Color)
return false;
final Color typedOther = other;
return value == typedOther.value;
}

@override
int get hashCode => _value.hashCode;

@override
String toString() => "Color(0x${_value.toRadixString(16).padLeft(8, '0')})";
}
16 changes: 16 additions & 0 deletions sky/engine/core/painting/FilterQuality.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,24 @@ part of dart_ui;
///
/// See [Paint.filterQuality].
enum FilterQuality {
/// Fastest possible filtering, albeit also the lowest quality.
///
/// Typically this implies nearest-neighbour filtering.
none,

/// Better quality than [none], faster than [medium].
///
/// Typically this implies bilinear interpolation.
low,

/// Better quality than [low], faster than [high].
///
/// Typically this implies a combination of bilinear interpolation and
/// pyramidal parametric prefiltering (mipmaps).
medium,

/// Best possible quality filtering, albeit also the slowest.
///
/// Typically this implies bicubic interpolation or better.
high,
}
50 changes: 48 additions & 2 deletions sky/engine/core/painting/Offset.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,13 @@ part of dart_ui;

/// An immutable 2D floating-point offset.
///
/// An Offset represents a vector from an unspecified point
/// An Offset represents a vector from an unspecified [Point].
///
/// Adding an offset to a [Point] returns the [Point] that is indicated by the
/// vector from that first point.
class Offset extends OffsetBase {
/// Creates an offset. The first argument sets [dx], the horizontal component,
/// and the second sets [dy], the vertical component.
const Offset(double dx, double dy) : super(dx, dy);

/// The x component of the offset.
Expand All @@ -20,6 +25,8 @@ class Offset extends OffsetBase {
double get distance => math.sqrt(_dx * _dx + _dy * _dy);

/// The square of the magnitude of the offset.
///
/// This is cheaper than computing the [distance] itself.
double get distanceSquared => _dx * _dx + _dy * _dy;

/// An offset with zero magnitude.
Expand All @@ -34,15 +41,52 @@ class Offset extends OffsetBase {
/// Returns a new offset with translateX added to the x component and translateY added to the y component.
Offset translate(double translateX, double translateY) => new Offset(dx + translateX, dy + translateY);

/// Unary negation operator. Returns an offset with the coordinates negated.
Offset operator -() => new Offset(-dx, -dy);

/// Binary subtraction operator. Returns an offset whose [dx] value is the
/// left-hand-side operand's [dx] minus the right-hand-side operand's [dx] and
/// whose [dy] value is the left-hand-side operand's [dy] minus the
/// right-hand-side operand's [dy].
Offset operator -(Offset other) => new Offset(dx - other.dx, dy - other.dy);

/// Binary addition operator. Returns an offset whose [dx] value is the sum of
/// the [dx] values of the two operands, and whose [dy] value is the sum of
/// the [dy] values of the two operands.
Offset operator +(Offset other) => new Offset(dx + other.dx, dy + other.dy);

/// Multiplication operator. Returns an offset whose coordinates are the
/// coordinates of the left-hand-side operand (an Offset) multiplied by the
/// scalar right-hand-side operand (a double).
Offset operator *(double operand) => new Offset(dx * operand, dy * operand);

/// Division operator. Returns an offset whose coordinates are the
/// coordinates of the left-hand-side operand (an Offset) divided by the
/// scalar right-hand-side operand (a double).
Offset operator /(double operand) => new Offset(dx / operand, dy / operand);

/// Integer (truncating) division operator. Returns an offset whose
/// coordinates are the coordinates of the left-hand-side operand (an Offset)
/// divided by the scalar right-hand-side operand (a double), rounded towards
/// zero.
Offset operator ~/(double operand) => new Offset((dx ~/ operand).toDouble(), (dy ~/ operand).toDouble());

/// Modulo (remainder) operator. Returns an offset whose coordinates are the
/// remainder of dividing the coordinates of the left-hand-side operand (an
/// Offset) by the scalar right-hand-side operand (a double).
Offset operator %(double operand) => new Offset(dx % operand, dy % operand);

/// Returns a rect of the given size that starts at (0, 0) plus this offset.
/// Rectangle constructor operator. Combines an offset and a [Size] to form a
/// [Rect] whose top-left coordinate is the point given by adding this offset,
/// the left-hand-side operand, to the origin, and whose size is the
/// right-hand-side operand.
///
/// ```dart
/// Rect myRect = Offset.zero & const Size(100.0, 100.0);
/// // same as: new Rect.fromLTWH(0.0, 0.0, 100.0, 100.0)
/// ```
///
/// See also: [Point.&]
Rect operator &(Size other) => new Rect.fromLTWH(dx, dy, other.width, other.height);

/// Returns the point at (0, 0) plus this offset.
Expand All @@ -62,7 +106,9 @@ class Offset extends OffsetBase {
}

/// Compares two Offsets for equality.
@override
bool operator ==(dynamic other) => other is Offset && super == other;

@override
String toString() => "Offset(${dx?.toStringAsFixed(1)}, ${dy?.toStringAsFixed(1)})";
}
52 changes: 52 additions & 0 deletions sky/engine/core/painting/OffsetBase.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,70 @@

part of dart_ui;

/// Base class for [Size] and [Offset], which are both ways to describe
/// a distance as a two-dimensional axis-aligned vector.
abstract class OffsetBase {
/// Abstract const constructor. This constructor enables subclasses to provide
/// const constructors so that they can be used in const expressions.
///
/// The first argument sets the horizontal dimension, and the second the
/// vertical dimension.
const OffsetBase(this._dx, this._dy);

final double _dx;
final double _dy;

/// Returns true if either dimension is [double.INFINITY], and false if both
/// are finite (or negative infinity, or NaN).
///
/// This is different than comparing for equality with an instance that has
/// _both_ dimensions set to [double.INFINITY].
bool get isInfinite => _dx >= double.INFINITY || _dy >= double.INFINITY;

/// Less-than operator. Compares an [Offset] or [Size] to another [Offset] or
/// [Size], and returns true if both the horizontal and vertical values of the
/// left-hand-side operand are smaller than the horizontal and vertical values
/// of the right-hand-side operand respectively. Returns false otherwise.
///
/// This is a partial ordering. It is possible for two values to be neither
/// less, nor greater than, nor equal to, another.
bool operator <(OffsetBase other) => _dx < other._dx && _dy < other._dy;
Copy link
Contributor

@krisgiesing krisgiesing May 31, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unrelated to documentation, but I wonder if cross-comparisons between Offset and Size should be disallowed via typing.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was intentionally allowed initially (it's why they share a base class). We haven't used it much, though.


/// Less-than-or-equal-to operator. Compares an [Offset] or [Size] to another
/// [Offset] or [Size], and returns true if both the horizontal and vertical
/// values of the left-hand-side operand are smaller than or equal to the
/// horizontal and vertical values of the right-hand-side operand
/// respectively. Returns false otherwise.
///
/// This is a partial ordering. It is possible for two values to be neither
/// less, nor greater than, nor equal to, another.
bool operator <=(OffsetBase other) => _dx <= other._dx && _dy <= other._dy;

/// Greater-than operator. Compares an [Offset] or [Size] to another [Offset]
/// or [Size], and returns true if both the horizontal and vertical values of
/// the left-hand-side operand are bigger than the horizontal and vertical
/// values of the right-hand-side operand respectively. Returns false
/// otherwise.
///
/// This is a partial ordering. It is possible for two values to be neither
/// less, nor greater than, nor equal to, another.
bool operator >(OffsetBase other) => _dx > other._dx && _dy > other._dy;

/// Less-than-or-equal-to operator. Compares an [Offset] or [Size] to another
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Greater-than-or-equal-to

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

/// [Offset] or [Size], and returns true if both the horizontal and vertical
/// values of the left-hand-side operand are bigger than or equal to the
/// horizontal and vertical values of the right-hand-side operand
/// respectively. Returns false otherwise.
///
/// This is a partial ordering. It is possible for two values to be neither
/// less, nor greater than, nor equal to, another.
bool operator >=(OffsetBase other) => _dx > other._dx && _dy >= other._dy;

/// Equality operator. Compares an [Offset] or [Size] to another [Offset] or
/// [Size], and returns true if the horizontal and vertical values of the
/// left-hand-side operand are equal to the horizontal and vertical values of
/// the right-hand-side operand respectively. Returns false otherwise.
@override
bool operator ==(dynamic other) {
if (other is! OffsetBase)
return false;
Expand All @@ -25,5 +76,6 @@ abstract class OffsetBase {
_dy == typedOther._dy;
}

@override
int get hashCode => hashValues(_dx, _dy);
}
71 changes: 62 additions & 9 deletions sky/engine/core/painting/Paint.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ class Paint {
///
/// If null, defaults to [PaintingStyle.fill].
PaintingStyle style;
static const PaintingStyle _kDefaultStyle = PaintingStyle.fill;

/// How wide to make edges drawn when [style] is set to
/// [PaintingStyle.stroke] or [PaintingStyle.strokeAndFill]. The
Expand All @@ -37,44 +38,95 @@ class Paint {
///
/// The values null and 0.0 correspond to a hairline width.
double strokeWidth;
static const double _kDefaultStrokeWidth = 0.0;

/// 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;
static const StrokeCap _kDefaultStrokeCap = StrokeCap.butt;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMHO, we should skip these defaults. The null values mean we don't have to call into skia in C++, which means we get the default in Skia. That's going to be slightly more efficient.


/// 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;

/// The color to use when stroking or filling a shape.
///
/// Defaults to black.
///
/// See also:
///
/// * [style], which controls whether to stroke or fill (or both).
/// * [colorFilter], which overrides [color].
/// * [shader], which overrides [color] with more elaborate effects.
///
/// This color is not used when compositing. To colorize a layer, use
/// [colorFilter].
Color color = _kDefaultPaintColor;
static const Color _kDefaultPaintColor = const Color(0xFF000000);

TransferMode transferMode;

ColorFilter colorFilter;

/// A mask filter (for example, a blur) to apply to a shape after it has been
/// drawn but before it has been composited into the image.
///
/// See [MaskFilter] for details.
MaskFilter maskFilter;

/// Controls the performance vs quality trade-off to use when applying
/// filters, such as [maskFilter], or when drawing images, as with
/// [Canvas.drawImageRect] or [Canvas.drawImageNine].
// TODO(ianh): verify that the image drawing methods actually respect this
FilterQuality filterQuality;

/// The shader to use when stroking or filling a shape.
///
/// When this is null, the [color] is used instead.
///
/// See also:
///
/// * [Gradient], a shader that paints a color gradient.
/// * [ImageShader], a shader that tiles an [Image].
/// * [colorFilter], which overrides [shader].
/// * [color], which is used if [shader] and [colorFilter] are null.
Shader shader;

/// A color filter to apply when a shape is drawn or when a layer is
/// composited.
///
/// See [ColorFilter] for details.
///
/// When a shape is being drawn, [colorFilter] overrides [color] and [shader].
ColorFilter colorFilter;

/// A transfer mode to apply when a shape is drawn or a layer is composited.
///
/// The source colors are from the shape being drawn (e.g. from
/// [Canvas.drawPath]) or layer being composited (the graphics that were drawn
/// between the [Canvas.saveLayer] and [Canvas.restore] calls), after applying
/// the [colorFilter], if any.
///
/// The destination colors are from the background onto which the shape or
/// layer is being composited.
///
/// If null, defaults to [TransferMode.srcOver].
TransferMode transferMode;
static const TransferMode _kDefaultTransferMode = TransferMode.srcOver;


// 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 ((style == null || style == PaintingStyle.fill) &&
(strokeWidth == null || strokeWidth == 0.0) &&
(strokeCap == null || strokeCap == StrokeCap.butt) &&
if ((style == null || style == _kDefaultStyle) &&
(strokeWidth == null || strokeWidth == _kDefaultStrokeWidth) &&
(strokeCap == null || strokeCap == _kDefaultStrokeCap) &&
isAntiAlias &&
color != null &&
transferMode == null &&
(transferMode == null || transferMode == _kDefaultTransferMode) &&
colorFilter == null &&
maskFilter == null &&
filterQuality == null &&
Expand All @@ -96,6 +148,7 @@ class Paint {
];
}

@override
String toString() {
StringBuffer result = new StringBuffer();
String semicolon = '';
Expand All @@ -106,7 +159,7 @@ class Paint {
result.write(' $strokeWidth');
else
result.write(' hairline');
if (strokeCap != null && strokeCap != StrokeCap.butt)
if (strokeCap != null && strokeCap != _kDefaultStrokeCap)
result.write(' $strokeCap');
semicolon = '; ';
}
Expand Down
Loading