Home | History | Annotate | Download | only in common
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "content/common/accessibility_node_data.h"
      6 
      7 #include <set>
      8 
      9 #include "base/containers/hash_tables.h"
     10 #include "base/strings/string_number_conversions.h"
     11 #include "base/strings/string_util.h"
     12 #include "base/strings/utf_string_conversions.h"
     13 
     14 using base::DoubleToString;
     15 using base::IntToString;
     16 
     17 namespace {
     18 
     19 #ifndef NDEBUG
     20 std::string IntVectorToString(const std::vector<int>& items) {
     21   std::string str;
     22   for (size_t i = 0; i < items.size(); ++i) {
     23     if (i > 0)
     24       str += ",";
     25     str += IntToString(items[i]);
     26   }
     27   return str;
     28 }
     29 #endif
     30 
     31 }  // Anonymous namespace
     32 
     33 namespace content {
     34 
     35 AccessibilityNodeData::AccessibilityNodeData()
     36     : id(-1),
     37       role(ROLE_UNKNOWN),
     38       state(-1) {
     39 }
     40 
     41 AccessibilityNodeData::~AccessibilityNodeData() {
     42 }
     43 
     44 AccessibilityNodeDataTreeNode::AccessibilityNodeDataTreeNode()
     45   : AccessibilityNodeData() {
     46 }
     47 
     48 AccessibilityNodeDataTreeNode::~AccessibilityNodeDataTreeNode() {
     49 }
     50 
     51 AccessibilityNodeDataTreeNode& AccessibilityNodeDataTreeNode::operator=(
     52     const AccessibilityNodeData& src) {
     53   AccessibilityNodeData::operator=(src);
     54   return *this;
     55 }
     56 
     57 void MakeAccessibilityNodeDataTree(
     58     const std::vector<AccessibilityNodeData>& src_vector,
     59     AccessibilityNodeDataTreeNode* dst_root) {
     60   // This method assumes |src_vector| contains all of the nodes of
     61   // an accessibility tree, and that each parent comes before its
     62   // children. Each node has an id, and the ids of its children.
     63   // The output is a tree where each node contains its children.
     64 
     65   // Initialize a hash map with all of the ids in |src_vector|.
     66   base::hash_map<int32, AccessibilityNodeDataTreeNode*> id_map;
     67   for (size_t i = 0; i < src_vector.size(); ++i)
     68     id_map[src_vector[i].id] = NULL;
     69 
     70   // Copy the nodes to the output tree one at a time.
     71   for (size_t i = 0; i < src_vector.size(); ++i) {
     72     const AccessibilityNodeData& src_node = src_vector[i];
     73     AccessibilityNodeDataTreeNode* dst_node;
     74 
     75     // If it's the first element in the vector, assume it's
     76     // the root.  For any other element, look for it in our
     77     // hash map, and skip it if not there (meaning there was
     78     // an extranous node, or the nodes were sent in the wrong
     79     // order).
     80     if (i == 0) {
     81       dst_node = dst_root;
     82     } else {
     83       dst_node = id_map[src_node.id];
     84       if (!dst_node)
     85         continue;
     86     }
     87 
     88     // Copy the node data.
     89     *dst_node = src_node;
     90 
     91     // Add placeholders for all of the node's children in the tree,
     92     // and add them to the hash map so we can find them when we
     93     // encounter them in |src_vector|.
     94     dst_node->children.reserve(src_node.child_ids.size());
     95     for (size_t j = 0; j < src_node.child_ids.size(); ++j) {
     96       int child_id = src_node.child_ids[j];
     97       if (id_map.find(child_id) != id_map.end()) {
     98         dst_node->children.push_back(AccessibilityNodeDataTreeNode());
     99         id_map[child_id] = &dst_node->children.back();
    100       }
    101     }
    102   }
    103 }
    104 
    105 #ifndef NDEBUG
    106 std::string AccessibilityNodeData::DebugString(bool recursive) const {
    107   std::string result;
    108 
    109   result += "id=" + IntToString(id);
    110 
    111   switch (role) {
    112     case ROLE_ALERT: result += " ALERT"; break;
    113     case ROLE_ALERT_DIALOG: result += " ALERT_DIALOG"; break;
    114     case ROLE_ANNOTATION: result += " ANNOTATION"; break;
    115     case ROLE_APPLICATION: result += " APPLICATION"; break;
    116     case ROLE_ARTICLE: result += " ARTICLE"; break;
    117     case ROLE_BROWSER: result += " BROWSER"; break;
    118     case ROLE_BUSY_INDICATOR: result += " BUSY_INDICATOR"; break;
    119     case ROLE_BUTTON: result += " BUTTON"; break;
    120     case ROLE_CANVAS: result += " CANVAS"; break;
    121     case ROLE_CANVAS_WITH_FALLBACK_CONTENT: result += " CANVAS_FALLBACK"; break;
    122     case ROLE_CELL: result += " CELL"; break;
    123     case ROLE_CHECKBOX: result += " CHECKBOX"; break;
    124     case ROLE_COLOR_WELL: result += " COLOR_WELL"; break;
    125     case ROLE_COLUMN: result += " COLUMN"; break;
    126     case ROLE_COLUMN_HEADER: result += " COLUMN_HEADER"; break;
    127     case ROLE_COMBO_BOX: result += " COMBO_BOX"; break;
    128     case ROLE_DEFINITION: result += " DEFINITION"; break;
    129     case ROLE_DESCRIPTION_LIST_DETAIL: result += " DD"; break;
    130     case ROLE_DESCRIPTION_LIST_TERM: result += " DT"; break;
    131     case ROLE_DIALOG: result += " DIALOG"; break;
    132     case ROLE_DIRECTORY: result += " DIRECTORY"; break;
    133     case ROLE_DISCLOSURE_TRIANGLE: result += " DISCLOSURE_TRIANGLE"; break;
    134     case ROLE_DIV: result += " DIV"; break;
    135     case ROLE_DOCUMENT: result += " DOCUMENT"; break;
    136     case ROLE_DRAWER: result += " DRAWER"; break;
    137     case ROLE_EDITABLE_TEXT: result += " EDITABLE_TEXT"; break;
    138     case ROLE_FOOTER: result += " FOOTER"; break;
    139     case ROLE_FORM: result += " FORM"; break;
    140     case ROLE_GRID: result += " GRID"; break;
    141     case ROLE_GROUP: result += " GROUP"; break;
    142     case ROLE_GROW_AREA: result += " GROW_AREA"; break;
    143     case ROLE_HEADING: result += " HEADING"; break;
    144     case ROLE_HELP_TAG: result += " HELP_TAG"; break;
    145     case ROLE_HORIZONTAL_RULE: result += " HORIZONTAL_RULE"; break;
    146     case ROLE_IGNORED: result += " IGNORED"; break;
    147     case ROLE_IMAGE: result += " IMAGE"; break;
    148     case ROLE_IMAGE_MAP: result += " IMAGE_MAP"; break;
    149     case ROLE_IMAGE_MAP_LINK: result += " IMAGE_MAP_LINK"; break;
    150     case ROLE_INCREMENTOR: result += " INCREMENTOR"; break;
    151     case ROLE_LABEL: result += " LABEL"; break;
    152     case ROLE_LANDMARK_APPLICATION: result += " L_APPLICATION"; break;
    153     case ROLE_LANDMARK_BANNER: result += " L_BANNER"; break;
    154     case ROLE_LANDMARK_COMPLEMENTARY: result += " L_COMPLEMENTARY"; break;
    155     case ROLE_LANDMARK_CONTENTINFO: result += " L_CONTENTINFO"; break;
    156     case ROLE_LANDMARK_MAIN: result += " L_MAIN"; break;
    157     case ROLE_LANDMARK_NAVIGATION: result += " L_NAVIGATION"; break;
    158     case ROLE_LANDMARK_SEARCH: result += " L_SEARCH"; break;
    159     case ROLE_LINK: result += " LINK"; break;
    160     case ROLE_LIST: result += " LIST"; break;
    161     case ROLE_LISTBOX: result += " LISTBOX"; break;
    162     case ROLE_LISTBOX_OPTION: result += " LISTBOX_OPTION"; break;
    163     case ROLE_LIST_ITEM: result += " LIST_ITEM"; break;
    164     case ROLE_LIST_MARKER: result += " LIST_MARKER"; break;
    165     case ROLE_LOG: result += " LOG"; break;
    166     case ROLE_MARQUEE: result += " MARQUEE"; break;
    167     case ROLE_MATH: result += " MATH"; break;
    168     case ROLE_MATTE: result += " MATTE"; break;
    169     case ROLE_MENU: result += " MENU"; break;
    170     case ROLE_MENU_BAR: result += " MENU_BAR"; break;
    171     case ROLE_MENU_BUTTON: result += " MENU_BUTTON"; break;
    172     case ROLE_MENU_ITEM: result += " MENU_ITEM"; break;
    173     case ROLE_MENU_LIST_OPTION: result += " MENU_LIST_OPTION"; break;
    174     case ROLE_MENU_LIST_POPUP: result += " MENU_LIST_POPUP"; break;
    175     case ROLE_NOTE: result += " NOTE"; break;
    176     case ROLE_OUTLINE: result += " OUTLINE"; break;
    177     case ROLE_PARAGRAPH: result += " PARAGRAPH"; break;
    178     case ROLE_POPUP_BUTTON: result += " POPUP_BUTTON"; break;
    179     case ROLE_PRESENTATIONAL: result += " PRESENTATIONAL"; break;
    180     case ROLE_PROGRESS_INDICATOR: result += " PROGRESS_INDICATOR"; break;
    181     case ROLE_RADIO_BUTTON: result += " RADIO_BUTTON"; break;
    182     case ROLE_RADIO_GROUP: result += " RADIO_GROUP"; break;
    183     case ROLE_REGION: result += " REGION"; break;
    184     case ROLE_ROOT_WEB_AREA: result += " ROOT_WEB_AREA"; break;
    185     case ROLE_ROW: result += " ROW"; break;
    186     case ROLE_ROW_HEADER: result += " ROW_HEADER"; break;
    187     case ROLE_RULER: result += " RULER"; break;
    188     case ROLE_RULER_MARKER: result += " RULER_MARKER"; break;
    189     case ROLE_SCROLLAREA: result += " SCROLLAREA"; break;
    190     case ROLE_SCROLLBAR: result += " SCROLLBAR"; break;
    191     case ROLE_SHEET: result += " SHEET"; break;
    192     case ROLE_SLIDER: result += " SLIDER"; break;
    193     case ROLE_SLIDER_THUMB: result += " SLIDER_THUMB"; break;
    194     case ROLE_SPIN_BUTTON: result += " SPIN_BUTTON"; break;
    195     case ROLE_SPIN_BUTTON_PART: result += " SPIN_BUTTON_PART"; break;
    196     case ROLE_SPLITTER: result += " SPLITTER"; break;
    197     case ROLE_SPLIT_GROUP: result += " SPLIT_GROUP"; break;
    198     case ROLE_STATIC_TEXT: result += " STATIC_TEXT"; break;
    199     case ROLE_STATUS: result += " STATUS"; break;
    200     case ROLE_SVG_ROOT: result += " SVG_ROOT"; break;
    201     case ROLE_SYSTEM_WIDE: result += " SYSTEM_WIDE"; break;
    202     case ROLE_TAB: result += " TAB"; break;
    203     case ROLE_TABLE: result += " TABLE"; break;
    204     case ROLE_TABLE_HEADER_CONTAINER: result += " TABLE_HDR_CONTAINER"; break;
    205     case ROLE_TAB_GROUP_UNUSED: result += " TAB_GROUP_UNUSED"; break;
    206     case ROLE_TAB_LIST: result += " TAB_LIST"; break;
    207     case ROLE_TAB_PANEL: result += " TAB_PANEL"; break;
    208     case ROLE_TEXTAREA: result += " TEXTAREA"; break;
    209     case ROLE_TEXT_FIELD: result += " TEXT_FIELD"; break;
    210     case ROLE_TIMER: result += " TIMER"; break;
    211     case ROLE_TOGGLE_BUTTON: result += " TOGGLE_BUTTON"; break;
    212     case ROLE_TOOLBAR: result += " TOOLBAR"; break;
    213     case ROLE_TOOLTIP: result += " TOOLTIP"; break;
    214     case ROLE_TREE: result += " TREE"; break;
    215     case ROLE_TREE_GRID: result += " TREE_GRID"; break;
    216     case ROLE_TREE_ITEM: result += " TREE_ITEM"; break;
    217     case ROLE_UNKNOWN: result += " UNKNOWN"; break;
    218     case ROLE_VALUE_INDICATOR: result += " VALUE_INDICATOR"; break;
    219     case ROLE_WEBCORE_LINK: result += " WEBCORE_LINK"; break;
    220     case ROLE_WEB_AREA: result += " WEB_AREA"; break;
    221     case ROLE_WINDOW: result += " WINDOW"; break;
    222     default:
    223       assert(false);
    224   }
    225 
    226   if (state & (1 << STATE_BUSY))
    227     result += " BUSY";
    228   if (state & (1 << STATE_CHECKED))
    229     result += " CHECKED";
    230   if (state & (1 << STATE_COLLAPSED))
    231     result += " COLLAPSED";
    232   if (state & (1 << STATE_EXPANDED))
    233     result += " EXPANDED";
    234   if (state & (1 << STATE_FOCUSABLE))
    235     result += " FOCUSABLE";
    236   if (state & (1 << STATE_FOCUSED))
    237     result += " FOCUSED";
    238   if (state & (1 << STATE_HASPOPUP))
    239     result += " HASPOPUP";
    240   if (state & (1 << STATE_HOTTRACKED))
    241     result += " HOTTRACKED";
    242   if (state & (1 << STATE_INDETERMINATE))
    243     result += " INDETERMINATE";
    244   if (state & (1 << STATE_INVISIBLE))
    245     result += " INVISIBLE";
    246   if (state & (1 << STATE_LINKED))
    247     result += " LINKED";
    248   if (state & (1 << STATE_MULTISELECTABLE))
    249     result += " MULTISELECTABLE";
    250   if (state & (1 << STATE_OFFSCREEN))
    251     result += " OFFSCREEN";
    252   if (state & (1 << STATE_PRESSED))
    253     result += " PRESSED";
    254   if (state & (1 << STATE_PROTECTED))
    255     result += " PROTECTED";
    256   if (state & (1 << STATE_READONLY))
    257     result += " READONLY";
    258   if (state & (1 << STATE_REQUIRED))
    259     result += " REQUIRED";
    260   if (state & (1 << STATE_SELECTABLE))
    261     result += " SELECTABLE";
    262   if (state & (1 << STATE_SELECTED))
    263     result += " SELECTED";
    264   if (state & (1 << STATE_TRAVERSED))
    265     result += " TRAVERSED";
    266   if (state & (1 << STATE_UNAVAILABLE))
    267     result += " UNAVAILABLE";
    268   if (state & (1 << STATE_VERTICAL))
    269     result += " VERTICAL";
    270   if (state & (1 << STATE_VISITED))
    271     result += " VISITED";
    272 
    273   std::string tmp = UTF16ToUTF8(name);
    274   RemoveChars(tmp, "\n", &tmp);
    275   if (!tmp.empty())
    276     result += " name=" + tmp;
    277 
    278   tmp = UTF16ToUTF8(value);
    279   RemoveChars(tmp, "\n", &tmp);
    280   if (!tmp.empty())
    281     result += " value=" + tmp;
    282 
    283   result += " (" + IntToString(location.x()) + ", " +
    284                    IntToString(location.y()) + ")-(" +
    285                    IntToString(location.width()) + ", " +
    286                    IntToString(location.height()) + ")";
    287 
    288   for (std::map<IntAttribute, int32>::const_iterator iter =
    289            int_attributes.begin();
    290        iter != int_attributes.end();
    291        ++iter) {
    292     std::string value = IntToString(iter->second);
    293     switch (iter->first) {
    294       case ATTR_SCROLL_X:
    295         result += " scroll_x=" + value;
    296         break;
    297       case ATTR_SCROLL_X_MIN:
    298         result += " scroll_x_min=" + value;
    299         break;
    300       case ATTR_SCROLL_X_MAX:
    301         result += " scroll_x_max=" + value;
    302         break;
    303       case ATTR_SCROLL_Y:
    304         result += " scroll_y=" + value;
    305         break;
    306       case ATTR_SCROLL_Y_MIN:
    307         result += " scroll_y_min=" + value;
    308         break;
    309       case ATTR_SCROLL_Y_MAX:
    310         result += " scroll_y_max=" + value;
    311         break;
    312       case ATTR_HIERARCHICAL_LEVEL:
    313         result += " level=" + value;
    314         break;
    315       case ATTR_TEXT_SEL_START:
    316         result += " sel_start=" + value;
    317         break;
    318       case ATTR_TEXT_SEL_END:
    319         result += " sel_end=" + value;
    320         break;
    321       case ATTR_TABLE_ROW_COUNT:
    322         result += " rows=" + value;
    323         break;
    324       case ATTR_TABLE_COLUMN_COUNT:
    325         result += " cols=" + value;
    326         break;
    327       case ATTR_TABLE_CELL_COLUMN_INDEX:
    328         result += " col=" + value;
    329         break;
    330       case ATTR_TABLE_CELL_ROW_INDEX:
    331         result += " row=" + value;
    332         break;
    333       case ATTR_TABLE_CELL_COLUMN_SPAN:
    334         result += " colspan=" + value;
    335         break;
    336       case ATTR_TABLE_CELL_ROW_SPAN:
    337         result += " rowspan=" + value;
    338         break;
    339       case ATTR_TABLE_COLUMN_HEADER_ID:
    340         result += " column_header_id=" + value;
    341         break;
    342       case ATTR_TABLE_COLUMN_INDEX:
    343         result += " column_index=" + value;
    344         break;
    345       case ATTR_TABLE_HEADER_ID:
    346         result += " header_id=" + value;
    347         break;
    348       case ATTR_TABLE_ROW_HEADER_ID:
    349         result += " row_header_id=" + value;
    350         break;
    351       case ATTR_TABLE_ROW_INDEX:
    352         result += " row_index=" + value;
    353         break;
    354       case ATTR_TITLE_UI_ELEMENT:
    355         result += " title_elem=" + value;
    356         break;
    357       case ATTR_COLOR_VALUE_RED:
    358         result += " color_value_red=" + value;
    359         break;
    360       case ATTR_COLOR_VALUE_GREEN:
    361         result += " color_value_green=" + value;
    362         break;
    363       case ATTR_COLOR_VALUE_BLUE:
    364         result += " color_value_blue=" + value;
    365         break;
    366     }
    367   }
    368 
    369   for (std::map<StringAttribute, string16>::const_iterator iter =
    370            string_attributes.begin();
    371        iter != string_attributes.end();
    372        ++iter) {
    373     std::string value = UTF16ToUTF8(iter->second);
    374     switch (iter->first) {
    375       case ATTR_DOC_URL:
    376         result += " doc_url=" + value;
    377         break;
    378       case ATTR_DOC_TITLE:
    379         result += " doc_title=" + value;
    380         break;
    381       case ATTR_DOC_MIMETYPE:
    382         result += " doc_mimetype=" + value;
    383         break;
    384       case ATTR_DOC_DOCTYPE:
    385         result += " doc_doctype=" + value;
    386         break;
    387       case ATTR_ACCESS_KEY:
    388         result += " access_key=" + value;
    389         break;
    390       case ATTR_ACTION:
    391         result += " action=" + value;
    392         break;
    393       case ATTR_DESCRIPTION:
    394         result += " description=" + value;
    395         break;
    396       case ATTR_DISPLAY:
    397         result += " display=" + value;
    398         break;
    399       case ATTR_HELP:
    400         result += " help=" + value;
    401         break;
    402       case ATTR_HTML_TAG:
    403         result += " html_tag=" + value;
    404         break;
    405       case ATTR_LIVE_RELEVANT:
    406         result += " relevant=" + value;
    407         break;
    408       case ATTR_LIVE_STATUS:
    409         result += " live=" + value;
    410         break;
    411       case ATTR_CONTAINER_LIVE_RELEVANT:
    412         result += " container_relevant=" + value;
    413         break;
    414       case ATTR_CONTAINER_LIVE_STATUS:
    415         result += " container_live=" + value;
    416         break;
    417       case ATTR_ROLE:
    418         result += " role=" + value;
    419         break;
    420       case ATTR_SHORTCUT:
    421         result += " shortcut=" + value;
    422         break;
    423       case ATTR_URL:
    424         result += " url=" + value;
    425         break;
    426     }
    427   }
    428 
    429   for (std::map<FloatAttribute, float>::const_iterator iter =
    430            float_attributes.begin();
    431        iter != float_attributes.end();
    432        ++iter) {
    433     std::string value = DoubleToString(iter->second);
    434     switch (iter->first) {
    435       case ATTR_DOC_LOADING_PROGRESS:
    436         result += " doc_progress=" + value;
    437         break;
    438       case ATTR_VALUE_FOR_RANGE:
    439         result += " value_for_range=" + value;
    440         break;
    441       case ATTR_MAX_VALUE_FOR_RANGE:
    442         result += " max_value=" + value;
    443         break;
    444       case ATTR_MIN_VALUE_FOR_RANGE:
    445         result += " min_value=" + value;
    446         break;
    447     }
    448   }
    449 
    450   for (std::map<BoolAttribute, bool>::const_iterator iter =
    451            bool_attributes.begin();
    452        iter != bool_attributes.end();
    453        ++iter) {
    454     std::string value = iter->second ? "true" : "false";
    455     switch (iter->first) {
    456       case ATTR_DOC_LOADED:
    457         result += " doc_loaded=" + value;
    458         break;
    459       case ATTR_BUTTON_MIXED:
    460         result += " mixed=" + value;
    461         break;
    462       case ATTR_LIVE_ATOMIC:
    463         result += " atomic=" + value;
    464         break;
    465       case ATTR_LIVE_BUSY:
    466         result += " busy=" + value;
    467         break;
    468       case ATTR_CONTAINER_LIVE_ATOMIC:
    469         result += " container_atomic=" + value;
    470         break;
    471       case ATTR_CONTAINER_LIVE_BUSY:
    472         result += " container_busy=" + value;
    473         break;
    474       case ATTR_ARIA_READONLY:
    475         result += " aria_readonly=" + value;
    476         break;
    477       case ATTR_CAN_SET_VALUE:
    478         result += " can_set_value=" + value;
    479         break;
    480       case ATTR_UPDATE_LOCATION_ONLY:
    481         result += " update_location_only=" + value;
    482         break;
    483     }
    484   }
    485 
    486   if (!child_ids.empty())
    487     result += " child_ids=" + IntVectorToString(child_ids);
    488 
    489   if (!indirect_child_ids.empty())
    490     result += " indirect_child_ids=" + IntVectorToString(indirect_child_ids);
    491 
    492   if (!line_breaks.empty())
    493     result += " line_breaks=" + IntVectorToString(line_breaks);
    494 
    495   if (!cell_ids.empty())
    496     result += " cell_ids=" + IntVectorToString(cell_ids);
    497 
    498   return result;
    499 }
    500 
    501 std::string AccessibilityNodeDataTreeNode::DebugString(bool recursive) const {
    502   std::string result;
    503 
    504   static int indent = 0;
    505   result += "\n";
    506   for (int i = 0; i < indent; ++i)
    507     result += "  ";
    508 
    509   result += AccessibilityNodeData::DebugString(recursive);
    510 
    511   if (recursive) {
    512     result += "\n";
    513     ++indent;
    514     for (size_t i = 0; i < children.size(); ++i)
    515       result += children[i].DebugString(true);
    516     --indent;
    517   }
    518 
    519   return result;
    520 }
    521 
    522 #endif  // ifndef NDEBUG
    523 
    524 }  // namespace content
    525