#include <stddef.h>
#include <map>
#include <set>
#include <string>
#include <string_view>
#include <tuple>
#include <variant>
#include <vector>
#include "base/containers/contains.h"
#include "base/containers/flat_set.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/strings/strcat.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/single_thread_task_runner.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/test_future.h"
#include "base/test/with_feature_override.h"
#include "base/threading/thread_restrictions.h"
#include "build/branding_buildflags.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/accessibility/accessibility_state_utils.h"
#include "chrome/browser/pdf/pdf_extension_test_base.h"
#include "chrome/browser/pdf/pdf_extension_test_util.h"
#include "chrome/browser/renderer_context_menu/render_view_context_menu_browsertest_util.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/metrics/content/subprocess_metrics_provider.h"
#include "components/prefs/pref_service.h"
#include "components/ukm/test_ukm_recorder.h"
#include "components/zoom/zoom_controller.h"
#include "content/public/browser/ax_inspect_factory.h"
#include "content/public/browser/browser_accessibility_state.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/accessibility_notification_waiter.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/context_menu_interceptor.h"
#include "content/public/test/scoped_accessibility_mode_override.h"
#include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "pdf/pdf_features.h"
#include "services/metrics/public/cpp/ukm_builders.h"
#include "services/screen_ai/buildflags/buildflags.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/context_menu_data/untrustworthy_context_menu_params.h"
#include "ui/accessibility/accessibility_features.h"
#include "ui/accessibility/accessibility_switches.h"
#include "ui/accessibility/ax_action_data.h"
#include "ui/accessibility/ax_enum_util.h"
#include "ui/accessibility/ax_features.mojom-features.h"
#include "ui/accessibility/ax_mode.h"
#include "ui/accessibility/ax_node.h"
#include "ui/accessibility/ax_tree.h"
#include "ui/accessibility/ax_tree_id.h"
#include "ui/accessibility/platform/ax_platform_node_delegate.h"
#include "ui/accessibility/platform/inspect/ax_api_type.h"
#include "ui/accessibility/platform/inspect/ax_inspect_scenario.h"
#include "ui/accessibility/platform/inspect/ax_inspect_test_helper.h"
#include "url/gurl.h"
#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "chrome/browser/ash/accessibility/accessibility_manager.h"
#endif
#if BUILDFLAG(ENABLE_SCREEN_AI_BROWSERTESTS) && !BUILDFLAG(USE_FAKE_SCREEN_AI)
#define PDF_OCR_INTEGRATION_TEST_ENABLED
#endif
#if defined(PDF_OCR_INTEGRATION_TEST_ENABLED)
#include "base/scoped_observation.h"
#include "chrome/browser/screen_ai/screen_ai_install_state.h"
#include "chrome/browser/screen_ai/screen_ai_service_router.h"
#include "chrome/browser/screen_ai/screen_ai_service_router_factory.h"
#include "components/strings/grit/components_strings.h"
#include "services/screen_ai/public/cpp/utilities.h"
#include "ui/base/l10n/l10n_util.h"
#endif
namespace {
WebContents;
MimeHandlerViewGuest;
std::string DumpPdfAccessibilityTree(const ui::AXTreeUpdate& ax_tree,
bool skip_status_subtree) { … }
constexpr char kExpectedPDFAXTree[] = …;
}
#define ASSERT_MULTILINE_STREQ(expected, actual) …
class PDFExtensionAccessibilityTest : public PDFExtensionTestBase { … };
class PDFExtensionAccessibilityTestWithOopifOverride
: public base::test::WithFeatureOverride,
public PDFExtensionAccessibilityTest { … };
#if BUILDFLAG(IS_MAC)
#define MAYBE_PdfAccessibility …
#else
#define MAYBE_PdfAccessibility …
#endif
IN_PROC_BROWSER_TEST_P(PDFExtensionAccessibilityTestWithOopifOverride,
MAYBE_PdfAccessibility) { … }
#if BUILDFLAG(IS_MAC)
#define MAYBE_PdfAccessibilityEnableLater …
#else
#define MAYBE_PdfAccessibilityEnableLater …
#endif
IN_PROC_BROWSER_TEST_P(PDFExtensionAccessibilityTestWithOopifOverride,
MAYBE_PdfAccessibilityEnableLater) { … }
IN_PROC_BROWSER_TEST_P(PDFExtensionAccessibilityTestWithOopifOverride,
PdfAccessibilityInIframe) { … }
IN_PROC_BROWSER_TEST_P(PDFExtensionAccessibilityTestWithOopifOverride,
PdfAccessibilityInOOPIF) { … }
#if (BUILDFLAG(IS_CHROMEOS) && defined(MEMORY_SANITIZER)) || BUILDFLAG(IS_MAC)
#define MAYBE_PdfAccessibilityWordBoundaries …
#else
#define MAYBE_PdfAccessibilityWordBoundaries …
#endif
IN_PROC_BROWSER_TEST_P(PDFExtensionAccessibilityTestWithOopifOverride,
MAYBE_PdfAccessibilityWordBoundaries) { … }
IN_PROC_BROWSER_TEST_P(PDFExtensionAccessibilityTestWithOopifOverride,
PdfAccessibilitySelection) { … }
#if BUILDFLAG(IS_WIN)
#define MAYBE_PdfAccessibilityContextMenuAction …
#else
#define MAYBE_PdfAccessibilityContextMenuAction …
#endif
IN_PROC_BROWSER_TEST_P(PDFExtensionAccessibilityTestWithOopifOverride,
MAYBE_PdfAccessibilityContextMenuAction) { … }
IN_PROC_BROWSER_TEST_P(PDFExtensionAccessibilityTestWithOopifOverride,
RecordHasAccessibleTextToUmaWithAccessiblePdf) { … }
IN_PROC_BROWSER_TEST_P(PDFExtensionAccessibilityTestWithOopifOverride,
RecordInaccessiblePdfUKM) { … }
IN_PROC_BROWSER_TEST_P(PDFExtensionAccessibilityTestWithOopifOverride,
RecordHasAccessibleTextToUmaWithInaccessible) { … }
#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
IN_PROC_BROWSER_TEST_P(PDFExtensionAccessibilityTestWithOopifOverride,
PdfAccessibilityTextRunCrash) {
content::ScopedAccessibilityModeOverride mode_override(ui::kAXModeComplete);
ASSERT_TRUE(LoadPdf(embedded_test_server()->GetURL(
"/pdf_private/accessibility_crash_2.pdf")));
WaitForAccessibilityTreeToContainNodeWithName(GetActiveWebContents(),
"Page 1");
}
#endif
class PDFExtensionAccessibilityTextExtractionTest
: public PDFExtensionAccessibilityTestWithOopifOverride { … };
IN_PROC_BROWSER_TEST_P(PDFExtensionAccessibilityTextExtractionTest,
NextOnLine) { … }
IN_PROC_BROWSER_TEST_P(PDFExtensionAccessibilityTextExtractionTest, DropCap) { … }
IN_PROC_BROWSER_TEST_P(PDFExtensionAccessibilityTextExtractionTest,
SuperscriptSubscript) { … }
IN_PROC_BROWSER_TEST_P(PDFExtensionAccessibilityTextExtractionTest,
FontChange) { … }
IN_PROC_BROWSER_TEST_P(PDFExtensionAccessibilityTextExtractionTest,
OnlyWhitespaceText) { … }
IN_PROC_BROWSER_TEST_P(PDFExtensionAccessibilityTextExtractionTest, WebLinks) { … }
IN_PROC_BROWSER_TEST_P(PDFExtensionAccessibilityTextExtractionTest,
Highlights) { … }
IN_PROC_BROWSER_TEST_P(PDFExtensionAccessibilityTextExtractionTest,
TextFields) { … }
IN_PROC_BROWSER_TEST_P(PDFExtensionAccessibilityTextExtractionTest,
ParagraphsAndHeadingUntagged) { … }
IN_PROC_BROWSER_TEST_P(PDFExtensionAccessibilityTextExtractionTest,
LinksImagesAndText) { … }
IN_PROC_BROWSER_TEST_P(PDFExtensionAccessibilityTextExtractionTest,
OverlappingAnnots) { … }
class PDFExtensionAccessibilityTreeDumpTest
: public PDFExtensionAccessibilityTest,
public ::testing::WithParamInterface<
std::tuple<ui::AXApiType::Type, bool>> { … };
const std::vector<ui::AXApiType::Type> GetAXTestValues() { … }
struct PDFExtensionAccessibilityTreeDumpTestPassToString { … };
INSTANTIATE_TEST_SUITE_P(…);
IN_PROC_BROWSER_TEST_P(PDFExtensionAccessibilityTreeDumpTest, HelloWorld) { … }
IN_PROC_BROWSER_TEST_P(PDFExtensionAccessibilityTreeDumpTest,
ParagraphsAndHeadingUntagged) { … }
IN_PROC_BROWSER_TEST_P(PDFExtensionAccessibilityTreeDumpTest, MultiPage) { … }
IN_PROC_BROWSER_TEST_P(PDFExtensionAccessibilityTreeDumpTest,
DirectionalTextRuns) { … }
IN_PROC_BROWSER_TEST_P(PDFExtensionAccessibilityTreeDumpTest, TextDirection) { … }
IN_PROC_BROWSER_TEST_P(PDFExtensionAccessibilityTreeDumpTest, WebLinks) { … }
IN_PROC_BROWSER_TEST_P(PDFExtensionAccessibilityTreeDumpTest,
OverlappingLinks) { … }
IN_PROC_BROWSER_TEST_P(PDFExtensionAccessibilityTreeDumpTest, Highlights) { … }
IN_PROC_BROWSER_TEST_P(PDFExtensionAccessibilityTreeDumpTest, TextFields) { … }
IN_PROC_BROWSER_TEST_P(PDFExtensionAccessibilityTreeDumpTest, Images) { … }
IN_PROC_BROWSER_TEST_P(PDFExtensionAccessibilityTreeDumpTest,
LinksImagesAndText) { … }
IN_PROC_BROWSER_TEST_P(PDFExtensionAccessibilityTreeDumpTest,
TextRunStyleHeuristic) { … }
IN_PROC_BROWSER_TEST_P(PDFExtensionAccessibilityTreeDumpTest, TextStyle) { … }
IN_PROC_BROWSER_TEST_P(PDFExtensionAccessibilityTreeDumpTest, XfaFields) { … }
PDFExtensionAccessibilityNavigationTest;
#if BUILDFLAG(IS_CHROMEOS)
#define MAYBE_LinkNavigation …
#else
#define MAYBE_LinkNavigation …
#endif
IN_PROC_BROWSER_TEST_P(PDFExtensionAccessibilityNavigationTest,
MAYBE_LinkNavigation) { … }
#if !BUILDFLAG(IS_CHROMEOS_LACROS)
class PdfOcrUmaTest : public PDFExtensionAccessibilityTest,
public ::testing::WithParamInterface<bool> { … };
IN_PROC_BROWSER_TEST_P(PdfOcrUmaTest, CheckOpenedWithScreenReader) { … }
#if BUILDFLAG(IS_CHROMEOS_ASH)
IN_PROC_BROWSER_TEST_P(PdfOcrUmaTest, CheckOpenedWithSelectToSpeak) {
if (UseOopif()) {
GTEST_SKIP();
}
::ash::AccessibilityManager::Get()->SetSelectToSpeakEnabled(true);
base::HistogramTester histograms;
histograms.ExpectUniqueSample(
"Accessibility.PDF.OpenedWithSelectToSpeak.PdfOcr", true,
0);
ASSERT_TRUE(LoadPdf(embedded_test_server()->GetURL("/pdf/test.pdf")));
WebContents* contents = GetActiveWebContents();
content::RenderFrameHost* extension_host =
pdf_extension_test_util::GetOnlyPdfExtensionHost(contents);
ASSERT_TRUE(extension_host);
metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
histograms.ExpectUniqueSample(
"Accessibility.PDF.OpenedWithSelectToSpeak.PdfOcr", true,
1);
}
IN_PROC_BROWSER_TEST_P(PdfOcrUmaTest,
CheckSelectToSpeakPagesOcredWithAccessiblePdf) {
if (UseOopif()) {
GTEST_SKIP();
}
::ash::AccessibilityManager::Get()->SetSelectToSpeakEnabled(true);
base::HistogramTester histograms;
histograms.ExpectTotalCount(
"Accessibility.PdfOcr.CrosSelectToSpeak.PagesOcred",
0);
ASSERT_TRUE(LoadPdf(embedded_test_server()->GetURL("/pdf/test.pdf")));
WebContents* contents = GetActiveWebContents();
content::RenderFrameHost* extension_host =
pdf_extension_test_util::GetOnlyPdfExtensionHost(contents);
ASSERT_TRUE(extension_host);
metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
histograms.ExpectTotalCount(
"Accessibility.PdfOcr.CrosSelectToSpeak.PagesOcred",
0);
}
#endif
INSTANTIATE_TEST_SUITE_P(…);
#endif
INSTANTIATE_FEATURE_OVERRIDE_TEST_SUITE(…);
INSTANTIATE_FEATURE_OVERRIDE_TEST_SUITE(…);
INSTANTIATE_FEATURE_OVERRIDE_TEST_SUITE(…);
#if defined(PDF_OCR_INTEGRATION_TEST_ENABLED)
class PdfOcrIntegrationTest
: public PDFExtensionAccessibilityTest,
public screen_ai::ScreenAIInstallState::Observer,
public ::testing::WithParamInterface<std::tuple<bool, bool, bool>> { … };
IN_PROC_BROWSER_TEST_P(PdfOcrIntegrationTest, EnsureScreenAIInitializes) { … }
IN_PROC_BROWSER_TEST_P(PdfOcrIntegrationTest, HelloWorld) { … }
IN_PROC_BROWSER_TEST_P(PdfOcrIntegrationTest, ThreePagePDF) { … }
IN_PROC_BROWSER_TEST_P(PdfOcrIntegrationTest, TestBatchingWithTwentyPagePDF) { … }
IN_PROC_BROWSER_TEST_P(PdfOcrIntegrationTest, NoOcrResultOnBlankImagePdf) { … }
INSTANTIATE_TEST_SUITE_P(…);
#endif