Add ClipMode to ClipPath/ClipRRect and PhysicalShape layers (flutter/engine#5647)
For flutter/flutter#18057
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
@@ -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<flow::ClipRectLayer>();
|
||||
auto layer = std::make_unique<flow::ClipRectLayer>(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<flow::ClipRRectLayer>();
|
||||
auto layer = std::make_unique<flow::ClipRRectLayer>(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<flow::ClipPathLayer>();
|
||||
auto layer = std::make_unique<flow::ClipPathLayer>(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<flow::PhysicalShapeLayer>();
|
||||
auto layer = std::make_unique<flow::PhysicalShapeLayer>(clip_mode);
|
||||
layer->set_path(sk_path);
|
||||
layer->set_elevation(elevation);
|
||||
layer->set_color(color);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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<flow::ClipMode>(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<flow::ClipMode>(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<flow::ClipMode>(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<SkColor>(color), //
|
||||
static_cast<SkColor>(shadow_color),
|
||||
UIDartState::Current()->window()->viewport_metrics().device_pixel_ratio);
|
||||
UIDartState::Current()->window()->viewport_metrics().device_pixel_ratio,
|
||||
static_cast<flow::ClipMode>(clip_mode));
|
||||
}
|
||||
|
||||
void SceneBuilder::pop() {
|
||||
|
||||
@@ -35,9 +35,9 @@ class SceneBuilder : public fxl::RefCountedThreadSafe<SceneBuilder>,
|
||||
~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<SceneBuilder>,
|
||||
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();
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user