diff --git a/engine/src/flutter/flow/layers/clip_path_layer.cc b/engine/src/flutter/flow/layers/clip_path_layer.cc index e5547a39a9..d6c091ee15 100644 --- a/engine/src/flutter/flow/layers/clip_path_layer.cc +++ b/engine/src/flutter/flow/layers/clip_path_layer.cc @@ -12,7 +12,7 @@ namespace flow { -ClipPathLayer::ClipPathLayer() = default; +ClipPathLayer::ClipPathLayer(ClipMode clip_mode) : clip_mode_(clip_mode) {} ClipPathLayer::~ClipPathLayer() = default; @@ -38,6 +38,7 @@ void ClipPathLayer::UpdateScene(SceneUpdateContext& context) { bounds.height() // height ); + // TODO(liyuqian): respect clip_mode_ SceneUpdateContext::Clip clip(context, shape, bounds); UpdateSceneChildren(context); } @@ -49,8 +50,14 @@ void ClipPathLayer::Paint(PaintContext& context) const { FXL_DCHECK(needs_painting()); SkAutoCanvasRestore save(&context.canvas, true); - context.canvas.clipPath(clip_path_, true); + context.canvas.clipPath(clip_path_, clip_mode_ != ClipMode::hardEdge); + if (clip_mode_ == ClipMode::antiAliasWithSaveLayer) { + context.canvas.saveLayer(paint_bounds(), nullptr); + } PaintChildren(context); + if (clip_mode_ == ClipMode::antiAliasWithSaveLayer) { + context.canvas.restore(); + } } } // namespace flow diff --git a/engine/src/flutter/flow/layers/clip_path_layer.h b/engine/src/flutter/flow/layers/clip_path_layer.h index 87a37bdc8a..78017144ed 100644 --- a/engine/src/flutter/flow/layers/clip_path_layer.h +++ b/engine/src/flutter/flow/layers/clip_path_layer.h @@ -11,7 +11,7 @@ namespace flow { class ClipPathLayer : public ContainerLayer { public: - ClipPathLayer(); + ClipPathLayer(ClipMode clip_mode = ClipMode::antiAlias); ~ClipPathLayer() override; void set_clip_path(const SkPath& clip_path) { clip_path_ = clip_path; } @@ -26,6 +26,7 @@ class ClipPathLayer : public ContainerLayer { private: SkPath clip_path_; + ClipMode clip_mode_; FXL_DISALLOW_COPY_AND_ASSIGN(ClipPathLayer); }; diff --git a/engine/src/flutter/flow/layers/clip_rect_layer.cc b/engine/src/flutter/flow/layers/clip_rect_layer.cc index 0e61379342..0fca7ab821 100644 --- a/engine/src/flutter/flow/layers/clip_rect_layer.cc +++ b/engine/src/flutter/flow/layers/clip_rect_layer.cc @@ -6,7 +6,7 @@ namespace flow { -ClipRectLayer::ClipRectLayer() = default; +ClipRectLayer::ClipRectLayer(ClipMode clip_mode) : clip_mode_(clip_mode) {} ClipRectLayer::~ClipRectLayer() = default; @@ -29,6 +29,7 @@ void ClipRectLayer::UpdateScene(SceneUpdateContext& context) { clip_rect_.height() // height ); + // TODO(liyuqian): respect clip_mode_ SceneUpdateContext::Clip clip(context, shape, clip_rect_); UpdateSceneChildren(context); } @@ -39,9 +40,15 @@ void ClipRectLayer::Paint(PaintContext& context) const { TRACE_EVENT0("flutter", "ClipRectLayer::Paint"); FXL_DCHECK(needs_painting()); - SkAutoCanvasRestore save(&context.canvas, true); + SkAutoCanvasRestore save(&context.canvas, clip_mode_ != ClipMode::hardEdge); context.canvas.clipRect(paint_bounds()); + if (clip_mode_ == ClipMode::antiAliasWithSaveLayer) { + context.canvas.saveLayer(paint_bounds(), nullptr); + } PaintChildren(context); + if (clip_mode_ == ClipMode::antiAliasWithSaveLayer) { + context.canvas.restore(); + } } } // namespace flow diff --git a/engine/src/flutter/flow/layers/clip_rect_layer.h b/engine/src/flutter/flow/layers/clip_rect_layer.h index a7dfecc88e..6e50856359 100644 --- a/engine/src/flutter/flow/layers/clip_rect_layer.h +++ b/engine/src/flutter/flow/layers/clip_rect_layer.h @@ -11,7 +11,7 @@ namespace flow { class ClipRectLayer : public ContainerLayer { public: - ClipRectLayer(); + ClipRectLayer(ClipMode clip_mode); ~ClipRectLayer() override; void set_clip_rect(const SkRect& clip_rect) { clip_rect_ = clip_rect; } @@ -25,6 +25,7 @@ class ClipRectLayer : public ContainerLayer { private: SkRect clip_rect_; + ClipMode clip_mode_; FXL_DISALLOW_COPY_AND_ASSIGN(ClipRectLayer); }; diff --git a/engine/src/flutter/flow/layers/clip_rrect_layer.cc b/engine/src/flutter/flow/layers/clip_rrect_layer.cc index 67ec489d6b..0a7ce3864a 100644 --- a/engine/src/flutter/flow/layers/clip_rrect_layer.cc +++ b/engine/src/flutter/flow/layers/clip_rrect_layer.cc @@ -6,7 +6,7 @@ namespace flow { -ClipRRectLayer::ClipRRectLayer() = default; +ClipRRectLayer::ClipRRectLayer(ClipMode clip_mode) : clip_mode_(clip_mode) {} ClipRRectLayer::~ClipRRectLayer() = default; @@ -36,6 +36,7 @@ void ClipRRectLayer::UpdateScene(SceneUpdateContext& context) { clip_rrect_.radii(SkRRect::kLowerLeft_Corner).x() // bottom_left_radius ); + // TODO(liyuqian): respect clip_mode_ SceneUpdateContext::Clip clip(context, shape, clip_rrect_.getBounds()); UpdateSceneChildren(context); } @@ -47,8 +48,14 @@ void ClipRRectLayer::Paint(PaintContext& context) const { FXL_DCHECK(needs_painting()); SkAutoCanvasRestore save(&context.canvas, true); - context.canvas.clipRRect(clip_rrect_, true); + context.canvas.clipRRect(clip_rrect_, clip_mode_ != ClipMode::hardEdge); + if (clip_mode_ == ClipMode::antiAliasWithSaveLayer) { + context.canvas.saveLayer(paint_bounds(), nullptr); + } PaintChildren(context); + if (clip_mode_ == ClipMode::antiAliasWithSaveLayer) { + context.canvas.restore(); + } } } // namespace flow diff --git a/engine/src/flutter/flow/layers/clip_rrect_layer.h b/engine/src/flutter/flow/layers/clip_rrect_layer.h index 5763313c97..24c7badf9b 100644 --- a/engine/src/flutter/flow/layers/clip_rrect_layer.h +++ b/engine/src/flutter/flow/layers/clip_rrect_layer.h @@ -11,7 +11,7 @@ namespace flow { class ClipRRectLayer : public ContainerLayer { public: - ClipRRectLayer(); + ClipRRectLayer(ClipMode clip_mode); ~ClipRRectLayer() override; void set_clip_rrect(const SkRRect& clip_rrect) { clip_rrect_ = clip_rrect; } @@ -26,6 +26,7 @@ class ClipRRectLayer : public ContainerLayer { private: SkRRect clip_rrect_; + ClipMode clip_mode_; FXL_DISALLOW_COPY_AND_ASSIGN(ClipRRectLayer); }; diff --git a/engine/src/flutter/flow/layers/default_layer_builder.cc b/engine/src/flutter/flow/layers/default_layer_builder.cc index fb2280b27e..c17f77cc14 100644 --- a/engine/src/flutter/flow/layers/default_layer_builder.cc +++ b/engine/src/flutter/flow/layers/default_layer_builder.cc @@ -49,32 +49,33 @@ void DefaultLayerBuilder::PushTransform(const SkMatrix& sk_matrix) { PushLayer(std::move(layer), cullRect); } -void DefaultLayerBuilder::PushClipRect(const SkRect& clipRect) { +void DefaultLayerBuilder::PushClipRect(const SkRect& clipRect, ClipMode clip_mode) { SkRect cullRect; if (!cullRect.intersect(clipRect, cull_rects_.top())) { cullRect = SkRect::MakeEmpty(); } - auto layer = std::make_unique(); + auto layer = std::make_unique(clip_mode); layer->set_clip_rect(clipRect); PushLayer(std::move(layer), cullRect); } -void DefaultLayerBuilder::PushClipRoundedRect(const SkRRect& rrect) { +void DefaultLayerBuilder::PushClipRoundedRect(const SkRRect& rrect, ClipMode clip_mode) { SkRect cullRect; if (!cullRect.intersect(rrect.rect(), cull_rects_.top())) { cullRect = SkRect::MakeEmpty(); } - auto layer = std::make_unique(); + auto layer = std::make_unique(clip_mode); layer->set_clip_rrect(rrect); PushLayer(std::move(layer), cullRect); } -void DefaultLayerBuilder::PushClipPath(const SkPath& path) { +void DefaultLayerBuilder::PushClipPath(const SkPath& path, ClipMode clip_mode) { + FXL_DCHECK(clip_mode != ClipMode::none); SkRect cullRect; if (!cullRect.intersect(path.getBounds(), cull_rects_.top())) { cullRect = SkRect::MakeEmpty(); } - auto layer = std::make_unique(); + auto layer = std::make_unique(clip_mode); layer->set_clip_path(path); PushLayer(std::move(layer), cullRect); } @@ -113,12 +114,13 @@ void DefaultLayerBuilder::PushPhysicalShape(const SkPath& sk_path, double elevation, SkColor color, SkColor shadow_color, - SkScalar device_pixel_ratio) { + SkScalar device_pixel_ratio, + ClipMode clip_mode) { SkRect cullRect; if (!cullRect.intersect(sk_path.getBounds(), cull_rects_.top())) { cullRect = SkRect::MakeEmpty(); } - auto layer = std::make_unique(); + auto layer = std::make_unique(clip_mode); layer->set_path(sk_path); layer->set_elevation(elevation); layer->set_color(color); diff --git a/engine/src/flutter/flow/layers/default_layer_builder.h b/engine/src/flutter/flow/layers/default_layer_builder.h index cadd173ab5..267eaad83f 100644 --- a/engine/src/flutter/flow/layers/default_layer_builder.h +++ b/engine/src/flutter/flow/layers/default_layer_builder.h @@ -24,13 +24,13 @@ class DefaultLayerBuilder final : public LayerBuilder { void PushTransform(const SkMatrix& matrix) override; // |flow::LayerBuilder| - void PushClipRect(const SkRect& rect) override; + void PushClipRect(const SkRect& rect, ClipMode clip_mode = ClipMode::antiAlias) override; // |flow::LayerBuilder| - void PushClipRoundedRect(const SkRRect& rect) override; + void PushClipRoundedRect(const SkRRect& rect, ClipMode clip_mode = ClipMode::antiAlias) override; // |flow::LayerBuilder| - void PushClipPath(const SkPath& path) override; + void PushClipPath(const SkPath& path, ClipMode clip_mode = ClipMode::antiAlias) override; // |flow::LayerBuilder| void PushOpacity(int alpha) override; @@ -51,7 +51,8 @@ class DefaultLayerBuilder final : public LayerBuilder { double elevation, SkColor color, SkColor shadow_color, - SkScalar device_pixel_ratio) override; + SkScalar device_pixel_ratio, + ClipMode clip_mode) override; // |flow::LayerBuilder| void PushPerformanceOverlay(uint64_t enabled_options, diff --git a/engine/src/flutter/flow/layers/layer.h b/engine/src/flutter/flow/layers/layer.h index 87539d3e98..464787ebda 100644 --- a/engine/src/flutter/flow/layers/layer.h +++ b/engine/src/flutter/flow/layers/layer.h @@ -34,6 +34,19 @@ namespace flow { +// This should be an exact copy of the Clip enum in painting.dart. +// +// We call it Clip in public Dart API to provide our developers the shortest +// name and the best experience. We call it ClipMode in C++ because we want to +// avoid name conflicts and refactoring C++ names without a nice IDE function +// is tedious. +enum ClipMode { + none, + hardEdge, + antiAlias, + antiAliasWithSaveLayer +}; + class ContainerLayer; // Represents a single composited layer. Created on the UI thread but then diff --git a/engine/src/flutter/flow/layers/layer_builder.h b/engine/src/flutter/flow/layers/layer_builder.h index a29e959514..93195b0364 100644 --- a/engine/src/flutter/flow/layers/layer_builder.h +++ b/engine/src/flutter/flow/layers/layer_builder.h @@ -32,11 +32,11 @@ class LayerBuilder { virtual void PushTransform(const SkMatrix& matrix) = 0; - virtual void PushClipRect(const SkRect& rect) = 0; + virtual void PushClipRect(const SkRect& rect, ClipMode clip_mode = ClipMode::antiAlias) = 0; - virtual void PushClipRoundedRect(const SkRRect& rect) = 0; + virtual void PushClipRoundedRect(const SkRRect& rect, ClipMode clip_mode = ClipMode::antiAlias) = 0; - virtual void PushClipPath(const SkPath& path) = 0; + virtual void PushClipPath(const SkPath& path, ClipMode clip_mode = ClipMode::antiAlias) = 0; virtual void PushOpacity(int alpha) = 0; @@ -52,7 +52,8 @@ class LayerBuilder { double elevation, SkColor color, SkColor shadow_color, - SkScalar device_pixel_ratio) = 0; + SkScalar device_pixel_ratio, + ClipMode clip_mode) = 0; virtual void PushPerformanceOverlay(uint64_t enabled_options, const SkRect& rect) = 0; diff --git a/engine/src/flutter/flow/layers/physical_shape_layer.cc b/engine/src/flutter/flow/layers/physical_shape_layer.cc index b793132cc8..a60b38dc5e 100644 --- a/engine/src/flutter/flow/layers/physical_shape_layer.cc +++ b/engine/src/flutter/flow/layers/physical_shape_layer.cc @@ -9,7 +9,7 @@ namespace flow { -PhysicalShapeLayer::PhysicalShapeLayer() : isRect_(false) {} +PhysicalShapeLayer::PhysicalShapeLayer(ClipMode clip_mode) : isRect_(false), clip_mode_(clip_mode) {} PhysicalShapeLayer::~PhysicalShapeLayer() = default; @@ -90,12 +90,25 @@ void PhysicalShapeLayer::Paint(PaintContext& context) const { paint.setColor(color_); context.canvas.drawPath(path_, paint); - SkAutoCanvasRestore save(&context.canvas, false); - context.canvas.save(); - context.canvas.clipPath(path_, true); + int saveCount = context.canvas.save(); + switch(clip_mode_) { + case ClipMode::hardEdge: + context.canvas.clipPath(path_, false); + break; + case ClipMode::antiAlias: + context.canvas.clipPath(path_, true); + break; + case ClipMode::antiAliasWithSaveLayer: + context.canvas.clipPath(path_, true); + context.canvas.saveLayer(paint_bounds(), nullptr); + break; + case ClipMode::none: + break; + } + PaintChildren(context); - if (context.checkerboard_offscreen_layers && !isRect_) - DrawCheckerboard(&context.canvas, path_.getBounds()); + + context.canvas.restoreToCount(saveCount); } void PhysicalShapeLayer::DrawShadow(SkCanvas* canvas, diff --git a/engine/src/flutter/flow/layers/physical_shape_layer.h b/engine/src/flutter/flow/layers/physical_shape_layer.h index c3df356b63..9ed4e3a50e 100644 --- a/engine/src/flutter/flow/layers/physical_shape_layer.h +++ b/engine/src/flutter/flow/layers/physical_shape_layer.h @@ -11,7 +11,7 @@ namespace flow { class PhysicalShapeLayer : public ContainerLayer { public: - PhysicalShapeLayer(); + PhysicalShapeLayer(ClipMode clip_mode); ~PhysicalShapeLayer() override; void set_path(const SkPath& path); @@ -44,6 +44,7 @@ class PhysicalShapeLayer : public ContainerLayer { SkPath path_; bool isRect_; SkRRect frameRRect_; + ClipMode clip_mode_; }; } // namespace flow diff --git a/engine/src/flutter/lib/ui/compositing.dart b/engine/src/flutter/lib/ui/compositing.dart index 35595f4cf6..f83a7deb4a 100644 --- a/engine/src/flutter/lib/ui/compositing.dart +++ b/engine/src/flutter/lib/ui/compositing.dart @@ -66,29 +66,44 @@ class SceneBuilder extends NativeFieldWrapperClass2 { /// /// Rasterization outside the given rectangle is discarded. /// - /// See [pop] for details about the operation stack. - void pushClipRect(Rect rect) { - _pushClipRect(rect.left, rect.right, rect.top, rect.bottom); + /// See [pop] for details about the operation stack, and [Clip] for different clip modes. + /// By default, the clip will be anti-aliased (clip = [Clip.antiAlias]). + void pushClipRect(Rect rect, {Clip clip = Clip.antiAlias}) { + assert(clip != null); + assert(clip != Clip.none); + _pushClipRect(rect.left, rect.right, rect.top, rect.bottom, clip.index); } void _pushClipRect(double left, double right, double top, - double bottom) native 'SceneBuilder_pushClipRect'; + double bottom, + int clipMode) native 'SceneBuilder_pushClipRect'; /// Pushes a rounded-rectangular clip operation onto the operation stack. /// /// Rasterization outside the given rounded rectangle is discarded. /// - /// See [pop] for details about the operation stack. - void pushClipRRect(RRect rrect) => _pushClipRRect(rrect._value); - void _pushClipRRect(Float32List rrect) native 'SceneBuilder_pushClipRRect'; + /// See [pop] for details about the operation stack, and [Clip] for different clip modes. + /// By default, the clip will be anti-aliased (clip = [Clip.antiAlias]). + void pushClipRRect(RRect rrect, {Clip clip = Clip.antiAlias}) { + assert(clip != null); + assert(clip != Clip.none); + _pushClipRRect(rrect._value, clip.index); + } + void _pushClipRRect(Float32List rrect, int clipMode) native 'SceneBuilder_pushClipRRect'; /// Pushes a path clip operation onto the operation stack. /// /// Rasterization outside the given path is discarded. /// - /// See [pop] for details about the operation stack. - void pushClipPath(Path path) native 'SceneBuilder_pushClipPath'; + /// See [pop] for details about the operation stack. See [Clip] for different clip modes. + /// By default, the clip will be anti-aliased (clip = [Clip.antiAlias]). + void pushClipPath(Path path, {Clip clip = Clip.antiAlias}) { + assert(clip != null); + assert(clip != Clip.none); + _pushClipPath(path, clip.index); + } + void _pushClipPath(Path path, int clipMode) native 'SceneBuilder_pushClipPath'; /// Pushes an opacity operation onto the operation stack. /// @@ -143,16 +158,20 @@ class SceneBuilder extends NativeFieldWrapperClass2 { /// Pushes a physical layer operation for an arbitrary shape onto the /// operation stack. /// - /// Rasterization will be clipped to the given shape defined by [path]. If - /// [elevation] is greater than 0.0, then a shadow is drawn around the layer. + /// By default, the layer's content will not be clipped (clip = [Clip.none]). + /// If clip equals [Clip.hardEdge], [Clip.antiAlias], or [Clip.antiAliasWithSaveLayer], + /// then the content is clipped to the given shape defined by [path]. + /// + /// If [elevation] is greater than 0.0, then a shadow is drawn around the layer. /// [shadowColor] defines the color of the shadow if present and [color] defines the /// color of the layer background. /// - /// See [pop] for details about the operation stack. - void pushPhysicalShape({ Path path, double elevation, Color color, Color shadowColor}) { - _pushPhysicalShape(path, elevation, color.value, shadowColor?.value ?? 0xFF000000); + /// See [pop] for details about the operation stack, and [Clip] for different clip modes. + // ignore: deprecated_member_use + void pushPhysicalShape({ Path path, double elevation, Color color, Color shadowColor, Clip clip = defaultClipBehavior}) { + _pushPhysicalShape(path, elevation, color.value, shadowColor?.value ?? 0xFF000000, clip.index); } - void _pushPhysicalShape(Path path, double elevation, int color, int shadowColor) native + void _pushPhysicalShape(Path path, double elevation, int color, int shadowColor, int clipMode) native 'SceneBuilder_pushPhysicalShape'; /// Ends the effect of the most recently pushed operation. diff --git a/engine/src/flutter/lib/ui/compositing/scene_builder.cc b/engine/src/flutter/lib/ui/compositing/scene_builder.cc index 60b911cb4d..fda3b8ee85 100644 --- a/engine/src/flutter/lib/ui/compositing/scene_builder.cc +++ b/engine/src/flutter/lib/ui/compositing/scene_builder.cc @@ -62,16 +62,17 @@ void SceneBuilder::pushTransform(const tonic::Float64List& matrix4) { void SceneBuilder::pushClipRect(double left, double right, double top, - double bottom) { - layer_builder_->PushClipRect(SkRect::MakeLTRB(left, top, right, bottom)); + double bottom, + int clipMode) { + layer_builder_->PushClipRect(SkRect::MakeLTRB(left, top, right, bottom), static_cast(clipMode)); } -void SceneBuilder::pushClipRRect(const RRect& rrect) { - layer_builder_->PushClipRoundedRect(rrect.sk_rrect); +void SceneBuilder::pushClipRRect(const RRect& rrect, int clipMode) { + layer_builder_->PushClipRoundedRect(rrect.sk_rrect, static_cast(clipMode)); } -void SceneBuilder::pushClipPath(const CanvasPath* path) { - layer_builder_->PushClipPath(path->path()); +void SceneBuilder::pushClipPath(const CanvasPath* path, int clipMode) { + layer_builder_->PushClipPath(path->path(), static_cast(clipMode)); } void SceneBuilder::pushOpacity(int alpha) { @@ -103,13 +104,15 @@ void SceneBuilder::pushShaderMask(Shader* shader, void SceneBuilder::pushPhysicalShape(const CanvasPath* path, double elevation, int color, - int shadow_color) { + int shadow_color, + int clip_mode) { layer_builder_->PushPhysicalShape( path->path(), // elevation, // static_cast(color), // static_cast(shadow_color), - UIDartState::Current()->window()->viewport_metrics().device_pixel_ratio); + UIDartState::Current()->window()->viewport_metrics().device_pixel_ratio, + static_cast(clip_mode)); } void SceneBuilder::pop() { diff --git a/engine/src/flutter/lib/ui/compositing/scene_builder.h b/engine/src/flutter/lib/ui/compositing/scene_builder.h index fd1e20d2aa..ebbc35efa2 100644 --- a/engine/src/flutter/lib/ui/compositing/scene_builder.h +++ b/engine/src/flutter/lib/ui/compositing/scene_builder.h @@ -35,9 +35,9 @@ class SceneBuilder : public fxl::RefCountedThreadSafe, ~SceneBuilder() override; void pushTransform(const tonic::Float64List& matrix4); - void pushClipRect(double left, double right, double top, double bottom); - void pushClipRRect(const RRect& rrect); - void pushClipPath(const CanvasPath* path); + void pushClipRect(double left, double right, double top, double bottom, int clipMode); + void pushClipRRect(const RRect& rrect, int clipMode); + void pushClipPath(const CanvasPath* path, int clipMode); void pushOpacity(int alpha); void pushColorFilter(int color, int blendMode); void pushBackdropFilter(ImageFilter* filter); @@ -47,7 +47,7 @@ class SceneBuilder : public fxl::RefCountedThreadSafe, double maskRectTop, double maskRectBottom, int blendMode); - void pushPhysicalShape(const CanvasPath* path, double elevation, int color, int shadowColor); + void pushPhysicalShape(const CanvasPath* path, double elevation, int color, int shadowColor, int clipMode); void pop(); diff --git a/engine/src/flutter/lib/ui/painting.dart b/engine/src/flutter/lib/ui/painting.dart index 348432ec72..e2fe0521a6 100644 --- a/engine/src/flutter/lib/ui/painting.dart +++ b/engine/src/flutter/lib/ui/painting.dart @@ -942,6 +942,89 @@ enum PaintingStyle { stroke, } + +/// Different ways to clip a widget's content. +enum Clip { + /// No clip at all. + /// + /// This is the default option for most widgets: if the content does not + /// overflow the widget boundary, don't pay any performance cost for clipping. + /// + /// If the content does overflow, please explicitly specify the following + /// [Clip] options: + /// * [hardEdge], which is the fastest clipping, but with lower fidelity. + /// * [antiAlias], which is a little slower than [hardEdge], but with smoothed edges. + /// * [antiAliasWithSaveLayer], which is much slower than [antiAlias], and should + /// rarely be used. + none, + + /// Clip, but do not apply anti-aliasing. + /// + /// This mode enables clipping, but curves and non-axis-aligned straight lines will be + /// jagged as no effort is made to anti-alias. + /// + /// Faster than other clipping modes, but slower than [none]. + /// + /// This is a reasonable choice when clipping is needed, if the container is an axis- + /// aligned rectangle or an axis-aligned rounded rectangle with very small corner radii. + /// + /// See also: + /// + /// * [antiAlias], which is more reasonable when clipping is needed and the shape is not + /// an axis-aligned rectangle. + hardEdge, + + /// Clip with anti-aliasing. + /// + /// This mode has anti-aliased clipping edges to achieve a smoother look. + /// + /// It' s much faster than [antiAliasWithSaveLayer], but slower than [hardEdge]. + /// + /// This will be the common case when dealing with circles and arcs. + /// + /// Different from [hardEdge] and [antiAliasWithSaveLayer], this clipping may have + /// bleeding edge artifacts. + /// (See https://fiddle.skia.org/c/21cb4c2b2515996b537f36e7819288ae for an example.) + /// + /// See also: + /// + /// * [hardEdge], which is a little faster, but with lower fidelity. + /// * [antiAliasWithSaveLayer], which is much slower, but can avoid the + /// bleeding edges if there's no other way. + /// * [Paint.isAntiAlias], which is the anti-aliasing switch for general draw operations. + antiAlias, + + /// Clip with anti-aliasing and saveLayer immediately following the clip. + /// + /// This mode not only clips with anti-aliasing, but also allocates an offscreen + /// buffer. All subsequent paints are carried out on that buffer before finally + /// being clipped and composited back. + /// + /// This is very slow. It has no bleeding edge artifacts (that [antiAlias] has) + /// but it changes the semantics as an offscreen buffer is now introduced. + /// (See https://github.com/flutter/flutter/issues/18057#issuecomment-394197336 + /// for a difference between paint without saveLayer and paint with saveLayer.) + /// + /// This will be only rarely needed. One case where you might need this is if + /// you have an image overlaid on a very different background color. In these + /// cases, consider whether you can avoid overlaying multiple colors in one + /// spot (e.g. by having the background color only present where the image is + /// absent). If you can, [antiAlias] would be fine and much faster. + /// + /// See also: + /// + /// * [antiAlias], which is much faster, and has similar clipping results. + antiAliasWithSaveLayer, +} + +/// The global default value of whether and how to clip a widget. This is only for +/// temporary migration from default-to-clip to default-to-NOT-clip. +/// +// TODO(liyuqian): Set it to Clip.none. (https://github.com/flutter/flutter/issues/18057) +// We currently have Clip.antiAlias to preserve our old behaviors. +@Deprecated("Do not use this as it'll soon be removed after we set the default behavior to Clip.none.") +const Clip defaultClipBehavior = Clip.antiAlias; + // If we actually run on big endian machines, we'll need to do something smarter // here. We don't use [Endian.Host] because it's not a compile-time // constant and can't propagate into the set/get calls.