Do not paint a layer's children if the children were not prerolled (#14149)

Prerolling a layer can have side effects.  In particular, PlatformViewLayer::Preroll
will call view_embedder->PrerollCompositeEmbeddedView.

Clip layers will check whether the layer's children are all clipped and if so
will skip calling Preroll on the children.  However, the Paint implementation in
these layers was always calling Paint on their children.

This could result in a call to PlatformViewLayer::Paint without a corresponding
call to PlatformViewLayer::Preroll.  This translates to a CompositeEmbeddedView
call without a PrerollCompositeEmbeddedView call on the affected view_id.
The EmbedderExternalViewEmbedder implementation does not allow that.

With this change, clip layers will only call PaintChildren if the preroll
called PrerollChildren.

See https://github.com/flutter/flutter/issues/46111
This commit is contained in:
Jason Simmons
2019-12-05 16:25:55 -08:00
committed by GitHub
parent 3ad666248c
commit af511babc7
6 changed files with 18 additions and 3 deletions
+5 -1
View File
@@ -20,7 +20,8 @@ ClipPathLayer::ClipPathLayer(const SkPath& clip_path, Clip clip_behavior)
void ClipPathLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
SkRect previous_cull_rect = context->cull_rect;
SkRect clip_path_bounds = clip_path_.getBounds();
if (context->cull_rect.intersect(clip_path_bounds)) {
children_inside_clip_ = context->cull_rect.intersect(clip_path_bounds);
if (children_inside_clip_) {
context->mutators_stack.PushClipPath(clip_path_);
SkRect child_paint_bounds = SkRect::MakeEmpty();
PrerollChildren(context, matrix, &child_paint_bounds);
@@ -49,6 +50,9 @@ void ClipPathLayer::Paint(PaintContext& context) const {
TRACE_EVENT0("flutter", "ClipPathLayer::Paint");
FML_DCHECK(needs_painting());
if (!children_inside_clip_)
return;
SkAutoCanvasRestore save(context.internal_nodes_canvas, true);
context.internal_nodes_canvas->clipPath(clip_path_,
clip_behavior_ != Clip::hardEdge);
+1
View File
@@ -24,6 +24,7 @@ class ClipPathLayer : public ContainerLayer {
private:
SkPath clip_path_;
Clip clip_behavior_;
bool children_inside_clip_ = false;
FML_DISALLOW_COPY_AND_ASSIGN(ClipPathLayer);
};
+5 -1
View File
@@ -13,7 +13,8 @@ ClipRectLayer::ClipRectLayer(const SkRect& clip_rect, Clip clip_behavior)
void ClipRectLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
SkRect previous_cull_rect = context->cull_rect;
if (context->cull_rect.intersect(clip_rect_)) {
children_inside_clip_ = context->cull_rect.intersect(clip_rect_);
if (children_inside_clip_) {
context->mutators_stack.PushClipRect(clip_rect_);
SkRect child_paint_bounds = SkRect::MakeEmpty();
PrerollChildren(context, matrix, &child_paint_bounds);
@@ -42,6 +43,9 @@ void ClipRectLayer::Paint(PaintContext& context) const {
TRACE_EVENT0("flutter", "ClipRectLayer::Paint");
FML_DCHECK(needs_painting());
if (!children_inside_clip_)
return;
SkAutoCanvasRestore save(context.internal_nodes_canvas, true);
context.internal_nodes_canvas->clipRect(clip_rect_,
clip_behavior_ != Clip::hardEdge);
+1
View File
@@ -23,6 +23,7 @@ class ClipRectLayer : public ContainerLayer {
private:
SkRect clip_rect_;
Clip clip_behavior_;
bool children_inside_clip_ = false;
FML_DISALLOW_COPY_AND_ASSIGN(ClipRectLayer);
};
+5 -1
View File
@@ -14,7 +14,8 @@ ClipRRectLayer::ClipRRectLayer(const SkRRect& clip_rrect, Clip clip_behavior)
void ClipRRectLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
SkRect previous_cull_rect = context->cull_rect;
SkRect clip_rrect_bounds = clip_rrect_.getBounds();
if (context->cull_rect.intersect(clip_rrect_bounds)) {
children_inside_clip_ = context->cull_rect.intersect(clip_rrect_bounds);
if (children_inside_clip_) {
context->mutators_stack.PushClipRRect(clip_rrect_);
SkRect child_paint_bounds = SkRect::MakeEmpty();
PrerollChildren(context, matrix, &child_paint_bounds);
@@ -43,6 +44,9 @@ void ClipRRectLayer::Paint(PaintContext& context) const {
TRACE_EVENT0("flutter", "ClipRRectLayer::Paint");
FML_DCHECK(needs_painting());
if (!children_inside_clip_)
return;
SkAutoCanvasRestore save(context.internal_nodes_canvas, true);
context.internal_nodes_canvas->clipRRect(clip_rrect_,
clip_behavior_ != Clip::hardEdge);
+1
View File
@@ -24,6 +24,7 @@ class ClipRRectLayer : public ContainerLayer {
private:
SkRRect clip_rrect_;
Clip clip_behavior_;
bool children_inside_clip_ = false;
FML_DISALLOW_COPY_AND_ASSIGN(ClipRRectLayer);
};