Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(200)

Side by Side Diff: examples/pdf_viewer/pdf_viewer.cc

Issue 690583002: Add PDF viewer example. (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: rebase Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « examples/pdf_viewer/DEPS ('k') | examples/png_viewer/BUILD.gn » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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>
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" 5 #include "base/strings/string_tokenizer.h"
11 #include "examples/bitmap_uploader/bitmap_uploader.h" 6 #include "examples/bitmap_uploader/bitmap_uploader.h"
12 #include "examples/media_viewer/media_viewer.mojom.h"
13 #include "mojo/application/application_runner_chromium.h" 7 #include "mojo/application/application_runner_chromium.h"
14 #include "mojo/public/c/system/main.h" 8 #include "mojo/public/c/system/main.h"
15 #include "mojo/public/cpp/application/application_connection.h" 9 #include "mojo/public/cpp/application/application_connection.h"
16 #include "mojo/public/cpp/application/application_delegate.h" 10 #include "mojo/public/cpp/application/application_delegate.h"
17 #include "mojo/public/cpp/application/application_impl.h" 11 #include "mojo/public/cpp/application/application_impl.h"
18 #include "mojo/public/cpp/application/interface_factory_impl.h" 12 #include "mojo/public/cpp/application/interface_factory_impl.h"
19 #include "mojo/public/cpp/application/service_provider_impl.h" 13 #include "mojo/public/cpp/application/service_provider_impl.h"
20 #include "mojo/services/public/cpp/view_manager/types.h" 14 #include "mojo/services/public/cpp/view_manager/types.h"
21 #include "mojo/services/public/cpp/view_manager/view.h" 15 #include "mojo/services/public/cpp/view_manager/view.h"
22 #include "mojo/services/public/cpp/view_manager/view_manager.h" 16 #include "mojo/services/public/cpp/view_manager/view_manager.h"
23 #include "mojo/services/public/cpp/view_manager/view_manager_client_factory.h" 17 #include "mojo/services/public/cpp/view_manager/view_manager_client_factory.h"
24 #include "mojo/services/public/cpp/view_manager/view_manager_delegate.h" 18 #include "mojo/services/public/cpp/view_manager/view_manager_delegate.h"
25 #include "mojo/services/public/cpp/view_manager/view_observer.h" 19 #include "mojo/services/public/cpp/view_manager/view_observer.h"
26 #include "mojo/services/public/interfaces/content_handler/content_handler.mojom. h" 20 #include "mojo/services/public/interfaces/content_handler/content_handler.mojom. h"
27 #include "third_party/skia/include/core/SkColor.h" 21 #include "mojo/services/public/interfaces/input_events/input_events.mojom.h"
28 #include "ui/gfx/codec/png_codec.h" 22 #include "mojo/services/public/interfaces/input_events/input_key_codes.mojom.h"
23 #include "third_party/pdfium/fpdfsdk/include/fpdf_ext.h"
24 #include "third_party/pdfium/fpdfsdk/include/fpdfformfill.h"
25 #include "third_party/pdfium/fpdfsdk/include/fpdftext.h"
26 #include "third_party/pdfium/fpdfsdk/include/fpdfview.h"
27 #include "v8/include/v8.h"
28
29 #define BACKGROUND_COLOR 0xFF888888
29 30
30 namespace mojo { 31 namespace mojo {
31 namespace examples { 32 namespace examples {
32 33
33 class PNGViewer; 34 class PDFViewer;
34 35
35 // TODO(aa): Hook up ZoomableMedia interface again. 36 class PDFView : public ViewManagerDelegate, public ViewObserver {
36 class PNGView : public ViewManagerDelegate, public ViewObserver {
37 public: 37 public:
38 static void Spawn(URLResponsePtr response, 38 static void Spawn(URLResponsePtr response,
39 ServiceProviderImpl* exported_services, 39 ServiceProviderImpl* exported_services,
40 scoped_ptr<ServiceProvider> imported_services, 40 scoped_ptr<ServiceProvider> imported_services,
41 Shell* shell) { 41 Shell* shell) {
42 // PNGView deletes itself when its View is destroyed. 42 // PDFView deletes itself when its View is destroyed.
43 new PNGView( 43 new PDFView(
44 response.Pass(), exported_services, imported_services.Pass(), shell); 44 response.Pass(), exported_services, imported_services.Pass(), shell);
45 } 45 }
46 46
47 private: 47 private:
48 static const uint16_t kMaxZoomPercentage = 400; 48 PDFView(URLResponsePtr response,
49 static const uint16_t kMinZoomPercentage = 20;
50 static const uint16_t kDefaultZoomPercentage = 100;
51 static const uint16_t kZoomStep = 20;
52
53 PNGView(URLResponsePtr response,
54 ServiceProviderImpl* exported_services, 49 ServiceProviderImpl* exported_services,
55 scoped_ptr<ServiceProvider> imported_services, 50 scoped_ptr<ServiceProvider> imported_services,
56 Shell* shell) 51 Shell* shell)
57 : width_(0), 52 : current_page_(0),
58 height_(0), 53 page_count_(0),
54 doc_(NULL),
59 imported_services_(imported_services.Pass()), 55 imported_services_(imported_services.Pass()),
60 shell_(shell), 56 shell_(shell),
61 root_(nullptr), 57 root_(nullptr),
62 view_manager_client_factory_(shell, this), 58 view_manager_client_factory_(shell, this) {
63 zoom_percentage_(kDefaultZoomPercentage) {
64 exported_services->AddService(&view_manager_client_factory_); 59 exported_services->AddService(&view_manager_client_factory_);
65 DecodePNG(response.Pass()); 60 FetchPDF(response.Pass());
66 } 61 }
67 62
68 virtual ~PNGView() { 63 virtual ~PDFView() {
64 if (doc_)
65 FPDF_CloseDocument(doc_);
69 if (root_) 66 if (root_)
70 root_->RemoveObserver(this); 67 root_->RemoveObserver(this);
71 } 68 }
72 69
73 // Overridden from ViewManagerDelegate: 70 // Overridden from ViewManagerDelegate:
74 virtual void OnEmbed(ViewManager* view_manager, 71 virtual void OnEmbed(ViewManager* view_manager,
75 View* root, 72 View* root,
76 ServiceProviderImpl* exported_services, 73 ServiceProviderImpl* exported_services,
77 scoped_ptr<ServiceProvider> imported_services) override { 74 scoped_ptr<ServiceProvider> imported_services) override {
78 root_ = root; 75 root_ = root;
79 root_->AddObserver(this); 76 root_->AddObserver(this);
80 bitmap_uploader_.reset(new BitmapUploader(root_)); 77 bitmap_uploader_.reset(new BitmapUploader(root_));
81 bitmap_uploader_->Init(shell_); 78 bitmap_uploader_->Init(shell_);
82 bitmap_uploader_->SetColor(SK_ColorGRAY); 79 bitmap_uploader_->SetColor(BACKGROUND_COLOR);
83 if (bitmap_.get()) 80 DrawBitmap();
84 DrawBitmap();
85 } 81 }
86 82
87 virtual void OnViewManagerDisconnected(ViewManager* view_manager) override { 83 virtual void OnViewManagerDisconnected(ViewManager* view_manager) override {
88 // TODO(aa): Need to figure out how shutdown works.
89 } 84 }
90 85
91 // Overridden from ViewObserver: 86 // Overridden from ViewObserver:
92 virtual void OnViewBoundsChanged(View* view, 87 virtual void OnViewBoundsChanged(View* view,
93 const Rect& old_bounds, 88 const Rect& old_bounds,
94 const Rect& new_bounds) override { 89 const Rect& new_bounds) override {
95 DCHECK_EQ(view, root_); 90 DCHECK_EQ(view, root_);
96 DrawBitmap(); 91 DrawBitmap();
97 } 92 }
98 93
94 virtual void OnViewInputEvent(View* view, const EventPtr& event) override {
95 if (event->key_data &&
96 (event->action != EVENT_TYPE_KEY_PRESSED ||
97 event->key_data->is_char)) {
98 return;
99 }
100 if ((event->key_data &&
101 event->key_data->windows_key_code == KEYBOARD_CODE_DOWN) ||
102 (event->wheel_data && event->wheel_data->y_offset < 0)) {
103 if (current_page_ < (page_count_ - 1)) {
104 current_page_++;
105 DrawBitmap();
106 }
107 } else if ((event->key_data &&
108 event->key_data->windows_key_code == KEYBOARD_CODE_UP) ||
109 (event->wheel_data && event->wheel_data->y_offset > 0)) {
110 if (current_page_ > 0) {
111 current_page_--;
112 DrawBitmap();
113 }
114 }
115 }
116
99 virtual void OnViewDestroyed(View* view) override { 117 virtual void OnViewDestroyed(View* view) override {
100 DCHECK_EQ(view, root_); 118 DCHECK_EQ(view, root_);
101 delete this; 119 delete this;
102 } 120 }
103 121
104 void DecodePNG(URLResponsePtr response) { 122 void DrawBitmap() {
123 if (!root_ || !doc_)
124 return;
125
126 FPDF_PAGE page = FPDF_LoadPage(doc_, current_page_);
127 FPDF_TEXTPAGE text_page = FPDFText_LoadPage(page);
128 int width = static_cast<int>(FPDF_GetPageWidth(page));
129 int height = static_cast<int>(FPDF_GetPageHeight(page));
130
131 scoped_ptr<std::vector<unsigned char>> bitmap;
132 bitmap.reset(new std::vector<unsigned char>);
133 bitmap->resize(width * height * 4);
134
135 FPDF_BITMAP f_bitmap = FPDFBitmap_CreateEx(
136 width, height, FPDFBitmap_BGRA, &(*bitmap)[0], width * 4);
137 FPDFBitmap_FillRect(f_bitmap, 0, 0, width, height, 0xFFFFFFFF);
138 FPDF_RenderPageBitmap(f_bitmap, page, 0, 0, width, height, 0, 0);
139 FPDFBitmap_Destroy(f_bitmap);
140
141 FPDFText_ClosePage(text_page);
142 FPDF_ClosePage(page);
143
144 bitmap_uploader_->SetBitmap(width, height, bitmap.Pass(),
145 BitmapUploader::BGRA);
146 }
147
148 void FetchPDF(URLResponsePtr response) {
105 int content_length = GetContentLength(response->headers); 149 int content_length = GetContentLength(response->headers);
106 scoped_ptr<unsigned char[]> data(new unsigned char[content_length]); 150 scoped_ptr<unsigned char[]> data;
107 unsigned char* buf = data.get(); 151 data_.reset(new unsigned char[content_length]);
152 unsigned char* buf = data_.get();
108 uint32_t bytes_remaining = content_length; 153 uint32_t bytes_remaining = content_length;
109 uint32_t num_bytes = bytes_remaining; 154 uint32_t num_bytes = bytes_remaining;
110 while (bytes_remaining > 0) { 155 while (bytes_remaining > 0) {
111 MojoResult result = ReadDataRaw( 156 MojoResult result = ReadDataRaw(
112 response->body.get(), buf, &num_bytes, MOJO_READ_DATA_FLAG_NONE); 157 response->body.get(), buf, &num_bytes, MOJO_READ_DATA_FLAG_NONE);
113 if (result == MOJO_RESULT_SHOULD_WAIT) { 158 if (result == MOJO_RESULT_SHOULD_WAIT) {
114 Wait(response->body.get(), 159 Wait(response->body.get(),
115 MOJO_HANDLE_SIGNAL_READABLE, 160 MOJO_HANDLE_SIGNAL_READABLE,
116 MOJO_DEADLINE_INDEFINITE); 161 MOJO_DEADLINE_INDEFINITE);
117 } else if (result == MOJO_RESULT_OK) { 162 } else if (result == MOJO_RESULT_OK) {
118 buf += num_bytes; 163 buf += num_bytes;
119 num_bytes = bytes_remaining -= num_bytes; 164 num_bytes = bytes_remaining -= num_bytes;
120 } else { 165 } else {
121 break; 166 break;
122 } 167 }
123 } 168 }
124 169
125 bitmap_.reset(new std::vector<unsigned char>); 170 doc_ = FPDF_LoadMemDocument(data_.get(), content_length, NULL);
126 gfx::PNGCodec::Decode(static_cast<const unsigned char*>(data.get()), 171 page_count_ = FPDF_GetPageCount(doc_);
127 content_length,
128 gfx::PNGCodec::FORMAT_BGRA,
129 bitmap_.get(),
130 &width_,
131 &height_);
132 }
133
134 void DrawBitmap() {
135 if (!root_)
136 return;
137
138
139 bitmap_uploader_->SetBitmap(width_, height_, bitmap_.Pass(),
140 BitmapUploader::BGRA);
141 }
142
143 void ZoomIn() {
144 if (zoom_percentage_ >= kMaxZoomPercentage)
145 return;
146 zoom_percentage_ += kZoomStep;
147 DrawBitmap();
148 }
149
150 void ZoomOut() {
151 if (zoom_percentage_ <= kMinZoomPercentage)
152 return;
153 zoom_percentage_ -= kZoomStep;
154 DrawBitmap();
155 }
156
157 void ZoomToActualSize() {
158 if (zoom_percentage_ == kDefaultZoomPercentage)
159 return;
160 zoom_percentage_ = kDefaultZoomPercentage;
161 DrawBitmap();
162 } 172 }
163 173
164 int GetContentLength(const Array<String>& headers) { 174 int GetContentLength(const Array<String>& headers) {
165 for (size_t i = 0; i < headers.size(); ++i) { 175 for (size_t i = 0; i < headers.size(); ++i) {
166 base::StringTokenizer t(headers[i], ": ;="); 176 base::StringTokenizer t(headers[i], ": ;=");
167 while (t.GetNext()) { 177 while (t.GetNext()) {
168 if (!t.token_is_delim() && t.token() == "Content-Length") { 178 if (!t.token_is_delim() && t.token() == "Content-Length") {
169 while (t.GetNext()) { 179 while (t.GetNext()) {
170 if (!t.token_is_delim()) 180 if (!t.token_is_delim())
171 return atoi(t.token().c_str()); 181 return atoi(t.token().c_str());
172 } 182 }
173 } 183 }
174 } 184 }
175 } 185 }
176 return 0; 186 return 0;
177 } 187 }
178 188
179 int width_; 189 scoped_ptr<unsigned char[]> data_;
180 int height_; 190 int current_page_;
181 scoped_ptr<std::vector<unsigned char>> bitmap_; 191 int page_count_;
192 FPDF_DOCUMENT doc_;
182 scoped_ptr<ServiceProvider> imported_services_; 193 scoped_ptr<ServiceProvider> imported_services_;
183 Shell* shell_; 194 Shell* shell_;
184 View* root_; 195 View* root_;
185 ViewManagerClientFactory view_manager_client_factory_; 196 ViewManagerClientFactory view_manager_client_factory_;
186 uint16_t zoom_percentage_;
187 scoped_ptr<BitmapUploader> bitmap_uploader_; 197 scoped_ptr<BitmapUploader> bitmap_uploader_;
188 198
189 DISALLOW_COPY_AND_ASSIGN(PNGView); 199 DISALLOW_COPY_AND_ASSIGN(PDFView);
190 }; 200 };
191 201
192 class ContentHandlerImpl : public InterfaceImpl<ContentHandler> { 202 class ContentHandlerImpl : public InterfaceImpl<ContentHandler> {
193 public: 203 public:
194 explicit ContentHandlerImpl(Shell* shell) : shell_(shell) {} 204 explicit ContentHandlerImpl(Shell* shell) : shell_(shell) {}
195 virtual ~ContentHandlerImpl() {} 205 virtual ~ContentHandlerImpl() {}
196 206
197 private: 207 private:
198 // Overridden from ContentHandler: 208 // Overridden from ContentHandler:
199 virtual void OnConnect( 209 virtual void OnConnect(
200 const mojo::String& requestor_url, 210 const mojo::String& requestor_url,
201 URLResponsePtr response, 211 URLResponsePtr response,
202 InterfaceRequest<ServiceProvider> service_provider) override { 212 InterfaceRequest<ServiceProvider> service_provider) override {
203 ServiceProviderImpl* exported_services = new ServiceProviderImpl(); 213 ServiceProviderImpl* exported_services = new ServiceProviderImpl();
204 BindToRequest(exported_services, &service_provider); 214 BindToRequest(exported_services, &service_provider);
205 scoped_ptr<ServiceProvider> remote( 215 scoped_ptr<ServiceProvider> remote(
206 exported_services->CreateRemoteServiceProvider()); 216 exported_services->CreateRemoteServiceProvider());
207 PNGView::Spawn(response.Pass(), exported_services, remote.Pass(), shell_); 217 PDFView::Spawn(response.Pass(), exported_services, remote.Pass(), shell_);
208 } 218 }
209 219
210 Shell* shell_; 220 Shell* shell_;
211 221
212 DISALLOW_COPY_AND_ASSIGN(ContentHandlerImpl); 222 DISALLOW_COPY_AND_ASSIGN(ContentHandlerImpl);
213 }; 223 };
214 224
215 class PNGViewer : public ApplicationDelegate { 225 class PDFViewer : public ApplicationDelegate {
216 public: 226 public:
217 PNGViewer() {} 227 PDFViewer() {}
228 virtual ~PDFViewer() {
229 FPDF_DestroyLibrary();
230 }
218 private: 231 private:
219 // Overridden from ApplicationDelegate: 232 // Overridden from ApplicationDelegate:
220 virtual void Initialize(ApplicationImpl* app) override { 233 virtual void Initialize(ApplicationImpl* app) override {
221 content_handler_factory_.reset( 234 content_handler_factory_.reset(
222 new InterfaceFactoryImplWithContext<ContentHandlerImpl, Shell>( 235 new InterfaceFactoryImplWithContext<ContentHandlerImpl, Shell>(
223 app->shell())); 236 app->shell()));
237
238 v8::V8::InitializeICU();
239 FPDF_InitLibrary(NULL);
224 } 240 }
225 241
226 // Overridden from ApplicationDelegate: 242 // Overridden from ApplicationDelegate:
227 virtual bool ConfigureIncomingConnection( 243 virtual bool ConfigureIncomingConnection(
228 ApplicationConnection* connection) override { 244 ApplicationConnection* connection) override {
229 connection->AddService(content_handler_factory_.get()); 245 connection->AddService(content_handler_factory_.get());
230 return true; 246 return true;
231 } 247 }
232 248
233 scoped_ptr<InterfaceFactoryImplWithContext<ContentHandlerImpl, Shell> > 249 scoped_ptr<InterfaceFactoryImplWithContext<ContentHandlerImpl, Shell> >
234 content_handler_factory_; 250 content_handler_factory_;
235 251
236 DISALLOW_COPY_AND_ASSIGN(PNGViewer); 252 DISALLOW_COPY_AND_ASSIGN(PDFViewer);
237 }; 253 };
238 254
239 } // namespace examples 255 } // namespace examples
240 } // namespace mojo 256 } // namespace mojo
241 257
242 MojoResult MojoMain(MojoHandle shell_handle) { 258 MojoResult MojoMain(MojoHandle shell_handle) {
243 mojo::ApplicationRunnerChromium runner(new mojo::examples::PNGViewer); 259 mojo::ApplicationRunnerChromium runner(new mojo::examples::PDFViewer);
244 return runner.Run(shell_handle); 260 return runner.Run(shell_handle);
245 } 261 }
OLDNEW
« no previous file with comments | « examples/pdf_viewer/DEPS ('k') | examples/png_viewer/BUILD.gn » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698