Change Shell / ShellClient to ServiceProvider
[chromium-blink-merge.git] / mojo / services / public / cpp / view_manager / lib / view_manager_synchronizer.cc
blob11d1b0107f69f93232c886d0e7ff3f4df1d33c67
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "mojo/services/public/cpp/view_manager/lib/view_manager_synchronizer.h"
7 #include "base/bind.h"
8 #include "base/run_loop.h"
9 #include "mojo/public/cpp/application/connect.h"
10 #include "mojo/public/interfaces/service_provider/service_provider.mojom.h"
11 #include "mojo/services/public/cpp/view_manager/lib/view_manager_private.h"
12 #include "mojo/services/public/cpp/view_manager/lib/view_private.h"
13 #include "mojo/services/public/cpp/view_manager/lib/view_tree_node_private.h"
14 #include "mojo/services/public/cpp/view_manager/util.h"
15 #include "third_party/skia/include/core/SkBitmap.h"
16 #include "ui/gfx/codec/png_codec.h"
18 namespace mojo {
19 namespace view_manager {
21 uint32_t MakeTransportId(uint16_t connection_id, uint16_t local_id) {
22 return (connection_id << 16) | local_id;
25 // Helper called to construct a local node/view object from transport data.
26 ViewTreeNode* AddNodeToViewManager(ViewManager* manager,
27 ViewTreeNode* parent,
28 TransportNodeId node_id,
29 TransportViewId view_id) {
30 // We don't use the ctor that takes a ViewManager here, since it will call
31 // back to the service and attempt to create a new node.
32 ViewTreeNode* node = ViewTreeNodePrivate::LocalCreate();
33 ViewTreeNodePrivate private_node(node);
34 private_node.set_view_manager(manager);
35 private_node.set_id(node_id);
36 if (parent)
37 ViewTreeNodePrivate(parent).LocalAddChild(node);
38 ViewManagerPrivate private_manager(manager);
39 private_manager.AddNode(node->id(), node);
41 // View.
42 if (view_id != 0) {
43 View* view = ViewPrivate::LocalCreate();
44 ViewPrivate private_view(view);
45 private_view.set_view_manager(manager);
46 private_view.set_id(view_id);
47 private_view.set_node(node);
48 // TODO(beng): this broadcasts notifications locally... do we want this? I
49 // don't think so. same story for LocalAddChild above!
50 private_node.LocalSetActiveView(view);
51 private_manager.AddView(view->id(), view);
53 return node;
56 ViewTreeNode* BuildNodeTree(ViewManager* manager,
57 const Array<INode>& nodes) {
58 std::vector<ViewTreeNode*> parents;
59 ViewTreeNode* root = NULL;
60 ViewTreeNode* last_node = NULL;
61 for (size_t i = 0; i < nodes.size(); ++i) {
62 if (last_node && nodes[i].parent_id() == last_node->id()) {
63 parents.push_back(last_node);
64 } else if (!parents.empty()) {
65 while (parents.back()->id() != nodes[i].parent_id())
66 parents.pop_back();
68 ViewTreeNode* node = AddNodeToViewManager(
69 manager,
70 !parents.empty() ? parents.back() : NULL,
71 nodes[i].node_id(),
72 nodes[i].view_id());
73 if (!last_node)
74 root = node;
75 last_node = node;
77 return root;
80 class ViewManagerTransaction {
81 public:
82 virtual ~ViewManagerTransaction() {}
84 void Commit() {
85 DCHECK(!committed_);
86 DoCommit();
87 committed_ = true;
90 bool committed() const { return committed_; }
92 protected:
93 enum TransactionType {
94 // View creation and destruction.
95 TYPE_CREATE_VIEW,
96 TYPE_DESTROY_VIEW,
97 // Node creation and destruction.
98 TYPE_CREATE_VIEW_TREE_NODE,
99 TYPE_DESTROY_VIEW_TREE_NODE,
100 // Modifications to the hierarchy (addition of or removal of nodes from a
101 // parent.)
102 TYPE_HIERARCHY,
103 // View replacement.
104 TYPE_SET_ACTIVE_VIEW,
105 // Node bounds.
106 TYPE_SET_BOUNDS,
107 // View contents
108 TYPE_SET_VIEW_CONTENTS
111 ViewManagerTransaction(TransactionType transaction_type,
112 ViewManagerSynchronizer* synchronizer)
113 : transaction_type_(transaction_type),
114 committed_(false),
115 synchronizer_(synchronizer) {
118 // Overridden to perform transaction-specific commit actions.
119 virtual void DoCommit() = 0;
121 // Overridden to perform transaction-specific cleanup on commit ack from the
122 // service.
123 virtual void DoActionCompleted(bool success) = 0;
125 IViewManager* service() { return synchronizer_->service_.get(); }
127 TransportChangeId GetAndAdvanceNextServerChangeId() {
128 return synchronizer_->next_server_change_id_++;
131 base::Callback<void(bool)> ActionCompletedCallback() {
132 return base::Bind(&ViewManagerTransaction::OnActionCompleted,
133 base::Unretained(this));
136 private:
137 // General callback to be used for commits to the service.
138 void OnActionCompleted(bool success) {
139 DCHECK(success);
140 DoActionCompleted(success);
141 synchronizer_->RemoveFromPendingQueue(this);
144 const TransactionType transaction_type_;
145 bool committed_;
146 ViewManagerSynchronizer* synchronizer_;
148 DISALLOW_COPY_AND_ASSIGN(ViewManagerTransaction);
151 class CreateViewTransaction : public ViewManagerTransaction {
152 public:
153 CreateViewTransaction(TransportViewId view_id,
154 ViewManagerSynchronizer* synchronizer)
155 : ViewManagerTransaction(TYPE_CREATE_VIEW, synchronizer),
156 view_id_(view_id) {}
157 virtual ~CreateViewTransaction() {}
159 private:
160 // Overridden from ViewManagerTransaction:
161 virtual void DoCommit() OVERRIDE {
162 service()->CreateView(view_id_, ActionCompletedCallback());
164 virtual void DoActionCompleted(bool success) OVERRIDE {
165 // TODO(beng): failure.
168 const TransportViewId view_id_;
170 DISALLOW_COPY_AND_ASSIGN(CreateViewTransaction);
173 class DestroyViewTransaction : public ViewManagerTransaction {
174 public:
175 DestroyViewTransaction(TransportViewId view_id,
176 ViewManagerSynchronizer* synchronizer)
177 : ViewManagerTransaction(TYPE_DESTROY_VIEW, synchronizer),
178 view_id_(view_id) {}
179 virtual ~DestroyViewTransaction() {}
181 private:
182 // Overridden from ViewManagerTransaction:
183 virtual void DoCommit() OVERRIDE {
184 service()->DeleteView(view_id_, ActionCompletedCallback());
186 virtual void DoActionCompleted(bool success) OVERRIDE {
187 // TODO(beng): recovery?
190 const TransportViewId view_id_;
192 DISALLOW_COPY_AND_ASSIGN(DestroyViewTransaction);
195 class CreateViewTreeNodeTransaction : public ViewManagerTransaction {
196 public:
197 CreateViewTreeNodeTransaction(TransportNodeId node_id,
198 ViewManagerSynchronizer* synchronizer)
199 : ViewManagerTransaction(TYPE_CREATE_VIEW_TREE_NODE, synchronizer),
200 node_id_(node_id) {}
201 virtual ~CreateViewTreeNodeTransaction() {}
203 private:
204 // Overridden from ViewManagerTransaction:
205 virtual void DoCommit() OVERRIDE {
206 service()->CreateNode(node_id_, ActionCompletedCallback());
208 virtual void DoActionCompleted(bool success) OVERRIDE {
209 // TODO(beng): Failure means we tried to create with an extant id for this
210 // connection. It also could mean we tried to do something
211 // invalid, or we tried applying a change out of order. Figure
212 // out what to do.
215 const TransportNodeId node_id_;
217 DISALLOW_COPY_AND_ASSIGN(CreateViewTreeNodeTransaction);
220 class DestroyViewTreeNodeTransaction : public ViewManagerTransaction {
221 public:
222 DestroyViewTreeNodeTransaction(TransportNodeId node_id,
223 ViewManagerSynchronizer* synchronizer)
224 : ViewManagerTransaction(TYPE_DESTROY_VIEW_TREE_NODE, synchronizer),
225 node_id_(node_id) {}
226 virtual ~DestroyViewTreeNodeTransaction() {}
228 private:
229 // Overridden from ViewManagerTransaction:
230 virtual void DoCommit() OVERRIDE {
231 service()->DeleteNode(node_id_, ActionCompletedCallback());
233 virtual void DoActionCompleted(bool success) OVERRIDE {
234 // TODO(beng): recovery?
237 const TransportNodeId node_id_;
238 DISALLOW_COPY_AND_ASSIGN(DestroyViewTreeNodeTransaction);
241 class HierarchyTransaction : public ViewManagerTransaction {
242 public:
243 enum HierarchyChangeType {
244 TYPE_ADD,
245 TYPE_REMOVE
247 HierarchyTransaction(HierarchyChangeType hierarchy_change_type,
248 TransportNodeId child_id,
249 TransportNodeId parent_id,
250 ViewManagerSynchronizer* synchronizer)
251 : ViewManagerTransaction(TYPE_HIERARCHY, synchronizer),
252 hierarchy_change_type_(hierarchy_change_type),
253 child_id_(child_id),
254 parent_id_(parent_id) {}
255 virtual ~HierarchyTransaction() {}
257 private:
258 // Overridden from ViewManagerTransaction:
259 virtual void DoCommit() OVERRIDE {
260 switch (hierarchy_change_type_) {
261 case TYPE_ADD:
262 service()->AddNode(
263 parent_id_,
264 child_id_,
265 GetAndAdvanceNextServerChangeId(),
266 ActionCompletedCallback());
267 break;
268 case TYPE_REMOVE:
269 service()->RemoveNodeFromParent(
270 child_id_,
271 GetAndAdvanceNextServerChangeId(),
272 ActionCompletedCallback());
273 break;
277 virtual void DoActionCompleted(bool success) OVERRIDE {
278 // TODO(beng): Failure means either one of the nodes specified didn't exist,
279 // or we passed the same node id for both params. Roll back?
282 const HierarchyChangeType hierarchy_change_type_;
283 const TransportNodeId child_id_;
284 const TransportNodeId parent_id_;
286 DISALLOW_COPY_AND_ASSIGN(HierarchyTransaction);
289 class SetActiveViewTransaction : public ViewManagerTransaction {
290 public:
291 SetActiveViewTransaction(TransportNodeId node_id,
292 TransportViewId view_id,
293 ViewManagerSynchronizer* synchronizer)
294 : ViewManagerTransaction(TYPE_SET_ACTIVE_VIEW, synchronizer),
295 node_id_(node_id),
296 view_id_(view_id) {}
297 virtual ~SetActiveViewTransaction() {}
299 private:
300 // Overridden from ViewManagerTransaction:
301 virtual void DoCommit() OVERRIDE {
302 service()->SetView(node_id_, view_id_, ActionCompletedCallback());
304 virtual void DoActionCompleted(bool success) OVERRIDE {
305 // TODO(beng): recovery?
308 const TransportNodeId node_id_;
309 const TransportViewId view_id_;
311 DISALLOW_COPY_AND_ASSIGN(SetActiveViewTransaction);
314 class SetBoundsTransaction : public ViewManagerTransaction {
315 public:
316 SetBoundsTransaction(TransportNodeId node_id,
317 const gfx::Rect& bounds,
318 ViewManagerSynchronizer* synchronizer)
319 : ViewManagerTransaction(TYPE_SET_BOUNDS, synchronizer),
320 node_id_(node_id),
321 bounds_(bounds) {}
322 virtual ~SetBoundsTransaction() {}
324 private:
325 // Overridden from ViewManagerTransaction:
326 virtual void DoCommit() OVERRIDE {
327 AllocationScope scope;
328 service()->SetNodeBounds(node_id_, bounds_, ActionCompletedCallback());
330 virtual void DoActionCompleted(bool success) OVERRIDE {
331 // TODO(beng): recovery?
334 const TransportNodeId node_id_;
335 const gfx::Rect bounds_;
337 DISALLOW_COPY_AND_ASSIGN(SetBoundsTransaction);
340 class SetViewContentsTransaction : public ViewManagerTransaction {
341 public:
342 SetViewContentsTransaction(TransportViewId view_id,
343 const SkBitmap& contents,
344 ViewManagerSynchronizer* synchronizer)
345 : ViewManagerTransaction(TYPE_SET_VIEW_CONTENTS, synchronizer),
346 view_id_(view_id),
347 contents_(contents) {}
348 virtual ~SetViewContentsTransaction() {}
350 private:
351 // Overridden from ViewManagerTransaction:
352 virtual void DoCommit() OVERRIDE {
353 std::vector<unsigned char> data;
354 gfx::PNGCodec::EncodeBGRASkBitmap(contents_, false, &data);
356 void* memory = NULL;
357 ScopedSharedBufferHandle duped;
358 bool result = CreateMapAndDupSharedBuffer(data.size(),
359 &memory,
360 &shared_state_handle_,
361 &duped);
362 if (!result)
363 return;
365 memcpy(memory, &data[0], data.size());
367 AllocationScope scope;
368 service()->SetViewContents(view_id_, duped.Pass(),
369 static_cast<uint32_t>(data.size()),
370 ActionCompletedCallback());
372 virtual void DoActionCompleted(bool success) OVERRIDE {
373 // TODO(beng): recovery?
376 bool CreateMapAndDupSharedBuffer(size_t size,
377 void** memory,
378 ScopedSharedBufferHandle* handle,
379 ScopedSharedBufferHandle* duped) {
380 MojoResult result = CreateSharedBuffer(NULL, size, handle);
381 if (result != MOJO_RESULT_OK)
382 return false;
383 DCHECK(handle->is_valid());
385 result = DuplicateBuffer(handle->get(), NULL, duped);
386 if (result != MOJO_RESULT_OK)
387 return false;
388 DCHECK(duped->is_valid());
390 result = MapBuffer(
391 handle->get(), 0, size, memory, MOJO_MAP_BUFFER_FLAG_NONE);
392 if (result != MOJO_RESULT_OK)
393 return false;
394 DCHECK(*memory);
396 return true;
399 const TransportViewId view_id_;
400 const SkBitmap contents_;
401 ScopedSharedBufferHandle shared_state_handle_;
403 DISALLOW_COPY_AND_ASSIGN(SetViewContentsTransaction);
406 ViewManagerSynchronizer::ViewManagerSynchronizer(ViewManager* view_manager)
407 : view_manager_(view_manager),
408 connected_(false),
409 connection_id_(0),
410 next_id_(1),
411 next_server_change_id_(0),
412 sync_factory_(this),
413 init_loop_(NULL) {
414 ConnectToService(
415 ViewManagerPrivate(view_manager_).service_provider(),
416 "mojo:mojo_view_manager",
417 &service_);
418 service_.set_client(this);
420 // Start a runloop. This loop is quit when the server tells us about the
421 // connection (OnConnectionEstablished()).
422 base::RunLoop loop;
423 init_loop_ = &loop;
424 init_loop_->Run();
425 init_loop_ = NULL;
428 ViewManagerSynchronizer::~ViewManagerSynchronizer() {
429 Sync();
432 TransportNodeId ViewManagerSynchronizer::CreateViewTreeNode() {
433 DCHECK(connected_);
434 const TransportNodeId node_id(
435 MakeTransportId(connection_id_, ++next_id_));
436 pending_transactions_.push_back(
437 new CreateViewTreeNodeTransaction(node_id, this));
438 Sync();
439 return node_id;
442 void ViewManagerSynchronizer::DestroyViewTreeNode(TransportNodeId node_id) {
443 DCHECK(connected_);
444 pending_transactions_.push_back(
445 new DestroyViewTreeNodeTransaction(node_id, this));
446 Sync();
449 TransportViewId ViewManagerSynchronizer::CreateView() {
450 DCHECK(connected_);
451 const TransportNodeId view_id(
452 MakeTransportId(connection_id_, ++next_id_));
453 pending_transactions_.push_back(new CreateViewTransaction(view_id, this));
454 Sync();
455 return view_id;
458 void ViewManagerSynchronizer::DestroyView(TransportViewId view_id) {
459 DCHECK(connected_);
460 pending_transactions_.push_back(new DestroyViewTransaction(view_id, this));
461 Sync();
464 void ViewManagerSynchronizer::AddChild(TransportNodeId child_id,
465 TransportNodeId parent_id) {
466 DCHECK(connected_);
467 pending_transactions_.push_back(
468 new HierarchyTransaction(HierarchyTransaction::TYPE_ADD,
469 child_id,
470 parent_id,
471 this));
472 Sync();
475 void ViewManagerSynchronizer::RemoveChild(TransportNodeId child_id,
476 TransportNodeId parent_id) {
477 DCHECK(connected_);
478 pending_transactions_.push_back(
479 new HierarchyTransaction(HierarchyTransaction::TYPE_REMOVE,
480 child_id,
481 parent_id,
482 this));
483 Sync();
486 bool ViewManagerSynchronizer::OwnsNode(TransportNodeId id) const {
487 return HiWord(id) == connection_id_;
490 bool ViewManagerSynchronizer::OwnsView(TransportViewId id) const {
491 return HiWord(id) == connection_id_;
494 void ViewManagerSynchronizer::SetActiveView(TransportNodeId node_id,
495 TransportViewId view_id) {
496 DCHECK(connected_);
497 pending_transactions_.push_back(
498 new SetActiveViewTransaction(node_id, view_id, this));
499 Sync();
502 void ViewManagerSynchronizer::SetBounds(TransportNodeId node_id,
503 const gfx::Rect& bounds) {
504 DCHECK(connected_);
505 pending_transactions_.push_back(
506 new SetBoundsTransaction(node_id, bounds, this));
507 Sync();
510 void ViewManagerSynchronizer::SetViewContents(TransportViewId view_id,
511 const SkBitmap& contents) {
512 DCHECK(connected_);
513 pending_transactions_.push_back(
514 new SetViewContentsTransaction(view_id, contents, this));
515 Sync();
518 ////////////////////////////////////////////////////////////////////////////////
519 // ViewManagerSynchronizer, IViewManagerClient implementation:
521 void ViewManagerSynchronizer::OnViewManagerConnectionEstablished(
522 TransportConnectionId connection_id,
523 TransportChangeId next_server_change_id,
524 const Array<INode>& nodes) {
525 connected_ = true;
526 connection_id_ = connection_id;
527 next_server_change_id_ = next_server_change_id;
529 ViewManagerPrivate(view_manager_).set_root(
530 BuildNodeTree(view_manager_, nodes));
531 if (init_loop_)
532 init_loop_->Quit();
534 Sync();
537 void ViewManagerSynchronizer::OnServerChangeIdAdvanced(
538 uint32_t next_server_change_id) {
539 next_server_change_id_ = next_server_change_id;
542 void ViewManagerSynchronizer::OnNodeBoundsChanged(uint32 node_id,
543 const Rect& old_bounds,
544 const Rect& new_bounds) {
545 ViewTreeNode* node = view_manager_->GetNodeById(node_id);
546 ViewTreeNodePrivate(node).LocalSetBounds(old_bounds, new_bounds);
549 void ViewManagerSynchronizer::OnNodeHierarchyChanged(
550 uint32_t node_id,
551 uint32_t new_parent_id,
552 uint32_t old_parent_id,
553 TransportChangeId server_change_id,
554 const Array<INode>& nodes) {
555 // TODO: deal with |nodes|.
556 next_server_change_id_ = server_change_id + 1;
558 BuildNodeTree(view_manager_, nodes);
560 ViewTreeNode* new_parent = view_manager_->GetNodeById(new_parent_id);
561 ViewTreeNode* old_parent = view_manager_->GetNodeById(old_parent_id);
562 ViewTreeNode* node = view_manager_->GetNodeById(node_id);
563 if (new_parent)
564 ViewTreeNodePrivate(new_parent).LocalAddChild(node);
565 else
566 ViewTreeNodePrivate(old_parent).LocalRemoveChild(node);
569 void ViewManagerSynchronizer::OnNodeDeleted(uint32_t node_id,
570 uint32_t server_change_id) {
571 next_server_change_id_ = server_change_id + 1;
573 ViewTreeNode* node = view_manager_->GetNodeById(node_id);
574 if (node)
575 ViewTreeNodePrivate(node).LocalDestroy();
578 void ViewManagerSynchronizer::OnNodeViewReplaced(uint32_t node_id,
579 uint32_t new_view_id,
580 uint32_t old_view_id) {
581 ViewTreeNode* node = view_manager_->GetNodeById(node_id);
582 View* new_view = view_manager_->GetViewById(new_view_id);
583 if (!new_view && new_view_id != 0) {
584 // This client wasn't aware of this View until now.
585 new_view = ViewPrivate::LocalCreate();
586 ViewPrivate private_view(new_view);
587 private_view.set_view_manager(view_manager_);
588 private_view.set_id(new_view_id);
589 private_view.set_node(node);
590 ViewManagerPrivate(view_manager_).AddView(new_view->id(), new_view);
592 View* old_view = view_manager_->GetViewById(old_view_id);
593 DCHECK_EQ(old_view, node->active_view());
594 ViewTreeNodePrivate(node).LocalSetActiveView(new_view);
597 void ViewManagerSynchronizer::OnViewDeleted(uint32_t view_id) {
598 View* view = view_manager_->GetViewById(view_id);
599 if (view)
600 ViewPrivate(view).LocalDestroy();
603 ////////////////////////////////////////////////////////////////////////////////
604 // ViewManagerSynchronizer, private:
606 void ViewManagerSynchronizer::Sync() {
607 // The service connection may not be set up yet. OnConnectionEstablished()
608 // will schedule another sync when it is.
609 if (!connected_)
610 return;
612 Transactions::const_iterator it = pending_transactions_.begin();
613 for (; it != pending_transactions_.end(); ++it) {
614 if (!(*it)->committed())
615 (*it)->Commit();
619 void ViewManagerSynchronizer::RemoveFromPendingQueue(
620 ViewManagerTransaction* transaction) {
621 DCHECK_EQ(transaction, pending_transactions_.front());
622 pending_transactions_.erase(pending_transactions_.begin());
623 if (pending_transactions_.empty() && !changes_acked_callback_.is_null())
624 changes_acked_callback_.Run();
627 } // namespace view_manager
628 } // namespace mojo