OLD | NEW |
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 Loading... |
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 Loading... |
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 index < 0 || |
| 1870 index >= static_cast<long>(hyperlinks_.size())) { |
| 1871 return E_INVALIDARG; |
| 1872 } |
| 1873 |
| 1874 BrowserAccessibilityWin* child = |
| 1875 children_[hyperlinks_[index]]->toBrowserAccessibilityWin(); |
| 1876 *hyperlink = static_cast<IAccessibleHyperlink*>(child->NewReference()); |
| 1877 return S_OK; |
| 1878 } |
| 1879 |
| 1880 STDMETHODIMP BrowserAccessibilityWin::get_hyperlinkIndex( |
| 1881 long char_index, |
| 1882 long* hyperlink_index) { |
| 1883 if (!instance_active_) |
| 1884 return E_FAIL; |
| 1885 |
| 1886 if (!hyperlink_index) |
| 1887 return E_INVALIDARG; |
| 1888 |
| 1889 *hyperlink_index = -1; |
| 1890 |
| 1891 if (char_index < 0 || char_index >= static_cast<long>(hypertext_.size())) |
| 1892 return E_INVALIDARG; |
| 1893 |
| 1894 std::map<int32, int32>::iterator it = |
| 1895 hyperlink_offset_to_index_.find(char_index); |
| 1896 if (it == hyperlink_offset_to_index_.end()) |
| 1897 return E_FAIL; |
| 1898 |
| 1899 *hyperlink_index = it->second; |
| 1900 return S_OK; |
| 1901 } |
| 1902 |
| 1903 // |
1852 // IAccessibleValue methods. | 1904 // IAccessibleValue methods. |
1853 // | 1905 // |
1854 | 1906 |
1855 STDMETHODIMP BrowserAccessibilityWin::get_currentValue(VARIANT* value) { | 1907 STDMETHODIMP BrowserAccessibilityWin::get_currentValue(VARIANT* value) { |
1856 if (!instance_active_) | 1908 if (!instance_active_) |
1857 return E_FAIL; | 1909 return E_FAIL; |
1858 | 1910 |
1859 if (!value) | 1911 if (!value) |
1860 return E_INVALIDARG; | 1912 return E_INVALIDARG; |
1861 | 1913 |
(...skipping 373 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2235 // IServiceProvider methods. | 2287 // IServiceProvider methods. |
2236 // | 2288 // |
2237 | 2289 |
2238 STDMETHODIMP BrowserAccessibilityWin::QueryService( | 2290 STDMETHODIMP BrowserAccessibilityWin::QueryService( |
2239 REFGUID guidService, REFIID riid, void** object) { | 2291 REFGUID guidService, REFIID riid, void** object) { |
2240 if (!instance_active_) | 2292 if (!instance_active_) |
2241 return E_FAIL; | 2293 return E_FAIL; |
2242 | 2294 |
2243 if (guidService == IID_IAccessible || | 2295 if (guidService == IID_IAccessible || |
2244 guidService == IID_IAccessible2 || | 2296 guidService == IID_IAccessible2 || |
| 2297 guidService == IID_IAccessibleAction || |
| 2298 guidService == IID_IAccessibleHyperlink || |
| 2299 guidService == IID_IAccessibleHypertext || |
2245 guidService == IID_IAccessibleImage || | 2300 guidService == IID_IAccessibleImage || |
2246 guidService == IID_IAccessibleTable || | 2301 guidService == IID_IAccessibleTable || |
2247 guidService == IID_IAccessibleTable2 || | 2302 guidService == IID_IAccessibleTable2 || |
2248 guidService == IID_IAccessibleTableCell || | 2303 guidService == IID_IAccessibleTableCell || |
2249 guidService == IID_IAccessibleText || | 2304 guidService == IID_IAccessibleText || |
2250 guidService == IID_IAccessibleValue || | 2305 guidService == IID_IAccessibleValue || |
2251 guidService == IID_ISimpleDOMDocument || | 2306 guidService == IID_ISimpleDOMDocument || |
2252 guidService == IID_ISimpleDOMNode || | 2307 guidService == IID_ISimpleDOMNode || |
2253 guidService == IID_ISimpleDOMText || | 2308 guidService == IID_ISimpleDOMText || |
2254 guidService == GUID_ISimpleDOM) { | 2309 guidService == GUID_ISimpleDOM) { |
2255 return QueryInterface(riid, object); | 2310 return QueryInterface(riid, object); |
2256 } | 2311 } |
2257 | 2312 |
2258 *object = NULL; | 2313 *object = NULL; |
2259 return E_FAIL; | 2314 return E_FAIL; |
2260 } | 2315 } |
2261 | 2316 |
2262 // | 2317 // |
2263 // CComObjectRootEx methods. | 2318 // CComObjectRootEx methods. |
2264 // | 2319 // |
2265 | 2320 |
2266 HRESULT WINAPI BrowserAccessibilityWin::InternalQueryInterface( | 2321 HRESULT WINAPI BrowserAccessibilityWin::InternalQueryInterface( |
2267 void* this_ptr, | 2322 void* this_ptr, |
2268 const _ATL_INTMAP_ENTRY* entries, | 2323 const _ATL_INTMAP_ENTRY* entries, |
2269 REFIID iid, | 2324 REFIID iid, |
2270 void** object) { | 2325 void** object) { |
2271 if (iid == IID_IAccessibleText) { | 2326 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) { | 2327 if (ia_role_ != ROLE_SYSTEM_GRAPHIC) { |
2278 *object = NULL; | 2328 *object = NULL; |
2279 return E_NOINTERFACE; | 2329 return E_NOINTERFACE; |
2280 } | 2330 } |
2281 } else if (iid == IID_IAccessibleTable || iid == IID_IAccessibleTable2) { | 2331 } else if (iid == IID_IAccessibleTable || iid == IID_IAccessibleTable2) { |
2282 if (ia_role_ != ROLE_SYSTEM_TABLE) { | 2332 if (ia_role_ != ROLE_SYSTEM_TABLE) { |
2283 *object = NULL; | 2333 *object = NULL; |
2284 return E_NOINTERFACE; | 2334 return E_NOINTERFACE; |
2285 } | 2335 } |
2286 } else if (iid == IID_IAccessibleTableCell) { | 2336 } else if (iid == IID_IAccessibleTableCell) { |
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2410 // Add a labelled by relationship. | 2460 // Add a labelled by relationship. |
2411 CComObject<BrowserAccessibilityRelation>* relation; | 2461 CComObject<BrowserAccessibilityRelation>* relation; |
2412 HRESULT hr = CComObject<BrowserAccessibilityRelation>::CreateInstance( | 2462 HRESULT hr = CComObject<BrowserAccessibilityRelation>::CreateInstance( |
2413 &relation); | 2463 &relation); |
2414 DCHECK(SUCCEEDED(hr)); | 2464 DCHECK(SUCCEEDED(hr)); |
2415 relation->AddRef(); | 2465 relation->AddRef(); |
2416 relation->Initialize(this, IA2_RELATION_LABELLED_BY); | 2466 relation->Initialize(this, IA2_RELATION_LABELLED_BY); |
2417 relation->AddTarget(title_elem_id); | 2467 relation->AddTarget(title_elem_id); |
2418 relations_.push_back(relation); | 2468 relations_.push_back(relation); |
2419 } | 2469 } |
| 2470 |
| 2471 // Construct the hypertext for this node. |
| 2472 hyperlink_offset_to_index_.clear(); |
| 2473 hyperlinks_.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()] = hyperlinks_.size(); |
| 2481 hypertext_ += kEmbeddedCharacter; |
| 2482 hyperlinks_.push_back(i); |
| 2483 } |
| 2484 } |
| 2485 DCHECK_EQ(hyperlink_offset_to_index_.size(), hyperlinks_.size()); |
2420 } | 2486 } |
2421 | 2487 |
2422 void BrowserAccessibilityWin::SendNodeUpdateEvents() { | 2488 void BrowserAccessibilityWin::SendNodeUpdateEvents() { |
2423 // Fire an event when an alert first appears. | 2489 // Fire an event when an alert first appears. |
2424 if (role_ == WebAccessibility::ROLE_ALERT && first_time_) | 2490 if (role_ == WebAccessibility::ROLE_ALERT && first_time_) |
2425 manager_->NotifyAccessibilityEvent(ViewHostMsg_AccEvent::ALERT, this); | 2491 manager_->NotifyAccessibilityEvent(ViewHostMsg_AccEvent::ALERT, this); |
2426 | 2492 |
2427 // Fire events if text has changed. | 2493 // Fire events if text has changed. |
2428 string16 text = TextForIAccessibleText(); | 2494 string16 text = TextForIAccessibleText(); |
2429 if (previous_text_ != text) { | 2495 if (previous_text_ != text) { |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2509 base::IntToString16(value)); | 2575 base::IntToString16(value)); |
2510 } | 2576 } |
2511 | 2577 |
2512 string16 BrowserAccessibilityWin::Escape(const string16& str) { | 2578 string16 BrowserAccessibilityWin::Escape(const string16& str) { |
2513 return net::EscapeQueryParamValueUTF8(str, false); | 2579 return net::EscapeQueryParamValueUTF8(str, false); |
2514 } | 2580 } |
2515 | 2581 |
2516 const string16& BrowserAccessibilityWin::TextForIAccessibleText() { | 2582 const string16& BrowserAccessibilityWin::TextForIAccessibleText() { |
2517 if (IsEditableText()) { | 2583 if (IsEditableText()) { |
2518 return value_; | 2584 return value_; |
| 2585 } else if (role_ == WebAccessibility::ROLE_STATIC_TEXT) { |
| 2586 return name_; |
2519 } else { | 2587 } else { |
2520 return name_; | 2588 return hypertext_; |
2521 } | 2589 } |
2522 } | 2590 } |
2523 | 2591 |
2524 void BrowserAccessibilityWin::HandleSpecialTextOffset( | 2592 void BrowserAccessibilityWin::HandleSpecialTextOffset( |
2525 const string16& text, LONG* offset) { | 2593 const string16& text, LONG* offset) { |
2526 if (*offset == IA2_TEXT_OFFSET_LENGTH) { | 2594 if (*offset == IA2_TEXT_OFFSET_LENGTH) { |
2527 *offset = static_cast<LONG>(text.size()); | 2595 *offset = static_cast<LONG>(text.size()); |
2528 } else if (*offset == IA2_TEXT_OFFSET_CARET) { | 2596 } else if (*offset == IA2_TEXT_OFFSET_CARET) { |
2529 get_caretOffset(offset); | 2597 get_caretOffset(offset); |
2530 } | 2598 } |
(...skipping 487 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3018 } | 3086 } |
3019 | 3087 |
3020 // The role should always be set. | 3088 // The role should always be set. |
3021 DCHECK(!role_name_.empty() || ia_role_); | 3089 DCHECK(!role_name_.empty() || ia_role_); |
3022 | 3090 |
3023 // If we didn't explicitly set the IAccessible2 role, make it the same | 3091 // If we didn't explicitly set the IAccessible2 role, make it the same |
3024 // as the MSAA role. | 3092 // as the MSAA role. |
3025 if (!ia2_role_) | 3093 if (!ia2_role_) |
3026 ia2_role_ = ia_role_; | 3094 ia2_role_ = ia_role_; |
3027 } | 3095 } |
OLD | NEW |