Commit 88fa18e8 authored by sky@chromium.org's avatar sky@chromium.org

Initial cut at layerless windows.

This has the minimal support working. You can create layerless
windows add/remove them from a hierarchy, add children with layers and
everything is kept in sync (including bounds).

Painting has not been wired up yet.

The interesting bit of this change is that Layer and Window bounds are
no longer in sync. This is necessitated by Layer's having to be
parented to Layers. To avoid changing bounds() to dynamically figure
out the real bounds I made Window cache the bounds.

BUG=none
TEST=none
R=ben@chromium.org

Review URL: https://codereview.chromium.org/82283002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@238408 0039d316-1c4b-4281-b951-d872f2087c98
parent 917cd320
......@@ -100,6 +100,7 @@
'window.cc',
'window.h',
'window_delegate.h',
'window_layer_type.h',
'window_observer.h',
'window_tracker.cc',
'window_tracker.h',
......
This diff is collapsed.
......@@ -16,6 +16,7 @@
#include "base/strings/string16.h"
#include "ui/aura/aura_export.h"
#include "ui/aura/client/window_types.h"
#include "ui/aura/window_layer_type.h"
#include "ui/aura/window_observer.h"
#include "ui/compositor/layer_animator.h"
#include "ui/compositor/layer_delegate.h"
......@@ -32,6 +33,7 @@
namespace gfx {
class Display;
class Transform;
class Vector2d;
}
namespace ui {
......@@ -74,6 +76,9 @@ class AURA_EXPORT Window : public ui::LayerDelegate,
// Initializes the window. This creates the window's layer.
void Init(ui::LayerType layer_type);
// TODO(sky): replace other Init() with this once m32 is more baked.
void InitWithWindowLayerType(WindowLayerType layer_type);
// Creates a new layer for the window. Erases the layer-owned bounds, so the
// caller may wish to set new bounds and other state on the window/layer.
// Returns the old layer, which can be used for animations. Caller owns the
......@@ -107,7 +112,7 @@ class AURA_EXPORT Window : public ui::LayerDelegate,
WindowDelegate* delegate() { return delegate_; }
const WindowDelegate* delegate() const { return delegate_; }
const gfx::Rect& bounds() const;
const gfx::Rect& bounds() const { return bounds_; }
Window* parent() { return parent_; }
const Window* parent() const { return parent_; }
......@@ -411,6 +416,22 @@ class AURA_EXPORT Window : public ui::LayerDelegate,
// to.
void RemoveChildImpl(Window* child, Window* new_parent);
// If this Window has a layer the layer's parent is set to NULL, otherwise
// UnparentLayers() is invoked on all the children. |offset| is the offset
// relative to the nearest ancestor with a layer.
void UnparentLayers(bool has_layerless_ancestor,
const gfx::Vector2d& offset);
// If this Window has a layer it is added to |parent| and the origin set to
// |offset|. Otherwise this recurses through the children invoking
// ReparentLayers(). The net effect is both setting the parent of layers to
// |parent| as well as updating bounds of windows with a layerless ancestor.
void ReparentLayers(ui::Layer* parent, const gfx::Vector2d& offset);
// Offsets the first encountered Windows with layers by |offset|. This
// recurses through all layerless Windows, stopping at windows with layers.
void OffsetLayerBounds(const gfx::Vector2d& offset);
// Called when this window's parent has changed.
void OnParentChanged();
......@@ -473,11 +494,12 @@ class AURA_EXPORT Window : public ui::LayerDelegate,
// Notifies this window and its parent hierarchy.
void NotifyWindowVisibilityChangedUp(aura::Window* target, bool visible);
// Invoked from the closure returned by PrepareForLayerBoundsChange() after
// the bounds of the layer has changed. |old_bounds| is the previous bounds of
// the layer, and |contained_mouse| is true if the mouse was previously within
// the window's bounds.
void OnLayerBoundsChanged(const gfx::Rect& old_bounds, bool contained_mouse);
// Invoked when the bounds of the window changes. This may be invoked directly
// by us, or from the closure returned by PrepareForLayerBoundsChange() after
// the bounds of the layer has changed. |old_bounds| is the previous bounds,
// and |contained_mouse| is true if the mouse was previously within the
// window's bounds.
void OnWindowBoundsChanged(const gfx::Rect& old_bounds, bool contained_mouse);
// Overridden from ui::LayerDelegate:
virtual void OnPaintLayer(gfx::Canvas* canvas) OVERRIDE;
......@@ -497,6 +519,20 @@ class AURA_EXPORT Window : public ui::LayerDelegate,
// Returns true if the mouse is currently within our bounds.
bool ContainsMouse();
// Returns the first ancestor (starting at |this|) with a layer. |offset| is
// set to the offset from |this| to the first ancestor with a layer.
Window* GetAncestorWithLayer(gfx::Vector2d* offset) {
return const_cast<Window*>(
const_cast<const Window*>(this)->GetAncestorWithLayer(offset));
}
const Window* GetAncestorWithLayer(gfx::Vector2d* offset) const;
// Bounds of this window relative to the parent. This is cached as the bounds
// of the Layer and Window are not necessarily the same. In particular bounds
// of the Layer are relative to the first ancestor with a Layer, where as this
// is relative to the parent Window.
gfx::Rect bounds_;
WindowEventDispatcher* dispatcher_;
client::WindowType type_;
......
// Copyright (c) 2012 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_AURA_WINDOW_LAYER_TYPE_H_
#define UI_AURA_WINDOW_LAYER_TYPE_H_
namespace aura {
// These constants mirror that of ui::LayerType with the addition of
// WINDOW_LAYER_NONE. See ui::LayerType for description of ones in common.
enum WindowLayerType {
// Note that Windows with WINDOW_LAYER_NONE impose limitations on the
// Window: transforms and animations aren't supported.
WINDOW_LAYER_NONE,
WINDOW_LAYER_NOT_DRAWN,
WINDOW_LAYER_TEXTURED,
WINDOW_LAYER_SOLID_COLOR,
};
} // namespace aura
#endif // UI_AURA_WINDOW_LAYER_TYPE_H_
......@@ -40,6 +40,7 @@
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/screen.h"
#include "ui/gfx/skia_util.h"
DECLARE_WINDOW_PROPERTY_TYPE(const char*)
DECLARE_WINDOW_PROPERTY_TYPE(int)
......@@ -2879,7 +2880,7 @@ TEST_F(WindowTest, DelegateNotifiedAsBoundsChangeInHiddenLayer) {
// No bounds changed notification at the end of animation since layer
// delegate is NULL.
EXPECT_FALSE(delegate.bounds_changed());
EXPECT_NE("0,0 100x100", window->bounds().ToString());
EXPECT_NE("0,0 100x100", window->layer()->bounds().ToString());
}
namespace {
......@@ -3185,5 +3186,185 @@ TEST_F(WindowTest, NotifyDelegateAfterDeletingTransients) {
EXPECT_EQ("parent", destruction_order[1]);
}
// Verifies SchedulePaint() on a layerless window results in damaging the right
// thing.
TEST_F(WindowTest, LayerlessWindowSchedulePaint) {
Window root(NULL);
root.Init(ui::LAYER_NOT_DRAWN);
root.SetBounds(gfx::Rect(0, 0, 100, 100));
Window* layerless_window = new Window(NULL); // Owned by |root|.
layerless_window->InitWithWindowLayerType(WINDOW_LAYER_NONE);
layerless_window->SetBounds(gfx::Rect(10, 11, 12, 13));
root.AddChild(layerless_window);
root.layer()->SendDamagedRects();
layerless_window->SchedulePaintInRect(gfx::Rect(1, 2, 100, 4));
// Note the the region is clipped by the parent hence 100 going to 11.
EXPECT_EQ("11,13 11x4",
gfx::SkIRectToRect(root.layer()->damaged_region().getBounds()).
ToString());
Window* layerless_window2 = new Window(NULL); // Owned by |layerless_window|.
layerless_window2->InitWithWindowLayerType(WINDOW_LAYER_NONE);
layerless_window2->SetBounds(gfx::Rect(1, 2, 3, 4));
layerless_window->AddChild(layerless_window2);
root.layer()->SendDamagedRects();
layerless_window2->SchedulePaintInRect(gfx::Rect(1, 2, 100, 4));
// Note the the region is clipped by the |layerless_window| hence 100 going to
// 2.
EXPECT_EQ("12,15 2x2",
gfx::SkIRectToRect(root.layer()->damaged_region().getBounds()).
ToString());
}
// Verifies bounds of layerless windows are correctly updated when adding
// removing.
TEST_F(WindowTest, NestedLayerlessWindowsBoundsOnAddRemove) {
// Creates the following structure (all children owned by root):
// root
// w1ll 1,2
// w11ll 3,4
// w111 5,6
// w12 7,8
// w121 9,10
//
// ll: layer less, eg no layer
Window root(NULL);
root.InitWithWindowLayerType(WINDOW_LAYER_NOT_DRAWN);
root.SetBounds(gfx::Rect(0, 0, 100, 100));
Window* w1ll = new Window(NULL);
w1ll->InitWithWindowLayerType(WINDOW_LAYER_NONE);
w1ll->SetBounds(gfx::Rect(1, 2, 100, 100));
Window* w11ll = new Window(NULL);
w11ll->InitWithWindowLayerType(WINDOW_LAYER_NONE);
w11ll->SetBounds(gfx::Rect(3, 4, 100, 100));
w1ll->AddChild(w11ll);
Window* w111 = new Window(NULL);
w111->InitWithWindowLayerType(WINDOW_LAYER_NOT_DRAWN);
w111->SetBounds(gfx::Rect(5, 6, 100, 100));
w11ll->AddChild(w111);
Window* w12 = new Window(NULL);
w12->InitWithWindowLayerType(WINDOW_LAYER_NOT_DRAWN);
w12->SetBounds(gfx::Rect(7, 8, 100, 100));
w1ll->AddChild(w12);
Window* w121 = new Window(NULL);
w121->InitWithWindowLayerType(WINDOW_LAYER_NOT_DRAWN);
w121->SetBounds(gfx::Rect(9, 10, 100, 100));
w12->AddChild(w121);
root.AddChild(w1ll);
// All layers should be parented to the root.
EXPECT_EQ(root.layer(), w111->layer()->parent());
EXPECT_EQ(root.layer(), w12->layer()->parent());
EXPECT_EQ(w12->layer(), w121->layer()->parent());
// Ensure bounds are what we expect.
EXPECT_EQ("1,2 100x100", w1ll->bounds().ToString());
EXPECT_EQ("3,4 100x100", w11ll->bounds().ToString());
EXPECT_EQ("5,6 100x100", w111->bounds().ToString());
EXPECT_EQ("7,8 100x100", w12->bounds().ToString());
EXPECT_EQ("9,10 100x100", w121->bounds().ToString());
// Bounds of layers are relative to the nearest ancestor with a layer.
EXPECT_EQ("8,10 100x100", w12->layer()->bounds().ToString());
EXPECT_EQ("9,12 100x100", w111->layer()->bounds().ToString());
EXPECT_EQ("9,10 100x100", w121->layer()->bounds().ToString());
// Remove and repeat.
root.RemoveChild(w1ll);
EXPECT_TRUE(w111->layer()->parent() == NULL);
EXPECT_TRUE(w12->layer()->parent() == NULL);
// Verify bounds haven't changed again.
EXPECT_EQ("1,2 100x100", w1ll->bounds().ToString());
EXPECT_EQ("3,4 100x100", w11ll->bounds().ToString());
EXPECT_EQ("5,6 100x100", w111->bounds().ToString());
EXPECT_EQ("7,8 100x100", w12->bounds().ToString());
EXPECT_EQ("9,10 100x100", w121->bounds().ToString());
// Bounds of layers should now match that of windows.
EXPECT_EQ("7,8 100x100", w12->layer()->bounds().ToString());
EXPECT_EQ("5,6 100x100", w111->layer()->bounds().ToString());
EXPECT_EQ("9,10 100x100", w121->layer()->bounds().ToString());
delete w1ll;
}
// Verifies bounds of layerless windows are correctly updated when bounds
// of ancestor changes.
TEST_F(WindowTest, NestedLayerlessWindowsBoundsOnSetBounds) {
// Creates the following structure (all children owned by root):
// root
// w1ll 1,2
// w11ll 3,4
// w111 5,6
// w12 7,8
// w121 9,10
//
// ll: layer less, eg no layer
Window root(NULL);
root.InitWithWindowLayerType(WINDOW_LAYER_NOT_DRAWN);
root.SetBounds(gfx::Rect(0, 0, 100, 100));
Window* w1ll = new Window(NULL);
w1ll->InitWithWindowLayerType(WINDOW_LAYER_NONE);
w1ll->SetBounds(gfx::Rect(1, 2, 100, 100));
Window* w11ll = new Window(NULL);
w11ll->InitWithWindowLayerType(WINDOW_LAYER_NONE);
w11ll->SetBounds(gfx::Rect(3, 4, 100, 100));
w1ll->AddChild(w11ll);
Window* w111 = new Window(NULL);
w111->InitWithWindowLayerType(WINDOW_LAYER_NOT_DRAWN);
w111->SetBounds(gfx::Rect(5, 6, 100, 100));
w11ll->AddChild(w111);
Window* w12 = new Window(NULL);
w12->InitWithWindowLayerType(WINDOW_LAYER_NOT_DRAWN);
w12->SetBounds(gfx::Rect(7, 8, 100, 100));
w1ll->AddChild(w12);
Window* w121 = new Window(NULL);
w121->InitWithWindowLayerType(WINDOW_LAYER_NOT_DRAWN);
w121->SetBounds(gfx::Rect(9, 10, 100, 100));
w12->AddChild(w121);
root.AddChild(w1ll);
w111->SetBounds(gfx::Rect(7, 8, 11, 12));
EXPECT_EQ("7,8 11x12", w111->bounds().ToString());
EXPECT_EQ("11,14 11x12", w111->layer()->bounds().ToString());
// Set back.
w111->SetBounds(gfx::Rect(5, 6, 100, 100));
EXPECT_EQ("5,6 100x100", w111->bounds().ToString());
EXPECT_EQ("9,12 100x100", w111->layer()->bounds().ToString());
// Setting the bounds of a layerless window needs to adjust the bounds of
// layered children.
w11ll->SetBounds(gfx::Rect(5, 6, 100, 100));
EXPECT_EQ("5,6 100x100", w11ll->bounds().ToString());
EXPECT_EQ("5,6 100x100", w111->bounds().ToString());
EXPECT_EQ("11,14 100x100", w111->layer()->bounds().ToString());
root.RemoveChild(w1ll);
w111->SetBounds(gfx::Rect(7, 8, 11, 12));
EXPECT_EQ("7,8 11x12", w111->bounds().ToString());
EXPECT_EQ("7,8 11x12", w111->layer()->bounds().ToString());
delete w1ll;
}
} // namespace test
} // namespace aura
......@@ -287,6 +287,8 @@ class COMPOSITOR_EXPORT Layer
// |compostior_| to repaint the content.
void SendDamagedRects();
const SkRegion& damaged_region() const { return damaged_region_; }
// Suppresses painting the content by disgarding damaged region and ignoring
// new paint requests.
void SuppressPaint();
......
......@@ -5,10 +5,10 @@
#ifndef UI_VIEWS_FOCUS_BORDER_H_
#define UI_VIEWS_FOCUS_BORDER_H_
#include "base/basictypes.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/insets.h"
#include "ui/views/views_export.h"
#include "base/basictypes.h"
namespace gfx {
class Canvas;
......
......@@ -1110,12 +1110,11 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
// recurses through all children. This is used when adding a layer to an
// existing view to make sure all descendants that have layers are parented to
// the right layer.
virtual void MoveLayerToParent(ui::Layer* parent_layer,
const gfx::Point& point);
void MoveLayerToParent(ui::Layer* parent_layer, const gfx::Point& point);
// Called to update the bounds of any child layers within this View's
// hierarchy when something happens to the hierarchy.
virtual void UpdateChildLayerBounds(const gfx::Vector2d& offset);
void UpdateChildLayerBounds(const gfx::Vector2d& offset);
// Overridden from ui::LayerDelegate:
virtual void OnPaintLayer(gfx::Canvas* canvas) OVERRIDE;
......
......@@ -343,11 +343,11 @@
'touchui/touch_selection_controller_impl.h',
'view.cc',
'view.h',
'view_aura.cc',
'view_constants.cc',
'view_constants.h',
'view_constants_aura.cc',
'view_constants_aura.h',
'view_aura.cc',
'view_model.cc',
'view_model.h',
'view_model_utils.cc',
......
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