diff options
-rw-r--r-- | chrome/browser/accessibility/browser_accessibility_mac_unittest.mm | 3 | ||||
-rw-r--r-- | chrome/browser/accessibility/renderer_accessibility_browsertest.cc | 106 | ||||
-rw-r--r-- | content/browser/accessibility/browser_accessibility.cc | 47 | ||||
-rw-r--r-- | content/browser/accessibility/browser_accessibility.h | 36 | ||||
-rw-r--r-- | content/browser/accessibility/browser_accessibility_cocoa.mm | 33 | ||||
-rw-r--r-- | content/browser/accessibility/browser_accessibility_win.cc | 856 | ||||
-rw-r--r-- | content/browser/accessibility/browser_accessibility_win.h | 145 | ||||
-rw-r--r-- | content/common/view_messages.h | 6 | ||||
-rw-r--r-- | webkit/glue/webaccessibility.cc | 60 | ||||
-rw-r--r-- | webkit/glue/webaccessibility.h | 39 |
10 files changed, 1203 insertions, 128 deletions
diff --git a/chrome/browser/accessibility/browser_accessibility_mac_unittest.mm b/chrome/browser/accessibility/browser_accessibility_mac_unittest.mm index 595fb33..fee3fd7 100644 --- a/chrome/browser/accessibility/browser_accessibility_mac_unittest.mm +++ b/chrome/browser/accessibility/browser_accessibility_mac_unittest.mm @@ -53,7 +53,8 @@ class BrowserAccessibilityTest : public CocoaTest { root.location.set_width(500); root.location.set_height(100); root.role = WebAccessibility::ROLE_WEB_AREA; - root.attributes[WebAccessibility::ATTR_HELP] = ASCIIToUTF16("HelpText"); + root.string_attributes[WebAccessibility::ATTR_HELP] = + ASCIIToUTF16("HelpText"); WebAccessibility child1; child1.name = ASCIIToUTF16("Child1"); diff --git a/chrome/browser/accessibility/renderer_accessibility_browsertest.cc b/chrome/browser/accessibility/renderer_accessibility_browsertest.cc index 123e559..980588a 100644 --- a/chrome/browser/accessibility/renderer_accessibility_browsertest.cc +++ b/chrome/browser/accessibility/renderer_accessibility_browsertest.cc @@ -59,7 +59,9 @@ class RendererAccessibilityBrowserTest : public InProcessBrowserTest { protected: std::string GetAttr(const WebAccessibility& node, - const WebAccessibility::Attribute attr); + const WebAccessibility::StringAttribute attr); + int GetIntAttr(const WebAccessibility& node, + const WebAccessibility::IntAttribute attr); }; void RendererAccessibilityBrowserTest::SetUpInProcessBrowserTestFixture() { @@ -82,14 +84,29 @@ void RendererAccessibilityBrowserTest::TearDownInProcessBrowserTestFixture() { // Convenience method to get the value of a particular WebAccessibility // node attribute as a UTF-8 const char*. std::string RendererAccessibilityBrowserTest::GetAttr( - const WebAccessibility& node, const WebAccessibility::Attribute attr) { - std::map<int32, string16>::const_iterator iter = node.attributes.find(attr); - if (iter != node.attributes.end()) + const WebAccessibility& node, + const WebAccessibility::StringAttribute attr) { + std::map<WebAccessibility::StringAttribute, string16>::const_iterator iter = + node.string_attributes.find(attr); + if (iter != node.string_attributes.end()) return UTF16ToUTF8(iter->second); else return ""; } +// Convenience method to get the value of a particular WebAccessibility +// node integer attribute. +int RendererAccessibilityBrowserTest::GetIntAttr( + const WebAccessibility& node, + const WebAccessibility::IntAttribute attr) { + std::map<WebAccessibility::IntAttribute, int32>::const_iterator iter = + node.int_attributes.find(attr); + if (iter != node.int_attributes.end()) + return iter->second; + else + return -1; +} + IN_PROC_BROWSER_TEST_F(RendererAccessibilityBrowserTest, CrossPlatformWebpageAccessibility) { // Create a data url and load it. @@ -172,10 +189,8 @@ IN_PROC_BROWSER_TEST_F(RendererAccessibilityBrowserTest, EXPECT_EQ(WebAccessibility::ROLE_TEXT_FIELD, text.role); EXPECT_STREQ( "input", GetAttr(text, WebAccessibility::ATTR_HTML_TAG).c_str()); - EXPECT_STREQ( - "0", GetAttr(text, WebAccessibility::ATTR_TEXT_SEL_START).c_str()); - EXPECT_STREQ( - "0", GetAttr(text, WebAccessibility::ATTR_TEXT_SEL_END).c_str()); + EXPECT_EQ(0, GetIntAttr(text, WebAccessibility::ATTR_TEXT_SEL_START)); + EXPECT_EQ(0, GetIntAttr(text, WebAccessibility::ATTR_TEXT_SEL_END)); EXPECT_STREQ("Hello, world.", UTF16ToUTF8(text.value).c_str()); // TODO(dmazzoni): as soon as more accessibility code is cross-platform, @@ -203,10 +218,8 @@ IN_PROC_BROWSER_TEST_F(RendererAccessibilityBrowserTest, EXPECT_EQ(WebAccessibility::ROLE_TEXT_FIELD, text.role); EXPECT_STREQ( "input", GetAttr(text, WebAccessibility::ATTR_HTML_TAG).c_str()); - EXPECT_STREQ( - "0", GetAttr(text, WebAccessibility::ATTR_TEXT_SEL_START).c_str()); - EXPECT_STREQ( - "13", GetAttr(text, WebAccessibility::ATTR_TEXT_SEL_END).c_str()); + EXPECT_EQ(0, GetIntAttr(text, WebAccessibility::ATTR_TEXT_SEL_START)); + EXPECT_EQ(13, GetIntAttr(text, WebAccessibility::ATTR_TEXT_SEL_END)); EXPECT_STREQ("Hello, world.", UTF16ToUTF8(text.value).c_str()); } @@ -334,4 +347,73 @@ IN_PROC_BROWSER_TEST_F(RendererAccessibilityBrowserTest, RecursiveAssertUniqueIds(tree, &ids); } +IN_PROC_BROWSER_TEST_F(RendererAccessibilityBrowserTest, + CrossPlatformTableSpan) { + // +---+---+---+ + // | 1 | 2 | + // +---+---+---+ + // | 3 | 4 | + // +---+---+---+ + + const char url_str[] = + "data:text/html," + "<!doctype html>" + "<table border=1>" + " <tr>" + " <td colspan=2>1</td><td>2</td>" + " </tr>" + " <tr>" + " <td>3</td><td colspan=2>4</td>" + " </tr>" + "</table>"; + GURL url(url_str); + browser()->OpenURL(url, GURL(), CURRENT_TAB, PageTransition::TYPED); + + const WebAccessibility& tree = GetWebAccessibilityTree(); + const WebAccessibility& table = tree.children[0]; + EXPECT_EQ(WebAccessibility::ROLE_TABLE, table.role); + ASSERT_GE(table.children.size(), 5U); + EXPECT_EQ(WebAccessibility::ROLE_ROW, table.children[0].role); + EXPECT_EQ(WebAccessibility::ROLE_ROW, table.children[1].role); + EXPECT_EQ(WebAccessibility::ROLE_COLUMN, table.children[2].role); + EXPECT_EQ(WebAccessibility::ROLE_COLUMN, table.children[3].role); + EXPECT_EQ(WebAccessibility::ROLE_COLUMN, table.children[4].role); + EXPECT_EQ(3, GetIntAttr(table, WebAccessibility::ATTR_TABLE_COLUMN_COUNT)); + EXPECT_EQ(2, GetIntAttr(table, WebAccessibility::ATTR_TABLE_ROW_COUNT)); + + const WebAccessibility& cell1 = table.children[0].children[0]; + const WebAccessibility& cell2 = table.children[0].children[1]; + const WebAccessibility& cell3 = table.children[1].children[0]; + const WebAccessibility& cell4 = table.children[1].children[1]; + + ASSERT_EQ(6U, table.cell_ids.size()); + EXPECT_EQ(cell1.id, table.cell_ids[0]); + EXPECT_EQ(cell1.id, table.cell_ids[1]); + EXPECT_EQ(cell2.id, table.cell_ids[2]); + EXPECT_EQ(cell3.id, table.cell_ids[3]); + EXPECT_EQ(cell4.id, table.cell_ids[4]); + EXPECT_EQ(cell4.id, table.cell_ids[5]); + + EXPECT_EQ(0, GetIntAttr(cell1, + WebAccessibility::ATTR_TABLE_CELL_COLUMN_INDEX)); + EXPECT_EQ(0, GetIntAttr(cell1, + WebAccessibility::ATTR_TABLE_CELL_ROW_INDEX)); + EXPECT_EQ(2, GetIntAttr(cell1, + WebAccessibility::ATTR_TABLE_CELL_COLUMN_SPAN)); + EXPECT_EQ(1, GetIntAttr(cell1, + WebAccessibility::ATTR_TABLE_CELL_ROW_SPAN)); + EXPECT_EQ(2, GetIntAttr(cell2, + WebAccessibility::ATTR_TABLE_CELL_COLUMN_INDEX)); + EXPECT_EQ(1, GetIntAttr(cell2, + WebAccessibility::ATTR_TABLE_CELL_COLUMN_SPAN)); + EXPECT_EQ(0, GetIntAttr(cell3, + WebAccessibility::ATTR_TABLE_CELL_COLUMN_INDEX)); + EXPECT_EQ(1, GetIntAttr(cell3, + WebAccessibility::ATTR_TABLE_CELL_COLUMN_SPAN)); + EXPECT_EQ(1, GetIntAttr(cell4, + WebAccessibility::ATTR_TABLE_CELL_COLUMN_INDEX)); + EXPECT_EQ(2, GetIntAttr(cell4, + WebAccessibility::ATTR_TABLE_CELL_COLUMN_SPAN)); +} + } // namespace diff --git a/content/browser/accessibility/browser_accessibility.cc b/content/browser/accessibility/browser_accessibility.cc index 784bae0..f8a4d51 100644 --- a/content/browser/accessibility/browser_accessibility.cc +++ b/content/browser/accessibility/browser_accessibility.cc @@ -8,6 +8,9 @@ #include "base/string_number_conversions.h" #include "content/browser/accessibility/browser_accessibility_manager.h" +typedef WebAccessibility::IntAttribute IntAttribute; +typedef WebAccessibility::StringAttribute StringAttribute; + #if defined(OS_POSIX) && !defined(OS_MACOSX) // There's no OS-specific implementation of BrowserAccessibilityManager // on Unix, so just instantiate the base class. @@ -55,13 +58,15 @@ void BrowserAccessibility::Initialize( renderer_id_ = src.id; name_ = src.name; value_ = src.value; - attributes_ = src.attributes; + string_attributes_ = src.string_attributes; + int_attributes_ = src.int_attributes; html_attributes_ = src.html_attributes; location_ = src.location; role_ = src.role; state_ = src.state; indirect_child_ids_ = src.indirect_child_ids; line_breaks_ = src.line_breaks; + cell_ids_ = src.cell_ids; Initialize(); } @@ -125,10 +130,8 @@ gfx::Rect BrowserAccessibility::GetBoundsRect() { BrowserAccessibility* root = manager_->GetRoot(); int scroll_x = 0; int scroll_y = 0; - root->GetAttributeAsInt( - WebAccessibility::ATTR_DOC_SCROLLX, &scroll_x); - root->GetAttributeAsInt( - WebAccessibility::ATTR_DOC_SCROLLY, &scroll_y); + root->GetIntAttribute(WebAccessibility::ATTR_DOC_SCROLLX, &scroll_x); + root->GetIntAttribute(WebAccessibility::ATTR_DOC_SCROLLY, &scroll_y); bounds.Offset(-scroll_x, -scroll_y); return bounds; @@ -174,15 +177,12 @@ void BrowserAccessibility::NativeReleaseReference() { delete this; } -bool BrowserAccessibility::HasAttribute( - WebAccessibility::Attribute attribute) { - return (attributes_.find(attribute) != attributes_.end()); -} - -bool BrowserAccessibility::GetAttribute( - WebAccessibility::Attribute attribute, string16* value) { - std::map<int32, string16>::iterator iter = attributes_.find(attribute); - if (iter != attributes_.end()) { +bool BrowserAccessibility::GetStringAttribute( + StringAttribute attribute, + string16* value) { + std::map<StringAttribute, string16>::iterator iter = + string_attributes_.find(attribute); + if (iter != string_attributes_.end()) { *value = iter->second; return true; } @@ -190,15 +190,14 @@ bool BrowserAccessibility::GetAttribute( return false; } -bool BrowserAccessibility::GetAttributeAsInt( - WebAccessibility::Attribute attribute, int* value_int) { - string16 value_str; - - if (!GetAttribute(attribute, &value_str)) - return false; - - if (!base::StringToInt(value_str, value_int)) - return false; +bool BrowserAccessibility::GetIntAttribute( + IntAttribute attribute, int* value) { + std::map<IntAttribute, int32>::iterator iter = + int_attributes_.find(attribute); + if (iter != int_attributes_.end()) { + *value = iter->second; + return true; + } - return true; + return false; } diff --git a/content/browser/accessibility/browser_accessibility.h b/content/browser/accessibility/browser_accessibility.h index dbd3e13..785fb23 100644 --- a/content/browser/accessibility/browser_accessibility.h +++ b/content/browser/accessibility/browser_accessibility.h @@ -129,7 +129,16 @@ class BrowserAccessibility { // Accessors // - const std::map<int32, string16>& attributes() const { return attributes_; } + const std::map<WebAccessibility::StringAttribute, string16>& + string_attributes() const { + return string_attributes_; + } + + const std::map<WebAccessibility::IntAttribute, int32>& + int_attributes() const { + return int_attributes_; + } + int32 child_id() const { return child_id_; } const std::vector<BrowserAccessibility*>& children() const { return children_; @@ -144,6 +153,9 @@ class BrowserAccessibility { const std::vector<int32>& line_breaks() const { return line_breaks_; } + const std::vector<int32>& cell_ids() const { + return cell_ids_; + } gfx::Rect location() const { return location_; } BrowserAccessibilityManager* manager() const { return manager_; } const string16& name() const { return name_; } @@ -161,20 +173,14 @@ class BrowserAccessibility { BrowserAccessibilityWin* toBrowserAccessibilityWin(); #endif - // BrowserAccessibilityCocoa needs access to these methods. - // Return true if this attribute is in the attributes map. - bool HasAttribute(WebAccessibility::Attribute attribute); - - // Retrieve the string value of an attribute from the attribute map and + // Retrieve the value of a string attribute from the attribute map and // returns true if found. - bool GetAttribute(WebAccessibility::Attribute attribute, string16* value); + bool GetStringAttribute(WebAccessibility::StringAttribute attribute, + string16* value); - // Retrieve the value of an attribute from the attribute map and - // if found and nonempty, try to convert it to an integer. - // Returns true only if both the attribute was found and it was successfully - // converted to an integer. - bool GetAttributeAsInt( - WebAccessibility::Attribute attribute, int* value_int); + // Retrieve the value of an integer attribute from the integer attribute + // map and returns true if found. + bool GetIntAttribute(WebAccessibility::IntAttribute attribute, int* value); protected: BrowserAccessibility(); @@ -204,7 +210,8 @@ class BrowserAccessibility { // Accessibility metadata from the renderer string16 name_; string16 value_; - std::map<int32, string16> attributes_; + std::map<WebAccessibility::StringAttribute, string16> string_attributes_; + std::map<WebAccessibility::IntAttribute, int32> int_attributes_; std::vector<std::pair<string16, string16> > html_attributes_; int32 role_; int32 state_; @@ -212,6 +219,7 @@ class BrowserAccessibility { gfx::Rect location_; std::vector<int32> indirect_child_ids_; std::vector<int32> line_breaks_; + std::vector<int32> cell_ids_; // BrowserAccessibility objects are reference-counted on some platforms. // When we're done with this object and it's removed from our accessibility diff --git a/content/browser/accessibility/browser_accessibility_cocoa.mm b/content/browser/accessibility/browser_accessibility_cocoa.mm index c4a670a..b6b08ea 100644 --- a/content/browser/accessibility/browser_accessibility_cocoa.mm +++ b/content/browser/accessibility/browser_accessibility_cocoa.mm @@ -16,13 +16,16 @@ #include "grit/webkit_strings.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebRect.h" +typedef WebAccessibility::IntAttribute IntAttribute; +typedef WebAccessibility::StringAttribute StringAttribute; + namespace { // Returns an autoreleased copy of the WebAccessibility's attribute. -NSString* NSStringForWebAccessibilityAttribute( - const std::map<int32, string16>& attributes, - WebAccessibility::Attribute attribute) { - std::map<int32, string16>::const_iterator iter = +NSString* NSStringForStringAttribute( + const std::map<StringAttribute, string16>& attributes, + StringAttribute attribute) { + std::map<StringAttribute, string16>::const_iterator iter = attributes.find(attribute); NSString* returnValue = @""; if (iter != attributes.end()) { @@ -301,8 +304,8 @@ NSDictionary* attributeToMethodNameMap = nil; } - (NSString*)description { - return NSStringForWebAccessibilityAttribute( - browserAccessibility_->attributes(), + return NSStringForStringAttribute( + browserAccessibility_->string_attributes(), WebAccessibility::ATTR_DESCRIPTION); } @@ -318,8 +321,8 @@ NSDictionary* attributeToMethodNameMap = nil; } - (NSString*)help { - return NSStringForWebAccessibilityAttribute( - browserAccessibility_->attributes(), + return NSStringForStringAttribute( + browserAccessibility_->string_attributes(), WebAccessibility::ATTR_HELP); } @@ -482,12 +485,12 @@ NSDictionary* attributeToMethodNameMap = nil; } - (NSString*)url { - WebAccessibility::Attribute urlAttribute = + StringAttribute urlAttribute = [[self role] isEqualToString:@"AXWebArea"] ? WebAccessibility::ATTR_DOC_URL : WebAccessibility::ATTR_URL; - return NSStringForWebAccessibilityAttribute( - browserAccessibility_->attributes(), + return NSStringForStringAttribute( + browserAccessibility_->string_attributes(), urlAttribute); } @@ -498,8 +501,8 @@ NSDictionary* attributeToMethodNameMap = nil; NSString* role = [self role]; if ([role isEqualToString:@"AXHeading"]) { NSString* headingLevel = - NSStringForWebAccessibilityAttribute( - browserAccessibility_->attributes(), + NSStringForStringAttribute( + browserAccessibility_->string_attributes(), WebAccessibility::ATTR_HTML_TAG); if ([headingLevel length] >= 2) { return [NSNumber numberWithInt: @@ -540,10 +543,10 @@ NSDictionary* attributeToMethodNameMap = nil; // TODO(dtseng): refactor remaining attributes. int selStart, selEnd; - if (browserAccessibility_->GetAttributeAsInt( + if (browserAccessibility_->GetIntAttribute( WebAccessibility::ATTR_TEXT_SEL_START, &selStart) && browserAccessibility_-> - GetAttributeAsInt(WebAccessibility::ATTR_TEXT_SEL_END, &selEnd)) { + GetIntAttribute(WebAccessibility::ATTR_TEXT_SEL_END, &selEnd)) { if (selStart > selEnd) std::swap(selStart, selEnd); int selLength = selEnd - selStart; diff --git a/content/browser/accessibility/browser_accessibility_win.cc b/content/browser/accessibility/browser_accessibility_win.cc index 8cd1566..9201866 100644 --- a/content/browser/accessibility/browser_accessibility_win.cc +++ b/content/browser/accessibility/browser_accessibility_win.cc @@ -201,7 +201,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_accDefaultAction(VARIANT var_id, if (!target) return E_INVALIDARG; - return target->GetAttributeAsBstr( + return target->GetStringAttributeAsBstr( WebAccessibility::ATTR_SHORTCUT, def_action); } @@ -217,7 +217,8 @@ STDMETHODIMP BrowserAccessibilityWin::get_accDescription(VARIANT var_id, if (!target) return E_INVALIDARG; - return target->GetAttributeAsBstr(WebAccessibility::ATTR_DESCRIPTION, desc); + return target->GetStringAttributeAsBstr( + WebAccessibility::ATTR_DESCRIPTION, desc); } STDMETHODIMP BrowserAccessibilityWin::get_accFocus(VARIANT* focus_child) { @@ -253,7 +254,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_accHelp(VARIANT var_id, BSTR* help) { if (!target) return E_INVALIDARG; - return target->GetAttributeAsBstr(WebAccessibility::ATTR_HELP, help); + return target->GetStringAttributeAsBstr(WebAccessibility::ATTR_HELP, help); } STDMETHODIMP BrowserAccessibilityWin::get_accKeyboardShortcut(VARIANT var_id, @@ -268,7 +269,8 @@ STDMETHODIMP BrowserAccessibilityWin::get_accKeyboardShortcut(VARIANT var_id, if (!target) return E_INVALIDARG; - return target->GetAttributeAsBstr(WebAccessibility::ATTR_SHORTCUT, acc_key); + return target->GetStringAttributeAsBstr( + WebAccessibility::ATTR_SHORTCUT, acc_key); } STDMETHODIMP BrowserAccessibilityWin::get_accName(VARIANT var_id, BSTR* name) { @@ -494,7 +496,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_description(BSTR* desc) { if (!desc) return E_INVALIDARG; - return GetAttributeAsBstr(WebAccessibility::ATTR_DESCRIPTION, desc); + return GetStringAttributeAsBstr(WebAccessibility::ATTR_DESCRIPTION, desc); } STDMETHODIMP BrowserAccessibilityWin::get_imagePosition( @@ -538,6 +540,777 @@ STDMETHODIMP BrowserAccessibilityWin::get_imageSize(LONG* height, LONG* width) { } // +// IAccessibleTable methods. +// + +STDMETHODIMP BrowserAccessibilityWin::get_accessibleAt( + long row, + long column, + IUnknown** accessible) { + if (!instance_active_) + return E_FAIL; + + if (!accessible) + 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) { + return S_FALSE; + } + + if (row < 0 || row >= rows || column < 0 || column >= columns) + return E_INVALIDARG; + + DCHECK_EQ(columns * rows, static_cast<int>(cell_ids_.size())); + + int cell_id = cell_ids_[row * columns + column]; + BrowserAccessibilityWin* cell = GetFromRendererID(cell_id); + if (cell) { + *accessible = static_cast<IAccessible*>(cell->NewReference()); + return S_OK; + } + + return S_FALSE; +} + +STDMETHODIMP BrowserAccessibilityWin::get_caption(IUnknown** accessible) { + if (!instance_active_) + return E_FAIL; + + if (!accessible) + return E_INVALIDARG; + + // TODO(dmazzoni): implement + return S_FALSE; +} + +STDMETHODIMP BrowserAccessibilityWin::get_childIndex( + long row, + long column, + long* cell_index) { + if (!instance_active_) + return E_FAIL; + + if (!cell_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) { + return S_FALSE; + } + + if (row < 0 || row >= rows || column < 0 || column >= columns) + return E_INVALIDARG; + + *cell_index = row * columns + column; + + return S_OK; +} + +STDMETHODIMP BrowserAccessibilityWin::get_columnDescription( + long column, + BSTR* description) { + if (!instance_active_) + return E_FAIL; + + if (!description) + 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) { + return S_FALSE; + } + + if (column < 0 || column >= columns) + return E_INVALIDARG; + + for (int i = 0; i < rows; i++) { + int cell_id = cell_ids_[i * columns + column]; + BrowserAccessibilityWin* cell = static_cast<BrowserAccessibilityWin*>( + manager_->GetFromRendererID(cell_id)); + if (cell && cell->role_ == WebAccessibility::ROLE_COLUMN_HEADER) { + if (cell->name_.size() > 0) { + *description = SysAllocString(cell->name_.c_str()); + return S_OK; + } + + return cell->GetStringAttributeAsBstr( + WebAccessibility::ATTR_DESCRIPTION, description); + } + } + + return S_FALSE; +} + +STDMETHODIMP BrowserAccessibilityWin::get_columnExtentAt( + long row, + long column, + long* n_columns_spanned) { + if (!instance_active_) + return E_FAIL; + + if (!n_columns_spanned) + 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) { + return S_FALSE; + } + + if (row < 0 || row >= rows || column < 0 || column >= columns) + return E_INVALIDARG; + + int cell_id = cell_ids_[row * columns + column]; + BrowserAccessibilityWin* cell = static_cast<BrowserAccessibilityWin*>( + manager_->GetFromRendererID(cell_id)); + int colspan; + if (cell && + cell->GetIntAttribute( + WebAccessibility::ATTR_TABLE_CELL_COLUMN_SPAN, &colspan) && + colspan >= 1) { + *n_columns_spanned = colspan; + return S_OK; + } + + return S_FALSE; +} + +STDMETHODIMP BrowserAccessibilityWin::get_columnHeader( + IAccessibleTable** accessible_table, + long* starting_row_index) { + // TODO(dmazzoni): implement + return E_NOTIMPL; +} + +STDMETHODIMP BrowserAccessibilityWin::get_columnIndex( + long cell_index, + long* column_index) { + if (!instance_active_) + return E_FAIL; + + 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) { + return S_FALSE; + } + + if (cell_index < 0 || cell_index >= columns * rows) + return E_INVALIDARG; + + *column_index = cell_index % columns; + + return S_OK; +} + +STDMETHODIMP BrowserAccessibilityWin::get_nColumns( + long* column_count) { + if (!instance_active_) + return E_FAIL; + + if (!column_count) + return E_INVALIDARG; + + int columns; + if (GetIntAttribute(WebAccessibility::ATTR_TABLE_COLUMN_COUNT, &columns)) { + *column_count = columns; + return S_OK; + } + + return S_FALSE; +} + +STDMETHODIMP BrowserAccessibilityWin::get_nRows( + long* row_count) { + if (!instance_active_) + return E_FAIL; + + if (!row_count) + return E_INVALIDARG; + + int rows; + if (GetIntAttribute(WebAccessibility::ATTR_TABLE_ROW_COUNT, &rows)) { + *row_count = rows; + return S_OK; + } + + return S_FALSE; +} + +STDMETHODIMP BrowserAccessibilityWin::get_nSelectedChildren( + long* cell_count) { + if (!instance_active_) + return E_FAIL; + + if (!cell_count) + return E_INVALIDARG; + + // TODO(dmazzoni): add support for selected cells/rows/columns in tables. + *cell_count = 0; + return S_OK; +} + +STDMETHODIMP BrowserAccessibilityWin::get_nSelectedColumns( + long* column_count) { + if (!instance_active_) + return E_FAIL; + + if (!column_count) + return E_INVALIDARG; + + *column_count = 0; + return S_OK; +} + +STDMETHODIMP BrowserAccessibilityWin::get_nSelectedRows( + long* row_count) { + if (!instance_active_) + return E_FAIL; + + if (!row_count) + return E_INVALIDARG; + + *row_count = 0; + return S_OK; +} + +STDMETHODIMP BrowserAccessibilityWin::get_rowDescription( + long row, + BSTR* description) { + if (!instance_active_) + return E_FAIL; + + if (!description) + 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) { + return S_FALSE; + } + + if (row < 0 || row >= rows) + return E_INVALIDARG; + + for (int i = 0; i < columns; i++) { + int cell_id = cell_ids_[row * columns + i]; + BrowserAccessibilityWin* cell = static_cast<BrowserAccessibilityWin*>( + manager_->GetFromRendererID(cell_id)); + if (cell && cell->role_ == WebAccessibility::ROLE_ROW_HEADER) { + if (cell->name_.size() > 0) { + *description = SysAllocString(cell->name_.c_str()); + return S_OK; + } + + return cell->GetStringAttributeAsBstr( + WebAccessibility::ATTR_DESCRIPTION, description); + } + } + + return S_FALSE; +} + +STDMETHODIMP BrowserAccessibilityWin::get_rowExtentAt( + long row, + long column, + long* n_rows_spanned) { + if (!instance_active_) + return E_FAIL; + + if (!n_rows_spanned) + 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) { + return S_FALSE; + } + + if (row < 0 || row >= rows || column < 0 || column >= columns) + return E_INVALIDARG; + + int cell_id = cell_ids_[row * columns + column]; + BrowserAccessibilityWin* cell = static_cast<BrowserAccessibilityWin*>( + manager_->GetFromRendererID(cell_id)); + int rowspan; + if (cell && + cell->GetIntAttribute( + WebAccessibility::ATTR_TABLE_CELL_ROW_SPAN, &rowspan) && + rowspan >= 1) { + *n_rows_spanned = rowspan; + return S_OK; + } + + return S_FALSE; +} + +STDMETHODIMP BrowserAccessibilityWin::get_rowHeader( + IAccessibleTable **accessible_table, + long* starting_column_index) { + // TODO(dmazzoni): implement + return E_NOTIMPL; +} + +STDMETHODIMP BrowserAccessibilityWin::get_rowIndex( + long cell_index, + long* row_index) { + if (!instance_active_) + return E_FAIL; + + 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) { + return S_FALSE; + } + + if (cell_index < 0 || cell_index >= columns * rows) + return E_INVALIDARG; + + *row_index = cell_index / columns; + + return S_OK; +} + +STDMETHODIMP BrowserAccessibilityWin::get_selectedChildren( + long max_children, + long** children, + long* n_children) { + if (!instance_active_) + return E_FAIL; + + if (!children || !n_children) + return E_INVALIDARG; + + *n_children = 0; + return S_OK; +} + +STDMETHODIMP BrowserAccessibilityWin::get_selectedColumns( + long max_columns, + long** columns, + long* n_columns) { + if (!instance_active_) + return E_FAIL; + + if (!columns || !n_columns) + return E_INVALIDARG; + + *n_columns = 0; + return S_OK; +} + +STDMETHODIMP BrowserAccessibilityWin::get_selectedRows( + long max_rows, + long** rows, + long* n_rows) { + if (!instance_active_) + return E_FAIL; + + if (!rows || !n_rows) + return E_INVALIDARG; + + *n_rows = 0; + return S_OK; +} + +STDMETHODIMP BrowserAccessibilityWin::get_summary( + IUnknown** accessible) { + if (!instance_active_) + return E_FAIL; + + if (!accessible) + return E_INVALIDARG; + + // TODO(dmazzoni): implement + return S_FALSE; +} + +STDMETHODIMP BrowserAccessibilityWin::get_isColumnSelected( + long column, + boolean* is_selected) { + if (!instance_active_) + return E_FAIL; + + if (!is_selected) + return E_INVALIDARG; + + *is_selected = false; + return S_OK; +} + +STDMETHODIMP BrowserAccessibilityWin::get_isRowSelected( + long row, + boolean* is_selected) { + if (!instance_active_) + return E_FAIL; + + if (!is_selected) + return E_INVALIDARG; + + *is_selected = false; + return S_OK; +} + +STDMETHODIMP BrowserAccessibilityWin::get_isSelected( + long row, + long column, + boolean* is_selected) { + if (!instance_active_) + return E_FAIL; + + if (!is_selected) + return E_INVALIDARG; + + *is_selected = false; + return S_OK; +} + +STDMETHODIMP BrowserAccessibilityWin::get_rowColumnExtentsAtIndex( + long index, + long* row, + long* column, + long* row_extents, + long* column_extents, + boolean* is_selected) { + if (!instance_active_) + return E_FAIL; + + 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) { + return S_FALSE; + } + + if (index < 0 || index >= columns * rows) + return E_INVALIDARG; + + *column = index % columns; + *row = index / columns; + int cell_id = cell_ids_[index]; + BrowserAccessibilityWin* cell = static_cast<BrowserAccessibilityWin*>( + manager_->GetFromRendererID(cell_id)); + int rowspan; + int colspan; + if (cell && + cell->GetIntAttribute( + WebAccessibility::ATTR_TABLE_CELL_ROW_SPAN, &rowspan) && + cell->GetIntAttribute( + WebAccessibility::ATTR_TABLE_CELL_COLUMN_SPAN, &colspan) && + rowspan >= 1 && + colspan >= 1) { + *row_extents = rowspan; + *column_extents = colspan; + return S_OK; + } + + return S_FALSE; +} + +// +// IAccessibleTableCell methods. +// + +STDMETHODIMP BrowserAccessibilityWin::get_columnExtent( + long* n_columns_spanned) { + if (!instance_active_) + return E_FAIL; + + if (!n_columns_spanned) + return E_INVALIDARG; + + int colspan; + if (GetIntAttribute( + WebAccessibility::ATTR_TABLE_CELL_COLUMN_SPAN, &colspan) && + colspan >= 1) { + *n_columns_spanned = colspan; + return S_OK; + } + + return S_FALSE; +} + +STDMETHODIMP BrowserAccessibilityWin::get_columnHeaderCells( + IUnknown*** cell_accessibles, + long* n_column_header_cells) { + if (!instance_active_) + return E_FAIL; + + if (!cell_accessibles || !n_column_header_cells) + return E_INVALIDARG; + + *n_column_header_cells = 0; + + int column; + if (!GetIntAttribute( + WebAccessibility::ATTR_TABLE_CELL_COLUMN_INDEX, &column)) { + return S_FALSE; + } + + BrowserAccessibility* table = parent(); + while (table && table->role() != WebAccessibility::ROLE_TABLE) + table = table->parent(); + if (!table) + return S_FALSE; + + int columns; + int rows; + if (!table->GetIntAttribute( + WebAccessibility::ATTR_TABLE_COLUMN_COUNT, &columns) || + !table->GetIntAttribute( + WebAccessibility::ATTR_TABLE_ROW_COUNT, &rows)) { + return S_FALSE; + } + if (columns <= 0 || rows <= 0 || column < 0 || column >= columns) + return S_FALSE; + + 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) + (*n_column_header_cells)++; + } + + *cell_accessibles = static_cast<IUnknown**>(CoTaskMemAlloc( + (*n_column_header_cells) * sizeof(cell_accessibles[0]))); + int index = 0; + 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++; + } + } + + return S_OK; +} + +STDMETHODIMP BrowserAccessibilityWin::get_columnIndex( + long* column_index) { + if (!instance_active_) + return E_FAIL; + + if (!column_index) + return E_INVALIDARG; + + int column; + if (GetIntAttribute( + WebAccessibility::ATTR_TABLE_CELL_COLUMN_INDEX, &column)) { + *column_index = column; + return S_OK; + } + + return S_FALSE; +} + +STDMETHODIMP BrowserAccessibilityWin::get_rowExtent( + long* n_rows_spanned) { + if (!instance_active_) + return E_FAIL; + + if (!n_rows_spanned) + return E_INVALIDARG; + + int rowspan; + if (GetIntAttribute( + WebAccessibility::ATTR_TABLE_CELL_ROW_SPAN, &rowspan) && + rowspan >= 1) { + *n_rows_spanned = rowspan; + return S_OK; + } + + return S_FALSE; +} + +STDMETHODIMP BrowserAccessibilityWin::get_rowHeaderCells( + IUnknown*** cell_accessibles, + long* n_row_header_cells) { + if (!instance_active_) + return E_FAIL; + + if (!cell_accessibles || !n_row_header_cells) + return E_INVALIDARG; + + *n_row_header_cells = 0; + + int row; + if (!GetIntAttribute( + WebAccessibility::ATTR_TABLE_CELL_ROW_INDEX, &row)) { + return S_FALSE; + } + + BrowserAccessibility* table = parent(); + while (table && table->role() != WebAccessibility::ROLE_TABLE) + table = table->parent(); + if (!table) + return S_FALSE; + + int columns; + int rows; + if (!table->GetIntAttribute( + WebAccessibility::ATTR_TABLE_COLUMN_COUNT, &columns) || + !table->GetIntAttribute( + WebAccessibility::ATTR_TABLE_ROW_COUNT, &rows)) { + return S_FALSE; + } + if (columns <= 0 || rows <= 0 || row < 0 || row >= rows) + return S_FALSE; + + 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) + (*n_row_header_cells)++; + } + + *cell_accessibles = static_cast<IUnknown**>(CoTaskMemAlloc( + (*n_row_header_cells) * sizeof(cell_accessibles[0]))); + int index = 0; + 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++; + } + } + + return S_OK; +} + +STDMETHODIMP BrowserAccessibilityWin::get_rowIndex( + long* row_index) { + if (!instance_active_) + return E_FAIL; + + if (!row_index) + return E_INVALIDARG; + + int row; + if (GetIntAttribute(WebAccessibility::ATTR_TABLE_CELL_ROW_INDEX, &row)) { + *row_index = row; + return S_OK; + } + return S_FALSE; +} + +STDMETHODIMP BrowserAccessibilityWin::get_isSelected( + boolean* is_selected) { + if (!instance_active_) + return E_FAIL; + + if (!is_selected) + return E_INVALIDARG; + + *is_selected = false; + return S_OK; +} + +STDMETHODIMP BrowserAccessibilityWin::get_rowColumnExtents( + long* row_index, + long* column_index, + long* row_extents, + long* column_extents, + boolean* is_selected) { + if (!instance_active_) + return E_FAIL; + + if (!row_index || + !column_index || + !row_extents || + !column_extents || + !is_selected) { + return E_INVALIDARG; + } + + int row; + int column; + int rowspan; + int colspan; + if (GetIntAttribute(WebAccessibility::ATTR_TABLE_CELL_ROW_INDEX, &row) && + GetIntAttribute( + WebAccessibility::ATTR_TABLE_CELL_COLUMN_INDEX, &column) && + GetIntAttribute( + WebAccessibility::ATTR_TABLE_CELL_ROW_SPAN, &rowspan) && + GetIntAttribute( + WebAccessibility::ATTR_TABLE_CELL_COLUMN_SPAN, &colspan)) { + *row_index = row; + *column_index = column; + *row_extents = rowspan; + *column_extents = colspan; + *is_selected = false; + return S_OK; + } + + return S_FALSE; +} + +STDMETHODIMP BrowserAccessibilityWin::get_table( + IUnknown** table) { + if (!instance_active_) + return E_FAIL; + + if (!table) + return E_INVALIDARG; + + BrowserAccessibility* find_table = parent(); + while (find_table && find_table->role() != WebAccessibility::ROLE_TABLE) + find_table = find_table->parent(); + if (!find_table) + return S_FALSE; + + *table = static_cast<IAccessible*>( + static_cast<BrowserAccessibilityWin*>(find_table)->NewReference()); + + return S_OK; +} + +// // IAccessibleText methods. // @@ -568,7 +1341,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_caretOffset(LONG* offset) { if (role_ == WebAccessibility::ROLE_TEXT_FIELD || role_ == WebAccessibility::ROLE_TEXTAREA) { int sel_start = 0; - if (GetAttributeAsInt(WebAccessibility::ATTR_TEXT_SEL_START, &sel_start)) { + if (GetIntAttribute(WebAccessibility::ATTR_TEXT_SEL_START, &sel_start)) { *offset = sel_start; } else { *offset = 0; @@ -591,8 +1364,8 @@ STDMETHODIMP BrowserAccessibilityWin::get_nSelections(LONG* n_selections) { role_ == WebAccessibility::ROLE_TEXTAREA) { int sel_start = 0; int sel_end = 0; - if (GetAttributeAsInt(WebAccessibility::ATTR_TEXT_SEL_START, &sel_start) && - GetAttributeAsInt(WebAccessibility::ATTR_TEXT_SEL_END, &sel_end) && + if (GetIntAttribute(WebAccessibility::ATTR_TEXT_SEL_START, &sel_start) && + GetIntAttribute(WebAccessibility::ATTR_TEXT_SEL_END, &sel_end) && sel_start != sel_end) { *n_selections = 1; } else { @@ -618,8 +1391,8 @@ STDMETHODIMP BrowserAccessibilityWin::get_selection(LONG selection_index, role_ == WebAccessibility::ROLE_TEXTAREA) { int sel_start = 0; int sel_end = 0; - if (GetAttributeAsInt(WebAccessibility::ATTR_TEXT_SEL_START, &sel_start) && - GetAttributeAsInt(WebAccessibility::ATTR_TEXT_SEL_END, &sel_end)) { + if (GetIntAttribute(WebAccessibility::ATTR_TEXT_SEL_START, &sel_start) && + GetIntAttribute(WebAccessibility::ATTR_TEXT_SEL_END, &sel_end)) { *start_offset = sel_start; *end_offset = sel_end; } else { @@ -764,7 +1537,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_URL(BSTR* url) { if (!url) return E_INVALIDARG; - return GetAttributeAsBstr(WebAccessibility::ATTR_DOC_URL, url); + return GetStringAttributeAsBstr(WebAccessibility::ATTR_DOC_URL, url); } STDMETHODIMP BrowserAccessibilityWin::get_title(BSTR* title) { @@ -774,7 +1547,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_title(BSTR* title) { if (!title) return E_INVALIDARG; - return GetAttributeAsBstr(WebAccessibility::ATTR_DOC_TITLE, title); + return GetStringAttributeAsBstr(WebAccessibility::ATTR_DOC_TITLE, title); } STDMETHODIMP BrowserAccessibilityWin::get_mimeType(BSTR* mime_type) { @@ -784,7 +1557,8 @@ STDMETHODIMP BrowserAccessibilityWin::get_mimeType(BSTR* mime_type) { if (!mime_type) return E_INVALIDARG; - return GetAttributeAsBstr(WebAccessibility::ATTR_DOC_MIMETYPE, mime_type); + return GetStringAttributeAsBstr( + WebAccessibility::ATTR_DOC_MIMETYPE, mime_type); } STDMETHODIMP BrowserAccessibilityWin::get_docType(BSTR* doc_type) { @@ -794,7 +1568,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_docType(BSTR* doc_type) { if (!doc_type) return E_INVALIDARG; - return GetAttributeAsBstr(WebAccessibility::ATTR_DOC_DOCTYPE, doc_type); + return GetStringAttributeAsBstr(WebAccessibility::ATTR_DOC_DOCTYPE, doc_type); } // @@ -817,7 +1591,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_nodeInfo( } string16 tag; - if (GetAttribute(WebAccessibility::ATTR_HTML_TAG, &tag)) + if (GetStringAttribute(WebAccessibility::ATTR_HTML_TAG, &tag)) *node_name = SysAllocString(tag.c_str()); else *node_name = NULL; @@ -906,14 +1680,13 @@ STDMETHODIMP BrowserAccessibilityWin::get_computedStyle( // We only cache a single style property for now: DISPLAY + string16 display; if (max_style_properties == 0 || - !HasAttribute(WebAccessibility::ATTR_DISPLAY)) { + !GetStringAttribute(WebAccessibility::ATTR_DISPLAY, &display)) { *num_style_properties = 0; return S_OK; } - string16 display; - GetAttribute(WebAccessibility::ATTR_DISPLAY, &display); *num_style_properties = 1; style_properties[0] = SysAllocString(L"display"); style_values[0] = SysAllocString(display.c_str()); @@ -939,7 +1712,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_computedStyleForProperties( StringToLowerASCII(&name); if (name == L"display") { string16 display; - GetAttribute(WebAccessibility::ATTR_DISPLAY, &display); + GetStringAttribute(WebAccessibility::ATTR_DISPLAY, &display); style_values[i] = SysAllocString(display.c_str()); } else { style_values[i] = NULL; @@ -1080,9 +1853,18 @@ STDMETHODIMP BrowserAccessibilityWin::QueryService( 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_IAccessibleTableCell || guidService == IID_IAccessibleText || guidService == IID_ISimpleDOMDocument || guidService == IID_ISimpleDOMNode || @@ -1114,6 +1896,16 @@ HRESULT WINAPI BrowserAccessibilityWin::InternalQueryInterface( *object = NULL; return E_NOINTERFACE; } + } else if (iid == IID_IAccessibleTable) { + if (ia_role_ != ROLE_SYSTEM_TABLE) { + *object = NULL; + return E_NOINTERFACE; + } + } else if (iid == IID_IAccessibleTableCell) { + if (ia_role_ != ROLE_SYSTEM_CELL) { + *object = NULL; + return E_NOINTERFACE; + } } else if (iid == IID_ISimpleDOMDocument) { if (ia_role_ != ROLE_SYSTEM_DOCUMENT) { *object = NULL; @@ -1143,7 +1935,7 @@ void BrowserAccessibilityWin::Initialize() { // Expose the "display" object attribute. string16 display; - if (GetAttribute(WebAccessibility::ATTR_DISPLAY, &display)) + if (GetStringAttribute(WebAccessibility::ATTR_DISPLAY, &display)) html_attributes_.push_back(std::make_pair(L"display", display)); // If this is static text, put the text in the name rather than the value. @@ -1153,15 +1945,14 @@ void BrowserAccessibilityWin::Initialize() { // 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 // announce the name. - if (name_.empty() && HasAttribute(WebAccessibility::ATTR_DESCRIPTION)) - GetAttribute(WebAccessibility::ATTR_DESCRIPTION, &name_); + if (name_.empty()) + GetStringAttribute(WebAccessibility::ATTR_DESCRIPTION, &name_); // If this doesn't have a value and is linked then set its value to the url // attribute. This allows screen readers to read an empty link's destination. - if (value_.empty() && (ia_state_ & STATE_SYSTEM_LINKED) && - HasAttribute(WebAccessibility::ATTR_URL)) { - GetAttribute(WebAccessibility::ATTR_URL, &value_); - } + string16 url; + if (value_.empty() && (ia_state_ & STATE_SYSTEM_LINKED)) + GetStringAttribute(WebAccessibility::ATTR_URL, &value_); } void BrowserAccessibilityWin::NativeAddReference() { @@ -1192,11 +1983,11 @@ BrowserAccessibilityWin* BrowserAccessibilityWin::GetTargetFromChildID( return manager_->GetFromChildID(child_id)->toBrowserAccessibilityWin(); } -HRESULT BrowserAccessibilityWin::GetAttributeAsBstr( - WebAccessibility::Attribute attribute, BSTR* value_bstr) { +HRESULT BrowserAccessibilityWin::GetStringAttributeAsBstr( + WebAccessibility::StringAttribute attribute, BSTR* value_bstr) { string16 str; - if (!GetAttribute(attribute, &str)) + if (!GetStringAttribute(attribute, &str)) return S_FALSE; if (str.empty()) @@ -1313,6 +2104,11 @@ LONG BrowserAccessibilityWin::FindBoundary( } } +BrowserAccessibilityWin* BrowserAccessibilityWin::GetFromRendererID( + int32 renderer_id) { + return manager_->GetFromRendererID(renderer_id)->toBrowserAccessibilityWin(); +} + void BrowserAccessibilityWin::InitRoleAndState() { ia_state_ = 0; ia2_state_ = IA2_STATE_OPAQUE; @@ -1358,7 +2154,7 @@ void BrowserAccessibilityWin::InitRoleAndState() { ia_state_|= STATE_SYSTEM_UNAVAILABLE; string16 html_tag; - GetAttribute(WebAccessibility::ATTR_HTML_TAG, &html_tag); + GetStringAttribute(WebAccessibility::ATTR_HTML_TAG, &html_tag); ia_role_ = 0; ia2_role_ = 0; switch (role_) { diff --git a/content/browser/accessibility/browser_accessibility_win.h b/content/browser/accessibility/browser_accessibility_win.h index fb8e014..23a1b5f 100644 --- a/content/browser/accessibility/browser_accessibility_win.h +++ b/content/browser/accessibility/browser_accessibility_win.h @@ -38,6 +38,8 @@ class BrowserAccessibilityWin public IDispatchImpl<IAccessible2, &IID_IAccessible2, &LIBID_IAccessible2Lib>, public IAccessibleImage, + public IAccessibleTable, + public IAccessibleTableCell, public IAccessibleText, public IServiceProvider, public ISimpleDOMDocument, @@ -49,6 +51,8 @@ class BrowserAccessibilityWin COM_INTERFACE_ENTRY2(IAccessible, IAccessible2) COM_INTERFACE_ENTRY(IAccessible2) COM_INTERFACE_ENTRY(IAccessibleImage) + COM_INTERFACE_ENTRY(IAccessibleTable) + COM_INTERFACE_ENTRY(IAccessibleTableCell) COM_INTERFACE_ENTRY(IAccessibleText) COM_INTERFACE_ENTRY(IServiceProvider) COM_INTERFACE_ENTRY(ISimpleDOMDocument) @@ -225,6 +229,137 @@ class BrowserAccessibilityWin STDMETHODIMP get_imageSize(LONG* height, LONG* width); // + // IAccessibleTable methods. + // + + // get_description - also used by IAccessibleImage + + STDMETHODIMP get_accessibleAt(long row, + long column, + IUnknown** accessible); + + STDMETHODIMP get_caption(IUnknown** accessible); + + STDMETHODIMP get_childIndex(long row_index, + long column_index, + long* cell_index); + + STDMETHODIMP get_columnDescription(long column, + BSTR* description); + + STDMETHODIMP get_columnExtentAt(long row, + long column, + long* n_columns_spanned); + + STDMETHODIMP get_columnHeader(IAccessibleTable** accessible_table, + long* starting_row_index); + + STDMETHODIMP get_columnIndex(long cell_index, + long* column_index); + + STDMETHODIMP get_nColumns(long* column_count); + + STDMETHODIMP get_nRows(long* row_count); + + STDMETHODIMP get_nSelectedChildren(long* cell_count); + + STDMETHODIMP get_nSelectedColumns(long* column_count); + + STDMETHODIMP get_nSelectedRows(long *row_count); + + STDMETHODIMP get_rowDescription(long row, + BSTR* description); + + STDMETHODIMP get_rowExtentAt(long row, + long column, + long* n_rows_spanned); + + STDMETHODIMP get_rowHeader(IAccessibleTable **accessible_table, + long* starting_column_index); + + STDMETHODIMP get_rowIndex(long cell_index, + long* row_index); + + STDMETHODIMP get_selectedChildren(long max_children, + long** children, + long* n_children); + + STDMETHODIMP get_selectedColumns(long max_columns, + long** columns, + long* n_columns); + + STDMETHODIMP get_selectedRows(long max_rows, + long** rows, + long* n_rows); + + STDMETHODIMP get_summary(IUnknown** accessible); + + STDMETHODIMP get_isColumnSelected(long column, + boolean* is_selected); + + STDMETHODIMP get_isRowSelected(long row, + boolean* is_selected); + + STDMETHODIMP get_isSelected(long row, + long column, + boolean* is_selected); + + STDMETHODIMP get_rowColumnExtentsAtIndex(long index, + long* row, + long* column, + long* row_extents, + long* column_extents, + boolean* is_selected); + + STDMETHODIMP selectRow(long row) { + return E_NOTIMPL; + } + + STDMETHODIMP selectColumn(long column) { + return E_NOTIMPL; + } + + STDMETHODIMP unselectRow(long row) { + return E_NOTIMPL; + } + + STDMETHODIMP unselectColumn(long column) { + return E_NOTIMPL; + } + + STDMETHODIMP get_modelChange(IA2TableModelChange* model_change) { + return E_NOTIMPL; + } + + // + // IAccessibleTableCell methods. + // + + STDMETHODIMP get_columnExtent(long* n_columns_spanned); + + STDMETHODIMP get_columnHeaderCells(IUnknown*** cell_accessibles, + long* n_column_header_cells); + + STDMETHODIMP get_columnIndex(long* column_index); + + STDMETHODIMP get_rowExtent(long* n_rows_spanned); + + STDMETHODIMP get_rowHeaderCells(IUnknown*** cell_accessibles, + long* n_row_header_cells); + + STDMETHODIMP get_rowIndex(long* row_index); + + STDMETHODIMP get_isSelected(boolean* is_selected); + + STDMETHODIMP get_rowColumnExtents(long* row, + long* column, + long* row_extents, + long* column_extents, + boolean* is_selected); + + STDMETHODIMP get_table(IUnknown** table); + + // // IAccessibleText methods. // @@ -457,11 +592,11 @@ class BrowserAccessibilityWin // bitmasks defined in webkit/glue/webaccessibility.h. void InitRoleAndState(); - // Retrieve the string value of an attribute from the attribute map and + // Retrieve the value of an attribute from the string attribute map and // if found and nonempty, allocate a new BSTR (with SysAllocString) // and return S_OK. If not found or empty, return S_FALSE. - HRESULT GetAttributeAsBstr( - WebAccessibility::Attribute attribute, BSTR* value_bstr); + HRESULT GetStringAttributeAsBstr( + WebAccessibility::StringAttribute attribute, BSTR* value_bstr); // Escape a string like it would be escaped for a URL or HTML form. string16 Escape(const string16& str); @@ -482,6 +617,10 @@ class BrowserAccessibilityWin LONG start_offset, LONG direction); + // Return a pointer to the object corresponding to the given renderer_id, + // does not make a new reference. + BrowserAccessibilityWin* GetFromRendererID(int32 renderer_id); + // IAccessible role and state. int32 ia_role_; int32 ia_state_; diff --git a/content/common/view_messages.h b/content/common/view_messages.h index 974f3e8..021352c 100644 --- a/content/common/view_messages.h +++ b/content/common/view_messages.h @@ -167,8 +167,10 @@ IPC_ENUM_TRAITS(WebKit::WebPopupType) IPC_ENUM_TRAITS(ui::TextInputType) IPC_ENUM_TRAITS(WebMenuItem::Type) IPC_ENUM_TRAITS(WindowContainerType) +IPC_ENUM_TRAITS(webkit_glue::WebAccessibility::IntAttribute) IPC_ENUM_TRAITS(webkit_glue::WebAccessibility::Role) IPC_ENUM_TRAITS(webkit_glue::WebAccessibility::State) +IPC_ENUM_TRAITS(webkit_glue::WebAccessibility::StringAttribute) IPC_STRUCT_TRAITS_BEGIN(ContextMenuParams) IPC_STRUCT_TRAITS_MEMBER(media_type) @@ -357,11 +359,13 @@ IPC_STRUCT_TRAITS_BEGIN(webkit_glue::WebAccessibility) IPC_STRUCT_TRAITS_MEMBER(role) IPC_STRUCT_TRAITS_MEMBER(state) IPC_STRUCT_TRAITS_MEMBER(location) - IPC_STRUCT_TRAITS_MEMBER(attributes) + IPC_STRUCT_TRAITS_MEMBER(string_attributes) + IPC_STRUCT_TRAITS_MEMBER(int_attributes) IPC_STRUCT_TRAITS_MEMBER(children) IPC_STRUCT_TRAITS_MEMBER(indirect_child_ids) IPC_STRUCT_TRAITS_MEMBER(html_attributes) IPC_STRUCT_TRAITS_MEMBER(line_breaks) + IPC_STRUCT_TRAITS_MEMBER(cell_ids) IPC_STRUCT_TRAITS_END() IPC_STRUCT_TRAITS_BEGIN(webkit_glue::WebCookie) diff --git a/webkit/glue/webaccessibility.cc b/webkit/glue/webaccessibility.cc index 73f3140..77c362e 100644 --- a/webkit/glue/webaccessibility.cc +++ b/webkit/glue/webaccessibility.cc @@ -319,17 +319,17 @@ void WebAccessibility::Init(const WebKit::WebAccessibilityObject& src, location = src.boundingBoxRect(); if (src.actionVerb().length()) - attributes[ATTR_ACTION] = src.actionVerb(); + string_attributes[ATTR_ACTION] = src.actionVerb(); if (src.accessibilityDescription().length()) - attributes[ATTR_DESCRIPTION] = src.accessibilityDescription(); + string_attributes[ATTR_DESCRIPTION] = src.accessibilityDescription(); if (src.helpText().length()) - attributes[ATTR_HELP] = src.helpText(); + string_attributes[ATTR_HELP] = src.helpText(); if (src.keyboardShortcut().length()) - attributes[ATTR_SHORTCUT] = src.keyboardShortcut(); + string_attributes[ATTR_SHORTCUT] = src.keyboardShortcut(); if (src.hasComputedStyle()) - attributes[ATTR_DISPLAY] = src.computedStyleDisplay(); + string_attributes[ATTR_DISPLAY] = src.computedStyleDisplay(); if (!src.url().isEmpty()) - attributes[ATTR_URL] = src.url().spec().utf16(); + string_attributes[ATTR_URL] = src.url().spec().utf16(); WebKit::WebNode node = src.node(); bool is_iframe = false; @@ -341,7 +341,8 @@ void WebAccessibility::Init(const WebKit::WebAccessibilityObject& src, // TODO(ctguil): The tagName in WebKit is lower cased but // HTMLElement::nodeName calls localNameUpper. Consider adding // a WebElement method that returns the original lower cased tagName. - attributes[ATTR_HTML_TAG] = StringToLowerASCII(string16(element.tagName())); + string_attributes[ATTR_HTML_TAG] = + StringToLowerASCII(string16(element.tagName())); for (unsigned i = 0; i < element.attributes().length(); i++) { html_attributes.push_back( std::pair<string16, string16>( @@ -357,9 +358,8 @@ void WebAccessibility::Init(const WebKit::WebAccessibilityObject& src, // Jaws gets confused by children of text fields, so we ignore them. include_children = false; - attributes[ATTR_TEXT_SEL_START] = base::IntToString16( - src.selectionStart()); - attributes[ATTR_TEXT_SEL_END] = base::IntToString16(src.selectionEnd()); + int_attributes[ATTR_TEXT_SEL_START] = src.selectionStart(); + int_attributes[ATTR_TEXT_SEL_END] = src.selectionEnd(); WebKit::WebVector<int> src_line_breaks; src.lineBreaks(src_line_breaks); line_breaks.reserve(src_line_breaks.size()); @@ -374,20 +374,46 @@ void WebAccessibility::Init(const WebKit::WebAccessibilityObject& src, const WebKit::WebDocument& document = src.document(); if (name.empty()) name = document.title(); - attributes[ATTR_DOC_TITLE] = document.title(); - attributes[ATTR_DOC_URL] = document.url().spec().utf16(); + string_attributes[ATTR_DOC_TITLE] = document.title(); + string_attributes[ATTR_DOC_URL] = document.url().spec().utf16(); if (document.isXHTMLDocument()) - attributes[ATTR_DOC_MIMETYPE] = WebKit::WebString("text/xhtml"); + string_attributes[ATTR_DOC_MIMETYPE] = WebKit::WebString("text/xhtml"); else - attributes[ATTR_DOC_MIMETYPE] = WebKit::WebString("text/html"); + string_attributes[ATTR_DOC_MIMETYPE] = WebKit::WebString("text/html"); const WebKit::WebDocumentType& doctype = document.doctype(); if (!doctype.isNull()) - attributes[ATTR_DOC_DOCTYPE] = doctype.name(); + string_attributes[ATTR_DOC_DOCTYPE] = doctype.name(); const gfx::Size& scroll_offset = document.frame()->scrollOffset(); - attributes[ATTR_DOC_SCROLLX] = base::IntToString16(scroll_offset.width()); - attributes[ATTR_DOC_SCROLLY] = base::IntToString16(scroll_offset.height()); + int_attributes[ATTR_DOC_SCROLLX] = scroll_offset.width(); + int_attributes[ATTR_DOC_SCROLLY] = scroll_offset.height(); + } + + if (role == WebAccessibility::ROLE_TABLE) { + int column_count = src.columnCount(); + int row_count = src.rowCount(); + if (column_count > 0 && row_count > 0) { + int_attributes[ATTR_TABLE_COLUMN_COUNT] = column_count; + int_attributes[ATTR_TABLE_ROW_COUNT] = row_count; + for (int i = 0; i < column_count * row_count; i++) { + WebAccessibilityObject cell = src.cellForColumnAndRow( + i % column_count, i / column_count); + int cell_id = -1; + if (!cell.isNull()) + cell_id = cache->addOrGetId(cell); + cell_ids.push_back(cell_id); + } + } + } + + if (role == WebAccessibility::ROLE_CELL || + role == WebAccessibility::ROLE_ROW_HEADER || + role == WebAccessibility::ROLE_COLUMN_HEADER) { + int_attributes[ATTR_TABLE_CELL_COLUMN_INDEX] = src.cellColumnIndex(); + int_attributes[ATTR_TABLE_CELL_COLUMN_SPAN] = src.cellColumnSpan(); + int_attributes[ATTR_TABLE_CELL_ROW_INDEX] = src.cellRowIndex(); + int_attributes[ATTR_TABLE_CELL_ROW_SPAN] = src.cellRowSpan(); } // Add the source object to the cache and store its id. diff --git a/webkit/glue/webaccessibility.h b/webkit/glue/webaccessibility.h index 6b2faaf..eb6350e 100644 --- a/webkit/glue/webaccessibility.h +++ b/webkit/glue/webaccessibility.h @@ -155,19 +155,12 @@ struct WebAccessibility { // Additional optional attributes that can be optionally attached to // a node. - enum Attribute { - // Doc attributes: only make sense when applied to the top-level - // Document node. + enum StringAttribute { + // Document attributes. ATTR_DOC_URL, ATTR_DOC_TITLE, ATTR_DOC_MIMETYPE, ATTR_DOC_DOCTYPE, - ATTR_DOC_SCROLLX, - ATTR_DOC_SCROLLY, - - // Editable text attributes - ATTR_TEXT_SEL_START, - ATTR_TEXT_SEL_END, // Attributes that could apply to any node. ATTR_ACTION, @@ -177,7 +170,29 @@ struct WebAccessibility { ATTR_HTML_TAG, ATTR_SHORTCUT, ATTR_URL, - NUM_ATTRIBUTES + NUM_STRING_ATTRIBUTES + }; + + enum IntAttribute { + // Document attributes. + ATTR_DOC_SCROLLX, + ATTR_DOC_SCROLLY, + + // Editable text attributes. + ATTR_TEXT_SEL_START, + ATTR_TEXT_SEL_END, + + // Table attributes. + ATTR_TABLE_ROW_COUNT, + ATTR_TABLE_COLUMN_COUNT, + + // Table cell attributes. + ATTR_TABLE_CELL_COLUMN_INDEX, + ATTR_TABLE_CELL_COLUMN_SPAN, + ATTR_TABLE_CELL_ROW_INDEX, + ATTR_TABLE_CELL_ROW_SPAN, + + NUM_INT_ATTRIBUTES }; // Empty constructor, for serialization. @@ -214,11 +229,13 @@ struct WebAccessibility { Role role; uint32 state; gfx::Rect location; - std::map<int32, string16> attributes; + std::map<StringAttribute, string16> string_attributes; + std::map<IntAttribute, int32> int_attributes; std::vector<WebAccessibility> children; std::vector<int32> indirect_child_ids; std::vector<std::pair<string16, string16> > html_attributes; std::vector<int32> line_breaks; + std::vector<int32> cell_ids; // For a table, the cell ids in row-major order. }; } // namespace webkit_glue |