Refactor clip layers to share common code (flutter/engine#32889)

This commit is contained in:
ColdPaleLight 2022-05-12 16:39:04 +08:00 committed by GitHub
parent 54f2dde409
commit c014ce9727
11 changed files with 186 additions and 232 deletions

View File

@ -139,6 +139,7 @@ FILE: ../../../flutter/flow/layers/clip_rect_layer_unittests.cc
FILE: ../../../flutter/flow/layers/clip_rrect_layer.cc
FILE: ../../../flutter/flow/layers/clip_rrect_layer.h
FILE: ../../../flutter/flow/layers/clip_rrect_layer_unittests.cc
FILE: ../../../flutter/flow/layers/clip_shape_layer.h
FILE: ../../../flutter/flow/layers/color_filter_layer.cc
FILE: ../../../flutter/flow/layers/color_filter_layer.h
FILE: ../../../flutter/flow/layers/color_filter_layer_unittests.cc

View File

@ -28,6 +28,7 @@ source_set("flow") {
"layers/clip_rect_layer.h",
"layers/clip_rrect_layer.cc",
"layers/clip_rrect_layer.h",
"layers/clip_shape_layer.h",
"layers/color_filter_layer.cc",
"layers/color_filter_layer.h",
"layers/container_layer.cc",

View File

@ -60,8 +60,8 @@ TEST_F(CheckerBoardLayerTest, ClipRectSaveLayerNotCheckBoard) {
1, MockCanvas::ClipRectData{layer_bounds, SkClipOp::kIntersect,
MockCanvas::kSoft_ClipEdgeStyle}},
MockCanvas::DrawCall{
1,
MockCanvas::SaveLayerData{layer_bounds, clip_paint, nullptr, 2}},
1, MockCanvas::SaveLayerData{layer->paint_bounds(), clip_paint,
nullptr, 2}},
MockCanvas::DrawCall{
2, MockCanvas::DrawPathData{child_path, child_paint}},
MockCanvas::DrawCall{2, MockCanvas::RestoreData{1}},
@ -110,8 +110,8 @@ TEST_F(CheckerBoardLayerTest, ClipRectSaveLayerCheckBoard) {
1, MockCanvas::ClipRectData{layer_bounds, SkClipOp::kIntersect,
MockCanvas::kSoft_ClipEdgeStyle}},
MockCanvas::DrawCall{
1,
MockCanvas::SaveLayerData{layer_bounds, clip_paint, nullptr, 2}},
1, MockCanvas::SaveLayerData{layer->paint_bounds(), clip_paint,
nullptr, 2}},
MockCanvas::DrawCall{
2, MockCanvas::DrawPathData{child_path, child_paint}},
MockCanvas::DrawCall{2, MockCanvas::RestoreData{1}},

View File

@ -3,86 +3,33 @@
// found in the LICENSE file.
#include "flutter/flow/layers/clip_path_layer.h"
#include "flutter/flow/paint_utils.h"
namespace flutter {
ClipPathLayer::ClipPathLayer(const SkPath& clip_path, Clip clip_behavior)
: clip_path_(clip_path), clip_behavior_(clip_behavior) {
FML_DCHECK(clip_behavior != Clip::none);
}
void ClipPathLayer::Diff(DiffContext* context, const Layer* old_layer) {
DiffContext::AutoSubtreeRestore subtree(context);
auto* prev = static_cast<const ClipPathLayer*>(old_layer);
if (!context->IsSubtreeDirty()) {
FML_DCHECK(prev);
if (clip_behavior_ != prev->clip_behavior_ ||
clip_path_ != prev->clip_path_) {
context->MarkSubtreeDirty(context->GetOldLayerPaintRegion(old_layer));
}
}
if (context->PushCullRect(clip_path_.getBounds())) {
DiffChildren(context, prev);
}
context->SetLayerPaintRegion(this, context->CurrentSubtreeRegion());
}
: ClipShapeLayer(clip_path, clip_behavior) {}
void ClipPathLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
TRACE_EVENT0("flutter", "ClipPathLayer::Preroll");
SkRect previous_cull_rect = context->cull_rect;
SkRect clip_path_bounds = clip_path_.getBounds();
if (!context->cull_rect.intersect(clip_path_bounds)) {
context->cull_rect.setEmpty();
}
Layer::AutoPrerollSaveLayerState save =
Layer::AutoPrerollSaveLayerState::Create(context, UsesSaveLayer());
context->mutators_stack.PushClipPath(clip_path_);
// Collect inheritance information on our children in Preroll so that
// we can pass it along by default.
context->subtree_can_inherit_opacity = true;
SkRect child_paint_bounds = SkRect::MakeEmpty();
PrerollChildren(context, matrix, &child_paint_bounds);
if (child_paint_bounds.intersect(clip_path_bounds)) {
set_paint_bounds(child_paint_bounds);
}
// If we use a SaveLayer then we can accept opacity on behalf
// of our children and apply it in the saveLayer.
if (UsesSaveLayer()) {
context->subtree_can_inherit_opacity = true;
}
context->mutators_stack.Pop();
context->cull_rect = previous_cull_rect;
ClipShapeLayer::Preroll(context, matrix);
}
void ClipPathLayer::Paint(PaintContext& context) const {
TRACE_EVENT0("flutter", "ClipPathLayer::Paint");
FML_DCHECK(needs_painting(context));
ClipShapeLayer::Paint(context);
}
SkAutoCanvasRestore save(context.internal_nodes_canvas, true);
context.internal_nodes_canvas->clipPath(clip_path_,
clip_behavior_ != Clip::hardEdge);
const SkRect& ClipPathLayer::clip_shape_bounds() const {
return clip_shape().getBounds();
}
if (!UsesSaveLayer()) {
PaintChildren(context);
return;
}
void ClipPathLayer::OnMutatorsStackPushClipShape(
MutatorsStack& mutators_stack) {
mutators_stack.PushClipPath(clip_shape());
}
AutoCachePaint cache_paint(context);
TRACE_EVENT0("flutter", "Canvas::saveLayer");
context.internal_nodes_canvas->saveLayer(paint_bounds(), cache_paint.paint());
PaintChildren(context);
context.internal_nodes_canvas->restore();
if (context.checkerboard_offscreen_layers) {
DrawCheckerboard(context.internal_nodes_canvas, paint_bounds());
}
void ClipPathLayer::OnCanvasClipShape(SkCanvas* canvas) const {
canvas->clipPath(clip_shape(), clip_behavior() != Clip::hardEdge);
}
} // namespace flutter

View File

@ -5,29 +5,27 @@
#ifndef FLUTTER_FLOW_LAYERS_CLIP_PATH_LAYER_H_
#define FLUTTER_FLOW_LAYERS_CLIP_PATH_LAYER_H_
#include "flutter/flow/layers/container_layer.h"
#include "flutter/flow/layers/clip_shape_layer.h"
namespace flutter {
class ClipPathLayer : public ContainerLayer {
class ClipPathLayer : public ClipShapeLayer<SkPath> {
public:
explicit ClipPathLayer(const SkPath& clip_path,
Clip clip_behavior = Clip::antiAlias);
void Diff(DiffContext* context, const Layer* old_layer) override;
void Preroll(PrerollContext* context, const SkMatrix& matrix) override;
void Paint(PaintContext& context) const override;
bool UsesSaveLayer() const {
return clip_behavior_ == Clip::antiAliasWithSaveLayer;
}
protected:
const SkRect& clip_shape_bounds() const override;
void OnMutatorsStackPushClipShape(MutatorsStack& mutators_stack) override;
void OnCanvasClipShape(SkCanvas* canvas) const override;
private:
SkPath clip_path_;
Clip clip_behavior_;
FML_DISALLOW_COPY_AND_ASSIGN(ClipPathLayer);
};

View File

@ -3,85 +3,33 @@
// found in the LICENSE file.
#include "flutter/flow/layers/clip_rect_layer.h"
#include "flutter/flow/paint_utils.h"
namespace flutter {
ClipRectLayer::ClipRectLayer(const SkRect& clip_rect, Clip clip_behavior)
: clip_rect_(clip_rect), clip_behavior_(clip_behavior) {
FML_DCHECK(clip_behavior != Clip::none);
}
void ClipRectLayer::Diff(DiffContext* context, const Layer* old_layer) {
DiffContext::AutoSubtreeRestore subtree(context);
auto* prev = static_cast<const ClipRectLayer*>(old_layer);
if (!context->IsSubtreeDirty()) {
FML_DCHECK(prev);
if (clip_behavior_ != prev->clip_behavior_ ||
clip_rect_ != prev->clip_rect_) {
context->MarkSubtreeDirty(context->GetOldLayerPaintRegion(old_layer));
}
}
if (context->PushCullRect(clip_rect_)) {
DiffChildren(context, prev);
}
context->SetLayerPaintRegion(this, context->CurrentSubtreeRegion());
}
: ClipShapeLayer(clip_rect, clip_behavior) {}
void ClipRectLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
TRACE_EVENT0("flutter", "ClipRectLayer::Preroll");
SkRect previous_cull_rect = context->cull_rect;
if (!context->cull_rect.intersect(clip_rect_)) {
context->cull_rect.setEmpty();
}
Layer::AutoPrerollSaveLayerState save =
Layer::AutoPrerollSaveLayerState::Create(context, UsesSaveLayer());
context->mutators_stack.PushClipRect(clip_rect_);
// Collect inheritance information on our children in Preroll so that
// we can pass it along by default.
context->subtree_can_inherit_opacity = true;
SkRect child_paint_bounds = SkRect::MakeEmpty();
PrerollChildren(context, matrix, &child_paint_bounds);
if (child_paint_bounds.intersect(clip_rect_)) {
set_paint_bounds(child_paint_bounds);
}
// If we use a SaveLayer then we can accept opacity on behalf
// of our children and apply it in the saveLayer.
if (UsesSaveLayer()) {
context->subtree_can_inherit_opacity = true;
}
context->mutators_stack.Pop();
context->cull_rect = previous_cull_rect;
ClipShapeLayer::Preroll(context, matrix);
}
void ClipRectLayer::Paint(PaintContext& context) const {
TRACE_EVENT0("flutter", "ClipRectLayer::Paint");
FML_DCHECK(needs_painting(context));
ClipShapeLayer::Paint(context);
}
SkAutoCanvasRestore save(context.internal_nodes_canvas, true);
context.internal_nodes_canvas->clipRect(clip_rect_,
clip_behavior_ != Clip::hardEdge);
const SkRect& ClipRectLayer::clip_shape_bounds() const {
return clip_shape();
}
if (!UsesSaveLayer()) {
PaintChildren(context);
return;
}
void ClipRectLayer::OnMutatorsStackPushClipShape(
MutatorsStack& mutators_stack) {
mutators_stack.PushClipRect(clip_shape());
}
AutoCachePaint cache_paint(context);
TRACE_EVENT0("flutter", "Canvas::saveLayer");
context.internal_nodes_canvas->saveLayer(clip_rect_, cache_paint.paint());
PaintChildren(context);
context.internal_nodes_canvas->restore();
if (context.checkerboard_offscreen_layers) {
DrawCheckerboard(context.internal_nodes_canvas, clip_rect_);
}
void ClipRectLayer::OnCanvasClipShape(SkCanvas* canvas) const {
canvas->clipRect(clip_shape(), clip_behavior() != Clip::hardEdge);
}
} // namespace flutter

View File

@ -5,27 +5,26 @@
#ifndef FLUTTER_FLOW_LAYERS_CLIP_RECT_LAYER_H_
#define FLUTTER_FLOW_LAYERS_CLIP_RECT_LAYER_H_
#include "flutter/flow/layers/container_layer.h"
#include "flutter/flow/layers/clip_shape_layer.h"
namespace flutter {
class ClipRectLayer : public ContainerLayer {
class ClipRectLayer : public ClipShapeLayer<SkRect> {
public:
ClipRectLayer(const SkRect& clip_rect, Clip clip_behavior);
void Diff(DiffContext* context, const Layer* old_layer) override;
void Preroll(PrerollContext* context, const SkMatrix& matrix) override;
void Paint(PaintContext& context) const override;
bool UsesSaveLayer() const {
return clip_behavior_ == Clip::antiAliasWithSaveLayer;
}
protected:
const SkRect& clip_shape_bounds() const override;
void OnMutatorsStackPushClipShape(MutatorsStack& mutators_stack) override;
void OnCanvasClipShape(SkCanvas* canvas) const override;
private:
SkRect clip_rect_;
Clip clip_behavior_;
FML_DISALLOW_COPY_AND_ASSIGN(ClipRectLayer);
};

View File

@ -431,6 +431,8 @@ TEST_F(ClipRectLayerTest, OpacityInheritanceSaveLayerPainting) {
auto mock1 = MockLayer::MakeOpacityCompatible(path1);
auto path2 = SkPath().addRect({20, 20, 40, 40});
auto mock2 = MockLayer::MakeOpacityCompatible(path2);
auto children_bounds = path1.getBounds();
children_bounds.join(path2.getBounds());
SkRect clip_rect = SkRect::MakeWH(500, 500);
auto clip_rect_layer =
std::make_shared<ClipRectLayer>(clip_rect, Clip::antiAliasWithSaveLayer);
@ -466,7 +468,7 @@ TEST_F(ClipRectLayerTest, OpacityInheritanceSaveLayerPainting) {
expected_builder.save();
expected_builder.clipRect(clip_rect, SkClipOp::kIntersect, true);
expected_builder.setColor(opacity_alpha << 24);
expected_builder.saveLayer(&clip_rect, true);
expected_builder.saveLayer(&children_bounds, true);
/* child layer1 paint */ {
expected_builder.setColor(0xFF000000);
expected_builder.drawPath(path1);

View File

@ -3,86 +3,33 @@
// found in the LICENSE file.
#include "flutter/flow/layers/clip_rrect_layer.h"
#include "flutter/flow/paint_utils.h"
namespace flutter {
ClipRRectLayer::ClipRRectLayer(const SkRRect& clip_rrect, Clip clip_behavior)
: clip_rrect_(clip_rrect), clip_behavior_(clip_behavior) {
FML_DCHECK(clip_behavior != Clip::none);
}
void ClipRRectLayer::Diff(DiffContext* context, const Layer* old_layer) {
DiffContext::AutoSubtreeRestore subtree(context);
auto* prev = static_cast<const ClipRRectLayer*>(old_layer);
if (!context->IsSubtreeDirty()) {
FML_DCHECK(prev);
if (clip_behavior_ != prev->clip_behavior_ ||
clip_rrect_ != prev->clip_rrect_) {
context->MarkSubtreeDirty(context->GetOldLayerPaintRegion(old_layer));
}
}
if (context->PushCullRect(clip_rrect_.getBounds())) {
DiffChildren(context, prev);
}
context->SetLayerPaintRegion(this, context->CurrentSubtreeRegion());
}
: ClipShapeLayer(clip_rrect, clip_behavior) {}
void ClipRRectLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
TRACE_EVENT0("flutter", "ClipRRectLayer::Preroll");
SkRect previous_cull_rect = context->cull_rect;
SkRect clip_rrect_bounds = clip_rrect_.getBounds();
if (!context->cull_rect.intersect(clip_rrect_bounds)) {
context->cull_rect.setEmpty();
}
Layer::AutoPrerollSaveLayerState save =
Layer::AutoPrerollSaveLayerState::Create(context, UsesSaveLayer());
context->mutators_stack.PushClipRRect(clip_rrect_);
// Collect inheritance information on our children in Preroll so that
// we can pass it along by default.
context->subtree_can_inherit_opacity = true;
SkRect child_paint_bounds = SkRect::MakeEmpty();
PrerollChildren(context, matrix, &child_paint_bounds);
if (child_paint_bounds.intersect(clip_rrect_bounds)) {
set_paint_bounds(child_paint_bounds);
}
// If we use a SaveLayer then we can accept opacity on behalf
// of our children and apply it in the saveLayer.
if (UsesSaveLayer()) {
context->subtree_can_inherit_opacity = true;
}
context->mutators_stack.Pop();
context->cull_rect = previous_cull_rect;
ClipShapeLayer::Preroll(context, matrix);
}
void ClipRRectLayer::Paint(PaintContext& context) const {
TRACE_EVENT0("flutter", "ClipRRectLayer::Paint");
FML_DCHECK(needs_painting(context));
ClipShapeLayer::Paint(context);
}
SkAutoCanvasRestore save(context.internal_nodes_canvas, true);
context.internal_nodes_canvas->clipRRect(clip_rrect_,
clip_behavior_ != Clip::hardEdge);
const SkRect& ClipRRectLayer::clip_shape_bounds() const {
return clip_shape().getBounds();
}
if (!UsesSaveLayer()) {
PaintChildren(context);
return;
}
void ClipRRectLayer::OnMutatorsStackPushClipShape(
MutatorsStack& mutators_stack) {
mutators_stack.PushClipRRect(clip_shape());
}
AutoCachePaint cache_paint(context);
TRACE_EVENT0("flutter", "Canvas::saveLayer");
context.internal_nodes_canvas->saveLayer(paint_bounds(), cache_paint.paint());
PaintChildren(context);
context.internal_nodes_canvas->restore();
if (context.checkerboard_offscreen_layers) {
DrawCheckerboard(context.internal_nodes_canvas, paint_bounds());
}
void ClipRRectLayer::OnCanvasClipShape(SkCanvas* canvas) const {
canvas->clipRRect(clip_shape(), clip_behavior() != Clip::hardEdge);
}
} // namespace flutter

View File

@ -5,28 +5,26 @@
#ifndef FLUTTER_FLOW_LAYERS_CLIP_RRECT_LAYER_H_
#define FLUTTER_FLOW_LAYERS_CLIP_RRECT_LAYER_H_
#include "flutter/flow/layers/container_layer.h"
#include "flutter/flow/layers/clip_shape_layer.h"
namespace flutter {
class ClipRRectLayer : public ContainerLayer {
class ClipRRectLayer : public ClipShapeLayer<SkRRect> {
public:
ClipRRectLayer(const SkRRect& clip_rrect, Clip clip_behavior);
void Diff(DiffContext* context, const Layer* old_layer) override;
void Preroll(PrerollContext* context, const SkMatrix& matrix) override;
void Paint(PaintContext& context) const override;
bool UsesSaveLayer() const {
return clip_behavior_ == Clip::antiAliasWithSaveLayer;
}
protected:
const SkRect& clip_shape_bounds() const override;
void OnMutatorsStackPushClipShape(MutatorsStack& mutators_stack) override;
void OnCanvasClipShape(SkCanvas* canvas) const override;
private:
SkRRect clip_rrect_;
Clip clip_behavior_;
FML_DISALLOW_COPY_AND_ASSIGN(ClipRRectLayer);
};

View File

@ -0,0 +1,113 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_FLOW_LAYERS_CLIP_SHAPE_LAYER_H_
#define FLUTTER_FLOW_LAYERS_CLIP_SHAPE_LAYER_H_
#include "flutter/flow/layers/container_layer.h"
#include "flutter/flow/paint_utils.h"
namespace flutter {
template <class T>
class ClipShapeLayer : public ContainerLayer {
public:
using ClipShape = T;
ClipShapeLayer(const ClipShape& clip_shape, Clip clip_behavior)
: clip_shape_(clip_shape), clip_behavior_(clip_behavior) {
FML_DCHECK(clip_behavior != Clip::none);
}
void Diff(DiffContext* context, const Layer* old_layer) override {
DiffContext::AutoSubtreeRestore subtree(context);
auto* prev = static_cast<const ClipShapeLayer<ClipShape>*>(old_layer);
if (!context->IsSubtreeDirty()) {
FML_DCHECK(prev);
if (clip_behavior_ != prev->clip_behavior_ ||
clip_shape_ != prev->clip_shape_) {
context->MarkSubtreeDirty(context->GetOldLayerPaintRegion(old_layer));
}
}
if (context->PushCullRect(clip_shape_bounds())) {
DiffChildren(context, prev);
}
context->SetLayerPaintRegion(this, context->CurrentSubtreeRegion());
}
void Preroll(PrerollContext* context, const SkMatrix& matrix) override {
SkRect previous_cull_rect = context->cull_rect;
if (!context->cull_rect.intersect(clip_shape_bounds())) {
context->cull_rect.setEmpty();
}
Layer::AutoPrerollSaveLayerState save =
Layer::AutoPrerollSaveLayerState::Create(context, UsesSaveLayer());
OnMutatorsStackPushClipShape(context->mutators_stack);
// Collect inheritance information on our children in Preroll so that
// we can pass it along by default.
context->subtree_can_inherit_opacity = true;
SkRect child_paint_bounds = SkRect::MakeEmpty();
PrerollChildren(context, matrix, &child_paint_bounds);
if (child_paint_bounds.intersect(clip_shape_bounds())) {
set_paint_bounds(child_paint_bounds);
}
// If we use a SaveLayer then we can accept opacity on behalf
// of our children and apply it in the saveLayer.
if (UsesSaveLayer()) {
context->subtree_can_inherit_opacity = true;
}
context->mutators_stack.Pop();
context->cull_rect = previous_cull_rect;
}
void Paint(PaintContext& context) const override {
FML_DCHECK(needs_painting(context));
SkAutoCanvasRestore save(context.internal_nodes_canvas, true);
OnCanvasClipShape(context.internal_nodes_canvas);
if (!UsesSaveLayer()) {
PaintChildren(context);
return;
}
AutoCachePaint cache_paint(context);
TRACE_EVENT0("flutter", "Canvas::saveLayer");
context.internal_nodes_canvas->saveLayer(paint_bounds(),
cache_paint.paint());
PaintChildren(context);
context.internal_nodes_canvas->restore();
if (context.checkerboard_offscreen_layers) {
DrawCheckerboard(context.internal_nodes_canvas, paint_bounds());
}
}
bool UsesSaveLayer() const {
return clip_behavior_ == Clip::antiAliasWithSaveLayer;
}
protected:
virtual const SkRect& clip_shape_bounds() const = 0;
virtual void OnMutatorsStackPushClipShape(MutatorsStack& mutators_stack) = 0;
virtual void OnCanvasClipShape(SkCanvas* canvas) const = 0;
virtual ~ClipShapeLayer() = default;
const ClipShape& clip_shape() const { return clip_shape_; }
Clip clip_behavior() const { return clip_behavior_; }
private:
const ClipShape clip_shape_;
Clip clip_behavior_;
FML_DISALLOW_COPY_AND_ASSIGN(ClipShapeLayer);
};
} // namespace flutter
#endif // FLUTTER_FLOW_LAYERS_CLIP_SHAPE_LAYER_H_