diff options
author | dmazzoni@chromium.org <dmazzoni@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-09-01 08:44:16 +0000 |
---|---|---|
committer | dmazzoni@chromium.org <dmazzoni@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-09-01 08:44:16 +0000 |
commit | ee84512d1534bdf10fc11850665f2f6f5a16ba50 (patch) | |
tree | df0a5130eb32a29932d9f1ef7766aaeee611ce00 /webkit/glue | |
parent | aec454416ace3ac53d95b2a00a4f89c2f5f443da (diff) | |
download | chromium_src-ee84512d1534bdf10fc11850665f2f6f5a16ba50.zip chromium_src-ee84512d1534bdf10fc11850665f2f6f5a16ba50.tar.gz chromium_src-ee84512d1534bdf10fc11850665f2f6f5a16ba50.tar.bz2 |
Add a big grab bag of missing web accessibility
functionality on Windows. (Much of this will benefit
Mac in a future changelist.) Improvements include
dozens of corrected roles and states for various
elements, improved support for tables with rowspan
and colspan, range control support, and live region
support.
Also adds a new command-line flag to turn on
logging of accessibility events, to help making
this type of bug fixing much easier in the future.
BUG=89181,89185,89187,89188,89202,89205,89210,89212,89213,89223
TEST=Manual testing with JAWS, NVDA, AViewer, and accProbe.
Review URL: http://codereview.chromium.org/7745035
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@99161 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/glue')
-rw-r--r-- | webkit/glue/webaccessibility.cc | 492 | ||||
-rw-r--r-- | webkit/glue/webaccessibility.h | 61 |
2 files changed, 533 insertions, 20 deletions
diff --git a/webkit/glue/webaccessibility.cc b/webkit/glue/webaccessibility.cc index 77c362e..90f956a 100644 --- a/webkit/glue/webaccessibility.cc +++ b/webkit/glue/webaccessibility.cc @@ -26,10 +26,26 @@ #include "third_party/WebKit/Source/WebKit/chromium/public/WebString.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebVector.h" +using base::DoubleToString; +using base::IntToString; using WebKit::WebAccessibilityCache; using WebKit::WebAccessibilityRole; using WebKit::WebAccessibilityObject; +namespace { + +std::string IntVectorToString(const std::vector<int>& items) { + std::string str; + for (size_t i = 0; i < items.size(); ++i) { + if (i > 0) + str += ","; + str += IntToString(items[i]); + } + return str; +} + +} // Anonymous namespace + namespace webkit_glue { // Provides a conversion between the WebKit::WebAccessibilityRole and a role @@ -245,9 +261,9 @@ uint32 ConvertState(const WebAccessibilityObject& o) { if (o.isFocused()) state |= (1 << WebAccessibility::STATE_FOCUSED); - if (o.roleValue() == WebKit::WebAccessibilityRolePopUpButton) { + if (o.roleValue() == WebKit::WebAccessibilityRolePopUpButton || + o.ariaHasPopup()) { state |= (1 << WebAccessibility::STATE_HASPOPUP); - if (!o.isCollapsed()) state |= (1 << WebAccessibility::STATE_EXPANDED); } @@ -276,9 +292,12 @@ uint32 ConvertState(const WebAccessibilityObject& o) { if (o.isPasswordField()) state |= (1 << WebAccessibility::STATE_PROTECTED); - if (o.isReadOnly()) + if (o.isAriaReadOnly()) state |= (1 << WebAccessibility::STATE_READONLY); + if (o.isRequired()) + state |= (1 << WebAccessibility::STATE_REQUIRED); + if (o.canSetSelectedAttribute()) state |= (1 << WebAccessibility::STATE_SELECTABLE); @@ -291,6 +310,12 @@ uint32 ConvertState(const WebAccessibilityObject& o) { if (!o.isEnabled()) state |= (1 << WebAccessibility::STATE_UNAVAILABLE); + if (o.isVertical()) + state |= (1 << WebAccessibility::STATE_VERTICAL); + + if (o.isVisited()) + state |= (1 << WebAccessibility::STATE_VISITED); + return state; } @@ -309,28 +334,388 @@ WebAccessibility::WebAccessibility(const WebKit::WebAccessibilityObject& src, WebAccessibility::~WebAccessibility() { } +#ifndef NDEBUG +std::string WebAccessibility::DebugString(bool recursive) { + std::string result; + static int indent = 0; + + for (int i = 0; i < indent; ++i) + result += " "; + + result += "id=" + IntToString(id); + + switch (role) { + case ROLE_ALERT: result += " ALERT"; break; + case ROLE_ALERT_DIALOG: result += " ALERT_DIALOG"; break; + case ROLE_ANNOTATION: result += " ANNOTATION"; break; + case ROLE_APPLICATION: result += " APPLICATION"; break; + case ROLE_ARTICLE: result += " ARTICLE"; break; + case ROLE_BROWSER: result += " BROWSER"; break; + case ROLE_BUSY_INDICATOR: result += " BUSY_INDICATOR"; break; + case ROLE_BUTTON: result += " BUTTON"; break; + case ROLE_CELL: result += " CELL"; break; + case ROLE_CHECKBOX: result += " CHECKBOX"; break; + case ROLE_COLOR_WELL: result += " COLOR_WELL"; break; + case ROLE_COLUMN: result += " COLUMN"; break; + case ROLE_COLUMN_HEADER: result += " COLUMN_HEADER"; break; + case ROLE_COMBO_BOX: result += " COMBO_BOX"; break; + case ROLE_DEFINITION_LIST_DEFINITION: result += " DL_DEFINITION"; break; + case ROLE_DEFINITION_LIST_TERM: result += " DL_TERM"; break; + case ROLE_DIALOG: result += " DIALOG"; break; + case ROLE_DIRECTORY: result += " DIRECTORY"; break; + case ROLE_DISCLOSURE_TRIANGLE: result += " DISCLOSURE_TRIANGLE"; break; + case ROLE_DOCUMENT: result += " DOCUMENT"; break; + case ROLE_DRAWER: result += " DRAWER"; break; + case ROLE_EDITABLE_TEXT: result += " EDITABLE_TEXT"; break; + case ROLE_GRID: result += " GRID"; break; + case ROLE_GROUP: result += " GROUP"; break; + case ROLE_GROW_AREA: result += " GROW_AREA"; break; + case ROLE_HEADING: result += " HEADING"; break; + case ROLE_HELP_TAG: result += " HELP_TAG"; break; + case ROLE_IGNORED: result += " IGNORED"; break; + case ROLE_IMAGE: result += " IMAGE"; break; + case ROLE_IMAGE_MAP: result += " IMAGE_MAP"; break; + case ROLE_IMAGE_MAP_LINK: result += " IMAGE_MAP_LINK"; break; + case ROLE_INCREMENTOR: result += " INCREMENTOR"; break; + case ROLE_LANDMARK_APPLICATION: result += " L_APPLICATION"; break; + case ROLE_LANDMARK_BANNER: result += " L_BANNER"; break; + case ROLE_LANDMARK_COMPLEMENTARY: result += " L_COMPLEMENTARY"; break; + case ROLE_LANDMARK_CONTENTINFO: result += " L_CONTENTINFO"; break; + case ROLE_LANDMARK_MAIN: result += " L_MAIN"; break; + case ROLE_LANDMARK_NAVIGATION: result += " L_NAVIGATION"; break; + case ROLE_LANDMARK_SEARCH: result += " L_SEARCH"; break; + case ROLE_LINK: result += " LINK"; break; + case ROLE_LIST: result += " LIST"; break; + case ROLE_LISTBOX: result += " LISTBOX"; break; + case ROLE_LISTBOX_OPTION: result += " LISTBOX_OPTION"; break; + case ROLE_LIST_ITEM: result += " LIST_ITEM"; break; + case ROLE_LIST_MARKER: result += " LIST_MARKER"; break; + case ROLE_LOG: result += " LOG"; break; + case ROLE_MARQUEE: result += " MARQUEE"; break; + case ROLE_MATH: result += " MATH"; break; + case ROLE_MATTE: result += " MATTE"; break; + case ROLE_MENU: result += " MENU"; break; + case ROLE_MENU_BAR: result += " MENU_BAR"; break; + case ROLE_MENU_BUTTON: result += " MENU_BUTTON"; break; + case ROLE_MENU_ITEM: result += " MENU_ITEM"; break; + case ROLE_MENU_LIST_OPTION: result += " MENU_LIST_OPTION"; break; + case ROLE_MENU_LIST_POPUP: result += " MENU_LIST_POPUP"; break; + case ROLE_NOTE: result += " NOTE"; break; + case ROLE_OUTLINE: result += " OUTLINE"; break; + case ROLE_POPUP_BUTTON: result += " POPUP_BUTTON"; break; + case ROLE_PROGRESS_INDICATOR: result += " PROGRESS_INDICATOR"; break; + case ROLE_RADIO_BUTTON: result += " RADIO_BUTTON"; break; + case ROLE_RADIO_GROUP: result += " RADIO_GROUP"; break; + case ROLE_REGION: result += " REGION"; break; + case ROLE_ROW: result += " ROW"; break; + case ROLE_ROW_HEADER: result += " ROW_HEADER"; break; + case ROLE_RULER: result += " RULER"; break; + case ROLE_RULER_MARKER: result += " RULER_MARKER"; break; + case ROLE_SCROLLAREA: result += " SCROLLAREA"; break; + case ROLE_SCROLLBAR: result += " SCROLLBAR"; break; + case ROLE_SHEET: result += " SHEET"; break; + case ROLE_SLIDER: result += " SLIDER"; break; + case ROLE_SLIDER_THUMB: result += " SLIDER_THUMB"; break; + case ROLE_SPLITTER: result += " SPLITTER"; break; + case ROLE_SPLIT_GROUP: result += " SPLIT_GROUP"; break; + case ROLE_STATIC_TEXT: result += " STATIC_TEXT"; break; + case ROLE_STATUS: result += " STATUS"; break; + case ROLE_SYSTEM_WIDE: result += " SYSTEM_WIDE"; break; + case ROLE_TAB: result += " TAB"; break; + case ROLE_TABLE: result += " TABLE"; break; + case ROLE_TABLE_HEADER_CONTAINER: result += " TABLE_HDR_CONTAINER"; break; + case ROLE_TAB_GROUP: result += " TAB_GROUP"; break; + case ROLE_TAB_LIST: result += " TAB_LIST"; break; + case ROLE_TAB_PANEL: result += " TAB_PANEL"; break; + case ROLE_TEXTAREA: result += " TEXTAREA"; break; + case ROLE_TEXT_FIELD: result += " TEXT_FIELD"; break; + case ROLE_TIMER: result += " TIMER"; break; + case ROLE_TOOLBAR: result += " TOOLBAR"; break; + case ROLE_TOOLTIP: result += " TOOLTIP"; break; + case ROLE_TREE: result += " TREE"; break; + case ROLE_TREE_GRID: result += " TREE_GRID"; break; + case ROLE_TREE_ITEM: result += " TREE_ITEM"; break; + case ROLE_UNKNOWN: result += " UNKNOWN"; break; + case ROLE_VALUE_INDICATOR: result += " VALUE_INDICATOR"; break; + case ROLE_WEBCORE_LINK: result += " WEBCORE_LINK"; break; + case ROLE_WEB_AREA: result += " WEB_AREA"; break; + case ROLE_WINDOW: result += " WINDOW"; break; + default: + assert(false); + } + + if (state & (1 << STATE_BUSY)) + result += " BUSY"; + if (state & (1 << STATE_CHECKED)) + result += " CHECKED"; + if (state & (1 << STATE_COLLAPSED)) + result += " COLLAPSED"; + if (state & (1 << STATE_EXPANDED)) + result += " EXPANDED"; + if (state & (1 << STATE_FOCUSABLE)) + result += " FOCUSABLE"; + if (state & (1 << STATE_FOCUSED)) + result += " FOCUSED"; + if (state & (1 << STATE_HASPOPUP)) + result += " HASPOPUP"; + if (state & (1 << STATE_HOTTRACKED)) + result += " HOTTRACKED"; + if (state & (1 << STATE_INDETERMINATE)) + result += " INDETERMINATE"; + if (state & (1 << STATE_INVISIBLE)) + result += " INVISIBLE"; + if (state & (1 << STATE_LINKED)) + result += " LINKED"; + if (state & (1 << STATE_MULTISELECTABLE)) + result += " MULTISELECTABLE"; + if (state & (1 << STATE_OFFSCREEN)) + result += " OFFSCREEN"; + if (state & (1 << STATE_PRESSED)) + result += " PRESSED"; + if (state & (1 << STATE_PROTECTED)) + result += " PROTECTED"; + if (state & (1 << STATE_READONLY)) + result += " READONLY"; + if (state & (1 << STATE_REQUIRED)) + result += " REQUIRED"; + if (state & (1 << STATE_SELECTABLE)) + result += " SELECTABLE"; + if (state & (1 << STATE_SELECTED)) + result += " SELECTED"; + if (state & (1 << STATE_TRAVERSED)) + result += " TRAVERSED"; + if (state & (1 << STATE_UNAVAILABLE)) + result += " UNAVAILABLE"; + if (state & (1 << STATE_VERTICAL)) + result += " VERTICAL"; + if (state & (1 << STATE_VISITED)) + result += " VISITED"; + + std::string tmp = UTF16ToUTF8(name); + RemoveChars(tmp, "\n", &tmp); + if (!tmp.empty()) + result += " name=" + tmp; + + tmp = UTF16ToUTF8(value); + RemoveChars(tmp, "\n", &tmp); + if (!tmp.empty()) + result += " value=" + tmp; + + result += " (" + IntToString(location.x()) + ", " + + IntToString(location.y()) + ")-(" + + IntToString(location.width()) + ", " + + IntToString(location.height()) + ")"; + + for (std::map<IntAttribute, int32>::const_iterator iter = + int_attributes.begin(); + iter != int_attributes.end(); + ++iter) { + std::string value = IntToString(iter->second); + switch (iter->first) { + case ATTR_DOC_SCROLLX: + result += " scrollx=" + value; + break; + case ATTR_DOC_SCROLLY: + result += " scrolly=" + value; + break; + case ATTR_HIERARCHICAL_LEVEL: + result += " level=" + value; + break; + case ATTR_TEXT_SEL_START: + result += " sel_start=" + value; + break; + case ATTR_TEXT_SEL_END: + result += " sel_end=" + value; + break; + case ATTR_TABLE_ROW_COUNT: + result += " rows=" + value; + break; + case ATTR_TABLE_COLUMN_COUNT: + result += " cols=" + value; + break; + case ATTR_TABLE_CELL_COLUMN_INDEX: + result += " col=" + value; + break; + case ATTR_TABLE_CELL_ROW_INDEX: + result += " row=" + value; + break; + case ATTR_TABLE_CELL_COLUMN_SPAN: + result += " colspan=" + value; + break; + case ATTR_TABLE_CELL_ROW_SPAN: + result += " rowspan=" + value; + break; + } + } + + for (std::map<StringAttribute, string16>::const_iterator iter = + string_attributes.begin(); + iter != string_attributes.end(); + ++iter) { + std::string value = UTF16ToUTF8(iter->second); + switch (iter->first) { + case ATTR_DOC_URL: + result += " doc_url=" + value; + break; + case ATTR_DOC_TITLE: + result += " doc_title=" + value; + break; + case ATTR_DOC_MIMETYPE: + result += " doc_mimetype=" + value; + break; + case ATTR_DOC_DOCTYPE: + result += " doc_doctype=" + value; + break; + case ATTR_ACCESS_KEY: + result += " access_key=" + value; + break; + case ATTR_ACTION: + result += " action=" + value; + break; + case ATTR_DESCRIPTION: + result += " description=" + value; + break; + case ATTR_DISPLAY: + result += " display=" + value; + break; + case ATTR_HELP: + result += " help=" + value; + break; + case ATTR_HTML_TAG: + result += " html_tag=" + value; + break; + case ATTR_LIVE_RELEVANT: + result += " relevant=" + value; + break; + case ATTR_LIVE_STATUS: + result += " live=" + value; + break; + case ATTR_CONTAINER_LIVE_RELEVANT: + result += " container_relevant=" + value; + break; + case ATTR_CONTAINER_LIVE_STATUS: + result += " container_live=" + value; + break; + case ATTR_ROLE: + result += " role=" + value; + break; + case ATTR_SHORTCUT: + result += " shortcut=" + value; + break; + case ATTR_URL: + result += " url=" + value; + break; + } + } + + for (std::map<FloatAttribute, float>::const_iterator iter = + float_attributes.begin(); + iter != float_attributes.end(); + ++iter) { + std::string value = DoubleToString(iter->second); + switch (iter->first) { + case ATTR_DOC_LOADING_PROGRESS: + result += " doc_progress=" + value; + break; + case ATTR_VALUE_FOR_RANGE: + result += " value_for_range=" + value; + break; + case ATTR_MAX_VALUE_FOR_RANGE: + result += " max_value=" + value; + break; + case ATTR_MIN_VALUE_FOR_RANGE: + result += " min_value=" + value; + break; + } + } + + for (std::map<BoolAttribute, bool>::const_iterator iter = + bool_attributes.begin(); + iter != bool_attributes.end(); + ++iter) { + std::string value = iter->second ? "true" : "false"; + switch (iter->first) { + case ATTR_DOC_LOADED: + result += " doc_loaded=" + value; + break; + case ATTR_BUTTON_MIXED: + result += " mixed=" + value; + break; + case ATTR_LIVE_ATOMIC: + result += " atomic=" + value; + break; + case ATTR_LIVE_BUSY: + result += " busy=" + value; + break; + case ATTR_CONTAINER_LIVE_ATOMIC: + result += " container_atomic=" + value; + break; + case ATTR_CONTAINER_LIVE_BUSY: + result += " container_busy=" + value; + break; + } + } + + if (!children.empty()) + result += " children=" + IntToString(children.size()); + + if (!indirect_child_ids.empty()) + result += " indirect_child_ids=" + IntVectorToString(indirect_child_ids); + + if (!line_breaks.empty()) + result += " line_breaks=" + IntVectorToString(line_breaks); + + if (!cell_ids.empty()) + result += " cell_ids=" + IntVectorToString(cell_ids); + + if (recursive) { + result += "\n"; + ++indent; + for (size_t i = 0; i < children.size(); ++i) + result += children[i].DebugString(true); + --indent; + } + + return result; +} +#endif // ifndef NDEBUG + void WebAccessibility::Init(const WebKit::WebAccessibilityObject& src, WebKit::WebAccessibilityCache* cache, bool include_children) { name = src.title(); - value = src.stringValue(); role = ConvertRole(src.roleValue()); state = ConvertState(src); location = src.boundingBoxRect(); + if (src.valueDescription().length()) + value = src.valueDescription(); + else + value = src.stringValue(); + + if (src.accessKey().length()) + string_attributes[ATTR_ACCESS_KEY] = src.accessKey(); if (src.actionVerb().length()) string_attributes[ATTR_ACTION] = src.actionVerb(); + if (src.isButtonStateMixed()) + bool_attributes[ATTR_BUTTON_MIXED] = true; if (src.accessibilityDescription().length()) string_attributes[ATTR_DESCRIPTION] = src.accessibilityDescription(); + if (src.hasComputedStyle()) + string_attributes[ATTR_DISPLAY] = src.computedStyleDisplay(); if (src.helpText().length()) string_attributes[ATTR_HELP] = src.helpText(); if (src.keyboardShortcut().length()) string_attributes[ATTR_SHORTCUT] = src.keyboardShortcut(); - if (src.hasComputedStyle()) - string_attributes[ATTR_DISPLAY] = src.computedStyleDisplay(); if (!src.url().isEmpty()) string_attributes[ATTR_URL] = src.url().spec().utf16(); + if (role == ROLE_TREE_ITEM) + int_attributes[ATTR_HIERARCHICAL_LEVEL] = src.hierarchicalLevel(); + + if (role == ROLE_SLIDER) + include_children = false; + WebKit::WebNode node = src.node(); bool is_iframe = false; @@ -343,11 +728,11 @@ void WebAccessibility::Init(const WebKit::WebAccessibilityObject& src, // a WebElement method that returns the original lower cased tagName. string_attributes[ATTR_HTML_TAG] = StringToLowerASCII(string16(element.tagName())); - for (unsigned i = 0; i < element.attributes().length(); i++) { - html_attributes.push_back( - std::pair<string16, string16>( - element.attributes().attributeItem(i).localName(), - element.attributes().attributeItem(i).value())); + for (unsigned i = 0; i < element.attributes().length(); ++i) { + string16 name = StringToLowerASCII(string16( + element.attributes().attributeItem(i).localName())); + string16 value = element.attributes().attributeItem(i).value(); + html_attributes.push_back(std::pair<string16, string16>(name, value)); } if (element.isFormControlElement()) { @@ -363,10 +748,78 @@ void WebAccessibility::Init(const WebKit::WebAccessibilityObject& src, WebKit::WebVector<int> src_line_breaks; src.lineBreaks(src_line_breaks); line_breaks.reserve(src_line_breaks.size()); - for (size_t i = 0; i < src_line_breaks.size(); i++) + for (size_t i = 0; i < src_line_breaks.size(); ++i) line_breaks.push_back(src_line_breaks[i]); } } + + // ARIA role. + if (element.hasAttribute("role")) { + string_attributes[ATTR_ROLE] = element.getAttribute("role"); + } + + // Live region attributes + if (element.hasAttribute("aria-atomic")) { + bool_attributes[ATTR_LIVE_ATOMIC] = + LowerCaseEqualsASCII(element.getAttribute("aria-atomic"), "true"); + } + if (element.hasAttribute("aria-busy")) { + bool_attributes[ATTR_LIVE_BUSY] = + LowerCaseEqualsASCII(element.getAttribute("aria-busy"), "true"); + } + if (element.hasAttribute("aria-live")) { + string_attributes[ATTR_LIVE_STATUS] = element.getAttribute("aria-live"); + } + if (element.hasAttribute("aria-relevant")) { + string_attributes[ATTR_LIVE_RELEVANT] = + element.getAttribute("aria-relevant"); + } + } + + // Walk up the parent chain to set live region attributes of containers + + WebKit::WebAccessibilityObject container_accessible = src; + while (!container_accessible.isNull()) { + WebKit::WebNode container_node = container_accessible.node(); + if (!container_node.isNull() && container_node.isElementNode()) { + WebKit::WebElement container_elem = + container_node.to<WebKit::WebElement>(); + if (container_elem.hasAttribute("aria-atomic") && + bool_attributes.find(ATTR_CONTAINER_LIVE_ATOMIC) == + bool_attributes.end()) { + bool_attributes[ATTR_CONTAINER_LIVE_ATOMIC] = + LowerCaseEqualsASCII(container_elem.getAttribute("aria-atomic"), + "true"); + } + if (container_elem.hasAttribute("aria-busy") && + bool_attributes.find(ATTR_CONTAINER_LIVE_BUSY) == + bool_attributes.end()) { + bool_attributes[ATTR_CONTAINER_LIVE_BUSY] = + LowerCaseEqualsASCII(container_elem.getAttribute("aria-busy"), + "true"); + } + if (container_elem.hasAttribute("aria-live") && + string_attributes.find(ATTR_CONTAINER_LIVE_STATUS) == + string_attributes.end()) { + string_attributes[ATTR_CONTAINER_LIVE_STATUS] = + container_elem.getAttribute("aria-live"); + } + if (container_elem.hasAttribute("aria-relevant") && + string_attributes.find(ATTR_CONTAINER_LIVE_RELEVANT) == + string_attributes.end()) { + string_attributes[ATTR_CONTAINER_LIVE_RELEVANT] = + container_elem.getAttribute("aria-relevant"); + } + } + container_accessible = container_accessible.parentObject(); + } + + if (role == WebAccessibility::ROLE_PROGRESS_INDICATOR || + role == WebAccessibility::ROLE_SCROLLBAR || + role == WebAccessibility::ROLE_SLIDER) { + float_attributes[ATTR_VALUE_FOR_RANGE] = src.valueForRange(); + float_attributes[ATTR_MAX_VALUE_FOR_RANGE] = src.minValueForRange(); + float_attributes[ATTR_MIN_VALUE_FOR_RANGE] = src.maxValueForRange(); } if (role == WebAccessibility::ROLE_DOCUMENT || @@ -380,6 +833,9 @@ void WebAccessibility::Init(const WebKit::WebAccessibilityObject& src, string_attributes[ATTR_DOC_MIMETYPE] = WebKit::WebString("text/xhtml"); else string_attributes[ATTR_DOC_MIMETYPE] = WebKit::WebString("text/html"); + bool_attributes[ATTR_DOC_LOADED] = src.isLoaded(); + float_attributes[ATTR_DOC_LOADING_PROGRESS] = + src.estimatedLoadingProgress(); const WebKit::WebDocumentType& doctype = document.doctype(); if (!doctype.isNull()) @@ -394,14 +850,20 @@ void WebAccessibility::Init(const WebKit::WebAccessibilityObject& src, int column_count = src.columnCount(); int row_count = src.rowCount(); if (column_count > 0 && row_count > 0) { + std::set<int> unique_cell_id_set; int_attributes[ATTR_TABLE_COLUMN_COUNT] = column_count; int_attributes[ATTR_TABLE_ROW_COUNT] = row_count; - for (int i = 0; i < column_count * row_count; i++) { + for (int i = 0; i < column_count * row_count; ++i) { WebAccessibilityObject cell = src.cellForColumnAndRow( i % column_count, i / column_count); int cell_id = -1; - if (!cell.isNull()) + if (!cell.isNull()) { cell_id = cache->addOrGetId(cell); + if (unique_cell_id_set.find(cell_id) == unique_cell_id_set.end()) { + unique_cell_id_set.insert(cell_id); + unique_cell_ids.push_back(cell_id); + } + } cell_ids.push_back(cell_id); } } @@ -423,7 +885,7 @@ void WebAccessibility::Init(const WebKit::WebAccessibilityObject& src, // Recursively create children. int child_count = src.childCount(); std::set<int32> child_ids; - for (int i = 0; i < child_count; i++) { + for (int i = 0; i < child_count; ++i) { WebAccessibilityObject child = src.childAt(i); int32 child_id = cache->addOrGetId(child); diff --git a/webkit/glue/webaccessibility.h b/webkit/glue/webaccessibility.h index eb6350e..8a4cf40 100644 --- a/webkit/glue/webaccessibility.h +++ b/webkit/glue/webaccessibility.h @@ -6,6 +6,7 @@ #define WEBKIT_GLUE_WEBACCESSIBILITY_H_ #include <map> +#include <string> #include <vector> #include "base/string16.h" @@ -131,6 +132,7 @@ struct WebAccessibility { // for example: // int mask = (1 << STATE_CHECKED) | (1 << STATE_FOCUSED); enum State { + STATE_BUSY, STATE_CHECKED, STATE_COLLAPSED, STATE_EXPANDED, @@ -146,13 +148,18 @@ struct WebAccessibility { STATE_PRESSED, STATE_PROTECTED, STATE_READONLY, + STATE_REQUIRED, STATE_SELECTABLE, STATE_SELECTED, STATE_TRAVERSED, - STATE_BUSY, - STATE_UNAVAILABLE + STATE_UNAVAILABLE, + STATE_VERTICAL, + STATE_VISITED, + NUM_STATES }; + COMPILE_ASSERT(NUM_STATES <= 31, state_enum_not_too_large); + // Additional optional attributes that can be optionally attached to // a node. enum StringAttribute { @@ -163,14 +170,19 @@ struct WebAccessibility { ATTR_DOC_DOCTYPE, // Attributes that could apply to any node. + ATTR_ACCESS_KEY, ATTR_ACTION, + ATTR_CONTAINER_LIVE_RELEVANT, + ATTR_CONTAINER_LIVE_STATUS, ATTR_DESCRIPTION, ATTR_DISPLAY, ATTR_HELP, ATTR_HTML_TAG, + ATTR_LIVE_RELEVANT, + ATTR_LIVE_STATUS, + ATTR_ROLE, ATTR_SHORTCUT, ATTR_URL, - NUM_STRING_ATTRIBUTES }; enum IntAttribute { @@ -192,7 +204,32 @@ struct WebAccessibility { ATTR_TABLE_CELL_ROW_INDEX, ATTR_TABLE_CELL_ROW_SPAN, - NUM_INT_ATTRIBUTES + // Tree control attributes. + ATTR_HIERARCHICAL_LEVEL, + }; + + enum FloatAttribute { + // Document attributes. + ATTR_DOC_LOADING_PROGRESS, + + // Range attributes. + ATTR_VALUE_FOR_RANGE, + ATTR_MIN_VALUE_FOR_RANGE, + ATTR_MAX_VALUE_FOR_RANGE, + }; + + enum BoolAttribute { + // Document attributes. + ATTR_DOC_LOADED, + + // True if a checkbox or radio button is in the "mixed" state. + ATTR_BUTTON_MIXED, + + // Live region attributes. + ATTR_CONTAINER_LIVE_ATOMIC, + ATTR_CONTAINER_LIVE_BUSY, + ATTR_LIVE_ATOMIC, + ATTR_LIVE_BUSY, }; // Empty constructor, for serialization. @@ -207,6 +244,10 @@ struct WebAccessibility { ~WebAccessibility(); +#ifndef NDEBUG + std::string DebugString(bool recursive); +#endif + private: // Initialize an already-created struct, same as the constructor above. void Init(const WebKit::WebAccessibilityObject& src, @@ -231,11 +272,21 @@ struct WebAccessibility { gfx::Rect location; std::map<StringAttribute, string16> string_attributes; std::map<IntAttribute, int32> int_attributes; + std::map<FloatAttribute, float> float_attributes; + std::map<BoolAttribute, bool> bool_attributes; std::vector<WebAccessibility> children; std::vector<int32> indirect_child_ids; std::vector<std::pair<string16, string16> > html_attributes; std::vector<int32> line_breaks; - std::vector<int32> cell_ids; // For a table, the cell ids in row-major order. + + // For a table, the cell ids in row-major order, with duplicate entries + // when there's a rowspan or colspan, and with -1 for missing cells. + // There are always exactly rows * columns entries. + std::vector<int32> cell_ids; + + // For a table, the unique cell ids in row-major order of their first + // occurrence. + std::vector<int32> unique_cell_ids; }; } // namespace webkit_glue |