1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/accessible/src/atk/AccessibleWrap.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1304 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set ts=2 et sw=2 tw=80: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "AccessibleWrap.h" 1.11 + 1.12 +#include "Accessible-inl.h" 1.13 +#include "ApplicationAccessibleWrap.h" 1.14 +#include "InterfaceInitFuncs.h" 1.15 +#include "nsAccUtils.h" 1.16 +#include "nsIAccessibleRelation.h" 1.17 +#include "nsIAccessibleTable.h" 1.18 +#include "RootAccessible.h" 1.19 +#include "nsIAccessibleValue.h" 1.20 +#include "nsMai.h" 1.21 +#include "nsMaiHyperlink.h" 1.22 +#include "nsString.h" 1.23 +#include "nsAutoPtr.h" 1.24 +#include "prprf.h" 1.25 +#include "nsStateMap.h" 1.26 +#include "Relation.h" 1.27 +#include "RootAccessible.h" 1.28 +#include "States.h" 1.29 +#include "nsISimpleEnumerator.h" 1.30 + 1.31 +#include "mozilla/ArrayUtils.h" 1.32 +#include "nsXPCOMStrings.h" 1.33 +#include "nsComponentManagerUtils.h" 1.34 +#include "nsIPersistentProperties2.h" 1.35 + 1.36 +using namespace mozilla; 1.37 +using namespace mozilla::a11y; 1.38 + 1.39 +AccessibleWrap::EAvailableAtkSignals AccessibleWrap::gAvailableAtkSignals = 1.40 + eUnknown; 1.41 + 1.42 +//defined in ApplicationAccessibleWrap.cpp 1.43 +extern "C" GType g_atk_hyperlink_impl_type; 1.44 + 1.45 +/* MaiAtkObject */ 1.46 + 1.47 +enum { 1.48 + ACTIVATE, 1.49 + CREATE, 1.50 + DEACTIVATE, 1.51 + DESTROY, 1.52 + MAXIMIZE, 1.53 + MINIMIZE, 1.54 + RESIZE, 1.55 + RESTORE, 1.56 + LAST_SIGNAL 1.57 +}; 1.58 + 1.59 +enum MaiInterfaceType { 1.60 + MAI_INTERFACE_COMPONENT, /* 0 */ 1.61 + MAI_INTERFACE_ACTION, 1.62 + MAI_INTERFACE_VALUE, 1.63 + MAI_INTERFACE_EDITABLE_TEXT, 1.64 + MAI_INTERFACE_HYPERTEXT, 1.65 + MAI_INTERFACE_HYPERLINK_IMPL, 1.66 + MAI_INTERFACE_SELECTION, 1.67 + MAI_INTERFACE_TABLE, 1.68 + MAI_INTERFACE_TEXT, 1.69 + MAI_INTERFACE_DOCUMENT, 1.70 + MAI_INTERFACE_IMAGE /* 10 */ 1.71 +}; 1.72 + 1.73 +static GType GetAtkTypeForMai(MaiInterfaceType type) 1.74 +{ 1.75 + switch (type) { 1.76 + case MAI_INTERFACE_COMPONENT: 1.77 + return ATK_TYPE_COMPONENT; 1.78 + case MAI_INTERFACE_ACTION: 1.79 + return ATK_TYPE_ACTION; 1.80 + case MAI_INTERFACE_VALUE: 1.81 + return ATK_TYPE_VALUE; 1.82 + case MAI_INTERFACE_EDITABLE_TEXT: 1.83 + return ATK_TYPE_EDITABLE_TEXT; 1.84 + case MAI_INTERFACE_HYPERTEXT: 1.85 + return ATK_TYPE_HYPERTEXT; 1.86 + case MAI_INTERFACE_HYPERLINK_IMPL: 1.87 + return g_atk_hyperlink_impl_type; 1.88 + case MAI_INTERFACE_SELECTION: 1.89 + return ATK_TYPE_SELECTION; 1.90 + case MAI_INTERFACE_TABLE: 1.91 + return ATK_TYPE_TABLE; 1.92 + case MAI_INTERFACE_TEXT: 1.93 + return ATK_TYPE_TEXT; 1.94 + case MAI_INTERFACE_DOCUMENT: 1.95 + return ATK_TYPE_DOCUMENT; 1.96 + case MAI_INTERFACE_IMAGE: 1.97 + return ATK_TYPE_IMAGE; 1.98 + } 1.99 + return G_TYPE_INVALID; 1.100 +} 1.101 + 1.102 +static const char* kNonUserInputEvent = ":system"; 1.103 + 1.104 +static const GInterfaceInfo atk_if_infos[] = { 1.105 + {(GInterfaceInitFunc)componentInterfaceInitCB, 1.106 + (GInterfaceFinalizeFunc) nullptr, nullptr}, 1.107 + {(GInterfaceInitFunc)actionInterfaceInitCB, 1.108 + (GInterfaceFinalizeFunc) nullptr, nullptr}, 1.109 + {(GInterfaceInitFunc)valueInterfaceInitCB, 1.110 + (GInterfaceFinalizeFunc) nullptr, nullptr}, 1.111 + {(GInterfaceInitFunc)editableTextInterfaceInitCB, 1.112 + (GInterfaceFinalizeFunc) nullptr, nullptr}, 1.113 + {(GInterfaceInitFunc)hypertextInterfaceInitCB, 1.114 + (GInterfaceFinalizeFunc) nullptr, nullptr}, 1.115 + {(GInterfaceInitFunc)hyperlinkImplInterfaceInitCB, 1.116 + (GInterfaceFinalizeFunc) nullptr, nullptr}, 1.117 + {(GInterfaceInitFunc)selectionInterfaceInitCB, 1.118 + (GInterfaceFinalizeFunc) nullptr, nullptr}, 1.119 + {(GInterfaceInitFunc)tableInterfaceInitCB, 1.120 + (GInterfaceFinalizeFunc) nullptr, nullptr}, 1.121 + {(GInterfaceInitFunc)textInterfaceInitCB, 1.122 + (GInterfaceFinalizeFunc) nullptr, nullptr}, 1.123 + {(GInterfaceInitFunc)documentInterfaceInitCB, 1.124 + (GInterfaceFinalizeFunc) nullptr, nullptr}, 1.125 + {(GInterfaceInitFunc)imageInterfaceInitCB, 1.126 + (GInterfaceFinalizeFunc) nullptr, nullptr} 1.127 +}; 1.128 + 1.129 +/** 1.130 + * This MaiAtkObject is a thin wrapper, in the MAI namespace, for AtkObject 1.131 + */ 1.132 +struct MaiAtkObject 1.133 +{ 1.134 + AtkObject parent; 1.135 + /* 1.136 + * The AccessibleWrap whose properties and features are exported 1.137 + * via this object instance. 1.138 + */ 1.139 + AccessibleWrap* accWrap; 1.140 +}; 1.141 + 1.142 +struct MaiAtkObjectClass 1.143 +{ 1.144 + AtkObjectClass parent_class; 1.145 +}; 1.146 + 1.147 +static guint mai_atk_object_signals [LAST_SIGNAL] = { 0, }; 1.148 + 1.149 +static void MaybeFireNameChange(AtkObject* aAtkObj, const nsString& aNewName); 1.150 + 1.151 +G_BEGIN_DECLS 1.152 +/* callbacks for MaiAtkObject */ 1.153 +static void classInitCB(AtkObjectClass *aClass); 1.154 +static void initializeCB(AtkObject *aAtkObj, gpointer aData); 1.155 +static void finalizeCB(GObject *aObj); 1.156 + 1.157 +/* callbacks for AtkObject virtual functions */ 1.158 +static const gchar* getNameCB (AtkObject *aAtkObj); 1.159 +/* getDescriptionCB is also used by image interface */ 1.160 + const gchar* getDescriptionCB (AtkObject *aAtkObj); 1.161 +static AtkRole getRoleCB(AtkObject *aAtkObj); 1.162 +static AtkAttributeSet* getAttributesCB(AtkObject *aAtkObj); 1.163 +static const gchar* GetLocaleCB(AtkObject*); 1.164 +static AtkObject* getParentCB(AtkObject *aAtkObj); 1.165 +static gint getChildCountCB(AtkObject *aAtkObj); 1.166 +static AtkObject* refChildCB(AtkObject *aAtkObj, gint aChildIndex); 1.167 +static gint getIndexInParentCB(AtkObject *aAtkObj); 1.168 +static AtkStateSet* refStateSetCB(AtkObject *aAtkObj); 1.169 +static AtkRelationSet* refRelationSetCB(AtkObject *aAtkObj); 1.170 + 1.171 +/* the missing atkobject virtual functions */ 1.172 +/* 1.173 + static AtkLayer getLayerCB(AtkObject *aAtkObj); 1.174 + static gint getMdiZorderCB(AtkObject *aAtkObj); 1.175 + static void SetNameCB(AtkObject *aAtkObj, 1.176 + const gchar *name); 1.177 + static void SetDescriptionCB(AtkObject *aAtkObj, 1.178 + const gchar *description); 1.179 + static void SetParentCB(AtkObject *aAtkObj, 1.180 + AtkObject *parent); 1.181 + static void SetRoleCB(AtkObject *aAtkObj, 1.182 + AtkRole role); 1.183 + static guint ConnectPropertyChangeHandlerCB( 1.184 + AtkObject *aObj, 1.185 + AtkPropertyChangeHandler *handler); 1.186 + static void RemovePropertyChangeHandlerCB( 1.187 + AtkObject *aAtkObj, 1.188 + guint handler_id); 1.189 + static void InitializeCB(AtkObject *aAtkObj, 1.190 + gpointer data); 1.191 + static void ChildrenChangedCB(AtkObject *aAtkObj, 1.192 + guint change_index, 1.193 + gpointer changed_child); 1.194 + static void FocusEventCB(AtkObject *aAtkObj, 1.195 + gboolean focus_in); 1.196 + static void PropertyChangeCB(AtkObject *aAtkObj, 1.197 + AtkPropertyValues *values); 1.198 + static void StateChangeCB(AtkObject *aAtkObj, 1.199 + const gchar *name, 1.200 + gboolean state_set); 1.201 + static void VisibleDataChangedCB(AtkObject *aAtkObj); 1.202 +*/ 1.203 +G_END_DECLS 1.204 + 1.205 +static GType GetMaiAtkType(uint16_t interfacesBits); 1.206 +static const char * GetUniqueMaiAtkTypeName(uint16_t interfacesBits); 1.207 + 1.208 +static gpointer parent_class = nullptr; 1.209 + 1.210 +static GQuark quark_mai_hyperlink = 0; 1.211 + 1.212 +GType 1.213 +mai_atk_object_get_type(void) 1.214 +{ 1.215 + static GType type = 0; 1.216 + 1.217 + if (!type) { 1.218 + static const GTypeInfo tinfo = { 1.219 + sizeof(MaiAtkObjectClass), 1.220 + (GBaseInitFunc)nullptr, 1.221 + (GBaseFinalizeFunc)nullptr, 1.222 + (GClassInitFunc)classInitCB, 1.223 + (GClassFinalizeFunc)nullptr, 1.224 + nullptr, /* class data */ 1.225 + sizeof(MaiAtkObject), /* instance size */ 1.226 + 0, /* nb preallocs */ 1.227 + (GInstanceInitFunc)nullptr, 1.228 + nullptr /* value table */ 1.229 + }; 1.230 + 1.231 + type = g_type_register_static(ATK_TYPE_OBJECT, 1.232 + "MaiAtkObject", &tinfo, GTypeFlags(0)); 1.233 + quark_mai_hyperlink = g_quark_from_static_string("MaiHyperlink"); 1.234 + } 1.235 + return type; 1.236 +} 1.237 + 1.238 +AccessibleWrap:: 1.239 + AccessibleWrap(nsIContent* aContent, DocAccessible* aDoc) : 1.240 + Accessible(aContent, aDoc), mAtkObject(nullptr) 1.241 +{ 1.242 +} 1.243 + 1.244 +AccessibleWrap::~AccessibleWrap() 1.245 +{ 1.246 + NS_ASSERTION(!mAtkObject, "ShutdownAtkObject() is not called"); 1.247 +} 1.248 + 1.249 +void 1.250 +AccessibleWrap::ShutdownAtkObject() 1.251 +{ 1.252 + if (mAtkObject) { 1.253 + if (IS_MAI_OBJECT(mAtkObject)) { 1.254 + MAI_ATK_OBJECT(mAtkObject)->accWrap = nullptr; 1.255 + } 1.256 + SetMaiHyperlink(nullptr); 1.257 + g_object_unref(mAtkObject); 1.258 + mAtkObject = nullptr; 1.259 + } 1.260 +} 1.261 + 1.262 +void 1.263 +AccessibleWrap::Shutdown() 1.264 +{ 1.265 + ShutdownAtkObject(); 1.266 + Accessible::Shutdown(); 1.267 +} 1.268 + 1.269 +MaiHyperlink* 1.270 +AccessibleWrap::GetMaiHyperlink(bool aCreate /* = true */) 1.271 +{ 1.272 + // make sure mAtkObject is created 1.273 + GetAtkObject(); 1.274 + 1.275 + NS_ASSERTION(quark_mai_hyperlink, "quark_mai_hyperlink not initialized"); 1.276 + NS_ASSERTION(IS_MAI_OBJECT(mAtkObject), "Invalid AtkObject"); 1.277 + MaiHyperlink* maiHyperlink = nullptr; 1.278 + if (quark_mai_hyperlink && IS_MAI_OBJECT(mAtkObject)) { 1.279 + maiHyperlink = (MaiHyperlink*)g_object_get_qdata(G_OBJECT(mAtkObject), 1.280 + quark_mai_hyperlink); 1.281 + if (!maiHyperlink && aCreate) { 1.282 + maiHyperlink = new MaiHyperlink(this); 1.283 + SetMaiHyperlink(maiHyperlink); 1.284 + } 1.285 + } 1.286 + return maiHyperlink; 1.287 +} 1.288 + 1.289 +void 1.290 +AccessibleWrap::SetMaiHyperlink(MaiHyperlink* aMaiHyperlink) 1.291 +{ 1.292 + NS_ASSERTION(quark_mai_hyperlink, "quark_mai_hyperlink not initialized"); 1.293 + NS_ASSERTION(IS_MAI_OBJECT(mAtkObject), "Invalid AtkObject"); 1.294 + if (quark_mai_hyperlink && IS_MAI_OBJECT(mAtkObject)) { 1.295 + MaiHyperlink* maiHyperlink = GetMaiHyperlink(false); 1.296 + if (!maiHyperlink && !aMaiHyperlink) { 1.297 + return; // Never set and we're shutting down 1.298 + } 1.299 + delete maiHyperlink; 1.300 + g_object_set_qdata(G_OBJECT(mAtkObject), quark_mai_hyperlink, 1.301 + aMaiHyperlink); 1.302 + } 1.303 +} 1.304 + 1.305 +NS_IMETHODIMP 1.306 +AccessibleWrap::GetNativeInterface(void** aOutAccessible) 1.307 +{ 1.308 + *aOutAccessible = nullptr; 1.309 + 1.310 + if (!mAtkObject) { 1.311 + if (IsDefunct() || !nsAccUtils::IsEmbeddedObject(this)) { 1.312 + // We don't create ATK objects for node which has been shutdown, or 1.313 + // nsIAccessible plain text leaves 1.314 + return NS_ERROR_FAILURE; 1.315 + } 1.316 + 1.317 + GType type = GetMaiAtkType(CreateMaiInterfaces()); 1.318 + NS_ENSURE_TRUE(type, NS_ERROR_FAILURE); 1.319 + mAtkObject = 1.320 + reinterpret_cast<AtkObject *> 1.321 + (g_object_new(type, nullptr)); 1.322 + NS_ENSURE_TRUE(mAtkObject, NS_ERROR_OUT_OF_MEMORY); 1.323 + 1.324 + atk_object_initialize(mAtkObject, this); 1.325 + mAtkObject->role = ATK_ROLE_INVALID; 1.326 + mAtkObject->layer = ATK_LAYER_INVALID; 1.327 + } 1.328 + 1.329 + *aOutAccessible = mAtkObject; 1.330 + return NS_OK; 1.331 +} 1.332 + 1.333 +AtkObject * 1.334 +AccessibleWrap::GetAtkObject(void) 1.335 +{ 1.336 + void *atkObj = nullptr; 1.337 + GetNativeInterface(&atkObj); 1.338 + return static_cast<AtkObject *>(atkObj); 1.339 +} 1.340 + 1.341 +// Get AtkObject from nsIAccessible interface 1.342 +/* static */ 1.343 +AtkObject * 1.344 +AccessibleWrap::GetAtkObject(nsIAccessible* acc) 1.345 +{ 1.346 + void *atkObjPtr = nullptr; 1.347 + acc->GetNativeInterface(&atkObjPtr); 1.348 + return atkObjPtr ? ATK_OBJECT(atkObjPtr) : nullptr; 1.349 +} 1.350 + 1.351 +/* private */ 1.352 +uint16_t 1.353 +AccessibleWrap::CreateMaiInterfaces(void) 1.354 +{ 1.355 + uint16_t interfacesBits = 0; 1.356 + 1.357 + // The Component interface is supported by all accessibles. 1.358 + interfacesBits |= 1 << MAI_INTERFACE_COMPONENT; 1.359 + 1.360 + // Add Action interface if the action count is more than zero. 1.361 + if (ActionCount() > 0) 1.362 + interfacesBits |= 1 << MAI_INTERFACE_ACTION; 1.363 + 1.364 + // Text, Editabletext, and Hypertext interface. 1.365 + HyperTextAccessible* hyperText = AsHyperText(); 1.366 + if (hyperText && hyperText->IsTextRole()) { 1.367 + interfacesBits |= 1 << MAI_INTERFACE_TEXT; 1.368 + interfacesBits |= 1 << MAI_INTERFACE_EDITABLE_TEXT; 1.369 + if (!nsAccUtils::MustPrune(this)) 1.370 + interfacesBits |= 1 << MAI_INTERFACE_HYPERTEXT; 1.371 + } 1.372 + 1.373 + // Value interface. 1.374 + nsCOMPtr<nsIAccessibleValue> accessInterfaceValue; 1.375 + QueryInterface(NS_GET_IID(nsIAccessibleValue), 1.376 + getter_AddRefs(accessInterfaceValue)); 1.377 + if (accessInterfaceValue) { 1.378 + interfacesBits |= 1 << MAI_INTERFACE_VALUE; 1.379 + } 1.380 + 1.381 + // Document interface. 1.382 + if (IsDoc()) 1.383 + interfacesBits |= 1 << MAI_INTERFACE_DOCUMENT; 1.384 + 1.385 + if (IsImage()) 1.386 + interfacesBits |= 1 << MAI_INTERFACE_IMAGE; 1.387 + 1.388 + // HyperLink interface. 1.389 + if (IsLink()) 1.390 + interfacesBits |= 1 << MAI_INTERFACE_HYPERLINK_IMPL; 1.391 + 1.392 + if (!nsAccUtils::MustPrune(this)) { // These interfaces require children 1.393 + // Table interface. 1.394 + if (AsTable()) 1.395 + interfacesBits |= 1 << MAI_INTERFACE_TABLE; 1.396 + 1.397 + // Selection interface. 1.398 + if (IsSelect()) { 1.399 + interfacesBits |= 1 << MAI_INTERFACE_SELECTION; 1.400 + } 1.401 + } 1.402 + 1.403 + return interfacesBits; 1.404 +} 1.405 + 1.406 +static GType 1.407 +GetMaiAtkType(uint16_t interfacesBits) 1.408 +{ 1.409 + GType type; 1.410 + static const GTypeInfo tinfo = { 1.411 + sizeof(MaiAtkObjectClass), 1.412 + (GBaseInitFunc) nullptr, 1.413 + (GBaseFinalizeFunc) nullptr, 1.414 + (GClassInitFunc) nullptr, 1.415 + (GClassFinalizeFunc) nullptr, 1.416 + nullptr, /* class data */ 1.417 + sizeof(MaiAtkObject), /* instance size */ 1.418 + 0, /* nb preallocs */ 1.419 + (GInstanceInitFunc) nullptr, 1.420 + nullptr /* value table */ 1.421 + }; 1.422 + 1.423 + /* 1.424 + * The members we use to register GTypes are GetAtkTypeForMai 1.425 + * and atk_if_infos, which are constant values to each MaiInterface 1.426 + * So we can reuse the registered GType when having 1.427 + * the same MaiInterface types. 1.428 + */ 1.429 + const char *atkTypeName = GetUniqueMaiAtkTypeName(interfacesBits); 1.430 + type = g_type_from_name(atkTypeName); 1.431 + if (type) { 1.432 + return type; 1.433 + } 1.434 + 1.435 + /* 1.436 + * gobject limits the number of types that can directly derive from any 1.437 + * given object type to 4095. 1.438 + */ 1.439 + static uint16_t typeRegCount = 0; 1.440 + if (typeRegCount++ >= 4095) { 1.441 + return G_TYPE_INVALID; 1.442 + } 1.443 + type = g_type_register_static(MAI_TYPE_ATK_OBJECT, 1.444 + atkTypeName, 1.445 + &tinfo, GTypeFlags(0)); 1.446 + 1.447 + for (uint32_t index = 0; index < ArrayLength(atk_if_infos); index++) { 1.448 + if (interfacesBits & (1 << index)) { 1.449 + g_type_add_interface_static(type, 1.450 + GetAtkTypeForMai((MaiInterfaceType)index), 1.451 + &atk_if_infos[index]); 1.452 + } 1.453 + } 1.454 + 1.455 + return type; 1.456 +} 1.457 + 1.458 +static const char* 1.459 +GetUniqueMaiAtkTypeName(uint16_t interfacesBits) 1.460 +{ 1.461 +#define MAI_ATK_TYPE_NAME_LEN (30) /* 10+sizeof(uint16_t)*8/4+1 < 30 */ 1.462 + 1.463 + static gchar namePrefix[] = "MaiAtkType"; /* size = 10 */ 1.464 + static gchar name[MAI_ATK_TYPE_NAME_LEN + 1]; 1.465 + 1.466 + PR_snprintf(name, MAI_ATK_TYPE_NAME_LEN, "%s%x", namePrefix, 1.467 + interfacesBits); 1.468 + name[MAI_ATK_TYPE_NAME_LEN] = '\0'; 1.469 + 1.470 + return name; 1.471 +} 1.472 + 1.473 +bool 1.474 +AccessibleWrap::IsValidObject() 1.475 +{ 1.476 + // to ensure we are not shut down 1.477 + return !IsDefunct(); 1.478 +} 1.479 + 1.480 +/* static functions for ATK callbacks */ 1.481 +void 1.482 +classInitCB(AtkObjectClass *aClass) 1.483 +{ 1.484 + GObjectClass *gobject_class = G_OBJECT_CLASS(aClass); 1.485 + 1.486 + parent_class = g_type_class_peek_parent(aClass); 1.487 + 1.488 + aClass->get_name = getNameCB; 1.489 + aClass->get_description = getDescriptionCB; 1.490 + aClass->get_parent = getParentCB; 1.491 + aClass->get_n_children = getChildCountCB; 1.492 + aClass->ref_child = refChildCB; 1.493 + aClass->get_index_in_parent = getIndexInParentCB; 1.494 + aClass->get_role = getRoleCB; 1.495 + aClass->get_attributes = getAttributesCB; 1.496 + aClass->get_object_locale = GetLocaleCB; 1.497 + aClass->ref_state_set = refStateSetCB; 1.498 + aClass->ref_relation_set = refRelationSetCB; 1.499 + 1.500 + aClass->initialize = initializeCB; 1.501 + 1.502 + gobject_class->finalize = finalizeCB; 1.503 + 1.504 + mai_atk_object_signals [ACTIVATE] = 1.505 + g_signal_new ("activate", 1.506 + MAI_TYPE_ATK_OBJECT, 1.507 + G_SIGNAL_RUN_LAST, 1.508 + 0, /* default signal handler */ 1.509 + nullptr, nullptr, 1.510 + g_cclosure_marshal_VOID__VOID, 1.511 + G_TYPE_NONE, 0); 1.512 + mai_atk_object_signals [CREATE] = 1.513 + g_signal_new ("create", 1.514 + MAI_TYPE_ATK_OBJECT, 1.515 + G_SIGNAL_RUN_LAST, 1.516 + 0, /* default signal handler */ 1.517 + nullptr, nullptr, 1.518 + g_cclosure_marshal_VOID__VOID, 1.519 + G_TYPE_NONE, 0); 1.520 + mai_atk_object_signals [DEACTIVATE] = 1.521 + g_signal_new ("deactivate", 1.522 + MAI_TYPE_ATK_OBJECT, 1.523 + G_SIGNAL_RUN_LAST, 1.524 + 0, /* default signal handler */ 1.525 + nullptr, nullptr, 1.526 + g_cclosure_marshal_VOID__VOID, 1.527 + G_TYPE_NONE, 0); 1.528 + mai_atk_object_signals [DESTROY] = 1.529 + g_signal_new ("destroy", 1.530 + MAI_TYPE_ATK_OBJECT, 1.531 + G_SIGNAL_RUN_LAST, 1.532 + 0, /* default signal handler */ 1.533 + nullptr, nullptr, 1.534 + g_cclosure_marshal_VOID__VOID, 1.535 + G_TYPE_NONE, 0); 1.536 + mai_atk_object_signals [MAXIMIZE] = 1.537 + g_signal_new ("maximize", 1.538 + MAI_TYPE_ATK_OBJECT, 1.539 + G_SIGNAL_RUN_LAST, 1.540 + 0, /* default signal handler */ 1.541 + nullptr, nullptr, 1.542 + g_cclosure_marshal_VOID__VOID, 1.543 + G_TYPE_NONE, 0); 1.544 + mai_atk_object_signals [MINIMIZE] = 1.545 + g_signal_new ("minimize", 1.546 + MAI_TYPE_ATK_OBJECT, 1.547 + G_SIGNAL_RUN_LAST, 1.548 + 0, /* default signal handler */ 1.549 + nullptr, nullptr, 1.550 + g_cclosure_marshal_VOID__VOID, 1.551 + G_TYPE_NONE, 0); 1.552 + mai_atk_object_signals [RESIZE] = 1.553 + g_signal_new ("resize", 1.554 + MAI_TYPE_ATK_OBJECT, 1.555 + G_SIGNAL_RUN_LAST, 1.556 + 0, /* default signal handler */ 1.557 + nullptr, nullptr, 1.558 + g_cclosure_marshal_VOID__VOID, 1.559 + G_TYPE_NONE, 0); 1.560 + mai_atk_object_signals [RESTORE] = 1.561 + g_signal_new ("restore", 1.562 + MAI_TYPE_ATK_OBJECT, 1.563 + G_SIGNAL_RUN_LAST, 1.564 + 0, /* default signal handler */ 1.565 + nullptr, nullptr, 1.566 + g_cclosure_marshal_VOID__VOID, 1.567 + G_TYPE_NONE, 0); 1.568 + 1.569 +} 1.570 + 1.571 +void 1.572 +initializeCB(AtkObject *aAtkObj, gpointer aData) 1.573 +{ 1.574 + NS_ASSERTION((IS_MAI_OBJECT(aAtkObj)), "Invalid AtkObject"); 1.575 + NS_ASSERTION(aData, "Invalid Data to init AtkObject"); 1.576 + if (!aAtkObj || !aData) 1.577 + return; 1.578 + 1.579 + /* call parent init function */ 1.580 + /* AtkObjectClass has not a "initialize" function now, 1.581 + * maybe it has later 1.582 + */ 1.583 + 1.584 + if (ATK_OBJECT_CLASS(parent_class)->initialize) 1.585 + ATK_OBJECT_CLASS(parent_class)->initialize(aAtkObj, aData); 1.586 + 1.587 + /* initialize object */ 1.588 + MAI_ATK_OBJECT(aAtkObj)->accWrap = 1.589 + static_cast<AccessibleWrap*>(aData); 1.590 +} 1.591 + 1.592 +void 1.593 +finalizeCB(GObject *aObj) 1.594 +{ 1.595 + if (!IS_MAI_OBJECT(aObj)) 1.596 + return; 1.597 + NS_ASSERTION(MAI_ATK_OBJECT(aObj)->accWrap == nullptr, "AccWrap NOT null"); 1.598 + 1.599 + // call parent finalize function 1.600 + // finalize of GObjectClass will unref the accessible parent if has 1.601 + if (G_OBJECT_CLASS (parent_class)->finalize) 1.602 + G_OBJECT_CLASS (parent_class)->finalize(aObj); 1.603 +} 1.604 + 1.605 +const gchar* 1.606 +getNameCB(AtkObject* aAtkObj) 1.607 +{ 1.608 + AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj); 1.609 + if (!accWrap) 1.610 + return nullptr; 1.611 + 1.612 + nsAutoString name; 1.613 + accWrap->Name(name); 1.614 + 1.615 + // XXX Firing an event from here does not seem right 1.616 + MaybeFireNameChange(aAtkObj, name); 1.617 + 1.618 + return aAtkObj->name; 1.619 +} 1.620 + 1.621 +static void 1.622 +MaybeFireNameChange(AtkObject* aAtkObj, const nsString& aNewName) 1.623 +{ 1.624 + NS_ConvertUTF16toUTF8 newNameUTF8(aNewName); 1.625 + if (aAtkObj->name && newNameUTF8.Equals(aAtkObj->name)) 1.626 + return; 1.627 + 1.628 + // Below we duplicate the functionality of atk_object_set_name(), 1.629 + // but without calling atk_object_get_name(). Instead of 1.630 + // atk_object_get_name() we directly access aAtkObj->name. This is because 1.631 + // atk_object_get_name() would call getNameCB() which would call 1.632 + // MaybeFireNameChange() (or atk_object_set_name() before this problem was 1.633 + // fixed) and we would get an infinite recursion. 1.634 + // See http://bugzilla.mozilla.org/733712 1.635 + 1.636 + // Do not notify for initial name setting. 1.637 + // See bug http://bugzilla.gnome.org/665870 1.638 + bool notify = !!aAtkObj->name; 1.639 + 1.640 + free(aAtkObj->name); 1.641 + aAtkObj->name = strdup(newNameUTF8.get()); 1.642 + 1.643 + if (notify) 1.644 + g_object_notify(G_OBJECT(aAtkObj), "accessible-name"); 1.645 +} 1.646 + 1.647 +const gchar * 1.648 +getDescriptionCB(AtkObject *aAtkObj) 1.649 +{ 1.650 + AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj); 1.651 + if (!accWrap || accWrap->IsDefunct()) 1.652 + return nullptr; 1.653 + 1.654 + /* nsIAccessible is responsible for the nonnull description */ 1.655 + nsAutoString uniDesc; 1.656 + accWrap->Description(uniDesc); 1.657 + 1.658 + NS_ConvertUTF8toUTF16 objDesc(aAtkObj->description); 1.659 + if (!uniDesc.Equals(objDesc)) 1.660 + atk_object_set_description(aAtkObj, 1.661 + NS_ConvertUTF16toUTF8(uniDesc).get()); 1.662 + 1.663 + return aAtkObj->description; 1.664 +} 1.665 + 1.666 +AtkRole 1.667 +getRoleCB(AtkObject *aAtkObj) 1.668 +{ 1.669 + AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj); 1.670 + if (!accWrap) 1.671 + return ATK_ROLE_INVALID; 1.672 + 1.673 +#ifdef DEBUG 1.674 + NS_ASSERTION(nsAccUtils::IsTextInterfaceSupportCorrect(accWrap), 1.675 + "Does not support nsIAccessibleText when it should"); 1.676 +#endif 1.677 + 1.678 + if (aAtkObj->role != ATK_ROLE_INVALID) 1.679 + return aAtkObj->role; 1.680 + 1.681 +#define ROLE(geckoRole, stringRole, atkRole, macRole, \ 1.682 + msaaRole, ia2Role, nameRule) \ 1.683 + case roles::geckoRole: \ 1.684 + aAtkObj->role = atkRole; \ 1.685 + break; 1.686 + 1.687 + switch (accWrap->Role()) { 1.688 +#include "RoleMap.h" 1.689 + default: 1.690 + MOZ_CRASH("Unknown role."); 1.691 + }; 1.692 + 1.693 +#undef ROLE 1.694 + 1.695 + if (aAtkObj->role == ATK_ROLE_LIST_BOX && !IsAtkVersionAtLeast(2, 1)) 1.696 + aAtkObj->role = ATK_ROLE_LIST; 1.697 + else if (aAtkObj->role == ATK_ROLE_TABLE_ROW && !IsAtkVersionAtLeast(2, 1)) 1.698 + aAtkObj->role = ATK_ROLE_LIST_ITEM; 1.699 + 1.700 + return aAtkObj->role; 1.701 +} 1.702 + 1.703 +static AtkAttributeSet* 1.704 +ConvertToAtkAttributeSet(nsIPersistentProperties* aAttributes) 1.705 +{ 1.706 + if (!aAttributes) 1.707 + return nullptr; 1.708 + 1.709 + AtkAttributeSet *objAttributeSet = nullptr; 1.710 + nsCOMPtr<nsISimpleEnumerator> propEnum; 1.711 + nsresult rv = aAttributes->Enumerate(getter_AddRefs(propEnum)); 1.712 + NS_ENSURE_SUCCESS(rv, nullptr); 1.713 + 1.714 + bool hasMore; 1.715 + while (NS_SUCCEEDED(propEnum->HasMoreElements(&hasMore)) && hasMore) { 1.716 + nsCOMPtr<nsISupports> sup; 1.717 + rv = propEnum->GetNext(getter_AddRefs(sup)); 1.718 + NS_ENSURE_SUCCESS(rv, objAttributeSet); 1.719 + 1.720 + nsCOMPtr<nsIPropertyElement> propElem(do_QueryInterface(sup)); 1.721 + NS_ENSURE_TRUE(propElem, objAttributeSet); 1.722 + 1.723 + nsAutoCString name; 1.724 + rv = propElem->GetKey(name); 1.725 + NS_ENSURE_SUCCESS(rv, objAttributeSet); 1.726 + 1.727 + nsAutoString value; 1.728 + rv = propElem->GetValue(value); 1.729 + NS_ENSURE_SUCCESS(rv, objAttributeSet); 1.730 + 1.731 + AtkAttribute *objAttr = (AtkAttribute *)g_malloc(sizeof(AtkAttribute)); 1.732 + objAttr->name = g_strdup(name.get()); 1.733 + objAttr->value = g_strdup(NS_ConvertUTF16toUTF8(value).get()); 1.734 + objAttributeSet = g_slist_prepend(objAttributeSet, objAttr); 1.735 + } 1.736 + 1.737 + //libspi will free it 1.738 + return objAttributeSet; 1.739 +} 1.740 + 1.741 +AtkAttributeSet* 1.742 +GetAttributeSet(Accessible* aAccessible) 1.743 +{ 1.744 + nsCOMPtr<nsIPersistentProperties> attributes = aAccessible->Attributes(); 1.745 + if (attributes) { 1.746 + // There is no ATK state for haspopup, must use object attribute to expose 1.747 + // the same info. 1.748 + if (aAccessible->State() & states::HASPOPUP) { 1.749 + nsAutoString unused; 1.750 + attributes->SetStringProperty(NS_LITERAL_CSTRING("haspopup"), 1.751 + NS_LITERAL_STRING("true"), unused); 1.752 + } 1.753 + 1.754 + return ConvertToAtkAttributeSet(attributes); 1.755 + } 1.756 + 1.757 + return nullptr; 1.758 +} 1.759 + 1.760 +AtkAttributeSet * 1.761 +getAttributesCB(AtkObject *aAtkObj) 1.762 +{ 1.763 + AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj); 1.764 + return accWrap ? GetAttributeSet(accWrap) : nullptr; 1.765 +} 1.766 + 1.767 +const gchar* 1.768 +GetLocaleCB(AtkObject* aAtkObj) 1.769 +{ 1.770 + AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj); 1.771 + if (!accWrap) 1.772 + return nullptr; 1.773 + 1.774 + nsAutoString locale; 1.775 + accWrap->Language(locale); 1.776 + return AccessibleWrap::ReturnString(locale); 1.777 +} 1.778 + 1.779 +AtkObject * 1.780 +getParentCB(AtkObject *aAtkObj) 1.781 +{ 1.782 + if (!aAtkObj->accessible_parent) { 1.783 + AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj); 1.784 + if (!accWrap) 1.785 + return nullptr; 1.786 + 1.787 + Accessible* accParent = accWrap->Parent(); 1.788 + if (!accParent) 1.789 + return nullptr; 1.790 + 1.791 + AtkObject* parent = AccessibleWrap::GetAtkObject(accParent); 1.792 + if (parent) 1.793 + atk_object_set_parent(aAtkObj, parent); 1.794 + } 1.795 + return aAtkObj->accessible_parent; 1.796 +} 1.797 + 1.798 +gint 1.799 +getChildCountCB(AtkObject *aAtkObj) 1.800 +{ 1.801 + AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj); 1.802 + if (!accWrap || nsAccUtils::MustPrune(accWrap)) { 1.803 + return 0; 1.804 + } 1.805 + 1.806 + return static_cast<gint>(accWrap->EmbeddedChildCount()); 1.807 +} 1.808 + 1.809 +AtkObject * 1.810 +refChildCB(AtkObject *aAtkObj, gint aChildIndex) 1.811 +{ 1.812 + // aChildIndex should not be less than zero 1.813 + if (aChildIndex < 0) { 1.814 + return nullptr; 1.815 + } 1.816 + 1.817 + AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj); 1.818 + if (!accWrap || nsAccUtils::MustPrune(accWrap)) { 1.819 + return nullptr; 1.820 + } 1.821 + 1.822 + Accessible* accChild = accWrap->GetEmbeddedChildAt(aChildIndex); 1.823 + if (!accChild) 1.824 + return nullptr; 1.825 + 1.826 + AtkObject* childAtkObj = AccessibleWrap::GetAtkObject(accChild); 1.827 + 1.828 + NS_ASSERTION(childAtkObj, "Fail to get AtkObj"); 1.829 + if (!childAtkObj) 1.830 + return nullptr; 1.831 + g_object_ref(childAtkObj); 1.832 + 1.833 + if (aAtkObj != childAtkObj->accessible_parent) 1.834 + atk_object_set_parent(childAtkObj, aAtkObj); 1.835 + 1.836 + return childAtkObj; 1.837 +} 1.838 + 1.839 +gint 1.840 +getIndexInParentCB(AtkObject *aAtkObj) 1.841 +{ 1.842 + // We don't use nsIAccessible::GetIndexInParent() because 1.843 + // for ATK we don't want to include text leaf nodes as children 1.844 + AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj); 1.845 + if (!accWrap) { 1.846 + return -1; 1.847 + } 1.848 + 1.849 + Accessible* parent = accWrap->Parent(); 1.850 + if (!parent) 1.851 + return -1; // No parent 1.852 + 1.853 + return parent->GetIndexOfEmbeddedChild(accWrap); 1.854 +} 1.855 + 1.856 +static void 1.857 +TranslateStates(uint64_t aState, AtkStateSet* aStateSet) 1.858 +{ 1.859 + // atk doesn't have a read only state so read only things shouldn't be 1.860 + // editable. 1.861 + if (aState & states::READONLY) 1.862 + aState &= ~states::EDITABLE; 1.863 + 1.864 + // Convert every state to an entry in AtkStateMap 1.865 + uint32_t stateIndex = 0; 1.866 + uint64_t bitMask = 1; 1.867 + while (gAtkStateMap[stateIndex].stateMapEntryType != kNoSuchState) { 1.868 + if (gAtkStateMap[stateIndex].atkState) { // There's potentially an ATK state for this 1.869 + bool isStateOn = (aState & bitMask) != 0; 1.870 + if (gAtkStateMap[stateIndex].stateMapEntryType == kMapOpposite) { 1.871 + isStateOn = !isStateOn; 1.872 + } 1.873 + if (isStateOn) { 1.874 + atk_state_set_add_state(aStateSet, gAtkStateMap[stateIndex].atkState); 1.875 + } 1.876 + } 1.877 + bitMask <<= 1; 1.878 + ++ stateIndex; 1.879 + } 1.880 +} 1.881 + 1.882 +AtkStateSet * 1.883 +refStateSetCB(AtkObject *aAtkObj) 1.884 +{ 1.885 + AtkStateSet *state_set = nullptr; 1.886 + state_set = ATK_OBJECT_CLASS(parent_class)->ref_state_set(aAtkObj); 1.887 + 1.888 + AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj); 1.889 + if (!accWrap) { 1.890 + TranslateStates(states::DEFUNCT, state_set); 1.891 + return state_set; 1.892 + } 1.893 + 1.894 + // Map states 1.895 + TranslateStates(accWrap->State(), state_set); 1.896 + 1.897 + return state_set; 1.898 +} 1.899 + 1.900 +static void 1.901 +UpdateAtkRelation(RelationType aType, Accessible* aAcc, 1.902 + AtkRelationType aAtkType, AtkRelationSet* aAtkSet) 1.903 +{ 1.904 + if (aAtkType == ATK_RELATION_NULL) 1.905 + return; 1.906 + 1.907 + AtkRelation* atkRelation = 1.908 + atk_relation_set_get_relation_by_type(aAtkSet, aAtkType); 1.909 + if (atkRelation) 1.910 + atk_relation_set_remove(aAtkSet, atkRelation); 1.911 + 1.912 + Relation rel(aAcc->RelationByType(aType)); 1.913 + nsTArray<AtkObject*> targets; 1.914 + Accessible* tempAcc = nullptr; 1.915 + while ((tempAcc = rel.Next())) 1.916 + targets.AppendElement(AccessibleWrap::GetAtkObject(tempAcc)); 1.917 + 1.918 + if (targets.Length()) { 1.919 + atkRelation = atk_relation_new(targets.Elements(), 1.920 + targets.Length(), aAtkType); 1.921 + atk_relation_set_add(aAtkSet, atkRelation); 1.922 + g_object_unref(atkRelation); 1.923 + } 1.924 +} 1.925 + 1.926 +AtkRelationSet * 1.927 +refRelationSetCB(AtkObject *aAtkObj) 1.928 +{ 1.929 + AtkRelationSet* relation_set = 1.930 + ATK_OBJECT_CLASS(parent_class)->ref_relation_set(aAtkObj); 1.931 + 1.932 + AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj); 1.933 + if (!accWrap) 1.934 + return relation_set; 1.935 + 1.936 +#define RELATIONTYPE(geckoType, geckoTypeName, atkType, msaaType, ia2Type) \ 1.937 + UpdateAtkRelation(RelationType::geckoType, accWrap, atkType, relation_set); 1.938 + 1.939 +#include "RelationTypeMap.h" 1.940 + 1.941 +#undef RELATIONTYPE 1.942 + 1.943 + return relation_set; 1.944 +} 1.945 + 1.946 +// Check if aAtkObj is a valid MaiAtkObject, and return the AccessibleWrap 1.947 +// for it. 1.948 +AccessibleWrap* 1.949 +GetAccessibleWrap(AtkObject* aAtkObj) 1.950 +{ 1.951 + NS_ENSURE_TRUE(IS_MAI_OBJECT(aAtkObj), nullptr); 1.952 + AccessibleWrap* accWrap = MAI_ATK_OBJECT(aAtkObj)->accWrap; 1.953 + 1.954 + // Check if the accessible was deconstructed. 1.955 + if (!accWrap) 1.956 + return nullptr; 1.957 + 1.958 + NS_ENSURE_TRUE(accWrap->GetAtkObject() == aAtkObj, nullptr); 1.959 + 1.960 + AccessibleWrap* appAccWrap = ApplicationAcc(); 1.961 + if (appAccWrap != accWrap && !accWrap->IsValidObject()) 1.962 + return nullptr; 1.963 + 1.964 + return accWrap; 1.965 +} 1.966 + 1.967 +nsresult 1.968 +AccessibleWrap::HandleAccEvent(AccEvent* aEvent) 1.969 +{ 1.970 + nsresult rv = Accessible::HandleAccEvent(aEvent); 1.971 + NS_ENSURE_SUCCESS(rv, rv); 1.972 + 1.973 + Accessible* accessible = aEvent->GetAccessible(); 1.974 + NS_ENSURE_TRUE(accessible, NS_ERROR_FAILURE); 1.975 + 1.976 + // The accessible can become defunct if we have an xpcom event listener 1.977 + // which decides it would be fun to change the DOM and flush layout. 1.978 + if (accessible->IsDefunct()) 1.979 + return NS_OK; 1.980 + 1.981 + uint32_t type = aEvent->GetEventType(); 1.982 + 1.983 + AtkObject* atkObj = AccessibleWrap::GetAtkObject(accessible); 1.984 + 1.985 + // We don't create ATK objects for nsIAccessible plain text leaves, 1.986 + // just return NS_OK in such case 1.987 + if (!atkObj) { 1.988 + NS_ASSERTION(type == nsIAccessibleEvent::EVENT_SHOW || 1.989 + type == nsIAccessibleEvent::EVENT_HIDE, 1.990 + "Event other than SHOW and HIDE fired for plain text leaves"); 1.991 + return NS_OK; 1.992 + } 1.993 + 1.994 + AccessibleWrap* accWrap = GetAccessibleWrap(atkObj); 1.995 + if (!accWrap) { 1.996 + return NS_OK; // Node is shut down 1.997 + } 1.998 + 1.999 + switch (type) { 1.1000 + case nsIAccessibleEvent::EVENT_STATE_CHANGE: 1.1001 + return FireAtkStateChangeEvent(aEvent, atkObj); 1.1002 + 1.1003 + case nsIAccessibleEvent::EVENT_TEXT_REMOVED: 1.1004 + case nsIAccessibleEvent::EVENT_TEXT_INSERTED: 1.1005 + return FireAtkTextChangedEvent(aEvent, atkObj); 1.1006 + 1.1007 + case nsIAccessibleEvent::EVENT_FOCUS: 1.1008 + { 1.1009 + a11y::RootAccessible* rootAccWrap = accWrap->RootAccessible(); 1.1010 + if (rootAccWrap && rootAccWrap->mActivated) { 1.1011 + atk_focus_tracker_notify(atkObj); 1.1012 + // Fire state change event for focus 1.1013 + atk_object_notify_state_change(atkObj, ATK_STATE_FOCUSED, true); 1.1014 + return NS_OK; 1.1015 + } 1.1016 + } break; 1.1017 + 1.1018 + case nsIAccessibleEvent::EVENT_NAME_CHANGE: 1.1019 + { 1.1020 + nsAutoString newName; 1.1021 + accessible->Name(newName); 1.1022 + 1.1023 + MaybeFireNameChange(atkObj, newName); 1.1024 + 1.1025 + break; 1.1026 + } 1.1027 + case nsIAccessibleEvent::EVENT_VALUE_CHANGE: 1.1028 + { 1.1029 + nsCOMPtr<nsIAccessibleValue> value(do_QueryObject(accessible)); 1.1030 + if (value) { // Make sure this is a numeric value 1.1031 + // Don't fire for MSAA string value changes (e.g. text editing) 1.1032 + // ATK values are always numeric 1.1033 + g_object_notify( (GObject*)atkObj, "accessible-value" ); 1.1034 + } 1.1035 + } break; 1.1036 + 1.1037 + case nsIAccessibleEvent::EVENT_SELECTION: 1.1038 + case nsIAccessibleEvent::EVENT_SELECTION_ADD: 1.1039 + case nsIAccessibleEvent::EVENT_SELECTION_REMOVE: 1.1040 + { 1.1041 + // XXX: dupe events may be fired 1.1042 + AccSelChangeEvent* selChangeEvent = downcast_accEvent(aEvent); 1.1043 + g_signal_emit_by_name(AccessibleWrap::GetAtkObject(selChangeEvent->Widget()), 1.1044 + "selection_changed"); 1.1045 + break; 1.1046 + } 1.1047 + 1.1048 + case nsIAccessibleEvent::EVENT_SELECTION_WITHIN: 1.1049 + { 1.1050 + g_signal_emit_by_name(atkObj, "selection_changed"); 1.1051 + break; 1.1052 + } 1.1053 + 1.1054 + case nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED: 1.1055 + g_signal_emit_by_name(atkObj, "text_selection_changed"); 1.1056 + break; 1.1057 + 1.1058 + case nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED: 1.1059 + { 1.1060 + AccCaretMoveEvent* caretMoveEvent = downcast_accEvent(aEvent); 1.1061 + NS_ASSERTION(caretMoveEvent, "Event needs event data"); 1.1062 + if (!caretMoveEvent) 1.1063 + break; 1.1064 + 1.1065 + int32_t caretOffset = caretMoveEvent->GetCaretOffset(); 1.1066 + g_signal_emit_by_name(atkObj, "text_caret_moved", caretOffset); 1.1067 + } break; 1.1068 + 1.1069 + case nsIAccessibleEvent::EVENT_TEXT_ATTRIBUTE_CHANGED: 1.1070 + g_signal_emit_by_name(atkObj, "text-attributes-changed"); 1.1071 + break; 1.1072 + 1.1073 + case nsIAccessibleEvent::EVENT_TABLE_MODEL_CHANGED: 1.1074 + g_signal_emit_by_name(atkObj, "model_changed"); 1.1075 + break; 1.1076 + 1.1077 + case nsIAccessibleEvent::EVENT_TABLE_ROW_INSERT: 1.1078 + { 1.1079 + AccTableChangeEvent* tableEvent = downcast_accEvent(aEvent); 1.1080 + NS_ENSURE_TRUE(tableEvent, NS_ERROR_FAILURE); 1.1081 + 1.1082 + int32_t rowIndex = tableEvent->GetIndex(); 1.1083 + int32_t numRows = tableEvent->GetCount(); 1.1084 + 1.1085 + g_signal_emit_by_name(atkObj, "row_inserted", rowIndex, numRows); 1.1086 + } break; 1.1087 + 1.1088 + case nsIAccessibleEvent::EVENT_TABLE_ROW_DELETE: 1.1089 + { 1.1090 + AccTableChangeEvent* tableEvent = downcast_accEvent(aEvent); 1.1091 + NS_ENSURE_TRUE(tableEvent, NS_ERROR_FAILURE); 1.1092 + 1.1093 + int32_t rowIndex = tableEvent->GetIndex(); 1.1094 + int32_t numRows = tableEvent->GetCount(); 1.1095 + 1.1096 + g_signal_emit_by_name(atkObj, "row_deleted", rowIndex, numRows); 1.1097 + } break; 1.1098 + 1.1099 + case nsIAccessibleEvent::EVENT_TABLE_ROW_REORDER: 1.1100 + { 1.1101 + g_signal_emit_by_name(atkObj, "row_reordered"); 1.1102 + break; 1.1103 + } 1.1104 + 1.1105 + case nsIAccessibleEvent::EVENT_TABLE_COLUMN_INSERT: 1.1106 + { 1.1107 + AccTableChangeEvent* tableEvent = downcast_accEvent(aEvent); 1.1108 + NS_ENSURE_TRUE(tableEvent, NS_ERROR_FAILURE); 1.1109 + 1.1110 + int32_t colIndex = tableEvent->GetIndex(); 1.1111 + int32_t numCols = tableEvent->GetCount(); 1.1112 + g_signal_emit_by_name(atkObj, "column_inserted", colIndex, numCols); 1.1113 + } break; 1.1114 + 1.1115 + case nsIAccessibleEvent::EVENT_TABLE_COLUMN_DELETE: 1.1116 + { 1.1117 + AccTableChangeEvent* tableEvent = downcast_accEvent(aEvent); 1.1118 + NS_ENSURE_TRUE(tableEvent, NS_ERROR_FAILURE); 1.1119 + 1.1120 + int32_t colIndex = tableEvent->GetIndex(); 1.1121 + int32_t numCols = tableEvent->GetCount(); 1.1122 + g_signal_emit_by_name(atkObj, "column_deleted", colIndex, numCols); 1.1123 + } break; 1.1124 + 1.1125 + case nsIAccessibleEvent::EVENT_TABLE_COLUMN_REORDER: 1.1126 + g_signal_emit_by_name(atkObj, "column_reordered"); 1.1127 + break; 1.1128 + 1.1129 + case nsIAccessibleEvent::EVENT_SECTION_CHANGED: 1.1130 + g_signal_emit_by_name(atkObj, "visible_data_changed"); 1.1131 + break; 1.1132 + 1.1133 + case nsIAccessibleEvent::EVENT_SHOW: 1.1134 + return FireAtkShowHideEvent(aEvent, atkObj, true); 1.1135 + 1.1136 + case nsIAccessibleEvent::EVENT_HIDE: 1.1137 + // XXX - Handle native dialog accessibles. 1.1138 + if (!accessible->IsRoot() && accessible->HasARIARole() && 1.1139 + accessible->ARIARole() == roles::DIALOG) { 1.1140 + guint id = g_signal_lookup("deactivate", MAI_TYPE_ATK_OBJECT); 1.1141 + g_signal_emit(atkObj, id, 0); 1.1142 + } 1.1143 + return FireAtkShowHideEvent(aEvent, atkObj, false); 1.1144 + 1.1145 + /* 1.1146 + * Because dealing with menu is very different between nsIAccessible 1.1147 + * and ATK, and the menu activity is important, specially transfer the 1.1148 + * following two event. 1.1149 + * Need more verification by AT test. 1.1150 + */ 1.1151 + case nsIAccessibleEvent::EVENT_MENU_START: 1.1152 + case nsIAccessibleEvent::EVENT_MENU_END: 1.1153 + break; 1.1154 + 1.1155 + case nsIAccessibleEvent::EVENT_WINDOW_ACTIVATE: 1.1156 + { 1.1157 + accessible->AsRoot()->mActivated = true; 1.1158 + guint id = g_signal_lookup("activate", MAI_TYPE_ATK_OBJECT); 1.1159 + g_signal_emit(atkObj, id, 0); 1.1160 + 1.1161 + // Always fire a current focus event after activation. 1.1162 + FocusMgr()->ForceFocusEvent(); 1.1163 + } break; 1.1164 + 1.1165 + case nsIAccessibleEvent::EVENT_WINDOW_DEACTIVATE: 1.1166 + { 1.1167 + accessible->AsRoot()->mActivated = false; 1.1168 + guint id = g_signal_lookup("deactivate", MAI_TYPE_ATK_OBJECT); 1.1169 + g_signal_emit(atkObj, id, 0); 1.1170 + } break; 1.1171 + 1.1172 + case nsIAccessibleEvent::EVENT_WINDOW_MAXIMIZE: 1.1173 + { 1.1174 + guint id = g_signal_lookup("maximize", MAI_TYPE_ATK_OBJECT); 1.1175 + g_signal_emit(atkObj, id, 0); 1.1176 + } break; 1.1177 + 1.1178 + case nsIAccessibleEvent::EVENT_WINDOW_MINIMIZE: 1.1179 + { 1.1180 + guint id = g_signal_lookup("minimize", MAI_TYPE_ATK_OBJECT); 1.1181 + g_signal_emit(atkObj, id, 0); 1.1182 + } break; 1.1183 + 1.1184 + case nsIAccessibleEvent::EVENT_WINDOW_RESTORE: 1.1185 + { 1.1186 + guint id = g_signal_lookup("restore", MAI_TYPE_ATK_OBJECT); 1.1187 + g_signal_emit(atkObj, id, 0); 1.1188 + } break; 1.1189 + 1.1190 + case nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_COMPLETE: 1.1191 + g_signal_emit_by_name (atkObj, "load_complete"); 1.1192 + // XXX - Handle native dialog accessibles. 1.1193 + if (!accessible->IsRoot() && accessible->HasARIARole() && 1.1194 + accessible->ARIARole() == roles::DIALOG) { 1.1195 + guint id = g_signal_lookup("activate", MAI_TYPE_ATK_OBJECT); 1.1196 + g_signal_emit(atkObj, id, 0); 1.1197 + } 1.1198 + break; 1.1199 + 1.1200 + case nsIAccessibleEvent::EVENT_DOCUMENT_RELOAD: 1.1201 + g_signal_emit_by_name (atkObj, "reload"); 1.1202 + break; 1.1203 + 1.1204 + case nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_STOPPED: 1.1205 + g_signal_emit_by_name (atkObj, "load_stopped"); 1.1206 + break; 1.1207 + 1.1208 + case nsIAccessibleEvent::EVENT_MENUPOPUP_START: 1.1209 + atk_focus_tracker_notify(atkObj); // fire extra focus event 1.1210 + atk_object_notify_state_change(atkObj, ATK_STATE_VISIBLE, true); 1.1211 + atk_object_notify_state_change(atkObj, ATK_STATE_SHOWING, true); 1.1212 + break; 1.1213 + 1.1214 + case nsIAccessibleEvent::EVENT_MENUPOPUP_END: 1.1215 + atk_object_notify_state_change(atkObj, ATK_STATE_VISIBLE, false); 1.1216 + atk_object_notify_state_change(atkObj, ATK_STATE_SHOWING, false); 1.1217 + break; 1.1218 + } 1.1219 + 1.1220 + return NS_OK; 1.1221 +} 1.1222 + 1.1223 +nsresult 1.1224 +AccessibleWrap::FireAtkStateChangeEvent(AccEvent* aEvent, 1.1225 + AtkObject* aObject) 1.1226 +{ 1.1227 + AccStateChangeEvent* event = downcast_accEvent(aEvent); 1.1228 + NS_ENSURE_TRUE(event, NS_ERROR_FAILURE); 1.1229 + 1.1230 + bool isEnabled = event->IsStateEnabled(); 1.1231 + int32_t stateIndex = AtkStateMap::GetStateIndexFor(event->GetState()); 1.1232 + if (stateIndex >= 0) { 1.1233 + NS_ASSERTION(gAtkStateMap[stateIndex].stateMapEntryType != kNoSuchState, 1.1234 + "No such state"); 1.1235 + 1.1236 + if (gAtkStateMap[stateIndex].atkState != kNone) { 1.1237 + NS_ASSERTION(gAtkStateMap[stateIndex].stateMapEntryType != kNoStateChange, 1.1238 + "State changes should not fired for this state"); 1.1239 + 1.1240 + if (gAtkStateMap[stateIndex].stateMapEntryType == kMapOpposite) 1.1241 + isEnabled = !isEnabled; 1.1242 + 1.1243 + // Fire state change for first state if there is one to map 1.1244 + atk_object_notify_state_change(aObject, 1.1245 + gAtkStateMap[stateIndex].atkState, 1.1246 + isEnabled); 1.1247 + } 1.1248 + } 1.1249 + 1.1250 + return NS_OK; 1.1251 +} 1.1252 + 1.1253 +nsresult 1.1254 +AccessibleWrap::FireAtkTextChangedEvent(AccEvent* aEvent, 1.1255 + AtkObject* aObject) 1.1256 +{ 1.1257 + AccTextChangeEvent* event = downcast_accEvent(aEvent); 1.1258 + NS_ENSURE_TRUE(event, NS_ERROR_FAILURE); 1.1259 + 1.1260 + int32_t start = event->GetStartOffset(); 1.1261 + uint32_t length = event->GetLength(); 1.1262 + bool isInserted = event->IsTextInserted(); 1.1263 + bool isFromUserInput = aEvent->IsFromUserInput(); 1.1264 + char* signal_name = nullptr; 1.1265 + 1.1266 + if (gAvailableAtkSignals == eUnknown) 1.1267 + gAvailableAtkSignals = 1.1268 + g_signal_lookup("text-insert", G_OBJECT_TYPE(aObject)) ? 1.1269 + eHaveNewAtkTextSignals : eNoNewAtkSignals; 1.1270 + 1.1271 + if (gAvailableAtkSignals == eNoNewAtkSignals) { 1.1272 + // XXX remove this code and the gHaveNewTextSignals check when we can 1.1273 + // stop supporting old atk since it doesn't really work anyway 1.1274 + // see bug 619002 1.1275 + signal_name = g_strconcat(isInserted ? "text_changed::insert" : 1.1276 + "text_changed::delete", 1.1277 + isFromUserInput ? "" : kNonUserInputEvent, nullptr); 1.1278 + g_signal_emit_by_name(aObject, signal_name, start, length); 1.1279 + } else { 1.1280 + nsAutoString text; 1.1281 + event->GetModifiedText(text); 1.1282 + signal_name = g_strconcat(isInserted ? "text-insert" : "text-remove", 1.1283 + isFromUserInput ? "" : "::system", nullptr); 1.1284 + g_signal_emit_by_name(aObject, signal_name, start, length, 1.1285 + NS_ConvertUTF16toUTF8(text).get()); 1.1286 + } 1.1287 + 1.1288 + g_free(signal_name); 1.1289 + return NS_OK; 1.1290 +} 1.1291 + 1.1292 +nsresult 1.1293 +AccessibleWrap::FireAtkShowHideEvent(AccEvent* aEvent, 1.1294 + AtkObject* aObject, bool aIsAdded) 1.1295 +{ 1.1296 + int32_t indexInParent = getIndexInParentCB(aObject); 1.1297 + AtkObject *parentObject = getParentCB(aObject); 1.1298 + NS_ENSURE_STATE(parentObject); 1.1299 + 1.1300 + bool isFromUserInput = aEvent->IsFromUserInput(); 1.1301 + char *signal_name = g_strconcat(aIsAdded ? "children_changed::add" : "children_changed::remove", 1.1302 + isFromUserInput ? "" : kNonUserInputEvent, nullptr); 1.1303 + g_signal_emit_by_name(parentObject, signal_name, indexInParent, aObject, nullptr); 1.1304 + g_free(signal_name); 1.1305 + 1.1306 + return NS_OK; 1.1307 +}