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 |