blob: 74486638f12bad7c29a0b0951af2c2c403b76240 [file] [log] [blame]
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <vector>
#include "base/test/bind.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/with_feature_override.h"
#include "chrome/browser/accessibility/pdf_ocr_controller.h"
#include "chrome/browser/accessibility/pdf_ocr_controller_factory.h"
#include "chrome/browser/pdf/pdf_extension_test_base.h"
#include "chrome/browser/screen_ai/screen_ai_install_state.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_commands.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/keyed_service/core/keyed_service.h"
#include "components/prefs/pref_service.h"
#include "content/public/browser/browser_accessibility_state.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_test.h"
#include "pdf/pdf_features.h"
#include "ui/accessibility/accessibility_features.h"
#if !BUILDFLAG(IS_CHROMEOS_ASH)
#include <optional>
#include "chrome/browser/browser_process.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/profiles/profile_test_util.h"
#include "content/public/test/scoped_accessibility_mode_override.h"
#else
#include "chrome/browser/ash/accessibility/accessibility_manager.h"
#endif // !BUILDFLAG(IS_CHROMEOS_ASH)
namespace {
class WebContentsLoadWaiter : public content::WebContentsObserver {
public:
// Observe `DidFinishLoad` for the specified |web_contents|.
explicit WebContentsLoadWaiter(content::WebContents* web_contents)
: content::WebContentsObserver(web_contents) {}
void DidFinishLoad(content::RenderFrameHost* render_frame_host,
const GURL& validated_url) override {
run_loop_.Quit();
}
void Wait() { run_loop_.Run(); }
private:
base::RunLoop run_loop_{base::RunLoop::Type::kNestableTasksAllowed};
};
class PrefChangeWaiter : public KeyedService {
public:
// Observe changes in prefs::kAccessibilityPdfOcrAlwaysActive.
explicit PrefChangeWaiter(Profile* profile) {
pref_change_registrar_.Init(profile->GetPrefs());
pref_change_registrar_.Add(
prefs::kAccessibilityPdfOcrAlwaysActive,
base::BindLambdaForTesting([&]() { run_loop_.Quit(); }));
}
void Wait() { run_loop_.Run(); }
private:
base::RunLoop run_loop_{base::RunLoop::Type::kNestableTasksAllowed};
PrefChangeRegistrar pref_change_registrar_;
};
#if !BUILDFLAG(IS_CHROMEOS_ASH)
Profile* CreateProfile(const base::FilePath& basename) {
ProfileManager* profile_manager = g_browser_process->profile_manager();
base::FilePath profile_path =
profile_manager->user_data_dir().Append(basename);
return &profiles::testing::CreateProfileSync(profile_manager, profile_path);
}
#endif // !BUILDFLAG(IS_CHROMEOS_ASH)
} // namespace
class PdfOcrControllerBrowserTest : public base::test::WithFeatureOverride,
public PDFExtensionTestBase {
public:
PdfOcrControllerBrowserTest()
: base::test::WithFeatureOverride(chrome_pdf::features::kPdfOopif) {}
~PdfOcrControllerBrowserTest() override = default;
PdfOcrControllerBrowserTest(const PdfOcrControllerBrowserTest&) = delete;
PdfOcrControllerBrowserTest& operator=(const PdfOcrControllerBrowserTest&) =
delete;
// PDFExtensionTestBase overrides:
void TearDownOnMainThread() override {
PDFExtensionTestBase::TearDownOnMainThread();
EnableScreenReader(false);
}
void EnableScreenReader(bool enabled) {
#if BUILDFLAG(IS_CHROMEOS_ASH)
// Enable Chromevox.
ash::AccessibilityManager::Get()->EnableSpokenFeedback(enabled);
#else
if (!enabled) {
scoped_accessibility_override_.reset();
} else if (!scoped_accessibility_override_) {
scoped_accessibility_override_.emplace(ui::AXMode::kScreenReader);
}
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
}
#if BUILDFLAG(IS_CHROMEOS_ASH)
void EnableSelectToSpeak(bool enabled) {
ash::AccessibilityManager::Get()->SetSelectToSpeakEnabled(enabled);
}
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
bool UseOopif() const override { return GetParam(); }
std::vector<base::test::FeatureRef> GetEnabledFeatures() const override {
auto enabled = PDFExtensionTestBase::GetEnabledFeatures();
enabled.push_back(features::kPdfOcr);
#if BUILDFLAG(IS_CHROMEOS)
enabled.push_back(features::kAccessibilityPdfOcrForSelectToSpeak);
#endif // BUILDFLAG(IS_CHROMEOS)
return enabled;
}
private:
#if !BUILDFLAG(IS_CHROMEOS_ASH)
std::optional<content::ScopedAccessibilityModeOverride>
scoped_accessibility_override_;
#endif
};
// TODO(crbug.com/40267312): Fix flakiness.
// Enabling PDF OCR should affect the accessibility mode of a new WebContents
// of PDF Viewer Mimehandler.
IN_PROC_BROWSER_TEST_P(PdfOcrControllerBrowserTest,
DISABLED_OpenPDFAfterTurningOnPdfOcr) {
EnableScreenReader(true);
ui::AXMode ax_mode =
content::BrowserAccessibilityState::GetInstance()->GetAccessibilityMode();
EXPECT_FALSE(ax_mode.has_mode(ui::AXMode::kPDFOcr));
PrefChangeWaiter pref_waiter(browser()->profile());
browser()->profile()->GetPrefs()->SetBoolean(
prefs::kAccessibilityPdfOcrAlwaysActive, true);
// Wait until the PDF OCR pref changes accordingly.
pref_waiter.Wait();
// Load test PDF.
content::WebContents* active_web_contents = GetActiveWebContents();
WebContentsLoadWaiter load_waiter(active_web_contents);
ASSERT_TRUE(ui_test_utils::NavigateToURL(
browser(), embedded_test_server()->GetURL("/pdf/test.pdf")));
load_waiter.Wait();
std::vector<content::WebContents*> html_web_contents_vector =
screen_ai::PdfOcrController::GetAllPdfWebContentsesForTesting(
browser()->profile());
for (auto* web_contents : html_web_contents_vector) {
ax_mode = web_contents->GetAccessibilityMode();
EXPECT_TRUE(ax_mode.has_mode(ui::AXMode::kPDFOcr));
}
}
// TODO(crbug.com/40267312): Fix flakiness.
// Enabling PDF OCR should affect the accessibility mode of an exiting
// WebContents of PDF Viewer Mimehandler.
IN_PROC_BROWSER_TEST_P(PdfOcrControllerBrowserTest,
DISABLED_OpenPDFBeforeTurningOnPdfOcr) {
EnableScreenReader(true);
ui::AXMode ax_mode =
content::BrowserAccessibilityState::GetInstance()->GetAccessibilityMode();
EXPECT_FALSE(ax_mode.has_mode(ui::AXMode::kPDFOcr));
// Load test PDF.
content::WebContents* active_web_contents = GetActiveWebContents();
WebContentsLoadWaiter load_waiter(active_web_contents);
ASSERT_TRUE(ui_test_utils::NavigateToURL(
browser(), embedded_test_server()->GetURL("/pdf/test.pdf")));
load_waiter.Wait();
std::vector<content::WebContents*> html_web_contents_vector =
screen_ai::PdfOcrController::GetAllPdfWebContentsesForTesting(
browser()->profile());
for (auto* web_contents : html_web_contents_vector) {
ax_mode = web_contents->GetAccessibilityMode();
EXPECT_FALSE(ax_mode.has_mode(ui::AXMode::kPDFOcr));
}
PrefChangeWaiter pref_waiter(browser()->profile());
browser()->profile()->GetPrefs()->SetBoolean(
prefs::kAccessibilityPdfOcrAlwaysActive, true);
// Wait until the PDF OCR pref changes accordingly.
pref_waiter.Wait();
html_web_contents_vector =
screen_ai::PdfOcrController::GetAllPdfWebContentsesForTesting(
browser()->profile());
for (auto* web_contents : html_web_contents_vector) {
ax_mode = web_contents->GetAccessibilityMode();
EXPECT_TRUE(ax_mode.has_mode(ui::AXMode::kPDFOcr));
}
}
IN_PROC_BROWSER_TEST_P(PdfOcrControllerBrowserTest,
NotEnabledWithoutScreenReader) {
EnableScreenReader(false);
screen_ai::PdfOcrControllerFactory::GetForProfile(browser()->profile())
->set_ocr_ready_for_testing();
PrefChangeWaiter pref_waiter(browser()->profile());
// Turn on PDF OCR.
browser()->profile()->GetPrefs()->SetBoolean(
prefs::kAccessibilityPdfOcrAlwaysActive, true);
// Wait until the PDF OCR pref changes accordingly.
pref_waiter.Wait();
ASSERT_TRUE(LoadPdf(embedded_test_server()->GetURL("/pdf/test.pdf")));
content::WebContents* pdf_contents = GetActiveWebContents();
ui::AXMode ax_mode = pdf_contents->GetAccessibilityMode();
EXPECT_FALSE(ax_mode.has_mode(ui::AXMode::kPDFOcr));
}
#if BUILDFLAG(IS_CHROMEOS_ASH)
IN_PROC_BROWSER_TEST_P(PdfOcrControllerBrowserTest,
NotEnabledWithoutSelectToSpeak) {
EnableSelectToSpeak(false);
screen_ai::PdfOcrControllerFactory::GetForProfile(browser()->profile())
->set_ocr_ready_for_testing();
PrefChangeWaiter pref_waiter(browser()->profile());
// Turn on PDF OCR.
browser()->profile()->GetPrefs()->SetBoolean(
prefs::kAccessibilityPdfOcrAlwaysActive, true);
// Wait until the PDF OCR pref changes accordingly.
pref_waiter.Wait();
ASSERT_TRUE(LoadPdf(embedded_test_server()->GetURL("/pdf/test.pdf")));
content::WebContents* pdf_contents = GetActiveWebContents();
ui::AXMode ax_mode = pdf_contents->GetAccessibilityMode();
EXPECT_FALSE(ax_mode.has_mode(ui::AXMode::kPDFOcr));
}
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
// Multi-profile is not supported on Ash.
#if !BUILDFLAG(IS_CHROMEOS_ASH)
// Enabling PDF OCR in one profile should not affect the accessibility mode of
// WebContents in another profile.
IN_PROC_BROWSER_TEST_P(PdfOcrControllerBrowserTest,
TurningOnPdfOcrInOneProfileNotAffectingAnotherProfile) {
EnableScreenReader(true);
ui::AXMode ax_mode =
content::BrowserAccessibilityState::GetInstance()->GetAccessibilityMode();
EXPECT_FALSE(ax_mode.has_mode(ui::AXMode::kPDFOcr));
Profile* profile1 = browser()->profile();
// Load test PDF on profile1.
ASSERT_TRUE(ui_test_utils::NavigateToURL(
browser(), embedded_test_server()->GetURL("/pdf/test.pdf")));
std::vector<content::WebContents*> html_web_contents_vector1 =
screen_ai::PdfOcrController::GetAllPdfWebContentsesForTesting(profile1);
for (auto* web_contents : html_web_contents_vector1) {
ax_mode = web_contents->GetAccessibilityMode();
EXPECT_FALSE(ax_mode.has_mode(ui::AXMode::kPDFOcr));
}
const base::FilePath kProfileDir2(FILE_PATH_LITERAL("Other"));
Profile* profile2 = CreateProfile(kProfileDir2);
// Set the PDF OCR pref for the profile2.
PrefChangeWaiter pref_waiter(profile2);
profile2->GetPrefs()->SetBoolean(prefs::kAccessibilityPdfOcrAlwaysActive,
true);
// Wait until the PDF OCR pref changes accordingly.
pref_waiter.Wait();
// Setting the PDF OCR pref for the profile2 should not affect a WebContents
// of PDF Viewer Mimehandler for the profile1.
html_web_contents_vector1 =
screen_ai::PdfOcrController::GetAllPdfWebContentsesForTesting(profile1);
for (auto* web_contents : html_web_contents_vector1) {
ax_mode = web_contents->GetAccessibilityMode();
EXPECT_FALSE(ax_mode.has_mode(ui::AXMode::kPDFOcr));
}
}
#endif // !BUILDFLAG(IS_CHROMEOS_ASH)
// TODO(crbug.com/40268279): Stop testing both modes after OOPIF PDF viewer
// launches.
INSTANTIATE_FEATURE_OVERRIDE_TEST_SUITE(PdfOcrControllerBrowserTest);