[GTK] Missing call to g_object_ref while retrieving accessible table cells
[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     // Adopt the AtkObject representing the cell because
778     // at_table_ref_at() transfers full ownership.
779     GRefPtr<AtkObject> foundCell = adoptGRef(atk_table_ref_at(ATK_TABLE(m_element), row, column));
780     return foundCell ? AccessibilityUIElement(foundCell.get()) : 0;
781 }
782
783 JSStringRef AccessibilityUIElement::selectedTextRange()
784 {
785     // FIXME: implement
786     return JSStringCreateWithCharacters(0, 0);
787 }
788
789 void AccessibilityUIElement::setSelectedTextRange(unsigned location, unsigned length)
790 {
791     // FIXME: implement
792 }
793
794 JSStringRef AccessibilityUIElement::stringAttributeValue(JSStringRef attribute)
795 {
796     if (!m_element)
797         return JSStringCreateWithCharacters(0, 0);
798
799     String atkAttributeName = coreAttributeToAtkAttribute(attribute);
800     if (atkAttributeName.isEmpty())
801         return JSStringCreateWithCharacters(0, 0);
802
803     for (GSList* atkAttributes = atk_object_get_attributes(ATK_OBJECT(m_element)); atkAttributes; atkAttributes = atkAttributes->next) {
804         AtkAttribute* atkAttribute = static_cast<AtkAttribute*>(atkAttributes->data);
805         if (!strcmp(atkAttribute->name, atkAttributeName.utf8().data()))
806             return JSStringCreateWithUTF8CString(atkAttribute->value);
807     }
808
809     return JSStringCreateWithCharacters(0, 0);
810 }
811
812 double AccessibilityUIElement::numberAttributeValue(JSStringRef attribute)
813 {
814     // FIXME: implement
815     return 0.0f;
816 }
817
818 bool AccessibilityUIElement::boolAttributeValue(JSStringRef attribute)
819 {
820     // FIXME: implement
821     return false;
822 }
823
824 bool AccessibilityUIElement::isAttributeSettable(JSStringRef attribute)
825 {
826     // FIXME: implement
827     return false;
828 }
829
830 bool AccessibilityUIElement::isAttributeSupported(JSStringRef attribute)
831 {
832     return false;
833 }
834
835 static void alterCurrentValue(PlatformUIElement element, int factor)
836 {
837     if (!element)
838         return;
839
840     ASSERT(ATK_IS_VALUE(element));
841
842     GValue currentValue = G_VALUE_INIT;
843     atk_value_get_current_value(ATK_VALUE(element), &currentValue);
844
845     GValue increment = G_VALUE_INIT;
846     atk_value_get_minimum_increment(ATK_VALUE(element), &increment);
847
848     GValue newValue = G_VALUE_INIT;
849     g_value_init(&newValue, G_TYPE_FLOAT);
850
851     g_value_set_float(&newValue, g_value_get_float(&currentValue) + factor * g_value_get_float(&increment));
852     atk_value_set_current_value(ATK_VALUE(element), &newValue);
853
854     g_value_unset(&newValue);
855     g_value_unset(&increment);
856     g_value_unset(&currentValue);
857 }
858
859 void AccessibilityUIElement::increment()
860 {
861     alterCurrentValue(m_element, 1);
862 }
863
864 void AccessibilityUIElement::decrement()
865 {
866     alterCurrentValue(m_element, -1);
867 }
868
869 void AccessibilityUIElement::press()
870 {
871     if (!m_element)
872         return;
873
874     ASSERT(ATK_IS_OBJECT(m_element));
875
876     if (!ATK_IS_ACTION(m_element))
877         return;
878
879     // Only one action per object is supported so far.
880     atk_action_do_action(ATK_ACTION(m_element), 0);
881 }
882
883 void AccessibilityUIElement::showMenu()
884 {
885     // FIXME: implement
886 }
887
888 AccessibilityUIElement AccessibilityUIElement::disclosedRowAtIndex(unsigned index)
889 {
890     return 0;
891 }
892
893 AccessibilityUIElement AccessibilityUIElement::ariaOwnsElementAtIndex(unsigned index)
894 {
895     return 0;
896 }
897
898 AccessibilityUIElement AccessibilityUIElement::ariaFlowToElementAtIndex(unsigned index)
899 {
900     return 0;
901 }
902
903 AccessibilityUIElement AccessibilityUIElement::selectedRowAtIndex(unsigned index)
904 {
905     return 0;
906 }
907
908 AccessibilityUIElement AccessibilityUIElement::rowAtIndex(unsigned index)
909 {
910     return 0;
911 }
912
913 AccessibilityUIElement AccessibilityUIElement::disclosedByRow()
914 {
915     return 0;
916 }
917
918 JSStringRef AccessibilityUIElement::accessibilityValue() const
919 {
920     // FIXME: implement
921     return JSStringCreateWithCharacters(0, 0);
922 }
923
924 JSStringRef AccessibilityUIElement::documentEncoding()
925 {
926     AtkRole role = atk_object_get_role(ATK_OBJECT(m_element));
927     if (role != ATK_ROLE_DOCUMENT_FRAME)
928         return JSStringCreateWithCharacters(0, 0);
929
930     return JSStringCreateWithUTF8CString(atk_document_get_attribute_value(ATK_DOCUMENT(m_element), "Encoding"));
931 }
932
933 JSStringRef AccessibilityUIElement::documentURI()
934 {
935     AtkRole role = atk_object_get_role(ATK_OBJECT(m_element));
936     if (role != ATK_ROLE_DOCUMENT_FRAME)
937         return JSStringCreateWithCharacters(0, 0);
938
939     return JSStringCreateWithUTF8CString(atk_document_get_attribute_value(ATK_DOCUMENT(m_element), "URI"));
940 }
941
942 JSStringRef AccessibilityUIElement::url()
943 {
944     // FIXME: implement
945     return JSStringCreateWithCharacters(0, 0);
946 }
947
948 bool AccessibilityUIElement::addNotificationListener(JSObjectRef functionCallback)
949 {
950     // FIXME: implement
951     return false;
952 }
953
954 void AccessibilityUIElement::removeNotificationListener()
955 {
956     // FIXME: implement
957 }
958
959 bool AccessibilityUIElement::isFocusable() const
960 {
961     if (!ATK_IS_OBJECT(m_element))
962         return false;
963
964     GRefPtr<AtkStateSet> stateSet = adoptGRef(atk_object_ref_state_set(ATK_OBJECT(m_element)));
965     gboolean isFocusable = atk_state_set_contains_state(stateSet.get(), ATK_STATE_FOCUSABLE);
966
967     return isFocusable;
968 }
969
970 bool AccessibilityUIElement::isSelectable() const
971 {
972     return checkElementState(m_element, ATK_STATE_SELECTABLE);
973 }
974
975 bool AccessibilityUIElement::isMultiSelectable() const
976 {
977     return checkElementState(m_element, ATK_STATE_MULTISELECTABLE);
978 }
979
980 bool AccessibilityUIElement::isSelectedOptionActive() const
981 {
982     // FIXME: implement
983     return false;
984 }
985
986 bool AccessibilityUIElement::isVisible() const
987 {
988     // FIXME: implement
989     return false;
990 }
991
992 bool AccessibilityUIElement::isOffScreen() const
993 {
994     // FIXME: implement
995     return false;
996 }
997
998 bool AccessibilityUIElement::isCollapsed() const
999 {
1000     // FIXME: implement
1001     return false;
1002 }
1003
1004 bool AccessibilityUIElement::isIgnored() const
1005 {
1006     // FIXME: implement
1007     return false;
1008 }
1009
1010 bool AccessibilityUIElement::hasPopup() const
1011 {
1012     // FIXME: implement
1013     return false;
1014 }
1015
1016 void AccessibilityUIElement::takeFocus()
1017 {
1018     // FIXME: implement
1019 }
1020
1021 void AccessibilityUIElement::takeSelection()
1022 {
1023     // FIXME: implement
1024 }
1025
1026 void AccessibilityUIElement::addSelection()
1027 {
1028     // FIXME: implement
1029 }
1030
1031 void AccessibilityUIElement::removeSelection()
1032 {
1033     // FIXME: implement
1034 }
1035
1036 void AccessibilityUIElement::scrollToMakeVisible()
1037 {
1038     // FIXME: implement
1039 }
1040
1041 void AccessibilityUIElement::scrollToMakeVisibleWithSubFocus(int x, int y, int width, int height)
1042 {
1043     // FIXME: implement
1044 }
1045
1046 void AccessibilityUIElement::scrollToGlobalPoint(int x, int y)
1047 {
1048     // FIXME: implement
1049 }
1050
1051 #endif