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