summaryrefslogtreecommitdiff
path: root/chromium/pdf/pdfium
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/pdf/pdfium')
-rw-r--r--chromium/pdf/pdfium/accessibility_unittest.cc9
-rw-r--r--chromium/pdf/pdfium/pdfium_api_string_buffer_adapter.cc35
-rw-r--r--chromium/pdf/pdfium/pdfium_api_string_buffer_adapter.h80
-rw-r--r--chromium/pdf/pdfium/pdfium_assert_matching_enums.cc15
-rw-r--r--chromium/pdf/pdfium/pdfium_engine.cc234
-rw-r--r--chromium/pdf/pdfium/pdfium_engine.h28
-rw-r--r--chromium/pdf/pdfium/pdfium_engine_unittest.cc156
-rw-r--r--chromium/pdf/pdfium/pdfium_form_filler.cc15
-rw-r--r--chromium/pdf/pdfium/pdfium_page.cc180
-rw-r--r--chromium/pdf/pdfium/pdfium_page.h157
-rw-r--r--chromium/pdf/pdfium/pdfium_page_unittest.cc166
-rw-r--r--chromium/pdf/pdfium/pdfium_permissions.cc2
-rw-r--r--chromium/pdf/pdfium/pdfium_print.cc2
-rw-r--r--chromium/pdf/pdfium/pdfium_test_base.cc3
14 files changed, 831 insertions, 251 deletions
diff --git a/chromium/pdf/pdfium/accessibility_unittest.cc b/chromium/pdf/pdfium/accessibility_unittest.cc
index f23e103ffde..98eb154f5ae 100644
--- a/chromium/pdf/pdfium/accessibility_unittest.cc
+++ b/chromium/pdf/pdfium/accessibility_unittest.cc
@@ -485,7 +485,7 @@ TEST_F(AccessibilityTest, GetAccessibilityHighlightInfo) {
constexpr uint32_t kHighlightNoColor = MakeARGB(0, 0, 0, 0);
static const pp::PDF::PrivateAccessibilityHighlightInfo
kExpectedHighlightInfo[] = {
- {"", 0, 0, 1, {{5, 196}, {49, 26}}, kHighlightDefaultColor},
+ {"Text Note", 0, 0, 1, {{5, 196}, {49, 26}}, kHighlightDefaultColor},
{"", 1, 2, 1, {{110, 196}, {77, 26}}, kHighlightRedColor},
{"", 2, 3, 1, {{192, 196}, {13, 26}}, kHighlightNoColor}};
@@ -520,6 +520,7 @@ TEST_F(AccessibilityTest, GetAccessibilityHighlightInfo) {
EXPECT_EQ(highlight_info.text_run_count,
kExpectedHighlightInfo[i].text_run_count);
EXPECT_EQ(highlight_info.color, kExpectedHighlightInfo[i].color);
+ EXPECT_EQ(highlight_info.note_text, kExpectedHighlightInfo[i].note_text);
}
}
@@ -563,12 +564,12 @@ TEST_F(AccessibilityTest, GetAccessibilityTextFieldInfo) {
CompareRect(kExpectedPageRect, page_info.bounds);
EXPECT_EQ(text_runs.size(), page_info.text_run_count);
EXPECT_EQ(chars.size(), page_info.char_count);
- ASSERT_EQ(page_objects.text_fields.size(),
+ ASSERT_EQ(page_objects.form_fields.text_fields.size(),
base::size(kExpectedTextFieldInfo));
- for (size_t i = 0; i < page_objects.text_fields.size(); ++i) {
+ for (size_t i = 0; i < page_objects.form_fields.text_fields.size(); ++i) {
const pp::PDF::PrivateAccessibilityTextFieldInfo& text_field_info =
- page_objects.text_fields[i];
+ page_objects.form_fields.text_fields[i];
EXPECT_EQ(kExpectedTextFieldInfo[i].name, text_field_info.name);
EXPECT_EQ(kExpectedTextFieldInfo[i].value, text_field_info.value);
EXPECT_EQ(kExpectedTextFieldInfo[i].is_read_only,
diff --git a/chromium/pdf/pdfium/pdfium_api_string_buffer_adapter.cc b/chromium/pdf/pdfium/pdfium_api_string_buffer_adapter.cc
index 382b3a9385c..9e02e34906f 100644
--- a/chromium/pdf/pdfium/pdfium_api_string_buffer_adapter.cc
+++ b/chromium/pdf/pdfium/pdfium_api_string_buffer_adapter.cc
@@ -6,14 +6,13 @@
#include <stddef.h>
-#include <string>
-
#include "base/check_op.h"
-#include "base/strings/string16.h"
#include "base/strings/string_util.h"
namespace chrome_pdf {
+namespace internal {
+
template <class StringType>
PDFiumAPIStringBufferAdapter<StringType>::PDFiumAPIStringBufferAdapter(
StringType* str,
@@ -52,36 +51,30 @@ void PDFiumAPIStringBufferAdapter<StringType>::Close(size_t actual_size) {
}
}
-template <class StringType>
-PDFiumAPIStringBufferSizeInBytesAdapter<StringType>::
- PDFiumAPIStringBufferSizeInBytesAdapter(StringType* str,
+PDFiumAPIStringBufferSizeInBytesAdapter::
+ PDFiumAPIStringBufferSizeInBytesAdapter(base::string16* str,
size_t expected_size,
bool check_expected_size)
- : adapter_(str,
- expected_size / sizeof(typename StringType::value_type),
- check_expected_size) {
- DCHECK(expected_size % sizeof(typename StringType::value_type) == 0);
+ : adapter_(str, expected_size / sizeof(base::char16), check_expected_size) {
+ DCHECK(expected_size % sizeof(base::char16) == 0);
}
-template <class StringType>
-PDFiumAPIStringBufferSizeInBytesAdapter<
- StringType>::~PDFiumAPIStringBufferSizeInBytesAdapter() = default;
+PDFiumAPIStringBufferSizeInBytesAdapter::
+ ~PDFiumAPIStringBufferSizeInBytesAdapter() = default;
-template <class StringType>
-void* PDFiumAPIStringBufferSizeInBytesAdapter<StringType>::GetData() {
+void* PDFiumAPIStringBufferSizeInBytesAdapter::GetData() {
return adapter_.GetData();
}
-template <class StringType>
-void PDFiumAPIStringBufferSizeInBytesAdapter<StringType>::Close(
- size_t actual_size) {
- DCHECK(actual_size % sizeof(typename StringType::value_type) == 0);
- adapter_.Close(actual_size / sizeof(typename StringType::value_type));
+void PDFiumAPIStringBufferSizeInBytesAdapter::Close(size_t actual_size) {
+ DCHECK(actual_size % sizeof(base::char16) == 0);
+ adapter_.Close(actual_size / sizeof(base::char16));
}
// explicit instantiations
template class PDFiumAPIStringBufferAdapter<std::string>;
template class PDFiumAPIStringBufferAdapter<base::string16>;
-template class PDFiumAPIStringBufferSizeInBytesAdapter<base::string16>;
+
+} // namespace internal
} // namespace chrome_pdf
diff --git a/chromium/pdf/pdfium/pdfium_api_string_buffer_adapter.h b/chromium/pdf/pdfium/pdfium_api_string_buffer_adapter.h
index d3a413cd5a7..9c2587a19bf 100644
--- a/chromium/pdf/pdfium/pdfium_api_string_buffer_adapter.h
+++ b/chromium/pdf/pdfium/pdfium_api_string_buffer_adapter.h
@@ -7,16 +7,21 @@
#include <stddef.h>
+#include <string>
+
+#include "base/callback.h"
#include "base/macros.h"
#include "base/numerics/safe_math.h"
+#include "base/strings/string16.h"
namespace chrome_pdf {
+namespace internal {
+
// Helper to deal with the fact that many PDFium APIs write the null-terminator
-// into string buffers that are passed to them, but the PDF plugin likes to pass
-// in std::strings / base::string16s, where one should not count on the internal
+// into string buffers that are passed to them, but the PDF code likes to use
+// std::strings / base::string16s, where one should not count on the internal
// string buffers to be null-terminated.
-
template <class StringType>
class PDFiumAPIStringBufferAdapter {
public:
@@ -56,11 +61,11 @@ class PDFiumAPIStringBufferAdapter {
};
// Helper to deal with the fact that many PDFium APIs write the null-terminator
-// into string buffers that are passed to them, but the PDF plugin likes to pass
-// in std::strings / base::string16s, where one should not count on the internal
+// into string buffers that are passed to them, but the PDF code likes to use
+// std::strings / base::string16s, where one should not count on the internal
// string buffers to be null-terminated. This version is suitable for APIs that
-// work in terms of number of bytes instead of the number of characters.
-template <class StringType>
+// work in terms of number of bytes instead of the number of characters. Though
+// for std::strings, PDFiumAPIStringBufferAdapter is equivalent.
class PDFiumAPIStringBufferSizeInBytesAdapter {
public:
// |str| is the string to write into.
@@ -69,19 +74,19 @@ class PDFiumAPIStringBufferSizeInBytesAdapter {
// character in bytes.
// |check_expected_size| whether to check the actual number of bytes
// written into |str| against |expected_size| when calling Close().
- PDFiumAPIStringBufferSizeInBytesAdapter(StringType* str,
+ PDFiumAPIStringBufferSizeInBytesAdapter(base::string16* str,
size_t expected_size,
bool check_expected_size);
~PDFiumAPIStringBufferSizeInBytesAdapter();
// Returns a pointer to |str_|'s buffer. The buffer's size is large enough to
- // hold |expected_size_| + sizeof(StringType::value_type) bytes, so the PDFium
- // API that uses the pointer has space to write a null-terminator.
+ // hold |expected_size_| + sizeof(base::char16) bytes, so the PDFium API that
+ // uses the pointer has space to write a null-terminator.
void* GetData();
- // Resizes |str_| to |actual_size| - sizeof(StringType::value_type) bytes,
- // thereby removing the extra null-terminator. This must be called prior to
- // the adapter's destruction. The pointer returned by GetData() should be
+ // Resizes |str_| to |actual_size| - sizeof(base::char16) bytes, thereby
+ // removing the extra null-terminator. This must be called prior to the
+ // adapter's destruction. The pointer returned by GetData() should be
// considered invalid.
void Close(size_t actual_size);
@@ -91,9 +96,56 @@ class PDFiumAPIStringBufferSizeInBytesAdapter {
}
private:
- PDFiumAPIStringBufferAdapter<StringType> adapter_;
+ PDFiumAPIStringBufferAdapter<base::string16> adapter_;
};
+template <class AdapterType,
+ class StringType,
+ typename BufferType,
+ typename ReturnType>
+StringType CallPDFiumStringBufferApi(
+ base::RepeatingCallback<ReturnType(BufferType*, ReturnType)> api,
+ bool check_expected_size) {
+ StringType str;
+ ReturnType expected_size = api.Run(nullptr, 0);
+ if (expected_size > 0) {
+ AdapterType api_string_adapter(&str, expected_size, check_expected_size);
+ auto* data = reinterpret_cast<BufferType*>(api_string_adapter.GetData());
+ api_string_adapter.Close(api.Run(data, expected_size));
+ }
+ return str;
+}
+
+} // namespace internal
+
+// Helper function to call PDFium APIs where the output buffer is expected to
+// hold UTF-16 data, and the buffer length is specified in bytes.
+template <typename BufferType>
+base::string16 CallPDFiumWideStringBufferApi(
+ base::RepeatingCallback<unsigned long(BufferType*, unsigned long)> api,
+ bool check_expected_size) {
+ using adapter_type = internal::PDFiumAPIStringBufferSizeInBytesAdapter;
+ return internal::CallPDFiumStringBufferApi<adapter_type, base::string16>(
+ api, check_expected_size);
+}
+
+// Helper function to call PDFium APIs where the output buffer is expected to
+// hold ASCII or UTF-8 data, and the buffer length is specified in bytes.
+template <typename BufferType, typename ReturnType>
+std::string CallPDFiumStringBufferApi(
+ base::RepeatingCallback<ReturnType(BufferType*, ReturnType)> api,
+ bool check_expected_size) {
+ using adapter_type = internal::PDFiumAPIStringBufferAdapter<std::string>;
+ return internal::CallPDFiumStringBufferApi<adapter_type, std::string>(
+ api, check_expected_size);
+}
+
+// Expose internal::PDFiumAPIStringBufferAdapter for special cases that cannot
+// use the CallPDFiumStringBuffer* functions above.
+template <class StringType>
+using PDFiumAPIStringBufferAdapter =
+ internal::PDFiumAPIStringBufferAdapter<StringType>;
+
} // namespace chrome_pdf
#endif // PDF_PDFIUM_PDFIUM_API_STRING_BUFFER_ADAPTER_H_
diff --git a/chromium/pdf/pdfium/pdfium_assert_matching_enums.cc b/chromium/pdf/pdfium/pdfium_assert_matching_enums.cc
index a58ecff0daa..fc52f804e9c 100644
--- a/chromium/pdf/pdfium/pdfium_assert_matching_enums.cc
+++ b/chromium/pdf/pdfium/pdfium_assert_matching_enums.cc
@@ -4,10 +4,12 @@
#include "build/build_config.h"
#include "pdf/pdf.h"
+#include "pdf/pdf_engine.h"
#include "ppapi/c/pp_input_event.h"
#include "ppapi/c/private/ppb_pdf.h"
#include "ppapi/c/private/ppp_pdf.h"
#include "third_party/pdfium/public/fpdf_edit.h"
+#include "third_party/pdfium/public/fpdf_formfill.h"
#include "third_party/pdfium/public/fpdf_fwlevent.h"
#include "third_party/pdfium/public/fpdf_sysfontinfo.h"
#include "third_party/pdfium/public/fpdfview.h"
@@ -229,6 +231,19 @@ STATIC_ASSERT_ENUM(PP_TEXTRENDERINGMODE_FILLSTROKECLIP,
FPDF_TEXTRENDERMODE_FILL_STROKE_CLIP);
STATIC_ASSERT_ENUM(PP_TEXTRENDERINGMODE_CLIP, FPDF_TEXTRENDERMODE_CLIP);
+STATIC_ASSERT_ENUM(chrome_pdf::PDFEngine::FormType::kNone, FORMTYPE_NONE);
+STATIC_ASSERT_ENUM(chrome_pdf::PDFEngine::FormType::kAcroForm,
+ FORMTYPE_ACRO_FORM);
+STATIC_ASSERT_ENUM(chrome_pdf::PDFEngine::FormType::kXFAFull,
+ FORMTYPE_XFA_FULL);
+STATIC_ASSERT_ENUM(chrome_pdf::PDFEngine::FormType::kXFAForeground,
+ FORMTYPE_XFA_FOREGROUND);
+STATIC_ASSERT_ENUM(chrome_pdf::PDFEngine::FormType::kCount, FORMTYPE_COUNT);
+
+STATIC_ASSERT_ENUM(PP_PRIVATEBUTTON_PUSHBUTTON, FPDF_FORMFIELD_PUSHBUTTON);
+STATIC_ASSERT_ENUM(PP_PRIVATEBUTTON_CHECKBOX, FPDF_FORMFIELD_CHECKBOX);
+STATIC_ASSERT_ENUM(PP_PRIVATEBUTTON_RADIOBUTTON, FPDF_FORMFIELD_RADIOBUTTON);
+
#if defined(OS_WIN)
STATIC_ASSERT_ENUM(chrome_pdf::kEmf, FPDF_PRINTMODE_EMF);
STATIC_ASSERT_ENUM(chrome_pdf::kTextOnly, FPDF_PRINTMODE_TEXTONLY);
diff --git a/chromium/pdf/pdfium/pdfium_engine.cc b/chromium/pdf/pdfium/pdfium_engine.cc
index 090a8edcbdf..66f988b568b 100644
--- a/chromium/pdf/pdfium/pdfium_engine.cc
+++ b/chromium/pdf/pdfium/pdfium_engine.cc
@@ -28,6 +28,7 @@
#include "gin/array_buffer.h"
#include "gin/public/gin_embedders.h"
#include "gin/public/isolate_holder.h"
+#include "gin/public/v8_platform.h"
#include "pdf/document_loader_impl.h"
#include "pdf/draw_utils/coordinates.h"
#include "pdf/draw_utils/shadow.h"
@@ -68,20 +69,6 @@ using printing::kPixelsPerInch;
namespace chrome_pdf {
-static_assert(static_cast<int>(PDFEngine::FormType::kNone) == FORMTYPE_NONE,
- "None form types must match");
-static_assert(static_cast<int>(PDFEngine::FormType::kAcroForm) ==
- FORMTYPE_ACRO_FORM,
- "AcroForm form types must match");
-static_assert(static_cast<int>(PDFEngine::FormType::kXFAFull) ==
- FORMTYPE_XFA_FULL,
- "XFA full form types must match");
-static_assert(static_cast<int>(PDFEngine::FormType::kXFAForeground) ==
- FORMTYPE_XFA_FOREGROUND,
- "XFA foreground form types must match");
-static_assert(static_cast<int>(PDFEngine::FormType::kCount) == FORMTYPE_COUNT,
- "Form type counts must match");
-
namespace {
constexpr int32_t kHighlightColorR = 153;
@@ -234,8 +221,10 @@ bool IsV8Initialized() {
void SetUpV8() {
const char* recommended = FPDF_GetRecommendedV8Flags();
v8::V8::SetFlagsFromString(recommended, strlen(recommended));
- gin::IsolateHolder::Initialize(gin::IsolateHolder::kNonStrictMode,
- gin::ArrayBufferAllocator::SharedInstance());
+ gin::IsolateHolder::Initialize(
+ gin::IsolateHolder::kNonStrictMode,
+ static_cast<v8::ArrayBuffer::Allocator*>(
+ FPDF_GetArrayBufferAllocatorSharedInstance()));
DCHECK(!g_isolate_holder);
g_isolate_holder = new gin::IsolateHolder(
base::ThreadTaskRunnerHandle::Get(), gin::IsolateHolder::kSingleThread,
@@ -365,18 +354,44 @@ void SetLinkUnderCursor(pp::Instance* instance,
pp::PDF::SetLinkUnderCursor(instance, link_under_cursor.c_str());
}
+base::string16 GetAttachmentAttribute(FPDF_ATTACHMENT attachment,
+ FPDF_BYTESTRING field) {
+ return CallPDFiumWideStringBufferApi(
+ base::BindRepeating(&FPDFAttachment_GetStringValue, attachment, field),
+ /*check_expected_size=*/true);
+}
+
+unsigned long GetAttachmentFileLengthInBytes(FPDF_ATTACHMENT attachment) {
+ unsigned long actual_length_bytes;
+ bool is_attachment_readable = FPDFAttachment_GetFile(
+ attachment, /*buffer=*/nullptr, /*buflen=*/0, &actual_length_bytes);
+ DCHECK(is_attachment_readable);
+ return actual_length_bytes;
+}
+
+base::string16 GetAttachmentName(FPDF_ATTACHMENT attachment) {
+ return CallPDFiumWideStringBufferApi(
+ base::BindRepeating(&FPDFAttachment_GetName, attachment),
+ /*check_expected_size=*/true);
+}
+
} // namespace
void InitializeSDK(bool enable_v8) {
FPDF_LIBRARY_CONFIG config;
- config.version = 2;
+ config.version = 3;
config.m_pUserFontPaths = nullptr;
if (enable_v8) {
SetUpV8();
config.m_pIsolate = v8::Isolate::GetCurrent();
+ // NOTE: static_cast<> prior to assigning to (void*) is safer since it
+ // will manipulate the pointer value should gin::V8Platform someday have
+ // multiple base classes.
+ config.m_pPlatform = static_cast<v8::Platform*>(gin::V8Platform::Get());
} else {
config.m_pIsolate = nullptr;
+ config.m_pPlatform = nullptr;
}
config.m_v8EmbedderSlot = gin::kEmbedderPDFium;
FPDF_InitLibraryWithConfig(&config);
@@ -746,6 +761,8 @@ void PDFiumEngine::FinishLoadingDocument() {
if (need_update)
LoadPageInfo();
+ LoadDocumentAttachmentInfoList();
+
LoadDocumentMetadata();
if (called_do_document_action_)
@@ -948,7 +965,7 @@ void PDFiumEngine::KillFormFocus() {
void PDFiumEngine::UpdateFocus(bool has_focus) {
base::AutoReset<bool> updating_focus_guard(&updating_focus_, true);
if (has_focus) {
- focus_item_type_ = last_focused_item_type_;
+ UpdateFocusItemType(last_focused_item_type_);
if (focus_item_type_ == FocusElementType::kPage &&
PageIndexInBounds(last_focused_page_) &&
last_focused_annot_index_ != -1) {
@@ -962,7 +979,7 @@ void PDFiumEngine::UpdateFocus(bool has_focus) {
} else {
last_focused_item_type_ = focus_item_type_;
if (focus_item_type_ == FocusElementType::kDocument) {
- focus_item_type_ = FocusElementType::kNone;
+ UpdateFocusItemType(FocusElementType::kNone);
} else if (focus_item_type_ == FocusElementType::kPage) {
FPDF_ANNOTATION last_focused_annot = nullptr;
FPDF_BOOL ret = FORM_GetFocusedAnnot(form(), &last_focused_page_,
@@ -991,21 +1008,15 @@ bool PDFiumEngine::ReadLoadedBytes(uint32_t length, void* buffer) {
void PDFiumEngine::SetFormSelectedText(FPDF_FORMHANDLE form_handle,
FPDF_PAGE page) {
- unsigned long form_sel_text_len =
- FORM_GetSelectedText(form_handle, page, nullptr, 0);
+ base::string16 selected_form_text16 = CallPDFiumWideStringBufferApi(
+ base::BindRepeating(&FORM_GetSelectedText, form_handle, page),
+ /*check_expected_size=*/false);
// If form selected text is empty and there was no previous form text
- // selection, exit early because nothing has changed. When |form_sel_text_len|
- // is 2, that represents a wide string with just a NUL-terminator.
- if (form_sel_text_len <= 2 && selected_form_text_.empty())
+ // selection, exit early because nothing has changed.
+ if (selected_form_text16.empty() && selected_form_text_.empty())
return;
- base::string16 selected_form_text16;
- PDFiumAPIStringBufferSizeInBytesAdapter<base::string16> string_adapter(
- &selected_form_text16, form_sel_text_len, false);
- string_adapter.Close(FORM_GetSelectedText(
- form_handle, page, string_adapter.GetData(), form_sel_text_len));
-
// Update previous and current selections, then compare them to check if
// selection has changed. If so, set plugin text selection.
std::string selected_form_text = selected_form_text_;
@@ -1098,6 +1109,9 @@ void PDFiumEngine::OnMultipleClick(int click_count,
selection_.push_back(PDFiumRange(pages_[page_index].get(), start_index,
end_index - start_index));
+
+ if (handling_long_press_)
+ client_->NotifyTouchSelectionOccurred();
}
bool PDFiumEngine::OnLeftMouseDown(const pp::MouseInputEvent& event) {
@@ -1123,7 +1137,7 @@ bool PDFiumEngine::OnLeftMouseDown(const pp::MouseInputEvent& event) {
return true;
if (page_index != -1) {
- focus_item_type_ = FocusElementType::kPage;
+ UpdateFocusItemType(FocusElementType::kPage);
last_focused_page_ = page_index;
double page_x;
double page_y;
@@ -1554,6 +1568,17 @@ bool PDFiumEngine::OnKeyDown(const pp::KeyboardInputEvent& event) {
OnChar(synthesized);
}
+#if !defined(OS_MACOSX)
+ // macOS doesn't have keyboard-triggered context menus.
+ // Scroll focused annotation into view when context menu is invoked through
+ // keyboard <Shift-F10>.
+ if (event.GetKeyCode() == FWL_VKEY_F10 &&
+ (event.GetModifiers() & PP_INPUTEVENT_MODIFIER_SHIFTKEY)) {
+ DCHECK(!rv);
+ ScrollFocusedAnnotationIntoView();
+ }
+#endif
+
return rv;
}
@@ -1574,8 +1599,17 @@ bool PDFiumEngine::OnChar(const pp::KeyboardInputEvent& event) {
return false;
base::string16 str = base::UTF8ToUTF16(event.GetCharacterText().AsString());
- return !!FORM_OnChar(form(), pages_[last_focused_page_]->GetPage(), str[0],
- event.GetModifiers());
+ bool rv = !!FORM_OnChar(form(), pages_[last_focused_page_]->GetPage(), str[0],
+ event.GetModifiers());
+
+ // Scroll editable form text into view on char events. We should not scroll
+ // focused annotation on escape char event since escape char is used to
+ // dismiss focus from form controls.
+ if (rv && editable_form_text_area_ && event.GetKeyCode() != ui::VKEY_ESCAPE) {
+ ScrollFocusedAnnotationIntoView();
+ }
+
+ return rv;
}
void PDFiumEngine::StartFind(const std::string& text, bool case_sensitive) {
@@ -1974,6 +2008,14 @@ void PDFiumEngine::SetTwoUpView(bool enable) {
ProposeNextDocumentLayout();
}
+void PDFiumEngine::DisplayAnnotations(bool display) {
+ if (render_annots_ == display)
+ return;
+
+ render_annots_ = display;
+ InvalidateAllPages();
+}
+
void PDFiumEngine::InvalidateAllPages() {
CancelPaints();
StopFind();
@@ -2124,6 +2166,12 @@ void PDFiumEngine::SelectAll() {
}
}
+const std::vector<DocumentAttachmentInfo>&
+PDFiumEngine::GetDocumentAttachmentInfoList() const {
+ DCHECK(document_loaded_);
+ return doc_attachment_info_list_;
+}
+
const DocumentMetadata& PDFiumEngine::GetDocumentMetadata() const {
DCHECK(document_loaded_);
return doc_metadata_;
@@ -2142,14 +2190,9 @@ pp::VarArray PDFiumEngine::GetBookmarks() {
pp::VarDictionary PDFiumEngine::TraverseBookmarks(FPDF_BOOKMARK bookmark,
unsigned int depth) {
pp::VarDictionary dict;
- base::string16 title;
- unsigned long buffer_size = FPDFBookmark_GetTitle(bookmark, nullptr, 0);
- if (buffer_size > 0) {
- PDFiumAPIStringBufferSizeInBytesAdapter<base::string16> api_string_adapter(
- &title, buffer_size, true);
- api_string_adapter.Close(FPDFBookmark_GetTitle(
- bookmark, api_string_adapter.GetData(), buffer_size));
- }
+ base::string16 title = CallPDFiumWideStringBufferApi(
+ base::BindRepeating(&FPDFBookmark_GetTitle, bookmark),
+ /*check_expected_size=*/true);
dict.Set(pp::Var("title"), pp::Var(base::UTF16ToUTF8(title)));
FPDF_DEST dest = FPDFBookmark_GetDest(doc(), bookmark);
@@ -2173,15 +2216,11 @@ pp::VarDictionary PDFiumEngine::TraverseBookmarks(FPDF_BOOKMARK bookmark,
} else {
// Extract URI for bookmarks linking to an external page.
FPDF_ACTION action = FPDFBookmark_GetAction(bookmark);
- buffer_size = FPDFAction_GetURIPath(doc(), action, nullptr, 0);
- if (buffer_size > 0) {
- std::string uri;
- PDFiumAPIStringBufferAdapter<std::string> api_string_adapter(
- &uri, buffer_size, true);
- api_string_adapter.Close(FPDFAction_GetURIPath(
- doc(), action, api_string_adapter.GetData(), buffer_size));
+ std::string uri = CallPDFiumStringBufferApi(
+ base::BindRepeating(&FPDFAction_GetURIPath, doc(), action),
+ /*check_expected_size=*/true);
+ if (!uri.empty())
dict.Set(pp::Var("uri"), pp::Var(uri));
- }
}
pp::VarArray children;
@@ -2328,6 +2367,7 @@ void PDFiumEngine::SetGrayscale(bool grayscale) {
}
void PDFiumEngine::HandleLongPress(const pp::TouchInputEvent& event) {
+ base::AutoReset<bool> handling_long_press_guard(&handling_long_press_, true);
pp::FloatPoint fp =
event.GetTouchByIndex(PP_TOUCHLIST_TYPE_TARGETTOUCHES, 0).position();
pp::Point point;
@@ -2719,7 +2759,8 @@ void PDFiumEngine::LoadForm() {
kFormHighlightColor);
FPDF_SetFormFieldHighlightAlpha(form(), kFormHighlightAlpha);
- if (base::FeatureList::IsEnabled(features::kTabAcrossPDFAnnotations)) {
+ if (base::FeatureList::IsEnabled(features::kTabAcrossPDFAnnotations) &&
+ !client_->IsPrintPreview()) {
static constexpr FPDF_ANNOTATION_SUBTYPE kFocusableAnnotSubtypes[] = {
FPDF_ANNOT_LINK, FPDF_ANNOT_HIGHLIGHT, FPDF_ANNOT_WIDGET};
FPDF_BOOL ret = FPDFAnnot_SetFocusableSubtypes(
@@ -3558,12 +3599,12 @@ void PDFiumEngine::SetSelecting(bool selecting) {
client_->IsSelectingChanged(selecting);
}
-void PDFiumEngine::SetEditMode(bool edit_mode) {
- if (edit_mode_ == edit_mode)
+void PDFiumEngine::EnteredEditMode() {
+ if (edit_mode_)
return;
- edit_mode_ = edit_mode;
- client_->IsEditModeChanged(edit_mode_);
+ edit_mode_ = true;
+ client_->EnteredEditMode();
}
void PDFiumEngine::SetInFormTextArea(bool in_form_text_area) {
@@ -3671,7 +3712,30 @@ void PDFiumEngine::SetSelection(
}
}
-void PDFiumEngine::ScrollIntoView(const pp::Rect& rect) {
+void PDFiumEngine::ScrollFocusedAnnotationIntoView() {
+ FPDF_ANNOTATION annot;
+ int page_index;
+ if (!FORM_GetFocusedAnnot(form(), &page_index, &annot))
+ return;
+
+ ScrollAnnotationIntoView(annot, page_index);
+ FPDFPage_CloseAnnot(annot);
+}
+
+void PDFiumEngine::ScrollAnnotationIntoView(FPDF_ANNOTATION annot,
+ int page_index) {
+ if (!PageIndexInBounds(page_index))
+ return;
+
+ FS_RECTF annot_rect;
+ if (!FPDFAnnot_GetRect(annot, &annot_rect))
+ return;
+
+ pp::Rect rect = pages_[page_index]->PageToScreen(
+ pp::Point(), /*zoom=*/1.0, annot_rect.left, annot_rect.top,
+ annot_rect.right, annot_rect.bottom,
+ layout_.options().default_page_orientation());
+
pp::Rect visible_rect = GetVisibleRect();
if (visible_rect.Contains(rect))
return;
@@ -3778,6 +3842,28 @@ void PDFiumEngine::GetSelection(uint32_t* selection_start_page_index,
}
}
+void PDFiumEngine::LoadDocumentAttachmentInfoList() {
+ DCHECK(document_loaded_);
+
+ int attachment_count = FPDFDoc_GetAttachmentCount(doc());
+ if (attachment_count <= 0)
+ return;
+
+ doc_attachment_info_list_.resize(attachment_count);
+ for (int i = 0; i < attachment_count; ++i) {
+ FPDF_ATTACHMENT attachment = FPDFDoc_GetAttachment(doc(), i);
+ DCHECK(attachment);
+
+ doc_attachment_info_list_[i].name = GetAttachmentName(attachment);
+ doc_attachment_info_list_[i].size_bytes =
+ GetAttachmentFileLengthInBytes(attachment);
+ doc_attachment_info_list_[i].creation_date =
+ GetAttachmentAttribute(attachment, "CreationDate");
+ doc_attachment_info_list_[i].modified_date =
+ GetAttachmentAttribute(attachment, "ModDate");
+ }
+}
+
void PDFiumEngine::LoadDocumentMetadata() {
DCHECK(document_loaded_);
@@ -3793,17 +3879,9 @@ void PDFiumEngine::LoadDocumentMetadata() {
std::string PDFiumEngine::GetMetadataByField(FPDF_BYTESTRING field) const {
DCHECK(doc());
- size_t size =
- FPDF_GetMetaText(doc(), field, /*buffer=*/nullptr, /*buflen=*/0);
- if (size == 0)
- return std::string();
-
- base::string16 value;
- PDFiumAPIStringBufferSizeInBytesAdapter<base::string16> string_adapter(
- &value, size, /*check_expected_size=*/false);
- string_adapter.Close(
- FPDF_GetMetaText(doc(), field, string_adapter.GetData(), size));
- return base::UTF16ToUTF8(value);
+ return base::UTF16ToUTF8(CallPDFiumWideStringBufferApi(
+ base::BindRepeating(&FPDF_GetMetaText, doc(), field),
+ /*check_expected_size=*/false));
}
PdfVersion PDFiumEngine::GetDocumentVersion() const {
@@ -3869,7 +3947,7 @@ bool PDFiumEngine::HandleTabEventWithModifiers(uint32_t modifiers) {
bool PDFiumEngine::HandleTabForward(uint32_t modifiers) {
if (focus_item_type_ == FocusElementType::kNone) {
- focus_item_type_ = FocusElementType::kDocument;
+ UpdateFocusItemType(FocusElementType::kDocument);
return true;
}
@@ -3887,17 +3965,17 @@ bool PDFiumEngine::HandleTabForward(uint32_t modifiers) {
if (did_tab_forward) {
last_focused_page_ = page_index;
- focus_item_type_ = FocusElementType::kPage;
+ UpdateFocusItemType(FocusElementType::kPage);
} else {
last_focused_page_ = -1;
- focus_item_type_ = FocusElementType::kNone;
+ UpdateFocusItemType(FocusElementType::kNone);
}
return did_tab_forward;
}
bool PDFiumEngine::HandleTabBackward(uint32_t modifiers) {
if (focus_item_type_ == FocusElementType::kDocument) {
- focus_item_type_ = FocusElementType::kNone;
+ UpdateFocusItemType(FocusElementType::kNone);
return false;
}
@@ -3915,7 +3993,7 @@ bool PDFiumEngine::HandleTabBackward(uint32_t modifiers) {
if (did_tab_backward) {
last_focused_page_ = page_index;
- focus_item_type_ = FocusElementType::kPage;
+ UpdateFocusItemType(FocusElementType::kPage);
} else {
// No focusable annotation found in pages. Possible scenarios:
// Case 1: |focus_item_type_| is None. Since no object in any page can take
@@ -3928,11 +4006,11 @@ bool PDFiumEngine::HandleTabBackward(uint32_t modifiers) {
case FocusElementType::kNone:
did_tab_backward = true;
last_focused_page_ = -1;
- focus_item_type_ = FocusElementType::kDocument;
+ UpdateFocusItemType(FocusElementType::kDocument);
KillFormFocus();
break;
case FocusElementType::kDocument:
- focus_item_type_ = FocusElementType::kNone;
+ UpdateFocusItemType(FocusElementType::kNone);
break;
default:
NOTREACHED();
@@ -3942,6 +4020,16 @@ bool PDFiumEngine::HandleTabBackward(uint32_t modifiers) {
return did_tab_backward;
}
+void PDFiumEngine::UpdateFocusItemType(FocusElementType focus_item_type) {
+ if (focus_item_type_ == focus_item_type)
+ return;
+ if (focus_item_type_ == FocusElementType::kDocument)
+ client_->DocumentFocusChanged(false);
+ focus_item_type_ = focus_item_type;
+ if (focus_item_type_ == FocusElementType::kDocument)
+ client_->DocumentFocusChanged(true);
+}
+
#if defined(PDF_ENABLE_XFA)
void PDFiumEngine::UpdatePageCount() {
InvalidateAllPages();
diff --git a/chromium/pdf/pdfium/pdfium_engine.h b/chromium/pdf/pdfium/pdfium_engine.h
index cf507e8d469..2261904a961 100644
--- a/chromium/pdf/pdfium/pdfium_engine.h
+++ b/chromium/pdf/pdfium/pdfium_engine.h
@@ -17,6 +17,7 @@
#include "base/optional.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
+#include "pdf/document_attachment_info.h"
#include "pdf/document_layout.h"
#include "pdf/document_loader.h"
#include "pdf/document_metadata.h"
@@ -99,6 +100,7 @@ class PDFiumEngine : public PDFEngine,
void RotateClockwise() override;
void RotateCounterclockwise() override;
void SetTwoUpView(bool enable) override;
+ void DisplayAnnotations(bool display) override;
pp::Size ApplyDocumentLayout(const DocumentLayout::Options& options) override;
std::string GetSelectedText() override;
bool CanEditText() override;
@@ -113,6 +115,8 @@ class PDFiumEngine : public PDFEngine,
std::string GetLinkAtPosition(const pp::Point& point) override;
bool HasPermission(DocumentPermission permission) const override;
void SelectAll() override;
+ const std::vector<DocumentAttachmentInfo>& GetDocumentAttachmentInfoList()
+ const override;
const DocumentMetadata& GetDocumentMetadata() const override;
int GetNumberOfPages() override;
pp::VarArray GetBookmarks() override;
@@ -564,7 +568,7 @@ class PDFiumEngine : public PDFEngine,
const pp::Point& global_point);
// Set if the document has any local edits.
- void SetEditMode(bool edit_mode);
+ void EnteredEditMode();
// Navigates to a link destination depending on the type of destination.
// Returns false if |area| is not a link.
@@ -580,12 +584,18 @@ class PDFiumEngine : public PDFEngine,
void SetSelection(const PP_PdfPageCharacterIndex& selection_start_index,
const PP_PdfPageCharacterIndex& selection_end_index);
- // Given |rect| in document coordinates, scroll the |rect| into view if not
- // already in view.
- void ScrollIntoView(const pp::Rect& rect);
+ // Scroll the current focused annotation into view if not already in view.
+ void ScrollFocusedAnnotationIntoView();
+
+ // Given |annot|, scroll the |annot| into view if not already in view.
+ void ScrollAnnotationIntoView(FPDF_ANNOTATION annot, int page_index);
void OnFocusedAnnotationUpdated(FPDF_ANNOTATION annot, int page_index);
+ // Read the attachments' information inside the PDF document, and set
+ // |doc_attachment_info_list_|. To be called after the document is loaded.
+ void LoadDocumentAttachmentInfoList();
+
// Fetches and populates the fields of |doc_metadata_|. To be called after the
// document is loaded.
void LoadDocumentMetadata();
@@ -606,6 +616,10 @@ class PDFiumEngine : public PDFEngine,
bool HandleTabForward(uint32_t modifiers);
bool HandleTabBackward(uint32_t modifiers);
+ // Updates the currently focused object stored in |focus_item_type_|. Notifies
+ // |client_| about document focus change, if any.
+ void UpdateFocusItemType(FocusElementType focus_item_type);
+
void UpdateLinkUnderCursor(const std::string& target_url);
void SetLinkUnderCursorForAnnotation(FPDF_ANNOTATION annot, int page_index);
@@ -710,6 +724,9 @@ class PDFiumEngine : public PDFEngine,
// Timer for touch long press detection.
base::OneShotTimer touch_timer_;
+ // Set to true when handling long touch press.
+ bool handling_long_press_ = false;
+
// Set to true when updating plugin focus.
bool updating_focus_ = false;
@@ -792,6 +809,9 @@ class PDFiumEngine : public PDFEngine,
// Shadow matrix for generating the page shadow bitmap.
std::unique_ptr<draw_utils::ShadowMatrix> page_shadow_;
+ // A list of information of document attachments.
+ std::vector<DocumentAttachmentInfo> doc_attachment_info_list_;
+
// Stores parsed document metadata.
DocumentMetadata doc_metadata_;
diff --git a/chromium/pdf/pdfium/pdfium_engine_unittest.cc b/chromium/pdf/pdfium/pdfium_engine_unittest.cc
index 4aa29dd8451..978be627972 100644
--- a/chromium/pdf/pdfium/pdfium_engine_unittest.cc
+++ b/chromium/pdf/pdfium/pdfium_engine_unittest.cc
@@ -4,8 +4,10 @@
#include "pdf/pdfium/pdfium_engine.h"
+#include "base/strings/utf_string_conversions.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
+#include "pdf/document_attachment_info.h"
#include "pdf/document_layout.h"
#include "pdf/document_metadata.h"
#include "pdf/pdf_features.h"
@@ -185,6 +187,53 @@ TEST_F(PDFiumEngineTest, ApplyDocumentLayoutAvoidsInfiniteLoop) {
CompareSize({343, 1463}, engine->ApplyDocumentLayout(options));
}
+TEST_F(PDFiumEngineTest, GetDocumentAttachmentInfo) {
+ NiceMock<MockTestClient> client;
+ std::unique_ptr<PDFiumEngine> engine =
+ InitializeEngine(&client, FILE_PATH_LITERAL("embedded_attachments.pdf"));
+ ASSERT_TRUE(engine);
+
+ const std::vector<DocumentAttachmentInfo>& attachments =
+ engine->GetDocumentAttachmentInfoList();
+ ASSERT_EQ(3u, attachments.size());
+
+ {
+ const DocumentAttachmentInfo& attachment = attachments[0];
+ EXPECT_EQ("1.txt", base::UTF16ToUTF8(attachment.name));
+ EXPECT_EQ(4u, attachment.size_bytes);
+ EXPECT_EQ("D:20170712214438-07'00'",
+ base::UTF16ToUTF8(attachment.creation_date));
+ EXPECT_EQ("D:20160115091400", base::UTF16ToUTF8(attachment.modified_date));
+ }
+
+ {
+ const DocumentAttachmentInfo& attachment = attachments[1];
+ EXPECT_EQ("attached.pdf", base::UTF16ToUTF8(attachment.name));
+ EXPECT_EQ(5869u, attachment.size_bytes);
+ EXPECT_EQ("D:20170712214443-07'00'",
+ base::UTF16ToUTF8(attachment.creation_date));
+ EXPECT_EQ("D:20170712214410", base::UTF16ToUTF8(attachment.modified_date));
+ }
+
+ {
+ // Test attachments with no creation date or last modified date.
+ const DocumentAttachmentInfo& attachment = attachments[2];
+ EXPECT_EQ("附錄.txt", base::UTF16ToUTF8(attachment.name));
+ EXPECT_EQ(5u, attachment.size_bytes);
+ EXPECT_THAT(attachment.creation_date, IsEmpty());
+ EXPECT_THAT(attachment.modified_date, IsEmpty());
+ }
+}
+
+TEST_F(PDFiumEngineTest, NoDocumentAttachmentInfo) {
+ NiceMock<MockTestClient> client;
+ std::unique_ptr<PDFiumEngine> engine =
+ InitializeEngine(&client, FILE_PATH_LITERAL("hello_world2.pdf"));
+ ASSERT_TRUE(engine);
+
+ EXPECT_EQ(0u, engine->GetDocumentAttachmentInfoList().size());
+}
+
TEST_F(PDFiumEngineTest, GetDocumentMetadata) {
NiceMock<MockTestClient> client;
std::unique_ptr<PDFiumEngine> engine =
@@ -229,6 +278,17 @@ TEST_F(PDFiumEngineTest, GetBadPdfVersion) {
} // namespace
+class TabbingTestClient : public TestClient {
+ public:
+ TabbingTestClient() = default;
+ ~TabbingTestClient() override = default;
+ TabbingTestClient(const TabbingTestClient&) = delete;
+ TabbingTestClient& operator=(const TabbingTestClient&) = delete;
+
+ // Mock PDFEngine::Client methods.
+ MOCK_METHOD1(DocumentFocusChanged, void(bool));
+};
+
class PDFiumEngineTabbingTest : public PDFiumTestBase {
public:
PDFiumEngineTabbingTest() = default;
@@ -269,6 +329,10 @@ class PDFiumEngineTabbingTest : public PDFiumTestBase {
return engine->link_under_cursor_;
}
+ void ScrollFocusedAnnotationIntoView(PDFiumEngine* engine) {
+ engine->ScrollFocusedAnnotationIntoView();
+ }
+
protected:
base::test::TaskEnvironment task_environment_{
base::test::TaskEnvironment::TimeSource::MOCK_TIME};
@@ -378,13 +442,20 @@ TEST_F(PDFiumEngineTabbingTest, TabbingForwardTest) {
* ++ Page 2
* ++++ Annotation
*/
- TestClient client;
+ TabbingTestClient client;
std::unique_ptr<PDFiumEngine> engine = InitializeEngine(
&client, FILE_PATH_LITERAL("annotation_form_fields.pdf"));
ASSERT_TRUE(engine);
ASSERT_EQ(2, engine->GetNumberOfPages());
+ static constexpr bool kExpectedFocusState[] = {true, false};
+ {
+ InSequence sequence;
+ for (auto focused : kExpectedFocusState)
+ EXPECT_CALL(client, DocumentFocusChanged(focused));
+ }
+
ASSERT_EQ(PDFiumEngine::FocusElementType::kNone,
GetFocusedElementType(engine.get()));
EXPECT_EQ(-1, GetLastFocusedPage(engine.get()));
@@ -423,13 +494,20 @@ TEST_F(PDFiumEngineTabbingTest, TabbingBackwardTest) {
* ++ Page 2
* ++++ Annotation
*/
- TestClient client;
+ TabbingTestClient client;
std::unique_ptr<PDFiumEngine> engine = InitializeEngine(
&client, FILE_PATH_LITERAL("annotation_form_fields.pdf"));
ASSERT_TRUE(engine);
ASSERT_EQ(2, engine->GetNumberOfPages());
+ static constexpr bool kExpectedFocusState[] = {true, false};
+ {
+ InSequence sequence;
+ for (auto focused : kExpectedFocusState)
+ EXPECT_CALL(client, DocumentFocusChanged(focused));
+ }
+
ASSERT_EQ(PDFiumEngine::FocusElementType::kNone,
GetFocusedElementType(engine.get()));
EXPECT_EQ(-1, GetLastFocusedPage(engine.get()));
@@ -512,13 +590,20 @@ TEST_F(PDFiumEngineTabbingTest, NoFocusableItemTabbingTest) {
* ++ Page 1
* ++ Page 2
*/
- TestClient client;
+ TabbingTestClient client;
std::unique_ptr<PDFiumEngine> engine =
InitializeEngine(&client, FILE_PATH_LITERAL("hello_world2.pdf"));
ASSERT_TRUE(engine);
ASSERT_EQ(2, engine->GetNumberOfPages());
+ static constexpr bool kExpectedFocusState[] = {true, false, true, false};
+ {
+ InSequence sequence;
+ for (auto focused : kExpectedFocusState)
+ EXPECT_CALL(client, DocumentFocusChanged(focused));
+ }
+
ASSERT_EQ(PDFiumEngine::FocusElementType::kNone,
GetFocusedElementType(engine.get()));
EXPECT_EQ(-1, GetLastFocusedPage(engine.get()));
@@ -552,13 +637,20 @@ TEST_F(PDFiumEngineTabbingTest, RestoringDocumentFocusTest) {
* ++ Page 2
* ++++ Annotation
*/
- TestClient client;
+ TabbingTestClient client;
std::unique_ptr<PDFiumEngine> engine = InitializeEngine(
&client, FILE_PATH_LITERAL("annotation_form_fields.pdf"));
ASSERT_TRUE(engine);
ASSERT_EQ(2, engine->GetNumberOfPages());
+ static constexpr bool kExpectedFocusState[] = {true, false, true};
+ {
+ InSequence sequence;
+ for (auto focused : kExpectedFocusState)
+ EXPECT_CALL(client, DocumentFocusChanged(focused));
+ }
+
EXPECT_EQ(PDFiumEngine::FocusElementType::kNone,
GetFocusedElementType(engine.get()));
EXPECT_EQ(-1, GetLastFocusedPage(engine.get()));
@@ -590,13 +682,20 @@ TEST_F(PDFiumEngineTabbingTest, RestoringAnnotFocusTest) {
* ++ Page 2
* ++++ Annotation
*/
- TestClient client;
+ TabbingTestClient client;
std::unique_ptr<PDFiumEngine> engine = InitializeEngine(
&client, FILE_PATH_LITERAL("annotation_form_fields.pdf"));
ASSERT_TRUE(engine);
ASSERT_EQ(2, engine->GetNumberOfPages());
+ static constexpr bool kExpectedFocusState[] = {true, false};
+ {
+ InSequence sequence;
+ for (auto focused : kExpectedFocusState)
+ EXPECT_CALL(client, DocumentFocusChanged(focused));
+ }
+
EXPECT_EQ(PDFiumEngine::FocusElementType::kNone,
GetFocusedElementType(engine.get()));
EXPECT_EQ(-1, GetLastFocusedPage(engine.get()));
@@ -773,4 +872,51 @@ TEST_F(PDFiumEngineTabbingTest, MaintainViewportWhenFocusIsUpdated) {
EXPECT_EQ(0, GetLastFocusedPage(engine.get()));
}
+TEST_F(PDFiumEngineTabbingTest, ScrollFocusedAnnotationIntoView) {
+ StrictMock<ScrollingTestClient> client;
+ std::unique_ptr<PDFiumEngine> engine = InitializeEngine(
+ &client, FILE_PATH_LITERAL("annotation_form_fields.pdf"));
+ ASSERT_TRUE(engine);
+ ASSERT_EQ(2, engine->GetNumberOfPages());
+ engine->PluginSizeUpdated(pp::Size(60, 40));
+
+ {
+ InSequence sequence;
+ static constexpr PP_Point kScrollValues[] = {{510, 478}, {510, 478}};
+
+ for (const auto& scroll_value : kScrollValues) {
+ EXPECT_CALL(client, ScrollToY(scroll_value.y, false))
+ .WillOnce(Invoke([&engine, &scroll_value]() {
+ engine->ScrolledToYPosition(scroll_value.y);
+ }));
+ EXPECT_CALL(client, ScrollToX(scroll_value.x))
+ .WillOnce(Invoke([&engine, &scroll_value]() {
+ engine->ScrolledToXPosition(scroll_value.x);
+ }));
+ }
+ }
+
+ EXPECT_EQ(PDFiumEngine::FocusElementType::kNone,
+ GetFocusedElementType(engine.get()));
+ EXPECT_EQ(-1, GetLastFocusedPage(engine.get()));
+
+ // Tabbing to bring the document into focus.
+ ASSERT_TRUE(HandleTabEvent(engine.get(), 0));
+ EXPECT_EQ(PDFiumEngine::FocusElementType::kDocument,
+ GetFocusedElementType(engine.get()));
+
+ // Tab to an annotation.
+ ASSERT_TRUE(HandleTabEvent(engine.get(), 0));
+ EXPECT_EQ(PDFiumEngine::FocusElementType::kPage,
+ GetFocusedElementType(engine.get()));
+
+ // Scroll focused annotation out of viewport.
+ static constexpr PP_Point kScrollPosition = {242, 746};
+ engine->ScrolledToXPosition(kScrollPosition.x);
+ engine->ScrolledToYPosition(kScrollPosition.y);
+
+ // Scroll the focused annotation into view.
+ ScrollFocusedAnnotationIntoView(engine.get());
+}
+
} // namespace chrome_pdf
diff --git a/chromium/pdf/pdfium/pdfium_form_filler.cc b/chromium/pdf/pdfium/pdfium_form_filler.cc
index 4a142b4cba5..d85bd2ceef1 100644
--- a/chromium/pdf/pdfium/pdfium_form_filler.cc
+++ b/chromium/pdf/pdfium/pdfium_form_filler.cc
@@ -194,7 +194,7 @@ FPDF_SYSTEMTIME PDFiumFormFiller::Form_GetLocalTime(FPDF_FORMFILLINFO* param) {
// static
void PDFiumFormFiller::Form_OnChange(FPDF_FORMFILLINFO* param) {
PDFiumEngine* engine = GetEngine(param);
- engine->SetEditMode(true);
+ engine->EnteredEditMode();
}
// static
@@ -285,17 +285,8 @@ void PDFiumFormFiller::Form_OnFocusChange(FPDF_FORMFILLINFO* param,
// Maintain viewport if we are updating focus. This is to ensure that we don't
// scroll the focused annotation into view when focus is regained.
- if (!engine->updating_focus_) {
- FS_RECTF annot_rect;
- if (!FPDFAnnot_GetRect(annot, &annot_rect))
- return;
-
- pp::Rect screen_rect = engine->pages_[page_index]->PageToScreen(
- pp::Point(), /*zoom=*/1.0, annot_rect.left, annot_rect.top,
- annot_rect.right, annot_rect.bottom,
- engine->layout_.options().default_page_orientation());
- engine->ScrollIntoView(screen_rect);
- }
+ if (!engine->updating_focus_)
+ engine->ScrollAnnotationIntoView(annot, page_index);
engine->OnFocusedAnnotationUpdated(annot, page_index);
}
diff --git a/chromium/pdf/pdfium/pdfium_page.cc b/chromium/pdf/pdfium/pdfium_page.cc
index 4f5f5af65b8..6f95affddc8 100644
--- a/chromium/pdf/pdfium/pdfium_page.cc
+++ b/chromium/pdf/pdfium/pdfium_page.cc
@@ -186,24 +186,6 @@ bool FloatEquals(float f1, float f2) {
kEpsilonScale * fmaxf(fmaxf(fabsf(f1), fabsf(f2)), kEpsilonScale);
}
-using GetFormFieldPropertyFunction =
- base::RepeatingCallback<unsigned long(unsigned short* buffer,
- unsigned long buflen)>;
-
-// Helper method to fetch string properties of form fields.
-std::string GetFormFieldProperty(GetFormFieldPropertyFunction function) {
- base::string16 data;
- size_t buffer_size = function.Run(nullptr, 0);
- if (buffer_size > 0) {
- PDFiumAPIStringBufferSizeInBytesAdapter<base::string16> api_string_adapter(
- &data, buffer_size, true);
- api_string_adapter.Close(function.Run(
- reinterpret_cast<unsigned short*>(api_string_adapter.GetData()),
- buffer_size));
- }
- return base::UTF16ToUTF8(data);
-}
-
// Count overlaps across text annotations.
template <typename T, typename U>
uint32_t CountOverlaps(const std::vector<T>& first_set,
@@ -472,6 +454,18 @@ PDFiumPage::GetTextRunInfo(int start_char_index) {
info.direction = PP_PRIVATEDIRECTION_NONE;
return info;
}
+
+ // If the first character in a text run is a space, we need to start
+ // |text_run_bounds| from the space character instead of the first
+ // non-space unicode character.
+ pp::FloatRect text_run_bounds =
+ actual_start_char_index > start_char_index
+ ? GetFloatCharRectInPixels(page, text_page, start_char_index)
+ : pp::FloatRect();
+
+ // Pdfium trims more than 1 consecutive spaces to 1 space.
+ DCHECK_LE(actual_start_char_index - start_char_index, 1);
+
int char_index = actual_start_char_index;
// Set text run's style info from the first character of the text run.
@@ -494,8 +488,8 @@ PDFiumPage::GetTextRunInfo(int start_char_index) {
AddCharSizeToAverageCharSize(start_char_rect.Floatsize(), &avg_char_size,
&non_whitespace_chars_count);
- // Add first char to text run.
- pp::FloatRect text_run_bounds = start_char_rect;
+ // Add first non-space char to text run.
+ text_run_bounds = text_run_bounds.Union(start_char_rect);
PP_PrivateDirection char_direction =
GetDirectionFromAngle(FPDFText_GetCharAngle(text_page, char_index));
if (char_index < chars_count)
@@ -676,6 +670,7 @@ PDFiumPage::GetHighlightInfo() {
highlight.bounding_rect.x(), highlight.bounding_rect.y(),
highlight.bounding_rect.width(), highlight.bounding_rect.height());
cur_info.color = highlight.color;
+ cur_info.note_text = highlight.note_text;
highlight_info.push_back(std::move(cur_info));
}
return highlight_info;
@@ -900,16 +895,11 @@ gfx::PointF PDFiumPage::TransformPageToScreenXY(const gfx::PointF& xy) {
PDFiumPage::Area PDFiumPage::GetURITarget(FPDF_ACTION uri_action,
LinkTarget* target) const {
if (target) {
- size_t buffer_size =
- FPDFAction_GetURIPath(engine_->doc(), uri_action, nullptr, 0);
- if (buffer_size > 0) {
- PDFiumAPIStringBufferAdapter<std::string> api_string_adapter(
- &target->url, buffer_size, true);
- void* data = api_string_adapter.GetData();
- size_t bytes_written =
- FPDFAction_GetURIPath(engine_->doc(), uri_action, data, buffer_size);
- api_string_adapter.Close(bytes_written);
- }
+ std::string url = CallPDFiumStringBufferApi(
+ base::BindRepeating(&FPDFAction_GetURIPath, engine_->doc(), uri_action),
+ /*check_expected_size=*/true);
+ if (!url.empty())
+ target->url = url;
}
return WEBLINK_AREA;
}
@@ -956,6 +946,8 @@ void PDFiumPage::PopulateWebLinks() {
ScopedFPDFPageLink links(FPDFLink_LoadWebLinks(GetTextPage()));
int count = FPDFLink_CountWebLinks(links.get());
for (int i = 0; i < count; ++i) {
+ // WARNING: FPDFLink_GetURL() is not compatible with
+ // CallPDFiumWideStringBufferApi().
base::string16 url;
int url_length = FPDFLink_GetURL(links.get(), i, nullptr, 0);
if (url_length > 0) {
@@ -1141,16 +1133,11 @@ void PDFiumPage::PopulateImageAltTextForStructElement(
auto it = marked_content_id_image_map.find(marked_content_id);
if (it != marked_content_id_image_map.end() &&
images_[it->second].alt_text.empty()) {
- size_t buffer_size =
- FPDF_StructElement_GetAltText(current_element, nullptr, 0);
- if (buffer_size > 0) {
- base::string16 alt_text;
- PDFiumAPIStringBufferSizeInBytesAdapter<base::string16>
- api_string_adapter(&alt_text, buffer_size, true);
- api_string_adapter.Close(FPDF_StructElement_GetAltText(
- current_element, api_string_adapter.GetData(), buffer_size));
- images_[it->second].alt_text = base::UTF16ToUTF8(alt_text);
- }
+ images_[it->second].alt_text =
+ base::UTF16ToUTF8(CallPDFiumWideStringBufferApi(
+ base::BindRepeating(&FPDF_StructElement_GetAltText,
+ current_element),
+ /*check_expected_size=*/true));
}
}
int children_count = FPDF_StructElement_CountChildren(current_element);
@@ -1182,11 +1169,7 @@ void PDFiumPage::PopulateAnnotations() {
break;
}
case FPDF_ANNOT_WIDGET: {
- // TODO(crbug.com/1030242): Populate other types of form fields too.
- if (FPDFAnnot_GetFormFieldType(engine_->form(), annot.get()) ==
- FPDF_FORMFIELD_TEXTFIELD) {
- PopulateTextField(annot.get());
- }
+ PopulateFormField(annot.get());
break;
}
default:
@@ -1230,6 +1213,14 @@ void PDFiumPage::PopulateHighlight(FPDF_ANNOTATION annot) {
highlight.color = MakeARGB(255, 255, 255, 0);
}
+ // Retrieve the contents of the popup note associated with highlight.
+ // See table 164 in ISO 32000-1 standard for more details around "Contents"
+ // key in a highlight annotation.
+ static constexpr char kContents[] = "Contents";
+ highlight.note_text = base::UTF16ToUTF8(CallPDFiumWideStringBufferApi(
+ base::BindRepeating(&FPDFAnnot_GetStringValue, annot, kContents),
+ /*check_expected_size=*/true));
+
highlights_.push_back(std::move(highlight));
}
@@ -1239,21 +1230,81 @@ void PDFiumPage::PopulateTextField(FPDF_ANNOTATION annot) {
DCHECK_EQ(FPDFAnnot_GetFormFieldType(form_handle, annot),
FPDF_FORMFIELD_TEXTFIELD);
+ TextField text_field;
+ if (!PopulateFormFieldProperties(annot, &text_field))
+ return;
+
+ text_field.value = base::UTF16ToUTF8(CallPDFiumWideStringBufferApi(
+ base::BindRepeating(&FPDFAnnot_GetFormFieldValue, form_handle, annot),
+ /*check_expected_size=*/true));
+ text_fields_.push_back(std::move(text_field));
+}
+
+void PDFiumPage::PopulateChoiceField(FPDF_ANNOTATION annot) {
+ DCHECK(annot);
+ FPDF_FORMHANDLE form_handle = engine_->form();
+ int form_field_type = FPDFAnnot_GetFormFieldType(form_handle, annot);
+ DCHECK(form_field_type == FPDF_FORMFIELD_LISTBOX ||
+ form_field_type == FPDF_FORMFIELD_COMBOBOX);
+
+ ChoiceField choice_field;
+ if (!PopulateFormFieldProperties(annot, &choice_field))
+ return;
+
+ int options_count = FPDFAnnot_GetOptionCount(form_handle, annot);
+ if (options_count < 0)
+ return;
+
+ choice_field.options.resize(options_count);
+ for (int i = 0; i < options_count; ++i) {
+ choice_field.options[i].name =
+ base::UTF16ToUTF8(CallPDFiumWideStringBufferApi(
+ base::BindRepeating(&FPDFAnnot_GetOptionLabel, form_handle, annot,
+ i),
+ /*check_expected_size=*/true));
+ choice_field.options[i].is_selected =
+ FPDFAnnot_IsOptionSelected(form_handle, annot, i);
+ }
+ choice_fields_.push_back(std::move(choice_field));
+}
+
+void PDFiumPage::PopulateFormField(FPDF_ANNOTATION annot) {
+ DCHECK_EQ(FPDFAnnot_GetSubtype(annot), FPDF_ANNOT_WIDGET);
+ int form_field_type = FPDFAnnot_GetFormFieldType(engine_->form(), annot);
+
+ // TODO(crbug.com/1030242): Populate other types of form fields too.
+ switch (form_field_type) {
+ case FPDF_FORMFIELD_COMBOBOX:
+ case FPDF_FORMFIELD_LISTBOX: {
+ PopulateChoiceField(annot);
+ break;
+ }
+ case FPDF_FORMFIELD_TEXTFIELD: {
+ PopulateTextField(annot);
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+bool PDFiumPage::PopulateFormFieldProperties(FPDF_ANNOTATION annot,
+ FormField* form_field) {
+ DCHECK(annot);
FS_RECTF rect;
if (!FPDFAnnot_GetRect(annot, &rect))
- return;
+ return false;
- TextField text_field;
- // We use the bounding box of the text field as the bounding rect.
- text_field.bounding_rect =
+ // We use the bounding box of the form field as the bounding rect.
+ form_field->bounding_rect =
PageToScreen(pp::Point(), 1.0, rect.left, rect.top, rect.right,
rect.bottom, PageOrientation::kOriginal);
- text_field.value = GetFormFieldProperty(
- base::BindRepeating(FPDFAnnot_GetFormFieldValue, form_handle, annot));
- text_field.name = GetFormFieldProperty(
- base::BindRepeating(FPDFAnnot_GetFormFieldName, form_handle, annot));
- text_field.flags = FPDFAnnot_GetFormFieldFlags(form_handle, annot);
- text_fields_.push_back(std::move(text_field));
+ FPDF_FORMHANDLE form_handle = engine_->form();
+ form_field->name = base::UTF16ToUTF8(CallPDFiumWideStringBufferApi(
+ base::BindRepeating(&FPDFAnnot_GetFormFieldName, form_handle, annot),
+ /*check_expected_size=*/true));
+ form_field->flags = FPDFAnnot_GetFormFieldFlags(form_handle, annot);
+ return true;
}
bool PDFiumPage::GetUnderlyingTextRangeForRect(const pp::FloatRect& rect,
@@ -1385,12 +1436,31 @@ PDFiumPage::Highlight::Highlight(const Highlight& that) = default;
PDFiumPage::Highlight::~Highlight() = default;
+PDFiumPage::FormField::FormField() = default;
+
+PDFiumPage::FormField::FormField(const FormField& that) = default;
+
+PDFiumPage::FormField::~FormField() = default;
+
PDFiumPage::TextField::TextField() = default;
PDFiumPage::TextField::TextField(const TextField& that) = default;
PDFiumPage::TextField::~TextField() = default;
+PDFiumPage::ChoiceFieldOption::ChoiceFieldOption() = default;
+
+PDFiumPage::ChoiceFieldOption::ChoiceFieldOption(
+ const ChoiceFieldOption& that) = default;
+
+PDFiumPage::ChoiceFieldOption::~ChoiceFieldOption() = default;
+
+PDFiumPage::ChoiceField::ChoiceField() = default;
+
+PDFiumPage::ChoiceField::ChoiceField(const ChoiceField& that) = default;
+
+PDFiumPage::ChoiceField::~ChoiceField() = default;
+
// static
uint32_t PDFiumPage::CountLinkHighlightOverlaps(
const std::vector<Link>& links,
diff --git a/chromium/pdf/pdfium/pdfium_page.h b/chromium/pdf/pdfium/pdfium_page.h
index 5a3aefae9da..baaec24e081 100644
--- a/chromium/pdf/pdfium/pdfium_page.h
+++ b/chromium/pdf/pdfium/pdfium_page.h
@@ -178,63 +178,10 @@ class PDFiumPage {
FRIEND_TEST_ALL_PREFIXES(PDFiumPageLinkTest, TestLinkGeneration);
FRIEND_TEST_ALL_PREFIXES(PDFiumPageHighlightTest, TestPopulateHighlights);
FRIEND_TEST_ALL_PREFIXES(PDFiumPageTextFieldTest, TestPopulateTextFields);
+ FRIEND_TEST_ALL_PREFIXES(PDFiumPageChoiceFieldTest, TestPopulateChoiceFields);
FRIEND_TEST_ALL_PREFIXES(PDFiumPageOverlappingTest, CountPartialOverlaps);
FRIEND_TEST_ALL_PREFIXES(PDFiumPageOverlappingTest, CountCompleteOverlaps);
- // Returns a link index if the given character index is over a link, or -1
- // otherwise.
- int GetLink(int char_index, LinkTarget* target);
- // Calculate the locations of any links on the page.
- void CalculateLinks();
- // Populates weblinks on the page.
- void PopulateWebLinks();
- // Populates annotation links on the page.
- void PopulateAnnotationLinks();
- // Calculate the locations of images on the page.
- void CalculateImages();
- // Populate annotations like highlight and text field on the page.
- void PopulateAnnotations();
- // Populate |highlights_| with |annot|.
- void PopulateHighlight(FPDF_ANNOTATION annot);
- // Populate |text_fields_| with |annot|.
- void PopulateTextField(FPDF_ANNOTATION annot);
- // Returns link type and fills target associated with a destination. Returns
- // NONSELECTABLE_AREA if detection failed.
- Area GetDestinationTarget(FPDF_DEST destination, LinkTarget* target);
- // Returns link type and fills target associated with a URI action. Returns
- // NONSELECTABLE_AREA if detection failed.
- Area GetURITarget(FPDF_ACTION uri_action, LinkTarget* target) const;
- // Calculates the set of character indices on which text runs need to be
- // broken for page objects such as links and images.
- void CalculatePageObjectTextRunBreaks();
- // Set text run style information based on a character of the text run.
- void CalculateTextRunStyleInfo(
- int char_index,
- pp::PDF::PrivateAccessibilityTextStyleInfo* style_info);
- // Returns a boolean indicating if the character at index |char_index| has the
- // same text style as the text run.
- bool AreTextStyleEqual(
- int char_index,
- const pp::PDF::PrivateAccessibilityTextStyleInfo& style);
-
- // Key : Marked content id for the image element as specified in the
- // struct tree.
- // Value : Index of image in the |images_| vector.
- using MarkedContentIdToImageMap = std::map<int, size_t>;
- // Traverses the entire struct tree of the page recursively and extracts the
- // alt text from struct tree elements corresponding to the marked content IDs
- // present in |marked_content_id_image_map|.
- void PopulateImageAltText(
- const MarkedContentIdToImageMap& marked_content_id_image_map);
- // Traverses a struct element and its sub-tree recursively and extracts the
- // alt text from struct elements corresponding to the marked content IDs
- // present in |marked_content_id_image_map|. Uses |visited_elements| to guard
- // against malformed struct trees.
- void PopulateImageAltTextForStructElement(
- const MarkedContentIdToImageMap& marked_content_id_image_map,
- FPDF_STRUCTELEMENT current_element,
- std::set<FPDF_STRUCTELEMENT>* visited_elements);
-
class ScopedUnloadPreventer {
public:
explicit ScopedUnloadPreventer(PDFiumPage* page);
@@ -284,25 +231,114 @@ class PDFiumPage {
// Color of the highlight in ARGB. Alpha is stored in the first 8 MSBs. RGB
// follows after it with each using 8 bytes.
uint32_t color;
+
+ // Text of the popup note associated with highlight.
+ std::string note_text;
+ };
+
+ // Represents a form field within the page.
+ struct FormField {
+ FormField();
+ FormField(const FormField& other);
+ ~FormField();
+
+ pp::Rect bounding_rect;
+ // Represents the name of form field as defined in the field dictionary.
+ std::string name;
+ // Represents the flags of form field as defined in the field dictionary.
+ int flags;
};
// Represents a text field within the page.
- struct TextField {
+ struct TextField : FormField {
TextField();
TextField(const TextField& other);
~TextField();
- // Represents the name of form field as defined in the field dictionary.
- std::string name;
std::string value;
- pp::Rect bounding_rect;
- // Represents the flags of form field as defined in the field dictionary.
- int flags;
};
+ // Represents a choice field option.
+ struct ChoiceFieldOption {
+ ChoiceFieldOption();
+ ChoiceFieldOption(const ChoiceFieldOption& other);
+ ~ChoiceFieldOption();
+
+ std::string name;
+ bool is_selected;
+ };
+
+ // Represents a choice field within the page.
+ struct ChoiceField : FormField {
+ ChoiceField();
+ ChoiceField(const ChoiceField& other);
+ ~ChoiceField();
+
+ std::vector<ChoiceFieldOption> options;
+ };
+
+ // Returns a link index if the given character index is over a link, or -1
+ // otherwise.
+ int GetLink(int char_index, LinkTarget* target);
+ // Calculate the locations of any links on the page.
+ void CalculateLinks();
+ // Populates weblinks on the page.
+ void PopulateWebLinks();
+ // Populates annotation links on the page.
+ void PopulateAnnotationLinks();
+ // Calculate the locations of images on the page.
+ void CalculateImages();
+ // Populate annotations like highlight and text field on the page.
+ void PopulateAnnotations();
+ // Populate |highlights_| with |annot|.
+ void PopulateHighlight(FPDF_ANNOTATION annot);
+ // Populate |text_fields_| with |annot|.
+ void PopulateTextField(FPDF_ANNOTATION annot);
+ // Populate |choice_fields_| with |annot|.
+ void PopulateChoiceField(FPDF_ANNOTATION annot);
+ // Populate form fields like text field and choice field on the page.
+ void PopulateFormField(FPDF_ANNOTATION annot);
+ // Returns link type and fills target associated with a destination. Returns
+ // NONSELECTABLE_AREA if detection failed.
+ Area GetDestinationTarget(FPDF_DEST destination, LinkTarget* target);
+ // Returns link type and fills target associated with a URI action. Returns
+ // NONSELECTABLE_AREA if detection failed.
+ Area GetURITarget(FPDF_ACTION uri_action, LinkTarget* target) const;
+ // Calculates the set of character indices on which text runs need to be
+ // broken for page objects such as links and images.
+ void CalculatePageObjectTextRunBreaks();
+ // Set text run style information based on a character of the text run.
+ void CalculateTextRunStyleInfo(
+ int char_index,
+ pp::PDF::PrivateAccessibilityTextStyleInfo* style_info);
+ // Returns a boolean indicating if the character at index |char_index| has the
+ // same text style as the text run.
+ bool AreTextStyleEqual(
+ int char_index,
+ const pp::PDF::PrivateAccessibilityTextStyleInfo& style);
+
+ // Key : Marked content id for the image element as specified in the
+ // struct tree.
+ // Value : Index of image in the |images_| vector.
+ using MarkedContentIdToImageMap = std::map<int, size_t>;
+ // Traverses the entire struct tree of the page recursively and extracts the
+ // alt text from struct tree elements corresponding to the marked content IDs
+ // present in |marked_content_id_image_map|.
+ void PopulateImageAltText(
+ const MarkedContentIdToImageMap& marked_content_id_image_map);
+ // Traverses a struct element and its sub-tree recursively and extracts the
+ // alt text from struct elements corresponding to the marked content IDs
+ // present in |marked_content_id_image_map|. Uses |visited_elements| to guard
+ // against malformed struct trees.
+ void PopulateImageAltTextForStructElement(
+ const MarkedContentIdToImageMap& marked_content_id_image_map,
+ FPDF_STRUCTELEMENT current_element,
+ std::set<FPDF_STRUCTELEMENT>* visited_elements);
static uint32_t CountLinkHighlightOverlaps(
const std::vector<Link>& links,
const std::vector<Highlight>& highlights);
+ bool PopulateFormFieldProperties(FPDF_ANNOTATION annot,
+ FormField* form_field);
PDFiumEngine* engine_;
ScopedFPDFPage page_;
@@ -317,6 +353,7 @@ class PDFiumPage {
bool calculated_annotations_ = false;
std::vector<Highlight> highlights_;
std::vector<TextField> text_fields_;
+ std::vector<ChoiceField> choice_fields_;
bool logged_overlapping_annotations_ = false;
bool calculated_page_object_text_run_breaks_ = false;
// The set of character indices on which text runs need to be broken for page
diff --git a/chromium/pdf/pdfium/pdfium_page_unittest.cc b/chromium/pdf/pdfium/pdfium_page_unittest.cc
index 7906515599d..fae64ca8f2e 100644
--- a/chromium/pdf/pdfium/pdfium_page_unittest.cc
+++ b/chromium/pdf/pdfium/pdfium_page_unittest.cc
@@ -8,6 +8,8 @@
#include <vector>
#include "base/check.h"
+#include "base/optional.h"
+#include "base/strings/string_util.h"
#include "base/test/gtest_util.h"
#include "pdf/pdfium/pdfium_engine.h"
#include "pdf/pdfium/pdfium_test_base.h"
@@ -234,6 +236,80 @@ TEST_F(PDFiumPageImageTest, TestImageAltText) {
using PDFiumPageTextTest = PDFiumTestBase;
+TEST_F(PDFiumPageTextTest, TestTextRunBounds) {
+ TestClient client;
+ std::unique_ptr<PDFiumEngine> engine = InitializeEngine(
+ &client, FILE_PATH_LITERAL("leading_trailing_spaces_per_text_run.pdf"));
+ ASSERT_TRUE(engine);
+
+ constexpr int kFirstRunStartIndex = 0;
+ constexpr int kFirstRunEndIndex = 20;
+ constexpr int kPageIndex = 0;
+ base::Optional<pp::PDF::PrivateAccessibilityTextRunInfo> text_run_info_1 =
+ engine->GetTextRunInfo(kPageIndex, kFirstRunStartIndex);
+ ASSERT_TRUE(text_run_info_1.has_value());
+
+ const auto& actual_text_run_1 = text_run_info_1.value();
+ EXPECT_EQ(21u, actual_text_run_1.len);
+
+ EXPECT_TRUE(base::IsUnicodeWhitespace(
+ engine->GetCharUnicode(kPageIndex, kFirstRunStartIndex)));
+ pp::FloatRect text_run_bounds = actual_text_run_1.bounds;
+ EXPECT_TRUE(text_run_bounds.Contains(
+ engine->GetCharBounds(kPageIndex, kFirstRunStartIndex)));
+
+ // Last non-space character should fall in the bounding box of the text run.
+ // Text run looks like this:
+ // " Hello, world! \r\n "<17 characters><first Tj>
+ // " \r\n "<4 characters><second Tj>
+ // " "<1 character><third Tj starting spaces>
+ // Finally generated text run: " Hello, world! \r\n \r\n "
+ constexpr int kFirstRunLastNonSpaceCharIndex = 13;
+ EXPECT_FALSE(base::IsUnicodeWhitespace(
+ engine->GetCharUnicode(kPageIndex, kFirstRunLastNonSpaceCharIndex)));
+ EXPECT_TRUE(text_run_bounds.Contains(
+ engine->GetCharBounds(kPageIndex, kFirstRunLastNonSpaceCharIndex)));
+
+ EXPECT_TRUE(base::IsUnicodeWhitespace(
+ engine->GetCharUnicode(kPageIndex, kFirstRunEndIndex)));
+ pp::FloatRect end_char_rect =
+ engine->GetCharBounds(kPageIndex, kFirstRunEndIndex);
+ EXPECT_FALSE(text_run_bounds.Contains(end_char_rect));
+ // Equals to the length of the previous text run.
+ constexpr int kSecondRunStartIndex = 21;
+ constexpr int kSecondRunEndIndex = 36;
+ // Test the properties of second text run.
+ // Note: The leading spaces in second text run are accounted for in the end
+ // of first text run. Hence we won't see a space leading the second text run.
+ base::Optional<pp::PDF::PrivateAccessibilityTextRunInfo> text_run_info_2 =
+ engine->GetTextRunInfo(kPageIndex, kSecondRunStartIndex);
+ ASSERT_TRUE(text_run_info_2.has_value());
+
+ const auto& actual_text_run_2 = text_run_info_2.value();
+ EXPECT_EQ(16u, actual_text_run_2.len);
+
+ EXPECT_FALSE(base::IsUnicodeWhitespace(
+ engine->GetCharUnicode(kPageIndex, kSecondRunStartIndex)));
+ text_run_bounds = actual_text_run_2.bounds;
+ EXPECT_TRUE(text_run_bounds.Contains(
+ engine->GetCharBounds(kPageIndex, kSecondRunStartIndex)));
+
+ // Last non-space character should fall in the bounding box of the text run.
+ // Text run looks like this:
+ // "Goodbye, world! "<19 characters><first Tj>
+ // Finally generated text run: "Goodbye, world! "
+ constexpr int kSecondRunLastNonSpaceCharIndex = 35;
+ EXPECT_FALSE(base::IsUnicodeWhitespace(
+ engine->GetCharUnicode(kPageIndex, kSecondRunLastNonSpaceCharIndex)));
+ EXPECT_TRUE(text_run_bounds.Contains(
+ engine->GetCharBounds(kPageIndex, kSecondRunLastNonSpaceCharIndex)));
+
+ EXPECT_TRUE(base::IsUnicodeWhitespace(
+ engine->GetCharUnicode(kPageIndex, kSecondRunEndIndex)));
+ EXPECT_FALSE(text_run_bounds.Contains(
+ engine->GetCharBounds(kPageIndex, kSecondRunEndIndex)));
+}
+
TEST_F(PDFiumPageTextTest, GetTextRunInfo) {
TestClient client;
std::unique_ptr<PDFiumEngine> engine =
@@ -333,7 +409,7 @@ TEST_F(PDFiumPageTextTest, TestHighlightTextRunInfo) {
{7,
PP_MakeFloatRectFromXYWH(106.66666f, 198.66667f, 73.333336f, 18.666672f),
PP_PrivateDirection::PP_PRIVATEDIRECTION_LTR, kExpectedStyle},
- {2, PP_MakeFloatRectFromXYWH(188.0f, 202.66667f, 9.333333f, 14.666667f),
+ {2, PP_MakeFloatRectFromXYWH(181.33333f, 192.0f, 16.0f, 25.333344f),
PP_PrivateDirection::PP_PRIVATEDIRECTION_NONE, kExpectedStyle},
{2,
PP_MakeFloatRectFromXYWH(198.66667f, 202.66667f, 21.333328f, 10.666672f),
@@ -437,6 +513,94 @@ TEST_F(PDFiumPageTextFieldTest, TestPopulateTextFields) {
}
}
+using PDFiumPageChoiceFieldTest = PDFiumTestBase;
+
+TEST_F(PDFiumPageChoiceFieldTest, TestPopulateChoiceFields) {
+ struct ExpectedChoiceFieldOption {
+ const char* name;
+ bool is_selected;
+ };
+
+ struct ExpectedChoiceField {
+ const char* name;
+ std::vector<struct ExpectedChoiceFieldOption> options;
+ pp::Rect bounding_rect;
+ int flags;
+ };
+
+ static const ExpectedChoiceField kExpectedChoiceFields[] = {
+ {"Listbox_SingleSelect",
+ {{"Foo", false}, {"Bar", false}, {"Qux", false}},
+ {138, 296, 135, 41},
+ 0},
+ {"Combo1",
+ {{"Apple", false}, {"Banana", true}, {"Cherry", false}},
+ {138, 230, 135, 41},
+ 131072},
+ {"Listbox_ReadOnly",
+ {{"Dog", false}, {"Elephant", false}, {"Frog", false}},
+ {138, 96, 135, 41},
+ 1},
+ {"Listbox_MultiSelectMultipleIndices",
+ {
+ {"Albania", false},
+ {"Belgium", true},
+ {"Croatia", false},
+ {"Denmark", true},
+ {"Estonia", false},
+ },
+ {138, 430, 135, 41},
+ 2097152},
+ {"Listbox_MultiSelectMultipleValues",
+ {
+ {"Alpha", false},
+ {"Beta", false},
+ {"Gamma", true},
+ {"Delta", false},
+ {"Epsilon", true},
+ },
+ {138, 496, 135, 41},
+ 2097152},
+ {"Listbox_MultiSelectMultipleMismatch",
+ {
+ {"Alligator", true},
+ {"Bear", false},
+ {"Cougar", true},
+ {"Deer", false},
+ {"Echidna", false},
+ },
+ {138, 563, 135, 41},
+ 2097152}};
+
+ TestClient client;
+ std::unique_ptr<PDFiumEngine> engine =
+ InitializeEngine(&client, FILE_PATH_LITERAL("form_choice_fields.pdf"));
+ ASSERT_TRUE(engine);
+ ASSERT_EQ(1, engine->GetNumberOfPages());
+
+ PDFiumPage* page = GetPDFiumPageForTest(engine.get(), 0);
+ ASSERT_TRUE(page);
+ page->PopulateAnnotations();
+ size_t choice_fields_count = page->choice_fields_.size();
+ ASSERT_EQ(base::size(kExpectedChoiceFields), choice_fields_count);
+
+ for (size_t i = 0; i < choice_fields_count; ++i) {
+ EXPECT_EQ(kExpectedChoiceFields[i].name, page->choice_fields_[i].name);
+ size_t choice_field_options_count = page->choice_fields_[i].options.size();
+ ASSERT_EQ(base::size(kExpectedChoiceFields[i].options),
+ choice_field_options_count);
+ for (size_t j = 0; j < choice_field_options_count; ++j) {
+ EXPECT_EQ(kExpectedChoiceFields[i].options[j].name,
+ page->choice_fields_[i].options[j].name);
+ EXPECT_EQ(kExpectedChoiceFields[i].options[j].is_selected,
+ page->choice_fields_[i].options[j].is_selected);
+ }
+ CompareRect(kExpectedChoiceFields[i].bounding_rect,
+ page->choice_fields_[i].bounding_rect);
+ EXPECT_EQ(kExpectedChoiceFields[i].flags, page->choice_fields_[i].flags);
+ }
+}
+
using PDFiumPageOverlappingTest = PDFiumTestBase;
// The following scenarios are covered across both test cases:
diff --git a/chromium/pdf/pdfium/pdfium_permissions.cc b/chromium/pdf/pdfium/pdfium_permissions.cc
index db3c98032b7..b24c6f42a58 100644
--- a/chromium/pdf/pdfium/pdfium_permissions.cc
+++ b/chromium/pdf/pdfium/pdfium_permissions.cc
@@ -4,6 +4,8 @@
#include "pdf/pdfium/pdfium_permissions.h"
+#include "base/notreached.h"
+
namespace chrome_pdf {
// static
diff --git a/chromium/pdf/pdfium/pdfium_print.cc b/chromium/pdf/pdfium/pdfium_print.cc
index 5cb79dce728..be5dd656dda 100644
--- a/chromium/pdf/pdfium/pdfium_print.cc
+++ b/chromium/pdf/pdfium/pdfium_print.cc
@@ -9,11 +9,11 @@
#include <utility>
#include "base/strings/string_number_conversions.h"
-#include "pdf/geometry_conversions.h"
#include "pdf/pdf_transform.h"
#include "pdf/pdfium/pdfium_engine.h"
#include "pdf/pdfium/pdfium_mem_buffer_file_read.h"
#include "pdf/pdfium/pdfium_mem_buffer_file_write.h"
+#include "pdf/ppapi_migration/geometry_conversions.h"
#include "ppapi/c/dev/ppp_printing_dev.h"
#include "ppapi/c/private/ppp_pdf.h"
#include "printing/nup_parameters.h"
diff --git a/chromium/pdf/pdfium/pdfium_test_base.cc b/chromium/pdf/pdfium/pdfium_test_base.cc
index 95c48c11c9b..b220fb92535 100644
--- a/chromium/pdf/pdfium/pdfium_test_base.cc
+++ b/chromium/pdf/pdfium/pdfium_test_base.cc
@@ -103,10 +103,11 @@ PDFiumTestBase::InitializeEngineWithoutLoading(
void PDFiumTestBase::InitializePDFium() {
FPDF_LIBRARY_CONFIG config;
- config.version = 2;
+ config.version = 3;
config.m_pUserFontPaths = nullptr;
config.m_pIsolate = nullptr;
config.m_v8EmbedderSlot = 0;
+ config.m_pPlatform = nullptr;
FPDF_InitLibraryWithConfig(&config);
}