OLD | NEW |
| (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/lib/view_tree_client_impl.h" | |
6 | |
7 #include "components/view_manager/public/cpp/lib/view_private.h" | |
8 #include "components/view_manager/public/cpp/util.h" | |
9 #include "components/view_manager/public/cpp/view_observer.h" | |
10 #include "components/view_manager/public/cpp/view_tree_connection.h" | |
11 #include "components/view_manager/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" | |
16 | |
17 namespace mojo { | |
18 | |
19 Id MakeTransportId(ConnectionSpecificId connection_id, | |
20 ConnectionSpecificId local_id) { | |
21 return (connection_id << 16) | local_id; | |
22 } | |
23 | |
24 // Helper called to construct a local view object from transport data. | |
25 View* AddViewToConnection(ViewTreeClientImpl* client, | |
26 View* parent, | |
27 const 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(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(Rect(), *view_data->bounds); | |
42 if (parent) | |
43 ViewPrivate(parent).LocalAddChild(view); | |
44 return view; | |
45 } | |
46 | |
47 View* BuildViewTree(ViewTreeClientImpl* client, | |
48 const Array<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(); | |
61 } | |
62 View* view = AddViewToConnection( | |
63 client, !parents.empty() ? parents.back() : NULL, views[i]); | |
64 if (!last_view) | |
65 root = view; | |
66 last_view = view; | |
67 } | |
68 return root; | |
69 } | |
70 | |
71 ViewTreeConnection* ViewTreeConnection::Create( | |
72 ViewTreeDelegate* delegate, | |
73 InterfaceRequest<ViewTreeClient> request) { | |
74 return new ViewTreeClientImpl(delegate, request.Pass()); | |
75 } | |
76 | |
77 ViewTreeClientImpl::ViewTreeClientImpl( | |
78 ViewTreeDelegate* delegate, | |
79 InterfaceRequest<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) { | |
90 } | |
91 | |
92 ViewTreeClientImpl::~ViewTreeClientImpl() { | |
93 in_destructor_ = true; | |
94 | |
95 std::vector<View*> non_owned; | |
96 while (!views_.empty()) { | |
97 IdToViewMap::iterator it = views_.begin(); | |
98 if (OwnsView(it->second->id())) { | |
99 it->second->Destroy(); | |
100 } else { | |
101 non_owned.push_back(it->second); | |
102 views_.erase(it); | |
103 } | |
104 } | |
105 | |
106 // Delete the non-owned views last. In the typical case these are roots. The | |
107 // exception is the window manager and embed roots, which may know about | |
108 // other random views that it doesn't own. | |
109 // NOTE: we manually delete as we're a friend. | |
110 for (size_t i = 0; i < non_owned.size(); ++i) | |
111 delete non_owned[i]; | |
112 | |
113 delegate_->OnConnectionLost(this); | |
114 } | |
115 | |
116 void ViewTreeClientImpl::DestroyView(Id view_id) { | |
117 DCHECK(tree_); | |
118 tree_->DeleteView(view_id, ActionCompletedCallback()); | |
119 } | |
120 | |
121 void ViewTreeClientImpl::AddChild(Id child_id, Id parent_id) { | |
122 DCHECK(tree_); | |
123 tree_->AddView(parent_id, child_id, ActionCompletedCallback()); | |
124 } | |
125 | |
126 void ViewTreeClientImpl::RemoveChild(Id child_id, Id parent_id) { | |
127 DCHECK(tree_); | |
128 tree_->RemoveViewFromParent(child_id, ActionCompletedCallback()); | |
129 } | |
130 | |
131 void ViewTreeClientImpl::Reorder( | |
132 Id view_id, | |
133 Id relative_view_id, | |
134 OrderDirection direction) { | |
135 DCHECK(tree_); | |
136 tree_->ReorderView(view_id, relative_view_id, direction, | |
137 ActionCompletedCallback()); | |
138 } | |
139 | |
140 bool ViewTreeClientImpl::OwnsView(Id id) const { | |
141 return HiWord(id) == connection_id_; | |
142 } | |
143 | |
144 void ViewTreeClientImpl::SetBounds(Id view_id, const Rect& bounds) { | |
145 DCHECK(tree_); | |
146 tree_->SetViewBounds(view_id, bounds.Clone(), ActionCompletedCallback()); | |
147 } | |
148 | |
149 void ViewTreeClientImpl::SetFocus(Id view_id) { | |
150 // In order for us to get here we had to have exposed a view, which implies we | |
151 // got a connection. | |
152 DCHECK(tree_); | |
153 tree_->SetFocus(view_id); | |
154 } | |
155 | |
156 void ViewTreeClientImpl::SetVisible(Id view_id, bool visible) { | |
157 DCHECK(tree_); | |
158 tree_->SetViewVisibility(view_id, visible, ActionCompletedCallback()); | |
159 } | |
160 | |
161 void ViewTreeClientImpl::SetProperty( | |
162 Id view_id, | |
163 const std::string& name, | |
164 const std::vector<uint8_t>& data) { | |
165 DCHECK(tree_); | |
166 tree_->SetViewProperty(view_id, | |
167 String(name), | |
168 Array<uint8_t>::From(data), | |
169 ActionCompletedCallback()); | |
170 } | |
171 | |
172 void ViewTreeClientImpl::SetViewTextInputState(Id view_id, | |
173 TextInputStatePtr state) { | |
174 DCHECK(tree_); | |
175 tree_->SetViewTextInputState(view_id, state.Pass()); | |
176 } | |
177 | |
178 void ViewTreeClientImpl::SetImeVisibility(Id view_id, | |
179 bool visible, | |
180 TextInputStatePtr state) { | |
181 DCHECK(tree_); | |
182 tree_->SetImeVisibility(view_id, visible, state.Pass()); | |
183 } | |
184 | |
185 void ViewTreeClientImpl::SetAccessPolicy(Id view_id, uint32_t access_policy) { | |
186 DCHECK(tree_); | |
187 tree_->SetAccessPolicy(view_id, access_policy); | |
188 } | |
189 | |
190 void ViewTreeClientImpl::Embed(Id view_id, | |
191 ViewTreeClientPtr client, | |
192 const ViewTree::EmbedCallback& callback) { | |
193 DCHECK(tree_); | |
194 tree_->Embed(view_id, client.Pass(), callback); | |
195 } | |
196 | |
197 void ViewTreeClientImpl::RequestSurface(Id view_id, | |
198 InterfaceRequest<Surface> surface, | |
199 SurfaceClientPtr client) { | |
200 DCHECK(tree_); | |
201 tree_->RequestSurface(view_id, surface.Pass(), client.Pass()); | |
202 } | |
203 | |
204 void ViewTreeClientImpl::AddView(View* view) { | |
205 DCHECK(views_.find(view->id()) == views_.end()); | |
206 views_[view->id()] = view; | |
207 } | |
208 | |
209 void ViewTreeClientImpl::RemoveView(Id view_id) { | |
210 if (focused_view_ && focused_view_->id() == view_id) | |
211 OnViewFocused(0); | |
212 | |
213 IdToViewMap::iterator it = views_.find(view_id); | |
214 if (it != views_.end()) | |
215 views_.erase(it); | |
216 } | |
217 | |
218 void ViewTreeClientImpl::OnRootDestroyed(View* root) { | |
219 DCHECK_EQ(root, root_); | |
220 root_ = nullptr; | |
221 | |
222 // When the root is gone we can't do anything useful. | |
223 if (!in_destructor_) | |
224 delete this; | |
225 } | |
226 | |
227 //////////////////////////////////////////////////////////////////////////////// | |
228 // ViewTreeClientImpl, ViewTreeConnection implementation: | |
229 | |
230 Id ViewTreeClientImpl::CreateViewOnServer() { | |
231 DCHECK(tree_); | |
232 const Id view_id = MakeTransportId(connection_id_, ++next_id_); | |
233 tree_->CreateView(view_id, [this](ErrorCode code) { | |
234 OnActionCompleted(code == ERROR_CODE_NONE); | |
235 }); | |
236 return view_id; | |
237 } | |
238 | |
239 View* ViewTreeClientImpl::GetRoot() { | |
240 return root_; | |
241 } | |
242 | |
243 View* ViewTreeClientImpl::GetViewById(Id id) { | |
244 IdToViewMap::const_iterator it = views_.find(id); | |
245 return it != views_.end() ? it->second : NULL; | |
246 } | |
247 | |
248 View* ViewTreeClientImpl::GetFocusedView() { | |
249 return focused_view_; | |
250 } | |
251 | |
252 View* ViewTreeClientImpl::CreateView() { | |
253 View* view = new View(this, CreateViewOnServer()); | |
254 AddView(view); | |
255 return view; | |
256 } | |
257 | |
258 bool ViewTreeClientImpl::IsEmbedRoot() { | |
259 return is_embed_root_; | |
260 } | |
261 | |
262 ConnectionSpecificId ViewTreeClientImpl::GetConnectionId() { | |
263 return connection_id_; | |
264 } | |
265 | |
266 //////////////////////////////////////////////////////////////////////////////// | |
267 // ViewTreeClientImpl, ViewTreeClient implementation: | |
268 | |
269 void ViewTreeClientImpl::OnEmbed(ConnectionSpecificId connection_id, | |
270 ViewDataPtr root_data, | |
271 ViewTreePtr tree, | |
272 Id focused_view_id, | |
273 uint32 access_policy) { | |
274 if (tree) { | |
275 DCHECK(!tree_); | |
276 tree_ = tree.Pass(); | |
277 tree_.set_connection_error_handler([this]() { delete this; }); | |
278 } | |
279 connection_id_ = connection_id; | |
280 is_embed_root_ = | |
281 (access_policy & mojo::ViewTree::ACCESS_POLICY_EMBED_ROOT) != 0; | |
282 | |
283 DCHECK(!root_); | |
284 root_ = AddViewToConnection(this, nullptr, root_data); | |
285 | |
286 focused_view_ = GetViewById(focused_view_id); | |
287 | |
288 delegate_->OnEmbed(root_); | |
289 } | |
290 | |
291 void ViewTreeClientImpl::OnEmbeddedAppDisconnected(Id view_id) { | |
292 View* view = GetViewById(view_id); | |
293 if (view) { | |
294 FOR_EACH_OBSERVER(ViewObserver, *ViewPrivate(view).observers(), | |
295 OnViewEmbeddedAppDisconnected(view)); | |
296 } | |
297 } | |
298 | |
299 void ViewTreeClientImpl::OnUnembed() { | |
300 delegate_->OnUnembed(); | |
301 // This will send out the various notifications. | |
302 delete this; | |
303 } | |
304 | |
305 void ViewTreeClientImpl::OnViewBoundsChanged(Id view_id, | |
306 RectPtr old_bounds, | |
307 RectPtr new_bounds) { | |
308 View* view = GetViewById(view_id); | |
309 ViewPrivate(view).LocalSetBounds(*old_bounds, *new_bounds); | |
310 } | |
311 | |
312 namespace { | |
313 | |
314 void SetViewportMetricsOnDecendants(View* root, | |
315 const ViewportMetrics& old_metrics, | |
316 const ViewportMetrics& new_metrics) { | |
317 ViewPrivate(root).LocalSetViewportMetrics(old_metrics, new_metrics); | |
318 const View::Children& children = root->children(); | |
319 for (size_t i = 0; i < children.size(); ++i) | |
320 SetViewportMetricsOnDecendants(children[i], old_metrics, new_metrics); | |
321 } | |
322 } | |
323 | |
324 void ViewTreeClientImpl::OnViewViewportMetricsChanged( | |
325 ViewportMetricsPtr old_metrics, | |
326 ViewportMetricsPtr new_metrics) { | |
327 View* view = GetRoot(); | |
328 if (view) | |
329 SetViewportMetricsOnDecendants(view, *old_metrics, *new_metrics); | |
330 } | |
331 | |
332 void ViewTreeClientImpl::OnViewHierarchyChanged( | |
333 Id view_id, | |
334 Id new_parent_id, | |
335 Id old_parent_id, | |
336 mojo::Array<ViewDataPtr> views) { | |
337 View* initial_parent = views.size() ? | |
338 GetViewById(views[0]->parent_id) : NULL; | |
339 | |
340 const bool was_view_known = GetViewById(view_id) != nullptr; | |
341 | |
342 BuildViewTree(this, views, initial_parent); | |
343 | |
344 // If the view was not known, then BuildViewTree() will have created it and | |
345 // parented the view. | |
346 if (!was_view_known) | |
347 return; | |
348 | |
349 View* new_parent = GetViewById(new_parent_id); | |
350 View* old_parent = GetViewById(old_parent_id); | |
351 View* view = GetViewById(view_id); | |
352 if (new_parent) | |
353 ViewPrivate(new_parent).LocalAddChild(view); | |
354 else | |
355 ViewPrivate(old_parent).LocalRemoveChild(view); | |
356 } | |
357 | |
358 void ViewTreeClientImpl::OnViewReordered(Id view_id, | |
359 Id relative_view_id, | |
360 OrderDirection direction) { | |
361 View* view = GetViewById(view_id); | |
362 View* relative_view = GetViewById(relative_view_id); | |
363 if (view && relative_view) | |
364 ViewPrivate(view).LocalReorder(relative_view, direction); | |
365 } | |
366 | |
367 void ViewTreeClientImpl::OnViewDeleted(Id view_id) { | |
368 View* view = GetViewById(view_id); | |
369 if (view) | |
370 ViewPrivate(view).LocalDestroy(); | |
371 } | |
372 | |
373 void ViewTreeClientImpl::OnViewVisibilityChanged(Id view_id, bool visible) { | |
374 // TODO(sky): there is a race condition here. If this client and another | |
375 // client change the visibility at the same time the wrong value may be set. | |
376 // Deal with this some how. | |
377 View* view = GetViewById(view_id); | |
378 if (view) | |
379 ViewPrivate(view).LocalSetVisible(visible); | |
380 } | |
381 | |
382 void ViewTreeClientImpl::OnViewDrawnStateChanged(Id view_id, bool drawn) { | |
383 View* view = GetViewById(view_id); | |
384 if (view) | |
385 ViewPrivate(view).LocalSetDrawn(drawn); | |
386 } | |
387 | |
388 void ViewTreeClientImpl::OnViewSharedPropertyChanged( | |
389 Id view_id, | |
390 const String& name, | |
391 Array<uint8_t> new_data) { | |
392 View* view = GetViewById(view_id); | |
393 if (view) { | |
394 std::vector<uint8_t> data; | |
395 std::vector<uint8_t>* data_ptr = NULL; | |
396 if (!new_data.is_null()) { | |
397 data = new_data.To<std::vector<uint8_t>>(); | |
398 data_ptr = &data; | |
399 } | |
400 | |
401 view->SetSharedProperty(name, data_ptr); | |
402 } | |
403 } | |
404 | |
405 void ViewTreeClientImpl::OnViewInputEvent( | |
406 Id view_id, | |
407 EventPtr event, | |
408 const Callback<void()>& ack_callback) { | |
409 View* view = GetViewById(view_id); | |
410 if (view) { | |
411 FOR_EACH_OBSERVER(ViewObserver, | |
412 *ViewPrivate(view).observers(), | |
413 OnViewInputEvent(view, event)); | |
414 } | |
415 ack_callback.Run(); | |
416 } | |
417 | |
418 void ViewTreeClientImpl::OnViewFocused(Id focused_view_id) { | |
419 View* focused = GetViewById(focused_view_id); | |
420 View* blurred = focused_view_; | |
421 // Update |focused_view_| before calling any of the observers, so that the | |
422 // observers get the correct result from calling |View::HasFocus()|, | |
423 // |ViewTreeConnection::GetFocusedView()| etc. | |
424 focused_view_ = focused; | |
425 if (blurred) { | |
426 FOR_EACH_OBSERVER(ViewObserver, *ViewPrivate(blurred).observers(), | |
427 OnViewFocusChanged(focused, blurred)); | |
428 } | |
429 if (focused) { | |
430 FOR_EACH_OBSERVER(ViewObserver, *ViewPrivate(focused).observers(), | |
431 OnViewFocusChanged(focused, blurred)); | |
432 } | |
433 } | |
434 | |
435 //////////////////////////////////////////////////////////////////////////////// | |
436 // ViewTreeClientImpl, private: | |
437 | |
438 void ViewTreeClientImpl::OnActionCompleted(bool success) { | |
439 if (!change_acked_callback_.is_null()) | |
440 change_acked_callback_.Run(); | |
441 } | |
442 | |
443 Callback<void(bool)> ViewTreeClientImpl::ActionCompletedCallback() { | |
444 return [this](bool success) { OnActionCompleted(success); }; | |
445 } | |
446 | |
447 } // namespace mojo | |
OLD | NEW |