// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef PDF_PDFIUM_PDFIUM_ENGINE_H_ #define PDF_PDFIUM_PDFIUM_ENGINE_H_ #include <map> #include <string> #include <utility> #include <vector> #include "base/memory/scoped_ptr.h" #include "base/time/time.h" #include "pdf/document_loader.h" #include "pdf/pdf_engine.h" #include "pdf/pdfium/pdfium_page.h" #include "pdf/pdfium/pdfium_range.h" #include "ppapi/cpp/completion_callback.h" #include "ppapi/cpp/dev/buffer_dev.h" #include "ppapi/cpp/image_data.h" #include "ppapi/cpp/point.h" #include "third_party/pdfium/fpdfsdk/include/fpdf_dataavail.h" #include "third_party/pdfium/fpdfsdk/include/fpdf_progressive.h" #include "third_party/pdfium/fpdfsdk/include/fpdfformfill.h" #include "third_party/pdfium/fpdfsdk/include/fpdfview.h" namespace pp { class KeyboardInputEvent; class MouseInputEvent; } namespace chrome_pdf { class ShadowMatrix; class PDFiumEngine : public PDFEngine, public DocumentLoader::Client, public FPDF_FORMFILLINFO, public IPDF_JSPLATFORM, public IFSDK_PAUSE { public: explicit PDFiumEngine(PDFEngine::Client* client); virtual ~PDFiumEngine(); // PDFEngine implementation. virtual bool New(const char* url); virtual bool New(const char* url, const char* headers); virtual void PageOffsetUpdated(const pp::Point& page_offset); virtual void PluginSizeUpdated(const pp::Size& size); virtual void ScrolledToXPosition(int position); virtual void ScrolledToYPosition(int position); virtual void PrePaint(); virtual void Paint(const pp::Rect& rect, pp::ImageData* image_data, std::vector<pp::Rect>* ready, std::vector<pp::Rect>* pending); virtual void PostPaint(); virtual bool HandleDocumentLoad(const pp::URLLoader& loader); virtual bool HandleEvent(const pp::InputEvent& event); virtual uint32_t QuerySupportedPrintOutputFormats(); virtual void PrintBegin(); virtual pp::Resource PrintPages( const PP_PrintPageNumberRange_Dev* page_ranges, uint32_t page_range_count, const PP_PrintSettings_Dev& print_settings); virtual void PrintEnd(); virtual void StartFind(const char* text, bool case_sensitive); virtual bool SelectFindResult(bool forward); virtual void StopFind(); virtual void ZoomUpdated(double new_zoom_level); virtual void RotateClockwise(); virtual void RotateCounterclockwise(); virtual std::string GetSelectedText(); virtual std::string GetLinkAtPosition(const pp::Point& point); virtual bool IsSelecting(); virtual bool HasPermission(DocumentPermission permission) const; virtual void SelectAll(); virtual int GetNumberOfPages(); virtual int GetNamedDestinationPage(const std::string& destination); virtual int GetFirstVisiblePage(); virtual int GetMostVisiblePage(); virtual pp::Rect GetPageRect(int index); virtual pp::Rect GetPageContentsRect(int index); virtual int GetVerticalScrollbarYPosition() { return position_.y(); } virtual void PaintThumbnail(pp::ImageData* image_data, int index); virtual void SetGrayscale(bool grayscale); virtual void OnCallback(int id); virtual std::string GetPageAsJSON(int index); virtual bool GetPrintScaling(); virtual void AppendBlankPages(int num_pages); virtual void AppendPage(PDFEngine* engine, int index); virtual pp::Point GetScrollPosition(); virtual void SetScrollPosition(const pp::Point& position); virtual bool IsProgressiveLoad(); // DocumentLoader::Client implementation. virtual pp::Instance* GetPluginInstance(); virtual pp::URLLoader CreateURLLoader(); virtual void OnPartialDocumentLoaded(); virtual void OnPendingRequestComplete(); virtual void OnNewDataAvailable(); virtual void OnDocumentComplete(); void UnsupportedFeature(int type); std::string current_find_text() const { return current_find_text_; } FPDF_DOCUMENT doc() { return doc_; } FPDF_FORMHANDLE form() { return form_; } private: // This helper class is used to detect the difference in selection between // construction and destruction. At destruction, it invalidates all the // parts that are newly selected, along with all the parts that used to be // selected but are not anymore. class SelectionChangeInvalidator { public: explicit SelectionChangeInvalidator(PDFiumEngine* engine); ~SelectionChangeInvalidator(); private: // Sets the given container to the all the currently visible selection // rectangles, in screen coordinates. void GetVisibleSelectionsScreenRects(std::vector<pp::Rect>* rects); PDFiumEngine* engine_; // Screen rectangles that were selected on construction. std::vector<pp::Rect> old_selections_; // The origin at the time this object was constructed. pp::Point previous_origin_; }; friend class SelectionChangeInvalidator; struct FileAvail : public FX_FILEAVAIL { DocumentLoader* loader; }; struct DownloadHints : public FX_DOWNLOADHINTS { DocumentLoader* loader; }; // PDFium interface to get block of data. static int GetBlock(void* param, unsigned long position, unsigned char* buffer, unsigned long size); // PDFium interface to check is block of data is available. static bool IsDataAvail(FX_FILEAVAIL* param, size_t offset, size_t size); // PDFium interface to request download of the block of data. static void AddSegment(FX_DOWNLOADHINTS* param, size_t offset, size_t size); // We finished getting the pdf file, so load it. This will complete // asynchronously (due to password fetching) and may be run multiple times. void LoadDocument(); // Try loading the document. Returns true if the document is successfully // loaded or is already loaded otherwise it will return false. If // |with_password| is set to true, the document will be loaded with // |password|. If the document could not be loaded and needs a password, // |needs_password| will be set to true. bool TryLoadingDoc(bool with_password, const std::string& password, bool* needs_password); // Ask the user for the document password and then continue loading the // document. void GetPasswordAndLoad(); // Called when the password has been retrieved. void OnGetPasswordComplete(int32_t result, const pp::Var& password); // Continues loading the document when the password has been retrieved, or if // there is no password. void ContinueLoadingDocument(bool has_password, const std::string& password); // Finish loading the document and notify the client that the document has // been loaded. This should only be run after |doc_| has been loaded and the // document is fully downloaded. If this has been run once, it will result in // a no-op. void FinishLoadingDocument(); // Loads information about the pages in the document and calculate the // document size. void LoadPageInfo(bool reload); // Calculate which pages should be displayed right now. void CalculateVisiblePages(); // Returns true iff the given page index is visible. CalculateVisiblePages // must have been called first. bool IsPageVisible(int index) const; // Checks if a page is now available, and if so marks it as such and returns // true. Otherwise, it will return false and will add the index to the given // array if it's not already there. bool CheckPageAvailable(int index, std::vector<int>* pending); // Helper function to get a given page's size in pixels. This is not part of // PDFiumPage because we might not have that structure when we need this. pp::Size GetPageSize(int index); void UpdateTickMarks(); // Called to continue searching so we don't block the main thread. void ContinueFind(int32_t result); // Inserts a find result into find_results_, which is sorted. void AddFindResult(const PDFiumRange& result); // Search a page using PDFium's methods. Doesn't work with unicode. This // function is just kept arount in case PDFium code is fixed. void SearchUsingPDFium(const base::string16& term, bool case_sensitive, bool first_search, int character_to_start_searching_from, int current_page); // Search a page ourself using ICU. void SearchUsingICU(const base::string16& term, bool case_sensitive, bool first_search, int character_to_start_searching_from, int current_page); // Input event handlers. bool OnMouseDown(const pp::MouseInputEvent& event); bool OnMouseUp(const pp::MouseInputEvent& event); bool OnMouseMove(const pp::MouseInputEvent& event); bool OnKeyDown(const pp::KeyboardInputEvent& event); bool OnKeyUp(const pp::KeyboardInputEvent& event); bool OnChar(const pp::KeyboardInputEvent& event); pp::Buffer_Dev PrintPagesAsRasterPDF( const PP_PrintPageNumberRange_Dev* page_ranges, uint32_t page_range_count, const PP_PrintSettings_Dev& print_settings); pp::Buffer_Dev PrintPagesAsPDF(const PP_PrintPageNumberRange_Dev* page_ranges, uint32_t page_range_count, const PP_PrintSettings_Dev& print_settings); pp::Buffer_Dev GetFlattenedPrintData(const FPDF_DOCUMENT& doc); void FitContentsToPrintableAreaIfRequired( const FPDF_DOCUMENT& doc, const PP_PrintSettings_Dev& print_settings); void SaveSelectedFormForPrint(); // Given a mouse event, returns which page and character location it's closest // to. PDFiumPage::Area GetCharIndex(const pp::MouseInputEvent& event, int* page_index, int* char_index, PDFiumPage::LinkTarget* target); PDFiumPage::Area GetCharIndex(const pp::Point& point, int* page_index, int* char_index, PDFiumPage::LinkTarget* target); void OnSingleClick(int page_index, int char_index); void OnMultipleClick(int click_count, int page_index, int char_index); // Starts a progressive paint operation given a rectangle in screen // coordinates. Returns the index in progressive_rects_. int StartPaint(int page_index, const pp::Rect& dirty); // Continues a paint operation that was started earlier. Returns true if the // paint is done, or false if it needs to be continued. bool ContinuePaint(int progressive_index, pp::ImageData* image_data); // Called once PDFium is finished rendering a page so that we draw our // borders, highlighting etc. void FinishPaint(int progressive_index, pp::ImageData* image_data); // Stops any paints that are in progress. void CancelPaints(); // Invalidates all pages. Use this when some global parameter, such as page // orientation, has changed. void InvalidateAllPages(); // If the page is narrower than the document size, paint the extra space // with the page background. void FillPageSides(int progressive_index); void PaintPageShadow(int progressive_index, pp::ImageData* image_data); // Highlight visible find results and selections. void DrawSelections(int progressive_index, pp::ImageData* image_data); // Paints an page that hasn't finished downloading. void PaintUnavailablePage(int page_index, const pp::Rect& dirty, pp::ImageData* image_data); // Given a page index, returns the corresponding index in progressive_rects_, // or -1 if it doesn't exist. int GetProgressiveIndex(int page_index) const; // Creates a FPDF_BITMAP from a rectangle in screen coordinates. FPDF_BITMAP CreateBitmap(const pp::Rect& rect, pp::ImageData* image_data) const; // Given a rectangle in screen coordinates, returns the coordinates in the // units that PDFium rendering functions expect. void GetPDFiumRect(int page_index, const pp::Rect& rect, int* start_x, int* start_y, int* size_x, int* size_y) const; // Returns the rendering flags to pass to PDFium. int GetRenderingFlags() const; // Returns the currently visible rectangle in document coordinates. pp::Rect GetVisibleRect() const; // Returns a page's rect in screen coordinates, as well as its surrounding // border areas and bottom separator. pp::Rect GetPageScreenRect(int page_index) const; // Given a rectangle in document coordinates, returns the rectange into screen // coordinates (i.e. 0,0 is top left corner of plugin area). If it's not // visible, an empty rectangle is returned. pp::Rect GetScreenRect(const pp::Rect& rect) const; // Highlights the given rectangle. void Highlight(void* buffer, int stride, const pp::Rect& rect, std::vector<pp::Rect>* highlighted_rects); // Helper function to convert a device to page coordinates. If the page is // not yet loaded, page_x and page_y will be set to 0. void DeviceToPage(int page_index, float device_x, float device_y, double* page_x, double* page_y); // Helper function to get the index of a given FPDF_PAGE. Returns -1 if not // found. int GetVisiblePageIndex(FPDF_PAGE page); // Helper function to change the current page, running page open/close // triggers as necessary. void SetCurrentPage(int index); // Transform |page| contents to fit in the selected printer paper size. void TransformPDFPageForPrinting(FPDF_PAGE page, const PP_PrintSettings_Dev& print_settings); void DrawPageShadow(const pp::Rect& page_rect, const pp::Rect& shadow_rect, const pp::Rect& clip_rect, pp::ImageData* image_data); void GetRegion(const pp::Point& location, pp::ImageData* image_data, void** region, int* stride) const; // Called when the selection changes. void OnSelectionChanged(); // FPDF_FORMFILLINFO callbacks. static void Form_Invalidate(FPDF_FORMFILLINFO* param, FPDF_PAGE page, double left, double top, double right, double bottom); static void Form_OutputSelectedRect(FPDF_FORMFILLINFO* param, FPDF_PAGE page, double left, double top, double right, double bottom); static void Form_SetCursor(FPDF_FORMFILLINFO* param, int cursor_type); static int Form_SetTimer(FPDF_FORMFILLINFO* param, int elapse, TimerCallback timer_func); static void Form_KillTimer(FPDF_FORMFILLINFO* param, int timer_id); static FPDF_SYSTEMTIME Form_GetLocalTime(FPDF_FORMFILLINFO* param); static void Form_OnChange(FPDF_FORMFILLINFO* param); static FPDF_PAGE Form_GetPage(FPDF_FORMFILLINFO* param, FPDF_DOCUMENT document, int page_index); static FPDF_PAGE Form_GetCurrentPage(FPDF_FORMFILLINFO* param, FPDF_DOCUMENT document); static int Form_GetRotation(FPDF_FORMFILLINFO* param, FPDF_PAGE page); static void Form_ExecuteNamedAction(FPDF_FORMFILLINFO* param, FPDF_BYTESTRING named_action); static void Form_SetTextFieldFocus(FPDF_FORMFILLINFO* param, FPDF_WIDESTRING value, FPDF_DWORD valueLen, FPDF_BOOL is_focus); static void Form_DoURIAction(FPDF_FORMFILLINFO* param, FPDF_BYTESTRING uri); static void Form_DoGoToAction(FPDF_FORMFILLINFO* param, int page_index, int zoom_mode, float* position_array, int size_of_array); // IPDF_JSPLATFORM callbacks. static int Form_Alert(IPDF_JSPLATFORM* param, FPDF_WIDESTRING message, FPDF_WIDESTRING title, int type, int icon); static void Form_Beep(IPDF_JSPLATFORM* param, int type); static int Form_Response(IPDF_JSPLATFORM* param, FPDF_WIDESTRING question, FPDF_WIDESTRING title, FPDF_WIDESTRING default_response, FPDF_WIDESTRING label, FPDF_BOOL password, void* response, int length); static int Form_GetFilePath(IPDF_JSPLATFORM* param, void* file_path, int length); static void Form_Mail(IPDF_JSPLATFORM* param, void* mail_data, int length, FPDF_BOOL ui, FPDF_WIDESTRING to, FPDF_WIDESTRING subject, FPDF_WIDESTRING cc, FPDF_WIDESTRING bcc, FPDF_WIDESTRING message); static void Form_Print(IPDF_JSPLATFORM* param, FPDF_BOOL ui, int start, int end, FPDF_BOOL silent, FPDF_BOOL shrink_to_fit, FPDF_BOOL print_as_image, FPDF_BOOL reverse, FPDF_BOOL annotations); static void Form_SubmitForm(IPDF_JSPLATFORM* param, void* form_data, int length, FPDF_WIDESTRING url); static void Form_GotoPage(IPDF_JSPLATFORM* param, int page_number); static int Form_Browse(IPDF_JSPLATFORM* param, void* file_path, int length); // IFSDK_PAUSE callbacks static FPDF_BOOL Pause_NeedToPauseNow(IFSDK_PAUSE* param); PDFEngine::Client* client_; pp::Size document_size_; // Size of document in pixels. // The scroll position in screen coordinates. pp::Point position_; // The offset of the page into the viewport. pp::Point page_offset_; // The plugin size in screen coordinates. pp::Size plugin_size_; double current_zoom_; unsigned int current_rotation_; DocumentLoader doc_loader_; // Main document's loader. std::string url_; std::string headers_; pp::CompletionCallbackFactory<PDFiumEngine> find_factory_; pp::CompletionCallbackFactory<PDFiumEngine> password_factory_; int32_t password_tries_remaining_; // The current text used for searching. std::string current_find_text_; // The PDFium wrapper object for the document. FPDF_DOCUMENT doc_; // The PDFium wrapper for form data. Used even if there are no form controls // on the page. FPDF_FORMHANDLE form_; // The page(s) of the document. Store a vector of pointers so that when the // vector is resized we don't close the pages that are used in pending // paints. std::vector<PDFiumPage*> pages_; // The indexes of the pages currently visible. std::vector<int> visible_pages_; // The indexes of the pages pending download. std::vector<int> pending_pages_; // During handling of input events we don't want to unload any pages in // callbacks to us from PDFium, since the current page can change while PDFium // code still has a pointer to it. bool defer_page_unload_; std::vector<int> deferred_page_unloads_; // Used for selection. There could be more than one range if selection spans // more than one page. std::vector<PDFiumRange> selection_; // True if we're in the middle of selection. bool selecting_; // Used for searching. typedef std::vector<PDFiumRange> FindResults; FindResults find_results_; // Which page to search next. int next_page_to_search_; // Where to stop searching. int last_page_to_search_; int last_character_index_to_search_; // -1 if search until end of page. // Which result the user has currently selected. int current_find_index_; // Permissions bitfield. unsigned long permissions_; // Interface structure to provide access to document stream. FPDF_FILEACCESS file_access_; // Interface structure to check data availability in the document stream. FileAvail file_availability_; // Interface structure to request data chunks from the document stream. DownloadHints download_hints_; // Pointer to the document availability interface. FPDF_AVAIL fpdf_availability_; pp::Size default_page_size_; // Used to manage timers that form fill API needs. The pair holds the timer // period, in ms, and the callback function. std::map<int, std::pair<int, TimerCallback> > timers_; int next_timer_id_; // Holds the page index of the last page that the mouse clicked on. int last_page_mouse_down_; // Holds the page index of the first visible page; refreshed by calling // CalculateVisiblePages() int first_visible_page_; // Holds the page index of the most visible page; refreshed by calling // CalculateVisiblePages() int most_visible_page_; // Set to true after FORM_DoDocumentJSAction/FORM_DoDocumentOpenAction have // been called. Only after that can we call FORM_DoPageAAction. bool called_do_document_action_; // Records parts of form fields that need to be highlighted at next paint, in // screen coordinates. std::vector<pp::Rect> form_highlights_; // Whether to render in grayscale or in color. bool render_grayscale_; // The link currently under the cursor. std::string link_under_cursor_; // Pending progressive paints. struct ProgressivePaint { pp::Rect rect; // In screen coordinates. FPDF_BITMAP bitmap; int page_index; // Temporary used to figure out if in a series of Paint() calls whether this // pending paint was updated or not. int painted_; }; std::vector<ProgressivePaint> progressive_paints_; // Keeps track of when we started the last progressive paint, so that in our // callback we can determine if we need to pause. base::Time last_progressive_start_time_; // The timeout to use for the current progressive paint. int progressive_paint_timeout_; // Shadow matrix for generating the page shadow bitmap. scoped_ptr<ShadowMatrix> page_shadow_; // Set to true if the user is being prompted for their password. Will be set // to false after the user finishes getting their password. bool getting_password_; }; // Create a local variable of this when calling PDFium functions which can call // our global callback when an unsupported feature is reached. class ScopedUnsupportedFeature { public: explicit ScopedUnsupportedFeature(PDFiumEngine* engine); ~ScopedUnsupportedFeature(); private: PDFiumEngine* engine_; PDFiumEngine* old_engine_; }; class PDFiumEngineExports : public PDFEngineExports { public: PDFiumEngineExports() {} #if defined(OS_WIN) // See the definition of RenderPDFPageToDC in pdf.cc for details. virtual bool RenderPDFPageToDC(const void* pdf_buffer, int buffer_size, int page_number, const RenderingSettings& settings, HDC dc); #endif // OS_WIN virtual bool RenderPDFPageToBitmap(const void* pdf_buffer, int pdf_buffer_size, int page_number, const RenderingSettings& settings, void* bitmap_buffer); virtual bool GetPDFDocInfo(const void* pdf_buffer, int buffer_size, int* page_count, double* max_page_width); }; } // namespace chrome_pdf #endif // PDF_PDFIUM_PDFIUM_ENGINE_H_