AccessibleWrap.cpp 52 KB

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