diff --git a/chrome/browser/resources/pdf/pdf_viewer.js b/chrome/browser/resources/pdf/pdf_viewer.js index 760160c8652a9..d5a432f6385db 100644 --- a/chrome/browser/resources/pdf/pdf_viewer.js +++ b/chrome/browser/resources/pdf/pdf_viewer.js @@ -1291,6 +1291,9 @@ export class PDFViewer { type: 'touchSelectionOccurred', }); return; + case 'documentFocusChanged': + // TODO(crbug.com/1069370): Draw a focus rect around plugin. + return; } assertNotReached('Unknown message type received: ' + data.type); } diff --git a/pdf/out_of_process_instance.cc b/pdf/out_of_process_instance.cc index 0ae0e1637bbd4..780c73aaa122d 100644 --- a/pdf/out_of_process_instance.cc +++ b/pdf/out_of_process_instance.cc @@ -186,6 +186,10 @@ constexpr char kJSIsSelecting[] = "isSelecting"; constexpr char kJSFieldFocusType[] = "formFocusChange"; constexpr char kJSFieldFocus[] = "focused"; +// Notify when document is focused (Plugin -> Page) +constexpr char kJSDocumentFocusChangedType[] = "documentFocusChanged"; +constexpr char kJSDocumentHasFocus[] = "hasFocus"; + constexpr int kFindResultCooldownMs = 100; // Do not save forms with over 100 MB. This cap should be kept in sync with and @@ -1934,6 +1938,13 @@ float OutOfProcessInstance::GetToolbarHeightInScreenCoords() { return top_toolbar_height_in_viewport_coords_ * device_scale_; } +void OutOfProcessInstance::DocumentFocusChanged(bool document_has_focus) { + pp::VarDictionary message; + message.Set(pp::Var(kType), pp::Var(kJSDocumentFocusChangedType)); + message.Set(pp::Var(kJSDocumentHasFocus), pp::Var(document_has_focus)); + PostMessage(message); +} + void OutOfProcessInstance::ProcessPreviewPageInfo(const std::string& url, int dest_page_index) { DCHECK(IsPrintPreview()); diff --git a/pdf/out_of_process_instance.h b/pdf/out_of_process_instance.h index e8c00636d7a01..6ac651287735a 100644 --- a/pdf/out_of_process_instance.h +++ b/pdf/out_of_process_instance.h @@ -146,6 +146,7 @@ class OutOfProcessInstance : public pp::Instance, void SelectionChanged(const pp::Rect& left, const pp::Rect& right) override; void IsEditModeChanged(bool is_edit_mode) override; float GetToolbarHeightInScreenCoords() override; + void DocumentFocusChanged(bool document_has_focus) override; // PreviewModeClient::Client implementation. void PreviewDocumentLoadComplete() override; diff --git a/pdf/pdf_engine.h b/pdf/pdf_engine.h index 33dbe762bd186..51284e1177faf 100644 --- a/pdf/pdf_engine.h +++ b/pdf/pdf_engine.h @@ -266,6 +266,9 @@ class PDFEngine { // Gets the height of the top toolbar in screen coordinates. This is // independent of whether it is hidden or not at the moment. virtual float GetToolbarHeightInScreenCoords() = 0; + + // Notifies the client about focus changes for the document. + virtual void DocumentFocusChanged(bool document_has_focus) {} }; struct AccessibilityLinkInfo { diff --git a/pdf/pdfium/pdfium_engine.cc b/pdf/pdfium/pdfium_engine.cc index 3adfadd68513b..425ac23b26e57 100644 --- a/pdf/pdfium/pdfium_engine.cc +++ b/pdf/pdfium/pdfium_engine.cc @@ -947,7 +947,7 @@ void PDFiumEngine::KillFormFocus() { void PDFiumEngine::UpdateFocus(bool has_focus) { 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) { @@ -961,7 +961,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_, @@ -1119,7 +1119,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; @@ -3849,7 +3849,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; } @@ -3867,17 +3867,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; } @@ -3895,7 +3895,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 @@ -3908,11 +3908,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(); @@ -3922,6 +3922,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/pdf/pdfium/pdfium_engine.h b/pdf/pdfium/pdfium_engine.h index 16e33cf32e315..c79ee7fd80897 100644 --- a/pdf/pdfium/pdfium_engine.h +++ b/pdf/pdfium/pdfium_engine.h @@ -606,6 +606,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); diff --git a/pdf/pdfium/pdfium_engine_unittest.cc b/pdf/pdfium/pdfium_engine_unittest.cc index 623c8e11b4aeb..b112703fa9a4c 100644 --- a/pdf/pdfium/pdfium_engine_unittest.cc +++ b/pdf/pdfium/pdfium_engine_unittest.cc @@ -227,6 +227,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; @@ -376,13 +387,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())); @@ -421,13 +439,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())); @@ -510,13 +535,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())); @@ -550,13 +582,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())); @@ -588,13 +627,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()));