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.
5 #include "pdf/pdfium/pdfium_engine.h"
9 #include "base/json/json_writer.h"
10 #include "base/logging.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/numerics/safe_conversions.h"
13 #include "base/stl_util.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/strings/string_piece.h"
16 #include "base/strings/string_util.h"
17 #include "base/strings/utf_string_conversions.h"
18 #include "base/values.h"
19 #include "pdf/draw_utils.h"
20 #include "pdf/pdfium/pdfium_api_string_buffer_adapter.h"
21 #include "pdf/pdfium/pdfium_mem_buffer_file_read.h"
22 #include "pdf/pdfium/pdfium_mem_buffer_file_write.h"
23 #include "ppapi/c/pp_errors.h"
24 #include "ppapi/c/pp_input_event.h"
25 #include "ppapi/c/ppb_core.h"
26 #include "ppapi/c/private/ppb_pdf.h"
27 #include "ppapi/cpp/dev/memory_dev.h"
28 #include "ppapi/cpp/input_event.h"
29 #include "ppapi/cpp/instance.h"
30 #include "ppapi/cpp/module.h"
31 #include "ppapi/cpp/private/pdf.h"
32 #include "ppapi/cpp/trusted/browser_font_trusted.h"
33 #include "ppapi/cpp/url_response_info.h"
34 #include "ppapi/cpp/var.h"
35 #include "ppapi/cpp/var_dictionary.h"
36 #include "printing/units.h"
37 #include "third_party/pdfium/fpdfsdk/include/fpdf_ext.h"
38 #include "third_party/pdfium/fpdfsdk/include/fpdf_flatten.h"
39 #include "third_party/pdfium/fpdfsdk/include/fpdf_searchex.h"
40 #include "third_party/pdfium/fpdfsdk/include/fpdf_sysfontinfo.h"
41 #include "third_party/pdfium/fpdfsdk/include/fpdf_transformpage.h"
42 #include "third_party/pdfium/fpdfsdk/include/fpdfedit.h"
43 #include "third_party/pdfium/fpdfsdk/include/fpdfppo.h"
44 #include "third_party/pdfium/fpdfsdk/include/fpdfsave.h"
45 #include "third_party/pdfium/fpdfsdk/include/pdfwindow/PDFWindow.h"
46 #include "third_party/pdfium/fpdfsdk/include/pdfwindow/PWL_FontMap.h"
47 #include "ui/events/keycodes/keyboard_codes.h"
49 using printing::ConvertUnit
;
50 using printing::ConvertUnitDouble
;
51 using printing::kPointsPerInch
;
52 using printing::kPixelsPerInch
;
54 namespace chrome_pdf
{
58 #define kPageShadowTop 3
59 #define kPageShadowBottom 7
60 #define kPageShadowLeft 5
61 #define kPageShadowRight 5
63 #define kPageSeparatorThickness 4
64 #define kHighlightColorR 153
65 #define kHighlightColorG 193
66 #define kHighlightColorB 218
68 const uint32 kPendingPageColor
= 0xFFEEEEEE;
70 #define kFormHighlightColor 0xFFE4DD
71 #define kFormHighlightAlpha 100
73 #define kMaxPasswordTries 3
76 // http://www.adobe.com/devnet/acrobat/pdfs/pdf_reference_1-7.pdf
77 #define kPDFPermissionPrintLowQualityMask 1 << 2
78 #define kPDFPermissionPrintHighQualityMask 1 << 11
79 #define kPDFPermissionCopyMask 1 << 4
80 #define kPDFPermissionCopyAccessibleMask 1 << 9
82 #define kLoadingTextVerticalOffset 50
84 // The maximum amount of time we'll spend doing a paint before we give back
85 // control of the thread.
86 #define kMaxProgressivePaintTimeMs 50
88 // The maximum amount of time we'll spend doing the first paint. This is less
89 // than the above to keep things smooth if the user is scrolling quickly. We
90 // try painting a little because with accelerated compositing, we get flushes
91 // only every 16 ms. If we were to wait until the next flush to paint the rest
92 // of the pdf, we would never get to draw the pdf and would only draw the
93 // scrollbars. This value is picked to give enough time for gpu related code to
94 // do its thing and still fit within the timelimit for 60Hz. For the
95 // non-composited case, this doesn't make things worse since we're still
96 // painting the scrollbars > 60 Hz.
97 #define kMaxInitialProgressivePaintTimeMs 10
106 std::vector
<uint32_t> GetPageNumbersFromPrintPageNumberRange(
107 const PP_PrintPageNumberRange_Dev
* page_ranges
,
108 uint32_t page_range_count
) {
109 std::vector
<uint32_t> page_numbers
;
110 for (uint32_t index
= 0; index
< page_range_count
; ++index
) {
111 for (uint32_t page_number
= page_ranges
[index
].first_page_number
;
112 page_number
<= page_ranges
[index
].last_page_number
; ++page_number
) {
113 page_numbers
.push_back(page_number
);
119 #if defined(OS_LINUX)
121 PP_Instance g_last_instance_id
;
123 struct PDFFontSubstitution
{
124 const char* pdf_name
;
130 PP_BrowserFont_Trusted_Weight
WeightToBrowserFontTrustedWeight(int weight
) {
131 static_assert(PP_BROWSERFONT_TRUSTED_WEIGHT_100
== 0,
132 "PP_BrowserFont_Trusted_Weight min");
133 static_assert(PP_BROWSERFONT_TRUSTED_WEIGHT_900
== 8,
134 "PP_BrowserFont_Trusted_Weight max");
135 const int kMinimumWeight
= 100;
136 const int kMaximumWeight
= 900;
137 int normalized_weight
=
138 std::min(std::max(weight
, kMinimumWeight
), kMaximumWeight
);
139 normalized_weight
= (normalized_weight
/ 100) - 1;
140 return static_cast<PP_BrowserFont_Trusted_Weight
>(normalized_weight
);
143 // This list is for CPWL_FontMap::GetDefaultFontByCharset().
144 // We pretend to have these font natively and let the browser (or underlying
145 // fontconfig) to pick the proper font on the system.
146 void EnumFonts(struct _FPDF_SYSFONTINFO
* sysfontinfo
, void* mapper
) {
147 FPDF_AddInstalledFont(mapper
, "Arial", FXFONT_DEFAULT_CHARSET
);
150 while (CPWL_FontMap::defaultTTFMap
[i
].charset
!= -1) {
151 FPDF_AddInstalledFont(mapper
,
152 CPWL_FontMap::defaultTTFMap
[i
].fontname
,
153 CPWL_FontMap::defaultTTFMap
[i
].charset
);
158 const PDFFontSubstitution PDFFontSubstitutions
[] = {
159 {"Courier", "Courier New", false, false},
160 {"Courier-Bold", "Courier New", true, false},
161 {"Courier-BoldOblique", "Courier New", true, true},
162 {"Courier-Oblique", "Courier New", false, true},
163 {"Helvetica", "Arial", false, false},
164 {"Helvetica-Bold", "Arial", true, false},
165 {"Helvetica-BoldOblique", "Arial", true, true},
166 {"Helvetica-Oblique", "Arial", false, true},
167 {"Times-Roman", "Times New Roman", false, false},
168 {"Times-Bold", "Times New Roman", true, false},
169 {"Times-BoldItalic", "Times New Roman", true, true},
170 {"Times-Italic", "Times New Roman", false, true},
172 // MS P?(Mincho|Gothic) are the most notable fonts in Japanese PDF files
173 // without embedding the glyphs. Sometimes the font names are encoded
174 // in Japanese Windows's locale (CP932/Shift_JIS) without space.
175 // Most Linux systems don't have the exact font, but for outsourcing
176 // fontconfig to find substitutable font in the system, we pass ASCII
178 {"MS-PGothic", "MS PGothic", false, false},
179 {"MS-Gothic", "MS Gothic", false, false},
180 {"MS-PMincho", "MS PMincho", false, false},
181 {"MS-Mincho", "MS Mincho", false, false},
182 // MS PGothic in Shift_JIS encoding.
183 {"\x82\x6C\x82\x72\x82\x6F\x83\x53\x83\x56\x83\x62\x83\x4E",
184 "MS PGothic", false, false},
185 // MS Gothic in Shift_JIS encoding.
186 {"\x82\x6C\x82\x72\x83\x53\x83\x56\x83\x62\x83\x4E",
187 "MS Gothic", false, false},
188 // MS PMincho in Shift_JIS encoding.
189 {"\x82\x6C\x82\x72\x82\x6F\x96\xBE\x92\xA9",
190 "MS PMincho", false, false},
191 // MS Mincho in Shift_JIS encoding.
192 {"\x82\x6C\x82\x72\x96\xBE\x92\xA9",
193 "MS Mincho", false, false},
196 void* MapFont(struct _FPDF_SYSFONTINFO
*, int weight
, int italic
,
197 int charset
, int pitch_family
, const char* face
, int* exact
) {
198 // Do not attempt to map fonts if pepper is not initialized (for privet local
200 // TODO(noamsml): Real font substitution (http://crbug.com/391978)
201 if (!pp::Module::Get())
204 pp::BrowserFontDescription description
;
206 // Pretend the system does not have the Symbol font to force a fallback to
207 // the built in Symbol font in CFX_FontMapper::FindSubstFont().
208 if (strcmp(face
, "Symbol") == 0)
211 if (pitch_family
& FXFONT_FF_FIXEDPITCH
) {
212 description
.set_family(PP_BROWSERFONT_TRUSTED_FAMILY_MONOSPACE
);
213 } else if (pitch_family
& FXFONT_FF_ROMAN
) {
214 description
.set_family(PP_BROWSERFONT_TRUSTED_FAMILY_SERIF
);
217 // Map from the standard PDF fonts to TrueType font names.
219 for (i
= 0; i
< arraysize(PDFFontSubstitutions
); ++i
) {
220 if (strcmp(face
, PDFFontSubstitutions
[i
].pdf_name
) == 0) {
221 description
.set_face(PDFFontSubstitutions
[i
].face
);
222 if (PDFFontSubstitutions
[i
].bold
)
223 description
.set_weight(PP_BROWSERFONT_TRUSTED_WEIGHT_BOLD
);
224 if (PDFFontSubstitutions
[i
].italic
)
225 description
.set_italic(true);
230 if (i
== arraysize(PDFFontSubstitutions
)) {
231 // TODO(kochi): Pass the face in UTF-8. If face is not encoded in UTF-8,
232 // convert to UTF-8 before passing.
233 description
.set_face(face
);
235 description
.set_weight(WeightToBrowserFontTrustedWeight(weight
));
236 description
.set_italic(italic
> 0);
239 if (!pp::PDF::IsAvailable()) {
244 PP_Resource font_resource
= pp::PDF::GetFontFileWithFallback(
245 pp::InstanceHandle(g_last_instance_id
),
246 &description
.pp_font_description(),
247 static_cast<PP_PrivateFontCharset
>(charset
));
248 long res_id
= font_resource
;
249 return reinterpret_cast<void*>(res_id
);
252 unsigned long GetFontData(struct _FPDF_SYSFONTINFO
*, void* font_id
,
253 unsigned int table
, unsigned char* buffer
,
254 unsigned long buf_size
) {
255 if (!pp::PDF::IsAvailable()) {
260 uint32_t size
= buf_size
;
261 long res_id
= reinterpret_cast<long>(font_id
);
262 if (!pp::PDF::GetFontTableForPrivateFontFile(res_id
, table
, buffer
, &size
))
267 void DeleteFont(struct _FPDF_SYSFONTINFO
*, void* font_id
) {
268 long res_id
= reinterpret_cast<long>(font_id
);
269 pp::Module::Get()->core()->ReleaseResource(res_id
);
272 FPDF_SYSFONTINFO g_font_info
= {
283 #endif // defined(OS_LINUX)
285 PDFiumEngine
* g_engine_for_unsupported
;
287 void Unsupported_Handler(UNSUPPORT_INFO
*, int type
) {
288 if (!g_engine_for_unsupported
) {
293 g_engine_for_unsupported
->UnsupportedFeature(type
);
296 UNSUPPORT_INFO g_unsuppored_info
= {
301 // Set the destination page size and content area in points based on source
302 // page rotation and orientation.
304 // |rotated| True if source page is rotated 90 degree or 270 degree.
305 // |is_src_page_landscape| is true if the source page orientation is landscape.
306 // |page_size| has the actual destination page size in points.
307 // |content_rect| has the actual destination page printable area values in
309 void SetPageSizeAndContentRect(bool rotated
,
310 bool is_src_page_landscape
,
312 pp::Rect
* content_rect
) {
313 bool is_dst_page_landscape
= page_size
->width() > page_size
->height();
314 bool page_orientation_mismatched
= is_src_page_landscape
!=
315 is_dst_page_landscape
;
316 bool rotate_dst_page
= rotated
^ page_orientation_mismatched
;
317 if (rotate_dst_page
) {
318 page_size
->SetSize(page_size
->height(), page_size
->width());
319 content_rect
->SetRect(content_rect
->y(), content_rect
->x(),
320 content_rect
->height(), content_rect
->width());
324 // Calculate the scale factor between |content_rect| and a page of size
325 // |src_width| x |src_height|.
327 // |scale_to_fit| is true, if we need to calculate the scale factor.
328 // |content_rect| specifies the printable area of the destination page, with
329 // origin at left-bottom. Values are in points.
330 // |src_width| specifies the source page width in points.
331 // |src_height| specifies the source page height in points.
332 // |rotated| True if source page is rotated 90 degree or 270 degree.
333 double CalculateScaleFactor(bool scale_to_fit
,
334 const pp::Rect
& content_rect
,
335 double src_width
, double src_height
, bool rotated
) {
336 if (!scale_to_fit
|| src_width
== 0 || src_height
== 0)
339 double actual_source_page_width
= rotated
? src_height
: src_width
;
340 double actual_source_page_height
= rotated
? src_width
: src_height
;
341 double ratio_x
= static_cast<double>(content_rect
.width()) /
342 actual_source_page_width
;
343 double ratio_y
= static_cast<double>(content_rect
.height()) /
344 actual_source_page_height
;
345 return std::min(ratio_x
, ratio_y
);
348 // Compute source clip box boundaries based on the crop box / media box of
349 // source page and scale factor.
351 // |page| Handle to the source page. Returned by FPDF_LoadPage function.
352 // |scale_factor| specifies the scale factor that should be applied to source
353 // clip box boundaries.
354 // |rotated| True if source page is rotated 90 degree or 270 degree.
355 // |clip_box| out param to hold the computed source clip box values.
356 void CalculateClipBoxBoundary(FPDF_PAGE page
, double scale_factor
, bool rotated
,
358 if (!FPDFPage_GetCropBox(page
, &clip_box
->left
, &clip_box
->bottom
,
359 &clip_box
->right
, &clip_box
->top
)) {
360 if (!FPDFPage_GetMediaBox(page
, &clip_box
->left
, &clip_box
->bottom
,
361 &clip_box
->right
, &clip_box
->top
)) {
362 // Make the default size to be letter size (8.5" X 11"). We are just
363 // following the PDFium way of handling these corner cases. PDFium always
364 // consider US-Letter as the default page size.
365 float paper_width
= 612;
366 float paper_height
= 792;
368 clip_box
->bottom
= 0;
369 clip_box
->right
= rotated
? paper_height
: paper_width
;
370 clip_box
->top
= rotated
? paper_width
: paper_height
;
373 clip_box
->left
*= scale_factor
;
374 clip_box
->right
*= scale_factor
;
375 clip_box
->bottom
*= scale_factor
;
376 clip_box
->top
*= scale_factor
;
379 // Calculate the clip box translation offset for a page that does need to be
380 // scaled. All parameters are in points.
382 // |content_rect| specifies the printable area of the destination page, with
383 // origin at left-bottom.
384 // |source_clip_box| specifies the source clip box positions, relative to
385 // origin at left-bottom.
386 // |offset_x| and |offset_y| will contain the final translation offsets for the
387 // source clip box, relative to origin at left-bottom.
388 void CalculateScaledClipBoxOffset(const pp::Rect
& content_rect
,
389 const ClipBox
& source_clip_box
,
390 double* offset_x
, double* offset_y
) {
391 const float clip_box_width
= source_clip_box
.right
- source_clip_box
.left
;
392 const float clip_box_height
= source_clip_box
.top
- source_clip_box
.bottom
;
394 // Center the intended clip region to real clip region.
395 *offset_x
= (content_rect
.width() - clip_box_width
) / 2 + content_rect
.x() -
396 source_clip_box
.left
;
397 *offset_y
= (content_rect
.height() - clip_box_height
) / 2 + content_rect
.y() -
398 source_clip_box
.bottom
;
401 // Calculate the clip box offset for a page that does not need to be scaled.
402 // All parameters are in points.
404 // |content_rect| specifies the printable area of the destination page, with
405 // origin at left-bottom.
406 // |rotation| specifies the source page rotation values which are N / 90
408 // |page_width| specifies the screen destination page width.
409 // |page_height| specifies the screen destination page height.
410 // |source_clip_box| specifies the source clip box positions, relative to origin
412 // |offset_x| and |offset_y| will contain the final translation offsets for the
413 // source clip box, relative to origin at left-bottom.
414 void CalculateNonScaledClipBoxOffset(const pp::Rect
& content_rect
, int rotation
,
415 int page_width
, int page_height
,
416 const ClipBox
& source_clip_box
,
417 double* offset_x
, double* offset_y
) {
418 // Align the intended clip region to left-top corner of real clip region.
421 *offset_x
= -1 * source_clip_box
.left
;
422 *offset_y
= page_height
- source_clip_box
.top
;
426 *offset_y
= -1 * source_clip_box
.bottom
;
429 *offset_x
= page_width
- source_clip_box
.right
;
433 *offset_x
= page_height
- source_clip_box
.right
;
434 *offset_y
= page_width
- source_clip_box
.top
;
442 // This formats a string with special 0xfffe end-of-line hyphens the same way
443 // as Adobe Reader. When a hyphen is encountered, the next non-CR/LF whitespace
444 // becomes CR+LF and the hyphen is erased. If there is no whitespace between
445 // two hyphens, the latter hyphen is erased and ignored.
446 void FormatStringWithHyphens(base::string16
* text
) {
447 // First pass marks all the hyphen positions.
448 struct HyphenPosition
{
449 HyphenPosition() : position(0), next_whitespace_position(0) {}
451 size_t next_whitespace_position
; // 0 for none
453 std::vector
<HyphenPosition
> hyphen_positions
;
454 HyphenPosition current_hyphen_position
;
455 bool current_hyphen_position_is_valid
= false;
456 const base::char16 kPdfiumHyphenEOL
= 0xfffe;
458 for (size_t i
= 0; i
< text
->size(); ++i
) {
459 const base::char16
& current_char
= (*text
)[i
];
460 if (current_char
== kPdfiumHyphenEOL
) {
461 if (current_hyphen_position_is_valid
)
462 hyphen_positions
.push_back(current_hyphen_position
);
463 current_hyphen_position
= HyphenPosition();
464 current_hyphen_position
.position
= i
;
465 current_hyphen_position_is_valid
= true;
466 } else if (IsWhitespace(current_char
)) {
467 if (current_hyphen_position_is_valid
) {
468 if (current_char
!= L
'\r' && current_char
!= L
'\n')
469 current_hyphen_position
.next_whitespace_position
= i
;
470 hyphen_positions
.push_back(current_hyphen_position
);
471 current_hyphen_position_is_valid
= false;
475 if (current_hyphen_position_is_valid
)
476 hyphen_positions
.push_back(current_hyphen_position
);
478 // With all the hyphen positions, do the search and replace.
479 while (!hyphen_positions
.empty()) {
480 static const base::char16 kCr
[] = {L
'\r', L
'\0'};
481 const HyphenPosition
& position
= hyphen_positions
.back();
482 if (position
.next_whitespace_position
!= 0) {
483 (*text
)[position
.next_whitespace_position
] = L
'\n';
484 text
->insert(position
.next_whitespace_position
, kCr
);
486 text
->erase(position
.position
, 1);
487 hyphen_positions
.pop_back();
490 // Adobe Reader also get rid of trailing spaces right before a CRLF.
491 static const base::char16 kSpaceCrCn
[] = {L
' ', L
'\r', L
'\n', L
'\0'};
492 static const base::char16 kCrCn
[] = {L
'\r', L
'\n', L
'\0'};
493 ReplaceSubstringsAfterOffset(text
, 0, kSpaceCrCn
, kCrCn
);
496 // Replace CR/LF with just LF on POSIX.
497 void FormatStringForOS(base::string16
* text
) {
498 #if defined(OS_POSIX)
499 static const base::char16 kCr
[] = {L
'\r', L
'\0'};
500 static const base::char16 kBlank
[] = {L
'\0'};
501 base::ReplaceChars(*text
, kCr
, kBlank
, text
);
502 #elif defined(OS_WIN)
509 // Returns a VarDictionary (representing a bookmark), which in turn contains
510 // child VarDictionaries (representing the child bookmarks).
511 // If NULL is passed in as the bookmark then we traverse from the "root".
512 // Note that the "root" bookmark contains no useful information.
513 pp::VarDictionary
TraverseBookmarks(FPDF_DOCUMENT doc
, FPDF_BOOKMARK bookmark
) {
514 pp::VarDictionary dict
;
515 base::string16 title
;
516 unsigned long buffer_size
= FPDFBookmark_GetTitle(bookmark
, NULL
, 0);
517 size_t title_length
= base::checked_cast
<size_t>(buffer_size
) /
518 sizeof(base::string16::value_type
);
519 if (title_length
> 0) {
520 PDFiumAPIStringBufferAdapter
<base::string16
> api_string_adapter(
521 &title
, title_length
, true);
522 void* data
= api_string_adapter
.GetData();
523 FPDFBookmark_GetTitle(bookmark
, data
, buffer_size
);
524 api_string_adapter
.Close(title_length
);
526 dict
.Set(pp::Var("title"), pp::Var(base::UTF16ToUTF8(title
)));
528 FPDF_DEST dest
= FPDFBookmark_GetDest(doc
, bookmark
);
529 // Some bookmarks don't have a page to select.
531 int page_index
= FPDFDest_GetPageIndex(doc
, dest
);
532 dict
.Set(pp::Var("page"), pp::Var(page_index
));
535 pp::VarArray children
;
537 for (FPDF_BOOKMARK child_bookmark
= FPDFBookmark_GetFirstChild(doc
, bookmark
);
538 child_bookmark
!= NULL
;
539 child_bookmark
= FPDFBookmark_GetNextSibling(doc
, child_bookmark
)) {
540 children
.Set(child_index
, TraverseBookmarks(doc
, child_bookmark
));
543 dict
.Set(pp::Var("children"), children
);
549 bool InitializeSDK() {
552 #if defined(OS_LINUX)
553 // Font loading doesn't work in the renderer sandbox in Linux.
554 FPDF_SetSystemFontInfo(&g_font_info
);
557 FSDK_SetUnSpObjProcessHandler(&g_unsuppored_info
);
563 FPDF_DestroyLibrary();
566 PDFEngine
* PDFEngine::Create(PDFEngine::Client
* client
) {
567 return new PDFiumEngine(client
);
570 PDFiumEngine::PDFiumEngine(PDFEngine::Client
* client
)
573 current_rotation_(0),
575 password_tries_remaining_(0),
578 defer_page_unload_(false),
580 mouse_down_state_(PDFiumPage::NONSELECTABLE_AREA
,
581 PDFiumPage::LinkTarget()),
582 next_page_to_search_(-1),
583 last_page_to_search_(-1),
584 last_character_index_to_search_(-1),
586 fpdf_availability_(NULL
),
588 last_page_mouse_down_(-1),
589 first_visible_page_(-1),
590 most_visible_page_(-1),
591 called_do_document_action_(false),
592 render_grayscale_(false),
593 progressive_paint_timeout_(0),
594 getting_password_(false) {
595 find_factory_
.Initialize(this);
596 password_factory_
.Initialize(this);
598 file_access_
.m_FileLen
= 0;
599 file_access_
.m_GetBlock
= &GetBlock
;
600 file_access_
.m_Param
= &doc_loader_
;
602 file_availability_
.version
= 1;
603 file_availability_
.IsDataAvail
= &IsDataAvail
;
604 file_availability_
.loader
= &doc_loader_
;
606 download_hints_
.version
= 1;
607 download_hints_
.AddSegment
= &AddSegment
;
608 download_hints_
.loader
= &doc_loader_
;
610 // Initialize FPDF_FORMFILLINFO member variables. Deriving from this struct
611 // allows the static callbacks to be able to cast the FPDF_FORMFILLINFO in
612 // callbacks to ourself instead of maintaining a map of them to
614 FPDF_FORMFILLINFO::version
= 1;
615 FPDF_FORMFILLINFO::m_pJsPlatform
= this;
616 FPDF_FORMFILLINFO::Release
= NULL
;
617 FPDF_FORMFILLINFO::FFI_Invalidate
= Form_Invalidate
;
618 FPDF_FORMFILLINFO::FFI_OutputSelectedRect
= Form_OutputSelectedRect
;
619 FPDF_FORMFILLINFO::FFI_SetCursor
= Form_SetCursor
;
620 FPDF_FORMFILLINFO::FFI_SetTimer
= Form_SetTimer
;
621 FPDF_FORMFILLINFO::FFI_KillTimer
= Form_KillTimer
;
622 FPDF_FORMFILLINFO::FFI_GetLocalTime
= Form_GetLocalTime
;
623 FPDF_FORMFILLINFO::FFI_OnChange
= Form_OnChange
;
624 FPDF_FORMFILLINFO::FFI_GetPage
= Form_GetPage
;
625 FPDF_FORMFILLINFO::FFI_GetCurrentPage
= Form_GetCurrentPage
;
626 FPDF_FORMFILLINFO::FFI_GetRotation
= Form_GetRotation
;
627 FPDF_FORMFILLINFO::FFI_ExecuteNamedAction
= Form_ExecuteNamedAction
;
628 FPDF_FORMFILLINFO::FFI_SetTextFieldFocus
= Form_SetTextFieldFocus
;
629 FPDF_FORMFILLINFO::FFI_DoURIAction
= Form_DoURIAction
;
630 FPDF_FORMFILLINFO::FFI_DoGoToAction
= Form_DoGoToAction
;
632 FPDF_FORMFILLINFO::version
= 2;
633 FPDF_FORMFILLINFO::FFI_EmailTo
= Form_EmailTo
;
634 FPDF_FORMFILLINFO::FFI_DisplayCaret
= Form_DisplayCaret
;
635 FPDF_FORMFILLINFO::FFI_SetCurrentPage
= Form_SetCurrentPage
;
636 FPDF_FORMFILLINFO::FFI_GetCurrentPageIndex
= Form_GetCurrentPageIndex
;
637 FPDF_FORMFILLINFO::FFI_GetPageViewRect
= Form_GetPageViewRect
;
638 FPDF_FORMFILLINFO::FFI_GetPlatform
= Form_GetPlatform
;
639 FPDF_FORMFILLINFO::FFI_PopupMenu
= Form_PopupMenu
;
640 FPDF_FORMFILLINFO::FFI_PostRequestURL
= Form_PostRequestURL
;
641 FPDF_FORMFILLINFO::FFI_PutRequestURL
= Form_PutRequestURL
;
642 FPDF_FORMFILLINFO::FFI_UploadTo
= Form_UploadTo
;
643 FPDF_FORMFILLINFO::FFI_DownloadFromURL
= Form_DownloadFromURL
;
644 FPDF_FORMFILLINFO::FFI_OpenFile
= Form_OpenFile
;
645 FPDF_FORMFILLINFO::FFI_GotoURL
= Form_GotoURL
;
646 FPDF_FORMFILLINFO::FFI_GetLanguage
= Form_GetLanguage
;
647 #endif // PDF_USE_XFA
648 IPDF_JSPLATFORM::version
= 1;
649 IPDF_JSPLATFORM::app_alert
= Form_Alert
;
650 IPDF_JSPLATFORM::app_beep
= Form_Beep
;
651 IPDF_JSPLATFORM::app_response
= Form_Response
;
652 IPDF_JSPLATFORM::Doc_getFilePath
= Form_GetFilePath
;
653 IPDF_JSPLATFORM::Doc_mail
= Form_Mail
;
654 IPDF_JSPLATFORM::Doc_print
= Form_Print
;
655 IPDF_JSPLATFORM::Doc_submitForm
= Form_SubmitForm
;
656 IPDF_JSPLATFORM::Doc_gotoPage
= Form_GotoPage
;
657 IPDF_JSPLATFORM::Field_browse
= Form_Browse
;
659 IFSDK_PAUSE::version
= 1;
660 IFSDK_PAUSE::user
= NULL
;
661 IFSDK_PAUSE::NeedToPauseNow
= Pause_NeedToPauseNow
;
664 PDFiumEngine::~PDFiumEngine() {
665 for (size_t i
= 0; i
< pages_
.size(); ++i
)
670 FORM_DoDocumentAAction(form_
, FPDFDOC_AACTION_WC
);
672 FPDF_CloseDocument(doc_
);
674 FPDFDOC_ExitFormFillEnvironment(form_
);
678 if (fpdf_availability_
)
679 FPDFAvail_Destroy(fpdf_availability_
);
681 STLDeleteElements(&pages_
);
686 // This is just for testing, needs to be removed later
688 #define XFA_TESTFILE(filename) "E:/"#filename
690 #define XFA_TESTFILE(filename) "/home/"#filename
694 FPDF_FILEHANDLER file_handler
;
698 void Sample_Release(FPDF_LPVOID client_data
) {
701 FPDF_FILE
* file_wrapper
= (FPDF_FILE
*)client_data
;
702 fclose(file_wrapper
->file
);
706 FPDF_DWORD
Sample_GetSize(FPDF_LPVOID client_data
) {
709 FPDF_FILE
* file_wrapper
= (FPDF_FILE
*)client_data
;
710 long cur_pos
= ftell(file_wrapper
->file
);
713 if (fseek(file_wrapper
->file
, 0, SEEK_END
))
715 long size
= ftell(file_wrapper
->file
);
716 fseek(file_wrapper
->file
, cur_pos
, SEEK_SET
);
717 return (FPDF_DWORD
)size
;
720 FPDF_RESULT
Sample_ReadBlock(FPDF_LPVOID client_data
,
726 FPDF_FILE
* file_wrapper
= (FPDF_FILE
*)client_data
;
727 if (fseek(file_wrapper
->file
, (long)offset
, SEEK_SET
))
729 size_t read_size
= fread(buffer
, 1, size
, file_wrapper
->file
);
730 return read_size
== size
? 0 : -1;
733 FPDF_RESULT
Sample_WriteBlock(FPDF_LPVOID client_data
,
739 FPDF_FILE
* file_wrapper
= (FPDF_FILE
*)client_data
;
740 if (fseek(file_wrapper
->file
, (long)offset
, SEEK_SET
))
743 size_t write_size
= fwrite(buffer
, 1, size
, file_wrapper
->file
);
744 return write_size
== size
? 0 : -1;
747 FPDF_RESULT
Sample_Flush(FPDF_LPVOID client_data
) {
751 fflush(((FPDF_FILE
*)client_data
)->file
);
755 FPDF_RESULT
Sample_Truncate(FPDF_LPVOID client_data
, FPDF_DWORD size
) {
759 void PDFiumEngine::Form_EmailTo(FPDF_FORMFILLINFO
* param
,
760 FPDF_FILEHANDLER
* file_handler
,
762 FPDF_WIDESTRING subject
,
765 FPDF_WIDESTRING message
) {
767 base::UTF16ToUTF8(reinterpret_cast<const base::char16
*>(to
));
768 std::string subject_str
=
769 base::UTF16ToUTF8(reinterpret_cast<const base::char16
*>(subject
));
771 base::UTF16ToUTF8(reinterpret_cast<const base::char16
*>(cc
));
772 std::string bcc_str
=
773 base::UTF16ToUTF8(reinterpret_cast<const base::char16
*>(bcc
));
774 std::string message_str
=
775 base::UTF16ToUTF8(reinterpret_cast<const base::char16
*>(message
));
777 PDFiumEngine
* engine
= static_cast<PDFiumEngine
*>(param
);
778 engine
->client_
->Email(to_str
, cc_str
, bcc_str
, subject_str
, message_str
);
781 void PDFiumEngine::Form_DisplayCaret(FPDF_FORMFILLINFO
* param
,
788 PDFiumEngine
* engine
= static_cast<PDFiumEngine
*>(param
);
789 engine
->client_
->UpdateCursor(PP_CURSORTYPE_IBEAM
);
790 std::vector
<pp::Rect
> tickmarks
;
791 pp::Rect
rect(left
, top
, right
, bottom
);
792 tickmarks
.push_back(rect
);
793 engine
->client_
->UpdateTickMarks(tickmarks
);
796 void PDFiumEngine::Form_SetCurrentPage(FPDF_FORMFILLINFO
* param
,
797 FPDF_DOCUMENT document
,
799 PDFiumEngine
* engine
= static_cast<PDFiumEngine
*>(param
);
800 pp::Rect page_view_rect
= engine
->GetPageContentsRect(page
);
801 engine
->ScrolledToYPosition(page_view_rect
.height());
802 pp::Point
pos(1, page_view_rect
.height());
803 engine
->SetScrollPosition(pos
);
806 int PDFiumEngine::Form_GetCurrentPageIndex(FPDF_FORMFILLINFO
* param
,
807 FPDF_DOCUMENT document
) {
808 PDFiumEngine
* engine
= static_cast<PDFiumEngine
*>(param
);
809 return engine
->GetMostVisiblePage();
812 void PDFiumEngine::Form_GetPageViewRect(FPDF_FORMFILLINFO
* param
,
818 PDFiumEngine
* engine
= static_cast<PDFiumEngine
*>(param
);
819 int page_index
= engine
->GetMostVisiblePage();
820 pp::Rect page_view_rect
= engine
->GetPageContentsRect(page_index
);
822 *left
= page_view_rect
.x();
823 *right
= page_view_rect
.right();
824 *top
= page_view_rect
.y();
825 *bottom
= page_view_rect
.bottom();
828 int PDFiumEngine::Form_GetPlatform(FPDF_FORMFILLINFO
* param
,
831 int platform_flag
= -1;
835 #elif defined(__linux__)
841 std::string javascript
= "alert(\"Platform:"
842 + base::DoubleToString(platform_flag
)
845 return platform_flag
;
848 FPDF_BOOL
PDFiumEngine::Form_PopupMenu(FPDF_FORMFILLINFO
* param
,
857 FPDF_BOOL
PDFiumEngine::Form_PostRequestURL(FPDF_FORMFILLINFO
* param
,
859 FPDF_WIDESTRING data
,
860 FPDF_WIDESTRING content_type
,
861 FPDF_WIDESTRING encode
,
862 FPDF_WIDESTRING header
,
863 FPDF_BSTR
* response
) {
864 std::string url_str
=
865 base::UTF16ToUTF8(reinterpret_cast<const base::char16
*>(url
));
866 std::string data_str
=
867 base::UTF16ToUTF8(reinterpret_cast<const base::char16
*>(data
));
868 std::string content_type_str
=
869 base::UTF16ToUTF8(reinterpret_cast<const base::char16
*>(content_type
));
870 std::string encode_str
=
871 base::UTF16ToUTF8(reinterpret_cast<const base::char16
*>(encode
));
872 std::string header_str
=
873 base::UTF16ToUTF8(reinterpret_cast<const base::char16
*>(header
));
875 std::string javascript
= "alert(\"Post:"
876 + url_str
+ "," + data_str
+ "," + content_type_str
+ ","
877 + encode_str
+ "," + header_str
882 FPDF_BOOL
PDFiumEngine::Form_PutRequestURL(FPDF_FORMFILLINFO
* param
,
884 FPDF_WIDESTRING data
,
885 FPDF_WIDESTRING encode
) {
886 std::string url_str
=
887 base::UTF16ToUTF8(reinterpret_cast<const base::char16
*>(url
));
888 std::string data_str
=
889 base::UTF16ToUTF8(reinterpret_cast<const base::char16
*>(data
));
890 std::string encode_str
=
891 base::UTF16ToUTF8(reinterpret_cast<const base::char16
*>(encode
));
893 std::string javascript
= "alert(\"Put:"
894 + url_str
+ "," + data_str
+ "," + encode_str
900 void PDFiumEngine::Form_UploadTo(FPDF_FORMFILLINFO
* param
,
901 FPDF_FILEHANDLER
* file_handle
,
903 FPDF_WIDESTRING to
) {
905 base::UTF16ToUTF8(reinterpret_cast<const base::char16
*>(to
));
906 // TODO: needs the full implementation of form uploading
909 FPDF_LPFILEHANDLER
PDFiumEngine::Form_DownloadFromURL(FPDF_FORMFILLINFO
* param
,
910 FPDF_WIDESTRING url
) {
911 std::string url_str
=
912 base::UTF16ToUTF8(reinterpret_cast<const base::char16
*>(url
));
914 // Now should get data from url.
915 // For testing purpose, use data read from file
916 // TODO: needs the full implementation here
917 FILE* file
= fopen(XFA_TESTFILE("downloadtest.tem"), "w");
919 FPDF_FILE
* file_wrapper
= new FPDF_FILE
;
920 file_wrapper
->file
= file
;
921 file_wrapper
->file_handler
.clientData
= file_wrapper
;
922 file_wrapper
->file_handler
.Flush
= Sample_Flush
;
923 file_wrapper
->file_handler
.GetSize
= Sample_GetSize
;
924 file_wrapper
->file_handler
.ReadBlock
= Sample_ReadBlock
;
925 file_wrapper
->file_handler
.Release
= Sample_Release
;
926 file_wrapper
->file_handler
.Truncate
= Sample_Truncate
;
927 file_wrapper
->file_handler
.WriteBlock
= Sample_WriteBlock
;
929 return &file_wrapper
->file_handler
;
932 FPDF_FILEHANDLER
* PDFiumEngine::Form_OpenFile(FPDF_FORMFILLINFO
* param
,
936 std::string url_str
= "NULL";
939 base::UTF16ToUTF8(reinterpret_cast<const base::char16
*>(url
));
941 // TODO: need to implement open file from the url
942 // Use a file path for the ease of testing
943 FILE* file
= fopen(XFA_TESTFILE("tem.txt"), mode
);
944 FPDF_FILE
* file_wrapper
= new FPDF_FILE
;
945 file_wrapper
->file
= file
;
946 file_wrapper
->file_handler
.clientData
= file_wrapper
;
947 file_wrapper
->file_handler
.Flush
= Sample_Flush
;
948 file_wrapper
->file_handler
.GetSize
= Sample_GetSize
;
949 file_wrapper
->file_handler
.ReadBlock
= Sample_ReadBlock
;
950 file_wrapper
->file_handler
.Release
= Sample_Release
;
951 file_wrapper
->file_handler
.Truncate
= Sample_Truncate
;
952 file_wrapper
->file_handler
.WriteBlock
= Sample_WriteBlock
;
953 return &file_wrapper
->file_handler
;
956 void PDFiumEngine::Form_GotoURL(FPDF_FORMFILLINFO
* param
,
957 FPDF_DOCUMENT document
,
958 FPDF_WIDESTRING url
) {
959 std::string url_str
=
960 base::UTF16ToUTF8(reinterpret_cast<const base::char16
*>(url
));
961 // TODO: needs to implement GOTO URL action
964 int PDFiumEngine::Form_GetLanguage(FPDF_FORMFILLINFO
* param
,
970 #endif // PDF_USE_XFA
972 int PDFiumEngine::GetBlock(void* param
, unsigned long position
,
973 unsigned char* buffer
, unsigned long size
) {
974 DocumentLoader
* loader
= static_cast<DocumentLoader
*>(param
);
975 return loader
->GetBlock(position
, size
, buffer
);
978 bool PDFiumEngine::IsDataAvail(FX_FILEAVAIL
* param
,
979 size_t offset
, size_t size
) {
980 PDFiumEngine::FileAvail
* file_avail
=
981 static_cast<PDFiumEngine::FileAvail
*>(param
);
982 return file_avail
->loader
->IsDataAvailable(offset
, size
);
985 void PDFiumEngine::AddSegment(FX_DOWNLOADHINTS
* param
,
986 size_t offset
, size_t size
) {
987 PDFiumEngine::DownloadHints
* download_hints
=
988 static_cast<PDFiumEngine::DownloadHints
*>(param
);
989 return download_hints
->loader
->RequestData(offset
, size
);
992 bool PDFiumEngine::New(const char* url
) {
994 headers_
= std::string();
998 bool PDFiumEngine::New(const char* url
,
999 const char* headers
) {
1002 headers_
= std::string();
1008 void PDFiumEngine::PageOffsetUpdated(const pp::Point
& page_offset
) {
1009 page_offset_
= page_offset
;
1012 void PDFiumEngine::PluginSizeUpdated(const pp::Size
& size
) {
1015 plugin_size_
= size
;
1016 CalculateVisiblePages();
1019 void PDFiumEngine::ScrolledToXPosition(int position
) {
1022 int old_x
= position_
.x();
1023 position_
.set_x(position
);
1024 CalculateVisiblePages();
1025 client_
->Scroll(pp::Point(old_x
- position
, 0));
1028 void PDFiumEngine::ScrolledToYPosition(int position
) {
1031 int old_y
= position_
.y();
1032 position_
.set_y(position
);
1033 CalculateVisiblePages();
1034 client_
->Scroll(pp::Point(0, old_y
- position
));
1037 void PDFiumEngine::PrePaint() {
1038 for (size_t i
= 0; i
< progressive_paints_
.size(); ++i
)
1039 progressive_paints_
[i
].painted_
= false;
1042 void PDFiumEngine::Paint(const pp::Rect
& rect
,
1043 pp::ImageData
* image_data
,
1044 std::vector
<pp::Rect
>* ready
,
1045 std::vector
<pp::Rect
>* pending
) {
1050 pp::Rect leftover
= rect
;
1051 for (size_t i
= 0; i
< visible_pages_
.size(); ++i
) {
1052 int index
= visible_pages_
[i
];
1053 pp::Rect page_rect
= pages_
[index
]->rect();
1054 // Convert the current page's rectangle to screen rectangle. We do this
1055 // instead of the reverse (converting the dirty rectangle from screen to
1056 // page coordinates) because then we'd have to convert back to screen
1057 // coordinates, and the rounding errors sometime leave pixels dirty or even
1058 // move the text up or down a pixel when zoomed.
1059 pp::Rect page_rect_in_screen
= GetPageScreenRect(index
);
1060 pp::Rect dirty_in_screen
= page_rect_in_screen
.Intersect(leftover
);
1061 if (dirty_in_screen
.IsEmpty())
1064 leftover
= leftover
.Subtract(dirty_in_screen
);
1066 if (pages_
[index
]->available()) {
1067 int progressive
= GetProgressiveIndex(index
);
1068 if (progressive
!= -1) {
1069 DCHECK_GE(progressive
, 0);
1070 DCHECK_LT(static_cast<size_t>(progressive
), progressive_paints_
.size());
1071 if (progressive_paints_
[progressive
].rect
!= dirty_in_screen
) {
1072 // The PDFium code can only handle one progressive paint at a time, so
1073 // queue this up. Previously we used to merge the rects when this
1074 // happened, but it made scrolling up on complex PDFs very slow since
1075 // there would be a damaged rect at the top (from scroll) and at the
1076 // bottom (from toolbar).
1077 pending
->push_back(dirty_in_screen
);
1082 if (progressive
== -1) {
1083 progressive
= StartPaint(index
, dirty_in_screen
);
1084 progressive_paint_timeout_
= kMaxInitialProgressivePaintTimeMs
;
1086 progressive_paint_timeout_
= kMaxProgressivePaintTimeMs
;
1089 progressive_paints_
[progressive
].painted_
= true;
1090 if (ContinuePaint(progressive
, image_data
)) {
1091 FinishPaint(progressive
, image_data
);
1092 ready
->push_back(dirty_in_screen
);
1094 pending
->push_back(dirty_in_screen
);
1097 PaintUnavailablePage(index
, dirty_in_screen
, image_data
);
1098 ready
->push_back(dirty_in_screen
);
1103 void PDFiumEngine::PostPaint() {
1104 for (size_t i
= 0; i
< progressive_paints_
.size(); ++i
) {
1105 if (progressive_paints_
[i
].painted_
)
1108 // This rectangle must have been merged with another one, that's why we
1109 // weren't asked to paint it. Remove it or otherwise we'll never finish
1111 FPDF_RenderPage_Close(
1112 pages_
[progressive_paints_
[i
].page_index
]->GetPage());
1113 FPDFBitmap_Destroy(progressive_paints_
[i
].bitmap
);
1114 progressive_paints_
.erase(progressive_paints_
.begin() + i
);
1119 bool PDFiumEngine::HandleDocumentLoad(const pp::URLLoader
& loader
) {
1120 password_tries_remaining_
= kMaxPasswordTries
;
1121 return doc_loader_
.Init(loader
, url_
, headers_
);
1124 pp::Instance
* PDFiumEngine::GetPluginInstance() {
1125 return client_
->GetPluginInstance();
1128 pp::URLLoader
PDFiumEngine::CreateURLLoader() {
1129 return client_
->CreateURLLoader();
1132 void PDFiumEngine::AppendPage(PDFEngine
* engine
, int index
) {
1133 // Unload and delete the blank page before appending.
1134 pages_
[index
]->Unload();
1135 pages_
[index
]->set_calculated_links(false);
1136 pp::Size curr_page_size
= GetPageSize(index
);
1137 FPDFPage_Delete(doc_
, index
);
1138 FPDF_ImportPages(doc_
,
1139 static_cast<PDFiumEngine
*>(engine
)->doc(),
1142 pp::Size new_page_size
= GetPageSize(index
);
1143 if (curr_page_size
!= new_page_size
)
1145 client_
->Invalidate(GetPageScreenRect(index
));
1148 pp::Point
PDFiumEngine::GetScrollPosition() {
1152 void PDFiumEngine::SetScrollPosition(const pp::Point
& position
) {
1153 position_
= position
;
1156 bool PDFiumEngine::IsProgressiveLoad() {
1157 return doc_loader_
.is_partial_document();
1160 void PDFiumEngine::OnPartialDocumentLoaded() {
1161 file_access_
.m_FileLen
= doc_loader_
.document_size();
1162 fpdf_availability_
= FPDFAvail_Create(&file_availability_
, &file_access_
);
1163 DCHECK(fpdf_availability_
);
1165 // Currently engine does not deal efficiently with some non-linearized files.
1166 // See http://code.google.com/p/chromium/issues/detail?id=59400
1167 // To improve user experience we download entire file for non-linearized PDF.
1168 if (!FPDFAvail_IsLinearized(fpdf_availability_
)) {
1169 doc_loader_
.RequestData(0, doc_loader_
.document_size());
1176 void PDFiumEngine::OnPendingRequestComplete() {
1177 if (!doc_
|| !form_
) {
1182 // LoadDocument() will result in |pending_pages_| being reset so there's no
1183 // need to run the code below in that case.
1184 bool update_pages
= false;
1185 std::vector
<int> still_pending
;
1186 for (size_t i
= 0; i
< pending_pages_
.size(); ++i
) {
1187 if (CheckPageAvailable(pending_pages_
[i
], &still_pending
)) {
1188 update_pages
= true;
1189 if (IsPageVisible(pending_pages_
[i
]))
1190 client_
->Invalidate(GetPageScreenRect(pending_pages_
[i
]));
1193 pending_pages_
.swap(still_pending
);
1198 void PDFiumEngine::OnNewDataAvailable() {
1199 client_
->DocumentLoadProgress(doc_loader_
.GetAvailableData(),
1200 doc_loader_
.document_size());
1203 void PDFiumEngine::OnDocumentComplete() {
1204 if (!doc_
|| !form_
) {
1205 file_access_
.m_FileLen
= doc_loader_
.document_size();
1210 bool need_update
= false;
1211 for (size_t i
= 0; i
< pages_
.size(); ++i
) {
1212 if (pages_
[i
]->available())
1215 pages_
[i
]->set_available(true);
1216 // We still need to call IsPageAvail() even if the whole document is
1217 // already downloaded.
1218 FPDFAvail_IsPageAvail(fpdf_availability_
, i
, &download_hints_
);
1220 if (IsPageVisible(i
))
1221 client_
->Invalidate(GetPageScreenRect(i
));
1226 FinishLoadingDocument();
1229 void PDFiumEngine::FinishLoadingDocument() {
1230 DCHECK(doc_loader_
.IsDocumentComplete() && doc_
);
1231 if (called_do_document_action_
)
1233 called_do_document_action_
= true;
1235 // These can only be called now, as the JS might end up needing a page.
1236 FORM_DoDocumentJSAction(form_
);
1237 FORM_DoDocumentOpenAction(form_
);
1238 if (most_visible_page_
!= -1) {
1239 FPDF_PAGE new_page
= pages_
[most_visible_page_
]->GetPage();
1240 FORM_DoPageAAction(new_page
, form_
, FPDFPAGE_AACTION_OPEN
);
1243 if (doc_
) // This can only happen if loading |doc_| fails.
1244 client_
->DocumentLoadComplete(pages_
.size());
1247 void PDFiumEngine::UnsupportedFeature(int type
) {
1248 std::string feature
;
1251 case FPDF_UNSP_DOC_XFAFORM
:
1255 case FPDF_UNSP_DOC_PORTABLECOLLECTION
:
1256 feature
= "Portfolios_Packages";
1258 case FPDF_UNSP_DOC_ATTACHMENT
:
1259 case FPDF_UNSP_ANNOT_ATTACHMENT
:
1260 feature
= "Attachment";
1262 case FPDF_UNSP_DOC_SECURITY
:
1263 feature
= "Rights_Management";
1265 case FPDF_UNSP_DOC_SHAREDREVIEW
:
1266 feature
= "Shared_Review";
1268 case FPDF_UNSP_DOC_SHAREDFORM_ACROBAT
:
1269 case FPDF_UNSP_DOC_SHAREDFORM_FILESYSTEM
:
1270 case FPDF_UNSP_DOC_SHAREDFORM_EMAIL
:
1271 feature
= "Shared_Form";
1273 case FPDF_UNSP_ANNOT_3DANNOT
:
1276 case FPDF_UNSP_ANNOT_MOVIE
:
1279 case FPDF_UNSP_ANNOT_SOUND
:
1282 case FPDF_UNSP_ANNOT_SCREEN_MEDIA
:
1283 case FPDF_UNSP_ANNOT_SCREEN_RICHMEDIA
:
1286 case FPDF_UNSP_ANNOT_SIG
:
1287 feature
= "Digital_Signature";
1290 client_
->DocumentHasUnsupportedFeature(feature
);
1293 void PDFiumEngine::ContinueFind(int32_t result
) {
1294 StartFind(current_find_text_
.c_str(), !!result
);
1297 bool PDFiumEngine::HandleEvent(const pp::InputEvent
& event
) {
1298 DCHECK(!defer_page_unload_
);
1299 defer_page_unload_
= true;
1301 switch (event
.GetType()) {
1302 case PP_INPUTEVENT_TYPE_MOUSEDOWN
:
1303 rv
= OnMouseDown(pp::MouseInputEvent(event
));
1305 case PP_INPUTEVENT_TYPE_MOUSEUP
:
1306 rv
= OnMouseUp(pp::MouseInputEvent(event
));
1308 case PP_INPUTEVENT_TYPE_MOUSEMOVE
:
1309 rv
= OnMouseMove(pp::MouseInputEvent(event
));
1311 case PP_INPUTEVENT_TYPE_KEYDOWN
:
1312 rv
= OnKeyDown(pp::KeyboardInputEvent(event
));
1314 case PP_INPUTEVENT_TYPE_KEYUP
:
1315 rv
= OnKeyUp(pp::KeyboardInputEvent(event
));
1317 case PP_INPUTEVENT_TYPE_CHAR
:
1318 rv
= OnChar(pp::KeyboardInputEvent(event
));
1324 DCHECK(defer_page_unload_
);
1325 defer_page_unload_
= false;
1326 for (size_t i
= 0; i
< deferred_page_unloads_
.size(); ++i
)
1327 pages_
[deferred_page_unloads_
[i
]]->Unload();
1328 deferred_page_unloads_
.clear();
1332 uint32_t PDFiumEngine::QuerySupportedPrintOutputFormats() {
1333 if (!HasPermission(PDFEngine::PERMISSION_PRINT_LOW_QUALITY
))
1335 return PP_PRINTOUTPUTFORMAT_PDF
;
1338 void PDFiumEngine::PrintBegin() {
1339 FORM_DoDocumentAAction(form_
, FPDFDOC_AACTION_WP
);
1342 pp::Resource
PDFiumEngine::PrintPages(
1343 const PP_PrintPageNumberRange_Dev
* page_ranges
, uint32_t page_range_count
,
1344 const PP_PrintSettings_Dev
& print_settings
) {
1345 if (HasPermission(PDFEngine::PERMISSION_PRINT_HIGH_QUALITY
))
1346 return PrintPagesAsPDF(page_ranges
, page_range_count
, print_settings
);
1347 else if (HasPermission(PDFEngine::PERMISSION_PRINT_LOW_QUALITY
))
1348 return PrintPagesAsRasterPDF(page_ranges
, page_range_count
, print_settings
);
1349 return pp::Resource();
1352 FPDF_DOCUMENT
PDFiumEngine::CreateSinglePageRasterPdf(
1353 double source_page_width
,
1354 double source_page_height
,
1355 const PP_PrintSettings_Dev
& print_settings
,
1356 PDFiumPage
* page_to_print
) {
1357 FPDF_DOCUMENT temp_doc
= FPDF_CreateNewDocument();
1361 const pp::Size
& bitmap_size(page_to_print
->rect().size());
1363 FPDF_PAGE temp_page
=
1364 FPDFPage_New(temp_doc
, 0, source_page_width
, source_page_height
);
1366 pp::ImageData image
= pp::ImageData(client_
->GetPluginInstance(),
1367 PP_IMAGEDATAFORMAT_BGRA_PREMUL
,
1371 FPDF_BITMAP bitmap
= FPDFBitmap_CreateEx(bitmap_size
.width(),
1372 bitmap_size
.height(),
1378 FPDFBitmap_FillRect(
1379 bitmap
, 0, 0, bitmap_size
.width(), bitmap_size
.height(), 0xFFFFFFFF);
1381 pp::Rect page_rect
= page_to_print
->rect();
1382 FPDF_RenderPageBitmap(bitmap
,
1383 page_to_print
->GetPrintPage(),
1388 print_settings
.orientation
,
1389 FPDF_ANNOT
| FPDF_PRINTING
| FPDF_NO_CATCH
);
1391 double ratio_x
= ConvertUnitDouble(bitmap_size
.width(),
1394 double ratio_y
= ConvertUnitDouble(bitmap_size
.height(),
1398 // Add the bitmap to an image object and add the image object to the output
1400 FPDF_PAGEOBJECT temp_img
= FPDFPageObj_NewImgeObj(temp_doc
);
1401 FPDFImageObj_SetBitmap(&temp_page
, 1, temp_img
, bitmap
);
1402 FPDFImageObj_SetMatrix(temp_img
, ratio_x
, 0, 0, ratio_y
, 0, 0);
1403 FPDFPage_InsertObject(temp_page
, temp_img
);
1404 FPDFPage_GenerateContent(temp_page
);
1405 FPDF_ClosePage(temp_page
);
1407 page_to_print
->ClosePrintPage();
1408 FPDFBitmap_Destroy(bitmap
);
1413 pp::Buffer_Dev
PDFiumEngine::PrintPagesAsRasterPDF(
1414 const PP_PrintPageNumberRange_Dev
* page_ranges
, uint32_t page_range_count
,
1415 const PP_PrintSettings_Dev
& print_settings
) {
1416 if (!page_range_count
)
1417 return pp::Buffer_Dev();
1419 // If document is not downloaded yet, disable printing.
1420 if (doc_
&& !doc_loader_
.IsDocumentComplete())
1421 return pp::Buffer_Dev();
1423 FPDF_DOCUMENT output_doc
= FPDF_CreateNewDocument();
1425 return pp::Buffer_Dev();
1427 SaveSelectedFormForPrint();
1429 std::vector
<PDFiumPage
> pages_to_print
;
1430 // width and height of source PDF pages.
1431 std::vector
<std::pair
<double, double> > source_page_sizes
;
1432 // Collect pages to print and sizes of source pages.
1433 std::vector
<uint32_t> page_numbers
=
1434 GetPageNumbersFromPrintPageNumberRange(page_ranges
, page_range_count
);
1435 for (size_t i
= 0; i
< page_numbers
.size(); ++i
) {
1436 uint32_t page_number
= page_numbers
[i
];
1437 FPDF_PAGE pdf_page
= FPDF_LoadPage(doc_
, page_number
);
1438 double source_page_width
= FPDF_GetPageWidth(pdf_page
);
1439 double source_page_height
= FPDF_GetPageHeight(pdf_page
);
1440 source_page_sizes
.push_back(std::make_pair(source_page_width
,
1441 source_page_height
));
1443 int width_in_pixels
= ConvertUnit(source_page_width
,
1445 print_settings
.dpi
);
1446 int height_in_pixels
= ConvertUnit(source_page_height
,
1448 print_settings
.dpi
);
1450 pp::Rect
rect(width_in_pixels
, height_in_pixels
);
1451 pages_to_print
.push_back(PDFiumPage(this, page_number
, rect
, true));
1452 FPDF_ClosePage(pdf_page
);
1455 #if defined(OS_LINUX)
1456 g_last_instance_id
= client_
->GetPluginInstance()->pp_instance();
1460 for (; i
< pages_to_print
.size(); ++i
) {
1461 double source_page_width
= source_page_sizes
[i
].first
;
1462 double source_page_height
= source_page_sizes
[i
].second
;
1464 // Use temp_doc to compress image by saving PDF to buffer.
1465 FPDF_DOCUMENT temp_doc
= CreateSinglePageRasterPdf(source_page_width
,
1468 &pages_to_print
[i
]);
1473 pp::Buffer_Dev buffer
= GetFlattenedPrintData(temp_doc
);
1474 FPDF_CloseDocument(temp_doc
);
1476 PDFiumMemBufferFileRead
file_read(buffer
.data(), buffer
.size());
1477 temp_doc
= FPDF_LoadCustomDocument(&file_read
, NULL
);
1479 FPDF_BOOL imported
= FPDF_ImportPages(output_doc
, temp_doc
, "1", i
);
1480 FPDF_CloseDocument(temp_doc
);
1485 pp::Buffer_Dev buffer
;
1486 if (i
== pages_to_print
.size()) {
1487 FPDF_CopyViewerPreferences(output_doc
, doc_
);
1488 FitContentsToPrintableAreaIfRequired(output_doc
, print_settings
);
1489 // Now flatten all the output pages.
1490 buffer
= GetFlattenedPrintData(output_doc
);
1492 FPDF_CloseDocument(output_doc
);
1496 pp::Buffer_Dev
PDFiumEngine::GetFlattenedPrintData(const FPDF_DOCUMENT
& doc
) {
1497 int page_count
= FPDF_GetPageCount(doc
);
1498 bool flatten_succeeded
= true;
1499 for (int i
= 0; i
< page_count
; ++i
) {
1500 FPDF_PAGE page
= FPDF_LoadPage(doc
, i
);
1503 int flatten_ret
= FPDFPage_Flatten(page
, FLAT_PRINT
);
1504 FPDF_ClosePage(page
);
1505 if (flatten_ret
== FLATTEN_FAIL
) {
1506 flatten_succeeded
= false;
1510 flatten_succeeded
= false;
1514 if (!flatten_succeeded
) {
1515 FPDF_CloseDocument(doc
);
1516 return pp::Buffer_Dev();
1519 pp::Buffer_Dev buffer
;
1520 PDFiumMemBufferFileWrite output_file_write
;
1521 if (FPDF_SaveAsCopy(doc
, &output_file_write
, 0)) {
1522 buffer
= pp::Buffer_Dev(
1523 client_
->GetPluginInstance(), output_file_write
.size());
1524 if (!buffer
.is_null()) {
1525 memcpy(buffer
.data(), output_file_write
.buffer().c_str(),
1526 output_file_write
.size());
1532 pp::Buffer_Dev
PDFiumEngine::PrintPagesAsPDF(
1533 const PP_PrintPageNumberRange_Dev
* page_ranges
, uint32_t page_range_count
,
1534 const PP_PrintSettings_Dev
& print_settings
) {
1535 if (!page_range_count
)
1536 return pp::Buffer_Dev();
1539 FPDF_DOCUMENT output_doc
= FPDF_CreateNewDocument();
1541 return pp::Buffer_Dev();
1543 SaveSelectedFormForPrint();
1545 std::string page_number_str
;
1546 for (uint32_t index
= 0; index
< page_range_count
; ++index
) {
1547 if (!page_number_str
.empty())
1548 page_number_str
.append(",");
1549 page_number_str
.append(
1550 base::IntToString(page_ranges
[index
].first_page_number
+ 1));
1551 if (page_ranges
[index
].first_page_number
!=
1552 page_ranges
[index
].last_page_number
) {
1553 page_number_str
.append("-");
1554 page_number_str
.append(
1555 base::IntToString(page_ranges
[index
].last_page_number
+ 1));
1559 std::vector
<uint32_t> page_numbers
=
1560 GetPageNumbersFromPrintPageNumberRange(page_ranges
, page_range_count
);
1561 for (size_t i
= 0; i
< page_numbers
.size(); ++i
) {
1562 uint32_t page_number
= page_numbers
[i
];
1563 pages_
[page_number
]->GetPage();
1564 if (!IsPageVisible(page_numbers
[i
]))
1565 pages_
[page_number
]->Unload();
1568 FPDF_CopyViewerPreferences(output_doc
, doc_
);
1569 if (!FPDF_ImportPages(output_doc
, doc_
, page_number_str
.c_str(), 0)) {
1570 FPDF_CloseDocument(output_doc
);
1571 return pp::Buffer_Dev();
1574 FitContentsToPrintableAreaIfRequired(output_doc
, print_settings
);
1576 // Now flatten all the output pages.
1577 pp::Buffer_Dev buffer
= GetFlattenedPrintData(output_doc
);
1578 FPDF_CloseDocument(output_doc
);
1582 void PDFiumEngine::FitContentsToPrintableAreaIfRequired(
1583 const FPDF_DOCUMENT
& doc
, const PP_PrintSettings_Dev
& print_settings
) {
1584 // Check to see if we need to fit pdf contents to printer paper size.
1585 if (print_settings
.print_scaling_option
!=
1586 PP_PRINTSCALINGOPTION_SOURCE_SIZE
) {
1587 int num_pages
= FPDF_GetPageCount(doc
);
1588 // In-place transformation is more efficient than creating a new
1589 // transformed document from the source document. Therefore, transform
1590 // every page to fit the contents in the selected printer paper.
1591 for (int i
= 0; i
< num_pages
; ++i
) {
1592 FPDF_PAGE page
= FPDF_LoadPage(doc
, i
);
1593 TransformPDFPageForPrinting(page
, print_settings
);
1594 FPDF_ClosePage(page
);
1599 void PDFiumEngine::SaveSelectedFormForPrint() {
1600 FORM_ForceToKillFocus(form_
);
1601 client_
->FormTextFieldFocusChange(false);
1604 void PDFiumEngine::PrintEnd() {
1605 FORM_DoDocumentAAction(form_
, FPDFDOC_AACTION_DP
);
1608 PDFiumPage::Area
PDFiumEngine::GetCharIndex(const pp::MouseInputEvent
& event
,
1612 PDFiumPage::LinkTarget
* target
) {
1613 // First figure out which page this is in.
1614 pp::Point mouse_point
= event
.GetPosition();
1615 return GetCharIndex(mouse_point
, page_index
, char_index
, form_type
, target
);
1618 PDFiumPage::Area
PDFiumEngine::GetCharIndex(const pp::Point
& point
,
1622 PDFiumPage::LinkTarget
* target
) {
1624 pp::Point
point_in_page(
1625 static_cast<int>((point
.x() + position_
.x()) / current_zoom_
),
1626 static_cast<int>((point
.y() + position_
.y()) / current_zoom_
));
1627 for (size_t i
= 0; i
< visible_pages_
.size(); ++i
) {
1628 if (pages_
[visible_pages_
[i
]]->rect().Contains(point_in_page
)) {
1629 page
= visible_pages_
[i
];
1634 return PDFiumPage::NONSELECTABLE_AREA
;
1636 // If the page hasn't finished rendering, calling into the page sometimes
1638 for (size_t i
= 0; i
< progressive_paints_
.size(); ++i
) {
1639 if (progressive_paints_
[i
].page_index
== page
)
1640 return PDFiumPage::NONSELECTABLE_AREA
;
1644 return pages_
[page
]->GetCharIndex(
1645 point_in_page
, current_rotation_
, char_index
, form_type
, target
);
1648 bool PDFiumEngine::OnMouseDown(const pp::MouseInputEvent
& event
) {
1649 if (event
.GetButton() == PP_INPUTEVENT_MOUSEBUTTON_RIGHT
) {
1650 if (!selection_
.size())
1652 std::vector
<pp::Rect
> selection_rect_vector
;
1653 GetAllScreenRectsUnion(&selection_
, GetVisibleRect().point(),
1654 &selection_rect_vector
);
1655 pp::Point point
= event
.GetPosition();
1656 for (size_t i
= 0; i
< selection_rect_vector
.size(); ++i
) {
1657 if (selection_rect_vector
[i
].Contains(point
.x(), point
.y()))
1660 SelectionChangeInvalidator
selection_invalidator(this);
1664 if (event
.GetButton() != PP_INPUTEVENT_MOUSEBUTTON_LEFT
)
1667 SelectionChangeInvalidator
selection_invalidator(this);
1670 int page_index
= -1;
1671 int char_index
= -1;
1672 int form_type
= FPDF_FORMFIELD_UNKNOWN
;
1673 PDFiumPage::LinkTarget target
;
1674 PDFiumPage::Area area
=
1675 GetCharIndex(event
, &page_index
, &char_index
, &form_type
, &target
);
1676 mouse_down_state_
.Set(area
, target
);
1678 // Decide whether to open link or not based on user action in mouse up and
1679 // mouse move events.
1680 if (area
== PDFiumPage::WEBLINK_AREA
)
1683 if (area
== PDFiumPage::DOCLINK_AREA
) {
1684 client_
->ScrollToPage(target
.page
);
1685 client_
->FormTextFieldFocusChange(false);
1689 if (page_index
!= -1) {
1690 last_page_mouse_down_
= page_index
;
1691 double page_x
, page_y
;
1692 pp::Point point
= event
.GetPosition();
1693 DeviceToPage(page_index
, point
.x(), point
.y(), &page_x
, &page_y
);
1695 FORM_OnLButtonDown(form_
, pages_
[page_index
]->GetPage(), 0, page_x
, page_y
);
1696 if (form_type
> FPDF_FORMFIELD_UNKNOWN
) { // returns -1 sometimes...
1697 mouse_down_state_
.Set(PDFiumPage::NONSELECTABLE_AREA
, target
);
1698 bool is_valid_control
= (form_type
== FPDF_FORMFIELD_TEXTFIELD
||
1699 form_type
== FPDF_FORMFIELD_COMBOBOX
);
1701 is_valid_control
|= (form_type
== FPDF_FORMFIELD_XFA
);
1703 client_
->FormTextFieldFocusChange(is_valid_control
);
1704 return true; // Return now before we get into the selection code.
1708 client_
->FormTextFieldFocusChange(false);
1710 if (area
!= PDFiumPage::TEXT_AREA
)
1711 return true; // Return true so WebKit doesn't do its own highlighting.
1713 if (event
.GetClickCount() == 1) {
1714 OnSingleClick(page_index
, char_index
);
1715 } else if (event
.GetClickCount() == 2 ||
1716 event
.GetClickCount() == 3) {
1717 OnMultipleClick(event
.GetClickCount(), page_index
, char_index
);
1723 void PDFiumEngine::OnSingleClick(int page_index
, int char_index
) {
1725 selection_
.push_back(PDFiumRange(pages_
[page_index
], char_index
, 0));
1728 void PDFiumEngine::OnMultipleClick(int click_count
,
1731 // It would be more efficient if the SDK could support finding a space, but
1733 int start_index
= char_index
;
1735 base::char16 cur
= pages_
[page_index
]->GetCharAtIndex(start_index
);
1736 // For double click, we want to select one word so we look for whitespace
1737 // boundaries. For triple click, we want the whole line.
1738 if (cur
== '\n' || (click_count
== 2 && (cur
== ' ' || cur
== '\t')))
1740 } while (--start_index
>= 0);
1744 int end_index
= char_index
;
1745 int total
= pages_
[page_index
]->GetCharCount();
1746 while (end_index
++ <= total
) {
1747 base::char16 cur
= pages_
[page_index
]->GetCharAtIndex(end_index
);
1748 if (cur
== '\n' || (click_count
== 2 && (cur
== ' ' || cur
== '\t')))
1752 selection_
.push_back(PDFiumRange(
1753 pages_
[page_index
], start_index
, end_index
- start_index
));
1756 bool PDFiumEngine::OnMouseUp(const pp::MouseInputEvent
& event
) {
1757 if (event
.GetButton() != PP_INPUTEVENT_MOUSEBUTTON_LEFT
)
1760 int page_index
= -1;
1761 int char_index
= -1;
1762 int form_type
= FPDF_FORMFIELD_UNKNOWN
;
1763 PDFiumPage::LinkTarget target
;
1764 PDFiumPage::Area area
=
1765 GetCharIndex(event
, &page_index
, &char_index
, &form_type
, &target
);
1767 // Open link on mouse up for same link for which mouse down happened earlier.
1768 if (mouse_down_state_
.Matches(area
, target
)) {
1769 if (area
== PDFiumPage::WEBLINK_AREA
) {
1770 bool open_in_new_tab
= !!(event
.GetModifiers() & kDefaultKeyModifier
);
1771 client_
->NavigateTo(target
.url
, open_in_new_tab
);
1772 client_
->FormTextFieldFocusChange(false);
1777 if (page_index
!= -1) {
1778 double page_x
, page_y
;
1779 pp::Point point
= event
.GetPosition();
1780 DeviceToPage(page_index
, point
.x(), point
.y(), &page_x
, &page_y
);
1782 form_
, pages_
[page_index
]->GetPage(), 0, page_x
, page_y
);
1788 SetSelecting(false);
1792 bool PDFiumEngine::OnMouseMove(const pp::MouseInputEvent
& event
) {
1793 int page_index
= -1;
1794 int char_index
= -1;
1795 int form_type
= FPDF_FORMFIELD_UNKNOWN
;
1796 PDFiumPage::LinkTarget target
;
1797 PDFiumPage::Area area
=
1798 GetCharIndex(event
, &page_index
, &char_index
, &form_type
, &target
);
1800 // Clear |mouse_down_state_| if mouse moves away from where the mouse down
1802 if (!mouse_down_state_
.Matches(area
, target
))
1803 mouse_down_state_
.Reset();
1806 PP_CursorType_Dev cursor
;
1808 case PDFiumPage::TEXT_AREA
:
1809 cursor
= PP_CURSORTYPE_IBEAM
;
1811 case PDFiumPage::WEBLINK_AREA
:
1812 case PDFiumPage::DOCLINK_AREA
:
1813 cursor
= PP_CURSORTYPE_HAND
;
1815 case PDFiumPage::NONSELECTABLE_AREA
:
1817 switch (form_type
) {
1818 case FPDF_FORMFIELD_PUSHBUTTON
:
1819 case FPDF_FORMFIELD_CHECKBOX
:
1820 case FPDF_FORMFIELD_RADIOBUTTON
:
1821 case FPDF_FORMFIELD_COMBOBOX
:
1822 case FPDF_FORMFIELD_LISTBOX
:
1823 cursor
= PP_CURSORTYPE_HAND
;
1825 case FPDF_FORMFIELD_TEXTFIELD
:
1826 cursor
= PP_CURSORTYPE_IBEAM
;
1829 cursor
= PP_CURSORTYPE_POINTER
;
1835 if (page_index
!= -1) {
1836 double page_x
, page_y
;
1837 pp::Point point
= event
.GetPosition();
1838 DeviceToPage(page_index
, point
.x(), point
.y(), &page_x
, &page_y
);
1839 FORM_OnMouseMove(form_
, pages_
[page_index
]->GetPage(), 0, page_x
, page_y
);
1842 client_
->UpdateCursor(cursor
);
1843 pp::Point point
= event
.GetPosition();
1844 std::string url
= GetLinkAtPosition(event
.GetPosition());
1845 if (url
!= link_under_cursor_
) {
1846 link_under_cursor_
= url
;
1847 pp::PDF::SetLinkUnderCursor(GetPluginInstance(), url
.c_str());
1849 // No need to swallow the event, since this might interfere with the
1850 // scrollbars if the user is dragging them.
1854 // We're selecting but right now we're not over text, so don't change the
1855 // current selection.
1856 if (area
!= PDFiumPage::TEXT_AREA
&& area
!= PDFiumPage::WEBLINK_AREA
&&
1857 area
!= PDFiumPage::DOCLINK_AREA
) {
1861 SelectionChangeInvalidator
selection_invalidator(this);
1863 // Check if the user has descreased their selection area and we need to remove
1864 // pages from selection_.
1865 for (size_t i
= 0; i
< selection_
.size(); ++i
) {
1866 if (selection_
[i
].page_index() == page_index
) {
1867 // There should be no other pages after this.
1868 selection_
.erase(selection_
.begin() + i
+ 1, selection_
.end());
1873 if (selection_
.size() == 0)
1876 int last
= selection_
.size() - 1;
1877 if (selection_
[last
].page_index() == page_index
) {
1878 // Selecting within a page.
1880 if (char_index
>= selection_
[last
].char_index()) {
1881 // Selecting forward.
1882 count
= char_index
- selection_
[last
].char_index() + 1;
1884 count
= char_index
- selection_
[last
].char_index() - 1;
1886 selection_
[last
].SetCharCount(count
);
1887 } else if (selection_
[last
].page_index() < page_index
) {
1888 // Selecting into the next page.
1890 // First make sure that there are no gaps in selection, i.e. if mousedown on
1891 // page one but we only get mousemove over page three, we want page two.
1892 for (int i
= selection_
[last
].page_index() + 1; i
< page_index
; ++i
) {
1893 selection_
.push_back(PDFiumRange(pages_
[i
], 0,
1894 pages_
[i
]->GetCharCount()));
1897 int count
= pages_
[selection_
[last
].page_index()]->GetCharCount();
1898 selection_
[last
].SetCharCount(count
- selection_
[last
].char_index());
1899 selection_
.push_back(PDFiumRange(pages_
[page_index
], 0, char_index
));
1901 // Selecting into the previous page.
1902 // The selection's char_index is 0-based, so the character count is one
1903 // more than the index. The character count needs to be negative to
1904 // indicate a backwards selection.
1905 selection_
[last
].SetCharCount(-(selection_
[last
].char_index() + 1));
1907 // First make sure that there are no gaps in selection, i.e. if mousedown on
1908 // page three but we only get mousemove over page one, we want page two.
1909 for (int i
= selection_
[last
].page_index() - 1; i
> page_index
; --i
) {
1910 selection_
.push_back(PDFiumRange(pages_
[i
], 0,
1911 pages_
[i
]->GetCharCount()));
1914 int count
= pages_
[page_index
]->GetCharCount();
1915 selection_
.push_back(
1916 PDFiumRange(pages_
[page_index
], count
, count
- char_index
));
1922 bool PDFiumEngine::OnKeyDown(const pp::KeyboardInputEvent
& event
) {
1923 if (last_page_mouse_down_
== -1)
1926 bool rv
= !!FORM_OnKeyDown(
1927 form_
, pages_
[last_page_mouse_down_
]->GetPage(),
1928 event
.GetKeyCode(), event
.GetModifiers());
1930 if (event
.GetKeyCode() == ui::VKEY_BACK
||
1931 event
.GetKeyCode() == ui::VKEY_ESCAPE
) {
1932 // Chrome doesn't send char events for backspace or escape keys, see
1933 // PlatformKeyboardEventBuilder::isCharacterKey() and
1934 // http://chrome-corpsvn.mtv.corp.google.com/viewvc?view=rev&root=chrome&revision=31805
1935 // for more information. So just fake one since PDFium uses it.
1937 str
.push_back(event
.GetKeyCode());
1938 pp::KeyboardInputEvent
synthesized(pp::KeyboardInputEvent(
1939 client_
->GetPluginInstance(),
1940 PP_INPUTEVENT_TYPE_CHAR
,
1941 event
.GetTimeStamp(),
1942 event
.GetModifiers(),
1945 OnChar(synthesized
);
1951 bool PDFiumEngine::OnKeyUp(const pp::KeyboardInputEvent
& event
) {
1952 if (last_page_mouse_down_
== -1)
1955 return !!FORM_OnKeyUp(
1956 form_
, pages_
[last_page_mouse_down_
]->GetPage(),
1957 event
.GetKeyCode(), event
.GetModifiers());
1960 bool PDFiumEngine::OnChar(const pp::KeyboardInputEvent
& event
) {
1961 if (last_page_mouse_down_
== -1)
1964 base::string16 str
= base::UTF8ToUTF16(event
.GetCharacterText().AsString());
1965 return !!FORM_OnChar(
1966 form_
, pages_
[last_page_mouse_down_
]->GetPage(),
1968 event
.GetModifiers());
1971 void PDFiumEngine::StartFind(const char* text
, bool case_sensitive
) {
1972 // We can get a call to StartFind before we have any page information (i.e.
1973 // before the first call to LoadDocument has happened). Handle this case.
1977 bool first_search
= false;
1978 int character_to_start_searching_from
= 0;
1979 if (current_find_text_
!= text
) { // First time we search for this text.
1980 first_search
= true;
1981 std::vector
<PDFiumRange
> old_selection
= selection_
;
1983 current_find_text_
= text
;
1985 if (old_selection
.empty()) {
1986 // Start searching from the beginning of the document.
1987 next_page_to_search_
= 0;
1988 last_page_to_search_
= pages_
.size() - 1;
1989 last_character_index_to_search_
= -1;
1991 // There's a current selection, so start from it.
1992 next_page_to_search_
= old_selection
[0].page_index();
1993 last_character_index_to_search_
= old_selection
[0].char_index();
1994 character_to_start_searching_from
= old_selection
[0].char_index();
1995 last_page_to_search_
= next_page_to_search_
;
1999 int current_page
= next_page_to_search_
;
2001 if (pages_
[current_page
]->available()) {
2002 base::string16 str
= base::UTF8ToUTF16(text
);
2003 // Don't use PDFium to search for now, since it doesn't support unicode text.
2004 // Leave the code for now to avoid bit-rot, in case it's fixed later.
2007 str
, case_sensitive
, first_search
, character_to_start_searching_from
,
2011 str
, case_sensitive
, first_search
, character_to_start_searching_from
,
2015 if (!IsPageVisible(current_page
))
2016 pages_
[current_page
]->Unload();
2019 if (next_page_to_search_
!= last_page_to_search_
||
2020 (first_search
&& last_character_index_to_search_
!= -1)) {
2021 ++next_page_to_search_
;
2024 if (next_page_to_search_
== static_cast<int>(pages_
.size()))
2025 next_page_to_search_
= 0;
2026 // If there's only one page in the document and we start searching midway,
2027 // then we'll want to search the page one more time.
2028 bool end_of_search
=
2029 next_page_to_search_
== last_page_to_search_
&&
2030 // Only one page but didn't start midway.
2031 ((pages_
.size() == 1 && last_character_index_to_search_
== -1) ||
2032 // Started midway, but only 1 page and we already looped around.
2033 (pages_
.size() == 1 && !first_search
) ||
2034 // Started midway, and we've just looped around.
2035 (pages_
.size() > 1 && current_page
== next_page_to_search_
));
2037 if (end_of_search
) {
2038 // Send the final notification.
2039 client_
->NotifyNumberOfFindResultsChanged(find_results_
.size(), true);
2041 // When searching is complete, resume finding at a particular index.
2042 // Assuming the user has not clicked the find button in the meanwhile.
2043 if (resume_find_index_
.valid() && !current_find_index_
.valid()) {
2044 size_t resume_index
= resume_find_index_
.GetIndex();
2045 if (resume_index
>= find_results_
.size()) {
2046 // This might happen if the PDF has some dynamically generated text?
2049 current_find_index_
.SetIndex(resume_index
);
2050 client_
->NotifySelectedFindResultChanged(resume_index
);
2052 resume_find_index_
.Invalidate();
2054 pp::CompletionCallback callback
=
2055 find_factory_
.NewCallback(&PDFiumEngine::ContinueFind
);
2056 pp::Module::Get()->core()->CallOnMainThread(
2057 0, callback
, case_sensitive
? 1 : 0);
2061 void PDFiumEngine::SearchUsingPDFium(const base::string16
& term
,
2062 bool case_sensitive
,
2064 int character_to_start_searching_from
,
2066 // Find all the matches in the current page.
2067 unsigned long flags
= case_sensitive
? FPDF_MATCHCASE
: 0;
2068 FPDF_SCHHANDLE find
= FPDFText_FindStart(
2069 pages_
[current_page
]->GetTextPage(),
2070 reinterpret_cast<const unsigned short*>(term
.c_str()),
2071 flags
, character_to_start_searching_from
);
2073 // Note: since we search one page at a time, we don't find matches across
2074 // page boundaries. We could do this manually ourself, but it seems low
2075 // priority since Reader itself doesn't do it.
2076 while (FPDFText_FindNext(find
)) {
2077 PDFiumRange
result(pages_
[current_page
],
2078 FPDFText_GetSchResultIndex(find
),
2079 FPDFText_GetSchCount(find
));
2081 if (!first_search
&&
2082 last_character_index_to_search_
!= -1 &&
2083 result
.page_index() == last_page_to_search_
&&
2084 result
.char_index() >= last_character_index_to_search_
) {
2088 AddFindResult(result
);
2091 FPDFText_FindClose(find
);
2094 void PDFiumEngine::SearchUsingICU(const base::string16
& term
,
2095 bool case_sensitive
,
2097 int character_to_start_searching_from
,
2099 base::string16 page_text
;
2100 int text_length
= pages_
[current_page
]->GetCharCount();
2101 if (character_to_start_searching_from
) {
2102 text_length
-= character_to_start_searching_from
;
2103 } else if (!first_search
&&
2104 last_character_index_to_search_
!= -1 &&
2105 current_page
== last_page_to_search_
) {
2106 text_length
= last_character_index_to_search_
;
2108 if (text_length
<= 0)
2111 PDFiumAPIStringBufferAdapter
<base::string16
> api_string_adapter(&page_text
,
2114 unsigned short* data
=
2115 reinterpret_cast<unsigned short*>(api_string_adapter
.GetData());
2116 int written
= FPDFText_GetText(pages_
[current_page
]->GetTextPage(),
2117 character_to_start_searching_from
,
2120 api_string_adapter
.Close(written
);
2122 std::vector
<PDFEngine::Client::SearchStringResult
> results
;
2123 client_
->SearchString(
2124 page_text
.c_str(), term
.c_str(), case_sensitive
, &results
);
2125 for (size_t i
= 0; i
< results
.size(); ++i
) {
2126 // Need to map the indexes from the page text, which may have generated
2127 // characters like space etc, to character indices from the page.
2128 int temp_start
= results
[i
].start_index
+ character_to_start_searching_from
;
2129 int start
= FPDFText_GetCharIndexFromTextIndex(
2130 pages_
[current_page
]->GetTextPage(), temp_start
);
2131 int end
= FPDFText_GetCharIndexFromTextIndex(
2132 pages_
[current_page
]->GetTextPage(),
2133 temp_start
+ results
[i
].length
);
2134 AddFindResult(PDFiumRange(pages_
[current_page
], start
, end
- start
));
2138 void PDFiumEngine::AddFindResult(const PDFiumRange
& result
) {
2139 // Figure out where to insert the new location, since we could have
2140 // started searching midway and now we wrapped.
2141 size_t result_index
;
2142 int page_index
= result
.page_index();
2143 int char_index
= result
.char_index();
2144 for (result_index
= 0; result_index
< find_results_
.size(); ++result_index
) {
2145 if (find_results_
[result_index
].page_index() > page_index
||
2146 (find_results_
[result_index
].page_index() == page_index
&&
2147 find_results_
[result_index
].char_index() > char_index
)) {
2151 find_results_
.insert(find_results_
.begin() + result_index
, result
);
2154 if (current_find_index_
.valid()) {
2155 if (result_index
<= current_find_index_
.GetIndex()) {
2156 // Update the current match index
2157 size_t find_index
= current_find_index_
.IncrementIndex();
2158 DCHECK_LT(find_index
, find_results_
.size());
2159 client_
->NotifySelectedFindResultChanged(current_find_index_
.GetIndex());
2161 } else if (!resume_find_index_
.valid()) {
2162 // Both indices are invalid. Select the first match.
2163 SelectFindResult(true);
2165 client_
->NotifyNumberOfFindResultsChanged(find_results_
.size(), false);
2168 bool PDFiumEngine::SelectFindResult(bool forward
) {
2169 if (find_results_
.empty()) {
2174 SelectionChangeInvalidator
selection_invalidator(this);
2176 // Move back/forward through the search locations we previously found.
2178 const size_t last_index
= find_results_
.size() - 1;
2179 if (current_find_index_
.valid()) {
2180 size_t current_index
= current_find_index_
.GetIndex();
2182 new_index
= (current_index
>= last_index
) ? 0 : current_index
+ 1;
2184 new_index
= (current_find_index_
.GetIndex() == 0) ?
2185 last_index
: current_index
- 1;
2188 new_index
= forward
? 0 : last_index
;
2190 current_find_index_
.SetIndex(new_index
);
2192 // Update the selection before telling the client to scroll, since it could
2195 selection_
.push_back(find_results_
[current_find_index_
.GetIndex()]);
2197 // If the result is not in view, scroll to it.
2198 pp::Rect bounding_rect
;
2199 pp::Rect visible_rect
= GetVisibleRect();
2200 // Use zoom of 1.0 since visible_rect is without zoom.
2201 std::vector
<pp::Rect
> rects
;
2202 rects
= find_results_
[current_find_index_
.GetIndex()].GetScreenRects(
2203 pp::Point(), 1.0, current_rotation_
);
2204 for (size_t i
= 0; i
< rects
.size(); ++i
)
2205 bounding_rect
= bounding_rect
.Union(rects
[i
]);
2206 if (!visible_rect
.Contains(bounding_rect
)) {
2207 pp::Point center
= bounding_rect
.CenterPoint();
2208 // Make the page centered.
2209 int new_y
= static_cast<int>(center
.y() * current_zoom_
) -
2210 static_cast<int>(visible_rect
.height() * current_zoom_
/ 2);
2213 client_
->ScrollToY(new_y
);
2215 // Only move horizontally if it's not visible.
2216 if (center
.x() < visible_rect
.x() || center
.x() > visible_rect
.right()) {
2217 int new_x
= static_cast<int>(center
.x() * current_zoom_
) -
2218 static_cast<int>(visible_rect
.width() * current_zoom_
/ 2);
2221 client_
->ScrollToX(new_x
);
2225 client_
->NotifySelectedFindResultChanged(current_find_index_
.GetIndex());
2229 void PDFiumEngine::StopFind() {
2230 SelectionChangeInvalidator
selection_invalidator(this);
2234 find_results_
.clear();
2235 next_page_to_search_
= -1;
2236 last_page_to_search_
= -1;
2237 last_character_index_to_search_
= -1;
2238 current_find_index_
.Invalidate();
2239 current_find_text_
.clear();
2241 find_factory_
.CancelAll();
2244 void PDFiumEngine::GetAllScreenRectsUnion(std::vector
<PDFiumRange
>* rect_range
,
2245 const pp::Point
& offset_point
,
2246 std::vector
<pp::Rect
>* rect_vector
) {
2247 for (std::vector
<PDFiumRange
>::iterator it
= rect_range
->begin();
2248 it
!= rect_range
->end(); ++it
) {
2250 std::vector
<pp::Rect
> rects
=
2251 it
->GetScreenRects(offset_point
, current_zoom_
, current_rotation_
);
2252 for (size_t j
= 0; j
< rects
.size(); ++j
)
2253 rect
= rect
.Union(rects
[j
]);
2254 rect_vector
->push_back(rect
);
2258 void PDFiumEngine::UpdateTickMarks() {
2259 std::vector
<pp::Rect
> tickmarks
;
2260 GetAllScreenRectsUnion(&find_results_
, pp::Point(0, 0), &tickmarks
);
2261 client_
->UpdateTickMarks(tickmarks
);
2264 void PDFiumEngine::ZoomUpdated(double new_zoom_level
) {
2267 current_zoom_
= new_zoom_level
;
2269 CalculateVisiblePages();
2273 void PDFiumEngine::RotateClockwise() {
2274 current_rotation_
= (current_rotation_
+ 1) % 4;
2278 void PDFiumEngine::RotateCounterclockwise() {
2279 current_rotation_
= (current_rotation_
- 1) % 4;
2283 void PDFiumEngine::InvalidateAllPages() {
2287 client_
->Invalidate(pp::Rect(plugin_size_
));
2290 std::string
PDFiumEngine::GetSelectedText() {
2291 if (!HasPermission(PDFEngine::PERMISSION_COPY
))
2292 return std::string();
2294 base::string16 result
;
2295 base::string16 new_line_char
= base::UTF8ToUTF16("\n");
2296 for (size_t i
= 0; i
< selection_
.size(); ++i
) {
2298 selection_
[i
- 1].page_index() > selection_
[i
].page_index()) {
2299 result
= selection_
[i
].GetText() + new_line_char
+ result
;
2302 result
.append(new_line_char
);
2303 result
.append(selection_
[i
].GetText());
2307 FormatStringWithHyphens(&result
);
2308 FormatStringForOS(&result
);
2309 return base::UTF16ToUTF8(result
);
2312 std::string
PDFiumEngine::GetLinkAtPosition(const pp::Point
& point
) {
2315 int page_index
= -1;
2316 int form_type
= FPDF_FORMFIELD_UNKNOWN
;
2317 PDFiumPage::LinkTarget target
;
2318 PDFiumPage::Area area
=
2319 GetCharIndex(point
, &page_index
, &temp
, &form_type
, &target
);
2320 if (area
== PDFiumPage::WEBLINK_AREA
)
2325 bool PDFiumEngine::IsSelecting() {
2329 bool PDFiumEngine::HasPermission(DocumentPermission permission
) const {
2330 switch (permission
) {
2331 case PERMISSION_COPY
:
2332 return (permissions_
& kPDFPermissionCopyMask
) != 0;
2333 case PERMISSION_COPY_ACCESSIBLE
:
2334 return (permissions_
& kPDFPermissionCopyAccessibleMask
) != 0;
2335 case PERMISSION_PRINT_LOW_QUALITY
:
2336 return (permissions_
& kPDFPermissionPrintLowQualityMask
) != 0;
2337 case PERMISSION_PRINT_HIGH_QUALITY
:
2338 return (permissions_
& kPDFPermissionPrintLowQualityMask
) != 0 &&
2339 (permissions_
& kPDFPermissionPrintHighQualityMask
) != 0;
2345 void PDFiumEngine::SelectAll() {
2346 SelectionChangeInvalidator
selection_invalidator(this);
2349 for (size_t i
= 0; i
< pages_
.size(); ++i
)
2350 if (pages_
[i
]->available()) {
2351 selection_
.push_back(PDFiumRange(pages_
[i
], 0,
2352 pages_
[i
]->GetCharCount()));
2356 int PDFiumEngine::GetNumberOfPages() {
2357 return pages_
.size();
2360 pp::VarArray
PDFiumEngine::GetBookmarks() {
2361 pp::VarDictionary dict
= TraverseBookmarks(doc_
, NULL
);
2362 // The root bookmark contains no useful information.
2363 return pp::VarArray(dict
.Get(pp::Var("children")));
2366 int PDFiumEngine::GetNamedDestinationPage(const std::string
& destination
) {
2367 // Look for the destination.
2368 FPDF_DEST dest
= FPDF_GetNamedDestByName(doc_
, destination
.c_str());
2370 // Look for a bookmark with the same name.
2371 base::string16 destination_wide
= base::UTF8ToUTF16(destination
);
2372 FPDF_WIDESTRING destination_pdf_wide
=
2373 reinterpret_cast<FPDF_WIDESTRING
>(destination_wide
.c_str());
2374 FPDF_BOOKMARK bookmark
= FPDFBookmark_Find(doc_
, destination_pdf_wide
);
2377 dest
= FPDFBookmark_GetDest(doc_
, bookmark
);
2379 return dest
? FPDFDest_GetPageIndex(doc_
, dest
) : -1;
2382 int PDFiumEngine::GetFirstVisiblePage() {
2383 CalculateVisiblePages();
2384 return first_visible_page_
;
2387 int PDFiumEngine::GetMostVisiblePage() {
2388 CalculateVisiblePages();
2389 return most_visible_page_
;
2392 pp::Rect
PDFiumEngine::GetPageRect(int index
) {
2393 pp::Rect
rc(pages_
[index
]->rect());
2394 rc
.Inset(-kPageShadowLeft
, -kPageShadowTop
,
2395 -kPageShadowRight
, -kPageShadowBottom
);
2399 pp::Rect
PDFiumEngine::GetPageContentsRect(int index
) {
2400 return GetScreenRect(pages_
[index
]->rect());
2403 void PDFiumEngine::PaintThumbnail(pp::ImageData
* image_data
, int index
) {
2404 FPDF_BITMAP bitmap
= FPDFBitmap_CreateEx(
2405 image_data
->size().width(), image_data
->size().height(),
2406 FPDFBitmap_BGRx
, image_data
->data(), image_data
->stride());
2408 if (pages_
[index
]->available()) {
2409 FPDFBitmap_FillRect(bitmap
, 0, 0, image_data
->size().width(),
2410 image_data
->size().height(), 0xFFFFFFFF);
2412 FPDF_RenderPageBitmap(
2413 bitmap
, pages_
[index
]->GetPage(), 0, 0, image_data
->size().width(),
2414 image_data
->size().height(), 0, GetRenderingFlags());
2416 FPDFBitmap_FillRect(bitmap
, 0, 0, image_data
->size().width(),
2417 image_data
->size().height(), kPendingPageColor
);
2420 FPDFBitmap_Destroy(bitmap
);
2423 void PDFiumEngine::SetGrayscale(bool grayscale
) {
2424 render_grayscale_
= grayscale
;
2427 void PDFiumEngine::OnCallback(int id
) {
2428 if (!timers_
.count(id
))
2431 timers_
[id
].second(id
);
2432 if (timers_
.count(id
)) // The callback might delete the timer.
2433 client_
->ScheduleCallback(id
, timers_
[id
].first
);
2436 std::string
PDFiumEngine::GetPageAsJSON(int index
) {
2437 if (!(HasPermission(PERMISSION_COPY
) ||
2438 HasPermission(PERMISSION_COPY_ACCESSIBLE
))) {
2442 if (index
< 0 || static_cast<size_t>(index
) > pages_
.size() - 1)
2445 scoped_ptr
<base::Value
> node(
2446 pages_
[index
]->GetAccessibleContentAsValue(current_rotation_
));
2447 std::string page_json
;
2448 base::JSONWriter::Write(node
.get(), &page_json
);
2452 bool PDFiumEngine::GetPrintScaling() {
2453 return !!FPDF_VIEWERREF_GetPrintScaling(doc_
);
2456 int PDFiumEngine::GetCopiesToPrint() {
2457 return FPDF_VIEWERREF_GetNumCopies(doc_
);
2460 int PDFiumEngine::GetDuplexType() {
2461 return static_cast<int>(FPDF_VIEWERREF_GetDuplex(doc_
));
2464 bool PDFiumEngine::GetPageSizeAndUniformity(pp::Size
* size
) {
2468 pp::Size page_size
= GetPageSize(0);
2469 for (size_t i
= 1; i
< pages_
.size(); ++i
) {
2470 if (page_size
!= GetPageSize(i
))
2474 // Convert |page_size| back to points.
2476 ConvertUnit(page_size
.width(), kPixelsPerInch
, kPointsPerInch
));
2478 ConvertUnit(page_size
.height(), kPixelsPerInch
, kPointsPerInch
));
2482 void PDFiumEngine::AppendBlankPages(int num_pages
) {
2483 DCHECK(num_pages
!= 0);
2489 pending_pages_
.clear();
2491 // Delete all pages except the first one.
2492 while (pages_
.size() > 1) {
2493 delete pages_
.back();
2495 FPDFPage_Delete(doc_
, pages_
.size());
2498 // Calculate document size and all page sizes.
2499 std::vector
<pp::Rect
> page_rects
;
2500 pp::Size page_size
= GetPageSize(0);
2501 page_size
.Enlarge(kPageShadowLeft
+ kPageShadowRight
,
2502 kPageShadowTop
+ kPageShadowBottom
);
2503 pp::Size old_document_size
= document_size_
;
2504 document_size_
= pp::Size(page_size
.width(), 0);
2505 for (int i
= 0; i
< num_pages
; ++i
) {
2507 // Add space for horizontal separator.
2508 document_size_
.Enlarge(0, kPageSeparatorThickness
);
2511 pp::Rect
rect(pp::Point(0, document_size_
.height()), page_size
);
2512 page_rects
.push_back(rect
);
2514 document_size_
.Enlarge(0, page_size
.height());
2517 // Create blank pages.
2518 for (int i
= 1; i
< num_pages
; ++i
) {
2519 pp::Rect
page_rect(page_rects
[i
]);
2520 page_rect
.Inset(kPageShadowLeft
, kPageShadowTop
,
2521 kPageShadowRight
, kPageShadowBottom
);
2522 double width_in_points
= ConvertUnitDouble(page_rect
.width(),
2525 double height_in_points
= ConvertUnitDouble(page_rect
.height(),
2528 FPDFPage_New(doc_
, i
, width_in_points
, height_in_points
);
2529 pages_
.push_back(new PDFiumPage(this, i
, page_rect
, true));
2532 CalculateVisiblePages();
2533 if (document_size_
!= old_document_size
)
2534 client_
->DocumentSizeUpdated(document_size_
);
2537 void PDFiumEngine::LoadDocument() {
2538 // Check if the document is ready for loading. If it isn't just bail for now,
2539 // we will call LoadDocument() again later.
2540 if (!doc_
&& !doc_loader_
.IsDocumentComplete() &&
2541 !FPDFAvail_IsDocAvail(fpdf_availability_
, &download_hints_
)) {
2545 // If we're in the middle of getting a password, just return. We will retry
2546 // loading the document after we get the password anyway.
2547 if (getting_password_
)
2550 ScopedUnsupportedFeature
scoped_unsupported_feature(this);
2551 bool needs_password
= false;
2552 if (TryLoadingDoc(false, std::string(), &needs_password
)) {
2553 ContinueLoadingDocument(false, std::string());
2557 GetPasswordAndLoad();
2559 client_
->DocumentLoadFailed();
2562 bool PDFiumEngine::TryLoadingDoc(bool with_password
,
2563 const std::string
& password
,
2564 bool* needs_password
) {
2565 *needs_password
= false;
2569 const char* password_cstr
= NULL
;
2570 if (with_password
) {
2571 password_cstr
= password
.c_str();
2572 password_tries_remaining_
--;
2574 if (doc_loader_
.IsDocumentComplete())
2575 doc_
= FPDF_LoadCustomDocument(&file_access_
, password_cstr
);
2577 doc_
= FPDFAvail_GetDocument(fpdf_availability_
, password_cstr
);
2579 if (!doc_
&& FPDF_GetLastError() == FPDF_ERR_PASSWORD
)
2580 *needs_password
= true;
2582 return doc_
!= NULL
;
2585 void PDFiumEngine::GetPasswordAndLoad() {
2586 getting_password_
= true;
2587 DCHECK(!doc_
&& FPDF_GetLastError() == FPDF_ERR_PASSWORD
);
2588 client_
->GetDocumentPassword(password_factory_
.NewCallbackWithOutput(
2589 &PDFiumEngine::OnGetPasswordComplete
));
2592 void PDFiumEngine::OnGetPasswordComplete(int32_t result
,
2593 const pp::Var
& password
) {
2594 getting_password_
= false;
2596 bool password_given
= false;
2597 std::string password_text
;
2598 if (result
== PP_OK
&& password
.is_string()) {
2599 password_text
= password
.AsString();
2600 if (!password_text
.empty())
2601 password_given
= true;
2603 ContinueLoadingDocument(password_given
, password_text
);
2606 void PDFiumEngine::ContinueLoadingDocument(
2608 const std::string
& password
) {
2609 ScopedUnsupportedFeature
scoped_unsupported_feature(this);
2611 bool needs_password
= false;
2612 bool loaded
= TryLoadingDoc(has_password
, password
, &needs_password
);
2613 bool password_incorrect
= !loaded
&& has_password
&& needs_password
;
2614 if (password_incorrect
&& password_tries_remaining_
> 0) {
2615 GetPasswordAndLoad();
2620 client_
->DocumentLoadFailed();
2624 if (FPDFDoc_GetPageMode(doc_
) == PAGEMODE_USEOUTLINES
)
2625 client_
->DocumentHasUnsupportedFeature("Bookmarks");
2627 permissions_
= FPDF_GetDocPermissions(doc_
);
2630 // Only returns 0 when data isn't available. If form data is downloaded, or
2631 // if this isn't a form, returns positive values.
2632 if (!doc_loader_
.IsDocumentComplete() &&
2633 !FPDFAvail_IsFormAvail(fpdf_availability_
, &download_hints_
)) {
2637 form_
= FPDFDOC_InitFormFillEnvironment(
2638 doc_
, static_cast<FPDF_FORMFILLINFO
*>(this));
2643 FPDF_SetFormFieldHighlightColor(form_
, 0, kFormHighlightColor
);
2644 FPDF_SetFormFieldHighlightAlpha(form_
, kFormHighlightAlpha
);
2647 if (!doc_loader_
.IsDocumentComplete()) {
2648 // Check if the first page is available. In a linearized PDF, that is not
2649 // always page 0. Doing this gives us the default page size, since when the
2650 // document is available, the first page is available as well.
2651 CheckPageAvailable(FPDFAvail_GetFirstPageNum(doc_
), &pending_pages_
);
2654 LoadPageInfo(false);
2656 if (doc_loader_
.IsDocumentComplete())
2657 FinishLoadingDocument();
2660 void PDFiumEngine::LoadPageInfo(bool reload
) {
2661 pending_pages_
.clear();
2662 pp::Size old_document_size
= document_size_
;
2663 document_size_
= pp::Size();
2664 std::vector
<pp::Rect
> page_rects
;
2665 int page_count
= FPDF_GetPageCount(doc_
);
2666 bool doc_complete
= doc_loader_
.IsDocumentComplete();
2667 for (int i
= 0; i
< page_count
; ++i
) {
2669 // Add space for horizontal separator.
2670 document_size_
.Enlarge(0, kPageSeparatorThickness
);
2673 // Get page availability. If reload==false, and document is not loaded yet
2674 // (we are using async loading) - mark all pages as unavailable.
2675 // If reload==true (we have document constructed already), get page
2676 // availability flag from already existing PDFiumPage class.
2677 bool page_available
= reload
? pages_
[i
]->available() : doc_complete
;
2679 pp::Size size
= page_available
? GetPageSize(i
) : default_page_size_
;
2680 size
.Enlarge(kPageShadowLeft
+ kPageShadowRight
,
2681 kPageShadowTop
+ kPageShadowBottom
);
2682 pp::Rect
rect(pp::Point(0, document_size_
.height()), size
);
2683 page_rects
.push_back(rect
);
2685 if (size
.width() > document_size_
.width())
2686 document_size_
.set_width(size
.width());
2688 document_size_
.Enlarge(0, size
.height());
2691 for (int i
= 0; i
< page_count
; ++i
) {
2692 // Center pages relative to the entire document.
2693 page_rects
[i
].set_x((document_size_
.width() - page_rects
[i
].width()) / 2);
2694 pp::Rect
page_rect(page_rects
[i
]);
2695 page_rect
.Inset(kPageShadowLeft
, kPageShadowTop
,
2696 kPageShadowRight
, kPageShadowBottom
);
2698 pages_
[i
]->set_rect(page_rect
);
2700 pages_
.push_back(new PDFiumPage(this, i
, page_rect
, doc_complete
));
2704 CalculateVisiblePages();
2705 if (document_size_
!= old_document_size
)
2706 client_
->DocumentSizeUpdated(document_size_
);
2709 void PDFiumEngine::CalculateVisiblePages() {
2710 // Clear pending requests queue, since it may contain requests to the pages
2711 // that are already invisible (after scrolling for example).
2712 pending_pages_
.clear();
2713 doc_loader_
.ClearPendingRequests();
2715 visible_pages_
.clear();
2716 pp::Rect
visible_rect(plugin_size_
);
2717 for (size_t i
= 0; i
< pages_
.size(); ++i
) {
2718 // Check an entire PageScreenRect, since we might need to repaint side
2719 // borders and shadows even if the page itself is not visible.
2720 // For example, when user use pdf with different page sizes and zoomed in
2721 // outside page area.
2722 if (visible_rect
.Intersects(GetPageScreenRect(i
))) {
2723 visible_pages_
.push_back(i
);
2724 CheckPageAvailable(i
, &pending_pages_
);
2726 // Need to unload pages when we're not using them, since some PDFs use a
2727 // lot of memory. See http://crbug.com/48791
2728 if (defer_page_unload_
) {
2729 deferred_page_unloads_
.push_back(i
);
2731 pages_
[i
]->Unload();
2734 // If the last mouse down was on a page that's no longer visible, reset
2735 // that variable so that we don't send keyboard events to it (the focus
2736 // will be lost when the page is first closed anyways).
2737 if (static_cast<int>(i
) == last_page_mouse_down_
)
2738 last_page_mouse_down_
= -1;
2742 // Any pending highlighting of form fields will be invalid since these are in
2743 // screen coordinates.
2744 form_highlights_
.clear();
2746 if (visible_pages_
.size() == 0)
2747 first_visible_page_
= -1;
2749 first_visible_page_
= visible_pages_
.front();
2751 int most_visible_page
= first_visible_page_
;
2752 // Check if the next page is more visible than the first one.
2753 if (most_visible_page
!= -1 &&
2754 pages_
.size() > 0 &&
2755 most_visible_page
< static_cast<int>(pages_
.size()) - 1) {
2757 visible_rect
.Intersect(GetPageScreenRect(most_visible_page
));
2759 visible_rect
.Intersect(GetPageScreenRect(most_visible_page
+ 1));
2760 if (rc_next
.height() > rc_first
.height())
2761 most_visible_page
++;
2764 SetCurrentPage(most_visible_page
);
2767 bool PDFiumEngine::IsPageVisible(int index
) const {
2768 for (size_t i
= 0; i
< visible_pages_
.size(); ++i
) {
2769 if (visible_pages_
[i
] == index
)
2776 bool PDFiumEngine::CheckPageAvailable(int index
, std::vector
<int>* pending
) {
2777 if (!doc_
|| !form_
)
2780 if (static_cast<int>(pages_
.size()) > index
&& pages_
[index
]->available())
2783 if (!FPDFAvail_IsPageAvail(fpdf_availability_
, index
, &download_hints_
)) {
2785 for (j
= 0; j
< pending
->size(); ++j
) {
2786 if ((*pending
)[j
] == index
)
2790 if (j
== pending
->size())
2791 pending
->push_back(index
);
2795 if (static_cast<int>(pages_
.size()) > index
)
2796 pages_
[index
]->set_available(true);
2797 if (!default_page_size_
.GetArea())
2798 default_page_size_
= GetPageSize(index
);
2802 pp::Size
PDFiumEngine::GetPageSize(int index
) {
2804 double width_in_points
= 0;
2805 double height_in_points
= 0;
2806 int rv
= FPDF_GetPageSizeByIndex(
2807 doc_
, index
, &width_in_points
, &height_in_points
);
2810 int width_in_pixels
= static_cast<int>(
2811 ConvertUnitDouble(width_in_points
, kPointsPerInch
, kPixelsPerInch
));
2812 int height_in_pixels
= static_cast<int>(
2813 ConvertUnitDouble(height_in_points
, kPointsPerInch
, kPixelsPerInch
));
2814 if (current_rotation_
% 2 == 1)
2815 std::swap(width_in_pixels
, height_in_pixels
);
2816 size
= pp::Size(width_in_pixels
, height_in_pixels
);
2821 int PDFiumEngine::StartPaint(int page_index
, const pp::Rect
& dirty
) {
2822 // For the first time we hit paint, do nothing and just record the paint for
2823 // the next callback. This keeps the UI responsive in case the user is doing
2824 // a lot of scrolling.
2825 ProgressivePaint progressive
;
2826 progressive
.rect
= dirty
;
2827 progressive
.page_index
= page_index
;
2828 progressive
.bitmap
= NULL
;
2829 progressive
.painted_
= false;
2830 progressive_paints_
.push_back(progressive
);
2831 return progressive_paints_
.size() - 1;
2834 bool PDFiumEngine::ContinuePaint(int progressive_index
,
2835 pp::ImageData
* image_data
) {
2836 DCHECK_GE(progressive_index
, 0);
2837 DCHECK_LT(static_cast<size_t>(progressive_index
), progressive_paints_
.size());
2840 #if defined(OS_LINUX)
2841 g_last_instance_id
= client_
->GetPluginInstance()->pp_instance();
2845 FPDF_BITMAP bitmap
= progressive_paints_
[progressive_index
].bitmap
;
2846 int page_index
= progressive_paints_
[progressive_index
].page_index
;
2847 DCHECK_GE(page_index
, 0);
2848 DCHECK_LT(static_cast<size_t>(page_index
), pages_
.size());
2849 FPDF_PAGE page
= pages_
[page_index
]->GetPage();
2851 last_progressive_start_time_
= base::Time::Now();
2853 rv
= FPDF_RenderPage_Continue(page
, static_cast<IFSDK_PAUSE
*>(this));
2855 pp::Rect dirty
= progressive_paints_
[progressive_index
].rect
;
2856 bitmap
= CreateBitmap(dirty
, image_data
);
2857 int start_x
, start_y
, size_x
, size_y
;
2858 GetPDFiumRect(page_index
, dirty
, &start_x
, &start_y
, &size_x
, &size_y
);
2859 FPDFBitmap_FillRect(bitmap
, start_x
, start_y
, size_x
, size_y
, 0xFFFFFFFF);
2860 rv
= FPDF_RenderPageBitmap_Start(
2861 bitmap
, page
, start_x
, start_y
, size_x
, size_y
,
2863 GetRenderingFlags(), static_cast<IFSDK_PAUSE
*>(this));
2864 progressive_paints_
[progressive_index
].bitmap
= bitmap
;
2866 return rv
!= FPDF_RENDER_TOBECOUNTINUED
;
2869 void PDFiumEngine::FinishPaint(int progressive_index
,
2870 pp::ImageData
* image_data
) {
2871 DCHECK_GE(progressive_index
, 0);
2872 DCHECK_LT(static_cast<size_t>(progressive_index
), progressive_paints_
.size());
2875 int page_index
= progressive_paints_
[progressive_index
].page_index
;
2876 pp::Rect dirty_in_screen
= progressive_paints_
[progressive_index
].rect
;
2877 FPDF_BITMAP bitmap
= progressive_paints_
[progressive_index
].bitmap
;
2878 int start_x
, start_y
, size_x
, size_y
;
2880 page_index
, dirty_in_screen
, &start_x
, &start_y
, &size_x
, &size_y
);
2884 form_
, bitmap
, pages_
[page_index
]->GetPage(), start_x
, start_y
, size_x
,
2885 size_y
, current_rotation_
, GetRenderingFlags());
2887 FillPageSides(progressive_index
);
2889 // Paint the page shadows.
2890 PaintPageShadow(progressive_index
, image_data
);
2892 DrawSelections(progressive_index
, image_data
);
2894 FPDF_RenderPage_Close(pages_
[page_index
]->GetPage());
2895 FPDFBitmap_Destroy(bitmap
);
2896 progressive_paints_
.erase(progressive_paints_
.begin() + progressive_index
);
2898 client_
->DocumentPaintOccurred();
2901 void PDFiumEngine::CancelPaints() {
2902 for (size_t i
= 0; i
< progressive_paints_
.size(); ++i
) {
2903 FPDF_RenderPage_Close(pages_
[progressive_paints_
[i
].page_index
]->GetPage());
2904 FPDFBitmap_Destroy(progressive_paints_
[i
].bitmap
);
2906 progressive_paints_
.clear();
2909 void PDFiumEngine::FillPageSides(int progressive_index
) {
2910 DCHECK_GE(progressive_index
, 0);
2911 DCHECK_LT(static_cast<size_t>(progressive_index
), progressive_paints_
.size());
2913 int page_index
= progressive_paints_
[progressive_index
].page_index
;
2914 pp::Rect dirty_in_screen
= progressive_paints_
[progressive_index
].rect
;
2915 FPDF_BITMAP bitmap
= progressive_paints_
[progressive_index
].bitmap
;
2917 pp::Rect page_rect
= pages_
[page_index
]->rect();
2918 if (page_rect
.x() > 0) {
2920 page_rect
.y() - kPageShadowTop
,
2921 page_rect
.x() - kPageShadowLeft
,
2922 page_rect
.height() + kPageShadowTop
+
2923 kPageShadowBottom
+ kPageSeparatorThickness
);
2924 left
= GetScreenRect(left
).Intersect(dirty_in_screen
);
2926 FPDFBitmap_FillRect(bitmap
, left
.x() - dirty_in_screen
.x(),
2927 left
.y() - dirty_in_screen
.y(), left
.width(),
2928 left
.height(), client_
->GetBackgroundColor());
2931 if (page_rect
.right() < document_size_
.width()) {
2932 pp::Rect
right(page_rect
.right() + kPageShadowRight
,
2933 page_rect
.y() - kPageShadowTop
,
2934 document_size_
.width() - page_rect
.right() -
2936 page_rect
.height() + kPageShadowTop
+
2937 kPageShadowBottom
+ kPageSeparatorThickness
);
2938 right
= GetScreenRect(right
).Intersect(dirty_in_screen
);
2940 FPDFBitmap_FillRect(bitmap
, right
.x() - dirty_in_screen
.x(),
2941 right
.y() - dirty_in_screen
.y(), right
.width(),
2942 right
.height(), client_
->GetBackgroundColor());
2946 pp::Rect
bottom(page_rect
.x() - kPageShadowLeft
,
2947 page_rect
.bottom() + kPageShadowBottom
,
2948 page_rect
.width() + kPageShadowLeft
+ kPageShadowRight
,
2949 kPageSeparatorThickness
);
2950 bottom
= GetScreenRect(bottom
).Intersect(dirty_in_screen
);
2952 FPDFBitmap_FillRect(bitmap
, bottom
.x() - dirty_in_screen
.x(),
2953 bottom
.y() - dirty_in_screen
.y(), bottom
.width(),
2954 bottom
.height(), client_
->GetBackgroundColor());
2957 void PDFiumEngine::PaintPageShadow(int progressive_index
,
2958 pp::ImageData
* image_data
) {
2959 DCHECK_GE(progressive_index
, 0);
2960 DCHECK_LT(static_cast<size_t>(progressive_index
), progressive_paints_
.size());
2963 int page_index
= progressive_paints_
[progressive_index
].page_index
;
2964 pp::Rect dirty_in_screen
= progressive_paints_
[progressive_index
].rect
;
2965 pp::Rect page_rect
= pages_
[page_index
]->rect();
2966 pp::Rect
shadow_rect(page_rect
);
2967 shadow_rect
.Inset(-kPageShadowLeft
, -kPageShadowTop
,
2968 -kPageShadowRight
, -kPageShadowBottom
);
2970 // Due to the rounding errors of the GetScreenRect it is possible to get
2971 // different size shadows on the left and right sides even they are defined
2972 // the same. To fix this issue let's calculate shadow rect and then shrink
2973 // it by the size of the shadows.
2974 shadow_rect
= GetScreenRect(shadow_rect
);
2975 page_rect
= shadow_rect
;
2977 page_rect
.Inset(static_cast<int>(ceil(kPageShadowLeft
* current_zoom_
)),
2978 static_cast<int>(ceil(kPageShadowTop
* current_zoom_
)),
2979 static_cast<int>(ceil(kPageShadowRight
* current_zoom_
)),
2980 static_cast<int>(ceil(kPageShadowBottom
* current_zoom_
)));
2982 DrawPageShadow(page_rect
, shadow_rect
, dirty_in_screen
, image_data
);
2985 void PDFiumEngine::DrawSelections(int progressive_index
,
2986 pp::ImageData
* image_data
) {
2987 DCHECK_GE(progressive_index
, 0);
2988 DCHECK_LT(static_cast<size_t>(progressive_index
), progressive_paints_
.size());
2991 int page_index
= progressive_paints_
[progressive_index
].page_index
;
2992 pp::Rect dirty_in_screen
= progressive_paints_
[progressive_index
].rect
;
2994 void* region
= NULL
;
2996 GetRegion(dirty_in_screen
.point(), image_data
, ®ion
, &stride
);
2998 std::vector
<pp::Rect
> highlighted_rects
;
2999 pp::Rect visible_rect
= GetVisibleRect();
3000 for (size_t k
= 0; k
< selection_
.size(); ++k
) {
3001 if (selection_
[k
].page_index() != page_index
)
3003 std::vector
<pp::Rect
> rects
= selection_
[k
].GetScreenRects(
3004 visible_rect
.point(), current_zoom_
, current_rotation_
);
3005 for (size_t j
= 0; j
< rects
.size(); ++j
) {
3006 pp::Rect visible_selection
= rects
[j
].Intersect(dirty_in_screen
);
3007 if (visible_selection
.IsEmpty())
3010 visible_selection
.Offset(
3011 -dirty_in_screen
.point().x(), -dirty_in_screen
.point().y());
3012 Highlight(region
, stride
, visible_selection
, &highlighted_rects
);
3016 for (size_t k
= 0; k
< form_highlights_
.size(); ++k
) {
3017 pp::Rect visible_selection
= form_highlights_
[k
].Intersect(dirty_in_screen
);
3018 if (visible_selection
.IsEmpty())
3021 visible_selection
.Offset(
3022 -dirty_in_screen
.point().x(), -dirty_in_screen
.point().y());
3023 Highlight(region
, stride
, visible_selection
, &highlighted_rects
);
3025 form_highlights_
.clear();
3028 void PDFiumEngine::PaintUnavailablePage(int page_index
,
3029 const pp::Rect
& dirty
,
3030 pp::ImageData
* image_data
) {
3031 int start_x
, start_y
, size_x
, size_y
;
3032 GetPDFiumRect(page_index
, dirty
, &start_x
, &start_y
, &size_x
, &size_y
);
3033 FPDF_BITMAP bitmap
= CreateBitmap(dirty
, image_data
);
3034 FPDFBitmap_FillRect(bitmap
, start_x
, start_y
, size_x
, size_y
,
3037 pp::Rect
loading_text_in_screen(
3038 pages_
[page_index
]->rect().width() / 2,
3039 pages_
[page_index
]->rect().y() + kLoadingTextVerticalOffset
, 0, 0);
3040 loading_text_in_screen
= GetScreenRect(loading_text_in_screen
);
3041 FPDFBitmap_Destroy(bitmap
);
3044 int PDFiumEngine::GetProgressiveIndex(int page_index
) const {
3045 for (size_t i
= 0; i
< progressive_paints_
.size(); ++i
) {
3046 if (progressive_paints_
[i
].page_index
== page_index
)
3052 FPDF_BITMAP
PDFiumEngine::CreateBitmap(const pp::Rect
& rect
,
3053 pp::ImageData
* image_data
) const {
3056 GetRegion(rect
.point(), image_data
, ®ion
, &stride
);
3059 return FPDFBitmap_CreateEx(
3060 rect
.width(), rect
.height(), FPDFBitmap_BGRx
, region
, stride
);
3063 void PDFiumEngine::GetPDFiumRect(
3064 int page_index
, const pp::Rect
& rect
, int* start_x
, int* start_y
,
3065 int* size_x
, int* size_y
) const {
3066 pp::Rect page_rect
= GetScreenRect(pages_
[page_index
]->rect());
3067 page_rect
.Offset(-rect
.x(), -rect
.y());
3069 *start_x
= page_rect
.x();
3070 *start_y
= page_rect
.y();
3071 *size_x
= page_rect
.width();
3072 *size_y
= page_rect
.height();
3075 int PDFiumEngine::GetRenderingFlags() const {
3076 int flags
= FPDF_LCD_TEXT
| FPDF_NO_CATCH
;
3077 if (render_grayscale_
)
3078 flags
|= FPDF_GRAYSCALE
;
3079 if (client_
->IsPrintPreview())
3080 flags
|= FPDF_PRINTING
;
3084 pp::Rect
PDFiumEngine::GetVisibleRect() const {
3086 rv
.set_x(static_cast<int>(position_
.x() / current_zoom_
));
3087 rv
.set_y(static_cast<int>(position_
.y() / current_zoom_
));
3088 rv
.set_width(static_cast<int>(ceil(plugin_size_
.width() / current_zoom_
)));
3089 rv
.set_height(static_cast<int>(ceil(plugin_size_
.height() / current_zoom_
)));
3093 pp::Rect
PDFiumEngine::GetPageScreenRect(int page_index
) const {
3094 // Since we use this rect for creating the PDFium bitmap, also include other
3095 // areas around the page that we might need to update such as the page
3096 // separator and the sides if the page is narrower than the document.
3097 return GetScreenRect(pp::Rect(
3099 pages_
[page_index
]->rect().y() - kPageShadowTop
,
3100 document_size_
.width(),
3101 pages_
[page_index
]->rect().height() + kPageShadowTop
+
3102 kPageShadowBottom
+ kPageSeparatorThickness
));
3105 pp::Rect
PDFiumEngine::GetScreenRect(const pp::Rect
& rect
) const {
3108 static_cast<int>(ceil(rect
.right() * current_zoom_
- position_
.x()));
3110 static_cast<int>(ceil(rect
.bottom() * current_zoom_
- position_
.y()));
3112 rv
.set_x(static_cast<int>(rect
.x() * current_zoom_
- position_
.x()));
3113 rv
.set_y(static_cast<int>(rect
.y() * current_zoom_
- position_
.y()));
3114 rv
.set_width(right
- rv
.x());
3115 rv
.set_height(bottom
- rv
.y());
3119 void PDFiumEngine::Highlight(void* buffer
,
3121 const pp::Rect
& rect
,
3122 std::vector
<pp::Rect
>* highlighted_rects
) {
3126 pp::Rect new_rect
= rect
;
3127 for (size_t i
= 0; i
< highlighted_rects
->size(); ++i
)
3128 new_rect
= new_rect
.Subtract((*highlighted_rects
)[i
]);
3130 highlighted_rects
->push_back(new_rect
);
3131 int l
= new_rect
.x();
3132 int t
= new_rect
.y();
3133 int w
= new_rect
.width();
3134 int h
= new_rect
.height();
3136 for (int y
= t
; y
< t
+ h
; ++y
) {
3137 for (int x
= l
; x
< l
+ w
; ++x
) {
3138 uint8
* pixel
= static_cast<uint8
*>(buffer
) + y
* stride
+ x
* 4;
3139 // This is our highlight color.
3140 pixel
[0] = static_cast<uint8
>(
3141 pixel
[0] * (kHighlightColorB
/ 255.0));
3142 pixel
[1] = static_cast<uint8
>(
3143 pixel
[1] * (kHighlightColorG
/ 255.0));
3144 pixel
[2] = static_cast<uint8
>(
3145 pixel
[2] * (kHighlightColorR
/ 255.0));
3150 PDFiumEngine::SelectionChangeInvalidator::SelectionChangeInvalidator(
3151 PDFiumEngine
* engine
) : engine_(engine
) {
3152 previous_origin_
= engine_
->GetVisibleRect().point();
3153 GetVisibleSelectionsScreenRects(&old_selections_
);
3156 PDFiumEngine::SelectionChangeInvalidator::~SelectionChangeInvalidator() {
3157 // Offset the old selections if the document scrolled since we recorded them.
3158 pp::Point offset
= previous_origin_
- engine_
->GetVisibleRect().point();
3159 for (size_t i
= 0; i
< old_selections_
.size(); ++i
)
3160 old_selections_
[i
].Offset(offset
);
3162 std::vector
<pp::Rect
> new_selections
;
3163 GetVisibleSelectionsScreenRects(&new_selections
);
3164 for (size_t i
= 0; i
< new_selections
.size(); ++i
) {
3165 for (size_t j
= 0; j
< old_selections_
.size(); ++j
) {
3166 if (!old_selections_
[j
].IsEmpty() &&
3167 new_selections
[i
] == old_selections_
[j
]) {
3168 // Rectangle was selected before and after, so no need to invalidate it.
3169 // Mark the rectangles by setting them to empty.
3170 new_selections
[i
] = old_selections_
[j
] = pp::Rect();
3176 for (size_t i
= 0; i
< old_selections_
.size(); ++i
) {
3177 if (!old_selections_
[i
].IsEmpty())
3178 engine_
->client_
->Invalidate(old_selections_
[i
]);
3180 for (size_t i
= 0; i
< new_selections
.size(); ++i
) {
3181 if (!new_selections
[i
].IsEmpty())
3182 engine_
->client_
->Invalidate(new_selections
[i
]);
3184 engine_
->OnSelectionChanged();
3188 PDFiumEngine::SelectionChangeInvalidator::GetVisibleSelectionsScreenRects(
3189 std::vector
<pp::Rect
>* rects
) {
3190 pp::Rect visible_rect
= engine_
->GetVisibleRect();
3191 for (size_t i
= 0; i
< engine_
->selection_
.size(); ++i
) {
3192 int page_index
= engine_
->selection_
[i
].page_index();
3193 if (!engine_
->IsPageVisible(page_index
))
3194 continue; // This selection is on a page that's not currently visible.
3196 std::vector
<pp::Rect
> selection_rects
=
3197 engine_
->selection_
[i
].GetScreenRects(
3198 visible_rect
.point(),
3199 engine_
->current_zoom_
,
3200 engine_
->current_rotation_
);
3201 rects
->insert(rects
->end(), selection_rects
.begin(), selection_rects
.end());
3205 PDFiumEngine::MouseDownState::MouseDownState(
3206 const PDFiumPage::Area
& area
,
3207 const PDFiumPage::LinkTarget
& target
)
3208 : area_(area
), target_(target
) {
3211 PDFiumEngine::MouseDownState::~MouseDownState() {
3214 void PDFiumEngine::MouseDownState::Set(const PDFiumPage::Area
& area
,
3215 const PDFiumPage::LinkTarget
& target
) {
3220 void PDFiumEngine::MouseDownState::Reset() {
3221 area_
= PDFiumPage::NONSELECTABLE_AREA
;
3222 target_
= PDFiumPage::LinkTarget();
3225 bool PDFiumEngine::MouseDownState::Matches(
3226 const PDFiumPage::Area
& area
,
3227 const PDFiumPage::LinkTarget
& target
) const {
3228 if (area_
== area
) {
3229 if (area
== PDFiumPage::WEBLINK_AREA
)
3230 return target_
.url
== target
.url
;
3231 if (area
== PDFiumPage::DOCLINK_AREA
)
3232 return target_
.page
== target
.page
;
3238 PDFiumEngine::FindTextIndex::FindTextIndex()
3239 : valid_(false), index_(0) {
3242 PDFiumEngine::FindTextIndex::~FindTextIndex() {
3245 void PDFiumEngine::FindTextIndex::Invalidate() {
3249 size_t PDFiumEngine::FindTextIndex::GetIndex() const {
3254 void PDFiumEngine::FindTextIndex::SetIndex(size_t index
) {
3259 size_t PDFiumEngine::FindTextIndex::IncrementIndex() {
3264 void PDFiumEngine::DeviceToPage(int page_index
,
3269 *page_x
= *page_y
= 0;
3270 int temp_x
= static_cast<int>((device_x
+ position_
.x())/ current_zoom_
-
3271 pages_
[page_index
]->rect().x());
3272 int temp_y
= static_cast<int>((device_y
+ position_
.y())/ current_zoom_
-
3273 pages_
[page_index
]->rect().y());
3275 pages_
[page_index
]->GetPage(), 0, 0,
3276 pages_
[page_index
]->rect().width(), pages_
[page_index
]->rect().height(),
3277 current_rotation_
, temp_x
, temp_y
, page_x
, page_y
);
3280 int PDFiumEngine::GetVisiblePageIndex(FPDF_PAGE page
) {
3281 for (size_t i
= 0; i
< visible_pages_
.size(); ++i
) {
3282 if (pages_
[visible_pages_
[i
]]->GetPage() == page
)
3283 return visible_pages_
[i
];
3288 void PDFiumEngine::SetCurrentPage(int index
) {
3289 if (index
== most_visible_page_
|| !form_
)
3291 if (most_visible_page_
!= -1 && called_do_document_action_
) {
3292 FPDF_PAGE old_page
= pages_
[most_visible_page_
]->GetPage();
3293 FORM_DoPageAAction(old_page
, form_
, FPDFPAGE_AACTION_CLOSE
);
3295 most_visible_page_
= index
;
3296 #if defined(OS_LINUX)
3297 g_last_instance_id
= client_
->GetPluginInstance()->pp_instance();
3299 if (most_visible_page_
!= -1 && called_do_document_action_
) {
3300 FPDF_PAGE new_page
= pages_
[most_visible_page_
]->GetPage();
3301 FORM_DoPageAAction(new_page
, form_
, FPDFPAGE_AACTION_OPEN
);
3305 void PDFiumEngine::TransformPDFPageForPrinting(
3307 const PP_PrintSettings_Dev
& print_settings
) {
3308 // Get the source page width and height in points.
3309 const double src_page_width
= FPDF_GetPageWidth(page
);
3310 const double src_page_height
= FPDF_GetPageHeight(page
);
3312 const int src_page_rotation
= FPDFPage_GetRotation(page
);
3313 const bool fit_to_page
= print_settings
.print_scaling_option
==
3314 PP_PRINTSCALINGOPTION_FIT_TO_PRINTABLE_AREA
;
3316 pp::Size
page_size(print_settings
.paper_size
);
3317 pp::Rect
content_rect(print_settings
.printable_area
);
3318 const bool rotated
= (src_page_rotation
% 2 == 1);
3319 SetPageSizeAndContentRect(rotated
,
3320 src_page_width
> src_page_height
,
3324 // Compute the screen page width and height in points.
3325 const int actual_page_width
=
3326 rotated
? page_size
.height() : page_size
.width();
3327 const int actual_page_height
=
3328 rotated
? page_size
.width() : page_size
.height();
3330 const double scale_factor
= CalculateScaleFactor(fit_to_page
, content_rect
,
3332 src_page_height
, rotated
);
3334 // Calculate positions for the clip box.
3335 ClipBox source_clip_box
;
3336 CalculateClipBoxBoundary(page
, scale_factor
, rotated
, &source_clip_box
);
3338 // Calculate the translation offset values.
3339 double offset_x
= 0;
3340 double offset_y
= 0;
3342 CalculateScaledClipBoxOffset(content_rect
, source_clip_box
, &offset_x
,
3345 CalculateNonScaledClipBoxOffset(content_rect
, src_page_rotation
,
3346 actual_page_width
, actual_page_height
,
3347 source_clip_box
, &offset_x
, &offset_y
);
3350 // Reset the media box and crop box. When the page has crop box and media box,
3351 // the plugin will display the crop box contents and not the entire media box.
3352 // If the pages have different crop box values, the plugin will display a
3353 // document of multiple page sizes. To give better user experience, we
3354 // decided to have same crop box and media box values. Hence, the user will
3355 // see a list of uniform pages.
3356 FPDFPage_SetMediaBox(page
, 0, 0, page_size
.width(), page_size
.height());
3357 FPDFPage_SetCropBox(page
, 0, 0, page_size
.width(), page_size
.height());
3359 // Transformation is not required, return. Do this check only after updating
3360 // the media box and crop box. For more detailed information, please refer to
3361 // the comment block right before FPDF_SetMediaBox and FPDF_GetMediaBox calls.
3362 if (scale_factor
== 1.0 && offset_x
== 0 && offset_y
== 0)
3366 // All the positions have been calculated, now manipulate the PDF.
3367 FS_MATRIX matrix
= {static_cast<float>(scale_factor
),
3370 static_cast<float>(scale_factor
),
3371 static_cast<float>(offset_x
),
3372 static_cast<float>(offset_y
)};
3373 FS_RECTF cliprect
= {static_cast<float>(source_clip_box
.left
+offset_x
),
3374 static_cast<float>(source_clip_box
.top
+offset_y
),
3375 static_cast<float>(source_clip_box
.right
+offset_x
),
3376 static_cast<float>(source_clip_box
.bottom
+offset_y
)};
3377 FPDFPage_TransFormWithClip(page
, &matrix
, &cliprect
);
3378 FPDFPage_TransformAnnots(page
, scale_factor
, 0, 0, scale_factor
,
3379 offset_x
, offset_y
);
3382 void PDFiumEngine::DrawPageShadow(const pp::Rect
& page_rc
,
3383 const pp::Rect
& shadow_rc
,
3384 const pp::Rect
& clip_rc
,
3385 pp::ImageData
* image_data
) {
3386 pp::Rect
page_rect(page_rc
);
3387 page_rect
.Offset(page_offset_
);
3389 pp::Rect
shadow_rect(shadow_rc
);
3390 shadow_rect
.Offset(page_offset_
);
3392 pp::Rect
clip_rect(clip_rc
);
3393 clip_rect
.Offset(page_offset_
);
3395 // Page drop shadow parameters.
3396 const double factor
= 0.5;
3397 uint32 depth
= std::max(
3398 std::max(page_rect
.x() - shadow_rect
.x(),
3399 page_rect
.y() - shadow_rect
.y()),
3400 std::max(shadow_rect
.right() - page_rect
.right(),
3401 shadow_rect
.bottom() - page_rect
.bottom()));
3402 depth
= static_cast<uint32
>(depth
* 1.5) + 1;
3404 // We need to check depth only to verify our copy of shadow matrix is correct.
3405 if (!page_shadow_
.get() || page_shadow_
->depth() != depth
)
3406 page_shadow_
.reset(new ShadowMatrix(depth
, factor
,
3407 client_
->GetBackgroundColor()));
3409 DCHECK(!image_data
->is_null());
3410 DrawShadow(image_data
, shadow_rect
, page_rect
, clip_rect
, *page_shadow_
);
3413 void PDFiumEngine::GetRegion(const pp::Point
& location
,
3414 pp::ImageData
* image_data
,
3416 int* stride
) const {
3417 if (image_data
->is_null()) {
3418 DCHECK(plugin_size_
.IsEmpty());
3423 char* buffer
= static_cast<char*>(image_data
->data());
3424 *stride
= image_data
->stride();
3426 pp::Point offset_location
= location
+ page_offset_
;
3427 // TODO: update this when we support BIDI and scrollbars can be on the left.
3429 !pp::Rect(page_offset_
, plugin_size_
).Contains(offset_location
)) {
3434 buffer
+= location
.y() * (*stride
);
3435 buffer
+= (location
.x() + page_offset_
.x()) * 4;
3439 void PDFiumEngine::OnSelectionChanged() {
3440 pp::PDF::SetSelectedText(GetPluginInstance(), GetSelectedText().c_str());
3443 void PDFiumEngine::RotateInternal() {
3444 // Store the current find index so that we can resume finding at that
3445 // particular index after we have recomputed the find results.
3446 std::string current_find_text
= current_find_text_
;
3447 if (current_find_index_
.valid())
3448 resume_find_index_
.SetIndex(current_find_index_
.GetIndex());
3450 resume_find_index_
.Invalidate();
3452 InvalidateAllPages();
3454 if (!current_find_text
.empty()) {
3456 client_
->NotifyNumberOfFindResultsChanged(0, false);
3457 StartFind(current_find_text
.c_str(), false);
3461 void PDFiumEngine::SetSelecting(bool selecting
) {
3462 bool was_selecting
= selecting_
;
3463 selecting_
= selecting
;
3464 if (selecting_
!= was_selecting
)
3465 client_
->IsSelectingChanged(selecting
);
3468 void PDFiumEngine::Form_Invalidate(FPDF_FORMFILLINFO
* param
,
3474 PDFiumEngine
* engine
= static_cast<PDFiumEngine
*>(param
);
3475 int page_index
= engine
->GetVisiblePageIndex(page
);
3476 if (page_index
== -1) {
3477 // This can sometime happen when the page is closed because it went off
3478 // screen, and PDFium invalidates the control as it's being deleted.
3482 pp::Rect rect
= engine
->pages_
[page_index
]->PageToScreen(
3483 engine
->GetVisibleRect().point(), engine
->current_zoom_
, left
, top
, right
,
3484 bottom
, engine
->current_rotation_
);
3485 engine
->client_
->Invalidate(rect
);
3488 void PDFiumEngine::Form_OutputSelectedRect(FPDF_FORMFILLINFO
* param
,
3494 PDFiumEngine
* engine
= static_cast<PDFiumEngine
*>(param
);
3495 int page_index
= engine
->GetVisiblePageIndex(page
);
3496 if (page_index
== -1) {
3500 pp::Rect rect
= engine
->pages_
[page_index
]->PageToScreen(
3501 engine
->GetVisibleRect().point(), engine
->current_zoom_
, left
, top
, right
,
3502 bottom
, engine
->current_rotation_
);
3503 engine
->form_highlights_
.push_back(rect
);
3506 void PDFiumEngine::Form_SetCursor(FPDF_FORMFILLINFO
* param
, int cursor_type
) {
3507 // We don't need this since it's not enough to change the cursor in all
3508 // scenarios. Instead, we check which form field we're under in OnMouseMove.
3511 int PDFiumEngine::Form_SetTimer(FPDF_FORMFILLINFO
* param
,
3513 TimerCallback timer_func
) {
3514 PDFiumEngine
* engine
= static_cast<PDFiumEngine
*>(param
);
3515 engine
->timers_
[++engine
->next_timer_id_
] =
3516 std::pair
<int, TimerCallback
>(elapse
, timer_func
);
3517 engine
->client_
->ScheduleCallback(engine
->next_timer_id_
, elapse
);
3518 return engine
->next_timer_id_
;
3521 void PDFiumEngine::Form_KillTimer(FPDF_FORMFILLINFO
* param
, int timer_id
) {
3522 PDFiumEngine
* engine
= static_cast<PDFiumEngine
*>(param
);
3523 engine
->timers_
.erase(timer_id
);
3526 FPDF_SYSTEMTIME
PDFiumEngine::Form_GetLocalTime(FPDF_FORMFILLINFO
* param
) {
3527 base::Time time
= base::Time::Now();
3528 base::Time::Exploded exploded
;
3529 time
.LocalExplode(&exploded
);
3532 rv
.wYear
= exploded
.year
;
3533 rv
.wMonth
= exploded
.month
;
3534 rv
.wDayOfWeek
= exploded
.day_of_week
;
3535 rv
.wDay
= exploded
.day_of_month
;
3536 rv
.wHour
= exploded
.hour
;
3537 rv
.wMinute
= exploded
.minute
;
3538 rv
.wSecond
= exploded
.second
;
3539 rv
.wMilliseconds
= exploded
.millisecond
;
3543 void PDFiumEngine::Form_OnChange(FPDF_FORMFILLINFO
* param
) {
3544 // Don't care about.
3547 FPDF_PAGE
PDFiumEngine::Form_GetPage(FPDF_FORMFILLINFO
* param
,
3548 FPDF_DOCUMENT document
,
3550 PDFiumEngine
* engine
= static_cast<PDFiumEngine
*>(param
);
3551 if (page_index
< 0 || page_index
>= static_cast<int>(engine
->pages_
.size()))
3553 return engine
->pages_
[page_index
]->GetPage();
3556 FPDF_PAGE
PDFiumEngine::Form_GetCurrentPage(FPDF_FORMFILLINFO
* param
,
3557 FPDF_DOCUMENT document
) {
3558 // TODO(jam): find out what this is used for.
3559 PDFiumEngine
* engine
= static_cast<PDFiumEngine
*>(param
);
3560 int index
= engine
->last_page_mouse_down_
;
3562 index
= engine
->GetMostVisiblePage();
3569 return engine
->pages_
[index
]->GetPage();
3572 int PDFiumEngine::Form_GetRotation(FPDF_FORMFILLINFO
* param
, FPDF_PAGE page
) {
3576 void PDFiumEngine::Form_ExecuteNamedAction(FPDF_FORMFILLINFO
* param
,
3577 FPDF_BYTESTRING named_action
) {
3578 PDFiumEngine
* engine
= static_cast<PDFiumEngine
*>(param
);
3579 std::string
action(named_action
);
3580 if (action
== "Print") {
3581 engine
->client_
->Print();
3585 int index
= engine
->last_page_mouse_down_
;
3586 /* Don't try to calculate the most visible page if we don't have a left click
3587 before this event (this code originally copied Form_GetCurrentPage which of
3588 course needs to do that and which doesn't have recursion). This can end up
3589 causing infinite recursion. See http://crbug.com/240413 for more
3590 information. Either way, it's not necessary for the spec'd list of named
3593 index = engine->GetMostVisiblePage();
3598 // This is the only list of named actions per the spec (see 12.6.4.11). Adobe
3599 // Reader supports more, like FitWidth, but since they're not part of the spec
3600 // and we haven't got bugs about them, no need to now.
3601 if (action
== "NextPage") {
3602 engine
->client_
->ScrollToPage(index
+ 1);
3603 } else if (action
== "PrevPage") {
3604 engine
->client_
->ScrollToPage(index
- 1);
3605 } else if (action
== "FirstPage") {
3606 engine
->client_
->ScrollToPage(0);
3607 } else if (action
== "LastPage") {
3608 engine
->client_
->ScrollToPage(engine
->pages_
.size() - 1);
3612 void PDFiumEngine::Form_SetTextFieldFocus(FPDF_FORMFILLINFO
* param
,
3613 FPDF_WIDESTRING value
,
3614 FPDF_DWORD valueLen
,
3615 FPDF_BOOL is_focus
) {
3616 // Do nothing for now.
3617 // TODO(gene): use this signal to trigger OSK.
3620 void PDFiumEngine::Form_DoURIAction(FPDF_FORMFILLINFO
* param
,
3621 FPDF_BYTESTRING uri
) {
3622 PDFiumEngine
* engine
= static_cast<PDFiumEngine
*>(param
);
3623 engine
->client_
->NavigateTo(std::string(uri
), false);
3626 void PDFiumEngine::Form_DoGoToAction(FPDF_FORMFILLINFO
* param
,
3629 float* position_array
,
3630 int size_of_array
) {
3631 PDFiumEngine
* engine
= static_cast<PDFiumEngine
*>(param
);
3632 engine
->client_
->ScrollToPage(page_index
);
3635 int PDFiumEngine::Form_Alert(IPDF_JSPLATFORM
* param
,
3636 FPDF_WIDESTRING message
,
3637 FPDF_WIDESTRING title
,
3640 // See fpdfformfill.h for these values.
3643 ALERT_TYPE_OK_CANCEL
,
3645 ALERT_TYPE_YES_NO_CANCEL
3649 ALERT_RESULT_OK
= 1,
3650 ALERT_RESULT_CANCEL
,
3655 PDFiumEngine
* engine
= static_cast<PDFiumEngine
*>(param
);
3656 std::string message_str
=
3657 base::UTF16ToUTF8(reinterpret_cast<const base::char16
*>(message
));
3658 if (type
== ALERT_TYPE_OK
) {
3659 engine
->client_
->Alert(message_str
);
3660 return ALERT_RESULT_OK
;
3663 bool rv
= engine
->client_
->Confirm(message_str
);
3664 if (type
== ALERT_TYPE_OK_CANCEL
)
3665 return rv
? ALERT_RESULT_OK
: ALERT_RESULT_CANCEL
;
3666 return rv
? ALERT_RESULT_YES
: ALERT_RESULT_NO
;
3669 void PDFiumEngine::Form_Beep(IPDF_JSPLATFORM
* param
, int type
) {
3670 // Beeps are annoying, and not possible using javascript, so ignore for now.
3673 int PDFiumEngine::Form_Response(IPDF_JSPLATFORM
* param
,
3674 FPDF_WIDESTRING question
,
3675 FPDF_WIDESTRING title
,
3676 FPDF_WIDESTRING default_response
,
3677 FPDF_WIDESTRING label
,
3681 std::string question_str
= base::UTF16ToUTF8(
3682 reinterpret_cast<const base::char16
*>(question
));
3683 std::string default_str
= base::UTF16ToUTF8(
3684 reinterpret_cast<const base::char16
*>(default_response
));
3686 PDFiumEngine
* engine
= static_cast<PDFiumEngine
*>(param
);
3687 std::string rv
= engine
->client_
->Prompt(question_str
, default_str
);
3688 base::string16 rv_16
= base::UTF8ToUTF16(rv
);
3689 int rv_bytes
= rv_16
.size() * sizeof(base::char16
);
3691 int bytes_to_copy
= rv_bytes
< length
? rv_bytes
: length
;
3692 memcpy(response
, rv_16
.c_str(), bytes_to_copy
);
3697 int PDFiumEngine::Form_GetFilePath(IPDF_JSPLATFORM
* param
,
3700 PDFiumEngine
* engine
= static_cast<PDFiumEngine
*>(param
);
3701 std::string rv
= engine
->client_
->GetURL();
3702 if (file_path
&& rv
.size() <= static_cast<size_t>(length
))
3703 memcpy(file_path
, rv
.c_str(), rv
.size());
3707 void PDFiumEngine::Form_Mail(IPDF_JSPLATFORM
* param
,
3712 FPDF_WIDESTRING subject
,
3714 FPDF_WIDESTRING bcc
,
3715 FPDF_WIDESTRING message
) {
3716 // Note: |mail_data| and |length| are ignored. We don't handle attachments;
3717 // there is no way with mailto.
3718 std::string to_str
=
3719 base::UTF16ToUTF8(reinterpret_cast<const base::char16
*>(to
));
3720 std::string cc_str
=
3721 base::UTF16ToUTF8(reinterpret_cast<const base::char16
*>(cc
));
3722 std::string bcc_str
=
3723 base::UTF16ToUTF8(reinterpret_cast<const base::char16
*>(bcc
));
3724 std::string subject_str
=
3725 base::UTF16ToUTF8(reinterpret_cast<const base::char16
*>(subject
));
3726 std::string message_str
=
3727 base::UTF16ToUTF8(reinterpret_cast<const base::char16
*>(message
));
3729 PDFiumEngine
* engine
= static_cast<PDFiumEngine
*>(param
);
3730 engine
->client_
->Email(to_str
, cc_str
, bcc_str
, subject_str
, message_str
);
3733 void PDFiumEngine::Form_Print(IPDF_JSPLATFORM
* param
,
3738 FPDF_BOOL shrink_to_fit
,
3739 FPDF_BOOL print_as_image
,
3741 FPDF_BOOL annotations
) {
3742 // No way to pass the extra information to the print dialog using JavaScript.
3743 // Just opening it is fine for now.
3744 PDFiumEngine
* engine
= static_cast<PDFiumEngine
*>(param
);
3745 engine
->client_
->Print();
3748 void PDFiumEngine::Form_SubmitForm(IPDF_JSPLATFORM
* param
,
3751 FPDF_WIDESTRING url
) {
3752 std::string url_str
=
3753 base::UTF16ToUTF8(reinterpret_cast<const base::char16
*>(url
));
3754 PDFiumEngine
* engine
= static_cast<PDFiumEngine
*>(param
);
3755 engine
->client_
->SubmitForm(url_str
, form_data
, length
);
3758 void PDFiumEngine::Form_GotoPage(IPDF_JSPLATFORM
* param
,
3760 PDFiumEngine
* engine
= static_cast<PDFiumEngine
*>(param
);
3761 engine
->client_
->ScrollToPage(page_number
);
3764 int PDFiumEngine::Form_Browse(IPDF_JSPLATFORM
* param
,
3767 PDFiumEngine
* engine
= static_cast<PDFiumEngine
*>(param
);
3768 std::string path
= engine
->client_
->ShowFileSelectionDialog();
3769 if (path
.size() + 1 <= static_cast<size_t>(length
))
3770 memcpy(file_path
, &path
[0], path
.size() + 1);
3771 return path
.size() + 1;
3774 FPDF_BOOL
PDFiumEngine::Pause_NeedToPauseNow(IFSDK_PAUSE
* param
) {
3775 PDFiumEngine
* engine
= static_cast<PDFiumEngine
*>(param
);
3776 return (base::Time::Now() - engine
->last_progressive_start_time_
).
3777 InMilliseconds() > engine
->progressive_paint_timeout_
;
3780 ScopedUnsupportedFeature::ScopedUnsupportedFeature(PDFiumEngine
* engine
)
3781 : engine_(engine
), old_engine_(g_engine_for_unsupported
) {
3782 g_engine_for_unsupported
= engine_
;
3785 ScopedUnsupportedFeature::~ScopedUnsupportedFeature() {
3786 g_engine_for_unsupported
= old_engine_
;
3789 PDFEngineExports
* PDFEngineExports::Create() {
3790 return new PDFiumEngineExports
;
3795 int CalculatePosition(FPDF_PAGE page
,
3796 const PDFiumEngineExports::RenderingSettings
& settings
,
3798 int page_width
= static_cast<int>(ConvertUnitDouble(FPDF_GetPageWidth(page
),
3801 int page_height
= static_cast<int>(ConvertUnitDouble(FPDF_GetPageHeight(page
),
3805 // Start by assuming that we will draw exactly to the bounds rect
3807 *dest
= settings
.bounds
;
3809 int rotate
= 0; // normal orientation.
3811 // Auto-rotate landscape pages to print correctly.
3812 if (settings
.autorotate
&&
3813 (dest
->width() > dest
->height()) != (page_width
> page_height
)) {
3814 rotate
= 3; // 90 degrees counter-clockwise.
3815 std::swap(page_width
, page_height
);
3818 // See if we need to scale the output
3819 bool scale_to_bounds
= false;
3820 if (settings
.fit_to_bounds
&&
3821 ((page_width
> dest
->width()) || (page_height
> dest
->height()))) {
3822 scale_to_bounds
= true;
3823 } else if (settings
.stretch_to_bounds
&&
3824 ((page_width
< dest
->width()) || (page_height
< dest
->height()))) {
3825 scale_to_bounds
= true;
3828 if (scale_to_bounds
) {
3829 // If we need to maintain aspect ratio, calculate the actual width and
3831 if (settings
.keep_aspect_ratio
) {
3832 double scale_factor_x
= page_width
;
3833 scale_factor_x
/= dest
->width();
3834 double scale_factor_y
= page_height
;
3835 scale_factor_y
/= dest
->height();
3836 if (scale_factor_x
> scale_factor_y
) {
3837 dest
->set_height(page_height
/ scale_factor_x
);
3839 dest
->set_width(page_width
/ scale_factor_y
);
3843 // We are not scaling to bounds. Draw in the actual page size. If the
3844 // actual page size is larger than the bounds, the output will be
3846 dest
->set_width(page_width
);
3847 dest
->set_height(page_height
);
3850 if (settings
.center_in_bounds
) {
3851 pp::Point
offset((settings
.bounds
.width() - dest
->width()) / 2,
3852 (settings
.bounds
.height() - dest
->height()) / 2);
3853 dest
->Offset(offset
);
3861 bool PDFiumEngineExports::RenderPDFPageToDC(const void* pdf_buffer
,
3864 const RenderingSettings
& settings
,
3866 FPDF_DOCUMENT doc
= FPDF_LoadMemDocument(pdf_buffer
, buffer_size
, NULL
);
3869 FPDF_PAGE page
= FPDF_LoadPage(doc
, page_number
);
3871 FPDF_CloseDocument(doc
);
3874 RenderingSettings new_settings
= settings
;
3875 // calculate the page size
3876 if (new_settings
.dpi_x
== -1)
3877 new_settings
.dpi_x
= GetDeviceCaps(dc
, LOGPIXELSX
);
3878 if (new_settings
.dpi_y
== -1)
3879 new_settings
.dpi_y
= GetDeviceCaps(dc
, LOGPIXELSY
);
3882 int rotate
= CalculatePosition(page
, new_settings
, &dest
);
3884 int save_state
= SaveDC(dc
);
3885 // The caller wanted all drawing to happen within the bounds specified.
3886 // Based on scale calculations, our destination rect might be larger
3887 // than the bounds. Set the clip rect to the bounds.
3888 IntersectClipRect(dc
, settings
.bounds
.x(), settings
.bounds
.y(),
3889 settings
.bounds
.x() + settings
.bounds
.width(),
3890 settings
.bounds
.y() + settings
.bounds
.height());
3892 // A temporary hack. PDFs generated by Cairo (used by Chrome OS to generate
3893 // a PDF output from a webpage) result in very large metafiles and the
3894 // rendering using FPDF_RenderPage is incorrect. In this case, render as a
3895 // bitmap. Note that this code does not kick in for PDFs printed from Chrome
3896 // because in that case we create a temp PDF first before printing and this
3897 // temp PDF does not have a creator string that starts with "cairo".
3898 base::string16 creator
;
3899 size_t buffer_bytes
= FPDF_GetMetaText(doc
, "Creator", NULL
, 0);
3900 if (buffer_bytes
> 1) {
3902 doc
, "Creator", WriteInto(&creator
, buffer_bytes
+ 1), buffer_bytes
);
3904 bool use_bitmap
= false;
3905 if (StartsWith(creator
, L
"cairo", false))
3908 // Another temporary hack. Some PDFs seems to render very slowly if
3909 // FPDF_RenderPage is directly used on a printer DC. I suspect it is
3910 // because of the code to talk Postscript directly to the printer if
3911 // the printer supports this. Need to discuss this with PDFium. For now,
3912 // render to a bitmap and then blit the bitmap to the DC if we have been
3913 // supplied a printer DC.
3914 int device_type
= GetDeviceCaps(dc
, TECHNOLOGY
);
3916 (device_type
== DT_RASPRINTER
) || (device_type
== DT_PLOTTER
)) {
3917 FPDF_BITMAP bitmap
= FPDFBitmap_Create(dest
.width(), dest
.height(),
3920 FPDFBitmap_FillRect(bitmap
, 0, 0, dest
.width(), dest
.height(), 0xFFFFFFFF);
3921 FPDF_RenderPageBitmap(
3922 bitmap
, page
, 0, 0, dest
.width(), dest
.height(), rotate
,
3923 FPDF_ANNOT
| FPDF_PRINTING
| FPDF_NO_CATCH
);
3924 int stride
= FPDFBitmap_GetStride(bitmap
);
3926 memset(&bmi
, 0, sizeof(bmi
));
3927 bmi
.bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
3928 bmi
.bmiHeader
.biWidth
= dest
.width();
3929 bmi
.bmiHeader
.biHeight
= -dest
.height(); // top-down image
3930 bmi
.bmiHeader
.biPlanes
= 1;
3931 bmi
.bmiHeader
.biBitCount
= 32;
3932 bmi
.bmiHeader
.biCompression
= BI_RGB
;
3933 bmi
.bmiHeader
.biSizeImage
= stride
* dest
.height();
3934 StretchDIBits(dc
, dest
.x(), dest
.y(), dest
.width(), dest
.height(),
3935 0, 0, dest
.width(), dest
.height(),
3936 FPDFBitmap_GetBuffer(bitmap
), &bmi
, DIB_RGB_COLORS
, SRCCOPY
);
3937 FPDFBitmap_Destroy(bitmap
);
3939 FPDF_RenderPage(dc
, page
, dest
.x(), dest
.y(), dest
.width(), dest
.height(),
3940 rotate
, FPDF_ANNOT
| FPDF_PRINTING
| FPDF_NO_CATCH
);
3942 RestoreDC(dc
, save_state
);
3943 FPDF_ClosePage(page
);
3944 FPDF_CloseDocument(doc
);
3949 bool PDFiumEngineExports::RenderPDFPageToBitmap(
3950 const void* pdf_buffer
,
3951 int pdf_buffer_size
,
3953 const RenderingSettings
& settings
,
3954 void* bitmap_buffer
) {
3955 FPDF_DOCUMENT doc
= FPDF_LoadMemDocument(pdf_buffer
, pdf_buffer_size
, NULL
);
3958 FPDF_PAGE page
= FPDF_LoadPage(doc
, page_number
);
3960 FPDF_CloseDocument(doc
);
3965 int rotate
= CalculatePosition(page
, settings
, &dest
);
3967 FPDF_BITMAP bitmap
=
3968 FPDFBitmap_CreateEx(settings
.bounds
.width(), settings
.bounds
.height(),
3969 FPDFBitmap_BGRA
, bitmap_buffer
,
3970 settings
.bounds
.width() * 4);
3972 FPDFBitmap_FillRect(bitmap
, 0, 0, settings
.bounds
.width(),
3973 settings
.bounds
.height(), 0xFFFFFFFF);
3974 // Shift top-left corner of bounds to (0, 0) if it's not there.
3975 dest
.set_point(dest
.point() - settings
.bounds
.point());
3976 FPDF_RenderPageBitmap(
3977 bitmap
, page
, dest
.x(), dest
.y(), dest
.width(), dest
.height(), rotate
,
3978 FPDF_ANNOT
| FPDF_PRINTING
| FPDF_NO_CATCH
);
3979 FPDFBitmap_Destroy(bitmap
);
3980 FPDF_ClosePage(page
);
3981 FPDF_CloseDocument(doc
);
3985 bool PDFiumEngineExports::GetPDFDocInfo(const void* pdf_buffer
,
3988 double* max_page_width
) {
3989 FPDF_DOCUMENT doc
= FPDF_LoadMemDocument(pdf_buffer
, buffer_size
, NULL
);
3992 int page_count_local
= FPDF_GetPageCount(doc
);
3994 *page_count
= page_count_local
;
3996 if (max_page_width
) {
3997 *max_page_width
= 0;
3998 for (int page_number
= 0; page_number
< page_count_local
; page_number
++) {
3999 double page_width
= 0;
4000 double page_height
= 0;
4001 FPDF_GetPageSizeByIndex(doc
, page_number
, &page_width
, &page_height
);
4002 if (page_width
> *max_page_width
) {
4003 *max_page_width
= page_width
;
4007 FPDF_CloseDocument(doc
);
4011 bool PDFiumEngineExports::GetPDFPageSizeByIndex(
4012 const void* pdf_buffer
,
4013 int pdf_buffer_size
,
4017 FPDF_DOCUMENT doc
= FPDF_LoadMemDocument(pdf_buffer
, pdf_buffer_size
, NULL
);
4020 bool success
= FPDF_GetPageSizeByIndex(doc
, page_number
, width
, height
) != 0;
4021 FPDF_CloseDocument(doc
);
4025 } // namespace chrome_pdf