Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=2 et sw=2 tw=80: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #include "AccessibleWrap.h"
8 :
9 : #include "Accessible-inl.h"
10 : #include "ApplicationAccessibleWrap.h"
11 : #include "InterfaceInitFuncs.h"
12 : #include "nsAccUtils.h"
13 : #include "mozilla/a11y/PDocAccessible.h"
14 : #include "OuterDocAccessible.h"
15 : #include "ProxyAccessible.h"
16 : #include "DocAccessibleParent.h"
17 : #include "RootAccessible.h"
18 : #include "TableAccessible.h"
19 : #include "TableCellAccessible.h"
20 : #include "nsMai.h"
21 : #include "nsMaiHyperlink.h"
22 : #include "nsString.h"
23 : #include "nsStateMap.h"
24 : #include "mozilla/a11y/Platform.h"
25 : #include "Relation.h"
26 : #include "RootAccessible.h"
27 : #include "States.h"
28 : #include "nsISimpleEnumerator.h"
29 :
30 : #include "mozilla/ArrayUtils.h"
31 : #include "mozilla/Sprintf.h"
32 : #include "nsComponentManagerUtils.h"
33 : #include "nsIPersistentProperties2.h"
34 :
35 : using namespace mozilla;
36 : using namespace mozilla::a11y;
37 :
38 : MaiAtkObject::EAvailableAtkSignals MaiAtkObject::gAvailableAtkSignals =
39 : eUnknown;
40 :
41 : //defined in ApplicationAccessibleWrap.cpp
42 : extern "C" GType g_atk_hyperlink_impl_type;
43 :
44 : /* MaiAtkObject */
45 :
46 : enum {
47 : ACTIVATE,
48 : CREATE,
49 : DEACTIVATE,
50 : DESTROY,
51 : MAXIMIZE,
52 : MINIMIZE,
53 : RESIZE,
54 : RESTORE,
55 : LAST_SIGNAL
56 : };
57 :
58 : enum MaiInterfaceType {
59 : MAI_INTERFACE_COMPONENT, /* 0 */
60 : MAI_INTERFACE_ACTION,
61 : MAI_INTERFACE_VALUE,
62 : MAI_INTERFACE_EDITABLE_TEXT,
63 : MAI_INTERFACE_HYPERTEXT,
64 : MAI_INTERFACE_HYPERLINK_IMPL,
65 : MAI_INTERFACE_SELECTION,
66 : MAI_INTERFACE_TABLE,
67 : MAI_INTERFACE_TEXT,
68 : MAI_INTERFACE_DOCUMENT,
69 : MAI_INTERFACE_IMAGE, /* 10 */
70 : MAI_INTERFACE_TABLE_CELL
71 : };
72 :
73 0 : static GType GetAtkTypeForMai(MaiInterfaceType type)
74 : {
75 0 : switch (type) {
76 : case MAI_INTERFACE_COMPONENT:
77 0 : return ATK_TYPE_COMPONENT;
78 : case MAI_INTERFACE_ACTION:
79 0 : return ATK_TYPE_ACTION;
80 : case MAI_INTERFACE_VALUE:
81 0 : return ATK_TYPE_VALUE;
82 : case MAI_INTERFACE_EDITABLE_TEXT:
83 0 : return ATK_TYPE_EDITABLE_TEXT;
84 : case MAI_INTERFACE_HYPERTEXT:
85 0 : return ATK_TYPE_HYPERTEXT;
86 : case MAI_INTERFACE_HYPERLINK_IMPL:
87 0 : return g_atk_hyperlink_impl_type;
88 : case MAI_INTERFACE_SELECTION:
89 0 : return ATK_TYPE_SELECTION;
90 : case MAI_INTERFACE_TABLE:
91 0 : return ATK_TYPE_TABLE;
92 : case MAI_INTERFACE_TEXT:
93 0 : return ATK_TYPE_TEXT;
94 : case MAI_INTERFACE_DOCUMENT:
95 0 : return ATK_TYPE_DOCUMENT;
96 : case MAI_INTERFACE_IMAGE:
97 0 : return ATK_TYPE_IMAGE;
98 : case MAI_INTERFACE_TABLE_CELL:
99 0 : MOZ_ASSERT(false);
100 : }
101 0 : return G_TYPE_INVALID;
102 : }
103 :
104 : #define NON_USER_EVENT ":system"
105 :
106 : // The atk interfaces we can expose without checking what version of ATK we are
107 : // dealing with. At the moment AtkTableCell is the only interface we can't
108 : // always expose.
109 : static const GInterfaceInfo atk_if_infos[] = {
110 : {(GInterfaceInitFunc)componentInterfaceInitCB,
111 : (GInterfaceFinalizeFunc) nullptr, nullptr},
112 : {(GInterfaceInitFunc)actionInterfaceInitCB,
113 : (GInterfaceFinalizeFunc) nullptr, nullptr},
114 : {(GInterfaceInitFunc)valueInterfaceInitCB,
115 : (GInterfaceFinalizeFunc) nullptr, nullptr},
116 : {(GInterfaceInitFunc)editableTextInterfaceInitCB,
117 : (GInterfaceFinalizeFunc) nullptr, nullptr},
118 : {(GInterfaceInitFunc)hypertextInterfaceInitCB,
119 : (GInterfaceFinalizeFunc) nullptr, nullptr},
120 : {(GInterfaceInitFunc)hyperlinkImplInterfaceInitCB,
121 : (GInterfaceFinalizeFunc) nullptr, nullptr},
122 : {(GInterfaceInitFunc)selectionInterfaceInitCB,
123 : (GInterfaceFinalizeFunc) nullptr, nullptr},
124 : {(GInterfaceInitFunc)tableInterfaceInitCB,
125 : (GInterfaceFinalizeFunc) nullptr, nullptr},
126 : {(GInterfaceInitFunc)textInterfaceInitCB,
127 : (GInterfaceFinalizeFunc) nullptr, nullptr},
128 : {(GInterfaceInitFunc)documentInterfaceInitCB,
129 : (GInterfaceFinalizeFunc) nullptr, nullptr},
130 : {(GInterfaceInitFunc)imageInterfaceInitCB,
131 : (GInterfaceFinalizeFunc) nullptr, nullptr}
132 : };
133 :
134 : static GQuark quark_mai_hyperlink = 0;
135 :
136 : AtkHyperlink*
137 0 : MaiAtkObject::GetAtkHyperlink()
138 : {
139 0 : NS_ASSERTION(quark_mai_hyperlink, "quark_mai_hyperlink not initialized");
140 : MaiHyperlink* maiHyperlink =
141 0 : (MaiHyperlink*)g_object_get_qdata(G_OBJECT(this), quark_mai_hyperlink);
142 0 : if (!maiHyperlink) {
143 0 : maiHyperlink = new MaiHyperlink(accWrap);
144 0 : g_object_set_qdata(G_OBJECT(this), quark_mai_hyperlink, maiHyperlink);
145 : }
146 :
147 0 : return maiHyperlink->GetAtkHyperlink();
148 : }
149 :
150 : void
151 0 : MaiAtkObject::Shutdown()
152 : {
153 0 : accWrap.SetBits(0);
154 : MaiHyperlink* maiHyperlink =
155 0 : (MaiHyperlink*)g_object_get_qdata(G_OBJECT(this), quark_mai_hyperlink);
156 0 : if (maiHyperlink) {
157 0 : delete maiHyperlink;
158 0 : g_object_set_qdata(G_OBJECT(this), quark_mai_hyperlink, nullptr);
159 : }
160 0 : }
161 :
162 : struct MaiAtkObjectClass
163 : {
164 : AtkObjectClass parent_class;
165 : };
166 :
167 : static guint mai_atk_object_signals [LAST_SIGNAL] = { 0, };
168 :
169 : static void MaybeFireNameChange(AtkObject* aAtkObj, const nsString& aNewName);
170 :
171 : G_BEGIN_DECLS
172 : /* callbacks for MaiAtkObject */
173 : static void classInitCB(AtkObjectClass *aClass);
174 : static void initializeCB(AtkObject *aAtkObj, gpointer aData);
175 : static void finalizeCB(GObject *aObj);
176 :
177 : /* callbacks for AtkObject virtual functions */
178 : static const gchar* getNameCB (AtkObject *aAtkObj);
179 : /* getDescriptionCB is also used by image interface */
180 : const gchar* getDescriptionCB (AtkObject *aAtkObj);
181 : static AtkRole getRoleCB(AtkObject *aAtkObj);
182 : static AtkAttributeSet* getAttributesCB(AtkObject *aAtkObj);
183 : static const gchar* GetLocaleCB(AtkObject*);
184 : static AtkObject* getParentCB(AtkObject *aAtkObj);
185 : static gint getChildCountCB(AtkObject *aAtkObj);
186 : static AtkObject* refChildCB(AtkObject *aAtkObj, gint aChildIndex);
187 : static gint getIndexInParentCB(AtkObject *aAtkObj);
188 : static AtkStateSet* refStateSetCB(AtkObject *aAtkObj);
189 : static AtkRelationSet* refRelationSetCB(AtkObject *aAtkObj);
190 :
191 : /* the missing atkobject virtual functions */
192 : /*
193 : static AtkLayer getLayerCB(AtkObject *aAtkObj);
194 : static gint getMdiZorderCB(AtkObject *aAtkObj);
195 : static void SetNameCB(AtkObject *aAtkObj,
196 : const gchar *name);
197 : static void SetDescriptionCB(AtkObject *aAtkObj,
198 : const gchar *description);
199 : static void SetParentCB(AtkObject *aAtkObj,
200 : AtkObject *parent);
201 : static void SetRoleCB(AtkObject *aAtkObj,
202 : AtkRole role);
203 : static guint ConnectPropertyChangeHandlerCB(
204 : AtkObject *aObj,
205 : AtkPropertyChangeHandler *handler);
206 : static void RemovePropertyChangeHandlerCB(
207 : AtkObject *aAtkObj,
208 : guint handler_id);
209 : static void InitializeCB(AtkObject *aAtkObj,
210 : gpointer data);
211 : static void ChildrenChangedCB(AtkObject *aAtkObj,
212 : guint change_index,
213 : gpointer changed_child);
214 : static void FocusEventCB(AtkObject *aAtkObj,
215 : gboolean focus_in);
216 : static void PropertyChangeCB(AtkObject *aAtkObj,
217 : AtkPropertyValues *values);
218 : static void StateChangeCB(AtkObject *aAtkObj,
219 : const gchar *name,
220 : gboolean state_set);
221 : static void VisibleDataChangedCB(AtkObject *aAtkObj);
222 : */
223 : G_END_DECLS
224 :
225 : static GType GetMaiAtkType(uint16_t interfacesBits);
226 : static const char * GetUniqueMaiAtkTypeName(uint16_t interfacesBits);
227 :
228 : static gpointer parent_class = nullptr;
229 :
230 : GType
231 0 : mai_atk_object_get_type(void)
232 : {
233 : static GType type = 0;
234 :
235 0 : if (!type) {
236 : static const GTypeInfo tinfo = {
237 : sizeof(MaiAtkObjectClass),
238 : (GBaseInitFunc)nullptr,
239 : (GBaseFinalizeFunc)nullptr,
240 : (GClassInitFunc)classInitCB,
241 : (GClassFinalizeFunc)nullptr,
242 : nullptr, /* class data */
243 : sizeof(MaiAtkObject), /* instance size */
244 : 0, /* nb preallocs */
245 : (GInstanceInitFunc)nullptr,
246 : nullptr /* value table */
247 : };
248 :
249 0 : type = g_type_register_static(ATK_TYPE_OBJECT,
250 : "MaiAtkObject", &tinfo, GTypeFlags(0));
251 0 : quark_mai_hyperlink = g_quark_from_static_string("MaiHyperlink");
252 : }
253 0 : return type;
254 : }
255 :
256 0 : AccessibleWrap::
257 0 : AccessibleWrap(nsIContent* aContent, DocAccessible* aDoc) :
258 0 : Accessible(aContent, aDoc), mAtkObject(nullptr)
259 : {
260 0 : }
261 :
262 0 : AccessibleWrap::~AccessibleWrap()
263 : {
264 0 : NS_ASSERTION(!mAtkObject, "ShutdownAtkObject() is not called");
265 0 : }
266 :
267 : void
268 0 : AccessibleWrap::ShutdownAtkObject()
269 : {
270 0 : if (!mAtkObject)
271 0 : return;
272 :
273 0 : NS_ASSERTION(IS_MAI_OBJECT(mAtkObject), "wrong type of atk object");
274 0 : if (IS_MAI_OBJECT(mAtkObject))
275 0 : MAI_ATK_OBJECT(mAtkObject)->Shutdown();
276 :
277 0 : g_object_unref(mAtkObject);
278 0 : mAtkObject = nullptr;
279 : }
280 :
281 : void
282 0 : AccessibleWrap::Shutdown()
283 : {
284 0 : ShutdownAtkObject();
285 0 : Accessible::Shutdown();
286 0 : }
287 :
288 : void
289 0 : AccessibleWrap::GetNativeInterface(void** aOutAccessible)
290 : {
291 0 : *aOutAccessible = nullptr;
292 :
293 0 : if (!mAtkObject) {
294 0 : if (IsDefunct() || IsText()) {
295 : // We don't create ATK objects for node which has been shutdown or
296 : // plain text leaves
297 0 : return;
298 : }
299 :
300 0 : GType type = GetMaiAtkType(CreateMaiInterfaces());
301 0 : if (!type)
302 0 : return;
303 :
304 0 : mAtkObject = reinterpret_cast<AtkObject*>(g_object_new(type, nullptr));
305 0 : if (!mAtkObject)
306 0 : return;
307 :
308 0 : atk_object_initialize(mAtkObject, this);
309 0 : mAtkObject->role = ATK_ROLE_INVALID;
310 0 : mAtkObject->layer = ATK_LAYER_INVALID;
311 : }
312 :
313 0 : *aOutAccessible = mAtkObject;
314 : }
315 :
316 : AtkObject *
317 0 : AccessibleWrap::GetAtkObject(void)
318 : {
319 0 : void *atkObj = nullptr;
320 0 : GetNativeInterface(&atkObj);
321 0 : return static_cast<AtkObject *>(atkObj);
322 : }
323 :
324 : // Get AtkObject from Accessible interface
325 : /* static */
326 : AtkObject *
327 0 : AccessibleWrap::GetAtkObject(Accessible* acc)
328 : {
329 0 : void *atkObjPtr = nullptr;
330 0 : acc->GetNativeInterface(&atkObjPtr);
331 0 : return atkObjPtr ? ATK_OBJECT(atkObjPtr) : nullptr;
332 : }
333 :
334 : /* private */
335 : uint16_t
336 0 : AccessibleWrap::CreateMaiInterfaces(void)
337 : {
338 0 : uint16_t interfacesBits = 0;
339 :
340 : // The Component interface is supported by all accessibles.
341 0 : interfacesBits |= 1 << MAI_INTERFACE_COMPONENT;
342 :
343 : // Add Action interface if the action count is more than zero.
344 0 : if (ActionCount() > 0)
345 0 : interfacesBits |= 1 << MAI_INTERFACE_ACTION;
346 :
347 : // Text, Editabletext, and Hypertext interface.
348 0 : HyperTextAccessible* hyperText = AsHyperText();
349 0 : if (hyperText && hyperText->IsTextRole()) {
350 0 : interfacesBits |= 1 << MAI_INTERFACE_TEXT;
351 0 : interfacesBits |= 1 << MAI_INTERFACE_EDITABLE_TEXT;
352 0 : if (!nsAccUtils::MustPrune(this))
353 0 : interfacesBits |= 1 << MAI_INTERFACE_HYPERTEXT;
354 : }
355 :
356 : // Value interface.
357 0 : if (HasNumericValue())
358 0 : interfacesBits |= 1 << MAI_INTERFACE_VALUE;
359 :
360 : // Document interface.
361 0 : if (IsDoc())
362 0 : interfacesBits |= 1 << MAI_INTERFACE_DOCUMENT;
363 :
364 0 : if (IsImage())
365 0 : interfacesBits |= 1 << MAI_INTERFACE_IMAGE;
366 :
367 : // HyperLink interface.
368 0 : if (IsLink())
369 0 : interfacesBits |= 1 << MAI_INTERFACE_HYPERLINK_IMPL;
370 :
371 0 : if (!nsAccUtils::MustPrune(this)) { // These interfaces require children
372 : // Table interface.
373 0 : if (AsTable())
374 0 : interfacesBits |= 1 << MAI_INTERFACE_TABLE;
375 :
376 0 : if (AsTableCell())
377 0 : interfacesBits |= 1 << MAI_INTERFACE_TABLE_CELL;
378 :
379 : // Selection interface.
380 0 : if (IsSelect()) {
381 0 : interfacesBits |= 1 << MAI_INTERFACE_SELECTION;
382 : }
383 : }
384 :
385 0 : return interfacesBits;
386 : }
387 :
388 : static GType
389 0 : GetMaiAtkType(uint16_t interfacesBits)
390 : {
391 : GType type;
392 : static const GTypeInfo tinfo = {
393 : sizeof(MaiAtkObjectClass),
394 : (GBaseInitFunc) nullptr,
395 : (GBaseFinalizeFunc) nullptr,
396 : (GClassInitFunc) nullptr,
397 : (GClassFinalizeFunc) nullptr,
398 : nullptr, /* class data */
399 : sizeof(MaiAtkObject), /* instance size */
400 : 0, /* nb preallocs */
401 : (GInstanceInitFunc) nullptr,
402 : nullptr /* value table */
403 : };
404 :
405 : /*
406 : * The members we use to register GTypes are GetAtkTypeForMai
407 : * and atk_if_infos, which are constant values to each MaiInterface
408 : * So we can reuse the registered GType when having
409 : * the same MaiInterface types.
410 : */
411 0 : const char *atkTypeName = GetUniqueMaiAtkTypeName(interfacesBits);
412 0 : type = g_type_from_name(atkTypeName);
413 0 : if (type) {
414 0 : return type;
415 : }
416 :
417 : /*
418 : * gobject limits the number of types that can directly derive from any
419 : * given object type to 4095.
420 : */
421 : static uint16_t typeRegCount = 0;
422 0 : if (typeRegCount++ >= 4095) {
423 0 : return G_TYPE_INVALID;
424 : }
425 0 : type = g_type_register_static(MAI_TYPE_ATK_OBJECT,
426 : atkTypeName,
427 0 : &tinfo, GTypeFlags(0));
428 :
429 0 : for (uint32_t index = 0; index < ArrayLength(atk_if_infos); index++) {
430 0 : if (interfacesBits & (1 << index)) {
431 0 : g_type_add_interface_static(type,
432 : GetAtkTypeForMai((MaiInterfaceType)index),
433 0 : &atk_if_infos[index]);
434 : }
435 : }
436 :
437 : // Special case AtkTableCell so we can check what version of Atk we are
438 : // dealing with.
439 0 : if (IsAtkVersionAtLeast(2, 12) && (interfacesBits & (1 << MAI_INTERFACE_TABLE_CELL))) {
440 : const GInterfaceInfo cellInfo = {
441 : (GInterfaceInitFunc)tableCellInterfaceInitCB,
442 0 : (GInterfaceFinalizeFunc)nullptr, nullptr};
443 0 : g_type_add_interface_static(type, gAtkTableCellGetTypeFunc(), &cellInfo);
444 : }
445 :
446 0 : return type;
447 : }
448 :
449 : static const char*
450 0 : GetUniqueMaiAtkTypeName(uint16_t interfacesBits)
451 : {
452 : #define MAI_ATK_TYPE_NAME_LEN (30) /* 10+sizeof(uint16_t)*8/4+1 < 30 */
453 :
454 : static gchar namePrefix[] = "MaiAtkType"; /* size = 10 */
455 : static gchar name[MAI_ATK_TYPE_NAME_LEN + 1];
456 :
457 0 : SprintfLiteral(name, "%s%x", namePrefix, interfacesBits);
458 0 : name[MAI_ATK_TYPE_NAME_LEN] = '\0';
459 :
460 0 : return name;
461 : }
462 :
463 : bool
464 0 : AccessibleWrap::IsValidObject()
465 : {
466 : // to ensure we are not shut down
467 0 : return !IsDefunct();
468 : }
469 :
470 : /* static functions for ATK callbacks */
471 : void
472 0 : classInitCB(AtkObjectClass *aClass)
473 : {
474 0 : GObjectClass *gobject_class = G_OBJECT_CLASS(aClass);
475 :
476 0 : parent_class = g_type_class_peek_parent(aClass);
477 :
478 0 : aClass->get_name = getNameCB;
479 0 : aClass->get_description = getDescriptionCB;
480 0 : aClass->get_parent = getParentCB;
481 0 : aClass->get_n_children = getChildCountCB;
482 0 : aClass->ref_child = refChildCB;
483 0 : aClass->get_index_in_parent = getIndexInParentCB;
484 0 : aClass->get_role = getRoleCB;
485 0 : aClass->get_attributes = getAttributesCB;
486 0 : aClass->get_object_locale = GetLocaleCB;
487 0 : aClass->ref_state_set = refStateSetCB;
488 0 : aClass->ref_relation_set = refRelationSetCB;
489 :
490 0 : aClass->initialize = initializeCB;
491 :
492 0 : gobject_class->finalize = finalizeCB;
493 :
494 0 : mai_atk_object_signals [ACTIVATE] =
495 0 : g_signal_new ("activate",
496 : MAI_TYPE_ATK_OBJECT,
497 : G_SIGNAL_RUN_LAST,
498 : 0, /* default signal handler */
499 : nullptr, nullptr,
500 : g_cclosure_marshal_VOID__VOID,
501 : G_TYPE_NONE, 0);
502 0 : mai_atk_object_signals [CREATE] =
503 0 : g_signal_new ("create",
504 : MAI_TYPE_ATK_OBJECT,
505 : G_SIGNAL_RUN_LAST,
506 : 0, /* default signal handler */
507 : nullptr, nullptr,
508 : g_cclosure_marshal_VOID__VOID,
509 : G_TYPE_NONE, 0);
510 0 : mai_atk_object_signals [DEACTIVATE] =
511 0 : g_signal_new ("deactivate",
512 : MAI_TYPE_ATK_OBJECT,
513 : G_SIGNAL_RUN_LAST,
514 : 0, /* default signal handler */
515 : nullptr, nullptr,
516 : g_cclosure_marshal_VOID__VOID,
517 : G_TYPE_NONE, 0);
518 0 : mai_atk_object_signals [DESTROY] =
519 0 : g_signal_new ("destroy",
520 : MAI_TYPE_ATK_OBJECT,
521 : G_SIGNAL_RUN_LAST,
522 : 0, /* default signal handler */
523 : nullptr, nullptr,
524 : g_cclosure_marshal_VOID__VOID,
525 : G_TYPE_NONE, 0);
526 0 : mai_atk_object_signals [MAXIMIZE] =
527 0 : g_signal_new ("maximize",
528 : MAI_TYPE_ATK_OBJECT,
529 : G_SIGNAL_RUN_LAST,
530 : 0, /* default signal handler */
531 : nullptr, nullptr,
532 : g_cclosure_marshal_VOID__VOID,
533 : G_TYPE_NONE, 0);
534 0 : mai_atk_object_signals [MINIMIZE] =
535 0 : g_signal_new ("minimize",
536 : MAI_TYPE_ATK_OBJECT,
537 : G_SIGNAL_RUN_LAST,
538 : 0, /* default signal handler */
539 : nullptr, nullptr,
540 : g_cclosure_marshal_VOID__VOID,
541 : G_TYPE_NONE, 0);
542 0 : mai_atk_object_signals [RESIZE] =
543 0 : g_signal_new ("resize",
544 : MAI_TYPE_ATK_OBJECT,
545 : G_SIGNAL_RUN_LAST,
546 : 0, /* default signal handler */
547 : nullptr, nullptr,
548 : g_cclosure_marshal_VOID__VOID,
549 : G_TYPE_NONE, 0);
550 0 : mai_atk_object_signals [RESTORE] =
551 0 : g_signal_new ("restore",
552 : MAI_TYPE_ATK_OBJECT,
553 : G_SIGNAL_RUN_LAST,
554 : 0, /* default signal handler */
555 : nullptr, nullptr,
556 : g_cclosure_marshal_VOID__VOID,
557 : G_TYPE_NONE, 0);
558 :
559 0 : }
560 :
561 : void
562 0 : initializeCB(AtkObject *aAtkObj, gpointer aData)
563 : {
564 0 : NS_ASSERTION((IS_MAI_OBJECT(aAtkObj)), "Invalid AtkObject");
565 0 : NS_ASSERTION(aData, "Invalid Data to init AtkObject");
566 0 : if (!aAtkObj || !aData)
567 0 : return;
568 :
569 : /* call parent init function */
570 : /* AtkObjectClass has not a "initialize" function now,
571 : * maybe it has later
572 : */
573 :
574 0 : if (ATK_OBJECT_CLASS(parent_class)->initialize)
575 0 : ATK_OBJECT_CLASS(parent_class)->initialize(aAtkObj, aData);
576 :
577 : /* initialize object */
578 0 : MAI_ATK_OBJECT(aAtkObj)->accWrap.SetBits(reinterpret_cast<uintptr_t>(aData));
579 : }
580 :
581 : void
582 0 : finalizeCB(GObject *aObj)
583 : {
584 0 : if (!IS_MAI_OBJECT(aObj))
585 0 : return;
586 0 : NS_ASSERTION(MAI_ATK_OBJECT(aObj)->accWrap.IsNull(), "AccWrap NOT null");
587 :
588 : // call parent finalize function
589 : // finalize of GObjectClass will unref the accessible parent if has
590 0 : if (G_OBJECT_CLASS (parent_class)->finalize)
591 0 : G_OBJECT_CLASS (parent_class)->finalize(aObj);
592 : }
593 :
594 : const gchar*
595 0 : getNameCB(AtkObject* aAtkObj)
596 : {
597 0 : nsAutoString name;
598 0 : AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj);
599 0 : if (accWrap)
600 0 : accWrap->Name(name);
601 0 : else if (ProxyAccessible* proxy = GetProxy(aAtkObj))
602 0 : proxy->Name(name);
603 : else
604 0 : return nullptr;
605 :
606 : // XXX Firing an event from here does not seem right
607 0 : MaybeFireNameChange(aAtkObj, name);
608 :
609 0 : return aAtkObj->name;
610 : }
611 :
612 : static void
613 0 : MaybeFireNameChange(AtkObject* aAtkObj, const nsString& aNewName)
614 : {
615 0 : NS_ConvertUTF16toUTF8 newNameUTF8(aNewName);
616 0 : if (aAtkObj->name && !strcmp(aAtkObj->name, newNameUTF8.get()))
617 0 : return;
618 :
619 : // Below we duplicate the functionality of atk_object_set_name(),
620 : // but without calling atk_object_get_name(). Instead of
621 : // atk_object_get_name() we directly access aAtkObj->name. This is because
622 : // atk_object_get_name() would call getNameCB() which would call
623 : // MaybeFireNameChange() (or atk_object_set_name() before this problem was
624 : // fixed) and we would get an infinite recursion.
625 : // See http://bugzilla.mozilla.org/733712
626 :
627 : // Do not notify for initial name setting.
628 : // See bug http://bugzilla.gnome.org/665870
629 0 : bool notify = !!aAtkObj->name;
630 :
631 0 : free(aAtkObj->name);
632 0 : aAtkObj->name = strdup(newNameUTF8.get());
633 :
634 0 : if (notify)
635 0 : g_object_notify(G_OBJECT(aAtkObj), "accessible-name");
636 : }
637 :
638 : const gchar *
639 0 : getDescriptionCB(AtkObject *aAtkObj)
640 : {
641 0 : nsAutoString uniDesc;
642 0 : AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj);
643 0 : if (accWrap) {
644 0 : if (accWrap->IsDefunct())
645 0 : return nullptr;
646 :
647 0 : accWrap->Description(uniDesc);
648 0 : } else if (ProxyAccessible* proxy = GetProxy(aAtkObj)) {
649 0 : proxy->Description(uniDesc);
650 : } else {
651 0 : return nullptr;
652 : }
653 :
654 0 : NS_ConvertUTF8toUTF16 objDesc(aAtkObj->description);
655 0 : if (!uniDesc.Equals(objDesc))
656 0 : atk_object_set_description(aAtkObj,
657 0 : NS_ConvertUTF16toUTF8(uniDesc).get());
658 :
659 0 : return aAtkObj->description;
660 : }
661 :
662 : AtkRole
663 0 : getRoleCB(AtkObject *aAtkObj)
664 : {
665 0 : if (aAtkObj->role != ATK_ROLE_INVALID)
666 0 : return aAtkObj->role;
667 :
668 0 : AccessibleOrProxy acc = GetInternalObj(aAtkObj);
669 0 : if (acc.IsNull()) {
670 0 : return ATK_ROLE_INVALID;
671 : }
672 :
673 : #ifdef DEBUG
674 0 : if (AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj)) {
675 0 : NS_ASSERTION(nsAccUtils::IsTextInterfaceSupportCorrect(accWrap),
676 : "Does not support Text interface when it should");
677 : }
678 : #endif
679 :
680 : #define ROLE(geckoRole, stringRole, atkRole, macRole, \
681 : msaaRole, ia2Role, nameRule) \
682 : case roles::geckoRole: \
683 : aAtkObj->role = atkRole; \
684 : break;
685 :
686 0 : switch (acc.Role()) {
687 : #include "RoleMap.h"
688 : default:
689 0 : MOZ_CRASH("Unknown role.");
690 : }
691 :
692 : #undef ROLE
693 :
694 0 : if (aAtkObj->role == ATK_ROLE_LIST_BOX && !IsAtkVersionAtLeast(2, 1))
695 0 : aAtkObj->role = ATK_ROLE_LIST;
696 0 : else if (aAtkObj->role == ATK_ROLE_TABLE_ROW && !IsAtkVersionAtLeast(2, 1))
697 0 : aAtkObj->role = ATK_ROLE_LIST_ITEM;
698 0 : else if (aAtkObj->role == ATK_ROLE_MATH && !IsAtkVersionAtLeast(2, 12))
699 0 : aAtkObj->role = ATK_ROLE_SECTION;
700 0 : else if (aAtkObj->role == ATK_ROLE_COMMENT && !IsAtkVersionAtLeast(2, 12))
701 0 : aAtkObj->role = ATK_ROLE_SECTION;
702 0 : else if (aAtkObj->role == ATK_ROLE_LANDMARK && !IsAtkVersionAtLeast(2, 12))
703 0 : aAtkObj->role = ATK_ROLE_SECTION;
704 0 : else if (aAtkObj->role == ATK_ROLE_FOOTNOTE && !IsAtkVersionAtLeast(2, 25, 2))
705 0 : aAtkObj->role = ATK_ROLE_SECTION;
706 0 : else if (aAtkObj->role == ATK_ROLE_STATIC && !IsAtkVersionAtLeast(2, 16))
707 0 : aAtkObj->role = ATK_ROLE_TEXT;
708 0 : else if ((aAtkObj->role == ATK_ROLE_MATH_FRACTION ||
709 0 : aAtkObj->role == ATK_ROLE_MATH_ROOT) && !IsAtkVersionAtLeast(2, 16))
710 0 : aAtkObj->role = ATK_ROLE_SECTION;
711 :
712 0 : return aAtkObj->role;
713 : }
714 :
715 : static AtkAttributeSet*
716 0 : ConvertToAtkAttributeSet(nsIPersistentProperties* aAttributes)
717 : {
718 0 : if (!aAttributes)
719 0 : return nullptr;
720 :
721 0 : AtkAttributeSet *objAttributeSet = nullptr;
722 0 : nsCOMPtr<nsISimpleEnumerator> propEnum;
723 0 : nsresult rv = aAttributes->Enumerate(getter_AddRefs(propEnum));
724 0 : NS_ENSURE_SUCCESS(rv, nullptr);
725 :
726 : bool hasMore;
727 0 : while (NS_SUCCEEDED(propEnum->HasMoreElements(&hasMore)) && hasMore) {
728 0 : nsCOMPtr<nsISupports> sup;
729 0 : rv = propEnum->GetNext(getter_AddRefs(sup));
730 0 : NS_ENSURE_SUCCESS(rv, objAttributeSet);
731 :
732 0 : nsCOMPtr<nsIPropertyElement> propElem(do_QueryInterface(sup));
733 0 : NS_ENSURE_TRUE(propElem, objAttributeSet);
734 :
735 0 : nsAutoCString name;
736 0 : rv = propElem->GetKey(name);
737 0 : NS_ENSURE_SUCCESS(rv, objAttributeSet);
738 :
739 0 : nsAutoString value;
740 0 : rv = propElem->GetValue(value);
741 0 : NS_ENSURE_SUCCESS(rv, objAttributeSet);
742 :
743 0 : AtkAttribute *objAttr = (AtkAttribute *)g_malloc(sizeof(AtkAttribute));
744 0 : objAttr->name = g_strdup(name.get());
745 0 : objAttr->value = g_strdup(NS_ConvertUTF16toUTF8(value).get());
746 0 : objAttributeSet = g_slist_prepend(objAttributeSet, objAttr);
747 : }
748 :
749 : //libspi will free it
750 0 : return objAttributeSet;
751 : }
752 :
753 : AtkAttributeSet*
754 0 : GetAttributeSet(Accessible* aAccessible)
755 : {
756 0 : nsCOMPtr<nsIPersistentProperties> attributes = aAccessible->Attributes();
757 0 : if (attributes)
758 0 : return ConvertToAtkAttributeSet(attributes);
759 :
760 0 : return nullptr;
761 : }
762 :
763 : AtkAttributeSet *
764 0 : getAttributesCB(AtkObject *aAtkObj)
765 : {
766 0 : AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj);
767 0 : if (accWrap)
768 0 : return GetAttributeSet(accWrap);
769 :
770 0 : ProxyAccessible* proxy = GetProxy(aAtkObj);
771 0 : if (!proxy)
772 0 : return nullptr;
773 :
774 0 : AutoTArray<Attribute, 10> attrs;
775 0 : proxy->Attributes(&attrs);
776 0 : if (attrs.IsEmpty())
777 0 : return nullptr;
778 :
779 0 : AtkAttributeSet* objAttributeSet = nullptr;
780 0 : for (uint32_t i = 0; i < attrs.Length(); i++) {
781 0 : AtkAttribute *objAttr = (AtkAttribute *)g_malloc(sizeof(AtkAttribute));
782 0 : objAttr->name = g_strdup(attrs[i].Name().get());
783 0 : objAttr->value = g_strdup(NS_ConvertUTF16toUTF8(attrs[i].Value()).get());
784 0 : objAttributeSet = g_slist_prepend(objAttributeSet, objAttr);
785 : }
786 :
787 0 : return objAttributeSet;
788 : }
789 :
790 : const gchar*
791 0 : GetLocaleCB(AtkObject* aAtkObj)
792 : {
793 0 : AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj);
794 0 : if (!accWrap)
795 0 : return nullptr;
796 :
797 0 : nsAutoString locale;
798 0 : accWrap->Language(locale);
799 0 : return AccessibleWrap::ReturnString(locale);
800 : }
801 :
802 : AtkObject *
803 0 : getParentCB(AtkObject *aAtkObj)
804 : {
805 0 : if (aAtkObj->accessible_parent)
806 0 : return aAtkObj->accessible_parent;
807 :
808 0 : AccessibleOrProxy acc = GetInternalObj(aAtkObj);
809 0 : if (acc.IsNull()) {
810 0 : return nullptr;
811 : }
812 :
813 0 : AccessibleOrProxy parent = acc.Parent();
814 0 : AtkObject* atkParent = !parent.IsNull() ? GetWrapperFor(parent) : nullptr;
815 0 : if (atkParent)
816 0 : atk_object_set_parent(aAtkObj, atkParent);
817 :
818 0 : return aAtkObj->accessible_parent;
819 : }
820 :
821 : gint
822 0 : getChildCountCB(AtkObject *aAtkObj)
823 : {
824 0 : if (AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj)) {
825 0 : if (nsAccUtils::MustPrune(accWrap)) {
826 0 : return 0;
827 : }
828 :
829 0 : uint32_t count = accWrap->EmbeddedChildCount();
830 0 : if (count) {
831 0 : return static_cast<gint>(count);
832 : }
833 :
834 0 : OuterDocAccessible* outerDoc = accWrap->AsOuterDoc();
835 0 : if (outerDoc && outerDoc->RemoteChildDoc()) {
836 0 : return 1;
837 : }
838 : }
839 :
840 0 : ProxyAccessible* proxy = GetProxy(aAtkObj);
841 0 : if (proxy && !proxy->MustPruneChildren()) {
842 0 : return proxy->EmbeddedChildCount();
843 : }
844 :
845 0 : return 0;
846 : }
847 :
848 : AtkObject *
849 0 : refChildCB(AtkObject *aAtkObj, gint aChildIndex)
850 : {
851 : // aChildIndex should not be less than zero
852 0 : if (aChildIndex < 0) {
853 0 : return nullptr;
854 : }
855 :
856 0 : AtkObject* childAtkObj = nullptr;
857 0 : AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj);
858 0 : if (accWrap) {
859 0 : if (nsAccUtils::MustPrune(accWrap)) {
860 0 : return nullptr;
861 : }
862 :
863 0 : Accessible* accChild = accWrap->GetEmbeddedChildAt(aChildIndex);
864 0 : if (accChild) {
865 0 : childAtkObj = AccessibleWrap::GetAtkObject(accChild);
866 : } else {
867 0 : OuterDocAccessible* docOwner = accWrap->AsOuterDoc();
868 0 : if (docOwner) {
869 0 : ProxyAccessible* proxyDoc = docOwner->RemoteChildDoc();
870 0 : if (proxyDoc)
871 0 : childAtkObj = GetWrapperFor(proxyDoc);
872 : }
873 : }
874 0 : } else if (ProxyAccessible* proxy = GetProxy(aAtkObj)) {
875 0 : if (proxy->MustPruneChildren())
876 0 : return nullptr;
877 :
878 0 : ProxyAccessible* child = proxy->EmbeddedChildAt(aChildIndex);
879 0 : if (child)
880 0 : childAtkObj = GetWrapperFor(child);
881 : } else {
882 0 : return nullptr;
883 : }
884 :
885 0 : NS_ASSERTION(childAtkObj, "Fail to get AtkObj");
886 0 : if (!childAtkObj)
887 0 : return nullptr;
888 :
889 0 : g_object_ref(childAtkObj);
890 :
891 0 : if (aAtkObj != childAtkObj->accessible_parent)
892 0 : atk_object_set_parent(childAtkObj, aAtkObj);
893 :
894 0 : return childAtkObj;
895 : }
896 :
897 : gint
898 0 : getIndexInParentCB(AtkObject* aAtkObj)
899 : {
900 : // We don't use Accessible::IndexInParent() because we don't include text
901 : // leaf nodes as children in ATK.
902 0 : if (ProxyAccessible* proxy = GetProxy(aAtkObj)) {
903 0 : if (ProxyAccessible* parent = proxy->Parent())
904 0 : return parent->IndexOfEmbeddedChild(proxy);
905 :
906 0 : if (proxy->OuterDocOfRemoteBrowser())
907 0 : return 0;
908 :
909 0 : return -1;
910 : }
911 :
912 0 : AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj);
913 0 : if (!accWrap) {
914 0 : return -1;
915 : }
916 :
917 0 : Accessible* parent = accWrap->Parent();
918 0 : if (!parent)
919 0 : return -1; // No parent
920 :
921 0 : return parent->GetIndexOfEmbeddedChild(accWrap);
922 : }
923 :
924 : static void
925 0 : TranslateStates(uint64_t aState, AtkStateSet* aStateSet)
926 : {
927 : // atk doesn't have a read only state so read only things shouldn't be
928 : // editable.
929 0 : if (aState & states::READONLY)
930 0 : aState &= ~states::EDITABLE;
931 :
932 : // Convert every state to an entry in AtkStateMap
933 0 : uint32_t stateIndex = 0;
934 0 : uint64_t bitMask = 1;
935 0 : while (gAtkStateMap[stateIndex].stateMapEntryType != kNoSuchState) {
936 0 : if (gAtkStateMap[stateIndex].atkState) { // There's potentially an ATK state for this
937 0 : bool isStateOn = (aState & bitMask) != 0;
938 0 : if (gAtkStateMap[stateIndex].stateMapEntryType == kMapOpposite) {
939 0 : isStateOn = !isStateOn;
940 : }
941 0 : if (isStateOn) {
942 0 : atk_state_set_add_state(aStateSet, gAtkStateMap[stateIndex].atkState);
943 : }
944 : }
945 0 : bitMask <<= 1;
946 0 : ++ stateIndex;
947 : }
948 0 : }
949 :
950 : AtkStateSet *
951 0 : refStateSetCB(AtkObject *aAtkObj)
952 : {
953 0 : AtkStateSet *state_set = nullptr;
954 0 : state_set = ATK_OBJECT_CLASS(parent_class)->ref_state_set(aAtkObj);
955 :
956 0 : AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj);
957 0 : if (accWrap)
958 0 : TranslateStates(accWrap->State(), state_set);
959 0 : else if (ProxyAccessible* proxy = GetProxy(aAtkObj))
960 0 : TranslateStates(proxy->State(), state_set);
961 : else
962 0 : TranslateStates(states::DEFUNCT, state_set);
963 :
964 0 : return state_set;
965 : }
966 :
967 : static void
968 0 : UpdateAtkRelation(RelationType aType, Accessible* aAcc,
969 : AtkRelationType aAtkType, AtkRelationSet* aAtkSet)
970 : {
971 0 : if (aAtkType == ATK_RELATION_NULL)
972 0 : return;
973 :
974 : AtkRelation* atkRelation =
975 0 : atk_relation_set_get_relation_by_type(aAtkSet, aAtkType);
976 0 : if (atkRelation)
977 0 : atk_relation_set_remove(aAtkSet, atkRelation);
978 :
979 0 : Relation rel(aAcc->RelationByType(aType));
980 0 : nsTArray<AtkObject*> targets;
981 0 : Accessible* tempAcc = nullptr;
982 0 : while ((tempAcc = rel.Next()))
983 0 : targets.AppendElement(AccessibleWrap::GetAtkObject(tempAcc));
984 :
985 0 : if (aType == RelationType::EMBEDS && aAcc->IsRoot()) {
986 0 : if (ProxyAccessible* proxyDoc =
987 0 : aAcc->AsRoot()->GetPrimaryRemoteTopLevelContentDoc()) {
988 0 : targets.AppendElement(GetWrapperFor(proxyDoc));
989 : }
990 : }
991 :
992 0 : if (targets.Length()) {
993 0 : atkRelation = atk_relation_new(targets.Elements(),
994 0 : targets.Length(), aAtkType);
995 0 : atk_relation_set_add(aAtkSet, atkRelation);
996 0 : g_object_unref(atkRelation);
997 : }
998 : }
999 :
1000 : AtkRelationSet *
1001 0 : refRelationSetCB(AtkObject *aAtkObj)
1002 : {
1003 : AtkRelationSet* relation_set =
1004 0 : ATK_OBJECT_CLASS(parent_class)->ref_relation_set(aAtkObj);
1005 :
1006 : const AtkRelationType typeMap[] = {
1007 : #define RELATIONTYPE(gecko, s, atk, m, i) atk,
1008 : #include "RelationTypeMap.h"
1009 : #undef RELATIONTYPE
1010 0 : };
1011 :
1012 0 : if (ProxyAccessible* proxy = GetProxy(aAtkObj)) {
1013 0 : nsTArray<RelationType> types;
1014 0 : nsTArray<nsTArray<ProxyAccessible*>> targetSets;
1015 0 : proxy->Relations(&types, &targetSets);
1016 :
1017 0 : size_t relationCount = types.Length();
1018 0 : for (size_t i = 0; i < relationCount; i++) {
1019 0 : if (typeMap[static_cast<uint32_t>(types[i])] == ATK_RELATION_NULL)
1020 0 : continue;
1021 :
1022 0 : size_t targetCount = targetSets[i].Length();
1023 0 : AutoTArray<AtkObject*, 5> wrappers;
1024 0 : for (size_t j = 0; j < targetCount; j++)
1025 0 : wrappers.AppendElement(GetWrapperFor(targetSets[i][j]));
1026 :
1027 0 : AtkRelationType atkType = typeMap[static_cast<uint32_t>(types[i])];
1028 : AtkRelation* atkRelation =
1029 0 : atk_relation_set_get_relation_by_type(relation_set, atkType);
1030 0 : if (atkRelation)
1031 0 : atk_relation_set_remove(relation_set, atkRelation);
1032 :
1033 0 : atkRelation = atk_relation_new(wrappers.Elements(), wrappers.Length(),
1034 0 : atkType);
1035 0 : atk_relation_set_add(relation_set, atkRelation);
1036 0 : g_object_unref(atkRelation);
1037 : }
1038 : }
1039 :
1040 0 : AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj);
1041 0 : if (!accWrap)
1042 0 : return relation_set;
1043 :
1044 : #define RELATIONTYPE(geckoType, geckoTypeName, atkType, msaaType, ia2Type) \
1045 : UpdateAtkRelation(RelationType::geckoType, accWrap, atkType, relation_set);
1046 :
1047 : #include "RelationTypeMap.h"
1048 :
1049 : #undef RELATIONTYPE
1050 :
1051 0 : return relation_set;
1052 : }
1053 :
1054 : // Check if aAtkObj is a valid MaiAtkObject, and return the AccessibleWrap
1055 : // for it.
1056 : AccessibleWrap*
1057 0 : GetAccessibleWrap(AtkObject* aAtkObj)
1058 : {
1059 0 : bool isMAIObject = IS_MAI_OBJECT(aAtkObj);
1060 0 : NS_ENSURE_TRUE(isMAIObject || MAI_IS_ATK_SOCKET(aAtkObj),
1061 : nullptr);
1062 :
1063 0 : AccessibleWrap* accWrap = nullptr;
1064 0 : if (isMAIObject) {
1065 0 : Accessible* acc = MAI_ATK_OBJECT(aAtkObj)->accWrap.AsAccessible();
1066 0 : accWrap = static_cast<AccessibleWrap*>(acc);
1067 : } else {
1068 0 : accWrap = MAI_ATK_SOCKET(aAtkObj)->accWrap;
1069 : }
1070 :
1071 : // Check if the accessible was deconstructed.
1072 0 : if (!accWrap)
1073 0 : return nullptr;
1074 :
1075 0 : NS_ENSURE_TRUE(accWrap->GetAtkObject() == aAtkObj, nullptr);
1076 :
1077 0 : AccessibleWrap* appAccWrap = ApplicationAcc();
1078 0 : if (appAccWrap != accWrap && !accWrap->IsValidObject())
1079 0 : return nullptr;
1080 :
1081 0 : return accWrap;
1082 : }
1083 :
1084 : ProxyAccessible*
1085 0 : GetProxy(AtkObject* aObj)
1086 : {
1087 0 : return GetInternalObj(aObj).AsProxy();
1088 : }
1089 :
1090 : AccessibleOrProxy
1091 0 : GetInternalObj(AtkObject* aObj)
1092 : {
1093 0 : if (!aObj || !IS_MAI_OBJECT(aObj))
1094 0 : return nullptr;
1095 :
1096 0 : return MAI_ATK_OBJECT(aObj)->accWrap;
1097 : }
1098 :
1099 : AtkObject*
1100 0 : GetWrapperFor(ProxyAccessible* aProxy)
1101 : {
1102 0 : return reinterpret_cast<AtkObject*>(aProxy->GetWrapper() & ~IS_PROXY);
1103 : }
1104 :
1105 : AtkObject*
1106 0 : GetWrapperFor(AccessibleOrProxy aObj)
1107 : {
1108 0 : if (aObj.IsProxy()) {
1109 0 : return GetWrapperFor(aObj.AsProxy());
1110 : }
1111 :
1112 0 : return AccessibleWrap::GetAtkObject(aObj.AsAccessible());
1113 : }
1114 :
1115 : static uint16_t
1116 0 : GetInterfacesForProxy(ProxyAccessible* aProxy, uint32_t aInterfaces)
1117 : {
1118 0 : uint16_t interfaces = 1 << MAI_INTERFACE_COMPONENT;
1119 0 : if (aInterfaces & Interfaces::HYPERTEXT)
1120 0 : interfaces |= (1 << MAI_INTERFACE_HYPERTEXT) | (1 << MAI_INTERFACE_TEXT)
1121 : | (1 << MAI_INTERFACE_EDITABLE_TEXT);
1122 :
1123 0 : if (aInterfaces & Interfaces::HYPERLINK)
1124 0 : interfaces |= 1 << MAI_INTERFACE_HYPERLINK_IMPL;
1125 :
1126 0 : if (aInterfaces & Interfaces::VALUE)
1127 0 : interfaces |= 1 << MAI_INTERFACE_VALUE;
1128 :
1129 0 : if (aInterfaces & Interfaces::TABLE)
1130 0 : interfaces |= 1 << MAI_INTERFACE_TABLE;
1131 :
1132 0 : if (aInterfaces & Interfaces::TABLECELL)
1133 0 : interfaces |= 1 << MAI_INTERFACE_TABLE_CELL;
1134 :
1135 0 : if (aInterfaces & Interfaces::IMAGE)
1136 0 : interfaces |= 1 << MAI_INTERFACE_IMAGE;
1137 :
1138 0 : if (aInterfaces & Interfaces::DOCUMENT)
1139 0 : interfaces |= 1 << MAI_INTERFACE_DOCUMENT;
1140 :
1141 0 : if (aInterfaces & Interfaces::SELECTION) {
1142 0 : interfaces |= 1 << MAI_INTERFACE_SELECTION;
1143 : }
1144 :
1145 0 : if (aInterfaces & Interfaces::ACTION) {
1146 0 : interfaces |= 1 << MAI_INTERFACE_ACTION;
1147 : }
1148 :
1149 0 : return interfaces;
1150 : }
1151 :
1152 : void
1153 0 : a11y::ProxyCreated(ProxyAccessible* aProxy, uint32_t aInterfaces)
1154 : {
1155 0 : GType type = GetMaiAtkType(GetInterfacesForProxy(aProxy, aInterfaces));
1156 0 : NS_ASSERTION(type, "why don't we have a type!");
1157 :
1158 : AtkObject* obj =
1159 : reinterpret_cast<AtkObject *>
1160 0 : (g_object_new(type, nullptr));
1161 0 : if (!obj)
1162 0 : return;
1163 :
1164 0 : uintptr_t inner = reinterpret_cast<uintptr_t>(aProxy) | IS_PROXY;
1165 0 : atk_object_initialize(obj, reinterpret_cast<gpointer>(inner));
1166 0 : obj->role = ATK_ROLE_INVALID;
1167 0 : obj->layer = ATK_LAYER_INVALID;
1168 0 : aProxy->SetWrapper(reinterpret_cast<uintptr_t>(obj) | IS_PROXY);
1169 : }
1170 :
1171 : void
1172 0 : a11y::ProxyDestroyed(ProxyAccessible* aProxy)
1173 : {
1174 0 : auto obj = reinterpret_cast<MaiAtkObject*>(aProxy->GetWrapper() & ~IS_PROXY);
1175 0 : if (!obj) {
1176 0 : return;
1177 : }
1178 :
1179 0 : obj->Shutdown();
1180 0 : g_object_unref(obj);
1181 0 : aProxy->SetWrapper(0);
1182 : }
1183 :
1184 : nsresult
1185 0 : AccessibleWrap::HandleAccEvent(AccEvent* aEvent)
1186 : {
1187 0 : nsresult rv = Accessible::HandleAccEvent(aEvent);
1188 0 : NS_ENSURE_SUCCESS(rv, rv);
1189 :
1190 0 : if (IPCAccessibilityActive()) {
1191 0 : return NS_OK;
1192 : }
1193 :
1194 0 : Accessible* accessible = aEvent->GetAccessible();
1195 0 : NS_ENSURE_TRUE(accessible, NS_ERROR_FAILURE);
1196 :
1197 : // The accessible can become defunct if we have an xpcom event listener
1198 : // which decides it would be fun to change the DOM and flush layout.
1199 0 : if (accessible->IsDefunct())
1200 0 : return NS_OK;
1201 :
1202 0 : uint32_t type = aEvent->GetEventType();
1203 :
1204 0 : AtkObject* atkObj = AccessibleWrap::GetAtkObject(accessible);
1205 :
1206 : // We don't create ATK objects for plain text leaves, just return NS_OK in
1207 : // such case.
1208 0 : if (!atkObj) {
1209 0 : NS_ASSERTION(type == nsIAccessibleEvent::EVENT_SHOW ||
1210 : type == nsIAccessibleEvent::EVENT_HIDE,
1211 : "Event other than SHOW and HIDE fired for plain text leaves");
1212 0 : return NS_OK;
1213 : }
1214 :
1215 0 : AccessibleWrap* accWrap = GetAccessibleWrap(atkObj);
1216 0 : if (!accWrap) {
1217 0 : return NS_OK; // Node is shut down
1218 : }
1219 :
1220 0 : switch (type) {
1221 : case nsIAccessibleEvent::EVENT_STATE_CHANGE:
1222 : {
1223 0 : AccStateChangeEvent* event = downcast_accEvent(aEvent);
1224 0 : MAI_ATK_OBJECT(atkObj)->FireStateChangeEvent(event->GetState(),
1225 0 : event->IsStateEnabled());
1226 0 : break;
1227 : }
1228 :
1229 : case nsIAccessibleEvent::EVENT_TEXT_REMOVED:
1230 : case nsIAccessibleEvent::EVENT_TEXT_INSERTED:
1231 : {
1232 0 : AccTextChangeEvent* event = downcast_accEvent(aEvent);
1233 0 : NS_ENSURE_TRUE(event, NS_ERROR_FAILURE);
1234 :
1235 0 : MAI_ATK_OBJECT(atkObj)-> FireTextChangeEvent(event->ModifiedText(),
1236 : event->GetStartOffset(),
1237 : event->GetLength(),
1238 0 : event->IsTextInserted(),
1239 0 : event->IsFromUserInput());
1240 :
1241 0 : return NS_OK;
1242 : }
1243 :
1244 : case nsIAccessibleEvent::EVENT_FOCUS:
1245 : {
1246 0 : a11y::RootAccessible* rootAccWrap = accWrap->RootAccessible();
1247 0 : if (rootAccWrap && rootAccWrap->mActivated) {
1248 0 : atk_focus_tracker_notify(atkObj);
1249 : // Fire state change event for focus
1250 0 : atk_object_notify_state_change(atkObj, ATK_STATE_FOCUSED, true);
1251 0 : return NS_OK;
1252 : }
1253 0 : } break;
1254 :
1255 : case nsIAccessibleEvent::EVENT_NAME_CHANGE:
1256 : {
1257 0 : nsAutoString newName;
1258 0 : accessible->Name(newName);
1259 :
1260 0 : MaybeFireNameChange(atkObj, newName);
1261 :
1262 0 : break;
1263 : }
1264 :
1265 : case nsIAccessibleEvent::EVENT_VALUE_CHANGE:
1266 : case nsIAccessibleEvent::EVENT_TEXT_VALUE_CHANGE:
1267 0 : if (accessible->HasNumericValue()) {
1268 : // Make sure this is a numeric value. Don't fire for string value changes
1269 : // (e.g. text editing) ATK values are always numeric.
1270 0 : g_object_notify((GObject*)atkObj, "accessible-value");
1271 : }
1272 0 : break;
1273 :
1274 : case nsIAccessibleEvent::EVENT_SELECTION:
1275 : case nsIAccessibleEvent::EVENT_SELECTION_ADD:
1276 : case nsIAccessibleEvent::EVENT_SELECTION_REMOVE:
1277 : {
1278 : // XXX: dupe events may be fired
1279 0 : AccSelChangeEvent* selChangeEvent = downcast_accEvent(aEvent);
1280 0 : g_signal_emit_by_name(AccessibleWrap::GetAtkObject(selChangeEvent->Widget()),
1281 0 : "selection_changed");
1282 0 : break;
1283 : }
1284 :
1285 : case nsIAccessibleEvent::EVENT_SELECTION_WITHIN:
1286 : {
1287 0 : g_signal_emit_by_name(atkObj, "selection_changed");
1288 0 : break;
1289 : }
1290 :
1291 : case nsIAccessibleEvent::EVENT_ALERT:
1292 : // A hack using state change showing events as alert events.
1293 0 : atk_object_notify_state_change(atkObj, ATK_STATE_SHOWING, true);
1294 0 : break;
1295 :
1296 : case nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED:
1297 0 : g_signal_emit_by_name(atkObj, "text_selection_changed");
1298 0 : break;
1299 :
1300 : case nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED:
1301 : {
1302 0 : AccCaretMoveEvent* caretMoveEvent = downcast_accEvent(aEvent);
1303 0 : NS_ASSERTION(caretMoveEvent, "Event needs event data");
1304 0 : if (!caretMoveEvent)
1305 0 : break;
1306 :
1307 0 : int32_t caretOffset = caretMoveEvent->GetCaretOffset();
1308 0 : g_signal_emit_by_name(atkObj, "text_caret_moved", caretOffset);
1309 0 : } break;
1310 :
1311 : case nsIAccessibleEvent::EVENT_TEXT_ATTRIBUTE_CHANGED:
1312 0 : g_signal_emit_by_name(atkObj, "text-attributes-changed");
1313 0 : break;
1314 :
1315 : case nsIAccessibleEvent::EVENT_TABLE_MODEL_CHANGED:
1316 0 : g_signal_emit_by_name(atkObj, "model_changed");
1317 0 : break;
1318 :
1319 : case nsIAccessibleEvent::EVENT_TABLE_ROW_INSERT:
1320 : {
1321 0 : AccTableChangeEvent* tableEvent = downcast_accEvent(aEvent);
1322 0 : NS_ENSURE_TRUE(tableEvent, NS_ERROR_FAILURE);
1323 :
1324 0 : int32_t rowIndex = tableEvent->GetIndex();
1325 0 : int32_t numRows = tableEvent->GetCount();
1326 :
1327 0 : g_signal_emit_by_name(atkObj, "row_inserted", rowIndex, numRows);
1328 0 : } break;
1329 :
1330 : case nsIAccessibleEvent::EVENT_TABLE_ROW_DELETE:
1331 : {
1332 0 : AccTableChangeEvent* tableEvent = downcast_accEvent(aEvent);
1333 0 : NS_ENSURE_TRUE(tableEvent, NS_ERROR_FAILURE);
1334 :
1335 0 : int32_t rowIndex = tableEvent->GetIndex();
1336 0 : int32_t numRows = tableEvent->GetCount();
1337 :
1338 0 : g_signal_emit_by_name(atkObj, "row_deleted", rowIndex, numRows);
1339 0 : } break;
1340 :
1341 : case nsIAccessibleEvent::EVENT_TABLE_ROW_REORDER:
1342 : {
1343 0 : g_signal_emit_by_name(atkObj, "row_reordered");
1344 0 : break;
1345 : }
1346 :
1347 : case nsIAccessibleEvent::EVENT_TABLE_COLUMN_INSERT:
1348 : {
1349 0 : AccTableChangeEvent* tableEvent = downcast_accEvent(aEvent);
1350 0 : NS_ENSURE_TRUE(tableEvent, NS_ERROR_FAILURE);
1351 :
1352 0 : int32_t colIndex = tableEvent->GetIndex();
1353 0 : int32_t numCols = tableEvent->GetCount();
1354 0 : g_signal_emit_by_name(atkObj, "column_inserted", colIndex, numCols);
1355 0 : } break;
1356 :
1357 : case nsIAccessibleEvent::EVENT_TABLE_COLUMN_DELETE:
1358 : {
1359 0 : AccTableChangeEvent* tableEvent = downcast_accEvent(aEvent);
1360 0 : NS_ENSURE_TRUE(tableEvent, NS_ERROR_FAILURE);
1361 :
1362 0 : int32_t colIndex = tableEvent->GetIndex();
1363 0 : int32_t numCols = tableEvent->GetCount();
1364 0 : g_signal_emit_by_name(atkObj, "column_deleted", colIndex, numCols);
1365 0 : } break;
1366 :
1367 : case nsIAccessibleEvent::EVENT_TABLE_COLUMN_REORDER:
1368 0 : g_signal_emit_by_name(atkObj, "column_reordered");
1369 0 : break;
1370 :
1371 : case nsIAccessibleEvent::EVENT_SECTION_CHANGED:
1372 0 : g_signal_emit_by_name(atkObj, "visible_data_changed");
1373 0 : break;
1374 :
1375 : case nsIAccessibleEvent::EVENT_SHOW:
1376 : {
1377 0 : AccMutationEvent* event = downcast_accEvent(aEvent);
1378 0 : Accessible* parentAcc = event ? event->Parent() : accessible->Parent();
1379 0 : AtkObject* parent = AccessibleWrap::GetAtkObject(parentAcc);
1380 0 : NS_ENSURE_STATE(parent);
1381 0 : auto obj = reinterpret_cast<MaiAtkObject*>(atkObj);
1382 0 : obj->FireAtkShowHideEvent(parent, true, aEvent->IsFromUserInput());
1383 0 : return NS_OK;
1384 : }
1385 :
1386 : case nsIAccessibleEvent::EVENT_HIDE:
1387 : {
1388 : // XXX - Handle native dialog accessibles.
1389 0 : if (!accessible->IsRoot() && accessible->HasARIARole() &&
1390 0 : accessible->ARIARole() == roles::DIALOG) {
1391 0 : guint id = g_signal_lookup("deactivate", MAI_TYPE_ATK_OBJECT);
1392 0 : g_signal_emit(atkObj, id, 0);
1393 : }
1394 :
1395 0 : AccMutationEvent* event = downcast_accEvent(aEvent);
1396 0 : Accessible* parentAcc = event ? event->Parent() : accessible->Parent();
1397 0 : AtkObject* parent = AccessibleWrap::GetAtkObject(parentAcc);
1398 0 : NS_ENSURE_STATE(parent);
1399 0 : auto obj = reinterpret_cast<MaiAtkObject*>(atkObj);
1400 0 : obj->FireAtkShowHideEvent(parent, false, aEvent->IsFromUserInput());
1401 0 : return NS_OK;
1402 : }
1403 :
1404 : /*
1405 : * Because dealing with menu is very different between nsIAccessible
1406 : * and ATK, and the menu activity is important, specially transfer the
1407 : * following two event.
1408 : * Need more verification by AT test.
1409 : */
1410 : case nsIAccessibleEvent::EVENT_MENU_START:
1411 : case nsIAccessibleEvent::EVENT_MENU_END:
1412 0 : break;
1413 :
1414 : case nsIAccessibleEvent::EVENT_WINDOW_ACTIVATE:
1415 : {
1416 0 : accessible->AsRoot()->mActivated = true;
1417 0 : guint id = g_signal_lookup("activate", MAI_TYPE_ATK_OBJECT);
1418 0 : g_signal_emit(atkObj, id, 0);
1419 :
1420 : // Always fire a current focus event after activation.
1421 0 : FocusMgr()->ForceFocusEvent();
1422 0 : } break;
1423 :
1424 : case nsIAccessibleEvent::EVENT_WINDOW_DEACTIVATE:
1425 : {
1426 0 : accessible->AsRoot()->mActivated = false;
1427 0 : guint id = g_signal_lookup("deactivate", MAI_TYPE_ATK_OBJECT);
1428 0 : g_signal_emit(atkObj, id, 0);
1429 0 : } break;
1430 :
1431 : case nsIAccessibleEvent::EVENT_WINDOW_MAXIMIZE:
1432 : {
1433 0 : guint id = g_signal_lookup("maximize", MAI_TYPE_ATK_OBJECT);
1434 0 : g_signal_emit(atkObj, id, 0);
1435 0 : } break;
1436 :
1437 : case nsIAccessibleEvent::EVENT_WINDOW_MINIMIZE:
1438 : {
1439 0 : guint id = g_signal_lookup("minimize", MAI_TYPE_ATK_OBJECT);
1440 0 : g_signal_emit(atkObj, id, 0);
1441 0 : } break;
1442 :
1443 : case nsIAccessibleEvent::EVENT_WINDOW_RESTORE:
1444 : {
1445 0 : guint id = g_signal_lookup("restore", MAI_TYPE_ATK_OBJECT);
1446 0 : g_signal_emit(atkObj, id, 0);
1447 0 : } break;
1448 :
1449 : case nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_COMPLETE:
1450 0 : g_signal_emit_by_name (atkObj, "load_complete");
1451 : // XXX - Handle native dialog accessibles.
1452 0 : if (!accessible->IsRoot() && accessible->HasARIARole() &&
1453 0 : accessible->ARIARole() == roles::DIALOG) {
1454 0 : guint id = g_signal_lookup("activate", MAI_TYPE_ATK_OBJECT);
1455 0 : g_signal_emit(atkObj, id, 0);
1456 : }
1457 0 : break;
1458 :
1459 : case nsIAccessibleEvent::EVENT_DOCUMENT_RELOAD:
1460 0 : g_signal_emit_by_name (atkObj, "reload");
1461 0 : break;
1462 :
1463 : case nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_STOPPED:
1464 0 : g_signal_emit_by_name (atkObj, "load_stopped");
1465 0 : break;
1466 :
1467 : case nsIAccessibleEvent::EVENT_MENUPOPUP_START:
1468 0 : atk_focus_tracker_notify(atkObj); // fire extra focus event
1469 0 : atk_object_notify_state_change(atkObj, ATK_STATE_VISIBLE, true);
1470 0 : atk_object_notify_state_change(atkObj, ATK_STATE_SHOWING, true);
1471 0 : break;
1472 :
1473 : case nsIAccessibleEvent::EVENT_MENUPOPUP_END:
1474 0 : atk_object_notify_state_change(atkObj, ATK_STATE_VISIBLE, false);
1475 0 : atk_object_notify_state_change(atkObj, ATK_STATE_SHOWING, false);
1476 0 : break;
1477 : }
1478 :
1479 0 : return NS_OK;
1480 : }
1481 :
1482 : void
1483 0 : a11y::ProxyEvent(ProxyAccessible* aTarget, uint32_t aEventType)
1484 : {
1485 0 : AtkObject* wrapper = GetWrapperFor(aTarget);
1486 :
1487 0 : switch (aEventType) {
1488 : case nsIAccessibleEvent::EVENT_FOCUS:
1489 0 : atk_focus_tracker_notify(wrapper);
1490 0 : atk_object_notify_state_change(wrapper, ATK_STATE_FOCUSED, true);
1491 0 : break;
1492 : case nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_COMPLETE:
1493 0 : g_signal_emit_by_name(wrapper, "load_complete");
1494 0 : break;
1495 : case nsIAccessibleEvent::EVENT_DOCUMENT_RELOAD:
1496 0 : g_signal_emit_by_name(wrapper, "reload");
1497 0 : break;
1498 : case nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_STOPPED:
1499 0 : g_signal_emit_by_name(wrapper, "load_stopped");
1500 0 : break;
1501 : case nsIAccessibleEvent::EVENT_MENUPOPUP_START:
1502 0 : atk_focus_tracker_notify(wrapper); // fire extra focus event
1503 0 : atk_object_notify_state_change(wrapper, ATK_STATE_VISIBLE, true);
1504 0 : atk_object_notify_state_change(wrapper, ATK_STATE_SHOWING, true);
1505 0 : break;
1506 : case nsIAccessibleEvent::EVENT_MENUPOPUP_END:
1507 0 : atk_object_notify_state_change(wrapper, ATK_STATE_VISIBLE, false);
1508 0 : atk_object_notify_state_change(wrapper, ATK_STATE_SHOWING, false);
1509 0 : break;
1510 : case nsIAccessibleEvent::EVENT_ALERT:
1511 : // A hack using state change showing events as alert events.
1512 0 : atk_object_notify_state_change(wrapper, ATK_STATE_SHOWING, true);
1513 0 : break;
1514 : case nsIAccessibleEvent::EVENT_VALUE_CHANGE:
1515 0 : g_object_notify((GObject*)wrapper, "accessible-value");
1516 0 : break;
1517 : case nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED:
1518 : case nsIAccessibleEvent::EVENT_SELECTION_WITHIN:
1519 0 : g_signal_emit_by_name(wrapper, "selection_changed");
1520 0 : break;
1521 : }
1522 0 : }
1523 :
1524 : void
1525 0 : a11y::ProxyStateChangeEvent(ProxyAccessible* aTarget, uint64_t aState,
1526 : bool aEnabled)
1527 : {
1528 0 : MaiAtkObject* atkObj = MAI_ATK_OBJECT(GetWrapperFor(aTarget));
1529 0 : atkObj->FireStateChangeEvent(aState, aEnabled);
1530 0 : }
1531 :
1532 : void
1533 0 : a11y::ProxyCaretMoveEvent(ProxyAccessible* aTarget, int32_t aOffset)
1534 : {
1535 0 : AtkObject* wrapper = GetWrapperFor(aTarget);
1536 0 : g_signal_emit_by_name(wrapper, "text_caret_moved", aOffset);
1537 0 : }
1538 :
1539 : void
1540 0 : MaiAtkObject::FireStateChangeEvent(uint64_t aState, bool aEnabled)
1541 : {
1542 0 : int32_t stateIndex = AtkStateMap::GetStateIndexFor(aState);
1543 0 : if (stateIndex >= 0) {
1544 0 : NS_ASSERTION(gAtkStateMap[stateIndex].stateMapEntryType != kNoSuchState,
1545 : "No such state");
1546 :
1547 0 : if (gAtkStateMap[stateIndex].atkState != kNone) {
1548 0 : NS_ASSERTION(gAtkStateMap[stateIndex].stateMapEntryType != kNoStateChange,
1549 : "State changes should not fired for this state");
1550 :
1551 0 : if (gAtkStateMap[stateIndex].stateMapEntryType == kMapOpposite)
1552 0 : aEnabled = !aEnabled;
1553 :
1554 : // Fire state change for first state if there is one to map
1555 0 : atk_object_notify_state_change(&parent,
1556 0 : gAtkStateMap[stateIndex].atkState,
1557 0 : aEnabled);
1558 : }
1559 : }
1560 0 : }
1561 :
1562 : void
1563 0 : a11y::ProxyTextChangeEvent(ProxyAccessible* aTarget, const nsString& aStr,
1564 : int32_t aStart, uint32_t aLen, bool aIsInsert,
1565 : bool aFromUser)
1566 : {
1567 0 : MaiAtkObject* atkObj = MAI_ATK_OBJECT(GetWrapperFor(aTarget));
1568 0 : atkObj->FireTextChangeEvent(aStr, aStart, aLen, aIsInsert, aFromUser);
1569 0 : }
1570 :
1571 : #define OLD_TEXT_INSERTED "text_changed::insert"
1572 : #define OLD_TEXT_REMOVED "text_changed::delete"
1573 : static const char* oldTextChangeStrings[2][2] = {
1574 : { OLD_TEXT_REMOVED NON_USER_EVENT, OLD_TEXT_INSERTED NON_USER_EVENT },
1575 : { OLD_TEXT_REMOVED, OLD_TEXT_INSERTED }
1576 : };
1577 :
1578 : #define TEXT_INSERTED "text-insert"
1579 : #define TEXT_REMOVED "text-remove"
1580 : #define NON_USER_DETAIL "::system"
1581 : static const char* textChangedStrings[2][2] = {
1582 : { TEXT_REMOVED NON_USER_DETAIL, TEXT_INSERTED NON_USER_DETAIL },
1583 : { TEXT_REMOVED, TEXT_INSERTED}
1584 : };
1585 :
1586 : void
1587 0 : MaiAtkObject::FireTextChangeEvent(const nsString& aStr, int32_t aStart,
1588 : uint32_t aLen, bool aIsInsert,
1589 : bool aFromUser)
1590 : {
1591 0 : if (gAvailableAtkSignals == eUnknown)
1592 0 : gAvailableAtkSignals =
1593 0 : g_signal_lookup("text-insert", G_OBJECT_TYPE(this)) ?
1594 : eHaveNewAtkTextSignals : eNoNewAtkSignals;
1595 :
1596 0 : if (gAvailableAtkSignals == eNoNewAtkSignals) {
1597 : // XXX remove this code and the gHaveNewTextSignals check when we can
1598 : // stop supporting old atk since it doesn't really work anyway
1599 : // see bug 619002
1600 : const char* signal_name =
1601 0 : oldTextChangeStrings[aFromUser][aIsInsert];
1602 0 : g_signal_emit_by_name(this, signal_name, aStart, aLen);
1603 : } else {
1604 : const char* signal_name =
1605 0 : textChangedStrings[aFromUser][aIsInsert];
1606 0 : g_signal_emit_by_name(this, signal_name, aStart, aLen,
1607 0 : NS_ConvertUTF16toUTF8(aStr).get());
1608 : }
1609 0 : }
1610 :
1611 : void
1612 0 : a11y::ProxyShowHideEvent(ProxyAccessible* aTarget, ProxyAccessible* aParent,
1613 : bool aInsert, bool aFromUser)
1614 : {
1615 0 : MaiAtkObject* obj = MAI_ATK_OBJECT(GetWrapperFor(aTarget));
1616 0 : obj->FireAtkShowHideEvent(GetWrapperFor(aParent), aInsert, aFromUser);
1617 0 : }
1618 :
1619 : #define ADD_EVENT "children_changed::add"
1620 : #define HIDE_EVENT "children_changed::remove"
1621 :
1622 : static const char *kMutationStrings[2][2] = {
1623 : { HIDE_EVENT NON_USER_EVENT, ADD_EVENT NON_USER_EVENT },
1624 : { HIDE_EVENT, ADD_EVENT },
1625 : };
1626 :
1627 : void
1628 0 : MaiAtkObject::FireAtkShowHideEvent(AtkObject* aParent, bool aIsAdded,
1629 : bool aFromUser)
1630 : {
1631 0 : int32_t indexInParent = getIndexInParentCB(&this->parent);
1632 0 : const char *signal_name = kMutationStrings[aFromUser][aIsAdded];
1633 0 : g_signal_emit_by_name(aParent, signal_name, indexInParent, this, nullptr);
1634 0 : }
1635 :
1636 : void
1637 0 : a11y::ProxySelectionEvent(ProxyAccessible*, ProxyAccessible* aWidget, uint32_t)
1638 : {
1639 0 : MaiAtkObject* obj = MAI_ATK_OBJECT(GetWrapperFor(aWidget));
1640 0 : g_signal_emit_by_name(obj, "selection_changed");
1641 0 : }
1642 :
1643 : // static
1644 : void
1645 0 : AccessibleWrap::GetKeyBinding(Accessible* aAccessible, nsAString& aResult)
1646 : {
1647 : // Return all key bindings including access key and keyboard shortcut.
1648 :
1649 : // Get access key.
1650 0 : nsAutoString keyBindingsStr;
1651 0 : KeyBinding keyBinding = aAccessible->AccessKey();
1652 0 : if (!keyBinding.IsEmpty()) {
1653 0 : keyBinding.AppendToString(keyBindingsStr, KeyBinding::eAtkFormat);
1654 :
1655 0 : Accessible* parent = aAccessible->Parent();
1656 0 : roles::Role role = parent ? parent->Role() : roles::NOTHING;
1657 0 : if (role == roles::PARENT_MENUITEM || role == roles::MENUITEM ||
1658 0 : role == roles::RADIO_MENU_ITEM || role == roles::CHECK_MENU_ITEM) {
1659 : // It is submenu, expose keyboard shortcuts from menu hierarchy like
1660 : // "s;<Alt>f:s"
1661 0 : nsAutoString keysInHierarchyStr = keyBindingsStr;
1662 0 : do {
1663 0 : KeyBinding parentKeyBinding = parent->AccessKey();
1664 0 : if (!parentKeyBinding.IsEmpty()) {
1665 0 : nsAutoString str;
1666 0 : parentKeyBinding.ToString(str, KeyBinding::eAtkFormat);
1667 0 : str.Append(':');
1668 :
1669 0 : keysInHierarchyStr.Insert(str, 0);
1670 : }
1671 0 : } while ((parent = parent->Parent()) && parent->Role() != roles::MENUBAR);
1672 :
1673 0 : keyBindingsStr.Append(';');
1674 0 : keyBindingsStr.Append(keysInHierarchyStr);
1675 : }
1676 : } else {
1677 : // No access key, add ';' to point this.
1678 0 : keyBindingsStr.Append(';');
1679 : }
1680 :
1681 : // Get keyboard shortcut.
1682 0 : keyBindingsStr.Append(';');
1683 0 : keyBinding = aAccessible->KeyboardShortcut();
1684 0 : if (!keyBinding.IsEmpty()) {
1685 0 : keyBinding.AppendToString(keyBindingsStr, KeyBinding::eAtkFormat);
1686 : }
1687 0 : aResult = keyBindingsStr;
1688 0 : }
1689 :
1690 : // static
1691 : Accessible*
1692 0 : AccessibleWrap::GetColumnHeader(TableAccessible* aAccessible, int32_t aColIdx)
1693 : {
1694 0 : if (!aAccessible) {
1695 0 : return nullptr;
1696 : }
1697 :
1698 0 : Accessible* cell = aAccessible->CellAt(0, aColIdx);
1699 0 : if (!cell) {
1700 0 : return nullptr;
1701 : }
1702 :
1703 : // If the cell at the first row is column header then assume it is column
1704 : // header for all rows,
1705 0 : if (cell->Role() == roles::COLUMNHEADER) {
1706 0 : return cell;
1707 : }
1708 :
1709 : // otherwise get column header for the data cell at the first row.
1710 0 : TableCellAccessible* tableCell = cell->AsTableCell();
1711 0 : if (!tableCell) {
1712 0 : return nullptr;
1713 : }
1714 :
1715 0 : AutoTArray<Accessible*, 10> headerCells;
1716 0 : tableCell->ColHeaderCells(&headerCells);
1717 0 : if (headerCells.IsEmpty()) {
1718 0 : return nullptr;
1719 : }
1720 :
1721 0 : return headerCells[0];
1722 : }
1723 :
1724 : // static
1725 : Accessible*
1726 0 : AccessibleWrap::GetRowHeader(TableAccessible* aAccessible, int32_t aRowIdx)
1727 : {
1728 0 : if (!aAccessible) {
1729 0 : return nullptr;
1730 : }
1731 :
1732 0 : Accessible* cell = aAccessible->CellAt(aRowIdx, 0);
1733 0 : if (!cell) {
1734 0 : return nullptr;
1735 : }
1736 :
1737 : // If the cell at the first column is row header then assume it is row
1738 : // header for all columns,
1739 0 : if (cell->Role() == roles::ROWHEADER) {
1740 0 : return cell;
1741 : }
1742 :
1743 : // otherwise get row header for the data cell at the first column.
1744 0 : TableCellAccessible* tableCell = cell->AsTableCell();
1745 0 : if (!tableCell) {
1746 0 : return nullptr;
1747 : }
1748 :
1749 0 : AutoTArray<Accessible*, 10> headerCells;
1750 0 : tableCell->RowHeaderCells(&headerCells);
1751 0 : if (headerCells.IsEmpty()) {
1752 0 : return nullptr;
1753 : }
1754 :
1755 0 : return headerCells[0];
1756 : }
|