Chromium Code Reviews| Index: content/browser/accessibility/browser_accessibility_win.cc |
| =================================================================== |
| --- content/browser/accessibility/browser_accessibility_win.cc (revision 98804) |
| +++ content/browser/accessibility/browser_accessibility_win.cc (working copy) |
| @@ -8,6 +8,7 @@ |
| #include "base/string_util.h" |
| #include "base/utf_string_conversions.h" |
| #include "content/browser/accessibility/browser_accessibility_manager_win.h" |
| +#include "content/common/view_messages.h" |
| #include "net/base/escape.h" |
| using webkit_glue::WebAccessibility; |
| @@ -37,7 +38,8 @@ |
| : ia_role_(0), |
| ia_state_(0), |
| ia2_role_(0), |
| - ia2_state_(0) { |
| + ia2_state_(0), |
| + first_time_(true) { |
| } |
| BrowserAccessibilityWin::~BrowserAccessibilityWin() { |
| @@ -421,15 +423,13 @@ |
| if (!attributes) |
| return E_INVALIDARG; |
| - // Follow Firefox's convention, which is to return a set of key-value pairs |
| + // The iaccessible2 attributes are a set of key-value pairs |
| // separated by semicolons, with a colon between the key and the value. |
| string16 str; |
| - for (unsigned int i = 0; i < html_attributes_.size(); i++) { |
| + for (unsigned int i = 0; i < ia2_attributes_.size(); ++i) { |
| if (i != 0) |
| str += L';'; |
| - str += Escape(html_attributes_[i].first); |
| - str += L':'; |
| - str += Escape(html_attributes_[i].second); |
| + str += ia2_attributes_[i]; |
| } |
| if (str.empty()) |
| @@ -574,7 +574,8 @@ |
| return S_OK; |
| } |
| - return S_FALSE; |
| + *accessible = NULL; |
| + return E_INVALIDARG; |
| } |
| STDMETHODIMP BrowserAccessibilityWin::get_caption(IUnknown** accessible) { |
| @@ -610,9 +611,16 @@ |
| if (row < 0 || row >= rows || column < 0 || column >= columns) |
| return E_INVALIDARG; |
| - *cell_index = row * columns + column; |
| + DCHECK_EQ(columns * rows, static_cast<int>(cell_ids_.size())); |
| + int cell_id = cell_ids_[row * columns + column]; |
| + for (size_t i = 0; i < unique_cell_ids_.size(); ++i) { |
| + if (unique_cell_ids_[i] == cell_id) { |
| + *cell_index = (long)i; |
| + return S_OK; |
| + } |
| + } |
| - return S_OK; |
| + return S_FALSE; |
| } |
| STDMETHODIMP BrowserAccessibilityWin::get_columnDescription( |
| @@ -636,7 +644,7 @@ |
| if (column < 0 || column >= columns) |
| return E_INVALIDARG; |
| - for (int i = 0; i < rows; i++) { |
| + for (int i = 0; i < rows; ++i) { |
| int cell_id = cell_ids_[i * columns + column]; |
| BrowserAccessibilityWin* cell = static_cast<BrowserAccessibilityWin*>( |
| manager_->GetFromRendererID(cell_id)); |
| @@ -707,21 +715,24 @@ |
| if (!column_index) |
| return E_INVALIDARG; |
| - int columns; |
| - int rows; |
| - if (!GetIntAttribute(WebAccessibility::ATTR_TABLE_COLUMN_COUNT, &columns) || |
| - !GetIntAttribute(WebAccessibility::ATTR_TABLE_ROW_COUNT, &rows) || |
| - columns <= 0 || |
| - rows <= 0) { |
| + int cell_id_count = static_cast<int>(unique_cell_ids_.size()); |
| + if (cell_index < 0) |
| + return E_INVALIDARG; |
| + if (cell_index >= cell_id_count) |
| return S_FALSE; |
| + |
| + int cell_id = unique_cell_ids_[cell_index]; |
| + BrowserAccessibilityWin* cell = static_cast<BrowserAccessibilityWin*>( |
| + manager_->GetFromRendererID(cell_id)); |
|
Chris Guillory
2011/08/31 02:14:53
toBrowserAccessibilityWin()
dmazzoni
2011/08/31 22:02:54
Done.
|
| + int col_index; |
| + if (cell && |
| + cell->GetIntAttribute( |
| + WebAccessibility::ATTR_TABLE_CELL_COLUMN_INDEX, &col_index)) { |
| + *column_index = col_index; |
| + return S_OK; |
| } |
| - if (cell_index < 0 || cell_index >= columns * rows) |
| - return E_INVALIDARG; |
| - |
| - *column_index = cell_index % columns; |
| - |
| - return S_OK; |
| + return S_FALSE; |
| } |
| STDMETHODIMP BrowserAccessibilityWin::get_nColumns( |
| @@ -816,7 +827,7 @@ |
| if (row < 0 || row >= rows) |
| return E_INVALIDARG; |
| - for (int i = 0; i < columns; i++) { |
| + for (int i = 0; i < columns; ++i) { |
| int cell_id = cell_ids_[row * columns + i]; |
| BrowserAccessibilityWin* cell = static_cast<BrowserAccessibilityWin*>( |
| manager_->GetFromRendererID(cell_id)); |
| @@ -887,21 +898,24 @@ |
| if (!row_index) |
| return E_INVALIDARG; |
| - int columns; |
| - int rows; |
| - if (!GetIntAttribute(WebAccessibility::ATTR_TABLE_COLUMN_COUNT, &columns) || |
| - !GetIntAttribute(WebAccessibility::ATTR_TABLE_ROW_COUNT, &rows) || |
| - columns <= 0 || |
| - rows <= 0) { |
| + int cell_id_count = static_cast<int>(unique_cell_ids_.size()); |
| + if (cell_index < 0) |
| + return E_INVALIDARG; |
| + if (cell_index >= cell_id_count) |
| return S_FALSE; |
| + |
| + int cell_id = unique_cell_ids_[cell_index]; |
| + BrowserAccessibilityWin* cell = static_cast<BrowserAccessibilityWin*>( |
|
Chris Guillory
2011/08/31 02:14:53
toBrowserAccessibilityWin()
|
| + manager_->GetFromRendererID(cell_id)); |
| + int cell_row_index; |
| + if (cell && |
| + cell->GetIntAttribute( |
| + WebAccessibility::ATTR_TABLE_CELL_ROW_INDEX, &cell_row_index)) { |
| + *row_index = cell_row_index; |
| + return S_OK; |
| } |
| - if (cell_index < 0 || cell_index >= columns * rows) |
| - return E_INVALIDARG; |
| - |
| - *row_index = cell_index / columns; |
| - |
| - return S_OK; |
| + return S_FALSE; |
| } |
| STDMETHODIMP BrowserAccessibilityWin::get_selectedChildren( |
| @@ -914,6 +928,7 @@ |
| if (!children || !n_children) |
| return E_INVALIDARG; |
| + // TODO(dmazzoni): Implement this. |
| *n_children = 0; |
| return S_OK; |
| } |
| @@ -928,6 +943,7 @@ |
| if (!columns || !n_columns) |
| return E_INVALIDARG; |
| + // TODO(dmazzoni): Implement this. |
| *n_columns = 0; |
| return S_OK; |
| } |
| @@ -942,6 +958,7 @@ |
| if (!rows || !n_rows) |
| return E_INVALIDARG; |
| + // TODO(dmazzoni): Implement this. |
| *n_rows = 0; |
| return S_OK; |
| } |
| @@ -967,6 +984,7 @@ |
| if (!is_selected) |
| return E_INVALIDARG; |
| + // TODO(dmazzoni): Implement this. |
| *is_selected = false; |
| return S_OK; |
| } |
| @@ -980,6 +998,7 @@ |
| if (!is_selected) |
| return E_INVALIDARG; |
| + // TODO(dmazzoni): Implement this. |
| *is_selected = false; |
| return S_OK; |
| } |
| @@ -994,6 +1013,7 @@ |
| if (!is_selected) |
| return E_INVALIDARG; |
| + // TODO(dmazzoni): Implement this. |
| *is_selected = false; |
| return S_OK; |
| } |
| @@ -1011,21 +1031,13 @@ |
| if (!row || !column || !row_extents || !column_extents || !is_selected) |
| return E_INVALIDARG; |
| - int columns; |
| - int rows; |
| - if (!GetIntAttribute(WebAccessibility::ATTR_TABLE_COLUMN_COUNT, &columns) || |
| - !GetIntAttribute(WebAccessibility::ATTR_TABLE_ROW_COUNT, &rows) || |
| - columns <= 0 || |
| - rows <= 0) { |
| + int cell_id_count = static_cast<int>(unique_cell_ids_.size()); |
| + if (index < 0) |
| + return E_INVALIDARG; |
| + if (index >= cell_id_count) |
| return S_FALSE; |
| - } |
| - if (index < 0 || index >= columns * rows) |
| - return E_INVALIDARG; |
| - |
| - *column = index % columns; |
| - *row = index / columns; |
| - int cell_id = cell_ids_[index]; |
| + int cell_id = unique_cell_ids_[index]; |
| BrowserAccessibilityWin* cell = static_cast<BrowserAccessibilityWin*>( |
| manager_->GetFromRendererID(cell_id)); |
| int rowspan; |
| @@ -1046,6 +1058,64 @@ |
| } |
| // |
| +// IAccessibleTable2 methods. |
| +// |
| + |
| +STDMETHODIMP BrowserAccessibilityWin::get_cellAt( |
| + long row, |
| + long column, |
| + IUnknown** cell) { |
| + return get_accessibleAt(row, column, cell); |
| +} |
| + |
| +STDMETHODIMP BrowserAccessibilityWin::get_nSelectedCells(long* cell_count) { |
| + return get_nSelectedChildren(cell_count); |
| +} |
| + |
| +STDMETHODIMP BrowserAccessibilityWin::get_selectedCells( |
| + IUnknown*** cells, |
| + long* n_selected_cells) { |
| + if (!instance_active_) |
| + return E_FAIL; |
| + |
| + if (!cells || !n_selected_cells) |
| + return E_INVALIDARG; |
| + |
| + // TODO(dmazzoni): Implement this. |
| + *n_selected_cells = 0; |
| + return S_OK; |
| +} |
| + |
| +STDMETHODIMP BrowserAccessibilityWin::get_selectedColumns( |
| + long** columns, |
| + long* n_columns) { |
| + if (!instance_active_) |
| + return E_FAIL; |
| + |
| + if (!columns || !n_columns) |
| + return E_INVALIDARG; |
| + |
| + // TODO(dmazzoni): Implement this. |
| + *n_columns = 0; |
| + return S_OK; |
| +} |
| + |
| +STDMETHODIMP BrowserAccessibilityWin::get_selectedRows( |
| + long** rows, |
| + long* n_rows) { |
| + if (!instance_active_) |
| + return E_FAIL; |
| + |
| + if (!rows || !n_rows) |
| + return E_INVALIDARG; |
| + |
| + // TODO(dmazzoni): Implement this. |
| + *n_rows = 0; |
| + return S_OK; |
| +} |
| + |
| + |
| +// |
| // IAccessibleTableCell methods. |
| // |
| @@ -1088,8 +1158,10 @@ |
| BrowserAccessibility* table = parent(); |
| while (table && table->role() != WebAccessibility::ROLE_TABLE) |
| table = table->parent(); |
| - if (!table) |
| + if (!table) { |
| + DCHECK(false); |
|
Chris Guillory
2011/08/31 02:14:53
NOTREACHED()
|
| return S_FALSE; |
| + } |
| int columns; |
| int rows; |
| @@ -1102,7 +1174,7 @@ |
| if (columns <= 0 || rows <= 0 || column < 0 || column >= columns) |
| return S_FALSE; |
| - for (int i = 0; i < rows; i++) { |
| + for (int i = 0; i < rows; ++i) { |
| int cell_id = table->cell_ids()[i * columns + column]; |
| BrowserAccessibilityWin* cell = static_cast<BrowserAccessibilityWin*>( |
| manager_->GetFromRendererID(cell_id)); |
| @@ -1113,14 +1185,14 @@ |
| *cell_accessibles = static_cast<IUnknown**>(CoTaskMemAlloc( |
| (*n_column_header_cells) * sizeof(cell_accessibles[0]))); |
| int index = 0; |
| - for (int i = 0; i < rows; i++) { |
| + for (int i = 0; i < rows; ++i) { |
| int cell_id = table->cell_ids()[i * columns + column]; |
| BrowserAccessibilityWin* cell = static_cast<BrowserAccessibilityWin*>( |
| manager_->GetFromRendererID(cell_id)); |
| if (cell && cell->role_ == WebAccessibility::ROLE_COLUMN_HEADER) { |
| (*cell_accessibles)[index] = |
| static_cast<IAccessible*>(cell->NewReference()); |
| - index++; |
| + ++index; |
| } |
| } |
| @@ -1184,8 +1256,10 @@ |
| BrowserAccessibility* table = parent(); |
| while (table && table->role() != WebAccessibility::ROLE_TABLE) |
| table = table->parent(); |
| - if (!table) |
| + if (!table) { |
| + DCHECK(false); |
|
Chris Guillory
2011/08/31 02:14:53
NOTREACHED()
dmazzoni
2011/08/31 22:02:54
Done.
|
| return S_FALSE; |
| + } |
| int columns; |
| int rows; |
| @@ -1198,7 +1272,7 @@ |
| if (columns <= 0 || rows <= 0 || row < 0 || row >= rows) |
| return S_FALSE; |
| - for (int i = 0; i < columns; i++) { |
| + for (int i = 0; i < columns; ++i) { |
| int cell_id = table->cell_ids()[row * columns + i]; |
| BrowserAccessibilityWin* cell = static_cast<BrowserAccessibilityWin*>( |
| manager_->GetFromRendererID(cell_id)); |
| @@ -1209,14 +1283,14 @@ |
| *cell_accessibles = static_cast<IUnknown**>(CoTaskMemAlloc( |
| (*n_row_header_cells) * sizeof(cell_accessibles[0]))); |
| int index = 0; |
| - for (int i = 0; i < columns; i++) { |
| + for (int i = 0; i < columns; ++i) { |
| int cell_id = table->cell_ids()[row * columns + i]; |
| BrowserAccessibilityWin* cell = static_cast<BrowserAccessibilityWin*>( |
| manager_->GetFromRendererID(cell_id)); |
| if (cell && cell->role_ == WebAccessibility::ROLE_ROW_HEADER) { |
| (*cell_accessibles)[index] = |
| static_cast<IAccessible*>(cell->NewReference()); |
| - index++; |
| + ++index; |
| } |
| } |
| @@ -1298,13 +1372,21 @@ |
| if (!table) |
| return E_INVALIDARG; |
| + |
| + int row; |
| + int column; |
| + GetIntAttribute(WebAccessibility::ATTR_TABLE_CELL_ROW_INDEX, &row); |
| + GetIntAttribute(WebAccessibility::ATTR_TABLE_CELL_COLUMN_INDEX, &column); |
| + |
| BrowserAccessibility* find_table = parent(); |
| while (find_table && find_table->role() != WebAccessibility::ROLE_TABLE) |
| find_table = find_table->parent(); |
| - if (!find_table) |
| + if (!find_table) { |
| + DCHECK(false); |
|
Chris Guillory
2011/08/31 02:14:53
NOTREACHED()
|
| return S_FALSE; |
| + } |
| - *table = static_cast<IAccessible*>( |
| + *table = static_cast<IAccessibleTable*>( |
|
Chris Guillory
2011/08/31 02:14:53
toBrowserAccessibilityWin(). IAccessibleTable* cas
dmazzoni
2011/08/31 22:02:54
Switched to use toBrowserAccessibilityWin(), but t
|
| static_cast<BrowserAccessibilityWin*>(find_table)->NewReference()); |
| return S_OK; |
| @@ -1526,7 +1608,115 @@ |
| return get_text(*start_offset, *end_offset, text); |
| } |
| +STDMETHODIMP BrowserAccessibilityWin::get_newText(IA2TextSegment* new_text) { |
| + if (!instance_active_) |
| + return E_FAIL; |
| + |
| + if (!new_text) |
| + return E_INVALIDARG; |
| + |
| + string16 text = TextForIAccessibleText(); |
| + |
| + new_text->text = SysAllocString(text.c_str()); |
| + new_text->start = 0; |
| + new_text->end = static_cast<long>(text.size()); |
|
Chris Guillory
2011/08/31 02:14:53
Verification: string16 keeps a local for the text
dmazzoni
2011/08/31 22:02:54
Correct, this is O(1)
|
| + return S_OK; |
| +} |
| + |
| +STDMETHODIMP BrowserAccessibilityWin::get_oldText(IA2TextSegment* old_text) { |
| + if (!instance_active_) |
| + return E_FAIL; |
| + |
| + if (!old_text) |
| + return E_INVALIDARG; |
| + |
| + old_text->text = SysAllocString(old_text_.c_str()); |
| + old_text->start = 0; |
| + old_text->end = static_cast<long>(old_text_.size()); |
| + return S_OK; |
| +} |
| + |
| +STDMETHODIMP BrowserAccessibilityWin::get_offsetAtPoint( |
| + LONG x, LONG y, enum IA2CoordinateType coord_type, LONG* offset) { |
| + if (!instance_active_) |
| + return E_FAIL; |
| + |
| + if (!offset) |
| + return E_INVALIDARG; |
| + |
| + // TODO(dmazzoni): implement this. We're returning S_OK for now so that |
| + // screen readers still return partially accurate results rather than |
| + // completely failing. |
| + *offset = 0; |
| + return S_OK; |
| +} |
| + |
| // |
| +// IAccessibleValue methods. |
| +// |
| + |
| +STDMETHODIMP BrowserAccessibilityWin::get_currentValue(VARIANT* value) { |
| + if (!instance_active_) |
| + return E_FAIL; |
| + |
| + if (!value) |
| + return E_INVALIDARG; |
| + |
| + float float_val; |
| + if (GetFloatAttribute(WebAccessibility::ATTR_VALUE_FOR_RANGE, &float_val)) { |
| + value->vt = VT_R8; |
| + value->dblVal = float_val; |
| + return S_OK; |
| + } |
| + |
| + value->vt = VT_EMPTY; |
| + return S_FALSE; |
| +} |
| + |
| +STDMETHODIMP BrowserAccessibilityWin::get_minimumValue(VARIANT* value) { |
| + if (!instance_active_) |
| + return E_FAIL; |
| + |
| + if (!value) |
| + return E_INVALIDARG; |
| + |
| + float float_val; |
| + if (GetFloatAttribute(WebAccessibility::ATTR_MIN_VALUE_FOR_RANGE, |
| + &float_val)) { |
| + value->vt = VT_R8; |
| + value->dblVal = float_val; |
| + return S_OK; |
| + } |
| + |
| + value->vt = VT_EMPTY; |
| + return S_FALSE; |
| +} |
| + |
| +STDMETHODIMP BrowserAccessibilityWin::get_maximumValue(VARIANT* value) { |
| + if (!instance_active_) |
| + return E_FAIL; |
| + |
| + if (!value) |
| + return E_INVALIDARG; |
| + |
| + float float_val; |
| + if (GetFloatAttribute(WebAccessibility::ATTR_MAX_VALUE_FOR_RANGE, |
| + &float_val)) { |
| + value->vt = VT_R8; |
| + value->dblVal = float_val; |
| + return S_OK; |
| + } |
| + |
| + value->vt = VT_EMPTY; |
| + return S_FALSE; |
| +} |
| + |
| +STDMETHODIMP BrowserAccessibilityWin::setCurrentValue(VARIANT new_value) { |
| + // TODO(dmazzoni): Implement this. |
| + return E_NOTIMPL; |
| +} |
| + |
| +// |
| // ISimpleDOMDocument methods. |
| // |
| @@ -1707,7 +1897,7 @@ |
| // We only cache a single style property for now: DISPLAY |
| - for (unsigned short i = 0; i < num_style_properties; i++) { |
| + for (unsigned short i = 0; i < num_style_properties; ++i) { |
| string16 name = (LPCWSTR)style_properties[i]; |
| StringToLowerASCII(&name); |
| if (name == L"display") { |
| @@ -1853,19 +2043,14 @@ |
| if (!instance_active_) |
| return E_FAIL; |
| - if (guidService == IID_IAccessibleTable) { |
| - printf("iatable"); |
| - } |
| - if (guidService == IID_IAccessibleTableCell) { |
| - printf("iatable"); |
| - } |
| - |
| if (guidService == IID_IAccessible || |
| guidService == IID_IAccessible2 || |
| guidService == IID_IAccessibleImage || |
| guidService == IID_IAccessibleTable || |
| + guidService == IID_IAccessibleTable2 || |
| guidService == IID_IAccessibleTableCell || |
| guidService == IID_IAccessibleText || |
| + guidService == IID_IAccessibleValue || |
| guidService == IID_ISimpleDOMDocument || |
| guidService == IID_ISimpleDOMNode || |
| guidService == IID_ISimpleDOMText || |
| @@ -1896,7 +2081,7 @@ |
| *object = NULL; |
| return E_NOINTERFACE; |
| } |
| - } else if (iid == IID_IAccessibleTable) { |
| + } else if (iid == IID_IAccessibleTable || iid == IID_IAccessibleTable2) { |
| if (ia_role_ != ROLE_SYSTEM_TABLE) { |
| *object = NULL; |
| return E_NOINTERFACE; |
| @@ -1906,6 +2091,13 @@ |
| *object = NULL; |
| return E_NOINTERFACE; |
| } |
| + } else if (iid == IID_IAccessibleValue) { |
| + if (ia_role_ != ROLE_SYSTEM_PROGRESSBAR && |
| + ia_role_ != ROLE_SYSTEM_SCROLLBAR && |
| + ia_role_ != ROLE_SYSTEM_SLIDER) { |
| + *object = NULL; |
| + return E_NOINTERFACE; |
| + } |
| } else if (iid == IID_ISimpleDOMDocument) { |
| if (ia_role_ != ROLE_SYSTEM_DOCUMENT) { |
| *object = NULL; |
| @@ -1927,17 +2119,72 @@ |
| InitRoleAndState(); |
| - // Expose headings levels to NVDA with the "level" object attribute. |
| + // Expose headings levels with the "level" attribute. |
| if (role_ == WebAccessibility::ROLE_HEADING && role_name_.size() == 2 && |
| IsAsciiDigit(role_name_[1])) { |
| - html_attributes_.push_back(std::make_pair(L"level", role_name_.substr(1))); |
| + ia2_attributes_.push_back(string16(L"level:") + role_name_.substr(1)); |
| } |
| - // Expose the "display" object attribute. |
| - string16 display; |
| - if (GetStringAttribute(WebAccessibility::ATTR_DISPLAY, &display)) |
| - html_attributes_.push_back(std::make_pair(L"display", display)); |
| + // Expose the "display" and "tag" attributes. |
| + StringAttributeToIA2(WebAccessibility::ATTR_DISPLAY, "display"); |
| + StringAttributeToIA2(WebAccessibility::ATTR_HTML_TAG, "tag"); |
| + StringAttributeToIA2(WebAccessibility::ATTR_ROLE, "xml-roles"); |
| + // Expose "level" attribute for tree nodes. |
| + IntAttributeToIA2(WebAccessibility::ATTR_HIERARCHICAL_LEVEL, "level"); |
| + |
| + // Expose live region attributes. |
| + StringAttributeToIA2(WebAccessibility::ATTR_LIVE_STATUS, "live"); |
| + StringAttributeToIA2(WebAccessibility::ATTR_LIVE_RELEVANT, "relevant"); |
| + BoolAttributeToIA2(WebAccessibility::ATTR_LIVE_ATOMIC, "atomic"); |
| + BoolAttributeToIA2(WebAccessibility::ATTR_LIVE_BUSY, "busy"); |
| + |
| + // Expose container live region attributes. |
| + StringAttributeToIA2(WebAccessibility::ATTR_CONTAINER_LIVE_STATUS, |
| + "container-live"); |
| + StringAttributeToIA2(WebAccessibility::ATTR_CONTAINER_LIVE_RELEVANT, |
| + "container-relevant"); |
| + BoolAttributeToIA2(WebAccessibility::ATTR_CONTAINER_LIVE_ATOMIC, |
| + "container-atomic"); |
| + BoolAttributeToIA2(WebAccessibility::ATTR_CONTAINER_LIVE_BUSY, |
| + "container-busy"); |
| + |
| + // Expose slider value. |
| + if (ia_role_ == ROLE_SYSTEM_PROGRESSBAR || |
| + ia_role_ == ROLE_SYSTEM_SCROLLBAR || |
| + ia_role_ == ROLE_SYSTEM_SLIDER) { |
| + float fval; |
| + if (value_.empty() && |
| + GetFloatAttribute(WebAccessibility::ATTR_VALUE_FOR_RANGE, &fval)) { |
| + // TODO(dmazzoni): Use ICU to localize this? |
| + value_ = UTF8ToUTF16(base::DoubleToString(fval)); |
| + } |
| + ia2_attributes_.push_back(L"valuetext:" + value_); |
| + } |
| + |
| + // Expose table cell index. |
| + if (ia_role_ == ROLE_SYSTEM_CELL) { |
| + BrowserAccessibility* table = parent(); |
| + while (table && table->role() != WebAccessibility::ROLE_TABLE) |
| + table = table->parent(); |
| + if (table) { |
| + const std::vector<int32>& unique_cell_ids = table->unique_cell_ids(); |
| + int index = -1; |
| + for (size_t i = 0; i < unique_cell_ids.size(); ++i) { |
| + if (unique_cell_ids[i] == renderer_id_) { |
| + index = static_cast<int>(i); |
| + break; |
| + } |
| + } |
| + if (index >= 0) { |
| + ia2_attributes_.push_back(string16(L"table-cell-index:") + |
| + base::IntToString16(index)); |
| + } |
| + } else { |
| + DCHECK(false); |
|
Chris Guillory
2011/08/31 02:14:53
NOTREACHED()
|
| + } |
| + } |
| + |
| // If this is static text, put the text in the name rather than the value. |
| if (role_ == WebAccessibility::ROLE_STATIC_TEXT && name_.empty()) |
| name_.swap(value_); |
| @@ -1955,6 +2202,28 @@ |
| GetStringAttribute(WebAccessibility::ATTR_URL, &value_); |
| } |
| +void BrowserAccessibilityWin::SendNodeUpdateEvents() { |
| + // Fire an event when an alert first appears. |
| + if (role_ == WebAccessibility::ROLE_ALERT && first_time_) |
| + manager_->NotifyAccessibilityEvent(ViewHostMsg_AccEvent::ALERT, this); |
| + |
| + // Fire events if text has changed. |
| + string16 text = TextForIAccessibleText(); |
| + if (previous_text_ != text) { |
| + if (!previous_text_.empty() && !text.empty()) { |
| + manager_->NotifyAccessibilityEvent( |
| + ViewHostMsg_AccEvent::OBJECT_SHOW, this); |
| + } |
| + |
| + // TODO(dmazzoni): look into HIDE events, too. |
|
Chris Guillory
2011/08/31 02:14:53
Nit: look -> Look
dmazzoni
2011/08/31 22:02:54
Done.
|
| + |
| + old_text_ = previous_text_; |
| + previous_text_ = text; |
| + } |
| + |
| + first_time_ = false; |
| +} |
| + |
| void BrowserAccessibilityWin::NativeAddReference() { |
| AddRef(); |
| } |
| @@ -1999,13 +2268,36 @@ |
| return S_OK; |
| } |
| +void BrowserAccessibilityWin::StringAttributeToIA2( |
| + WebAccessibility::StringAttribute attribute, const char* ia2_attr) { |
| + string16 value; |
| + if (GetStringAttribute(attribute, &value)) |
| + ia2_attributes_.push_back(ASCIIToUTF16(ia2_attr) + L":" + value); |
| +} |
| + |
| +void BrowserAccessibilityWin::BoolAttributeToIA2( |
| + WebAccessibility::BoolAttribute attribute, const char* ia2_attr) { |
| + bool value; |
| + if (GetBoolAttribute(attribute, &value)) { |
| + ia2_attributes_.push_back((ASCIIToUTF16(ia2_attr) + L":") + |
| + (value ? L"true" : L"false")); |
| + } |
| +} |
| + |
| +void BrowserAccessibilityWin::IntAttributeToIA2( |
| + WebAccessibility::IntAttribute attribute, const char* ia2_attr) { |
| + int value; |
| + if (GetIntAttribute(attribute, &value)) |
| + ia2_attributes_.push_back(ASCIIToUTF16(ia2_attr) + L":" + |
| + base::IntToString16(value)); |
| +} |
| + |
| string16 BrowserAccessibilityWin::Escape(const string16& str) { |
| return EscapeQueryParamValueUTF8(str, false); |
| } |
| const string16& BrowserAccessibilityWin::TextForIAccessibleText() { |
| - if (role_ == WebAccessibility::ROLE_TEXT_FIELD || |
| - role_ == WebAccessibility::ROLE_TEXTAREA) { |
| + if (IsEditableText()) { |
| return value_; |
| } else { |
| return name_; |
| @@ -2041,7 +2333,7 @@ |
| return start_offset; |
| } else if (boundary == IA2_TEXT_BOUNDARY_LINE) { |
| if (direction == 1) { |
| - for (int j = 0; j < static_cast<int>(line_breaks_.size()); j++) { |
| + for (int j = 0; j < static_cast<int>(line_breaks_.size()); ++j) { |
|
Chris Guillory
2011/08/31 02:14:53
Verification: This is a no effect change on releas
dmazzoni
2011/08/31 22:02:54
Our style guide slightly prefers ++j, but yes, it
|
| if (line_breaks_[j] > start_offset) |
| return line_breaks_[j]; |
| } |
| @@ -2112,7 +2404,10 @@ |
| void BrowserAccessibilityWin::InitRoleAndState() { |
| ia_state_ = 0; |
| ia2_state_ = IA2_STATE_OPAQUE; |
| + ia2_attributes_.clear(); |
| + if ((state_ >> WebAccessibility::STATE_BUSY) & 1) |
| + ia_state_|= STATE_SYSTEM_BUSY; |
| if ((state_ >> WebAccessibility::STATE_CHECKED) & 1) |
| ia_state_ |= STATE_SYSTEM_CHECKED; |
| if ((state_ >> WebAccessibility::STATE_COLLAPSED) & 1) |
| @@ -2140,43 +2435,65 @@ |
| ia_state_|= STATE_SYSTEM_PRESSED; |
| if ((state_ >> WebAccessibility::STATE_PROTECTED) & 1) |
| ia_state_|= STATE_SYSTEM_PROTECTED; |
| + if ((state_ >> WebAccessibility::STATE_READONLY) & 1) |
| + ia_state_|= STATE_SYSTEM_READONLY; |
| + if ((state_ >> WebAccessibility::STATE_REQUIRED) & 1) |
| + ia2_state_|= IA2_STATE_REQUIRED; |
| if ((state_ >> WebAccessibility::STATE_SELECTABLE) & 1) |
| ia_state_|= STATE_SYSTEM_SELECTABLE; |
| if ((state_ >> WebAccessibility::STATE_SELECTED) & 1) |
| ia_state_|= STATE_SYSTEM_SELECTED; |
| - if ((state_ >> WebAccessibility::STATE_READONLY) & 1) |
| - ia_state_|= STATE_SYSTEM_READONLY; |
| if ((state_ >> WebAccessibility::STATE_TRAVERSED) & 1) |
| ia_state_|= STATE_SYSTEM_TRAVERSED; |
| - if ((state_ >> WebAccessibility::STATE_BUSY) & 1) |
| - ia_state_|= STATE_SYSTEM_BUSY; |
| if ((state_ >> WebAccessibility::STATE_UNAVAILABLE) & 1) |
| ia_state_|= STATE_SYSTEM_UNAVAILABLE; |
| + if ((state_ >> WebAccessibility::STATE_VERTICAL) & 1) { |
| + ia2_state_|= IA2_STATE_VERTICAL; |
| + } else { |
| + ia2_state_|= IA2_STATE_HORIZONTAL; |
| + } |
| + if ((state_ >> WebAccessibility::STATE_VISITED) & 1) |
| + ia_state_|= STATE_SYSTEM_TRAVERSED; |
| + string16 invalid; |
| + if (GetHtmlAttribute("aria-invalid", &invalid)) |
| + ia2_state_|= IA2_STATE_INVALID_ENTRY; |
| + |
| + bool mixed = false; |
| + GetBoolAttribute(WebAccessibility::ATTR_BUTTON_MIXED, &mixed); |
| + if (mixed) |
| + ia_state_|= STATE_SYSTEM_MIXED; |
| + |
| string16 html_tag; |
| GetStringAttribute(WebAccessibility::ATTR_HTML_TAG, &html_tag); |
| ia_role_ = 0; |
| ia2_role_ = 0; |
| switch (role_) { |
| case WebAccessibility::ROLE_ALERT: |
| - case WebAccessibility::ROLE_ALERT_DIALOG: |
| ia_role_ = ROLE_SYSTEM_ALERT; |
| break; |
| + case WebAccessibility::ROLE_ALERT_DIALOG: |
| + ia_role_ = ROLE_SYSTEM_DIALOG; |
| + break; |
| case WebAccessibility::ROLE_APPLICATION: |
| ia_role_ = ROLE_SYSTEM_APPLICATION; |
| break; |
| case WebAccessibility::ROLE_ARTICLE: |
| ia_role_ = ROLE_SYSTEM_GROUPING; |
| ia2_role_ = IA2_ROLE_SECTION; |
| + ia_state_|= STATE_SYSTEM_READONLY; |
| break; |
| case WebAccessibility::ROLE_BUSY_INDICATOR: |
| ia_role_ = ROLE_SYSTEM_ANIMATION; |
| + ia_state_|= STATE_SYSTEM_READONLY; |
| break; |
| case WebAccessibility::ROLE_BUTTON: |
| ia_role_ = ROLE_SYSTEM_PUSHBUTTON; |
| + ia_state_|= STATE_SYSTEM_READONLY; |
| break; |
| case WebAccessibility::ROLE_CELL: |
| ia_role_ = ROLE_SYSTEM_CELL; |
| + ia_state_|= STATE_SYSTEM_READONLY; |
| break; |
| case WebAccessibility::ROLE_CHECKBOX: |
| ia_role_ = ROLE_SYSTEM_CHECKBUTTON; |
| @@ -2187,9 +2504,11 @@ |
| break; |
| case WebAccessibility::ROLE_COLUMN: |
| ia_role_ = ROLE_SYSTEM_COLUMN; |
| + ia_state_|= STATE_SYSTEM_READONLY; |
| break; |
| case WebAccessibility::ROLE_COLUMN_HEADER: |
| ia_role_ = ROLE_SYSTEM_COLUMNHEADER; |
| + ia_state_|= STATE_SYSTEM_READONLY; |
| break; |
| case WebAccessibility::ROLE_COMBO_BOX: |
| ia_role_ = ROLE_SYSTEM_COMBOBOX; |
| @@ -2197,15 +2516,19 @@ |
| case WebAccessibility::ROLE_DEFINITION_LIST_DEFINITION: |
| role_name_ = html_tag; |
| ia2_role_ = IA2_ROLE_PARAGRAPH; |
| + ia_state_|= STATE_SYSTEM_READONLY; |
| break; |
| case WebAccessibility::ROLE_DEFINITION_LIST_TERM: |
| ia_role_ = ROLE_SYSTEM_LISTITEM; |
| + ia_state_|= STATE_SYSTEM_READONLY; |
| break; |
| case WebAccessibility::ROLE_DIALOG: |
| ia_role_ = ROLE_SYSTEM_DIALOG; |
| + ia_state_|= STATE_SYSTEM_READONLY; |
| break; |
| case WebAccessibility::ROLE_DISCLOSURE_TRIANGLE: |
| ia_role_ = ROLE_SYSTEM_OUTLINEBUTTON; |
| + ia_state_|= STATE_SYSTEM_READONLY; |
| break; |
| case WebAccessibility::ROLE_DOCUMENT: |
| case WebAccessibility::ROLE_WEB_AREA: |
| @@ -2220,10 +2543,17 @@ |
| break; |
| case WebAccessibility::ROLE_GRID: |
| ia_role_ = ROLE_SYSTEM_TABLE; |
| + ia_state_|= STATE_SYSTEM_READONLY; |
| break; |
| case WebAccessibility::ROLE_GROUP: |
| if (html_tag == L"li") { |
| ia_role_ = ROLE_SYSTEM_LISTITEM; |
| + } else if (html_tag == L"form") { |
| + role_name_ = html_tag; |
| + ia2_role_ = IA2_ROLE_FORM; |
| + } else if (html_tag == L"p") { |
| + role_name_ = html_tag; |
| + ia2_role_ = IA2_ROLE_PARAGRAPH; |
| } else { |
| if (html_tag.empty()) |
| role_name_ = L"div"; |
| @@ -2231,24 +2561,30 @@ |
| role_name_ = html_tag; |
| ia2_role_ = IA2_ROLE_SECTION; |
| } |
| + ia_state_|= STATE_SYSTEM_READONLY; |
| break; |
| case WebAccessibility::ROLE_GROW_AREA: |
| ia_role_ = ROLE_SYSTEM_GRIP; |
| + ia_state_|= STATE_SYSTEM_READONLY; |
| break; |
| case WebAccessibility::ROLE_HEADING: |
| role_name_ = html_tag; |
| ia2_role_ = IA2_ROLE_HEADING; |
| + ia_state_|= STATE_SYSTEM_READONLY; |
| break; |
| case WebAccessibility::ROLE_IMAGE: |
| ia_role_ = ROLE_SYSTEM_GRAPHIC; |
| + ia_state_|= STATE_SYSTEM_READONLY; |
| break; |
| case WebAccessibility::ROLE_IMAGE_MAP: |
| role_name_ = html_tag; |
| ia2_role_ = IA2_ROLE_IMAGE_MAP; |
| + ia_state_|= STATE_SYSTEM_READONLY; |
| break; |
| case WebAccessibility::ROLE_IMAGE_MAP_LINK: |
| ia_role_ = ROLE_SYSTEM_LINK; |
| ia_state_|= STATE_SYSTEM_LINKED; |
| + ia_state_|= STATE_SYSTEM_READONLY; |
| break; |
| case WebAccessibility::ROLE_LANDMARK_APPLICATION: |
| case WebAccessibility::ROLE_LANDMARK_BANNER: |
| @@ -2259,25 +2595,35 @@ |
| case WebAccessibility::ROLE_LANDMARK_SEARCH: |
| ia_role_ = ROLE_SYSTEM_GROUPING; |
| ia2_role_ = IA2_ROLE_SECTION; |
| + ia_state_|= STATE_SYSTEM_READONLY; |
| break; |
| case WebAccessibility::ROLE_LINK: |
| case WebAccessibility::ROLE_WEBCORE_LINK: |
| ia_role_ = ROLE_SYSTEM_LINK; |
| ia_state_|= STATE_SYSTEM_LINKED; |
| + ia_state_|= STATE_SYSTEM_READONLY; |
| break; |
| case WebAccessibility::ROLE_LIST: |
| ia_role_ = ROLE_SYSTEM_LIST; |
| + ia_state_|= STATE_SYSTEM_READONLY; |
| break; |
| case WebAccessibility::ROLE_LISTBOX: |
| ia_role_ = ROLE_SYSTEM_LIST; |
| break; |
| case WebAccessibility::ROLE_LISTBOX_OPTION: |
| + ia_role_ = ROLE_SYSTEM_LISTITEM; |
| + break; |
| case WebAccessibility::ROLE_LIST_ITEM: |
| - case WebAccessibility::ROLE_LIST_MARKER: |
| ia_role_ = ROLE_SYSTEM_LISTITEM; |
| + ia_state_|= STATE_SYSTEM_READONLY; |
| break; |
| + case WebAccessibility::ROLE_LIST_MARKER: |
| + ia_role_ = ROLE_SYSTEM_TEXT; |
| + ia_state_|= STATE_SYSTEM_READONLY; |
| + break; |
| case WebAccessibility::ROLE_MATH: |
| ia_role_ = ROLE_SYSTEM_EQUATION; |
| + ia_state_|= STATE_SYSTEM_READONLY; |
| break; |
| case WebAccessibility::ROLE_MENU: |
| case WebAccessibility::ROLE_MENU_BUTTON: |
| @@ -2296,15 +2642,23 @@ |
| case WebAccessibility::ROLE_NOTE: |
| ia_role_ = ROLE_SYSTEM_GROUPING; |
| ia2_role_ = IA2_ROLE_NOTE; |
| + ia_state_|= STATE_SYSTEM_READONLY; |
| break; |
| case WebAccessibility::ROLE_OUTLINE: |
| ia_role_ = ROLE_SYSTEM_OUTLINE; |
| + ia_state_|= STATE_SYSTEM_READONLY; |
| break; |
| case WebAccessibility::ROLE_POPUP_BUTTON: |
| - ia_role_ = ROLE_SYSTEM_COMBOBOX; |
| + if (html_tag == L"select") { |
| + ia_role_ = ROLE_SYSTEM_COMBOBOX; |
| + } else { |
| + ia_role_ = ROLE_SYSTEM_BUTTONMENU; |
| + } |
| + ia_state_|= STATE_SYSTEM_READONLY; |
| break; |
| case WebAccessibility::ROLE_PROGRESS_INDICATOR: |
| ia_role_ = ROLE_SYSTEM_PROGRESSBAR; |
| + ia_state_|= STATE_SYSTEM_READONLY; |
| break; |
| case WebAccessibility::ROLE_RADIO_BUTTON: |
| ia_role_ = ROLE_SYSTEM_RADIOBUTTON; |
| @@ -2316,20 +2670,25 @@ |
| case WebAccessibility::ROLE_REGION: |
| ia_role_ = ROLE_SYSTEM_GROUPING; |
| ia2_role_ = IA2_ROLE_SECTION; |
| + ia_state_|= STATE_SYSTEM_READONLY; |
| break; |
| case WebAccessibility::ROLE_ROW: |
| ia_role_ = ROLE_SYSTEM_ROW; |
| + ia_state_|= STATE_SYSTEM_READONLY; |
| break; |
| case WebAccessibility::ROLE_ROW_HEADER: |
| ia_role_ = ROLE_SYSTEM_ROWHEADER; |
| + ia_state_|= STATE_SYSTEM_READONLY; |
| break; |
| case WebAccessibility::ROLE_RULER: |
| ia_role_ = ROLE_SYSTEM_CLIENT; |
| ia2_role_ = IA2_ROLE_RULER; |
| + ia_state_|= STATE_SYSTEM_READONLY; |
| break; |
| case WebAccessibility::ROLE_SCROLLAREA: |
| ia_role_ = ROLE_SYSTEM_CLIENT; |
| ia2_role_ = IA2_ROLE_SCROLL_PANE; |
| + ia_state_|= STATE_SYSTEM_READONLY; |
| break; |
| case WebAccessibility::ROLE_SCROLLBAR: |
| ia_role_ = ROLE_SYSTEM_SCROLLBAR; |
| @@ -2340,13 +2699,16 @@ |
| case WebAccessibility::ROLE_SPLIT_GROUP: |
| ia_role_ = ROLE_SYSTEM_CLIENT; |
| ia2_role_ = IA2_ROLE_SPLIT_PANE; |
| + ia_state_|= STATE_SYSTEM_READONLY; |
| break; |
| case WebAccessibility::ROLE_ANNOTATION: |
| case WebAccessibility::ROLE_STATIC_TEXT: |
| ia_role_ = ROLE_SYSTEM_TEXT; |
| + ia_state_|= STATE_SYSTEM_READONLY; |
| break; |
| case WebAccessibility::ROLE_STATUS: |
| ia_role_ = ROLE_SYSTEM_STATUSBAR; |
| + ia_state_|= STATE_SYSTEM_READONLY; |
| break; |
| case WebAccessibility::ROLE_SPLITTER: |
| ia_role_ = ROLE_SYSTEM_SEPARATOR; |
| @@ -2356,10 +2718,12 @@ |
| break; |
| case WebAccessibility::ROLE_TABLE: |
| ia_role_ = ROLE_SYSTEM_TABLE; |
| + ia_state_|= STATE_SYSTEM_READONLY; |
| break; |
| case WebAccessibility::ROLE_TABLE_HEADER_CONTAINER: |
| ia_role_ = ROLE_SYSTEM_GROUPING; |
| ia2_role_ = IA2_ROLE_SECTION; |
| + ia_state_|= STATE_SYSTEM_READONLY; |
| break; |
| case WebAccessibility::ROLE_TAB_GROUP: |
| case WebAccessibility::ROLE_TAB_LIST: |
| @@ -2380,21 +2744,27 @@ |
| break; |
| case WebAccessibility::ROLE_TIMER: |
| ia_role_ = ROLE_SYSTEM_CLOCK; |
| + ia_state_|= STATE_SYSTEM_READONLY; |
| break; |
| case WebAccessibility::ROLE_TOOLBAR: |
| ia_role_ = ROLE_SYSTEM_TOOLBAR; |
| + ia_state_|= STATE_SYSTEM_READONLY; |
| break; |
| case WebAccessibility::ROLE_TOOLTIP: |
| ia_role_ = ROLE_SYSTEM_TOOLTIP; |
| + ia_state_|= STATE_SYSTEM_READONLY; |
| break; |
| case WebAccessibility::ROLE_TREE: |
| ia_role_ = ROLE_SYSTEM_OUTLINE; |
| + ia_state_|= STATE_SYSTEM_READONLY; |
| break; |
| case WebAccessibility::ROLE_TREE_GRID: |
| ia_role_ = ROLE_SYSTEM_OUTLINE; |
| + ia_state_|= STATE_SYSTEM_READONLY; |
| break; |
| case WebAccessibility::ROLE_TREE_ITEM: |
| ia_role_ = ROLE_SYSTEM_OUTLINEITEM; |
| + ia_state_|= STATE_SYSTEM_READONLY; |
| break; |
| case WebAccessibility::ROLE_WINDOW: |
| ia_role_ = ROLE_SYSTEM_WINDOW; |