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