Linux: Depend on liberation-fonts package for RPMs.
[chromium-blink-merge.git] / components / mus / public / cpp / lib / view_tree_client_impl.cc
blob43a19353c72494b9515bdac7bf988dc550fef84a
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/mus/public/cpp/lib/view_tree_client_impl.h"
7 #include "components/mus/public/cpp/lib/view_private.h"
8 #include "components/mus/public/cpp/util.h"
9 #include "components/mus/public/cpp/view_observer.h"
10 #include "components/mus/public/cpp/view_tree_connection.h"
11 #include "components/mus/public/cpp/view_tree_delegate.h"
12 #include "mojo/application/public/cpp/application_impl.h"
13 #include "mojo/application/public/cpp/connect.h"
14 #include "mojo/application/public/cpp/service_provider_impl.h"
15 #include "mojo/application/public/interfaces/service_provider.mojom.h"
17 namespace mus {
19 Id MakeTransportId(ConnectionSpecificId connection_id,
20 ConnectionSpecificId local_id) {
21 return (connection_id << 16) | local_id;
24 // Helper called to construct a local view object from transport data.
25 View* AddViewToConnection(ViewTreeClientImpl* client,
26 View* parent,
27 const mojo::ViewDataPtr& view_data) {
28 // We don't use the cto that takes a ViewTreeConnection here, since it will
29 // call back to the service and attempt to create a new view.
30 View* view = ViewPrivate::LocalCreate();
31 ViewPrivate private_view(view);
32 private_view.set_connection(client);
33 private_view.set_id(view_data->view_id);
34 private_view.set_visible(view_data->visible);
35 private_view.set_drawn(view_data->drawn);
36 private_view.LocalSetViewportMetrics(mojo::ViewportMetrics(),
37 *view_data->viewport_metrics);
38 private_view.set_properties(
39 view_data->properties.To<std::map<std::string, std::vector<uint8_t>>>());
40 client->AddView(view);
41 private_view.LocalSetBounds(mojo::Rect(), *view_data->bounds);
42 if (parent)
43 ViewPrivate(parent).LocalAddChild(view);
44 return view;
47 View* BuildViewTree(ViewTreeClientImpl* client,
48 const mojo::Array<mojo::ViewDataPtr>& views,
49 View* initial_parent) {
50 std::vector<View*> parents;
51 View* root = NULL;
52 View* last_view = NULL;
53 if (initial_parent)
54 parents.push_back(initial_parent);
55 for (size_t i = 0; i < views.size(); ++i) {
56 if (last_view && views[i]->parent_id == last_view->id()) {
57 parents.push_back(last_view);
58 } else if (!parents.empty()) {
59 while (parents.back()->id() != views[i]->parent_id)
60 parents.pop_back();
62 View* view = AddViewToConnection(
63 client, !parents.empty() ? parents.back() : NULL, views[i]);
64 if (!last_view)
65 root = view;
66 last_view = view;
68 return root;
71 ViewTreeConnection* ViewTreeConnection::Create(
72 ViewTreeDelegate* delegate,
73 mojo::InterfaceRequest<mojo::ViewTreeClient> request) {
74 return new ViewTreeClientImpl(delegate, request.Pass());
77 ViewTreeClientImpl::ViewTreeClientImpl(
78 ViewTreeDelegate* delegate,
79 mojo::InterfaceRequest<mojo::ViewTreeClient> request)
80 : connection_id_(0),
81 next_id_(1),
82 delegate_(delegate),
83 root_(nullptr),
84 capture_view_(nullptr),
85 focused_view_(nullptr),
86 activated_view_(nullptr),
87 binding_(this, request.Pass()),
88 is_embed_root_(false),
89 in_destructor_(false) {}
91 ViewTreeClientImpl::~ViewTreeClientImpl() {
92 in_destructor_ = true;
94 std::vector<View*> non_owned;
95 while (!views_.empty()) {
96 IdToViewMap::iterator it = views_.begin();
97 if (OwnsView(it->second->id())) {
98 it->second->Destroy();
99 } else {
100 non_owned.push_back(it->second);
101 views_.erase(it);
105 // Delete the non-owned views last. In the typical case these are roots. The
106 // exception is the window manager and embed roots, which may know about
107 // other random views that it doesn't own.
108 // NOTE: we manually delete as we're a friend.
109 for (size_t i = 0; i < non_owned.size(); ++i)
110 delete non_owned[i];
112 delegate_->OnConnectionLost(this);
115 void ViewTreeClientImpl::DestroyView(Id view_id) {
116 DCHECK(tree_);
117 tree_->DeleteView(view_id, ActionCompletedCallback());
120 void ViewTreeClientImpl::AddChild(Id child_id, Id parent_id) {
121 DCHECK(tree_);
122 tree_->AddView(parent_id, child_id, ActionCompletedCallback());
125 void ViewTreeClientImpl::RemoveChild(Id child_id, Id parent_id) {
126 DCHECK(tree_);
127 tree_->RemoveViewFromParent(child_id, ActionCompletedCallback());
130 void ViewTreeClientImpl::Reorder(Id view_id,
131 Id relative_view_id,
132 mojo::OrderDirection direction) {
133 DCHECK(tree_);
134 tree_->ReorderView(view_id, relative_view_id, direction,
135 ActionCompletedCallback());
138 bool ViewTreeClientImpl::OwnsView(Id id) const {
139 return HiWord(id) == connection_id_;
142 void ViewTreeClientImpl::SetBounds(Id view_id, const mojo::Rect& bounds) {
143 DCHECK(tree_);
144 tree_->SetViewBounds(view_id, bounds.Clone(), ActionCompletedCallback());
147 void ViewTreeClientImpl::SetFocus(Id view_id) {
148 // In order for us to get here we had to have exposed a view, which implies we
149 // got a connection.
150 DCHECK(tree_);
151 tree_->SetFocus(view_id);
154 void ViewTreeClientImpl::SetVisible(Id view_id, bool visible) {
155 DCHECK(tree_);
156 tree_->SetViewVisibility(view_id, visible, ActionCompletedCallback());
159 void ViewTreeClientImpl::SetProperty(Id view_id,
160 const std::string& name,
161 const std::vector<uint8_t>& data) {
162 DCHECK(tree_);
163 tree_->SetViewProperty(view_id, mojo::String(name),
164 mojo::Array<uint8_t>::From(data),
165 ActionCompletedCallback());
168 void ViewTreeClientImpl::SetViewTextInputState(Id view_id,
169 mojo::TextInputStatePtr state) {
170 DCHECK(tree_);
171 tree_->SetViewTextInputState(view_id, state.Pass());
174 void ViewTreeClientImpl::SetImeVisibility(Id view_id,
175 bool visible,
176 mojo::TextInputStatePtr state) {
177 DCHECK(tree_);
178 tree_->SetImeVisibility(view_id, visible, state.Pass());
181 void ViewTreeClientImpl::Embed(Id view_id,
182 mojo::ViewTreeClientPtr client,
183 uint32_t policy_bitmask,
184 const mojo::ViewTree::EmbedCallback& callback) {
185 DCHECK(tree_);
186 tree_->Embed(view_id, client.Pass(), policy_bitmask, callback);
189 void ViewTreeClientImpl::RequestSurface(
190 Id view_id,
191 mojo::InterfaceRequest<mojo::Surface> surface,
192 mojo::SurfaceClientPtr client) {
193 DCHECK(tree_);
194 tree_->RequestSurface(view_id, surface.Pass(), client.Pass());
197 void ViewTreeClientImpl::AddView(View* view) {
198 DCHECK(views_.find(view->id()) == views_.end());
199 views_[view->id()] = view;
202 void ViewTreeClientImpl::RemoveView(Id view_id) {
203 if (focused_view_ && focused_view_->id() == view_id)
204 OnViewFocused(0);
206 IdToViewMap::iterator it = views_.find(view_id);
207 if (it != views_.end())
208 views_.erase(it);
211 void ViewTreeClientImpl::OnRootDestroyed(View* root) {
212 DCHECK_EQ(root, root_);
213 root_ = nullptr;
215 // When the root is gone we can't do anything useful.
216 if (!in_destructor_)
217 delete this;
220 ////////////////////////////////////////////////////////////////////////////////
221 // ViewTreeClientImpl, ViewTreeConnection implementation:
223 Id ViewTreeClientImpl::CreateViewOnServer() {
224 DCHECK(tree_);
225 const Id view_id = MakeTransportId(connection_id_, ++next_id_);
226 tree_->CreateView(view_id, [this](mojo::ErrorCode code) {
227 OnActionCompleted(code == mojo::ERROR_CODE_NONE);
229 return view_id;
232 View* ViewTreeClientImpl::GetRoot() {
233 return root_;
236 View* ViewTreeClientImpl::GetViewById(Id id) {
237 IdToViewMap::const_iterator it = views_.find(id);
238 return it != views_.end() ? it->second : NULL;
241 View* ViewTreeClientImpl::GetFocusedView() {
242 return focused_view_;
245 View* ViewTreeClientImpl::CreateView() {
246 View* view = new View(this, CreateViewOnServer());
247 AddView(view);
248 return view;
251 bool ViewTreeClientImpl::IsEmbedRoot() {
252 return is_embed_root_;
255 ConnectionSpecificId ViewTreeClientImpl::GetConnectionId() {
256 return connection_id_;
259 ////////////////////////////////////////////////////////////////////////////////
260 // ViewTreeClientImpl, ViewTreeClient implementation:
262 void ViewTreeClientImpl::OnEmbed(ConnectionSpecificId connection_id,
263 mojo::ViewDataPtr root_data,
264 mojo::ViewTreePtr tree,
265 Id focused_view_id,
266 uint32 access_policy) {
267 if (tree) {
268 DCHECK(!tree_);
269 tree_ = tree.Pass();
270 tree_.set_connection_error_handler([this]() { delete this; });
272 connection_id_ = connection_id;
273 is_embed_root_ =
274 (access_policy & mojo::ViewTree::ACCESS_POLICY_EMBED_ROOT) != 0;
276 DCHECK(!root_);
277 root_ = AddViewToConnection(this, nullptr, root_data);
279 focused_view_ = GetViewById(focused_view_id);
281 delegate_->OnEmbed(root_);
284 void ViewTreeClientImpl::OnEmbeddedAppDisconnected(Id view_id) {
285 View* view = GetViewById(view_id);
286 if (view) {
287 FOR_EACH_OBSERVER(ViewObserver, *ViewPrivate(view).observers(),
288 OnViewEmbeddedAppDisconnected(view));
292 void ViewTreeClientImpl::OnUnembed() {
293 delegate_->OnUnembed();
294 // This will send out the various notifications.
295 delete this;
298 void ViewTreeClientImpl::OnViewBoundsChanged(Id view_id,
299 mojo::RectPtr old_bounds,
300 mojo::RectPtr new_bounds) {
301 View* view = GetViewById(view_id);
302 ViewPrivate(view).LocalSetBounds(*old_bounds, *new_bounds);
305 namespace {
307 void SetViewportMetricsOnDecendants(View* root,
308 const mojo::ViewportMetrics& old_metrics,
309 const mojo::ViewportMetrics& new_metrics) {
310 ViewPrivate(root).LocalSetViewportMetrics(old_metrics, new_metrics);
311 const View::Children& children = root->children();
312 for (size_t i = 0; i < children.size(); ++i)
313 SetViewportMetricsOnDecendants(children[i], old_metrics, new_metrics);
317 void ViewTreeClientImpl::OnViewViewportMetricsChanged(
318 mojo::ViewportMetricsPtr old_metrics,
319 mojo::ViewportMetricsPtr new_metrics) {
320 View* view = GetRoot();
321 if (view)
322 SetViewportMetricsOnDecendants(view, *old_metrics, *new_metrics);
325 void ViewTreeClientImpl::OnViewHierarchyChanged(
326 Id view_id,
327 Id new_parent_id,
328 Id old_parent_id,
329 mojo::Array<mojo::ViewDataPtr> views) {
330 View* initial_parent = views.size() ? GetViewById(views[0]->parent_id) : NULL;
332 const bool was_view_known = GetViewById(view_id) != nullptr;
334 BuildViewTree(this, views, initial_parent);
336 // If the view was not known, then BuildViewTree() will have created it and
337 // parented the view.
338 if (!was_view_known)
339 return;
341 View* new_parent = GetViewById(new_parent_id);
342 View* old_parent = GetViewById(old_parent_id);
343 View* view = GetViewById(view_id);
344 if (new_parent)
345 ViewPrivate(new_parent).LocalAddChild(view);
346 else
347 ViewPrivate(old_parent).LocalRemoveChild(view);
350 void ViewTreeClientImpl::OnViewReordered(Id view_id,
351 Id relative_view_id,
352 mojo::OrderDirection direction) {
353 View* view = GetViewById(view_id);
354 View* relative_view = GetViewById(relative_view_id);
355 if (view && relative_view)
356 ViewPrivate(view).LocalReorder(relative_view, direction);
359 void ViewTreeClientImpl::OnViewDeleted(Id view_id) {
360 View* view = GetViewById(view_id);
361 if (view)
362 ViewPrivate(view).LocalDestroy();
365 void ViewTreeClientImpl::OnViewVisibilityChanged(Id view_id, bool visible) {
366 // TODO(sky): there is a race condition here. If this client and another
367 // client change the visibility at the same time the wrong value may be set.
368 // Deal with this some how.
369 View* view = GetViewById(view_id);
370 if (view)
371 ViewPrivate(view).LocalSetVisible(visible);
374 void ViewTreeClientImpl::OnViewDrawnStateChanged(Id view_id, bool drawn) {
375 View* view = GetViewById(view_id);
376 if (view)
377 ViewPrivate(view).LocalSetDrawn(drawn);
380 void ViewTreeClientImpl::OnViewSharedPropertyChanged(
381 Id view_id,
382 const mojo::String& name,
383 mojo::Array<uint8_t> new_data) {
384 View* view = GetViewById(view_id);
385 if (view) {
386 std::vector<uint8_t> data;
387 std::vector<uint8_t>* data_ptr = NULL;
388 if (!new_data.is_null()) {
389 data = new_data.To<std::vector<uint8_t>>();
390 data_ptr = &data;
393 view->SetSharedProperty(name, data_ptr);
397 void ViewTreeClientImpl::OnViewInputEvent(
398 Id view_id,
399 mojo::EventPtr event,
400 const mojo::Callback<void()>& ack_callback) {
401 View* view = GetViewById(view_id);
402 if (view) {
403 FOR_EACH_OBSERVER(ViewObserver, *ViewPrivate(view).observers(),
404 OnViewInputEvent(view, event));
406 ack_callback.Run();
409 void ViewTreeClientImpl::OnViewFocused(Id focused_view_id) {
410 View* focused = GetViewById(focused_view_id);
411 View* blurred = focused_view_;
412 // Update |focused_view_| before calling any of the observers, so that the
413 // observers get the correct result from calling |View::HasFocus()|,
414 // |ViewTreeConnection::GetFocusedView()| etc.
415 focused_view_ = focused;
416 if (blurred) {
417 FOR_EACH_OBSERVER(ViewObserver, *ViewPrivate(blurred).observers(),
418 OnViewFocusChanged(focused, blurred));
420 if (focused) {
421 FOR_EACH_OBSERVER(ViewObserver, *ViewPrivate(focused).observers(),
422 OnViewFocusChanged(focused, blurred));
426 ////////////////////////////////////////////////////////////////////////////////
427 // ViewTreeClientImpl, private:
429 void ViewTreeClientImpl::OnActionCompleted(bool success) {
430 if (!change_acked_callback_.is_null())
431 change_acked_callback_.Run();
434 mojo::Callback<void(bool)> ViewTreeClientImpl::ActionCompletedCallback() {
435 return [this](bool success) { OnActionCompleted(success); };
438 } // namespace mus