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 "components/view_manager/view_tree_impl.h"
8 #include "base/stl_util.h"
9 #include "components/view_manager/connection_manager.h"
10 #include "components/view_manager/default_access_policy.h"
11 #include "components/view_manager/display_manager.h"
12 #include "components/view_manager/server_view.h"
13 #include "components/view_manager/view_tree_host_impl.h"
14 #include "components/view_manager/window_manager_access_policy.h"
15 #include "mojo/converters/geometry/geometry_type_converters.h"
16 #include "mojo/converters/ime/ime_type_converters.h"
17 #include "mojo/converters/input_events/input_events_type_converters.h"
18 #include "mojo/converters/surfaces/surfaces_type_converters.h"
19 #include "ui/platform_window/text_input_state.h"
24 using mojo::InterfaceRequest
;
25 using mojo::OrderDirection
;
27 using mojo::ServiceProvider
;
28 using mojo::ServiceProviderPtr
;
30 using mojo::ViewDataPtr
;
32 namespace view_manager
{
34 ViewTreeImpl::ViewTreeImpl(
35 ConnectionManager
* connection_manager
,
36 mojo::ConnectionSpecificId creator_id
,
37 const ViewId
& root_id
)
38 : connection_manager_(connection_manager
),
39 id_(connection_manager_
->GetAndAdvanceNextConnectionId()),
40 creator_id_(creator_id
),
42 is_embed_root_(false) {
43 ServerView
* view
= GetView(root_id
);
45 root_
.reset(new ViewId(root_id
));
46 if (view
->GetRoot() == view
)
47 access_policy_
.reset(new WindowManagerAccessPolicy(id_
, this));
49 access_policy_
.reset(new DefaultAccessPolicy(id_
, this));
52 ViewTreeImpl::~ViewTreeImpl() {
56 void ViewTreeImpl::Init(mojo::ViewTreeClient
* client
, mojo::ViewTreePtr tree
) {
59 std::vector
<const ServerView
*> to_send
;
61 GetUnknownViewsFrom(GetView(*root_
), &to_send
);
63 // TODO(beng): verify that host can actually be nullptr here.
64 ViewTreeHostImpl
* host
= GetHost();
65 const ServerView
* focused_view
= host
? host
->GetFocusedView() : nullptr;
67 focused_view
= access_policy_
->GetViewForFocusChange(focused_view
);
68 const mojo::Id
focused_view_transport_id(
69 ViewIdToTransportId(focused_view
? focused_view
->id() : ViewId()));
71 client
->OnEmbed(id_
, ViewToViewData(to_send
.front()), tree
.Pass(),
72 focused_view_transport_id
);
75 const ServerView
* ViewTreeImpl::GetView(const ViewId
& id
) const {
76 if (id_
== id
.connection_id
) {
77 ViewMap::const_iterator i
= view_map_
.find(id
.view_id
);
78 return i
== view_map_
.end() ? NULL
: i
->second
;
80 return connection_manager_
->GetView(id
);
83 bool ViewTreeImpl::IsRoot(const ViewId
& id
) const {
84 return root_
.get() && *root_
== id
;
87 ViewTreeHostImpl
* ViewTreeImpl::GetHost() {
89 connection_manager_
->GetViewTreeHostByView(GetView(*root_
)) : nullptr;
92 void ViewTreeImpl::OnWillDestroyViewTreeImpl(
93 ViewTreeImpl
* connection
) {
94 if (creator_id_
== connection
->id())
95 creator_id_
= kInvalidConnectionId
;
96 if (connection
->root_
&& connection
->root_
->connection_id
== id_
&&
97 view_map_
.count(connection
->root_
->view_id
) > 0) {
98 client()->OnEmbeddedAppDisconnected(
99 ViewIdToTransportId(*connection
->root_
));
101 if (root_
.get() && root_
->connection_id
== connection
->id())
105 mojo::ErrorCode
ViewTreeImpl::CreateView(const ViewId
& view_id
) {
106 if (view_id
.connection_id
!= id_
)
107 return mojo::ERROR_CODE_ILLEGAL_ARGUMENT
;
108 if (view_map_
.find(view_id
.view_id
) != view_map_
.end())
109 return mojo::ERROR_CODE_VALUE_IN_USE
;
110 view_map_
[view_id
.view_id
] = connection_manager_
->CreateServerView(view_id
);
111 known_views_
.insert(ViewIdToTransportId(view_id
));
112 return mojo::ERROR_CODE_NONE
;
115 bool ViewTreeImpl::AddView(const ViewId
& parent_id
, const ViewId
& child_id
) {
116 ServerView
* parent
= GetView(parent_id
);
117 ServerView
* child
= GetView(child_id
);
118 if (parent
&& child
&& child
->parent() != parent
&&
119 !child
->Contains(parent
) && access_policy_
->CanAddView(parent
, child
)) {
120 ConnectionManager::ScopedChange
change(this, connection_manager_
, false);
127 std::vector
<const ServerView
*> ViewTreeImpl::GetViewTree(
128 const ViewId
& view_id
) const {
129 const ServerView
* view
= GetView(view_id
);
130 std::vector
<const ServerView
*> views
;
132 GetViewTreeImpl(view
, &views
);
136 bool ViewTreeImpl::SetViewVisibility(const ViewId
& view_id
, bool visible
) {
137 ServerView
* view
= GetView(view_id
);
138 if (!view
|| view
->visible() == visible
||
139 !access_policy_
->CanChangeViewVisibility(view
)) {
142 ConnectionManager::ScopedChange
change(this, connection_manager_
, false);
143 view
->SetVisible(visible
);
147 bool ViewTreeImpl::Embed(const ViewId
& view_id
,
148 mojo::ViewTreeClientPtr client
) {
149 if (!client
.get() || !CanEmbed(view_id
))
151 PrepareForEmbed(view_id
);
153 connection_manager_
->EmbedAtView(id_
, view_id
, client
.Pass()));
157 void ViewTreeImpl::Embed(const ViewId
& view_id
, mojo::URLRequestPtr request
) {
158 if (!CanEmbed(view_id
))
160 PrepareForEmbed(view_id
);
161 connection_manager_
->EmbedAtView(id_
, view_id
, request
.Pass());
164 void ViewTreeImpl::ProcessViewBoundsChanged(
165 const ServerView
* view
,
166 const gfx::Rect
& old_bounds
,
167 const gfx::Rect
& new_bounds
,
168 bool originated_change
) {
169 if (originated_change
|| !IsViewKnown(view
))
171 client()->OnViewBoundsChanged(ViewIdToTransportId(view
->id()),
172 Rect::From(old_bounds
),
173 Rect::From(new_bounds
));
176 void ViewTreeImpl::ProcessViewportMetricsChanged(
177 const mojo::ViewportMetrics
& old_metrics
,
178 const mojo::ViewportMetrics
& new_metrics
,
179 bool originated_change
) {
180 client()->OnViewViewportMetricsChanged(old_metrics
.Clone(),
181 new_metrics
.Clone());
184 void ViewTreeImpl::ProcessWillChangeViewHierarchy(
185 const ServerView
* view
,
186 const ServerView
* new_parent
,
187 const ServerView
* old_parent
,
188 bool originated_change
) {
189 if (originated_change
)
192 const bool old_drawn
= view
->IsDrawn();
193 const bool new_drawn
= view
->visible() && new_parent
&& new_parent
->IsDrawn();
194 if (old_drawn
== new_drawn
)
197 NotifyDrawnStateChanged(view
, new_drawn
);
200 void ViewTreeImpl::ProcessViewPropertyChanged(
201 const ServerView
* view
,
202 const std::string
& name
,
203 const std::vector
<uint8_t>* new_data
,
204 bool originated_change
) {
205 if (originated_change
)
210 data
= Array
<uint8_t>::From(*new_data
);
212 client()->OnViewSharedPropertyChanged(ViewIdToTransportId(view
->id()),
213 String(name
), data
.Pass());
216 void ViewTreeImpl::ProcessViewHierarchyChanged(
217 const ServerView
* view
,
218 const ServerView
* new_parent
,
219 const ServerView
* old_parent
,
220 bool originated_change
) {
221 if (originated_change
&& !IsViewKnown(view
) && new_parent
&&
222 IsViewKnown(new_parent
)) {
223 std::vector
<const ServerView
*> unused
;
224 GetUnknownViewsFrom(view
, &unused
);
226 if (originated_change
|| connection_manager_
->is_processing_delete_view() ||
227 connection_manager_
->DidConnectionMessageClient(id_
)) {
231 if (!access_policy_
->ShouldNotifyOnHierarchyChange(
232 view
, &new_parent
, &old_parent
)) {
235 // Inform the client of any new views and update the set of views we know
237 std::vector
<const ServerView
*> to_send
;
238 if (!IsViewKnown(view
))
239 GetUnknownViewsFrom(view
, &to_send
);
240 const ViewId
new_parent_id(new_parent
? new_parent
->id() : ViewId());
241 const ViewId
old_parent_id(old_parent
? old_parent
->id() : ViewId());
242 client()->OnViewHierarchyChanged(ViewIdToTransportId(view
->id()),
243 ViewIdToTransportId(new_parent_id
),
244 ViewIdToTransportId(old_parent_id
),
245 ViewsToViewDatas(to_send
));
246 connection_manager_
->OnConnectionMessagedClient(id_
);
249 void ViewTreeImpl::ProcessViewReorder(const ServerView
* view
,
250 const ServerView
* relative_view
,
251 OrderDirection direction
,
252 bool originated_change
) {
253 if (originated_change
|| !IsViewKnown(view
) || !IsViewKnown(relative_view
))
256 client()->OnViewReordered(ViewIdToTransportId(view
->id()),
257 ViewIdToTransportId(relative_view
->id()),
261 void ViewTreeImpl::ProcessViewDeleted(const ViewId
& view
,
262 bool originated_change
) {
263 if (view
.connection_id
== id_
)
264 view_map_
.erase(view
.view_id
);
266 const bool in_known
= known_views_
.erase(ViewIdToTransportId(view
)) > 0;
271 if (originated_change
)
275 client()->OnViewDeleted(ViewIdToTransportId(view
));
276 connection_manager_
->OnConnectionMessagedClient(id_
);
280 void ViewTreeImpl::ProcessWillChangeViewVisibility(
281 const ServerView
* view
,
282 bool originated_change
) {
283 if (originated_change
)
286 if (IsViewKnown(view
)) {
287 client()->OnViewVisibilityChanged(ViewIdToTransportId(view
->id()),
292 bool view_target_drawn_state
;
293 if (view
->visible()) {
294 // View is being hidden, won't be drawn.
295 view_target_drawn_state
= false;
297 // View is being shown. View will be drawn if its parent is drawn.
298 view_target_drawn_state
= view
->parent() && view
->parent()->IsDrawn();
301 NotifyDrawnStateChanged(view
, view_target_drawn_state
);
304 void ViewTreeImpl::ProcessFocusChanged(
305 const ServerView
* old_focused_view
,
306 const ServerView
* new_focused_view
) {
307 const ServerView
* view
=
308 new_focused_view
? access_policy_
->GetViewForFocusChange(new_focused_view
)
310 client()->OnViewFocused(view
? ViewIdToTransportId(view
->id())
311 : ViewIdToTransportId(ViewId()));
314 bool ViewTreeImpl::IsViewKnown(const ServerView
* view
) const {
315 return known_views_
.count(ViewIdToTransportId(view
->id())) > 0;
318 bool ViewTreeImpl::CanReorderView(const ServerView
* view
,
319 const ServerView
* relative_view
,
320 OrderDirection direction
) const {
321 if (!view
|| !relative_view
)
324 if (!view
->parent() || view
->parent() != relative_view
->parent())
327 if (!access_policy_
->CanReorderView(view
, relative_view
, direction
))
330 std::vector
<const ServerView
*> children
= view
->parent()->GetChildren();
331 const size_t child_i
=
332 std::find(children
.begin(), children
.end(), view
) - children
.begin();
333 const size_t target_i
=
334 std::find(children
.begin(), children
.end(), relative_view
) -
336 if ((direction
== mojo::ORDER_DIRECTION_ABOVE
&& child_i
== target_i
+ 1) ||
337 (direction
== mojo::ORDER_DIRECTION_BELOW
&& child_i
+ 1 == target_i
)) {
344 bool ViewTreeImpl::DeleteViewImpl(ViewTreeImpl
* source
, ServerView
* view
) {
346 DCHECK_EQ(view
->id().connection_id
, id_
);
347 ConnectionManager::ScopedChange
change(source
, connection_manager_
, true);
352 void ViewTreeImpl::GetUnknownViewsFrom(
353 const ServerView
* view
,
354 std::vector
<const ServerView
*>* views
) {
355 if (IsViewKnown(view
) || !access_policy_
->CanGetViewTree(view
))
357 views
->push_back(view
);
358 known_views_
.insert(ViewIdToTransportId(view
->id()));
359 if (!access_policy_
->CanDescendIntoViewForViewTree(view
))
361 std::vector
<const ServerView
*> children(view
->GetChildren());
362 for (size_t i
= 0 ; i
< children
.size(); ++i
)
363 GetUnknownViewsFrom(children
[i
], views
);
366 void ViewTreeImpl::RemoveFromKnown(
367 const ServerView
* view
,
368 std::vector
<ServerView
*>* local_views
) {
369 if (view
->id().connection_id
== id_
) {
371 local_views
->push_back(GetView(view
->id()));
374 known_views_
.erase(ViewIdToTransportId(view
->id()));
375 std::vector
<const ServerView
*> children
= view
->GetChildren();
376 for (size_t i
= 0; i
< children
.size(); ++i
)
377 RemoveFromKnown(children
[i
], local_views
);
380 void ViewTreeImpl::RemoveRoot() {
382 const ViewId
root_id(*root_
);
384 // No need to do anything if we created the view.
385 if (root_id
.connection_id
== id_
)
388 client()->OnUnembed();
389 client()->OnViewDeleted(ViewIdToTransportId(root_id
));
390 connection_manager_
->OnConnectionMessagedClient(id_
);
392 // This connection no longer knows about the view. Unparent any views that
393 // were parented to views in the root.
394 std::vector
<ServerView
*> local_views
;
395 RemoveFromKnown(GetView(root_id
), &local_views
);
396 for (size_t i
= 0; i
< local_views
.size(); ++i
)
397 local_views
[i
]->parent()->Remove(local_views
[i
]);
400 Array
<ViewDataPtr
> ViewTreeImpl::ViewsToViewDatas(
401 const std::vector
<const ServerView
*>& views
) {
402 Array
<ViewDataPtr
> array(views
.size());
403 for (size_t i
= 0; i
< views
.size(); ++i
)
404 array
[i
] = ViewToViewData(views
[i
]).Pass();
408 ViewDataPtr
ViewTreeImpl::ViewToViewData(const ServerView
* view
) {
409 DCHECK(IsViewKnown(view
));
410 const ServerView
* parent
= view
->parent();
411 // If the parent isn't known, it means the parent is not visible to us (not
412 // in roots), and should not be sent over.
413 if (parent
&& !IsViewKnown(parent
))
415 ViewDataPtr
view_data(mojo::ViewData::New());
416 view_data
->parent_id
= ViewIdToTransportId(parent
? parent
->id() : ViewId());
417 view_data
->view_id
= ViewIdToTransportId(view
->id());
418 view_data
->bounds
= Rect::From(view
->bounds());
419 view_data
->properties
=
420 mojo::Map
<String
, Array
<uint8_t>>::From(view
->properties());
421 view_data
->visible
= view
->visible();
422 view_data
->drawn
= view
->IsDrawn();
423 view_data
->viewport_metrics
=
424 connection_manager_
->GetViewportMetricsForView(view
);
425 return view_data
.Pass();
428 void ViewTreeImpl::GetViewTreeImpl(
429 const ServerView
* view
,
430 std::vector
<const ServerView
*>* views
) const {
433 if (!access_policy_
->CanGetViewTree(view
))
436 views
->push_back(view
);
438 if (!access_policy_
->CanDescendIntoViewForViewTree(view
))
441 std::vector
<const ServerView
*> children(view
->GetChildren());
442 for (size_t i
= 0 ; i
< children
.size(); ++i
)
443 GetViewTreeImpl(children
[i
], views
);
446 void ViewTreeImpl::NotifyDrawnStateChanged(const ServerView
* view
,
447 bool new_drawn_value
) {
448 // Even though we don't know about view, it may be an ancestor of our root, in
449 // which case the change may effect our roots drawn state.
453 const ServerView
* root
= GetView(*root_
);
455 if (view
->Contains(root
) && (new_drawn_value
!= root
->IsDrawn())) {
456 client()->OnViewDrawnStateChanged(ViewIdToTransportId(root
->id()),
461 void ViewTreeImpl::DestroyViews() {
462 if (!view_map_
.empty()) {
463 ConnectionManager::ScopedChange
change(this, connection_manager_
, true);
464 // If we get here from the destructor we're not going to get
465 // ProcessViewDeleted(). Copy the map and delete from the copy so that we
466 // don't have to worry about whether |view_map_| changes or not.
467 ViewMap view_map_copy
;
468 view_map_
.swap(view_map_copy
);
469 STLDeleteValues(&view_map_copy
);
473 bool ViewTreeImpl::CanEmbed(const ViewId
& view_id
) const {
474 const ServerView
* view
= GetView(view_id
);
475 return view
&& access_policy_
->CanEmbed(view
);
478 void ViewTreeImpl::PrepareForEmbed(const ViewId
& view_id
) {
479 const ServerView
* view
= GetView(view_id
);
480 DCHECK(view
&& access_policy_
->CanEmbed(view
));
482 // Only allow a node to be the root for one connection.
483 ViewTreeImpl
* existing_owner
=
484 connection_manager_
->GetConnectionWithRoot(view_id
);
486 ConnectionManager::ScopedChange
change(this, connection_manager_
, true);
487 RemoveChildrenAsPartOfEmbed(view_id
);
488 if (existing_owner
) {
489 // Never message the originating connection.
490 connection_manager_
->OnConnectionMessagedClient(id_
);
491 existing_owner
->RemoveRoot();
495 void ViewTreeImpl::RemoveChildrenAsPartOfEmbed(const ViewId
& view_id
) {
496 ServerView
* view
= GetView(view_id
);
498 CHECK(view
->id().connection_id
== view_id
.connection_id
);
499 std::vector
<ServerView
*> children
= view
->GetChildren();
500 for (size_t i
= 0; i
< children
.size(); ++i
)
501 view
->Remove(children
[i
]);
504 void ViewTreeImpl::CreateView(
505 Id transport_view_id
,
506 const Callback
<void(mojo::ErrorCode
)>& callback
) {
507 callback
.Run(CreateView(ViewIdFromTransportId(transport_view_id
)));
510 void ViewTreeImpl::DeleteView(
511 Id transport_view_id
,
512 const Callback
<void(bool)>& callback
) {
513 ServerView
* view
= GetView(ViewIdFromTransportId(transport_view_id
));
514 bool success
= false;
515 if (view
&& access_policy_
->CanDeleteView(view
)) {
516 ViewTreeImpl
* connection
=
517 connection_manager_
->GetConnection(view
->id().connection_id
);
518 success
= connection
&& connection
->DeleteViewImpl(this, view
);
520 callback
.Run(success
);
523 void ViewTreeImpl::AddView(
526 const Callback
<void(bool)>& callback
) {
527 callback
.Run(AddView(ViewIdFromTransportId(parent_id
),
528 ViewIdFromTransportId(child_id
)));
531 void ViewTreeImpl::RemoveViewFromParent(
533 const Callback
<void(bool)>& callback
) {
534 bool success
= false;
535 ServerView
* view
= GetView(ViewIdFromTransportId(view_id
));
536 if (view
&& view
->parent() && access_policy_
->CanRemoveViewFromParent(view
)) {
538 ConnectionManager::ScopedChange
change(this, connection_manager_
, false);
539 view
->parent()->Remove(view
);
541 callback
.Run(success
);
544 void ViewTreeImpl::ReorderView(Id view_id
,
546 OrderDirection direction
,
547 const Callback
<void(bool)>& callback
) {
548 bool success
= false;
549 ServerView
* view
= GetView(ViewIdFromTransportId(view_id
));
550 ServerView
* relative_view
= GetView(ViewIdFromTransportId(relative_view_id
));
551 if (CanReorderView(view
, relative_view
, direction
)) {
553 ConnectionManager::ScopedChange
change(this, connection_manager_
, false);
554 view
->parent()->Reorder(view
, relative_view
, direction
);
555 connection_manager_
->ProcessViewReorder(view
, relative_view
, direction
);
557 callback
.Run(success
);
560 void ViewTreeImpl::GetViewTree(
562 const Callback
<void(Array
<ViewDataPtr
>)>& callback
) {
563 std::vector
<const ServerView
*> views(
564 GetViewTree(ViewIdFromTransportId(view_id
)));
565 callback
.Run(ViewsToViewDatas(views
));
568 void ViewTreeImpl::SetViewBounds(
570 mojo::RectPtr bounds
,
571 const Callback
<void(bool)>& callback
) {
572 ServerView
* view
= GetView(ViewIdFromTransportId(view_id
));
573 const bool success
= view
&& access_policy_
->CanSetViewBounds(view
);
575 ConnectionManager::ScopedChange
change(this, connection_manager_
, false);
576 view
->SetBounds(bounds
.To
<gfx::Rect
>());
578 callback
.Run(success
);
581 void ViewTreeImpl::SetViewVisibility(
582 Id transport_view_id
,
584 const Callback
<void(bool)>& callback
) {
586 SetViewVisibility(ViewIdFromTransportId(transport_view_id
), visible
));
589 void ViewTreeImpl::SetViewProperty(
591 const mojo::String
& name
,
592 mojo::Array
<uint8_t> value
,
593 const mojo::Callback
<void(bool)>& callback
) {
594 ServerView
* view
= GetView(ViewIdFromTransportId(view_id
));
595 const bool success
= view
&& access_policy_
->CanSetViewProperties(view
);
597 ConnectionManager::ScopedChange
change(this, connection_manager_
, false);
599 if (value
.is_null()) {
600 view
->SetProperty(name
, nullptr);
602 std::vector
<uint8_t> data
= value
.To
<std::vector
<uint8_t>>();
603 view
->SetProperty(name
, &data
);
606 callback
.Run(success
);
609 void ViewTreeImpl::RequestSurface(
611 mojo::InterfaceRequest
<mojo::Surface
> surface
,
612 mojo::SurfaceClientPtr client
) {
613 ServerView
* view
= GetView(ViewIdFromTransportId(view_id
));
614 const bool success
= view
&& access_policy_
->CanSetViewSurfaceId(view
);
617 view
->Bind(surface
.Pass(), client
.Pass());
620 void ViewTreeImpl::SetViewTextInputState(
622 mojo::TextInputStatePtr state
) {
623 ServerView
* view
= GetView(ViewIdFromTransportId(view_id
));
624 bool success
= view
&& access_policy_
->CanSetViewTextInputState(view
);
626 view
->SetTextInputState(state
.To
<ui::TextInputState
>());
629 void ViewTreeImpl::SetImeVisibility(uint32_t view_id
,
631 mojo::TextInputStatePtr state
) {
632 ServerView
* view
= GetView(ViewIdFromTransportId(view_id
));
633 bool success
= view
&& access_policy_
->CanSetViewTextInputState(view
);
635 if (!state
.is_null())
636 view
->SetTextInputState(state
.To
<ui::TextInputState
>());
638 ViewTreeHostImpl
* host
= GetHost();
640 host
->SetImeVisibility(view
, visible
);
644 void ViewTreeImpl::SetEmbedRoot() {
645 is_embed_root_
= true;
648 void ViewTreeImpl::Embed(mojo::Id transport_view_id
,
649 mojo::ViewTreeClientPtr client
,
650 const mojo::Callback
<void(bool)>& callback
) {
651 callback
.Run(Embed(ViewIdFromTransportId(transport_view_id
), client
.Pass()));
654 void ViewTreeImpl::SetFocus(uint32_t view_id
) {
655 ServerView
* view
= GetView(ViewIdFromTransportId(view_id
));
656 // TODO(beng): consider shifting non-policy drawn check logic to VTH's
658 if (view
&& view
->IsDrawn() && access_policy_
->CanSetFocus(view
)) {
659 ConnectionManager::ScopedChange
change(this, connection_manager_
, false);
660 ViewTreeHostImpl
* host
= GetHost();
662 host
->SetFocusedView(view
);
666 bool ViewTreeImpl::IsRootForAccessPolicy(const ViewId
& id
) const {
670 bool ViewTreeImpl::IsViewKnownForAccessPolicy(const ServerView
* view
) const {
671 return IsViewKnown(view
);
674 bool ViewTreeImpl::IsViewRootOfAnotherConnectionForAccessPolicy(
675 const ServerView
* view
) const {
676 ViewTreeImpl
* connection
=
677 connection_manager_
->GetConnectionWithRoot(view
->id());
678 return connection
&& connection
!= this;
681 bool ViewTreeImpl::IsDescendantOfEmbedRoot(const ServerView
* view
) {
682 return is_embed_root_
&& root_
&& GetView(*root_
)->Contains(view
);
685 } // namespace view_manager