#include "components/pdf/renderer/pdf_accessibility_tree.h"
#include <algorithm>
#include <iterator>
#include <ranges>
#include <string>
#include <utility>
#include <vector>
#include "base/check_is_test.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/location.h"
#include "base/memory/ptr_util.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/raw_ref.h"
#include "base/metrics/histogram_functions.h"
#include "base/notreached.h"
#include "base/ranges/algorithm.h"
#include "base/task/single_thread_task_runner.h"
#include "base/time/time.h"
#include "components/pdf/renderer/pdf_accessibility_tree_builder.h"
#include "components/pdf/renderer/pdf_ax_action_target.h"
#include "components/strings/grit/components_strings.h"
#include "content/public/renderer/render_accessibility.h"
#include "content/public/renderer/render_frame.h"
#include "content/public/renderer/render_thread.h"
#include "pdf/pdf_accessibility_action_handler.h"
#include "third_party/blink/public/web/web_element.h"
#include "third_party/blink/public/web/web_local_frame.h"
#include "third_party/blink/public/web/web_plugin_container.h"
#include "ui/accessibility/accessibility_features.h"
#include "ui/accessibility/ax_action_data.h"
#include "ui/accessibility/ax_enums.mojom-shared.h"
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/ax_mode.h"
#include "ui/accessibility/ax_node_id_forward.h"
#include "ui/accessibility/ax_tree_id.h"
#include "ui/accessibility/ax_tree_update.h"
#include "ui/accessibility/null_ax_action_target.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/geometry/point_f.h"
#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gfx/geometry/transform.h"
#if BUILDFLAG(ENABLE_SCREEN_AI_SERVICE)
#include "base/containers/contains.h"
#include "services/screen_ai/public/cpp/metrics.h"
#include "ui/strings/grit/auto_image_annotation_strings.h"
#endif
namespace pdf {
ranges;
namespace {
constexpr base::TimeDelta kDelayBeforeResettingStatusNode = …;
enum class AttributeUpdateType { … };
ui::AXNode* GetStaticTextNodeFromNode(ui::AXNode* node) { … }
template <typename T>
bool CompareTextRuns(const T& a, const T& b) { … }
template <typename T>
bool CompareTextRunsWithRange(const T& a, const T& b) { … }
std::unique_ptr<ui::AXNodeData> CreateNode(ax::mojom::Role role,
ax::mojom::Restriction restriction,
ui::AXNodeID id) { … }
void UpdateStatusNodeLiveRegionAttributes(ui::AXNodeData* node,
AttributeUpdateType update_type) { … }
std::unique_ptr<ui::AXNodeData> CreateStatusNodeStaticText(
ui::AXNodeID id,
ui::AXNodeData* parent_node) { … }
std::unique_ptr<ui::AXNodeData> CreateStatusNode(ui::AXNodeID id,
ui::AXNodeData* parent_node,
bool currently_in_foreground) { … }
std::unique_ptr<ui::AXNodeData> CreateBannerNode(ui::AXNodeID id,
ui::AXNodeData* root_node) { … }
#if BUILDFLAG(ENABLE_SCREEN_AI_SERVICE)
gfx::Transform MakeTransformForImage(const gfx::RectF image_screen_size,
const gfx::SizeF image_pixel_size,
const int32_t orientation) { … }
#endif
}
PdfAccessibilityTree::PdfAccessibilityTree(
content::RenderFrame* render_frame,
chrome_pdf::PdfAccessibilityActionHandler* action_handler,
chrome_pdf::PdfAccessibilityImageFetcher* image_fetcher,
blink::WebPluginContainer* plugin_container,
bool print_preview)
: … { … }
PdfAccessibilityTree::~PdfAccessibilityTree() { … }
bool PdfAccessibilityTree::IsDataFromPluginValid(
const std::vector<chrome_pdf::AccessibilityTextRunInfo>& text_runs,
const std::vector<chrome_pdf::AccessibilityCharInfo>& chars,
const chrome_pdf::AccessibilityPageObjects& page_objects) { … }
void PdfAccessibilityTree::SetAccessibilityViewportInfo(
chrome_pdf::AccessibilityViewportInfo viewport_info) { … }
void PdfAccessibilityTree::DoSetAccessibilityViewportInfo(
const chrome_pdf::AccessibilityViewportInfo& viewport_info) { … }
void PdfAccessibilityTree::SetAccessibilityDocInfo(
chrome_pdf::AccessibilityDocInfo doc_info) { … }
void PdfAccessibilityTree::DoSetAccessibilityDocInfo(
const chrome_pdf::AccessibilityDocInfo& doc_info) { … }
void PdfAccessibilityTree::SetAccessibilityPageInfo(
chrome_pdf::AccessibilityPageInfo page_info,
std::vector<chrome_pdf::AccessibilityTextRunInfo> text_runs,
std::vector<chrome_pdf::AccessibilityCharInfo> chars,
chrome_pdf::AccessibilityPageObjects page_objects) { … }
void PdfAccessibilityTree::DoSetAccessibilityPageInfo(
const chrome_pdf::AccessibilityPageInfo& page_info,
const std::vector<chrome_pdf::AccessibilityTextRunInfo>& text_runs,
const std::vector<chrome_pdf::AccessibilityCharInfo>& chars,
const chrome_pdf::AccessibilityPageObjects& page_objects) { … }
void PdfAccessibilityTree::AddPageContent(
const chrome_pdf::AccessibilityPageInfo& page_info,
uint32_t page_index,
const std::vector<chrome_pdf::AccessibilityTextRunInfo>& text_runs,
const std::vector<chrome_pdf::AccessibilityCharInfo>& chars,
const chrome_pdf::AccessibilityPageObjects& page_objects) { … }
void PdfAccessibilityTree::UnserializeNodes() { … }
#if BUILDFLAG(ENABLE_SCREEN_AI_SERVICE)
void PdfAccessibilityTree::SetOcrCompleteStatus() { … }
#endif
void PdfAccessibilityTree::SetStatusMessage(int message_id) { … }
void PdfAccessibilityTree::ResetStatusNodeAttributes() { … }
void PdfAccessibilityTree::UpdateAXTreeDataFromSelection() { … }
void PdfAccessibilityTree::FindNodeOffset(uint32_t page_index,
uint32_t page_char_index,
int32_t* out_node_id,
int32_t* out_node_char_index) const { … }
bool PdfAccessibilityTree::FindCharacterOffset(
const ui::AXNode& node,
uint32_t char_offset_in_node,
chrome_pdf::PageCharacterIndex& page_char_index) const { … }
void PdfAccessibilityTree::ClearAccessibilityNodes() { … }
std::optional<blink::WebAXObject>
PdfAccessibilityTree::GetPluginContainerAXObject() { … }
std::unique_ptr<gfx::Transform>
PdfAccessibilityTree::MakeTransformFromViewInfo() const { … }
PdfAccessibilityTree::AnnotationInfo::AnnotationInfo(uint32_t page_index,
uint32_t annotation_index)
: … { … }
PdfAccessibilityTree::AnnotationInfo::AnnotationInfo(
const AnnotationInfo& other) = default;
PdfAccessibilityTree::AnnotationInfo::~AnnotationInfo() = default;
bool PdfAccessibilityTree::GetTreeData(ui::AXTreeData* tree_data) const { … }
ui::AXNode* PdfAccessibilityTree::GetRoot() const { … }
ui::AXNode* PdfAccessibilityTree::GetFromId(int32_t id) const { … }
int32_t PdfAccessibilityTree::GetId(const ui::AXNode* node) const { … }
size_t PdfAccessibilityTree::GetChildCount(const ui::AXNode* node) const { … }
const ui::AXNode* PdfAccessibilityTree::ChildAt(const ui::AXNode* node,
size_t index) const { … }
ui::AXNode* PdfAccessibilityTree::GetParent(const ui::AXNode* node) const { … }
bool PdfAccessibilityTree::IsIgnored(const ui::AXNode* node) const { … }
bool PdfAccessibilityTree::IsEqual(const ui::AXNode* node1,
const ui::AXNode* node2) const { … }
const ui::AXNode* PdfAccessibilityTree::GetNull() const { … }
void PdfAccessibilityTree::SerializeNode(const ui::AXNode* node,
ui::AXNodeData* out_data) const { … }
std::unique_ptr<ui::AXActionTarget> PdfAccessibilityTree::CreateActionTarget(
ui::AXNodeID id) { … }
void PdfAccessibilityTree::AccessibilityModeChanged(const ui::AXMode& mode) { … }
void PdfAccessibilityTree::OnDestruct() { … }
void PdfAccessibilityTree::WasHidden() { … }
void PdfAccessibilityTree::WasShown() { … }
#if BUILDFLAG(ENABLE_SCREEN_AI_SERVICE)
void PdfAccessibilityTree::OnOcrDataReceived(
std::vector<PdfOcrRequest> ocr_requests,
std::vector<ui::AXTreeUpdate> tree_updates) { … }
void PdfAccessibilityTree::CreateOcrHelper() { … }
#endif
bool PdfAccessibilityTree::ShowContextMenu() { … }
bool PdfAccessibilityTree::SetChildTree(const ui::AXNodeID& target_node_id,
const ui::AXTreeID& child_tree_id) { … }
void PdfAccessibilityTree::HandleAction(
const chrome_pdf::AccessibilityActionData& action_data) { … }
std::optional<PdfAccessibilityTree::AnnotationInfo>
PdfAccessibilityTree::GetPdfAnnotationInfoFromAXNode(int32_t ax_node_id) const { … }
void PdfAccessibilityTree::MaybeHandleAccessibilityChange(
bool always_load_or_reload_accessibility) { … }
void PdfAccessibilityTree::MarkPluginContainerDirty() { … }
bool PdfAccessibilityTree::UpdateDependentObjects(bool set_this) { … }
void PdfAccessibilityTree::ForcePluginAXObjectForTesting(
const blink::WebAXObject& obj) { … }
}