Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(627)

Side by Side Diff: mojo/services/view_manager/cpp/lib/view.cc

Issue 1531403003: Delete the ViewManager and WindowManager services. (Closed) Base URL: git@github.com:domokit/mojo.git@moz-3
Patch Set: rebase Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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 "view_manager/cpp/view.h"
6
7 #include <set>
8 #include <string>
9
10 #include "mojo/public/cpp/application/service_provider_impl.h"
11 #include "view_manager/cpp/lib/view_manager_client_impl.h"
12 #include "view_manager/cpp/lib/view_private.h"
13 #include "view_manager/cpp/view_observer.h"
14 #include "view_manager/cpp/view_tracker.h"
15
16 namespace mojo {
17
18 namespace {
19
20 void NotifyViewTreeChangeAtReceiver(
21 View* receiver,
22 const ViewObserver::TreeChangeParams& params,
23 bool change_applied) {
24 ViewObserver::TreeChangeParams local_params = params;
25 local_params.receiver = receiver;
26 if (change_applied) {
27 FOR_EACH_OBSERVER(ViewObserver, *ViewPrivate(receiver).observers(),
28 OnTreeChanged(local_params));
29 } else {
30 FOR_EACH_OBSERVER(ViewObserver, *ViewPrivate(receiver).observers(),
31 OnTreeChanging(local_params));
32 }
33 }
34
35 void NotifyViewTreeChangeUp(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(View* start_at,
43 const ViewObserver::TreeChangeParams& params,
44 bool change_applied) {
45 NotifyViewTreeChangeAtReceiver(start_at, params, change_applied);
46 View::Children::const_iterator it = start_at->children().begin();
47 for (; it != start_at->children().end(); ++it)
48 NotifyViewTreeChangeDown(*it, params, change_applied);
49 }
50
51 void NotifyViewTreeChange(const ViewObserver::TreeChangeParams& params,
52 bool change_applied) {
53 NotifyViewTreeChangeDown(params.target, params, change_applied);
54 if (params.old_parent)
55 NotifyViewTreeChangeUp(params.old_parent, params, change_applied);
56 if (params.new_parent)
57 NotifyViewTreeChangeUp(params.new_parent, params, change_applied);
58 }
59
60 class ScopedTreeNotifier {
61 public:
62 ScopedTreeNotifier(View* target, View* old_parent, View* new_parent) {
63 params_.target = target;
64 params_.old_parent = old_parent;
65 params_.new_parent = new_parent;
66 NotifyViewTreeChange(params_, false);
67 }
68 ~ScopedTreeNotifier() { NotifyViewTreeChange(params_, true); }
69
70 private:
71 ViewObserver::TreeChangeParams params_;
72
73 MOJO_DISALLOW_COPY_AND_ASSIGN(ScopedTreeNotifier);
74 };
75
76 void RemoveChildImpl(View* child, View::Children* children) {
77 View::Children::iterator it =
78 std::find(children->begin(), children->end(), child);
79 if (it != children->end()) {
80 children->erase(it);
81 ViewPrivate(child).ClearParent();
82 }
83 }
84
85 class ScopedOrderChangedNotifier {
86 public:
87 ScopedOrderChangedNotifier(View* view,
88 View* relative_view,
89 OrderDirection direction)
90 : view_(view), relative_view_(relative_view), direction_(direction) {
91 FOR_EACH_OBSERVER(ViewObserver, *ViewPrivate(view_).observers(),
92 OnViewReordering(view_, relative_view_, direction_));
93 }
94 ~ScopedOrderChangedNotifier() {
95 FOR_EACH_OBSERVER(ViewObserver, *ViewPrivate(view_).observers(),
96 OnViewReordered(view_, relative_view_, direction_));
97 }
98
99 private:
100 View* view_;
101 View* relative_view_;
102 OrderDirection direction_;
103
104 MOJO_DISALLOW_COPY_AND_ASSIGN(ScopedOrderChangedNotifier);
105 };
106
107 // Returns true if the order actually changed.
108 bool ReorderImpl(View::Children* children,
109 View* view,
110 View* relative,
111 OrderDirection direction) {
112 DCHECK(relative);
113 DCHECK_NE(view, relative);
114 DCHECK_EQ(view->parent(), relative->parent());
115
116 const size_t child_i =
117 std::find(children->begin(), children->end(), view) - children->begin();
118 const size_t target_i =
119 std::find(children->begin(), children->end(), relative) -
120 children->begin();
121 if ((direction == OrderDirection::ABOVE && child_i == target_i + 1) ||
122 (direction == OrderDirection::BELOW && child_i + 1 == target_i)) {
123 return false;
124 }
125
126 ScopedOrderChangedNotifier notifier(view, relative, direction);
127
128 const size_t dest_i = direction == OrderDirection::ABOVE
129 ? (child_i < target_i ? target_i : target_i + 1)
130 : (child_i < target_i ? target_i - 1 : target_i);
131 children->erase(children->begin() + child_i);
132 children->insert(children->begin() + dest_i, view);
133
134 return true;
135 }
136
137 class ScopedSetBoundsNotifier {
138 public:
139 ScopedSetBoundsNotifier(View* view,
140 const Rect& old_bounds,
141 const Rect& new_bounds)
142 : view_(view), old_bounds_(old_bounds), new_bounds_(new_bounds) {
143 FOR_EACH_OBSERVER(ViewObserver, *ViewPrivate(view_).observers(),
144 OnViewBoundsChanging(view_, old_bounds_, new_bounds_));
145 }
146 ~ScopedSetBoundsNotifier() {
147 FOR_EACH_OBSERVER(ViewObserver, *ViewPrivate(view_).observers(),
148 OnViewBoundsChanged(view_, old_bounds_, new_bounds_));
149 }
150
151 private:
152 View* view_;
153 const Rect old_bounds_;
154 const Rect new_bounds_;
155
156 MOJO_DISALLOW_COPY_AND_ASSIGN(ScopedSetBoundsNotifier);
157 };
158
159 // Some operations are only permitted in the connection that created the view.
160 bool OwnsView(ViewManager* manager, View* view) {
161 return !manager ||
162 static_cast<ViewManagerClientImpl*>(manager)->OwnsView(view->id());
163 }
164
165 } // namespace
166
167 ////////////////////////////////////////////////////////////////////////////////
168 // View, public:
169
170 void View::Destroy() {
171 if (!OwnsView(manager_, this))
172 return;
173
174 if (manager_)
175 static_cast<ViewManagerClientImpl*>(manager_)->DestroyView(id_);
176 while (!children_.empty()) {
177 View* child = children_.front();
178 if (!OwnsView(manager_, child)) {
179 ViewPrivate(child).ClearParent();
180 children_.erase(children_.begin());
181 } else {
182 child->Destroy();
183 DCHECK(std::find(children_.begin(), children_.end(), child) ==
184 children_.end());
185 }
186 }
187 LocalDestroy();
188 }
189
190 void View::SetBounds(const Rect& bounds) {
191 if (!OwnsView(manager_, this))
192 return;
193
194 if (bounds_.Equals(bounds))
195 return;
196
197 if (manager_)
198 static_cast<ViewManagerClientImpl*>(manager_)->SetBounds(id_, bounds);
199 LocalSetBounds(bounds_, bounds);
200 }
201
202 void View::SetVisible(bool value) {
203 if (visible_ == value)
204 return;
205
206 if (manager_)
207 static_cast<ViewManagerClientImpl*>(manager_)->SetVisible(id_, value);
208 LocalSetVisible(value);
209 }
210
211 void View::SetSharedProperty(const std::string& name,
212 const std::vector<uint8_t>* value) {
213 std::vector<uint8_t> old_value;
214 std::vector<uint8_t>* old_value_ptr = nullptr;
215 auto it = properties_.find(name);
216 if (it != properties_.end()) {
217 old_value = it->second;
218 old_value_ptr = &old_value;
219
220 if (value && old_value == *value)
221 return;
222 } else if (!value) {
223 // This property isn't set in |properties_| and |value| is NULL, so there's
224 // no change.
225 return;
226 }
227
228 if (value) {
229 properties_[name] = *value;
230 } else if (it != properties_.end()) {
231 properties_.erase(it);
232 }
233
234 // TODO: add test coverage of this (450303).
235 if (manager_) {
236 Array<uint8_t> transport_value;
237 if (value) {
238 transport_value.resize(value->size());
239 if (value->size())
240 memcpy(&transport_value.front(), &(value->front()), value->size());
241 }
242 static_cast<ViewManagerClientImpl*>(manager_)
243 ->SetProperty(id_, name, transport_value.Pass());
244 }
245
246 FOR_EACH_OBSERVER(
247 ViewObserver, observers_,
248 OnViewSharedPropertyChanged(this, name, old_value_ptr, value));
249 }
250
251 bool View::IsDrawn() const {
252 if (!visible_)
253 return false;
254 return parent_ ? parent_->IsDrawn() : drawn_;
255 }
256
257 void View::AddObserver(ViewObserver* observer) {
258 observers_.AddObserver(observer);
259 }
260
261 void View::RemoveObserver(ViewObserver* observer) {
262 observers_.RemoveObserver(observer);
263 }
264
265 const View* View::GetRoot() const {
266 const View* root = this;
267 for (const View* parent = this; parent; parent = parent->parent())
268 root = parent;
269 return root;
270 }
271
272 void View::AddChild(View* child) {
273 // TODO(beng): not necessarily valid to all connections, but possibly to the
274 // embeddee in an embedder-embeddee relationship.
275 if (manager_)
276 CHECK_EQ(child->view_manager(), manager_);
277 LocalAddChild(child);
278 if (manager_)
279 static_cast<ViewManagerClientImpl*>(manager_)->AddChild(child->id(), id_);
280 }
281
282 void View::RemoveChild(View* child) {
283 // TODO(beng): not necessarily valid to all connections, but possibly to the
284 // embeddee in an embedder-embeddee relationship.
285 if (manager_)
286 CHECK_EQ(child->view_manager(), manager_);
287 LocalRemoveChild(child);
288 if (manager_) {
289 static_cast<ViewManagerClientImpl*>(manager_)
290 ->RemoveChild(child->id(), id_);
291 }
292 }
293
294 void View::MoveToFront() {
295 if (!parent_ || parent_->children_.back() == this)
296 return;
297 Reorder(parent_->children_.back(), OrderDirection::ABOVE);
298 }
299
300 void View::MoveToBack() {
301 if (!parent_ || parent_->children_.front() == this)
302 return;
303 Reorder(parent_->children_.front(), OrderDirection::BELOW);
304 }
305
306 void View::Reorder(View* relative, OrderDirection direction) {
307 if (!LocalReorder(relative, direction))
308 return;
309 if (manager_) {
310 static_cast<ViewManagerClientImpl*>(manager_)
311 ->Reorder(id_, relative->id(), direction);
312 }
313 }
314
315 bool View::Contains(View* child) const {
316 if (!child)
317 return false;
318 if (child == this)
319 return true;
320 if (manager_)
321 CHECK_EQ(child->view_manager(), manager_);
322 for (View* p = child->parent(); p; p = p->parent()) {
323 if (p == this)
324 return true;
325 }
326 return false;
327 }
328
329 View* View::GetChildById(Id id) {
330 if (id == id_)
331 return this;
332 // TODO(beng): this could be improved depending on how we decide to own views.
333 Children::const_iterator it = children_.begin();
334 for (; it != children_.end(); ++it) {
335 View* view = (*it)->GetChildById(id);
336 if (view)
337 return view;
338 }
339 return NULL;
340 }
341
342 void View::SetSurfaceId(SurfaceIdPtr id) {
343 if (manager_) {
344 static_cast<ViewManagerClientImpl*>(manager_)->SetSurfaceId(id_, id.Pass());
345 }
346 }
347
348 void View::SetFocus() {
349 if (manager_)
350 static_cast<ViewManagerClientImpl*>(manager_)->SetFocus(id_);
351 }
352
353 void View::Embed(const String& url) {
354 if (PrepareForEmbed())
355 static_cast<ViewManagerClientImpl*>(manager_)->Embed(url, id_);
356 }
357
358 void View::Embed(const String& url,
359 InterfaceRequest<ServiceProvider> services,
360 ServiceProviderPtr exposed_services) {
361 if (PrepareForEmbed()) {
362 static_cast<ViewManagerClientImpl*>(manager_)
363 ->Embed(url, id_, services.Pass(), exposed_services.Pass());
364 }
365 }
366
367 void View::Embed(ViewManagerClientPtr client) {
368 if (PrepareForEmbed())
369 static_cast<ViewManagerClientImpl*>(manager_)->Embed(id_, client.Pass());
370 }
371
372 ////////////////////////////////////////////////////////////////////////////////
373 // View, protected:
374
375 namespace {
376
377 ViewportMetricsPtr CreateEmptyViewportMetrics() {
378 ViewportMetricsPtr metrics = ViewportMetrics::New();
379 metrics->size = Size::New();
380 return metrics;
381 }
382
383 } // namespace
384
385 View::View()
386 : manager_(NULL),
387 id_(static_cast<Id>(-1)),
388 parent_(NULL),
389 viewport_metrics_(CreateEmptyViewportMetrics()),
390 visible_(true),
391 drawn_(false) {}
392
393 View::~View() {
394 FOR_EACH_OBSERVER(ViewObserver, observers_, OnViewDestroying(this));
395 if (parent_)
396 parent_->LocalRemoveChild(this);
397
398 // We may still have children. This can happen if the embedder destroys the
399 // root while we're still alive.
400 while (!children_.empty()) {
401 View* child = children_.front();
402 LocalRemoveChild(child);
403 DCHECK(children_.empty() || children_.front() != child);
404 }
405
406 // TODO(beng): It'd be better to do this via a destruction observer in the
407 // ViewManagerClientImpl.
408 if (manager_)
409 static_cast<ViewManagerClientImpl*>(manager_)->RemoveView(id_);
410
411 // Clear properties.
412 for (auto& pair : prop_map_) {
413 if (pair.second.deallocator)
414 (*pair.second.deallocator)(pair.second.value);
415 }
416 prop_map_.clear();
417
418 FOR_EACH_OBSERVER(ViewObserver, observers_, OnViewDestroyed(this));
419 }
420
421 ////////////////////////////////////////////////////////////////////////////////
422 // View, private:
423
424 View::View(ViewManager* manager, Id id)
425 : manager_(manager),
426 id_(id),
427 parent_(nullptr),
428 viewport_metrics_(CreateEmptyViewportMetrics()),
429 visible_(false),
430 drawn_(false) {}
431
432 int64 View::SetLocalPropertyInternal(const void* key,
433 const char* name,
434 PropertyDeallocator deallocator,
435 int64 value,
436 int64 default_value) {
437 int64 old = GetLocalPropertyInternal(key, default_value);
438 if (value == default_value) {
439 prop_map_.erase(key);
440 } else {
441 Value prop_value;
442 prop_value.name = name;
443 prop_value.value = value;
444 prop_value.deallocator = deallocator;
445 prop_map_[key] = prop_value;
446 }
447 FOR_EACH_OBSERVER(ViewObserver, observers_,
448 OnViewLocalPropertyChanged(this, key, old));
449 return old;
450 }
451
452 int64 View::GetLocalPropertyInternal(const void* key,
453 int64 default_value) const {
454 std::map<const void*, Value>::const_iterator iter = prop_map_.find(key);
455 if (iter == prop_map_.end())
456 return default_value;
457 return iter->second.value;
458 }
459
460 void View::LocalDestroy() {
461 delete this;
462 }
463
464 void View::LocalAddChild(View* child) {
465 ScopedTreeNotifier notifier(child, child->parent(), this);
466 if (child->parent())
467 RemoveChildImpl(child, &child->parent_->children_);
468 children_.push_back(child);
469 child->parent_ = this;
470 }
471
472 void View::LocalRemoveChild(View* child) {
473 DCHECK_EQ(this, child->parent());
474 ScopedTreeNotifier notifier(child, this, NULL);
475 RemoveChildImpl(child, &children_);
476 }
477
478 bool View::LocalReorder(View* relative, OrderDirection direction) {
479 return ReorderImpl(&parent_->children_, this, relative, direction);
480 }
481
482 void View::LocalSetBounds(const Rect& old_bounds, const Rect& new_bounds) {
483 DCHECK(old_bounds.x == bounds_.x);
484 DCHECK(old_bounds.y == bounds_.y);
485 DCHECK(old_bounds.width == bounds_.width);
486 DCHECK(old_bounds.height == bounds_.height);
487 ScopedSetBoundsNotifier notifier(this, old_bounds, new_bounds);
488 bounds_ = new_bounds;
489 }
490
491 void View::LocalSetViewportMetrics(const ViewportMetrics& old_metrics,
492 const ViewportMetrics& new_metrics) {
493 // TODO(eseidel): We could check old_metrics against viewport_metrics_.
494 viewport_metrics_ = new_metrics.Clone();
495 FOR_EACH_OBSERVER(
496 ViewObserver, observers_,
497 OnViewViewportMetricsChanged(this, old_metrics, new_metrics));
498 }
499
500 void View::LocalSetDrawn(bool value) {
501 if (drawn_ == value)
502 return;
503
504 // As IsDrawn() is derived from |visible_| and |drawn_|, only send drawn
505 // notification is the value of IsDrawn() is really changing.
506 if (IsDrawn() == value) {
507 drawn_ = value;
508 return;
509 }
510 FOR_EACH_OBSERVER(ViewObserver, observers_, OnViewDrawnChanging(this));
511 drawn_ = value;
512 FOR_EACH_OBSERVER(ViewObserver, observers_, OnViewDrawnChanged(this));
513 }
514
515 void View::LocalSetVisible(bool visible) {
516 if (visible_ == visible)
517 return;
518
519 FOR_EACH_OBSERVER(ViewObserver, observers_, OnViewVisibilityChanging(this));
520 visible_ = visible;
521 NotifyViewVisibilityChanged(this);
522 }
523
524 void View::NotifyViewVisibilityChanged(View* target) {
525 if (!NotifyViewVisibilityChangedDown(target)) {
526 return; // |this| has been deleted.
527 }
528 NotifyViewVisibilityChangedUp(target);
529 }
530
531 bool View::NotifyViewVisibilityChangedAtReceiver(View* target) {
532 // |this| may be deleted during a call to OnViewVisibilityChanged() on one
533 // of the observers. We create an local observer for that. In that case we
534 // exit without further access to any members.
535 ViewTracker tracker;
536 tracker.Add(this);
537 FOR_EACH_OBSERVER(ViewObserver, observers_, OnViewVisibilityChanged(target));
538 return tracker.Contains(this);
539 }
540
541 bool View::NotifyViewVisibilityChangedDown(View* target) {
542 if (!NotifyViewVisibilityChangedAtReceiver(target))
543 return false; // |this| was deleted.
544 std::set<const View*> child_already_processed;
545 bool child_destroyed = false;
546 do {
547 child_destroyed = false;
548 for (View::Children::const_iterator it = children_.begin();
549 it != children_.end(); ++it) {
550 if (!child_already_processed.insert(*it).second)
551 continue;
552 if (!(*it)->NotifyViewVisibilityChangedDown(target)) {
553 // |*it| was deleted, |it| is invalid and |children_| has changed. We
554 // exit the current for-loop and enter a new one.
555 child_destroyed = true;
556 break;
557 }
558 }
559 } while (child_destroyed);
560 return true;
561 }
562
563 void View::NotifyViewVisibilityChangedUp(View* target) {
564 // Start with the parent as we already notified |this|
565 // in NotifyViewVisibilityChangedDown.
566 for (View* view = parent(); view; view = view->parent()) {
567 bool ret = view->NotifyViewVisibilityChangedAtReceiver(target);
568 DCHECK(ret);
569 }
570 }
571
572 bool View::PrepareForEmbed() {
573 if (!OwnsView(manager_, this))
574 return false;
575
576 while (!children_.empty())
577 RemoveChild(children_[0]);
578 return true;
579 }
580
581 } // namespace mojo
OLDNEW
« no previous file with comments | « mojo/services/view_manager/cpp/keys.cc ('k') | mojo/services/view_manager/cpp/lib/view_manager_client_factory.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698