mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
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
70 lines
2.1 KiB
C++
70 lines
2.1 KiB
C++
// 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.
|
|
|
|
#include "flutter/flow/layers/clip_path_layer.h"
|
|
|
|
#if defined(OS_FUCHSIA)
|
|
|
|
#include "lib/ui/scenic/cpp/commands.h"
|
|
|
|
#endif // defined(OS_FUCHSIA)
|
|
|
|
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::Preroll(PrerollContext* context, const SkMatrix& matrix) {
|
|
SkRect previous_cull_rect = context->cull_rect;
|
|
SkRect clip_path_bounds = clip_path_.getBounds();
|
|
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);
|
|
|
|
if (child_paint_bounds.intersect(clip_path_bounds)) {
|
|
set_paint_bounds(child_paint_bounds);
|
|
}
|
|
context->mutators_stack.Pop();
|
|
}
|
|
context->cull_rect = previous_cull_rect;
|
|
}
|
|
|
|
#if defined(OS_FUCHSIA)
|
|
|
|
void ClipPathLayer::UpdateScene(SceneUpdateContext& context) {
|
|
FML_DCHECK(needs_system_composite());
|
|
|
|
// TODO(liyuqian): respect clip_behavior_
|
|
SceneUpdateContext::Clip clip(context, clip_path_.getBounds());
|
|
UpdateSceneChildren(context);
|
|
}
|
|
|
|
#endif // defined(OS_FUCHSIA)
|
|
|
|
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);
|
|
|
|
if (clip_behavior_ == Clip::antiAliasWithSaveLayer) {
|
|
context.internal_nodes_canvas->saveLayer(paint_bounds(), nullptr);
|
|
}
|
|
PaintChildren(context);
|
|
if (clip_behavior_ == Clip::antiAliasWithSaveLayer) {
|
|
context.internal_nodes_canvas->restore();
|
|
}
|
|
}
|
|
|
|
} // namespace flutter
|