Merge XFA to PDFium master at 4dc95e7 on 10/28/2014
[pdfium.git] / xfa_test / pdf / pdfium / pdfium_engine.cc
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.\r
2 // Use of this source code is governed by a BSD-style license that can be\r
3 // found in the LICENSE file.\r
4 \r
5 #include "pdf/pdfium/pdfium_engine.h"\r
6 \r
7 #include <math.h>\r
8 \r
9 #include "base/json/json_writer.h"\r
10 #include "base/logging.h"\r
11 #include "base/memory/scoped_ptr.h"\r
12 #include "base/stl_util.h"\r
13 #include "base/strings/string_number_conversions.h"\r
14 #include "base/strings/string_piece.h"\r
15 #include "base/strings/string_util.h"\r
16 #include "base/strings/utf_string_conversions.h"\r
17 #include "base/values.h"\r
18 #include "pdf/draw_utils.h"\r
19 #include "pdf/pdfium/pdfium_mem_buffer_file_read.h"\r
20 #include "pdf/pdfium/pdfium_mem_buffer_file_write.h"\r
21 #include "ppapi/c/pp_errors.h"\r
22 #include "ppapi/c/pp_input_event.h"\r
23 #include "ppapi/c/ppb_core.h"\r
24 #include "ppapi/c/private/ppb_pdf.h"\r
25 #include "ppapi/cpp/dev/memory_dev.h"\r
26 #include "ppapi/cpp/input_event.h"\r
27 #include "ppapi/cpp/instance.h"\r
28 #include "ppapi/cpp/module.h"\r
29 #include "ppapi/cpp/private/pdf.h"\r
30 #include "ppapi/cpp/trusted/browser_font_trusted.h"\r
31 #include "ppapi/cpp/url_response_info.h"\r
32 #include "ppapi/cpp/var.h"\r
33 #include "third_party/pdfium/fpdfsdk/include/fpdf_ext.h"\r
34 #include "third_party/pdfium/fpdfsdk/include/fpdf_flatten.h"\r
35 #include "third_party/pdfium/fpdfsdk/include/fpdf_searchex.h"\r
36 #include "third_party/pdfium/fpdfsdk/include/fpdf_sysfontinfo.h"\r
37 #include "third_party/pdfium/fpdfsdk/include/fpdf_transformpage.h"\r
38 #include "third_party/pdfium/fpdfsdk/include/fpdfedit.h"\r
39 #include "third_party/pdfium/fpdfsdk/include/fpdfoom.h"\r
40 #include "third_party/pdfium/fpdfsdk/include/fpdfppo.h"\r
41 #include "third_party/pdfium/fpdfsdk/include/fpdfsave.h"\r
42 #include "third_party/pdfium/fpdfsdk/include/pdfwindow/PDFWindow.h"\r
43 #include "third_party/pdfium/fpdfsdk/include/pdfwindow/PWL_FontMap.h"\r
44 #include "ui/events/keycodes/keyboard_codes.h"\r
45 \r
46 namespace chrome_pdf {\r
47 \r
48 namespace {\r
49 \r
50 #define kPageShadowTop    3\r
51 #define kPageShadowBottom 7\r
52 #define kPageShadowLeft   5\r
53 #define kPageShadowRight  5\r
54 \r
55 #define kPageSeparatorThickness 4\r
56 #define kHighlightColorR 153\r
57 #define kHighlightColorG 193\r
58 #define kHighlightColorB 218\r
59 \r
60 const uint32 kPendingPageColor = 0xFFEEEEEE;\r
61 \r
62 #define kFormHighlightColor 0xFFE4DD\r
63 #define kFormHighlightAlpha 100\r
64 \r
65 #define kMaxPasswordTries 3\r
66 \r
67 // See Table 3.20 in\r
68 // http://www.adobe.com/devnet/acrobat/pdfs/pdf_reference_1-7.pdf\r
69 #define kPDFPermissionPrintLowQualityMask  1 << 2\r
70 #define kPDFPermissionPrintHighQualityMask 1 << 11\r
71 #define kPDFPermissionCopyMask             1 << 4\r
72 #define kPDFPermissionCopyAccessibleMask   1 << 9\r
73 \r
74 #define kLoadingTextVerticalOffset 50\r
75 \r
76 // The maximum amount of time we'll spend doing a paint before we give back\r
77 // control of the thread.\r
78 #define kMaxProgressivePaintTimeMs 50\r
79 \r
80 // The maximum amount of time we'll spend doing the first paint. This is less\r
81 // than the above to keep things smooth if the user is scrolling quickly. We\r
82 // try painting a little because with accelerated compositing, we get flushes\r
83 // only every 16 ms. If we were to wait until the next flush to paint the rest\r
84 // of the pdf, we would never get to draw the pdf and would only draw the\r
85 // scrollbars. This value is picked to give enough time for gpu related code to\r
86 // do its thing and still fit within the timelimit for 60Hz. For the\r
87 // non-composited case, this doesn't make things worse since we're still\r
88 // painting the scrollbars > 60 Hz.\r
89 #define kMaxInitialProgressivePaintTimeMs 10\r
90 \r
91 // Copied from printing/units.cc because we don't want to depend on printing\r
92 // since it brings in libpng which causes duplicate symbols with PDFium.\r
93 const int kPointsPerInch = 72;\r
94 const int kPixelsPerInch = 96;\r
95 \r
96 struct ClipBox {\r
97   float left;\r
98   float right;\r
99   float top;\r
100   float bottom;\r
101 };\r
102 \r
103 int ConvertUnit(int value, int old_unit, int new_unit) {\r
104   // With integer arithmetic, to divide a value with correct rounding, you need\r
105   // to add half of the divisor value to the dividend value. You need to do the\r
106   // reverse with negative number.\r
107   if (value >= 0) {\r
108     return ((value * new_unit) + (old_unit / 2)) / old_unit;\r
109   } else {\r
110     return ((value * new_unit) - (old_unit / 2)) / old_unit;\r
111   }\r
112 }\r
113 \r
114 std::vector<uint32_t> GetPageNumbersFromPrintPageNumberRange(\r
115     const PP_PrintPageNumberRange_Dev* page_ranges,\r
116     uint32_t page_range_count) {\r
117   std::vector<uint32_t> page_numbers;\r
118   for (uint32_t index = 0; index < page_range_count; ++index) {\r
119     for (uint32_t page_number = page_ranges[index].first_page_number;\r
120          page_number <= page_ranges[index].last_page_number; ++page_number) {\r
121       page_numbers.push_back(page_number);\r
122     }\r
123   }\r
124   return page_numbers;\r
125 }\r
126 \r
127 #if defined(OS_LINUX)\r
128 \r
129 PP_Instance g_last_instance_id;\r
130 \r
131 struct PDFFontSubstitution {\r
132   const char* pdf_name;\r
133   const char* face;\r
134   bool bold;\r
135   bool italic;\r
136 };\r
137 \r
138 PP_BrowserFont_Trusted_Weight WeightToBrowserFontTrustedWeight(int weight) {\r
139   COMPILE_ASSERT(PP_BROWSERFONT_TRUSTED_WEIGHT_100 == 0,\r
140                  PP_BrowserFont_Trusted_Weight_Min);\r
141   COMPILE_ASSERT(PP_BROWSERFONT_TRUSTED_WEIGHT_900 == 8,\r
142                  PP_BrowserFont_Trusted_Weight_Max);\r
143   const int kMinimumWeight = 100;\r
144   const int kMaximumWeight = 900;\r
145   int normalized_weight =\r
146       std::min(std::max(weight, kMinimumWeight), kMaximumWeight);\r
147   normalized_weight = (normalized_weight / 100) - 1;\r
148   return static_cast<PP_BrowserFont_Trusted_Weight>(normalized_weight);\r
149 }\r
150 \r
151 // This list is for CPWL_FontMap::GetDefaultFontByCharset().\r
152 // We pretend to have these font natively and let the browser (or underlying\r
153 // fontconfig) to pick the proper font on the system.\r
154 void EnumFonts(struct _FPDF_SYSFONTINFO* sysfontinfo, void* mapper) {\r
155   FPDF_AddInstalledFont(mapper, "Arial", FXFONT_DEFAULT_CHARSET);\r
156 \r
157   int i = 0;\r
158   while (CPWL_FontMap::defaultTTFMap[i].charset != -1) {\r
159     FPDF_AddInstalledFont(mapper,\r
160                           CPWL_FontMap::defaultTTFMap[i].fontname,\r
161                           CPWL_FontMap::defaultTTFMap[i].charset);\r
162     ++i;\r
163   }\r
164 }\r
165 \r
166 const PDFFontSubstitution PDFFontSubstitutions[] = {\r
167     {"Courier", "Courier New", false, false},\r
168     {"Courier-Bold", "Courier New", true, false},\r
169     {"Courier-BoldOblique", "Courier New", true, true},\r
170     {"Courier-Oblique", "Courier New", false, true},\r
171     {"Helvetica", "Arial", false, false},\r
172     {"Helvetica-Bold", "Arial", true, false},\r
173     {"Helvetica-BoldOblique", "Arial", true, true},\r
174     {"Helvetica-Oblique", "Arial", false, true},\r
175     {"Times-Roman", "Times New Roman", false, false},\r
176     {"Times-Bold", "Times New Roman", true, false},\r
177     {"Times-BoldItalic", "Times New Roman", true, true},\r
178     {"Times-Italic", "Times New Roman", false, true},\r
179 \r
180     // MS P?(Mincho|Gothic) are the most notable fonts in Japanese PDF files\r
181     // without embedding the glyphs. Sometimes the font names are encoded\r
182     // in Japanese Windows's locale (CP932/Shift_JIS) without space.\r
183     // Most Linux systems don't have the exact font, but for outsourcing\r
184     // fontconfig to find substitutable font in the system, we pass ASCII\r
185     // font names to it.\r
186     {"MS-PGothic", "MS PGothic", false, false},\r
187     {"MS-Gothic", "MS Gothic", false, false},\r
188     {"MS-PMincho", "MS PMincho", false, false},\r
189     {"MS-Mincho", "MS Mincho", false, false},\r
190     // MS PGothic in Shift_JIS encoding.\r
191     {"\x82\x6C\x82\x72\x82\x6F\x83\x53\x83\x56\x83\x62\x83\x4E",\r
192      "MS PGothic", false, false},\r
193     // MS Gothic in Shift_JIS encoding.\r
194     {"\x82\x6C\x82\x72\x83\x53\x83\x56\x83\x62\x83\x4E",\r
195      "MS Gothic", false, false},\r
196     // MS PMincho in Shift_JIS encoding.\r
197     {"\x82\x6C\x82\x72\x82\x6F\x96\xBE\x92\xA9",\r
198      "MS PMincho", false, false},\r
199     // MS Mincho in Shift_JIS encoding.\r
200     {"\x82\x6C\x82\x72\x96\xBE\x92\xA9",\r
201      "MS Mincho", false, false},\r
202 };\r
203 \r
204 void* MapFont(struct _FPDF_SYSFONTINFO*, int weight, int italic,\r
205               int charset, int pitch_family, const char* face, int* exact) {\r
206   // Do not attempt to map fonts if pepper is not initialized (for privet local\r
207   // printing).\r
208   // TODO(noamsml): Real font substitution (http://crbug.com/391978)\r
209   if (!pp::Module::Get())\r
210     return NULL;\r
211 \r
212   pp::BrowserFontDescription description;\r
213 \r
214   // Pretend the system does not have the Symbol font to force a fallback to\r
215   // the built in Symbol font in CFX_FontMapper::FindSubstFont().\r
216   if (strcmp(face, "Symbol") == 0)\r
217     return NULL;\r
218 \r
219   if (pitch_family & FXFONT_FF_FIXEDPITCH) {\r
220     description.set_family(PP_BROWSERFONT_TRUSTED_FAMILY_MONOSPACE);\r
221   } else if (pitch_family & FXFONT_FF_ROMAN) {\r
222     description.set_family(PP_BROWSERFONT_TRUSTED_FAMILY_SERIF);\r
223   }\r
224 \r
225   // Map from the standard PDF fonts to TrueType font names.\r
226   size_t i;\r
227   for (i = 0; i < arraysize(PDFFontSubstitutions); ++i) {\r
228     if (strcmp(face, PDFFontSubstitutions[i].pdf_name) == 0) {\r
229       description.set_face(PDFFontSubstitutions[i].face);\r
230       if (PDFFontSubstitutions[i].bold)\r
231         description.set_weight(PP_BROWSERFONT_TRUSTED_WEIGHT_BOLD);\r
232       if (PDFFontSubstitutions[i].italic)\r
233         description.set_italic(true);\r
234       break;\r
235     }\r
236   }\r
237 \r
238   if (i == arraysize(PDFFontSubstitutions)) {\r
239     // TODO(kochi): Pass the face in UTF-8. If face is not encoded in UTF-8,\r
240     // convert to UTF-8 before passing.\r
241     description.set_face(face);\r
242 \r
243     description.set_weight(WeightToBrowserFontTrustedWeight(weight));\r
244     description.set_italic(italic > 0);\r
245   }\r
246 \r
247   if (!pp::PDF::IsAvailable()) {\r
248     NOTREACHED();\r
249     return NULL;\r
250   }\r
251 \r
252   PP_Resource font_resource = pp::PDF::GetFontFileWithFallback(\r
253       pp::InstanceHandle(g_last_instance_id),\r
254       &description.pp_font_description(),\r
255       static_cast<PP_PrivateFontCharset>(charset));\r
256   long res_id = font_resource;\r
257   return reinterpret_cast<void*>(res_id);\r
258 }\r
259 \r
260 unsigned long GetFontData(struct _FPDF_SYSFONTINFO*, void* font_id,\r
261                           unsigned int table, unsigned char* buffer,\r
262                           unsigned long buf_size) {\r
263   if (!pp::PDF::IsAvailable()) {\r
264     NOTREACHED();\r
265     return 0;\r
266   }\r
267 \r
268   uint32_t size = buf_size;\r
269   long res_id = reinterpret_cast<long>(font_id);\r
270   if (!pp::PDF::GetFontTableForPrivateFontFile(res_id, table, buffer, &size))\r
271     return 0;\r
272   return size;\r
273 }\r
274 \r
275 void DeleteFont(struct _FPDF_SYSFONTINFO*, void* font_id) {\r
276   long res_id = reinterpret_cast<long>(font_id);\r
277   pp::Module::Get()->core()->ReleaseResource(res_id);\r
278 }\r
279 \r
280 FPDF_SYSFONTINFO g_font_info = {\r
281   1,\r
282   0,\r
283   EnumFonts,\r
284   MapFont,\r
285   0,\r
286   GetFontData,\r
287   0,\r
288   0,\r
289   DeleteFont\r
290 };\r
291 #endif  // defined(OS_LINUX)\r
292 \r
293 void OOM_Handler(_OOM_INFO*) {\r
294   // Kill the process.  This is important for security, since the code doesn't\r
295   // NULL-check many memory allocations.  If a malloc fails, returns NULL, and\r
296   // the buffer is then used, it provides a handy mapping of memory starting at\r
297   // address 0 for an attacker to utilize.\r
298   abort();\r
299 }\r
300 \r
301 OOM_INFO g_oom_info = {\r
302   1,\r
303   OOM_Handler\r
304 };\r
305 \r
306 PDFiumEngine* g_engine_for_unsupported;\r
307 \r
308 void Unsupported_Handler(UNSUPPORT_INFO*, int type) {\r
309   if (!g_engine_for_unsupported) {\r
310     NOTREACHED();\r
311     return;\r
312   }\r
313 \r
314   g_engine_for_unsupported->UnsupportedFeature(type);\r
315 }\r
316 \r
317 UNSUPPORT_INFO g_unsuppored_info = {\r
318   1,\r
319   Unsupported_Handler\r
320 };\r
321 \r
322 // Set the destination page size and content area in points based on source\r
323 // page rotation and orientation.\r
324 //\r
325 // |rotated| True if source page is rotated 90 degree or 270 degree.\r
326 // |is_src_page_landscape| is true if the source page orientation is landscape.\r
327 // |page_size| has the actual destination page size in points.\r
328 // |content_rect| has the actual destination page printable area values in\r
329 // points.\r
330 void SetPageSizeAndContentRect(bool rotated,\r
331                                bool is_src_page_landscape,\r
332                                pp::Size* page_size,\r
333                                pp::Rect* content_rect) {\r
334   bool is_dst_page_landscape = page_size->width() > page_size->height();\r
335   bool page_orientation_mismatched = is_src_page_landscape !=\r
336                                      is_dst_page_landscape;\r
337   bool rotate_dst_page = rotated ^ page_orientation_mismatched;\r
338   if (rotate_dst_page) {\r
339     page_size->SetSize(page_size->height(), page_size->width());\r
340     content_rect->SetRect(content_rect->y(), content_rect->x(),\r
341                           content_rect->height(), content_rect->width());\r
342   }\r
343 }\r
344 \r
345 // Calculate the scale factor between |content_rect| and a page of size\r
346 // |src_width| x |src_height|.\r
347 //\r
348 // |scale_to_fit| is true, if we need to calculate the scale factor.\r
349 // |content_rect| specifies the printable area of the destination page, with\r
350 // origin at left-bottom. Values are in points.\r
351 // |src_width| specifies the source page width in points.\r
352 // |src_height| specifies the source page height in points.\r
353 // |rotated| True if source page is rotated 90 degree or 270 degree.\r
354 double CalculateScaleFactor(bool scale_to_fit,\r
355                             const pp::Rect& content_rect,\r
356                             double src_width, double src_height, bool rotated) {\r
357   if (!scale_to_fit || src_width == 0 || src_height == 0)\r
358     return 1.0;\r
359 \r
360   double actual_source_page_width = rotated ? src_height : src_width;\r
361   double actual_source_page_height = rotated ? src_width : src_height;\r
362   double ratio_x = static_cast<double>(content_rect.width()) /\r
363                    actual_source_page_width;\r
364   double ratio_y = static_cast<double>(content_rect.height()) /\r
365                    actual_source_page_height;\r
366   return std::min(ratio_x, ratio_y);\r
367 }\r
368 \r
369 // Compute source clip box boundaries based on the crop box / media box of\r
370 // source page and scale factor.\r
371 //\r
372 // |page| Handle to the source page. Returned by FPDF_LoadPage function.\r
373 // |scale_factor| specifies the scale factor that should be applied to source\r
374 // clip box boundaries.\r
375 // |rotated| True if source page is rotated 90 degree or 270 degree.\r
376 // |clip_box| out param to hold the computed source clip box values.\r
377 void CalculateClipBoxBoundary(FPDF_PAGE page, double scale_factor, bool rotated,\r
378                               ClipBox* clip_box) {\r
379   if (!FPDFPage_GetCropBox(page, &clip_box->left, &clip_box->bottom,\r
380                            &clip_box->right, &clip_box->top)) {\r
381     if (!FPDFPage_GetMediaBox(page, &clip_box->left, &clip_box->bottom,\r
382                               &clip_box->right, &clip_box->top)) {\r
383       // Make the default size to be letter size (8.5" X 11"). We are just\r
384       // following the PDFium way of handling these corner cases. PDFium always\r
385       // consider US-Letter as the default page size.\r
386       float paper_width = 612;\r
387       float paper_height = 792;\r
388       clip_box->left = 0;\r
389       clip_box->bottom = 0;\r
390       clip_box->right = rotated ? paper_height : paper_width;\r
391       clip_box->top = rotated ? paper_width : paper_height;\r
392     }\r
393   }\r
394   clip_box->left *= scale_factor;\r
395   clip_box->right *= scale_factor;\r
396   clip_box->bottom *= scale_factor;\r
397   clip_box->top *= scale_factor;\r
398 }\r
399 \r
400 // Calculate the clip box translation offset for a page that does need to be\r
401 // scaled. All parameters are in points.\r
402 //\r
403 // |content_rect| specifies the printable area of the destination page, with\r
404 // origin at left-bottom.\r
405 // |source_clip_box| specifies the source clip box positions, relative to\r
406 // origin at left-bottom.\r
407 // |offset_x| and |offset_y| will contain the final translation offsets for the\r
408 // source clip box, relative to origin at left-bottom.\r
409 void CalculateScaledClipBoxOffset(const pp::Rect& content_rect,\r
410                                   const ClipBox& source_clip_box,\r
411                                   double* offset_x, double* offset_y) {\r
412   const float clip_box_width = source_clip_box.right - source_clip_box.left;\r
413   const float clip_box_height = source_clip_box.top - source_clip_box.bottom;\r
414 \r
415   // Center the intended clip region to real clip region.\r
416   *offset_x = (content_rect.width() - clip_box_width) / 2 + content_rect.x() -\r
417               source_clip_box.left;\r
418   *offset_y = (content_rect.height() - clip_box_height) / 2 + content_rect.y() -\r
419               source_clip_box.bottom;\r
420 }\r
421 \r
422 // Calculate the clip box offset for a page that does not need to be scaled.\r
423 // All parameters are in points.\r
424 //\r
425 // |content_rect| specifies the printable area of the destination page, with\r
426 // origin at left-bottom.\r
427 // |rotation| specifies the source page rotation values which are N / 90\r
428 // degrees.\r
429 // |page_width| specifies the screen destination page width.\r
430 // |page_height| specifies the screen destination page height.\r
431 // |source_clip_box| specifies the source clip box positions, relative to origin\r
432 // at left-bottom.\r
433 // |offset_x| and |offset_y| will contain the final translation offsets for the\r
434 // source clip box, relative to origin at left-bottom.\r
435 void CalculateNonScaledClipBoxOffset(const pp::Rect& content_rect, int rotation,\r
436                                      int page_width, int page_height,\r
437                                      const ClipBox& source_clip_box,\r
438                                      double* offset_x, double* offset_y) {\r
439   // Align the intended clip region to left-top corner of real clip region.\r
440   switch (rotation) {\r
441     case 0:\r
442       *offset_x = -1 * source_clip_box.left;\r
443       *offset_y = page_height - source_clip_box.top;\r
444       break;\r
445     case 1:\r
446       *offset_x = 0;\r
447       *offset_y = -1 * source_clip_box.bottom;\r
448       break;\r
449     case 2:\r
450       *offset_x = page_width - source_clip_box.right;\r
451       *offset_y = 0;\r
452       break;\r
453     case 3:\r
454       *offset_x = page_height - source_clip_box.right;\r
455       *offset_y = page_width - source_clip_box.top;\r
456       break;\r
457     default:\r
458       NOTREACHED();\r
459       break;\r
460   }\r
461 }\r
462 \r
463 // This formats a string with special 0xfffe end-of-line hyphens the same way\r
464 // as Adobe Reader. When a hyphen is encountered, the next non-CR/LF whitespace\r
465 // becomes CR+LF and the hyphen is erased. If there is no whitespace between\r
466 // two hyphens, the latter hyphen is erased and ignored.\r
467 void FormatStringWithHyphens(base::string16* text) {\r
468   // First pass marks all the hyphen positions.\r
469   struct HyphenPosition {\r
470     HyphenPosition() : position(0), next_whitespace_position(0) {}\r
471     size_t position;\r
472     size_t next_whitespace_position;  // 0 for none\r
473   };\r
474   std::vector<HyphenPosition> hyphen_positions;\r
475   HyphenPosition current_hyphen_position;\r
476   bool current_hyphen_position_is_valid = false;\r
477   const base::char16 kPdfiumHyphenEOL = 0xfffe;\r
478 \r
479   for (size_t i = 0; i < text->size(); ++i) {\r
480     const base::char16& current_char = (*text)[i];\r
481     if (current_char == kPdfiumHyphenEOL) {\r
482       if (current_hyphen_position_is_valid)\r
483         hyphen_positions.push_back(current_hyphen_position);\r
484       current_hyphen_position = HyphenPosition();\r
485       current_hyphen_position.position = i;\r
486       current_hyphen_position_is_valid = true;\r
487     } else if (IsWhitespace(current_char)) {\r
488       if (current_hyphen_position_is_valid) {\r
489         if (current_char != L'\r' && current_char != L'\n')\r
490           current_hyphen_position.next_whitespace_position = i;\r
491         hyphen_positions.push_back(current_hyphen_position);\r
492         current_hyphen_position_is_valid = false;\r
493       }\r
494     }\r
495   }\r
496   if (current_hyphen_position_is_valid)\r
497     hyphen_positions.push_back(current_hyphen_position);\r
498 \r
499   // With all the hyphen positions, do the search and replace.\r
500   while (!hyphen_positions.empty()) {\r
501     static const base::char16 kCr[] = {L'\r', L'\0'};\r
502     const HyphenPosition& position = hyphen_positions.back();\r
503     if (position.next_whitespace_position != 0) {\r
504       (*text)[position.next_whitespace_position] = L'\n';\r
505       text->insert(position.next_whitespace_position, kCr);\r
506     }\r
507     text->erase(position.position, 1);\r
508     hyphen_positions.pop_back();\r
509   }\r
510 \r
511   // Adobe Reader also get rid of trailing spaces right before a CRLF.\r
512   static const base::char16 kSpaceCrCn[] = {L' ', L'\r', L'\n', L'\0'};\r
513   static const base::char16 kCrCn[] = {L'\r', L'\n', L'\0'};\r
514   ReplaceSubstringsAfterOffset(text, 0, kSpaceCrCn, kCrCn);\r
515 }\r
516 \r
517 // Replace CR/LF with just LF on POSIX.\r
518 void FormatStringForOS(base::string16* text) {\r
519 #if defined(OS_POSIX)\r
520   static const base::char16 kCr[] = {L'\r', L'\0'};\r
521   static const base::char16 kBlank[] = {L'\0'};\r
522   base::ReplaceChars(*text, kCr, kBlank, text);\r
523 #elif defined(OS_WIN)\r
524   // Do nothing\r
525 #else\r
526   NOTIMPLEMENTED();\r
527 #endif\r
528 }\r
529 \r
530 }  // namespace\r
531 \r
532 bool InitializeSDK(void* data) {\r
533   FPDF_InitLibrary(data);\r
534 \r
535 #if defined(OS_LINUX)\r
536   // Font loading doesn't work in the renderer sandbox in Linux.\r
537   FPDF_SetSystemFontInfo(&g_font_info);\r
538 #endif\r
539 \r
540   FSDK_SetOOMHandler(&g_oom_info);\r
541   FSDK_SetUnSpObjProcessHandler(&g_unsuppored_info);\r
542 \r
543   return true;\r
544 }\r
545 \r
546 void ShutdownSDK() {\r
547   FPDF_DestroyLibrary();\r
548 }\r
549 \r
550 PDFEngine* PDFEngine::Create(PDFEngine::Client* client) {\r
551   return new PDFiumEngine(client);\r
552 }\r
553 \r
554 PDFiumEngine::PDFiumEngine(PDFEngine::Client* client)\r
555     : client_(client),\r
556       current_zoom_(1.0),\r
557       current_rotation_(0),\r
558       doc_loader_(this),\r
559       password_tries_remaining_(0),\r
560       doc_(NULL),\r
561       form_(NULL),\r
562       defer_page_unload_(false),\r
563       selecting_(false),\r
564       mouse_down_state_(PDFiumPage::NONSELECTABLE_AREA,\r
565                         PDFiumPage::LinkTarget()),\r
566       next_page_to_search_(-1),\r
567       last_page_to_search_(-1),\r
568       last_character_index_to_search_(-1),\r
569       current_find_index_(-1),\r
570       resume_find_index_(-1),\r
571       permissions_(0),\r
572       fpdf_availability_(NULL),\r
573       next_timer_id_(0),\r
574       last_page_mouse_down_(-1),\r
575       first_visible_page_(-1),\r
576       most_visible_page_(-1),\r
577       called_do_document_action_(false),\r
578       render_grayscale_(false),\r
579       progressive_paint_timeout_(0),\r
580       getting_password_(false) {\r
581   find_factory_.Initialize(this);\r
582   password_factory_.Initialize(this);\r
583 \r
584   file_access_.m_FileLen = 0;\r
585   file_access_.m_GetBlock = &GetBlock;\r
586   file_access_.m_Param = &doc_loader_;\r
587 \r
588   file_availability_.version = 1;\r
589   file_availability_.IsDataAvail = &IsDataAvail;\r
590   file_availability_.loader = &doc_loader_;\r
591 \r
592   download_hints_.version = 1;\r
593   download_hints_.AddSegment = &AddSegment;\r
594   download_hints_.loader = &doc_loader_;\r
595 \r
596   // Initialize FPDF_FORMFILLINFO member variables.  Deriving from this struct\r
597   // allows the static callbacks to be able to cast the FPDF_FORMFILLINFO in\r
598   // callbacks to ourself instead of maintaining a map of them to\r
599   // PDFiumEngine.\r
600   FPDF_FORMFILLINFO::version = 1;\r
601   FPDF_FORMFILLINFO::m_pJsPlatform = this;\r
602   FPDF_FORMFILLINFO::Release = NULL;\r
603   FPDF_FORMFILLINFO::FFI_Invalidate = Form_Invalidate;\r
604   FPDF_FORMFILLINFO::FFI_OutputSelectedRect = Form_OutputSelectedRect;\r
605   FPDF_FORMFILLINFO::FFI_SetCursor = Form_SetCursor;\r
606   FPDF_FORMFILLINFO::FFI_SetTimer = Form_SetTimer;\r
607   FPDF_FORMFILLINFO::FFI_KillTimer = Form_KillTimer;\r
608   FPDF_FORMFILLINFO::FFI_GetLocalTime = Form_GetLocalTime;\r
609   FPDF_FORMFILLINFO::FFI_OnChange = Form_OnChange;\r
610   FPDF_FORMFILLINFO::FFI_GetPage = Form_GetPage;\r
611   FPDF_FORMFILLINFO::FFI_GetCurrentPage = Form_GetCurrentPage;\r
612   FPDF_FORMFILLINFO::FFI_GetRotation = Form_GetRotation;\r
613   FPDF_FORMFILLINFO::FFI_ExecuteNamedAction = Form_ExecuteNamedAction;\r
614   FPDF_FORMFILLINFO::FFI_SetTextFieldFocus = Form_SetTextFieldFocus;\r
615   FPDF_FORMFILLINFO::FFI_DoURIAction = Form_DoURIAction;\r
616   FPDF_FORMFILLINFO::FFI_DoGoToAction = Form_DoGoToAction;\r
617 #ifdef _TEST_XFA\r
618   FPDF_FORMFILLINFO::FFI_EmailTo = Form_EmailTo;\r
619   FPDF_FORMFILLINFO::FFI_DisplayCaret = Form_DisplayCaret;\r
620   //FPDF_FORMFILLINFO::FFI_GetCurDocumentIndex = Form_GetCurDocumentIndex;\r
621   //FPDF_FORMFILLINFO::FFI_GetDocumentCount = Form_GetDocumentCount;\r
622   FPDF_FORMFILLINFO::FFI_SetCurrentPage = Form_SetCurrentPage;\r
623   FPDF_FORMFILLINFO::FFI_GetCurrentPageIndex = Form_GetCurrentPageIndex;\r
624   FPDF_FORMFILLINFO::FFI_GetPageViewRect = Form_GetPageViewRect;\r
625   FPDF_FORMFILLINFO::FFI_GetPlatform = Form_GetPlatform;\r
626   FPDF_FORMFILLINFO::FFI_PopupMenu = Form_PopupMenu;\r
627   FPDF_FORMFILLINFO::FFI_PostRequestURL = Form_PostRequestURL;\r
628   FPDF_FORMFILLINFO::FFI_PutRequestURL = Form_PutRequestURL;\r
629 //  FPDF_FORMFILLINFO::FFI_ShowFileDialog = Form_ShowFileDialog;\r
630   FPDF_FORMFILLINFO::FFI_UploadTo = Form_UploadTo;\r
631   FPDF_FORMFILLINFO::FFI_DownloadFromURL = Form_DownloadFromURL;\r
632  // FPDF_FORMFILLINFO::FFI_GetFilePath = MyForm_GetFilePath;\r
633   FPDF_FORMFILLINFO::FFI_OpenFile = Form_OpenFile;\r
634   FPDF_FORMFILLINFO::FFI_GotoURL = Form_GotoURL;\r
635   FPDF_FORMFILLINFO::FFI_GetLanguage = Form_GetLanguage;\r
636 #endif // _TEST_XFA\r
637   IPDF_JSPLATFORM::version = 1;\r
638   IPDF_JSPLATFORM::app_alert = Form_Alert;\r
639   IPDF_JSPLATFORM::app_beep = Form_Beep;\r
640   IPDF_JSPLATFORM::app_response = Form_Response;\r
641   IPDF_JSPLATFORM::Doc_getFilePath = Form_GetFilePath;\r
642   IPDF_JSPLATFORM::Doc_mail = Form_Mail;\r
643   IPDF_JSPLATFORM::Doc_print = Form_Print;\r
644   IPDF_JSPLATFORM::Doc_submitForm = Form_SubmitForm;\r
645   IPDF_JSPLATFORM::Doc_gotoPage = Form_GotoPage;\r
646   IPDF_JSPLATFORM::Field_browse = Form_Browse;\r
647 \r
648   IFSDK_PAUSE::version = 1;\r
649   IFSDK_PAUSE::user = NULL;\r
650   IFSDK_PAUSE::NeedToPauseNow = Pause_NeedToPauseNow;\r
651 }\r
652 \r
653 PDFiumEngine::~PDFiumEngine() {\r
654   for (size_t i = 0; i < pages_.size(); ++i)\r
655     pages_[i]->Unload();\r
656 \r
657   if (doc_) {\r
658     if (form_) {\r
659       FORM_DoDocumentAAction(form_, FPDFDOC_AACTION_WC);\r
660     }\r
661     FPDF_CloseDocument(doc_);\r
662         if (form_) {\r
663                 FPDFDOC_ExitFormFillEnviroument(form_);\r
664         }\r
665   }\r
666 \r
667   if (fpdf_availability_)\r
668     FPDFAvail_Destroy(fpdf_availability_);\r
669 \r
670   STLDeleteElements(&pages_);\r
671 }\r
672 \r
673 #ifdef _TEST_XFA\r
674 \r
675 typedef struct _FPDF_FILE {\r
676         FPDF_FILEHANDLER fileHandler;\r
677         FILE* file;\r
678 }FPDF_FILE;\r
679 \r
680 \r
681 void            Sample_Release(FPDF_LPVOID clientData) {\r
682         if (!clientData) return;\r
683 \r
684         fclose(((FPDF_FILE*)clientData)->file);\r
685         delete ((FPDF_FILE*)clientData);\r
686 }\r
687 \r
688 FPDF_DWORD      Sample_GetSize(FPDF_LPVOID clientData) {\r
689         if (!clientData) return 0;\r
690 \r
691         long curPos = ftell(((FPDF_FILE*)clientData)->file);\r
692         fseek(((FPDF_FILE*)clientData)->file, 0, SEEK_END);\r
693         long size = ftell(((FPDF_FILE*)clientData)->file);\r
694         fseek(((FPDF_FILE*)clientData)->file, curPos, SEEK_SET);\r
695 \r
696         return (FPDF_DWORD)size;\r
697 }\r
698 \r
699 FPDF_RESULT     Sample_ReadBlock(FPDF_LPVOID clientData, FPDF_DWORD offset, FPDF_LPVOID buffer, FPDF_DWORD size) {\r
700         if (!clientData) return -1;\r
701 \r
702         fseek(((FPDF_FILE*)clientData)->file, (long)offset, SEEK_SET);\r
703         size_t readSize = fread(buffer, 1, size, ((FPDF_FILE*)clientData)->file);\r
704         return readSize == size ? 0 : -1;\r
705 }\r
706 \r
707 FPDF_RESULT     Sample_WriteBlock(FPDF_LPVOID clientData, FPDF_DWORD offset, FPDF_LPCVOID buffer, FPDF_DWORD size) {\r
708         if (!clientData) return -1;\r
709 \r
710         fseek(((FPDF_FILE*)clientData)->file, (long)offset, SEEK_SET);\r
711         //Write data\r
712         size_t writeSize = fwrite(buffer, 1, size, ((FPDF_FILE*)clientData)->file);\r
713         return writeSize == size ? 0 : -1;\r
714 }\r
715 \r
716 FPDF_RESULT     Sample_Flush(FPDF_LPVOID clientData) {\r
717         if (!clientData) return -1;\r
718 \r
719         //Flush file\r
720         fflush(((FPDF_FILE*)clientData)->file);\r
721 \r
722         return 0;\r
723 }\r
724 \r
725 FPDF_RESULT     Sample_Truncate(FPDF_LPVOID clientData, FPDF_DWORD size) {\r
726         return 0;\r
727 }\r
728 \r
729 \r
730 void PDFiumEngine::Form_EmailTo(FPDF_FORMFILLINFO* pThis,\r
731         FPDF_FILEHANDLER* fileHandler,\r
732         FPDF_WIDESTRING to,\r
733         FPDF_WIDESTRING subject,\r
734         FPDF_WIDESTRING cc,\r
735         FPDF_WIDESTRING bcc,\r
736         FPDF_WIDESTRING message) {\r
737         std::string to_str =\r
738                 base::UTF16ToUTF8(reinterpret_cast<const base::char16*>(to));\r
739         std::string subject_str =\r
740                 base::UTF16ToUTF8(reinterpret_cast<const base::char16*>(subject));\r
741         std::string cc_str =\r
742                 base::UTF16ToUTF8(reinterpret_cast<const base::char16*>(cc));\r
743         std::string bcc_str =\r
744                 base::UTF16ToUTF8(reinterpret_cast<const base::char16*>(bcc));\r
745         std::string message_str =\r
746                 base::UTF16ToUTF8(reinterpret_cast<const base::char16*>(message));\r
747 \r
748         PDFiumEngine* engine = static_cast<PDFiumEngine*>(pThis);\r
749         engine->client_->Email(to_str, cc_str, bcc_str, subject_str, message_str);\r
750 }\r
751 \r
752 void PDFiumEngine::Form_DisplayCaret(FPDF_FORMFILLINFO* pThis,\r
753                                            FPDF_PAGE page, FPDF_BOOL bVisible, \r
754                                            double left, double top, double right, double bottom) {\r
755         PDFiumEngine* engine = static_cast<PDFiumEngine*>(pThis);\r
756         engine->client_->UpdateCursor(PP_CURSORTYPE_IBEAM);\r
757         std::vector<pp::Rect> tickmarks;\r
758         pp::Rect rect(left, top, right, bottom);\r
759         tickmarks.push_back(rect);\r
760         engine->client_->UpdateTickMarks(tickmarks);\r
761 }\r
762 \r
763 //int PDFiumEngine::Form_GetCurDocumentIndex(FPDF_FORMFILLINFO* pThis) {\r
764 //      PDFiumEngine* engine = static_cast<PDFiumEngine*>(pThis);\r
765 //      engine->client_->RunJSCmd("alert(\"GetCurDocumentIndex\")");\r
766 //      return 0;\r
767 //}\r
768 //\r
769 //int PDFiumEngine::Form_GetDocumentCount(FPDF_FORMFILLINFO* pThis) {\r
770 //      PDFiumEngine* engine = static_cast<PDFiumEngine*>(pThis);\r
771 //      engine->client_->RunJSCmd("alert(\"GetCurDocumentCount\")");\r
772 //      return 0;\r
773 //}\r
774 \r
775 void PDFiumEngine::Form_SetCurrentPage(FPDF_FORMFILLINFO* pThis, FPDF_DOCUMENT document, int iCurPage) {\r
776         PDFiumEngine* engine = static_cast<PDFiumEngine*>(pThis);\r
777         pp::Rect pageViewRect = engine->GetPageContentsRect(iCurPage);\r
778         engine->ScrolledToYPosition(pageViewRect.height());\r
779         pp::Point pos(1, pageViewRect.height());\r
780         engine->SetScrollPosition(pos);\r
781 }\r
782 \r
783 int PDFiumEngine::Form_GetCurrentPageIndex(FPDF_FORMFILLINFO* pThis, FPDF_DOCUMENT document) {\r
784         //int pageCount = FPDF_GetPageCount(document);\r
785         int pageIndex = -1;\r
786         PDFiumEngine* engine = static_cast<PDFiumEngine*>(pThis);\r
787         pageIndex = engine->GetMostVisiblePage();\r
788         return pageIndex;\r
789 }\r
790 \r
791 void PDFiumEngine::Form_GetPageViewRect(FPDF_FORMFILLINFO* pThis,\r
792                                                   FPDF_PAGE page, \r
793                                                   double* left, double* top, double* right, double* bottom) {\r
794         PDFiumEngine* engine = static_cast<PDFiumEngine*>(pThis);\r
795         int page_index = engine->GetMostVisiblePage();\r
796         pp::Rect pageViewRect = engine->GetPageContentsRect(page_index);\r
797         \r
798         *left = pageViewRect.x();\r
799         *right = pageViewRect.width() + pageViewRect.x();\r
800         *top = pageViewRect.y();\r
801         *bottom = pageViewRect.height();\r
802 \r
803         std::string javascript = "alert(\"PageViewRect:" \r
804                 + base::DoubleToString(*left) + ","\r
805                 + base::DoubleToString(*right) + ","\r
806                 + base::DoubleToString(*top) + ","\r
807                 + base::DoubleToString(*bottom) + ","\r
808                 + "\")";\r
809  \r
810 }\r
811 \r
812 int PDFiumEngine::Form_GetPlatform(FPDF_FORMFILLINFO* pThis,\r
813                                           void* platform,\r
814                                           int length) {\r
815         int platform_flag = -1;\r
816 #if defined(WIN32)\r
817         platform_flag = 0;\r
818 #elif defined(__linux__)\r
819         platform_flag = 1;\r
820 #else\r
821         platform_flag = 2;\r
822 #endif\r
823         std::string javascript = "alert(\"Platform:" \r
824                 + base::DoubleToString(platform_flag)\r
825                 + "\")";\r
826         //platform = new char[3];\r
827         //char tem[10] = "WIN";\r
828         //strncpy((char*)platform, tem, 3);\r
829 \r
830         return 3;\r
831 }\r
832 \r
833 FPDF_BOOL PDFiumEngine::Form_PopupMenu(FPDF_FORMFILLINFO* pThis,\r
834                                         FPDF_PAGE page, \r
835                                         FPDF_WIDGET hWidget, \r
836                                         int menuFlag, float x, float y) {\r
837         return false;\r
838 }\r
839 \r
840 FPDF_BOOL PDFiumEngine::Form_PostRequestURL(FPDF_FORMFILLINFO* pThis, FPDF_WIDESTRING wsURL,\r
841                                                  FPDF_WIDESTRING wsData, FPDF_WIDESTRING wsContentType,\r
842                                                  FPDF_WIDESTRING wsEncode, FPDF_WIDESTRING wsHeader, FPDF_BSTR* respone) {\r
843         std::string url_str =\r
844                 base::UTF16ToUTF8(reinterpret_cast<const base::char16*>(wsURL));\r
845         std::string data_str =\r
846                 base::UTF16ToUTF8(reinterpret_cast<const base::char16*>(wsData));\r
847         std::string content_type_str =\r
848                 base::UTF16ToUTF8(reinterpret_cast<const base::char16*>(wsContentType));\r
849         std::string encode_str =\r
850                 base::UTF16ToUTF8(reinterpret_cast<const base::char16*>(wsEncode));\r
851         std::string header_str =\r
852                 base::UTF16ToUTF8(reinterpret_cast<const base::char16*>(wsHeader));\r
853 \r
854         std::string javascript = "alert(\"Post:"\r
855                 + url_str + "," + data_str + "," + content_type_str + ","\r
856                 + encode_str + "," + header_str \r
857                 + "\")";\r
858         return true;\r
859 }\r
860 \r
861 FPDF_BOOL PDFiumEngine::Form_PutRequestURL(FPDF_FORMFILLINFO* pThis,\r
862                                                 FPDF_WIDESTRING wsURL, FPDF_WIDESTRING wsData, FPDF_WIDESTRING wsEncode) {\r
863         std::string url_str =\r
864                 base::UTF16ToUTF8(reinterpret_cast<const base::char16*>(wsURL));\r
865         std::string data_str =\r
866                 base::UTF16ToUTF8(reinterpret_cast<const base::char16*>(wsData));\r
867         std::string encode_str =\r
868                 base::UTF16ToUTF8(reinterpret_cast<const base::char16*>(wsEncode));\r
869 \r
870         std::string javascript = "alert(\"Put:"\r
871                 + url_str + "," + data_str + "," + encode_str \r
872                 + "\")";\r
873 \r
874         return true;\r
875 }\r
876 \r
877 //FPDF_BOOL PDFiumEngine::Form_ShowFileDialog(FPDF_FORMFILLINFO* pThis, FPDF_WIDESTRING wsTitle, FPDF_WIDESTRING wsFilter, FPDF_BOOL isOpen, FPDF_STRINGHANDLE pathArr) {\r
878 //      int tem = 1;\r
879 //      tem++;\r
880 //      return false;\r
881 //}\r
882 \r
883 void PDFiumEngine::Form_UploadTo(FPDF_FORMFILLINFO* pThis, FPDF_FILEHANDLER* fileHandler, int fileFlag, FPDF_WIDESTRING uploadTo) {\r
884         std::string to_str =\r
885                 base::UTF16ToUTF8(reinterpret_cast<const base::char16*>(uploadTo));\r
886 \r
887 }\r
888 \r
889 FPDF_LPFILEHANDLER PDFiumEngine::Form_DownloadFromURL(FPDF_FORMFILLINFO* pThis, FPDF_WIDESTRING URL) {\r
890         std::string url_str =\r
891                 base::UTF16ToUTF8(reinterpret_cast<const base::char16*>(URL));\r
892 \r
893 \r
894         // Get URL data...\r
895         FILE* file = fopen(FXQA_TESTFILE("downloadtest.tem"), "w");\r
896         FPDF_FILE* pFileHander = new FPDF_FILE;\r
897         pFileHander->file = file;\r
898         pFileHander->fileHandler.clientData = pFileHander;\r
899         pFileHander->fileHandler.Flush = Sample_Flush;\r
900         pFileHander->fileHandler.GetSize = Sample_GetSize;\r
901         pFileHander->fileHandler.ReadBlock = Sample_ReadBlock;\r
902         pFileHander->fileHandler.Release = Sample_Release;\r
903         pFileHander->fileHandler.Truncate = Sample_Truncate;\r
904         pFileHander->fileHandler.WriteBlock = Sample_WriteBlock;\r
905 \r
906         return &pFileHander->fileHandler;\r
907 }\r
908 \r
909 //FPDF_BOOL PDFiumEngine::MyForm_GetFilePath(FPDF_FORMFILLINFO* pThis, FPDF_FILEHANDLER* pFileHandler, void* filePath, int length) {\r
910 //      //std::string filePath = engine->client_->FileOpen(fileFlag);\r
911 //      if (filePath == NULL) {\r
912 //              std::string javascript = "alert(\"GetFilePath:NULL\")";\r
913 //              PDFiumEngine* engine = static_cast<PDFiumEngine*>(pThis);\r
914 //              engine->client_->RunJSCmd(javascript);\r
915 //              return false;\r
916 //      }\r
917 //      std::string filePath_str = (char*)filePath;\r
918 //\r
919 //      std::string javascript = "alert(\"GetFilePath:" + filePath_str + "\")";\r
920 //      PDFiumEngine* engine = static_cast<PDFiumEngine*>(pThis);\r
921 //      engine->client_->RunJSCmd(javascript);\r
922 //\r
923 //      FILE* file = fopen(FXQA_TESTFILE("tem.xdp"), "w");\r
924 //      FPDF_FILE* pFileHander = new FPDF_FILE;\r
925 //      pFileHander->file = file;\r
926 //      pFileHander->fileHandler.clientData = pFileHander;\r
927 //      pFileHander->fileHandler.Flush = Sample_Flush;\r
928 //      pFileHander->fileHandler.GetSize = Sample_GetSize;\r
929 //      pFileHander->fileHandler.ReadBlock = Sample_ReadBlock;\r
930 //      pFileHander->fileHandler.Release = Sample_Release;\r
931 //      pFileHander->fileHandler.Truncate = Sample_Truncate;\r
932 //      pFileHander->fileHandler.WriteBlock = Sample_WriteBlock;\r
933 //\r
934 //      pFileHandler = &pFileHander->fileHandler;\r
935 //\r
936 //      return true;\r
937 //}\r
938 \r
939 FPDF_FILEHANDLER* PDFiumEngine::Form_OpenFile(FPDF_FORMFILLINFO* pThis, int fileFlag, FPDF_WIDESTRING wsURL, const char* mode) {\r
940         std::string url_str = "NULL";\r
941         if (wsURL == NULL) {\r
942                 url_str = "NULL";\r
943         }\r
944         else {\r
945                 url_str =\r
946                         base::UTF16ToUTF8(reinterpret_cast<const base::char16*>(wsURL));\r
947         }\r
948         if (strncmp(mode, "wb", 2) == 0) {\r
949 \r
950                 FILE* file = fopen(FXQA_TESTFILE("tem.txt"), mode);\r
951                 FPDF_FILE* pFileHander = new FPDF_FILE;\r
952                 pFileHander->file = file;\r
953                 pFileHander->fileHandler.clientData = pFileHander;\r
954                 pFileHander->fileHandler.Flush = Sample_Flush;\r
955                 pFileHander->fileHandler.GetSize = Sample_GetSize;\r
956                 pFileHander->fileHandler.ReadBlock = Sample_ReadBlock;\r
957                 pFileHander->fileHandler.Release = Sample_Release;\r
958                 pFileHander->fileHandler.Truncate = Sample_Truncate;\r
959                 pFileHander->fileHandler.WriteBlock = Sample_WriteBlock;\r
960                 return &pFileHander->fileHandler;\r
961         }\r
962         else {\r
963                 url_str = base::UTF16ToUTF8(reinterpret_cast<const base::char16*>(wsURL));\r
964         }\r
965         return NULL;\r
966 }\r
967 \r
968 \r
969 void PDFiumEngine::Form_GotoURL(FPDF_FORMFILLINFO* pThis, FPDF_DOCUMENT document, FPDF_WIDESTRING wsURL) {\r
970         std::string url_str =\r
971                 base::UTF16ToUTF8(reinterpret_cast<const base::char16*>(wsURL));\r
972         int pageCount = FPDF_GetPageCount(document);\r
973 }\r
974 \r
975 int PDFiumEngine::Form_GetLanguage(FPDF_FORMFILLINFO* pThis, void* language, int length) {\r
976         return 0;\r
977 }\r
978 \r
979 #endif // _TEST_XFA\r
980 \r
981 int PDFiumEngine::GetBlock(void* param, unsigned long position,\r
982                            unsigned char* buffer, unsigned long size) {\r
983   DocumentLoader* loader = static_cast<DocumentLoader*>(param);\r
984   return loader->GetBlock(position, size, buffer);\r
985 }\r
986 \r
987 bool PDFiumEngine::IsDataAvail(FX_FILEAVAIL* param,\r
988                                size_t offset, size_t size) {\r
989   PDFiumEngine::FileAvail* file_avail =\r
990       static_cast<PDFiumEngine::FileAvail*>(param);\r
991   return file_avail->loader->IsDataAvailable(offset, size);\r
992 }\r
993 \r
994 void PDFiumEngine::AddSegment(FX_DOWNLOADHINTS* param,\r
995                               size_t offset, size_t size) {\r
996   PDFiumEngine::DownloadHints* download_hints =\r
997       static_cast<PDFiumEngine::DownloadHints*>(param);\r
998   return download_hints->loader->RequestData(offset, size);\r
999 }\r
1000 \r
1001 bool PDFiumEngine::New(const char* url) {\r
1002   url_ = url;\r
1003   headers_ = std::string();\r
1004   return true;\r
1005 }\r
1006 \r
1007 bool PDFiumEngine::New(const char* url,\r
1008                        const char* headers) {\r
1009   url_ = url;\r
1010   if (!headers)\r
1011     headers_ = std::string();\r
1012   else\r
1013     headers_ = headers;\r
1014   return true;\r
1015 }\r
1016 \r
1017 void PDFiumEngine::PageOffsetUpdated(const pp::Point& page_offset) {\r
1018   page_offset_ = page_offset;\r
1019 }\r
1020 \r
1021 void PDFiumEngine::PluginSizeUpdated(const pp::Size& size) {\r
1022   CancelPaints();\r
1023 \r
1024   plugin_size_ = size;\r
1025   CalculateVisiblePages();\r
1026 }\r
1027 \r
1028 void PDFiumEngine::ScrolledToXPosition(int position) {\r
1029   CancelPaints();\r
1030 \r
1031   int old_x = position_.x();\r
1032   position_.set_x(position);\r
1033   CalculateVisiblePages();\r
1034   client_->Scroll(pp::Point(old_x - position, 0));\r
1035 }\r
1036 \r
1037 void PDFiumEngine::ScrolledToYPosition(int position) {\r
1038   CancelPaints();\r
1039 \r
1040   int old_y = position_.y();\r
1041   position_.set_y(position);\r
1042   CalculateVisiblePages();\r
1043   client_->Scroll(pp::Point(0, old_y - position));\r
1044 }\r
1045 \r
1046 void PDFiumEngine::PrePaint() {\r
1047   for (size_t i = 0; i < progressive_paints_.size(); ++i)\r
1048     progressive_paints_[i].painted_ = false;\r
1049 }\r
1050 \r
1051 void PDFiumEngine::Paint(const pp::Rect& rect,\r
1052                          pp::ImageData* image_data,\r
1053                          std::vector<pp::Rect>* ready,\r
1054                          std::vector<pp::Rect>* pending) {\r
1055   pp::Rect leftover = rect;\r
1056   for (size_t i = 0; i < visible_pages_.size(); ++i) {\r
1057     int index = visible_pages_[i];\r
1058     pp::Rect page_rect = pages_[index]->rect();\r
1059     // Convert the current page's rectangle to screen rectangle.  We do this\r
1060     // instead of the reverse (converting the dirty rectangle from screen to\r
1061     // page coordinates) because then we'd have to convert back to screen\r
1062     // coordinates, and the rounding errors sometime leave pixels dirty or even\r
1063     // move the text up or down a pixel when zoomed.\r
1064     pp::Rect page_rect_in_screen = GetPageScreenRect(index);\r
1065     pp::Rect dirty_in_screen = page_rect_in_screen.Intersect(leftover);\r
1066     if (dirty_in_screen.IsEmpty())\r
1067       continue;\r
1068 \r
1069     leftover = leftover.Subtract(dirty_in_screen);\r
1070 \r
1071     if (pages_[index]->available()) {\r
1072       int progressive = GetProgressiveIndex(index);\r
1073       if (progressive != -1 &&\r
1074           progressive_paints_[progressive].rect != dirty_in_screen) {\r
1075         // The PDFium code can only handle one progressive paint at a time, so\r
1076         // queue this up. Previously we used to merge the rects when this\r
1077         // happened, but it made scrolling up on complex PDFs very slow since\r
1078         // there would be a damaged rect at the top (from scroll) and at the\r
1079         // bottom (from toolbar).\r
1080         pending->push_back(dirty_in_screen);\r
1081         continue;\r
1082       }\r
1083 \r
1084       if (progressive == -1) {\r
1085         progressive = StartPaint(index, dirty_in_screen);\r
1086         progressive_paint_timeout_ = kMaxInitialProgressivePaintTimeMs;\r
1087       } else {\r
1088         progressive_paint_timeout_ = kMaxProgressivePaintTimeMs;\r
1089       }\r
1090 \r
1091       progressive_paints_[progressive].painted_ = true;\r
1092       if (ContinuePaint(progressive, image_data)) {\r
1093         FinishPaint(progressive, image_data);\r
1094         ready->push_back(dirty_in_screen);\r
1095       } else {\r
1096         pending->push_back(dirty_in_screen);\r
1097       }\r
1098     } else {\r
1099       PaintUnavailablePage(index, dirty_in_screen, image_data);\r
1100       ready->push_back(dirty_in_screen);\r
1101     }\r
1102   }\r
1103 }\r
1104 \r
1105 void PDFiumEngine::PostPaint() {\r
1106   for (size_t i = 0; i < progressive_paints_.size(); ++i) {\r
1107     if (progressive_paints_[i].painted_)\r
1108       continue;\r
1109 \r
1110     // This rectangle must have been merged with another one, that's why we\r
1111     // weren't asked to paint it. Remove it or otherwise we'll never finish\r
1112     // painting.\r
1113     FPDF_RenderPage_Close(\r
1114         pages_[progressive_paints_[i].page_index]->GetPage());\r
1115     FPDFBitmap_Destroy(progressive_paints_[i].bitmap);\r
1116     progressive_paints_.erase(progressive_paints_.begin() + i);\r
1117     --i;\r
1118   }\r
1119 }\r
1120 \r
1121 bool PDFiumEngine::HandleDocumentLoad(const pp::URLLoader& loader) {\r
1122   password_tries_remaining_ = kMaxPasswordTries;\r
1123   return doc_loader_.Init(loader, url_, headers_);\r
1124 }\r
1125 \r
1126 pp::Instance* PDFiumEngine::GetPluginInstance() {\r
1127   return client_->GetPluginInstance();\r
1128 }\r
1129 \r
1130 pp::URLLoader PDFiumEngine::CreateURLLoader() {\r
1131   return client_->CreateURLLoader();\r
1132 }\r
1133 \r
1134 void PDFiumEngine::AppendPage(PDFEngine* engine, int index) {\r
1135   // Unload and delete the blank page before appending.\r
1136   pages_[index]->Unload();\r
1137   pages_[index]->set_calculated_links(false);\r
1138   pp::Size curr_page_size = GetPageSize(index);\r
1139   FPDFPage_Delete(doc_, index);\r
1140   FPDF_ImportPages(doc_,\r
1141                    static_cast<PDFiumEngine*>(engine)->doc(),\r
1142                    "1",\r
1143                    index);\r
1144   pp::Size new_page_size = GetPageSize(index);\r
1145   if (curr_page_size != new_page_size)\r
1146     LoadPageInfo(true);\r
1147   client_->Invalidate(GetPageScreenRect(index));\r
1148 }\r
1149 \r
1150 pp::Point PDFiumEngine::GetScrollPosition() {\r
1151   return position_;\r
1152 }\r
1153 \r
1154 void PDFiumEngine::SetScrollPosition(const pp::Point& position) {\r
1155   position_ = position;\r
1156 }\r
1157 \r
1158 bool PDFiumEngine::IsProgressiveLoad() {\r
1159   return doc_loader_.is_partial_document();\r
1160 }\r
1161 \r
1162 void PDFiumEngine::OnPartialDocumentLoaded() {\r
1163   file_access_.m_FileLen = doc_loader_.document_size();\r
1164   fpdf_availability_ = FPDFAvail_Create(&file_availability_, &file_access_);\r
1165   DCHECK(fpdf_availability_);\r
1166 \r
1167   // Currently engine does not deal efficiently with some non-linearized files.\r
1168   // See http://code.google.com/p/chromium/issues/detail?id=59400\r
1169   // To improve user experience we download entire file for non-linearized PDF.\r
1170   if (!FPDFAvail_IsLinearized(fpdf_availability_)) {\r
1171     doc_loader_.RequestData(0, doc_loader_.document_size());\r
1172     return;\r
1173   }\r
1174 \r
1175   LoadDocument();\r
1176 }\r
1177 \r
1178 void PDFiumEngine::OnPendingRequestComplete() {\r
1179   if (!doc_ || !form_) {\r
1180     LoadDocument();\r
1181     return;\r
1182   }\r
1183 \r
1184   // LoadDocument() will result in |pending_pages_| being reset so there's no\r
1185   // need to run the code below in that case.\r
1186   bool update_pages = false;\r
1187   std::vector<int> still_pending;\r
1188   for (size_t i = 0; i < pending_pages_.size(); ++i) {\r
1189     if (CheckPageAvailable(pending_pages_[i], &still_pending)) {\r
1190       update_pages = true;\r
1191       if (IsPageVisible(pending_pages_[i]))\r
1192         client_->Invalidate(GetPageScreenRect(pending_pages_[i]));\r
1193     }\r
1194   }\r
1195   pending_pages_.swap(still_pending);\r
1196   if (update_pages)\r
1197     LoadPageInfo(true);\r
1198 }\r
1199 \r
1200 void PDFiumEngine::OnNewDataAvailable() {\r
1201   client_->DocumentLoadProgress(doc_loader_.GetAvailableData(),\r
1202                                 doc_loader_.document_size());\r
1203 }\r
1204 \r
1205 void PDFiumEngine::OnDocumentComplete() {\r
1206   if (!doc_ || !form_) {\r
1207     file_access_.m_FileLen = doc_loader_.document_size();\r
1208     LoadDocument();\r
1209     return;\r
1210   }\r
1211 \r
1212   bool need_update = false;\r
1213   for (size_t i = 0; i < pages_.size(); ++i) {\r
1214     if (pages_[i]->available())\r
1215       continue;\r
1216 \r
1217     pages_[i]->set_available(true);\r
1218     // We still need to call IsPageAvail() even if the whole document is\r
1219     // already downloaded.\r
1220     FPDFAvail_IsPageAvail(fpdf_availability_, i, &download_hints_);\r
1221     need_update = true;\r
1222     if (IsPageVisible(i))\r
1223       client_->Invalidate(GetPageScreenRect(i));\r
1224   }\r
1225   if (need_update)\r
1226     LoadPageInfo(true);\r
1227 \r
1228   FinishLoadingDocument();\r
1229 }\r
1230 \r
1231 void PDFiumEngine::FinishLoadingDocument() {\r
1232   DCHECK(doc_loader_.IsDocumentComplete() && doc_);\r
1233   if (called_do_document_action_)\r
1234     return;\r
1235   called_do_document_action_ = true;\r
1236 \r
1237   // These can only be called now, as the JS might end up needing a page.\r
1238   FORM_DoDocumentJSAction(form_);\r
1239   FORM_DoDocumentOpenAction(form_);\r
1240   if (most_visible_page_ != -1) {\r
1241     FPDF_PAGE new_page = pages_[most_visible_page_]->GetPage();\r
1242     FORM_DoPageAAction(new_page, form_, FPDFPAGE_AACTION_OPEN);\r
1243   }\r
1244 \r
1245   if (doc_) // This can only happen if loading |doc_| fails.\r
1246     client_->DocumentLoadComplete(pages_.size());\r
1247 }\r
1248 \r
1249 void PDFiumEngine::UnsupportedFeature(int type) {\r
1250   std::string feature;\r
1251   switch (type) {\r
1252     case FPDF_UNSP_DOC_XFAFORM:\r
1253       //feature = "XFA";\r
1254       break;\r
1255     case FPDF_UNSP_DOC_PORTABLECOLLECTION:\r
1256       feature = "Portfolios_Packages";\r
1257       break;\r
1258     case FPDF_UNSP_DOC_ATTACHMENT:\r
1259     case FPDF_UNSP_ANNOT_ATTACHMENT:\r
1260       feature = "Attachment";\r
1261       break;\r
1262     case FPDF_UNSP_DOC_SECURITY:\r
1263       feature = "Rights_Management";\r
1264       break;\r
1265     case FPDF_UNSP_DOC_SHAREDREVIEW:\r
1266       feature = "Shared_Review";\r
1267       break;\r
1268     case FPDF_UNSP_DOC_SHAREDFORM_ACROBAT:\r
1269     case FPDF_UNSP_DOC_SHAREDFORM_FILESYSTEM:\r
1270     case FPDF_UNSP_DOC_SHAREDFORM_EMAIL:\r
1271       feature = "Shared_Form";\r
1272       break;\r
1273     case FPDF_UNSP_ANNOT_3DANNOT:\r
1274       feature = "3D";\r
1275       break;\r
1276     case FPDF_UNSP_ANNOT_MOVIE:\r
1277       feature = "Movie";\r
1278       break;\r
1279     case FPDF_UNSP_ANNOT_SOUND:\r
1280       feature = "Sound";\r
1281       break;\r
1282     case FPDF_UNSP_ANNOT_SCREEN_MEDIA:\r
1283     case FPDF_UNSP_ANNOT_SCREEN_RICHMEDIA:\r
1284       feature = "Screen";\r
1285       break;\r
1286     case FPDF_UNSP_ANNOT_SIG:\r
1287       feature = "Digital_Signature";\r
1288       break;\r
1289   }\r
1290   client_->DocumentHasUnsupportedFeature(feature);\r
1291 }\r
1292 \r
1293 void PDFiumEngine::ContinueFind(int32_t result) {\r
1294   StartFind(current_find_text_.c_str(), !!result);\r
1295 }\r
1296 \r
1297 bool PDFiumEngine::HandleEvent(const pp::InputEvent& event) {\r
1298   DCHECK(!defer_page_unload_);\r
1299   defer_page_unload_ = true;\r
1300   bool rv = false;\r
1301   switch (event.GetType()) {\r
1302     case PP_INPUTEVENT_TYPE_MOUSEDOWN:\r
1303       rv = OnMouseDown(pp::MouseInputEvent(event));\r
1304       break;\r
1305     case PP_INPUTEVENT_TYPE_MOUSEUP:\r
1306       rv = OnMouseUp(pp::MouseInputEvent(event));\r
1307       break;\r
1308     case PP_INPUTEVENT_TYPE_MOUSEMOVE:\r
1309       rv = OnMouseMove(pp::MouseInputEvent(event));\r
1310       break;\r
1311     case PP_INPUTEVENT_TYPE_KEYDOWN:\r
1312       rv = OnKeyDown(pp::KeyboardInputEvent(event));\r
1313       break;\r
1314     case PP_INPUTEVENT_TYPE_KEYUP:\r
1315       rv = OnKeyUp(pp::KeyboardInputEvent(event));\r
1316       break;\r
1317     case PP_INPUTEVENT_TYPE_CHAR:\r
1318       rv = OnChar(pp::KeyboardInputEvent(event));\r
1319       break;\r
1320     default:\r
1321       break;\r
1322   }\r
1323 \r
1324   DCHECK(defer_page_unload_);\r
1325   defer_page_unload_ = false;\r
1326   for (size_t i = 0; i < deferred_page_unloads_.size(); ++i)\r
1327     pages_[deferred_page_unloads_[i]]->Unload();\r
1328   deferred_page_unloads_.clear();\r
1329   return rv;\r
1330 }\r
1331 \r
1332 uint32_t PDFiumEngine::QuerySupportedPrintOutputFormats() {\r
1333   if (!HasPermission(PDFEngine::PERMISSION_PRINT_LOW_QUALITY))\r
1334     return 0;\r
1335   return PP_PRINTOUTPUTFORMAT_PDF;\r
1336 }\r
1337 \r
1338 void PDFiumEngine::PrintBegin() {\r
1339   FORM_DoDocumentAAction(form_, FPDFDOC_AACTION_WP);\r
1340 }\r
1341 \r
1342 pp::Resource PDFiumEngine::PrintPages(\r
1343     const PP_PrintPageNumberRange_Dev* page_ranges, uint32_t page_range_count,\r
1344     const PP_PrintSettings_Dev& print_settings) {\r
1345   if (HasPermission(PDFEngine::PERMISSION_PRINT_HIGH_QUALITY))\r
1346     return PrintPagesAsPDF(page_ranges, page_range_count, print_settings);\r
1347   else if (HasPermission(PDFEngine::PERMISSION_PRINT_LOW_QUALITY))\r
1348     return PrintPagesAsRasterPDF(page_ranges, page_range_count, print_settings);\r
1349   return pp::Resource();\r
1350 }\r
1351 \r
1352 FPDF_DOCUMENT PDFiumEngine::CreateSinglePageRasterPdf(\r
1353     double source_page_width,\r
1354     double source_page_height,\r
1355     const PP_PrintSettings_Dev& print_settings,\r
1356     PDFiumPage* page_to_print) {\r
1357   FPDF_DOCUMENT temp_doc = FPDF_CreateNewDocument();\r
1358   if (!temp_doc)\r
1359     return temp_doc;\r
1360 \r
1361   const pp::Size& bitmap_size(page_to_print->rect().size());\r
1362 \r
1363   FPDF_PAGE temp_page =\r
1364       FPDFPage_New(temp_doc, 0, source_page_width, source_page_height);\r
1365 \r
1366   pp::ImageData image = pp::ImageData(client_->GetPluginInstance(),\r
1367                                       PP_IMAGEDATAFORMAT_BGRA_PREMUL,\r
1368                                       bitmap_size,\r
1369                                       false);\r
1370 \r
1371   FPDF_BITMAP bitmap = FPDFBitmap_CreateEx(bitmap_size.width(),\r
1372                                            bitmap_size.height(),\r
1373                                            FPDFBitmap_BGRx,\r
1374                                            image.data(),\r
1375                                            image.stride());\r
1376 \r
1377   // Clear the bitmap\r
1378   FPDFBitmap_FillRect(\r
1379       bitmap, 0, 0, bitmap_size.width(), bitmap_size.height(), 0xFFFFFFFF);\r
1380 \r
1381   pp::Rect page_rect = page_to_print->rect();\r
1382   FPDF_RenderPageBitmap(bitmap,\r
1383                         page_to_print->GetPrintPage(),\r
1384                         page_rect.x(),\r
1385                         page_rect.y(),\r
1386                         page_rect.width(),\r
1387                         page_rect.height(),\r
1388                         print_settings.orientation,\r
1389                         FPDF_ANNOT | FPDF_PRINTING | FPDF_NO_CATCH);\r
1390 \r
1391   double ratio_x = (static_cast<double>(bitmap_size.width()) * kPointsPerInch) /\r
1392                    print_settings.dpi;\r
1393   double ratio_y =\r
1394       (static_cast<double>(bitmap_size.height()) * kPointsPerInch) /\r
1395       print_settings.dpi;\r
1396 \r
1397   // Add the bitmap to an image object and add the image object to the output\r
1398   // page.\r
1399   FPDF_PAGEOBJECT temp_img = FPDFPageObj_NewImgeObj(temp_doc);\r
1400   FPDFImageObj_SetBitmap(&temp_page, 1, temp_img, bitmap);\r
1401   FPDFImageObj_SetMatrix(temp_img, ratio_x, 0, 0, ratio_y, 0, 0);\r
1402   FPDFPage_InsertObject(temp_page, temp_img);\r
1403   FPDFPage_GenerateContent(temp_page);\r
1404   FPDF_ClosePage(temp_page);\r
1405 \r
1406   page_to_print->ClosePrintPage();\r
1407   FPDFBitmap_Destroy(bitmap);\r
1408 \r
1409   return temp_doc;\r
1410 }\r
1411 \r
1412 pp::Buffer_Dev PDFiumEngine::PrintPagesAsRasterPDF(\r
1413     const PP_PrintPageNumberRange_Dev* page_ranges, uint32_t page_range_count,\r
1414     const PP_PrintSettings_Dev& print_settings) {\r
1415   if (!page_range_count)\r
1416     return pp::Buffer_Dev();\r
1417 \r
1418   // If document is not downloaded yet, disable printing.\r
1419   if (doc_ && !doc_loader_.IsDocumentComplete())\r
1420     return pp::Buffer_Dev();\r
1421 \r
1422   FPDF_DOCUMENT output_doc = FPDF_CreateNewDocument();\r
1423   if (!output_doc)\r
1424     return pp::Buffer_Dev();\r
1425 \r
1426   SaveSelectedFormForPrint();\r
1427 \r
1428   std::vector<PDFiumPage> pages_to_print;\r
1429   // width and height of source PDF pages.\r
1430   std::vector<std::pair<double, double> > source_page_sizes;\r
1431   // Collect pages to print and sizes of source pages.\r
1432   std::vector<uint32_t> page_numbers =\r
1433       GetPageNumbersFromPrintPageNumberRange(page_ranges, page_range_count);\r
1434   for (size_t i = 0; i < page_numbers.size(); ++i) {\r
1435     uint32_t page_number = page_numbers[i];\r
1436     FPDF_PAGE pdf_page = FPDF_LoadPage(doc_, page_number);\r
1437     double source_page_width = FPDF_GetPageWidth(pdf_page);\r
1438     double source_page_height = FPDF_GetPageHeight(pdf_page);\r
1439     source_page_sizes.push_back(std::make_pair(source_page_width,\r
1440                                                source_page_height));\r
1441 \r
1442     int width_in_pixels = ConvertUnit(source_page_width,\r
1443                                       static_cast<int>(kPointsPerInch),\r
1444                                       print_settings.dpi);\r
1445     int height_in_pixels = ConvertUnit(source_page_height,\r
1446                                        static_cast<int>(kPointsPerInch),\r
1447                                        print_settings.dpi);\r
1448 \r
1449     pp::Rect rect(width_in_pixels, height_in_pixels);\r
1450     pages_to_print.push_back(PDFiumPage(this, page_number, rect, true));\r
1451     FPDF_ClosePage(pdf_page);\r
1452   }\r
1453 \r
1454 #if defined(OS_LINUX)\r
1455   g_last_instance_id = client_->GetPluginInstance()->pp_instance();\r
1456 #endif\r
1457 \r
1458   size_t i = 0;\r
1459   for (; i < pages_to_print.size(); ++i) {\r
1460     double source_page_width = source_page_sizes[i].first;\r
1461     double source_page_height = source_page_sizes[i].second;\r
1462 \r
1463     // Use temp_doc to compress image by saving PDF to buffer.\r
1464     FPDF_DOCUMENT temp_doc = CreateSinglePageRasterPdf(source_page_width,\r
1465                                                        source_page_height,\r
1466                                                        print_settings,\r
1467                                                        &pages_to_print[i]);\r
1468 \r
1469     if (!temp_doc)\r
1470       break;\r
1471 \r
1472     pp::Buffer_Dev buffer = GetFlattenedPrintData(temp_doc);\r
1473     FPDF_CloseDocument(temp_doc);\r
1474 \r
1475     PDFiumMemBufferFileRead file_read(buffer.data(), buffer.size());\r
1476     temp_doc = FPDF_LoadCustomDocument(&file_read, NULL);\r
1477 \r
1478     FPDF_BOOL imported = FPDF_ImportPages(output_doc, temp_doc, "1", i);\r
1479     FPDF_CloseDocument(temp_doc);\r
1480     if (!imported)\r
1481       break;\r
1482   }\r
1483 \r
1484   pp::Buffer_Dev buffer;\r
1485   if (i == pages_to_print.size()) {\r
1486     FPDF_CopyViewerPreferences(output_doc, doc_);\r
1487     FitContentsToPrintableAreaIfRequired(output_doc, print_settings);\r
1488     // Now flatten all the output pages.\r
1489     buffer = GetFlattenedPrintData(output_doc);\r
1490   }\r
1491   FPDF_CloseDocument(output_doc);\r
1492   return buffer;\r
1493 }\r
1494 \r
1495 pp::Buffer_Dev PDFiumEngine::GetFlattenedPrintData(const FPDF_DOCUMENT& doc) {\r
1496   int page_count = FPDF_GetPageCount(doc);\r
1497   bool flatten_succeeded = true;\r
1498   for (int i = 0; i < page_count; ++i) {\r
1499     FPDF_PAGE page = FPDF_LoadPage(doc, i);\r
1500     DCHECK(page);\r
1501     if (page) {\r
1502       int flatten_ret = FPDFPage_Flatten(page, FLAT_PRINT);\r
1503       FPDF_ClosePage(page);\r
1504       if (flatten_ret == FLATTEN_FAIL) {\r
1505         flatten_succeeded = false;\r
1506         break;\r
1507       }\r
1508     } else {\r
1509       flatten_succeeded = false;\r
1510       break;\r
1511     }\r
1512   }\r
1513   if (!flatten_succeeded) {\r
1514     FPDF_CloseDocument(doc);\r
1515     return pp::Buffer_Dev();\r
1516   }\r
1517 \r
1518   pp::Buffer_Dev buffer;\r
1519   PDFiumMemBufferFileWrite output_file_write;\r
1520   if (FPDF_SaveAsCopy(doc, &output_file_write, 0)) {\r
1521     buffer = pp::Buffer_Dev(\r
1522         client_->GetPluginInstance(), output_file_write.size());\r
1523     if (!buffer.is_null()) {\r
1524       memcpy(buffer.data(), output_file_write.buffer().c_str(),\r
1525              output_file_write.size());\r
1526     }\r
1527   }\r
1528   return buffer;\r
1529 }\r
1530 \r
1531 pp::Buffer_Dev PDFiumEngine::PrintPagesAsPDF(\r
1532     const PP_PrintPageNumberRange_Dev* page_ranges, uint32_t page_range_count,\r
1533     const PP_PrintSettings_Dev& print_settings) {\r
1534   if (!page_range_count)\r
1535     return pp::Buffer_Dev();\r
1536 \r
1537   DCHECK(doc_);\r
1538   FPDF_DOCUMENT output_doc = FPDF_CreateNewDocument();\r
1539   if (!output_doc)\r
1540     return pp::Buffer_Dev();\r
1541 \r
1542   SaveSelectedFormForPrint();\r
1543 \r
1544   std::string page_number_str;\r
1545   for (uint32_t index = 0; index < page_range_count; ++index) {\r
1546     if (!page_number_str.empty())\r
1547       page_number_str.append(",");\r
1548     page_number_str.append(\r
1549         base::IntToString(page_ranges[index].first_page_number + 1));\r
1550     if (page_ranges[index].first_page_number !=\r
1551             page_ranges[index].last_page_number) {\r
1552       page_number_str.append("-");\r
1553       page_number_str.append(\r
1554           base::IntToString(page_ranges[index].last_page_number + 1));\r
1555     }\r
1556   }\r
1557 \r
1558   std::vector<uint32_t> page_numbers =\r
1559       GetPageNumbersFromPrintPageNumberRange(page_ranges, page_range_count);\r
1560   for (size_t i = 0; i < page_numbers.size(); ++i) {\r
1561     uint32_t page_number = page_numbers[i];\r
1562     pages_[page_number]->GetPage();\r
1563     if (!IsPageVisible(page_numbers[i]))\r
1564       pages_[page_number]->Unload();\r
1565   }\r
1566 \r
1567   FPDF_CopyViewerPreferences(output_doc, doc_);\r
1568   if (!FPDF_ImportPages(output_doc, doc_, page_number_str.c_str(), 0)) {\r
1569     FPDF_CloseDocument(output_doc);\r
1570     return pp::Buffer_Dev();\r
1571   }\r
1572 \r
1573   FitContentsToPrintableAreaIfRequired(output_doc, print_settings);\r
1574 \r
1575   // Now flatten all the output pages.\r
1576   pp::Buffer_Dev buffer = GetFlattenedPrintData(output_doc);\r
1577   FPDF_CloseDocument(output_doc);\r
1578   return buffer;\r
1579 }\r
1580 \r
1581 void PDFiumEngine::FitContentsToPrintableAreaIfRequired(\r
1582     const FPDF_DOCUMENT& doc, const PP_PrintSettings_Dev& print_settings) {\r
1583   // Check to see if we need to fit pdf contents to printer paper size.\r
1584   if (print_settings.print_scaling_option !=\r
1585           PP_PRINTSCALINGOPTION_SOURCE_SIZE) {\r
1586     int num_pages = FPDF_GetPageCount(doc);\r
1587     // In-place transformation is more efficient than creating a new\r
1588     // transformed document from the source document. Therefore, transform\r
1589     // every page to fit the contents in the selected printer paper.\r
1590     for (int i = 0; i < num_pages; ++i) {\r
1591       FPDF_PAGE page = FPDF_LoadPage(doc, i);\r
1592       TransformPDFPageForPrinting(page, print_settings);\r
1593       FPDF_ClosePage(page);\r
1594     }\r
1595   }\r
1596 }\r
1597 \r
1598 void PDFiumEngine::SaveSelectedFormForPrint() {\r
1599   FORM_ForceToKillFocus(form_);\r
1600   client_->FormTextFieldFocusChange(false);\r
1601 }\r
1602 \r
1603 void PDFiumEngine::PrintEnd() {\r
1604   FORM_DoDocumentAAction(form_, FPDFDOC_AACTION_DP);\r
1605 }\r
1606 \r
1607 PDFiumPage::Area PDFiumEngine::GetCharIndex(\r
1608     const pp::MouseInputEvent& event, int* page_index,\r
1609     int* char_index, PDFiumPage::LinkTarget* target) {\r
1610   // First figure out which page this is in.\r
1611   pp::Point mouse_point = event.GetPosition();\r
1612   pp::Point point(\r
1613       static_cast<int>((mouse_point.x() + position_.x()) / current_zoom_),\r
1614       static_cast<int>((mouse_point.y() + position_.y()) / current_zoom_));\r
1615   return GetCharIndex(point, page_index, char_index, target);\r
1616 }\r
1617 \r
1618 PDFiumPage::Area PDFiumEngine::GetCharIndex(\r
1619     const pp::Point& point,\r
1620     int* page_index,\r
1621     int* char_index,\r
1622     PDFiumPage::LinkTarget* target) {\r
1623   int page = -1;\r
1624   for (size_t i = 0; i < visible_pages_.size(); ++i) {\r
1625     if (pages_[visible_pages_[i]]->rect().Contains(point)) {\r
1626       page = visible_pages_[i];\r
1627       break;\r
1628     }\r
1629   }\r
1630   if (page == -1)\r
1631     return PDFiumPage::NONSELECTABLE_AREA;\r
1632 \r
1633   // If the page hasn't finished rendering, calling into the page sometimes\r
1634   // leads to hangs.\r
1635   for (size_t i = 0; i < progressive_paints_.size(); ++i) {\r
1636     if (progressive_paints_[i].page_index == page)\r
1637       return PDFiumPage::NONSELECTABLE_AREA;\r
1638   }\r
1639 \r
1640   *page_index = page;\r
1641   return pages_[page]->GetCharIndex(point, current_rotation_, char_index,\r
1642                                     target);\r
1643 }\r
1644 \r
1645 bool PDFiumEngine::OnMouseDown(const pp::MouseInputEvent& event) {\r
1646   if (event.GetButton() != PP_INPUTEVENT_MOUSEBUTTON_LEFT)\r
1647     return false;\r
1648 \r
1649   SelectionChangeInvalidator selection_invalidator(this);\r
1650   selection_.clear();\r
1651 \r
1652   int page_index = -1;\r
1653   int char_index = -1;\r
1654   PDFiumPage::LinkTarget target;\r
1655   PDFiumPage::Area area = GetCharIndex(event, &page_index,\r
1656                                        &char_index, &target);\r
1657   mouse_down_state_.Set(area, target);\r
1658 \r
1659   // Decide whether to open link or not based on user action in mouse up and\r
1660   // mouse move events.\r
1661   if (area == PDFiumPage::WEBLINK_AREA)\r
1662     return true;\r
1663 \r
1664   if (area == PDFiumPage::DOCLINK_AREA) {\r
1665     client_->ScrollToPage(target.page);\r
1666     client_->FormTextFieldFocusChange(false);\r
1667     return true;\r
1668   }\r
1669 \r
1670   if (page_index != -1) {\r
1671     last_page_mouse_down_ = page_index;\r
1672     double page_x, page_y;\r
1673     pp::Point point = event.GetPosition();\r
1674     DeviceToPage(page_index, point.x(), point.y(), &page_x, &page_y);\r
1675 \r
1676     FORM_OnLButtonDown(form_, pages_[page_index]->GetPage(), 0, page_x, page_y);\r
1677     int control = FPDPage_HasFormFieldAtPoint(\r
1678         form_, pages_[page_index]->GetPage(), page_x, page_y);\r
1679     if (control > FPDF_FORMFIELD_UNKNOWN) {  // returns -1 sometimes...\r
1680 #ifdef _TEST_XFA\r
1681       client_->FormTextFieldFocusChange(control == FPDF_FORMFIELD_TEXTFIELD ||\r
1682           control == FPDF_FORMFIELD_COMBOBOX ||\r
1683                   control == FPDF_FORMFIELD_XFA);\r
1684 #else \r
1685                 client_->FormTextFieldFocusChange(control == FPDF_FORMFIELD_TEXTFIELD ||\r
1686                         control == FPDF_FORMFIELD_COMBOBOX);\r
1687 #endif\r
1688       return true;  // Return now before we get into the selection code.\r
1689     }\r
1690   }\r
1691 \r
1692   client_->FormTextFieldFocusChange(false);\r
1693 \r
1694   if (area != PDFiumPage::TEXT_AREA)\r
1695     return true;  // Return true so WebKit doesn't do its own highlighting.\r
1696 \r
1697   if (event.GetClickCount() == 1) {\r
1698     OnSingleClick(page_index, char_index);\r
1699   } else if (event.GetClickCount() == 2 ||\r
1700              event.GetClickCount() == 3) {\r
1701     OnMultipleClick(event.GetClickCount(), page_index, char_index);\r
1702   }\r
1703 \r
1704   return true;\r
1705 }\r
1706 \r
1707 void PDFiumEngine::OnSingleClick(int page_index, int char_index) {\r
1708   selecting_ = true;\r
1709   selection_.push_back(PDFiumRange(pages_[page_index], char_index, 0));\r
1710 }\r
1711 \r
1712 void PDFiumEngine::OnMultipleClick(int click_count,\r
1713                                    int page_index,\r
1714                                    int char_index) {\r
1715   // It would be more efficient if the SDK could support finding a space, but\r
1716   // now it doesn't.\r
1717   int start_index = char_index;\r
1718   do {\r
1719     base::char16 cur = pages_[page_index]->GetCharAtIndex(start_index);\r
1720     // For double click, we want to select one word so we look for whitespace\r
1721     // boundaries.  For triple click, we want the whole line.\r
1722     if (cur == '\n' || (click_count == 2 && (cur == ' ' || cur == '\t')))\r
1723       break;\r
1724   } while (--start_index >= 0);\r
1725   if (start_index)\r
1726     start_index++;\r
1727 \r
1728   int end_index = char_index;\r
1729   int total = pages_[page_index]->GetCharCount();\r
1730   while (end_index++ <= total) {\r
1731     base::char16 cur = pages_[page_index]->GetCharAtIndex(end_index);\r
1732     if (cur == '\n' || (click_count == 2 && (cur == ' ' || cur == '\t')))\r
1733       break;\r
1734   }\r
1735 \r
1736   selection_.push_back(PDFiumRange(\r
1737       pages_[page_index], start_index, end_index - start_index));\r
1738 }\r
1739 \r
1740 bool PDFiumEngine::OnMouseUp(const pp::MouseInputEvent& event) {\r
1741   if (event.GetButton() != PP_INPUTEVENT_MOUSEBUTTON_LEFT)\r
1742     return false;\r
1743 \r
1744   int page_index = -1;\r
1745   int char_index = -1;\r
1746   PDFiumPage::LinkTarget target;\r
1747   PDFiumPage::Area area =\r
1748       GetCharIndex(event, &page_index, &char_index, &target);\r
1749 \r
1750   // Open link on mouse up for same link for which mouse down happened earlier.\r
1751   if (mouse_down_state_.Matches(area, target)) {\r
1752     if (area == PDFiumPage::WEBLINK_AREA) {\r
1753       bool open_in_new_tab = !!(event.GetModifiers() & kDefaultKeyModifier);\r
1754       client_->NavigateTo(target.url, open_in_new_tab);\r
1755       client_->FormTextFieldFocusChange(false);\r
1756       return true;\r
1757     }\r
1758   }\r
1759 \r
1760   if (page_index != -1) {\r
1761     double page_x, page_y;\r
1762     pp::Point point = event.GetPosition();\r
1763     DeviceToPage(page_index, point.x(), point.y(), &page_x, &page_y);\r
1764     FORM_OnLButtonUp(\r
1765         form_, pages_[page_index]->GetPage(), 0, page_x, page_y);\r
1766   }\r
1767 \r
1768   if (!selecting_)\r
1769     return false;\r
1770 \r
1771   selecting_ = false;\r
1772   return true;\r
1773 }\r
1774 \r
1775 bool PDFiumEngine::OnMouseMove(const pp::MouseInputEvent& event) {\r
1776   int page_index = -1;\r
1777   int char_index = -1;\r
1778   PDFiumPage::LinkTarget target;\r
1779   PDFiumPage::Area area =\r
1780       GetCharIndex(event, &page_index, &char_index, &target);\r
1781 \r
1782   // Clear |mouse_down_state_| if mouse moves away from where the mouse down\r
1783   // happened.\r
1784   if (!mouse_down_state_.Matches(area, target))\r
1785     mouse_down_state_.Reset();\r
1786 \r
1787   if (!selecting_) {\r
1788     PP_CursorType_Dev cursor;\r
1789     switch (area) {\r
1790       case PDFiumPage::TEXT_AREA:\r
1791         cursor = PP_CURSORTYPE_IBEAM;\r
1792         break;\r
1793       case PDFiumPage::WEBLINK_AREA:\r
1794       case PDFiumPage::DOCLINK_AREA:\r
1795         cursor = PP_CURSORTYPE_HAND;\r
1796         break;\r
1797       case PDFiumPage::NONSELECTABLE_AREA:\r
1798       default:\r
1799         cursor = PP_CURSORTYPE_POINTER;\r
1800         break;\r
1801     }\r
1802 \r
1803     if (page_index != -1) {\r
1804       double page_x, page_y;\r
1805       pp::Point point = event.GetPosition();\r
1806       DeviceToPage(page_index, point.x(), point.y(), &page_x, &page_y);\r
1807 \r
1808       FORM_OnMouseMove(form_, pages_[page_index]->GetPage(), 0, page_x, page_y);\r
1809       int control = FPDPage_HasFormFieldAtPoint(\r
1810           form_, pages_[page_index]->GetPage(), page_x, page_y);\r
1811       switch (control) {\r
1812         case FPDF_FORMFIELD_PUSHBUTTON:\r
1813         case FPDF_FORMFIELD_CHECKBOX:\r
1814         case FPDF_FORMFIELD_RADIOBUTTON:\r
1815         case FPDF_FORMFIELD_COMBOBOX:\r
1816         case FPDF_FORMFIELD_LISTBOX:\r
1817           cursor = PP_CURSORTYPE_HAND;\r
1818           break;\r
1819         case FPDF_FORMFIELD_TEXTFIELD:\r
1820           cursor = PP_CURSORTYPE_IBEAM;\r
1821           break;\r
1822         default:\r
1823           break;\r
1824       }\r
1825     }\r
1826 \r
1827     client_->UpdateCursor(cursor);\r
1828     pp::Point point = event.GetPosition();\r
1829     std::string url = GetLinkAtPosition(event.GetPosition());\r
1830     if (url != link_under_cursor_) {\r
1831       link_under_cursor_ = url;\r
1832       pp::PDF::SetLinkUnderCursor(GetPluginInstance(), url.c_str());\r
1833     }\r
1834     // No need to swallow the event, since this might interfere with the\r
1835     // scrollbars if the user is dragging them.\r
1836     return false;\r
1837   }\r
1838 \r
1839   // We're selecting but right now we're not over text, so don't change the\r
1840   // current selection.\r
1841   if (area != PDFiumPage::TEXT_AREA && area != PDFiumPage::WEBLINK_AREA &&\r
1842       area != PDFiumPage::DOCLINK_AREA) {\r
1843     return false;\r
1844   }\r
1845 \r
1846   SelectionChangeInvalidator selection_invalidator(this);\r
1847 \r
1848   // Check if the user has descreased their selection area and we need to remove\r
1849   // pages from selection_.\r
1850   for (size_t i = 0; i < selection_.size(); ++i) {\r
1851     if (selection_[i].page_index() == page_index) {\r
1852       // There should be no other pages after this.\r
1853       selection_.erase(selection_.begin() + i + 1, selection_.end());\r
1854       break;\r
1855     }\r
1856   }\r
1857 \r
1858   if (selection_.size() == 0)\r
1859     return false;\r
1860 \r
1861   int last = selection_.size() - 1;\r
1862   if (selection_[last].page_index() == page_index) {\r
1863     // Selecting within a page.\r
1864     int count;\r
1865     if (char_index >= selection_[last].char_index()) {\r
1866       // Selecting forward.\r
1867       count = char_index - selection_[last].char_index() + 1;\r
1868     } else {\r
1869       count = char_index - selection_[last].char_index() - 1;\r
1870     }\r
1871     selection_[last].SetCharCount(count);\r
1872   } else if (selection_[last].page_index() < page_index) {\r
1873     // Selecting into the next page.\r
1874 \r
1875     // First make sure that there are no gaps in selection, i.e. if mousedown on\r
1876     // page one but we only get mousemove over page three, we want page two.\r
1877     for (int i = selection_[last].page_index() + 1; i < page_index; ++i) {\r
1878       selection_.push_back(PDFiumRange(pages_[i], 0,\r
1879                            pages_[i]->GetCharCount()));\r
1880     }\r
1881 \r
1882     int count = pages_[selection_[last].page_index()]->GetCharCount();\r
1883     selection_[last].SetCharCount(count - selection_[last].char_index());\r
1884     selection_.push_back(PDFiumRange(pages_[page_index], 0, char_index));\r
1885   } else {\r
1886     // Selecting into the previous page.\r
1887     selection_[last].SetCharCount(-selection_[last].char_index());\r
1888 \r
1889     // First make sure that there are no gaps in selection, i.e. if mousedown on\r
1890     // page three but we only get mousemove over page one, we want page two.\r
1891     for (int i = selection_[last].page_index() - 1; i > page_index; --i) {\r
1892       selection_.push_back(PDFiumRange(pages_[i], 0,\r
1893                            pages_[i]->GetCharCount()));\r
1894     }\r
1895 \r
1896     int count = pages_[page_index]->GetCharCount();\r
1897     selection_.push_back(\r
1898         PDFiumRange(pages_[page_index], count, count - char_index));\r
1899   }\r
1900 \r
1901   return true;\r
1902 }\r
1903 \r
1904 bool PDFiumEngine::OnKeyDown(const pp::KeyboardInputEvent& event) {\r
1905   if (last_page_mouse_down_ == -1)\r
1906     return false;\r
1907 \r
1908   bool rv = !!FORM_OnKeyDown(\r
1909       form_, pages_[last_page_mouse_down_]->GetPage(),\r
1910       event.GetKeyCode(), event.GetModifiers());\r
1911 \r
1912   if (event.GetKeyCode() == ui::VKEY_BACK ||\r
1913       event.GetKeyCode() == ui::VKEY_ESCAPE) {\r
1914     // Chrome doesn't send char events for backspace or escape keys, see\r
1915     // PlatformKeyboardEventBuilder::isCharacterKey() and\r
1916     // http://chrome-corpsvn.mtv.corp.google.com/viewvc?view=rev&root=chrome&revision=31805\r
1917     // for more information.  So just fake one since PDFium uses it.\r
1918     std::string str;\r
1919     str.push_back(event.GetKeyCode());\r
1920     pp::KeyboardInputEvent synthesized(pp::KeyboardInputEvent(\r
1921         client_->GetPluginInstance(),\r
1922         PP_INPUTEVENT_TYPE_CHAR,\r
1923         event.GetTimeStamp(),\r
1924         event.GetModifiers(),\r
1925         event.GetKeyCode(),\r
1926         str));\r
1927     OnChar(synthesized);\r
1928   }\r
1929 \r
1930   return rv;\r
1931 }\r
1932 \r
1933 bool PDFiumEngine::OnKeyUp(const pp::KeyboardInputEvent& event) {\r
1934   if (last_page_mouse_down_ == -1)\r
1935     return false;\r
1936 \r
1937   return !!FORM_OnKeyUp(\r
1938       form_, pages_[last_page_mouse_down_]->GetPage(),\r
1939       event.GetKeyCode(), event.GetModifiers());\r
1940 }\r
1941 \r
1942 bool PDFiumEngine::OnChar(const pp::KeyboardInputEvent& event) {\r
1943   if (last_page_mouse_down_ == -1)\r
1944     return false;\r
1945 \r
1946   base::string16 str = base::UTF8ToUTF16(event.GetCharacterText().AsString());\r
1947   return !!FORM_OnChar(\r
1948       form_, pages_[last_page_mouse_down_]->GetPage(),\r
1949       str[0],\r
1950       event.GetModifiers());\r
1951 }\r
1952 \r
1953 void PDFiumEngine::StartFind(const char* text, bool case_sensitive) {\r
1954   // We can get a call to StartFind before we have any page information (i.e.\r
1955   // before the first call to LoadDocument has happened). Handle this case.\r
1956   if (pages_.empty())\r
1957     return;\r
1958 \r
1959   bool first_search = false;\r
1960   int character_to_start_searching_from = 0;\r
1961   if (current_find_text_ != text) {  // First time we search for this text.\r
1962     first_search = true;\r
1963     std::vector<PDFiumRange> old_selection = selection_;\r
1964     StopFind();\r
1965     current_find_text_ = text;\r
1966 \r
1967     if (old_selection.empty()) {\r
1968       // Start searching from the beginning of the document.\r
1969       next_page_to_search_ = 0;\r
1970       last_page_to_search_ = pages_.size() - 1;\r
1971       last_character_index_to_search_ = -1;\r
1972     } else {\r
1973       // There's a current selection, so start from it.\r
1974       next_page_to_search_ = old_selection[0].page_index();\r
1975       last_character_index_to_search_ = old_selection[0].char_index();\r
1976       character_to_start_searching_from = old_selection[0].char_index();\r
1977       last_page_to_search_ = next_page_to_search_;\r
1978     }\r
1979   }\r
1980 \r
1981   int current_page = next_page_to_search_;\r
1982 \r
1983   if (pages_[current_page]->available()) {\r
1984     base::string16 str = base::UTF8ToUTF16(text);\r
1985     // Don't use PDFium to search for now, since it doesn't support unicode text.\r
1986     // Leave the code for now to avoid bit-rot, in case it's fixed later.\r
1987     if (0) {\r
1988       SearchUsingPDFium(\r
1989           str, case_sensitive, first_search, character_to_start_searching_from,\r
1990           current_page);\r
1991     } else {\r
1992       SearchUsingICU(\r
1993           str, case_sensitive, first_search, character_to_start_searching_from,\r
1994           current_page);\r
1995     }\r
1996 \r
1997     if (!IsPageVisible(current_page))\r
1998       pages_[current_page]->Unload();\r
1999   }\r
2000 \r
2001   if (next_page_to_search_ != last_page_to_search_ ||\r
2002       (first_search && last_character_index_to_search_ != -1)) {\r
2003     ++next_page_to_search_;\r
2004   }\r
2005 \r
2006   if (next_page_to_search_ == static_cast<int>(pages_.size()))\r
2007     next_page_to_search_ = 0;\r
2008   // If there's only one page in the document and we start searching midway,\r
2009   // then we'll want to search the page one more time.\r
2010   bool end_of_search =\r
2011       next_page_to_search_ == last_page_to_search_ &&\r
2012       // Only one page but didn't start midway.\r
2013       ((pages_.size() == 1 && last_character_index_to_search_ == -1) ||\r
2014        // Started midway, but only 1 page and we already looped around.\r
2015        (pages_.size() == 1 && !first_search) ||\r
2016        // Started midway, and we've just looped around.\r
2017        (pages_.size() > 1 && current_page == next_page_to_search_));\r
2018 \r
2019   if (end_of_search) {\r
2020     // Send the final notification.\r
2021     client_->NotifyNumberOfFindResultsChanged(find_results_.size(), true);\r
2022 \r
2023     // When searching is complete, resume finding at a particular index.\r
2024     if (resume_find_index_ != -1) {\r
2025       current_find_index_ = resume_find_index_;\r
2026       resume_find_index_ = -1;\r
2027     }\r
2028   } else {\r
2029     pp::CompletionCallback callback =\r
2030         find_factory_.NewCallback(&PDFiumEngine::ContinueFind);\r
2031     pp::Module::Get()->core()->CallOnMainThread(\r
2032         0, callback, case_sensitive ? 1 : 0);\r
2033   }\r
2034 }\r
2035 \r
2036 void PDFiumEngine::SearchUsingPDFium(const base::string16& term,\r
2037                                      bool case_sensitive,\r
2038                                      bool first_search,\r
2039                                      int character_to_start_searching_from,\r
2040                                      int current_page) {\r
2041   // Find all the matches in the current page.\r
2042   unsigned long flags = case_sensitive ? FPDF_MATCHCASE : 0;\r
2043   FPDF_SCHHANDLE find = FPDFText_FindStart(\r
2044       pages_[current_page]->GetTextPage(),\r
2045       reinterpret_cast<const unsigned short*>(term.c_str()),\r
2046       flags, character_to_start_searching_from);\r
2047 \r
2048   // Note: since we search one page at a time, we don't find matches across\r
2049   // page boundaries.  We could do this manually ourself, but it seems low\r
2050   // priority since Reader itself doesn't do it.\r
2051   while (FPDFText_FindNext(find)) {\r
2052     PDFiumRange result(pages_[current_page],\r
2053                        FPDFText_GetSchResultIndex(find),\r
2054                        FPDFText_GetSchCount(find));\r
2055 \r
2056     if (!first_search &&\r
2057         last_character_index_to_search_ != -1 &&\r
2058         result.page_index() == last_page_to_search_ &&\r
2059         result.char_index() >= last_character_index_to_search_) {\r
2060       break;\r
2061     }\r
2062 \r
2063     AddFindResult(result);\r
2064   }\r
2065 \r
2066   FPDFText_FindClose(find);\r
2067 }\r
2068 \r
2069 void PDFiumEngine::SearchUsingICU(const base::string16& term,\r
2070                                   bool case_sensitive,\r
2071                                   bool first_search,\r
2072                                   int character_to_start_searching_from,\r
2073                                   int current_page) {\r
2074   base::string16 page_text;\r
2075   int text_length = pages_[current_page]->GetCharCount();\r
2076   if (character_to_start_searching_from) {\r
2077     text_length -= character_to_start_searching_from;\r
2078   } else if (!first_search &&\r
2079              last_character_index_to_search_ != -1 &&\r
2080              current_page == last_page_to_search_) {\r
2081     text_length = last_character_index_to_search_;\r
2082   }\r
2083   if (text_length <= 0)\r
2084     return;\r
2085   unsigned short* data =\r
2086       reinterpret_cast<unsigned short*>(WriteInto(&page_text, text_length + 1));\r
2087   FPDFText_GetText(pages_[current_page]->GetTextPage(),\r
2088                    character_to_start_searching_from,\r
2089                    text_length,\r
2090                    data);\r
2091   std::vector<PDFEngine::Client::SearchStringResult> results;\r
2092   client_->SearchString(\r
2093       page_text.c_str(), term.c_str(), case_sensitive, &results);\r
2094   for (size_t i = 0; i < results.size(); ++i) {\r
2095     // Need to map the indexes from the page text, which may have generated\r
2096     // characters like space etc, to character indices from the page.\r
2097     int temp_start = results[i].start_index + character_to_start_searching_from;\r
2098     int start = FPDFText_GetCharIndexFromTextIndex(\r
2099         pages_[current_page]->GetTextPage(), temp_start);\r
2100     int end = FPDFText_GetCharIndexFromTextIndex(\r
2101         pages_[current_page]->GetTextPage(),\r
2102         temp_start + results[i].length);\r
2103     AddFindResult(PDFiumRange(pages_[current_page], start, end - start));\r
2104   }\r
2105 }\r
2106 \r
2107 void PDFiumEngine::AddFindResult(const PDFiumRange& result) {\r
2108   // Figure out where to insert the new location, since we could have\r
2109   // started searching midway and now we wrapped.\r
2110   size_t i;\r
2111   int page_index = result.page_index();\r
2112   int char_index = result.char_index();\r
2113   for (i = 0; i < find_results_.size(); ++i) {\r
2114     if (find_results_[i].page_index() > page_index ||\r
2115         (find_results_[i].page_index() == page_index &&\r
2116          find_results_[i].char_index() > char_index)) {\r
2117       break;\r
2118     }\r
2119   }\r
2120   find_results_.insert(find_results_.begin() + i, result);\r
2121   UpdateTickMarks();\r
2122 \r
2123   if (current_find_index_ == -1 && resume_find_index_ == -1) {\r
2124     // Select the first match.\r
2125     SelectFindResult(true);\r
2126   } else if (static_cast<int>(i) <= current_find_index_) {\r
2127     // Update the current match index\r
2128     current_find_index_++;\r
2129     client_->NotifySelectedFindResultChanged(current_find_index_);\r
2130   }\r
2131   client_->NotifyNumberOfFindResultsChanged(find_results_.size(), false);\r
2132 }\r
2133 \r
2134 bool PDFiumEngine::SelectFindResult(bool forward) {\r
2135   if (find_results_.empty()) {\r
2136     NOTREACHED();\r
2137     return false;\r
2138   }\r
2139 \r
2140   SelectionChangeInvalidator selection_invalidator(this);\r
2141 \r
2142   // Move back/forward through the search locations we previously found.\r
2143   if (forward) {\r
2144     if (++current_find_index_ == static_cast<int>(find_results_.size()))\r
2145       current_find_index_ = 0;\r
2146   } else {\r
2147     if (--current_find_index_ < 0) {\r
2148       current_find_index_ = find_results_.size() - 1;\r
2149     }\r
2150   }\r
2151 \r
2152   // Update the selection before telling the client to scroll, since it could\r
2153   // paint then.\r
2154   selection_.clear();\r
2155   selection_.push_back(find_results_[current_find_index_]);\r
2156 \r
2157   // If the result is not in view, scroll to it.\r
2158   size_t i;\r
2159   pp::Rect bounding_rect;\r
2160   pp::Rect visible_rect = GetVisibleRect();\r
2161   // Use zoom of 1.0 since visible_rect is without zoom.\r
2162   std::vector<pp::Rect> rects = find_results_[current_find_index_].\r
2163       GetScreenRects(pp::Point(), 1.0, current_rotation_);\r
2164   for (i = 0; i < rects.size(); ++i)\r
2165     bounding_rect = bounding_rect.Union(rects[i]);\r
2166   if (!visible_rect.Contains(bounding_rect)) {\r
2167     pp::Point center = bounding_rect.CenterPoint();\r
2168     // Make the page centered.\r
2169     int new_y = static_cast<int>(center.y() * current_zoom_) -\r
2170                 static_cast<int>(visible_rect.height() * current_zoom_ / 2);\r
2171     if (new_y < 0)\r
2172       new_y = 0;\r
2173     client_->ScrollToY(new_y);\r
2174 \r
2175     // Only move horizontally if it's not visible.\r
2176     if (center.x() < visible_rect.x() || center.x() > visible_rect.right()) {\r
2177       int new_x = static_cast<int>(center.x()  * current_zoom_) -\r
2178                   static_cast<int>(visible_rect.width() * current_zoom_ / 2);\r
2179       if (new_x < 0)\r
2180         new_x = 0;\r
2181       client_->ScrollToX(new_x);\r
2182     }\r
2183   }\r
2184 \r
2185   client_->NotifySelectedFindResultChanged(current_find_index_);\r
2186 \r
2187   return true;\r
2188 }\r
2189 \r
2190 void PDFiumEngine::StopFind() {\r
2191   SelectionChangeInvalidator selection_invalidator(this);\r
2192 \r
2193   selection_.clear();\r
2194   selecting_ = false;\r
2195   find_results_.clear();\r
2196   next_page_to_search_ = -1;\r
2197   last_page_to_search_ = -1;\r
2198   last_character_index_to_search_ = -1;\r
2199   current_find_index_ = -1;\r
2200   current_find_text_.clear();\r
2201   UpdateTickMarks();\r
2202   find_factory_.CancelAll();\r
2203 }\r
2204 \r
2205 void PDFiumEngine::UpdateTickMarks() {\r
2206   std::vector<pp::Rect> tickmarks;\r
2207   for (size_t i = 0; i < find_results_.size(); ++i) {\r
2208     pp::Rect rect;\r
2209     // Always use an origin of 0,0 since scroll positions don't affect tickmark.\r
2210     std::vector<pp::Rect> rects = find_results_[i].GetScreenRects(\r
2211       pp::Point(0, 0), current_zoom_, current_rotation_);\r
2212     for (size_t j = 0; j < rects.size(); ++j)\r
2213       rect = rect.Union(rects[j]);\r
2214     tickmarks.push_back(rect);\r
2215   }\r
2216 \r
2217   client_->UpdateTickMarks(tickmarks);\r
2218 }\r
2219 \r
2220 void PDFiumEngine::ZoomUpdated(double new_zoom_level) {\r
2221   CancelPaints();\r
2222 \r
2223   current_zoom_ = new_zoom_level;\r
2224 \r
2225   CalculateVisiblePages();\r
2226   UpdateTickMarks();\r
2227 }\r
2228 \r
2229 void PDFiumEngine::RotateClockwise() {\r
2230   current_rotation_ = (current_rotation_ + 1) % 4;\r
2231 \r
2232   // Store the current find index so that we can resume finding at that\r
2233   // particular index after we have recomputed the find results.\r
2234   std::string current_find_text = current_find_text_;\r
2235   resume_find_index_ = current_find_index_;\r
2236 \r
2237   InvalidateAllPages();\r
2238 \r
2239   if (!current_find_text.empty())\r
2240     StartFind(current_find_text.c_str(), false);\r
2241 }\r
2242 \r
2243 void PDFiumEngine::RotateCounterclockwise() {\r
2244   current_rotation_ = (current_rotation_ - 1) % 4;\r
2245 \r
2246   // Store the current find index so that we can resume finding at that\r
2247   // particular index after we have recomputed the find results.\r
2248   std::string current_find_text = current_find_text_;\r
2249   resume_find_index_ = current_find_index_;\r
2250 \r
2251   InvalidateAllPages();\r
2252 \r
2253   if (!current_find_text.empty())\r
2254     StartFind(current_find_text.c_str(), false);\r
2255 }\r
2256 \r
2257 void PDFiumEngine::InvalidateAllPages() {\r
2258   CancelPaints();\r
2259   StopFind();\r
2260   LoadPageInfo(true);\r
2261   client_->Invalidate(pp::Rect(plugin_size_));\r
2262 }\r
2263 \r
2264 std::string PDFiumEngine::GetSelectedText() {\r
2265   base::string16 result;\r
2266   for (size_t i = 0; i < selection_.size(); ++i) {\r
2267     if (i > 0 &&\r
2268         selection_[i - 1].page_index() > selection_[i].page_index()) {\r
2269       result = selection_[i].GetText() + result;\r
2270     } else {\r
2271       result.append(selection_[i].GetText());\r
2272     }\r
2273   }\r
2274 \r
2275   FormatStringWithHyphens(&result);\r
2276   FormatStringForOS(&result);\r
2277   return base::UTF16ToUTF8(result);\r
2278 }\r
2279 \r
2280 std::string PDFiumEngine::GetLinkAtPosition(const pp::Point& point) {\r
2281   int temp;\r
2282   PDFiumPage::LinkTarget target;\r
2283   pp::Point point_in_page(\r
2284       static_cast<int>((point.x() + position_.x()) / current_zoom_),\r
2285       static_cast<int>((point.y() + position_.y()) / current_zoom_));\r
2286   PDFiumPage::Area area = GetCharIndex(point_in_page, &temp, &temp, &target);\r
2287   if (area == PDFiumPage::WEBLINK_AREA)\r
2288     return target.url;\r
2289   return std::string();\r
2290 }\r
2291 \r
2292 bool PDFiumEngine::IsSelecting() {\r
2293   return selecting_;\r
2294 }\r
2295 \r
2296 bool PDFiumEngine::HasPermission(DocumentPermission permission) const {\r
2297   switch (permission) {\r
2298     case PERMISSION_COPY:\r
2299       return (permissions_ & kPDFPermissionCopyMask) != 0;\r
2300     case PERMISSION_COPY_ACCESSIBLE:\r
2301       return (permissions_ & kPDFPermissionCopyAccessibleMask) != 0;\r
2302     case PERMISSION_PRINT_LOW_QUALITY:\r
2303       return (permissions_ & kPDFPermissionPrintLowQualityMask) != 0;\r
2304     case PERMISSION_PRINT_HIGH_QUALITY:\r
2305       return (permissions_ & kPDFPermissionPrintLowQualityMask) != 0 &&\r
2306              (permissions_ & kPDFPermissionPrintHighQualityMask) != 0;\r
2307     default:\r
2308       return true;\r
2309   };\r
2310 }\r
2311 \r
2312 void PDFiumEngine::SelectAll() {\r
2313   SelectionChangeInvalidator selection_invalidator(this);\r
2314 \r
2315   selection_.clear();\r
2316   for (size_t i = 0; i < pages_.size(); ++i)\r
2317     if (pages_[i]->available()) {\r
2318       selection_.push_back(PDFiumRange(pages_[i], 0,\r
2319                            pages_[i]->GetCharCount()));\r
2320     }\r
2321 }\r
2322 \r
2323 int PDFiumEngine::GetNumberOfPages() {\r
2324   return pages_.size();\r
2325 }\r
2326 \r
2327 int PDFiumEngine::GetNamedDestinationPage(const std::string& destination) {\r
2328   // Look for the destination.\r
2329   FPDF_DEST dest = FPDF_GetNamedDestByName(doc_, destination.c_str());\r
2330   if (!dest) {\r
2331     // Look for a bookmark with the same name.\r
2332     base::string16 destination_wide = base::UTF8ToUTF16(destination);\r
2333     FPDF_WIDESTRING destination_pdf_wide =\r
2334         reinterpret_cast<FPDF_WIDESTRING>(destination_wide.c_str());\r
2335     FPDF_BOOKMARK bookmark = FPDFBookmark_Find(doc_, destination_pdf_wide);\r
2336     if (!bookmark)\r
2337       return -1;\r
2338     dest = FPDFBookmark_GetDest(doc_, bookmark);\r
2339   }\r
2340   return dest ? FPDFDest_GetPageIndex(doc_, dest) : -1;\r
2341 }\r
2342 \r
2343 int PDFiumEngine::GetFirstVisiblePage() {\r
2344   CalculateVisiblePages();\r
2345   return first_visible_page_;\r
2346 }\r
2347 \r
2348 int PDFiumEngine::GetMostVisiblePage() {\r
2349   CalculateVisiblePages();\r
2350   return most_visible_page_;\r
2351 }\r
2352 \r
2353 pp::Rect PDFiumEngine::GetPageRect(int index) {\r
2354   pp::Rect rc(pages_[index]->rect());\r
2355   rc.Inset(-kPageShadowLeft, -kPageShadowTop,\r
2356            -kPageShadowRight, -kPageShadowBottom);\r
2357   return rc;\r
2358 }\r
2359 \r
2360 pp::Rect PDFiumEngine::GetPageContentsRect(int index) {\r
2361   return GetScreenRect(pages_[index]->rect());\r
2362 }\r
2363 \r
2364 void PDFiumEngine::PaintThumbnail(pp::ImageData* image_data, int index) {\r
2365   FPDF_BITMAP bitmap = FPDFBitmap_CreateEx(\r
2366       image_data->size().width(), image_data->size().height(),\r
2367       FPDFBitmap_BGRx, image_data->data(), image_data->stride());\r
2368 \r
2369   if (pages_[index]->available()) {\r
2370     FPDFBitmap_FillRect(bitmap, 0, 0, image_data->size().width(),\r
2371                         image_data->size().height(), 0xFFFFFFFF);\r
2372 \r
2373     FPDF_RenderPageBitmap(\r
2374         bitmap, pages_[index]->GetPage(), 0, 0, image_data->size().width(),\r
2375         image_data->size().height(), 0, GetRenderingFlags());\r
2376   } else {\r
2377     FPDFBitmap_FillRect(bitmap, 0, 0, image_data->size().width(),\r
2378                         image_data->size().height(), kPendingPageColor);\r
2379   }\r
2380 \r
2381   FPDFBitmap_Destroy(bitmap);\r
2382 }\r
2383 \r
2384 void PDFiumEngine::SetGrayscale(bool grayscale) {\r
2385   render_grayscale_ = grayscale;\r
2386 }\r
2387 \r
2388 void PDFiumEngine::OnCallback(int id) {\r
2389   if (!timers_.count(id))\r
2390     return;\r
2391 \r
2392   timers_[id].second(id);\r
2393   if (timers_.count(id))  // The callback might delete the timer.\r
2394     client_->ScheduleCallback(id, timers_[id].first);\r
2395 }\r
2396 \r
2397 std::string PDFiumEngine::GetPageAsJSON(int index) {\r
2398   if (!(HasPermission(PERMISSION_COPY) ||\r
2399         HasPermission(PERMISSION_COPY_ACCESSIBLE))) {\r
2400     return "{}";\r
2401   }\r
2402 \r
2403   if (index < 0 || static_cast<size_t>(index) > pages_.size() - 1)\r
2404     return "{}";\r
2405 \r
2406   scoped_ptr<base::Value> node(\r
2407       pages_[index]->GetAccessibleContentAsValue(current_rotation_));\r
2408   std::string page_json;\r
2409   base::JSONWriter::Write(node.get(), &page_json);\r
2410   return page_json;\r
2411 }\r
2412 \r
2413 bool PDFiumEngine::GetPrintScaling() {\r
2414   return !!FPDF_VIEWERREF_GetPrintScaling(doc_);\r
2415 }\r
2416 \r
2417 void PDFiumEngine::AppendBlankPages(int num_pages) {\r
2418   DCHECK(num_pages != 0);\r
2419 \r
2420   if (!doc_)\r
2421     return;\r
2422 \r
2423   selection_.clear();\r
2424   pending_pages_.clear();\r
2425 \r
2426   // Delete all pages except the first one.\r
2427   while (pages_.size() > 1) {\r
2428     delete pages_.back();\r
2429     pages_.pop_back();\r
2430     FPDFPage_Delete(doc_, pages_.size());\r
2431   }\r
2432 \r
2433   // Calculate document size and all page sizes.\r
2434   std::vector<pp::Rect> page_rects;\r
2435   pp::Size page_size = GetPageSize(0);\r
2436   page_size.Enlarge(kPageShadowLeft + kPageShadowRight,\r
2437                     kPageShadowTop + kPageShadowBottom);\r
2438   pp::Size old_document_size = document_size_;\r
2439   document_size_ = pp::Size(page_size.width(), 0);\r
2440   for (int i = 0; i < num_pages; ++i) {\r
2441     if (i != 0) {\r
2442       // Add space for horizontal separator.\r
2443       document_size_.Enlarge(0, kPageSeparatorThickness);\r
2444     }\r
2445 \r
2446     pp::Rect rect(pp::Point(0, document_size_.height()), page_size);\r
2447     page_rects.push_back(rect);\r
2448 \r
2449     document_size_.Enlarge(0, page_size.height());\r
2450   }\r
2451 \r
2452   // Create blank pages.\r
2453   for (int i = 1; i < num_pages; ++i) {\r
2454     pp::Rect page_rect(page_rects[i]);\r
2455     page_rect.Inset(kPageShadowLeft, kPageShadowTop,\r
2456                     kPageShadowRight, kPageShadowBottom);\r
2457     double width_in_points =\r
2458         page_rect.width() * kPointsPerInch / kPixelsPerInch;\r
2459     double height_in_points =\r
2460         page_rect.height() * kPointsPerInch / kPixelsPerInch;\r
2461     FPDFPage_New(doc_, i, width_in_points, height_in_points);\r
2462     pages_.push_back(new PDFiumPage(this, i, page_rect, true));\r
2463   }\r
2464 \r
2465   CalculateVisiblePages();\r
2466   if (document_size_ != old_document_size)\r
2467     client_->DocumentSizeUpdated(document_size_);\r
2468 }\r
2469 \r
2470 void PDFiumEngine::LoadDocument() {\r
2471   // Check if the document is ready for loading. If it isn't just bail for now,\r
2472   // we will call LoadDocument() again later.\r
2473   if (!doc_ && !doc_loader_.IsDocumentComplete() &&\r
2474       !FPDFAvail_IsDocAvail(fpdf_availability_, &download_hints_)) {\r
2475     return;\r
2476   }\r
2477 \r
2478   // If we're in the middle of getting a password, just return. We will retry\r
2479   // loading the document after we get the password anyway.\r
2480   if (getting_password_)\r
2481     return;\r
2482 \r
2483   ScopedUnsupportedFeature scoped_unsupported_feature(this);\r
2484   bool needs_password = false;\r
2485   if (TryLoadingDoc(false, std::string(), &needs_password)) {\r
2486     ContinueLoadingDocument(false, std::string());\r
2487     return;\r
2488   }\r
2489   if (needs_password)\r
2490     GetPasswordAndLoad();\r
2491   else\r
2492     client_->DocumentLoadFailed();\r
2493 }\r
2494 \r
2495 bool PDFiumEngine::TryLoadingDoc(bool with_password,\r
2496                                  const std::string& password,\r
2497                                  bool* needs_password) {\r
2498   *needs_password = false;\r
2499   if (doc_)\r
2500     return true;\r
2501 \r
2502   const char* password_cstr = NULL;\r
2503   if (with_password) {\r
2504     password_cstr = password.c_str();\r
2505     password_tries_remaining_--;\r
2506   }\r
2507   if (doc_loader_.IsDocumentComplete())\r
2508     doc_ = FPDF_LoadCustomDocument(&file_access_, password_cstr);\r
2509   else\r
2510     doc_ = FPDFAvail_GetDocument(fpdf_availability_, password_cstr);\r
2511 \r
2512   if (!doc_ && FPDF_GetLastError() == FPDF_ERR_PASSWORD)\r
2513     *needs_password = true;\r
2514 \r
2515   return doc_ != NULL;\r
2516 }\r
2517 \r
2518 void PDFiumEngine::GetPasswordAndLoad() {\r
2519   getting_password_ = true;\r
2520   DCHECK(!doc_ && FPDF_GetLastError() == FPDF_ERR_PASSWORD);\r
2521   client_->GetDocumentPassword(password_factory_.NewCallbackWithOutput(\r
2522       &PDFiumEngine::OnGetPasswordComplete));\r
2523 }\r
2524 \r
2525 void PDFiumEngine::OnGetPasswordComplete(int32_t result,\r
2526                                          const pp::Var& password) {\r
2527   getting_password_ = false;\r
2528 \r
2529   bool password_given = false;\r
2530   std::string password_text;\r
2531   if (result == PP_OK && password.is_string()) {\r
2532     password_text = password.AsString();\r
2533     if (!password_text.empty())\r
2534       password_given = true;\r
2535   }\r
2536   ContinueLoadingDocument(password_given, password_text);\r
2537 }\r
2538 \r
2539 void PDFiumEngine::ContinueLoadingDocument(\r
2540     bool has_password,\r
2541     const std::string& password) {\r
2542   ScopedUnsupportedFeature scoped_unsupported_feature(this);\r
2543 \r
2544   bool needs_password = false;\r
2545   bool loaded = TryLoadingDoc(has_password, password, &needs_password);\r
2546   bool password_incorrect = !loaded && has_password && needs_password;\r
2547   if (password_incorrect && password_tries_remaining_ > 0) {\r
2548     GetPasswordAndLoad();\r
2549     return;\r
2550   }\r
2551 \r
2552   if (!doc_) {\r
2553     client_->DocumentLoadFailed();\r
2554     return;\r
2555   }\r
2556 \r
2557   if (FPDFDoc_GetPageMode(doc_) == PAGEMODE_USEOUTLINES)\r
2558     client_->DocumentHasUnsupportedFeature("Bookmarks");\r
2559 \r
2560   permissions_ = FPDF_GetDocPermissions(doc_);\r
2561 \r
2562   if (!form_) {\r
2563     // Only returns 0 when data isn't available.  If form data is downloaded, or\r
2564     // if this isn't a form, returns positive values.\r
2565     if (!doc_loader_.IsDocumentComplete() &&\r
2566         !FPDFAvail_IsFormAvail(fpdf_availability_, &download_hints_)) {\r
2567       return;\r
2568     }\r
2569 \r
2570     form_ = FPDFDOC_InitFormFillEnviroument(\r
2571         doc_, static_cast<FPDF_FORMFILLINFO*>(this));\r
2572 #ifdef _TEST_XFA\r
2573         FPDF_LoadXFA(doc_);\r
2574 #endif\r
2575 \r
2576     FPDF_SetFormFieldHighlightColor(form_, 0, kFormHighlightColor);\r
2577     FPDF_SetFormFieldHighlightAlpha(form_, kFormHighlightAlpha);\r
2578   }\r
2579 \r
2580   if (!doc_loader_.IsDocumentComplete()) {\r
2581     // Check if the first page is available.  In a linearized PDF, that is not\r
2582     // always page 0.  Doing this gives us the default page size, since when the\r
2583     // document is available, the first page is available as well.\r
2584     CheckPageAvailable(FPDFAvail_GetFirstPageNum(doc_), &pending_pages_);\r
2585   }\r
2586 \r
2587   LoadPageInfo(false);\r
2588 \r
2589   if (doc_loader_.IsDocumentComplete())\r
2590     FinishLoadingDocument();\r
2591 }\r
2592 \r
2593 void PDFiumEngine::LoadPageInfo(bool reload) {\r
2594   pending_pages_.clear();\r
2595   pp::Size old_document_size = document_size_;\r
2596   document_size_ = pp::Size();\r
2597   std::vector<pp::Rect> page_rects;\r
2598   int page_count = FPDF_GetPageCount(doc_);\r
2599   bool doc_complete = doc_loader_.IsDocumentComplete();\r
2600   for (int i = 0; i < page_count; ++i) {\r
2601     if (i != 0) {\r
2602       // Add space for horizontal separator.\r
2603       document_size_.Enlarge(0, kPageSeparatorThickness);\r
2604     }\r
2605 \r
2606     // Get page availability. If reload==false, and document is not loaded yet\r
2607     // (we are using async loading) - mark all pages as unavailable.\r
2608     // If reload==true (we have document constructed already), get page\r
2609     // availability flag from already existing PDFiumPage class.\r
2610     bool page_available = reload ? pages_[i]->available() : doc_complete;\r
2611 \r
2612     pp::Size size = page_available ? GetPageSize(i) : default_page_size_;\r
2613     size.Enlarge(kPageShadowLeft + kPageShadowRight,\r
2614                  kPageShadowTop + kPageShadowBottom);\r
2615     pp::Rect rect(pp::Point(0, document_size_.height()), size);\r
2616     page_rects.push_back(rect);\r
2617 \r
2618     if (size.width() > document_size_.width())\r
2619       document_size_.set_width(size.width());\r
2620 \r
2621     document_size_.Enlarge(0, size.height());\r
2622   }\r
2623 \r
2624   for (int i = 0; i < page_count; ++i) {\r
2625     // Center pages relative to the entire document.\r
2626     page_rects[i].set_x((document_size_.width() - page_rects[i].width()) / 2);\r
2627     pp::Rect page_rect(page_rects[i]);\r
2628     page_rect.Inset(kPageShadowLeft, kPageShadowTop,\r
2629                     kPageShadowRight, kPageShadowBottom);\r
2630     if (reload) {\r
2631       pages_[i]->set_rect(page_rect);\r
2632     } else {\r
2633       pages_.push_back(new PDFiumPage(this, i, page_rect, doc_complete));\r
2634     }\r
2635   }\r
2636 \r
2637   CalculateVisiblePages();\r
2638   if (document_size_ != old_document_size)\r
2639     client_->DocumentSizeUpdated(document_size_);\r
2640 }\r
2641 \r
2642 void PDFiumEngine::CalculateVisiblePages() {\r
2643   // Clear pending requests queue, since it may contain requests to the pages\r
2644   // that are already invisible (after scrolling for example).\r
2645   pending_pages_.clear();\r
2646   doc_loader_.ClearPendingRequests();\r
2647 \r
2648   visible_pages_.clear();\r
2649   pp::Rect visible_rect(plugin_size_);\r
2650   for (size_t i = 0; i < pages_.size(); ++i) {\r
2651     // Check an entire PageScreenRect, since we might need to repaint side\r
2652     // borders and shadows even if the page itself is not visible.\r
2653     // For example, when user use pdf with different page sizes and zoomed in\r
2654     // outside page area.\r
2655     if (visible_rect.Intersects(GetPageScreenRect(i))) {\r
2656       visible_pages_.push_back(i);\r
2657       CheckPageAvailable(i, &pending_pages_);\r
2658     } else {\r
2659       // Need to unload pages when we're not using them, since some PDFs use a\r
2660       // lot of memory.  See http://crbug.com/48791\r
2661       if (defer_page_unload_) {\r
2662         deferred_page_unloads_.push_back(i);\r
2663       } else {\r
2664         pages_[i]->Unload();\r
2665       }\r
2666 \r
2667       // If the last mouse down was on a page that's no longer visible, reset\r
2668       // that variable so that we don't send keyboard events to it (the focus\r
2669       // will be lost when the page is first closed anyways).\r
2670       if (static_cast<int>(i) == last_page_mouse_down_)\r
2671         last_page_mouse_down_ = -1;\r
2672     }\r
2673   }\r
2674 \r
2675   // Any pending highlighting of form fields will be invalid since these are in\r
2676   // screen coordinates.\r
2677   form_highlights_.clear();\r
2678 \r
2679   if (visible_pages_.size() == 0)\r
2680     first_visible_page_ = -1;\r
2681   else\r
2682     first_visible_page_ = visible_pages_.front();\r
2683 \r
2684   int most_visible_page = first_visible_page_;\r
2685   // Check if the next page is more visible than the first one.\r
2686   if (most_visible_page != -1 &&\r
2687       pages_.size() > 0 &&\r
2688       most_visible_page < static_cast<int>(pages_.size()) - 1) {\r
2689     pp::Rect rc_first =\r
2690         visible_rect.Intersect(GetPageScreenRect(most_visible_page));\r
2691     pp::Rect rc_next =\r
2692         visible_rect.Intersect(GetPageScreenRect(most_visible_page + 1));\r
2693     if (rc_next.height() > rc_first.height())\r
2694       most_visible_page++;\r
2695   }\r
2696 \r
2697   SetCurrentPage(most_visible_page);\r
2698 }\r
2699 \r
2700 bool PDFiumEngine::IsPageVisible(int index) const {\r
2701   for (size_t i = 0; i < visible_pages_.size(); ++i) {\r
2702     if (visible_pages_[i] == index)\r
2703       return true;\r
2704   }\r
2705 \r
2706   return false;\r
2707 }\r
2708 \r
2709 bool PDFiumEngine::CheckPageAvailable(int index, std::vector<int>* pending) {\r
2710   if (!doc_ || !form_)\r
2711     return false;\r
2712 \r
2713   if (static_cast<int>(pages_.size()) > index && pages_[index]->available())\r
2714     return true;\r
2715 \r
2716   if (!FPDFAvail_IsPageAvail(fpdf_availability_, index, &download_hints_)) {\r
2717     size_t j;\r
2718     for (j = 0; j < pending->size(); ++j) {\r
2719       if ((*pending)[j] == index)\r
2720         break;\r
2721     }\r
2722 \r
2723     if (j == pending->size())\r
2724       pending->push_back(index);\r
2725     return false;\r
2726   }\r
2727 \r
2728   if (static_cast<int>(pages_.size()) > index)\r
2729     pages_[index]->set_available(true);\r
2730   if (!default_page_size_.GetArea())\r
2731     default_page_size_ = GetPageSize(index);\r
2732   return true;\r
2733 }\r
2734 \r
2735 pp::Size PDFiumEngine::GetPageSize(int index) {\r
2736   pp::Size size;\r
2737   double width_in_points = 0;\r
2738   double height_in_points = 0;\r
2739   int rv = FPDF_GetPageSizeByIndex(\r
2740       doc_, index, &width_in_points, &height_in_points);\r
2741 \r
2742   if (rv) {\r
2743     int width_in_pixels = static_cast<int>(\r
2744         width_in_points * kPixelsPerInch / kPointsPerInch);\r
2745     int height_in_pixels = static_cast<int>(\r
2746         height_in_points * kPixelsPerInch / kPointsPerInch);\r
2747     if (current_rotation_ % 2 == 1)\r
2748       std::swap(width_in_pixels, height_in_pixels);\r
2749     size = pp::Size(width_in_pixels, height_in_pixels);\r
2750   }\r
2751   return size;\r
2752 }\r
2753 \r
2754 int PDFiumEngine::StartPaint(int page_index, const pp::Rect& dirty) {\r
2755   // For the first time we hit paint, do nothing and just record the paint for\r
2756   // the next callback.  This keeps the UI responsive in case the user is doing\r
2757   // a lot of scrolling.\r
2758   ProgressivePaint progressive;\r
2759   progressive.rect = dirty;\r
2760   progressive.page_index = page_index;\r
2761   progressive.bitmap = NULL;\r
2762   progressive.painted_ = false;\r
2763   progressive_paints_.push_back(progressive);\r
2764   return progressive_paints_.size() - 1;\r
2765 }\r
2766 \r
2767 bool PDFiumEngine::ContinuePaint(int progressive_index,\r
2768                                  pp::ImageData* image_data) {\r
2769 #if defined(OS_LINUX)\r
2770   g_last_instance_id = client_->GetPluginInstance()->pp_instance();\r
2771 #endif\r
2772 \r
2773   int rv;\r
2774   int page_index = progressive_paints_[progressive_index].page_index;\r
2775   last_progressive_start_time_ = base::Time::Now();\r
2776   if (progressive_paints_[progressive_index].bitmap) {\r
2777     rv = FPDF_RenderPage_Continue(\r
2778         pages_[page_index]->GetPage(), static_cast<IFSDK_PAUSE*>(this));\r
2779   } else {\r
2780     pp::Rect dirty = progressive_paints_[progressive_index].rect;\r
2781     progressive_paints_[progressive_index].bitmap = CreateBitmap(dirty,\r
2782                                                                  image_data);\r
2783     int start_x, start_y, size_x, size_y;\r
2784     GetPDFiumRect(\r
2785         page_index, dirty, &start_x, &start_y, &size_x, &size_y);\r
2786     FPDFBitmap_FillRect(progressive_paints_[progressive_index].bitmap, start_x,\r
2787                         start_y, size_x, size_y, 0xFFFFFFFF);\r
2788     rv = FPDF_RenderPageBitmap_Start(\r
2789         progressive_paints_[progressive_index].bitmap,\r
2790         pages_[page_index]->GetPage(), start_x, start_y, size_x, size_y,\r
2791         current_rotation_,\r
2792         GetRenderingFlags(), static_cast<IFSDK_PAUSE*>(this));\r
2793   }\r
2794   return rv != FPDF_RENDER_TOBECOUNTINUED;\r
2795 }\r
2796 \r
2797 void PDFiumEngine::FinishPaint(int progressive_index,\r
2798                                pp::ImageData* image_data) {\r
2799   int page_index = progressive_paints_[progressive_index].page_index;\r
2800   pp::Rect dirty_in_screen = progressive_paints_[progressive_index].rect;\r
2801   FPDF_BITMAP bitmap = progressive_paints_[progressive_index].bitmap;\r
2802   int start_x, start_y, size_x, size_y;\r
2803   GetPDFiumRect(\r
2804       page_index, dirty_in_screen, &start_x, &start_y, &size_x, &size_y);\r
2805 \r
2806   // Draw the forms.\r
2807   FPDF_FFLDraw(\r
2808       form_, bitmap, pages_[page_index]->GetPage(), start_x, start_y, size_x,\r
2809       size_y, current_rotation_, GetRenderingFlags());\r
2810 \r
2811   FillPageSides(progressive_index);\r
2812 \r
2813   // Paint the page shadows.\r
2814   PaintPageShadow(progressive_index, image_data);\r
2815 \r
2816   DrawSelections(progressive_index, image_data);\r
2817 \r
2818   FPDF_RenderPage_Close(pages_[page_index]->GetPage());\r
2819   FPDFBitmap_Destroy(bitmap);\r
2820   progressive_paints_.erase(progressive_paints_.begin() + progressive_index);\r
2821 \r
2822   client_->DocumentPaintOccurred();\r
2823 }\r
2824 \r
2825 void PDFiumEngine::CancelPaints() {\r
2826   for (size_t i = 0; i < progressive_paints_.size(); ++i) {\r
2827     FPDF_RenderPage_Close(pages_[progressive_paints_[i].page_index]->GetPage());\r
2828     FPDFBitmap_Destroy(progressive_paints_[i].bitmap);\r
2829   }\r
2830   progressive_paints_.clear();\r
2831 }\r
2832 \r
2833 void PDFiumEngine::FillPageSides(int progressive_index) {\r
2834   int page_index = progressive_paints_[progressive_index].page_index;\r
2835   pp::Rect dirty_in_screen = progressive_paints_[progressive_index].rect;\r
2836   FPDF_BITMAP bitmap = progressive_paints_[progressive_index].bitmap;\r
2837 \r
2838   pp::Rect page_rect = pages_[page_index]->rect();\r
2839   if (page_rect.x() > 0) {\r
2840     pp::Rect left(0,\r
2841                   page_rect.y() - kPageShadowTop,\r
2842                   page_rect.x() - kPageShadowLeft,\r
2843                   page_rect.height() + kPageShadowTop +\r
2844                       kPageShadowBottom + kPageSeparatorThickness);\r
2845     left = GetScreenRect(left).Intersect(dirty_in_screen);\r
2846 \r
2847     FPDFBitmap_FillRect(bitmap, left.x() - dirty_in_screen.x(),\r
2848                         left.y() - dirty_in_screen.y(), left.width(),\r
2849                         left.height(), kBackgroundColor);\r
2850   }\r
2851 \r
2852   if (page_rect.right() < document_size_.width()) {\r
2853     pp::Rect right(page_rect.right() + kPageShadowRight,\r
2854                    page_rect.y() - kPageShadowTop,\r
2855                    document_size_.width() - page_rect.right() -\r
2856                       kPageShadowRight,\r
2857                    page_rect.height() + kPageShadowTop +\r
2858                        kPageShadowBottom + kPageSeparatorThickness);\r
2859     right = GetScreenRect(right).Intersect(dirty_in_screen);\r
2860 \r
2861     FPDFBitmap_FillRect(bitmap, right.x() - dirty_in_screen.x(),\r
2862                         right.y() - dirty_in_screen.y(), right.width(),\r
2863                         right.height(), kBackgroundColor);\r
2864   }\r
2865 \r
2866   // Paint separator.\r
2867   pp::Rect bottom(page_rect.x() - kPageShadowLeft,\r
2868                   page_rect.bottom() + kPageShadowBottom,\r
2869                   page_rect.width() + kPageShadowLeft + kPageShadowRight,\r
2870                   kPageSeparatorThickness);\r
2871   bottom = GetScreenRect(bottom).Intersect(dirty_in_screen);\r
2872 \r
2873   FPDFBitmap_FillRect(bitmap, bottom.x() - dirty_in_screen.x(),\r
2874                       bottom.y() - dirty_in_screen.y(), bottom.width(),\r
2875                       bottom.height(), kBackgroundColor);\r
2876 }\r
2877 \r
2878 void PDFiumEngine::PaintPageShadow(int progressive_index,\r
2879                                    pp::ImageData* image_data) {\r
2880   int page_index = progressive_paints_[progressive_index].page_index;\r
2881   pp::Rect dirty_in_screen = progressive_paints_[progressive_index].rect;\r
2882   pp::Rect page_rect = pages_[page_index]->rect();\r
2883   pp::Rect shadow_rect(page_rect);\r
2884   shadow_rect.Inset(-kPageShadowLeft, -kPageShadowTop,\r
2885                     -kPageShadowRight, -kPageShadowBottom);\r
2886 \r
2887   // Due to the rounding errors of the GetScreenRect it is possible to get\r
2888   // different size shadows on the left and right sides even they are defined\r
2889   // the same. To fix this issue let's calculate shadow rect and then shrink\r
2890   // it by the size of the shadows.\r
2891   shadow_rect = GetScreenRect(shadow_rect);\r
2892   page_rect = shadow_rect;\r
2893 \r
2894   page_rect.Inset(static_cast<int>(ceil(kPageShadowLeft * current_zoom_)),\r
2895                   static_cast<int>(ceil(kPageShadowTop * current_zoom_)),\r
2896                   static_cast<int>(ceil(kPageShadowRight * current_zoom_)),\r
2897                   static_cast<int>(ceil(kPageShadowBottom * current_zoom_)));\r
2898 \r
2899   DrawPageShadow(page_rect, shadow_rect, dirty_in_screen, image_data);\r
2900 }\r
2901 \r
2902 void PDFiumEngine::DrawSelections(int progressive_index,\r
2903                                   pp::ImageData* image_data) {\r
2904   int page_index = progressive_paints_[progressive_index].page_index;\r
2905   pp::Rect dirty_in_screen = progressive_paints_[progressive_index].rect;\r
2906 \r
2907   void* region = NULL;\r
2908   int stride;\r
2909   GetRegion(dirty_in_screen.point(), image_data, &region, &stride);\r
2910 \r
2911   std::vector<pp::Rect> highlighted_rects;\r
2912   pp::Rect visible_rect = GetVisibleRect();\r
2913   for (size_t k = 0; k < selection_.size(); ++k) {\r
2914     if (selection_[k].page_index() != page_index)\r
2915       continue;\r
2916     std::vector<pp::Rect> rects = selection_[k].GetScreenRects(\r
2917         visible_rect.point(), current_zoom_, current_rotation_);\r
2918     for (size_t j = 0; j < rects.size(); ++j) {\r
2919       pp::Rect visible_selection = rects[j].Intersect(dirty_in_screen);\r
2920       if (visible_selection.IsEmpty())\r
2921         continue;\r
2922 \r
2923       visible_selection.Offset(\r
2924           -dirty_in_screen.point().x(), -dirty_in_screen.point().y());\r
2925       Highlight(region, stride, visible_selection, &highlighted_rects);\r
2926     }\r
2927   }\r
2928 \r
2929   for (size_t k = 0; k < form_highlights_.size(); ++k) {\r
2930     pp::Rect visible_selection = form_highlights_[k].Intersect(dirty_in_screen);\r
2931       if (visible_selection.IsEmpty())\r
2932         continue;\r
2933 \r
2934     visible_selection.Offset(\r
2935         -dirty_in_screen.point().x(), -dirty_in_screen.point().y());\r
2936     Highlight(region, stride, visible_selection, &highlighted_rects);\r
2937   }\r
2938   form_highlights_.clear();\r
2939 }\r
2940 \r
2941 void PDFiumEngine::PaintUnavailablePage(int page_index,\r
2942                                         const pp::Rect& dirty,\r
2943                                         pp::ImageData* image_data) {\r
2944   int start_x, start_y, size_x, size_y;\r
2945   GetPDFiumRect(page_index, dirty, &start_x, &start_y, &size_x, &size_y);\r
2946   FPDF_BITMAP bitmap = CreateBitmap(dirty, image_data);\r
2947   FPDFBitmap_FillRect(bitmap, start_x, start_y, size_x, size_y,\r
2948                       kPendingPageColor);\r
2949 \r
2950   pp::Rect loading_text_in_screen(\r
2951       pages_[page_index]->rect().width() / 2,\r
2952       pages_[page_index]->rect().y() + kLoadingTextVerticalOffset, 0, 0);\r
2953   loading_text_in_screen = GetScreenRect(loading_text_in_screen);\r
2954   FPDFBitmap_Destroy(bitmap);\r
2955 }\r
2956 \r
2957 int PDFiumEngine::GetProgressiveIndex(int page_index) const {\r
2958   for (size_t i = 0; i < progressive_paints_.size(); ++i) {\r
2959     if (progressive_paints_[i].page_index == page_index)\r
2960       return i;\r
2961   }\r
2962   return -1;\r
2963 }\r
2964 \r
2965 FPDF_BITMAP PDFiumEngine::CreateBitmap(const pp::Rect& rect,\r
2966                                        pp::ImageData* image_data) const {\r
2967   void* region;\r
2968   int stride;\r
2969   GetRegion(rect.point(), image_data, &region, &stride);\r
2970   if (!region)\r
2971     return NULL;\r
2972   return FPDFBitmap_CreateEx(\r
2973       rect.width(), rect.height(), FPDFBitmap_BGRx, region, stride);\r
2974 }\r
2975 \r
2976 void PDFiumEngine::GetPDFiumRect(\r
2977     int page_index, const pp::Rect& rect, int* start_x, int* start_y,\r
2978     int* size_x, int* size_y) const {\r
2979   pp::Rect page_rect = GetScreenRect(pages_[page_index]->rect());\r
2980   page_rect.Offset(-rect.x(), -rect.y());\r
2981 \r
2982   *start_x = page_rect.x();\r
2983   *start_y = page_rect.y();\r
2984   *size_x = page_rect.width();\r
2985   *size_y = page_rect.height();\r
2986 }\r
2987 \r
2988 int PDFiumEngine::GetRenderingFlags() const {\r
2989   int flags = FPDF_LCD_TEXT | FPDF_NO_CATCH;\r
2990   if (render_grayscale_)\r
2991     flags |= FPDF_GRAYSCALE;\r
2992   if (client_->IsPrintPreview())\r
2993     flags |= FPDF_PRINTING;\r
2994   return flags;\r
2995 }\r
2996 \r
2997 pp::Rect PDFiumEngine::GetVisibleRect() const {\r
2998   pp::Rect rv;\r
2999   rv.set_x(static_cast<int>(position_.x() / current_zoom_));\r
3000   rv.set_y(static_cast<int>(position_.y() / current_zoom_));\r
3001   rv.set_width(static_cast<int>(ceil(plugin_size_.width() / current_zoom_)));\r
3002   rv.set_height(static_cast<int>(ceil(plugin_size_.height() / current_zoom_)));\r
3003   return rv;\r
3004 }\r
3005 \r
3006 pp::Rect PDFiumEngine::GetPageScreenRect(int page_index) const {\r
3007   // Since we use this rect for creating the PDFium bitmap, also include other\r
3008   // areas around the page that we might need to update such as the page\r
3009   // separator and the sides if the page is narrower than the document.\r
3010   return GetScreenRect(pp::Rect(\r
3011       0,\r
3012       pages_[page_index]->rect().y() - kPageShadowTop,\r
3013       document_size_.width(),\r
3014       pages_[page_index]->rect().height() + kPageShadowTop +\r
3015           kPageShadowBottom + kPageSeparatorThickness));\r
3016 }\r
3017 \r
3018 pp::Rect PDFiumEngine::GetScreenRect(const pp::Rect& rect) const {\r
3019   pp::Rect rv;\r
3020   int right =\r
3021       static_cast<int>(ceil(rect.right() * current_zoom_ - position_.x()));\r
3022   int bottom =\r
3023     static_cast<int>(ceil(rect.bottom() * current_zoom_ - position_.y()));\r
3024 \r
3025   rv.set_x(static_cast<int>(rect.x() * current_zoom_ - position_.x()));\r
3026   rv.set_y(static_cast<int>(rect.y() * current_zoom_ - position_.y()));\r
3027   rv.set_width(right - rv.x());\r
3028   rv.set_height(bottom - rv.y());\r
3029   return rv;\r
3030 }\r
3031 \r
3032 void PDFiumEngine::Highlight(void* buffer,\r
3033                              int stride,\r
3034                              const pp::Rect& rect,\r
3035                              std::vector<pp::Rect>* highlighted_rects) {\r
3036   if (!buffer)\r
3037     return;\r
3038 \r
3039   pp::Rect new_rect = rect;\r
3040   for (size_t i = 0; i < highlighted_rects->size(); ++i)\r
3041     new_rect = new_rect.Subtract((*highlighted_rects)[i]);\r
3042 \r
3043   highlighted_rects->push_back(new_rect);\r
3044   int l = new_rect.x();\r
3045   int t = new_rect.y();\r
3046   int w = new_rect.width();\r
3047   int h = new_rect.height();\r
3048 \r
3049   for (int y = t; y < t + h; ++y) {\r
3050     for (int x = l; x < l + w; ++x) {\r
3051       uint8* pixel = static_cast<uint8*>(buffer) + y * stride + x * 4;\r
3052       //  This is our highlight color.\r
3053       pixel[0] = static_cast<uint8>(\r
3054           pixel[0] * (kHighlightColorB / 255.0));\r
3055       pixel[1] = static_cast<uint8>(\r
3056           pixel[1] * (kHighlightColorG / 255.0));\r
3057       pixel[2] = static_cast<uint8>(\r
3058           pixel[2] * (kHighlightColorR / 255.0));\r
3059     }\r
3060   }\r
3061 }\r
3062 \r
3063 PDFiumEngine::SelectionChangeInvalidator::SelectionChangeInvalidator(\r
3064     PDFiumEngine* engine) : engine_(engine) {\r
3065   previous_origin_ = engine_->GetVisibleRect().point();\r
3066   GetVisibleSelectionsScreenRects(&old_selections_);\r
3067 }\r
3068 \r
3069 PDFiumEngine::SelectionChangeInvalidator::~SelectionChangeInvalidator() {\r
3070   // Offset the old selections if the document scrolled since we recorded them.\r
3071   pp::Point offset = previous_origin_ - engine_->GetVisibleRect().point();\r
3072   for (size_t i = 0; i < old_selections_.size(); ++i)\r
3073     old_selections_[i].Offset(offset);\r
3074 \r
3075   std::vector<pp::Rect> new_selections;\r
3076   GetVisibleSelectionsScreenRects(&new_selections);\r
3077   for (size_t i = 0; i < new_selections.size(); ++i) {\r
3078     for (size_t j = 0; j < old_selections_.size(); ++j) {\r
3079       if (!old_selections_[j].IsEmpty() &&\r
3080           new_selections[i] == old_selections_[j]) {\r
3081         // Rectangle was selected before and after, so no need to invalidate it.\r
3082         // Mark the rectangles by setting them to empty.\r
3083         new_selections[i] = old_selections_[j] = pp::Rect();\r
3084         break;\r
3085       }\r
3086     }\r
3087   }\r
3088 \r
3089   for (size_t i = 0; i < old_selections_.size(); ++i) {\r
3090     if (!old_selections_[i].IsEmpty())\r
3091       engine_->client_->Invalidate(old_selections_[i]);\r
3092   }\r
3093   for (size_t i = 0; i < new_selections.size(); ++i) {\r
3094     if (!new_selections[i].IsEmpty())\r
3095       engine_->client_->Invalidate(new_selections[i]);\r
3096   }\r
3097   engine_->OnSelectionChanged();\r
3098 }\r
3099 \r
3100 void\r
3101 PDFiumEngine::SelectionChangeInvalidator::GetVisibleSelectionsScreenRects(\r
3102     std::vector<pp::Rect>* rects) {\r
3103   pp::Rect visible_rect = engine_->GetVisibleRect();\r
3104   for (size_t i = 0; i < engine_->selection_.size(); ++i) {\r
3105     int page_index = engine_->selection_[i].page_index();\r
3106     if (!engine_->IsPageVisible(page_index))\r
3107       continue;  // This selection is on a page that's not currently visible.\r
3108 \r
3109     std::vector<pp::Rect> selection_rects =\r
3110         engine_->selection_[i].GetScreenRects(\r
3111             visible_rect.point(),\r
3112             engine_->current_zoom_,\r
3113             engine_->current_rotation_);\r
3114     rects->insert(rects->end(), selection_rects.begin(), selection_rects.end());\r
3115   }\r
3116 }\r
3117 \r
3118 PDFiumEngine::MouseDownState::MouseDownState(\r
3119     const PDFiumPage::Area& area,\r
3120     const PDFiumPage::LinkTarget& target)\r
3121     : area_(area), target_(target) {\r
3122 }\r
3123 \r
3124 PDFiumEngine::MouseDownState::~MouseDownState() {\r
3125 }\r
3126 \r
3127 void PDFiumEngine::MouseDownState::Set(const PDFiumPage::Area& area,\r
3128                                        const PDFiumPage::LinkTarget& target) {\r
3129   area_ = area;\r
3130   target_ = target;\r
3131 }\r
3132 \r
3133 void PDFiumEngine::MouseDownState::Reset() {\r
3134   area_ = PDFiumPage::NONSELECTABLE_AREA;\r
3135   target_ = PDFiumPage::LinkTarget();\r
3136 }\r
3137 \r
3138 bool PDFiumEngine::MouseDownState::Matches(\r
3139     const PDFiumPage::Area& area,\r
3140     const PDFiumPage::LinkTarget& target) const {\r
3141   if (area_ == area) {\r
3142     if (area == PDFiumPage::WEBLINK_AREA)\r
3143       return target_.url == target.url;\r
3144     if (area == PDFiumPage::DOCLINK_AREA)\r
3145       return target_.page == target.page;\r
3146     return true;\r
3147   }\r
3148   return false;\r
3149 }\r
3150 \r
3151 void PDFiumEngine::DeviceToPage(int page_index,\r
3152                                 float device_x,\r
3153                                 float device_y,\r
3154                                 double* page_x,\r
3155                                 double* page_y) {\r
3156   *page_x = *page_y = 0;\r
3157   int temp_x = static_cast<int>((device_x + position_.x())/ current_zoom_ -\r
3158       pages_[page_index]->rect().x());\r
3159   int temp_y = static_cast<int>((device_y + position_.y())/ current_zoom_ -\r
3160       pages_[page_index]->rect().y());\r
3161   FPDF_DeviceToPage(\r
3162       pages_[page_index]->GetPage(), 0, 0,\r
3163       pages_[page_index]->rect().width(),  pages_[page_index]->rect().height(),\r
3164       current_rotation_, temp_x, temp_y, page_x, page_y);\r
3165 }\r
3166 \r
3167 int PDFiumEngine::GetVisiblePageIndex(FPDF_PAGE page) {\r
3168   for (size_t i = 0; i < visible_pages_.size(); ++i) {\r
3169     if (pages_[visible_pages_[i]]->GetPage() == page)\r
3170       return visible_pages_[i];\r
3171   }\r
3172   return -1;\r
3173 }\r
3174 \r
3175 void PDFiumEngine::SetCurrentPage(int index) {\r
3176   if (index == most_visible_page_ || !form_)\r
3177     return;\r
3178   if (most_visible_page_ != -1 && called_do_document_action_) {\r
3179     FPDF_PAGE old_page = pages_[most_visible_page_]->GetPage();\r
3180     FORM_DoPageAAction(old_page, form_, FPDFPAGE_AACTION_CLOSE);\r
3181   }\r
3182   most_visible_page_ = index;\r
3183 #if defined(OS_LINUX)\r
3184     g_last_instance_id = client_->GetPluginInstance()->pp_instance();\r
3185 #endif\r
3186   if (most_visible_page_ != -1 && called_do_document_action_) {\r
3187     FPDF_PAGE new_page = pages_[most_visible_page_]->GetPage();\r
3188     FORM_DoPageAAction(new_page, form_, FPDFPAGE_AACTION_OPEN);\r
3189   }\r
3190 }\r
3191 \r
3192 void PDFiumEngine::TransformPDFPageForPrinting(\r
3193     FPDF_PAGE page,\r
3194     const PP_PrintSettings_Dev& print_settings) {\r
3195   // Get the source page width and height in points.\r
3196   const double src_page_width = FPDF_GetPageWidth(page);\r
3197   const double src_page_height = FPDF_GetPageHeight(page);\r
3198 \r
3199   const int src_page_rotation = FPDFPage_GetRotation(page);\r
3200   const bool fit_to_page = print_settings.print_scaling_option ==\r
3201       PP_PRINTSCALINGOPTION_FIT_TO_PRINTABLE_AREA;\r
3202 \r
3203   pp::Size page_size(print_settings.paper_size);\r
3204   pp::Rect content_rect(print_settings.printable_area);\r
3205   const bool rotated = (src_page_rotation % 2 == 1);\r
3206   SetPageSizeAndContentRect(rotated,\r
3207                             src_page_width > src_page_height,\r
3208                             &page_size,\r
3209                             &content_rect);\r
3210 \r
3211   // Compute the screen page width and height in points.\r
3212   const int actual_page_width =\r
3213       rotated ? page_size.height() : page_size.width();\r
3214   const int actual_page_height =\r
3215       rotated ? page_size.width() : page_size.height();\r
3216 \r
3217   const double scale_factor = CalculateScaleFactor(fit_to_page, content_rect,\r
3218                                                    src_page_width,\r
3219                                                    src_page_height, rotated);\r
3220 \r
3221   // Calculate positions for the clip box.\r
3222   ClipBox source_clip_box;\r
3223   CalculateClipBoxBoundary(page, scale_factor, rotated, &source_clip_box);\r
3224 \r
3225   // Calculate the translation offset values.\r
3226   double offset_x = 0;\r
3227   double offset_y = 0;\r
3228   if (fit_to_page) {\r
3229     CalculateScaledClipBoxOffset(content_rect, source_clip_box, &offset_x,\r
3230                                  &offset_y);\r