1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "mojo/services/view_manager/node.h"
6
7#include "mojo/services/view_manager/node_delegate.h"
8#include "mojo/services/view_manager/view.h"
9#include "ui/aura/window_property.h"
10#include "ui/base/cursor/cursor.h"
11#include "ui/base/hit_test.h"
12#include "ui/gfx/canvas.h"
13#include "ui/gfx/image/image_skia.h"
14#include "ui/gfx/native_widget_types.h"
15
16DECLARE_WINDOW_PROPERTY_TYPE(mojo::view_manager::service::Node*);
17
18namespace mojo {
19namespace view_manager {
20namespace service {
21
22DEFINE_WINDOW_PROPERTY_KEY(Node*, kNodeKey, NULL);
23
24Node::Node(NodeDelegate* delegate, const NodeId& id)
25    : delegate_(delegate),
26      id_(id),
27      view_(NULL),
28      window_(this) {
29  DCHECK(delegate);  // Must provide a delegate.
30  window_.set_owned_by_parent(false);
31  window_.AddObserver(this);
32  window_.SetProperty(kNodeKey, this);
33  window_.Init(aura::WINDOW_LAYER_TEXTURED);
34
35  // TODO(sky): this likely needs to be false and add a visibility API.
36  window_.Show();
37}
38
39Node::~Node() {
40  SetView(NULL);
41  // This is implicitly done during deletion of the window, but we do it here so
42  // that we're in a known state.
43  if (window_.parent())
44    window_.parent()->RemoveChild(&window_);
45}
46
47const Node* Node::GetParent() const {
48  if (!window_.parent())
49    return NULL;
50  return window_.parent()->GetProperty(kNodeKey);
51}
52
53void Node::Add(Node* child) {
54  window_.AddChild(&child->window_);
55}
56
57void Node::Remove(Node* child) {
58  window_.RemoveChild(&child->window_);
59}
60
61void Node::Reorder(Node* child, Node* relative, OrderDirection direction) {
62  if (direction == ORDER_ABOVE)
63    window_.StackChildAbove(child->window(), relative->window());
64  else if (direction == ORDER_BELOW)
65    window_.StackChildBelow(child->window(), relative->window());
66}
67
68const Node* Node::GetRoot() const {
69  const aura::Window* window = &window_;
70  while (window && window->parent())
71    window = window->parent();
72  return window->GetProperty(kNodeKey);
73}
74
75std::vector<const Node*> Node::GetChildren() const {
76  std::vector<const Node*> children;
77  children.reserve(window_.children().size());
78  for (size_t i = 0; i < window_.children().size(); ++i)
79    children.push_back(window_.children()[i]->GetProperty(kNodeKey));
80  return children;
81}
82
83std::vector<Node*> Node::GetChildren() {
84  std::vector<Node*> children;
85  children.reserve(window_.children().size());
86  for (size_t i = 0; i < window_.children().size(); ++i)
87    children.push_back(window_.children()[i]->GetProperty(kNodeKey));
88  return children;
89}
90
91bool Node::Contains(const Node* node) const {
92  return node && window_.Contains(&(node->window_));
93}
94
95void Node::SetView(View* view) {
96  if (view == view_)
97    return;
98
99  // Detach view from existing node. This way notifications are sent out.
100  if (view && view->node())
101    view->node()->SetView(NULL);
102
103  View* old_view = view_;
104  if (view_)
105    view_->set_node(NULL);
106  view_ = view;
107  if (view)
108    view->set_node(this);
109  delegate_->OnNodeViewReplaced(this, view, old_view);
110}
111
112void Node::OnWindowHierarchyChanged(
113    const aura::WindowObserver::HierarchyChangeParams& params) {
114  if (params.target != &window_ || params.receiver != &window_)
115    return;
116  const Node* new_parent = params.new_parent ?
117      params.new_parent->GetProperty(kNodeKey) : NULL;
118  const Node* old_parent = params.old_parent ?
119      params.old_parent->GetProperty(kNodeKey) : NULL;
120  delegate_->OnNodeHierarchyChanged(this, new_parent, old_parent);
121}
122
123gfx::Size Node::GetMinimumSize() const {
124  return gfx::Size();
125}
126
127gfx::Size Node::GetMaximumSize() const {
128  return gfx::Size();
129}
130
131void Node::OnBoundsChanged(const gfx::Rect& old_bounds,
132                           const gfx::Rect& new_bounds) {
133}
134
135gfx::NativeCursor Node::GetCursor(const gfx::Point& point) {
136  return gfx::kNullCursor;
137}
138
139int Node::GetNonClientComponent(const gfx::Point& point) const {
140  return HTCAPTION;
141}
142
143bool Node::ShouldDescendIntoChildForEventHandling(
144    aura::Window* child,
145    const gfx::Point& location) {
146  return true;
147}
148
149bool Node::CanFocus() {
150  return true;
151}
152
153void Node::OnCaptureLost() {
154}
155
156void Node::OnPaint(gfx::Canvas* canvas) {
157  if (view_) {
158    canvas->DrawImageInt(
159        gfx::ImageSkia::CreateFrom1xBitmap(view_->bitmap()), 0, 0);
160  }
161}
162
163void Node::OnDeviceScaleFactorChanged(float device_scale_factor) {
164}
165
166void Node::OnWindowDestroying(aura::Window* window) {
167}
168
169void Node::OnWindowDestroyed(aura::Window* window) {
170}
171
172void Node::OnWindowTargetVisibilityChanged(bool visible) {
173}
174
175bool Node::HasHitTestMask() const {
176  return false;
177}
178
179void Node::GetHitTestMask(gfx::Path* mask) const {
180}
181
182void Node::OnEvent(ui::Event* event) {
183  if (view_)
184    delegate_->OnViewInputEvent(view_, event);
185}
186
187}  // namespace service
188}  // namespace view_manager
189}  // namespace mojo
190