未验证 提交 3b6dedb8 编写于 作者: L liyuqian 提交者: GitHub

Add anti-alias switch to canvas clip calls (#5670)

This is a reland of #5638. We removed the restoreToCount, made doAntiAlias named, and updated the comments.
上级 d9a831c5
...@@ -1577,16 +1577,16 @@ enum PathFillType { ...@@ -1577,16 +1577,16 @@ enum PathFillType {
} }
/// Strategies for combining paths. /// Strategies for combining paths.
/// ///
/// See also: /// See also:
/// ///
/// * [Path.combine], which uses this enum to decide how to combine two paths. /// * [Path.combine], which uses this enum to decide how to combine two paths.
// Must be kept in sync with SkPathOp // Must be kept in sync with SkPathOp
enum PathOperation { enum PathOperation {
/// Subtract the second path from the first path. /// Subtract the second path from the first path.
/// ///
/// For example, if the two paths are overlapping circles of equal diameter /// For example, if the two paths are overlapping circles of equal diameter
/// but differing centers, the result would be a crescent portion of the /// but differing centers, the result would be a crescent portion of the
/// first circle that was not overlapped by the second circle. /// first circle that was not overlapped by the second circle.
/// ///
/// See also: /// See also:
...@@ -1596,33 +1596,33 @@ enum PathOperation { ...@@ -1596,33 +1596,33 @@ enum PathOperation {
difference, difference,
/// Create a new path that is the intersection of the two paths, leaving the /// Create a new path that is the intersection of the two paths, leaving the
/// overlapping pieces of the path. /// overlapping pieces of the path.
/// ///
/// For example, if the two paths are overlapping circles of equal diameter /// For example, if the two paths are overlapping circles of equal diameter
/// but differing centers, the result would be only the overlapping portion /// but differing centers, the result would be only the overlapping portion
/// of the two circles. /// of the two circles.
/// ///
/// See also: /// See also:
/// * [xor], which is the inverse of this operation /// * [xor], which is the inverse of this operation
intersect, intersect,
/// Create a new path that is the union (inclusive-or) of the two paths. /// Create a new path that is the union (inclusive-or) of the two paths.
/// ///
/// For example, if the two paths are overlapping circles of equal diameter /// For example, if the two paths are overlapping circles of equal diameter
/// but differing centers, the result would be a figure-eight like shape /// but differing centers, the result would be a figure-eight like shape
/// matching the outer boundaries of both circles. /// matching the outer boundaries of both circles.
union, union,
/// Create a new path that is the exclusive-or of the two paths, leaving /// Create a new path that is the exclusive-or of the two paths, leaving
/// everything but the overlapping pieces of the path. /// everything but the overlapping pieces of the path.
/// ///
/// For example, if the two paths are overlapping circles of equal diameter /// For example, if the two paths are overlapping circles of equal diameter
/// but differing centers, the figure-eight like shape less the overlapping parts /// but differing centers, the figure-eight like shape less the overlapping parts
/// ///
/// See also: /// See also:
/// * [intersect], which is the inverse of this operation /// * [intersect], which is the inverse of this operation
xor, xor,
/// Subtract the first path from the second path. /// Subtract the first path from the second path.
/// ///
/// For example, if the two paths are overlapping circles of equal diameter /// For example, if the two paths are overlapping circles of equal diameter
/// but differing centers, the result would be a crescent portion of the /// but differing centers, the result would be a crescent portion of the
/// second circle that was not overlapped by the first circle. /// second circle that was not overlapped by the first circle.
/// ///
/// See also: /// See also:
...@@ -1655,8 +1655,8 @@ class Path extends NativeFieldWrapperClass2 { ...@@ -1655,8 +1655,8 @@ class Path extends NativeFieldWrapperClass2 {
void _constructor() native 'Path_constructor'; void _constructor() native 'Path_constructor';
/// Creates a copy of another [Path]. /// Creates a copy of another [Path].
/// ///
/// This copy is fast and does not require additional memory unless either /// This copy is fast and does not require additional memory unless either
/// the `source` path or the path returned by this constructor are modified. /// the `source` path or the path returned by this constructor are modified.
factory Path.from(Path source) { factory Path.from(Path source) {
return source._clone(); return source._clone();
...@@ -1862,7 +1862,7 @@ class Path extends NativeFieldWrapperClass2 { ...@@ -1862,7 +1862,7 @@ class Path extends NativeFieldWrapperClass2 {
/// Adds a new subpath that consists of the given `path` offset by the given /// Adds a new subpath that consists of the given `path` offset by the given
/// `offset`. /// `offset`.
/// ///
/// If `matrix4` is specified, the path will be transformed by this matrix /// If `matrix4` is specified, the path will be transformed by this matrix
/// after the matrix is translated by the given offset. The matrix is a 4x4 /// after the matrix is translated by the given offset. The matrix is a 4x4
/// matrix stored in column major order. /// matrix stored in column major order.
...@@ -1878,10 +1878,10 @@ class Path extends NativeFieldWrapperClass2 { ...@@ -1878,10 +1878,10 @@ class Path extends NativeFieldWrapperClass2 {
} }
void _addPath(Path path, double dx, double dy) native 'Path_addPath'; void _addPath(Path path, double dx, double dy) native 'Path_addPath';
void _addPathWithMatrix(Path path, double dx, double dy, Float64List matrix) native 'Path_addPathWithMatrix'; void _addPathWithMatrix(Path path, double dx, double dy, Float64List matrix) native 'Path_addPathWithMatrix';
/// Adds the given path to this path by extending the current segment of this /// Adds the given path to this path by extending the current segment of this
/// path with the the first segment of the given path. /// path with the the first segment of the given path.
/// ///
/// If `matrix4` is specified, the path will be transformed by this matrix /// If `matrix4` is specified, the path will be transformed by this matrix
/// after the matrix is translated by the given `offset`. The matrix is a 4x4 /// after the matrix is translated by the given `offset`. The matrix is a 4x4
/// matrix stored in column major order. /// matrix stored in column major order.
...@@ -1937,16 +1937,16 @@ class Path extends NativeFieldWrapperClass2 { ...@@ -1937,16 +1937,16 @@ class Path extends NativeFieldWrapperClass2 {
Path _transform(Float64List matrix4) native 'Path_transform'; Path _transform(Float64List matrix4) native 'Path_transform';
/// Computes the bounding rectangle for this path. /// Computes the bounding rectangle for this path.
/// ///
/// A path containing only axis-aligned points on the same straight line will /// A path containing only axis-aligned points on the same straight line will
/// have no area, and therefore `Rect.isEmpty` will return true for such a /// have no area, and therefore `Rect.isEmpty` will return true for such a
/// path. Consider checking `rect.width + rect.height > 0.0` instead, or /// path. Consider checking `rect.width + rect.height > 0.0` instead, or
/// using the [computeMetrics] API to check the path length. /// using the [computeMetrics] API to check the path length.
/// ///
/// For many more elaborate paths, the bounds may be inaccurate. For example, /// For many more elaborate paths, the bounds may be inaccurate. For example,
/// when a path contains a circle, the points used to compute the bounds are /// when a path contains a circle, the points used to compute the bounds are
/// the circle's implied control points, which form a square around the circle; /// the circle's implied control points, which form a square around the circle;
/// if the circle has a transformation applied using [transform] then that /// if the circle has a transformation applied using [transform] then that
/// square is rotated, and the (axis-aligned, non-rotated) bounding box /// square is rotated, and the (axis-aligned, non-rotated) bounding box
/// therefore ends up grossly overestimating the actual area covered by the /// therefore ends up grossly overestimating the actual area covered by the
/// circle. /// circle.
...@@ -1957,9 +1957,9 @@ class Path extends NativeFieldWrapperClass2 { ...@@ -1957,9 +1957,9 @@ class Path extends NativeFieldWrapperClass2 {
} }
Float32List _getBounds() native 'Path_getBounds'; Float32List _getBounds() native 'Path_getBounds';
/// Combines the two paths according to the manner specified by the given /// Combines the two paths according to the manner specified by the given
/// `operation`. /// `operation`.
/// ///
/// The resulting path will be constructed from non-overlapping contours. The /// The resulting path will be constructed from non-overlapping contours. The
/// curve order is reduced where possible so that cubics may be turned into /// curve order is reduced where possible so that cubics may be turned into
/// quadratics, and quadratics maybe turned into lines. /// quadratics, and quadratics maybe turned into lines.
...@@ -1969,13 +1969,13 @@ class Path extends NativeFieldWrapperClass2 { ...@@ -1969,13 +1969,13 @@ class Path extends NativeFieldWrapperClass2 {
final Path path = new Path(); final Path path = new Path();
if (path._op(path1, path2, operation.index)) { if (path._op(path1, path2, operation.index)) {
return path; return path;
} }
throw new StateError('Path.combine() failed. This may be due an invalid path; in particular, check for NaN values.'); throw new StateError('Path.combine() failed. This may be due an invalid path; in particular, check for NaN values.');
} }
bool _op(Path path1, Path path2, int operation) native 'Path_op'; bool _op(Path path1, Path path2, int operation) native 'Path_op';
/// Creates a [PathMetrics] object for this path. /// Creates a [PathMetrics] object for this path.
/// ///
/// If `forceClosed` is set to true, the contours of the path will be measured /// If `forceClosed` is set to true, the contours of the path will be measured
/// as if they had been closed, even if they were not explicitly closed. /// as if they had been closed, even if they were not explicitly closed.
PathMetrics computeMetrics({bool forceClosed: false}) { PathMetrics computeMetrics({bool forceClosed: false}) {
...@@ -1984,19 +1984,19 @@ class Path extends NativeFieldWrapperClass2 { ...@@ -1984,19 +1984,19 @@ class Path extends NativeFieldWrapperClass2 {
} }
/// The geometric description of a tangent: the angle at a point. /// The geometric description of a tangent: the angle at a point.
/// ///
/// See also: /// See also:
/// * [PathMetric.getTangentForOffset], which returns the tangent of an offset along a path. /// * [PathMetric.getTangentForOffset], which returns the tangent of an offset along a path.
class Tangent { class Tangent {
/// Creates a [Tangent] with the given values. /// Creates a [Tangent] with the given values.
/// ///
/// The arguments must not be null. /// The arguments must not be null.
const Tangent(this.position, this.vector) const Tangent(this.position, this.vector)
: assert(position != null), : assert(position != null),
assert(vector != null); assert(vector != null);
/// Creates a [Tangent] based on the angle rather than the vector. /// Creates a [Tangent] based on the angle rather than the vector.
/// ///
/// The [vector] is computed to be the unit vector at the given angle, interpreted /// The [vector] is computed to be the unit vector at the given angle, interpreted
/// as clockwise radians from the x axis. /// as clockwise radians from the x axis.
factory Tangent.fromAngle(Offset position, double angle) { factory Tangent.fromAngle(Offset position, double angle) {
...@@ -2004,43 +2004,43 @@ class Tangent { ...@@ -2004,43 +2004,43 @@ class Tangent {
} }
/// Position of the tangent. /// Position of the tangent.
/// ///
/// When used with [PathMetric.getTangentForOffset], this represents the precise /// When used with [PathMetric.getTangentForOffset], this represents the precise
/// position that the given offset along the path corresponds to. /// position that the given offset along the path corresponds to.
final Offset position; final Offset position;
/// The vector of the curve at [position]. /// The vector of the curve at [position].
/// ///
/// When used with [PathMetric.getTangentForOffset], this is the vector of the /// When used with [PathMetric.getTangentForOffset], this is the vector of the
/// curve that is at the given offset along the path (i.e. the direction of the /// curve that is at the given offset along the path (i.e. the direction of the
/// curve at [position]). /// curve at [position]).
final Offset vector; final Offset vector;
/// The direction of the curve at [position]. /// The direction of the curve at [position].
/// ///
/// When used with [PathMetric.getTangentForOffset], this is the angle of the /// When used with [PathMetric.getTangentForOffset], this is the angle of the
/// curve that is the given offset along the path (i.e. the direction of the /// curve that is the given offset along the path (i.e. the direction of the
/// curve at [position]). /// curve at [position]).
/// ///
/// This value is in radians, with 0.0 meaning pointing along the x axis in /// This value is in radians, with 0.0 meaning pointing along the x axis in
/// the positive x-axis direction, positive numbers pointing downward toward /// the positive x-axis direction, positive numbers pointing downward toward
/// the negative y-axis, i.e. in a clockwise direction, and negative numbers /// the negative y-axis, i.e. in a clockwise direction, and negative numbers
/// pointing upward toward the positive y-axis, i.e. in a counter-clockwise /// pointing upward toward the positive y-axis, i.e. in a counter-clockwise
/// direction. /// direction.
// flip the sign to be consistent with [Path.arcTo]'s `sweepAngle` // flip the sign to be consistent with [Path.arcTo]'s `sweepAngle`
double get angle => -math.atan2(vector.dy, vector.dx); double get angle => -math.atan2(vector.dy, vector.dx);
} }
/// An iterable collection of [PathMetric] objects describing a [Path]. /// An iterable collection of [PathMetric] objects describing a [Path].
/// ///
/// A [PathMetrics] object is created by using the [Path.computeMetrics] method, /// A [PathMetrics] object is created by using the [Path.computeMetrics] method,
/// and represents the path as it stood at the time of the call. Subsequent /// and represents the path as it stood at the time of the call. Subsequent
/// modifications of the path do not affect the [PathMetrics] object. /// modifications of the path do not affect the [PathMetrics] object.
/// ///
/// Each path metric corresponds to a segment, or contour, of a path. /// Each path metric corresponds to a segment, or contour, of a path.
/// ///
/// For example, a path consisting of a [Path.lineTo], a [Path.moveTo], and /// For example, a path consisting of a [Path.lineTo], a [Path.moveTo], and
/// another [Path.lineTo] will contain two contours and thus be represented by /// another [Path.lineTo] will contain two contours and thus be represented by
/// two [PathMetric] objects. /// two [PathMetric] objects.
/// ///
/// When iterating across a [PathMetrics]' contours, the [PathMetric] objects are only /// When iterating across a [PathMetrics]' contours, the [PathMetric] objects are only
...@@ -2048,7 +2048,7 @@ class Tangent { ...@@ -2048,7 +2048,7 @@ class Tangent {
class PathMetrics extends collection.IterableBase<PathMetric> { class PathMetrics extends collection.IterableBase<PathMetric> {
PathMetrics._(Path path, bool forceClosed) : PathMetrics._(Path path, bool forceClosed) :
_iterator = new PathMetricIterator._(new PathMetric._(path, forceClosed)); _iterator = new PathMetricIterator._(new PathMetric._(path, forceClosed));
final Iterator<PathMetric> _iterator; final Iterator<PathMetric> _iterator;
@override @override
...@@ -2068,25 +2068,25 @@ class PathMetricIterator implements Iterator<PathMetric> { ...@@ -2068,25 +2068,25 @@ class PathMetricIterator implements Iterator<PathMetric> {
@override @override
bool moveNext() { bool moveNext() {
// PathMetric isn't a normal iterable - it's already initialized to its // PathMetric isn't a normal iterable - it's already initialized to its
// first Path. Should only call _moveNext when done with the first one. // first Path. Should only call _moveNext when done with the first one.
if (_firstTime == true) { if (_firstTime == true) {
_firstTime = false; _firstTime = false;
return true; return true;
} else if (_pathMetric?._moveNext() == true) { } else if (_pathMetric?._moveNext() == true) {
return true; return true;
} }
_pathMetric = null; _pathMetric = null;
return false; return false;
} }
} }
/// Utilities for measuring a [Path] and extracting subpaths. /// Utilities for measuring a [Path] and extracting subpaths.
/// ///
/// Iterate over the object returned by [Path.computeMetrics] to obtain /// Iterate over the object returned by [Path.computeMetrics] to obtain
/// [PathMetric] objects. /// [PathMetric] objects.
/// ///
/// Once created, metrics will only be valid while the iterator is at the given /// Once created, metrics will only be valid while the iterator is at the given
/// contour. When the next contour's [PathMetric] is obtained, this object /// contour. When the next contour's [PathMetric] is obtained, this object
/// becomes invalid. /// becomes invalid.
class PathMetric extends NativeFieldWrapperClass2 { class PathMetric extends NativeFieldWrapperClass2 {
/// Create a new empty [Path] object. /// Create a new empty [Path] object.
...@@ -2098,13 +2098,13 @@ class PathMetric extends NativeFieldWrapperClass2 { ...@@ -2098,13 +2098,13 @@ class PathMetric extends NativeFieldWrapperClass2 {
/// Computes the position of hte current contour at the given offset, and the /// Computes the position of hte current contour at the given offset, and the
/// angle of the path at that point. /// angle of the path at that point.
/// ///
/// For example, calling this method with a distance of 1.41 for a line from /// For example, calling this method with a distance of 1.41 for a line from
/// 0.0,0.0 to 2.0,2.0 would give a point 1.0,1.0 and the angle 45 degrees /// 0.0,0.0 to 2.0,2.0 would give a point 1.0,1.0 and the angle 45 degrees
/// (but in radians). /// (but in radians).
/// ///
/// Returns null if the contour has zero [length]. /// Returns null if the contour has zero [length].
/// ///
/// The distance is clamped to the [length] of the current contour. /// The distance is clamped to the [length] of the current contour.
Tangent getTangentForOffset(double distance) { Tangent getTangentForOffset(double distance) {
final Float32List posTan = _getPosTan(distance); final Float32List posTan = _getPosTan(distance);
...@@ -2113,24 +2113,24 @@ class PathMetric extends NativeFieldWrapperClass2 { ...@@ -2113,24 +2113,24 @@ class PathMetric extends NativeFieldWrapperClass2 {
return null; return null;
} else { } else {
return new Tangent( return new Tangent(
new Offset(posTan[1], posTan[2]), new Offset(posTan[1], posTan[2]),
new Offset(posTan[3], posTan[4]) new Offset(posTan[3], posTan[4])
); );
} }
} }
Float32List _getPosTan(double distance) native 'PathMeasure_getPosTan'; Float32List _getPosTan(double distance) native 'PathMeasure_getPosTan';
/// Given a start and stop distance, return the intervening segment(s). /// Given a start and stop distance, return the intervening segment(s).
/// ///
/// `start` and `end` are pinned to legal values (0..[length]) /// `start` and `end` are pinned to legal values (0..[length])
/// Returns null if the segment is 0 length or `start` > `stop`. /// Returns null if the segment is 0 length or `start` > `stop`.
/// Begin the segment with a moveTo if `startWithMoveTo` is true. /// Begin the segment with a moveTo if `startWithMoveTo` is true.
Path extractPath(double start, double end, {bool startWithMoveTo: true}) native 'PathMeasure_getSegment'; Path extractPath(double start, double end, {bool startWithMoveTo: true}) native 'PathMeasure_getSegment';
/// Whether the contour is closed. /// Whether the contour is closed.
/// ///
/// Returns true if the contour ends with a call to [Path.close] (which may /// Returns true if the contour ends with a call to [Path.close] (which may
/// have been implied when using [Path.addRect]) or if `forceClosed` was /// have been implied when using [Path.addRect]) or if `forceClosed` was
/// specified as true in the call to [Path.computeMetrics]. Returns false /// specified as true in the call to [Path.computeMetrics]. Returns false
/// otherwise. /// otherwise.
bool get isClosed native 'PathMeasure_isClosed'; bool get isClosed native 'PathMeasure_isClosed';
...@@ -2139,10 +2139,10 @@ class PathMetric extends NativeFieldWrapperClass2 { ...@@ -2139,10 +2139,10 @@ class PathMetric extends NativeFieldWrapperClass2 {
// //
// A path can have a next contour if [Path.moveTo] was called after drawing began. // A path can have a next contour if [Path.moveTo] was called after drawing began.
// Return true if one exists, or false. // Return true if one exists, or false.
// //
// This is not exactly congruent with a regular [Iterator.moveNext]. // This is not exactly congruent with a regular [Iterator.moveNext].
// Typically, [Iterator.moveNext] should be called before accessing the // Typically, [Iterator.moveNext] should be called before accessing the
// [Iterator.current]. In this case, the [PathMetric] is valid before // [Iterator.current]. In this case, the [PathMetric] is valid before
// calling `_moveNext` - `_moveNext` should be called after the first // calling `_moveNext` - `_moveNext` should be called after the first
// iteration is done instead of before. // iteration is done instead of before.
bool _moveNext() native 'PathMeasure_nextContour'; bool _moveNext() native 'PathMeasure_nextContour';
...@@ -2455,10 +2455,10 @@ class Gradient extends Shader { ...@@ -2455,10 +2455,10 @@ class Gradient extends Shader {
/// If `matrix4` is provided, the gradient fill will be transformed by the /// If `matrix4` is provided, the gradient fill will be transformed by the
/// specified 4x4 matrix relative to the local coordinate system. `matrix4` must /// specified 4x4 matrix relative to the local coordinate system. `matrix4` must
/// be a column-major matrix packed into a list of 16 values. /// be a column-major matrix packed into a list of 16 values.
/// ///
/// If `focal` is provided and not equal to `center` and `focalRadius` is /// If `focal` is provided and not equal to `center` and `focalRadius` is
/// provided and not equal to 0.0, the generated shader will be a two point /// provided and not equal to 0.0, the generated shader will be a two point
/// conical radial gradient, with `focal` being the center of the focal /// conical radial gradient, with `focal` being the center of the focal
/// circle and `focalRadius` being the radius of that circle. If `focal` is /// circle and `focalRadius` being the radius of that circle. If `focal` is
/// provided and not equal to `center`, at least one of the two offsets must /// provided and not equal to `center`, at least one of the two offsets must
/// not be equal to [Offset.zero]. /// not be equal to [Offset.zero].
...@@ -2518,7 +2518,7 @@ class Gradient extends Shader { ...@@ -2518,7 +2518,7 @@ class Gradient extends Shader {
/// or if `colors` or `colorStops` contain null values, this constructor will /// or if `colors` or `colorStops` contain null values, this constructor will
/// throw a [NoSuchMethodError]. /// throw a [NoSuchMethodError].
/// ///
/// If `matrix4` is provided, the gradient fill will be transformed by the /// If `matrix4` is provided, the gradient fill will be transformed by the
/// specified 4x4 matrix relative to the local coordinate system. `matrix4` must /// specified 4x4 matrix relative to the local coordinate system. `matrix4` must
/// be a column-major matrix packed into a list of 16 values. /// be a column-major matrix packed into a list of 16 values.
Gradient.sweep( Gradient.sweep(
...@@ -2930,50 +2930,57 @@ class Canvas extends NativeFieldWrapperClass2 { ...@@ -2930,50 +2930,57 @@ class Canvas extends NativeFieldWrapperClass2 {
/// Reduces the clip region to the intersection of the current clip and the /// Reduces the clip region to the intersection of the current clip and the
/// given rectangle. /// given rectangle.
/// ///
/// If the clip is not axis-aligned with the display device, and /// If [doAntiAlias] is true, then the clip will be anti-aliased.
/// [Paint.isAntiAlias] is true, then the clip will be anti-aliased. If ///
/// multiple draw commands intersect with the clip boundary, this can result /// If multiple draw commands intersect with the clip boundary, this can result
/// in incorrect blending at the clip boundary. See [saveLayer] for a /// in incorrect blending at the clip boundary. See [saveLayer] for a
/// discussion of how to address that. /// discussion of how to address that.
/// ///
/// Use [ClipOp.difference] to subtract the provided rectangle from the /// Use [ClipOp.difference] to subtract the provided rectangle from the
/// current clip. /// current clip.
void clipRect(Rect rect, { ClipOp clipOp: ClipOp.intersect }) { void clipRect(Rect rect, { ClipOp clipOp: ClipOp.intersect, bool doAntiAlias = true }) {
assert(_rectIsValid(rect)); assert(_rectIsValid(rect));
assert(clipOp != null); assert(clipOp != null);
_clipRect(rect.left, rect.top, rect.right, rect.bottom, clipOp.index); assert(doAntiAlias != null);
_clipRect(rect.left, rect.top, rect.right, rect.bottom, clipOp.index, doAntiAlias);
} }
void _clipRect(double left, void _clipRect(double left,
double top, double top,
double right, double right,
double bottom, double bottom,
int clipOp) native 'Canvas_clipRect'; int clipOp,
bool doAntiAlias) native 'Canvas_clipRect';
/// Reduces the clip region to the intersection of the current clip and the /// Reduces the clip region to the intersection of the current clip and the
/// given rounded rectangle. /// given rounded rectangle.
/// ///
/// If [Paint.isAntiAlias] is true, then the clip will be anti-aliased. If /// If [doAntiAlias] is true, then the clip will be anti-aliased.
/// multiple draw commands intersect with the clip boundary, this can result ///
/// If multiple draw commands intersect with the clip boundary, this can result
/// in incorrect blending at the clip boundary. See [saveLayer] for a /// in incorrect blending at the clip boundary. See [saveLayer] for a
/// discussion of how to address that and some examples of using [clipRRect]. /// discussion of how to address that and some examples of using [clipRRect].
void clipRRect(RRect rrect) { void clipRRect(RRect rrect, {bool doAntiAlias = true}) {
assert(_rrectIsValid(rrect)); assert(_rrectIsValid(rrect));
_clipRRect(rrect._value); assert(doAntiAlias != null);
_clipRRect(rrect._value, doAntiAlias);
} }
void _clipRRect(Float32List rrect) native 'Canvas_clipRRect'; void _clipRRect(Float32List rrect, bool doAntiAlias) native 'Canvas_clipRRect';
/// Reduces the clip region to the intersection of the current clip and the /// Reduces the clip region to the intersection of the current clip and the
/// given [Path]. /// given [Path].
/// ///
/// If [Paint.isAntiAlias] is true, then the clip will be anti-aliased. If /// If [doAntiAlias] is true, then the clip will be anti-aliased.
///
/// If multiple draw commands intersect with the clip boundary, this can result
/// multiple draw commands intersect with the clip boundary, this can result /// multiple draw commands intersect with the clip boundary, this can result
/// in incorrect blending at the clip boundary. See [saveLayer] for a /// in incorrect blending at the clip boundary. See [saveLayer] for a
/// discussion of how to address that. /// discussion of how to address that.
void clipPath(Path path) { void clipPath(Path path, {bool doAntiAlias = true}) {
assert(path != null); // path is checked on the engine side assert(path != null); // path is checked on the engine side
_clipPath(path); assert(doAntiAlias != null);
_clipPath(path, doAntiAlias);
} }
void _clipPath(Path path) native 'Canvas_clipPath'; void _clipPath(Path path, bool doAntiAlias) native 'Canvas_clipPath';
/// Paints the given [Color] onto the canvas, applying the given /// Paints the given [Color] onto the canvas, applying the given
/// [BlendMode], with the given color being the source and the background /// [BlendMode], with the given color being the source and the background
...@@ -3453,7 +3460,7 @@ class Picture extends NativeFieldWrapperClass2 { ...@@ -3453,7 +3460,7 @@ class Picture extends NativeFieldWrapperClass2 {
void dispose() native 'Picture_dispose'; void dispose() native 'Picture_dispose';
/// Returns the approximate number of bytes allocated for this object. /// Returns the approximate number of bytes allocated for this object.
/// ///
/// The actual size of this picture may be larger, particularly if it contains /// The actual size of this picture may be larger, particularly if it contains
/// references to image or other large objects. /// references to image or other large objects.
int get approximateBytesUsed native 'Picture_GetAllocationSize'; int get approximateBytesUsed native 'Picture_GetAllocationSize';
......
...@@ -160,25 +160,26 @@ void Canvas::clipRect(double left, ...@@ -160,25 +160,26 @@ void Canvas::clipRect(double left,
double top, double top,
double right, double right,
double bottom, double bottom,
SkClipOp clipOp) { SkClipOp clipOp,
bool doAntiAlias) {
if (!canvas_) if (!canvas_)
return; return;
canvas_->clipRect(SkRect::MakeLTRB(left, top, right, bottom), clipOp, true); canvas_->clipRect(SkRect::MakeLTRB(left, top, right, bottom), clipOp, doAntiAlias);
} }
void Canvas::clipRRect(const RRect& rrect) { void Canvas::clipRRect(const RRect& rrect, bool doAntiAlias) {
if (!canvas_) if (!canvas_)
return; return;
canvas_->clipRRect(rrect.sk_rrect, true); canvas_->clipRRect(rrect.sk_rrect, doAntiAlias);
} }
void Canvas::clipPath(const CanvasPath* path) { void Canvas::clipPath(const CanvasPath* path, bool doAntiAlias) {
if (!canvas_) if (!canvas_)
return; return;
if (!path) if (!path)
Dart_ThrowException( Dart_ThrowException(
ToDart("Canvas.clipPath called with non-genuine Path.")); ToDart("Canvas.clipPath called with non-genuine Path."));
canvas_->clipPath(path->path(), true); canvas_->clipPath(path->path(), doAntiAlias);
} }
void Canvas::drawColor(SkColor color, SkBlendMode blend_mode) { void Canvas::drawColor(SkColor color, SkBlendMode blend_mode) {
......
...@@ -60,9 +60,10 @@ class Canvas : public fxl::RefCountedThreadSafe<Canvas>, ...@@ -60,9 +60,10 @@ class Canvas : public fxl::RefCountedThreadSafe<Canvas>,
double top, double top,
double right, double right,
double bottom, double bottom,
SkClipOp clipOp); SkClipOp clipOp,
void clipRRect(const RRect& rrect); bool doAntiAlias = true);
void clipPath(const CanvasPath* path); void clipRRect(const RRect& rrect, bool doAntiAlias = true);
void clipPath(const CanvasPath* path, bool doAntiAlias = true);
void drawColor(SkColor color, SkBlendMode blend_mode); void drawColor(SkColor color, SkBlendMode blend_mode);
void drawLine(double x1, void drawLine(double x1,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册