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

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

Issue 1598583002: Fixed algorithms that compute bounding rectangles and word start offsets to take into account IA2 h… (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 11 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 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698