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 #include <iterator> | 10 #include <iterator> |
(...skipping 509 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
520 // Some screen readers like Jaws and older versions of VoiceOver require a | 520 // Some screen readers like Jaws and older versions of VoiceOver require a |
521 // value to be set in text fields with rich content, even though the same | 521 // value to be set in text fields with rich content, even though the same |
522 // information is available on the children. | 522 // information is available on the children. |
523 if (value.empty() && | 523 if (value.empty() && |
524 (IsSimpleTextControl() || IsRichTextControl()) && | 524 (IsSimpleTextControl() || IsRichTextControl()) && |
525 !IsNativeTextControl()) | 525 !IsNativeTextControl()) |
526 value = GetInnerText(); | 526 value = GetInnerText(); |
527 return value; | 527 return value; |
528 } | 528 } |
529 | 529 |
530 int BrowserAccessibility::GetLineStartBoundary( | |
531 int start, | |
532 ui::TextBoundaryDirection direction, | |
533 ui::AXTextAffinity affinity) const { | |
534 DCHECK_GE(start, 0); | |
535 DCHECK_LE(start, static_cast<int>(GetText().length())); | |
536 | |
537 if (IsSimpleTextControl()) { | |
538 return ui::FindAccessibleTextBoundary(GetText(), GetLineStartOffsets(), | |
539 ui::LINE_BOUNDARY, start, direction, | |
540 affinity); | |
541 } | |
542 | |
543 // Keeps track of the start offset of each consecutive line. | |
544 int line_start = 0; | |
545 // Keeps track of the length of each consecutive line. | |
546 int line_length = 0; | |
547 for (size_t i = 0; i < InternalChildCount(); ++i) { | |
548 const BrowserAccessibility* child = InternalGetChild(i); | |
549 DCHECK(child); | |
550 // Child objects are of length one, since they are represented by a | |
551 // single embedded object character. The exception is text-only objects. | |
552 int child_length = 1; | |
553 if (child->IsTextOnlyObject()) | |
554 child_length = static_cast<int>(child->GetText().length()); | |
555 | |
556 // Determine if |start| is within this child. As a special case, if | |
557 // the affinity is upstream, then the cursor position between two | |
558 // lines belongs to the previous line. | |
559 bool start_index_within_child = start < child_length; | |
560 if (start == child_length && | |
561 !child->IsNextSiblingOnSameLine() && | |
562 affinity == ui::AX_TEXT_AFFINITY_UPSTREAM) { | |
563 start_index_within_child = true; | |
564 } | |
565 | |
566 // Stop when we reach both the child containing our start offset and, in | |
567 // case we are searching forward, the child that is at the end of the line | |
568 // on which this object is located. | |
569 if (start_index_within_child && (direction == ui::BACKWARDS_DIRECTION || | |
570 !child->IsNextSiblingOnSameLine())) { | |
571 // Recurse into the inline text boxes. | |
572 if (child->GetRole() == ui::AX_ROLE_STATIC_TEXT) { | |
573 switch (direction) { | |
574 case ui::FORWARDS_DIRECTION: | |
575 line_length += child->GetLineStartBoundary( | |
576 std::max(start, 0), direction, affinity); | |
577 break; | |
578 case ui::BACKWARDS_DIRECTION: | |
579 line_start += child->GetLineStartBoundary( | |
580 std::max(start, 0), direction, affinity); | |
581 break; | |
582 } | |
583 } else { | |
584 line_length += child_length; | |
585 } | |
586 | |
587 break; | |
588 } | |
589 line_length += child_length; | |
590 | |
591 if (!child->IsNextSiblingOnSameLine()) { | |
592 // We are on a new line. | |
593 line_start += line_length; | |
594 line_length = 0; | |
595 } | |
596 | |
597 start -= child_length; | |
598 } | |
599 | |
600 switch (direction) { | |
601 case ui::FORWARDS_DIRECTION: | |
602 return line_start + line_length; | |
603 case ui::BACKWARDS_DIRECTION: | |
604 return line_start; | |
605 } | |
606 NOTREACHED(); | |
607 return 0; | |
608 } | |
609 | |
610 int BrowserAccessibility::GetWordStartBoundary( | |
611 int start, ui::TextBoundaryDirection direction) const { | |
612 DCHECK_GE(start, -1); | |
613 // Special offset that indicates that a word boundary has not been found. | |
614 int word_start_not_found = static_cast<int>(GetText().size()); | |
615 int word_start = word_start_not_found; | |
616 | |
617 switch (GetRole()) { | |
618 case ui::AX_ROLE_STATIC_TEXT: { | |
619 int prev_word_start = word_start_not_found; | |
620 int child_start = 0; | |
621 int child_end = 0; | |
622 | |
623 // Go through the inline text boxes. | |
624 for (size_t i = 0; i < InternalChildCount(); ++i) { | |
625 // The next child starts where the previous one ended. | |
626 child_start = child_end; | |
627 const BrowserAccessibility* child = InternalGetChild(i); | |
628 DCHECK_EQ(child->GetRole(), ui::AX_ROLE_INLINE_TEXT_BOX); | |
629 int child_len = static_cast<int>(child->GetText().size()); | |
630 child_end += child_len; // End is one past the last character. | |
631 | |
632 const std::vector<int32_t>& word_starts = | |
633 child->GetIntListAttribute(ui::AX_ATTR_WORD_STARTS); | |
634 if (word_starts.empty()) { | |
635 word_start = child_end; | |
636 continue; | |
637 } | |
638 | |
639 int local_start = start - child_start; | |
640 std::vector<int32_t>::const_iterator iter = std::upper_bound( | |
641 word_starts.begin(), word_starts.end(), local_start); | |
642 if (iter != word_starts.end()) { | |
643 if (direction == ui::FORWARDS_DIRECTION) { | |
644 word_start = child_start + *iter; | |
645 } else if (direction == ui::BACKWARDS_DIRECTION) { | |
646 if (iter == word_starts.begin()) { | |
647 // Return the position of the last word in the previous child. | |
648 word_start = prev_word_start; | |
649 } else { | |
650 word_start = child_start + *(iter - 1); | |
651 } | |
652 } else { | |
653 NOTREACHED(); | |
654 } | |
655 break; | |
656 } | |
657 | |
658 // No word start that is greater than the requested offset has been | |
659 // found. | |
660 prev_word_start = child_start + *(iter - 1); | |
661 if (direction == ui::FORWARDS_DIRECTION) { | |
662 word_start = child_end; | |
663 } else if (direction == ui::BACKWARDS_DIRECTION) { | |
664 word_start = prev_word_start; | |
665 } else { | |
666 NOTREACHED(); | |
667 } | |
668 } | |
669 return word_start; | |
670 } | |
671 | |
672 case ui::AX_ROLE_LINE_BREAK: | |
673 // Words never start at a line break. | |
674 return word_start_not_found; | |
675 | |
676 default: | |
677 // If there are no children, the word start boundary is still unknown or | |
678 // found previously depending on the direction. | |
679 if (!InternalChildCount()) | |
680 return word_start_not_found; | |
681 | |
682 const BrowserAccessibility* this_object = this; | |
683 // Standard text fields such as textarea have an embedded div inside them | |
684 // that should be skipped. | |
685 // TODO(nektar): This is fragile. Replace with code that flattens tree. | |
686 if (IsSimpleTextControl() && InternalChildCount() == 1) { | |
687 this_object = InternalGetChild(0); | |
688 } | |
689 int child_start = 0; | |
690 for (size_t i = 0; i < this_object->InternalChildCount(); ++i) { | |
691 BrowserAccessibility* child = this_object->InternalGetChild(i); | |
692 // Child objects are of length one, since they are represented by a | |
693 // single embedded object character. The exception is text-only objects. | |
694 int child_len = 1; | |
695 if (child->IsTextOnlyObject()) { | |
696 child_len = static_cast<int>(child->GetText().length()); | |
697 int child_word_start = child->GetWordStartBoundary(start, direction); | |
698 if (child_word_start < child_len) { | |
699 // We have found a possible word boundary. | |
700 word_start = child_start + child_word_start; | |
701 } | |
702 | |
703 // Decide when to stop searching. | |
704 if ((word_start != word_start_not_found && | |
705 direction == ui::FORWARDS_DIRECTION) || | |
706 (start < child_len && direction == ui::BACKWARDS_DIRECTION)) { | |
707 break; | |
708 } | |
709 } | |
710 | |
711 child_start += child_len; | |
712 if (start >= child_len) | |
713 start -= child_len; | |
714 else | |
715 start = -1; | |
716 } | |
717 return word_start; | |
718 } | |
719 } | |
720 | |
721 BrowserAccessibility* BrowserAccessibility::ApproximateHitTest( | 530 BrowserAccessibility* BrowserAccessibility::ApproximateHitTest( |
722 const gfx::Point& point) { | 531 const gfx::Point& point) { |
723 // The best result found that's a child of this object. | 532 // The best result found that's a child of this object. |
724 BrowserAccessibility* child_result = NULL; | 533 BrowserAccessibility* child_result = NULL; |
725 // The best result that's an indirect descendant like grandchild, etc. | 534 // The best result that's an indirect descendant like grandchild, etc. |
726 BrowserAccessibility* descendant_result = NULL; | 535 BrowserAccessibility* descendant_result = NULL; |
727 | 536 |
728 // Walk the children recursively looking for the BrowserAccessibility that | 537 // Walk the children recursively looking for the BrowserAccessibility that |
729 // most tightly encloses the specified point. Walk backwards so that in | 538 // most tightly encloses the specified point. Walk backwards so that in |
730 // the absence of any other information, we assume the object that occurs | 539 // the absence of any other information, we assume the object that occurs |
(...skipping 505 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1236 return name; | 1045 return name; |
1237 } | 1046 } |
1238 | 1047 |
1239 std::vector<int> BrowserAccessibility::GetLineStartOffsets() const { | 1048 std::vector<int> BrowserAccessibility::GetLineStartOffsets() const { |
1240 if (!instance_active()) | 1049 if (!instance_active()) |
1241 return std::vector<int>(); | 1050 return std::vector<int>(); |
1242 return node()->GetOrComputeLineStartOffsets(); | 1051 return node()->GetOrComputeLineStartOffsets(); |
1243 } | 1052 } |
1244 | 1053 |
1245 BrowserAccessibility::AXPlatformPositionInstance | 1054 BrowserAccessibility::AXPlatformPositionInstance |
1246 BrowserAccessibility::CreatePositionAt(int offset) const { | 1055 BrowserAccessibility::CreatePositionAt(int offset, |
| 1056 ui::AXTextAffinity affinity) const { |
1247 DCHECK(manager_); | 1057 DCHECK(manager_); |
1248 return AXPlatformPosition::CreateTextPosition( | 1058 return AXPlatformPosition::CreateTextPosition(manager_->ax_tree_id(), GetId(), |
1249 manager_->ax_tree_id(), GetId(), offset, ui::AX_TEXT_AFFINITY_DOWNSTREAM); | 1059 offset, affinity); |
1250 } | 1060 } |
1251 | 1061 |
1252 base::string16 BrowserAccessibility::GetInnerText() const { | 1062 base::string16 BrowserAccessibility::GetInnerText() const { |
1253 if (IsTextOnlyObject()) | 1063 if (IsTextOnlyObject()) |
1254 return GetString16Attribute(ui::AX_ATTR_NAME); | 1064 return GetString16Attribute(ui::AX_ATTR_NAME); |
1255 | 1065 |
1256 base::string16 text; | 1066 base::string16 text; |
1257 for (size_t i = 0; i < InternalChildCount(); ++i) | 1067 for (size_t i = 0; i < InternalChildCount(); ++i) |
1258 text += InternalGetChild(i)->GetInnerText(); | 1068 text += InternalGetChild(i)->GetInnerText(); |
1259 return text; | 1069 return text; |
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1379 return gfx::kNullAcceleratedWidget; | 1189 return gfx::kNullAcceleratedWidget; |
1380 } | 1190 } |
1381 | 1191 |
1382 bool BrowserAccessibility::AccessibilityPerformAction( | 1192 bool BrowserAccessibility::AccessibilityPerformAction( |
1383 const ui::AXActionData& data) { | 1193 const ui::AXActionData& data) { |
1384 NOTREACHED(); | 1194 NOTREACHED(); |
1385 return false; | 1195 return false; |
1386 } | 1196 } |
1387 | 1197 |
1388 } // namespace content | 1198 } // namespace content |
OLD | NEW |