| 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 |