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