blob: ac05303594492aa37e506e9eb325fa238d33b30d [file] [log] [blame]
// 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.
#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 "ppapi/cpp/var_array.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;
class VarDictionary;
namespace chrome_pdf {
class ShadowMatrix;
class PDFiumEngine : public PDFEngine,
public DocumentLoader::Client,
public IFSDK_PAUSE {
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 pp::VarArray GetBookmarks();
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 int GetCopiesToPrint();
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_; }
// 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 {
explicit SelectionChangeInvalidator(PDFiumEngine* engine);
// 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_;
// Used to store mouse down state to handle it in other mouse event handlers.
class MouseDownState {
MouseDownState(const PDFiumPage::Area& area,
const PDFiumPage::LinkTarget& target);
void Set(const PDFiumPage::Area& area,
const PDFiumPage::LinkTarget& target);
void Reset();
bool Matches(const PDFiumPage::Area& area,
const PDFiumPage::LinkTarget& target) const;
PDFiumPage::Area area_;
PDFiumPage::LinkTarget target_;
// Used to store the state of a text search.
class FindTextIndex {
bool valid() const { return valid_; }
void Invalidate();
size_t GetIndex() const;
void SetIndex(size_t index);
size_t IncrementIndex();
bool valid_; // Whether |index_| is valid or not.
size_t index_; // The current search result, 0-based.
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 GetAllScreenRectsUnion(std::vector<PDFiumRange>* rect_range,
const pp::Point& offset_point,
std::vector<pp::Rect>* rect_vector);
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);
FPDF_DOCUMENT CreateSinglePageRasterPdf(
double source_page_width,
double source_page_height,
const PP_PrintSettings_Dev& print_settings,
PDFiumPage* page_to_print);
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,
int* form_type,
PDFiumPage::LinkTarget* target);
PDFiumPage::Area GetCharIndex(const pp::Point& point,
int* page_index,
int* char_index,
int* form_type,
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();
// Common code shared by RotateClockwise() and RotateCounterclockwise().
void RotateInternal();
// Setting selection status of document.
void SetSelecting(bool selecting);
static void Form_Invalidate(FPDF_FORMFILLINFO* param,
double left,
double top,
double right,
double bottom);
static void Form_OutputSelectedRect(FPDF_FORMFILLINFO* param,
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 void Form_OnChange(FPDF_FORMFILLINFO* param);
static FPDF_PAGE Form_GetPage(FPDF_FORMFILLINFO* param,
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_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,
int type,
int icon);
static void Form_Beep(IPDF_JSPLATFORM* param, int type);
static int Form_Response(IPDF_JSPLATFORM* param,
FPDF_WIDESTRING default_response,
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,
static void Form_Print(IPDF_JSPLATFORM* param,
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,
static void Form_GotoPage(IPDF_JSPLATFORM* param, int page_number);
static int Form_Browse(IPDF_JSPLATFORM* param, void* file_path, int length);
#ifdef PDF_USE_XFA
static void Form_EmailTo(FPDF_FORMFILLINFO* param,
FPDF_FILEHANDLER* file_handler,
static void Form_DisplayCaret(FPDF_FORMFILLINFO* param,
FPDF_BOOL visible,
double left,
double top,
double right,
double bottom);
static void Form_SetCurrentPage(FPDF_FORMFILLINFO* param,
int page);
static int Form_GetCurrentPageIndex(FPDF_FORMFILLINFO* param,
FPDF_DOCUMENT document);
static void Form_GetPageViewRect(FPDF_FORMFILLINFO* param,
double* left,
double* top,
double* right,
double* bottom);
static int Form_GetPlatform(FPDF_FORMFILLINFO* param,
void* platform,
int length);
static FPDF_BOOL Form_PopupMenu(FPDF_FORMFILLINFO* param,
int menu_flag,
float x,
float y);
static FPDF_BOOL Form_PostRequestURL(FPDF_FORMFILLINFO* param,
FPDF_WIDESTRING content_type,
FPDF_BSTR* response);
static FPDF_BOOL Form_PutRequestURL(FPDF_FORMFILLINFO* param,
static void Form_UploadTo(FPDF_FORMFILLINFO* param,
FPDF_FILEHANDLER* file_handler,
int file_flag,
int file_flag,
const char* mode);
static void Form_GotoURL(FPDF_FORMFILLINFO* param,
static int Form_GetLanguage(FPDF_FORMFILLINFO* param,
void* language,
int length);
#endif // PDF_USE_XFA
// 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.
// The PDFium wrapper for form data. Used even if there are no form controls
// on the page.
// 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_;
MouseDownState mouse_down_state_;
// 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.
FindTextIndex current_find_index_;
// Where to resume searching.
FindTextIndex resume_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.
int page_index;
// Temporary used to figure out if in a series of Paint() calls whether this
// pending paint was updated or not.
bool 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 {
explicit ScopedUnsupportedFeature(PDFiumEngine* engine);
PDFiumEngine* engine_;
PDFiumEngine* old_engine_;
class PDFiumEngineExports : public PDFEngineExports {
PDFiumEngineExports() {}
#if defined(OS_WIN)
// See the definition of RenderPDFPageToDC in 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);
// See the definition of GetPDFPageSizeByIndex in for details.
virtual bool GetPDFPageSizeByIndex(const void* pdf_buffer,
int pdf_buffer_size, int page_number,
double* width, double* height);
} // namespace chrome_pdf