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