| 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 |