Coverage Report

Created: 2018-09-25 14:53

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