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 |