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/window_manager_access_policy.h"
14 #include "mojo/converters/geometry/geometry_type_converters.h"
15 #include "mojo/converters/ime/ime_type_converters.h"
16 #include "mojo/converters/input_events/input_events_type_converters.h"
17 #include "mojo/converters/surfaces/surfaces_type_converters.h"
18 #include "ui/platform_window/text_input_state.h"
23 using mojo::InterfaceRequest
;
24 using mojo::OrderDirection
;
26 using mojo::ServiceProvider
;
27 using mojo::ServiceProviderPtr
;
29 using mojo::ViewDataPtr
;
31 namespace view_manager
{
33 ViewTreeImpl::ViewTreeImpl(
34 ConnectionManager
* connection_manager
,
35 mojo::ConnectionSpecificId creator_id
,
36 const ViewId
& root_id
)
37 : connection_manager_(connection_manager
),
38 id_(connection_manager_
->GetAndAdvanceNextConnectionId()),
39 creator_id_(creator_id
),
41 is_embed_root_(false) {
42 ServerView
* view
= GetView(root_id
);
44 root_
.reset(new ViewId(root_id
));
45 if (view
->GetRoot() == view
)
46 access_policy_
.reset(new WindowManagerAccessPolicy(id_
, this));
48 access_policy_
.reset(new DefaultAccessPolicy(id_
, this));
51 ViewTreeImpl::~ViewTreeImpl() {
55 void ViewTreeImpl::Init(mojo::ViewTreeClient
* client
, mojo::ViewTreePtr tree
) {
58 std::vector
<const ServerView
*> to_send
;
60 GetUnknownViewsFrom(GetView(*root_
), &to_send
);
62 const ServerView
* focused_view
= connection_manager_
->GetFocusedView();
64 focused_view
= access_policy_
->GetViewForFocusChange(focused_view
);
65 const mojo::Id
focused_view_transport_id(
66 ViewIdToTransportId(focused_view
? focused_view
->id() : ViewId()));
68 client
->OnEmbed(id_
, ViewToViewData(to_send
.front()), tree
.Pass(),
69 focused_view_transport_id
);
72 const ServerView
* ViewTreeImpl::GetView(const ViewId
& id
) const {
73 if (id_
== id
.connection_id
) {
74 ViewMap::const_iterator i
= view_map_
.find(id
.view_id
);
75 return i
== view_map_
.end() ? NULL
: i
->second
;
77 return connection_manager_
->GetView(id
);
80 bool ViewTreeImpl::IsRoot(const ViewId
& id
) const {
81 return root_
.get() && *root_
== id
;
84 void ViewTreeImpl::OnWillDestroyViewTreeImpl(
85 ViewTreeImpl
* connection
) {
86 if (creator_id_
== connection
->id())
87 creator_id_
= kInvalidConnectionId
;
88 if (connection
->root_
&& connection
->root_
->connection_id
== id_
&&
89 view_map_
.count(connection
->root_
->view_id
) > 0) {
90 client()->OnEmbeddedAppDisconnected(
91 ViewIdToTransportId(*connection
->root_
));
93 if (root_
.get() && root_
->connection_id
== connection
->id())
97 mojo::ErrorCode
ViewTreeImpl::CreateView(const ViewId
& view_id
) {
98 if (view_id
.connection_id
!= id_
)
99 return mojo::ERROR_CODE_ILLEGAL_ARGUMENT
;
100 if (view_map_
.find(view_id
.view_id
) != view_map_
.end())
101 return mojo::ERROR_CODE_VALUE_IN_USE
;
102 view_map_
[view_id
.view_id
] = connection_manager_
->CreateServerView(view_id
);
103 known_views_
.insert(ViewIdToTransportId(view_id
));
104 return mojo::ERROR_CODE_NONE
;
107 bool ViewTreeImpl::AddView(const ViewId
& parent_id
, const ViewId
& child_id
) {
108 ServerView
* parent
= GetView(parent_id
);
109 ServerView
* child
= GetView(child_id
);
110 if (parent
&& child
&& child
->parent() != parent
&&
111 !child
->Contains(parent
) && access_policy_
->CanAddView(parent
, child
)) {
112 ConnectionManager::ScopedChange
change(this, connection_manager_
, false);
119 std::vector
<const ServerView
*> ViewTreeImpl::GetViewTree(
120 const ViewId
& view_id
) const {
121 const ServerView
* view
= GetView(view_id
);
122 std::vector
<const ServerView
*> views
;
124 GetViewTreeImpl(view
, &views
);
128 bool ViewTreeImpl::SetViewVisibility(const ViewId
& view_id
, bool visible
) {
129 ServerView
* view
= GetView(view_id
);
130 if (!view
|| view
->visible() == visible
||
131 !access_policy_
->CanChangeViewVisibility(view
)) {
134 ConnectionManager::ScopedChange
change(this, connection_manager_
, false);
135 view
->SetVisible(visible
);
139 bool ViewTreeImpl::Embed(const ViewId
& view_id
,
140 mojo::ViewTreeClientPtr client
) {
141 if (!client
.get() || !CanEmbed(view_id
))
143 PrepareForEmbed(view_id
);
145 connection_manager_
->EmbedAtView(id_
, view_id
, client
.Pass()));
149 void ViewTreeImpl::Embed(const ViewId
& view_id
, mojo::URLRequestPtr request
) {
150 if (!CanEmbed(view_id
))
152 PrepareForEmbed(view_id
);
153 connection_manager_
->EmbedAtView(id_
, view_id
, request
.Pass());
156 void ViewTreeImpl::ProcessViewBoundsChanged(
157 const ServerView
* view
,
158 const gfx::Rect
& old_bounds
,
159 const gfx::Rect
& new_bounds
,
160 bool originated_change
) {
161 if (originated_change
|| !IsViewKnown(view
))
163 client()->OnViewBoundsChanged(ViewIdToTransportId(view
->id()),
164 Rect::From(old_bounds
),
165 Rect::From(new_bounds
));
168 void ViewTreeImpl::ProcessViewportMetricsChanged(
169 const mojo::ViewportMetrics
& old_metrics
,
170 const mojo::ViewportMetrics
& new_metrics
,
171 bool originated_change
) {
172 client()->OnViewViewportMetricsChanged(old_metrics
.Clone(),
173 new_metrics
.Clone());
176 void ViewTreeImpl::ProcessWillChangeViewHierarchy(
177 const ServerView
* view
,
178 const ServerView
* new_parent
,
179 const ServerView
* old_parent
,
180 bool originated_change
) {
181 if (originated_change
)
184 const bool old_drawn
= view
->IsDrawn();
185 const bool new_drawn
= view
->visible() && new_parent
&& new_parent
->IsDrawn();
186 if (old_drawn
== new_drawn
)
189 NotifyDrawnStateChanged(view
, new_drawn
);
192 void ViewTreeImpl::ProcessViewPropertyChanged(
193 const ServerView
* view
,
194 const std::string
& name
,
195 const std::vector
<uint8_t>* new_data
,
196 bool originated_change
) {
197 if (originated_change
)
202 data
= Array
<uint8_t>::From(*new_data
);
204 client()->OnViewSharedPropertyChanged(ViewIdToTransportId(view
->id()),
205 String(name
), data
.Pass());
208 void ViewTreeImpl::ProcessViewHierarchyChanged(
209 const ServerView
* view
,
210 const ServerView
* new_parent
,
211 const ServerView
* old_parent
,
212 bool originated_change
) {
213 if (originated_change
&& !IsViewKnown(view
) && new_parent
&&
214 IsViewKnown(new_parent
)) {
215 std::vector
<const ServerView
*> unused
;
216 GetUnknownViewsFrom(view
, &unused
);
218 if (originated_change
|| connection_manager_
->is_processing_delete_view() ||
219 connection_manager_
->DidConnectionMessageClient(id_
)) {
223 if (!access_policy_
->ShouldNotifyOnHierarchyChange(
224 view
, &new_parent
, &old_parent
)) {
227 // Inform the client of any new views and update the set of views we know
229 std::vector
<const ServerView
*> to_send
;
230 if (!IsViewKnown(view
))
231 GetUnknownViewsFrom(view
, &to_send
);
232 const ViewId
new_parent_id(new_parent
? new_parent
->id() : ViewId());
233 const ViewId
old_parent_id(old_parent
? old_parent
->id() : ViewId());
234 client()->OnViewHierarchyChanged(ViewIdToTransportId(view
->id()),
235 ViewIdToTransportId(new_parent_id
),
236 ViewIdToTransportId(old_parent_id
),
237 ViewsToViewDatas(to_send
));
238 connection_manager_
->OnConnectionMessagedClient(id_
);
241 void ViewTreeImpl::ProcessViewReorder(const ServerView
* view
,
242 const ServerView
* relative_view
,
243 OrderDirection direction
,
244 bool originated_change
) {
245 if (originated_change
|| !IsViewKnown(view
) || !IsViewKnown(relative_view
))
248 client()->OnViewReordered(ViewIdToTransportId(view
->id()),
249 ViewIdToTransportId(relative_view
->id()),
253 void ViewTreeImpl::ProcessViewDeleted(const ViewId
& view
,
254 bool originated_change
) {
255 if (view
.connection_id
== id_
)
256 view_map_
.erase(view
.view_id
);
258 const bool in_known
= known_views_
.erase(ViewIdToTransportId(view
)) > 0;
263 if (originated_change
)
267 client()->OnViewDeleted(ViewIdToTransportId(view
));
268 connection_manager_
->OnConnectionMessagedClient(id_
);
272 void ViewTreeImpl::ProcessWillChangeViewVisibility(
273 const ServerView
* view
,
274 bool originated_change
) {
275 if (originated_change
)
278 if (IsViewKnown(view
)) {
279 client()->OnViewVisibilityChanged(ViewIdToTransportId(view
->id()),
284 bool view_target_drawn_state
;
285 if (view
->visible()) {
286 // View is being hidden, won't be drawn.
287 view_target_drawn_state
= false;
289 // View is being shown. View will be drawn if its parent is drawn.
290 view_target_drawn_state
= view
->parent() && view
->parent()->IsDrawn();
293 NotifyDrawnStateChanged(view
, view_target_drawn_state
);
296 void ViewTreeImpl::ProcessFocusChanged(
297 const ServerView
* old_focused_view
,
298 const ServerView
* new_focused_view
) {
299 const ServerView
* view
=
300 new_focused_view
? access_policy_
->GetViewForFocusChange(new_focused_view
)
302 client()->OnViewFocused(view
? ViewIdToTransportId(view
->id())
303 : ViewIdToTransportId(ViewId()));
306 bool ViewTreeImpl::IsViewKnown(const ServerView
* view
) const {
307 return known_views_
.count(ViewIdToTransportId(view
->id())) > 0;
310 bool ViewTreeImpl::CanReorderView(const ServerView
* view
,
311 const ServerView
* relative_view
,
312 OrderDirection direction
) const {
313 if (!view
|| !relative_view
)
316 if (!view
->parent() || view
->parent() != relative_view
->parent())
319 if (!access_policy_
->CanReorderView(view
, relative_view
, direction
))
322 std::vector
<const ServerView
*> children
= view
->parent()->GetChildren();
323 const size_t child_i
=
324 std::find(children
.begin(), children
.end(), view
) - children
.begin();
325 const size_t target_i
=
326 std::find(children
.begin(), children
.end(), relative_view
) -
328 if ((direction
== mojo::ORDER_DIRECTION_ABOVE
&& child_i
== target_i
+ 1) ||
329 (direction
== mojo::ORDER_DIRECTION_BELOW
&& child_i
+ 1 == target_i
)) {
336 bool ViewTreeImpl::DeleteViewImpl(ViewTreeImpl
* source
, ServerView
* view
) {
338 DCHECK_EQ(view
->id().connection_id
, id_
);
339 ConnectionManager::ScopedChange
change(source
, connection_manager_
, true);
344 void ViewTreeImpl::GetUnknownViewsFrom(
345 const ServerView
* view
,
346 std::vector
<const ServerView
*>* views
) {
347 if (IsViewKnown(view
) || !access_policy_
->CanGetViewTree(view
))
349 views
->push_back(view
);
350 known_views_
.insert(ViewIdToTransportId(view
->id()));
351 if (!access_policy_
->CanDescendIntoViewForViewTree(view
))
353 std::vector
<const ServerView
*> children(view
->GetChildren());
354 for (size_t i
= 0 ; i
< children
.size(); ++i
)
355 GetUnknownViewsFrom(children
[i
], views
);
358 void ViewTreeImpl::RemoveFromKnown(
359 const ServerView
* view
,
360 std::vector
<ServerView
*>* local_views
) {
361 if (view
->id().connection_id
== id_
) {
363 local_views
->push_back(GetView(view
->id()));
366 known_views_
.erase(ViewIdToTransportId(view
->id()));
367 std::vector
<const ServerView
*> children
= view
->GetChildren();
368 for (size_t i
= 0; i
< children
.size(); ++i
)
369 RemoveFromKnown(children
[i
], local_views
);
372 void ViewTreeImpl::RemoveRoot() {
374 const ViewId
root_id(*root_
);
376 // No need to do anything if we created the view.
377 if (root_id
.connection_id
== id_
)
380 client()->OnUnembed();
381 client()->OnViewDeleted(ViewIdToTransportId(root_id
));
382 connection_manager_
->OnConnectionMessagedClient(id_
);
384 // This connection no longer knows about the view. Unparent any views that
385 // were parented to views in the root.
386 std::vector
<ServerView
*> local_views
;
387 RemoveFromKnown(GetView(root_id
), &local_views
);
388 for (size_t i
= 0; i
< local_views
.size(); ++i
)
389 local_views
[i
]->parent()->Remove(local_views
[i
]);
392 Array
<ViewDataPtr
> ViewTreeImpl::ViewsToViewDatas(
393 const std::vector
<const ServerView
*>& views
) {
394 Array
<ViewDataPtr
> array(views
.size());
395 for (size_t i
= 0; i
< views
.size(); ++i
)
396 array
[i
] = ViewToViewData(views
[i
]).Pass();
400 ViewDataPtr
ViewTreeImpl::ViewToViewData(const ServerView
* view
) {
401 DCHECK(IsViewKnown(view
));
402 const ServerView
* parent
= view
->parent();
403 // If the parent isn't known, it means the parent is not visible to us (not
404 // in roots), and should not be sent over.
405 if (parent
&& !IsViewKnown(parent
))
407 ViewDataPtr
view_data(mojo::ViewData::New());
408 view_data
->parent_id
= ViewIdToTransportId(parent
? parent
->id() : ViewId());
409 view_data
->view_id
= ViewIdToTransportId(view
->id());
410 view_data
->bounds
= Rect::From(view
->bounds());
411 view_data
->properties
=
412 mojo::Map
<String
, Array
<uint8_t>>::From(view
->properties());
413 view_data
->visible
= view
->visible();
414 view_data
->drawn
= view
->IsDrawn();
415 view_data
->viewport_metrics
=
416 connection_manager_
->GetViewportMetricsForView(view
);
417 return view_data
.Pass();
420 void ViewTreeImpl::GetViewTreeImpl(
421 const ServerView
* view
,
422 std::vector
<const ServerView
*>* views
) const {
425 if (!access_policy_
->CanGetViewTree(view
))
428 views
->push_back(view
);
430 if (!access_policy_
->CanDescendIntoViewForViewTree(view
))
433 std::vector
<const ServerView
*> children(view
->GetChildren());
434 for (size_t i
= 0 ; i
< children
.size(); ++i
)
435 GetViewTreeImpl(children
[i
], views
);
438 void ViewTreeImpl::NotifyDrawnStateChanged(const ServerView
* view
,
439 bool new_drawn_value
) {
440 // Even though we don't know about view, it may be an ancestor of our root, in
441 // which case the change may effect our roots drawn state.
445 const ServerView
* root
= GetView(*root_
);
447 if (view
->Contains(root
) && (new_drawn_value
!= root
->IsDrawn())) {
448 client()->OnViewDrawnStateChanged(ViewIdToTransportId(root
->id()),
453 void ViewTreeImpl::DestroyViews() {
454 if (!view_map_
.empty()) {
455 ConnectionManager::ScopedChange
change(this, connection_manager_
, true);
456 // If we get here from the destructor we're not going to get
457 // ProcessViewDeleted(). Copy the map and delete from the copy so that we
458 // don't have to worry about whether |view_map_| changes or not.
459 ViewMap view_map_copy
;
460 view_map_
.swap(view_map_copy
);
461 STLDeleteValues(&view_map_copy
);
465 bool ViewTreeImpl::CanEmbed(const ViewId
& view_id
) const {
466 const ServerView
* view
= GetView(view_id
);
467 return view
&& access_policy_
->CanEmbed(view
);
470 void ViewTreeImpl::PrepareForEmbed(const ViewId
& view_id
) {
471 const ServerView
* view
= GetView(view_id
);
472 DCHECK(view
&& access_policy_
->CanEmbed(view
));
474 // Only allow a node to be the root for one connection.
475 ViewTreeImpl
* existing_owner
=
476 connection_manager_
->GetConnectionWithRoot(view_id
);
478 ConnectionManager::ScopedChange
change(this, connection_manager_
, true);
479 RemoveChildrenAsPartOfEmbed(view_id
);
480 if (existing_owner
) {
481 // Never message the originating connection.
482 connection_manager_
->OnConnectionMessagedClient(id_
);
483 existing_owner
->RemoveRoot();
487 void ViewTreeImpl::RemoveChildrenAsPartOfEmbed(const ViewId
& view_id
) {
488 ServerView
* view
= GetView(view_id
);
490 CHECK(view
->id().connection_id
== view_id
.connection_id
);
491 std::vector
<ServerView
*> children
= view
->GetChildren();
492 for (size_t i
= 0; i
< children
.size(); ++i
)
493 view
->Remove(children
[i
]);
496 void ViewTreeImpl::CreateView(
497 Id transport_view_id
,
498 const Callback
<void(mojo::ErrorCode
)>& callback
) {
499 callback
.Run(CreateView(ViewIdFromTransportId(transport_view_id
)));
502 void ViewTreeImpl::DeleteView(
503 Id transport_view_id
,
504 const Callback
<void(bool)>& callback
) {
505 ServerView
* view
= GetView(ViewIdFromTransportId(transport_view_id
));
506 bool success
= false;
507 if (view
&& access_policy_
->CanDeleteView(view
)) {
508 ViewTreeImpl
* connection
=
509 connection_manager_
->GetConnection(view
->id().connection_id
);
510 success
= connection
&& connection
->DeleteViewImpl(this, view
);
512 callback
.Run(success
);
515 void ViewTreeImpl::AddView(
518 const Callback
<void(bool)>& callback
) {
519 callback
.Run(AddView(ViewIdFromTransportId(parent_id
),
520 ViewIdFromTransportId(child_id
)));
523 void ViewTreeImpl::RemoveViewFromParent(
525 const Callback
<void(bool)>& callback
) {
526 bool success
= false;
527 ServerView
* view
= GetView(ViewIdFromTransportId(view_id
));
528 if (view
&& view
->parent() && access_policy_
->CanRemoveViewFromParent(view
)) {
530 ConnectionManager::ScopedChange
change(this, connection_manager_
, false);
531 view
->parent()->Remove(view
);
533 callback
.Run(success
);
536 void ViewTreeImpl::ReorderView(Id view_id
,
538 OrderDirection direction
,
539 const Callback
<void(bool)>& callback
) {
540 bool success
= false;
541 ServerView
* view
= GetView(ViewIdFromTransportId(view_id
));
542 ServerView
* relative_view
= GetView(ViewIdFromTransportId(relative_view_id
));
543 if (CanReorderView(view
, relative_view
, direction
)) {
545 ConnectionManager::ScopedChange
change(this, connection_manager_
, false);
546 view
->parent()->Reorder(view
, relative_view
, direction
);
547 connection_manager_
->ProcessViewReorder(view
, relative_view
, direction
);
549 callback
.Run(success
);
552 void ViewTreeImpl::GetViewTree(
554 const Callback
<void(Array
<ViewDataPtr
>)>& callback
) {
555 std::vector
<const ServerView
*> views(
556 GetViewTree(ViewIdFromTransportId(view_id
)));
557 callback
.Run(ViewsToViewDatas(views
));
560 void ViewTreeImpl::SetViewBounds(
562 mojo::RectPtr bounds
,
563 const Callback
<void(bool)>& callback
) {
564 ServerView
* view
= GetView(ViewIdFromTransportId(view_id
));
565 const bool success
= view
&& access_policy_
->CanSetViewBounds(view
);
567 ConnectionManager::ScopedChange
change(this, connection_manager_
, false);
568 view
->SetBounds(bounds
.To
<gfx::Rect
>());
570 callback
.Run(success
);
573 void ViewTreeImpl::SetViewVisibility(
574 Id transport_view_id
,
576 const Callback
<void(bool)>& callback
) {
578 SetViewVisibility(ViewIdFromTransportId(transport_view_id
), visible
));
581 void ViewTreeImpl::SetViewProperty(
583 const mojo::String
& name
,
584 mojo::Array
<uint8_t> value
,
585 const mojo::Callback
<void(bool)>& callback
) {
586 ServerView
* view
= GetView(ViewIdFromTransportId(view_id
));
587 const bool success
= view
&& access_policy_
->CanSetViewProperties(view
);
589 ConnectionManager::ScopedChange
change(this, connection_manager_
, false);
591 if (value
.is_null()) {
592 view
->SetProperty(name
, nullptr);
594 std::vector
<uint8_t> data
= value
.To
<std::vector
<uint8_t>>();
595 view
->SetProperty(name
, &data
);
598 callback
.Run(success
);
601 void ViewTreeImpl::RequestSurface(
603 mojo::InterfaceRequest
<mojo::Surface
> surface
,
604 mojo::SurfaceClientPtr client
) {
605 ServerView
* view
= GetView(ViewIdFromTransportId(view_id
));
606 const bool success
= view
&& access_policy_
->CanSetViewSurfaceId(view
);
609 view
->Bind(surface
.Pass(), client
.Pass());
612 void ViewTreeImpl::SetViewTextInputState(
614 mojo::TextInputStatePtr state
) {
615 ServerView
* view
= GetView(ViewIdFromTransportId(view_id
));
616 bool success
= view
&& access_policy_
->CanSetViewTextInputState(view
);
618 view
->SetTextInputState(state
.To
<ui::TextInputState
>());
621 void ViewTreeImpl::SetImeVisibility(uint32_t view_id
,
623 mojo::TextInputStatePtr state
) {
624 ServerView
* view
= GetView(ViewIdFromTransportId(view_id
));
625 bool success
= view
&& access_policy_
->CanSetViewTextInputState(view
);
627 if (!state
.is_null())
628 view
->SetTextInputState(state
.To
<ui::TextInputState
>());
629 connection_manager_
->SetImeVisibility(view
, visible
);
633 void ViewTreeImpl::SetEmbedRoot() {
634 is_embed_root_
= true;
637 void ViewTreeImpl::Embed(mojo::Id transport_view_id
,
638 mojo::ViewTreeClientPtr client
,
639 const mojo::Callback
<void(bool)>& callback
) {
640 callback
.Run(Embed(ViewIdFromTransportId(transport_view_id
), client
.Pass()));
643 void ViewTreeImpl::SetFocus(uint32_t view_id
,
644 const SetFocusCallback
& callback
) {
645 ServerView
* view
= GetView(ViewIdFromTransportId(view_id
));
646 bool success
= view
&& view
->IsDrawn() && access_policy_
->CanSetFocus(view
);
648 ConnectionManager::ScopedChange
change(this, connection_manager_
, false);
649 connection_manager_
->SetFocusedView(view
);
651 callback
.Run(success
);
654 bool ViewTreeImpl::IsRootForAccessPolicy(const ViewId
& id
) const {
658 bool ViewTreeImpl::IsViewKnownForAccessPolicy(const ServerView
* view
) const {
659 return IsViewKnown(view
);
662 bool ViewTreeImpl::IsViewRootOfAnotherConnectionForAccessPolicy(
663 const ServerView
* view
) const {
664 ViewTreeImpl
* connection
=
665 connection_manager_
->GetConnectionWithRoot(view
->id());
666 return connection
&& connection
!= this;
669 bool ViewTreeImpl::IsDescendantOfEmbedRoot(const ServerView
* view
) {
670 return is_embed_root_
&& root_
&& GetView(*root_
)->Contains(view
);
673 } // namespace view_manager