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 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |