Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / mojo / examples / media_viewer / media_viewer.cc
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 <map>
6 #include <string>
7
8 #include "base/macros.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "mojo/examples/media_viewer/media_viewer.mojom.h"
12 #include "mojo/public/cpp/application/application_connection.h"
13 #include "mojo/public/cpp/application/application_delegate.h"
14 #include "mojo/public/cpp/application/application_impl.h"
15 #include "mojo/public/cpp/application/interface_factory_impl.h"
16 #include "mojo/public/cpp/bindings/interface_impl.h"
17 #include "mojo/services/public/cpp/view_manager/view.h"
18 #include "mojo/services/public/cpp/view_manager/view_manager.h"
19 #include "mojo/services/public/cpp/view_manager/view_manager_client_factory.h"
20 #include "mojo/services/public/cpp/view_manager/view_manager_delegate.h"
21 #include "mojo/services/public/cpp/view_manager/view_observer.h"
22 #include "mojo/services/public/interfaces/navigation/navigation.mojom.h"
23 #include "mojo/views/native_widget_view_manager.h"
24 #include "mojo/views/views_init.h"
25 #include "skia/ext/platform_canvas.h"
26 #include "skia/ext/refptr.h"
27 #include "third_party/skia/include/core/SkBitmap.h"
28 #include "third_party/skia/include/core/SkCanvas.h"
29 #include "third_party/skia/include/core/SkColor.h"
30 #include "third_party/skia/include/core/SkPaint.h"
31 #include "third_party/skia/include/core/SkRect.h"
32 #include "ui/gfx/canvas.h"
33 #include "ui/gfx/geometry/insets.h"
34 #include "ui/gfx/geometry/rect.h"
35 #include "ui/views/background.h"
36 #include "ui/views/border.h"
37 #include "ui/views/controls/button/button.h"
38 #include "ui/views/controls/button/label_button.h"
39 #include "ui/views/layout/box_layout.h"
40 #include "ui/views/painter.h"
41 #include "ui/views/widget/widget.h"
42 #include "ui/views/widget/widget_delegate.h"
43
44 namespace mojo {
45 namespace examples {
46
47 class MediaViewer;
48
49 class CustomButtonBorder: public views::Border {
50  public:
51   CustomButtonBorder()
52       : normal_painter_(CreatePainter(SkColorSetRGB(0x80, 0x80, 0x80),
53                                       SkColorSetRGB(0xC0, 0xC0, 0xC0))),
54         hot_painter_(CreatePainter(SkColorSetRGB(0xA0, 0xA0, 0xA0),
55                                    SkColorSetRGB(0xD0, 0xD0, 0xD0))),
56         pushed_painter_(CreatePainter(SkColorSetRGB(0x80, 0x80, 0x80),
57                                       SkColorSetRGB(0x90, 0x90, 0x90))),
58         insets_(2, 6, 2, 6) {
59   }
60   virtual ~CustomButtonBorder() {}
61
62  private:
63   // Overridden from views::Border:
64   virtual void Paint(const views::View& view, gfx::Canvas* canvas) OVERRIDE {
65     const views::LabelButton* button =
66         static_cast<const views::LabelButton*>(&view);
67     views::Button::ButtonState state = button->state();
68
69     views::Painter* painter = normal_painter_.get();
70     if (state == views::Button::STATE_HOVERED) {
71       painter = hot_painter_.get();
72     } else if (state == views::Button::STATE_PRESSED) {
73       painter = pushed_painter_.get();
74     }
75     painter->Paint(canvas, view.size());
76   }
77
78   virtual gfx::Insets GetInsets() const OVERRIDE {
79     return insets_;
80   }
81
82   virtual gfx::Size GetMinimumSize() const OVERRIDE {
83     gfx::Size size;
84     if (normal_painter_)
85       size.SetToMax(normal_painter_->GetMinimumSize());
86     if (hot_painter_)
87       size.SetToMax(hot_painter_->GetMinimumSize());
88     if (pushed_painter_)
89       size.SetToMax(pushed_painter_->GetMinimumSize());
90     return size;
91   }
92
93   scoped_ptr<views::Painter> CreatePainter(SkColor border, SkColor background) {
94     skia::RefPtr<SkCanvas> canvas(skia::AdoptRef(skia::CreatePlatformCanvas(
95         64, 64, false)));
96     SkPaint paint;
97     paint.setColor(background);
98     canvas->drawRoundRect(SkRect::MakeWH(63, 63), 2, 2, paint);
99     paint.setStyle(SkPaint::kStroke_Style);
100     paint.setColor(border);
101     canvas->drawRoundRect(SkRect::MakeWH(63, 63), 2, 2, paint);
102
103     return scoped_ptr<views::Painter>(
104         views::Painter::CreateImagePainter(
105             gfx::ImageSkia::CreateFrom1xBitmap(
106                 skia::GetTopDevice(*canvas)->accessBitmap(true)),
107             gfx::Insets(5, 5, 5, 5)));
108   }
109
110   scoped_ptr<views::Painter> normal_painter_;
111   scoped_ptr<views::Painter> hot_painter_;
112   scoped_ptr<views::Painter> pushed_painter_;
113
114   gfx::Insets insets_;
115
116   DISALLOW_COPY_AND_ASSIGN(CustomButtonBorder);
117 };
118
119 class ControlPanel : public views::ButtonListener {
120  public:
121   enum ControlType {
122     CONTROL_ZOOM_IN,
123     CONTROL_ACTUAL_SIZE,
124     CONTROL_ZOOM_OUT,
125     CONTROL_COUNT,
126   };
127
128   class Delegate {
129    public:
130     virtual ~Delegate() {}
131
132     virtual void ButtonPressed(ControlType type) = 0;
133   };
134
135   ControlPanel(Delegate* delegate) : delegate_(delegate), buttons_() {}
136
137   virtual ~ControlPanel() {}
138
139   void Initialize(View* view) {
140     const char* kNames[] = { "Zoom In", "Actual Size", "Zoom Out" };
141
142     views::WidgetDelegateView* widget_delegate = new views::WidgetDelegateView;
143
144     widget_delegate->GetContentsView()->SetLayoutManager(
145         new views::BoxLayout(views::BoxLayout::kHorizontal, 5, 2, 5));
146
147     widget_delegate->GetContentsView()->set_background(
148         views::Background::CreateSolidBackground(SK_ColorLTGRAY));
149
150     for (int type = 0; type < CONTROL_COUNT; ++type) {
151       views::Button* button = new views::LabelButton(
152           this, base::ASCIIToUTF16(kNames[type]));
153       button->SetBorder(scoped_ptr<views::Border>(new CustomButtonBorder));
154       buttons_[type] = button;
155       widget_delegate->GetContentsView()->AddChildView(button);
156     }
157
158     views::Widget* widget = new views::Widget;
159     views::Widget::InitParams params(
160         views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
161     params.native_widget = new NativeWidgetViewManager(widget, view);
162     params.delegate = widget_delegate;
163     params.bounds = gfx::Rect(view->bounds().width(), view->bounds().height());
164     params.opacity = views::Widget::InitParams::OPAQUE_WINDOW;
165     widget->Init(params);
166     widget->Show();
167   }
168
169  private:
170   // Overridden from views::ButtonListener:
171   virtual void ButtonPressed(views::Button* sender,
172                              const ui::Event& event) OVERRIDE {
173     for (int i = 0; i < CONTROL_COUNT; ++i) {
174       if (sender == buttons_[i]) {
175         delegate_->ButtonPressed(static_cast<ControlType>(i));
176         return;
177       }
178     }
179   }
180
181   Delegate* delegate_;
182   views::Button* buttons_[CONTROL_COUNT];
183
184   DISALLOW_COPY_AND_ASSIGN(ControlPanel);
185 };
186
187 class NavigatorImpl : public InterfaceImpl<Navigator> {
188  public:
189   explicit NavigatorImpl(MediaViewer* viewer) : viewer_(viewer) {}
190   virtual ~NavigatorImpl() {}
191
192  private:
193   // Overridden from Navigator:
194   virtual void Navigate(
195       uint32_t view_id,
196       NavigationDetailsPtr navigation_details,
197       ResponseDetailsPtr response_details) OVERRIDE;
198
199   MediaViewer* viewer_;
200
201   DISALLOW_COPY_AND_ASSIGN(NavigatorImpl);
202 };
203
204 class MediaViewer
205     : public ApplicationDelegate,
206       public ViewManagerDelegate,
207       public ControlPanel::Delegate,
208       public ViewObserver {
209  public:
210   MediaViewer()
211       : navigator_factory_(this),
212         view_manager_client_factory_(this),
213         app_(NULL),
214         view_manager_(NULL),
215         root_view_(NULL),
216         control_view_(NULL),
217         content_view_(NULL),
218         control_panel_(this) {
219     handler_map_["image/png"] = "mojo:mojo_png_viewer";
220   }
221
222   virtual ~MediaViewer() {
223     if (root_view_)
224       root_view_->RemoveObserver(this);
225   }
226
227   void Navigate(
228       uint32_t view_id,
229       NavigationDetailsPtr navigation_details,
230       ResponseDetailsPtr response_details) {
231     // TODO(yzshen): This shouldn't be needed once FIFO is ready.
232     if (!view_manager_) {
233       pending_navigate_request_.reset(new PendingNavigateRequest);
234       pending_navigate_request_->view_id = view_id;
235       pending_navigate_request_->navigation_details = navigation_details.Pass();
236       pending_navigate_request_->response_details = response_details.Pass();
237
238       return;
239     }
240
241     std::string handler = GetHandlerForContentType(
242         response_details->response->mime_type);
243     if (handler.empty())
244       return;
245
246     content_view_->Embed(handler);
247
248     if (navigation_details) {
249       NavigatorPtr navigator;
250       app_->ConnectToService(handler, &navigator);
251       navigator->Navigate(content_view_->id(), navigation_details.Pass(),
252                           response_details.Pass());
253     }
254
255     // TODO(yzshen): determine the set of controls to show based on what
256     // interfaces the embedded app provides.
257     app_->ConnectToService(handler, &zoomable_media_);
258   }
259
260  private:
261   typedef std::map<std::string, std::string> HandlerMap;
262
263   struct PendingNavigateRequest {
264     uint32_t view_id;
265     NavigationDetailsPtr navigation_details;
266     ResponseDetailsPtr response_details;
267   };
268
269
270   // Overridden from ApplicationDelegate:
271   virtual void Initialize(ApplicationImpl* app) OVERRIDE {
272     app_ = app;
273     views_init_.reset(new ViewsInit);
274   }
275
276   virtual bool ConfigureIncomingConnection(ApplicationConnection* connection)
277       OVERRIDE {
278     connection->AddService(&navigator_factory_);
279     connection->AddService(&view_manager_client_factory_);
280     return true;
281   }
282
283   void LayoutViews() {
284     View* root = content_view_->parent();
285     gfx::Rect control_bounds(root->bounds().width(), 28);
286     control_view_->SetBounds(control_bounds);
287     gfx::Rect content_bounds(0, control_bounds.height(), root->bounds().width(),
288                              root->bounds().height() - control_bounds.height());
289     content_view_->SetBounds(content_bounds);
290   }
291
292   // Overridden from ViewManagerDelegate:
293   virtual void OnEmbed(ViewManager* view_manager,
294                        View* root,
295                        ServiceProviderImpl* exported_services,
296                        scoped_ptr<ServiceProvider> imported_services) OVERRIDE {
297     root_view_ = root;
298     view_manager_ = view_manager;
299
300     control_view_ = View::Create(view_manager_);
301     root_view_->AddChild(control_view_);
302
303     content_view_ = View::Create(view_manager_);
304     root_view_->AddChild(content_view_);
305
306     control_panel_.Initialize(control_view_);
307
308     LayoutViews();
309     root_view_->AddObserver(this);
310
311     if (pending_navigate_request_) {
312       scoped_ptr<PendingNavigateRequest> request(
313           pending_navigate_request_.release());
314
315       Navigate(request->view_id, request->navigation_details.Pass(),
316                request->response_details.Pass());
317     }
318   }
319   virtual void OnViewManagerDisconnected(
320       ViewManager* view_manager) OVERRIDE {
321     DCHECK_EQ(view_manager_, view_manager);
322     view_manager_ = NULL;
323     base::MessageLoop::current()->Quit();
324   }
325
326   // Overridden from ControlPanel::Delegate:
327   virtual void ButtonPressed(ControlPanel::ControlType type) OVERRIDE {
328     switch (type) {
329       case ControlPanel::CONTROL_ZOOM_IN:
330         zoomable_media_->ZoomIn();
331         break;
332       case ControlPanel::CONTROL_ACTUAL_SIZE:
333        zoomable_media_->ZoomToActualSize();
334         break;
335       case ControlPanel::CONTROL_ZOOM_OUT:
336         zoomable_media_->ZoomOut();
337         break;
338       default:
339         NOTIMPLEMENTED();
340     }
341   }
342
343   // ViewObserver:
344   virtual void OnViewBoundsChanged(View* view,
345                                    const gfx::Rect& old_bounds,
346                                    const gfx::Rect& new_bounds) OVERRIDE {
347     LayoutViews();
348   }
349   virtual void OnViewDestroyed(View* view) OVERRIDE {
350     DCHECK_EQ(view, root_view_);
351     view->RemoveObserver(this);
352     root_view_ = NULL;
353   }
354
355   std::string GetHandlerForContentType(const std::string& content_type) {
356     HandlerMap::const_iterator it = handler_map_.find(content_type);
357     return it != handler_map_.end() ? it->second : std::string();
358   }
359
360   InterfaceFactoryImplWithContext<NavigatorImpl, MediaViewer>
361       navigator_factory_;
362   ViewManagerClientFactory view_manager_client_factory_;
363
364   ApplicationImpl* app_;
365   scoped_ptr<ViewsInit> views_init_;
366   ViewManager* view_manager_;
367   View* root_view_;
368   View* control_view_;
369   View* content_view_;
370   ControlPanel control_panel_;
371   ZoomableMediaPtr zoomable_media_;
372   HandlerMap handler_map_;
373   scoped_ptr<PendingNavigateRequest> pending_navigate_request_;
374
375   DISALLOW_COPY_AND_ASSIGN(MediaViewer);
376 };
377
378 void NavigatorImpl::Navigate(
379     uint32_t view_id,
380     NavigationDetailsPtr navigation_details,
381     ResponseDetailsPtr response_details) {
382   viewer_->Navigate(view_id, navigation_details.Pass(),
383                     response_details.Pass());
384 }
385
386 }  // namespace examples
387
388 // static
389 ApplicationDelegate* ApplicationDelegate::Create() {
390   return new examples::MediaViewer;
391 }
392
393 }  // namespace mojo