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