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

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

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

Powered by Google App Engine
This is Rietveld 408576698