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

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

Issue 1111163002: Fixed word and line navigation in multi-line text fields. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 7 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 <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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698