Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(54)

Side by Side Diff: content/browser/accessibility/browser_accessibility.cc

Issue 1905263002: Correctly finds line boundaries in objects with rich text on Windows. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fixed standard text fields in unit test. Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 168 matching lines...) Expand 10 before | Expand all | Expand 10 after
179 if (GetParent() && 179 if (GetParent() &&
180 GetIndexInParent() >= 0 && 180 GetIndexInParent() >= 0 &&
181 GetIndexInParent() < static_cast<int>( 181 GetIndexInParent() < static_cast<int>(
182 GetParent()->InternalChildCount() - 1)) { 182 GetParent()->InternalChildCount() - 1)) {
183 return GetParent()->InternalGetChild(GetIndexInParent() + 1); 183 return GetParent()->InternalGetChild(GetIndexInParent() + 1);
184 } 184 }
185 185
186 return nullptr; 186 return nullptr;
187 } 187 }
188 188
189 bool BrowserAccessibility::IsPreviousSiblingOnSameLine() const {
190 const BrowserAccessibility* previous_sibling = GetPreviousSibling();
191 if (!previous_sibling)
192 return false;
193
194 const BrowserAccessibility* text_object = this;
195 while (!text_object->IsTextOnlyObject()) {
196 // If we don't find a text object, then sibling cannot be on the same line.
197 if (!text_object->InternalChildCount())
198 return false;
199 text_object = text_object->InternalGetChild(0);
200 }
201
202 int32_t previous_on_line_id;
203 if (text_object->GetIntAttribute(ui::AX_ATTR_PREVIOUS_ON_LINE_ID,
204 &previous_on_line_id)) {
205 const BrowserAccessibility* previous_on_line =
206 manager()->GetFromID(previous_on_line_id);
207 // In the case of static text objects, the object designated to be the
208 // previous object on this line might be a child of the previous sibling,
209 // i.e. the last inline text box of the previous static text object.
210 return previous_on_line &&
211 previous_on_line->IsDescendantOf(previous_sibling);
212 }
213 return false;
214 }
215
216 bool BrowserAccessibility::IsNextSiblingOnSameLine() const {
217 const BrowserAccessibility* next_sibling = GetNextSibling();
218 if (!next_sibling)
219 return false;
220
221 const BrowserAccessibility* text_object = this;
222 while (!text_object->IsTextOnlyObject()) {
223 // If we don't find a text object, then sibling cannot be on the same line.
224 if (!text_object->InternalChildCount())
225 return false;
226 text_object = text_object->InternalGetChild(0);
227 }
228
229 int32_t next_on_line_id;
230 if (text_object->GetIntAttribute(ui::AX_ATTR_NEXT_ON_LINE_ID,
231 &next_on_line_id)) {
232 const BrowserAccessibility* next_on_line =
233 manager()->GetFromID(next_on_line_id);
234 // In the case of static text objects, the object designated to be the next
235 // object on this line might be a child of the next sibling, i.e. the first
236 // inline text box of the next static text object.
237 return next_on_line && next_on_line->IsDescendantOf(next_sibling);
238 }
239 return false;
240 }
241
189 BrowserAccessibility* BrowserAccessibility::PlatformDeepestFirstChild() const { 242 BrowserAccessibility* BrowserAccessibility::PlatformDeepestFirstChild() const {
190 if (!PlatformChildCount()) 243 if (!PlatformChildCount())
191 return nullptr; 244 return nullptr;
192 245
193 BrowserAccessibility* deepest_child = PlatformGetChild(0); 246 BrowserAccessibility* deepest_child = PlatformGetChild(0);
194 while (deepest_child->PlatformChildCount()) 247 while (deepest_child->PlatformChildCount())
195 deepest_child = deepest_child->PlatformGetChild(0); 248 deepest_child = deepest_child->PlatformGetChild(0);
196 249
197 return deepest_child; 250 return deepest_child;
198 } 251 }
(...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after
461 base::string16 BrowserAccessibility::GetValue() const { 514 base::string16 BrowserAccessibility::GetValue() const {
462 base::string16 value = GetString16Attribute(ui::AX_ATTR_VALUE); 515 base::string16 value = GetString16Attribute(ui::AX_ATTR_VALUE);
463 // Some screen readers like Jaws and older versions of VoiceOver require a 516 // Some screen readers like Jaws and older versions of VoiceOver require a
464 // value to be set in text fields with rich content, even though the same 517 // value to be set in text fields with rich content, even though the same
465 // information is available on the children. 518 // information is available on the children.
466 if (value.empty() && (IsSimpleTextControl() || IsRichTextControl())) 519 if (value.empty() && (IsSimpleTextControl() || IsRichTextControl()))
467 value = GetInnerText(); 520 value = GetInnerText();
468 return value; 521 return value;
469 } 522 }
470 523
524 int BrowserAccessibility::GetLineStartBoundary(
525 int start,
526 ui::TextBoundaryDirection direction) const {
527 DCHECK_GE(start, 0);
528 DCHECK_LE(start, static_cast<int>(GetText().length()));
529
530 if (IsSimpleTextControl()) {
531 const std::vector<int32_t>& line_breaks =
532 GetIntListAttribute(ui::AX_ATTR_LINE_BREAKS);
533 return ui::FindAccessibleTextBoundary(GetText(), line_breaks,
534 ui::LINE_BOUNDARY, start, direction);
535 }
536
537 // Keeps track of the start offset of each consecutive line.
538 int line_start = 0;
539 // Keeps track of the length of each consecutive line.
540 int line_length = 0;
541 for (size_t i = 0; i < InternalChildCount(); ++i) {
542 const BrowserAccessibility* child = InternalGetChild(i);
543 DCHECK(child);
544 // Child objects are of length one, since they are represented by a
545 // single embedded object character. The exception is text-only objects.
546 int child_length = 1;
547 if (child->IsTextOnlyObject())
548 child_length = static_cast<int>(child->GetText().length());
549 line_length += child_length;
550 start -= child_length;
551
552 // Stop when we reach both the object containing our start offset and the
553 // end of the line on which this object is located.
554 if (start < 0 && !child->IsNextSiblingOnSameLine())
555 break;
556
557 if (!child->IsNextSiblingOnSameLine()) {
558 line_start += line_length;
559 line_length = 0;
560 }
561 }
562
563 int result = 0;
564 switch (direction) {
565 case ui::FORWARDS_DIRECTION:
566 result = line_start + line_length;
567 break;
568 case ui::BACKWARDS_DIRECTION:
569 result = line_start;
570 break;
571 default:
572 NOTREACHED();
573 }
574 return result;
575 }
576
471 int BrowserAccessibility::GetWordStartBoundary( 577 int BrowserAccessibility::GetWordStartBoundary(
472 int start, ui::TextBoundaryDirection direction) const { 578 int start, ui::TextBoundaryDirection direction) const {
473 DCHECK_GE(start, -1); 579 DCHECK_GE(start, -1);
474 // Special offset that indicates that a word boundary has not been found. 580 // Special offset that indicates that a word boundary has not been found.
475 int word_start_not_found = static_cast<int>(GetText().size()); 581 int word_start_not_found = static_cast<int>(GetText().size());
476 int word_start = word_start_not_found; 582 int word_start = word_start_not_found;
477 583
478 switch (GetRole()) { 584 switch (GetRole()) {
479 case ui::AX_ROLE_STATIC_TEXT: { 585 case ui::AX_ROLE_STATIC_TEXT: {
480 int prev_word_start = word_start_not_found; 586 int prev_word_start = word_start_not_found;
481 int child_start = 0; 587 int child_start = 0;
482 int child_end = 0; 588 int child_end = 0;
483 589
484 // Go through the inline text boxes. 590 // Go through the inline text boxes.
485 for (size_t i = 0; i < InternalChildCount(); ++i) { 591 for (size_t i = 0; i < InternalChildCount(); ++i) {
486 // The next child starts where the previous one ended. 592 // The next child starts where the previous one ended.
487 child_start = child_end; 593 child_start = child_end;
488 BrowserAccessibility* child = InternalGetChild(i); 594 const BrowserAccessibility* child = InternalGetChild(i);
489 DCHECK_EQ(child->GetRole(), ui::AX_ROLE_INLINE_TEXT_BOX); 595 DCHECK_EQ(child->GetRole(), ui::AX_ROLE_INLINE_TEXT_BOX);
490 int child_len = static_cast<int>(child->GetText().size()); 596 int child_len = static_cast<int>(child->GetText().size());
491 child_end += child_len; // End is one past the last character. 597 child_end += child_len; // End is one past the last character.
492 598
493 const std::vector<int32_t>& word_starts = 599 const std::vector<int32_t>& word_starts =
494 child->GetIntListAttribute(ui::AX_ATTR_WORD_STARTS); 600 child->GetIntListAttribute(ui::AX_ATTR_WORD_STARTS);
495 if (word_starts.empty()) { 601 if (word_starts.empty()) {
496 word_start = child_end; 602 word_start = child_end;
497 continue; 603 continue;
498 } 604 }
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
546 if (IsSimpleTextControl() && InternalChildCount() == 1) { 652 if (IsSimpleTextControl() && InternalChildCount() == 1) {
547 this_object = InternalGetChild(0); 653 this_object = InternalGetChild(0);
548 } 654 }
549 int child_start = 0; 655 int child_start = 0;
550 for (size_t i = 0; i < this_object->InternalChildCount(); ++i) { 656 for (size_t i = 0; i < this_object->InternalChildCount(); ++i) {
551 BrowserAccessibility* child = this_object->InternalGetChild(i); 657 BrowserAccessibility* child = this_object->InternalGetChild(i);
552 // Child objects are of length one, since they are represented by a 658 // Child objects are of length one, since they are represented by a
553 // single embedded object character. The exception is text-only objects. 659 // single embedded object character. The exception is text-only objects.
554 int child_len = 1; 660 int child_len = 1;
555 if (child->IsTextOnlyObject()) { 661 if (child->IsTextOnlyObject()) {
556 child_len = static_cast<int>(child->GetText().size()); 662 child_len = static_cast<int>(child->GetText().length());
557 int child_word_start = child->GetWordStartBoundary(start, direction); 663 int child_word_start = child->GetWordStartBoundary(start, direction);
558 if (child_word_start < child_len) { 664 if (child_word_start < child_len) {
559 // We have found a possible word boundary. 665 // We have found a possible word boundary.
560 word_start = child_start + child_word_start; 666 word_start = child_start + child_word_start;
561 } 667 }
562 668
563 // Decide when to stop searching. 669 // Decide when to stop searching.
564 if ((word_start != word_start_not_found && 670 if ((word_start != word_start_not_found &&
565 direction == ui::FORWARDS_DIRECTION) || 671 direction == ui::FORWARDS_DIRECTION) ||
566 (start < child_len && direction == ui::BACKWARDS_DIRECTION)) { 672 (start < child_len && direction == ui::BACKWARDS_DIRECTION)) {
(...skipping 498 matching lines...) Expand 10 before | Expand all | Expand 10 after
1065 break; 1171 break;
1066 1172
1067 manager = root->GetParent()->manager(); 1173 manager = root->GetParent()->manager();
1068 root = manager->GetRoot(); 1174 root = manager->GetRoot();
1069 } 1175 }
1070 1176
1071 return bounds; 1177 return bounds;
1072 } 1178 }
1073 1179
1074 } // namespace content 1180 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/accessibility/browser_accessibility.h ('k') | content/browser/accessibility/browser_accessibility_win.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698