| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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/blink_ax_tree_source.h" | 5 #include "content/renderer/accessibility/blink_ax_tree_source.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 | 8 |
| 9 #include <set> | 9 #include <set> |
| 10 | 10 |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 121 ScopedFreezeBlinkAXTreeSource::ScopedFreezeBlinkAXTreeSource( | 121 ScopedFreezeBlinkAXTreeSource::ScopedFreezeBlinkAXTreeSource( |
| 122 BlinkAXTreeSource* tree_source) | 122 BlinkAXTreeSource* tree_source) |
| 123 : tree_source_(tree_source) { | 123 : tree_source_(tree_source) { |
| 124 tree_source_->Freeze(); | 124 tree_source_->Freeze(); |
| 125 } | 125 } |
| 126 | 126 |
| 127 ScopedFreezeBlinkAXTreeSource::~ScopedFreezeBlinkAXTreeSource() { | 127 ScopedFreezeBlinkAXTreeSource::~ScopedFreezeBlinkAXTreeSource() { |
| 128 tree_source_->Thaw(); | 128 tree_source_->Thaw(); |
| 129 } | 129 } |
| 130 | 130 |
| 131 BlinkAXTreeSource::BlinkAXTreeSource(RenderFrameImpl* render_frame) | 131 BlinkAXTreeSource::BlinkAXTreeSource(RenderFrameImpl* render_frame, |
| 132 AccessibilityMode mode) |
| 132 : render_frame_(render_frame), | 133 : render_frame_(render_frame), |
| 134 accessibility_mode_(mode), |
| 133 frozen_(false) {} | 135 frozen_(false) {} |
| 134 | 136 |
| 135 BlinkAXTreeSource::~BlinkAXTreeSource() { | 137 BlinkAXTreeSource::~BlinkAXTreeSource() { |
| 136 } | 138 } |
| 137 | 139 |
| 138 void BlinkAXTreeSource::Freeze() { | 140 void BlinkAXTreeSource::Freeze() { |
| 139 CHECK(!frozen_); | 141 CHECK(!frozen_); |
| 140 frozen_ = true; | 142 frozen_ = true; |
| 141 | 143 |
| 142 if (render_frame_ && render_frame_->GetWebFrame()) | 144 if (render_frame_ && render_frame_->GetWebFrame()) |
| (...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 334 blink::WebString web_description = src.description( | 336 blink::WebString web_description = src.description( |
| 335 nameFrom, descriptionFrom, descriptionObjects); | 337 nameFrom, descriptionFrom, descriptionObjects); |
| 336 if (!web_description.isEmpty()) { | 338 if (!web_description.isEmpty()) { |
| 337 dst->AddStringAttribute(ui::AX_ATTR_DESCRIPTION, web_description.utf8()); | 339 dst->AddStringAttribute(ui::AX_ATTR_DESCRIPTION, web_description.utf8()); |
| 338 dst->AddIntAttribute(ui::AX_ATTR_DESCRIPTION_FROM, | 340 dst->AddIntAttribute(ui::AX_ATTR_DESCRIPTION_FROM, |
| 339 AXDescriptionFromFromBlink(descriptionFrom)); | 341 AXDescriptionFromFromBlink(descriptionFrom)); |
| 340 AddIntListAttributeFromWebObjects( | 342 AddIntListAttributeFromWebObjects( |
| 341 ui::AX_ATTR_DESCRIBEDBY_IDS, descriptionObjects, dst); | 343 ui::AX_ATTR_DESCRIBEDBY_IDS, descriptionObjects, dst); |
| 342 } | 344 } |
| 343 | 345 |
| 344 blink::WebString web_placeholder = src.placeholder(nameFrom); | |
| 345 if (!web_placeholder.isEmpty()) | |
| 346 dst->AddStringAttribute(ui::AX_ATTR_PLACEHOLDER, web_placeholder.utf8()); | |
| 347 | |
| 348 std::string value; | 346 std::string value; |
| 349 if (src.valueDescription().length()) { | 347 if (src.valueDescription().length()) { |
| 350 dst->AddStringAttribute(ui::AX_ATTR_VALUE, src.valueDescription().utf8()); | 348 dst->AddStringAttribute(ui::AX_ATTR_VALUE, src.valueDescription().utf8()); |
| 351 } else { | 349 } else { |
| 352 dst->AddStringAttribute(ui::AX_ATTR_VALUE, src.stringValue().utf8()); | 350 dst->AddStringAttribute(ui::AX_ATTR_VALUE, src.stringValue().utf8()); |
| 353 } | 351 } |
| 354 | 352 |
| 355 if (dst->role == ui::AX_ROLE_COLOR_WELL) | |
| 356 dst->AddIntAttribute(ui::AX_ATTR_COLOR_VALUE, src.colorValue()); | |
| 357 | |
| 358 | |
| 359 // Text attributes. | |
| 360 if (src.backgroundColor()) | |
| 361 dst->AddIntAttribute(ui::AX_ATTR_BACKGROUND_COLOR, src.backgroundColor()); | |
| 362 | |
| 363 if (src.color()) | |
| 364 dst->AddIntAttribute(ui::AX_ATTR_COLOR, src.color()); | |
| 365 | |
| 366 WebAXObject parent = ParentObjectUnignored(src); | |
| 367 if (src.fontFamily().length()) { | |
| 368 if (parent.isNull() || parent.fontFamily() != src.fontFamily()) | |
| 369 dst->AddStringAttribute(ui::AX_ATTR_FONT_FAMILY, src.fontFamily().utf8()); | |
| 370 } | |
| 371 | |
| 372 // Font size is in pixels. | |
| 373 if (src.fontSize()) | |
| 374 dst->AddFloatAttribute(ui::AX_ATTR_FONT_SIZE, src.fontSize()); | |
| 375 | |
| 376 if (src.ariaCurrentState()) { | |
| 377 dst->AddIntAttribute(ui::AX_ATTR_ARIA_CURRENT_STATE, | |
| 378 AXAriaCurrentStateFromBlink(src.ariaCurrentState())); | |
| 379 } | |
| 380 | |
| 381 if (src.invalidState()) { | |
| 382 dst->AddIntAttribute(ui::AX_ATTR_INVALID_STATE, | |
| 383 AXInvalidStateFromBlink(src.invalidState())); | |
| 384 } | |
| 385 if (src.invalidState() == blink::WebAXInvalidStateOther && | |
| 386 src.ariaInvalidValue().length()) { | |
| 387 dst->AddStringAttribute( | |
| 388 ui::AX_ATTR_ARIA_INVALID_VALUE, src.ariaInvalidValue().utf8()); | |
| 389 } | |
| 390 | |
| 391 if (src.textDirection()) { | |
| 392 dst->AddIntAttribute(ui::AX_ATTR_TEXT_DIRECTION, | |
| 393 AXTextDirectionFromBlink(src.textDirection())); | |
| 394 } | |
| 395 | |
| 396 if (src.textStyle()) { | |
| 397 dst->AddIntAttribute(ui::AX_ATTR_TEXT_STYLE, | |
| 398 AXTextStyleFromBlink(src.textStyle())); | |
| 399 } | |
| 400 | |
| 401 | |
| 402 if (dst->role == ui::AX_ROLE_INLINE_TEXT_BOX) { | |
| 403 WebVector<int> src_character_offsets; | |
| 404 src.characterOffsets(src_character_offsets); | |
| 405 std::vector<int32_t> character_offsets; | |
| 406 character_offsets.reserve(src_character_offsets.size()); | |
| 407 for (size_t i = 0; i < src_character_offsets.size(); ++i) | |
| 408 character_offsets.push_back(src_character_offsets[i]); | |
| 409 dst->AddIntListAttribute(ui::AX_ATTR_CHARACTER_OFFSETS, character_offsets); | |
| 410 | |
| 411 WebVector<int> src_word_starts; | |
| 412 WebVector<int> src_word_ends; | |
| 413 src.wordBoundaries(src_word_starts, src_word_ends); | |
| 414 std::vector<int32_t> word_starts; | |
| 415 std::vector<int32_t> word_ends; | |
| 416 word_starts.reserve(src_word_starts.size()); | |
| 417 word_ends.reserve(src_word_starts.size()); | |
| 418 for (size_t i = 0; i < src_word_starts.size(); ++i) { | |
| 419 word_starts.push_back(src_word_starts[i]); | |
| 420 word_ends.push_back(src_word_ends[i]); | |
| 421 } | |
| 422 dst->AddIntListAttribute(ui::AX_ATTR_WORD_STARTS, word_starts); | |
| 423 dst->AddIntListAttribute(ui::AX_ATTR_WORD_ENDS, word_ends); | |
| 424 } | |
| 425 | |
| 426 if (src.accessKey().length()) { | |
| 427 dst->AddStringAttribute(ui::AX_ATTR_ACCESS_KEY, src.accessKey().utf8()); | |
| 428 } | |
| 429 | |
| 430 if (src.action() != blink::WebAXSupportedAction::None) { | |
| 431 dst->AddIntAttribute(ui::AX_ATTR_ACTION, | |
| 432 AXSupportedActionFromBlink(src.action())); | |
| 433 } | |
| 434 | |
| 435 if (src.ariaAutoComplete().length()) { | |
| 436 dst->AddStringAttribute( | |
| 437 ui::AX_ATTR_AUTO_COMPLETE, | |
| 438 src.ariaAutoComplete().utf8()); | |
| 439 } | |
| 440 | |
| 441 if (src.isAriaReadOnly()) | |
| 442 dst->AddBoolAttribute(ui::AX_ATTR_ARIA_READONLY, true); | |
| 443 | |
| 444 if (src.isButtonStateMixed()) | 353 if (src.isButtonStateMixed()) |
| 445 dst->AddBoolAttribute(ui::AX_ATTR_STATE_MIXED, true); | 354 dst->AddBoolAttribute(ui::AX_ATTR_STATE_MIXED, true); |
| 446 | 355 |
| 447 if (src.canSetValueAttribute()) | 356 if (src.canSetValueAttribute()) |
| 448 dst->AddBoolAttribute(ui::AX_ATTR_CAN_SET_VALUE, true); | 357 dst->AddBoolAttribute(ui::AX_ATTR_CAN_SET_VALUE, true); |
| 449 | 358 |
| 450 if (src.hasComputedStyle()) { | |
| 451 dst->AddStringAttribute( | |
| 452 ui::AX_ATTR_DISPLAY, src.computedStyleDisplay().utf8()); | |
| 453 } | |
| 454 | |
| 455 if (src.language().length()) { | |
| 456 if (parent.isNull() || parent.language() != src.language()) | |
| 457 dst->AddStringAttribute(ui::AX_ATTR_LANGUAGE, src.language().utf8()); | |
| 458 } | |
| 459 | |
| 460 if (src.keyboardShortcut().length()) { | |
| 461 dst->AddStringAttribute( | |
| 462 ui::AX_ATTR_SHORTCUT, | |
| 463 src.keyboardShortcut().utf8()); | |
| 464 } | |
| 465 | |
| 466 if (!src.nextOnLine().isDetached()) { | |
| 467 dst->AddIntAttribute(ui::AX_ATTR_NEXT_ON_LINE_ID, src.nextOnLine().axID()); | |
| 468 } | |
| 469 | |
| 470 if (!src.previousOnLine().isDetached()) { | |
| 471 dst->AddIntAttribute(ui::AX_ATTR_PREVIOUS_ON_LINE_ID, | |
| 472 src.previousOnLine().axID()); | |
| 473 } | |
| 474 | |
| 475 if (!src.ariaActiveDescendant().isDetached()) { | |
| 476 dst->AddIntAttribute(ui::AX_ATTR_ACTIVEDESCENDANT_ID, | |
| 477 src.ariaActiveDescendant().axID()); | |
| 478 } | |
| 479 | |
| 480 if (!src.url().isEmpty()) | 359 if (!src.url().isEmpty()) |
| 481 dst->AddStringAttribute(ui::AX_ATTR_URL, src.url().string().utf8()); | 360 dst->AddStringAttribute(ui::AX_ATTR_URL, src.url().string().utf8()); |
| 482 | 361 |
| 483 if (dst->role == ui::AX_ROLE_HEADING && src.headingLevel()) { | 362 // The following set of attributes are only accessed when the accessibility |
| 484 dst->AddIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL, src.headingLevel()); | 363 // mode is set to screen reader mode, otherwise only the more basic |
| 485 } else if ((dst->role == ui::AX_ROLE_TREE_ITEM || | 364 // attributes are populated. |
| 486 dst->role == ui::AX_ROLE_ROW) && | 365 if (accessibility_mode_ & ACCESSIBILITY_MODE_FLAG_SCREEN_READER) { |
| 487 src.hierarchicalLevel()) { | 366 blink::WebString web_placeholder = src.placeholder(nameFrom); |
| 488 dst->AddIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL, | 367 if (!web_placeholder.isEmpty()) |
| 489 src.hierarchicalLevel()); | 368 dst->AddStringAttribute(ui::AX_ATTR_PLACEHOLDER, web_placeholder.utf8()); |
| 369 |
| 370 if (dst->role == ui::AX_ROLE_COLOR_WELL) |
| 371 dst->AddIntAttribute(ui::AX_ATTR_COLOR_VALUE, src.colorValue()); |
| 372 |
| 373 // Text attributes. |
| 374 if (src.backgroundColor()) |
| 375 dst->AddIntAttribute(ui::AX_ATTR_BACKGROUND_COLOR, src.backgroundColor()); |
| 376 |
| 377 if (src.color()) |
| 378 dst->AddIntAttribute(ui::AX_ATTR_COLOR, src.color()); |
| 379 |
| 380 WebAXObject parent = ParentObjectUnignored(src); |
| 381 if (src.fontFamily().length()) { |
| 382 if (parent.isNull() || parent.fontFamily() != src.fontFamily()) |
| 383 dst->AddStringAttribute(ui::AX_ATTR_FONT_FAMILY, |
| 384 src.fontFamily().utf8()); |
| 385 } |
| 386 |
| 387 // Font size is in pixels. |
| 388 if (src.fontSize()) |
| 389 dst->AddFloatAttribute(ui::AX_ATTR_FONT_SIZE, src.fontSize()); |
| 390 |
| 391 if (src.ariaCurrentState()) { |
| 392 dst->AddIntAttribute(ui::AX_ATTR_ARIA_CURRENT_STATE, |
| 393 AXAriaCurrentStateFromBlink(src.ariaCurrentState())); |
| 394 } |
| 395 |
| 396 if (src.invalidState()) { |
| 397 dst->AddIntAttribute(ui::AX_ATTR_INVALID_STATE, |
| 398 AXInvalidStateFromBlink(src.invalidState())); |
| 399 } |
| 400 if (src.invalidState() == blink::WebAXInvalidStateOther && |
| 401 src.ariaInvalidValue().length()) { |
| 402 dst->AddStringAttribute( |
| 403 ui::AX_ATTR_ARIA_INVALID_VALUE, src.ariaInvalidValue().utf8()); |
| 404 } |
| 405 |
| 406 if (src.textDirection()) { |
| 407 dst->AddIntAttribute(ui::AX_ATTR_TEXT_DIRECTION, |
| 408 AXTextDirectionFromBlink(src.textDirection())); |
| 409 } |
| 410 |
| 411 if (src.textStyle()) { |
| 412 dst->AddIntAttribute(ui::AX_ATTR_TEXT_STYLE, |
| 413 AXTextStyleFromBlink(src.textStyle())); |
| 414 } |
| 415 |
| 416 if (dst->role == ui::AX_ROLE_INLINE_TEXT_BOX) { |
| 417 WebVector<int> src_character_offsets; |
| 418 src.characterOffsets(src_character_offsets); |
| 419 std::vector<int32_t> character_offsets; |
| 420 character_offsets.reserve(src_character_offsets.size()); |
| 421 for (size_t i = 0; i < src_character_offsets.size(); ++i) |
| 422 character_offsets.push_back(src_character_offsets[i]); |
| 423 dst->AddIntListAttribute(ui::AX_ATTR_CHARACTER_OFFSETS, |
| 424 character_offsets); |
| 425 |
| 426 WebVector<int> src_word_starts; |
| 427 WebVector<int> src_word_ends; |
| 428 src.wordBoundaries(src_word_starts, src_word_ends); |
| 429 std::vector<int32_t> word_starts; |
| 430 std::vector<int32_t> word_ends; |
| 431 word_starts.reserve(src_word_starts.size()); |
| 432 word_ends.reserve(src_word_starts.size()); |
| 433 for (size_t i = 0; i < src_word_starts.size(); ++i) { |
| 434 word_starts.push_back(src_word_starts[i]); |
| 435 word_ends.push_back(src_word_ends[i]); |
| 436 } |
| 437 dst->AddIntListAttribute(ui::AX_ATTR_WORD_STARTS, word_starts); |
| 438 dst->AddIntListAttribute(ui::AX_ATTR_WORD_ENDS, word_ends); |
| 439 } |
| 440 |
| 441 if (src.accessKey().length()) { |
| 442 dst->AddStringAttribute(ui::AX_ATTR_ACCESS_KEY, src.accessKey().utf8()); |
| 443 } |
| 444 |
| 445 if (src.ariaAutoComplete().length()) { |
| 446 dst->AddStringAttribute( |
| 447 ui::AX_ATTR_AUTO_COMPLETE, |
| 448 src.ariaAutoComplete().utf8()); |
| 449 } |
| 450 |
| 451 if (src.action() != blink::WebAXSupportedAction::None) { |
| 452 dst->AddIntAttribute(ui::AX_ATTR_ACTION, |
| 453 AXSupportedActionFromBlink(src.action())); |
| 454 } |
| 455 |
| 456 if (src.isAriaReadOnly()) |
| 457 dst->AddBoolAttribute(ui::AX_ATTR_ARIA_READONLY, true); |
| 458 |
| 459 if (src.hasComputedStyle()) { |
| 460 dst->AddStringAttribute( |
| 461 ui::AX_ATTR_DISPLAY, src.computedStyleDisplay().utf8()); |
| 462 } |
| 463 |
| 464 if (src.language().length()) { |
| 465 if (parent.isNull() || parent.language() != src.language()) |
| 466 dst->AddStringAttribute(ui::AX_ATTR_LANGUAGE, src.language().utf8()); |
| 467 } |
| 468 |
| 469 if (src.keyboardShortcut().length()) { |
| 470 dst->AddStringAttribute( |
| 471 ui::AX_ATTR_SHORTCUT, |
| 472 src.keyboardShortcut().utf8()); |
| 473 } |
| 474 |
| 475 if (!src.nextOnLine().isDetached()) { |
| 476 dst->AddIntAttribute(ui::AX_ATTR_NEXT_ON_LINE_ID, |
| 477 src.nextOnLine().axID()); |
| 478 } |
| 479 |
| 480 if (!src.previousOnLine().isDetached()) { |
| 481 dst->AddIntAttribute(ui::AX_ATTR_PREVIOUS_ON_LINE_ID, |
| 482 src.previousOnLine().axID()); |
| 483 } |
| 484 |
| 485 if (!src.ariaActiveDescendant().isDetached()) { |
| 486 dst->AddIntAttribute(ui::AX_ATTR_ACTIVEDESCENDANT_ID, |
| 487 src.ariaActiveDescendant().axID()); |
| 488 } |
| 489 |
| 490 if (dst->role == ui::AX_ROLE_HEADING && src.headingLevel()) { |
| 491 dst->AddIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL, src.headingLevel()); |
| 492 } else if ((dst->role == ui::AX_ROLE_TREE_ITEM || |
| 493 dst->role == ui::AX_ROLE_ROW) && |
| 494 src.hierarchicalLevel()) { |
| 495 dst->AddIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL, |
| 496 src.hierarchicalLevel()); |
| 497 } |
| 498 |
| 499 if (src.setSize()) |
| 500 dst->AddIntAttribute(ui::AX_ATTR_SET_SIZE, src.setSize()); |
| 501 |
| 502 if (src.posInSet()) |
| 503 dst->AddIntAttribute(ui::AX_ATTR_POS_IN_SET, src.posInSet()); |
| 504 |
| 505 if (src.canvasHasFallbackContent()) |
| 506 dst->AddBoolAttribute(ui::AX_ATTR_CANVAS_HAS_FALLBACK, true); |
| 507 |
| 508 // Spelling, grammar and other document markers. |
| 509 WebVector<blink::WebAXMarkerType> src_marker_types; |
| 510 WebVector<int> src_marker_starts; |
| 511 WebVector<int> src_marker_ends; |
| 512 src.markers(src_marker_types, src_marker_starts, src_marker_ends); |
| 513 DCHECK_EQ(src_marker_types.size(), src_marker_starts.size()); |
| 514 DCHECK_EQ(src_marker_starts.size(), src_marker_ends.size()); |
| 515 |
| 516 if (src_marker_types.size()) { |
| 517 std::vector<int32_t> marker_types; |
| 518 std::vector<int32_t> marker_starts; |
| 519 std::vector<int32_t> marker_ends; |
| 520 marker_types.reserve(src_marker_types.size()); |
| 521 marker_starts.reserve(src_marker_starts.size()); |
| 522 marker_ends.reserve(src_marker_ends.size()); |
| 523 for (size_t i = 0; i < src_marker_types.size(); ++i) { |
| 524 marker_types.push_back( |
| 525 static_cast<int32_t>(AXMarkerTypeFromBlink(src_marker_types[i]))); |
| 526 marker_starts.push_back(src_marker_starts[i]); |
| 527 marker_ends.push_back(src_marker_ends[i]); |
| 528 } |
| 529 dst->AddIntListAttribute(ui::AX_ATTR_MARKER_TYPES, marker_types); |
| 530 dst->AddIntListAttribute(ui::AX_ATTR_MARKER_STARTS, marker_starts); |
| 531 dst->AddIntListAttribute(ui::AX_ATTR_MARKER_ENDS, marker_ends); |
| 532 } |
| 533 |
| 534 if (src.isInLiveRegion()) { |
| 535 dst->AddBoolAttribute(ui::AX_ATTR_LIVE_ATOMIC, src.liveRegionAtomic()); |
| 536 dst->AddBoolAttribute(ui::AX_ATTR_LIVE_BUSY, src.liveRegionBusy()); |
| 537 if (src.liveRegionBusy()) |
| 538 dst->state |= (1 << ui::AX_STATE_BUSY); |
| 539 if (!src.liveRegionStatus().isEmpty()) { |
| 540 dst->AddStringAttribute( |
| 541 ui::AX_ATTR_LIVE_STATUS, |
| 542 src.liveRegionStatus().utf8()); |
| 543 } |
| 544 dst->AddStringAttribute( |
| 545 ui::AX_ATTR_LIVE_RELEVANT, |
| 546 src.liveRegionRelevant().utf8()); |
| 547 // If we are not at the root of an atomic live region. |
| 548 if (src.containerLiveRegionAtomic() && |
| 549 !src.liveRegionRoot().isDetached() && |
| 550 !src.liveRegionAtomic()) { |
| 551 dst->AddIntAttribute(ui::AX_ATTR_MEMBER_OF_ID, |
| 552 src.liveRegionRoot().axID()); |
| 553 } |
| 554 dst->AddBoolAttribute(ui::AX_ATTR_CONTAINER_LIVE_ATOMIC, |
| 555 src.containerLiveRegionAtomic()); |
| 556 dst->AddBoolAttribute(ui::AX_ATTR_CONTAINER_LIVE_BUSY, |
| 557 src.containerLiveRegionBusy()); |
| 558 dst->AddStringAttribute( |
| 559 ui::AX_ATTR_CONTAINER_LIVE_STATUS, |
| 560 src.containerLiveRegionStatus().utf8()); |
| 561 dst->AddStringAttribute( |
| 562 ui::AX_ATTR_CONTAINER_LIVE_RELEVANT, |
| 563 src.containerLiveRegionRelevant().utf8()); |
| 564 } |
| 565 |
| 566 if (dst->role == ui::AX_ROLE_PROGRESS_INDICATOR || |
| 567 dst->role == ui::AX_ROLE_METER || |
| 568 dst->role == ui::AX_ROLE_SCROLL_BAR || |
| 569 dst->role == ui::AX_ROLE_SLIDER || |
| 570 dst->role == ui::AX_ROLE_SPIN_BUTTON) { |
| 571 dst->AddFloatAttribute(ui::AX_ATTR_VALUE_FOR_RANGE, src.valueForRange()); |
| 572 dst->AddFloatAttribute(ui::AX_ATTR_MAX_VALUE_FOR_RANGE, |
| 573 src.maxValueForRange()); |
| 574 dst->AddFloatAttribute(ui::AX_ATTR_MIN_VALUE_FOR_RANGE, |
| 575 src.minValueForRange()); |
| 576 } |
| 577 |
| 578 if (dst->role == ui::AX_ROLE_ROOT_WEB_AREA) |
| 579 dst->AddStringAttribute(ui::AX_ATTR_HTML_TAG, "#document"); |
| 580 |
| 581 if (dst->role == ui::AX_ROLE_TABLE) { |
| 582 int column_count = src.columnCount(); |
| 583 int row_count = src.rowCount(); |
| 584 if (column_count > 0 && row_count > 0) { |
| 585 std::set<int32_t> unique_cell_id_set; |
| 586 std::vector<int32_t> cell_ids; |
| 587 std::vector<int32_t> unique_cell_ids; |
| 588 dst->AddIntAttribute(ui::AX_ATTR_TABLE_COLUMN_COUNT, column_count); |
| 589 dst->AddIntAttribute(ui::AX_ATTR_TABLE_ROW_COUNT, row_count); |
| 590 WebAXObject header = src.headerContainerObject(); |
| 591 if (!header.isDetached()) |
| 592 dst->AddIntAttribute(ui::AX_ATTR_TABLE_HEADER_ID, header.axID()); |
| 593 for (int i = 0; i < column_count * row_count; ++i) { |
| 594 WebAXObject cell = src.cellForColumnAndRow( |
| 595 i % column_count, i / column_count); |
| 596 int cell_id = -1; |
| 597 if (!cell.isDetached()) { |
| 598 cell_id = cell.axID(); |
| 599 if (unique_cell_id_set.find(cell_id) == unique_cell_id_set.end()) { |
| 600 unique_cell_id_set.insert(cell_id); |
| 601 unique_cell_ids.push_back(cell_id); |
| 602 } |
| 603 } |
| 604 cell_ids.push_back(cell_id); |
| 605 } |
| 606 dst->AddIntListAttribute(ui::AX_ATTR_CELL_IDS, cell_ids); |
| 607 dst->AddIntListAttribute(ui::AX_ATTR_UNIQUE_CELL_IDS, unique_cell_ids); |
| 608 } |
| 609 } |
| 610 |
| 611 if (dst->role == ui::AX_ROLE_ROW) { |
| 612 dst->AddIntAttribute(ui::AX_ATTR_TABLE_ROW_INDEX, src.rowIndex()); |
| 613 WebAXObject header = src.rowHeader(); |
| 614 if (!header.isDetached()) |
| 615 dst->AddIntAttribute(ui::AX_ATTR_TABLE_ROW_HEADER_ID, header.axID()); |
| 616 } |
| 617 |
| 618 if (dst->role == ui::AX_ROLE_COLUMN) { |
| 619 dst->AddIntAttribute(ui::AX_ATTR_TABLE_COLUMN_INDEX, src.columnIndex()); |
| 620 WebAXObject header = src.columnHeader(); |
| 621 if (!header.isDetached()) |
| 622 dst->AddIntAttribute(ui::AX_ATTR_TABLE_COLUMN_HEADER_ID, header.axID()); |
| 623 } |
| 624 |
| 625 if (dst->role == ui::AX_ROLE_CELL || |
| 626 dst->role == ui::AX_ROLE_ROW_HEADER || |
| 627 dst->role == ui::AX_ROLE_COLUMN_HEADER) { |
| 628 dst->AddIntAttribute(ui::AX_ATTR_TABLE_CELL_COLUMN_INDEX, |
| 629 src.cellColumnIndex()); |
| 630 dst->AddIntAttribute(ui::AX_ATTR_TABLE_CELL_COLUMN_SPAN, |
| 631 src.cellColumnSpan()); |
| 632 dst->AddIntAttribute(ui::AX_ATTR_TABLE_CELL_ROW_INDEX, |
| 633 src.cellRowIndex()); |
| 634 dst->AddIntAttribute(ui::AX_ATTR_TABLE_CELL_ROW_SPAN, src.cellRowSpan()); |
| 635 } |
| 636 |
| 637 if ((dst->role == ui::AX_ROLE_ROW_HEADER || |
| 638 dst->role == ui::AX_ROLE_COLUMN_HEADER) && src.sortDirection()) { |
| 639 dst->AddIntAttribute(ui::AX_ATTR_SORT_DIRECTION, |
| 640 AXSortDirectionFromBlink(src.sortDirection())); |
| 641 } |
| 490 } | 642 } |
| 491 | 643 |
| 492 if (src.setSize()) | 644 // The majority of the rest of this code computes attributes needed for |
| 493 dst->AddIntAttribute(ui::AX_ATTR_SET_SIZE, src.setSize()); | 645 // all modes, not just for screen readers. |
| 494 | |
| 495 if (src.posInSet()) | |
| 496 dst->AddIntAttribute(ui::AX_ATTR_POS_IN_SET, src.posInSet()); | |
| 497 | |
| 498 if (src.canvasHasFallbackContent()) | |
| 499 dst->AddBoolAttribute(ui::AX_ATTR_CANVAS_HAS_FALLBACK, true); | |
| 500 | |
| 501 // Spelling, grammar and other document markers. | |
| 502 WebVector<blink::WebAXMarkerType> src_marker_types; | |
| 503 WebVector<int> src_marker_starts; | |
| 504 WebVector<int> src_marker_ends; | |
| 505 src.markers(src_marker_types, src_marker_starts, src_marker_ends); | |
| 506 DCHECK_EQ(src_marker_types.size(), src_marker_starts.size()); | |
| 507 DCHECK_EQ(src_marker_starts.size(), src_marker_ends.size()); | |
| 508 | |
| 509 if (src_marker_types.size()) { | |
| 510 std::vector<int32_t> marker_types; | |
| 511 std::vector<int32_t> marker_starts; | |
| 512 std::vector<int32_t> marker_ends; | |
| 513 marker_types.reserve(src_marker_types.size()); | |
| 514 marker_starts.reserve(src_marker_starts.size()); | |
| 515 marker_ends.reserve(src_marker_ends.size()); | |
| 516 for (size_t i = 0; i < src_marker_types.size(); ++i) { | |
| 517 marker_types.push_back( | |
| 518 static_cast<int32_t>(AXMarkerTypeFromBlink(src_marker_types[i]))); | |
| 519 marker_starts.push_back(src_marker_starts[i]); | |
| 520 marker_ends.push_back(src_marker_ends[i]); | |
| 521 } | |
| 522 dst->AddIntListAttribute(ui::AX_ATTR_MARKER_TYPES, marker_types); | |
| 523 dst->AddIntListAttribute(ui::AX_ATTR_MARKER_STARTS, marker_starts); | |
| 524 dst->AddIntListAttribute(ui::AX_ATTR_MARKER_ENDS, marker_ends); | |
| 525 } | |
| 526 | 646 |
| 527 WebNode node = src.node(); | 647 WebNode node = src.node(); |
| 528 bool is_iframe = false; | 648 bool is_iframe = false; |
| 529 | 649 |
| 530 if (!node.isNull() && node.isElementNode()) { | 650 if (!node.isNull() && node.isElementNode()) { |
| 531 WebElement element = node.to<WebElement>(); | 651 WebElement element = node.to<WebElement>(); |
| 532 is_iframe = element.hasHTMLTagName("iframe"); | 652 is_iframe = element.hasHTMLTagName("iframe"); |
| 533 | 653 |
| 534 // TODO(ctguil): The tagName in WebKit is lower cased but | 654 if (accessibility_mode_ & ACCESSIBILITY_MODE_FLAG_HTML) { |
| 535 // HTMLElement::nodeName calls localNameUpper. Consider adding | 655 // TODO(ctguil): The tagName in WebKit is lower cased but |
| 536 // a WebElement method that returns the original lower cased tagName. | 656 // HTMLElement::nodeName calls localNameUpper. Consider adding |
| 537 dst->AddStringAttribute( | 657 // a WebElement method that returns the original lower cased tagName. |
| 538 ui::AX_ATTR_HTML_TAG, | 658 dst->AddStringAttribute( |
| 539 base::ToLowerASCII(element.tagName().utf8())); | 659 ui::AX_ATTR_HTML_TAG, |
| 540 for (unsigned i = 0; i < element.attributeCount(); ++i) { | 660 base::ToLowerASCII(element.tagName().utf8())); |
| 541 std::string name = base::ToLowerASCII( | 661 for (unsigned i = 0; i < element.attributeCount(); ++i) { |
| 542 element.attributeLocalName(i).utf8()); | 662 std::string name = base::ToLowerASCII( |
| 543 std::string value = element.attributeValue(i).utf8(); | 663 element.attributeLocalName(i).utf8()); |
| 544 dst->html_attributes.push_back(std::make_pair(name, value)); | 664 std::string value = element.attributeValue(i).utf8(); |
| 665 dst->html_attributes.push_back(std::make_pair(name, value)); |
| 666 } |
| 545 } | 667 } |
| 546 | 668 |
| 547 if (src.isEditable()) { | 669 if (src.isEditable()) { |
| 548 dst->AddIntAttribute(ui::AX_ATTR_TEXT_SEL_START, src.selectionStart()); | 670 dst->AddIntAttribute(ui::AX_ATTR_TEXT_SEL_START, src.selectionStart()); |
| 549 dst->AddIntAttribute(ui::AX_ATTR_TEXT_SEL_END, src.selectionEnd()); | 671 dst->AddIntAttribute(ui::AX_ATTR_TEXT_SEL_END, src.selectionEnd()); |
| 550 | 672 |
| 551 #if defined(OS_CHROMEOS) | 673 #if defined(OS_CHROMEOS) |
| 552 // This attribute will soon be deprecated; see crbug.com/669134. | 674 // This attribute will soon be deprecated; see crbug.com/669134. |
| 553 WebVector<int> src_line_breaks; | 675 WebVector<int> src_line_breaks; |
| 554 src.lineBreaks(src_line_breaks); | 676 src.lineBreaks(src_line_breaks); |
| (...skipping 30 matching lines...) Expand all Loading... |
| 585 | 707 |
| 586 // Frames and iframes. | 708 // Frames and iframes. |
| 587 WebFrame* frame = WebFrame::fromFrameOwnerElement(element); | 709 WebFrame* frame = WebFrame::fromFrameOwnerElement(element); |
| 588 if (frame) { | 710 if (frame) { |
| 589 dst->AddContentIntAttribute( | 711 dst->AddContentIntAttribute( |
| 590 AX_CONTENT_ATTR_CHILD_ROUTING_ID, | 712 AX_CONTENT_ATTR_CHILD_ROUTING_ID, |
| 591 GetRoutingIdForFrameOrProxy(frame)); | 713 GetRoutingIdForFrameOrProxy(frame)); |
| 592 } | 714 } |
| 593 } | 715 } |
| 594 | 716 |
| 595 if (src.isInLiveRegion()) { | |
| 596 dst->AddBoolAttribute(ui::AX_ATTR_LIVE_ATOMIC, src.liveRegionAtomic()); | |
| 597 dst->AddBoolAttribute(ui::AX_ATTR_LIVE_BUSY, src.liveRegionBusy()); | |
| 598 if (src.liveRegionBusy()) | |
| 599 dst->state |= (1 << ui::AX_STATE_BUSY); | |
| 600 if (!src.liveRegionStatus().isEmpty()) { | |
| 601 dst->AddStringAttribute( | |
| 602 ui::AX_ATTR_LIVE_STATUS, | |
| 603 src.liveRegionStatus().utf8()); | |
| 604 } | |
| 605 dst->AddStringAttribute( | |
| 606 ui::AX_ATTR_LIVE_RELEVANT, | |
| 607 src.liveRegionRelevant().utf8()); | |
| 608 // If we are not at the root of an atomic live region. | |
| 609 if (src.containerLiveRegionAtomic() && !src.liveRegionRoot().isDetached() && | |
| 610 !src.liveRegionAtomic()) { | |
| 611 dst->AddIntAttribute(ui::AX_ATTR_MEMBER_OF_ID, | |
| 612 src.liveRegionRoot().axID()); | |
| 613 } | |
| 614 dst->AddBoolAttribute(ui::AX_ATTR_CONTAINER_LIVE_ATOMIC, | |
| 615 src.containerLiveRegionAtomic()); | |
| 616 dst->AddBoolAttribute(ui::AX_ATTR_CONTAINER_LIVE_BUSY, | |
| 617 src.containerLiveRegionBusy()); | |
| 618 dst->AddStringAttribute( | |
| 619 ui::AX_ATTR_CONTAINER_LIVE_STATUS, | |
| 620 src.containerLiveRegionStatus().utf8()); | |
| 621 dst->AddStringAttribute( | |
| 622 ui::AX_ATTR_CONTAINER_LIVE_RELEVANT, | |
| 623 src.containerLiveRegionRelevant().utf8()); | |
| 624 } | |
| 625 | |
| 626 if (dst->role == ui::AX_ROLE_PROGRESS_INDICATOR || | |
| 627 dst->role == ui::AX_ROLE_METER || | |
| 628 dst->role == ui::AX_ROLE_SCROLL_BAR || | |
| 629 dst->role == ui::AX_ROLE_SLIDER || | |
| 630 dst->role == ui::AX_ROLE_SPIN_BUTTON) { | |
| 631 dst->AddFloatAttribute(ui::AX_ATTR_VALUE_FOR_RANGE, src.valueForRange()); | |
| 632 dst->AddFloatAttribute(ui::AX_ATTR_MAX_VALUE_FOR_RANGE, | |
| 633 src.maxValueForRange()); | |
| 634 dst->AddFloatAttribute(ui::AX_ATTR_MIN_VALUE_FOR_RANGE, | |
| 635 src.minValueForRange()); | |
| 636 } | |
| 637 | |
| 638 if (dst->role == ui::AX_ROLE_ROOT_WEB_AREA) | |
| 639 dst->AddStringAttribute(ui::AX_ATTR_HTML_TAG, "#document"); | |
| 640 | |
| 641 if (dst->role == ui::AX_ROLE_TABLE) { | |
| 642 int column_count = src.columnCount(); | |
| 643 int row_count = src.rowCount(); | |
| 644 if (column_count > 0 && row_count > 0) { | |
| 645 std::set<int32_t> unique_cell_id_set; | |
| 646 std::vector<int32_t> cell_ids; | |
| 647 std::vector<int32_t> unique_cell_ids; | |
| 648 dst->AddIntAttribute(ui::AX_ATTR_TABLE_COLUMN_COUNT, column_count); | |
| 649 dst->AddIntAttribute(ui::AX_ATTR_TABLE_ROW_COUNT, row_count); | |
| 650 WebAXObject header = src.headerContainerObject(); | |
| 651 if (!header.isDetached()) | |
| 652 dst->AddIntAttribute(ui::AX_ATTR_TABLE_HEADER_ID, header.axID()); | |
| 653 for (int i = 0; i < column_count * row_count; ++i) { | |
| 654 WebAXObject cell = src.cellForColumnAndRow( | |
| 655 i % column_count, i / column_count); | |
| 656 int cell_id = -1; | |
| 657 if (!cell.isDetached()) { | |
| 658 cell_id = cell.axID(); | |
| 659 if (unique_cell_id_set.find(cell_id) == unique_cell_id_set.end()) { | |
| 660 unique_cell_id_set.insert(cell_id); | |
| 661 unique_cell_ids.push_back(cell_id); | |
| 662 } | |
| 663 } | |
| 664 cell_ids.push_back(cell_id); | |
| 665 } | |
| 666 dst->AddIntListAttribute(ui::AX_ATTR_CELL_IDS, cell_ids); | |
| 667 dst->AddIntListAttribute(ui::AX_ATTR_UNIQUE_CELL_IDS, unique_cell_ids); | |
| 668 } | |
| 669 } | |
| 670 | |
| 671 if (dst->role == ui::AX_ROLE_ROW) { | |
| 672 dst->AddIntAttribute(ui::AX_ATTR_TABLE_ROW_INDEX, src.rowIndex()); | |
| 673 WebAXObject header = src.rowHeader(); | |
| 674 if (!header.isDetached()) | |
| 675 dst->AddIntAttribute(ui::AX_ATTR_TABLE_ROW_HEADER_ID, header.axID()); | |
| 676 } | |
| 677 | |
| 678 if (dst->role == ui::AX_ROLE_COLUMN) { | |
| 679 dst->AddIntAttribute(ui::AX_ATTR_TABLE_COLUMN_INDEX, src.columnIndex()); | |
| 680 WebAXObject header = src.columnHeader(); | |
| 681 if (!header.isDetached()) | |
| 682 dst->AddIntAttribute(ui::AX_ATTR_TABLE_COLUMN_HEADER_ID, header.axID()); | |
| 683 } | |
| 684 | |
| 685 if (dst->role == ui::AX_ROLE_CELL || | |
| 686 dst->role == ui::AX_ROLE_ROW_HEADER || | |
| 687 dst->role == ui::AX_ROLE_COLUMN_HEADER) { | |
| 688 dst->AddIntAttribute(ui::AX_ATTR_TABLE_CELL_COLUMN_INDEX, | |
| 689 src.cellColumnIndex()); | |
| 690 dst->AddIntAttribute(ui::AX_ATTR_TABLE_CELL_COLUMN_SPAN, | |
| 691 src.cellColumnSpan()); | |
| 692 dst->AddIntAttribute(ui::AX_ATTR_TABLE_CELL_ROW_INDEX, src.cellRowIndex()); | |
| 693 dst->AddIntAttribute(ui::AX_ATTR_TABLE_CELL_ROW_SPAN, src.cellRowSpan()); | |
| 694 } | |
| 695 | |
| 696 if ((dst->role == ui::AX_ROLE_ROW_HEADER || | |
| 697 dst->role == ui::AX_ROLE_COLUMN_HEADER) && src.sortDirection()) { | |
| 698 dst->AddIntAttribute(ui::AX_ATTR_SORT_DIRECTION, | |
| 699 AXSortDirectionFromBlink(src.sortDirection())); | |
| 700 } | |
| 701 | |
| 702 // Add the ids of *indirect* children - those who are children of this node, | 717 // Add the ids of *indirect* children - those who are children of this node, |
| 703 // but whose parent is *not* this node. One example is a table | 718 // but whose parent is *not* this node. One example is a table |
| 704 // cell, which is a child of both a row and a column. Because the cell's | 719 // cell, which is a child of both a row and a column. Because the cell's |
| 705 // parent is the row, the row adds it as a child, and the column adds it | 720 // parent is the row, the row adds it as a child, and the column adds it |
| 706 // as an indirect child. | 721 // as an indirect child. |
| 707 int child_count = src.childCount(); | 722 int child_count = src.childCount(); |
| 708 for (int i = 0; i < child_count; ++i) { | 723 for (int i = 0; i < child_count; ++i) { |
| 709 WebAXObject child = src.childAt(i); | 724 WebAXObject child = src.childAt(i); |
| 710 std::vector<int32_t> indirect_child_ids; | 725 std::vector<int32_t> indirect_child_ids; |
| 711 if (!is_iframe && !child.isDetached() && !IsParentUnignoredOf(src, child)) | 726 if (!is_iframe && !child.isDetached() && !IsParentUnignoredOf(src, child)) |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 757 return WebAXObject(); | 772 return WebAXObject(); |
| 758 | 773 |
| 759 WebDocument document = render_frame_->GetWebFrame()->document(); | 774 WebDocument document = render_frame_->GetWebFrame()->document(); |
| 760 if (!document.isNull()) | 775 if (!document.isNull()) |
| 761 return document.accessibilityObject(); | 776 return document.accessibilityObject(); |
| 762 | 777 |
| 763 return WebAXObject(); | 778 return WebAXObject(); |
| 764 } | 779 } |
| 765 | 780 |
| 766 } // namespace content | 781 } // namespace content |
| OLD | NEW |