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

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: 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 int32_t previous_on_line_id;
195 if (GetIntAttribute(ui::AX_ATTR_PREVIOUS_ON_LINE_ID, &previous_on_line_id)) {
196 const BrowserAccessibility* previous_on_line =
197 manager()->GetFromID(previous_on_line_id);
198 // In the case of static text objects, the object designated to be the
199 // previous object on this line might be a child of the previous sibling,
200 // i.e. the last inline text box of the previous static text object.
201 return previous_on_line &&
202 previous_on_line->IsDescendantOf(previous_sibling);
203 }
204 return false;
205 }
206
207 bool BrowserAccessibility::IsNextSiblingOnSameLine() const {
208 const BrowserAccessibility* next_sibling = GetNextSibling();
209 if (!next_sibling)
210 return false;
211
212 int32_t next_on_line_id;
213 if (GetIntAttribute(ui::AX_ATTR_NEXT_ON_LINE_ID, &next_on_line_id)) {
214 const BrowserAccessibility* next_on_line =
215 manager()->GetFromID(next_on_line_id);
216 // In the case of static text objects, the object designated to be the next
217 // object on this line might be a child of the next sibling, i.e. the first
218 // inline text box of the next static text object.
219 return next_on_line && next_on_line->IsDescendantOf(next_sibling);
220 }
221 return false;
222 }
223
189 BrowserAccessibility* BrowserAccessibility::PlatformDeepestFirstChild() const { 224 BrowserAccessibility* BrowserAccessibility::PlatformDeepestFirstChild() const {
190 if (!PlatformChildCount()) 225 if (!PlatformChildCount())
191 return nullptr; 226 return nullptr;
192 227
193 BrowserAccessibility* deepest_child = PlatformGetChild(0); 228 BrowserAccessibility* deepest_child = PlatformGetChild(0);
194 while (deepest_child->PlatformChildCount()) 229 while (deepest_child->PlatformChildCount())
195 deepest_child = deepest_child->PlatformGetChild(0); 230 deepest_child = deepest_child->PlatformGetChild(0);
196 231
197 return deepest_child; 232 return deepest_child;
198 } 233 }
(...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after
461 base::string16 BrowserAccessibility::GetValue() const { 496 base::string16 BrowserAccessibility::GetValue() const {
462 base::string16 value = GetString16Attribute(ui::AX_ATTR_VALUE); 497 base::string16 value = GetString16Attribute(ui::AX_ATTR_VALUE);
463 // Some screen readers like Jaws and older versions of VoiceOver require a 498 // 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 499 // value to be set in text fields with rich content, even though the same
465 // information is available on the children. 500 // information is available on the children.
466 if (value.empty() && (IsSimpleTextControl() || IsRichTextControl())) 501 if (value.empty() && (IsSimpleTextControl() || IsRichTextControl()))
467 value = GetInnerText(); 502 value = GetInnerText();
468 return value; 503 return value;
469 } 504 }
470 505
506 int BrowserAccessibility::GetLineStartBoundary(
507 int start,
508 ui::TextBoundaryDirection direction) const {
509 DCHECK_GE(start, 0);
510 DCHECK_LE(start, static_cast<int>(GetText().length()));
511
512 if (IsSimpleTextControl()) {
513 const std::vector<int32_t>& line_breaks =
514 GetIntListAttribute(ui::AX_ATTR_LINE_BREAKS);
515 return ui::FindAccessibleTextBoundary(GetText(), line_breaks,
516 ui::LINE_BOUNDARY, start, direction);
517 }
518
519 // Keeps track of the start offset of each consecutive line.
520 int line_start = 0;
521 // Keeps track of the length of each consecutive line.
522 int line_length = 0;
523 for (size_t i = 0; i < InternalChildCount(); ++i) {
524 const BrowserAccessibility* child = InternalGetChild(i);
525 DCHECK(child);
526 // Child objects are of length one, since they are represented by a
527 // single embedded object character. The exception is text-only objects.
528 int child_length = 1;
529 if (child->IsTextOnlyObject())
530 child_length = static_cast<int>(child->GetText().length());
531 line_length += child_length;
532 start -= child_length;
533
534 // Stop when we reach both the object containing our start offset and the
535 // end of the line on which this object is located.
536 if (start < 0 && !IsNextSiblingOnSameLine())
537 break;
538
539 if (!IsNextSiblingOnSameLine()) {
540 line_start += line_length;
541 line_length = 0;
542 }
543 }
544
545 switch (direction) {
546 case ui::FORWARDS_DIRECTION:
547 return line_start + line_length;
548 case ui::BACKWARDS_DIRECTION:
549 return line_start;
550 default:
551 NOTREACHED();
552 }
553 return static_cast<int>(GetText().length());
554 ;
dmazzoni 2016/04/22 15:34:49 nit: extra semicolon?
555 }
556
471 int BrowserAccessibility::GetWordStartBoundary( 557 int BrowserAccessibility::GetWordStartBoundary(
472 int start, ui::TextBoundaryDirection direction) const { 558 int start, ui::TextBoundaryDirection direction) const {
473 DCHECK_GE(start, -1); 559 DCHECK_GE(start, -1);
474 // Special offset that indicates that a word boundary has not been found. 560 // Special offset that indicates that a word boundary has not been found.
475 int word_start_not_found = static_cast<int>(GetText().size()); 561 int word_start_not_found = static_cast<int>(GetText().size());
476 int word_start = word_start_not_found; 562 int word_start = word_start_not_found;
477 563
478 switch (GetRole()) { 564 switch (GetRole()) {
479 case ui::AX_ROLE_STATIC_TEXT: { 565 case ui::AX_ROLE_STATIC_TEXT: {
480 int prev_word_start = word_start_not_found; 566 int prev_word_start = word_start_not_found;
481 int child_start = 0; 567 int child_start = 0;
482 int child_end = 0; 568 int child_end = 0;
483 569
484 // Go through the inline text boxes. 570 // Go through the inline text boxes.
485 for (size_t i = 0; i < InternalChildCount(); ++i) { 571 for (size_t i = 0; i < InternalChildCount(); ++i) {
486 // The next child starts where the previous one ended. 572 // The next child starts where the previous one ended.
487 child_start = child_end; 573 child_start = child_end;
488 BrowserAccessibility* child = InternalGetChild(i); 574 const BrowserAccessibility* child = InternalGetChild(i);
489 DCHECK_EQ(child->GetRole(), ui::AX_ROLE_INLINE_TEXT_BOX); 575 DCHECK_EQ(child->GetRole(), ui::AX_ROLE_INLINE_TEXT_BOX);
490 int child_len = static_cast<int>(child->GetText().size()); 576 int child_len = static_cast<int>(child->GetText().size());
491 child_end += child_len; // End is one past the last character. 577 child_end += child_len; // End is one past the last character.
492 578
493 const std::vector<int32_t>& word_starts = 579 const std::vector<int32_t>& word_starts =
494 child->GetIntListAttribute(ui::AX_ATTR_WORD_STARTS); 580 child->GetIntListAttribute(ui::AX_ATTR_WORD_STARTS);
495 if (word_starts.empty()) { 581 if (word_starts.empty()) {
496 word_start = child_end; 582 word_start = child_end;
497 continue; 583 continue;
498 } 584 }
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
546 if (IsSimpleTextControl() && InternalChildCount() == 1) { 632 if (IsSimpleTextControl() && InternalChildCount() == 1) {
547 this_object = InternalGetChild(0); 633 this_object = InternalGetChild(0);
548 } 634 }
549 int child_start = 0; 635 int child_start = 0;
550 for (size_t i = 0; i < this_object->InternalChildCount(); ++i) { 636 for (size_t i = 0; i < this_object->InternalChildCount(); ++i) {
551 BrowserAccessibility* child = this_object->InternalGetChild(i); 637 BrowserAccessibility* child = this_object->InternalGetChild(i);
552 // Child objects are of length one, since they are represented by a 638 // Child objects are of length one, since they are represented by a
553 // single embedded object character. The exception is text-only objects. 639 // single embedded object character. The exception is text-only objects.
554 int child_len = 1; 640 int child_len = 1;
555 if (child->IsTextOnlyObject()) { 641 if (child->IsTextOnlyObject()) {
556 child_len = static_cast<int>(child->GetText().size()); 642 child_len = static_cast<int>(child->GetText().length());
557 int child_word_start = child->GetWordStartBoundary(start, direction); 643 int child_word_start = child->GetWordStartBoundary(start, direction);
558 if (child_word_start < child_len) { 644 if (child_word_start < child_len) {
559 // We have found a possible word boundary. 645 // We have found a possible word boundary.
560 word_start = child_start + child_word_start; 646 word_start = child_start + child_word_start;
561 } 647 }
562 648
563 // Decide when to stop searching. 649 // Decide when to stop searching.
564 if ((word_start != word_start_not_found && 650 if ((word_start != word_start_not_found &&
565 direction == ui::FORWARDS_DIRECTION) || 651 direction == ui::FORWARDS_DIRECTION) ||
566 (start < child_len && direction == ui::BACKWARDS_DIRECTION)) { 652 (start < child_len && direction == ui::BACKWARDS_DIRECTION)) {
(...skipping 498 matching lines...) Expand 10 before | Expand all | Expand 10 after
1065 break; 1151 break;
1066 1152
1067 manager = root->GetParent()->manager(); 1153 manager = root->GetParent()->manager();
1068 root = manager->GetRoot(); 1154 root = manager->GetRoot();
1069 } 1155 }
1070 1156
1071 return bounds; 1157 return bounds;
1072 } 1158 }
1073 1159
1074 } // namespace content 1160 } // 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