Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / mojo / services / public / cpp / view_manager / lib / view.cc
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/public/cpp/view_manager/view.h"
6
7 #include "mojo/public/cpp/application/service_provider_impl.h"
8 #include "mojo/services/public/cpp/view_manager/lib/view_manager_client_impl.h"
9 #include "mojo/services/public/cpp/view_manager/lib/view_private.h"
10 #include "mojo/services/public/cpp/view_manager/view_observer.h"
11 #include "ui/gfx/canvas.h"
12
13 namespace mojo {
14
15 namespace {
16
17 void NotifyViewTreeChangeAtReceiver(
18     View* receiver,
19     const ViewObserver::TreeChangeParams& params,
20     bool change_applied) {
21   ViewObserver::TreeChangeParams local_params = params;
22   local_params.receiver = receiver;
23   if (change_applied) {
24     FOR_EACH_OBSERVER(ViewObserver,
25                       *ViewPrivate(receiver).observers(),
26                       OnTreeChanged(local_params));
27   } else {
28     FOR_EACH_OBSERVER(ViewObserver,
29                       *ViewPrivate(receiver).observers(),
30                       OnTreeChanging(local_params));
31   }
32 }
33
34 void NotifyViewTreeChangeUp(
35     View* start_at,
36     const ViewObserver::TreeChangeParams& params,
37     bool change_applied) {
38   for (View* current = start_at; current; current = current->parent())
39     NotifyViewTreeChangeAtReceiver(current, params, change_applied);
40 }
41
42 void NotifyViewTreeChangeDown(
43     View* start_at,
44     const ViewObserver::TreeChangeParams& params,
45     bool change_applied) {
46   NotifyViewTreeChangeAtReceiver(start_at, params, change_applied);
47   View::Children::const_iterator it = start_at->children().begin();
48   for (; it != start_at->children().end(); ++it)
49     NotifyViewTreeChangeDown(*it, params, change_applied);
50 }
51
52 void NotifyViewTreeChange(
53     const ViewObserver::TreeChangeParams& params,
54     bool change_applied) {
55   NotifyViewTreeChangeDown(params.target, params, change_applied);
56   if (params.old_parent)
57     NotifyViewTreeChangeUp(params.old_parent, params, change_applied);
58   if (params.new_parent)
59     NotifyViewTreeChangeUp(params.new_parent, params, change_applied);
60 }
61
62 class ScopedTreeNotifier {
63  public:
64   ScopedTreeNotifier(View* target, View* old_parent, View* new_parent) {
65     params_.target = target;
66     params_.old_parent = old_parent;
67     params_.new_parent = new_parent;
68     NotifyViewTreeChange(params_, false);
69   }
70   ~ScopedTreeNotifier() {
71     NotifyViewTreeChange(params_, true);
72   }
73
74  private:
75   ViewObserver::TreeChangeParams params_;
76
77   DISALLOW_COPY_AND_ASSIGN(ScopedTreeNotifier);
78 };
79
80 void RemoveChildImpl(View* child, View::Children* children) {
81   View::Children::iterator it =
82       std::find(children->begin(), children->end(), child);
83   if (it != children->end()) {
84     children->erase(it);
85     ViewPrivate(child).ClearParent();
86   }
87 }
88
89 class ScopedOrderChangedNotifier {
90  public:
91   ScopedOrderChangedNotifier(View* view,
92                              View* relative_view,
93                              OrderDirection direction)
94       : view_(view),
95         relative_view_(relative_view),
96         direction_(direction) {
97     FOR_EACH_OBSERVER(ViewObserver,
98                       *ViewPrivate(view_).observers(),
99                       OnViewReordering(view_, relative_view_, direction_));
100   }
101   ~ScopedOrderChangedNotifier() {
102     FOR_EACH_OBSERVER(ViewObserver,
103                       *ViewPrivate(view_).observers(),
104                       OnViewReordered(view_, relative_view_, direction_));
105   }
106
107  private:
108   View* view_;
109   View* relative_view_;
110   OrderDirection direction_;
111
112   DISALLOW_COPY_AND_ASSIGN(ScopedOrderChangedNotifier);
113 };
114
115 // Returns true if the order actually changed.
116 bool ReorderImpl(View::Children* children,
117                  View* view,
118                  View* relative,
119                  OrderDirection direction) {
120   DCHECK(relative);
121   DCHECK_NE(view, relative);
122   DCHECK_EQ(view->parent(), relative->parent());
123
124   const size_t child_i =
125       std::find(children->begin(), children->end(), view) - children->begin();
126   const size_t target_i =
127       std::find(children->begin(), children->end(), relative) -
128       children->begin();
129   if ((direction == ORDER_DIRECTION_ABOVE && child_i == target_i + 1) ||
130       (direction == ORDER_DIRECTION_BELOW && child_i + 1 == target_i)) {
131     return false;
132   }
133
134   ScopedOrderChangedNotifier notifier(view, relative, direction);
135
136   const size_t dest_i = direction == ORDER_DIRECTION_ABOVE
137                             ? (child_i < target_i ? target_i : target_i + 1)
138                             : (child_i < target_i ? target_i - 1 : target_i);
139   children->erase(children->begin() + child_i);
140   children->insert(children->begin() + dest_i, view);
141
142   return true;
143 }
144
145 class ScopedSetBoundsNotifier {
146  public:
147   ScopedSetBoundsNotifier(View* view,
148                           const gfx::Rect& old_bounds,
149                           const gfx::Rect& new_bounds)
150       : view_(view),
151         old_bounds_(old_bounds),
152         new_bounds_(new_bounds) {
153     FOR_EACH_OBSERVER(ViewObserver,
154                       *ViewPrivate(view_).observers(),
155                       OnViewBoundsChanging(view_, old_bounds_, new_bounds_));
156   }
157   ~ScopedSetBoundsNotifier() {
158     FOR_EACH_OBSERVER(ViewObserver,
159                       *ViewPrivate(view_).observers(),
160                       OnViewBoundsChanged(view_, old_bounds_, new_bounds_));
161   }
162
163  private:
164   View* view_;
165   const gfx::Rect old_bounds_;
166   const gfx::Rect new_bounds_;
167
168   DISALLOW_COPY_AND_ASSIGN(ScopedSetBoundsNotifier);
169 };
170
171 // Some operations are only permitted in the connection that created the view.
172 bool OwnsView(ViewManager* manager, View* view) {
173   return !manager ||
174       static_cast<ViewManagerClientImpl*>(manager)->OwnsView(view->id());
175 }
176
177 }  // namespace
178
179 ////////////////////////////////////////////////////////////////////////////////
180 // View, public:
181
182 // static
183 View* View::Create(ViewManager* view_manager) {
184   View* view = new View(view_manager);
185   static_cast<ViewManagerClientImpl*>(view_manager)->AddView(view);
186   return view;
187 }
188
189 void View::Destroy() {
190   if (!OwnsView(manager_, this))
191     return;
192
193   if (manager_)
194     static_cast<ViewManagerClientImpl*>(manager_)->DestroyView(id_);
195   while (!children_.empty()) {
196     View* child = children_.front();
197     if (!OwnsView(manager_, child)) {
198       ViewPrivate(child).ClearParent();
199       children_.erase(children_.begin());
200     } else {
201       child->Destroy();
202       DCHECK(std::find(children_.begin(), children_.end(), child) ==
203              children_.end());
204     }
205   }
206   LocalDestroy();
207 }
208
209 void View::SetBounds(const gfx::Rect& bounds) {
210   if (!OwnsView(manager_, this))
211     return;
212
213   if (manager_)
214     static_cast<ViewManagerClientImpl*>(manager_)->SetBounds(id_, bounds);
215   LocalSetBounds(bounds_, bounds);
216 }
217
218 void View::SetVisible(bool value) {
219   if (manager_)
220     static_cast<ViewManagerClientImpl*>(manager_)->SetVisible(id_, value);
221 }
222
223 void View::AddObserver(ViewObserver* observer) {
224   observers_.AddObserver(observer);
225 }
226
227 void View::RemoveObserver(ViewObserver* observer) {
228   observers_.RemoveObserver(observer);
229 }
230
231 void View::AddChild(View* child) {
232   // TODO(beng): not necessarily valid to all connections, but possibly to the
233   //             embeddee in an embedder-embeddee relationship.
234   if (manager_)
235     CHECK_EQ(ViewPrivate(child).view_manager(), manager_);
236   LocalAddChild(child);
237   if (manager_)
238     static_cast<ViewManagerClientImpl*>(manager_)->AddChild(child->id(), id_);
239 }
240
241 void View::RemoveChild(View* child) {
242   // TODO(beng): not necessarily valid to all connections, but possibly to the
243   //             embeddee in an embedder-embeddee relationship.
244   if (manager_)
245     CHECK_EQ(ViewPrivate(child).view_manager(), manager_);
246   LocalRemoveChild(child);
247   if (manager_) {
248     static_cast<ViewManagerClientImpl*>(manager_)->RemoveChild(child->id(),
249                                                                id_);
250   }
251 }
252
253 void View::MoveToFront() {
254   Reorder(parent_->children_.back(), ORDER_DIRECTION_ABOVE);
255 }
256
257 void View::MoveToBack() {
258   Reorder(parent_->children_.front(), ORDER_DIRECTION_BELOW);
259 }
260
261 void View::Reorder(View* relative, OrderDirection direction) {
262   if (!LocalReorder(relative, direction))
263     return;
264   if (manager_) {
265     static_cast<ViewManagerClientImpl*>(manager_)->Reorder(id_,
266                                                             relative->id(),
267                                                             direction);
268   }
269 }
270
271 bool View::Contains(View* child) const {
272   if (manager_)
273     CHECK_EQ(ViewPrivate(child).view_manager(), manager_);
274   for (View* p = child->parent(); p; p = p->parent()) {
275     if (p == this)
276       return true;
277   }
278   return false;
279 }
280
281 View* View::GetChildById(Id id) {
282   if (id == id_)
283     return this;
284   // TODO(beng): this could be improved depending on how we decide to own views.
285   Children::const_iterator it = children_.begin();
286   for (; it != children_.end(); ++it) {
287     View* view = (*it)->GetChildById(id);
288     if (view)
289       return view;
290   }
291   return NULL;
292 }
293
294 void View::SetContents(const SkBitmap& contents) {
295   if (manager_) {
296     static_cast<ViewManagerClientImpl*>(manager_)->SetViewContents(id_,
297         contents);
298   }
299 }
300
301 void View::SetColor(SkColor color) {
302   gfx::Canvas canvas(bounds_.size(), 1.0f, true);
303   canvas.DrawColor(color);
304   SetContents(skia::GetTopDevice(*canvas.sk_canvas())->accessBitmap(true));
305 }
306
307 void View::SetFocus() {
308   if (manager_)
309     static_cast<ViewManagerClientImpl*>(manager_)->SetFocus(id_);
310 }
311
312 void View::Embed(const String& url) {
313   static_cast<ViewManagerClientImpl*>(manager_)->Embed(url, id_);
314 }
315
316 scoped_ptr<ServiceProvider>
317     View::Embed(const String& url,
318                 scoped_ptr<ServiceProviderImpl> exported_services) {
319   scoped_ptr<ServiceProvider> imported_services;
320   // BindToProxy() takes ownership of |exported_services|.
321   ServiceProviderImpl* registry = exported_services.release();
322   ServiceProviderPtr sp;
323   if (registry) {
324     BindToProxy(registry, &sp);
325     imported_services.reset(registry->CreateRemoteServiceProvider());
326   }
327   static_cast<ViewManagerClientImpl*>(manager_)->Embed(url, id_, sp.Pass());
328   return imported_services.Pass();
329 }
330
331 ////////////////////////////////////////////////////////////////////////////////
332 // View, protected:
333
334 View::View()
335     : manager_(NULL),
336       id_(static_cast<Id>(-1)),
337       parent_(NULL) {}
338
339 View::~View() {
340   FOR_EACH_OBSERVER(ViewObserver, observers_, OnViewDestroying(this));
341   if (parent_)
342     parent_->LocalRemoveChild(this);
343   // TODO(beng): It'd be better to do this via a destruction observer in the
344   //             ViewManagerClientImpl.
345   if (manager_)
346     static_cast<ViewManagerClientImpl*>(manager_)->RemoveView(id_);
347   FOR_EACH_OBSERVER(ViewObserver, observers_, OnViewDestroyed(this));
348 }
349
350 ////////////////////////////////////////////////////////////////////////////////
351 // View, private:
352
353 View::View(ViewManager* manager)
354     : manager_(manager),
355       id_(static_cast<ViewManagerClientImpl*>(manager_)->CreateView()),
356       parent_(NULL) {}
357
358 void View::LocalDestroy() {
359   delete this;
360 }
361
362 void View::LocalAddChild(View* child) {
363   ScopedTreeNotifier notifier(child, child->parent(), this);
364   if (child->parent())
365     RemoveChildImpl(child, &child->parent_->children_);
366   children_.push_back(child);
367   child->parent_ = this;
368 }
369
370 void View::LocalRemoveChild(View* child) {
371   DCHECK_EQ(this, child->parent());
372   ScopedTreeNotifier notifier(child, this, NULL);
373   RemoveChildImpl(child, &children_);
374 }
375
376 bool View::LocalReorder(View* relative, OrderDirection direction) {
377   return ReorderImpl(&parent_->children_, this, relative, direction);
378 }
379
380 void View::LocalSetBounds(const gfx::Rect& old_bounds,
381                           const gfx::Rect& new_bounds) {
382   DCHECK(old_bounds == bounds_);
383   ScopedSetBoundsNotifier notifier(this, old_bounds, new_bounds);
384   bounds_ = new_bounds;
385 }
386
387 }  // namespace mojo