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