Chromium Code Reviews| Index: ui/aura/window.cc |
| diff --git a/ui/aura/window.cc b/ui/aura/window.cc |
| index e421789684a33322112b4f43b90896f75cd0f56c..d39a54329cbb7e9c7420997bb0ba320c96945bbe 100644 |
| --- a/ui/aura/window.cc |
| +++ b/ui/aura/window.cc |
| @@ -35,6 +35,38 @@ |
| namespace aura { |
| +namespace { |
| + |
| +WindowLayerType UILayerTypeToWindowLayerType(ui::LayerType layer_type) { |
| + switch (layer_type) { |
| + case ui::LAYER_NOT_DRAWN: |
| + return WINDOW_LAYER_NOT_DRAWN; |
| + case ui::LAYER_TEXTURED: |
| + return WINDOW_LAYER_TEXTURED; |
| + case ui::LAYER_SOLID_COLOR: |
| + return WINDOW_LAYER_SOLID_COLOR; |
| + } |
| + NOTREACHED(); |
| + return WINDOW_LAYER_NOT_DRAWN; |
| +} |
| + |
| +ui::LayerType WindowLayerTypeToUILayerType(WindowLayerType window_layer_type) { |
| + switch (window_layer_type) { |
| + case WINDOW_LAYER_NONE: |
| + break; |
| + case WINDOW_LAYER_NOT_DRAWN: |
| + return ui::LAYER_NOT_DRAWN; |
| + case WINDOW_LAYER_TEXTURED: |
| + return ui::LAYER_TEXTURED; |
| + case WINDOW_LAYER_SOLID_COLOR: |
| + return ui::LAYER_SOLID_COLOR; |
| + } |
| + NOTREACHED(); |
| + return ui::LAYER_NOT_DRAWN; |
| +} |
| + |
| +} // namespace |
| + |
| class ScopedCursorHider { |
| public: |
| explicit ScopedCursorHider(Window* window) |
| @@ -77,7 +109,8 @@ class ScopedCursorHider { |
| }; |
| Window::Window(WindowDelegate* delegate) |
| - : dispatcher_(NULL), |
| + : window_layer_type_(WINDOW_LAYER_NOT_DRAWN), |
| + dispatcher_(NULL), |
| type_(client::WINDOW_TYPE_UNKNOWN), |
| owned_by_parent_(true), |
| delegate_(delegate), |
| @@ -154,12 +187,20 @@ Window::~Window() { |
| } |
| void Window::Init(ui::LayerType layer_type) { |
| - layer_ = new ui::Layer(layer_type); |
| - layer_owner_.reset(layer_); |
| - layer_->SetVisible(false); |
| - layer_->set_delegate(this); |
| - UpdateLayerName(name_); |
| - layer_->SetFillsBoundsOpaquely(!transparent_); |
| + InitWithWindowLayerType(UILayerTypeToWindowLayerType(layer_type)); |
| +} |
| + |
| +void Window::InitWithWindowLayerType(WindowLayerType window_layer_type) { |
| + window_layer_type_ = window_layer_type; |
| + |
| + if (window_layer_type != WINDOW_LAYER_NONE) { |
| + layer_ = new ui::Layer(WindowLayerTypeToUILayerType(window_layer_type)); |
| + layer_owner_.reset(layer_); |
| + layer_->SetVisible(false); |
| + layer_->set_delegate(this); |
| + UpdateLayerName(name_); |
| + layer_->SetFillsBoundsOpaquely(!transparent_); |
| + } |
| Env::GetInstance()->NotifyWindowInitialized(this); |
| } |
| @@ -203,20 +244,20 @@ ui::Layer* Window::RecreateLayer() { |
| void Window::SetType(client::WindowType type) { |
| // Cannot change type after the window is initialized. |
| - DCHECK(!layer()); |
| + DCHECK(!layer_); |
| type_ = type; |
| } |
| void Window::SetName(const std::string& name) { |
| name_ = name; |
| - if (layer()) |
| + if (layer_) |
| UpdateLayerName(name_); |
| } |
| void Window::SetTransparent(bool transparent) { |
| transparent_ = transparent; |
| - if (layer()) |
| + if (layer_) |
| layer_->SetFillsBoundsOpaquely(!transparent_); |
| } |
| @@ -257,7 +298,13 @@ bool Window::IsVisible() const { |
| // when a Window is hidden, we want this function to return false immediately |
| // after, even though the client may decide to animate the hide effect (and |
| // so the layer will be visible for some time after Hide() is called). |
| - return visible_ && layer_ && layer_->IsDrawn(); |
| + for (const Window* window = this; window; window = window->parent()) { |
| + if (!window->visible_) |
| + return false; |
| + if (window->layer_) |
| + return window->layer_->IsDrawn(); |
| + } |
| + return false; |
| } |
| gfx::Rect Window::GetBoundsInRootWindow() const { |
| @@ -287,10 +334,15 @@ gfx::Rect Window::GetBoundsInScreen() const { |
| } |
| void Window::SetTransform(const gfx::Transform& transform) { |
| + if (is_layerless()) { |
| + // Transforms aren't supported on layerless windows. |
| + NOTREACHED(); |
| + return; |
| + } |
| WindowEventDispatcher* dispatcher = GetDispatcher(); |
| bool contained_mouse = IsVisible() && dispatcher && |
| ContainsPointInRoot(dispatcher->GetLastMouseLocationInRoot()); |
| - layer()->SetTransform(transform); |
| + layer_->SetTransform(transform); |
| if (dispatcher) |
| dispatcher->OnWindowTransformed(this, contained_mouse); |
| } |
| @@ -330,15 +382,20 @@ void Window::SetBoundsInScreen(const gfx::Rect& new_bounds_in_screen, |
| } |
| gfx::Rect Window::GetTargetBounds() const { |
| - return layer_->GetTargetBounds(); |
| -} |
| - |
| -const gfx::Rect& Window::bounds() const { |
| - return layer_->bounds(); |
| + // TODO(sky): this needs to be updated when there is a layerless ancestor. |
| + return is_layerless() ? bounds() : layer_->GetTargetBounds(); |
| } |
| void Window::SchedulePaintInRect(const gfx::Rect& rect) { |
| - if (layer_->SchedulePaint(rect)) { |
| + if (is_layerless() && parent_) { |
| + // Notification of paint scheduled happens for the window with a layer. |
| + gfx::Rect parent_rect(bounds().size()); |
| + parent_rect.Intersect(rect); |
| + if (!parent_rect.IsEmpty()) { |
| + parent_rect.Offset(bounds().origin().OffsetFromOrigin()); |
| + parent_->SchedulePaintInRect(parent_rect); |
| + } |
| + } else if (layer_ && layer_->SchedulePaint(rect)) { |
| FOR_EACH_OBSERVER( |
| WindowObserver, observers_, OnWindowPaintScheduled(this, rect)); |
| } |
| @@ -378,9 +435,15 @@ void Window::AddChild(Window* child) { |
| children_.end()); |
| if (child->parent()) |
| child->parent()->RemoveChildImpl(child, this); |
| - child->parent_ = this; |
| - layer_->Add(child->layer_); |
| + gfx::Vector2d offset; |
| + aura::Window* ancestor_with_layer = GetAncestorWithLayer(&offset); |
| + if (ancestor_with_layer) { |
| + offset += child->bounds().OffsetFromOrigin(); |
| + child->ReparentLayers(ancestor_with_layer->layer(), offset); |
| + } |
| + |
| + child->parent_ = this; |
| children_.push_back(child); |
| if (layout_manager_) |
| @@ -473,7 +536,7 @@ void Window::ConvertPointToTarget(const Window* source, |
| client::GetScreenPositionClient(target->GetRootWindow()); |
| target_client->ConvertPointFromScreen(target, point); |
| } else { |
| - ui::Layer::ConvertPointToLayer(source->layer(), target->layer(), point); |
| + ui::Layer::ConvertPointToLayer(source->layer_, target->layer_, point); |
| } |
| } |
| @@ -743,13 +806,27 @@ void Window::SetBoundsInternal(const gfx::Rect& new_bounds) { |
| // Always need to set the layer's bounds -- even if it is to the same thing. |
| // This may cause important side effects such as stopping animation. |
| - layer_->SetBounds(actual_new_bounds); |
| + if (is_layerless()) { |
| + const gfx::Vector2d origin_delta = new_bounds.OffsetFromOrigin() - |
| + bounds_.OffsetFromOrigin(); |
| + bounds_ = new_bounds; |
| + OffsetLayerBounds(origin_delta); |
| + } else { |
| + if (parent_ && parent_->is_layerless()) { |
| + gfx::Vector2d offset; |
| + const aura::Window* ancestor_with_layer = |
| + parent_->GetAncestorWithLayer(&offset); |
| + if (ancestor_with_layer) |
| + actual_new_bounds.Offset(offset); |
| + } |
| + layer_->SetBounds(actual_new_bounds); |
| + } |
| // If we are currently not the layer's delegate, we will not get bounds |
| // changed notification from the layer (this typically happens after animating |
| // hidden). We must notify ourselves. |
| - if (layer_->delegate() != this) |
| - OnLayerBoundsChanged(old_bounds, ContainsMouse()); |
| + if (is_layerless() || layer_->delegate() != this) |
| + OnWindowBoundsChanged(old_bounds, ContainsMouse()); |
| } |
| void Window::SetVisible(bool visible) { |
| @@ -854,12 +931,11 @@ void Window::RemoveChildImpl(Window* child, Window* new_parent) { |
| child, new_root_window); |
| child->NotifyRemovingFromRootWindow(); |
| } |
| + |
| + gfx::Vector2d offset; |
| + GetAncestorWithLayer(&offset); |
| + child->UnparentLayers(is_layerless(), offset); |
| child->parent_ = NULL; |
| - // We should only remove the child's layer if the child still owns that layer. |
| - // Someone else may have acquired ownership of it via AcquireLayer() and may |
| - // expect the hierarchy to go unchanged as the Window is destroyed. |
| - if (child->layer_owner_) |
| - layer_->Remove(child->layer_); |
| Windows::iterator i = std::find(children_.begin(), children_.end(), child); |
| DCHECK(i != children_.end()); |
| children_.erase(i); |
| @@ -868,6 +944,60 @@ void Window::RemoveChildImpl(Window* child, Window* new_parent) { |
| layout_manager_->OnWindowRemovedFromLayout(child); |
| } |
| +void Window::UnparentLayers(bool has_layerless_ancestor, |
| + const gfx::Vector2d& offset) { |
| + if (is_layerless()) { |
| + const gfx::Vector2d new_offset = offset + bounds().OffsetFromOrigin(); |
| + for (size_t i = 0; i < children_.size(); ++i) { |
| + children_[i]->UnparentLayers(true, new_offset); |
| + } |
| + } else { |
| + // We should only remove the child's layer if the child still owns that |
|
Ben Goodger (Google)
2013/11/22 05:49:24
use of the term "child" here is confusing.
// We
sky
2013/11/22 20:20:12
Ya, sorry, I copied this comment from 858 old wher
|
| + // layer. Someone else may have acquired ownership of it via AcquireLayer() |
| + // and may expect the hierarchy to go unchanged as the Window is destroyed. |
| + if (layer_owner_) { |
| + if (layer_->parent()) |
| + layer_->parent()->Remove(layer_); |
| + if (has_layerless_ancestor) { |
| + const gfx::Rect real_bounds(bounds_); |
| + gfx::Rect layer_bounds(layer_->bounds()); |
| + layer_bounds.Offset(-offset); |
| + layer_->SetBounds(layer_bounds); |
| + bounds_ = real_bounds; |
| + } |
| + } |
| + } |
| +} |
| + |
| +void Window::ReparentLayers(ui::Layer* parent_layer, |
| + const gfx::Vector2d& offset) { |
| + if (is_layerless()) { |
| + for (size_t i = 0; i < children_.size(); ++i) { |
| + children_[i]->ReparentLayers( |
| + parent_layer, |
| + offset + children_[i]->bounds().OffsetFromOrigin()); |
| + } |
| + } else { |
| + const gfx::Rect real_bounds(bounds()); |
| + parent_layer->Add(layer_); |
| + gfx::Rect layer_bounds(layer_->bounds().size()); |
| + layer_bounds += offset; |
| + layer_->SetBounds(layer_bounds); |
| + bounds_ = real_bounds; |
| + } |
| +} |
| + |
| +void Window::OffsetLayerBounds(const gfx::Vector2d& offset) { |
| + if (is_layerless()) { |
| + for (size_t i = 0; i < children_.size(); ++i) |
| + children_[i]->OffsetLayerBounds(offset); |
| + } else { |
| + gfx::Rect layer_bounds(layer_->bounds()); |
| + layer_bounds += offset; |
| + layer_->SetBounds(layer_bounds); |
| + } |
| +} |
| + |
| void Window::OnParentChanged() { |
| FOR_EACH_OBSERVER( |
| WindowObserver, observers_, OnWindowParentChanged(this, parent_)); |
| @@ -946,7 +1076,7 @@ void Window::StackChildRelativeTo(Window* child, |
| // for an explanation of this. |
| while (final_target_i > 0 && |
| children_[direction == STACK_ABOVE ? final_target_i : |
| - final_target_i - 1]->layer() |
| + final_target_i - 1]->layer_ |
| ->delegate() == NULL) { |
| --final_target_i; |
| } |
| @@ -954,7 +1084,7 @@ void Window::StackChildRelativeTo(Window* child, |
| Window* final_target = children_[final_target_i]; |
| // If we couldn't find a valid target position, don't move anything. |
| - if (direction == STACK_ABOVE && final_target->layer()->delegate() == NULL) |
| + if (direction == STACK_ABOVE && final_target->layer_->delegate() == NULL) |
| return; |
| // Don't try to stack a child above itself. |
| @@ -1006,9 +1136,9 @@ void Window::StackChildRelativeToImpl(Window* child, |
| children_.insert(children_.begin() + dest_i, child); |
| if (direction == STACK_ABOVE) |
| - layer()->StackAbove(child->layer(), target->layer()); |
| + layer_->StackAbove(child->layer_, target->layer_); |
| else |
| - layer()->StackBelow(child->layer(), target->layer()); |
| + layer_->StackBelow(child->layer_, target->layer_); |
| child->OnStackingChanged(); |
| } |
| @@ -1139,8 +1269,19 @@ void Window::NotifyWindowVisibilityChangedUp(aura::Window* target, |
| } |
| } |
| -void Window::OnLayerBoundsChanged(const gfx::Rect& old_bounds, |
| - bool contained_mouse) { |
| +void Window::OnWindowBoundsChanged(const gfx::Rect& old_bounds, |
| + bool contained_mouse) { |
| + if (layer_) { |
| + bounds_ = layer_->bounds(); |
| + if (parent_ && parent_->is_layerless()) { |
| + gfx::Vector2d offset; |
| + aura::Window* ancestor_with_layer = |
| + parent_->GetAncestorWithLayer(&offset); |
| + if (ancestor_with_layer) |
| + bounds_.Offset(-offset); |
| + } |
| + } |
| + |
| if (layout_manager_) |
| layout_manager_->OnWindowResized(); |
| if (delegate_) |
| @@ -1159,7 +1300,7 @@ void Window::OnPaintLayer(gfx::Canvas* canvas) { |
| } |
| base::Closure Window::PrepareForLayerBoundsChange() { |
| - return base::Bind(&Window::OnLayerBoundsChanged, base::Unretained(this), |
| + return base::Bind(&Window::OnWindowBoundsChanged, base::Unretained(this), |
| bounds(), ContainsMouse()); |
| } |
| @@ -1194,7 +1335,7 @@ ui::EventTarget* Window::GetParentTarget() { |
| void Window::UpdateLayerName(const std::string& name) { |
| #if !defined(NDEBUG) |
| - DCHECK(layer()); |
| + DCHECK(layer_); |
| std::string layer_name(name_); |
| if (layer_name.empty()) |
| @@ -1205,7 +1346,7 @@ void Window::UpdateLayerName(const std::string& name) { |
| base::snprintf(id_buf, sizeof(id_buf), " %d", id_); |
| layer_name.append(id_buf); |
| } |
| - layer()->set_name(layer_name); |
| + layer_->set_name(layer_name); |
| #endif |
| } |
| @@ -1219,4 +1360,14 @@ bool Window::ContainsMouse() { |
| return contains_mouse; |
| } |
| +const Window* Window::GetAncestorWithLayer(gfx::Vector2d* offset) const { |
| + for (const aura::Window* window = this; window; window = window->parent()) { |
| + if (!window->is_layerless()) |
| + return window; |
| + *offset += window->bounds().OffsetFromOrigin(); |
| + } |
| + *offset = gfx::Vector2d(); |
| + return NULL; |
| +} |
| + |
| } // namespace aura |