summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ui/aura/window.cc6
-rw-r--r--ui/aura/window.h3
-rw-r--r--ui/views/controls/native/native_view_host_aura.cc8
-rw-r--r--ui/views/controls/native/native_view_host_aura_unittest.cc22
-rw-r--r--ui/views/view.cc28
-rw-r--r--ui/views/view.h6
-rw-r--r--ui/views/view_constants_aura.cc16
-rw-r--r--ui/views/view_constants_aura.h22
-rw-r--r--ui/views/view_unittest.cc63
-rw-r--r--ui/views/views.gyp8
-rw-r--r--ui/views/widget/desktop_aura/desktop_native_widget_aura.cc8
-rw-r--r--ui/views/widget/desktop_aura/desktop_native_widget_aura.h6
-rw-r--r--ui/views/widget/native_widget_aura.cc8
-rw-r--r--ui/views/widget/native_widget_aura.h6
-rw-r--r--ui/views/widget/native_widget_aura_unittest.cc22
-rw-r--r--ui/views/widget/native_widget_private.h9
-rw-r--r--ui/views/widget/native_widget_win.cc3
-rw-r--r--ui/views/widget/native_widget_win.h1
-rw-r--r--ui/views/widget/widget.cc4
-rw-r--r--ui/views/widget/widget.h9
-rw-r--r--ui/views/widget/window_reorderer.cc201
-rw-r--r--ui/views/widget/window_reorderer.h59
-rw-r--r--ui/views/widget/window_reorderer_unittest.cc263
23 files changed, 757 insertions, 24 deletions
diff --git a/ui/aura/window.cc b/ui/aura/window.cc
index c1f7487..5160bf6 100644
--- a/ui/aura/window.cc
+++ b/ui/aura/window.cc
@@ -340,6 +340,12 @@ void Window::StackChildAbove(Window* child, Window* target) {
StackChildRelativeTo(child, target, STACK_ABOVE);
}
+void Window::StackChildAtBottom(Window* child) {
+ if (children_.size() <= 1 || child == children_.front())
+ return; // At the bottom already.
+ StackChildBelow(child, children_.front());
+}
+
void Window::StackChildBelow(Window* child, Window* target) {
StackChildRelativeTo(child, target, STACK_BELOW);
}
diff --git a/ui/aura/window.h b/ui/aura/window.h
index e2c0d83..cd6fa63 100644
--- a/ui/aura/window.h
+++ b/ui/aura/window.h
@@ -175,6 +175,9 @@ class AURA_EXPORT Window : public ui::LayerDelegate,
// see WindowTest.StackingMadrigal for details.
void StackChildAbove(Window* child, Window* target);
+ // Stacks the specified child of this window at the bottom of the z-order.
+ void StackChildAtBottom(Window* child);
+
// Stacks |child| below |target|. Does nothing if |child| is already below
// |target|.
void StackChildBelow(Window* child, Window* target);
diff --git a/ui/views/controls/native/native_view_host_aura.cc b/ui/views/controls/native/native_view_host_aura.cc
index fb8a725..3a3ed14 100644
--- a/ui/views/controls/native/native_view_host_aura.cc
+++ b/ui/views/controls/native/native_view_host_aura.cc
@@ -8,6 +8,7 @@
#include "ui/aura/focus_manager.h"
#include "ui/aura/window.h"
#include "ui/views/controls/native/native_view_host.h"
+#include "ui/views/view_constants_aura.h"
#include "ui/views/widget/widget.h"
namespace views {
@@ -18,18 +19,23 @@ NativeViewHostAura::NativeViewHostAura(NativeViewHost* host)
}
NativeViewHostAura::~NativeViewHostAura() {
- if (host_->native_view())
+ if (host_->native_view()) {
+ host_->native_view()->ClearProperty(views::kHostViewKey);
host_->native_view()->RemoveObserver(this);
+ }
}
////////////////////////////////////////////////////////////////////////////////
// NativeViewHostAura, NativeViewHostWrapper implementation:
void NativeViewHostAura::NativeViewWillAttach() {
host_->native_view()->AddObserver(this);
+ host_->native_view()->SetProperty(views::kHostViewKey,
+ static_cast<View*>(host_));
}
void NativeViewHostAura::NativeViewDetaching(bool destroyed) {
if (!destroyed) {
+ host_->native_view()->ClearProperty(views::kHostViewKey);
host_->native_view()->RemoveObserver(this);
host_->native_view()->Hide();
if (host_->native_view()->parent())
diff --git a/ui/views/controls/native/native_view_host_aura_unittest.cc b/ui/views/controls/native/native_view_host_aura_unittest.cc
index 3099932..7653cc9 100644
--- a/ui/views/controls/native/native_view_host_aura_unittest.cc
+++ b/ui/views/controls/native/native_view_host_aura_unittest.cc
@@ -10,6 +10,7 @@
#include "ui/views/controls/native/native_view_host.h"
#include "ui/views/test/views_test_base.h"
#include "ui/views/view.h"
+#include "ui/views/view_constants_aura.h"
#include "ui/views/widget/widget.h"
namespace views {
@@ -23,6 +24,10 @@ class NativeViewHostAuraTest : public ViewsTestBase {
return static_cast<NativeViewHostAura*>(host_->native_wrapper_.get());
}
+ NativeViewHost* host() {
+ return host_.get();
+ }
+
Widget* child() {
return child_.get();
}
@@ -73,4 +78,21 @@ TEST_F(NativeViewHostAuraTest, StopObservingNativeViewOnDestruct) {
EXPECT_FALSE(child_win->HasObserver(aura_host));
}
+// Tests that the kHostViewKey is correctly set and cleared.
+TEST_F(NativeViewHostAuraTest, HostViewPropertyKey) {
+ // Create the NativeViewHost and attach a NativeView.
+ CreateHost();
+ aura::Window* child_win = child()->GetNativeView();
+ EXPECT_EQ(host(), child_win->GetProperty(views::kHostViewKey));
+
+ host()->Detach();
+ EXPECT_FALSE(child_win->GetProperty(views::kHostViewKey));
+
+ host()->Attach(child_win);
+ EXPECT_EQ(host(), child_win->GetProperty(views::kHostViewKey));
+
+ DestroyHost();
+ EXPECT_FALSE(child_win->GetProperty(views::kHostViewKey));
+}
+
} // namespace views
diff --git a/ui/views/view.cc b/ui/views/view.cc
index 43719f3..18656ea 100644
--- a/ui/views/view.cc
+++ b/ui/views/view.cc
@@ -535,12 +535,6 @@ ui::Layer* View::RecreateLayer() {
return NULL;
CreateLayer();
-
- // TODO(pkotwicz): Remove this once ReorderLayers() stacks layers not attached
- // to a view above layers attached to a view.
- if (layer->parent())
- layer->parent()->StackAtTop(layer);
-
layer_->set_scale_content(layer->scale_content());
return layer;
}
@@ -1458,8 +1452,8 @@ void View::ReorderLayers() {
while (v && !v->layer())
v = v->parent();
+ Widget* widget = GetWidget();
if (!v) {
- Widget* widget = GetWidget();
if (widget) {
ui::Layer* layer = widget->GetLayer();
if (layer)
@@ -1468,15 +1462,29 @@ void View::ReorderLayers() {
} else {
v->ReorderChildLayers(v->layer());
}
+
+ if (widget) {
+ // Reorder the widget's child NativeViews in case a child NativeView is
+ // associated with a view (eg via a NativeViewHost). Always do the
+ // reordering because the associated NativeView's layer (if it has one)
+ // is parented to the widget's layer regardless of whether the host view has
+ // an ancestor with a layer.
+ widget->ReorderNativeViews();
+ }
}
void View::ReorderChildLayers(ui::Layer* parent_layer) {
if (layer() && layer() != parent_layer) {
DCHECK_EQ(parent_layer, layer()->parent());
- parent_layer->StackAtTop(layer());
+ parent_layer->StackAtBottom(layer());
} else {
- for (Views::const_iterator i(children_.begin()); i != children_.end(); ++i)
- (*i)->ReorderChildLayers(parent_layer);
+ // Iterate backwards through the children so that a child with a layer
+ // which is further to the back is stacked above one which is further to
+ // the front.
+ for (Views::const_reverse_iterator it(children_.rbegin());
+ it != children_.rend(); ++it) {
+ (*it)->ReorderChildLayers(parent_layer);
+ }
}
}
diff --git a/ui/views/view.h b/ui/views/view.h
index db2452b..4b10f0c 100644
--- a/ui/views/view.h
+++ b/ui/views/view.h
@@ -1104,7 +1104,11 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
virtual void ReorderLayers();
// This reorders the immediate children of |*parent_layer| to match the
- // order of the view tree.
+ // order of the view tree. Child layers which are owned by a view are
+ // reordered so that they are below any child layers not owned by a view.
+ // Widget::ReorderNativeViews() should be called to reorder any child layers
+ // with an associated view. Widget::ReorderNativeViews() may reorder layers
+ // below layers owned by a view.
virtual void ReorderChildLayers(ui::Layer* parent_layer);
// Input ---------------------------------------------------------------------
diff --git a/ui/views/view_constants_aura.cc b/ui/views/view_constants_aura.cc
new file mode 100644
index 0000000..977050f
--- /dev/null
+++ b/ui/views/view_constants_aura.cc
@@ -0,0 +1,16 @@
+// Copyright 2013 The Chromium 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 "ui/views/view_constants_aura.h"
+
+#include "ui/aura/window_property.h"
+#include "ui/views/view.h"
+
+DECLARE_EXPORTED_WINDOW_PROPERTY_TYPE(VIEWS_EXPORT, views::View*);
+
+namespace views {
+
+DEFINE_WINDOW_PROPERTY_KEY(views::View*, kHostViewKey, NULL);
+
+} // namespace views
diff --git a/ui/views/view_constants_aura.h b/ui/views/view_constants_aura.h
new file mode 100644
index 0000000..e0d718d
--- /dev/null
+++ b/ui/views/view_constants_aura.h
@@ -0,0 +1,22 @@
+// Copyright 2013 The Chromium 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 UI_VIEWS_VIEW_CONSTANTS_AURA_H_
+#define UI_VIEWS_VIEW_CONSTANTS_AURA_H_
+
+#include "ui/aura/window.h"
+#include "ui/views/views_export.h"
+
+namespace views {
+class View;
+
+// A property key to indicate the view the window is associated with. If
+// specified, the z-order of the view, relative to other views, dictates the
+// z-order of the window and its associated layer. The associated view must
+// have the same parent widget as the window on which the property is set.
+VIEWS_EXPORT extern const aura::WindowProperty<View*>* const kHostViewKey;
+
+} // namespace views
+
+#endif // UI_VIEWS_VIEW_CONSTANTS_AURA_H_
diff --git a/ui/views/view_unittest.cc b/ui/views/view_unittest.cc
index a5ccc2e..60aadde 100644
--- a/ui/views/view_unittest.cc
+++ b/ui/views/view_unittest.cc
@@ -3367,7 +3367,7 @@ TEST_F(ViewLayerTest, AcquireLayer) {
}
// Verify that new layer scales content only if the old layer does.
-TEST_F(ViewLayerTest, RecreateLayer) {
+TEST_F(ViewLayerTest, RecreateLayerScaling) {
scoped_ptr<View> v(new View());
v->SetPaintToLayer(true);
// Set to non default value.
@@ -3377,6 +3377,67 @@ TEST_F(ViewLayerTest, RecreateLayer) {
EXPECT_FALSE(new_layer->scale_content());
}
+// Verify the z-order of the layers as a result of calling RecreateLayer().
+TEST_F(ViewLayerTest, RecreateLayerZOrder) {
+ scoped_ptr<View> v(new View());
+ v->SetPaintToLayer(true);
+
+ View* v1 = new View();
+ v1->SetPaintToLayer(true);
+ v->AddChildView(v1);
+ View* v2 = new View();
+ v2->SetPaintToLayer(true);
+ v->AddChildView(v2);
+
+ // Test the initial z-order.
+ const std::vector<ui::Layer*>& child_layers_pre = v->layer()->children();
+ ASSERT_EQ(2u, child_layers_pre.size());
+ EXPECT_EQ(v1->layer(), child_layers_pre[0]);
+ EXPECT_EQ(v2->layer(), child_layers_pre[1]);
+
+ scoped_ptr<ui::Layer> v1_old_layer(v1->RecreateLayer());
+
+ // Test the new layer order. |v1_old_layer| should be above the layers
+ // for |v1| and |v2|.
+ const std::vector<ui::Layer*>& child_layers_post = v->layer()->children();
+ ASSERT_EQ(3u, child_layers_post.size());
+ EXPECT_EQ(v1->layer(), child_layers_post[0]);
+ EXPECT_EQ(v2->layer(), child_layers_post[1]);
+ EXPECT_EQ(v1_old_layer, child_layers_post[2]);
+}
+
+// Verify the z-order of the layers as a result of calling RecreateLayer when
+// the widget is the parent with the layer.
+TEST_F(ViewLayerTest, RecreateLayerZOrderWidgetParent) {
+ View* v = new View();
+ widget()->SetContentsView(v);
+
+ View* v1 = new View();
+ v1->SetPaintToLayer(true);
+ v->AddChildView(v1);
+ View* v2 = new View();
+ v2->SetPaintToLayer(true);
+ v->AddChildView(v2);
+
+ ui::Layer* root_layer = GetRootLayer();
+
+ // Test the initial z-order.
+ const std::vector<ui::Layer*>& child_layers_pre = root_layer->children();
+ ASSERT_EQ(2u, child_layers_pre.size());
+ EXPECT_EQ(v1->layer(), child_layers_pre[0]);
+ EXPECT_EQ(v2->layer(), child_layers_pre[1]);
+
+ scoped_ptr<ui::Layer> v1_old_layer(v1->RecreateLayer());
+
+ // Test the new layer order. |v1_old_layer| should be above the layers
+ // for |v1| and |v2|.
+ const std::vector<ui::Layer*>& child_layers_post = root_layer->children();
+ ASSERT_EQ(3u, child_layers_post.size());
+ EXPECT_EQ(v1->layer(), child_layers_post[0]);
+ EXPECT_EQ(v2->layer(), child_layers_post[1]);
+ EXPECT_EQ(v1_old_layer, child_layers_post[2]);
+}
+
#endif // USE_AURA
} // namespace views
diff --git a/ui/views/views.gyp b/ui/views/views.gyp
index 635ed67..a8d4bfa 100644
--- a/ui/views/views.gyp
+++ b/ui/views/views.gyp
@@ -328,6 +328,8 @@
'view.h',
'view_constants.cc',
'view_constants.h',
+ 'view_constants_aura.cc',
+ 'view_constants_aura.h',
'view_aura.cc',
'view_model.cc',
'view_model.h',
@@ -421,6 +423,8 @@
'widget/widget_message_filter.cc',
'widget/widget_message_filter.h',
'widget/widget_observer.h',
+ 'widget/window_reorderer.cc',
+ 'widget/window_reorderer.h',
'win/fullscreen_handler.cc',
'win/fullscreen_handler.h',
'win/hwnd_message_handler.cc',
@@ -493,6 +497,8 @@
'sources/': [
['exclude', 'corewm'],
['exclude', 'widget/desktop_aura'],
+ ['exclude', 'widget/window_reorderer.h'],
+ ['exclude', 'widget/window_reorderer.cc'],
],
'sources!': [
'widget/native_widget_aura_window_observer.cc',
@@ -723,6 +729,7 @@
'widget/native_widget_unittest.cc',
'widget/native_widget_win_unittest.cc',
'widget/widget_unittest.cc',
+ 'widget/window_reorderer_unittest.cc',
'run_all_unittests.cc',
],
'conditions': [
@@ -766,6 +773,7 @@
'sources/': [
['exclude', 'corewm'],
['exclude', 'widget/desktop_aura'],
+ ['exclude', 'widget/window_reorderer_unittest.cc']
],
}],
],
diff --git a/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc b/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc
index 26828e0..c4634c3 100644
--- a/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc
+++ b/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc
@@ -41,6 +41,7 @@
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_aura_utils.h"
#include "ui/views/widget/widget_delegate.h"
+#include "ui/views/widget/window_reorderer.h"
DECLARE_EXPORTED_WINDOW_PROPERTY_TYPE(VIEWS_EXPORT,
views::DesktopNativeWidgetAura*);
@@ -274,6 +275,9 @@ void DesktopNativeWidgetAura::InitNativeWidget(
shadow_controller_.reset(
new corewm::ShadowController(
aura::client::GetActivationClient(root_window_.get())));
+
+ window_reorderer_.reset(new WindowReorderer(window_,
+ GetWidget()->GetRootView()));
}
NonClientFrameView* DesktopNativeWidgetAura::CreateNonClientFrameView() {
@@ -320,6 +324,10 @@ ui::Layer* DesktopNativeWidgetAura::GetLayer() {
return window_->layer();
}
+void DesktopNativeWidgetAura::ReorderNativeViews() {
+ window_reorderer_->ReorderChildWindows();
+}
+
void DesktopNativeWidgetAura::ViewRemoved(View* view) {
}
diff --git a/ui/views/widget/desktop_aura/desktop_native_widget_aura.h b/ui/views/widget/desktop_aura/desktop_native_widget_aura.h
index d46f0ba..fed511c 100644
--- a/ui/views/widget/desktop_aura/desktop_native_widget_aura.h
+++ b/ui/views/widget/desktop_aura/desktop_native_widget_aura.h
@@ -37,6 +37,7 @@ class DesktopRootWindowHost;
class DropHelper;
class NativeWidgetAuraWindowObserver;
class TooltipManagerAura;
+class WindowReorderer;
class VIEWS_EXPORT DesktopNativeWidgetAura
: public internal::NativeWidgetPrivate,
@@ -82,6 +83,7 @@ class VIEWS_EXPORT DesktopNativeWidgetAura
virtual const ui::Compositor* GetCompositor() const OVERRIDE;
virtual ui::Compositor* GetCompositor() OVERRIDE;
virtual ui::Layer* GetLayer() OVERRIDE;
+ virtual void ReorderNativeViews() OVERRIDE;
virtual void ViewRemoved(View* view) OVERRIDE;
virtual void SetNativeWindowProperty(const char* name, void* value) OVERRIDE;
virtual void* GetNativeWindowProperty(const char* name) const OVERRIDE;
@@ -244,6 +246,10 @@ class VIEWS_EXPORT DesktopNativeWidgetAura
scoped_ptr<corewm::ShadowController> shadow_controller_;
+ // Reorders child windows of |window_| associated with a view based on the
+ // order of the associated views in the widget's view hierarchy.
+ scoped_ptr<WindowReorderer> window_reorderer_;
+
DISALLOW_COPY_AND_ASSIGN(DesktopNativeWidgetAura);
};
diff --git a/ui/views/widget/native_widget_aura.cc b/ui/views/widget/native_widget_aura.cc
index 37a6e41..413e1ce9 100644
--- a/ui/views/widget/native_widget_aura.cc
+++ b/ui/views/widget/native_widget_aura.cc
@@ -39,6 +39,7 @@
#include "ui/views/widget/tooltip_manager_aura.h"
#include "ui/views/widget/widget_aura_utils.h"
#include "ui/views/widget/widget_delegate.h"
+#include "ui/views/widget/window_reorderer.h"
#if defined(OS_WIN)
#include "base/win/scoped_gdi_object.h"
@@ -172,6 +173,9 @@ void NativeWidgetAura::InitNativeWidget(const Widget::InitParams& params) {
GetWidget()->widget_delegate()->CanMaximize());
window_->SetProperty(aura::client::kCanResizeKey,
GetWidget()->widget_delegate()->CanResize());
+
+ window_reorderer_.reset(new WindowReorderer(window_,
+ GetWidget()->GetRootView()));
}
NonClientFrameView* NativeWidgetAura::CreateNonClientFrameView() {
@@ -223,6 +227,10 @@ ui::Layer* NativeWidgetAura::GetLayer() {
return window_->layer();
}
+void NativeWidgetAura::ReorderNativeViews() {
+ window_reorderer_->ReorderChildWindows();
+}
+
void NativeWidgetAura::ViewRemoved(View* view) {
DCHECK(drop_helper_.get() != NULL);
drop_helper_->ResetTargetViewIfEquals(view);
diff --git a/ui/views/widget/native_widget_aura.h b/ui/views/widget/native_widget_aura.h
index 3dc64d6..c40901a 100644
--- a/ui/views/widget/native_widget_aura.h
+++ b/ui/views/widget/native_widget_aura.h
@@ -29,6 +29,7 @@ namespace views {
class DropHelper;
class NativeWidgetAuraWindowObserver;
class TooltipManagerAura;
+class WindowReorderer;
class VIEWS_EXPORT NativeWidgetAura
: public internal::NativeWidgetPrivate,
@@ -58,6 +59,7 @@ class VIEWS_EXPORT NativeWidgetAura
virtual const ui::Compositor* GetCompositor() const OVERRIDE;
virtual ui::Compositor* GetCompositor() OVERRIDE;
virtual ui::Layer* GetLayer() OVERRIDE;
+ virtual void ReorderNativeViews() OVERRIDE;
virtual void ViewRemoved(View* view) OVERRIDE;
virtual void SetNativeWindowProperty(const char* name, void* value) OVERRIDE;
virtual void* GetNativeWindowProperty(const char* name) const OVERRIDE;
@@ -205,6 +207,10 @@ class VIEWS_EXPORT NativeWidgetAura
scoped_ptr<TooltipManagerAura> tooltip_manager_;
+ // Reorders child windows of |window_| associated with a view based on the
+ // order of the associated views in the widget's view hierarchy.
+ scoped_ptr<WindowReorderer> window_reorderer_;
+
scoped_ptr<NativeWidgetAuraWindowObserver> active_window_observer_;
scoped_ptr<DropHelper> drop_helper_;
diff --git a/ui/views/widget/native_widget_aura_unittest.cc b/ui/views/widget/native_widget_aura_unittest.cc
index 13e7de5..ae8b223 100644
--- a/ui/views/widget/native_widget_aura_unittest.cc
+++ b/ui/views/widget/native_widget_aura_unittest.cc
@@ -315,8 +315,7 @@ TEST_F(NativeWidgetAuraTest, ReleaseCaptureOnTouchRelease) {
// Verifies views with layers are targeted for events properly.
TEST_F(NativeWidgetAuraTest, PreferViewLayersToChildWindows) {
- // Create two widget, |parent_root| and |child|. |child| is a child of
- // |parent_root|.
+ // Create two widgets: |parent| and |child|. |child| is a child of |parent|.
views::View* parent_root = new views::View;
scoped_ptr<Widget> parent(new Widget());
Widget::InitParams parent_params(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
@@ -341,13 +340,21 @@ TEST_F(NativeWidgetAuraTest, PreferViewLayersToChildWindows) {
parent->GetNativeWindow()->GetEventHandlerForPoint(
gfx::Point(50, 50)));
- // Create a view with a layer and stack it at the top (above |child|).
+ // Create a view with a layer and stack it at the bottom (below |child|).
views::View* view_with_layer = new views::View;
parent_root->AddChildView(view_with_layer);
view_with_layer->SetBounds(0, 0, 50, 50);
view_with_layer->SetPaintToLayer(true);
- // Point is over |view_with_layer|, it should get the event.
+ // Make sure that |child| still gets the event.
+ EXPECT_EQ(child->GetNativeWindow(),
+ parent->GetNativeWindow()->GetEventHandlerForPoint(
+ gfx::Point(20, 20)));
+
+ // Move |view_with_layer| to the top and make sure it gets the
+ // event when the point is within |view_with_layer|'s bounds.
+ view_with_layer->layer()->parent()->StackAtTop(
+ view_with_layer->layer());
EXPECT_EQ(parent->GetNativeWindow(),
parent->GetNativeWindow()->GetEventHandlerForPoint(
gfx::Point(20, 20)));
@@ -357,13 +364,6 @@ TEST_F(NativeWidgetAuraTest, PreferViewLayersToChildWindows) {
parent->GetNativeWindow()->GetEventHandlerForPoint(
gfx::Point(70, 70)));
- // Move |child| to the top and make sure it gets the event.
- child->GetNativeWindow()->layer()->parent()->StackAtTop(
- child->GetNativeWindow()->layer());
- EXPECT_EQ(child->GetNativeWindow(),
- parent->GetNativeWindow()->GetEventHandlerForPoint(
- gfx::Point(20, 20)));
-
delete view_with_layer;
view_with_layer = NULL;
diff --git a/ui/views/widget/native_widget_private.h b/ui/views/widget/native_widget_private.h
index 2bb61c0..b9cc7af 100644
--- a/ui/views/widget/native_widget_private.h
+++ b/ui/views/widget/native_widget_private.h
@@ -100,6 +100,15 @@ class VIEWS_EXPORT NativeWidgetPrivate : public NativeWidget {
// Returns the NativeWidget's layer, if any.
virtual ui::Layer* GetLayer() = 0;
+ // Reorders the widget's child NativeViews which are associated to the view
+ // tree (eg via a NativeViewHost) to match the z-order of the views in the
+ // view tree. The z-order of views with layers relative to views with
+ // associated NativeViews is used to reorder the NativeView layers. This
+ // method assumes that the widget's child layers which are owned by a view are
+ // already in the correct z-order relative to each other and does no
+ // reordering if there are no views with an associated NativeView.
+ virtual void ReorderNativeViews() = 0;
+
// Notifies the NativeWidget that a view was removed from the Widget's view
// hierarchy.
virtual void ViewRemoved(View* view) = 0;
diff --git a/ui/views/widget/native_widget_win.cc b/ui/views/widget/native_widget_win.cc
index 59abe0b..f7a242b 100644
--- a/ui/views/widget/native_widget_win.cc
+++ b/ui/views/widget/native_widget_win.cc
@@ -161,6 +161,9 @@ ui::Layer* NativeWidgetWin::GetLayer() {
return NULL;
}
+void NativeWidgetWin::ReorderNativeViews() {
+}
+
void NativeWidgetWin::ViewRemoved(View* view) {
if (drop_target_.get())
drop_target_->ResetTargetViewIfEquals(view);
diff --git a/ui/views/widget/native_widget_win.h b/ui/views/widget/native_widget_win.h
index 85f1e84..a2c3f91 100644
--- a/ui/views/widget/native_widget_win.h
+++ b/ui/views/widget/native_widget_win.h
@@ -80,6 +80,7 @@ class VIEWS_EXPORT NativeWidgetWin : public internal::NativeWidgetPrivate,
virtual const ui::Compositor* GetCompositor() const OVERRIDE;
virtual ui::Compositor* GetCompositor() OVERRIDE;
virtual ui::Layer* GetLayer() OVERRIDE;
+ virtual void ReorderNativeViews() OVERRIDE;
virtual void ViewRemoved(View* view) OVERRIDE;
virtual void SetNativeWindowProperty(const char* name, void* value) OVERRIDE;
virtual void* GetNativeWindowProperty(const char* name) const OVERRIDE;
diff --git a/ui/views/widget/widget.cc b/ui/views/widget/widget.cc
index c78d90c..0be49ae 100644
--- a/ui/views/widget/widget.cc
+++ b/ui/views/widget/widget.cc
@@ -884,6 +884,10 @@ ui::Layer* Widget::GetLayer() {
return native_widget_->GetLayer();
}
+void Widget::ReorderNativeViews() {
+ native_widget_->ReorderNativeViews();
+}
+
void Widget::UpdateRootLayers() {
// Calculate the layers requires traversing the tree, and since nearly any
// mutation of the tree can trigger this call we delay until absolutely
diff --git a/ui/views/widget/widget.h b/ui/views/widget/widget.h
index 6246faa..2ab9da3 100644
--- a/ui/views/widget/widget.h
+++ b/ui/views/widget/widget.h
@@ -573,6 +573,15 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate,
// Returns the widget's layer, if any.
ui::Layer* GetLayer();
+ // Reorders the widget's child NativeViews which are associated to the view
+ // tree (eg via a NativeViewHost) to match the z-order of the views in the
+ // view tree. The z-order of views with layers relative to views with
+ // associated NativeViews is used to reorder the NativeView layers. This
+ // method assumes that the widget's child layers which are owned by a view are
+ // already in the correct z-order relative to each other and does no
+ // reordering if there are no views with an associated NativeView.
+ void ReorderNativeViews();
+
// Schedules an update to the root layers. The actual processing occurs when
// GetRootLayers() is invoked.
void UpdateRootLayers();
diff --git a/ui/views/widget/window_reorderer.cc b/ui/views/widget/window_reorderer.cc
new file mode 100644
index 0000000..dcf51c8
--- /dev/null
+++ b/ui/views/widget/window_reorderer.cc
@@ -0,0 +1,201 @@
+// Copyright 2013 The Chromium 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 "ui/views/widget/window_reorderer.h"
+
+#include <map>
+#include <vector>
+
+#include "ui/aura/window.h"
+#include "ui/views/view.h"
+#include "ui/views/view_constants_aura.h"
+
+namespace views {
+
+namespace {
+
+// Sets |hosted_windows| to a mapping of the views with an associated window to
+// the window that they are associated to. Only views associated to a child of
+// |parent_window| are returned.
+void GetViewsWithAssociatedWindow(
+ const aura::Window& parent_window,
+ std::map<views::View*, aura::Window*>* hosted_windows) {
+ const std::vector<aura::Window*>& child_windows = parent_window.children();
+ for (size_t i = 0; i < child_windows.size(); ++i) {
+ aura::Window* child = child_windows[i];
+ View* host_view = child->GetProperty(kHostViewKey);
+ if (host_view)
+ (*hosted_windows)[host_view] = child;
+ }
+}
+
+// Sets |order| to the list of views whose layer / associated window's layer
+// is a child of |parent_layer|. |order| is sorted in ascending z-order of
+// the views.
+// |hosts| are the views with an associated window whose layer is a child of
+// |parent_layer|.
+void GetOrderOfViewsWithLayers(
+ views::View* view,
+ ui::Layer* parent_layer,
+ const std::map<views::View*, aura::Window*>& hosts,
+ std::vector<views::View*>* order) {
+ DCHECK(view);
+ DCHECK(parent_layer);
+ DCHECK(order);
+ if (view->layer() && view->layer()->parent() == parent_layer) {
+ order->push_back(view);
+ // |hosts| may contain a child of |view|.
+ } else if (hosts.find(view) != hosts.end()) {
+ order->push_back(view);
+ }
+
+ for (int i = 0; i < view->child_count(); ++i)
+ GetOrderOfViewsWithLayers(view->child_at(i), parent_layer, hosts, order);
+}
+
+} // namespace
+
+// Class which reorders windows as a result of the kHostViewKey property being
+// set on the window.
+class WindowReorderer::AssociationObserver : public aura::WindowObserver {
+ public:
+ explicit AssociationObserver(WindowReorderer* reorderer);
+ virtual ~AssociationObserver();
+
+ // Start/stop observing changes in the kHostViewKey property on |window|.
+ void StartObserving(aura::Window* window);
+ void StopObserving(aura::Window* window);
+
+ private:
+ // aura::WindowObserver overrides:
+ virtual void OnWindowPropertyChanged(aura::Window* window,
+ const void* key,
+ intptr_t old) OVERRIDE;
+ virtual void OnWindowDestroying(aura::Window* window) OVERRIDE;
+
+ // Not owned.
+ WindowReorderer* reorderer_;
+
+ std::set<aura::Window*> windows_;
+
+ DISALLOW_COPY_AND_ASSIGN(AssociationObserver);
+};
+
+WindowReorderer::AssociationObserver::AssociationObserver(
+ WindowReorderer* reorderer)
+ : reorderer_(reorderer) {
+}
+
+WindowReorderer::AssociationObserver::~AssociationObserver() {
+ while (!windows_.empty())
+ StopObserving(*windows_.begin());
+}
+
+void WindowReorderer::AssociationObserver::StartObserving(
+ aura::Window* window) {
+ windows_.insert(window);
+ window->AddObserver(this);
+}
+
+void WindowReorderer::AssociationObserver::StopObserving(
+ aura::Window* window) {
+ windows_.erase(window);
+ window->RemoveObserver(this);
+}
+
+void WindowReorderer::AssociationObserver::OnWindowPropertyChanged(
+ aura::Window* window,
+ const void* key,
+ intptr_t old) {
+ if (key == kHostViewKey)
+ reorderer_->ReorderChildWindows();
+}
+
+void WindowReorderer::AssociationObserver::OnWindowDestroying(
+ aura::Window* window) {
+ windows_.erase(window);
+ window->RemoveObserver(this);
+}
+
+WindowReorderer::WindowReorderer(aura::Window* parent_window,
+ View* root_view)
+ : parent_window_(parent_window),
+ root_view_(root_view),
+ association_observer_(new AssociationObserver(this)) {
+ parent_window_->AddObserver(this);
+ const std::vector<aura::Window*>& windows = parent_window_->children();
+ for (size_t i = 0; i < windows.size(); ++i)
+ association_observer_->StartObserving(windows[i]);
+ ReorderChildWindows();
+}
+
+WindowReorderer::~WindowReorderer() {
+ if (parent_window_) {
+ parent_window_->RemoveObserver(this);
+ // |association_observer_| stops observing any windows it is observing upon
+ // destruction.
+ }
+}
+
+void WindowReorderer::ReorderChildWindows() {
+ if (!parent_window_)
+ return;
+
+ std::map<View*, aura::Window*> hosted_windows;
+ GetViewsWithAssociatedWindow(*parent_window_, &hosted_windows);
+
+ if (hosted_windows.empty()) {
+ // Exit early if there are no views with associated windows.
+ // View::ReorderLayers() should have already reordered the layers owned by
+ // views.
+ return;
+ }
+
+ // Compute the desired z-order of the layers based on the order of the views
+ // with layers and views with associated windows in the view tree.
+ std::vector<View*> view_with_layer_order;
+ GetOrderOfViewsWithLayers(root_view_, parent_window_->layer(), hosted_windows,
+ &view_with_layer_order);
+
+ // For the sake of simplicity, reorder both the layers owned by views and the
+ // layers of windows associated with a view. Iterate through
+ // |view_with_layer_order| backwards and stack windows at the bottom so that
+ // windows not associated to a view are stacked above windows with an
+ // associated view.
+ for (std::vector<View*>::reverse_iterator it = view_with_layer_order.rbegin();
+ it != view_with_layer_order.rend(); ++it) {
+ View* view = *it;
+ ui::Layer* layer = view->layer();
+ aura::Window* window = NULL;
+
+ std::map<View*, aura::Window*>::iterator hosted_window_it =
+ hosted_windows.find(view);
+ if (hosted_window_it != hosted_windows.end()) {
+ window = hosted_window_it->second;
+ layer = window->layer();
+ }
+
+ DCHECK(layer);
+ if (window)
+ parent_window_->StackChildAtBottom(window);
+ parent_window_->layer()->StackAtBottom(layer);
+ }
+}
+
+void WindowReorderer::OnWindowAdded(aura::Window* new_window) {
+ association_observer_->StartObserving(new_window);
+ ReorderChildWindows();
+}
+
+void WindowReorderer::OnWillRemoveWindow(aura::Window* window) {
+ association_observer_->StopObserving(window);
+}
+
+void WindowReorderer::OnWindowDestroying(aura::Window* window) {
+ parent_window_->RemoveObserver(this);
+ parent_window_ = NULL;
+ association_observer_.reset();
+}
+
+} // namespace views
diff --git a/ui/views/widget/window_reorderer.h b/ui/views/widget/window_reorderer.h
new file mode 100644
index 0000000..b04e48f
--- /dev/null
+++ b/ui/views/widget/window_reorderer.h
@@ -0,0 +1,59 @@
+// Copyright 2013 The Chromium 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 UI_VIEWS_WIDGET_WINDOW_REORDERER_H_
+#define UI_VIEWS_WIDGET_WINDOW_REORDERER_H_
+
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "ui/aura/window_observer.h"
+
+namespace aura {
+class Window;
+}
+
+namespace views {
+class View;
+
+// Class which reorders the widget's child windows which have an associated view
+// in the widget's view tree according the z-order of the views in the view
+// tree. Windows not associated to a view are stacked above windows with an
+// associated view. The child windows' layers are additionally reordered
+// according to the z-order of the associated views relative to views with
+// layers.
+class WindowReorderer : public aura::WindowObserver {
+ public:
+ WindowReorderer(aura::Window* window, View* root_view);
+ virtual ~WindowReorderer();
+
+ // Explicitly reorder the children of |window_| (and their layers). This
+ // method should be called when the position of a view with an associated
+ // window changes in the view hierarchy. This method assumes that the
+ // child layers of |window_| which are owned by views are already in the
+ // correct z-order relative to each other and does no reordering if there
+ // are no views with an associated window.
+ void ReorderChildWindows();
+
+ private:
+ // aura::WindowObserver overrides:
+ virtual void OnWindowAdded(aura::Window* new_window) OVERRIDE;
+ virtual void OnWillRemoveWindow(aura::Window* window) OVERRIDE;
+ virtual void OnWindowDestroying(aura::Window* window) OVERRIDE;
+
+ // The window and the root view of the native widget which owns the
+ // WindowReorderer.
+ aura::Window* parent_window_;
+ View* root_view_;
+
+ // Reorders windows as a result of the kHostViewKey being set on a child of
+ // |parent_window_|.
+ class AssociationObserver;
+ scoped_ptr<AssociationObserver> association_observer_;
+
+ DISALLOW_COPY_AND_ASSIGN(WindowReorderer);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_WIDGET_WINDOW_REORDERER_H_
diff --git a/ui/views/widget/window_reorderer_unittest.cc b/ui/views/widget/window_reorderer_unittest.cc
new file mode 100644
index 0000000..1d9566c
--- /dev/null
+++ b/ui/views/widget/window_reorderer_unittest.cc
@@ -0,0 +1,263 @@
+// Copyright 2013 The Chromium 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 "ui/aura/root_window.h"
+#include "ui/aura/test/aura_test_base.h"
+#include "ui/aura/test/test_windows.h"
+#include "ui/aura/window.h"
+#include "ui/compositor/layer.h"
+#include "ui/compositor/test/test_layers.h"
+#include "ui/views/view.h"
+#include "ui/views/view_constants_aura.h"
+#include "ui/views/widget/widget.h"
+
+namespace views {
+namespace {
+
+// Creates a control widget with the passed in parameters.
+// The caller takes ownership of the returned widget.
+Widget* CreateControlWidget(aura::Window* parent, const gfx::Rect& bounds) {
+ Widget::InitParams params(Widget::InitParams::TYPE_CONTROL);
+ params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ params.parent = parent;
+ params.bounds = bounds;
+ Widget* widget = new Widget();
+ widget->Init(params);
+ return widget;
+}
+
+// Sets the name of |window| and |window|'s layer to |name|.
+void SetWindowAndLayerName(aura::Window* window, const std::string& name) {
+ window->SetName(name);
+ window->layer()->set_name(name);
+}
+
+// Returns a string containing the name of each of the child windows (bottommost
+// first) of |parent|. The format of the string is "name1 name2 name3 ...".
+std::string ChildWindowNamesAsString(const aura::Window& parent) {
+ std::string names;
+ typedef std::vector<aura::Window*> Windows;
+ for (Windows::const_iterator it = parent.children().begin();
+ it != parent.children().end(); ++it) {
+ if (!names.empty())
+ names += " ";
+ names += (*it)->name();
+ }
+ return names;
+}
+
+typedef aura::test::AuraTestBase WindowReordererTest;
+
+// Test that views with layers and views with associated windows are reordered
+// according to the view hierarchy.
+TEST_F(WindowReordererTest, Basic) {
+ scoped_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);
+
+ // 1) Test that layers for views and layers for windows associated to a host
+ // view are stacked below the layers for any windows not associated to a host
+ // view.
+ View* v = new View();
+ v->SetPaintToLayer(true);
+ v->layer()->set_name("v");
+ contents_view->AddChildView(v);
+
+ scoped_ptr<Widget> w1(CreateControlWidget(parent_window,
+ gfx::Rect(0, 1, 100, 101)));
+ SetWindowAndLayerName(w1->GetNativeView(), "w1");
+ w1->Show();
+ scoped_ptr<Widget> w2(CreateControlWidget(parent_window,
+ gfx::Rect(0, 2, 100, 102)));
+ SetWindowAndLayerName(w2->GetNativeView(), "w2");
+ w2->Show();
+
+ EXPECT_EQ("w1 w2", ChildWindowNamesAsString(*parent_window));
+ EXPECT_EQ("v w1 w2",
+ ui::test::ChildLayerNamesAsString(*parent_window->layer()));
+
+ View* host_view2 = new View();
+ contents_view->AddChildView(host_view2);
+ w2->GetNativeView()->SetProperty(kHostViewKey, host_view2);
+ EXPECT_EQ("w2 w1", ChildWindowNamesAsString(*parent_window));
+ EXPECT_EQ("v w2 w1",
+ ui::test::ChildLayerNamesAsString(*parent_window->layer()));
+
+ View* host_view1 = new View();
+ w1->GetNativeView()->SetProperty(kHostViewKey, host_view1);
+ contents_view->AddChildViewAt(host_view1, 0);
+ EXPECT_EQ("w1 w2", ChildWindowNamesAsString(*parent_window));
+ EXPECT_EQ("w1 v w2",
+ ui::test::ChildLayerNamesAsString(*parent_window->layer()));
+
+ // 2) Test the z-order of the windows and layers as a result of reordering the
+ // views.
+ contents_view->ReorderChildView(host_view1, -1);
+ EXPECT_EQ("w2 w1", ChildWindowNamesAsString(*parent_window));
+ EXPECT_EQ("v w2 w1",
+ ui::test::ChildLayerNamesAsString(*parent_window->layer()));
+
+ contents_view->ReorderChildView(host_view2, -1);
+ EXPECT_EQ("w1 w2", ChildWindowNamesAsString(*parent_window));
+ EXPECT_EQ("v w1 w2",
+ ui::test::ChildLayerNamesAsString(*parent_window->layer()));
+
+ // 3) Test the z-order of the windows and layers as a result of reordering the
+ // views in situations where the window order remains unchanged.
+ contents_view->ReorderChildView(v, -1);
+ EXPECT_EQ("w1 w2", ChildWindowNamesAsString(*parent_window));
+ EXPECT_EQ("w1 w2 v",
+ ui::test::ChildLayerNamesAsString(*parent_window->layer()));
+
+ contents_view->ReorderChildView(host_view2, -1);
+ EXPECT_EQ("w1 w2", ChildWindowNamesAsString(*parent_window));
+ EXPECT_EQ("w1 v w2",
+ ui::test::ChildLayerNamesAsString(*parent_window->layer()));
+
+ // Work around for bug in NativeWidgetAura.
+ // TODO: fix bug and remove this.
+ parent->Close();
+}
+
+// Test that different orderings of:
+// - adding a window to a parent widget
+// - adding a "host" view to a parent widget
+// - associating the "host" view and window
+// all correctly reorder the child windows and layers.
+TEST_F(WindowReordererTest, Association) {
+ scoped_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);
+
+ aura::Window* w1 = aura::test::CreateTestWindowWithId(0,
+ parent->GetNativeWindow());
+ SetWindowAndLayerName(w1, "w1");
+
+ aura::Window* w2 = aura::test::CreateTestWindowWithId(0, NULL);
+ SetWindowAndLayerName(w2, "w2");
+
+ View* host_view2 = new View();
+
+ // 1) Test that parenting the window to the parent widget last results in a
+ // correct ordering of child windows and layers.
+ contents_view->AddChildView(host_view2);
+ w2->SetProperty(views::kHostViewKey, host_view2);
+ EXPECT_EQ("w1", ChildWindowNamesAsString(*parent_window));
+ EXPECT_EQ("w1",
+ ui::test::ChildLayerNamesAsString(*parent_window->layer()));
+
+ parent_window->AddChild(w2);
+ EXPECT_EQ("w2 w1", ChildWindowNamesAsString(*parent_window));
+ EXPECT_EQ("w2 w1",
+ ui::test::ChildLayerNamesAsString(*parent_window->layer()));
+
+ // 2) Test that associating the window and "host" view last results in a
+ // correct ordering of child windows and layers.
+ View* host_view1 = new View();
+ contents_view->AddChildViewAt(host_view1, 0);
+ EXPECT_EQ("w2 w1", ChildWindowNamesAsString(*parent_window));
+ EXPECT_EQ("w2 w1",
+ ui::test::ChildLayerNamesAsString(*parent_window->layer()));
+
+ w1->SetProperty(views::kHostViewKey, host_view1);
+ EXPECT_EQ("w1 w2", ChildWindowNamesAsString(*parent_window));
+ EXPECT_EQ("w1 w2",
+ ui::test::ChildLayerNamesAsString(*parent_window->layer()));
+
+ // 3) Test that parenting the "host" view to the parent widget last results
+ // in a correct ordering of child windows and layers.
+ contents_view->RemoveChildView(host_view2);
+ contents_view->AddChildViewAt(host_view2, 0);
+ EXPECT_EQ("w2 w1", ChildWindowNamesAsString(*parent_window));
+ EXPECT_EQ("w2 w1",
+ ui::test::ChildLayerNamesAsString(*parent_window->layer()));
+
+ // Work around for bug in NativeWidgetAura.
+ // TODO: fix bug and remove this.
+ parent->Close();
+}
+
+// It is possible to associate a window to a view which has a parent layer
+// (other than the widget layer). In this case, the parent layer of the host
+// view and the parent layer of the associated window are different. Test that
+// the layers and windows are properly reordered in this case.
+TEST_F(WindowReordererTest, HostViewParentHasLayer) {
+ scoped_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);
+
+ // Create the following view hierarchy. (*) denotes views which paint to a
+ // layer.
+ //
+ // contents_view
+ // +-- v1
+ // +-- v11*
+ // +-- v12 (attached window)
+ // +-- v13*
+ // +--v2*
+
+ View* v1 = new View();
+ contents_view->AddChildView(v1);
+
+ View* v11 = new View();
+ v11->SetPaintToLayer(true);
+ v11->layer()->set_name("v11");
+ v1->AddChildView(v11);
+
+ scoped_ptr<Widget> w(CreateControlWidget(parent_window,
+ gfx::Rect(0, 1, 100, 101)));
+ SetWindowAndLayerName(w->GetNativeView(), "w");
+ w->Show();
+
+ View* v12 = new View();
+ v1->AddChildView(v12);
+ w->GetNativeView()->SetProperty(kHostViewKey, v12);
+
+ View* v13 = new View();
+ v13->SetPaintToLayer(true);
+ v13->layer()->set_name("v13");
+ v1->AddChildView(v13);
+
+ View* v2 = new View();
+ v2->SetPaintToLayer(true);
+ v2->layer()->set_name("v2");
+ contents_view->AddChildView(v2);
+
+ // Test intial state.
+ EXPECT_EQ("w", ChildWindowNamesAsString(*parent_window));
+ EXPECT_EQ("v11 w v13 v2",
+ ui::test::ChildLayerNamesAsString(*parent_window->layer()));
+
+ // |w|'s layer should be stacked above |v1|'s layer.
+ v1->SetPaintToLayer(true);
+ v1->layer()->set_name("v1");
+ EXPECT_EQ("w", ChildWindowNamesAsString(*parent_window));
+ EXPECT_EQ("v1 w v2",
+ ui::test::ChildLayerNamesAsString(*parent_window->layer()));
+
+ // Test moving the host view from one view with a layer to another.
+ v2->AddChildView(v12);
+ EXPECT_EQ("w", ChildWindowNamesAsString(*parent_window));
+ EXPECT_EQ("v1 v2 w",
+ ui::test::ChildLayerNamesAsString(*parent_window->layer()));
+
+ // Work around for bug in NativeWidgetAura.
+ // TODO: fix bug and remove this.
+ parent->Close();
+}
+
+} // namespace
+} // namespace views