mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Fixed ChildSceneLayer elevation issue on Fuchsia. (flutter/engine#18144)
* Fixed ChildSceneLayer elevation issue on Fuchsia. ChildSceneLayers would draw on top of stacked Flutter content on Fuchsia if not wrapped up in a Material widget, i.e. a PhysicalShapeLayer. This patch pushes the logic from there to all types of Layers.
This commit is contained in:
parent
b1b1cea351
commit
4271b2a33e
@ -20,6 +20,9 @@ ChildSceneLayer::ChildSceneLayer(zx_koid_t layer_id,
|
||||
void ChildSceneLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
|
||||
TRACE_EVENT0("flutter", "ChildSceneLayer::Preroll");
|
||||
set_needs_system_composite(true);
|
||||
|
||||
CheckForChildLayerBelow(context);
|
||||
|
||||
context->child_scene_layer_exists_below = true;
|
||||
|
||||
// An alpha "hole punch" is required if the frame behind us is not opaque.
|
||||
@ -47,6 +50,8 @@ void ChildSceneLayer::UpdateScene(SceneUpdateContext& context) {
|
||||
TRACE_EVENT0("flutter", "ChildSceneLayer::UpdateScene");
|
||||
FML_DCHECK(needs_system_composite());
|
||||
|
||||
Layer::UpdateScene(context);
|
||||
|
||||
auto* view_holder = ViewHolder::FromId(layer_id_);
|
||||
FML_DCHECK(view_holder);
|
||||
|
||||
|
||||
@ -29,6 +29,11 @@ void ContainerLayer::Paint(PaintContext& context) const {
|
||||
void ContainerLayer::PrerollChildren(PrerollContext* context,
|
||||
const SkMatrix& child_matrix,
|
||||
SkRect* child_paint_bounds) {
|
||||
#if defined(OS_FUCHSIA)
|
||||
child_layer_exists_below_ = context->child_scene_layer_exists_below;
|
||||
context->child_scene_layer_exists_below = false;
|
||||
#endif
|
||||
|
||||
// Platform views have no children, so context->has_platform_view should
|
||||
// always be false.
|
||||
FML_DCHECK(!context->has_platform_view);
|
||||
@ -51,6 +56,14 @@ void ContainerLayer::PrerollChildren(PrerollContext* context,
|
||||
}
|
||||
|
||||
context->has_platform_view = child_has_platform_view;
|
||||
|
||||
#if defined(OS_FUCHSIA)
|
||||
if (child_layer_exists_below_) {
|
||||
set_needs_system_composite(true);
|
||||
}
|
||||
context->child_scene_layer_exists_below =
|
||||
context->child_scene_layer_exists_below || child_layer_exists_below_;
|
||||
#endif
|
||||
}
|
||||
|
||||
void ContainerLayer::PaintChildren(PaintContext& context) const {
|
||||
@ -67,19 +80,72 @@ void ContainerLayer::PaintChildren(PaintContext& context) const {
|
||||
|
||||
#if defined(OS_FUCHSIA)
|
||||
|
||||
void ContainerLayer::CheckForChildLayerBelow(PrerollContext* context) {
|
||||
// All ContainerLayers make the check in PrerollChildren.
|
||||
}
|
||||
|
||||
void ContainerLayer::UpdateScene(SceneUpdateContext& context) {
|
||||
UpdateSceneChildren(context);
|
||||
}
|
||||
|
||||
void ContainerLayer::UpdateSceneChildren(SceneUpdateContext& context) {
|
||||
auto update_scene_layers = [&] {
|
||||
// Paint all of the layers which need to be drawn into the container.
|
||||
// These may be flattened down to a containing Scenic Frame.
|
||||
for (auto& layer : layers_) {
|
||||
if (layer->needs_system_composite()) {
|
||||
layer->UpdateScene(context);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
FML_DCHECK(needs_system_composite());
|
||||
|
||||
// Paint all of the layers which need to be drawn into the container.
|
||||
// These may be flattened down to a containing
|
||||
for (auto& layer : layers_) {
|
||||
if (layer->needs_system_composite()) {
|
||||
layer->UpdateScene(context);
|
||||
// If there is embedded Fuchsia content in the scene (a ChildSceneLayer),
|
||||
// PhysicalShapeLayers that appear above the embedded content will be turned
|
||||
// into their own Scenic layers.
|
||||
if (child_layer_exists_below_) {
|
||||
float global_scenic_elevation =
|
||||
context.GetGlobalElevationForNextScenicLayer();
|
||||
float local_scenic_elevation =
|
||||
global_scenic_elevation - context.scenic_elevation();
|
||||
float z_translation = -local_scenic_elevation;
|
||||
|
||||
// Retained rendering: speedup by reusing a retained entity node if
|
||||
// possible. When an entity node is reused, no paint layer is added to the
|
||||
// frame so we won't call PhysicalShapeLayer::Paint.
|
||||
LayerRasterCacheKey key(unique_id(), context.Matrix());
|
||||
if (context.HasRetainedNode(key)) {
|
||||
TRACE_EVENT_INSTANT0("flutter", "retained layer cache hit");
|
||||
scenic::EntityNode* retained_node = context.GetRetainedNode(key);
|
||||
FML_DCHECK(context.top_entity());
|
||||
FML_DCHECK(retained_node->session() == context.session());
|
||||
|
||||
// Re-adjust the elevation.
|
||||
retained_node->SetTranslation(0.f, 0.f, z_translation);
|
||||
|
||||
context.top_entity()->entity_node().AddChild(*retained_node);
|
||||
return;
|
||||
}
|
||||
|
||||
TRACE_EVENT_INSTANT0("flutter", "cache miss, creating");
|
||||
// If we can't find an existing retained surface, create one.
|
||||
SceneUpdateContext::Frame frame(
|
||||
context, SkRRect::MakeRect(paint_bounds()), SK_ColorTRANSPARENT,
|
||||
SkScalarRoundToInt(context.alphaf() * 255),
|
||||
"flutter::PhysicalShapeLayer", z_translation, this);
|
||||
|
||||
frame.AddPaintLayer(this);
|
||||
|
||||
// Node: UpdateSceneChildren needs to be called here so that |frame| is
|
||||
// still in scope (and therefore alive) while UpdateSceneChildren is being
|
||||
// called.
|
||||
float scenic_elevation = context.scenic_elevation();
|
||||
context.set_scenic_elevation(scenic_elevation + local_scenic_elevation);
|
||||
update_scene_layers();
|
||||
context.set_scenic_elevation(scenic_elevation);
|
||||
} else {
|
||||
update_scene_layers();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -19,6 +19,7 @@ class ContainerLayer : public Layer {
|
||||
void Preroll(PrerollContext* context, const SkMatrix& matrix) override;
|
||||
void Paint(PaintContext& context) const override;
|
||||
#if defined(OS_FUCHSIA)
|
||||
void CheckForChildLayerBelow(PrerollContext* context) override;
|
||||
void UpdateScene(SceneUpdateContext& context) override;
|
||||
#endif // defined(OS_FUCHSIA)
|
||||
|
||||
|
||||
@ -56,7 +56,53 @@ Layer::AutoPrerollSaveLayerState::~AutoPrerollSaveLayerState() {
|
||||
}
|
||||
|
||||
#if defined(OS_FUCHSIA)
|
||||
void Layer::UpdateScene(SceneUpdateContext& context) {}
|
||||
|
||||
void Layer::CheckForChildLayerBelow(PrerollContext* context) {
|
||||
child_layer_exists_below_ = context->child_scene_layer_exists_below;
|
||||
if (child_layer_exists_below_) {
|
||||
set_needs_system_composite(true);
|
||||
}
|
||||
}
|
||||
|
||||
void Layer::UpdateScene(SceneUpdateContext& context) {
|
||||
// If there is embedded Fuchsia content in the scene (a ChildSceneLayer),
|
||||
// PhysicalShapeLayers that appear above the embedded content will be turned
|
||||
// into their own Scenic layers.
|
||||
if (child_layer_exists_below_) {
|
||||
float global_scenic_elevation =
|
||||
context.GetGlobalElevationForNextScenicLayer();
|
||||
float local_scenic_elevation =
|
||||
global_scenic_elevation - context.scenic_elevation();
|
||||
float z_translation = -local_scenic_elevation;
|
||||
|
||||
// Retained rendering: speedup by reusing a retained entity node if
|
||||
// possible. When an entity node is reused, no paint layer is added to the
|
||||
// frame so we won't call PhysicalShapeLayer::Paint.
|
||||
LayerRasterCacheKey key(unique_id(), context.Matrix());
|
||||
if (context.HasRetainedNode(key)) {
|
||||
TRACE_EVENT_INSTANT0("flutter", "retained layer cache hit");
|
||||
scenic::EntityNode* retained_node = context.GetRetainedNode(key);
|
||||
FML_DCHECK(context.top_entity());
|
||||
FML_DCHECK(retained_node->session() == context.session());
|
||||
|
||||
// Re-adjust the elevation.
|
||||
retained_node->SetTranslation(0.f, 0.f, z_translation);
|
||||
|
||||
context.top_entity()->entity_node().AddChild(*retained_node);
|
||||
return;
|
||||
}
|
||||
|
||||
TRACE_EVENT_INSTANT0("flutter", "cache miss, creating");
|
||||
// If we can't find an existing retained surface, create one.
|
||||
SceneUpdateContext::Frame frame(
|
||||
context, SkRRect::MakeRect(paint_bounds()), SK_ColorTRANSPARENT,
|
||||
SkScalarRoundToInt(context.alphaf() * 255),
|
||||
"flutter::PhysicalShapeLayer", z_translation, this);
|
||||
|
||||
frame.AddPaintLayer(this);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // defined(OS_FUCHSIA)
|
||||
|
||||
Layer::AutoSaveLayer::AutoSaveLayer(const PaintContext& paint_context,
|
||||
|
||||
@ -165,6 +165,7 @@ class Layer {
|
||||
#if defined(OS_FUCHSIA)
|
||||
// Updates the system composited scene.
|
||||
virtual void UpdateScene(SceneUpdateContext& context);
|
||||
virtual void CheckForChildLayerBelow(PrerollContext* context);
|
||||
#endif
|
||||
|
||||
bool needs_system_composite() const { return needs_system_composite_; }
|
||||
@ -184,6 +185,11 @@ class Layer {
|
||||
|
||||
uint64_t unique_id() const { return unique_id_; }
|
||||
|
||||
protected:
|
||||
#if defined(OS_FUCHSIA)
|
||||
bool child_layer_exists_below_ = false;
|
||||
#endif
|
||||
|
||||
private:
|
||||
SkRect paint_bounds_;
|
||||
uint64_t unique_id_;
|
||||
|
||||
@ -52,21 +52,10 @@ void PhysicalShapeLayer::Preroll(PrerollContext* context,
|
||||
|
||||
context->total_elevation += elevation_;
|
||||
total_elevation_ = context->total_elevation;
|
||||
#if defined(OS_FUCHSIA)
|
||||
child_layer_exists_below_ = context->child_scene_layer_exists_below;
|
||||
context->child_scene_layer_exists_below = false;
|
||||
#endif
|
||||
|
||||
SkRect child_paint_bounds;
|
||||
PrerollChildren(context, matrix, &child_paint_bounds);
|
||||
|
||||
#if defined(OS_FUCHSIA)
|
||||
if (child_layer_exists_below_) {
|
||||
set_needs_system_composite(true);
|
||||
}
|
||||
context->child_scene_layer_exists_below =
|
||||
context->child_scene_layer_exists_below || child_layer_exists_below_;
|
||||
#endif
|
||||
context->total_elevation -= elevation_;
|
||||
|
||||
if (elevation_ == 0) {
|
||||
@ -80,62 +69,6 @@ void PhysicalShapeLayer::Preroll(PrerollContext* context,
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(OS_FUCHSIA)
|
||||
|
||||
void PhysicalShapeLayer::UpdateScene(SceneUpdateContext& context) {
|
||||
FML_DCHECK(needs_system_composite());
|
||||
TRACE_EVENT0("flutter", "PhysicalShapeLayer::UpdateScene");
|
||||
|
||||
// If there is embedded Fuchsia content in the scene (a ChildSceneLayer),
|
||||
// PhysicalShapeLayers that appear above the embedded content will be turned
|
||||
// into their own Scenic layers.
|
||||
if (child_layer_exists_below_) {
|
||||
float global_scenic_elevation =
|
||||
context.GetGlobalElevationForNextScenicLayer();
|
||||
float local_scenic_elevation =
|
||||
global_scenic_elevation - context.scenic_elevation();
|
||||
float z_translation = -local_scenic_elevation;
|
||||
|
||||
// Retained rendering: speedup by reusing a retained entity node if
|
||||
// possible. When an entity node is reused, no paint layer is added to the
|
||||
// frame so we won't call PhysicalShapeLayer::Paint.
|
||||
LayerRasterCacheKey key(unique_id(), context.Matrix());
|
||||
if (context.HasRetainedNode(key)) {
|
||||
TRACE_EVENT_INSTANT0("flutter", "retained layer cache hit");
|
||||
scenic::EntityNode* retained_node = context.GetRetainedNode(key);
|
||||
FML_DCHECK(context.top_entity());
|
||||
FML_DCHECK(retained_node->session() == context.session());
|
||||
|
||||
// Re-adjust the elevation.
|
||||
retained_node->SetTranslation(0.f, 0.f, z_translation);
|
||||
|
||||
context.top_entity()->entity_node().AddChild(*retained_node);
|
||||
return;
|
||||
}
|
||||
|
||||
TRACE_EVENT_INSTANT0("flutter", "cache miss, creating");
|
||||
// If we can't find an existing retained surface, create one.
|
||||
SceneUpdateContext::Frame frame(context, frameRRect_, SK_ColorTRANSPARENT,
|
||||
SkScalarRoundToInt(context.alphaf() * 255),
|
||||
"flutter::PhysicalShapeLayer",
|
||||
z_translation, this);
|
||||
|
||||
frame.AddPaintLayer(this);
|
||||
|
||||
// Node: UpdateSceneChildren needs to be called here so that |frame| is
|
||||
// still in scope (and therefore alive) while UpdateSceneChildren is being
|
||||
// called.
|
||||
float scenic_elevation = context.scenic_elevation();
|
||||
context.set_scenic_elevation(scenic_elevation + local_scenic_elevation);
|
||||
ContainerLayer::UpdateSceneChildren(context);
|
||||
context.set_scenic_elevation(scenic_elevation);
|
||||
} else {
|
||||
ContainerLayer::UpdateSceneChildren(context);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // defined(OS_FUCHSIA)
|
||||
|
||||
void PhysicalShapeLayer::Paint(PaintContext& context) const {
|
||||
TRACE_EVENT0("flutter", "PhysicalShapeLayer::Paint");
|
||||
FML_DCHECK(needs_painting());
|
||||
|
||||
@ -35,16 +35,9 @@ class PhysicalShapeLayer : public ContainerLayer {
|
||||
return clip_behavior_ == Clip::antiAliasWithSaveLayer;
|
||||
}
|
||||
|
||||
#if defined(OS_FUCHSIA)
|
||||
void UpdateScene(SceneUpdateContext& context) override;
|
||||
#endif // defined(OS_FUCHSIA)
|
||||
|
||||
float total_elevation() const { return total_elevation_; }
|
||||
|
||||
private:
|
||||
#if defined(OS_FUCHSIA)
|
||||
bool child_layer_exists_below_ = false;
|
||||
#endif
|
||||
SkColor color_;
|
||||
SkColor shadow_color_;
|
||||
float elevation_ = 0.0f;
|
||||
|
||||
@ -19,6 +19,11 @@ PictureLayer::PictureLayer(const SkPoint& offset,
|
||||
|
||||
void PictureLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
|
||||
TRACE_EVENT0("flutter", "PictureLayer::Preroll");
|
||||
|
||||
#if defined(OS_FUCHSIA)
|
||||
CheckForChildLayerBelow(context);
|
||||
#endif
|
||||
|
||||
SkPicture* sk_picture = picture();
|
||||
|
||||
if (auto* cache = context->raster_cache) {
|
||||
|
||||
@ -13,6 +13,10 @@ PlatformViewLayer::PlatformViewLayer(const SkPoint& offset,
|
||||
|
||||
void PlatformViewLayer::Preroll(PrerollContext* context,
|
||||
const SkMatrix& matrix) {
|
||||
#if defined(OS_FUCHSIA)
|
||||
CheckForChildLayerBelow(context);
|
||||
#endif
|
||||
|
||||
set_paint_bounds(SkRect::MakeXYWH(offset_.x(), offset_.y(), size_.width(),
|
||||
size_.height()));
|
||||
|
||||
|
||||
@ -12,6 +12,10 @@ ShaderMaskLayer::ShaderMaskLayer(sk_sp<SkShader> shader,
|
||||
: shader_(shader), mask_rect_(mask_rect), blend_mode_(blend_mode) {}
|
||||
|
||||
void ShaderMaskLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
|
||||
#if defined(OS_FUCHSIA)
|
||||
CheckForChildLayerBelow(context);
|
||||
#endif
|
||||
|
||||
Layer::AutoPrerollSaveLayerState save =
|
||||
Layer::AutoPrerollSaveLayerState::Create(context);
|
||||
ContainerLayer::Preroll(context, matrix);
|
||||
|
||||
@ -17,6 +17,10 @@ TextureLayer::TextureLayer(const SkPoint& offset,
|
||||
void TextureLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
|
||||
TRACE_EVENT0("flutter", "TextureLayer::Preroll");
|
||||
|
||||
#if defined(OS_FUCHSIA)
|
||||
CheckForChildLayerBelow(context);
|
||||
#endif
|
||||
|
||||
set_paint_bounds(SkRect::MakeXYWH(offset_.x(), offset_.y(), size_.width(),
|
||||
size_.height()));
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user