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"
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"
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
,
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
);
37 ViewTreeNodePrivate(parent
).LocalAddChild(node
);
38 ViewManagerPrivate
private_manager(manager
);
39 private_manager
.AddNode(node
->id(), node
);
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
);
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())
68 ViewTreeNode
* node
= AddNodeToViewManager(
70 !parents
.empty() ? parents
.back() : NULL
,
80 class ViewManagerTransaction
{
82 virtual ~ViewManagerTransaction() {}
90 bool committed() const { return committed_
; }
93 enum TransactionType
{
94 // View creation and destruction.
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
104 TYPE_SET_ACTIVE_VIEW
,
108 TYPE_SET_VIEW_CONTENTS
111 ViewManagerTransaction(TransactionType transaction_type
,
112 ViewManagerSynchronizer
* synchronizer
)
113 : transaction_type_(transaction_type
),
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
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));
137 // General callback to be used for commits to the service.
138 void OnActionCompleted(bool success
) {
140 DoActionCompleted(success
);
141 synchronizer_
->RemoveFromPendingQueue(this);
144 const TransactionType transaction_type_
;
146 ViewManagerSynchronizer
* synchronizer_
;
148 DISALLOW_COPY_AND_ASSIGN(ViewManagerTransaction
);
151 class CreateViewTransaction
: public ViewManagerTransaction
{
153 CreateViewTransaction(TransportViewId view_id
,
154 ViewManagerSynchronizer
* synchronizer
)
155 : ViewManagerTransaction(TYPE_CREATE_VIEW
, synchronizer
),
157 virtual ~CreateViewTransaction() {}
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
{
175 DestroyViewTransaction(TransportViewId view_id
,
176 ViewManagerSynchronizer
* synchronizer
)
177 : ViewManagerTransaction(TYPE_DESTROY_VIEW
, synchronizer
),
179 virtual ~DestroyViewTransaction() {}
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
{
197 CreateViewTreeNodeTransaction(TransportNodeId node_id
,
198 ViewManagerSynchronizer
* synchronizer
)
199 : ViewManagerTransaction(TYPE_CREATE_VIEW_TREE_NODE
, synchronizer
),
201 virtual ~CreateViewTreeNodeTransaction() {}
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
215 const TransportNodeId node_id_
;
217 DISALLOW_COPY_AND_ASSIGN(CreateViewTreeNodeTransaction
);
220 class DestroyViewTreeNodeTransaction
: public ViewManagerTransaction
{
222 DestroyViewTreeNodeTransaction(TransportNodeId node_id
,
223 ViewManagerSynchronizer
* synchronizer
)
224 : ViewManagerTransaction(TYPE_DESTROY_VIEW_TREE_NODE
, synchronizer
),
226 virtual ~DestroyViewTreeNodeTransaction() {}
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
{
243 enum HierarchyChangeType
{
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
),
254 parent_id_(parent_id
) {}
255 virtual ~HierarchyTransaction() {}
258 // Overridden from ViewManagerTransaction:
259 virtual void DoCommit() OVERRIDE
{
260 switch (hierarchy_change_type_
) {
265 GetAndAdvanceNextServerChangeId(),
266 ActionCompletedCallback());
269 service()->RemoveNodeFromParent(
271 GetAndAdvanceNextServerChangeId(),
272 ActionCompletedCallback());
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
{
291 SetActiveViewTransaction(TransportNodeId node_id
,
292 TransportViewId view_id
,
293 ViewManagerSynchronizer
* synchronizer
)
294 : ViewManagerTransaction(TYPE_SET_ACTIVE_VIEW
, synchronizer
),
297 virtual ~SetActiveViewTransaction() {}
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
{
316 SetBoundsTransaction(TransportNodeId node_id
,
317 const gfx::Rect
& bounds
,
318 ViewManagerSynchronizer
* synchronizer
)
319 : ViewManagerTransaction(TYPE_SET_BOUNDS
, synchronizer
),
322 virtual ~SetBoundsTransaction() {}
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
{
342 SetViewContentsTransaction(TransportViewId view_id
,
343 const SkBitmap
& contents
,
344 ViewManagerSynchronizer
* synchronizer
)
345 : ViewManagerTransaction(TYPE_SET_VIEW_CONTENTS
, synchronizer
),
347 contents_(contents
) {}
348 virtual ~SetViewContentsTransaction() {}
351 // Overridden from ViewManagerTransaction:
352 virtual void DoCommit() OVERRIDE
{
353 std::vector
<unsigned char> data
;
354 gfx::PNGCodec::EncodeBGRASkBitmap(contents_
, false, &data
);
357 ScopedSharedBufferHandle duped
;
358 bool result
= CreateMapAndDupSharedBuffer(data
.size(),
360 &shared_state_handle_
,
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
,
378 ScopedSharedBufferHandle
* handle
,
379 ScopedSharedBufferHandle
* duped
) {
380 MojoResult result
= CreateSharedBuffer(NULL
, size
, handle
);
381 if (result
!= MOJO_RESULT_OK
)
383 DCHECK(handle
->is_valid());
385 result
= DuplicateBuffer(handle
->get(), NULL
, duped
);
386 if (result
!= MOJO_RESULT_OK
)
388 DCHECK(duped
->is_valid());
391 handle
->get(), 0, size
, memory
, MOJO_MAP_BUFFER_FLAG_NONE
);
392 if (result
!= MOJO_RESULT_OK
)
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
),
411 next_server_change_id_(0),
415 ViewManagerPrivate(view_manager_
).service_provider(),
416 "mojo:mojo_view_manager",
418 service_
.set_client(this);
420 // Start a runloop. This loop is quit when the server tells us about the
421 // connection (OnConnectionEstablished()).
428 ViewManagerSynchronizer::~ViewManagerSynchronizer() {
432 TransportNodeId
ViewManagerSynchronizer::CreateViewTreeNode() {
434 const TransportNodeId
node_id(
435 MakeTransportId(connection_id_
, ++next_id_
));
436 pending_transactions_
.push_back(
437 new CreateViewTreeNodeTransaction(node_id
, this));
442 void ViewManagerSynchronizer::DestroyViewTreeNode(TransportNodeId node_id
) {
444 pending_transactions_
.push_back(
445 new DestroyViewTreeNodeTransaction(node_id
, this));
449 TransportViewId
ViewManagerSynchronizer::CreateView() {
451 const TransportNodeId
view_id(
452 MakeTransportId(connection_id_
, ++next_id_
));
453 pending_transactions_
.push_back(new CreateViewTransaction(view_id
, this));
458 void ViewManagerSynchronizer::DestroyView(TransportViewId view_id
) {
460 pending_transactions_
.push_back(new DestroyViewTransaction(view_id
, this));
464 void ViewManagerSynchronizer::AddChild(TransportNodeId child_id
,
465 TransportNodeId parent_id
) {
467 pending_transactions_
.push_back(
468 new HierarchyTransaction(HierarchyTransaction::TYPE_ADD
,
475 void ViewManagerSynchronizer::RemoveChild(TransportNodeId child_id
,
476 TransportNodeId parent_id
) {
478 pending_transactions_
.push_back(
479 new HierarchyTransaction(HierarchyTransaction::TYPE_REMOVE
,
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
) {
497 pending_transactions_
.push_back(
498 new SetActiveViewTransaction(node_id
, view_id
, this));
502 void ViewManagerSynchronizer::SetBounds(TransportNodeId node_id
,
503 const gfx::Rect
& bounds
) {
505 pending_transactions_
.push_back(
506 new SetBoundsTransaction(node_id
, bounds
, this));
510 void ViewManagerSynchronizer::SetViewContents(TransportViewId view_id
,
511 const SkBitmap
& contents
) {
513 pending_transactions_
.push_back(
514 new SetViewContentsTransaction(view_id
, contents
, this));
518 ////////////////////////////////////////////////////////////////////////////////
519 // ViewManagerSynchronizer, IViewManagerClient implementation:
521 void ViewManagerSynchronizer::OnViewManagerConnectionEstablished(
522 TransportConnectionId connection_id
,
523 TransportChangeId next_server_change_id
,
524 const Array
<INode
>& nodes
) {
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
));
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(
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
);
564 ViewTreeNodePrivate(new_parent
).LocalAddChild(node
);
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
);
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
);
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.
612 Transactions::const_iterator it
= pending_transactions_
.begin();
613 for (; it
!= pending_transactions_
.end(); ++it
) {
614 if (!(*it
)->committed())
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