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

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: Addressed first bunch of comments. 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 210 matching lines...) Expand 10 before | Expand all | Expand 10 after
221 return ElementBoundsToLocalBounds(bounds); 221 return ElementBoundsToLocalBounds(bounds);
222 } 222 }
223 223
224 int end = start + len; 224 int end = start + len;
225 int child_start = 0; 225 int child_start = 0;
226 int child_end = 0; 226 int child_end = 0;
227 227
228 gfx::Rect bounds; 228 gfx::Rect bounds;
229 for (size_t i = 0; i < InternalChildCount() && child_end < start + len; ++i) { 229 for (size_t i = 0; i < InternalChildCount() && child_end < start + len; ++i) {
230 BrowserAccessibility* child = InternalGetChild(i); 230 BrowserAccessibility* child = InternalGetChild(i);
231 DCHECK_EQ(child->GetRole(), ui::AX_ROLE_INLINE_TEXT_BOX); 231 if (child->GetRole() != ui::AX_ROLE_INLINE_TEXT_BOX) {
232 DLOG(WARNING) << "BrowserAccessibility objects with role STATIC_TEXT " <<
233 "should have children of role INLINE_TEXT_BOX.";
234 continue;
235 }
236
232 std::string child_text; 237 std::string child_text;
233 child->GetStringAttribute(ui::AX_ATTR_VALUE, &child_text); 238 child->GetStringAttribute(ui::AX_ATTR_VALUE, &child_text);
234 int child_len = static_cast<int>(child_text.size()); 239 int child_len = static_cast<int>(child_text.size());
235 child_start = child_end; 240 child_start = child_end;
236 child_end += child_len; 241 child_end += child_len;
237 242
238 if (child_end < start) 243 if (child_end < start)
239 continue; 244 continue;
240 245
241 int overlap_start = std::max(start, child_start); 246 int overlap_start = std::max(start, child_start);
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
304 309
305 // Adjust the bounds by the top left corner of the containing view's bounds 310 // Adjust the bounds by the top left corner of the containing view's bounds
306 // in screen coordinates. 311 // in screen coordinates.
307 bounds.Offset(manager_->GetViewBounds().OffsetFromOrigin()); 312 bounds.Offset(manager_->GetViewBounds().OffsetFromOrigin());
308 313
309 return bounds; 314 return bounds;
310 } 315 }
311 316
312 int BrowserAccessibility::GetWordStartBoundary( 317 int BrowserAccessibility::GetWordStartBoundary(
313 int start, ui::TextBoundaryDirection direction) const { 318 int start, ui::TextBoundaryDirection direction) const {
314 int word_start = 0; 319 DCHECK_GE(start, -1);
315 int prev_word_start = 0; 320 // Special offset that indicates that a word boundary has not been found.
316 if (GetRole() != ui::AX_ROLE_STATIC_TEXT) { 321 int word_start_not_found = GetStaticTextLenRecursive();
317 for (size_t i = 0; i < InternalChildCount(); ++i) { 322 int word_start = word_start_not_found;
318 BrowserAccessibility* child = InternalGetChild(i); 323
319 int child_len = child->GetStaticTextLenRecursive(); 324 switch (GetRole()) {
320 int child_word_start = child->GetWordStartBoundary(start, direction); 325 case ui::AX_ROLE_STATIC_TEXT: {
321 word_start += child_word_start; 326 int prev_word_start = word_start_not_found;
322 if (child_word_start != child_len) 327 int child_start = 0;
328 int child_end = 0;
329
330 // Go through the inline text boxes.
331 for (size_t i = 0; i < InternalChildCount(); ++i) {
332 // The next child starts where the previous one ended.
333 child_start = child_end;
334 BrowserAccessibility* child = InternalGetChild(i);
335 DCHECK_EQ(child->GetRole(), ui::AX_ROLE_INLINE_TEXT_BOX);
336 const std::string& child_text = child->GetStringAttribute(
337 ui::AX_ATTR_VALUE);
338 int child_len = static_cast<int>(child_text.size());
339 child_end += child_len; // End is one past the last character.
340
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 }
347
348 int local_start = start - child_start;
349 std::vector<int32>::const_iterator iter = std::upper_bound(
350 word_starts.begin(), word_starts.end(), local_start);
351 if (iter != word_starts.end()) {
352 if (direction == ui::FORWARDS_DIRECTION) {
353 word_start = child_start + *iter;
354 } else if (direction == ui::BACKWARDS_DIRECTION) {
355 if (iter == word_starts.begin()) {
356 // Return the position of the last word in the previous child.
357 word_start = prev_word_start;
358 } else {
359 word_start = child_start + *(iter - 1);
360 }
361 } else {
362 NOTREACHED();
363 }
323 break; 364 break;
324 start -= child_len; 365 }
325 }
326 return word_start;
327 }
328 366
329 int child_start = 0; 367 // No word start that is greater than the requested offset has been
330 int child_end = 0; 368 // found.
331 for (size_t i = 0; i < InternalChildCount(); ++i) { 369 prev_word_start = child_start + *(iter - 1);
332 // The next child starts where the previous one ended. 370 if (direction == ui::FORWARDS_DIRECTION) {
333 child_start = child_end; 371 word_start = child_end;
334 BrowserAccessibility* child = InternalGetChild(i); 372 } else if (direction == ui::BACKWARDS_DIRECTION) {
335 DCHECK_EQ(child->GetRole(), ui::AX_ROLE_INLINE_TEXT_BOX); 373 word_start = prev_word_start;
336 const std::string& child_text = child->GetStringAttribute( 374 } else {
337 ui::AX_ATTR_VALUE); 375 NOTREACHED();
338 int child_len = static_cast<int>(child_text.size()); 376 }
339 child_end += child_len; // End is one past the last character. 377 }
340 378 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 } 379 }
347 380
348 int local_start = start - child_start; 381 case ui::AX_ROLE_LINE_BREAK:
349 std::vector<int32>::const_iterator iter = std::upper_bound( 382 // Words never start at a line break.
350 word_starts.begin(), word_starts.end(), local_start); 383 return word_start_not_found;
351 if (iter != word_starts.end()) { 384
352 if (direction == ui::FORWARDS_DIRECTION) { 385 default:
353 word_start = child_start + *iter; 386 // If there are no children, the word start boundary is still unknown or
354 } else if (direction == ui::BACKWARDS_DIRECTION) { 387 // found previously depending on the direction.
355 if (iter == word_starts.begin()) { 388 if (!InternalChildCount())
356 // Return the position of the last word in the previous child. 389 return word_start_not_found;
357 word_start = prev_word_start; 390
358 } else { 391 int child_start = 0;
359 word_start = child_start + *(iter - 1); 392 for (size_t i = 0; i < InternalChildCount(); ++i) {
393 BrowserAccessibility* child = InternalGetChild(i);
394 int child_len = child->GetStaticTextLenRecursive();
395 int child_word_start = child->GetWordStartBoundary(start, direction);
396 if (child_word_start < child_len) {
397 // We have found a possible word boundary.
398 word_start = child_start + child_word_start;
360 } 399 }
361 } else { 400
362 NOTREACHED(); 401 // Decide when to stop searching.
402 if ((word_start != word_start_not_found &&
403 direction == ui::FORWARDS_DIRECTION) ||
404 (start < child_len &&
405 direction == ui::BACKWARDS_DIRECTION)) {
406 break;
407 }
408
409 child_start += child_len;
410 if (start >= child_len)
411 start -= child_len;
412 else
413 start = -1;
363 } 414 }
364 break; 415 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 } 416 }
377
378 return word_start;
379 } 417 }
380 418
381 BrowserAccessibility* BrowserAccessibility::BrowserAccessibilityForPoint( 419 BrowserAccessibility* BrowserAccessibility::BrowserAccessibilityForPoint(
382 const gfx::Point& point) { 420 const gfx::Point& point) {
383 // The best result found that's a child of this object. 421 // The best result found that's a child of this object.
384 BrowserAccessibility* child_result = NULL; 422 BrowserAccessibility* child_result = NULL;
385 // The best result that's an indirect descendant like grandchild, etc. 423 // The best result that's an indirect descendant like grandchild, etc.
386 BrowserAccessibility* descendant_result = NULL; 424 BrowserAccessibility* descendant_result = NULL;
387 425
388 // Walk the children recursively looking for the BrowserAccessibility that 426 // Walk the children recursively looking for the BrowserAccessibility that
(...skipping 326 matching lines...) Expand 10 before | Expand all | Expand 10 after
715 return false; 753 return false;
716 754
717 BrowserAccessibility* grandparent = parent->GetParent(); 755 BrowserAccessibility* grandparent = parent->GetParent();
718 if (!grandparent) 756 if (!grandparent)
719 return false; 757 return false;
720 758
721 return grandparent->GetRole() == ui::AX_ROLE_IFRAME_PRESENTATIONAL; 759 return grandparent->GetRole() == ui::AX_ROLE_IFRAME_PRESENTATIONAL;
722 } 760 }
723 761
724 int BrowserAccessibility::GetStaticTextLenRecursive() const { 762 int BrowserAccessibility::GetStaticTextLenRecursive() const {
725 if (GetRole() == ui::AX_ROLE_STATIC_TEXT) 763 if (GetRole() == ui::AX_ROLE_STATIC_TEXT ||
764 GetRole() == ui::AX_ROLE_LINE_BREAK) {
726 return static_cast<int>(GetStringAttribute(ui::AX_ATTR_VALUE).size()); 765 return static_cast<int>(GetStringAttribute(ui::AX_ATTR_VALUE).size());
766 }
727 767
728 int len = 0; 768 int len = 0;
729 for (size_t i = 0; i < InternalChildCount(); ++i) 769 for (size_t i = 0; i < InternalChildCount(); ++i)
730 len += InternalGetChild(i)->GetStaticTextLenRecursive(); 770 len += InternalGetChild(i)->GetStaticTextLenRecursive();
731 return len; 771 return len;
732 } 772 }
733 773
734 BrowserAccessibility* BrowserAccessibility::GetParentForBoundsCalculation() 774 BrowserAccessibility* BrowserAccessibility::GetParentForBoundsCalculation()
735 const { 775 const {
736 if (!node_ || !manager_) 776 if (!node_ || !manager_)
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
779 } 819 }
780 need_to_offset_web_area = true; 820 need_to_offset_web_area = true;
781 } 821 }
782 parent = parent->GetParentForBoundsCalculation(); 822 parent = parent->GetParentForBoundsCalculation();
783 } 823 }
784 824
785 return bounds; 825 return bounds;
786 } 826 }
787 827
788 } // namespace content 828 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698