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