Chromium Code Reviews| 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/browser/accessibility/browser_accessibility.h" | 5 #include "content/browser/accessibility/browser_accessibility.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 | 8 |
| 9 #include <algorithm> | 9 #include <algorithm> |
| 10 | 10 |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 97 return false; | 97 return false; |
| 98 } | 98 } |
| 99 | 99 |
| 100 bool BrowserAccessibility::IsTextOnlyObject() const { | 100 bool BrowserAccessibility::IsTextOnlyObject() const { |
| 101 return GetRole() == ui::AX_ROLE_STATIC_TEXT || | 101 return GetRole() == ui::AX_ROLE_STATIC_TEXT || |
| 102 GetRole() == ui::AX_ROLE_LINE_BREAK; | 102 GetRole() == ui::AX_ROLE_LINE_BREAK; |
| 103 } | 103 } |
| 104 | 104 |
| 105 BrowserAccessibility* BrowserAccessibility::PlatformGetChild( | 105 BrowserAccessibility* BrowserAccessibility::PlatformGetChild( |
| 106 uint32_t child_index) const { | 106 uint32_t child_index) const { |
| 107 DCHECK(child_index < PlatformChildCount()); | 107 DCHECK_LT(child_index, PlatformChildCount()); |
| 108 BrowserAccessibility* result = nullptr; | 108 BrowserAccessibility* result = nullptr; |
| 109 | 109 |
| 110 if (HasIntAttribute(ui::AX_ATTR_CHILD_TREE_ID)) { | 110 if (HasIntAttribute(ui::AX_ATTR_CHILD_TREE_ID)) { |
| 111 BrowserAccessibilityManager* child_manager = | 111 BrowserAccessibilityManager* child_manager = |
| 112 BrowserAccessibilityManager::FromID( | 112 BrowserAccessibilityManager::FromID( |
| 113 GetIntAttribute(ui::AX_ATTR_CHILD_TREE_ID)); | 113 GetIntAttribute(ui::AX_ATTR_CHILD_TREE_ID)); |
| 114 if (child_manager) | 114 if (child_manager) |
| 115 result = child_manager->GetRoot(); | 115 result = child_manager->GetRoot(); |
| 116 } else { | 116 } else { |
| 117 result = InternalGetChild(child_index); | 117 result = InternalGetChild(child_index); |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 254 // Adjust the bounds by the top left corner of the containing view's bounds | 254 // Adjust the bounds by the top left corner of the containing view's bounds |
| 255 // in screen coordinates. | 255 // in screen coordinates. |
| 256 bounds.Offset(manager_->GetViewBounds().OffsetFromOrigin()); | 256 bounds.Offset(manager_->GetViewBounds().OffsetFromOrigin()); |
| 257 | 257 |
| 258 return bounds; | 258 return bounds; |
| 259 } | 259 } |
| 260 | 260 |
| 261 gfx::Rect BrowserAccessibility::GetLocalBoundsForRange(int start, int len) | 261 gfx::Rect BrowserAccessibility::GetLocalBoundsForRange(int start, int len) |
| 262 const { | 262 const { |
| 263 if (GetRole() != ui::AX_ROLE_STATIC_TEXT) { | 263 if (GetRole() != ui::AX_ROLE_STATIC_TEXT) { |
| 264 // Apply recursively to all static text descendants. For example, if | |
| 265 // you call it on a div with two text node children, it just calls | |
| 266 // GetLocalBoundsForRange on each of the two children (adjusting | |
| 267 // |start| for each one) and unions the resulting rects. | |
| 268 gfx::Rect bounds; | 264 gfx::Rect bounds; |
| 269 for (size_t i = 0; i < InternalChildCount(); ++i) { | 265 for (size_t i = 0; i < InternalChildCount() && start >= 0; ++i) { |
| 270 BrowserAccessibility* child = InternalGetChild(i); | 266 BrowserAccessibility* child = InternalGetChild(i); |
| 271 int child_len = child->GetInnerTextLength(); | 267 // Embedded objects are of length one, since they are represented only by |
|
dmazzoni
2016/01/20 01:10:43
This comment confuses me. It talks about embedded
| |
| 272 if (start < child_len && start + len > 0) { | 268 // a special character. |
| 273 gfx::Rect child_rect = child->GetLocalBoundsForRange(start, len); | 269 int child_length_in_parent = |
| 270 child->IsTextOnlyObject() ? static_cast<int>(child->GetText().size()) | |
| 271 : 1; | |
| 272 if (start < child_length_in_parent) { | |
| 273 gfx::Rect child_rect; | |
| 274 if (child->IsTextOnlyObject()) | |
| 275 child_rect = child->GetLocalBoundsForRange(start, len); | |
| 276 else | |
|
dmazzoni
2016/01/20 01:10:43
nit: Need braces around both blocks
| |
| 277 child_rect = child->GetLocalBoundsForRange( | |
| 278 start, static_cast<int>(child->GetText().size())); | |
| 274 bounds.Union(child_rect); | 279 bounds.Union(child_rect); |
| 280 len -= child_length_in_parent; | |
| 275 } | 281 } |
| 276 start -= child_len; | 282 start -= child_length_in_parent; |
| 277 } | 283 } |
| 278 return ElementBoundsToLocalBounds(bounds); | 284 return ElementBoundsToLocalBounds(bounds); |
| 279 } | 285 } |
| 280 | 286 |
| 281 int end = start + len; | 287 int end = start + len; |
| 282 int child_start = 0; | 288 int child_start = 0; |
| 283 int child_end = 0; | 289 int child_end = 0; |
| 284 | 290 |
| 285 gfx::Rect bounds; | 291 gfx::Rect bounds; |
| 286 for (size_t i = 0; i < InternalChildCount() && child_end < start + len; ++i) { | 292 for (size_t i = 0; i < InternalChildCount() && child_end < start + len; ++i) { |
| 287 BrowserAccessibility* child = InternalGetChild(i); | 293 BrowserAccessibility* child = InternalGetChild(i); |
| 288 if (child->GetRole() != ui::AX_ROLE_INLINE_TEXT_BOX) { | 294 if (child->GetRole() != ui::AX_ROLE_INLINE_TEXT_BOX) { |
| 289 DLOG(WARNING) << "BrowserAccessibility objects with role STATIC_TEXT " << | 295 DLOG(WARNING) << "BrowserAccessibility objects with role STATIC_TEXT " << |
| 290 "should have children of role INLINE_TEXT_BOX."; | 296 "should have children of role INLINE_TEXT_BOX."; |
| 291 continue; | 297 continue; |
| 292 } | 298 } |
| 293 | 299 |
| 294 std::string child_text; | 300 int child_len = static_cast<int>(GetText().size()); |
| 295 child->GetStringAttribute(ui::AX_ATTR_NAME, &child_text); | |
| 296 int child_len = static_cast<int>(child_text.size()); | |
| 297 child_start = child_end; | 301 child_start = child_end; |
| 298 child_end += child_len; | 302 child_end += child_len; |
| 299 | 303 |
| 300 if (child_end < start) | 304 if (child_end < start) |
| 301 continue; | 305 continue; |
| 302 | 306 |
| 303 int overlap_start = std::max(start, child_start); | 307 int overlap_start = std::max(start, child_start); |
| 304 int overlap_end = std::min(end, child_end); | 308 int overlap_end = std::min(end, child_end); |
| 305 | 309 |
| 306 int local_start = overlap_start - child_start; | 310 int local_start = overlap_start - child_start; |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 375 base::string16 value = GetString16Attribute(ui::AX_ATTR_VALUE); | 379 base::string16 value = GetString16Attribute(ui::AX_ATTR_VALUE); |
| 376 if (value.empty() && IsSimpleTextControl()) | 380 if (value.empty() && IsSimpleTextControl()) |
| 377 value = GetInnerText(); | 381 value = GetInnerText(); |
| 378 return value; | 382 return value; |
| 379 } | 383 } |
| 380 | 384 |
| 381 int BrowserAccessibility::GetWordStartBoundary( | 385 int BrowserAccessibility::GetWordStartBoundary( |
| 382 int start, ui::TextBoundaryDirection direction) const { | 386 int start, ui::TextBoundaryDirection direction) const { |
| 383 DCHECK_GE(start, -1); | 387 DCHECK_GE(start, -1); |
| 384 // Special offset that indicates that a word boundary has not been found. | 388 // Special offset that indicates that a word boundary has not been found. |
| 385 int word_start_not_found = GetInnerTextLength(); | 389 int word_start_not_found = static_cast<int>(GetText().size()); |
| 386 int word_start = word_start_not_found; | 390 int word_start = word_start_not_found; |
| 387 | 391 |
| 388 switch (GetRole()) { | 392 switch (GetRole()) { |
| 389 case ui::AX_ROLE_STATIC_TEXT: { | 393 case ui::AX_ROLE_STATIC_TEXT: { |
| 390 int prev_word_start = word_start_not_found; | 394 int prev_word_start = word_start_not_found; |
| 391 int child_start = 0; | 395 int child_start = 0; |
| 392 int child_end = 0; | 396 int child_end = 0; |
| 393 | 397 |
| 394 // Go through the inline text boxes. | 398 // Go through the inline text boxes. |
| 395 for (size_t i = 0; i < InternalChildCount(); ++i) { | 399 for (size_t i = 0; i < InternalChildCount(); ++i) { |
| 396 // The next child starts where the previous one ended. | 400 // The next child starts where the previous one ended. |
| 397 child_start = child_end; | 401 child_start = child_end; |
| 398 BrowserAccessibility* child = InternalGetChild(i); | 402 BrowserAccessibility* child = InternalGetChild(i); |
| 399 DCHECK_EQ(child->GetRole(), ui::AX_ROLE_INLINE_TEXT_BOX); | 403 DCHECK_EQ(child->GetRole(), ui::AX_ROLE_INLINE_TEXT_BOX); |
| 400 const std::string& child_text = child->GetStringAttribute( | 404 int child_len = static_cast<int>(GetText().size()); |
| 401 ui::AX_ATTR_NAME); | |
| 402 int child_len = static_cast<int>(child_text.size()); | |
| 403 child_end += child_len; // End is one past the last character. | 405 child_end += child_len; // End is one past the last character. |
| 404 | 406 |
| 405 const std::vector<int32_t>& word_starts = | 407 const std::vector<int32_t>& word_starts = |
| 406 child->GetIntListAttribute(ui::AX_ATTR_WORD_STARTS); | 408 child->GetIntListAttribute(ui::AX_ATTR_WORD_STARTS); |
| 407 if (word_starts.empty()) { | 409 if (word_starts.empty()) { |
| 408 word_start = child_end; | 410 word_start = child_end; |
| 409 continue; | 411 continue; |
| 410 } | 412 } |
| 411 | 413 |
| 412 int local_start = start - child_start; | 414 int local_start = start - child_start; |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 448 | 450 |
| 449 default: | 451 default: |
| 450 // If there are no children, the word start boundary is still unknown or | 452 // If there are no children, the word start boundary is still unknown or |
| 451 // found previously depending on the direction. | 453 // found previously depending on the direction. |
| 452 if (!InternalChildCount()) | 454 if (!InternalChildCount()) |
| 453 return word_start_not_found; | 455 return word_start_not_found; |
| 454 | 456 |
| 455 int child_start = 0; | 457 int child_start = 0; |
| 456 for (size_t i = 0; i < InternalChildCount(); ++i) { | 458 for (size_t i = 0; i < InternalChildCount(); ++i) { |
| 457 BrowserAccessibility* child = InternalGetChild(i); | 459 BrowserAccessibility* child = InternalGetChild(i); |
| 458 int child_len = child->GetInnerTextLength(); | 460 // An embedded object is always represented by a single special |
| 459 int child_word_start = child->GetWordStartBoundary(start, direction); | 461 // character. |
| 460 if (child_word_start < child_len) { | 462 int child_len = 1; |
| 461 // We have found a possible word boundary. | 463 if (child->IsTextOnlyObject()) { |
| 462 word_start = child_start + child_word_start; | 464 child_len = static_cast<int>(child->GetText().size()); |
| 463 } | 465 int child_word_start = child->GetWordStartBoundary(start, direction); |
| 466 if (child_word_start < child_len) { | |
| 467 // We have found a possible word boundary. | |
| 468 word_start = child_start + child_word_start; | |
| 469 } | |
| 464 | 470 |
| 465 // Decide when to stop searching. | 471 // Decide when to stop searching. |
| 466 if ((word_start != word_start_not_found && | 472 if ((word_start != word_start_not_found && |
| 467 direction == ui::FORWARDS_DIRECTION) || | 473 direction == ui::FORWARDS_DIRECTION) || |
| 468 (start < child_len && | 474 (start < child_len && direction == ui::BACKWARDS_DIRECTION)) { |
| 469 direction == ui::BACKWARDS_DIRECTION)) { | 475 break; |
| 470 break; | 476 } |
| 471 } | 477 } |
| 472 | 478 |
| 473 child_start += child_len; | 479 child_start += child_len; |
| 474 if (start >= child_len) | 480 if (start >= child_len) |
| 475 start -= child_len; | 481 start -= child_len; |
| 476 else | 482 else |
| 477 start = -1; | 483 start = -1; |
| 478 } | 484 } |
| 479 return word_start; | 485 return word_start; |
| 480 } | 486 } |
| (...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 649 } | 655 } |
| 650 | 656 |
| 651 *is_defined = true; | 657 *is_defined = true; |
| 652 | 658 |
| 653 if (base::EqualsASCII(value, "true")) | 659 if (base::EqualsASCII(value, "true")) |
| 654 return true; | 660 return true; |
| 655 | 661 |
| 656 if (base::EqualsASCII(value, "mixed")) | 662 if (base::EqualsASCII(value, "mixed")) |
| 657 *is_mixed = true; | 663 *is_mixed = true; |
| 658 | 664 |
| 659 return false; // Not set | 665 return false; // Not set. |
| 660 } | 666 } |
| 661 | 667 |
| 662 bool BrowserAccessibility::HasState(ui::AXState state_enum) const { | 668 bool BrowserAccessibility::HasState(ui::AXState state_enum) const { |
| 663 return (GetState() >> state_enum) & 1; | 669 return (GetState() >> state_enum) & 1; |
| 664 } | 670 } |
| 665 | 671 |
| 666 bool BrowserAccessibility::IsCellOrTableHeaderRole() const { | 672 bool BrowserAccessibility::IsCellOrTableHeaderRole() const { |
| 667 return (GetRole() == ui::AX_ROLE_CELL || | 673 return (GetRole() == ui::AX_ROLE_CELL || |
| 668 GetRole() == ui::AX_ROLE_COLUMN_HEADER || | 674 GetRole() == ui::AX_ROLE_COLUMN_HEADER || |
| 669 GetRole() == ui::AX_ROLE_ROW_HEADER); | 675 GetRole() == ui::AX_ROLE_ROW_HEADER); |
| 670 } | 676 } |
| 671 | 677 |
| 672 bool BrowserAccessibility::HasCaret() const { | 678 bool BrowserAccessibility::HasCaret() const { |
| 673 if (IsEditableText() && !HasState(ui::AX_STATE_RICHLY_EDITABLE) && | 679 if (HasState(ui::AX_STATE_EDITABLE) && |
| 680 !HasState(ui::AX_STATE_RICHLY_EDITABLE) && | |
| 674 HasIntAttribute(ui::AX_ATTR_TEXT_SEL_START) && | 681 HasIntAttribute(ui::AX_ATTR_TEXT_SEL_START) && |
| 675 HasIntAttribute(ui::AX_ATTR_TEXT_SEL_END)) { | 682 HasIntAttribute(ui::AX_ATTR_TEXT_SEL_END)) { |
| 676 return true; | 683 return true; |
| 677 } | 684 } |
| 678 | 685 |
| 679 // The caret is always at the focus of the selection. | 686 // The caret is always at the focus of the selection. |
| 680 int32_t focus_id = manager()->GetTreeData().sel_focus_object_id; | 687 int32_t focus_id = manager()->GetTreeData().sel_focus_object_id; |
| 681 BrowserAccessibility* focus_object = manager()->GetFromID(focus_id); | 688 BrowserAccessibility* focus_object = manager()->GetFromID(focus_id); |
| 682 if (!focus_object) | 689 if (!focus_object) |
| 683 return false; | 690 return false; |
| 684 | 691 |
| 685 if (!focus_object->IsDescendantOf(this)) | 692 if (!focus_object->IsDescendantOf(this)) |
| 686 return false; | 693 return false; |
| 687 | 694 |
| 688 return true; | 695 return true; |
| 689 } | 696 } |
| 690 | 697 |
| 691 bool BrowserAccessibility::IsEditableText() const { | |
| 692 return HasState(ui::AX_STATE_EDITABLE); | |
| 693 } | |
| 694 | |
| 695 bool BrowserAccessibility::IsWebAreaForPresentationalIframe() const { | 698 bool BrowserAccessibility::IsWebAreaForPresentationalIframe() const { |
| 696 if (GetRole() != ui::AX_ROLE_WEB_AREA && | 699 if (GetRole() != ui::AX_ROLE_WEB_AREA && |
| 697 GetRole() != ui::AX_ROLE_ROOT_WEB_AREA) { | 700 GetRole() != ui::AX_ROLE_ROOT_WEB_AREA) { |
| 698 return false; | 701 return false; |
| 699 } | 702 } |
| 700 | 703 |
| 701 BrowserAccessibility* parent = GetParent(); | 704 BrowserAccessibility* parent = GetParent(); |
| 702 if (!parent) | 705 if (!parent) |
| 703 return false; | 706 return false; |
| 704 | 707 |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 785 base::string16 BrowserAccessibility::GetInnerText() const { | 788 base::string16 BrowserAccessibility::GetInnerText() const { |
| 786 if (IsTextOnlyObject()) | 789 if (IsTextOnlyObject()) |
| 787 return GetString16Attribute(ui::AX_ATTR_NAME); | 790 return GetString16Attribute(ui::AX_ATTR_NAME); |
| 788 | 791 |
| 789 base::string16 text; | 792 base::string16 text; |
| 790 for (size_t i = 0; i < InternalChildCount(); ++i) | 793 for (size_t i = 0; i < InternalChildCount(); ++i) |
| 791 text += InternalGetChild(i)->GetInnerText(); | 794 text += InternalGetChild(i)->GetInnerText(); |
| 792 return text; | 795 return text; |
| 793 } | 796 } |
| 794 | 797 |
| 795 int BrowserAccessibility::GetInnerTextLength() const { | |
| 796 return static_cast<int>(GetInnerText().size()); | |
| 797 } | |
| 798 | |
| 799 void BrowserAccessibility::FixEmptyBounds(gfx::Rect* bounds) const | 798 void BrowserAccessibility::FixEmptyBounds(gfx::Rect* bounds) const |
| 800 { | 799 { |
| 801 if (bounds->width() > 0 && bounds->height() > 0) | 800 if (bounds->width() > 0 && bounds->height() > 0) |
| 802 return; | 801 return; |
| 803 | 802 |
| 804 for (size_t i = 0; i < InternalChildCount(); ++i) { | 803 for (size_t i = 0; i < InternalChildCount(); ++i) { |
| 805 // Compute the bounds of each child - this calls FixEmptyBounds | 804 // Compute the bounds of each child - this calls FixEmptyBounds |
| 806 // recursively if necessary. | 805 // recursively if necessary. |
| 807 BrowserAccessibility* child = InternalGetChild(i); | 806 BrowserAccessibility* child = InternalGetChild(i); |
| 808 gfx::Rect child_bounds = child->GetLocalBoundsRect(); | 807 gfx::Rect child_bounds = child->GetLocalBoundsRect(); |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 856 } | 855 } |
| 857 need_to_offset_web_area = true; | 856 need_to_offset_web_area = true; |
| 858 } | 857 } |
| 859 parent = parent->GetParent(); | 858 parent = parent->GetParent(); |
| 860 } | 859 } |
| 861 | 860 |
| 862 return bounds; | 861 return bounds; |
| 863 } | 862 } |
| 864 | 863 |
| 865 } // namespace content | 864 } // namespace content |
| OLD | NEW |