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