blob: 2d52193668bb7f0c9091249b5a0824fdfa18cfda [file] [log] [blame]
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +00001/*
2 * Copyright (C) 2008 Nuanti Ltd.
xan@webkit.orge4387102009-04-09 11:08:48 +00003 * Copyright (C) 2009 Igalia S.L.
4 *
5 * Portions from Mozilla a11y, copyright as follows:
6 *
7 * The Original Code is mozilla.org code.
8 *
9 * The Initial Developer of the Original Code is
10 * Sun Microsystems, Inc.
11 * Portions created by the Initial Developer are Copyright (C) 2002
12 * the Initial Developer. All Rights Reserved.
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +000013 *
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Library General Public
16 * License as published by the Free Software Foundation; either
17 * version 2 of the License, or (at your option) any later version.
18 *
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Library General Public License for more details.
23 *
24 * You should have received a copy of the GNU Library General Public License
25 * along with this library; see the file COPYING.LIB. If not, write to
26 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
27 * Boston, MA 02110-1301, USA.
28 */
29
30#include "config.h"
31#include "AccessibilityObjectWrapperAtk.h"
32
ddkilzer@apple.com8d878632008-11-09 19:50:37 +000033#if HAVE(ACCESSIBILITY)
34
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +000035#include "AXObjectCache.h"
36#include "AccessibilityListBox.h"
37#include "AccessibilityRenderObject.h"
alp@webkit.orgc7738992008-05-27 02:48:14 +000038#include "AtomicString.h"
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +000039#include "CString.h"
alp@webkit.orgc7738992008-05-27 02:48:14 +000040#include "Document.h"
41#include "Editor.h"
42#include "Frame.h"
43#include "FrameView.h"
44#include "IntRect.h"
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +000045#include "NotImplemented.h"
46
47#include <atk/atk.h>
xan@webkit.orge4387102009-04-09 11:08:48 +000048#include <glib.h>
49#include <glib/gprintf.h>
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +000050
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +000051using namespace WebCore;
52
xan@webkit.orgc886cc62009-04-09 11:17:48 +000053static AccessibilityObject* fallbackObject()
54{
55 static AXObjectCache* fallbackCache = new AXObjectCache();
56 static AccessibilityObject* object = 0;
57 if (!object) {
58 // FIXME: using fallbackCache->getOrCreate(ListBoxOptionRole) is a hack
59 object = fallbackCache->getOrCreate(ListBoxOptionRole);
60 object->ref();
61 }
62
63 return object;
64}
65
alp@webkit.orgc7738992008-05-27 02:48:14 +000066// Used to provide const char* returns.
67static const char* returnString(const String& str)
68{
69 static CString returnedString;
70 returnedString = str.utf8();
71 return returnedString.data();
72}
73
74static AccessibilityObject* core(WebKitAccessible* accessible)
75{
76 if (!accessible)
77 return 0;
78
79 return accessible->m_object;
80}
81
82static AccessibilityObject* core(AtkObject* object)
83{
84 if (!WEBKIT_IS_ACCESSIBLE(object))
85 return 0;
86
87 return core(WEBKIT_ACCESSIBLE(object));
88}
89
90static AccessibilityObject* core(AtkAction* action)
91{
92 return core(ATK_OBJECT(action));
93}
94
95static AccessibilityObject* core(AtkStreamableContent* streamable)
96{
97 return core(ATK_OBJECT(streamable));
98}
99
100static AccessibilityObject* core(AtkText* text)
101{
102 return core(ATK_OBJECT(text));
103}
104
105static AccessibilityObject* core(AtkEditableText* text)
106{
107 return core(ATK_OBJECT(text));
108}
109
110extern "C" {
111
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +0000112static const gchar* webkit_accessible_get_name(AtkObject* object)
113{
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +0000114 // TODO: Deal with later changes.
115 if (!object->name)
zecke@webkit.org7f6b1232009-01-30 23:13:59 +0000116 atk_object_set_name(object, core(object)->stringValue().utf8().data());
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +0000117 return object->name;
118}
119
120static const gchar* webkit_accessible_get_description(AtkObject* object)
121{
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +0000122 // TODO: the Mozilla MSAA implementation prepends "Description: "
123 // Should we do this too?
124
125 // TODO: Deal with later changes.
126 if (!object->description)
alp@webkit.orgc7738992008-05-27 02:48:14 +0000127 atk_object_set_description(object, core(object)->accessibilityDescription().utf8().data());
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +0000128 return object->description;
129}
130
alp@webkit.orgc7738992008-05-27 02:48:14 +0000131static AtkObject* webkit_accessible_get_parent(AtkObject* object)
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +0000132{
alp@webkit.orgc7738992008-05-27 02:48:14 +0000133 AccessibilityObject* coreParent = core(object)->parentObject();
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +0000134
135 if (!coreParent)
136 return NULL;
137
138 return coreParent->wrapper();
139}
140
141static gint webkit_accessible_get_n_children(AtkObject* object)
142{
alp@webkit.orgc7738992008-05-27 02:48:14 +0000143 return core(object)->children().size();
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +0000144}
145
146static AtkObject* webkit_accessible_ref_child(AtkObject* object, gint index)
147{
alp@webkit.orgc7738992008-05-27 02:48:14 +0000148 AccessibilityObject* coreObject = core(object);
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +0000149
150 g_return_val_if_fail(index >= 0, NULL);
alp@webkit.org369cdca2008-09-06 04:08:30 +0000151 g_return_val_if_fail(static_cast<size_t>(index) < coreObject->children().size(), NULL);
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +0000152
153 AccessibilityObject* coreChild = coreObject->children().at(index).get();
154
155 if (!coreChild)
156 return NULL;
157
158 AtkObject* child = coreChild->wrapper();
alp@webkit.orgc7738992008-05-27 02:48:14 +0000159 // TODO: Should we call atk_object_set_parent() here?
160 //atk_object_set_parent(child, object);
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +0000161 g_object_ref(child);
162
163 return child;
164}
165
166static gint webkit_accessible_get_index_in_parent(AtkObject* object)
167{
168 // FIXME: This needs to be implemented.
169 notImplemented();
170 return 0;
171}
172
173static AtkRole atkRole(AccessibilityRole role)
174{
175 switch (role) {
176 case WebCore::ButtonRole:
177 return ATK_ROLE_PUSH_BUTTON;
178 case WebCore::RadioButtonRole:
179 return ATK_ROLE_RADIO_BUTTON;
180 case WebCore::CheckBoxRole:
181 return ATK_ROLE_CHECK_BOX;
182 case WebCore::SliderRole:
183 return ATK_ROLE_SLIDER;
184 case WebCore::TabGroupRole:
185 return ATK_ROLE_PAGE_TAB_LIST;
186 case WebCore::TextFieldRole:
187 case WebCore::TextAreaRole:
188 case WebCore::ListMarkerRole:
189 return ATK_ROLE_ENTRY;
190 case WebCore::StaticTextRole:
191 return ATK_ROLE_TEXT; //?
192 case WebCore::OutlineRole:
193 return ATK_ROLE_TREE;
194 case WebCore::ColumnRole:
195 return ATK_ROLE_UNKNOWN; //?
196 case WebCore::RowRole:
197 return ATK_ROLE_LIST_ITEM;
198 case WebCore::GroupRole:
199 return ATK_ROLE_UNKNOWN; //?
200 case WebCore::ListRole:
201 return ATK_ROLE_LIST;
202 case WebCore::TableRole:
203 return ATK_ROLE_TABLE;
204 case WebCore::LinkRole:
205 case WebCore::WebCoreLinkRole:
206 return ATK_ROLE_LINK;
207 case WebCore::ImageMapRole:
208 case WebCore::ImageRole:
209 return ATK_ROLE_IMAGE;
210 default:
211 return ATK_ROLE_UNKNOWN;
212 }
213}
214
alp@webkit.orgc7738992008-05-27 02:48:14 +0000215static AtkRole webkit_accessible_get_role(AtkObject* object)
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +0000216{
alp@webkit.orgc7738992008-05-27 02:48:14 +0000217 return atkRole(core(object)->roleValue());
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +0000218}
219
xan@webkit.orge4387102009-04-09 11:08:48 +0000220static gpointer webkit_accessible_parent_class = NULL;
221
222static void webkit_accessible_init(AtkObject* object, gpointer data)
223{
224 g_return_if_fail(WEBKIT_IS_ACCESSIBLE(object));
225 g_return_if_fail(data);
226
227 if (ATK_OBJECT_CLASS(webkit_accessible_parent_class)->initialize)
228 ATK_OBJECT_CLASS(webkit_accessible_parent_class)->initialize(object, data);
229
230 WEBKIT_ACCESSIBLE(object)->m_object = reinterpret_cast<AccessibilityObject*>(data);
231}
232
233static void webkit_accessible_finalize(GObject* object)
234{
235 // This is a good time to clear the return buffer.
236 returnString(String());
237
238 if (G_OBJECT_CLASS(webkit_accessible_parent_class)->finalize)
239 G_OBJECT_CLASS(webkit_accessible_parent_class)->finalize(object);
240}
241
alp@webkit.orgc7738992008-05-27 02:48:14 +0000242static void webkit_accessible_class_init(AtkObjectClass* klass)
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +0000243{
xan@webkit.orge4387102009-04-09 11:08:48 +0000244 GObjectClass* gobjectClass = G_OBJECT_CLASS(klass);
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +0000245
xan@webkit.orge4387102009-04-09 11:08:48 +0000246 webkit_accessible_parent_class = g_type_class_peek_parent(klass);
247
248 gobjectClass->finalize = webkit_accessible_finalize;
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +0000249
alp@webkit.orgc7738992008-05-27 02:48:14 +0000250 klass->initialize = webkit_accessible_init;
alp@webkit.orgc7738992008-05-27 02:48:14 +0000251 klass->get_name = webkit_accessible_get_name;
252 klass->get_description = webkit_accessible_get_description;
253 klass->get_parent = webkit_accessible_get_parent;
254 klass->get_n_children = webkit_accessible_get_n_children;
255 klass->ref_child = webkit_accessible_ref_child;
alp@webkit.orgc7738992008-05-27 02:48:14 +0000256 klass->get_role = webkit_accessible_get_role;
xan@webkit.orge4387102009-04-09 11:08:48 +0000257}
258
259GType
260webkit_accessible_get_type(void)
261{
262 static volatile gsize type_volatile = 0;
263
264 if (g_once_init_enter(&type_volatile)) {
265 static const GTypeInfo tinfo = {
266 sizeof(WebKitAccessibleClass),
267 (GBaseInitFunc)NULL,
268 (GBaseFinalizeFunc)NULL,
269 (GClassInitFunc)webkit_accessible_class_init,
270 (GClassFinalizeFunc)NULL,
271 NULL, /* class data */
272 sizeof(WebKitAccessible), /* instance size */
273 0, /* nb preallocs */
274 (GInstanceInitFunc)NULL,
275 NULL /* value table */
276 };
277
278 GType type = g_type_register_static(ATK_TYPE_OBJECT,
279 "WebKitAccessible", &tinfo, GTypeFlags(0));
280 g_once_init_leave(&type_volatile, type);
281 }
282
283 return type_volatile;
alp@webkit.orgc7738992008-05-27 02:48:14 +0000284}
285
286static gboolean webkit_accessible_action_do_action(AtkAction* action, gint i)
287{
288 g_return_val_if_fail(i == 0, FALSE);
289 return core(action)->performDefaultAction();
290}
291
292static gint webkit_accessible_action_get_n_actions(AtkAction* action)
293{
294 return 1;
295}
296
297static const gchar* webkit_accessible_action_get_description(AtkAction* action, gint i)
298{
299 g_return_val_if_fail(i == 0, NULL);
300 // TODO: Need a way to provide/localize action descriptions.
301 notImplemented();
302 return "";
303}
304
305static const gchar* webkit_accessible_action_get_keybinding(AtkAction* action, gint i)
306{
307 g_return_val_if_fail(i == 0, NULL);
308 // FIXME: Construct a proper keybinding string.
309 return returnString(core(action)->accessKey().string());
310}
311
312static const gchar* webkit_accessible_action_get_name(AtkAction* action, gint i)
313{
314 g_return_val_if_fail(i == 0, NULL);
315 return returnString(core(action)->actionVerb());
316}
317
318static void atk_action_interface_init(AtkActionIface* iface)
319{
320 g_return_if_fail(iface);
321
322 iface->do_action = webkit_accessible_action_do_action;
323 iface->get_n_actions = webkit_accessible_action_get_n_actions;
324 iface->get_description = webkit_accessible_action_get_description;
325 iface->get_keybinding = webkit_accessible_action_get_keybinding;
326 iface->get_name = webkit_accessible_action_get_name;
327}
328
329// Text
330
331static gchar* webkit_accessible_text_get_text(AtkText* text, gint start_offset, gint end_offset)
332{
333 String ret = core(text)->doAXStringForRange(PlainTextRange(start_offset, end_offset - start_offset));
334 // TODO: Intentionally copied?
335 return g_strdup(ret.utf8().data());
336}
337
338static gchar* webkit_accessible_text_get_text_after_offset(AtkText* text, gint offset, AtkTextBoundary boundary_type, gint* start_offset, gint* end_offset)
339{
340 notImplemented();
341 return NULL;
342}
343
344static gchar* webkit_accessible_text_get_text_at_offset(AtkText* text, gint offset, AtkTextBoundary boundary_type, gint* start_offset, gint* end_offset)
345{
346 notImplemented();
347 return NULL;
348}
349
350static gunichar webkit_accessible_text_get_character_at_offset(AtkText* text, gint offset)
351{
352 notImplemented();
353 return 0;
354}
355
356static gchar* webkit_accessible_text_get_text_before_offset(AtkText* text, gint offset, AtkTextBoundary boundary_type, gint* start_offset, gint* end_offset)
357{
358 notImplemented();
359 return NULL;
360}
361
362static gint webkit_accessible_text_get_caret_offset(AtkText* text)
363{
364 // TODO: Verify this, especially for RTL text.
365 return core(text)->selectionStart();
366}
367
368static AtkAttributeSet* webkit_accessible_text_get_run_attributes(AtkText* text, gint offset, gint* start_offset, gint* end_offset)
369{
370 notImplemented();
371 return NULL;
372}
373
374static AtkAttributeSet* webkit_accessible_text_get_default_attributes(AtkText* text)
375{
376 notImplemented();
377 return NULL;
378}
379
380static void webkit_accessible_text_get_character_extents(AtkText* text, gint offset, gint* x, gint* y, gint* width, gint* height, AtkCoordType coords)
381{
382 IntRect extents = core(text)->doAXBoundsForRange(PlainTextRange(offset, 1));
383 // FIXME: Use the AtkCoordType
384 // Requires WebCore::ScrollView::contentsToScreen() to be implemented
385
386#if 0
387 switch(coords) {
388 case ATK_XY_SCREEN:
389 extents = core(text)->document()->view()->contentsToScreen(extents);
390 break;
391 case ATK_XY_WINDOW:
392 // No-op
393 break;
394 }
395#endif
396
397 *x = extents.x();
398 *y = extents.y();
399 *width = extents.width();
400 *height = extents.height();
401}
402
403static gint webkit_accessible_text_get_character_count(AtkText* text)
404{
405 return core(text)->textLength();
406}
407
408static gint webkit_accessible_text_get_offset_at_point(AtkText* text, gint x, gint y, AtkCoordType coords)
409{
410 // FIXME: Use the AtkCoordType
411 // TODO: Is it correct to ignore range.length?
412 IntPoint pos(x, y);
413 PlainTextRange range = core(text)->doAXRangeForPosition(pos);
414 return range.start;
415}
416
417static gint webkit_accessible_text_get_n_selections(AtkText* text)
418{
419 notImplemented();
420 return 0;
421}
422
423static gchar* webkit_accessible_text_get_selection(AtkText* text, gint selection_num, gint* start_offset, gint* end_offset)
424{
425 notImplemented();
426 return NULL;
427}
428
429static gboolean webkit_accessible_text_add_selection(AtkText* text, gint start_offset, gint end_offset)
430{
431 notImplemented();
432 return FALSE;
433}
434
435static gboolean webkit_accessible_text_remove_selection(AtkText* text, gint selection_num)
436{
437 notImplemented();
438 return FALSE;
439}
440
441static gboolean webkit_accessible_text_set_selection(AtkText* text, gint selection_num, gint start_offset, gint end_offset)
442{
443 notImplemented();
444 return FALSE;
445}
446
447static gboolean webkit_accessible_text_set_caret_offset(AtkText* text, gint offset)
448{
449 // TODO: Verify
450 //core(text)->setSelectedTextRange(PlainTextRange(offset, 0));
451 AccessibilityObject* coreObject = core(text);
christian@webkit.orgade6c5e2008-06-18 09:54:25 +0000452 coreObject->setSelectedVisiblePositionRange(coreObject->visiblePositionRangeForRange(PlainTextRange(offset, 0)));
alp@webkit.orgc7738992008-05-27 02:48:14 +0000453 return TRUE;
454}
455
456#if 0
457// Signal handlers
458static void webkit_accessible_text_text_changed(AtkText* text, gint position, gint length)
459{
460}
461
462static void webkit_accessible_text_text_caret_moved(AtkText* text, gint location)
463{
464}
465
466static void webkit_accessible_text_text_selection_changed(AtkText* text)
467{
468}
469
470static void webkit_accessible_text_text_attributes_changed(AtkText* text)
471{
472}
473
474static void webkit_accessible_text_get_range_extents(AtkText* text, gint start_offset, gint end_offset, AtkCoordType coord_type, AtkTextRectangle* rect)
475{
476}
477
478static AtkTextRange** webkit_accessible_text_get_bounded_ranges(AtkText* text, AtkTextRectangle* rect, AtkCoordType coord_type, AtkTextClipType x_clip_type, AtkTextClipType y_clip_type)
479{
480}
481#endif
482
483static void atk_text_interface_init(AtkTextIface* iface)
484{
485 g_return_if_fail(iface);
486
487 iface->get_text = webkit_accessible_text_get_text;
488 iface->get_text_after_offset = webkit_accessible_text_get_text_after_offset;
489 iface->get_text_at_offset = webkit_accessible_text_get_text_at_offset;
490 iface->get_character_at_offset = webkit_accessible_text_get_character_at_offset;
491 iface->get_text_before_offset = webkit_accessible_text_get_text_before_offset;
492 iface->get_caret_offset = webkit_accessible_text_get_caret_offset;
493 iface->get_run_attributes = webkit_accessible_text_get_run_attributes;
494 iface->get_default_attributes = webkit_accessible_text_get_default_attributes;
495 iface->get_character_extents = webkit_accessible_text_get_character_extents;
496 //iface->get_range_extents = ;
497 iface->get_character_count = webkit_accessible_text_get_character_count;
498 iface->get_offset_at_point = webkit_accessible_text_get_offset_at_point;
499 iface->get_n_selections = webkit_accessible_text_get_n_selections;
500 iface->get_selection = webkit_accessible_text_get_selection;
501
502 // set methods
503 iface->add_selection = webkit_accessible_text_add_selection;
504 iface->remove_selection = webkit_accessible_text_remove_selection;
505 iface->set_selection = webkit_accessible_text_set_selection;
506 iface->set_caret_offset = webkit_accessible_text_set_caret_offset;
507}
508
509// EditableText
510
511static gboolean webkit_accessible_editable_text_set_run_attributes(AtkEditableText* text, AtkAttributeSet* attrib_set, gint start_offset, gint end_offset)
512{
513 notImplemented();
514 return FALSE;
515}
516
517static void webkit_accessible_editable_text_set_text_contents(AtkEditableText* text, const gchar* string)
518{
519 // FIXME: string nullcheck?
520 core(text)->setValue(String::fromUTF8(string));
521}
522
523static void webkit_accessible_editable_text_insert_text(AtkEditableText* text, const gchar* string, gint length, gint* position)
524{
525 // FIXME: string nullcheck?
526
527 AccessibilityObject* coreObject = core(text);
528 // FIXME: Not implemented in WebCore
529 //coreObject->setSelectedTextRange(PlainTextRange(*position, 0));
530 //coreObject->setSelectedText(String::fromUTF8(string));
531
532 if (!coreObject->document() || !coreObject->document()->frame())
533 return;
christian@webkit.orgade6c5e2008-06-18 09:54:25 +0000534 coreObject->setSelectedVisiblePositionRange(coreObject->visiblePositionRangeForRange(PlainTextRange(*position, 0)));
alp@webkit.orgc7738992008-05-27 02:48:14 +0000535 coreObject->setFocused(true);
536 // FIXME: We should set position to the actual inserted text length, which may be less than that requested.
537 if (coreObject->document()->frame()->editor()->insertTextWithoutSendingTextEvent(String::fromUTF8(string), false, 0))
538 *position += length;
539}
540
541static void webkit_accessible_editable_text_copy_text(AtkEditableText* text, gint start_pos, gint end_pos)
542{
543 notImplemented();
544}
545
546static void webkit_accessible_editable_text_cut_text(AtkEditableText* text, gint start_pos, gint end_pos)
547{
548 notImplemented();
549}
550
551static void webkit_accessible_editable_text_delete_text(AtkEditableText* text, gint start_pos, gint end_pos)
552{
553 AccessibilityObject* coreObject = core(text);
554 // FIXME: Not implemented in WebCore
555 //coreObject->setSelectedTextRange(PlainTextRange(start_pos, end_pos - start_pos));
556 //coreObject->setSelectedText(String());
557
558 if (!coreObject->document() || !coreObject->document()->frame())
559 return;
christian@webkit.orgade6c5e2008-06-18 09:54:25 +0000560 coreObject->setSelectedVisiblePositionRange(coreObject->visiblePositionRangeForRange(PlainTextRange(start_pos, end_pos - start_pos)));
alp@webkit.orgc7738992008-05-27 02:48:14 +0000561 coreObject->setFocused(true);
562 coreObject->document()->frame()->editor()->performDelete();
563}
564
565static void webkit_accessible_editable_text_paste_text(AtkEditableText* text, gint position)
566{
567 notImplemented();
568}
569
570static void atk_editable_text_interface_init(AtkEditableTextIface* iface)
571{
572 g_return_if_fail(iface);
573
574 iface->set_run_attributes = webkit_accessible_editable_text_set_run_attributes;
575 iface->set_text_contents = webkit_accessible_editable_text_set_text_contents;
576 iface->insert_text = webkit_accessible_editable_text_insert_text;
577 iface->copy_text = webkit_accessible_editable_text_copy_text;
578 iface->cut_text = webkit_accessible_editable_text_cut_text;
579 iface->delete_text = webkit_accessible_editable_text_delete_text;
580 iface->paste_text = webkit_accessible_editable_text_paste_text;
581}
582
583// StreamableContent
584
585static gint webkit_accessible_streamable_content_get_n_mime_types(AtkStreamableContent* streamable)
586{
587 notImplemented();
588 return 0;
589}
590
591static G_CONST_RETURN gchar* webkit_accessible_streamable_content_get_mime_type(AtkStreamableContent* streamable, gint i)
592{
593 notImplemented();
594 return "";
595}
596
597static GIOChannel* webkit_accessible_streamable_content_get_stream(AtkStreamableContent* streamable, const gchar* mime_type)
598{
599 notImplemented();
600 return NULL;
601}
602
603static G_CONST_RETURN gchar* webkit_accessible_streamable_content_get_uri(AtkStreamableContent* streamable, const gchar* mime_type)
604{
605 notImplemented();
606 return NULL;
607}
608
609static void atk_streamable_content_interface_init(AtkStreamableContentIface* iface)
610{
611 g_return_if_fail(iface);
612
613 iface->get_n_mime_types = webkit_accessible_streamable_content_get_n_mime_types;
614 iface->get_mime_type = webkit_accessible_streamable_content_get_mime_type;
615 iface->get_stream = webkit_accessible_streamable_content_get_stream;
616 iface->get_uri = webkit_accessible_streamable_content_get_uri;
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +0000617}
618
xan@webkit.orge4387102009-04-09 11:08:48 +0000619static const GInterfaceInfo AtkInterfacesInitFunctions[] = {
620 {(GInterfaceInitFunc)atk_action_interface_init,
621 (GInterfaceFinalizeFunc) NULL, NULL},
622 {(GInterfaceInitFunc)atk_streamable_content_interface_init,
623 (GInterfaceFinalizeFunc) NULL, NULL},
624 {(GInterfaceInitFunc)atk_editable_text_interface_init,
625 (GInterfaceFinalizeFunc) NULL, NULL},
626 {(GInterfaceInitFunc)atk_text_interface_init,
627 (GInterfaceFinalizeFunc) NULL, NULL}
628};
629
630enum WAIType {
631 WAI_ACTION,
632 WAI_STREAMABLE,
633 WAI_EDITABLE_TEXT,
634 WAI_TEXT
635};
636
637static GType GetAtkInterfaceTypeFromWAIType(WAIType type)
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +0000638{
xan@webkit.orge4387102009-04-09 11:08:48 +0000639 switch (type) {
640 case WAI_ACTION:
641 return ATK_TYPE_ACTION;
642 case WAI_STREAMABLE:
643 return ATK_TYPE_STREAMABLE_CONTENT;
644 case WAI_EDITABLE_TEXT:
645 return ATK_TYPE_EDITABLE_TEXT;
646 case WAI_TEXT:
647 return ATK_TYPE_TEXT;
648 }
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +0000649
xan@webkit.orge4387102009-04-09 11:08:48 +0000650 return G_TYPE_INVALID;
651}
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +0000652
xan@webkit.orge4387102009-04-09 11:08:48 +0000653static guint16 getInterfaceMaskFromObject(AccessibilityObject* coreObject)
654{
655 guint16 interfaceMask = 0;
alp@webkit.orgc7738992008-05-27 02:48:14 +0000656
xan@webkit.orge4387102009-04-09 11:08:48 +0000657 // Action and Streamable are always supported (FIXME: Should they?)
658 interfaceMask |= 1 << WAI_ACTION;
659 interfaceMask |= 1 << WAI_STREAMABLE;
alp@webkit.orgc7738992008-05-27 02:48:14 +0000660
xan@webkit.orge4387102009-04-09 11:08:48 +0000661 // Text & Editable Text
662 if (coreObject->isAccessibilityRenderObject() && coreObject->isTextControl()) {
663 if (coreObject->isReadOnly())
664 interfaceMask |= 1 << WAI_TEXT;
665 else
666 interfaceMask |= 1 << WAI_EDITABLE_TEXT;
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +0000667 }
xan@webkit.orge4387102009-04-09 11:08:48 +0000668
669 return interfaceMask;
670}
671
672static const char* getUniqueAccessibilityTypeName(guint16 interfaceMask)
673{
674#define WAI_TYPE_NAME_LEN (30) /* Enough for prefix + 5 hex characters (max) */
675 static char name[WAI_TYPE_NAME_LEN + 1];
676
677 g_sprintf(name, "WAIType%x", interfaceMask);
678 name[WAI_TYPE_NAME_LEN] = '\0';
679
680 return name;
681}
682
683static GType getAccessibilityTypeFromObject(AccessibilityObject* coreObject)
684{
685 static const GTypeInfo typeInfo = {
686 sizeof(WebKitAccessibleClass),
687 (GBaseInitFunc) NULL,
688 (GBaseFinalizeFunc) NULL,
689 (GClassInitFunc) NULL,
690 (GClassFinalizeFunc) NULL,
691 NULL, /* class data */
692 sizeof(WebKitAccessible), /* instance size */
693 0, /* nb preallocs */
694 (GInstanceInitFunc) NULL,
695 NULL /* value table */
696 };
697
698 guint16 interfaceMask = getInterfaceMaskFromObject(coreObject);
699 const char* atkTypeName = getUniqueAccessibilityTypeName(interfaceMask);
700 GType type = g_type_from_name(atkTypeName);
701 if (type)
702 return type;
703
704 type = g_type_register_static(WEBKIT_TYPE_ACCESSIBLE,
705 atkTypeName,
706 &typeInfo, GTypeFlags(0));
707 for (guint i = 0; i < G_N_ELEMENTS(AtkInterfacesInitFunctions); i++) {
708 if (interfaceMask & (1 << i))
709 g_type_add_interface_static(type,
710 GetAtkInterfaceTypeFromWAIType(static_cast<WAIType>(i)),
711 &AtkInterfacesInitFunctions[i]);
712 }
713
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +0000714 return type;
715}
716
717WebKitAccessible* webkit_accessible_new(AccessibilityObject* coreObject)
718{
xan@webkit.orge4387102009-04-09 11:08:48 +0000719 GType type = getAccessibilityTypeFromObject(coreObject);
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +0000720 AtkObject* object = static_cast<AtkObject*>(g_object_new(type, NULL));
xan@webkit.orge4387102009-04-09 11:08:48 +0000721
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +0000722 atk_object_initialize(object, coreObject);
xan@webkit.orge4387102009-04-09 11:08:48 +0000723
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +0000724 return WEBKIT_ACCESSIBLE(object);
725}
726
727AccessibilityObject* webkit_accessible_get_accessibility_object(WebKitAccessible* accessible)
728{
729 return accessible->m_object;
730}
731
732void webkit_accessible_detach(WebKitAccessible* accessible)
733{
alp@webkit.orgc7738992008-05-27 02:48:14 +0000734 ASSERT(accessible->m_object);
735
736 // We replace the WebCore AccessibilityObject with a fallback object that
737 // provides default implementations to avoid repetitive null-checking after
738 // detachment.
xan@webkit.orgc886cc62009-04-09 11:17:48 +0000739 accessible->m_object = fallbackObject();
alp@webkit.org3a5e7ca2008-05-20 01:12:20 +0000740}
741
742}
743
ddkilzer@apple.com8d878632008-11-09 19:50:37 +0000744#endif // HAVE(ACCESSIBILITY)