Battery Status API: add UMA logging for Linux.
[chromium-blink-merge.git] / mojo / services / public / cpp / view_manager / lib / view.cc
blobd2f6f54efb84b7909a3bf1a7bd1aba622dc13218
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.
5 #include "mojo/services/public/cpp/view_manager/view.h"
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"
13 namespace mojo {
15 namespace {
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));
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);
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);
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);
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);
70 ~ScopedTreeNotifier() {
71 NotifyViewTreeChange(params_, true);
74 private:
75 ViewObserver::TreeChangeParams params_;
77 DISALLOW_COPY_AND_ASSIGN(ScopedTreeNotifier);
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();
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_));
101 ~ScopedOrderChangedNotifier() {
102 FOR_EACH_OBSERVER(ViewObserver,
103 *ViewPrivate(view_).observers(),
104 OnViewReordered(view_, relative_view_, direction_));
107 private:
108 View* view_;
109 View* relative_view_;
110 OrderDirection direction_;
112 DISALLOW_COPY_AND_ASSIGN(ScopedOrderChangedNotifier);
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());
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;
134 ScopedOrderChangedNotifier notifier(view, relative, direction);
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);
142 return true;
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_));
157 ~ScopedSetBoundsNotifier() {
158 FOR_EACH_OBSERVER(ViewObserver,
159 *ViewPrivate(view_).observers(),
160 OnViewBoundsChanged(view_, old_bounds_, new_bounds_));
163 private:
164 View* view_;
165 const gfx::Rect old_bounds_;
166 const gfx::Rect new_bounds_;
168 DISALLOW_COPY_AND_ASSIGN(ScopedSetBoundsNotifier);
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());
177 } // namespace
179 ////////////////////////////////////////////////////////////////////////////////
180 // View, public:
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;
189 void View::Destroy() {
190 if (!OwnsView(manager_, this))
191 return;
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());
206 LocalDestroy();
209 void View::SetBounds(const gfx::Rect& bounds) {
210 if (!OwnsView(manager_, this))
211 return;
213 if (manager_)
214 static_cast<ViewManagerClientImpl*>(manager_)->SetBounds(id_, bounds);
215 LocalSetBounds(bounds_, bounds);
218 void View::SetVisible(bool value) {
219 if (manager_)
220 static_cast<ViewManagerClientImpl*>(manager_)->SetVisible(id_, value);
223 void View::AddObserver(ViewObserver* observer) {
224 observers_.AddObserver(observer);
227 void View::RemoveObserver(ViewObserver* observer) {
228 observers_.RemoveObserver(observer);
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_);
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_);
253 void View::MoveToFront() {
254 Reorder(parent_->children_.back(), ORDER_DIRECTION_ABOVE);
257 void View::MoveToBack() {
258 Reorder(parent_->children_.front(), ORDER_DIRECTION_BELOW);
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);
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;
278 return false;
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;
291 return NULL;
294 void View::SetContents(const SkBitmap& contents) {
295 if (manager_) {
296 static_cast<ViewManagerClientImpl*>(manager_)->SetViewContents(id_,
297 contents);
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));
307 void View::SetFocus() {
308 if (manager_)
309 static_cast<ViewManagerClientImpl*>(manager_)->SetFocus(id_);
312 void View::Embed(const String& url) {
313 static_cast<ViewManagerClientImpl*>(manager_)->Embed(url, id_);
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());
327 static_cast<ViewManagerClientImpl*>(manager_)->Embed(url, id_, sp.Pass());
328 return imported_services.Pass();
331 ////////////////////////////////////////////////////////////////////////////////
332 // View, protected:
334 View::View()
335 : manager_(NULL),
336 id_(static_cast<Id>(-1)),
337 parent_(NULL) {}
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));
350 ////////////////////////////////////////////////////////////////////////////////
351 // View, private:
353 View::View(ViewManager* manager)
354 : manager_(manager),
355 id_(static_cast<ViewManagerClientImpl*>(manager_)->CreateView()),
356 parent_(NULL) {}
358 void View::LocalDestroy() {
359 delete this;
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;
370 void View::LocalRemoveChild(View* child) {
371 DCHECK_EQ(this, child->parent());
372 ScopedTreeNotifier notifier(child, this, NULL);
373 RemoveChildImpl(child, &children_);
376 bool View::LocalReorder(View* relative, OrderDirection direction) {
377 return ReorderImpl(&parent_->children_, this, relative, direction);
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;
387 } // namespace mojo