| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <algorithm> | 5 #include <algorithm> |
| 6 | 6 |
| 7 #include "base/memory/ptr_util.h" | 7 #include "base/memory/ptr_util.h" |
| 8 #include "base/strings/stringprintf.h" | 8 #include "base/strings/stringprintf.h" |
| 9 #include "base/strings/utf_string_conversion_utils.h" | 9 #include "base/strings/utf_string_conversion_utils.h" |
| 10 #include "components/pdf/renderer/pdf_accessibility_tree.h" | 10 #include "components/pdf/renderer/pdf_accessibility_tree.h" |
| 11 #include "content/public/renderer/render_accessibility.h" | 11 #include "content/public/renderer/render_accessibility.h" |
| 12 #include "content/public/renderer/render_frame.h" | 12 #include "content/public/renderer/render_frame.h" |
| 13 #include "content/public/renderer/render_view.h" | 13 #include "content/public/renderer/render_view.h" |
| 14 #include "content/public/renderer/renderer_ppapi_host.h" | 14 #include "content/public/renderer/renderer_ppapi_host.h" |
| 15 #include "grit/components_strings.h" | 15 #include "grit/components_strings.h" |
| 16 #include "ui/base/l10n/l10n_util.h" | 16 #include "ui/base/l10n/l10n_util.h" |
| 17 #include "ui/gfx/geometry/rect_conversions.h" | 17 #include "ui/gfx/geometry/rect_conversions.h" |
| 18 #include "ui/gfx/transform.h" |
| 18 | 19 |
| 19 namespace pdf { | 20 namespace pdf { |
| 20 | 21 |
| 21 namespace { | 22 namespace { |
| 22 | 23 |
| 23 // Don't try to apply font size thresholds to automatically identify headings | 24 // Don't try to apply font size thresholds to automatically identify headings |
| 24 // if the median font size is not at least this many points. | 25 // if the median font size is not at least this many points. |
| 25 const double kMinimumFontSize = 5; | 26 const double kMinimumFontSize = 5; |
| 26 | 27 |
| 27 // Don't try to apply line break thresholds to automatically identify | 28 // Don't try to apply line break thresholds to automatically identify |
| (...skipping 26 matching lines...) Expand all Loading... |
| 54 } | 55 } |
| 55 | 56 |
| 56 void PdfAccessibilityTree::SetAccessibilityViewportInfo( | 57 void PdfAccessibilityTree::SetAccessibilityViewportInfo( |
| 57 const PP_PrivateAccessibilityViewportInfo& viewport_info) { | 58 const PP_PrivateAccessibilityViewportInfo& viewport_info) { |
| 58 zoom_ = viewport_info.zoom; | 59 zoom_ = viewport_info.zoom; |
| 59 CHECK_GT(zoom_, 0); | 60 CHECK_GT(zoom_, 0); |
| 60 scroll_ = ToVector2dF(viewport_info.scroll); | 61 scroll_ = ToVector2dF(viewport_info.scroll); |
| 61 scroll_.Scale(1.0 / zoom_); | 62 scroll_.Scale(1.0 / zoom_); |
| 62 offset_ = ToVector2dF(viewport_info.offset); | 63 offset_ = ToVector2dF(viewport_info.offset); |
| 63 offset_.Scale(1.0 / zoom_); | 64 offset_.Scale(1.0 / zoom_); |
| 65 |
| 66 content::RenderAccessibility* render_accessibility = GetRenderAccessibility(); |
| 67 if (render_accessibility && tree_.size() > 1) { |
| 68 ui::AXNode* root = tree_.root(); |
| 69 ui::AXNodeData root_data = root->data(); |
| 70 root_data.transform = base::WrapUnique(MakeTransformFromViewInfo()); |
| 71 root->SetData(root_data); |
| 72 render_accessibility->OnPdfRootNodeUpdated(); |
| 73 } |
| 64 } | 74 } |
| 65 | 75 |
| 66 void PdfAccessibilityTree::SetAccessibilityDocInfo( | 76 void PdfAccessibilityTree::SetAccessibilityDocInfo( |
| 67 const PP_PrivateAccessibilityDocInfo& doc_info) { | 77 const PP_PrivateAccessibilityDocInfo& doc_info) { |
| 68 if (!GetRenderAccessibility()) | 78 if (!GetRenderAccessibility()) |
| 69 return; | 79 return; |
| 70 | 80 |
| 71 doc_info_ = doc_info; | 81 doc_info_ = doc_info; |
| 72 doc_node_ = CreateNode(ui::AX_ROLE_GROUP); | 82 doc_node_ = CreateNode(ui::AX_ROLE_GROUP); |
| 83 |
| 84 // Because all of the coordinates are expressed relative to the |
| 85 // doc's coordinates, the origin of the doc must be (0, 0). Its |
| 86 // width and height will be updated as we add each page so that the |
| 87 // doc's bounding box surrounds all pages. |
| 88 doc_node_->location = gfx::RectF(0, 0, 1, 1); |
| 73 } | 89 } |
| 74 | 90 |
| 75 void PdfAccessibilityTree::SetAccessibilityPageInfo( | 91 void PdfAccessibilityTree::SetAccessibilityPageInfo( |
| 76 const PP_PrivateAccessibilityPageInfo& page_info, | 92 const PP_PrivateAccessibilityPageInfo& page_info, |
| 77 const std::vector<PP_PrivateAccessibilityTextRunInfo>& text_runs, | 93 const std::vector<PP_PrivateAccessibilityTextRunInfo>& text_runs, |
| 78 const std::vector<PP_PrivateAccessibilityCharInfo>& chars) { | 94 const std::vector<PP_PrivateAccessibilityCharInfo>& chars) { |
| 79 content::RenderAccessibility* render_accessibility = GetRenderAccessibility(); | 95 content::RenderAccessibility* render_accessibility = GetRenderAccessibility(); |
| 80 if (!render_accessibility) | 96 if (!render_accessibility) |
| 81 return; | 97 return; |
| 82 | 98 |
| 83 uint32_t page_index = page_info.page_index; | 99 uint32_t page_index = page_info.page_index; |
| 84 CHECK_GE(page_index, 0U); | 100 CHECK_GE(page_index, 0U); |
| 85 CHECK_LT(page_index, doc_info_.page_count); | 101 CHECK_LT(page_index, doc_info_.page_count); |
| 86 | 102 |
| 87 ui::AXNodeData* page_node = CreateNode(ui::AX_ROLE_REGION); | 103 ui::AXNodeData* page_node = CreateNode(ui::AX_ROLE_REGION); |
| 88 page_node->AddStringAttribute( | 104 page_node->AddStringAttribute( |
| 89 ui::AX_ATTR_NAME, | 105 ui::AX_ATTR_NAME, |
| 90 l10n_util::GetPluralStringFUTF8( | 106 l10n_util::GetPluralStringFUTF8( |
| 91 IDS_PDF_PAGE_INDEX, page_index + 1)); | 107 IDS_PDF_PAGE_INDEX, page_index + 1)); |
| 92 | 108 |
| 93 gfx::RectF page_bounds = ToRectF(page_info.bounds); | 109 gfx::RectF page_bounds = ToRectF(page_info.bounds); |
| 94 page_bounds += offset_; | |
| 95 page_bounds -= scroll_; | |
| 96 page_bounds.Scale(zoom_ / GetDeviceScaleFactor()); | |
| 97 page_node->location = page_bounds; | 110 page_node->location = page_bounds; |
| 98 doc_node_->location.Union(page_node->location); | 111 doc_node_->location.Union(page_node->location); |
| 99 doc_node_->child_ids.push_back(page_node->id); | 112 doc_node_->child_ids.push_back(page_node->id); |
| 100 | 113 |
| 101 double heading_font_size_threshold = 0; | 114 double heading_font_size_threshold = 0; |
| 102 double line_spacing_threshold = 0; | 115 double line_spacing_threshold = 0; |
| 103 ComputeParagraphAndHeadingThresholds(text_runs, | 116 ComputeParagraphAndHeadingThresholds(text_runs, |
| 104 &heading_font_size_threshold, | 117 &heading_font_size_threshold, |
| 105 &line_spacing_threshold); | 118 &line_spacing_threshold); |
| 106 | 119 |
| (...skipping 28 matching lines...) Expand all Loading... |
| 135 para_node->child_ids.push_back(static_text_node->id); | 148 para_node->child_ids.push_back(static_text_node->id); |
| 136 } | 149 } |
| 137 | 150 |
| 138 // Add this text run to the current static text node. | 151 // Add this text run to the current static text node. |
| 139 ui::AXNodeData* inline_text_box_node = CreateNode( | 152 ui::AXNodeData* inline_text_box_node = CreateNode( |
| 140 ui::AX_ROLE_INLINE_TEXT_BOX); | 153 ui::AX_ROLE_INLINE_TEXT_BOX); |
| 141 static_text_node->child_ids.push_back(inline_text_box_node->id); | 154 static_text_node->child_ids.push_back(inline_text_box_node->id); |
| 142 | 155 |
| 143 inline_text_box_node->AddStringAttribute(ui::AX_ATTR_NAME, chars_utf8); | 156 inline_text_box_node->AddStringAttribute(ui::AX_ATTR_NAME, chars_utf8); |
| 144 gfx::RectF text_run_bounds = ToGfxRectF(text_run.bounds); | 157 gfx::RectF text_run_bounds = ToGfxRectF(text_run.bounds); |
| 145 text_run_bounds.Scale(zoom_ / GetDeviceScaleFactor()); | |
| 146 text_run_bounds += page_bounds.OffsetFromOrigin(); | 158 text_run_bounds += page_bounds.OffsetFromOrigin(); |
| 147 inline_text_box_node->location = text_run_bounds; | 159 inline_text_box_node->location = text_run_bounds; |
| 148 inline_text_box_node->AddIntListAttribute(ui::AX_ATTR_CHARACTER_OFFSETS, | 160 inline_text_box_node->AddIntListAttribute(ui::AX_ATTR_CHARACTER_OFFSETS, |
| 149 char_offsets); | 161 char_offsets); |
| 150 | 162 |
| 151 para_node->location.Union(inline_text_box_node->location); | 163 para_node->location.Union(inline_text_box_node->location); |
| 152 static_text_node->location.Union(inline_text_box_node->location); | 164 static_text_node->location.Union(inline_text_box_node->location); |
| 153 | 165 |
| 154 if (i == text_runs.size() - 1) { | 166 if (i == text_runs.size() - 1) { |
| 155 static_text_node->AddStringAttribute(ui::AX_ATTR_NAME, static_text); | 167 static_text_node->AddStringAttribute(ui::AX_ATTR_NAME, static_text); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 166 static_text_node = nullptr; | 178 static_text_node = nullptr; |
| 167 static_text.clear(); | 179 static_text.clear(); |
| 168 } | 180 } |
| 169 } | 181 } |
| 170 | 182 |
| 171 if (page_index == doc_info_.page_count - 1) | 183 if (page_index == doc_info_.page_count - 1) |
| 172 Finish(); | 184 Finish(); |
| 173 } | 185 } |
| 174 | 186 |
| 175 void PdfAccessibilityTree::Finish() { | 187 void PdfAccessibilityTree::Finish() { |
| 188 doc_node_->transform = base::WrapUnique(MakeTransformFromViewInfo()); |
| 189 |
| 176 ui::AXTreeUpdate update; | 190 ui::AXTreeUpdate update; |
| 177 update.root_id = doc_node_->id; | 191 update.root_id = doc_node_->id; |
| 178 for (const auto& node : nodes_) | 192 for (const auto& node : nodes_) |
| 179 update.nodes.push_back(*node); | 193 update.nodes.push_back(*node); |
| 180 | 194 |
| 181 CHECK(tree_.Unserialize(update)) << update.ToString() << tree_.error(); | 195 CHECK(tree_.Unserialize(update)) << update.ToString() << tree_.error(); |
| 182 content::RenderAccessibility* render_accessibility = GetRenderAccessibility(); | 196 content::RenderAccessibility* render_accessibility = GetRenderAccessibility(); |
| 183 if (render_accessibility) | 197 if (render_accessibility) |
| 184 render_accessibility->SetPdfTreeSource(this); | 198 render_accessibility->SetPdfTreeSource(this); |
| 185 } | 199 } |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 234 } | 248 } |
| 235 | 249 |
| 236 std::vector<int32_t> PdfAccessibilityTree::GetTextRunCharOffsets( | 250 std::vector<int32_t> PdfAccessibilityTree::GetTextRunCharOffsets( |
| 237 const PP_PrivateAccessibilityTextRunInfo& text_run, | 251 const PP_PrivateAccessibilityTextRunInfo& text_run, |
| 238 const std::vector<PP_PrivateAccessibilityCharInfo>& chars, | 252 const std::vector<PP_PrivateAccessibilityCharInfo>& chars, |
| 239 int char_index) { | 253 int char_index) { |
| 240 std::vector<int32_t> char_offsets(text_run.len); | 254 std::vector<int32_t> char_offsets(text_run.len); |
| 241 double offset = 0.0; | 255 double offset = 0.0; |
| 242 for (uint32_t j = 0; j < text_run.len; ++j) { | 256 for (uint32_t j = 0; j < text_run.len; ++j) { |
| 243 offset += chars[char_index + j].char_width; | 257 offset += chars[char_index + j].char_width; |
| 244 char_offsets[j] = floor(offset * zoom_ / GetDeviceScaleFactor()); | 258 char_offsets[j] = floor(offset); |
| 245 } | 259 } |
| 246 return char_offsets; | 260 return char_offsets; |
| 247 } | 261 } |
| 248 | 262 |
| 249 gfx::Vector2dF PdfAccessibilityTree::ToVector2dF(const PP_Point& p) { | 263 gfx::Vector2dF PdfAccessibilityTree::ToVector2dF(const PP_Point& p) { |
| 250 return gfx::Vector2dF(p.x, p.y); | 264 return gfx::Vector2dF(p.x, p.y); |
| 251 } | 265 } |
| 252 | 266 |
| 253 gfx::RectF PdfAccessibilityTree::ToRectF(const PP_Rect& r) { | 267 gfx::RectF PdfAccessibilityTree::ToRectF(const PP_Rect& r) { |
| 254 return gfx::RectF(r.point.x, r.point.y, r.size.width, r.size.height); | 268 return gfx::RectF(r.point.x, r.point.y, r.size.width, r.size.height); |
| 255 } | 269 } |
| 256 | 270 |
| 257 ui::AXNodeData* PdfAccessibilityTree::CreateNode(ui::AXRole role) { | 271 ui::AXNodeData* PdfAccessibilityTree::CreateNode(ui::AXRole role) { |
| 258 content::RenderAccessibility* render_accessibility = GetRenderAccessibility(); | 272 content::RenderAccessibility* render_accessibility = GetRenderAccessibility(); |
| 259 DCHECK(render_accessibility); | 273 DCHECK(render_accessibility); |
| 260 | 274 |
| 261 ui::AXNodeData* node = new ui::AXNodeData(); | 275 ui::AXNodeData* node = new ui::AXNodeData(); |
| 262 node->id = render_accessibility->GenerateAXID(); | 276 node->id = render_accessibility->GenerateAXID(); |
| 263 node->role = role; | 277 node->role = role; |
| 264 node->state = 1 << ui::AX_STATE_READ_ONLY; | 278 node->state = 1 << ui::AX_STATE_READ_ONLY; |
| 279 |
| 280 // All nodes other than the first one have coordinates relative to |
| 281 // the first node. |
| 282 if (nodes_.size() > 0) |
| 283 node->offset_container_id = nodes_[0]->id; |
| 284 |
| 265 nodes_.push_back(base::WrapUnique(node)); | 285 nodes_.push_back(base::WrapUnique(node)); |
| 286 |
| 266 return node; | 287 return node; |
| 267 } | 288 } |
| 268 | 289 |
| 269 float PdfAccessibilityTree::GetDeviceScaleFactor() const { | 290 float PdfAccessibilityTree::GetDeviceScaleFactor() const { |
| 270 content::RenderFrame* render_frame = | 291 content::RenderFrame* render_frame = |
| 271 host_->GetRenderFrameForInstance(instance_); | 292 host_->GetRenderFrameForInstance(instance_); |
| 272 DCHECK(render_frame); | 293 DCHECK(render_frame); |
| 273 return render_frame->GetRenderView()->GetDeviceScaleFactor(); | 294 return render_frame->GetRenderView()->GetDeviceScaleFactor(); |
| 274 } | 295 } |
| 275 | 296 |
| 276 content::RenderAccessibility* PdfAccessibilityTree::GetRenderAccessibility() { | 297 content::RenderAccessibility* PdfAccessibilityTree::GetRenderAccessibility() { |
| 277 content::RenderFrame* render_frame = | 298 content::RenderFrame* render_frame = |
| 278 host_->GetRenderFrameForInstance(instance_); | 299 host_->GetRenderFrameForInstance(instance_); |
| 279 return render_frame ? render_frame->GetRenderAccessibility() : nullptr; | 300 return render_frame ? render_frame->GetRenderAccessibility() : nullptr; |
| 280 } | 301 } |
| 281 | 302 |
| 303 gfx::Transform* PdfAccessibilityTree::MakeTransformFromViewInfo() { |
| 304 gfx::Transform* transform = new gfx::Transform(); |
| 305 float scale_factor = zoom_ / GetDeviceScaleFactor(); |
| 306 transform->Scale(scale_factor, scale_factor); |
| 307 transform->Translate(offset_); |
| 308 transform->Translate(-scroll_); |
| 309 return transform; |
| 310 } |
| 311 |
| 282 // | 312 // |
| 283 // AXTreeSource implementation. | 313 // AXTreeSource implementation. |
| 284 // | 314 // |
| 285 | 315 |
| 286 bool PdfAccessibilityTree::GetTreeData(ui::AXTreeData* tree_data) const { | 316 bool PdfAccessibilityTree::GetTreeData(ui::AXTreeData* tree_data) const { |
| 287 return false; | 317 return false; |
| 288 } | 318 } |
| 289 | 319 |
| 290 ui::AXNode* PdfAccessibilityTree::GetRoot() const { | 320 ui::AXNode* PdfAccessibilityTree::GetRoot() const { |
| 291 return tree_.root(); | 321 return tree_.root(); |
| (...skipping 30 matching lines...) Expand all Loading... |
| 322 const ui::AXNode* PdfAccessibilityTree::GetNull() const { | 352 const ui::AXNode* PdfAccessibilityTree::GetNull() const { |
| 323 return nullptr; | 353 return nullptr; |
| 324 } | 354 } |
| 325 | 355 |
| 326 void PdfAccessibilityTree::SerializeNode( | 356 void PdfAccessibilityTree::SerializeNode( |
| 327 const ui::AXNode* node, ui::AXNodeData* out_data) const { | 357 const ui::AXNode* node, ui::AXNodeData* out_data) const { |
| 328 *out_data = node->data(); | 358 *out_data = node->data(); |
| 329 } | 359 } |
| 330 | 360 |
| 331 } // namespace pdf | 361 } // namespace pdf |
| OLD | NEW |