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

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

Issue 1559723002: Update the UI examples. (Closed) Base URL: git@github.com:domokit/mojo.git@moz-14
Patch Set: Created 4 years, 11 months 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
OLDNEW
(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 <memory>
6 #include <string>
7
8 #include "base/bind.h"
9 #include "base/macros.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "mojo/application/application_runner_chromium.h"
12 #include "mojo/data_pipe_utils/data_pipe_utils.h"
13 #include "mojo/public/c/system/main.h"
14 #include "mojo/ui/content_viewer_app.h"
15 #include "mojo/ui/ganesh_view.h"
16 #include "mojo/ui/input_handler.h"
17 #include "third_party/pdfium/fpdfsdk/include/fpdf_ext.h"
18 #include "third_party/pdfium/fpdfsdk/include/fpdfview.h"
19 #include "third_party/skia/include/core/SkCanvas.h"
20 #include "third_party/skia/include/core/SkData.h"
21 #include "third_party/skia/include/core/SkImage.h"
22 #include "third_party/skia/include/core/SkImageInfo.h"
23 #include "third_party/skia/include/core/SkSurface.h"
24 #include "v8/include/v8.h"
25
26 namespace examples {
27
28 constexpr uint32_t kContentImageResourceId = 1;
29 constexpr uint32_t kRootNodeId = mojo::gfx::composition::kSceneRootNodeId;
30
31 class PDFLibrary;
32
33 class PDFDocument {
34 public:
35 PDFDocument(const std::shared_ptr<PDFLibrary>& pdf_library,
36 FPDF_DOCUMENT doc,
37 const std::string& data)
38 : pdf_library_(pdf_library),
39 doc_(doc),
40 data_(data),
41 page_count_(FPDF_GetPageCount(doc_)) {}
42
43 ~PDFDocument() { FPDF_CloseDocument(doc_); }
44
45 uint32_t page_count() { return page_count_; }
46
47 skia::RefPtr<SkImage> DrawPage(int page_index) {
48 FPDF_PAGE page = FPDF_LoadPage(doc_, page_index);
49 int width = static_cast<int>(FPDF_GetPageWidth(page));
50 int height = static_cast<int>(FPDF_GetPageHeight(page));
51 int stride = width * 4;
52
53 skia::RefPtr<SkData> pixels =
54 skia::AdoptRef(SkData::NewUninitialized(stride * height));
55 DCHECK(pixels);
56
57 FPDF_BITMAP bitmap = FPDFBitmap_CreateEx(width, height, FPDFBitmap_BGRA,
58 pixels->writable_data(), stride);
59 FPDFBitmap_FillRect(bitmap, 0, 0, width, height, 0xFFFFFFFF);
60 FPDF_RenderPageBitmap(bitmap, page, 0, 0, width, height, 0, 0);
61 FPDFBitmap_Destroy(bitmap);
62
63 FPDF_ClosePage(page);
64
65 SkImageInfo info = SkImageInfo::Make(width, height, kBGRA_8888_SkColorType,
66 kOpaque_SkAlphaType);
67 return skia::AdoptRef(SkImage::NewRasterData(info, pixels.get(), stride));
68 }
69
70 private:
71 std::shared_ptr<PDFLibrary> pdf_library_;
72 FPDF_DOCUMENT doc_;
73 std::string data_;
74 uint32_t page_count_;
75 };
76
77 class PDFLibrary : public std::enable_shared_from_this<PDFLibrary> {
78 public:
79 PDFLibrary() {
80 v8::V8::InitializeICU();
81 FPDF_InitLibrary();
82 }
83
84 ~PDFLibrary() { FPDF_DestroyLibrary(); }
85
86 std::shared_ptr<PDFDocument> Decode(mojo::URLResponsePtr response) {
87 std::string data;
88 mojo::common::BlockingCopyToString(response->body.Pass(), &data);
89 if (data.length() >= static_cast<size_t>(std::numeric_limits<int>::max()))
90 return nullptr;
91
92 FPDF_DOCUMENT doc = FPDF_LoadMemDocument(
93 data.data(), static_cast<int>(data.length()), nullptr);
94 if (!doc)
95 return nullptr;
96
97 return std::make_shared<PDFDocument>(shared_from_this(), doc, data);
98 }
99 };
100
101 class PDFDocumentView : public mojo::ui::GaneshView,
102 public mojo::ui::InputListener {
103 public:
104 PDFDocumentView(
105 mojo::ApplicationImpl* app_impl,
106 const std::shared_ptr<PDFDocument>& pdf_document,
107 const mojo::ui::ViewProvider::CreateViewCallback& create_view_callback)
108 : GaneshView(app_impl, "PDFDocumentViewer", create_view_callback),
109 pdf_document_(pdf_document),
110 input_handler_(view_service_provider(), this) {
111 DCHECK(pdf_document_);
112 }
113
114 ~PDFDocumentView() override {}
115
116 private:
117 // |View|:
118 void OnLayout(mojo::ui::ViewLayoutParamsPtr layout_params,
119 mojo::Array<uint32_t> children_needing_layout,
120 const OnLayoutCallback& callback) override {
121 size_.width = layout_params->constraints->max_width;
122 size_.height = layout_params->constraints->max_height;
123
124 auto info = mojo::ui::ViewLayoutResult::New();
125 info->size = size_.Clone();
126 callback.Run(info.Pass());
127
128 UpdateScene();
abarth 2016/01/10 23:09:31 I'm surprised there's no token that I get from lay
jeffbrown 2016/01/26 08:14:17 I'll be redoing layout once this gets checked in.
129 }
130
131 // |InputListener|:
132 void OnEvent(mojo::EventPtr event, const OnEventCallback& callback) override {
133 if (event->key_data && (event->action != mojo::EventType::KEY_PRESSED ||
134 event->key_data->is_char)) {
135 callback.Run(false);
136 return;
137 }
138
139 if ((event->key_data &&
140 event->key_data->windows_key_code == mojo::KeyboardCode::DOWN) ||
141 (event->pointer_data && event->pointer_data->vertical_wheel < 0)) {
142 GotoNextPage();
143 callback.Run(true);
144 return;
145 }
146
147 if ((event->key_data &&
148 event->key_data->windows_key_code == mojo::KeyboardCode::UP) ||
149 (event->pointer_data && event->pointer_data->vertical_wheel > 0)) {
150 GotoPreviousPage();
151 callback.Run(true);
152 return;
153 }
154
155 callback.Run(false);
156 }
157
158 void UpdateScene() {
159 mojo::Rect bounds;
160 bounds.width = size_.width;
161 bounds.height = size_.height;
162
163 auto update = mojo::gfx::composition::SceneUpdate::New();
164 mojo::gfx::composition::ResourcePtr content_resource =
165 ganesh_renderer()->DrawCanvas(
166 size_,
167 base::Bind(&PDFDocumentView::DrawContent, base::Unretained(this)));
168 DCHECK(content_resource);
169 update->resources.insert(kContentImageResourceId, content_resource.Pass());
170
171 auto root_node = mojo::gfx::composition::Node::New();
172 root_node->op = mojo::gfx::composition::NodeOp::New();
173 root_node->op->set_image(mojo::gfx::composition::ImageNodeOp::New());
174 root_node->op->get_image()->content_rect = bounds.Clone();
175 root_node->op->get_image()->image_resource_id = kContentImageResourceId;
176 update->nodes.insert(kRootNodeId, root_node.Pass());
177
178 scene()->Update(update.Pass());
179 scene()->Publish(nullptr);
180 }
181
182 void DrawContent(SkCanvas* canvas) {
183 if (!cached_image_) {
184 cached_image_ = pdf_document_->DrawPage(page_);
185 }
186
187 if (cached_image_) {
188 canvas->clear(SK_ColorBLACK);
189
190 int32_t w, h;
191 if (size_.width * cached_image_->height() <
192 size_.height * cached_image_->width()) {
193 w = size_.width;
194 h = cached_image_->height() * size_.width / cached_image_->width();
195 } else {
196 w = cached_image_->width() * size_.height / cached_image_->height();
197 h = size_.height;
198 }
199 canvas->drawImageRect(
200 cached_image_.get(),
201 SkRect::MakeWH(cached_image_->width(), cached_image_->height()),
202 SkRect::MakeXYWH((size_.width - w) / 2, (size_.height - h) / 2, w, h),
203 nullptr);
204 } else {
205 canvas->clear(SK_ColorBLUE);
206 }
207
208 canvas->flush();
209 }
210
211 void GotoNextPage() {
212 if (page_ + 1 < pdf_document_->page_count()) {
213 page_++;
214 Redraw();
215 }
216 }
217
218 void GotoPreviousPage() {
219 if (page_ > 0) {
220 page_--;
221 Redraw();
222 }
223 }
224
225 void Redraw() {
226 cached_image_.clear();
227 UpdateScene();
abarth 2016/01/10 23:09:31 I was expecting some sort of "invalidate and wait
jeffbrown 2016/01/26 08:14:17 Good point. Let's add that.
228 }
229
230 std::shared_ptr<PDFDocument> pdf_document_;
231 uint32_t page_ = 0u;
232 skia::RefPtr<SkImage> cached_image_;
233
234 mojo::Size size_;
235 mojo::ui::InputHandler input_handler_;
236
237 DISALLOW_COPY_AND_ASSIGN(PDFDocumentView);
238 };
239
240 class PDFContentViewProviderApp : public mojo::ui::ViewProviderApp {
241 public:
242 PDFContentViewProviderApp(const std::shared_ptr<PDFLibrary>& pdf_library,
243 const std::shared_ptr<PDFDocument>& pdf_document)
244 : pdf_library_(pdf_library), pdf_document_(pdf_document) {
245 DCHECK(pdf_library_);
246 DCHECK(pdf_document_);
247 }
248
249 ~PDFContentViewProviderApp() override {}
250
251 bool CreateView(
252 const std::string& connection_url,
253 mojo::InterfaceRequest<mojo::ServiceProvider> services,
254 mojo::ServiceProviderPtr exposed_services,
255 const mojo::ui::ViewProvider::CreateViewCallback& callback) override {
256 new PDFDocumentView(app_impl(), pdf_document_, callback);
257 return true;
258 }
259
260 private:
261 std::shared_ptr<PDFLibrary> pdf_library_;
262 std::shared_ptr<PDFDocument> pdf_document_;
263
264 DISALLOW_COPY_AND_ASSIGN(PDFContentViewProviderApp);
265 };
266
267 class PDFContentViewerApp : public mojo::ui::ContentViewerApp {
268 public:
269 PDFContentViewerApp() : pdf_library_(std::make_shared<PDFLibrary>()) {}
270
271 ~PDFContentViewerApp() override {}
272
273 mojo::ui::ViewProviderApp* LoadContent(
274 const std::string& content_handler_url,
275 mojo::URLResponsePtr response) override {
276 std::shared_ptr<PDFDocument> pdf_document =
277 pdf_library_->Decode(response.Pass());
278 if (!pdf_document) {
279 LOG(ERROR) << "Could not decode PDFDocument.";
280 return nullptr;
281 }
282
283 return new PDFContentViewProviderApp(pdf_library_, pdf_document);
284 }
285
286 private:
287 std::shared_ptr<PDFLibrary> pdf_library_;
288
289 DISALLOW_COPY_AND_ASSIGN(PDFContentViewerApp);
290 };
291
292 } // namespace examples
293
294 MojoResult MojoMain(MojoHandle application_request) {
295 mojo::ApplicationRunnerChromium runner(new examples::PDFContentViewerApp());
296 return runner.Run(application_request);
297 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698