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 |