1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "components/pdf/renderer/pdf_ax_action_target.h"
6 
7 #include "components/pdf/renderer/pdf_accessibility_tree.h"
8 #include "ui/accessibility/ax_enums.mojom.h"
9 
10 namespace pdf {
11 
12 namespace {
13 
ConvertAXScrollToPdfScrollAlignment(ax::mojom::ScrollAlignment scroll_alignment)14 PP_PdfAccessibilityScrollAlignment ConvertAXScrollToPdfScrollAlignment(
15     ax::mojom::ScrollAlignment scroll_alignment) {
16   switch (scroll_alignment) {
17     case ax::mojom::ScrollAlignment::kScrollAlignmentCenter:
18       return PP_PdfAccessibilityScrollAlignment::PP_PDF_SCROLL_ALIGNMENT_CENTER;
19     case ax::mojom::ScrollAlignment::kScrollAlignmentTop:
20       return PP_PdfAccessibilityScrollAlignment::PP_PDF_SCROLL_ALIGNMENT_TOP;
21     case ax::mojom::ScrollAlignment::kScrollAlignmentBottom:
22       return PP_PdfAccessibilityScrollAlignment::PP_PDF_SCROLL_ALIGNMENT_BOTTOM;
23     case ax::mojom::ScrollAlignment::kScrollAlignmentLeft:
24       return PP_PdfAccessibilityScrollAlignment::PP_PDF_SCROLL_ALIGNMENT_LEFT;
25     case ax::mojom::ScrollAlignment::kScrollAlignmentRight:
26       return PP_PdfAccessibilityScrollAlignment::PP_PDF_SCROLL_ALIGNMENT_RIGHT;
27     case ax::mojom::ScrollAlignment::kScrollAlignmentClosestEdge:
28       return PP_PdfAccessibilityScrollAlignment::
29           PP_PDF_SCROLL_ALIGNMENT_CLOSEST_EDGE;
30     case ax::mojom::ScrollAlignment::kNone:
31     default:
32       return PP_PdfAccessibilityScrollAlignment::PP_PDF_SCROLL_NONE;
33   }
34 }
35 
36 }  // namespace
37 
38 // static
FromAXActionTarget(const ui::AXActionTarget * ax_action_target)39 const PdfAXActionTarget* PdfAXActionTarget::FromAXActionTarget(
40     const ui::AXActionTarget* ax_action_target) {
41   if (ax_action_target &&
42       ax_action_target->GetType() == ui::AXActionTarget::Type::kPdf) {
43     return static_cast<const PdfAXActionTarget*>(ax_action_target);
44   }
45 
46   return nullptr;
47 }
48 
PdfAXActionTarget(const ui::AXNode & plugin_node,PdfAccessibilityTree * pdf_tree_source)49 PdfAXActionTarget::PdfAXActionTarget(const ui::AXNode& plugin_node,
50                                      PdfAccessibilityTree* pdf_tree_source)
51     : target_plugin_node_(plugin_node),
52       pdf_accessibility_tree_source_(pdf_tree_source) {
53   DCHECK(pdf_accessibility_tree_source_);
54 }
55 
56 PdfAXActionTarget::~PdfAXActionTarget() = default;
57 
GetType() const58 ui::AXActionTarget::Type PdfAXActionTarget::GetType() const {
59   return ui::AXActionTarget::Type::kPdf;
60 }
61 
ClearAccessibilityFocus() const62 bool PdfAXActionTarget::ClearAccessibilityFocus() const {
63   return false;
64 }
65 
Click() const66 bool PdfAXActionTarget::Click() const {
67   PP_PdfAccessibilityActionData pdf_action_data = {};
68 
69   if (target_plugin_node_.data().role != ax::mojom::Role::kLink)
70     return false;
71 
72   base::Optional<PdfAccessibilityTree::AnnotationInfo> annotation_info_result =
73       pdf_accessibility_tree_source_->GetPdfAnnotationInfoFromAXNode(
74           target_plugin_node_.data().id);
75   if (!annotation_info_result.has_value())
76     return false;
77 
78   const auto& annotation_info = annotation_info_result.value();
79   pdf_action_data.page_index = annotation_info.page_index;
80   pdf_action_data.annotation_index = annotation_info.annotation_index;
81   pdf_action_data.annotation_type =
82       PP_PdfAccessibilityAnnotationType::PP_PDF_LINK;
83   pdf_action_data.action = PP_PdfAccessibilityAction::PP_PDF_DO_DEFAULT_ACTION;
84   pdf_accessibility_tree_source_->HandleAction(pdf_action_data);
85   return true;
86 }
87 
Decrement() const88 bool PdfAXActionTarget::Decrement() const {
89   return false;
90 }
91 
Increment() const92 bool PdfAXActionTarget::Increment() const {
93   return false;
94 }
95 
Focus() const96 bool PdfAXActionTarget::Focus() const {
97   return false;
98 }
99 
GetRelativeBounds() const100 gfx::Rect PdfAXActionTarget::GetRelativeBounds() const {
101   return gfx::Rect();
102 }
103 
GetScrollOffset() const104 gfx::Point PdfAXActionTarget::GetScrollOffset() const {
105   return gfx::Point();
106 }
107 
MinimumScrollOffset() const108 gfx::Point PdfAXActionTarget::MinimumScrollOffset() const {
109   return gfx::Point();
110 }
111 
MaximumScrollOffset() const112 gfx::Point PdfAXActionTarget::MaximumScrollOffset() const {
113   return gfx::Point();
114 }
115 
SetAccessibilityFocus() const116 bool PdfAXActionTarget::SetAccessibilityFocus() const {
117   return false;
118 }
119 
SetScrollOffset(const gfx::Point & point) const120 void PdfAXActionTarget::SetScrollOffset(const gfx::Point& point) const {}
121 
SetSelected(bool selected) const122 bool PdfAXActionTarget::SetSelected(bool selected) const {
123   return false;
124 }
125 
SetSelection(const ui::AXActionTarget * anchor_object,int anchor_offset,const ui::AXActionTarget * focus_object,int focus_offset) const126 bool PdfAXActionTarget::SetSelection(const ui::AXActionTarget* anchor_object,
127                                      int anchor_offset,
128                                      const ui::AXActionTarget* focus_object,
129                                      int focus_offset) const {
130   const PdfAXActionTarget* pdf_anchor_object =
131       FromAXActionTarget(anchor_object);
132   const PdfAXActionTarget* pdf_focus_object = FromAXActionTarget(focus_object);
133   if (!pdf_anchor_object || !pdf_focus_object || anchor_offset < 0 ||
134       focus_offset < 0) {
135     return false;
136   }
137   PP_PdfAccessibilityActionData pdf_action_data = {};
138   if (!pdf_accessibility_tree_source_->FindCharacterOffset(
139           pdf_anchor_object->AXNode(), anchor_offset,
140           &pdf_action_data.selection_start_index) ||
141       !pdf_accessibility_tree_source_->FindCharacterOffset(
142           pdf_focus_object->AXNode(), focus_offset,
143           &pdf_action_data.selection_end_index)) {
144     return false;
145   }
146   pdf_action_data.action = PP_PdfAccessibilityAction::PP_PDF_SET_SELECTION;
147   pdf_accessibility_tree_source_->HandleAction(pdf_action_data);
148   return true;
149 }
150 
SetSequentialFocusNavigationStartingPoint() const151 bool PdfAXActionTarget::SetSequentialFocusNavigationStartingPoint() const {
152   return false;
153 }
154 
SetValue(const std::string & value) const155 bool PdfAXActionTarget::SetValue(const std::string& value) const {
156   return false;
157 }
158 
ShowContextMenu() const159 bool PdfAXActionTarget::ShowContextMenu() const {
160   return pdf_accessibility_tree_source_->ShowContextMenu();
161 }
162 
ScrollToMakeVisible() const163 bool PdfAXActionTarget::ScrollToMakeVisible() const {
164   return false;
165 }
166 
ScrollToMakeVisibleWithSubFocus(const gfx::Rect & rect,ax::mojom::ScrollAlignment horizontal_scroll_alignment,ax::mojom::ScrollAlignment vertical_scroll_alignment,ax::mojom::ScrollBehavior scroll_behavior) const167 bool PdfAXActionTarget::ScrollToMakeVisibleWithSubFocus(
168     const gfx::Rect& rect,
169     ax::mojom::ScrollAlignment horizontal_scroll_alignment,
170     ax::mojom::ScrollAlignment vertical_scroll_alignment,
171     ax::mojom::ScrollBehavior scroll_behavior) const {
172   PP_PdfAccessibilityActionData pdf_action_data = {};
173   pdf_action_data.action =
174       PP_PdfAccessibilityAction::PP_PDF_SCROLL_TO_MAKE_VISIBLE;
175   pdf_action_data.horizontal_scroll_alignment =
176       ConvertAXScrollToPdfScrollAlignment(horizontal_scroll_alignment);
177   pdf_action_data.vertical_scroll_alignment =
178       ConvertAXScrollToPdfScrollAlignment(vertical_scroll_alignment);
179   pdf_action_data.target_rect = {
180       {target_plugin_node_.data().relative_bounds.bounds.x(),
181        target_plugin_node_.data().relative_bounds.bounds.y()},
182       {target_plugin_node_.data().relative_bounds.bounds.width(),
183        target_plugin_node_.data().relative_bounds.bounds.height()}};
184   pdf_accessibility_tree_source_->HandleAction(pdf_action_data);
185   return true;
186 }
187 
ScrollToGlobalPoint(const gfx::Point & point) const188 bool PdfAXActionTarget::ScrollToGlobalPoint(const gfx::Point& point) const {
189   PP_PdfAccessibilityActionData pdf_action_data = {};
190   pdf_action_data.action =
191       PP_PdfAccessibilityAction::PP_PDF_SCROLL_TO_GLOBAL_POINT;
192   pdf_action_data.target_point = {point.x(), point.y()};
193   pdf_action_data.target_rect = {
194       {target_plugin_node_.data().relative_bounds.bounds.x(),
195        target_plugin_node_.data().relative_bounds.bounds.y()},
196       {target_plugin_node_.data().relative_bounds.bounds.width(),
197        target_plugin_node_.data().relative_bounds.bounds.height()}};
198   pdf_accessibility_tree_source_->HandleAction(pdf_action_data);
199   return true;
200 }
201 
202 }  // namespace pdf
203