Chromium Code Reviews| 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, | |
| 40 public ViewObserver { | |
| 36 public: | 41 public: |
| 37 explicit ZoomableMediaImpl(PNGViewer* viewer) : viewer_(viewer) {} | 42 PNGView(URLResponsePtr response, |
| 38 virtual ~ZoomableMediaImpl() {} | 43 ServiceProviderImpl* exported_services, |
| 44 scoped_ptr<ServiceProvider> imported_services, | |
| 45 Shell* shell) | |
| 46 : imported_services_(imported_services.Pass()), | |
| 47 root_(NULL), | |
| 48 view_manager_client_factory_(shell, this), | |
| 49 zoom_percentage_(kDefaultZoomPercentage) { | |
| 50 exported_services->AddService(&view_manager_client_factory_); | |
| 51 DecodePNG(response.Pass()); | |
| 52 } | |
| 39 | 53 |
| 40 private: | 54 private: |
| 41 // Overridden from ZoomableMedia: | 55 static const uint16_t kMaxZoomPercentage = 400; |
| 42 virtual void ZoomIn() OVERRIDE; | 56 static const uint16_t kMinZoomPercentage = 20; |
| 43 virtual void ZoomOut() OVERRIDE; | 57 static const uint16_t kDefaultZoomPercentage = 100; |
| 44 virtual void ZoomToActualSize() OVERRIDE; | 58 static const uint16_t kZoomStep = 20; |
| 45 | 59 |
| 46 PNGViewer* viewer_; | 60 virtual ~PNGView() { |
| 61 if (root_) | |
| 62 root_->RemoveObserver(this); | |
| 63 } | |
| 47 | 64 |
| 48 DISALLOW_COPY_AND_ASSIGN(ZoomableMediaImpl); | 65 // Overridden from ViewManagerDelegate: |
| 49 }; | 66 virtual void OnEmbed(ViewManager* view_manager, |
| 67 View* root, | |
| 68 ServiceProviderImpl* exported_services, | |
| 69 scoped_ptr<ServiceProvider> imported_services) OVERRIDE { | |
| 70 root_ = root; | |
| 71 root_->AddObserver(this); | |
| 72 root_->SetColor(SK_ColorGRAY); | |
| 73 if (!bitmap_.isNull()) | |
| 74 DrawBitmap(); | |
| 75 } | |
| 50 | 76 |
| 51 class NavigatorImpl : public InterfaceImpl<Navigator> { | 77 virtual void OnViewManagerDisconnected( |
| 52 public: | 78 ViewManager* view_manager) OVERRIDE { |
| 53 explicit NavigatorImpl(PNGViewer* viewer) : viewer_(viewer) {} | 79 // TODO(aa): Need to figure out how shutdown works. |
| 54 virtual ~NavigatorImpl() {} | 80 } |
| 55 | 81 |
| 56 private: | 82 // Overridden from ViewObserver: |
| 57 // Overridden from Navigator: | 83 virtual void OnViewBoundsChanged(View* view, |
| 58 virtual void Navigate( | 84 const gfx::Rect& old_bounds, |
| 59 uint32_t view_id, | 85 const gfx::Rect& new_bounds) OVERRIDE { |
| 60 NavigationDetailsPtr navigation_details, | 86 DCHECK_EQ(view, root_); |
| 61 ResponseDetailsPtr response_details) OVERRIDE { | 87 DrawBitmap(); |
| 62 int content_length = GetContentLength(response_details->response->headers); | 88 } |
| 63 unsigned char* data = new unsigned char[content_length]; | 89 |
| 64 unsigned char* buf = data; | 90 virtual void OnViewDestroyed(View* view) OVERRIDE { |
| 91 DCHECK_EQ(view, root_); | |
| 92 delete this; | |
| 93 } | |
| 94 | |
| 95 void DecodePNG(URLResponsePtr response) { | |
| 96 int content_length = GetContentLength(response->headers); | |
| 97 scoped_ptr<unsigned char[]> data(new unsigned char[content_length]); | |
| 98 unsigned char* buf = data.get(); | |
| 65 uint32_t bytes_remaining = content_length; | 99 uint32_t bytes_remaining = content_length; |
| 66 uint32_t num_bytes = bytes_remaining; | 100 uint32_t num_bytes = bytes_remaining; |
| 67 while (bytes_remaining > 0) { | 101 while (bytes_remaining > 0) { |
| 68 MojoResult result = ReadDataRaw( | 102 MojoResult result = ReadDataRaw(response->body.get(), |
| 69 response_details->response->body.get(), | 103 buf, |
| 70 buf, | 104 &num_bytes, |
| 71 &num_bytes, | 105 MOJO_READ_DATA_FLAG_NONE); |
| 72 MOJO_READ_DATA_FLAG_NONE); | |
| 73 if (result == MOJO_RESULT_SHOULD_WAIT) { | 106 if (result == MOJO_RESULT_SHOULD_WAIT) { |
| 74 Wait(response_details->response->body.get(), | 107 Wait(response->body.get(), |
| 75 MOJO_HANDLE_SIGNAL_READABLE, | 108 MOJO_HANDLE_SIGNAL_READABLE, |
| 76 MOJO_DEADLINE_INDEFINITE); | 109 MOJO_DEADLINE_INDEFINITE); |
| 77 } else if (result == MOJO_RESULT_OK) { | 110 } else if (result == MOJO_RESULT_OK) { |
| 78 buf += num_bytes; | 111 buf += num_bytes; |
| 79 num_bytes = bytes_remaining -= num_bytes; | 112 num_bytes = bytes_remaining -= num_bytes; |
| 80 } else { | 113 } else { |
| 81 break; | 114 break; |
| 82 } | 115 } |
| 83 } | 116 } |
| 84 | 117 |
| 85 SkBitmap bitmap; | 118 gfx::PNGCodec::Decode(static_cast<const unsigned char*>(data.get()), |
| 86 gfx::PNGCodec::Decode(static_cast<const unsigned char*>(data), | 119 content_length, &bitmap_); |
| 87 content_length, &bitmap); | |
| 88 UpdateView(view_id, bitmap); | |
| 89 | |
| 90 delete[] data; | |
| 91 } | 120 } |
| 92 | 121 |
| 93 void UpdateView(Id view_id, const SkBitmap& bitmap); | 122 void DrawBitmap() { |
| 123 if (!root_) | |
| 124 return; | |
| 125 | |
| 126 skia::RefPtr<SkCanvas> canvas(skia::AdoptRef(skia::CreatePlatformCanvas( | |
| 127 root_->bounds().width(), | |
| 128 root_->bounds().height(), | |
| 129 true))); | |
| 130 canvas->drawColor(SK_ColorGRAY); | |
| 131 SkPaint paint; | |
| 132 SkScalar scale = | |
| 133 SkFloatToScalar(zoom_percentage_ * 1.0f / kDefaultZoomPercentage); | |
| 134 canvas->scale(scale, scale); | |
| 135 canvas->drawBitmap(bitmap_, 0, 0, &paint); | |
| 136 root_->SetContents(skia::GetTopDevice(*canvas)->accessBitmap(true)); | |
| 137 } | |
| 138 | |
| 139 void ZoomIn() { | |
| 140 if (zoom_percentage_ >= kMaxZoomPercentage) | |
| 141 return; | |
| 142 zoom_percentage_ += kZoomStep; | |
| 143 DrawBitmap(); | |
| 144 } | |
| 145 | |
| 146 void ZoomOut() { | |
| 147 if (zoom_percentage_ <= kMinZoomPercentage) | |
| 148 return; | |
| 149 zoom_percentage_ -= kZoomStep; | |
| 150 DrawBitmap(); | |
| 151 } | |
| 152 | |
| 153 void ZoomToActualSize() { | |
| 154 if (zoom_percentage_ == kDefaultZoomPercentage) | |
| 155 return; | |
| 156 zoom_percentage_ = kDefaultZoomPercentage; | |
| 157 DrawBitmap(); | |
| 158 } | |
| 94 | 159 |
| 95 int GetContentLength(const Array<String>& headers) { | 160 int GetContentLength(const Array<String>& headers) { |
| 96 for (size_t i = 0; i < headers.size(); ++i) { | 161 for (size_t i = 0; i < headers.size(); ++i) { |
| 97 base::StringTokenizer t(headers[i], ": ;="); | 162 base::StringTokenizer t(headers[i], ": ;="); |
| 98 while (t.GetNext()) { | 163 while (t.GetNext()) { |
| 99 if (!t.token_is_delim() && t.token() == "Content-Length") { | 164 if (!t.token_is_delim() && t.token() == "Content-Length") { |
| 100 while (t.GetNext()) { | 165 while (t.GetNext()) { |
| 101 if (!t.token_is_delim()) | 166 if (!t.token_is_delim()) |
| 102 return atoi(t.token().c_str()); | 167 return atoi(t.token().c_str()); |
| 103 } | 168 } |
| 104 } | 169 } |
| 105 } | 170 } |
| 106 } | 171 } |
| 107 return 0; | 172 return 0; |
| 108 } | 173 } |
| 109 | 174 |
| 110 PNGViewer* viewer_; | 175 SkBitmap bitmap_; |
| 176 scoped_ptr<ServiceProvider> imported_services_; | |
| 177 View* root_; | |
| 178 ViewManagerClientFactory view_manager_client_factory_; | |
| 179 uint16_t zoom_percentage_; | |
| 111 | 180 |
| 112 DISALLOW_COPY_AND_ASSIGN(NavigatorImpl); | 181 DISALLOW_COPY_AND_ASSIGN(PNGView); |
| 113 }; | 182 }; |
| 114 | 183 |
| 115 class PNGViewer | 184 class ContentHandlerImpl : public InterfaceImpl<ContentHandler> { |
| 116 : public ApplicationDelegate, | |
| 117 public ViewManagerDelegate, | |
| 118 public ViewObserver { | |
| 119 public: | 185 public: |
| 120 PNGViewer() | 186 explicit ContentHandlerImpl(Shell* shell) |
| 121 : navigator_factory_(this), | 187 : shell_(shell) { |
| 122 zoomable_media_factory_(this), | 188 } |
| 123 view_manager_client_factory_(this), | 189 virtual ~ContentHandlerImpl() {} |
| 124 root_(NULL), | 190 |
| 125 zoom_percentage_(kDefaultZoomPercentage) {} | 191 private: |
| 126 virtual ~PNGViewer() { | 192 // Overridden from ContentHandler: |
| 127 if (root_) | 193 virtual void OnConnect( |
| 128 root_->RemoveObserver(this); | 194 const mojo::String& url, |
| 195 URLResponsePtr response, | |
| 196 InterfaceRequest<ServiceProvider> service_provider) OVERRIDE { | |
| 197 ServiceProviderImpl* exported_services = new ServiceProviderImpl(); | |
| 198 BindToRequest(exported_services, &service_provider); | |
| 199 scoped_ptr<ServiceProvider> remote( | |
| 200 exported_services->CreateRemoteServiceProvider()); | |
| 201 new PNGView(response.Pass(), exported_services, remote.Pass(), shell_); | |
|
darin (slow to review)
2014/09/04 21:33:51
nit: add a comment here about memory management?
Aaron Boodman
2014/09/05 02:41:31
Yeah good point -- instead, I made the ctor privat
| |
| 129 } | 202 } |
| 130 | 203 |
| 131 void UpdateView(Id view_id, const SkBitmap& bitmap) { | 204 Shell* shell_; |
| 132 bitmap_ = bitmap; | 205 |
| 133 zoom_percentage_ = kDefaultZoomPercentage; | 206 DISALLOW_COPY_AND_ASSIGN(ContentHandlerImpl); |
| 134 DrawBitmap(); | 207 }; |
| 208 | |
| 209 class PNGViewer : public ApplicationDelegate { | |
| 210 public: | |
| 211 PNGViewer() { | |
| 135 } | 212 } |
| 136 | 213 private: |
| 137 void ZoomIn() { | 214 // Overridden from ApplicationDelegate: |
| 138 if (zoom_percentage_ >= kMaxZoomPercentage) | 215 virtual void Initialize(ApplicationImpl* app) MOJO_OVERRIDE { |
| 139 return; | 216 content_handler_factory_.reset( |
|
darin (slow to review)
2014/09/04 21:33:51
food for thought...
it seems like it'd be possibl
Aaron Boodman
2014/09/04 22:31:43
I'm keeping it in mind. I wanted to flush things o
| |
| 140 zoom_percentage_ += kZoomStep; | 217 new InterfaceFactoryImplWithContext<ContentHandlerImpl, Shell>( |
| 141 DrawBitmap(); | 218 app->shell())); |
| 142 } | 219 } |
| 143 | 220 |
| 144 void ZoomOut() { | |
| 145 if (zoom_percentage_ <= kMinZoomPercentage) | |
| 146 return; | |
| 147 zoom_percentage_ -= kZoomStep; | |
| 148 DrawBitmap(); | |
| 149 } | |
| 150 | |
| 151 void ZoomToActualSize() { | |
| 152 if (zoom_percentage_ == kDefaultZoomPercentage) | |
| 153 return; | |
| 154 zoom_percentage_ = kDefaultZoomPercentage; | |
| 155 DrawBitmap(); | |
| 156 } | |
| 157 | |
| 158 private: | |
| 159 static const uint16_t kMaxZoomPercentage = 400; | |
| 160 static const uint16_t kMinZoomPercentage = 20; | |
| 161 static const uint16_t kDefaultZoomPercentage = 100; | |
| 162 static const uint16_t kZoomStep = 20; | |
| 163 | |
| 164 // Overridden from ApplicationDelegate: | 221 // Overridden from ApplicationDelegate: |
| 165 virtual bool ConfigureIncomingConnection(ApplicationConnection* connection) | 222 virtual bool ConfigureIncomingConnection(ApplicationConnection* connection) |
| 166 MOJO_OVERRIDE { | 223 MOJO_OVERRIDE { |
| 167 connection->AddService(&navigator_factory_); | 224 connection->AddService(content_handler_factory_.get()); |
| 168 connection->AddService(&zoomable_media_factory_); | |
| 169 connection->AddService(&view_manager_client_factory_); | |
| 170 return true; | 225 return true; |
| 171 } | 226 } |
| 172 | 227 |
| 173 // Overridden from ViewManagerDelegate: | 228 scoped_ptr<InterfaceFactoryImplWithContext<ContentHandlerImpl, Shell> > |
| 174 virtual void OnEmbed(ViewManager* view_manager, | 229 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 | 230 |
| 228 DISALLOW_COPY_AND_ASSIGN(PNGViewer); | 231 DISALLOW_COPY_AND_ASSIGN(PNGViewer); |
| 229 }; | 232 }; |
| 230 | 233 |
| 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 | 234 } // namespace examples |
| 249 } // namespace mojo | 235 } // namespace mojo |
| 250 | 236 |
| 251 MojoResult MojoMain(MojoHandle shell_handle) { | 237 MojoResult MojoMain(MojoHandle shell_handle) { |
| 252 mojo::ApplicationRunnerChromium runner(new mojo::examples::PNGViewer); | 238 mojo::ApplicationRunnerChromium runner(new mojo::examples::PNGViewer); |
| 253 return runner.Run(shell_handle); | 239 return runner.Run(shell_handle); |
| 254 } | 240 } |
| OLD | NEW |