Commit 164615a5 authored by Collin Baker's avatar Collin Baker Committed by Commit Bot

Handle layers beneath views in WindowReorderer

Layers added beneath views weren't handled in
WindowReorderer::ReorderChildWindows(). When this method was called,
any layers beneath would end up incorrectly stacked above all other
sibling layers. This bug surfaced recently with an ink drop painting
above its view.

This CL exposes a View method that returns all layers associated with
it that should be immediate children of its parent.
ReorderChildWindows() is modified to call this instead of simply
restacking the view's main layer.

Bug: 973243
Change-Id: I65b5a3266bbe20afe9adb5db4acf709c6c506b16
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1663037
Commit-Queue: Collin Baker <collinbaker@chromium.org>
Reviewed-by: default avatarScott Violet <sky@chromium.org>
Cr-Commit-Position: refs/heads/master@{#670144}
parent b8b37fac
...@@ -581,6 +581,20 @@ void View::RemoveLayerBeneathView(ui::Layer* old_layer) { ...@@ -581,6 +581,20 @@ void View::RemoveLayerBeneathView(ui::Layer* old_layer) {
CreateOrDestroyLayer(); CreateOrDestroyLayer();
} }
std::vector<ui::Layer*> View::GetLayersInOrder() {
// If not painting to a layer, there are no layers immediately related to this
// view.
if (!layer())
return {};
std::vector<ui::Layer*> result;
for (ui::Layer* layer_beneath : layers_beneath_)
result.push_back(layer_beneath);
result.push_back(layer());
return result;
}
void View::LayerDestroyed(ui::Layer* layer) { void View::LayerDestroyed(ui::Layer* layer) {
// Only layers added with |AddLayerBeneathView()| are observed so |layer| can // Only layers added with |AddLayerBeneathView()| are observed so |layer| can
// safely be removed. // safely be removed.
......
...@@ -631,6 +631,12 @@ class VIEWS_EXPORT View : public ui::LayerDelegate, ...@@ -631,6 +631,12 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
virtual void AddLayerBeneathView(ui::Layer* new_layer); virtual void AddLayerBeneathView(ui::Layer* new_layer);
virtual void RemoveLayerBeneathView(ui::Layer* old_layer); virtual void RemoveLayerBeneathView(ui::Layer* old_layer);
// Gets the layers associated with this view that should be immediate children
// of the parent layer. They are returned in bottom-to-top order. This
// includes |this->layer()| and any layers added with |AddLayerBeneathView()|.
// Returns an empty vector if this view doesn't paint to a layer.
std::vector<ui::Layer*> GetLayersInOrder();
// ui::LayerObserver: // ui::LayerObserver:
void LayerDestroyed(ui::Layer* layer) override; void LayerDestroyed(ui::Layer* layer) override;
......
...@@ -168,19 +168,24 @@ void WindowReorderer::ReorderChildWindows() { ...@@ -168,19 +168,24 @@ void WindowReorderer::ReorderChildWindows() {
// windows not associated to a view are stacked above windows with an // windows not associated to a view are stacked above windows with an
// associated view. // associated view.
for (View* view : base::Reversed(view_with_layer_order)) { for (View* view : base::Reversed(view_with_layer_order)) {
ui::Layer* layer = view->layer(); std::vector<ui::Layer*> layers;
aura::Window* window = nullptr; aura::Window* window = nullptr;
auto hosted_window_it = hosted_windows.find(view); auto hosted_window_it = hosted_windows.find(view);
if (hosted_window_it != hosted_windows.end()) { if (hosted_window_it != hosted_windows.end()) {
window = hosted_window_it->second; window = hosted_window_it->second;
layer = window->layer(); layers.push_back(window->layer());
} else {
layers = view->GetLayersInOrder();
std::reverse(layers.begin(), layers.end());
} }
DCHECK(layer); DCHECK(!layers.empty());
if (window) if (window)
parent_window_->StackChildAtBottom(window); parent_window_->StackChildAtBottom(window);
children_layer_order.emplace_back(layer);
for (ui::Layer* layer : layers)
children_layer_order.emplace_back(layer);
} }
std::reverse(children_layer_order.begin(), children_layer_order.end()); std::reverse(children_layer_order.begin(), children_layer_order.end());
parent_window_->layer()->StackChildrenAtBottom(children_layer_order); parent_window_->layer()->StackChildrenAtBottom(children_layer_order);
......
...@@ -259,5 +259,43 @@ TEST_F(WindowReordererTest, HostViewParentHasLayer) { ...@@ -259,5 +259,43 @@ TEST_F(WindowReordererTest, HostViewParentHasLayer) {
parent->Close(); parent->Close();
} }
// Test that a layer added beneath a view is restacked correctly.
TEST_F(WindowReordererTest, ViewWithLayerBeneath) {
std::unique_ptr<Widget> parent(
CreateControlWidget(root_window(), gfx::Rect(0, 0, 100, 100)));
parent->Show();
aura::Window* parent_window = parent->GetNativeWindow();
View* contents_view = new View;
parent->SetContentsView(contents_view);
View* view_with_layer_beneath =
contents_view->AddChildView(std::make_unique<View>());
ui::Layer layer_beneath;
view_with_layer_beneath->AddLayerBeneathView(&layer_beneath);
ASSERT_NE(nullptr, view_with_layer_beneath->layer());
view_with_layer_beneath->layer()->set_name("view");
layer_beneath.set_name("beneath");
// Verify that the initial ordering is correct.
EXPECT_EQ("beneath view",
ui::test::ChildLayerNamesAsString(*parent_window->layer()));
// Add a hosted window to make WindowReorderer::ReorderChildWindows() restack
// layers.
std::unique_ptr<Widget> child_widget(
CreateControlWidget(parent_window, gfx::Rect(gfx::Rect(0, 0, 50, 50))));
SetWindowAndLayerName(child_widget->GetNativeView(), "child_widget");
child_widget->Show();
View* host_view = contents_view->AddChildView(std::make_unique<View>());
child_widget->GetNativeView()->SetProperty(kHostViewKey, host_view);
// Verify the new order is correct.
EXPECT_EQ("beneath view child_widget",
ui::test::ChildLayerNamesAsString(*parent_window->layer()));
}
} // namespace } // namespace
} // namespace views } // namespace views
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment