#ifndef PDF_PDFIUM_PDFIUM_ENGINE_H_
#define PDF_PDFIUM_PDFIUM_ENGINE_H_
#include <stddef.h>
#include <stdint.h>
#include <map>
#include <memory>
#include <string>
#include <vector>
#include "base/check.h"
#include "base/containers/flat_map.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "base/values.h"
#include "pdf/document_attachment_info.h"
#include "pdf/document_layout.h"
#include "pdf/document_metadata.h"
#include "pdf/loader/document_loader.h"
#include "pdf/pdf_engine.h"
#include "pdf/pdfium/pdfium_form_filler.h"
#include "pdf/pdfium/pdfium_page.h"
#include "pdf/pdfium/pdfium_print.h"
#include "pdf/pdfium/pdfium_range.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "third_party/pdfium/public/cpp/fpdf_scopers.h"
#include "third_party/pdfium/public/fpdf_formfill.h"
#include "third_party/pdfium/public/fpdf_progressive.h"
#include "third_party/pdfium/public/fpdfview.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/rect_f.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/geometry/vector2d.h"
namespace blink {
class WebKeyboardEvent;
class WebMouseEvent;
class WebTouchEvent;
}
namespace chrome_pdf {
enum class AccessibilityScrollAlignment;
class PDFiumDocument;
class PDFiumPermissions;
struct AccessibilityActionData;
struct AccessibilityTextRunInfo;
struct PageCharacterIndex;
namespace draw_utils {
class ShadowMatrix;
struct PageInsetSizes;
}
class PDFiumEngine : public PDFEngine,
public DocumentLoader::Client,
public IFSDK_PAUSE {
public:
enum class FocusElementType { kNone, kDocument, kPage };
PDFiumEngine(PDFEngine::Client* client,
PDFiumFormFiller::ScriptOption script_option);
PDFiumEngine(const PDFiumEngine&) = delete;
PDFiumEngine& operator=(const PDFiumEngine&) = delete;
~PDFiumEngine() override;
void SetDocumentLoaderForTesting(std::unique_ptr<DocumentLoader> loader);
static FontMappingMode GetFontMappingMode();
bool HandleDocumentLoad(std::unique_ptr<UrlLoader> loader,
const std::string& original_url);
void PageOffsetUpdated(const gfx::Vector2d& page_offset) override;
void PluginSizeUpdated(const gfx::Size& size) override;
void ScrolledToXPosition(int position) override;
void ScrolledToYPosition(int position) override;
void PrePaint() override;
void Paint(const gfx::Rect& rect,
SkBitmap& image_data,
std::vector<gfx::Rect>& ready,
std::vector<gfx::Rect>& pending) override;
void PostPaint() override;
bool HandleInputEvent(const blink::WebInputEvent& event) override;
void PrintBegin() override;
std::vector<uint8_t> PrintPages(
const std::vector<int>& page_numbers,
const blink::WebPrintParams& print_params) override;
void PrintEnd() override;
void StartFind(const std::u16string& text, bool case_sensitive) override;
bool SelectFindResult(bool forward) override;
void StopFind() override;
void ZoomUpdated(double new_zoom_level) override;
void RotateClockwise() override;
void RotateCounterclockwise() override;
#if defined(OHOS_PDF)
void ResetDesiredLayoutOptions() override;
#endif
bool IsReadOnly() const override;
void SetReadOnly(bool enable) override;
void SetDocumentLayout(DocumentLayout::PageSpread page_spread) override;
void DisplayAnnotations(bool display) override;
gfx::Size ApplyDocumentLayout(
const DocumentLayout::Options& options) override;
std::string GetSelectedText() override;
bool CanEditText() const override;
bool HasEditableText() const override;
void ReplaceSelection(const std::string& text) override;
bool CanUndo() const override;
bool CanRedo() const override;
void Undo() override;
void Redo() override;
void HandleAccessibilityAction(
const AccessibilityActionData& action_data) override;
std::string GetLinkAtPosition(const gfx::Point& point) override;
bool HasPermission(DocumentPermission permission) const override;
void SelectAll() override;
const std::vector<DocumentAttachmentInfo>& GetDocumentAttachmentInfoList()
const override;
std::vector<uint8_t> GetAttachmentData(size_t index) override;
const DocumentMetadata& GetDocumentMetadata() const override;
int GetNumberOfPages() const override;
base::Value::List GetBookmarks() override;
absl::optional<PDFEngine::NamedDestination> GetNamedDestination(
const std::string& destination) override;
int GetMostVisiblePage() override;
gfx::Rect GetPageBoundsRect(int index) override;
gfx::Rect GetPageContentsRect(int index) override;
gfx::Rect GetPageScreenRect(int page_index) const override;
gfx::RectF GetPageBoundingBox(int page_index) override;
void SetGrayscale(bool grayscale) override;
int GetCharCount(int page_index) override;
gfx::RectF GetCharBounds(int page_index, int char_index) override;
uint32_t GetCharUnicode(int page_index, int char_index) override;
absl::optional<AccessibilityTextRunInfo> GetTextRunInfo(
int page_index,
int start_char_index) override;
std::vector<AccessibilityLinkInfo> GetLinkInfo(
int page_index,
const std::vector<AccessibilityTextRunInfo>& text_runs) override;
std::vector<AccessibilityImageInfo> GetImageInfo(
int page_index,
uint32_t text_run_count) override;
std::vector<AccessibilityHighlightInfo> GetHighlightInfo(
int page_index,
const std::vector<AccessibilityTextRunInfo>& text_runs) override;
std::vector<AccessibilityTextFieldInfo> GetTextFieldInfo(
int page_index,
uint32_t text_run_count) override;
bool GetPrintScaling() override;
int GetCopiesToPrint() override;
printing::mojom::DuplexMode GetDuplexMode() override;
absl::optional<gfx::Size> GetUniformPageSizePoints() override;
void AppendBlankPages(size_t num_pages) override;
void AppendPage(PDFEngine* engine, int index) override;
std::vector<uint8_t> GetSaveData() override;
void SetCaretPosition(const gfx::Point& position) override;
void MoveRangeSelectionExtent(const gfx::Point& extent) override;
void SetSelectionBounds(const gfx::Point& base,
const gfx::Point& extent) override;
void GetSelection(uint32_t* selection_start_page_index,
uint32_t* selection_start_char_index,
uint32_t* selection_end_page_index,
uint32_t* selection_end_char_index) override;
void KillFormFocus() override;
void UpdateFocus(bool has_focus) override;
AccessibilityFocusInfo GetFocusInfo() override;
uint32_t GetLoadedByteSize() override;
bool ReadLoadedBytes(uint32_t length, void* buffer) override;
void RequestThumbnail(int page_index,
float device_pixel_ratio,
SendThumbnailCallback send_callback) override;
std::unique_ptr<URLLoaderWrapper> CreateURLLoader() override;
void OnPendingRequestComplete() override;
void OnNewDataReceived() override;
void OnDocumentComplete() override;
void OnDocumentCanceled() override;
#if defined(PDF_ENABLE_XFA)
void UpdatePageCount();
#endif
void UnsupportedFeature(const std::string& feature);
FPDF_AVAIL fpdf_availability() const;
FPDF_DOCUMENT doc() const;
FPDF_FORMHANDLE form() const;
PDFiumPage* GetPage(size_t index);
bool IsValidLink(const std::string& url);
private:
class SelectionChangeInvalidator {
public:
explicit SelectionChangeInvalidator(PDFiumEngine* engine);
~SelectionChangeInvalidator();
private:
std::vector<gfx::Rect> GetVisibleSelections() const;
void Invalidate(const gfx::Rect& selection);
const raw_ptr<PDFiumEngine> engine_;
const gfx::Point previous_origin_;
std::vector<gfx::Rect> old_selections_;
};
class MouseDownState {
public:
MouseDownState(const PDFiumPage::Area& area,
const PDFiumPage::LinkTarget& target);
MouseDownState(const MouseDownState&) = delete;
MouseDownState& operator=(const MouseDownState&) = delete;
~MouseDownState();
void Set(const PDFiumPage::Area& area,
const PDFiumPage::LinkTarget& target);
void Reset();
bool Matches(const PDFiumPage::Area& area,
const PDFiumPage::LinkTarget& target) const;
private:
PDFiumPage::Area area_;
PDFiumPage::LinkTarget target_;
};
friend class FormFillerTest;
friend class PDFiumEngineTabbingTest;
friend class PDFiumFormFiller;
friend class PDFiumTestBase;
friend class SelectionChangeInvalidator;
gfx::Size plugin_size() const {
DCHECK(plugin_size_.has_value());
return plugin_size_.value_or(gfx::Size());
}
void LoadDocument();
bool TryLoadingDoc(const std::string& password, bool* needs_password);
void GetPasswordAndLoad();
void OnGetPasswordComplete(const std::string& password);
void ContinueLoadingDocument(const std::string& password);
void FinishLoadingDocument();
void LoadPageInfo();
void RefreshCurrentDocumentLayout();
void ProposeNextDocumentLayout();
void UpdateDocumentLayout(DocumentLayout* layout);
std::vector<gfx::Size> LoadPageSizes(
const DocumentLayout::Options& layout_options);
void LoadBody();
void LoadPages();
void LoadForm();
bool IsLinearized();
void CalculateVisiblePages();
bool IsPageVisible(int index) const;
void ScrollToPage(int page);
bool CheckPageAvailable(int index, std::vector<int>* pending);
gfx::Size GetPageSize(int index);
gfx::Size GetPageSizeForLayout(int index,
const DocumentLayout::Options& layout_options);
draw_utils::PageInsetSizes GetInsetSizes(
const DocumentLayout::Options& layout_options,
size_t page_index,
size_t num_of_pages) const;
void EnlargePage(const DocumentLayout::Options& layout_options,
size_t page_index,
size_t num_of_pages,
gfx::Size* page_size) const;
void InsetPage(const DocumentLayout::Options& layout_options,
size_t page_index,
size_t num_of_pages,
double multiplier,
gfx::Rect& rect) const;
absl::optional<size_t> GetAdjacentPageIndexForTwoUpView(
size_t page_index,
size_t num_of_pages) const;
std::vector<gfx::Rect> GetAllScreenRectsUnion(
const std::vector<PDFiumRange>& rect_range,
const gfx::Point& point) const;
void UpdateTickMarks();
void ContinueFind(bool case_sensitive);
void AddFindResult(const PDFiumRange& result);
void SearchUsingPDFium(const std::u16string& term,
bool case_sensitive,
bool first_search,
int character_to_start_searching_from,
int current_page);
void SearchUsingICU(const std::u16string& term,
bool case_sensitive,
bool first_search,
int character_to_start_searching_from,
int current_page);
bool OnMouseDown(const blink::WebMouseEvent& event);
bool OnMouseUp(const blink::WebMouseEvent& event);
bool OnMouseMove(const blink::WebMouseEvent& event);
void OnMouseEnter(const blink::WebMouseEvent& event);
bool OnKeyDown(const blink::WebKeyboardEvent& event);
bool OnKeyUp(const blink::WebKeyboardEvent& event);
bool OnChar(const blink::WebKeyboardEvent& event);
ui::mojom::CursorType DetermineCursorType(PDFiumPage::Area area,
int form_type) const;
bool ExtendSelection(int page_index, int char_index);
std::vector<uint8_t> PrintPagesAsRasterPdf(
const std::vector<int>& page_numbers,
const blink::WebPrintParams& print_params);
std::vector<uint8_t> PrintPagesAsPdf(
const std::vector<int>& page_numbers,
const blink::WebPrintParams& print_params);
void SetFormSelectedText(FPDF_FORMHANDLE form_handle, FPDF_PAGE page);
PDFiumPage::Area GetCharIndex(const gfx::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);
bool OnLeftMouseDown(const blink::WebMouseEvent& event);
bool OnMiddleMouseDown(const blink::WebMouseEvent& event);
bool OnRightMouseDown(const blink::WebMouseEvent& event);
int StartPaint(int page_index, const gfx::Rect& dirty);
bool ContinuePaint(int progressive_index, SkBitmap& image_data);
void FinishPaint(int progressive_index, SkBitmap& image_data);
void CancelPaints();
void InvalidateAllPages();
void FillPageSides(int progressive_index);
void PaintPageShadow(int progressive_index, SkBitmap& image_data);
void DrawSelections(int progressive_index, SkBitmap& image_data) const;
void PaintUnavailablePage(int page_index,
const gfx::Rect& dirty,
SkBitmap& image_data);
int GetProgressiveIndex(int page_index) const;
ScopedFPDFBitmap CreateBitmap(const gfx::Rect& rect,
bool has_alpha,
SkBitmap& image_data) const;
void GetPDFiumRect(int page_index,
const gfx::Rect& rect,
int* start_x,
int* start_y,
int* size_x,
int* size_y) const;
int GetRenderingFlags() const;
gfx::Rect GetVisibleRect() const;
gfx::Rect GetScreenRect(const gfx::Rect& rect) const;
void Highlight(void* buffer,
int stride,
const gfx::Rect& rect,
int color_red,
int color_green,
int color_blue,
std::vector<gfx::Rect>& highlighted_rects) const;
void DeviceToPage(int page_index,
const gfx::Point& device_point,
double* page_x,
double* page_y);
int GetVisiblePageIndex(FPDF_PAGE page);
void SetCurrentPage(int index);
void DrawPageShadow(const gfx::Rect& page_rect,
const gfx::Rect& shadow_rect,
const gfx::Rect& clip_rect,
SkBitmap& image_data);
void GetRegion(const gfx::Point& location,
SkBitmap& image_data,
void*& region,
int& stride) const;
void OnSelectionTextChanged();
void OnSelectionPositionChanged();
void SetSelecting(bool selecting);
void SetFieldFocus(PDFEngine::FocusFieldType type);
void SetMouseLeftButtonDown(bool is_mouse_left_button_down);
bool IsAnnotationAnEditableFormTextArea(FPDF_ANNOTATION annot,
int form_type) const;
bool PageIndexInBounds(int index) const;
bool IsPageCharacterIndexInBounds(const PageCharacterIndex& index) const;
void ScheduleTouchTimer(const blink::WebTouchEvent& event);
void KillTouchTimer();
void HandleLongPress(const blink::WebTouchEvent& event);
base::Value::Dict TraverseBookmarks(FPDF_BOOKMARK bookmark,
unsigned int depth);
void ScrollBasedOnScrollAlignment(
const gfx::Rect& scroll_rect,
const AccessibilityScrollAlignment& horizontal_scroll_alignment,
const AccessibilityScrollAlignment& vertical_scroll_alignment);
void ScrollToGlobalPoint(const gfx::Rect& target_rect,
const gfx::Point& global_point);
void EnteredEditMode();
bool NavigateToLinkDestination(PDFiumPage::Area area,
const PDFiumPage::LinkTarget& target,
WindowOpenDisposition disposition);
static FPDF_BOOL Pause_NeedToPauseNow(IFSDK_PAUSE* param);
void SetSelection(const PageCharacterIndex& selection_start_index,
const PageCharacterIndex& selection_end_index);
void ScrollFocusedAnnotationIntoView();
void ScrollAnnotationIntoView(FPDF_ANNOTATION annot, int page_index);
void OnFocusedAnnotationUpdated(FPDF_ANNOTATION annot, int page_index);
void LoadDocumentAttachmentInfoList();
void LoadDocumentMetadata();
std::string GetTrimmedMetadataByField(FPDF_BYTESTRING field) const;
PdfVersion GetDocumentVersion() const;
bool HandleTabEvent(int modifiers);
bool HandleTabEventWithModifiers(int modifiers);
bool HandleTabForward(int modifiers);
bool HandleTabBackward(int modifiers);
void UpdateFocusElementType(FocusElementType focus_element_type);
void UpdateLinkUnderCursor(const std::string& target_url);
void SetLinkUnderCursorForAnnotation(FPDF_ANNOTATION annot, int page_index);
void MaybeRequestPendingThumbnail(int page_index);
const raw_ptr<PDFEngine::Client> client_;
DocumentLayout layout_;
DocumentLayout::Options desired_layout_options_;
gfx::Point position_;
gfx::Vector2d page_offset_;
absl::optional<gfx::Size> plugin_size_;
double current_zoom_ = 1.0;
gfx::Rect caret_rect_;
std::unique_ptr<DocumentLoader> doc_loader_;
bool doc_loader_set_for_testing_ = false;
bool getting_password_ = false;
int password_tries_remaining_ = 0;
PDFiumFormFiller form_filler_;
std::unique_ptr<PDFiumDocument> document_;
bool document_pending_ = false;
bool document_loaded_ = false;
std::vector<std::unique_ptr<PDFiumPage>> pages_;
std::vector<int> visible_pages_;
std::vector<int> pending_pages_;
bool defer_page_unload_ = false;
std::vector<int> deferred_page_unloads_;
std::vector<PDFiumRange> selection_;
bool selecting_ = false;
MouseDownState mouse_down_state_;
std::string selected_form_text_;
bool mouse_left_button_down_ = false;
bool mouse_middle_button_down_ = false;
gfx::Point mouse_middle_button_last_position_;
std::u16string current_find_text_;
std::vector<PDFiumRange> find_results_;
bool search_in_progress_ = false;
int next_page_to_search_ = -1;
int last_page_to_search_ = -1;
int last_character_index_to_search_ = -1;
absl::optional<size_t> current_find_index_;
absl::optional<size_t> resume_find_index_;
std::unique_ptr<PDFiumPermissions> permissions_;
gfx::Size default_page_size_;
base::OneShotTimer touch_timer_;
bool handling_long_press_ = false;
bool updating_focus_ = false;
bool editable_form_text_area_ = false;
FocusFieldType focus_field_type_ = FocusFieldType::kNoFocus;
FocusElementType focus_element_type_ = FocusElementType::kNone;
FocusElementType last_focused_element_type_ = FocusElementType::kNone;
int last_focused_annot_index_ = -1;
int last_focused_page_ = -1;
int most_visible_page_ = -1;
absl::optional<int> in_flight_visible_page_;
bool called_do_document_action_ = false;
std::vector<gfx::Rect> form_highlights_;
bool render_grayscale_ = false;
bool render_annots_ = true;
class ProgressivePaint {
public:
ProgressivePaint(int page_index, const gfx::Rect& rect);
ProgressivePaint(ProgressivePaint&& that);
ProgressivePaint& operator=(ProgressivePaint&& that);
~ProgressivePaint();
int page_index() const { return page_index_; }
const gfx::Rect& rect() const { return rect_; }
FPDF_BITMAP bitmap() const { return bitmap_.get(); }
bool painted() const { return painted_; }
void set_painted(bool enable) { painted_ = enable; }
void SetBitmapAndImageData(ScopedFPDFBitmap bitmap, SkBitmap image_data);
private:
int page_index_;
gfx::Rect rect_;
SkBitmap image_data_;
ScopedFPDFBitmap bitmap_;
bool painted_ = false;
};
std::vector<ProgressivePaint> progressive_paints_;
base::Time last_progressive_start_time_;
base::TimeDelta progressive_paint_timeout_;
std::unique_ptr<draw_utils::ShadowMatrix> page_shadow_;
struct PendingThumbnail {
PendingThumbnail();
PendingThumbnail(PendingThumbnail&& that);
PendingThumbnail& operator=(PendingThumbnail&& that);
~PendingThumbnail();
float device_pixel_ratio = 1.0f;
SendThumbnailCallback send_callback;
};
base::flat_map<int, PendingThumbnail> pending_thumbnails_;
std::vector<DocumentAttachmentInfo> doc_attachment_info_list_;
DocumentMetadata doc_metadata_;
bool process_when_pending_request_complete_ = true;
enum class RangeSelectionDirection { Left, Right };
RangeSelectionDirection range_selection_direction_ =
RangeSelectionDirection::Right;
gfx::Point range_selection_base_;
bool edit_mode_ = false;
bool read_only_ = false;
PDFiumPrint print_;
base::WeakPtrFactory<PDFiumEngine> weak_factory_{this};
base::WeakPtrFactory<PDFiumEngine> find_weak_factory_{this};
};
}
#endif