diff options
author | nektar <nektar@chromium.org> | 2016-03-16 15:08:48 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-03-16 22:12:16 +0000 |
commit | 0eebf0cd114b70337c0ae3562786e538bd6aac9d (patch) | |
tree | 9781a9cfc4c2084d2fe1f80528095682e0b7857f | |
parent | df644193ff164f1d3df85d857f2b21b5ba51f77e (diff) | |
download | chromium_src-0eebf0cd114b70337c0ae3562786e538bd6aac9d.zip chromium_src-0eebf0cd114b70337c0ae3562786e538bd6aac9d.tar.gz chromium_src-0eebf0cd114b70337c0ae3562786e538bd6aac9d.tar.bz2 |
Implemented the reporting of text style and language information on Windows.
BUG=484228
TESTED=unit test, dump accessibility tree tests, manually with Jaws and NVDA screen readers
R=dmazzoni@chromium.org,aboxhall@chromium.org
Review URL: https://codereview.chromium.org/1768753003
Cr-Commit-Position: refs/heads/master@{#381560}
35 files changed, 914 insertions, 251 deletions
diff --git a/components/test_runner/web_ax_object_proxy.cc b/components/test_runner/web_ax_object_proxy.cc index 347da31..efc2574 100644 --- a/components/test_runner/web_ax_object_proxy.cc +++ b/components/test_runner/web_ax_object_proxy.cc @@ -517,6 +517,7 @@ WebAXObjectProxy::GetObjectTemplateBuilder(v8::Isolate* isolate) { .SetProperty("backgroundColor", &WebAXObjectProxy::BackgroundColor) .SetProperty("color", &WebAXObjectProxy::Color) .SetProperty("colorValue", &WebAXObjectProxy::ColorValue) + .SetProperty("fontFamily", &WebAXObjectProxy::FontFamily) .SetProperty("fontSize", &WebAXObjectProxy::FontSize) .SetProperty("orientation", &WebAXObjectProxy::Orientation) .SetProperty("posInSet", &WebAXObjectProxy::PosInSet) @@ -550,8 +551,7 @@ WebAXObjectProxy::GetObjectTemplateBuilder(v8::Isolate* isolate) { .SetMethod("cellForColumnAndRow", &WebAXObjectProxy::CellForColumnAndRow) .SetMethod("setSelectedTextRange", &WebAXObjectProxy::SetSelectedTextRange) - .SetMethod("setSelection", - &WebAXObjectProxy::SetSelection) + .SetMethod("setSelection", &WebAXObjectProxy::SetSelection) .SetMethod("isAttributeSettable", &WebAXObjectProxy::IsAttributeSettable) .SetMethod("isPressActionSupported", &WebAXObjectProxy::IsPressActionSupported) @@ -597,7 +597,6 @@ WebAXObjectProxy::GetObjectTemplateBuilder(v8::Isolate* isolate) { &WebAXObjectProxy::DescriptionElementCount) .SetMethod("descriptionElementAtIndex", &WebAXObjectProxy::DescriptionElementAtIndex); - } v8::Local<v8::Object> WebAXObjectProxy::GetChildAtIndex(unsigned index) { @@ -896,6 +895,12 @@ unsigned int WebAXObjectProxy::ColorValue() { return accessibility_object_.colorValue(); } +std::string WebAXObjectProxy::FontFamily() { + accessibility_object_.updateLayoutAndCheckValidity(); + std::string font_family(accessibility_object_.fontFamily().utf8()); + return font_family.insert(0, "AXFontFamily: "); +} + float WebAXObjectProxy::FontSize() { accessibility_object_.updateLayoutAndCheckValidity(); return accessibility_object_.fontSize(); diff --git a/components/test_runner/web_ax_object_proxy.h b/components/test_runner/web_ax_object_proxy.h index cc7853a..a90a713 100644 --- a/components/test_runner/web_ax_object_proxy.h +++ b/components/test_runner/web_ax_object_proxy.h @@ -111,6 +111,7 @@ class WebAXObjectProxy : public gin::Wrappable<WebAXObjectProxy> { unsigned int Color(); // For input elements of type color. unsigned int ColorValue(); + std::string FontFamily(); float FontSize(); std::string Orientation(); int PosInSet(); diff --git a/content/browser/accessibility/accessibility_tree_formatter_win.cc b/content/browser/accessibility/accessibility_tree_formatter_win.cc index c799846..acb299c 100644 --- a/content/browser/accessibility/accessibility_tree_formatter_win.cc +++ b/content/browser/accessibility/accessibility_tree_formatter_win.cc @@ -54,36 +54,35 @@ AccessibilityTreeFormatterWin::AccessibilityTreeFormatterWin() { AccessibilityTreeFormatterWin::~AccessibilityTreeFormatterWin() { } -const char* ALL_ATTRIBUTES[] = { - "name", - "value", - "states", - "attributes", - "role_name", - "ia2_hypertext", - "currentValue", - "minimumValue", - "maximumValue", - "description", - "default_action", - "keyboard_shortcut", - "location", - "size", - "index_in_parent", - "n_relations", - "group_level", - "similar_items_in_group", - "position_in_group", - "table_rows", - "table_columns", - "row_index", - "column_index", - "n_characters", - "caret_offset", - "n_selections", - "selection_start", - "selection_end" -}; +const char* ALL_ATTRIBUTES[] = {"name", + "value", + "states", + "attributes", + "text_attributes", + "role_name", + "ia2_hypertext", + "currentValue", + "minimumValue", + "maximumValue", + "description", + "default_action", + "keyboard_shortcut", + "location", + "size", + "index_in_parent", + "n_relations", + "group_level", + "similar_items_in_group", + "position_in_group", + "table_rows", + "table_columns", + "row_index", + "column_index", + "n_characters", + "caret_offset", + "n_selections", + "selection_start", + "selection_end"}; namespace { @@ -190,17 +189,29 @@ void AccessibilityTreeFormatterWin::AddProperties( IAccessibleStateToStringVector(ia_state, &state_strings); IAccessible2StateToStringVector(ax_object->ia2_state(), &state_strings); - base::ListValue* states = new base::ListValue; - for (const auto& state_string : state_strings) + scoped_ptr<base::ListValue> states(new base::ListValue()); + for (const base::string16& state_string : state_strings) states->AppendString(base::UTF16ToUTF8(state_string)); - dict->Set("states", states); + dict->Set("states", std::move(states)); const std::vector<base::string16>& ia2_attributes = ax_object->ia2_attributes(); - base::ListValue* attributes = new base::ListValue; - for (const auto& ia2_attribute : ia2_attributes) + scoped_ptr<base::ListValue> attributes(new base::ListValue()); + for (const base::string16& ia2_attribute : ia2_attributes) attributes->AppendString(base::UTF16ToUTF8(ia2_attribute)); - dict->Set("attributes", attributes); + dict->Set("attributes", std::move(attributes)); + + ax_object->ComputeStylesIfNeeded(); + const std::map<int, std::vector<base::string16>>& ia2_text_attributes = + ax_object->offset_to_text_attributes(); + scoped_ptr<base::ListValue> text_attributes(new base::ListValue()); + for (const auto& style_span : ia2_text_attributes) { + int start_offset = style_span.first; + text_attributes->AppendString("offset:" + base::IntToString(start_offset)); + for (const base::string16& text_attribute : style_span.second) + text_attributes->AppendString(base::UTF16ToUTF8(text_attribute)); + } + dict->Set("text_attributes", std::move(text_attributes)); dict->SetString("role_name", ax_object->role_name()); dict->SetString("ia2_hypertext", GetIA2Hypertext(*ax_object)); diff --git a/content/browser/accessibility/browser_accessibility.cc b/content/browser/accessibility/browser_accessibility.cc index b45b196..4afad6b 100644 --- a/content/browser/accessibility/browser_accessibility.cc +++ b/content/browser/accessibility/browser_accessibility.cc @@ -252,8 +252,9 @@ BrowserAccessibility* BrowserAccessibility::InternalGetChild( } BrowserAccessibility* BrowserAccessibility::GetParent() const { - if (!node_ || !manager_) - return NULL; + if (!instance_active()) + return nullptr; + ui::AXNode* parent = node_->parent(); if (parent) return manager_->GetFromAXNode(parent); @@ -384,8 +385,8 @@ gfx::Rect BrowserAccessibility::GetLocalBoundsForRange(int start, int len) int local_end = overlap_end - child_start; gfx::Rect child_rect = child->GetLocation(); - int text_direction = child->GetIntAttribute( - ui::AX_ATTR_TEXT_DIRECTION); + auto text_direction = static_cast<ui::AXTextDirection>( + child->GetIntAttribute(ui::AX_ATTR_TEXT_DIRECTION)); const std::vector<int32_t>& character_offsets = child->GetIntListAttribute(ui::AX_ATTR_CHARACTER_OFFSETS); int start_pixel_offset = @@ -657,6 +658,72 @@ bool BrowserAccessibility::GetFloatAttribute( return GetData().GetFloatAttribute(attribute, value); } +bool BrowserAccessibility::HasInheritedStringAttribute( + ui::AXStringAttribute attribute) const { + if (!instance_active()) + return false; + + if (GetData().HasStringAttribute(attribute)) + return true; + return GetParent() && GetParent()->HasInheritedStringAttribute(attribute); +} + +const std::string& BrowserAccessibility::GetInheritedStringAttribute( + ui::AXStringAttribute attribute) const { + if (!instance_active()) + return base::EmptyString(); + + const BrowserAccessibility* current_object = this; + do { + if (current_object->GetData().HasStringAttribute(attribute)) + return current_object->GetData().GetStringAttribute(attribute); + current_object = current_object->GetParent(); + } while (current_object); + return base::EmptyString(); +} + +bool BrowserAccessibility::GetInheritedStringAttribute( + ui::AXStringAttribute attribute, + std::string* value) const { + if (!instance_active()) { + *value = std::string(); + return false; + } + + if (GetData().GetStringAttribute(attribute, value)) + return true; + return GetParent() && + GetParent()->GetData().GetStringAttribute(attribute, value); +} + +base::string16 BrowserAccessibility::GetInheritedString16Attribute( + ui::AXStringAttribute attribute) const { + if (!instance_active()) + return base::string16(); + + const BrowserAccessibility* current_object = this; + do { + if (current_object->GetData().HasStringAttribute(attribute)) + return current_object->GetData().GetString16Attribute(attribute); + current_object = current_object->GetParent(); + } while (current_object); + return base::string16(); +} + +bool BrowserAccessibility::GetInheritedString16Attribute( + ui::AXStringAttribute attribute, + base::string16* value) const { + if (!instance_active()) { + *value = base::string16(); + return false; + } + + if (GetData().GetString16Attribute(attribute, value)) + return true; + return GetParent() && + GetParent()->GetData().GetString16Attribute(attribute, value); +} + bool BrowserAccessibility::HasIntAttribute( ui::AXIntAttribute attribute) const { return GetData().HasIntAttribute(attribute); @@ -691,9 +758,8 @@ base::string16 BrowserAccessibility::GetString16Attribute( return GetData().GetString16Attribute(attribute); } -bool BrowserAccessibility::GetString16Attribute( - ui::AXStringAttribute attribute, - base::string16* value) const { +bool BrowserAccessibility::GetString16Attribute(ui::AXStringAttribute attribute, + base::string16* value) const { return GetData().GetString16Attribute(attribute, value); } diff --git a/content/browser/accessibility/browser_accessibility.h b/content/browser/accessibility/browser_accessibility.h index ff17bc5..f93eea12 100644 --- a/content/browser/accessibility/browser_accessibility.h +++ b/content/browser/accessibility/browser_accessibility.h @@ -194,7 +194,7 @@ class CONTENT_EXPORT BrowserAccessibility { // BrowserAccessibilityManager* manager() const { return manager_; } - bool instance_active() const { return node_ != NULL; } + bool instance_active() const { return node_ && manager_; } ui::AXNode* node() const { return node_; } int32_t unique_id() const { return unique_id_; } @@ -246,6 +246,17 @@ class CONTENT_EXPORT BrowserAccessibility { float GetFloatAttribute(ui::AXFloatAttribute attr) const; bool GetFloatAttribute(ui::AXFloatAttribute attr, float* value) const; + bool HasInheritedStringAttribute(ui::AXStringAttribute attribute) const; + const std::string& GetInheritedStringAttribute( + ui::AXStringAttribute attribute) const; + bool GetInheritedStringAttribute(ui::AXStringAttribute attribute, + std::string* value) const; + + base::string16 GetInheritedString16Attribute( + ui::AXStringAttribute attribute) const; + bool GetInheritedString16Attribute(ui::AXStringAttribute attribute, + base::string16* value) const; + bool HasIntAttribute(ui::AXIntAttribute attribute) const; int GetIntAttribute(ui::AXIntAttribute attribute) const; bool GetIntAttribute(ui::AXIntAttribute attribute, int* value) const; @@ -256,10 +267,10 @@ class CONTENT_EXPORT BrowserAccessibility { bool GetStringAttribute(ui::AXStringAttribute attribute, std::string* value) const; - bool GetString16Attribute(ui::AXStringAttribute attribute, - base::string16* value) const; base::string16 GetString16Attribute( ui::AXStringAttribute attribute) const; + bool GetString16Attribute(ui::AXStringAttribute attribute, + base::string16* value) const; bool HasIntListAttribute(ui::AXIntListAttribute attribute) const; const std::vector<int32_t>& GetIntListAttribute( @@ -288,6 +299,8 @@ class CONTENT_EXPORT BrowserAccessibility { bool* is_defined, bool* is_mixed) const; + base::string16 GetFontFamily() const; + base::string16 GetLanguage() const; virtual base::string16 GetText() const; // Returns true if the bit corresponding to the given state enum is 1. diff --git a/content/browser/accessibility/browser_accessibility_android.cc b/content/browser/accessibility/browser_accessibility_android.cc index 8257c74..53df249 100644 --- a/content/browser/accessibility/browser_accessibility_android.cc +++ b/content/browser/accessibility/browser_accessibility_android.cc @@ -13,6 +13,7 @@ #include "content/browser/accessibility/browser_accessibility_manager_android.h" #include "content/common/accessibility_messages.h" #include "content/public/common/content_client.h" +#include "third_party/skia/include/core/SkColor.h" namespace { @@ -362,10 +363,11 @@ base::string16 BrowserAccessibilityAndroid::GetText() const { // For color wells, the color is stored in separate attributes. // Perhaps we could return color names in the future? if (GetRole() == ui::AX_ROLE_COLOR_WELL) { - int color = GetIntAttribute(ui::AX_ATTR_COLOR_VALUE); - int red = (color >> 16) & 0xFF; - int green = (color >> 8) & 0xFF; - int blue = color & 0xFF; + unsigned int color = + static_cast<unsigned int>(GetIntAttribute(ui::AX_ATTR_COLOR_VALUE)); + unsigned int red = SkColorGetR(color); + unsigned int green = SkColorGetG(color); + unsigned int blue = SkColorGetB(color); return base::UTF8ToUTF16( base::StringPrintf("#%02X%02X%02X", red, green, blue)); } diff --git a/content/browser/accessibility/browser_accessibility_cocoa.mm b/content/browser/accessibility/browser_accessibility_cocoa.mm index 0574c25..1ae72bd 100644 --- a/content/browser/accessibility/browser_accessibility_cocoa.mm +++ b/content/browser/accessibility/browser_accessibility_cocoa.mm @@ -21,6 +21,7 @@ #include "content/browser/accessibility/browser_accessibility_manager_mac.h" #include "content/browser/accessibility/one_shot_accessibility_tree_search.h" #include "content/public/common/content_client.h" +#include "third_party/skia/include/core/SkColor.h" #import "ui/accessibility/platform/ax_platform_node_mac.h" using content::AXTreeIDRegistry; @@ -1719,11 +1720,11 @@ bool InitializeAccessibilityTreeSearch( return [NSNumber numberWithFloat:floatValue]; } } else if ([role isEqualToString:NSAccessibilityColorWellRole]) { - int color = browserAccessibility_->GetIntAttribute( - ui::AX_ATTR_COLOR_VALUE); - int red = (color >> 16) & 0xFF; - int green = (color >> 8) & 0xFF; - int blue = color & 0xFF; + unsigned int color = static_cast<unsigned int>( + browserAccessibility_->GetIntAttribute(ui::AX_ATTR_COLOR_VALUE)); + unsigned int red = SkColorGetR(color); + unsigned int green = SkColorGetG(color); + unsigned int blue = SkColorGetB(color); // This string matches the one returned by a native Mac color well. return [NSString stringWithFormat:@"rgb %7.5f %7.5f %7.5f 1", red / 255., green / 255., blue / 255.]; diff --git a/content/browser/accessibility/browser_accessibility_win.cc b/content/browser/accessibility/browser_accessibility_win.cc index bf3b0af..03c199c 100644 --- a/content/browser/accessibility/browser_accessibility_win.cc +++ b/content/browser/accessibility/browser_accessibility_win.cc @@ -20,6 +20,7 @@ #include "content/browser/accessibility/browser_accessibility_state_impl.h" #include "content/common/accessibility_messages.h" #include "content/public/common/content_client.h" +#include "third_party/skia/include/core/SkColor.h" #include "ui/accessibility/ax_text_utils.h" #include "ui/base/win/accessibility_ids_win.h" #include "ui/base/win/accessibility_misc_utils.h" @@ -115,9 +116,8 @@ STDMETHODIMP BrowserAccessibilityRelation::get_nTargets(long* n_targets) { *n_targets = static_cast<long>(target_ids_.size()); - BrowserAccessibilityManager* manager = owner_->manager(); for (long i = *n_targets - 1; i >= 0; --i) { - BrowserAccessibility* result = manager->GetFromID(target_ids_[i]); + BrowserAccessibilityWin* result = owner_->GetFromID(target_ids_[i]); if (!result || !result->instance_active()) { *n_targets = 0; break; @@ -139,9 +139,7 @@ STDMETHODIMP BrowserAccessibilityRelation::get_target(long target_index, return E_INVALIDARG; } - BrowserAccessibilityManager* manager = owner_->manager(); - BrowserAccessibility* result = - manager->GetFromID(target_ids_[target_index]); + BrowserAccessibility* result = owner_->GetFromID(target_ids_[target_index]); if (!result || !result->instance_active()) return E_FAIL; @@ -576,14 +574,15 @@ STDMETHODIMP BrowserAccessibilityWin::get_accValue(VARIANT var_id, // Expose color well value. if (target->ia2_role() == IA2_ROLE_COLOR_CHOOSER) { - int color = target->GetIntAttribute(ui::AX_ATTR_COLOR_VALUE); - int red = (color >> 16) & 0xFF; - int green = (color >> 8) & 0xFF; - int blue = color & 0xFF; + unsigned int color = static_cast<unsigned int>( + target->GetIntAttribute(ui::AX_ATTR_COLOR_VALUE)); + unsigned int red = SkColorGetR(color); + unsigned int green = SkColorGetG(color); + unsigned int blue = SkColorGetB(color); base::string16 value_text; - value_text = base::IntToString16((red * 100) / 255) + L"% red " + - base::IntToString16((green * 100) / 255) + L"% green " + - base::IntToString16((blue * 100) / 255) + L"% blue"; + value_text = base::UintToString16(red * 100 / 255) + L"% red " + + base::UintToString16(green * 100 / 255) + L"% green " + + base::UintToString16(blue * 100 / 255) + L"% blue"; *value = SysAllocString(value_text.c_str()); DCHECK(*value); return S_OK; @@ -687,19 +686,16 @@ STDMETHODIMP BrowserAccessibilityWin::role(LONG* role) { } STDMETHODIMP BrowserAccessibilityWin::get_attributes(BSTR* attributes) { - if (!instance_active()) - return E_FAIL; - if (!attributes) return E_INVALIDARG; + *attributes = nullptr; + + if (!instance_active()) + return E_FAIL; - // The iaccessible2 attributes are a set of key-value pairs - // separated by semicolons, with a colon between the key and the value. base::string16 str; - const std::vector<base::string16>& attributes_list = ia2_attributes(); - for (unsigned int i = 0; i < attributes_list.size(); ++i) { - str += attributes_list[i] + L';'; - } + for (const base::string16& attribute : ia2_attributes()) + str += attribute + L';'; if (str.empty()) return S_FALSE; @@ -847,7 +843,6 @@ STDMETHODIMP BrowserAccessibilityWin::scrollTo(IA2ScrollType scroll_type) { } manager()->ToBrowserAccessibilityManagerWin()->TrackScrollingObject(this); - return S_OK; } @@ -1181,8 +1176,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_columnDescription(long column, GetIntListAttribute(ui::AX_ATTR_CELL_IDS); for (int i = 0; i < rows; ++i) { int cell_id = cell_ids[i * columns + column]; - BrowserAccessibilityWin* cell = static_cast<BrowserAccessibilityWin*>( - manager()->GetFromID(cell_id)); + BrowserAccessibilityWin* cell = GetFromID(cell_id); if (cell && cell->GetRole() == ui::AX_ROLE_COLUMN_HEADER) { base::string16 cell_name = cell->GetString16Attribute( ui::AX_ATTR_NAME); @@ -1227,8 +1221,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_columnExtentAt( const std::vector<int32_t>& cell_ids = GetIntListAttribute(ui::AX_ATTR_CELL_IDS); int cell_id = cell_ids[row * columns + column]; - BrowserAccessibilityWin* cell = static_cast<BrowserAccessibilityWin*>( - manager()->GetFromID(cell_id)); + BrowserAccessibilityWin* cell = GetFromID(cell_id); int colspan; if (cell && cell->GetIntAttribute( @@ -1265,8 +1258,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_columnIndex(long cell_index, return S_FALSE; int cell_id = unique_cell_ids[cell_index]; - BrowserAccessibilityWin* cell = - ToBrowserAccessibilityWin(manager()->GetFromID(cell_id)); + BrowserAccessibilityWin* cell = GetFromID(cell_id); int col_index; if (cell && cell->GetIntAttribute( @@ -1370,8 +1362,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_rowDescription(long row, GetIntListAttribute(ui::AX_ATTR_CELL_IDS); for (int i = 0; i < columns; ++i) { int cell_id = cell_ids[row * columns + i]; - BrowserAccessibilityWin* cell = - ToBrowserAccessibilityWin(manager()->GetFromID(cell_id)); + BrowserAccessibilityWin* cell = GetFromID(cell_id); if (cell && cell->GetRole() == ui::AX_ROLE_ROW_HEADER) { base::string16 cell_name = cell->GetString16Attribute( ui::AX_ATTR_NAME); @@ -1415,8 +1406,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_rowExtentAt(long row, const std::vector<int32_t>& cell_ids = GetIntListAttribute(ui::AX_ATTR_CELL_IDS); int cell_id = cell_ids[row * columns + column]; - BrowserAccessibilityWin* cell = - ToBrowserAccessibilityWin(manager()->GetFromID(cell_id)); + BrowserAccessibilityWin* cell = GetFromID(cell_id); int rowspan; if (cell && cell->GetIntAttribute( @@ -1453,8 +1443,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_rowIndex(long cell_index, return S_FALSE; int cell_id = unique_cell_ids[cell_index]; - BrowserAccessibilityWin* cell = - ToBrowserAccessibilityWin(manager()->GetFromID(cell_id)); + BrowserAccessibilityWin* cell = GetFromID(cell_id); int cell_row_index; if (cell && cell->GetIntAttribute( @@ -1582,8 +1571,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_rowColumnExtentsAtIndex( return S_FALSE; int cell_id = unique_cell_ids[index]; - BrowserAccessibilityWin* cell = - ToBrowserAccessibilityWin(manager()->GetFromID(cell_id)); + BrowserAccessibilityWin* cell = GetFromID(cell_id); int rowspan; int colspan; if (cell && @@ -1741,8 +1729,7 @@ STDMETHODIMP BrowserAccessibilityWin::get_columnHeaderCells( for (int i = 0; i < rows; ++i) { int cell_id = cell_ids[i * columns + column]; - BrowserAccessibilityWin* cell = - ToBrowserAccessibilityWin(manager()->GetFromID(cell_id)); + BrowserAccessibilityWin* cell = GetFromID(cell_id); if (cell && cell->GetRole() == ui::AX_ROLE_COLUMN_HEADER) (*n_column_header_cells)++; } @@ -2349,15 +2336,40 @@ STDMETHODIMP BrowserAccessibilityWin::setSelection(LONG selection_index, return S_OK; } -// -// IAccessibleText methods not implemented. -// - STDMETHODIMP BrowserAccessibilityWin::get_attributes(LONG offset, LONG* start_offset, LONG* end_offset, BSTR* text_attributes) { - return E_NOTIMPL; + if (!start_offset || !end_offset || !text_attributes) + return E_INVALIDARG; + + *start_offset = *end_offset = 0; + *text_attributes = nullptr; + if (!instance_active()) + return E_FAIL; + + const base::string16& text = GetText(); + HandleSpecialTextOffset(text, &offset); + if (offset < 0 || offset > static_cast<LONG>(text.size())) + return E_INVALIDARG; + + ComputeStylesIfNeeded(); + *start_offset = FindStartOfStyle(offset, ui::BACKWARDS_DIRECTION); + *end_offset = FindStartOfStyle(offset, ui::FORWARDS_DIRECTION); + + base::string16 attributes_str; + const std::vector<base::string16>& attributes = + offset_to_text_attributes().find(*start_offset)->second; + for (const base::string16& attribute : attributes) { + attributes_str += attribute + L';'; + } + + if (attributes.empty()) + return S_FALSE; + + *text_attributes = SysAllocString(attributes_str.c_str()); + DCHECK(*text_attributes); + return S_OK; } // @@ -2388,14 +2400,12 @@ STDMETHODIMP BrowserAccessibilityWin::get_hyperlink( } int32_t id = hyperlinks()[index]; - BrowserAccessibilityWin* child = - ToBrowserAccessibilityWin(manager()->GetFromID(id)); - if (child) { - *hyperlink = static_cast<IAccessibleHyperlink*>(child->NewReference()); - return S_OK; - } + BrowserAccessibilityWin* link = GetFromID(id); + if (!link) + return E_FAIL; - return E_FAIL; + *hyperlink = static_cast<IAccessibleHyperlink*>(link->NewReference()); + return S_OK; } STDMETHODIMP BrowserAccessibilityWin::get_hyperlinkIndex( @@ -2973,7 +2983,20 @@ BrowserAccessibilityWin::get_localInterface(void** local_interface) { } STDMETHODIMP BrowserAccessibilityWin::get_language(BSTR* language) { - return E_NOTIMPL; + if (!language) + return E_INVALIDARG; + *language = nullptr; + + if (!instance_active()) + return E_FAIL; + + base::string16 lang = GetInheritedString16Attribute(ui::AX_ATTR_LANGUAGE); + if (lang.empty()) + lang = L"en-US"; + + *language = SysAllocString(lang.c_str()); + DCHECK(*language); + return S_OK; } // @@ -3052,7 +3075,21 @@ STDMETHODIMP BrowserAccessibilityWin::scrollToSubstring( } STDMETHODIMP BrowserAccessibilityWin::get_fontFamily(BSTR* font_family) { - return E_NOTIMPL; + if (!font_family) + return E_INVALIDARG; + *font_family = nullptr; + + if (!instance_active()) + return E_FAIL; + + base::string16 family = + GetInheritedString16Attribute(ui::AX_ATTR_FONT_FAMILY); + if (family.empty()) + return S_FALSE; + + *font_family = SysAllocString(family.c_str()); + DCHECK(*font_family); + return S_OK; } // @@ -3233,6 +3270,45 @@ HRESULT WINAPI BrowserAccessibilityWin::InternalQueryInterface( this_ptr, entries, iid, object); } +void BrowserAccessibilityWin::ComputeStylesIfNeeded() { + if (!offset_to_text_attributes().empty()) + return; + + std::map<int, std::vector<base::string16>> attributes_map; + if (PlatformIsLeaf()) { + attributes_map[0] = ComputeTextAttributes(); + win_attributes_->offset_to_text_attributes.swap(attributes_map); + return; + } + + int start_offset = 0; + for (size_t i = 0; i < PlatformChildCount(); ++i) { + const auto child = ToBrowserAccessibilityWin(PlatformGetChild(i)); + DCHECK(child); + std::vector<base::string16> attributes(child->ComputeTextAttributes()); + + if (attributes_map.empty()) { + attributes_map[start_offset] = attributes; + } else { + // Only add the attributes for this child if we are at the start of a new + // style span. + std::vector<base::string16> previous_attributes = + attributes_map.rbegin()->second; + if (!std::equal(attributes.begin(), attributes.end(), + previous_attributes.begin())) { + attributes_map[start_offset] = attributes; + } + } + + if (child->IsTextOnlyObject()) + start_offset += child->GetText().length(); + else + start_offset += 1; + } + + win_attributes_->offset_to_text_attributes.swap(attributes_map); +} + base::string16 BrowserAccessibilityWin::GetText() const { if (PlatformIsChildOfLeaf()) return BrowserAccessibility::GetText(); @@ -3317,44 +3393,6 @@ void BrowserAccessibilityWin::UpdateStep1ComputeWinAttributes() { } } - // Expose invalid state for form controls and elements with aria-invalid. - int invalid_state; - if (GetIntAttribute(ui::AX_ATTR_INVALID_STATE, &invalid_state)) { - // TODO(nektar): Handle the possibility of having multiple aria-invalid - // attributes defined, e.g., "invalid:spelling,grammar". - switch (invalid_state) { - case ui::AX_INVALID_STATE_FALSE: - win_attributes_->ia2_attributes.push_back(L"invalid:false"); - break; - case ui::AX_INVALID_STATE_TRUE: - win_attributes_->ia2_attributes.push_back(L"invalid:true"); - break; - case ui::AX_INVALID_STATE_SPELLING: - win_attributes_->ia2_attributes.push_back(L"invalid:spelling"); - break; - case ui::AX_INVALID_STATE_GRAMMAR: - win_attributes_->ia2_attributes.push_back(L"invalid:grammar"); - break; - case ui::AX_INVALID_STATE_OTHER: - { - base::string16 aria_invalid_value; - if (GetString16Attribute(ui::AX_ATTR_ARIA_INVALID_VALUE, - &aria_invalid_value)) { - SanitizeStringAttributeForIA2(aria_invalid_value, - &aria_invalid_value); - win_attributes_->ia2_attributes.push_back( - L"invalid:" + aria_invalid_value); - } else { - // Set the attribute to L"true", since we cannot be more specific. - win_attributes_->ia2_attributes.push_back(L"invalid:true"); - } - } - break; - default: - NOTREACHED(); - } - } - // Expose row or column header sort direction. int32_t sort_direction; if ((ia_role() == ROLE_SYSTEM_COLUMNHEADER || @@ -3434,8 +3472,7 @@ void BrowserAccessibilityWin::UpdateStep2ComputeHypertext() { // the character index of each embedded object character to the id of the // child object it points to. for (unsigned int i = 0; i < PlatformChildCount(); ++i) { - BrowserAccessibilityWin* child = - ToBrowserAccessibilityWin(PlatformGetChild(i)); + const auto child = ToBrowserAccessibilityWin(PlatformGetChild(i)); DCHECK(child); // Similar to Firefox, we don't expose text-only objects in IA2 hypertext. if (child->IsTextOnlyObject()) { @@ -3573,6 +3610,182 @@ void BrowserAccessibilityWin::OnLocationChanged() { EVENT_OBJECT_LOCATIONCHANGE, this); } +std::vector<base::string16> BrowserAccessibilityWin::ComputeTextAttributes() + const { + std::vector<base::string16> attributes; + + // We include list markers for now, but there might be other objects that are + // auto generated. + // TODO(nektar): Compute what objects are auto-generated in Blink. + if (GetRole() == ui::AX_ROLE_LIST_MARKER) + attributes.push_back(L"auto-generated:true"); + else + attributes.push_back(L"auto-generated:false"); + + int color; + base::string16 color_value(L"transparent"); + if (GetIntAttribute(ui::AX_ATTR_BACKGROUND_COLOR, &color)) { + unsigned int alpha = SkColorGetA(color); + unsigned int red = SkColorGetR(color); + unsigned int green = SkColorGetG(color); + unsigned int blue = SkColorGetB(color); + if (alpha) { + color_value = L"rgb(" + base::UintToString16(red) + L',' + + base::UintToString16(green) + L',' + + base::UintToString16(blue) + L')'; + } + } + SanitizeStringAttributeForIA2(color_value, &color_value); + attributes.push_back(L"background-color:" + color_value); + + if (GetIntAttribute(ui::AX_ATTR_COLOR, &color)) { + unsigned int red = SkColorGetR(color); + unsigned int green = SkColorGetG(color); + unsigned int blue = SkColorGetB(color); + color_value = L"rgb(" + base::UintToString16(red) + L',' + + base::UintToString16(green) + L',' + + base::UintToString16(blue) + L')'; + } else { + color_value = L"rgb(0,0,0)"; + } + SanitizeStringAttributeForIA2(color_value, &color_value); + attributes.push_back(L"color:" + color_value); + + base::string16 font_family( + GetInheritedString16Attribute(ui::AX_ATTR_FONT_FAMILY)); + // Attribute has no default value. + if (!font_family.empty()) { + SanitizeStringAttributeForIA2(font_family, &font_family); + attributes.push_back(L"font-family:" + font_family); + } + + float font_size; + // Attribute has no default value. + if (GetFloatAttribute(ui::AX_ATTR_FONT_SIZE, &font_size)) { + // The IA2 Spec requires the value to be in pt, not in pixels. + // There are 72 points per inch. + // We assume that there are 96 pixels per inch on a standard display. + // TODO(nektar): Figure out the current value of pixels per inch. + float points = font_size * 72.0 / 96.0; + attributes.push_back(L"font-size:" + + base::UTF8ToUTF16(base::DoubleToString(points)) + + L"pt"); + } + + auto text_style = + static_cast<ui::AXTextStyle>(GetIntAttribute(ui::AX_ATTR_TEXT_STYLE)); + if (text_style == ui::AX_TEXT_STYLE_NONE) { + attributes.push_back(L"font-style:normal"); + attributes.push_back(L"font-weight:normal"); + } else { + if (text_style & ui::AX_TEXT_STYLE_BOLD) + attributes.push_back(L"font-weight:bold"); + + base::string16 font_style; + if (text_style & ui::AX_TEXT_STYLE_ITALIC) + font_style += L",italic"; + if (text_style & ui::AX_TEXT_STYLE_UNDERLINE) + font_style += L",underline"; + if (text_style & ui::AX_TEXT_STYLE_LINE_THROUGH) + font_style += L",line-through"; + // TODO(nektar): Support more font style attributes in Blink. + + if (font_style.empty()) { + font_style = L"normal"; + } else { + // Remove the leading comma. + font_style.erase(0, 1); + } + attributes.push_back(L"font-style:" + font_style); + } + + auto invalid_state = static_cast<ui::AXInvalidState>( + GetIntAttribute(ui::AX_ATTR_INVALID_STATE)); + switch (invalid_state) { + case ui::AX_INVALID_STATE_NONE: + case ui::AX_INVALID_STATE_FALSE: + attributes.push_back(L"invalid:false"); + break; + case ui::AX_INVALID_STATE_TRUE: + attributes.push_back(L"invalid:true"); + break; + case ui::AX_INVALID_STATE_SPELLING: + case ui::AX_INVALID_STATE_GRAMMAR: { + base::string16 spelling_grammar_value; + if (invalid_state & ui::AX_INVALID_STATE_SPELLING) + spelling_grammar_value = L"spelling"; + else if (invalid_state & ui::AX_INVALID_STATE_GRAMMAR) + spelling_grammar_value = L"grammar"; + else + spelling_grammar_value = L"spelling,grammar"; + attributes.push_back(L"invalid:" + spelling_grammar_value); + break; + } + case ui::AX_INVALID_STATE_OTHER: { + base::string16 aria_invalid_value; + if (GetString16Attribute(ui::AX_ATTR_ARIA_INVALID_VALUE, + &aria_invalid_value)) { + SanitizeStringAttributeForIA2(aria_invalid_value, &aria_invalid_value); + attributes.push_back(L"invalid:" + aria_invalid_value); + } else { + // Set the attribute to L"true", since we cannot be more specific. + attributes.push_back(L"invalid:true"); + } + break; + } + default: + NOTREACHED(); + } + + base::string16 language(GetInheritedString16Attribute(ui::AX_ATTR_LANGUAGE)); + // Default value should be L"en-US". + if (language.empty()) { + attributes.push_back(L"language:en-US"); + } else { + SanitizeStringAttributeForIA2(language, &language); + attributes.push_back(L"language:" + language); + } + + // TODO(nektar): Add Blink support for the following attributes. + // Currently set to their default values as dictated by the IA2 Spec. + attributes.push_back(L"text-line-through-mode:continuous"); + attributes.push_back(L"text-line-through-style:none"); + // Default value must be the empty string. + attributes.push_back(L"text-line-through-text:"); + attributes.push_back(L"text-line-through-type:none"); + attributes.push_back(L"text-line-through-width:auto"); + attributes.push_back(L"text-outline:false"); + attributes.push_back(L"text-position:baseline"); + attributes.push_back(L"text-shadow:none"); + attributes.push_back(L"text-underline-mode:continuous"); + attributes.push_back(L"text-underline-style:none"); + attributes.push_back(L"text-underline-type:none"); + attributes.push_back(L"text-underline-width:auto"); + + auto text_direction = static_cast<ui::AXTextDirection>( + GetIntAttribute(ui::AX_ATTR_TEXT_DIRECTION)); + switch (text_direction) { + case ui::AX_TEXT_DIRECTION_NONE: + case ui::AX_TEXT_DIRECTION_LTR: + attributes.push_back(L"writing-mode:lr"); + break; + case ui::AX_TEXT_DIRECTION_RTL: + attributes.push_back(L"writing-mode:rl"); + break; + case ui::AX_TEXT_DIRECTION_TTB: + attributes.push_back(L"writing-mode:tb"); + break; + case ui::AX_TEXT_DIRECTION_BTT: + // Not listed in the IA2 Spec. + attributes.push_back(L"writing-mode:bt"); + break; + default: + NOTREACHED(); + } + + return attributes; +} + BrowserAccessibilityWin* BrowserAccessibilityWin::NewReference() { AddRef(); return this; @@ -3672,6 +3885,23 @@ bool BrowserAccessibilityWin::IsHyperlink() const { return false; } +BrowserAccessibilityWin* +BrowserAccessibilityWin::GetHyperlinkFromHypertextOffset(int offset) const { + std::map<int32_t, int32_t>::iterator iterator = + hyperlink_offset_to_index().find(offset); + if (iterator == hyperlink_offset_to_index().end()) + return nullptr; + + int32_t index = iterator->second; + DCHECK_GE(index, 0); + DCHECK_LT(index, static_cast<int32_t>(hyperlinks().size())); + int32_t id = hyperlinks()[index]; + BrowserAccessibilityWin* hyperlink = GetFromID(id); + if (!hyperlink) + return nullptr; + return hyperlink; +} + int32_t BrowserAccessibilityWin::GetHyperlinkIndexFromChild( const BrowserAccessibilityWin& child) const { if (hyperlinks().empty()) @@ -3815,8 +4045,7 @@ int BrowserAccessibilityWin::GetHypertextOffsetFromEndpoint( int BrowserAccessibilityWin::GetSelectionAnchor() const { int32_t anchor_id = manager()->GetTreeData().sel_anchor_object_id; - const auto anchor_object = - ToBrowserAccessibilityWin(manager()->GetFromID(anchor_id)); + const BrowserAccessibilityWin* anchor_object = GetFromID(anchor_id); if (!anchor_object) return -1; @@ -3826,8 +4055,7 @@ int BrowserAccessibilityWin::GetSelectionAnchor() const { int BrowserAccessibilityWin::GetSelectionFocus() const { int32_t focus_id = manager()->GetTreeData().sel_focus_object_id; - const auto focus_object = - ToBrowserAccessibilityWin(manager()->GetFromID(focus_id)); + const BrowserAccessibilityWin* focus_object = GetFromID(focus_id); if (!focus_object) return -1; @@ -3877,22 +4105,13 @@ void BrowserAccessibilityWin::GetSelectionOffsets( // the selection. int* largest_offset = (*selection_start <= *selection_end) ? selection_end : selection_start; - auto current_object = const_cast<BrowserAccessibilityWin*>(this); - LONG hyperlink_index; - HRESULT hr = - current_object->get_hyperlinkIndex(*largest_offset, &hyperlink_index); - if (hr != S_OK) + BrowserAccessibilityWin* hyperlink = + GetHyperlinkFromHypertextOffset(*largest_offset); + if (!hyperlink) return; - DCHECK_GE(hyperlink_index, 0); - base::win::ScopedComPtr<IAccessibleHyperlink> hyperlink; - hr = current_object->get_hyperlink(hyperlink_index, hyperlink.Receive()); - DCHECK(SUCCEEDED(hr)); - base::win::ScopedComPtr<IAccessibleText> hyperlink_text; - hr = hyperlink.QueryInterface(hyperlink_text.Receive()); - DCHECK(SUCCEEDED(hr)); LONG n_selections = 0; - hr = hyperlink_text->get_nSelections(&n_selections); + HRESULT hr = hyperlink->get_nSelections(&n_selections); DCHECK(SUCCEEDED(hr)); if (n_selections > 0) ++(*largest_offset); @@ -4024,7 +4243,39 @@ LONG BrowserAccessibilityWin::FindBoundary( text, line_breaks, boundary, start_offset, direction); } -BrowserAccessibilityWin* BrowserAccessibilityWin::GetFromID(int32_t id) { +LONG BrowserAccessibilityWin::FindStartOfStyle( + LONG start_offset, + ui::TextBoundaryDirection direction) const { + LONG text_length = static_cast<LONG>(GetText().length()); + DCHECK_GE(start_offset, 0); + DCHECK_LE(start_offset, text_length); + + switch (direction) { + case ui::BACKWARDS_DIRECTION: { + if (offset_to_text_attributes().empty()) + return 0; + + auto iterator = offset_to_text_attributes().upper_bound(start_offset); + --iterator; + return static_cast<LONG>(iterator->first); + } + case ui::FORWARDS_DIRECTION: { + const auto iterator = + offset_to_text_attributes().upper_bound(start_offset); + if (iterator == offset_to_text_attributes().end()) + return text_length; + return static_cast<LONG>(iterator->first); + } + default: + NOTREACHED(); + } + + return start_offset; +} + +BrowserAccessibilityWin* BrowserAccessibilityWin::GetFromID(int32_t id) const { + if (!instance_active()) + return nullptr; return ToBrowserAccessibilityWin(manager()->GetFromID(id)); } @@ -4048,6 +4299,25 @@ bool BrowserAccessibilityWin::IsListBoxOptionOrMenuListOption() { return false; } +void BrowserAccessibilityWin::AddRelations( + ui::AXIntListAttribute src_attr, + const base::string16& iaccessiblerelation_type) { + if (!HasIntListAttribute(src_attr)) + return; + + const std::vector<int32_t>& ids = GetIntListAttribute(src_attr); + for (size_t i = 0; i < ids.size(); ++i) { + CComObject<BrowserAccessibilityRelation>* relation; + HRESULT hr = + CComObject<BrowserAccessibilityRelation>::CreateInstance(&relation); + DCHECK(SUCCEEDED(hr)); + relation->AddRef(); + relation->Initialize(this, iaccessiblerelation_type); + relation->AddTarget(ids[i]); + relations_.push_back(relation); + } +} + void BrowserAccessibilityWin::UpdateRequiredAttributes() { // Expose slider value. if (ia_role() == ROLE_SYSTEM_PROGRESSBAR || @@ -4111,25 +4381,6 @@ void BrowserAccessibilityWin::UpdateRequiredAttributes() { } } -void BrowserAccessibilityWin::AddRelations( - ui::AXIntListAttribute src_attr, - const base::string16& iaccessiblerelation_type) { - if (!HasIntListAttribute(src_attr)) - return; - - const std::vector<int32_t>& ids = GetIntListAttribute(src_attr); - for (size_t i = 0; i < ids.size(); ++i) { - CComObject<BrowserAccessibilityRelation>* relation; - HRESULT hr = CComObject<BrowserAccessibilityRelation>::CreateInstance( - &relation); - DCHECK(SUCCEEDED(hr)); - relation->AddRef(); - relation->Initialize(this, iaccessiblerelation_type); - relation->AddTarget(ids[i]); - relations_.push_back(relation); - } -} - void BrowserAccessibilityWin::InitRoleAndState() { int32_t ia_role = 0; int32_t ia_state = 0; diff --git a/content/browser/accessibility/browser_accessibility_win.h b/content/browser/accessibility/browser_accessibility_win.h index b237be9..82e03ca 100644 --- a/content/browser/accessibility/browser_accessibility_win.h +++ b/content/browser/accessibility/browser_accessibility_win.h @@ -709,6 +709,10 @@ BrowserAccessibilityWin REFIID iid, void** object); + // Computes and caches the IA2 text style attributes for the text and other + // embedded child objects. + CONTENT_EXPORT void ComputeStylesIfNeeded(); + CONTENT_EXPORT base::string16 GetText() const override; // Accessors. @@ -723,6 +727,10 @@ BrowserAccessibilityWin base::string16 name() const { return win_attributes_->name; } base::string16 description() const { return win_attributes_->description; } base::string16 value() const { return win_attributes_->value; } + const std::map<int, std::vector<base::string16>>& offset_to_text_attributes() + const { + return win_attributes_->offset_to_text_attributes; + } std::map<int32_t, int32_t>& hyperlink_offset_to_index() const { return win_attributes_->hyperlink_offset_to_index; } @@ -731,6 +739,9 @@ BrowserAccessibilityWin } private: + // Returns the IA2 text attributes for this object. + std::vector<base::string16> ComputeTextAttributes() const; + // Add one to the reference count and return the same object. Always // use this method when returning a BrowserAccessibilityWin object as // an output parameter to a COM interface, never use it otherwise. @@ -786,6 +797,9 @@ BrowserAccessibilityWin // Returns true if the current object is an IA2 hyperlink. bool IsHyperlink() const; + // Returns the hyperlink at the given text position, or nullptr if no + // hyperlink can be found. + BrowserAccessibilityWin* GetHyperlinkFromHypertextOffset(int offset) const; // Functions for retrieving offsets for hyperlinks and hypertext. // Return -1 in case of failure. @@ -847,22 +861,32 @@ BrowserAccessibilityWin LONG start_offset, ui::TextBoundaryDirection direction); - // Return a pointer to the object corresponding to the given id, - // does not make a new reference. - BrowserAccessibilityWin* GetFromID(int32_t id); + // Searches forward from the given offset until the start of the next style + // is found, or searches backward from the given offset until the start of the + // current style is found. + LONG FindStartOfStyle(LONG start_offset, + ui::TextBoundaryDirection direction) const; + + // ID refers to the node ID in the current tree, not the globally unique ID. + // TODO(nektar): Could we use globally unique IDs everywhere? + // TODO(nektar): Rename this function to GetFromNodeID. + BrowserAccessibilityWin* GetFromID(int32_t id) const; // Returns true if this is a list box option with a parent of type list box, // or a menu list option with a parent of type menu list popup. bool IsListBoxOptionOrMenuListOption(); - // Updates object attributes of IA2 with html attributes. - void UpdateRequiredAttributes(); - // Given an int list attribute containing the ids of related elements, // add a new IAccessibleRelation for this object with the given type name. void AddRelations(ui::AXIntListAttribute src_attr, const base::string16& iaccessiblerelation_type); + // Updates object attributes of IA2 with html attributes. + void UpdateRequiredAttributes(); + + // Updates the IA2 text style attributes. + void UpdateTextAttributes(); + struct WinAttributes { WinAttributes(); ~WinAttributes(); @@ -887,6 +911,9 @@ BrowserAccessibilityWin // Hypertext. base::string16 hypertext; + // Maps each style span to its start offset in hypertext. + std::map<int, std::vector<base::string16>> offset_to_text_attributes; + // Maps the |hypertext_| embedded character offset to an index in // |hyperlinks_|. std::map<int32_t, int32_t> hyperlink_offset_to_index; diff --git a/content/browser/accessibility/browser_accessibility_win_unittest.cc b/content/browser/accessibility/browser_accessibility_win_unittest.cc index b8b3e77..780d0f4 100644 --- a/content/browser/accessibility/browser_accessibility_win_unittest.cc +++ b/content/browser/accessibility/browser_accessibility_win_unittest.cc @@ -1793,6 +1793,121 @@ TEST_F(BrowserAccessibilityTest, TestDeepestFirstLastChild) { EXPECT_EQ(nullptr, child2_child2_accessible->InternalDeepestLastChild()); } +TEST_F(BrowserAccessibilityTest, TestInheritedStringAttributes) { + ui::AXNodeData root; + root.id = 1; + root.role = ui::AX_ROLE_ROOT_WEB_AREA; + root.AddStringAttribute(ui::AX_ATTR_LANGUAGE, "en-US"); + root.AddStringAttribute(ui::AX_ATTR_FONT_FAMILY, "Helvetica"); + + ui::AXNodeData child1; + child1.id = 2; + child1.role = ui::AX_ROLE_STATIC_TEXT; + root.child_ids.push_back(2); + + ui::AXNodeData child2; + child2.id = 3; + child2.role = ui::AX_ROLE_STATIC_TEXT; + child2.AddStringAttribute(ui::AX_ATTR_LANGUAGE, "fr"); + child2.AddStringAttribute(ui::AX_ATTR_FONT_FAMILY, "Arial"); + root.child_ids.push_back(3); + + ui::AXNodeData child2_child1; + child2_child1.id = 4; + child2_child1.role = ui::AX_ROLE_INLINE_TEXT_BOX; + child2.child_ids.push_back(4); + + ui::AXNodeData child2_child2; + child2_child2.id = 5; + child2_child2.role = ui::AX_ROLE_INLINE_TEXT_BOX; + child2.child_ids.push_back(5); + + scoped_ptr<BrowserAccessibilityManager> manager( + BrowserAccessibilityManager::Create( + MakeAXTreeUpdate(root, child1, child2, child2_child1, child2_child2), + nullptr, new CountedBrowserAccessibilityFactory())); + + BrowserAccessibility* root_accessible = manager->GetRoot(); + ASSERT_NE(nullptr, root_accessible); + BrowserAccessibility* child1_accessible = + root_accessible->PlatformGetChild(0); + ASSERT_NE(nullptr, child1_accessible); + BrowserAccessibility* child2_accessible = + root_accessible->PlatformGetChild(1); + ASSERT_NE(nullptr, child2_accessible); + BrowserAccessibility* child2_child1_accessible = + child2_accessible->InternalGetChild(0); + ASSERT_NE(nullptr, child2_child1_accessible); + BrowserAccessibility* child2_child2_accessible = + child2_accessible->InternalGetChild(1); + ASSERT_NE(nullptr, child2_child2_accessible); + + // Test GetInheritedString16Attribute(attribute). + EXPECT_EQ( + base::UTF8ToUTF16("en-US"), + root_accessible->GetInheritedString16Attribute(ui::AX_ATTR_LANGUAGE)); + EXPECT_EQ( + base::UTF8ToUTF16("en-US"), + child1_accessible->GetInheritedString16Attribute(ui::AX_ATTR_LANGUAGE)); + EXPECT_EQ( + base::UTF8ToUTF16("fr"), + child2_accessible->GetInheritedString16Attribute(ui::AX_ATTR_LANGUAGE)); + EXPECT_EQ(base::UTF8ToUTF16("fr"), + child2_child1_accessible->GetInheritedString16Attribute( + ui::AX_ATTR_LANGUAGE)); + EXPECT_EQ(base::UTF8ToUTF16("fr"), + child2_child2_accessible->GetInheritedString16Attribute( + ui::AX_ATTR_LANGUAGE)); + + // Test GetInheritedString16Attribute(attribute, out_value). + base::string16 value16; + EXPECT_TRUE(root_accessible->GetInheritedString16Attribute( + ui::AX_ATTR_LANGUAGE, &value16)); + EXPECT_EQ(base::UTF8ToUTF16("en-US"), value16); + EXPECT_TRUE(child1_accessible->GetInheritedString16Attribute( + ui::AX_ATTR_LANGUAGE, &value16)); + EXPECT_EQ(base::UTF8ToUTF16("en-US"), value16); + EXPECT_TRUE(child2_accessible->GetInheritedString16Attribute( + ui::AX_ATTR_LANGUAGE, &value16)); + EXPECT_EQ(base::UTF8ToUTF16("fr"), value16); + EXPECT_TRUE(child2_child1_accessible->GetInheritedString16Attribute( + ui::AX_ATTR_LANGUAGE, &value16)); + EXPECT_EQ(base::UTF8ToUTF16("fr"), value16); + EXPECT_TRUE(child2_child2_accessible->GetInheritedString16Attribute( + ui::AX_ATTR_LANGUAGE, &value16)); + EXPECT_EQ(base::UTF8ToUTF16("fr"), value16); + + // Test GetInheritedStringAttribute(attribute). + EXPECT_EQ("Helvetica", root_accessible->GetInheritedStringAttribute( + ui::AX_ATTR_FONT_FAMILY)); + EXPECT_EQ("Helvetica", child1_accessible->GetInheritedStringAttribute( + ui::AX_ATTR_FONT_FAMILY)); + EXPECT_EQ("Arial", child2_accessible->GetInheritedStringAttribute( + ui::AX_ATTR_FONT_FAMILY)); + EXPECT_EQ("Arial", child2_child1_accessible->GetInheritedStringAttribute( + ui::AX_ATTR_FONT_FAMILY)); + EXPECT_EQ("Arial", child2_child2_accessible->GetInheritedStringAttribute( + ui::AX_ATTR_FONT_FAMILY)); + + // Test GetInheritedStringAttribute(attribute, out_value). + std::string value; + EXPECT_TRUE(root_accessible->GetInheritedStringAttribute( + ui::AX_ATTR_FONT_FAMILY, &value)); + EXPECT_EQ("Helvetica", value); + EXPECT_TRUE(child1_accessible->GetInheritedStringAttribute( + ui::AX_ATTR_FONT_FAMILY, &value)); + EXPECT_EQ("Helvetica", value); + EXPECT_TRUE(child2_accessible->GetInheritedStringAttribute( + ui::AX_ATTR_FONT_FAMILY, &value)); + EXPECT_EQ("Arial", value); + EXPECT_TRUE(child2_child1_accessible->GetInheritedStringAttribute( + ui::AX_ATTR_FONT_FAMILY, &value)); + EXPECT_EQ("Arial", value); + EXPECT_TRUE(child2_child2_accessible->GetInheritedStringAttribute( + ui::AX_ATTR_FONT_FAMILY, &value)); + EXPECT_EQ("Arial", value); +} + TEST_F(BrowserAccessibilityTest, TestSanitizeStringAttributeForIA2) { base::string16 input(L"\\:=,;"); base::string16 output; diff --git a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc index 68e9779..a89e48e 100644 --- a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc +++ b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc @@ -79,6 +79,17 @@ class DumpAccessibilityTreeTest : public DumpAccessibilityTestBase { RunTest(aria_file, "accessibility/aria"); } + void RunCSSTest(const base::FilePath::CharType* file_path) { + base::FilePath dir_test_data; + ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &dir_test_data)); + base::FilePath test_path( + dir_test_data.AppendASCII("accessibility").AppendASCII("css")); + ASSERT_TRUE(base::PathExists(test_path)) << test_path.LossyDisplayName(); + + base::FilePath css_file = test_path.Append(base::FilePath(file_path)); + RunTest(css_file, "accessibility/css"); + } + void RunHtmlTest(const base::FilePath::CharType* file_path) { base::FilePath dir_test_data; ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &dir_test_data)); @@ -107,6 +118,18 @@ class DumpAccessibilityTreeTest : public DumpAccessibilityTestBase { } }; +IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityCSSColor) { + RunCSSTest(FILE_PATH_LITERAL("color.html")); +} + +IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityCSSFontStyle) { + RunCSSTest(FILE_PATH_LITERAL("font-style.html")); +} + +IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityCSSLanguage) { + RunCSSTest(FILE_PATH_LITERAL("language.html")); +} + IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityA) { RunHtmlTest(FILE_PATH_LITERAL("a.html")); } diff --git a/content/renderer/accessibility/blink_ax_tree_source.cc b/content/renderer/accessibility/blink_ax_tree_source.cc index b4094e0..858c3a0 100644 --- a/content/renderer/accessibility/blink_ax_tree_source.cc +++ b/content/renderer/accessibility/blink_ax_tree_source.cc @@ -138,12 +138,12 @@ AXContentTreeData BlinkAXTreeSource::GetTreeData() const { blink::WebDocument document = BlinkAXTreeSource::GetMainDocument(); const blink::WebAXObject& root = GetRoot(); - tree_data.title = document.title().utf8(); - tree_data.url = document.url().string().utf8(); - tree_data.mimetype = document.isXHTMLDocument() ? "text/xhtml" : "text/html"; + tree_data.doctype = "html"; tree_data.loaded = root.isLoaded(); tree_data.loading_progress = root.estimatedLoadingProgress(); - tree_data.doctype = "html"; + tree_data.mimetype = document.isXHTMLDocument() ? "text/xhtml" : "text/html"; + tree_data.title = document.title().utf8(); + tree_data.url = document.url().string().utf8(); WebAXObject focus = document.focusedAccessibilityObject(); if (!focus.isNull()) @@ -312,6 +312,12 @@ void BlinkAXTreeSource::SerializeNode(blink::WebAXObject src, if (src.color()) dst->AddIntAttribute(ui::AX_ATTR_COLOR, src.color()); + if (src.fontFamily().length()) { + WebAXObject parent = src.parentObject(); + if (parent.isNull() || parent.fontFamily() != src.fontFamily()) + dst->AddStringAttribute(ui::AX_ATTR_FONT_FAMILY, src.fontFamily().utf8()); + } + // Font size is in pixels. if (src.fontSize()) dst->AddFloatAttribute(ui::AX_ATTR_FONT_SIZE, src.fontSize()); @@ -320,7 +326,8 @@ void BlinkAXTreeSource::SerializeNode(blink::WebAXObject src, dst->AddIntAttribute(ui::AX_ATTR_INVALID_STATE, AXInvalidStateFromBlink(src.invalidState())); } - if (src.invalidState() == blink::WebAXInvalidStateOther) { + if (src.invalidState() == blink::WebAXInvalidStateOther && + src.ariaInvalidValue().length()) { dst->AddStringAttribute( ui::AX_ATTR_ARIA_INVALID_VALUE, src.ariaInvalidValue().utf8()); } @@ -367,25 +374,39 @@ void BlinkAXTreeSource::SerializeNode(blink::WebAXObject src, if (src.actionVerb().length()) { dst->AddStringAttribute(ui::AX_ATTR_ACTION, src.actionVerb().utf8()); } - if (src.ariaAutoComplete().length()) + + if (src.ariaAutoComplete().length()) { dst->AddStringAttribute( ui::AX_ATTR_AUTO_COMPLETE, src.ariaAutoComplete().utf8()); + } + if (src.isAriaReadOnly()) dst->AddBoolAttribute(ui::AX_ATTR_ARIA_READONLY, true); + if (src.isButtonStateMixed()) dst->AddBoolAttribute(ui::AX_ATTR_STATE_MIXED, true); + if (src.canSetValueAttribute()) dst->AddBoolAttribute(ui::AX_ATTR_CAN_SET_VALUE, true); + if (src.hasComputedStyle()) { dst->AddStringAttribute( ui::AX_ATTR_DISPLAY, src.computedStyleDisplay().utf8()); } + + if (src.language().length()) { + WebAXObject parent = src.parentObject(); + if (parent.isNull() || parent.language() != src.language()) + dst->AddStringAttribute(ui::AX_ATTR_LANGUAGE, src.language().utf8()); + } + if (src.keyboardShortcut().length()) { dst->AddStringAttribute( ui::AX_ATTR_SHORTCUT, src.keyboardShortcut().utf8()); } + if (!src.ariaActiveDescendant().isDetached()) { dst->AddIntAttribute(ui::AX_ATTR_ACTIVEDESCENDANT_ID, src.ariaActiveDescendant().axID()); diff --git a/content/test/data/accessibility/aria/aria-invalid-expected-win.txt b/content/test/data/accessibility/aria/aria-invalid-expected-win.txt index 2fbe377..873bf49 100644 --- a/content/test/data/accessibility/aria/aria-invalid-expected-win.txt +++ b/content/test/data/accessibility/aria/aria-invalid-expected-win.txt @@ -1,17 +1,17 @@ -ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE -++IA2_ROLE_SECTION IA2_STATE_INVALID_ENTRY invalid:true -++++ROLE_SYSTEM_STATICTEXT name='invalid=true' -++IA2_ROLE_SECTION IA2_STATE_INVALID_ENTRY invalid:spelling -++++ROLE_SYSTEM_STATICTEXT name='invalid=spelling' -++IA2_ROLE_SECTION IA2_STATE_INVALID_ENTRY invalid:grammar -++++ROLE_SYSTEM_STATICTEXT name='invalid=grammar' +ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE invalid:true invalid:spelling invalid:grammar invalid:false invalid:unknown invalid:false +++IA2_ROLE_SECTION IA2_STATE_INVALID_ENTRY invalid:false +++++ROLE_SYSTEM_STATICTEXT name='invalid=true' invalid:false +++IA2_ROLE_SECTION IA2_STATE_INVALID_ENTRY invalid:false +++++ROLE_SYSTEM_STATICTEXT name='invalid=spelling' invalid:false +++IA2_ROLE_SECTION IA2_STATE_INVALID_ENTRY invalid:false +++++ROLE_SYSTEM_STATICTEXT name='invalid=grammar' invalid:false ++IA2_ROLE_SECTION invalid:false -++++ROLE_SYSTEM_STATICTEXT name='invalid=false' -++IA2_ROLE_SECTION -++++ROLE_SYSTEM_STATICTEXT name='invalid=<empty>' -++IA2_ROLE_SECTION -++++ROLE_SYSTEM_STATICTEXT name='invalid=<default>' -++IA2_ROLE_SECTION IA2_STATE_INVALID_ENTRY invalid:unknown -++++ROLE_SYSTEM_STATICTEXT name='invalid=unknown' -++IA2_ROLE_FORM +++++ROLE_SYSTEM_STATICTEXT name='invalid=false' invalid:false +++IA2_ROLE_SECTION invalid:false +++++ROLE_SYSTEM_STATICTEXT name='invalid=<empty>' invalid:false +++IA2_ROLE_SECTION invalid:false +++++ROLE_SYSTEM_STATICTEXT name='invalid=<default>' invalid:false +++IA2_ROLE_SECTION IA2_STATE_INVALID_ENTRY invalid:false +++++ROLE_SYSTEM_STATICTEXT name='invalid=unknown' invalid:false +++IA2_ROLE_FORM invalid:true ++++ROLE_SYSTEM_TEXT FOCUSABLE IA2_STATE_INVALID_ENTRY invalid:true diff --git a/content/test/data/accessibility/css/color-expected-blink.txt b/content/test/data/accessibility/css/color-expected-blink.txt new file mode 100644 index 0000000..79c5d80 --- /dev/null +++ b/content/test/data/accessibility/css/color-expected-blink.txt @@ -0,0 +1,11 @@ +rootWebArea color=-16777216 +++paragraph backgroundColor=-16776961 color=-65536 +++++staticText name='Red on blue.' backgroundColor=-16776961 color=-65536 +++++++inlineTextBox name='Red on blue.' color=-16777216 +++div color=-16777216 +++++staticText name='Default.' color=-16777216 +++++++inlineTextBox name='Default.' color=-16777216 +++++staticText name='Blue background.' backgroundColor=-16776961 color=-16777216 +++++++inlineTextBox name='Blue background.' color=-16777216 +++++staticText name='Green text.' color=-16711936 +++++++inlineTextBox name='Green text.' color=-16777216 diff --git a/content/test/data/accessibility/css/color-expected-win.txt b/content/test/data/accessibility/css/color-expected-win.txt new file mode 100644 index 0000000..5fc6beb --- /dev/null +++ b/content/test/data/accessibility/css/color-expected-win.txt @@ -0,0 +1,7 @@ +ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE background-color:rgb(0\,0\,255) color:rgb(255\,0\,0) background-color:transparent color:rgb(0\,0\,0) ia2_hypertext='<obj0><obj1>' +++IA2_ROLE_PARAGRAPH background-color:rgb(0\,0\,255) color:rgb(255\,0\,0) ia2_hypertext='Red on blue.' +++++ROLE_SYSTEM_STATICTEXT name='Red on blue.' background-color:rgb(0\,0\,255) color:rgb(255\,0\,0) ia2_hypertext='Red on blue.' +++IA2_ROLE_SECTION FOCUSABLE background-color:transparent color:rgb(0\,0\,0) background-color:rgb(0\,0\,255) color:rgb(0\,0\,0) background-color:transparent color:rgb(0\,255\,0) ia2_hypertext='Default.Blue background.Green text.' +++++ROLE_SYSTEM_STATICTEXT name='Default.' background-color:transparent color:rgb(0\,0\,0) ia2_hypertext='Default.' +++++ROLE_SYSTEM_STATICTEXT name='Blue background.' background-color:rgb(0\,0\,255) color:rgb(0\,0\,0) ia2_hypertext='Blue background.' +++++ROLE_SYSTEM_STATICTEXT name='Green text.' background-color:transparent color:rgb(0\,255\,0) ia2_hypertext='Green text.' diff --git a/content/test/data/accessibility/css/color.html b/content/test/data/accessibility/css/color.html new file mode 100644 index 0000000..b5db005 --- /dev/null +++ b/content/test/data/accessibility/css/color.html @@ -0,0 +1,17 @@ +<!-- +@BLINK-ALLOW:backgroundColor=* +@BLINK-ALLOW:color=* +@WIN-ALLOW:background-color:* +@WIN-ALLOW:color:* +@WIN-ALLOW:ia2_hypertext=* +--> +<!DOCTYPE html> +<html> + <body> + <p style="background-color: #0000FF; color: #FF0000">Red on blue.</p> + <div contentEditable><span>Default.</span> + <span style="background-color: #0000FF;">Blue background.</span> + <span style="color: #00FF00;">Green text.</span> + </div> + </body> +</html> diff --git a/content/test/data/accessibility/css/font-style-expected-blink.txt b/content/test/data/accessibility/css/font-style-expected-blink.txt new file mode 100644 index 0000000..0be2e0a --- /dev/null +++ b/content/test/data/accessibility/css/font-style-expected-blink.txt @@ -0,0 +1,15 @@ +rootWebArea +++paragraph +++++staticText name='Normal ' +++++++inlineTextBox name='Normal ' +++++staticText name='bold' textStyle=1 +++++++inlineTextBox name='bold' +++++staticText name='italic' textStyle=2 +++++++inlineTextBox name='italic' +++div +++++staticText name='Normal' +++++++inlineTextBox name='Normal' +++++staticText name='bold' textStyle=1 +++++++inlineTextBox name='bold' +++++staticText name='italic' textStyle=2 +++++++inlineTextBox name='italic' diff --git a/content/test/data/accessibility/css/font-style-expected-win.txt b/content/test/data/accessibility/css/font-style-expected-win.txt new file mode 100644 index 0000000..5699609 --- /dev/null +++ b/content/test/data/accessibility/css/font-style-expected-win.txt @@ -0,0 +1,9 @@ +ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE font-style:normal font-weight:normal ia2_hypertext='<obj0><obj1>' +++IA2_ROLE_PARAGRAPH font-style:normal font-weight:normal font-weight:bold font-style:underline font-style:italic,underline ia2_hypertext='Normal bolditalic' +++++ROLE_SYSTEM_STATICTEXT name='Normal ' font-style:normal font-weight:normal ia2_hypertext='Normal ' +++++ROLE_SYSTEM_STATICTEXT name='bold' font-weight:bold font-style:underline ia2_hypertext='bold' +++++ROLE_SYSTEM_STATICTEXT name='italic' font-style:italic,underline ia2_hypertext='italic' +++IA2_ROLE_SECTION FOCUSABLE font-style:normal font-weight:normal font-weight:bold font-style:underline font-style:italic,underline ia2_hypertext='Normalbolditalic' +++++ROLE_SYSTEM_STATICTEXT name='Normal' font-style:normal font-weight:normal ia2_hypertext='Normal' +++++ROLE_SYSTEM_STATICTEXT name='bold' font-weight:bold font-style:underline ia2_hypertext='bold' +++++ROLE_SYSTEM_STATICTEXT name='italic' font-style:italic,underline ia2_hypertext='italic' diff --git a/content/test/data/accessibility/css/font-style.html b/content/test/data/accessibility/css/font-style.html new file mode 100644 index 0000000..5df21b4 --- /dev/null +++ b/content/test/data/accessibility/css/font-style.html @@ -0,0 +1,16 @@ +<!-- +@BLINK-ALLOW:textStyle=* +@WIN-ALLOW:font-weight:* +@WIN-ALLOW:font-style:* +@WIN-ALLOW:ia2_hypertext=* +--> +<!DOCTYPE html> +<html> + <body> + <p>Normal <b>bold</b> <i>italic</i></p> + <div contentEditable><span>Normal</span> + <span style="font-weight: bold;">bold</span> + <span style="font-style: italic;">italic</span> + </div> + </body> +</html> diff --git a/content/test/data/accessibility/css/language-expected-blink.txt b/content/test/data/accessibility/css/language-expected-blink.txt new file mode 100644 index 0000000..d6f6a81 --- /dev/null +++ b/content/test/data/accessibility/css/language-expected-blink.txt @@ -0,0 +1,7 @@ +rootWebArea +++paragraph language='en-US' +++++staticText name='How are you?' +++++++inlineTextBox name='How are you?' +++paragraph language='fr-FR' +++++staticText name='Comment allez-vous?' +++++++inlineTextBox name='Comment allez-vous?' diff --git a/content/test/data/accessibility/css/language-expected-win.txt b/content/test/data/accessibility/css/language-expected-win.txt new file mode 100644 index 0000000..51afa6a --- /dev/null +++ b/content/test/data/accessibility/css/language-expected-win.txt @@ -0,0 +1,5 @@ +ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE language:en-US language:fr-FR ia2_hypertext='<obj0><obj1>' +++IA2_ROLE_PARAGRAPH language:en-US ia2_hypertext='How are you?' +++++ROLE_SYSTEM_STATICTEXT name='How are you?' language:en-US ia2_hypertext='How are you?' +++IA2_ROLE_PARAGRAPH language:fr-FR ia2_hypertext='Comment allez-vous?' +++++ROLE_SYSTEM_STATICTEXT name='Comment allez-vous?' language:fr-FR ia2_hypertext='Comment allez-vous?' diff --git a/content/test/data/accessibility/css/language.html b/content/test/data/accessibility/css/language.html new file mode 100644 index 0000000..3d46856 --- /dev/null +++ b/content/test/data/accessibility/css/language.html @@ -0,0 +1,12 @@ +<!-- +@BLINK-ALLOW:language=* +@WIN-ALLOW:ia2_hypertext=* +@WIN-ALLOW:language:* +--> +<!DOCTYPE html> +<html> + <body> + <p lang="en-US">How are you?</p> + <p lang="fr-FR">Comment allez-vous?</p> + </body> +</html> diff --git a/content/test/data/accessibility/html/keygen-expected-win.txt b/content/test/data/accessibility/html/keygen-expected-win.txt index 5f5869c..11e72f7 100644 --- a/content/test/data/accessibility/html/keygen-expected-win.txt +++ b/content/test/data/accessibility/html/keygen-expected-win.txt @@ -1,7 +1,7 @@ ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE ++IA2_ROLE_SECTION role_name='body' -++++IA2_ROLE_SECTION FOCUSABLE invalid:false role_name='keygen' -++++++ROLE_SYSTEM_COMBOBOX COLLAPSED FOCUSABLE HASPOPUP invalid:false +++++IA2_ROLE_SECTION FOCUSABLE role_name='keygen' +++++++ROLE_SYSTEM_COMBOBOX COLLAPSED FOCUSABLE HASPOPUP ++++++++ROLE_SYSTEM_LIST INVISIBLE ++++++++++ROLE_SYSTEM_LISTITEM SELECTED FOCUSABLE SELECTABLE ++++++++++ROLE_SYSTEM_LISTITEM INVISIBLE FOCUSABLE SELECTABLE diff --git a/content/test/data/accessibility/html/keygen.html b/content/test/data/accessibility/html/keygen.html index 0e3d0a1..ce904c2 100644 --- a/content/test/data/accessibility/html/keygen.html +++ b/content/test/data/accessibility/html/keygen.html @@ -1,7 +1,6 @@ <!-- @WIN-ALLOW:SELECTED @WIN-ALLOW:SELECTABLE -@WIN-ALLOW:invalid* @WIN-ALLOW:role_name* @WIN-ALLOW:COLLAPSED @WIN-ALLOW:INVISIBLE diff --git a/content/test/data/accessibility/html/optgroup-expected-win.txt b/content/test/data/accessibility/html/optgroup-expected-win.txt index 69ba92a..d3b393bd 100644 --- a/content/test/data/accessibility/html/optgroup-expected-win.txt +++ b/content/test/data/accessibility/html/optgroup-expected-win.txt @@ -1,6 +1,6 @@ ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE ++IA2_ROLE_SECTION -++++ROLE_SYSTEM_LIST FOCUSABLE IA2_STATE_VERTICAL invalid:false +++++ROLE_SYSTEM_LIST FOCUSABLE IA2_STATE_VERTICAL ++++++ROLE_SYSTEM_GROUPING name='Enabled' xml-roles:group ++++++++ROLE_SYSTEM_STATICTEXT name='Enabled' ++++++ROLE_SYSTEM_LISTITEM name='One' FOCUSABLE SELECTABLE diff --git a/content/test/data/accessibility/html/optgroup.html b/content/test/data/accessibility/html/optgroup.html index bef8d42..2571670 100644 --- a/content/test/data/accessibility/html/optgroup.html +++ b/content/test/data/accessibility/html/optgroup.html @@ -3,7 +3,6 @@ @WIN-ALLOW:xml-roles* @WIN-ALLOW:IA2_STATE_VERTICAL @WIN-ALLOW:SELECTABLE -@WIN-ALLOW:invalid* --> <!DOCTYPE html> <html> diff --git a/third_party/WebKit/Source/modules/accessibility/AXLayoutObject.cpp b/third_party/WebKit/Source/modules/accessibility/AXLayoutObject.cpp index 409f370..bf68f5e 100644 --- a/third_party/WebKit/Source/modules/accessibility/AXLayoutObject.cpp +++ b/third_party/WebKit/Source/modules/accessibility/AXLayoutObject.cpp @@ -827,10 +827,10 @@ const AtomicString& AXLayoutObject::accessKey() const RGBA32 AXLayoutObject::backgroundColor() const { - if (!m_layoutObject) + if (!getLayoutObject()) return AXNodeObject::backgroundColor(); - const ComputedStyle* style = m_layoutObject->style(); + const ComputedStyle* style = getLayoutObject()->style(); if (!style || !style->hasBackground()) return AXNodeObject::backgroundColor(); @@ -840,10 +840,10 @@ RGBA32 AXLayoutObject::backgroundColor() const RGBA32 AXLayoutObject::color() const { - if (!m_layoutObject || isColorWell()) + if (!getLayoutObject() || isColorWell()) return AXNodeObject::color(); - const ComputedStyle* style = m_layoutObject->style(); + const ComputedStyle* style = getLayoutObject()->style(); if (!style) return AXNodeObject::color(); @@ -851,13 +851,26 @@ RGBA32 AXLayoutObject::color() const return color.rgb(); } +String AXLayoutObject::fontFamily() const +{ + if (!getLayoutObject()) + return AXNodeObject::fontFamily(); + + const ComputedStyle* style = getLayoutObject()->style(); + if (!style) + return AXNodeObject::fontFamily(); + + FontDescription& fontDescription = const_cast<FontDescription&>(style->getFontDescription()); + return fontDescription.firstFamily().family(); +} + // Font size is in pixels. float AXLayoutObject::fontSize() const { - if (!m_layoutObject) + if (!getLayoutObject()) return AXNodeObject::fontSize(); - const ComputedStyle* style = m_layoutObject->style(); + const ComputedStyle* style = getLayoutObject()->style(); if (!style) return AXNodeObject::fontSize(); @@ -867,10 +880,10 @@ float AXLayoutObject::fontSize() const String AXLayoutObject::text() const { if (isPasswordFieldAndShouldHideValue()) { - if (!m_layoutObject) + if (!getLayoutObject()) return String(); - const ComputedStyle* style = m_layoutObject->style(); + const ComputedStyle* style = getLayoutObject()->style(); if (!style) return String(); @@ -906,10 +919,10 @@ String AXLayoutObject::text() const AccessibilityTextDirection AXLayoutObject::textDirection() const { - if (!m_layoutObject) + if (!getLayoutObject()) return AXNodeObject::textDirection(); - const ComputedStyle* style = m_layoutObject->style(); + const ComputedStyle* style = getLayoutObject()->style(); if (!style) return AXNodeObject::textDirection(); @@ -942,10 +955,10 @@ int AXLayoutObject::textLength() const TextStyle AXLayoutObject::getTextStyle() const { - if (!m_layoutObject) + if (!getLayoutObject()) return AXNodeObject::getTextStyle(); - const ComputedStyle* style = m_layoutObject->style(); + const ComputedStyle* style = getLayoutObject()->style(); if (!style) return AXNodeObject::getTextStyle(); diff --git a/third_party/WebKit/Source/modules/accessibility/AXLayoutObject.h b/third_party/WebKit/Source/modules/accessibility/AXLayoutObject.h index e43355a..4eab54b 100644 --- a/third_party/WebKit/Source/modules/accessibility/AXLayoutObject.h +++ b/third_party/WebKit/Source/modules/accessibility/AXLayoutObject.h @@ -101,6 +101,7 @@ protected: const AtomicString& accessKey() const override; RGBA32 backgroundColor() const final; RGBA32 color() const final; + String fontFamily() const final; // Font size is in pixels. float fontSize() const final; String text() const override; diff --git a/third_party/WebKit/Source/modules/accessibility/AXObject.h b/third_party/WebKit/Source/modules/accessibility/AXObject.h index 0495800..bec65aa 100644 --- a/third_party/WebKit/Source/modules/accessibility/AXObject.h +++ b/third_party/WebKit/Source/modules/accessibility/AXObject.h @@ -699,6 +699,7 @@ public: // Used by objects of role ColorWellRole. virtual RGBA32 colorValue() const { return Color::transparent; } virtual bool canvasHasFallbackContent() const { return false; } + virtual String fontFamily() const { return nullAtom; } // Font size is in pixels. virtual float fontSize() const { return 0.0f; } virtual int headingLevel() const { return 0; } diff --git a/third_party/WebKit/Source/web/WebAXObject.cpp b/third_party/WebKit/Source/web/WebAXObject.cpp index b892249..4445b63 100644 --- a/third_party/WebKit/Source/web/WebAXObject.cpp +++ b/third_party/WebKit/Source/web/WebAXObject.cpp @@ -636,6 +636,14 @@ WebRect WebAXObject::boundingBoxRect() const return pixelSnappedIntRect(m_private->elementRect()); } +WebString WebAXObject::fontFamily() const +{ + if (isDetached()) + return WebString(); + + return m_private->fontFamily(); +} + float WebAXObject::fontSize() const { if (isDetached()) diff --git a/third_party/WebKit/public/web/WebAXObject.h b/third_party/WebKit/public/web/WebAXObject.h index f0051c1..b591739 100644 --- a/third_party/WebKit/public/web/WebAXObject.h +++ b/third_party/WebKit/public/web/WebAXObject.h @@ -142,6 +142,7 @@ public: BLINK_EXPORT bool isRichlyEditable() const; BLINK_EXPORT bool ariaOwns(WebVector<WebAXObject>& ownsElements) const; BLINK_EXPORT WebRect boundingBoxRect() const; + BLINK_EXPORT WebString fontFamily() const; BLINK_EXPORT float fontSize() const; BLINK_EXPORT bool canvasHasFallbackContent() const; BLINK_EXPORT WebPoint clickPoint() const; diff --git a/ui/accessibility/ax_enums.idl b/ui/accessibility/ax_enums.idl index bad6a7a..be08a8a36 100644 --- a/ui/accessibility/ax_enums.idl +++ b/ui/accessibility/ax_enums.idl @@ -236,14 +236,18 @@ [cpp_enum_prefix_override="ax_attr"] enum AXStringAttribute { access_key, action, + // Only used when invalid_state == invalid_state_other. + aria_invalid_value, auto_complete, container_live_relevant, container_live_status, description, display, + // Only present when different from parent. + font_family, html_tag, - // Only used when invalid_state == invalid_state_other. - aria_invalid_value, + // Only present when different from parent. + language, name, live_relevant, live_status, diff --git a/ui/accessibility/ax_node_data.cc b/ui/accessibility/ax_node_data.cc index be59c71..6c2be76 100644 --- a/ui/accessibility/ax_node_data.cc +++ b/ui/accessibility/ax_node_data.cc @@ -513,6 +513,9 @@ std::string AXNodeData::ToString() const { case AX_ATTR_ACTION: result += " action=" + value; break; + case AX_ATTR_ARIA_INVALID_VALUE: + result += " aria_invalid_value=" + value; + break; case AX_ATTR_AUTO_COMPLETE: result += " autocomplete=" + value; break; @@ -522,11 +525,14 @@ std::string AXNodeData::ToString() const { case AX_ATTR_DISPLAY: result += " display=" + value; break; + case AX_ATTR_FONT_FAMILY: + result += " font-family=" + value; + break; case AX_ATTR_HTML_TAG: result += " html_tag=" + value; break; - case AX_ATTR_ARIA_INVALID_VALUE: - result += " aria_invalid_value=" + value; + case AX_ATTR_LANGUAGE: + result += " language=" + value; break; case AX_ATTR_LIVE_RELEVANT: result += " relevant=" + value; diff --git a/ui/accessibility/ax_tree_data.cc b/ui/accessibility/ax_tree_data.cc index 274da85..4e434db 100644 --- a/ui/accessibility/ax_tree_data.cc +++ b/ui/accessibility/ax_tree_data.cc @@ -46,19 +46,18 @@ std::string AXTreeData::ToString() const { if (focused_tree_id != -1) result += " focused_tree_id=" + IntToString(focused_tree_id); - if (!url.empty()) - result += " url=" + url; - if (!title.empty()) - result += " title=" + title; - if (!mimetype.empty()) - result += " mimetype=" + mimetype; if (!doctype.empty()) result += " doctype=" + doctype; - if (loaded) result += " loaded=true"; if (loading_progress != 0.0) result += " loading_progress=" + DoubleToString(loading_progress); + if (!mimetype.empty()) + result += " mimetype=" + mimetype; + if (!url.empty()) + result += " url=" + url; + if (!title.empty()) + result += " title=" + title; if (focus_id != -1) result += " focus_id=" + IntToString(focus_id); @@ -79,13 +78,10 @@ bool operator==(const AXTreeData& lhs, const AXTreeData& rhs) { return (lhs.tree_id == rhs.tree_id && lhs.parent_tree_id == rhs.parent_tree_id && lhs.focused_tree_id == rhs.focused_tree_id && - lhs.url == rhs.url && - lhs.title == rhs.title && - lhs.mimetype == rhs.mimetype && - lhs.doctype == rhs.doctype && - lhs.loaded == rhs.loaded && + lhs.doctype == rhs.doctype && lhs.loaded == rhs.loaded && lhs.loading_progress == rhs.loading_progress && - lhs.focus_id == rhs.focus_id && + lhs.mimetype == rhs.mimetype && lhs.title == rhs.title && + lhs.url == rhs.url && lhs.focus_id == rhs.focus_id && lhs.sel_anchor_object_id == rhs.sel_anchor_object_id && lhs.sel_anchor_offset == rhs.sel_anchor_offset && lhs.sel_focus_object_id == rhs.sel_focus_object_id && diff --git a/ui/accessibility/ax_tree_data.h b/ui/accessibility/ax_tree_data.h index f780415..83a1589 100644 --- a/ui/accessibility/ax_tree_data.h +++ b/ui/accessibility/ax_tree_data.h @@ -43,12 +43,12 @@ struct AX_EXPORT AXTreeData { int32_t focused_tree_id; // Attributes specific to trees that are web frames. - std::string url; - std::string title; - std::string mimetype; std::string doctype; bool loaded; float loading_progress; + std::string mimetype; + std::string title; + std::string url; // The node with keyboard focus within this tree, if any, or -1 if no node // in this tree has focus. |