| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "content/renderer/accessibility/accessibility_node_serializer.h" | 5 #include "content/renderer/accessibility/accessibility_node_serializer.h" |
| 6 | 6 |
| 7 #include <set> | 7 #include <set> |
| 8 | 8 |
| 9 #include "base/strings/string_number_conversions.h" | 9 #include "base/strings/string_number_conversions.h" |
| 10 #include "base/strings/string_util.h" | 10 #include "base/strings/string_util.h" |
| 11 #include "base/strings/utf_string_conversions.h" | 11 #include "base/strings/utf_string_conversions.h" |
| 12 #include "content/renderer/accessibility/blink_ax_enum_conversion.h" |
| 12 #include "third_party/WebKit/public/platform/WebRect.h" | 13 #include "third_party/WebKit/public/platform/WebRect.h" |
| 13 #include "third_party/WebKit/public/platform/WebSize.h" | 14 #include "third_party/WebKit/public/platform/WebSize.h" |
| 14 #include "third_party/WebKit/public/platform/WebString.h" | 15 #include "third_party/WebKit/public/platform/WebString.h" |
| 15 #include "third_party/WebKit/public/platform/WebVector.h" | 16 #include "third_party/WebKit/public/platform/WebVector.h" |
| 16 #include "third_party/WebKit/public/web/WebAXEnums.h" | 17 #include "third_party/WebKit/public/web/WebAXEnums.h" |
| 17 #include "third_party/WebKit/public/web/WebAXObject.h" | 18 #include "third_party/WebKit/public/web/WebAXObject.h" |
| 18 #include "third_party/WebKit/public/web/WebDocument.h" | 19 #include "third_party/WebKit/public/web/WebDocument.h" |
| 19 #include "third_party/WebKit/public/web/WebDocumentType.h" | 20 #include "third_party/WebKit/public/web/WebDocumentType.h" |
| 20 #include "third_party/WebKit/public/web/WebElement.h" | 21 #include "third_party/WebKit/public/web/WebElement.h" |
| 21 #include "third_party/WebKit/public/web/WebFormControlElement.h" | 22 #include "third_party/WebKit/public/web/WebFormControlElement.h" |
| 22 #include "third_party/WebKit/public/web/WebFrame.h" | 23 #include "third_party/WebKit/public/web/WebFrame.h" |
| 23 #include "third_party/WebKit/public/web/WebInputElement.h" | 24 #include "third_party/WebKit/public/web/WebInputElement.h" |
| 24 #include "third_party/WebKit/public/web/WebNode.h" | 25 #include "third_party/WebKit/public/web/WebNode.h" |
| 25 | 26 |
| 27 using base::UTF16ToUTF8; |
| 26 using blink::WebAXObject; | 28 using blink::WebAXObject; |
| 27 using blink::WebDocument; | 29 using blink::WebDocument; |
| 28 using blink::WebDocumentType; | 30 using blink::WebDocumentType; |
| 29 using blink::WebElement; | 31 using blink::WebElement; |
| 30 using blink::WebNode; | 32 using blink::WebNode; |
| 31 using blink::WebVector; | 33 using blink::WebVector; |
| 32 | 34 |
| 33 namespace content { | 35 namespace content { |
| 34 namespace { | 36 namespace { |
| 35 | 37 |
| 36 // Returns true if |ancestor| is the first unignored parent of |child|, | 38 // Returns true if |ancestor| is the first unignored parent of |child|, |
| 37 // which means that when walking up the parent chain from |child|, | 39 // which means that when walking up the parent chain from |child|, |
| 38 // |ancestor| is the *first* ancestor that isn't marked as | 40 // |ancestor| is the *first* ancestor that isn't marked as |
| 39 // accessibilityIsIgnored(). | 41 // accessibilityIsIgnored(). |
| 40 bool IsParentUnignoredOf(const WebAXObject& ancestor, | 42 bool IsParentUnignoredOf(const WebAXObject& ancestor, |
| 41 const WebAXObject& child) { | 43 const WebAXObject& child) { |
| 42 WebAXObject parent = child.parentObject(); | 44 WebAXObject parent = child.parentObject(); |
| 43 while (!parent.isDetached() && parent.accessibilityIsIgnored()) | 45 while (!parent.isDetached() && parent.accessibilityIsIgnored()) |
| 44 parent = parent.parentObject(); | 46 parent = parent.parentObject(); |
| 45 return parent.equals(ancestor); | 47 return parent.equals(ancestor); |
| 46 } | 48 } |
| 47 | 49 |
| 48 bool IsTrue(std::string html_value) { | 50 bool IsTrue(std::string html_value) { |
| 49 return LowerCaseEqualsASCII(html_value, "true"); | 51 return LowerCaseEqualsASCII(html_value, "true"); |
| 50 } | 52 } |
| 51 | 53 |
| 52 // Provides a conversion between the WebAXObject state | |
| 53 // accessors and a state bitmask that can be serialized and sent to the | |
| 54 // Browser process. Rare state are sent as boolean attributes instead. | |
| 55 uint32 ConvertState(const WebAXObject& o) { | |
| 56 uint32 state = 0; | |
| 57 if (o.isChecked()) | |
| 58 state |= (1 << blink::WebAXStateChecked); | |
| 59 | |
| 60 if (o.isCollapsed()) | |
| 61 state |= (1 << blink::WebAXStateCollapsed); | |
| 62 | |
| 63 if (o.canSetFocusAttribute()) | |
| 64 state |= (1 << blink::WebAXStateFocusable); | |
| 65 | |
| 66 if (o.isFocused()) | |
| 67 state |= (1 << blink::WebAXStateFocused); | |
| 68 | |
| 69 if (o.role() == blink::WebAXRolePopUpButton || | |
| 70 o.ariaHasPopup()) { | |
| 71 state |= (1 << blink::WebAXStateHaspopup); | |
| 72 if (!o.isCollapsed()) | |
| 73 state |= (1 << blink::WebAXStateExpanded); | |
| 74 } | |
| 75 | |
| 76 if (o.isHovered()) | |
| 77 state |= (1 << blink::WebAXStateHovered); | |
| 78 | |
| 79 if (o.isIndeterminate()) | |
| 80 state |= (1 << blink::WebAXStateIndeterminate); | |
| 81 | |
| 82 if (!o.isVisible()) | |
| 83 state |= (1 << blink::WebAXStateInvisible); | |
| 84 | |
| 85 if (o.isLinked()) | |
| 86 state |= (1 << blink::WebAXStateLinked); | |
| 87 | |
| 88 if (o.isMultiSelectable()) | |
| 89 state |= (1 << blink::WebAXStateMultiselectable); | |
| 90 | |
| 91 if (o.isOffScreen()) | |
| 92 state |= (1 << blink::WebAXStateOffscreen); | |
| 93 | |
| 94 if (o.isPressed()) | |
| 95 state |= (1 << blink::WebAXStatePressed); | |
| 96 | |
| 97 if (o.isPasswordField()) | |
| 98 state |= (1 << blink::WebAXStateProtected); | |
| 99 | |
| 100 if (o.isReadOnly()) | |
| 101 state |= (1 << blink::WebAXStateReadonly); | |
| 102 | |
| 103 if (o.isRequired()) | |
| 104 state |= (1 << blink::WebAXStateRequired); | |
| 105 | |
| 106 if (o.canSetSelectedAttribute()) | |
| 107 state |= (1 << blink::WebAXStateSelectable); | |
| 108 | |
| 109 if (o.isSelected()) | |
| 110 state |= (1 << blink::WebAXStateSelected); | |
| 111 | |
| 112 if (o.isVisited()) | |
| 113 state |= (1 << blink::WebAXStateVisited); | |
| 114 | |
| 115 if (o.isEnabled()) | |
| 116 state |= (1 << blink::WebAXStateEnabled); | |
| 117 | |
| 118 if (o.isVertical()) | |
| 119 state |= (1 << blink::WebAXStateVertical); | |
| 120 | |
| 121 if (o.isVisited()) | |
| 122 state |= (1 << blink::WebAXStateVisited); | |
| 123 | |
| 124 return state; | |
| 125 } | |
| 126 | |
| 127 } // Anonymous namespace | 54 } // Anonymous namespace |
| 128 | 55 |
| 129 void SerializeAccessibilityNode( | 56 void SerializeAccessibilityNode( |
| 130 const WebAXObject& src, | 57 const WebAXObject& src, |
| 131 AccessibilityNodeData* dst) { | 58 ui::AXNodeData* dst) { |
| 132 dst->role = src.role(); | 59 dst->role = AXRoleFromBlink(src.role()); |
| 133 dst->state = ConvertState(src); | 60 dst->state = AXStateFromBlink(src); |
| 134 dst->location = src.boundingBoxRect(); | 61 dst->location = src.boundingBoxRect(); |
| 135 dst->id = src.axID(); | 62 dst->id = src.axID(); |
| 136 std::string name = base::UTF16ToUTF8(src.title()); | 63 std::string name = base::UTF16ToUTF8(src.title()); |
| 137 | 64 |
| 138 std::string value; | 65 std::string value; |
| 139 if (src.valueDescription().length()) { | 66 if (src.valueDescription().length()) { |
| 140 dst->AddStringAttribute(dst->ATTR_VALUE, | 67 dst->AddStringAttribute(ui::AX_ATTR_VALUE, |
| 141 base::UTF16ToUTF8(src.valueDescription())); | 68 UTF16ToUTF8(src.valueDescription())); |
| 142 } else { | 69 } else { |
| 143 dst->AddStringAttribute(dst->ATTR_VALUE, | 70 dst->AddStringAttribute(ui::AX_ATTR_VALUE, UTF16ToUTF8(src.stringValue())); |
| 144 base::UTF16ToUTF8(src.stringValue())); | |
| 145 } | 71 } |
| 146 | 72 |
| 147 if (dst->role == blink::WebAXRoleColorWell) { | 73 if (dst->role == ui::AX_ROLE_COLOR_WELL) { |
| 148 int r, g, b; | 74 int r, g, b; |
| 149 src.colorValue(r, g, b); | 75 src.colorValue(r, g, b); |
| 150 dst->AddIntAttribute(dst->ATTR_COLOR_VALUE_RED, r); | 76 dst->AddIntAttribute(ui::AX_ATTR_COLOR_VALUE_RED, r); |
| 151 dst->AddIntAttribute(dst->ATTR_COLOR_VALUE_GREEN, g); | 77 dst->AddIntAttribute(ui::AX_ATTR_COLOR_VALUE_GREEN, g); |
| 152 dst->AddIntAttribute(dst->ATTR_COLOR_VALUE_BLUE, b); | 78 dst->AddIntAttribute(ui::AX_ATTR_COLOR_VALUE_BLUE, b); |
| 153 } | 79 } |
| 154 | 80 |
| 155 if (dst->role == blink::WebAXRoleInlineTextBox) { | 81 if (dst->role == ui::AX_ROLE_INLINE_TEXT_BOX) { |
| 156 dst->AddIntAttribute(dst->ATTR_TEXT_DIRECTION, src.textDirection()); | 82 dst->AddIntAttribute(ui::AX_ATTR_TEXT_DIRECTION, src.textDirection()); |
| 157 | 83 |
| 158 WebVector<int> src_character_offsets; | 84 WebVector<int> src_character_offsets; |
| 159 src.characterOffsets(src_character_offsets); | 85 src.characterOffsets(src_character_offsets); |
| 160 std::vector<int32> character_offsets; | 86 std::vector<int32> character_offsets; |
| 161 character_offsets.reserve(src_character_offsets.size()); | 87 character_offsets.reserve(src_character_offsets.size()); |
| 162 for (size_t i = 0; i < src_character_offsets.size(); ++i) | 88 for (size_t i = 0; i < src_character_offsets.size(); ++i) |
| 163 character_offsets.push_back(src_character_offsets[i]); | 89 character_offsets.push_back(src_character_offsets[i]); |
| 164 dst->AddIntListAttribute(dst->ATTR_CHARACTER_OFFSETS, character_offsets); | 90 dst->AddIntListAttribute(ui::AX_ATTR_CHARACTER_OFFSETS, character_offsets); |
| 165 | 91 |
| 166 WebVector<int> src_word_starts; | 92 WebVector<int> src_word_starts; |
| 167 WebVector<int> src_word_ends; | 93 WebVector<int> src_word_ends; |
| 168 src.wordBoundaries(src_word_starts, src_word_ends); | 94 src.wordBoundaries(src_word_starts, src_word_ends); |
| 169 std::vector<int32> word_starts; | 95 std::vector<int32> word_starts; |
| 170 std::vector<int32> word_ends; | 96 std::vector<int32> word_ends; |
| 171 word_starts.reserve(src_word_starts.size()); | 97 word_starts.reserve(src_word_starts.size()); |
| 172 word_ends.reserve(src_word_starts.size()); | 98 word_ends.reserve(src_word_starts.size()); |
| 173 for (size_t i = 0; i < src_word_starts.size(); ++i) { | 99 for (size_t i = 0; i < src_word_starts.size(); ++i) { |
| 174 word_starts.push_back(src_word_starts[i]); | 100 word_starts.push_back(src_word_starts[i]); |
| 175 word_ends.push_back(src_word_ends[i]); | 101 word_ends.push_back(src_word_ends[i]); |
| 176 } | 102 } |
| 177 dst->AddIntListAttribute(dst->ATTR_WORD_STARTS, word_starts); | 103 dst->AddIntListAttribute(ui::AX_ATTR_WORD_STARTS, word_starts); |
| 178 dst->AddIntListAttribute(dst->ATTR_WORD_ENDS, word_ends); | 104 dst->AddIntListAttribute(ui::AX_ATTR_WORD_ENDS, word_ends); |
| 179 } | 105 } |
| 180 | 106 |
| 181 if (src.accessKey().length()) { | 107 if (src.accessKey().length()) |
| 182 dst->AddStringAttribute(dst->ATTR_ACCESS_KEY, | 108 dst->AddStringAttribute(ui::AX_ATTR_ACCESS_KEY, |
| 183 base::UTF16ToUTF8(src.accessKey())); | 109 UTF16ToUTF8(src.accessKey())); |
| 184 } | 110 if (src.actionVerb().length()) |
| 185 if (src.actionVerb().length()) { | 111 dst->AddStringAttribute(ui::AX_ATTR_ACTION, UTF16ToUTF8(src.actionVerb())); |
| 186 dst->AddStringAttribute(dst->ATTR_ACTION, | |
| 187 base::UTF16ToUTF8(src.actionVerb())); | |
| 188 } | |
| 189 if (src.isAriaReadOnly()) | 112 if (src.isAriaReadOnly()) |
| 190 dst->AddBoolAttribute(dst->ATTR_ARIA_READONLY, true); | 113 dst->AddBoolAttribute(ui::AX_ATTR_ARIA_READONLY, true); |
| 191 if (src.isButtonStateMixed()) | 114 if (src.isButtonStateMixed()) |
| 192 dst->AddBoolAttribute(dst->ATTR_BUTTON_MIXED, true); | 115 dst->AddBoolAttribute(ui::AX_ATTR_BUTTON_MIXED, true); |
| 193 if (src.canSetValueAttribute()) | 116 if (src.canSetValueAttribute()) |
| 194 dst->AddBoolAttribute(dst->ATTR_CAN_SET_VALUE, true); | 117 dst->AddBoolAttribute(ui::AX_ATTR_CAN_SET_VALUE, true); |
| 195 if (src.accessibilityDescription().length()) { | 118 if (src.accessibilityDescription().length()) { |
| 196 dst->AddStringAttribute(dst->ATTR_DESCRIPTION, | 119 dst->AddStringAttribute(ui::AX_ATTR_DESCRIPTION, |
| 197 base::UTF16ToUTF8(src.accessibilityDescription())); | 120 UTF16ToUTF8(src.accessibilityDescription())); |
| 198 } | 121 } |
| 199 if (src.hasComputedStyle()) { | 122 if (src.hasComputedStyle()) { |
| 200 dst->AddStringAttribute(dst->ATTR_DISPLAY, | 123 dst->AddStringAttribute(ui::AX_ATTR_DISPLAY, |
| 201 base::UTF16ToUTF8(src.computedStyleDisplay())); | 124 UTF16ToUTF8(src.computedStyleDisplay())); |
| 202 } | 125 } |
| 203 if (src.helpText().length()) | 126 if (src.helpText().length()) |
| 204 dst->AddStringAttribute(dst->ATTR_HELP, base::UTF16ToUTF8(src.helpText())); | 127 dst->AddStringAttribute(ui::AX_ATTR_HELP, UTF16ToUTF8(src.helpText())); |
| 205 if (src.keyboardShortcut().length()) { | 128 if (src.keyboardShortcut().length()) { |
| 206 dst->AddStringAttribute(dst->ATTR_SHORTCUT, | 129 dst->AddStringAttribute(ui::AX_ATTR_SHORTCUT, |
| 207 base::UTF16ToUTF8(src.keyboardShortcut())); | 130 UTF16ToUTF8(src.keyboardShortcut())); |
| 208 } | 131 } |
| 209 if (!src.titleUIElement().isDetached()) { | 132 if (!src.titleUIElement().isDetached()) { |
| 210 dst->AddIntAttribute(dst->ATTR_TITLE_UI_ELEMENT, | 133 dst->AddIntAttribute(ui::AX_ATTR_TITLE_UI_ELEMENT, |
| 211 src.titleUIElement().axID()); | 134 src.titleUIElement().axID()); |
| 212 } | 135 } |
| 213 if (!src.url().isEmpty()) | 136 if (!src.url().isEmpty()) |
| 214 dst->AddStringAttribute(dst->ATTR_URL, src.url().spec()); | 137 dst->AddStringAttribute(ui::AX_ATTR_URL, src.url().spec()); |
| 215 | 138 |
| 216 if (dst->role == blink::WebAXRoleHeading) | 139 if (dst->role == ui::AX_ROLE_HEADING) |
| 217 dst->AddIntAttribute(dst->ATTR_HIERARCHICAL_LEVEL, src.headingLevel()); | 140 dst->AddIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL, src.headingLevel()); |
| 218 else if ((dst->role == blink::WebAXRoleTreeItem || | 141 else if ((dst->role == ui::AX_ROLE_TREE_ITEM || |
| 219 dst->role == blink::WebAXRoleRow) && | 142 dst->role == ui::AX_ROLE_ROW) && |
| 220 src.hierarchicalLevel() > 0) { | 143 src.hierarchicalLevel() > 0) { |
| 221 dst->AddIntAttribute(dst->ATTR_HIERARCHICAL_LEVEL, src.hierarchicalLevel()); | 144 dst->AddIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL, |
| 145 src.hierarchicalLevel()); |
| 222 } | 146 } |
| 223 | 147 |
| 224 // Treat the active list box item as focused. | 148 // Treat the active list box item as focused. |
| 225 if (dst->role == blink::WebAXRoleListBoxOption && | 149 if (dst->role == ui::AX_ROLE_LIST_BOX_OPTION && |
| 226 src.isSelectedOptionActive()) { | 150 src.isSelectedOptionActive()) { |
| 227 dst->state |= (1 << blink::WebAXStateFocused); | 151 dst->state |= (1 << ui::AX_STATE_FOCUSED); |
| 228 } | 152 } |
| 229 | 153 |
| 230 if (src.canvasHasFallbackContent()) | 154 if (src.canvasHasFallbackContent()) |
| 231 dst->AddBoolAttribute(dst->ATTR_CANVAS_HAS_FALLBACK, true); | 155 dst->AddBoolAttribute(ui::AX_ATTR_CANVAS_HAS_FALLBACK, true); |
| 232 | 156 |
| 233 WebNode node = src.node(); | 157 WebNode node = src.node(); |
| 234 bool is_iframe = false; | 158 bool is_iframe = false; |
| 235 std::string live_atomic; | 159 std::string live_atomic; |
| 236 std::string live_busy; | 160 std::string live_busy; |
| 237 std::string live_status; | 161 std::string live_status; |
| 238 std::string live_relevant; | 162 std::string live_relevant; |
| 239 | 163 |
| 240 if (!node.isNull() && node.isElementNode()) { | 164 if (!node.isNull() && node.isElementNode()) { |
| 241 WebElement element = node.to<WebElement>(); | 165 WebElement element = node.to<WebElement>(); |
| 242 is_iframe = (element.tagName() == base::ASCIIToUTF16("IFRAME")); | 166 is_iframe = (element.tagName() == base::ASCIIToUTF16("IFRAME")); |
| 243 | 167 |
| 244 if (LowerCaseEqualsASCII(element.getAttribute("aria-expanded"), "true")) | 168 if (LowerCaseEqualsASCII(element.getAttribute("aria-expanded"), "true")) |
| 245 dst->state |= (1 << blink::WebAXStateExpanded); | 169 dst->state |= (1 << ui::AX_STATE_EXPANDED); |
| 246 | 170 |
| 247 // TODO(ctguil): The tagName in WebKit is lower cased but | 171 // TODO(ctguil): The tagName in WebKit is lower cased but |
| 248 // HTMLElement::nodeName calls localNameUpper. Consider adding | 172 // HTMLElement::nodeName calls localNameUpper. Consider adding |
| 249 // a WebElement method that returns the original lower cased tagName. | 173 // a WebElement method that returns the original lower cased tagName. |
| 250 dst->AddStringAttribute( | 174 dst->AddStringAttribute( |
| 251 dst->ATTR_HTML_TAG, | 175 ui::AX_ATTR_HTML_TAG, |
| 252 StringToLowerASCII(base::UTF16ToUTF8(element.tagName()))); | 176 StringToLowerASCII(UTF16ToUTF8(element.tagName()))); |
| 253 for (unsigned i = 0; i < element.attributeCount(); ++i) { | 177 for (unsigned i = 0; i < element.attributeCount(); ++i) { |
| 254 std::string name = StringToLowerASCII(base::UTF16ToUTF8( | 178 std::string name = StringToLowerASCII(base::UTF16ToUTF8( |
| 255 element.attributeLocalName(i))); | 179 element.attributeLocalName(i))); |
| 256 std::string value = base::UTF16ToUTF8(element.attributeValue(i)); | 180 std::string value = base::UTF16ToUTF8(element.attributeValue(i)); |
| 257 dst->html_attributes.push_back(std::make_pair(name, value)); | 181 dst->html_attributes.push_back(std::make_pair(name, value)); |
| 258 } | 182 } |
| 259 | 183 |
| 260 if (dst->role == blink::WebAXRoleEditableText || | 184 if (dst->role == ui::AX_ROLE_EDITABLE_TEXT || |
| 261 dst->role == blink::WebAXRoleTextArea || | 185 dst->role == ui::AX_ROLE_TEXT_AREA || |
| 262 dst->role == blink::WebAXRoleTextField) { | 186 dst->role == ui::AX_ROLE_TEXT_FIELD) { |
| 263 dst->AddIntAttribute(dst->ATTR_TEXT_SEL_START, src.selectionStart()); | 187 dst->AddIntAttribute(ui::AX_ATTR_TEXT_SEL_START, src.selectionStart()); |
| 264 dst->AddIntAttribute(dst->ATTR_TEXT_SEL_END, src.selectionEnd()); | 188 dst->AddIntAttribute(ui::AX_ATTR_TEXT_SEL_END, src.selectionEnd()); |
| 265 | 189 |
| 266 WebVector<int> src_line_breaks; | 190 WebVector<int> src_line_breaks; |
| 267 src.lineBreaks(src_line_breaks); | 191 src.lineBreaks(src_line_breaks); |
| 268 if (src_line_breaks.size() > 0) { | 192 if (src_line_breaks.size() > 0) { |
| 269 std::vector<int32> line_breaks; | 193 std::vector<int32> line_breaks; |
| 270 line_breaks.reserve(src_line_breaks.size()); | 194 line_breaks.reserve(src_line_breaks.size()); |
| 271 for (size_t i = 0; i < src_line_breaks.size(); ++i) | 195 for (size_t i = 0; i < src_line_breaks.size(); ++i) |
| 272 line_breaks.push_back(src_line_breaks[i]); | 196 line_breaks.push_back(src_line_breaks[i]); |
| 273 dst->AddIntListAttribute(dst->ATTR_LINE_BREAKS, line_breaks); | 197 dst->AddIntListAttribute(ui::AX_ATTR_LINE_BREAKS, line_breaks); |
| 274 } | 198 } |
| 275 } | 199 } |
| 276 | 200 |
| 277 // ARIA role. | 201 // ARIA role. |
| 278 if (element.hasAttribute("role")) { | 202 if (element.hasAttribute("role")) { |
| 279 dst->AddStringAttribute(dst->ATTR_ROLE, | 203 dst->AddStringAttribute(ui::AX_ATTR_ROLE, |
| 280 base::UTF16ToUTF8(element.getAttribute("role"))); | 204 UTF16ToUTF8(element.getAttribute("role"))); |
| 281 } | 205 } |
| 282 | 206 |
| 283 // Live region attributes | 207 // Live region attributes |
| 284 live_atomic = base::UTF16ToUTF8(element.getAttribute("aria-atomic")); | 208 live_atomic = base::UTF16ToUTF8(element.getAttribute("aria-atomic")); |
| 285 live_busy = base::UTF16ToUTF8(element.getAttribute("aria-busy")); | 209 live_busy = base::UTF16ToUTF8(element.getAttribute("aria-busy")); |
| 286 live_status = base::UTF16ToUTF8(element.getAttribute("aria-live")); | 210 live_status = base::UTF16ToUTF8(element.getAttribute("aria-live")); |
| 287 live_relevant = base::UTF16ToUTF8(element.getAttribute("aria-relevant")); | 211 live_relevant = base::UTF16ToUTF8(element.getAttribute("aria-relevant")); |
| 288 } | 212 } |
| 289 | 213 |
| 290 // Walk up the parent chain to set live region attributes of containers | 214 // Walk up the parent chain to set live region attributes of containers |
| (...skipping 24 matching lines...) Expand all Loading... |
| 315 if (container_elem.hasAttribute("aria-relevant") && | 239 if (container_elem.hasAttribute("aria-relevant") && |
| 316 container_live_relevant.empty()) { | 240 container_live_relevant.empty()) { |
| 317 container_live_relevant = | 241 container_live_relevant = |
| 318 base::UTF16ToUTF8(container_elem.getAttribute("aria-relevant")); | 242 base::UTF16ToUTF8(container_elem.getAttribute("aria-relevant")); |
| 319 } | 243 } |
| 320 } | 244 } |
| 321 container_accessible = container_accessible.parentObject(); | 245 container_accessible = container_accessible.parentObject(); |
| 322 } | 246 } |
| 323 | 247 |
| 324 if (!live_atomic.empty()) | 248 if (!live_atomic.empty()) |
| 325 dst->AddBoolAttribute(dst->ATTR_LIVE_ATOMIC, IsTrue(live_atomic)); | 249 dst->AddBoolAttribute(ui::AX_ATTR_LIVE_ATOMIC, IsTrue(live_atomic)); |
| 326 if (!live_busy.empty()) | 250 if (!live_busy.empty()) |
| 327 dst->AddBoolAttribute(dst->ATTR_LIVE_BUSY, IsTrue(live_busy)); | 251 dst->AddBoolAttribute(ui::AX_ATTR_LIVE_BUSY, IsTrue(live_busy)); |
| 328 if (!live_status.empty()) | 252 if (!live_status.empty()) |
| 329 dst->AddStringAttribute(dst->ATTR_LIVE_STATUS, live_status); | 253 dst->AddStringAttribute(ui::AX_ATTR_LIVE_STATUS, live_status); |
| 330 if (!live_relevant.empty()) | 254 if (!live_relevant.empty()) |
| 331 dst->AddStringAttribute(dst->ATTR_LIVE_RELEVANT, live_relevant); | 255 dst->AddStringAttribute(ui::AX_ATTR_LIVE_RELEVANT, live_relevant); |
| 332 | 256 |
| 333 if (!container_live_atomic.empty()) { | 257 if (!container_live_atomic.empty()) { |
| 334 dst->AddBoolAttribute(dst->ATTR_CONTAINER_LIVE_ATOMIC, | 258 dst->AddBoolAttribute(ui::AX_ATTR_CONTAINER_LIVE_ATOMIC, |
| 335 IsTrue(container_live_atomic)); | 259 IsTrue(container_live_atomic)); |
| 336 } | 260 } |
| 337 if (!container_live_busy.empty()) { | 261 if (!container_live_busy.empty()) { |
| 338 dst->AddBoolAttribute(dst->ATTR_CONTAINER_LIVE_BUSY, | 262 dst->AddBoolAttribute(ui::AX_ATTR_CONTAINER_LIVE_BUSY, |
| 339 IsTrue(container_live_busy)); | 263 IsTrue(container_live_busy)); |
| 340 } | 264 } |
| 341 if (!container_live_status.empty()) { | 265 if (!container_live_status.empty()) { |
| 342 dst->AddStringAttribute(dst->ATTR_CONTAINER_LIVE_STATUS, | 266 dst->AddStringAttribute(ui::AX_ATTR_CONTAINER_LIVE_STATUS, |
| 343 container_live_status); | 267 container_live_status); |
| 344 } | 268 } |
| 345 if (!container_live_relevant.empty()) { | 269 if (!container_live_relevant.empty()) { |
| 346 dst->AddStringAttribute(dst->ATTR_CONTAINER_LIVE_RELEVANT, | 270 dst->AddStringAttribute(ui::AX_ATTR_CONTAINER_LIVE_RELEVANT, |
| 347 container_live_relevant); | 271 container_live_relevant); |
| 348 } | 272 } |
| 349 | 273 |
| 350 if (dst->role == blink::WebAXRoleProgressIndicator || | 274 if (dst->role == ui::AX_ROLE_PROGRESS_INDICATOR || |
| 351 dst->role == blink::WebAXRoleScrollBar || | 275 dst->role == ui::AX_ROLE_SCROLL_BAR || |
| 352 dst->role == blink::WebAXRoleSlider || | 276 dst->role == ui::AX_ROLE_SLIDER || |
| 353 dst->role == blink::WebAXRoleSpinButton) { | 277 dst->role == ui::AX_ROLE_SPIN_BUTTON) { |
| 354 dst->AddFloatAttribute(dst->ATTR_VALUE_FOR_RANGE, src.valueForRange()); | 278 dst->AddFloatAttribute(ui::AX_ATTR_VALUE_FOR_RANGE, src.valueForRange()); |
| 355 dst->AddFloatAttribute(dst->ATTR_MAX_VALUE_FOR_RANGE, | 279 dst->AddFloatAttribute(ui::AX_ATTR_MAX_VALUE_FOR_RANGE, |
| 356 src.maxValueForRange()); | 280 src.maxValueForRange()); |
| 357 dst->AddFloatAttribute(dst->ATTR_MIN_VALUE_FOR_RANGE, | 281 dst->AddFloatAttribute(ui::AX_ATTR_MIN_VALUE_FOR_RANGE, |
| 358 src.minValueForRange()); | 282 src.minValueForRange()); |
| 359 } | 283 } |
| 360 | 284 |
| 361 if (dst->role == blink::WebAXRoleDocument || | 285 if (dst->role == ui::AX_ROLE_DOCUMENT || |
| 362 dst->role == blink::WebAXRoleWebArea) { | 286 dst->role == ui::AX_ROLE_WEB_AREA) { |
| 363 dst->AddStringAttribute(dst->ATTR_HTML_TAG, "#document"); | 287 dst->AddStringAttribute(ui::AX_ATTR_HTML_TAG, "#document"); |
| 364 const WebDocument& document = src.document(); | 288 const WebDocument& document = src.document(); |
| 365 if (name.empty()) | 289 if (name.empty()) |
| 366 name = base::UTF16ToUTF8(document.title()); | 290 name = UTF16ToUTF8(document.title()); |
| 367 dst->AddStringAttribute(dst->ATTR_DOC_TITLE, | 291 dst->AddStringAttribute(ui::AX_ATTR_DOC_TITLE, |
| 368 base::UTF16ToUTF8(document.title())); | 292 UTF16ToUTF8(document.title())); |
| 369 dst->AddStringAttribute(dst->ATTR_DOC_URL, document.url().spec()); | 293 dst->AddStringAttribute(ui::AX_ATTR_DOC_URL, document.url().spec()); |
| 370 dst->AddStringAttribute( | 294 dst->AddStringAttribute( |
| 371 dst->ATTR_DOC_MIMETYPE, | 295 ui::AX_ATTR_DOC_MIMETYPE, |
| 372 document.isXHTMLDocument() ? "text/xhtml" : "text/html"); | 296 document.isXHTMLDocument() ? "text/xhtml" : "text/html"); |
| 373 dst->AddBoolAttribute(dst->ATTR_DOC_LOADED, src.isLoaded()); | 297 dst->AddBoolAttribute(ui::AX_ATTR_DOC_LOADED, src.isLoaded()); |
| 374 dst->AddFloatAttribute(dst->ATTR_DOC_LOADING_PROGRESS, | 298 dst->AddFloatAttribute(ui::AX_ATTR_DOC_LOADING_PROGRESS, |
| 375 src.estimatedLoadingProgress()); | 299 src.estimatedLoadingProgress()); |
| 376 | 300 |
| 377 const WebDocumentType& doctype = document.doctype(); | 301 const WebDocumentType& doctype = document.doctype(); |
| 378 if (!doctype.isNull()) { | 302 if (!doctype.isNull()) { |
| 379 dst->AddStringAttribute(dst->ATTR_DOC_DOCTYPE, | 303 dst->AddStringAttribute(ui::AX_ATTR_DOC_DOCTYPE, |
| 380 base::UTF16ToUTF8(doctype.name())); | 304 UTF16ToUTF8(doctype.name())); |
| 381 } | 305 } |
| 382 | 306 |
| 383 const gfx::Size& scroll_offset = document.frame()->scrollOffset(); | 307 const gfx::Size& scroll_offset = document.frame()->scrollOffset(); |
| 384 dst->AddIntAttribute(dst->ATTR_SCROLL_X, scroll_offset.width()); | 308 dst->AddIntAttribute(ui::AX_ATTR_SCROLL_X, scroll_offset.width()); |
| 385 dst->AddIntAttribute(dst->ATTR_SCROLL_Y, scroll_offset.height()); | 309 dst->AddIntAttribute(ui::AX_ATTR_SCROLL_Y, scroll_offset.height()); |
| 386 | 310 |
| 387 const gfx::Size& min_offset = document.frame()->minimumScrollOffset(); | 311 const gfx::Size& min_offset = document.frame()->minimumScrollOffset(); |
| 388 dst->AddIntAttribute(dst->ATTR_SCROLL_X_MIN, min_offset.width()); | 312 dst->AddIntAttribute(ui::AX_ATTR_SCROLL_X_MIN, min_offset.width()); |
| 389 dst->AddIntAttribute(dst->ATTR_SCROLL_Y_MIN, min_offset.height()); | 313 dst->AddIntAttribute(ui::AX_ATTR_SCROLL_Y_MIN, min_offset.height()); |
| 390 | 314 |
| 391 const gfx::Size& max_offset = document.frame()->maximumScrollOffset(); | 315 const gfx::Size& max_offset = document.frame()->maximumScrollOffset(); |
| 392 dst->AddIntAttribute(dst->ATTR_SCROLL_X_MAX, max_offset.width()); | 316 dst->AddIntAttribute(ui::AX_ATTR_SCROLL_X_MAX, max_offset.width()); |
| 393 dst->AddIntAttribute(dst->ATTR_SCROLL_Y_MAX, max_offset.height()); | 317 dst->AddIntAttribute(ui::AX_ATTR_SCROLL_Y_MAX, max_offset.height()); |
| 394 } | 318 } |
| 395 | 319 |
| 396 if (dst->role == blink::WebAXRoleTable) { | 320 if (dst->role == ui::AX_ROLE_TABLE) { |
| 397 int column_count = src.columnCount(); | 321 int column_count = src.columnCount(); |
| 398 int row_count = src.rowCount(); | 322 int row_count = src.rowCount(); |
| 399 if (column_count > 0 && row_count > 0) { | 323 if (column_count > 0 && row_count > 0) { |
| 400 std::set<int32> unique_cell_id_set; | 324 std::set<int32> unique_cell_id_set; |
| 401 std::vector<int32> cell_ids; | 325 std::vector<int32> cell_ids; |
| 402 std::vector<int32> unique_cell_ids; | 326 std::vector<int32> unique_cell_ids; |
| 403 dst->AddIntAttribute(dst->ATTR_TABLE_COLUMN_COUNT, column_count); | 327 dst->AddIntAttribute(ui::AX_ATTR_TABLE_COLUMN_COUNT, column_count); |
| 404 dst->AddIntAttribute(dst->ATTR_TABLE_ROW_COUNT, row_count); | 328 dst->AddIntAttribute(ui::AX_ATTR_TABLE_ROW_COUNT, row_count); |
| 405 WebAXObject header = src.headerContainerObject(); | 329 WebAXObject header = src.headerContainerObject(); |
| 406 if (!header.isDetached()) | 330 if (!header.isDetached()) |
| 407 dst->AddIntAttribute(dst->ATTR_TABLE_HEADER_ID, header.axID()); | 331 dst->AddIntAttribute(ui::AX_ATTR_TABLE_HEADER_ID, header.axID()); |
| 408 for (int i = 0; i < column_count * row_count; ++i) { | 332 for (int i = 0; i < column_count * row_count; ++i) { |
| 409 WebAXObject cell = src.cellForColumnAndRow( | 333 WebAXObject cell = src.cellForColumnAndRow( |
| 410 i % column_count, i / column_count); | 334 i % column_count, i / column_count); |
| 411 int cell_id = -1; | 335 int cell_id = -1; |
| 412 if (!cell.isDetached()) { | 336 if (!cell.isDetached()) { |
| 413 cell_id = cell.axID(); | 337 cell_id = cell.axID(); |
| 414 if (unique_cell_id_set.find(cell_id) == unique_cell_id_set.end()) { | 338 if (unique_cell_id_set.find(cell_id) == unique_cell_id_set.end()) { |
| 415 unique_cell_id_set.insert(cell_id); | 339 unique_cell_id_set.insert(cell_id); |
| 416 unique_cell_ids.push_back(cell_id); | 340 unique_cell_ids.push_back(cell_id); |
| 417 } | 341 } |
| 418 } | 342 } |
| 419 cell_ids.push_back(cell_id); | 343 cell_ids.push_back(cell_id); |
| 420 } | 344 } |
| 421 dst->AddIntListAttribute(dst->ATTR_CELL_IDS, cell_ids); | 345 dst->AddIntListAttribute(ui::AX_ATTR_CELL_IDS, cell_ids); |
| 422 dst->AddIntListAttribute(dst->ATTR_UNIQUE_CELL_IDS, unique_cell_ids); | 346 dst->AddIntListAttribute(ui::AX_ATTR_UNIQUE_CELL_IDS, unique_cell_ids); |
| 423 } | 347 } |
| 424 } | 348 } |
| 425 | 349 |
| 426 if (dst->role == blink::WebAXRoleRow) { | 350 if (dst->role == ui::AX_ROLE_ROW) { |
| 427 dst->AddIntAttribute(dst->ATTR_TABLE_ROW_INDEX, src.rowIndex()); | 351 dst->AddIntAttribute(ui::AX_ATTR_TABLE_ROW_INDEX, src.rowIndex()); |
| 428 WebAXObject header = src.rowHeader(); | 352 WebAXObject header = src.rowHeader(); |
| 429 if (!header.isDetached()) | 353 if (!header.isDetached()) |
| 430 dst->AddIntAttribute(dst->ATTR_TABLE_ROW_HEADER_ID, header.axID()); | 354 dst->AddIntAttribute(ui::AX_ATTR_TABLE_ROW_HEADER_ID, header.axID()); |
| 431 } | 355 } |
| 432 | 356 |
| 433 if (dst->role == blink::WebAXRoleColumn) { | 357 if (dst->role == ui::AX_ROLE_COLUMN) { |
| 434 dst->AddIntAttribute(dst->ATTR_TABLE_COLUMN_INDEX, src.columnIndex()); | 358 dst->AddIntAttribute(ui::AX_ATTR_TABLE_COLUMN_INDEX, src.columnIndex()); |
| 435 WebAXObject header = src.columnHeader(); | 359 WebAXObject header = src.columnHeader(); |
| 436 if (!header.isDetached()) | 360 if (!header.isDetached()) |
| 437 dst->AddIntAttribute(dst->ATTR_TABLE_COLUMN_HEADER_ID, header.axID()); | 361 dst->AddIntAttribute(ui::AX_ATTR_TABLE_COLUMN_HEADER_ID, header.axID()); |
| 438 } | 362 } |
| 439 | 363 |
| 440 if (dst->role == blink::WebAXRoleCell || | 364 if (dst->role == ui::AX_ROLE_CELL || |
| 441 dst->role == blink::WebAXRoleRowHeader || | 365 dst->role == ui::AX_ROLE_ROW_HEADER || |
| 442 dst->role == blink::WebAXRoleColumnHeader) { | 366 dst->role == ui::AX_ROLE_COLUMN_HEADER) { |
| 443 dst->AddIntAttribute(dst->ATTR_TABLE_CELL_COLUMN_INDEX, | 367 dst->AddIntAttribute(ui::AX_ATTR_TABLE_CELL_COLUMN_INDEX, |
| 444 src.cellColumnIndex()); | 368 src.cellColumnIndex()); |
| 445 dst->AddIntAttribute(dst->ATTR_TABLE_CELL_COLUMN_SPAN, | 369 dst->AddIntAttribute(ui::AX_ATTR_TABLE_CELL_COLUMN_SPAN, |
| 446 src.cellColumnSpan()); | 370 src.cellColumnSpan()); |
| 447 dst->AddIntAttribute(dst->ATTR_TABLE_CELL_ROW_INDEX, src.cellRowIndex()); | 371 dst->AddIntAttribute(ui::AX_ATTR_TABLE_CELL_ROW_INDEX, src.cellRowIndex()); |
| 448 dst->AddIntAttribute(dst->ATTR_TABLE_CELL_ROW_SPAN, src.cellRowSpan()); | 372 dst->AddIntAttribute(ui::AX_ATTR_TABLE_CELL_ROW_SPAN, src.cellRowSpan()); |
| 449 } | 373 } |
| 450 | 374 |
| 451 dst->AddStringAttribute(dst->ATTR_NAME, name); | 375 dst->AddStringAttribute(ui::AX_ATTR_NAME, name); |
| 452 | 376 |
| 453 // Add the ids of *indirect* children - those who are children of this node, | 377 // Add the ids of *indirect* children - those who are children of this node, |
| 454 // but whose parent is *not* this node. One example is a table | 378 // but whose parent is *not* this node. One example is a table |
| 455 // cell, which is a child of both a row and a column. Because the cell's | 379 // cell, which is a child of both a row and a column. Because the cell's |
| 456 // parent is the row, the row adds it as a child, and the column adds it | 380 // parent is the row, the row adds it as a child, and the column adds it |
| 457 // as an indirect child. | 381 // as an indirect child. |
| 458 int child_count = src.childCount(); | 382 int child_count = src.childCount(); |
| 459 for (int i = 0; i < child_count; ++i) { | 383 for (int i = 0; i < child_count; ++i) { |
| 460 WebAXObject child = src.childAt(i); | 384 WebAXObject child = src.childAt(i); |
| 461 std::vector<int32> indirect_child_ids; | 385 std::vector<int32> indirect_child_ids; |
| 462 if (!is_iframe && !child.isDetached() && !IsParentUnignoredOf(src, child)) | 386 if (!is_iframe && !child.isDetached() && !IsParentUnignoredOf(src, child)) |
| 463 indirect_child_ids.push_back(child.axID()); | 387 indirect_child_ids.push_back(child.axID()); |
| 464 if (indirect_child_ids.size() > 0) { | 388 if (indirect_child_ids.size() > 0) { |
| 465 dst->AddIntListAttribute( | 389 dst->AddIntListAttribute( |
| 466 dst->ATTR_INDIRECT_CHILD_IDS, indirect_child_ids); | 390 ui::AX_ATTR_INDIRECT_CHILD_IDS, indirect_child_ids); |
| 467 } | 391 } |
| 468 } | 392 } |
| 469 } | 393 } |
| 470 | 394 |
| 471 bool ShouldIncludeChildNode( | 395 bool ShouldIncludeChildNode( |
| 472 const WebAXObject& parent, | 396 const WebAXObject& parent, |
| 473 const WebAXObject& child) { | 397 const WebAXObject& child) { |
| 474 // The child may be invalid due to issues in webkit accessibility code. | 398 // The child may be invalid due to issues in webkit accessibility code. |
| 475 // Don't add children that are invalid thus preventing a crash. | 399 // Don't add children that are invalid thus preventing a crash. |
| 476 // https://bugs.webkit.org/show_bug.cgi?id=44149 | 400 // https://bugs.webkit.org/show_bug.cgi?id=44149 |
| 477 // TODO(ctguil): We may want to remove this check as webkit stabilizes. | 401 // TODO(ctguil): We may want to remove this check as webkit stabilizes. |
| 478 if (child.isDetached()) | 402 if (child.isDetached()) |
| 479 return false; | 403 return false; |
| 480 | 404 |
| 481 // Skip children whose parent isn't this - see indirect_child_ids, above. | 405 // Skip children whose parent isn't this - see indirect_child_ids, above. |
| 482 // As an exception, include children of an iframe element. | 406 // As an exception, include children of an iframe element. |
| 483 bool is_iframe = false; | 407 bool is_iframe = false; |
| 484 WebNode node = parent.node(); | 408 WebNode node = parent.node(); |
| 485 if (!node.isNull() && node.isElementNode()) { | 409 if (!node.isNull() && node.isElementNode()) { |
| 486 WebElement element = node.to<WebElement>(); | 410 WebElement element = node.to<WebElement>(); |
| 487 is_iframe = (element.tagName() == base::ASCIIToUTF16("IFRAME")); | 411 is_iframe = (element.tagName() == base::ASCIIToUTF16("IFRAME")); |
| 488 } | 412 } |
| 489 | 413 |
| 490 return (is_iframe || IsParentUnignoredOf(parent, child)); | 414 return (is_iframe || IsParentUnignoredOf(parent, child)); |
| 491 } | 415 } |
| 492 | 416 |
| 493 } // namespace content | 417 } // namespace content |
| OLD | NEW |