Upload upstream chromium 67.0.3396
[platform/framework/web/chromium-efl.git] / pdf / pdfium / pdfium_engine.cc
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "pdf/pdfium/pdfium_engine.h"
6
7 #include <math.h>
8 #include <stddef.h>
9 #include <stdint.h>
10
11 #include <algorithm>
12 #include <limits>
13 #include <memory>
14 #include <set>
15
16 #include "base/auto_reset.h"
17 #include "base/i18n/encoding_detection.h"
18 #include "base/i18n/icu_string_conversions.h"
19 #include "base/lazy_instance.h"
20 #include "base/logging.h"
21 #include "base/macros.h"
22 #include "base/numerics/safe_conversions.h"
23 #include "base/stl_util.h"
24 #include "base/strings/string_number_conversions.h"
25 #include "base/strings/string_piece.h"
26 #include "base/strings/string_util.h"
27 #include "base/strings/utf_string_conversions.h"
28 #include "base/threading/thread_task_runner_handle.h"
29 #include "build/build_config.h"
30 #include "gin/array_buffer.h"
31 #include "gin/public/gin_embedders.h"
32 #include "gin/public/isolate_holder.h"
33 #include "pdf/draw_utils.h"
34 #include "pdf/pdf_transform.h"
35 #include "pdf/pdfium/pdfium_api_string_buffer_adapter.h"
36 #include "pdf/pdfium/pdfium_mem_buffer_file_read.h"
37 #include "pdf/pdfium/pdfium_mem_buffer_file_write.h"
38 #include "pdf/url_loader_wrapper_impl.h"
39 #include "ppapi/c/pp_errors.h"
40 #include "ppapi/c/pp_input_event.h"
41 #include "ppapi/c/ppb_core.h"
42 #include "ppapi/c/private/ppb_pdf.h"
43 #include "ppapi/cpp/dev/memory_dev.h"
44 #include "ppapi/cpp/input_event.h"
45 #include "ppapi/cpp/instance.h"
46 #include "ppapi/cpp/module.h"
47 #include "ppapi/cpp/private/pdf.h"
48 #include "ppapi/cpp/trusted/browser_font_trusted.h"
49 #include "ppapi/cpp/url_response_info.h"
50 #include "ppapi/cpp/var.h"
51 #include "ppapi/cpp/var_dictionary.h"
52 #include "printing/units.h"
53 #include "third_party/pdfium/public/cpp/fpdf_deleters.h"
54 #include "third_party/pdfium/public/fpdf_annot.h"
55 #include "third_party/pdfium/public/fpdf_attachment.h"
56 #include "third_party/pdfium/public/fpdf_catalog.h"
57 #include "third_party/pdfium/public/fpdf_edit.h"
58 #include "third_party/pdfium/public/fpdf_ext.h"
59 #include "third_party/pdfium/public/fpdf_flatten.h"
60 #include "third_party/pdfium/public/fpdf_ppo.h"
61 #include "third_party/pdfium/public/fpdf_save.h"
62 #include "third_party/pdfium/public/fpdf_searchex.h"
63 #include "third_party/pdfium/public/fpdf_sysfontinfo.h"
64 #include "third_party/pdfium/public/fpdf_transformpage.h"
65 #include "third_party/pdfium/public/fpdfview.h"
66 #include "ui/events/keycodes/keyboard_codes.h"
67 #include "ui/gfx/codec/jpeg_codec.h"
68 #include "ui/gfx/geometry/rect.h"
69 #include "v8/include/v8.h"
70
71 using printing::ConvertUnit;
72 using printing::ConvertUnitDouble;
73 using printing::kPointsPerInch;
74 using printing::kPixelsPerInch;
75
76 namespace chrome_pdf {
77
78 static_assert(static_cast<int>(PDFEngine::FormType::kNone) == FORMTYPE_NONE,
79               "None form types must match");
80 static_assert(static_cast<int>(PDFEngine::FormType::kAcroForm) ==
81                   FORMTYPE_ACRO_FORM,
82               "AcroForm form types must match");
83 static_assert(static_cast<int>(PDFEngine::FormType::kXFAFull) ==
84                   FORMTYPE_XFA_FULL,
85               "XFA full form types must match");
86 static_assert(static_cast<int>(PDFEngine::FormType::kXFAForeground) ==
87                   FORMTYPE_XFA_FOREGROUND,
88               "XFA foreground form types must match");
89 static_assert(static_cast<int>(PDFEngine::FormType::kCount) == FORMTYPE_COUNT,
90               "Form type counts must match");
91
92 namespace {
93
94 const int32_t kPageShadowTop = 3;
95 const int32_t kPageShadowBottom = 7;
96 const int32_t kPageShadowLeft = 5;
97 const int32_t kPageShadowRight = 5;
98
99 const int32_t kPageSeparatorThickness = 4;
100 const int32_t kHighlightColorR = 153;
101 const int32_t kHighlightColorG = 193;
102 const int32_t kHighlightColorB = 218;
103
104 const uint32_t kPendingPageColor = 0xFFEEEEEE;
105
106 const uint32_t kFormHighlightColor = 0xFFE4DD;
107 const int32_t kFormHighlightAlpha = 100;
108
109 constexpr int kMaxPasswordTries = 3;
110
111 constexpr base::TimeDelta kTouchLongPressTimeout =
112     base::TimeDelta::FromMilliseconds(300);
113
114 // Windows has native panning capabilities. No need to use our own.
115 #if defined(OS_WIN)
116 constexpr bool kViewerImplementedPanning = false;
117 #else
118 constexpr bool kViewerImplementedPanning = true;
119 #endif
120
121 // See Table 3.20 in
122 // http://www.adobe.com/devnet/acrobat/pdfs/pdf_reference_1-7.pdf
123 const uint32_t kPDFPermissionPrintLowQualityMask = 1 << 2;
124 const uint32_t kPDFPermissionPrintHighQualityMask = 1 << 11;
125 const uint32_t kPDFPermissionCopyMask = 1 << 4;
126 const uint32_t kPDFPermissionCopyAccessibleMask = 1 << 9;
127
128 const int32_t kLoadingTextVerticalOffset = 50;
129
130 // The maximum amount of time we'll spend doing a paint before we give back
131 // control of the thread.
132 constexpr base::TimeDelta kMaxProgressivePaintTime =
133     base::TimeDelta::FromMilliseconds(300);
134
135 // The maximum amount of time we'll spend doing the first paint. This is less
136 // than the above to keep things smooth if the user is scrolling quickly. This
137 // is set to 250 ms to give enough time for most PDFs to render, while avoiding
138 // adding too much latency to the display of the final image when the user
139 // stops scrolling.
140 // Setting a higher value has minimal benefit (scrolling at less than 4 fps will
141 // never be a great experience) and there is some cost, since when the user
142 // stops scrolling the in-progress painting has to complete or timeout before
143 // the final painting can start.
144 // The scrollbar will always be responsive since it is managed by a separate
145 // process.
146 constexpr base::TimeDelta kMaxInitialProgressivePaintTime =
147     base::TimeDelta::FromMilliseconds(250);
148
149 // Flag to turn edit mode tracking on.
150 // Do not flip until form saving is completely functional.
151 constexpr bool kIsEditModeTracked = false;
152
153 PDFiumEngine* g_engine_for_fontmapper = nullptr;
154
155 std::vector<uint32_t> GetPageNumbersFromPrintPageNumberRange(
156     const PP_PrintPageNumberRange_Dev* page_ranges,
157     uint32_t page_range_count) {
158   std::vector<uint32_t> page_numbers;
159   for (uint32_t index = 0; index < page_range_count; ++index) {
160     for (uint32_t page_number = page_ranges[index].first_page_number;
161          page_number <= page_ranges[index].last_page_number; ++page_number) {
162       page_numbers.push_back(page_number);
163     }
164   }
165   return page_numbers;
166 }
167
168 #if defined(OS_LINUX)
169
170 PP_Instance g_last_instance_id;
171
172 // TODO(npm): Move font stuff to another file to reduce the size of this one
173 PP_BrowserFont_Trusted_Weight WeightToBrowserFontTrustedWeight(int weight) {
174   static_assert(PP_BROWSERFONT_TRUSTED_WEIGHT_100 == 0,
175                 "PP_BrowserFont_Trusted_Weight min");
176   static_assert(PP_BROWSERFONT_TRUSTED_WEIGHT_900 == 8,
177                 "PP_BrowserFont_Trusted_Weight max");
178   const int kMinimumWeight = 100;
179   const int kMaximumWeight = 900;
180   int normalized_weight =
181       std::min(std::max(weight, kMinimumWeight), kMaximumWeight);
182   normalized_weight = (normalized_weight / 100) - 1;
183   return static_cast<PP_BrowserFont_Trusted_Weight>(normalized_weight);
184 }
185
186 // This list is for CPWL_FontMap::GetDefaultFontByCharset().
187 // We pretend to have these font natively and let the browser (or underlying
188 // fontconfig) to pick the proper font on the system.
189 void EnumFonts(FPDF_SYSFONTINFO* sysfontinfo, void* mapper) {
190   FPDF_AddInstalledFont(mapper, "Arial", FXFONT_DEFAULT_CHARSET);
191
192   const FPDF_CharsetFontMap* font_map = FPDF_GetDefaultTTFMap();
193   for (; font_map->charset != -1; ++font_map) {
194     FPDF_AddInstalledFont(mapper, font_map->fontname, font_map->charset);
195   }
196 }
197
198 void* MapFont(FPDF_SYSFONTINFO*,
199               int weight,
200               int italic,
201               int charset,
202               int pitch_family,
203               const char* face,
204               int* exact) {
205   // Do not attempt to map fonts if pepper is not initialized (for privet local
206   // printing).
207   // TODO(noamsml): Real font substitution (http://crbug.com/391978)
208   if (!pp::Module::Get())
209     return nullptr;
210
211   pp::BrowserFontDescription description;
212
213   // Pretend the system does not have the Symbol font to force a fallback to
214   // the built in Symbol font in CFX_FontMapper::FindSubstFont().
215   if (strcmp(face, "Symbol") == 0)
216     return nullptr;
217
218   if (pitch_family & FXFONT_FF_FIXEDPITCH) {
219     description.set_family(PP_BROWSERFONT_TRUSTED_FAMILY_MONOSPACE);
220   } else if (pitch_family & FXFONT_FF_ROMAN) {
221     description.set_family(PP_BROWSERFONT_TRUSTED_FAMILY_SERIF);
222   }
223
224   static const struct {
225     const char* pdf_name;
226     const char* face;
227     bool bold;
228     bool italic;
229   } kPdfFontSubstitutions[] = {
230       {"Courier", "Courier New", false, false},
231       {"Courier-Bold", "Courier New", true, false},
232       {"Courier-BoldOblique", "Courier New", true, true},
233       {"Courier-Oblique", "Courier New", false, true},
234       {"Helvetica", "Arial", false, false},
235       {"Helvetica-Bold", "Arial", true, false},
236       {"Helvetica-BoldOblique", "Arial", true, true},
237       {"Helvetica-Oblique", "Arial", false, true},
238       {"Times-Roman", "Times New Roman", false, false},
239       {"Times-Bold", "Times New Roman", true, false},
240       {"Times-BoldItalic", "Times New Roman", true, true},
241       {"Times-Italic", "Times New Roman", false, true},
242
243       // MS P?(Mincho|Gothic) are the most notable fonts in Japanese PDF files
244       // without embedding the glyphs. Sometimes the font names are encoded
245       // in Japanese Windows's locale (CP932/Shift_JIS) without space.
246       // Most Linux systems don't have the exact font, but for outsourcing
247       // fontconfig to find substitutable font in the system, we pass ASCII
248       // font names to it.
249       {"MS-PGothic", "MS PGothic", false, false},
250       {"MS-Gothic", "MS Gothic", false, false},
251       {"MS-PMincho", "MS PMincho", false, false},
252       {"MS-Mincho", "MS Mincho", false, false},
253       // MS PGothic in Shift_JIS encoding.
254       {"\x82\x6C\x82\x72\x82\x6F\x83\x53\x83\x56\x83\x62\x83\x4E", "MS PGothic",
255        false, false},
256       // MS Gothic in Shift_JIS encoding.
257       {"\x82\x6C\x82\x72\x83\x53\x83\x56\x83\x62\x83\x4E", "MS Gothic", false,
258        false},
259       // MS PMincho in Shift_JIS encoding.
260       {"\x82\x6C\x82\x72\x82\x6F\x96\xBE\x92\xA9", "MS PMincho", false, false},
261       // MS Mincho in Shift_JIS encoding.
262       {"\x82\x6C\x82\x72\x96\xBE\x92\xA9", "MS Mincho", false, false},
263   };
264
265   // Similar logic exists in PDFium's CFX_FolderFontInfo::FindFont().
266   if (charset == FXFONT_ANSI_CHARSET && (pitch_family & FXFONT_FF_FIXEDPITCH))
267     face = "Courier New";
268
269   // Map from the standard PDF fonts to TrueType font names.
270   size_t i;
271   for (i = 0; i < arraysize(kPdfFontSubstitutions); ++i) {
272     if (strcmp(face, kPdfFontSubstitutions[i].pdf_name) == 0) {
273       description.set_face(kPdfFontSubstitutions[i].face);
274       if (kPdfFontSubstitutions[i].bold)
275         description.set_weight(PP_BROWSERFONT_TRUSTED_WEIGHT_BOLD);
276       if (kPdfFontSubstitutions[i].italic)
277         description.set_italic(true);
278       break;
279     }
280   }
281
282   if (i == arraysize(kPdfFontSubstitutions)) {
283     // Convert to UTF-8 before calling set_face().
284     std::string face_utf8;
285     if (base::IsStringUTF8(face)) {
286       face_utf8 = face;
287     } else {
288       std::string encoding;
289       if (base::DetectEncoding(face, &encoding)) {
290         // ConvertToUtf8AndNormalize() clears |face_utf8| on failure.
291         base::ConvertToUtf8AndNormalize(face, encoding, &face_utf8);
292       }
293     }
294
295     if (face_utf8.empty())
296       return nullptr;
297
298     description.set_face(face_utf8);
299     description.set_weight(WeightToBrowserFontTrustedWeight(weight));
300     description.set_italic(italic > 0);
301   }
302
303   if (!pp::PDF::IsAvailable()) {
304     NOTREACHED();
305     return nullptr;
306   }
307
308   if (g_engine_for_fontmapper)
309     g_engine_for_fontmapper->FontSubstituted();
310
311   PP_Resource font_resource = pp::PDF::GetFontFileWithFallback(
312       pp::InstanceHandle(g_last_instance_id),
313       &description.pp_font_description(),
314       static_cast<PP_PrivateFontCharset>(charset));
315   long res_id = font_resource;
316   return reinterpret_cast<void*>(res_id);
317 }
318
319 unsigned long GetFontData(FPDF_SYSFONTINFO*,
320                           void* font_id,
321                           unsigned int table,
322                           unsigned char* buffer,
323                           unsigned long buf_size) {
324   if (!pp::PDF::IsAvailable()) {
325     NOTREACHED();
326     return 0;
327   }
328
329   uint32_t size = buf_size;
330   long res_id = reinterpret_cast<long>(font_id);
331   if (!pp::PDF::GetFontTableForPrivateFontFile(res_id, table, buffer, &size))
332     return 0;
333   return size;
334 }
335
336 void DeleteFont(FPDF_SYSFONTINFO*, void* font_id) {
337   long res_id = reinterpret_cast<long>(font_id);
338   pp::Module::Get()->core()->ReleaseResource(res_id);
339 }
340
341 FPDF_SYSFONTINFO g_font_info = {1,           0, EnumFonts, MapFont,   0,
342                                 GetFontData, 0, 0,         DeleteFont};
343 #else
344 struct FPDF_SYSFONTINFO_WITHMETRICS : public FPDF_SYSFONTINFO {
345   explicit FPDF_SYSFONTINFO_WITHMETRICS(FPDF_SYSFONTINFO* sysfontinfo) {
346     version = sysfontinfo->version;
347     default_sysfontinfo = sysfontinfo;
348   }
349
350   ~FPDF_SYSFONTINFO_WITHMETRICS() {
351     FPDF_FreeDefaultSystemFontInfo(default_sysfontinfo);
352   }
353
354   FPDF_SYSFONTINFO* default_sysfontinfo;
355 };
356
357 FPDF_SYSFONTINFO_WITHMETRICS* g_font_info = nullptr;
358
359 void* MapFontWithMetrics(FPDF_SYSFONTINFO* sysfontinfo,
360                          int weight,
361                          int italic,
362                          int charset,
363                          int pitch_family,
364                          const char* face,
365                          int* exact) {
366   auto* fontinfo_with_metrics =
367       static_cast<FPDF_SYSFONTINFO_WITHMETRICS*>(sysfontinfo);
368   if (!fontinfo_with_metrics->default_sysfontinfo->MapFont)
369     return nullptr;
370   void* mapped_font = fontinfo_with_metrics->default_sysfontinfo->MapFont(
371       fontinfo_with_metrics->default_sysfontinfo, weight, italic, charset,
372       pitch_family, face, exact);
373   if (mapped_font && g_engine_for_fontmapper)
374     g_engine_for_fontmapper->FontSubstituted();
375   return mapped_font;
376 }
377
378 void DeleteFont(FPDF_SYSFONTINFO* sysfontinfo, void* font_id) {
379   auto* fontinfo_with_metrics =
380       static_cast<FPDF_SYSFONTINFO_WITHMETRICS*>(sysfontinfo);
381   if (!fontinfo_with_metrics->default_sysfontinfo->DeleteFont)
382     return;
383   fontinfo_with_metrics->default_sysfontinfo->DeleteFont(
384       fontinfo_with_metrics->default_sysfontinfo, font_id);
385 }
386
387 void EnumFonts(FPDF_SYSFONTINFO* sysfontinfo, void* mapper) {
388   auto* fontinfo_with_metrics =
389       static_cast<FPDF_SYSFONTINFO_WITHMETRICS*>(sysfontinfo);
390   if (!fontinfo_with_metrics->default_sysfontinfo->EnumFonts)
391     return;
392   fontinfo_with_metrics->default_sysfontinfo->EnumFonts(
393       fontinfo_with_metrics->default_sysfontinfo, mapper);
394 }
395
396 unsigned long GetFaceName(FPDF_SYSFONTINFO* sysfontinfo,
397                           void* hFont,
398                           char* buffer,
399                           unsigned long buffer_size) {
400   auto* fontinfo_with_metrics =
401       static_cast<FPDF_SYSFONTINFO_WITHMETRICS*>(sysfontinfo);
402   if (!fontinfo_with_metrics->default_sysfontinfo->GetFaceName)
403     return 0;
404   return fontinfo_with_metrics->default_sysfontinfo->GetFaceName(
405       fontinfo_with_metrics->default_sysfontinfo, hFont, buffer, buffer_size);
406 }
407
408 void* GetFont(FPDF_SYSFONTINFO* sysfontinfo, const char* face) {
409   auto* fontinfo_with_metrics =
410       static_cast<FPDF_SYSFONTINFO_WITHMETRICS*>(sysfontinfo);
411   if (!fontinfo_with_metrics->default_sysfontinfo->GetFont)
412     return nullptr;
413   return fontinfo_with_metrics->default_sysfontinfo->GetFont(
414       fontinfo_with_metrics->default_sysfontinfo, face);
415 }
416
417 int GetFontCharset(FPDF_SYSFONTINFO* sysfontinfo, void* hFont) {
418   auto* fontinfo_with_metrics =
419       static_cast<FPDF_SYSFONTINFO_WITHMETRICS*>(sysfontinfo);
420   if (!fontinfo_with_metrics->default_sysfontinfo->GetFontCharset)
421     return 0;
422   return fontinfo_with_metrics->default_sysfontinfo->GetFontCharset(
423       fontinfo_with_metrics->default_sysfontinfo, hFont);
424 }
425
426 unsigned long GetFontData(FPDF_SYSFONTINFO* sysfontinfo,
427                           void* hFont,
428                           unsigned int table,
429                           unsigned char* buffer,
430                           unsigned long buf_size) {
431   auto* fontinfo_with_metrics =
432       static_cast<FPDF_SYSFONTINFO_WITHMETRICS*>(sysfontinfo);
433   if (!fontinfo_with_metrics->default_sysfontinfo->GetFontData)
434     return 0;
435   return fontinfo_with_metrics->default_sysfontinfo->GetFontData(
436       fontinfo_with_metrics->default_sysfontinfo, hFont, table, buffer,
437       buf_size);
438 }
439
440 void Release(FPDF_SYSFONTINFO* sysfontinfo) {
441   auto* fontinfo_with_metrics =
442       static_cast<FPDF_SYSFONTINFO_WITHMETRICS*>(sysfontinfo);
443   if (!fontinfo_with_metrics->default_sysfontinfo->Release)
444     return;
445   fontinfo_with_metrics->default_sysfontinfo->Release(
446       fontinfo_with_metrics->default_sysfontinfo);
447 }
448 #endif  // defined(OS_LINUX)
449
450 PDFiumEngine* g_engine_for_unsupported = nullptr;
451
452 void Unsupported_Handler(UNSUPPORT_INFO*, int type) {
453   if (!g_engine_for_unsupported) {
454     NOTREACHED();
455     return;
456   }
457
458   g_engine_for_unsupported->UnsupportedFeature(type);
459 }
460
461 UNSUPPORT_INFO g_unsupported_info = {1, Unsupported_Handler};
462
463 // Set the destination page size and content area in points based on source
464 // page rotation and orientation.
465 //
466 // |rotated| True if source page is rotated 90 degree or 270 degree.
467 // |is_src_page_landscape| is true if the source page orientation is landscape.
468 // |page_size| has the actual destination page size in points.
469 // |content_rect| has the actual destination page printable area values in
470 // points.
471 void SetPageSizeAndContentRect(bool rotated,
472                                bool is_src_page_landscape,
473                                pp::Size* page_size,
474                                pp::Rect* content_rect) {
475   bool is_dst_page_landscape = page_size->width() > page_size->height();
476   bool page_orientation_mismatched =
477       is_src_page_landscape != is_dst_page_landscape;
478   bool rotate_dst_page = rotated ^ page_orientation_mismatched;
479   if (rotate_dst_page) {
480     page_size->SetSize(page_size->height(), page_size->width());
481     content_rect->SetRect(content_rect->y(), content_rect->x(),
482                           content_rect->height(), content_rect->width());
483   }
484 }
485
486 template <class S>
487 bool IsAboveOrDirectlyLeftOf(const S& lhs, const S& rhs) {
488   return lhs.y() < rhs.y() || (lhs.y() == rhs.y() && lhs.x() < rhs.x());
489 }
490
491 int CalculateCenterForZoom(int center, int length, double zoom) {
492   int adjusted_center =
493       static_cast<int>(center * zoom) - static_cast<int>(length * zoom / 2);
494   return std::max(adjusted_center, 0);
495 }
496
497 // This formats a string with special 0xfffe end-of-line hyphens the same way
498 // as Adobe Reader. When a hyphen is encountered, the next non-CR/LF whitespace
499 // becomes CR+LF and the hyphen is erased. If there is no whitespace between
500 // two hyphens, the latter hyphen is erased and ignored.
501 void FormatStringWithHyphens(base::string16* text) {
502   // First pass marks all the hyphen positions.
503   struct HyphenPosition {
504     HyphenPosition() : position(0), next_whitespace_position(0) {}
505     size_t position;
506     size_t next_whitespace_position;  // 0 for none
507   };
508   std::vector<HyphenPosition> hyphen_positions;
509   HyphenPosition current_hyphen_position;
510   bool current_hyphen_position_is_valid = false;
511   const base::char16 kPdfiumHyphenEOL = 0xfffe;
512
513   for (size_t i = 0; i < text->size(); ++i) {
514     const base::char16& current_char = (*text)[i];
515     if (current_char == kPdfiumHyphenEOL) {
516       if (current_hyphen_position_is_valid)
517         hyphen_positions.push_back(current_hyphen_position);
518       current_hyphen_position = HyphenPosition();
519       current_hyphen_position.position = i;
520       current_hyphen_position_is_valid = true;
521     } else if (base::IsUnicodeWhitespace(current_char)) {
522       if (current_hyphen_position_is_valid) {
523         if (current_char != L'\r' && current_char != L'\n')
524           current_hyphen_position.next_whitespace_position = i;
525         hyphen_positions.push_back(current_hyphen_position);
526         current_hyphen_position_is_valid = false;
527       }
528     }
529   }
530   if (current_hyphen_position_is_valid)
531     hyphen_positions.push_back(current_hyphen_position);
532
533   // With all the hyphen positions, do the search and replace.
534   while (!hyphen_positions.empty()) {
535     static const base::char16 kCr[] = {L'\r', L'\0'};
536     const HyphenPosition& position = hyphen_positions.back();
537     if (position.next_whitespace_position != 0) {
538       (*text)[position.next_whitespace_position] = L'\n';
539       text->insert(position.next_whitespace_position, kCr);
540     }
541     text->erase(position.position, 1);
542     hyphen_positions.pop_back();
543   }
544
545   // Adobe Reader also get rid of trailing spaces right before a CRLF.
546   static const base::char16 kSpaceCrCn[] = {L' ', L'\r', L'\n', L'\0'};
547   static const base::char16 kCrCn[] = {L'\r', L'\n', L'\0'};
548   base::ReplaceSubstringsAfterOffset(text, 0, kSpaceCrCn, kCrCn);
549 }
550
551 // Replace CR/LF with just LF on POSIX.
552 void FormatStringForOS(base::string16* text) {
553 #if defined(OS_POSIX)
554   static const base::char16 kCr[] = {L'\r', L'\0'};
555   static const base::char16 kBlank[] = {L'\0'};
556   base::ReplaceChars(*text, kCr, kBlank, text);
557 #elif defined(OS_WIN)
558   // Do nothing
559 #else
560   NOTIMPLEMENTED();
561 #endif
562 }
563
564 // Returns true if |cur| is a character to break on.
565 // For double clicks, look for work breaks.
566 // For triple clicks, look for line breaks.
567 // The actual algorithm used in Blink is much more complicated, so do a simple
568 // approximation.
569 bool FindMultipleClickBoundary(bool is_double_click, base::char16 cur) {
570   if (!is_double_click)
571     return cur == '\n';
572
573   // Deal with ASCII characters.
574   if (base::IsAsciiAlpha(cur) || base::IsAsciiDigit(cur) || cur == '_')
575     return false;
576   if (cur < 128)
577     return true;
578
579   static constexpr base::char16 kZeroWidthSpace = 0x200B;
580   if (cur == kZeroWidthSpace)
581     return true;
582
583   return false;
584 }
585
586 std::string GetDocumentMetadata(FPDF_DOCUMENT doc, const std::string& key) {
587   size_t size = FPDF_GetMetaText(doc, key.c_str(), nullptr, 0);
588   if (size == 0)
589     return std::string();
590
591   base::string16 value;
592   PDFiumAPIStringBufferSizeInBytesAdapter<base::string16> string_adapter(
593       &value, size, false);
594   string_adapter.Close(
595       FPDF_GetMetaText(doc, key.c_str(), string_adapter.GetData(), size));
596   return base::UTF16ToUTF8(value);
597 }
598
599 gin::IsolateHolder* g_isolate_holder = nullptr;
600
601 void SetUpV8() {
602   gin::IsolateHolder::Initialize(gin::IsolateHolder::kNonStrictMode,
603                                  gin::IsolateHolder::kStableV8Extras,
604                                  gin::ArrayBufferAllocator::SharedInstance());
605   DCHECK(!g_isolate_holder);
606   g_isolate_holder = new gin::IsolateHolder(base::ThreadTaskRunnerHandle::Get(),
607                                             gin::IsolateHolder::kSingleThread);
608   g_isolate_holder->isolate()->Enter();
609 }
610
611 void TearDownV8() {
612   g_isolate_holder->isolate()->Exit();
613   delete g_isolate_holder;
614   g_isolate_holder = nullptr;
615 }
616
617 int GetBlockForJpeg(void* param,
618                     unsigned long pos,
619                     unsigned char* buf,
620                     unsigned long size) {
621   std::vector<uint8_t>* data_vector = static_cast<std::vector<uint8_t>*>(param);
622   if (pos + size < pos || pos + size > data_vector->size())
623     return 0;
624   memcpy(buf, data_vector->data() + pos, size);
625   return 1;
626 }
627
628 std::string WideStringToString(FPDF_WIDESTRING wide_string) {
629   return base::UTF16ToUTF8(reinterpret_cast<const base::char16*>(wide_string));
630 }
631
632 // Returns true if the given |area| and |form_type| combination from
633 // PDFiumEngine::GetCharIndex() indicates it is a form text area.
634 bool IsFormTextArea(PDFiumPage::Area area, int form_type) {
635   if (form_type == FPDF_FORMFIELD_UNKNOWN)
636     return false;
637
638   DCHECK_EQ(area, PDFiumPage::FormTypeToArea(form_type));
639   return area == PDFiumPage::FORM_TEXT_AREA;
640 }
641
642 // Checks whether or not focus is in an editable form text area given the
643 // form field annotation flags and form type.
644 bool CheckIfEditableFormTextArea(int flags, int form_type) {
645   if (!!(flags & FPDF_FORMFLAG_READONLY))
646     return false;
647   if (form_type == FPDF_FORMFIELD_TEXTFIELD)
648     return true;
649   if (form_type == FPDF_FORMFIELD_COMBOBOX &&
650       (!!(flags & FPDF_FORMFLAG_CHOICE_EDIT))) {
651     return true;
652   }
653   return false;
654 }
655
656 bool IsLinkArea(PDFiumPage::Area area) {
657   return area == PDFiumPage::WEBLINK_AREA || area == PDFiumPage::DOCLINK_AREA;
658 }
659
660 // Normalize a MouseInputEvent. For Mac, this means transforming ctrl + left
661 // button down events into a right button down events.
662 pp::MouseInputEvent NormalizeMouseEvent(pp::Instance* instance,
663                                         const pp::MouseInputEvent& event) {
664   pp::MouseInputEvent normalized_event = event;
665 #if defined(OS_MACOSX)
666   uint32_t modifiers = event.GetModifiers();
667   if ((modifiers & PP_INPUTEVENT_MODIFIER_CONTROLKEY) &&
668       event.GetButton() == PP_INPUTEVENT_MOUSEBUTTON_LEFT &&
669       event.GetType() == PP_INPUTEVENT_TYPE_MOUSEDOWN) {
670     uint32_t new_modifiers = modifiers & ~PP_INPUTEVENT_MODIFIER_CONTROLKEY;
671     normalized_event = pp::MouseInputEvent(
672         instance, PP_INPUTEVENT_TYPE_MOUSEDOWN, event.GetTimeStamp(),
673         new_modifiers, PP_INPUTEVENT_MOUSEBUTTON_RIGHT, event.GetPosition(), 1,
674         event.GetMovement());
675   }
676 #endif
677   return normalized_event;
678 }
679
680 // These values are intended for the JS to handle, and it doesn't have access
681 // to the PDFDEST_VIEW_* defines.
682 std::string ConvertViewIntToViewString(unsigned long view_int) {
683   switch (view_int) {
684     case PDFDEST_VIEW_XYZ:
685       return "XYZ";
686     case PDFDEST_VIEW_FIT:
687       return "Fit";
688     case PDFDEST_VIEW_FITH:
689       return "FitH";
690     case PDFDEST_VIEW_FITV:
691       return "FitV";
692     case PDFDEST_VIEW_FITR:
693       return "FitR";
694     case PDFDEST_VIEW_FITB:
695       return "FitB";
696     case PDFDEST_VIEW_FITBH:
697       return "FitBH";
698     case PDFDEST_VIEW_FITBV:
699       return "FitBV";
700     case PDFDEST_VIEW_UNKNOWN_MODE:
701       return "";
702     default:
703       NOTREACHED();
704       return "";
705   }
706 }
707
708 }  // namespace
709
710 bool InitializeSDK() {
711   SetUpV8();
712
713   FPDF_LIBRARY_CONFIG config;
714   config.version = 2;
715   config.m_pUserFontPaths = nullptr;
716   config.m_pIsolate = v8::Isolate::GetCurrent();
717   config.m_v8EmbedderSlot = gin::kEmbedderPDFium;
718   FPDF_InitLibraryWithConfig(&config);
719
720 #if defined(OS_LINUX)
721   // Font loading doesn't work in the renderer sandbox in Linux.
722   FPDF_SetSystemFontInfo(&g_font_info);
723 #else
724   g_font_info =
725       new FPDF_SYSFONTINFO_WITHMETRICS(FPDF_GetDefaultSystemFontInfo());
726   g_font_info->Release = Release;
727   g_font_info->EnumFonts = EnumFonts;
728   // Set new MapFont that calculates metrics
729   g_font_info->MapFont = MapFontWithMetrics;
730   g_font_info->GetFont = GetFont;
731   g_font_info->GetFaceName = GetFaceName;
732   g_font_info->GetFontCharset = GetFontCharset;
733   g_font_info->GetFontData = GetFontData;
734   g_font_info->DeleteFont = DeleteFont;
735   FPDF_SetSystemFontInfo(g_font_info);
736 #endif
737
738   FSDK_SetUnSpObjProcessHandler(&g_unsupported_info);
739
740   return true;
741 }
742
743 void ShutdownSDK() {
744   FPDF_DestroyLibrary();
745 #if !defined(OS_LINUX)
746   delete g_font_info;
747 #endif
748   TearDownV8();
749 }
750
751 std::unique_ptr<PDFEngine> PDFEngine::Create(PDFEngine::Client* client) {
752   return std::make_unique<PDFiumEngine>(client);
753 }
754
755 PDFiumEngine::PDFiumEngine(PDFEngine::Client* client)
756     : client_(client),
757       current_zoom_(1.0),
758       current_rotation_(0),
759       doc_(nullptr),
760       form_(nullptr),
761       defer_page_unload_(false),
762       selecting_(false),
763       mouse_down_state_(PDFiumPage::NONSELECTABLE_AREA,
764                         PDFiumPage::LinkTarget()),
765       in_form_text_area_(false),
766       editable_form_text_area_(false),
767       mouse_left_button_down_(false),
768       mouse_middle_button_down_(false),
769       permissions_(0),
770       permissions_handler_revision_(-1),
771       fpdf_availability_(nullptr),
772       last_page_mouse_down_(-1),
773       most_visible_page_(-1),
774       called_do_document_action_(false),
775       render_grayscale_(false),
776       render_annots_(true),
777       edit_mode_(false) {
778   find_factory_.Initialize(this);
779   password_factory_.Initialize(this);
780
781   file_access_.m_FileLen = 0;
782   file_access_.m_GetBlock = &GetBlock;
783   file_access_.m_Param = this;
784
785   file_availability_.version = 1;
786   file_availability_.IsDataAvail = &IsDataAvail;
787   file_availability_.engine = this;
788
789   download_hints_.version = 1;
790   download_hints_.AddSegment = &AddSegment;
791   download_hints_.engine = this;
792
793   // Initialize FPDF_FORMFILLINFO member variables.  Deriving from this struct
794   // allows the static callbacks to be able to cast the FPDF_FORMFILLINFO in
795   // callbacks to ourself instead of maintaining a map of them to
796   // PDFiumEngine.
797   FPDF_FORMFILLINFO::version = 1;
798   FPDF_FORMFILLINFO::m_pJsPlatform = this;
799   FPDF_FORMFILLINFO::Release = nullptr;
800   FPDF_FORMFILLINFO::FFI_Invalidate = Form_Invalidate;
801   FPDF_FORMFILLINFO::FFI_OutputSelectedRect = Form_OutputSelectedRect;
802   FPDF_FORMFILLINFO::FFI_SetCursor = Form_SetCursor;
803   FPDF_FORMFILLINFO::FFI_SetTimer = Form_SetTimer;
804   FPDF_FORMFILLINFO::FFI_KillTimer = Form_KillTimer;
805   FPDF_FORMFILLINFO::FFI_GetLocalTime = Form_GetLocalTime;
806   FPDF_FORMFILLINFO::FFI_OnChange = Form_OnChange;
807   FPDF_FORMFILLINFO::FFI_GetPage = Form_GetPage;
808   FPDF_FORMFILLINFO::FFI_GetCurrentPage = Form_GetCurrentPage;
809   FPDF_FORMFILLINFO::FFI_GetRotation = Form_GetRotation;
810   FPDF_FORMFILLINFO::FFI_ExecuteNamedAction = Form_ExecuteNamedAction;
811   FPDF_FORMFILLINFO::FFI_SetTextFieldFocus = Form_SetTextFieldFocus;
812   FPDF_FORMFILLINFO::FFI_DoURIAction = Form_DoURIAction;
813   FPDF_FORMFILLINFO::FFI_DoGoToAction = Form_DoGoToAction;
814 #if defined(PDF_ENABLE_XFA)
815   FPDF_FORMFILLINFO::version = 2;
816   FPDF_FORMFILLINFO::FFI_EmailTo = Form_EmailTo;
817   FPDF_FORMFILLINFO::FFI_DisplayCaret = Form_DisplayCaret;
818   FPDF_FORMFILLINFO::FFI_SetCurrentPage = Form_SetCurrentPage;
819   FPDF_FORMFILLINFO::FFI_GetCurrentPageIndex = Form_GetCurrentPageIndex;
820   FPDF_FORMFILLINFO::FFI_GetPageViewRect = Form_GetPageViewRect;
821   FPDF_FORMFILLINFO::FFI_GetPlatform = Form_GetPlatform;
822   FPDF_FORMFILLINFO::FFI_PageEvent = nullptr;
823   FPDF_FORMFILLINFO::FFI_PopupMenu = Form_PopupMenu;
824   FPDF_FORMFILLINFO::FFI_PostRequestURL = Form_PostRequestURL;
825   FPDF_FORMFILLINFO::FFI_PutRequestURL = Form_PutRequestURL;
826   FPDF_FORMFILLINFO::FFI_UploadTo = Form_UploadTo;
827   FPDF_FORMFILLINFO::FFI_DownloadFromURL = Form_DownloadFromURL;
828   FPDF_FORMFILLINFO::FFI_OpenFile = Form_OpenFile;
829   FPDF_FORMFILLINFO::FFI_GotoURL = Form_GotoURL;
830   FPDF_FORMFILLINFO::FFI_GetLanguage = Form_GetLanguage;
831 #endif  // defined(PDF_ENABLE_XFA)
832   IPDF_JSPLATFORM::version = 3;
833   IPDF_JSPLATFORM::app_alert = Form_Alert;
834   IPDF_JSPLATFORM::app_beep = Form_Beep;
835   IPDF_JSPLATFORM::app_response = Form_Response;
836   IPDF_JSPLATFORM::Doc_getFilePath = Form_GetFilePath;
837   IPDF_JSPLATFORM::Doc_mail = Form_Mail;
838   IPDF_JSPLATFORM::Doc_print = Form_Print;
839   IPDF_JSPLATFORM::Doc_submitForm = Form_SubmitForm;
840   IPDF_JSPLATFORM::Doc_gotoPage = Form_GotoPage;
841   IPDF_JSPLATFORM::Field_browse = nullptr;
842
843   IFSDK_PAUSE::version = 1;
844   IFSDK_PAUSE::user = nullptr;
845   IFSDK_PAUSE::NeedToPauseNow = Pause_NeedToPauseNow;
846
847 #if defined(OS_LINUX)
848   // PreviewModeClient does not know its pp::Instance.
849   pp::Instance* instance = client_->GetPluginInstance();
850   if (instance)
851     g_last_instance_id = instance->pp_instance();
852 #endif
853 }
854
855 PDFiumEngine::~PDFiumEngine() {
856   for (auto& page : pages_)
857     page->Unload();
858
859   if (doc_) {
860     FORM_DoDocumentAAction(form_, FPDFDOC_AACTION_WC);
861     FPDFDOC_ExitFormFillEnvironment(form_);
862     FPDF_CloseDocument(doc_);
863   }
864   FPDFAvail_Destroy(fpdf_availability_);
865 }
866
867 #if defined(PDF_ENABLE_XFA)
868
869 void PDFiumEngine::Form_EmailTo(FPDF_FORMFILLINFO* param,
870                                 FPDF_FILEHANDLER* file_handler,
871                                 FPDF_WIDESTRING to,
872                                 FPDF_WIDESTRING subject,
873                                 FPDF_WIDESTRING cc,
874                                 FPDF_WIDESTRING bcc,
875                                 FPDF_WIDESTRING message) {
876   std::string to_str = WideStringToString(to);
877   std::string subject_str = WideStringToString(subject);
878   std::string cc_str = WideStringToString(cc);
879   std::string bcc_str = WideStringToString(bcc);
880   std::string message_str = WideStringToString(message);
881
882   PDFiumEngine* engine = static_cast<PDFiumEngine*>(param);
883   engine->client_->Email(to_str, cc_str, bcc_str, subject_str, message_str);
884 }
885
886 void PDFiumEngine::Form_DisplayCaret(FPDF_FORMFILLINFO* param,
887                                      FPDF_PAGE page,
888                                      FPDF_BOOL visible,
889                                      double left,
890                                      double top,
891                                      double right,
892                                      double bottom) {}
893
894 void PDFiumEngine::Form_SetCurrentPage(FPDF_FORMFILLINFO* param,
895                                        FPDF_DOCUMENT document,
896                                        int page) {
897   PDFiumEngine* engine = static_cast<PDFiumEngine*>(param);
898   pp::Rect page_view_rect = engine->GetPageContentsRect(page);
899   engine->ScrolledToYPosition(page_view_rect.height());
900   pp::Point pos(1, page_view_rect.height());
901   engine->SetScrollPosition(pos);
902 }
903
904 int PDFiumEngine::Form_GetCurrentPageIndex(FPDF_FORMFILLINFO* param,
905                                            FPDF_DOCUMENT document) {
906   PDFiumEngine* engine = static_cast<PDFiumEngine*>(param);
907   return engine->GetMostVisiblePage();
908 }
909
910 void PDFiumEngine::Form_GetPageViewRect(FPDF_FORMFILLINFO* param,
911                                         FPDF_PAGE page,
912                                         double* left,
913                                         double* top,
914                                         double* right,
915                                         double* bottom) {
916   PDFiumEngine* engine = static_cast<PDFiumEngine*>(param);
917   int page_index = engine->GetVisiblePageIndex(page);
918   if (!engine->PageIndexInBounds(page_index)) {
919     *left = 0;
920     *right = 0;
921     *top = 0;
922     *bottom = 0;
923     return;
924   }
925
926   pp::Rect page_view_rect = engine->GetPageContentsRect(page_index);
927
928   float toolbar_height_in_screen_coords =
929       engine->GetToolbarHeightInScreenCoords();
930
931   float page_width = FPDF_GetPageWidth(page);
932   float page_height = FPDF_GetPageHeight(page);
933
934   // To convert from a screen scale to a page scale, we multiply by
935   // (page_height / page_view_rect.height()) and
936   // (page_width / page_view_rect.width()),
937   // The base point of the page in screen coords is (page_view_rect.x(),
938   // page_view_rect.y()).
939   // Therefore, to convert an x position from screen to page
940   // coords, we use (page_width * (x - base_x) / page_view_rect.width()).
941   // For y positions, (page_height * (y - base_y) / page_view_rect.height()).
942
943   // The top-most y position that can be relied to be visible on the screen is
944   // the bottom of the toolbar, which is y = toolbar_height_in_screen_coords.
945   float screen_top_in_page_coords =
946       page_height * (toolbar_height_in_screen_coords - page_view_rect.y()) /
947       page_view_rect.height();
948   // The bottom-most y position that is visible on the screen is the bottom of
949   // the plugin area, which is y = engine->plugin_size_.height().
950   float screen_bottom_in_page_coords =
951       page_height * (engine->plugin_size_.height() - page_view_rect.y()) /
952       page_view_rect.height();
953   // The left-most x position that is visible on the screen is the left of the
954   // plugin area, which is x = 0.
955   float screen_left_in_page_coords =
956       page_width * (0 - page_view_rect.x()) / page_view_rect.width();
957   // The right-most x position that is visible on the screen is the right of the
958   // plugin area, which is x = engine->plugin_size_.width().
959   float screen_right_in_page_coords =
960       page_width * (engine->plugin_size_.width() - page_view_rect.x()) /
961       page_view_rect.width();
962
963   // Return the edge of the screen or of the page, since we're restricted to
964   // both.
965   *left = std::max(screen_left_in_page_coords, 0.0f);
966   *right = std::min(screen_right_in_page_coords, page_width);
967   *top = std::max(screen_top_in_page_coords, 0.0f);
968   *bottom = std::min(screen_bottom_in_page_coords, page_height);
969 }
970
971 int PDFiumEngine::Form_GetPlatform(FPDF_FORMFILLINFO* param,
972                                    void* platform,
973                                    int length) {
974   int platform_flag = -1;
975
976 #if defined(WIN32)
977   platform_flag = 0;
978 #elif defined(__linux__)
979   platform_flag = 1;
980 #else
981   platform_flag = 2;
982 #endif
983
984   std::string javascript =
985       "alert(\"Platform:" + base::NumberToString(platform_flag) + "\")";
986
987   return platform_flag;
988 }
989
990 FPDF_BOOL PDFiumEngine::Form_PopupMenu(FPDF_FORMFILLINFO* param,
991                                        FPDF_PAGE page,
992                                        FPDF_WIDGET widget,
993                                        int menu_flag,
994                                        float x,
995                                        float y) {
996   return false;
997 }
998
999 FPDF_BOOL PDFiumEngine::Form_PostRequestURL(FPDF_FORMFILLINFO* param,
1000                                             FPDF_WIDESTRING url,
1001                                             FPDF_WIDESTRING data,
1002                                             FPDF_WIDESTRING content_type,
1003                                             FPDF_WIDESTRING encode,
1004                                             FPDF_WIDESTRING header,
1005                                             FPDF_BSTR* response) {
1006   std::string url_str = WideStringToString(url);
1007   std::string data_str = WideStringToString(data);
1008   std::string content_type_str = WideStringToString(content_type);
1009   std::string encode_str = WideStringToString(encode);
1010   std::string header_str = WideStringToString(header);
1011
1012   std::string javascript = "alert(\"Post:" + url_str + "," + data_str + "," +
1013                            content_type_str + "," + encode_str + "," +
1014                            header_str + "\")";
1015   return true;
1016 }
1017
1018 FPDF_BOOL PDFiumEngine::Form_PutRequestURL(FPDF_FORMFILLINFO* param,
1019                                            FPDF_WIDESTRING url,
1020                                            FPDF_WIDESTRING data,
1021                                            FPDF_WIDESTRING encode) {
1022   std::string url_str = WideStringToString(url);
1023   std::string data_str = WideStringToString(data);
1024   std::string encode_str = WideStringToString(encode);
1025
1026   std::string javascript =
1027       "alert(\"Put:" + url_str + "," + data_str + "," + encode_str + "\")";
1028
1029   return true;
1030 }
1031
1032 void PDFiumEngine::Form_UploadTo(FPDF_FORMFILLINFO* param,
1033                                  FPDF_FILEHANDLER* file_handle,
1034                                  int file_flag,
1035                                  FPDF_WIDESTRING to) {
1036   std::string to_str = WideStringToString(to);
1037   // TODO: needs the full implementation of form uploading
1038 }
1039
1040 FPDF_LPFILEHANDLER PDFiumEngine::Form_DownloadFromURL(FPDF_FORMFILLINFO* param,
1041                                                       FPDF_WIDESTRING url) {
1042   // NOTE: Think hard about the security implications before allowing
1043   // a PDF file to perform this action.
1044   return nullptr;
1045 }
1046
1047 FPDF_FILEHANDLER* PDFiumEngine::Form_OpenFile(FPDF_FORMFILLINFO* param,
1048                                               int file_flag,
1049                                               FPDF_WIDESTRING url,
1050                                               const char* mode) {
1051   // NOTE: Think hard about the security implications before allowing
1052   // a PDF file to perform this action.
1053   return nullptr;
1054 }
1055
1056 void PDFiumEngine::Form_GotoURL(FPDF_FORMFILLINFO* param,
1057                                 FPDF_DOCUMENT document,
1058                                 FPDF_WIDESTRING url) {
1059   std::string url_str = WideStringToString(url);
1060   // TODO: needs to implement GOTO URL action
1061 }
1062
1063 int PDFiumEngine::Form_GetLanguage(FPDF_FORMFILLINFO* param,
1064                                    void* language,
1065                                    int length) {
1066   return 0;
1067 }
1068
1069 #endif  // defined(PDF_ENABLE_XFA)
1070
1071 int PDFiumEngine::GetBlock(void* param,
1072                            unsigned long position,
1073                            unsigned char* buffer,
1074                            unsigned long size) {
1075   PDFiumEngine* engine = static_cast<PDFiumEngine*>(param);
1076   return engine->doc_loader_->GetBlock(position, size, buffer);
1077 }
1078
1079 FPDF_BOOL PDFiumEngine::IsDataAvail(FX_FILEAVAIL* param,
1080                                     size_t offset,
1081                                     size_t size) {
1082   auto* file_avail = static_cast<FileAvail*>(param);
1083   return file_avail->engine->doc_loader_->IsDataAvailable(offset, size);
1084 }
1085
1086 void PDFiumEngine::AddSegment(FX_DOWNLOADHINTS* param,
1087                               size_t offset,
1088                               size_t size) {
1089   auto* download_hints = static_cast<DownloadHints*>(param);
1090   return download_hints->engine->doc_loader_->RequestData(offset, size);
1091 }
1092
1093 bool PDFiumEngine::New(const char* url, const char* headers) {
1094   url_ = url;
1095   if (headers)
1096     headers_ = headers;
1097   else
1098     headers_.clear();
1099   return true;
1100 }
1101
1102 void PDFiumEngine::PageOffsetUpdated(const pp::Point& page_offset) {
1103   page_offset_ = page_offset;
1104 }
1105
1106 void PDFiumEngine::PluginSizeUpdated(const pp::Size& size) {
1107   CancelPaints();
1108
1109   plugin_size_ = size;
1110   CalculateVisiblePages();
1111 }
1112
1113 void PDFiumEngine::ScrolledToXPosition(int position) {
1114   CancelPaints();
1115
1116   int old_x = position_.x();
1117   position_.set_x(position);
1118   CalculateVisiblePages();
1119   client_->DidScroll(pp::Point(old_x - position, 0));
1120   OnSelectionPositionChanged();
1121 }
1122
1123 void PDFiumEngine::ScrolledToYPosition(int position) {
1124   CancelPaints();
1125
1126   int old_y = position_.y();
1127   position_.set_y(position);
1128   CalculateVisiblePages();
1129   client_->DidScroll(pp::Point(0, old_y - position));
1130   OnSelectionPositionChanged();
1131 }
1132
1133 void PDFiumEngine::PrePaint() {
1134   for (auto& paint : progressive_paints_)
1135     paint.painted_ = false;
1136 }
1137
1138 void PDFiumEngine::Paint(const pp::Rect& rect,
1139                          pp::ImageData* image_data,
1140                          std::vector<pp::Rect>* ready,
1141                          std::vector<pp::Rect>* pending) {
1142   DCHECK(image_data);
1143   DCHECK(ready);
1144   DCHECK(pending);
1145
1146   pp::Rect leftover = rect;
1147   for (size_t i = 0; i < visible_pages_.size(); ++i) {
1148     int index = visible_pages_[i];
1149     // Convert the current page's rectangle to screen rectangle.  We do this
1150     // instead of the reverse (converting the dirty rectangle from screen to
1151     // page coordinates) because then we'd have to convert back to screen
1152     // coordinates, and the rounding errors sometime leave pixels dirty or even
1153     // move the text up or down a pixel when zoomed.
1154     pp::Rect page_rect_in_screen = GetPageScreenRect(index);
1155     pp::Rect dirty_in_screen = page_rect_in_screen.Intersect(leftover);
1156     if (dirty_in_screen.IsEmpty())
1157       continue;
1158
1159     // Compute the leftover dirty region. The first page may have blank space
1160     // above it, in which case we also need to subtract that space from the
1161     // dirty region.
1162     if (i == 0) {
1163       pp::Rect blank_space_in_screen = dirty_in_screen;
1164       blank_space_in_screen.set_y(0);
1165       blank_space_in_screen.set_height(dirty_in_screen.y());
1166       leftover = leftover.Subtract(blank_space_in_screen);
1167     }
1168     leftover = leftover.Subtract(dirty_in_screen);
1169
1170     if (pages_[index]->available()) {
1171       int progressive = GetProgressiveIndex(index);
1172       if (progressive != -1) {
1173         DCHECK_GE(progressive, 0);
1174         DCHECK_LT(static_cast<size_t>(progressive), progressive_paints_.size());
1175         if (progressive_paints_[progressive].rect != dirty_in_screen) {
1176           // The PDFium code can only handle one progressive paint at a time, so
1177           // queue this up. Previously we used to merge the rects when this
1178           // happened, but it made scrolling up on complex PDFs very slow since
1179           // there would be a damaged rect at the top (from scroll) and at the
1180           // bottom (from toolbar).
1181           pending->push_back(dirty_in_screen);
1182           continue;
1183         }
1184       }
1185
1186       if (progressive == -1) {
1187         progressive = StartPaint(index, dirty_in_screen);
1188         progressive_paint_timeout_ = kMaxInitialProgressivePaintTime;
1189       } else {
1190         progressive_paint_timeout_ = kMaxProgressivePaintTime;
1191       }
1192
1193       progressive_paints_[progressive].painted_ = true;
1194       if (ContinuePaint(progressive, image_data)) {
1195         FinishPaint(progressive, image_data);
1196         ready->push_back(dirty_in_screen);
1197       } else {
1198         pending->push_back(dirty_in_screen);
1199       }
1200     } else {
1201       PaintUnavailablePage(index, dirty_in_screen, image_data);
1202       ready->push_back(dirty_in_screen);
1203     }
1204   }
1205 }
1206
1207 void PDFiumEngine::PostPaint() {
1208   for (size_t i = 0; i < progressive_paints_.size(); ++i) {
1209     if (progressive_paints_[i].painted_)
1210       continue;
1211
1212     // This rectangle must have been merged with another one, that's why we
1213     // weren't asked to paint it. Remove it or otherwise we'll never finish
1214     // painting.
1215     FPDF_RenderPage_Close(pages_[progressive_paints_[i].page_index]->GetPage());
1216     FPDFBitmap_Destroy(progressive_paints_[i].bitmap);
1217     progressive_paints_.erase(progressive_paints_.begin() + i);
1218     --i;
1219   }
1220 }
1221
1222 bool PDFiumEngine::HandleDocumentLoad(const pp::URLLoader& loader) {
1223   password_tries_remaining_ = kMaxPasswordTries;
1224   process_when_pending_request_complete_ = true;
1225   auto loader_wrapper =
1226       std::make_unique<URLLoaderWrapperImpl>(GetPluginInstance(), loader);
1227   loader_wrapper->SetResponseHeaders(headers_);
1228
1229   doc_loader_ = std::make_unique<DocumentLoader>(this);
1230   if (doc_loader_->Init(std::move(loader_wrapper), url_)) {
1231     // request initial data.
1232     doc_loader_->RequestData(0, 1);
1233     return true;
1234   }
1235   return false;
1236 }
1237
1238 pp::Instance* PDFiumEngine::GetPluginInstance() {
1239   return client_->GetPluginInstance();
1240 }
1241
1242 std::unique_ptr<URLLoaderWrapper> PDFiumEngine::CreateURLLoader() {
1243   return std::make_unique<URLLoaderWrapperImpl>(GetPluginInstance(),
1244                                                 client_->CreateURLLoader());
1245 }
1246
1247 void PDFiumEngine::AppendPage(PDFEngine* engine, int index) {
1248   // Unload and delete the blank page before appending.
1249   pages_[index]->Unload();
1250   pages_[index]->set_calculated_links(false);
1251   pp::Size curr_page_size = GetPageSize(index);
1252   FPDFPage_Delete(doc_, index);
1253   FPDF_ImportPages(doc_, static_cast<PDFiumEngine*>(engine)->doc(), "1", index);
1254   pp::Size new_page_size = GetPageSize(index);
1255   if (curr_page_size != new_page_size)
1256     LoadPageInfo(true);
1257   client_->Invalidate(GetPageScreenRect(index));
1258 }
1259
1260 #if defined(PDF_ENABLE_XFA)
1261 void PDFiumEngine::SetScrollPosition(const pp::Point& position) {
1262   position_ = position;
1263 }
1264 #endif
1265
1266 std::string PDFiumEngine::GetMetadata(const std::string& key) {
1267   return GetDocumentMetadata(doc(), key);
1268 }
1269
1270 void PDFiumEngine::OnPendingRequestComplete() {
1271   if (!process_when_pending_request_complete_)
1272     return;
1273   if (!fpdf_availability_) {
1274     file_access_.m_FileLen = doc_loader_->GetDocumentSize();
1275     fpdf_availability_ = FPDFAvail_Create(&file_availability_, &file_access_);
1276     DCHECK(fpdf_availability_);
1277     // Currently engine does not deal efficiently with some non-linearized
1278     // files.
1279     // See http://code.google.com/p/chromium/issues/detail?id=59400
1280     // To improve user experience we download entire file for non-linearized
1281     // PDF.
1282     if (FPDFAvail_IsLinearized(fpdf_availability_) != PDF_LINEARIZED) {
1283       // Wait complete document.
1284       process_when_pending_request_complete_ = false;
1285       FPDFAvail_Destroy(fpdf_availability_);
1286       fpdf_availability_ = nullptr;
1287       return;
1288     }
1289   }
1290
1291   if (!doc_) {
1292     LoadDocument();
1293     return;
1294   }
1295
1296   if (pages_.empty()) {
1297     LoadBody();
1298     return;
1299   }
1300
1301   // LoadDocument() will result in |pending_pages_| being reset so there's no
1302   // need to run the code below in that case.
1303   bool update_pages = false;
1304   std::vector<int> still_pending;
1305   for (int pending_page : pending_pages_) {
1306     if (CheckPageAvailable(pending_page, &still_pending)) {
1307       update_pages = true;
1308       if (IsPageVisible(pending_page)) {
1309         client_->NotifyPageBecameVisible(
1310             pages_[pending_page]->GetPageFeatures());
1311         client_->Invalidate(GetPageScreenRect(pending_page));
1312       }
1313     }
1314   }
1315   pending_pages_.swap(still_pending);
1316   if (update_pages)
1317     LoadPageInfo(true);
1318 }
1319
1320 void PDFiumEngine::OnNewDataReceived() {
1321   client_->DocumentLoadProgress(doc_loader_->bytes_received(),
1322                                 doc_loader_->GetDocumentSize());
1323 }
1324
1325 void PDFiumEngine::OnDocumentComplete() {
1326   if (doc_)
1327     return FinishLoadingDocument();
1328
1329   file_access_.m_FileLen = doc_loader_->GetDocumentSize();
1330   if (!fpdf_availability_) {
1331     fpdf_availability_ = FPDFAvail_Create(&file_availability_, &file_access_);
1332     DCHECK(fpdf_availability_);
1333   }
1334   LoadDocument();
1335 }
1336
1337 void PDFiumEngine::OnDocumentCanceled() {
1338   if (visible_pages_.empty())
1339     client_->DocumentLoadFailed();
1340   else
1341     OnDocumentComplete();
1342 }
1343
1344 void PDFiumEngine::CancelBrowserDownload() {
1345   client_->CancelBrowserDownload();
1346 }
1347
1348 void PDFiumEngine::FinishLoadingDocument() {
1349   DCHECK(doc_);
1350   DCHECK(doc_loader_->IsDocumentComplete());
1351
1352   LoadBody();
1353
1354   bool need_update = false;
1355   for (size_t i = 0; i < pages_.size(); ++i) {
1356     if (pages_[i]->available())
1357       continue;
1358
1359     pages_[i]->set_available(true);
1360     // We still need to call IsPageAvail() even if the whole document is
1361     // already downloaded.
1362     FPDFAvail_IsPageAvail(fpdf_availability_, i, &download_hints_);
1363     need_update = true;
1364     if (IsPageVisible(i))
1365       client_->Invalidate(GetPageScreenRect(i));
1366   }
1367   if (need_update)
1368     LoadPageInfo(true);
1369
1370   if (called_do_document_action_)
1371     return;
1372   called_do_document_action_ = true;
1373
1374   // These can only be called now, as the JS might end up needing a page.
1375   FORM_DoDocumentJSAction(form_);
1376   FORM_DoDocumentOpenAction(form_);
1377   if (most_visible_page_ != -1) {
1378     FPDF_PAGE new_page = pages_[most_visible_page_]->GetPage();
1379     FORM_DoPageAAction(new_page, form_, FPDFPAGE_AACTION_OPEN);
1380   }
1381
1382   if (doc_) {
1383     DocumentFeatures document_features;
1384     document_features.page_count = pages_.size();
1385     document_features.has_attachments = (FPDFDoc_GetAttachmentCount(doc_) > 0);
1386     document_features.is_linearized =
1387         (FPDFAvail_IsLinearized(fpdf_availability_) == PDF_LINEARIZED);
1388     document_features.is_tagged = FPDFCatalog_IsTagged(doc_);
1389     document_features.form_type = static_cast<FormType>(FPDF_GetFormType(doc_));
1390     client_->DocumentLoadComplete(document_features,
1391                                   doc_loader_->bytes_received());
1392   }
1393 }
1394
1395 void PDFiumEngine::UnsupportedFeature(int type) {
1396   std::string feature;
1397   switch (type) {
1398 #if !defined(PDF_ENABLE_XFA)
1399     case FPDF_UNSP_DOC_XFAFORM:
1400       feature = "XFA";
1401       break;
1402 #endif
1403     case FPDF_UNSP_DOC_PORTABLECOLLECTION:
1404       feature = "Portfolios_Packages";
1405       break;
1406     case FPDF_UNSP_DOC_ATTACHMENT:
1407     case FPDF_UNSP_ANNOT_ATTACHMENT:
1408       feature = "Attachment";
1409       break;
1410     case FPDF_UNSP_DOC_SECURITY:
1411       feature = "Rights_Management";
1412       break;
1413     case FPDF_UNSP_DOC_SHAREDREVIEW:
1414       feature = "Shared_Review";
1415       break;
1416     case FPDF_UNSP_DOC_SHAREDFORM_ACROBAT:
1417     case FPDF_UNSP_DOC_SHAREDFORM_FILESYSTEM:
1418     case FPDF_UNSP_DOC_SHAREDFORM_EMAIL:
1419       feature = "Shared_Form";
1420       break;
1421     case FPDF_UNSP_ANNOT_3DANNOT:
1422       feature = "3D";
1423       break;
1424     case FPDF_UNSP_ANNOT_MOVIE:
1425       feature = "Movie";
1426       break;
1427     case FPDF_UNSP_ANNOT_SOUND:
1428       feature = "Sound";
1429       break;
1430     case FPDF_UNSP_ANNOT_SCREEN_MEDIA:
1431     case FPDF_UNSP_ANNOT_SCREEN_RICHMEDIA:
1432       feature = "Screen";
1433       break;
1434     case FPDF_UNSP_ANNOT_SIG:
1435       feature = "Digital_Signature";
1436       break;
1437   }
1438   client_->DocumentHasUnsupportedFeature(feature);
1439 }
1440
1441 void PDFiumEngine::FontSubstituted() {
1442   client_->FontSubstituted();
1443 }
1444
1445 void PDFiumEngine::ContinueFind(int32_t result) {
1446   StartFind(current_find_text_, result != 0);
1447 }
1448
1449 bool PDFiumEngine::HandleEvent(const pp::InputEvent& event) {
1450   DCHECK(!defer_page_unload_);
1451   defer_page_unload_ = true;
1452   bool rv = false;
1453   switch (event.GetType()) {
1454     case PP_INPUTEVENT_TYPE_MOUSEDOWN:
1455       rv = OnMouseDown(pp::MouseInputEvent(event));
1456       break;
1457     case PP_INPUTEVENT_TYPE_MOUSEUP:
1458       rv = OnMouseUp(pp::MouseInputEvent(event));
1459       break;
1460     case PP_INPUTEVENT_TYPE_MOUSEMOVE:
1461       rv = OnMouseMove(pp::MouseInputEvent(event));
1462       break;
1463     case PP_INPUTEVENT_TYPE_MOUSEENTER:
1464       OnMouseEnter(pp::MouseInputEvent(event));
1465       break;
1466     case PP_INPUTEVENT_TYPE_KEYDOWN:
1467       rv = OnKeyDown(pp::KeyboardInputEvent(event));
1468       break;
1469     case PP_INPUTEVENT_TYPE_KEYUP:
1470       rv = OnKeyUp(pp::KeyboardInputEvent(event));
1471       break;
1472     case PP_INPUTEVENT_TYPE_CHAR:
1473       rv = OnChar(pp::KeyboardInputEvent(event));
1474       break;
1475     case PP_INPUTEVENT_TYPE_TOUCHSTART: {
1476       KillTouchTimer(next_touch_timer_id_);
1477
1478       pp::TouchInputEvent touch_event(event);
1479       if (touch_event.GetTouchCount(PP_TOUCHLIST_TYPE_TARGETTOUCHES) == 1)
1480         ScheduleTouchTimer(touch_event);
1481       break;
1482     }
1483     case PP_INPUTEVENT_TYPE_TOUCHEND:
1484       KillTouchTimer(next_touch_timer_id_);
1485       break;
1486     case PP_INPUTEVENT_TYPE_TOUCHMOVE:
1487       // TODO(dsinclair): This should allow a little bit of movement (up to the
1488       // touch radii) to account for finger jiggle.
1489       KillTouchTimer(next_touch_timer_id_);
1490       break;
1491     default:
1492       break;
1493   }
1494
1495   DCHECK(defer_page_unload_);
1496   defer_page_unload_ = false;
1497
1498   // Store the pages to unload away because the act of unloading pages can cause
1499   // there to be more pages to unload. We leave those extra pages to be unloaded
1500   // on the next go around.
1501   std::vector<int> pages_to_unload;
1502   std::swap(pages_to_unload, deferred_page_unloads_);
1503   for (int page_index : pages_to_unload)
1504     pages_[page_index]->Unload();
1505
1506   return rv;
1507 }
1508
1509 uint32_t PDFiumEngine::QuerySupportedPrintOutputFormats() {
1510   if (HasPermission(PERMISSION_PRINT_HIGH_QUALITY))
1511     return PP_PRINTOUTPUTFORMAT_PDF | PP_PRINTOUTPUTFORMAT_RASTER;
1512   if (HasPermission(PERMISSION_PRINT_LOW_QUALITY))
1513     return PP_PRINTOUTPUTFORMAT_RASTER;
1514   return 0;
1515 }
1516
1517 void PDFiumEngine::PrintBegin() {
1518   FORM_DoDocumentAAction(form_, FPDFDOC_AACTION_WP);
1519 }
1520
1521 pp::Resource PDFiumEngine::PrintPages(
1522     const PP_PrintPageNumberRange_Dev* page_ranges,
1523     uint32_t page_range_count,
1524     const PP_PrintSettings_Dev& print_settings) {
1525   ScopedSubstFont scoped_subst_font(this);
1526   if ((print_settings.format & PP_PRINTOUTPUTFORMAT_PDF) &&
1527       HasPermission(PERMISSION_PRINT_HIGH_QUALITY)) {
1528     return PrintPagesAsPDF(page_ranges, page_range_count, print_settings);
1529   }
1530   if (HasPermission(PERMISSION_PRINT_LOW_QUALITY))
1531     return PrintPagesAsRasterPDF(page_ranges, page_range_count, print_settings);
1532   return pp::Resource();
1533 }
1534
1535 FPDF_DOCUMENT PDFiumEngine::CreateSinglePageRasterPdf(
1536     double source_page_width,
1537     double source_page_height,
1538     const PP_PrintSettings_Dev& print_settings,
1539     PDFiumPage* page_to_print) {
1540   FPDF_DOCUMENT temp_doc = FPDF_CreateNewDocument();
1541   if (!temp_doc)
1542     return temp_doc;
1543
1544   const pp::Size& bitmap_size(page_to_print->rect().size());
1545
1546   pp::ImageData image =
1547       pp::ImageData(client_->GetPluginInstance(),
1548                     PP_IMAGEDATAFORMAT_BGRA_PREMUL, bitmap_size, false);
1549
1550   FPDF_BITMAP bitmap =
1551       FPDFBitmap_CreateEx(bitmap_size.width(), bitmap_size.height(),
1552                           FPDFBitmap_BGRx, image.data(), image.stride());
1553
1554   // Clear the bitmap
1555   FPDFBitmap_FillRect(bitmap, 0, 0, bitmap_size.width(), bitmap_size.height(),
1556                       0xFFFFFFFF);
1557
1558   pp::Rect page_rect = page_to_print->rect();
1559   FPDF_RenderPageBitmap(bitmap, page_to_print->GetPrintPage(), page_rect.x(),
1560                         page_rect.y(), page_rect.width(), page_rect.height(),
1561                         print_settings.orientation,
1562                         FPDF_PRINTING | FPDF_NO_CATCH);
1563
1564   // Draw the forms.
1565   FPDF_FFLDraw(form_, bitmap, page_to_print->GetPrintPage(), page_rect.x(),
1566                page_rect.y(), page_rect.width(), page_rect.height(),
1567                print_settings.orientation,
1568                FPDF_ANNOT | FPDF_PRINTING | FPDF_NO_CATCH);
1569
1570   unsigned char* bitmap_data =
1571       static_cast<unsigned char*>(FPDFBitmap_GetBuffer(bitmap));
1572   double ratio_x = ConvertUnitDouble(bitmap_size.width(), print_settings.dpi,
1573                                      kPointsPerInch);
1574   double ratio_y = ConvertUnitDouble(bitmap_size.height(), print_settings.dpi,
1575                                      kPointsPerInch);
1576
1577   // Add the bitmap to an image object and add the image object to the output
1578   // page.
1579   FPDF_PAGEOBJECT temp_img = FPDFPageObj_NewImageObj(temp_doc);
1580
1581   bool encoded = false;
1582   std::vector<uint8_t> compressed_bitmap_data;
1583   if (!(print_settings.format & PP_PRINTOUTPUTFORMAT_PDF)) {
1584     // Use quality = 40 as this does not significantly degrade the printed
1585     // document relative to a normal bitmap and provides better compression than
1586     // a higher quality setting.
1587     const int kQuality = 40;
1588     SkImageInfo info = SkImageInfo::Make(
1589         FPDFBitmap_GetWidth(bitmap), FPDFBitmap_GetHeight(bitmap),
1590         kBGRA_8888_SkColorType, kOpaque_SkAlphaType);
1591     SkPixmap src(info, bitmap_data, FPDFBitmap_GetStride(bitmap));
1592     encoded = gfx::JPEGCodec::Encode(src, kQuality, &compressed_bitmap_data);
1593   }
1594
1595   {
1596     std::unique_ptr<void, FPDFPageDeleter> temp_page_holder(
1597         FPDFPage_New(temp_doc, 0, source_page_width, source_page_height));
1598     FPDF_PAGE temp_page = temp_page_holder.get();
1599     if (encoded) {
1600       FPDF_FILEACCESS file_access = {};
1601       file_access.m_FileLen =
1602           static_cast<unsigned long>(compressed_bitmap_data.size());
1603       file_access.m_GetBlock = &GetBlockForJpeg;
1604       file_access.m_Param = &compressed_bitmap_data;
1605
1606       FPDFImageObj_LoadJpegFileInline(&temp_page, 1, temp_img, &file_access);
1607     } else {
1608       FPDFImageObj_SetBitmap(&temp_page, 1, temp_img, bitmap);
1609     }
1610
1611     FPDFImageObj_SetMatrix(temp_img, ratio_x, 0, 0, ratio_y, 0, 0);
1612     FPDFPage_InsertObject(temp_page, temp_img);
1613     FPDFPage_GenerateContent(temp_page);
1614   }
1615
1616   page_to_print->ClosePrintPage();
1617   FPDFBitmap_Destroy(bitmap);
1618
1619   return temp_doc;
1620 }
1621
1622 pp::Buffer_Dev PDFiumEngine::PrintPagesAsRasterPDF(
1623     const PP_PrintPageNumberRange_Dev* page_ranges,
1624     uint32_t page_range_count,
1625     const PP_PrintSettings_Dev& print_settings) {
1626   if (!page_range_count)
1627     return pp::Buffer_Dev();
1628
1629   // If document is not downloaded yet, disable printing.
1630   if (doc_ && !doc_loader_->IsDocumentComplete())
1631     return pp::Buffer_Dev();
1632
1633   FPDF_DOCUMENT output_doc = FPDF_CreateNewDocument();
1634   if (!output_doc)
1635     return pp::Buffer_Dev();
1636
1637   KillFormFocus();
1638
1639   std::vector<PDFiumPage> pages_to_print;
1640   // width and height of source PDF pages.
1641   std::vector<std::pair<double, double>> source_page_sizes;
1642   // Collect pages to print and sizes of source pages.
1643   std::vector<uint32_t> page_numbers =
1644       GetPageNumbersFromPrintPageNumberRange(page_ranges, page_range_count);
1645   for (uint32_t page_number : page_numbers) {
1646     FPDF_PAGE pdf_page = FPDF_LoadPage(doc_, page_number);
1647     double source_page_width = FPDF_GetPageWidth(pdf_page);
1648     double source_page_height = FPDF_GetPageHeight(pdf_page);
1649     source_page_sizes.push_back(
1650         std::make_pair(source_page_width, source_page_height));
1651     // For computing size in pixels, use a square dpi since the source PDF page
1652     // has square DPI.
1653     int width_in_pixels =
1654         ConvertUnit(source_page_width, kPointsPerInch, print_settings.dpi);
1655     int height_in_pixels =
1656         ConvertUnit(source_page_height, kPointsPerInch, print_settings.dpi);
1657
1658     pp::Rect rect(width_in_pixels, height_in_pixels);
1659     pages_to_print.push_back(PDFiumPage(this, page_number, rect, true));
1660     FPDF_ClosePage(pdf_page);
1661   }
1662
1663 #if defined(OS_LINUX)
1664   g_last_instance_id = client_->GetPluginInstance()->pp_instance();
1665 #endif
1666
1667   size_t i = 0;
1668   for (; i < pages_to_print.size(); ++i) {
1669     double source_page_width = source_page_sizes[i].first;
1670     double source_page_height = source_page_sizes[i].second;
1671
1672     // Use temp_doc to compress image by saving PDF to buffer.
1673     FPDF_DOCUMENT temp_doc =
1674         CreateSinglePageRasterPdf(source_page_width, source_page_height,
1675                                   print_settings, &pages_to_print[i]);
1676
1677     if (!temp_doc)
1678       break;
1679
1680     pp::Buffer_Dev buffer = GetFlattenedPrintData(temp_doc);
1681     FPDF_CloseDocument(temp_doc);
1682
1683     PDFiumMemBufferFileRead file_read(buffer.data(), buffer.size());
1684     temp_doc = FPDF_LoadCustomDocument(&file_read, nullptr);
1685
1686     FPDF_BOOL imported = FPDF_ImportPages(output_doc, temp_doc, "1", i);
1687     FPDF_CloseDocument(temp_doc);
1688     if (!imported)
1689       break;
1690   }
1691
1692   pp::Buffer_Dev buffer;
1693   if (i == pages_to_print.size()) {
1694     FPDF_CopyViewerPreferences(output_doc, doc_);
1695     FitContentsToPrintableAreaIfRequired(output_doc, print_settings);
1696     // Now flatten all the output pages.
1697     buffer = GetFlattenedPrintData(output_doc);
1698   }
1699   FPDF_CloseDocument(output_doc);
1700   return buffer;
1701 }
1702
1703 pp::Buffer_Dev PDFiumEngine::GetFlattenedPrintData(FPDF_DOCUMENT doc) {
1704   pp::Buffer_Dev buffer;
1705   ScopedSubstFont scoped_subst_font(this);
1706   int page_count = FPDF_GetPageCount(doc);
1707   for (int i = 0; i < page_count; ++i) {
1708     FPDF_PAGE page = FPDF_LoadPage(doc, i);
1709     DCHECK(page);
1710     int flatten_ret = FPDFPage_Flatten(page, FLAT_PRINT);
1711     FPDF_ClosePage(page);
1712     if (flatten_ret == FLATTEN_FAIL)
1713       return buffer;
1714   }
1715
1716   PDFiumMemBufferFileWrite output_file_write;
1717   if (FPDF_SaveAsCopy(doc, &output_file_write, 0)) {
1718     size_t size = output_file_write.size();
1719     buffer = pp::Buffer_Dev(client_->GetPluginInstance(), size);
1720     if (!buffer.is_null())
1721       memcpy(buffer.data(), output_file_write.buffer().c_str(), size);
1722   }
1723   return buffer;
1724 }
1725
1726 pp::Buffer_Dev PDFiumEngine::PrintPagesAsPDF(
1727     const PP_PrintPageNumberRange_Dev* page_ranges,
1728     uint32_t page_range_count,
1729     const PP_PrintSettings_Dev& print_settings) {
1730   if (!page_range_count)
1731     return pp::Buffer_Dev();
1732
1733   DCHECK(doc_);
1734   FPDF_DOCUMENT output_doc = FPDF_CreateNewDocument();
1735   if (!output_doc)
1736     return pp::Buffer_Dev();
1737
1738   KillFormFocus();
1739
1740   std::string page_number_str;
1741   for (uint32_t index = 0; index < page_range_count; ++index) {
1742     if (!page_number_str.empty())
1743       page_number_str.append(",");
1744     const PP_PrintPageNumberRange_Dev& range = page_ranges[index];
1745     page_number_str.append(base::UintToString(range.first_page_number + 1));
1746     if (range.first_page_number != range.last_page_number) {
1747       page_number_str.append("-");
1748       page_number_str.append(base::UintToString(range.last_page_number + 1));
1749     }
1750   }
1751
1752   std::vector<uint32_t> page_numbers =
1753       GetPageNumbersFromPrintPageNumberRange(page_ranges, page_range_count);
1754   for (uint32_t page_number : page_numbers) {
1755     pages_[page_number]->GetPage();
1756     if (!IsPageVisible(page_number))
1757       pages_[page_number]->Unload();
1758   }
1759
1760   FPDF_CopyViewerPreferences(output_doc, doc_);
1761   if (!FPDF_ImportPages(output_doc, doc_, page_number_str.c_str(), 0)) {
1762     FPDF_CloseDocument(output_doc);
1763     return pp::Buffer_Dev();
1764   }
1765
1766   FitContentsToPrintableAreaIfRequired(output_doc, print_settings);
1767
1768   // Now flatten all the output pages.
1769   pp::Buffer_Dev buffer = GetFlattenedPrintData(output_doc);
1770   FPDF_CloseDocument(output_doc);
1771   return buffer;
1772 }
1773
1774 void PDFiumEngine::FitContentsToPrintableAreaIfRequired(
1775     FPDF_DOCUMENT doc,
1776     const PP_PrintSettings_Dev& print_settings) {
1777   // Check to see if we need to fit pdf contents to printer paper size.
1778   if (print_settings.print_scaling_option !=
1779       PP_PRINTSCALINGOPTION_SOURCE_SIZE) {
1780     int num_pages = FPDF_GetPageCount(doc);
1781     // In-place transformation is more efficient than creating a new
1782     // transformed document from the source document. Therefore, transform
1783     // every page to fit the contents in the selected printer paper.
1784     for (int i = 0; i < num_pages; ++i) {
1785       FPDF_PAGE page = FPDF_LoadPage(doc, i);
1786       TransformPDFPageForPrinting(page, print_settings);
1787       FPDF_ClosePage(page);
1788     }
1789   }
1790 }
1791
1792 void PDFiumEngine::KillFormFocus() {
1793   FORM_ForceToKillFocus(form_);
1794   SetInFormTextArea(false);
1795 }
1796
1797 void PDFiumEngine::SetFormSelectedText(FPDF_FORMHANDLE form_handle,
1798                                        FPDF_PAGE page) {
1799   unsigned long form_sel_text_len =
1800       FORM_GetSelectedText(form_handle, page, nullptr, 0);
1801
1802   // If form selected text is empty and there was no previous form text
1803   // selection, exit early because nothing has changed. When |form_sel_text_len|
1804   // is 2, that represents a wide string with just a NUL-terminator.
1805   if (form_sel_text_len <= 2 && selected_form_text_.empty())
1806     return;
1807
1808   base::string16 selected_form_text16;
1809   PDFiumAPIStringBufferSizeInBytesAdapter<base::string16> string_adapter(
1810       &selected_form_text16, form_sel_text_len, false);
1811   string_adapter.Close(FORM_GetSelectedText(
1812       form_handle, page, string_adapter.GetData(), form_sel_text_len));
1813
1814   // Update previous and current selections, then compare them to check if
1815   // selection has changed. If so, set plugin text selection.
1816   std::string selected_form_text = selected_form_text_;
1817   selected_form_text_ = base::UTF16ToUTF8(selected_form_text16);
1818   if (selected_form_text != selected_form_text_) {
1819     DCHECK(in_form_text_area_);
1820     pp::PDF::SetSelectedText(GetPluginInstance(), selected_form_text_.c_str());
1821   }
1822 }
1823
1824 void PDFiumEngine::PrintEnd() {
1825   FORM_DoDocumentAAction(form_, FPDFDOC_AACTION_DP);
1826 }
1827
1828 PDFiumPage::Area PDFiumEngine::GetCharIndex(const pp::Point& point,
1829                                             int* page_index,
1830                                             int* char_index,
1831                                             int* form_type,
1832                                             PDFiumPage::LinkTarget* target) {
1833   int page = -1;
1834   pp::Point point_in_page(
1835       static_cast<int>((point.x() + position_.x()) / current_zoom_),
1836       static_cast<int>((point.y() + position_.y()) / current_zoom_));
1837   for (int visible_page : visible_pages_) {
1838     if (pages_[visible_page]->rect().Contains(point_in_page)) {
1839       page = visible_page;
1840       break;
1841     }
1842   }
1843   if (page == -1)
1844     return PDFiumPage::NONSELECTABLE_AREA;
1845
1846   // If the page hasn't finished rendering, calling into the page sometimes
1847   // leads to hangs.
1848   for (const auto& paint : progressive_paints_) {
1849     if (paint.page_index == page)
1850       return PDFiumPage::NONSELECTABLE_AREA;
1851   }
1852
1853   *page_index = page;
1854   PDFiumPage::Area result = pages_[page]->GetCharIndex(
1855       point_in_page, current_rotation_, char_index, form_type, target);
1856   return (client_->IsPrintPreview() && result == PDFiumPage::WEBLINK_AREA)
1857              ? PDFiumPage::NONSELECTABLE_AREA
1858              : result;
1859 }
1860
1861 bool PDFiumEngine::OnMouseDown(const pp::MouseInputEvent& event) {
1862   pp::MouseInputEvent normalized_event =
1863       NormalizeMouseEvent(client_->GetPluginInstance(), event);
1864   if (normalized_event.GetButton() == PP_INPUTEVENT_MOUSEBUTTON_LEFT)
1865     return OnLeftMouseDown(normalized_event);
1866   if (normalized_event.GetButton() == PP_INPUTEVENT_MOUSEBUTTON_MIDDLE)
1867     return OnMiddleMouseDown(normalized_event);
1868   if (normalized_event.GetButton() == PP_INPUTEVENT_MOUSEBUTTON_RIGHT)
1869     return OnRightMouseDown(normalized_event);
1870   return false;
1871 }
1872
1873 void PDFiumEngine::OnSingleClick(int page_index, int char_index) {
1874   SetSelecting(true);
1875   selection_.push_back(PDFiumRange(pages_[page_index].get(), char_index, 0));
1876 }
1877
1878 void PDFiumEngine::OnMultipleClick(int click_count,
1879                                    int page_index,
1880                                    int char_index) {
1881   DCHECK_GE(click_count, 2);
1882   bool is_double_click = click_count == 2;
1883
1884   // It would be more efficient if the SDK could support finding a space, but
1885   // now it doesn't.
1886   int start_index = char_index;
1887   do {
1888     base::char16 cur = pages_[page_index]->GetCharAtIndex(start_index);
1889     if (FindMultipleClickBoundary(is_double_click, cur))
1890       break;
1891   } while (--start_index >= 0);
1892   if (start_index)
1893     start_index++;
1894
1895   int end_index = char_index;
1896   int total = pages_[page_index]->GetCharCount();
1897   while (end_index++ <= total) {
1898     base::char16 cur = pages_[page_index]->GetCharAtIndex(end_index);
1899     if (FindMultipleClickBoundary(is_double_click, cur))
1900       break;
1901   }
1902
1903   selection_.push_back(PDFiumRange(pages_[page_index].get(), start_index,
1904                                    end_index - start_index));
1905 }
1906
1907 bool PDFiumEngine::OnLeftMouseDown(const pp::MouseInputEvent& event) {
1908   SetMouseLeftButtonDown(true);
1909
1910   auto selection_invalidator =
1911       std::make_unique<SelectionChangeInvalidator>(this);
1912   selection_.clear();
1913
1914   int page_index = -1;
1915   int char_index = -1;
1916   int form_type = FPDF_FORMFIELD_UNKNOWN;
1917   PDFiumPage::LinkTarget target;
1918   pp::Point point = event.GetPosition();
1919   PDFiumPage::Area area =
1920       GetCharIndex(point, &page_index, &char_index, &form_type, &target);
1921   DCHECK_GE(form_type, FPDF_FORMFIELD_UNKNOWN);
1922   mouse_down_state_.Set(area, target);
1923
1924   // Decide whether to open link or not based on user action in mouse up and
1925   // mouse move events.
1926   if (IsLinkArea(area))
1927     return true;
1928
1929   if (page_index != -1) {
1930     last_page_mouse_down_ = page_index;
1931     double page_x;
1932     double page_y;
1933     DeviceToPage(page_index, point.x(), point.y(), &page_x, &page_y);
1934
1935     bool is_form_text_area = IsFormTextArea(area, form_type);
1936     FPDF_PAGE page = pages_[page_index]->GetPage();
1937     bool is_editable_form_text_area =
1938         is_form_text_area &&
1939         IsPointInEditableFormTextArea(page, page_x, page_y, form_type);
1940
1941     FORM_OnLButtonDown(form_, page, 0, page_x, page_y);
1942     if (form_type != FPDF_FORMFIELD_UNKNOWN) {
1943       // Destroy SelectionChangeInvalidator object before SetInFormTextArea()
1944       // changes plugin's focus to be in form text area. This way, regular text
1945       // selection can be cleared when a user clicks into a form text area
1946       // because the pp::PDF::SetSelectedText() call in
1947       // ~SelectionChangeInvalidator() still goes to the Mimehandler
1948       // (not the Renderer).
1949       selection_invalidator.reset();
1950
1951       SetInFormTextArea(is_form_text_area);
1952       editable_form_text_area_ = is_editable_form_text_area;
1953       return true;  // Return now before we get into the selection code.
1954     }
1955   }
1956   SetInFormTextArea(false);
1957
1958   if (area != PDFiumPage::TEXT_AREA)
1959     return true;  // Return true so WebKit doesn't do its own highlighting.
1960
1961   if (event.GetClickCount() == 1)
1962     OnSingleClick(page_index, char_index);
1963   else if (event.GetClickCount() == 2 || event.GetClickCount() == 3)
1964     OnMultipleClick(event.GetClickCount(), page_index, char_index);
1965
1966   return true;
1967 }
1968
1969 bool PDFiumEngine::OnMiddleMouseDown(const pp::MouseInputEvent& event) {
1970   SetMouseLeftButtonDown(false);
1971   mouse_middle_button_down_ = true;
1972   mouse_middle_button_last_position_ = event.GetPosition();
1973
1974   SelectionChangeInvalidator selection_invalidator(this);
1975   selection_.clear();
1976
1977   int unused_page_index = -1;
1978   int unused_char_index = -1;
1979   int unused_form_type = FPDF_FORMFIELD_UNKNOWN;
1980   PDFiumPage::LinkTarget target;
1981   PDFiumPage::Area area =
1982       GetCharIndex(event.GetPosition(), &unused_page_index, &unused_char_index,
1983                    &unused_form_type, &target);
1984   mouse_down_state_.Set(area, target);
1985
1986   // Decide whether to open link or not based on user action in mouse up and
1987   // mouse move events.
1988   if (IsLinkArea(area))
1989     return true;
1990
1991   if (kViewerImplementedPanning) {
1992     // Switch to hand cursor when panning.
1993     client_->UpdateCursor(PP_CURSORTYPE_HAND);
1994   }
1995
1996   // Prevent middle mouse button from selecting texts.
1997   return false;
1998 }
1999
2000 bool PDFiumEngine::OnRightMouseDown(const pp::MouseInputEvent& event) {
2001   DCHECK_EQ(PP_INPUTEVENT_MOUSEBUTTON_RIGHT, event.GetButton());
2002
2003   pp::Point point = event.GetPosition();
2004   int page_index = -1;
2005   int char_index = -1;
2006   int form_type = FPDF_FORMFIELD_UNKNOWN;
2007   PDFiumPage::LinkTarget target;
2008   PDFiumPage::Area area =
2009       GetCharIndex(point, &page_index, &char_index, &form_type, &target);
2010   DCHECK_GE(form_type, FPDF_FORMFIELD_UNKNOWN);
2011
2012   bool is_form_text_area = IsFormTextArea(area, form_type);
2013   bool is_editable_form_text_area = false;
2014
2015   double page_x = -1;
2016   double page_y = -1;
2017   FPDF_PAGE page = nullptr;
2018   if (is_form_text_area) {
2019     DCHECK_NE(page_index, -1);
2020
2021     DeviceToPage(page_index, point.x(), point.y(), &page_x, &page_y);
2022     page = pages_[page_index]->GetPage();
2023     is_editable_form_text_area =
2024         IsPointInEditableFormTextArea(page, page_x, page_y, form_type);
2025   }
2026
2027   // Handle the case when focus starts inside a form text area.
2028   if (in_form_text_area_) {
2029     if (is_form_text_area) {
2030       FORM_OnFocus(form_, page, 0, page_x, page_y);
2031     } else {
2032       // Transition out of a form text area.
2033       FORM_ForceToKillFocus(form_);
2034       SetInFormTextArea(false);
2035     }
2036     return true;
2037   }
2038
2039   // Handle the case when focus starts outside a form text area and transitions
2040   // into a form text area.
2041   if (is_form_text_area) {
2042     {
2043       SelectionChangeInvalidator selection_invalidator(this);
2044       selection_.clear();
2045     }
2046
2047     SetInFormTextArea(true);
2048     editable_form_text_area_ = is_editable_form_text_area;
2049     FORM_OnFocus(form_, page, 0, page_x, page_y);
2050     return true;
2051   }
2052
2053   // Handle the case when focus starts outside a form text area and stays
2054   // outside.
2055   if (selection_.empty())
2056     return false;
2057
2058   std::vector<pp::Rect> selection_rect_vector;
2059   GetAllScreenRectsUnion(&selection_, GetVisibleRect().point(),
2060                          &selection_rect_vector);
2061   for (const auto& rect : selection_rect_vector) {
2062     if (rect.Contains(point.x(), point.y()))
2063       return false;
2064   }
2065   SelectionChangeInvalidator selection_invalidator(this);
2066   selection_.clear();
2067   return true;
2068 }
2069
2070 bool PDFiumEngine::OnMouseUp(const pp::MouseInputEvent& event) {
2071   if (event.GetButton() != PP_INPUTEVENT_MOUSEBUTTON_LEFT &&
2072       event.GetButton() != PP_INPUTEVENT_MOUSEBUTTON_MIDDLE) {
2073     return false;
2074   }
2075
2076   if (event.GetButton() == PP_INPUTEVENT_MOUSEBUTTON_LEFT)
2077     SetMouseLeftButtonDown(false);
2078   else if (event.GetButton() == PP_INPUTEVENT_MOUSEBUTTON_MIDDLE)
2079     mouse_middle_button_down_ = false;
2080
2081   int page_index = -1;
2082   int char_index = -1;
2083   int form_type = FPDF_FORMFIELD_UNKNOWN;
2084   PDFiumPage::LinkTarget target;
2085   pp::Point point = event.GetPosition();
2086   PDFiumPage::Area area =
2087       GetCharIndex(point, &page_index, &char_index, &form_type, &target);
2088
2089   // Open link on mouse up for same link for which mouse down happened earlier.
2090   if (mouse_down_state_.Matches(area, target)) {
2091     if (area == PDFiumPage::WEBLINK_AREA) {
2092       uint32_t modifiers = event.GetModifiers();
2093       bool middle_button =
2094           !!(modifiers & PP_INPUTEVENT_MODIFIER_MIDDLEBUTTONDOWN);
2095       bool alt_key = !!(modifiers & PP_INPUTEVENT_MODIFIER_ALTKEY);
2096       bool ctrl_key = !!(modifiers & PP_INPUTEVENT_MODIFIER_CONTROLKEY);
2097       bool meta_key = !!(modifiers & PP_INPUTEVENT_MODIFIER_METAKEY);
2098       bool shift_key = !!(modifiers & PP_INPUTEVENT_MODIFIER_SHIFTKEY);
2099
2100       WindowOpenDisposition disposition = ui::DispositionFromClick(
2101           middle_button, alt_key, ctrl_key, meta_key, shift_key);
2102
2103       client_->NavigateTo(target.url, disposition);
2104       SetInFormTextArea(false);
2105       return true;
2106     }
2107     if (area == PDFiumPage::DOCLINK_AREA) {
2108       if (!PageIndexInBounds(target.page))
2109         return true;
2110
2111       pp::Rect page_rect(GetPageScreenRect(target.page));
2112       int y = position_.y() + page_rect.y();
2113       if (target.y_in_pixels)
2114         y += target.y_in_pixels.value() * current_zoom_;
2115       client_->ScrollToY(y, /*compensate_for_toolbar=*/true);
2116       SetInFormTextArea(false);
2117       return true;
2118     }
2119   }
2120
2121   if (event.GetButton() == PP_INPUTEVENT_MOUSEBUTTON_MIDDLE) {
2122     if (kViewerImplementedPanning) {
2123       // Update the cursor when panning stops.
2124       client_->UpdateCursor(DetermineCursorType(area, form_type));
2125     }
2126
2127     // Prevent middle mouse button from selecting texts.
2128     return false;
2129   }
2130
2131   if (page_index != -1) {
2132     double page_x;
2133     double page_y;
2134     DeviceToPage(page_index, point.x(), point.y(), &page_x, &page_y);
2135     FORM_OnLButtonUp(form_, pages_[page_index]->GetPage(), 0, page_x, page_y);
2136   }
2137
2138   if (!selecting_)
2139     return false;
2140
2141   SetSelecting(false);
2142   return true;
2143 }
2144
2145 bool PDFiumEngine::OnMouseMove(const pp::MouseInputEvent& event) {
2146   int page_index = -1;
2147   int char_index = -1;
2148   int form_type = FPDF_FORMFIELD_UNKNOWN;
2149   PDFiumPage::LinkTarget target;
2150   pp::Point point = event.GetPosition();
2151   PDFiumPage::Area area =
2152       GetCharIndex(point, &page_index, &char_index, &form_type, &target);
2153
2154   // Clear |mouse_down_state_| if mouse moves away from where the mouse down
2155   // happened.
2156   if (!mouse_down_state_.Matches(area, target))
2157     mouse_down_state_.Reset();
2158
2159   if (!selecting_) {
2160     client_->UpdateCursor(DetermineCursorType(area, form_type));
2161
2162     if (page_index != -1) {
2163       double page_x;
2164       double page_y;
2165       DeviceToPage(page_index, point.x(), point.y(), &page_x, &page_y);
2166       FORM_OnMouseMove(form_, pages_[page_index]->GetPage(), 0, page_x, page_y);
2167     }
2168
2169     std::string url = GetLinkAtPosition(event.GetPosition());
2170     if (url != link_under_cursor_) {
2171       link_under_cursor_ = url;
2172       pp::PDF::SetLinkUnderCursor(GetPluginInstance(), url.c_str());
2173     }
2174
2175     // If in form text area while left mouse button is held down, check if form
2176     // text selection needs to be updated.
2177     if (mouse_left_button_down_ && area == PDFiumPage::FORM_TEXT_AREA &&
2178         last_page_mouse_down_ != -1) {
2179       SetFormSelectedText(form_, pages_[last_page_mouse_down_]->GetPage());
2180     }
2181
2182     if (kViewerImplementedPanning && mouse_middle_button_down_) {
2183       // Subtract (origin - destination) so delta is already the delta for
2184       // moving the page, rather than the delta the mouse moved.
2185       // GetMovement() does not work here, as small mouse movements are
2186       // considered zero.
2187       pp::Point page_position_delta =
2188           mouse_middle_button_last_position_ - event.GetPosition();
2189       if (page_position_delta.x() != 0 || page_position_delta.y() != 0) {
2190         client_->ScrollBy(page_position_delta);
2191         mouse_middle_button_last_position_ = event.GetPosition();
2192       }
2193     }
2194
2195     // No need to swallow the event, since this might interfere with the
2196     // scrollbars if the user is dragging them.
2197     return false;
2198   }
2199
2200   // We're selecting but right now we're not over text, so don't change the
2201   // current selection.
2202   if (area != PDFiumPage::TEXT_AREA && !IsLinkArea(area))
2203     return false;
2204
2205   SelectionChangeInvalidator selection_invalidator(this);
2206   return ExtendSelection(page_index, char_index);
2207 }
2208
2209 PP_CursorType_Dev PDFiumEngine::DetermineCursorType(PDFiumPage::Area area,
2210                                                     int form_type) const {
2211   if (kViewerImplementedPanning && mouse_middle_button_down_) {
2212     return PP_CURSORTYPE_HAND;
2213   }
2214
2215   switch (area) {
2216     case PDFiumPage::TEXT_AREA:
2217       return PP_CURSORTYPE_IBEAM;
2218     case PDFiumPage::WEBLINK_AREA:
2219     case PDFiumPage::DOCLINK_AREA:
2220       return PP_CURSORTYPE_HAND;
2221     case PDFiumPage::NONSELECTABLE_AREA:
2222     case PDFiumPage::FORM_TEXT_AREA:
2223     default:
2224       switch (form_type) {
2225         case FPDF_FORMFIELD_PUSHBUTTON:
2226         case FPDF_FORMFIELD_CHECKBOX:
2227         case FPDF_FORMFIELD_RADIOBUTTON:
2228         case FPDF_FORMFIELD_COMBOBOX:
2229         case FPDF_FORMFIELD_LISTBOX:
2230           return PP_CURSORTYPE_HAND;
2231         case FPDF_FORMFIELD_TEXTFIELD:
2232           return PP_CURSORTYPE_IBEAM;
2233 #if defined(PDF_ENABLE_XFA)
2234         case FPDF_FORMFIELD_XFA_CHECKBOX:
2235         case FPDF_FORMFIELD_XFA_COMBOBOX:
2236         case FPDF_FORMFIELD_XFA_IMAGEFIELD:
2237         case FPDF_FORMFIELD_XFA_LISTBOX:
2238         case FPDF_FORMFIELD_XFA_PUSHBUTTON:
2239         case FPDF_FORMFIELD_XFA_SIGNATURE:
2240           return PP_CURSORTYPE_HAND;
2241         case FPDF_FORMFIELD_XFA_TEXTFIELD:
2242           return PP_CURSORTYPE_IBEAM;
2243 #endif
2244         default:
2245           return PP_CURSORTYPE_POINTER;
2246       }
2247   }
2248 }
2249
2250 void PDFiumEngine::OnMouseEnter(const pp::MouseInputEvent& event) {
2251   if (event.GetModifiers() & PP_INPUTEVENT_MODIFIER_MIDDLEBUTTONDOWN) {
2252     if (!mouse_middle_button_down_) {
2253       mouse_middle_button_down_ = true;
2254       mouse_middle_button_last_position_ = event.GetPosition();
2255     }
2256   } else {
2257     if (mouse_middle_button_down_) {
2258       mouse_middle_button_down_ = false;
2259     }
2260   }
2261 }
2262
2263 bool PDFiumEngine::ExtendSelection(int page_index, int char_index) {
2264   // Check if the user has decreased their selection area and we need to remove
2265   // pages from |selection_|.
2266   for (size_t i = 0; i < selection_.size(); ++i) {
2267     if (selection_[i].page_index() == page_index) {
2268       // There should be no other pages after this.
2269       selection_.erase(selection_.begin() + i + 1, selection_.end());
2270       break;
2271     }
2272   }
2273   if (selection_.empty())
2274     return false;
2275
2276   PDFiumRange& last_selection = selection_.back();
2277   const int last_page_index = last_selection.page_index();
2278   const int last_char_index = last_selection.char_index();
2279   if (last_page_index == page_index) {
2280     // Selecting within a page.
2281     int count = char_index - last_char_index;
2282     if (count >= 0) {
2283       // Selecting forward.
2284       ++count;
2285     } else {
2286       --count;
2287     }
2288     last_selection.SetCharCount(count);
2289   } else if (last_page_index < page_index) {
2290     // Selecting into the next page.
2291
2292     // First make sure that there are no gaps in selection, i.e. if mousedown on
2293     // page one but we only get mousemove over page three, we want page two.
2294     for (int i = last_page_index + 1; i < page_index; ++i) {
2295       selection_.push_back(
2296           PDFiumRange(pages_[i].get(), 0, pages_[i]->GetCharCount()));
2297     }
2298
2299     int count = pages_[last_page_index]->GetCharCount();
2300     last_selection.SetCharCount(count - last_char_index);
2301     selection_.push_back(PDFiumRange(pages_[page_index].get(), 0, char_index));
2302   } else {
2303     // Selecting into the previous page.
2304     // The selection's char_index is 0-based, so the character count is one
2305     // more than the index. The character count needs to be negative to
2306     // indicate a backwards selection.
2307     last_selection.SetCharCount(-last_char_index - 1);
2308
2309     // First make sure that there are no gaps in selection, i.e. if mousedown on
2310     // page three but we only get mousemove over page one, we want page two.
2311     for (int i = last_page_index - 1; i > page_index; --i) {
2312       selection_.push_back(
2313           PDFiumRange(pages_[i].get(), 0, pages_[i]->GetCharCount()));
2314     }
2315
2316     int count = pages_[page_index]->GetCharCount();
2317     selection_.push_back(
2318         PDFiumRange(pages_[page_index].get(), count, count - char_index));
2319   }
2320
2321   return true;
2322 }
2323
2324 bool PDFiumEngine::OnKeyDown(const pp::KeyboardInputEvent& event) {
2325   if (last_page_mouse_down_ == -1)
2326     return false;
2327
2328   bool rv = !!FORM_OnKeyDown(form_, pages_[last_page_mouse_down_]->GetPage(),
2329                              event.GetKeyCode(), event.GetModifiers());
2330
2331   if (event.GetKeyCode() == ui::VKEY_BACK ||
2332       event.GetKeyCode() == ui::VKEY_ESCAPE) {
2333     // Blink does not send char events for backspace or escape keys, see
2334     // WebKeyboardEvent::IsCharacterKey() and b/961192 for more information.
2335     // So just fake one since PDFium uses it.
2336     std::string str;
2337     str.push_back(event.GetKeyCode());
2338     pp::KeyboardInputEvent synthesized(pp::KeyboardInputEvent(
2339         client_->GetPluginInstance(), PP_INPUTEVENT_TYPE_CHAR,
2340         event.GetTimeStamp(), event.GetModifiers(), event.GetKeyCode(), str));
2341     OnChar(synthesized);
2342   }
2343
2344   return rv;
2345 }
2346
2347 bool PDFiumEngine::OnKeyUp(const pp::KeyboardInputEvent& event) {
2348   if (last_page_mouse_down_ == -1)
2349     return false;
2350
2351   // Check if form text selection needs to be updated.
2352   FPDF_PAGE page = pages_[last_page_mouse_down_]->GetPage();
2353   if (in_form_text_area_)
2354     SetFormSelectedText(form_, page);
2355
2356   return !!FORM_OnKeyUp(form_, page, event.GetKeyCode(), event.GetModifiers());
2357 }
2358
2359 bool PDFiumEngine::OnChar(const pp::KeyboardInputEvent& event) {
2360   if (last_page_mouse_down_ == -1)
2361     return false;
2362
2363   base::string16 str = base::UTF8ToUTF16(event.GetCharacterText().AsString());
2364   return !!FORM_OnChar(form_, pages_[last_page_mouse_down_]->GetPage(), str[0],
2365                        event.GetModifiers());
2366 }
2367
2368 void PDFiumEngine::StartFind(const std::string& text, bool case_sensitive) {
2369   // If the caller asks StartFind() to search for no text, then this is an
2370   // error on the part of the caller. The PPAPI Find_Private interface
2371   // guarantees it is not empty, so this should never happen.
2372   DCHECK(!text.empty());
2373
2374   // If StartFind() gets called before we have any page information (i.e.
2375   // before the first call to LoadDocument has happened). Handle this case.
2376   if (pages_.empty())
2377     return;
2378
2379   bool first_search = (current_find_text_ != text);
2380   int character_to_start_searching_from = 0;
2381   if (first_search) {
2382     std::vector<PDFiumRange> old_selection = selection_;
2383     StopFind();
2384     current_find_text_ = text;
2385
2386     if (old_selection.empty()) {
2387       // Start searching from the beginning of the document.
2388       next_page_to_search_ = 0;
2389       last_page_to_search_ = pages_.size() - 1;
2390       last_character_index_to_search_ = -1;
2391     } else {
2392       // There's a current selection, so start from it.
2393       next_page_to_search_ = old_selection[0].page_index();
2394       last_character_index_to_search_ = old_selection[0].char_index();
2395       character_to_start_searching_from = old_selection[0].char_index();
2396       last_page_to_search_ = next_page_to_search_;
2397     }
2398   }
2399
2400   int current_page = next_page_to_search_;
2401
2402   if (pages_[current_page]->available()) {
2403     base::string16 str = base::UTF8ToUTF16(text);
2404     // Don't use PDFium to search for now, since it doesn't support unicode
2405     // text. Leave the code for now to avoid bit-rot, in case it's fixed later.
2406     if (0) {
2407       SearchUsingPDFium(str, case_sensitive, first_search,
2408                         character_to_start_searching_from, current_page);
2409     } else {
2410       SearchUsingICU(str, case_sensitive, first_search,
2411                      character_to_start_searching_from, current_page);
2412     }
2413
2414     if (!IsPageVisible(current_page))
2415       pages_[current_page]->Unload();
2416   }
2417
2418   if (next_page_to_search_ != last_page_to_search_ ||
2419       (first_search && last_character_index_to_search_ != -1)) {
2420     ++next_page_to_search_;
2421   }
2422
2423   if (next_page_to_search_ == static_cast<int>(pages_.size()))
2424     next_page_to_search_ = 0;
2425   // If there's only one page in the document and we start searching midway,
2426   // then we'll want to search the page one more time.
2427   bool end_of_search =
2428       next_page_to_search_ == last_page_to_search_ &&
2429       // Only one page but didn't start midway.
2430       ((pages_.size() == 1 && last_character_index_to_search_ == -1) ||
2431        // Started midway, but only 1 page and we already looped around.
2432        (pages_.size() == 1 && !first_search) ||
2433        // Started midway, and we've just looped around.
2434        (pages_.size() > 1 && current_page == next_page_to_search_));
2435
2436   if (end_of_search) {
2437     // Send the final notification.
2438     client_->NotifyNumberOfFindResultsChanged(find_results_.size(), true);
2439   } else {
2440     pp::CompletionCallback callback =
2441         find_factory_.NewCallback(&PDFiumEngine::ContinueFind);
2442     pp::Module::Get()->core()->CallOnMainThread(0, callback,
2443                                                 case_sensitive ? 1 : 0);
2444   }
2445 }
2446
2447 void PDFiumEngine::SearchUsingPDFium(const base::string16& term,
2448                                      bool case_sensitive,
2449                                      bool first_search,
2450                                      int character_to_start_searching_from,
2451                                      int current_page) {
2452   // Find all the matches in the current page.
2453   unsigned long flags = case_sensitive ? FPDF_MATCHCASE : 0;
2454   FPDF_SCHHANDLE find =
2455       FPDFText_FindStart(pages_[current_page]->GetTextPage(),
2456                          reinterpret_cast<const unsigned short*>(term.c_str()),
2457                          flags, character_to_start_searching_from);
2458
2459   // Note: since we search one page at a time, we don't find matches across
2460   // page boundaries.  We could do this manually ourself, but it seems low
2461   // priority since Reader itself doesn't do it.
2462   while (FPDFText_FindNext(find)) {
2463     PDFiumRange result(pages_[current_page].get(),
2464                        FPDFText_GetSchResultIndex(find),
2465                        FPDFText_GetSchCount(find));
2466
2467     if (!first_search && last_character_index_to_search_ != -1 &&
2468         result.page_index() == last_page_to_search_ &&
2469         result.char_index() >= last_character_index_to_search_) {
2470       break;
2471     }
2472
2473     AddFindResult(result);
2474   }
2475
2476   FPDFText_FindClose(find);
2477 }
2478
2479 void PDFiumEngine::SearchUsingICU(const base::string16& term,
2480                                   bool case_sensitive,
2481                                   bool first_search,
2482                                   int character_to_start_searching_from,
2483                                   int current_page) {
2484   DCHECK(!term.empty());
2485
2486   const int original_text_length = pages_[current_page]->GetCharCount();
2487   int text_length = original_text_length;
2488   if (character_to_start_searching_from) {
2489     text_length -= character_to_start_searching_from;
2490   } else if (!first_search && last_character_index_to_search_ != -1 &&
2491              current_page == last_page_to_search_) {
2492     text_length = last_character_index_to_search_;
2493   }
2494   if (text_length <= 0)
2495     return;
2496
2497   base::string16 page_text;
2498   PDFiumAPIStringBufferAdapter<base::string16> api_string_adapter(
2499       &page_text, text_length, false);
2500   unsigned short* data =
2501       reinterpret_cast<unsigned short*>(api_string_adapter.GetData());
2502   int written =
2503       FPDFText_GetText(pages_[current_page]->GetTextPage(),
2504                        character_to_start_searching_from, text_length, data);
2505   api_string_adapter.Close(written);
2506
2507   std::vector<PDFEngine::Client::SearchStringResult> results =
2508       client_->SearchString(page_text.c_str(), term.c_str(), case_sensitive);
2509   for (const auto& result : results) {
2510     // Need to map the indexes from the page text, which may have generated
2511     // characters like space etc, to character indices from the page.
2512     int text_to_start_searching_from = FPDFText_GetTextIndexFromCharIndex(
2513         pages_[current_page]->GetTextPage(), character_to_start_searching_from);
2514     int temp_start = result.start_index + text_to_start_searching_from;
2515     int start = FPDFText_GetCharIndexFromTextIndex(
2516         pages_[current_page]->GetTextPage(), temp_start);
2517     int end = FPDFText_GetCharIndexFromTextIndex(
2518         pages_[current_page]->GetTextPage(), temp_start + result.length);
2519
2520     // If |term| occurs at the end of a page, then |end| will be -1 due to the
2521     // index being out of bounds. Compensate for this case so the range
2522     // character count calculation below works out.
2523     if (temp_start + result.length == original_text_length) {
2524       DCHECK_EQ(-1, end);
2525       end = original_text_length;
2526     }
2527     DCHECK_LT(start, end);
2528     DCHECK_EQ(term.size(), static_cast<size_t>(end - start));
2529     AddFindResult(PDFiumRange(pages_[current_page].get(), start, end - start));
2530   }
2531 }
2532
2533 void PDFiumEngine::AddFindResult(const PDFiumRange& result) {
2534   // Figure out where to insert the new location, since we could have
2535   // started searching midway and now we wrapped.
2536   size_t result_index;
2537   int page_index = result.page_index();
2538   int char_index = result.char_index();
2539   for (result_index = 0; result_index < find_results_.size(); ++result_index) {
2540     if (find_results_[result_index].page_index() > page_index ||
2541         (find_results_[result_index].page_index() == page_index &&
2542          find_results_[result_index].char_index() > char_index)) {
2543       break;
2544     }
2545   }
2546   find_results_.insert(find_results_.begin() + result_index, result);
2547   UpdateTickMarks();
2548   client_->NotifyNumberOfFindResultsChanged(find_results_.size(), false);
2549 }
2550
2551 bool PDFiumEngine::SelectFindResult(bool forward) {
2552   if (find_results_.empty()) {
2553     NOTREACHED();
2554     return false;
2555   }
2556
2557   SelectionChangeInvalidator selection_invalidator(this);
2558
2559   // Move back/forward through the search locations we previously found.
2560   size_t new_index;
2561   const size_t last_index = find_results_.size() - 1;
2562
2563   if (resume_find_index_) {
2564     new_index = resume_find_index_.value();
2565     resume_find_index_.reset();
2566   } else if (current_find_index_) {
2567     size_t current_index = current_find_index_.value();
2568     if ((forward && current_index >= last_index) ||
2569         (!forward && current_index == 0)) {
2570       current_find_index_.reset();
2571       client_->NotifySelectedFindResultChanged(-1);
2572       client_->NotifyNumberOfFindResultsChanged(find_results_.size(), true);
2573       return true;
2574     }
2575     int increment = forward ? 1 : -1;
2576     new_index = current_index + increment;
2577   } else {
2578     new_index = forward ? 0 : last_index;
2579   }
2580   current_find_index_ = new_index;
2581
2582   // Update the selection before telling the client to scroll, since it could
2583   // paint then.
2584   selection_.clear();
2585   selection_.push_back(find_results_[current_find_index_.value()]);
2586
2587   // If the result is not in view, scroll to it.
2588   pp::Rect bounding_rect;
2589   pp::Rect visible_rect = GetVisibleRect();
2590   // Use zoom of 1.0 since |visible_rect| is without zoom.
2591   const std::vector<pp::Rect>& rects =
2592       find_results_[current_find_index_.value()].GetScreenRects(
2593           pp::Point(), 1.0, current_rotation_);
2594   for (const auto& rect : rects)
2595     bounding_rect = bounding_rect.Union(rect);
2596   if (!visible_rect.Contains(bounding_rect)) {
2597     pp::Point center = bounding_rect.CenterPoint();
2598     // Make the page centered.
2599     int new_y = CalculateCenterForZoom(center.y(), visible_rect.height(),
2600                                        current_zoom_);
2601     client_->ScrollToY(new_y, /*compensate_for_toolbar=*/false);
2602
2603     // Only move horizontally if it's not visible.
2604     if (center.x() < visible_rect.x() || center.x() > visible_rect.right()) {
2605       int new_x = CalculateCenterForZoom(center.x(), visible_rect.width(),
2606                                          current_zoom_);
2607       client_->ScrollToX(new_x);
2608     }
2609   }
2610
2611   client_->NotifySelectedFindResultChanged(current_find_index_.value());
2612   client_->NotifyNumberOfFindResultsChanged(find_results_.size(), true);
2613   return true;
2614 }
2615
2616 void PDFiumEngine::StopFind() {
2617   SelectionChangeInvalidator selection_invalidator(this);
2618   selection_.clear();
2619   selecting_ = false;
2620
2621   find_results_.clear();
2622   next_page_to_search_ = -1;
2623   last_page_to_search_ = -1;
2624   last_character_index_to_search_ = -1;
2625   current_find_index_.reset();
2626   current_find_text_.clear();
2627
2628   UpdateTickMarks();
2629   find_factory_.CancelAll();
2630 }
2631
2632 void PDFiumEngine::GetAllScreenRectsUnion(std::vector<PDFiumRange>* rect_range,
2633                                           const pp::Point& offset_point,
2634                                           std::vector<pp::Rect>* rect_vector) {
2635   for (auto& range : *rect_range) {
2636     pp::Rect result_rect;
2637     const std::vector<pp::Rect>& rects =
2638         range.GetScreenRects(offset_point, current_zoom_, current_rotation_);
2639     for (const auto& rect : rects)
2640       result_rect = result_rect.Union(rect);
2641     rect_vector->push_back(result_rect);
2642   }
2643 }
2644
2645 void PDFiumEngine::UpdateTickMarks() {
2646   std::vector<pp::Rect> tickmarks;
2647   GetAllScreenRectsUnion(&find_results_, pp::Point(0, 0), &tickmarks);
2648   client_->UpdateTickMarks(tickmarks);
2649 }
2650
2651 void PDFiumEngine::ZoomUpdated(double new_zoom_level) {
2652   CancelPaints();
2653
2654   current_zoom_ = new_zoom_level;
2655
2656   CalculateVisiblePages();
2657   UpdateTickMarks();
2658 }
2659
2660 void PDFiumEngine::RotateClockwise() {
2661   current_rotation_ = (current_rotation_ + 1) % 4;
2662   RotateInternal();
2663 }
2664
2665 void PDFiumEngine::RotateCounterclockwise() {
2666   current_rotation_ = (current_rotation_ - 1) % 4;
2667   RotateInternal();
2668 }
2669
2670 void PDFiumEngine::InvalidateAllPages() {
2671   CancelPaints();
2672   StopFind();
2673   LoadPageInfo(true);
2674   client_->Invalidate(pp::Rect(plugin_size_));
2675 }
2676
2677 std::string PDFiumEngine::GetSelectedText() {
2678   if (!HasPermission(PDFEngine::PERMISSION_COPY))
2679     return std::string();
2680
2681   base::string16 result;
2682   for (size_t i = 0; i < selection_.size(); ++i) {
2683     static constexpr base::char16 kNewLineChar = L'\n';
2684     base::string16 current_selection_text = selection_[i].GetText();
2685     if (i != 0) {
2686       if (selection_[i - 1].page_index() > selection_[i].page_index())
2687         std::swap(current_selection_text, result);
2688       result.push_back(kNewLineChar);
2689     }
2690     result.append(current_selection_text);
2691   }
2692
2693   FormatStringWithHyphens(&result);
2694   FormatStringForOS(&result);
2695   return base::UTF16ToUTF8(result);
2696 }
2697
2698 bool PDFiumEngine::CanEditText() {
2699   return editable_form_text_area_;
2700 }
2701
2702 void PDFiumEngine::ReplaceSelection(const std::string& text) {
2703   DCHECK(CanEditText());
2704   if (last_page_mouse_down_ != -1) {
2705     base::string16 text_wide = base::UTF8ToUTF16(text);
2706     FPDF_WIDESTRING text_pdf_wide =
2707         reinterpret_cast<FPDF_WIDESTRING>(text_wide.c_str());
2708
2709     FORM_ReplaceSelection(form_, pages_[last_page_mouse_down_]->GetPage(),
2710                           text_pdf_wide);
2711   }
2712 }
2713
2714 std::string PDFiumEngine::GetLinkAtPosition(const pp::Point& point) {
2715   std::string url;
2716   int temp;
2717   int page_index = -1;
2718   int form_type = FPDF_FORMFIELD_UNKNOWN;
2719   PDFiumPage::LinkTarget target;
2720   PDFiumPage::Area area =
2721       GetCharIndex(point, &page_index, &temp, &form_type, &target);
2722   if (area == PDFiumPage::WEBLINK_AREA)
2723     url = target.url;
2724   return url;
2725 }
2726
2727 bool PDFiumEngine::HasPermission(DocumentPermission permission) const {
2728   // PDF 1.7 spec, section 3.5.2 says: "If the revision number is 2 or greater,
2729   // the operations to which user access can be controlled are as follows: ..."
2730   //
2731   // Thus for revision numbers less than 2, permissions are ignored and this
2732   // always returns true.
2733   if (permissions_handler_revision_ < 2)
2734     return true;
2735
2736   // Handle high quality printing permission separately for security handler
2737   // revision 3+. See table 3.20 in the PDF 1.7 spec.
2738   if (permission == PERMISSION_PRINT_HIGH_QUALITY &&
2739       permissions_handler_revision_ >= 3) {
2740     return (permissions_ & kPDFPermissionPrintLowQualityMask) != 0 &&
2741            (permissions_ & kPDFPermissionPrintHighQualityMask) != 0;
2742   }
2743
2744   switch (permission) {
2745     case PERMISSION_COPY:
2746       return (permissions_ & kPDFPermissionCopyMask) != 0;
2747     case PERMISSION_COPY_ACCESSIBLE:
2748       return (permissions_ & kPDFPermissionCopyAccessibleMask) != 0;
2749     case PERMISSION_PRINT_LOW_QUALITY:
2750     case PERMISSION_PRINT_HIGH_QUALITY:
2751       // With security handler revision 2 rules, check the same bit for high
2752       // and low quality. See table 3.20 in the PDF 1.7 spec.
2753       return (permissions_ & kPDFPermissionPrintLowQualityMask) != 0;
2754     default:
2755       return true;
2756   }
2757 }
2758
2759 void PDFiumEngine::SelectAll() {
2760   if (in_form_text_area_)
2761     return;
2762
2763   SelectionChangeInvalidator selection_invalidator(this);
2764
2765   selection_.clear();
2766   for (const auto& page : pages_) {
2767     if (page->available())
2768       selection_.push_back(PDFiumRange(page.get(), 0, page->GetCharCount()));
2769   }
2770 }
2771
2772 int PDFiumEngine::GetNumberOfPages() {
2773   return pages_.size();
2774 }
2775
2776 pp::VarArray PDFiumEngine::GetBookmarks() {
2777   pp::VarDictionary dict = TraverseBookmarks(nullptr, 0);
2778   // The root bookmark contains no useful information.
2779   return pp::VarArray(dict.Get(pp::Var("children")));
2780 }
2781
2782 pp::VarDictionary PDFiumEngine::TraverseBookmarks(FPDF_BOOKMARK bookmark,
2783                                                   unsigned int depth) {
2784   pp::VarDictionary dict;
2785   base::string16 title;
2786   unsigned long buffer_size = FPDFBookmark_GetTitle(bookmark, nullptr, 0);
2787   if (buffer_size > 0) {
2788     PDFiumAPIStringBufferSizeInBytesAdapter<base::string16> api_string_adapter(
2789         &title, buffer_size, true);
2790     api_string_adapter.Close(FPDFBookmark_GetTitle(
2791         bookmark, api_string_adapter.GetData(), buffer_size));
2792   }
2793   dict.Set(pp::Var("title"), pp::Var(base::UTF16ToUTF8(title)));
2794
2795   FPDF_DEST dest = FPDFBookmark_GetDest(doc_, bookmark);
2796   // Some bookmarks don't have a page to select.
2797   if (dest) {
2798     int page_index = FPDFDest_GetDestPageIndex(doc_, dest);
2799     if (PageIndexInBounds(page_index)) {
2800       dict.Set(pp::Var("page"), pp::Var(page_index));
2801
2802       base::Optional<gfx::PointF> xy =
2803           pages_[page_index]->GetPageXYTarget(dest);
2804       if (xy)
2805         dict.Set(pp::Var("y"), pp::Var(static_cast<int>(xy.value().y())));
2806     }
2807   } else {
2808     // Extract URI for bookmarks linking to an external page.
2809     FPDF_ACTION action = FPDFBookmark_GetAction(bookmark);
2810     buffer_size = FPDFAction_GetURIPath(doc_, action, nullptr, 0);
2811     if (buffer_size > 0) {
2812       std::string uri;
2813       PDFiumAPIStringBufferAdapter<std::string> api_string_adapter(
2814           &uri, buffer_size, true);
2815       api_string_adapter.Close(FPDFAction_GetURIPath(
2816           doc_, action, api_string_adapter.GetData(), buffer_size));
2817       dict.Set(pp::Var("uri"), pp::Var(uri));
2818     }
2819   }
2820
2821   pp::VarArray children;
2822
2823   // Don't trust PDFium to handle circular bookmarks.
2824   const unsigned int kMaxDepth = 128;
2825   if (depth < kMaxDepth) {
2826     int child_index = 0;
2827     std::set<FPDF_BOOKMARK> seen_bookmarks;
2828     for (FPDF_BOOKMARK child_bookmark =
2829              FPDFBookmark_GetFirstChild(doc_, bookmark);
2830          child_bookmark;
2831          child_bookmark = FPDFBookmark_GetNextSibling(doc_, child_bookmark)) {
2832       if (base::ContainsKey(seen_bookmarks, child_bookmark))
2833         break;
2834
2835       seen_bookmarks.insert(child_bookmark);
2836       children.Set(child_index, TraverseBookmarks(child_bookmark, depth + 1));
2837       child_index++;
2838     }
2839   }
2840   dict.Set(pp::Var("children"), children);
2841   return dict;
2842 }
2843
2844 base::Optional<PDFEngine::NamedDestination> PDFiumEngine::GetNamedDestination(
2845     const std::string& destination) {
2846   // Look for the destination.
2847   FPDF_DEST dest = FPDF_GetNamedDestByName(doc_, destination.c_str());
2848   if (!dest) {
2849     // Look for a bookmark with the same name.
2850     base::string16 destination_wide = base::UTF8ToUTF16(destination);
2851     FPDF_WIDESTRING destination_pdf_wide =
2852         reinterpret_cast<FPDF_WIDESTRING>(destination_wide.c_str());
2853     FPDF_BOOKMARK bookmark = FPDFBookmark_Find(doc_, destination_pdf_wide);
2854     if (bookmark)
2855       dest = FPDFBookmark_GetDest(doc_, bookmark);
2856   }
2857
2858   if (!dest)
2859     return {};
2860
2861   int page = FPDFDest_GetDestPageIndex(doc_, dest);
2862   if (page < 0)
2863     return {};
2864
2865   PDFEngine::NamedDestination result;
2866   result.page = page;
2867   unsigned long view_int =
2868       FPDFDest_GetView(dest, &result.num_params, result.params);
2869   result.view = ConvertViewIntToViewString(view_int);
2870   return result;
2871 }
2872
2873 gfx::PointF PDFiumEngine::TransformPagePoint(int page_index,
2874                                              const gfx::PointF& page_xy) {
2875   DCHECK(PageIndexInBounds(page_index));
2876   return pages_[page_index]->TransformPageToScreenXY(page_xy);
2877 }
2878
2879 int PDFiumEngine::GetMostVisiblePage() {
2880   if (in_flight_visible_page_)
2881     return *in_flight_visible_page_;
2882
2883   // We can call GetMostVisiblePage through a callback from PDFium. We have
2884   // to defer the page deletion otherwise we could potentially delete the page
2885   // that originated the calling JS request and destroy the objects that are
2886   // currently being used.
2887   base::AutoReset<bool> defer_page_unload_guard(&defer_page_unload_, true);
2888   CalculateVisiblePages();
2889   return most_visible_page_;
2890 }
2891
2892 pp::Rect PDFiumEngine::GetPageRect(int index) {
2893   pp::Rect rc(pages_[index]->rect());
2894   rc.Inset(-kPageShadowLeft, -kPageShadowTop, -kPageShadowRight,
2895            -kPageShadowBottom);
2896   return rc;
2897 }
2898
2899 pp::Rect PDFiumEngine::GetPageBoundsRect(int index) {
2900   return pages_[index]->rect();
2901 }
2902
2903 pp::Rect PDFiumEngine::GetPageContentsRect(int index) {
2904   return GetScreenRect(pages_[index]->rect());
2905 }
2906
2907 int PDFiumEngine::GetVerticalScrollbarYPosition() {
2908   return position_.y();
2909 }
2910
2911 void PDFiumEngine::SetGrayscale(bool grayscale) {
2912   render_grayscale_ = grayscale;
2913 }
2914
2915 void PDFiumEngine::OnCallback(int id) {
2916   auto it = formfill_timers_.find(id);
2917   if (it == formfill_timers_.end())
2918     return;
2919
2920   it->second.timer_callback(id);
2921   it = formfill_timers_.find(id);  // The callback might delete the timer.
2922   if (it != formfill_timers_.end())
2923     client_->ScheduleCallback(id, it->second.timer_period);
2924 }
2925
2926 void PDFiumEngine::OnTouchTimerCallback(int id) {
2927   if (!touch_timers_.count(id))
2928     return;
2929
2930   HandleLongPress(touch_timers_[id]);
2931   KillTouchTimer(id);
2932 }
2933
2934 void PDFiumEngine::HandleLongPress(const pp::TouchInputEvent& event) {
2935   pp::FloatPoint fp =
2936       event.GetTouchByIndex(PP_TOUCHLIST_TYPE_TARGETTOUCHES, 0).position();
2937   pp::Point point;
2938   point.set_x(fp.x());
2939   point.set_y(fp.y());
2940
2941   // Send a fake mouse down to trigger the multi-click selection code.
2942   pp::MouseInputEvent mouse_event(
2943       client_->GetPluginInstance(), PP_INPUTEVENT_TYPE_MOUSEDOWN,
2944       event.GetTimeStamp(), event.GetModifiers(),
2945       PP_INPUTEVENT_MOUSEBUTTON_LEFT, point, 2, point);
2946
2947   OnMouseDown(mouse_event);
2948 }
2949
2950 int PDFiumEngine::GetCharCount(int page_index) {
2951   DCHECK(PageIndexInBounds(page_index));
2952   return pages_[page_index]->GetCharCount();
2953 }
2954
2955 pp::FloatRect PDFiumEngine::GetCharBounds(int page_index, int char_index) {
2956   DCHECK(PageIndexInBounds(page_index));
2957   return pages_[page_index]->GetCharBounds(char_index);
2958 }
2959
2960 uint32_t PDFiumEngine::GetCharUnicode(int page_index, int char_index) {
2961   DCHECK(PageIndexInBounds(page_index));
2962   return pages_[page_index]->GetCharUnicode(char_index);
2963 }
2964
2965 void PDFiumEngine::GetTextRunInfo(int page_index,
2966                                   int start_char_index,
2967                                   uint32_t* out_len,
2968                                   double* out_font_size,
2969                                   pp::FloatRect* out_bounds) {
2970   DCHECK(PageIndexInBounds(page_index));
2971   return pages_[page_index]->GetTextRunInfo(start_char_index, out_len,
2972                                             out_font_size, out_bounds);
2973 }
2974
2975 bool PDFiumEngine::GetPrintScaling() {
2976   return !!FPDF_VIEWERREF_GetPrintScaling(doc_);
2977 }
2978
2979 int PDFiumEngine::GetCopiesToPrint() {
2980   return FPDF_VIEWERREF_GetNumCopies(doc_);
2981 }
2982
2983 int PDFiumEngine::GetDuplexType() {
2984   return static_cast<int>(FPDF_VIEWERREF_GetDuplex(doc_));
2985 }
2986
2987 bool PDFiumEngine::GetPageSizeAndUniformity(pp::Size* size) {
2988   if (pages_.empty())
2989     return false;
2990
2991   pp::Size page_size = GetPageSize(0);
2992   for (size_t i = 1; i < pages_.size(); ++i) {
2993     if (page_size != GetPageSize(i))
2994       return false;
2995   }
2996
2997   // Convert |page_size| back to points.
2998   size->set_width(
2999       ConvertUnit(page_size.width(), kPixelsPerInch, kPointsPerInch));
3000   size->set_height(
3001       ConvertUnit(page_size.height(), kPixelsPerInch, kPointsPerInch));
3002   return true;
3003 }
3004
3005 void PDFiumEngine::AppendBlankPages(int num_pages) {
3006   DCHECK_NE(num_pages, 0);
3007
3008   if (!doc_)
3009     return;
3010
3011   selection_.clear();
3012   pending_pages_.clear();
3013
3014   // Delete all pages except the first one.
3015   while (pages_.size() > 1) {
3016     pages_.pop_back();
3017     FPDFPage_Delete(doc_, pages_.size());
3018   }
3019
3020   // Calculate document size and all page sizes.
3021   std::vector<pp::Rect> page_rects;
3022   pp::Size page_size = GetPageSize(0);
3023   page_size.Enlarge(kPageShadowLeft + kPageShadowRight,
3024                     kPageShadowTop + kPageShadowBottom);
3025   pp::Size old_document_size = document_size_;
3026   document_size_ = pp::Size(page_size.width(), 0);
3027   for (int i = 0; i < num_pages; ++i) {
3028     if (i != 0) {
3029       // Add space for horizontal separator.
3030       document_size_.Enlarge(0, kPageSeparatorThickness);
3031     }
3032
3033     pp::Rect rect(pp::Point(0, document_size_.height()), page_size);
3034     page_rects.push_back(rect);
3035
3036     document_size_.Enlarge(0, page_size.height());
3037   }
3038
3039   // Create blank pages.
3040   for (int i = 1; i < num_pages; ++i) {
3041     pp::Rect page_rect(page_rects[i]);
3042     page_rect.Inset(kPageShadowLeft, kPageShadowTop, kPageShadowRight,
3043                     kPageShadowBottom);
3044     double width_in_points =
3045         ConvertUnitDouble(page_rect.width(), kPixelsPerInch, kPointsPerInch);
3046     double height_in_points =
3047         ConvertUnitDouble(page_rect.height(), kPixelsPerInch, kPointsPerInch);
3048     // Add a new page to the document, but delete the FPDF_PAGE object.
3049     FPDF_PAGE temp_page =
3050         FPDFPage_New(doc_, i, width_in_points, height_in_points);
3051     FPDF_ClosePage(temp_page);
3052     pages_.push_back(std::make_unique<PDFiumPage>(this, i, page_rect, true));
3053   }
3054
3055   CalculateVisiblePages();
3056   if (document_size_ != old_document_size)
3057     client_->DocumentSizeUpdated(document_size_);
3058 }
3059
3060 void PDFiumEngine::LoadDocument() {
3061   // Check if the document is ready for loading. If it isn't just bail for now,
3062   // we will call LoadDocument() again later.
3063   if (!doc_ && !doc_loader_->IsDocumentComplete() &&
3064       !FPDFAvail_IsDocAvail(fpdf_availability_, &download_hints_)) {
3065     return;
3066   }
3067
3068   // If we're in the middle of getting a password, just return. We will retry
3069   // loading the document after we get the password anyway.
3070   if (getting_password_)
3071     return;
3072
3073   ScopedUnsupportedFeature scoped_unsupported_feature(this);
3074   ScopedSubstFont scoped_subst_font(this);
3075   bool needs_password = false;
3076   if (TryLoadingDoc(std::string(), &needs_password)) {
3077     ContinueLoadingDocument(std::string());
3078     return;
3079   }
3080   if (needs_password)
3081     GetPasswordAndLoad();
3082   else
3083     client_->DocumentLoadFailed();
3084 }
3085
3086 bool PDFiumEngine::TryLoadingDoc(const std::string& password,
3087                                  bool* needs_password) {
3088   *needs_password = false;
3089   if (doc_) {
3090     // This is probably not necessary, because it should have already been
3091     // called below in the |doc_| initialization path. However, the previous
3092     // call may have failed, so call it again for good measure.
3093     FPDFAvail_IsDocAvail(fpdf_availability_, &download_hints_);
3094     return true;
3095   }
3096
3097   const char* password_cstr = nullptr;
3098   if (!password.empty()) {
3099     password_cstr = password.c_str();
3100     password_tries_remaining_--;
3101   }
3102   if (doc_loader_->IsDocumentComplete() &&
3103       !FPDFAvail_IsLinearized(fpdf_availability_)) {
3104     doc_ = FPDF_LoadCustomDocument(&file_access_, password_cstr);
3105   } else {
3106     doc_ = FPDFAvail_GetDocument(fpdf_availability_, password_cstr);
3107   }
3108   if (!doc_) {
3109     if (FPDF_GetLastError() == FPDF_ERR_PASSWORD)
3110       *needs_password = true;
3111     return false;
3112   }
3113
3114   // Always call FPDFAvail_IsDocAvail() so PDFium initializes internal data
3115   // structures.
3116   FPDFAvail_IsDocAvail(fpdf_availability_, &download_hints_);
3117   return true;
3118 }
3119
3120 void PDFiumEngine::GetPasswordAndLoad() {
3121   getting_password_ = true;
3122   DCHECK(!doc_);
3123   DCHECK_EQ(static_cast<unsigned long>(FPDF_ERR_PASSWORD), FPDF_GetLastError());
3124   client_->GetDocumentPassword(password_factory_.NewCallbackWithOutput(
3125       &PDFiumEngine::OnGetPasswordComplete));
3126 }
3127
3128 void PDFiumEngine::OnGetPasswordComplete(int32_t result,
3129                                          const pp::Var& password) {
3130   getting_password_ = false;
3131
3132   std::string password_text;
3133   if (result == PP_OK && password.is_string())
3134     password_text = password.AsString();
3135   ContinueLoadingDocument(password_text);
3136 }
3137
3138 void PDFiumEngine::ContinueLoadingDocument(const std::string& password) {
3139   ScopedUnsupportedFeature scoped_unsupported_feature(this);
3140   ScopedSubstFont scoped_subst_font(this);
3141
3142   bool needs_password = false;
3143   bool loaded = TryLoadingDoc(password, &needs_password);
3144   bool password_incorrect = !loaded && needs_password && !password.empty();
3145   if (password_incorrect && password_tries_remaining_ > 0) {
3146     GetPasswordAndLoad();
3147     return;
3148   }
3149
3150   if (!doc_) {
3151     client_->DocumentLoadFailed();
3152     return;
3153   }
3154
3155   if (FPDFDoc_GetPageMode(doc_) == PAGEMODE_USEOUTLINES)
3156     client_->DocumentHasUnsupportedFeature("Bookmarks");
3157
3158   permissions_ = FPDF_GetDocPermissions(doc_);
3159   permissions_handler_revision_ = FPDF_GetSecurityHandlerRevision(doc_);
3160
3161   LoadBody();
3162
3163   if (doc_loader_->IsDocumentComplete())
3164     FinishLoadingDocument();
3165 }
3166
3167 void PDFiumEngine::LoadPageInfo(bool reload) {
3168   if (!doc_loader_)
3169     return;
3170   if (pages_.empty() && reload)
3171     return;
3172   pending_pages_.clear();
3173   pp::Size old_document_size = document_size_;
3174   document_size_ = pp::Size();
3175   std::vector<pp::Rect> page_rects;
3176   int page_count = FPDF_GetPageCount(doc_);
3177   bool doc_complete = doc_loader_->IsDocumentComplete();
3178   bool is_linear = FPDFAvail_IsLinearized(fpdf_availability_) == PDF_LINEARIZED;
3179   for (int i = 0; i < page_count; ++i) {
3180     if (i != 0) {
3181       // Add space for horizontal separator.
3182       document_size_.Enlarge(0, kPageSeparatorThickness);
3183     }
3184
3185     // Get page availability. If |reload| == true, then the document has been
3186     // constructed already. Get page availability flag from already existing
3187     // PDFiumPage class.
3188     // If |reload| == false, then the document may not be fully loaded yet.
3189     bool page_available;
3190     if (reload) {
3191       page_available = pages_[i]->available();
3192     } else if (is_linear) {
3193       int linear_page_avail =
3194           FPDFAvail_IsPageAvail(fpdf_availability_, i, &download_hints_);
3195       page_available = linear_page_avail == PDF_DATA_AVAIL;
3196     } else {
3197       page_available = doc_complete;
3198     }
3199
3200     pp::Size size = page_available ? GetPageSize(i) : default_page_size_;
3201     size.Enlarge(kPageShadowLeft + kPageShadowRight,
3202                  kPageShadowTop + kPageShadowBottom);
3203     pp::Rect rect(pp::Point(0, document_size_.height()), size);
3204     page_rects.push_back(rect);
3205
3206     if (size.width() > document_size_.width())
3207       document_size_.set_width(size.width());
3208
3209     document_size_.Enlarge(0, size.height());
3210   }
3211
3212   for (int i = 0; i < page_count; ++i) {
3213     // Center pages relative to the entire document.
3214     page_rects[i].set_x((document_size_.width() - page_rects[i].width()) / 2);
3215     pp::Rect page_rect(page_rects[i]);
3216     page_rect.Inset(kPageShadowLeft, kPageShadowTop, kPageShadowRight,
3217                     kPageShadowBottom);
3218     if (reload) {
3219       pages_[i]->set_rect(page_rect);
3220     } else {
3221       // The page is marked as not being available even if |doc_complete| is
3222       // true because FPDFAvail_IsPageAvail() still has to be called for this
3223       // page, which will be done in FinishLoadingDocument().
3224       pages_.push_back(std::make_unique<PDFiumPage>(this, i, page_rect, false));
3225     }
3226   }
3227
3228   CalculateVisiblePages();
3229   if (document_size_ != old_document_size)
3230     client_->DocumentSizeUpdated(document_size_);
3231 }
3232
3233 void PDFiumEngine::LoadBody() {
3234   DCHECK(doc_);
3235   DCHECK(fpdf_availability_);
3236   if (doc_loader_->IsDocumentComplete()) {
3237     LoadForm();
3238   } else if (FPDFAvail_IsLinearized(fpdf_availability_) == PDF_LINEARIZED &&
3239              FPDF_GetPageCount(doc_) == 1) {
3240     // If we have only one page we should load form first, bacause it is may be
3241     // XFA document. And after loading form the page count and its contents may
3242     // be changed.
3243     LoadForm();
3244     if (form_status_ == PDF_FORM_NOTAVAIL)
3245       return;
3246   }
3247   LoadPages();
3248 }
3249
3250 void PDFiumEngine::LoadPages() {
3251   if (pages_.empty()) {
3252     if (!doc_loader_->IsDocumentComplete()) {
3253       // Check if the first page is available.  In a linearized PDF, that is not
3254       // always page 0.  Doing this gives us the default page size, since when
3255       // the document is available, the first page is available as well.
3256       CheckPageAvailable(FPDFAvail_GetFirstPageNum(doc_), &pending_pages_);
3257     }
3258     LoadPageInfo(false);
3259   }
3260 }
3261
3262 void PDFiumEngine::LoadForm() {
3263   if (form_)
3264     return;
3265   DCHECK(doc_);
3266   form_status_ = FPDFAvail_IsFormAvail(fpdf_availability_, &download_hints_);
3267   if (form_status_ != PDF_FORM_NOTAVAIL || doc_loader_->IsDocumentComplete()) {
3268     form_ = FPDFDOC_InitFormFillEnvironment(
3269         doc_, static_cast<FPDF_FORMFILLINFO*>(this));
3270 #if defined(PDF_ENABLE_XFA)
3271     FPDF_LoadXFA(doc_);
3272 #endif
3273
3274     FPDF_SetFormFieldHighlightColor(form_, FPDF_FORMFIELD_UNKNOWN,
3275                                     kFormHighlightColor);
3276     FPDF_SetFormFieldHighlightAlpha(form_, kFormHighlightAlpha);
3277   }
3278 }  // namespace chrome_pdf
3279
3280 void PDFiumEngine::CalculateVisiblePages() {
3281   if (!doc_loader_)
3282     return;
3283   // Clear pending requests queue, since it may contain requests to the pages
3284   // that are already invisible (after scrolling for example).
3285   pending_pages_.clear();
3286   doc_loader_->ClearPendingRequests();
3287
3288   std::vector<int> formerly_visible_pages;
3289   std::swap(visible_pages_, formerly_visible_pages);
3290
3291   pp::Rect visible_rect(plugin_size_);
3292   for (int i = 0; i < static_cast<int>(pages_.size()); ++i) {
3293     // Check an entire PageScreenRect, since we might need to repaint side
3294     // borders and shadows even if the page itself is not visible.
3295     // For example, when user use pdf with different page sizes and zoomed in
3296     // outside page area.
3297     if (visible_rect.Intersects(GetPageScreenRect(i))) {
3298       visible_pages_.push_back(i);
3299       if (CheckPageAvailable(i, &pending_pages_)) {
3300         auto it = std::find(formerly_visible_pages.begin(),
3301                             formerly_visible_pages.end(), i);
3302         if (it == formerly_visible_pages.end())
3303           client_->NotifyPageBecameVisible(pages_[i]->GetPageFeatures());
3304       }
3305     } else {
3306       // Need to unload pages when we're not using them, since some PDFs use a
3307       // lot of memory.  See http://crbug.com/48791
3308       if (defer_page_unload_) {
3309         deferred_page_unloads_.push_back(i);
3310       } else {
3311         pages_[i]->Unload();
3312       }
3313
3314       // If the last mouse down was on a page that's no longer visible, reset
3315       // that variable so that we don't send keyboard events to it (the focus
3316       // will be lost when the page is first closed anyways).
3317       if (static_cast<int>(i) == last_page_mouse_down_)
3318         last_page_mouse_down_ = -1;
3319     }
3320   }
3321
3322   // Any pending highlighting of form fields will be invalid since these are in
3323   // screen coordinates.
3324   form_highlights_.clear();
3325
3326   int most_visible_page = visible_pages_.empty() ? -1 : visible_pages_.front();
3327   // Check if the next page is more visible than the first one.
3328   if (most_visible_page != -1 && !pages_.empty() &&
3329       most_visible_page < static_cast<int>(pages_.size()) - 1) {
3330     pp::Rect rc_first =
3331         visible_rect.Intersect(GetPageScreenRect(most_visible_page));
3332     pp::Rect rc_next =
3333         visible_rect.Intersect(GetPageScreenRect(most_visible_page + 1));
3334     if (rc_next.height() > rc_first.height())
3335       most_visible_page++;
3336   }
3337
3338   SetCurrentPage(most_visible_page);
3339 }
3340
3341 bool PDFiumEngine::IsPageVisible(int index) const {
3342   return base::ContainsValue(visible_pages_, index);
3343 }
3344
3345 void PDFiumEngine::ScrollToPage(int page) {
3346   if (!PageIndexInBounds(page))
3347     return;
3348
3349   in_flight_visible_page_ = page;
3350   client_->ScrollToPage(page);
3351 }
3352
3353 bool PDFiumEngine::CheckPageAvailable(int index, std::vector<int>* pending) {
3354   if (!doc_)
3355     return false;
3356
3357   const int num_pages = static_cast<int>(pages_.size());
3358   if (index < num_pages && pages_[index]->available())
3359     return true;
3360
3361   if (!FPDFAvail_IsPageAvail(fpdf_availability_, index, &download_hints_)) {
3362     if (!base::ContainsValue(*pending, index))
3363       pending->push_back(index);
3364     return false;
3365   }
3366
3367   if (index < num_pages)
3368     pages_[index]->set_available(true);
3369   if (default_page_size_.IsEmpty())
3370     default_page_size_ = GetPageSize(index);
3371   return true;
3372 }
3373
3374 pp::Size PDFiumEngine::GetPageSize(int index) {
3375   pp::Size size;
3376   double width_in_points = 0;
3377   double height_in_points = 0;
3378   int rv =
3379       FPDF_GetPageSizeByIndex(doc_, index, &width_in_points, &height_in_points);
3380
3381   if (rv) {
3382     int width_in_pixels = static_cast<int>(
3383         ConvertUnitDouble(width_in_points, kPointsPerInch, kPixelsPerInch));
3384     int height_in_pixels = static_cast<int>(
3385         ConvertUnitDouble(height_in_points, kPointsPerInch, kPixelsPerInch));
3386     if (current_rotation_ % 2 == 1)
3387       std::swap(width_in_pixels, height_in_pixels);
3388     size = pp::Size(width_in_pixels, height_in_pixels);
3389   }
3390   return size;
3391 }
3392
3393 int PDFiumEngine::StartPaint(int page_index, const pp::Rect& dirty) {
3394   // For the first time we hit paint, do nothing and just record the paint for
3395   // the next callback.  This keeps the UI responsive in case the user is doing
3396   // a lot of scrolling.
3397   ProgressivePaint progressive;
3398   progressive.rect = dirty;
3399   progressive.page_index = page_index;
3400   progressive.bitmap = nullptr;
3401   progressive.painted_ = false;
3402   progressive_paints_.push_back(progressive);
3403   return progressive_paints_.size() - 1;
3404 }
3405
3406 bool PDFiumEngine::ContinuePaint(int progressive_index,
3407                                  pp::ImageData* image_data) {
3408   DCHECK_GE(progressive_index, 0);
3409   DCHECK_LT(static_cast<size_t>(progressive_index), progressive_paints_.size());
3410   DCHECK(image_data);
3411
3412 #if defined(OS_LINUX)
3413   g_last_instance_id = client_->GetPluginInstance()->pp_instance();
3414 #endif
3415
3416   int rv;
3417   FPDF_BITMAP bitmap = progressive_paints_[progressive_index].bitmap;
3418   int page_index = progressive_paints_[progressive_index].page_index;
3419   DCHECK(PageIndexInBounds(page_index));
3420   FPDF_PAGE page = pages_[page_index]->GetPage();
3421
3422   last_progressive_start_time_ = base::Time::Now();
3423   if (bitmap) {
3424     rv = FPDF_RenderPage_Continue(page, static_cast<IFSDK_PAUSE*>(this));
3425   } else {
3426     pp::Rect dirty = progressive_paints_[progressive_index].rect;
3427     bitmap = CreateBitmap(dirty, image_data);
3428     int start_x, start_y, size_x, size_y;
3429     GetPDFiumRect(page_index, dirty, &start_x, &start_y, &size_x, &size_y);
3430     FPDFBitmap_FillRect(bitmap, start_x, start_y, size_x, size_y, 0xFFFFFFFF);
3431     rv = FPDF_RenderPageBitmap_Start(
3432         bitmap, page, start_x, start_y, size_x, size_y, current_rotation_,
3433         GetRenderingFlags(), static_cast<IFSDK_PAUSE*>(this));
3434     progressive_paints_[progressive_index].bitmap = bitmap;
3435   }
3436   return rv != FPDF_RENDER_TOBECOUNTINUED;
3437 }
3438
3439 void PDFiumEngine::FinishPaint(int progressive_index,
3440                                pp::ImageData* image_data) {
3441   DCHECK_GE(progressive_index, 0);
3442   DCHECK_LT(static_cast<size_t>(progressive_index), progressive_paints_.size());
3443   DCHECK(image_data);
3444
3445   int page_index = progressive_paints_[progressive_index].page_index;
3446   const pp::Rect& dirty_in_screen = progressive_paints_[progressive_index].rect;
3447   FPDF_BITMAP bitmap = progressive_paints_[progressive_index].bitmap;
3448   int start_x, start_y, size_x, size_y;
3449   GetPDFiumRect(page_index, dirty_in_screen, &start_x, &start_y, &size_x,
3450                 &size_y);
3451
3452   // Draw the forms.
3453   FPDF_FFLDraw(form_, bitmap, pages_[page_index]->GetPage(), start_x, start_y,
3454                size_x, size_y, current_rotation_, GetRenderingFlags());
3455
3456   FillPageSides(progressive_index);
3457
3458   // Paint the page shadows.
3459   PaintPageShadow(progressive_index, image_data);
3460
3461   DrawSelections(progressive_index, image_data);
3462
3463   FPDF_RenderPage_Close(pages_[page_index]->GetPage());
3464   FPDFBitmap_Destroy(bitmap);
3465   progressive_paints_.erase(progressive_paints_.begin() + progressive_index);
3466
3467   client_->DocumentPaintOccurred();
3468 }
3469
3470 void PDFiumEngine::CancelPaints() {
3471   for (const auto& paint : progressive_paints_) {
3472     FPDF_RenderPage_Close(pages_[paint.page_index]->GetPage());
3473     FPDFBitmap_Destroy(paint.bitmap);
3474   }
3475   progressive_paints_.clear();
3476 }
3477
3478 void PDFiumEngine::FillPageSides(int progressive_index) {
3479   DCHECK_GE(progressive_index, 0);
3480   DCHECK_LT(static_cast<size_t>(progressive_index), progressive_paints_.size());
3481
3482   int page_index = progressive_paints_[progressive_index].page_index;
3483   const pp::Rect& dirty_in_screen = progressive_paints_[progressive_index].rect;
3484   FPDF_BITMAP bitmap = progressive_paints_[progressive_index].bitmap;
3485
3486   pp::Rect page_rect = pages_[page_index]->rect();
3487   if (page_rect.x() > 0) {
3488     pp::Rect left(0, page_rect.y() - kPageShadowTop,
3489                   page_rect.x() - kPageShadowLeft,
3490                   page_rect.height() + kPageShadowTop + kPageShadowBottom +
3491                       kPageSeparatorThickness);
3492     left = GetScreenRect(left).Intersect(dirty_in_screen);
3493
3494     FPDFBitmap_FillRect(bitmap, left.x() - dirty_in_screen.x(),
3495                         left.y() - dirty_in_screen.y(), left.width(),
3496                         left.height(), client_->GetBackgroundColor());
3497   }
3498
3499   if (page_rect.right() < document_size_.width()) {
3500     pp::Rect right(
3501         page_rect.right() + kPageShadowRight, page_rect.y() - kPageShadowTop,
3502         document_size_.width() - page_rect.right() - kPageShadowRight,
3503         page_rect.height() + kPageShadowTop + kPageShadowBottom +
3504             kPageSeparatorThickness);
3505     right = GetScreenRect(right).Intersect(dirty_in_screen);
3506
3507     FPDFBitmap_FillRect(bitmap, right.x() - dirty_in_screen.x(),
3508                         right.y() - dirty_in_screen.y(), right.width(),
3509                         right.height(), client_->GetBackgroundColor());
3510   }
3511
3512   // Paint separator.
3513   pp::Rect bottom(page_rect.x() - kPageShadowLeft,
3514                   page_rect.bottom() + kPageShadowBottom,
3515                   page_rect.width() + kPageShadowLeft + kPageShadowRight,
3516                   kPageSeparatorThickness);
3517   bottom = GetScreenRect(bottom).Intersect(dirty_in_screen);
3518
3519   FPDFBitmap_FillRect(bitmap, bottom.x() - dirty_in_screen.x(),
3520                       bottom.y() - dirty_in_screen.y(), bottom.width(),
3521                       bottom.height(), client_->GetBackgroundColor());
3522 }
3523
3524 void PDFiumEngine::PaintPageShadow(int progressive_index,
3525                                    pp::ImageData* image_data) {
3526   DCHECK_GE(progressive_index, 0);
3527   DCHECK_LT(static_cast<size_t>(progressive_index), progressive_paints_.size());
3528   DCHECK(image_data);
3529
3530   int page_index = progressive_paints_[progressive_index].page_index;
3531   const pp::Rect& dirty_in_screen = progressive_paints_[progressive_index].rect;
3532   pp::Rect page_rect = pages_[page_index]->rect();
3533   pp::Rect shadow_rect(page_rect);
3534   shadow_rect.Inset(-kPageShadowLeft, -kPageShadowTop, -kPageShadowRight,
3535                     -kPageShadowBottom);
3536
3537   // Due to the rounding errors of the GetScreenRect it is possible to get
3538   // different size shadows on the left and right sides even they are defined
3539   // the same. To fix this issue let's calculate shadow rect and then shrink
3540   // it by the size of the shadows.
3541   shadow_rect = GetScreenRect(shadow_rect);
3542   page_rect = shadow_rect;
3543
3544   page_rect.Inset(static_cast<int>(ceil(kPageShadowLeft * current_zoom_)),
3545                   static_cast<int>(ceil(kPageShadowTop * current_zoom_)),
3546                   static_cast<int>(ceil(kPageShadowRight * current_zoom_)),
3547                   static_cast<int>(ceil(kPageShadowBottom * current_zoom_)));
3548
3549   DrawPageShadow(page_rect, shadow_rect, dirty_in_screen, image_data);
3550 }
3551
3552 void PDFiumEngine::DrawSelections(int progressive_index,
3553                                   pp::ImageData* image_data) {
3554   DCHECK_GE(progressive_index, 0);
3555   DCHECK_LT(static_cast<size_t>(progressive_index), progressive_paints_.size());
3556   DCHECK(image_data);
3557
3558   int page_index = progressive_paints_[progressive_index].page_index;
3559   const pp::Rect& dirty_in_screen = progressive_paints_[progressive_index].rect;
3560
3561   void* region = nullptr;
3562   int stride;
3563   GetRegion(dirty_in_screen.point(), image_data, &region, &stride);
3564
3565   std::vector<pp::Rect> highlighted_rects;
3566   pp::Rect visible_rect = GetVisibleRect();
3567   for (auto& range : selection_) {
3568     if (range.page_index() != page_index)
3569       continue;
3570
3571     const std::vector<pp::Rect>& rects = range.GetScreenRects(
3572         visible_rect.point(), current_zoom_, current_rotation_);
3573     for (const auto& rect : rects) {
3574       pp::Rect visible_selection = rect.Intersect(dirty_in_screen);
3575       if (visible_selection.IsEmpty())
3576         continue;
3577
3578       visible_selection.Offset(-dirty_in_screen.point().x(),
3579                                -dirty_in_screen.point().y());
3580       Highlight(region, stride, visible_selection, &highlighted_rects);
3581     }
3582   }
3583
3584   for (const auto& highlight : form_highlights_) {
3585     pp::Rect visible_selection = highlight.Intersect(dirty_in_screen);
3586     if (visible_selection.IsEmpty())
3587       continue;
3588
3589     visible_selection.Offset(-dirty_in_screen.point().x(),
3590                              -dirty_in_screen.point().y());
3591     Highlight(region, stride, visible_selection, &highlighted_rects);
3592   }
3593   form_highlights_.clear();
3594 }
3595
3596 void PDFiumEngine::PaintUnavailablePage(int page_index,
3597                                         const pp::Rect& dirty,
3598                                         pp::ImageData* image_data) {
3599   int start_x, start_y, size_x, size_y;
3600   GetPDFiumRect(page_index, dirty, &start_x, &start_y, &size_x, &size_y);
3601   FPDF_BITMAP bitmap = CreateBitmap(dirty, image_data);
3602   FPDFBitmap_FillRect(bitmap, start_x, start_y, size_x, size_y,
3603                       kPendingPageColor);
3604
3605   pp::Rect loading_text_in_screen(
3606       pages_[page_index]->rect().width() / 2,
3607       pages_[page_index]->rect().y() + kLoadingTextVerticalOffset, 0, 0);
3608   loading_text_in_screen = GetScreenRect(loading_text_in_screen);
3609   FPDFBitmap_Destroy(bitmap);
3610 }
3611
3612 int PDFiumEngine::GetProgressiveIndex(int page_index) const {
3613   for (size_t i = 0; i < progressive_paints_.size(); ++i) {
3614     if (progressive_paints_[i].page_index == page_index)
3615       return i;
3616   }
3617   return -1;
3618 }
3619
3620 FPDF_BITMAP PDFiumEngine::CreateBitmap(const pp::Rect& rect,
3621                                        pp::ImageData* image_data) const {
3622   void* region;
3623   int stride;
3624   GetRegion(rect.point(), image_data, &region, &stride);
3625   if (!region)
3626     return nullptr;
3627   return FPDFBitmap_CreateEx(rect.width(), rect.height(), FPDFBitmap_BGRx,
3628                              region, stride);
3629 }
3630
3631 void PDFiumEngine::GetPDFiumRect(int page_index,
3632                                  const pp::Rect& rect,
3633                                  int* start_x,
3634                                  int* start_y,
3635                                  int* size_x,
3636                                  int* size_y) const {
3637   pp::Rect page_rect = GetScreenRect(pages_[page_index]->rect());
3638   page_rect.Offset(-rect.x(), -rect.y());
3639
3640   *start_x = page_rect.x();
3641   *start_y = page_rect.y();
3642   *size_x = page_rect.width();
3643   *size_y = page_rect.height();
3644 }
3645
3646 int PDFiumEngine::GetRenderingFlags() const {
3647   int flags = FPDF_LCD_TEXT | FPDF_NO_CATCH;
3648   if (render_grayscale_)
3649     flags |= FPDF_GRAYSCALE;
3650   if (client_->IsPrintPreview())
3651     flags |= FPDF_PRINTING;
3652   if (render_annots_)
3653     flags |= FPDF_ANNOT;
3654   return flags;
3655 }
3656
3657 pp::Rect PDFiumEngine::GetVisibleRect() const {
3658   pp::Rect rv;
3659   rv.set_x(static_cast<int>(position_.x() / current_zoom_));
3660   rv.set_y(static_cast<int>(position_.y() / current_zoom_));
3661   rv.set_width(static_cast<int>(ceil(plugin_size_.width() / current_zoom_)));
3662   rv.set_height(static_cast<int>(ceil(plugin_size_.height() / current_zoom_)));
3663   return rv;
3664 }
3665
3666 pp::Rect PDFiumEngine::GetPageScreenRect(int page_index) const {
3667   // Since we use this rect for creating the PDFium bitmap, also include other
3668   // areas around the page that we might need to update such as the page
3669   // separator and the sides if the page is narrower than the document.
3670   return GetScreenRect(
3671       pp::Rect(0, pages_[page_index]->rect().y() - kPageShadowTop,
3672                document_size_.width(),
3673                pages_[page_index]->rect().height() + kPageShadowTop +
3674                    kPageShadowBottom + kPageSeparatorThickness));
3675 }
3676
3677 pp::Rect PDFiumEngine::GetScreenRect(const pp::Rect& rect) const {
3678   pp::Rect rv;
3679   int right =
3680       static_cast<int>(ceil(rect.right() * current_zoom_ - position_.x()));
3681   int bottom =
3682       static_cast<int>(ceil(rect.bottom() * current_zoom_ - position_.y()));
3683
3684   rv.set_x(static_cast<int>(rect.x() * current_zoom_ - position_.x()));
3685   rv.set_y(static_cast<int>(rect.y() * current_zoom_ - position_.y()));
3686   rv.set_width(right - rv.x());
3687   rv.set_height(bottom - rv.y());
3688   return rv;
3689 }
3690
3691 void PDFiumEngine::Highlight(void* buffer,
3692                              int stride,
3693                              const pp::Rect& rect,
3694                              std::vector<pp::Rect>* highlighted_rects) {
3695   if (!buffer)
3696     return;
3697
3698   pp::Rect new_rect = rect;
3699   for (const auto& highlighted : *highlighted_rects)
3700     new_rect = new_rect.Subtract(highlighted);
3701   if (new_rect.IsEmpty())
3702     return;
3703
3704   std::vector<size_t> overlapping_rect_indices;
3705   for (size_t i = 0; i < highlighted_rects->size(); ++i) {
3706     if (new_rect.Intersects((*highlighted_rects)[i]))
3707       overlapping_rect_indices.push_back(i);
3708   }
3709
3710   highlighted_rects->push_back(new_rect);
3711   int l = new_rect.x();
3712   int t = new_rect.y();
3713   int w = new_rect.width();
3714   int h = new_rect.height();
3715
3716   for (int y = t; y < t + h; ++y) {
3717     for (int x = l; x < l + w; ++x) {
3718       bool overlaps = false;
3719       for (size_t i : overlapping_rect_indices) {
3720         const auto& highlighted = (*highlighted_rects)[i];
3721         if (highlighted.Contains(x, y)) {
3722           overlaps = true;
3723           break;
3724         }
3725       }
3726       if (overlaps)
3727         continue;
3728
3729       uint8_t* pixel = static_cast<uint8_t*>(buffer) + y * stride + x * 4;
3730       pixel[0] = static_cast<uint8_t>(pixel[0] * (kHighlightColorB / 255.0));
3731       pixel[1] = static_cast<uint8_t>(pixel[1] * (kHighlightColorG / 255.0));
3732       pixel[2] = static_cast<uint8_t>(pixel[2] * (kHighlightColorR / 255.0));
3733     }
3734   }
3735 }
3736
3737 PDFiumEngine::SelectionChangeInvalidator::SelectionChangeInvalidator(
3738     PDFiumEngine* engine)
3739     : engine_(engine),
3740       previous_origin_(engine_->GetVisibleRect().point()),
3741       old_selections_(GetVisibleSelections()) {}
3742
3743 PDFiumEngine::SelectionChangeInvalidator::~SelectionChangeInvalidator() {
3744   // Offset the old selections if the document scrolled since we recorded them.
3745   pp::Point offset = previous_origin_ - engine_->GetVisibleRect().point();
3746   for (auto& old_selection : old_selections_)
3747     old_selection.Offset(offset);
3748
3749   std::vector<pp::Rect> new_selections = GetVisibleSelections();
3750   for (auto& new_selection : new_selections) {
3751     for (auto& old_selection : old_selections_) {
3752       if (!old_selection.IsEmpty() && new_selection == old_selection) {
3753         // Rectangle was selected before and after, so no need to invalidate it.
3754         // Mark the rectangles by setting them to empty.
3755         new_selection = old_selection = pp::Rect();
3756         break;
3757       }
3758     }
3759   }
3760
3761   bool selection_changed = false;
3762   for (const auto& old_selection : old_selections_) {
3763     if (!old_selection.IsEmpty()) {
3764       Invalidate(old_selection);
3765       selection_changed = true;
3766     }
3767   }
3768   for (const auto& new_selection : new_selections) {
3769     if (!new_selection.IsEmpty()) {
3770       Invalidate(new_selection);
3771       selection_changed = true;
3772     }
3773   }
3774
3775   if (selection_changed) {
3776     engine_->OnSelectionTextChanged();
3777     engine_->OnSelectionPositionChanged();
3778   }
3779 }
3780
3781 std::vector<pp::Rect>
3782 PDFiumEngine::SelectionChangeInvalidator::GetVisibleSelections() const {
3783   std::vector<pp::Rect> rects;
3784   pp::Point visible_point = engine_->GetVisibleRect().point();
3785   for (auto& range : engine_->selection_) {
3786     // Exclude selections on pages that's not currently visible.
3787     if (!engine_->IsPageVisible(range.page_index()))
3788       continue;
3789
3790     const std::vector<pp::Rect>& selection_rects = range.GetScreenRects(
3791         visible_point, engine_->current_zoom_, engine_->current_rotation_);
3792     rects.insert(rects.end(), selection_rects.begin(), selection_rects.end());
3793   }
3794   return rects;
3795 }
3796
3797 void PDFiumEngine::SelectionChangeInvalidator::Invalidate(
3798     const pp::Rect& selection) {
3799   pp::Rect expanded_selection = selection;
3800   expanded_selection.Inset(-1, -1);
3801   engine_->client_->Invalidate(expanded_selection);
3802 }
3803
3804 PDFiumEngine::MouseDownState::MouseDownState(
3805     const PDFiumPage::Area& area,
3806     const PDFiumPage::LinkTarget& target)
3807     : area_(area), target_(target) {}
3808
3809 PDFiumEngine::MouseDownState::~MouseDownState() = default;
3810
3811 void PDFiumEngine::MouseDownState::Set(const PDFiumPage::Area& area,
3812                                        const PDFiumPage::LinkTarget& target) {
3813   area_ = area;
3814   target_ = target;
3815 }
3816
3817 void PDFiumEngine::MouseDownState::Reset() {
3818   area_ = PDFiumPage::NONSELECTABLE_AREA;
3819   target_ = PDFiumPage::LinkTarget();
3820 }
3821
3822 bool PDFiumEngine::MouseDownState::Matches(
3823     const PDFiumPage::Area& area,
3824     const PDFiumPage::LinkTarget& target) const {
3825   if (area_ != area)
3826     return false;
3827
3828   if (area == PDFiumPage::WEBLINK_AREA)
3829     return target_.url == target.url;
3830
3831   if (area == PDFiumPage::DOCLINK_AREA)
3832     return target_.page == target.page;
3833
3834   return true;
3835 }
3836
3837 void PDFiumEngine::DeviceToPage(int page_index,
3838                                 float device_x,
3839                                 float device_y,
3840                                 double* page_x,
3841                                 double* page_y) {
3842   *page_x = *page_y = 0;
3843   int temp_x = static_cast<int>((device_x + position_.x()) / current_zoom_ -
3844                                 pages_[page_index]->rect().x());
3845   int temp_y = static_cast<int>((device_y + position_.y()) / current_zoom_ -
3846                                 pages_[page_index]->rect().y());
3847   FPDF_DeviceToPage(pages_[page_index]->GetPage(), 0, 0,
3848                     pages_[page_index]->rect().width(),
3849                     pages_[page_index]->rect().height(), current_rotation_,
3850                     temp_x, temp_y, page_x, page_y);
3851 }
3852
3853 int PDFiumEngine::GetVisiblePageIndex(FPDF_PAGE page) {
3854   // Copy visible_pages_ since it can change as a result of loading the page in
3855   // GetPage(). See https://crbug.com/822091.
3856   std::vector<int> visible_pages_copy(visible_pages_);
3857   for (int page_index : visible_pages_copy) {
3858     if (pages_[page_index]->GetPage() == page)
3859       return page_index;
3860   }
3861   return -1;
3862 }
3863
3864 void PDFiumEngine::SetCurrentPage(int index) {
3865   in_flight_visible_page_.reset();
3866
3867   if (index == most_visible_page_ || !form_)
3868     return;
3869
3870   if (most_visible_page_ != -1 && called_do_document_action_) {
3871     FPDF_PAGE old_page = pages_[most_visible_page_]->GetPage();
3872     FORM_DoPageAAction(old_page, form_, FPDFPAGE_AACTION_CLOSE);
3873   }
3874   most_visible_page_ = index;
3875 #if defined(OS_LINUX)
3876   g_last_instance_id = client_->GetPluginInstance()->pp_instance();
3877 #endif
3878   if (most_visible_page_ != -1 && called_do_document_action_) {
3879     FPDF_PAGE new_page = pages_[most_visible_page_]->GetPage();
3880     FORM_DoPageAAction(new_page, form_, FPDFPAGE_AACTION_OPEN);
3881   }
3882 }
3883
3884 void PDFiumEngine::TransformPDFPageForPrinting(
3885     FPDF_PAGE page,
3886     const PP_PrintSettings_Dev& print_settings) {
3887   // Get the source page width and height in points.
3888   const double src_page_width = FPDF_GetPageWidth(page);
3889   const double src_page_height = FPDF_GetPageHeight(page);
3890
3891   const int src_page_rotation = FPDFPage_GetRotation(page);
3892   const bool fit_to_page = print_settings.print_scaling_option ==
3893                            PP_PRINTSCALINGOPTION_FIT_TO_PRINTABLE_AREA;
3894
3895   pp::Size page_size(print_settings.paper_size);
3896   pp::Rect content_rect(print_settings.printable_area);
3897   const bool rotated = (src_page_rotation % 2 == 1);
3898   SetPageSizeAndContentRect(rotated, src_page_width > src_page_height,
3899                             &page_size, &content_rect);
3900
3901   // Compute the screen page width and height in points.
3902   const int actual_page_width =
3903       rotated ? page_size.height() : page_size.width();
3904   const int actual_page_height =
3905       rotated ? page_size.width() : page_size.height();
3906
3907   const gfx::Rect gfx_content_rect(content_rect.x(), content_rect.y(),
3908                                    content_rect.width(), content_rect.height());
3909   const double scale_factor =
3910       fit_to_page ? CalculateScaleFactor(gfx_content_rect, src_page_width,
3911                                          src_page_height, rotated)
3912                   : 1.0;
3913
3914   // Calculate positions for the clip box.
3915   PdfRectangle media_box;
3916   PdfRectangle crop_box;
3917   bool has_media_box =
3918       !!FPDFPage_GetMediaBox(page, &media_box.left, &media_box.bottom,
3919                              &media_box.right, &media_box.top);
3920   bool has_crop_box = !!FPDFPage_GetCropBox(
3921       page, &crop_box.left, &crop_box.bottom, &crop_box.right, &crop_box.top);
3922   CalculateMediaBoxAndCropBox(rotated, has_media_box, has_crop_box, &media_box,
3923                               &crop_box);
3924   PdfRectangle source_clip_box = CalculateClipBoxBoundary(media_box, crop_box);
3925   ScalePdfRectangle(scale_factor, &source_clip_box);
3926
3927   // Calculate the translation offset values.
3928   double offset_x = 0;
3929   double offset_y = 0;
3930   if (fit_to_page) {
3931     CalculateScaledClipBoxOffset(gfx_content_rect, source_clip_box, &offset_x,
3932                                  &offset_y);
3933   } else {
3934     CalculateNonScaledClipBoxOffset(gfx_content_rect, src_page_rotation,
3935                                     actual_page_width, actual_page_height,
3936                                     source_clip_box, &offset_x, &offset_y);
3937   }
3938
3939   // Reset the media box and crop box. When the page has crop box and media box,
3940   // the plugin will display the crop box contents and not the entire media box.
3941   // If the pages have different crop box values, the plugin will display a
3942   // document of multiple page sizes. To give better user experience, we
3943   // decided to have same crop box and media box values. Hence, the user will
3944   // see a list of uniform pages.
3945   FPDFPage_SetMediaBox(page, 0, 0, page_size.width(), page_size.height());
3946   FPDFPage_SetCropBox(page, 0, 0, page_size.width(), page_size.height());
3947
3948   // Transformation is not required, return. Do this check only after updating
3949   // the media box and crop box. For more detailed information, please refer to
3950   // the comment block right before FPDF_SetMediaBox and FPDF_GetMediaBox calls.
3951   if (scale_factor == 1.0 && offset_x == 0 && offset_y == 0)
3952     return;
3953
3954   // All the positions have been calculated, now manipulate the PDF.
3955   FS_MATRIX matrix = {static_cast<float>(scale_factor),
3956                       0,
3957                       0,
3958                       static_cast<float>(scale_factor),
3959                       static_cast<float>(offset_x),
3960                       static_cast<float>(offset_y)};
3961   FS_RECTF cliprect = {static_cast<float>(source_clip_box.left + offset_x),
3962                        static_cast<float>(source_clip_box.top + offset_y),
3963                        static_cast<float>(source_clip_box.right + offset_x),
3964                        static_cast<float>(source_clip_box.bottom + offset_y)};
3965   FPDFPage_TransFormWithClip(page, &matrix, &cliprect);
3966   FPDFPage_TransformAnnots(page, scale_factor, 0, 0, scale_factor, offset_x,
3967                            offset_y);
3968 }
3969
3970 void PDFiumEngine::DrawPageShadow(const pp::Rect& page_rc,
3971                                   const pp::Rect& shadow_rc,
3972                                   const pp::Rect& clip_rc,
3973                                   pp::ImageData* image_data) {
3974   pp::Rect page_rect(page_rc);
3975   page_rect.Offset(page_offset_);
3976
3977   pp::Rect shadow_rect(shadow_rc);
3978   shadow_rect.Offset(page_offset_);
3979
3980   pp::Rect clip_rect(clip_rc);
3981   clip_rect.Offset(page_offset_);
3982
3983   // Page drop shadow parameters.
3984   const double factor = 0.5;
3985   uint32_t depth =
3986       std::max(std::max(page_rect.x() - shadow_rect.x(),
3987                         page_rect.y() - shadow_rect.y()),
3988                std::max(shadow_rect.right() - page_rect.right(),
3989                         shadow_rect.bottom() - page_rect.bottom()));
3990   depth = static_cast<uint32_t>(depth * 1.5) + 1;
3991
3992   // We need to check depth only to verify our copy of shadow matrix is correct.
3993   if (!page_shadow_.get() || page_shadow_->depth() != depth) {
3994     page_shadow_ = std::make_unique<ShadowMatrix>(
3995         depth, factor, client_->GetBackgroundColor());
3996   }
3997
3998   DCHECK(!image_data->is_null());
3999   DrawShadow(image_data, shadow_rect, page_rect, clip_rect, *page_shadow_);
4000 }
4001
4002 void PDFiumEngine::GetRegion(const pp::Point& location,
4003                              pp::ImageData* image_data,
4004                              void** region,
4005                              int* stride) const {
4006   if (image_data->is_null()) {
4007     DCHECK(plugin_size_.IsEmpty());
4008     *stride = 0;
4009     *region = nullptr;
4010     return;
4011   }
4012   char* buffer = static_cast<char*>(image_data->data());
4013   *stride = image_data->stride();
4014
4015   pp::Point offset_location = location + page_offset_;
4016   // TODO: update this when we support BIDI and scrollbars can be on the left.
4017   if (!buffer ||
4018       !pp::Rect(page_offset_, plugin_size_).Contains(offset_location)) {
4019     *region = nullptr;
4020     return;
4021   }
4022
4023   buffer += location.y() * (*stride);
4024   buffer += (location.x() + page_offset_.x()) * 4;
4025   *region = buffer;
4026 }
4027
4028 void PDFiumEngine::OnSelectionTextChanged() {
4029   DCHECK(!in_form_text_area_);
4030   pp::PDF::SetSelectedText(GetPluginInstance(), GetSelectedText().c_str());
4031 }
4032
4033 void PDFiumEngine::OnSelectionPositionChanged() {
4034   // We need to determine the top-left and bottom-right points of the selection
4035   // in order to report those to the embedder. This code assumes that the
4036   // selection list is out of order.
4037   pp::Rect left(std::numeric_limits<int32_t>::max(),
4038                 std::numeric_limits<int32_t>::max(), 0, 0);
4039   pp::Rect right;
4040   for (auto& sel : selection_) {
4041     const std::vector<pp::Rect>& screen_rects = sel.GetScreenRects(
4042         GetVisibleRect().point(), current_zoom_, current_rotation_);
4043     for (const auto& rect : screen_rects) {
4044       if (IsAboveOrDirectlyLeftOf(rect, left))
4045         left = rect;
4046       if (IsAboveOrDirectlyLeftOf(right, rect))
4047         right = rect;
4048     }
4049   }
4050   right.set_x(right.x() + right.width());
4051   if (left.IsEmpty()) {
4052     left.set_x(0);
4053     left.set_y(0);
4054   }
4055   client_->SelectionChanged(left, right);
4056 }
4057
4058 void PDFiumEngine::RotateInternal() {
4059   // Store the current find index so that we can resume finding at that
4060   // particular index after we have recomputed the find results.
4061   std::string current_find_text = current_find_text_;
4062   resume_find_index_ = current_find_index_;
4063
4064   // Save the current page.
4065   int most_visible_page = most_visible_page_;
4066
4067   InvalidateAllPages();
4068
4069   // Restore find results.
4070   if (!current_find_text.empty()) {
4071     // Clear the UI.
4072     client_->NotifyNumberOfFindResultsChanged(0, false);
4073     StartFind(current_find_text, false);
4074   }
4075
4076   // Restore current page. After a rotation, the page heights have changed but
4077   // the scroll position has not. Re-adjust.
4078   // TODO(thestig): It would be better to also restore the position on the page.
4079   client_->ScrollToPage(most_visible_page);
4080 }
4081
4082 void PDFiumEngine::SetSelecting(bool selecting) {
4083   bool was_selecting = selecting_;
4084   selecting_ = selecting;
4085   if (selecting_ != was_selecting)
4086     client_->IsSelectingChanged(selecting);
4087 }
4088
4089 void PDFiumEngine::SetEditMode(bool edit_mode) {
4090   if (!kIsEditModeTracked || edit_mode_ == edit_mode)
4091     return;
4092
4093   edit_mode_ = edit_mode;
4094   client_->IsEditModeChanged(edit_mode_);
4095 }
4096
4097 void PDFiumEngine::SetInFormTextArea(bool in_form_text_area) {
4098   // If focus was previously in form text area, clear form text selection.
4099   // Clearing needs to be done before changing focus to ensure the correct
4100   // observer is notified of the change in selection. When |in_form_text_area_|
4101   // is true, this is the Renderer. After it flips, the MimeHandler is notified.
4102   if (in_form_text_area_)
4103     pp::PDF::SetSelectedText(GetPluginInstance(), "");
4104
4105   client_->FormTextFieldFocusChange(in_form_text_area);
4106   in_form_text_area_ = in_form_text_area;
4107
4108   // Clear |editable_form_text_area_| when focus no longer in form text area.
4109   if (!in_form_text_area_)
4110     editable_form_text_area_ = false;
4111 }
4112
4113 void PDFiumEngine::SetMouseLeftButtonDown(bool is_mouse_left_button_down) {
4114   mouse_left_button_down_ = is_mouse_left_button_down;
4115 }
4116
4117 bool PDFiumEngine::IsPointInEditableFormTextArea(FPDF_PAGE page,
4118                                                  double page_x,
4119                                                  double page_y,
4120                                                  int form_type) {
4121 #if defined(PDF_ENABLE_XFA)
4122   if (IS_XFA_FORMFIELD(form_type))
4123     return form_type == FPDF_FORMFIELD_XFA_TEXTFIELD ||
4124            form_type == FPDF_FORMFIELD_XFA_COMBOBOX;
4125 #endif  // defined(PDF_ENABLE_XFA)
4126
4127   FPDF_ANNOTATION annot =
4128       FPDFAnnot_GetFormFieldAtPoint(form_, page, page_x, page_y);
4129   if (!annot)
4130     return false;
4131
4132   int flags = FPDFAnnot_GetFormFieldFlags(page, annot);
4133   bool is_editable_form_text_area =
4134       CheckIfEditableFormTextArea(flags, form_type);
4135   FPDFPage_CloseAnnot(annot);
4136   return is_editable_form_text_area;
4137 }
4138
4139 void PDFiumEngine::ScheduleTouchTimer(const pp::TouchInputEvent& evt) {
4140   touch_timers_[++next_touch_timer_id_] = evt;
4141   client_->ScheduleTouchTimerCallback(next_touch_timer_id_,
4142                                       kTouchLongPressTimeout);
4143 }
4144
4145 void PDFiumEngine::KillTouchTimer(int timer_id) {
4146   touch_timers_.erase(timer_id);
4147 }
4148
4149 bool PDFiumEngine::PageIndexInBounds(int index) const {
4150   return index >= 0 && index < static_cast<int>(pages_.size());
4151 }
4152
4153 float PDFiumEngine::GetToolbarHeightInScreenCoords() {
4154   return client_->GetToolbarHeightInScreenCoords();
4155 }
4156
4157 void PDFiumEngine::Form_Invalidate(FPDF_FORMFILLINFO* param,
4158                                    FPDF_PAGE page,
4159                                    double left,
4160                                    double top,
4161                                    double right,
4162                                    double bottom) {
4163   PDFiumEngine* engine = static_cast<PDFiumEngine*>(param);
4164   int page_index = engine->GetVisiblePageIndex(page);
4165   if (page_index == -1) {
4166     // This can sometime happen when the page is closed because it went off
4167     // screen, and PDFium invalidates the control as it's being deleted.
4168     return;
4169   }
4170
4171   pp::Rect rect = engine->pages_[page_index]->PageToScreen(
4172       engine->GetVisibleRect().point(), engine->current_zoom_, left, top, right,
4173       bottom, engine->current_rotation_);
4174   engine->client_->Invalidate(rect);
4175 }
4176
4177 void PDFiumEngine::Form_OutputSelectedRect(FPDF_FORMFILLINFO* param,
4178                                            FPDF_PAGE page,
4179                                            double left,
4180                                            double top,
4181                                            double right,
4182                                            double bottom) {
4183   PDFiumEngine* engine = static_cast<PDFiumEngine*>(param);
4184   int page_index = engine->GetVisiblePageIndex(page);
4185   if (page_index == -1) {
4186     NOTREACHED();
4187     return;
4188   }
4189   pp::Rect rect = engine->pages_[page_index]->PageToScreen(
4190       engine->GetVisibleRect().point(), engine->current_zoom_, left, top, right,
4191       bottom, engine->current_rotation_);
4192   if (rect.IsEmpty())
4193     return;
4194
4195   engine->form_highlights_.push_back(rect);
4196 }
4197
4198 void PDFiumEngine::Form_SetCursor(FPDF_FORMFILLINFO* param, int cursor_type) {
4199   // We don't need this since it's not enough to change the cursor in all
4200   // scenarios.  Instead, we check which form field we're under in OnMouseMove.
4201 }
4202
4203 int PDFiumEngine::Form_SetTimer(FPDF_FORMFILLINFO* param,
4204                                 int elapse,
4205                                 TimerCallback timer_func) {
4206   PDFiumEngine* engine = static_cast<PDFiumEngine*>(param);
4207   base::TimeDelta elapse_time = base::TimeDelta::FromMilliseconds(elapse);
4208   engine->formfill_timers_.emplace(
4209       std::piecewise_construct,
4210       std::forward_as_tuple(++engine->next_formfill_timer_id_),
4211       std::forward_as_tuple(elapse_time, timer_func));
4212   engine->client_->ScheduleCallback(engine->next_formfill_timer_id_,
4213                                     elapse_time);
4214   return engine->next_formfill_timer_id_;
4215 }
4216
4217 void PDFiumEngine::Form_KillTimer(FPDF_FORMFILLINFO* param, int timer_id) {
4218   PDFiumEngine* engine = static_cast<PDFiumEngine*>(param);
4219   engine->formfill_timers_.erase(timer_id);
4220 }
4221
4222 FPDF_SYSTEMTIME PDFiumEngine::Form_GetLocalTime(FPDF_FORMFILLINFO* param) {
4223   base::Time time = base::Time::Now();
4224   base::Time::Exploded exploded;
4225   time.LocalExplode(&exploded);
4226
4227   FPDF_SYSTEMTIME rv;
4228   rv.wYear = exploded.year;
4229   rv.wMonth = exploded.month;
4230   rv.wDayOfWeek = exploded.day_of_week;
4231   rv.wDay = exploded.day_of_month;
4232   rv.wHour = exploded.hour;
4233   rv.wMinute = exploded.minute;
4234   rv.wSecond = exploded.second;
4235   rv.wMilliseconds = exploded.millisecond;
4236   return rv;
4237 }
4238
4239 void PDFiumEngine::Form_OnChange(FPDF_FORMFILLINFO* param) {
4240   PDFiumEngine* engine = static_cast<PDFiumEngine*>(param);
4241   engine->SetEditMode(true);
4242 }
4243
4244 FPDF_PAGE PDFiumEngine::Form_GetPage(FPDF_FORMFILLINFO* param,
4245                                      FPDF_DOCUMENT document,
4246                                      int page_index) {
4247   PDFiumEngine* engine = static_cast<PDFiumEngine*>(param);
4248   if (!engine->PageIndexInBounds(page_index))
4249     return nullptr;
4250   return engine->pages_[page_index]->GetPage();
4251 }
4252
4253 FPDF_PAGE PDFiumEngine::Form_GetCurrentPage(FPDF_FORMFILLINFO* param,
4254                                             FPDF_DOCUMENT document) {
4255   PDFiumEngine* engine = static_cast<PDFiumEngine*>(param);
4256   int index = engine->last_page_mouse_down_;
4257   if (index == -1) {
4258     index = engine->GetMostVisiblePage();
4259     if (index == -1) {
4260       NOTREACHED();
4261       return nullptr;
4262     }
4263   }
4264
4265   return engine->pages_[index]->GetPage();
4266 }
4267
4268 int PDFiumEngine::Form_GetRotation(FPDF_FORMFILLINFO* param, FPDF_PAGE page) {
4269   return 0;
4270 }
4271
4272 void PDFiumEngine::Form_ExecuteNamedAction(FPDF_FORMFILLINFO* param,
4273                                            FPDF_BYTESTRING named_action) {
4274   PDFiumEngine* engine = static_cast<PDFiumEngine*>(param);
4275   std::string action(named_action);
4276   if (action == "Print") {
4277     engine->client_->Print();
4278     return;
4279   }
4280
4281   int index = engine->last_page_mouse_down_;
4282   /* Don't try to calculate the most visible page if we don't have a left click
4283      before this event (this code originally copied Form_GetCurrentPage which of
4284      course needs to do that and which doesn't have recursion). This can end up
4285      causing infinite recursion. See http://crbug.com/240413 for more
4286      information. Either way, it's not necessary for the spec'd list of named
4287      actions.
4288   if (index == -1)
4289     index = engine->GetMostVisiblePage();
4290   */
4291   if (index == -1)
4292     return;
4293
4294   // This is the only list of named actions per the spec (see 12.6.4.11). Adobe
4295   // Reader supports more, like FitWidth, but since they're not part of the spec
4296   // and we haven't got bugs about them, no need to now.
4297   if (action == "NextPage") {
4298     engine->ScrollToPage(index + 1);
4299   } else if (action == "PrevPage") {
4300     engine->ScrollToPage(index - 1);
4301   } else if (action == "FirstPage") {
4302     engine->ScrollToPage(0);
4303   } else if (action == "LastPage") {
4304     engine->ScrollToPage(engine->pages_.size() - 1);
4305   }
4306 }
4307
4308 void PDFiumEngine::Form_SetTextFieldFocus(FPDF_FORMFILLINFO* param,
4309                                           FPDF_WIDESTRING value,
4310                                           FPDF_DWORD valueLen,
4311                                           FPDF_BOOL is_focus) {
4312   // Do nothing for now.
4313   // TODO(gene): use this signal to trigger OSK.
4314 }
4315
4316 void PDFiumEngine::Form_DoURIAction(FPDF_FORMFILLINFO* param,
4317                                     FPDF_BYTESTRING uri) {
4318   PDFiumEngine* engine = static_cast<PDFiumEngine*>(param);
4319   engine->client_->NavigateTo(std::string(uri),
4320                               WindowOpenDisposition::CURRENT_TAB);
4321 }
4322
4323 void PDFiumEngine::Form_DoGoToAction(FPDF_FORMFILLINFO* param,
4324                                      int page_index,
4325                                      int zoom_mode,
4326                                      float* position_array,
4327                                      int size_of_array) {
4328   PDFiumEngine* engine = static_cast<PDFiumEngine*>(param);
4329   engine->ScrollToPage(page_index);
4330 }
4331
4332 int PDFiumEngine::Form_Alert(IPDF_JSPLATFORM* param,
4333                              FPDF_WIDESTRING message,
4334                              FPDF_WIDESTRING title,
4335                              int type,
4336                              int icon) {
4337   // See fpdfformfill.h for these values.
4338   enum AlertType {
4339     ALERT_TYPE_OK = 0,
4340     ALERT_TYPE_OK_CANCEL,
4341     ALERT_TYPE_YES_ON,
4342     ALERT_TYPE_YES_NO_CANCEL
4343   };
4344
4345   enum AlertResult {
4346     ALERT_RESULT_OK = 1,
4347     ALERT_RESULT_CANCEL,
4348     ALERT_RESULT_NO,
4349     ALERT_RESULT_YES
4350   };
4351
4352   PDFiumEngine* engine = static_cast<PDFiumEngine*>(param);
4353   std::string message_str = WideStringToString(message);
4354   if (type == ALERT_TYPE_OK) {
4355     engine->client_->Alert(message_str);
4356     return ALERT_RESULT_OK;
4357   }
4358
4359   bool rv = engine->client_->Confirm(message_str);
4360   if (type == ALERT_TYPE_OK_CANCEL)
4361     return rv ? ALERT_RESULT_OK : ALERT_RESULT_CANCEL;
4362   return rv ? ALERT_RESULT_YES : ALERT_RESULT_NO;
4363 }
4364
4365 void PDFiumEngine::Form_Beep(IPDF_JSPLATFORM* param, int type) {
4366   // Beeps are annoying, and not possible using javascript, so ignore for now.
4367 }
4368
4369 int PDFiumEngine::Form_Response(IPDF_JSPLATFORM* param,
4370                                 FPDF_WIDESTRING question,
4371                                 FPDF_WIDESTRING title,
4372                                 FPDF_WIDESTRING default_response,
4373                                 FPDF_WIDESTRING label,
4374                                 FPDF_BOOL password,
4375                                 void* response,
4376                                 int length) {
4377   std::string question_str = WideStringToString(question);
4378   std::string default_str = WideStringToString(default_response);
4379
4380   PDFiumEngine* engine = static_cast<PDFiumEngine*>(param);
4381   std::string rv = engine->client_->Prompt(question_str, default_str);
4382   base::string16 rv_16 = base::UTF8ToUTF16(rv);
4383   int rv_bytes = rv_16.size() * sizeof(base::char16);
4384   if (response) {
4385     int bytes_to_copy = rv_bytes < length ? rv_bytes : length;
4386     memcpy(response, rv_16.c_str(), bytes_to_copy);
4387   }
4388   return rv_bytes;
4389 }
4390
4391 int PDFiumEngine::Form_GetFilePath(IPDF_JSPLATFORM* param,
4392                                    void* file_path,
4393                                    int length) {
4394   PDFiumEngine* engine = static_cast<PDFiumEngine*>(param);
4395   std::string rv = engine->client_->GetURL();
4396   if (file_path && rv.size() <= static_cast<size_t>(length))
4397     memcpy(file_path, rv.c_str(), rv.size());
4398   return rv.size();
4399 }
4400
4401 void PDFiumEngine::Form_Mail(IPDF_JSPLATFORM* param,
4402                              void* mail_data,
4403                              int length,
4404                              FPDF_BOOL ui,
4405                              FPDF_WIDESTRING to,
4406                              FPDF_WIDESTRING subject,
4407                              FPDF_WIDESTRING cc,
4408                              FPDF_WIDESTRING bcc,
4409                              FPDF_WIDESTRING message) {
4410   // Note: |mail_data| and |length| are ignored. We don't handle attachments;
4411   // there is no way with mailto.
4412   std::string to_str = WideStringToString(to);
4413   std::string cc_str = WideStringToString(cc);
4414   std::string bcc_str = WideStringToString(bcc);
4415   std::string subject_str = WideStringToString(subject);
4416   std::string message_str = WideStringToString(message);
4417
4418   PDFiumEngine* engine = static_cast<PDFiumEngine*>(param);
4419   engine->client_->Email(to_str, cc_str, bcc_str, subject_str, message_str);
4420 }
4421
4422 void PDFiumEngine::Form_Print(IPDF_JSPLATFORM* param,
4423                               FPDF_BOOL ui,
4424                               int start,
4425                               int end,
4426                               FPDF_BOOL silent,
4427                               FPDF_BOOL shrink_to_fit,
4428                               FPDF_BOOL print_as_image,
4429                               FPDF_BOOL reverse,
4430                               FPDF_BOOL annotations) {
4431   // No way to pass the extra information to the print dialog using JavaScript.
4432   // Just opening it is fine for now.
4433   PDFiumEngine* engine = static_cast<PDFiumEngine*>(param);
4434   engine->client_->Print();
4435 }
4436
4437 void PDFiumEngine::Form_SubmitForm(IPDF_JSPLATFORM* param,
4438                                    void* form_data,
4439                                    int length,
4440                                    FPDF_WIDESTRING url) {
4441   std::string url_str = WideStringToString(url);
4442   PDFiumEngine* engine = static_cast<PDFiumEngine*>(param);
4443   engine->client_->SubmitForm(url_str, form_data, length);
4444 }
4445
4446 void PDFiumEngine::Form_GotoPage(IPDF_JSPLATFORM* param, int page_number) {
4447   PDFiumEngine* engine = static_cast<PDFiumEngine*>(param);
4448   engine->ScrollToPage(page_number);
4449 }
4450
4451 FPDF_BOOL PDFiumEngine::Pause_NeedToPauseNow(IFSDK_PAUSE* param) {
4452   PDFiumEngine* engine = static_cast<PDFiumEngine*>(param);
4453   return base::Time::Now() - engine->last_progressive_start_time_ >
4454          engine->progressive_paint_timeout_;
4455 }
4456
4457 void PDFiumEngine::SetCaretPosition(const pp::Point& position) {
4458   // TODO(dsinclair): Handle caret position ...
4459 }
4460
4461 void PDFiumEngine::MoveRangeSelectionExtent(const pp::Point& extent) {
4462   int page_index = -1;
4463   int char_index = -1;
4464   int form_type = FPDF_FORMFIELD_UNKNOWN;
4465   PDFiumPage::LinkTarget target;
4466   GetCharIndex(extent, &page_index, &char_index, &form_type, &target);
4467   if (page_index < 0 || char_index < 0)
4468     return;
4469
4470   SelectionChangeInvalidator selection_invalidator(this);
4471   if (range_selection_direction_ == RangeSelectionDirection::Right) {
4472     ExtendSelection(page_index, char_index);
4473     return;
4474   }
4475
4476   // For a left selection we clear the current selection and set a new starting
4477   // point based on the new left position. We then extend that selection out to
4478   // the previously provided base location.
4479   selection_.clear();
4480   selection_.push_back(PDFiumRange(pages_[page_index].get(), char_index, 0));
4481
4482   // This should always succeeed because the range selection base should have
4483   // already been selected.
4484   GetCharIndex(range_selection_base_, &page_index, &char_index, &form_type,
4485                &target);
4486   ExtendSelection(page_index, char_index);
4487 }
4488
4489 void PDFiumEngine::SetSelectionBounds(const pp::Point& base,
4490                                       const pp::Point& extent) {
4491   range_selection_base_ = base;
4492   range_selection_direction_ = IsAboveOrDirectlyLeftOf(base, extent)
4493                                    ? RangeSelectionDirection::Left
4494                                    : RangeSelectionDirection::Right;
4495 }
4496
4497 void PDFiumEngine::GetSelection(uint32_t* selection_start_page_index,
4498                                 uint32_t* selection_start_char_index,
4499                                 uint32_t* selection_end_page_index,
4500                                 uint32_t* selection_end_char_index) {
4501   size_t len = selection_.size();
4502   if (len == 0) {
4503     *selection_start_page_index = 0;
4504     *selection_start_char_index = 0;
4505     *selection_end_page_index = 0;
4506     *selection_end_char_index = 0;
4507     return;
4508   }
4509
4510   *selection_start_page_index = selection_[0].page_index();
4511   *selection_start_char_index = selection_[0].char_index();
4512   *selection_end_page_index = selection_[len - 1].page_index();
4513
4514   // If the selection is all within one page, the end index is the
4515   // start index plus the char count. But if the selection spans
4516   // multiple pages, the selection starts at the beginning of the
4517   // last page in |selection_| and goes to the char count.
4518   if (len == 1) {
4519     *selection_end_char_index =
4520         selection_[0].char_index() + selection_[0].char_count();
4521   } else {
4522     *selection_end_char_index = selection_[len - 1].char_count();
4523   }
4524 }
4525
4526 PDFiumEngine::FormFillTimerData::FormFillTimerData(base::TimeDelta period,
4527                                                    TimerCallback callback)
4528     : timer_period(period), timer_callback(callback) {}
4529
4530 ScopedUnsupportedFeature::ScopedUnsupportedFeature(PDFiumEngine* engine)
4531     : old_engine_(g_engine_for_unsupported) {
4532   g_engine_for_unsupported = engine;
4533 }
4534
4535 ScopedUnsupportedFeature::~ScopedUnsupportedFeature() {
4536   g_engine_for_unsupported = old_engine_;
4537 }
4538
4539 ScopedSubstFont::ScopedSubstFont(PDFiumEngine* engine)
4540     : old_engine_(g_engine_for_fontmapper) {
4541   g_engine_for_fontmapper = engine;
4542 }
4543
4544 ScopedSubstFont::~ScopedSubstFont() {
4545   g_engine_for_fontmapper = old_engine_;
4546 }
4547
4548 namespace {
4549
4550 base::LazyInstance<PDFiumEngineExports>::Leaky g_pdf_engine_exports =
4551     LAZY_INSTANCE_INITIALIZER;
4552
4553 int CalculatePosition(FPDF_PAGE page,
4554                       const PDFiumEngineExports::RenderingSettings& settings,
4555                       pp::Rect* dest) {
4556   // settings.bounds is in terms of the max DPI. Convert page sizes to match.
4557   int dpi = std::max(settings.dpi_x, settings.dpi_y);
4558   int page_width = static_cast<int>(
4559       ConvertUnitDouble(FPDF_GetPageWidth(page), kPointsPerInch, dpi));
4560   int page_height = static_cast<int>(
4561       ConvertUnitDouble(FPDF_GetPageHeight(page), kPointsPerInch, dpi));
4562
4563   // Start by assuming that we will draw exactly to the bounds rect
4564   // specified.
4565   *dest = settings.bounds;
4566
4567   int rotate = 0;  // normal orientation.
4568
4569   // Auto-rotate landscape pages to print correctly.
4570   if (settings.autorotate &&
4571       (dest->width() > dest->height()) != (page_width > page_height)) {
4572     rotate = 3;  // 90 degrees counter-clockwise.
4573     std::swap(page_width, page_height);
4574   }
4575
4576   // See if we need to scale the output
4577   bool scale_to_bounds = false;
4578   if (settings.fit_to_bounds &&
4579       ((page_width > dest->width()) || (page_height > dest->height()))) {
4580     scale_to_bounds = true;
4581   } else if (settings.stretch_to_bounds &&
4582              ((page_width < dest->width()) || (page_height < dest->height()))) {
4583     scale_to_bounds = true;
4584   }
4585
4586   if (scale_to_bounds) {
4587     // If we need to maintain aspect ratio, calculate the actual width and
4588     // height.
4589     if (settings.keep_aspect_ratio) {
4590       double scale_factor_x = page_width;
4591       scale_factor_x /= dest->width();
4592       double scale_factor_y = page_height;
4593       scale_factor_y /= dest->height();
4594       if (scale_factor_x > scale_factor_y) {
4595         dest->set_height(page_height / scale_factor_x);
4596       } else {
4597         dest->set_width(page_width / scale_factor_y);
4598       }
4599     }
4600   } else {
4601     // We are not scaling to bounds. Draw in the actual page size. If the
4602     // actual page size is larger than the bounds, the output will be
4603     // clipped.
4604     dest->set_width(page_width);
4605     dest->set_height(page_height);
4606   }
4607
4608   // Scale the bounds to device units if DPI is rectangular.
4609   if (settings.dpi_x != settings.dpi_y) {
4610     dest->set_width(dest->width() * settings.dpi_x / dpi);
4611     dest->set_height(dest->height() * settings.dpi_y / dpi);
4612   }
4613
4614   if (settings.center_in_bounds) {
4615     pp::Point offset(
4616         (settings.bounds.width() * settings.dpi_x / dpi - dest->width()) / 2,
4617         (settings.bounds.height() * settings.dpi_y / dpi - dest->height()) / 2);
4618     dest->Offset(offset);
4619   }
4620   return rotate;
4621 }
4622
4623 }  // namespace
4624
4625 PDFEngineExports::RenderingSettings::RenderingSettings(int dpi_x,
4626                                                        int dpi_y,
4627                                                        const pp::Rect& bounds,
4628                                                        bool fit_to_bounds,
4629                                                        bool stretch_to_bounds,
4630                                                        bool keep_aspect_ratio,
4631                                                        bool center_in_bounds,
4632                                                        bool autorotate,
4633                                                        bool use_color)
4634     : dpi_x(dpi_x),
4635       dpi_y(dpi_y),
4636       bounds(bounds),
4637       fit_to_bounds(fit_to_bounds),
4638       stretch_to_bounds(stretch_to_bounds),
4639       keep_aspect_ratio(keep_aspect_ratio),
4640       center_in_bounds(center_in_bounds),
4641       autorotate(autorotate),
4642       use_color(use_color) {}
4643
4644 PDFEngineExports::RenderingSettings::RenderingSettings(
4645     const RenderingSettings& that) = default;
4646
4647 PDFEngineExports* PDFEngineExports::Get() {
4648   return g_pdf_engine_exports.Pointer();
4649 }
4650
4651 #if defined(OS_WIN)
4652 bool PDFiumEngineExports::RenderPDFPageToDC(const void* pdf_buffer,
4653                                             int buffer_size,
4654                                             int page_number,
4655                                             const RenderingSettings& settings,
4656                                             HDC dc) {
4657   std::unique_ptr<void, FPDFDocumentDeleter> doc(
4658       FPDF_LoadMemDocument(pdf_buffer, buffer_size, nullptr));
4659   if (!doc)
4660     return false;
4661   FPDF_PAGE page = FPDF_LoadPage(doc.get(), page_number);
4662   if (!page)
4663     return false;
4664
4665   RenderingSettings new_settings = settings;
4666   // calculate the page size
4667   if (new_settings.dpi_x == -1)
4668     new_settings.dpi_x = GetDeviceCaps(dc, LOGPIXELSX);
4669   if (new_settings.dpi_y == -1)
4670     new_settings.dpi_y = GetDeviceCaps(dc, LOGPIXELSY);
4671
4672   pp::Rect dest;
4673   int rotate = CalculatePosition(page, new_settings, &dest);
4674
4675   int save_state = SaveDC(dc);
4676   // The caller wanted all drawing to happen within the bounds specified.
4677   // Based on scale calculations, our destination rect might be larger
4678   // than the bounds. Set the clip rect to the bounds.
4679   IntersectClipRect(dc, settings.bounds.x(), settings.bounds.y(),
4680                     settings.bounds.x() + settings.bounds.width(),
4681                     settings.bounds.y() + settings.bounds.height());
4682
4683   int flags = FPDF_ANNOT | FPDF_PRINTING | FPDF_NO_CATCH;
4684   if (!settings.use_color)
4685     flags |= FPDF_GRAYSCALE;
4686
4687   // A "temporary" hack. Some PDFs seems to render very slowly if
4688   // FPDF_RenderPage() is directly used on a printer DC. I suspect it is
4689   // because of the code to talk Postscript directly to the printer if
4690   // the printer supports this. Need to discuss this with PDFium. For now,
4691   // render to a bitmap and then blit the bitmap to the DC if we have been
4692   // supplied a printer DC.
4693   int device_type = GetDeviceCaps(dc, TECHNOLOGY);
4694   if (device_type == DT_RASPRINTER || device_type == DT_PLOTTER) {
4695     FPDF_BITMAP bitmap =
4696         FPDFBitmap_Create(dest.width(), dest.height(), FPDFBitmap_BGRx);
4697     // Clear the bitmap
4698     FPDFBitmap_FillRect(bitmap, 0, 0, dest.width(), dest.height(), 0xFFFFFFFF);
4699     FPDF_RenderPageBitmap(bitmap, page, 0, 0, dest.width(), dest.height(),
4700                           rotate, flags);
4701     int stride = FPDFBitmap_GetStride(bitmap);
4702     BITMAPINFO bmi;
4703     memset(&bmi, 0, sizeof(bmi));
4704     bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
4705     bmi.bmiHeader.biWidth = dest.width();
4706     bmi.bmiHeader.biHeight = -dest.height();  // top-down image
4707     bmi.bmiHeader.biPlanes = 1;
4708     bmi.bmiHeader.biBitCount = 32;
4709     bmi.bmiHeader.biCompression = BI_RGB;
4710     bmi.bmiHeader.biSizeImage = stride * dest.height();
4711     StretchDIBits(dc, dest.x(), dest.y(), dest.width(), dest.height(), 0, 0,
4712                   dest.width(), dest.height(), FPDFBitmap_GetBuffer(bitmap),
4713                   &bmi, DIB_RGB_COLORS, SRCCOPY);
4714     FPDFBitmap_Destroy(bitmap);
4715   } else {
4716     FPDF_RenderPage(dc, page, dest.x(), dest.y(), dest.width(), dest.height(),
4717                     rotate, flags);
4718   }
4719   RestoreDC(dc, save_state);
4720   FPDF_ClosePage(page);
4721   return true;
4722 }
4723
4724 void PDFiumEngineExports::SetPDFEnsureTypefaceCharactersAccessible(
4725     PDFEnsureTypefaceCharactersAccessible func) {
4726   FPDF_SetTypefaceAccessibleFunc(
4727       reinterpret_cast<PDFiumEnsureTypefaceCharactersAccessible>(func));
4728 }
4729
4730 void PDFiumEngineExports::SetPDFUseGDIPrinting(bool enable) {
4731   FPDF_SetPrintTextWithGDI(enable);
4732 }
4733
4734 void PDFiumEngineExports::SetPDFUsePrintMode(int mode) {
4735   FPDF_SetPrintMode(mode);
4736 }
4737 #endif  // defined(OS_WIN)
4738
4739 bool PDFiumEngineExports::RenderPDFPageToBitmap(
4740     const void* pdf_buffer,
4741     int pdf_buffer_size,
4742     int page_number,
4743     const RenderingSettings& settings,
4744     void* bitmap_buffer) {
4745   std::unique_ptr<void, FPDFDocumentDeleter> doc(
4746       FPDF_LoadMemDocument(pdf_buffer, pdf_buffer_size, nullptr));
4747   if (!doc)
4748     return false;
4749   FPDF_PAGE page = FPDF_LoadPage(doc.get(), page_number);
4750   if (!page)
4751     return false;
4752
4753   pp::Rect dest;
4754   int rotate = CalculatePosition(page, settings, &dest);
4755
4756   FPDF_BITMAP bitmap = FPDFBitmap_CreateEx(
4757       settings.bounds.width(), settings.bounds.height(), FPDFBitmap_BGRA,
4758       bitmap_buffer, settings.bounds.width() * 4);
4759   // Clear the bitmap
4760   FPDFBitmap_FillRect(bitmap, 0, 0, settings.bounds.width(),
4761                       settings.bounds.height(), 0xFFFFFFFF);
4762   // Shift top-left corner of bounds to (0, 0) if it's not there.
4763   dest.set_point(dest.point() - settings.bounds.point());
4764
4765   int flags = FPDF_ANNOT | FPDF_PRINTING | FPDF_NO_CATCH;
4766   if (!settings.use_color)
4767     flags |= FPDF_GRAYSCALE;
4768
4769   FPDF_RenderPageBitmap(bitmap, page, dest.x(), dest.y(), dest.width(),
4770                         dest.height(), rotate, flags);
4771   FPDFBitmap_Destroy(bitmap);
4772   FPDF_ClosePage(page);
4773   return true;
4774 }
4775
4776 bool PDFiumEngineExports::GetPDFDocInfo(const void* pdf_buffer,
4777                                         int buffer_size,
4778                                         int* page_count,
4779                                         double* max_page_width) {
4780   std::unique_ptr<void, FPDFDocumentDeleter> doc(
4781       FPDF_LoadMemDocument(pdf_buffer, buffer_size, nullptr));
4782   if (!doc)
4783     return false;
4784
4785   if (!page_count && !max_page_width)
4786     return true;
4787
4788   int page_count_local = FPDF_GetPageCount(doc.get());
4789   if (page_count)
4790     *page_count = page_count_local;
4791
4792   if (max_page_width) {
4793     *max_page_width = 0;
4794     for (int page_number = 0; page_number < page_count_local; page_number++) {
4795       double page_width = 0;
4796       double page_height = 0;
4797       FPDF_GetPageSizeByIndex(doc.get(), page_number, &page_width,
4798                               &page_height);
4799       if (page_width > *max_page_width) {
4800         *max_page_width = page_width;
4801       }
4802     }
4803   }
4804   return true;
4805 }
4806
4807 bool PDFiumEngineExports::GetPDFPageSizeByIndex(const void* pdf_buffer,
4808                                                 int pdf_buffer_size,
4809                                                 int page_number,
4810                                                 double* width,
4811                                                 double* height) {
4812   std::unique_ptr<void, FPDFDocumentDeleter> doc(
4813       FPDF_LoadMemDocument(pdf_buffer, pdf_buffer_size, nullptr));
4814   if (!doc)
4815     return false;
4816   return FPDF_GetPageSizeByIndex(doc.get(), page_number, width, height) != 0;
4817 }
4818
4819 }  // namespace chrome_pdf