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