67a993edd33dd5300956b1d430025e17d23c7dc6
[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 static bool checkElementState(PlatformUIElement element, AtkStateType stateType)
179 {
180     if (!ATK_IS_OBJECT(element))
181         return false;
182
183     GRefPtr<AtkStateSet> stateSet = adoptGRef(atk_object_ref_state_set(ATK_OBJECT(element)));
184     return atk_state_set_contains_state(stateSet.get(), stateType);
185 }
186
187 AccessibilityUIElement::AccessibilityUIElement(PlatformUIElement element)
188     : m_element(element)
189 {
190     if (m_element)
191         g_object_ref(m_element);
192 }
193
194 AccessibilityUIElement::AccessibilityUIElement(const AccessibilityUIElement& other)
195     : m_element(other.m_element)
196 {
197     if (m_element)
198         g_object_ref(m_element);
199 }
200
201 AccessibilityUIElement::~AccessibilityUIElement()
202 {
203     if (m_element)
204         g_object_unref(m_element);
205 }
206
207 void AccessibilityUIElement::getLinkedUIElements(Vector<AccessibilityUIElement>& elements)
208 {
209     // FIXME: implement
210 }
211
212 void AccessibilityUIElement::getDocumentLinks(Vector<AccessibilityUIElement>&)
213 {
214     // FIXME: implement
215 }
216
217 void AccessibilityUIElement::getChildren(Vector<AccessibilityUIElement>& children)
218 {
219     int count = childrenCount();
220     for (int i = 0; i < count; i++) {
221         AtkObject* child = atk_object_ref_accessible_child(ATK_OBJECT(m_element), i);
222         children.append(AccessibilityUIElement(child));
223     }
224 }
225
226 void AccessibilityUIElement::getChildrenWithRange(Vector<AccessibilityUIElement>& elementVector, unsigned start, unsigned end)
227 {
228     for (unsigned i = start; i < end; i++) {
229         AtkObject* child = atk_object_ref_accessible_child(ATK_OBJECT(m_element), i);
230         elementVector.append(AccessibilityUIElement(child));
231     }
232 }
233
234 int AccessibilityUIElement::rowCount()
235 {
236     if (!m_element)
237         return 0;
238
239     ASSERT(ATK_IS_TABLE(m_element));
240
241     return atk_table_get_n_rows(ATK_TABLE(m_element));
242 }
243
244 int AccessibilityUIElement::columnCount()
245 {
246     if (!m_element)
247         return 0;
248
249     ASSERT(ATK_IS_TABLE(m_element));
250
251     return atk_table_get_n_columns(ATK_TABLE(m_element));
252 }
253
254 int AccessibilityUIElement::childrenCount()
255 {
256     if (!m_element)
257         return 0;
258
259     ASSERT(ATK_IS_OBJECT(m_element));
260
261     return atk_object_get_n_accessible_children(ATK_OBJECT(m_element));
262 }
263
264 AccessibilityUIElement AccessibilityUIElement::elementAtPoint(int x, int y)
265 {
266     if (!m_element)
267         return 0;
268
269     return AccessibilityUIElement(atk_component_ref_accessible_at_point(ATK_COMPONENT(m_element), x, y, ATK_XY_WINDOW));
270 }
271
272 AccessibilityUIElement AccessibilityUIElement::linkedUIElementAtIndex(unsigned index)
273 {
274     // FIXME: implement
275     return 0;
276 }
277
278 AccessibilityUIElement AccessibilityUIElement::getChildAtIndex(unsigned index)
279 {
280     Vector<AccessibilityUIElement> children;
281     getChildrenWithRange(children, index, index + 1);
282
283     if (children.size() == 1)
284         return children.at(0);
285
286     return 0;
287 }
288
289 unsigned AccessibilityUIElement::indexOfChild(AccessibilityUIElement* element)
290
291     // FIXME: implement
292     return 0;
293 }
294
295 gchar* attributeSetToString(AtkAttributeSet* attributeSet)
296 {
297     GString* str = g_string_new(0);
298     for (GSList* attributes = attributeSet; attributes; attributes = attributes->next) {
299         AtkAttribute* attribute = static_cast<AtkAttribute*>(attributes->data);
300         GOwnPtr<gchar> attributeData(g_strconcat(attribute->name, ":", attribute->value, NULL));
301         g_string_append(str, attributeData.get());
302         if (attributes->next)
303             g_string_append(str, ", ");
304     }
305
306     return g_string_free(str, FALSE);
307 }
308
309 JSStringRef AccessibilityUIElement::allAttributes()
310 {
311     if (!m_element)
312         return JSStringCreateWithCharacters(0, 0);
313
314     ASSERT(ATK_IS_OBJECT(m_element));
315     GOwnPtr<gchar> attributeData(attributeSetToString(atk_object_get_attributes(ATK_OBJECT(m_element))));
316     return JSStringCreateWithUTF8CString(attributeData.get());
317 }
318
319 JSStringRef AccessibilityUIElement::attributesOfLinkedUIElements()
320 {
321     // FIXME: implement
322     return JSStringCreateWithCharacters(0, 0);
323 }
324
325 JSStringRef AccessibilityUIElement::attributesOfDocumentLinks()
326 {
327     // FIXME: implement
328     return JSStringCreateWithCharacters(0, 0);
329 }
330
331 AccessibilityUIElement AccessibilityUIElement::titleUIElement()
332 {
333     if (!m_element)
334         return 0;
335
336     AtkRelationSet* set = atk_object_ref_relation_set(ATK_OBJECT(m_element));
337     if (!set)
338         return 0;
339
340     AtkObject* target = 0;
341     int count = atk_relation_set_get_n_relations(set);
342     for (int i = 0; i < count; i++) {
343         AtkRelation* relation = atk_relation_set_get_relation(set, i);
344         if (atk_relation_get_relation_type(relation) == ATK_RELATION_LABELLED_BY) {
345             GPtrArray* targetList = atk_relation_get_target(relation);
346             if (targetList->len)
347                 target = static_cast<AtkObject*>(g_ptr_array_index(targetList, 0));
348         }
349     }
350
351     g_object_unref(set);
352     return target ? AccessibilityUIElement(target) : 0;
353 }
354
355 AccessibilityUIElement AccessibilityUIElement::parentElement()
356 {
357     if (!m_element)
358         return 0;
359
360     ASSERT(ATK_IS_OBJECT(m_element));
361
362     AtkObject* parent =  atk_object_get_parent(ATK_OBJECT(m_element));
363     return parent ? AccessibilityUIElement(parent) : 0;
364 }
365
366 JSStringRef AccessibilityUIElement::attributesOfChildren()
367 {
368     // FIXME: implement
369     return JSStringCreateWithCharacters(0, 0);
370 }
371
372 JSStringRef AccessibilityUIElement::parameterizedAttributeNames()
373 {
374     // FIXME: implement
375     return JSStringCreateWithCharacters(0, 0);
376 }
377
378 JSStringRef AccessibilityUIElement::role()
379 {
380     AtkRole role = atk_object_get_role(ATK_OBJECT(m_element));
381     if (!role)
382         return JSStringCreateWithCharacters(0, 0);
383
384     String roleString = roleToString(role);
385     return JSStringCreateWithUTF8CString(roleString.utf8().data());
386 }
387
388 JSStringRef AccessibilityUIElement::subrole()
389 {
390     return 0;
391 }
392
393 JSStringRef AccessibilityUIElement::roleDescription()
394 {
395     return 0;
396 }
397
398 JSStringRef AccessibilityUIElement::title()
399 {
400     const gchar* name = atk_object_get_name(ATK_OBJECT(m_element));
401     GOwnPtr<gchar> axTitle(g_strdup_printf("AXTitle: %s", name ? name : ""));
402
403     return JSStringCreateWithUTF8CString(axTitle.get());
404 }
405
406 JSStringRef AccessibilityUIElement::description()
407 {
408     const gchar* description = atk_object_get_description(ATK_OBJECT(m_element));
409
410     if (!description)
411         return JSStringCreateWithCharacters(0, 0);
412
413     GOwnPtr<gchar> axDesc(g_strdup_printf("AXDescription: %s", description));
414
415     return JSStringCreateWithUTF8CString(axDesc.get());
416 }
417
418 JSStringRef AccessibilityUIElement::stringValue()
419 {
420     if (!m_element || !ATK_IS_TEXT(m_element))
421         return JSStringCreateWithCharacters(0, 0);
422
423     gchar* text = atk_text_get_text(ATK_TEXT(m_element), 0, -1);
424     GOwnPtr<gchar> axValue(g_strdup_printf("AXValue: %s", replaceCharactersForResults(text)));
425     g_free(text);
426
427     return JSStringCreateWithUTF8CString(axValue.get());
428 }
429
430 JSStringRef AccessibilityUIElement::language()
431 {
432     if (!m_element)
433         return JSStringCreateWithCharacters(0, 0);
434
435     const gchar* locale = atk_object_get_object_locale(ATK_OBJECT(m_element));
436     if (!locale)
437         return JSStringCreateWithCharacters(0, 0);
438
439     return JSStringCreateWithUTF8CString(g_strdup_printf("AXLanguage: %s", locale));
440 }
441
442 double AccessibilityUIElement::x()
443 {
444     int x, y;
445
446     atk_component_get_position(ATK_COMPONENT(m_element), &x, &y, ATK_XY_SCREEN);
447
448     return x;
449 }
450
451 double AccessibilityUIElement::y()
452 {
453     int x, y;
454
455     atk_component_get_position(ATK_COMPONENT(m_element), &x, &y, ATK_XY_SCREEN);
456
457     return y;
458 }
459
460 double AccessibilityUIElement::width()
461 {
462     int width, height;
463
464     atk_component_get_size(ATK_COMPONENT(m_element), &width, &height);
465
466     return width;
467 }
468
469 double AccessibilityUIElement::height()
470 {
471     int width, height;
472
473     atk_component_get_size(ATK_COMPONENT(m_element), &width, &height);
474
475     return height;
476 }
477
478 double AccessibilityUIElement::clickPointX()
479 {
480     // Note: This is not something we have in ATK.
481     return 0.f;
482 }
483
484 double AccessibilityUIElement::clickPointY()
485 {
486     // Note: This is not something we have in ATK.
487     return 0.f;
488 }
489
490 JSStringRef AccessibilityUIElement::orientation() const
491 {
492     if (!m_element || !ATK_IS_OBJECT(m_element))
493         return JSStringCreateWithCharacters(0, 0);
494
495     const char* axOrientation = 0;
496     if (checkElementState(m_element, ATK_STATE_HORIZONTAL))
497         axOrientation = "AXOrientation: AXHorizontalOrientation";
498     else if (checkElementState(m_element, ATK_STATE_VERTICAL))
499         axOrientation = "AXOrientation: AXVerticalOrientation";
500
501     if (!axOrientation)
502         return JSStringCreateWithCharacters(0, 0);
503
504     return JSStringCreateWithUTF8CString(axOrientation);
505 }
506
507 double AccessibilityUIElement::intValue() const
508 {
509     GValue value = { 0, { { 0 } } };
510
511     if (!ATK_IS_VALUE(m_element))
512         return 0.0f;
513
514     atk_value_get_current_value(ATK_VALUE(m_element), &value);
515     if (!G_VALUE_HOLDS_FLOAT(&value))
516         return 0.0f;
517     return g_value_get_float(&value);
518 }
519
520 double AccessibilityUIElement::minValue()
521 {
522     GValue value = { 0, { { 0 } } };
523
524     if (!ATK_IS_VALUE(m_element))
525         return 0.0f;
526
527     atk_value_get_minimum_value(ATK_VALUE(m_element), &value);
528     if (!G_VALUE_HOLDS_FLOAT(&value))
529         return 0.0f;
530     return g_value_get_float(&value);
531 }
532
533 double AccessibilityUIElement::maxValue()
534 {
535     GValue value = { 0, { { 0 } } };
536
537     if (!ATK_IS_VALUE(m_element))
538         return 0.0f;
539
540     atk_value_get_maximum_value(ATK_VALUE(m_element), &value);
541     if (!G_VALUE_HOLDS_FLOAT(&value))
542         return 0.0f;
543     return g_value_get_float(&value);
544 }
545
546 JSStringRef AccessibilityUIElement::valueDescription()
547 {
548     // FIXME: implement after it has been implemented in ATK.
549     // See: https://bugzilla.gnome.org/show_bug.cgi?id=684576
550     return JSStringCreateWithCharacters(0, 0);
551 }
552
553 bool AccessibilityUIElement::isEnabled()
554 {
555     return checkElementState(m_element, ATK_STATE_ENABLED);
556 }
557
558 int AccessibilityUIElement::insertionPointLineNumber()
559 {
560     // FIXME: implement
561     return 0;
562 }
563
564 bool AccessibilityUIElement::isPressActionSupported()
565 {
566     // FIXME: implement
567     return false;
568 }
569
570 bool AccessibilityUIElement::isIncrementActionSupported()
571 {
572     // FIXME: implement
573     return false;
574 }
575
576 bool AccessibilityUIElement::isDecrementActionSupported()
577 {
578     // FIXME: implement
579     return false;
580 }
581
582 bool AccessibilityUIElement::isRequired() const
583 {
584     // FIXME: implement
585     return false;
586 }
587
588 bool AccessibilityUIElement::isFocused() const
589 {
590     if (!ATK_IS_OBJECT(m_element))
591         return false;
592
593     GRefPtr<AtkStateSet> stateSet = adoptGRef(atk_object_ref_state_set(ATK_OBJECT(m_element)));
594     gboolean isFocused = atk_state_set_contains_state(stateSet.get(), ATK_STATE_FOCUSED);
595
596     return isFocused;
597 }
598
599 bool AccessibilityUIElement::isSelected() const
600 {
601     return checkElementState(m_element, ATK_STATE_SELECTED);
602 }
603
604 int AccessibilityUIElement::hierarchicalLevel() const
605 {
606     // FIXME: implement
607     return 0;
608 }
609
610 bool AccessibilityUIElement::ariaIsGrabbed() const
611 {
612     return false;
613 }
614
615 JSStringRef AccessibilityUIElement::ariaDropEffects() const
616 {   
617     return 0; 
618 }
619
620 bool AccessibilityUIElement::isExpanded() const
621 {
622     if (!ATK_IS_OBJECT(m_element))
623         return false;
624
625     GRefPtr<AtkStateSet> stateSet = adoptGRef(atk_object_ref_state_set(ATK_OBJECT(m_element)));
626     gboolean isExpanded = atk_state_set_contains_state(stateSet.get(), ATK_STATE_EXPANDED);
627
628     return isExpanded;
629 }
630
631 bool AccessibilityUIElement::isChecked() const
632 {
633     if (!ATK_IS_OBJECT(m_element))
634         return false;
635
636     GRefPtr<AtkStateSet> stateSet = adoptGRef(atk_object_ref_state_set(ATK_OBJECT(m_element)));
637     gboolean isChecked = atk_state_set_contains_state(stateSet.get(), ATK_STATE_CHECKED);
638
639     return isChecked;
640 }
641
642 JSStringRef AccessibilityUIElement::attributesOfColumnHeaders()
643 {
644     // FIXME: implement
645     return JSStringCreateWithCharacters(0, 0);
646 }
647
648 JSStringRef AccessibilityUIElement::attributesOfRowHeaders()
649 {
650     // FIXME: implement
651     return JSStringCreateWithCharacters(0, 0);
652 }
653
654 JSStringRef AccessibilityUIElement::attributesOfColumns()
655 {
656     // FIXME: implement
657     return JSStringCreateWithCharacters(0, 0);
658 }
659
660 JSStringRef AccessibilityUIElement::attributesOfRows()
661 {
662     // FIXME: implement
663     return JSStringCreateWithCharacters(0, 0);
664 }
665
666 JSStringRef AccessibilityUIElement::attributesOfVisibleCells()
667 {
668     // FIXME: implement
669     return JSStringCreateWithCharacters(0, 0);
670 }
671
672 JSStringRef AccessibilityUIElement::attributesOfHeader()
673 {
674     // FIXME: implement
675     return JSStringCreateWithCharacters(0, 0);
676 }
677
678 int AccessibilityUIElement::indexInTable()
679 {
680     // FIXME: implement
681     return 0;
682 }
683
684 static JSStringRef indexRangeInTable(PlatformUIElement element, bool isRowRange)
685 {
686     GOwnPtr<gchar> rangeString(g_strdup("{0, 0}"));
687
688     if (!element)
689         return JSStringCreateWithUTF8CString(rangeString.get());
690
691     ASSERT(ATK_IS_OBJECT(element));
692
693     AtkObject* axTable = atk_object_get_parent(ATK_OBJECT(element));
694     if (!axTable || !ATK_IS_TABLE(axTable))
695         return JSStringCreateWithUTF8CString(rangeString.get());
696
697     // Look for the cell in the table.
698     gint indexInParent = atk_object_get_index_in_parent(ATK_OBJECT(element));
699     if (indexInParent == -1)
700         return JSStringCreateWithUTF8CString(rangeString.get());
701
702     int row = -1;
703     int column = -1;
704     row = atk_table_get_row_at_index(ATK_TABLE(axTable), indexInParent);
705     column = atk_table_get_column_at_index(ATK_TABLE(axTable), indexInParent);
706
707     // Get the actual values, if row and columns are valid values.
708     if (row != -1 && column != -1) {
709         int base = 0;
710         int length = 0;
711         if (isRowRange) {
712             base = row;
713             length = atk_table_get_row_extent_at(ATK_TABLE(axTable), row, column);
714         } else {
715             base = column;
716             length = atk_table_get_column_extent_at(ATK_TABLE(axTable), row, column);
717         }
718         rangeString.set(g_strdup_printf("{%d, %d}", base, length));
719     }
720
721     return JSStringCreateWithUTF8CString(rangeString.get());
722 }
723
724 JSStringRef AccessibilityUIElement::rowIndexRange()
725 {
726     // Range in table for rows.
727     return indexRangeInTable(m_element, true);
728 }
729
730 JSStringRef AccessibilityUIElement::columnIndexRange()
731 {
732     // Range in table for columns.
733     return indexRangeInTable(m_element, false);
734 }
735
736 int AccessibilityUIElement::lineForIndex(int)
737 {
738     // FIXME: implement
739     return 0;
740 }
741
742 JSStringRef AccessibilityUIElement::boundsForRange(unsigned location, unsigned length)
743 {
744     // FIXME: implement
745     return JSStringCreateWithCharacters(0, 0);
746 }
747
748 JSStringRef AccessibilityUIElement::stringForRange(unsigned, unsigned) 
749 {
750     // FIXME: implement
751     return JSStringCreateWithCharacters(0, 0);
752
753
754 JSStringRef AccessibilityUIElement::attributedStringForRange(unsigned, unsigned)
755 {
756     // FIXME: implement
757     return JSStringCreateWithCharacters(0, 0);
758 }
759
760 bool AccessibilityUIElement::attributedStringRangeIsMisspelled(unsigned location, unsigned length)
761 {
762     // FIXME: implement
763     return false;
764 }
765
766 AccessibilityUIElement AccessibilityUIElement::uiElementForSearchPredicate(JSContextRef context, AccessibilityUIElement* startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly)
767 {
768     // FIXME: implement
769     return 0;
770 }
771
772 AccessibilityUIElement AccessibilityUIElement::cellForColumnAndRow(unsigned column, unsigned row)
773 {
774     if (!m_element)
775         return 0;
776
777     ASSERT(ATK_IS_TABLE(m_element));
778
779     // Adopt the AtkObject representing the cell because
780     // at_table_ref_at() transfers full ownership.
781     GRefPtr<AtkObject> foundCell = adoptGRef(atk_table_ref_at(ATK_TABLE(m_element), row, column));
782     return foundCell ? AccessibilityUIElement(foundCell.get()) : 0;
783 }
784
785 JSStringRef AccessibilityUIElement::selectedTextRange()
786 {
787     // FIXME: implement
788     return JSStringCreateWithCharacters(0, 0);
789 }
790
791 void AccessibilityUIElement::setSelectedTextRange(unsigned location, unsigned length)
792 {
793     // FIXME: implement
794 }
795
796 JSStringRef AccessibilityUIElement::stringAttributeValue(JSStringRef attribute)
797 {
798     if (!m_element)
799         return JSStringCreateWithCharacters(0, 0);
800
801     String atkAttributeName = coreAttributeToAtkAttribute(attribute);
802     if (atkAttributeName.isEmpty())
803         return JSStringCreateWithCharacters(0, 0);
804
805     for (GSList* atkAttributes = atk_object_get_attributes(ATK_OBJECT(m_element)); atkAttributes; atkAttributes = atkAttributes->next) {
806         AtkAttribute* atkAttribute = static_cast<AtkAttribute*>(atkAttributes->data);
807         if (!strcmp(atkAttribute->name, atkAttributeName.utf8().data()))
808             return JSStringCreateWithUTF8CString(atkAttribute->value);
809     }
810
811     return JSStringCreateWithCharacters(0, 0);
812 }
813
814 double AccessibilityUIElement::numberAttributeValue(JSStringRef attribute)
815 {
816     // FIXME: implement
817     return 0.0f;
818 }
819
820 bool AccessibilityUIElement::boolAttributeValue(JSStringRef attribute)
821 {
822     // FIXME: implement
823     return false;
824 }
825
826 bool AccessibilityUIElement::isAttributeSettable(JSStringRef attribute)
827 {
828     // FIXME: implement
829     return false;
830 }
831
832 bool AccessibilityUIElement::isAttributeSupported(JSStringRef attribute)
833 {
834     return false;
835 }
836
837 static void alterCurrentValue(PlatformUIElement element, int factor)
838 {
839     if (!element)
840         return;
841
842     ASSERT(ATK_IS_VALUE(element));
843
844     GValue currentValue = G_VALUE_INIT;
845     atk_value_get_current_value(ATK_VALUE(element), &currentValue);
846
847     GValue increment = G_VALUE_INIT;
848     atk_value_get_minimum_increment(ATK_VALUE(element), &increment);
849
850     GValue newValue = G_VALUE_INIT;
851     g_value_init(&newValue, G_TYPE_FLOAT);
852
853     g_value_set_float(&newValue, g_value_get_float(&currentValue) + factor * g_value_get_float(&increment));
854     atk_value_set_current_value(ATK_VALUE(element), &newValue);
855
856     g_value_unset(&newValue);
857     g_value_unset(&increment);
858     g_value_unset(&currentValue);
859 }
860
861 void AccessibilityUIElement::increment()
862 {
863     alterCurrentValue(m_element, 1);
864 }
865
866 void AccessibilityUIElement::decrement()
867 {
868     alterCurrentValue(m_element, -1);
869 }
870
871 void AccessibilityUIElement::press()
872 {
873     if (!m_element)
874         return;
875
876     ASSERT(ATK_IS_OBJECT(m_element));
877
878     if (!ATK_IS_ACTION(m_element))
879         return;
880
881     // Only one action per object is supported so far.
882     atk_action_do_action(ATK_ACTION(m_element), 0);
883 }
884
885 void AccessibilityUIElement::showMenu()
886 {
887     // FIXME: implement
888 }
889
890 AccessibilityUIElement AccessibilityUIElement::disclosedRowAtIndex(unsigned index)
891 {
892     return 0;
893 }
894
895 AccessibilityUIElement AccessibilityUIElement::ariaOwnsElementAtIndex(unsigned index)
896 {
897     return 0;
898 }
899
900 AccessibilityUIElement AccessibilityUIElement::ariaFlowToElementAtIndex(unsigned index)
901 {
902     return 0;
903 }
904
905 AccessibilityUIElement AccessibilityUIElement::selectedRowAtIndex(unsigned index)
906 {
907     return 0;
908 }
909
910 AccessibilityUIElement AccessibilityUIElement::rowAtIndex(unsigned index)
911 {
912     return 0;
913 }
914
915 AccessibilityUIElement AccessibilityUIElement::disclosedByRow()
916 {
917     return 0;
918 }
919
920 JSStringRef AccessibilityUIElement::accessibilityValue() const
921 {
922     // FIXME: implement
923     return JSStringCreateWithCharacters(0, 0);
924 }
925
926 JSStringRef AccessibilityUIElement::documentEncoding()
927 {
928     AtkRole role = atk_object_get_role(ATK_OBJECT(m_element));
929     if (role != ATK_ROLE_DOCUMENT_FRAME)
930         return JSStringCreateWithCharacters(0, 0);
931
932     return JSStringCreateWithUTF8CString(atk_document_get_attribute_value(ATK_DOCUMENT(m_element), "Encoding"));
933 }
934
935 JSStringRef AccessibilityUIElement::documentURI()
936 {
937     AtkRole role = atk_object_get_role(ATK_OBJECT(m_element));
938     if (role != ATK_ROLE_DOCUMENT_FRAME)
939         return JSStringCreateWithCharacters(0, 0);
940
941     return JSStringCreateWithUTF8CString(atk_document_get_attribute_value(ATK_DOCUMENT(m_element), "URI"));
942 }
943
944 JSStringRef AccessibilityUIElement::url()
945 {
946     // FIXME: implement
947     return JSStringCreateWithCharacters(0, 0);
948 }
949
950 bool AccessibilityUIElement::addNotificationListener(JSObjectRef functionCallback)
951 {
952     // FIXME: implement
953     return false;
954 }
955
956 void AccessibilityUIElement::removeNotificationListener()
957 {
958     // FIXME: implement
959 }
960
961 bool AccessibilityUIElement::isFocusable() const
962 {
963     if (!ATK_IS_OBJECT(m_element))
964         return false;
965
966     GRefPtr<AtkStateSet> stateSet = adoptGRef(atk_object_ref_state_set(ATK_OBJECT(m_element)));
967     gboolean isFocusable = atk_state_set_contains_state(stateSet.get(), ATK_STATE_FOCUSABLE);
968
969     return isFocusable;
970 }
971
972 bool AccessibilityUIElement::isSelectable() const
973 {
974     return checkElementState(m_element, ATK_STATE_SELECTABLE);
975 }
976
977 bool AccessibilityUIElement::isMultiSelectable() const
978 {
979     return checkElementState(m_element, ATK_STATE_MULTISELECTABLE);
980 }
981
982 bool AccessibilityUIElement::isSelectedOptionActive() const
983 {
984     // FIXME: implement
985     return false;
986 }
987
988 bool AccessibilityUIElement::isVisible() const
989 {
990     // FIXME: implement
991     return false;
992 }
993
994 bool AccessibilityUIElement::isOffScreen() const
995 {
996     // FIXME: implement
997     return false;
998 }
999
1000 bool AccessibilityUIElement::isCollapsed() const
1001 {
1002     // FIXME: implement
1003     return false;
1004 }
1005
1006 bool AccessibilityUIElement::isIgnored() const
1007 {
1008     // FIXME: implement
1009     return false;
1010 }
1011
1012 bool AccessibilityUIElement::hasPopup() const
1013 {
1014     // FIXME: implement
1015     return false;
1016 }
1017
1018 void AccessibilityUIElement::takeFocus()
1019 {
1020     // FIXME: implement
1021 }
1022
1023 void AccessibilityUIElement::takeSelection()
1024 {
1025     // FIXME: implement
1026 }
1027
1028 void AccessibilityUIElement::addSelection()
1029 {
1030     // FIXME: implement
1031 }
1032
1033 void AccessibilityUIElement::removeSelection()
1034 {
1035     // FIXME: implement
1036 }
1037
1038 void AccessibilityUIElement::scrollToMakeVisible()
1039 {
1040     // FIXME: implement
1041 }
1042
1043 void AccessibilityUIElement::scrollToMakeVisibleWithSubFocus(int x, int y, int width, int height)
1044 {
1045     // FIXME: implement
1046 }
1047
1048 void AccessibilityUIElement::scrollToGlobalPoint(int x, int y)
1049 {
1050     // FIXME: implement
1051 }
1052
1053 #endif