| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "services/ui/view_manager/view_registry.h" | 5 #include "services/ui/view_manager/view_registry.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <utility> | 8 #include <utility> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| 11 #include "base/bind_helpers.h" | 11 #include "base/bind_helpers.h" |
| 12 #include "mojo/services/ui/views/cpp/formatting.h" | 12 #include "mojo/services/ui/views/cpp/formatting.h" |
| 13 #include "services/ui/view_manager/view_host_impl.h" | 13 #include "services/ui/view_manager/view_host_impl.h" |
| 14 #include "services/ui/view_manager/view_tree_host_impl.h" | 14 #include "services/ui/view_manager/view_tree_host_impl.h" |
| 15 | 15 |
| 16 namespace view_manager { | 16 namespace view_manager { |
| 17 | 17 namespace { |
| 18 static bool AreViewLayoutParamsValid(const mojo::ui::ViewLayoutParams* params) { | 18 bool AreViewLayoutParamsValid(const mojo::ui::ViewLayoutParams* params) { |
| 19 return params && params->constraints && params->constraints->min_width >= 0 && | 19 return params && params->constraints && params->constraints->min_width >= 0 && |
| 20 params->constraints->max_width >= params->constraints->min_width && | 20 params->constraints->max_width >= params->constraints->min_width && |
| 21 params->constraints->min_height >= 0 && | 21 params->constraints->min_height >= 0 && |
| 22 params->constraints->max_height >= params->constraints->min_height && | 22 params->constraints->max_height >= params->constraints->min_height && |
| 23 params->device_pixel_ratio > 0; | 23 params->device_pixel_ratio > 0; |
| 24 } | 24 } |
| 25 | 25 |
| 26 bool IsSizeInBounds(mojo::ui::BoxConstraints* constraints, mojo::Size* size) { |
| 27 return size && size->width >= constraints->min_width && |
| 28 size->width <= constraints->max_width && |
| 29 size->height >= constraints->min_height && |
| 30 size->height <= constraints->max_height; |
| 31 } |
| 32 } // namespace |
| 33 |
| 26 ViewRegistry::ViewRegistry(mojo::gfx::composition::CompositorPtr compositor) | 34 ViewRegistry::ViewRegistry(mojo::gfx::composition::CompositorPtr compositor) |
| 27 : compositor_(compositor.Pass()) {} | 35 : compositor_(compositor.Pass()) {} |
| 28 | 36 |
| 29 ViewRegistry::~ViewRegistry() {} | 37 ViewRegistry::~ViewRegistry() {} |
| 30 | 38 |
| 31 void ViewRegistry::ConnectAssociates( | 39 void ViewRegistry::ConnectAssociates( |
| 32 mojo::ApplicationImpl* app_impl, | 40 mojo::ApplicationImpl* app_impl, |
| 33 const std::vector<std::string>& urls, | 41 const std::vector<std::string>& urls, |
| 34 const AssociateConnectionErrorCallback& connection_error_callback) { | 42 const AssociateConnectionErrorCallback& connection_error_callback) { |
| 35 associate_table_.ConnectAssociates(app_impl, this, urls, | 43 associate_table_.ConnectAssociates(app_impl, this, urls, |
| 36 connection_error_callback); | 44 connection_error_callback); |
| 37 } | 45 } |
| 38 | 46 |
| 39 mojo::ui::ViewTokenPtr ViewRegistry::RegisterView( | 47 void ViewRegistry::RegisterView( |
| 40 mojo::ui::ViewPtr view, | 48 mojo::ui::ViewPtr view, |
| 41 mojo::InterfaceRequest<mojo::ui::ViewHost> view_host_request, | 49 mojo::InterfaceRequest<mojo::ui::ViewHost> view_host_request, |
| 50 mojo::InterfaceRequest<mojo::ui::ViewOwner> view_owner_request, |
| 42 const mojo::String& label) { | 51 const mojo::String& label) { |
| 43 DCHECK(view); | 52 DCHECK(view); |
| 53 DCHECK(view_host_request.is_pending()); |
| 54 DCHECK(view_owner_request.is_pending()); |
| 44 | 55 |
| 45 auto view_token = mojo::ui::ViewToken::New(); | 56 auto view_token = mojo::ui::ViewToken::New(); |
| 46 view_token->value = next_view_token_value_++; | 57 view_token->value = next_view_token_value_++; |
| 47 CHECK(view_token->value); | 58 CHECK(view_token->value); |
| 48 CHECK(!FindView(view_token->value)); | 59 CHECK(!FindView(view_token->value)); |
| 49 | 60 |
| 50 // Create the state and bind host to it. | 61 // Create the state and bind host to it. |
| 51 std::string sanitized_label = | 62 std::string sanitized_label = |
| 52 label.get().substr(0, mojo::ui::kLabelMaxLength); | 63 label.get().substr(0, mojo::ui::kLabelMaxLength); |
| 53 ViewState* view_state = | 64 ViewState* view_state = |
| 54 new ViewState(view.Pass(), view_token.Pass(), sanitized_label); | 65 new ViewState(this, view.Pass(), view_token.Pass(), |
| 55 ViewHostImpl* view_host = | 66 view_host_request.Pass(), sanitized_label); |
| 56 new ViewHostImpl(this, view_state, view_host_request.Pass()); | 67 view_state->BindOwner(view_owner_request.Pass()); |
| 57 view_state->set_view_host(view_host); | |
| 58 view_state->set_view_connection_error_handler( | |
| 59 base::Bind(&ViewRegistry::OnViewConnectionError, base::Unretained(this), | |
| 60 view_state)); | |
| 61 view_host->set_view_host_connection_error_handler( | |
| 62 base::Bind(&ViewRegistry::OnViewConnectionError, base::Unretained(this), | |
| 63 view_state)); | |
| 64 | 68 |
| 65 // Add to registry and return token. | 69 // Add to registry and return token. |
| 66 views_by_token_.insert({view_state->view_token()->value, view_state}); | 70 views_by_token_.insert({view_state->view_token()->value, view_state}); |
| 67 DVLOG(1) << "RegisterView: view=" << view_state; | 71 DVLOG(1) << "RegisterView: view=" << view_state; |
| 68 return view_state->view_token()->Clone(); | |
| 69 } | 72 } |
| 70 | 73 |
| 71 void ViewRegistry::OnViewConnectionError(ViewState* view_state) { | 74 void ViewRegistry::OnViewDied(ViewState* view_state, |
| 75 const std::string& reason) { |
| 72 DCHECK(IsViewStateRegisteredDebug(view_state)); | 76 DCHECK(IsViewStateRegisteredDebug(view_state)); |
| 73 DVLOG(1) << "OnViewConnectionError: view=" << view_state; | 77 DVLOG(1) << "OnViewDied: view=" << view_state << ", reason=" << reason; |
| 74 | 78 |
| 75 UnregisterView(view_state); | 79 UnregisterView(view_state); |
| 76 } | 80 } |
| 77 | 81 |
| 78 void ViewRegistry::UnregisterView(ViewState* view_state) { | 82 void ViewRegistry::UnregisterView(ViewState* view_state) { |
| 79 DCHECK(IsViewStateRegisteredDebug(view_state)); | 83 DCHECK(IsViewStateRegisteredDebug(view_state)); |
| 80 DVLOG(1) << "UnregisterView: view=" << view_state; | 84 DVLOG(1) << "UnregisterView: view=" << view_state; |
| 81 | 85 |
| 82 // Remove from parent or roots. | 86 // Remove from parent or roots. |
| 87 // This may send a view unavailable message to the view's parent or tree. |
| 83 HijackView(view_state); | 88 HijackView(view_state); |
| 84 | 89 |
| 90 // Recursively unregister all children since they will become unowned |
| 91 // at this point taking care to unlink each one before its unregistration. |
| 92 for (auto& child : view_state->UnlinkAllChildren()) |
| 93 UnregisterViewStub(std::move(child)); |
| 94 |
| 85 // Remove from registry. | 95 // Remove from registry. |
| 86 views_by_token_.erase(view_state->view_token()->value); | 96 views_by_token_.erase(view_state->view_token()->value); |
| 87 delete view_state; | 97 delete view_state; |
| 88 } | 98 } |
| 89 | 99 |
| 90 mojo::ui::ViewTreeTokenPtr ViewRegistry::RegisterViewTree( | 100 void ViewRegistry::RegisterViewTree( |
| 91 mojo::ui::ViewTreePtr view_tree, | 101 mojo::ui::ViewTreePtr view_tree, |
| 92 mojo::InterfaceRequest<mojo::ui::ViewTreeHost> view_tree_host_request, | 102 mojo::InterfaceRequest<mojo::ui::ViewTreeHost> view_tree_host_request, |
| 93 const mojo::String& label) { | 103 const mojo::String& label) { |
| 94 DCHECK(view_tree); | 104 DCHECK(view_tree); |
| 105 DCHECK(view_tree_host_request.is_pending()); |
| 95 | 106 |
| 96 auto view_tree_token = mojo::ui::ViewTreeToken::New(); | 107 auto view_tree_token = mojo::ui::ViewTreeToken::New(); |
| 97 view_tree_token->value = next_view_tree_token_value_++; | 108 view_tree_token->value = next_view_tree_token_value_++; |
| 98 CHECK(view_tree_token->value); | 109 CHECK(view_tree_token->value); |
| 99 CHECK(!FindViewTree(view_tree_token->value)); | 110 CHECK(!FindViewTree(view_tree_token->value)); |
| 100 | 111 |
| 101 // Create the state and bind host to it. | 112 // Create the state and bind host to it. |
| 102 std::string sanitized_label = | 113 std::string sanitized_label = |
| 103 label.get().substr(0, mojo::ui::kLabelMaxLength); | 114 label.get().substr(0, mojo::ui::kLabelMaxLength); |
| 104 ViewTreeState* tree_state = new ViewTreeState( | 115 ViewTreeState* tree_state = |
| 105 view_tree.Pass(), view_tree_token.Pass(), sanitized_label); | 116 new ViewTreeState(this, view_tree.Pass(), view_tree_token.Pass(), |
| 106 ViewTreeHostImpl* tree_host = | 117 view_tree_host_request.Pass(), sanitized_label); |
| 107 new ViewTreeHostImpl(this, tree_state, view_tree_host_request.Pass()); | |
| 108 tree_state->set_view_tree_host(tree_host); | |
| 109 tree_state->set_view_tree_connection_error_handler( | |
| 110 base::Bind(&ViewRegistry::OnViewTreeConnectionError, | |
| 111 base::Unretained(this), tree_state)); | |
| 112 tree_host->set_view_tree_host_connection_error_handler( | |
| 113 base::Bind(&ViewRegistry::OnViewTreeConnectionError, | |
| 114 base::Unretained(this), tree_state)); | |
| 115 | 118 |
| 116 // Add to registry. | 119 // Add to registry. |
| 117 view_trees_by_token_.insert( | 120 view_trees_by_token_.insert( |
| 118 {tree_state->view_tree_token()->value, tree_state}); | 121 {tree_state->view_tree_token()->value, tree_state}); |
| 119 DVLOG(1) << "RegisterViewTree: tree=" << tree_state; | 122 DVLOG(1) << "RegisterViewTree: tree=" << tree_state; |
| 120 return tree_state->view_tree_token()->Clone(); | |
| 121 } | 123 } |
| 122 | 124 |
| 123 void ViewRegistry::OnViewTreeConnectionError(ViewTreeState* tree_state) { | 125 void ViewRegistry::OnViewTreeDied(ViewTreeState* tree_state, |
| 126 const std::string& reason) { |
| 124 DCHECK(IsViewTreeStateRegisteredDebug(tree_state)); | 127 DCHECK(IsViewTreeStateRegisteredDebug(tree_state)); |
| 125 DVLOG(1) << "OnViewTreeConnectionError: tree=" << tree_state; | 128 DVLOG(1) << "OnViewTreeDied: tree=" << tree_state << ", reason=" << reason; |
| 126 | 129 |
| 127 UnregisterViewTree(tree_state); | 130 UnregisterViewTree(tree_state); |
| 128 } | 131 } |
| 129 | 132 |
| 130 void ViewRegistry::UnregisterViewTree(ViewTreeState* tree_state) { | 133 void ViewRegistry::UnregisterViewTree(ViewTreeState* tree_state) { |
| 131 DCHECK(IsViewTreeStateRegisteredDebug(tree_state)); | 134 DCHECK(IsViewTreeStateRegisteredDebug(tree_state)); |
| 132 DVLOG(1) << "UnregisterViewTree: tree=" << tree_state; | 135 DVLOG(1) << "UnregisterViewTree: tree=" << tree_state; |
| 133 | 136 |
| 134 // Unlink the root if needed. | 137 // Unlink the root if needed. |
| 135 if (tree_state->root()) | 138 if (tree_state->root()) |
| 136 UnlinkRoot(tree_state); | 139 UnregisterViewStub(tree_state->UnlinkRoot()); |
| 137 | 140 |
| 138 // Remove from registry. | 141 // Remove from registry. |
| 139 view_trees_by_token_.erase(tree_state->view_tree_token()->value); | 142 view_trees_by_token_.erase(tree_state->view_tree_token()->value); |
| 140 delete tree_state; | 143 delete tree_state; |
| 141 } | 144 } |
| 142 | 145 |
| 143 void ViewRegistry::CreateScene( | 146 void ViewRegistry::CreateScene( |
| 144 ViewState* view_state, | 147 ViewState* view_state, |
| 145 mojo::InterfaceRequest<mojo::gfx::composition::Scene> scene) { | 148 mojo::InterfaceRequest<mojo::gfx::composition::Scene> scene) { |
| 146 DCHECK(IsViewStateRegisteredDebug(view_state)); | 149 DCHECK(IsViewStateRegisteredDebug(view_state)); |
| 150 DCHECK(scene.is_pending()); |
| 147 DVLOG(1) << "CreateScene: view=" << view_state; | 151 DVLOG(1) << "CreateScene: view=" << view_state; |
| 148 | 152 |
| 149 compositor_->CreateScene( | 153 compositor_->CreateScene( |
| 150 scene.Pass(), view_state->label(), | 154 scene.Pass(), view_state->label(), |
| 151 base::Bind(&ViewRegistry::OnSceneCreated, base::Unretained(this), | 155 base::Bind(&ViewRegistry::OnSceneCreated, base::Unretained(this), |
| 152 view_state->GetWeakPtr())); | 156 view_state->GetWeakPtr())); |
| 153 } | 157 } |
| 154 | 158 |
| 155 void ViewRegistry::OnSceneCreated( | 159 void ViewRegistry::OnSceneCreated( |
| 156 base::WeakPtr<ViewState> view_state_weak, | 160 base::WeakPtr<ViewState> view_state_weak, |
| (...skipping 11 matching lines...) Expand all Loading... |
| 168 | 172 |
| 169 void ViewRegistry::RequestLayout(ViewState* view_state) { | 173 void ViewRegistry::RequestLayout(ViewState* view_state) { |
| 170 DCHECK(IsViewStateRegisteredDebug(view_state)); | 174 DCHECK(IsViewStateRegisteredDebug(view_state)); |
| 171 DVLOG(1) << "RequestLayout: view=" << view_state; | 175 DVLOG(1) << "RequestLayout: view=" << view_state; |
| 172 | 176 |
| 173 InvalidateLayout(view_state); | 177 InvalidateLayout(view_state); |
| 174 } | 178 } |
| 175 | 179 |
| 176 void ViewRegistry::AddChild(ViewState* parent_state, | 180 void ViewRegistry::AddChild(ViewState* parent_state, |
| 177 uint32_t child_key, | 181 uint32_t child_key, |
| 178 mojo::ui::ViewTokenPtr child_view_token) { | 182 mojo::ui::ViewOwnerPtr child_view_owner) { |
| 179 DCHECK(IsViewStateRegisteredDebug(parent_state)); | 183 DCHECK(IsViewStateRegisteredDebug(parent_state)); |
| 180 DCHECK(child_view_token); | 184 DCHECK(child_view_owner); |
| 181 DVLOG(1) << "AddChild: parent=" << parent_state << ", child_key=" << child_key | 185 DVLOG(1) << "AddChild: parent=" << parent_state |
| 182 << ", child=" << child_view_token; | 186 << ", child_key=" << child_key; |
| 183 | 187 |
| 184 // Check for duplicate children. | 188 // Ensure there are no other children with the same key. |
| 185 if (parent_state->children().find(child_key) != | 189 if (parent_state->children().find(child_key) != |
| 186 parent_state->children().end()) { | 190 parent_state->children().end()) { |
| 187 LOG(ERROR) << "View attempted to add a child with a duplicate key: " | 191 LOG(ERROR) << "View attempted to add a child with a duplicate key: " |
| 188 << "parent=" << parent_state << ", child_key=" << child_key | 192 << "parent=" << parent_state << ", child_key=" << child_key; |
| 189 << ", child=" << child_view_token; | |
| 190 UnregisterView(parent_state); | 193 UnregisterView(parent_state); |
| 191 return; | 194 return; |
| 192 } | 195 } |
| 193 | 196 |
| 194 // Check whether the desired child view still exists. | 197 // Add a stub, pending resolution of the view owner. |
| 195 // Adding a non-existent child still succeeds but the view manager will | 198 parent_state->LinkChild(child_key, std::unique_ptr<ViewStub>(new ViewStub( |
| 196 // immediately report it as being unavailable. | 199 this, child_view_owner.Pass()))); |
| 197 ViewState* child_state = FindView(child_view_token->value); | |
| 198 if (!child_state) { | |
| 199 LinkChildAsUnavailable(parent_state, child_key); | |
| 200 return; | |
| 201 } | |
| 202 | 200 |
| 203 // Check whether the child needs to be reparented. | 201 // Schedule layout of the parent on behalf of its newly added child. |
| 204 // The old parent will receive an unavailable event. For interface symmetry, | 202 // We don't need to schedule layout of the child until the parent provides |
| 205 // we deliberately do this even if the old and new parents are the same. | 203 // new layout parameters. |
| 206 HijackView(child_state); | 204 InvalidateLayoutForChild(parent_state, child_key); |
| 207 | |
| 208 // Link the child into its new parent. | |
| 209 LinkChild(parent_state, child_key, child_state); | |
| 210 } | 205 } |
| 211 | 206 |
| 212 void ViewRegistry::RemoveChild(ViewState* parent_state, uint32_t child_key) { | 207 void ViewRegistry::RemoveChild(ViewState* parent_state, |
| 208 uint32_t child_key, |
| 209 mojo::InterfaceRequest<mojo::ui::ViewOwner> |
| 210 transferred_view_owner_request) { |
| 213 DCHECK(IsViewStateRegisteredDebug(parent_state)); | 211 DCHECK(IsViewStateRegisteredDebug(parent_state)); |
| 214 DVLOG(1) << "RemoveChild: parent=" << parent_state | 212 DVLOG(1) << "RemoveChild: parent=" << parent_state |
| 215 << ", child_key=" << child_key; | 213 << ", child_key=" << child_key; |
| 216 | 214 |
| 217 // Check whether the child key exists in the parent. | 215 // Ensure the child key exists in the parent. |
| 218 auto child_it = parent_state->children().find(child_key); | 216 auto child_it = parent_state->children().find(child_key); |
| 219 if (child_it == parent_state->children().end()) { | 217 if (child_it == parent_state->children().end()) { |
| 220 LOG(ERROR) << "View attempted to remove a child with an invalid key: " | 218 LOG(ERROR) << "View attempted to remove a child with an invalid key: " |
| 221 << "parent=" << parent_state << ", child_key=" << child_key; | 219 << "parent=" << parent_state << ", child_key=" << child_key; |
| 222 UnregisterView(parent_state); | 220 UnregisterView(parent_state); |
| 223 return; | 221 return; |
| 224 } | 222 } |
| 225 | 223 |
| 226 // Unlink the child from its parent. | 224 // Unlink the child from its parent. |
| 227 UnlinkChild(parent_state, child_it); | 225 TransferOrUnregisterViewStub(parent_state->UnlinkChild(child_key), |
| 226 transferred_view_owner_request.Pass()); |
| 227 |
| 228 // Schedule layout for the parent now that it has lost its child. |
| 229 // We don't need to schedule layout for the child itself since it will |
| 230 // retain its old layout parameters until it is reparented. |
| 231 InvalidateLayout(parent_state); |
| 228 } | 232 } |
| 229 | 233 |
| 230 void ViewRegistry::LayoutChild( | 234 void ViewRegistry::LayoutChild( |
| 231 ViewState* parent_state, | 235 ViewState* parent_state, |
| 232 uint32_t child_key, | 236 uint32_t child_key, |
| 233 mojo::ui::ViewLayoutParamsPtr child_layout_params, | 237 mojo::ui::ViewLayoutParamsPtr child_layout_params, |
| 234 const ViewLayoutCallback& callback) { | 238 const ViewLayoutCallback& callback) { |
| 235 DCHECK(IsViewStateRegisteredDebug(parent_state)); | 239 DCHECK(IsViewStateRegisteredDebug(parent_state)); |
| 236 DCHECK(child_layout_params); | 240 DCHECK(child_layout_params); |
| 237 DCHECK(child_layout_params->constraints); | 241 DCHECK(child_layout_params->constraints); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 253 auto child_it = parent_state->children().find(child_key); | 257 auto child_it = parent_state->children().find(child_key); |
| 254 if (child_it == parent_state->children().end()) { | 258 if (child_it == parent_state->children().end()) { |
| 255 LOG(ERROR) << "View attempted to layout a child with an invalid key: " | 259 LOG(ERROR) << "View attempted to layout a child with an invalid key: " |
| 256 << "parent=" << parent_state << ", child_key=" << child_key | 260 << "parent=" << parent_state << ", child_key=" << child_key |
| 257 << ", child_layout_params=" << child_layout_params; | 261 << ", child_layout_params=" << child_layout_params; |
| 258 UnregisterView(parent_state); | 262 UnregisterView(parent_state); |
| 259 callback.Run(nullptr); | 263 callback.Run(nullptr); |
| 260 return; | 264 return; |
| 261 } | 265 } |
| 262 | 266 |
| 263 SetLayout(child_it->second, child_layout_params.Pass(), callback); | 267 SetLayout(child_it->second.get(), child_layout_params.Pass(), callback); |
| 264 } | 268 } |
| 265 | 269 |
| 266 void ViewRegistry::ConnectToViewService( | 270 void ViewRegistry::ConnectToViewService( |
| 267 ViewState* view_state, | 271 ViewState* view_state, |
| 268 const mojo::String& service_name, | 272 const mojo::String& service_name, |
| 269 mojo::ScopedMessagePipeHandle client_handle) { | 273 mojo::ScopedMessagePipeHandle client_handle) { |
| 270 DCHECK(IsViewStateRegisteredDebug(view_state)); | 274 DCHECK(IsViewStateRegisteredDebug(view_state)); |
| 271 | 275 |
| 272 associate_table_.ConnectToViewService(view_state->view_token()->Clone(), | 276 associate_table_.ConnectToViewService(view_state->view_token()->Clone(), |
| 273 service_name, client_handle.Pass()); | 277 service_name, client_handle.Pass()); |
| 274 } | 278 } |
| 275 | 279 |
| 276 void ViewRegistry::RequestLayout(ViewTreeState* tree_state) { | 280 void ViewRegistry::RequestLayout(ViewTreeState* tree_state) { |
| 277 DCHECK(IsViewTreeStateRegisteredDebug(tree_state)); | 281 DCHECK(IsViewTreeStateRegisteredDebug(tree_state)); |
| 278 DVLOG(1) << "RequestLayout: tree=" << tree_state; | 282 DVLOG(1) << "RequestLayout: tree=" << tree_state; |
| 279 | 283 |
| 280 InvalidateLayoutForRoot(tree_state); | 284 InvalidateLayoutForRoot(tree_state); |
| 281 } | 285 } |
| 282 | 286 |
| 283 void ViewRegistry::SetRoot(ViewTreeState* tree_state, | 287 void ViewRegistry::SetRoot(ViewTreeState* tree_state, |
| 284 uint32_t root_key, | 288 uint32_t root_key, |
| 285 mojo::ui::ViewTokenPtr root_view_token) { | 289 mojo::ui::ViewOwnerPtr root_view_owner) { |
| 286 DCHECK(IsViewTreeStateRegisteredDebug(tree_state)); | 290 DCHECK(IsViewTreeStateRegisteredDebug(tree_state)); |
| 287 DCHECK(root_view_token); | 291 DCHECK(root_view_owner); |
| 288 DVLOG(1) << "SetRoot: tree=" << tree_state << ", root_key=" << root_key | 292 DVLOG(1) << "SetRoot: tree=" << tree_state << ", root_key=" << root_key; |
| 289 << ", root=" << root_view_token; | |
| 290 | 293 |
| 291 // Check whether the desired root view still exists. | 294 // Ensure there isn't already a root. |
| 292 // Using a non-existent root view still succeeds but the view manager will | 295 if (tree_state->root()) { |
| 293 // immediately report it as being unavailable. | 296 LOG(ERROR) |
| 294 ViewState* root_state = FindView(root_view_token->value); | 297 << "View tree attempted to set the root while one is already set: tree=" |
| 295 if (root_state) { | 298 << tree_state << ", root_key=" << root_key; |
| 296 HijackView(root_state); | 299 UnregisterViewTree(tree_state); |
| 297 LinkRoot(tree_state, root_state, root_key); | 300 return; |
| 298 } else { | |
| 299 SendRootUnavailable(tree_state, root_key); | |
| 300 } | 301 } |
| 301 tree_state->set_explicit_root(true); | 302 |
| 303 // Set the root to a stub, pending resolution of the view owner. |
| 304 tree_state->LinkRoot(root_key, std::unique_ptr<ViewStub>(new ViewStub( |
| 305 this, root_view_owner.Pass()))); |
| 306 |
| 307 // Schedule layout of the tree on behalf of its newly added root. |
| 308 // We don't need to schedule layout of the root until the tree provides |
| 309 // new layout parameters. |
| 310 InvalidateLayoutForRoot(tree_state); |
| 302 } | 311 } |
| 303 | 312 |
| 304 void ViewRegistry::ResetRoot(ViewTreeState* tree_state) { | 313 void ViewRegistry::ResetRoot(ViewTreeState* tree_state, |
| 314 mojo::InterfaceRequest<mojo::ui::ViewOwner> |
| 315 transferred_view_owner_request) { |
| 305 DCHECK(IsViewTreeStateRegisteredDebug(tree_state)); | 316 DCHECK(IsViewTreeStateRegisteredDebug(tree_state)); |
| 306 DVLOG(1) << "ResetRoot: tree=" << tree_state; | 317 DVLOG(1) << "ResetRoot: tree=" << tree_state; |
| 307 | 318 |
| 308 if (tree_state->root()) | 319 // Ensure there is a root. |
| 309 UnlinkRoot(tree_state); | 320 if (!tree_state->root()) { |
| 310 tree_state->set_explicit_root(false); | 321 LOG(ERROR) |
| 322 << "View tree attempted to reset the root but there is none: tree=" |
| 323 << tree_state; |
| 324 UnregisterViewTree(tree_state); |
| 325 return; |
| 326 } |
| 327 |
| 328 // Unlink the root from its tree. |
| 329 TransferOrUnregisterViewStub(tree_state->UnlinkRoot(), |
| 330 transferred_view_owner_request.Pass()); |
| 331 |
| 332 // Note: We don't need to schedule layout for the root since it will retain |
| 333 // its old layout parameters. And there's no need to tell the tree |
| 334 // either since it won't have any work to do. So we're done. |
| 311 } | 335 } |
| 312 | 336 |
| 313 void ViewRegistry::LayoutRoot(ViewTreeState* tree_state, | 337 void ViewRegistry::LayoutRoot(ViewTreeState* tree_state, |
| 314 mojo::ui::ViewLayoutParamsPtr root_layout_params, | 338 mojo::ui::ViewLayoutParamsPtr root_layout_params, |
| 315 const ViewLayoutCallback& callback) { | 339 const ViewLayoutCallback& callback) { |
| 316 DCHECK(IsViewTreeStateRegisteredDebug(tree_state)); | 340 DCHECK(IsViewTreeStateRegisteredDebug(tree_state)); |
| 317 DCHECK(root_layout_params); | 341 DCHECK(root_layout_params); |
| 318 DCHECK(root_layout_params->constraints); | 342 DCHECK(root_layout_params->constraints); |
| 319 DVLOG(1) << "LayoutRoot: tree=" << tree_state | 343 DVLOG(1) << "LayoutRoot: tree=" << tree_state |
| 320 << ", root_layout_params=" << root_layout_params; | 344 << ", root_layout_params=" << root_layout_params; |
| 321 | 345 |
| 322 // Check whether the layout parameters are well-formed. | 346 // Check whether the layout parameters are well-formed. |
| 323 if (!AreViewLayoutParamsValid(root_layout_params.get())) { | 347 if (!AreViewLayoutParamsValid(root_layout_params.get())) { |
| 324 LOG(ERROR) << "View tree provided invalid root layout parameters: " | 348 LOG(ERROR) << "View tree provided invalid root layout parameters: " |
| 325 << "tree=" << tree_state | 349 << "tree=" << tree_state |
| 326 << ", root_layout_params=" << root_layout_params; | 350 << ", root_layout_params=" << root_layout_params; |
| 327 UnregisterViewTree(tree_state); | 351 UnregisterViewTree(tree_state); |
| 328 callback.Run(nullptr); | 352 callback.Run(nullptr); |
| 329 return; | 353 return; |
| 330 } | 354 } |
| 331 | 355 |
| 332 // Check whether the client called LayoutRoot without first having actually | 356 // Check whether the client called LayoutRoot without first having actually |
| 333 // set a root. | 357 // set a root. |
| 334 if (!tree_state->explicit_root()) { | 358 if (!tree_state->root()) { |
| 335 LOG(ERROR) << "View tree attempted to layout the rout without having " | 359 LOG(ERROR) << "View tree attempted to layout the root without having " |
| 336 "set one first: tree=" | 360 "set one first: tree=" |
| 337 << tree_state << ", root_layout_params=" << root_layout_params; | 361 << tree_state << ", root_layout_params=" << root_layout_params; |
| 338 UnregisterViewTree(tree_state); | 362 UnregisterViewTree(tree_state); |
| 339 callback.Run(nullptr); | 363 callback.Run(nullptr); |
| 340 return; | 364 return; |
| 341 } | 365 } |
| 342 | 366 |
| 343 // Check whether the root is unavailable and therefore cannot be laid out. | |
| 344 // This is not an error. | |
| 345 if (!tree_state->root()) { | |
| 346 callback.Run(nullptr); | |
| 347 return; | |
| 348 } | |
| 349 | |
| 350 SetLayout(tree_state->root(), root_layout_params.Pass(), callback); | 367 SetLayout(tree_state->root(), root_layout_params.Pass(), callback); |
| 351 } | 368 } |
| 352 | 369 |
| 353 void ViewRegistry::ConnectToViewTreeService( | 370 void ViewRegistry::ConnectToViewTreeService( |
| 354 ViewTreeState* tree_state, | 371 ViewTreeState* tree_state, |
| 355 const mojo::String& service_name, | 372 const mojo::String& service_name, |
| 356 mojo::ScopedMessagePipeHandle client_handle) { | 373 mojo::ScopedMessagePipeHandle client_handle) { |
| 357 DCHECK(IsViewTreeStateRegisteredDebug(tree_state)); | 374 DCHECK(IsViewTreeStateRegisteredDebug(tree_state)); |
| 358 | 375 |
| 359 associate_table_.ConnectToViewTreeService( | 376 associate_table_.ConnectToViewTreeService( |
| 360 tree_state->view_tree_token()->Clone(), service_name, | 377 tree_state->view_tree_token()->Clone(), service_name, |
| 361 client_handle.Pass()); | 378 client_handle.Pass()); |
| 362 } | 379 } |
| 363 | 380 |
| 364 ViewState* ViewRegistry::FindView(uint32_t view_token_value) { | 381 ViewState* ViewRegistry::FindView(uint32_t view_token_value) { |
| 365 auto it = views_by_token_.find(view_token_value); | 382 auto it = views_by_token_.find(view_token_value); |
| 366 return it != views_by_token_.end() ? it->second : nullptr; | 383 return it != views_by_token_.end() ? it->second : nullptr; |
| 367 } | 384 } |
| 368 | 385 |
| 369 void ViewRegistry::LinkChild(ViewState* parent_state, | |
| 370 uint32_t child_key, | |
| 371 ViewState* child_state) { | |
| 372 DCHECK(IsViewStateRegisteredDebug(parent_state)); | |
| 373 DCHECK(parent_state->children().find(child_key) == | |
| 374 parent_state->children().end()); | |
| 375 DCHECK(IsViewStateRegisteredDebug(child_state)); | |
| 376 | |
| 377 DVLOG(2) << "Added child " << child_key << " {" << child_state->label() | |
| 378 << "} to parent {" << parent_state->label() << "}"; | |
| 379 | |
| 380 parent_state->children().insert({child_key, child_state}); | |
| 381 child_state->SetParent(parent_state, child_key); | |
| 382 | |
| 383 // Schedule layout of the parent on behalf of its newly added child. | |
| 384 // We don't need to schedule layout of the child until the parent provides | |
| 385 // new layout parameters. | |
| 386 InvalidateLayoutForChild(parent_state, child_key); | |
| 387 } | |
| 388 | |
| 389 void ViewRegistry::LinkChildAsUnavailable(ViewState* parent_state, | |
| 390 uint32_t child_key) { | |
| 391 DCHECK(IsViewStateRegisteredDebug(parent_state)); | |
| 392 DCHECK(parent_state->children().find(child_key) == | |
| 393 parent_state->children().end()); | |
| 394 | |
| 395 DVLOG(2) << "Added unavailable child " << child_key << " to parent {" | |
| 396 << parent_state->label() << "}"; | |
| 397 | |
| 398 parent_state->children().insert({child_key, nullptr}); | |
| 399 SendChildUnavailable(parent_state, child_key); | |
| 400 | |
| 401 // Don't schedule layout for the parent just yet. Wait for it to | |
| 402 // remove its child in response to the OnChildUnavailable notification. | |
| 403 } | |
| 404 | |
| 405 void ViewRegistry::MarkChildAsUnavailable(ViewState* parent_state, | |
| 406 uint32_t child_key) { | |
| 407 DCHECK(IsViewStateRegisteredDebug(parent_state)); | |
| 408 auto child_it = parent_state->children().find(child_key); | |
| 409 DCHECK(child_it != parent_state->children().end()); | |
| 410 DCHECK(child_it->second); | |
| 411 | |
| 412 DVLOG(2) << "Marked unavailable child " << child_key << " {" | |
| 413 << child_it->second->label() << "} from parent {" | |
| 414 << parent_state->label() << "}"; | |
| 415 | |
| 416 ResetStateWhenUnlinking(child_it->second); | |
| 417 child_it->second->ResetContainer(); | |
| 418 child_it->second = nullptr; | |
| 419 SendChildUnavailable(parent_state, child_key); | |
| 420 | |
| 421 // Don't schedule layout for the parent just yet. Wait for it to | |
| 422 // remove its child in response to the OnChildUnavailable notification. | |
| 423 // We don't need to schedule layout for the child either since it will | |
| 424 // retain its old layout parameters. | |
| 425 } | |
| 426 | |
| 427 void ViewRegistry::UnlinkChild(ViewState* parent_state, | |
| 428 ViewState::ChildrenMap::iterator child_it) { | |
| 429 DCHECK(IsViewStateRegisteredDebug(parent_state)); | |
| 430 DCHECK(child_it != parent_state->children().end()); | |
| 431 | |
| 432 ViewState* child_state = child_it->second; | |
| 433 if (child_state) { | |
| 434 DVLOG(2) << "Removed child " << child_state->key() << " {" | |
| 435 << child_state->label() << "} from parent {" | |
| 436 << parent_state->label() << "}"; | |
| 437 ResetStateWhenUnlinking(child_it->second); | |
| 438 child_state->ResetContainer(); | |
| 439 } else { | |
| 440 DVLOG(2) << "Removed unavailable child " << child_it->first | |
| 441 << "} from parent {" << parent_state->label() << "}"; | |
| 442 } | |
| 443 parent_state->children().erase(child_it); | |
| 444 | |
| 445 // Schedule layout for the parent now that it has lost its child. | |
| 446 // We don't need to schedule layout for the child itself since it will | |
| 447 // retain its old layout parameters. | |
| 448 InvalidateLayout(parent_state); | |
| 449 } | |
| 450 | |
| 451 ViewTreeState* ViewRegistry::FindViewTree(uint32_t view_tree_token_value) { | 386 ViewTreeState* ViewRegistry::FindViewTree(uint32_t view_tree_token_value) { |
| 452 auto it = view_trees_by_token_.find(view_tree_token_value); | 387 auto it = view_trees_by_token_.find(view_tree_token_value); |
| 453 return it != view_trees_by_token_.end() ? it->second : nullptr; | 388 return it != view_trees_by_token_.end() ? it->second : nullptr; |
| 454 } | 389 } |
| 455 | 390 |
| 456 void ViewRegistry::LinkRoot(ViewTreeState* tree_state, | 391 void ViewRegistry::HijackView(ViewState* view_state) { |
| 457 ViewState* root_state, | 392 DCHECK(IsViewStateRegisteredDebug(view_state)); |
| 458 uint32_t root_key) { | |
| 459 DCHECK(IsViewTreeStateRegisteredDebug(tree_state)); | |
| 460 DCHECK(IsViewStateRegisteredDebug(root_state)); | |
| 461 DCHECK(!tree_state->root()); | |
| 462 DCHECK(!root_state->parent()); | |
| 463 | 393 |
| 464 DVLOG(2) << "Linked view tree root " << root_key << " {" | 394 ViewStub* view_stub = view_state->view_stub(); |
| 465 << root_state->label() << "}"; | 395 if (view_stub) |
| 466 | 396 ReleaseViewStubAndNotify(view_stub); |
| 467 tree_state->SetRoot(root_state, root_key); | |
| 468 | |
| 469 // Schedule layout of the tree on behalf of its newly added root. | |
| 470 // We don't need to schedule layout of the root until the tree provides | |
| 471 // new layout parameters. | |
| 472 InvalidateLayoutForRoot(tree_state); | |
| 473 } | 397 } |
| 474 | 398 |
| 475 void ViewRegistry::UnlinkRoot(ViewTreeState* tree_state) { | 399 void ViewRegistry::OnViewResolved(ViewStub* view_stub, |
| 476 DCHECK(IsViewTreeStateRegisteredDebug(tree_state)); | 400 mojo::ui::ViewTokenPtr view_token) { |
| 477 DCHECK(tree_state->root()); | 401 DCHECK(view_stub); |
| 478 | 402 |
| 479 DVLOG(2) << "Unlinked view tree root " << tree_state->root()->key() << " {" | 403 ViewState* view_state = view_token ? FindView(view_token->value) : nullptr; |
| 480 << tree_state->root()->label() << "}"; | 404 if (view_state) |
| 481 | 405 AttachViewStubAndNotify(view_stub, view_state); |
| 482 ResetStateWhenUnlinking(tree_state->root()); | 406 else |
| 483 tree_state->ResetRoot(); | 407 ReleaseViewStubAndNotify(view_stub); |
| 484 | |
| 485 // We don't need to schedule layout for the root since it will retain | |
| 486 // its old layout parameters. | |
| 487 } | 408 } |
| 488 | 409 |
| 489 void ViewRegistry::HijackView(ViewState* view_state) { | 410 void ViewRegistry::AttachViewStubAndNotify(ViewStub* view_stub, |
| 490 if (view_state->parent()) { | 411 ViewState* view_state) { |
| 491 MarkChildAsUnavailable(view_state->parent(), view_state->key()); | 412 DCHECK(view_stub); |
| 492 } else if (view_state->tree()) { | |
| 493 ViewTreeState* tree_state = view_state->tree(); | |
| 494 uint32_t root_key = tree_state->root()->key(); | |
| 495 UnlinkRoot(tree_state); | |
| 496 SendRootUnavailable(tree_state, root_key); | |
| 497 } | |
| 498 } | |
| 499 | 413 |
| 500 void ViewRegistry::InvalidateLayout(ViewState* view_state) { | 414 view_state->ReleaseOwner(); // don't need the ViewOwner pipe anymore |
| 501 DCHECK(IsViewStateRegisteredDebug(view_state)); | 415 view_stub->AttachView(view_state); |
| 502 | 416 |
| 503 // We can consider the layout request to have been satisfied if | 417 if (view_stub->pending_layout_request()) { |
| 504 // there is already a pending layout request in the queue that has not | 418 view_state->pending_layout_requests().push_back( |
| 505 // yet been issued (this is coalescing). Otherwise we must manufacture | 419 std::move(view_stub->pending_layout_request())); |
| 506 // a new one based on the current layout parameters. | |
| 507 if (view_state->layout_params() && | |
| 508 (view_state->pending_layout_requests().empty() || | |
| 509 view_state->pending_layout_requests().back()->issued())) { | |
| 510 EnqueueLayoutRequest(view_state, view_state->layout_params()->Clone()); | |
| 511 IssueNextViewLayoutRequest(view_state); | 420 IssueNextViewLayoutRequest(view_state); |
| 512 } | 421 } |
| 513 } | 422 } |
| 514 | 423 |
| 515 void ViewRegistry::InvalidateLayoutForChild(ViewState* parent_state, | 424 void ViewRegistry::ReleaseViewStubAndNotify(ViewStub* view_stub) { |
| 516 uint32_t child_key) { | 425 DCHECK(view_stub); |
| 517 DCHECK(IsViewStateRegisteredDebug(parent_state)); | |
| 518 DCHECK(parent_state->children().find(child_key) != | |
| 519 parent_state->children().end()); | |
| 520 | 426 |
| 521 parent_state->children_needing_layout().insert(child_key); | 427 view_stub->ReleaseView(); |
| 522 InvalidateLayout(parent_state); | 428 |
| 429 if (view_stub->parent()) |
| 430 SendChildUnavailable(view_stub->parent(), view_stub->key()); |
| 431 else if (view_stub->tree()) |
| 432 SendRootUnavailable(view_stub->tree(), view_stub->key()); |
| 433 |
| 434 // Note: We don't need to schedule layout for the previous owner. |
| 435 // We can simply wait for it to remove its unavailable child or root in |
| 436 // response to the notification at which point layout will occur. |
| 437 // We don't need to schedule layout for the child either since it will |
| 438 // retain its old layout parameters. |
| 523 } | 439 } |
| 524 | 440 |
| 525 void ViewRegistry::InvalidateLayoutForRoot(ViewTreeState* tree_state) { | 441 void ViewRegistry::TransferOrUnregisterViewStub( |
| 526 DCHECK(IsViewTreeStateRegisteredDebug(tree_state)); | 442 std::unique_ptr<ViewStub> view_stub, |
| 443 mojo::InterfaceRequest<mojo::ui::ViewOwner> |
| 444 transferred_view_owner_request) { |
| 445 DCHECK(view_stub); |
| 527 | 446 |
| 528 if (!tree_state->layout_request_pending()) { | 447 if (transferred_view_owner_request.is_pending()) { |
| 529 tree_state->set_layout_request_pending(true); | 448 if (view_stub->state()) |
| 530 IssueNextViewTreeLayoutRequest(tree_state); | 449 view_stub->state()->BindOwner(transferred_view_owner_request.Pass()); |
| 450 else if (view_stub->is_pending()) |
| 451 CHECK(false); // TODO(jeffbrown): Handle transfer of pending view |
| 452 } else { |
| 453 UnregisterViewStub(std::move(view_stub)); |
| 531 } | 454 } |
| 532 } | 455 } |
| 533 | 456 |
| 534 void ViewRegistry::SetLayout(ViewState* view_state, | 457 void ViewRegistry::UnregisterViewStub(std::unique_ptr<ViewStub> view_stub) { |
| 458 DCHECK(view_stub); |
| 459 |
| 460 if (view_stub->state()) |
| 461 UnregisterView(view_stub->state()); |
| 462 } |
| 463 |
| 464 void ViewRegistry::SetLayout(ViewStub* view_stub, |
| 535 mojo::ui::ViewLayoutParamsPtr layout_params, | 465 mojo::ui::ViewLayoutParamsPtr layout_params, |
| 536 const ViewLayoutCallback& callback) { | 466 const ViewLayoutCallback& callback) { |
| 537 DCHECK(IsViewStateRegisteredDebug(view_state)); | 467 DCHECK(view_stub); |
| 538 DCHECK(AreViewLayoutParamsValid(layout_params.get())); | 468 DCHECK(AreViewLayoutParamsValid(layout_params.get())); |
| 539 | 469 |
| 470 // Immediately discard layout requests on unavailable views. |
| 471 if (view_stub->is_unavailable()) { |
| 472 callback.Run(nullptr); |
| 473 return; |
| 474 } |
| 475 |
| 476 // For pending views, only remember the most recent distinct layout request. |
| 477 if (view_stub->is_pending()) { |
| 478 if (!view_stub->pending_layout_request() || |
| 479 !view_stub->pending_layout_request()->layout_params()->Equals( |
| 480 *layout_params)) { |
| 481 view_stub->pending_layout_request().reset( |
| 482 new ViewLayoutRequest(layout_params.Pass())); |
| 483 } |
| 484 view_stub->pending_layout_request()->AddCallback(callback); |
| 485 return; |
| 486 } |
| 487 |
| 488 // For actual views, maintain a queue of pending layout requests. |
| 489 ViewState* view_state = view_stub->state(); |
| 490 DCHECK(view_state); |
| 491 DCHECK(!view_stub->pending_layout_request()); |
| 492 |
| 540 // Check whether the currently cached layout parameters are the same | 493 // Check whether the currently cached layout parameters are the same |
| 541 // and we already have a result and we have no pending layout requests. | 494 // and we already have a result and we have no pending layout requests. |
| 542 if (view_state->pending_layout_requests().empty() && | 495 if (view_state->pending_layout_requests().empty() && |
| 543 view_state->layout_params() && | 496 view_state->layout_params() && |
| 544 view_state->layout_params()->Equals(*layout_params)) { | 497 view_state->layout_params()->Equals(*layout_params)) { |
| 545 mojo::ui::ViewLayoutInfoPtr info = view_state->CreateLayoutInfo(); | 498 mojo::ui::ViewLayoutInfoPtr info = view_state->CreateLayoutInfo(); |
| 546 if (info) { | 499 if (info) { |
| 547 DVLOG(2) << "Layout cache hit"; | 500 DVLOG(2) << "Layout cache hit"; |
| 548 view_state->set_scene_changed_since_last_report(false); | 501 view_state->set_scene_changed_since_last_report(false); |
| 549 callback.Run(info.Pass()); | 502 callback.Run(info.Pass()); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 561 } | 514 } |
| 562 | 515 |
| 563 // Enlist ourselves into the callbacks for the pending request. | 516 // Enlist ourselves into the callbacks for the pending request. |
| 564 view_state->pending_layout_requests().back()->AddCallback(callback); | 517 view_state->pending_layout_requests().back()->AddCallback(callback); |
| 565 IssueNextViewLayoutRequest(view_state); | 518 IssueNextViewLayoutRequest(view_state); |
| 566 } | 519 } |
| 567 | 520 |
| 568 void ViewRegistry::EnqueueLayoutRequest( | 521 void ViewRegistry::EnqueueLayoutRequest( |
| 569 ViewState* view_state, | 522 ViewState* view_state, |
| 570 mojo::ui::ViewLayoutParamsPtr layout_params) { | 523 mojo::ui::ViewLayoutParamsPtr layout_params) { |
| 571 DCHECK(IsViewStateRegisteredDebug(view_state)); | 524 DCHECK(view_state); |
| 572 DCHECK(AreViewLayoutParamsValid(layout_params.get())); | 525 DCHECK(AreViewLayoutParamsValid(layout_params.get())); |
| 573 | 526 |
| 574 // Drop the previous layout request if it hasn't been issued yet. | 527 // Drop the previous layout request if it hasn't been issued yet. |
| 575 // This may cause callbacks to be invoked will null information. | 528 // This may cause callbacks to be invoked will null information. |
| 576 if (!view_state->pending_layout_requests().empty() && | 529 if (!view_state->pending_layout_requests().empty() && |
| 577 !view_state->pending_layout_requests().back()->issued()) | 530 !view_state->pending_layout_requests().back()->issued()) |
| 578 view_state->pending_layout_requests().pop_back(); | 531 view_state->pending_layout_requests().pop_back(); |
| 579 | 532 |
| 580 // Enqueue the new request. | 533 // Enqueue the new request. |
| 581 view_state->pending_layout_requests().emplace_back( | 534 view_state->pending_layout_requests().emplace_back( |
| 582 std::unique_ptr<ViewLayoutRequest>( | 535 std::unique_ptr<ViewLayoutRequest>( |
| 583 new ViewLayoutRequest(layout_params.Pass()))); | 536 new ViewLayoutRequest(layout_params.Pass()))); |
| 584 } | 537 } |
| 585 | 538 |
| 539 void ViewRegistry::InvalidateLayout(ViewState* view_state) { |
| 540 DCHECK(IsViewStateRegisteredDebug(view_state)); |
| 541 |
| 542 // We can consider the layout request to have been satisfied if |
| 543 // there is already a pending layout request in the queue that has not |
| 544 // yet been issued (this is coalescing). Otherwise we must manufacture |
| 545 // a new one based on the current layout parameters. |
| 546 if (view_state->layout_params() && |
| 547 (view_state->pending_layout_requests().empty() || |
| 548 view_state->pending_layout_requests().back()->issued())) { |
| 549 EnqueueLayoutRequest(view_state, view_state->layout_params()->Clone()); |
| 550 IssueNextViewLayoutRequest(view_state); |
| 551 } |
| 552 } |
| 553 |
| 554 void ViewRegistry::InvalidateLayoutForChild(ViewState* parent_state, |
| 555 uint32_t child_key) { |
| 556 DCHECK(IsViewStateRegisteredDebug(parent_state)); |
| 557 DCHECK(parent_state->children().find(child_key) != |
| 558 parent_state->children().end()); |
| 559 |
| 560 parent_state->children_needing_layout().insert(child_key); |
| 561 InvalidateLayout(parent_state); |
| 562 } |
| 563 |
| 564 void ViewRegistry::InvalidateLayoutForRoot(ViewTreeState* tree_state) { |
| 565 DCHECK(IsViewTreeStateRegisteredDebug(tree_state)); |
| 566 |
| 567 if (!tree_state->layout_request_pending()) { |
| 568 tree_state->set_layout_request_pending(true); |
| 569 IssueNextViewTreeLayoutRequest(tree_state); |
| 570 } |
| 571 } |
| 572 |
| 586 void ViewRegistry::IssueNextViewLayoutRequest(ViewState* view_state) { | 573 void ViewRegistry::IssueNextViewLayoutRequest(ViewState* view_state) { |
| 587 DCHECK(IsViewStateRegisteredDebug(view_state)); | 574 DCHECK(IsViewStateRegisteredDebug(view_state)); |
| 588 | 575 |
| 589 if (!view_state->pending_layout_requests().empty() && | 576 if (view_state->pending_layout_requests().empty()) |
| 590 !view_state->pending_layout_requests().front()->issued()) { | 577 return; |
| 591 view_state->pending_layout_requests().front()->set_issued(true); | 578 |
| 592 SendViewLayoutRequest(view_state); | 579 ViewLayoutRequest* request = |
| 593 } | 580 view_state->pending_layout_requests().front().get(); |
| 581 if (request->issued()) |
| 582 return; |
| 583 |
| 584 // TODO: Detect ANRs |
| 585 DVLOG(1) << "IssueNextViewLayoutRequest: view_state=" << view_state; |
| 586 view_state->view()->OnLayout( |
| 587 request->layout_params()->Clone(), |
| 588 mojo::Array<uint32_t>::From(view_state->children_needing_layout()), |
| 589 base::Bind(&ViewRegistry::OnViewLayoutResult, base::Unretained(this), |
| 590 view_state->GetWeakPtr())); |
| 591 view_state->children_needing_layout().clear(); |
| 592 request->set_issued(true); |
| 594 } | 593 } |
| 595 | 594 |
| 596 void ViewRegistry::IssueNextViewTreeLayoutRequest(ViewTreeState* tree_state) { | 595 void ViewRegistry::IssueNextViewTreeLayoutRequest(ViewTreeState* tree_state) { |
| 597 DCHECK(IsViewTreeStateRegisteredDebug(tree_state)); | 596 DCHECK(IsViewTreeStateRegisteredDebug(tree_state)); |
| 598 | 597 |
| 599 if (tree_state->layout_request_pending() && | 598 if (!tree_state->layout_request_pending() || |
| 600 !tree_state->layout_request_issued()) { | 599 tree_state->layout_request_issued()) |
| 601 tree_state->set_layout_request_pending(false); | 600 return; |
| 602 tree_state->set_layout_request_issued(true); | |
| 603 SendViewTreeLayoutRequest(tree_state); | |
| 604 } | |
| 605 } | |
| 606 | |
| 607 void ViewRegistry::ResetStateWhenUnlinking(ViewState* view_state) { | |
| 608 // Clean up parent's recorded state for the child. | |
| 609 if (view_state->parent()) { | |
| 610 view_state->parent()->children_needing_layout().erase(view_state->key()); | |
| 611 } | |
| 612 } | |
| 613 | |
| 614 void ViewRegistry::SendChildUnavailable(ViewState* parent_state, | |
| 615 uint32_t child_key) { | |
| 616 DCHECK(IsViewStateRegisteredDebug(parent_state)); | |
| 617 | |
| 618 // TODO: Detect ANRs | |
| 619 DVLOG(1) << "SendChildUnavailable: child_key=" << child_key; | |
| 620 parent_state->view()->OnChildUnavailable(child_key, | |
| 621 base::Bind(&base::DoNothing)); | |
| 622 } | |
| 623 | |
| 624 void ViewRegistry::SendRootUnavailable(ViewTreeState* tree_state, | |
| 625 uint32_t root_key) { | |
| 626 DCHECK(IsViewTreeStateRegisteredDebug(tree_state)); | |
| 627 | |
| 628 // TODO: Detect ANRs | |
| 629 DVLOG(1) << "SendRootUnavailable: root_key=" << root_key; | |
| 630 tree_state->view_tree()->OnRootUnavailable(root_key, | |
| 631 base::Bind(&base::DoNothing)); | |
| 632 } | |
| 633 | |
| 634 void ViewRegistry::SendViewLayoutRequest(ViewState* view_state) { | |
| 635 DCHECK(IsViewStateRegisteredDebug(view_state)); | |
| 636 DCHECK(!view_state->pending_layout_requests().empty()); | |
| 637 DCHECK(view_state->pending_layout_requests().front()->issued()); | |
| 638 | |
| 639 // TODO: Detect ANRs | |
| 640 DVLOG(1) << "SendViewLayoutRequest: view.token=" << view_state->label(); | |
| 641 view_state->view()->OnLayout( | |
| 642 view_state->pending_layout_requests().front()->layout_params()->Clone(), | |
| 643 mojo::Array<uint32_t>::From(view_state->children_needing_layout()), | |
| 644 base::Bind(&ViewRegistry::OnViewLayoutResult, base::Unretained(this), | |
| 645 view_state->GetWeakPtr())); | |
| 646 view_state->children_needing_layout().clear(); | |
| 647 } | |
| 648 | |
| 649 void ViewRegistry::SendViewTreeLayoutRequest(ViewTreeState* tree_state) { | |
| 650 DCHECK(IsViewTreeStateRegisteredDebug(tree_state)); | |
| 651 DCHECK(tree_state->layout_request_issued()); | |
| 652 | 601 |
| 653 // TODO: Detect ANRs | 602 // TODO: Detect ANRs |
| 654 DVLOG(1) << "SendViewTreeLayoutRequest"; | 603 DVLOG(1) << "SendViewTreeLayoutRequest"; |
| 655 tree_state->view_tree()->OnLayout( | 604 tree_state->view_tree()->OnLayout( |
| 656 base::Bind(&ViewRegistry::OnViewTreeLayoutResult, base::Unretained(this), | 605 base::Bind(&ViewRegistry::OnViewTreeLayoutResult, base::Unretained(this), |
| 657 tree_state->GetWeakPtr())); | 606 tree_state->GetWeakPtr())); |
| 658 } | 607 tree_state->set_layout_request_pending(false); |
| 659 | 608 tree_state->set_layout_request_issued(true); |
| 660 static bool IsSizeInBounds(mojo::ui::BoxConstraints* constraints, | |
| 661 mojo::Size* size) { | |
| 662 return size && size->width >= constraints->min_width && | |
| 663 size->width <= constraints->max_width && | |
| 664 size->height >= constraints->min_height && | |
| 665 size->height <= constraints->max_height; | |
| 666 } | 609 } |
| 667 | 610 |
| 668 void ViewRegistry::OnViewLayoutResult(base::WeakPtr<ViewState> view_state_weak, | 611 void ViewRegistry::OnViewLayoutResult(base::WeakPtr<ViewState> view_state_weak, |
| 669 mojo::ui::ViewLayoutResultPtr result) { | 612 mojo::ui::ViewLayoutResultPtr result) { |
| 670 DCHECK(result); | 613 DCHECK(result); |
| 671 | 614 |
| 672 ViewState* view_state = view_state_weak.get(); | 615 ViewState* view_state = view_state_weak.get(); |
| 673 if (!view_state) | 616 if (!view_state) |
| 674 return; | 617 return; |
| 675 | 618 |
| 676 DCHECK(!view_state->pending_layout_requests().empty()); | 619 DCHECK(!view_state->pending_layout_requests().empty()); |
| 677 DCHECK(view_state->pending_layout_requests().front()->issued()); | 620 DCHECK(view_state->pending_layout_requests().front()->issued()); |
| 678 | 621 |
| 679 std::unique_ptr<ViewLayoutRequest> request( | 622 std::unique_ptr<ViewLayoutRequest> request( |
| 680 std::move(view_state->pending_layout_requests().front())); | 623 std::move(view_state->pending_layout_requests().front())); |
| 681 view_state->pending_layout_requests().erase( | 624 view_state->pending_layout_requests().erase( |
| 682 view_state->pending_layout_requests().begin()); | 625 view_state->pending_layout_requests().begin()); |
| 683 | 626 |
| 684 DVLOG(1) << "OnViewLayoutResult: view=" << view_state | 627 DVLOG(1) << "OnViewLayoutResult: view=" << view_state |
| 685 << ", params=" << request->layout_params() << ", result=" << result; | 628 << ", params=" << *request->layout_params() << ", result=" << result; |
| 686 | 629 |
| 687 // Validate the layout info. | 630 // Validate the layout info. |
| 688 if (!IsSizeInBounds(request->layout_params()->constraints.get(), | 631 if (!IsSizeInBounds(request->layout_params()->constraints.get(), |
| 689 result->size.get())) { | 632 result->size.get())) { |
| 690 LOG(ERROR) << "View returned invalid size in its layout info: " | 633 LOG(ERROR) << "View returned invalid size in its layout info: " |
| 691 << "view=" << view_state | 634 << "view=" << view_state |
| 692 << ", params=" << request->layout_params() | 635 << ", params=" << *request->layout_params() |
| 693 << ", result=" << result; | 636 << ", result=" << result; |
| 694 UnregisterView(view_state); | 637 UnregisterView(view_state); |
| 695 return; | 638 return; |
| 696 } | 639 } |
| 697 | 640 |
| 698 // Assume the parent or root will not see the new layout information if | 641 // Assume the parent or root will not see the new layout information if |
| 699 // there are no callbacks so we need to inform it when things change. | 642 // there are no callbacks so we need to inform it when things change. |
| 700 const bool size_changed = | 643 const bool size_changed = |
| 701 !view_state->layout_result() || | 644 !view_state->layout_result() || |
| 702 !view_state->layout_result()->size->Equals(*result->size); | 645 !view_state->layout_result()->size->Equals(*result->size); |
| 703 const bool recurse = | 646 const bool recurse = |
| 704 !request->has_callbacks() && | 647 !request->has_callbacks() && |
| 705 (size_changed || view_state->scene_changed_since_last_report()); | 648 (size_changed || view_state->scene_changed_since_last_report()); |
| 706 | 649 |
| 707 view_state->set_layout_params(request->TakeLayoutParams().Pass()); | 650 view_state->set_layout_params(request->TakeLayoutParams().Pass()); |
| 708 view_state->set_layout_result(result.Pass()); | 651 view_state->set_layout_result(result.Pass()); |
| 709 | 652 |
| 710 mojo::ui::ViewLayoutInfoPtr info = view_state->CreateLayoutInfo(); | 653 mojo::ui::ViewLayoutInfoPtr info = view_state->CreateLayoutInfo(); |
| 711 if (info) { | 654 if (info) { |
| 712 view_state->set_scene_changed_since_last_report(false); | 655 view_state->set_scene_changed_since_last_report(false); |
| 713 request->DispatchLayoutInfo(info.Pass()); | 656 request->DispatchLayoutInfo(info.Pass()); |
| 714 } | 657 } |
| 715 | 658 |
| 716 if (recurse) { | 659 if (recurse && view_state->view_stub()) { |
| 717 if (view_state->parent()) { | 660 if (view_state->view_stub()->parent()) { |
| 718 InvalidateLayoutForChild(view_state->parent(), view_state->key()); | 661 InvalidateLayoutForChild(view_state->view_stub()->parent(), |
| 719 } else if (view_state->tree()) { | 662 view_state->view_stub()->key()); |
| 720 InvalidateLayoutForRoot(view_state->tree()); | 663 } else if (view_state->view_stub()->tree()) { |
| 664 InvalidateLayoutForRoot(view_state->view_stub()->tree()); |
| 721 } | 665 } |
| 722 } | 666 } |
| 723 | 667 |
| 724 IssueNextViewLayoutRequest(view_state); | 668 IssueNextViewLayoutRequest(view_state); |
| 725 } | 669 } |
| 726 | 670 |
| 727 void ViewRegistry::OnViewTreeLayoutResult( | 671 void ViewRegistry::OnViewTreeLayoutResult( |
| 728 base::WeakPtr<ViewTreeState> tree_state_weak) { | 672 base::WeakPtr<ViewTreeState> tree_state_weak) { |
| 729 ViewTreeState* tree_state = tree_state_weak.get(); | 673 ViewTreeState* tree_state = tree_state_weak.get(); |
| 730 if (tree_state) { | 674 if (tree_state) { |
| 731 DCHECK(tree_state->layout_request_issued()); | 675 DCHECK(tree_state->layout_request_issued()); |
| 732 | 676 |
| 733 DVLOG(1) << "OnViewTreeLayoutResult"; | 677 DVLOG(1) << "OnViewTreeLayoutResult"; |
| 734 | 678 |
| 735 tree_state->set_layout_request_issued(false); | 679 tree_state->set_layout_request_issued(false); |
| 736 IssueNextViewTreeLayoutRequest(tree_state); | 680 IssueNextViewTreeLayoutRequest(tree_state); |
| 737 } | 681 } |
| 738 } | 682 } |
| 739 | 683 |
| 684 void ViewRegistry::SendChildUnavailable(ViewState* parent_state, |
| 685 uint32_t child_key) { |
| 686 DCHECK(IsViewStateRegisteredDebug(parent_state)); |
| 687 |
| 688 // TODO: Detect ANRs |
| 689 DVLOG(1) << "SendChildUnavailable: parent_state=" << parent_state |
| 690 << ", child_key=" << child_key; |
| 691 parent_state->view()->OnChildUnavailable(child_key, |
| 692 base::Bind(&base::DoNothing)); |
| 693 } |
| 694 |
| 695 void ViewRegistry::SendRootUnavailable(ViewTreeState* tree_state, |
| 696 uint32_t root_key) { |
| 697 DCHECK(IsViewTreeStateRegisteredDebug(tree_state)); |
| 698 |
| 699 // TODO: Detect ANRs |
| 700 DVLOG(1) << "SendRootUnavailable: tree_state=" << tree_state |
| 701 << ", root_key=" << root_key; |
| 702 tree_state->view_tree()->OnRootUnavailable(root_key, |
| 703 base::Bind(&base::DoNothing)); |
| 704 } |
| 705 |
| 740 } // namespace view_manager | 706 } // namespace view_manager |
| OLD | NEW |