summaryrefslogtreecommitdiff
path: root/accessible/atk
diff options
context:
space:
mode:
authorMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
committerMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
commit5f8de423f190bbb79a62f804151bc24824fa32d8 (patch)
tree10027f336435511475e392454359edea8e25895d /accessible/atk
parent49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff)
downloaduxp-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz
Add m-esr52 at 52.6.0
Diffstat (limited to 'accessible/atk')
-rw-r--r--accessible/atk/ARIAGridAccessibleWrap.h21
-rw-r--r--accessible/atk/AccessibleWrap.cpp1759
-rw-r--r--accessible/atk/AccessibleWrap.h92
-rw-r--r--accessible/atk/ApplicationAccessibleWrap.cpp167
-rw-r--r--accessible/atk/ApplicationAccessibleWrap.h35
-rw-r--r--accessible/atk/AtkSocketAccessible.cpp126
-rw-r--r--accessible/atk/AtkSocketAccessible.h56
-rw-r--r--accessible/atk/DocAccessibleWrap.cpp25
-rw-r--r--accessible/atk/DocAccessibleWrap.h31
-rw-r--r--accessible/atk/HTMLTableAccessibleWrap.h23
-rw-r--r--accessible/atk/HyperTextAccessibleWrap.h21
-rw-r--r--accessible/atk/ImageAccessibleWrap.h21
-rw-r--r--accessible/atk/InterfaceInitFuncs.h44
-rw-r--r--accessible/atk/Platform.cpp377
-rw-r--r--accessible/atk/RootAccessibleWrap.cpp24
-rw-r--r--accessible/atk/RootAccessibleWrap.h34
-rw-r--r--accessible/atk/TextLeafAccessibleWrap.h20
-rw-r--r--accessible/atk/UtilInterface.cpp411
-rw-r--r--accessible/atk/XULListboxAccessibleWrap.h21
-rw-r--r--accessible/atk/XULMenuAccessibleWrap.h20
-rw-r--r--accessible/atk/XULTreeGridAccessibleWrap.h22
-rw-r--r--accessible/atk/moz.build63
-rw-r--r--accessible/atk/nsMai.h149
-rw-r--r--accessible/atk/nsMaiHyperlink.cpp262
-rw-r--r--accessible/atk/nsMaiHyperlink.h55
-rw-r--r--accessible/atk/nsMaiInterfaceAction.cpp105
-rw-r--r--accessible/atk/nsMaiInterfaceComponent.cpp151
-rw-r--r--accessible/atk/nsMaiInterfaceDocument.cpp151
-rw-r--r--accessible/atk/nsMaiInterfaceEditableText.cpp134
-rw-r--r--accessible/atk/nsMaiInterfaceHyperlinkImpl.cpp37
-rw-r--r--accessible/atk/nsMaiInterfaceHypertext.cpp94
-rw-r--r--accessible/atk/nsMaiInterfaceImage.cpp77
-rw-r--r--accessible/atk/nsMaiInterfaceSelection.cpp152
-rw-r--r--accessible/atk/nsMaiInterfaceTable.cpp391
-rw-r--r--accessible/atk/nsMaiInterfaceTableCell.cpp216
-rw-r--r--accessible/atk/nsMaiInterfaceText.cpp629
-rw-r--r--accessible/atk/nsMaiInterfaceValue.cpp133
-rw-r--r--accessible/atk/nsStateMap.h117
38 files changed, 6266 insertions, 0 deletions
diff --git a/accessible/atk/ARIAGridAccessibleWrap.h b/accessible/atk/ARIAGridAccessibleWrap.h
new file mode 100644
index 0000000000..8d53c6eb20
--- /dev/null
+++ b/accessible/atk/ARIAGridAccessibleWrap.h
@@ -0,0 +1,21 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef MOZILLA_A11Y_ARIAGRIDACCESSIBLEWRAP_H
+#define MOZILLA_A11Y_ARIAGRIDACCESSIBLEWRAP_H
+
+#include "ARIAGridAccessible.h"
+
+namespace mozilla {
+namespace a11y {
+
+typedef class ARIAGridAccessible ARIAGridAccessibleWrap;
+typedef class ARIAGridCellAccessible ARIAGridCellAccessibleWrap;
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif
diff --git a/accessible/atk/AccessibleWrap.cpp b/accessible/atk/AccessibleWrap.cpp
new file mode 100644
index 0000000000..cd0f2999a6
--- /dev/null
+++ b/accessible/atk/AccessibleWrap.cpp
@@ -0,0 +1,1759 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "AccessibleWrap.h"
+
+#include "Accessible-inl.h"
+#include "ApplicationAccessibleWrap.h"
+#include "InterfaceInitFuncs.h"
+#include "nsAccUtils.h"
+#include "mozilla/a11y/PDocAccessible.h"
+#include "OuterDocAccessible.h"
+#include "ProxyAccessible.h"
+#include "RootAccessible.h"
+#include "TableAccessible.h"
+#include "TableCellAccessible.h"
+#include "nsMai.h"
+#include "nsMaiHyperlink.h"
+#include "nsString.h"
+#include "nsStateMap.h"
+#include "mozilla/a11y/Platform.h"
+#include "Relation.h"
+#include "RootAccessible.h"
+#include "States.h"
+#include "nsISimpleEnumerator.h"
+
+#include "mozilla/ArrayUtils.h"
+#include "mozilla/Sprintf.h"
+#include "nsXPCOMStrings.h"
+#include "nsComponentManagerUtils.h"
+#include "nsIPersistentProperties2.h"
+
+using namespace mozilla;
+using namespace mozilla::a11y;
+
+MaiAtkObject::EAvailableAtkSignals MaiAtkObject::gAvailableAtkSignals =
+ eUnknown;
+
+//defined in ApplicationAccessibleWrap.cpp
+extern "C" GType g_atk_hyperlink_impl_type;
+
+/* MaiAtkObject */
+
+enum {
+ ACTIVATE,
+ CREATE,
+ DEACTIVATE,
+ DESTROY,
+ MAXIMIZE,
+ MINIMIZE,
+ RESIZE,
+ RESTORE,
+ LAST_SIGNAL
+};
+
+enum MaiInterfaceType {
+ MAI_INTERFACE_COMPONENT, /* 0 */
+ MAI_INTERFACE_ACTION,
+ MAI_INTERFACE_VALUE,
+ MAI_INTERFACE_EDITABLE_TEXT,
+ MAI_INTERFACE_HYPERTEXT,
+ MAI_INTERFACE_HYPERLINK_IMPL,
+ MAI_INTERFACE_SELECTION,
+ MAI_INTERFACE_TABLE,
+ MAI_INTERFACE_TEXT,
+ MAI_INTERFACE_DOCUMENT,
+ MAI_INTERFACE_IMAGE, /* 10 */
+ MAI_INTERFACE_TABLE_CELL
+};
+
+static GType GetAtkTypeForMai(MaiInterfaceType type)
+{
+ switch (type) {
+ case MAI_INTERFACE_COMPONENT:
+ return ATK_TYPE_COMPONENT;
+ case MAI_INTERFACE_ACTION:
+ return ATK_TYPE_ACTION;
+ case MAI_INTERFACE_VALUE:
+ return ATK_TYPE_VALUE;
+ case MAI_INTERFACE_EDITABLE_TEXT:
+ return ATK_TYPE_EDITABLE_TEXT;
+ case MAI_INTERFACE_HYPERTEXT:
+ return ATK_TYPE_HYPERTEXT;
+ case MAI_INTERFACE_HYPERLINK_IMPL:
+ return g_atk_hyperlink_impl_type;
+ case MAI_INTERFACE_SELECTION:
+ return ATK_TYPE_SELECTION;
+ case MAI_INTERFACE_TABLE:
+ return ATK_TYPE_TABLE;
+ case MAI_INTERFACE_TEXT:
+ return ATK_TYPE_TEXT;
+ case MAI_INTERFACE_DOCUMENT:
+ return ATK_TYPE_DOCUMENT;
+ case MAI_INTERFACE_IMAGE:
+ return ATK_TYPE_IMAGE;
+ case MAI_INTERFACE_TABLE_CELL:
+ MOZ_ASSERT(false);
+ }
+ return G_TYPE_INVALID;
+}
+
+#define NON_USER_EVENT ":system"
+
+// The atk interfaces we can expose without checking what version of ATK we are
+// dealing with. At the moment AtkTableCell is the only interface we can't
+// always expose.
+static const GInterfaceInfo atk_if_infos[] = {
+ {(GInterfaceInitFunc)componentInterfaceInitCB,
+ (GInterfaceFinalizeFunc) nullptr, nullptr},
+ {(GInterfaceInitFunc)actionInterfaceInitCB,
+ (GInterfaceFinalizeFunc) nullptr, nullptr},
+ {(GInterfaceInitFunc)valueInterfaceInitCB,
+ (GInterfaceFinalizeFunc) nullptr, nullptr},
+ {(GInterfaceInitFunc)editableTextInterfaceInitCB,
+ (GInterfaceFinalizeFunc) nullptr, nullptr},
+ {(GInterfaceInitFunc)hypertextInterfaceInitCB,
+ (GInterfaceFinalizeFunc) nullptr, nullptr},
+ {(GInterfaceInitFunc)hyperlinkImplInterfaceInitCB,
+ (GInterfaceFinalizeFunc) nullptr, nullptr},
+ {(GInterfaceInitFunc)selectionInterfaceInitCB,
+ (GInterfaceFinalizeFunc) nullptr, nullptr},
+ {(GInterfaceInitFunc)tableInterfaceInitCB,
+ (GInterfaceFinalizeFunc) nullptr, nullptr},
+ {(GInterfaceInitFunc)textInterfaceInitCB,
+ (GInterfaceFinalizeFunc) nullptr, nullptr},
+ {(GInterfaceInitFunc)documentInterfaceInitCB,
+ (GInterfaceFinalizeFunc) nullptr, nullptr},
+ {(GInterfaceInitFunc)imageInterfaceInitCB,
+ (GInterfaceFinalizeFunc) nullptr, nullptr}
+};
+
+static GQuark quark_mai_hyperlink = 0;
+
+AtkHyperlink*
+MaiAtkObject::GetAtkHyperlink()
+{
+ NS_ASSERTION(quark_mai_hyperlink, "quark_mai_hyperlink not initialized");
+ MaiHyperlink* maiHyperlink =
+ (MaiHyperlink*)g_object_get_qdata(G_OBJECT(this), quark_mai_hyperlink);
+ if (!maiHyperlink) {
+ maiHyperlink = new MaiHyperlink(accWrap);
+ g_object_set_qdata(G_OBJECT(this), quark_mai_hyperlink, maiHyperlink);
+ }
+
+ return maiHyperlink->GetAtkHyperlink();
+}
+
+void
+MaiAtkObject::Shutdown()
+{
+ accWrap.SetBits(0);
+ MaiHyperlink* maiHyperlink =
+ (MaiHyperlink*)g_object_get_qdata(G_OBJECT(this), quark_mai_hyperlink);
+ if (maiHyperlink) {
+ delete maiHyperlink;
+ g_object_set_qdata(G_OBJECT(this), quark_mai_hyperlink, nullptr);
+ }
+}
+
+struct MaiAtkObjectClass
+{
+ AtkObjectClass parent_class;
+};
+
+static guint mai_atk_object_signals [LAST_SIGNAL] = { 0, };
+
+static void MaybeFireNameChange(AtkObject* aAtkObj, const nsString& aNewName);
+
+G_BEGIN_DECLS
+/* callbacks for MaiAtkObject */
+static void classInitCB(AtkObjectClass *aClass);
+static void initializeCB(AtkObject *aAtkObj, gpointer aData);
+static void finalizeCB(GObject *aObj);
+
+/* callbacks for AtkObject virtual functions */
+static const gchar* getNameCB (AtkObject *aAtkObj);
+/* getDescriptionCB is also used by image interface */
+ const gchar* getDescriptionCB (AtkObject *aAtkObj);
+static AtkRole getRoleCB(AtkObject *aAtkObj);
+static AtkAttributeSet* getAttributesCB(AtkObject *aAtkObj);
+static const gchar* GetLocaleCB(AtkObject*);
+static AtkObject* getParentCB(AtkObject *aAtkObj);
+static gint getChildCountCB(AtkObject *aAtkObj);
+static AtkObject* refChildCB(AtkObject *aAtkObj, gint aChildIndex);
+static gint getIndexInParentCB(AtkObject *aAtkObj);
+static AtkStateSet* refStateSetCB(AtkObject *aAtkObj);
+static AtkRelationSet* refRelationSetCB(AtkObject *aAtkObj);
+
+/* the missing atkobject virtual functions */
+/*
+ static AtkLayer getLayerCB(AtkObject *aAtkObj);
+ static gint getMdiZorderCB(AtkObject *aAtkObj);
+ static void SetNameCB(AtkObject *aAtkObj,
+ const gchar *name);
+ static void SetDescriptionCB(AtkObject *aAtkObj,
+ const gchar *description);
+ static void SetParentCB(AtkObject *aAtkObj,
+ AtkObject *parent);
+ static void SetRoleCB(AtkObject *aAtkObj,
+ AtkRole role);
+ static guint ConnectPropertyChangeHandlerCB(
+ AtkObject *aObj,
+ AtkPropertyChangeHandler *handler);
+ static void RemovePropertyChangeHandlerCB(
+ AtkObject *aAtkObj,
+ guint handler_id);
+ static void InitializeCB(AtkObject *aAtkObj,
+ gpointer data);
+ static void ChildrenChangedCB(AtkObject *aAtkObj,
+ guint change_index,
+ gpointer changed_child);
+ static void FocusEventCB(AtkObject *aAtkObj,
+ gboolean focus_in);
+ static void PropertyChangeCB(AtkObject *aAtkObj,
+ AtkPropertyValues *values);
+ static void StateChangeCB(AtkObject *aAtkObj,
+ const gchar *name,
+ gboolean state_set);
+ static void VisibleDataChangedCB(AtkObject *aAtkObj);
+*/
+G_END_DECLS
+
+static GType GetMaiAtkType(uint16_t interfacesBits);
+static const char * GetUniqueMaiAtkTypeName(uint16_t interfacesBits);
+
+static gpointer parent_class = nullptr;
+
+GType
+mai_atk_object_get_type(void)
+{
+ static GType type = 0;
+
+ if (!type) {
+ static const GTypeInfo tinfo = {
+ sizeof(MaiAtkObjectClass),
+ (GBaseInitFunc)nullptr,
+ (GBaseFinalizeFunc)nullptr,
+ (GClassInitFunc)classInitCB,
+ (GClassFinalizeFunc)nullptr,
+ nullptr, /* class data */
+ sizeof(MaiAtkObject), /* instance size */
+ 0, /* nb preallocs */
+ (GInstanceInitFunc)nullptr,
+ nullptr /* value table */
+ };
+
+ type = g_type_register_static(ATK_TYPE_OBJECT,
+ "MaiAtkObject", &tinfo, GTypeFlags(0));
+ quark_mai_hyperlink = g_quark_from_static_string("MaiHyperlink");
+ }
+ return type;
+}
+
+AccessibleWrap::
+ AccessibleWrap(nsIContent* aContent, DocAccessible* aDoc) :
+ Accessible(aContent, aDoc), mAtkObject(nullptr)
+{
+}
+
+AccessibleWrap::~AccessibleWrap()
+{
+ NS_ASSERTION(!mAtkObject, "ShutdownAtkObject() is not called");
+}
+
+void
+AccessibleWrap::ShutdownAtkObject()
+{
+ if (!mAtkObject)
+ return;
+
+ NS_ASSERTION(IS_MAI_OBJECT(mAtkObject), "wrong type of atk object");
+ if (IS_MAI_OBJECT(mAtkObject))
+ MAI_ATK_OBJECT(mAtkObject)->Shutdown();
+
+ g_object_unref(mAtkObject);
+ mAtkObject = nullptr;
+}
+
+void
+AccessibleWrap::Shutdown()
+{
+ ShutdownAtkObject();
+ Accessible::Shutdown();
+}
+
+void
+AccessibleWrap::GetNativeInterface(void** aOutAccessible)
+{
+ *aOutAccessible = nullptr;
+
+ if (!mAtkObject) {
+ if (IsDefunct() || IsText()) {
+ // We don't create ATK objects for node which has been shutdown or
+ // plain text leaves
+ return;
+ }
+
+ GType type = GetMaiAtkType(CreateMaiInterfaces());
+ if (!type)
+ return;
+
+ mAtkObject = reinterpret_cast<AtkObject*>(g_object_new(type, nullptr));
+ if (!mAtkObject)
+ return;
+
+ atk_object_initialize(mAtkObject, this);
+ mAtkObject->role = ATK_ROLE_INVALID;
+ mAtkObject->layer = ATK_LAYER_INVALID;
+ }
+
+ *aOutAccessible = mAtkObject;
+}
+
+AtkObject *
+AccessibleWrap::GetAtkObject(void)
+{
+ void *atkObj = nullptr;
+ GetNativeInterface(&atkObj);
+ return static_cast<AtkObject *>(atkObj);
+}
+
+// Get AtkObject from Accessible interface
+/* static */
+AtkObject *
+AccessibleWrap::GetAtkObject(Accessible* acc)
+{
+ void *atkObjPtr = nullptr;
+ acc->GetNativeInterface(&atkObjPtr);
+ return atkObjPtr ? ATK_OBJECT(atkObjPtr) : nullptr;
+}
+
+/* private */
+uint16_t
+AccessibleWrap::CreateMaiInterfaces(void)
+{
+ uint16_t interfacesBits = 0;
+
+ // The Component interface is supported by all accessibles.
+ interfacesBits |= 1 << MAI_INTERFACE_COMPONENT;
+
+ // Add Action interface if the action count is more than zero.
+ if (ActionCount() > 0)
+ interfacesBits |= 1 << MAI_INTERFACE_ACTION;
+
+ // Text, Editabletext, and Hypertext interface.
+ HyperTextAccessible* hyperText = AsHyperText();
+ if (hyperText && hyperText->IsTextRole()) {
+ interfacesBits |= 1 << MAI_INTERFACE_TEXT;
+ interfacesBits |= 1 << MAI_INTERFACE_EDITABLE_TEXT;
+ if (!nsAccUtils::MustPrune(this))
+ interfacesBits |= 1 << MAI_INTERFACE_HYPERTEXT;
+ }
+
+ // Value interface.
+ if (HasNumericValue())
+ interfacesBits |= 1 << MAI_INTERFACE_VALUE;
+
+ // Document interface.
+ if (IsDoc())
+ interfacesBits |= 1 << MAI_INTERFACE_DOCUMENT;
+
+ if (IsImage())
+ interfacesBits |= 1 << MAI_INTERFACE_IMAGE;
+
+ // HyperLink interface.
+ if (IsLink())
+ interfacesBits |= 1 << MAI_INTERFACE_HYPERLINK_IMPL;
+
+ if (!nsAccUtils::MustPrune(this)) { // These interfaces require children
+ // Table interface.
+ if (AsTable())
+ interfacesBits |= 1 << MAI_INTERFACE_TABLE;
+
+ if (AsTableCell())
+ interfacesBits |= 1 << MAI_INTERFACE_TABLE_CELL;
+
+ // Selection interface.
+ if (IsSelect()) {
+ interfacesBits |= 1 << MAI_INTERFACE_SELECTION;
+ }
+ }
+
+ return interfacesBits;
+}
+
+static GType
+GetMaiAtkType(uint16_t interfacesBits)
+{
+ GType type;
+ static const GTypeInfo tinfo = {
+ sizeof(MaiAtkObjectClass),
+ (GBaseInitFunc) nullptr,
+ (GBaseFinalizeFunc) nullptr,
+ (GClassInitFunc) nullptr,
+ (GClassFinalizeFunc) nullptr,
+ nullptr, /* class data */
+ sizeof(MaiAtkObject), /* instance size */
+ 0, /* nb preallocs */
+ (GInstanceInitFunc) nullptr,
+ nullptr /* value table */
+ };
+
+ /*
+ * The members we use to register GTypes are GetAtkTypeForMai
+ * and atk_if_infos, which are constant values to each MaiInterface
+ * So we can reuse the registered GType when having
+ * the same MaiInterface types.
+ */
+ const char *atkTypeName = GetUniqueMaiAtkTypeName(interfacesBits);
+ type = g_type_from_name(atkTypeName);
+ if (type) {
+ return type;
+ }
+
+ /*
+ * gobject limits the number of types that can directly derive from any
+ * given object type to 4095.
+ */
+ static uint16_t typeRegCount = 0;
+ if (typeRegCount++ >= 4095) {
+ return G_TYPE_INVALID;
+ }
+ type = g_type_register_static(MAI_TYPE_ATK_OBJECT,
+ atkTypeName,
+ &tinfo, GTypeFlags(0));
+
+ for (uint32_t index = 0; index < ArrayLength(atk_if_infos); index++) {
+ if (interfacesBits & (1 << index)) {
+ g_type_add_interface_static(type,
+ GetAtkTypeForMai((MaiInterfaceType)index),
+ &atk_if_infos[index]);
+ }
+ }
+
+ // Special case AtkTableCell so we can check what version of Atk we are
+ // dealing with.
+ if (IsAtkVersionAtLeast(2, 12) && (interfacesBits & (1 << MAI_INTERFACE_TABLE_CELL))) {
+ const GInterfaceInfo cellInfo = {
+ (GInterfaceInitFunc)tableCellInterfaceInitCB,
+ (GInterfaceFinalizeFunc)nullptr, nullptr};
+ g_type_add_interface_static(type, gAtkTableCellGetTypeFunc(), &cellInfo);
+ }
+
+ return type;
+}
+
+static const char*
+GetUniqueMaiAtkTypeName(uint16_t interfacesBits)
+{
+#define MAI_ATK_TYPE_NAME_LEN (30) /* 10+sizeof(uint16_t)*8/4+1 < 30 */
+
+ static gchar namePrefix[] = "MaiAtkType"; /* size = 10 */
+ static gchar name[MAI_ATK_TYPE_NAME_LEN + 1];
+
+ SprintfLiteral(name, "%s%x", namePrefix, interfacesBits);
+ name[MAI_ATK_TYPE_NAME_LEN] = '\0';
+
+ return name;
+}
+
+bool
+AccessibleWrap::IsValidObject()
+{
+ // to ensure we are not shut down
+ return !IsDefunct();
+}
+
+/* static functions for ATK callbacks */
+void
+classInitCB(AtkObjectClass *aClass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS(aClass);
+
+ parent_class = g_type_class_peek_parent(aClass);
+
+ aClass->get_name = getNameCB;
+ aClass->get_description = getDescriptionCB;
+ aClass->get_parent = getParentCB;
+ aClass->get_n_children = getChildCountCB;
+ aClass->ref_child = refChildCB;
+ aClass->get_index_in_parent = getIndexInParentCB;
+ aClass->get_role = getRoleCB;
+ aClass->get_attributes = getAttributesCB;
+ aClass->get_object_locale = GetLocaleCB;
+ aClass->ref_state_set = refStateSetCB;
+ aClass->ref_relation_set = refRelationSetCB;
+
+ aClass->initialize = initializeCB;
+
+ gobject_class->finalize = finalizeCB;
+
+ mai_atk_object_signals [ACTIVATE] =
+ g_signal_new ("activate",
+ MAI_TYPE_ATK_OBJECT,
+ G_SIGNAL_RUN_LAST,
+ 0, /* default signal handler */
+ nullptr, nullptr,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+ mai_atk_object_signals [CREATE] =
+ g_signal_new ("create",
+ MAI_TYPE_ATK_OBJECT,
+ G_SIGNAL_RUN_LAST,
+ 0, /* default signal handler */
+ nullptr, nullptr,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+ mai_atk_object_signals [DEACTIVATE] =
+ g_signal_new ("deactivate",
+ MAI_TYPE_ATK_OBJECT,
+ G_SIGNAL_RUN_LAST,
+ 0, /* default signal handler */
+ nullptr, nullptr,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+ mai_atk_object_signals [DESTROY] =
+ g_signal_new ("destroy",
+ MAI_TYPE_ATK_OBJECT,
+ G_SIGNAL_RUN_LAST,
+ 0, /* default signal handler */
+ nullptr, nullptr,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+ mai_atk_object_signals [MAXIMIZE] =
+ g_signal_new ("maximize",
+ MAI_TYPE_ATK_OBJECT,
+ G_SIGNAL_RUN_LAST,
+ 0, /* default signal handler */
+ nullptr, nullptr,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+ mai_atk_object_signals [MINIMIZE] =
+ g_signal_new ("minimize",
+ MAI_TYPE_ATK_OBJECT,
+ G_SIGNAL_RUN_LAST,
+ 0, /* default signal handler */
+ nullptr, nullptr,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+ mai_atk_object_signals [RESIZE] =
+ g_signal_new ("resize",
+ MAI_TYPE_ATK_OBJECT,
+ G_SIGNAL_RUN_LAST,
+ 0, /* default signal handler */
+ nullptr, nullptr,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+ mai_atk_object_signals [RESTORE] =
+ g_signal_new ("restore",
+ MAI_TYPE_ATK_OBJECT,
+ G_SIGNAL_RUN_LAST,
+ 0, /* default signal handler */
+ nullptr, nullptr,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+}
+
+void
+initializeCB(AtkObject *aAtkObj, gpointer aData)
+{
+ NS_ASSERTION((IS_MAI_OBJECT(aAtkObj)), "Invalid AtkObject");
+ NS_ASSERTION(aData, "Invalid Data to init AtkObject");
+ if (!aAtkObj || !aData)
+ return;
+
+ /* call parent init function */
+ /* AtkObjectClass has not a "initialize" function now,
+ * maybe it has later
+ */
+
+ if (ATK_OBJECT_CLASS(parent_class)->initialize)
+ ATK_OBJECT_CLASS(parent_class)->initialize(aAtkObj, aData);
+
+ /* initialize object */
+ MAI_ATK_OBJECT(aAtkObj)->accWrap.SetBits(reinterpret_cast<uintptr_t>(aData));
+}
+
+void
+finalizeCB(GObject *aObj)
+{
+ if (!IS_MAI_OBJECT(aObj))
+ return;
+ NS_ASSERTION(MAI_ATK_OBJECT(aObj)->accWrap.IsNull(), "AccWrap NOT null");
+
+ // call parent finalize function
+ // finalize of GObjectClass will unref the accessible parent if has
+ if (G_OBJECT_CLASS (parent_class)->finalize)
+ G_OBJECT_CLASS (parent_class)->finalize(aObj);
+}
+
+const gchar*
+getNameCB(AtkObject* aAtkObj)
+{
+ nsAutoString name;
+ AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj);
+ if (accWrap)
+ accWrap->Name(name);
+ else if (ProxyAccessible* proxy = GetProxy(aAtkObj))
+ proxy->Name(name);
+ else
+ return nullptr;
+
+ // XXX Firing an event from here does not seem right
+ MaybeFireNameChange(aAtkObj, name);
+
+ return aAtkObj->name;
+}
+
+static void
+MaybeFireNameChange(AtkObject* aAtkObj, const nsString& aNewName)
+{
+ NS_ConvertUTF16toUTF8 newNameUTF8(aNewName);
+ if (aAtkObj->name && !strcmp(aAtkObj->name, newNameUTF8.get()))
+ return;
+
+ // Below we duplicate the functionality of atk_object_set_name(),
+ // but without calling atk_object_get_name(). Instead of
+ // atk_object_get_name() we directly access aAtkObj->name. This is because
+ // atk_object_get_name() would call getNameCB() which would call
+ // MaybeFireNameChange() (or atk_object_set_name() before this problem was
+ // fixed) and we would get an infinite recursion.
+ // See http://bugzilla.mozilla.org/733712
+
+ // Do not notify for initial name setting.
+ // See bug http://bugzilla.gnome.org/665870
+ bool notify = !!aAtkObj->name;
+
+ free(aAtkObj->name);
+ aAtkObj->name = strdup(newNameUTF8.get());
+
+ if (notify)
+ g_object_notify(G_OBJECT(aAtkObj), "accessible-name");
+}
+
+const gchar *
+getDescriptionCB(AtkObject *aAtkObj)
+{
+ nsAutoString uniDesc;
+ AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj);
+ if (accWrap) {
+ if (accWrap->IsDefunct())
+ return nullptr;
+
+ accWrap->Description(uniDesc);
+ } else if (ProxyAccessible* proxy = GetProxy(aAtkObj)) {
+ proxy->Description(uniDesc);
+ } else {
+ return nullptr;
+ }
+
+ NS_ConvertUTF8toUTF16 objDesc(aAtkObj->description);
+ if (!uniDesc.Equals(objDesc))
+ atk_object_set_description(aAtkObj,
+ NS_ConvertUTF16toUTF8(uniDesc).get());
+
+ return aAtkObj->description;
+}
+
+AtkRole
+getRoleCB(AtkObject *aAtkObj)
+{
+ if (aAtkObj->role != ATK_ROLE_INVALID)
+ return aAtkObj->role;
+
+ AccessibleOrProxy acc = GetInternalObj(aAtkObj);
+ if (acc.IsNull()) {
+ return ATK_ROLE_INVALID;
+ }
+
+#ifdef DEBUG
+ if (AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj)) {
+ NS_ASSERTION(nsAccUtils::IsTextInterfaceSupportCorrect(accWrap),
+ "Does not support Text interface when it should");
+ }
+#endif
+
+#define ROLE(geckoRole, stringRole, atkRole, macRole, \
+ msaaRole, ia2Role, nameRule) \
+ case roles::geckoRole: \
+ aAtkObj->role = atkRole; \
+ break;
+
+ switch (acc.Role()) {
+#include "RoleMap.h"
+ default:
+ MOZ_CRASH("Unknown role.");
+ }
+
+#undef ROLE
+
+ if (aAtkObj->role == ATK_ROLE_LIST_BOX && !IsAtkVersionAtLeast(2, 1))
+ aAtkObj->role = ATK_ROLE_LIST;
+ else if (aAtkObj->role == ATK_ROLE_TABLE_ROW && !IsAtkVersionAtLeast(2, 1))
+ aAtkObj->role = ATK_ROLE_LIST_ITEM;
+ else if (aAtkObj->role == ATK_ROLE_MATH && !IsAtkVersionAtLeast(2, 12))
+ aAtkObj->role = ATK_ROLE_SECTION;
+ else if (aAtkObj->role == ATK_ROLE_STATIC && !IsAtkVersionAtLeast(2, 16))
+ aAtkObj->role = ATK_ROLE_TEXT;
+ else if ((aAtkObj->role == ATK_ROLE_MATH_FRACTION ||
+ aAtkObj->role == ATK_ROLE_MATH_ROOT) && !IsAtkVersionAtLeast(2, 16))
+ aAtkObj->role = ATK_ROLE_SECTION;
+
+ return aAtkObj->role;
+}
+
+static AtkAttributeSet*
+ConvertToAtkAttributeSet(nsIPersistentProperties* aAttributes)
+{
+ if (!aAttributes)
+ return nullptr;
+
+ AtkAttributeSet *objAttributeSet = nullptr;
+ nsCOMPtr<nsISimpleEnumerator> propEnum;
+ nsresult rv = aAttributes->Enumerate(getter_AddRefs(propEnum));
+ NS_ENSURE_SUCCESS(rv, nullptr);
+
+ bool hasMore;
+ while (NS_SUCCEEDED(propEnum->HasMoreElements(&hasMore)) && hasMore) {
+ nsCOMPtr<nsISupports> sup;
+ rv = propEnum->GetNext(getter_AddRefs(sup));
+ NS_ENSURE_SUCCESS(rv, objAttributeSet);
+
+ nsCOMPtr<nsIPropertyElement> propElem(do_QueryInterface(sup));
+ NS_ENSURE_TRUE(propElem, objAttributeSet);
+
+ nsAutoCString name;
+ rv = propElem->GetKey(name);
+ NS_ENSURE_SUCCESS(rv, objAttributeSet);
+
+ nsAutoString value;
+ rv = propElem->GetValue(value);
+ NS_ENSURE_SUCCESS(rv, objAttributeSet);
+
+ AtkAttribute *objAttr = (AtkAttribute *)g_malloc(sizeof(AtkAttribute));
+ objAttr->name = g_strdup(name.get());
+ objAttr->value = g_strdup(NS_ConvertUTF16toUTF8(value).get());
+ objAttributeSet = g_slist_prepend(objAttributeSet, objAttr);
+ }
+
+ //libspi will free it
+ return objAttributeSet;
+}
+
+AtkAttributeSet*
+GetAttributeSet(Accessible* aAccessible)
+{
+ nsCOMPtr<nsIPersistentProperties> attributes = aAccessible->Attributes();
+ if (attributes) {
+ // There is no ATK state for haspopup, must use object attribute to expose
+ // the same info.
+ if (aAccessible->State() & states::HASPOPUP) {
+ nsAutoString unused;
+ attributes->SetStringProperty(NS_LITERAL_CSTRING("haspopup"),
+ NS_LITERAL_STRING("true"), unused);
+ }
+
+ return ConvertToAtkAttributeSet(attributes);
+ }
+
+ return nullptr;
+}
+
+AtkAttributeSet *
+getAttributesCB(AtkObject *aAtkObj)
+{
+ AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj);
+ if (accWrap)
+ return GetAttributeSet(accWrap);
+
+ ProxyAccessible* proxy = GetProxy(aAtkObj);
+ if (!proxy)
+ return nullptr;
+
+ AutoTArray<Attribute, 10> attrs;
+ proxy->Attributes(&attrs);
+ if (attrs.IsEmpty())
+ return nullptr;
+
+ AtkAttributeSet* objAttributeSet = nullptr;
+ for (uint32_t i = 0; i < attrs.Length(); i++) {
+ AtkAttribute *objAttr = (AtkAttribute *)g_malloc(sizeof(AtkAttribute));
+ objAttr->name = g_strdup(attrs[i].Name().get());
+ objAttr->value = g_strdup(NS_ConvertUTF16toUTF8(attrs[i].Value()).get());
+ objAttributeSet = g_slist_prepend(objAttributeSet, objAttr);
+ }
+
+ return objAttributeSet;
+}
+
+const gchar*
+GetLocaleCB(AtkObject* aAtkObj)
+{
+ AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj);
+ if (!accWrap)
+ return nullptr;
+
+ nsAutoString locale;
+ accWrap->Language(locale);
+ return AccessibleWrap::ReturnString(locale);
+}
+
+AtkObject *
+getParentCB(AtkObject *aAtkObj)
+{
+ if (aAtkObj->accessible_parent)
+ return aAtkObj->accessible_parent;
+
+ AccessibleOrProxy acc = GetInternalObj(aAtkObj);
+ if (acc.IsNull()) {
+ return nullptr;
+ }
+
+ AccessibleOrProxy parent = acc.Parent();
+ AtkObject* atkParent = !parent.IsNull() ? GetWrapperFor(parent) : nullptr;
+ if (atkParent)
+ atk_object_set_parent(aAtkObj, atkParent);
+
+ return aAtkObj->accessible_parent;
+}
+
+gint
+getChildCountCB(AtkObject *aAtkObj)
+{
+ if (AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj)) {
+ if (nsAccUtils::MustPrune(accWrap)) {
+ return 0;
+ }
+
+ uint32_t count = accWrap->EmbeddedChildCount();
+ if (count) {
+ return static_cast<gint>(count);
+ }
+
+ OuterDocAccessible* outerDoc = accWrap->AsOuterDoc();
+ if (outerDoc && outerDoc->RemoteChildDoc()) {
+ return 1;
+ }
+ }
+
+ ProxyAccessible* proxy = GetProxy(aAtkObj);
+ if (proxy && !proxy->MustPruneChildren()) {
+ return proxy->EmbeddedChildCount();
+ }
+
+ return 0;
+}
+
+AtkObject *
+refChildCB(AtkObject *aAtkObj, gint aChildIndex)
+{
+ // aChildIndex should not be less than zero
+ if (aChildIndex < 0) {
+ return nullptr;
+ }
+
+ AtkObject* childAtkObj = nullptr;
+ AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj);
+ if (accWrap) {
+ if (nsAccUtils::MustPrune(accWrap)) {
+ return nullptr;
+ }
+
+ Accessible* accChild = accWrap->GetEmbeddedChildAt(aChildIndex);
+ if (accChild) {
+ childAtkObj = AccessibleWrap::GetAtkObject(accChild);
+ } else {
+ OuterDocAccessible* docOwner = accWrap->AsOuterDoc();
+ if (docOwner) {
+ ProxyAccessible* proxyDoc = docOwner->RemoteChildDoc();
+ if (proxyDoc)
+ childAtkObj = GetWrapperFor(proxyDoc);
+ }
+ }
+ } else if (ProxyAccessible* proxy = GetProxy(aAtkObj)) {
+ if (proxy->MustPruneChildren())
+ return nullptr;
+
+ ProxyAccessible* child = proxy->EmbeddedChildAt(aChildIndex);
+ if (child)
+ childAtkObj = GetWrapperFor(child);
+ } else {
+ return nullptr;
+ }
+
+ NS_ASSERTION(childAtkObj, "Fail to get AtkObj");
+ if (!childAtkObj)
+ return nullptr;
+
+ g_object_ref(childAtkObj);
+
+ if (aAtkObj != childAtkObj->accessible_parent)
+ atk_object_set_parent(childAtkObj, aAtkObj);
+
+ return childAtkObj;
+}
+
+gint
+getIndexInParentCB(AtkObject* aAtkObj)
+{
+ // We don't use Accessible::IndexInParent() because we don't include text
+ // leaf nodes as children in ATK.
+ if (ProxyAccessible* proxy = GetProxy(aAtkObj)) {
+ if (ProxyAccessible* parent = proxy->Parent())
+ return parent->IndexOfEmbeddedChild(proxy);
+
+ if (proxy->OuterDocOfRemoteBrowser())
+ return 0;
+
+ return -1;
+ }
+
+ AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj);
+ if (!accWrap) {
+ return -1;
+ }
+
+ Accessible* parent = accWrap->Parent();
+ if (!parent)
+ return -1; // No parent
+
+ return parent->GetIndexOfEmbeddedChild(accWrap);
+}
+
+static void
+TranslateStates(uint64_t aState, AtkStateSet* aStateSet)
+{
+ // atk doesn't have a read only state so read only things shouldn't be
+ // editable.
+ if (aState & states::READONLY)
+ aState &= ~states::EDITABLE;
+
+ // Convert every state to an entry in AtkStateMap
+ uint32_t stateIndex = 0;
+ uint64_t bitMask = 1;
+ while (gAtkStateMap[stateIndex].stateMapEntryType != kNoSuchState) {
+ if (gAtkStateMap[stateIndex].atkState) { // There's potentially an ATK state for this
+ bool isStateOn = (aState & bitMask) != 0;
+ if (gAtkStateMap[stateIndex].stateMapEntryType == kMapOpposite) {
+ isStateOn = !isStateOn;
+ }
+ if (isStateOn) {
+ atk_state_set_add_state(aStateSet, gAtkStateMap[stateIndex].atkState);
+ }
+ }
+ bitMask <<= 1;
+ ++ stateIndex;
+ }
+}
+
+AtkStateSet *
+refStateSetCB(AtkObject *aAtkObj)
+{
+ AtkStateSet *state_set = nullptr;
+ state_set = ATK_OBJECT_CLASS(parent_class)->ref_state_set(aAtkObj);
+
+ AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj);
+ if (accWrap)
+ TranslateStates(accWrap->State(), state_set);
+ else if (ProxyAccessible* proxy = GetProxy(aAtkObj))
+ TranslateStates(proxy->State(), state_set);
+ else
+ TranslateStates(states::DEFUNCT, state_set);
+
+ return state_set;
+}
+
+static void
+UpdateAtkRelation(RelationType aType, Accessible* aAcc,
+ AtkRelationType aAtkType, AtkRelationSet* aAtkSet)
+{
+ if (aAtkType == ATK_RELATION_NULL)
+ return;
+
+ AtkRelation* atkRelation =
+ atk_relation_set_get_relation_by_type(aAtkSet, aAtkType);
+ if (atkRelation)
+ atk_relation_set_remove(aAtkSet, atkRelation);
+
+ Relation rel(aAcc->RelationByType(aType));
+ nsTArray<AtkObject*> targets;
+ Accessible* tempAcc = nullptr;
+ while ((tempAcc = rel.Next()))
+ targets.AppendElement(AccessibleWrap::GetAtkObject(tempAcc));
+
+ if (aType == RelationType::EMBEDS && aAcc->IsRoot()) {
+ if (ProxyAccessible* proxyDoc =
+ aAcc->AsRoot()->GetPrimaryRemoteTopLevelContentDoc()) {
+ targets.AppendElement(GetWrapperFor(proxyDoc));
+ }
+ }
+
+ if (targets.Length()) {
+ atkRelation = atk_relation_new(targets.Elements(),
+ targets.Length(), aAtkType);
+ atk_relation_set_add(aAtkSet, atkRelation);
+ g_object_unref(atkRelation);
+ }
+}
+
+AtkRelationSet *
+refRelationSetCB(AtkObject *aAtkObj)
+{
+ AtkRelationSet* relation_set =
+ ATK_OBJECT_CLASS(parent_class)->ref_relation_set(aAtkObj);
+
+ const AtkRelationType typeMap[] = {
+#define RELATIONTYPE(gecko, s, atk, m, i) atk,
+#include "RelationTypeMap.h"
+#undef RELATIONTYPE
+ };
+
+ if (ProxyAccessible* proxy = GetProxy(aAtkObj)) {
+ nsTArray<RelationType> types;
+ nsTArray<nsTArray<ProxyAccessible*>> targetSets;
+ proxy->Relations(&types, &targetSets);
+
+ size_t relationCount = types.Length();
+ for (size_t i = 0; i < relationCount; i++) {
+ if (typeMap[static_cast<uint32_t>(types[i])] == ATK_RELATION_NULL)
+ continue;
+
+ size_t targetCount = targetSets[i].Length();
+ AutoTArray<AtkObject*, 5> wrappers;
+ for (size_t j = 0; j < targetCount; j++)
+ wrappers.AppendElement(GetWrapperFor(targetSets[i][j]));
+
+ AtkRelationType atkType = typeMap[static_cast<uint32_t>(types[i])];
+ AtkRelation* atkRelation =
+ atk_relation_set_get_relation_by_type(relation_set, atkType);
+ if (atkRelation)
+ atk_relation_set_remove(relation_set, atkRelation);
+
+ atkRelation = atk_relation_new(wrappers.Elements(), wrappers.Length(),
+ atkType);
+ atk_relation_set_add(relation_set, atkRelation);
+ g_object_unref(atkRelation);
+ }
+ }
+
+ AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj);
+ if (!accWrap)
+ return relation_set;
+
+#define RELATIONTYPE(geckoType, geckoTypeName, atkType, msaaType, ia2Type) \
+ UpdateAtkRelation(RelationType::geckoType, accWrap, atkType, relation_set);
+
+#include "RelationTypeMap.h"
+
+#undef RELATIONTYPE
+
+ return relation_set;
+}
+
+// Check if aAtkObj is a valid MaiAtkObject, and return the AccessibleWrap
+// for it.
+AccessibleWrap*
+GetAccessibleWrap(AtkObject* aAtkObj)
+{
+ bool isMAIObject = IS_MAI_OBJECT(aAtkObj);
+ NS_ENSURE_TRUE(isMAIObject || MAI_IS_ATK_SOCKET(aAtkObj),
+ nullptr);
+
+ AccessibleWrap* accWrap = nullptr;
+ if (isMAIObject) {
+ Accessible* acc = MAI_ATK_OBJECT(aAtkObj)->accWrap.AsAccessible();
+ accWrap = static_cast<AccessibleWrap*>(acc);
+ } else {
+ accWrap = MAI_ATK_SOCKET(aAtkObj)->accWrap;
+ }
+
+ // Check if the accessible was deconstructed.
+ if (!accWrap)
+ return nullptr;
+
+ NS_ENSURE_TRUE(accWrap->GetAtkObject() == aAtkObj, nullptr);
+
+ AccessibleWrap* appAccWrap = ApplicationAcc();
+ if (appAccWrap != accWrap && !accWrap->IsValidObject())
+ return nullptr;
+
+ return accWrap;
+}
+
+ProxyAccessible*
+GetProxy(AtkObject* aObj)
+{
+ return GetInternalObj(aObj).AsProxy();
+}
+
+AccessibleOrProxy
+GetInternalObj(AtkObject* aObj)
+{
+ if (!aObj || !IS_MAI_OBJECT(aObj))
+ return nullptr;
+
+ return MAI_ATK_OBJECT(aObj)->accWrap;
+}
+
+AtkObject*
+GetWrapperFor(ProxyAccessible* aProxy)
+{
+ return reinterpret_cast<AtkObject*>(aProxy->GetWrapper() & ~IS_PROXY);
+}
+
+AtkObject*
+GetWrapperFor(AccessibleOrProxy aObj)
+{
+ if (aObj.IsProxy()) {
+ return GetWrapperFor(aObj.AsProxy());
+ }
+
+ return AccessibleWrap::GetAtkObject(aObj.AsAccessible());
+}
+
+static uint16_t
+GetInterfacesForProxy(ProxyAccessible* aProxy, uint32_t aInterfaces)
+{
+ uint16_t interfaces = 1 << MAI_INTERFACE_COMPONENT;
+ if (aInterfaces & Interfaces::HYPERTEXT)
+ interfaces |= (1 << MAI_INTERFACE_HYPERTEXT) | (1 << MAI_INTERFACE_TEXT)
+ | (1 << MAI_INTERFACE_EDITABLE_TEXT);
+
+ if (aInterfaces & Interfaces::HYPERLINK)
+ interfaces |= 1 << MAI_INTERFACE_HYPERLINK_IMPL;
+
+ if (aInterfaces & Interfaces::VALUE)
+ interfaces |= 1 << MAI_INTERFACE_VALUE;
+
+ if (aInterfaces & Interfaces::TABLE)
+ interfaces |= 1 << MAI_INTERFACE_TABLE;
+
+ if (aInterfaces & Interfaces::TABLECELL)
+ interfaces |= 1 << MAI_INTERFACE_TABLE_CELL;
+
+ if (aInterfaces & Interfaces::IMAGE)
+ interfaces |= 1 << MAI_INTERFACE_IMAGE;
+
+ if (aInterfaces & Interfaces::DOCUMENT)
+ interfaces |= 1 << MAI_INTERFACE_DOCUMENT;
+
+ if (aInterfaces & Interfaces::SELECTION) {
+ interfaces |= 1 << MAI_INTERFACE_SELECTION;
+ }
+
+ if (aInterfaces & Interfaces::ACTION) {
+ interfaces |= 1 << MAI_INTERFACE_ACTION;
+ }
+
+ return interfaces;
+}
+
+void
+a11y::ProxyCreated(ProxyAccessible* aProxy, uint32_t aInterfaces)
+{
+ GType type = GetMaiAtkType(GetInterfacesForProxy(aProxy, aInterfaces));
+ NS_ASSERTION(type, "why don't we have a type!");
+
+ AtkObject* obj =
+ reinterpret_cast<AtkObject *>
+ (g_object_new(type, nullptr));
+ if (!obj)
+ return;
+
+ uintptr_t inner = reinterpret_cast<uintptr_t>(aProxy) | IS_PROXY;
+ atk_object_initialize(obj, reinterpret_cast<gpointer>(inner));
+ obj->role = ATK_ROLE_INVALID;
+ obj->layer = ATK_LAYER_INVALID;
+ aProxy->SetWrapper(reinterpret_cast<uintptr_t>(obj) | IS_PROXY);
+}
+
+void
+a11y::ProxyDestroyed(ProxyAccessible* aProxy)
+{
+ auto obj = reinterpret_cast<MaiAtkObject*>(aProxy->GetWrapper() & ~IS_PROXY);
+ if (!obj) {
+ return;
+ }
+
+ obj->Shutdown();
+ g_object_unref(obj);
+ aProxy->SetWrapper(0);
+}
+
+nsresult
+AccessibleWrap::HandleAccEvent(AccEvent* aEvent)
+{
+ nsresult rv = Accessible::HandleAccEvent(aEvent);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (IPCAccessibilityActive()) {
+ return NS_OK;
+ }
+
+ Accessible* accessible = aEvent->GetAccessible();
+ NS_ENSURE_TRUE(accessible, NS_ERROR_FAILURE);
+
+ // The accessible can become defunct if we have an xpcom event listener
+ // which decides it would be fun to change the DOM and flush layout.
+ if (accessible->IsDefunct())
+ return NS_OK;
+
+ uint32_t type = aEvent->GetEventType();
+
+ AtkObject* atkObj = AccessibleWrap::GetAtkObject(accessible);
+
+ // We don't create ATK objects for plain text leaves, just return NS_OK in
+ // such case.
+ if (!atkObj) {
+ NS_ASSERTION(type == nsIAccessibleEvent::EVENT_SHOW ||
+ type == nsIAccessibleEvent::EVENT_HIDE,
+ "Event other than SHOW and HIDE fired for plain text leaves");
+ return NS_OK;
+ }
+
+ AccessibleWrap* accWrap = GetAccessibleWrap(atkObj);
+ if (!accWrap) {
+ return NS_OK; // Node is shut down
+ }
+
+ switch (type) {
+ case nsIAccessibleEvent::EVENT_STATE_CHANGE:
+ {
+ AccStateChangeEvent* event = downcast_accEvent(aEvent);
+ MAI_ATK_OBJECT(atkObj)->FireStateChangeEvent(event->GetState(),
+ event->IsStateEnabled());
+ break;
+ }
+
+ case nsIAccessibleEvent::EVENT_TEXT_REMOVED:
+ case nsIAccessibleEvent::EVENT_TEXT_INSERTED:
+ {
+ AccTextChangeEvent* event = downcast_accEvent(aEvent);
+ NS_ENSURE_TRUE(event, NS_ERROR_FAILURE);
+
+ MAI_ATK_OBJECT(atkObj)-> FireTextChangeEvent(event->ModifiedText(),
+ event->GetStartOffset(),
+ event->GetLength(),
+ event->IsTextInserted(),
+ event->IsFromUserInput());
+
+ return NS_OK;
+ }
+
+ case nsIAccessibleEvent::EVENT_FOCUS:
+ {
+ a11y::RootAccessible* rootAccWrap = accWrap->RootAccessible();
+ if (rootAccWrap && rootAccWrap->mActivated) {
+ atk_focus_tracker_notify(atkObj);
+ // Fire state change event for focus
+ atk_object_notify_state_change(atkObj, ATK_STATE_FOCUSED, true);
+ return NS_OK;
+ }
+ } break;
+
+ case nsIAccessibleEvent::EVENT_NAME_CHANGE:
+ {
+ nsAutoString newName;
+ accessible->Name(newName);
+
+ MaybeFireNameChange(atkObj, newName);
+
+ break;
+ }
+
+ case nsIAccessibleEvent::EVENT_VALUE_CHANGE:
+ case nsIAccessibleEvent::EVENT_TEXT_VALUE_CHANGE:
+ if (accessible->HasNumericValue()) {
+ // Make sure this is a numeric value. Don't fire for string value changes
+ // (e.g. text editing) ATK values are always numeric.
+ g_object_notify((GObject*)atkObj, "accessible-value");
+ }
+ break;
+
+ case nsIAccessibleEvent::EVENT_SELECTION:
+ case nsIAccessibleEvent::EVENT_SELECTION_ADD:
+ case nsIAccessibleEvent::EVENT_SELECTION_REMOVE:
+ {
+ // XXX: dupe events may be fired
+ AccSelChangeEvent* selChangeEvent = downcast_accEvent(aEvent);
+ g_signal_emit_by_name(AccessibleWrap::GetAtkObject(selChangeEvent->Widget()),
+ "selection_changed");
+ break;
+ }
+
+ case nsIAccessibleEvent::EVENT_SELECTION_WITHIN:
+ {
+ g_signal_emit_by_name(atkObj, "selection_changed");
+ break;
+ }
+
+ case nsIAccessibleEvent::EVENT_ALERT:
+ // A hack using state change showing events as alert events.
+ atk_object_notify_state_change(atkObj, ATK_STATE_SHOWING, true);
+ break;
+
+ case nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED:
+ g_signal_emit_by_name(atkObj, "text_selection_changed");
+ break;
+
+ case nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED:
+ {
+ AccCaretMoveEvent* caretMoveEvent = downcast_accEvent(aEvent);
+ NS_ASSERTION(caretMoveEvent, "Event needs event data");
+ if (!caretMoveEvent)
+ break;
+
+ int32_t caretOffset = caretMoveEvent->GetCaretOffset();
+ g_signal_emit_by_name(atkObj, "text_caret_moved", caretOffset);
+ } break;
+
+ case nsIAccessibleEvent::EVENT_TEXT_ATTRIBUTE_CHANGED:
+ g_signal_emit_by_name(atkObj, "text-attributes-changed");
+ break;
+
+ case nsIAccessibleEvent::EVENT_TABLE_MODEL_CHANGED:
+ g_signal_emit_by_name(atkObj, "model_changed");
+ break;
+
+ case nsIAccessibleEvent::EVENT_TABLE_ROW_INSERT:
+ {
+ AccTableChangeEvent* tableEvent = downcast_accEvent(aEvent);
+ NS_ENSURE_TRUE(tableEvent, NS_ERROR_FAILURE);
+
+ int32_t rowIndex = tableEvent->GetIndex();
+ int32_t numRows = tableEvent->GetCount();
+
+ g_signal_emit_by_name(atkObj, "row_inserted", rowIndex, numRows);
+ } break;
+
+ case nsIAccessibleEvent::EVENT_TABLE_ROW_DELETE:
+ {
+ AccTableChangeEvent* tableEvent = downcast_accEvent(aEvent);
+ NS_ENSURE_TRUE(tableEvent, NS_ERROR_FAILURE);
+
+ int32_t rowIndex = tableEvent->GetIndex();
+ int32_t numRows = tableEvent->GetCount();
+
+ g_signal_emit_by_name(atkObj, "row_deleted", rowIndex, numRows);
+ } break;
+
+ case nsIAccessibleEvent::EVENT_TABLE_ROW_REORDER:
+ {
+ g_signal_emit_by_name(atkObj, "row_reordered");
+ break;
+ }
+
+ case nsIAccessibleEvent::EVENT_TABLE_COLUMN_INSERT:
+ {
+ AccTableChangeEvent* tableEvent = downcast_accEvent(aEvent);
+ NS_ENSURE_TRUE(tableEvent, NS_ERROR_FAILURE);
+
+ int32_t colIndex = tableEvent->GetIndex();
+ int32_t numCols = tableEvent->GetCount();
+ g_signal_emit_by_name(atkObj, "column_inserted", colIndex, numCols);
+ } break;
+
+ case nsIAccessibleEvent::EVENT_TABLE_COLUMN_DELETE:
+ {
+ AccTableChangeEvent* tableEvent = downcast_accEvent(aEvent);
+ NS_ENSURE_TRUE(tableEvent, NS_ERROR_FAILURE);
+
+ int32_t colIndex = tableEvent->GetIndex();
+ int32_t numCols = tableEvent->GetCount();
+ g_signal_emit_by_name(atkObj, "column_deleted", colIndex, numCols);
+ } break;
+
+ case nsIAccessibleEvent::EVENT_TABLE_COLUMN_REORDER:
+ g_signal_emit_by_name(atkObj, "column_reordered");
+ break;
+
+ case nsIAccessibleEvent::EVENT_SECTION_CHANGED:
+ g_signal_emit_by_name(atkObj, "visible_data_changed");
+ break;
+
+ case nsIAccessibleEvent::EVENT_SHOW:
+ {
+ AccMutationEvent* event = downcast_accEvent(aEvent);
+ Accessible* parentAcc = event ? event->Parent() : accessible->Parent();
+ AtkObject* parent = AccessibleWrap::GetAtkObject(parentAcc);
+ NS_ENSURE_STATE(parent);
+ auto obj = reinterpret_cast<MaiAtkObject*>(atkObj);
+ obj->FireAtkShowHideEvent(parent, true, aEvent->IsFromUserInput());
+ return NS_OK;
+ }
+
+ case nsIAccessibleEvent::EVENT_HIDE:
+ {
+ // XXX - Handle native dialog accessibles.
+ if (!accessible->IsRoot() && accessible->HasARIARole() &&
+ accessible->ARIARole() == roles::DIALOG) {
+ guint id = g_signal_lookup("deactivate", MAI_TYPE_ATK_OBJECT);
+ g_signal_emit(atkObj, id, 0);
+ }
+
+ AccMutationEvent* event = downcast_accEvent(aEvent);
+ Accessible* parentAcc = event ? event->Parent() : accessible->Parent();
+ AtkObject* parent = AccessibleWrap::GetAtkObject(parentAcc);
+ NS_ENSURE_STATE(parent);
+ auto obj = reinterpret_cast<MaiAtkObject*>(atkObj);
+ obj->FireAtkShowHideEvent(parent, false, aEvent->IsFromUserInput());
+ return NS_OK;
+ }
+
+ /*
+ * Because dealing with menu is very different between nsIAccessible
+ * and ATK, and the menu activity is important, specially transfer the
+ * following two event.
+ * Need more verification by AT test.
+ */
+ case nsIAccessibleEvent::EVENT_MENU_START:
+ case nsIAccessibleEvent::EVENT_MENU_END:
+ break;
+
+ case nsIAccessibleEvent::EVENT_WINDOW_ACTIVATE:
+ {
+ accessible->AsRoot()->mActivated = true;
+ guint id = g_signal_lookup("activate", MAI_TYPE_ATK_OBJECT);
+ g_signal_emit(atkObj, id, 0);
+
+ // Always fire a current focus event after activation.
+ FocusMgr()->ForceFocusEvent();
+ } break;
+
+ case nsIAccessibleEvent::EVENT_WINDOW_DEACTIVATE:
+ {
+ accessible->AsRoot()->mActivated = false;
+ guint id = g_signal_lookup("deactivate", MAI_TYPE_ATK_OBJECT);
+ g_signal_emit(atkObj, id, 0);
+ } break;
+
+ case nsIAccessibleEvent::EVENT_WINDOW_MAXIMIZE:
+ {
+ guint id = g_signal_lookup("maximize", MAI_TYPE_ATK_OBJECT);
+ g_signal_emit(atkObj, id, 0);
+ } break;
+
+ case nsIAccessibleEvent::EVENT_WINDOW_MINIMIZE:
+ {
+ guint id = g_signal_lookup("minimize", MAI_TYPE_ATK_OBJECT);
+ g_signal_emit(atkObj, id, 0);
+ } break;
+
+ case nsIAccessibleEvent::EVENT_WINDOW_RESTORE:
+ {
+ guint id = g_signal_lookup("restore", MAI_TYPE_ATK_OBJECT);
+ g_signal_emit(atkObj, id, 0);
+ } break;
+
+ case nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_COMPLETE:
+ g_signal_emit_by_name (atkObj, "load_complete");
+ // XXX - Handle native dialog accessibles.
+ if (!accessible->IsRoot() && accessible->HasARIARole() &&
+ accessible->ARIARole() == roles::DIALOG) {
+ guint id = g_signal_lookup("activate", MAI_TYPE_ATK_OBJECT);
+ g_signal_emit(atkObj, id, 0);
+ }
+ break;
+
+ case nsIAccessibleEvent::EVENT_DOCUMENT_RELOAD:
+ g_signal_emit_by_name (atkObj, "reload");
+ break;
+
+ case nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_STOPPED:
+ g_signal_emit_by_name (atkObj, "load_stopped");
+ break;
+
+ case nsIAccessibleEvent::EVENT_MENUPOPUP_START:
+ atk_focus_tracker_notify(atkObj); // fire extra focus event
+ atk_object_notify_state_change(atkObj, ATK_STATE_VISIBLE, true);
+ atk_object_notify_state_change(atkObj, ATK_STATE_SHOWING, true);
+ break;
+
+ case nsIAccessibleEvent::EVENT_MENUPOPUP_END:
+ atk_object_notify_state_change(atkObj, ATK_STATE_VISIBLE, false);
+ atk_object_notify_state_change(atkObj, ATK_STATE_SHOWING, false);
+ break;
+ }
+
+ return NS_OK;
+}
+
+void
+a11y::ProxyEvent(ProxyAccessible* aTarget, uint32_t aEventType)
+{
+ AtkObject* wrapper = GetWrapperFor(aTarget);
+
+ switch (aEventType) {
+ case nsIAccessibleEvent::EVENT_FOCUS:
+ atk_focus_tracker_notify(wrapper);
+ atk_object_notify_state_change(wrapper, ATK_STATE_FOCUSED, true);
+ break;
+ case nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_COMPLETE:
+ g_signal_emit_by_name(wrapper, "load_complete");
+ break;
+ case nsIAccessibleEvent::EVENT_DOCUMENT_RELOAD:
+ g_signal_emit_by_name(wrapper, "reload");
+ break;
+ case nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_STOPPED:
+ g_signal_emit_by_name(wrapper, "load_stopped");
+ break;
+ case nsIAccessibleEvent::EVENT_MENUPOPUP_START:
+ atk_focus_tracker_notify(wrapper); // fire extra focus event
+ atk_object_notify_state_change(wrapper, ATK_STATE_VISIBLE, true);
+ atk_object_notify_state_change(wrapper, ATK_STATE_SHOWING, true);
+ break;
+ case nsIAccessibleEvent::EVENT_MENUPOPUP_END:
+ atk_object_notify_state_change(wrapper, ATK_STATE_VISIBLE, false);
+ atk_object_notify_state_change(wrapper, ATK_STATE_SHOWING, false);
+ break;
+ case nsIAccessibleEvent::EVENT_ALERT:
+ // A hack using state change showing events as alert events.
+ atk_object_notify_state_change(wrapper, ATK_STATE_SHOWING, true);
+ break;
+ case nsIAccessibleEvent::EVENT_VALUE_CHANGE:
+ g_object_notify((GObject*)wrapper, "accessible-value");
+ break;
+ case nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED:
+ case nsIAccessibleEvent::EVENT_SELECTION_WITHIN:
+ g_signal_emit_by_name(wrapper, "selection_changed");
+ break;
+ }
+}
+
+void
+a11y::ProxyStateChangeEvent(ProxyAccessible* aTarget, uint64_t aState,
+ bool aEnabled)
+{
+ MaiAtkObject* atkObj = MAI_ATK_OBJECT(GetWrapperFor(aTarget));
+ atkObj->FireStateChangeEvent(aState, aEnabled);
+}
+
+void
+a11y::ProxyCaretMoveEvent(ProxyAccessible* aTarget, int32_t aOffset)
+{
+ AtkObject* wrapper = GetWrapperFor(aTarget);
+ g_signal_emit_by_name(wrapper, "text_caret_moved", aOffset);
+}
+
+void
+MaiAtkObject::FireStateChangeEvent(uint64_t aState, bool aEnabled)
+{
+ int32_t stateIndex = AtkStateMap::GetStateIndexFor(aState);
+ if (stateIndex >= 0) {
+ NS_ASSERTION(gAtkStateMap[stateIndex].stateMapEntryType != kNoSuchState,
+ "No such state");
+
+ if (gAtkStateMap[stateIndex].atkState != kNone) {
+ NS_ASSERTION(gAtkStateMap[stateIndex].stateMapEntryType != kNoStateChange,
+ "State changes should not fired for this state");
+
+ if (gAtkStateMap[stateIndex].stateMapEntryType == kMapOpposite)
+ aEnabled = !aEnabled;
+
+ // Fire state change for first state if there is one to map
+ atk_object_notify_state_change(&parent,
+ gAtkStateMap[stateIndex].atkState,
+ aEnabled);
+ }
+ }
+}
+
+void
+a11y::ProxyTextChangeEvent(ProxyAccessible* aTarget, const nsString& aStr,
+ int32_t aStart, uint32_t aLen, bool aIsInsert,
+ bool aFromUser)
+{
+ MaiAtkObject* atkObj = MAI_ATK_OBJECT(GetWrapperFor(aTarget));
+ atkObj->FireTextChangeEvent(aStr, aStart, aLen, aIsInsert, aFromUser);
+}
+
+#define OLD_TEXT_INSERTED "text_changed::insert"
+#define OLD_TEXT_REMOVED "text_changed::delete"
+static const char* oldTextChangeStrings[2][2] = {
+ { OLD_TEXT_REMOVED NON_USER_EVENT, OLD_TEXT_INSERTED NON_USER_EVENT },
+ { OLD_TEXT_REMOVED, OLD_TEXT_INSERTED }
+};
+
+#define TEXT_INSERTED "text-insert"
+#define TEXT_REMOVED "text-remove"
+#define NON_USER_DETAIL "::system"
+static const char* textChangedStrings[2][2] = {
+ { TEXT_REMOVED NON_USER_DETAIL, TEXT_INSERTED NON_USER_DETAIL },
+ { TEXT_REMOVED, TEXT_INSERTED}
+};
+
+void
+MaiAtkObject::FireTextChangeEvent(const nsString& aStr, int32_t aStart,
+ uint32_t aLen, bool aIsInsert,
+ bool aFromUser)
+{
+ if (gAvailableAtkSignals == eUnknown)
+ gAvailableAtkSignals =
+ g_signal_lookup("text-insert", G_OBJECT_TYPE(this)) ?
+ eHaveNewAtkTextSignals : eNoNewAtkSignals;
+
+ if (gAvailableAtkSignals == eNoNewAtkSignals) {
+ // XXX remove this code and the gHaveNewTextSignals check when we can
+ // stop supporting old atk since it doesn't really work anyway
+ // see bug 619002
+ const char* signal_name =
+ oldTextChangeStrings[aFromUser][aIsInsert];
+ g_signal_emit_by_name(this, signal_name, aStart, aLen);
+ } else {
+ const char* signal_name =
+ textChangedStrings[aFromUser][aIsInsert];
+ g_signal_emit_by_name(this, signal_name, aStart, aLen,
+ NS_ConvertUTF16toUTF8(aStr).get());
+ }
+}
+
+void
+a11y::ProxyShowHideEvent(ProxyAccessible* aTarget, ProxyAccessible* aParent,
+ bool aInsert, bool aFromUser)
+{
+ MaiAtkObject* obj = MAI_ATK_OBJECT(GetWrapperFor(aTarget));
+ obj->FireAtkShowHideEvent(GetWrapperFor(aParent), aInsert, aFromUser);
+}
+
+#define ADD_EVENT "children_changed::add"
+#define HIDE_EVENT "children_changed::remove"
+
+static const char *kMutationStrings[2][2] = {
+ { HIDE_EVENT NON_USER_EVENT, ADD_EVENT NON_USER_EVENT },
+ { HIDE_EVENT, ADD_EVENT },
+};
+
+void
+MaiAtkObject::FireAtkShowHideEvent(AtkObject* aParent, bool aIsAdded,
+ bool aFromUser)
+{
+ int32_t indexInParent = getIndexInParentCB(&this->parent);
+ const char *signal_name = kMutationStrings[aFromUser][aIsAdded];
+ g_signal_emit_by_name(aParent, signal_name, indexInParent, this, nullptr);
+}
+
+void
+a11y::ProxySelectionEvent(ProxyAccessible*, ProxyAccessible* aWidget, uint32_t)
+{
+ MaiAtkObject* obj = MAI_ATK_OBJECT(GetWrapperFor(aWidget));
+ g_signal_emit_by_name(obj, "selection_changed");
+}
+
+// static
+void
+AccessibleWrap::GetKeyBinding(Accessible* aAccessible, nsAString& aResult)
+{
+ // Return all key bindings including access key and keyboard shortcut.
+
+ // Get access key.
+ nsAutoString keyBindingsStr;
+ KeyBinding keyBinding = aAccessible->AccessKey();
+ if (!keyBinding.IsEmpty()) {
+ keyBinding.AppendToString(keyBindingsStr, KeyBinding::eAtkFormat);
+
+ Accessible* parent = aAccessible->Parent();
+ roles::Role role = parent ? parent->Role() : roles::NOTHING;
+ if (role == roles::PARENT_MENUITEM || role == roles::MENUITEM ||
+ role == roles::RADIO_MENU_ITEM || role == roles::CHECK_MENU_ITEM) {
+ // It is submenu, expose keyboard shortcuts from menu hierarchy like
+ // "s;<Alt>f:s"
+ nsAutoString keysInHierarchyStr = keyBindingsStr;
+ do {
+ KeyBinding parentKeyBinding = parent->AccessKey();
+ if (!parentKeyBinding.IsEmpty()) {
+ nsAutoString str;
+ parentKeyBinding.ToString(str, KeyBinding::eAtkFormat);
+ str.Append(':');
+
+ keysInHierarchyStr.Insert(str, 0);
+ }
+ } while ((parent = parent->Parent()) && parent->Role() != roles::MENUBAR);
+
+ keyBindingsStr.Append(';');
+ keyBindingsStr.Append(keysInHierarchyStr);
+ }
+ } else {
+ // No access key, add ';' to point this.
+ keyBindingsStr.Append(';');
+ }
+
+ // Get keyboard shortcut.
+ keyBindingsStr.Append(';');
+ keyBinding = aAccessible->KeyboardShortcut();
+ if (!keyBinding.IsEmpty()) {
+ keyBinding.AppendToString(keyBindingsStr, KeyBinding::eAtkFormat);
+ }
+ aResult = keyBindingsStr;
+}
+
+// static
+Accessible*
+AccessibleWrap::GetColumnHeader(TableAccessible* aAccessible, int32_t aColIdx)
+{
+ if (!aAccessible) {
+ return nullptr;
+ }
+
+ Accessible* cell = aAccessible->CellAt(0, aColIdx);
+ if (!cell) {
+ return nullptr;
+ }
+
+ // If the cell at the first row is column header then assume it is column
+ // header for all rows,
+ if (cell->Role() == roles::COLUMNHEADER) {
+ return cell;
+ }
+
+ // otherwise get column header for the data cell at the first row.
+ TableCellAccessible* tableCell = cell->AsTableCell();
+ if (!tableCell) {
+ return nullptr;
+ }
+
+ AutoTArray<Accessible*, 10> headerCells;
+ tableCell->ColHeaderCells(&headerCells);
+ if (headerCells.IsEmpty()) {
+ return nullptr;
+ }
+
+ return headerCells[0];
+}
+
+// static
+Accessible*
+AccessibleWrap::GetRowHeader(TableAccessible* aAccessible, int32_t aRowIdx)
+{
+ if (!aAccessible) {
+ return nullptr;
+ }
+
+ Accessible* cell = aAccessible->CellAt(aRowIdx, 0);
+ if (!cell) {
+ return nullptr;
+ }
+
+ // If the cell at the first column is row header then assume it is row
+ // header for all columns,
+ if (cell->Role() == roles::ROWHEADER) {
+ return cell;
+ }
+
+ // otherwise get row header for the data cell at the first column.
+ TableCellAccessible* tableCell = cell->AsTableCell();
+ if (!tableCell) {
+ return nullptr;
+ }
+
+ AutoTArray<Accessible*, 10> headerCells;
+ tableCell->RowHeaderCells(&headerCells);
+ if (headerCells.IsEmpty()) {
+ return nullptr;
+ }
+
+ return headerCells[0];
+}
diff --git a/accessible/atk/AccessibleWrap.h b/accessible/atk/AccessibleWrap.h
new file mode 100644
index 0000000000..f73d2f0f48
--- /dev/null
+++ b/accessible/atk/AccessibleWrap.h
@@ -0,0 +1,92 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef __NS_ACCESSIBLE_WRAP_H__
+#define __NS_ACCESSIBLE_WRAP_H__
+
+#include "nsCOMPtr.h"
+#include "Accessible.h"
+
+struct _AtkObject;
+typedef struct _AtkObject AtkObject;
+
+enum AtkProperty {
+ PROP_0, // gobject convention
+ PROP_NAME,
+ PROP_DESCRIPTION,
+ PROP_PARENT, // ancestry has changed
+ PROP_ROLE,
+ PROP_LAYER,
+ PROP_MDI_ZORDER,
+ PROP_TABLE_CAPTION,
+ PROP_TABLE_COLUMN_DESCRIPTION,
+ PROP_TABLE_COLUMN_HEADER,
+ PROP_TABLE_ROW_DESCRIPTION,
+ PROP_TABLE_ROW_HEADER,
+ PROP_TABLE_SUMMARY,
+ PROP_LAST // gobject convention
+};
+
+struct AtkPropertyChange {
+ int32_t type; // property type as listed above
+ void *oldvalue;
+ void *newvalue;
+};
+
+namespace mozilla {
+namespace a11y {
+
+class MaiHyperlink;
+
+/**
+ * AccessibleWrap, and its descendents in atk directory provide the
+ * implementation of AtkObject.
+ */
+class AccessibleWrap : public Accessible
+{
+public:
+ AccessibleWrap(nsIContent* aContent, DocAccessible* aDoc);
+ virtual ~AccessibleWrap();
+ void ShutdownAtkObject();
+
+ virtual void Shutdown() override;
+
+ // return the atk object for this AccessibleWrap
+ virtual void GetNativeInterface(void** aOutAccessible) override;
+ virtual nsresult HandleAccEvent(AccEvent* aEvent) override;
+
+ AtkObject * GetAtkObject(void);
+ static AtkObject* GetAtkObject(Accessible* aAccessible);
+
+ bool IsValidObject();
+
+ static const char * ReturnString(nsAString &aString) {
+ static nsCString returnedString;
+ returnedString = NS_ConvertUTF16toUTF8(aString);
+ return returnedString.get();
+ }
+
+ static void GetKeyBinding(Accessible* aAccessible, nsAString& aResult);
+
+ static Accessible* GetColumnHeader(TableAccessible* aAccessible,
+ int32_t aColIdx);
+ static Accessible* GetRowHeader(TableAccessible* aAccessible,
+ int32_t aRowIdx);
+protected:
+
+ nsresult FireAtkStateChangeEvent(AccEvent* aEvent, AtkObject *aObject);
+ nsresult FireAtkTextChangedEvent(AccEvent* aEvent, AtkObject *aObject);
+
+ AtkObject *mAtkObject;
+
+private:
+ uint16_t CreateMaiInterfaces();
+};
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif /* __NS_ACCESSIBLE_WRAP_H__ */
diff --git a/accessible/atk/ApplicationAccessibleWrap.cpp b/accessible/atk/ApplicationAccessibleWrap.cpp
new file mode 100644
index 0000000000..011881023c
--- /dev/null
+++ b/accessible/atk/ApplicationAccessibleWrap.cpp
@@ -0,0 +1,167 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "ApplicationAccessibleWrap.h"
+
+#include "nsCOMPtr.h"
+#include "nsMai.h"
+#include "nsAccessibilityService.h"
+
+#include <gtk/gtk.h>
+#include <atk/atk.h>
+
+using namespace mozilla;
+using namespace mozilla::a11y;
+
+
+// ApplicationAccessibleWrap
+
+ApplicationAccessibleWrap::ApplicationAccessibleWrap():
+ ApplicationAccessible()
+{
+}
+
+ApplicationAccessibleWrap::~ApplicationAccessibleWrap()
+{
+ AccessibleWrap::ShutdownAtkObject();
+}
+
+gboolean
+toplevel_event_watcher(GSignalInvocationHint* ihint,
+ guint n_param_values,
+ const GValue* param_values,
+ gpointer data)
+{
+ static GQuark sQuark_gecko_acc_obj = 0;
+
+ if (!sQuark_gecko_acc_obj)
+ sQuark_gecko_acc_obj = g_quark_from_static_string("GeckoAccObj");
+
+ if (nsAccessibilityService::IsShutdown())
+ return TRUE;
+
+ GObject* object = reinterpret_cast<GObject*>(g_value_get_object(param_values));
+ if (!GTK_IS_WINDOW(object))
+ return TRUE;
+
+ AtkObject* child = gtk_widget_get_accessible(GTK_WIDGET(object));
+
+ // GTK native dialog
+ if (!IS_MAI_OBJECT(child) &&
+ (atk_object_get_role(child) == ATK_ROLE_DIALOG)) {
+
+ if (data == reinterpret_cast<gpointer>(nsIAccessibleEvent::EVENT_SHOW)) {
+
+ // Attach the dialog accessible to app accessible tree
+ Accessible* windowAcc = GetAccService()->AddNativeRootAccessible(child);
+ g_object_set_qdata(G_OBJECT(child), sQuark_gecko_acc_obj,
+ reinterpret_cast<gpointer>(windowAcc));
+
+ } else {
+
+ // Deattach the dialog accessible
+ Accessible* windowAcc =
+ reinterpret_cast<Accessible*>
+ (g_object_get_qdata(G_OBJECT(child), sQuark_gecko_acc_obj));
+ if (windowAcc) {
+ GetAccService()->RemoveNativeRootAccessible(windowAcc);
+ g_object_set_qdata(G_OBJECT(child), sQuark_gecko_acc_obj, nullptr);
+ }
+
+ }
+ }
+
+ return TRUE;
+}
+
+ENameValueFlag
+ApplicationAccessibleWrap::Name(nsString& aName)
+{
+ // ATK doesn't provide a way to obtain an application name (for example,
+ // Firefox or Thunderbird) like IA2 does. Thus let's return an application
+ // name as accessible name that was used to get a branding name (for example,
+ // Minefield aka nightly Firefox or Daily aka nightly Thunderbird).
+ AppName(aName);
+ return eNameOK;
+}
+
+void
+ApplicationAccessibleWrap::GetNativeInterface(void** aOutAccessible)
+{
+ *aOutAccessible = nullptr;
+
+ if (!mAtkObject) {
+ mAtkObject =
+ reinterpret_cast<AtkObject*>(g_object_new(MAI_TYPE_ATK_OBJECT, nullptr));
+ if (!mAtkObject)
+ return;
+
+ atk_object_initialize(mAtkObject, this);
+ mAtkObject->role = ATK_ROLE_INVALID;
+ mAtkObject->layer = ATK_LAYER_INVALID;
+ }
+
+ *aOutAccessible = mAtkObject;
+}
+
+struct AtkRootAccessibleAddedEvent {
+ AtkObject *app_accessible;
+ AtkObject *root_accessible;
+ uint32_t index;
+};
+
+gboolean fireRootAccessibleAddedCB(gpointer data)
+{
+ AtkRootAccessibleAddedEvent* eventData = (AtkRootAccessibleAddedEvent*)data;
+ g_signal_emit_by_name(eventData->app_accessible, "children_changed::add",
+ eventData->index, eventData->root_accessible, nullptr);
+ g_object_unref(eventData->app_accessible);
+ g_object_unref(eventData->root_accessible);
+ free(data);
+
+ return FALSE;
+}
+
+bool
+ApplicationAccessibleWrap::InsertChildAt(uint32_t aIdx, Accessible* aChild)
+{
+ if (!ApplicationAccessible::InsertChildAt(aIdx, aChild))
+ return false;
+
+ AtkObject* atkAccessible = AccessibleWrap::GetAtkObject(aChild);
+ atk_object_set_parent(atkAccessible, mAtkObject);
+
+ uint32_t count = mChildren.Length();
+
+ // Emit children_changed::add in a timeout
+ // to make sure aRootAccWrap is fully initialized.
+ AtkRootAccessibleAddedEvent* eventData = (AtkRootAccessibleAddedEvent*)
+ malloc(sizeof(AtkRootAccessibleAddedEvent));
+ if (eventData) {
+ eventData->app_accessible = mAtkObject;
+ eventData->root_accessible = atkAccessible;
+ eventData->index = count -1;
+ g_object_ref(mAtkObject);
+ g_object_ref(atkAccessible);
+ g_timeout_add(0, fireRootAccessibleAddedCB, eventData);
+ }
+
+ return true;
+}
+
+bool
+ApplicationAccessibleWrap::RemoveChild(Accessible* aChild)
+{
+ int32_t index = aChild->IndexInParent();
+
+ AtkObject* atkAccessible = AccessibleWrap::GetAtkObject(aChild);
+ atk_object_set_parent(atkAccessible, nullptr);
+ g_signal_emit_by_name(mAtkObject, "children_changed::remove", index,
+ atkAccessible, nullptr);
+
+ return ApplicationAccessible::RemoveChild(aChild);
+}
+
diff --git a/accessible/atk/ApplicationAccessibleWrap.h b/accessible/atk/ApplicationAccessibleWrap.h
new file mode 100644
index 0000000000..468616b6cc
--- /dev/null
+++ b/accessible/atk/ApplicationAccessibleWrap.h
@@ -0,0 +1,35 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_a11y_ApplicationAccessibleWrap_h__
+#define mozilla_a11y_ApplicationAccessibleWrap_h__
+
+#include "ApplicationAccessible.h"
+
+namespace mozilla {
+namespace a11y {
+
+class ApplicationAccessibleWrap: public ApplicationAccessible
+{
+public:
+ ApplicationAccessibleWrap();
+ virtual ~ApplicationAccessibleWrap();
+
+ // Accessible
+ virtual mozilla::a11y::ENameValueFlag Name(nsString& aName) override;
+ virtual bool InsertChildAt(uint32_t aIdx, Accessible* aChild) override;
+ virtual bool RemoveChild(Accessible* aChild) override;
+
+ /**
+ * Return the atk object for app root accessible.
+ */
+ virtual void GetNativeInterface(void** aOutAccessible) override;
+};
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif /* __NS_APP_ROOT_ACCESSIBLE_H__ */
diff --git a/accessible/atk/AtkSocketAccessible.cpp b/accessible/atk/AtkSocketAccessible.cpp
new file mode 100644
index 0000000000..95c3075e80
--- /dev/null
+++ b/accessible/atk/AtkSocketAccessible.cpp
@@ -0,0 +1,126 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <atk/atk.h>
+#include "AtkSocketAccessible.h"
+
+#include "InterfaceInitFuncs.h"
+#include "nsMai.h"
+#include "mozilla/Likely.h"
+
+using namespace mozilla::a11y;
+
+AtkSocketEmbedType AtkSocketAccessible::g_atk_socket_embed = nullptr;
+GType AtkSocketAccessible::g_atk_socket_type = G_TYPE_INVALID;
+const char* AtkSocketAccessible::sATKSocketEmbedSymbol = "atk_socket_embed";
+const char* AtkSocketAccessible::sATKSocketGetTypeSymbol = "atk_socket_get_type";
+
+bool AtkSocketAccessible::gCanEmbed = FALSE;
+
+extern "C" void mai_atk_component_iface_init(AtkComponentIface* aIface);
+
+G_DEFINE_TYPE_EXTENDED(MaiAtkSocket, mai_atk_socket,
+ AtkSocketAccessible::g_atk_socket_type, 0,
+ G_IMPLEMENT_INTERFACE(ATK_TYPE_COMPONENT,
+ mai_atk_component_iface_init))
+
+void
+mai_atk_socket_class_init(MaiAtkSocketClass* aAcc)
+{
+}
+
+void
+mai_atk_socket_init(MaiAtkSocket* aAcc)
+{
+}
+
+static AtkObject*
+mai_atk_socket_new(AccessibleWrap* aAccWrap)
+{
+ NS_ENSURE_TRUE(aAccWrap, nullptr);
+
+ MaiAtkSocket* acc = nullptr;
+ acc = static_cast<MaiAtkSocket*>(g_object_new(MAI_TYPE_ATK_SOCKET, nullptr));
+ NS_ENSURE_TRUE(acc, nullptr);
+
+ acc->accWrap = aAccWrap;
+ return ATK_OBJECT(acc);
+}
+
+extern "C" {
+static AtkObject*
+RefAccessibleAtPoint(AtkComponent* aComponent, gint aX, gint aY,
+ AtkCoordType aCoordType)
+{
+ NS_ENSURE_TRUE(MAI_IS_ATK_SOCKET(aComponent), nullptr);
+
+ return refAccessibleAtPointHelper(ATK_OBJECT(MAI_ATK_SOCKET(aComponent)),
+ aX, aY, aCoordType);
+}
+
+static void
+GetExtents(AtkComponent* aComponent, gint* aX, gint* aY, gint* aWidth,
+ gint* aHeight, AtkCoordType aCoordType)
+{
+ *aX = *aY = *aWidth = *aHeight = 0;
+
+ if (!MAI_IS_ATK_SOCKET(aComponent))
+ return;
+
+ getExtentsHelper(ATK_OBJECT(MAI_ATK_SOCKET(aComponent)),
+ aX, aY, aWidth, aHeight, aCoordType);
+}
+}
+
+void
+mai_atk_component_iface_init(AtkComponentIface* aIface)
+{
+ NS_ASSERTION(aIface, "Invalid Interface");
+ if (MOZ_UNLIKELY(!aIface))
+ return;
+
+ aIface->ref_accessible_at_point = RefAccessibleAtPoint;
+ aIface->get_extents = GetExtents;
+}
+
+AtkSocketAccessible::AtkSocketAccessible(nsIContent* aContent,
+ DocAccessible* aDoc,
+ const nsCString& aPlugId) :
+ AccessibleWrap(aContent, aDoc)
+{
+ mAtkObject = mai_atk_socket_new(this);
+ if (!mAtkObject)
+ return;
+
+ // Embeds the children of an AtkPlug, specified by plugId, as the children of
+ // this socket.
+ // Using G_TYPE macros instead of ATK_SOCKET macros to avoid undefined
+ // symbols.
+ if (gCanEmbed && G_TYPE_CHECK_INSTANCE_TYPE(mAtkObject, g_atk_socket_type) &&
+ !aPlugId.IsVoid()) {
+ AtkSocket* accSocket =
+ G_TYPE_CHECK_INSTANCE_CAST(mAtkObject, g_atk_socket_type, AtkSocket);
+ g_atk_socket_embed(accSocket, (gchar*)aPlugId.get());
+ }
+}
+
+void
+AtkSocketAccessible::GetNativeInterface(void** aOutAccessible)
+{
+ *aOutAccessible = mAtkObject;
+}
+
+void
+AtkSocketAccessible::Shutdown()
+{
+ if (mAtkObject) {
+ if (MAI_IS_ATK_SOCKET(mAtkObject))
+ MAI_ATK_SOCKET(mAtkObject)->accWrap = nullptr;
+ g_object_unref(mAtkObject);
+ mAtkObject = nullptr;
+ }
+ AccessibleWrap::Shutdown();
+}
diff --git a/accessible/atk/AtkSocketAccessible.h b/accessible/atk/AtkSocketAccessible.h
new file mode 100644
index 0000000000..3b63a8e730
--- /dev/null
+++ b/accessible/atk/AtkSocketAccessible.h
@@ -0,0 +1,56 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _AtkSocketAccessible_H_
+#define _AtkSocketAccessible_H_
+
+#include "AccessibleWrap.h"
+
+// This file gets included by nsAccessibilityService.cpp, which can't include
+// atk.h (or glib.h), so we can't rely on it being included.
+#ifdef __ATK_H__
+extern "C" typedef void (*AtkSocketEmbedType) (AtkSocket*, gchar*);
+#else
+extern "C" typedef void (*AtkSocketEmbedType) (void*, void*);
+#endif
+
+namespace mozilla {
+namespace a11y {
+
+/**
+ * Provides a AccessibleWrap wrapper around AtkSocket for out-of-process
+ * accessibles.
+ */
+class AtkSocketAccessible : public AccessibleWrap
+{
+public:
+
+ // Soft references to AtkSocket
+ static AtkSocketEmbedType g_atk_socket_embed;
+#ifdef __ATK_H__
+ static GType g_atk_socket_type;
+#endif
+ static const char* sATKSocketEmbedSymbol;
+ static const char* sATKSocketGetTypeSymbol;
+
+ /*
+ * True if the current Atk version supports AtkSocket and it was correctly
+ * loaded.
+ */
+ static bool gCanEmbed;
+
+ AtkSocketAccessible(nsIContent* aContent, DocAccessible* aDoc,
+ const nsCString& aPlugId);
+
+ virtual void Shutdown() override;
+
+ virtual void GetNativeInterface(void** aOutAccessible) override;
+};
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif
diff --git a/accessible/atk/DocAccessibleWrap.cpp b/accessible/atk/DocAccessibleWrap.cpp
new file mode 100644
index 0000000000..d78d724b43
--- /dev/null
+++ b/accessible/atk/DocAccessibleWrap.cpp
@@ -0,0 +1,25 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsMai.h"
+#include "DocAccessibleWrap.h"
+
+using namespace mozilla::a11y;
+
+////////////////////////////////////////////////////////////////////////////////
+// DocAccessibleWrap
+////////////////////////////////////////////////////////////////////////////////
+
+DocAccessibleWrap::
+ DocAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell) :
+ DocAccessible(aDocument, aPresShell), mActivated(false)
+{
+}
+
+DocAccessibleWrap::~DocAccessibleWrap()
+{
+}
+
diff --git a/accessible/atk/DocAccessibleWrap.h b/accessible/atk/DocAccessibleWrap.h
new file mode 100644
index 0000000000..e5fc8e5e47
--- /dev/null
+++ b/accessible/atk/DocAccessibleWrap.h
@@ -0,0 +1,31 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* For documentation of the accessibility architecture,
+ * see http://lxr.mozilla.org/seamonkey/source/accessible/accessible-docs.html
+ */
+
+#ifndef mozilla_a11y_DocAccessibleWrap_h__
+#define mozilla_a11y_DocAccessibleWrap_h__
+
+#include "DocAccessible.h"
+
+namespace mozilla {
+namespace a11y {
+
+class DocAccessibleWrap : public DocAccessible
+{
+public:
+ DocAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell);
+ virtual ~DocAccessibleWrap();
+
+ bool mActivated;
+};
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif
diff --git a/accessible/atk/HTMLTableAccessibleWrap.h b/accessible/atk/HTMLTableAccessibleWrap.h
new file mode 100644
index 0000000000..88d40cc2e6
--- /dev/null
+++ b/accessible/atk/HTMLTableAccessibleWrap.h
@@ -0,0 +1,23 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_a11y_HTMLTableAccessibleWrap_h__
+#define mozilla_a11y_HTMLTableAccessibleWrap_h__
+
+#include "HTMLTableAccessible.h"
+
+namespace mozilla {
+namespace a11y {
+
+typedef class HTMLTableAccessible HTMLTableAccessibleWrap;
+typedef class HTMLTableCellAccessible HTMLTableCellAccessibleWrap;
+typedef class HTMLTableHeaderCellAccessible HTMLTableHeaderCellAccessibleWrap;
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif
+
diff --git a/accessible/atk/HyperTextAccessibleWrap.h b/accessible/atk/HyperTextAccessibleWrap.h
new file mode 100644
index 0000000000..a43fe65cf8
--- /dev/null
+++ b/accessible/atk/HyperTextAccessibleWrap.h
@@ -0,0 +1,21 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_a11y_HyperTextAccessibleWrap_h__
+#define mozilla_a11y_HyperTextAccessibleWrap_h__
+
+#include "HyperTextAccessible.h"
+
+namespace mozilla {
+namespace a11y {
+
+typedef class HyperTextAccessible HyperTextAccessibleWrap;
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif
+
diff --git a/accessible/atk/ImageAccessibleWrap.h b/accessible/atk/ImageAccessibleWrap.h
new file mode 100644
index 0000000000..7f1620a599
--- /dev/null
+++ b/accessible/atk/ImageAccessibleWrap.h
@@ -0,0 +1,21 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_a11y_ImageAccessibleWrap_h__
+#define mozilla_a11y_ImageAccessibleWrap_h__
+
+#include "ImageAccessible.h"
+
+namespace mozilla {
+namespace a11y {
+
+typedef class ImageAccessible ImageAccessibleWrap;
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif
+
diff --git a/accessible/atk/InterfaceInitFuncs.h b/accessible/atk/InterfaceInitFuncs.h
new file mode 100644
index 0000000000..c604a99fc2
--- /dev/null
+++ b/accessible/atk/InterfaceInitFuncs.h
@@ -0,0 +1,44 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef ATK_INTERFACE_INIT_FUNCS_H_
+#define ATK_INTERFACE_INIT_FUNCS_H_
+
+#include <atk/atk.h>
+
+namespace mozilla {
+namespace a11y {
+
+class AccessibleWrap;
+
+} // namespace a11y
+} // namespace mozilla
+
+extern "C" {
+void actionInterfaceInitCB(AtkActionIface* aIface);
+void componentInterfaceInitCB(AtkComponentIface* aIface);
+void documentInterfaceInitCB(AtkDocumentIface *aIface);
+void editableTextInterfaceInitCB(AtkEditableTextIface* aIface);
+void hyperlinkImplInterfaceInitCB(AtkHyperlinkImplIface *aIface);
+void hypertextInterfaceInitCB(AtkHypertextIface* aIface);
+void imageInterfaceInitCB(AtkImageIface* aIface);
+void selectionInterfaceInitCB(AtkSelectionIface* aIface);
+void tableInterfaceInitCB(AtkTableIface *aIface);
+void tableCellInterfaceInitCB(AtkTableCellIface *aIface);
+void textInterfaceInitCB(AtkTextIface* aIface);
+void valueInterfaceInitCB(AtkValueIface *aIface);
+}
+
+/**
+ * XXX these should live in a file of utils for atk.
+ */
+AtkObject* refAccessibleAtPointHelper(AtkObject* aAtkObj,
+ gint aX, gint aY, AtkCoordType aCoordType);
+void getExtentsHelper(AtkObject* aAtkObj,
+ gint* aX, gint* aY, gint* aWidth, gint* aHeight,
+ AtkCoordType aCoordType);
+
+#endif // ATK_INTERFACE_INIT_FUNCS_H_
diff --git a/accessible/atk/Platform.cpp b/accessible/atk/Platform.cpp
new file mode 100644
index 0000000000..e64084f5a0
--- /dev/null
+++ b/accessible/atk/Platform.cpp
@@ -0,0 +1,377 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "Platform.h"
+
+#include "nsIAccessibleEvent.h"
+#include "nsIGConfService.h"
+#include "nsIServiceManager.h"
+#include "nsMai.h"
+#include "AtkSocketAccessible.h"
+#include "prenv.h"
+#include "prlink.h"
+
+#ifdef MOZ_ENABLE_DBUS
+#include <dbus/dbus.h>
+#endif
+#include <gtk/gtk.h>
+
+#if (MOZ_WIDGET_GTK == 3)
+extern "C" __attribute__((weak,visibility("default"))) int atk_bridge_adaptor_init(int*, char **[]);
+#endif
+
+using namespace mozilla;
+using namespace mozilla::a11y;
+
+int atkMajorVersion = 1, atkMinorVersion = 12;
+
+GType (*gAtkTableCellGetTypeFunc)();
+
+extern "C" {
+typedef GType (* AtkGetTypeType) (void);
+typedef void (*GnomeAccessibilityInit) (void);
+typedef void (*GnomeAccessibilityShutdown) (void);
+}
+
+static PRLibrary* sATKLib = nullptr;
+static const char sATKLibName[] = "libatk-1.0.so.0";
+static const char sATKHyperlinkImplGetTypeSymbol[] =
+ "atk_hyperlink_impl_get_type";
+
+gboolean toplevel_event_watcher(GSignalInvocationHint*, guint, const GValue*,
+ gpointer);
+static bool sToplevel_event_hook_added = false;
+static gulong sToplevel_show_hook = 0;
+static gulong sToplevel_hide_hook = 0;
+
+GType g_atk_hyperlink_impl_type = G_TYPE_INVALID;
+
+struct GnomeAccessibilityModule
+{
+ const char *libName;
+ PRLibrary *lib;
+ const char *initName;
+ GnomeAccessibilityInit init;
+ const char *shutdownName;
+ GnomeAccessibilityShutdown shutdown;
+};
+
+static GnomeAccessibilityModule sAtkBridge = {
+#ifdef AIX
+ "libatk-bridge.a(libatk-bridge.so.0)", nullptr,
+#else
+ "libatk-bridge.so", nullptr,
+#endif
+ "gnome_accessibility_module_init", nullptr,
+ "gnome_accessibility_module_shutdown", nullptr
+};
+
+#if (MOZ_WIDGET_GTK == 2)
+static GnomeAccessibilityModule sGail = {
+ "libgail.so", nullptr,
+ "gnome_accessibility_module_init", nullptr,
+ "gnome_accessibility_module_shutdown", nullptr
+};
+#endif
+
+static nsresult
+LoadGtkModule(GnomeAccessibilityModule& aModule)
+{
+ NS_ENSURE_ARG(aModule.libName);
+
+ if (!(aModule.lib = PR_LoadLibrary(aModule.libName))) {
+ //try to load the module with "gtk-2.0/modules" appended
+ char *curLibPath = PR_GetLibraryPath();
+ nsAutoCString libPath(curLibPath);
+#if defined(LINUX) && defined(__x86_64__)
+ libPath.AppendLiteral(":/usr/lib64:/usr/lib");
+#else
+ libPath.AppendLiteral(":/usr/lib");
+#endif
+ PR_FreeLibraryName(curLibPath);
+
+ int16_t loc1 = 0, loc2 = 0;
+ int16_t subLen = 0;
+ while (loc2 >= 0) {
+ loc2 = libPath.FindChar(':', loc1);
+ if (loc2 < 0)
+ subLen = libPath.Length() - loc1;
+ else
+ subLen = loc2 - loc1;
+ nsAutoCString sub(Substring(libPath, loc1, subLen));
+#if (MOZ_WIDGET_GTK == 2)
+ sub.AppendLiteral("/gtk-2.0/modules/");
+#else
+ sub.AppendLiteral("/gtk-3.0/modules/");
+#endif
+ sub.Append(aModule.libName);
+ aModule.lib = PR_LoadLibrary(sub.get());
+ if (aModule.lib)
+ break;
+
+ loc1 = loc2+1;
+ }
+ if (!aModule.lib)
+ return NS_ERROR_FAILURE;
+ }
+
+ //we have loaded the library, try to get the function ptrs
+ if (!(aModule.init = PR_FindFunctionSymbol(aModule.lib,
+ aModule.initName)) ||
+ !(aModule.shutdown = PR_FindFunctionSymbol(aModule.lib,
+ aModule.shutdownName))) {
+
+ //fail, :(
+ PR_UnloadLibrary(aModule.lib);
+ aModule.lib = nullptr;
+ return NS_ERROR_FAILURE;
+ }
+ return NS_OK;
+}
+
+void
+a11y::PlatformInit()
+{
+ if (!ShouldA11yBeEnabled())
+ return;
+
+ sATKLib = PR_LoadLibrary(sATKLibName);
+ if (!sATKLib)
+ return;
+
+ AtkGetTypeType pfn_atk_hyperlink_impl_get_type =
+ (AtkGetTypeType) PR_FindFunctionSymbol(sATKLib, sATKHyperlinkImplGetTypeSymbol);
+ if (pfn_atk_hyperlink_impl_get_type)
+ g_atk_hyperlink_impl_type = pfn_atk_hyperlink_impl_get_type();
+
+ AtkGetTypeType pfn_atk_socket_get_type = (AtkGetTypeType)
+ PR_FindFunctionSymbol(sATKLib, AtkSocketAccessible::sATKSocketGetTypeSymbol);
+ if (pfn_atk_socket_get_type) {
+ AtkSocketAccessible::g_atk_socket_type = pfn_atk_socket_get_type();
+ AtkSocketAccessible::g_atk_socket_embed = (AtkSocketEmbedType)
+ PR_FindFunctionSymbol(sATKLib, AtkSocketAccessible ::sATKSocketEmbedSymbol);
+ AtkSocketAccessible::gCanEmbed =
+ AtkSocketAccessible::g_atk_socket_type != G_TYPE_INVALID &&
+ AtkSocketAccessible::g_atk_socket_embed;
+ }
+
+ gAtkTableCellGetTypeFunc = (GType (*)())
+ PR_FindFunctionSymbol(sATKLib, "atk_table_cell_get_type");
+
+ const char* (*atkGetVersion)() =
+ (const char* (*)()) PR_FindFunctionSymbol(sATKLib, "atk_get_version");
+ if (atkGetVersion) {
+ const char* version = atkGetVersion();
+ if (version) {
+ char* endPtr = nullptr;
+ atkMajorVersion = strtol(version, &endPtr, 10);
+ if (*endPtr == '.')
+ atkMinorVersion = strtol(endPtr + 1, &endPtr, 10);
+ }
+ }
+
+#if (MOZ_WIDGET_GTK == 2)
+ // Load and initialize gail library.
+ nsresult rv = LoadGtkModule(sGail);
+ if (NS_SUCCEEDED(rv))
+ (*sGail.init)();
+#endif
+
+ // Initialize the MAI Utility class, it will overwrite gail_util.
+ g_type_class_unref(g_type_class_ref(mai_util_get_type()));
+
+ // Init atk-bridge now
+ PR_SetEnv("NO_AT_BRIDGE=0");
+#if (MOZ_WIDGET_GTK == 3)
+ if (atk_bridge_adaptor_init) {
+ atk_bridge_adaptor_init(nullptr, nullptr);
+ } else
+#endif
+ {
+ nsresult rv = LoadGtkModule(sAtkBridge);
+ if (NS_SUCCEEDED(rv)) {
+ (*sAtkBridge.init)();
+ }
+ }
+
+ if (!sToplevel_event_hook_added) {
+ sToplevel_event_hook_added = true;
+ sToplevel_show_hook =
+ g_signal_add_emission_hook(g_signal_lookup("show", GTK_TYPE_WINDOW),
+ 0, toplevel_event_watcher,
+ reinterpret_cast<gpointer>(nsIAccessibleEvent::EVENT_SHOW),
+ nullptr);
+ sToplevel_hide_hook =
+ g_signal_add_emission_hook(g_signal_lookup("hide", GTK_TYPE_WINDOW), 0,
+ toplevel_event_watcher,
+ reinterpret_cast<gpointer>(nsIAccessibleEvent::EVENT_HIDE),
+ nullptr);
+ }
+}
+
+void
+a11y::PlatformShutdown()
+{
+ if (sToplevel_event_hook_added) {
+ sToplevel_event_hook_added = false;
+ g_signal_remove_emission_hook(g_signal_lookup("show", GTK_TYPE_WINDOW),
+ sToplevel_show_hook);
+ g_signal_remove_emission_hook(g_signal_lookup("hide", GTK_TYPE_WINDOW),
+ sToplevel_hide_hook);
+ }
+
+ if (sAtkBridge.lib) {
+ // Do not shutdown/unload atk-bridge,
+ // an exit function registered will take care of it
+ // if (sAtkBridge.shutdown)
+ // (*sAtkBridge.shutdown)();
+ // PR_UnloadLibrary(sAtkBridge.lib);
+ sAtkBridge.lib = nullptr;
+ sAtkBridge.init = nullptr;
+ sAtkBridge.shutdown = nullptr;
+ }
+#if (MOZ_WIDGET_GTK == 2)
+ if (sGail.lib) {
+ // Do not shutdown gail because
+ // 1) Maybe it's not init-ed by us. e.g. GtkEmbed
+ // 2) We need it to avoid assert in spi_atk_tidy_windows
+ // if (sGail.shutdown)
+ // (*sGail.shutdown)();
+ // PR_UnloadLibrary(sGail.lib);
+ sGail.lib = nullptr;
+ sGail.init = nullptr;
+ sGail.shutdown = nullptr;
+ }
+#endif
+ // if (sATKLib) {
+ // PR_UnloadLibrary(sATKLib);
+ // sATKLib = nullptr;
+ // }
+}
+
+ static const char sAccEnv [] = "GNOME_ACCESSIBILITY";
+#ifdef MOZ_ENABLE_DBUS
+static DBusPendingCall *sPendingCall = nullptr;
+#endif
+
+void
+a11y::PreInit()
+{
+#ifdef MOZ_ENABLE_DBUS
+ static bool sChecked = FALSE;
+ if (sChecked)
+ return;
+
+ sChecked = TRUE;
+
+ // dbus is only checked if GNOME_ACCESSIBILITY is unset
+ // also make sure that a session bus address is available to prevent dbus from
+ // starting a new one. Dbus confuses the test harness when it creates a new
+ // process (see bug 693343)
+ if (PR_GetEnv(sAccEnv) || !PR_GetEnv("DBUS_SESSION_BUS_ADDRESS"))
+ return;
+
+ DBusConnection* bus = dbus_bus_get(DBUS_BUS_SESSION, nullptr);
+ if (!bus)
+ return;
+
+ dbus_connection_set_exit_on_disconnect(bus, FALSE);
+
+ static const char* iface = "org.a11y.Status";
+ static const char* member = "IsEnabled";
+ DBusMessage *message;
+ message = dbus_message_new_method_call("org.a11y.Bus", "/org/a11y/bus",
+ "org.freedesktop.DBus.Properties",
+ "Get");
+ if (!message)
+ goto dbus_done;
+
+ dbus_message_append_args(message, DBUS_TYPE_STRING, &iface,
+ DBUS_TYPE_STRING, &member, DBUS_TYPE_INVALID);
+ dbus_connection_send_with_reply(bus, message, &sPendingCall, 1000);
+ dbus_message_unref(message);
+
+dbus_done:
+ dbus_connection_unref(bus);
+#endif
+}
+
+bool
+a11y::ShouldA11yBeEnabled()
+{
+ static bool sChecked = false, sShouldEnable = false;
+ if (sChecked)
+ return sShouldEnable;
+
+ sChecked = true;
+
+ EPlatformDisabledState disabledState = PlatformDisabledState();
+ if (disabledState == ePlatformIsDisabled)
+ return sShouldEnable = false;
+
+ // check if accessibility enabled/disabled by environment variable
+ const char* envValue = PR_GetEnv(sAccEnv);
+ if (envValue)
+ return sShouldEnable = !!atoi(envValue);
+
+#ifdef MOZ_ENABLE_DBUS
+ PreInit();
+ bool dbusSuccess = false;
+ DBusMessage *reply = nullptr;
+ if (!sPendingCall)
+ goto dbus_done;
+
+ dbus_pending_call_block(sPendingCall);
+ reply = dbus_pending_call_steal_reply(sPendingCall);
+ dbus_pending_call_unref(sPendingCall);
+ sPendingCall = nullptr;
+ if (!reply ||
+ dbus_message_get_type(reply) != DBUS_MESSAGE_TYPE_METHOD_RETURN ||
+ strcmp(dbus_message_get_signature (reply), DBUS_TYPE_VARIANT_AS_STRING))
+ goto dbus_done;
+
+ DBusMessageIter iter, iter_variant, iter_struct;
+ dbus_bool_t dResult;
+ dbus_message_iter_init(reply, &iter);
+ dbus_message_iter_recurse (&iter, &iter_variant);
+ switch (dbus_message_iter_get_arg_type(&iter_variant)) {
+ case DBUS_TYPE_STRUCT:
+ // at-spi2-core 2.2.0-2.2.1 had a bug where it returned a struct
+ dbus_message_iter_recurse(&iter_variant, &iter_struct);
+ if (dbus_message_iter_get_arg_type(&iter_struct) == DBUS_TYPE_BOOLEAN) {
+ dbus_message_iter_get_basic(&iter_struct, &dResult);
+ sShouldEnable = dResult;
+ dbusSuccess = true;
+ }
+
+ break;
+ case DBUS_TYPE_BOOLEAN:
+ dbus_message_iter_get_basic(&iter_variant, &dResult);
+ sShouldEnable = dResult;
+ dbusSuccess = true;
+ break;
+ default:
+ break;
+ }
+
+dbus_done:
+ if (reply)
+ dbus_message_unref(reply);
+
+ if (dbusSuccess)
+ return sShouldEnable;
+#endif
+
+ //check gconf-2 setting
+#define GCONF_A11Y_KEY "/desktop/gnome/interface/accessibility"
+ nsresult rv = NS_OK;
+ nsCOMPtr<nsIGConfService> gconf =
+ do_GetService(NS_GCONFSERVICE_CONTRACTID, &rv);
+ if (NS_SUCCEEDED(rv) && gconf)
+ gconf->GetBool(NS_LITERAL_CSTRING(GCONF_A11Y_KEY), &sShouldEnable);
+
+ return sShouldEnable;
+}
diff --git a/accessible/atk/RootAccessibleWrap.cpp b/accessible/atk/RootAccessibleWrap.cpp
new file mode 100644
index 0000000000..e1142e1613
--- /dev/null
+++ b/accessible/atk/RootAccessibleWrap.cpp
@@ -0,0 +1,24 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "RootAccessibleWrap.h"
+
+#include "nsMai.h"
+
+using namespace mozilla::a11y;
+
+GtkWindowAccessible::GtkWindowAccessible(AtkObject* aAccessible) :
+ DummyAccessible()
+{
+ g_object_ref(aAccessible);
+ mAtkObject = aAccessible;
+}
+
+GtkWindowAccessible::~GtkWindowAccessible()
+{
+ g_object_unref(mAtkObject);
+ mAtkObject = nullptr;
+}
diff --git a/accessible/atk/RootAccessibleWrap.h b/accessible/atk/RootAccessibleWrap.h
new file mode 100644
index 0000000000..cf4b5c18ce
--- /dev/null
+++ b/accessible/atk/RootAccessibleWrap.h
@@ -0,0 +1,34 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_a11y_RootAccessibleWrap_h__
+#define mozilla_a11y_RootAccessibleWrap_h__
+
+#include "BaseAccessibles.h"
+#include "RootAccessible.h"
+
+namespace mozilla {
+namespace a11y {
+
+typedef RootAccessible RootAccessibleWrap;
+
+/* GtkWindowAccessible is the accessible class for gtk+ native window.
+ * The instance of GtkWindowAccessible is a child of MaiAppRoot instance.
+ * It is added into root when the toplevel window is created, and removed
+ * from root when the toplevel window is destroyed.
+ */
+class GtkWindowAccessible final : public DummyAccessible
+{
+public:
+ explicit GtkWindowAccessible(AtkObject* aAccessible);
+ virtual ~GtkWindowAccessible();
+};
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif /* mozilla_a11y_Root_Accessible_Wrap_h__ */
+
diff --git a/accessible/atk/TextLeafAccessibleWrap.h b/accessible/atk/TextLeafAccessibleWrap.h
new file mode 100644
index 0000000000..726feff01a
--- /dev/null
+++ b/accessible/atk/TextLeafAccessibleWrap.h
@@ -0,0 +1,20 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_a11y_TextLeafAccessibleWrap_h__
+#define mozilla_a11y_TextLeafAccessibleWrap_h__
+
+#include "TextLeafAccessible.h"
+
+namespace mozilla {
+namespace a11y {
+
+typedef class TextLeafAccessible TextLeafAccessibleWrap;
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif
diff --git a/accessible/atk/UtilInterface.cpp b/accessible/atk/UtilInterface.cpp
new file mode 100644
index 0000000000..a2ab00141d
--- /dev/null
+++ b/accessible/atk/UtilInterface.cpp
@@ -0,0 +1,411 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "ApplicationAccessibleWrap.h"
+#include "mozilla/Likely.h"
+#include "nsAccessibilityService.h"
+#include "nsMai.h"
+
+#include <atk/atk.h>
+#include <gtk/gtk.h>
+#include <string.h>
+
+using namespace mozilla;
+using namespace mozilla::a11y;
+
+typedef AtkUtil MaiUtil;
+typedef AtkUtilClass MaiUtilClass;
+
+#define MAI_VERSION MOZILLA_VERSION
+#define MAI_NAME "Gecko"
+
+extern "C" {
+static guint (*gail_add_global_event_listener)(GSignalEmissionHook listener,
+ const gchar* event_type);
+static void (*gail_remove_global_event_listener) (guint remove_listener);
+static void (*gail_remove_key_event_listener) (guint remove_listener);
+static AtkObject* (*gail_get_root)();
+}
+
+struct MaiUtilListenerInfo
+{
+ gint key;
+ guint signal_id;
+ gulong hook_id;
+ // For window create/destory/minimize/maximize/restore/activate/deactivate
+ // events, we'll chain gail_util's add/remove_global_event_listener.
+ // So we store the listenerid returned by gail's add_global_event_listener
+ // in this structure to call gail's remove_global_event_listener later.
+ guint gail_listenerid;
+};
+
+static GHashTable* sListener_list = nullptr;
+static gint sListener_idx = 1;
+
+extern "C" {
+static guint
+add_listener (GSignalEmissionHook listener,
+ const gchar *object_type,
+ const gchar *signal,
+ const gchar *hook_data,
+ guint gail_listenerid = 0)
+{
+ GType type;
+ guint signal_id;
+ gint rc = 0;
+
+ type = g_type_from_name(object_type);
+ if (type) {
+ signal_id = g_signal_lookup(signal, type);
+ if (signal_id > 0) {
+ MaiUtilListenerInfo *listener_info;
+
+ rc = sListener_idx;
+
+ listener_info = (MaiUtilListenerInfo *)
+ g_malloc(sizeof(MaiUtilListenerInfo));
+ listener_info->key = sListener_idx;
+ listener_info->hook_id =
+ g_signal_add_emission_hook(signal_id, 0, listener,
+ g_strdup(hook_data),
+ (GDestroyNotify)g_free);
+ listener_info->signal_id = signal_id;
+ listener_info->gail_listenerid = gail_listenerid;
+
+ g_hash_table_insert(sListener_list, &(listener_info->key),
+ listener_info);
+ sListener_idx++;
+ }
+ else {
+ g_warning("Invalid signal type %s\n", signal);
+ }
+ }
+ else {
+ g_warning("Invalid object type %s\n", object_type);
+ }
+ return rc;
+}
+
+static guint
+mai_util_add_global_event_listener(GSignalEmissionHook listener,
+ const gchar *event_type)
+{
+ guint rc = 0;
+ gchar **split_string;
+
+ split_string = g_strsplit (event_type, ":", 3);
+
+ if (split_string) {
+ if (!strcmp ("window", split_string[0])) {
+ guint gail_listenerid = 0;
+ if (gail_add_global_event_listener) {
+ // call gail's function to track gtk native window events
+ gail_listenerid =
+ gail_add_global_event_listener(listener, event_type);
+ }
+
+ rc = add_listener (listener, "MaiAtkObject", split_string[1],
+ event_type, gail_listenerid);
+ }
+ else {
+ rc = add_listener (listener, split_string[1], split_string[2],
+ event_type);
+ }
+ g_strfreev(split_string);
+ }
+ return rc;
+}
+
+static void
+mai_util_remove_global_event_listener(guint remove_listener)
+{
+ if (remove_listener > 0) {
+ MaiUtilListenerInfo *listener_info;
+ gint tmp_idx = remove_listener;
+
+ listener_info = (MaiUtilListenerInfo *)
+ g_hash_table_lookup(sListener_list, &tmp_idx);
+
+ if (listener_info != nullptr) {
+ if (gail_remove_global_event_listener &&
+ listener_info->gail_listenerid) {
+ gail_remove_global_event_listener(listener_info->gail_listenerid);
+ }
+
+ /* Hook id of 0 and signal id of 0 are invalid */
+ if (listener_info->hook_id != 0 && listener_info->signal_id != 0) {
+ /* Remove the emission hook */
+ g_signal_remove_emission_hook(listener_info->signal_id,
+ listener_info->hook_id);
+
+ /* Remove the element from the hash */
+ g_hash_table_remove(sListener_list, &tmp_idx);
+ }
+ else {
+ g_warning("Invalid listener hook_id %ld or signal_id %d\n",
+ listener_info->hook_id, listener_info->signal_id);
+ }
+ }
+ else {
+ // atk-bridge is initialized with gail (e.g. yelp)
+ // try gail_remove_global_event_listener
+ if (gail_remove_global_event_listener) {
+ return gail_remove_global_event_listener(remove_listener);
+ }
+
+ g_warning("No listener with the specified listener id %d",
+ remove_listener);
+ }
+ }
+ else {
+ g_warning("Invalid listener_id %d", remove_listener);
+ }
+}
+
+static AtkKeyEventStruct *
+atk_key_event_from_gdk_event_key (GdkEventKey *key)
+{
+ AtkKeyEventStruct *event = g_new0(AtkKeyEventStruct, 1);
+ switch (key->type) {
+ case GDK_KEY_PRESS:
+ event->type = ATK_KEY_EVENT_PRESS;
+ break;
+ case GDK_KEY_RELEASE:
+ event->type = ATK_KEY_EVENT_RELEASE;
+ break;
+ default:
+ g_assert_not_reached ();
+ return nullptr;
+ }
+ event->state = key->state;
+ event->keyval = key->keyval;
+ event->length = key->length;
+ if (key->string && key->string [0] &&
+ (key->state & GDK_CONTROL_MASK ||
+ g_unichar_isgraph (g_utf8_get_char (key->string)))) {
+ event->string = key->string;
+ }
+ else if (key->type == GDK_KEY_PRESS ||
+ key->type == GDK_KEY_RELEASE) {
+ event->string = gdk_keyval_name (key->keyval);
+ }
+ event->keycode = key->hardware_keycode;
+ event->timestamp = key->time;
+
+ return event;
+}
+
+struct MaiKeyEventInfo
+{
+ AtkKeyEventStruct *key_event;
+ gpointer func_data;
+};
+
+union AtkKeySnoopFuncPointer
+{
+ AtkKeySnoopFunc func_ptr;
+ gpointer data;
+};
+
+static gboolean
+notify_hf(gpointer key, gpointer value, gpointer data)
+{
+ MaiKeyEventInfo *info = (MaiKeyEventInfo *)data;
+ AtkKeySnoopFuncPointer atkKeySnoop;
+ atkKeySnoop.data = value;
+ return (atkKeySnoop.func_ptr)(info->key_event, info->func_data) ? TRUE : FALSE;
+}
+
+static void
+insert_hf(gpointer key, gpointer value, gpointer data)
+{
+ GHashTable *new_table = (GHashTable *) data;
+ g_hash_table_insert (new_table, key, value);
+}
+
+static GHashTable* sKey_listener_list = nullptr;
+
+static gint
+mai_key_snooper(GtkWidget *the_widget, GdkEventKey *event, gpointer func_data)
+{
+ /* notify each AtkKeySnoopFunc in turn... */
+
+ MaiKeyEventInfo *info = g_new0(MaiKeyEventInfo, 1);
+ gint consumed = 0;
+ if (sKey_listener_list) {
+ GHashTable *new_hash = g_hash_table_new(nullptr, nullptr);
+ g_hash_table_foreach (sKey_listener_list, insert_hf, new_hash);
+ info->key_event = atk_key_event_from_gdk_event_key (event);
+ info->func_data = func_data;
+ consumed = g_hash_table_foreach_steal (new_hash, notify_hf, info);
+ g_hash_table_destroy (new_hash);
+ g_free(info->key_event);
+ }
+ g_free(info);
+ return (consumed ? 1 : 0);
+}
+
+static guint sKey_snooper_id = 0;
+
+static guint
+mai_util_add_key_event_listener(AtkKeySnoopFunc listener, gpointer data)
+{
+ if (MOZ_UNLIKELY(!listener)) {
+ return 0;
+ }
+
+ static guint key = 0;
+
+ if (!sKey_listener_list) {
+ sKey_listener_list = g_hash_table_new(nullptr, nullptr);
+ }
+
+ // If we have no registered event listeners then we need to (re)install the
+ // key event snooper.
+ if (g_hash_table_size(sKey_listener_list) == 0) {
+ sKey_snooper_id = gtk_key_snooper_install(mai_key_snooper, data);
+ }
+
+ AtkKeySnoopFuncPointer atkKeySnoop;
+ atkKeySnoop.func_ptr = listener;
+ key++;
+ g_hash_table_insert(sKey_listener_list, GUINT_TO_POINTER(key),
+ atkKeySnoop.data);
+ return key;
+}
+
+static void
+mai_util_remove_key_event_listener (guint remove_listener)
+{
+ if (!sKey_listener_list) {
+ // atk-bridge is initialized with gail (e.g. yelp)
+ // try gail_remove_key_event_listener
+ return gail_remove_key_event_listener(remove_listener);
+ }
+
+ g_hash_table_remove(sKey_listener_list, GUINT_TO_POINTER (remove_listener));
+ if (g_hash_table_size(sKey_listener_list) == 0) {
+ gtk_key_snooper_remove(sKey_snooper_id);
+ }
+}
+
+static AtkObject*
+mai_util_get_root()
+{
+ ApplicationAccessible* app = ApplicationAcc();
+ if (app)
+ return app->GetAtkObject();
+
+ // We've shutdown, try to use gail instead
+ // (to avoid assert in spi_atk_tidy_windows())
+ // XXX tbsaunde then why didn't we replace the gail atk_util impl?
+ if (gail_get_root)
+ return gail_get_root();
+
+ return nullptr;
+}
+
+static const gchar*
+mai_util_get_toolkit_name()
+{
+ return MAI_NAME;
+}
+
+static const gchar*
+mai_util_get_toolkit_version()
+{
+ return MAI_VERSION;
+}
+
+static void
+_listener_info_destroy(gpointer data)
+{
+ g_free(data);
+}
+
+static void
+window_added (AtkObject *atk_obj,
+ guint index,
+ AtkObject *child)
+{
+ if (!IS_MAI_OBJECT(child))
+ return;
+
+ static guint id = g_signal_lookup ("create", MAI_TYPE_ATK_OBJECT);
+ g_signal_emit (child, id, 0);
+}
+
+static void
+window_removed (AtkObject *atk_obj,
+ guint index,
+ AtkObject *child)
+{
+ if (!IS_MAI_OBJECT(child))
+ return;
+
+ static guint id = g_signal_lookup ("destroy", MAI_TYPE_ATK_OBJECT);
+ g_signal_emit (child, id, 0);
+}
+
+ static void
+UtilInterfaceInit(MaiUtilClass* klass)
+{
+ AtkUtilClass *atk_class;
+ gpointer data;
+
+ data = g_type_class_peek(ATK_TYPE_UTIL);
+ atk_class = ATK_UTIL_CLASS(data);
+
+ // save gail function pointer
+ gail_add_global_event_listener = atk_class->add_global_event_listener;
+ gail_remove_global_event_listener = atk_class->remove_global_event_listener;
+ gail_remove_key_event_listener = atk_class->remove_key_event_listener;
+ gail_get_root = atk_class->get_root;
+
+ atk_class->add_global_event_listener =
+ mai_util_add_global_event_listener;
+ atk_class->remove_global_event_listener =
+ mai_util_remove_global_event_listener;
+ atk_class->add_key_event_listener = mai_util_add_key_event_listener;
+ atk_class->remove_key_event_listener = mai_util_remove_key_event_listener;
+ atk_class->get_root = mai_util_get_root;
+ atk_class->get_toolkit_name = mai_util_get_toolkit_name;
+ atk_class->get_toolkit_version = mai_util_get_toolkit_version;
+
+ sListener_list = g_hash_table_new_full(g_int_hash, g_int_equal, nullptr,
+ _listener_info_destroy);
+ // Keep track of added/removed windows.
+ AtkObject *root = atk_get_root ();
+ g_signal_connect (root, "children-changed::add", (GCallback) window_added, nullptr);
+ g_signal_connect (root, "children-changed::remove", (GCallback) window_removed, nullptr);
+}
+}
+
+GType
+mai_util_get_type()
+{
+ static GType type = 0;
+
+ if (!type) {
+ static const GTypeInfo tinfo = {
+ sizeof(MaiUtilClass),
+ (GBaseInitFunc) nullptr, /* base init */
+ (GBaseFinalizeFunc) nullptr, /* base finalize */
+ (GClassInitFunc) UtilInterfaceInit, /* class init */
+ (GClassFinalizeFunc) nullptr, /* class finalize */
+ nullptr, /* class data */
+ sizeof(MaiUtil), /* instance size */
+ 0, /* nb preallocs */
+ (GInstanceInitFunc) nullptr, /* instance init */
+ nullptr /* value table */
+ };
+
+ type = g_type_register_static(ATK_TYPE_UTIL,
+ "MaiUtil", &tinfo, GTypeFlags(0));
+ }
+ return type;
+}
+
diff --git a/accessible/atk/XULListboxAccessibleWrap.h b/accessible/atk/XULListboxAccessibleWrap.h
new file mode 100644
index 0000000000..c0a7594527
--- /dev/null
+++ b/accessible/atk/XULListboxAccessibleWrap.h
@@ -0,0 +1,21 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_a11y_XULListboxAccessibleWrap_h__
+#define mozilla_a11y_XULListboxAccessibleWrap_h__
+
+#include "XULListboxAccessible.h"
+
+namespace mozilla {
+namespace a11y {
+
+typedef class XULListboxAccessible XULListboxAccessibleWrap;
+typedef class XULListCellAccessible XULListCellAccessibleWrap;
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif
diff --git a/accessible/atk/XULMenuAccessibleWrap.h b/accessible/atk/XULMenuAccessibleWrap.h
new file mode 100644
index 0000000000..d9e325053d
--- /dev/null
+++ b/accessible/atk/XULMenuAccessibleWrap.h
@@ -0,0 +1,20 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_a11y_XULMenuAccessibleWrap_h__
+#define mozilla_a11y_XULMenuAccessibleWrap_h__
+
+#include "XULMenuAccessible.h"
+
+namespace mozilla {
+namespace a11y {
+
+typedef class XULMenuitemAccessible XULMenuitemAccessibleWrap;
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif
diff --git a/accessible/atk/XULTreeGridAccessibleWrap.h b/accessible/atk/XULTreeGridAccessibleWrap.h
new file mode 100644
index 0000000000..b7f23434bf
--- /dev/null
+++ b/accessible/atk/XULTreeGridAccessibleWrap.h
@@ -0,0 +1,22 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_a11y_XULTreeGridAccessibleWrap_h__
+#define mozilla_a11y_XULTreeGridAccessibleWrap_h__
+
+#include "XULTreeGridAccessible.h"
+
+namespace mozilla {
+namespace a11y {
+
+typedef class XULTreeGridAccessible XULTreeGridAccessibleWrap;
+typedef class XULTreeGridCellAccessible XULTreeGridCellAccessibleWrap;
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif
+
diff --git a/accessible/atk/moz.build b/accessible/atk/moz.build
new file mode 100644
index 0000000000..0d6ff9bbe6
--- /dev/null
+++ b/accessible/atk/moz.build
@@ -0,0 +1,63 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+EXPORTS.mozilla.a11y += [
+ 'AccessibleWrap.h',
+ 'HyperTextAccessibleWrap.h',
+]
+
+SOURCES += [
+ 'AccessibleWrap.cpp',
+ 'ApplicationAccessibleWrap.cpp',
+ 'AtkSocketAccessible.cpp',
+ 'DocAccessibleWrap.cpp',
+ 'nsMaiHyperlink.cpp',
+ 'nsMaiInterfaceAction.cpp',
+ 'nsMaiInterfaceComponent.cpp',
+ 'nsMaiInterfaceDocument.cpp',
+ 'nsMaiInterfaceEditableText.cpp',
+ 'nsMaiInterfaceHyperlinkImpl.cpp',
+ 'nsMaiInterfaceHypertext.cpp',
+ 'nsMaiInterfaceImage.cpp',
+ 'nsMaiInterfaceSelection.cpp',
+ 'nsMaiInterfaceTable.cpp',
+ 'nsMaiInterfaceTableCell.cpp',
+ 'nsMaiInterfaceText.cpp',
+ 'nsMaiInterfaceValue.cpp',
+ 'Platform.cpp',
+ 'RootAccessibleWrap.cpp',
+ 'UtilInterface.cpp',
+]
+
+LOCAL_INCLUDES += [
+ '/accessible/base',
+ '/accessible/generic',
+ '/accessible/html',
+ '/accessible/ipc',
+ '/accessible/ipc/other',
+ '/accessible/xpcom',
+ '/accessible/xul',
+ '/other-licenses/atk-1.0',
+]
+
+FINAL_LIBRARY = 'xul'
+
+if 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT']:
+ CFLAGS += CONFIG['TK_CFLAGS']
+ CXXFLAGS += CONFIG['TK_CFLAGS']
+
+if CONFIG['MOZ_ENABLE_DBUS']:
+ CXXFLAGS += CONFIG['MOZ_DBUS_CFLAGS']
+
+include('/ipc/chromium/chromium-config.mozbuild')
+
+if CONFIG['CLANG_CXX'] or CONFIG['GNU_CXX']:
+ # Used in G_DEFINE_TYPE_EXTENDED macro, probably fixed in newer glib /
+ # gobject headers. See bug 1243331 comment 3.
+ CXXFLAGS += [
+ '-Wno-error=shadow',
+ '-Wno-unused-local-typedefs',
+ ]
diff --git a/accessible/atk/nsMai.h b/accessible/atk/nsMai.h
new file mode 100644
index 0000000000..1a9082e99b
--- /dev/null
+++ b/accessible/atk/nsMai.h
@@ -0,0 +1,149 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef __NS_MAI_H__
+#define __NS_MAI_H__
+
+#include <atk/atk.h>
+#include <glib.h>
+#include <glib-object.h>
+
+#include "AccessibleOrProxy.h"
+#include "AccessibleWrap.h"
+
+namespace mozilla {
+namespace a11y {
+class ProxyAccessible;
+}
+}
+
+#define MAI_TYPE_ATK_OBJECT (mai_atk_object_get_type ())
+#define MAI_ATK_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+ MAI_TYPE_ATK_OBJECT, MaiAtkObject))
+#define MAI_ATK_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), \
+ MAI_TYPE_ATK_OBJECT, \
+ MaiAtkObjectClass))
+#define IS_MAI_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+ MAI_TYPE_ATK_OBJECT))
+#define IS_MAI_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+ MAI_TYPE_ATK_OBJECT))
+#define MAI_ATK_OBJECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+ MAI_TYPE_ATK_OBJECT, \
+ MaiAtkObjectClass))
+GType mai_atk_object_get_type(void);
+GType mai_util_get_type();
+extern "C" GType mai_atk_socket_get_type(void);
+
+/* MaiAtkSocket */
+
+#define MAI_TYPE_ATK_SOCKET (mai_atk_socket_get_type ())
+#define MAI_ATK_SOCKET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),\
+ MAI_TYPE_ATK_SOCKET, MaiAtkSocket))
+#define MAI_IS_ATK_SOCKET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj),\
+ MAI_TYPE_ATK_SOCKET))
+#define MAI_ATK_SOCKET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
+ MAI_TYPE_ATK_SOCKET,\
+ MaiAtkSocketClass))
+#define MAI_IS_ATK_SOCKET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),\
+ MAI_TYPE_ATK_SOCKET))
+#define MAI_ATK_SOCKET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
+ MAI_TYPE_ATK_SOCKET,\
+ MaiAtkSocketClass))
+
+typedef struct _MaiAtkSocket
+{
+ AtkSocket parent;
+
+ mozilla::a11y::AccessibleWrap* accWrap;
+} MaiAtkSocket;
+
+typedef struct _MaiAtkSocketClass
+{
+ AtkSocketClass parent_class;
+} MaiAtkSocketClass;
+
+// This is a pointer to the atk_table_cell_get_type function if we are using
+// a version of atk that defines that.
+extern "C" GType (*gAtkTableCellGetTypeFunc)();
+
+mozilla::a11y::AccessibleWrap* GetAccessibleWrap(AtkObject* aAtkObj);
+mozilla::a11y::ProxyAccessible* GetProxy(AtkObject* aAtkObj);
+mozilla::a11y::AccessibleOrProxy GetInternalObj(AtkObject* aObj);
+AtkObject* GetWrapperFor(mozilla::a11y::ProxyAccessible* aProxy);
+AtkObject* GetWrapperFor(mozilla::a11y::AccessibleOrProxy aObj);
+
+extern int atkMajorVersion, atkMinorVersion;
+
+/**
+ * Return true if the loaded version of libatk-1.0.so is at least
+ * aMajor.aMinor.0.
+ */
+static inline bool
+IsAtkVersionAtLeast(int aMajor, int aMinor)
+{
+ return aMajor < atkMajorVersion ||
+ (aMajor == atkMajorVersion && aMinor <= atkMinorVersion);
+}
+
+// This is or'd with the pointer in MaiAtkObject::accWrap if the wrap-ee is a
+// proxy.
+static const uintptr_t IS_PROXY = 1;
+
+/**
+ * This MaiAtkObject is a thin wrapper, in the MAI namespace, for AtkObject
+ */
+struct MaiAtkObject
+{
+ AtkObject parent;
+ /*
+ * The AccessibleWrap whose properties and features are exported
+ * via this object instance.
+ */
+ mozilla::a11y::AccessibleOrProxy accWrap;
+
+ /*
+ * Get the AtkHyperlink for this atk object.
+ */
+ AtkHyperlink* GetAtkHyperlink();
+
+ /*
+ * Shutdown this AtkObject.
+ */
+ void Shutdown();
+
+ /*
+ * Notify atk of a state change on this AtkObject.
+ */
+ void FireStateChangeEvent(uint64_t aState, bool aEnabled);
+
+ /*
+ * Notify ATK of a text change within this ATK object.
+ */
+ void FireTextChangeEvent(const nsString& aStr, int32_t aStart, uint32_t aLen,
+ bool aIsInsert, bool aIsFromUser);
+
+ /**
+ * Notify ATK of a shown or hidden subtree rooted at aObject whose parent is
+ * aParent
+ */
+ void FireAtkShowHideEvent(AtkObject* aParent, bool aIsAdded, bool aFromUser);
+
+private:
+ /*
+ * do we have text-remove and text-insert signals if not we need to use
+ * text-changed see AccessibleWrap::FireAtkTextChangedEvent() and
+ * bug 619002
+ */
+ enum EAvailableAtkSignals {
+ eUnknown,
+ eHaveNewAtkTextSignals,
+ eNoNewAtkSignals
+ };
+
+ static EAvailableAtkSignals gAvailableAtkSignals;
+};
+
+#endif /* __NS_MAI_H__ */
diff --git a/accessible/atk/nsMaiHyperlink.cpp b/accessible/atk/nsMaiHyperlink.cpp
new file mode 100644
index 0000000000..9d33f6665a
--- /dev/null
+++ b/accessible/atk/nsMaiHyperlink.cpp
@@ -0,0 +1,262 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsIURI.h"
+#include "nsMaiHyperlink.h"
+#include "mozilla/a11y/ProxyAccessible.h"
+
+using namespace mozilla::a11y;
+
+/* MaiAtkHyperlink */
+
+#define MAI_TYPE_ATK_HYPERLINK (mai_atk_hyperlink_get_type ())
+#define MAI_ATK_HYPERLINK(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),\
+ MAI_TYPE_ATK_HYPERLINK, MaiAtkHyperlink))
+#define MAI_ATK_HYPERLINK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),\
+ MAI_TYPE_ATK_HYPERLINK, MaiAtkHyperlinkClass))
+#define MAI_IS_ATK_HYPERLINK(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj),\
+ MAI_TYPE_ATK_HYPERLINK))
+#define MAI_IS_ATK_HYPERLINK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),\
+ MAI_TYPE_ATK_HYPERLINK))
+#define MAI_ATK_HYPERLINK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
+ MAI_TYPE_ATK_HYPERLINK, MaiAtkHyperlinkClass))
+
+/**
+ * This MaiAtkHyperlink is a thin wrapper, in the MAI namespace,
+ * for AtkHyperlink
+ */
+
+struct MaiAtkHyperlink
+{
+ AtkHyperlink parent;
+
+ /*
+ * The MaiHyperlink whose properties and features are exported via this
+ * hyperlink instance.
+ */
+ MaiHyperlink *maiHyperlink;
+};
+
+struct MaiAtkHyperlinkClass
+{
+ AtkHyperlinkClass parent_class;
+};
+
+GType mai_atk_hyperlink_get_type(void);
+
+G_BEGIN_DECLS
+/* callbacks for AtkHyperlink */
+static void classInitCB(AtkHyperlinkClass *aClass);
+static void finalizeCB(GObject *aObj);
+
+/* callbacks for AtkHyperlink virtual functions */
+static gchar *getUriCB(AtkHyperlink *aLink, gint aLinkIndex);
+static AtkObject *getObjectCB(AtkHyperlink *aLink, gint aLinkIndex);
+static gint getEndIndexCB(AtkHyperlink *aLink);
+static gint getStartIndexCB(AtkHyperlink *aLink);
+static gboolean isValidCB(AtkHyperlink *aLink);
+static gint getAnchorCountCB(AtkHyperlink *aLink);
+G_END_DECLS
+
+static gpointer parent_class = nullptr;
+
+static MaiHyperlink*
+GetMaiHyperlink(AtkHyperlink *aHyperlink)
+{
+ NS_ENSURE_TRUE(MAI_IS_ATK_HYPERLINK(aHyperlink), nullptr);
+ MaiHyperlink * maiHyperlink =
+ MAI_ATK_HYPERLINK(aHyperlink)->maiHyperlink;
+ NS_ENSURE_TRUE(maiHyperlink != nullptr, nullptr);
+ NS_ENSURE_TRUE(maiHyperlink->GetAtkHyperlink() == aHyperlink, nullptr);
+ return maiHyperlink;
+}
+
+GType
+mai_atk_hyperlink_get_type(void)
+{
+ static GType type = 0;
+
+ if (!type) {
+ static const GTypeInfo tinfo = {
+ sizeof(MaiAtkHyperlinkClass),
+ (GBaseInitFunc)nullptr,
+ (GBaseFinalizeFunc)nullptr,
+ (GClassInitFunc)classInitCB,
+ (GClassFinalizeFunc)nullptr,
+ nullptr, /* class data */
+ sizeof(MaiAtkHyperlink), /* instance size */
+ 0, /* nb preallocs */
+ (GInstanceInitFunc)nullptr,
+ nullptr /* value table */
+ };
+
+ type = g_type_register_static(ATK_TYPE_HYPERLINK,
+ "MaiAtkHyperlink",
+ &tinfo, GTypeFlags(0));
+ }
+ return type;
+}
+
+MaiHyperlink::MaiHyperlink(AccessibleOrProxy aHyperLink) :
+ mHyperlink(aHyperLink),
+ mMaiAtkHyperlink(nullptr)
+{
+ mMaiAtkHyperlink =
+ reinterpret_cast<AtkHyperlink *>
+ (g_object_new(mai_atk_hyperlink_get_type(), nullptr));
+ NS_ASSERTION(mMaiAtkHyperlink, "OUT OF MEMORY");
+ if (!mMaiAtkHyperlink)
+ return;
+
+ MAI_ATK_HYPERLINK(mMaiAtkHyperlink)->maiHyperlink = this;
+}
+
+MaiHyperlink::~MaiHyperlink()
+{
+ if (mMaiAtkHyperlink) {
+ MAI_ATK_HYPERLINK(mMaiAtkHyperlink)->maiHyperlink = nullptr;
+ g_object_unref(mMaiAtkHyperlink);
+ }
+}
+
+
+/* static functions for ATK callbacks */
+
+void
+classInitCB(AtkHyperlinkClass *aClass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS(aClass);
+
+ parent_class = g_type_class_peek_parent(aClass);
+
+ aClass->get_uri = getUriCB;
+ aClass->get_object = getObjectCB;
+ aClass->get_end_index = getEndIndexCB;
+ aClass->get_start_index = getStartIndexCB;
+ aClass->is_valid = isValidCB;
+ aClass->get_n_anchors = getAnchorCountCB;
+
+ gobject_class->finalize = finalizeCB;
+}
+
+void
+finalizeCB(GObject *aObj)
+{
+ NS_ASSERTION(MAI_IS_ATK_HYPERLINK(aObj), "Invalid MaiAtkHyperlink");
+ if (!MAI_IS_ATK_HYPERLINK(aObj))
+ return;
+
+ MaiAtkHyperlink *maiAtkHyperlink = MAI_ATK_HYPERLINK(aObj);
+ maiAtkHyperlink->maiHyperlink = nullptr;
+
+ /* call parent finalize function */
+ if (G_OBJECT_CLASS (parent_class)->finalize)
+ G_OBJECT_CLASS (parent_class)->finalize(aObj);
+}
+
+gchar *
+getUriCB(AtkHyperlink *aLink, gint aLinkIndex)
+{
+ MaiHyperlink* maiLink = GetMaiHyperlink(aLink);
+ if (!maiLink)
+ return nullptr;
+
+ nsAutoCString cautoStr;
+ if (Accessible* hyperlink = maiLink->GetAccHyperlink()) {
+ nsCOMPtr<nsIURI> uri = hyperlink->AnchorURIAt(aLinkIndex);
+ if (!uri)
+ return nullptr;
+
+ nsresult rv = uri->GetSpec(cautoStr);
+ NS_ENSURE_SUCCESS(rv, nullptr);
+
+ return g_strdup(cautoStr.get());
+ }
+
+ bool valid;
+ maiLink->Proxy()->AnchorURIAt(aLinkIndex, cautoStr, &valid);
+ if (!valid)
+ return nullptr;
+
+ return g_strdup(cautoStr.get());
+}
+
+AtkObject *
+getObjectCB(AtkHyperlink *aLink, gint aLinkIndex)
+{
+ MaiHyperlink* maiLink = GetMaiHyperlink(aLink);
+ if (!maiLink) {
+ return nullptr;
+ }
+
+ if (Accessible* hyperlink = maiLink->GetAccHyperlink()) {
+ Accessible* anchor = hyperlink->AnchorAt(aLinkIndex);
+ NS_ENSURE_TRUE(anchor, nullptr);
+
+ return AccessibleWrap::GetAtkObject(anchor);
+ }
+
+ ProxyAccessible* anchor = maiLink->Proxy()->AnchorAt(aLinkIndex);
+ return anchor ? GetWrapperFor(anchor) : nullptr;
+}
+
+gint
+getEndIndexCB(AtkHyperlink *aLink)
+{
+ MaiHyperlink* maiLink = GetMaiHyperlink(aLink);
+ if (!maiLink)
+ return false;
+
+ if (Accessible* hyperlink = maiLink->GetAccHyperlink())
+ return static_cast<gint>(hyperlink->EndOffset());
+
+ bool valid = false;
+ uint32_t endIdx = maiLink->Proxy()->EndOffset(&valid);
+ return valid ? static_cast<gint>(endIdx) : -1;
+}
+
+gint
+getStartIndexCB(AtkHyperlink *aLink)
+{
+ MaiHyperlink* maiLink = GetMaiHyperlink(aLink);
+ if (!maiLink)
+ return -1;
+
+ if (Accessible* hyperlink = maiLink->GetAccHyperlink())
+ return static_cast<gint>(hyperlink->StartOffset());
+
+ bool valid = false;
+ uint32_t startIdx = maiLink->Proxy()->StartOffset(&valid);
+ return valid ? static_cast<gint>(startIdx) : -1;
+}
+
+gboolean
+isValidCB(AtkHyperlink *aLink)
+{
+ MaiHyperlink* maiLink = GetMaiHyperlink(aLink);
+ if (!maiLink)
+ return false;
+
+ if (Accessible* hyperlink = maiLink->GetAccHyperlink())
+ return static_cast<gboolean>(hyperlink->IsLinkValid());
+
+ return static_cast<gboolean>(maiLink->Proxy()->IsLinkValid());
+}
+
+gint
+getAnchorCountCB(AtkHyperlink *aLink)
+{
+ MaiHyperlink* maiLink = GetMaiHyperlink(aLink);
+ if (!maiLink)
+ return -1;
+
+ if (Accessible* hyperlink = maiLink->GetAccHyperlink())
+ return static_cast<gint>(hyperlink->AnchorCount());
+
+ bool valid = false;
+ uint32_t anchorCount = maiLink->Proxy()->AnchorCount(&valid);
+ return valid ? static_cast<gint>(anchorCount) : -1;
+}
diff --git a/accessible/atk/nsMaiHyperlink.h b/accessible/atk/nsMaiHyperlink.h
new file mode 100644
index 0000000000..7dc1b73551
--- /dev/null
+++ b/accessible/atk/nsMaiHyperlink.h
@@ -0,0 +1,55 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef __MAI_HYPERLINK_H__
+#define __MAI_HYPERLINK_H__
+
+#include "nsMai.h"
+#include "Accessible.h"
+
+struct _AtkHyperlink;
+typedef struct _AtkHyperlink AtkHyperlink;
+
+namespace mozilla {
+namespace a11y {
+
+/*
+ * MaiHyperlink is a auxiliary class for MaiInterfaceHyperText.
+ */
+
+class MaiHyperlink
+{
+public:
+ explicit MaiHyperlink(AccessibleOrProxy aHyperLink);
+ ~MaiHyperlink();
+
+public:
+ AtkHyperlink* GetAtkHyperlink() const { return mMaiAtkHyperlink; }
+ Accessible* GetAccHyperlink()
+ {
+ if (!mHyperlink.IsAccessible())
+ return nullptr;
+
+ Accessible* link = mHyperlink.AsAccessible();
+ if (!link) {
+ return nullptr;
+ }
+
+ NS_ASSERTION(link->IsLink(), "Why isn't it a link!");
+ return link;
+ }
+
+ ProxyAccessible* Proxy() const { return mHyperlink.AsProxy(); }
+
+protected:
+ AccessibleOrProxy mHyperlink;
+ AtkHyperlink* mMaiAtkHyperlink;
+};
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif /* __MAI_HYPERLINK_H__ */
diff --git a/accessible/atk/nsMaiInterfaceAction.cpp b/accessible/atk/nsMaiInterfaceAction.cpp
new file mode 100644
index 0000000000..9ba1216658
--- /dev/null
+++ b/accessible/atk/nsMaiInterfaceAction.cpp
@@ -0,0 +1,105 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "InterfaceInitFuncs.h"
+
+#include "Accessible-inl.h"
+#include "nsMai.h"
+#include "Role.h"
+#include "mozilla/Likely.h"
+#include "ProxyAccessible.h"
+#include "nsString.h"
+
+using namespace mozilla::a11y;
+
+extern "C" {
+
+static gboolean
+doActionCB(AtkAction *aAction, gint aActionIndex)
+{
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aAction));
+ if (accWrap) {
+ return accWrap->DoAction(aActionIndex);
+ }
+
+ ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aAction));
+ return proxy && proxy->DoAction(aActionIndex);
+}
+
+static gint
+getActionCountCB(AtkAction *aAction)
+{
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aAction));
+ if (accWrap) {
+ return accWrap->ActionCount();
+ }
+
+ ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aAction));
+ return proxy ? proxy->ActionCount() : 0;
+}
+
+static const gchar*
+getActionDescriptionCB(AtkAction *aAction, gint aActionIndex)
+{
+ nsAutoString description;
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aAction));
+ if (accWrap) {
+ accWrap->ActionDescriptionAt(aActionIndex, description);
+ } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aAction))) {
+ proxy->ActionDescriptionAt(aActionIndex, description);
+ } else {
+ return nullptr;
+ }
+
+ return AccessibleWrap::ReturnString(description);
+}
+
+static const gchar*
+getActionNameCB(AtkAction *aAction, gint aActionIndex)
+{
+ nsAutoString autoStr;
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aAction));
+ if (accWrap) {
+ accWrap->ActionNameAt(aActionIndex, autoStr);
+ } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aAction))) {
+ proxy->ActionNameAt(aActionIndex, autoStr);
+ } else {
+ return nullptr;
+ }
+
+ return AccessibleWrap::ReturnString(autoStr);
+}
+
+static const gchar*
+getKeyBindingCB(AtkAction *aAction, gint aActionIndex)
+{
+ nsAutoString keyBindingsStr;
+ AccessibleWrap* acc = GetAccessibleWrap(ATK_OBJECT(aAction));
+ if (acc) {
+ AccessibleWrap::GetKeyBinding(acc, keyBindingsStr);
+ } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aAction))) {
+ proxy->AtkKeyBinding(keyBindingsStr);
+ } else {
+ return nullptr;
+ }
+
+ return AccessibleWrap::ReturnString(keyBindingsStr);
+}
+}
+
+void
+actionInterfaceInitCB(AtkActionIface* aIface)
+{
+ NS_ASSERTION(aIface, "Invalid aIface");
+ if (MOZ_UNLIKELY(!aIface))
+ return;
+
+ aIface->do_action = doActionCB;
+ aIface->get_n_actions = getActionCountCB;
+ aIface->get_description = getActionDescriptionCB;
+ aIface->get_keybinding = getKeyBindingCB;
+ aIface->get_name = getActionNameCB;
+}
diff --git a/accessible/atk/nsMaiInterfaceComponent.cpp b/accessible/atk/nsMaiInterfaceComponent.cpp
new file mode 100644
index 0000000000..efd8eb65cd
--- /dev/null
+++ b/accessible/atk/nsMaiInterfaceComponent.cpp
@@ -0,0 +1,151 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "InterfaceInitFuncs.h"
+
+#include "AccessibleWrap.h"
+#include "nsAccUtils.h"
+#include "nsCoreUtils.h"
+#include "nsMai.h"
+#include "mozilla/Likely.h"
+#include "mozilla/a11y/ProxyAccessible.h"
+
+using namespace mozilla::a11y;
+
+extern "C" {
+
+static AtkObject*
+refAccessibleAtPointCB(AtkComponent* aComponent, gint aAccX, gint aAccY,
+ AtkCoordType aCoordType)
+{
+ return refAccessibleAtPointHelper(ATK_OBJECT(aComponent),
+ aAccX, aAccY, aCoordType);
+}
+
+static void
+getExtentsCB(AtkComponent* aComponent, gint* aX, gint* aY,
+ gint* aWidth, gint* aHeight, AtkCoordType aCoordType)
+{
+ getExtentsHelper(ATK_OBJECT(aComponent),
+ aX, aY, aWidth, aHeight, aCoordType);
+}
+
+static gboolean
+grabFocusCB(AtkComponent* aComponent)
+{
+ AtkObject* atkObject = ATK_OBJECT(aComponent);
+ AccessibleWrap* accWrap = GetAccessibleWrap(atkObject);
+ if (accWrap) {
+ accWrap->TakeFocus();
+ return TRUE;
+ }
+
+ ProxyAccessible* proxy = GetProxy(atkObject);
+ if (proxy) {
+ proxy->TakeFocus();
+ return TRUE;
+ }
+
+ return FALSE;
+}
+}
+
+AtkObject*
+refAccessibleAtPointHelper(AtkObject* aAtkObj, gint aX, gint aY,
+ AtkCoordType aCoordType)
+{
+ AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj);
+ if (accWrap) {
+ if (accWrap->IsDefunct() || nsAccUtils::MustPrune(accWrap)) {
+ return nullptr;
+ }
+
+ // Accessible::ChildAtPoint(x,y) is in screen pixels.
+ if (aCoordType == ATK_XY_WINDOW) {
+ nsIntPoint winCoords =
+ nsCoreUtils::GetScreenCoordsForWindow(accWrap->GetNode());
+ aX += winCoords.x;
+ aY += winCoords.y;
+ }
+
+ Accessible* accAtPoint = accWrap->ChildAtPoint(aX, aY,
+ Accessible::eDirectChild);
+ if (!accAtPoint) {
+ return nullptr;
+ }
+
+ AtkObject* atkObj = AccessibleWrap::GetAtkObject(accAtPoint);
+ if (atkObj) {
+ g_object_ref(atkObj);
+ }
+
+ return atkObj;
+ }
+
+ if (ProxyAccessible* proxy = GetProxy(aAtkObj)) {
+ ProxyAccessible* result =
+ proxy->AccessibleAtPoint(aX, aY, aCoordType == ATK_XY_WINDOW);
+ AtkObject* atkObj = result ? GetWrapperFor(result) : nullptr;
+ if (atkObj) {
+ g_object_ref(atkObj);
+ }
+ return atkObj;
+ }
+
+ return nullptr;
+}
+
+void
+getExtentsHelper(AtkObject* aAtkObj,
+ gint* aX, gint* aY, gint* aWidth, gint* aHeight,
+ AtkCoordType aCoordType)
+{
+ AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj);
+ *aX = *aY = *aWidth = *aHeight = 0;
+
+ if (accWrap) {
+ if (accWrap->IsDefunct()) {
+ return;
+ }
+
+ nsIntRect screenRect = accWrap->Bounds();
+ if (screenRect.IsEmpty())
+ return;
+
+ if (aCoordType == ATK_XY_WINDOW) {
+ nsIntPoint winCoords =
+ nsCoreUtils::GetScreenCoordsForWindow(accWrap->GetNode());
+ screenRect.x -= winCoords.x;
+ screenRect.y -= winCoords.y;
+ }
+
+ *aX = screenRect.x;
+ *aY = screenRect.y;
+ *aWidth = screenRect.width;
+ *aHeight = screenRect.height;
+ return;
+ }
+
+ if (ProxyAccessible* proxy = GetProxy(aAtkObj)) {
+ proxy->Extents(aCoordType == ATK_XY_WINDOW, aX, aY, aWidth, aHeight);
+ }
+}
+
+void
+componentInterfaceInitCB(AtkComponentIface* aIface)
+{
+ NS_ASSERTION(aIface, "Invalid Interface");
+ if(MOZ_UNLIKELY(!aIface))
+ return;
+
+ /*
+ * Use default implementation in atk for contains, get_position,
+ * and get_size
+ */
+ aIface->ref_accessible_at_point = refAccessibleAtPointCB;
+ aIface->get_extents = getExtentsCB;
+ aIface->grab_focus = grabFocusCB;
+}
diff --git a/accessible/atk/nsMaiInterfaceDocument.cpp b/accessible/atk/nsMaiInterfaceDocument.cpp
new file mode 100644
index 0000000000..801028f9c3
--- /dev/null
+++ b/accessible/atk/nsMaiInterfaceDocument.cpp
@@ -0,0 +1,151 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "InterfaceInitFuncs.h"
+
+#include "Accessible-inl.h"
+#include "AccessibleWrap.h"
+#include "DocAccessible.h"
+#include "nsMai.h"
+#include "ProxyAccessible.h"
+#include "mozilla/Likely.h"
+
+using namespace mozilla::a11y;
+
+static const char* const kDocTypeName = "W3C-doctype";
+static const char* const kDocUrlName = "DocURL";
+static const char* const kMimeTypeName = "MimeType";
+
+// below functions are vfuncs on an ATK interface so they need to be C call
+extern "C" {
+
+static const gchar* getDocumentLocaleCB(AtkDocument* aDocument);
+static AtkAttributeSet* getDocumentAttributesCB(AtkDocument* aDocument);
+static const gchar* getDocumentAttributeValueCB(AtkDocument* aDocument,
+ const gchar* aAttrName);
+
+void
+documentInterfaceInitCB(AtkDocumentIface *aIface)
+{
+ NS_ASSERTION(aIface, "Invalid Interface");
+ if(MOZ_UNLIKELY(!aIface))
+ return;
+
+ /*
+ * We don't support get_document or set_attribute right now.
+ * get_document_type is deprecated, we return DocType in
+ * get_document_attribute_value and get_document_attributes instead.
+ */
+ aIface->get_document_attributes = getDocumentAttributesCB;
+ aIface->get_document_attribute_value = getDocumentAttributeValueCB;
+ aIface->get_document_locale = getDocumentLocaleCB;
+}
+
+const gchar *
+getDocumentLocaleCB(AtkDocument *aDocument)
+{
+ nsAutoString locale;
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aDocument));
+ if (accWrap) {
+ accWrap->Language(locale);
+ } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aDocument))) {
+ proxy->Language(locale);
+ }
+
+ return locale.IsEmpty() ? nullptr : AccessibleWrap::ReturnString(locale);
+}
+
+static inline GSList *
+prependToList(GSList *aList, const char *const aName, const nsAutoString &aValue)
+{
+ if (aValue.IsEmpty()) {
+ return aList;
+ }
+
+ // libspi will free these
+ AtkAttribute *atkAttr = (AtkAttribute *)g_malloc(sizeof(AtkAttribute));
+ atkAttr->name = g_strdup(aName);
+ atkAttr->value = g_strdup(NS_ConvertUTF16toUTF8(aValue).get());
+ return g_slist_prepend(aList, atkAttr);
+}
+
+AtkAttributeSet *
+getDocumentAttributesCB(AtkDocument *aDocument)
+{
+ nsAutoString url;
+ nsAutoString w3cDocType;
+ nsAutoString mimeType;
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aDocument));
+ if (accWrap) {
+ if (!accWrap->IsDoc()) {
+ return nullptr;
+ }
+
+ DocAccessible* document = accWrap->AsDoc();
+ document->URL(url);
+ document->DocType(w3cDocType);
+ document->MimeType(mimeType);
+ } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aDocument))) {
+ proxy->URLDocTypeMimeType(url, w3cDocType, mimeType);
+ } else {
+ return nullptr;
+ }
+
+ // according to atkobject.h, AtkAttributeSet is a GSList
+ GSList* attributes = nullptr;
+ attributes = prependToList(attributes, kDocUrlName, url);
+ attributes = prependToList(attributes, kDocTypeName, w3cDocType);
+ attributes = prependToList(attributes, kMimeTypeName, mimeType);
+
+ return attributes;
+}
+
+const gchar *
+getDocumentAttributeValueCB(AtkDocument *aDocument,
+ const gchar *aAttrName)
+{
+ ProxyAccessible* proxy = nullptr;
+ DocAccessible* document = nullptr;
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aDocument));
+ if (accWrap) {
+ if (!accWrap->IsDoc()) {
+ return nullptr;
+ }
+
+ document = accWrap->AsDoc();
+ } else {
+ proxy = GetProxy(ATK_OBJECT(aDocument));
+ if (!proxy) {
+ return nullptr;
+ }
+ }
+
+ nsAutoString attrValue;
+ if (!strcasecmp(aAttrName, kDocTypeName)) {
+ if (document) {
+ document->DocType(attrValue);
+ } else {
+ proxy->DocType(attrValue);
+ }
+ } else if (!strcasecmp(aAttrName, kDocUrlName)) {
+ if (document) {
+ document->URL(attrValue);
+ } else {
+ proxy->URL(attrValue);
+ }
+ } else if (!strcasecmp(aAttrName, kMimeTypeName)) {
+ if (document) {
+ document->MimeType(attrValue);
+ } else {
+ proxy->MimeType(attrValue);
+ }
+ } else {
+ return nullptr;
+ }
+
+ return attrValue.IsEmpty() ? nullptr : AccessibleWrap::ReturnString(attrValue);
+}
+}
diff --git a/accessible/atk/nsMaiInterfaceEditableText.cpp b/accessible/atk/nsMaiInterfaceEditableText.cpp
new file mode 100644
index 0000000000..18a1b6f422
--- /dev/null
+++ b/accessible/atk/nsMaiInterfaceEditableText.cpp
@@ -0,0 +1,134 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "InterfaceInitFuncs.h"
+
+#include "Accessible-inl.h"
+#include "HyperTextAccessible-inl.h"
+#include "nsMai.h"
+#include "ProxyAccessible.h"
+#include "nsString.h"
+#include "mozilla/Likely.h"
+
+using namespace mozilla::a11y;
+
+extern "C" {
+static void
+setTextContentsCB(AtkEditableText *aText, const gchar *aString)
+{
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
+ if (accWrap) {
+ HyperTextAccessible* text = accWrap->AsHyperText();
+ if (!text || !text->IsTextRole()) {
+ return;
+ }
+
+ NS_ConvertUTF8toUTF16 strContent(aString);
+ text->ReplaceText(strContent);
+ } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
+ NS_ConvertUTF8toUTF16 strContent(aString);
+ proxy->ReplaceText(strContent);
+ }
+}
+
+static void
+insertTextCB(AtkEditableText *aText,
+ const gchar *aString, gint aLength, gint *aPosition)
+{
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
+ if (accWrap) {
+ HyperTextAccessible* text = accWrap->AsHyperText();
+ if (!text || !text->IsTextRole()) {
+ return;
+ }
+
+ NS_ConvertUTF8toUTF16 strContent(aString);
+ text->InsertText(strContent, *aPosition);
+ } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
+ NS_ConvertUTF8toUTF16 strContent(aString);
+ proxy->InsertText(strContent, *aPosition);
+ }
+}
+
+static void
+copyTextCB(AtkEditableText *aText, gint aStartPos, gint aEndPos)
+{
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
+ if (accWrap) {
+ HyperTextAccessible* text = accWrap->AsHyperText();
+ if (!text || !text->IsTextRole()) {
+ return;
+ }
+
+ text->CopyText(aStartPos, aEndPos);
+ } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
+ proxy->CopyText(aStartPos, aEndPos);
+ }
+}
+
+static void
+cutTextCB(AtkEditableText *aText, gint aStartPos, gint aEndPos)
+{
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
+ if (accWrap) {
+ HyperTextAccessible* text = accWrap->AsHyperText();
+ if (!text || !text->IsTextRole()) {
+ return;
+ }
+
+ text->CutText(aStartPos, aEndPos);
+ } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
+ proxy->CutText(aStartPos, aEndPos);
+ }
+}
+
+static void
+deleteTextCB(AtkEditableText *aText, gint aStartPos, gint aEndPos)
+{
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
+ if (accWrap) {
+ HyperTextAccessible* text = accWrap->AsHyperText();
+ if (!text || !text->IsTextRole()) {
+ return;
+ }
+
+ text->DeleteText(aStartPos, aEndPos);
+ } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
+ proxy->DeleteText(aStartPos, aEndPos);
+ }
+}
+
+static void
+pasteTextCB(AtkEditableText *aText, gint aPosition)
+{
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
+ if (accWrap) {
+ HyperTextAccessible* text = accWrap->AsHyperText();
+ if (!text || !text->IsTextRole()) {
+ return;
+ }
+
+ text->PasteText(aPosition);
+ } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
+ proxy->PasteText(aPosition);
+ }
+}
+}
+
+void
+editableTextInterfaceInitCB(AtkEditableTextIface* aIface)
+{
+ NS_ASSERTION(aIface, "Invalid aIface");
+ if (MOZ_UNLIKELY(!aIface))
+ return;
+
+ aIface->set_text_contents = setTextContentsCB;
+ aIface->insert_text = insertTextCB;
+ aIface->copy_text = copyTextCB;
+ aIface->cut_text = cutTextCB;
+ aIface->delete_text = deleteTextCB;
+ aIface->paste_text = pasteTextCB;
+}
diff --git a/accessible/atk/nsMaiInterfaceHyperlinkImpl.cpp b/accessible/atk/nsMaiInterfaceHyperlinkImpl.cpp
new file mode 100644
index 0000000000..f8cfd6fc16
--- /dev/null
+++ b/accessible/atk/nsMaiInterfaceHyperlinkImpl.cpp
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "InterfaceInitFuncs.h"
+
+#include "nsMaiHyperlink.h"
+#include "mozilla/Likely.h"
+
+using namespace mozilla::a11y;
+
+extern "C" {
+static AtkHyperlink*
+getHyperlinkCB(AtkHyperlinkImpl* aImpl)
+{
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aImpl));
+ if (!accWrap && !GetProxy(ATK_OBJECT(aImpl)))
+ return nullptr;
+
+ if (accWrap)
+ NS_ASSERTION(accWrap->IsLink(), "why isn't it a link!");
+
+ return MAI_ATK_OBJECT(aImpl)->GetAtkHyperlink();
+}
+}
+
+void
+hyperlinkImplInterfaceInitCB(AtkHyperlinkImplIface *aIface)
+{
+ NS_ASSERTION(aIface, "no interface!");
+ if (MOZ_UNLIKELY(!aIface))
+ return;
+
+ aIface->get_hyperlink = getHyperlinkCB;
+}
diff --git a/accessible/atk/nsMaiInterfaceHypertext.cpp b/accessible/atk/nsMaiInterfaceHypertext.cpp
new file mode 100644
index 0000000000..d6b3ee8f47
--- /dev/null
+++ b/accessible/atk/nsMaiInterfaceHypertext.cpp
@@ -0,0 +1,94 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "InterfaceInitFuncs.h"
+
+#include "Accessible-inl.h"
+#include "HyperTextAccessible.h"
+#include "nsMai.h"
+#include "nsMaiHyperlink.h"
+#include "ProxyAccessible.h"
+#include "mozilla/Likely.h"
+
+
+using namespace mozilla::a11y;
+
+extern "C" {
+
+static AtkHyperlink*
+getLinkCB(AtkHypertext *aText, gint aLinkIndex)
+{
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
+ AtkObject* atkHyperLink = nullptr;
+ if (accWrap) {
+ HyperTextAccessible* hyperText = accWrap->AsHyperText();
+ NS_ENSURE_TRUE(hyperText, nullptr);
+
+ Accessible* hyperLink = hyperText->LinkAt(aLinkIndex);
+ if (!hyperLink || !hyperLink->IsLink()) {
+ return nullptr;
+ }
+
+ atkHyperLink = AccessibleWrap::GetAtkObject(hyperLink);
+ } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
+ ProxyAccessible* proxyLink = proxy->LinkAt(aLinkIndex);
+ if (!proxyLink)
+ return nullptr;
+
+ atkHyperLink = GetWrapperFor(proxyLink);
+ }
+
+ NS_ENSURE_TRUE(IS_MAI_OBJECT(atkHyperLink), nullptr);
+ return MAI_ATK_OBJECT(atkHyperLink)->GetAtkHyperlink();
+}
+
+static gint
+getLinkCountCB(AtkHypertext *aText)
+{
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
+ if (accWrap) {
+ HyperTextAccessible* hyperText = accWrap->AsHyperText();
+ NS_ENSURE_TRUE(hyperText, -1);
+ return hyperText->LinkCount();
+ }
+
+ if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
+ return proxy->LinkCount();
+ }
+
+ return -1;
+}
+
+static gint
+getLinkIndexCB(AtkHypertext *aText, gint aCharIndex)
+{
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
+ if (accWrap) {
+ HyperTextAccessible* hyperText = accWrap->AsHyperText();
+ NS_ENSURE_TRUE(hyperText, -1);
+
+ return hyperText->LinkIndexAtOffset(aCharIndex);
+ }
+
+ if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
+ return proxy->LinkIndexAtOffset(aCharIndex);
+ }
+
+ return -1;
+}
+}
+
+void
+hypertextInterfaceInitCB(AtkHypertextIface* aIface)
+{
+ NS_ASSERTION(aIface, "no interface!");
+ if (MOZ_UNLIKELY(!aIface))
+ return;
+
+ aIface->get_link = getLinkCB;
+ aIface->get_n_links = getLinkCountCB;
+ aIface->get_link_index = getLinkIndexCB;
+}
diff --git a/accessible/atk/nsMaiInterfaceImage.cpp b/accessible/atk/nsMaiInterfaceImage.cpp
new file mode 100644
index 0000000000..64a3beaab3
--- /dev/null
+++ b/accessible/atk/nsMaiInterfaceImage.cpp
@@ -0,0 +1,77 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "InterfaceInitFuncs.h"
+
+#include "AccessibleWrap.h"
+#include "ImageAccessible.h"
+#include "mozilla/Likely.h"
+#include "nsMai.h"
+#include "nsIAccessibleTypes.h"
+#include "nsIURI.h"
+#include "ProxyAccessible.h"
+
+using namespace mozilla;
+using namespace mozilla::a11y;
+
+extern "C" {
+const gchar* getDescriptionCB(AtkObject* aAtkObj);
+
+static void
+getImagePositionCB(AtkImage* aImage, gint* aAccX, gint* aAccY,
+ AtkCoordType aCoordType)
+{
+ nsIntPoint pos;
+ uint32_t geckoCoordType = (aCoordType == ATK_XY_WINDOW) ?
+ nsIAccessibleCoordinateType::COORDTYPE_WINDOW_RELATIVE :
+ nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE;
+
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aImage));
+ if (accWrap && accWrap->IsImage()) {
+ ImageAccessible* image = accWrap->AsImage();
+ pos = image->Position(geckoCoordType);
+ } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aImage))) {
+ pos = proxy->ImagePosition(geckoCoordType);
+ }
+
+ *aAccX = pos.x;
+ *aAccY = pos.y;
+}
+
+static const gchar*
+getImageDescriptionCB(AtkImage* aImage)
+{
+ return getDescriptionCB(ATK_OBJECT(aImage));
+}
+
+static void
+getImageSizeCB(AtkImage* aImage, gint* aAccWidth, gint* aAccHeight)
+{
+ nsIntSize size;
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aImage));
+ if (accWrap && accWrap->IsImage()) {
+ size = accWrap->AsImage()->Size();
+ } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aImage))) {
+ size = proxy->ImageSize();
+ }
+
+ *aAccWidth = size.width;
+ *aAccHeight = size.height;
+}
+
+} // extern "C"
+
+void
+imageInterfaceInitCB(AtkImageIface* aIface)
+{
+ NS_ASSERTION(aIface, "no interface!");
+ if (MOZ_UNLIKELY(!aIface))
+ return;
+
+ aIface->get_image_position = getImagePositionCB;
+ aIface->get_image_description = getImageDescriptionCB;
+ aIface->get_image_size = getImageSizeCB;
+}
diff --git a/accessible/atk/nsMaiInterfaceSelection.cpp b/accessible/atk/nsMaiInterfaceSelection.cpp
new file mode 100644
index 0000000000..2ce63a4513
--- /dev/null
+++ b/accessible/atk/nsMaiInterfaceSelection.cpp
@@ -0,0 +1,152 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "InterfaceInitFuncs.h"
+
+#include "Accessible-inl.h"
+#include "AccessibleWrap.h"
+#include "nsMai.h"
+#include "ProxyAccessible.h"
+#include "mozilla/Likely.h"
+
+#include <atk/atk.h>
+
+using namespace mozilla::a11y;
+
+extern "C" {
+
+static gboolean
+addSelectionCB(AtkSelection *aSelection, gint i)
+{
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aSelection));
+ if (accWrap && accWrap->IsSelect()) {
+ return accWrap->AddItemToSelection(i);
+ }
+
+ if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aSelection))) {
+ return proxy->AddItemToSelection(i);
+ }
+
+ return FALSE;
+}
+
+static gboolean
+clearSelectionCB(AtkSelection *aSelection)
+{
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aSelection));
+ if (accWrap && accWrap->IsSelect()) {
+ return accWrap->UnselectAll();
+ }
+
+ if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aSelection))) {
+ return proxy->UnselectAll();
+ }
+
+ return FALSE;
+}
+
+static AtkObject*
+refSelectionCB(AtkSelection *aSelection, gint i)
+{
+ AtkObject* atkObj = nullptr;
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aSelection));
+ if (accWrap && accWrap->IsSelect()) {
+ Accessible* selectedItem = accWrap->GetSelectedItem(i);
+ if (!selectedItem) {
+ return nullptr;
+ }
+
+ atkObj = AccessibleWrap::GetAtkObject(selectedItem);
+ } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aSelection))) {
+ ProxyAccessible* selectedItem = proxy->GetSelectedItem(i);
+ if (selectedItem) {
+ atkObj = GetWrapperFor(selectedItem);
+ }
+ }
+
+ if (atkObj) {
+ g_object_ref(atkObj);
+ }
+
+ return atkObj;
+}
+
+static gint
+getSelectionCountCB(AtkSelection *aSelection)
+{
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aSelection));
+ if (accWrap && accWrap->IsSelect()) {
+ return accWrap->SelectedItemCount();
+ }
+
+ if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aSelection))) {
+ return proxy->SelectedItemCount();
+ }
+
+ return -1;
+}
+
+static gboolean
+isChildSelectedCB(AtkSelection *aSelection, gint i)
+{
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aSelection));
+ if (accWrap && accWrap->IsSelect()) {
+ return accWrap->IsItemSelected(i);
+ }
+
+ if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aSelection))) {
+ return proxy->IsItemSelected(i);
+ }
+
+ return FALSE;
+}
+
+static gboolean
+removeSelectionCB(AtkSelection *aSelection, gint i)
+{
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aSelection));
+ if (accWrap && accWrap->IsSelect()) {
+ return accWrap->RemoveItemFromSelection(i);
+ }
+
+ if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aSelection))) {
+ return proxy->RemoveItemFromSelection(i);
+ }
+
+ return FALSE;
+}
+
+static gboolean
+selectAllSelectionCB(AtkSelection *aSelection)
+{
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aSelection));
+ if (accWrap && accWrap->IsSelect()) {
+ return accWrap->SelectAll();
+ }
+
+ if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aSelection))) {
+ return proxy->SelectAll();
+ }
+
+ return FALSE;
+}
+}
+
+void
+selectionInterfaceInitCB(AtkSelectionIface* aIface)
+{
+ NS_ASSERTION(aIface, "Invalid aIface");
+ if (MOZ_UNLIKELY(!aIface))
+ return;
+
+ aIface->add_selection = addSelectionCB;
+ aIface->clear_selection = clearSelectionCB;
+ aIface->ref_selection = refSelectionCB;
+ aIface->get_selection_count = getSelectionCountCB;
+ aIface->is_child_selected = isChildSelectedCB;
+ aIface->remove_selection = removeSelectionCB;
+ aIface->select_all_selection = selectAllSelectionCB;
+}
diff --git a/accessible/atk/nsMaiInterfaceTable.cpp b/accessible/atk/nsMaiInterfaceTable.cpp
new file mode 100644
index 0000000000..c94815f3c8
--- /dev/null
+++ b/accessible/atk/nsMaiInterfaceTable.cpp
@@ -0,0 +1,391 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "InterfaceInitFuncs.h"
+
+#include "Accessible-inl.h"
+#include "AccessibleWrap.h"
+#include "nsAccUtils.h"
+#include "TableAccessible.h"
+#include "TableCellAccessible.h"
+#include "nsMai.h"
+#include "ProxyAccessible.h"
+#include "nsArrayUtils.h"
+
+#include "mozilla/Likely.h"
+
+using namespace mozilla::a11y;
+
+extern "C" {
+static AtkObject*
+refAtCB(AtkTable* aTable, gint aRowIdx, gint aColIdx)
+{
+ if (aRowIdx < 0 || aColIdx < 0) {
+ return nullptr;
+ }
+
+ AtkObject* cellAtkObj = nullptr;
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
+ if (accWrap) {
+ Accessible* cell = accWrap->AsTable()->CellAt(aRowIdx, aColIdx);
+ if (!cell) {
+ return nullptr;
+ }
+
+ cellAtkObj = AccessibleWrap::GetAtkObject(cell);
+ } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
+ ProxyAccessible* cell = proxy->TableCellAt(aRowIdx, aColIdx);
+ if (!cell) {
+ return nullptr;
+ }
+
+ cellAtkObj = GetWrapperFor(cell);
+ }
+
+ if (cellAtkObj) {
+ g_object_ref(cellAtkObj);
+ }
+
+ return cellAtkObj;
+}
+
+static gint
+getIndexAtCB(AtkTable* aTable, gint aRowIdx, gint aColIdx)
+{
+ if (aRowIdx < 0 || aColIdx < 0) {
+ return -1;
+ }
+
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
+ if (accWrap) {
+ return static_cast<gint>(accWrap->AsTable()->CellIndexAt(aRowIdx, aColIdx));
+ }
+
+ if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
+ return static_cast<gint>(proxy->TableCellIndexAt(aRowIdx, aColIdx));
+ }
+
+ return -1;
+}
+
+static gint
+getColumnAtIndexCB(AtkTable *aTable, gint aIdx)
+{
+ if (aIdx < 0) {
+ return -1;
+ }
+
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
+ if (accWrap) {
+ return static_cast<gint>(accWrap->AsTable()->ColIndexAt(aIdx));
+ }
+
+ if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
+ return static_cast<gint>(proxy->TableColumnIndexAt(aIdx));
+ }
+
+ return -1;
+}
+
+static gint
+getRowAtIndexCB(AtkTable *aTable, gint aIdx)
+{
+ if (aIdx < 0) {
+ return -1;
+ }
+
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
+ if (accWrap) {
+ return static_cast<gint>(accWrap->AsTable()->RowIndexAt(aIdx));
+ }
+
+ if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
+ return static_cast<gint>(proxy->TableRowIndexAt(aIdx));
+ }
+
+ return -1;
+}
+
+static gint
+getColumnCountCB(AtkTable *aTable)
+{
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
+ if (accWrap) {
+ return static_cast<gint>(accWrap->AsTable()->ColCount());
+ }
+
+ if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
+ return static_cast<gint>(proxy->TableColumnCount());
+ }
+
+ return -1;
+}
+
+static gint
+getRowCountCB(AtkTable *aTable)
+{
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
+ if (accWrap) {
+ return static_cast<gint>(accWrap->AsTable()->RowCount());
+ }
+
+ if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
+ return static_cast<gint>(proxy->TableRowCount());
+ }
+
+ return -1;
+}
+
+static gint
+getColumnExtentAtCB(AtkTable *aTable, gint aRowIdx, gint aColIdx)
+{
+ if (aRowIdx < 0 || aColIdx < 0) {
+ return -1;
+ }
+
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
+ if (accWrap) {
+ return static_cast<gint>(accWrap->AsTable()->ColExtentAt(aRowIdx, aColIdx));
+ }
+
+ if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
+ return static_cast<gint>(proxy->TableColumnExtentAt(aRowIdx, aColIdx));
+ }
+
+ return -1;
+}
+
+static gint
+getRowExtentAtCB(AtkTable *aTable, gint aRowIdx, gint aColIdx)
+{
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
+ if (accWrap) {
+ return static_cast<gint>(accWrap->AsTable()->RowExtentAt(aRowIdx, aColIdx));
+ }
+
+ if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
+ return static_cast<gint>(proxy->TableRowExtentAt(aRowIdx, aColIdx));
+ }
+
+ return -1;
+}
+
+static AtkObject*
+getCaptionCB(AtkTable* aTable)
+{
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
+ if (accWrap) {
+ Accessible* caption = accWrap->AsTable()->Caption();
+ return caption ? AccessibleWrap::GetAtkObject(caption) : nullptr;
+ }
+
+ if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
+ ProxyAccessible* caption = proxy->TableCaption();
+ return caption ? GetWrapperFor(caption) : nullptr;
+ }
+
+ return nullptr;
+}
+
+static const gchar*
+getColumnDescriptionCB(AtkTable *aTable, gint aColumn)
+{
+ nsAutoString autoStr;
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
+ if (accWrap) {
+ accWrap->AsTable()->ColDescription(aColumn, autoStr);
+ } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
+ proxy->TableColumnDescription(aColumn, autoStr);
+ } else {
+ return nullptr;
+ }
+
+ return AccessibleWrap::ReturnString(autoStr);
+}
+
+static AtkObject*
+getColumnHeaderCB(AtkTable *aTable, gint aColIdx)
+{
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
+ if (accWrap) {
+ Accessible* header =
+ AccessibleWrap::GetColumnHeader(accWrap->AsTable(), aColIdx);
+ return header ? AccessibleWrap::GetAtkObject(header) : nullptr;
+ }
+
+ if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
+ ProxyAccessible* header = proxy->AtkTableColumnHeader(aColIdx);
+ return header ? GetWrapperFor(header) : nullptr;
+ }
+
+ return nullptr;
+}
+
+static const gchar*
+getRowDescriptionCB(AtkTable *aTable, gint aRow)
+{
+ nsAutoString autoStr;
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
+ if (accWrap) {
+ accWrap->AsTable()->RowDescription(aRow, autoStr);
+ } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
+ proxy->TableRowDescription(aRow, autoStr);
+ } else {
+ return nullptr;
+ }
+
+ return AccessibleWrap::ReturnString(autoStr);
+}
+
+static AtkObject*
+getRowHeaderCB(AtkTable *aTable, gint aRowIdx)
+{
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
+ if (accWrap) {
+ Accessible* header =
+ AccessibleWrap::GetRowHeader(accWrap->AsTable(), aRowIdx);
+ return header ? AccessibleWrap::GetAtkObject(header) : nullptr;
+ }
+
+ if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
+ ProxyAccessible* header = proxy->AtkTableRowHeader(aRowIdx);
+ return header ? GetWrapperFor(header) : nullptr;
+ }
+
+ return nullptr;
+}
+
+static AtkObject*
+getSummaryCB(AtkTable *aTable)
+{
+ // Neither html:table nor xul:tree nor ARIA grid/tree have an ability to
+ // link an accessible object to specify a summary. There is closes method
+ // in TableAccessible::summary to get a summary as a string which is not
+ // mapped directly to ATK.
+ return nullptr;
+}
+
+static gint
+getSelectedColumnsCB(AtkTable *aTable, gint** aSelected)
+{
+ *aSelected = nullptr;
+
+ AutoTArray<uint32_t, 10> cols;
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
+ if (accWrap) {
+ accWrap->AsTable()->SelectedColIndices(&cols);
+ } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
+ proxy->TableSelectedColumnIndices(&cols);
+ } else {
+ return 0;
+ }
+
+ if (cols.IsEmpty())
+ return 0;
+
+ gint* atkColumns = g_new(gint, cols.Length());
+ if (!atkColumns) {
+ NS_WARNING("OUT OF MEMORY");
+ return 0;
+ }
+
+ memcpy(atkColumns, cols.Elements(), cols.Length() * sizeof(uint32_t));
+ *aSelected = atkColumns;
+ return cols.Length();
+}
+
+static gint
+getSelectedRowsCB(AtkTable *aTable, gint **aSelected)
+{
+ AutoTArray<uint32_t, 10> rows;
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
+ if (accWrap) {
+ accWrap->AsTable()->SelectedRowIndices(&rows);
+ } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
+ proxy->TableSelectedRowIndices(&rows);
+ } else {
+ return 0;
+ }
+
+ gint* atkRows = g_new(gint, rows.Length());
+ if (!atkRows) {
+ NS_WARNING("OUT OF MEMORY");
+ return 0;
+ }
+
+ memcpy(atkRows, rows.Elements(), rows.Length() * sizeof(uint32_t));
+ *aSelected = atkRows;
+ return rows.Length();
+}
+
+static gboolean
+isColumnSelectedCB(AtkTable *aTable, gint aColIdx)
+{
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
+ if (accWrap) {
+ return static_cast<gboolean>(accWrap->AsTable()->IsColSelected(aColIdx));
+ } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
+ return static_cast<gboolean>(proxy->TableColumnSelected(aColIdx));
+ }
+
+ return FALSE;
+}
+
+static gboolean
+isRowSelectedCB(AtkTable *aTable, gint aRowIdx)
+{
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
+ if (accWrap) {
+ return static_cast<gboolean>(accWrap->AsTable()->IsRowSelected(aRowIdx));
+ } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
+ return static_cast<gboolean>(proxy->TableRowSelected(aRowIdx));
+ }
+
+ return FALSE;
+}
+
+static gboolean
+isCellSelectedCB(AtkTable *aTable, gint aRowIdx, gint aColIdx)
+{
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
+ if (accWrap) {
+ return static_cast<gboolean>(accWrap->AsTable()->
+ IsCellSelected(aRowIdx, aColIdx));
+ } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
+ return static_cast<gboolean>(proxy->TableCellSelected(aRowIdx, aColIdx));
+ }
+
+ return FALSE;
+}
+}
+
+void
+tableInterfaceInitCB(AtkTableIface* aIface)
+{
+ NS_ASSERTION(aIface, "no interface!");
+ if (MOZ_UNLIKELY(!aIface))
+ return;
+
+ aIface->ref_at = refAtCB;
+ aIface->get_index_at = getIndexAtCB;
+ aIface->get_column_at_index = getColumnAtIndexCB;
+ aIface->get_row_at_index = getRowAtIndexCB;
+ aIface->get_n_columns = getColumnCountCB;
+ aIface->get_n_rows = getRowCountCB;
+ aIface->get_column_extent_at = getColumnExtentAtCB;
+ aIface->get_row_extent_at = getRowExtentAtCB;
+ aIface->get_caption = getCaptionCB;
+ aIface->get_column_description = getColumnDescriptionCB;
+ aIface->get_column_header = getColumnHeaderCB;
+ aIface->get_row_description = getRowDescriptionCB;
+ aIface->get_row_header = getRowHeaderCB;
+ aIface->get_summary = getSummaryCB;
+ aIface->get_selected_columns = getSelectedColumnsCB;
+ aIface->get_selected_rows = getSelectedRowsCB;
+ aIface->is_column_selected = isColumnSelectedCB;
+ aIface->is_row_selected = isRowSelectedCB;
+ aIface->is_selected = isCellSelectedCB;
+}
diff --git a/accessible/atk/nsMaiInterfaceTableCell.cpp b/accessible/atk/nsMaiInterfaceTableCell.cpp
new file mode 100644
index 0000000000..39bdd40677
--- /dev/null
+++ b/accessible/atk/nsMaiInterfaceTableCell.cpp
@@ -0,0 +1,216 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "InterfaceInitFuncs.h"
+
+#include "Accessible-inl.h"
+#include "AccessibleWrap.h"
+#include "nsAccUtils.h"
+#include "TableAccessible.h"
+#include "TableCellAccessible.h"
+#include "nsMai.h"
+#include "ProxyAccessible.h"
+#include "nsArrayUtils.h"
+
+#include "mozilla/Likely.h"
+
+using namespace mozilla::a11y;
+
+extern "C" {
+static gint
+GetColumnSpanCB(AtkTableCell* aCell)
+{
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aCell));
+ if (accWrap) {
+ return accWrap->AsTableCell()->ColExtent();
+ }
+
+ if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aCell))) {
+ return proxy->ColExtent();
+ }
+
+ return 0;
+}
+
+static gboolean
+GetRowSpanCB(AtkTableCell* aCell)
+{
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aCell));
+ if (accWrap) {
+ return accWrap->AsTableCell()->RowExtent();
+ }
+
+ if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aCell))) {
+ return proxy->RowExtent();
+ }
+
+ return 0;
+}
+
+static gboolean
+GetPositionCB(AtkTableCell* aCell, gint* aRow, gint* aCol)
+{
+ if (AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aCell))) {
+ TableCellAccessible* cell = accWrap->AsTableCell();
+ *aRow = cell->RowIdx();
+ *aCol = cell->ColIdx();
+ return true;
+ }
+
+ if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aCell))) {
+ uint32_t rowIdx = 0, colIdx = 0;
+ proxy->GetPosition(&rowIdx, &colIdx);
+ *aCol = colIdx;
+ *aRow = rowIdx;
+ return true;
+ }
+
+ return false;
+}
+
+static gboolean
+GetColumnRowSpanCB(AtkTableCell* aCell, gint* aCol, gint* aRow,
+ gint* aColExtent, gint* aRowExtent) {
+ if (AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aCell))) {
+ TableCellAccessible* cellAcc = accWrap->AsTableCell();
+ *aCol = cellAcc->ColIdx();
+ *aRow = cellAcc->RowIdx();
+ *aColExtent = cellAcc->ColExtent();
+ *aRowExtent = cellAcc->ColExtent();
+ return true;
+ }
+
+ if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aCell))) {
+ uint32_t colIdx = 0, rowIdx = 0, colExtent = 0, rowExtent = 0;
+ proxy->GetColRowExtents(&colIdx, &rowIdx, &colExtent, &rowExtent);
+ *aCol = colIdx;
+ *aRow = rowIdx;
+ *aColExtent = colExtent;
+ *aRowExtent = rowExtent;
+ return true;
+ }
+
+ return false;
+}
+
+static AtkObject*
+GetTableCB(AtkTableCell* aTableCell)
+{
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTableCell));
+ if (accWrap) {
+ TableAccessible* table = accWrap->AsTableCell()->Table();
+ if (!table) {
+ return nullptr;
+ }
+
+ Accessible* tableAcc = table->AsAccessible();
+ return tableAcc ? AccessibleWrap::GetAtkObject(tableAcc) : nullptr;
+ }
+
+ if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTableCell))) {
+ ProxyAccessible* table = proxy->TableOfACell();
+ return table ? GetWrapperFor(table) : nullptr;
+ }
+
+ return nullptr;
+}
+
+static GPtrArray*
+GetColumnHeaderCellsCB(AtkTableCell* aCell)
+{
+ if (AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aCell))) {
+ AutoTArray<Accessible*, 10> headers;
+ accWrap->AsTableCell()->ColHeaderCells(&headers);
+ if (headers.IsEmpty()) {
+ return nullptr;
+ }
+
+ GPtrArray* atkHeaders = g_ptr_array_sized_new(headers.Length());
+ for (Accessible* header: headers) {
+ AtkObject* atkHeader = AccessibleWrap::GetAtkObject(header);
+ g_object_ref(atkHeader);
+ g_ptr_array_add(atkHeaders, atkHeader);
+ }
+
+ return atkHeaders;
+ }
+
+ if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aCell))) {
+ AutoTArray<ProxyAccessible*, 10> headers;
+ proxy->ColHeaderCells(&headers);
+ if (headers.IsEmpty()) {
+ return nullptr;
+ }
+
+ GPtrArray* atkHeaders = g_ptr_array_sized_new(headers.Length());
+ for (ProxyAccessible* header: headers) {
+ AtkObject* atkHeader = GetWrapperFor(header);
+ g_object_ref(atkHeader);
+ g_ptr_array_add(atkHeaders, atkHeader);
+ }
+
+ return atkHeaders;
+ }
+
+ return nullptr;
+}
+
+static GPtrArray*
+GetRowHeaderCellsCB(AtkTableCell* aCell)
+{
+ if (AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aCell))) {
+ AutoTArray<Accessible*, 10> headers;
+ accWrap->AsTableCell()->RowHeaderCells(&headers);
+ if (headers.IsEmpty()) {
+ return nullptr;
+ }
+
+ GPtrArray* atkHeaders = g_ptr_array_sized_new(headers.Length());
+ for (Accessible* header: headers) {
+ AtkObject* atkHeader = AccessibleWrap::GetAtkObject(header);
+ g_object_ref(atkHeader);
+ g_ptr_array_add(atkHeaders, atkHeader);
+ }
+
+ return atkHeaders;
+ }
+
+ if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aCell))) {
+ AutoTArray<ProxyAccessible*, 10> headers;
+ proxy->RowHeaderCells(&headers);
+ if (headers.IsEmpty()) {
+ return nullptr;
+ }
+
+ GPtrArray* atkHeaders = g_ptr_array_sized_new(headers.Length());
+ for (ProxyAccessible* header: headers) {
+ AtkObject* atkHeader = GetWrapperFor(header);
+ g_object_ref(atkHeader);
+ g_ptr_array_add(atkHeaders, atkHeader);
+ }
+
+ return atkHeaders;
+ }
+
+ return nullptr;
+}
+}
+
+void
+tableCellInterfaceInitCB(AtkTableCellIface* aIface)
+{
+ NS_ASSERTION(aIface, "no interface!");
+ if (MOZ_UNLIKELY(!aIface))
+ return;
+
+ aIface->get_column_span = GetColumnSpanCB;
+ aIface->get_column_header_cells = GetColumnHeaderCellsCB;
+ aIface->get_position = GetPositionCB;
+ aIface->get_row_span = GetRowSpanCB;
+ aIface->get_row_header_cells = GetRowHeaderCellsCB;
+ aIface->get_row_column_span = GetColumnRowSpanCB;
+ aIface->get_table = GetTableCB;
+}
diff --git a/accessible/atk/nsMaiInterfaceText.cpp b/accessible/atk/nsMaiInterfaceText.cpp
new file mode 100644
index 0000000000..1982f37309
--- /dev/null
+++ b/accessible/atk/nsMaiInterfaceText.cpp
@@ -0,0 +1,629 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "InterfaceInitFuncs.h"
+#include "mozilla/a11y/PDocAccessible.h"
+#include "Accessible-inl.h"
+#include "HyperTextAccessible-inl.h"
+#include "nsMai.h"
+#include "ProxyAccessible.h"
+
+#include "nsIAccessibleTypes.h"
+#include "nsIPersistentProperties2.h"
+#include "nsISimpleEnumerator.h"
+
+#include "mozilla/Likely.h"
+
+using namespace mozilla;
+using namespace mozilla::a11y;
+
+static const char* sAtkTextAttrNames[ATK_TEXT_ATTR_LAST_DEFINED];
+
+void
+ConvertTextAttributeToAtkAttribute(const nsACString& aName,
+ const nsAString& aValue,
+ AtkAttributeSet** aAttributeSet)
+{
+ // Handle attributes where atk has its own name.
+ const char* atkName = nullptr;
+ nsAutoString atkValue;
+ if (aName.EqualsLiteral("color")) {
+ // The format of the atk attribute is r,g,b and the gecko one is
+ // rgb(r, g, b).
+ atkValue = Substring(aValue, 4, aValue.Length() - 5);
+ atkValue.StripWhitespace();
+ atkName = sAtkTextAttrNames[ATK_TEXT_ATTR_FG_COLOR];
+ } else if (aName.EqualsLiteral("background-color")) {
+ // The format of the atk attribute is r,g,b and the gecko one is
+ // rgb(r, g, b).
+ atkValue = Substring(aValue, 4, aValue.Length() - 5);
+ atkValue.StripWhitespace();
+ atkName = sAtkTextAttrNames[ATK_TEXT_ATTR_BG_COLOR];
+ } else if (aName.EqualsLiteral("font-family")) {
+ atkValue = aValue;
+ atkName = sAtkTextAttrNames[ATK_TEXT_ATTR_FAMILY_NAME];
+ } else if (aName.EqualsLiteral("font-size")) {
+ // ATK wants the number of pixels without px at the end.
+ atkValue = StringHead(aValue, aValue.Length() - 2);
+ atkName = sAtkTextAttrNames[ATK_TEXT_ATTR_SIZE];
+ } else if (aName.EqualsLiteral("font-weight")) {
+ atkValue = aValue;
+ atkName = sAtkTextAttrNames[ATK_TEXT_ATTR_WEIGHT];
+ } else if (aName.EqualsLiteral("invalid")) {
+ atkValue = aValue;
+ atkName = sAtkTextAttrNames[ATK_TEXT_ATTR_INVALID];
+ }
+
+ if (atkName) {
+ AtkAttribute* objAttr =
+ static_cast<AtkAttribute*>(g_malloc(sizeof(AtkAttribute)));
+ objAttr->name = g_strdup(atkName);
+ objAttr->value = g_strdup(NS_ConvertUTF16toUTF8(atkValue).get());
+ *aAttributeSet = g_slist_prepend(*aAttributeSet, objAttr);
+ }
+}
+
+static AtkAttributeSet*
+ConvertToAtkTextAttributeSet(nsTArray<Attribute>& aAttributes)
+{
+ AtkAttributeSet* objAttributeSet = nullptr;
+ for (size_t i = 0; i < aAttributes.Length(); ++i) {
+ AtkAttribute* objAttr = (AtkAttribute *)g_malloc(sizeof(AtkAttribute));
+ objAttr->name = g_strdup(aAttributes[i].Name().get());
+ objAttr->value =
+ g_strdup(NS_ConvertUTF16toUTF8(aAttributes[i].Value()).get());
+ objAttributeSet = g_slist_prepend(objAttributeSet, objAttr);
+ ConvertTextAttributeToAtkAttribute(aAttributes[i].Name(),
+ aAttributes[i].Value(),
+ &objAttributeSet);
+ }
+ return objAttributeSet;
+}
+
+static AtkAttributeSet*
+ConvertToAtkTextAttributeSet(nsIPersistentProperties* aAttributes)
+{
+ if (!aAttributes)
+ return nullptr;
+
+ AtkAttributeSet* objAttributeSet = nullptr;
+ nsCOMPtr<nsISimpleEnumerator> propEnum;
+ nsresult rv = aAttributes->Enumerate(getter_AddRefs(propEnum));
+ NS_ENSURE_SUCCESS(rv, nullptr);
+
+ bool hasMore = false;
+ while (NS_SUCCEEDED(propEnum->HasMoreElements(&hasMore)) && hasMore) {
+ nsCOMPtr<nsISupports> sup;
+ rv = propEnum->GetNext(getter_AddRefs(sup));
+ NS_ENSURE_SUCCESS(rv, objAttributeSet);
+
+ nsCOMPtr<nsIPropertyElement> propElem(do_QueryInterface(sup));
+ NS_ENSURE_TRUE(propElem, objAttributeSet);
+
+ nsAutoCString name;
+ rv = propElem->GetKey(name);
+ NS_ENSURE_SUCCESS(rv, objAttributeSet);
+
+ nsAutoString value;
+ rv = propElem->GetValue(value);
+ NS_ENSURE_SUCCESS(rv, objAttributeSet);
+
+ AtkAttribute* objAttr = (AtkAttribute*)g_malloc(sizeof(AtkAttribute));
+ objAttr->name = g_strdup(name.get());
+ objAttr->value = g_strdup(NS_ConvertUTF16toUTF8(value).get());
+ objAttributeSet = g_slist_prepend(objAttributeSet, objAttr);
+
+ ConvertTextAttributeToAtkAttribute(name, value, &objAttributeSet);
+ }
+
+ // libatk-adaptor will free it
+ return objAttributeSet;
+}
+
+static void
+ConvertTexttoAsterisks(AccessibleWrap* accWrap, nsAString& aString)
+{
+ // convert each char to "*" when it's "password text"
+ if (accWrap->NativeRole() == roles::PASSWORD_TEXT) {
+ for (uint32_t i = 0; i < aString.Length(); i++)
+ aString.Replace(i, 1, NS_LITERAL_STRING("*"));
+ }
+}
+
+extern "C" {
+
+static gchar*
+getTextCB(AtkText *aText, gint aStartOffset, gint aEndOffset)
+{
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
+ nsAutoString autoStr;
+ if (accWrap) {
+ HyperTextAccessible* text = accWrap->AsHyperText();
+ if (!text || !text->IsTextRole())
+ return nullptr;
+
+ text->TextSubstring(aStartOffset, aEndOffset, autoStr);
+
+ ConvertTexttoAsterisks(accWrap, autoStr);
+ } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
+ proxy->TextSubstring(aStartOffset, aEndOffset, autoStr);
+ }
+
+ NS_ConvertUTF16toUTF8 cautoStr(autoStr);
+
+ //copy and return, libspi will free it.
+ return (cautoStr.get()) ? g_strdup(cautoStr.get()) : nullptr;
+}
+
+static gchar*
+getTextAfterOffsetCB(AtkText *aText, gint aOffset,
+ AtkTextBoundary aBoundaryType,
+ gint *aStartOffset, gint *aEndOffset)
+{
+ nsAutoString autoStr;
+ int32_t startOffset = 0, endOffset = 0;
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
+ if (accWrap) {
+ HyperTextAccessible* text = accWrap->AsHyperText();
+ if (!text || !text->IsTextRole())
+ return nullptr;
+
+ text->TextAfterOffset(aOffset, aBoundaryType, &startOffset, &endOffset, autoStr);
+ ConvertTexttoAsterisks(accWrap, autoStr);
+ } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
+ proxy->GetTextAfterOffset(aOffset, aBoundaryType, autoStr, &startOffset,
+ &endOffset);
+ }
+
+ *aStartOffset = startOffset;
+ *aEndOffset = endOffset;
+
+ NS_ConvertUTF16toUTF8 cautoStr(autoStr);
+ return (cautoStr.get()) ? g_strdup(cautoStr.get()) : nullptr;
+}
+
+static gchar*
+getTextAtOffsetCB(AtkText *aText, gint aOffset,
+ AtkTextBoundary aBoundaryType,
+ gint *aStartOffset, gint *aEndOffset)
+{
+ nsAutoString autoStr;
+ int32_t startOffset = 0, endOffset = 0;
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
+ if (accWrap) {
+ HyperTextAccessible* text = accWrap->AsHyperText();
+ if (!text || !text->IsTextRole())
+ return nullptr;
+
+ text->TextAtOffset(aOffset, aBoundaryType, &startOffset, &endOffset, autoStr);
+ ConvertTexttoAsterisks(accWrap, autoStr);
+ } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
+ proxy->GetTextAtOffset(aOffset, aBoundaryType, autoStr, &startOffset,
+ &endOffset);
+ }
+
+ *aStartOffset = startOffset;
+ *aEndOffset = endOffset;
+
+ NS_ConvertUTF16toUTF8 cautoStr(autoStr);
+ return (cautoStr.get()) ? g_strdup(cautoStr.get()) : nullptr;
+}
+
+static gunichar
+getCharacterAtOffsetCB(AtkText* aText, gint aOffset)
+{
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
+ if (accWrap) {
+ HyperTextAccessible* text = accWrap->AsHyperText();
+ if (!text || !text->IsTextRole()) {
+ return 0;
+ }
+
+ // char16_t is unsigned short in Mozilla, gnuichar is guint32 in glib.
+ return static_cast<gunichar>(text->CharAt(aOffset));
+ }
+
+ if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
+ return static_cast<gunichar>(proxy->CharAt(aOffset));
+ }
+
+ return 0;
+}
+
+static gchar*
+getTextBeforeOffsetCB(AtkText *aText, gint aOffset,
+ AtkTextBoundary aBoundaryType,
+ gint *aStartOffset, gint *aEndOffset)
+{
+ nsAutoString autoStr;
+ int32_t startOffset = 0, endOffset = 0;
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
+ if (accWrap) {
+ HyperTextAccessible* text = accWrap->AsHyperText();
+ if (!text || !text->IsTextRole())
+ return nullptr;
+
+ text->TextBeforeOffset(aOffset, aBoundaryType,
+ &startOffset, &endOffset, autoStr);
+ ConvertTexttoAsterisks(accWrap, autoStr);
+ } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
+ proxy->GetTextBeforeOffset(aOffset, aBoundaryType, autoStr, &startOffset,
+ &endOffset);
+ }
+
+ *aStartOffset = startOffset;
+ *aEndOffset = endOffset;
+
+ NS_ConvertUTF16toUTF8 cautoStr(autoStr);
+ return (cautoStr.get()) ? g_strdup(cautoStr.get()) : nullptr;
+}
+
+static gint
+getCaretOffsetCB(AtkText *aText)
+{
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
+ if (accWrap) {
+ HyperTextAccessible* text = accWrap->AsHyperText();
+ if (!text || !text->IsTextRole()) {
+ return 0;
+ }
+
+ return static_cast<gint>(text->CaretOffset());
+ }
+
+ if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
+ return static_cast<gint>(proxy->CaretOffset());
+ }
+
+ return 0;
+}
+
+static AtkAttributeSet*
+getRunAttributesCB(AtkText *aText, gint aOffset,
+ gint *aStartOffset,
+ gint *aEndOffset)
+{
+ *aStartOffset = -1;
+ *aEndOffset = -1;
+ int32_t startOffset = 0, endOffset = 0;
+
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
+ if (accWrap) {
+ HyperTextAccessible* text = accWrap->AsHyperText();
+ if (!text || !text->IsTextRole()) {
+ return nullptr;
+ }
+
+ nsCOMPtr<nsIPersistentProperties> attributes =
+ text->TextAttributes(false, aOffset, &startOffset, &endOffset);
+
+ *aStartOffset = startOffset;
+ *aEndOffset = endOffset;
+
+ return ConvertToAtkTextAttributeSet(attributes);
+ }
+
+ ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText));
+ if (!proxy) {
+ return nullptr;
+ }
+
+ AutoTArray<Attribute, 10> attrs;
+ proxy->TextAttributes(false, aOffset, &attrs, &startOffset, &endOffset);
+ *aStartOffset = startOffset;
+ *aEndOffset = endOffset;
+ return ConvertToAtkTextAttributeSet(attrs);
+}
+
+static AtkAttributeSet*
+getDefaultAttributesCB(AtkText *aText)
+{
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
+ if (accWrap) {
+ HyperTextAccessible* text = accWrap->AsHyperText();
+ if (!text || !text->IsTextRole()) {
+ return nullptr;
+ }
+
+ nsCOMPtr<nsIPersistentProperties> attributes = text->DefaultTextAttributes();
+ return ConvertToAtkTextAttributeSet(attributes);
+ }
+
+ ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText));
+ if (!proxy) {
+ return nullptr;
+ }
+
+ AutoTArray<Attribute, 10> attrs;
+ proxy->DefaultTextAttributes(&attrs);
+ return ConvertToAtkTextAttributeSet(attrs);
+}
+
+static void
+getCharacterExtentsCB(AtkText *aText, gint aOffset,
+ gint *aX, gint *aY,
+ gint *aWidth, gint *aHeight,
+ AtkCoordType aCoords)
+{
+ if(!aX || !aY || !aWidth || !aHeight) {
+ return;
+ }
+
+ nsIntRect rect;
+ uint32_t geckoCoordType;
+ if (aCoords == ATK_XY_SCREEN) {
+ geckoCoordType = nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE;
+ } else {
+ geckoCoordType = nsIAccessibleCoordinateType::COORDTYPE_WINDOW_RELATIVE;
+ }
+
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
+ if (accWrap) {
+ HyperTextAccessible* text = accWrap->AsHyperText();
+ if (!text || !text->IsTextRole()) {
+ return;
+ }
+
+ rect = text->CharBounds(aOffset, geckoCoordType);
+ } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
+ rect = proxy->CharBounds(aOffset, geckoCoordType);
+ } else {
+ return;
+ }
+
+ *aX = rect.x;
+ *aY = rect.y;
+ *aWidth = rect.width;
+ *aHeight = rect.height;
+}
+
+static void
+getRangeExtentsCB(AtkText *aText, gint aStartOffset, gint aEndOffset,
+ AtkCoordType aCoords, AtkTextRectangle *aRect)
+{
+ if (!aRect) {
+ return;
+ }
+
+ nsIntRect rect;
+ uint32_t geckoCoordType;
+ if (aCoords == ATK_XY_SCREEN) {
+ geckoCoordType = nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE;
+ } else {
+ geckoCoordType = nsIAccessibleCoordinateType::COORDTYPE_WINDOW_RELATIVE;
+ }
+
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
+ if(accWrap) {
+ HyperTextAccessible* text = accWrap->AsHyperText();
+ if (!text || !text->IsTextRole()) {
+ return;
+ }
+
+ rect = text->TextBounds(aStartOffset, aEndOffset, geckoCoordType);
+ } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
+ rect = proxy->TextBounds(aStartOffset, aEndOffset, geckoCoordType);
+ } else {
+ return;
+ }
+
+ aRect->x = rect.x;
+ aRect->y = rect.y;
+ aRect->width = rect.width;
+ aRect->height = rect.height;
+}
+
+static gint
+getCharacterCountCB(AtkText *aText)
+{
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
+ if (accWrap) {
+ HyperTextAccessible* textAcc = accWrap->AsHyperText();
+ return
+ textAcc->IsDefunct() ? 0 : static_cast<gint>(textAcc->CharacterCount());
+ }
+
+ if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
+ return proxy->CharacterCount();
+ }
+
+ return 0;
+}
+
+static gint
+getOffsetAtPointCB(AtkText *aText,
+ gint aX, gint aY,
+ AtkCoordType aCoords)
+{
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
+ if (accWrap) {
+ HyperTextAccessible* text = accWrap->AsHyperText();
+ if (!text || !text->IsTextRole()) {
+ return -1;
+ }
+
+ return static_cast<gint>(
+ text->OffsetAtPoint(aX, aY,
+ (aCoords == ATK_XY_SCREEN ?
+ nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE :
+ nsIAccessibleCoordinateType::COORDTYPE_WINDOW_RELATIVE)));
+ }
+
+ if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
+ return static_cast<gint>(
+ proxy->OffsetAtPoint(aX, aY,
+ (aCoords == ATK_XY_SCREEN ?
+ nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE :
+ nsIAccessibleCoordinateType::COORDTYPE_WINDOW_RELATIVE)));
+ }
+
+ return -1;
+}
+
+static gint
+getTextSelectionCountCB(AtkText *aText)
+{
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
+ if (accWrap) {
+ HyperTextAccessible* text = accWrap->AsHyperText();
+ if (!text || !text->IsTextRole()) {
+ return 0;
+ }
+
+ return text->SelectionCount();
+ }
+
+ if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
+ return proxy->SelectionCount();
+ }
+
+ return 0;
+}
+
+static gchar*
+getTextSelectionCB(AtkText *aText, gint aSelectionNum,
+ gint *aStartOffset, gint *aEndOffset)
+{
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
+ int32_t startOffset = 0, endOffset = 0;
+ if (accWrap) {
+ HyperTextAccessible* text = accWrap->AsHyperText();
+ if (!text || !text->IsTextRole()) {
+ return nullptr;
+ }
+
+ text->SelectionBoundsAt(aSelectionNum, &startOffset, &endOffset);
+ *aStartOffset = startOffset;
+ *aEndOffset = endOffset;
+
+ return getTextCB(aText, *aStartOffset, *aEndOffset);
+ } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
+ nsString data;
+ proxy->SelectionBoundsAt(aSelectionNum, data, &startOffset, &endOffset);
+ *aStartOffset = startOffset;
+ *aEndOffset = endOffset;
+
+ NS_ConvertUTF16toUTF8 dataAsUTF8(data);
+ return (dataAsUTF8.get()) ? g_strdup(dataAsUTF8.get()) : nullptr;
+ }
+ return nullptr;
+}
+
+// set methods
+static gboolean
+addTextSelectionCB(AtkText *aText,
+ gint aStartOffset,
+ gint aEndOffset)
+{
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
+ if (accWrap) {
+ HyperTextAccessible* text = accWrap->AsHyperText();
+ if (!text || !text->IsTextRole()) {
+ return FALSE;
+ }
+
+ return text->AddToSelection(aStartOffset, aEndOffset);
+ } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
+ return proxy->AddToSelection(aStartOffset, aEndOffset);
+ }
+
+ return FALSE;
+}
+
+static gboolean
+removeTextSelectionCB(AtkText *aText,
+ gint aSelectionNum)
+{
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
+ if (accWrap) {
+ HyperTextAccessible* text = accWrap->AsHyperText();
+ if (!text || !text->IsTextRole()) {
+ return FALSE;
+ }
+
+ return text->RemoveFromSelection(aSelectionNum);
+ } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
+ return proxy->RemoveFromSelection(aSelectionNum);
+ }
+
+ return FALSE;
+}
+
+static gboolean
+setTextSelectionCB(AtkText *aText, gint aSelectionNum,
+ gint aStartOffset, gint aEndOffset)
+{
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
+ if (accWrap) {
+ HyperTextAccessible* text = accWrap->AsHyperText();
+ if (!text || !text->IsTextRole()) {
+ return FALSE;
+ }
+
+ return text->SetSelectionBoundsAt(aSelectionNum, aStartOffset, aEndOffset);
+ } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
+ return proxy->SetSelectionBoundsAt(aSelectionNum, aStartOffset, aEndOffset);
+ }
+
+ return FALSE;
+}
+
+static gboolean
+setCaretOffsetCB(AtkText *aText, gint aOffset)
+{
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
+ if (accWrap) {
+ HyperTextAccessible* text = accWrap->AsHyperText();
+ if (!text || !text->IsTextRole() || !text->IsValidOffset(aOffset)) {
+ return FALSE;
+ }
+
+ text->SetCaretOffset(aOffset);
+ return TRUE;
+ }
+
+ if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
+ proxy->SetCaretOffset(aOffset);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+}
+
+void
+textInterfaceInitCB(AtkTextIface* aIface)
+{
+ NS_ASSERTION(aIface, "Invalid aIface");
+ if (MOZ_UNLIKELY(!aIface))
+ return;
+
+ aIface->get_text = getTextCB;
+ aIface->get_text_after_offset = getTextAfterOffsetCB;
+ aIface->get_text_at_offset = getTextAtOffsetCB;
+ aIface->get_character_at_offset = getCharacterAtOffsetCB;
+ aIface->get_text_before_offset = getTextBeforeOffsetCB;
+ aIface->get_caret_offset = getCaretOffsetCB;
+ aIface->get_run_attributes = getRunAttributesCB;
+ aIface->get_default_attributes = getDefaultAttributesCB;
+ aIface->get_character_extents = getCharacterExtentsCB;
+ aIface->get_range_extents = getRangeExtentsCB;
+ aIface->get_character_count = getCharacterCountCB;
+ aIface->get_offset_at_point = getOffsetAtPointCB;
+ aIface->get_n_selections = getTextSelectionCountCB;
+ aIface->get_selection = getTextSelectionCB;
+
+ // set methods
+ aIface->add_selection = addTextSelectionCB;
+ aIface->remove_selection = removeTextSelectionCB;
+ aIface->set_selection = setTextSelectionCB;
+ aIface->set_caret_offset = setCaretOffsetCB;
+
+ // Cache the string values of the atk text attribute names.
+ for (uint32_t i = 0; i < ArrayLength(sAtkTextAttrNames); i++)
+ sAtkTextAttrNames[i] =
+ atk_text_attribute_get_name(static_cast<AtkTextAttribute>(i));
+}
diff --git a/accessible/atk/nsMaiInterfaceValue.cpp b/accessible/atk/nsMaiInterfaceValue.cpp
new file mode 100644
index 0000000000..016b3b672c
--- /dev/null
+++ b/accessible/atk/nsMaiInterfaceValue.cpp
@@ -0,0 +1,133 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "InterfaceInitFuncs.h"
+
+#include "AccessibleWrap.h"
+#include "nsMai.h"
+#include "ProxyAccessible.h"
+#include "mozilla/FloatingPoint.h"
+#include "mozilla/Likely.h"
+
+using namespace mozilla;
+using namespace mozilla::a11y;
+
+extern "C" {
+
+static void
+getCurrentValueCB(AtkValue *obj, GValue *value)
+{
+ ProxyAccessible* proxy = nullptr;
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(obj));
+ if (!accWrap) {
+ proxy = GetProxy(ATK_OBJECT(obj));
+ if (!proxy) {
+ return;
+ }
+ }
+
+ memset (value, 0, sizeof (GValue));
+ double accValue = accWrap ? accWrap->CurValue() : proxy->CurValue();
+ if (IsNaN(accValue))
+ return;
+
+ g_value_init (value, G_TYPE_DOUBLE);
+ g_value_set_double (value, accValue);
+}
+
+static void
+getMaximumValueCB(AtkValue *obj, GValue *value)
+{
+ ProxyAccessible* proxy = nullptr;
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(obj));
+ if (!accWrap) {
+ proxy = GetProxy(ATK_OBJECT(obj));
+ if (!proxy) {
+ return;
+ }
+ }
+
+ memset(value, 0, sizeof (GValue));
+ double accValue = accWrap ? accWrap->MaxValue() : proxy->MaxValue();
+ if (IsNaN(accValue))
+ return;
+
+ g_value_init(value, G_TYPE_DOUBLE);
+ g_value_set_double(value, accValue);
+}
+
+static void
+getMinimumValueCB(AtkValue *obj, GValue *value)
+{
+ ProxyAccessible* proxy = nullptr;
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(obj));
+ if (!accWrap) {
+ proxy = GetProxy(ATK_OBJECT(obj));
+ if (!proxy) {
+ return;
+ }
+ }
+
+ memset(value, 0, sizeof (GValue));
+ double accValue = accWrap ? accWrap->MinValue() : proxy->MinValue();
+ if (IsNaN(accValue))
+ return;
+
+ g_value_init(value, G_TYPE_DOUBLE);
+ g_value_set_double(value, accValue);
+}
+
+static void
+getMinimumIncrementCB(AtkValue *obj, GValue *minimumIncrement)
+{
+ ProxyAccessible* proxy = nullptr;
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(obj));
+ if (!accWrap) {
+ proxy = GetProxy(ATK_OBJECT(obj));
+ if (!proxy) {
+ return;
+ }
+ }
+
+ memset(minimumIncrement, 0, sizeof (GValue));
+ double accValue = accWrap ? accWrap->Step() : proxy->Step();
+ if (IsNaN(accValue))
+ accValue = 0; // zero if the minimum increment is undefined
+
+ g_value_init(minimumIncrement, G_TYPE_DOUBLE);
+ g_value_set_double(minimumIncrement, accValue);
+}
+
+static gboolean
+setCurrentValueCB(AtkValue *obj, const GValue *value)
+{
+ ProxyAccessible* proxy = nullptr;
+ AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(obj));
+ if (!accWrap) {
+ proxy = GetProxy(ATK_OBJECT(obj));
+ if (!proxy) {
+ return FALSE;
+ }
+ }
+
+ double accValue =g_value_get_double(value);
+ return accWrap ? accWrap->SetCurValue(accValue) : proxy->SetCurValue(accValue);
+}
+}
+
+void
+valueInterfaceInitCB(AtkValueIface* aIface)
+{
+ NS_ASSERTION(aIface, "Invalid aIface");
+ if (MOZ_UNLIKELY(!aIface))
+ return;
+
+ aIface->get_current_value = getCurrentValueCB;
+ aIface->get_maximum_value = getMaximumValueCB;
+ aIface->get_minimum_value = getMinimumValueCB;
+ aIface->get_minimum_increment = getMinimumIncrementCB;
+ aIface->set_current_value = setCurrentValueCB;
+}
diff --git a/accessible/atk/nsStateMap.h b/accessible/atk/nsStateMap.h
new file mode 100644
index 0000000000..2f3cde2407
--- /dev/null
+++ b/accessible/atk/nsStateMap.h
@@ -0,0 +1,117 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <atk/atk.h>
+#include "AccessibleWrap.h"
+
+/******************************************************************************
+The following accessible states aren't translated, just ignored:
+ STATE_READONLY: Supported indirectly via EXT_STATE_EDITABLE
+ STATE_HOTTRACKED: No ATK equivalent. No known use case.
+ The nsIAccessible state is not currently supported.
+ STATE_FLOATING: No ATK equivalent. No known use case.
+ The nsIAccessible state is not currently supported.
+ STATE_MOVEABLE: No ATK equivalent. No known use case.
+ The nsIAccessible state is not currently supported.
+ STATE_SELFVOICING: No ATK equivalent -- the object has self-TTS.
+ The nsIAccessible state is not currently supported.
+ STATE_LINKED: The object is formatted as a hyperlink. Supported via ATK_ROLE_LINK.
+ STATE_EXTSELECTABLE: Indicates that an object extends its selection.
+ This is supported via STATE_MULTISELECTABLE.
+ STATE_PROTECTED: The object is a password-protected edit control.
+ Supported via ATK_ROLE_PASSWORD_TEXT
+ STATE_HASPOPUP: Object displays a pop-up menu or window when invoked.
+ No ATK equivalent. The accessible state is not
+ currently supported.
+ STATE_PINNED: The object is pinned, usually indicating it is fixed in
+ place and has permanence. No ATK equivalent. The
+ accessible state is not currently supported.
+
+The following ATK states are not supported:
+ ATK_STATE_ARMED: No clear use case, used briefly when button is activated
+ ATK_STATE_HAS_TOOLTIP: No clear use case, no IA2 equivalent
+ ATK_STATE_ICONIFIED: Mozilla does not have elements which are collapsable into icons
+ ATK_STATE_TRUNCATED: No clear use case. Indicates that an object's onscreen content is truncated,
+ e.g. a text value in a spreadsheet cell. No IA2 state.
+******************************************************************************/
+
+enum EStateMapEntryType {
+ kMapDirectly,
+ kMapOpposite, // For example, UNAVAILABLE is the opposite of ENABLED
+ kNoStateChange, // Don't fire state change event
+ kNoSuchState
+};
+
+const AtkStateType kNone = ATK_STATE_INVALID;
+
+struct AtkStateMap {
+ AtkStateType atkState;
+ EStateMapEntryType stateMapEntryType;
+
+ static int32_t GetStateIndexFor(uint64_t aState)
+ {
+ int32_t stateIndex = -1;
+ while (aState > 0) {
+ ++ stateIndex;
+ aState >>= 1;
+ }
+ return stateIndex; // Returns -1 if not mapped
+ }
+};
+
+
+// Map array from cross platform states to ATK states
+static const AtkStateMap gAtkStateMap[] = { // Cross Platform States
+ { kNone, kMapOpposite }, // states::UNAVAILABLE = 1 << 0
+ { ATK_STATE_SELECTED, kMapDirectly }, // states::SELECTED = 1 << 1
+ { ATK_STATE_FOCUSED, kMapDirectly }, // states::FOCUSED = 1 << 2
+ { ATK_STATE_PRESSED, kMapDirectly }, // states::PRESSED = 1 << 3
+ { ATK_STATE_CHECKED, kMapDirectly }, // states::CHECKED = 1 << 4
+ { ATK_STATE_INDETERMINATE, kMapDirectly }, // states::MIXED = 1 << 5
+ { kNone, kMapDirectly }, // states::READONLY = 1 << 6
+ { kNone, kMapDirectly }, // states::HOTTRACKED = 1 << 7
+ { ATK_STATE_DEFAULT, kMapDirectly }, // states::DEFAULT = 1 << 8
+ { ATK_STATE_EXPANDED, kMapDirectly }, // states::EXPANDED = 1 << 9
+ { kNone, kNoStateChange }, // states::COLLAPSED = 1 << 10
+ { ATK_STATE_BUSY, kMapDirectly }, // states::BUSY = 1 << 11
+ { kNone, kMapDirectly }, // states::FLOATING = 1 << 12
+ { ATK_STATE_CHECKABLE, kMapDirectly }, // states::CHECKABLE = 1 << 13
+ { ATK_STATE_ANIMATED, kMapDirectly }, // states::ANIMATED = 1 << 14
+ { ATK_STATE_VISIBLE, kMapOpposite }, // states::INVISIBLE = 1 << 15
+ { ATK_STATE_SHOWING, kMapOpposite }, // states::OFFSCREEN = 1 << 16
+ { ATK_STATE_RESIZABLE, kMapDirectly }, // states::SIZEABLE = 1 << 17
+ { kNone, kMapDirectly }, // states::MOVEABLE = 1 << 18
+ { kNone, kMapDirectly }, // states::SELFVOICING = 1 << 19
+ { ATK_STATE_FOCUSABLE, kMapDirectly }, // states::FOCUSABLE = 1 << 20
+ { ATK_STATE_SELECTABLE, kMapDirectly }, // states::SELECTABLE = 1 << 21
+ { kNone, kMapDirectly }, // states::LINKED = 1 << 22
+ { ATK_STATE_VISITED, kMapDirectly }, // states::TRAVERSED = 1 << 23
+ { ATK_STATE_MULTISELECTABLE, kMapDirectly }, // states::MULTISELECTABLE = 1 << 24
+ { kNone, kMapDirectly }, // states::EXTSELECTABLE = 1 << 25
+ { ATK_STATE_REQUIRED, kMapDirectly }, // states::STATE_REQUIRED = 1 << 26
+ { kNone, kMapDirectly }, // states::ALERT_MEDIUM = 1 << 27
+ { ATK_STATE_INVALID_ENTRY, kMapDirectly }, // states::INVALID = 1 << 28
+ { kNone, kMapDirectly }, // states::PROTECTED = 1 << 29
+ { kNone, kMapDirectly }, // states::HASPOPUP = 1 << 30
+ { ATK_STATE_SUPPORTS_AUTOCOMPLETION, kMapDirectly }, // states::SUPPORTS_AUTOCOMPLETION = 1 << 31
+ { ATK_STATE_DEFUNCT, kMapDirectly }, // states::DEFUNCT = 1 << 32
+ { ATK_STATE_SELECTABLE_TEXT, kMapDirectly }, // states::SELECTABLE_TEXT = 1 << 33
+ { ATK_STATE_EDITABLE, kMapDirectly }, // states::EDITABLE = 1 << 34
+ { ATK_STATE_ACTIVE, kMapDirectly }, // states::ACTIVE = 1 << 35
+ { ATK_STATE_MODAL, kMapDirectly }, // states::MODAL = 1 << 36
+ { ATK_STATE_MULTI_LINE, kMapDirectly }, // states::MULTI_LINE = 1 << 37
+ { ATK_STATE_HORIZONTAL, kMapDirectly }, // states::HORIZONTAL = 1 << 38
+ { ATK_STATE_OPAQUE, kMapDirectly }, // states::OPAQUE = 1 << 39
+ { ATK_STATE_SINGLE_LINE, kMapDirectly }, // states::SINGLE_LINE = 1 << 40
+ { ATK_STATE_TRANSIENT, kMapDirectly }, // states::TRANSIENT = 1 << 41
+ { ATK_STATE_VERTICAL, kMapDirectly }, // states::VERTICAL = 1 << 42
+ { ATK_STATE_STALE, kMapDirectly }, // states::STALE = 1 << 43
+ { ATK_STATE_ENABLED, kMapDirectly }, // states::ENABLED = 1 << 44
+ { ATK_STATE_SENSITIVE, kMapDirectly }, // states::SENSITIVE = 1 << 45
+ { ATK_STATE_EXPANDABLE, kMapDirectly }, // states::EXPANDABLE = 1 << 46
+ { kNone, kMapDirectly }, // states::PINNED = 1 << 47
+ { kNone, kNoSuchState }, // = 1 << 48
+};