| Index: content/browser/accessibility/browser_accessibility_win.cc
|
| diff --git a/content/browser/accessibility/browser_accessibility_win.cc b/content/browser/accessibility/browser_accessibility_win.cc
|
| index bf3b0affdd751d7d45d1dc592723149d05660882..03c199c87f1c1ba83e77d74cda3aa5fd9bbabe9d 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;
|
|
|