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

Side by Side Diff: components/view_manager/public/cpp/lib/view.cc

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

Powered by Google App Engine
This is Rietveld 408576698