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 <stddef.h> | 7 #include <stddef.h> |
8 | 8 |
9 #include <algorithm> | 9 #include <algorithm> |
10 | 10 |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
97 return false; | 97 return false; |
98 } | 98 } |
99 | 99 |
100 bool BrowserAccessibility::IsTextOnlyObject() const { | 100 bool BrowserAccessibility::IsTextOnlyObject() const { |
101 return GetRole() == ui::AX_ROLE_STATIC_TEXT || | 101 return GetRole() == ui::AX_ROLE_STATIC_TEXT || |
102 GetRole() == ui::AX_ROLE_LINE_BREAK; | 102 GetRole() == ui::AX_ROLE_LINE_BREAK; |
103 } | 103 } |
104 | 104 |
105 BrowserAccessibility* BrowserAccessibility::PlatformGetChild( | 105 BrowserAccessibility* BrowserAccessibility::PlatformGetChild( |
106 uint32_t child_index) const { | 106 uint32_t child_index) const { |
107 DCHECK(child_index < PlatformChildCount()); | 107 DCHECK_LT(child_index, PlatformChildCount()); |
108 BrowserAccessibility* result = nullptr; | 108 BrowserAccessibility* result = nullptr; |
109 | 109 |
110 if (HasIntAttribute(ui::AX_ATTR_CHILD_TREE_ID)) { | 110 if (HasIntAttribute(ui::AX_ATTR_CHILD_TREE_ID)) { |
111 BrowserAccessibilityManager* child_manager = | 111 BrowserAccessibilityManager* child_manager = |
112 BrowserAccessibilityManager::FromID( | 112 BrowserAccessibilityManager::FromID( |
113 GetIntAttribute(ui::AX_ATTR_CHILD_TREE_ID)); | 113 GetIntAttribute(ui::AX_ATTR_CHILD_TREE_ID)); |
114 if (child_manager) | 114 if (child_manager) |
115 result = child_manager->GetRoot(); | 115 result = child_manager->GetRoot(); |
116 } else { | 116 } else { |
117 result = InternalGetChild(child_index); | 117 result = InternalGetChild(child_index); |
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
254 // Adjust the bounds by the top left corner of the containing view's bounds | 254 // Adjust the bounds by the top left corner of the containing view's bounds |
255 // in screen coordinates. | 255 // in screen coordinates. |
256 bounds.Offset(manager_->GetViewBounds().OffsetFromOrigin()); | 256 bounds.Offset(manager_->GetViewBounds().OffsetFromOrigin()); |
257 | 257 |
258 return bounds; | 258 return bounds; |
259 } | 259 } |
260 | 260 |
261 gfx::Rect BrowserAccessibility::GetLocalBoundsForRange(int start, int len) | 261 gfx::Rect BrowserAccessibility::GetLocalBoundsForRange(int start, int len) |
262 const { | 262 const { |
263 if (GetRole() != ui::AX_ROLE_STATIC_TEXT) { | 263 if (GetRole() != ui::AX_ROLE_STATIC_TEXT) { |
264 // Apply recursively to all static text descendants. For example, if | |
265 // you call it on a div with two text node children, it just calls | |
266 // GetLocalBoundsForRange on each of the two children (adjusting | |
267 // |start| for each one) and unions the resulting rects. | |
268 gfx::Rect bounds; | 264 gfx::Rect bounds; |
269 for (size_t i = 0; i < InternalChildCount(); ++i) { | 265 for (size_t i = 0; i < InternalChildCount() && start >= 0; ++i) { |
270 BrowserAccessibility* child = InternalGetChild(i); | 266 BrowserAccessibility* child = InternalGetChild(i); |
271 int child_len = child->GetInnerTextLength(); | 267 // Embedded objects are of length one, since they are represented only by |
dmazzoni
2016/01/20 01:10:43
This comment confuses me. It talks about embedded
| |
272 if (start < child_len && start + len > 0) { | 268 // a special character. |
273 gfx::Rect child_rect = child->GetLocalBoundsForRange(start, len); | 269 int child_length_in_parent = |
270 child->IsTextOnlyObject() ? static_cast<int>(child->GetText().size()) | |
271 : 1; | |
272 if (start < child_length_in_parent) { | |
273 gfx::Rect child_rect; | |
274 if (child->IsTextOnlyObject()) | |
275 child_rect = child->GetLocalBoundsForRange(start, len); | |
276 else | |
dmazzoni
2016/01/20 01:10:43
nit: Need braces around both blocks
| |
277 child_rect = child->GetLocalBoundsForRange( | |
278 start, static_cast<int>(child->GetText().size())); | |
274 bounds.Union(child_rect); | 279 bounds.Union(child_rect); |
280 len -= child_length_in_parent; | |
275 } | 281 } |
276 start -= child_len; | 282 start -= child_length_in_parent; |
277 } | 283 } |
278 return ElementBoundsToLocalBounds(bounds); | 284 return ElementBoundsToLocalBounds(bounds); |
279 } | 285 } |
280 | 286 |
281 int end = start + len; | 287 int end = start + len; |
282 int child_start = 0; | 288 int child_start = 0; |
283 int child_end = 0; | 289 int child_end = 0; |
284 | 290 |
285 gfx::Rect bounds; | 291 gfx::Rect bounds; |
286 for (size_t i = 0; i < InternalChildCount() && child_end < start + len; ++i) { | 292 for (size_t i = 0; i < InternalChildCount() && child_end < start + len; ++i) { |
287 BrowserAccessibility* child = InternalGetChild(i); | 293 BrowserAccessibility* child = InternalGetChild(i); |
288 if (child->GetRole() != ui::AX_ROLE_INLINE_TEXT_BOX) { | 294 if (child->GetRole() != ui::AX_ROLE_INLINE_TEXT_BOX) { |
289 DLOG(WARNING) << "BrowserAccessibility objects with role STATIC_TEXT " << | 295 DLOG(WARNING) << "BrowserAccessibility objects with role STATIC_TEXT " << |
290 "should have children of role INLINE_TEXT_BOX."; | 296 "should have children of role INLINE_TEXT_BOX."; |
291 continue; | 297 continue; |
292 } | 298 } |
293 | 299 |
294 std::string child_text; | 300 int child_len = static_cast<int>(GetText().size()); |
295 child->GetStringAttribute(ui::AX_ATTR_NAME, &child_text); | |
296 int child_len = static_cast<int>(child_text.size()); | |
297 child_start = child_end; | 301 child_start = child_end; |
298 child_end += child_len; | 302 child_end += child_len; |
299 | 303 |
300 if (child_end < start) | 304 if (child_end < start) |
301 continue; | 305 continue; |
302 | 306 |
303 int overlap_start = std::max(start, child_start); | 307 int overlap_start = std::max(start, child_start); |
304 int overlap_end = std::min(end, child_end); | 308 int overlap_end = std::min(end, child_end); |
305 | 309 |
306 int local_start = overlap_start - child_start; | 310 int local_start = overlap_start - child_start; |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
375 base::string16 value = GetString16Attribute(ui::AX_ATTR_VALUE); | 379 base::string16 value = GetString16Attribute(ui::AX_ATTR_VALUE); |
376 if (value.empty() && IsSimpleTextControl()) | 380 if (value.empty() && IsSimpleTextControl()) |
377 value = GetInnerText(); | 381 value = GetInnerText(); |
378 return value; | 382 return value; |
379 } | 383 } |
380 | 384 |
381 int BrowserAccessibility::GetWordStartBoundary( | 385 int BrowserAccessibility::GetWordStartBoundary( |
382 int start, ui::TextBoundaryDirection direction) const { | 386 int start, ui::TextBoundaryDirection direction) const { |
383 DCHECK_GE(start, -1); | 387 DCHECK_GE(start, -1); |
384 // Special offset that indicates that a word boundary has not been found. | 388 // Special offset that indicates that a word boundary has not been found. |
385 int word_start_not_found = GetInnerTextLength(); | 389 int word_start_not_found = static_cast<int>(GetText().size()); |
386 int word_start = word_start_not_found; | 390 int word_start = word_start_not_found; |
387 | 391 |
388 switch (GetRole()) { | 392 switch (GetRole()) { |
389 case ui::AX_ROLE_STATIC_TEXT: { | 393 case ui::AX_ROLE_STATIC_TEXT: { |
390 int prev_word_start = word_start_not_found; | 394 int prev_word_start = word_start_not_found; |
391 int child_start = 0; | 395 int child_start = 0; |
392 int child_end = 0; | 396 int child_end = 0; |
393 | 397 |
394 // Go through the inline text boxes. | 398 // Go through the inline text boxes. |
395 for (size_t i = 0; i < InternalChildCount(); ++i) { | 399 for (size_t i = 0; i < InternalChildCount(); ++i) { |
396 // The next child starts where the previous one ended. | 400 // The next child starts where the previous one ended. |
397 child_start = child_end; | 401 child_start = child_end; |
398 BrowserAccessibility* child = InternalGetChild(i); | 402 BrowserAccessibility* child = InternalGetChild(i); |
399 DCHECK_EQ(child->GetRole(), ui::AX_ROLE_INLINE_TEXT_BOX); | 403 DCHECK_EQ(child->GetRole(), ui::AX_ROLE_INLINE_TEXT_BOX); |
400 const std::string& child_text = child->GetStringAttribute( | 404 int child_len = static_cast<int>(GetText().size()); |
401 ui::AX_ATTR_NAME); | |
402 int child_len = static_cast<int>(child_text.size()); | |
403 child_end += child_len; // End is one past the last character. | 405 child_end += child_len; // End is one past the last character. |
404 | 406 |
405 const std::vector<int32_t>& word_starts = | 407 const std::vector<int32_t>& word_starts = |
406 child->GetIntListAttribute(ui::AX_ATTR_WORD_STARTS); | 408 child->GetIntListAttribute(ui::AX_ATTR_WORD_STARTS); |
407 if (word_starts.empty()) { | 409 if (word_starts.empty()) { |
408 word_start = child_end; | 410 word_start = child_end; |
409 continue; | 411 continue; |
410 } | 412 } |
411 | 413 |
412 int local_start = start - child_start; | 414 int local_start = start - child_start; |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
448 | 450 |
449 default: | 451 default: |
450 // If there are no children, the word start boundary is still unknown or | 452 // If there are no children, the word start boundary is still unknown or |
451 // found previously depending on the direction. | 453 // found previously depending on the direction. |
452 if (!InternalChildCount()) | 454 if (!InternalChildCount()) |
453 return word_start_not_found; | 455 return word_start_not_found; |
454 | 456 |
455 int child_start = 0; | 457 int child_start = 0; |
456 for (size_t i = 0; i < InternalChildCount(); ++i) { | 458 for (size_t i = 0; i < InternalChildCount(); ++i) { |
457 BrowserAccessibility* child = InternalGetChild(i); | 459 BrowserAccessibility* child = InternalGetChild(i); |
458 int child_len = child->GetInnerTextLength(); | 460 // An embedded object is always represented by a single special |
459 int child_word_start = child->GetWordStartBoundary(start, direction); | 461 // character. |
460 if (child_word_start < child_len) { | 462 int child_len = 1; |
461 // We have found a possible word boundary. | 463 if (child->IsTextOnlyObject()) { |
462 word_start = child_start + child_word_start; | 464 child_len = static_cast<int>(child->GetText().size()); |
463 } | 465 int child_word_start = child->GetWordStartBoundary(start, direction); |
466 if (child_word_start < child_len) { | |
467 // We have found a possible word boundary. | |
468 word_start = child_start + child_word_start; | |
469 } | |
464 | 470 |
465 // Decide when to stop searching. | 471 // Decide when to stop searching. |
466 if ((word_start != word_start_not_found && | 472 if ((word_start != word_start_not_found && |
467 direction == ui::FORWARDS_DIRECTION) || | 473 direction == ui::FORWARDS_DIRECTION) || |
468 (start < child_len && | 474 (start < child_len && direction == ui::BACKWARDS_DIRECTION)) { |
469 direction == ui::BACKWARDS_DIRECTION)) { | 475 break; |
470 break; | 476 } |
471 } | 477 } |
472 | 478 |
473 child_start += child_len; | 479 child_start += child_len; |
474 if (start >= child_len) | 480 if (start >= child_len) |
475 start -= child_len; | 481 start -= child_len; |
476 else | 482 else |
477 start = -1; | 483 start = -1; |
478 } | 484 } |
479 return word_start; | 485 return word_start; |
480 } | 486 } |
(...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
649 } | 655 } |
650 | 656 |
651 *is_defined = true; | 657 *is_defined = true; |
652 | 658 |
653 if (base::EqualsASCII(value, "true")) | 659 if (base::EqualsASCII(value, "true")) |
654 return true; | 660 return true; |
655 | 661 |
656 if (base::EqualsASCII(value, "mixed")) | 662 if (base::EqualsASCII(value, "mixed")) |
657 *is_mixed = true; | 663 *is_mixed = true; |
658 | 664 |
659 return false; // Not set | 665 return false; // Not set. |
660 } | 666 } |
661 | 667 |
662 bool BrowserAccessibility::HasState(ui::AXState state_enum) const { | 668 bool BrowserAccessibility::HasState(ui::AXState state_enum) const { |
663 return (GetState() >> state_enum) & 1; | 669 return (GetState() >> state_enum) & 1; |
664 } | 670 } |
665 | 671 |
666 bool BrowserAccessibility::IsCellOrTableHeaderRole() const { | 672 bool BrowserAccessibility::IsCellOrTableHeaderRole() const { |
667 return (GetRole() == ui::AX_ROLE_CELL || | 673 return (GetRole() == ui::AX_ROLE_CELL || |
668 GetRole() == ui::AX_ROLE_COLUMN_HEADER || | 674 GetRole() == ui::AX_ROLE_COLUMN_HEADER || |
669 GetRole() == ui::AX_ROLE_ROW_HEADER); | 675 GetRole() == ui::AX_ROLE_ROW_HEADER); |
670 } | 676 } |
671 | 677 |
672 bool BrowserAccessibility::HasCaret() const { | 678 bool BrowserAccessibility::HasCaret() const { |
673 if (IsEditableText() && !HasState(ui::AX_STATE_RICHLY_EDITABLE) && | 679 if (HasState(ui::AX_STATE_EDITABLE) && |
680 !HasState(ui::AX_STATE_RICHLY_EDITABLE) && | |
674 HasIntAttribute(ui::AX_ATTR_TEXT_SEL_START) && | 681 HasIntAttribute(ui::AX_ATTR_TEXT_SEL_START) && |
675 HasIntAttribute(ui::AX_ATTR_TEXT_SEL_END)) { | 682 HasIntAttribute(ui::AX_ATTR_TEXT_SEL_END)) { |
676 return true; | 683 return true; |
677 } | 684 } |
678 | 685 |
679 // The caret is always at the focus of the selection. | 686 // The caret is always at the focus of the selection. |
680 int32_t focus_id = manager()->GetTreeData().sel_focus_object_id; | 687 int32_t focus_id = manager()->GetTreeData().sel_focus_object_id; |
681 BrowserAccessibility* focus_object = manager()->GetFromID(focus_id); | 688 BrowserAccessibility* focus_object = manager()->GetFromID(focus_id); |
682 if (!focus_object) | 689 if (!focus_object) |
683 return false; | 690 return false; |
684 | 691 |
685 if (!focus_object->IsDescendantOf(this)) | 692 if (!focus_object->IsDescendantOf(this)) |
686 return false; | 693 return false; |
687 | 694 |
688 return true; | 695 return true; |
689 } | 696 } |
690 | 697 |
691 bool BrowserAccessibility::IsEditableText() const { | |
692 return HasState(ui::AX_STATE_EDITABLE); | |
693 } | |
694 | |
695 bool BrowserAccessibility::IsWebAreaForPresentationalIframe() const { | 698 bool BrowserAccessibility::IsWebAreaForPresentationalIframe() const { |
696 if (GetRole() != ui::AX_ROLE_WEB_AREA && | 699 if (GetRole() != ui::AX_ROLE_WEB_AREA && |
697 GetRole() != ui::AX_ROLE_ROOT_WEB_AREA) { | 700 GetRole() != ui::AX_ROLE_ROOT_WEB_AREA) { |
698 return false; | 701 return false; |
699 } | 702 } |
700 | 703 |
701 BrowserAccessibility* parent = GetParent(); | 704 BrowserAccessibility* parent = GetParent(); |
702 if (!parent) | 705 if (!parent) |
703 return false; | 706 return false; |
704 | 707 |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
785 base::string16 BrowserAccessibility::GetInnerText() const { | 788 base::string16 BrowserAccessibility::GetInnerText() const { |
786 if (IsTextOnlyObject()) | 789 if (IsTextOnlyObject()) |
787 return GetString16Attribute(ui::AX_ATTR_NAME); | 790 return GetString16Attribute(ui::AX_ATTR_NAME); |
788 | 791 |
789 base::string16 text; | 792 base::string16 text; |
790 for (size_t i = 0; i < InternalChildCount(); ++i) | 793 for (size_t i = 0; i < InternalChildCount(); ++i) |
791 text += InternalGetChild(i)->GetInnerText(); | 794 text += InternalGetChild(i)->GetInnerText(); |
792 return text; | 795 return text; |
793 } | 796 } |
794 | 797 |
795 int BrowserAccessibility::GetInnerTextLength() const { | |
796 return static_cast<int>(GetInnerText().size()); | |
797 } | |
798 | |
799 void BrowserAccessibility::FixEmptyBounds(gfx::Rect* bounds) const | 798 void BrowserAccessibility::FixEmptyBounds(gfx::Rect* bounds) const |
800 { | 799 { |
801 if (bounds->width() > 0 && bounds->height() > 0) | 800 if (bounds->width() > 0 && bounds->height() > 0) |
802 return; | 801 return; |
803 | 802 |
804 for (size_t i = 0; i < InternalChildCount(); ++i) { | 803 for (size_t i = 0; i < InternalChildCount(); ++i) { |
805 // Compute the bounds of each child - this calls FixEmptyBounds | 804 // Compute the bounds of each child - this calls FixEmptyBounds |
806 // recursively if necessary. | 805 // recursively if necessary. |
807 BrowserAccessibility* child = InternalGetChild(i); | 806 BrowserAccessibility* child = InternalGetChild(i); |
808 gfx::Rect child_bounds = child->GetLocalBoundsRect(); | 807 gfx::Rect child_bounds = child->GetLocalBoundsRect(); |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
856 } | 855 } |
857 need_to_offset_web_area = true; | 856 need_to_offset_web_area = true; |
858 } | 857 } |
859 parent = parent->GetParent(); | 858 parent = parent->GetParent(); |
860 } | 859 } |
861 | 860 |
862 return bounds; | 861 return bounds; |
863 } | 862 } |
864 | 863 |
865 } // namespace content | 864 } // namespace content |
OLD | NEW |