Home | History | Annotate | Download | only in gtk
      1 /*
      2  * Copyright (C) 2008 Nuanti Ltd.
      3  * Copyright (C) 2009 Igalia S.L.
      4  * Copyright (C) 2009 Jan Alonzo
      5  *
      6  * Portions from Mozilla a11y, copyright as follows:
      7  *
      8  * The Original Code is mozilla.org code.
      9  *
     10  * The Initial Developer of the Original Code is
     11  * Sun Microsystems, Inc.
     12  * Portions created by the Initial Developer are Copyright (C) 2002
     13  * the Initial Developer. All Rights Reserved.
     14  *
     15  * This library is free software; you can redistribute it and/or
     16  * modify it under the terms of the GNU Library General Public
     17  * License as published by the Free Software Foundation; either
     18  * version 2 of the License, or (at your option) any later version.
     19  *
     20  * This library is distributed in the hope that it will be useful,
     21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     23  * Library General Public License for more details.
     24  *
     25  * You should have received a copy of the GNU Library General Public License
     26  * along with this library; see the file COPYING.LIB.  If not, write to
     27  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     28  * Boston, MA 02110-1301, USA.
     29  */
     30 
     31 #include "config.h"
     32 #include "AccessibilityObjectWrapperAtk.h"
     33 
     34 #if HAVE(ACCESSIBILITY)
     35 
     36 #include "AXObjectCache.h"
     37 #include "AccessibilityList.h"
     38 #include "AccessibilityListBox.h"
     39 #include "AccessibilityListBoxOption.h"
     40 #include "AccessibilityTable.h"
     41 #include "AccessibilityTableCell.h"
     42 #include "AccessibilityTableColumn.h"
     43 #include "AccessibilityTableRow.h"
     44 #include "CharacterNames.h"
     45 #include "Document.h"
     46 #include "DocumentType.h"
     47 #include "Editor.h"
     48 #include "Frame.h"
     49 #include "FrameView.h"
     50 #include "GOwnPtr.h"
     51 #include "HostWindow.h"
     52 #include "HTMLNames.h"
     53 #include "HTMLTableCaptionElement.h"
     54 #include "HTMLTableElement.h"
     55 #include "InlineTextBox.h"
     56 #include "IntRect.h"
     57 #include "NotImplemented.h"
     58 #include "RenderListItem.h"
     59 #include "RenderListMarker.h"
     60 #include "RenderText.h"
     61 #include "SelectElement.h"
     62 #include "Settings.h"
     63 #include "TextEncoding.h"
     64 #include "TextIterator.h"
     65 #include "WebKitAccessibleHyperlink.h"
     66 #include "htmlediting.h"
     67 #include "visible_units.h"
     68 
     69 #include <atk/atk.h>
     70 #include <glib.h>
     71 #include <glib/gprintf.h>
     72 #include <libgail-util/gail-util.h>
     73 #include <pango/pango.h>
     74 #include <wtf/text/AtomicString.h>
     75 #include <wtf/text/CString.h>
     76 
     77 using namespace WebCore;
     78 
     79 static AccessibilityObject* fallbackObject()
     80 {
     81     // FIXME: An AXObjectCache with a Document is meaningless.
     82     static AXObjectCache* fallbackCache = new AXObjectCache(0);
     83     static AccessibilityObject* object = 0;
     84     if (!object) {
     85         // FIXME: using fallbackCache->getOrCreate(ListBoxOptionRole) is a hack
     86         object = fallbackCache->getOrCreate(ListBoxOptionRole);
     87         object->ref();
     88     }
     89 
     90     return object;
     91 }
     92 
     93 // Used to provide const char* returns.
     94 static const char* returnString(const String& str)
     95 {
     96     static CString returnedString;
     97     returnedString = str.utf8();
     98     return returnedString.data();
     99 }
    100 
    101 static AccessibilityObject* core(WebKitAccessible* accessible)
    102 {
    103     if (!accessible)
    104         return 0;
    105 
    106     return accessible->m_object;
    107 }
    108 
    109 static AccessibilityObject* core(AtkObject* object)
    110 {
    111     if (!WEBKIT_IS_ACCESSIBLE(object))
    112         return 0;
    113 
    114     return core(WEBKIT_ACCESSIBLE(object));
    115 }
    116 
    117 static AccessibilityObject* core(AtkAction* action)
    118 {
    119     return core(ATK_OBJECT(action));
    120 }
    121 
    122 static AccessibilityObject* core(AtkSelection* selection)
    123 {
    124     return core(ATK_OBJECT(selection));
    125 }
    126 
    127 static AccessibilityObject* core(AtkText* text)
    128 {
    129     return core(ATK_OBJECT(text));
    130 }
    131 
    132 static AccessibilityObject* core(AtkEditableText* text)
    133 {
    134     return core(ATK_OBJECT(text));
    135 }
    136 
    137 static AccessibilityObject* core(AtkComponent* component)
    138 {
    139     return core(ATK_OBJECT(component));
    140 }
    141 
    142 static AccessibilityObject* core(AtkImage* image)
    143 {
    144     return core(ATK_OBJECT(image));
    145 }
    146 
    147 static AccessibilityObject* core(AtkTable* table)
    148 {
    149     return core(ATK_OBJECT(table));
    150 }
    151 
    152 static AccessibilityObject* core(AtkHypertext* hypertext)
    153 {
    154     return core(ATK_OBJECT(hypertext));
    155 }
    156 
    157 static AccessibilityObject* core(AtkDocument* document)
    158 {
    159     return core(ATK_OBJECT(document));
    160 }
    161 
    162 static AccessibilityObject* core(AtkValue* value)
    163 {
    164     return core(ATK_OBJECT(value));
    165 }
    166 
    167 static gchar* webkit_accessible_text_get_text(AtkText* text, gint startOffset, gint endOffset);
    168 
    169 static const gchar* webkit_accessible_get_name(AtkObject* object)
    170 {
    171     AccessibilityObject* coreObject = core(object);
    172     if (!coreObject->isAccessibilityRenderObject())
    173         return returnString(coreObject->stringValue());
    174 
    175     if (coreObject->isControl()) {
    176         AccessibilityObject* label = coreObject->correspondingLabelForControlElement();
    177         if (label) {
    178             AtkObject* atkObject = label->wrapper();
    179             if (ATK_IS_TEXT(atkObject))
    180                 return webkit_accessible_text_get_text(ATK_TEXT(atkObject), 0, -1);
    181         }
    182 
    183         // Try text under the node.
    184         String textUnder = coreObject->textUnderElement();
    185         if (textUnder.length())
    186             return returnString(textUnder);
    187     }
    188 
    189     if (coreObject->isImage() || coreObject->isInputImage()) {
    190         Node* node = coreObject->node();
    191         if (node && node->isHTMLElement()) {
    192             // Get the attribute rather than altText String so as not to fall back on title.
    193             String alt = toHTMLElement(node)->getAttribute(HTMLNames::altAttr);
    194             if (!alt.isEmpty())
    195                 return returnString(alt);
    196         }
    197     }
    198 
    199     // Fallback for the webArea object: just return the document's title.
    200     if (coreObject->isWebArea()) {
    201         Document* document = coreObject->document();
    202         if (document)
    203             return returnString(document->title());
    204     }
    205 
    206     return returnString(coreObject->stringValue());
    207 }
    208 
    209 static const gchar* webkit_accessible_get_description(AtkObject* object)
    210 {
    211     AccessibilityObject* coreObject = core(object);
    212     Node* node = 0;
    213     if (coreObject->isAccessibilityRenderObject())
    214         node = coreObject->node();
    215     if (!node || !node->isHTMLElement() || coreObject->ariaRoleAttribute() != UnknownRole)
    216         return returnString(coreObject->accessibilityDescription());
    217 
    218     // atk_table_get_summary returns an AtkObject. We have no summary object, so expose summary here.
    219     if (coreObject->roleValue() == TableRole) {
    220         String summary = static_cast<HTMLTableElement*>(node)->summary();
    221         if (!summary.isEmpty())
    222             return returnString(summary);
    223     }
    224 
    225     // The title attribute should be reliably available as the object's descripton.
    226     // We do not want to fall back on other attributes in its absence. See bug 25524.
    227     String title = toHTMLElement(node)->title();
    228     if (!title.isEmpty())
    229         return returnString(title);
    230 
    231     return returnString(coreObject->accessibilityDescription());
    232 }
    233 
    234 static void setAtkRelationSetFromCoreObject(AccessibilityObject* coreObject, AtkRelationSet* relationSet)
    235 {
    236     if (coreObject->isControl()) {
    237         AccessibilityObject* label = coreObject->correspondingLabelForControlElement();
    238         if (label)
    239             atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_LABELLED_BY, label->wrapper());
    240     } else {
    241         AccessibilityObject* control = coreObject->correspondingControlForLabelElement();
    242         if (control)
    243             atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_LABEL_FOR, control->wrapper());
    244     }
    245 }
    246 
    247 static gpointer webkit_accessible_parent_class = 0;
    248 
    249 static bool isRootObject(AccessibilityObject* coreObject)
    250 {
    251     // The root accessible object in WebCore is always an object with
    252     // the ScrolledArea role with one child with the WebArea role.
    253     if (!coreObject || !coreObject->isScrollView())
    254         return false;
    255 
    256     AccessibilityObject* firstChild = coreObject->firstChild();
    257     if (!firstChild || !firstChild->isWebArea())
    258         return false;
    259 
    260     return true;
    261 }
    262 
    263 static AtkObject* atkParentOfRootObject(AtkObject* object)
    264 {
    265     AccessibilityObject* coreObject = core(object);
    266     AccessibilityObject* coreParent = coreObject->parentObjectUnignored();
    267 
    268     // The top level object claims to not have a parent. This makes it
    269     // impossible for assistive technologies to ascend the accessible
    270     // hierarchy all the way to the application. (Bug 30489)
    271     if (!coreParent && isRootObject(coreObject)) {
    272         Document* document = coreObject->document();
    273         if (!document)
    274             return 0;
    275 
    276         HostWindow* hostWindow = document->view()->hostWindow();
    277         if (hostWindow) {
    278             PlatformPageClient scrollView = hostWindow->platformPageClient();
    279             if (scrollView) {
    280                 GtkWidget* scrollViewParent = gtk_widget_get_parent(scrollView);
    281                 if (scrollViewParent)
    282                     return gtk_widget_get_accessible(scrollViewParent);
    283             }
    284         }
    285     }
    286 
    287     if (!coreParent)
    288         return 0;
    289 
    290     return coreParent->wrapper();
    291 }
    292 
    293 static AtkObject* webkit_accessible_get_parent(AtkObject* object)
    294 {
    295     AccessibilityObject* coreObject = core(object);
    296     AccessibilityObject* coreParent = coreObject->parentObjectUnignored();
    297     if (!coreParent && isRootObject(coreObject))
    298         return atkParentOfRootObject(object);
    299 
    300     if (!coreParent)
    301         return 0;
    302 
    303     return coreParent->wrapper();
    304 }
    305 
    306 static gint webkit_accessible_get_n_children(AtkObject* object)
    307 {
    308     return core(object)->children().size();
    309 }
    310 
    311 static AtkObject* webkit_accessible_ref_child(AtkObject* object, gint index)
    312 {
    313     AccessibilityObject* coreObject = core(object);
    314     AccessibilityObject::AccessibilityChildrenVector children = coreObject->children();
    315     if (index < 0 || static_cast<unsigned>(index) >= children.size())
    316         return 0;
    317 
    318     AccessibilityObject* coreChild = children.at(index).get();
    319 
    320     if (!coreChild)
    321         return 0;
    322 
    323     AtkObject* child = coreChild->wrapper();
    324     atk_object_set_parent(child, object);
    325     g_object_ref(child);
    326 
    327     return child;
    328 }
    329 
    330 static gint webkit_accessible_get_index_in_parent(AtkObject* object)
    331 {
    332     AccessibilityObject* coreObject = core(object);
    333     AccessibilityObject* parent = coreObject->parentObjectUnignored();
    334 
    335     if (!parent && isRootObject(coreObject)) {
    336         AtkObject* atkParent = atkParentOfRootObject(object);
    337         if (!atkParent)
    338             return -1;
    339 
    340         unsigned count = atk_object_get_n_accessible_children(atkParent);
    341         for (unsigned i = 0; i < count; ++i) {
    342             AtkObject* child = atk_object_ref_accessible_child(atkParent, i);
    343             bool childIsObject = child == object;
    344             g_object_unref(child);
    345             if (childIsObject)
    346                 return i;
    347         }
    348     }
    349 
    350     AccessibilityObject::AccessibilityChildrenVector children = parent->children();
    351     unsigned count = children.size();
    352     for (unsigned i = 0; i < count; ++i) {
    353         if (children[i] == coreObject)
    354             return i;
    355     }
    356 
    357     return -1;
    358 }
    359 
    360 static AtkAttributeSet* addAttributeToSet(AtkAttributeSet* attributeSet, const char* name, const char* value)
    361 {
    362     AtkAttribute* attribute = static_cast<AtkAttribute*>(g_malloc(sizeof(AtkAttribute)));
    363     attribute->name = g_strdup(name);
    364     attribute->value = g_strdup(value);
    365     attributeSet = g_slist_prepend(attributeSet, attribute);
    366 
    367     return attributeSet;
    368 }
    369 
    370 static AtkAttributeSet* webkit_accessible_get_attributes(AtkObject* object)
    371 {
    372     AtkAttributeSet* attributeSet = 0;
    373     attributeSet = addAttributeToSet(attributeSet, "toolkit", "WebKitGtk");
    374 
    375     AccessibilityObject* coreObject = core(object);
    376     if (!coreObject)
    377         return attributeSet;
    378 
    379     int headingLevel = coreObject->headingLevel();
    380     if (headingLevel) {
    381         String value = String::number(headingLevel);
    382         attributeSet = addAttributeToSet(attributeSet, "level", value.utf8().data());
    383     }
    384 
    385     // Set the 'layout-guess' attribute to help Assistive
    386     // Technologies know when an exposed table is not data table.
    387     if (coreObject->isAccessibilityTable() && !coreObject->isDataTable())
    388         attributeSet = addAttributeToSet(attributeSet, "layout-guess", "true");
    389 
    390     return attributeSet;
    391 }
    392 
    393 static AtkRole atkRole(AccessibilityRole role)
    394 {
    395     switch (role) {
    396     case UnknownRole:
    397         return ATK_ROLE_UNKNOWN;
    398     case ButtonRole:
    399         return ATK_ROLE_PUSH_BUTTON;
    400     case RadioButtonRole:
    401         return ATK_ROLE_RADIO_BUTTON;
    402     case CheckBoxRole:
    403         return ATK_ROLE_CHECK_BOX;
    404     case SliderRole:
    405         return ATK_ROLE_SLIDER;
    406     case TabGroupRole:
    407         return ATK_ROLE_PAGE_TAB_LIST;
    408     case TextFieldRole:
    409     case TextAreaRole:
    410         return ATK_ROLE_ENTRY;
    411     case StaticTextRole:
    412         return ATK_ROLE_TEXT;
    413     case OutlineRole:
    414         return ATK_ROLE_TREE;
    415     case MenuBarRole:
    416         return ATK_ROLE_MENU_BAR;
    417     case MenuListPopupRole:
    418     case MenuRole:
    419         return ATK_ROLE_MENU;
    420     case MenuListOptionRole:
    421     case MenuItemRole:
    422         return ATK_ROLE_MENU_ITEM;
    423     case ColumnRole:
    424         //return ATK_ROLE_TABLE_COLUMN_HEADER; // Is this right?
    425         return ATK_ROLE_UNKNOWN; // Matches Mozilla
    426     case RowRole:
    427         //return ATK_ROLE_TABLE_ROW_HEADER; // Is this right?
    428         return ATK_ROLE_LIST_ITEM; // Matches Mozilla
    429     case ToolbarRole:
    430         return ATK_ROLE_TOOL_BAR;
    431     case BusyIndicatorRole:
    432         return ATK_ROLE_PROGRESS_BAR; // Is this right?
    433     case ProgressIndicatorRole:
    434         //return ATK_ROLE_SPIN_BUTTON; // Some confusion about this role in AccessibilityRenderObject.cpp
    435         return ATK_ROLE_PROGRESS_BAR;
    436     case WindowRole:
    437         return ATK_ROLE_WINDOW;
    438     case PopUpButtonRole:
    439     case ComboBoxRole:
    440         return ATK_ROLE_COMBO_BOX;
    441     case SplitGroupRole:
    442         return ATK_ROLE_SPLIT_PANE;
    443     case SplitterRole:
    444         return ATK_ROLE_SEPARATOR;
    445     case ColorWellRole:
    446         return ATK_ROLE_COLOR_CHOOSER;
    447     case ListRole:
    448         return ATK_ROLE_LIST;
    449     case ScrollBarRole:
    450         return ATK_ROLE_SCROLL_BAR;
    451     case ScrollAreaRole:
    452         return ATK_ROLE_SCROLL_PANE;
    453     case GridRole: // Is this right?
    454     case TableRole:
    455         return ATK_ROLE_TABLE;
    456     case ApplicationRole:
    457         return ATK_ROLE_APPLICATION;
    458     case GroupRole:
    459     case RadioGroupRole:
    460         return ATK_ROLE_PANEL;
    461     case RowHeaderRole: // Row headers are cells after all.
    462     case ColumnHeaderRole: // Column headers are cells after all.
    463     case CellRole:
    464         return ATK_ROLE_TABLE_CELL;
    465     case LinkRole:
    466     case WebCoreLinkRole:
    467     case ImageMapLinkRole:
    468         return ATK_ROLE_LINK;
    469     case ImageMapRole:
    470     case ImageRole:
    471         return ATK_ROLE_IMAGE;
    472     case ListMarkerRole:
    473         return ATK_ROLE_TEXT;
    474     case WebAreaRole:
    475         //return ATK_ROLE_HTML_CONTAINER; // Is this right?
    476         return ATK_ROLE_DOCUMENT_FRAME;
    477     case HeadingRole:
    478         return ATK_ROLE_HEADING;
    479     case ListBoxRole:
    480         return ATK_ROLE_LIST;
    481     case ListItemRole:
    482     case ListBoxOptionRole:
    483         return ATK_ROLE_LIST_ITEM;
    484     case ParagraphRole:
    485         return ATK_ROLE_PARAGRAPH;
    486     case LabelRole:
    487         return ATK_ROLE_LABEL;
    488     case DivRole:
    489         return ATK_ROLE_SECTION;
    490     case FormRole:
    491         return ATK_ROLE_FORM;
    492     default:
    493         return ATK_ROLE_UNKNOWN;
    494     }
    495 }
    496 
    497 static AtkRole webkit_accessible_get_role(AtkObject* object)
    498 {
    499     AccessibilityObject* coreObject = core(object);
    500 
    501     if (!coreObject)
    502         return ATK_ROLE_UNKNOWN;
    503 
    504     // Note: Why doesn't WebCore have a password field for this
    505     if (coreObject->isPasswordField())
    506         return ATK_ROLE_PASSWORD_TEXT;
    507 
    508     return atkRole(coreObject->roleValue());
    509 }
    510 
    511 static bool selectionBelongsToObject(AccessibilityObject* coreObject, VisibleSelection& selection)
    512 {
    513     if (!coreObject || !coreObject->isAccessibilityRenderObject())
    514         return false;
    515 
    516     if (selection.isNone())
    517         return false;
    518 
    519     RefPtr<Range> range = selection.toNormalizedRange();
    520     if (!range)
    521         return false;
    522 
    523     // We want to check that both the selection intersects the node
    524     // AND that the selection is not just "touching" one of the
    525     // boundaries for the selected node. We want to check whether the
    526     // node is actually inside the region, at least partially.
    527     Node* node = coreObject->node();
    528     Node* lastDescendant = node->lastDescendant();
    529     ExceptionCode ec = 0;
    530     return (range->intersectsNode(node, ec)
    531             && (range->endContainer() != node || range->endOffset())
    532             && (range->startContainer() != lastDescendant || range->startOffset() != lastOffsetInNode(lastDescendant)));
    533 }
    534 
    535 static bool isTextWithCaret(AccessibilityObject* coreObject)
    536 {
    537     if (!coreObject || !coreObject->isAccessibilityRenderObject())
    538         return false;
    539 
    540     Document* document = coreObject->document();
    541     if (!document)
    542         return false;
    543 
    544     Frame* frame = document->frame();
    545     if (!frame)
    546         return false;
    547 
    548     Settings* settings = frame->settings();
    549     if (!settings || !settings->caretBrowsingEnabled())
    550         return false;
    551 
    552     // Check text objects and paragraphs only.
    553     AtkObject* axObject = coreObject->wrapper();
    554     AtkRole role = axObject ? atk_object_get_role(axObject) : ATK_ROLE_INVALID;
    555     if (role != ATK_ROLE_TEXT && role != ATK_ROLE_PARAGRAPH)
    556         return false;
    557 
    558     // Finally, check whether the caret is set in the current object.
    559     VisibleSelection selection = coreObject->selection();
    560     if (!selection.isCaret())
    561         return false;
    562 
    563     return selectionBelongsToObject(coreObject, selection);
    564 }
    565 
    566 static void setAtkStateSetFromCoreObject(AccessibilityObject* coreObject, AtkStateSet* stateSet)
    567 {
    568     AccessibilityObject* parent = coreObject->parentObject();
    569     bool isListBoxOption = parent && parent->isListBox();
    570 
    571     // Please keep the state list in alphabetical order
    572     if (coreObject->isChecked())
    573         atk_state_set_add_state(stateSet, ATK_STATE_CHECKED);
    574 
    575     // FIXME: isReadOnly does not seem to do the right thing for
    576     // controls, so check explicitly for them. In addition, because
    577     // isReadOnly is false for listBoxOptions, we need to add one
    578     // more check so that we do not present them as being "editable".
    579     if ((!coreObject->isReadOnly() ||
    580         (coreObject->isControl() && coreObject->canSetValueAttribute())) &&
    581         !isListBoxOption)
    582         atk_state_set_add_state(stateSet, ATK_STATE_EDITABLE);
    583 
    584     // FIXME: Put both ENABLED and SENSITIVE together here for now
    585     if (coreObject->isEnabled()) {
    586         atk_state_set_add_state(stateSet, ATK_STATE_ENABLED);
    587         atk_state_set_add_state(stateSet, ATK_STATE_SENSITIVE);
    588     }
    589 
    590     if (coreObject->canSetExpandedAttribute())
    591         atk_state_set_add_state(stateSet, ATK_STATE_EXPANDABLE);
    592 
    593     if (coreObject->isExpanded())
    594         atk_state_set_add_state(stateSet, ATK_STATE_EXPANDED);
    595 
    596     if (coreObject->canSetFocusAttribute())
    597         atk_state_set_add_state(stateSet, ATK_STATE_FOCUSABLE);
    598 
    599     if (coreObject->isFocused() || isTextWithCaret(coreObject))
    600         atk_state_set_add_state(stateSet, ATK_STATE_FOCUSED);
    601 
    602     // TODO: ATK_STATE_HORIZONTAL
    603 
    604     if (coreObject->isIndeterminate())
    605         atk_state_set_add_state(stateSet, ATK_STATE_INDETERMINATE);
    606 
    607     if (coreObject->isMultiSelectable())
    608         atk_state_set_add_state(stateSet, ATK_STATE_MULTISELECTABLE);
    609 
    610     // TODO: ATK_STATE_OPAQUE
    611 
    612     if (coreObject->isPressed())
    613         atk_state_set_add_state(stateSet, ATK_STATE_PRESSED);
    614 
    615     // TODO: ATK_STATE_SELECTABLE_TEXT
    616 
    617     if (coreObject->canSetSelectedAttribute()) {
    618         atk_state_set_add_state(stateSet, ATK_STATE_SELECTABLE);
    619         // Items in focusable lists in Gtk have both STATE_SELECT{ABLE,ED}
    620         // and STATE_FOCUS{ABLE,ED}. We'll fake the latter based on the
    621         // former.
    622         if (isListBoxOption)
    623             atk_state_set_add_state(stateSet, ATK_STATE_FOCUSABLE);
    624     }
    625 
    626     if (coreObject->isSelected()) {
    627         atk_state_set_add_state(stateSet, ATK_STATE_SELECTED);
    628         // Items in focusable lists in Gtk have both STATE_SELECT{ABLE,ED}
    629         // and STATE_FOCUS{ABLE,ED}. We'll fake the latter based on the
    630         // former.
    631         if (isListBoxOption)
    632             atk_state_set_add_state(stateSet, ATK_STATE_FOCUSED);
    633     }
    634 
    635     // FIXME: Group both SHOWING and VISIBLE here for now
    636     // Not sure how to handle this in WebKit, see bug
    637     // http://bugzilla.gnome.org/show_bug.cgi?id=509650 for other
    638     // issues with SHOWING vs VISIBLE within GTK+
    639     if (!coreObject->isOffScreen()) {
    640         atk_state_set_add_state(stateSet, ATK_STATE_SHOWING);
    641         atk_state_set_add_state(stateSet, ATK_STATE_VISIBLE);
    642     }
    643 
    644     // Mutually exclusive, so we group these two
    645     if (coreObject->roleValue() == TextFieldRole)
    646         atk_state_set_add_state(stateSet, ATK_STATE_SINGLE_LINE);
    647     else if (coreObject->roleValue() == TextAreaRole)
    648         atk_state_set_add_state(stateSet, ATK_STATE_MULTI_LINE);
    649 
    650     // TODO: ATK_STATE_SENSITIVE
    651 
    652     // TODO: ATK_STATE_VERTICAL
    653 
    654     if (coreObject->isVisited())
    655         atk_state_set_add_state(stateSet, ATK_STATE_VISITED);
    656 }
    657 
    658 static AtkStateSet* webkit_accessible_ref_state_set(AtkObject* object)
    659 {
    660     AtkStateSet* stateSet = ATK_OBJECT_CLASS(webkit_accessible_parent_class)->ref_state_set(object);
    661     AccessibilityObject* coreObject = core(object);
    662 
    663     if (coreObject == fallbackObject()) {
    664         atk_state_set_add_state(stateSet, ATK_STATE_DEFUNCT);
    665         return stateSet;
    666     }
    667 
    668     // Text objects must be focusable.
    669     AtkRole role = atk_object_get_role(object);
    670     if (role == ATK_ROLE_TEXT || role == ATK_ROLE_PARAGRAPH)
    671         atk_state_set_add_state(stateSet, ATK_STATE_FOCUSABLE);
    672 
    673     setAtkStateSetFromCoreObject(coreObject, stateSet);
    674     return stateSet;
    675 }
    676 
    677 static AtkRelationSet* webkit_accessible_ref_relation_set(AtkObject* object)
    678 {
    679     AtkRelationSet* relationSet = ATK_OBJECT_CLASS(webkit_accessible_parent_class)->ref_relation_set(object);
    680     AccessibilityObject* coreObject = core(object);
    681 
    682     setAtkRelationSetFromCoreObject(coreObject, relationSet);
    683 
    684     return relationSet;
    685 }
    686 
    687 static void webkit_accessible_init(AtkObject* object, gpointer data)
    688 {
    689     if (ATK_OBJECT_CLASS(webkit_accessible_parent_class)->initialize)
    690         ATK_OBJECT_CLASS(webkit_accessible_parent_class)->initialize(object, data);
    691 
    692     WEBKIT_ACCESSIBLE(object)->m_object = reinterpret_cast<AccessibilityObject*>(data);
    693 }
    694 
    695 static void webkit_accessible_finalize(GObject* object)
    696 {
    697     // This is a good time to clear the return buffer.
    698     returnString(String());
    699 
    700     G_OBJECT_CLASS(webkit_accessible_parent_class)->finalize(object);
    701 }
    702 
    703 static void webkit_accessible_class_init(AtkObjectClass* klass)
    704 {
    705     GObjectClass* gobjectClass = G_OBJECT_CLASS(klass);
    706 
    707     webkit_accessible_parent_class = g_type_class_peek_parent(klass);
    708 
    709     gobjectClass->finalize = webkit_accessible_finalize;
    710 
    711     klass->initialize = webkit_accessible_init;
    712     klass->get_name = webkit_accessible_get_name;
    713     klass->get_description = webkit_accessible_get_description;
    714     klass->get_parent = webkit_accessible_get_parent;
    715     klass->get_n_children = webkit_accessible_get_n_children;
    716     klass->ref_child = webkit_accessible_ref_child;
    717     klass->get_role = webkit_accessible_get_role;
    718     klass->ref_state_set = webkit_accessible_ref_state_set;
    719     klass->get_index_in_parent = webkit_accessible_get_index_in_parent;
    720     klass->get_attributes = webkit_accessible_get_attributes;
    721     klass->ref_relation_set = webkit_accessible_ref_relation_set;
    722 }
    723 
    724 GType
    725 webkit_accessible_get_type(void)
    726 {
    727     static volatile gsize type_volatile = 0;
    728 
    729     if (g_once_init_enter(&type_volatile)) {
    730         static const GTypeInfo tinfo = {
    731             sizeof(WebKitAccessibleClass),
    732             (GBaseInitFunc) 0,
    733             (GBaseFinalizeFunc) 0,
    734             (GClassInitFunc) webkit_accessible_class_init,
    735             (GClassFinalizeFunc) 0,
    736             0, /* class data */
    737             sizeof(WebKitAccessible), /* instance size */
    738             0, /* nb preallocs */
    739             (GInstanceInitFunc) 0,
    740             0 /* value table */
    741         };
    742 
    743         GType type = g_type_register_static(ATK_TYPE_OBJECT,
    744                                             "WebKitAccessible", &tinfo, GTypeFlags(0));
    745         g_once_init_leave(&type_volatile, type);
    746     }
    747 
    748     return type_volatile;
    749 }
    750 
    751 static gboolean webkit_accessible_action_do_action(AtkAction* action, gint i)
    752 {
    753     g_return_val_if_fail(i == 0, FALSE);
    754     return core(action)->performDefaultAction();
    755 }
    756 
    757 static gint webkit_accessible_action_get_n_actions(AtkAction* action)
    758 {
    759     return 1;
    760 }
    761 
    762 static const gchar* webkit_accessible_action_get_description(AtkAction* action, gint i)
    763 {
    764     g_return_val_if_fail(i == 0, 0);
    765     // TODO: Need a way to provide/localize action descriptions.
    766     notImplemented();
    767     return "";
    768 }
    769 
    770 static const gchar* webkit_accessible_action_get_keybinding(AtkAction* action, gint i)
    771 {
    772     g_return_val_if_fail(i == 0, 0);
    773     // FIXME: Construct a proper keybinding string.
    774     return returnString(core(action)->accessKey().string());
    775 }
    776 
    777 static const gchar* webkit_accessible_action_get_name(AtkAction* action, gint i)
    778 {
    779     g_return_val_if_fail(i == 0, 0);
    780     return returnString(core(action)->actionVerb());
    781 }
    782 
    783 static void atk_action_interface_init(AtkActionIface* iface)
    784 {
    785     iface->do_action = webkit_accessible_action_do_action;
    786     iface->get_n_actions = webkit_accessible_action_get_n_actions;
    787     iface->get_description = webkit_accessible_action_get_description;
    788     iface->get_keybinding = webkit_accessible_action_get_keybinding;
    789     iface->get_name = webkit_accessible_action_get_name;
    790 }
    791 
    792 // Selection (for controls)
    793 
    794 static AccessibilityObject* listObjectForSelection(AtkSelection* selection)
    795 {
    796     AccessibilityObject* coreSelection = core(selection);
    797 
    798     // Only list boxes and menu lists supported so far.
    799     if (!coreSelection->isListBox() && !coreSelection->isMenuList())
    800         return 0;
    801 
    802     // For list boxes the list object is just itself.
    803     if (coreSelection->isListBox())
    804         return coreSelection;
    805 
    806     // For menu lists we need to return the first accessible child,
    807     // with role MenuListPopupRole, since that's the one holding the list
    808     // of items with role MenuListOptionRole.
    809     AccessibilityObject::AccessibilityChildrenVector children = coreSelection->children();
    810     if (!children.size())
    811         return 0;
    812 
    813     AccessibilityObject* listObject = children.at(0).get();
    814     if (!listObject->isMenuListPopup())
    815         return 0;
    816 
    817     return listObject;
    818 }
    819 
    820 static AccessibilityObject* optionFromList(AtkSelection* selection, gint i)
    821 {
    822     AccessibilityObject* coreSelection = core(selection);
    823     if (!coreSelection || i < 0)
    824         return 0;
    825 
    826     // Need to select the proper list object depending on the type.
    827     AccessibilityObject* listObject = listObjectForSelection(selection);
    828     if (!listObject)
    829         return 0;
    830 
    831     AccessibilityObject::AccessibilityChildrenVector options = listObject->children();
    832     if (i < static_cast<gint>(options.size()))
    833         return options.at(i).get();
    834 
    835     return 0;
    836 }
    837 
    838 static AccessibilityObject* optionFromSelection(AtkSelection* selection, gint i)
    839 {
    840     // i is the ith selection as opposed to the ith child.
    841 
    842     AccessibilityObject* coreSelection = core(selection);
    843     if (!coreSelection || !coreSelection->isAccessibilityRenderObject() || i < 0)
    844         return 0;
    845 
    846     AccessibilityObject::AccessibilityChildrenVector selectedItems;
    847     if (coreSelection->isListBox())
    848         coreSelection->selectedChildren(selectedItems);
    849     else if (coreSelection->isMenuList()) {
    850         RenderObject* renderer = coreSelection->renderer();
    851         if (!renderer)
    852             return 0;
    853 
    854         SelectElement* selectNode = toSelectElement(static_cast<Element*>(renderer->node()));
    855         int selectedIndex = selectNode->selectedIndex();
    856         const Vector<Element*> listItems = selectNode->listItems();
    857 
    858         if (selectedIndex < 0 || selectedIndex >= static_cast<int>(listItems.size()))
    859             return 0;
    860 
    861         return optionFromList(selection, selectedIndex);
    862     }
    863 
    864     if (i < static_cast<gint>(selectedItems.size()))
    865         return selectedItems.at(i).get();
    866 
    867     return 0;
    868 }
    869 
    870 static gboolean webkit_accessible_selection_add_selection(AtkSelection* selection, gint i)
    871 {
    872     AccessibilityObject* coreSelection = core(selection);
    873     if (!coreSelection)
    874         return false;
    875 
    876     AccessibilityObject* option = optionFromList(selection, i);
    877     if (option && (coreSelection->isListBox() || coreSelection->isMenuList())) {
    878         option->setSelected(true);
    879         return option->isSelected();
    880     }
    881 
    882     return false;
    883 }
    884 
    885 static gboolean webkit_accessible_selection_clear_selection(AtkSelection* selection)
    886 {
    887     AccessibilityObject* coreSelection = core(selection);
    888     if (!coreSelection)
    889         return false;
    890 
    891     AccessibilityObject::AccessibilityChildrenVector selectedItems;
    892     if (coreSelection->isListBox() || coreSelection->isMenuList()) {
    893         // Set the list of selected items to an empty list; then verify that it worked.
    894         AccessibilityListBox* listBox = static_cast<AccessibilityListBox*>(coreSelection);
    895         listBox->setSelectedChildren(selectedItems);
    896         listBox->selectedChildren(selectedItems);
    897         return selectedItems.size() == 0;
    898     }
    899     return false;
    900 }
    901 
    902 static AtkObject* webkit_accessible_selection_ref_selection(AtkSelection* selection, gint i)
    903 {
    904     AccessibilityObject* option = optionFromSelection(selection, i);
    905     if (option) {
    906         AtkObject* child = option->wrapper();
    907         g_object_ref(child);
    908         return child;
    909     }
    910 
    911     return 0;
    912 }
    913 
    914 static gint webkit_accessible_selection_get_selection_count(AtkSelection* selection)
    915 {
    916     AccessibilityObject* coreSelection = core(selection);
    917     if (!coreSelection || !coreSelection->isAccessibilityRenderObject())
    918         return 0;
    919 
    920     if (coreSelection->isListBox()) {
    921         AccessibilityObject::AccessibilityChildrenVector selectedItems;
    922         coreSelection->selectedChildren(selectedItems);
    923         return static_cast<gint>(selectedItems.size());
    924     }
    925 
    926     if (coreSelection->isMenuList()) {
    927         RenderObject* renderer = coreSelection->renderer();
    928         if (!renderer)
    929             return 0;
    930 
    931         SelectElement* selectNode = toSelectElement(static_cast<Element*>(renderer->node()));
    932         int selectedIndex = selectNode->selectedIndex();
    933         const Vector<Element*> listItems = selectNode->listItems();
    934 
    935         return selectedIndex >= 0 && selectedIndex < static_cast<int>(listItems.size());
    936     }
    937 
    938     return 0;
    939 }
    940 
    941 static gboolean webkit_accessible_selection_is_child_selected(AtkSelection* selection, gint i)
    942 {
    943     AccessibilityObject* coreSelection = core(selection);
    944     if (!coreSelection)
    945         return 0;
    946 
    947     AccessibilityObject* option = optionFromList(selection, i);
    948     if (option && (coreSelection->isListBox() || coreSelection->isMenuList()))
    949         return option->isSelected();
    950 
    951     return false;
    952 }
    953 
    954 static gboolean webkit_accessible_selection_remove_selection(AtkSelection* selection, gint i)
    955 {
    956     AccessibilityObject* coreSelection = core(selection);
    957     if (!coreSelection)
    958         return 0;
    959 
    960     // TODO: This is only getting called if i == 0. What is preventing the rest?
    961     AccessibilityObject* option = optionFromSelection(selection, i);
    962     if (option && (coreSelection->isListBox() || coreSelection->isMenuList())) {
    963         option->setSelected(false);
    964         return !option->isSelected();
    965     }
    966 
    967     return false;
    968 }
    969 
    970 static gboolean webkit_accessible_selection_select_all_selection(AtkSelection* selection)
    971 {
    972     AccessibilityObject* coreSelection = core(selection);
    973     if (!coreSelection || !coreSelection->isMultiSelectable())
    974         return false;
    975 
    976     AccessibilityObject::AccessibilityChildrenVector children = coreSelection->children();
    977     if (coreSelection->isListBox()) {
    978         AccessibilityListBox* listBox = static_cast<AccessibilityListBox*>(coreSelection);
    979         listBox->setSelectedChildren(children);
    980         AccessibilityObject::AccessibilityChildrenVector selectedItems;
    981         listBox->selectedChildren(selectedItems);
    982         return selectedItems.size() == children.size();
    983     }
    984 
    985     return false;
    986 }
    987 
    988 static void atk_selection_interface_init(AtkSelectionIface* iface)
    989 {
    990     iface->add_selection = webkit_accessible_selection_add_selection;
    991     iface->clear_selection = webkit_accessible_selection_clear_selection;
    992     iface->ref_selection = webkit_accessible_selection_ref_selection;
    993     iface->get_selection_count = webkit_accessible_selection_get_selection_count;
    994     iface->is_child_selected = webkit_accessible_selection_is_child_selected;
    995     iface->remove_selection = webkit_accessible_selection_remove_selection;
    996     iface->select_all_selection = webkit_accessible_selection_select_all_selection;
    997 }
    998 
    999 // Text
   1000 
   1001 static gchar* utf8Substr(const gchar* string, gint start, gint end)
   1002 {
   1003     ASSERT(string);
   1004     glong strLen = g_utf8_strlen(string, -1);
   1005     if (start > strLen || end > strLen)
   1006         return 0;
   1007     gchar* startPtr = g_utf8_offset_to_pointer(string, start);
   1008     gsize lenInBytes = g_utf8_offset_to_pointer(string, end + 1) -  startPtr;
   1009     gchar* output = static_cast<gchar*>(g_malloc0(lenInBytes + 1));
   1010     return g_utf8_strncpy(output, startPtr, end - start + 1);
   1011 }
   1012 
   1013 // This function is not completely general, is it's tied to the
   1014 // internals of WebCore's text presentation.
   1015 static gchar* convertUniCharToUTF8(const UChar* characters, gint length, int from, int to)
   1016 {
   1017     CString stringUTF8 = UTF8Encoding().encode(characters, length, QuestionMarksForUnencodables);
   1018     gchar* utf8String = utf8Substr(stringUTF8.data(), from, to);
   1019     if (!g_utf8_validate(utf8String, -1, 0)) {
   1020         g_free(utf8String);
   1021         return 0;
   1022     }
   1023     gsize len = strlen(utf8String);
   1024     GString* ret = g_string_new_len(0, len);
   1025     gchar* ptr = utf8String;
   1026 
   1027     // WebCore introduces line breaks in the text that do not reflect
   1028     // the layout you see on the screen, replace them with spaces
   1029     while (len > 0) {
   1030         gint index, start;
   1031         pango_find_paragraph_boundary(ptr, len, &index, &start);
   1032         g_string_append_len(ret, ptr, index);
   1033         if (index == start)
   1034             break;
   1035         g_string_append_c(ret, ' ');
   1036         ptr += start;
   1037         len -= start;
   1038     }
   1039 
   1040     g_free(utf8String);
   1041     return g_string_free(ret, FALSE);
   1042 }
   1043 
   1044 gchar* textForRenderer(RenderObject* renderer)
   1045 {
   1046     GString* resultText = g_string_new(0);
   1047 
   1048     if (!renderer)
   1049         return g_string_free(resultText, FALSE);
   1050 
   1051     // For RenderBlocks, piece together the text from the RenderText objects they contain.
   1052     for (RenderObject* object = renderer->firstChild(); object; object = object->nextSibling()) {
   1053         if (object->isBR()) {
   1054             g_string_append(resultText, "\n");
   1055             continue;
   1056         }
   1057 
   1058         RenderText* renderText;
   1059         if (object->isText())
   1060             renderText = toRenderText(object);
   1061         else {
   1062             if (object->isReplaced())
   1063                 g_string_append_unichar(resultText, objectReplacementCharacter);
   1064 
   1065             // We need to check children, if any, to consider when
   1066             // current object is not a text object but some of its
   1067             // children are, in order not to miss those portions of
   1068             // text by not properly handling those situations
   1069             if (object->firstChild())
   1070                 g_string_append(resultText, textForRenderer(object));
   1071 
   1072             continue;
   1073         }
   1074 
   1075         InlineTextBox* box = renderText ? renderText->firstTextBox() : 0;
   1076         while (box) {
   1077             gchar* text = convertUniCharToUTF8(renderText->characters(), renderText->textLength(), box->start(), box->end());
   1078             g_string_append(resultText, text);
   1079             // Newline chars in the source result in separate text boxes, so check
   1080             // before adding a newline in the layout. See bug 25415 comment #78.
   1081             // If the next sibling is a BR, we'll add the newline when we examine that child.
   1082             if (!box->nextOnLineExists() && (!object->nextSibling() || !object->nextSibling()->isBR()))
   1083                 g_string_append(resultText, "\n");
   1084             box = box->nextTextBox();
   1085         }
   1086     }
   1087 
   1088     // Insert the text of the marker for list item in the right place, if present
   1089     if (renderer->isListItem()) {
   1090         String markerText = toRenderListItem(renderer)->markerTextWithSuffix();
   1091         if (renderer->style()->direction() == LTR)
   1092             g_string_prepend(resultText, markerText.utf8().data());
   1093         else
   1094             g_string_append(resultText, markerText.utf8().data());
   1095     }
   1096 
   1097     return g_string_free(resultText, FALSE);
   1098 }
   1099 
   1100 gchar* textForObject(AccessibilityObject* coreObject)
   1101 {
   1102     GString* str = g_string_new(0);
   1103 
   1104     // For text controls, we can get the text line by line.
   1105     if (coreObject->isTextControl()) {
   1106         unsigned textLength = coreObject->textLength();
   1107         int lineNumber = 0;
   1108         PlainTextRange range = coreObject->doAXRangeForLine(lineNumber);
   1109         while (range.length) {
   1110             // When a line of text wraps in a text area, the final space is removed.
   1111             if (range.start + range.length < textLength)
   1112                 range.length -= 1;
   1113             String lineText = coreObject->doAXStringForRange(range);
   1114             g_string_append(str, lineText.utf8().data());
   1115             g_string_append(str, "\n");
   1116             range = coreObject->doAXRangeForLine(++lineNumber);
   1117         }
   1118     } else if (coreObject->isAccessibilityRenderObject()) {
   1119         GOwnPtr<gchar> rendererText(textForRenderer(coreObject->renderer()));
   1120         g_string_append(str, rendererText.get());
   1121     }
   1122 
   1123     return g_string_free(str, FALSE);
   1124 }
   1125 
   1126 static gchar* webkit_accessible_text_get_text(AtkText* text, gint startOffset, gint endOffset)
   1127 {
   1128     AccessibilityObject* coreObject = core(text);
   1129 
   1130     int end = endOffset;
   1131     if (endOffset == -1) {
   1132         end = coreObject->stringValue().length();
   1133         if (!end)
   1134             end = coreObject->textUnderElement().length();
   1135     }
   1136 
   1137     String ret;
   1138     if (coreObject->isTextControl())
   1139         ret = coreObject->doAXStringForRange(PlainTextRange(0, endOffset));
   1140     else {
   1141         ret = coreObject->stringValue();
   1142         if (!ret)
   1143             ret = coreObject->textUnderElement();
   1144     }
   1145 
   1146     if (!ret.length()) {
   1147         // This can happen at least with anonymous RenderBlocks (e.g. body text amongst paragraphs)
   1148         ret = String(textForObject(coreObject));
   1149         if (!end)
   1150             end = ret.length();
   1151     }
   1152 
   1153     // Prefix a item number/bullet if needed
   1154     if (coreObject->roleValue() == ListItemRole) {
   1155         RenderObject* objRenderer = coreObject->renderer();
   1156         if (objRenderer && objRenderer->isListItem()) {
   1157             String markerText = toRenderListItem(objRenderer)->markerTextWithSuffix();
   1158             ret = objRenderer->style()->direction() == LTR ? markerText + ret : ret + markerText;
   1159             if (endOffset == -1)
   1160                 end += markerText.length();
   1161         }
   1162     }
   1163 
   1164     ret = ret.substring(startOffset, end - startOffset);
   1165     return g_strdup(ret.utf8().data());
   1166 }
   1167 
   1168 static GailTextUtil* getGailTextUtilForAtk(AtkText* textObject)
   1169 {
   1170     gpointer data = g_object_get_data(G_OBJECT(textObject), "webkit-accessible-gail-text-util");
   1171     if (data)
   1172         return static_cast<GailTextUtil*>(data);
   1173 
   1174     GailTextUtil* gailTextUtil = gail_text_util_new();
   1175     gail_text_util_text_setup(gailTextUtil, webkit_accessible_text_get_text(textObject, 0, -1));
   1176     g_object_set_data_full(G_OBJECT(textObject), "webkit-accessible-gail-text-util", gailTextUtil, g_object_unref);
   1177     return gailTextUtil;
   1178 }
   1179 
   1180 static PangoLayout* getPangoLayoutForAtk(AtkText* textObject)
   1181 {
   1182     AccessibilityObject* coreObject = core(textObject);
   1183 
   1184     Document* document = coreObject->document();
   1185     if (!document)
   1186         return 0;
   1187 
   1188     HostWindow* hostWindow = document->view()->hostWindow();
   1189     if (!hostWindow)
   1190         return 0;
   1191     PlatformPageClient webView = hostWindow->platformPageClient();
   1192     if (!webView)
   1193         return 0;
   1194 
   1195     // Create a string with the layout as it appears on the screen
   1196     PangoLayout* layout = gtk_widget_create_pango_layout(static_cast<GtkWidget*>(webView), textForObject(coreObject));
   1197     g_object_set_data_full(G_OBJECT(textObject), "webkit-accessible-pango-layout", layout, g_object_unref);
   1198     return layout;
   1199 }
   1200 
   1201 static gchar* webkit_accessible_text_get_text_after_offset(AtkText* text, gint offset, AtkTextBoundary boundaryType, gint* startOffset, gint* endOffset)
   1202 {
   1203     return gail_text_util_get_text(getGailTextUtilForAtk(text), getPangoLayoutForAtk(text), GAIL_AFTER_OFFSET, boundaryType, offset, startOffset, endOffset);
   1204 }
   1205 
   1206 static gchar* webkit_accessible_text_get_text_at_offset(AtkText* text, gint offset, AtkTextBoundary boundaryType, gint* startOffset, gint* endOffset)
   1207 {
   1208     return gail_text_util_get_text(getGailTextUtilForAtk(text), getPangoLayoutForAtk(text), GAIL_AT_OFFSET, boundaryType, offset, startOffset, endOffset);
   1209 }
   1210 
   1211 static gchar* webkit_accessible_text_get_text_before_offset(AtkText* text, gint offset, AtkTextBoundary boundaryType, gint* startOffset, gint* endOffset)
   1212 {
   1213     return gail_text_util_get_text(getGailTextUtilForAtk(text), getPangoLayoutForAtk(text), GAIL_BEFORE_OFFSET, boundaryType, offset, startOffset, endOffset);
   1214 }
   1215 
   1216 static gunichar webkit_accessible_text_get_character_at_offset(AtkText* text, gint offset)
   1217 {
   1218     notImplemented();
   1219     return 0;
   1220 }
   1221 
   1222 static gint webkit_accessible_text_get_caret_offset(AtkText* text)
   1223 {
   1224     // coreObject is the unignored object whose offset the caller is requesting.
   1225     // focusedObject is the object with the caret. It is likely ignored -- unless it's a link.
   1226     AccessibilityObject* coreObject = core(text);
   1227     if (!coreObject->isAccessibilityRenderObject())
   1228         return 0;
   1229 
   1230     Document* document = coreObject->document();
   1231     if (!document)
   1232         return 0;
   1233 
   1234     Node* focusedNode = coreObject->selection().end().deprecatedNode();
   1235     if (!focusedNode)
   1236         return 0;
   1237 
   1238     RenderObject* focusedRenderer = focusedNode->renderer();
   1239     AccessibilityObject* focusedObject = document->axObjectCache()->getOrCreate(focusedRenderer);
   1240 
   1241     int offset;
   1242     // Don't ignore links if the offset is being requested for a link.
   1243     if (!objectAndOffsetUnignored(focusedObject, offset, !coreObject->isLink()))
   1244         return 0;
   1245 
   1246     RenderObject* renderer = coreObject->renderer();
   1247     if (renderer && renderer->isListItem()) {
   1248         String markerText = toRenderListItem(renderer)->markerTextWithSuffix();
   1249 
   1250         // We need to adjust the offset for the list item marker.
   1251         offset += markerText.length();
   1252     }
   1253 
   1254     // TODO: Verify this for RTL text.
   1255     return offset;
   1256 }
   1257 
   1258 static int baselinePositionForRenderObject(RenderObject* renderObject)
   1259 {
   1260     // FIXME: This implementation of baselinePosition originates from RenderObject.cpp and was
   1261     // removed in r70072. The implementation looks incorrect though, because this is not the
   1262     // baseline of the underlying RenderObject, but of the AccessibilityRenderObject.
   1263     const FontMetrics& fontMetrics = renderObject->firstLineStyle()->fontMetrics();
   1264     return fontMetrics.ascent() + (renderObject->firstLineStyle()->computedLineHeight() - fontMetrics.height()) / 2;
   1265 }
   1266 
   1267 static AtkAttributeSet* getAttributeSetForAccessibilityObject(const AccessibilityObject* object)
   1268 {
   1269     if (!object->isAccessibilityRenderObject())
   1270         return 0;
   1271 
   1272     RenderObject* renderer = object->renderer();
   1273     RenderStyle* style = renderer->style();
   1274 
   1275     AtkAttributeSet* result = 0;
   1276     GOwnPtr<gchar> buffer(g_strdup_printf("%i", style->fontSize()));
   1277     result = addAttributeToSet(result, atk_text_attribute_get_name(ATK_TEXT_ATTR_SIZE), buffer.get());
   1278 
   1279     Color bgColor = style->visitedDependentColor(CSSPropertyBackgroundColor);
   1280     if (bgColor.isValid()) {
   1281         buffer.set(g_strdup_printf("%i,%i,%i",
   1282                                    bgColor.red(), bgColor.green(), bgColor.blue()));
   1283         result = addAttributeToSet(result, atk_text_attribute_get_name(ATK_TEXT_ATTR_BG_COLOR), buffer.get());
   1284     }
   1285 
   1286     Color fgColor = style->visitedDependentColor(CSSPropertyColor);
   1287     if (fgColor.isValid()) {
   1288         buffer.set(g_strdup_printf("%i,%i,%i",
   1289                                    fgColor.red(), fgColor.green(), fgColor.blue()));
   1290         result = addAttributeToSet(result, atk_text_attribute_get_name(ATK_TEXT_ATTR_FG_COLOR), buffer.get());
   1291     }
   1292 
   1293     int baselinePosition;
   1294     bool includeRise = true;
   1295     switch (style->verticalAlign()) {
   1296     case SUB:
   1297         baselinePosition = -1 * baselinePositionForRenderObject(renderer);
   1298         break;
   1299     case SUPER:
   1300         baselinePosition = baselinePositionForRenderObject(renderer);
   1301         break;
   1302     case BASELINE:
   1303         baselinePosition = 0;
   1304         break;
   1305     default:
   1306         includeRise = false;
   1307         break;
   1308     }
   1309 
   1310     if (includeRise) {
   1311         buffer.set(g_strdup_printf("%i", baselinePosition));
   1312         result = addAttributeToSet(result, atk_text_attribute_get_name(ATK_TEXT_ATTR_RISE), buffer.get());
   1313     }
   1314 
   1315     int indentation = style->textIndent().calcValue(object->size().width());
   1316     if (indentation != undefinedLength) {
   1317         buffer.set(g_strdup_printf("%i", indentation));
   1318         result = addAttributeToSet(result, atk_text_attribute_get_name(ATK_TEXT_ATTR_INDENT), buffer.get());
   1319     }
   1320 
   1321     String fontFamilyName = style->font().family().family().string();
   1322     if (fontFamilyName.left(8) == "-webkit-")
   1323         fontFamilyName = fontFamilyName.substring(8);
   1324 
   1325     result = addAttributeToSet(result, atk_text_attribute_get_name(ATK_TEXT_ATTR_FAMILY_NAME), fontFamilyName.utf8().data());
   1326 
   1327     int fontWeight = -1;
   1328     switch (style->font().weight()) {
   1329     case FontWeight100:
   1330         fontWeight = 100;
   1331         break;
   1332     case FontWeight200:
   1333         fontWeight = 200;
   1334         break;
   1335     case FontWeight300:
   1336         fontWeight = 300;
   1337         break;
   1338     case FontWeight400:
   1339         fontWeight = 400;
   1340         break;
   1341     case FontWeight500:
   1342         fontWeight = 500;
   1343         break;
   1344     case FontWeight600:
   1345         fontWeight = 600;
   1346         break;
   1347     case FontWeight700:
   1348         fontWeight = 700;
   1349         break;
   1350     case FontWeight800:
   1351         fontWeight = 800;
   1352         break;
   1353     case FontWeight900:
   1354         fontWeight = 900;
   1355     }
   1356     if (fontWeight > 0) {
   1357         buffer.set(g_strdup_printf("%i", fontWeight));
   1358         result = addAttributeToSet(result, atk_text_attribute_get_name(ATK_TEXT_ATTR_WEIGHT), buffer.get());
   1359     }
   1360 
   1361     switch (style->textAlign()) {
   1362     case TAAUTO:
   1363     case TASTART:
   1364     case TAEND:
   1365         break;
   1366     case LEFT:
   1367     case WEBKIT_LEFT:
   1368         result = addAttributeToSet(result, atk_text_attribute_get_name(ATK_TEXT_ATTR_JUSTIFICATION), "left");
   1369         break;
   1370     case RIGHT:
   1371     case WEBKIT_RIGHT:
   1372         result = addAttributeToSet(result, atk_text_attribute_get_name(ATK_TEXT_ATTR_JUSTIFICATION), "right");
   1373         break;
   1374     case CENTER:
   1375     case WEBKIT_CENTER:
   1376         result = addAttributeToSet(result, atk_text_attribute_get_name(ATK_TEXT_ATTR_JUSTIFICATION), "center");
   1377         break;
   1378     case JUSTIFY:
   1379         result = addAttributeToSet(result, atk_text_attribute_get_name(ATK_TEXT_ATTR_JUSTIFICATION), "fill");
   1380     }
   1381 
   1382     result = addAttributeToSet(result, atk_text_attribute_get_name(ATK_TEXT_ATTR_UNDERLINE), (style->textDecoration() & UNDERLINE) ? "single" : "none");
   1383 
   1384     result = addAttributeToSet(result, atk_text_attribute_get_name(ATK_TEXT_ATTR_STYLE), style->font().italic() ? "italic" : "normal");
   1385 
   1386     result = addAttributeToSet(result, atk_text_attribute_get_name(ATK_TEXT_ATTR_STRIKETHROUGH), (style->textDecoration() & LINE_THROUGH) ? "true" : "false");
   1387 
   1388     result = addAttributeToSet(result, atk_text_attribute_get_name(ATK_TEXT_ATTR_INVISIBLE), (style->visibility() == HIDDEN) ? "true" : "false");
   1389 
   1390     result = addAttributeToSet(result, atk_text_attribute_get_name(ATK_TEXT_ATTR_EDITABLE), object->isReadOnly() ? "false" : "true");
   1391 
   1392     return result;
   1393 }
   1394 
   1395 static gint compareAttribute(const AtkAttribute* a, const AtkAttribute* b)
   1396 {
   1397     return g_strcmp0(a->name, b->name) || g_strcmp0(a->value, b->value);
   1398 }
   1399 
   1400 // Returns an AtkAttributeSet with the elements of a1 which are either
   1401 // not present or different in a2.  Neither a1 nor a2 should be used
   1402 // after calling this function.
   1403 static AtkAttributeSet* attributeSetDifference(AtkAttributeSet* a1, AtkAttributeSet* a2)
   1404 {
   1405     if (!a2)
   1406         return a1;
   1407 
   1408     AtkAttributeSet* i = a1;
   1409     AtkAttributeSet* found;
   1410     AtkAttributeSet* toDelete = 0;
   1411 
   1412     while (i) {
   1413         found = g_slist_find_custom(a2, i->data, (GCompareFunc)compareAttribute);
   1414         if (found) {
   1415             AtkAttributeSet* t = i->next;
   1416             toDelete = g_slist_prepend(toDelete, i->data);
   1417             a1 = g_slist_delete_link(a1, i);
   1418             i = t;
   1419         } else
   1420             i = i->next;
   1421     }
   1422 
   1423     atk_attribute_set_free(a2);
   1424     atk_attribute_set_free(toDelete);
   1425     return a1;
   1426 }
   1427 
   1428 static guint accessibilityObjectLength(const AccessibilityObject* object)
   1429 {
   1430     // Non render objects are not taken into account
   1431     if (!object->isAccessibilityRenderObject())
   1432         return 0;
   1433 
   1434     // For those objects implementing the AtkText interface we use the
   1435     // well known API to always get the text in a consistent way
   1436     AtkObject* atkObj = ATK_OBJECT(object->wrapper());
   1437     if (ATK_IS_TEXT(atkObj)) {
   1438         GOwnPtr<gchar> text(webkit_accessible_text_get_text(ATK_TEXT(atkObj), 0, -1));
   1439         return g_utf8_strlen(text.get(), -1);
   1440     }
   1441 
   1442     // Even if we don't expose list markers to Assistive
   1443     // Technologies, we need to have a way to measure their length
   1444     // for those cases when it's needed to take it into account
   1445     // separately (as in getAccessibilityObjectForOffset)
   1446     RenderObject* renderer = object->renderer();
   1447     if (renderer && renderer->isListMarker()) {
   1448         RenderListMarker* marker = toRenderListMarker(renderer);
   1449         return marker->text().length() + marker->suffix().length();
   1450     }
   1451 
   1452     return 0;
   1453 }
   1454 
   1455 static const AccessibilityObject* getAccessibilityObjectForOffset(const AccessibilityObject* object, guint offset, gint* startOffset, gint* endOffset)
   1456 {
   1457     const AccessibilityObject* result;
   1458     guint length = accessibilityObjectLength(object);
   1459     if (length > offset) {
   1460         *startOffset = 0;
   1461         *endOffset = length;
   1462         result = object;
   1463     } else {
   1464         *startOffset = -1;
   1465         *endOffset = -1;
   1466         result = 0;
   1467     }
   1468 
   1469     if (!object->firstChild())
   1470         return result;
   1471 
   1472     AccessibilityObject* child = object->firstChild();
   1473     guint currentOffset = 0;
   1474     guint childPosition = 0;
   1475     while (child && currentOffset <= offset) {
   1476         guint childLength = accessibilityObjectLength(child);
   1477         currentOffset = childLength + childPosition;
   1478         if (currentOffset > offset) {
   1479             gint childStartOffset;
   1480             gint childEndOffset;
   1481             const AccessibilityObject* grandChild = getAccessibilityObjectForOffset(child, offset-childPosition,  &childStartOffset, &childEndOffset);
   1482             if (childStartOffset >= 0) {
   1483                 *startOffset = childStartOffset + childPosition;
   1484                 *endOffset = childEndOffset + childPosition;
   1485                 result = grandChild;
   1486             }
   1487         } else {
   1488             childPosition += childLength;
   1489             child = child->nextSibling();
   1490         }
   1491     }
   1492     return result;
   1493 }
   1494 
   1495 static AtkAttributeSet* getRunAttributesFromAccesibilityObject(const AccessibilityObject* element, gint offset, gint* startOffset, gint* endOffset)
   1496 {
   1497     const AccessibilityObject *child = getAccessibilityObjectForOffset(element, offset, startOffset, endOffset);
   1498     if (!child) {
   1499         *startOffset = -1;
   1500         *endOffset = -1;
   1501         return 0;
   1502     }
   1503 
   1504     AtkAttributeSet* defaultAttributes = getAttributeSetForAccessibilityObject(element);
   1505     AtkAttributeSet* childAttributes = getAttributeSetForAccessibilityObject(child);
   1506 
   1507     return attributeSetDifference(childAttributes, defaultAttributes);
   1508 }
   1509 
   1510 static AtkAttributeSet* webkit_accessible_text_get_run_attributes(AtkText* text, gint offset, gint* startOffset, gint* endOffset)
   1511 {
   1512     AccessibilityObject* coreObject = core(text);
   1513     AtkAttributeSet* result;
   1514 
   1515     if (!coreObject) {
   1516         *startOffset = 0;
   1517         *endOffset = atk_text_get_character_count(text);
   1518         return 0;
   1519     }
   1520 
   1521     if (offset == -1)
   1522         offset = atk_text_get_caret_offset(text);
   1523 
   1524     result = getRunAttributesFromAccesibilityObject(coreObject, offset, startOffset, endOffset);
   1525 
   1526     if (*startOffset < 0) {
   1527         *startOffset = offset;
   1528         *endOffset = offset;
   1529     }
   1530 
   1531     return result;
   1532 }
   1533 
   1534 static AtkAttributeSet* webkit_accessible_text_get_default_attributes(AtkText* text)
   1535 {
   1536     AccessibilityObject* coreObject = core(text);
   1537     if (!coreObject || !coreObject->isAccessibilityRenderObject())
   1538         return 0;
   1539 
   1540     return getAttributeSetForAccessibilityObject(coreObject);
   1541 }
   1542 
   1543 static IntRect textExtents(AtkText* text, gint startOffset, gint length, AtkCoordType coords)
   1544 {
   1545     gchar* textContent = webkit_accessible_text_get_text(text, startOffset, -1);
   1546     gint textLength = g_utf8_strlen(textContent, -1);
   1547 
   1548     // The first case (endOffset of -1) should work, but seems broken for all Gtk+ apps.
   1549     gint rangeLength = length;
   1550     if (rangeLength < 0 || rangeLength > textLength)
   1551         rangeLength = textLength;
   1552     AccessibilityObject* coreObject = core(text);
   1553 
   1554     IntRect extents = coreObject->doAXBoundsForRange(PlainTextRange(startOffset, rangeLength));
   1555     switch(coords) {
   1556     case ATK_XY_SCREEN:
   1557         if (Document* document = coreObject->document())
   1558             extents = document->view()->contentsToScreen(extents);
   1559         break;
   1560     case ATK_XY_WINDOW:
   1561         // No-op
   1562         break;
   1563     }
   1564 
   1565     return extents;
   1566 }
   1567 
   1568 static void webkit_accessible_text_get_character_extents(AtkText* text, gint offset, gint* x, gint* y, gint* width, gint* height, AtkCoordType coords)
   1569 {
   1570     IntRect extents = textExtents(text, offset, 1, coords);
   1571     *x = extents.x();
   1572     *y = extents.y();
   1573     *width = extents.width();
   1574     *height = extents.height();
   1575 }
   1576 
   1577 static void webkit_accessible_text_get_range_extents(AtkText* text, gint startOffset, gint endOffset, AtkCoordType coords, AtkTextRectangle* rect)
   1578 {
   1579     IntRect extents = textExtents(text, startOffset, endOffset - startOffset, coords);
   1580     rect->x = extents.x();
   1581     rect->y = extents.y();
   1582     rect->width = extents.width();
   1583     rect->height = extents.height();
   1584 }
   1585 
   1586 static gint webkit_accessible_text_get_character_count(AtkText* text)
   1587 {
   1588     return accessibilityObjectLength(core(text));
   1589 }
   1590 
   1591 static gint webkit_accessible_text_get_offset_at_point(AtkText* text, gint x, gint y, AtkCoordType coords)
   1592 {
   1593     // FIXME: Use the AtkCoordType
   1594     // TODO: Is it correct to ignore range.length?
   1595     IntPoint pos(x, y);
   1596     PlainTextRange range = core(text)->doAXRangeForPosition(pos);
   1597     return range.start;
   1598 }
   1599 
   1600 static void getSelectionOffsetsForObject(AccessibilityObject* coreObject, VisibleSelection& selection, gint& startOffset, gint& endOffset)
   1601 {
   1602     if (!coreObject->isAccessibilityRenderObject())
   1603         return;
   1604 
   1605     // Early return if the selection doesn't affect the selected node.
   1606     if (!selectionBelongsToObject(coreObject, selection))
   1607         return;
   1608 
   1609     // We need to find the exact start and end positions in the
   1610     // selected node that intersects the selection, to later on get
   1611     // the right values for the effective start and end offsets.
   1612     ExceptionCode ec = 0;
   1613     Position nodeRangeStart;
   1614     Position nodeRangeEnd;
   1615     Node* node = coreObject->node();
   1616     RefPtr<Range> selRange = selection.toNormalizedRange();
   1617 
   1618     // If the selection affects the selected node and its first
   1619     // possible position is also in the selection, we must set
   1620     // nodeRangeStart to that position, otherwise to the selection's
   1621     // start position (it would belong to the node anyway).
   1622     Node* firstLeafNode = node->firstDescendant();
   1623     if (selRange->isPointInRange(firstLeafNode, 0, ec))
   1624         nodeRangeStart = firstPositionInOrBeforeNode(firstLeafNode);
   1625     else
   1626         nodeRangeStart = selRange->startPosition();
   1627 
   1628     // If the selection affects the selected node and its last
   1629     // possible position is also in the selection, we must set
   1630     // nodeRangeEnd to that position, otherwise to the selection's
   1631     // end position (it would belong to the node anyway).
   1632     Node* lastLeafNode = node->lastDescendant();
   1633     if (selRange->isPointInRange(lastLeafNode, lastOffsetInNode(lastLeafNode), ec))
   1634         nodeRangeEnd = lastPositionInOrAfterNode(lastLeafNode);
   1635     else
   1636         nodeRangeEnd = selRange->endPosition();
   1637 
   1638     // Calculate position of the selected range inside the object.
   1639     Position parentFirstPosition = firstPositionInOrBeforeNode(node);
   1640     RefPtr<Range> rangeInParent = Range::create(node->document(), parentFirstPosition, nodeRangeStart);
   1641 
   1642     // Set values for start and end offsets.
   1643     startOffset = TextIterator::rangeLength(rangeInParent.get(), true);
   1644 
   1645     // We need to adjust the offsets for the list item marker.
   1646     RenderObject* renderer = coreObject->renderer();
   1647     if (renderer && renderer->isListItem()) {
   1648         String markerText = toRenderListItem(renderer)->markerTextWithSuffix();
   1649         startOffset += markerText.length();
   1650     }
   1651 
   1652     RefPtr<Range> nodeRange = Range::create(node->document(), nodeRangeStart, nodeRangeEnd);
   1653     endOffset = startOffset + TextIterator::rangeLength(nodeRange.get(), true);
   1654 }
   1655 
   1656 static gint webkit_accessible_text_get_n_selections(AtkText* text)
   1657 {
   1658     AccessibilityObject* coreObject = core(text);
   1659     VisibleSelection selection = coreObject->selection();
   1660 
   1661     // Only range selections are needed for the purpose of this method
   1662     if (!selection.isRange())
   1663         return 0;
   1664 
   1665     // We don't support multiple selections for now, so there's only
   1666     // two possibilities
   1667     // Also, we don't want to do anything if the selection does not
   1668     // belong to the currently selected object. We have to check since
   1669     // there's no way to get the selection for a given object, only
   1670     // the global one (the API is a bit confusing)
   1671     return selectionBelongsToObject(coreObject, selection) ? 1 : 0;
   1672 }
   1673 
   1674 static gchar* webkit_accessible_text_get_selection(AtkText* text, gint selectionNum, gint* startOffset, gint* endOffset)
   1675 {
   1676     // Default values, unless the contrary is proved
   1677     *startOffset = *endOffset = 0;
   1678 
   1679     // WebCore does not support multiple selection, so anything but 0 does not make sense for now.
   1680     if (selectionNum)
   1681         return 0;
   1682 
   1683     // Get the offsets of the selection for the selected object
   1684     AccessibilityObject* coreObject = core(text);
   1685     VisibleSelection selection = coreObject->selection();
   1686     getSelectionOffsetsForObject(coreObject, selection, *startOffset, *endOffset);
   1687 
   1688     // Return 0 instead of "", as that's the expected result for
   1689     // this AtkText method when there's no selection
   1690     if (*startOffset == *endOffset)
   1691         return 0;
   1692 
   1693     return webkit_accessible_text_get_text(text, *startOffset, *endOffset);
   1694 }
   1695 
   1696 static gboolean webkit_accessible_text_add_selection(AtkText* text, gint start_offset, gint end_offset)
   1697 {
   1698     notImplemented();
   1699     return FALSE;
   1700 }
   1701 
   1702 static gboolean webkit_accessible_text_set_selection(AtkText* text, gint selectionNum, gint startOffset, gint endOffset)
   1703 {
   1704     // WebCore does not support multiple selection, so anything but 0 does not make sense for now.
   1705     if (selectionNum)
   1706         return FALSE;
   1707 
   1708     AccessibilityObject* coreObject = core(text);
   1709     if (!coreObject->isAccessibilityRenderObject())
   1710         return FALSE;
   1711 
   1712     // Consider -1 and out-of-bound values and correct them to length
   1713     gint textCount = webkit_accessible_text_get_character_count(text);
   1714     if (startOffset < 0 || startOffset > textCount)
   1715         startOffset = textCount;
   1716     if (endOffset < 0 || endOffset > textCount)
   1717         endOffset = textCount;
   1718 
   1719     // We need to adjust the offsets for the list item marker.
   1720     RenderObject* renderer = coreObject->renderer();
   1721     if (renderer && renderer->isListItem()) {
   1722         String markerText = toRenderListItem(renderer)->markerTextWithSuffix();
   1723         int markerLength = markerText.length();
   1724         if (startOffset < markerLength || endOffset < markerLength)
   1725             return FALSE;
   1726 
   1727         startOffset -= markerLength;
   1728         endOffset -= markerLength;
   1729     }
   1730 
   1731     PlainTextRange textRange(startOffset, endOffset - startOffset);
   1732     VisiblePositionRange range = coreObject->visiblePositionRangeForRange(textRange);
   1733     if (range.isNull())
   1734         return FALSE;
   1735 
   1736     coreObject->setSelectedVisiblePositionRange(range);
   1737     return TRUE;
   1738 }
   1739 
   1740 static gboolean webkit_accessible_text_remove_selection(AtkText* text, gint selectionNum)
   1741 {
   1742     // WebCore does not support multiple selection, so anything but 0 does not make sense for now.
   1743     if (selectionNum)
   1744         return FALSE;
   1745 
   1746     // Do nothing if current selection doesn't belong to the object
   1747     if (!webkit_accessible_text_get_n_selections(text))
   1748         return FALSE;
   1749 
   1750     // Set a new 0-sized selection to the caret position, in order
   1751     // to simulate selection removal (GAIL style)
   1752     gint caretOffset = webkit_accessible_text_get_caret_offset(text);
   1753     return webkit_accessible_text_set_selection(text, selectionNum, caretOffset, caretOffset);
   1754 }
   1755 
   1756 static gboolean webkit_accessible_text_set_caret_offset(AtkText* text, gint offset)
   1757 {
   1758     AccessibilityObject* coreObject = core(text);
   1759 
   1760     if (!coreObject->isAccessibilityRenderObject())
   1761         return FALSE;
   1762 
   1763     RenderObject* renderer = coreObject->renderer();
   1764     if (renderer && renderer->isListItem()) {
   1765         String markerText = toRenderListItem(renderer)->markerTextWithSuffix();
   1766         int markerLength = markerText.length();
   1767         if (offset < markerLength)
   1768             return FALSE;
   1769 
   1770         // We need to adjust the offset for list items.
   1771         offset -= markerLength;
   1772     }
   1773 
   1774     PlainTextRange textRange(offset, 0);
   1775     VisiblePositionRange range = coreObject->visiblePositionRangeForRange(textRange);
   1776     if (range.isNull())
   1777         return FALSE;
   1778 
   1779     coreObject->setSelectedVisiblePositionRange(range);
   1780     return TRUE;
   1781 }
   1782 
   1783 static void atk_text_interface_init(AtkTextIface* iface)
   1784 {
   1785     iface->get_text = webkit_accessible_text_get_text;
   1786     iface->get_text_after_offset = webkit_accessible_text_get_text_after_offset;
   1787     iface->get_text_at_offset = webkit_accessible_text_get_text_at_offset;
   1788     iface->get_character_at_offset = webkit_accessible_text_get_character_at_offset;
   1789     iface->get_text_before_offset = webkit_accessible_text_get_text_before_offset;
   1790     iface->get_caret_offset = webkit_accessible_text_get_caret_offset;
   1791     iface->get_run_attributes = webkit_accessible_text_get_run_attributes;
   1792     iface->get_default_attributes = webkit_accessible_text_get_default_attributes;
   1793     iface->get_character_extents = webkit_accessible_text_get_character_extents;
   1794     iface->get_range_extents = webkit_accessible_text_get_range_extents;
   1795     iface->get_character_count = webkit_accessible_text_get_character_count;
   1796     iface->get_offset_at_point = webkit_accessible_text_get_offset_at_point;
   1797     iface->get_n_selections = webkit_accessible_text_get_n_selections;
   1798     iface->get_selection = webkit_accessible_text_get_selection;
   1799 
   1800     // set methods
   1801     iface->add_selection = webkit_accessible_text_add_selection;
   1802     iface->remove_selection = webkit_accessible_text_remove_selection;
   1803     iface->set_selection = webkit_accessible_text_set_selection;
   1804     iface->set_caret_offset = webkit_accessible_text_set_caret_offset;
   1805 }
   1806 
   1807 // EditableText
   1808 
   1809 static gboolean webkit_accessible_editable_text_set_run_attributes(AtkEditableText* text, AtkAttributeSet* attrib_set, gint start_offset, gint end_offset)
   1810 {
   1811     notImplemented();
   1812     return FALSE;
   1813 }
   1814 
   1815 static void webkit_accessible_editable_text_set_text_contents(AtkEditableText* text, const gchar* string)
   1816 {
   1817     // FIXME: string nullcheck?
   1818     core(text)->setValue(String::fromUTF8(string));
   1819 }
   1820 
   1821 static void webkit_accessible_editable_text_insert_text(AtkEditableText* text, const gchar* string, gint length, gint* position)
   1822 {
   1823     // FIXME: string nullcheck?
   1824 
   1825     AccessibilityObject* coreObject = core(text);
   1826     // FIXME: Not implemented in WebCore
   1827     //coreObject->setSelectedTextRange(PlainTextRange(*position, 0));
   1828     //coreObject->setSelectedText(String::fromUTF8(string));
   1829 
   1830     Document* document = coreObject->document();
   1831     if (!document || !document->frame())
   1832         return;
   1833 
   1834     coreObject->setSelectedVisiblePositionRange(coreObject->visiblePositionRangeForRange(PlainTextRange(*position, 0)));
   1835     coreObject->setFocused(true);
   1836     // FIXME: We should set position to the actual inserted text length, which may be less than that requested.
   1837     if (document->frame()->editor()->insertTextWithoutSendingTextEvent(String::fromUTF8(string), false, 0))
   1838         *position += length;
   1839 }
   1840 
   1841 static void webkit_accessible_editable_text_copy_text(AtkEditableText* text, gint start_pos, gint end_pos)
   1842 {
   1843     notImplemented();
   1844 }
   1845 
   1846 static void webkit_accessible_editable_text_cut_text(AtkEditableText* text, gint start_pos, gint end_pos)
   1847 {
   1848     notImplemented();
   1849 }
   1850 
   1851 static void webkit_accessible_editable_text_delete_text(AtkEditableText* text, gint start_pos, gint end_pos)
   1852 {
   1853     AccessibilityObject* coreObject = core(text);
   1854     // FIXME: Not implemented in WebCore
   1855     //coreObject->setSelectedTextRange(PlainTextRange(start_pos, end_pos - start_pos));
   1856     //coreObject->setSelectedText(String());
   1857 
   1858     Document* document = coreObject->document();
   1859     if (!document || !document->frame())
   1860         return;
   1861 
   1862     coreObject->setSelectedVisiblePositionRange(coreObject->visiblePositionRangeForRange(PlainTextRange(start_pos, end_pos - start_pos)));
   1863     coreObject->setFocused(true);
   1864     document->frame()->editor()->performDelete();
   1865 }
   1866 
   1867 static void webkit_accessible_editable_text_paste_text(AtkEditableText* text, gint position)
   1868 {
   1869     notImplemented();
   1870 }
   1871 
   1872 static void atk_editable_text_interface_init(AtkEditableTextIface* iface)
   1873 {
   1874     iface->set_run_attributes = webkit_accessible_editable_text_set_run_attributes;
   1875     iface->set_text_contents = webkit_accessible_editable_text_set_text_contents;
   1876     iface->insert_text = webkit_accessible_editable_text_insert_text;
   1877     iface->copy_text = webkit_accessible_editable_text_copy_text;
   1878     iface->cut_text = webkit_accessible_editable_text_cut_text;
   1879     iface->delete_text = webkit_accessible_editable_text_delete_text;
   1880     iface->paste_text = webkit_accessible_editable_text_paste_text;
   1881 }
   1882 
   1883 static void contentsToAtk(AccessibilityObject* coreObject, AtkCoordType coordType, IntRect rect, gint* x, gint* y, gint* width = 0, gint* height = 0)
   1884 {
   1885     FrameView* frameView = coreObject->documentFrameView();
   1886 
   1887     if (frameView) {
   1888         switch (coordType) {
   1889         case ATK_XY_WINDOW:
   1890             rect = frameView->contentsToWindow(rect);
   1891             break;
   1892         case ATK_XY_SCREEN:
   1893             rect = frameView->contentsToScreen(rect);
   1894             break;
   1895         }
   1896     }
   1897 
   1898     if (x)
   1899         *x = rect.x();
   1900     if (y)
   1901         *y = rect.y();
   1902     if (width)
   1903         *width = rect.width();
   1904     if (height)
   1905         *height = rect.height();
   1906 }
   1907 
   1908 static IntPoint atkToContents(AccessibilityObject* coreObject, AtkCoordType coordType, gint x, gint y)
   1909 {
   1910     IntPoint pos(x, y);
   1911 
   1912     FrameView* frameView = coreObject->documentFrameView();
   1913     if (frameView) {
   1914         switch (coordType) {
   1915         case ATK_XY_SCREEN:
   1916             return frameView->screenToContents(pos);
   1917         case ATK_XY_WINDOW:
   1918             return frameView->windowToContents(pos);
   1919         }
   1920     }
   1921 
   1922     return pos;
   1923 }
   1924 
   1925 static AtkObject* webkit_accessible_component_ref_accessible_at_point(AtkComponent* component, gint x, gint y, AtkCoordType coordType)
   1926 {
   1927     IntPoint pos = atkToContents(core(component), coordType, x, y);
   1928 
   1929     AccessibilityObject* target = core(component)->accessibilityHitTest(pos);
   1930     if (!target)
   1931         return 0;
   1932     g_object_ref(target->wrapper());
   1933     return target->wrapper();
   1934 }
   1935 
   1936 static void webkit_accessible_component_get_extents(AtkComponent* component, gint* x, gint* y, gint* width, gint* height, AtkCoordType coordType)
   1937 {
   1938     IntRect rect = core(component)->elementRect();
   1939     contentsToAtk(core(component), coordType, rect, x, y, width, height);
   1940 }
   1941 
   1942 static gboolean webkit_accessible_component_grab_focus(AtkComponent* component)
   1943 {
   1944     core(component)->setFocused(true);
   1945     return core(component)->isFocused();
   1946 }
   1947 
   1948 static void atk_component_interface_init(AtkComponentIface* iface)
   1949 {
   1950     iface->ref_accessible_at_point = webkit_accessible_component_ref_accessible_at_point;
   1951     iface->get_extents = webkit_accessible_component_get_extents;
   1952     iface->grab_focus = webkit_accessible_component_grab_focus;
   1953 }
   1954 
   1955 // Image
   1956 
   1957 static void webkit_accessible_image_get_image_position(AtkImage* image, gint* x, gint* y, AtkCoordType coordType)
   1958 {
   1959     IntRect rect = core(image)->elementRect();
   1960     contentsToAtk(core(image), coordType, rect, x, y);
   1961 }
   1962 
   1963 static const gchar* webkit_accessible_image_get_image_description(AtkImage* image)
   1964 {
   1965     return returnString(core(image)->accessibilityDescription());
   1966 }
   1967 
   1968 static void webkit_accessible_image_get_image_size(AtkImage* image, gint* width, gint* height)
   1969 {
   1970     IntSize size = core(image)->size();
   1971 
   1972     if (width)
   1973         *width = size.width();
   1974     if (height)
   1975         *height = size.height();
   1976 }
   1977 
   1978 static void atk_image_interface_init(AtkImageIface* iface)
   1979 {
   1980     iface->get_image_position = webkit_accessible_image_get_image_position;
   1981     iface->get_image_description = webkit_accessible_image_get_image_description;
   1982     iface->get_image_size = webkit_accessible_image_get_image_size;
   1983 }
   1984 
   1985 // Table
   1986 
   1987 static AccessibilityTableCell* cell(AtkTable* table, guint row, guint column)
   1988 {
   1989     AccessibilityObject* accTable = core(table);
   1990     if (accTable->isAccessibilityRenderObject())
   1991         return static_cast<AccessibilityTable*>(accTable)->cellForColumnAndRow(column, row);
   1992     return 0;
   1993 }
   1994 
   1995 static gint cellIndex(AccessibilityTableCell* axCell, AccessibilityTable* axTable)
   1996 {
   1997     // Calculate the cell's index as if we had a traditional Gtk+ table in
   1998     // which cells are all direct children of the table, arranged row-first.
   1999     AccessibilityObject::AccessibilityChildrenVector allCells;
   2000     axTable->cells(allCells);
   2001     AccessibilityObject::AccessibilityChildrenVector::iterator position;
   2002     position = std::find(allCells.begin(), allCells.end(), axCell);
   2003     if (position == allCells.end())
   2004         return -1;
   2005     return position - allCells.begin();
   2006 }
   2007 
   2008 static AccessibilityTableCell* cellAtIndex(AtkTable* table, gint index)
   2009 {
   2010     AccessibilityObject* accTable = core(table);
   2011     if (accTable->isAccessibilityRenderObject()) {
   2012         AccessibilityObject::AccessibilityChildrenVector allCells;
   2013         static_cast<AccessibilityTable*>(accTable)->cells(allCells);
   2014         if (0 <= index && static_cast<unsigned>(index) < allCells.size()) {
   2015             AccessibilityObject* accCell = allCells.at(index).get();
   2016             return static_cast<AccessibilityTableCell*>(accCell);
   2017         }
   2018     }
   2019     return 0;
   2020 }
   2021 
   2022 static AtkObject* webkit_accessible_table_ref_at(AtkTable* table, gint row, gint column)
   2023 {
   2024     AccessibilityTableCell* axCell = cell(table, row, column);
   2025     if (!axCell)
   2026         return 0;
   2027     return axCell->wrapper();
   2028 }
   2029 
   2030 static gint webkit_accessible_table_get_index_at(AtkTable* table, gint row, gint column)
   2031 {
   2032     AccessibilityTableCell* axCell = cell(table, row, column);
   2033     AccessibilityTable* axTable = static_cast<AccessibilityTable*>(core(table));
   2034     return cellIndex(axCell, axTable);
   2035 }
   2036 
   2037 static gint webkit_accessible_table_get_column_at_index(AtkTable* table, gint index)
   2038 {
   2039     AccessibilityTableCell* axCell = cellAtIndex(table, index);
   2040     if (axCell){
   2041         pair<int, int> columnRange;
   2042         axCell->columnIndexRange(columnRange);
   2043         return columnRange.first;
   2044     }
   2045     return -1;
   2046 }
   2047 
   2048 static gint webkit_accessible_table_get_row_at_index(AtkTable* table, gint index)
   2049 {
   2050     AccessibilityTableCell* axCell = cellAtIndex(table, index);
   2051     if (axCell){
   2052         pair<int, int> rowRange;
   2053         axCell->rowIndexRange(rowRange);
   2054         return rowRange.first;
   2055     }
   2056     return -1;
   2057 }
   2058 
   2059 static gint webkit_accessible_table_get_n_columns(AtkTable* table)
   2060 {
   2061     AccessibilityObject* accTable = core(table);
   2062     if (accTable->isAccessibilityRenderObject())
   2063         return static_cast<AccessibilityTable*>(accTable)->columnCount();
   2064     return 0;
   2065 }
   2066 
   2067 static gint webkit_accessible_table_get_n_rows(AtkTable* table)
   2068 {
   2069     AccessibilityObject* accTable = core(table);
   2070     if (accTable->isAccessibilityRenderObject())
   2071         return static_cast<AccessibilityTable*>(accTable)->rowCount();
   2072     return 0;
   2073 }
   2074 
   2075 static gint webkit_accessible_table_get_column_extent_at(AtkTable* table, gint row, gint column)
   2076 {
   2077     AccessibilityTableCell* axCell = cell(table, row, column);
   2078     if (axCell) {
   2079         pair<int, int> columnRange;
   2080         axCell->columnIndexRange(columnRange);
   2081         return columnRange.second;
   2082     }
   2083     return 0;
   2084 }
   2085 
   2086 static gint webkit_accessible_table_get_row_extent_at(AtkTable* table, gint row, gint column)
   2087 {
   2088     AccessibilityTableCell* axCell = cell(table, row, column);
   2089     if (axCell) {
   2090         pair<int, int> rowRange;
   2091         axCell->rowIndexRange(rowRange);
   2092         return rowRange.second;
   2093     }
   2094     return 0;
   2095 }
   2096 
   2097 static AtkObject* webkit_accessible_table_get_column_header(AtkTable* table, gint column)
   2098 {
   2099     AccessibilityObject* accTable = core(table);
   2100     if (accTable->isAccessibilityRenderObject()) {
   2101         AccessibilityObject::AccessibilityChildrenVector allColumnHeaders;
   2102         static_cast<AccessibilityTable*>(accTable)->columnHeaders(allColumnHeaders);
   2103         unsigned columnCount = allColumnHeaders.size();
   2104         for (unsigned k = 0; k < columnCount; ++k) {
   2105             pair<int, int> columnRange;
   2106             AccessibilityTableCell* cell = static_cast<AccessibilityTableCell*>(allColumnHeaders.at(k).get());
   2107             cell->columnIndexRange(columnRange);
   2108             if (columnRange.first <= column && column < columnRange.first + columnRange.second)
   2109                 return allColumnHeaders[k]->wrapper();
   2110         }
   2111     }
   2112     return 0;
   2113 }
   2114 
   2115 static AtkObject* webkit_accessible_table_get_row_header(AtkTable* table, gint row)
   2116 {
   2117     AccessibilityObject* accTable = core(table);
   2118     if (accTable->isAccessibilityRenderObject()) {
   2119         AccessibilityObject::AccessibilityChildrenVector allRowHeaders;
   2120         static_cast<AccessibilityTable*>(accTable)->rowHeaders(allRowHeaders);
   2121         unsigned rowCount = allRowHeaders.size();
   2122         for (unsigned k = 0; k < rowCount; ++k) {
   2123             pair<int, int> rowRange;
   2124             AccessibilityTableCell* cell = static_cast<AccessibilityTableCell*>(allRowHeaders.at(k).get());
   2125             cell->rowIndexRange(rowRange);
   2126             if (rowRange.first <= row && row < rowRange.first + rowRange.second)
   2127                 return allRowHeaders[k]->wrapper();
   2128         }
   2129     }
   2130     return 0;
   2131 }
   2132 
   2133 static AtkObject* webkit_accessible_table_get_caption(AtkTable* table)
   2134 {
   2135     AccessibilityObject* accTable = core(table);
   2136     if (accTable->isAccessibilityRenderObject()) {
   2137         Node* node = accTable->node();
   2138         if (node && node->hasTagName(HTMLNames::tableTag)) {
   2139             HTMLTableCaptionElement* caption = static_cast<HTMLTableElement*>(node)->caption();
   2140             if (caption)
   2141                 return AccessibilityObject::firstAccessibleObjectFromNode(caption->renderer()->node())->wrapper();
   2142         }
   2143     }
   2144     return 0;
   2145 }
   2146 
   2147 static const gchar* webkit_accessible_table_get_column_description(AtkTable* table, gint column)
   2148 {
   2149     AtkObject* columnHeader = atk_table_get_column_header(table, column);
   2150     if (columnHeader && ATK_IS_TEXT(columnHeader))
   2151         return webkit_accessible_text_get_text(ATK_TEXT(columnHeader), 0, -1);
   2152 
   2153     return 0;
   2154 }
   2155 
   2156 static const gchar* webkit_accessible_table_get_row_description(AtkTable* table, gint row)
   2157 {
   2158     AtkObject* rowHeader = atk_table_get_row_header(table, row);
   2159     if (rowHeader && ATK_IS_TEXT(rowHeader))
   2160         return webkit_accessible_text_get_text(ATK_TEXT(rowHeader), 0, -1);
   2161 
   2162     return 0;
   2163 }
   2164 
   2165 static void atk_table_interface_init(AtkTableIface* iface)
   2166 {
   2167     iface->ref_at = webkit_accessible_table_ref_at;
   2168     iface->get_index_at = webkit_accessible_table_get_index_at;
   2169     iface->get_column_at_index = webkit_accessible_table_get_column_at_index;
   2170     iface->get_row_at_index = webkit_accessible_table_get_row_at_index;
   2171     iface->get_n_columns = webkit_accessible_table_get_n_columns;
   2172     iface->get_n_rows = webkit_accessible_table_get_n_rows;
   2173     iface->get_column_extent_at = webkit_accessible_table_get_column_extent_at;
   2174     iface->get_row_extent_at = webkit_accessible_table_get_row_extent_at;
   2175     iface->get_column_header = webkit_accessible_table_get_column_header;
   2176     iface->get_row_header = webkit_accessible_table_get_row_header;
   2177     iface->get_caption = webkit_accessible_table_get_caption;
   2178     iface->get_column_description = webkit_accessible_table_get_column_description;
   2179     iface->get_row_description = webkit_accessible_table_get_row_description;
   2180 }
   2181 
   2182 static AtkHyperlink* webkitAccessibleHypertextGetLink(AtkHypertext* hypertext, gint index)
   2183 {
   2184     AccessibilityObject::AccessibilityChildrenVector children = core(hypertext)->children();
   2185     if (index < 0 || static_cast<unsigned>(index) >= children.size())
   2186         return 0;
   2187 
   2188     gint currentLink = -1;
   2189     for (unsigned i = 0; i < children.size(); i++) {
   2190         AccessibilityObject* coreChild = children.at(i).get();
   2191         if (!coreChild->accessibilityIsIgnored()) {
   2192             AtkObject* axObject = coreChild->wrapper();
   2193             if (!axObject || !ATK_IS_HYPERLINK_IMPL(axObject))
   2194                 continue;
   2195 
   2196             currentLink++;
   2197             if (index != currentLink)
   2198                 continue;
   2199 
   2200             return atk_hyperlink_impl_get_hyperlink(ATK_HYPERLINK_IMPL(axObject));
   2201         }
   2202     }
   2203 
   2204     return 0;
   2205 }
   2206 
   2207 static gint webkitAccessibleHypertextGetNLinks(AtkHypertext* hypertext)
   2208 {
   2209     AccessibilityObject::AccessibilityChildrenVector children = core(hypertext)->children();
   2210     if (!children.size())
   2211         return 0;
   2212 
   2213     gint linksFound = 0;
   2214     for (size_t i = 0; i < children.size(); i++) {
   2215         AccessibilityObject* coreChild = children.at(i).get();
   2216         if (!coreChild->accessibilityIsIgnored()) {
   2217             AtkObject* axObject = coreChild->wrapper();
   2218             if (axObject && ATK_IS_HYPERLINK_IMPL(axObject))
   2219                 linksFound++;
   2220         }
   2221     }
   2222 
   2223     return linksFound;
   2224 }
   2225 
   2226 static gint webkitAccessibleHypertextGetLinkIndex(AtkHypertext* hypertext, gint charIndex)
   2227 {
   2228     size_t linksCount = webkitAccessibleHypertextGetNLinks(hypertext);
   2229     if (!linksCount)
   2230         return -1;
   2231 
   2232     for (size_t i = 0; i < linksCount; i++) {
   2233         AtkHyperlink* hyperlink = ATK_HYPERLINK(webkitAccessibleHypertextGetLink(hypertext, i));
   2234         gint startIndex = atk_hyperlink_get_start_index(hyperlink);
   2235         gint endIndex = atk_hyperlink_get_end_index(hyperlink);
   2236 
   2237         // Check if the char index in the link's offset range
   2238         if (startIndex <= charIndex && charIndex < endIndex)
   2239             return i;
   2240     }
   2241 
   2242     // Not found if reached
   2243     return -1;
   2244 }
   2245 
   2246 static void atkHypertextInterfaceInit(AtkHypertextIface* iface)
   2247 {
   2248     iface->get_link = webkitAccessibleHypertextGetLink;
   2249     iface->get_n_links = webkitAccessibleHypertextGetNLinks;
   2250     iface->get_link_index = webkitAccessibleHypertextGetLinkIndex;
   2251 }
   2252 
   2253 static AtkHyperlink* webkitAccessibleHyperlinkImplGetHyperlink(AtkHyperlinkImpl* hyperlink)
   2254 {
   2255     AtkHyperlink* hyperlinkObject = ATK_HYPERLINK(g_object_get_data(G_OBJECT(hyperlink), "hyperlink-object"));
   2256     if (!hyperlinkObject) {
   2257         hyperlinkObject = ATK_HYPERLINK(webkitAccessibleHyperlinkNew(hyperlink));
   2258         g_object_set_data(G_OBJECT(hyperlink), "hyperlink-object", hyperlinkObject);
   2259     }
   2260     return hyperlinkObject;
   2261 }
   2262 
   2263 static void atkHyperlinkImplInterfaceInit(AtkHyperlinkImplIface* iface)
   2264 {
   2265     iface->get_hyperlink = webkitAccessibleHyperlinkImplGetHyperlink;
   2266 }
   2267 
   2268 static const gchar* documentAttributeValue(AtkDocument* document, const gchar* attribute)
   2269 {
   2270     Document* coreDocument = core(document)->document();
   2271     if (!coreDocument)
   2272         return 0;
   2273 
   2274     String value = String();
   2275     if (!g_ascii_strcasecmp(attribute, "DocType") && coreDocument->doctype())
   2276         value = coreDocument->doctype()->name();
   2277     else if (!g_ascii_strcasecmp(attribute, "Encoding"))
   2278         value = coreDocument->charset();
   2279     else if (!g_ascii_strcasecmp(attribute, "URI"))
   2280         value = coreDocument->documentURI();
   2281     if (!value.isEmpty())
   2282         return returnString(value);
   2283 
   2284     return 0;
   2285 }
   2286 
   2287 static const gchar* webkit_accessible_document_get_attribute_value(AtkDocument* document, const gchar* attribute)
   2288 {
   2289     return documentAttributeValue(document, attribute);
   2290 }
   2291 
   2292 static AtkAttributeSet* webkit_accessible_document_get_attributes(AtkDocument* document)
   2293 {
   2294     AtkAttributeSet* attributeSet = 0;
   2295     const gchar* attributes [] = {"DocType", "Encoding", "URI"};
   2296 
   2297     for (unsigned i = 0; i < G_N_ELEMENTS(attributes); i++) {
   2298         const gchar* value = documentAttributeValue(document, attributes[i]);
   2299         if (value)
   2300             attributeSet = addAttributeToSet(attributeSet, attributes[i], value);
   2301     }
   2302 
   2303     return attributeSet;
   2304 }
   2305 
   2306 static const gchar* webkit_accessible_document_get_locale(AtkDocument* document)
   2307 {
   2308 
   2309     // TODO: Should we fall back on lang xml:lang when the following comes up empty?
   2310     String language = core(document)->language();
   2311     if (!language.isEmpty())
   2312         return returnString(language);
   2313 
   2314     return 0;
   2315 }
   2316 
   2317 static void atk_document_interface_init(AtkDocumentIface* iface)
   2318 {
   2319     iface->get_document_attribute_value = webkit_accessible_document_get_attribute_value;
   2320     iface->get_document_attributes = webkit_accessible_document_get_attributes;
   2321     iface->get_document_locale = webkit_accessible_document_get_locale;
   2322 }
   2323 
   2324 
   2325 static void webkitAccessibleValueGetCurrentValue(AtkValue* value, GValue* gValue)
   2326 {
   2327     memset(gValue,  0, sizeof(GValue));
   2328     g_value_init(gValue, G_TYPE_DOUBLE);
   2329     g_value_set_double(gValue, core(value)->valueForRange());
   2330 }
   2331 
   2332 static void webkitAccessibleValueGetMaximumValue(AtkValue* value, GValue* gValue)
   2333 {
   2334     memset(gValue,  0, sizeof(GValue));
   2335     g_value_init(gValue, G_TYPE_DOUBLE);
   2336     g_value_set_double(gValue, core(value)->maxValueForRange());
   2337 }
   2338 
   2339 static void webkitAccessibleValueGetMinimumValue(AtkValue* value, GValue* gValue)
   2340 {
   2341     memset(gValue,  0, sizeof(GValue));
   2342     g_value_init(gValue, G_TYPE_DOUBLE);
   2343     g_value_set_double(gValue, core(value)->minValueForRange());
   2344 }
   2345 
   2346 static gboolean webkitAccessibleValueSetCurrentValue(AtkValue* value, const GValue* gValue)
   2347 {
   2348     if (!G_VALUE_HOLDS_DOUBLE(gValue) && !G_VALUE_HOLDS_INT(gValue))
   2349         return FALSE;
   2350 
   2351     AccessibilityObject* coreObject = core(value);
   2352     if (!coreObject->canSetValueAttribute())
   2353         return FALSE;
   2354 
   2355     if (G_VALUE_HOLDS_DOUBLE(gValue))
   2356         coreObject->setValue(String::number(g_value_get_double(gValue)));
   2357     else
   2358         coreObject->setValue(String::number(g_value_get_int(gValue)));
   2359 
   2360     return TRUE;
   2361 }
   2362 
   2363 static void webkitAccessibleValueGetMinimumIncrement(AtkValue* value, GValue* gValue)
   2364 {
   2365     memset(gValue,  0, sizeof(GValue));
   2366     g_value_init(gValue, G_TYPE_DOUBLE);
   2367 
   2368     // There's not such a thing in the WAI-ARIA specification, thus return zero.
   2369     g_value_set_double(gValue, 0.0);
   2370 }
   2371 
   2372 static void atkValueInterfaceInit(AtkValueIface* iface)
   2373 {
   2374     iface->get_current_value = webkitAccessibleValueGetCurrentValue;
   2375     iface->get_maximum_value = webkitAccessibleValueGetMaximumValue;
   2376     iface->get_minimum_value = webkitAccessibleValueGetMinimumValue;
   2377     iface->set_current_value = webkitAccessibleValueSetCurrentValue;
   2378     iface->get_minimum_increment = webkitAccessibleValueGetMinimumIncrement;
   2379 }
   2380 
   2381 static const GInterfaceInfo AtkInterfacesInitFunctions[] = {
   2382     {(GInterfaceInitFunc)atk_action_interface_init,
   2383      (GInterfaceFinalizeFunc) 0, 0},
   2384     {(GInterfaceInitFunc)atk_selection_interface_init,
   2385      (GInterfaceFinalizeFunc) 0, 0},
   2386     {(GInterfaceInitFunc)atk_editable_text_interface_init,
   2387      (GInterfaceFinalizeFunc) 0, 0},
   2388     {(GInterfaceInitFunc)atk_text_interface_init,
   2389      (GInterfaceFinalizeFunc) 0, 0},
   2390     {(GInterfaceInitFunc)atk_component_interface_init,
   2391      (GInterfaceFinalizeFunc) 0, 0},
   2392     {(GInterfaceInitFunc)atk_image_interface_init,
   2393      (GInterfaceFinalizeFunc) 0, 0},
   2394     {(GInterfaceInitFunc)atk_table_interface_init,
   2395      (GInterfaceFinalizeFunc) 0, 0},
   2396     {(GInterfaceInitFunc)atkHypertextInterfaceInit,
   2397      (GInterfaceFinalizeFunc) 0, 0},
   2398     {(GInterfaceInitFunc)atkHyperlinkImplInterfaceInit,
   2399      (GInterfaceFinalizeFunc) 0, 0},
   2400     {(GInterfaceInitFunc)atk_document_interface_init,
   2401      (GInterfaceFinalizeFunc) 0, 0},
   2402     {(GInterfaceInitFunc)atkValueInterfaceInit,
   2403      (GInterfaceFinalizeFunc) 0, 0}
   2404 };
   2405 
   2406 enum WAIType {
   2407     WAI_ACTION,
   2408     WAI_SELECTION,
   2409     WAI_EDITABLE_TEXT,
   2410     WAI_TEXT,
   2411     WAI_COMPONENT,
   2412     WAI_IMAGE,
   2413     WAI_TABLE,
   2414     WAI_HYPERTEXT,
   2415     WAI_HYPERLINK,
   2416     WAI_DOCUMENT,
   2417     WAI_VALUE,
   2418 };
   2419 
   2420 static GType GetAtkInterfaceTypeFromWAIType(WAIType type)
   2421 {
   2422     switch (type) {
   2423     case WAI_ACTION:
   2424         return ATK_TYPE_ACTION;
   2425     case WAI_SELECTION:
   2426         return ATK_TYPE_SELECTION;
   2427     case WAI_EDITABLE_TEXT:
   2428         return ATK_TYPE_EDITABLE_TEXT;
   2429     case WAI_TEXT:
   2430         return ATK_TYPE_TEXT;
   2431     case WAI_COMPONENT:
   2432         return ATK_TYPE_COMPONENT;
   2433     case WAI_IMAGE:
   2434         return ATK_TYPE_IMAGE;
   2435     case WAI_TABLE:
   2436         return ATK_TYPE_TABLE;
   2437     case WAI_HYPERTEXT:
   2438         return ATK_TYPE_HYPERTEXT;
   2439     case WAI_HYPERLINK:
   2440         return ATK_TYPE_HYPERLINK_IMPL;
   2441     case WAI_DOCUMENT:
   2442         return ATK_TYPE_DOCUMENT;
   2443     case WAI_VALUE:
   2444         return ATK_TYPE_VALUE;
   2445     }
   2446 
   2447     return G_TYPE_INVALID;
   2448 }
   2449 
   2450 static guint16 getInterfaceMaskFromObject(AccessibilityObject* coreObject)
   2451 {
   2452     guint16 interfaceMask = 0;
   2453 
   2454     // Component interface is always supported
   2455     interfaceMask |= 1 << WAI_COMPONENT;
   2456 
   2457     AccessibilityRole role = coreObject->roleValue();
   2458 
   2459     // Action
   2460     // As the implementation of the AtkAction interface is a very
   2461     // basic one (just relays in executing the default action for each
   2462     // object, and only supports having one action per object), it is
   2463     // better just to implement this interface for every instance of
   2464     // the WebKitAccessible class and let WebCore decide what to do.
   2465     interfaceMask |= 1 << WAI_ACTION;
   2466 
   2467     // Selection
   2468     if (coreObject->isListBox() || coreObject->isMenuList())
   2469         interfaceMask |= 1 << WAI_SELECTION;
   2470 
   2471     // Get renderer if available.
   2472     RenderObject* renderer = 0;
   2473     if (coreObject->isAccessibilityRenderObject())
   2474         renderer = coreObject->renderer();
   2475 
   2476     // Hyperlink (links and embedded objects).
   2477     if (coreObject->isLink() || (renderer && renderer->isReplaced()))
   2478         interfaceMask |= 1 << WAI_HYPERLINK;
   2479 
   2480     // Text & Editable Text
   2481     if (role == StaticTextRole || coreObject->isMenuListOption())
   2482         interfaceMask |= 1 << WAI_TEXT;
   2483     else {
   2484         if (coreObject->isTextControl()) {
   2485             interfaceMask |= 1 << WAI_TEXT;
   2486             if (!coreObject->isReadOnly())
   2487                 interfaceMask |= 1 << WAI_EDITABLE_TEXT;
   2488         } else {
   2489             if (role != TableRole) {
   2490                 interfaceMask |= 1 << WAI_HYPERTEXT;
   2491                 if (renderer && renderer->childrenInline())
   2492                     interfaceMask |= 1 << WAI_TEXT;
   2493             }
   2494 
   2495             // Add the TEXT interface for list items whose
   2496             // first accessible child has a text renderer
   2497             if (role == ListItemRole) {
   2498                 AccessibilityObject::AccessibilityChildrenVector children = coreObject->children();
   2499                 if (children.size()) {
   2500                     AccessibilityObject* axRenderChild = children.at(0).get();
   2501                     interfaceMask |= getInterfaceMaskFromObject(axRenderChild);
   2502                 }
   2503             }
   2504         }
   2505     }
   2506 
   2507     // Image
   2508     if (coreObject->isImage())
   2509         interfaceMask |= 1 << WAI_IMAGE;
   2510 
   2511     // Table
   2512     if (role == TableRole)
   2513         interfaceMask |= 1 << WAI_TABLE;
   2514 
   2515     // Document
   2516     if (role == WebAreaRole)
   2517         interfaceMask |= 1 << WAI_DOCUMENT;
   2518 
   2519     // Value
   2520     if (role == SliderRole)
   2521         interfaceMask |= 1 << WAI_VALUE;
   2522 
   2523     return interfaceMask;
   2524 }
   2525 
   2526 static const char* getUniqueAccessibilityTypeName(guint16 interfaceMask)
   2527 {
   2528 #define WAI_TYPE_NAME_LEN (30) /* Enough for prefix + 5 hex characters (max) */
   2529     static char name[WAI_TYPE_NAME_LEN + 1];
   2530 
   2531     g_sprintf(name, "WAIType%x", interfaceMask);
   2532     name[WAI_TYPE_NAME_LEN] = '\0';
   2533 
   2534     return name;
   2535 }
   2536 
   2537 static GType getAccessibilityTypeFromObject(AccessibilityObject* coreObject)
   2538 {
   2539     static const GTypeInfo typeInfo = {
   2540         sizeof(WebKitAccessibleClass),
   2541         (GBaseInitFunc) 0,
   2542         (GBaseFinalizeFunc) 0,
   2543         (GClassInitFunc) 0,
   2544         (GClassFinalizeFunc) 0,
   2545         0, /* class data */
   2546         sizeof(WebKitAccessible), /* instance size */
   2547         0, /* nb preallocs */
   2548         (GInstanceInitFunc) 0,
   2549         0 /* value table */
   2550     };
   2551 
   2552     guint16 interfaceMask = getInterfaceMaskFromObject(coreObject);
   2553     const char* atkTypeName = getUniqueAccessibilityTypeName(interfaceMask);
   2554     GType type = g_type_from_name(atkTypeName);
   2555     if (type)
   2556         return type;
   2557 
   2558     type = g_type_register_static(WEBKIT_TYPE_ACCESSIBLE,
   2559                                   atkTypeName,
   2560                                   &typeInfo, GTypeFlags(0));
   2561     for (guint i = 0; i < G_N_ELEMENTS(AtkInterfacesInitFunctions); i++) {
   2562         if (interfaceMask & (1 << i))
   2563             g_type_add_interface_static(type,
   2564                                         GetAtkInterfaceTypeFromWAIType(static_cast<WAIType>(i)),
   2565                                         &AtkInterfacesInitFunctions[i]);
   2566     }
   2567 
   2568     return type;
   2569 }
   2570 
   2571 WebKitAccessible* webkit_accessible_new(AccessibilityObject* coreObject)
   2572 {
   2573     GType type = getAccessibilityTypeFromObject(coreObject);
   2574     AtkObject* object = static_cast<AtkObject*>(g_object_new(type, 0));
   2575 
   2576     atk_object_initialize(object, coreObject);
   2577 
   2578     return WEBKIT_ACCESSIBLE(object);
   2579 }
   2580 
   2581 AccessibilityObject* webkit_accessible_get_accessibility_object(WebKitAccessible* accessible)
   2582 {
   2583     return accessible->m_object;
   2584 }
   2585 
   2586 void webkit_accessible_detach(WebKitAccessible* accessible)
   2587 {
   2588     ASSERT(accessible->m_object);
   2589 
   2590     if (core(accessible)->roleValue() == WebAreaRole)
   2591         g_signal_emit_by_name(accessible, "state-change", "defunct", true);
   2592 
   2593     // We replace the WebCore AccessibilityObject with a fallback object that
   2594     // provides default implementations to avoid repetitive null-checking after
   2595     // detachment.
   2596     accessible->m_object = fallbackObject();
   2597 }
   2598 
   2599 AtkObject* webkit_accessible_get_focused_element(WebKitAccessible* accessible)
   2600 {
   2601     if (!accessible->m_object)
   2602         return 0;
   2603 
   2604     RefPtr<AccessibilityObject> focusedObj = accessible->m_object->focusedUIElement();
   2605     if (!focusedObj)
   2606         return 0;
   2607 
   2608     return focusedObj->wrapper();
   2609 }
   2610 
   2611 AccessibilityObject* objectAndOffsetUnignored(AccessibilityObject* coreObject, int& offset, bool ignoreLinks)
   2612 {
   2613     // Indication that something bogus has transpired.
   2614     offset = -1;
   2615 
   2616     AccessibilityObject* realObject = coreObject;
   2617     if (realObject->accessibilityIsIgnored())
   2618         realObject = realObject->parentObjectUnignored();
   2619     if (!realObject)
   2620         return 0;
   2621 
   2622     if (ignoreLinks && realObject->isLink())
   2623         realObject = realObject->parentObjectUnignored();
   2624     if (!realObject)
   2625         return 0;
   2626 
   2627     Node* node = realObject->node();
   2628     if (node) {
   2629         VisiblePosition startPosition = VisiblePosition(positionBeforeNode(node), DOWNSTREAM);
   2630         VisiblePosition endPosition = realObject->selection().visibleEnd();
   2631 
   2632         if (startPosition == endPosition)
   2633             offset = 0;
   2634         else if (!isStartOfLine(endPosition)) {
   2635             RefPtr<Range> range = makeRange(startPosition, endPosition.previous());
   2636             offset = TextIterator::rangeLength(range.get(), true) + 1;
   2637         } else {
   2638             RefPtr<Range> range = makeRange(startPosition, endPosition);
   2639             offset = TextIterator::rangeLength(range.get(), true);
   2640         }
   2641 
   2642     }
   2643 
   2644     return realObject;
   2645 }
   2646 
   2647 #endif // HAVE(ACCESSIBILITY)
   2648