1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef PDF_PDF_ENGINE_H_
6 #define PDF_PDF_ENGINE_H_
7 
8 #include <stdint.h>
9 
10 #include <memory>
11 #include <string>
12 #include <vector>
13 
14 #include "base/containers/span.h"
15 #include "base/optional.h"
16 #include "base/strings/string16.h"
17 #include "base/time/time.h"
18 #include "base/values.h"
19 #include "build/build_config.h"
20 #include "pdf/document_layout.h"
21 #include "ppapi/c/dev/pp_cursor_type_dev.h"
22 #include "ppapi/c/dev/ppp_printing_dev.h"
23 #include "ppapi/c/ppb_input_event.h"
24 #include "ppapi/cpp/completion_callback.h"
25 #include "ppapi/cpp/image_data.h"
26 #include "ppapi/cpp/private/pdf.h"
27 #include "ppapi/cpp/rect.h"
28 #include "ppapi/cpp/size.h"
29 #include "ppapi/cpp/url_loader.h"
30 #include "ppapi/cpp/var_array.h"
31 #include "ui/base/window_open_disposition.h"
32 #include "ui/gfx/geometry/point_f.h"
33 
34 #if defined(OS_WIN)
35 #include <windows.h>
36 #endif
37 
38 #if defined(OS_WIN)
39 typedef void (*PDFEnsureTypefaceCharactersAccessible)(const LOGFONT* font,
40                                                       const wchar_t* text,
41                                                       size_t text_length);
42 #endif
43 
44 struct PP_PdfAccessibilityActionData;
45 struct PP_PdfPrintSettings_Dev;
46 
47 namespace gfx {
48 class Rect;
49 class Size;
50 }
51 
52 namespace pp {
53 class InputEvent;
54 class VarDictionary;
55 }
56 
57 namespace chrome_pdf {
58 
59 struct DocumentMetadata;
60 
61 // Do one time initialization of the SDK.
62 // If |enable_v8| is false, then the PDFEngine will not be able to run
63 // JavaScript.
64 void InitializeSDK(bool enable_v8);
65 // Tells the SDK that we're shutting down.
66 void ShutdownSDK();
67 
68 // This class encapsulates a PDF rendering engine.
69 class PDFEngine {
70  public:
71   enum DocumentPermission {
72     PERMISSION_COPY,
73     PERMISSION_COPY_ACCESSIBLE,
74     PERMISSION_PRINT_LOW_QUALITY,
75     PERMISSION_PRINT_HIGH_QUALITY,
76   };
77 
78   // Values other then |kCount| are persisted to logs as part of metric
79   // collection, so should not be changed.
80   enum class FormType {
81     kNone = 0,
82     kAcroForm = 1,
83     kXFAFull = 2,
84     kXFAForeground = 3,
85     kCount = 4,
86   };
87 
88   // Maximum number of parameters a nameddest view can contain.
89   static constexpr size_t kMaxViewParams = 4;
90 
91   // Named destination in a document.
92   struct NamedDestination {
93     // 0-based page number.
94     unsigned long page;
95 
96     // View fit type (see table 8.2 "Destination syntax" on page 582 of PDF
97     // Reference 1.7). Empty string if not present.
98     std::string view;
99 
100     // Number of parameters for the view.
101     unsigned long num_params;
102 
103     // Parameters for the view. Their meaning depends on the |view| and their
104     // number is defined by |num_params| but is at most |kMaxViewParams|.
105     float params[kMaxViewParams];
106   };
107 
108   // Features in a document that are relevant to measure.
109   struct DocumentFeatures {
110     // Number of pages in document.
111     size_t page_count = 0;
112     // Whether any files are attached to document (see "File Attachment
113     // Annotations" on page 637 of PDF Reference 1.7).
114     bool has_attachments = false;
115     // Whether the PDF is Tagged (see 10.7 "Tagged PDF" in PDF Reference 1.7).
116     bool is_tagged = false;
117     // What type of form the document contains.
118     FormType form_type = FormType::kNone;
119   };
120 
121   // The interface that's provided to the rendering engine.
122   class Client {
123    public:
~Client()124     virtual ~Client() {}
125 
126     // Proposes a document layout to the client. For the proposed layout to
127     // become effective, the client must call PDFEngine::ApplyDocumentLayout()
128     // with the new layout options (although this call can be asynchronous).
129     virtual void ProposeDocumentLayout(const DocumentLayout& layout) = 0;
130 
131     // Informs the client that the given rect needs to be repainted.
Invalidate(const pp::Rect & rect)132     virtual void Invalidate(const pp::Rect& rect) {}
133 
134     // Informs the client to scroll the plugin area by the given offset.
DidScroll(const pp::Point & point)135     virtual void DidScroll(const pp::Point& point) {}
136 
137     // Scroll the horizontal/vertical scrollbars to a given position.
138     // Values are in screen coordinates, where 0 is the top/left of the document
139     // and a positive value is the distance in pixels from that line.
140     // For ScrollToY, setting |compensate_for_toolbar| will align the position
141     // with the bottom of the toolbar so the given position is always visible.
ScrollToX(int x_in_screen_coords)142     virtual void ScrollToX(int x_in_screen_coords) {}
ScrollToY(int y_in_screen_coords,bool compensate_for_toolbar)143     virtual void ScrollToY(int y_in_screen_coords,
144                            bool compensate_for_toolbar) {}
145 
146     // Scroll by a given delta relative to the current position.
ScrollBy(const pp::Point & point)147     virtual void ScrollBy(const pp::Point& point) {}
148 
149     // Scroll to zero-based |page|.
ScrollToPage(int page)150     virtual void ScrollToPage(int page) {}
151 
152     // Navigate to the given url.
NavigateTo(const std::string & url,WindowOpenDisposition disposition)153     virtual void NavigateTo(const std::string& url,
154                             WindowOpenDisposition disposition) {}
155 
156     // Navigate to the given destination. Zero-based |page| index. |x|, |y| and
157     // |zoom| are optional and can be nullptr.
NavigateToDestination(int page,const float * x,const float * y,const float * zoom)158     virtual void NavigateToDestination(int page,
159                                        const float* x,
160                                        const float* y,
161                                        const float* zoom) {}
162 
163     // Updates the cursor.
UpdateCursor(PP_CursorType_Dev cursor)164     virtual void UpdateCursor(PP_CursorType_Dev cursor) {}
165 
166     // Updates the tick marks in the vertical scrollbar.
UpdateTickMarks(const std::vector<pp::Rect> & tickmarks)167     virtual void UpdateTickMarks(const std::vector<pp::Rect>& tickmarks) {}
168 
169     // Updates the number of find results for the current search term.  If
170     // there are no matches 0 should be passed in.  Only when the plugin has
171     // finished searching should it pass in the final count with final_result
172     // set to true.
NotifyNumberOfFindResultsChanged(int total,bool final_result)173     virtual void NotifyNumberOfFindResultsChanged(int total,
174                                                   bool final_result) {}
175 
176     // Updates the index of the currently selected search item.
NotifySelectedFindResultChanged(int current_find_index)177     virtual void NotifySelectedFindResultChanged(int current_find_index) {}
178 
179     // Prompts the user for a password to open this document. The callback is
180     // called when the password is retrieved.
GetDocumentPassword(pp::CompletionCallbackWithOutput<pp::Var> callback)181     virtual void GetDocumentPassword(
182         pp::CompletionCallbackWithOutput<pp::Var> callback) {}
183 
184     // Play a "beeping" sound.
Beep()185     virtual void Beep() {}
186 
187     // Puts up an alert with the given message.
Alert(const std::string & message)188     virtual void Alert(const std::string& message) {}
189 
190     // Puts up a confirm with the given message, and returns true if the user
191     // presses OK, or false if they press cancel.
192     virtual bool Confirm(const std::string& message) = 0;
193 
194     // Puts up a prompt with the given message and default answer and returns
195     // the answer.
196     virtual std::string Prompt(const std::string& question,
197                                const std::string& default_answer) = 0;
198 
199     // Returns the url of the pdf.
200     virtual std::string GetURL() = 0;
201 
202     // Send an email.
Email(const std::string & to,const std::string & cc,const std::string & bcc,const std::string & subject,const std::string & body)203     virtual void Email(const std::string& to,
204                        const std::string& cc,
205                        const std::string& bcc,
206                        const std::string& subject,
207                        const std::string& body) {}
208 
209     // Put up the print dialog.
Print()210     virtual void Print() {}
211 
212     // Submit the data using HTTP POST.
SubmitForm(const std::string & url,const void * data,int length)213     virtual void SubmitForm(const std::string& url,
214                             const void* data,
215                             int length) {}
216 
217     // Creates and returns new URL loader for partial document requests.
218     virtual pp::URLLoader CreateURLLoader() = 0;
219 
220     // Searches the given string for "term" and returns the results.  Unicode-
221     // aware.
222     struct SearchStringResult {
223       int start_index;
224       int length;
225     };
226     virtual std::vector<SearchStringResult> SearchString(
227         const base::char16* string,
228         const base::char16* term,
229         bool case_sensitive) = 0;
230 
231     // Notifies the client that the document has finished loading.
DocumentLoadComplete(const DocumentFeatures & document_features)232     virtual void DocumentLoadComplete(
233         const DocumentFeatures& document_features) {}
234 
235     // Notifies the client that the document has failed to load.
DocumentLoadFailed()236     virtual void DocumentLoadFailed() {}
237 
238     virtual pp::Instance* GetPluginInstance() = 0;
239 
240     // Notifies that an unsupported feature in the PDF was encountered.
DocumentHasUnsupportedFeature(const std::string & feature)241     virtual void DocumentHasUnsupportedFeature(const std::string& feature) {}
242 
243     // Notifies the client about document load progress.
DocumentLoadProgress(uint32_t available,uint32_t doc_size)244     virtual void DocumentLoadProgress(uint32_t available, uint32_t doc_size) {}
245 
246     // Notifies the client about focus changes for form text fields.
FormTextFieldFocusChange(bool in_focus)247     virtual void FormTextFieldFocusChange(bool in_focus) {}
248 
249     // Returns true if the plugin has been opened within print preview.
250     virtual bool IsPrintPreview() = 0;
251 
252     // Get the background color of the PDF.
253     virtual uint32_t GetBackgroundColor() = 0;
254 
255     // Sets selection status.
IsSelectingChanged(bool is_selecting)256     virtual void IsSelectingChanged(bool is_selecting) {}
257 
SelectionChanged(const pp::Rect & left,const pp::Rect & right)258     virtual void SelectionChanged(const pp::Rect& left, const pp::Rect& right) {
259     }
260 
261     // Sets edit mode state.
IsEditModeChanged(bool is_edit_mode)262     virtual void IsEditModeChanged(bool is_edit_mode) {}
263 
264     // Gets the height of the top toolbar in screen coordinates. This is
265     // independent of whether it is hidden or not at the moment.
266     virtual float GetToolbarHeightInScreenCoords() = 0;
267   };
268 
269   struct AccessibilityLinkInfo {
270     std::string url;
271     int start_char_index;
272     int char_count;
273     pp::FloatRect bounds;
274   };
275 
276   struct AccessibilityImageInfo {
277     std::string alt_text;
278     pp::FloatRect bounds;
279   };
280 
281   struct AccessibilityHighlightInfo {
282     int start_char_index = -1;
283     int char_count;
284     pp::FloatRect bounds;
285     uint32_t color;
286   };
287 
288   struct AccessibilityTextFieldInfo {
289     AccessibilityTextFieldInfo();
290     AccessibilityTextFieldInfo(const AccessibilityTextFieldInfo& that);
291     ~AccessibilityTextFieldInfo();
292 
293     std::string name;
294     std::string value;
295     bool is_read_only;
296     bool is_required;
297     bool is_password;
298     pp::FloatRect bounds;
299   };
300 
301   // Factory method to create an instance of the PDF Engine.
302   static std::unique_ptr<PDFEngine> Create(Client* client,
303                                            bool enable_javascript);
304 
~PDFEngine()305   virtual ~PDFEngine() {}
306 
307   // Most of these functions are similar to the Pepper functions of the same
308   // name, so not repeating the description here unless it's different.
309   virtual bool New(const char* url, const char* headers) = 0;
310   virtual void PageOffsetUpdated(const pp::Point& page_offset) = 0;
311   virtual void PluginSizeUpdated(const pp::Size& size) = 0;
312   virtual void ScrolledToXPosition(int position) = 0;
313   virtual void ScrolledToYPosition(int position) = 0;
314   // Paint is called a series of times. Before these n calls are made, PrePaint
315   // is called once. After Paint is called n times, PostPaint is called once.
316   virtual void PrePaint() = 0;
317   virtual void Paint(const pp::Rect& rect,
318                      pp::ImageData* image_data,
319                      std::vector<pp::Rect>* ready,
320                      std::vector<pp::Rect>* pending) = 0;
321   virtual void PostPaint() = 0;
322   virtual bool HandleDocumentLoad(const pp::URLLoader& loader) = 0;
323   virtual bool HandleEvent(const pp::InputEvent& event) = 0;
324   virtual uint32_t QuerySupportedPrintOutputFormats() = 0;
325   virtual void PrintBegin() = 0;
326   virtual pp::Resource PrintPages(
327       const PP_PrintPageNumberRange_Dev* page_ranges,
328       uint32_t page_range_count,
329       const PP_PrintSettings_Dev& print_settings,
330       const PP_PdfPrintSettings_Dev& pdf_print_settings) = 0;
331   virtual void PrintEnd() = 0;
332   virtual void StartFind(const std::string& text, bool case_sensitive) = 0;
333   virtual bool SelectFindResult(bool forward) = 0;
334   virtual void StopFind() = 0;
335   virtual void ZoomUpdated(double new_zoom_level) = 0;
336   virtual void RotateClockwise() = 0;
337   virtual void RotateCounterclockwise() = 0;
338   virtual void SetTwoUpView(bool enable) = 0;
339 
340   // Applies the document layout options proposed by a call to
341   // PDFEngine::Client::ProposeDocumentLayout(), returning the overall size of
342   // the new effective layout.
343   virtual pp::Size ApplyDocumentLayout(
344       const DocumentLayout::Options& options) = 0;
345 
346   virtual std::string GetSelectedText() = 0;
347   // Returns true if focus is within an editable form text area.
348   virtual bool CanEditText() = 0;
349   // Returns true if focus is within an editable form text area and the text
350   // area has text.
351   virtual bool HasEditableText() = 0;
352   // Replace selected text within an editable form text area with another
353   // string. If there is no selected text, append the replacement text after the
354   // current caret position.
355   virtual void ReplaceSelection(const std::string& text) = 0;
356   // Methods to check if undo/redo is possible, and to perform them.
357   virtual bool CanUndo() = 0;
358   virtual bool CanRedo() = 0;
359   virtual void Undo() = 0;
360   virtual void Redo() = 0;
361   // Handles actions invoked by Accessibility clients.
362   virtual void HandleAccessibilityAction(
363       const PP_PdfAccessibilityActionData& action_data) = 0;
364   virtual std::string GetLinkAtPosition(const pp::Point& point) = 0;
365   // Checks the permissions associated with this document.
366   virtual bool HasPermission(DocumentPermission permission) const = 0;
367   virtual void SelectAll() = 0;
368   // Gets metadata about the document.
369   virtual const DocumentMetadata& GetDocumentMetadata() const = 0;
370   // Gets the number of pages in the document.
371   virtual int GetNumberOfPages() = 0;
372   // Gets the named destination by name.
373   virtual base::Optional<PDFEngine::NamedDestination> GetNamedDestination(
374       const std::string& destination) = 0;
375   // Gets the index of the most visible page, or -1 if none are visible.
376   virtual int GetMostVisiblePage() = 0;
377   // Gets the rectangle of the page not including the shadow.
378   virtual pp::Rect GetPageBoundsRect(int index) = 0;
379   // Gets the rectangle of the page excluding any additional areas.
380   virtual pp::Rect GetPageContentsRect(int index) = 0;
381   // Returns a page's rect in screen coordinates, as well as its surrounding
382   // border areas and bottom separator.
383   virtual pp::Rect GetPageScreenRect(int page_index) const = 0;
384   // Gets the offset of the vertical scrollbar from the top in document
385   // coordinates.
386   virtual int GetVerticalScrollbarYPosition() = 0;
387   // Set color / grayscale rendering modes.
388   virtual void SetGrayscale(bool grayscale) = 0;
389   // Get the number of characters on a given page.
390   virtual int GetCharCount(int page_index) = 0;
391   // Get the bounds in page pixels of a character on a given page.
392   virtual pp::FloatRect GetCharBounds(int page_index, int char_index) = 0;
393   // Get a given unicode character on a given page.
394   virtual uint32_t GetCharUnicode(int page_index, int char_index) = 0;
395   // Given a start char index, find the longest continuous run of text that's
396   // in a single direction and with the same text style. Return a filled out
397   // pp::PDF::PrivateAccessibilityTextRunInfo on success or base::nullopt on
398   // failure. e.g. When |start_char_index| is out of bounds.
399   virtual base::Optional<pp::PDF::PrivateAccessibilityTextRunInfo>
400   GetTextRunInfo(int page_index, int start_char_index) = 0;
401   // For all the links on page |page_index|, get their urls, underlying text
402   // ranges and bounding boxes.
403   virtual std::vector<AccessibilityLinkInfo> GetLinkInfo(int page_index) = 0;
404   // For all the images in page |page_index|, get their alt texts and bounding
405   // boxes.
406   virtual std::vector<AccessibilityImageInfo> GetImageInfo(int page_index) = 0;
407   // For all the highlights in page |page_index|, get their underlying text
408   // ranges and bounding boxes.
409   virtual std::vector<AccessibilityHighlightInfo> GetHighlightInfo(
410       int page_index) = 0;
411   // For all the text fields in page |page_index|, get their properties like
412   // name, value, bounding boxes etc.
413   virtual std::vector<AccessibilityTextFieldInfo> GetTextFieldInfo(
414       int page_index) = 0;
415 
416   // Gets the PDF document's print scaling preference. True if the document can
417   // be scaled to fit.
418   virtual bool GetPrintScaling() = 0;
419   // Returns number of copies to be printed.
420   virtual int GetCopiesToPrint() = 0;
421   // Returns the duplex setting.
422   virtual int GetDuplexType() = 0;
423   // Returns true if all the pages are the same size.
424   virtual bool GetPageSizeAndUniformity(pp::Size* size) = 0;
425 
426   // Returns a VarArray of Bookmarks, each a VarDictionary containing the
427   // following key/values:
428   // - "title" - a string Var.
429   // - "page" - an int Var.
430   // - "children" - a VarArray(), with each entry containing a VarDictionary of
431   //   the same structure.
432   virtual pp::VarArray GetBookmarks() = 0;
433 
434   // Append blank pages to make a 1-page document to a |num_pages| document.
435   // Always retain the first page data.
436   virtual void AppendBlankPages(size_t num_pages) = 0;
437   // Append the first page of the document loaded with the |engine| to this
438   // document at page |index|.
439   virtual void AppendPage(PDFEngine* engine, int index) = 0;
440 
441   virtual std::vector<uint8_t> GetSaveData() = 0;
442 
443   virtual void SetCaretPosition(const pp::Point& position) = 0;
444   virtual void MoveRangeSelectionExtent(const pp::Point& extent) = 0;
445   virtual void SetSelectionBounds(const pp::Point& base,
446                                   const pp::Point& extent) = 0;
447   virtual void GetSelection(uint32_t* selection_start_page_index,
448                             uint32_t* selection_start_char_index,
449                             uint32_t* selection_end_page_index,
450                             uint32_t* selection_end_char_index) = 0;
451 
452   // Remove focus from form widgets, consolidating the user input.
453   virtual void KillFormFocus() = 0;
454 
455   virtual uint32_t GetLoadedByteSize() = 0;
456   virtual bool ReadLoadedBytes(uint32_t length, void* buffer) = 0;
457 };
458 
459 // Interface for exports that wrap the PDF engine.
460 class PDFEngineExports {
461  public:
462   struct RenderingSettings {
463     RenderingSettings(int dpi_x,
464                       int dpi_y,
465                       const pp::Rect& bounds,
466                       bool fit_to_bounds,
467                       bool stretch_to_bounds,
468                       bool keep_aspect_ratio,
469                       bool center_in_bounds,
470                       bool autorotate,
471                       bool use_color);
472     RenderingSettings(const RenderingSettings& that);
473 
474     int dpi_x;
475     int dpi_y;
476     pp::Rect bounds;
477     bool fit_to_bounds;
478     bool stretch_to_bounds;
479     bool keep_aspect_ratio;
480     bool center_in_bounds;
481     bool autorotate;
482     bool use_color;
483   };
484 
PDFEngineExports()485   PDFEngineExports() {}
~PDFEngineExports()486   virtual ~PDFEngineExports() {}
487 
488   static PDFEngineExports* Get();
489 
490 #if defined(OS_CHROMEOS)
491   // See the definition of CreateFlattenedPdf in pdf.cc for details.
492   virtual std::vector<uint8_t> CreateFlattenedPdf(
493       base::span<const uint8_t> input_buffer) = 0;
494 #endif  // defined(OS_CHROMEOS)
495 
496 #if defined(OS_WIN)
497   // See the definition of RenderPDFPageToDC in pdf.cc for details.
498   virtual bool RenderPDFPageToDC(base::span<const uint8_t> pdf_buffer,
499                                  int page_number,
500                                  const RenderingSettings& settings,
501                                  HDC dc) = 0;
502 
503   virtual void SetPDFEnsureTypefaceCharactersAccessible(
504       PDFEnsureTypefaceCharactersAccessible func) = 0;
505 
506   virtual void SetPDFUseGDIPrinting(bool enable) = 0;
507   virtual void SetPDFUsePrintMode(int mode) = 0;
508 #endif  // defined(OS_WIN)
509 
510   // See the definition of RenderPDFPageToBitmap in pdf.cc for details.
511   virtual bool RenderPDFPageToBitmap(base::span<const uint8_t> pdf_buffer,
512                                      int page_number,
513                                      const RenderingSettings& settings,
514                                      void* bitmap_buffer) = 0;
515 
516   // See the definition of ConvertPdfPagesToNupPdf in pdf.cc for details.
517   virtual std::vector<uint8_t> ConvertPdfPagesToNupPdf(
518       std::vector<base::span<const uint8_t>> input_buffers,
519       size_t pages_per_sheet,
520       const gfx::Size& page_size,
521       const gfx::Rect& printable_area) = 0;
522 
523   // See the definition of ConvertPdfDocumentToNupPdf in pdf.cc for details.
524   virtual std::vector<uint8_t> ConvertPdfDocumentToNupPdf(
525       base::span<const uint8_t> input_buffer,
526       size_t pages_per_sheet,
527       const gfx::Size& page_size,
528       const gfx::Rect& printable_area) = 0;
529 
530   virtual bool GetPDFDocInfo(base::span<const uint8_t> pdf_buffer,
531                              int* page_count,
532                              double* max_page_width) = 0;
533 
534   // Whether the PDF is Tagged (see 10.7 "Tagged PDF" in PDF Reference 1.7).
535   // Returns true if it's a tagged (accessible) PDF, false if it's a valid
536   // PDF but untagged, and nullopt if the PDF can't be parsed.
537   virtual base::Optional<bool> IsPDFDocTagged(
538       base::span<const uint8_t> pdf_buffer) = 0;
539 
540   // Given a tagged PDF (see IsPDFDocTagged, above), return the portion of
541   // the structure tree for a given page as a hierarchical tree of base::Values.
542   virtual base::Value GetPDFStructTreeForPage(
543       base::span<const uint8_t> pdf_buffer,
544       int page_index) = 0;
545 
546   // See the definition of GetPDFPageSizeByIndex in pdf.cc for details.
547   virtual bool GetPDFPageSizeByIndex(base::span<const uint8_t> pdf_buffer,
548                                      int page_number,
549                                      double* width,
550                                      double* height) = 0;
551 };
552 
553 }  // namespace chrome_pdf
554 
555 #endif  // PDF_PDF_ENGINE_H_
556