0

Update form field states in PDFiumEngine

This CL updates the form field states in PDFiumEngine. This is done via
setting |PDFiumEngine::in_form_text_area_| and
|PDFiumEngine::editable_form_text_area_| as per the focused annotation.

Unit tests have been added to validate the scenario.

Bug: 989040
Change-Id: I27e163819f5ca5f88e6ce10df48f2e7c7a6e97dc
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2086466
Reviewed-by: Lei Zhang <thestig@chromium.org>
Reviewed-by: Kevin Babbitt <kbabbitt@microsoft.com>
Commit-Queue: Ankit Kumar 🌪️ <ankk@microsoft.com>
Cr-Commit-Position: refs/heads/master@{#765557}
This commit is contained in:
Ankit Kumar
2020-05-05 15:16:37 +00:00
committed by Commit Bot
parent f4b242aaa3
commit 209bc5efc0
4 changed files with 78 additions and 36 deletions

@ -1114,19 +1114,9 @@ bool PDFiumEngine::OnLeftMouseDown(const pp::MouseInputEvent& event) {
double page_y;
DeviceToPage(page_index, point, &page_x, &page_y);
bool is_form_text_area = IsFormTextArea(area, form_type);
FPDF_PAGE page = pages_[page_index]->GetPage();
bool is_editable_form_text_area =
is_form_text_area &&
IsPointInEditableFormTextArea(page, page_x, page_y, form_type);
if (event.GetClickCount() == 1) {
FORM_OnLButtonDown(form(), page, event.GetModifiers(), page_x, page_y);
} else if (event.GetClickCount() == 2) {
FORM_OnLButtonDoubleClick(form(), page, event.GetModifiers(), page_x,
page_y);
}
if (form_type != FPDF_FORMFIELD_UNKNOWN) {
// FORM_OnLButton*() will trigger a callback to
// OnFocusedAnnotationUpdated() which will call SetInFormTextArea().
// Destroy SelectionChangeInvalidator object before SetInFormTextArea()
// changes plugin's focus to be in form text area. This way, regular text
// selection can be cleared when a user clicks into a form text area
@ -1134,11 +1124,18 @@ bool PDFiumEngine::OnLeftMouseDown(const pp::MouseInputEvent& event) {
// ~SelectionChangeInvalidator() still goes to the Mimehandler
// (not the Renderer).
selection_invalidator.reset();
SetInFormTextArea(is_form_text_area);
editable_form_text_area_ = is_editable_form_text_area;
return true; // Return now before we get into the selection code.
}
FPDF_PAGE page = pages_[page_index]->GetPage();
if (event.GetClickCount() == 1) {
FORM_OnLButtonDown(form(), page, event.GetModifiers(), page_x, page_y);
} else if (event.GetClickCount() == 2) {
FORM_OnLButtonDoubleClick(form(), page, event.GetModifiers(), page_x,
page_y);
}
if (form_type != FPDF_FORMFIELD_UNKNOWN)
return true; // Return now before we get into the selection code.
}
SetInFormTextArea(false);
@ -1197,7 +1194,6 @@ bool PDFiumEngine::OnRightMouseDown(const pp::MouseInputEvent& event) {
DCHECK_GE(form_type, FPDF_FORMFIELD_UNKNOWN);
bool is_form_text_area = IsFormTextArea(area, form_type);
bool is_editable_form_text_area = false;
double page_x = -1;
double page_y = -1;
@ -1207,8 +1203,6 @@ bool PDFiumEngine::OnRightMouseDown(const pp::MouseInputEvent& event) {
DeviceToPage(page_index, point, &page_x, &page_y);
page = pages_[page_index]->GetPage();
is_editable_form_text_area =
IsPointInEditableFormTextArea(page, page_x, page_y, form_type);
}
// Handle the case when focus starts inside a form text area.
@ -1231,8 +1225,6 @@ bool PDFiumEngine::OnRightMouseDown(const pp::MouseInputEvent& event) {
selection_.clear();
}
SetInFormTextArea(true);
editable_form_text_area_ = is_editable_form_text_area;
FORM_OnFocus(form(), page, 0, page_x, page_y);
return true;
}
@ -3593,23 +3585,19 @@ void PDFiumEngine::SetMouseLeftButtonDown(bool is_mouse_left_button_down) {
mouse_left_button_down_ = is_mouse_left_button_down;
}
bool PDFiumEngine::IsPointInEditableFormTextArea(FPDF_PAGE page,
double page_x,
double page_y,
int form_type) {
bool PDFiumEngine::IsAnnotationAnEditableFormTextArea(FPDF_ANNOTATION annot,
int form_type) const {
#if defined(PDF_ENABLE_XFA)
if (IS_XFA_FORMFIELD(form_type))
if (IS_XFA_FORMFIELD(form_type)) {
return form_type == FPDF_FORMFIELD_XFA_TEXTFIELD ||
form_type == FPDF_FORMFIELD_XFA_COMBOBOX;
}
#endif // defined(PDF_ENABLE_XFA)
const FS_POINTF point = {page_x, page_y};
ScopedFPDFAnnotation annot(
FPDFAnnot_GetFormFieldAtPoint(form(), page, &point));
if (!annot)
return false;
int flags = FPDFAnnot_GetFormFieldFlags(form(), annot.get());
int flags = FPDFAnnot_GetFormFieldFlags(form(), annot);
return CheckIfEditableFormTextArea(flags, form_type);
}
@ -3696,6 +3684,19 @@ void PDFiumEngine::ScrollIntoView(const pp::Rect& rect) {
}
}
void PDFiumEngine::OnFocusedAnnotationUpdated(FPDF_ANNOTATION annot) {
int form_type = FPDFAnnot_GetFormFieldType(form(), annot);
if (form_type <= FPDF_FORMFIELD_UNKNOWN) {
SetInFormTextArea(false);
return;
}
bool is_form_text_area =
PDFiumPage::FormTypeToArea(form_type) == PDFiumPage::FORM_TEXT_AREA;
SetInFormTextArea(is_form_text_area);
editable_form_text_area_ =
is_form_text_area && IsAnnotationAnEditableFormTextArea(annot, form_type);
}
void PDFiumEngine::SetCaretPosition(const pp::Point& position) {
// TODO(dsinclair): Handle caret position ...
}

@ -524,12 +524,10 @@ class PDFiumEngine : public PDFEngine,
// Sets whether or not left mouse button is currently being held down.
void SetMouseLeftButtonDown(bool is_mouse_left_button_down);
// Given coordinates on |page| has a form of |form_type| which is known to be
// a form text area, check if it is an editable form text area.
bool IsPointInEditableFormTextArea(FPDF_PAGE page,
double page_x,
double page_y,
int form_type);
// Given an annotation which is a form of |form_type| which is known to be a
// form text area, check if it is an editable form text area.
bool IsAnnotationAnEditableFormTextArea(FPDF_ANNOTATION annot,
int form_type) const;
bool PageIndexInBounds(int index) const;
bool IsPageCharacterIndexInBounds(
@ -581,6 +579,8 @@ class PDFiumEngine : public PDFEngine,
// already in view.
void ScrollIntoView(const pp::Rect& rect);
void OnFocusedAnnotationUpdated(FPDF_ANNOTATION annot);
// Fetches and populates the fields of |doc_metadata_|. To be called after the
// document is loaded.
void LoadDocumentMetadata();

@ -255,6 +255,10 @@ class PDFiumEngineTabbingTest : public PDFiumTestBase {
return engine->last_focused_annot_index_;
}
bool IsInFormTextArea(PDFiumEngine* engine) {
return engine->in_form_text_area_;
}
protected:
base::test::TaskEnvironment task_environment_{
base::test::TaskEnvironment::TimeSource::MOCK_TIME};
@ -574,4 +578,39 @@ TEST_F(PDFiumEngineTabbingTest, RestoringAnnotFocusTest) {
EXPECT_EQ(1, GetLastFocusedPage(engine.get()));
}
TEST_F(PDFiumEngineTabbingTest, VerifyFormFieldStatesOnTabbing) {
/*
* Document structure
* Document
* ++ Page 1
* ++++ Annotation (Text Field)
* ++++ Annotation (Radio Button)
*/
TestClient client;
std::unique_ptr<PDFiumEngine> engine =
InitializeEngine(&client, FILE_PATH_LITERAL("annots.pdf"));
ASSERT_TRUE(engine);
ASSERT_EQ(1, engine->GetNumberOfPages());
ASSERT_TRUE(HandleTabEvent(engine.get(), 0));
EXPECT_EQ(PDFiumEngine::FocusElementType::kDocument,
GetFocusedElementType(engine.get()));
// Bring focus to the text field.
ASSERT_TRUE(HandleTabEvent(engine.get(), 0));
EXPECT_EQ(PDFiumEngine::FocusElementType::kPage,
GetFocusedElementType(engine.get()));
EXPECT_EQ(0, GetLastFocusedPage(engine.get()));
EXPECT_TRUE(IsInFormTextArea(engine.get()));
EXPECT_TRUE(engine->CanEditText());
// Bring focus to the button.
ASSERT_TRUE(HandleTabEvent(engine.get(), 0));
EXPECT_EQ(PDFiumEngine::FocusElementType::kPage,
GetFocusedElementType(engine.get()));
EXPECT_EQ(0, GetLastFocusedPage(engine.get()));
EXPECT_FALSE(IsInFormTextArea(engine.get()));
EXPECT_FALSE(engine->CanEditText());
}
} // namespace chrome_pdf

@ -293,6 +293,8 @@ void PDFiumFormFiller::Form_OnFocusChange(FPDF_FORMFILLINFO* param,
engine->layout_.options().default_page_orientation());
engine->ScrollIntoView(screen_rect);
engine->OnFocusedAnnotationUpdated(annot);
}
// static