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