Index: content/browser/accessibility/browser_accessibility_win.cc |
=================================================================== |
--- content/browser/accessibility/browser_accessibility_win.cc (revision 110985) |
+++ content/browser/accessibility/browser_accessibility_win.cc (working copy) |
@@ -7,6 +7,7 @@ |
#include "base/string_number_conversions.h" |
#include "base/string_util.h" |
#include "base/utf_string_conversions.h" |
+#include "base/win/enum_variant.h" |
#include "base/win/scoped_comptr.h" |
#include "content/browser/accessibility/browser_accessibility_manager_win.h" |
#include "content/common/view_messages.h" |
@@ -168,7 +169,8 @@ |
ia_state_(0), |
ia2_role_(0), |
ia2_state_(0), |
- first_time_(true) { |
+ first_time_(true), |
+ old_ia_state_(0) { |
} |
BrowserAccessibilityWin::~BrowserAccessibilityWin() { |
@@ -529,6 +531,45 @@ |
if (!instance_active_) |
return E_FAIL; |
+ if (role_ == WebAccessibility::ROLE_LISTBOX && children_.size() > 0) { |
+ unsigned long selected_count = 0; |
+ for (size_t i = 0; i < children_.size(); i++) { |
+ if ((children_[i]->state() >> WebAccessibility::STATE_SELECTED) & 1) |
darin (slow to review)
2011/11/22 01:16:52
nit: A HasState method might be nice here.
if (
dmazzoni
2011/11/22 08:08:14
Good idea, done.
|
+ selected_count++; |
+ } |
+ |
+ if (selected_count == 0) { |
+ selected->vt = VT_EMPTY; |
+ return S_OK; |
+ } |
+ |
+ if (selected_count == 1) { |
+ for (size_t i = 0; i < children_.size(); i++) { |
+ if ((children_[i]->state() >> WebAccessibility::STATE_SELECTED) & 1) { |
+ selected->vt = VT_DISPATCH; |
+ selected->pdispVal = |
+ children_[i]->toBrowserAccessibilityWin()->NewReference(); |
+ return S_OK; |
+ } |
+ } |
+ } |
+ |
+ // Multiple items are selected. |
+ base::win::EnumVariant* enum_variant = |
+ new base::win::EnumVariant(selected_count); |
+ unsigned long index = 0; |
+ for (size_t i = 0; i < children_.size(); i++) { |
+ if ((children_[i]->state() >> WebAccessibility::STATE_SELECTED) & 1) { |
+ enum_variant->get(index)->vt = VT_DISPATCH; |
+ enum_variant->get(index)->pdispVal = |
+ children_[i]->toBrowserAccessibilityWin()->NewReference(); |
darin (slow to review)
2011/11/22 01:16:52
NewReference appears to take a reference count. I
dmazzoni
2011/11/22 08:08:14
It's the responsibility of the client who calls th
|
+ index++; |
+ } |
+ } |
+ selected->vt = VT_UNKNOWN; |
+ selected->punkVal = enum_variant; |
+ } |
+ |
return E_NOTIMPL; |
} |
@@ -683,6 +724,22 @@ |
return S_OK; |
} |
+STDMETHODIMP BrowserAccessibilityWin::get_groupPosition( |
+ LONG* group_level, |
+ LONG* similar_items_in_group, |
+ LONG* position_in_group) { |
+ if (role_ == WebAccessibility::ROLE_LISTBOX_OPTION && |
+ parent_ && |
+ parent_->role() == WebAccessibility::ROLE_LISTBOX) { |
+ *group_level = 0; |
+ *similar_items_in_group = parent_->child_count(); |
+ *position_in_group = index_in_parent_ + 1; |
+ return S_OK; |
+ } |
+ |
+ return E_NOTIMPL; |
+} |
+ |
// |
// IAccessibleImage methods. |
// |
@@ -2335,6 +2392,16 @@ |
// Expose "level" attribute for tree nodes. |
IntAttributeToIA2(WebAccessibility::ATTR_HIERARCHICAL_LEVEL, "level"); |
+ // Expose the set size and position in set for listbox options. |
+ if (role_ == WebAccessibility::ROLE_LISTBOX_OPTION && |
+ parent_ && |
+ parent_->role() == WebAccessibility::ROLE_LISTBOX) { |
+ ia2_attributes_.push_back( |
+ string16(L"setsize:") + base::IntToString16(parent_->child_count())); |
darin (slow to review)
2011/11/22 01:16:52
nit: is it necessary to wrap those constants with
dmazzoni
2011/11/22 08:08:14
You're right, thanks.
|
+ ia2_attributes_.push_back( |
+ string16(L"setsize:") + base::IntToString16(index_in_parent_ + 1)); |
+ } |
+ |
// Expose live region attributes. |
StringAttributeToIA2(WebAccessibility::ATTR_LIVE_STATUS, "live"); |
StringAttributeToIA2(WebAccessibility::ATTR_LIVE_RELEVANT, "relevant"); |
@@ -2387,9 +2454,11 @@ |
} |
} |
- // If this is static text, put the text in the name rather than the value. |
- if (role_ == WebAccessibility::ROLE_STATIC_TEXT && name_.empty()) |
+ if (name_.empty() && |
+ (role_ == WebAccessibility::ROLE_LISTBOX_OPTION || |
+ role_ == WebAccessibility::ROLE_STATIC_TEXT)) { |
name_.swap(value_); |
+ } |
// If this object doesn't have a name but it does have a description, |
// use the description as its name - because some screen readers only |
@@ -2443,6 +2512,40 @@ |
previous_text_ = text; |
} |
+ // Fire events if the state has changed. |
+ if (!first_time_ && ia_state_ != old_ia_state_) { |
+ // Normally focus events are handled elsewhere, however |
+ // focus for managed descendants is platform-specific. |
+ // Fire a focus event if the focused descendant in a multi-select |
+ // list box changes. |
+ if (role_ == WebAccessibility::ROLE_LISTBOX_OPTION && |
+ (ia_state_ & STATE_SYSTEM_FOCUSABLE) && |
+ (ia_state_ & STATE_SYSTEM_SELECTABLE) && |
+ (ia_state_ & STATE_SYSTEM_FOCUSED) && |
+ !(old_ia_state_ & STATE_SYSTEM_FOCUSED)) { |
+ ::NotifyWinEvent(EVENT_OBJECT_FOCUS, |
+ manager_->GetParentView(), |
+ OBJID_CLIENT, |
+ child_id()); |
+ } |
+ |
+ if ((ia_state_ & STATE_SYSTEM_SELECTED) && |
+ !(old_ia_state_ & STATE_SYSTEM_SELECTED)) { |
+ ::NotifyWinEvent(EVENT_OBJECT_SELECTIONADD, |
+ manager_->GetParentView(), |
+ OBJID_CLIENT, |
+ child_id()); |
+ } else if (!(ia_state_ & STATE_SYSTEM_SELECTED) && |
+ (old_ia_state_ & STATE_SYSTEM_SELECTED)) { |
+ ::NotifyWinEvent(EVENT_OBJECT_SELECTIONREMOVE, |
+ manager_->GetParentView(), |
+ OBJID_CLIENT, |
+ child_id()); |
+ } |
+ |
+ old_ia_state_ = ia_state_; |
darin (slow to review)
2011/11/22 01:16:52
do we have to worry about |this| being deleted upo
dmazzoni
2011/11/22 08:08:14
I don't think we have to worry about that. It'd do
|
+ } |
+ |
first_time_ = false; |
} |
@@ -2591,8 +2694,10 @@ |
ia_state_|= STATE_SYSTEM_INVISIBLE; |
if ((state_ >> WebAccessibility::STATE_LINKED) & 1) |
ia_state_|= STATE_SYSTEM_LINKED; |
- if ((state_ >> WebAccessibility::STATE_MULTISELECTABLE) & 1) |
+ if ((state_ >> WebAccessibility::STATE_MULTISELECTABLE) & 1) { |
+ ia_state_|= STATE_SYSTEM_EXTSELECTABLE; |
ia_state_|= STATE_SYSTEM_MULTISELECTABLE; |
+ } |
// TODO(ctguil): Support STATE_SYSTEM_EXTSELECTABLE/accSelect. |
if ((state_ >> WebAccessibility::STATE_OFFSCREEN) & 1) |
ia_state_|= STATE_SYSTEM_OFFSCREEN; |
@@ -2788,6 +2893,11 @@ |
break; |
case WebAccessibility::ROLE_LISTBOX_OPTION: |
ia_role_ = ROLE_SYSTEM_LISTITEM; |
+ if (ia_state_ & STATE_SYSTEM_SELECTABLE) { |
+ ia_state_ |= STATE_SYSTEM_FOCUSABLE; |
+ if ((state_ >> WebAccessibility::STATE_FOCUSED) & 1) |
darin (slow to review)
2011/11/22 01:16:52
again, it feels like a HasState type function migh
dmazzoni
2011/11/22 08:08:14
Done.
|
+ ia_state_|= STATE_SYSTEM_FOCUSED; |
+ } |
break; |
case WebAccessibility::ROLE_LIST_ITEM: |
ia_role_ = ROLE_SYSTEM_LISTITEM; |