1 // Copyright 2016 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 #ifndef COMPONENTS_PDF_RENDERER_PDF_ACCESSIBILITY_TREE_H_
6 #define COMPONENTS_PDF_RENDERER_PDF_ACCESSIBILITY_TREE_H_
7 
8 #include <map>
9 #include <memory>
10 #include <string>
11 #include <vector>
12 
13 #include "base/optional.h"
14 #include "content/public/renderer/plugin_ax_tree_source.h"
15 #include "ppapi/c/pp_instance.h"
16 #include "ppapi/c/private/ppb_pdf.h"
17 #include "ppapi/c/private/ppp_pdf.h"
18 #include "ppapi/shared_impl/pdf_accessibility_shared.h"
19 #include "ui/accessibility/ax_node.h"
20 #include "ui/accessibility/ax_tree.h"
21 #include "ui/accessibility/ax_tree_source.h"
22 #include "ui/gfx/geometry/rect_f.h"
23 #include "ui/gfx/geometry/vector2d_f.h"
24 
25 namespace content {
26 class RenderAccessibility;
27 class RendererPpapiHost;
28 }
29 
30 namespace gfx {
31 class Transform;
32 }
33 
34 namespace pdf {
35 
36 class PdfAccessibilityTree : public content::PluginAXTreeSource {
37  public:
38   PdfAccessibilityTree(content::RendererPpapiHost* host,
39                        PP_Instance instance);
40   ~PdfAccessibilityTree() override;
41 
42   static bool IsDataFromPluginValid(
43       const std::vector<ppapi::PdfAccessibilityTextRunInfo>& text_runs,
44       const std::vector<PP_PrivateAccessibilityCharInfo>& chars,
45       const ppapi::PdfAccessibilityPageObjects& page_objects);
46 
47   // Stores the page index and annotation index in the page.
48   struct AnnotationInfo {
49     AnnotationInfo(uint32_t page_index, uint32_t annotation_index);
50     AnnotationInfo(const AnnotationInfo& other);
51     ~AnnotationInfo();
52 
53     uint32_t page_index;
54     uint32_t annotation_index;
55   };
56 
57   void SetAccessibilityViewportInfo(
58       const PP_PrivateAccessibilityViewportInfo& viewport_info);
59   void SetAccessibilityDocInfo(
60       const PP_PrivateAccessibilityDocInfo& doc_info);
61   void SetAccessibilityPageInfo(
62       const PP_PrivateAccessibilityPageInfo& page_info,
63       const std::vector<ppapi::PdfAccessibilityTextRunInfo>& text_runs,
64       const std::vector<PP_PrivateAccessibilityCharInfo>& chars,
65       const ppapi::PdfAccessibilityPageObjects& page_objects);
66   void HandleAction(const PP_PdfAccessibilityActionData& action_data);
67   base::Optional<AnnotationInfo> GetPdfAnnotationInfoFromAXNode(
68       int32_t ax_node_id) const;
69 
70   // Given the AXNode and the character offset within the AXNode, finds the
71   // respective page index and character index within the page. Returns
72   // false if the |node| is not a valid static text or inline text box
73   // AXNode. Used to find the character offsets of selection.
74   bool FindCharacterOffset(const ui::AXNode& node,
75                            uint32_t char_offset_in_node,
76                            PP_PdfPageCharacterIndex* page_char_index) const;
77 
78   // PluginAXTreeSource implementation.
79   bool GetTreeData(ui::AXTreeData* tree_data) const override;
80   ui::AXNode* GetRoot() const override;
81   ui::AXNode* GetFromId(int32_t id) const override;
82   int32_t GetId(const ui::AXNode* node) const override;
83   void GetChildren(const ui::AXNode* node,
84                    std::vector<const ui::AXNode*>* out_children) const override;
85   ui::AXNode* GetParent(const ui::AXNode* node) const override;
86   bool IsIgnored(const ui::AXNode* node) const override;
87   bool IsValid(const ui::AXNode* node) const override;
88   bool IsEqual(const ui::AXNode* node1, const ui::AXNode* node2) const override;
89   const ui::AXNode* GetNull() const override;
90   void SerializeNode(const ui::AXNode* node, ui::AXNodeData* out_data)
91       const override;
92   std::unique_ptr<ui::AXActionTarget> CreateActionTarget(
93       const ui::AXNode& target_node) override;
94 
95  private:
96   // Update the AXTreeData when the selected range changed.
97   void UpdateAXTreeDataFromSelection();
98 
99   // Given a 0-based page index and 0-based character index within a page,
100   // find the node ID of the associated static text AXNode, and the character
101   // index within that text node. Used to find the start and end of the
102   // selected text range.
103   void FindNodeOffset(uint32_t page_index,
104                       uint32_t page_char_index,
105                       int32_t* out_node_id,
106                       int32_t* out_node_char_index) const;
107 
108   // Called after the data for all pages in the PDF have been received.
109   // Finishes assembling a complete accessibility tree and grafts it
110   // onto the host tree.
111   void Finish();
112 
113   void AddPageContent(
114       ui::AXNodeData* page_node,
115       const gfx::RectF& page_bounds,
116       uint32_t page_index,
117       const std::vector<ppapi::PdfAccessibilityTextRunInfo>& text_runs,
118       const std::vector<PP_PrivateAccessibilityCharInfo>& chars,
119       const ppapi::PdfAccessibilityPageObjects& page_objects);
120   void AddRemainingAnnotations(
121       ui::AXNodeData* page_node,
122       const gfx::RectF& page_bounds,
123       uint32_t page_index,
124       base::span<const ppapi::PdfAccessibilityLinkInfo> links,
125       base::span<const ppapi::PdfAccessibilityImageInfo> images,
126       base::span<const ppapi::PdfAccessibilityTextFieldInfo> text_fields,
127       ui::AXNodeData* para_node);
128 
129   ui::AXNodeData* CreateNode(ax::mojom::Role role,
130                              ax::mojom::Restriction restriction);
131   ui::AXNodeData* CreateParagraphNode(float font_size,
132                                       float heading_font_size_threshold);
133   ui::AXNodeData* CreateStaticTextNode(
134       const PP_PdfPageCharacterIndex& page_char_index);
135   ui::AXNodeData* CreateInlineTextBoxNode(
136       const ppapi::PdfAccessibilityTextRunInfo& text_run,
137       const std::vector<PP_PrivateAccessibilityCharInfo>& chars,
138       const PP_PdfPageCharacterIndex& page_char_index,
139       const gfx::RectF& page_bounds);
140   ui::AXNodeData* CreateLinkNode(const ppapi::PdfAccessibilityLinkInfo& link,
141                                  uint32_t page_index);
142   ui::AXNodeData* CreateImageNode(
143       const ppapi::PdfAccessibilityImageInfo& image);
144   ui::AXNodeData* CreateHighlightNode(
145       const ppapi::PdfAccessibilityHighlightInfo& highlight);
146   ui::AXNodeData* CreateTextFieldNode(
147       const ppapi::PdfAccessibilityTextFieldInfo& text_field);
148   void AddTextToAXNode(
149       uint32_t start_text_run_index,
150       uint32_t end_text_run_index,
151       const std::vector<ppapi::PdfAccessibilityTextRunInfo>& text_runs,
152       const std::vector<PP_PrivateAccessibilityCharInfo>& chars,
153       const gfx::RectF& page_bounds,
154       uint32_t page_index,
155       const std::vector<uint32_t>& text_run_start_indices,
156       ui::AXNodeData* ax_node,
157       ui::AXNodeData** previous_on_line_node);
158   content::RenderAccessibility* GetRenderAccessibility();
159   std::unique_ptr<gfx::Transform> MakeTransformFromViewInfo() const;
160   void AddWordStartsAndEnds(ui::AXNodeData* inline_text_box);
161 
162   ui::AXTreeData tree_data_;
163   ui::AXTree tree_;
164 
165   // Unowned. Must outlive |this|.
166   content::RendererPpapiHost* const host_;
167 
168   const PP_Instance instance_;
169   // |zoom_| signifies the zoom level set in for the browser content.
170   // |scale_| signifies the scale level set by user. Scale is applied
171   // by the OS while zoom is applied by the application. Higher scale
172   // values are usually set to increase the size of everything on screen.
173   // Preferred by people with blurry/low vision. |zoom_| and |scale_|
174   // both help us increase/descrease the size of content on screen.
175   // From PDF plugin we receive all the data in logical pixels. Which is
176   // without the zoom and scale factor applied. We apply the |zoom_| and
177   // |scale_| to generate the final bounding boxes of elements in accessibility
178   // tree.
179   double zoom_ = 1.0;
180   double scale_ = 1.0;
181   gfx::Vector2dF scroll_;
182   gfx::Vector2dF offset_;
183   uint32_t selection_start_page_index_ = 0;
184   uint32_t selection_start_char_index_ = 0;
185   uint32_t selection_end_page_index_ = 0;
186   uint32_t selection_end_char_index_ = 0;
187   PP_PrivateAccessibilityDocInfo doc_info_;
188   ui::AXNodeData* doc_node_;
189   std::vector<std::unique_ptr<ui::AXNodeData>> nodes_;
190 
191   // Map from the id of each static text AXNode and inline text box
192   // AXNode to the page index and index of the character within its
193   // page. Used to find the node associated with the start or end of
194   // a selection and vice-versa.
195   std::map<int32_t, PP_PdfPageCharacterIndex> node_id_to_page_char_index_;
196 
197   // Map between AXNode id to annotation object. Used to find the annotation
198   // object to which an action can be passed.
199   std::map<int32_t, AnnotationInfo> node_id_to_annotation_info_;
200   bool invalid_plugin_message_received_ = false;
201 };
202 
203 }  // namespace pdf
204 
205 #endif  // COMPONENTS_PDF_RENDERER_PDF_ACCESSIBILITY_TREE_H_
206