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

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

Issue 8914009: Reland 8775059 Support IAccessibleHypertext. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 9 years 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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_win.h" 5 #include "content/browser/accessibility/browser_accessibility_win.h"
6 6
7 #include <limits> 7 #include <limits>
8 8
9 #include "base/string_number_conversions.h" 9 #include "base/string_number_conversions.h"
10 #include "base/string_util.h" 10 #include "base/string_util.h"
11 #include "base/utf_string_conversions.h" 11 #include "base/utf_string_conversions.h"
12 #include "base/win/enum_variant.h" 12 #include "base/win/enum_variant.h"
13 #include "base/win/scoped_comptr.h" 13 #include "base/win/scoped_comptr.h"
14 #include "content/browser/accessibility/browser_accessibility_manager_win.h" 14 #include "content/browser/accessibility/browser_accessibility_manager_win.h"
15 #include "content/common/view_messages.h" 15 #include "content/common/view_messages.h"
16 #include "net/base/escape.h" 16 #include "net/base/escape.h"
17 #include "ui/base/accessibility/accessible_text_utils.h" 17 #include "ui/base/accessibility/accessible_text_utils.h"
18 18
19 using webkit_glue::WebAccessibility; 19 using webkit_glue::WebAccessibility;
20 20
21 // The GUID for the ISimpleDOM service is not defined in the IDL files. 21 // The GUID for the ISimpleDOM service is not defined in the IDL files.
22 // This is taken directly from the Mozilla sources 22 // This is taken directly from the Mozilla sources
23 // (accessible/src/msaa/nsAccessNodeWrap.cpp) and it's also documented at: 23 // (accessible/src/msaa/nsAccessNodeWrap.cpp) and it's also documented at:
24 // http://developer.mozilla.org/en/Accessibility/AT-APIs/ImplementationFeatures/ MSAA 24 // http://developer.mozilla.org/en/Accessibility/AT-APIs/ImplementationFeatures/ MSAA
25 25
26 const GUID GUID_ISimpleDOM = { 26 const GUID GUID_ISimpleDOM = {
27 0x0c539790, 0x12e4, 0x11cf, 27 0x0c539790, 0x12e4, 0x11cf,
28 0xb6, 0x61, 0x00, 0xaa, 0x00, 0x4c, 0xd6, 0xd8}; 28 0xb6, 0x61, 0x00, 0xaa, 0x00, 0x4c, 0xd6, 0xd8};
29 29
30 const char16 BrowserAccessibilityWin::kEmbeddedCharacter[] = L"\xfffc";
31
30 // 32 //
31 // BrowserAccessibilityRelation 33 // BrowserAccessibilityRelation
32 // 34 //
33 // A simple implementation of IAccessibleRelation, used to represent 35 // A simple implementation of IAccessibleRelation, used to represent
34 // a relationship between two accessible nodes in the tree. 36 // a relationship between two accessible nodes in the tree.
35 // 37 //
36 38
37 class BrowserAccessibilityRelation 39 class BrowserAccessibilityRelation
38 : public CComObjectRootEx<CComMultiThreadModel>, 40 : public CComObjectRootEx<CComMultiThreadModel>,
39 public IAccessibleRelation { 41 public IAccessibleRelation {
(...skipping 1705 matching lines...) Expand 10 before | Expand all | Expand 10 after
1745 // IAccessibleText methods. 1747 // IAccessibleText methods.
1746 // 1748 //
1747 1749
1748 STDMETHODIMP BrowserAccessibilityWin::get_nCharacters(LONG* n_characters) { 1750 STDMETHODIMP BrowserAccessibilityWin::get_nCharacters(LONG* n_characters) {
1749 if (!instance_active_) 1751 if (!instance_active_)
1750 return E_FAIL; 1752 return E_FAIL;
1751 1753
1752 if (!n_characters) 1754 if (!n_characters)
1753 return E_INVALIDARG; 1755 return E_INVALIDARG;
1754 1756
1755 if (role_ == WebAccessibility::ROLE_TEXT_FIELD || 1757 *n_characters = TextForIAccessibleText().length();
1756 role_ == WebAccessibility::ROLE_TEXTAREA) {
1757 *n_characters = value_.length();
1758 } else {
1759 *n_characters = name_.length();
1760 }
1761
1762 return S_OK; 1758 return S_OK;
1763 } 1759 }
1764 1760
1765 STDMETHODIMP BrowserAccessibilityWin::get_caretOffset(LONG* offset) { 1761 STDMETHODIMP BrowserAccessibilityWin::get_caretOffset(LONG* offset) {
1766 if (!instance_active_) 1762 if (!instance_active_)
1767 return E_FAIL; 1763 return E_FAIL;
1768 1764
1769 if (!offset) 1765 if (!offset)
1770 return E_INVALIDARG; 1766 return E_INVALIDARG;
1771 1767
(...skipping 294 matching lines...) Expand 10 before | Expand all | Expand 10 after
2066 2062
2067 const string16& text_str = TextForIAccessibleText(); 2063 const string16& text_str = TextForIAccessibleText();
2068 HandleSpecialTextOffset(text_str, &start_offset); 2064 HandleSpecialTextOffset(text_str, &start_offset);
2069 HandleSpecialTextOffset(text_str, &end_offset); 2065 HandleSpecialTextOffset(text_str, &end_offset);
2070 2066
2071 manager_->SetTextSelection(*this, start_offset, end_offset); 2067 manager_->SetTextSelection(*this, start_offset, end_offset);
2072 return S_OK; 2068 return S_OK;
2073 } 2069 }
2074 2070
2075 // 2071 //
2072 // IAccessibleHypertext methods.
2073 //
2074
2075 STDMETHODIMP BrowserAccessibilityWin::get_nHyperlinks(long* hyperlink_count) {
2076 if (!instance_active_)
2077 return E_FAIL;
2078
2079 if (!hyperlink_count)
2080 return E_INVALIDARG;
2081
2082 *hyperlink_count = hyperlink_offset_to_index_.size();
2083 return S_OK;
2084 }
2085
2086 STDMETHODIMP BrowserAccessibilityWin::get_hyperlink(
2087 long index,
2088 IAccessibleHyperlink** hyperlink) {
2089 if (!instance_active_)
2090 return E_FAIL;
2091
2092 if (!hyperlink ||
2093 index < 0 ||
2094 index >= static_cast<long>(hyperlinks_.size())) {
2095 return E_INVALIDARG;
2096 }
2097
2098 BrowserAccessibilityWin* child =
2099 children_[hyperlinks_[index]]->toBrowserAccessibilityWin();
2100 *hyperlink = static_cast<IAccessibleHyperlink*>(child->NewReference());
2101 return S_OK;
2102 }
2103
2104 STDMETHODIMP BrowserAccessibilityWin::get_hyperlinkIndex(
2105 long char_index,
2106 long* hyperlink_index) {
2107 if (!instance_active_)
2108 return E_FAIL;
2109
2110 if (!hyperlink_index)
2111 return E_INVALIDARG;
2112
2113 *hyperlink_index = -1;
2114
2115 if (char_index < 0 || char_index >= static_cast<long>(hypertext_.size()))
2116 return E_INVALIDARG;
2117
2118 std::map<int32, int32>::iterator it =
2119 hyperlink_offset_to_index_.find(char_index);
2120 if (it == hyperlink_offset_to_index_.end())
2121 return E_FAIL;
2122
2123 *hyperlink_index = it->second;
2124 return S_OK;
2125 }
2126
2127 //
2076 // IAccessibleValue methods. 2128 // IAccessibleValue methods.
2077 // 2129 //
2078 2130
2079 STDMETHODIMP BrowserAccessibilityWin::get_currentValue(VARIANT* value) { 2131 STDMETHODIMP BrowserAccessibilityWin::get_currentValue(VARIANT* value) {
2080 if (!instance_active_) 2132 if (!instance_active_)
2081 return E_FAIL; 2133 return E_FAIL;
2082 2134
2083 if (!value) 2135 if (!value)
2084 return E_INVALIDARG; 2136 return E_INVALIDARG;
2085 2137
(...skipping 375 matching lines...) Expand 10 before | Expand all | Expand 10 after
2461 // IServiceProvider methods. 2513 // IServiceProvider methods.
2462 // 2514 //
2463 2515
2464 STDMETHODIMP BrowserAccessibilityWin::QueryService( 2516 STDMETHODIMP BrowserAccessibilityWin::QueryService(
2465 REFGUID guidService, REFIID riid, void** object) { 2517 REFGUID guidService, REFIID riid, void** object) {
2466 if (!instance_active_) 2518 if (!instance_active_)
2467 return E_FAIL; 2519 return E_FAIL;
2468 2520
2469 if (guidService == IID_IAccessible || 2521 if (guidService == IID_IAccessible ||
2470 guidService == IID_IAccessible2 || 2522 guidService == IID_IAccessible2 ||
2523 guidService == IID_IAccessibleAction ||
2524 guidService == IID_IAccessibleHyperlink ||
2525 guidService == IID_IAccessibleHypertext ||
2471 guidService == IID_IAccessibleImage || 2526 guidService == IID_IAccessibleImage ||
2472 guidService == IID_IAccessibleTable || 2527 guidService == IID_IAccessibleTable ||
2473 guidService == IID_IAccessibleTable2 || 2528 guidService == IID_IAccessibleTable2 ||
2474 guidService == IID_IAccessibleTableCell || 2529 guidService == IID_IAccessibleTableCell ||
2475 guidService == IID_IAccessibleText || 2530 guidService == IID_IAccessibleText ||
2476 guidService == IID_IAccessibleValue || 2531 guidService == IID_IAccessibleValue ||
2477 guidService == IID_ISimpleDOMDocument || 2532 guidService == IID_ISimpleDOMDocument ||
2478 guidService == IID_ISimpleDOMNode || 2533 guidService == IID_ISimpleDOMNode ||
2479 guidService == IID_ISimpleDOMText || 2534 guidService == IID_ISimpleDOMText ||
2480 guidService == GUID_ISimpleDOM) { 2535 guidService == GUID_ISimpleDOM) {
2481 return QueryInterface(riid, object); 2536 return QueryInterface(riid, object);
2482 } 2537 }
2483 2538
2484 *object = NULL; 2539 *object = NULL;
2485 return E_FAIL; 2540 return E_FAIL;
2486 } 2541 }
2487 2542
2488 // 2543 //
2489 // CComObjectRootEx methods. 2544 // CComObjectRootEx methods.
2490 // 2545 //
2491 2546
2492 HRESULT WINAPI BrowserAccessibilityWin::InternalQueryInterface( 2547 HRESULT WINAPI BrowserAccessibilityWin::InternalQueryInterface(
2493 void* this_ptr, 2548 void* this_ptr,
2494 const _ATL_INTMAP_ENTRY* entries, 2549 const _ATL_INTMAP_ENTRY* entries,
2495 REFIID iid, 2550 REFIID iid,
2496 void** object) { 2551 void** object) {
2497 if (iid == IID_IAccessibleText) { 2552 if (iid == IID_IAccessibleImage) {
2498 if (ia_role_ != ROLE_SYSTEM_LINK && ia_role_ != ROLE_SYSTEM_TEXT) {
2499 *object = NULL;
2500 return E_NOINTERFACE;
2501 }
2502 } else if (iid == IID_IAccessibleImage) {
2503 if (ia_role_ != ROLE_SYSTEM_GRAPHIC) { 2553 if (ia_role_ != ROLE_SYSTEM_GRAPHIC) {
2504 *object = NULL; 2554 *object = NULL;
2505 return E_NOINTERFACE; 2555 return E_NOINTERFACE;
2506 } 2556 }
2507 } else if (iid == IID_IAccessibleTable || iid == IID_IAccessibleTable2) { 2557 } else if (iid == IID_IAccessibleTable || iid == IID_IAccessibleTable2) {
2508 if (ia_role_ != ROLE_SYSTEM_TABLE) { 2558 if (ia_role_ != ROLE_SYSTEM_TABLE) {
2509 *object = NULL; 2559 *object = NULL;
2510 return E_NOINTERFACE; 2560 return E_NOINTERFACE;
2511 } 2561 }
2512 } else if (iid == IID_IAccessibleTableCell) { 2562 } else if (iid == IID_IAccessibleTableCell) {
(...skipping 17 matching lines...) Expand all
2530 2580
2531 return CComObjectRootBase::InternalQueryInterface( 2581 return CComObjectRootBase::InternalQueryInterface(
2532 this_ptr, entries, iid, object); 2582 this_ptr, entries, iid, object);
2533 } 2583 }
2534 2584
2535 // 2585 //
2536 // Private methods. 2586 // Private methods.
2537 // 2587 //
2538 2588
2539 // Initialize this object and mark it as active. 2589 // Initialize this object and mark it as active.
2540 void BrowserAccessibilityWin::Initialize() { 2590 void BrowserAccessibilityWin::PreInitialize() {
2541 BrowserAccessibility::Initialize(); 2591 BrowserAccessibility::PreInitialize();
2542 2592
2543 InitRoleAndState(); 2593 InitRoleAndState();
2544 2594
2545 // Expose headings levels with the "level" attribute. 2595 // Expose headings levels with the "level" attribute.
2546 if (role_ == WebAccessibility::ROLE_HEADING && role_name_.size() == 2 && 2596 if (role_ == WebAccessibility::ROLE_HEADING && role_name_.size() == 2 &&
2547 IsAsciiDigit(role_name_[1])) { 2597 IsAsciiDigit(role_name_[1])) {
2548 ia2_attributes_.push_back(string16(L"level:") + role_name_.substr(1)); 2598 ia2_attributes_.push_back(string16(L"level:") + role_name_.substr(1));
2549 } 2599 }
2550 2600
2551 // Expose the "display" and "tag" attributes. 2601 // Expose the "display" and "tag" attributes.
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after
2650 HRESULT hr = CComObject<BrowserAccessibilityRelation>::CreateInstance( 2700 HRESULT hr = CComObject<BrowserAccessibilityRelation>::CreateInstance(
2651 &relation); 2701 &relation);
2652 DCHECK(SUCCEEDED(hr)); 2702 DCHECK(SUCCEEDED(hr));
2653 relation->AddRef(); 2703 relation->AddRef();
2654 relation->Initialize(this, IA2_RELATION_LABELLED_BY); 2704 relation->Initialize(this, IA2_RELATION_LABELLED_BY);
2655 relation->AddTarget(title_elem_id); 2705 relation->AddTarget(title_elem_id);
2656 relations_.push_back(relation); 2706 relations_.push_back(relation);
2657 } 2707 }
2658 } 2708 }
2659 2709
2660 void BrowserAccessibilityWin::SendNodeUpdateEvents() { 2710 void BrowserAccessibilityWin::PostInitialize() {
2711 BrowserAccessibility::PostInitialize();
2712
2713 // Construct the hypertext for this node.
2714 hyperlink_offset_to_index_.clear();
2715 hyperlinks_.clear();
2716 hypertext_.clear();
2717 for (unsigned int i = 0; i < children().size(); ++i) {
2718 BrowserAccessibility* child = children()[i];
2719 if (child->role() == WebAccessibility::ROLE_STATIC_TEXT) {
2720 hypertext_ += child->name();
2721 } else {
2722 hyperlink_offset_to_index_[hypertext_.size()] = hyperlinks_.size();
2723 hypertext_ += kEmbeddedCharacter;
2724 hyperlinks_.push_back(i);
2725 }
2726 }
2727 DCHECK_EQ(hyperlink_offset_to_index_.size(), hyperlinks_.size());
2728
2661 // Fire an event when an alert first appears. 2729 // Fire an event when an alert first appears.
2662 if (role_ == WebAccessibility::ROLE_ALERT && first_time_) 2730 if (role_ == WebAccessibility::ROLE_ALERT && first_time_)
2663 manager_->NotifyAccessibilityEvent(ViewHostMsg_AccEvent::ALERT, this); 2731 manager_->NotifyAccessibilityEvent(ViewHostMsg_AccEvent::ALERT, this);
2664 2732
2665 // Fire events if text has changed. 2733 // Fire events if text has changed.
2666 string16 text = TextForIAccessibleText(); 2734 string16 text = TextForIAccessibleText();
2667 if (previous_text_ != text) { 2735 if (previous_text_ != text) {
2668 if (!previous_text_.empty() && !text.empty()) { 2736 if (!previous_text_.empty() && !text.empty()) {
2669 manager_->NotifyAccessibilityEvent( 2737 manager_->NotifyAccessibilityEvent(
2670 ViewHostMsg_AccEvent::OBJECT_SHOW, this); 2738 ViewHostMsg_AccEvent::OBJECT_SHOW, this);
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after
2781 base::IntToString16(value)); 2849 base::IntToString16(value));
2782 } 2850 }
2783 2851
2784 string16 BrowserAccessibilityWin::Escape(const string16& str) { 2852 string16 BrowserAccessibilityWin::Escape(const string16& str) {
2785 return net::EscapeQueryParamValueUTF8(str, false); 2853 return net::EscapeQueryParamValueUTF8(str, false);
2786 } 2854 }
2787 2855
2788 const string16& BrowserAccessibilityWin::TextForIAccessibleText() { 2856 const string16& BrowserAccessibilityWin::TextForIAccessibleText() {
2789 if (IsEditableText()) { 2857 if (IsEditableText()) {
2790 return value_; 2858 return value_;
2859 } else if (role_ == WebAccessibility::ROLE_STATIC_TEXT) {
2860 return name_;
2791 } else { 2861 } else {
2792 return name_; 2862 return hypertext_;
2793 } 2863 }
2794 } 2864 }
2795 2865
2796 void BrowserAccessibilityWin::HandleSpecialTextOffset( 2866 void BrowserAccessibilityWin::HandleSpecialTextOffset(
2797 const string16& text, LONG* offset) { 2867 const string16& text, LONG* offset) {
2798 if (*offset == IA2_TEXT_OFFSET_LENGTH) { 2868 if (*offset == IA2_TEXT_OFFSET_LENGTH) {
2799 *offset = static_cast<LONG>(text.size()); 2869 *offset = static_cast<LONG>(text.size());
2800 } else if (*offset == IA2_TEXT_OFFSET_CARET) { 2870 } else if (*offset == IA2_TEXT_OFFSET_CARET) {
2801 get_caretOffset(offset); 2871 get_caretOffset(offset);
2802 } 2872 }
(...skipping 437 matching lines...) Expand 10 before | Expand all | Expand 10 after
3240 } 3310 }
3241 3311
3242 // The role should always be set. 3312 // The role should always be set.
3243 DCHECK(!role_name_.empty() || ia_role_); 3313 DCHECK(!role_name_.empty() || ia_role_);
3244 3314
3245 // If we didn't explicitly set the IAccessible2 role, make it the same 3315 // If we didn't explicitly set the IAccessible2 role, make it the same
3246 // as the MSAA role. 3316 // as the MSAA role.
3247 if (!ia2_role_) 3317 if (!ia2_role_)
3248 ia2_role_ = ia_role_; 3318 ia2_role_ = ia_role_;
3249 } 3319 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698