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