Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / mojo / examples / png_viewer / png_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 <algorithm>
6
7 #include "base/memory/scoped_ptr.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/strings/string_tokenizer.h"
10 #include "mojo/application/application_runner_chromium.h"
11 #include "mojo/examples/media_viewer/media_viewer.mojom.h"
12 #include "mojo/public/c/system/main.h"
13 #include "mojo/public/cpp/application/application_connection.h"
14 #include "mojo/public/cpp/application/application_delegate.h"
15 #include "mojo/public/cpp/application/application_impl.h"
16 #include "mojo/public/cpp/application/interface_factory_impl.h"
17 #include "mojo/public/cpp/application/service_provider_impl.h"
18 #include "mojo/services/public/cpp/view_manager/types.h"
19 #include "mojo/services/public/cpp/view_manager/view.h"
20 #include "mojo/services/public/cpp/view_manager/view_manager.h"
21 #include "mojo/services/public/cpp/view_manager/view_manager_client_factory.h"
22 #include "mojo/services/public/cpp/view_manager/view_manager_delegate.h"
23 #include "mojo/services/public/cpp/view_manager/view_observer.h"
24 #include "mojo/services/public/interfaces/content_handler/content_handler.mojom.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/SkPaint.h"
30 #include "third_party/skia/include/core/SkScalar.h"
31 #include "ui/gfx/codec/png_codec.h"
32
33 namespace mojo {
34 namespace examples {
35
36 class PNGViewer;
37
38 // TODO(aa): Hook up ZoomableMedia interface again.
39 class PNGView : public ViewManagerDelegate, public ViewObserver {
40  public:
41   static void Spawn(URLResponsePtr response,
42                     ServiceProviderImpl* exported_services,
43                     scoped_ptr<ServiceProvider> imported_services,
44                     Shell* shell) {
45     // PNGView deletes itself when its View is destroyed.
46     new PNGView(
47         response.Pass(), exported_services, imported_services.Pass(), shell);
48   }
49
50  private:
51   static const uint16_t kMaxZoomPercentage = 400;
52   static const uint16_t kMinZoomPercentage = 20;
53   static const uint16_t kDefaultZoomPercentage = 100;
54   static const uint16_t kZoomStep = 20;
55
56   PNGView(URLResponsePtr response,
57           ServiceProviderImpl* exported_services,
58           scoped_ptr<ServiceProvider> imported_services,
59           Shell* shell)
60       : imported_services_(imported_services.Pass()),
61         root_(NULL),
62         view_manager_client_factory_(shell, this),
63         zoom_percentage_(kDefaultZoomPercentage) {
64     exported_services->AddService(&view_manager_client_factory_);
65     DecodePNG(response.Pass());
66   }
67
68   virtual ~PNGView() {
69     if (root_)
70       root_->RemoveObserver(this);
71   }
72
73   // Overridden from ViewManagerDelegate:
74   virtual void OnEmbed(ViewManager* view_manager,
75                        View* root,
76                        ServiceProviderImpl* exported_services,
77                        scoped_ptr<ServiceProvider> imported_services) OVERRIDE {
78     root_ = root;
79     root_->AddObserver(this);
80     root_->SetColor(SK_ColorGRAY);
81     if (!bitmap_.isNull())
82       DrawBitmap();
83   }
84
85   virtual void OnViewManagerDisconnected(ViewManager* view_manager) OVERRIDE {
86     // TODO(aa): Need to figure out how shutdown works.
87   }
88
89   // Overridden from ViewObserver:
90   virtual void OnViewBoundsChanged(View* view,
91                                    const gfx::Rect& old_bounds,
92                                    const gfx::Rect& new_bounds) OVERRIDE {
93     DCHECK_EQ(view, root_);
94     DrawBitmap();
95   }
96
97   virtual void OnViewDestroyed(View* view) OVERRIDE {
98     DCHECK_EQ(view, root_);
99     delete this;
100   }
101
102   void DecodePNG(URLResponsePtr response) {
103     int content_length = GetContentLength(response->headers);
104     scoped_ptr<unsigned char[]> data(new unsigned char[content_length]);
105     unsigned char* buf = data.get();
106     uint32_t bytes_remaining = content_length;
107     uint32_t num_bytes = bytes_remaining;
108     while (bytes_remaining > 0) {
109       MojoResult result = ReadDataRaw(
110           response->body.get(), buf, &num_bytes, MOJO_READ_DATA_FLAG_NONE);
111       if (result == MOJO_RESULT_SHOULD_WAIT) {
112         Wait(response->body.get(),
113              MOJO_HANDLE_SIGNAL_READABLE,
114              MOJO_DEADLINE_INDEFINITE);
115       } else if (result == MOJO_RESULT_OK) {
116         buf += num_bytes;
117         num_bytes = bytes_remaining -= num_bytes;
118       } else {
119         break;
120       }
121     }
122
123     gfx::PNGCodec::Decode(static_cast<const unsigned char*>(data.get()),
124                           content_length,
125                           &bitmap_);
126   }
127
128   void DrawBitmap() {
129     if (!root_)
130       return;
131
132     skia::RefPtr<SkCanvas> canvas(skia::AdoptRef(skia::CreatePlatformCanvas(
133         root_->bounds().width(), root_->bounds().height(), true)));
134     canvas->drawColor(SK_ColorGRAY);
135     SkPaint paint;
136     SkScalar scale =
137         SkFloatToScalar(zoom_percentage_ * 1.0f / kDefaultZoomPercentage);
138     canvas->scale(scale, scale);
139     canvas->drawBitmap(bitmap_, 0, 0, &paint);
140     root_->SetContents(skia::GetTopDevice(*canvas)->accessBitmap(true));
141   }
142
143   void ZoomIn() {
144     if (zoom_percentage_ >= kMaxZoomPercentage)
145       return;
146     zoom_percentage_ += kZoomStep;
147     DrawBitmap();
148   }
149
150   void ZoomOut() {
151     if (zoom_percentage_ <= kMinZoomPercentage)
152       return;
153     zoom_percentage_ -= kZoomStep;
154     DrawBitmap();
155   }
156
157   void ZoomToActualSize() {
158     if (zoom_percentage_ == kDefaultZoomPercentage)
159       return;
160     zoom_percentage_ = kDefaultZoomPercentage;
161     DrawBitmap();
162   }
163
164   int GetContentLength(const Array<String>& headers) {
165     for (size_t i = 0; i < headers.size(); ++i) {
166       base::StringTokenizer t(headers[i], ": ;=");
167       while (t.GetNext()) {
168         if (!t.token_is_delim() && t.token() == "Content-Length") {
169           while (t.GetNext()) {
170             if (!t.token_is_delim())
171               return atoi(t.token().c_str());
172           }
173         }
174       }
175     }
176     return 0;
177   }
178
179   SkBitmap bitmap_;
180   scoped_ptr<ServiceProvider> imported_services_;
181   View* root_;
182   ViewManagerClientFactory view_manager_client_factory_;
183   uint16_t zoom_percentage_;
184
185   DISALLOW_COPY_AND_ASSIGN(PNGView);
186 };
187
188 class ContentHandlerImpl : public InterfaceImpl<ContentHandler> {
189  public:
190   explicit ContentHandlerImpl(Shell* shell) : shell_(shell) {}
191   virtual ~ContentHandlerImpl() {}
192
193  private:
194   // Overridden from ContentHandler:
195   virtual void OnConnect(
196       const mojo::String& url,
197       URLResponsePtr response,
198       InterfaceRequest<ServiceProvider> service_provider) OVERRIDE {
199     ServiceProviderImpl* exported_services = new ServiceProviderImpl();
200     BindToRequest(exported_services, &service_provider);
201     scoped_ptr<ServiceProvider> remote(
202         exported_services->CreateRemoteServiceProvider());
203     PNGView::Spawn(response.Pass(), exported_services, remote.Pass(), shell_);
204   }
205
206   Shell* shell_;
207
208   DISALLOW_COPY_AND_ASSIGN(ContentHandlerImpl);
209 };
210
211 class PNGViewer : public ApplicationDelegate {
212  public:
213   PNGViewer() {}
214  private:
215   // Overridden from ApplicationDelegate:
216   virtual void Initialize(ApplicationImpl* app) MOJO_OVERRIDE {
217     content_handler_factory_.reset(
218         new InterfaceFactoryImplWithContext<ContentHandlerImpl, Shell>(
219             app->shell()));
220   }
221
222   // Overridden from ApplicationDelegate:
223   virtual bool ConfigureIncomingConnection(ApplicationConnection* connection)
224       MOJO_OVERRIDE {
225     connection->AddService(content_handler_factory_.get());
226     return true;
227   }
228
229   scoped_ptr<InterfaceFactoryImplWithContext<ContentHandlerImpl, Shell> >
230       content_handler_factory_;
231
232   DISALLOW_COPY_AND_ASSIGN(PNGViewer);
233 };
234
235 }  // namespace examples
236 }  // namespace mojo
237
238 MojoResult MojoMain(MojoHandle shell_handle) {
239   mojo::ApplicationRunnerChromium runner(new mojo::examples::PNGViewer);
240   return runner.Run(shell_handle);
241 }