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