456b1322e65b4fa1405e2c751cd0891a9f41bd62
[WebKit-https.git] / Tools / WebKitTestRunner / InjectedBundle / atk / AccessibilityUIElementAtk.cpp
1 /*
2  * Copyright (C) 2011 Apple Inc. All Rights Reserved.
3  * Copyright (C) 2012 Igalia S.L.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include "config.h"
28 #include "AccessibilityUIElement.h"
29
30 #if HAVE(ACCESSIBILITY)
31
32 #include "InjectedBundle.h"
33 #include "InjectedBundlePage.h"
34 #include "NotImplemented.h"
35 #include <JavaScriptCore/JSStringRef.h>
36 #include <atk/atk.h>
37 #include <wtf/Assertions.h>
38 #include <wtf/gobject/GOwnPtr.h>
39 #include <wtf/gobject/GRefPtr.h>
40 #include <wtf/text/CString.h>
41 #include <wtf/text/WTFString.h>
42 #include <wtf/unicode/CharacterNames.h>
43
44 namespace WTR {
45
46 static String coreAttributeToAtkAttribute(JSStringRef attribute)
47 {
48     size_t bufferSize = JSStringGetMaximumUTF8CStringSize(attribute);
49     GOwnPtr<gchar> buffer(static_cast<gchar*>(g_malloc(bufferSize)));
50     JSStringGetUTF8CString(attribute, buffer.get(), bufferSize);
51
52     String attributeString = String::fromUTF8(buffer.get());
53     return attributeString == "AXPlaceholderValue" ? "placeholder-text" : String();
54 }
55
56 static void attributesClear(AtkAttributeSet* attributesSet)
57 {
58     for (GSList* attributes = attributesSet; attributes; attributes = attributes->next) {
59         AtkAttribute* atkAttribute = static_cast<AtkAttribute*>(attributes->data);
60         g_free(atkAttribute->name);
61         g_free(atkAttribute->value);
62         g_free(atkAttribute);
63     }
64 }
65
66 static gchar* attributeSetToString(AtkAttributeSet* attributeSet)
67 {
68     GOwnPtr<GSList> atkAttributes(attributeSet);
69     GString* str = g_string_new(0);
70     for (GSList* attributes = atkAttributes.get(); attributes; attributes = attributes->next) {
71         AtkAttribute* attribute = static_cast<AtkAttribute*>(attributes->data);
72         GOwnPtr<gchar> attributeData(g_strconcat(attribute->name, ":", attribute->value, NULL));
73         g_string_append(str, attributeData.get());
74         if (attributes->next)
75             g_string_append(str, ", ");
76     }
77
78     attributesClear(atkAttributes.get());
79
80     return g_string_free(str, FALSE);
81 }
82
83 static bool checkElementState(PlatformUIElement element, AtkStateType stateType)
84 {
85     if (!ATK_IS_OBJECT(element.get()))
86         return false;
87
88     GRefPtr<AtkStateSet> stateSet = adoptGRef(atk_object_ref_state_set(ATK_OBJECT(element.get())));
89     return atk_state_set_contains_state(stateSet.get(), stateType);
90 }
91
92 static JSStringRef indexRangeInTable(PlatformUIElement element, bool isRowRange)
93 {
94     GOwnPtr<gchar> rangeString(g_strdup("{0, 0}"));
95
96     if (!element || !ATK_IS_OBJECT(element.get()))
97         return JSStringCreateWithUTF8CString(rangeString.get());
98
99     AtkObject* axTable = atk_object_get_parent(ATK_OBJECT(element.get()));
100     if (!axTable || !ATK_IS_TABLE(axTable))
101         return JSStringCreateWithUTF8CString(rangeString.get());
102
103     // Look for the cell in the table.
104     gint indexInParent = atk_object_get_index_in_parent(ATK_OBJECT(element.get()));
105     if (indexInParent == -1)
106         return JSStringCreateWithUTF8CString(rangeString.get());
107
108     int row = -1;
109     int column = -1;
110     row = atk_table_get_row_at_index(ATK_TABLE(axTable), indexInParent);
111     column = atk_table_get_column_at_index(ATK_TABLE(axTable), indexInParent);
112
113     // Get the actual values, if row and columns are valid values.
114     if (row != -1 && column != -1) {
115         int base = 0;
116         int length = 0;
117         if (isRowRange) {
118             base = row;
119             length = atk_table_get_row_extent_at(ATK_TABLE(axTable), row, column);
120         } else {
121             base = column;
122             length = atk_table_get_column_extent_at(ATK_TABLE(axTable), row, column);
123         }
124         rangeString.set(g_strdup_printf("{%d, %d}", base, length));
125     }
126
127     return JSStringCreateWithUTF8CString(rangeString.get());
128 }
129
130 static void alterCurrentValue(PlatformUIElement element, int factor)
131 {
132     if (!element || !ATK_IS_VALUE(element.get()))
133         return;
134
135     GValue currentValue = G_VALUE_INIT;
136     atk_value_get_current_value(ATK_VALUE(element.get()), &currentValue);
137
138     GValue increment = G_VALUE_INIT;
139     atk_value_get_minimum_increment(ATK_VALUE(element.get()), &increment);
140
141     GValue newValue = G_VALUE_INIT;
142     g_value_init(&newValue, G_TYPE_DOUBLE);
143
144     g_value_set_float(&newValue, g_value_get_float(&currentValue) + factor * g_value_get_float(&increment));
145     atk_value_set_current_value(ATK_VALUE(element.get()), &newValue);
146
147     g_value_unset(&newValue);
148     g_value_unset(&increment);
149     g_value_unset(&currentValue);
150 }
151
152 static gchar* replaceCharactersForResults(gchar* str)
153 {
154     WTF::String uString = WTF::String::fromUTF8(str);
155
156     // The object replacement character is passed along to ATs so we need to be
157     // able to test for their presence and do so without causing test failures.
158     uString.replace(objectReplacementCharacter, "<obj>");
159
160     // The presence of newline characters in accessible text of a single object
161     // is appropriate, but it makes test results (especially the accessible tree)
162     // harder to read.
163     uString.replace("\n", "<\\n>");
164
165     return g_strdup(uString.utf8().data());
166 }
167
168 static const gchar* roleToString(AtkRole role)
169 {
170     switch (role) {
171     case ATK_ROLE_ALERT:
172         return "AXRole: AXAlert";
173     case ATK_ROLE_CANVAS:
174         return "AXRole: AXCanvas";
175     case ATK_ROLE_CHECK_BOX:
176         return "AXRole: AXCheckBox";
177     case ATK_ROLE_COLUMN_HEADER:
178         return "AXRole: AXColumnHeader";
179     case ATK_ROLE_COMBO_BOX:
180         return "AXRole: AXComboBox";
181     case ATK_ROLE_DOCUMENT_FRAME:
182         return "AXRole: AXWebArea";
183     case ATK_ROLE_ENTRY:
184         return "AXRole: AXTextField";
185     case ATK_ROLE_FOOTER:
186         return "AXRole: AXFooter";
187     case ATK_ROLE_FORM:
188         return "AXRole: AXForm";
189     case ATK_ROLE_GROUPING:
190         return "AXRole: AXGroup";
191     case ATK_ROLE_HEADING:
192         return "AXRole: AXHeading";
193     case ATK_ROLE_IMAGE:
194         return "AXRole: AXImage";
195     case ATK_ROLE_IMAGE_MAP:
196         return "AXRole: AXImageMap";
197     case ATK_ROLE_LABEL:
198         return "AXRole: AXLabel";
199     case ATK_ROLE_LINK:
200         return "AXRole: AXLink";
201     case ATK_ROLE_LIST:
202         return "AXRole: AXList";
203     case ATK_ROLE_LIST_BOX:
204         return "AXRole: AXListBox";
205     case ATK_ROLE_LIST_ITEM:
206         return "AXRole: AXListItem";
207     case ATK_ROLE_MENU:
208         return "AXRole: AXMenu";
209     case ATK_ROLE_MENU_BAR:
210         return "AXRole: AXMenuBar";
211     case ATK_ROLE_MENU_ITEM:
212         return "AXRole: AXMenuItem";
213     case ATK_ROLE_PAGE_TAB:
214         return "AXRole: AXTab";
215     case ATK_ROLE_PAGE_TAB_LIST:
216         return "AXRole: AXTabGroup";
217     case ATK_ROLE_PANEL:
218         return "AXRole: AXGroup";
219     case ATK_ROLE_PARAGRAPH:
220         return "AXRole: AXParagraph";
221     case ATK_ROLE_PASSWORD_TEXT:
222         return "AXRole: AXPasswordField";
223     case ATK_ROLE_PUSH_BUTTON:
224         return "AXRole: AXButton";
225     case ATK_ROLE_RADIO_BUTTON:
226         return "AXRole: AXRadioButton";
227     case ATK_ROLE_ROW_HEADER:
228         return "AXRole: AXRowHeader";
229     case ATK_ROLE_RULER:
230         return "AXRole: AXRuler";
231     case ATK_ROLE_SCROLL_BAR:
232         return "AXRole: AXScrollBar";
233     case ATK_ROLE_SCROLL_PANE:
234         return "AXRole: AXScrollArea";
235     case ATK_ROLE_SECTION:
236         return "AXRole: AXDiv";
237     case ATK_ROLE_SEPARATOR:
238         return "AXRole: AXHorizontalRule";
239     case ATK_ROLE_SLIDER:
240         return "AXRole: AXSlider";
241     case ATK_ROLE_SPIN_BUTTON:
242         return "AXRole: AXSpinButton";
243     case ATK_ROLE_TABLE:
244         return "AXRole: AXTable";
245     case ATK_ROLE_TABLE_CELL:
246         return "AXRole: AXCell";
247     case ATK_ROLE_TABLE_COLUMN_HEADER:
248         return "AXRole: AXColumnHeader";
249     case ATK_ROLE_TABLE_ROW:
250         return "AXRole: AXRow";
251     case ATK_ROLE_TABLE_ROW_HEADER:
252         return "AXRole: AXRowHeader";
253     case ATK_ROLE_TOGGLE_BUTTON:
254         return "AXRole: AXToggleButton";
255     case ATK_ROLE_TOOL_BAR:
256         return "AXRole: AXToolbar";
257     case ATK_ROLE_TOOL_TIP:
258         return "AXRole: AXUserInterfaceTooltip";
259     case ATK_ROLE_TREE:
260         return "AXRole: AXTree";
261     case ATK_ROLE_TREE_TABLE:
262         return "AXRole: AXTreeGrid";
263     case ATK_ROLE_TREE_ITEM:
264         return "AXRole: AXTreeItem";
265     case ATK_ROLE_WINDOW:
266         return "AXRole: AXWindow";
267     case ATK_ROLE_UNKNOWN:
268         return "AXRole: AXUnknown";
269     default:
270         // We want to distinguish ATK_ROLE_UNKNOWN from a known AtkRole which
271         // our DRT isn't properly handling.
272         return "AXRole: FIXME not identified";
273     }
274 }
275
276 AccessibilityUIElement::AccessibilityUIElement(PlatformUIElement element)
277     : m_element(element)
278 {
279 }
280
281 AccessibilityUIElement::AccessibilityUIElement(const AccessibilityUIElement& other)
282     : JSWrappable()
283     , m_element(other.m_element)
284 {
285 }
286
287 AccessibilityUIElement::~AccessibilityUIElement()
288 {
289 }
290
291 bool AccessibilityUIElement::isEqual(AccessibilityUIElement* otherElement)
292 {
293     return m_element == otherElement->platformUIElement();
294 }
295
296 void AccessibilityUIElement::getChildren(Vector<RefPtr<AccessibilityUIElement> >& children)
297 {
298     if (!m_element || !ATK_IS_OBJECT(m_element.get()))
299         return;
300
301     int count = childrenCount();
302     for (int i = 0; i < count; i++) {
303         GRefPtr<AtkObject> child = adoptGRef(atk_object_ref_accessible_child(ATK_OBJECT(m_element.get()), i));
304         children.append(AccessibilityUIElement::create(child.get()));
305     }
306 }
307
308 void AccessibilityUIElement::getChildrenWithRange(Vector<RefPtr<AccessibilityUIElement> >& children, unsigned location, unsigned length)
309 {
310     if (!m_element || !ATK_IS_OBJECT(m_element.get()))
311         return;
312     unsigned end = location + length;
313     for (unsigned i = location; i < end; i++) {
314         GRefPtr<AtkObject> child = adoptGRef(atk_object_ref_accessible_child(ATK_OBJECT(m_element.get()), i));
315         children.append(AccessibilityUIElement::create(child.get()));
316     }
317 }
318
319 int AccessibilityUIElement::childrenCount()
320 {
321     if (!m_element)
322         return 0;
323
324     return atk_object_get_n_accessible_children(ATK_OBJECT(m_element.get()));
325 }
326
327 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::elementAtPoint(int x, int y)
328 {
329     if (!m_element || !ATK_IS_OBJECT(m_element.get()))
330         return 0;
331
332     GRefPtr<AtkObject> objectAtPoint = adoptGRef(atk_component_ref_accessible_at_point(ATK_COMPONENT(m_element.get()), x, y, ATK_XY_WINDOW));
333     return objectAtPoint ? AccessibilityUIElement::create(objectAtPoint.get()) : 0;
334 }
335
336 unsigned AccessibilityUIElement::indexOfChild(AccessibilityUIElement* element)
337 {
338     if (!m_element || !ATK_IS_OBJECT(m_element.get()))
339         return 0;
340
341     Vector<RefPtr<AccessibilityUIElement> > children;
342     getChildren(children);
343
344     unsigned count = children.size();
345     for (unsigned i = 0; i < count; i++)
346         if (children[i]->isEqual(element))
347             return i;
348
349     return 0;
350 }
351
352 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::childAtIndex(unsigned index)
353 {
354     Vector<RefPtr<AccessibilityUIElement> > children;
355     getChildrenWithRange(children, index, 1);
356
357     if (children.size() == 1)
358         return children[0];
359
360     return 0;
361 }
362
363 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::linkedUIElementAtIndex(unsigned index)
364 {
365     // FIXME: implement
366     return 0;
367 }
368
369 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::ariaOwnsElementAtIndex(unsigned index)
370 {
371     // FIXME: implement
372     return 0;
373 }
374
375 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::ariaFlowToElementAtIndex(unsigned index)
376 {
377     // FIXME: implement
378     return 0;
379 }
380
381 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::disclosedRowAtIndex(unsigned index)
382 {
383     // FIXME: implement
384     return 0;
385 }
386
387 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::rowAtIndex(unsigned index)
388 {
389     // FIXME: implement
390     return 0;
391 }
392
393 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::selectedChildAtIndex(unsigned index) const
394 {
395     // FIXME: implement
396     return 0;
397 }
398
399 unsigned AccessibilityUIElement::selectedChildrenCount() const
400 {
401     // FIXME: implement
402     return 0;
403 }
404
405 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::selectedRowAtIndex(unsigned index)
406 {
407     // FIXME: implement
408     return 0;
409 }
410
411 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::titleUIElement()
412 {
413     if (!m_element)
414         return 0;
415
416     AtkRelationSet* set = atk_object_ref_relation_set(ATK_OBJECT(m_element.get()));
417     if (!set)
418         return 0;
419
420     AtkObject* target = 0;
421     int count = atk_relation_set_get_n_relations(set);
422     for (int i = 0; i < count; i++) {
423         AtkRelation* relation = atk_relation_set_get_relation(set, i);
424         if (atk_relation_get_relation_type(relation) == ATK_RELATION_LABELLED_BY) {
425             GPtrArray* targetList = atk_relation_get_target(relation);
426             if (targetList->len)
427                 target = static_cast<AtkObject*>(g_ptr_array_index(targetList, 0));
428         }
429     }
430
431     g_object_unref(set);
432     return target ? AccessibilityUIElement::create(target) : 0;
433 }
434
435 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::parentElement()
436 {
437     if (!m_element || !ATK_IS_OBJECT(m_element.get()))
438         return 0;
439
440     AtkObject* parent = atk_object_get_parent(ATK_OBJECT(m_element.get()));
441     return parent ? AccessibilityUIElement::create(parent) : 0;
442 }
443
444 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::disclosedByRow()
445 {
446     // FIXME: implement
447     return 0;
448 }
449
450 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfLinkedUIElements()
451 {
452     // FIXME: implement
453     return JSStringCreateWithCharacters(0, 0);
454 }
455
456 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfDocumentLinks()
457 {
458     // FIXME: implement
459     return JSStringCreateWithCharacters(0, 0);
460 }
461
462 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfChildren()
463 {
464     // FIXME: implement
465     return JSStringCreateWithCharacters(0, 0);
466 }
467
468 JSRetainPtr<JSStringRef> AccessibilityUIElement::allAttributes()
469 {
470     if (!m_element || !ATK_IS_OBJECT(m_element.get()))
471         return JSStringCreateWithCharacters(0, 0);
472
473     GOwnPtr<gchar> attributeData(attributeSetToString(atk_object_get_attributes(ATK_OBJECT(m_element.get()))));
474     return JSStringCreateWithUTF8CString(attributeData.get());
475 }
476
477 JSRetainPtr<JSStringRef> AccessibilityUIElement::stringAttributeValue(JSStringRef attribute)
478 {
479     if (!m_element)
480         return JSStringCreateWithCharacters(0, 0);
481
482     String atkAttributeName = coreAttributeToAtkAttribute(attribute);
483     if (atkAttributeName.isNull())
484         return JSStringCreateWithCharacters(0, 0);
485
486     GOwnPtr<gchar> attributeValue;
487     GOwnPtr<GSList> objectAttributes(atk_object_get_attributes(ATK_OBJECT(m_element.get())));
488     for (GSList* attributes =  objectAttributes.get(); attributes; attributes = attributes->next) {
489         AtkAttribute* atkAttribute = static_cast<AtkAttribute*>(attributes->data);
490         if (!strcmp(atkAttribute->name, atkAttributeName.utf8().data())) {
491             attributeValue.set(g_strdup(atkAttribute->value));
492             break;
493         }
494     }
495
496     attributesClear(objectAttributes.get());
497
498     return JSStringCreateWithUTF8CString(attributeValue.get());
499 }
500
501 double AccessibilityUIElement::numberAttributeValue(JSStringRef attribute)
502 {
503     // FIXME: implement
504     return 0.0f;
505 }
506
507 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::uiElementAttributeValue(JSStringRef attribute) const
508 {
509     // FIXME: implement
510     return 0;
511 }
512
513 bool AccessibilityUIElement::boolAttributeValue(JSStringRef attribute)
514 {
515     // FIXME: implement
516     return false;
517 }
518
519 bool AccessibilityUIElement::isAttributeSettable(JSStringRef attribute)
520 {
521     // FIXME: implement
522     return false;
523 }
524
525 bool AccessibilityUIElement::isAttributeSupported(JSStringRef attribute)
526 {
527     // FIXME: implement
528     return false;
529 }
530
531 JSRetainPtr<JSStringRef> AccessibilityUIElement::parameterizedAttributeNames()
532 {
533     // FIXME: implement
534     return JSStringCreateWithCharacters(0, 0);
535 }
536
537 JSRetainPtr<JSStringRef> AccessibilityUIElement::role()
538 {
539     if (!m_element || !ATK_IS_OBJECT(m_element.get()))
540         return JSStringCreateWithCharacters(0, 0);
541
542     AtkRole role = atk_object_get_role(ATK_OBJECT(m_element.get()));
543     if (!role)
544         return JSStringCreateWithCharacters(0, 0);
545
546     GOwnPtr<gchar> axRole(g_strdup(roleToString(role)));
547     return JSStringCreateWithUTF8CString(axRole.get());
548 }
549
550 JSRetainPtr<JSStringRef> AccessibilityUIElement::subrole()
551 {
552     // FIXME: implement
553     return JSStringCreateWithCharacters(0, 0);
554 }
555
556 JSRetainPtr<JSStringRef> AccessibilityUIElement::roleDescription()
557 {
558     // FIXME: implement
559     return JSStringCreateWithCharacters(0, 0);
560 }
561
562 JSRetainPtr<JSStringRef> AccessibilityUIElement::title()
563 {
564     if (!m_element || !ATK_IS_OBJECT(m_element.get()))
565         return JSStringCreateWithCharacters(0, 0);
566
567     const gchar* name = atk_object_get_name(ATK_OBJECT(m_element.get()));
568     GOwnPtr<gchar> axTitle(g_strdup_printf("AXTitle: %s", name ? name : ""));
569
570     return JSStringCreateWithUTF8CString(axTitle.get());
571 }
572
573 JSRetainPtr<JSStringRef> AccessibilityUIElement::description()
574 {
575     if (!m_element || !ATK_IS_OBJECT(m_element.get()))
576         return JSStringCreateWithCharacters(0, 0);
577
578     const gchar* description = atk_object_get_description(ATK_OBJECT(m_element.get()));
579     if (!description)
580         return JSStringCreateWithCharacters(0, 0);
581
582     GOwnPtr<gchar> axDesc(g_strdup_printf("AXDescription: %s", description));
583
584     return JSStringCreateWithUTF8CString(axDesc.get());
585 }
586
587 JSRetainPtr<JSStringRef> AccessibilityUIElement::orientation() const
588 {
589     if (!m_element || !ATK_IS_OBJECT(m_element.get()))
590         return JSStringCreateWithCharacters(0, 0);
591
592     const gchar* axOrientation = 0;
593     if (checkElementState(m_element.get(), ATK_STATE_HORIZONTAL))
594         axOrientation = "AXOrientation: AXHorizontalOrientation";
595     else if (checkElementState(m_element.get(), ATK_STATE_VERTICAL))
596         axOrientation = "AXOrientation: AXVerticalOrientation";
597
598     if (!axOrientation)
599         return JSStringCreateWithCharacters(0, 0);
600
601     return JSStringCreateWithUTF8CString(axOrientation);
602 }
603
604 JSRetainPtr<JSStringRef> AccessibilityUIElement::stringValue()
605 {
606     if (!m_element || !ATK_IS_TEXT(m_element.get()))
607         return JSStringCreateWithCharacters(0, 0);
608
609     GOwnPtr<gchar> text(atk_text_get_text(ATK_TEXT(m_element.get()), 0, -1));
610     GOwnPtr<gchar> textWithReplacedCharacters(replaceCharactersForResults(text.get()));
611     GOwnPtr<gchar> axValue(g_strdup_printf("AXValue: %s", textWithReplacedCharacters.get()));
612
613     return JSStringCreateWithUTF8CString(axValue.get());
614 }
615
616 JSRetainPtr<JSStringRef> AccessibilityUIElement::language()
617 {
618     if (!m_element || !ATK_IS_OBJECT(m_element.get()))
619         return JSStringCreateWithCharacters(0, 0);
620
621     GOwnPtr<gchar> language;
622     // In ATK, the document language is exposed as the document's locale.
623     if (atk_object_get_role(ATK_OBJECT(m_element.get())) == ATK_ROLE_DOCUMENT_FRAME) {
624         language.set(g_strdup_printf("AXLanguage: %s", atk_document_get_locale(ATK_DOCUMENT(m_element.get()))));
625         return JSStringCreateWithUTF8CString(language.get());
626     }
627
628     // For all other objects, the language is exposed as an AtkText attribute.
629     if (!ATK_IS_TEXT(m_element.get()))
630         return JSStringCreateWithCharacters(0, 0);
631
632     GOwnPtr<GSList> textAttributes(atk_text_get_default_attributes(ATK_TEXT(m_element.get())));
633     for (GSList* attributes = textAttributes.get(); attributes; attributes = attributes->next) {
634         AtkAttribute* atkAttribute = static_cast<AtkAttribute*>(attributes->data);
635         if (!strcmp(atkAttribute->name, atk_text_attribute_get_name(ATK_TEXT_ATTR_LANGUAGE))) {
636             language.set(g_strdup_printf("AXLanguage: %s", atkAttribute->value));
637             break;
638         }
639     }
640
641     attributesClear(textAttributes.get());
642
643     return JSStringCreateWithUTF8CString(language.get());
644 }
645
646 JSRetainPtr<JSStringRef> AccessibilityUIElement::helpText() const
647 {
648     // FIXME: implement
649     // We need a way to call WebCore::AccessibilityObject::helpText()
650     // from here, probably a new helper class in WebProcess/WebCoreSupport.
651     return JSStringCreateWithCharacters(0, 0);
652 }
653
654 double AccessibilityUIElement::x()
655 {
656     if (!m_element || !ATK_IS_OBJECT(m_element.get()))
657         return 0.0f;
658
659     int x, y;
660     atk_component_get_position(ATK_COMPONENT(m_element.get()), &x, &y, ATK_XY_SCREEN);
661     return x;
662 }
663
664 double AccessibilityUIElement::y()
665 {
666     if (!m_element || !ATK_IS_OBJECT(m_element.get()))
667         return 0.0f;
668
669     int x, y;
670     atk_component_get_position(ATK_COMPONENT(m_element.get()), &x, &y, ATK_XY_SCREEN);
671     return y;
672 }
673
674 double AccessibilityUIElement::width()
675 {
676     if (!m_element || !ATK_IS_OBJECT(m_element.get()))
677         return 0.0f;
678
679     int width, height;
680     atk_component_get_size(ATK_COMPONENT(m_element.get()), &width, &height);
681     return width;
682 }
683
684 double AccessibilityUIElement::height()
685 {
686     if (!m_element || !ATK_IS_OBJECT(m_element.get()))
687         return 0.0f;
688
689     int width, height;
690     atk_component_get_size(ATK_COMPONENT(m_element.get()), &width, &height);
691     return height;
692 }
693
694 double AccessibilityUIElement::clickPointX()
695 {
696     // FIXME: implement
697     return 0.0f;
698 }
699
700 double AccessibilityUIElement::clickPointY()
701 {
702     // FIXME: implement
703     return 0.0f;
704 }
705
706 double AccessibilityUIElement::intValue() const
707 {
708     if (!m_element || !ATK_IS_OBJECT(m_element.get()))
709         return 0.0f;
710
711     GValue value = G_VALUE_INIT;
712     atk_value_get_current_value(ATK_VALUE(m_element.get()), &value);
713     if (!G_VALUE_HOLDS_FLOAT(&value))
714         return 0.0f;
715
716     return g_value_get_float(&value);
717 }
718
719 double AccessibilityUIElement::minValue()
720 {
721     if (!m_element || !ATK_IS_OBJECT(m_element.get()))
722         return 0.0f;
723
724     GValue value = G_VALUE_INIT;
725     atk_value_get_minimum_value(ATK_VALUE(m_element.get()), &value);
726     if (!G_VALUE_HOLDS_FLOAT(&value))
727         return 0.0f;
728
729     return g_value_get_float(&value);
730 }
731
732 double AccessibilityUIElement::maxValue()
733 {
734     if (!m_element || !ATK_IS_OBJECT(m_element.get()))
735         return 0.0f;
736
737     GValue value = G_VALUE_INIT;
738     atk_value_get_maximum_value(ATK_VALUE(m_element.get()), &value);
739     if (!G_VALUE_HOLDS_FLOAT(&value))
740         return 0.0f;
741
742     return g_value_get_float(&value);
743 }
744
745 JSRetainPtr<JSStringRef> AccessibilityUIElement::valueDescription()
746 {
747     // FIXME: implement
748     return JSStringCreateWithCharacters(0, 0);
749 }
750
751 int AccessibilityUIElement::insertionPointLineNumber()
752 {
753     // FIXME: implement
754     return -1;
755 }
756
757 bool AccessibilityUIElement::isPressActionSupported()
758 {
759     // FIXME: implement
760     return false;
761 }
762
763 bool AccessibilityUIElement::isIncrementActionSupported()
764 {
765     // FIXME: implement
766     return false;
767 }
768
769 bool AccessibilityUIElement::isDecrementActionSupported()
770 {
771     // FIXME: implement
772     return false;
773 }
774
775 bool AccessibilityUIElement::isEnabled()
776 {
777     return checkElementState(m_element.get(), ATK_STATE_ENABLED);
778 }
779
780 bool AccessibilityUIElement::isRequired() const
781 {
782     // FIXME: implement
783     return false;
784 }
785
786 bool AccessibilityUIElement::isFocused() const
787 {
788     return checkElementState(m_element.get(), ATK_STATE_FOCUSED);
789 }
790
791 bool AccessibilityUIElement::isSelected() const
792 {
793     return checkElementState(m_element.get(), ATK_STATE_SELECTED);
794 }
795
796 bool AccessibilityUIElement::isExpanded() const
797 {
798     return checkElementState(m_element.get(), ATK_STATE_EXPANDED);
799 }
800
801 bool AccessibilityUIElement::isChecked() const
802 {
803     return checkElementState(m_element.get(), ATK_STATE_CHECKED);
804 }
805
806 int AccessibilityUIElement::hierarchicalLevel() const
807 {
808     // FIXME: implement
809     return 0;
810 }
811
812 JSRetainPtr<JSStringRef> AccessibilityUIElement::speak()
813 {
814     // FIXME: implement
815     return JSStringCreateWithCharacters(0, 0);
816 }
817
818 bool AccessibilityUIElement::ariaIsGrabbed() const
819 {
820     // FIXME: implement
821     return false;
822 }
823
824 JSRetainPtr<JSStringRef> AccessibilityUIElement::ariaDropEffects() const
825 {
826     // FIXME: implement
827     return JSStringCreateWithCharacters(0, 0);
828 }
829
830 // parameterized attributes
831 int AccessibilityUIElement::lineForIndex(int index)
832 {
833     // FIXME: implement
834     return 0;
835 }
836
837 JSRetainPtr<JSStringRef> AccessibilityUIElement::rangeForLine(int line)
838 {
839     // FIXME: implement
840     return JSStringCreateWithCharacters(0, 0);
841 }
842
843 JSRetainPtr<JSStringRef> AccessibilityUIElement::rangeForPosition(int x, int y)
844 {
845     // FIXME: implement
846     return JSStringCreateWithCharacters(0, 0);
847 }
848
849 JSRetainPtr<JSStringRef> AccessibilityUIElement::boundsForRange(unsigned location, unsigned length)
850 {
851     // FIXME: implement
852     return JSStringCreateWithCharacters(0, 0);
853 }
854
855 JSRetainPtr<JSStringRef> AccessibilityUIElement::stringForRange(unsigned location, unsigned length)
856 {
857     // FIXME: implement
858     return JSStringCreateWithCharacters(0, 0);
859 }
860
861 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributedStringForRange(unsigned location, unsigned length)
862 {
863     // FIXME: implement
864     return JSStringCreateWithCharacters(0, 0);
865 }
866
867 bool AccessibilityUIElement::attributedStringRangeIsMisspelled(unsigned location, unsigned length)
868 {
869     // FIXME: implement
870     return false;
871 }
872
873 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::uiElementForSearchPredicate(JSContextRef context, AccessibilityUIElement* startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly)
874 {
875     // FIXME: implement
876     return 0;
877 }
878
879 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfColumnHeaders()
880 {
881     // FIXME: implement
882     return JSStringCreateWithCharacters(0, 0);
883 }
884
885 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfRowHeaders()
886 {
887     // FIXME: implement
888     return JSStringCreateWithCharacters(0, 0);
889 }
890
891 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfColumns()
892 {
893     // FIXME: implement
894     return JSStringCreateWithCharacters(0, 0);
895 }
896
897 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfRows()
898 {
899     // FIXME: implement
900     return JSStringCreateWithCharacters(0, 0);
901 }
902
903 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfVisibleCells()
904 {
905     // FIXME: implement
906     return JSStringCreateWithCharacters(0, 0);
907 }
908
909 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfHeader()
910 {
911     // FIXME: implement
912     return JSStringCreateWithCharacters(0, 0);
913 }
914
915 int AccessibilityUIElement::rowCount()
916 {
917     if (!m_element || !ATK_IS_TABLE(m_element.get()))
918         return 0;
919
920     return atk_table_get_n_rows(ATK_TABLE(m_element.get()));
921 }
922
923 int AccessibilityUIElement::columnCount()
924 {
925     if (!m_element || !ATK_IS_TABLE(m_element.get()))
926         return 0;
927
928     return atk_table_get_n_columns(ATK_TABLE(m_element.get()));
929 }
930
931 int AccessibilityUIElement::indexInTable()
932 {
933     // FIXME: implement
934     return -1;
935 }
936
937 JSRetainPtr<JSStringRef> AccessibilityUIElement::rowIndexRange()
938 {
939     // Range in table for rows.
940     return indexRangeInTable(m_element.get(), true);
941 }
942
943 JSRetainPtr<JSStringRef> AccessibilityUIElement::columnIndexRange()
944 {
945     // Range in table for columns.
946     return indexRangeInTable(m_element.get(), false);
947 }
948
949 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::cellForColumnAndRow(unsigned col, unsigned row)
950 {
951     if (!m_element || !ATK_IS_TABLE(m_element.get()))
952         return 0;
953
954     // Adopt the AtkObject representing the cell because
955     // at_table_ref_at() transfers full ownership.
956     GRefPtr<AtkObject> foundCell = adoptGRef(atk_table_ref_at(ATK_TABLE(m_element.get()), row, col));
957     return foundCell ? AccessibilityUIElement::create(foundCell.get()) : 0;
958 }
959
960 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::horizontalScrollbar() const
961 {
962     // FIXME: implement
963     return 0;
964 }
965
966 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::verticalScrollbar() const
967 {
968     // FIXME: implement
969     return 0;
970 }
971
972 JSRetainPtr<JSStringRef> AccessibilityUIElement::selectedTextRange()
973 {
974     // FIXME: implement
975     return JSStringCreateWithCharacters(0, 0);
976 }
977
978 void AccessibilityUIElement::setSelectedTextRange(unsigned location, unsigned length)
979 {
980     // FIXME: implement
981 }
982
983 void AccessibilityUIElement::increment()
984 {
985     alterCurrentValue(m_element.get(), 1);
986 }
987
988 void AccessibilityUIElement::decrement()
989 {
990     alterCurrentValue(m_element.get(), -1);
991 }
992
993 void AccessibilityUIElement::showMenu()
994 {
995     // FIXME: implement
996 }
997
998 void AccessibilityUIElement::press()
999 {
1000     if (!m_element || !ATK_IS_OBJECT(m_element.get()))
1001         return;
1002
1003     if (!ATK_IS_ACTION(m_element.get()))
1004         return;
1005
1006     // Only one action per object is supported so far.
1007     atk_action_do_action(ATK_ACTION(m_element.get()), 0);
1008 }
1009
1010 void AccessibilityUIElement::setSelectedChild(AccessibilityUIElement* element) const
1011 {
1012     // FIXME: implement
1013 }
1014
1015 JSRetainPtr<JSStringRef> AccessibilityUIElement::accessibilityValue() const
1016 {
1017     // FIXME: implement
1018     return JSStringCreateWithCharacters(0, 0);
1019 }
1020
1021 JSRetainPtr<JSStringRef> AccessibilityUIElement::documentEncoding()
1022 {
1023     if (!m_element || !ATK_IS_OBJECT(m_element.get()))
1024         return JSStringCreateWithCharacters(0, 0);
1025
1026     AtkRole role = atk_object_get_role(ATK_OBJECT(m_element.get()));
1027     if (role != ATK_ROLE_DOCUMENT_FRAME)
1028         return JSStringCreateWithCharacters(0, 0);
1029
1030     return JSStringCreateWithUTF8CString(atk_document_get_attribute_value(ATK_DOCUMENT(m_element.get()), "Encoding"));
1031 }
1032
1033 JSRetainPtr<JSStringRef> AccessibilityUIElement::documentURI()
1034 {
1035     if (!m_element || !ATK_IS_OBJECT(m_element.get()))
1036         return JSStringCreateWithCharacters(0, 0);
1037
1038     AtkRole role = atk_object_get_role(ATK_OBJECT(m_element.get()));
1039     if (role != ATK_ROLE_DOCUMENT_FRAME)
1040         return JSStringCreateWithCharacters(0, 0);
1041
1042     return JSStringCreateWithUTF8CString(atk_document_get_attribute_value(ATK_DOCUMENT(m_element.get()), "URI"));
1043 }
1044
1045 JSRetainPtr<JSStringRef> AccessibilityUIElement::url()
1046 {
1047     // FIXME: implement
1048     return JSStringCreateWithCharacters(0, 0);
1049 }
1050
1051 bool AccessibilityUIElement::addNotificationListener(JSValueRef functionCallback)
1052 {
1053     // FIXME: implement
1054     return true;
1055 }
1056
1057 bool AccessibilityUIElement::removeNotificationListener()
1058 {
1059     // FIXME: implement
1060     return true;
1061 }
1062
1063 bool AccessibilityUIElement::isFocusable() const
1064 {
1065     return checkElementState(m_element.get(), ATK_STATE_FOCUSABLE);
1066 }
1067
1068 bool AccessibilityUIElement::isSelectable() const
1069 {
1070     return checkElementState(m_element.get(), ATK_STATE_SELECTABLE);
1071 }
1072
1073 bool AccessibilityUIElement::isMultiSelectable() const
1074 {
1075     return checkElementState(m_element.get(), ATK_STATE_MULTISELECTABLE);
1076 }
1077
1078 bool AccessibilityUIElement::isVisible() const
1079 {
1080     return checkElementState(m_element.get(), ATK_STATE_VISIBLE);
1081 }
1082
1083 bool AccessibilityUIElement::isOffScreen() const
1084 {
1085     // FIXME: implement
1086     return false;
1087 }
1088
1089 bool AccessibilityUIElement::isCollapsed() const
1090 {
1091     // FIXME: implement
1092     return false;
1093 }
1094
1095 bool AccessibilityUIElement::isIgnored() const
1096 {
1097     // FIXME: implement
1098     return false;
1099 }
1100
1101 bool AccessibilityUIElement::hasPopup() const
1102 {
1103     // FIXME: implement
1104     return false;
1105 }
1106
1107 void AccessibilityUIElement::takeFocus()
1108 {
1109     // FIXME: implement
1110 }
1111
1112 void AccessibilityUIElement::takeSelection()
1113 {
1114     // FIXME: implement
1115 }
1116
1117 void AccessibilityUIElement::addSelection()
1118 {
1119     // FIXME: implement
1120 }
1121
1122 void AccessibilityUIElement::removeSelection()
1123 {
1124     // FIXME: implement
1125 }
1126
1127 // Text markers
1128 PassRefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::textMarkerRangeForElement(AccessibilityUIElement* element)
1129 {
1130     // FIXME: implement
1131     return 0;
1132 }
1133
1134 int AccessibilityUIElement::textMarkerRangeLength(AccessibilityTextMarkerRange* range)
1135 {
1136     // FIXME: implement
1137     return 0;
1138 }
1139
1140 PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::previousTextMarker(AccessibilityTextMarker* textMarker)
1141 {
1142     // FIXME: implement
1143     return 0;
1144 }
1145
1146 PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::nextTextMarker(AccessibilityTextMarker* textMarker)
1147 {
1148     // FIXME: implement
1149     return 0;
1150 }
1151
1152 JSRetainPtr<JSStringRef> AccessibilityUIElement::stringForTextMarkerRange(AccessibilityTextMarkerRange* markerRange)
1153 {
1154     // FIXME: implement
1155     return JSStringCreateWithCharacters(0, 0);
1156 }
1157
1158 PassRefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::textMarkerRangeForMarkers(AccessibilityTextMarker* startMarker, AccessibilityTextMarker* endMarker)
1159 {
1160     // FIXME: implement
1161     return 0;
1162 }
1163
1164 PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::startTextMarkerForTextMarkerRange(AccessibilityTextMarkerRange* range)
1165 {
1166     // FIXME: implement
1167     return 0;
1168 }
1169
1170 PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::endTextMarkerForTextMarkerRange(AccessibilityTextMarkerRange* range)
1171 {
1172     // FIXME: implement
1173     return 0;
1174 }
1175
1176 PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::textMarkerForPoint(int x, int y)
1177 {
1178     // FIXME: implement
1179     return 0;
1180 }
1181
1182 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::accessibilityElementForTextMarker(AccessibilityTextMarker* marker)
1183 {
1184     // FIXME: implement
1185     return 0;
1186 }
1187
1188 bool AccessibilityUIElement::attributedStringForTextMarkerRangeContainsAttribute(JSStringRef attribute, AccessibilityTextMarkerRange* range)
1189 {
1190     // FIXME: implement
1191     return false;
1192 }
1193
1194 int AccessibilityUIElement::indexForTextMarker(AccessibilityTextMarker* marker)
1195 {
1196     // FIXME: implement
1197     return -1;
1198 }
1199
1200 bool AccessibilityUIElement::isTextMarkerValid(AccessibilityTextMarker* textMarker)
1201 {
1202     // FIXME: implement
1203     return false;
1204 }
1205
1206 PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::textMarkerForIndex(int textIndex)
1207 {
1208     // FIXME: implement
1209     return 0;
1210 }
1211
1212 void AccessibilityUIElement::scrollToMakeVisible()
1213 {
1214     // FIXME: implement
1215 }
1216
1217 JSRetainPtr<JSStringRef> AccessibilityUIElement::supportedActions() const
1218 {
1219     // FIXME: implement
1220     return 0;
1221 }
1222
1223 JSRetainPtr<JSStringRef> AccessibilityUIElement::pathDescription() const
1224 {
1225     notImplemented();
1226     return 0;
1227 }
1228
1229 JSRetainPtr<JSStringRef> AccessibilityUIElement::mathPostscriptsDescription() const
1230 {
1231     notImplemented();
1232     return 0;
1233 }
1234
1235 JSRetainPtr<JSStringRef> AccessibilityUIElement::mathPrescriptsDescription() const
1236 {
1237     notImplemented();
1238     return 0;
1239 }
1240
1241 } // namespace WTR
1242
1243 #endif