accessibility.cc 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  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. #include "pdf/accessibility.h"
  5. #include <algorithm>
  6. #include <utility>
  7. #include <vector>
  8. #include "base/numerics/safe_math.h"
  9. #include "pdf/accessibility_helper.h"
  10. #include "pdf/accessibility_structs.h"
  11. #include "pdf/pdf_engine.h"
  12. #include "ui/gfx/geometry/rect_f.h"
  13. namespace chrome_pdf {
  14. namespace {
  15. AccessibilityFormFieldInfo GetAccessibilityFormFieldInfo(
  16. PDFEngine* engine,
  17. int32_t page_index,
  18. uint32_t text_run_count) {
  19. AccessibilityFormFieldInfo form_field_info;
  20. form_field_info.text_fields =
  21. engine->GetTextFieldInfo(page_index, text_run_count);
  22. return form_field_info;
  23. }
  24. } // namespace
  25. bool GetAccessibilityInfo(PDFEngine* engine,
  26. int32_t page_index,
  27. AccessibilityPageInfo& page_info,
  28. std::vector<AccessibilityTextRunInfo>& text_runs,
  29. std::vector<AccessibilityCharInfo>& chars,
  30. AccessibilityPageObjects& page_objects) {
  31. int page_count = engine->GetNumberOfPages();
  32. if (page_index < 0 || page_index >= page_count)
  33. return false;
  34. int char_count = engine->GetCharCount(page_index);
  35. // Treat a char count of -1 (error) as 0 (an empty page), since
  36. // other pages might have valid content.
  37. if (char_count < 0)
  38. char_count = 0;
  39. page_info.page_index = page_index;
  40. page_info.bounds = engine->GetPageBoundsRect(page_index);
  41. page_info.char_count = char_count;
  42. chars.resize(page_info.char_count);
  43. for (uint32_t i = 0; i < page_info.char_count; ++i) {
  44. chars[i].unicode_character = engine->GetCharUnicode(page_index, i);
  45. }
  46. int char_index = 0;
  47. while (char_index < char_count) {
  48. absl::optional<AccessibilityTextRunInfo> text_run_info_result =
  49. engine->GetTextRunInfo(page_index, char_index);
  50. DCHECK(text_run_info_result.has_value());
  51. const auto& text_run_info = text_run_info_result.value();
  52. uint32_t text_run_end = char_index + text_run_info.len;
  53. DCHECK_LE(text_run_end, static_cast<uint32_t>(char_count));
  54. text_runs.push_back(text_run_info);
  55. // We need to provide enough information to draw a bounding box
  56. // around any arbitrary text range, but the bounding boxes of characters
  57. // we get from PDFium don't necessarily "line up".
  58. // Example for LTR text direction: walk through the
  59. // characters in each text run and let the width of each character be
  60. // the difference between the x coordinate of one character and the
  61. // x coordinate of the next. The rest of the bounds of each character
  62. // can be computed from the bounds of the text run.
  63. // The same idea is used for RTL, TTB and BTT text direction.
  64. gfx::RectF char_bounds = engine->GetCharBounds(page_index, char_index);
  65. for (uint32_t i = char_index; i < text_run_end - 1; i++) {
  66. DCHECK_LT(i + 1, static_cast<uint32_t>(char_count));
  67. gfx::RectF next_char_bounds = engine->GetCharBounds(page_index, i + 1);
  68. double& char_width = chars[i].char_width;
  69. switch (text_run_info.direction) {
  70. case AccessibilityTextDirection::kNone:
  71. case AccessibilityTextDirection::kLeftToRight:
  72. char_width = next_char_bounds.x() - char_bounds.x();
  73. break;
  74. case AccessibilityTextDirection::kTopToBottom:
  75. char_width = next_char_bounds.y() - char_bounds.y();
  76. break;
  77. case AccessibilityTextDirection::kRightToLeft:
  78. char_width = char_bounds.right() - next_char_bounds.right();
  79. break;
  80. case AccessibilityTextDirection::kBottomToTop:
  81. char_width = char_bounds.bottom() - next_char_bounds.bottom();
  82. break;
  83. }
  84. char_bounds = next_char_bounds;
  85. }
  86. double& char_width = chars[text_run_end - 1].char_width;
  87. if (text_run_info.direction == AccessibilityTextDirection::kBottomToTop ||
  88. text_run_info.direction == AccessibilityTextDirection::kTopToBottom) {
  89. char_width = char_bounds.height();
  90. } else {
  91. char_width = char_bounds.width();
  92. }
  93. char_index += text_run_info.len;
  94. }
  95. page_info.text_run_count = text_runs.size();
  96. page_objects.links = engine->GetLinkInfo(page_index, text_runs);
  97. page_objects.images =
  98. engine->GetImageInfo(page_index, page_info.text_run_count);
  99. page_objects.highlights = engine->GetHighlightInfo(page_index, text_runs);
  100. page_objects.form_fields = GetAccessibilityFormFieldInfo(
  101. engine, page_index, page_info.text_run_count);
  102. return true;
  103. }
  104. } // namespace chrome_pdf