WebCore/accessibility/gtk/AccessibilityObjectWrapperAtk.cpp
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     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 "AccessibilityListBox.h"
       
    38 #include "AccessibilityListBoxOption.h"
       
    39 #include "AccessibilityRenderObject.h"
       
    40 #include "AccessibilityTable.h"
       
    41 #include "AccessibilityTableCell.h"
       
    42 #include "AccessibilityTableColumn.h"
       
    43 #include "AccessibilityTableRow.h"
       
    44 #include "AtomicString.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 "RenderText.h"
       
    59 #include "TextEncoding.h"
       
    60 #include <wtf/text/CString.h>
       
    61 
       
    62 #include <atk/atk.h>
       
    63 #include <glib.h>
       
    64 #include <glib/gprintf.h>
       
    65 #include <libgail-util/gail-util.h>
       
    66 #include <pango/pango.h>
       
    67 
       
    68 using namespace WebCore;
       
    69 
       
    70 static AccessibilityObject* fallbackObject()
       
    71 {
       
    72     static AXObjectCache* fallbackCache = new AXObjectCache;
       
    73     static AccessibilityObject* object = 0;
       
    74     if (!object) {
       
    75         // FIXME: using fallbackCache->getOrCreate(ListBoxOptionRole) is a hack
       
    76         object = fallbackCache->getOrCreate(ListBoxOptionRole);
       
    77         object->ref();
       
    78     }
       
    79 
       
    80     return object;
       
    81 }
       
    82 
       
    83 // Used to provide const char* returns.
       
    84 static const char* returnString(const String& str)
       
    85 {
       
    86     static CString returnedString;
       
    87     returnedString = str.utf8();
       
    88     return returnedString.data();
       
    89 }
       
    90 
       
    91 static AccessibilityObject* core(WebKitAccessible* accessible)
       
    92 {
       
    93     if (!accessible)
       
    94         return 0;
       
    95 
       
    96     return accessible->m_object;
       
    97 }
       
    98 
       
    99 static AccessibilityObject* core(AtkObject* object)
       
   100 {
       
   101     if (!WEBKIT_IS_ACCESSIBLE(object))
       
   102         return 0;
       
   103 
       
   104     return core(WEBKIT_ACCESSIBLE(object));
       
   105 }
       
   106 
       
   107 static AccessibilityObject* core(AtkAction* action)
       
   108 {
       
   109     return core(ATK_OBJECT(action));
       
   110 }
       
   111 
       
   112 static AccessibilityObject* core(AtkSelection* selection)
       
   113 {
       
   114     return core(ATK_OBJECT(selection));
       
   115 }
       
   116 
       
   117 static AccessibilityObject* core(AtkText* text)
       
   118 {
       
   119     return core(ATK_OBJECT(text));
       
   120 }
       
   121 
       
   122 static AccessibilityObject* core(AtkEditableText* text)
       
   123 {
       
   124     return core(ATK_OBJECT(text));
       
   125 }
       
   126 
       
   127 static AccessibilityObject* core(AtkComponent* component)
       
   128 {
       
   129     return core(ATK_OBJECT(component));
       
   130 }
       
   131 
       
   132 static AccessibilityObject* core(AtkImage* image)
       
   133 {
       
   134     return core(ATK_OBJECT(image));
       
   135 }
       
   136 
       
   137 static AccessibilityObject* core(AtkTable* table)
       
   138 {
       
   139     return core(ATK_OBJECT(table));
       
   140 }
       
   141 
       
   142 static AccessibilityObject* core(AtkDocument* document)
       
   143 {
       
   144     return core(ATK_OBJECT(document));
       
   145 }
       
   146 
       
   147 static gchar* webkit_accessible_text_get_text(AtkText* text, gint startOffset, gint endOffset);
       
   148 
       
   149 static const gchar* webkit_accessible_get_name(AtkObject* object)
       
   150 {
       
   151     AccessibilityObject* coreObject = core(object);
       
   152     if (!coreObject->isAccessibilityRenderObject())
       
   153         return returnString(coreObject->stringValue());
       
   154 
       
   155     AccessibilityRenderObject* renderObject = static_cast<AccessibilityRenderObject*>(coreObject);
       
   156     if (coreObject->isControl()) {
       
   157         AccessibilityObject* label = renderObject->correspondingLabelForControlElement();
       
   158         if (label) {
       
   159             AtkObject* atkObject = label->wrapper();
       
   160             if (ATK_IS_TEXT(atkObject))
       
   161                 return webkit_accessible_text_get_text(ATK_TEXT(atkObject), 0, -1);
       
   162         }
       
   163     }
       
   164 
       
   165     if (renderObject->isImage() || renderObject->isInputImage()) {
       
   166         Node* node = renderObject->renderer()->node();
       
   167         if (node && node->isHTMLElement()) {
       
   168             // Get the attribute rather than altText String so as not to fall back on title.
       
   169             String alt = static_cast<HTMLElement*>(node)->getAttribute(HTMLNames::altAttr);
       
   170             if (!alt.isEmpty())
       
   171                 return returnString(alt);
       
   172         }
       
   173     }
       
   174 
       
   175     return returnString(coreObject->stringValue());
       
   176 }
       
   177 
       
   178 static const gchar* webkit_accessible_get_description(AtkObject* object)
       
   179 {
       
   180     AccessibilityObject* coreObject = core(object);
       
   181     Node* node = 0;
       
   182     if (coreObject->isAccessibilityRenderObject())
       
   183         node = static_cast<AccessibilityRenderObject*>(coreObject)->renderer()->node();
       
   184     if (!node || !node->isHTMLElement() || coreObject->ariaRoleAttribute() != UnknownRole)
       
   185         return returnString(coreObject->accessibilityDescription());
       
   186 
       
   187     // atk_table_get_summary returns an AtkObject. We have no summary object, so expose summary here.
       
   188     if (coreObject->roleValue() == TableRole) {
       
   189         String summary = static_cast<HTMLTableElement*>(node)->summary();
       
   190         if (!summary.isEmpty())
       
   191             return returnString(summary);
       
   192     }
       
   193 
       
   194     // The title attribute should be reliably available as the object's descripton.
       
   195     // We do not want to fall back on other attributes in its absence. See bug 25524.
       
   196     String title = static_cast<HTMLElement*>(node)->title();
       
   197     if (!title.isEmpty())
       
   198         return returnString(title);
       
   199 
       
   200     return returnString(coreObject->accessibilityDescription());
       
   201 }
       
   202 
       
   203 static void setAtkRelationSetFromCoreObject(AccessibilityObject* coreObject, AtkRelationSet* relationSet)
       
   204 {
       
   205     AccessibilityRenderObject* accObject = static_cast<AccessibilityRenderObject*>(coreObject);
       
   206     if (accObject->isControl()) {
       
   207         AccessibilityObject* label = accObject->correspondingLabelForControlElement();
       
   208         if (label)
       
   209             atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_LABELLED_BY, label->wrapper());
       
   210     } else {
       
   211         AccessibilityObject* control = accObject->correspondingControlForLabelElement();
       
   212         if (control)
       
   213             atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_LABEL_FOR, control->wrapper());
       
   214     }
       
   215 }
       
   216 
       
   217 static gpointer webkit_accessible_parent_class = 0;
       
   218 
       
   219 static AtkObject* atkParentOfWebView(AtkObject* object)
       
   220 {
       
   221     AccessibilityObject* coreParent = core(object)->parentObjectUnignored();
       
   222 
       
   223     // The top level web view claims to not have a parent. This makes it
       
   224     // impossible for assistive technologies to ascend the accessible
       
   225     // hierarchy all the way to the application. (Bug 30489)
       
   226     if (!coreParent && core(object)->isWebArea()) {
       
   227         HostWindow* hostWindow = core(object)->document()->view()->hostWindow();
       
   228         if (hostWindow) {
       
   229             PlatformPageClient webView = hostWindow->platformPageClient();
       
   230             if (webView) {
       
   231                 GtkWidget* webViewParent = gtk_widget_get_parent(webView);
       
   232                 if (webViewParent)
       
   233                     return gtk_widget_get_accessible(webViewParent);
       
   234             }
       
   235         }
       
   236     }
       
   237 
       
   238     if (!coreParent)
       
   239         return 0;
       
   240 
       
   241     return coreParent->wrapper();
       
   242 }
       
   243 
       
   244 static AtkObject* webkit_accessible_get_parent(AtkObject* object)
       
   245 {
       
   246     AccessibilityObject* coreParent = core(object)->parentObjectUnignored();
       
   247     if (!coreParent && core(object)->isWebArea())
       
   248         return atkParentOfWebView(object);
       
   249 
       
   250     if (!coreParent)
       
   251         return 0;
       
   252 
       
   253     return coreParent->wrapper();
       
   254 }
       
   255 
       
   256 static gint webkit_accessible_get_n_children(AtkObject* object)
       
   257 {
       
   258     return core(object)->children().size();
       
   259 }
       
   260 
       
   261 static AtkObject* webkit_accessible_ref_child(AtkObject* object, gint index)
       
   262 {
       
   263     AccessibilityObject* coreObject = core(object);
       
   264     AccessibilityObject::AccessibilityChildrenVector children = coreObject->children();
       
   265     if (index < 0 || static_cast<unsigned>(index) >= children.size())
       
   266         return 0;
       
   267 
       
   268     AccessibilityObject* coreChild = children.at(index).get();
       
   269 
       
   270     if (!coreChild)
       
   271         return 0;
       
   272 
       
   273     AtkObject* child = coreChild->wrapper();
       
   274     atk_object_set_parent(child, object);
       
   275     g_object_ref(child);
       
   276 
       
   277     return child;
       
   278 }
       
   279 
       
   280 static gint webkit_accessible_get_index_in_parent(AtkObject* object)
       
   281 {
       
   282     AccessibilityObject* coreObject = core(object);
       
   283     AccessibilityObject* parent = coreObject->parentObjectUnignored();
       
   284 
       
   285     if (!parent && core(object)->isWebArea()) {
       
   286         AtkObject* atkParent = atkParentOfWebView(object);
       
   287         if (!atkParent)
       
   288             return -1;
       
   289 
       
   290         unsigned count = atk_object_get_n_accessible_children(atkParent);
       
   291         for (unsigned i = 0; i < count; ++i) {
       
   292             AtkObject* child = atk_object_ref_accessible_child(atkParent, i);
       
   293             bool childIsObject = child == object;
       
   294             g_object_unref(child);
       
   295             if (childIsObject)
       
   296                 return i;
       
   297         }
       
   298     }
       
   299 
       
   300     AccessibilityObject::AccessibilityChildrenVector children = parent->children();
       
   301     unsigned count = children.size();
       
   302     for (unsigned i = 0; i < count; ++i) {
       
   303         if (children[i] == coreObject)
       
   304             return i;
       
   305     }
       
   306 
       
   307     return -1;
       
   308 }
       
   309 
       
   310 static AtkAttributeSet* addAttributeToSet(AtkAttributeSet* attributeSet, const char* name, const char* value)
       
   311 {
       
   312     AtkAttribute* attribute = static_cast<AtkAttribute*>(g_malloc(sizeof(AtkAttribute)));
       
   313     attribute->name = g_strdup(name);
       
   314     attribute->value = g_strdup(value);
       
   315     attributeSet = g_slist_prepend(attributeSet, attribute);
       
   316 
       
   317     return attributeSet;
       
   318 }
       
   319 
       
   320 static AtkAttributeSet* webkit_accessible_get_attributes(AtkObject* object)
       
   321 {
       
   322     AtkAttributeSet* attributeSet = 0;
       
   323 
       
   324     attributeSet = addAttributeToSet(attributeSet, "toolkit", "WebKitGtk");
       
   325 
       
   326     int headingLevel = core(object)->headingLevel();
       
   327     if (headingLevel) {
       
   328         String value = String::number(headingLevel);
       
   329         attributeSet = addAttributeToSet(attributeSet, "level", value.utf8().data());
       
   330     }
       
   331     return attributeSet;
       
   332 }
       
   333 
       
   334 static AtkRole atkRole(AccessibilityRole role)
       
   335 {
       
   336     switch (role) {
       
   337     case UnknownRole:
       
   338         return ATK_ROLE_UNKNOWN;
       
   339     case ButtonRole:
       
   340         return ATK_ROLE_PUSH_BUTTON;
       
   341     case RadioButtonRole:
       
   342         return ATK_ROLE_RADIO_BUTTON;
       
   343     case CheckBoxRole:
       
   344         return ATK_ROLE_CHECK_BOX;
       
   345     case SliderRole:
       
   346         return ATK_ROLE_SLIDER;
       
   347     case TabGroupRole:
       
   348         return ATK_ROLE_PAGE_TAB_LIST;
       
   349     case TextFieldRole:
       
   350     case TextAreaRole:
       
   351         return ATK_ROLE_ENTRY;
       
   352     case StaticTextRole:
       
   353         return ATK_ROLE_TEXT;
       
   354     case OutlineRole:
       
   355         return ATK_ROLE_TREE;
       
   356     case MenuBarRole:
       
   357         return ATK_ROLE_MENU_BAR;
       
   358     case MenuListPopupRole:
       
   359     case MenuRole:
       
   360         return ATK_ROLE_MENU;
       
   361     case MenuListOptionRole:
       
   362     case MenuItemRole:
       
   363         return ATK_ROLE_MENU_ITEM;
       
   364     case ColumnRole:
       
   365         //return ATK_ROLE_TABLE_COLUMN_HEADER; // Is this right?
       
   366         return ATK_ROLE_UNKNOWN; // Matches Mozilla
       
   367     case RowRole:
       
   368         //return ATK_ROLE_TABLE_ROW_HEADER; // Is this right?
       
   369         return ATK_ROLE_LIST_ITEM; // Matches Mozilla
       
   370     case ToolbarRole:
       
   371         return ATK_ROLE_TOOL_BAR;
       
   372     case BusyIndicatorRole:
       
   373         return ATK_ROLE_PROGRESS_BAR; // Is this right?
       
   374     case ProgressIndicatorRole:
       
   375         //return ATK_ROLE_SPIN_BUTTON; // Some confusion about this role in AccessibilityRenderObject.cpp
       
   376         return ATK_ROLE_PROGRESS_BAR;
       
   377     case WindowRole:
       
   378         return ATK_ROLE_WINDOW;
       
   379     case PopUpButtonRole:
       
   380     case ComboBoxRole:
       
   381         return ATK_ROLE_COMBO_BOX;
       
   382     case SplitGroupRole:
       
   383         return ATK_ROLE_SPLIT_PANE;
       
   384     case SplitterRole:
       
   385         return ATK_ROLE_SEPARATOR;
       
   386     case ColorWellRole:
       
   387         return ATK_ROLE_COLOR_CHOOSER;
       
   388     case ListRole:
       
   389         return ATK_ROLE_LIST;
       
   390     case ScrollBarRole:
       
   391         return ATK_ROLE_SCROLL_BAR;
       
   392     case GridRole: // Is this right?
       
   393     case TableRole:
       
   394         return ATK_ROLE_TABLE;
       
   395     case ApplicationRole:
       
   396         return ATK_ROLE_APPLICATION;
       
   397     case GroupRole:
       
   398     case RadioGroupRole:
       
   399         return ATK_ROLE_PANEL;
       
   400     case CellRole:
       
   401         return ATK_ROLE_TABLE_CELL;
       
   402     case LinkRole:
       
   403     case WebCoreLinkRole:
       
   404     case ImageMapLinkRole:
       
   405         return ATK_ROLE_LINK;
       
   406     case ImageMapRole:
       
   407     case ImageRole:
       
   408         return ATK_ROLE_IMAGE;
       
   409     case ListMarkerRole:
       
   410         return ATK_ROLE_TEXT;
       
   411     case WebAreaRole:
       
   412         //return ATK_ROLE_HTML_CONTAINER; // Is this right?
       
   413         return ATK_ROLE_DOCUMENT_FRAME;
       
   414     case HeadingRole:
       
   415         return ATK_ROLE_HEADING;
       
   416     case ListBoxRole:
       
   417         return ATK_ROLE_LIST;
       
   418     case ListItemRole:
       
   419     case ListBoxOptionRole:
       
   420         return ATK_ROLE_LIST_ITEM;
       
   421     default:
       
   422         return ATK_ROLE_UNKNOWN;
       
   423     }
       
   424 }
       
   425 
       
   426 static AtkRole webkit_accessible_get_role(AtkObject* object)
       
   427 {
       
   428     AccessibilityObject* axObject = core(object);
       
   429 
       
   430     if (!axObject)
       
   431         return ATK_ROLE_UNKNOWN;
       
   432 
       
   433     // WebCore does not know about paragraph role, label role, or section role
       
   434     if (axObject->isAccessibilityRenderObject()) {
       
   435         Node* node = static_cast<AccessibilityRenderObject*>(axObject)->renderer()->node();
       
   436         if (node) {
       
   437             if (node->hasTagName(HTMLNames::pTag))
       
   438                 return ATK_ROLE_PARAGRAPH;
       
   439             if (node->hasTagName(HTMLNames::labelTag))
       
   440                 return ATK_ROLE_LABEL;
       
   441             if (node->hasTagName(HTMLNames::divTag))
       
   442                 return ATK_ROLE_SECTION;
       
   443             if (node->hasTagName(HTMLNames::formTag))
       
   444                 return ATK_ROLE_FORM;
       
   445         }
       
   446     }
       
   447 
       
   448     // Note: Why doesn't WebCore have a password field for this
       
   449     if (axObject->isPasswordField())
       
   450         return ATK_ROLE_PASSWORD_TEXT;
       
   451 
       
   452     return atkRole(axObject->roleValue());
       
   453 }
       
   454 
       
   455 static void setAtkStateSetFromCoreObject(AccessibilityObject* coreObject, AtkStateSet* stateSet)
       
   456 {
       
   457     AccessibilityObject* parent = coreObject->parentObject();
       
   458     bool isListBoxOption = parent && parent->isListBox();
       
   459 
       
   460     // Please keep the state list in alphabetical order
       
   461     if (coreObject->isChecked())
       
   462         atk_state_set_add_state(stateSet, ATK_STATE_CHECKED);
       
   463 
       
   464     // FIXME: isReadOnly does not seem to do the right thing for
       
   465     // controls, so check explicitly for them. In addition, because
       
   466     // isReadOnly is false for listBoxOptions, we need to add one
       
   467     // more check so that we do not present them as being "editable".
       
   468     if ((!coreObject->isReadOnly() ||
       
   469         (coreObject->isControl() && coreObject->canSetValueAttribute())) &&
       
   470         !isListBoxOption)
       
   471         atk_state_set_add_state(stateSet, ATK_STATE_EDITABLE);
       
   472 
       
   473     // FIXME: Put both ENABLED and SENSITIVE together here for now
       
   474     if (coreObject->isEnabled()) {
       
   475         atk_state_set_add_state(stateSet, ATK_STATE_ENABLED);
       
   476         atk_state_set_add_state(stateSet, ATK_STATE_SENSITIVE);
       
   477     }
       
   478 
       
   479     if (coreObject->canSetFocusAttribute())
       
   480         atk_state_set_add_state(stateSet, ATK_STATE_FOCUSABLE);
       
   481 
       
   482     if (coreObject->isFocused())
       
   483         atk_state_set_add_state(stateSet, ATK_STATE_FOCUSED);
       
   484 
       
   485     // TODO: ATK_STATE_HORIZONTAL
       
   486 
       
   487     if (coreObject->isIndeterminate())
       
   488         atk_state_set_add_state(stateSet, ATK_STATE_INDETERMINATE);
       
   489 
       
   490     if (coreObject->isMultiSelectable())
       
   491         atk_state_set_add_state(stateSet, ATK_STATE_MULTISELECTABLE);
       
   492 
       
   493     // TODO: ATK_STATE_OPAQUE
       
   494 
       
   495     if (coreObject->isPressed())
       
   496         atk_state_set_add_state(stateSet, ATK_STATE_PRESSED);
       
   497 
       
   498     // TODO: ATK_STATE_SELECTABLE_TEXT
       
   499 
       
   500     if (coreObject->canSetSelectedAttribute()) {
       
   501         atk_state_set_add_state(stateSet, ATK_STATE_SELECTABLE);
       
   502         // Items in focusable lists in Gtk have both STATE_SELECT{ABLE,ED}
       
   503         // and STATE_FOCUS{ABLE,ED}. We'll fake the latter based on the
       
   504         // former.
       
   505         if (isListBoxOption)
       
   506             atk_state_set_add_state(stateSet, ATK_STATE_FOCUSABLE);
       
   507     }
       
   508 
       
   509     if (coreObject->isSelected()) {
       
   510         atk_state_set_add_state(stateSet, ATK_STATE_SELECTED);
       
   511         // Items in focusable lists in Gtk have both STATE_SELECT{ABLE,ED}
       
   512         // and STATE_FOCUS{ABLE,ED}. We'll fake the latter based on the
       
   513         // former.
       
   514         if (isListBoxOption)
       
   515             atk_state_set_add_state(stateSet, ATK_STATE_FOCUSED);
       
   516     }
       
   517 
       
   518     // FIXME: Group both SHOWING and VISIBLE here for now
       
   519     // Not sure how to handle this in WebKit, see bug
       
   520     // http://bugzilla.gnome.org/show_bug.cgi?id=509650 for other
       
   521     // issues with SHOWING vs VISIBLE within GTK+
       
   522     if (!coreObject->isOffScreen()) {
       
   523         atk_state_set_add_state(stateSet, ATK_STATE_SHOWING);
       
   524         atk_state_set_add_state(stateSet, ATK_STATE_VISIBLE);
       
   525     }
       
   526 
       
   527     // Mutually exclusive, so we group these two
       
   528     if (coreObject->roleValue() == TextFieldRole)
       
   529         atk_state_set_add_state(stateSet, ATK_STATE_SINGLE_LINE);
       
   530     else if (coreObject->roleValue() == TextAreaRole)
       
   531         atk_state_set_add_state(stateSet, ATK_STATE_MULTI_LINE);
       
   532 
       
   533     // TODO: ATK_STATE_SENSITIVE
       
   534 
       
   535     // TODO: ATK_STATE_VERTICAL
       
   536 
       
   537     if (coreObject->isVisited())
       
   538         atk_state_set_add_state(stateSet, ATK_STATE_VISITED);
       
   539 }
       
   540 
       
   541 static AtkStateSet* webkit_accessible_ref_state_set(AtkObject* object)
       
   542 {
       
   543     AtkStateSet* stateSet = ATK_OBJECT_CLASS(webkit_accessible_parent_class)->ref_state_set(object);
       
   544     AccessibilityObject* coreObject = core(object);
       
   545 
       
   546     if (coreObject == fallbackObject()) {
       
   547         atk_state_set_add_state(stateSet, ATK_STATE_DEFUNCT);
       
   548         return stateSet;
       
   549     }
       
   550 
       
   551     setAtkStateSetFromCoreObject(coreObject, stateSet);
       
   552 
       
   553     return stateSet;
       
   554 }
       
   555 
       
   556 static AtkRelationSet* webkit_accessible_ref_relation_set(AtkObject* object)
       
   557 {
       
   558     AtkRelationSet* relationSet = ATK_OBJECT_CLASS(webkit_accessible_parent_class)->ref_relation_set(object);
       
   559     AccessibilityObject* coreObject = core(object);
       
   560 
       
   561     setAtkRelationSetFromCoreObject(coreObject, relationSet);
       
   562 
       
   563     return relationSet;
       
   564 }
       
   565 
       
   566 static void webkit_accessible_init(AtkObject* object, gpointer data)
       
   567 {
       
   568     if (ATK_OBJECT_CLASS(webkit_accessible_parent_class)->initialize)
       
   569         ATK_OBJECT_CLASS(webkit_accessible_parent_class)->initialize(object, data);
       
   570 
       
   571     WEBKIT_ACCESSIBLE(object)->m_object = reinterpret_cast<AccessibilityObject*>(data);
       
   572 }
       
   573 
       
   574 static void webkit_accessible_finalize(GObject* object)
       
   575 {
       
   576     // This is a good time to clear the return buffer.
       
   577     returnString(String());
       
   578 
       
   579     G_OBJECT_CLASS(webkit_accessible_parent_class)->finalize(object);
       
   580 }
       
   581 
       
   582 static void webkit_accessible_class_init(AtkObjectClass* klass)
       
   583 {
       
   584     GObjectClass* gobjectClass = G_OBJECT_CLASS(klass);
       
   585 
       
   586     webkit_accessible_parent_class = g_type_class_peek_parent(klass);
       
   587 
       
   588     gobjectClass->finalize = webkit_accessible_finalize;
       
   589 
       
   590     klass->initialize = webkit_accessible_init;
       
   591     klass->get_name = webkit_accessible_get_name;
       
   592     klass->get_description = webkit_accessible_get_description;
       
   593     klass->get_parent = webkit_accessible_get_parent;
       
   594     klass->get_n_children = webkit_accessible_get_n_children;
       
   595     klass->ref_child = webkit_accessible_ref_child;
       
   596     klass->get_role = webkit_accessible_get_role;
       
   597     klass->ref_state_set = webkit_accessible_ref_state_set;
       
   598     klass->get_index_in_parent = webkit_accessible_get_index_in_parent;
       
   599     klass->get_attributes = webkit_accessible_get_attributes;
       
   600     klass->ref_relation_set = webkit_accessible_ref_relation_set;
       
   601 }
       
   602 
       
   603 GType
       
   604 webkit_accessible_get_type(void)
       
   605 {
       
   606     static volatile gsize type_volatile = 0;
       
   607 
       
   608     if (g_once_init_enter(&type_volatile)) {
       
   609         static const GTypeInfo tinfo = {
       
   610             sizeof(WebKitAccessibleClass),
       
   611             (GBaseInitFunc) 0,
       
   612             (GBaseFinalizeFunc) 0,
       
   613             (GClassInitFunc) webkit_accessible_class_init,
       
   614             (GClassFinalizeFunc) 0,
       
   615             0, /* class data */
       
   616             sizeof(WebKitAccessible), /* instance size */
       
   617             0, /* nb preallocs */
       
   618             (GInstanceInitFunc) 0,
       
   619             0 /* value table */
       
   620         };
       
   621 
       
   622         GType type = g_type_register_static(ATK_TYPE_OBJECT,
       
   623                                             "WebKitAccessible", &tinfo, GTypeFlags(0));
       
   624         g_once_init_leave(&type_volatile, type);
       
   625     }
       
   626 
       
   627     return type_volatile;
       
   628 }
       
   629 
       
   630 static gboolean webkit_accessible_action_do_action(AtkAction* action, gint i)
       
   631 {
       
   632     g_return_val_if_fail(i == 0, FALSE);
       
   633     return core(action)->performDefaultAction();
       
   634 }
       
   635 
       
   636 static gint webkit_accessible_action_get_n_actions(AtkAction* action)
       
   637 {
       
   638     return 1;
       
   639 }
       
   640 
       
   641 static const gchar* webkit_accessible_action_get_description(AtkAction* action, gint i)
       
   642 {
       
   643     g_return_val_if_fail(i == 0, 0);
       
   644     // TODO: Need a way to provide/localize action descriptions.
       
   645     notImplemented();
       
   646     return "";
       
   647 }
       
   648 
       
   649 static const gchar* webkit_accessible_action_get_keybinding(AtkAction* action, gint i)
       
   650 {
       
   651     g_return_val_if_fail(i == 0, 0);
       
   652     // FIXME: Construct a proper keybinding string.
       
   653     return returnString(core(action)->accessKey().string());
       
   654 }
       
   655 
       
   656 static const gchar* webkit_accessible_action_get_name(AtkAction* action, gint i)
       
   657 {
       
   658     g_return_val_if_fail(i == 0, 0);
       
   659     return returnString(core(action)->actionVerb());
       
   660 }
       
   661 
       
   662 static void atk_action_interface_init(AtkActionIface* iface)
       
   663 {
       
   664     iface->do_action = webkit_accessible_action_do_action;
       
   665     iface->get_n_actions = webkit_accessible_action_get_n_actions;
       
   666     iface->get_description = webkit_accessible_action_get_description;
       
   667     iface->get_keybinding = webkit_accessible_action_get_keybinding;
       
   668     iface->get_name = webkit_accessible_action_get_name;
       
   669 }
       
   670 
       
   671 // Selection (for controls)
       
   672 
       
   673 static AccessibilityObject* optionFromList(AtkSelection* selection, gint i)
       
   674 {
       
   675     AccessibilityObject* coreSelection = core(selection);
       
   676     if (!coreSelection || i < 0)
       
   677         return 0;
       
   678 
       
   679     AccessibilityRenderObject::AccessibilityChildrenVector options = core(selection)->children();
       
   680     if (i < static_cast<gint>(options.size()))
       
   681         return options.at(i).get();
       
   682 
       
   683     return 0;
       
   684 }
       
   685 
       
   686 static AccessibilityObject* optionFromSelection(AtkSelection* selection, gint i)
       
   687 {
       
   688     // i is the ith selection as opposed to the ith child.
       
   689 
       
   690     AccessibilityObject* coreSelection = core(selection);
       
   691     if (!coreSelection || i < 0)
       
   692         return 0;
       
   693 
       
   694     AccessibilityRenderObject::AccessibilityChildrenVector selectedItems;
       
   695     if (coreSelection->isListBox())
       
   696         static_cast<AccessibilityListBox*>(coreSelection)->selectedChildren(selectedItems);
       
   697 
       
   698     // TODO: Combo boxes
       
   699 
       
   700     if (i < static_cast<gint>(selectedItems.size()))
       
   701         return selectedItems.at(i).get();
       
   702 
       
   703     return 0;
       
   704 }
       
   705 
       
   706 static gboolean webkit_accessible_selection_add_selection(AtkSelection* selection, gint i)
       
   707 {
       
   708     AccessibilityObject* option = optionFromList(selection, i);
       
   709     if (option && core(selection)->isListBox()) {
       
   710         AccessibilityListBoxOption* listBoxOption = static_cast<AccessibilityListBoxOption*>(option);
       
   711         listBoxOption->setSelected(true);
       
   712         return listBoxOption->isSelected();
       
   713     }
       
   714 
       
   715     return false;
       
   716 }
       
   717 
       
   718 static gboolean webkit_accessible_selection_clear_selection(AtkSelection* selection)
       
   719 {
       
   720     AccessibilityObject* coreSelection = core(selection);
       
   721     if (!coreSelection)
       
   722         return false;
       
   723 
       
   724     AccessibilityRenderObject::AccessibilityChildrenVector selectedItems;
       
   725     if (coreSelection->isListBox()) {
       
   726         // Set the list of selected items to an empty list; then verify that it worked.
       
   727         AccessibilityListBox* listBox = static_cast<AccessibilityListBox*>(coreSelection);
       
   728         listBox->setSelectedChildren(selectedItems);
       
   729         listBox->selectedChildren(selectedItems);
       
   730         return selectedItems.size() == 0;
       
   731     }
       
   732     return false;
       
   733 }
       
   734 
       
   735 static AtkObject* webkit_accessible_selection_ref_selection(AtkSelection* selection, gint i)
       
   736 {
       
   737     AccessibilityObject* option = optionFromSelection(selection, i);
       
   738     if (option) {
       
   739         AtkObject* child = option->wrapper();
       
   740         g_object_ref(child);
       
   741         return child;
       
   742     }
       
   743 
       
   744     return 0;
       
   745 }
       
   746 
       
   747 static gint webkit_accessible_selection_get_selection_count(AtkSelection* selection)
       
   748 {
       
   749     AccessibilityObject* coreSelection = core(selection);
       
   750     if (coreSelection && coreSelection->isListBox()) {
       
   751         AccessibilityRenderObject::AccessibilityChildrenVector selectedItems;
       
   752         static_cast<AccessibilityListBox*>(coreSelection)->selectedChildren(selectedItems);
       
   753         return static_cast<gint>(selectedItems.size());
       
   754     }
       
   755 
       
   756     return 0;
       
   757 }
       
   758 
       
   759 static gboolean webkit_accessible_selection_is_child_selected(AtkSelection* selection, gint i)
       
   760 {
       
   761     AccessibilityObject* option = optionFromList(selection, i);
       
   762     if (option && core(selection)->isListBox())
       
   763         return static_cast<AccessibilityListBoxOption*>(option)->isSelected();
       
   764 
       
   765     return false;
       
   766 }
       
   767 
       
   768 static gboolean webkit_accessible_selection_remove_selection(AtkSelection* selection, gint i)
       
   769 {
       
   770     // TODO: This is only getting called if i == 0. What is preventing the rest?
       
   771     AccessibilityObject* option = optionFromSelection(selection, i);
       
   772     if (option && core(selection)->isListBox()) {
       
   773         AccessibilityListBoxOption* listBoxOption = static_cast<AccessibilityListBoxOption*>(option);
       
   774         listBoxOption->setSelected(false);
       
   775         return !listBoxOption->isSelected();
       
   776     }
       
   777 
       
   778     return false;
       
   779 }
       
   780 
       
   781 static gboolean webkit_accessible_selection_select_all_selection(AtkSelection* selection)
       
   782 {
       
   783     AccessibilityObject* coreSelection = core(selection);
       
   784     if (!coreSelection || !coreSelection->isMultiSelectable())
       
   785         return false;
       
   786 
       
   787     AccessibilityRenderObject::AccessibilityChildrenVector children = coreSelection->children();
       
   788     if (coreSelection->isListBox()) {
       
   789         AccessibilityListBox* listBox = static_cast<AccessibilityListBox*>(coreSelection);
       
   790         listBox->setSelectedChildren(children);
       
   791         AccessibilityRenderObject::AccessibilityChildrenVector selectedItems;
       
   792         listBox->selectedChildren(selectedItems);
       
   793         return selectedItems.size() == children.size();
       
   794     }
       
   795 
       
   796     return false;
       
   797 }
       
   798 
       
   799 static void atk_selection_interface_init(AtkSelectionIface* iface)
       
   800 {
       
   801     iface->add_selection = webkit_accessible_selection_add_selection;
       
   802     iface->clear_selection = webkit_accessible_selection_clear_selection;
       
   803     iface->ref_selection = webkit_accessible_selection_ref_selection;
       
   804     iface->get_selection_count = webkit_accessible_selection_get_selection_count;
       
   805     iface->is_child_selected = webkit_accessible_selection_is_child_selected;
       
   806     iface->remove_selection = webkit_accessible_selection_remove_selection;
       
   807     iface->select_all_selection = webkit_accessible_selection_select_all_selection;
       
   808 }
       
   809 
       
   810 // Text
       
   811 
       
   812 static gchar* utf8Substr(const gchar* string, gint start, gint end)
       
   813 {
       
   814     ASSERT(string);
       
   815     glong strLen = g_utf8_strlen(string, -1);
       
   816     if (start > strLen || end > strLen)
       
   817         return 0;
       
   818     gchar* startPtr = g_utf8_offset_to_pointer(string, start);
       
   819     gsize lenInBytes = g_utf8_offset_to_pointer(string, end) -  startPtr + 1;
       
   820     gchar* output = static_cast<gchar*>(g_malloc0(lenInBytes + 1));
       
   821     return g_utf8_strncpy(output, startPtr, end - start + 1);
       
   822 }
       
   823 
       
   824 // This function is not completely general, is it's tied to the
       
   825 // internals of WebCore's text presentation.
       
   826 static gchar* convertUniCharToUTF8(const UChar* characters, gint length, int from, int to)
       
   827 {
       
   828     CString stringUTF8 = UTF8Encoding().encode(characters, length, QuestionMarksForUnencodables);
       
   829     gchar* utf8String = utf8Substr(stringUTF8.data(), from, to);
       
   830     if (!g_utf8_validate(utf8String, -1, 0)) {
       
   831         g_free(utf8String);
       
   832         return 0;
       
   833     }
       
   834     gsize len = strlen(utf8String);
       
   835     GString* ret = g_string_new_len(0, len);
       
   836     gchar* ptr = utf8String;
       
   837 
       
   838     // WebCore introduces line breaks in the text that do not reflect
       
   839     // the layout you see on the screen, replace them with spaces
       
   840     while (len > 0) {
       
   841         gint index, start;
       
   842         pango_find_paragraph_boundary(ptr, len, &index, &start);
       
   843         g_string_append_len(ret, ptr, index);
       
   844         if (index == start)
       
   845             break;
       
   846         g_string_append_c(ret, ' ');
       
   847         ptr += start;
       
   848         len -= start;
       
   849     }
       
   850 
       
   851     g_free(utf8String);
       
   852     return g_string_free(ret, FALSE);
       
   853 }
       
   854 
       
   855 gchar* textForObject(AccessibilityRenderObject* accObject)
       
   856 {
       
   857     GString* str = g_string_new(0);
       
   858 
       
   859     // For text controls, we can get the text line by line.
       
   860     if (accObject->isTextControl()) {
       
   861         unsigned textLength = accObject->textLength();
       
   862         int lineNumber = 0;
       
   863         PlainTextRange range = accObject->doAXRangeForLine(lineNumber);
       
   864         while (range.length) {
       
   865             // When a line of text wraps in a text area, the final space is removed.
       
   866             if (range.start + range.length < textLength)
       
   867                 range.length -= 1;
       
   868             String lineText = accObject->doAXStringForRange(range);
       
   869             g_string_append(str, lineText.utf8().data());
       
   870             g_string_append(str, "\n");
       
   871             range = accObject->doAXRangeForLine(++lineNumber);
       
   872         }
       
   873     } else if (accObject->renderer()) {
       
   874         // For RenderBlocks, piece together the text from the RenderText objects they contain.
       
   875         for (RenderObject* obj = accObject->renderer()->firstChild(); obj; obj = obj->nextSibling()) {
       
   876             if (obj->isBR()) {
       
   877                 g_string_append(str, "\n");
       
   878                 continue;
       
   879             }
       
   880 
       
   881             RenderText* renderText;
       
   882             if (obj->isText())
       
   883                 renderText = toRenderText(obj);
       
   884             else if (obj->firstChild() && obj->firstChild()->isText()) {
       
   885                 // Handle RenderInlines (and any other similiar RenderObjects).
       
   886                 renderText = toRenderText(obj->firstChild());
       
   887             } else
       
   888                 continue;
       
   889 
       
   890             InlineTextBox* box = renderText->firstTextBox();
       
   891             while (box) {
       
   892                 gchar* text = convertUniCharToUTF8(renderText->characters(), renderText->textLength(), box->start(), box->end());
       
   893                 g_string_append(str, text);
       
   894                 // Newline chars in the source result in separate text boxes, so check
       
   895                 // before adding a newline in the layout. See bug 25415 comment #78.
       
   896                 // If the next sibling is a BR, we'll add the newline when we examine that child.
       
   897                 if (!box->nextOnLineExists() && (!obj->nextSibling() || !obj->nextSibling()->isBR()))
       
   898                     g_string_append(str, "\n");
       
   899                 box = box->nextTextBox();
       
   900             }
       
   901         }
       
   902     }
       
   903     return g_string_free(str, FALSE);
       
   904 }
       
   905 
       
   906 static gchar* webkit_accessible_text_get_text(AtkText* text, gint startOffset, gint endOffset)
       
   907 {
       
   908     AccessibilityObject* coreObject = core(text);
       
   909     String ret;
       
   910     unsigned start = startOffset;
       
   911     if (endOffset == -1) {
       
   912         endOffset = coreObject->stringValue().length();
       
   913         if (!endOffset)
       
   914             endOffset = coreObject->textUnderElement().length();
       
   915     }
       
   916     int length = endOffset - startOffset;
       
   917 
       
   918     if (coreObject->isTextControl())
       
   919         ret = coreObject->doAXStringForRange(PlainTextRange(start, length));
       
   920     else
       
   921         ret = coreObject->textUnderElement().substring(start, length);
       
   922 
       
   923     if (!ret.length()) {
       
   924         // This can happen at least with anonymous RenderBlocks (e.g. body text amongst paragraphs)
       
   925         ret = String(textForObject(static_cast<AccessibilityRenderObject*>(coreObject)));
       
   926         if (!endOffset)
       
   927             endOffset = ret.length();
       
   928         ret = ret.substring(start, endOffset - startOffset);
       
   929     }
       
   930 
       
   931     return g_strdup(ret.utf8().data());
       
   932 }
       
   933 
       
   934 static GailTextUtil* getGailTextUtilForAtk(AtkText* textObject)
       
   935 {
       
   936     gpointer data = g_object_get_data(G_OBJECT(textObject), "webkit-accessible-gail-text-util");
       
   937     if (data)
       
   938         return static_cast<GailTextUtil*>(data);
       
   939 
       
   940     GailTextUtil* gailTextUtil = gail_text_util_new();
       
   941     gail_text_util_text_setup(gailTextUtil, webkit_accessible_text_get_text(textObject, 0, -1));
       
   942     g_object_set_data_full(G_OBJECT(textObject), "webkit-accessible-gail-text-util", gailTextUtil, g_object_unref);
       
   943     return gailTextUtil;
       
   944 }
       
   945 
       
   946 static PangoLayout* getPangoLayoutForAtk(AtkText* textObject)
       
   947 {
       
   948     AccessibilityObject* coreObject = core(textObject);
       
   949 
       
   950     HostWindow* hostWindow = coreObject->document()->view()->hostWindow();
       
   951     if (!hostWindow)
       
   952         return 0;
       
   953     PlatformPageClient webView = hostWindow->platformPageClient();
       
   954     if (!webView)
       
   955         return 0;
       
   956 
       
   957     AccessibilityRenderObject* accObject = static_cast<AccessibilityRenderObject*>(coreObject);
       
   958     if (!accObject)
       
   959         return 0;
       
   960 
       
   961     // Create a string with the layout as it appears on the screen
       
   962     PangoLayout* layout = gtk_widget_create_pango_layout(static_cast<GtkWidget*>(webView), textForObject(accObject));
       
   963     g_object_set_data_full(G_OBJECT(textObject), "webkit-accessible-pango-layout", layout, g_object_unref);
       
   964     return layout;
       
   965 }
       
   966 
       
   967 static gchar* webkit_accessible_text_get_text_after_offset(AtkText* text, gint offset, AtkTextBoundary boundaryType, gint* startOffset, gint* endOffset)
       
   968 {
       
   969     return gail_text_util_get_text(getGailTextUtilForAtk(text), getPangoLayoutForAtk(text), GAIL_AFTER_OFFSET, boundaryType, offset, startOffset, endOffset);
       
   970 }
       
   971 
       
   972 static gchar* webkit_accessible_text_get_text_at_offset(AtkText* text, gint offset, AtkTextBoundary boundaryType, gint* startOffset, gint* endOffset)
       
   973 {
       
   974     return gail_text_util_get_text(getGailTextUtilForAtk(text), getPangoLayoutForAtk(text), GAIL_AT_OFFSET, boundaryType, offset, startOffset, endOffset);
       
   975 }
       
   976 
       
   977 static gchar* webkit_accessible_text_get_text_before_offset(AtkText* text, gint offset, AtkTextBoundary boundaryType, gint* startOffset, gint* endOffset)
       
   978 {
       
   979     return gail_text_util_get_text(getGailTextUtilForAtk(text), getPangoLayoutForAtk(text), GAIL_BEFORE_OFFSET, boundaryType, offset, startOffset, endOffset);
       
   980 }
       
   981 
       
   982 static gunichar webkit_accessible_text_get_character_at_offset(AtkText* text, gint offset)
       
   983 {
       
   984     notImplemented();
       
   985     return 0;
       
   986 }
       
   987 
       
   988 static gint webkit_accessible_text_get_caret_offset(AtkText* text)
       
   989 {
       
   990     // coreObject is the unignored object whose offset the caller is requesting.
       
   991     // focusedObject is the object with the caret. It is likely ignored -- unless it's a link.
       
   992     AccessibilityObject* coreObject = core(text);
       
   993     Node* focusedNode = coreObject->selection().end().node();
       
   994 
       
   995     if (!focusedNode)
       
   996         return 0;
       
   997 
       
   998     RenderObject* focusedRenderer = focusedNode->renderer();
       
   999     AccessibilityObject* focusedObject = coreObject->document()->axObjectCache()->getOrCreate(focusedRenderer);
       
  1000 
       
  1001     int offset;
       
  1002     // Don't ignore links if the offset is being requested for a link.
       
  1003     objectAndOffsetUnignored(focusedObject, offset, !coreObject->isLink());
       
  1004 
       
  1005     // TODO: Verify this for RTL text.
       
  1006     return offset;
       
  1007 }
       
  1008 
       
  1009 static AtkAttributeSet* getAttributeSetForAccessibilityObject(const AccessibilityObject* object)
       
  1010 {
       
  1011     if (!object->isAccessibilityRenderObject())
       
  1012         return 0;
       
  1013 
       
  1014     RenderObject* renderer = static_cast<const AccessibilityRenderObject*>(object)->renderer();
       
  1015     RenderStyle* style = renderer->style();
       
  1016 
       
  1017     AtkAttributeSet* result = 0;
       
  1018     GOwnPtr<gchar> buffer(g_strdup_printf("%i", style->fontSize()));
       
  1019     result = addAttributeToSet(result, atk_text_attribute_get_name(ATK_TEXT_ATTR_SIZE), buffer.get());
       
  1020 
       
  1021     Color bgColor = style->visitedDependentColor(CSSPropertyBackgroundColor);
       
  1022     if (bgColor.isValid()) {
       
  1023         buffer.set(g_strdup_printf("%i,%i,%i",
       
  1024                                    bgColor.red(), bgColor.green(), bgColor.blue()));
       
  1025         result = addAttributeToSet(result, atk_text_attribute_get_name(ATK_TEXT_ATTR_BG_COLOR), buffer.get());
       
  1026     }
       
  1027 
       
  1028     Color fgColor = style->visitedDependentColor(CSSPropertyColor);
       
  1029     if (fgColor.isValid()) {
       
  1030         buffer.set(g_strdup_printf("%i,%i,%i",
       
  1031                                    fgColor.red(), fgColor.green(), fgColor.blue()));
       
  1032         result = addAttributeToSet(result, atk_text_attribute_get_name(ATK_TEXT_ATTR_FG_COLOR), buffer.get());
       
  1033     }
       
  1034 
       
  1035     int baselinePosition;
       
  1036     bool includeRise = true;
       
  1037     switch (style->verticalAlign()) {
       
  1038     case SUB:
       
  1039         baselinePosition = -1 * renderer->baselinePosition(true);
       
  1040         break;
       
  1041     case SUPER:
       
  1042         baselinePosition = renderer->baselinePosition(true);
       
  1043         break;
       
  1044     case BASELINE:
       
  1045         baselinePosition = 0;
       
  1046         break;
       
  1047     default:
       
  1048         includeRise = false;
       
  1049         break;
       
  1050     }
       
  1051 
       
  1052     if (includeRise) {
       
  1053         buffer.set(g_strdup_printf("%i", baselinePosition));
       
  1054         result = addAttributeToSet(result, atk_text_attribute_get_name(ATK_TEXT_ATTR_RISE), buffer.get());
       
  1055     }
       
  1056 
       
  1057     int indentation = style->textIndent().calcValue(object->size().width());
       
  1058     if (indentation != undefinedLength) {
       
  1059         buffer.set(g_strdup_printf("%i", indentation));
       
  1060         result = addAttributeToSet(result, atk_text_attribute_get_name(ATK_TEXT_ATTR_INDENT), buffer.get());
       
  1061     }
       
  1062 
       
  1063     String fontFamilyName = style->font().family().family().string();
       
  1064     if (fontFamilyName.left(8) == "-webkit-")
       
  1065         fontFamilyName = fontFamilyName.substring(8);
       
  1066 
       
  1067     result = addAttributeToSet(result, atk_text_attribute_get_name(ATK_TEXT_ATTR_FAMILY_NAME), fontFamilyName.utf8().data());
       
  1068 
       
  1069     int fontWeight = -1;
       
  1070     switch (style->font().weight()) {
       
  1071     case FontWeight100:
       
  1072         fontWeight = 100;
       
  1073         break;
       
  1074     case FontWeight200:
       
  1075         fontWeight = 200;
       
  1076         break;
       
  1077     case FontWeight300:
       
  1078         fontWeight = 300;
       
  1079         break;
       
  1080     case FontWeight400:
       
  1081         fontWeight = 400;
       
  1082         break;
       
  1083     case FontWeight500:
       
  1084         fontWeight = 500;
       
  1085         break;
       
  1086     case FontWeight600:
       
  1087         fontWeight = 600;
       
  1088         break;
       
  1089     case FontWeight700:
       
  1090         fontWeight = 700;
       
  1091         break;
       
  1092     case FontWeight800:
       
  1093         fontWeight = 800;
       
  1094         break;
       
  1095     case FontWeight900:
       
  1096         fontWeight = 900;
       
  1097     }
       
  1098     if (fontWeight > 0) {
       
  1099         buffer.set(g_strdup_printf("%i", fontWeight));
       
  1100         result = addAttributeToSet(result, atk_text_attribute_get_name(ATK_TEXT_ATTR_WEIGHT), buffer.get());
       
  1101     }
       
  1102 
       
  1103     switch (style->textAlign()) {
       
  1104     case TAAUTO:
       
  1105         break;
       
  1106     case LEFT:
       
  1107     case WEBKIT_LEFT:
       
  1108         result = addAttributeToSet(result, atk_text_attribute_get_name(ATK_TEXT_ATTR_JUSTIFICATION), "left");
       
  1109         break;
       
  1110     case RIGHT:
       
  1111     case WEBKIT_RIGHT:
       
  1112         result = addAttributeToSet(result, atk_text_attribute_get_name(ATK_TEXT_ATTR_JUSTIFICATION), "right");
       
  1113         break;
       
  1114     case CENTER:
       
  1115     case WEBKIT_CENTER:
       
  1116         result = addAttributeToSet(result, atk_text_attribute_get_name(ATK_TEXT_ATTR_JUSTIFICATION), "center");
       
  1117         break;
       
  1118     case JUSTIFY:
       
  1119         result = addAttributeToSet(result, atk_text_attribute_get_name(ATK_TEXT_ATTR_JUSTIFICATION), "fill");
       
  1120     }
       
  1121 
       
  1122     result = addAttributeToSet(result, atk_text_attribute_get_name(ATK_TEXT_ATTR_UNDERLINE), (style->textDecoration() & UNDERLINE) ? "single" : "none");
       
  1123 
       
  1124     result = addAttributeToSet(result, atk_text_attribute_get_name(ATK_TEXT_ATTR_STYLE), style->font().italic() ? "italic" : "normal");
       
  1125 
       
  1126     result = addAttributeToSet(result, atk_text_attribute_get_name(ATK_TEXT_ATTR_STRIKETHROUGH), (style->textDecoration() & LINE_THROUGH) ? "true" : "false");
       
  1127 
       
  1128     result = addAttributeToSet(result, atk_text_attribute_get_name(ATK_TEXT_ATTR_INVISIBLE), (style->visibility() == HIDDEN) ? "true" : "false");
       
  1129 
       
  1130     result = addAttributeToSet(result, atk_text_attribute_get_name(ATK_TEXT_ATTR_EDITABLE), object->isReadOnly() ? "false" : "true");
       
  1131 
       
  1132     return result;
       
  1133 }
       
  1134 
       
  1135 static gint compareAttribute(const AtkAttribute* a, const AtkAttribute* b)
       
  1136 {
       
  1137     return g_strcmp0(a->name, b->name) || g_strcmp0(a->value, b->value);
       
  1138 }
       
  1139 
       
  1140 // Returns an AtkAttributeSet with the elements of a1 which are either
       
  1141 // not present or different in a2.  Neither a1 nor a2 should be used
       
  1142 // after calling this function.
       
  1143 static AtkAttributeSet* attributeSetDifference(AtkAttributeSet* a1, AtkAttributeSet* a2)
       
  1144 {
       
  1145     if (!a2)
       
  1146         return a1;
       
  1147 
       
  1148     AtkAttributeSet* i = a1;
       
  1149     AtkAttributeSet* found;
       
  1150     AtkAttributeSet* toDelete = 0;
       
  1151 
       
  1152     while (i) {
       
  1153         found = g_slist_find_custom(a2, i->data, (GCompareFunc)compareAttribute);
       
  1154         if (found) {
       
  1155             AtkAttributeSet* t = i->next;
       
  1156             toDelete = g_slist_prepend(toDelete, i->data);
       
  1157             a1 = g_slist_delete_link(a1, i);
       
  1158             i = t;
       
  1159         } else
       
  1160             i = i->next;
       
  1161     }
       
  1162 
       
  1163     atk_attribute_set_free(a2);
       
  1164     atk_attribute_set_free(toDelete);
       
  1165     return a1;
       
  1166 }
       
  1167 
       
  1168 static guint accessibilityObjectLength(const AccessibilityObject* object)
       
  1169 {
       
  1170     GOwnPtr<gchar> text(webkit_accessible_text_get_text(ATK_TEXT(object->wrapper()), 0, -1));
       
  1171     return g_utf8_strlen(text.get(), -1);
       
  1172 }
       
  1173 
       
  1174 static const AccessibilityObject* getAccessibilityObjectForOffset(const AccessibilityObject* object, guint offset, gint* startOffset, gint* endOffset)
       
  1175 {
       
  1176     const AccessibilityObject* result;
       
  1177     guint length = accessibilityObjectLength(object);
       
  1178     if (length > offset) {
       
  1179         *startOffset = 0;
       
  1180         *endOffset = length;
       
  1181         result = object;
       
  1182     } else {
       
  1183         *startOffset = -1;
       
  1184         *endOffset = -1;
       
  1185         result = 0;
       
  1186     }
       
  1187 
       
  1188     if (!object->firstChild())
       
  1189         return result;
       
  1190 
       
  1191     AccessibilityObject* child = object->firstChild();
       
  1192     guint currentOffset = 0;
       
  1193     guint childPosition = 0;
       
  1194     while (child && currentOffset <= offset) {
       
  1195         guint childLength = accessibilityObjectLength(child);
       
  1196         currentOffset = childLength + childPosition;
       
  1197         if (currentOffset > offset) {
       
  1198             gint childStartOffset;
       
  1199             gint childEndOffset;
       
  1200             const AccessibilityObject* grandChild = getAccessibilityObjectForOffset(child, offset-childPosition,  &childStartOffset, &childEndOffset);
       
  1201             if (childStartOffset >= 0) {
       
  1202                 *startOffset = childStartOffset + childPosition;
       
  1203                 *endOffset = childEndOffset + childPosition;
       
  1204                 result = grandChild;
       
  1205             }
       
  1206         } else {
       
  1207             childPosition += childLength;
       
  1208             child = child->nextSibling();
       
  1209         }
       
  1210     }
       
  1211     return result;
       
  1212 }
       
  1213 
       
  1214 static AtkAttributeSet* getRunAttributesFromAccesibilityObject(const AccessibilityObject* element, gint offset, gint* startOffset, gint* endOffset)
       
  1215 {
       
  1216     const AccessibilityObject *child = getAccessibilityObjectForOffset(element, offset, startOffset, endOffset);
       
  1217     if (!child) {
       
  1218         *startOffset = -1;
       
  1219         *endOffset = -1;
       
  1220         return 0;
       
  1221     }
       
  1222 
       
  1223     AtkAttributeSet* defaultAttributes = getAttributeSetForAccessibilityObject(element);
       
  1224     AtkAttributeSet* childAttributes = getAttributeSetForAccessibilityObject(child);
       
  1225 
       
  1226     return attributeSetDifference(childAttributes, defaultAttributes);
       
  1227 }
       
  1228 
       
  1229 static AtkAttributeSet* webkit_accessible_text_get_run_attributes(AtkText* text, gint offset, gint* startOffset, gint* endOffset)
       
  1230 {
       
  1231     AccessibilityObject* coreObject = core(text);
       
  1232     AtkAttributeSet* result;
       
  1233 
       
  1234     if (!coreObject) {
       
  1235         *startOffset = 0;
       
  1236         *endOffset = atk_text_get_character_count(text);
       
  1237         return 0;
       
  1238     }
       
  1239 
       
  1240     if (offset == -1)
       
  1241         offset = atk_text_get_caret_offset(text);
       
  1242 
       
  1243     result = getRunAttributesFromAccesibilityObject(coreObject, offset, startOffset, endOffset);
       
  1244 
       
  1245     if (*startOffset < 0) {
       
  1246         *startOffset = offset;
       
  1247         *endOffset = offset;
       
  1248     }
       
  1249 
       
  1250     return result;
       
  1251 }
       
  1252 
       
  1253 static AtkAttributeSet* webkit_accessible_text_get_default_attributes(AtkText* text)
       
  1254 {
       
  1255     AccessibilityObject* coreObject = core(text);
       
  1256     if (!coreObject || !coreObject->isAccessibilityRenderObject())
       
  1257         return 0;
       
  1258 
       
  1259     return getAttributeSetForAccessibilityObject(coreObject);
       
  1260 }
       
  1261 
       
  1262 static void webkit_accessible_text_get_character_extents(AtkText* text, gint offset, gint* x, gint* y, gint* width, gint* height, AtkCoordType coords)
       
  1263 {
       
  1264     IntRect extents = core(text)->doAXBoundsForRange(PlainTextRange(offset, 1));
       
  1265     // FIXME: Use the AtkCoordType
       
  1266     // Requires WebCore::ScrollView::contentsToScreen() to be implemented
       
  1267 
       
  1268 #if 0
       
  1269     switch(coords) {
       
  1270     case ATK_XY_SCREEN:
       
  1271         extents = core(text)->document()->view()->contentsToScreen(extents);
       
  1272         break;
       
  1273     case ATK_XY_WINDOW:
       
  1274         // No-op
       
  1275         break;
       
  1276     }
       
  1277 #endif
       
  1278 
       
  1279     *x = extents.x();
       
  1280     *y = extents.y();
       
  1281     *width = extents.width();
       
  1282     *height = extents.height();
       
  1283 }
       
  1284 
       
  1285 static gint webkit_accessible_text_get_character_count(AtkText* text)
       
  1286 {
       
  1287     AccessibilityObject* coreObject = core(text);
       
  1288 
       
  1289     if (coreObject->isTextControl())
       
  1290         return coreObject->textLength();
       
  1291     else
       
  1292         return coreObject->textUnderElement().length();
       
  1293 }
       
  1294 
       
  1295 static gint webkit_accessible_text_get_offset_at_point(AtkText* text, gint x, gint y, AtkCoordType coords)
       
  1296 {
       
  1297     // FIXME: Use the AtkCoordType
       
  1298     // TODO: Is it correct to ignore range.length?
       
  1299     IntPoint pos(x, y);
       
  1300     PlainTextRange range = core(text)->doAXRangeForPosition(pos);
       
  1301     return range.start;
       
  1302 }
       
  1303 
       
  1304 static bool selectionBelongsToObject(AccessibilityObject* coreObject, VisibleSelection& selection)
       
  1305 {
       
  1306     if (!coreObject->isAccessibilityRenderObject())
       
  1307         return false;
       
  1308 
       
  1309     Node* node = static_cast<AccessibilityRenderObject*>(coreObject)->renderer()->node();
       
  1310     return node == selection.base().containerNode();
       
  1311 }
       
  1312 
       
  1313 static gint webkit_accessible_text_get_n_selections(AtkText* text)
       
  1314 {
       
  1315     AccessibilityObject* coreObject = core(text);
       
  1316     VisibleSelection selection = coreObject->selection();
       
  1317 
       
  1318     // We don't support multiple selections for now, so there's only
       
  1319     // two possibilities
       
  1320     // Also, we don't want to do anything if the selection does not
       
  1321     // belong to the currently selected object. We have to check since
       
  1322     // there's no way to get the selection for a given object, only
       
  1323     // the global one (the API is a bit confusing)
       
  1324     return !selectionBelongsToObject(coreObject, selection) || selection.isNone() ? 0 : 1;
       
  1325 }
       
  1326 
       
  1327 static gchar* webkit_accessible_text_get_selection(AtkText* text, gint selection_num, gint* start_offset, gint* end_offset)
       
  1328 {
       
  1329     AccessibilityObject* coreObject = core(text);
       
  1330     VisibleSelection selection = coreObject->selection();
       
  1331 
       
  1332     // WebCore does not support multiple selection, so anything but 0 does not make sense for now.
       
  1333     // Also, we don't want to do anything if the selection does not
       
  1334     // belong to the currently selected object. We have to check since
       
  1335     // there's no way to get the selection for a given object, only
       
  1336     // the global one (the API is a bit confusing)
       
  1337     if (selection_num != 0 || !selectionBelongsToObject(coreObject, selection)) {
       
  1338         *start_offset = *end_offset = 0;
       
  1339         return 0;
       
  1340     }
       
  1341 
       
  1342     *start_offset = selection.start().offsetInContainerNode();
       
  1343     *end_offset = selection.end().offsetInContainerNode();
       
  1344 
       
  1345     return webkit_accessible_text_get_text(text, *start_offset, *end_offset);
       
  1346 }
       
  1347 
       
  1348 static gboolean webkit_accessible_text_add_selection(AtkText* text, gint start_offset, gint end_offset)
       
  1349 {
       
  1350     notImplemented();
       
  1351     return FALSE;
       
  1352 }
       
  1353 
       
  1354 static gboolean webkit_accessible_text_remove_selection(AtkText* text, gint selection_num)
       
  1355 {
       
  1356     notImplemented();
       
  1357     return FALSE;
       
  1358 }
       
  1359 
       
  1360 static gboolean webkit_accessible_text_set_selection(AtkText* text, gint selection_num, gint start_offset, gint end_offset)
       
  1361 {
       
  1362     notImplemented();
       
  1363     return FALSE;
       
  1364 }
       
  1365 
       
  1366 static gboolean webkit_accessible_text_set_caret_offset(AtkText* text, gint offset)
       
  1367 {
       
  1368     AccessibilityObject* coreObject = core(text);
       
  1369 
       
  1370     // FIXME: We need to reimplement visiblePositionRangeForRange here
       
  1371     // because the actual function checks the offset is within the
       
  1372     // boundaries of text().length(), but text() only works for text
       
  1373     // controls...
       
  1374     VisiblePosition startPosition = coreObject->visiblePositionForIndex(offset);
       
  1375     startPosition.setAffinity(DOWNSTREAM);
       
  1376     VisiblePosition endPosition = coreObject->visiblePositionForIndex(offset);
       
  1377     VisiblePositionRange range = VisiblePositionRange(startPosition, endPosition);
       
  1378 
       
  1379     coreObject->setSelectedVisiblePositionRange(range);
       
  1380     return TRUE;
       
  1381 }
       
  1382 
       
  1383 static void atk_text_interface_init(AtkTextIface* iface)
       
  1384 {
       
  1385     iface->get_text = webkit_accessible_text_get_text;
       
  1386     iface->get_text_after_offset = webkit_accessible_text_get_text_after_offset;
       
  1387     iface->get_text_at_offset = webkit_accessible_text_get_text_at_offset;
       
  1388     iface->get_character_at_offset = webkit_accessible_text_get_character_at_offset;
       
  1389     iface->get_text_before_offset = webkit_accessible_text_get_text_before_offset;
       
  1390     iface->get_caret_offset = webkit_accessible_text_get_caret_offset;
       
  1391     iface->get_run_attributes = webkit_accessible_text_get_run_attributes;
       
  1392     iface->get_default_attributes = webkit_accessible_text_get_default_attributes;
       
  1393     iface->get_character_extents = webkit_accessible_text_get_character_extents;
       
  1394     iface->get_character_count = webkit_accessible_text_get_character_count;
       
  1395     iface->get_offset_at_point = webkit_accessible_text_get_offset_at_point;
       
  1396     iface->get_n_selections = webkit_accessible_text_get_n_selections;
       
  1397     iface->get_selection = webkit_accessible_text_get_selection;
       
  1398 
       
  1399     // set methods
       
  1400     iface->add_selection = webkit_accessible_text_add_selection;
       
  1401     iface->remove_selection = webkit_accessible_text_remove_selection;
       
  1402     iface->set_selection = webkit_accessible_text_set_selection;
       
  1403     iface->set_caret_offset = webkit_accessible_text_set_caret_offset;
       
  1404 }
       
  1405 
       
  1406 // EditableText
       
  1407 
       
  1408 static gboolean webkit_accessible_editable_text_set_run_attributes(AtkEditableText* text, AtkAttributeSet* attrib_set, gint start_offset, gint end_offset)
       
  1409 {
       
  1410     notImplemented();
       
  1411     return FALSE;
       
  1412 }
       
  1413 
       
  1414 static void webkit_accessible_editable_text_set_text_contents(AtkEditableText* text, const gchar* string)
       
  1415 {
       
  1416     // FIXME: string nullcheck?
       
  1417     core(text)->setValue(String::fromUTF8(string));
       
  1418 }
       
  1419 
       
  1420 static void webkit_accessible_editable_text_insert_text(AtkEditableText* text, const gchar* string, gint length, gint* position)
       
  1421 {
       
  1422     // FIXME: string nullcheck?
       
  1423 
       
  1424     AccessibilityObject* coreObject = core(text);
       
  1425     // FIXME: Not implemented in WebCore
       
  1426     //coreObject->setSelectedTextRange(PlainTextRange(*position, 0));
       
  1427     //coreObject->setSelectedText(String::fromUTF8(string));
       
  1428 
       
  1429     if (!coreObject->document() || !coreObject->document()->frame())
       
  1430         return;
       
  1431     coreObject->setSelectedVisiblePositionRange(coreObject->visiblePositionRangeForRange(PlainTextRange(*position, 0)));
       
  1432     coreObject->setFocused(true);
       
  1433     // FIXME: We should set position to the actual inserted text length, which may be less than that requested.
       
  1434     if (coreObject->document()->frame()->editor()->insertTextWithoutSendingTextEvent(String::fromUTF8(string), false, 0))
       
  1435         *position += length;
       
  1436 }
       
  1437 
       
  1438 static void webkit_accessible_editable_text_copy_text(AtkEditableText* text, gint start_pos, gint end_pos)
       
  1439 {
       
  1440     notImplemented();
       
  1441 }
       
  1442 
       
  1443 static void webkit_accessible_editable_text_cut_text(AtkEditableText* text, gint start_pos, gint end_pos)
       
  1444 {
       
  1445     notImplemented();
       
  1446 }
       
  1447 
       
  1448 static void webkit_accessible_editable_text_delete_text(AtkEditableText* text, gint start_pos, gint end_pos)
       
  1449 {
       
  1450     AccessibilityObject* coreObject = core(text);
       
  1451     // FIXME: Not implemented in WebCore
       
  1452     //coreObject->setSelectedTextRange(PlainTextRange(start_pos, end_pos - start_pos));
       
  1453     //coreObject->setSelectedText(String());
       
  1454 
       
  1455     if (!coreObject->document() || !coreObject->document()->frame())
       
  1456         return;
       
  1457     coreObject->setSelectedVisiblePositionRange(coreObject->visiblePositionRangeForRange(PlainTextRange(start_pos, end_pos - start_pos)));
       
  1458     coreObject->setFocused(true);
       
  1459     coreObject->document()->frame()->editor()->performDelete();
       
  1460 }
       
  1461 
       
  1462 static void webkit_accessible_editable_text_paste_text(AtkEditableText* text, gint position)
       
  1463 {
       
  1464     notImplemented();
       
  1465 }
       
  1466 
       
  1467 static void atk_editable_text_interface_init(AtkEditableTextIface* iface)
       
  1468 {
       
  1469     iface->set_run_attributes = webkit_accessible_editable_text_set_run_attributes;
       
  1470     iface->set_text_contents = webkit_accessible_editable_text_set_text_contents;
       
  1471     iface->insert_text = webkit_accessible_editable_text_insert_text;
       
  1472     iface->copy_text = webkit_accessible_editable_text_copy_text;
       
  1473     iface->cut_text = webkit_accessible_editable_text_cut_text;
       
  1474     iface->delete_text = webkit_accessible_editable_text_delete_text;
       
  1475     iface->paste_text = webkit_accessible_editable_text_paste_text;
       
  1476 }
       
  1477 
       
  1478 static void contentsToAtk(AccessibilityObject* coreObject, AtkCoordType coordType, IntRect rect, gint* x, gint* y, gint* width = 0, gint* height = 0)
       
  1479 {
       
  1480     FrameView* frameView = coreObject->documentFrameView();
       
  1481 
       
  1482     if (frameView) {
       
  1483         switch (coordType) {
       
  1484         case ATK_XY_WINDOW:
       
  1485             rect = frameView->contentsToWindow(rect);
       
  1486             break;
       
  1487         case ATK_XY_SCREEN:
       
  1488             rect = frameView->contentsToScreen(rect);
       
  1489             break;
       
  1490         }
       
  1491     }
       
  1492 
       
  1493     if (x)
       
  1494         *x = rect.x();
       
  1495     if (y)
       
  1496         *y = rect.y();
       
  1497     if (width)
       
  1498         *width = rect.width();
       
  1499     if (height)
       
  1500         *height = rect.height();
       
  1501 }
       
  1502 
       
  1503 static IntPoint atkToContents(AccessibilityObject* coreObject, AtkCoordType coordType, gint x, gint y)
       
  1504 {
       
  1505     IntPoint pos(x, y);
       
  1506 
       
  1507     FrameView* frameView = coreObject->documentFrameView();
       
  1508     if (frameView) {
       
  1509         switch (coordType) {
       
  1510         case ATK_XY_SCREEN:
       
  1511             return frameView->screenToContents(pos);
       
  1512         case ATK_XY_WINDOW:
       
  1513             return frameView->windowToContents(pos);
       
  1514         }
       
  1515     }
       
  1516 
       
  1517     return pos;
       
  1518 }
       
  1519 
       
  1520 static AtkObject* webkit_accessible_component_ref_accessible_at_point(AtkComponent* component, gint x, gint y, AtkCoordType coordType)
       
  1521 {
       
  1522     IntPoint pos = atkToContents(core(component), coordType, x, y);
       
  1523     AccessibilityObject* target = core(component)->doAccessibilityHitTest(pos);
       
  1524     if (!target)
       
  1525         return 0;
       
  1526     g_object_ref(target->wrapper());
       
  1527     return target->wrapper();
       
  1528 }
       
  1529 
       
  1530 static void webkit_accessible_component_get_extents(AtkComponent* component, gint* x, gint* y, gint* width, gint* height, AtkCoordType coordType)
       
  1531 {
       
  1532     IntRect rect = core(component)->elementRect();
       
  1533     contentsToAtk(core(component), coordType, rect, x, y, width, height);
       
  1534 }
       
  1535 
       
  1536 static gboolean webkit_accessible_component_grab_focus(AtkComponent* component)
       
  1537 {
       
  1538     core(component)->setFocused(true);
       
  1539     return core(component)->isFocused();
       
  1540 }
       
  1541 
       
  1542 static void atk_component_interface_init(AtkComponentIface* iface)
       
  1543 {
       
  1544     iface->ref_accessible_at_point = webkit_accessible_component_ref_accessible_at_point;
       
  1545     iface->get_extents = webkit_accessible_component_get_extents;
       
  1546     iface->grab_focus = webkit_accessible_component_grab_focus;
       
  1547 }
       
  1548 
       
  1549 // Image
       
  1550 
       
  1551 static void webkit_accessible_image_get_image_position(AtkImage* image, gint* x, gint* y, AtkCoordType coordType)
       
  1552 {
       
  1553     IntRect rect = core(image)->elementRect();
       
  1554     contentsToAtk(core(image), coordType, rect, x, y);
       
  1555 }
       
  1556 
       
  1557 static const gchar* webkit_accessible_image_get_image_description(AtkImage* image)
       
  1558 {
       
  1559     return returnString(core(image)->accessibilityDescription());
       
  1560 }
       
  1561 
       
  1562 static void webkit_accessible_image_get_image_size(AtkImage* image, gint* width, gint* height)
       
  1563 {
       
  1564     IntSize size = core(image)->size();
       
  1565 
       
  1566     if (width)
       
  1567         *width = size.width();
       
  1568     if (height)
       
  1569         *height = size.height();
       
  1570 }
       
  1571 
       
  1572 static void atk_image_interface_init(AtkImageIface* iface)
       
  1573 {
       
  1574     iface->get_image_position = webkit_accessible_image_get_image_position;
       
  1575     iface->get_image_description = webkit_accessible_image_get_image_description;
       
  1576     iface->get_image_size = webkit_accessible_image_get_image_size;
       
  1577 }
       
  1578 
       
  1579 // Table
       
  1580 
       
  1581 static AccessibilityTableCell* cell(AtkTable* table, guint row, guint column)
       
  1582 {
       
  1583     AccessibilityObject* accTable = core(table);
       
  1584     if (accTable->isAccessibilityRenderObject())
       
  1585         return static_cast<AccessibilityTable*>(accTable)->cellForColumnAndRow(column, row);
       
  1586     return 0;
       
  1587 }
       
  1588 
       
  1589 static gint cellIndex(AccessibilityTableCell* axCell, AccessibilityTable* axTable)
       
  1590 {
       
  1591     // Calculate the cell's index as if we had a traditional Gtk+ table in
       
  1592     // which cells are all direct children of the table, arranged row-first.
       
  1593     AccessibilityObject::AccessibilityChildrenVector allCells;
       
  1594     axTable->cells(allCells);
       
  1595     AccessibilityObject::AccessibilityChildrenVector::iterator position;
       
  1596     position = std::find(allCells.begin(), allCells.end(), axCell);
       
  1597     if (position == allCells.end())
       
  1598         return -1;
       
  1599     return position - allCells.begin();
       
  1600 }
       
  1601 
       
  1602 static AccessibilityTableCell* cellAtIndex(AtkTable* table, gint index)
       
  1603 {
       
  1604     AccessibilityObject* accTable = core(table);
       
  1605     if (accTable->isAccessibilityRenderObject()) {
       
  1606         AccessibilityObject::AccessibilityChildrenVector allCells;
       
  1607         static_cast<AccessibilityTable*>(accTable)->cells(allCells);
       
  1608         if (0 <= index && static_cast<unsigned>(index) < allCells.size()) {
       
  1609             AccessibilityObject* accCell = allCells.at(index).get();
       
  1610             return static_cast<AccessibilityTableCell*>(accCell);
       
  1611         }
       
  1612     }
       
  1613     return 0;
       
  1614 }
       
  1615 
       
  1616 static AtkObject* webkit_accessible_table_ref_at(AtkTable* table, gint row, gint column)
       
  1617 {
       
  1618     AccessibilityTableCell* axCell = cell(table, row, column);
       
  1619     if (!axCell)
       
  1620         return 0;
       
  1621     return axCell->wrapper();
       
  1622 }
       
  1623 
       
  1624 static gint webkit_accessible_table_get_index_at(AtkTable* table, gint row, gint column)
       
  1625 {
       
  1626     AccessibilityTableCell* axCell = cell(table, row, column);
       
  1627     AccessibilityTable* axTable = static_cast<AccessibilityTable*>(core(table));
       
  1628     return cellIndex(axCell, axTable);
       
  1629 }
       
  1630 
       
  1631 static gint webkit_accessible_table_get_column_at_index(AtkTable* table, gint index)
       
  1632 {
       
  1633     AccessibilityTableCell* axCell = cellAtIndex(table, index);
       
  1634     if (axCell){
       
  1635         pair<int, int> columnRange;
       
  1636         axCell->columnIndexRange(columnRange);
       
  1637         return columnRange.first;
       
  1638     }
       
  1639     return -1;
       
  1640 }
       
  1641 
       
  1642 static gint webkit_accessible_table_get_row_at_index(AtkTable* table, gint index)
       
  1643 {
       
  1644     AccessibilityTableCell* axCell = cellAtIndex(table, index);
       
  1645     if (axCell){
       
  1646         pair<int, int> rowRange;
       
  1647         axCell->rowIndexRange(rowRange);
       
  1648         return rowRange.first;
       
  1649     }
       
  1650     return -1;
       
  1651 }
       
  1652 
       
  1653 static gint webkit_accessible_table_get_n_columns(AtkTable* table)
       
  1654 {
       
  1655     AccessibilityObject* accTable = core(table);
       
  1656     if (accTable->isAccessibilityRenderObject())
       
  1657         return static_cast<AccessibilityTable*>(accTable)->columnCount();
       
  1658     return 0;
       
  1659 }
       
  1660 
       
  1661 static gint webkit_accessible_table_get_n_rows(AtkTable* table)
       
  1662 {
       
  1663     AccessibilityObject* accTable = core(table);
       
  1664     if (accTable->isAccessibilityRenderObject())
       
  1665         return static_cast<AccessibilityTable*>(accTable)->rowCount();
       
  1666     return 0;
       
  1667 }
       
  1668 
       
  1669 static gint webkit_accessible_table_get_column_extent_at(AtkTable* table, gint row, gint column)
       
  1670 {
       
  1671     AccessibilityTableCell* axCell = cell(table, row, column);
       
  1672     if (axCell) {
       
  1673         pair<int, int> columnRange;
       
  1674         axCell->columnIndexRange(columnRange);
       
  1675         return columnRange.second;
       
  1676     }
       
  1677     return 0;
       
  1678 }
       
  1679 
       
  1680 static gint webkit_accessible_table_get_row_extent_at(AtkTable* table, gint row, gint column)
       
  1681 {
       
  1682     AccessibilityTableCell* axCell = cell(table, row, column);
       
  1683     if (axCell) {
       
  1684         pair<int, int> rowRange;
       
  1685         axCell->rowIndexRange(rowRange);
       
  1686         return rowRange.second;
       
  1687     }
       
  1688     return 0;
       
  1689 }
       
  1690 
       
  1691 static AtkObject* webkit_accessible_table_get_column_header(AtkTable* table, gint column)
       
  1692 {
       
  1693     AccessibilityObject* accTable = core(table);
       
  1694     if (accTable->isAccessibilityRenderObject()) {
       
  1695         AccessibilityObject::AccessibilityChildrenVector allColumnHeaders;
       
  1696         static_cast<AccessibilityTable*>(accTable)->columnHeaders(allColumnHeaders);
       
  1697         unsigned columnCount = allColumnHeaders.size();
       
  1698         for (unsigned k = 0; k < columnCount; ++k) {
       
  1699             pair<int, int> columnRange;
       
  1700             AccessibilityTableCell* cell = static_cast<AccessibilityTableCell*>(allColumnHeaders.at(k).get());
       
  1701             cell->columnIndexRange(columnRange);
       
  1702             if (columnRange.first <= column && column < columnRange.first + columnRange.second)
       
  1703                 return allColumnHeaders[k]->wrapper();
       
  1704         }
       
  1705     }
       
  1706     return 0;
       
  1707 }
       
  1708 
       
  1709 static AtkObject* webkit_accessible_table_get_row_header(AtkTable* table, gint row)
       
  1710 {
       
  1711     AccessibilityObject* accTable = core(table);
       
  1712     if (accTable->isAccessibilityRenderObject()) {
       
  1713         AccessibilityObject::AccessibilityChildrenVector allRowHeaders;
       
  1714         static_cast<AccessibilityTable*>(accTable)->rowHeaders(allRowHeaders);
       
  1715         unsigned rowCount = allRowHeaders.size();
       
  1716         for (unsigned k = 0; k < rowCount; ++k) {
       
  1717             pair<int, int> rowRange;
       
  1718             AccessibilityTableCell* cell = static_cast<AccessibilityTableCell*>(allRowHeaders.at(k).get());
       
  1719             cell->rowIndexRange(rowRange);
       
  1720             if (rowRange.first <= row && row < rowRange.first + rowRange.second)
       
  1721                 return allRowHeaders[k]->wrapper();
       
  1722         }
       
  1723     }
       
  1724     return 0;
       
  1725 }
       
  1726 
       
  1727 static AtkObject* webkit_accessible_table_get_caption(AtkTable* table)
       
  1728 {
       
  1729     AccessibilityObject* accTable = core(table);
       
  1730     if (accTable->isAccessibilityRenderObject()) {
       
  1731         Node* node = static_cast<AccessibilityRenderObject*>(accTable)->renderer()->node();
       
  1732         if (node && node->hasTagName(HTMLNames::tableTag)) {
       
  1733             HTMLTableCaptionElement* caption = static_cast<HTMLTableElement*>(node)->caption();
       
  1734             if (caption)
       
  1735                 return AccessibilityObject::firstAccessibleObjectFromNode(caption->renderer()->node())->wrapper();
       
  1736         }
       
  1737     }
       
  1738     return 0;
       
  1739 }
       
  1740 
       
  1741 static const gchar* webkit_accessible_table_get_column_description(AtkTable* table, gint column)
       
  1742 {
       
  1743     AtkObject* columnHeader = atk_table_get_column_header(table, column);
       
  1744     if (columnHeader && ATK_IS_TEXT(columnHeader))
       
  1745         return webkit_accessible_text_get_text(ATK_TEXT(columnHeader), 0, -1);
       
  1746 
       
  1747     return 0;
       
  1748 }
       
  1749 
       
  1750 static const gchar* webkit_accessible_table_get_row_description(AtkTable* table, gint row)
       
  1751 {
       
  1752     AtkObject* rowHeader = atk_table_get_row_header(table, row);
       
  1753     if (rowHeader && ATK_IS_TEXT(rowHeader))
       
  1754         return webkit_accessible_text_get_text(ATK_TEXT(rowHeader), 0, -1);
       
  1755 
       
  1756     return 0;
       
  1757 }
       
  1758 
       
  1759 static void atk_table_interface_init(AtkTableIface* iface)
       
  1760 {
       
  1761     iface->ref_at = webkit_accessible_table_ref_at;
       
  1762     iface->get_index_at = webkit_accessible_table_get_index_at;
       
  1763     iface->get_column_at_index = webkit_accessible_table_get_column_at_index;
       
  1764     iface->get_row_at_index = webkit_accessible_table_get_row_at_index;
       
  1765     iface->get_n_columns = webkit_accessible_table_get_n_columns;
       
  1766     iface->get_n_rows = webkit_accessible_table_get_n_rows;
       
  1767     iface->get_column_extent_at = webkit_accessible_table_get_column_extent_at;
       
  1768     iface->get_row_extent_at = webkit_accessible_table_get_row_extent_at;
       
  1769     iface->get_column_header = webkit_accessible_table_get_column_header;
       
  1770     iface->get_row_header = webkit_accessible_table_get_row_header;
       
  1771     iface->get_caption = webkit_accessible_table_get_caption;
       
  1772     iface->get_column_description = webkit_accessible_table_get_column_description;
       
  1773     iface->get_row_description = webkit_accessible_table_get_row_description;
       
  1774 }
       
  1775 
       
  1776 static const gchar* documentAttributeValue(AtkDocument* document, const gchar* attribute)
       
  1777 {
       
  1778     Document* coreDocument = core(document)->document();
       
  1779     if (!coreDocument)
       
  1780         return 0;
       
  1781 
       
  1782     String value = String();
       
  1783     if (!g_ascii_strcasecmp(attribute, "DocType") && coreDocument->doctype())
       
  1784         value = coreDocument->doctype()->name();
       
  1785     else if (!g_ascii_strcasecmp(attribute, "Encoding"))
       
  1786         value = coreDocument->charset();
       
  1787     else if (!g_ascii_strcasecmp(attribute, "URI"))
       
  1788         value = coreDocument->documentURI();
       
  1789     if (!value.isEmpty())
       
  1790         return returnString(value);
       
  1791 
       
  1792     return 0;
       
  1793 }
       
  1794 
       
  1795 static const gchar* webkit_accessible_document_get_attribute_value(AtkDocument* document, const gchar* attribute)
       
  1796 {
       
  1797     return documentAttributeValue(document, attribute);
       
  1798 }
       
  1799 
       
  1800 static AtkAttributeSet* webkit_accessible_document_get_attributes(AtkDocument* document)
       
  1801 {
       
  1802     AtkAttributeSet* attributeSet = 0;
       
  1803     const gchar* attributes [] = {"DocType", "Encoding", "URI"};
       
  1804 
       
  1805     for (unsigned i = 0; i < G_N_ELEMENTS(attributes); i++) {
       
  1806         const gchar* value = documentAttributeValue(document, attributes[i]);
       
  1807         if (value)
       
  1808             attributeSet = addAttributeToSet(attributeSet, attributes[i], value);
       
  1809     }
       
  1810 
       
  1811     return attributeSet;
       
  1812 }
       
  1813 
       
  1814 static const gchar* webkit_accessible_document_get_locale(AtkDocument* document)
       
  1815 {
       
  1816 
       
  1817     // TODO: Should we fall back on lang xml:lang when the following comes up empty?
       
  1818     String language = core(document)->language();
       
  1819     if (!language.isEmpty())
       
  1820         return returnString(language);
       
  1821 
       
  1822     return 0;
       
  1823 }
       
  1824 
       
  1825 static void atk_document_interface_init(AtkDocumentIface* iface)
       
  1826 {
       
  1827     iface->get_document_attribute_value = webkit_accessible_document_get_attribute_value;
       
  1828     iface->get_document_attributes = webkit_accessible_document_get_attributes;
       
  1829     iface->get_document_locale = webkit_accessible_document_get_locale;
       
  1830 }
       
  1831 
       
  1832 static const GInterfaceInfo AtkInterfacesInitFunctions[] = {
       
  1833     {(GInterfaceInitFunc)atk_action_interface_init,
       
  1834      (GInterfaceFinalizeFunc) 0, 0},
       
  1835     {(GInterfaceInitFunc)atk_selection_interface_init,
       
  1836      (GInterfaceFinalizeFunc) 0, 0},
       
  1837     {(GInterfaceInitFunc)atk_editable_text_interface_init,
       
  1838      (GInterfaceFinalizeFunc) 0, 0},
       
  1839     {(GInterfaceInitFunc)atk_text_interface_init,
       
  1840      (GInterfaceFinalizeFunc) 0, 0},
       
  1841     {(GInterfaceInitFunc)atk_component_interface_init,
       
  1842      (GInterfaceFinalizeFunc) 0, 0},
       
  1843     {(GInterfaceInitFunc)atk_image_interface_init,
       
  1844      (GInterfaceFinalizeFunc) 0, 0},
       
  1845     {(GInterfaceInitFunc)atk_table_interface_init,
       
  1846      (GInterfaceFinalizeFunc) 0, 0},
       
  1847     {(GInterfaceInitFunc)atk_document_interface_init,
       
  1848      (GInterfaceFinalizeFunc) 0, 0}
       
  1849 };
       
  1850 
       
  1851 enum WAIType {
       
  1852     WAI_ACTION,
       
  1853     WAI_SELECTION,
       
  1854     WAI_EDITABLE_TEXT,
       
  1855     WAI_TEXT,
       
  1856     WAI_COMPONENT,
       
  1857     WAI_IMAGE,
       
  1858     WAI_TABLE,
       
  1859     WAI_DOCUMENT
       
  1860 };
       
  1861 
       
  1862 static GType GetAtkInterfaceTypeFromWAIType(WAIType type)
       
  1863 {
       
  1864   switch (type) {
       
  1865   case WAI_ACTION:
       
  1866       return ATK_TYPE_ACTION;
       
  1867   case WAI_SELECTION:
       
  1868       return ATK_TYPE_SELECTION;
       
  1869   case WAI_EDITABLE_TEXT:
       
  1870       return ATK_TYPE_EDITABLE_TEXT;
       
  1871   case WAI_TEXT:
       
  1872       return ATK_TYPE_TEXT;
       
  1873   case WAI_COMPONENT:
       
  1874       return ATK_TYPE_COMPONENT;
       
  1875   case WAI_IMAGE:
       
  1876       return ATK_TYPE_IMAGE;
       
  1877   case WAI_TABLE:
       
  1878       return ATK_TYPE_TABLE;
       
  1879   case WAI_DOCUMENT:
       
  1880       return ATK_TYPE_DOCUMENT;
       
  1881   }
       
  1882 
       
  1883   return G_TYPE_INVALID;
       
  1884 }
       
  1885 
       
  1886 static guint16 getInterfaceMaskFromObject(AccessibilityObject* coreObject)
       
  1887 {
       
  1888     guint16 interfaceMask = 0;
       
  1889 
       
  1890     // Component interface is always supported
       
  1891     interfaceMask |= 1 << WAI_COMPONENT;
       
  1892 
       
  1893     // Action
       
  1894     if (!coreObject->actionVerb().isEmpty())
       
  1895         interfaceMask |= 1 << WAI_ACTION;
       
  1896 
       
  1897     // Selection
       
  1898     if (coreObject->isListBox())
       
  1899         interfaceMask |= 1 << WAI_SELECTION;
       
  1900 
       
  1901     // Text & Editable Text
       
  1902     AccessibilityRole role = coreObject->roleValue();
       
  1903 
       
  1904     if (role == StaticTextRole)
       
  1905         interfaceMask |= 1 << WAI_TEXT;
       
  1906     else if (coreObject->isAccessibilityRenderObject())
       
  1907         if (coreObject->isTextControl()) {
       
  1908             interfaceMask |= 1 << WAI_TEXT;
       
  1909             if (!coreObject->isReadOnly())
       
  1910                 interfaceMask |= 1 << WAI_EDITABLE_TEXT;
       
  1911         } else if (role != TableRole && static_cast<AccessibilityRenderObject*>(coreObject)->renderer()->childrenInline())
       
  1912             interfaceMask |= 1 << WAI_TEXT;
       
  1913 
       
  1914     // Image
       
  1915     if (coreObject->isImage())
       
  1916         interfaceMask |= 1 << WAI_IMAGE;
       
  1917 
       
  1918     // Table
       
  1919     if (role == TableRole)
       
  1920         interfaceMask |= 1 << WAI_TABLE;
       
  1921 
       
  1922     // Document
       
  1923     if (role == WebAreaRole)
       
  1924         interfaceMask |= 1 << WAI_DOCUMENT;
       
  1925 
       
  1926     return interfaceMask;
       
  1927 }
       
  1928 
       
  1929 static const char* getUniqueAccessibilityTypeName(guint16 interfaceMask)
       
  1930 {
       
  1931 #define WAI_TYPE_NAME_LEN (30) /* Enough for prefix + 5 hex characters (max) */
       
  1932     static char name[WAI_TYPE_NAME_LEN + 1];
       
  1933 
       
  1934     g_sprintf(name, "WAIType%x", interfaceMask);
       
  1935     name[WAI_TYPE_NAME_LEN] = '\0';
       
  1936 
       
  1937     return name;
       
  1938 }
       
  1939 
       
  1940 static GType getAccessibilityTypeFromObject(AccessibilityObject* coreObject)
       
  1941 {
       
  1942     static const GTypeInfo typeInfo = {
       
  1943         sizeof(WebKitAccessibleClass),
       
  1944         (GBaseInitFunc) 0,
       
  1945         (GBaseFinalizeFunc) 0,
       
  1946         (GClassInitFunc) 0,
       
  1947         (GClassFinalizeFunc) 0,
       
  1948         0, /* class data */
       
  1949         sizeof(WebKitAccessible), /* instance size */
       
  1950         0, /* nb preallocs */
       
  1951         (GInstanceInitFunc) 0,
       
  1952         0 /* value table */
       
  1953     };
       
  1954 
       
  1955     guint16 interfaceMask = getInterfaceMaskFromObject(coreObject);
       
  1956     const char* atkTypeName = getUniqueAccessibilityTypeName(interfaceMask);
       
  1957     GType type = g_type_from_name(atkTypeName);
       
  1958     if (type)
       
  1959         return type;
       
  1960 
       
  1961     type = g_type_register_static(WEBKIT_TYPE_ACCESSIBLE,
       
  1962                                   atkTypeName,
       
  1963                                   &typeInfo, GTypeFlags(0));
       
  1964     for (guint i = 0; i < G_N_ELEMENTS(AtkInterfacesInitFunctions); i++) {
       
  1965         if (interfaceMask & (1 << i))
       
  1966             g_type_add_interface_static(type,
       
  1967                                         GetAtkInterfaceTypeFromWAIType(static_cast<WAIType>(i)),
       
  1968                                         &AtkInterfacesInitFunctions[i]);
       
  1969     }
       
  1970 
       
  1971     return type;
       
  1972 }
       
  1973 
       
  1974 WebKitAccessible* webkit_accessible_new(AccessibilityObject* coreObject)
       
  1975 {
       
  1976     GType type = getAccessibilityTypeFromObject(coreObject);
       
  1977     AtkObject* object = static_cast<AtkObject*>(g_object_new(type, 0));
       
  1978 
       
  1979     atk_object_initialize(object, coreObject);
       
  1980 
       
  1981     return WEBKIT_ACCESSIBLE(object);
       
  1982 }
       
  1983 
       
  1984 AccessibilityObject* webkit_accessible_get_accessibility_object(WebKitAccessible* accessible)
       
  1985 {
       
  1986     return accessible->m_object;
       
  1987 }
       
  1988 
       
  1989 void webkit_accessible_detach(WebKitAccessible* accessible)
       
  1990 {
       
  1991     ASSERT(accessible->m_object);
       
  1992 
       
  1993     // We replace the WebCore AccessibilityObject with a fallback object that
       
  1994     // provides default implementations to avoid repetitive null-checking after
       
  1995     // detachment.
       
  1996     accessible->m_object = fallbackObject();
       
  1997 }
       
  1998 
       
  1999 AtkObject* webkit_accessible_get_focused_element(WebKitAccessible* accessible)
       
  2000 {
       
  2001     if (!accessible->m_object)
       
  2002         return 0;
       
  2003 
       
  2004     RefPtr<AccessibilityObject> focusedObj = accessible->m_object->focusedUIElement();
       
  2005     if (!focusedObj)
       
  2006         return 0;
       
  2007 
       
  2008     return focusedObj->wrapper();
       
  2009 }
       
  2010 
       
  2011 AccessibilityObject* objectAndOffsetUnignored(AccessibilityObject* coreObject, int& offset, bool ignoreLinks)
       
  2012 {
       
  2013     Node* endNode = static_cast<AccessibilityRenderObject*>(coreObject)->renderer()->node();
       
  2014     int endOffset = coreObject->selection().end().computeOffsetInContainerNode();
       
  2015     // Indication that something bogus has transpired.
       
  2016     offset = -1;
       
  2017 
       
  2018     AccessibilityObject* realObject = coreObject;
       
  2019     if (realObject->accessibilityIsIgnored())
       
  2020         realObject = realObject->parentObjectUnignored();
       
  2021 
       
  2022     if (ignoreLinks && realObject->isLink())
       
  2023         realObject = realObject->parentObjectUnignored();
       
  2024 
       
  2025     Node* node = static_cast<AccessibilityRenderObject*>(realObject)->renderer()->node();
       
  2026     if (node) {
       
  2027         RefPtr<Range> range = rangeOfContents(node);
       
  2028         if (range->ownerDocument() == node->document()) {
       
  2029             ExceptionCode ec = 0;
       
  2030             range->setEndBefore(endNode, ec);
       
  2031             if (range->boundaryPointsValid())
       
  2032                 offset = range->text().length() + endOffset;
       
  2033         }
       
  2034     }
       
  2035     return realObject;
       
  2036 }
       
  2037 
       
  2038 #endif // HAVE(ACCESSIBILITY)