| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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_android.h" | 5 #include "content/browser/accessibility/browser_accessibility_android.h" |
| 6 | 6 |
| 7 #include "base/i18n/break_iterator.h" | 7 #include "base/i18n/break_iterator.h" |
| 8 #include "base/strings/string_util.h" | 8 #include "base/strings/string_util.h" |
| 9 #include "base/strings/stringprintf.h" | 9 #include "base/strings/stringprintf.h" |
| 10 #include "base/strings/utf_string_conversions.h" | 10 #include "base/strings/utf_string_conversions.h" |
| (...skipping 354 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 365 } | 365 } |
| 366 | 366 |
| 367 if (text.empty()) | 367 if (text.empty()) |
| 368 text = value; | 368 text = value; |
| 369 | 369 |
| 370 // This is called from PlatformIsLeaf, so don't call PlatformChildCount | 370 // This is called from PlatformIsLeaf, so don't call PlatformChildCount |
| 371 // from within this! | 371 // from within this! |
| 372 if (text.empty() && | 372 if (text.empty() && |
| 373 (HasOnlyStaticTextChildren() || | 373 (HasOnlyStaticTextChildren() || |
| 374 (IsFocusable() && HasOnlyTextAndImageChildren()))) { | 374 (IsFocusable() && HasOnlyTextAndImageChildren()))) { |
| 375 for (uint32 i = 0; i < InternalChildCount(); i++) { | 375 for (uint32_t i = 0; i < InternalChildCount(); i++) { |
| 376 BrowserAccessibility* child = InternalGetChild(i); | 376 BrowserAccessibility* child = InternalGetChild(i); |
| 377 text += static_cast<BrowserAccessibilityAndroid*>(child)->GetText(); | 377 text += static_cast<BrowserAccessibilityAndroid*>(child)->GetText(); |
| 378 } | 378 } |
| 379 } | 379 } |
| 380 | 380 |
| 381 if (text.empty() && (IsLink() || GetRole() == ui::AX_ROLE_IMAGE)) { | 381 if (text.empty() && (IsLink() || GetRole() == ui::AX_ROLE_IMAGE)) { |
| 382 base::string16 url = GetString16Attribute(ui::AX_ATTR_URL); | 382 base::string16 url = GetString16Attribute(ui::AX_ATTR_URL); |
| 383 // Given a url like http://foo.com/bar/baz.png, just return the | 383 // Given a url like http://foo.com/bar/baz.png, just return the |
| 384 // base text, e.g., "baz". | 384 // base text, e.g., "baz". |
| 385 int trailing_slashes = 0; | 385 int trailing_slashes = 0; |
| (...skipping 379 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 765 float BrowserAccessibilityAndroid::RangeMax() const { | 765 float BrowserAccessibilityAndroid::RangeMax() const { |
| 766 return GetFloatAttribute(ui::AX_ATTR_MAX_VALUE_FOR_RANGE); | 766 return GetFloatAttribute(ui::AX_ATTR_MAX_VALUE_FOR_RANGE); |
| 767 } | 767 } |
| 768 | 768 |
| 769 float BrowserAccessibilityAndroid::RangeCurrentValue() const { | 769 float BrowserAccessibilityAndroid::RangeCurrentValue() const { |
| 770 return GetFloatAttribute(ui::AX_ATTR_VALUE_FOR_RANGE); | 770 return GetFloatAttribute(ui::AX_ATTR_VALUE_FOR_RANGE); |
| 771 } | 771 } |
| 772 | 772 |
| 773 void BrowserAccessibilityAndroid::GetGranularityBoundaries( | 773 void BrowserAccessibilityAndroid::GetGranularityBoundaries( |
| 774 int granularity, | 774 int granularity, |
| 775 std::vector<int32>* starts, | 775 std::vector<int32_t>* starts, |
| 776 std::vector<int32>* ends, | 776 std::vector<int32_t>* ends, |
| 777 int offset) { | 777 int offset) { |
| 778 switch (granularity) { | 778 switch (granularity) { |
| 779 case ANDROID_ACCESSIBILITY_NODE_INFO_MOVEMENT_GRANULARITY_LINE: | 779 case ANDROID_ACCESSIBILITY_NODE_INFO_MOVEMENT_GRANULARITY_LINE: |
| 780 GetLineBoundaries(starts, ends, offset); | 780 GetLineBoundaries(starts, ends, offset); |
| 781 break; | 781 break; |
| 782 case ANDROID_ACCESSIBILITY_NODE_INFO_MOVEMENT_GRANULARITY_WORD: | 782 case ANDROID_ACCESSIBILITY_NODE_INFO_MOVEMENT_GRANULARITY_WORD: |
| 783 GetWordBoundaries(starts, ends, offset); | 783 GetWordBoundaries(starts, ends, offset); |
| 784 break; | 784 break; |
| 785 default: | 785 default: |
| 786 NOTREACHED(); | 786 NOTREACHED(); |
| 787 } | 787 } |
| 788 } | 788 } |
| 789 | 789 |
| 790 void BrowserAccessibilityAndroid::GetLineBoundaries( | 790 void BrowserAccessibilityAndroid::GetLineBoundaries( |
| 791 std::vector<int32>* line_starts, | 791 std::vector<int32_t>* line_starts, |
| 792 std::vector<int32>* line_ends, | 792 std::vector<int32_t>* line_ends, |
| 793 int offset) { | 793 int offset) { |
| 794 // If this node has no children, treat it as all one line. | 794 // If this node has no children, treat it as all one line. |
| 795 if (GetText().size() > 0 && !InternalChildCount()) { | 795 if (GetText().size() > 0 && !InternalChildCount()) { |
| 796 line_starts->push_back(offset); | 796 line_starts->push_back(offset); |
| 797 line_ends->push_back(offset + GetText().size()); | 797 line_ends->push_back(offset + GetText().size()); |
| 798 } | 798 } |
| 799 | 799 |
| 800 // If this is a static text node, get the line boundaries from the | 800 // If this is a static text node, get the line boundaries from the |
| 801 // inline text boxes if possible. | 801 // inline text boxes if possible. |
| 802 if (GetRole() == ui::AX_ROLE_STATIC_TEXT) { | 802 if (GetRole() == ui::AX_ROLE_STATIC_TEXT) { |
| 803 int last_y = 0; | 803 int last_y = 0; |
| 804 for (uint32 i = 0; i < InternalChildCount(); i++) { | 804 for (uint32_t i = 0; i < InternalChildCount(); i++) { |
| 805 BrowserAccessibilityAndroid* child = | 805 BrowserAccessibilityAndroid* child = |
| 806 static_cast<BrowserAccessibilityAndroid*>(InternalGetChild(i)); | 806 static_cast<BrowserAccessibilityAndroid*>(InternalGetChild(i)); |
| 807 CHECK_EQ(ui::AX_ROLE_INLINE_TEXT_BOX, child->GetRole()); | 807 CHECK_EQ(ui::AX_ROLE_INLINE_TEXT_BOX, child->GetRole()); |
| 808 // TODO(dmazzoni): replace this with a proper API to determine | 808 // TODO(dmazzoni): replace this with a proper API to determine |
| 809 // if two inline text boxes are on the same line. http://crbug.com/421771 | 809 // if two inline text boxes are on the same line. http://crbug.com/421771 |
| 810 int y = child->GetLocation().y(); | 810 int y = child->GetLocation().y(); |
| 811 if (i == 0) { | 811 if (i == 0) { |
| 812 line_starts->push_back(offset); | 812 line_starts->push_back(offset); |
| 813 } else if (y != last_y) { | 813 } else if (y != last_y) { |
| 814 line_ends->push_back(offset); | 814 line_ends->push_back(offset); |
| 815 line_starts->push_back(offset); | 815 line_starts->push_back(offset); |
| 816 } | 816 } |
| 817 offset += child->GetText().size(); | 817 offset += child->GetText().size(); |
| 818 last_y = y; | 818 last_y = y; |
| 819 } | 819 } |
| 820 line_ends->push_back(offset); | 820 line_ends->push_back(offset); |
| 821 return; | 821 return; |
| 822 } | 822 } |
| 823 | 823 |
| 824 // Otherwise, call GetLineBoundaries recursively on the children. | 824 // Otherwise, call GetLineBoundaries recursively on the children. |
| 825 for (uint32 i = 0; i < InternalChildCount(); i++) { | 825 for (uint32_t i = 0; i < InternalChildCount(); i++) { |
| 826 BrowserAccessibilityAndroid* child = | 826 BrowserAccessibilityAndroid* child = |
| 827 static_cast<BrowserAccessibilityAndroid*>(InternalGetChild(i)); | 827 static_cast<BrowserAccessibilityAndroid*>(InternalGetChild(i)); |
| 828 child->GetLineBoundaries(line_starts, line_ends, offset); | 828 child->GetLineBoundaries(line_starts, line_ends, offset); |
| 829 offset += child->GetText().size(); | 829 offset += child->GetText().size(); |
| 830 } | 830 } |
| 831 } | 831 } |
| 832 | 832 |
| 833 void BrowserAccessibilityAndroid::GetWordBoundaries( | 833 void BrowserAccessibilityAndroid::GetWordBoundaries( |
| 834 std::vector<int32>* word_starts, | 834 std::vector<int32_t>* word_starts, |
| 835 std::vector<int32>* word_ends, | 835 std::vector<int32_t>* word_ends, |
| 836 int offset) { | 836 int offset) { |
| 837 if (GetRole() == ui::AX_ROLE_INLINE_TEXT_BOX) { | 837 if (GetRole() == ui::AX_ROLE_INLINE_TEXT_BOX) { |
| 838 const std::vector<int32>& starts = GetIntListAttribute( | 838 const std::vector<int32_t>& starts = |
| 839 ui::AX_ATTR_WORD_STARTS); | 839 GetIntListAttribute(ui::AX_ATTR_WORD_STARTS); |
| 840 const std::vector<int32>& ends = GetIntListAttribute( | 840 const std::vector<int32_t>& ends = |
| 841 ui::AX_ATTR_WORD_ENDS); | 841 GetIntListAttribute(ui::AX_ATTR_WORD_ENDS); |
| 842 for (size_t i = 0; i < starts.size(); ++i) { | 842 for (size_t i = 0; i < starts.size(); ++i) { |
| 843 word_starts->push_back(offset + starts[i]); | 843 word_starts->push_back(offset + starts[i]); |
| 844 word_ends->push_back(offset + ends[i]); | 844 word_ends->push_back(offset + ends[i]); |
| 845 } | 845 } |
| 846 return; | 846 return; |
| 847 } | 847 } |
| 848 | 848 |
| 849 base::string16 concatenated_text; | 849 base::string16 concatenated_text; |
| 850 for (uint32 i = 0; i < InternalChildCount(); i++) { | 850 for (uint32_t i = 0; i < InternalChildCount(); i++) { |
| 851 BrowserAccessibilityAndroid* child = | 851 BrowserAccessibilityAndroid* child = |
| 852 static_cast<BrowserAccessibilityAndroid*>(InternalGetChild(i)); | 852 static_cast<BrowserAccessibilityAndroid*>(InternalGetChild(i)); |
| 853 base::string16 child_text = child->GetText(); | 853 base::string16 child_text = child->GetText(); |
| 854 concatenated_text += child->GetText(); | 854 concatenated_text += child->GetText(); |
| 855 } | 855 } |
| 856 | 856 |
| 857 base::string16 text = GetText(); | 857 base::string16 text = GetText(); |
| 858 if (text.empty() || concatenated_text == text) { | 858 if (text.empty() || concatenated_text == text) { |
| 859 // Great - this node is just the concatenation of its children, so | 859 // Great - this node is just the concatenation of its children, so |
| 860 // we can get the word boundaries recursively. | 860 // we can get the word boundaries recursively. |
| 861 for (uint32 i = 0; i < InternalChildCount(); i++) { | 861 for (uint32_t i = 0; i < InternalChildCount(); i++) { |
| 862 BrowserAccessibilityAndroid* child = | 862 BrowserAccessibilityAndroid* child = |
| 863 static_cast<BrowserAccessibilityAndroid*>(InternalGetChild(i)); | 863 static_cast<BrowserAccessibilityAndroid*>(InternalGetChild(i)); |
| 864 child->GetWordBoundaries(word_starts, word_ends, offset); | 864 child->GetWordBoundaries(word_starts, word_ends, offset); |
| 865 offset += child->GetText().size(); | 865 offset += child->GetText().size(); |
| 866 } | 866 } |
| 867 } else { | 867 } else { |
| 868 // This node has its own accessible text that doesn't match its | 868 // This node has its own accessible text that doesn't match its |
| 869 // visible text - like alt text for an image or something with an | 869 // visible text - like alt text for an image or something with an |
| 870 // aria-label, so split the text into words locally. | 870 // aria-label, so split the text into words locally. |
| 871 base::i18n::BreakIterator iter(text, base::i18n::BreakIterator::BREAK_WORD); | 871 base::i18n::BreakIterator iter(text, base::i18n::BreakIterator::BREAK_WORD); |
| 872 if (!iter.Init()) | 872 if (!iter.Init()) |
| 873 return; | 873 return; |
| 874 while (iter.Advance()) { | 874 while (iter.Advance()) { |
| 875 if (iter.IsWord()) { | 875 if (iter.IsWord()) { |
| 876 word_starts->push_back(iter.prev()); | 876 word_starts->push_back(iter.prev()); |
| 877 word_ends->push_back(iter.pos()); | 877 word_ends->push_back(iter.pos()); |
| 878 } | 878 } |
| 879 } | 879 } |
| 880 } | 880 } |
| 881 } | 881 } |
| 882 | 882 |
| 883 bool BrowserAccessibilityAndroid::HasFocusableChild() const { | 883 bool BrowserAccessibilityAndroid::HasFocusableChild() const { |
| 884 // This is called from PlatformIsLeaf, so don't call PlatformChildCount | 884 // This is called from PlatformIsLeaf, so don't call PlatformChildCount |
| 885 // from within this! | 885 // from within this! |
| 886 for (uint32 i = 0; i < InternalChildCount(); i++) { | 886 for (uint32_t i = 0; i < InternalChildCount(); i++) { |
| 887 BrowserAccessibility* child = InternalGetChild(i); | 887 BrowserAccessibility* child = InternalGetChild(i); |
| 888 if (child->HasState(ui::AX_STATE_FOCUSABLE)) | 888 if (child->HasState(ui::AX_STATE_FOCUSABLE)) |
| 889 return true; | 889 return true; |
| 890 if (static_cast<BrowserAccessibilityAndroid*>(child)->HasFocusableChild()) | 890 if (static_cast<BrowserAccessibilityAndroid*>(child)->HasFocusableChild()) |
| 891 return true; | 891 return true; |
| 892 } | 892 } |
| 893 return false; | 893 return false; |
| 894 } | 894 } |
| 895 | 895 |
| 896 bool BrowserAccessibilityAndroid::HasOnlyStaticTextChildren() const { | 896 bool BrowserAccessibilityAndroid::HasOnlyStaticTextChildren() const { |
| 897 // This is called from PlatformIsLeaf, so don't call PlatformChildCount | 897 // This is called from PlatformIsLeaf, so don't call PlatformChildCount |
| 898 // from within this! | 898 // from within this! |
| 899 for (uint32 i = 0; i < InternalChildCount(); i++) { | 899 for (uint32_t i = 0; i < InternalChildCount(); i++) { |
| 900 BrowserAccessibility* child = InternalGetChild(i); | 900 BrowserAccessibility* child = InternalGetChild(i); |
| 901 if (child->GetRole() != ui::AX_ROLE_STATIC_TEXT) | 901 if (child->GetRole() != ui::AX_ROLE_STATIC_TEXT) |
| 902 return false; | 902 return false; |
| 903 } | 903 } |
| 904 return true; | 904 return true; |
| 905 } | 905 } |
| 906 | 906 |
| 907 bool BrowserAccessibilityAndroid::HasOnlyTextAndImageChildren() const { | 907 bool BrowserAccessibilityAndroid::HasOnlyTextAndImageChildren() const { |
| 908 // This is called from PlatformIsLeaf, so don't call PlatformChildCount | 908 // This is called from PlatformIsLeaf, so don't call PlatformChildCount |
| 909 // from within this! | 909 // from within this! |
| 910 for (uint32 i = 0; i < InternalChildCount(); i++) { | 910 for (uint32_t i = 0; i < InternalChildCount(); i++) { |
| 911 BrowserAccessibility* child = InternalGetChild(i); | 911 BrowserAccessibility* child = InternalGetChild(i); |
| 912 if (child->GetRole() != ui::AX_ROLE_STATIC_TEXT && | 912 if (child->GetRole() != ui::AX_ROLE_STATIC_TEXT && |
| 913 child->GetRole() != ui::AX_ROLE_IMAGE) { | 913 child->GetRole() != ui::AX_ROLE_IMAGE) { |
| 914 return false; | 914 return false; |
| 915 } | 915 } |
| 916 } | 916 } |
| 917 return true; | 917 return true; |
| 918 } | 918 } |
| 919 | 919 |
| 920 bool BrowserAccessibilityAndroid::IsIframe() const { | 920 bool BrowserAccessibilityAndroid::IsIframe() const { |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 957 if (!text.empty()) { | 957 if (!text.empty()) { |
| 958 manager()->NotifyAccessibilityEvent(ui::AX_EVENT_SHOW, | 958 manager()->NotifyAccessibilityEvent(ui::AX_EVENT_SHOW, |
| 959 this); | 959 this); |
| 960 } | 960 } |
| 961 cached_text_ = text; | 961 cached_text_ = text; |
| 962 } | 962 } |
| 963 } | 963 } |
| 964 | 964 |
| 965 int BrowserAccessibilityAndroid::CountChildrenWithRole(ui::AXRole role) const { | 965 int BrowserAccessibilityAndroid::CountChildrenWithRole(ui::AXRole role) const { |
| 966 int count = 0; | 966 int count = 0; |
| 967 for (uint32 i = 0; i < PlatformChildCount(); i++) { | 967 for (uint32_t i = 0; i < PlatformChildCount(); i++) { |
| 968 if (PlatformGetChild(i)->GetRole() == role) | 968 if (PlatformGetChild(i)->GetRole() == role) |
| 969 count++; | 969 count++; |
| 970 } | 970 } |
| 971 return count; | 971 return count; |
| 972 } | 972 } |
| 973 | 973 |
| 974 } // namespace content | 974 } // namespace content |
| OLD | NEW |