Chromium Code Reviews| 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_win.h" | 5 #include "content/browser/accessibility/browser_accessibility_win.h" |
| 6 | 6 |
| 7 #include <UIAutomationClient.h> | 7 #include <UIAutomationClient.h> |
| 8 #include <UIAutomationCoreApi.h> | 8 #include <UIAutomationCoreApi.h> |
| 9 | 9 |
| 10 #include "base/strings/string_number_conversions.h" | 10 #include "base/strings/string_number_conversions.h" |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 28 // These nonstandard GUIDs are taken directly from the Mozilla sources | 28 // These nonstandard GUIDs are taken directly from the Mozilla sources |
| 29 // (accessible/src/msaa/nsAccessNodeWrap.cpp); some documentation is here: | 29 // (accessible/src/msaa/nsAccessNodeWrap.cpp); some documentation is here: |
| 30 // http://developer.mozilla.org/en/Accessibility/AT-APIs/ImplementationFeatures/ MSAA | 30 // http://developer.mozilla.org/en/Accessibility/AT-APIs/ImplementationFeatures/ MSAA |
| 31 const GUID GUID_ISimpleDOM = { | 31 const GUID GUID_ISimpleDOM = { |
| 32 0x0c539790, 0x12e4, 0x11cf, | 32 0x0c539790, 0x12e4, 0x11cf, |
| 33 0xb6, 0x61, 0x00, 0xaa, 0x00, 0x4c, 0xd6, 0xd8}; | 33 0xb6, 0x61, 0x00, 0xaa, 0x00, 0x4c, 0xd6, 0xd8}; |
| 34 const GUID GUID_IAccessibleContentDocument = { | 34 const GUID GUID_IAccessibleContentDocument = { |
| 35 0xa5d8e1f3, 0x3571, 0x4d8f, | 35 0xa5d8e1f3, 0x3571, 0x4d8f, |
| 36 0x95, 0x21, 0x07, 0xed, 0x28, 0xfb, 0x07, 0x2e}; | 36 0x95, 0x21, 0x07, 0xed, 0x28, 0xfb, 0x07, 0x2e}; |
| 37 | 37 |
| 38 const base::char16 BrowserAccessibilityWin::kEmbeddedCharacter[] = L"\xfffc"; | 38 const base::char16 BrowserAccessibilityWin::kEmbeddedCharacter = L'\xfffc'; |
| 39 | 39 |
| 40 // static | 40 // static |
| 41 LONG BrowserAccessibilityWin::next_unique_id_win_ = | 41 LONG BrowserAccessibilityWin::next_unique_id_win_ = |
| 42 base::win::kFirstBrowserAccessibilityManagerAccessibilityId; | 42 base::win::kFirstBrowserAccessibilityManagerAccessibilityId; |
| 43 | 43 |
| 44 // | 44 // |
| 45 // BrowserAccessibilityRelation | 45 // BrowserAccessibilityRelation |
| 46 // | 46 // |
| 47 // A simple implementation of IAccessibleRelation, used to represent | 47 // A simple implementation of IAccessibleRelation, used to represent |
| 48 // a relationship between two accessible nodes in the tree. | 48 // a relationship between two accessible nodes in the tree. |
| (...skipping 2118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2167 return get_text(*start_offset, *end_offset, text); | 2167 return get_text(*start_offset, *end_offset, text); |
| 2168 } | 2168 } |
| 2169 | 2169 |
| 2170 STDMETHODIMP BrowserAccessibilityWin::get_newText(IA2TextSegment* new_text) { | 2170 STDMETHODIMP BrowserAccessibilityWin::get_newText(IA2TextSegment* new_text) { |
| 2171 if (!instance_active()) | 2171 if (!instance_active()) |
| 2172 return E_FAIL; | 2172 return E_FAIL; |
| 2173 | 2173 |
| 2174 if (!new_text) | 2174 if (!new_text) |
| 2175 return E_INVALIDARG; | 2175 return E_INVALIDARG; |
| 2176 | 2176 |
| 2177 if (!old_win_attributes_) | |
| 2178 return E_FAIL; | |
| 2179 | |
| 2177 int start, old_len, new_len; | 2180 int start, old_len, new_len; |
| 2178 ComputeHypertextRemovedAndInserted(&start, &old_len, &new_len); | 2181 ComputeHypertextRemovedAndInserted(&start, &old_len, &new_len); |
| 2179 if (new_len == 0) | 2182 if (new_len == 0) |
| 2180 return E_FAIL; | 2183 return E_FAIL; |
| 2181 | 2184 |
| 2182 base::string16 substr = hypertext_.substr(start, new_len); | 2185 base::string16 substr = hypertext().substr(start, new_len); |
| 2183 new_text->text = SysAllocString(substr.c_str()); | 2186 new_text->text = SysAllocString(substr.c_str()); |
| 2184 new_text->start = static_cast<long>(start); | 2187 new_text->start = static_cast<long>(start); |
| 2185 new_text->end = static_cast<long>(start + new_len); | 2188 new_text->end = static_cast<long>(start + new_len); |
| 2186 return S_OK; | 2189 return S_OK; |
| 2187 } | 2190 } |
| 2188 | 2191 |
| 2189 STDMETHODIMP BrowserAccessibilityWin::get_oldText(IA2TextSegment* old_text) { | 2192 STDMETHODIMP BrowserAccessibilityWin::get_oldText(IA2TextSegment* old_text) { |
| 2190 if (!instance_active()) | 2193 if (!instance_active()) |
| 2191 return E_FAIL; | 2194 return E_FAIL; |
| 2192 | 2195 |
| 2193 if (!old_text) | 2196 if (!old_text) |
| 2194 return E_INVALIDARG; | 2197 return E_INVALIDARG; |
| 2195 | 2198 |
| 2199 if (!old_win_attributes_) | |
| 2200 return E_FAIL; | |
| 2201 | |
| 2196 int start, old_len, new_len; | 2202 int start, old_len, new_len; |
| 2197 ComputeHypertextRemovedAndInserted(&start, &old_len, &new_len); | 2203 ComputeHypertextRemovedAndInserted(&start, &old_len, &new_len); |
| 2198 if (old_len == 0) | 2204 if (old_len == 0) |
| 2199 return E_FAIL; | 2205 return E_FAIL; |
| 2200 | 2206 |
| 2201 base::string16 substr = old_hypertext_.substr(start, old_len); | 2207 base::string16 old_hypertext = old_win_attributes_->hypertext; |
| 2208 base::string16 substr = old_hypertext.substr(start, old_len); | |
| 2202 old_text->text = SysAllocString(substr.c_str()); | 2209 old_text->text = SysAllocString(substr.c_str()); |
| 2203 old_text->start = static_cast<long>(start); | 2210 old_text->start = static_cast<long>(start); |
| 2204 old_text->end = static_cast<long>(start + old_len); | 2211 old_text->end = static_cast<long>(start + old_len); |
| 2205 return S_OK; | 2212 return S_OK; |
| 2206 } | 2213 } |
| 2207 | 2214 |
| 2208 STDMETHODIMP BrowserAccessibilityWin::get_offsetAtPoint( | 2215 STDMETHODIMP BrowserAccessibilityWin::get_offsetAtPoint( |
| 2209 LONG x, | 2216 LONG x, |
| 2210 LONG y, | 2217 LONG y, |
| 2211 enum IA2CoordinateType coord_type, | 2218 enum IA2CoordinateType coord_type, |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2295 // IAccessibleHypertext methods. | 2302 // IAccessibleHypertext methods. |
| 2296 // | 2303 // |
| 2297 | 2304 |
| 2298 STDMETHODIMP BrowserAccessibilityWin::get_nHyperlinks(long* hyperlink_count) { | 2305 STDMETHODIMP BrowserAccessibilityWin::get_nHyperlinks(long* hyperlink_count) { |
| 2299 if (!instance_active()) | 2306 if (!instance_active()) |
| 2300 return E_FAIL; | 2307 return E_FAIL; |
| 2301 | 2308 |
| 2302 if (!hyperlink_count) | 2309 if (!hyperlink_count) |
| 2303 return E_INVALIDARG; | 2310 return E_INVALIDARG; |
| 2304 | 2311 |
| 2305 *hyperlink_count = hyperlink_offset_to_index_.size(); | 2312 *hyperlink_count = hyperlink_offset_to_index().size(); |
| 2306 return S_OK; | 2313 return S_OK; |
| 2307 } | 2314 } |
| 2308 | 2315 |
| 2309 STDMETHODIMP BrowserAccessibilityWin::get_hyperlink( | 2316 STDMETHODIMP BrowserAccessibilityWin::get_hyperlink( |
| 2310 long index, | 2317 long index, |
| 2311 IAccessibleHyperlink** hyperlink) { | 2318 IAccessibleHyperlink** hyperlink) { |
| 2312 if (!instance_active()) | 2319 if (!instance_active()) |
| 2313 return E_FAIL; | 2320 return E_FAIL; |
| 2314 | 2321 |
| 2315 if (!hyperlink || | 2322 if (!hyperlink || |
| 2316 index < 0 || | 2323 index < 0 || |
| 2317 index >= static_cast<long>(hyperlinks_.size())) { | 2324 index >= static_cast<long>(hyperlinks().size())) { |
| 2318 return E_INVALIDARG; | 2325 return E_INVALIDARG; |
| 2319 } | 2326 } |
| 2320 | 2327 |
| 2328 int32 id = hyperlinks()[index]; | |
| 2321 BrowserAccessibilityWin* child = | 2329 BrowserAccessibilityWin* child = |
| 2322 InternalGetChild(hyperlinks_[index])->ToBrowserAccessibilityWin(); | 2330 manager()->GetFromID(id)->ToBrowserAccessibilityWin(); |
| 2323 *hyperlink = static_cast<IAccessibleHyperlink*>(child->NewReference()); | 2331 if (child) { |
| 2324 return S_OK; | 2332 *hyperlink = static_cast<IAccessibleHyperlink*>(child->NewReference()); |
| 2333 return S_OK; | |
| 2334 } | |
| 2335 | |
| 2336 return E_FAIL; | |
| 2325 } | 2337 } |
| 2326 | 2338 |
| 2327 STDMETHODIMP BrowserAccessibilityWin::get_hyperlinkIndex( | 2339 STDMETHODIMP BrowserAccessibilityWin::get_hyperlinkIndex( |
| 2328 long char_index, | 2340 long char_index, |
| 2329 long* hyperlink_index) { | 2341 long* hyperlink_index) { |
| 2330 if (!instance_active()) | 2342 if (!instance_active()) |
| 2331 return E_FAIL; | 2343 return E_FAIL; |
| 2332 | 2344 |
| 2333 if (!hyperlink_index) | 2345 if (!hyperlink_index) |
| 2334 return E_INVALIDARG; | 2346 return E_INVALIDARG; |
| 2335 | 2347 |
| 2336 *hyperlink_index = -1; | 2348 *hyperlink_index = -1; |
| 2337 | 2349 |
| 2338 if (char_index < 0 || | 2350 if (char_index < 0 || |
| 2339 char_index >= static_cast<long>(hypertext_.size())) { | 2351 char_index >= static_cast<long>(hypertext().size())) { |
| 2340 return E_INVALIDARG; | 2352 return E_INVALIDARG; |
| 2341 } | 2353 } |
| 2342 | 2354 |
| 2343 std::map<int32, int32>::iterator it = | 2355 std::map<int32, int32>::iterator it = |
| 2344 hyperlink_offset_to_index_.find(char_index); | 2356 hyperlink_offset_to_index().find(char_index); |
| 2345 if (it == hyperlink_offset_to_index_.end()) | 2357 if (it == hyperlink_offset_to_index().end()) |
| 2346 return E_FAIL; | 2358 return E_FAIL; |
| 2347 | 2359 |
| 2348 *hyperlink_index = it->second; | 2360 *hyperlink_index = it->second; |
| 2349 return S_OK; | 2361 return S_OK; |
| 2350 } | 2362 } |
| 2351 | 2363 |
| 2352 // | 2364 // |
| 2353 // IAccessibleValue methods. | 2365 // IAccessibleValue methods. |
| 2354 // | 2366 // |
| 2355 | 2367 |
| (...skipping 580 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2936 } | 2948 } |
| 2937 | 2949 |
| 2938 return CComObjectRootBase::InternalQueryInterface( | 2950 return CComObjectRootBase::InternalQueryInterface( |
| 2939 this_ptr, entries, iid, object); | 2951 this_ptr, entries, iid, object); |
| 2940 } | 2952 } |
| 2941 | 2953 |
| 2942 // | 2954 // |
| 2943 // Private methods. | 2955 // Private methods. |
| 2944 // | 2956 // |
| 2945 | 2957 |
| 2946 // Called every time this node's data changes, while the tree update is | 2958 void BrowserAccessibilityWin::UpdateStep1ComputeWinAttributes() { |
| 2947 // still in progress. | 2959 // Swap win_attributes_ to old_win_attributes_, allowing us to see |
| 2948 void BrowserAccessibilityWin::OnDataChanged() { | 2960 // exactly what changed and fire appropriate events. Note that |
| 2949 BrowserAccessibility::OnDataChanged(); | 2961 // old_win_attributes_ is cleared at the end of FireIAccessibleTextEvents. |
| 2950 } | |
| 2951 | |
| 2952 // Called every time this node's data changes, after an atomic tree update. | |
| 2953 void BrowserAccessibilityWin::OnUpdateFinished() { | |
| 2954 BrowserAccessibility::OnUpdateFinished(); | |
| 2955 | |
| 2956 if (PlatformIsChildOfLeaf()) | |
| 2957 return; | |
| 2958 | |
| 2959 bool is_new_object = ia_role() == 0 && role_name().empty(); | |
| 2960 | |
| 2961 old_win_attributes_.swap(win_attributes_); | 2962 old_win_attributes_.swap(win_attributes_); |
| 2962 win_attributes_.reset(new WinAttributes()); | 2963 win_attributes_.reset(new WinAttributes()); |
| 2963 | 2964 |
| 2964 InitRoleAndState(); | 2965 InitRoleAndState(); |
| 2965 | 2966 |
| 2966 win_attributes_->ia2_attributes.clear(); | 2967 win_attributes_->ia2_attributes.clear(); |
| 2967 | 2968 |
| 2968 // Expose autocomplete attribute for combobox and textbox. | 2969 // Expose autocomplete attribute for combobox and textbox. |
| 2969 StringAttributeToIA2(ui::AX_ATTR_AUTO_COMPLETE, "autocomplete"); | 2970 StringAttributeToIA2(ui::AX_ATTR_AUTO_COMPLETE, "autocomplete"); |
| 2970 | 2971 |
| (...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3188 win_attributes_->ia2_attributes.push_back(L"valuetext:" + GetValueText()); | 3189 win_attributes_->ia2_attributes.push_back(L"valuetext:" + GetValueText()); |
| 3189 } | 3190 } |
| 3190 | 3191 |
| 3191 // If this is a web area for a presentational iframe, give it a role of | 3192 // If this is a web area for a presentational iframe, give it a role of |
| 3192 // something other than DOCUMENT so that the fact that it's a separate doc | 3193 // something other than DOCUMENT so that the fact that it's a separate doc |
| 3193 // is not exposed to AT. | 3194 // is not exposed to AT. |
| 3194 if (IsWebAreaForPresentationalIframe()) { | 3195 if (IsWebAreaForPresentationalIframe()) { |
| 3195 win_attributes_->ia_role = ROLE_SYSTEM_GROUPING; | 3196 win_attributes_->ia_role = ROLE_SYSTEM_GROUPING; |
| 3196 win_attributes_->ia2_role = ROLE_SYSTEM_GROUPING; | 3197 win_attributes_->ia2_role = ROLE_SYSTEM_GROUPING; |
| 3197 } | 3198 } |
| 3199 } | |
| 3198 | 3200 |
| 3201 void BrowserAccessibilityWin::UpdateStep2ComputeHypertext() { | |
| 3202 // Construct the hypertext for this node, which contains the concatenation | |
| 3203 // of all of the static text of this node's children and an embedded object | |
| 3204 // character for all non-static-text children. Build up a map from the | |
| 3205 // character index of each embedded object character to the id of the | |
| 3206 // child object it points to. | |
| 3207 for (unsigned int i = 0; i < PlatformChildCount(); ++i) { | |
| 3208 BrowserAccessibilityWin* child = | |
| 3209 PlatformGetChild(i)->ToBrowserAccessibilityWin(); | |
| 3210 if (child->GetRole() == ui::AX_ROLE_STATIC_TEXT) { | |
| 3211 win_attributes_->hypertext += child->name(); | |
| 3212 } else { | |
| 3213 int32 char_offset = hypertext().size(); | |
| 3214 int32 child_id = child->GetId(); | |
| 3215 int32 index = hyperlinks().size(); | |
| 3216 win_attributes_->hyperlink_offset_to_index[char_offset] = index; | |
| 3217 win_attributes_->hyperlinks.push_back(child_id); | |
| 3218 win_attributes_->hypertext += kEmbeddedCharacter; | |
| 3219 } | |
| 3220 } | |
| 3221 } | |
| 3222 | |
| 3223 void BrowserAccessibilityWin::UpdateStep3FireEvents(bool is_subtree_creation) { | |
| 3199 BrowserAccessibilityManagerWin* manager = | 3224 BrowserAccessibilityManagerWin* manager = |
| 3200 this->manager()->ToBrowserAccessibilityManagerWin(); | 3225 this->manager()->ToBrowserAccessibilityManagerWin(); |
| 3201 | 3226 |
| 3202 // Fire an event when an alert first appears. | 3227 // Fire an event when an alert first appears. |
| 3203 if (ia_role() == ROLE_SYSTEM_ALERT && | 3228 if (ia_role() == ROLE_SYSTEM_ALERT && |
| 3204 old_win_attributes_->ia_role != ROLE_SYSTEM_ALERT) { | 3229 old_win_attributes_->ia_role != ROLE_SYSTEM_ALERT) { |
| 3205 manager->NotifyAccessibilityEvent(ui::AX_EVENT_ALERT, this); | 3230 manager->NotifyAccessibilityEvent(ui::AX_EVENT_ALERT, this); |
| 3206 } | 3231 } |
| 3207 | 3232 |
| 3233 // Fire an event when a new subtree is created. | |
| 3234 if (is_subtree_creation) | |
| 3235 manager->MaybeCallNotifyWinEvent(EVENT_OBJECT_SHOW, this); | |
| 3236 | |
| 3237 // No other events fire on new objects, only on objects that changed, | |
| 3238 // so exit now if this is a new object. | |
| 3239 bool is_new_object = old_win_attributes_->ia_role == 0 && | |
| 3240 old_win_attributes_->role_name.empty(); | |
| 3241 if (is_new_object) | |
|
David Tseng
2015/01/30 23:57:25
nit: no need for this local var.
dmazzoni
2015/01/31 07:45:21
Done.
| |
| 3242 return; | |
| 3243 | |
| 3208 // Fire an event if the name, description, help, or value changes. | 3244 // Fire an event if the name, description, help, or value changes. |
| 3209 if (!is_new_object) { | 3245 if (name() != old_win_attributes_->name) |
| 3210 if (name != old_win_attributes_->name) | 3246 manager->MaybeCallNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, this); |
| 3211 manager->MaybeCallNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, this); | 3247 if (description() != old_win_attributes_->description) |
| 3212 if (description != old_win_attributes_->description) | 3248 manager->MaybeCallNotifyWinEvent(EVENT_OBJECT_DESCRIPTIONCHANGE, this); |
| 3213 manager->MaybeCallNotifyWinEvent(EVENT_OBJECT_DESCRIPTIONCHANGE, this); | 3249 if (help() != old_win_attributes_->help) |
| 3214 if (help != old_win_attributes_->help) | 3250 manager->MaybeCallNotifyWinEvent(EVENT_OBJECT_HELPCHANGE, this); |
| 3215 manager->MaybeCallNotifyWinEvent(EVENT_OBJECT_HELPCHANGE, this); | 3251 if (value() != old_win_attributes_->value) |
| 3216 if (value != old_win_attributes_->value) | 3252 manager->MaybeCallNotifyWinEvent(EVENT_OBJECT_VALUECHANGE, this); |
| 3217 manager->MaybeCallNotifyWinEvent(EVENT_OBJECT_VALUECHANGE, this); | 3253 if (ia_state() != old_win_attributes_->ia_state) |
| 3218 if (ia_state() != old_win_attributes_->ia_state) | 3254 manager->MaybeCallNotifyWinEvent(EVENT_OBJECT_STATECHANGE, this); |
| 3219 manager->MaybeCallNotifyWinEvent(EVENT_OBJECT_STATECHANGE, this); | |
| 3220 | 3255 |
| 3221 // Normally focus events are handled elsewhere, however | 3256 // Normally focus events are handled elsewhere, however |
| 3222 // focus for managed descendants is platform-specific. | 3257 // focus for managed descendants is platform-specific. |
| 3223 // Fire a focus event if the focused descendant in a multi-select | 3258 // Fire a focus event if the focused descendant in a multi-select |
| 3224 // list box changes. | 3259 // list box changes. |
| 3225 if (GetRole() == ui::AX_ROLE_LIST_BOX_OPTION && | 3260 if (GetRole() == ui::AX_ROLE_LIST_BOX_OPTION && |
| 3226 (ia_state() & STATE_SYSTEM_FOCUSABLE) && | 3261 (ia_state() & STATE_SYSTEM_FOCUSABLE) && |
| 3227 (ia_state() & STATE_SYSTEM_SELECTABLE) && | 3262 (ia_state() & STATE_SYSTEM_SELECTABLE) && |
| 3228 (ia_state() & STATE_SYSTEM_FOCUSED) && | 3263 (ia_state() & STATE_SYSTEM_FOCUSED) && |
| 3229 !(old_win_attributes_->ia_state & STATE_SYSTEM_FOCUSED)) { | 3264 !(old_win_attributes_->ia_state & STATE_SYSTEM_FOCUSED)) { |
| 3230 manager->MaybeCallNotifyWinEvent(EVENT_OBJECT_FOCUS, this); | 3265 manager->MaybeCallNotifyWinEvent(EVENT_OBJECT_FOCUS, this); |
| 3231 } | |
| 3232 | |
| 3233 // Handle selection being added or removed. | |
| 3234 bool is_selected_now = (ia_state() & STATE_SYSTEM_SELECTED) != 0; | |
| 3235 bool was_selected_before = | |
| 3236 (old_win_attributes_->ia_state & STATE_SYSTEM_SELECTED) != 0; | |
| 3237 if (is_selected_now && !was_selected_before) { | |
| 3238 manager->MaybeCallNotifyWinEvent(EVENT_OBJECT_SELECTIONADD, this); | |
| 3239 } else if (!is_selected_now && was_selected_before) { | |
| 3240 manager->MaybeCallNotifyWinEvent(EVENT_OBJECT_SELECTIONREMOVE, this); | |
| 3241 } | |
| 3242 | |
| 3243 // Fire an event if this container object has scrolled. | |
| 3244 int sx = 0; | |
| 3245 int sy = 0; | |
| 3246 if (GetIntAttribute(ui::AX_ATTR_SCROLL_X, &sx) && | |
| 3247 GetIntAttribute(ui::AX_ATTR_SCROLL_Y, &sy)) { | |
| 3248 if (sx != previous_scroll_x_ || sy != previous_scroll_y_) | |
| 3249 manager->MaybeCallNotifyWinEvent(EVENT_SYSTEM_SCROLLINGEND, this); | |
| 3250 previous_scroll_x_ = sx; | |
| 3251 previous_scroll_y_ = sy; | |
| 3252 } | |
| 3253 | |
| 3254 // Changing a static text node can affect the IAccessibleText hypertext | |
| 3255 // of the parent node, so force it to be recomputed here. | |
| 3256 if (GetParent() && | |
| 3257 GetRole() == ui::AX_ROLE_STATIC_TEXT && | |
| 3258 name != old_win_attributes_->name) { | |
| 3259 GetParent()->ToBrowserAccessibilityWin()->UpdateIAccessibleText(); | |
| 3260 } | |
| 3261 } | 3266 } |
| 3262 | 3267 |
| 3268 // Handle selection being added or removed. | |
| 3269 bool is_selected_now = (ia_state() & STATE_SYSTEM_SELECTED) != 0; | |
| 3270 bool was_selected_before = | |
| 3271 (old_win_attributes_->ia_state & STATE_SYSTEM_SELECTED) != 0; | |
| 3272 if (is_selected_now && !was_selected_before) { | |
| 3273 manager->MaybeCallNotifyWinEvent(EVENT_OBJECT_SELECTIONADD, this); | |
| 3274 } else if (!is_selected_now && was_selected_before) { | |
| 3275 manager->MaybeCallNotifyWinEvent(EVENT_OBJECT_SELECTIONREMOVE, this); | |
| 3276 } | |
| 3277 | |
| 3278 // Fire an event if this container object has scrolled. | |
| 3279 int sx = 0; | |
| 3280 int sy = 0; | |
| 3281 if (GetIntAttribute(ui::AX_ATTR_SCROLL_X, &sx) && | |
| 3282 GetIntAttribute(ui::AX_ATTR_SCROLL_Y, &sy)) { | |
| 3283 if (sx != previous_scroll_x_ || sy != previous_scroll_y_) | |
| 3284 manager->MaybeCallNotifyWinEvent(EVENT_SYSTEM_SCROLLINGEND, this); | |
| 3285 previous_scroll_x_ = sx; | |
| 3286 previous_scroll_y_ = sy; | |
| 3287 } | |
| 3288 | |
| 3289 // Changing a static text node can affect the IAccessibleText hypertext | |
| 3290 // of the parent node, so force an update on the parent. | |
| 3291 if (GetParent() && | |
|
David Tseng
2015/01/30 23:57:25
nit: store parent in a local variable.
dmazzoni
2015/01/31 07:45:21
Done.
| |
| 3292 GetRole() == ui::AX_ROLE_STATIC_TEXT && | |
| 3293 name() != old_win_attributes_->name) { | |
| 3294 GetParent()->ToBrowserAccessibilityWin()->UpdateStep1ComputeWinAttributes(); | |
| 3295 GetParent()->ToBrowserAccessibilityWin()->UpdateStep2ComputeHypertext(); | |
| 3296 GetParent()->ToBrowserAccessibilityWin()->UpdateStep3FireEvents(false); | |
| 3297 GetParent()->ToBrowserAccessibilityWin()-> | |
| 3298 UpdateStep4DeleteOldWinAttributes(); | |
| 3299 } | |
| 3300 | |
| 3301 // Fire hypertext-related events. | |
|
David Tseng
2015/01/30 23:57:25
This would mean this object's parent fires hyperte
dmazzoni
2015/01/31 07:45:21
No, I checked with NV Access. The order in which w
| |
| 3302 int start, old_len, new_len; | |
| 3303 ComputeHypertextRemovedAndInserted(&start, &old_len, &new_len); | |
| 3304 if (old_len) { | |
|
David Tseng
2015/01/30 23:57:25
nit: old_len > 0?
dmazzoni
2015/01/31 07:45:21
Done.
| |
| 3305 // In-process screen readers may call IAccessibleText::get_oldText | |
| 3306 // to retrieve the text that was removed. | |
| 3307 manager->MaybeCallNotifyWinEvent(IA2_EVENT_TEXT_REMOVED, this); | |
| 3308 } | |
| 3309 if (new_len) { | |
|
David Tseng
2015/01/30 23:57:25
ditto
dmazzoni
2015/01/31 07:45:21
Done.
| |
| 3310 // In-process screen readers may call IAccessibleText::get_newText | |
|
David Tseng
2015/01/30 23:57:25
in reaction to this event?
dmazzoni
2015/01/31 07:45:21
Done.
| |
| 3311 // to retrieve the text that was inserted. | |
| 3312 manager->MaybeCallNotifyWinEvent(IA2_EVENT_TEXT_INSERTED, this); | |
| 3313 } | |
| 3314 } | |
| 3315 | |
| 3316 void BrowserAccessibilityWin::UpdateStep4DeleteOldWinAttributes() { | |
| 3263 old_win_attributes_.reset(nullptr); | 3317 old_win_attributes_.reset(nullptr); |
| 3264 } | 3318 } |
| 3265 | 3319 |
| 3266 void BrowserAccessibilityWin::UpdateIAccessibleText() { | |
| 3267 old_hypertext_ = hypertext_; | |
| 3268 hypertext_.clear(); | |
| 3269 | |
| 3270 // Construct the hypertext for this node. | |
| 3271 hyperlink_offset_to_index_.clear(); | |
| 3272 hyperlinks_.clear(); | |
| 3273 for (unsigned int i = 0; i < PlatformChildCount(); ++i) { | |
| 3274 BrowserAccessibilityWin* child = | |
| 3275 PlatformGetChild(i)->ToBrowserAccessibilityWin(); | |
| 3276 if (child->GetRole() == ui::AX_ROLE_STATIC_TEXT) { | |
| 3277 hypertext_ += child->name(); | |
| 3278 } else { | |
| 3279 hyperlink_offset_to_index_[hypertext_.size()] = | |
| 3280 hyperlinks_.size(); | |
| 3281 hypertext_ += kEmbeddedCharacter; | |
| 3282 hyperlinks_.push_back(i); | |
| 3283 } | |
| 3284 } | |
| 3285 DCHECK_EQ(hyperlink_offset_to_index_.size(), hyperlinks_.size()); | |
| 3286 | |
| 3287 if (hypertext_ != old_hypertext_) { | |
| 3288 BrowserAccessibilityManagerWin* manager = | |
| 3289 this->manager()->ToBrowserAccessibilityManagerWin(); | |
| 3290 | |
| 3291 int start, old_len, new_len; | |
| 3292 ComputeHypertextRemovedAndInserted(&start, &old_len, &new_len); | |
| 3293 if (old_len) { | |
| 3294 // In-process screen readers may call IAccessibleText::get_oldText | |
| 3295 // to retrieve the text that was removed. | |
| 3296 manager->MaybeCallNotifyWinEvent(IA2_EVENT_TEXT_REMOVED, this); | |
| 3297 } | |
| 3298 if (new_len) { | |
| 3299 // In-process screen readers may call IAccessibleText::get_newText | |
| 3300 // to retrieve the text that was inserted. | |
| 3301 manager->MaybeCallNotifyWinEvent(IA2_EVENT_TEXT_INSERTED, this); | |
| 3302 } | |
| 3303 } | |
| 3304 | |
| 3305 old_hypertext_.clear(); | |
| 3306 } | |
| 3307 | |
| 3308 void BrowserAccessibilityWin::OnSubtreeWillBeDeleted() { | 3320 void BrowserAccessibilityWin::OnSubtreeWillBeDeleted() { |
| 3309 manager()->ToBrowserAccessibilityManagerWin()->MaybeCallNotifyWinEvent( | 3321 manager()->ToBrowserAccessibilityManagerWin()->MaybeCallNotifyWinEvent( |
| 3310 EVENT_OBJECT_HIDE, this); | 3322 EVENT_OBJECT_HIDE, this); |
| 3311 } | 3323 } |
| 3312 | 3324 |
| 3313 void BrowserAccessibilityWin::OnSubtreeCreationFinished() { | |
| 3314 manager()->ToBrowserAccessibilityManagerWin()->MaybeCallNotifyWinEvent( | |
| 3315 EVENT_OBJECT_SHOW, this); | |
| 3316 } | |
| 3317 | |
| 3318 void BrowserAccessibilityWin::NativeAddReference() { | 3325 void BrowserAccessibilityWin::NativeAddReference() { |
| 3319 AddRef(); | 3326 AddRef(); |
| 3320 } | 3327 } |
| 3321 | 3328 |
| 3322 void BrowserAccessibilityWin::NativeReleaseReference() { | 3329 void BrowserAccessibilityWin::NativeReleaseReference() { |
| 3323 Release(); | 3330 Release(); |
| 3324 } | 3331 } |
| 3325 | 3332 |
| 3326 bool BrowserAccessibilityWin::IsNative() const { | 3333 bool BrowserAccessibilityWin::IsNative() const { |
| 3327 return true; | 3334 return true; |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3422 if (value.empty() && | 3429 if (value.empty() && |
| 3423 GetFloatAttribute(ui::AX_ATTR_VALUE_FOR_RANGE, &fval)) { | 3430 GetFloatAttribute(ui::AX_ATTR_VALUE_FOR_RANGE, &fval)) { |
| 3424 value = base::UTF8ToUTF16(base::DoubleToString(fval)); | 3431 value = base::UTF8ToUTF16(base::DoubleToString(fval)); |
| 3425 } | 3432 } |
| 3426 return value; | 3433 return value; |
| 3427 } | 3434 } |
| 3428 | 3435 |
| 3429 base::string16 BrowserAccessibilityWin::TextForIAccessibleText() { | 3436 base::string16 BrowserAccessibilityWin::TextForIAccessibleText() { |
| 3430 if (IsEditableText()) | 3437 if (IsEditableText()) |
| 3431 return value(); | 3438 return value(); |
| 3432 return (GetRole() == ui::AX_ROLE_STATIC_TEXT) ? name() : hypertext_; | 3439 return (GetRole() == ui::AX_ROLE_STATIC_TEXT) ? name() : hypertext(); |
| 3440 } | |
| 3441 | |
| 3442 bool BrowserAccessibilityWin::IsSameHypertextCharacter(size_t old_char_index, | |
| 3443 size_t new_char_index) { | |
| 3444 CHECK(old_win_attributes_); | |
| 3445 | |
| 3446 // For anything other than the "embedded character", we just compare the | |
| 3447 // characters directly. | |
| 3448 base::char16 old_ch = old_win_attributes_->hypertext[old_char_index]; | |
| 3449 base::char16 new_ch = win_attributes_->hypertext[new_char_index]; | |
| 3450 if (old_ch != new_ch) | |
| 3451 return false; | |
| 3452 if (old_ch == new_ch && new_ch != kEmbeddedCharacter) | |
| 3453 return true; | |
| 3454 | |
| 3455 // If it's an embedded character, they're only identical if the child id | |
| 3456 // the hyperlink points to is the same. | |
| 3457 std::map<int32, int32>& old_offset_to_index = | |
| 3458 old_win_attributes_->hyperlink_offset_to_index; | |
| 3459 std::vector<int32>& old_hyperlinks = old_win_attributes_->hyperlinks; | |
| 3460 int32 old_hyperlinks_count = static_cast<int32>(old_hyperlinks.size()); | |
| 3461 std::map<int32, int32>::iterator iter; | |
| 3462 iter = old_offset_to_index.find(old_char_index); | |
| 3463 int old_index = (iter != old_offset_to_index.end()) ? iter->second : -1; | |
| 3464 int old_child_id = (old_index >= 0 && old_index < old_hyperlinks_count) ? | |
| 3465 old_hyperlinks[old_index] : -1; | |
| 3466 | |
| 3467 std::map<int32, int32>& new_offset_to_index = | |
| 3468 win_attributes_->hyperlink_offset_to_index; | |
| 3469 std::vector<int32>& new_hyperlinks = win_attributes_->hyperlinks; | |
| 3470 int32 new_hyperlinks_count = static_cast<int32>(new_hyperlinks.size()); | |
| 3471 iter = new_offset_to_index.find(new_char_index); | |
| 3472 int new_index = (iter != new_offset_to_index.end()) ? iter->second : -1; | |
| 3473 int new_child_id = (new_index >= 0 && new_index < new_hyperlinks_count) ? | |
| 3474 new_hyperlinks[new_index] : -1; | |
| 3475 | |
| 3476 return old_child_id == new_child_id; | |
| 3433 } | 3477 } |
| 3434 | 3478 |
| 3435 void BrowserAccessibilityWin::ComputeHypertextRemovedAndInserted( | 3479 void BrowserAccessibilityWin::ComputeHypertextRemovedAndInserted( |
| 3436 int* start, int* old_len, int* new_len) { | 3480 int* start, int* old_len, int* new_len) { |
| 3481 CHECK(old_win_attributes_); | |
| 3482 | |
| 3437 *start = 0; | 3483 *start = 0; |
| 3438 *old_len = 0; | 3484 *old_len = 0; |
| 3439 *new_len = 0; | 3485 *new_len = 0; |
| 3440 | 3486 |
| 3441 const base::string16& old_text = old_hypertext_; | 3487 const base::string16& old_text = old_win_attributes_->hypertext; |
| 3442 const base::string16& new_text = hypertext_; | 3488 const base::string16& new_text = hypertext(); |
| 3443 | 3489 |
| 3444 size_t common_prefix = 0; | 3490 size_t common_prefix = 0; |
| 3445 while (common_prefix < old_text.size() && | 3491 while (common_prefix < old_text.size() && |
| 3446 common_prefix < new_text.size() && | 3492 common_prefix < new_text.size() && |
| 3447 old_text[common_prefix] == new_text[common_prefix]) { | 3493 IsSameHypertextCharacter(common_prefix, common_prefix)) { |
| 3448 ++common_prefix; | 3494 ++common_prefix; |
| 3449 } | 3495 } |
| 3450 | 3496 |
| 3451 size_t common_suffix = 0; | 3497 size_t common_suffix = 0; |
| 3452 while (common_prefix + common_suffix < old_text.size() && | 3498 while (common_prefix + common_suffix < old_text.size() && |
| 3453 common_prefix + common_suffix < new_text.size() && | 3499 common_prefix + common_suffix < new_text.size() && |
| 3454 old_text[old_text.size() - common_suffix - 1] == | 3500 IsSameHypertextCharacter( |
| 3455 new_text[new_text.size() - common_suffix - 1]) { | 3501 old_text.size() - common_suffix - 1, |
| 3502 new_text.size() - common_suffix - 1)) { | |
| 3456 ++common_suffix; | 3503 ++common_suffix; |
| 3457 } | 3504 } |
| 3458 | 3505 |
| 3459 *start = common_prefix; | 3506 *start = common_prefix; |
| 3460 *old_len = old_text.size() - common_prefix - common_suffix; | 3507 *old_len = old_text.size() - common_prefix - common_suffix; |
| 3461 *new_len = new_text.size() - common_prefix - common_suffix; | 3508 *new_len = new_text.size() - common_prefix - common_suffix; |
| 3462 } | 3509 } |
| 3463 | 3510 |
| 3464 void BrowserAccessibilityWin::HandleSpecialTextOffset( | 3511 void BrowserAccessibilityWin::HandleSpecialTextOffset( |
| 3465 const base::string16& text, | 3512 const base::string16& text, |
| (...skipping 574 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4040 ia2_role = ia_role; | 4087 ia2_role = ia_role; |
| 4041 | 4088 |
| 4042 win_attributes_->ia_role = ia_role; | 4089 win_attributes_->ia_role = ia_role; |
| 4043 win_attributes_->ia_state = ia_state; | 4090 win_attributes_->ia_state = ia_state; |
| 4044 win_attributes_->role_name = role_name; | 4091 win_attributes_->role_name = role_name; |
| 4045 win_attributes_->ia2_role = ia2_role; | 4092 win_attributes_->ia2_role = ia2_role; |
| 4046 win_attributes_->ia2_state = ia2_state; | 4093 win_attributes_->ia2_state = ia2_state; |
| 4047 } | 4094 } |
| 4048 | 4095 |
| 4049 } // namespace content | 4096 } // namespace content |
| OLD | NEW |