Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(639)

Side by Side Diff: services/ui/view_manager/view_registry.cc

Issue 1679023006: Reify view ownership as a message pipe. (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « services/ui/view_manager/view_registry.h ('k') | services/ui/view_manager/view_state.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
OLDNEW
« no previous file with comments | « services/ui/view_manager/view_registry.h ('k') | services/ui/view_manager/view_state.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698