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.
4
5 #include "mojo/services/public/cpp/view_manager/lib/view_manager_client_impl.h"
6
7 #include "base/bind.h"
8 #include "base/command_line.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/stl_util.h"
11 #include "mojo/public/cpp/application/application_impl.h"
12 #include "mojo/public/cpp/application/connect.h"
13 #include "mojo/public/cpp/application/service_provider_impl.h"
14 #include "mojo/public/interfaces/application/service_provider.mojom.h"
15 #include "mojo/public/interfaces/application/shell.mojom.h"
16 #include "mojo/services/public/cpp/view_manager/lib/view_private.h"
17 #include "mojo/services/public/cpp/view_manager/util.h"
18 #include "mojo/services/public/cpp/view_manager/view_manager_delegate.h"
19 #include "mojo/services/public/cpp/view_manager/view_observer.h"
20 #include "mojo/services/public/cpp/view_manager/window_manager_delegate.h"
21 #include "third_party/skia/include/core/SkBitmap.h"
22 #include "ui/gfx/codec/png_codec.h"
23
24 namespace mojo {
25
MakeTransportId(ConnectionSpecificId connection_id,ConnectionSpecificId local_id)26 Id MakeTransportId(ConnectionSpecificId connection_id,
27 ConnectionSpecificId local_id) {
28 return (connection_id << 16) | local_id;
29 }
30
31 // Helper called to construct a local view object from transport data.
AddViewToViewManager(ViewManagerClientImpl * client,View * parent,Id view_id,const gfx::Rect & bounds)32 View* AddViewToViewManager(ViewManagerClientImpl* client,
33 View* parent,
34 Id view_id,
35 const gfx::Rect& bounds) {
36 // We don't use the ctor that takes a ViewManager here, since it will call
37 // back to the service and attempt to create a new view.
38 View* view = ViewPrivate::LocalCreate();
39 ViewPrivate private_view(view);
40 private_view.set_view_manager(client);
41 private_view.set_id(view_id);
42 client->AddView(view);
43 private_view.LocalSetBounds(gfx::Rect(), bounds);
44 if (parent)
45 ViewPrivate(parent).LocalAddChild(view);
46 return view;
47 }
48
BuildViewTree(ViewManagerClientImpl * client,const Array<ViewDataPtr> & views,View * initial_parent)49 View* BuildViewTree(ViewManagerClientImpl* client,
50 const Array<ViewDataPtr>& views,
51 View* initial_parent) {
52 std::vector<View*> parents;
53 View* root = NULL;
54 View* last_view = NULL;
55 if (initial_parent)
56 parents.push_back(initial_parent);
57 for (size_t i = 0; i < views.size(); ++i) {
58 if (last_view && views[i]->parent_id == last_view->id()) {
59 parents.push_back(last_view);
60 } else if (!parents.empty()) {
61 while (parents.back()->id() != views[i]->parent_id)
62 parents.pop_back();
63 }
64 View* view = AddViewToViewManager(
65 client,
66 !parents.empty() ? parents.back() : NULL,
67 views[i]->view_id,
68 views[i]->bounds.To<gfx::Rect>());
69 if (!last_view)
70 root = view;
71 last_view = view;
72 }
73 return root;
74 }
75
76 // Responsible for removing a root from the ViewManager when that view is
77 // destroyed.
78 class RootObserver : public ViewObserver {
79 public:
RootObserver(View * root)80 explicit RootObserver(View* root) : root_(root) {}
~RootObserver()81 virtual ~RootObserver() {}
82
83 private:
84 // Overridden from ViewObserver:
OnViewDestroyed(View * view)85 virtual void OnViewDestroyed(View* view) OVERRIDE {
86 DCHECK_EQ(view, root_);
87 static_cast<ViewManagerClientImpl*>(
88 ViewPrivate(root_).view_manager())->RemoveRoot(root_);
89 view->RemoveObserver(this);
90 delete this;
91 }
92
93 View* root_;
94
95 DISALLOW_COPY_AND_ASSIGN(RootObserver);
96 };
97
ViewManagerClientImpl(ViewManagerDelegate * delegate,Shell * shell)98 ViewManagerClientImpl::ViewManagerClientImpl(ViewManagerDelegate* delegate,
99 Shell* shell)
100 : connected_(false),
101 connection_id_(0),
102 next_id_(1),
103 delegate_(delegate),
104 window_manager_delegate_(NULL),
105 shell_(shell) {
106 // TODO(beng): Come up with a better way of establishing a configuration for
107 // what the active window manager is.
108 std::string window_manager_url = "mojo:mojo_window_manager";
109 if (base::CommandLine::ForCurrentProcess()->HasSwitch("window-manager")) {
110 window_manager_url =
111 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
112 "window-manager");
113 }
114 InterfacePtr<ServiceProvider> sp;
115 shell->ConnectToApplication(window_manager_url, Get(&sp));
116 ConnectToService(sp.get(), &window_manager_);
117 window_manager_.set_client(this);
118 }
119
~ViewManagerClientImpl()120 ViewManagerClientImpl::~ViewManagerClientImpl() {
121 std::vector<View*> non_owned;
122 while (!views_.empty()) {
123 IdToViewMap::iterator it = views_.begin();
124 if (OwnsView(it->second->id())) {
125 it->second->Destroy();
126 } else {
127 non_owned.push_back(it->second);
128 views_.erase(it);
129 }
130 }
131 // Delete the non-owned views last. In the typical case these are roots. The
132 // exception is the window manager, which may know aboutother random views
133 // that it doesn't own.
134 // NOTE: we manually delete as we're a friend.
135 for (size_t i = 0; i < non_owned.size(); ++i)
136 delete non_owned[i];
137
138 delegate_->OnViewManagerDisconnected(this);
139 }
140
CreateView()141 Id ViewManagerClientImpl::CreateView() {
142 DCHECK(connected_);
143 const Id view_id = MakeTransportId(connection_id_, ++next_id_);
144 service_->CreateView(view_id, ActionCompletedCallbackWithErrorCode());
145 return view_id;
146 }
147
DestroyView(Id view_id)148 void ViewManagerClientImpl::DestroyView(Id view_id) {
149 DCHECK(connected_);
150 service_->DeleteView(view_id, ActionCompletedCallback());
151 }
152
AddChild(Id child_id,Id parent_id)153 void ViewManagerClientImpl::AddChild(Id child_id, Id parent_id) {
154 DCHECK(connected_);
155 service_->AddView(parent_id, child_id, ActionCompletedCallback());
156 }
157
RemoveChild(Id child_id,Id parent_id)158 void ViewManagerClientImpl::RemoveChild(Id child_id, Id parent_id) {
159 DCHECK(connected_);
160 service_->RemoveViewFromParent(child_id, ActionCompletedCallback());
161 }
162
Reorder(Id view_id,Id relative_view_id,OrderDirection direction)163 void ViewManagerClientImpl::Reorder(
164 Id view_id,
165 Id relative_view_id,
166 OrderDirection direction) {
167 DCHECK(connected_);
168 service_->ReorderView(view_id, relative_view_id, direction,
169 ActionCompletedCallback());
170 }
171
OwnsView(Id id) const172 bool ViewManagerClientImpl::OwnsView(Id id) const {
173 return HiWord(id) == connection_id_;
174 }
175
SetBounds(Id view_id,const gfx::Rect & bounds)176 void ViewManagerClientImpl::SetBounds(Id view_id, const gfx::Rect& bounds) {
177 DCHECK(connected_);
178 service_->SetViewBounds(view_id, Rect::From(bounds),
179 ActionCompletedCallback());
180 }
181
SetSurfaceId(Id view_id,SurfaceIdPtr surface_id)182 void ViewManagerClientImpl::SetSurfaceId(Id view_id, SurfaceIdPtr surface_id) {
183 DCHECK(connected_);
184 if (surface_id.is_null())
185 return;
186 service_->SetViewSurfaceId(
187 view_id, surface_id.Pass(), ActionCompletedCallback());
188 }
189
SetFocus(Id view_id)190 void ViewManagerClientImpl::SetFocus(Id view_id) {
191 window_manager_->FocusWindow(view_id, ActionCompletedCallback());
192 }
193
SetVisible(Id view_id,bool visible)194 void ViewManagerClientImpl::SetVisible(Id view_id, bool visible) {
195 DCHECK(connected_);
196 service_->SetViewVisibility(view_id, visible, ActionCompletedCallback());
197 }
198
Embed(const String & url,Id view_id)199 void ViewManagerClientImpl::Embed(const String& url, Id view_id) {
200 ServiceProviderPtr sp;
201 BindToProxy(new ServiceProviderImpl, &sp);
202 Embed(url, view_id, sp.Pass());
203 }
204
Embed(const String & url,Id view_id,ServiceProviderPtr service_provider)205 void ViewManagerClientImpl::Embed(
206 const String& url,
207 Id view_id,
208 ServiceProviderPtr service_provider) {
209 DCHECK(connected_);
210 service_->Embed(url, view_id, service_provider.Pass(),
211 ActionCompletedCallback());
212 }
213
AddView(View * view)214 void ViewManagerClientImpl::AddView(View* view) {
215 DCHECK(views_.find(view->id()) == views_.end());
216 views_[view->id()] = view;
217 }
218
RemoveView(Id view_id)219 void ViewManagerClientImpl::RemoveView(Id view_id) {
220 IdToViewMap::iterator it = views_.find(view_id);
221 if (it != views_.end())
222 views_.erase(it);
223 }
224
225 ////////////////////////////////////////////////////////////////////////////////
226 // ViewManagerClientImpl, ViewManager implementation:
227
SetWindowManagerDelegate(WindowManagerDelegate * window_manager_delegate)228 void ViewManagerClientImpl::SetWindowManagerDelegate(
229 WindowManagerDelegate* window_manager_delegate) {
230 CHECK(NULL != GetViewById(1));
231 CHECK(!window_manager_delegate_);
232 window_manager_delegate_ = window_manager_delegate;
233 }
234
DispatchEvent(View * target,EventPtr event)235 void ViewManagerClientImpl::DispatchEvent(View* target, EventPtr event) {
236 CHECK(window_manager_delegate_);
237 service_->DispatchOnViewInputEvent(target->id(), event.Pass());
238 }
239
GetEmbedderURL() const240 const std::string& ViewManagerClientImpl::GetEmbedderURL() const {
241 return creator_url_;
242 }
243
GetRoots() const244 const std::vector<View*>& ViewManagerClientImpl::GetRoots() const {
245 return roots_;
246 }
247
GetViewById(Id id)248 View* ViewManagerClientImpl::GetViewById(Id id) {
249 IdToViewMap::const_iterator it = views_.find(id);
250 return it != views_.end() ? it->second : NULL;
251 }
252
253 ////////////////////////////////////////////////////////////////////////////////
254 // ViewManagerClientImpl, InterfaceImpl overrides:
255
OnConnectionEstablished()256 void ViewManagerClientImpl::OnConnectionEstablished() {
257 service_ = client();
258 }
259
260 ////////////////////////////////////////////////////////////////////////////////
261 // ViewManagerClientImpl, ViewManagerClient implementation:
262
OnEmbed(ConnectionSpecificId connection_id,const String & creator_url,ViewDataPtr root_data,InterfaceRequest<ServiceProvider> service_provider)263 void ViewManagerClientImpl::OnEmbed(
264 ConnectionSpecificId connection_id,
265 const String& creator_url,
266 ViewDataPtr root_data,
267 InterfaceRequest<ServiceProvider> service_provider) {
268 if (!connected_) {
269 connected_ = true;
270 connection_id_ = connection_id;
271 creator_url_ = String::From(creator_url);
272 } else {
273 DCHECK_EQ(connection_id_, connection_id);
274 DCHECK_EQ(creator_url_, creator_url);
275 }
276
277 // A new root must not already exist as a root or be contained by an existing
278 // hierarchy visible to this view manager.
279 View* root = AddViewToViewManager(this, NULL, root_data->view_id,
280 root_data->bounds.To<gfx::Rect>());
281 roots_.push_back(root);
282 root->AddObserver(new RootObserver(root));
283
284 // BindToRequest() binds the lifetime of |exported_services| to the pipe.
285 ServiceProviderImpl* exported_services = new ServiceProviderImpl;
286 BindToRequest(exported_services, &service_provider);
287 scoped_ptr<ServiceProvider> remote(
288 exported_services->CreateRemoteServiceProvider());
289 delegate_->OnEmbed(this, root, exported_services, remote.Pass());
290 }
291
OnViewBoundsChanged(Id view_id,RectPtr old_bounds,RectPtr new_bounds)292 void ViewManagerClientImpl::OnViewBoundsChanged(Id view_id,
293 RectPtr old_bounds,
294 RectPtr new_bounds) {
295 View* view = GetViewById(view_id);
296 ViewPrivate(view).LocalSetBounds(old_bounds.To<gfx::Rect>(),
297 new_bounds.To<gfx::Rect>());
298 }
299
OnViewHierarchyChanged(Id view_id,Id new_parent_id,Id old_parent_id,mojo::Array<ViewDataPtr> views)300 void ViewManagerClientImpl::OnViewHierarchyChanged(
301 Id view_id,
302 Id new_parent_id,
303 Id old_parent_id,
304 mojo::Array<ViewDataPtr> views) {
305 View* initial_parent = views.size() ?
306 GetViewById(views[0]->parent_id) : NULL;
307
308 BuildViewTree(this, views, initial_parent);
309
310 View* new_parent = GetViewById(new_parent_id);
311 View* old_parent = GetViewById(old_parent_id);
312 View* view = GetViewById(view_id);
313 if (new_parent)
314 ViewPrivate(new_parent).LocalAddChild(view);
315 else
316 ViewPrivate(old_parent).LocalRemoveChild(view);
317 }
318
OnViewReordered(Id view_id,Id relative_view_id,OrderDirection direction)319 void ViewManagerClientImpl::OnViewReordered(Id view_id,
320 Id relative_view_id,
321 OrderDirection direction) {
322 View* view = GetViewById(view_id);
323 View* relative_view = GetViewById(relative_view_id);
324 if (view && relative_view)
325 ViewPrivate(view).LocalReorder(relative_view, direction);
326 }
327
OnViewDeleted(Id view_id)328 void ViewManagerClientImpl::OnViewDeleted(Id view_id) {
329 View* view = GetViewById(view_id);
330 if (view)
331 ViewPrivate(view).LocalDestroy();
332 }
333
OnViewVisibilityChanged(Id view_id,bool visible)334 void ViewManagerClientImpl::OnViewVisibilityChanged(Id view_id, bool visible) {
335 // TODO(sky): implement me.
336 NOTIMPLEMENTED();
337 }
338
OnViewDrawnStateChanged(Id view_id,bool drawn)339 void ViewManagerClientImpl::OnViewDrawnStateChanged(Id view_id, bool drawn) {
340 // TODO(sky): implement me.
341 NOTIMPLEMENTED();
342 }
343
OnViewInputEvent(Id view_id,EventPtr event,const Callback<void ()> & ack_callback)344 void ViewManagerClientImpl::OnViewInputEvent(
345 Id view_id,
346 EventPtr event,
347 const Callback<void()>& ack_callback) {
348 View* view = GetViewById(view_id);
349 if (view) {
350 FOR_EACH_OBSERVER(ViewObserver,
351 *ViewPrivate(view).observers(),
352 OnViewInputEvent(view, event));
353 }
354 ack_callback.Run();
355 }
356
Embed(const String & url,InterfaceRequest<ServiceProvider> service_provider)357 void ViewManagerClientImpl::Embed(
358 const String& url,
359 InterfaceRequest<ServiceProvider> service_provider) {
360 if (window_manager_delegate_)
361 window_manager_delegate_->Embed(url, service_provider.Pass());
362 }
363
DispatchOnViewInputEvent(EventPtr event)364 void ViewManagerClientImpl::DispatchOnViewInputEvent(EventPtr event) {
365 if (window_manager_delegate_)
366 window_manager_delegate_->DispatchEvent(event.Pass());
367 }
368
369 ////////////////////////////////////////////////////////////////////////////////
370 // ViewManagerClientImpl, WindowManagerClient implementation:
371
OnWindowManagerReady()372 void ViewManagerClientImpl::OnWindowManagerReady() {}
373
OnCaptureChanged(Id old_capture_view_id,Id new_capture_view_id)374 void ViewManagerClientImpl::OnCaptureChanged(Id old_capture_view_id,
375 Id new_capture_view_id) {}
376
OnFocusChanged(Id old_focused_view_id,Id new_focused_view_id)377 void ViewManagerClientImpl::OnFocusChanged(Id old_focused_view_id,
378 Id new_focused_view_id) {
379 View* focused = GetViewById(new_focused_view_id);
380 View* blurred = GetViewById(old_focused_view_id);
381 if (blurred) {
382 FOR_EACH_OBSERVER(ViewObserver,
383 *ViewPrivate(blurred).observers(),
384 OnViewFocusChanged(focused, blurred));
385 }
386 if (focused) {
387 FOR_EACH_OBSERVER(ViewObserver,
388 *ViewPrivate(focused).observers(),
389 OnViewFocusChanged(focused, blurred));
390 }
391 }
392
OnActiveWindowChanged(Id old_focused_window,Id new_focused_window)393 void ViewManagerClientImpl::OnActiveWindowChanged(Id old_focused_window,
394 Id new_focused_window) {}
395
396 ////////////////////////////////////////////////////////////////////////////////
397 // ViewManagerClientImpl, private:
398
RemoveRoot(View * root)399 void ViewManagerClientImpl::RemoveRoot(View* root) {
400 std::vector<View*>::iterator it =
401 std::find(roots_.begin(), roots_.end(), root);
402 if (it != roots_.end())
403 roots_.erase(it);
404 }
405
OnActionCompleted(bool success)406 void ViewManagerClientImpl::OnActionCompleted(bool success) {
407 if (!change_acked_callback_.is_null())
408 change_acked_callback_.Run();
409 }
410
OnActionCompletedWithErrorCode(ErrorCode code)411 void ViewManagerClientImpl::OnActionCompletedWithErrorCode(ErrorCode code) {
412 OnActionCompleted(code == ERROR_CODE_NONE);
413 }
414
ActionCompletedCallback()415 base::Callback<void(bool)> ViewManagerClientImpl::ActionCompletedCallback() {
416 return base::Bind(&ViewManagerClientImpl::OnActionCompleted,
417 base::Unretained(this));
418 }
419
420 base::Callback<void(ErrorCode)>
ActionCompletedCallbackWithErrorCode()421 ViewManagerClientImpl::ActionCompletedCallbackWithErrorCode() {
422 return base::Bind(&ViewManagerClientImpl::OnActionCompletedWithErrorCode,
423 base::Unretained(this));
424 }
425
426 } // namespace mojo
427