Chromium Code Reviews| 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 <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "base/strings/string_number_conversions.h" | 10 #include "base/strings/string_number_conversions.h" |
| (...skipping 293 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 304 | 304 |
| 305 // Adjust the bounds by the top left corner of the containing view's bounds | 305 // Adjust the bounds by the top left corner of the containing view's bounds |
| 306 // in screen coordinates. | 306 // in screen coordinates. |
| 307 bounds.Offset(manager_->GetViewBounds().OffsetFromOrigin()); | 307 bounds.Offset(manager_->GetViewBounds().OffsetFromOrigin()); |
| 308 | 308 |
| 309 return bounds; | 309 return bounds; |
| 310 } | 310 } |
| 311 | 311 |
| 312 int BrowserAccessibility::GetWordStartBoundary( | 312 int BrowserAccessibility::GetWordStartBoundary( |
| 313 int start, ui::TextBoundaryDirection direction) const { | 313 int start, ui::TextBoundaryDirection direction) const { |
| 314 int word_start = 0; | 314 DCHECK_GE(start, -1); |
| 315 int prev_word_start = 0; | 315 int unknown_offset = GetStaticTextLenRecursive(); |
| 316 if (GetRole() != ui::AX_ROLE_STATIC_TEXT) { | 316 int word_start = unknown_offset; |
| 317 for (size_t i = 0; i < InternalChildCount(); ++i) { | 317 |
| 318 BrowserAccessibility* child = InternalGetChild(i); | 318 switch (GetRole()) { |
| 319 int child_len = child->GetStaticTextLenRecursive(); | 319 case ui::AX_ROLE_STATIC_TEXT: { |
| 320 int child_word_start = child->GetWordStartBoundary(start, direction); | 320 int prev_word_start = unknown_offset; |
| 321 word_start += child_word_start; | 321 int child_start = 0; |
| 322 if (child_word_start != child_len) | 322 int child_end = 0; |
| 323 | |
| 324 // Go through the inline text boxes. | |
| 325 for (size_t i = 0; i < InternalChildCount(); ++i) { | |
| 326 // The next child starts where the previous one ended. | |
| 327 child_start = child_end; | |
| 328 BrowserAccessibility* child = InternalGetChild(i); | |
| 329 DCHECK_EQ(child->GetRole(), ui::AX_ROLE_INLINE_TEXT_BOX); | |
|
dmazzoni
2015/04/29 21:49:49
I think there's a bug that could trip this: I just
| |
| 330 const std::string& child_text = child->GetStringAttribute( | |
| 331 ui::AX_ATTR_VALUE); | |
| 332 int child_len = static_cast<int>(child_text.size()); | |
| 333 child_end += child_len; // End is one past the last character. | |
| 334 | |
| 335 const std::vector<int32>& word_starts = child->GetIntListAttribute( | |
| 336 ui::AX_ATTR_WORD_STARTS); | |
| 337 if (word_starts.empty()) { | |
| 338 word_start = child_end; | |
| 339 continue; | |
| 340 } | |
| 341 | |
| 342 int local_start = start - child_start; | |
| 343 std::vector<int32>::const_iterator iter = std::upper_bound( | |
| 344 word_starts.begin(), word_starts.end(), local_start); | |
| 345 if (iter != word_starts.end()) { | |
| 346 if (direction == ui::FORWARDS_DIRECTION) { | |
| 347 word_start = child_start + *iter; | |
| 348 } else if (direction == ui::BACKWARDS_DIRECTION) { | |
| 349 if (iter == word_starts.begin()) { | |
| 350 // Return the position of the last word in the previous child. | |
| 351 word_start = prev_word_start; | |
| 352 } else { | |
| 353 word_start = child_start + *(iter - 1); | |
|
dmazzoni
2015/04/29 21:49:50
Is this safe if iter points to the first element i
| |
| 354 } | |
| 355 } else { | |
| 356 NOTREACHED(); | |
| 357 } | |
| 323 break; | 358 break; |
| 324 start -= child_len; | 359 } |
| 325 } | |
| 326 return word_start; | |
| 327 } | |
| 328 | 360 |
| 329 int child_start = 0; | 361 // No word start that is greater than the requested offset has been |
| 330 int child_end = 0; | 362 // found. |
| 331 for (size_t i = 0; i < InternalChildCount(); ++i) { | 363 prev_word_start = child_start + *(iter - 1); |
| 332 // The next child starts where the previous one ended. | 364 if (direction == ui::FORWARDS_DIRECTION) { |
| 333 child_start = child_end; | 365 word_start = child_end; |
| 334 BrowserAccessibility* child = InternalGetChild(i); | 366 } else if (direction == ui::BACKWARDS_DIRECTION) { |
| 335 DCHECK_EQ(child->GetRole(), ui::AX_ROLE_INLINE_TEXT_BOX); | 367 word_start = prev_word_start; |
| 336 const std::string& child_text = child->GetStringAttribute( | 368 } else { |
| 337 ui::AX_ATTR_VALUE); | 369 NOTREACHED(); |
| 338 int child_len = static_cast<int>(child_text.size()); | 370 } |
| 339 child_end += child_len; // End is one past the last character. | 371 } |
| 340 | 372 return word_start; |
| 341 const std::vector<int32>& word_starts = child->GetIntListAttribute( | |
| 342 ui::AX_ATTR_WORD_STARTS); | |
| 343 if (word_starts.empty()) { | |
| 344 word_start = child_end; | |
| 345 continue; | |
| 346 } | 373 } |
| 347 | 374 |
| 348 int local_start = start - child_start; | 375 case ui::AX_ROLE_LINE_BREAK: |
| 349 std::vector<int32>::const_iterator iter = std::upper_bound( | 376 // Words never start at a line break. |
| 350 word_starts.begin(), word_starts.end(), local_start); | 377 return unknown_offset; |
|
dmazzoni
2015/04/29 21:49:49
I think it'd be more clear to use something like "
| |
| 351 if (iter != word_starts.end()) { | 378 |
| 352 if (direction == ui::FORWARDS_DIRECTION) { | 379 default: |
| 353 word_start = child_start + *iter; | 380 // If there are no children, the word start boundary is still unknown or |
| 354 } else if (direction == ui::BACKWARDS_DIRECTION) { | 381 // found previously depending on the direction. |
| 355 if (iter == word_starts.begin()) { | 382 if (!InternalChildCount()) |
| 356 // Return the position of the last word in the previous child. | 383 return unknown_offset; |
|
dmazzoni
2015/04/29 21:49:49
What happens if you have an element with a lot of
| |
| 357 word_start = prev_word_start; | 384 |
| 358 } else { | 385 int child_start = 0; |
| 359 word_start = child_start + *(iter - 1); | 386 for (size_t i = 0; i < InternalChildCount(); ++i) { |
| 387 BrowserAccessibility* child = InternalGetChild(i); | |
| 388 int child_len = child->GetStaticTextLenRecursive(); | |
| 389 int child_word_start = child->GetWordStartBoundary(start, direction); | |
| 390 if (child_word_start < child_len) { | |
| 391 // We have found a possible word boundary. | |
| 392 word_start = child_start + child_word_start; | |
| 360 } | 393 } |
| 361 } else { | 394 |
| 362 NOTREACHED(); | 395 // Decide when to stop searching. |
| 396 if ((word_start != unknown_offset && | |
|
dmazzoni
2015/04/29 21:49:50
nit: indentation
| |
| 397 direction == ui::FORWARDS_DIRECTION) || | |
| 398 (start < child_len && | |
| 399 direction == ui::BACKWARDS_DIRECTION)) { | |
| 400 break; | |
| 401 } | |
| 402 | |
| 403 child_start += child_len; | |
| 404 if (start >= child_len) | |
| 405 start -= child_len; | |
| 406 else | |
| 407 start = -1; | |
| 363 } | 408 } |
| 364 break; | 409 return word_start; |
| 365 } | |
| 366 | |
| 367 // No word start that is >= to the requested offset has been found. | |
| 368 prev_word_start = child_start + *(iter - 1); | |
| 369 if (direction == ui::FORWARDS_DIRECTION) { | |
| 370 word_start = child_end; | |
| 371 } else if (direction == ui::BACKWARDS_DIRECTION) { | |
| 372 word_start = prev_word_start; | |
| 373 } else { | |
| 374 NOTREACHED(); | |
| 375 } | |
| 376 } | 410 } |
| 377 | |
| 378 return word_start; | |
| 379 } | 411 } |
| 380 | 412 |
| 381 BrowserAccessibility* BrowserAccessibility::BrowserAccessibilityForPoint( | 413 BrowserAccessibility* BrowserAccessibility::BrowserAccessibilityForPoint( |
| 382 const gfx::Point& point) { | 414 const gfx::Point& point) { |
| 383 // The best result found that's a child of this object. | 415 // The best result found that's a child of this object. |
| 384 BrowserAccessibility* child_result = NULL; | 416 BrowserAccessibility* child_result = NULL; |
| 385 // The best result that's an indirect descendant like grandchild, etc. | 417 // The best result that's an indirect descendant like grandchild, etc. |
| 386 BrowserAccessibility* descendant_result = NULL; | 418 BrowserAccessibility* descendant_result = NULL; |
| 387 | 419 |
| 388 // Walk the children recursively looking for the BrowserAccessibility that | 420 // Walk the children recursively looking for the BrowserAccessibility that |
| (...skipping 326 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 715 return false; | 747 return false; |
| 716 | 748 |
| 717 BrowserAccessibility* grandparent = parent->GetParent(); | 749 BrowserAccessibility* grandparent = parent->GetParent(); |
| 718 if (!grandparent) | 750 if (!grandparent) |
| 719 return false; | 751 return false; |
| 720 | 752 |
| 721 return grandparent->GetRole() == ui::AX_ROLE_IFRAME_PRESENTATIONAL; | 753 return grandparent->GetRole() == ui::AX_ROLE_IFRAME_PRESENTATIONAL; |
| 722 } | 754 } |
| 723 | 755 |
| 724 int BrowserAccessibility::GetStaticTextLenRecursive() const { | 756 int BrowserAccessibility::GetStaticTextLenRecursive() const { |
| 725 if (GetRole() == ui::AX_ROLE_STATIC_TEXT) | 757 if (GetRole() == ui::AX_ROLE_STATIC_TEXT || |
| 758 GetRole() == ui::AX_ROLE_LINE_BREAK) { | |
| 726 return static_cast<int>(GetStringAttribute(ui::AX_ATTR_VALUE).size()); | 759 return static_cast<int>(GetStringAttribute(ui::AX_ATTR_VALUE).size()); |
| 760 } | |
| 727 | 761 |
| 728 int len = 0; | 762 int len = 0; |
| 729 for (size_t i = 0; i < InternalChildCount(); ++i) | 763 for (size_t i = 0; i < InternalChildCount(); ++i) |
| 730 len += InternalGetChild(i)->GetStaticTextLenRecursive(); | 764 len += InternalGetChild(i)->GetStaticTextLenRecursive(); |
| 731 return len; | 765 return len; |
| 732 } | 766 } |
| 733 | 767 |
| 734 BrowserAccessibility* BrowserAccessibility::GetParentForBoundsCalculation() | 768 BrowserAccessibility* BrowserAccessibility::GetParentForBoundsCalculation() |
| 735 const { | 769 const { |
| 736 if (!node_ || !manager_) | 770 if (!node_ || !manager_) |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 779 } | 813 } |
| 780 need_to_offset_web_area = true; | 814 need_to_offset_web_area = true; |
| 781 } | 815 } |
| 782 parent = parent->GetParentForBoundsCalculation(); | 816 parent = parent->GetParentForBoundsCalculation(); |
| 783 } | 817 } |
| 784 | 818 |
| 785 return bounds; | 819 return bounds; |
| 786 } | 820 } |
| 787 | 821 |
| 788 } // namespace content | 822 } // namespace content |
| OLD | NEW |