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

Side by Side Diff: pdf/out_of_process_instance.cc

Issue 294793003: Add the pdf plugin's source in src\pdf. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: review comments and sync past DEPS roll to fix gyp Created 6 years, 7 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 | Annotate | Revision Log
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
1 // Copyright (c) 2012 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 "pdf/out_of_process_instance.h"
6
7 #include <algorithm> // for min/max()
8 #define _USE_MATH_DEFINES // for M_PI
9 #include <cmath> // for log() and pow()
10 #include <math.h>
11 #include <list>
12
13 #include "base/json/json_reader.h"
14 #include "base/json/json_writer.h"
15 #include "base/logging.h"
16 #include "base/strings/string_number_conversions.h"
17 #include "base/strings/string_split.h"
18 #include "base/strings/string_util.h"
19 #include "base/values.h"
20 #include "chrome/common/content_restriction.h"
21 #include "net/base/escape.h"
22 #include "pdf/draw_utils.h"
23 #include "pdf/pdf.h"
24 #include "ppapi/c/dev/ppb_cursor_control_dev.h"
25 #include "ppapi/c/pp_errors.h"
26 #include "ppapi/c/pp_rect.h"
27 #include "ppapi/c/private/ppp_pdf.h"
28 #include "ppapi/c/trusted/ppb_url_loader_trusted.h"
29 #include "ppapi/cpp/core.h"
30 #include "ppapi/cpp/dev/memory_dev.h"
31 #include "ppapi/cpp/dev/text_input_dev.h"
32 #include "ppapi/cpp/dev/url_util_dev.h"
33 #include "ppapi/cpp/module.h"
34 #include "ppapi/cpp/point.h"
35 #include "ppapi/cpp/private/pdf.h"
36 #include "ppapi/cpp/rect.h"
37 #include "ppapi/cpp/resource.h"
38 #include "ppapi/cpp/url_request_info.h"
39 #include "ppapi/cpp/var_array.h"
40 #include "ppapi/cpp/var_dictionary.h"
41 #include "ui/events/keycodes/keyboard_codes.h"
42
43 #if defined(OS_MACOSX)
44 #include "base/mac/mac_util.h"
45 #endif
46
47 namespace chrome_pdf {
48
49 // URL reference parameters.
50 // For more possible parameters, see RFC 3778 and the "PDF Open Parameters"
51 // document from Adobe.
52 const char kDelimiters[] = "#&";
53 const char kNamedDest[] = "nameddest";
54 const char kPage[] = "page";
55
56 const char kChromePrint[] = "chrome://print/";
57 const char kChromeExtension[] =
58 "chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai";
59
60 // Dictionary Value key names for the document accessibility info
61 const char kAccessibleNumberOfPages[] = "numberOfPages";
62 const char kAccessibleLoaded[] = "loaded";
63 const char kAccessibleCopyable[] = "copyable";
64
65 // Constants used in handling postMessage() messages.
66 const char* kType = "type";
67 // Viewport message arguments. (Page -> Plugin).
68 const char* kJSViewportType = "viewport";
69 const char* kJSXOffset = "xOffset";
70 const char* kJSYOffset = "yOffset";
71 const char* kJSZoom = "zoom";
72 // Document dimension arguments (Plugin -> Page).
73 const char* kJSDocumentDimensionsType = "documentDimensions";
74 const char* kJSDocumentWidth = "width";
75 const char* kJSDocumentHeight = "height";
76 const char* kJSPageDimensions = "pageDimensions";
77 const char* kJSPageX = "x";
78 const char* kJSPageY = "y";
79 const char* kJSPageWidth = "width";
80 const char* kJSPageHeight = "height";
81 // Document load progress arguments (Plugin -> Page)
82 const char* kJSLoadProgressType = "loadProgress";
83 const char* kJSProgressPercentage = "progress";
84 // Get password arguments (Plugin -> Page)
85 const char* kJSGetPasswordType = "getPassword";
86 // Get password complete arguments (Page -> Plugin)
87 const char* kJSGetPasswordCompleteType = "getPasswordComplete";
88 const char* kJSPassword = "password";
89 // Print (Page -> Plugin)
90 const char* kJSPrintType = "print";
91 // Go to page (Plugin -> Page)
92 const char* kJSGoToPageType = "goToPage";
93 const char* kJSPageNumber = "page";
94 // Reset print preview mode (Page -> Plugin)
95 const char* kJSResetPrintPreviewModeType = "resetPrintPreviewMode";
96 const char* kJSPrintPreviewUrl = "url";
97 const char* kJSPrintPreviewGrayscale = "grayscale";
98 const char* kJSPrintPreviewPageCount = "pageCount";
99 // Load preview page (Page -> Plugin)
100 const char* kJSLoadPreviewPageType = "loadPreviewPage";
101 const char* kJSPreviewPageUrl = "url";
102 const char* kJSPreviewPageIndex = "index";
103 // Set scroll position (Plugin -> Page)
104 const char* kJSSetScrollPositionType = "setScrollPosition";
105 const char* kJSPositionX = "x";
106 const char* kJSPositionY = "y";
107 // Set translated strings (Plugin -> Page)
108 const char* kJSSetTranslatedStringsType = "setTranslatedStrings";
109 const char* kJSGetPasswordString = "getPasswordString";
110 const char* kJSLoadingString = "loadingString";
111 const char* kJSLoadFailedString = "loadFailedString";
112 // Request accessibility JSON data (Page -> Plugin)
113 const char* kJSGetAccessibilityJSONType = "getAccessibilityJSON";
114 const char* kJSAccessibilityPageNumber = "page";
115 // Reply with accessibility JSON data (Plugin -> Page)
116 const char* kJSGetAccessibilityJSONReplyType = "getAccessibilityJSONReply";
117 const char* kJSAccessibilityJSON = "json";
118 // Cancel the stream URL request (Plugin -> Page)
119 const char* kJSCancelStreamUrlType = "cancelStreamUrl";
120
121 const int kFindResultCooldownMs = 100;
122
123 const double kMinZoom = 0.01;
124
125 namespace {
126
127 static const char kPPPPdfInterface[] = PPP_PDF_INTERFACE_1;
128
129 PP_Var GetLinkAtPosition(PP_Instance instance, PP_Point point) {
130 pp::Var var;
131 void* object = pp::Instance::GetPerInstanceObject(instance, kPPPPdfInterface);
132 if (object) {
133 var = static_cast<OutOfProcessInstance*>(object)->GetLinkAtPosition(
134 pp::Point(point));
135 }
136 return var.Detach();
137 }
138
139 void Transform(PP_Instance instance, PP_PrivatePageTransformType type) {
140 void* object =
141 pp::Instance::GetPerInstanceObject(instance, kPPPPdfInterface);
142 if (object) {
143 OutOfProcessInstance* obj_instance =
144 static_cast<OutOfProcessInstance*>(object);
145 switch (type) {
146 case PP_PRIVATEPAGETRANSFORMTYPE_ROTATE_90_CW:
147 obj_instance->RotateClockwise();
148 break;
149 case PP_PRIVATEPAGETRANSFORMTYPE_ROTATE_90_CCW:
150 obj_instance->RotateCounterclockwise();
151 break;
152 }
153 }
154 }
155
156 const PPP_Pdf ppp_private = {
157 &GetLinkAtPosition,
158 &Transform
159 };
160
161 int ExtractPrintPreviewPageIndex(const std::string& src_url) {
162 // Sample |src_url| format: chrome://print/id/page_index/print.pdf
163 std::vector<std::string> url_substr;
164 base::SplitString(src_url.substr(strlen(kChromePrint)), '/', &url_substr);
165 if (url_substr.size() != 3)
166 return -1;
167
168 if (url_substr[2] != "print.pdf")
169 return -1;
170
171 int page_index = 0;
172 if (!base::StringToInt(url_substr[1], &page_index))
173 return -1;
174 return page_index;
175 }
176
177 bool IsPrintPreviewUrl(const std::string& url) {
178 return url.substr(0, strlen(kChromePrint)) == kChromePrint;
179 }
180
181 void ScalePoint(float scale, pp::Point* point) {
182 point->set_x(static_cast<int>(point->x() * scale));
183 point->set_y(static_cast<int>(point->y() * scale));
184 }
185
186 void ScaleRect(float scale, pp::Rect* rect) {
187 int left = static_cast<int>(floorf(rect->x() * scale));
188 int top = static_cast<int>(floorf(rect->y() * scale));
189 int right = static_cast<int>(ceilf((rect->x() + rect->width()) * scale));
190 int bottom = static_cast<int>(ceilf((rect->y() + rect->height()) * scale));
191 rect->SetRect(left, top, right - left, bottom - top);
192 }
193
194 } // namespace
195
196 OutOfProcessInstance::OutOfProcessInstance(PP_Instance instance)
197 : pp::InstancePrivate(instance),
198 pp::Find_Private(this),
199 pp::Printing_Dev(this),
200 pp::Selection_Dev(this),
201 cursor_(PP_CURSORTYPE_POINTER),
202 zoom_(1.0),
203 device_scale_(1.0),
204 printing_enabled_(true),
205 full_(false),
206 paint_manager_(this, this, true),
207 first_paint_(true),
208 document_load_state_(LOAD_STATE_LOADING),
209 preview_document_load_state_(LOAD_STATE_COMPLETE),
210 uma_(this),
211 told_browser_about_unsupported_feature_(false),
212 print_preview_page_count_(0),
213 last_progress_sent_(0),
214 recently_sent_find_update_(false),
215 received_viewport_message_(false) {
216 loader_factory_.Initialize(this);
217 timer_factory_.Initialize(this);
218 form_factory_.Initialize(this);
219 print_callback_factory_.Initialize(this);
220 engine_.reset(PDFEngine::Create(this));
221 pp::Module::Get()->AddPluginInterface(kPPPPdfInterface, &ppp_private);
222 AddPerInstanceObject(kPPPPdfInterface, this);
223
224 RequestFilteringInputEvents(PP_INPUTEVENT_CLASS_MOUSE);
225 RequestFilteringInputEvents(PP_INPUTEVENT_CLASS_KEYBOARD);
226 RequestFilteringInputEvents(PP_INPUTEVENT_CLASS_TOUCH);
227 }
228
229 OutOfProcessInstance::~OutOfProcessInstance() {
230 RemovePerInstanceObject(kPPPPdfInterface, this);
231 }
232
233 bool OutOfProcessInstance::Init(uint32_t argc,
234 const char* argn[],
235 const char* argv[]) {
236 // Check if the PDF is being loaded in the PDF chrome extension. We only allow
237 // the plugin to be put into "full frame" mode when it is being loaded in the
238 // extension because this enables some features that we don't want pages
239 // abusing outside of the extension.
240 pp::Var document_url_var = pp::URLUtil_Dev::Get()->GetDocumentURL(this);
241 std::string document_url = document_url_var.is_string() ?
242 document_url_var.AsString() : std::string();
243 std::string extension_url = std::string(kChromeExtension);
244 bool in_extension =
245 !document_url.compare(0, extension_url.size(), extension_url);
246
247 if (in_extension) {
248 // Check if the plugin is full frame. This is passed in from JS.
249 for (uint32_t i = 0; i < argc; ++i) {
250 if (strcmp(argn[i], "full-frame") == 0) {
251 full_ = true;
252 break;
253 }
254 }
255 }
256
257 // Only allow the plugin to handle find requests if it is full frame.
258 if (full_)
259 SetPluginToHandleFindRequests();
260
261 // Send translated strings to the extension where they will be displayed.
262 // TODO(raymes): It would be better to get these in the extension directly
263 // through an API but no such API currently exists.
264 pp::VarDictionary translated_strings;
265 translated_strings.Set(kType, kJSSetTranslatedStringsType);
266 translated_strings.Set(kJSGetPasswordString,
267 GetLocalizedString(PP_RESOURCESTRING_PDFGETPASSWORD));
268 translated_strings.Set(kJSLoadingString,
269 GetLocalizedString(PP_RESOURCESTRING_PDFLOADING));
270 translated_strings.Set(kJSLoadFailedString,
271 GetLocalizedString(PP_RESOURCESTRING_PDFLOAD_FAILED));
272 PostMessage(translated_strings);
273
274 text_input_.reset(new pp::TextInput_Dev(this));
275
276 const char* stream_url = NULL;
277 const char* original_url = NULL;
278 const char* headers = NULL;
279 for (uint32_t i = 0; i < argc; ++i) {
280 if (strcmp(argn[i], "src") == 0)
281 original_url = argv[i];
282 else if (strcmp(argn[i], "stream-url") == 0)
283 stream_url = argv[i];
284 else if (strcmp(argn[i], "headers") == 0)
285 headers = argv[i];
286 }
287
288 if (!original_url)
289 return false;
290
291 if (!stream_url)
292 stream_url = original_url;
293
294 // If we're in print preview mode we don't need to load the document yet.
295 // A |kJSResetPrintPreviewModeType| message will be sent to the plugin letting
296 // it know the url to load. By not loading here we avoid loading the same
297 // document twice.
298 if (IsPrintPreviewUrl(original_url))
299 return true;
300
301 LoadUrl(stream_url);
302 url_ = original_url;
303 return engine_->New(original_url, headers);
304 }
305
306 void OutOfProcessInstance::HandleMessage(const pp::Var& message) {
307 pp::VarDictionary dict(message);
308 if (!dict.Get(kType).is_string()) {
309 NOTREACHED();
310 return;
311 }
312
313 std::string type = dict.Get(kType).AsString();
314
315 if (type == kJSViewportType &&
316 dict.Get(pp::Var(kJSXOffset)).is_int() &&
317 dict.Get(pp::Var(kJSYOffset)).is_int() &&
318 dict.Get(pp::Var(kJSZoom)).is_number()) {
319 received_viewport_message_ = true;
320 double zoom = dict.Get(pp::Var(kJSZoom)).AsDouble();
321 int x = dict.Get(pp::Var(kJSXOffset)).AsInt();
322 int y = dict.Get(pp::Var(kJSYOffset)).AsInt();
323
324 // Bound the input parameters.
325 zoom = std::max(kMinZoom, zoom);
326 int max_x = document_size_.width() * zoom - plugin_dip_size_.width();
327 x = std::max(std::min(x, max_x), 0);
328 int max_y = document_size_.height() * zoom - plugin_dip_size_.height();
329 y = std::max(std::min(y, max_y), 0);
330
331 SetZoom(zoom);
332 engine_->ScrolledToXPosition(x * device_scale_);
333 engine_->ScrolledToYPosition(y * device_scale_);
334 } else if (type == kJSGetPasswordCompleteType &&
335 dict.Get(pp::Var(kJSPassword)).is_string()) {
336 if (password_callback_) {
337 pp::CompletionCallbackWithOutput<pp::Var> callback = *password_callback_;
338 password_callback_.reset();
339 *callback.output() = dict.Get(pp::Var(kJSPassword)).pp_var();
340 callback.Run(PP_OK);
341 } else {
342 NOTREACHED();
343 }
344 } else if (type == kJSPrintType) {
345 Print();
346 } else if (type == kJSResetPrintPreviewModeType &&
347 dict.Get(pp::Var(kJSPrintPreviewUrl)).is_string() &&
348 dict.Get(pp::Var(kJSPrintPreviewGrayscale)).is_bool() &&
349 dict.Get(pp::Var(kJSPrintPreviewPageCount)).is_int()) {
350 url_ = dict.Get(pp::Var(kJSPrintPreviewUrl)).AsString();
351 preview_pages_info_ = std::queue<PreviewPageInfo>();
352 preview_document_load_state_ = LOAD_STATE_COMPLETE;
353 document_load_state_ = LOAD_STATE_LOADING;
354 LoadUrl(url_);
355 preview_engine_.reset();
356 engine_.reset(PDFEngine::Create(this));
357 engine_->SetGrayscale(dict.Get(pp::Var(kJSPrintPreviewGrayscale)).AsBool());
358 engine_->New(url_.c_str());
359
360 print_preview_page_count_ =
361 std::max(dict.Get(pp::Var(kJSPrintPreviewPageCount)).AsInt(), 0);
362
363 paint_manager_.InvalidateRect(pp::Rect(pp::Point(), plugin_size_));
364 } else if (type == kJSLoadPreviewPageType &&
365 dict.Get(pp::Var(kJSPreviewPageUrl)).is_string() &&
366 dict.Get(pp::Var(kJSPreviewPageIndex)).is_int()) {
367 ProcessPreviewPageInfo(dict.Get(pp::Var(kJSPreviewPageUrl)).AsString(),
368 dict.Get(pp::Var(kJSPreviewPageIndex)).AsInt());
369 } else if (type == kJSGetAccessibilityJSONType) {
370 pp::VarDictionary reply;
371 reply.Set(pp::Var(kType), pp::Var(kJSGetAccessibilityJSONReplyType));
372 if (dict.Get(pp::Var(kJSAccessibilityPageNumber)).is_int()) {
373 int page = pp::Var(kJSAccessibilityPageNumber).AsInt();
374 reply.Set(pp::Var(kJSAccessibilityJSON),
375 pp::Var(engine_->GetPageAsJSON(page)));
376 } else {
377 base::DictionaryValue node;
378 node.SetInteger(kAccessibleNumberOfPages, engine_->GetNumberOfPages());
379 node.SetBoolean(kAccessibleLoaded,
380 document_load_state_ != LOAD_STATE_LOADING);
381 bool has_permissions =
382 engine_->HasPermission(PDFEngine::PERMISSION_COPY) ||
383 engine_->HasPermission(PDFEngine::PERMISSION_COPY_ACCESSIBLE);
384 node.SetBoolean(kAccessibleCopyable, has_permissions);
385 std::string json;
386 base::JSONWriter::Write(&node, &json);
387 reply.Set(pp::Var(kJSAccessibilityJSON), pp::Var(json));
388 }
389 PostMessage(reply);
390 } else {
391 NOTREACHED();
392 }
393 }
394
395 bool OutOfProcessInstance::HandleInputEvent(
396 const pp::InputEvent& event) {
397 // To simplify things, convert the event into device coordinates if it is
398 // a mouse event.
399 pp::InputEvent event_device_res(event);
400 {
401 pp::MouseInputEvent mouse_event(event);
402 if (!mouse_event.is_null()) {
403 pp::Point point = mouse_event.GetPosition();
404 pp::Point movement = mouse_event.GetMovement();
405 ScalePoint(device_scale_, &point);
406 ScalePoint(device_scale_, &movement);
407 mouse_event = pp::MouseInputEvent(
408 this,
409 event.GetType(),
410 event.GetTimeStamp(),
411 event.GetModifiers(),
412 mouse_event.GetButton(),
413 point,
414 mouse_event.GetClickCount(),
415 movement);
416 event_device_res = mouse_event;
417 }
418 }
419
420 pp::InputEvent offset_event(event_device_res);
421 switch (offset_event.GetType()) {
422 case PP_INPUTEVENT_TYPE_MOUSEDOWN:
423 case PP_INPUTEVENT_TYPE_MOUSEUP:
424 case PP_INPUTEVENT_TYPE_MOUSEMOVE:
425 case PP_INPUTEVENT_TYPE_MOUSEENTER:
426 case PP_INPUTEVENT_TYPE_MOUSELEAVE: {
427 pp::MouseInputEvent mouse_event(event_device_res);
428 pp::MouseInputEvent mouse_event_dip(event);
429 pp::Point point = mouse_event.GetPosition();
430 point.set_x(point.x() - available_area_.x());
431 offset_event = pp::MouseInputEvent(
432 this,
433 event.GetType(),
434 event.GetTimeStamp(),
435 event.GetModifiers(),
436 mouse_event.GetButton(),
437 point,
438 mouse_event.GetClickCount(),
439 mouse_event.GetMovement());
440 break;
441 }
442 default:
443 break;
444 }
445 if (engine_->HandleEvent(offset_event))
446 return true;
447
448 // TODO(raymes): Implement this scroll behavior in JS:
449 // When click+dragging, scroll the document correctly.
450
451 if (event.GetType() == PP_INPUTEVENT_TYPE_KEYDOWN &&
452 event.GetModifiers() & kDefaultKeyModifier) {
453 pp::KeyboardInputEvent keyboard_event(event);
454 switch (keyboard_event.GetKeyCode()) {
455 case 'A':
456 engine_->SelectAll();
457 return true;
458 }
459 }
460
461 // Return true for unhandled clicks so the plugin takes focus.
462 return (event.GetType() == PP_INPUTEVENT_TYPE_MOUSEDOWN);
463 }
464
465 void OutOfProcessInstance::DidChangeView(const pp::View& view) {
466 pp::Rect view_rect(view.GetRect());
467 float old_device_scale = device_scale_;
468 float device_scale = view.GetDeviceScale();
469 pp::Size view_device_size(view_rect.width() * device_scale,
470 view_rect.height() * device_scale);
471
472 if (view_device_size == plugin_size_ && device_scale == device_scale_)
473 return; // We don't care about the position, only the size.
474
475 device_scale_ = device_scale;
476 plugin_dip_size_ = view_rect.size();
477 plugin_size_ = view_device_size;
478
479 paint_manager_.SetSize(view_device_size, device_scale_);
480
481 pp::Size new_image_data_size = PaintManager::GetNewContextSize(
482 image_data_.size(),
483 plugin_size_);
484 if (new_image_data_size != image_data_.size()) {
485 image_data_ = pp::ImageData(this,
486 PP_IMAGEDATAFORMAT_BGRA_PREMUL,
487 new_image_data_size,
488 false);
489 first_paint_ = true;
490 }
491
492 if (image_data_.is_null()) {
493 DCHECK(plugin_size_.IsEmpty());
494 return;
495 }
496
497 OnGeometryChanged(zoom_, old_device_scale);
498 }
499
500 pp::Var OutOfProcessInstance::GetInstanceObject() {
501 return pp::Var();
502 }
503
504 pp::Var OutOfProcessInstance::GetLinkAtPosition(
505 const pp::Point& point) {
506 pp::Point offset_point(point);
507 ScalePoint(device_scale_, &offset_point);
508 offset_point.set_x(offset_point.x() - available_area_.x());
509 return engine_->GetLinkAtPosition(offset_point);
510 }
511
512 pp::Var OutOfProcessInstance::GetSelectedText(bool html) {
513 if (html || !engine_->HasPermission(PDFEngine::PERMISSION_COPY))
514 return pp::Var();
515 return engine_->GetSelectedText();
516 }
517
518 uint32_t OutOfProcessInstance::QuerySupportedPrintOutputFormats() {
519 return engine_->QuerySupportedPrintOutputFormats();
520 }
521
522 int32_t OutOfProcessInstance::PrintBegin(
523 const PP_PrintSettings_Dev& print_settings) {
524 // For us num_pages is always equal to the number of pages in the PDF
525 // document irrespective of the printable area.
526 int32_t ret = engine_->GetNumberOfPages();
527 if (!ret)
528 return 0;
529
530 uint32_t supported_formats = engine_->QuerySupportedPrintOutputFormats();
531 if ((print_settings.format & supported_formats) == 0)
532 return 0;
533
534 print_settings_.is_printing = true;
535 print_settings_.pepper_print_settings = print_settings;
536 engine_->PrintBegin();
537 return ret;
538 }
539
540 pp::Resource OutOfProcessInstance::PrintPages(
541 const PP_PrintPageNumberRange_Dev* page_ranges,
542 uint32_t page_range_count) {
543 if (!print_settings_.is_printing)
544 return pp::Resource();
545
546 print_settings_.print_pages_called_ = true;
547 return engine_->PrintPages(page_ranges, page_range_count,
548 print_settings_.pepper_print_settings);
549 }
550
551 void OutOfProcessInstance::PrintEnd() {
552 if (print_settings_.print_pages_called_)
553 UserMetricsRecordAction("PDF.PrintPage");
554 print_settings_.Clear();
555 engine_->PrintEnd();
556 }
557
558 bool OutOfProcessInstance::IsPrintScalingDisabled() {
559 return !engine_->GetPrintScaling();
560 }
561
562 bool OutOfProcessInstance::StartFind(const std::string& text,
563 bool case_sensitive) {
564 engine_->StartFind(text.c_str(), case_sensitive);
565 return true;
566 }
567
568 void OutOfProcessInstance::SelectFindResult(bool forward) {
569 engine_->SelectFindResult(forward);
570 }
571
572 void OutOfProcessInstance::StopFind() {
573 engine_->StopFind();
574 tickmarks_.clear();
575 SetTickmarks(tickmarks_);
576 }
577
578 void OutOfProcessInstance::OnPaint(
579 const std::vector<pp::Rect>& paint_rects,
580 std::vector<PaintManager::ReadyRect>* ready,
581 std::vector<pp::Rect>* pending) {
582 if (image_data_.is_null()) {
583 DCHECK(plugin_size_.IsEmpty());
584 return;
585 }
586 if (first_paint_) {
587 first_paint_ = false;
588 pp::Rect rect = pp::Rect(pp::Point(), image_data_.size());
589 unsigned int color = kBackgroundColorA << 24 |
590 kBackgroundColorR << 16 |
591 kBackgroundColorG << 8 |
592 kBackgroundColorB;
593 FillRect(rect, color);
594 ready->push_back(PaintManager::ReadyRect(rect, image_data_, true));
595 }
596
597 if (!received_viewport_message_)
598 return;
599
600 engine_->PrePaint();
601
602 for (size_t i = 0; i < paint_rects.size(); i++) {
603 // Intersect with plugin area since there could be pending invalidates from
604 // when the plugin area was larger.
605 pp::Rect rect =
606 paint_rects[i].Intersect(pp::Rect(pp::Point(), plugin_size_));
607 if (rect.IsEmpty())
608 continue;
609
610 pp::Rect pdf_rect = available_area_.Intersect(rect);
611 if (!pdf_rect.IsEmpty()) {
612 pdf_rect.Offset(available_area_.x() * -1, 0);
613
614 std::vector<pp::Rect> pdf_ready;
615 std::vector<pp::Rect> pdf_pending;
616 engine_->Paint(pdf_rect, &image_data_, &pdf_ready, &pdf_pending);
617 for (size_t j = 0; j < pdf_ready.size(); ++j) {
618 pdf_ready[j].Offset(available_area_.point());
619 ready->push_back(
620 PaintManager::ReadyRect(pdf_ready[j], image_data_, false));
621 }
622 for (size_t j = 0; j < pdf_pending.size(); ++j) {
623 pdf_pending[j].Offset(available_area_.point());
624 pending->push_back(pdf_pending[j]);
625 }
626 }
627
628 for (size_t j = 0; j < background_parts_.size(); ++j) {
629 pp::Rect intersection = background_parts_[j].location.Intersect(rect);
630 if (!intersection.IsEmpty()) {
631 FillRect(intersection, background_parts_[j].color);
632 ready->push_back(
633 PaintManager::ReadyRect(intersection, image_data_, false));
634 }
635 }
636 }
637
638 engine_->PostPaint();
639 }
640
641 void OutOfProcessInstance::DidOpen(int32_t result) {
642 if (result == PP_OK) {
643 if (!engine_->HandleDocumentLoad(embed_loader_)) {
644 document_load_state_ = LOAD_STATE_LOADING;
645 DocumentLoadFailed();
646 }
647 } else if (result != PP_ERROR_ABORTED) { // Can happen in tests.
648 NOTREACHED();
649 DocumentLoadFailed();
650 }
651
652 // If it's a progressive load, cancel the stream URL request so that requests
653 // can be made on the original URL.
654 // TODO(raymes): Make this clearer once the in-process plugin is deleted.
655 if (engine_->IsProgressiveLoad()) {
656 pp::VarDictionary message;
657 message.Set(kType, kJSCancelStreamUrlType);
658 PostMessage(message);
659 }
660 }
661
662 void OutOfProcessInstance::DidOpenPreview(int32_t result) {
663 if (result == PP_OK) {
664 preview_engine_.reset(PDFEngine::Create(new PreviewModeClient(this)));
665 preview_engine_->HandleDocumentLoad(embed_preview_loader_);
666 } else {
667 NOTREACHED();
668 }
669 }
670
671 void OutOfProcessInstance::OnClientTimerFired(int32_t id) {
672 engine_->OnCallback(id);
673 }
674
675 void OutOfProcessInstance::CalculateBackgroundParts() {
676 background_parts_.clear();
677 int left_width = available_area_.x();
678 int right_start = available_area_.right();
679 int right_width = abs(plugin_size_.width() - available_area_.right());
680 int bottom = std::min(available_area_.bottom(), plugin_size_.height());
681
682 // Add the left, right, and bottom rectangles. Note: we assume only
683 // horizontal centering.
684 BackgroundPart part;
685 part.color = kBackgroundColorA << 24 |
686 kBackgroundColorR << 16 |
687 kBackgroundColorG << 8 |
688 kBackgroundColorB;
689 part.location = pp::Rect(0, 0, left_width, bottom);
690 if (!part.location.IsEmpty())
691 background_parts_.push_back(part);
692 part.location = pp::Rect(right_start, 0, right_width, bottom);
693 if (!part.location.IsEmpty())
694 background_parts_.push_back(part);
695 part.location = pp::Rect(
696 0, bottom, plugin_size_.width(), plugin_size_.height() - bottom);
697 if (!part.location.IsEmpty())
698 background_parts_.push_back(part);
699 }
700
701 int OutOfProcessInstance::GetDocumentPixelWidth() const {
702 return static_cast<int>(ceil(document_size_.width() * zoom_ * device_scale_));
703 }
704
705 int OutOfProcessInstance::GetDocumentPixelHeight() const {
706 return static_cast<int>(
707 ceil(document_size_.height() * zoom_ * device_scale_));
708 }
709
710 void OutOfProcessInstance::FillRect(const pp::Rect& rect, unsigned int color) {
711 DCHECK(!image_data_.is_null() || rect.IsEmpty());
712 unsigned int* buffer_start = static_cast<unsigned int*>(image_data_.data());
713 int stride = image_data_.stride();
714 unsigned int* ptr = buffer_start + rect.y() * stride / 4 + rect.x();
715 int height = rect.height();
716 int width = rect.width();
717 for (int y = 0; y < height; ++y) {
718 for (int x = 0; x < width; ++x)
719 *(ptr + x) = color;
720 ptr += stride /4;
721 }
722 }
723
724 void OutOfProcessInstance::DocumentSizeUpdated(const pp::Size& size) {
725 document_size_ = size;
726
727 pp::VarDictionary dimensions;
728 dimensions.Set(kType, kJSDocumentDimensionsType);
729 dimensions.Set(kJSDocumentWidth, pp::Var(document_size_.width()));
730 dimensions.Set(kJSDocumentHeight, pp::Var(document_size_.height()));
731 pp::VarArray page_dimensions_array;
732 int num_pages = engine_->GetNumberOfPages();
733 for (int i = 0; i < num_pages; ++i) {
734 pp::Rect page_rect = engine_->GetPageRect(i);
735 pp::VarDictionary page_dimensions;
736 page_dimensions.Set(kJSPageX, pp::Var(page_rect.x()));
737 page_dimensions.Set(kJSPageY, pp::Var(page_rect.y()));
738 page_dimensions.Set(kJSPageWidth, pp::Var(page_rect.width()));
739 page_dimensions.Set(kJSPageHeight, pp::Var(page_rect.height()));
740 page_dimensions_array.Set(i, page_dimensions);
741 }
742 dimensions.Set(kJSPageDimensions, page_dimensions_array);
743 PostMessage(dimensions);
744
745 OnGeometryChanged(zoom_, device_scale_);
746 }
747
748 void OutOfProcessInstance::Invalidate(const pp::Rect& rect) {
749 pp::Rect offset_rect(rect);
750 offset_rect.Offset(available_area_.point());
751 paint_manager_.InvalidateRect(offset_rect);
752 }
753
754 void OutOfProcessInstance::Scroll(const pp::Point& point) {
755 paint_manager_.ScrollRect(available_area_, point);
756 }
757
758 void OutOfProcessInstance::ScrollToX(int x) {
759 pp::VarDictionary position;
760 position.Set(kType, kJSSetScrollPositionType);
761 position.Set(kJSPositionX, pp::Var(x / device_scale_));
762 PostMessage(position);
763 }
764
765 void OutOfProcessInstance::ScrollToY(int y) {
766 pp::VarDictionary position;
767 position.Set(kType, kJSSetScrollPositionType);
768 position.Set(kJSPositionY, pp::Var(y / device_scale_));
769 PostMessage(position);
770 }
771
772 void OutOfProcessInstance::ScrollToPage(int page) {
773 if (engine_->GetNumberOfPages() == 0)
774 return;
775
776 pp::VarDictionary message;
777 message.Set(kType, kJSGoToPageType);
778 message.Set(kJSPageNumber, pp::Var(page));
779 PostMessage(message);
780 }
781
782 void OutOfProcessInstance::NavigateTo(const std::string& url,
783 bool open_in_new_tab) {
784 std::string url_copy(url);
785
786 // Empty |url_copy| is ok, and will effectively be a reload.
787 // Skip the code below so an empty URL does not turn into "http://", which
788 // will cause GURL to fail a DCHECK.
789 if (!url_copy.empty()) {
790 // If there's no scheme, add http.
791 if (url_copy.find("://") == std::string::npos &&
792 url_copy.find("mailto:") == std::string::npos) {
793 url_copy = std::string("http://") + url_copy;
794 }
795 // Make sure |url_copy| starts with a valid scheme.
796 if (url_copy.find("http://") != 0 &&
797 url_copy.find("https://") != 0 &&
798 url_copy.find("ftp://") != 0 &&
799 url_copy.find("mailto:") != 0) {
800 return;
801 }
802 // Make sure |url_copy| is not only a scheme.
803 if (url_copy == "http://" ||
804 url_copy == "https://" ||
805 url_copy == "ftp://" ||
806 url_copy == "mailto:") {
807 return;
808 }
809 }
810 if (open_in_new_tab) {
811 GetWindowObject().Call("open", url_copy);
812 } else {
813 GetWindowObject().GetProperty("top").GetProperty("location").
814 SetProperty("href", url_copy);
815 }
816 }
817
818 void OutOfProcessInstance::UpdateCursor(PP_CursorType_Dev cursor) {
819 if (cursor == cursor_)
820 return;
821 cursor_ = cursor;
822
823 const PPB_CursorControl_Dev* cursor_interface =
824 reinterpret_cast<const PPB_CursorControl_Dev*>(
825 pp::Module::Get()->GetBrowserInterface(PPB_CURSOR_CONTROL_DEV_INTERFACE));
826 if (!cursor_interface) {
827 NOTREACHED();
828 return;
829 }
830
831 cursor_interface->SetCursor(
832 pp_instance(), cursor_, pp::ImageData().pp_resource(), NULL);
833 }
834
835 void OutOfProcessInstance::UpdateTickMarks(
836 const std::vector<pp::Rect>& tickmarks) {
837 float inverse_scale = 1.0f / device_scale_;
838 std::vector<pp::Rect> scaled_tickmarks = tickmarks;
839 for (size_t i = 0; i < scaled_tickmarks.size(); i++)
840 ScaleRect(inverse_scale, &scaled_tickmarks[i]);
841 tickmarks_ = scaled_tickmarks;
842 }
843
844 void OutOfProcessInstance::NotifyNumberOfFindResultsChanged(int total,
845 bool final_result) {
846 // We don't want to spam the renderer with too many updates to the number of
847 // find results. Don't send an update if we sent one too recently. If it's the
848 // final update, we always send it though.
849 if (final_result) {
850 NumberOfFindResultsChanged(total, final_result);
851 SetTickmarks(tickmarks_);
852 return;
853 }
854
855 if (recently_sent_find_update_)
856 return;
857
858 NumberOfFindResultsChanged(total, final_result);
859 SetTickmarks(tickmarks_);
860 recently_sent_find_update_ = true;
861 pp::CompletionCallback callback =
862 timer_factory_.NewCallback(
863 &OutOfProcessInstance::ResetRecentlySentFindUpdate);
864 pp::Module::Get()->core()->CallOnMainThread(kFindResultCooldownMs,
865 callback, 0);
866 }
867
868 void OutOfProcessInstance::NotifySelectedFindResultChanged(
869 int current_find_index) {
870 SelectedFindResultChanged(current_find_index);
871 }
872
873 void OutOfProcessInstance::GetDocumentPassword(
874 pp::CompletionCallbackWithOutput<pp::Var> callback) {
875 if (password_callback_) {
876 NOTREACHED();
877 return;
878 }
879
880 password_callback_.reset(
881 new pp::CompletionCallbackWithOutput<pp::Var>(callback));
882 pp::VarDictionary message;
883 message.Set(pp::Var(kType), pp::Var(kJSGetPasswordType));
884 PostMessage(message);
885 }
886
887 void OutOfProcessInstance::Alert(const std::string& message) {
888 GetWindowObject().Call("alert", message);
889 }
890
891 bool OutOfProcessInstance::Confirm(const std::string& message) {
892 pp::Var result = GetWindowObject().Call("confirm", message);
893 return result.is_bool() ? result.AsBool() : false;
894 }
895
896 std::string OutOfProcessInstance::Prompt(const std::string& question,
897 const std::string& default_answer) {
898 pp::Var result = GetWindowObject().Call("prompt", question, default_answer);
899 return result.is_string() ? result.AsString() : std::string();
900 }
901
902 std::string OutOfProcessInstance::GetURL() {
903 return url_;
904 }
905
906 void OutOfProcessInstance::Email(const std::string& to,
907 const std::string& cc,
908 const std::string& bcc,
909 const std::string& subject,
910 const std::string& body) {
911 std::string javascript =
912 "var href = 'mailto:" + net::EscapeUrlEncodedData(to, false) +
913 "?cc=" + net::EscapeUrlEncodedData(cc, false) +
914 "&bcc=" + net::EscapeUrlEncodedData(bcc, false) +
915 "&subject=" + net::EscapeUrlEncodedData(subject, false) +
916 "&body=" + net::EscapeUrlEncodedData(body, false) +
917 "';var temp = window.open(href, '_blank', " +
918 "'width=1,height=1');if(temp) temp.close();";
919 ExecuteScript(javascript);
920 }
921
922 void OutOfProcessInstance::Print() {
923 if (!printing_enabled_ ||
924 (!engine_->HasPermission(PDFEngine::PERMISSION_PRINT_LOW_QUALITY) &&
925 !engine_->HasPermission(PDFEngine::PERMISSION_PRINT_HIGH_QUALITY))) {
926 return;
927 }
928
929 pp::CompletionCallback callback =
930 print_callback_factory_.NewCallback(&OutOfProcessInstance::OnPrint);
931 pp::Module::Get()->core()->CallOnMainThread(0, callback);
932 }
933
934 void OutOfProcessInstance::OnPrint(int32_t) {
935 pp::PDF::Print(this);
936 }
937
938 void OutOfProcessInstance::SubmitForm(const std::string& url,
939 const void* data,
940 int length) {
941 pp::URLRequestInfo request(this);
942 request.SetURL(url);
943 request.SetMethod("POST");
944 request.AppendDataToBody(reinterpret_cast<const char*>(data), length);
945
946 pp::CompletionCallback callback =
947 form_factory_.NewCallback(&OutOfProcessInstance::FormDidOpen);
948 form_loader_ = CreateURLLoaderInternal();
949 int rv = form_loader_.Open(request, callback);
950 if (rv != PP_OK_COMPLETIONPENDING)
951 callback.Run(rv);
952 }
953
954 void OutOfProcessInstance::FormDidOpen(int32_t result) {
955 // TODO: inform the user of success/failure.
956 if (result != PP_OK) {
957 NOTREACHED();
958 }
959 }
960
961 std::string OutOfProcessInstance::ShowFileSelectionDialog() {
962 // Seems like very low priority to implement, since the pdf has no way to get
963 // the file data anyways. Javascript doesn't let you do this synchronously.
964 NOTREACHED();
965 return std::string();
966 }
967
968 pp::URLLoader OutOfProcessInstance::CreateURLLoader() {
969 return CreateURLLoaderInternal();
970 }
971
972 void OutOfProcessInstance::ScheduleCallback(int id, int delay_in_ms) {
973 pp::CompletionCallback callback =
974 timer_factory_.NewCallback(&OutOfProcessInstance::OnClientTimerFired);
975 pp::Module::Get()->core()->CallOnMainThread(delay_in_ms, callback, id);
976 }
977
978 void OutOfProcessInstance::SearchString(const base::char16* string,
979 const base::char16* term,
980 bool case_sensitive,
981 std::vector<SearchStringResult>* results) {
982 PP_PrivateFindResult* pp_results;
983 int count = 0;
984 pp::PDF::SearchString(
985 this,
986 reinterpret_cast<const unsigned short*>(string),
987 reinterpret_cast<const unsigned short*>(term),
988 case_sensitive,
989 &pp_results,
990 &count);
991
992 results->resize(count);
993 for (int i = 0; i < count; ++i) {
994 (*results)[i].start_index = pp_results[i].start_index;
995 (*results)[i].length = pp_results[i].length;
996 }
997
998 pp::Memory_Dev memory;
999 memory.MemFree(pp_results);
1000 }
1001
1002 void OutOfProcessInstance::DocumentPaintOccurred() {
1003 }
1004
1005 void OutOfProcessInstance::DocumentLoadComplete(int page_count) {
1006 // Clear focus state for OSK.
1007 FormTextFieldFocusChange(false);
1008
1009 DCHECK(document_load_state_ == LOAD_STATE_LOADING);
1010 document_load_state_ = LOAD_STATE_COMPLETE;
1011 UserMetricsRecordAction("PDF.LoadSuccess");
1012
1013 // Note: If we are in print preview mode the scroll location is retained
1014 // across document loads so we don't want to scroll again and override it.
1015 if (!IsPrintPreview()) {
1016 int initial_page = GetInitialPage(url_);
1017 if (initial_page >= 0)
1018 ScrollToPage(initial_page);
1019 } else {
1020 AppendBlankPrintPreviewPages();
1021 OnGeometryChanged(0, 0);
1022 }
1023
1024 pp::VarDictionary message;
1025 message.Set(pp::Var(kType), pp::Var(kJSLoadProgressType));
1026 message.Set(pp::Var(kJSProgressPercentage), pp::Var(100)) ;
1027 PostMessage(message);
1028
1029 if (!full_)
1030 return;
1031
1032 pp::PDF::DidStopLoading(this);
1033
1034 int content_restrictions =
1035 CONTENT_RESTRICTION_CUT | CONTENT_RESTRICTION_PASTE;
1036 if (!engine_->HasPermission(PDFEngine::PERMISSION_COPY))
1037 content_restrictions |= CONTENT_RESTRICTION_COPY;
1038
1039 if (!engine_->HasPermission(PDFEngine::PERMISSION_PRINT_LOW_QUALITY) &&
1040 !engine_->HasPermission(PDFEngine::PERMISSION_PRINT_HIGH_QUALITY)) {
1041 printing_enabled_ = false;
1042 }
1043
1044 pp::PDF::SetContentRestriction(this, content_restrictions);
1045
1046 uma_.HistogramCustomCounts("PDF.PageCount", page_count,
1047 1, 1000000, 50);
1048 }
1049
1050 void OutOfProcessInstance::RotateClockwise() {
1051 engine_->RotateClockwise();
1052 }
1053
1054 void OutOfProcessInstance::RotateCounterclockwise() {
1055 engine_->RotateCounterclockwise();
1056 }
1057
1058 void OutOfProcessInstance::PreviewDocumentLoadComplete() {
1059 if (preview_document_load_state_ != LOAD_STATE_LOADING ||
1060 preview_pages_info_.empty()) {
1061 return;
1062 }
1063
1064 preview_document_load_state_ = LOAD_STATE_COMPLETE;
1065
1066 int dest_page_index = preview_pages_info_.front().second;
1067 int src_page_index =
1068 ExtractPrintPreviewPageIndex(preview_pages_info_.front().first);
1069 if (src_page_index > 0 && dest_page_index > -1 && preview_engine_.get())
1070 engine_->AppendPage(preview_engine_.get(), dest_page_index);
1071
1072 preview_pages_info_.pop();
1073 // |print_preview_page_count_| is not updated yet. Do not load any
1074 // other preview pages till we get this information.
1075 if (print_preview_page_count_ == 0)
1076 return;
1077
1078 if (preview_pages_info_.size())
1079 LoadAvailablePreviewPage();
1080 }
1081
1082 void OutOfProcessInstance::DocumentLoadFailed() {
1083 DCHECK(document_load_state_ == LOAD_STATE_LOADING);
1084 UserMetricsRecordAction("PDF.LoadFailure");
1085
1086 if (full_)
1087 pp::PDF::DidStopLoading(this);
1088 document_load_state_ = LOAD_STATE_FAILED;
1089
1090 paint_manager_.InvalidateRect(pp::Rect(pp::Point(), plugin_size_));
1091
1092 // Send a progress value of -1 to indicate a failure.
1093 pp::VarDictionary message;
1094 message.Set(pp::Var(kType), pp::Var(kJSLoadProgressType));
1095 message.Set(pp::Var(kJSProgressPercentage), pp::Var(-1)) ;
1096 PostMessage(message);
1097 }
1098
1099 void OutOfProcessInstance::PreviewDocumentLoadFailed() {
1100 UserMetricsRecordAction("PDF.PreviewDocumentLoadFailure");
1101 if (preview_document_load_state_ != LOAD_STATE_LOADING ||
1102 preview_pages_info_.empty()) {
1103 return;
1104 }
1105
1106 preview_document_load_state_ = LOAD_STATE_FAILED;
1107 preview_pages_info_.pop();
1108
1109 if (preview_pages_info_.size())
1110 LoadAvailablePreviewPage();
1111 }
1112
1113 pp::Instance* OutOfProcessInstance::GetPluginInstance() {
1114 return this;
1115 }
1116
1117 void OutOfProcessInstance::DocumentHasUnsupportedFeature(
1118 const std::string& feature) {
1119 std::string metric("PDF_Unsupported_");
1120 metric += feature;
1121 if (!unsupported_features_reported_.count(metric)) {
1122 unsupported_features_reported_.insert(metric);
1123 UserMetricsRecordAction(metric);
1124 }
1125
1126 // Since we use an info bar, only do this for full frame plugins..
1127 if (!full_)
1128 return;
1129
1130 if (told_browser_about_unsupported_feature_)
1131 return;
1132 told_browser_about_unsupported_feature_ = true;
1133
1134 pp::PDF::HasUnsupportedFeature(this);
1135 }
1136
1137 void OutOfProcessInstance::DocumentLoadProgress(uint32 available,
1138 uint32 doc_size) {
1139 double progress = 0.0;
1140 if (doc_size == 0) {
1141 // Document size is unknown. Use heuristics.
1142 // We'll make progress logarithmic from 0 to 100M.
1143 static const double kFactor = log(100000000.0) / 100.0;
1144 if (available > 0) {
1145 progress = log(static_cast<double>(available)) / kFactor;
1146 if (progress > 100.0)
1147 progress = 100.0;
1148 }
1149 } else {
1150 progress = 100.0 * static_cast<double>(available) / doc_size;
1151 }
1152
1153 // We send 100% load progress in DocumentLoadComplete.
1154 if (progress >= 100)
1155 return;
1156
1157 // Avoid sending too many progress messages over PostMessage.
1158 if (progress > last_progress_sent_ + 1) {
1159 last_progress_sent_ = progress;
1160 pp::VarDictionary message;
1161 message.Set(pp::Var(kType), pp::Var(kJSLoadProgressType));
1162 message.Set(pp::Var(kJSProgressPercentage), pp::Var(progress)) ;
1163 PostMessage(message);
1164 }
1165 }
1166
1167 void OutOfProcessInstance::FormTextFieldFocusChange(bool in_focus) {
1168 if (!text_input_.get())
1169 return;
1170 if (in_focus)
1171 text_input_->SetTextInputType(PP_TEXTINPUT_TYPE_DEV_TEXT);
1172 else
1173 text_input_->SetTextInputType(PP_TEXTINPUT_TYPE_DEV_NONE);
1174 }
1175
1176 void OutOfProcessInstance::ResetRecentlySentFindUpdate(int32_t /* unused */) {
1177 recently_sent_find_update_ = false;
1178 }
1179
1180 void OutOfProcessInstance::OnGeometryChanged(double old_zoom,
1181 float old_device_scale) {
1182 if (zoom_ != old_zoom || device_scale_ != old_device_scale)
1183 engine_->ZoomUpdated(zoom_ * device_scale_);
1184
1185 available_area_ = pp::Rect(plugin_size_);
1186 int doc_width = GetDocumentPixelWidth();
1187 if (doc_width < available_area_.width()) {
1188 available_area_.Offset((available_area_.width() - doc_width) / 2, 0);
1189 available_area_.set_width(doc_width);
1190 }
1191 int doc_height = GetDocumentPixelHeight();
1192 if (doc_height < available_area_.height()) {
1193 available_area_.set_height(doc_height);
1194 }
1195
1196 CalculateBackgroundParts();
1197 engine_->PageOffsetUpdated(available_area_.point());
1198 engine_->PluginSizeUpdated(available_area_.size());
1199
1200 if (!document_size_.GetArea())
1201 return;
1202 paint_manager_.InvalidateRect(pp::Rect(pp::Point(), plugin_size_));
1203 }
1204
1205 void OutOfProcessInstance::LoadUrl(const std::string& url) {
1206 LoadUrlInternal(url, &embed_loader_, &OutOfProcessInstance::DidOpen);
1207 }
1208
1209 void OutOfProcessInstance::LoadPreviewUrl(const std::string& url) {
1210 LoadUrlInternal(url, &embed_preview_loader_,
1211 &OutOfProcessInstance::DidOpenPreview);
1212 }
1213
1214 void OutOfProcessInstance::LoadUrlInternal(
1215 const std::string& url,
1216 pp::URLLoader* loader,
1217 void (OutOfProcessInstance::* method)(int32_t)) {
1218 pp::URLRequestInfo request(this);
1219 request.SetURL(url);
1220 request.SetMethod("GET");
1221
1222 *loader = CreateURLLoaderInternal();
1223 pp::CompletionCallback callback = loader_factory_.NewCallback(method);
1224 int rv = loader->Open(request, callback);
1225 if (rv != PP_OK_COMPLETIONPENDING)
1226 callback.Run(rv);
1227 }
1228
1229 pp::URLLoader OutOfProcessInstance::CreateURLLoaderInternal() {
1230 if (full_) {
1231 pp::PDF::DidStartLoading(this);
1232
1233 // Disable save and print until the document is fully loaded, since they
1234 // would generate an incomplete document. Need to do this each time we
1235 // call DidStartLoading since that resets the content restrictions.
1236 pp::PDF::SetContentRestriction(this, CONTENT_RESTRICTION_SAVE |
1237 CONTENT_RESTRICTION_PRINT);
1238 }
1239
1240 pp::URLLoader loader(this);
1241
1242 const PPB_URLLoaderTrusted* trusted_interface =
1243 reinterpret_cast<const PPB_URLLoaderTrusted*>(
1244 pp::Module::Get()->GetBrowserInterface(
1245 PPB_URLLOADERTRUSTED_INTERFACE));
1246 if (trusted_interface)
1247 trusted_interface->GrantUniversalAccess(loader.pp_resource());
1248 return loader;
1249 }
1250
1251 int OutOfProcessInstance::GetInitialPage(const std::string& url) {
1252 #if defined(OS_NACL)
1253 return -1;
1254 #else
1255 size_t found_idx = url.find('#');
1256 if (found_idx == std::string::npos)
1257 return -1;
1258
1259 const std::string& ref = url.substr(found_idx + 1);
1260 std::vector<std::string> fragments;
1261 Tokenize(ref, kDelimiters, &fragments);
1262
1263 // Page number to return, zero-based.
1264 int page = -1;
1265
1266 // Handle the case of http://foo.com/bar#NAMEDDEST. This is not explicitly
1267 // mentioned except by example in the Adobe "PDF Open Parameters" document.
1268 if ((fragments.size() == 1) && (fragments[0].find('=') == std::string::npos))
1269 return engine_->GetNamedDestinationPage(fragments[0]);
1270
1271 for (size_t i = 0; i < fragments.size(); ++i) {
1272 std::vector<std::string> key_value;
1273 base::SplitString(fragments[i], '=', &key_value);
1274 if (key_value.size() != 2)
1275 continue;
1276 const std::string& key = key_value[0];
1277 const std::string& value = key_value[1];
1278
1279 if (base::strcasecmp(kPage, key.c_str()) == 0) {
1280 // |page_value| is 1-based.
1281 int page_value = -1;
1282 if (base::StringToInt(value, &page_value) && page_value > 0)
1283 page = page_value - 1;
1284 continue;
1285 }
1286 if (base::strcasecmp(kNamedDest, key.c_str()) == 0) {
1287 // |page_value| is 0-based.
1288 int page_value = engine_->GetNamedDestinationPage(value);
1289 if (page_value >= 0)
1290 page = page_value;
1291 continue;
1292 }
1293 }
1294 return page;
1295 #endif
1296 }
1297
1298 void OutOfProcessInstance::SetZoom(double scale) {
1299 double old_zoom = zoom_;
1300 zoom_ = scale;
1301 OnGeometryChanged(old_zoom, device_scale_);
1302 }
1303
1304 std::string OutOfProcessInstance::GetLocalizedString(PP_ResourceString id) {
1305 pp::Var rv(pp::PDF::GetLocalizedString(this, id));
1306 if (!rv.is_string())
1307 return std::string();
1308
1309 return rv.AsString();
1310 }
1311
1312 void OutOfProcessInstance::AppendBlankPrintPreviewPages() {
1313 if (print_preview_page_count_ == 0)
1314 return;
1315 engine_->AppendBlankPages(print_preview_page_count_);
1316 if (preview_pages_info_.size() > 0)
1317 LoadAvailablePreviewPage();
1318 }
1319
1320 bool OutOfProcessInstance::IsPrintPreview() {
1321 return IsPrintPreviewUrl(url_);
1322 }
1323
1324 void OutOfProcessInstance::ProcessPreviewPageInfo(const std::string& url,
1325 int dst_page_index) {
1326 if (!IsPrintPreview())
1327 return;
1328
1329 int src_page_index = ExtractPrintPreviewPageIndex(url);
1330 if (src_page_index < 1)
1331 return;
1332
1333 preview_pages_info_.push(std::make_pair(url, dst_page_index));
1334 LoadAvailablePreviewPage();
1335 }
1336
1337 void OutOfProcessInstance::LoadAvailablePreviewPage() {
1338 if (preview_pages_info_.size() <= 0 ||
1339 document_load_state_ != LOAD_STATE_COMPLETE) {
1340 return;
1341 }
1342
1343 std::string url = preview_pages_info_.front().first;
1344 int dst_page_index = preview_pages_info_.front().second;
1345 int src_page_index = ExtractPrintPreviewPageIndex(url);
1346 if (src_page_index < 1 ||
1347 dst_page_index >= print_preview_page_count_ ||
1348 preview_document_load_state_ == LOAD_STATE_LOADING) {
1349 return;
1350 }
1351
1352 preview_document_load_state_ = LOAD_STATE_LOADING;
1353 LoadPreviewUrl(url);
1354 }
1355
1356 void OutOfProcessInstance::UserMetricsRecordAction(
1357 const std::string& action) {
1358 // TODO(raymes): Move this function to PPB_UMA_Private.
1359 pp::PDF::UserMetricsRecordAction(this, pp::Var(action));
1360 }
1361
1362 } // namespace chrome_pdf
OLDNEW
« no previous file with comments | « pdf/out_of_process_instance.h ('k') | pdf/page_indicator.h » ('j') | pdf/pdf.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698