0

Send PDF Searchifier running state to browser to show UX elements.

To show PDF Searchify promo and progress state in browser, PDF
searchifier's rough state is passed to the PDF document helper in the
browser process.
This state will be used in the next CLs to show the promo and manage
the progress bubble.

UX design:
https://docs.google.com/presentation/d/17zeY-H3bYpTkyNos_kHEQXaaFOHECHqMLlXorj4DLb0/edit?resourcekey=0-f0k0VHM3j--WirgSZSp5ow#slide=id.YEkgNTa

AX-Relnotes: n/a
Bug: 360803943
Change-Id: I97a9b7ab40b3404fa4162b9651bf5819ad8ad988
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5968218
Reviewed-by: Lei Zhang <thestig@chromium.org>
Reviewed-by: Kinuko Yasuda <kinuko@chromium.org>
Reviewed-by: Antonio Sartori <antoniosartori@chromium.org>
Auto-Submit: Ramin Halavati <rhalavati@chromium.org>
Commit-Queue: Ramin Halavati <rhalavati@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1377711}
This commit is contained in:
Ramin Halavati
2024-11-04 17:14:55 +00:00
committed by Chromium LUCI CQ
parent 04cb0be1b2
commit a957501802
25 changed files with 175 additions and 2 deletions

@ -19,5 +19,6 @@ source_set("pdf") {
"//components/pdf/browser",
"//extensions/browser",
"//pdf:features",
"//services/screen_ai/buildflags",
]
}

@ -87,3 +87,11 @@ void ChromePDFDocumentHelperClient::SetPluginCanSave(
guest_view->SetPluginCanSave(can_save);
}
}
#if BUILDFLAG(ENABLE_SCREEN_AI_SERVICE)
void ChromePDFDocumentHelperClient::OnSearchifyStateChange(
bool busy,
content::WebContents* contents) {
// TODO(crbug.com/360803943): Show promo and manage progress bubble.
}
#endif

@ -6,6 +6,7 @@
#define CHROME_BROWSER_UI_PDF_CHROME_PDF_DOCUMENT_HELPER_CLIENT_H_
#include "components/pdf/browser/pdf_document_helper_client.h"
#include "services/screen_ai/buildflags/buildflags.h"
class ChromePDFDocumentHelperClient : public pdf::PDFDocumentHelperClient {
public:
@ -25,6 +26,10 @@ class ChromePDFDocumentHelperClient : public pdf::PDFDocumentHelperClient {
void OnSaveURL(content::WebContents* contents) override;
void SetPluginCanSave(content::RenderFrameHost* render_frame_host,
bool can_save) override;
#if BUILDFLAG(ENABLE_SCREEN_AI_SERVICE)
void OnSearchifyStateChange(bool busy,
content::WebContents* contents) override;
#endif
};
#endif // CHROME_BROWSER_UI_PDF_CHROME_PDF_DOCUMENT_HELPER_CLIENT_H_

@ -30,6 +30,7 @@ source_set("browser") {
"//components/pdf/common:util",
"//content/public/common",
"//pdf:features",
"//services/screen_ai/buildflags",
"//ui/base",
"//ui/gfx/geometry",
]

@ -10,6 +10,7 @@ include_rules = [
"+services/network/public/cpp",
"+services/network/public/mojom",
"+services/network/test",
"+services/screen_ai/buildflags",
"+third_party/blink/public/common/associated_interfaces/associated_interface_provider.h",
"+third_party/skia/include/core",
"+ui/base",

@ -128,6 +128,12 @@ void PDFDocumentHelper::SetPluginCanSave(bool can_save) {
can_save);
}
#if BUILDFLAG(ENABLE_SCREEN_AI_SERVICE)
void PDFDocumentHelper::OnSearchifyStateChange(bool busy) {
client_->OnSearchifyStateChange(busy, &GetWebContents());
}
#endif
void PDFDocumentHelper::DidScroll() {
if (!touch_selection_controller_client_manager_) {
InitTouchSelectionClientManager();

@ -15,6 +15,7 @@
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "pdf/mojom/pdf.mojom.h"
#include "services/screen_ai/buildflags/buildflags.h"
#include "ui/touch_selection/selection_event_type.h"
#include "ui/touch_selection/touch_selection_controller.h"
#include "ui/touch_selection/touch_selection_menu_runner.h"
@ -86,6 +87,9 @@ class PDFDocumentHelper
const gfx::PointF& right,
int32_t right_height) override;
void SetPluginCanSave(bool can_save) override;
#if BUILDFLAG(ENABLE_SCREEN_AI_SERVICE)
void OnSearchifyStateChange(bool busy) override;
#endif
void GetPdfBytes(uint32_t size_limit,
pdf::mojom::PdfListener::GetPdfBytesCallback callback);

@ -71,6 +71,8 @@ class TestPDFDocumentHelperClient : public PDFDocumentHelperClient {
start_ = start;
end_ = end;
}
void OnSearchifyStateChange(bool busy,
content::WebContents* contents) override {}
private:
// The last bounds reported by PDFDocumentHelper.

@ -35,6 +35,10 @@ class PDFDocumentHelperClient {
// Lets the client observe scroll events. Only used for testing.
virtual void OnDidScroll(const gfx::SelectionBound& start,
const gfx::SelectionBound& end) {}
// See the comment for `OnSearchifyStateChange` in pdf/pdf.mojom.
virtual void OnSearchifyStateChange(bool busy,
content::WebContents* contents) = 0;
};
} // namespace pdf

@ -405,6 +405,7 @@ if (enable_pdf) {
"//cc:test_support",
"//pdf/loader",
"//printing",
"//services/screen_ai/buildflags",
"//testing/gmock",
"//testing/gtest",
"//third_party/blink/public:blink",

@ -4,6 +4,7 @@
import("//build/config/features.gni")
import("//mojo/public/tools/bindings/mojom.gni")
import("//services/screen_ai/buildflags/features.gni")
mojom("mojom") {
sources = [ "pdf.mojom" ]
@ -15,4 +16,8 @@ mojom("mojom") {
]
cpp_only = true
if (enable_screen_ai_service) {
enabled_features = [ "enable_screen_ai_service" ]
}
}

@ -55,4 +55,11 @@ interface PdfHost {
// Notifies the embedder know the plugin can handle save commands internally.
SetPluginCanSave(bool can_save);
// Notifies that PDF searchifier has switched between busy or not busy.
// A busy state is when it has some queued pages to process or is processing a
// page at the moment. It comes out of this state either when all tasks are
// completed or canceled.
[EnableIf=enable_screen_ai_service]
OnSearchifyStateChange(bool busy);
};

@ -1338,6 +1338,12 @@ bool PdfViewWebPlugin::IsInAnnotationMode() const {
}
#endif // BUILDFLAG(ENABLE_PDF_INK2)
#if BUILDFLAG(ENABLE_SCREEN_AI_SERVICE)
void PdfViewWebPlugin::OnSearchifyStateChange(bool busy) {
pdf_host_->OnSearchifyStateChange(busy);
}
#endif
void PdfViewWebPlugin::SetCaretPosition(const gfx::PointF& position) {
engine_->SetCaretPosition(FrameToPdfCoordinates(position));
}

@ -389,6 +389,9 @@ class PdfViewWebPlugin final : public PDFiumEngineClient,
#if BUILDFLAG(ENABLE_PDF_INK2)
bool IsInAnnotationMode() const override;
#endif // BUILDFLAG(ENABLE_PDF_INK2)
#if BUILDFLAG(ENABLE_SCREEN_AI_SERVICE)
void OnSearchifyStateChange(bool busy) override;
#endif
// pdf::mojom::PdfListener:
void SetCaretPosition(const gfx::PointF& position) override;

@ -353,6 +353,9 @@ class FakePdfHost : public pdf::mojom::PdfHost {
(const gfx::PointF&, int32_t, const gfx::PointF&, int32_t),
(override));
MOCK_METHOD(void, SetPluginCanSave, (bool), (override));
#if BUILDFLAG(ENABLE_SCREEN_AI_SERVICE)
MOCK_METHOD(void, OnSearchifyStateChange, (bool), (override));
#endif
};
} // namespace

@ -4265,6 +4265,10 @@ void PDFiumEngine::CancelPendingSearchify(int page_index) {
searchifier_->CancelPage(page_index);
}
}
void PDFiumEngine::OnSearchifyStateChange(bool busy) {
client_->OnSearchifyStateChange(busy);
}
#endif // BUILDFLAG(ENABLE_SCREEN_AI_SERVICE)
void PDFiumEngine::UpdateLinkUnderCursor(const std::string& target_url) {

@ -387,10 +387,13 @@ class PDFiumEngine : public DocumentLoader::Client, public IFSDK_PAUSE {
// if the page is not scheduled for searchify.
void CancelPendingSearchify(int page_index);
// See the comment for `OnSearchifyStateChange` in pdf/pdf.mojom.
void OnSearchifyStateChange(bool busy);
PDFiumOnDemandSearchifier* GetSearchifierForTesting() {
return searchifier_.get();
}
#endif
#endif // BUILDFLAG(ENABLE_SCREEN_AI_SERVICE)
void UnsupportedFeature(const std::string& feature);

@ -14,6 +14,7 @@
#include "base/functional/callback.h"
#include "pdf/buildflags.h"
#include "services/screen_ai/buildflags/buildflags.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/base/cursor/mojom/cursor_type.mojom-forward.h"
#include "ui/base/window_open_disposition.h"
@ -202,6 +203,11 @@ class PDFiumEngineClient {
// Returns true if the client is in annotation mode.
virtual bool IsInAnnotationMode() const = 0;
#endif // BUILDFLAG(ENABLE_PDF_INK2)
#if BUILDFLAG(ENABLE_SCREEN_AI_SERVICE)
// See the comment for `OnSearchifyStateChange` in pdf/pdf.mojom.
virtual void OnSearchifyStateChange(bool busy) = 0;
#endif
};
} // namespace chrome_pdf

@ -133,6 +133,9 @@ class MockTestClient : public TestClient {
#if BUILDFLAG(ENABLE_PDF_INK2)
MOCK_METHOD(bool, IsInAnnotationMode, (), (const override));
#endif // BUILDFLAG(ENABLE_PDF_INK2)
#if BUILDFLAG(ENABLE_SCREEN_AI_SERVICE)
MOCK_METHOD(void, OnSearchifyStateChange, (bool), (override));
#endif
};
} // namespace

@ -66,6 +66,7 @@ void PDFiumOnDemandSearchifier::OnOcrDisconnected() {
current_page_ = nullptr;
pages_queue_.clear();
state_ = State::kFailed;
engine_->OnSearchifyStateChange(/*busy=*/false);
return;
case State::kFailed:
@ -90,6 +91,9 @@ void PDFiumOnDemandSearchifier::SchedulePage(int page_index) {
if (IsPageScheduled(page_index)) {
return;
}
if (!current_page_ && pages_queue_.empty() && state_ == State::kIdle) {
engine_->OnSearchifyStateChange(/*busy=*/true);
}
pages_queue_.push_back(page_index);
if (state_ == State::kWaitingForResults || !perform_ocr_callback_) {
return;
@ -123,6 +127,7 @@ void PDFiumOnDemandSearchifier::SearchifyNextPage() {
if (pages_queue_.empty()) {
state_ = State::kIdle;
engine_->OnSearchifyStateChange(/*busy=*/false);
return;
}

@ -30,6 +30,25 @@ using VisualAnnotationPtr = screen_ai::mojom::VisualAnnotationPtr;
constexpr base::TimeDelta kOcrDelay = base::Milliseconds(100);
class SearchifierTestClient : public TestClient {
public:
explicit SearchifierTestClient() = default;
SearchifierTestClient(const SearchifierTestClient&) = delete;
SearchifierTestClient& operator=(const SearchifierTestClient&) = delete;
~SearchifierTestClient() override = default;
void OnSearchifyStateChange(bool busy) override {
if (busy) {
busy_state_changed_count_++;
} else {
idle_state_changed_count_++;
}
}
int busy_state_changed_count_ = 0;
int idle_state_changed_count_ = 0;
};
void WaitUntilIdle(PDFiumOnDemandSearchifier* searchifier,
base::OnceClosure callback) {
if (searchifier->IsIdleForTesting()) {
@ -130,11 +149,17 @@ class PDFiumOnDemandSearchifierTest : public PDFiumTestBase {
int performed_ocrs() const { return performed_ocrs_; }
PDFiumEngine* engine() { return engine_.get(); }
int busy_state_changed_count() const {
return client_.busy_state_changed_count_;
}
int idle_state_changed_count() const {
return client_.idle_state_changed_count_;
}
private:
base::test::ScopedFeatureList scoped_feature_list_;
std::unique_ptr<PDFiumEngine> engine_;
TestClient client_;
SearchifierTestClient client_;
int performed_ocrs_ = 0;
};
@ -372,6 +397,60 @@ TEST_P(PDFiumOnDemandSearchifierTest, OcrCancellation) {
ASSERT_LT(performed_ocrs(), kPageCount);
}
TEST_P(PDFiumOnDemandSearchifierTest, SearchifyStateChanges) {
CreateEngine(FILE_PATH_LITERAL("multi_page_no_text.pdf"));
// Trigger one page load.
GetPDFiumPageForTest(*engine(), 0).GetPage();
EXPECT_EQ(busy_state_changed_count(), 1);
EXPECT_EQ(idle_state_changed_count(), 0);
StartSearchify(/*empty_results=*/false);
EXPECT_EQ(busy_state_changed_count(), 1);
EXPECT_EQ(idle_state_changed_count(), 0);
// Wait for searchifier to process all pending tasks.
{
base::test::TestFuture<void> future;
WaitUntilIdle(engine()->GetSearchifierForTesting(), future.GetCallback());
ASSERT_TRUE(future.Wait());
}
EXPECT_EQ(busy_state_changed_count(), 1);
EXPECT_EQ(idle_state_changed_count(), 1);
// Trigger more page loads.
GetPDFiumPageForTest(*engine(), 1).GetPage();
GetPDFiumPageForTest(*engine(), 2).GetPage();
EXPECT_EQ(busy_state_changed_count(), 2);
EXPECT_EQ(idle_state_changed_count(), 1);
// Wait for searchifier to process all pending tasks.
{
base::test::TestFuture<void> future;
WaitUntilIdle(engine()->GetSearchifierForTesting(), future.GetCallback());
ASSERT_TRUE(future.Wait());
}
EXPECT_EQ(busy_state_changed_count(), 2);
EXPECT_EQ(idle_state_changed_count(), 2);
// Trigger more page loads.
GetPDFiumPageForTest(*engine(), 3).GetPage();
EXPECT_EQ(busy_state_changed_count(), 3);
EXPECT_EQ(idle_state_changed_count(), 2);
// Disconnect OCR before searchifier processes the pending task.
engine()->GetOcrDisconnectHandler().Run();
EXPECT_EQ(busy_state_changed_count(), 3);
EXPECT_EQ(idle_state_changed_count(), 3);
}
INSTANTIATE_TEST_SUITE_P(All, PDFiumOnDemandSearchifierTest, testing::Bool());
} // namespace chrome_pdf

@ -178,4 +178,8 @@ bool PreviewModeClient::IsInAnnotationMode() const {
}
#endif // BUILDFLAG(ENABLE_PDF_INK2)
#if BUILDFLAG(ENABLE_SCREEN_AI_SERVICE)
void PreviewModeClient::OnSearchifyStateChange(bool busy) {}
#endif
} // namespace chrome_pdf

@ -14,6 +14,7 @@
#include "base/memory/raw_ptr.h"
#include "pdf/buildflags.h"
#include "pdf/pdfium/pdfium_engine_client.h"
#include "services/screen_ai/buildflags/buildflags.h"
namespace chrome_pdf {
@ -77,6 +78,9 @@ class PreviewModeClient : public PDFiumEngineClient {
#if BUILDFLAG(ENABLE_PDF_INK2)
bool IsInAnnotationMode() const override;
#endif // BUILDFLAG(ENABLE_PDF_INK2)
#if BUILDFLAG(ENABLE_SCREEN_AI_SERVICE)
void OnSearchifyStateChange(bool busy) override;
#endif
private:
const raw_ptr<Client> client_;

@ -78,4 +78,8 @@ bool TestClient::IsInAnnotationMode() const {
}
#endif // BUILDFLAG(ENABLE_PDF_INK2)
#if BUILDFLAG(ENABLE_SCREEN_AI_SERVICE)
void TestClient::OnSearchifyStateChange(bool busy) {}
#endif
} // namespace chrome_pdf

@ -11,6 +11,7 @@
#include "base/memory/raw_ptr.h"
#include "pdf/buildflags.h"
#include "pdf/pdfium/pdfium_engine_client.h"
#include "services/screen_ai/buildflags/buildflags.h"
namespace chrome_pdf {
@ -47,6 +48,9 @@ class TestClient : public PDFiumEngineClient {
#if BUILDFLAG(ENABLE_PDF_INK2)
bool IsInAnnotationMode() const override;
#endif // BUILDFLAG(ENABLE_PDF_INK2)
#if BUILDFLAG(ENABLE_SCREEN_AI_SERVICE)
void OnSearchifyStateChange(bool busy) override;
#endif
private:
// Not owned. Expected to dangle briefly, as the engine usually is destroyed