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

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

Issue 8416034: Support IAccessibleHypertext. (Closed) Base URL: http://git.chromium.org/git/chromium.git@trunk
Patch Set: Add unit tests. Created 9 years, 1 month 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 "base/string_number_conversions.h" 7 #include "base/string_number_conversions.h"
8 #include "base/string_util.h" 8 #include "base/string_util.h"
9 #include "base/utf_string_conversions.h" 9 #include "base/utf_string_conversions.h"
10 #include "base/win/scoped_comptr.h" 10 #include "base/win/scoped_comptr.h"
11 #include "content/browser/accessibility/browser_accessibility_manager_win.h" 11 #include "content/browser/accessibility/browser_accessibility_manager_win.h"
12 #include "content/common/view_messages.h" 12 #include "content/common/view_messages.h"
13 #include "net/base/escape.h" 13 #include "net/base/escape.h"
14 14
15 using webkit_glue::WebAccessibility; 15 using webkit_glue::WebAccessibility;
16 16
17 // The GUID for the ISimpleDOM service is not defined in the IDL files. 17 // The GUID for the ISimpleDOM service is not defined in the IDL files.
18 // This is taken directly from the Mozilla sources 18 // This is taken directly from the Mozilla sources
19 // (accessible/src/msaa/nsAccessNodeWrap.cpp) and it's also documented at: 19 // (accessible/src/msaa/nsAccessNodeWrap.cpp) and it's also documented at:
20 // http://developer.mozilla.org/en/Accessibility/AT-APIs/ImplementationFeatures/ MSAA 20 // http://developer.mozilla.org/en/Accessibility/AT-APIs/ImplementationFeatures/ MSAA
21 21
22 const GUID GUID_ISimpleDOM = { 22 const GUID GUID_ISimpleDOM = {
23 0x0c539790, 0x12e4, 0x11cf, 23 0x0c539790, 0x12e4, 0x11cf,
24 0xb6, 0x61, 0x00, 0xaa, 0x00, 0x4c, 0xd6, 0xd8}; 24 0xb6, 0x61, 0x00, 0xaa, 0x00, 0x4c, 0xd6, 0xd8};
25 25
26 const char16 BrowserAccessibilityWin::kEmbeddedCharacter[] = L"\xfffc";
27
26 // 28 //
27 // BrowserAccessibilityRelation 29 // BrowserAccessibilityRelation
28 // 30 //
29 // A simple implementation of IAccessibleRelation, used to represent 31 // A simple implementation of IAccessibleRelation, used to represent
30 // a relationship between two accessible nodes in the tree. 32 // a relationship between two accessible nodes in the tree.
31 // 33 //
32 34
33 class BrowserAccessibilityRelation 35 class BrowserAccessibilityRelation
34 : public CComObjectRootEx<CComMultiThreadModel>, 36 : public CComObjectRootEx<CComMultiThreadModel>,
35 public IAccessibleRelation { 37 public IAccessibleRelation {
(...skipping 1557 matching lines...) Expand 10 before | Expand all | Expand 10 after
1593 // IAccessibleText methods. 1595 // IAccessibleText methods.
1594 // 1596 //
1595 1597
1596 STDMETHODIMP BrowserAccessibilityWin::get_nCharacters(LONG* n_characters) { 1598 STDMETHODIMP BrowserAccessibilityWin::get_nCharacters(LONG* n_characters) {
1597 if (!instance_active_) 1599 if (!instance_active_)
1598 return E_FAIL; 1600 return E_FAIL;
1599 1601
1600 if (!n_characters) 1602 if (!n_characters)
1601 return E_INVALIDARG; 1603 return E_INVALIDARG;
1602 1604
1603 if (role_ == WebAccessibility::ROLE_TEXT_FIELD || 1605 *n_characters = TextForIAccessibleText().length();
1604 role_ == WebAccessibility::ROLE_TEXTAREA) {
1605 *n_characters = value_.length();
1606 } else {
1607 *n_characters = name_.length();
1608 }
1609
1610 return S_OK; 1606 return S_OK;
1611 } 1607 }
1612 1608
1613 STDMETHODIMP BrowserAccessibilityWin::get_caretOffset(LONG* offset) { 1609 STDMETHODIMP BrowserAccessibilityWin::get_caretOffset(LONG* offset) {
1614 if (!instance_active_) 1610 if (!instance_active_)
1615 return E_FAIL; 1611 return E_FAIL;
1616 1612
1617 if (!offset) 1613 if (!offset)
1618 return E_INVALIDARG; 1614 return E_INVALIDARG;
1619 1615
(...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after
1842 return E_INVALIDARG; 1838 return E_INVALIDARG;
1843 1839
1844 // TODO(dmazzoni): implement this. We're returning S_OK for now so that 1840 // TODO(dmazzoni): implement this. We're returning S_OK for now so that
1845 // screen readers still return partially accurate results rather than 1841 // screen readers still return partially accurate results rather than
1846 // completely failing. 1842 // completely failing.
1847 *offset = 0; 1843 *offset = 0;
1848 return S_OK; 1844 return S_OK;
1849 } 1845 }
1850 1846
1851 // 1847 //
1848 // IAccessibleHypertext methods.
1849 //
1850
1851 STDMETHODIMP BrowserAccessibilityWin::get_nHyperlinks(long* hyperlink_count) {
1852 if (!instance_active_)
1853 return E_FAIL;
1854
1855 if (!hyperlink_count)
1856 return E_INVALIDARG;
1857
1858 *hyperlink_count = hyperlink_offset_to_index_.size();
1859 return S_OK;
1860 }
1861
1862 STDMETHODIMP BrowserAccessibilityWin::get_hyperlink(
1863 long index,
1864 IAccessibleHyperlink** hyperlink) {
1865 if (!instance_active_)
1866 return E_FAIL;
1867
1868 if (!hyperlink)
1869 return E_INVALIDARG;
1870
1871 std::map<int32, int32>::iterator it =
1872 hyperlink_offset_to_index_.find(index);
1873 if (it == hyperlink_offset_to_index_.end())
1874 return E_FAIL;
1875
1876 *hyperlink = static_cast<IAccessibleHyperlink*>(
1877 children_[it->second]->toBrowserAccessibilityWin()->NewReference());
1878 return S_OK;
1879 }
1880
1881 STDMETHODIMP BrowserAccessibilityWin::get_hyperlinkIndex(
1882 long char_index,
1883 long* hyperlink_index) {
1884 if (!instance_active_)
1885 return E_FAIL;
1886
1887 if (!hyperlink_index)
1888 return E_INVALIDARG;
1889
1890 *hyperlink_index = -1;
1891
1892 if (char_index < 0 || char_index >= static_cast<long>(hypertext_.size()))
1893 return E_INVALIDARG;
1894
1895 std::map<int32, int32>::iterator it =
1896 hyperlink_offset_to_index_.find(char_index);
1897 if (it == hyperlink_offset_to_index_.end())
1898 return E_FAIL;
1899
1900 *hyperlink_index = it->first;
1901 return S_OK;
1902 }
1903
1904 //
1852 // IAccessibleValue methods. 1905 // IAccessibleValue methods.
1853 // 1906 //
1854 1907
1855 STDMETHODIMP BrowserAccessibilityWin::get_currentValue(VARIANT* value) { 1908 STDMETHODIMP BrowserAccessibilityWin::get_currentValue(VARIANT* value) {
1856 if (!instance_active_) 1909 if (!instance_active_)
1857 return E_FAIL; 1910 return E_FAIL;
1858 1911
1859 if (!value) 1912 if (!value)
1860 return E_INVALIDARG; 1913 return E_INVALIDARG;
1861 1914
(...skipping 373 matching lines...) Expand 10 before | Expand all | Expand 10 after
2235 // IServiceProvider methods. 2288 // IServiceProvider methods.
2236 // 2289 //
2237 2290
2238 STDMETHODIMP BrowserAccessibilityWin::QueryService( 2291 STDMETHODIMP BrowserAccessibilityWin::QueryService(
2239 REFGUID guidService, REFIID riid, void** object) { 2292 REFGUID guidService, REFIID riid, void** object) {
2240 if (!instance_active_) 2293 if (!instance_active_)
2241 return E_FAIL; 2294 return E_FAIL;
2242 2295
2243 if (guidService == IID_IAccessible || 2296 if (guidService == IID_IAccessible ||
2244 guidService == IID_IAccessible2 || 2297 guidService == IID_IAccessible2 ||
2298 guidService == IID_IAccessibleAction ||
2299 guidService == IID_IAccessibleHyperlink ||
2300 guidService == IID_IAccessibleHypertext ||
2245 guidService == IID_IAccessibleImage || 2301 guidService == IID_IAccessibleImage ||
2246 guidService == IID_IAccessibleTable || 2302 guidService == IID_IAccessibleTable ||
2247 guidService == IID_IAccessibleTable2 || 2303 guidService == IID_IAccessibleTable2 ||
2248 guidService == IID_IAccessibleTableCell || 2304 guidService == IID_IAccessibleTableCell ||
2249 guidService == IID_IAccessibleText || 2305 guidService == IID_IAccessibleText ||
2250 guidService == IID_IAccessibleValue || 2306 guidService == IID_IAccessibleValue ||
2251 guidService == IID_ISimpleDOMDocument || 2307 guidService == IID_ISimpleDOMDocument ||
2252 guidService == IID_ISimpleDOMNode || 2308 guidService == IID_ISimpleDOMNode ||
2253 guidService == IID_ISimpleDOMText || 2309 guidService == IID_ISimpleDOMText ||
2254 guidService == GUID_ISimpleDOM) { 2310 guidService == GUID_ISimpleDOM) {
2255 return QueryInterface(riid, object); 2311 return QueryInterface(riid, object);
2256 } 2312 }
2257 2313
2258 *object = NULL; 2314 *object = NULL;
2259 return E_FAIL; 2315 return E_FAIL;
2260 } 2316 }
2261 2317
2262 // 2318 //
2263 // CComObjectRootEx methods. 2319 // CComObjectRootEx methods.
2264 // 2320 //
2265 2321
2266 HRESULT WINAPI BrowserAccessibilityWin::InternalQueryInterface( 2322 HRESULT WINAPI BrowserAccessibilityWin::InternalQueryInterface(
2267 void* this_ptr, 2323 void* this_ptr,
2268 const _ATL_INTMAP_ENTRY* entries, 2324 const _ATL_INTMAP_ENTRY* entries,
2269 REFIID iid, 2325 REFIID iid,
2270 void** object) { 2326 void** object) {
2271 if (iid == IID_IAccessibleText) { 2327 if (iid == IID_IAccessibleImage) {
2272 if (ia_role_ != ROLE_SYSTEM_LINK && ia_role_ != ROLE_SYSTEM_TEXT) {
2273 *object = NULL;
2274 return E_NOINTERFACE;
2275 }
2276 } else if (iid == IID_IAccessibleImage) {
2277 if (ia_role_ != ROLE_SYSTEM_GRAPHIC) { 2328 if (ia_role_ != ROLE_SYSTEM_GRAPHIC) {
2278 *object = NULL; 2329 *object = NULL;
2279 return E_NOINTERFACE; 2330 return E_NOINTERFACE;
2280 } 2331 }
2281 } else if (iid == IID_IAccessibleTable || iid == IID_IAccessibleTable2) { 2332 } else if (iid == IID_IAccessibleTable || iid == IID_IAccessibleTable2) {
2282 if (ia_role_ != ROLE_SYSTEM_TABLE) { 2333 if (ia_role_ != ROLE_SYSTEM_TABLE) {
2283 *object = NULL; 2334 *object = NULL;
2284 return E_NOINTERFACE; 2335 return E_NOINTERFACE;
2285 } 2336 }
2286 } else if (iid == IID_IAccessibleTableCell) { 2337 } else if (iid == IID_IAccessibleTableCell) {
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after
2410 // Add a labelled by relationship. 2461 // Add a labelled by relationship.
2411 CComObject<BrowserAccessibilityRelation>* relation; 2462 CComObject<BrowserAccessibilityRelation>* relation;
2412 HRESULT hr = CComObject<BrowserAccessibilityRelation>::CreateInstance( 2463 HRESULT hr = CComObject<BrowserAccessibilityRelation>::CreateInstance(
2413 &relation); 2464 &relation);
2414 DCHECK(SUCCEEDED(hr)); 2465 DCHECK(SUCCEEDED(hr));
2415 relation->AddRef(); 2466 relation->AddRef();
2416 relation->Initialize(this, IA2_RELATION_LABELLED_BY); 2467 relation->Initialize(this, IA2_RELATION_LABELLED_BY);
2417 relation->AddTarget(title_elem_id); 2468 relation->AddTarget(title_elem_id);
2418 relations_.push_back(relation); 2469 relations_.push_back(relation);
2419 } 2470 }
2471
2472 // Construct the hypertext for this node.
2473 hyperlink_offset_to_index_.clear();
2474 hypertext_.clear();
2475 for (unsigned int i = 0; i < children().size(); ++i) {
2476 BrowserAccessibility* child = children()[i];
2477 if (child->role() == WebAccessibility::ROLE_STATIC_TEXT) {
2478 hypertext_ += child->name();
2479 } else {
2480 hyperlink_offset_to_index_[hypertext_.size()] = i;
2481 hypertext_ += kEmbeddedCharacter;
2482 }
2483 }
2420 } 2484 }
2421 2485
2422 void BrowserAccessibilityWin::SendNodeUpdateEvents() { 2486 void BrowserAccessibilityWin::SendNodeUpdateEvents() {
2423 // Fire an event when an alert first appears. 2487 // Fire an event when an alert first appears.
2424 if (role_ == WebAccessibility::ROLE_ALERT && first_time_) 2488 if (role_ == WebAccessibility::ROLE_ALERT && first_time_)
2425 manager_->NotifyAccessibilityEvent(ViewHostMsg_AccEvent::ALERT, this); 2489 manager_->NotifyAccessibilityEvent(ViewHostMsg_AccEvent::ALERT, this);
2426 2490
2427 // Fire events if text has changed. 2491 // Fire events if text has changed.
2428 string16 text = TextForIAccessibleText(); 2492 string16 text = TextForIAccessibleText();
2429 if (previous_text_ != text) { 2493 if (previous_text_ != text) {
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
2509 base::IntToString16(value)); 2573 base::IntToString16(value));
2510 } 2574 }
2511 2575
2512 string16 BrowserAccessibilityWin::Escape(const string16& str) { 2576 string16 BrowserAccessibilityWin::Escape(const string16& str) {
2513 return net::EscapeQueryParamValueUTF8(str, false); 2577 return net::EscapeQueryParamValueUTF8(str, false);
2514 } 2578 }
2515 2579
2516 const string16& BrowserAccessibilityWin::TextForIAccessibleText() { 2580 const string16& BrowserAccessibilityWin::TextForIAccessibleText() {
2517 if (IsEditableText()) { 2581 if (IsEditableText()) {
2518 return value_; 2582 return value_;
2583 } else if (role_ == WebAccessibility::ROLE_STATIC_TEXT) {
2584 return name_;
2519 } else { 2585 } else {
2520 return name_; 2586 return hypertext_;
2521 } 2587 }
2522 } 2588 }
2523 2589
2524 void BrowserAccessibilityWin::HandleSpecialTextOffset( 2590 void BrowserAccessibilityWin::HandleSpecialTextOffset(
2525 const string16& text, LONG* offset) { 2591 const string16& text, LONG* offset) {
2526 if (*offset == IA2_TEXT_OFFSET_LENGTH) { 2592 if (*offset == IA2_TEXT_OFFSET_LENGTH) {
2527 *offset = static_cast<LONG>(text.size()); 2593 *offset = static_cast<LONG>(text.size());
2528 } else if (*offset == IA2_TEXT_OFFSET_CARET) { 2594 } else if (*offset == IA2_TEXT_OFFSET_CARET) {
2529 get_caretOffset(offset); 2595 get_caretOffset(offset);
2530 } 2596 }
(...skipping 487 matching lines...) Expand 10 before | Expand all | Expand 10 after
3018 } 3084 }
3019 3085
3020 // The role should always be set. 3086 // The role should always be set.
3021 DCHECK(!role_name_.empty() || ia_role_); 3087 DCHECK(!role_name_.empty() || ia_role_);
3022 3088
3023 // If we didn't explicitly set the IAccessible2 role, make it the same 3089 // If we didn't explicitly set the IAccessible2 role, make it the same
3024 // as the MSAA role. 3090 // as the MSAA role.
3025 if (!ia2_role_) 3091 if (!ia2_role_)
3026 ia2_role_ = ia_role_; 3092 ia2_role_ = ia_role_;
3027 } 3093 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698