| 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" |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 126 | 126 |
| 127 } // Anonymous namespace | 127 } // Anonymous namespace |
| 128 | 128 |
| 129 void SerializeAccessibilityNode( | 129 void SerializeAccessibilityNode( |
| 130 const WebAXObject& src, | 130 const WebAXObject& src, |
| 131 AccessibilityNodeData* dst) { | 131 AccessibilityNodeData* dst) { |
| 132 dst->role = src.role(); | 132 dst->role = src.role(); |
| 133 dst->state = ConvertState(src); | 133 dst->state = ConvertState(src); |
| 134 dst->location = src.boundingBoxRect(); | 134 dst->location = src.boundingBoxRect(); |
| 135 dst->id = src.axID(); | 135 dst->id = src.axID(); |
| 136 std::string name = UTF16ToUTF8(src.title()); | 136 std::string name = base::UTF16ToUTF8(src.title()); |
| 137 | 137 |
| 138 std::string value; | 138 std::string value; |
| 139 if (src.valueDescription().length()) { | 139 if (src.valueDescription().length()) { |
| 140 dst->AddStringAttribute(dst->ATTR_VALUE, | 140 dst->AddStringAttribute(dst->ATTR_VALUE, |
| 141 UTF16ToUTF8(src.valueDescription())); | 141 base::UTF16ToUTF8(src.valueDescription())); |
| 142 } else { | 142 } else { |
| 143 dst->AddStringAttribute(dst->ATTR_VALUE, UTF16ToUTF8(src.stringValue())); | 143 dst->AddStringAttribute(dst->ATTR_VALUE, |
| 144 base::UTF16ToUTF8(src.stringValue())); |
| 144 } | 145 } |
| 145 | 146 |
| 146 if (dst->role == blink::WebAXRoleColorWell) { | 147 if (dst->role == blink::WebAXRoleColorWell) { |
| 147 int r, g, b; | 148 int r, g, b; |
| 148 src.colorValue(r, g, b); | 149 src.colorValue(r, g, b); |
| 149 dst->AddIntAttribute(dst->ATTR_COLOR_VALUE_RED, r); | 150 dst->AddIntAttribute(dst->ATTR_COLOR_VALUE_RED, r); |
| 150 dst->AddIntAttribute(dst->ATTR_COLOR_VALUE_GREEN, g); | 151 dst->AddIntAttribute(dst->ATTR_COLOR_VALUE_GREEN, g); |
| 151 dst->AddIntAttribute(dst->ATTR_COLOR_VALUE_BLUE, b); | 152 dst->AddIntAttribute(dst->ATTR_COLOR_VALUE_BLUE, b); |
| 152 } | 153 } |
| 153 | 154 |
| (...skipping 16 matching lines...) Expand all Loading... |
| 170 word_starts.reserve(src_word_starts.size()); | 171 word_starts.reserve(src_word_starts.size()); |
| 171 word_ends.reserve(src_word_starts.size()); | 172 word_ends.reserve(src_word_starts.size()); |
| 172 for (size_t i = 0; i < src_word_starts.size(); ++i) { | 173 for (size_t i = 0; i < src_word_starts.size(); ++i) { |
| 173 word_starts.push_back(src_word_starts[i]); | 174 word_starts.push_back(src_word_starts[i]); |
| 174 word_ends.push_back(src_word_ends[i]); | 175 word_ends.push_back(src_word_ends[i]); |
| 175 } | 176 } |
| 176 dst->AddIntListAttribute(dst->ATTR_WORD_STARTS, word_starts); | 177 dst->AddIntListAttribute(dst->ATTR_WORD_STARTS, word_starts); |
| 177 dst->AddIntListAttribute(dst->ATTR_WORD_ENDS, word_ends); | 178 dst->AddIntListAttribute(dst->ATTR_WORD_ENDS, word_ends); |
| 178 } | 179 } |
| 179 | 180 |
| 180 if (src.accessKey().length()) | 181 if (src.accessKey().length()) { |
| 181 dst->AddStringAttribute(dst->ATTR_ACCESS_KEY, UTF16ToUTF8(src.accessKey())); | 182 dst->AddStringAttribute(dst->ATTR_ACCESS_KEY, |
| 182 if (src.actionVerb().length()) | 183 base::UTF16ToUTF8(src.accessKey())); |
| 183 dst->AddStringAttribute(dst->ATTR_ACTION, UTF16ToUTF8(src.actionVerb())); | 184 } |
| 185 if (src.actionVerb().length()) { |
| 186 dst->AddStringAttribute(dst->ATTR_ACTION, |
| 187 base::UTF16ToUTF8(src.actionVerb())); |
| 188 } |
| 184 if (src.isAriaReadOnly()) | 189 if (src.isAriaReadOnly()) |
| 185 dst->AddBoolAttribute(dst->ATTR_ARIA_READONLY, true); | 190 dst->AddBoolAttribute(dst->ATTR_ARIA_READONLY, true); |
| 186 if (src.isButtonStateMixed()) | 191 if (src.isButtonStateMixed()) |
| 187 dst->AddBoolAttribute(dst->ATTR_BUTTON_MIXED, true); | 192 dst->AddBoolAttribute(dst->ATTR_BUTTON_MIXED, true); |
| 188 if (src.canSetValueAttribute()) | 193 if (src.canSetValueAttribute()) |
| 189 dst->AddBoolAttribute(dst->ATTR_CAN_SET_VALUE, true); | 194 dst->AddBoolAttribute(dst->ATTR_CAN_SET_VALUE, true); |
| 190 if (src.accessibilityDescription().length()) { | 195 if (src.accessibilityDescription().length()) { |
| 191 dst->AddStringAttribute(dst->ATTR_DESCRIPTION, | 196 dst->AddStringAttribute(dst->ATTR_DESCRIPTION, |
| 192 UTF16ToUTF8(src.accessibilityDescription())); | 197 base::UTF16ToUTF8(src.accessibilityDescription())); |
| 193 } | 198 } |
| 194 if (src.hasComputedStyle()) { | 199 if (src.hasComputedStyle()) { |
| 195 dst->AddStringAttribute(dst->ATTR_DISPLAY, | 200 dst->AddStringAttribute(dst->ATTR_DISPLAY, |
| 196 UTF16ToUTF8(src.computedStyleDisplay())); | 201 base::UTF16ToUTF8(src.computedStyleDisplay())); |
| 197 } | 202 } |
| 198 if (src.helpText().length()) | 203 if (src.helpText().length()) |
| 199 dst->AddStringAttribute(dst->ATTR_HELP, UTF16ToUTF8(src.helpText())); | 204 dst->AddStringAttribute(dst->ATTR_HELP, base::UTF16ToUTF8(src.helpText())); |
| 200 if (src.keyboardShortcut().length()) { | 205 if (src.keyboardShortcut().length()) { |
| 201 dst->AddStringAttribute(dst->ATTR_SHORTCUT, | 206 dst->AddStringAttribute(dst->ATTR_SHORTCUT, |
| 202 UTF16ToUTF8(src.keyboardShortcut())); | 207 base::UTF16ToUTF8(src.keyboardShortcut())); |
| 203 } | 208 } |
| 204 if (!src.titleUIElement().isDetached()) { | 209 if (!src.titleUIElement().isDetached()) { |
| 205 dst->AddIntAttribute(dst->ATTR_TITLE_UI_ELEMENT, | 210 dst->AddIntAttribute(dst->ATTR_TITLE_UI_ELEMENT, |
| 206 src.titleUIElement().axID()); | 211 src.titleUIElement().axID()); |
| 207 } | 212 } |
| 208 if (!src.url().isEmpty()) | 213 if (!src.url().isEmpty()) |
| 209 dst->AddStringAttribute(dst->ATTR_URL, src.url().spec()); | 214 dst->AddStringAttribute(dst->ATTR_URL, src.url().spec()); |
| 210 | 215 |
| 211 if (dst->role == blink::WebAXRoleHeading) | 216 if (dst->role == blink::WebAXRoleHeading) |
| 212 dst->AddIntAttribute(dst->ATTR_HIERARCHICAL_LEVEL, src.headingLevel()); | 217 dst->AddIntAttribute(dst->ATTR_HIERARCHICAL_LEVEL, src.headingLevel()); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 227 | 232 |
| 228 WebNode node = src.node(); | 233 WebNode node = src.node(); |
| 229 bool is_iframe = false; | 234 bool is_iframe = false; |
| 230 std::string live_atomic; | 235 std::string live_atomic; |
| 231 std::string live_busy; | 236 std::string live_busy; |
| 232 std::string live_status; | 237 std::string live_status; |
| 233 std::string live_relevant; | 238 std::string live_relevant; |
| 234 | 239 |
| 235 if (!node.isNull() && node.isElementNode()) { | 240 if (!node.isNull() && node.isElementNode()) { |
| 236 WebElement element = node.to<WebElement>(); | 241 WebElement element = node.to<WebElement>(); |
| 237 is_iframe = (element.tagName() == ASCIIToUTF16("IFRAME")); | 242 is_iframe = (element.tagName() == base::ASCIIToUTF16("IFRAME")); |
| 238 | 243 |
| 239 if (LowerCaseEqualsASCII(element.getAttribute("aria-expanded"), "true")) | 244 if (LowerCaseEqualsASCII(element.getAttribute("aria-expanded"), "true")) |
| 240 dst->state |= (1 << blink::WebAXStateExpanded); | 245 dst->state |= (1 << blink::WebAXStateExpanded); |
| 241 | 246 |
| 242 // TODO(ctguil): The tagName in WebKit is lower cased but | 247 // TODO(ctguil): The tagName in WebKit is lower cased but |
| 243 // HTMLElement::nodeName calls localNameUpper. Consider adding | 248 // HTMLElement::nodeName calls localNameUpper. Consider adding |
| 244 // a WebElement method that returns the original lower cased tagName. | 249 // a WebElement method that returns the original lower cased tagName. |
| 245 dst->AddStringAttribute( | 250 dst->AddStringAttribute( |
| 246 dst->ATTR_HTML_TAG, | 251 dst->ATTR_HTML_TAG, |
| 247 StringToLowerASCII(UTF16ToUTF8(element.tagName()))); | 252 StringToLowerASCII(base::UTF16ToUTF8(element.tagName()))); |
| 248 for (unsigned i = 0; i < element.attributeCount(); ++i) { | 253 for (unsigned i = 0; i < element.attributeCount(); ++i) { |
| 249 std::string name = StringToLowerASCII(UTF16ToUTF8( | 254 std::string name = StringToLowerASCII(base::UTF16ToUTF8( |
| 250 element.attributeLocalName(i))); | 255 element.attributeLocalName(i))); |
| 251 std::string value = UTF16ToUTF8(element.attributeValue(i)); | 256 std::string value = base::UTF16ToUTF8(element.attributeValue(i)); |
| 252 dst->html_attributes.push_back(std::make_pair(name, value)); | 257 dst->html_attributes.push_back(std::make_pair(name, value)); |
| 253 } | 258 } |
| 254 | 259 |
| 255 if (dst->role == blink::WebAXRoleEditableText || | 260 if (dst->role == blink::WebAXRoleEditableText || |
| 256 dst->role == blink::WebAXRoleTextArea || | 261 dst->role == blink::WebAXRoleTextArea || |
| 257 dst->role == blink::WebAXRoleTextField) { | 262 dst->role == blink::WebAXRoleTextField) { |
| 258 dst->AddIntAttribute(dst->ATTR_TEXT_SEL_START, src.selectionStart()); | 263 dst->AddIntAttribute(dst->ATTR_TEXT_SEL_START, src.selectionStart()); |
| 259 dst->AddIntAttribute(dst->ATTR_TEXT_SEL_END, src.selectionEnd()); | 264 dst->AddIntAttribute(dst->ATTR_TEXT_SEL_END, src.selectionEnd()); |
| 260 | 265 |
| 261 WebVector<int> src_line_breaks; | 266 WebVector<int> src_line_breaks; |
| 262 src.lineBreaks(src_line_breaks); | 267 src.lineBreaks(src_line_breaks); |
| 263 if (src_line_breaks.size() > 0) { | 268 if (src_line_breaks.size() > 0) { |
| 264 std::vector<int32> line_breaks; | 269 std::vector<int32> line_breaks; |
| 265 line_breaks.reserve(src_line_breaks.size()); | 270 line_breaks.reserve(src_line_breaks.size()); |
| 266 for (size_t i = 0; i < src_line_breaks.size(); ++i) | 271 for (size_t i = 0; i < src_line_breaks.size(); ++i) |
| 267 line_breaks.push_back(src_line_breaks[i]); | 272 line_breaks.push_back(src_line_breaks[i]); |
| 268 dst->AddIntListAttribute(dst->ATTR_LINE_BREAKS, line_breaks); | 273 dst->AddIntListAttribute(dst->ATTR_LINE_BREAKS, line_breaks); |
| 269 } | 274 } |
| 270 } | 275 } |
| 271 | 276 |
| 272 // ARIA role. | 277 // ARIA role. |
| 273 if (element.hasAttribute("role")) { | 278 if (element.hasAttribute("role")) { |
| 274 dst->AddStringAttribute(dst->ATTR_ROLE, | 279 dst->AddStringAttribute(dst->ATTR_ROLE, |
| 275 UTF16ToUTF8(element.getAttribute("role"))); | 280 base::UTF16ToUTF8(element.getAttribute("role"))); |
| 276 } | 281 } |
| 277 | 282 |
| 278 // Live region attributes | 283 // Live region attributes |
| 279 live_atomic = UTF16ToUTF8(element.getAttribute("aria-atomic")); | 284 live_atomic = base::UTF16ToUTF8(element.getAttribute("aria-atomic")); |
| 280 live_busy = UTF16ToUTF8(element.getAttribute("aria-busy")); | 285 live_busy = base::UTF16ToUTF8(element.getAttribute("aria-busy")); |
| 281 live_status = UTF16ToUTF8(element.getAttribute("aria-live")); | 286 live_status = base::UTF16ToUTF8(element.getAttribute("aria-live")); |
| 282 live_relevant = UTF16ToUTF8(element.getAttribute("aria-relevant")); | 287 live_relevant = base::UTF16ToUTF8(element.getAttribute("aria-relevant")); |
| 283 } | 288 } |
| 284 | 289 |
| 285 // Walk up the parent chain to set live region attributes of containers | 290 // Walk up the parent chain to set live region attributes of containers |
| 286 std::string container_live_atomic; | 291 std::string container_live_atomic; |
| 287 std::string container_live_busy; | 292 std::string container_live_busy; |
| 288 std::string container_live_status; | 293 std::string container_live_status; |
| 289 std::string container_live_relevant; | 294 std::string container_live_relevant; |
| 290 WebAXObject container_accessible = src; | 295 WebAXObject container_accessible = src; |
| 291 while (!container_accessible.isDetached()) { | 296 while (!container_accessible.isDetached()) { |
| 292 WebNode container_node = container_accessible.node(); | 297 WebNode container_node = container_accessible.node(); |
| 293 if (!container_node.isNull() && container_node.isElementNode()) { | 298 if (!container_node.isNull() && container_node.isElementNode()) { |
| 294 WebElement container_elem = container_node.to<WebElement>(); | 299 WebElement container_elem = container_node.to<WebElement>(); |
| 295 if (container_elem.hasAttribute("aria-atomic") && | 300 if (container_elem.hasAttribute("aria-atomic") && |
| 296 container_live_atomic.empty()) { | 301 container_live_atomic.empty()) { |
| 297 container_live_atomic = | 302 container_live_atomic = |
| 298 UTF16ToUTF8(container_elem.getAttribute("aria-atomic")); | 303 base::UTF16ToUTF8(container_elem.getAttribute("aria-atomic")); |
| 299 } | 304 } |
| 300 if (container_elem.hasAttribute("aria-busy") && | 305 if (container_elem.hasAttribute("aria-busy") && |
| 301 container_live_busy.empty()) { | 306 container_live_busy.empty()) { |
| 302 container_live_busy = | 307 container_live_busy = |
| 303 UTF16ToUTF8(container_elem.getAttribute("aria-busy")); | 308 base::UTF16ToUTF8(container_elem.getAttribute("aria-busy")); |
| 304 } | 309 } |
| 305 if (container_elem.hasAttribute("aria-live") && | 310 if (container_elem.hasAttribute("aria-live") && |
| 306 container_live_status.empty()) { | 311 container_live_status.empty()) { |
| 307 container_live_status = | 312 container_live_status = |
| 308 UTF16ToUTF8(container_elem.getAttribute("aria-live")); | 313 base::UTF16ToUTF8(container_elem.getAttribute("aria-live")); |
| 309 } | 314 } |
| 310 if (container_elem.hasAttribute("aria-relevant") && | 315 if (container_elem.hasAttribute("aria-relevant") && |
| 311 container_live_relevant.empty()) { | 316 container_live_relevant.empty()) { |
| 312 container_live_relevant = | 317 container_live_relevant = |
| 313 UTF16ToUTF8(container_elem.getAttribute("aria-relevant")); | 318 base::UTF16ToUTF8(container_elem.getAttribute("aria-relevant")); |
| 314 } | 319 } |
| 315 } | 320 } |
| 316 container_accessible = container_accessible.parentObject(); | 321 container_accessible = container_accessible.parentObject(); |
| 317 } | 322 } |
| 318 | 323 |
| 319 if (!live_atomic.empty()) | 324 if (!live_atomic.empty()) |
| 320 dst->AddBoolAttribute(dst->ATTR_LIVE_ATOMIC, IsTrue(live_atomic)); | 325 dst->AddBoolAttribute(dst->ATTR_LIVE_ATOMIC, IsTrue(live_atomic)); |
| 321 if (!live_busy.empty()) | 326 if (!live_busy.empty()) |
| 322 dst->AddBoolAttribute(dst->ATTR_LIVE_BUSY, IsTrue(live_busy)); | 327 dst->AddBoolAttribute(dst->ATTR_LIVE_BUSY, IsTrue(live_busy)); |
| 323 if (!live_status.empty()) | 328 if (!live_status.empty()) |
| (...skipping 27 matching lines...) Expand all Loading... |
| 351 src.maxValueForRange()); | 356 src.maxValueForRange()); |
| 352 dst->AddFloatAttribute(dst->ATTR_MIN_VALUE_FOR_RANGE, | 357 dst->AddFloatAttribute(dst->ATTR_MIN_VALUE_FOR_RANGE, |
| 353 src.minValueForRange()); | 358 src.minValueForRange()); |
| 354 } | 359 } |
| 355 | 360 |
| 356 if (dst->role == blink::WebAXRoleDocument || | 361 if (dst->role == blink::WebAXRoleDocument || |
| 357 dst->role == blink::WebAXRoleWebArea) { | 362 dst->role == blink::WebAXRoleWebArea) { |
| 358 dst->AddStringAttribute(dst->ATTR_HTML_TAG, "#document"); | 363 dst->AddStringAttribute(dst->ATTR_HTML_TAG, "#document"); |
| 359 const WebDocument& document = src.document(); | 364 const WebDocument& document = src.document(); |
| 360 if (name.empty()) | 365 if (name.empty()) |
| 361 name = UTF16ToUTF8(document.title()); | 366 name = base::UTF16ToUTF8(document.title()); |
| 362 dst->AddStringAttribute(dst->ATTR_DOC_TITLE, UTF16ToUTF8(document.title())); | 367 dst->AddStringAttribute(dst->ATTR_DOC_TITLE, |
| 368 base::UTF16ToUTF8(document.title())); |
| 363 dst->AddStringAttribute(dst->ATTR_DOC_URL, document.url().spec()); | 369 dst->AddStringAttribute(dst->ATTR_DOC_URL, document.url().spec()); |
| 364 dst->AddStringAttribute( | 370 dst->AddStringAttribute( |
| 365 dst->ATTR_DOC_MIMETYPE, | 371 dst->ATTR_DOC_MIMETYPE, |
| 366 document.isXHTMLDocument() ? "text/xhtml" : "text/html"); | 372 document.isXHTMLDocument() ? "text/xhtml" : "text/html"); |
| 367 dst->AddBoolAttribute(dst->ATTR_DOC_LOADED, src.isLoaded()); | 373 dst->AddBoolAttribute(dst->ATTR_DOC_LOADED, src.isLoaded()); |
| 368 dst->AddFloatAttribute(dst->ATTR_DOC_LOADING_PROGRESS, | 374 dst->AddFloatAttribute(dst->ATTR_DOC_LOADING_PROGRESS, |
| 369 src.estimatedLoadingProgress()); | 375 src.estimatedLoadingProgress()); |
| 370 | 376 |
| 371 const WebDocumentType& doctype = document.doctype(); | 377 const WebDocumentType& doctype = document.doctype(); |
| 372 if (!doctype.isNull()) { | 378 if (!doctype.isNull()) { |
| 373 dst->AddStringAttribute(dst->ATTR_DOC_DOCTYPE, | 379 dst->AddStringAttribute(dst->ATTR_DOC_DOCTYPE, |
| 374 UTF16ToUTF8(doctype.name())); | 380 base::UTF16ToUTF8(doctype.name())); |
| 375 } | 381 } |
| 376 | 382 |
| 377 const gfx::Size& scroll_offset = document.frame()->scrollOffset(); | 383 const gfx::Size& scroll_offset = document.frame()->scrollOffset(); |
| 378 dst->AddIntAttribute(dst->ATTR_SCROLL_X, scroll_offset.width()); | 384 dst->AddIntAttribute(dst->ATTR_SCROLL_X, scroll_offset.width()); |
| 379 dst->AddIntAttribute(dst->ATTR_SCROLL_Y, scroll_offset.height()); | 385 dst->AddIntAttribute(dst->ATTR_SCROLL_Y, scroll_offset.height()); |
| 380 | 386 |
| 381 const gfx::Size& min_offset = document.frame()->minimumScrollOffset(); | 387 const gfx::Size& min_offset = document.frame()->minimumScrollOffset(); |
| 382 dst->AddIntAttribute(dst->ATTR_SCROLL_X_MIN, min_offset.width()); | 388 dst->AddIntAttribute(dst->ATTR_SCROLL_X_MIN, min_offset.width()); |
| 383 dst->AddIntAttribute(dst->ATTR_SCROLL_Y_MIN, min_offset.height()); | 389 dst->AddIntAttribute(dst->ATTR_SCROLL_Y_MIN, min_offset.height()); |
| 384 | 390 |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 471 // TODO(ctguil): We may want to remove this check as webkit stabilizes. | 477 // TODO(ctguil): We may want to remove this check as webkit stabilizes. |
| 472 if (child.isDetached()) | 478 if (child.isDetached()) |
| 473 return false; | 479 return false; |
| 474 | 480 |
| 475 // Skip children whose parent isn't this - see indirect_child_ids, above. | 481 // Skip children whose parent isn't this - see indirect_child_ids, above. |
| 476 // As an exception, include children of an iframe element. | 482 // As an exception, include children of an iframe element. |
| 477 bool is_iframe = false; | 483 bool is_iframe = false; |
| 478 WebNode node = parent.node(); | 484 WebNode node = parent.node(); |
| 479 if (!node.isNull() && node.isElementNode()) { | 485 if (!node.isNull() && node.isElementNode()) { |
| 480 WebElement element = node.to<WebElement>(); | 486 WebElement element = node.to<WebElement>(); |
| 481 is_iframe = (element.tagName() == ASCIIToUTF16("IFRAME")); | 487 is_iframe = (element.tagName() == base::ASCIIToUTF16("IFRAME")); |
| 482 } | 488 } |
| 483 | 489 |
| 484 return (is_iframe || IsParentUnignoredOf(parent, child)); | 490 return (is_iframe || IsParentUnignoredOf(parent, child)); |
| 485 } | 491 } |
| 486 | 492 |
| 487 } // namespace content | 493 } // namespace content |
| OLD | NEW |