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