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_manager_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_manager_delegate.h" | |
10 #include "components/view_manager/public/cpp/view_observer.h" | |
11 #include "mojo/application/public/cpp/application_impl.h" | |
12 #include "mojo/application/public/cpp/connect.h" | |
13 #include "mojo/application/public/cpp/service_provider_impl.h" | |
14 #include "mojo/application/public/interfaces/service_provider.mojom.h" | |
15 | |
16 namespace mojo { | |
17 | |
18 Id MakeTransportId(ConnectionSpecificId connection_id, | |
19 ConnectionSpecificId local_id) { | |
20 return (connection_id << 16) | local_id; | |
21 } | |
22 | |
23 // Helper called to construct a local view object from transport data. | |
24 View* AddViewToViewManager(ViewManagerClientImpl* client, | |
25 View* parent, | |
26 const ViewDataPtr& view_data) { | |
27 // We don't use the ctor that takes a ViewManager here, since it will call | |
28 // back to the service and attempt to create a new view. | |
29 View* view = ViewPrivate::LocalCreate(); | |
30 ViewPrivate private_view(view); | |
31 private_view.set_view_manager(client); | |
32 private_view.set_id(view_data->view_id); | |
33 private_view.set_visible(view_data->visible); | |
34 private_view.set_drawn(view_data->drawn); | |
35 private_view.LocalSetViewportMetrics(ViewportMetrics(), | |
36 *view_data->viewport_metrics); | |
37 private_view.set_properties( | |
38 view_data->properties.To<std::map<std::string, std::vector<uint8_t>>>()); | |
39 client->AddView(view); | |
40 private_view.LocalSetBounds(Rect(), *view_data->bounds); | |
41 if (parent) | |
42 ViewPrivate(parent).LocalAddChild(view); | |
43 return view; | |
44 } | |
45 | |
46 View* BuildViewTree(ViewManagerClientImpl* client, | |
47 const Array<ViewDataPtr>& views, | |
48 View* initial_parent) { | |
49 std::vector<View*> parents; | |
50 View* root = NULL; | |
51 View* last_view = NULL; | |
52 if (initial_parent) | |
53 parents.push_back(initial_parent); | |
54 for (size_t i = 0; i < views.size(); ++i) { | |
55 if (last_view && views[i]->parent_id == last_view->id()) { | |
56 parents.push_back(last_view); | |
57 } else if (!parents.empty()) { | |
58 while (parents.back()->id() != views[i]->parent_id) | |
59 parents.pop_back(); | |
60 } | |
61 View* view = AddViewToViewManager( | |
62 client, !parents.empty() ? parents.back() : NULL, views[i]); | |
63 if (!last_view) | |
64 root = view; | |
65 last_view = view; | |
66 } | |
67 return root; | |
68 } | |
69 | |
70 ViewManager* ViewManager::Create( | |
71 ViewManagerDelegate* delegate, | |
72 InterfaceRequest<ViewManagerClient> request) { | |
73 return new ViewManagerClientImpl(delegate, request.Pass()); | |
74 } | |
75 | |
76 ViewManagerClientImpl::ViewManagerClientImpl( | |
77 ViewManagerDelegate* delegate, | |
78 InterfaceRequest<ViewManagerClient> request) | |
79 : connection_id_(0), | |
80 next_id_(1), | |
81 delegate_(delegate), | |
82 root_(nullptr), | |
83 capture_view_(nullptr), | |
84 focused_view_(nullptr), | |
85 activated_view_(nullptr), | |
86 binding_(this, request.Pass()), | |
87 is_embed_root_(false), | |
88 in_destructor_(false) { | |
89 } | |
90 | |
91 ViewManagerClientImpl::~ViewManagerClientImpl() { | |
92 in_destructor_ = true; | |
93 | |
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); | |
102 } | |
103 } | |
104 | |
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]; | |
111 | |
112 delegate_->OnViewManagerDestroyed(this); | |
113 } | |
114 | |
115 void ViewManagerClientImpl::DestroyView(Id view_id) { | |
116 DCHECK(service_); | |
117 service_->DeleteView(view_id, ActionCompletedCallback()); | |
118 } | |
119 | |
120 void ViewManagerClientImpl::AddChild(Id child_id, Id parent_id) { | |
121 DCHECK(service_); | |
122 service_->AddView(parent_id, child_id, ActionCompletedCallback()); | |
123 } | |
124 | |
125 void ViewManagerClientImpl::RemoveChild(Id child_id, Id parent_id) { | |
126 DCHECK(service_); | |
127 service_->RemoveViewFromParent(child_id, ActionCompletedCallback()); | |
128 } | |
129 | |
130 void ViewManagerClientImpl::Reorder( | |
131 Id view_id, | |
132 Id relative_view_id, | |
133 OrderDirection direction) { | |
134 DCHECK(service_); | |
135 service_->ReorderView(view_id, relative_view_id, direction, | |
136 ActionCompletedCallback()); | |
137 } | |
138 | |
139 bool ViewManagerClientImpl::OwnsView(Id id) const { | |
140 return HiWord(id) == connection_id_; | |
141 } | |
142 | |
143 void ViewManagerClientImpl::SetBounds(Id view_id, const Rect& bounds) { | |
144 DCHECK(service_); | |
145 service_->SetViewBounds(view_id, bounds.Clone(), ActionCompletedCallback()); | |
146 } | |
147 | |
148 void ViewManagerClientImpl::SetSurfaceId(Id view_id, SurfaceIdPtr surface_id) { | |
149 DCHECK(service_); | |
150 if (surface_id.is_null()) | |
151 return; | |
152 service_->SetViewSurfaceId( | |
153 view_id, surface_id.Pass(), ActionCompletedCallback()); | |
154 } | |
155 | |
156 void ViewManagerClientImpl::SetFocus(Id view_id) { | |
157 // In order for us to get here we had to have exposed a view, which implies we | |
158 // got a connection. | |
159 DCHECK(service_); | |
160 service_->SetFocus(view_id, ActionCompletedCallback()); | |
161 } | |
162 | |
163 void ViewManagerClientImpl::SetVisible(Id view_id, bool visible) { | |
164 DCHECK(service_); | |
165 service_->SetViewVisibility(view_id, visible, ActionCompletedCallback()); | |
166 } | |
167 | |
168 void ViewManagerClientImpl::SetProperty( | |
169 Id view_id, | |
170 const std::string& name, | |
171 const std::vector<uint8_t>& data) { | |
172 DCHECK(service_); | |
173 service_->SetViewProperty(view_id, | |
174 String(name), | |
175 Array<uint8_t>::From(data), | |
176 ActionCompletedCallback()); | |
177 } | |
178 | |
179 void ViewManagerClientImpl::SetViewTextInputState(Id view_id, | |
180 TextInputStatePtr state) { | |
181 DCHECK(service_); | |
182 service_->SetViewTextInputState(view_id, state.Pass()); | |
183 } | |
184 | |
185 void ViewManagerClientImpl::SetImeVisibility(Id view_id, | |
186 bool visible, | |
187 TextInputStatePtr state) { | |
188 DCHECK(service_); | |
189 service_->SetImeVisibility(view_id, visible, state.Pass()); | |
190 } | |
191 | |
192 void ViewManagerClientImpl::Embed(Id view_id, ViewManagerClientPtr client) { | |
193 DCHECK(service_); | |
194 service_->Embed(view_id, client.Pass(), ActionCompletedCallback()); | |
195 } | |
196 | |
197 void ViewManagerClientImpl::EmbedAllowingReembed(mojo::URLRequestPtr request, | |
198 Id view_id) { | |
199 DCHECK(service_); | |
200 service_->EmbedAllowingReembed(view_id, request.Pass(), | |
201 ActionCompletedCallback()); | |
202 } | |
203 | |
204 void ViewManagerClientImpl::AddView(View* view) { | |
205 DCHECK(views_.find(view->id()) == views_.end()); | |
206 views_[view->id()] = view; | |
207 } | |
208 | |
209 void ViewManagerClientImpl::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 ViewManagerClientImpl::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 // ViewManagerClientImpl, ViewManager implementation: | |
229 | |
230 Id ViewManagerClientImpl::CreateViewOnServer() { | |
231 DCHECK(service_); | |
232 const Id view_id = MakeTransportId(connection_id_, ++next_id_); | |
233 service_->CreateView(view_id, [this](ErrorCode code) { | |
234 OnActionCompleted(code == ERROR_CODE_NONE); | |
235 }); | |
236 return view_id; | |
237 } | |
238 | |
239 View* ViewManagerClientImpl::GetRoot() { | |
240 return root_; | |
241 } | |
242 | |
243 View* ViewManagerClientImpl::GetViewById(Id id) { | |
244 IdToViewMap::const_iterator it = views_.find(id); | |
245 return it != views_.end() ? it->second : NULL; | |
246 } | |
247 | |
248 View* ViewManagerClientImpl::GetFocusedView() { | |
249 return focused_view_; | |
250 } | |
251 | |
252 View* ViewManagerClientImpl::CreateView() { | |
253 View* view = new View(this, CreateViewOnServer()); | |
254 AddView(view); | |
255 return view; | |
256 } | |
257 | |
258 void ViewManagerClientImpl::SetEmbedRoot() { | |
259 // TODO(sky): this isn't right. The server may ignore the call. | |
260 is_embed_root_ = true; | |
261 service_->SetEmbedRoot(); | |
262 } | |
263 | |
264 //////////////////////////////////////////////////////////////////////////////// | |
265 // ViewManagerClientImpl, ViewManagerClient implementation: | |
266 | |
267 void ViewManagerClientImpl::OnEmbed(ConnectionSpecificId connection_id, | |
268 ViewDataPtr root_data, | |
269 ViewManagerServicePtr view_manager_service, | |
270 Id focused_view_id) { | |
271 if (view_manager_service) { | |
272 DCHECK(!service_); | |
273 service_ = view_manager_service.Pass(); | |
274 service_.set_connection_error_handler([this]() { delete this; }); | |
275 } | |
276 connection_id_ = connection_id; | |
277 | |
278 DCHECK(!root_); | |
279 root_ = AddViewToViewManager(this, nullptr, root_data); | |
280 | |
281 focused_view_ = GetViewById(focused_view_id); | |
282 | |
283 delegate_->OnEmbed(root_); | |
284 } | |
285 | |
286 void ViewManagerClientImpl::OnEmbedForDescendant( | |
287 Id view_id, | |
288 mojo::URLRequestPtr request, | |
289 const OnEmbedForDescendantCallback& callback) { | |
290 View* view = GetViewById(view_id); | |
291 ViewManagerClientPtr client; | |
292 if (view) | |
293 delegate_->OnEmbedForDescendant(view, request.Pass(), &client); | |
294 callback.Run(client.Pass()); | |
295 } | |
296 | |
297 void ViewManagerClientImpl::OnEmbeddedAppDisconnected(Id view_id) { | |
298 View* view = GetViewById(view_id); | |
299 if (view) { | |
300 FOR_EACH_OBSERVER(ViewObserver, *ViewPrivate(view).observers(), | |
301 OnViewEmbeddedAppDisconnected(view)); | |
302 } | |
303 } | |
304 | |
305 void ViewManagerClientImpl::OnUnembed() { | |
306 delegate_->OnUnembed(); | |
307 // This will send out the various notifications. | |
308 delete this; | |
309 } | |
310 | |
311 void ViewManagerClientImpl::OnViewBoundsChanged(Id view_id, | |
312 RectPtr old_bounds, | |
313 RectPtr new_bounds) { | |
314 View* view = GetViewById(view_id); | |
315 ViewPrivate(view).LocalSetBounds(*old_bounds, *new_bounds); | |
316 } | |
317 | |
318 namespace { | |
319 | |
320 void SetViewportMetricsOnDecendants(View* root, | |
321 const ViewportMetrics& old_metrics, | |
322 const ViewportMetrics& new_metrics) { | |
323 ViewPrivate(root).LocalSetViewportMetrics(old_metrics, new_metrics); | |
324 const View::Children& children = root->children(); | |
325 for (size_t i = 0; i < children.size(); ++i) | |
326 SetViewportMetricsOnDecendants(children[i], old_metrics, new_metrics); | |
327 } | |
328 } | |
329 | |
330 void ViewManagerClientImpl::OnViewViewportMetricsChanged( | |
331 ViewportMetricsPtr old_metrics, | |
332 ViewportMetricsPtr new_metrics) { | |
333 View* view = GetRoot(); | |
334 if (view) | |
335 SetViewportMetricsOnDecendants(view, *old_metrics, *new_metrics); | |
336 } | |
337 | |
338 void ViewManagerClientImpl::OnViewHierarchyChanged( | |
339 Id view_id, | |
340 Id new_parent_id, | |
341 Id old_parent_id, | |
342 mojo::Array<ViewDataPtr> views) { | |
343 View* initial_parent = views.size() ? | |
344 GetViewById(views[0]->parent_id) : NULL; | |
345 | |
346 const bool was_view_known = GetViewById(view_id) != nullptr; | |
347 | |
348 BuildViewTree(this, views, initial_parent); | |
349 | |
350 // If the view was not known, then BuildViewTree() will have created it and | |
351 // parented the view. | |
352 if (!was_view_known) | |
353 return; | |
354 | |
355 View* new_parent = GetViewById(new_parent_id); | |
356 View* old_parent = GetViewById(old_parent_id); | |
357 View* view = GetViewById(view_id); | |
358 if (new_parent) | |
359 ViewPrivate(new_parent).LocalAddChild(view); | |
360 else | |
361 ViewPrivate(old_parent).LocalRemoveChild(view); | |
362 } | |
363 | |
364 void ViewManagerClientImpl::OnViewReordered(Id view_id, | |
365 Id relative_view_id, | |
366 OrderDirection direction) { | |
367 View* view = GetViewById(view_id); | |
368 View* relative_view = GetViewById(relative_view_id); | |
369 if (view && relative_view) | |
370 ViewPrivate(view).LocalReorder(relative_view, direction); | |
371 } | |
372 | |
373 void ViewManagerClientImpl::OnViewDeleted(Id view_id) { | |
374 View* view = GetViewById(view_id); | |
375 if (view) | |
376 ViewPrivate(view).LocalDestroy(); | |
377 } | |
378 | |
379 void ViewManagerClientImpl::OnViewVisibilityChanged(Id view_id, bool visible) { | |
380 // TODO(sky): there is a race condition here. If this client and another | |
381 // client change the visibility at the same time the wrong value may be set. | |
382 // Deal with this some how. | |
383 View* view = GetViewById(view_id); | |
384 if (view) | |
385 ViewPrivate(view).LocalSetVisible(visible); | |
386 } | |
387 | |
388 void ViewManagerClientImpl::OnViewDrawnStateChanged(Id view_id, bool drawn) { | |
389 View* view = GetViewById(view_id); | |
390 if (view) | |
391 ViewPrivate(view).LocalSetDrawn(drawn); | |
392 } | |
393 | |
394 void ViewManagerClientImpl::OnViewSharedPropertyChanged( | |
395 Id view_id, | |
396 const String& name, | |
397 Array<uint8_t> new_data) { | |
398 View* view = GetViewById(view_id); | |
399 if (view) { | |
400 std::vector<uint8_t> data; | |
401 std::vector<uint8_t>* data_ptr = NULL; | |
402 if (!new_data.is_null()) { | |
403 data = new_data.To<std::vector<uint8_t>>(); | |
404 data_ptr = &data; | |
405 } | |
406 | |
407 view->SetSharedProperty(name, data_ptr); | |
408 } | |
409 } | |
410 | |
411 void ViewManagerClientImpl::OnViewInputEvent( | |
412 Id view_id, | |
413 EventPtr event, | |
414 const Callback<void()>& ack_callback) { | |
415 View* view = GetViewById(view_id); | |
416 if (view) { | |
417 FOR_EACH_OBSERVER(ViewObserver, | |
418 *ViewPrivate(view).observers(), | |
419 OnViewInputEvent(view, event)); | |
420 } | |
421 ack_callback.Run(); | |
422 } | |
423 | |
424 void ViewManagerClientImpl::OnViewFocused(Id focused_view_id) { | |
425 View* focused = GetViewById(focused_view_id); | |
426 View* blurred = focused_view_; | |
427 if (blurred) { | |
428 FOR_EACH_OBSERVER(ViewObserver, *ViewPrivate(blurred).observers(), | |
429 OnViewFocusChanged(focused, blurred)); | |
430 } | |
431 focused_view_ = focused; | |
432 if (focused) { | |
433 FOR_EACH_OBSERVER(ViewObserver, *ViewPrivate(focused).observers(), | |
434 OnViewFocusChanged(focused, blurred)); | |
435 } | |
436 } | |
437 | |
438 //////////////////////////////////////////////////////////////////////////////// | |
439 // ViewManagerClientImpl, private: | |
440 | |
441 void ViewManagerClientImpl::OnActionCompleted(bool success) { | |
442 if (!change_acked_callback_.is_null()) | |
443 change_acked_callback_.Run(); | |
444 } | |
445 | |
446 Callback<void(bool)> ViewManagerClientImpl::ActionCompletedCallback() { | |
447 return [this](bool success) { OnActionCompleted(success); }; | |
448 } | |
449 | |
450 } // namespace mojo | |
OLD | NEW |