Merge pull request #6 from roytam1/master

Merge Arctic-Fox commits
This commit is contained in:
Nicholas
2023-11-09 17:56:24 -08:00
committed by GitHub
25351 changed files with 2154476 additions and 898726 deletions
+7 -2
View File
@@ -10,9 +10,14 @@ TAGS
tags
ID
.DS_Store*
*.pdb
# Vim swap files.
.*.sw[a-z]
.sw[a-z]
# Emacs directory variable files.
**/.dir-locals.el
# User files that may appear at the root
/.mozconfig*
@@ -51,8 +56,8 @@ parser/html/java/javaparser/
.settings/
# Python virtualenv artifacts.
python/psutil/*.so
python/psutil/*.pyd
python/psutil/**/*.so
python/psutil/**/*.pyd
python/psutil/build/
# Ignore chrome.manifest files from the devtools loader
+1 -1
View File
@@ -5,7 +5,7 @@
# and in the accompanying Python scripts, see python/lldbutils/README.txt.
# -----------------------------------------------------------------------------
# Import the module that defines complex Goanna debugging commands. This assumes
# Import the module that defines complex Gecko debugging commands. This assumes
# you are either running lldb from the top level source directory, the objdir,
# or the dist/bin directory. (.lldbinit files in the objdir and dist/bin set
# topsrcdir appropriately.)
+14 -1
View File
@@ -6,6 +6,10 @@ import imp
import os
from StringIO import StringIO
import shlex
import sys
old_bytecode = sys.dont_write_bytecode
sys.dont_write_bytecode = True
path = os.path.join(os.path.dirname(__file__), 'mach')
@@ -15,13 +19,22 @@ if not os.path.exists(path):
path = os.path.join(config.topsrcdir, 'mach')
mach_module = imp.load_module('_mach', open(path), path, ('', 'r', imp.PY_SOURCE))
sys.dont_write_bytecode = old_bytecode
def FlagsForFile(filename):
mach = mach_module.get_mach()
out = StringIO()
out.encoding = None
mach.run(['compileflags', filename], stdout=out, stderr=out)
flag_list = shlex.split(out.getvalue())
# This flag is added by Fennec for android build and causes ycmd to fail to parse the file.
# Removing this flag is a workaround until ycmd starts to handle this flag properly.
# https://github.com/Valloric/YouCompleteMe/issues/1490
final_flags = [x for x in flag_list if not x.startswith('-march=armv')]
return {
'flags': shlex.split(out.getvalue()),
'flags': final_flags,
'do_cache': True
}
+5 -9
View File
@@ -39,13 +39,11 @@ ifndef MOZ_PROFILE_USE
# otherwise the rule in rules.mk doesn't run early enough.
$(TIERS) binaries:: CLOBBER $(configure_dir)/configure config.status backend.RecursiveMakeBackend
ifndef JS_STANDALONE
ifndef LIBXUL_SDK
ifdef COMPILE_ENVIRONMENT
$(TIERS) binaries:: $(topsrcdir)/js/src/configure js/src/config.status
endif
endif
endif
endif
ifdef JS_STANDALONE
.PHONY: CLOBBER
@@ -106,7 +104,6 @@ install_manifest_depends = \
$(NULL)
ifndef JS_STANDALONE
ifndef LIBXUL_SDK
ifdef COMPILE_ENVIRONMENT
install_manifest_depends += \
$(topsrcdir)/js/src/configure \
@@ -114,7 +111,6 @@ install_manifest_depends += \
$(NULL)
endif
endif
endif
.PHONY: install-manifests
install-manifests: $(addprefix install-,$(install_manifests))
@@ -128,12 +124,12 @@ ifdef JS_STANDALONE
NO_REMOVE=1
endif
.PHONY: $(addprefix install-,$(install_manifests))
$(addprefix install-,$(filter dist/%,$(install_manifests))): install-dist/%: $(install_manifest_depends)
$(call py_action,process_install_manifest,$(if $(NO_REMOVE),--no-remove )$(DIST)/$* _build_manifests/install/dist_$*)
.PHONY: $(addprefix install-,$(subst /,_,$(install_manifests)))
$(addprefix install-,$(install_manifests)): install-%: $(install_manifest_depends)
$(addprefix $(call py_action,process_install_manifest,$(if $(NO_REMOVE),--no-remove )$*) ,$(wildcard _build_manifests/install/$(subst /,_,$*)))
install-_tests: $(install_manifest_depends)
$(call py_action,process_install_manifest,$(if $(NO_REMOVE),--no-remove )_tests _build_manifests/install/tests)
# Dummy wrapper rule to allow the faster backend to piggy back
install-dist_%: install-dist/% ;
# For compatibility
.PHONY: install-tests
+404 -153
View File
@@ -11,8 +11,11 @@
#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"
@@ -33,7 +36,7 @@
using namespace mozilla;
using namespace mozilla::a11y;
AccessibleWrap::EAvailableAtkSignals AccessibleWrap::gAvailableAtkSignals =
MaiAtkObject::EAvailableAtkSignals MaiAtkObject::gAvailableAtkSignals =
eUnknown;
//defined in ApplicationAccessibleWrap.cpp
@@ -96,7 +99,7 @@ static GType GetAtkTypeForMai(MaiInterfaceType type)
return G_TYPE_INVALID;
}
static const char* kNonUserInputEvent = ":system";
#define NON_USER_EVENT ":system"
static const GInterfaceInfo atk_if_infos[] = {
{(GInterfaceInitFunc)componentInterfaceInitCB,
@@ -123,22 +126,33 @@ static const GInterfaceInfo atk_if_infos[] = {
(GInterfaceFinalizeFunc) nullptr, nullptr}
};
/**
* 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.
*/
uintptr_t accWrap;
};
static GQuark quark_mai_hyperlink = 0;
// This is or'd with the pointer in MaiAtkObject::accWrap if the wrap-ee is a
// proxy.
static const uintptr_t IS_PROXY = 1;
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
{
@@ -208,8 +222,6 @@ static const char * GetUniqueMaiAtkTypeName(uint16_t interfacesBits);
static gpointer parent_class = nullptr;
static GQuark quark_mai_hyperlink = 0;
GType
mai_atk_object_get_type(void)
{
@@ -250,14 +262,15 @@ AccessibleWrap::~AccessibleWrap()
void
AccessibleWrap::ShutdownAtkObject()
{
if (mAtkObject) {
if (IS_MAI_OBJECT(mAtkObject)) {
MAI_ATK_OBJECT(mAtkObject)->accWrap = 0;
}
SetMaiHyperlink(nullptr);
g_object_unref(mAtkObject);
mAtkObject = nullptr;
}
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
@@ -267,42 +280,6 @@ AccessibleWrap::Shutdown()
Accessible::Shutdown();
}
MaiHyperlink*
AccessibleWrap::GetMaiHyperlink(bool aCreate /* = true */)
{
// make sure mAtkObject is created
GetAtkObject();
NS_ASSERTION(quark_mai_hyperlink, "quark_mai_hyperlink not initialized");
NS_ASSERTION(IS_MAI_OBJECT(mAtkObject), "Invalid AtkObject");
MaiHyperlink* maiHyperlink = nullptr;
if (quark_mai_hyperlink && IS_MAI_OBJECT(mAtkObject)) {
maiHyperlink = (MaiHyperlink*)g_object_get_qdata(G_OBJECT(mAtkObject),
quark_mai_hyperlink);
if (!maiHyperlink && aCreate) {
maiHyperlink = new MaiHyperlink(this);
SetMaiHyperlink(maiHyperlink);
}
}
return maiHyperlink;
}
void
AccessibleWrap::SetMaiHyperlink(MaiHyperlink* aMaiHyperlink)
{
NS_ASSERTION(quark_mai_hyperlink, "quark_mai_hyperlink not initialized");
NS_ASSERTION(IS_MAI_OBJECT(mAtkObject), "Invalid AtkObject");
if (quark_mai_hyperlink && IS_MAI_OBJECT(mAtkObject)) {
MaiHyperlink* maiHyperlink = GetMaiHyperlink(false);
if (!maiHyperlink && !aMaiHyperlink) {
return; // Never set and we're shutting down
}
delete maiHyperlink;
g_object_set_qdata(G_OBJECT(mAtkObject), quark_mai_hyperlink,
aMaiHyperlink);
}
}
void
AccessibleWrap::GetNativeInterface(void** aOutAccessible)
{
@@ -582,7 +559,7 @@ initializeCB(AtkObject *aAtkObj, gpointer aData)
ATK_OBJECT_CLASS(parent_class)->initialize(aAtkObj, aData);
/* initialize object */
MAI_ATK_OBJECT(aAtkObj)->accWrap = reinterpret_cast<uintptr_t>(aData);
MAI_ATK_OBJECT(aAtkObj)->accWrap.SetBits(reinterpret_cast<uintptr_t>(aData));
}
void
@@ -590,7 +567,7 @@ finalizeCB(GObject *aObj)
{
if (!IS_MAI_OBJECT(aObj))
return;
NS_ASSERTION(MAI_ATK_OBJECT(aObj)->accWrap == 0, "AccWrap NOT null");
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
@@ -620,7 +597,8 @@ static void
MaybeFireNameChange(AtkObject* aAtkObj, const nsString& aNewName)
{
NS_ConvertUTF16toUTF8 newNameUTF8(aNewName);
if (aAtkObj->name && newNameUTF8.Equals(aAtkObj->name))
if (aAtkObj->name &&
!strncmp(aAtkObj->name, newNameUTF8.get(), newNameUTF8.Length()))
return;
// Below we duplicate the functionality of atk_object_set_name(),
@@ -672,22 +650,17 @@ getRoleCB(AtkObject *aAtkObj)
if (aAtkObj->role != ATK_ROLE_INVALID)
return aAtkObj->role;
AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj);
a11y::role role;
if (!accWrap) {
ProxyAccessible* proxy = GetProxy(aAtkObj);
if (!proxy)
return ATK_ROLE_INVALID;
AccessibleOrProxy acc = GetInternalObj(aAtkObj);
if (acc.IsNull()) {
return ATK_ROLE_INVALID;
}
role = proxy->Role();
} else {
#ifdef DEBUG
if (AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj)) {
NS_ASSERTION(nsAccUtils::IsTextInterfaceSupportCorrect(accWrap),
"Does not support Text interface when it should");
#endif
role = accWrap->Role();
}
#endif
#define ROLE(geckoRole, stringRole, atkRole, macRole, \
msaaRole, ia2Role, nameRule) \
@@ -695,11 +668,11 @@ getRoleCB(AtkObject *aAtkObj)
aAtkObj->role = atkRole; \
break;
switch (role) {
switch (acc.Role()) {
#include "RoleMap.h"
default:
MOZ_CRASH("Unknown role.");
};
}
#undef ROLE
@@ -708,12 +681,12 @@ getRoleCB(AtkObject *aAtkObj)
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_PANEL;
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_UNKNOWN;
aAtkObj->role = ATK_ROLE_SECTION;
return aAtkObj->role;
}
@@ -786,7 +759,7 @@ getAttributesCB(AtkObject *aAtkObj)
if (!proxy)
return nullptr;
nsAutoTArray<Attribute, 10> attrs;
AutoTArray<Attribute, 10> attrs;
proxy->Attributes(&attrs);
if (attrs.IsEmpty())
return nullptr;
@@ -826,7 +799,16 @@ getParentCB(AtkObject *aAtkObj)
atkParent = parent ? AccessibleWrap::GetAtkObject(parent) : nullptr;
} else if (ProxyAccessible* proxy = GetProxy(aAtkObj)) {
ProxyAccessible* parent = proxy->Parent();
atkParent = parent ? GetWrapperFor(parent) : nullptr;
if (parent) {
atkParent = GetWrapperFor(parent);
} else {
// Otherwise this should be the proxy for the tab's top level document.
Accessible* outerDocParent = proxy->OuterDocOfRemoteBrowser();
NS_ASSERTION(outerDocParent, "this document should have an outerDoc as a parent");
if (outerDocParent) {
atkParent = AccessibleWrap::GetAtkObject(outerDocParent);
}
}
}
if (atkParent)
@@ -838,37 +820,72 @@ getParentCB(AtkObject *aAtkObj)
gint
getChildCountCB(AtkObject *aAtkObj)
{
AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj);
if (!accWrap || nsAccUtils::MustPrune(accWrap)) {
return 0;
if (AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj)) {
if (nsAccUtils::MustPrune(accWrap)) {
return 0;
}
return static_cast<gint>(accWrap->EmbeddedChildCount());
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) {
// 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;
}
AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj);
if (!accWrap || nsAccUtils::MustPrune(accWrap)) {
return nullptr;
}
Accessible* accChild = accWrap->GetEmbeddedChildAt(aChildIndex);
if (!accChild)
return nullptr;
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;
AtkObject* childAtkObj = AccessibleWrap::GetAtkObject(accChild);
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);
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);
@@ -885,6 +902,9 @@ getIndexInParentCB(AtkObject* aAtkObj)
if (ProxyAccessible* parent = proxy->Parent())
return parent->IndexOfEmbeddedChild(proxy);
if (proxy->OuterDocOfRemoteBrowser())
return 0;
return -1;
}
@@ -961,6 +981,13 @@ UpdateAtkRelation(RelationType aType, Accessible* aAcc,
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);
@@ -992,7 +1019,7 @@ refRelationSetCB(AtkObject *aAtkObj)
continue;
size_t targetCount = targetSets[i].Length();
nsAutoTArray<AtkObject*, 5> wrappers;
AutoTArray<AtkObject*, 5> wrappers;
for (size_t j = 0; j < targetCount; j++)
wrappers.AppendElement(GetWrapperFor(targetSets[i][j]));
@@ -1028,14 +1055,17 @@ refRelationSetCB(AtkObject *aAtkObj)
AccessibleWrap*
GetAccessibleWrap(AtkObject* aAtkObj)
{
NS_ENSURE_TRUE(IS_MAI_OBJECT(aAtkObj), nullptr);
bool isMAIObject = IS_MAI_OBJECT(aAtkObj);
NS_ENSURE_TRUE(isMAIObject || MAI_IS_ATK_SOCKET(aAtkObj),
nullptr);
// Make sure its native is an AccessibleWrap not a proxy.
if (MAI_ATK_OBJECT(aAtkObj)->accWrap & IS_PROXY)
uintptr_t accWrapPtr = isMAIObject ?
MAI_ATK_OBJECT(aAtkObj)->accWrap.Bits() :
reinterpret_cast<uintptr_t>(MAI_ATK_SOCKET(aAtkObj)->accWrap);
if (accWrapPtr & IS_PROXY)
return nullptr;
AccessibleWrap* accWrap =
reinterpret_cast<AccessibleWrap*>(MAI_ATK_OBJECT(aAtkObj)->accWrap);
AccessibleWrap* accWrap = reinterpret_cast<AccessibleWrap*>(accWrapPtr);
// Check if the accessible was deconstructed.
if (!accWrap)
@@ -1053,11 +1083,16 @@ GetAccessibleWrap(AtkObject* aAtkObj)
ProxyAccessible*
GetProxy(AtkObject* aObj)
{
if (!aObj || !(MAI_ATK_OBJECT(aObj)->accWrap & IS_PROXY))
return GetInternalObj(aObj).AsProxy();
}
AccessibleOrProxy
GetInternalObj(AtkObject* aObj)
{
if (!aObj || !IS_MAI_OBJECT(aObj))
return nullptr;
return reinterpret_cast<ProxyAccessible*>(MAI_ATK_OBJECT(aObj)->accWrap
& ~IS_PROXY);
return MAI_ATK_OBJECT(aObj)->accWrap;
}
AtkObject*
@@ -1074,6 +1109,29 @@ GetInterfacesForProxy(ProxyAccessible* aProxy, uint32_t aInterfaces)
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::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;
}
@@ -1100,7 +1158,7 @@ void
a11y::ProxyDestroyed(ProxyAccessible* aProxy)
{
auto obj = reinterpret_cast<MaiAtkObject*>(aProxy->GetWrapper() & ~IS_PROXY);
obj->accWrap = 0;
obj->Shutdown();
g_object_unref(obj);
aProxy->SetWrapper(0);
}
@@ -1111,6 +1169,10 @@ 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);
@@ -1139,11 +1201,27 @@ AccessibleWrap::HandleAccEvent(AccEvent* aEvent)
switch (type) {
case nsIAccessibleEvent::EVENT_STATE_CHANGE:
return FireAtkStateChangeEvent(aEvent, atkObj);
{
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:
return FireAtkTextChangedEvent(aEvent, atkObj);
{
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:
{
@@ -1167,6 +1245,7 @@ AccessibleWrap::HandleAccEvent(AccEvent* aEvent)
}
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.
@@ -1191,6 +1270,11 @@ AccessibleWrap::HandleAccEvent(AccEvent* aEvent)
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;
@@ -1364,21 +1448,59 @@ void
a11y::ProxyEvent(ProxyAccessible* aTarget, uint32_t aEventType)
{
AtkObject* wrapper = GetWrapperFor(aTarget);
if (aEventType == nsIAccessibleEvent::EVENT_FOCUS) {
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;
}
}
nsresult
AccessibleWrap::FireAtkStateChangeEvent(AccEvent* aEvent,
AtkObject* aObject)
void
a11y::ProxyStateChangeEvent(ProxyAccessible* aTarget, uint64_t aState,
bool aEnabled)
{
AccStateChangeEvent* event = downcast_accEvent(aEvent);
NS_ENSURE_TRUE(event, NS_ERROR_FAILURE);
MaiAtkObject* atkObj = MAI_ATK_OBJECT(GetWrapperFor(aTarget));
atkObj->FireStateChangeEvent(aState, aEnabled);
}
bool isEnabled = event->IsStateEnabled();
int32_t stateIndex = AtkStateMap::GetStateIndexFor(event->GetState());
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");
@@ -1388,57 +1510,73 @@ AccessibleWrap::FireAtkStateChangeEvent(AccEvent* aEvent,
"State changes should not fired for this state");
if (gAtkStateMap[stateIndex].stateMapEntryType == kMapOpposite)
isEnabled = !isEnabled;
aEnabled = !aEnabled;
// Fire state change for first state if there is one to map
atk_object_notify_state_change(aObject,
atk_object_notify_state_change(&parent,
gAtkStateMap[stateIndex].atkState,
isEnabled);
aEnabled);
}
}
return NS_OK;
}
nsresult
AccessibleWrap::FireAtkTextChangedEvent(AccEvent* aEvent,
AtkObject* aObject)
void
a11y::ProxyTextChangeEvent(ProxyAccessible* aTarget, const nsString& aStr,
int32_t aStart, uint32_t aLen, bool aIsInsert,
bool aFromUser)
{
AccTextChangeEvent* event = downcast_accEvent(aEvent);
NS_ENSURE_TRUE(event, NS_ERROR_FAILURE);
MaiAtkObject* atkObj = MAI_ATK_OBJECT(GetWrapperFor(aTarget));
atkObj->FireTextChangeEvent(aStr, aStart, aLen, aIsInsert, aFromUser);
}
int32_t start = event->GetStartOffset();
uint32_t length = event->GetLength();
bool isInserted = event->IsTextInserted();
bool isFromUserInput = aEvent->IsFromUserInput();
char* signal_name = nullptr;
#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(aObject)) ?
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
signal_name = g_strconcat(isInserted ? "text_changed::insert" :
"text_changed::delete",
isFromUserInput ? "" : kNonUserInputEvent, nullptr);
g_signal_emit_by_name(aObject, signal_name, start, length);
const char* signal_name =
oldTextChangeStrings[aFromUser][aIsInsert];
g_signal_emit_by_name(this, signal_name, aStart, aLen);
} else {
nsAutoString text;
event->GetModifiedText(text);
signal_name = g_strconcat(isInserted ? "text-insert" : "text-remove",
isFromUserInput ? "" : "::system", nullptr);
g_signal_emit_by_name(aObject, signal_name, start, length,
NS_ConvertUTF16toUTF8(text).get());
const char* signal_name =
textChangedStrings[aFromUser][aIsInsert];
g_signal_emit_by_name(this, signal_name, aStart, aLen,
NS_ConvertUTF16toUTF8(aStr).get());
}
g_free(signal_name);
return NS_OK;
}
#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 },
};
nsresult
AccessibleWrap::FireAtkShowHideEvent(AccEvent* aEvent,
AtkObject* aObject, bool aIsAdded)
@@ -1448,10 +1586,123 @@ AccessibleWrap::FireAtkShowHideEvent(AccEvent* aEvent,
NS_ENSURE_STATE(parentObject);
bool isFromUserInput = aEvent->IsFromUserInput();
char *signal_name = g_strconcat(aIsAdded ? "children_changed::add" : "children_changed::remove",
isFromUserInput ? "" : kNonUserInputEvent, nullptr);
const char *signal_name = kMutationStrings[isFromUserInput][aIsAdded];
g_signal_emit_by_name(parentObject, signal_name, indexInParent, aObject, nullptr);
g_free(signal_name);
return NS_OK;
}
// 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];
}
+6 -18
View File
@@ -63,16 +63,18 @@ public:
bool IsValidObject();
// get/set the MaiHyperlink object for this AccessibleWrap
MaiHyperlink* GetMaiHyperlink(bool aCreate = true);
void SetMaiHyperlink(MaiHyperlink* aMaiHyperlink);
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);
@@ -83,20 +85,6 @@ protected:
AtkObject *mAtkObject;
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;
uint16_t CreateMaiInterfaces();
};
+2 -31
View File
@@ -21,35 +21,6 @@ const char* AtkSocketAccessible::sATKSocketGetTypeSymbol = "atk_socket_get_type"
bool AtkSocketAccessible::gCanEmbed = FALSE;
extern "C" void mai_atk_component_iface_init(AtkComponentIface* aIface);
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;
AccessibleWrap* accWrap;
} MaiAtkSocket;
typedef struct _MaiAtkSocketClass
{
AtkSocketClass parent_class;
} MaiAtkSocketClass;
G_DEFINE_TYPE_EXTENDED(MaiAtkSocket, mai_atk_socket,
AtkSocketAccessible::g_atk_socket_type, 0,
@@ -86,7 +57,7 @@ RefAccessibleAtPoint(AtkComponent* aComponent, gint aX, gint aY,
{
NS_ENSURE_TRUE(MAI_IS_ATK_SOCKET(aComponent), nullptr);
return refAccessibleAtPointHelper(MAI_ATK_SOCKET(aComponent)->accWrap,
return refAccessibleAtPointHelper(ATK_OBJECT(MAI_ATK_SOCKET(aComponent)),
aX, aY, aCoordType);
}
@@ -99,7 +70,7 @@ GetExtents(AtkComponent* aComponent, gint* aX, gint* aY, gint* aWidth,
if (!MAI_IS_ATK_SOCKET(aComponent))
return;
getExtentsHelper(MAI_ATK_SOCKET(aComponent)->accWrap,
getExtentsHelper(ATK_OBJECT(MAI_ATK_SOCKET(aComponent)),
aX, aY, aWidth, aHeight, aCoordType);
}
}
+2 -2
View File
@@ -34,9 +34,9 @@ void valueInterfaceInitCB(AtkValueIface *aIface);
/**
* XXX these should live in a file of utils for atk.
*/
AtkObject* refAccessibleAtPointHelper(mozilla::a11y::AccessibleWrap* aAccWrap,
AtkObject* refAccessibleAtPointHelper(AtkObject* aAtkObj,
gint aX, gint aY, AtkCoordType aCoordType);
void getExtentsHelper(mozilla::a11y::AccessibleWrap* aAccWrap,
void getExtentsHelper(AtkObject* aAtkObj,
gint* aX, gint* aY, gint* aWidth, gint* aHeight,
AtkCoordType aCoordType);
+19 -11
View File
@@ -18,8 +18,9 @@
#include <dbus/dbus.h>
#endif
#include <gtk/gtk.h>
#if (MOZ_WIDGET_GTK == 3)
#include <atk-bridge.h>
extern "C" __attribute__((weak,visibility("default"))) int atk_bridge_adaptor_init(int*, char **[]);
#endif
using namespace mozilla;
@@ -46,7 +47,6 @@ static gulong sToplevel_hide_hook = 0;
GType g_atk_hyperlink_impl_type = G_TYPE_INVALID;
#if (MOZ_WIDGET_GTK == 2)
struct GnomeAccessibilityModule
{
const char *libName;
@@ -67,11 +67,13 @@ static GnomeAccessibilityModule sAtkBridge = {
"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)
@@ -98,7 +100,11 @@ LoadGtkModule(GnomeAccessibilityModule& aModule)
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)
@@ -123,7 +129,6 @@ LoadGtkModule(GnomeAccessibilityModule& aModule)
}
return NS_OK;
}
#endif // (MOZ_WIDGET_GTK == 2)
void
a11y::PlatformInit()
@@ -175,14 +180,17 @@ a11y::PlatformInit()
// Init atk-bridge now
PR_SetEnv("NO_AT_BRIDGE=0");
#if (MOZ_WIDGET_GTK == 2)
rv = LoadGtkModule(sAtkBridge);
if (NS_SUCCEEDED(rv)) {
(*sAtkBridge.init)();
}
#else
atk_bridge_adaptor_init(nullptr, nullptr);
#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;
@@ -210,7 +218,6 @@ a11y::PlatformShutdown()
sToplevel_hide_hook);
}
#if (MOZ_WIDGET_GTK == 2)
if (sAtkBridge.lib) {
// Do not shutdown/unload atk-bridge,
// an exit function registered will take care of it
@@ -221,6 +228,7 @@ a11y::PlatformShutdown()
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
View File
@@ -55,5 +55,3 @@ include('/ipc/chromium/chromium-config.mozbuild')
if CONFIG['CLANG_CXX']:
# Suppress clang warning about unused function from gobject's RTTI macros.
CXXFLAGS += ['-Wno-unused-function']
FAIL_ON_WARNINGS = True
+84
View File
@@ -11,6 +11,7 @@
#include <glib.h>
#include <glib-object.h>
#include "AccessibleOrProxy.h"
#include "AccessibleWrap.h"
namespace mozilla {
@@ -34,8 +35,39 @@ class ProxyAccessible;
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;
mozilla::a11y::AccessibleWrap* GetAccessibleWrap(AtkObject* aAtkObj);
mozilla::a11y::ProxyAccessible* GetProxy(AtkObject* aAtkObj);
mozilla::a11y::AccessibleOrProxy GetInternalObj(AtkObject* aObj);
AtkObject* GetWrapperFor(mozilla::a11y::ProxyAccessible* aProxy);
extern int atkMajorVersion, atkMinorVersion;
@@ -51,4 +83,56 @@ IsAtkVersionAtLeast(int aMajor, int aMinor)
(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);
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__ */
+76 -74
View File
@@ -6,6 +6,7 @@
#include "nsIURI.h"
#include "nsMaiHyperlink.h"
#include "mozilla/a11y/ProxyAccessible.h"
using namespace mozilla::a11y;
@@ -61,8 +62,17 @@ static gint getAnchorCountCB(AtkHyperlink *aLink);
G_END_DECLS
static gpointer parent_class = nullptr;
static Accessible*
get_accessible_hyperlink(AtkHyperlink *aHyperlink);
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)
@@ -90,60 +100,29 @@ mai_atk_hyperlink_get_type(void)
return type;
}
MaiHyperlink::MaiHyperlink(Accessible* aHyperLink) :
MaiHyperlink::MaiHyperlink(AccessibleOrProxy aHyperLink) :
mHyperlink(aHyperLink),
mMaiAtkHyperlink(nullptr)
{
}
MaiHyperlink::~MaiHyperlink()
{
if (mMaiAtkHyperlink) {
MAI_ATK_HYPERLINK(mMaiAtkHyperlink)->maiHyperlink = nullptr;
g_object_unref(mMaiAtkHyperlink);
}
}
AtkHyperlink*
MaiHyperlink::GetAtkHyperlink(void)
{
NS_ENSURE_TRUE(mHyperlink, nullptr);
if (mMaiAtkHyperlink)
return mMaiAtkHyperlink;
if (!mHyperlink->IsLink())
return nullptr;
mMaiAtkHyperlink =
reinterpret_cast<AtkHyperlink *>
(g_object_new(mai_atk_hyperlink_get_type(), nullptr));
NS_ASSERTION(mMaiAtkHyperlink, "OUT OF MEMORY");
NS_ENSURE_TRUE(mMaiAtkHyperlink, nullptr);
if (!mMaiAtkHyperlink)
return;
/* be sure to initialize it with "this" */
MaiHyperlink::Initialize(mMaiAtkHyperlink, this);
return mMaiAtkHyperlink;
MAI_ATK_HYPERLINK(mMaiAtkHyperlink)->maiHyperlink = this;
}
/* static */
/* remember to call this static function when a MaiAtkHyperlink
* is created
*/
nsresult
MaiHyperlink::Initialize(AtkHyperlink *aObj, MaiHyperlink *aHyperlink)
MaiHyperlink::~MaiHyperlink()
{
NS_ENSURE_ARG(MAI_IS_ATK_HYPERLINK(aObj));
NS_ENSURE_ARG(aHyperlink);
/* initialize hyperlink */
MAI_ATK_HYPERLINK(aObj)->maiHyperlink = aHyperlink;
return NS_OK;
if (mMaiAtkHyperlink) {
MAI_ATK_HYPERLINK(mMaiAtkHyperlink)->maiHyperlink = nullptr;
g_object_unref(mMaiAtkHyperlink);
}
}
/* static functions for ATK callbacks */
void
@@ -181,79 +160,102 @@ finalizeCB(GObject *aObj)
gchar *
getUriCB(AtkHyperlink *aLink, gint aLinkIndex)
{
Accessible* hyperlink = get_accessible_hyperlink(aLink);
NS_ENSURE_TRUE(hyperlink, nullptr);
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;
return nullptr;
nsAutoCString cautoStr;
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)
{
Accessible* hyperlink = get_accessible_hyperlink(aLink);
NS_ENSURE_TRUE(hyperlink, nullptr);
MaiHyperlink* maiLink = GetMaiHyperlink(aLink);
if (!maiLink)
return nullptr;
Accessible* anchor = hyperlink->AnchorAt(aLinkIndex);
NS_ENSURE_TRUE(anchor, nullptr);
if (Accessible* hyperlink = maiLink->GetAccHyperlink()) {
Accessible* anchor = hyperlink->AnchorAt(aLinkIndex);
NS_ENSURE_TRUE(anchor, nullptr);
AtkObject* atkObj = AccessibleWrap::GetAtkObject(anchor);
//no need to add ref it, because it is "get" not "ref"
return atkObj;
return AccessibleWrap::GetAtkObject(anchor);
}
ProxyAccessible* anchor = maiLink->Proxy()->AnchorAt(aLinkIndex);
return anchor ? GetWrapperFor(anchor) : nullptr;
}
gint
getEndIndexCB(AtkHyperlink *aLink)
{
Accessible* hyperlink = get_accessible_hyperlink(aLink);
NS_ENSURE_TRUE(hyperlink, -1);
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)
{
Accessible* hyperlink = get_accessible_hyperlink(aLink);
NS_ENSURE_TRUE(hyperlink, -1);
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)
{
Accessible* hyperlink = get_accessible_hyperlink(aLink);
NS_ENSURE_TRUE(hyperlink, FALSE);
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)
{
Accessible* hyperlink = get_accessible_hyperlink(aLink);
NS_ENSURE_TRUE(hyperlink, -1);
MaiHyperlink* maiLink = GetMaiHyperlink(aLink);
if (!maiLink)
return -1;
if (Accessible* hyperlink = maiLink->GetAccHyperlink())
return static_cast<gint>(hyperlink->AnchorCount());
}
// Check if aHyperlink is a valid MaiHyperlink, and return the
// HyperLinkAccessible related.
Accessible*
get_accessible_hyperlink(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->GetAccHyperlink();
bool valid = false;
uint32_t anchorCount = maiLink->Proxy()->AnchorCount(&valid);
return valid ? static_cast<gint>(anchorCount) : -1;
}
+17 -6
View File
@@ -23,19 +23,30 @@ namespace a11y {
class MaiHyperlink
{
public:
explicit MaiHyperlink(Accessible* aHyperLink);
explicit MaiHyperlink(AccessibleOrProxy aHyperLink);
~MaiHyperlink();
public:
AtkHyperlink *GetAtkHyperlink(void);
AtkHyperlink* GetAtkHyperlink() const { return mMaiAtkHyperlink; }
Accessible* GetAccHyperlink()
{ return mHyperlink && mHyperlink->IsLink() ? mHyperlink : nullptr; }
{
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:
Accessible* mHyperlink;
AccessibleOrProxy mHyperlink;
AtkHyperlink* mMaiAtkHyperlink;
public:
static nsresult Initialize(AtkHyperlink *aObj, MaiHyperlink *aClass);
};
} // namespace a11y
+37 -54
View File
@@ -10,7 +10,7 @@
#include "nsMai.h"
#include "Role.h"
#include "mozilla/Likely.h"
#include "ProxyAccessible.h"
#include "nsString.h"
using namespace mozilla::a11y;
@@ -21,86 +21,69 @@ static gboolean
doActionCB(AtkAction *aAction, gint aActionIndex)
{
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aAction));
return accWrap && accWrap->DoAction(aActionIndex);
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));
return accWrap ? accWrap->ActionCount() : 0;
if (accWrap) {
return accWrap->ActionCount();
}
ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aAction));
return proxy ? proxy->ActionCount() : 0;
}
static const gchar*
getActionDescriptionCB(AtkAction *aAction, gint aActionIndex)
{
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aAction));
if (!accWrap)
return nullptr;
nsAutoString description;
accWrap->ActionDescriptionAt(aActionIndex, 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)
{
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aAction));
if (!accWrap)
return nullptr;
nsAutoString autoStr;
accWrap->ActionNameAt(aActionIndex, 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)
{
AccessibleWrap* acc = GetAccessibleWrap(ATK_OBJECT(aAction));
if (!acc)
return nullptr;
// Return all key bindings including access key and keyboard shortcut.
nsAutoString keyBindingsStr;
// Get access key.
KeyBinding keyBinding = acc->AccessKey();
if (!keyBinding.IsEmpty()) {
keyBinding.AppendToString(keyBindingsStr, KeyBinding::eAtkFormat);
Accessible* parent = acc->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);
}
AccessibleWrap* acc = GetAccessibleWrap(ATK_OBJECT(aAction));
if (acc) {
AccessibleWrap::GetKeyBinding(acc, keyBindingsStr);
} else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aAction))) {
proxy->AtkKeyBinding(keyBindingsStr);
} else {
// No access key, add ';' to point this.
keyBindingsStr.Append(';');
}
// Get keyboard shortcut.
keyBindingsStr.Append(';');
keyBinding = acc->KeyboardShortcut();
if (!keyBinding.IsEmpty()) {
keyBinding.AppendToString(keyBindingsStr, KeyBinding::eAtkFormat);
return nullptr;
}
return AccessibleWrap::ReturnString(keyBindingsStr);
+76 -39
View File
@@ -11,6 +11,7 @@
#include "nsCoreUtils.h"
#include "nsMai.h"
#include "mozilla/Likely.h"
#include "mozilla/a11y/ProxyAccessible.h"
using namespace mozilla::a11y;
@@ -20,7 +21,7 @@ static AtkObject*
refAccessibleAtPointCB(AtkComponent* aComponent, gint aAccX, gint aAccY,
AtkCoordType aCoordType)
{
return refAccessibleAtPointHelper(GetAccessibleWrap(ATK_OBJECT(aComponent)),
return refAccessibleAtPointHelper(ATK_OBJECT(aComponent),
aAccX, aAccY, aCoordType);
}
@@ -28,73 +29,109 @@ static void
getExtentsCB(AtkComponent* aComponent, gint* aX, gint* aY,
gint* aWidth, gint* aHeight, AtkCoordType aCoordType)
{
getExtentsHelper(GetAccessibleWrap(ATK_OBJECT(aComponent)),
getExtentsHelper(ATK_OBJECT(aComponent),
aX, aY, aWidth, aHeight, aCoordType);
}
static gboolean
grabFocusCB(AtkComponent* aComponent)
{
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aComponent));
if (!accWrap)
return FALSE;
AtkObject* atkObject = ATK_OBJECT(aComponent);
AccessibleWrap* accWrap = GetAccessibleWrap(atkObject);
if (accWrap) {
accWrap->TakeFocus();
return TRUE;
}
accWrap->TakeFocus();
return TRUE;
ProxyAccessible* proxy = GetProxy(atkObject);
if (proxy) {
proxy->TakeFocus();
return TRUE;
}
return FALSE;
}
}
AtkObject*
refAccessibleAtPointHelper(AccessibleWrap* aAccWrap, gint aX, gint aY,
refAccessibleAtPointHelper(AtkObject* aAtkObj, gint aX, gint aY,
AtkCoordType aCoordType)
{
if (!aAccWrap || aAccWrap->IsDefunct() || nsAccUtils::MustPrune(aAccWrap))
return nullptr;
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(aAccWrap->GetNode());
aX += winCoords.x;
aY += winCoords.y;
// 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;
}
Accessible* accAtPoint = aAccWrap->ChildAtPoint(aX, aY,
Accessible::eDirectChild);
if (!accAtPoint)
return nullptr;
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;
}
AtkObject* atkObj = AccessibleWrap::GetAtkObject(accAtPoint);
if (atkObj)
g_object_ref(atkObj);
return atkObj;
return nullptr;
}
void
getExtentsHelper(AccessibleWrap* aAccWrap,
getExtentsHelper(AtkObject* aAtkObj,
gint* aX, gint* aY, gint* aWidth, gint* aHeight,
AtkCoordType aCoordType)
{
AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj);
*aX = *aY = *aWidth = *aHeight = 0;
if (!aAccWrap || aAccWrap->IsDefunct())
return;
if (accWrap) {
if (accWrap->IsDefunct()) {
return;
}
nsIntRect screenRect = aAccWrap->Bounds();
if (screenRect.IsEmpty())
return;
nsIntRect screenRect = accWrap->Bounds();
if (screenRect.IsEmpty())
return;
if (aCoordType == ATK_XY_WINDOW) {
nsIntPoint winCoords =
nsCoreUtils::GetScreenCoordsForWindow(aAccWrap->GetNode());
screenRect.x -= winCoords.x;
screenRect.y -= winCoords.y;
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;
}
*aX = screenRect.x;
*aY = screenRect.y;
*aWidth = screenRect.width;
*aHeight = screenRect.height;
if (ProxyAccessible* proxy = GetProxy(aAtkObj)) {
proxy->Extents(aCoordType == ATK_XY_WINDOW, aX, aY, aWidth, aHeight);
}
}
void
@@ -16,14 +16,13 @@ static AtkHyperlink*
getHyperlinkCB(AtkHyperlinkImpl* aImpl)
{
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aImpl));
if (!accWrap)
if (!accWrap && !GetProxy(ATK_OBJECT(aImpl)))
return nullptr;
NS_ENSURE_TRUE(accWrap->IsLink(), nullptr);
if (accWrap)
NS_ASSERTION(accWrap->IsLink(), "why isn't it a link!");
MaiHyperlink* maiHyperlink = accWrap->GetMaiHyperlink();
NS_ENSURE_TRUE(maiHyperlink, nullptr);
return maiHyperlink->GetAtkHyperlink();
return MAI_ATK_OBJECT(aImpl)->GetAtkHyperlink();
}
}
+10 -17
View File
@@ -22,34 +22,27 @@ 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) {
if (!hyperLink || !hyperLink->IsLink()) {
return nullptr;
}
AtkObject* hyperLinkAtkObj = AccessibleWrap::GetAtkObject(hyperLink);
AccessibleWrap* accChild = GetAccessibleWrap(hyperLinkAtkObj);
NS_ENSURE_TRUE(accChild, nullptr);
MaiHyperlink* maiHyperlink = accChild->GetMaiHyperlink();
NS_ENSURE_TRUE(maiHyperlink, nullptr);
return maiHyperlink->GetAtkHyperlink();
}
if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
atkHyperLink = AccessibleWrap::GetAtkObject(hyperLink);
} else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
ProxyAccessible* proxyLink = proxy->LinkAt(aLinkIndex);
if (proxyLink) {
NS_WARNING("IMPLEMENT ME! See bug 1146518.");
// We should somehow get from ProxyAccessible* to AtkHyperlink*.
}
return nullptr;
if (!proxyLink)
return nullptr;
atkHyperLink = GetWrapperFor(proxyLink);
}
return nullptr;
NS_ENSURE_TRUE(IS_MAI_OBJECT(atkHyperLink), nullptr);
return MAI_ATK_OBJECT(atkHyperLink)->GetAtkHyperlink();
}
static gint
+169 -98
View File
@@ -12,7 +12,7 @@
#include "TableAccessible.h"
#include "TableCellAccessible.h"
#include "nsMai.h"
#include "ProxyAccessible.h"
#include "nsArrayUtils.h"
#include "mozilla/Likely.h"
@@ -23,17 +23,31 @@ 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 || aRowIdx < 0 || aColIdx < 0)
return nullptr;
if (accWrap) {
Accessible* cell = accWrap->AsTable()->CellAt(aRowIdx, aColIdx);
if (!cell) {
return nullptr;
}
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;
}
AtkObject* cellAtkObj = AccessibleWrap::GetAtkObject(cell);
if (cellAtkObj)
cellAtkObj = GetWrapperFor(cell);
}
if (cellAtkObj) {
g_object_ref(cellAtkObj);
}
return cellAtkObj;
}
@@ -41,93 +55,153 @@ refAtCB(AtkTable* aTable, gint aRowIdx, gint aColIdx)
static gint
getIndexAtCB(AtkTable* aTable, gint aRowIdx, gint aColIdx)
{
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
if (!accWrap || aRowIdx < 0 || aColIdx < 0)
if (aRowIdx < 0 || aColIdx < 0) {
return -1;
}
return static_cast<gint>(accWrap->AsTable()->CellIndexAt(aRowIdx, aColIdx));
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)
{
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
if (!accWrap || aIdx < 0)
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)
{
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
if (!accWrap || aIdx < 0)
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 -1;
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 -1;
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)
{
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
if (!accWrap || aRowIdx < 0 || aColIdx < 0)
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 -1;
if (accWrap) {
return static_cast<gint>(accWrap->AsTable()->RowExtentAt(aRowIdx, aColIdx));
}
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)
return nullptr;
if (accWrap) {
Accessible* caption = accWrap->AsTable()->Caption();
return caption ? AccessibleWrap::GetAtkObject(caption) : nullptr;
}
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)
{
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
if (!accWrap)
return nullptr;
nsAutoString autoStr;
accWrap->AsTable()->ColDescription(aColumn, 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);
}
@@ -136,40 +210,32 @@ static AtkObject*
getColumnHeaderCB(AtkTable *aTable, gint aColIdx)
{
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
if (!accWrap)
return nullptr;
if (accWrap) {
Accessible* header =
AccessibleWrap::GetColumnHeader(accWrap->AsTable(), aColIdx);
return header ? AccessibleWrap::GetAtkObject(header) : nullptr;
}
Accessible* cell = accWrap->AsTable()->CellAt(0, aColIdx);
if (!cell)
return nullptr;
if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
ProxyAccessible* header = proxy->AtkTableColumnHeader(aColIdx);
return header ? GetWrapperFor(header) : 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 AccessibleWrap::GetAtkObject(cell);
// otherwise get column header for the data cell at the first row.
TableCellAccessible* tableCell = cell->AsTableCell();
if (!tableCell)
return nullptr;
nsAutoTArray<Accessible*, 10> headerCells;
tableCell->ColHeaderCells(&headerCells);
if (headerCells.IsEmpty())
return nullptr;
return AccessibleWrap::GetAtkObject(headerCells[0]);
return nullptr;
}
static const gchar*
getRowDescriptionCB(AtkTable *aTable, gint aRow)
{
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
if (!accWrap)
return nullptr;
nsAutoString autoStr;
accWrap->AsTable()->RowDescription(aRow, 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);
}
@@ -178,29 +244,18 @@ static AtkObject*
getRowHeaderCB(AtkTable *aTable, gint aRowIdx)
{
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
if (!accWrap)
return nullptr;
if (accWrap) {
Accessible* header =
AccessibleWrap::GetRowHeader(accWrap->AsTable(), aRowIdx);
return header ? AccessibleWrap::GetAtkObject(header) : nullptr;
}
Accessible* cell = accWrap->AsTable()->CellAt(aRowIdx, 0);
if (!cell)
return nullptr;
if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
ProxyAccessible* header = proxy->AtkTableRowHeader(aRowIdx);
return header ? GetWrapperFor(header) : 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 AccessibleWrap::GetAtkObject(cell);
// otherwise get row header for the data cell at the first column.
TableCellAccessible* tableCell = cell->AsTableCell();
if (!tableCell)
return nullptr;
nsAutoTArray<Accessible*, 10> headerCells;
tableCell->RowHeaderCells(&headerCells);
if (headerCells.IsEmpty())
return nullptr;
return AccessibleWrap::GetAtkObject(headerCells[0]);
return nullptr;
}
static AtkObject*
@@ -218,12 +273,16 @@ getSelectedColumnsCB(AtkTable *aTable, gint** aSelected)
{
*aSelected = nullptr;
AutoTArray<uint32_t, 10> cols;
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
if (!accWrap)
if (accWrap) {
accWrap->AsTable()->SelectedColIndices(&cols);
} else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
proxy->TableSelectedColumnIndices(&cols);
} else {
return 0;
}
nsAutoTArray<uint32_t, 10> cols;
accWrap->AsTable()->SelectedColIndices(&cols);
if (cols.IsEmpty())
return 0;
@@ -241,12 +300,15 @@ getSelectedColumnsCB(AtkTable *aTable, gint** aSelected)
static gint
getSelectedRowsCB(AtkTable *aTable, gint **aSelected)
{
AutoTArray<uint32_t, 10> rows;
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
if (!accWrap)
if (accWrap) {
accWrap->AsTable()->SelectedRowIndices(&rows);
} else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
proxy->TableSelectedRowIndices(&rows);
} else {
return 0;
nsAutoTArray<uint32_t, 10> rows;
accWrap->AsTable()->SelectedRowIndices(&rows);
}
gint* atkRows = g_new(gint, rows.Length());
if (!atkRows) {
@@ -263,31 +325,40 @@ static gboolean
isColumnSelectedCB(AtkTable *aTable, gint aColIdx)
{
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
if (!accWrap)
return FALSE;
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 static_cast<gboolean>(accWrap->AsTable()->IsColSelected(aColIdx));
return FALSE;
}
static gboolean
isRowSelectedCB(AtkTable *aTable, gint aRowIdx)
{
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
if (!accWrap)
return FALSE;
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 static_cast<gboolean>(accWrap->AsTable()->IsRowSelected(aRowIdx));
return FALSE;
}
static gboolean
isCellSelectedCB(AtkTable *aTable, gint aRowIdx, gint aColIdx)
{
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
if (!accWrap)
return FALSE;
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;
}
}
+56 -47
View File
@@ -32,13 +32,15 @@ ConvertTextAttributeToAtkAttribute(const nsACString& aName,
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, 5, aValue.Length() - 1);
// 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, 5, aValue.Length() - 1);
// 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;
@@ -161,22 +163,24 @@ getTextAfterOffsetCB(AtkText *aText, gint aOffset,
AtkTextBoundary aBoundaryType,
gint *aStartOffset, gint *aEndOffset)
{
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
if (!accWrap)
return nullptr;
HyperTextAccessible* text = accWrap->AsHyperText();
if (!text || !text->IsTextRole())
return nullptr;
nsAutoString autoStr;
nsAutoString autoStr;
int32_t startOffset = 0, endOffset = 0;
text->TextAfterOffset(aOffset, aBoundaryType, &startOffset, &endOffset, autoStr);
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;
ConvertTexttoAsterisks(accWrap, autoStr);
NS_ConvertUTF16toUTF8 cautoStr(autoStr);
return (cautoStr.get()) ? g_strdup(cautoStr.get()) : nullptr;
}
@@ -186,23 +190,26 @@ 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)
return nullptr;
if (accWrap) {
HyperTextAccessible* text = accWrap->AsHyperText();
if (!text || !text->IsTextRole())
return nullptr;
HyperTextAccessible* text = accWrap->AsHyperText();
if (!text || !text->IsTextRole())
return nullptr;
nsAutoString autoStr;
int32_t startOffset = 0, endOffset = 0;
text->TextAtOffset(aOffset, aBoundaryType, &startOffset, &endOffset, autoStr);
*aStartOffset = startOffset;
*aEndOffset = endOffset;
ConvertTexttoAsterisks(accWrap, autoStr);
NS_ConvertUTF16toUTF8 cautoStr(autoStr);
return (cautoStr.get()) ? g_strdup(cautoStr.get()) : nullptr;
} 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
@@ -231,22 +238,25 @@ getTextBeforeOffsetCB(AtkText *aText, gint aOffset,
AtkTextBoundary aBoundaryType,
gint *aStartOffset, gint *aEndOffset)
{
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
if (!accWrap)
return nullptr;
HyperTextAccessible* text = accWrap->AsHyperText();
if (!text || !text->IsTextRole())
return nullptr;
nsAutoString autoStr;
int32_t startOffset = 0, endOffset = 0;
text->TextBeforeOffset(aOffset, aBoundaryType,
&startOffset, &endOffset, autoStr);
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;
ConvertTexttoAsterisks(accWrap, autoStr);
NS_ConvertUTF16toUTF8 cautoStr(autoStr);
return (cautoStr.get()) ? g_strdup(cautoStr.get()) : nullptr;
}
@@ -301,7 +311,7 @@ getRunAttributesCB(AtkText *aText, gint aOffset,
return nullptr;
}
nsAutoTArray<Attribute, 10> attrs;
AutoTArray<Attribute, 10> attrs;
proxy->TextAttributes(false, aOffset, &attrs, &startOffset, &endOffset);
*aStartOffset = startOffset;
*aEndOffset = endOffset;
@@ -327,7 +337,7 @@ getDefaultAttributesCB(AtkText *aText)
return nullptr;
}
nsAutoTArray<Attribute, 10> attrs;
AutoTArray<Attribute, 10> attrs;
proxy->DefaultTextAttributes(&attrs);
return ConvertToAtkTextAttributeSet(attrs);
}
@@ -347,7 +357,7 @@ getCharacterExtentsCB(AtkText *aText, gint aOffset,
if (aCoords == ATK_XY_SCREEN) {
geckoCoordType = nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE;
} else {
giabbaCoordType = nsIAccessibleCoordinateType::COORDTYPE_WINDOW_RELATIVE;
geckoCoordType = nsIAccessibleCoordinateType::COORDTYPE_WINDOW_RELATIVE;
}
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
@@ -381,9 +391,9 @@ getRangeExtentsCB(AtkText *aText, gint aStartOffset, gint aEndOffset,
nsIntRect rect;
uint32_t geckoCoordType;
if (aCoords == ATK_XY_SCREEN) {
geckoCoordType = nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE;
geckoCoordType = nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE;
} else {
geckoCoordType = nsIAccessibleCoordinateType::COORDTYPE_WINDOW_RELATIVE;
geckoCoordType = nsIAccessibleCoordinateType::COORDTYPE_WINDOW_RELATIVE;
}
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
@@ -576,9 +586,8 @@ setCaretOffsetCB(AtkText *aText, gint aOffset)
}
if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
if (proxy->SetCaretOffset(aOffset)) {
return TRUE;
}
proxy->SetCaretOffset(aOffset);
return TRUE;
}
return FALSE;
+22 -1
View File
@@ -98,6 +98,16 @@ static nsRoleMapEntry sWAIRoleMaps[] =
kNoReqStates
// eARIAPressed is auto applied on any button
},
{ // cell
&nsGkAtoms::cell,
roles::CELL,
kUseMapRole,
eNoValue,
eNoAction,
eNoLiveAttr,
eTableCell,
kNoReqStates
},
{ // checkbox
&nsGkAtoms::checkbox,
roles::CHECKBUTTON,
@@ -478,7 +488,7 @@ static nsRoleMapEntry sWAIRoleMaps[] =
},
{ // radiogroup
&nsGkAtoms::radiogroup,
roles::GROUPING,
roles::RADIO_GROUP,
kUseMapRole,
eNoValue,
eNoAction,
@@ -631,6 +641,17 @@ static nsRoleMapEntry sWAIRoleMaps[] =
kNoReqStates,
eARIASelectable
},
{ // table
&nsGkAtoms::table,
roles::TABLE,
kUseMapRole,
eNoValue,
eNoAction,
eNoLiveAttr,
eTable,
kNoReqStates,
eARIASelectable
},
{ // tablist
&nsGkAtoms::tablist,
roles::PAGETABLIST,
+5 -3
View File
@@ -102,8 +102,9 @@ EmbeddedObjCollector::GetIndexAt(Accessible* aAccessible)
if (aAccessible->mParent != mRoot)
return -1;
if (aAccessible->mIndexOfEmbeddedChild != -1)
return aAccessible->mIndexOfEmbeddedChild;
MOZ_ASSERT(!aAccessible->IsProxy());
if (aAccessible->mInt.mIndexOfEmbeddedChild != -1)
return aAccessible->mInt.mIndexOfEmbeddedChild;
return mFilterFunc(aAccessible) & filters::eMatch ?
EnsureNGetIndex(aAccessible) : -1;
@@ -112,6 +113,7 @@ EmbeddedObjCollector::GetIndexAt(Accessible* aAccessible)
void
EmbeddedObjCollector::AppendObject(Accessible* aAccessible)
{
aAccessible->mIndexOfEmbeddedChild = mObjects.Length();
MOZ_ASSERT(!aAccessible->IsProxy());
aAccessible->mInt.mIndexOfEmbeddedChild = mObjects.Length();
mObjects.AppendElement(aAccessible);
}
+5 -4
View File
@@ -104,8 +104,9 @@ AccReorderEvent::IsShowHideEventTarget(const Accessible* aTarget) const
////////////////////////////////////////////////////////////////////////////////
AccHideEvent::
AccHideEvent(Accessible* aTarget, nsINode* aTargetNode) :
AccMutationEvent(::nsIAccessibleEvent::EVENT_HIDE, aTarget, aTargetNode)
AccHideEvent(Accessible* aTarget, bool aNeedsShutdown) :
AccMutationEvent(::nsIAccessibleEvent::EVENT_HIDE, aTarget),
mNeedsShutdown(aNeedsShutdown)
{
mNextSibling = mAccessible->NextSibling();
mPrevSibling = mAccessible->PrevSibling();
@@ -117,8 +118,8 @@ AccHideEvent::
////////////////////////////////////////////////////////////////////////////////
AccShowEvent::
AccShowEvent(Accessible* aTarget, nsINode* aTargetNode) :
AccMutationEvent(::nsIAccessibleEvent::EVENT_SHOW, aTarget, aTargetNode)
AccShowEvent(Accessible* aTarget) :
AccMutationEvent(::nsIAccessibleEvent::EVENT_SHOW, aTarget)
{
}
+15 -13
View File
@@ -127,7 +127,7 @@ protected:
bool mIsFromUserInput;
uint32_t mEventType;
EEventRule mEventRule;
nsRefPtr<Accessible> mAccessible;
RefPtr<Accessible> mAccessible;
friend class EventQueue;
friend class AccReorderEvent;
@@ -194,6 +194,7 @@ public:
bool IsTextInserted() const { return mIsInserted; }
void GetModifiedText(nsAString& aModifiedText)
{ aModifiedText = mModifiedText; }
const nsString& ModifiedText() const { return mModifiedText; }
private:
int32_t mStart;
@@ -211,8 +212,7 @@ private:
class AccMutationEvent: public AccEvent
{
public:
AccMutationEvent(uint32_t aEventType, Accessible* aTarget,
nsINode* aTargetNode) :
AccMutationEvent(uint32_t aEventType, Accessible* aTarget) :
AccEvent(aEventType, aTarget, eAutoDetect, eCoalesceMutationTextChange)
{
// Don't coalesce these since they are coalesced by reorder event. Coalesce
@@ -236,8 +236,8 @@ public:
protected:
nsCOMPtr<nsINode> mNode;
nsRefPtr<Accessible> mParent;
nsRefPtr<AccTextChangeEvent> mTextChangeEvent;
RefPtr<Accessible> mParent;
RefPtr<AccTextChangeEvent> mTextChangeEvent;
friend class EventQueue;
};
@@ -249,7 +249,7 @@ protected:
class AccHideEvent: public AccMutationEvent
{
public:
AccHideEvent(Accessible* aTarget, nsINode* aTargetNode);
explicit AccHideEvent(Accessible* aTarget, bool aNeedsShutdown = true);
// Event
static const EventGroup kEventGroup = eHideEvent;
@@ -262,10 +262,12 @@ public:
Accessible* TargetParent() const { return mParent; }
Accessible* TargetNextSibling() const { return mNextSibling; }
Accessible* TargetPrevSibling() const { return mPrevSibling; }
bool NeedsShutdown() const { return mNeedsShutdown; }
protected:
nsRefPtr<Accessible> mNextSibling;
nsRefPtr<Accessible> mPrevSibling;
bool mNeedsShutdown;
RefPtr<Accessible> mNextSibling;
RefPtr<Accessible> mPrevSibling;
friend class EventQueue;
};
@@ -277,7 +279,7 @@ protected:
class AccShowEvent: public AccMutationEvent
{
public:
AccShowEvent(Accessible* aTarget, nsINode* aTargetNode);
explicit AccShowEvent(Accessible* aTarget);
// Event
static const EventGroup kEventGroup = eShowEvent;
@@ -393,7 +395,7 @@ public:
bool IsCaretMoveOnly() const;
private:
nsRefPtr<dom::Selection> mSel;
RefPtr<dom::Selection> mSel;
int32_t mReason;
friend class EventQueue;
@@ -428,8 +430,8 @@ public:
Accessible* Widget() const { return mWidget; }
private:
nsRefPtr<Accessible> mWidget;
nsRefPtr<Accessible> mItem;
RefPtr<Accessible> mWidget;
RefPtr<Accessible> mItem;
SelChangeType mSelChangeType;
uint32_t mPreceedingCount;
AccSelChangeEvent* mPackedEvent;
@@ -491,7 +493,7 @@ public:
int32_t Reason() const { return mReason; }
private:
nsRefPtr<Accessible> mOldAccessible;
RefPtr<Accessible> mOldAccessible;
int32_t mOldStart;
int32_t mOldEnd;
int16_t mReason;
+27 -67
View File
@@ -9,7 +9,7 @@
#include "XULTreeAccessible.h"
#endif
#include "mozilla/dom/Element.h"
#include "mozilla/dom/HTMLLabelElement.h"
using namespace mozilla;
using namespace mozilla::a11y;
@@ -134,6 +134,14 @@ HTMLLabelIterator::
{
}
bool
HTMLLabelIterator::IsLabel(Accessible* aLabel)
{
dom::HTMLLabelElement* labelEl =
dom::HTMLLabelElement::FromContent(aLabel->GetContent());
return labelEl && labelEl->GetControl() == mAcc->GetContent();
}
Accessible*
HTMLLabelIterator::Next()
{
@@ -141,8 +149,9 @@ HTMLLabelIterator::Next()
// element, or <label> ancestor which implicitly point to it.
Accessible* label = nullptr;
while ((label = mRelIter.Next())) {
if (label->GetContent()->IsHTMLElement(nsGkAtoms::label))
if (IsLabel(label)) {
return label;
}
}
// Ignore ancestor label on not widget accessible.
@@ -154,14 +163,14 @@ HTMLLabelIterator::Next()
// document.
Accessible* walkUp = mAcc->Parent();
while (walkUp && !walkUp->IsDoc()) {
nsIContent* walkUpElm = walkUp->GetContent();
if (walkUpElm->IsHTMLElement(nsGkAtoms::label) &&
!walkUpElm->HasAttr(kNameSpaceID_None, nsGkAtoms::_for)) {
nsIContent* walkUpEl = walkUp->GetContent();
if (IsLabel(walkUp) &&
!walkUpEl->HasAttr(kNameSpaceID_None, nsGkAtoms::_for)) {
mLabelFilter = eSkipAncestorLabel; // prevent infinite loop
return walkUp;
}
if (walkUpElm->IsHTMLElement(nsGkAtoms::form))
if (walkUpEl->IsHTMLElement(nsGkAtoms::form))
break;
walkUp = walkUp->Parent();
@@ -324,66 +333,14 @@ IDRefsIterator::GetElem(const nsDependentSubstring& aID)
Accessible*
IDRefsIterator::Next()
{
nsIContent* nextElm = NextElem();
return nextElm ? mDoc->GetAccessible(nextElm) : nullptr;
}
////////////////////////////////////////////////////////////////////////////////
// ARIAOwnedByIterator
////////////////////////////////////////////////////////////////////////////////
ARIAOwnedByIterator::ARIAOwnedByIterator(const Accessible* aDependent) :
RelatedAccIterator(aDependent->Document(), aDependent->GetContent(),
nsGkAtoms::aria_owns), mDependent(aDependent)
{
}
Accessible*
ARIAOwnedByIterator::Next()
{
Accessible* owner = RelatedAccIterator::Next();
Accessible* cur = owner;
while (cur) {
if (cur == mDependent)
return Next(); // owner cannot be a child of dependent.
if (cur->IsDoc())
break; // don't cross document boundaries
cur = cur->Parent();
nsIContent* nextEl = nullptr;
while ((nextEl = NextElem())) {
Accessible* acc = mDoc->GetAccessible(nextEl);
if (acc) {
return acc;
}
}
return owner;
}
////////////////////////////////////////////////////////////////////////////////
// ARIAOwnsIterator
////////////////////////////////////////////////////////////////////////////////
ARIAOwnsIterator::ARIAOwnsIterator(const Accessible* aOwner) :
mIter(aOwner->Document(), aOwner->GetContent(), nsGkAtoms::aria_owns),
mOwner(aOwner)
{
}
Accessible*
ARIAOwnsIterator::Next()
{
Accessible* child = mIter.Next();
const Accessible* cur = mOwner;
while (cur) {
if (cur == child)
return Next(); // cannot own its own parent
if (cur->IsDoc())
break; // don't cross document boundaries
cur = cur->Parent();
}
return child;
return nullptr;
}
@@ -394,9 +351,12 @@ ARIAOwnsIterator::Next()
Accessible*
SingleAccIterator::Next()
{
nsRefPtr<Accessible> nextAcc;
RefPtr<Accessible> nextAcc;
mAcc.swap(nextAcc);
return (nextAcc && !nextAcc->IsDefunct()) ? nextAcc : nullptr;
if (!nextAcc || nextAcc->IsDefunct()) {
return nullptr;
}
return nextAcc;
}
+3 -42
View File
@@ -130,6 +130,8 @@ private:
HTMLLabelIterator(const HTMLLabelIterator&);
HTMLLabelIterator& operator = (const HTMLLabelIterator&);
bool IsLabel(Accessible* aLabel);
RelatedAccIterator mRelIter;
// XXX: replace it on weak reference (bug 678429), it's safe to use raw
// pointer now because iterators life cycle is short.
@@ -248,47 +250,6 @@ private:
};
/**
* Iterates over related accessible referred by aria-owns.
*/
class ARIAOwnedByIterator final : public RelatedAccIterator
{
public:
explicit ARIAOwnedByIterator(const Accessible* aDependent);
virtual ~ARIAOwnedByIterator() { }
virtual Accessible* Next() override;
private:
ARIAOwnedByIterator() = delete;
ARIAOwnedByIterator(const ARIAOwnedByIterator&) = delete;
ARIAOwnedByIterator& operator = (const ARIAOwnedByIterator&) = delete;
const Accessible* mDependent;
};
/**
* Iterates over related accessible referred by aria-owns.
*/
class ARIAOwnsIterator final : public AccIterable
{
public:
explicit ARIAOwnsIterator(const Accessible* aOwner);
virtual ~ARIAOwnsIterator() { }
virtual Accessible* Next() override;
private:
ARIAOwnsIterator() = delete;
ARIAOwnsIterator(const ARIAOwnsIterator&) = delete;
ARIAOwnsIterator& operator = (const ARIAOwnsIterator&) = delete;
IDRefsIterator mIter;
const Accessible* mOwner;
};
/**
* Iterator that points to a single accessible returning it on the first call
* to Next().
@@ -306,7 +267,7 @@ private:
SingleAccIterator(const SingleAccIterator&);
SingleAccIterator& operator = (const SingleAccIterator&);
nsRefPtr<Accessible> mAcc;
RefPtr<Accessible> mAcc;
};
+121
View File
@@ -0,0 +1,121 @@
/* -*- 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_AccessibleOrProxy_h
#define mozilla_a11y_AccessibleOrProxy_h
#include "mozilla/a11y/Accessible.h"
#include "mozilla/a11y/ProxyAccessible.h"
#include "mozilla/a11y/Role.h"
#include <stdint.h>
namespace mozilla {
namespace a11y {
/**
* This class stores an Accessible* or a ProxyAccessible* in a safe manner
* with size sizeof(void*).
*/
class AccessibleOrProxy
{
public:
MOZ_IMPLICIT AccessibleOrProxy(Accessible* aAcc) :
mBits(reinterpret_cast<uintptr_t>(aAcc)) {}
MOZ_IMPLICIT AccessibleOrProxy(ProxyAccessible* aProxy) :
mBits(reinterpret_cast<uintptr_t>(aProxy) | IS_PROXY) {}
MOZ_IMPLICIT AccessibleOrProxy(decltype(nullptr)) : mBits(0) {}
bool IsProxy() const { return mBits & IS_PROXY; }
ProxyAccessible* AsProxy() const
{
if (IsProxy()) {
return reinterpret_cast<ProxyAccessible*>(mBits & ~IS_PROXY);
}
return nullptr;
}
bool IsAccessible() const { return !IsProxy(); }
Accessible* AsAccessible() const
{
if (IsAccessible()) {
return reinterpret_cast<Accessible*>(mBits);
}
return nullptr;
}
bool IsNull() const { return mBits == 0; }
uint32_t ChildCount() const
{
if (IsProxy()) {
return AsProxy()->ChildrenCount();
}
return AsAccessible()->ChildCount();
}
/**
* Return the child object either an accessible or a proxied accessible at
* the given index.
*/
AccessibleOrProxy ChildAt(uint32_t aIdx)
{
if (IsProxy()) {
return AsProxy()->ChildAt(aIdx);
}
return AsAccessible()->GetChildAt(aIdx);
}
/**
* Return the first child object.
*/
AccessibleOrProxy FirstChild()
{
if (IsProxy()) {
return AsProxy()->FirstChild();
}
return AsAccessible()->FirstChild();
}
/**
* Return the first child object.
*/
AccessibleOrProxy LastChild()
{
if (IsProxy()) {
return AsProxy()->LastChild();
}
return AsAccessible()->LastChild();
}
role Role() const
{
if (IsProxy()) {
return AsProxy()->Role();
}
return AsAccessible()->Role();
}
// XXX these are implementation details that ideally would not be exposed.
uintptr_t Bits() const { return mBits; }
void SetBits(uintptr_t aBits) { mBits = aBits; }
private:
uintptr_t mBits;
static const uintptr_t IS_PROXY = 0x1;
};
}
}
#endif
+83 -72
View File
@@ -1,4 +1,5 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=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/. */
@@ -39,6 +40,8 @@ using namespace mozilla::a11y;
using namespace mozilla::dom;
StaticAutoPtr<nsTArray<DocAccessibleParent*>> DocManager::sRemoteDocuments;
nsRefPtrHashtable<nsPtrHashKey<const DocAccessibleParent>, xpcAccessibleDocument>*
DocManager::sRemoteXPCDocumentCache = nullptr;
////////////////////////////////////////////////////////////////////////////////
// DocManager
@@ -71,13 +74,19 @@ DocManager::GetDocAccessible(nsIDocument* aDocument)
Accessible*
DocManager::FindAccessibleInCache(nsINode* aNode) const
{
nsSearchAccessibleInCacheArg arg;
arg.mNode = aNode;
for (auto iter = mDocAccessibleCache.ConstIter(); !iter.Done(); iter.Next()) {
DocAccessible* docAccessible = iter.UserData();
NS_ASSERTION(docAccessible,
"No doc accessible for the object in doc accessible cache!");
mDocAccessibleCache.EnumerateRead(SearchAccessibleInDocCache,
static_cast<void*>(&arg));
return arg.mAccessible;
if (docAccessible) {
Accessible* accessible = docAccessible->GetAccessible(aNode);
if (accessible) {
return accessible;
}
}
}
return nullptr;
}
void
@@ -94,6 +103,16 @@ DocManager::NotifyOfDocumentShutdown(DocAccessible* aDocument,
RemoveListeners(aDOMDocument);
}
void
DocManager::NotifyOfRemoteDocShutdown(DocAccessibleParent* aDoc)
{
xpcAccessibleDocument* doc = GetCachedXPCDocument(aDoc);
if (doc) {
doc->Shutdown();
sRemoteXPCDocumentCache->Remove(aDoc);
}
}
xpcAccessibleDocument*
DocManager::GetXPCDocument(DocAccessible* aDocument)
{
@@ -108,15 +127,41 @@ DocManager::GetXPCDocument(DocAccessible* aDocument)
return xpcDoc;
}
xpcAccessibleDocument*
DocManager::GetXPCDocument(DocAccessibleParent* aDoc)
{
xpcAccessibleDocument* doc = GetCachedXPCDocument(aDoc);
if (doc) {
return doc;
}
if (!sRemoteXPCDocumentCache) {
sRemoteXPCDocumentCache =
new nsRefPtrHashtable<nsPtrHashKey<const DocAccessibleParent>, xpcAccessibleDocument>;
}
doc =
new xpcAccessibleDocument(aDoc, Interfaces::DOCUMENT | Interfaces::HYPERTEXT);
sRemoteXPCDocumentCache->Put(aDoc, doc);
return doc;
}
#ifdef DEBUG
bool
DocManager::IsProcessingRefreshDriverNotification() const
{
bool isDocRefreshing = false;
mDocAccessibleCache.EnumerateRead(SearchIfDocIsRefreshing,
static_cast<void*>(&isDocRefreshing));
for (auto iter = mDocAccessibleCache.ConstIter(); !iter.Done(); iter.Next()) {
DocAccessible* docAccessible = iter.UserData();
NS_ASSERTION(docAccessible,
"No doc accessible for the object in doc accessible cache!");
return isDocRefreshing;
if (docAccessible && docAccessible->mNotificationController &&
docAccessible->mNotificationController->IsUpdating()) {
return true;
}
}
return false;
}
#endif
@@ -427,7 +472,7 @@ DocManager::CreateDocOrRootAccessible(nsIDocument* aDocument)
// We only create root accessibles for the true root, otherwise create a
// doc accessible.
nsIContent *rootElm = nsCoreUtils::GetRoleContent(aDocument);
nsRefPtr<DocAccessible> docAcc = isRootDoc ?
RefPtr<DocAccessible> docAcc = isRootDoc ?
new RootAccessibleWrap(aDocument, rootElm, presShell) :
new DocAccessibleWrap(aDocument, rootElm, presShell);
@@ -455,12 +500,20 @@ DocManager::CreateDocOrRootAccessible(nsIDocument* aDocument)
ApplicationAcc());
if (IPCAccessibilityActive()) {
DocAccessibleChild* ipcDoc = new DocAccessibleChild(docAcc);
docAcc->SetIPCDoc(ipcDoc);
nsCOMPtr<nsITabChild> tabChild =
do_GetInterface(aDocument->GetDocShell());
static_cast<TabChild*>(tabChild.get())->
SendPDocAccessibleConstructor(ipcDoc, nullptr, 0);
nsIDocShell* docShell = aDocument->GetDocShell();
if (docShell) {
nsCOMPtr<nsITabChild> tabChild = do_GetInterface(docShell);
// XXX We may need to handle the case that we don't have a tab child
// differently. It may be that this will cause us to fail to notify
// the parent process about important accessible documents.
if (tabChild) {
DocAccessibleChild* ipcDoc = new DocAccessibleChild(docAcc);
docAcc->SetIPCDoc(ipcDoc);
static_cast<TabChild*>(tabChild.get())->
SendPDocAccessibleConstructor(ipcDoc, nullptr, 0);
}
}
}
} else {
parentDocAcc->BindChildDocument(docAcc);
@@ -480,66 +533,24 @@ DocManager::CreateDocOrRootAccessible(nsIDocument* aDocument)
////////////////////////////////////////////////////////////////////////////////
// DocManager static
PLDHashOperator
DocManager::GetFirstEntryInDocCache(const nsIDocument* aKey,
DocAccessible* aDocAccessible,
void* aUserArg)
{
NS_ASSERTION(aDocAccessible,
"No doc accessible for the object in doc accessible cache!");
*reinterpret_cast<DocAccessible**>(aUserArg) = aDocAccessible;
return PL_DHASH_STOP;
}
void
DocManager::ClearDocCache()
{
DocAccessible* docAcc = nullptr;
while (mDocAccessibleCache.EnumerateRead(GetFirstEntryInDocCache, static_cast<void*>(&docAcc))) {
if (docAcc)
// This unusual do-one-element-per-iterator approach is required because each
// DocAccessible is removed elsewhere upon its Shutdown() method being
// called, which invalidates the existing iterator.
while (mDocAccessibleCache.Count() > 0) {
auto iter = mDocAccessibleCache.Iter();
MOZ_ASSERT(!iter.Done());
DocAccessible* docAcc = iter.UserData();
NS_ASSERTION(docAcc,
"No doc accessible for the object in doc accessible cache!");
if (docAcc) {
docAcc->Shutdown();
}
}
}
PLDHashOperator
DocManager::SearchAccessibleInDocCache(const nsIDocument* aKey,
DocAccessible* aDocAccessible,
void* aUserArg)
{
NS_ASSERTION(aDocAccessible,
"No doc accessible for the object in doc accessible cache!");
if (aDocAccessible) {
nsSearchAccessibleInCacheArg* arg =
static_cast<nsSearchAccessibleInCacheArg*>(aUserArg);
arg->mAccessible = aDocAccessible->GetAccessible(arg->mNode);
if (arg->mAccessible)
return PL_DHASH_STOP;
}
return PL_DHASH_NEXT;
}
#ifdef DEBUG
PLDHashOperator
DocManager::SearchIfDocIsRefreshing(const nsIDocument* aKey,
DocAccessible* aDocAccessible,
void* aUserArg)
{
NS_ASSERTION(aDocAccessible,
"No doc accessible for the object in doc accessible cache!");
if (aDocAccessible && aDocAccessible->mNotificationController &&
aDocAccessible->mNotificationController->IsUpdating()) {
*(static_cast<bool*>(aUserArg)) = true;
return PL_DHASH_STOP;
}
return PL_DHASH_NEXT;
}
#endif
void
DocManager::RemoteDocAdded(DocAccessibleParent* aDoc)
{
@@ -551,5 +562,5 @@ DocManager::RemoteDocAdded(DocAccessibleParent* aDoc)
MOZ_ASSERT(!sRemoteDocuments->Contains(aDoc),
"How did we already have the doc!");
sRemoteDocuments->AppendElement(aDoc);
ProxyCreated(aDoc, 0);
ProxyCreated(aDoc, Interfaces::DOCUMENT | Interfaces::HYPERTEXT);
}
+20 -25
View File
@@ -87,6 +87,24 @@ public:
*/
static void RemoteDocAdded(DocAccessibleParent* aDoc);
static const nsTArray<DocAccessibleParent*>* TopLevelRemoteDocs()
{ return sRemoteDocuments; }
/**
* Remove the xpc document for a remote document if there is one.
*/
static void NotifyOfRemoteDocShutdown(DocAccessibleParent* adoc);
/**
* Get a XPC document for a remote document.
*/
static xpcAccessibleDocument* GetXPCDocument(DocAccessibleParent* aDoc);
static xpcAccessibleDocument* GetCachedXPCDocument(const DocAccessibleParent* aDoc)
{
return sRemoteXPCDocumentCache ? sRemoteXPCDocumentCache->GetWeak(aDoc)
: nullptr;
}
#ifdef DEBUG
bool IsProcessingRefreshDriverNotification() const;
#endif
@@ -132,36 +150,11 @@ private:
*/
DocAccessible* CreateDocOrRootAccessible(nsIDocument* aDocument);
/**
* Get first entry of the document accessible from cache.
*/
static PLDHashOperator
GetFirstEntryInDocCache(const nsIDocument* aKey,
DocAccessible* aDocAccessible,
void* aUserArg);
/**
* Clear the cache and shutdown the document accessibles.
*/
void ClearDocCache();
struct nsSearchAccessibleInCacheArg
{
Accessible* mAccessible;
nsINode* mNode;
};
static PLDHashOperator
SearchAccessibleInDocCache(const nsIDocument* aKey,
DocAccessible* aDocAccessible,
void* aUserArg);
#ifdef DEBUG
static PLDHashOperator
SearchIfDocIsRefreshing(const nsIDocument* aKey,
DocAccessible* aDocAccessible, void* aUserArg);
#endif
typedef nsRefPtrHashtable<nsPtrHashKey<const nsIDocument>, DocAccessible>
DocAccessibleHashtable;
DocAccessibleHashtable mDocAccessibleCache;
@@ -169,6 +162,8 @@ private:
typedef nsRefPtrHashtable<nsPtrHashKey<const DocAccessible>, xpcAccessibleDocument>
XPCDocumentHashtable;
XPCDocumentHashtable mXPCDocumentCache;
static nsRefPtrHashtable<nsPtrHashKey<const DocAccessibleParent>, xpcAccessibleDocument>*
sRemoteXPCDocumentCache;
/*
* The list of remote top level documents.
+13 -42
View File
@@ -61,7 +61,7 @@ EventQueue::PushEvent(AccEvent* aEvent)
ENameValueFlag nameFlag = parent->Name(name);
// If name is obtained from subtree, fire name change event.
if (nameFlag == eNameFromSubtree) {
nsRefPtr<AccEvent> nameChangeEvent =
RefPtr<AccEvent> nameChangeEvent =
new AccEvent(nsIAccessibleEvent::EVENT_NAME_CHANGE, parent);
PushEvent(nameChangeEvent);
}
@@ -248,12 +248,7 @@ EventQueue::CoalesceReorderEvents(AccEvent* aTailEvent)
// Coalesce earlier event of the same target.
if (thisEvent->mAccessible == aTailEvent->mAccessible) {
if (thisEvent->mEventRule == AccEvent::eDoNotEmit) {
AccReorderEvent* tailReorder = downcast_accEvent(aTailEvent);
tailReorder->DoNotEmitAll();
} else {
thisEvent->mEventRule = AccEvent::eDoNotEmit;
}
thisEvent->mEventRule = AccEvent::eDoNotEmit;
return;
}
@@ -300,12 +295,16 @@ EventQueue::CoalesceReorderEvents(AccEvent* aTailEvent)
AccReorderEvent* thisReorder = downcast_accEvent(thisEvent);
AccReorderEvent* tailReorder = downcast_accEvent(aTailEvent);
uint32_t eventType = thisReorder->IsShowHideEventTarget(tailParent);
if (eventType == nsIAccessibleEvent::EVENT_SHOW)
if (eventType == nsIAccessibleEvent::EVENT_SHOW) {
tailReorder->DoNotEmitAll();
else if (eventType == nsIAccessibleEvent::EVENT_HIDE)
}
else if (eventType == nsIAccessibleEvent::EVENT_HIDE) {
NS_ERROR("Accessible tree was modified after it was removed! Huh?");
else
}
else {
aTailEvent->mEventRule = AccEvent::eDoNotEmit;
mEvents[index].swap(mEvents[count - 1]);
}
return;
}
@@ -480,33 +479,6 @@ EventQueue::CreateTextChangeEventFor(AccMutationEvent* aEvent)
aEvent->mIsFromUserInput ? eFromUserInput : eNoUserInput);
}
void
EventQueue::SendIPCEvent(AccEvent* aEvent) const
{
DocAccessibleChild* ipcDoc = mDocument->IPCDoc();
uint64_t id = aEvent->GetAccessible()->IsDoc() ? 0 :
reinterpret_cast<uintptr_t>(aEvent->GetAccessible());
switch(aEvent->GetEventType()) {
case nsIAccessibleEvent::EVENT_SHOW:
ipcDoc->ShowEvent(downcast_accEvent(aEvent));
break;
case nsIAccessibleEvent::EVENT_HIDE:
ipcDoc->SendHideEvent(id);
break;
case nsIAccessibleEvent::EVENT_REORDER:
// reorder events on the application acc aren't necessary to tell the parent
// about new top level documents.
if (!aEvent->GetAccessible()->IsApplication())
ipcDoc->SendEvent(id, aEvent->GetEventType());
break;
default:
ipcDoc->SendEvent(id, aEvent->GetEventType());
}
}
////////////////////////////////////////////////////////////////////////////////
// EventQueue: event queue
@@ -514,7 +486,7 @@ void
EventQueue::ProcessEventQueue()
{
// Process only currently queued events.
nsTArray<nsRefPtr<AccEvent> > events;
nsTArray<RefPtr<AccEvent> > events;
events.SwapElements(mEvents);
uint32_t eventCount = events.Length();
@@ -578,13 +550,12 @@ EventQueue::ProcessEventQueue()
}
}
if (event->mEventType == nsIAccessibleEvent::EVENT_HIDE)
AccHideEvent* hideEvent = downcast_accEvent(event);
if (hideEvent && hideEvent->NeedsShutdown()) {
mDocument->ShutdownChildrenInSubtree(event->mAccessible);
}
if (!mDocument)
return;
if (IPCAccessibilityActive())
SendIPCEvent(event);
}
}
+2 -7
View File
@@ -53,11 +53,6 @@ private:
AccSelChangeEvent* aThisEvent,
uint32_t aThisIndex);
/**
* Notify the parent process of events being fired by this event queue.
*/
void SendIPCEvent(AccEvent* aEvent) const;
/**
* Coalesce text change events caused by sibling hide events.
*/
@@ -81,10 +76,10 @@ protected:
DocAccessible* mDocument;
/**
* Pending events array. Don't make this an nsAutoTArray; we use
* Pending events array. Don't make this an AutoTArray; we use
* SwapElements() on it.
*/
nsTArray<nsRefPtr<AccEvent> > mEvents;
nsTArray<RefPtr<AccEvent> > mEvents;
};
} // namespace a11y
+1 -3
View File
@@ -47,9 +47,7 @@ filters::GetRow(Accessible* aAccessible)
uint32_t
filters::GetCell(Accessible* aAccessible)
{
a11y::role role = aAccessible->Role();
return role == roles::GRID_CELL || role == roles::ROWHEADER ||
role == roles::COLUMNHEADER ? eMatch : eSkipSubtree;
return aAccessible->IsTableCell() ? eMatch : eSkipSubtree;
}
uint32_t
+13 -28
View File
@@ -218,7 +218,7 @@ FocusManager::DispatchFocusEvent(DocAccessible* aDocument,
{
NS_PRECONDITION(aDocument, "No document for focused accessible!");
if (aDocument) {
nsRefPtr<AccEvent> event =
RefPtr<AccEvent> event =
new AccEvent(nsIAccessibleEvent::EVENT_FOCUS, aTarget,
eAutoDetect, AccEvent::eCoalesceOfSameType);
aDocument->FireDelayedEvent(event);
@@ -299,39 +299,24 @@ FocusManager::ProcessFocusEvent(AccEvent* aEvent)
// Fire menu start/end events for ARIA menus.
if (target->IsARIARole(nsGkAtoms::menuitem)) {
// The focus was moved into menu.
bool tryOwnsParent = true;
Accessible* ARIAMenubar = nullptr;
Accessible* child = target;
Accessible* parent = child->Parent();
while (parent) {
nsRoleMapEntry* roleMap = parent->ARIARoleMap();
if (roleMap) {
if (roleMap->Is(nsGkAtoms::menubar)) {
ARIAMenubar = parent;
break;
}
// Go up in the parent chain of the menu hierarchy.
if (roleMap->Is(nsGkAtoms::menuitem) || roleMap->Is(nsGkAtoms::menu)) {
child = parent;
parent = child->Parent();
tryOwnsParent = true;
continue;
}
for (Accessible* parent = target->Parent(); parent; parent = parent->Parent()) {
if (parent->IsARIARole(nsGkAtoms::menubar)) {
ARIAMenubar = parent;
break;
}
// If no required context role then check aria-owns relation.
if (!tryOwnsParent)
// Go up in the parent chain of the menu hierarchy.
if (!parent->IsARIARole(nsGkAtoms::menuitem) &&
!parent->IsARIARole(nsGkAtoms::menu)) {
break;
parent = ARIAOwnedByIterator(child).Next();
tryOwnsParent = false;
}
}
if (ARIAMenubar != mActiveARIAMenubar) {
// Leaving ARIA menu. Fire menu_end event on current menubar.
if (mActiveARIAMenubar) {
nsRefPtr<AccEvent> menuEndEvent =
RefPtr<AccEvent> menuEndEvent =
new AccEvent(nsIAccessibleEvent::EVENT_MENU_END, mActiveARIAMenubar,
aEvent->FromUserInput());
nsEventShell::FireEvent(menuEndEvent);
@@ -341,7 +326,7 @@ FocusManager::ProcessFocusEvent(AccEvent* aEvent)
// Entering ARIA menu. Fire menu_start event.
if (mActiveARIAMenubar) {
nsRefPtr<AccEvent> menuStartEvent =
RefPtr<AccEvent> menuStartEvent =
new AccEvent(nsIAccessibleEvent::EVENT_MENU_START,
mActiveARIAMenubar, aEvent->FromUserInput());
nsEventShell::FireEvent(menuStartEvent);
@@ -349,7 +334,7 @@ FocusManager::ProcessFocusEvent(AccEvent* aEvent)
}
} else if (mActiveARIAMenubar) {
// Focus left a menu. Fire menu_end event.
nsRefPtr<AccEvent> menuEndEvent =
RefPtr<AccEvent> menuEndEvent =
new AccEvent(nsIAccessibleEvent::EVENT_MENU_END, mActiveARIAMenubar,
aEvent->FromUserInput());
nsEventShell::FireEvent(menuEndEvent);
@@ -367,7 +352,7 @@ FocusManager::ProcessFocusEvent(AccEvent* aEvent)
// offset before the caret move event is handled.
SelectionMgr()->ResetCaretOffset();
nsRefPtr<AccEvent> focusEvent =
RefPtr<AccEvent> focusEvent =
new AccEvent(nsIAccessibleEvent::EVENT_FOCUS, target, aEvent->FromUserInput());
nsEventShell::FireEvent(focusEvent);
+2 -2
View File
@@ -124,8 +124,8 @@ private:
nsIDocument* FocusedDOMDocument() const;
private:
nsRefPtr<Accessible> mActiveItem;
nsRefPtr<Accessible> mActiveARIAMenubar;
RefPtr<Accessible> mActiveItem;
RefPtr<Accessible> mActiveARIAMenubar;
};
} // namespace a11y
+12 -16
View File
@@ -103,6 +103,10 @@ MARKUPMAP(li,
New_HTMLListitem,
0)
MARKUPMAP(map,
nullptr,
roles::TEXT_CONTAINER)
MARKUPMAP(math,
New_HyperText,
roles::MATHML_MATH)
@@ -205,22 +209,22 @@ MARKUPMAP(mmultiscripts_,
roles::MATHML_MULTISCRIPTS)
MARKUPMAP(mtable_,
New_HyperText,
New_HTMLTableAccessible,
roles::MATHML_TABLE,
AttrFromDOM(align, align),
AttrFromDOM(columnlines_, columnlines_),
AttrFromDOM(rowlines_, rowlines_))
MARKUPMAP(mlabeledtr_,
New_HyperText,
New_HTMLTableRowAccessible,
roles::MATHML_LABELED_ROW)
MARKUPMAP(mtr_,
New_HyperText,
New_HTMLTableRowAccessible,
roles::MATHML_TABLE_ROW)
MARKUPMAP(mtd_,
New_HyperText,
New_HTMLTableCellAccessible,
roles::MATHML_CELL)
MARKUPMAP(maction_,
@@ -233,18 +237,6 @@ MARKUPMAP(merror_,
New_HyperText,
roles::MATHML_ERROR)
MARKUPMAP(semantics_,
New_HyperText,
roles::MATHML_SEMANTICS)
MARKUPMAP(annotation_,
New_HyperText,
roles::MATHML_ANNOTATION)
MARKUPMAP(annotation_xml_,
New_HyperText,
roles::MATHML_XML_ANNOTATION)
MARKUPMAP(mstack_,
New_HyperText,
roles::MATHML_STACK,
@@ -304,6 +296,10 @@ MARKUPMAP(output,
roles::SECTION,
Attr(live, polite))
MARKUPMAP(p,
nullptr,
roles::PARAGRAPH)
MARKUPMAP(progress,
New_HTMLProgress,
0)
+23 -8
View File
@@ -54,6 +54,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(NotificationController)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mHangingChildDocuments)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContentInsertions)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvents)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRelocations)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(NotificationController, AddRef)
@@ -86,6 +87,7 @@ NotificationController::Shutdown()
mContentInsertions.Clear();
mNotifications.Clear();
mEvents.Clear();
mRelocations.Clear();
}
void
@@ -101,7 +103,7 @@ NotificationController::ScheduleContentInsertion(Accessible* aContainer,
nsIContent* aStartChildNode,
nsIContent* aEndChildNode)
{
nsRefPtr<ContentInsertion> insertion = new ContentInsertion(mDocument,
RefPtr<ContentInsertion> insertion = new ContentInsertion(mDocument,
aContainer);
if (insertion && insertion->InitChildList(aStartChildNode, aEndChildNode) &&
mContentInsertions.AppendElement(insertion)) {
@@ -109,9 +111,6 @@ NotificationController::ScheduleContentInsertion(Accessible* aContainer,
}
}
////////////////////////////////////////////////////////////////////////////////
// NotificationCollector: protected
void
NotificationController::ScheduleProcessing()
{
@@ -123,6 +122,9 @@ NotificationController::ScheduleProcessing()
}
}
////////////////////////////////////////////////////////////////////////////////
// NotificationCollector: protected
bool
NotificationController::IsUpdatePending()
{
@@ -139,6 +141,7 @@ NotificationController::IsUpdatePending()
void
NotificationController::WillRefresh(mozilla::TimeStamp aTime)
{
PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER);
Telemetry::AutoTimer<Telemetry::A11Y_UPDATE_TIME> updateTimer;
// If the document accessible that notification collector was created for is
@@ -193,7 +196,7 @@ NotificationController::WillRefresh(mozilla::TimeStamp aTime)
// document accessible.
// Process only currently queued content inserted notifications.
nsTArray<nsRefPtr<ContentInsertion> > contentInsertions;
nsTArray<RefPtr<ContentInsertion> > contentInsertions;
contentInsertions.SwapElements(mContentInsertions);
uint32_t insertionCount = contentInsertions.Length();
@@ -228,7 +231,9 @@ NotificationController::WillRefresh(mozilla::TimeStamp aTime)
nsIContent* containerElm = containerNode->IsElement() ?
containerNode->AsElement() : nullptr;
nsIFrame::RenderedText text = textFrame->GetRenderedText();
nsIFrame::RenderedText text = textFrame->GetRenderedText(0,
UINT32_MAX, nsIFrame::TextOffsetType::OFFSETS_IN_CONTENT_TEXT,
nsIFrame::TrailingWhitespace::DONT_TRIM_TRAILING_WHITESPACE);
// Remove text accessible if rendered text is empty.
if (textAcc) {
@@ -290,7 +295,7 @@ NotificationController::WillRefresh(mozilla::TimeStamp aTime)
// Bind hanging child documents.
uint32_t hangingDocCnt = mHangingChildDocuments.Length();
nsTArray<nsRefPtr<DocAccessible>> newChildDocs;
nsTArray<RefPtr<DocAccessible>> newChildDocs;
for (uint32_t idx = 0; idx < hangingDocCnt; idx++) {
DocAccessible* childDoc = mHangingChildDocuments[idx];
if (childDoc->IsDefunct())
@@ -336,7 +341,7 @@ NotificationController::WillRefresh(mozilla::TimeStamp aTime)
}
// Process only currently queued generic notifications.
nsTArray < nsRefPtr<Notification> > notifications;
nsTArray < RefPtr<Notification> > notifications;
notifications.SwapElements(mNotifications);
uint32_t notificationCount = notifications.Length();
@@ -350,6 +355,16 @@ NotificationController::WillRefresh(mozilla::TimeStamp aTime)
// modification are done.
mDocument->ProcessInvalidationList();
// We cannot rely on DOM tree to keep aria-owns relations updated. Make
// a validation to remove dead links.
mDocument->ValidateARIAOwned();
// Process relocation list.
for (uint32_t idx = 0; idx < mRelocations.Length(); idx++) {
mDocument->DoARIAOwnsRelocation(mRelocations[idx]);
}
mRelocations.Clear();
// If a generic notification occurs after this point then we may be allowed to
// process it synchronously. However we do not want to reenter if fireing
// events causes script to run.
+46 -30
View File
@@ -8,6 +8,8 @@
#include "EventQueue.h"
#include "mozilla/IndexSequence.h"
#include "mozilla/Tuple.h"
#include "nsCycleCollectionParticipant.h"
#include "nsRefreshDriver.h"
@@ -54,32 +56,32 @@ private:
* longer than the document accessible owning the notification controller
* that this notification is processed by.
*/
template<class Class, class Arg>
template<class Class, class ... Args>
class TNotification : public Notification
{
public:
typedef void (Class::*Callback)(Arg*);
typedef void (Class::*Callback)(Args* ...);
TNotification(Class* aInstance, Callback aCallback, Arg* aArg) :
mInstance(aInstance), mCallback(aCallback), mArg(aArg) { }
TNotification(Class* aInstance, Callback aCallback, Args* ... aArgs) :
mInstance(aInstance), mCallback(aCallback), mArgs(aArgs...) { }
virtual ~TNotification() { mInstance = nullptr; }
virtual void Process() override
{
(mInstance->*mCallback)(mArg);
mInstance = nullptr;
mCallback = nullptr;
mArg = nullptr;
}
{ ProcessHelper(typename IndexSequenceFor<Args...>::Type()); }
private:
TNotification(const TNotification&);
TNotification& operator = (const TNotification&);
template <size_t... Indices>
void ProcessHelper(IndexSequence<Indices...>)
{
(mInstance->*mCallback)(Get<Indices>(mArgs)...);
}
Class* mInstance;
Callback mCallback;
nsRefPtr<Arg> mArg;
Tuple<RefPtr<Args> ...> mArgs;
};
/**
@@ -131,6 +133,22 @@ public:
nsIContent* aStartChildNode,
nsIContent* aEndChildNode);
/**
* Pend an accessible subtree relocation.
*/
void ScheduleRelocation(Accessible* aOwner)
{
if (!mRelocations.Contains(aOwner) && mRelocations.AppendElement(aOwner)) {
ScheduleProcessing();
}
}
/**
* Start to observe refresh to make notifications and events processing after
* layout.
*/
void ScheduleProcessing();
/**
* Process the generic notification synchronously if there are no pending
* layout changes and no notifications are pending or being processed right
@@ -153,7 +171,7 @@ public:
return;
}
nsRefPtr<Notification> notification =
RefPtr<Notification> notification =
new TNotification<Class, Arg>(aInstance, aMethod, aArg);
if (notification && mNotifications.AppendElement(notification))
ScheduleProcessing();
@@ -165,13 +183,12 @@ public:
* @note The caller must guarantee that the given instance still exists when
* the notification is processed.
*/
template<class Class, class Arg>
template<class Class>
inline void ScheduleNotification(Class* aInstance,
typename TNotification<Class, Arg>::Callback aMethod,
Arg* aArg)
typename TNotification<Class>::Callback aMethod)
{
nsRefPtr<Notification> notification =
new TNotification<Class, Arg>(aInstance, aMethod, aArg);
RefPtr<Notification> notification =
new TNotification<Class>(aInstance, aMethod);
if (notification && mNotifications.AppendElement(notification))
ScheduleProcessing();
}
@@ -187,12 +204,6 @@ protected:
nsCycleCollectingAutoRefCnt mRefCnt;
NS_DECL_OWNINGTHREAD
/**
* Start to observe refresh to make notifications and events processing after
* layout.
*/
void ScheduleProcessing();
/**
* Return true if the accessible tree state update is pending.
*/
@@ -226,7 +237,7 @@ private:
/**
* Child documents that needs to be bound to the tree.
*/
nsTArray<nsRefPtr<DocAccessible> > mHangingChildDocuments;
nsTArray<RefPtr<DocAccessible> > mHangingChildDocuments;
/**
* Storage for content inserted notification information.
@@ -256,7 +267,7 @@ private:
DocAccessible* mDocument;
// The container accessible that content insertion occurs within.
nsRefPtr<Accessible> mContainer;
RefPtr<Accessible> mContainer;
// Array of inserted contents.
nsTArray<nsCOMPtr<nsIContent> > mInsertedContent;
@@ -264,9 +275,9 @@ private:
/**
* A pending accessible tree update notifications for content insertions.
* Don't make this an nsAutoTArray; we use SwapElements() on it.
* Don't make this an AutoTArray; we use SwapElements() on it.
*/
nsTArray<nsRefPtr<ContentInsertion> > mContentInsertions;
nsTArray<RefPtr<ContentInsertion> > mContentInsertions;
template<class T>
class nsCOMPtrHashKey : public PLDHashEntryHdr
@@ -298,10 +309,15 @@ private:
nsTHashtable<nsCOMPtrHashKey<nsIContent> > mTextHash;
/**
* Other notifications like DOM events. Don't make this an nsAutoTArray; we
* Other notifications like DOM events. Don't make this an AutoTArray; we
* use SwapElements() on it.
*/
nsTArray<nsRefPtr<Notification> > mNotifications;
nsTArray<RefPtr<Notification> > mNotifications;
/**
* Holds all scheduled relocations.
*/
nsTArray<RefPtr<Accessible> > mRelocations;
};
} // namespace a11y
+8
View File
@@ -6,6 +6,8 @@
#include <stdint.h>
class nsString;
namespace mozilla {
namespace a11y {
@@ -67,6 +69,12 @@ void ProxyDestroyed(ProxyAccessible*);
* Callied when an event is fired on a proxied accessible.
*/
void ProxyEvent(ProxyAccessible* aTarget, uint32_t aEventType);
void ProxyStateChangeEvent(ProxyAccessible* aTarget, uint64_t aState,
bool aEnabled);
void ProxyCaretMoveEvent(ProxyAccessible* aTarget, int32_t aOffset);
void ProxyTextChangeEvent(ProxyAccessible* aTarget, const nsString& aStr,
int32_t aStart, uint32_t aLen, bool aIsInsert,
bool aFromUser);
} // namespace a11y
} // namespace mozilla
+19 -23
View File
@@ -926,57 +926,53 @@ enum Role {
*/
MATHML_ERROR = 157,
/**
* A MathML semantics annotation element (semantics in MathML).
*/
MATHML_SEMANTICS = 158,
/**
* A MathML annotation (annotation in MathML).
*/
MATHML_ANNOTATION = 159,
/**
* A MathML XML annotation (annotation-xml in MathML).
*/
MATHML_XML_ANNOTATION = 160,
/**
* A MathML stacked (rows of numbers) element (mstack in MathML).
*/
MATHML_STACK = 161,
MATHML_STACK = 158,
/**
* A MathML long division element (mlongdiv in MathML).
*/
MATHML_LONG_DIVISION = 162,
MATHML_LONG_DIVISION = 159,
/**
* A MathML stack group (msgroup in MathML).
*/
MATHML_STACK_GROUP = 163,
MATHML_STACK_GROUP = 160,
/**
* A MathML stack row (msrow in MathML).
*/
MATHML_STACK_ROW = 164,
MATHML_STACK_ROW = 161,
/**
* MathML carries, borrows, or crossouts for a row (mscarries in MathML).
*/
MATHML_STACK_CARRIES = 165,
MATHML_STACK_CARRIES = 162,
/**
* A MathML carry, borrow, or crossout for a column (mscarry in MathML).
*/
MATHML_STACK_CARRY = 166,
MATHML_STACK_CARRY = 163,
/**
* A MathML line in a stack (msline in MathML).
*/
MATHML_STACK_LINE = 167,
MATHML_STACK_LINE = 164,
LAST_ROLE = MATHML_STACK_LINE
/**
* A group containing radio buttons
*/
RADIO_GROUP = 165,
/**
* A text container exposing brief amount of information. See related
* TEXT_CONTAINER role.
*/
TEXT = 166,
LAST_ROLE = TEXT
};
} // namespace role
+38 -45
View File
@@ -74,7 +74,7 @@ ROLE(CARET,
ROLE(ALERT,
"alert",
ATK_ROLE_ALERT,
NSAccessibilityWindowRole,
NSAccessibilityGroupRole,
ROLE_SYSTEM_ALERT,
ROLE_SYSTEM_ALERT,
eNoNameRule)
@@ -187,7 +187,7 @@ ROLE(GROUPING,
ROLE(SEPARATOR,
"separator",
ATK_ROLE_SEPARATOR,
NSAccessibilityUnknownRole,
NSAccessibilitySplitterRole,
ROLE_SYSTEM_SEPARATOR,
ROLE_SYSTEM_SEPARATOR,
eNoNameRule)
@@ -211,7 +211,7 @@ ROLE(STATUSBAR,
ROLE(TABLE,
"table",
ATK_ROLE_TABLE,
NSAccessibilityGroupRole,
NSAccessibilityTableRole,
ROLE_SYSTEM_TABLE,
ROLE_SYSTEM_TABLE,
eNoNameRule)
@@ -219,7 +219,7 @@ ROLE(TABLE,
ROLE(COLUMNHEADER,
"columnheader",
ATK_ROLE_COLUMN_HEADER,
NSAccessibilityGroupRole,
NSAccessibilityCellRole,
ROLE_SYSTEM_COLUMNHEADER,
ROLE_SYSTEM_COLUMNHEADER,
eNameFromSubtreeRule)
@@ -227,7 +227,7 @@ ROLE(COLUMNHEADER,
ROLE(ROWHEADER,
"rowheader",
ATK_ROLE_ROW_HEADER,
NSAccessibilityGroupRole,
NSAccessibilityCellRole,
ROLE_SYSTEM_ROWHEADER,
ROLE_SYSTEM_ROWHEADER,
eNameFromSubtreeRule)
@@ -251,7 +251,7 @@ ROLE(ROW,
ROLE(CELL,
"cell",
ATK_ROLE_TABLE_CELL,
NSAccessibilityGroupRole,
NSAccessibilityCellRole,
ROLE_SYSTEM_CELL,
ROLE_SYSTEM_CELL,
eNameFromSubtreeIfReqRule)
@@ -754,7 +754,7 @@ ROLE(TERMINAL,
ROLE(TEXT_CONTAINER,
"text container",
ATK_ROLE_TEXT,
ATK_ROLE_SECTION,
NSAccessibilityGroupRole,
USE_ROLE_STRING,
IA2_ROLE_TEXT_FRAME,
@@ -955,7 +955,7 @@ ROLE(IMAGE_MAP,
ROLE(OPTION,
"listbox option",
ATK_ROLE_LIST_ITEM,
NSAccessibilityRowRole,
NSAccessibilityStaticTextRole,
ROLE_SYSTEM_LISTITEM,
ROLE_SYSTEM_LISTITEM,
eNameFromSubtreeRule)
@@ -1122,7 +1122,7 @@ ROLE(MATHML_GLYPH,
ROLE(MATHML_ROW,
"mathml row",
ATK_ROLE_PANEL,
ATK_ROLE_SECTION,
NSAccessibilityGroupRole,
0,
IA2_ROLE_UNKNOWN,
@@ -1154,7 +1154,7 @@ ROLE(MATHML_ROOT,
ROLE(MATHML_FENCED,
"mathml fenced",
ATK_ROLE_PANEL,
ATK_ROLE_SECTION,
NSAccessibilityGroupRole,
0,
IA2_ROLE_UNKNOWN,
@@ -1162,7 +1162,7 @@ ROLE(MATHML_FENCED,
ROLE(MATHML_ENCLOSED,
"mathml enclosed",
ATK_ROLE_PANEL,
ATK_ROLE_SECTION,
NSAccessibilityGroupRole,
0,
IA2_ROLE_UNKNOWN,
@@ -1170,7 +1170,7 @@ ROLE(MATHML_ENCLOSED,
ROLE(MATHML_STYLE,
"mathml style",
ATK_ROLE_PANEL,
ATK_ROLE_SECTION,
NSAccessibilityGroupRole,
0,
IA2_ROLE_UNKNOWN,
@@ -1178,7 +1178,7 @@ ROLE(MATHML_STYLE,
ROLE(MATHML_SUB,
"mathml sub",
ATK_ROLE_UNKNOWN,
ATK_ROLE_SECTION,
NSAccessibilityGroupRole,
0,
IA2_ROLE_UNKNOWN,
@@ -1186,7 +1186,7 @@ ROLE(MATHML_SUB,
ROLE(MATHML_SUP,
"mathml sup",
ATK_ROLE_UNKNOWN,
ATK_ROLE_SECTION,
NSAccessibilityGroupRole,
0,
IA2_ROLE_UNKNOWN,
@@ -1194,7 +1194,7 @@ ROLE(MATHML_SUP,
ROLE(MATHML_SUB_SUP,
"mathml sub sup",
ATK_ROLE_UNKNOWN,
ATK_ROLE_SECTION,
NSAccessibilityGroupRole,
0,
IA2_ROLE_UNKNOWN,
@@ -1202,7 +1202,7 @@ ROLE(MATHML_SUB_SUP,
ROLE(MATHML_UNDER,
"mathml under",
ATK_ROLE_UNKNOWN,
ATK_ROLE_SECTION,
NSAccessibilityGroupRole,
0,
IA2_ROLE_UNKNOWN,
@@ -1210,7 +1210,7 @@ ROLE(MATHML_UNDER,
ROLE(MATHML_OVER,
"mathml over",
ATK_ROLE_UNKNOWN,
ATK_ROLE_SECTION,
NSAccessibilityGroupRole,
0,
IA2_ROLE_UNKNOWN,
@@ -1218,7 +1218,7 @@ ROLE(MATHML_OVER,
ROLE(MATHML_UNDER_OVER,
"mathml under over",
ATK_ROLE_UNKNOWN,
ATK_ROLE_SECTION,
NSAccessibilityGroupRole,
0,
IA2_ROLE_UNKNOWN,
@@ -1226,7 +1226,7 @@ ROLE(MATHML_UNDER_OVER,
ROLE(MATHML_MULTISCRIPTS,
"mathml multiscripts",
ATK_ROLE_UNKNOWN,
ATK_ROLE_SECTION,
NSAccessibilityGroupRole,
0,
IA2_ROLE_UNKNOWN,
@@ -1266,7 +1266,7 @@ ROLE(MATHML_CELL,
ROLE(MATHML_ACTION,
"mathml action",
ATK_ROLE_UNKNOWN,
ATK_ROLE_SECTION,
NSAccessibilityGroupRole,
0,
IA2_ROLE_UNKNOWN,
@@ -1274,36 +1274,12 @@ ROLE(MATHML_ACTION,
ROLE(MATHML_ERROR,
"mathml error",
ATK_ROLE_PANEL,
ATK_ROLE_SECTION,
NSAccessibilityGroupRole,
0,
IA2_ROLE_UNKNOWN,
eNoNameRule)
ROLE(MATHML_SEMANTICS,
"mathml semantics",
ATK_ROLE_UNKNOWN,
NSAccessibilityUnknownRole,
0,
IA2_ROLE_UNKNOWN,
eNoNameRule)
ROLE(MATHML_ANNOTATION,
"mathml annotation",
ATK_ROLE_UNKNOWN,
NSAccessibilityUnknownRole,
0,
IA2_ROLE_UNKNOWN,
eNoNameRule)
ROLE(MATHML_XML_ANNOTATION,
"mathml xml annotation",
ATK_ROLE_UNKNOWN,
NSAccessibilityUnknownRole,
0,
IA2_ROLE_UNKNOWN,
eNoNameRule)
ROLE(MATHML_STACK,
"mathml stack",
ATK_ROLE_UNKNOWN,
@@ -1359,3 +1335,20 @@ ROLE(MATHML_STACK_LINE,
0,
IA2_ROLE_UNKNOWN,
eNoNameRule)
ROLE(RADIO_GROUP,
"grouping",
ATK_ROLE_PANEL,
NSAccessibilityRadioGroupRole,
ROLE_SYSTEM_GROUPING,
ROLE_SYSTEM_GROUPING,
eNoNameRule)
ROLE(TEXT,
"text",
ATK_ROLE_STATIC,
NSAccessibilityGroupRole,
USE_ROLE_STRING,
IA2_ROLE_TEXT_FRAME,
eNameFromSubtreeIfReqRule)
+4 -4
View File
@@ -29,7 +29,7 @@ struct mozilla::a11y::SelData final
SelData(Selection* aSel, int32_t aReason) :
mSel(aSel), mReason(aReason) {}
nsRefPtr<Selection> mSel;
RefPtr<Selection> mSel;
int16_t mReason;
NS_INLINE_DECL_REFCOUNTING(SelData)
@@ -159,7 +159,7 @@ SelectionManager::ProcessTextSelChangeEvent(AccEvent* aEvent)
selection->FocusOffset());
mAccWithCaret = caretCntr;
if (mCaretOffset != -1) {
nsRefPtr<AccCaretMoveEvent> caretMoveEvent =
RefPtr<AccCaretMoveEvent> caretMoveEvent =
new AccCaretMoveEvent(caretCntr, mCaretOffset, aEvent->FromUserInput());
nsEventShell::FireEvent(caretMoveEvent);
}
@@ -184,7 +184,7 @@ SelectionManager::NotifySelectionChanged(nsIDOMDocument* aDOMDocument,
// Selection manager has longer lifetime than any document accessible,
// so that we are guaranteed that the notification is processed before
// the selection manager is destroyed.
nsRefPtr<SelData> selData =
RefPtr<SelData> selData =
new SelData(static_cast<Selection*>(aSelection), aReason);
document->HandleNotification<SelectionManager, SelData>
(this, &SelectionManager::ProcessSelectionChanged, selData);
@@ -221,7 +221,7 @@ SelectionManager::ProcessSelectionChanged(SelData* aSelData)
}
if (selection->GetType() == nsISelectionController::SELECTION_NORMAL) {
nsRefPtr<AccEvent> event =
RefPtr<AccEvent> event =
new AccTextSelChangeEvent(text, selection, aSelData->mReason);
text->Document()->FireDelayedEvent(event);
+1 -1
View File
@@ -39,7 +39,7 @@ private:
void Margin(Side aSide, nsAString& aValue);
dom::Element* mElement;
nsRefPtr<nsStyleContext> mStyleContext;
RefPtr<nsStyleContext> mStyleContext;
};
} // namespace a11y
+2 -2
View File
@@ -460,7 +460,7 @@ bool
TextAttrsMgr::FontFamilyTextAttr::
GetFontFamily(nsIFrame* aFrame, nsString& aFamily)
{
nsRefPtr<nsFontMetrics> fm;
RefPtr<nsFontMetrics> fm;
nsLayoutUtils::GetFontMetricsForFrame(aFrame, getter_AddRefs(fm));
gfxFontGroup* fontGroup = fm->GetThebesFontGroup();
@@ -618,7 +618,7 @@ TextAttrsMgr::FontWeightTextAttr::
{
// nsFont::width isn't suitable here because it's necessary to expose real
// value of font weight (used font might not have some font weight values).
nsRefPtr<nsFontMetrics> fm;
RefPtr<nsFontMetrics> fm;
nsLayoutUtils::GetFontMetricsForFrame(aFrame, getter_AddRefs(fm));
gfxFontGroup *fontGroup = fm->GetThebesFontGroup();
+29
View File
@@ -0,0 +1,29 @@
/* -*- 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_TextRange_inl_h__
#define mozilla_a11y_TextRange_inl_h__
#include "TextRange.h"
#include "HyperTextAccessible.h"
namespace mozilla {
namespace a11y {
inline Accessible*
TextRange::Container() const
{
uint32_t pos1 = 0, pos2 = 0;
AutoTArray<Accessible*, 30> parents1, parents2;
return CommonParent(mStartContainer, mEndContainer,
&parents1, &pos1, &parents2, &pos2);
}
} // namespace a11y
} // namespace mozilla
#endif
+136 -60
View File
@@ -4,10 +4,9 @@
* 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 "TextRange.h"
#include "TextRange-inl.h"
#include "Accessible-inl.h"
#include "HyperTextAccessible.h"
#include "nsAccUtils.h"
namespace mozilla {
@@ -25,7 +24,7 @@ TextPoint::operator <(const TextPoint& aPoint) const
// Build the chain of parents
Accessible* p1 = mContainer;
Accessible* p2 = aPoint.mContainer;
nsAutoTArray<Accessible*, 30> parents1, parents2;
AutoTArray<Accessible*, 30> parents1, parents2;
do {
parents1.AppendElement(p1);
p1 = p1->Parent();
@@ -59,42 +58,6 @@ TextRange::TextRange(HyperTextAccessible* aRoot,
{
}
Accessible*
TextRange::Container() const
{
if (mStartContainer == mEndContainer)
return mStartContainer;
// Build the chain of parents
Accessible* p1 = mStartContainer;
Accessible* p2 = mEndContainer;
nsAutoTArray<Accessible*, 30> parents1, parents2;
do {
parents1.AppendElement(p1);
p1 = p1->Parent();
} while (p1);
do {
parents2.AppendElement(p2);
p2 = p2->Parent();
} while (p2);
// Find where the parent chain differs
uint32_t pos1 = parents1.Length();
uint32_t pos2 = parents2.Length();
Accessible* parent = nullptr;
uint32_t len = 0;
for (len = std::min(pos1, pos2); len > 0; --len) {
Accessible* child1 = parents1.ElementAt(--pos1);
Accessible* child2 = parents2.ElementAt(--pos2);
if (child1 != child2)
break;
parent = child1;
}
return parent;
}
void
TextRange::EmbeddedChildren(nsTArray<Accessible*>* aChildren) const
{
@@ -111,28 +74,11 @@ TextRange::EmbeddedChildren(nsTArray<Accessible*>* aChildren) const
Accessible* p1 = mStartContainer->GetChildAtOffset(mStartOffset);
Accessible* p2 = mEndContainer->GetChildAtOffset(mEndOffset);
nsAutoTArray<Accessible*, 30> parents1, parents2;
do {
parents1.AppendElement(p1);
p1 = p1->Parent();
} while (p1);
do {
parents2.AppendElement(p2);
p2 = p2->Parent();
} while (p2);
// Find deepest common container.
uint32_t pos1 = parents1.Length();
uint32_t pos2 = parents2.Length();
Accessible* container = nullptr;
for (uint32_t len = std::min(pos1, pos2); len > 0; --len) {
Accessible* child1 = parents1.ElementAt(--pos1);
Accessible* child2 = parents2.ElementAt(--pos2);
if (child1 != child2)
break;
container = child1;
}
uint32_t pos1 = 0, pos2 = 0;
AutoTArray<Accessible*, 30> parents1, parents2;
Accessible* container =
CommonParent(p1, p2, &parents1, &pos1, &parents2, &pos2);
// Traverse the tree up to the container and collect embedded objects.
for (uint32_t idx = 0; idx < pos1 - 1; idx++) {
@@ -196,6 +142,95 @@ TextRange::Normalize(ETextUnit aUnit)
}
bool
TextRange::Crop(Accessible* aContainer)
{
uint32_t boundaryPos = 0, containerPos = 0;
AutoTArray<Accessible*, 30> boundaryParents, containerParents;
// Crop the start boundary.
Accessible* container = nullptr;
Accessible* boundary = mStartContainer->GetChildAtOffset(mStartOffset);
if (boundary != aContainer) {
CommonParent(boundary, aContainer, &boundaryParents, &boundaryPos,
&containerParents, &containerPos);
if (boundaryPos == 0) {
if (containerPos != 0) {
// The container is contained by the start boundary, reduce the range to
// the point starting at the container.
aContainer->ToTextPoint(mStartContainer.StartAssignment(), &mStartOffset);
static_cast<Accessible*>(mStartContainer)->AddRef();
}
else {
// The start boundary and the container are siblings.
container = aContainer;
}
}
else if (containerPos != 0) {
// The container does not contain the start boundary.
boundary = boundaryParents[boundaryPos];
container = containerParents[containerPos];
}
if (container) {
// If the range start is after the container, then make the range invalid.
if (boundary->IndexInParent() > container->IndexInParent()) {
return !!(mRoot = nullptr);
}
// If the range starts before the container, then reduce the range to
// the point starting at the container.
if (boundary->IndexInParent() < container->IndexInParent()) {
container->ToTextPoint(mStartContainer.StartAssignment(), &mStartOffset);
mStartContainer.get()->AddRef();
}
}
boundaryParents.SetLengthAndRetainStorage(0);
containerParents.SetLengthAndRetainStorage(0);
}
boundary = mEndContainer->GetChildAtOffset(mEndOffset);
if (boundary == aContainer) {
return true;
}
// Crop the end boundary.
container = nullptr;
CommonParent(boundary, aContainer, &boundaryParents, &boundaryPos,
&containerParents, &containerPos);
if (boundaryPos == 0) {
if (containerPos != 0) {
aContainer->ToTextPoint(mEndContainer.StartAssignment(), &mEndOffset, false);
static_cast<Accessible*>(mEndContainer)->AddRef();
}
else {
container = aContainer;
}
}
else if (containerPos != 0) {
boundary = boundaryParents[boundaryPos];
container = containerParents[containerPos];
}
if (!container) {
return true;
}
if (boundary->IndexInParent() < container->IndexInParent()) {
return !!(mRoot = nullptr);
}
if (boundary->IndexInParent() > container->IndexInParent()) {
container->ToTextPoint(mEndContainer.StartAssignment(), &mEndOffset, false);
static_cast<Accessible*>(mEndContainer)->AddRef();
}
return true;
}
void
TextRange::FindText(const nsAString& aText, EDirection aDirection,
nsCaseTreatment aCaseSensitive, TextRange* aFoundRange) const
@@ -296,5 +331,46 @@ TextRange::MoveInternal(ETextUnit aUnit, int32_t aCount,
}
Accessible*
TextRange::CommonParent(Accessible* aAcc1, Accessible* aAcc2,
nsTArray<Accessible*>* aParents1, uint32_t* aPos1,
nsTArray<Accessible*>* aParents2, uint32_t* aPos2) const
{
if (aAcc1 == aAcc2) {
return aAcc1;
}
MOZ_ASSERT(aParents1->Length() == 0 || aParents2->Length() == 0,
"Wrong arguments");
// Build the chain of parents.
Accessible* p1 = aAcc1;
Accessible* p2 = aAcc2;
do {
aParents1->AppendElement(p1);
p1 = p1->Parent();
} while (p1);
do {
aParents2->AppendElement(p2);
p2 = p2->Parent();
} while (p2);
// Find where the parent chain differs
*aPos1 = aParents1->Length();
*aPos2 = aParents2->Length();
Accessible* parent = nullptr;
uint32_t len = 0;
for (len = std::min(*aPos1, *aPos2); len > 0; --len) {
Accessible* child1 = aParents1->ElementAt(--(*aPos1));
Accessible* child2 = aParents2->ElementAt(--(*aPos2));
if (child1 != child2)
break;
parent = child1;
}
return parent;
}
} // namespace a11y
} // namespace mozilla
+17 -3
View File
@@ -131,6 +131,12 @@ public:
*/
void Normalize(ETextUnit aUnit);
/**
* Crops the range if it overlaps the given accessible element boundaries,
* returns true if the range was cropped successfully.
*/
bool Crop(Accessible* aContainer);
enum EDirection {
eBackward,
eForward
@@ -243,9 +249,17 @@ private:
HyperTextAccessible* aStopContainer = nullptr,
int32_t aStopOffset = 0);
nsRefPtr<HyperTextAccessible> mRoot;
nsRefPtr<HyperTextAccessible> mStartContainer;
nsRefPtr<HyperTextAccessible> mEndContainer;
/**
* A helper method returning a common parent for two given accessible
* elements.
*/
Accessible* CommonParent(Accessible* aAcc1, Accessible* aAcc2,
nsTArray<Accessible*>* aParents1, uint32_t* aPos1,
nsTArray<Accessible*>* aParents2, uint32_t* aPos2) const;
RefPtr<HyperTextAccessible> mRoot;
RefPtr<HyperTextAccessible> mStartContainer;
RefPtr<HyperTextAccessible> mEndContainer;
int32_t mStartOffset;
int32_t mEndOffset;
};
+4 -4
View File
@@ -81,14 +81,14 @@ TextUpdater::DoUpdate(const nsAString& aNewText, const nsAString& aOldText,
strLen1 > kMaxStrLen || strLen2 > kMaxStrLen) {
if (strLen1 > 0) {
// Fire text change event for removal.
nsRefPtr<AccEvent> textRemoveEvent =
RefPtr<AccEvent> textRemoveEvent =
new AccTextChangeEvent(mHyperText, mTextOffset, str1, false);
mDocument->FireDelayedEvent(textRemoveEvent);
}
if (strLen2 > 0) {
// Fire text change event for insertion.
nsRefPtr<AccEvent> textInsertEvent =
RefPtr<AccEvent> textInsertEvent =
new AccTextChangeEvent(mHyperText, mTextOffset, str2, true);
mDocument->FireDelayedEvent(textInsertEvent);
}
@@ -129,7 +129,7 @@ TextUpdater::DoUpdate(const nsAString& aNewText, const nsAString& aOldText,
}
// Compute events based on the difference.
nsTArray<nsRefPtr<AccEvent> > events;
nsTArray<RefPtr<AccEvent> > events;
ComputeTextChangeEvents(str1, str2, entries, events);
delete [] entries;
@@ -148,7 +148,7 @@ void
TextUpdater::ComputeTextChangeEvents(const nsAString& aStr1,
const nsAString& aStr2,
uint32_t* aEntries,
nsTArray<nsRefPtr<AccEvent> >& aEvents)
nsTArray<RefPtr<AccEvent> >& aEvents)
{
int32_t colIdx = aStr1.Length(), rowIdx = aStr2.Length();
+5 -5
View File
@@ -51,15 +51,15 @@ private:
void ComputeTextChangeEvents(const nsAString& aStr1,
const nsAString& aStr2,
uint32_t* aEntries,
nsTArray<nsRefPtr<AccEvent> >& aEvents);
nsTArray<RefPtr<AccEvent> >& aEvents);
/**
* Helper to create text change events for inserted text.
*/
inline void FireInsertEvent(const nsAString& aText, uint32_t aAddlOffset,
nsTArray<nsRefPtr<AccEvent> >& aEvents)
nsTArray<RefPtr<AccEvent> >& aEvents)
{
nsRefPtr<AccEvent> event =
RefPtr<AccEvent> event =
new AccTextChangeEvent(mHyperText, mTextOffset + aAddlOffset,
aText, true);
aEvents.AppendElement(event);
@@ -69,9 +69,9 @@ private:
* Helper to create text change events for removed text.
*/
inline void FireDeleteEvent(const nsAString& aText, uint32_t aAddlOffset,
nsTArray<nsRefPtr<AccEvent> >& aEvents)
nsTArray<RefPtr<AccEvent> >& aEvents)
{
nsRefPtr<AccEvent> event =
RefPtr<AccEvent> event =
new AccTextChangeEvent(mHyperText, mTextOffset + aAddlOffset,
aText, false);
aEvents.AppendElement(event);
+56 -22
View File
@@ -6,6 +6,7 @@
#include "TreeWalker.h"
#include "Accessible.h"
#include "AccIterator.h"
#include "nsAccessibilityService.h"
#include "DocAccessible.h"
@@ -26,8 +27,8 @@ TreeWalker::
{
NS_ASSERTION(aContent, "No node for the accessible tree walker!");
mChildFilter = mContext->CanHaveAnonChildren() ?
nsIContent::eAllChildren : nsIContent::eAllButXBL;
mChildFilter = mContext->NoXBLKids() ?
nsIContent::eAllButXBL : nsIContent::eAllChildren;
mChildFilter |= nsIContent::eSkipPlaceholderContent;
if (aContent)
@@ -45,25 +46,21 @@ TreeWalker::~TreeWalker()
// TreeWalker: private
Accessible*
TreeWalker::NextChild()
TreeWalker::Next()
{
if (mStateStack.IsEmpty())
return nullptr;
dom::AllChildrenIterator* top = &mStateStack[mStateStack.Length() - 1];
ChildrenIterator* top = &mStateStack[mStateStack.Length() - 1];
while (top) {
while (nsIContent* childNode = top->GetNextChild()) {
bool isSubtreeHidden = false;
Accessible* accessible = mFlags & eWalkCache ?
mDoc->GetAccessible(childNode) :
GetAccService()->GetOrCreateAccessible(childNode, mContext,
&isSubtreeHidden);
if (accessible)
return accessible;
Accessible* child = nullptr;
bool skipSubtree = false;
while (nsIContent* childNode = Next(top, &child, &skipSubtree)) {
if (child)
return child;
// Walk down into subtree to find accessibles.
if (!isSubtreeHidden && childNode->IsElement())
if (!skipSubtree && childNode->IsElement())
top = PushState(childNode);
}
@@ -82,13 +79,10 @@ TreeWalker::NextChild()
return nullptr;
nsIContent* parent = parentNode->AsElement();
top = mStateStack.AppendElement(dom::AllChildrenIterator(parent,
mChildFilter));
while (nsIContent* childNode = top->GetNextChild()) {
if (childNode == mAnchorNode) {
mAnchorNode = parent;
return NextChild();
}
top = PushState(parent);
if (top->mDOMIter.Seek(mAnchorNode)) {
mAnchorNode = parent;
return Next();
}
// XXX We really should never get here, it means we're trying to find an
@@ -101,7 +95,47 @@ TreeWalker::NextChild()
return nullptr;
}
dom::AllChildrenIterator*
nsIContent*
TreeWalker::Next(ChildrenIterator* aIter, Accessible** aAccesible,
bool* aSkipSubtree)
{
nsIContent* childEl = aIter->mDOMIter.GetNextChild();
if (!aAccesible)
return childEl;
*aAccesible = nullptr;
*aSkipSubtree = false;
if (childEl) {
Accessible* accessible = mFlags & eWalkCache ?
mDoc->GetAccessible(childEl) :
GetAccService()->GetOrCreateAccessible(childEl, mContext, aSkipSubtree);
// Ignore the accessible and its subtree if it was repositioned by means of
// aria-owns.
if (accessible) {
if (accessible->IsRelocated()) {
*aSkipSubtree = true;
} else {
*aAccesible = accessible;
}
}
return childEl;
}
// At last iterate over ARIA owned children.
Accessible* parent = mDoc->GetAccessible(aIter->mDOMIter.Parent());
if (parent) {
Accessible* child = mDoc->ARIAOwnedAt(parent, aIter->mARIAOwnsIdx++);
if (child) {
*aAccesible = child;
return child->GetContent();
}
}
return nullptr;
}
TreeWalker::ChildrenIterator*
TreeWalker::PopState()
{
size_t length = mStateStack.Length();
+17 -7
View File
@@ -44,40 +44,50 @@ public:
~TreeWalker();
/**
* Return the next child accessible.
* Return the next accessible.
*
* @note Returned accessible is bound to the document, if the accessible is
* rejected during tree creation then the caller should be unbind it
* from the document.
*/
Accessible* NextChild();
Accessible* Next();
private:
TreeWalker();
TreeWalker(const TreeWalker&);
TreeWalker& operator =(const TreeWalker&);
struct ChildrenIterator {
ChildrenIterator(nsIContent* aNode, uint32_t aFilter) :
mDOMIter(aNode, aFilter), mARIAOwnsIdx(0) { }
dom::AllChildrenIterator mDOMIter;
uint32_t mARIAOwnsIdx;
};
nsIContent* Next(ChildrenIterator* aIter, Accessible** aAccessible = nullptr,
bool* aSkipSubtree = nullptr);
/**
* Create new state for the given node and push it on top of stack.
*
* @note State stack is used to navigate up/down the DOM subtree during
* accessible children search.
*/
dom::AllChildrenIterator* PushState(nsIContent* aContent)
ChildrenIterator* PushState(nsIContent* aContent)
{
return mStateStack.AppendElement(dom::AllChildrenIterator(aContent,
mChildFilter));
return mStateStack.AppendElement(ChildrenIterator(aContent, mChildFilter));
}
/**
* Pop state from stack.
*/
dom::AllChildrenIterator* PopState();
ChildrenIterator* PopState();
DocAccessible* mDoc;
Accessible* mContext;
nsIContent* mAnchorNode;
nsAutoTArray<dom::AllChildrenIterator, 20> mStateStack;
AutoTArray<ChildrenIterator, 20> mStateStack;
int32_t mChildFilter;
uint32_t mFlags;
};
-2
View File
@@ -97,5 +97,3 @@ if CONFIG['MOZ_ENABLE_GTK']:
CXXFLAGS += CONFIG['MOZ_CAIRO_CFLAGS']
include('/ipc/chromium/chromium-config.mozbuild')
FAIL_ON_WARNINGS = True
+17 -23
View File
@@ -12,40 +12,34 @@
// Accessible cache utils
////////////////////////////////////////////////////////////////////////////////
/**
* Shutdown and removes the accessible from cache.
*/
template <class T>
static PLDHashOperator
ClearCacheEntry(const void* aKey, nsRefPtr<T>& aAccessible, void* aUserArg)
void
UnbindCacheEntriesFromDocument(
nsRefPtrHashtable<nsPtrHashKey<const void>, T>& aCache)
{
NS_ASSERTION(aAccessible, "Calling ClearCacheEntry with a nullptr pointer!");
if (aAccessible && !aAccessible->IsDefunct())
aAccessible->Shutdown();
return PL_DHASH_REMOVE;
}
template <class T>
static PLDHashOperator
UnbindCacheEntryFromDocument(const void* aKey, nsRefPtr<T>& aAccessible,
void* aUserArg)
{
MOZ_ASSERT(aAccessible && !aAccessible->IsDefunct());
aAccessible->Document()->UnbindFromDocument(aAccessible);
return PL_DHASH_REMOVE;
for (auto iter = aCache.Iter(); !iter.Done(); iter.Next()) {
T* accessible = iter.Data();
MOZ_ASSERT(accessible && !accessible->IsDefunct());
accessible->Document()->UnbindFromDocument(accessible);
iter.Remove();
}
}
/**
* Clear the cache and shutdown the accessibles.
*/
template <class T>
static void
ClearCache(nsRefPtrHashtable<nsPtrHashKey<const void>, T>& aCache)
{
aCache.Enumerate(ClearCacheEntry<T>, nullptr);
for (auto iter = aCache.Iter(); !iter.Done(); iter.Next()) {
T* accessible = iter.Data();
MOZ_ASSERT(accessible);
if (accessible && !accessible->IsDefunct()) {
accessible->Shutdown();
}
iter.Remove();
}
}
#endif
+21
View File
@@ -242,6 +242,27 @@ nsAccUtils::IsARIASelected(Accessible* aAccessible)
nsGkAtoms::_true, eCaseMatters);
}
Accessible*
nsAccUtils::TableFor(Accessible* aRow)
{
if (aRow) {
Accessible* table = aRow->Parent();
if (table) {
roles::Role tableRole = table->Role();
if (tableRole == roles::GROUPING) { // if there's a rowgroup.
table = table->Parent();
if (table)
tableRole = table->Role();
}
return (tableRole == roles::TABLE || tableRole == roles::TREE_TABLE ||
tableRole == roles::MATHML_TABLE) ? table : nullptr;
}
}
return nullptr;
}
HyperTextAccessible*
nsAccUtils::GetTextContainer(nsINode* aNode)
{
+2
View File
@@ -134,6 +134,8 @@ public:
*/
static HyperTextAccessible* GetTextContainer(nsINode* aNode);
static Accessible* TableFor(Accessible* aRow);
/**
* Return true if the DOM node of given accessible has aria-selected="true"
* attribute.
+131 -27
View File
@@ -22,6 +22,7 @@
#include "RootAccessible.h"
#include "nsAccessiblePivot.h"
#include "nsAccUtils.h"
#include "nsArrayUtils.h"
#include "nsAttrName.h"
#include "nsEventShell.h"
#include "nsIURI.h"
@@ -52,6 +53,10 @@
#include "Logging.h"
#endif
#ifdef MOZ_CRASHREPORTER
#include "nsExceptionHandler.h"
#endif
#include "nsImageFrame.h"
#include "nsIObserverService.h"
#include "nsLayoutUtils.h"
@@ -196,6 +201,18 @@ static Accessible* New_HTMLOutput(nsIContent* aContent, Accessible* aContext)
static Accessible* New_HTMLProgress(nsIContent* aContent, Accessible* aContext)
{ return new HTMLProgressMeterAccessible(aContent, aContext->Document()); }
static Accessible*
New_HTMLTableAccessible(nsIContent* aContent, Accessible* aContext)
{ return new HTMLTableAccessible(aContent, aContext->Document()); }
static Accessible*
New_HTMLTableRowAccessible(nsIContent* aContent, Accessible* aContext)
{ return new HTMLTableRowAccessible(aContent, aContext->Document()); }
static Accessible*
New_HTMLTableCellAccessible(nsIContent* aContent, Accessible* aContext)
{ return new HTMLTableCellAccessible(aContent, aContext->Document()); }
static Accessible*
New_HTMLTableHeaderCell(nsIContent* aContent, Accessible* aContext)
{
@@ -257,6 +274,64 @@ nsAccessibilityService::~nsAccessibilityService()
gAccessibilityService = nullptr;
}
////////////////////////////////////////////////////////////////////////////////
// nsIListenerChangeListener
NS_IMETHODIMP
nsAccessibilityService::ListenersChanged(nsIArray* aEventChanges)
{
uint32_t targetCount;
nsresult rv = aEventChanges->GetLength(&targetCount);
NS_ENSURE_SUCCESS(rv, rv);
for (uint32_t i = 0 ; i < targetCount ; i++) {
nsCOMPtr<nsIEventListenerChange> change = do_QueryElementAt(aEventChanges, i);
nsCOMPtr<nsIDOMEventTarget> target;
change->GetTarget(getter_AddRefs(target));
nsCOMPtr<nsIContent> node(do_QueryInterface(target));
if (!node || !node->IsHTMLElement()) {
continue;
}
nsCOMPtr<nsIArray> listenerNames;
change->GetChangedListenerNames(getter_AddRefs(listenerNames));
uint32_t changeCount;
rv = listenerNames->GetLength(&changeCount);
NS_ENSURE_SUCCESS(rv, rv);
for (uint32_t i = 0 ; i < changeCount ; i++) {
nsCOMPtr<nsIAtom> listenerName = do_QueryElementAt(listenerNames, i);
// We are only interested in event listener changes which may
// make an element accessible or inaccessible.
if (listenerName != nsGkAtoms::onclick &&
listenerName != nsGkAtoms::onmousedown &&
listenerName != nsGkAtoms::onmouseup) {
continue;
}
nsIDocument* ownerDoc = node->OwnerDoc();
DocAccessible* document = GetExistingDocAccessible(ownerDoc);
// Always recreate for onclick changes.
if (document) {
if (nsCoreUtils::HasClickListener(node)) {
if (!document->GetAccessible(node)) {
document->RecreateAccessible(node);
}
} else {
if (document->GetAccessible(node)) {
document->RecreateAccessible(node);
}
}
break;
}
}
}
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////////
// nsISupports
@@ -265,6 +340,7 @@ NS_IMPL_ISUPPORTS_INHERITED(nsAccessibilityService,
nsIAccessibilityService,
nsIAccessibleRetrieval,
nsIObserver,
nsIListenerChangeListener,
nsISelectionListener) // from SelectionManager
////////////////////////////////////////////////////////////////////////////////
@@ -380,7 +456,7 @@ nsAccessibilityService::CreatePluginAccessible(nsPluginFrame* aFrame,
return nullptr;
#if defined(XP_WIN) || defined(MOZ_ACCESSIBILITY_ATK)
nsRefPtr<nsNPAPIPluginInstance> pluginInstance;
RefPtr<nsNPAPIPluginInstance> pluginInstance;
if (NS_SUCCEEDED(aFrame->GetPluginInstance(getter_AddRefs(pluginInstance))) &&
pluginInstance) {
#ifdef XP_WIN
@@ -388,7 +464,7 @@ nsAccessibilityService::CreatePluginAccessible(nsPluginFrame* aFrame,
(Preferences::GetBool("accessibility.delay_plugins") ||
Compatibility::IsJAWS() || Compatibility::IsWE())) {
nsCOMPtr<nsITimer> timer = do_CreateInstance(NS_TIMER_CONTRACTID);
nsRefPtr<PluginTimerCallBack> cb = new PluginTimerCallBack(aContent);
RefPtr<PluginTimerCallBack> cb = new PluginTimerCallBack(aContent);
timer->InitWithCallback(cb, Preferences::GetUint("accessibility.delay_plugin_time"),
nsITimer::TYPE_ONE_SHOT);
sPluginTimers->AppendElement(timer);
@@ -405,7 +481,7 @@ nsAccessibilityService::CreatePluginAccessible(nsPluginFrame* aFrame,
HWND pluginPort = nullptr;
aFrame->GetPluginPort(&pluginPort);
nsRefPtr<Accessible> accessible =
RefPtr<Accessible> accessible =
new HTMLWin32ObjectOwnerAccessible(aContent, aContext->Document(),
pluginPort);
return accessible.forget();
@@ -420,7 +496,7 @@ nsAccessibilityService::CreatePluginAccessible(nsPluginFrame* aFrame,
nsresult rv = pluginInstance->GetValueFromPlugin(
NPPVpluginNativeAccessibleAtkPlugId, &plugId);
if (NS_SUCCEEDED(rv) && !plugId.IsEmpty()) {
nsRefPtr<AtkSocketAccessible> socketAccessible =
RefPtr<AtkSocketAccessible> socketAccessible =
new AtkSocketAccessible(aContent, aContext->Document(), plugId);
return socketAccessible.forget();
@@ -517,9 +593,10 @@ nsAccessibilityService::ContentRemoved(nsIPresShell* aPresShell,
// accessibles in subtree then we don't care about the change.
Accessible* child = document->GetAccessible(aChildNode);
if (!child) {
a11y::TreeWalker walker(document->GetContainerAccessible(aChildNode),
aChildNode, a11y::TreeWalker::eWalkCache);
child = walker.NextChild();
Accessible* container = document->GetContainerAccessible(aChildNode);
a11y::TreeWalker walker(container ? container : document, aChildNode,
a11y::TreeWalker::eWalkCache);
child = walker.Next();
}
if (child) {
@@ -710,7 +787,7 @@ NS_IMETHODIMP
nsAccessibilityService::GetStringStates(uint32_t aState, uint32_t aExtraState,
nsISupports **aStringStates)
{
nsRefPtr<DOMStringList> stringStates = new DOMStringList();
RefPtr<DOMStringList> stringStates = new DOMStringList();
uint64_t state = nsAccUtils::To64State(aState, aExtraState);
@@ -1010,11 +1087,13 @@ nsAccessibilityService::GetOrCreateAccessible(nsINode* aNode,
#endif
// Attempt to create an accessible based on what we know.
nsRefPtr<Accessible> newAcc;
RefPtr<Accessible> newAcc;
// Create accessible for visible text frames.
if (content->IsNodeOfType(nsINode::eTEXT)) {
nsIFrame::RenderedText text = frame->GetRenderedText();
nsIFrame::RenderedText text = frame->GetRenderedText(0,
UINT32_MAX, nsIFrame::TextOffsetType::OFFSETS_IN_CONTENT_TEXT,
nsIFrame::TrailingWhitespace::DONT_TRIM_TRAILING_WHITESPACE);
// Ignore not rendered text nodes and whitespace text nodes between table
// cells.
if (text.mString.IsEmpty() ||
@@ -1074,11 +1153,12 @@ nsAccessibilityService::GetOrCreateAccessible(nsINode* aNode,
}
if (!newAcc && content->IsHTMLElement()) { // HTML accessibles
bool isARIATableOrCell = roleMapEntry &&
(roleMapEntry->accTypes & (eTableCell | eTable));
bool isARIATablePart = roleMapEntry &&
(roleMapEntry->accTypes & (eTableCell | eTableRow | eTable));
if (!isARIATableOrCell ||
if (!isARIATablePart ||
frame->AccessibleType() == eHTMLTableCellType ||
frame->AccessibleType() == eHTMLTableRowType ||
frame->AccessibleType() == eHTMLTableType) {
// Prefer to use markup to decide if and what kind of accessible to create,
const MarkupMapInfo* markupMap =
@@ -1090,13 +1170,17 @@ nsAccessibilityService::GetOrCreateAccessible(nsINode* aNode,
newAcc = CreateAccessibleByFrameType(frame, content, aContext);
}
// In case of ARIA grids use grid-specific classes if it's not native table
// based.
if (isARIATableOrCell && (!newAcc || newAcc->IsGenericHyperText())) {
// In case of ARIA grid or table use table-specific classes if it's not
// native table based.
if (isARIATablePart && (!newAcc || newAcc->IsGenericHyperText())) {
if ((roleMapEntry->accTypes & eTableCell)) {
if (aContext->IsTableRow())
newAcc = new ARIAGridCellAccessibleWrap(content, document);
} else if (roleMapEntry->IsOfType(eTableRow)) {
if (aContext->IsTable())
newAcc = new ARIARowAccessible(content, document);
} else if (roleMapEntry->IsOfType(eTable)) {
newAcc = new ARIAGridAccessibleWrap(content, document);
}
@@ -1173,12 +1257,15 @@ nsAccessibilityService::GetOrCreateAccessible(nsINode* aNode,
newAcc = markupMap->new_func(content, aContext);
// Fall back to text when encountering Content MathML.
if (!newAcc && !content->IsAnyOfMathMLElements(nsGkAtoms::mpadded_,
if (!newAcc && !content->IsAnyOfMathMLElements(nsGkAtoms::annotation_,
nsGkAtoms::annotation_xml_,
nsGkAtoms::mpadded_,
nsGkAtoms::mphantom_,
nsGkAtoms::maligngroup_,
nsGkAtoms::malignmark_,
nsGkAtoms::mspace_)) {
newAcc = new HyperTextAccessible(content, document);
nsGkAtoms::mspace_,
nsGkAtoms::semantics_)) {
newAcc = new HyperTextAccessible(content, document);
}
}
}
@@ -1232,6 +1319,14 @@ nsAccessibilityService::Init()
static const char16_t kInitIndicator[] = { '1', 0 };
observerService->NotifyObservers(nullptr, "a11y-init-or-shutdown", kInitIndicator);
// Subscribe to EventListenerService.
nsCOMPtr<nsIEventListenerService> eventListenerService =
do_GetService("@mozilla.org/eventlistenerservice;1");
if (!eventListenerService)
return false;
eventListenerService->AddListenerChangeListener(this);
for (uint32_t i = 0; i < ArrayLength(sMarkupMapList); i++)
mMarkupMaps.Put(*sMarkupMapList[i].tag, &sMarkupMapList[i]);
@@ -1246,6 +1341,12 @@ nsAccessibilityService::Init()
NS_ADDREF(gApplicationAccessible); // will release in Shutdown()
#ifdef MOZ_CRASHREPORTER
CrashReporter::
AnnotateCrashReport(NS_LITERAL_CSTRING("Accessibility"),
NS_LITERAL_CSTRING("Active"));
#endif
#ifdef XP_WIN
sPendingPlugins = new nsTArray<nsCOMPtr<nsIContent> >;
sPluginTimers = new nsTArray<nsCOMPtr<nsITimer> >;
@@ -1324,11 +1425,11 @@ nsAccessibilityService::CreateAccessibleByType(nsIContent* aContent,
return nullptr;
if (role.EqualsLiteral("outerdoc")) {
nsRefPtr<Accessible> accessible = new OuterDocAccessible(aContent, aDoc);
RefPtr<Accessible> accessible = new OuterDocAccessible(aContent, aDoc);
return accessible.forget();
}
nsRefPtr<Accessible> accessible;
RefPtr<Accessible> accessible;
#ifdef MOZ_XUL
// XUL controls
if (role.EqualsLiteral("xul:alert")) {
@@ -1500,7 +1601,7 @@ nsAccessibilityService::CreateAccessibleByFrameType(nsIFrame* aFrame,
{
DocAccessible* document = aContext->Document();
nsRefPtr<Accessible> newAcc;
RefPtr<Accessible> newAcc;
switch (aFrame->AccessibleType()) {
case eNoType:
return nullptr;
@@ -1562,7 +1663,10 @@ nsAccessibilityService::CreateAccessibleByFrameType(nsIFrame* aFrame,
newAcc = new HTMLSpinnerAccessible(aContent, document);
break;
case eHTMLTableType:
newAcc = new HTMLTableAccessibleWrap(aContent, document);
if (aContent->IsHTMLElement(nsGkAtoms::table))
newAcc = new HTMLTableAccessibleWrap(aContent, document);
else
newAcc = new HyperTextAccessibleWrap(aContent, document);
break;
case eHTMLTableCellType:
// Accessible HTML table cell should be a child of accessible HTML table
@@ -1727,7 +1831,7 @@ NS_GetAccessibilityService(nsIAccessibilityService** aResult)
return NS_OK;
}
nsRefPtr<nsAccessibilityService> service = new nsAccessibilityService();
RefPtr<nsAccessibilityService> service = new nsAccessibilityService();
NS_ENSURE_TRUE(service, NS_ERROR_OUT_OF_MEMORY);
if (!service->Init()) {
@@ -1760,19 +1864,19 @@ nsAccessibilityService::CreateAccessibleForXULTree(nsIContent* aContent,
if (!treeFrame)
return nullptr;
nsRefPtr<nsTreeColumns> treeCols = treeFrame->Columns();
RefPtr<nsTreeColumns> treeCols = treeFrame->Columns();
int32_t count = 0;
treeCols->GetCount(&count);
// Outline of list accessible.
if (count == 1) {
nsRefPtr<Accessible> accessible =
RefPtr<Accessible> accessible =
new XULTreeAccessible(aContent, aDoc, treeFrame);
return accessible.forget();
}
// Table or tree table accessible.
nsRefPtr<Accessible> accessible =
RefPtr<Accessible> accessible =
new XULTreeGridAccessibleWrap(aContent, aDoc, treeFrame);
return accessible.forget();
}
+8 -1
View File
@@ -15,8 +15,10 @@
#include "mozilla/Preferences.h"
#include "nsIObserver.h"
#include "nsIEventListenerService.h"
class nsImageFrame;
class nsIArray;
class nsIPersistentProperties;
class nsPluginFrame;
class nsITreeView;
@@ -67,12 +69,16 @@ class nsAccessibilityService final : public mozilla::a11y::DocManager,
public mozilla::a11y::FocusManager,
public mozilla::a11y::SelectionManager,
public nsIAccessibilityService,
public nsIListenerChangeListener,
public nsIObserver
{
public:
typedef mozilla::a11y::Accessible Accessible;
typedef mozilla::a11y::DocAccessible DocAccessible;
// nsIListenerChangeListener
NS_IMETHOD ListenersChanged(nsIArray* aEventChanges) override;
protected:
virtual ~nsAccessibilityService();
@@ -378,7 +384,8 @@ static const char kEventTypeNames[][40] = {
"hypertext changed", // EVENT_HYPERTEXT_CHANGED
"hypertext links count changed", // EVENT_HYPERTEXT_NLINKS_CHANGED
"object attribute changed", // EVENT_OBJECT_ATTRIBUTE_CHANGED
"virtual cursor changed" // EVENT_VIRTUALCURSOR_CHANGED
"virtual cursor changed", // EVENT_VIRTUALCURSOR_CHANGED
"text value change", // EVENT_TEXT_VALUE_CHANGE
};
#endif /* __nsIAccessibilityService_h__ */
+3 -3
View File
@@ -89,7 +89,7 @@ nsAccessiblePivot::GetPosition(nsIAccessible** aPosition)
NS_IMETHODIMP
nsAccessiblePivot::SetPosition(nsIAccessible* aPosition)
{
nsRefPtr<Accessible> position = nullptr;
RefPtr<Accessible> position = nullptr;
if (aPosition) {
position = aPosition->ToInternalAccessible();
@@ -168,7 +168,7 @@ nsAccessiblePivot::SetTextRange(nsIAccessibleText* aTextAccessible,
nsCOMPtr<nsIAccessible> xpcAcc = do_QueryInterface(aTextAccessible);
NS_ENSURE_ARG(xpcAcc);
nsRefPtr<Accessible> acc = xpcAcc->ToInternalAccessible();
RefPtr<Accessible> acc = xpcAcc->ToInternalAccessible();
NS_ENSURE_ARG(acc);
HyperTextAccessible* position = acc->AsHyperText();
@@ -643,7 +643,7 @@ nsAccessiblePivot::MovePivotInternal(Accessible* aPosition,
PivotMoveReason aReason,
bool aIsFromUserInput)
{
nsRefPtr<Accessible> oldPosition = mPosition.forget();
RefPtr<Accessible> oldPosition = mPosition.forget();
mPosition = aPosition;
int32_t oldStart = mStartOffset, oldEnd = mEndOffset;
mStartOffset = mEndOffset = -1;
+3 -3
View File
@@ -114,17 +114,17 @@ private:
/*
* The root accessible.
*/
nsRefPtr<Accessible> mRoot;
RefPtr<Accessible> mRoot;
/*
* The temporary modal root accessible.
*/
nsRefPtr<Accessible> mModalRoot;
RefPtr<Accessible> mModalRoot;
/*
* The current pivot position.
*/
nsRefPtr<Accessible> mPosition;
RefPtr<Accessible> mPosition;
/*
* The text start offset ofthe pivot.
+37 -9
View File
@@ -16,11 +16,13 @@
#include "nsIBoxObject.h"
#include "nsIDOMXULElement.h"
#include "nsIDocShell.h"
#include "nsIObserverService.h"
#include "nsIPresShell.h"
#include "nsPresContext.h"
#include "nsIScrollableFrame.h"
#include "nsISelectionPrivate.h"
#include "nsISelectionController.h"
#include "nsISimpleEnumerator.h"
#include "mozilla/dom/TouchEvent.h"
#include "mozilla/EventListenerManager.h"
#include "mozilla/EventStateManager.h"
@@ -102,7 +104,7 @@ nsCoreUtils::DispatchClickEvent(nsITreeBoxObject *aTreeBoxObj,
nsIWidget *rootWidget =
rootFrame->GetViewExternal()->GetNearestWidget(&offset);
nsRefPtr<nsPresContext> presContext = presShell->GetPresContext();
RefPtr<nsPresContext> presContext = presShell->GetPresContext();
int32_t cnvdX = presContext->CSSPixelsToDevPixels(tcX + x + 1) +
presContext->AppUnitsToDevPixels(offset.x);
@@ -110,19 +112,19 @@ nsCoreUtils::DispatchClickEvent(nsITreeBoxObject *aTreeBoxObj,
presContext->AppUnitsToDevPixels(offset.y);
// XUL is just desktop, so there is no real reason for senfing touch events.
DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, cnvdX, cnvdY,
DispatchMouseEvent(eMouseDown, cnvdX, cnvdY,
tcContent, tcFrame, presShell, rootWidget);
DispatchMouseEvent(NS_MOUSE_BUTTON_UP, cnvdX, cnvdY,
DispatchMouseEvent(eMouseUp, cnvdX, cnvdY,
tcContent, tcFrame, presShell, rootWidget);
}
void
nsCoreUtils::DispatchMouseEvent(uint32_t aEventType, int32_t aX, int32_t aY,
nsCoreUtils::DispatchMouseEvent(EventMessage aMessage, int32_t aX, int32_t aY,
nsIContent *aContent, nsIFrame *aFrame,
nsIPresShell *aPresShell, nsIWidget *aRootWidget)
{
WidgetMouseEvent event(true, aEventType, aRootWidget,
WidgetMouseEvent event(true, aMessage, aRootWidget,
WidgetMouseEvent::eReal, WidgetMouseEvent::eNormal);
event.refPoint = LayoutDeviceIntPoint(aX, aY);
@@ -137,20 +139,20 @@ nsCoreUtils::DispatchMouseEvent(uint32_t aEventType, int32_t aX, int32_t aY,
}
void
nsCoreUtils::DispatchTouchEvent(uint32_t aEventType, int32_t aX, int32_t aY,
nsCoreUtils::DispatchTouchEvent(EventMessage aMessage, int32_t aX, int32_t aY,
nsIContent* aContent, nsIFrame* aFrame,
nsIPresShell* aPresShell, nsIWidget* aRootWidget)
{
if (!dom::TouchEvent::PrefEnabled())
return;
WidgetTouchEvent event(true, aEventType, aRootWidget);
WidgetTouchEvent event(true, aMessage, aRootWidget);
event.time = PR_IntervalNow();
// XXX: Touch has an identifier of -1 to hint that it is synthesized.
nsRefPtr<dom::Touch> t = new dom::Touch(-1, LayoutDeviceIntPoint(aX, aY),
nsIntPoint(1, 1), 0.0f, 1.0f);
RefPtr<dom::Touch> t = new dom::Touch(-1, LayoutDeviceIntPoint(aX, aY),
LayoutDeviceIntPoint(1, 1), 0.0f, 1.0f);
t->SetTarget(aContent);
event.touches.AppendElement(t);
nsEventStatus status = nsEventStatus_eIgnore;
@@ -647,3 +649,29 @@ nsCoreUtils::IsWhitespaceString(const nsSubstring& aString)
return iterBegin == iterEnd;
}
bool
nsCoreUtils::AccEventObserversExist()
{
nsCOMPtr<nsIObserverService> obsService = services::GetObserverService();
NS_ENSURE_TRUE(obsService, false);
nsCOMPtr<nsISimpleEnumerator> observers;
obsService->EnumerateObservers(NS_ACCESSIBLE_EVENT_TOPIC,
getter_AddRefs(observers));
NS_ENSURE_TRUE(observers, false);
bool hasObservers = false;
observers->HasMoreElements(&hasObservers);
return hasObservers;
}
void
nsCoreUtils::DispatchAccEvent(RefPtr<nsIAccessibleEvent> event)
{
nsCOMPtr<nsIObserverService> obsService = services::GetObserverService();
NS_ENSURE_TRUE_VOID(obsService);
obsService->NotifyObservers(event, NS_ACCESSIBLE_EVENT_TOPIC, nullptr);
}
+19 -5
View File
@@ -6,6 +6,8 @@
#ifndef nsCoreUtils_h_
#define nsCoreUtils_h_
#include "mozilla/EventForwards.h"
#include "nsIAccessibleEvent.h"
#include "nsIContent.h"
#include "nsIDocument.h" // for GetShell()
#include "nsIPresShell.h"
@@ -49,7 +51,7 @@ public:
/**
* Send mouse event to the given element.
*
* @param aEventType [in] an event type (see BasicEvents.h for constants)
* @param aMessage [in] an event message (see EventForwards.h)
* @param aX [in] x coordinate in dev pixels
* @param aY [in] y coordinate in dev pixels
* @param aContent [in] the element
@@ -57,14 +59,15 @@ public:
* @param aPresShell [in] the presshell for the element
* @param aRootWidget [in] the root widget of the element
*/
static void DispatchMouseEvent(uint32_t aEventType, int32_t aX, int32_t aY,
static void DispatchMouseEvent(mozilla::EventMessage aMessage,
int32_t aX, int32_t aY,
nsIContent *aContent, nsIFrame *aFrame,
nsIPresShell *aPresShell, nsIWidget *aRootWidget);
/**
* Send a touch event with a single touch point to the given element.
*
* @param aEventType [in] an event type (see BasicEvents.h for constants)
* @param aMessage [in] an event message (see EventForwards.h)
* @param aX [in] x coordinate in dev pixels
* @param aY [in] y coordinate in dev pixels
* @param aContent [in] the element
@@ -72,7 +75,8 @@ public:
* @param aPresShell [in] the presshell for the element
* @param aRootWidget [in] the root widget of the element
*/
static void DispatchTouchEvent(uint32_t aEventType, int32_t aX, int32_t aY,
static void DispatchTouchEvent(mozilla::EventMessage aMessage,
int32_t aX, int32_t aY,
nsIContent* aContent, nsIFrame* aFrame,
nsIPresShell* aPresShell, nsIWidget* aRootWidget);
@@ -223,7 +227,7 @@ public:
* attribute or wrong value then false is returned.
*/
static bool GetUIntAttr(nsIContent *aContent, nsIAtom *aAttr,
int32_t *aUInt);
int32_t* aUInt);
/**
* Returns language for the given node.
@@ -311,6 +315,16 @@ public:
return aChar == ' ' || aChar == '\n' ||
aChar == '\r' || aChar == '\t' || aChar == 0xa0;
}
/*
* Return true if there are any observers of accessible events.
*/
static bool AccEventObserversExist();
/**
* Notify accessible event observers of an event.
*/
static void DispatchAccEvent(RefPtr<nsIAccessibleEvent> aEvent);
};
#endif
+1 -1
View File
@@ -42,7 +42,7 @@ nsEventShell::FireEvent(uint32_t aEventType, Accessible* aAccessible,
{
NS_ENSURE_TRUE_VOID(aAccessible);
nsRefPtr<AccEvent> event = new AccEvent(aEventType, aAccessible,
RefPtr<AccEvent> event = new AccEvent(aEventType, aAccessible,
aIsFromUserInput);
FireEvent(event);
+1 -1
View File
@@ -41,7 +41,7 @@ public:
static void FireEvent(mozilla::a11y::Accessible* aTarget, uint64_t aState,
bool aIsEnabled, bool aIsFromUserInput)
{
nsRefPtr<mozilla::a11y::AccStateChangeEvent> stateChangeEvent =
RefPtr<mozilla::a11y::AccStateChangeEvent> stateChangeEvent =
new mozilla::a11y::AccStateChangeEvent(aTarget, aState, aIsEnabled,
(aIsFromUserInput ?
mozilla::a11y::eFromUserInput :
+3 -1
View File
@@ -139,7 +139,9 @@ nsTextEquivUtils::AppendTextEquivFromTextContent(nsIContent *aContent,
if (aContent->TextLength() > 0) {
nsIFrame *frame = aContent->GetPrimaryFrame();
if (frame) {
nsIFrame::RenderedText text = frame->GetRenderedText();
nsIFrame::RenderedText text = frame->GetRenderedText(0,
UINT32_MAX, nsIFrame::TextOffsetType::OFFSETS_IN_CONTENT_TEXT,
nsIFrame::TrailingWhitespace::DONT_TRIM_TRAILING_WHITESPACE);
aString->Append(text.mString);
} else {
// If aContent is an object that is display: none, we have no a frame.
+2 -22
View File
@@ -10,35 +10,15 @@
#include "ARIAGridAccessible.h"
#include "AccIterator.h"
#include "nsAccUtils.h"
namespace mozilla {
namespace a11y {
inline Accessible*
ARIAGridCellAccessible::TableFor(Accessible* aRow) const
{
if (aRow) {
Accessible* table = aRow->Parent();
if (table) {
roles::Role tableRole = table->Role();
if (tableRole == roles::GROUPING) { // if there's a rowgroup.
table = table->Parent();
if (table)
tableRole = table->Role();
}
return tableRole == roles::TABLE || tableRole == roles::TREE_TABLE ?
table : nullptr;
}
}
return nullptr;
}
inline int32_t
ARIAGridCellAccessible::RowIndexFor(Accessible* aRow) const
{
Accessible* table = TableFor(aRow);
Accessible* table = nsAccUtils::TableFor(aRow);
if (table) {
int32_t rowIdx = 0;
Accessible* row = nullptr;
+94 -7
View File
@@ -68,7 +68,7 @@ ARIAGridAccessible::RowCount()
Accessible*
ARIAGridAccessible::CellAt(uint32_t aRowIndex, uint32_t aColumnIndex)
{
{
Accessible* row = GetRowAt(aRowIndex);
if (!row)
return nullptr;
@@ -79,6 +79,9 @@ ARIAGridAccessible::CellAt(uint32_t aRowIndex, uint32_t aColumnIndex)
bool
ARIAGridAccessible::IsColSelected(uint32_t aColIdx)
{
if (IsARIARole(nsGkAtoms::table))
return false;
AccIterator rowIter(this, filters::GetRow);
Accessible* row = rowIter.Next();
if (!row)
@@ -98,6 +101,9 @@ ARIAGridAccessible::IsColSelected(uint32_t aColIdx)
bool
ARIAGridAccessible::IsRowSelected(uint32_t aRowIdx)
{
if (IsARIARole(nsGkAtoms::table))
return false;
Accessible* row = GetRowAt(aRowIdx);
if(!row)
return false;
@@ -117,6 +123,9 @@ ARIAGridAccessible::IsRowSelected(uint32_t aRowIdx)
bool
ARIAGridAccessible::IsCellSelected(uint32_t aRowIdx, uint32_t aColIdx)
{
if (IsARIARole(nsGkAtoms::table))
return false;
Accessible* row = GetRowAt(aRowIdx);
if(!row)
return false;
@@ -133,6 +142,9 @@ ARIAGridAccessible::IsCellSelected(uint32_t aRowIdx, uint32_t aColIdx)
uint32_t
ARIAGridAccessible::SelectedCellCount()
{
if (IsARIARole(nsGkAtoms::table))
return 0;
uint32_t count = 0, colCount = ColCount();
AccIterator rowIter(this, filters::GetRow);
@@ -159,6 +171,9 @@ ARIAGridAccessible::SelectedCellCount()
uint32_t
ARIAGridAccessible::SelectedColCount()
{
if (IsARIARole(nsGkAtoms::table))
return 0;
uint32_t colCount = ColCount();
if (!colCount)
return 0;
@@ -193,6 +208,9 @@ ARIAGridAccessible::SelectedColCount()
uint32_t
ARIAGridAccessible::SelectedRowCount()
{
if (IsARIARole(nsGkAtoms::table))
return 0;
uint32_t count = 0;
AccIterator rowIter(this, filters::GetRow);
@@ -227,6 +245,9 @@ ARIAGridAccessible::SelectedRowCount()
void
ARIAGridAccessible::SelectedCells(nsTArray<Accessible*>* aCells)
{
if (IsARIARole(nsGkAtoms::table))
return;
AccIterator rowIter(this, filters::GetRow);
Accessible* row = nullptr;
@@ -251,6 +272,9 @@ ARIAGridAccessible::SelectedCells(nsTArray<Accessible*>* aCells)
void
ARIAGridAccessible::SelectedCellIndices(nsTArray<uint32_t>* aCells)
{
if (IsARIARole(nsGkAtoms::table))
return;
uint32_t colCount = ColCount();
AccIterator rowIter(this, filters::GetRow);
@@ -275,6 +299,9 @@ ARIAGridAccessible::SelectedCellIndices(nsTArray<uint32_t>* aCells)
void
ARIAGridAccessible::SelectedColIndices(nsTArray<uint32_t>* aCols)
{
if (IsARIARole(nsGkAtoms::table))
return;
uint32_t colCount = ColCount();
if (!colCount)
return;
@@ -309,6 +336,9 @@ ARIAGridAccessible::SelectedColIndices(nsTArray<uint32_t>* aCols)
void
ARIAGridAccessible::SelectedRowIndices(nsTArray<uint32_t>* aRows)
{
if (IsARIARole(nsGkAtoms::table))
return;
AccIterator rowIter(this, filters::GetRow);
Accessible* row = nullptr;
for (uint32_t rowIdx = 0; (row = rowIter.Next()); rowIdx++) {
@@ -338,6 +368,9 @@ ARIAGridAccessible::SelectedRowIndices(nsTArray<uint32_t>* aRows)
void
ARIAGridAccessible::SelectRow(uint32_t aRowIdx)
{
if (IsARIARole(nsGkAtoms::table))
return;
AccIterator rowIter(this, filters::GetRow);
Accessible* row = nullptr;
@@ -350,6 +383,9 @@ ARIAGridAccessible::SelectRow(uint32_t aRowIdx)
void
ARIAGridAccessible::SelectCol(uint32_t aColIdx)
{
if (IsARIARole(nsGkAtoms::table))
return;
AccIterator rowIter(this, filters::GetRow);
Accessible* row = nullptr;
@@ -368,8 +404,10 @@ ARIAGridAccessible::SelectCol(uint32_t aColIdx)
void
ARIAGridAccessible::UnselectRow(uint32_t aRowIdx)
{
Accessible* row = GetRowAt(aRowIdx);
if (IsARIARole(nsGkAtoms::table))
return;
Accessible* row = GetRowAt(aRowIdx);
if (row)
SetARIASelected(row, false);
}
@@ -377,6 +415,9 @@ ARIAGridAccessible::UnselectRow(uint32_t aRowIdx)
void
ARIAGridAccessible::UnselectCol(uint32_t aColIdx)
{
if (IsARIARole(nsGkAtoms::table))
return;
AccIterator rowIter(this, filters::GetRow);
Accessible* row = nullptr;
@@ -421,6 +462,9 @@ nsresult
ARIAGridAccessible::SetARIASelected(Accessible* aAccessible,
bool aIsSelected, bool aNotify)
{
if (IsARIARole(nsGkAtoms::table))
return NS_OK;
nsIContent *content = aAccessible->GetContent();
NS_ENSURE_STATE(content);
@@ -485,6 +529,35 @@ ARIAGridAccessible::SetARIASelected(Accessible* aAccessible,
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////////
// ARIARowAccessible
////////////////////////////////////////////////////////////////////////////////
ARIARowAccessible::
ARIARowAccessible(nsIContent* aContent, DocAccessible* aDoc) :
AccessibleWrap(aContent, aDoc)
{
mGenericTypes |= eTableRow;
}
NS_IMPL_ISUPPORTS_INHERITED0(ARIARowAccessible, Accessible)
GroupPos
ARIARowAccessible::GroupPosition()
{
int32_t count = 0, index = 0;
Accessible* table = nsAccUtils::TableFor(this);
if (table && nsCoreUtils::GetUIntAttr(table->GetContent(),
nsGkAtoms::aria_rowcount, &count) &&
nsCoreUtils::GetUIntAttr(mContent, nsGkAtoms::aria_rowindex, &index)) {
return GroupPos(0, index, count);
}
return AccessibleWrap::GroupPosition();
}
////////////////////////////////////////////////////////////////////////////////
// ARIAGridCellAccessible
////////////////////////////////////////////////////////////////////////////////
@@ -508,7 +581,7 @@ NS_IMPL_ISUPPORTS_INHERITED0(ARIAGridCellAccessible, HyperTextAccessible)
TableAccessible*
ARIAGridCellAccessible::Table() const
{
Accessible* table = TableFor(Row());
Accessible* table = nsAccUtils::TableFor(Row());
return table ? table->AsTable() : nullptr;
}
@@ -524,8 +597,8 @@ ARIAGridCellAccessible::ColIdx() const
for (int32_t idx = 0; idx < indexInRow; idx++) {
Accessible* cell = row->GetChildAt(idx);
roles::Role role = cell->Role();
if (role == roles::GRID_CELL || role == roles::ROWHEADER ||
role == roles::COLUMNHEADER)
if (role == roles::CELL || role == roles::GRID_CELL ||
role == roles::ROWHEADER || role == roles::COLUMNHEADER)
colIdx++;
}
@@ -593,8 +666,8 @@ ARIAGridCellAccessible::NativeAttributes()
colIdx = colCount;
roles::Role role = child->Role();
if (role == roles::GRID_CELL || role == roles::ROWHEADER ||
role == roles::COLUMNHEADER)
if (role == roles::CELL || role == roles::GRID_CELL ||
role == roles::ROWHEADER || role == roles::COLUMNHEADER)
colCount++;
}
@@ -613,3 +686,17 @@ ARIAGridCellAccessible::NativeAttributes()
return attributes.forget();
}
GroupPos
ARIAGridCellAccessible::GroupPosition()
{
int32_t count = 0, index = 0;
TableAccessible* table = Table();
if (table && nsCoreUtils::GetUIntAttr(table->AsAccessible()->GetContent(),
nsGkAtoms::aria_colcount, &count) &&
nsCoreUtils::GetUIntAttr(mContent, nsGkAtoms::aria_colindex, &index)) {
return GroupPos(0, index, count);
}
return GroupPos();
}
+20 -6
View File
@@ -73,6 +73,24 @@ protected:
};
/**
* Accessible for ARIA row.
*/
class ARIARowAccessible : public AccessibleWrap
{
public:
ARIARowAccessible(nsIContent* aContent, DocAccessible* aDoc);
NS_DECL_ISUPPORTS_INHERITED
// Accessible
virtual mozilla::a11y::GroupPos GroupPosition() override;
protected:
virtual ~ARIARowAccessible() {}
};
/**
* Accessible for ARIA gridcell and rowheader/columnheader.
*/
@@ -88,6 +106,7 @@ public:
virtual TableCellAccessible* AsTableCell() override { return this; }
virtual void ApplyARIAState(uint64_t* aState) const override;
virtual already_AddRefed<nsIPersistentProperties> NativeAttributes() override;
virtual mozilla::a11y::GroupPos GroupPosition() override;
protected:
virtual ~ARIAGridCellAccessible() {}
@@ -98,14 +117,9 @@ protected:
Accessible* Row() const
{
Accessible* row = Parent();
return row && row->Role() == roles::ROW ? row : nullptr;
return row && row->IsTableRow() ? row : nullptr;
}
/**
* Return a table for the given row.
*/
Accessible* TableFor(Accessible* aRow) const;
/**
* Return index of the given row.
*/
+115 -60
View File
@@ -15,6 +15,7 @@
#include "ApplicationAccessible.h"
#include "nsEventShell.h"
#include "nsTextEquivUtils.h"
#include "DocAccessibleChild.h"
#include "Relation.h"
#include "Role.h"
#include "RootAccessible.h"
@@ -106,9 +107,10 @@ Accessible::Accessible(nsIContent* aContent, DocAccessible* aDoc) :
mContent(aContent), mDoc(aDoc),
mParent(nullptr), mIndexInParent(-1), mChildrenFlags(eChildrenUninitialized),
mStateFlags(0), mContextFlags(0), mType(0), mGenericTypes(0),
mIndexOfEmbeddedChild(-1), mRoleMapEntry(nullptr)
mRoleMapEntry(nullptr)
{
mBits.groupInfo = nullptr;
mInt.mIndexOfEmbeddedChild = -1;
}
Accessible::~Accessible()
@@ -300,12 +302,6 @@ Accessible::KeyboardShortcut() const
return KeyBinding();
}
bool
Accessible::CanHaveAnonChildren()
{
return true;
}
void
Accessible::TranslateString(const nsString& aKey, nsAString& aStringOut)
{
@@ -392,7 +388,9 @@ Accessible::VisibilityState()
if (frame->GetType() == nsGkAtoms::textFrame &&
!(frame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) &&
frame->GetRect().IsEmpty()) {
nsIFrame::RenderedText text = frame->GetRenderedText();
nsIFrame::RenderedText text = frame->GetRenderedText(0,
UINT32_MAX, nsIFrame::TextOffsetType::OFFSETS_IN_CONTENT_TEXT,
nsIFrame::TrailingWhitespace::DONT_TRIM_TRAILING_WHITESPACE);
if (text.mString.IsEmpty()) {
return states::INVISIBLE;
}
@@ -533,10 +531,10 @@ Accessible::ChildAtPoint(int32_t aX, int32_t aY,
nsIWidget* rootWidget = rootFrame->GetView()->GetNearestWidget(nullptr);
NS_ENSURE_TRUE(rootWidget, nullptr);
nsIntRect rootRect;
LayoutDeviceIntRect rootRect;
rootWidget->GetScreenBounds(rootRect);
WidgetMouseEvent dummyEvent(true, NS_MOUSE_MOVE, rootWidget,
WidgetMouseEvent dummyEvent(true, eMouseMove, rootWidget,
WidgetMouseEvent::eSynthesized);
dummyEvent.refPoint = LayoutDeviceIntPoint(aX - rootRect.x, aY - rootRect.y);
@@ -832,20 +830,57 @@ Accessible::HandleAccEvent(AccEvent* aEvent)
{
NS_ENSURE_ARG_POINTER(aEvent);
nsCOMPtr<nsIObserverService> obsService = services::GetObserverService();
NS_ENSURE_TRUE(obsService, NS_ERROR_FAILURE);
if (IPCAccessibilityActive() && Document()) {
DocAccessibleChild* ipcDoc = mDoc->IPCDoc();
MOZ_ASSERT(ipcDoc);
if (ipcDoc) {
uint64_t id = aEvent->GetAccessible()->IsDoc() ? 0 :
reinterpret_cast<uintptr_t>(aEvent->GetAccessible());
nsCOMPtr<nsISimpleEnumerator> observers;
obsService->EnumerateObservers(NS_ACCESSIBLE_EVENT_TOPIC,
getter_AddRefs(observers));
switch(aEvent->GetEventType()) {
case nsIAccessibleEvent::EVENT_SHOW:
ipcDoc->ShowEvent(downcast_accEvent(aEvent));
break;
NS_ENSURE_STATE(observers);
case nsIAccessibleEvent::EVENT_HIDE:
ipcDoc->SendHideEvent(id);
break;
bool hasObservers = false;
observers->HasMoreElements(&hasObservers);
if (hasObservers) {
nsCOMPtr<nsIAccessibleEvent> event = MakeXPCEvent(aEvent);
return obsService->NotifyObservers(event, NS_ACCESSIBLE_EVENT_TOPIC, nullptr);
case nsIAccessibleEvent::EVENT_REORDER:
// reorder events on the application acc aren't necessary to tell the parent
// about new top level documents.
if (!aEvent->GetAccessible()->IsApplication())
ipcDoc->SendEvent(id, aEvent->GetEventType());
break;
case nsIAccessibleEvent::EVENT_STATE_CHANGE: {
AccStateChangeEvent* event = downcast_accEvent(aEvent);
ipcDoc->SendStateChangeEvent(id, event->GetState(),
event->IsStateEnabled());
break;
}
case nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED: {
AccCaretMoveEvent* event = downcast_accEvent(aEvent);
ipcDoc->SendCaretMoveEvent(id, event->GetCaretOffset());
break;
}
case nsIAccessibleEvent::EVENT_TEXT_INSERTED:
case nsIAccessibleEvent::EVENT_TEXT_REMOVED: {
AccTextChangeEvent* event = downcast_accEvent(aEvent);
ipcDoc->SendTextChangeEvent(id, event->ModifiedText(),
event->GetStartOffset(),
event->GetLength(),
event->IsTextInserted(),
event->IsFromUserInput());
break;
}
default:
ipcDoc->SendEvent(id, aEvent->GetEventType());
}
}
}
if (nsCoreUtils::AccEventObserversExist()) {
nsCoreUtils::DispatchAccEvent(MakeXPCEvent(aEvent));
}
return NS_OK;
@@ -1187,11 +1222,13 @@ Accessible::ApplyARIAState(uint64_t* aState) const
*aState &= ~states::READONLY;
if (mContent->HasID()) {
// If has a role & ID and aria-activedescendant on the container, assume focusable
nsIContent *ancestorContent = mContent;
while ((ancestorContent = ancestorContent->GetParent()) != nullptr) {
if (ancestorContent->HasAttr(kNameSpaceID_None, nsGkAtoms::aria_activedescendant)) {
// ancestor has activedescendant property, this content could be active
// If has a role & ID and aria-activedescendant on the container, assume
// focusable.
const Accessible* ancestor = this;
while ((ancestor = ancestor->Parent()) && !ancestor->IsDoc()) {
dom::Element* el = ancestor->Elm();
if (el &&
el->HasAttr(kNameSpaceID_None, nsGkAtoms::aria_activedescendant)) {
*aState |= states::FOCUSABLE;
break;
}
@@ -1200,12 +1237,12 @@ Accessible::ApplyARIAState(uint64_t* aState) const
}
if (*aState & states::FOCUSABLE) {
// Special case: aria-disabled propagates from ancestors down to any focusable descendant
nsIContent *ancestorContent = mContent;
while ((ancestorContent = ancestorContent->GetParent()) != nullptr) {
if (ancestorContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::aria_disabled,
nsGkAtoms::_true, eCaseMatters)) {
// ancestor has aria-disabled property, this is disabled
// Propogate aria-disabled from ancestors down to any focusable descendant.
const Accessible* ancestor = this;
while ((ancestor = ancestor->Parent()) && !ancestor->IsDoc()) {
dom::Element* el = ancestor->Elm();
if (el && el->AttrValueIs(kNameSpaceID_None, nsGkAtoms::aria_disabled,
nsGkAtoms::_true, eCaseMatters)) {
*aState |= states::UNAVAILABLE;
break;
}
@@ -1274,21 +1311,14 @@ Accessible::Value(nsString& aValue)
if (mRoleMapEntry->Is(nsGkAtoms::combobox)) {
Accessible* option = CurrentItem();
if (!option) {
Accessible* listbox = nullptr;
ARIAOwnsIterator iter(this);
while ((listbox = iter.Next()) && !listbox->IsListControl());
if (!listbox) {
uint32_t childCount = ChildCount();
for (uint32_t idx = 0; idx < childCount; idx++) {
Accessible* child = mChildren.ElementAt(idx);
if (child->IsListControl())
listbox = child;
uint32_t childCount = ChildCount();
for (uint32_t idx = 0; idx < childCount; idx++) {
Accessible* child = mChildren.ElementAt(idx);
if (child->IsListControl()) {
option = child->GetSelectedItem(0);
break;
}
}
if (listbox)
option = listbox->GetSelectedItem(0);
}
if (option)
@@ -1559,8 +1589,7 @@ Accessible::RelationByType(RelationType aType)
}
case RelationType::NODE_CHILD_OF: {
Relation rel(new ARIAOwnedByIterator(this));
Relation rel;
// This is an ARIA tree or treegrid that doesn't use owns, so we need to
// get the parent the hard way.
if (mRoleMapEntry && (mRoleMapEntry->role == roles::OUTLINEITEM ||
@@ -1589,8 +1618,6 @@ Accessible::RelationByType(RelationType aType)
}
case RelationType::NODE_PARENT_OF: {
Relation rel(new ARIAOwnsIterator(this));
// ARIA tree or treegrid can do the hierarchy by @aria-level, ARIA trees
// also can be organized by groups.
if (mRoleMapEntry &&
@@ -1600,10 +1627,10 @@ Accessible::RelationByType(RelationType aType)
mRoleMapEntry->role == roles::OUTLINE ||
mRoleMapEntry->role == roles::LIST ||
mRoleMapEntry->role == roles::TREE_TABLE)) {
rel.AppendIter(new ItemIterator(this));
return Relation(new ItemIterator(this));
}
return rel;
return Relation();
}
case RelationType::CONTROLLED_BY:
@@ -1743,7 +1770,7 @@ Accessible::DoCommand(nsIContent *aContent, uint32_t aActionIndex)
}
private:
nsRefPtr<Accessible> mAcc;
RefPtr<Accessible> mAcc;
nsCOMPtr<nsIContent> mContent;
uint32_t mIdx;
};
@@ -1779,15 +1806,19 @@ Accessible::DispatchClickEvent(nsIContent *aContent, uint32_t aActionIndex)
nsSize size = frame->GetSize();
nsRefPtr<nsPresContext> presContext = presShell->GetPresContext();
RefPtr<nsPresContext> presContext = presShell->GetPresContext();
int32_t x = presContext->AppUnitsToDevPixels(point.x + size.width / 2);
int32_t y = presContext->AppUnitsToDevPixels(point.y + size.height / 2);
// Simulate a touch interaction by dispatching touch events with mouse events.
nsCoreUtils::DispatchTouchEvent(NS_TOUCH_START, x, y, aContent, frame, presShell, widget);
nsCoreUtils::DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, x, y, aContent, frame, presShell, widget);
nsCoreUtils::DispatchTouchEvent(NS_TOUCH_END, x, y, aContent, frame, presShell, widget);
nsCoreUtils::DispatchMouseEvent(NS_MOUSE_BUTTON_UP, x, y, aContent, frame, presShell, widget);
nsCoreUtils::DispatchTouchEvent(eTouchStart, x, y, aContent, frame,
presShell, widget);
nsCoreUtils::DispatchMouseEvent(eMouseDown, x, y, aContent, frame,
presShell, widget);
nsCoreUtils::DispatchTouchEvent(eTouchEnd, x, y, aContent, frame,
presShell, widget);
nsCoreUtils::DispatchMouseEvent(eMouseUp, x, y, aContent, frame,
presShell, widget);
}
void
@@ -1920,8 +1951,8 @@ Accessible::BindToParent(Accessible* aParent, uint32_t aIndexInParent)
if (mParent) {
if (mParent != aParent) {
NS_ERROR("Adopting child!");
mParent->RemoveChild(this);
mParent->InvalidateChildrenGroupInfo();
mParent->RemoveChild(this);
} else {
NS_ERROR("Binding to the same parent!");
return;
@@ -1954,7 +1985,7 @@ Accessible::UnbindFromParent()
#endif
mParent = nullptr;
mIndexInParent = -1;
mIndexOfEmbeddedChild = -1;
mInt.mIndexOfEmbeddedChild = -1;
if (IsProxy())
MOZ_CRASH("this should never be called on proxy wrappers");
@@ -2201,6 +2232,30 @@ Accessible::AnchorURIAt(uint32_t aAnchorIndex)
return nullptr;
}
void
Accessible::ToTextPoint(HyperTextAccessible** aContainer, int32_t* aOffset,
bool aIsBefore) const
{
if (IsHyperText()) {
*aContainer = const_cast<Accessible*>(this)->AsHyperText();
*aOffset = aIsBefore ? 0 : (*aContainer)->CharacterCount();
return;
}
const Accessible* child = nullptr;
const Accessible* parent = this;
do {
child = parent;
parent = parent->Parent();
} while (parent && !parent->IsHyperText());
if (parent) {
*aContainer = const_cast<Accessible*>(parent)->AsHyperText();
*aOffset = (*aContainer)->GetChildOffset(
child->IndexInParent() + static_cast<int32_t>(!aIsBefore));
}
}
////////////////////////////////////////////////////////////////////////////////
// SelectAccessible
@@ -2439,7 +2494,7 @@ Accessible::CacheChildren()
TreeWalker walker(this, mContent);
Accessible* child = nullptr;
while ((child = walker.NextChild()) && AppendChild(child));
while ((child = walker.Next()) && AppendChild(child));
}
void
+57 -19
View File
@@ -38,6 +38,7 @@ class HTMLLIAccessible;
class HyperTextAccessible;
class ImageAccessible;
class KeyBinding;
class OuterDocAccessible;
class ProxyAccessible;
class Relation;
class RootAccessible;
@@ -81,6 +82,8 @@ enum ENameValueFlag {
struct GroupPos
{
GroupPos() : level(0), posInSet(0), setSize(0) { }
GroupPos(int32_t aLevel, int32_t aPosInSet, int32_t aSetSize) :
level(aLevel), posInSet(aPosInSet), setSize(aSetSize) { }
int32_t level;
int32_t posInSet;
@@ -157,6 +160,8 @@ public:
return DOMNode.forget();
}
nsIContent* GetContent() const { return mContent; }
mozilla::dom::Element* Elm() const
{ return mContent && mContent->IsElement() ? mContent->AsElement() : nullptr; }
/**
* Return node type information of DOM node associated with the accessible.
@@ -484,11 +489,6 @@ public:
*/
virtual nsresult HandleAccEvent(AccEvent* aAccEvent);
/**
* Return true if this accessible allows accessible children from anonymous subtree.
*/
virtual bool CanHaveAnonChildren();
/**
* Return true if the accessible is an acceptable child.
*/
@@ -528,11 +528,6 @@ public:
*/
virtual void SetSelected(bool aSelect);
/**
* Extend selection to this accessible.
*/
void ExtendSelection() { };
/**
* Select the accessible within its container.
*/
@@ -618,6 +613,19 @@ public:
MOZ_ASSERT(IsProxy());
return mBits.proxy;
}
uint32_t ProxyInterfaces() const
{
MOZ_ASSERT(IsProxy());
return mInt.mProxyInterfaces;
}
void SetProxyInterfaces(uint32_t aInterfaces)
{
MOZ_ASSERT(IsProxy());
mInt.mProxyInterfaces = aInterfaces;
}
bool IsOuterDoc() const { return mType == eOuterDocType; }
OuterDocAccessible* AsOuterDoc();
bool IsProgress() const { return mType == eProgressType; }
@@ -745,6 +753,12 @@ public:
*/
virtual already_AddRefed<nsIURI> AnchorURIAt(uint32_t aAnchorIndex);
/**
* Returns a text point for the accessible element.
*/
void ToTextPoint(HyperTextAccessible** aContainer, int32_t* aOffset,
bool aIsBefore = true) const;
//////////////////////////////////////////////////////////////////////////////
// SelectAccessible
@@ -845,7 +859,7 @@ public:
bool IsDefunct() const { return mStateFlags & eIsDefunct; }
/**
* Return true if the accessible is no longer in the document.
* Return false if the accessible is no longer in the document.
*/
bool IsInDocument() const { return !(mStateFlags & eIsNotInDocument); }
@@ -893,6 +907,25 @@ public:
mStateFlags &= ~eSurvivingInUpdate;
}
/**
* Get/set repositioned bit indicating that the accessible was moved in
* the accessible tree, i.e. the accessible tree structure differs from DOM.
*/
bool IsRelocated() const { return mStateFlags & eRelocated; }
void SetRelocated(bool aRelocated)
{
if (aRelocated)
mStateFlags |= eRelocated;
else
mStateFlags &= ~eRelocated;
}
/**
* Return true if the accessible doesn't allow accessible children from XBL
* anonymous subtree.
*/
bool NoXBLKids() { return mStateFlags & eNoXBLKids; }
/**
* Return true if this accessible has a parent whose name depends on this
* accessible.
@@ -908,7 +941,6 @@ public:
void SetARIAHidden(bool aIsDefined);
protected:
virtual ~Accessible();
/**
@@ -939,8 +971,8 @@ protected:
/**
* Set accessible parent and index in parent.
*/
virtual void BindToParent(Accessible* aParent, uint32_t aIndexInParent);
virtual void UnbindFromParent();
void BindToParent(Accessible* aParent, uint32_t aIndexInParent);
void UnbindFromParent();
/**
* Return sibling accessible at the given offset.
@@ -984,8 +1016,10 @@ protected:
eSubtreeMutating = 1 << 6, // subtree is being mutated
eIgnoreDOMUIEvent = 1 << 7, // don't process DOM UI events for a11y events
eSurvivingInUpdate = 1 << 8, // parent drops children to recollect them
eRelocated = 1 << 9, // accessible was moved in tree
eNoXBLKids = 1 << 10, // accessible don't allows XBL children
eLastStateFlag = eSurvivingInUpdate
eLastStateFlag = eNoXBLKids
};
/**
@@ -1095,12 +1129,12 @@ protected:
nsCOMPtr<nsIContent> mContent;
DocAccessible* mDoc;
nsRefPtr<Accessible> mParent;
nsTArray<nsRefPtr<Accessible> > mChildren;
RefPtr<Accessible> mParent;
nsTArray<RefPtr<Accessible> > mChildren;
int32_t mIndexInParent;
static const uint8_t kChildrenFlagsBits = 2;
static const uint8_t kStateFlagsBits = 9;
static const uint8_t kStateFlagsBits = 11;
static const uint8_t kContextFlagsBits = 2;
static const uint8_t kTypeBits = 6;
static const uint8_t kGenericTypesBits = 14;
@@ -1122,7 +1156,11 @@ protected:
friend class AutoTreeMutation;
nsAutoPtr<mozilla::a11y::EmbeddedObjCollector> mEmbeddedObjCollector;
int32_t mIndexOfEmbeddedChild;
union {
int32_t mIndexOfEmbeddedChild;
uint32_t mProxyInterfaces;
} mInt;
friend class EmbeddedObjCollector;
union
+83 -88
View File
@@ -67,15 +67,6 @@ LeafAccessible::CacheChildren()
// LinkableAccessible
////////////////////////////////////////////////////////////////////////////////
LinkableAccessible::
LinkableAccessible(nsIContent* aContent, DocAccessible* aDoc) :
AccessibleWrap(aContent, aDoc),
mActionAcc(nullptr),
mIsLink(false),
mIsOnclick(false)
{
}
NS_IMPL_ISUPPORTS_INHERITED0(LinkableAccessible, AccessibleWrap)
////////////////////////////////////////////////////////////////////////////////
@@ -84,17 +75,22 @@ NS_IMPL_ISUPPORTS_INHERITED0(LinkableAccessible, AccessibleWrap)
void
LinkableAccessible::TakeFocus()
{
if (mActionAcc)
mActionAcc->TakeFocus();
else
if (Accessible* actionAcc = ActionWalk()) {
actionAcc->TakeFocus();
} else {
AccessibleWrap::TakeFocus();
}
}
uint64_t
LinkableAccessible::NativeLinkState() const
{
if (mIsLink)
return states::LINKED | (mActionAcc->LinkState() & states::TRAVERSED);
bool isLink;
Accessible* actionAcc =
const_cast<LinkableAccessible*>(this)->ActionWalk(&isLink);
if (isLink) {
return states::LINKED | (actionAcc->LinkState() & states::TRAVERSED);
}
return 0;
}
@@ -105,18 +101,62 @@ LinkableAccessible::Value(nsString& aValue)
aValue.Truncate();
Accessible::Value(aValue);
if (!aValue.IsEmpty())
if (!aValue.IsEmpty()) {
return;
}
if (aValue.IsEmpty() && mIsLink)
mActionAcc->Value(aValue);
bool isLink;
Accessible* actionAcc = ActionWalk(&isLink);
if (isLink) {
actionAcc->Value(aValue);
}
}
uint8_t
LinkableAccessible::ActionCount()
{
return (mIsOnclick || mIsLink) ? 1 : 0;
bool isLink, isOnclick;
ActionWalk(&isLink, &isOnclick);
return (isLink || isOnclick) ? 1 : 0;
}
Accessible*
LinkableAccessible::ActionWalk(bool* aIsLink, bool* aIsOnclick)
{
if (aIsOnclick) {
*aIsOnclick = false;
}
if (aIsLink) {
*aIsLink = false;
}
if (nsCoreUtils::HasClickListener(mContent)) {
if (aIsOnclick) {
*aIsOnclick = true;
}
return nullptr;
}
// XXX: The logic looks broken since the click listener may be registered
// on non accessible node in parent chain but this node is skipped when tree
// is traversed.
Accessible* walkUpAcc = this;
while ((walkUpAcc = walkUpAcc->Parent()) && !walkUpAcc->IsDoc()) {
if (walkUpAcc->LinkState() & states::LINKED) {
if (aIsLink) {
*aIsLink = true;
}
return walkUpAcc;
}
if (nsCoreUtils::HasClickListener(walkUpAcc->GetContent())) {
if (aIsOnclick) {
*aIsOnclick = true;
}
return walkUpAcc;
}
}
return nullptr;
}
void
@@ -126,40 +166,39 @@ LinkableAccessible::ActionNameAt(uint8_t aIndex, nsAString& aName)
// Action 0 (default action): Jump to link
if (aIndex == eAction_Jump) {
if (mIsLink)
bool isOnclick, isLink;
ActionWalk(&isLink, &isOnclick);
if (isLink) {
aName.AssignLiteral("jump");
else if (mIsOnclick)
} else if (isOnclick) {
aName.AssignLiteral("click");
}
}
}
bool
LinkableAccessible::DoAction(uint8_t aIndex)
{
if (aIndex != eAction_Jump)
if (aIndex != eAction_Jump) {
return false;
}
return mActionAcc ? mActionAcc->DoAction(aIndex) :
AccessibleWrap::DoAction(aIndex);
if (Accessible* actionAcc = ActionWalk()) {
return actionAcc->DoAction(aIndex);
}
return AccessibleWrap::DoAction(aIndex);
}
KeyBinding
LinkableAccessible::AccessKey() const
{
return mActionAcc ?
mActionAcc->AccessKey() : Accessible::AccessKey();
}
if (const Accessible* actionAcc =
const_cast<LinkableAccessible*>(this)->ActionWalk()) {
return actionAcc->AccessKey();
}
////////////////////////////////////////////////////////////////////////////////
// LinkableAccessible. Accessible
void
LinkableAccessible::Shutdown()
{
mIsLink = false;
mIsOnclick = false;
mActionAcc = nullptr;
AccessibleWrap::Shutdown();
return Accessible::AccessKey();
}
////////////////////////////////////////////////////////////////////////////////
@@ -168,63 +207,19 @@ LinkableAccessible::Shutdown()
already_AddRefed<nsIURI>
LinkableAccessible::AnchorURIAt(uint32_t aAnchorIndex)
{
if (mIsLink) {
NS_ASSERTION(mActionAcc->IsLink(), "HyperLink isn't implemented.");
bool isLink;
Accessible* actionAcc = ActionWalk(&isLink);
if (isLink) {
NS_ASSERTION(actionAcc->IsLink(), "HyperLink isn't implemented.");
if (mActionAcc->IsLink())
return mActionAcc->AnchorURIAt(aAnchorIndex);
if (actionAcc->IsLink()) {
return actionAcc->AnchorURIAt(aAnchorIndex);
}
}
return nullptr;
}
////////////////////////////////////////////////////////////////////////////////
// LinkableAccessible: Accessible protected
void
LinkableAccessible::BindToParent(Accessible* aParent,
uint32_t aIndexInParent)
{
AccessibleWrap::BindToParent(aParent, aIndexInParent);
// Cache action content.
mActionAcc = nullptr;
mIsLink = false;
mIsOnclick = false;
if (nsCoreUtils::HasClickListener(mContent)) {
mIsOnclick = true;
return;
}
// XXX: The logic looks broken since the click listener may be registered
// on non accessible node in parent chain but this node is skipped when tree
// is traversed.
Accessible* walkUpAcc = this;
while ((walkUpAcc = walkUpAcc->Parent()) && !walkUpAcc->IsDoc()) {
if (walkUpAcc->LinkState() & states::LINKED) {
mIsLink = true;
mActionAcc = walkUpAcc;
return;
}
if (nsCoreUtils::HasClickListener(walkUpAcc->GetContent())) {
mActionAcc = walkUpAcc;
mIsOnclick = true;
return;
}
}
}
void
LinkableAccessible::UnbindFromParent()
{
mActionAcc = nullptr;
mIsLink = false;
mIsOnclick = false;
AccessibleWrap::UnbindFromParent();
}
////////////////////////////////////////////////////////////////////////////////
// DummyAccessible
+8 -13
View File
@@ -56,12 +56,14 @@ class LinkableAccessible : public AccessibleWrap
public:
enum { eAction_Jump = 0 };
LinkableAccessible(nsIContent* aContent, DocAccessible* aDoc);
LinkableAccessible(nsIContent* aContent, DocAccessible* aDoc) :
AccessibleWrap(aContent, aDoc)
{
}
NS_DECL_ISUPPORTS_INHERITED
// Accessible
virtual void Shutdown() override;
virtual void Value(nsString& aValue) override;
virtual uint64_t NativeLinkState() const override;
virtual void TakeFocus() override;
@@ -72,26 +74,19 @@ public:
virtual bool DoAction(uint8_t index) override;
virtual KeyBinding AccessKey() const override;
// ActionAccessible helpers
Accessible* ActionWalk(bool* aIsLink = nullptr,
bool* aIsOnclick = nullptr);
// HyperLinkAccessible
virtual already_AddRefed<nsIURI> AnchorURIAt(uint32_t aAnchorIndex) override;
protected:
virtual ~LinkableAccessible() {}
// Accessible
virtual void BindToParent(Accessible* aParent, uint32_t aIndexInParent) override;
virtual void UnbindFromParent() override;
/**
* Parent accessible that provides an action for this linkable accessible.
*/
Accessible* mActionAcc;
bool mIsLink;
bool mIsOnclick;
};
/**
* A simple accessible that gets its enumerated role passed into constructor.
* A simple accessible that gets its enumerated role.
*/
template<a11y::role R>
class EnumRoleAccessible : public AccessibleWrap
+3 -3
View File
@@ -45,7 +45,7 @@ DocAccessible::FireDelayedEvent(AccEvent* aEvent)
inline void
DocAccessible::FireDelayedEvent(uint32_t aEventType, Accessible* aTarget)
{
nsRefPtr<AccEvent> event = new AccEvent(aEventType, aTarget);
RefPtr<AccEvent> event = new AccEvent(aEventType, aTarget);
FireDelayedEvent(event);
}
@@ -113,7 +113,7 @@ DocAccessible::NotifyOfLoad(uint32_t aLoadEventType)
// If the document is loaded completely then network activity was presumingly
// caused by file loading. Fire busy state change event.
if (HasLoadState(eCompletelyLoaded) && IsLoadEventTarget()) {
nsRefPtr<AccEvent> stateEvent =
RefPtr<AccEvent> stateEvent =
new AccStateChangeEvent(this, states::BUSY, false);
FireDelayedEvent(stateEvent);
}
@@ -124,7 +124,7 @@ DocAccessible::MaybeNotifyOfValueChange(Accessible* aAccessible)
{
a11y::role role = aAccessible->Role();
if (role == roles::ENTRY || role == roles::COMBOBOX)
FireDelayedEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE, aAccessible);
FireDelayedEvent(nsIAccessibleEvent::EVENT_TEXT_VALUE_CHANGE, aAccessible);
}
inline Accessible*
+385 -93
View File
@@ -1,4 +1,5 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=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/. */
@@ -113,10 +114,31 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(DocAccessible, Accessible)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNotificationController)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVirtualCursor)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChildDocuments)
tmp->mDependentIDsHash.EnumerateRead(CycleCollectorTraverseDepIDsEntry, &cb);
for (auto iter = tmp->mDependentIDsHash.Iter(); !iter.Done(); iter.Next()) {
AttrRelProviderArray* providers = iter.UserData();
for (int32_t jdx = providers->Length() - 1; jdx >= 0; jdx--) {
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(
cb, "content of dependent ids hash entry of document accessible");
AttrRelProvider* provider = (*providers)[jdx];
cb.NoteXPCOMChild(provider->mContent);
NS_ASSERTION(provider->mContent->IsInDoc(),
"Referred content is not in document!");
}
}
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAccessibleCache)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAnchorJumpElm)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mInvalidationList)
for (auto it = tmp->mARIAOwnsHash.ConstIter(); !it.Done(); it.Next()) {
nsTArray<RefPtr<Accessible> >* ar = it.UserData();
for (uint32_t i = 0; i < ar->Length(); i++) {
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
"mARIAOwnsHash entry item");
cb.NoteXPCOMChild(ar->ElementAt(i));
}
}
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(DocAccessible, Accessible)
@@ -128,6 +150,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(DocAccessible, Accessible)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mAccessibleCache)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mAnchorJumpElm)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mInvalidationList)
tmp->mARIAOwnsHash.Clear();
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(DocAccessible)
@@ -457,8 +480,9 @@ DocAccessible::Shutdown()
mChildDocuments.Clear();
// XXX thinking about ordering?
if (IPCAccessibilityActive()) {
DocAccessibleChild::Send__delete__(mIPCDoc);
if (mIPCDoc) {
MOZ_ASSERT(IPCAccessibilityActive());
mIPCDoc->Shutdown();
MOZ_ASSERT(!mIPCDoc);
}
@@ -654,7 +678,7 @@ DocAccessible::Observe(nsISupports* aSubject, const char* aTopic,
// Normally we only fire delayed events created from the node, not an
// accessible object. See the AccStateChangeEvent constructor for details
// about this exceptional case.
nsRefPtr<AccEvent> event =
RefPtr<AccEvent> event =
new AccStateChangeEvent(this, states::EDITABLE, true);
FireDelayedEvent(event);
}
@@ -672,7 +696,7 @@ DocAccessible::OnPivotChanged(nsIAccessiblePivot* aPivot,
PivotMoveReason aReason,
bool aIsFromUserInput)
{
nsRefPtr<AccEvent> event =
RefPtr<AccEvent> event =
new AccVCChangeEvent(
this, (aOldAccessible ? aOldAccessible->ToInternalAccessible() : nullptr),
aOldStart, aOldEnd, aReason,
@@ -708,7 +732,11 @@ DocAccessible::AttributeWillChange(nsIDocument* aDocument,
// because dependent IDs cache doesn't contain IDs from non accessible
// elements.
if (aModType != nsIDOMMutationEvent::ADDITION)
RemoveDependentIDsFor(aElement, aAttribute);
RemoveDependentIDsFor(accessible, aAttribute);
if (aAttribute == nsGkAtoms::id) {
RelocateARIAOwnedIfNeeded(aElement);
}
// Store the ARIA attribute old value so that it can be used after
// attribute change. Note, we assume there's no nested ARIA attribute
@@ -731,6 +759,13 @@ DocAccessible::AttributeWillChange(nsIDocument* aDocument,
mStateBitWasOn = accessible->Unavailable();
}
void
DocAccessible::NativeAnonymousChildListChange(nsIDocument* aDocument,
nsIContent* aContent,
bool aIsRemove)
{
}
void
DocAccessible::AttributeChanged(nsIDocument* aDocument,
dom::Element* aElement,
@@ -770,7 +805,7 @@ DocAccessible::AttributeChanged(nsIDocument* aDocument,
// dependent IDs cache when its accessible is created.
if (aModType == nsIDOMMutationEvent::MODIFICATION ||
aModType == nsIDOMMutationEvent::ADDITION) {
AddDependentIDsFor(aElement, aAttribute);
AddDependentIDsFor(accessible, aAttribute);
}
}
@@ -809,11 +844,11 @@ DocAccessible::AttributeChangedImpl(Accessible* aAccessible,
if (aAccessible->Unavailable() == mStateBitWasOn)
return;
nsRefPtr<AccEvent> enabledChangeEvent =
RefPtr<AccEvent> enabledChangeEvent =
new AccStateChangeEvent(aAccessible, states::ENABLED, mStateBitWasOn);
FireDelayedEvent(enabledChangeEvent);
nsRefPtr<AccEvent> sensitiveChangeEvent =
RefPtr<AccEvent> sensitiveChangeEvent =
new AccStateChangeEvent(aAccessible, states::SENSITIVE, mStateBitWasOn);
FireDelayedEvent(sensitiveChangeEvent);
return;
@@ -872,12 +907,16 @@ DocAccessible::AttributeChangedImpl(Accessible* aAccessible,
if (aAttribute == nsGkAtoms::aria_busy) {
bool isOn = elm->AttrValueIs(aNameSpaceID, aAttribute, nsGkAtoms::_true,
eCaseMatters);
nsRefPtr<AccEvent> event =
RefPtr<AccEvent> event =
new AccStateChangeEvent(aAccessible, states::BUSY, isOn);
FireDelayedEvent(event);
return;
}
if (aAttribute == nsGkAtoms::id) {
RelocateARIAOwnedIfNeeded(elm);
}
// ARIA or XUL selection
if ((aAccessible->GetContent()->IsXULElement() &&
aAttribute == nsGkAtoms::selected) ||
@@ -889,7 +928,7 @@ DocAccessible::AttributeChangedImpl(Accessible* aAccessible,
elm->AttrValueIs(aNameSpaceID, aAttribute, nsGkAtoms::_true, eCaseMatters) ?
AccSelChangeEvent::eSelectionAdd : AccSelChangeEvent::eSelectionRemove;
nsRefPtr<AccEvent> event =
RefPtr<AccEvent> event =
new AccSelChangeEvent(widget, aAccessible, selChangeType);
FireDelayedEvent(event);
}
@@ -898,7 +937,7 @@ DocAccessible::AttributeChangedImpl(Accessible* aAccessible,
}
if (aAttribute == nsGkAtoms::contenteditable) {
nsRefPtr<AccEvent> editableChangeEvent =
RefPtr<AccEvent> editableChangeEvent =
new AccStateChangeEvent(aAccessible, states::EDITABLE);
FireDelayedEvent(editableChangeEvent);
return;
@@ -918,14 +957,14 @@ DocAccessible::ARIAAttributeChanged(Accessible* aAccessible, nsIAtom* aAttribute
// there is an ARIA role present or not.
if (aAttribute == nsGkAtoms::aria_required) {
nsRefPtr<AccEvent> event =
RefPtr<AccEvent> event =
new AccStateChangeEvent(aAccessible, states::REQUIRED);
FireDelayedEvent(event);
return;
}
if (aAttribute == nsGkAtoms::aria_invalid) {
nsRefPtr<AccEvent> event =
RefPtr<AccEvent> event =
new AccStateChangeEvent(aAccessible, states::INVALID);
FireDelayedEvent(event);
return;
@@ -943,7 +982,7 @@ DocAccessible::ARIAAttributeChanged(Accessible* aAccessible, nsIAtom* aAttribute
// We treat aria-expanded as a global ARIA state for historical reasons
if (aAttribute == nsGkAtoms::aria_expanded) {
nsRefPtr<AccEvent> event =
RefPtr<AccEvent> event =
new AccStateChangeEvent(aAccessible, states::EXPANDED);
FireDelayedEvent(event);
return;
@@ -953,7 +992,7 @@ DocAccessible::ARIAAttributeChanged(Accessible* aAccessible, nsIAtom* aAttribute
// change event; at least until native API comes up with a more meaningful event.
uint8_t attrFlags = aria::AttrCharacteristicsFor(aAttribute);
if (!(attrFlags & ATTR_BYPASSOBJ)) {
nsRefPtr<AccEvent> event =
RefPtr<AccEvent> event =
new AccObjectAttrChangedEvent(aAccessible, aAttribute);
FireDelayedEvent(event);
}
@@ -969,7 +1008,7 @@ DocAccessible::ARIAAttributeChanged(Accessible* aAccessible, nsIAtom* aAttribute
!aAccessible->Parent()->IsARIAHidden()) {
aAccessible->SetARIAHidden(isDefined);
nsRefPtr<AccEvent> event =
RefPtr<AccEvent> event =
new AccObjectAttrChangedEvent(aAccessible, aAttribute);
FireDelayedEvent(event);
}
@@ -981,14 +1020,14 @@ DocAccessible::ARIAAttributeChanged(Accessible* aAccessible, nsIAtom* aAttribute
aAttribute == nsGkAtoms::aria_pressed)) {
const uint64_t kState = (aAttribute == nsGkAtoms::aria_checked) ?
states::CHECKED : states::PRESSED;
nsRefPtr<AccEvent> event = new AccStateChangeEvent(aAccessible, kState);
RefPtr<AccEvent> event = new AccStateChangeEvent(aAccessible, kState);
FireDelayedEvent(event);
bool wasMixed = (mARIAAttrOldValue == nsGkAtoms::mixed);
bool isMixed = elm->AttrValueIs(kNameSpaceID_None, aAttribute,
nsGkAtoms::mixed, eCaseMatters);
if (isMixed != wasMixed) {
nsRefPtr<AccEvent> event =
RefPtr<AccEvent> event =
new AccStateChangeEvent(aAccessible, states::MIXED, isMixed);
FireDelayedEvent(event);
}
@@ -996,22 +1035,31 @@ DocAccessible::ARIAAttributeChanged(Accessible* aAccessible, nsIAtom* aAttribute
}
if (aAttribute == nsGkAtoms::aria_readonly) {
nsRefPtr<AccEvent> event =
RefPtr<AccEvent> event =
new AccStateChangeEvent(aAccessible, states::READONLY);
FireDelayedEvent(event);
return;
}
// Fire value change event whenever aria-valuetext is changed, or
// when aria-valuenow is changed and aria-valuetext is empty
if (aAttribute == nsGkAtoms::aria_valuetext ||
(aAttribute == nsGkAtoms::aria_valuenow &&
(!elm->HasAttr(kNameSpaceID_None, nsGkAtoms::aria_valuetext) ||
elm->AttrValueIs(kNameSpaceID_None, nsGkAtoms::aria_valuetext,
nsGkAtoms::_empty, eCaseMatters)))) {
// Fire text value change event whenever aria-valuetext is changed.
if (aAttribute == nsGkAtoms::aria_valuetext) {
FireDelayedEvent(nsIAccessibleEvent::EVENT_TEXT_VALUE_CHANGE, aAccessible);
return;
}
// Fire numeric value change event when aria-valuenow is changed and
// aria-valuetext is empty
if (aAttribute == nsGkAtoms::aria_valuenow &&
(!elm->HasAttr(kNameSpaceID_None, nsGkAtoms::aria_valuetext) ||
elm->AttrValueIs(kNameSpaceID_None, nsGkAtoms::aria_valuetext,
nsGkAtoms::_empty, eCaseMatters))) {
FireDelayedEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE, aAccessible);
return;
}
if (aAttribute == nsGkAtoms::aria_owns) {
mNotificationController->ScheduleRelocation(aAccessible);
}
}
void
@@ -1060,26 +1108,26 @@ DocAccessible::ContentStateChanged(nsIDocument* aDocument,
AccSelChangeEvent::SelChangeType selChangeType =
aContent->AsElement()->State().HasState(NS_EVENT_STATE_CHECKED) ?
AccSelChangeEvent::eSelectionAdd : AccSelChangeEvent::eSelectionRemove;
nsRefPtr<AccEvent> event =
RefPtr<AccEvent> event =
new AccSelChangeEvent(widget, accessible, selChangeType);
FireDelayedEvent(event);
return;
}
nsRefPtr<AccEvent> event =
RefPtr<AccEvent> event =
new AccStateChangeEvent(accessible, states::CHECKED,
aContent->AsElement()->State().HasState(NS_EVENT_STATE_CHECKED));
FireDelayedEvent(event);
}
if (aStateMask.HasState(NS_EVENT_STATE_INVALID)) {
nsRefPtr<AccEvent> event =
RefPtr<AccEvent> event =
new AccStateChangeEvent(accessible, states::INVALID, true);
FireDelayedEvent(event);
}
if (aStateMask.HasState(NS_EVENT_STATE_VISITED)) {
nsRefPtr<AccEvent> event =
RefPtr<AccEvent> event =
new AccStateChangeEvent(accessible, states::TRAVERSED, true);
FireDelayedEvent(event);
}
@@ -1242,9 +1290,16 @@ DocAccessible::BindToDocument(Accessible* aAccessible,
aAccessible->SetRoleMapEntry(aRoleMapEntry);
nsIContent* content = aAccessible->GetContent();
if (content && content->IsElement())
AddDependentIDsFor(content->AsElement());
AddDependentIDsFor(aAccessible);
if (aAccessible->HasOwnContent()) {
nsIContent* el = aAccessible->GetContent();
if (el->HasAttr(kNameSpaceID_None, nsGkAtoms::aria_owns)) {
mNotificationController->ScheduleRelocation(aAccessible);
}
RelocateARIAOwnedIfNeeded(el);
}
}
void
@@ -1295,10 +1350,12 @@ DocAccessible::ContentInserted(nsIContent* aContainerNode,
// null (document element is inserted or removed).
Accessible* container = aContainerNode ?
GetAccessibleOrContainer(aContainerNode) : this;
mNotificationController->ScheduleContentInsertion(container,
aStartChildNode,
aEndChildNode);
if (container) {
// Ignore notification if the container node is no longer in the DOM tree.
mNotificationController->ScheduleContentInsertion(container,
aStartChildNode,
aEndChildNode);
}
}
}
@@ -1380,7 +1437,7 @@ DocAccessible::CacheChildren()
// Ignore last HTML:br, copied from HyperTextAccessible.
TreeWalker walker(this, rootElm);
Accessible* lastChild = nullptr;
while (Accessible* child = walker.NextChild()) {
while (Accessible* child = walker.Next()) {
if (lastChild)
AppendChild(lastChild);
@@ -1412,14 +1469,14 @@ DocAccessible::NotifyOfLoading(bool aIsReloading)
// Fire reload and state busy events on existing document accessible while
// event from user input flag can be calculated properly and accessible
// is alive. When new document gets loaded then this one is destroyed.
nsRefPtr<AccEvent> reloadEvent =
RefPtr<AccEvent> reloadEvent =
new AccEvent(nsIAccessibleEvent::EVENT_DOCUMENT_RELOAD, this);
nsEventShell::FireEvent(reloadEvent);
}
// Fire state busy change event. Use delayed event since we don't care
// actually if event isn't delivered when the document goes away like a shot.
nsRefPtr<AccEvent> stateEvent =
RefPtr<AccEvent> stateEvent =
new AccStateChangeEvent(this, states::BUSY, true);
FireDelayedEvent(stateEvent);
}
@@ -1451,14 +1508,14 @@ DocAccessible::DoInitialUpdate()
// this document may be fired prior to this reorder event. If this is
// a problem then consider to keep event processing per tab document.
if (!IsRoot()) {
nsRefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(Parent());
RefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(Parent());
ParentDocument()->FireDelayedEvent(reorderEvent);
}
uint32_t childCount = ChildCount();
for (uint32_t i = 0; i < childCount; i++) {
Accessible* child = GetChildAt(i);
nsRefPtr<AccShowEvent> event = new AccShowEvent(child, child->GetContent());
RefPtr<AccShowEvent> event = new AccShowEvent(child);
FireDelayedEvent(event);
}
}
@@ -1484,39 +1541,42 @@ DocAccessible::ProcessLoad()
// Fire complete/load stopped if the load event type is given.
if (mLoadEventType) {
nsRefPtr<AccEvent> loadEvent = new AccEvent(mLoadEventType, this);
RefPtr<AccEvent> loadEvent = new AccEvent(mLoadEventType, this);
FireDelayedEvent(loadEvent);
mLoadEventType = 0;
}
// Fire busy state change event.
nsRefPtr<AccEvent> stateEvent =
RefPtr<AccEvent> stateEvent =
new AccStateChangeEvent(this, states::BUSY, false);
FireDelayedEvent(stateEvent);
}
void
DocAccessible::AddDependentIDsFor(dom::Element* aRelProviderElm,
nsIAtom* aRelAttr)
DocAccessible::AddDependentIDsFor(Accessible* aRelProvider, nsIAtom* aRelAttr)
{
dom::Element* relProviderEl = aRelProvider->Elm();
if (!relProviderEl)
return;
for (uint32_t idx = 0; idx < kRelationAttrsLen; idx++) {
nsIAtom* relAttr = *kRelationAttrs[idx];
if (aRelAttr && aRelAttr != relAttr)
continue;
if (relAttr == nsGkAtoms::_for) {
if (!aRelProviderElm->IsAnyOfHTMLElements(nsGkAtoms::label,
nsGkAtoms::output))
if (!relProviderEl->IsAnyOfHTMLElements(nsGkAtoms::label,
nsGkAtoms::output))
continue;
} else if (relAttr == nsGkAtoms::control) {
if (!aRelProviderElm->IsAnyOfXULElements(nsGkAtoms::label,
nsGkAtoms::description))
if (!relProviderEl->IsAnyOfXULElements(nsGkAtoms::label,
nsGkAtoms::description))
continue;
}
IDRefsIterator iter(this, aRelProviderElm, relAttr);
IDRefsIterator iter(this, relProviderEl, relAttr);
while (true) {
const nsDependentSubstring id = iter.NextID();
if (id.IsEmpty())
@@ -1532,7 +1592,7 @@ DocAccessible::AddDependentIDsFor(dom::Element* aRelProviderElm,
if (providers) {
AttrRelProvider* provider =
new AttrRelProvider(relAttr, aRelProviderElm);
new AttrRelProvider(relAttr, relProviderEl);
if (provider) {
providers->AppendElement(provider);
@@ -1541,8 +1601,10 @@ DocAccessible::AddDependentIDsFor(dom::Element* aRelProviderElm,
// children invalidation (this happens immediately after the caching
// is finished).
nsIContent* dependentContent = iter.GetElem(id);
if (dependentContent && !HasAccessible(dependentContent)) {
mInvalidationList.AppendElement(dependentContent);
if (dependentContent) {
if (!HasAccessible(dependentContent)) {
mInvalidationList.AppendElement(dependentContent);
}
}
}
}
@@ -1553,18 +1615,25 @@ DocAccessible::AddDependentIDsFor(dom::Element* aRelProviderElm,
if (aRelAttr)
break;
}
// Make sure to schedule the tree update if needed.
mNotificationController->ScheduleProcessing();
}
void
DocAccessible::RemoveDependentIDsFor(dom::Element* aRelProviderElm,
DocAccessible::RemoveDependentIDsFor(Accessible* aRelProvider,
nsIAtom* aRelAttr)
{
dom::Element* relProviderElm = aRelProvider->Elm();
if (!relProviderElm)
return;
for (uint32_t idx = 0; idx < kRelationAttrsLen; idx++) {
nsIAtom* relAttr = *kRelationAttrs[idx];
if (aRelAttr && aRelAttr != *kRelationAttrs[idx])
continue;
IDRefsIterator iter(this, aRelProviderElm, relAttr);
IDRefsIterator iter(this, relProviderElm, relAttr);
while (true) {
const nsDependentSubstring id = iter.NextID();
if (id.IsEmpty())
@@ -1575,7 +1644,7 @@ DocAccessible::RemoveDependentIDsFor(dom::Element* aRelProviderElm,
for (uint32_t jdx = 0; jdx < providers->Length(); ) {
AttrRelProvider* provider = (*providers)[jdx];
if (provider->mRelAttr == relAttr &&
provider->mContent == aRelProviderElm)
provider->mContent == relProviderElm)
providers->RemoveElement(provider);
else
jdx++;
@@ -1612,8 +1681,7 @@ DocAccessible::UpdateAccessibleOnAttrChange(dom::Element* aElement,
return true;
}
if (aAttribute == nsGkAtoms::href ||
aAttribute == nsGkAtoms::onclick) {
if (aAttribute == nsGkAtoms::href) {
// Not worth the expense to ensure which namespace these are in. It doesn't
// kill use to recreate the accessible even if the attribute was used in
// the wrong namespace or an element that doesn't support it.
@@ -1699,7 +1767,7 @@ DocAccessible::UpdateTreeOnInsertion(Accessible* aContainer)
aContainer->InvalidateChildren();
aContainer->EnsureChildren();
nsRefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(aContainer);
RefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(aContainer);
uint32_t updateFlags = eNoAccessible;
for (uint32_t idx = 0; idx < aContainer->ContentChildCount(); idx++) {
@@ -1771,7 +1839,7 @@ DocAccessible::UpdateTreeOnRemoval(Accessible* aContainer, nsIContent* aChildNod
#endif
uint32_t updateFlags = eNoAccessible;
nsRefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(aContainer);
RefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(aContainer);
AutoTreeMutation mut(aContainer);
if (child) {
@@ -1828,7 +1896,6 @@ DocAccessible::UpdateTreeInternal(Accessible* aChild, bool aIsInsert,
// this node already then it will be suppressed by this one.
Accessible* focusedAcc = nullptr;
nsINode* node = aChild->GetNode();
if (aIsInsert) {
// Create accessible tree for shown accessible.
CacheChildrenInSubtree(aChild, &focusedAcc);
@@ -1848,11 +1915,11 @@ DocAccessible::UpdateTreeInternal(Accessible* aChild, bool aIsInsert,
}
// Fire show/hide event.
nsRefPtr<AccMutationEvent> event;
RefPtr<AccMutationEvent> event;
if (aIsInsert)
event = new AccShowEvent(aChild, node);
event = new AccShowEvent(aChild);
else
event = new AccHideEvent(aChild, node);
event = new AccHideEvent(aChild);
FireDelayedEvent(event);
aReorderEvent->AddSubMutationEvent(event);
@@ -1891,6 +1958,256 @@ DocAccessible::UpdateTreeInternal(Accessible* aChild, bool aIsInsert,
return updateFlags;
}
void
DocAccessible::RelocateARIAOwnedIfNeeded(nsIContent* aElement)
{
if (!aElement->HasID())
return;
AttrRelProviderArray* list =
mDependentIDsHash.Get(nsDependentAtomString(aElement->GetID()));
if (list) {
for (uint32_t idx = 0; idx < list->Length(); idx++) {
if (list->ElementAt(idx)->mRelAttr == nsGkAtoms::aria_owns) {
Accessible* owner = GetAccessible(list->ElementAt(idx)->mContent);
if (owner) {
mNotificationController->ScheduleRelocation(owner);
}
}
}
}
}
void
DocAccessible::ValidateARIAOwned()
{
for (auto it = mARIAOwnsHash.Iter(); !it.Done(); it.Next()) {
Accessible* owner = it.Key();
nsTArray<RefPtr<Accessible> >* children = it.UserData();
// Owner is about to die, put children back if applicable.
if (!mAccessibleCache.GetWeak(reinterpret_cast<void*>(owner)) ||
!owner->IsInDocument()) {
PutChildrenBack(children, 0);
it.Remove();
continue;
}
for (uint32_t idx = 0; idx < children->Length(); idx++) {
Accessible* child = children->ElementAt(idx);
if (!child->IsInDocument()) {
children->RemoveElementAt(idx);
idx--;
continue;
}
NS_ASSERTION(child->Parent(), "No parent for ARIA owned?");
// If DOM node doesn't have a frame anymore then shutdown its accessible.
if (child->Parent() && !child->GetFrame()) {
UpdateTreeOnRemoval(child->Parent(), child->GetContent());
children->RemoveElementAt(idx);
idx--;
continue;
}
NS_ASSERTION(child->Parent() == owner,
"Illigally stolen ARIA owned child!");
}
if (children->Length() == 0) {
it.Remove();
}
}
}
void
DocAccessible::DoARIAOwnsRelocation(Accessible* aOwner)
{
nsTArray<RefPtr<Accessible> >* children = mARIAOwnsHash.LookupOrAdd(aOwner);
MOZ_ASSERT(aOwner, "aOwner must be a valid pointer");
MOZ_ASSERT(aOwner->Elm(), "aOwner->Elm() must be a valid pointer");
IDRefsIterator iter(this, aOwner->Elm(), nsGkAtoms::aria_owns);
Accessible* child = nullptr;
uint32_t arrayIdx = 0, insertIdx = aOwner->ChildCount() - children->Length();
while ((child = iter.Next())) {
// Same child on same position, no change.
if (child->Parent() == aOwner &&
child->IndexInParent() == static_cast<int32_t>(insertIdx)) {
NS_ASSERTION(child == children->ElementAt(arrayIdx), "Not in sync!");
insertIdx++; arrayIdx++;
continue;
}
NS_ASSERTION(children->SafeElementAt(arrayIdx) != child, "Already in place!");
nsTArray<RefPtr<Accessible> >::index_type idx = children->IndexOf(child);
if (idx < arrayIdx) {
continue; // ignore second entry of same ID
}
// A new child is found, check for loops.
if (child->Parent() != aOwner) {
Accessible* parent = aOwner;
while (parent && parent != child && !parent->IsDoc()) {
parent = parent->Parent();
}
// A referred child cannot be a parent of the owner.
if (parent == child) {
continue;
}
}
if (child->Parent() == aOwner) {
MoveChild(child, insertIdx - 1);
children->InsertElementAt(arrayIdx, child);
arrayIdx++;
} else if (SeizeChild(aOwner, child, insertIdx)) {
children->InsertElementAt(arrayIdx, child);
insertIdx++; arrayIdx++;
}
}
// Put back children that are not seized anymore.
PutChildrenBack(children, arrayIdx);
if (children->Length() == 0) {
mARIAOwnsHash.Remove(aOwner);
}
}
bool
DocAccessible::SeizeChild(Accessible* aNewParent, Accessible* aChild,
int32_t aIdxInParent)
{
Accessible* oldParent = aChild->Parent();
if (!oldParent) {
NS_ERROR("No parent? The tree is broken!");
return false;
}
int32_t oldIdxInParent = aChild->IndexInParent();
RefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(oldParent);
RefPtr<AccMutationEvent> hideEvent = new AccHideEvent(aChild, false);
reorderEvent->AddSubMutationEvent(hideEvent);
{
AutoTreeMutation mut(oldParent);
oldParent->RemoveChild(aChild);
}
bool isReinserted = false;
{
AutoTreeMutation mut(aNewParent);
isReinserted = aNewParent->InsertChildAt(aIdxInParent, aChild);
}
if (!isReinserted) {
AutoTreeMutation mut(oldParent);
oldParent->InsertChildAt(oldIdxInParent, aChild);
return false;
}
// The child may be stolen from other ARIA owns element.
if (aChild->IsRelocated()) {
nsTArray<RefPtr<Accessible> >* children = mARIAOwnsHash.Get(oldParent);
children->RemoveElement(aChild);
}
FireDelayedEvent(hideEvent);
MaybeNotifyOfValueChange(oldParent);
FireDelayedEvent(reorderEvent);
reorderEvent = new AccReorderEvent(aNewParent);
RefPtr<AccMutationEvent> showEvent = new AccShowEvent(aChild);
reorderEvent->AddSubMutationEvent(showEvent);
FireDelayedEvent(showEvent);
MaybeNotifyOfValueChange(aNewParent);
FireDelayedEvent(reorderEvent);
aChild->SetRelocated(true);
return true;
}
void
DocAccessible::MoveChild(Accessible* aChild, int32_t aIdxInParent)
{
NS_PRECONDITION(aChild->Parent(), "No parent?");
Accessible* parent = aChild->Parent();
RefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(parent);
RefPtr<AccMutationEvent> hideEvent = new AccHideEvent(aChild, false);
reorderEvent->AddSubMutationEvent(hideEvent);
AutoTreeMutation mut(parent);
parent->RemoveChild(aChild);
parent->InsertChildAt(aIdxInParent, aChild);
aChild->SetRelocated(true);
FireDelayedEvent(hideEvent);
RefPtr<AccMutationEvent> showEvent = new AccShowEvent(aChild);
reorderEvent->AddSubMutationEvent(showEvent);
FireDelayedEvent(showEvent);
MaybeNotifyOfValueChange(parent);
FireDelayedEvent(reorderEvent);
}
void
DocAccessible::PutChildrenBack(nsTArray<RefPtr<Accessible> >* aChildren,
uint32_t aStartIdx)
{
nsTArray<RefPtr<Accessible> > containers;
for (auto idx = aStartIdx; idx < aChildren->Length(); idx++) {
Accessible* child = aChildren->ElementAt(idx);
// If the child is in the tree then remove it from the owner.
if (child->IsInDocument()) {
Accessible* owner = child->Parent();
if (!owner) {
NS_ERROR("Cannot put the child back. No parent, a broken tree.");
continue;
}
RefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(owner);
RefPtr<AccMutationEvent> hideEvent = new AccHideEvent(child, false);
reorderEvent->AddSubMutationEvent(hideEvent);
{
AutoTreeMutation mut(owner);
owner->RemoveChild(child);
child->SetRelocated(false);
}
FireDelayedEvent(hideEvent);
MaybeNotifyOfValueChange(owner);
FireDelayedEvent(reorderEvent);
}
Accessible* container = GetContainerAccessible(child->GetContent());
if (container &&
containers.IndexOf(container) == nsTArray<Accessible*>::NoIndex) {
containers.AppendElement(container);
}
}
// And put it back where it belongs to.
aChildren->RemoveElementsAt(aStartIdx, aChildren->Length() - aStartIdx);
for (uint32_t idx = 0; idx < containers.Length(); idx++) {
NS_ASSERTION(containers[idx]->IsInDocument(),
"A container has been destroyed.");
if (containers[idx]->IsInDocument()) {
UpdateTreeOnInsertion(containers[idx]);
}
}
}
void
DocAccessible::CacheChildrenInSubtree(Accessible* aRoot,
Accessible** aFocusedAcc)
@@ -1928,10 +2245,7 @@ void
DocAccessible::UncacheChildrenInSubtree(Accessible* aRoot)
{
aRoot->mStateFlags |= eIsNotInDocument;
nsIContent* rootContent = aRoot->GetContent();
if (rootContent && rootContent->IsElement())
RemoveDependentIDsFor(rootContent->AsElement());
RemoveDependentIDsFor(aRoot);
uint32_t count = aRoot->ContentChildCount();
for (uint32_t idx = 0; idx < count; idx++)
@@ -1995,25 +2309,3 @@ DocAccessible::IsLoadEventTarget() const
return (treeItem->ItemType() == nsIDocShellTreeItem::typeContent);
}
PLDHashOperator
DocAccessible::CycleCollectorTraverseDepIDsEntry(const nsAString& aKey,
AttrRelProviderArray* aProviders,
void* aUserArg)
{
nsCycleCollectionTraversalCallback* cb =
static_cast<nsCycleCollectionTraversalCallback*>(aUserArg);
for (int32_t jdx = aProviders->Length() - 1; jdx >= 0; jdx--) {
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb,
"content of dependent ids hash entry of document accessible");
AttrRelProvider* provider = (*aProviders)[jdx];
cb->NoteXPCOMChild(provider->mContent);
NS_ASSERTION(provider->mContent->IsInDoc(),
"Referred content is not in document!");
}
return PL_DHASH_NEXT;
}
+66 -23
View File
@@ -32,7 +32,7 @@ class DocManager;
class NotificationController;
class DocAccessibleChild;
class RelatedAccIterator;
template<class Class, class Arg>
template<class Class, class ... Args>
class TNotification;
class DocAccessible : public HyperTextAccessibleWrap,
@@ -281,6 +281,18 @@ public:
*/
Accessible* GetAccessibleOrDescendant(nsINode* aNode) const;
/**
* Returns aria-owns seized child at the given index.
*/
Accessible* ARIAOwnedAt(Accessible* aParent, uint32_t aIndex) const
{
nsTArray<RefPtr<Accessible> >* children = mARIAOwnsHash.Get(aParent);
if (children) {
return children->SafeElementAt(aIndex);
}
return nullptr;
}
/**
* Return true if the given ID is referred by relation attribute.
*
@@ -336,6 +348,12 @@ public:
*/
void RecreateAccessible(nsIContent* aContent);
/**
* If this document is in a content process return the object responsible for
* communicating with the main process for it.
*/
DocAccessibleChild* IPCDoc() const { return mIPCDoc; }
protected:
virtual ~DocAccessible();
@@ -400,7 +418,7 @@ protected:
* @param aRelProvider [in] accessible that element has relation attribute
* @param aRelAttr [in, optional] relation attribute
*/
void AddDependentIDsFor(dom::Element* aRelProviderElm,
void AddDependentIDsFor(Accessible* aRelProvider,
nsIAtom* aRelAttr = nullptr);
/**
@@ -411,7 +429,7 @@ protected:
* @param aRelProvider [in] accessible that element has relation attribute
* @param aRelAttr [in, optional] relation attribute
*/
void RemoveDependentIDsFor(dom::Element* aRelProviderElm,
void RemoveDependentIDsFor(Accessible* aRelProvider,
nsIAtom* aRelAttr = nullptr);
/**
@@ -485,6 +503,38 @@ protected:
uint32_t UpdateTreeInternal(Accessible* aChild, bool aIsInsert,
AccReorderEvent* aReorderEvent);
/**
* Schedule ARIA owned element relocation if needed.
*/
void RelocateARIAOwnedIfNeeded(nsIContent* aEl);
/**
* Validates all aria-owns connections and updates the tree accordingly.
*/
void ValidateARIAOwned();
/**
* Steals or puts back accessible subtrees.
*/
void DoARIAOwnsRelocation(Accessible* aOwner);
/**
* Moves the child from old parent under new one.
*/
bool SeizeChild(Accessible* aNewParent, Accessible* aChild,
int32_t aIdxInParent);
/**
* Move the child under same parent.
*/
void MoveChild(Accessible* aChild, int32_t aIdxInParent);
/**
* Moves children back under their original parents.
*/
void PutChildrenBack(nsTArray<RefPtr<Accessible> >* aChildren,
uint32_t aStartIdx);
/**
* Create accessible tree.
*
@@ -519,12 +569,6 @@ protected:
*/
bool IsLoadEventTarget() const;
/**
* If this document is in a content process return the object responsible for
* communicating with the main process for it.
*/
DocAccessibleChild* IPCDoc() const { return mIPCDoc; }
/*
* Set the object responsible for communicating with the main process on
* behalf of this document.
@@ -597,12 +641,12 @@ protected:
bool mStateBitWasOn;
};
nsTArray<nsRefPtr<DocAccessible> > mChildDocuments;
nsTArray<RefPtr<DocAccessible> > mChildDocuments;
/**
* The virtual cursor of the document.
*/
nsRefPtr<nsAccessiblePivot> mVirtualCursor;
RefPtr<nsAccessiblePivot> mVirtualCursor;
/**
* A storage class for pairing content with one of its relation attributes.
@@ -622,19 +666,12 @@ protected:
AttrRelProvider& operator =(const AttrRelProvider&);
};
typedef nsTArray<nsAutoPtr<AttrRelProvider> > AttrRelProviderArray;
typedef nsClassHashtable<nsStringHashKey, AttrRelProviderArray>
DependentIDsHashtable;
/**
* The cache of IDs pointed by relation attributes.
*/
DependentIDsHashtable mDependentIDsHash;
static PLDHashOperator
CycleCollectorTraverseDepIDsEntry(const nsAString& aKey,
AttrRelProviderArray* aProviders,
void* aUserArg);
typedef nsTArray<nsAutoPtr<AttrRelProvider> > AttrRelProviderArray;
nsClassHashtable<nsStringHashKey, AttrRelProviderArray>
mDependentIDsHash;
friend class RelatedAccIterator;
@@ -644,12 +681,18 @@ protected:
*
* @see ProcessInvalidationList
*/
nsTArray<nsRefPtr<nsIContent>> mInvalidationList;
nsTArray<RefPtr<nsIContent>> mInvalidationList;
/**
* Holds a list of aria-owns relocations.
*/
nsClassHashtable<nsPtrHashKey<Accessible>, nsTArray<RefPtr<Accessible> > >
mARIAOwnsHash;
/**
* Used to process notification from core and accessible events.
*/
nsRefPtr<NotificationController> mNotificationController;
RefPtr<NotificationController> mNotificationController;
friend class EventQueue;
friend class NotificationController;
+17 -6
View File
@@ -55,11 +55,22 @@ HyperTextAccessible::AddToSelection(int32_t aStartOffset, int32_t aEndOffset)
inline void
HyperTextAccessible::ReplaceText(const nsAString& aText)
{
int32_t numChars = CharacterCount();
if (numChars != 0)
DeleteText(0, numChars);
// We need to call DeleteText() even if there is no contents because we need
// to ensure to move focus to the editor via SetSelectionRange() called in
// DeleteText().
DeleteText(0, CharacterCount());
InsertText(aText, 0);
nsCOMPtr<nsIEditor> editor = GetEditor();
nsCOMPtr<nsIPlaintextEditor> plaintextEditor(do_QueryInterface(editor));
if (!plaintextEditor) {
return;
}
// DeleteText() may cause inserting <br> element in some cases. Let's
// select all again and replace whole contents.
editor->SelectAll();
plaintextEditor->InsertText(aText);
}
inline void
@@ -142,7 +153,7 @@ HyperTextAccessible::AdjustCaretOffset(uint32_t aOffset) const
inline bool
HyperTextAccessible::IsCaretAtEndOfLine() const
{
nsRefPtr<nsFrameSelection> frameSelection = FrameSelection();
RefPtr<nsFrameSelection> frameSelection = FrameSelection();
return frameSelection &&
frameSelection->GetHint() == CARET_ASSOCIATE_BEFORE;
}
@@ -157,7 +168,7 @@ HyperTextAccessible::FrameSelection() const
inline dom::Selection*
HyperTextAccessible::DOMSelection() const
{
nsRefPtr<nsFrameSelection> frameSelection = FrameSelection();
RefPtr<nsFrameSelection> frameSelection = FrameSelection();
return frameSelection ?
frameSelection->GetSelection(nsISelectionController::SELECTION_NORMAL) :
nullptr;
+277 -30
View File
@@ -30,6 +30,7 @@
#include "nsIScrollableFrame.h"
#include "nsIServiceManager.h"
#include "nsITextControlElement.h"
#include "nsIMathMLFrame.h"
#include "nsTextFragment.h"
#include "mozilla/BinarySearch.h"
#include "mozilla/dom/Element.h"
@@ -63,12 +64,11 @@ HyperTextAccessible::NativeRole()
if (r != roles::NOTHING)
return r;
// Treat block frames as paragraphs
nsIFrame *frame = GetFrame();
if (frame && frame->GetType() == nsGkAtoms::blockFrame)
return roles::PARAGRAPH;
nsIFrame* frame = GetFrame();
if (frame && frame->GetType() == nsGkAtoms::inlineFrame)
return roles::TEXT;
return roles::TEXT_CONTAINER; // In ATK this works
return roles::TEXT_CONTAINER;
}
uint64_t
@@ -284,7 +284,7 @@ HyperTextAccessible::DOMPointToOffset(nsINode* aNode, int32_t aNodeOffset,
if (container) {
TreeWalker walker(container, findNode->AsContent(),
TreeWalker::eWalkContextTree);
descendant = walker.NextChild();
descendant = walker.Next();
if (!descendant)
descendant = container;
}
@@ -326,6 +326,23 @@ HyperTextAccessible::TransformOffset(Accessible* aDescendant,
return CharacterCount();
}
/**
* GetElementAsContentOf() returns a content representing an element which is
* or includes aNode.
*
* XXX This method is enough to retrieve ::before or ::after pseudo element.
* So, if you want to use this for other purpose, you might need to check
* ancestors too.
*/
static nsIContent* GetElementAsContentOf(nsINode* aNode)
{
if (aNode->IsElement()) {
return aNode->AsContent();
}
nsIContent* parent = aNode->GetParent();
return parent && parent->IsElement() ? parent : nullptr;
}
bool
HyperTextAccessible::OffsetsToDOMRange(int32_t aStartOffset, int32_t aEndOffset,
nsRange* aRange)
@@ -334,9 +351,19 @@ HyperTextAccessible::OffsetsToDOMRange(int32_t aStartOffset, int32_t aEndOffset,
if (!startPoint.node)
return false;
aRange->SetStart(startPoint.node, startPoint.idx);
// HyperTextAccessible manages pseudo elements generated by ::before or
// ::after. However, contents of them are not in the DOM tree normally.
// Therefore, they are not selectable and editable. So, when this creates
// a DOM range, it should not start from nor end in any pseudo contents.
nsIContent* container = GetElementAsContentOf(startPoint.node);
DOMPoint startPointForDOMRange =
ClosestNotGeneratedDOMPoint(startPoint, container);
aRange->SetStart(startPointForDOMRange.node, startPointForDOMRange.idx);
// If the caller wants collapsed range, let's collapse the range to its start.
if (aStartOffset == aEndOffset) {
aRange->SetEnd(startPoint.node, startPoint.idx);
aRange->Collapse(true);
return true;
}
@@ -344,7 +371,13 @@ HyperTextAccessible::OffsetsToDOMRange(int32_t aStartOffset, int32_t aEndOffset,
if (!endPoint.node)
return false;
aRange->SetEnd(endPoint.node, endPoint.idx);
if (startPoint.node != endPoint.node) {
container = GetElementAsContentOf(endPoint.node);
}
DOMPoint endPointForDOMRange =
ClosestNotGeneratedDOMPoint(endPoint, container);
aRange->SetEnd(endPointForDOMRange.node, endPointForDOMRange.idx);
return true;
}
@@ -395,6 +428,36 @@ HyperTextAccessible::OffsetToDOMPoint(int32_t aOffset)
DOMPoint();
}
DOMPoint
HyperTextAccessible::ClosestNotGeneratedDOMPoint(const DOMPoint& aDOMPoint,
nsIContent* aElementContent)
{
MOZ_ASSERT(aDOMPoint.node, "The node must not be null");
// ::before pseudo element
if (aElementContent &&
aElementContent->NodeInfo()->NameAtom() == nsGkAtoms::mozgeneratedcontentbefore) {
MOZ_ASSERT(aElementContent->GetParent(),
"::before must have parent element");
// The first child of its parent (i.e., immediately after the ::before) is
// good point for a DOM range.
return DOMPoint(aElementContent->GetParent(), 0);
}
// ::after pseudo element
if (aElementContent &&
aElementContent->NodeInfo()->NameAtom() == nsGkAtoms::mozgeneratedcontentafter) {
MOZ_ASSERT(aElementContent->GetParent(),
"::after must have parent element");
// The end of its parent (i.e., immediately before the ::after) is good
// point for a DOM range.
return DOMPoint(aElementContent->GetParent(),
aElementContent->GetParent()->GetChildCount());
}
return aDOMPoint;
}
uint32_t
HyperTextAccessible::FindOffset(uint32_t aOffset, nsDirection aDirection,
nsSelectionAmount aAmount,
@@ -890,6 +953,145 @@ HyperTextAccessible::GetLevelInternal()
return AccessibleWrap::GetLevelInternal();
}
void
HyperTextAccessible::SetMathMLXMLRoles(nsIPersistentProperties* aAttributes)
{
// Add MathML xmlroles based on the position inside the parent.
Accessible* parent = Parent();
if (parent) {
switch (parent->Role()) {
case roles::MATHML_CELL:
case roles::MATHML_ENCLOSED:
case roles::MATHML_ERROR:
case roles::MATHML_MATH:
case roles::MATHML_ROW:
case roles::MATHML_SQUARE_ROOT:
case roles::MATHML_STYLE:
if (Role() == roles::MATHML_OPERATOR) {
// This is an operator inside an <mrow> (or an inferred <mrow>).
// See http://www.w3.org/TR/MathML3/chapter3.html#presm.inferredmrow
// XXX We should probably do something similar for MATHML_FENCED, but
// operators do not appear in the accessible tree. See bug 1175747.
nsIMathMLFrame* mathMLFrame = do_QueryFrame(GetFrame());
if (mathMLFrame) {
nsEmbellishData embellishData;
mathMLFrame->GetEmbellishData(embellishData);
if (NS_MATHML_EMBELLISH_IS_FENCE(embellishData.flags)) {
if (!PrevSibling()) {
nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::xmlroles,
nsGkAtoms::open_fence);
} else if (!NextSibling()) {
nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::xmlroles,
nsGkAtoms::close_fence);
}
}
if (NS_MATHML_EMBELLISH_IS_SEPARATOR(embellishData.flags)) {
nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::xmlroles,
nsGkAtoms::separator_);
}
}
}
break;
case roles::MATHML_FRACTION:
nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::xmlroles,
IndexInParent() == 0 ?
nsGkAtoms::numerator :
nsGkAtoms::denominator);
break;
case roles::MATHML_ROOT:
nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::xmlroles,
IndexInParent() == 0 ? nsGkAtoms::base :
nsGkAtoms::root_index);
break;
case roles::MATHML_SUB:
nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::xmlroles,
IndexInParent() == 0 ? nsGkAtoms::base :
nsGkAtoms::subscript);
break;
case roles::MATHML_SUP:
nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::xmlroles,
IndexInParent() == 0 ? nsGkAtoms::base :
nsGkAtoms::superscript);
break;
case roles::MATHML_SUB_SUP: {
int32_t index = IndexInParent();
nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::xmlroles,
index == 0 ? nsGkAtoms::base :
(index == 1 ? nsGkAtoms::subscript :
nsGkAtoms::superscript));
} break;
case roles::MATHML_UNDER:
nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::xmlroles,
IndexInParent() == 0 ? nsGkAtoms::base :
nsGkAtoms::underscript);
break;
case roles::MATHML_OVER:
nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::xmlroles,
IndexInParent() == 0 ? nsGkAtoms::base :
nsGkAtoms::overscript);
break;
case roles::MATHML_UNDER_OVER: {
int32_t index = IndexInParent();
nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::xmlroles,
index == 0 ? nsGkAtoms::base :
(index == 1 ? nsGkAtoms::underscript :
nsGkAtoms::overscript));
} break;
case roles::MATHML_MULTISCRIPTS: {
// Get the <multiscripts> base.
nsIContent* child;
bool baseFound = false;
for (child = parent->GetContent()->GetFirstChild(); child;
child = child->GetNextSibling()) {
if (child->IsMathMLElement()) {
baseFound = true;
break;
}
}
if (baseFound) {
nsIContent* content = GetContent();
if (child == content) {
// We are the base.
nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::xmlroles,
nsGkAtoms::base);
} else {
// Browse the list of scripts to find us and determine our type.
bool postscript = true;
bool subscript = true;
for (child = child->GetNextSibling(); child;
child = child->GetNextSibling()) {
if (!child->IsMathMLElement())
continue;
if (child->IsMathMLElement(nsGkAtoms::mprescripts_)) {
postscript = false;
subscript = true;
continue;
}
if (child == content) {
if (postscript) {
nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::xmlroles,
subscript ?
nsGkAtoms::subscript :
nsGkAtoms::superscript);
} else {
nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::xmlroles,
subscript ?
nsGkAtoms::presubscript :
nsGkAtoms::presuperscript);
}
break;
}
subscript = !subscript;
}
}
}
} break;
default:
break;
}
}
}
already_AddRefed<nsIPersistentProperties>
HyperTextAccessible::NativeAttributes()
{
@@ -914,8 +1116,11 @@ HyperTextAccessible::NativeAttributes()
}
}
if (HasOwnContent())
if (HasOwnContent()) {
GetAccService()->MarkupAttributes(mContent, attributes);
if (mContent->IsMathMLElement())
SetMathMLXMLRoles(attributes);
}
return attributes.forget();
}
@@ -923,6 +1128,9 @@ HyperTextAccessible::NativeAttributes()
nsIAtom*
HyperTextAccessible::LandmarkRole() const
{
if (!HasOwnContent())
return nullptr;
// For the html landmark elements we expose them like we do ARIA landmarks to
// make AT navigation schemes "just work".
if (mContent->IsHTMLElement(nsGkAtoms::nav)) {
@@ -1222,7 +1430,7 @@ HyperTextAccessible::CaretLineNumber()
{
// Provide the line number for the caret, relative to the
// currently focused node. Use a 1-based index
nsRefPtr<nsFrameSelection> frameSelection = FrameSelection();
RefPtr<nsFrameSelection> frameSelection = FrameSelection();
if (!frameSelection)
return -1;
@@ -1258,7 +1466,7 @@ HyperTextAccessible::CaretLineNumber()
break;
// Add lines for the sibling frames before the caret
nsIFrame *sibling = parentFrame->GetFirstPrincipalChild();
nsIFrame *sibling = parentFrame->PrincipalChildList().FirstChild();
while (sibling && sibling != caretFrame) {
nsAutoLineIterator lineIterForSibling = sibling->GetLineIterator();
if (lineIterForSibling) {
@@ -1286,34 +1494,34 @@ HyperTextAccessible::CaretLineNumber()
return lineNumber;
}
nsIntRect
LayoutDeviceIntRect
HyperTextAccessible::GetCaretRect(nsIWidget** aWidget)
{
*aWidget = nullptr;
nsRefPtr<nsCaret> caret = mDoc->PresShell()->GetCaret();
NS_ENSURE_TRUE(caret, nsIntRect());
RefPtr<nsCaret> caret = mDoc->PresShell()->GetCaret();
NS_ENSURE_TRUE(caret, LayoutDeviceIntRect());
bool isVisible = caret->IsVisible();
if (!isVisible)
return nsIntRect();
return LayoutDeviceIntRect();
nsRect rect;
nsIFrame* frame = caret->GetGeometry(&rect);
if (!frame || rect.IsEmpty())
return nsIntRect();
return LayoutDeviceIntRect();
nsPoint offset;
// Offset from widget origin to the frame origin, which includes chrome
// on the widget.
*aWidget = frame->GetNearestWidget(offset);
NS_ENSURE_TRUE(*aWidget, nsIntRect());
NS_ENSURE_TRUE(*aWidget, LayoutDeviceIntRect());
rect.MoveBy(offset);
nsIntRect caretRect;
caretRect = rect.ToOutsidePixels(frame->PresContext()->AppUnitsPerDevPixel());
LayoutDeviceIntRect caretRect = LayoutDeviceIntRect::FromUnknownRect(
rect.ToOutsidePixels(frame->PresContext()->AppUnitsPerDevPixel()));
// ((content screen origin) - (content offset in the widget)) = widget origin on the screen
caretRect.MoveBy((*aWidget)->WidgetToScreenOffsetUntyped() - (*aWidget)->GetClientOffset());
caretRect.MoveBy((*aWidget)->WidgetToScreenOffset() - (*aWidget)->GetClientOffset());
// Correct for character size, so that caret always matches the size of
// the character. This is important for font size transitions, and is
@@ -1333,7 +1541,7 @@ HyperTextAccessible::GetSelectionDOMRanges(int16_t aType,
nsTArray<nsRange*>* aRanges)
{
// Ignore selection if it is not visible.
nsRefPtr<nsFrameSelection> frameSelection = FrameSelection();
RefPtr<nsFrameSelection> frameSelection = FrameSelection();
if (!frameSelection ||
frameSelection->GetDisplaySelection() <= nsISelectionController::SELECTION_HIDDEN)
return;
@@ -1441,7 +1649,7 @@ HyperTextAccessible::SetSelectionBoundsAt(int32_t aSelectionNum,
if (!domSel)
return false;
nsRefPtr<nsRange> range;
RefPtr<nsRange> range;
uint32_t rangeCount = domSel->RangeCount();
if (aSelectionNum == static_cast<int32_t>(rangeCount))
range = new nsRange(mContent);
@@ -1481,7 +1689,7 @@ void
HyperTextAccessible::ScrollSubstringTo(int32_t aStartOffset, int32_t aEndOffset,
uint32_t aScrollType)
{
nsRefPtr<nsRange> range = new nsRange(mContent);
RefPtr<nsRange> range = new nsRange(mContent);
if (OffsetsToDOMRange(aStartOffset, aEndOffset, range))
nsCoreUtils::ScrollSubstringTo(GetFrame(), range, aScrollType);
}
@@ -1499,7 +1707,7 @@ HyperTextAccessible::ScrollSubstringToPoint(int32_t aStartOffset,
nsIntPoint coords = nsAccUtils::ConvertToScreenCoords(aX, aY, aCoordinateType,
this);
nsRefPtr<nsRange> range = new nsRange(mContent);
RefPtr<nsRange> range = new nsRange(mContent);
if (!OffsetsToDOMRange(aStartOffset, aEndOffset, range))
return;
@@ -1561,7 +1769,7 @@ HyperTextAccessible::EnclosingRange(a11y::TextRange& aRange) const
void
HyperTextAccessible::SelectionRanges(nsTArray<a11y::TextRange>* aRanges) const
{
NS_ASSERTION(aRanges->Length() != 0, "TextRange array supposed to be empty");
MOZ_ASSERT(aRanges->Length() == 0, "TextRange array supposed to be empty");
dom::Selection* sel = DOMSelection();
if (!sel)
@@ -1690,6 +1898,43 @@ HyperTextAccessible::RemoveChild(Accessible* aAccessible)
return Accessible::RemoveChild(aAccessible);
}
Relation
HyperTextAccessible::RelationByType(RelationType aType)
{
Relation rel = Accessible::RelationByType(aType);
switch (aType) {
case RelationType::NODE_CHILD_OF:
if (HasOwnContent() && mContent->IsMathMLElement()) {
Accessible* parent = Parent();
if (parent) {
nsIContent* parentContent = parent->GetContent();
if (parentContent &&
parentContent->IsMathMLElement(nsGkAtoms::mroot_)) {
// Add a relation pointing to the parent <mroot>.
rel.AppendTarget(parent);
}
}
}
break;
case RelationType::NODE_PARENT_OF:
if (HasOwnContent() && mContent->IsMathMLElement(nsGkAtoms::mroot_)) {
Accessible* base = GetChildAt(0);
Accessible* index = GetChildAt(1);
if (base && index) {
// Append the <mroot> children in the order index, base.
rel.AppendTarget(index);
rel.AppendTarget(base);
}
}
break;
default:
break;
}
return rel;
}
void
HyperTextAccessible::CacheChildren()
{
@@ -1700,7 +1945,7 @@ HyperTextAccessible::CacheChildren()
TreeWalker walker(this, mContent);
Accessible* child = nullptr;
Accessible* lastChild = nullptr;
while ((child = walker.NextChild())) {
while ((child = walker.Next())) {
if (lastChild)
AppendChild(lastChild);
@@ -1740,7 +1985,8 @@ HyperTextAccessible::ContentToRenderedOffset(nsIFrame* aFrame, int32_t aContentO
"Call on primary frame only");
nsIFrame::RenderedText text = aFrame->GetRenderedText(aContentOffset,
aContentOffset + 1);
aContentOffset + 1, nsIFrame::TextOffsetType::OFFSETS_IN_CONTENT_TEXT,
nsIFrame::TrailingWhitespace::DONT_TRIM_TRAILING_WHITESPACE);
*aRenderedOffset = text.mOffsetWithinNodeRenderedText;
return NS_OK;
@@ -1764,7 +2010,8 @@ HyperTextAccessible::RenderedToContentOffset(nsIFrame* aFrame, uint32_t aRendere
"Call on primary frame only");
nsIFrame::RenderedText text = aFrame->GetRenderedText(aRenderedOffset,
aRenderedOffset + 1, nsIFrame::TextOffsetType::OFFSETS_IN_RENDERED_TEXT);
aRenderedOffset + 1, nsIFrame::TextOffsetType::OFFSETS_IN_RENDERED_TEXT,
nsIFrame::TrailingWhitespace::DONT_TRIM_TRAILING_WHITESPACE);
*aContentOffset = text.mOffsetWithinNodeText;
return NS_OK;
@@ -1893,7 +2140,7 @@ HyperTextAccessible::GetSpellTextAttr(nsINode* aNode,
uint32_t* aEndOffset,
nsIPersistentProperties* aAttributes)
{
nsRefPtr<nsFrameSelection> fs = FrameSelection();
RefPtr<nsFrameSelection> fs = FrameSelection();
if (!fs)
return;
+30 -3
View File
@@ -62,6 +62,7 @@ public:
virtual void InvalidateChildren() override;
virtual bool RemoveChild(Accessible* aAccessible) override;
virtual Relation RelationByType(RelationType aType) override;
// HyperTextAccessible (static helper method)
@@ -139,7 +140,10 @@ public:
bool aIsEndOffset) const;
/**
* Convert start and end hypertext offsets into DOM range.
* Convert start and end hypertext offsets into DOM range. Note that if
* aStartOffset and/or aEndOffset is in generated content such as ::before or
* ::after, the result range excludes the generated content. See also
* ClosestNotGeneratedDOMPoint() for more information.
*
* @param aStartOffset [in] the given start hypertext offset
* @param aEndOffset [in] the given end hypertext offset
@@ -254,7 +258,7 @@ public:
* @param aInvalidateAfter [in, optional] indicates whether invalidate
* cached offsets for next siblings of the child
*/
int32_t GetChildOffset(Accessible* aChild,
int32_t GetChildOffset(const Accessible* aChild,
bool aInvalidateAfter = false) const
{
int32_t index = GetIndexOf(aChild);
@@ -331,7 +335,7 @@ public:
* @param [out] the widget containing the caret
* @return the caret rect
*/
nsIntRect GetCaretRect(nsIWidget** aWidget);
mozilla::LayoutDeviceIntRect GetCaretRect(nsIWidget** aWidget);
/**
* Return selected regions count within the accessible.
@@ -518,6 +522,23 @@ protected:
nsresult SetSelectionRange(int32_t aStartPos, int32_t aEndPos);
/**
* Convert the given DOM point to a DOM point in non-generated contents.
*
* If aDOMPoint is in ::before, the result is immediately after it.
* If aDOMPoint is in ::after, the result is immediately before it.
*
* @param aDOMPoint [in] A DOM node and an index of its child. This may
* be in a generated content such as ::before or
* ::after.
* @param aElementContent [in] An nsIContent representing an element of
* aDOMPoint.node.
* @return An DOM point which must not be in generated
* contents.
*/
DOMPoint ClosestNotGeneratedDOMPoint(const DOMPoint& aDOMPoint,
nsIContent* aElementContent);
// Helpers
nsresult GetDOMPointByFrameOffset(nsIFrame* aFrame, int32_t aOffset,
Accessible* aAccessible,
@@ -540,6 +561,12 @@ protected:
uint32_t* aStartOffset, uint32_t* aEndOffset,
nsIPersistentProperties* aAttributes);
/**
* Set xml-roles attributes for MathML elements.
* @param aAttributes
*/
void SetMathMLXMLRoles(nsIPersistentProperties* aAttributes);
private:
/**
* End text offsets array.
+13
View File
@@ -8,6 +8,8 @@
#include "Accessible-inl.h"
#include "nsAccUtils.h"
#include "DocAccessible-inl.h"
#include "mozilla/a11y/DocAccessibleParent.h"
#include "mozilla/dom/TabParent.h"
#include "Role.h"
#include "States.h"
@@ -26,6 +28,7 @@ OuterDocAccessible::
OuterDocAccessible(nsIContent* aContent, DocAccessible* aDoc) :
AccessibleWrap(aContent, aDoc)
{
mType = eOuterDocType;
}
OuterDocAccessible::~OuterDocAccessible()
@@ -181,3 +184,13 @@ OuterDocAccessible::CacheChildren()
GetAccService()->GetDocAccessible(innerDoc);
}
}
ProxyAccessible*
OuterDocAccessible::RemoteChildDoc() const
{
dom::TabParent* tab = dom::TabParent::GetFrom(GetContent());
if (!tab)
return nullptr;
return tab->GetTopLevelDocAccessible();
}
+9
View File
@@ -10,6 +10,7 @@
namespace mozilla {
namespace a11y {
class ProxyAccessible;
/**
* Used for <browser>, <frame>, <iframe>, <page> or editor> elements.
@@ -27,6 +28,8 @@ public:
NS_DECL_ISUPPORTS_INHERITED
ProxyAccessible* RemoteChildDoc() const;
// Accessible
virtual void Shutdown() override;
virtual mozilla::a11y::role NativeRole() override;
@@ -44,6 +47,12 @@ protected:
virtual void CacheChildren() override;
};
inline OuterDocAccessible*
Accessible::AsOuterDoc()
{
return IsOuterDoc() ? static_cast<OuterDocAccessible*>(this) : nullptr;
}
} // namespace a11y
} // namespace mozilla
+30 -11
View File
@@ -39,6 +39,7 @@
#include "nsIWebBrowserChrome.h"
#include "nsReadableUtils.h"
#include "nsFocusManager.h"
#include "nsGlobalWindow.h"
#ifdef MOZ_XUL
#include "nsIXULDocument.h"
@@ -310,7 +311,7 @@ RootAccessible::ProcessDOMEvent(nsIDOMEvent* aDOMEvent)
bool isEnabled = (state & (states::CHECKED | states::SELECTED)) != 0;
if (accessible->NeedsDOMUIEvent()) {
nsRefPtr<AccEvent> accEvent =
RefPtr<AccEvent> accEvent =
new AccStateChangeEvent(accessible, states::CHECKED, isEnabled);
nsEventShell::FireEvent(accEvent);
}
@@ -331,7 +332,7 @@ RootAccessible::ProcessDOMEvent(nsIDOMEvent* aDOMEvent)
uint64_t state = accessible->State();
bool isEnabled = !!(state & states::CHECKED);
nsRefPtr<AccEvent> accEvent =
RefPtr<AccEvent> accEvent =
new AccStateChangeEvent(accessible, states::CHECKED, isEnabled);
nsEventShell::FireEvent(accEvent);
}
@@ -351,7 +352,7 @@ RootAccessible::ProcessDOMEvent(nsIDOMEvent* aDOMEvent)
uint64_t state = accessible->State();
bool isEnabled = (state & states::EXPANDED) != 0;
nsRefPtr<AccEvent> accEvent =
RefPtr<AccEvent> accEvent =
new AccStateChangeEvent(accessible, states::EXPANDED, isEnabled);
nsEventShell::FireEvent(accEvent);
return;
@@ -377,7 +378,7 @@ RootAccessible::ProcessDOMEvent(nsIDOMEvent* aDOMEvent)
return;
}
nsRefPtr<AccSelChangeEvent> selChangeEvent =
RefPtr<AccSelChangeEvent> selChangeEvent =
new AccSelChangeEvent(treeAcc, treeItemAcc,
AccSelChangeEvent::eSelectionAdd);
nsEventShell::FireEvent(selChangeEvent);
@@ -451,8 +452,10 @@ RootAccessible::ProcessDOMEvent(nsIDOMEvent* aDOMEvent)
}
else if (accessible->NeedsDOMUIEvent() &&
eventType.EqualsLiteral("ValueChange")) {
targetDocument->FireDelayedEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE,
accessible);
uint32_t event = accessible->HasNumericValue()
? nsIAccessibleEvent::EVENT_VALUE_CHANGE
: nsIAccessibleEvent::EVENT_TEXT_VALUE_CHANGE;
targetDocument->FireDelayedEvent(event, accessible);
}
#ifdef DEBUG_DRAGDROPSTART
else if (eventType.EqualsLiteral("mouseover")) {
@@ -482,10 +485,9 @@ RootAccessible::RelationByType(RelationType aType)
if (!mDocumentNode || aType != RelationType::EMBEDS)
return DocAccessibleWrap::RelationByType(aType);
nsIDOMWindow* rootWindow = mDocumentNode->GetWindow();
nsPIDOMWindow* rootWindow = mDocumentNode->GetWindow();
if (rootWindow) {
nsCOMPtr<nsIDOMWindow> contentWindow;
rootWindow->GetContent(getter_AddRefs(contentWindow));
nsCOMPtr<nsIDOMWindow> contentWindow = nsGlobalWindow::Cast(rootWindow)->GetContent();
if (contentWindow) {
nsCOMPtr<nsIDOMDocument> contentDOMDocument;
contentWindow->GetDocument(getter_AddRefs(contentDOMDocument));
@@ -536,7 +538,7 @@ RootAccessible::HandlePopupShownEvent(Accessible* aAccessible)
roles::Role comboboxRole = combobox->Role();
if (comboboxRole == roles::COMBOBOX ||
comboboxRole == roles::AUTOCOMPLETE) {
nsRefPtr<AccEvent> event =
RefPtr<AccEvent> event =
new AccStateChangeEvent(combobox, states::EXPANDED, true);
if (event)
nsEventShell::FireEvent(event);
@@ -645,7 +647,7 @@ RootAccessible::HandlePopupHidingEvent(nsINode* aPopupNode)
// Fire expanded state change event.
if (notifyOf & kNotifyOfState) {
nsRefPtr<AccEvent> event =
RefPtr<AccEvent> event =
new AccStateChangeEvent(widget, states::EXPANDED, false);
document->FireDelayedEvent(event);
}
@@ -716,3 +718,20 @@ RootAccessible::HandleTreeInvalidatedEvent(nsIDOMEvent* aEvent,
aAccessible->TreeViewInvalidated(startRow, endRow, startCol, endCol);
}
#endif
ProxyAccessible*
RootAccessible::GetPrimaryRemoteTopLevelContentDoc() const
{
nsCOMPtr<nsIDocShellTreeOwner> owner;
mDocumentNode->GetDocShell()->GetTreeOwner(getter_AddRefs(owner));
NS_ENSURE_TRUE(owner, nullptr);
nsCOMPtr<nsITabParent> tabParent;
owner->GetPrimaryTabParent(getter_AddRefs(tabParent));
if (!tabParent) {
return nullptr;
}
auto tab = static_cast<dom::TabParent*>(tabParent.get());
return tab->GetTopLevelDocAccessible();
}
+5
View File
@@ -42,6 +42,11 @@ public:
*/
virtual void DocumentActivated(DocAccessible* aDocument);
/**
* Return the primary remote top level document if any.
*/
ProxyAccessible* GetPrimaryRemoteTopLevelContentDoc() const;
protected:
virtual ~RootAccessible();
-2
View File
@@ -57,5 +57,3 @@ else:
FINAL_LIBRARY = 'xul'
include('/ipc/chromium/chromium-config.mozbuild')
FAIL_ON_WARNINGS = True
+1 -1
View File
@@ -68,7 +68,7 @@ HTMLLabelAccessible::RelationByType(RelationType aType)
{
Relation rel = AccessibleWrap::RelationByType(aType);
if (aType == RelationType::LABEL_FOR) {
nsRefPtr<dom::HTMLLabelElement> label = dom::HTMLLabelElement::FromContent(mContent);
dom::HTMLLabelElement* label = dom::HTMLLabelElement::FromContent(mContent);
rel.AppendTarget(mDoc, label->GetControl());
}
@@ -134,7 +134,7 @@ HTMLRadioButtonAccessible::GetPositionAndSizeInternal(int32_t* aPosInSet,
nsAutoString name;
mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
nsRefPtr<nsContentList> inputElms;
RefPtr<nsContentList> inputElms;
nsCOMPtr<nsIFormControl> formControlNode(do_QueryInterface(mContent));
dom::Element* formElm = formControlNode->GetFormElement();
@@ -486,7 +486,10 @@ HTMLTextFieldAccessible::IsWidget() const
Accessible*
HTMLTextFieldAccessible::ContainerWidget() const
{
return mParent && mParent->Role() == roles::AUTOCOMPLETE ? mParent : nullptr;
if (!mParent || mParent->Role() != roles::AUTOCOMPLETE) {
return nullptr;
}
return mParent;
}
@@ -526,7 +529,7 @@ HTMLFileInputAccessible::HandleAccEvent(AccEvent* aEvent)
event->GetState() == states::INVALID)) {
Accessible* button = GetChildAt(0);
if (button && button->Role() == roles::PUSHBUTTON) {
nsRefPtr<AccStateChangeEvent> childEvent =
RefPtr<AccStateChangeEvent> childEvent =
new AccStateChangeEvent(button, event->GetState(),
event->IsStateEnabled(), event->FromUserInput());
nsEventShell::FireEvent(childEvent);
+4 -4
View File
@@ -87,7 +87,7 @@ HTMLImageMapAccessible::UpdateChildAreas(bool aDoFireEvents)
bool treeChanged = false;
AutoTreeMutation mut(this);
nsRefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(this);
RefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(this);
// Remove areas that are not a valid part of the image map anymore.
for (int32_t childIdx = mChildren.Length() - 1; childIdx >= 0; childIdx--) {
@@ -96,7 +96,7 @@ HTMLImageMapAccessible::UpdateChildAreas(bool aDoFireEvents)
continue;
if (aDoFireEvents) {
nsRefPtr<AccHideEvent> event = new AccHideEvent(area, area->GetContent());
RefPtr<AccHideEvent> event = new AccHideEvent(area, area->GetContent());
mDoc->FireDelayedEvent(event);
reorderEvent->AddSubMutationEvent(event);
}
@@ -112,7 +112,7 @@ HTMLImageMapAccessible::UpdateChildAreas(bool aDoFireEvents)
Accessible* area = mChildren.SafeElementAt(idx);
if (!area || area->GetContent() != areaContent) {
nsRefPtr<Accessible> area = new HTMLAreaAccessible(areaContent, mDoc);
RefPtr<Accessible> area = new HTMLAreaAccessible(areaContent, mDoc);
mDoc->BindToDocument(area, aria::GetRoleMap(areaContent));
if (!InsertChildAt(idx, area)) {
@@ -121,7 +121,7 @@ HTMLImageMapAccessible::UpdateChildAreas(bool aDoFireEvents)
}
if (aDoFireEvents) {
nsRefPtr<AccShowEvent> event = new AccShowEvent(area, areaContent);
RefPtr<AccShowEvent> event = new AccShowEvent(area);
mDoc->FireDelayedEvent(event);
reorderEvent->AddSubMutationEvent(event);
}
+12 -3
View File
@@ -102,19 +102,28 @@ HTMLLIAccessible::UpdateBullet(bool aHasBullet)
return;
}
RefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(this);
AutoTreeMutation mut(this);
DocAccessible* document = Document();
if (aHasBullet) {
mBullet = new HTMLListBulletAccessible(mContent, mDoc);
document->BindToDocument(mBullet, nullptr);
InsertChildAt(0, mBullet);
RefPtr<AccShowEvent> event = new AccShowEvent(mBullet);
mDoc->FireDelayedEvent(event);
reorderEvent->AddSubMutationEvent(event);
} else {
RefPtr<AccHideEvent> event = new AccHideEvent(mBullet, mBullet->GetContent());
mDoc->FireDelayedEvent(event);
reorderEvent->AddSubMutationEvent(event);
RemoveChild(mBullet);
document->UnbindFromDocument(mBullet);
mBullet = nullptr;
}
// XXXtodo: fire show/hide and reorder events. That's hard to make it
// right now because coalescence happens by DOM node.
mDoc->FireDelayedEvent(reorderEvent);
}
////////////////////////////////////////////////////////////////////////////////
+1 -1
View File
@@ -64,7 +64,7 @@ protected:
virtual void CacheChildren() override;
private:
nsRefPtr<HTMLListBulletAccessible> mBullet;
RefPtr<HTMLListBulletAccessible> mBullet;
};
+1 -1
View File
@@ -134,7 +134,7 @@ HTMLSelectListAccessible::CacheChildren()
nsGkAtoms::optgroup)) {
// Get an accessible for option or optgroup and cache it.
nsRefPtr<Accessible> accessible =
RefPtr<Accessible> accessible =
GetAccService()->GetOrCreateAccessible(childContent, this);
if (accessible)
AppendChild(accessible);
+1 -1
View File
@@ -196,7 +196,7 @@ protected:
Accessible* SelectedOption() const;
private:
nsRefPtr<HTMLComboboxListAccessible> mListAccessible;
RefPtr<HTMLComboboxListAccessible> mListAccessible;
};
/*
+74 -34
View File
@@ -60,6 +60,9 @@ NS_IMPL_ISUPPORTS_INHERITED0(HTMLTableCellAccessible, HyperTextAccessible)
role
HTMLTableCellAccessible::NativeRole()
{
if (mContent->IsMathMLElement(nsGkAtoms::mtd_)) {
return roles::MATHML_CELL;
}
return roles::CELL;
}
@@ -140,6 +143,20 @@ HTMLTableCellAccessible::NativeAttributes()
return attributes.forget();
}
GroupPos
HTMLTableCellAccessible::GroupPosition()
{
int32_t count = 0, index = 0;
TableAccessible* table = Table();
if (table && nsCoreUtils::GetUIntAttr(table->AsAccessible()->GetContent(),
nsGkAtoms::aria_colcount, &count) &&
nsCoreUtils::GetUIntAttr(mContent, nsGkAtoms::aria_colindex, &index)) {
return GroupPos(0, index, count);
}
return HyperTextAccessibleWrap::GroupPosition();
}
////////////////////////////////////////////////////////////////////////////////
// HTMLTableCellAccessible: TableCellAccessible implementation
@@ -148,8 +165,7 @@ HTMLTableCellAccessible::Table() const
{
Accessible* parent = const_cast<HTMLTableCellAccessible*>(this);
while ((parent = parent->Parent())) {
roles::Role role = parent->Role();
if (role == roles::TABLE || role == roles::TREE_TABLE)
if (parent->IsTable())
return parent->AsTable();
}
@@ -297,46 +313,43 @@ HTMLTableHeaderCellAccessible::NativeRole()
{
// Check value of @scope attribute.
static nsIContent::AttrValuesArray scopeValues[] =
{&nsGkAtoms::col, &nsGkAtoms::row, nullptr};
{ &nsGkAtoms::col, &nsGkAtoms::colgroup,
&nsGkAtoms::row, &nsGkAtoms::rowgroup, nullptr };
int32_t valueIdx =
mContent->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::scope,
scopeValues, eCaseMatters);
switch (valueIdx) {
case 0:
return roles::COLUMNHEADER;
case 1:
return roles::COLUMNHEADER;
case 2:
case 3:
return roles::ROWHEADER;
}
// Assume it's columnheader if there are headers in siblings, otherwise
// rowheader.
// This should iterate the flattened tree
nsIContent* parentContent = mContent->GetParent();
if (!parentContent) {
NS_ERROR("Deattached content on alive accessible?");
TableAccessible* table = Table();
if (!table)
return roles::NOTHING;
}
for (nsIContent* siblingContent = mContent->GetPreviousSibling(); siblingContent;
siblingContent = siblingContent->GetPreviousSibling()) {
if (siblingContent->IsElement()) {
return nsCoreUtils::IsHTMLTableHeader(siblingContent) ?
roles::COLUMNHEADER : roles::ROWHEADER;
}
}
// If the cell next to this one is not a header cell then assume this cell is
// a row header for it.
uint32_t rowIdx = RowIdx(), colIdx = ColIdx();
Accessible* cell = table->CellAt(rowIdx, colIdx + ColExtent());
if (cell && !nsCoreUtils::IsHTMLTableHeader(cell->GetContent()))
return roles::ROWHEADER;
for (nsIContent* siblingContent = mContent->GetNextSibling(); siblingContent;
siblingContent = siblingContent->GetNextSibling()) {
if (siblingContent->IsElement()) {
return nsCoreUtils::IsHTMLTableHeader(siblingContent) ?
roles::COLUMNHEADER : roles::ROWHEADER;
}
}
// If the cell below this one is not a header cell then assume this cell is
// a column header for it.
uint32_t rowExtent = RowExtent();
cell = table->CellAt(rowIdx + rowExtent, colIdx);
if (cell && !nsCoreUtils::IsHTMLTableHeader(cell->GetContent()))
return roles::COLUMNHEADER;
// No elements in siblings what means the table has one column only. Therefore
// it should be column header.
return roles::COLUMNHEADER;
// Otherwise if this cell is surrounded by header cells only then make a guess
// based on its cell spanning. In other words if it is row spanned then assume
// it's a row header, otherwise it's a column header.
return rowExtent > 1 ? roles::ROWHEADER : roles::COLUMNHEADER;
}
@@ -349,9 +362,28 @@ NS_IMPL_ISUPPORTS_INHERITED0(HTMLTableRowAccessible, Accessible)
role
HTMLTableRowAccessible::NativeRole()
{
if (mContent->IsMathMLElement(nsGkAtoms::mtr_)) {
return roles::MATHML_TABLE_ROW;
} else if (mContent->IsMathMLElement(nsGkAtoms::mlabeledtr_)) {
return roles::MATHML_LABELED_ROW;
}
return roles::ROW;
}
GroupPos
HTMLTableRowAccessible::GroupPosition()
{
int32_t count = 0, index = 0;
Accessible* table = nsAccUtils::TableFor(this);
if (table && nsCoreUtils::GetUIntAttr(table->GetContent(),
nsGkAtoms::aria_rowcount, &count) &&
nsCoreUtils::GetUIntAttr(mContent, nsGkAtoms::aria_rowindex, &index)) {
return GroupPos(0, index, count);
}
return AccessibleWrap::GroupPosition();
}
////////////////////////////////////////////////////////////////////////////////
// HTMLTableAccessible
////////////////////////////////////////////////////////////////////////////////
@@ -371,10 +403,10 @@ HTMLTableAccessible::CacheChildren()
TreeWalker walker(this, mContent);
Accessible* child = nullptr;
while ((child = walker.NextChild())) {
while ((child = walker.Next())) {
if (child->Role() == roles::CAPTION) {
InsertChildAt(0, child);
while ((child = walker.NextChild()) && AppendChild(child));
while ((child = walker.Next()) && AppendChild(child));
break;
}
AppendChild(child);
@@ -384,6 +416,9 @@ HTMLTableAccessible::CacheChildren()
role
HTMLTableAccessible::NativeRole()
{
if (mContent->IsMathMLElement(nsGkAtoms::mtable_)) {
return roles::MATHML_TABLE;
}
return roles::TABLE;
}
@@ -421,6 +456,11 @@ HTMLTableAccessible::NativeAttributes()
{
nsCOMPtr<nsIPersistentProperties> attributes =
AccessibleWrap::NativeAttributes();
if (mContent->IsMathMLElement(nsGkAtoms::mtable_)) {
GetAccService()->MarkupAttributes(mContent, attributes);
}
if (IsProbablyLayoutTable()) {
nsAutoString unused;
attributes->SetStringProperty(NS_LITERAL_CSTRING("layout-guess"),
@@ -772,7 +812,7 @@ HTMLTableAccessible::AddRowOrColumnToSelection(int32_t aIndex, uint32_t aTarget)
count = RowCount();
nsIPresShell* presShell(mDoc->PresShell());
nsRefPtr<nsFrameSelection> tableSelection =
RefPtr<nsFrameSelection> tableSelection =
const_cast<nsFrameSelection*>(presShell->ConstFrameSelection());
for (uint32_t idx = 0; idx < count; idx++) {
@@ -798,7 +838,7 @@ HTMLTableAccessible::RemoveRowsOrColumnsFromSelection(int32_t aIndex,
return NS_OK;
nsIPresShell* presShell(mDoc->PresShell());
nsRefPtr<nsFrameSelection> tableSelection =
RefPtr<nsFrameSelection> tableSelection =
const_cast<nsFrameSelection*>(presShell->ConstFrameSelection());
bool doUnselectRow = (aTarget == nsISelectionPrivate::TABLESELECTION_ROW);
@@ -929,8 +969,8 @@ HTMLTableAccessible::IsProbablyLayoutTable()
RETURN_LAYOUT_ANSWER(false, "Has role attribute, weak role, and role is table");
}
if (!mContent->IsHTMLElement(nsGkAtoms::table))
RETURN_LAYOUT_ANSWER(true, "table built by CSS display:table style");
NS_ASSERTION(mContent->IsHTMLElement(nsGkAtoms::table),
"table should not be built by CSS display:table style");
// Check if datatable attribute has "0" value.
if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::datatable,
+2
View File
@@ -33,6 +33,7 @@ public:
virtual uint64_t NativeState() override;
virtual uint64_t NativeInteractiveState() const override;
virtual already_AddRefed<nsIPersistentProperties> NativeAttributes() override;
virtual mozilla::a11y::GroupPos GroupPosition() override;
// TableCellAccessible
virtual TableAccessible* Table() const override;
@@ -89,6 +90,7 @@ public:
// Accessible
virtual a11y::role NativeRole() override;
virtual mozilla::a11y::GroupPos GroupPosition() override;
protected:
virtual ~HTMLTableRowAccessible() { }
-2
View File
@@ -43,5 +43,3 @@ else:
]
FINAL_LIBRARY = 'xul'
FAIL_ON_WARNINGS = True
+1
View File
@@ -11,6 +11,7 @@ GARBAGE += $(MIDL_GENERATED_FILES)
MIDL_INTERFACES = \
Accessible2.idl \
Accessible2_2.idl \
Accessible2_3.idl \
AccessibleAction.idl \
AccessibleApplication.idl \
AccessibleComponent.idl \
-1
View File
@@ -13,7 +13,6 @@ DEFFILE = SRCDIR + '/IA2Marshal.def'
OS_LIBS += [
'uuid',
'kernel32',
'rpcns4',
'rpcrt4',
'ole32',
'oleaut32',
-1
View File
@@ -22,7 +22,6 @@ DEFFILE = SRCDIR + '/AccessibleMarshal.def'
OS_LIBS += [
'kernel32',
'rpcns4',
'rpcrt4',
'oleaut32',
]
+1 -7
View File
@@ -30,7 +30,7 @@ class Accessible;
* Mozilla creates the implementations of nsIAccessible on demand.
* See http://www.mozilla.org/projects/ui/accessibility for more information.
*/
[scriptable, uuid(66b110b0-c25a-4784-8623-f6ba40c7cfee)]
[scriptable, uuid(de2869d9-563c-4943-996b-31a4daa4d097)]
interface nsIAccessible : nsISupports
{
/**
@@ -231,12 +231,6 @@ interface nsIAccessible : nsISupports
*/
void setSelected(in boolean isSelected);
/**
* Extend the current selection from its current accessible anchor node
* to this accessible
*/
void extendSelection();
/**
* Select this accessible node only
*/
@@ -8,7 +8,7 @@
/**
* Fired when the caret changes position in text.
*/
[scriptable, builtinclass, uuid(5675c486-a230-4d85-a4bd-33670826d5ff)]
[scriptable, builtinclass, uuid(ed1982e4-57d7-41a8-8cd8-9023f809383e)]
interface nsIAccessibleCaretMoveEvent: nsIAccessibleEvent
{
/**
+8 -3
View File
@@ -25,7 +25,7 @@ interface nsIDOMNode;
* if (NS_SUCCEEDED(rv))
* rv = observerService->AddObserver(this, "accessible-event", PR_TRUE);
*/
[scriptable, builtinclass, uuid(7f66a33a-9ed7-4fd4-87a8-e431b0f43368)]
[scriptable, builtinclass, uuid(20c69a40-6c2c-42a3-a578-6f4473aab9dd)]
interface nsIAccessibleEvent : nsISupports
{
/**
@@ -75,7 +75,7 @@ interface nsIAccessibleEvent : nsISupports
const unsigned long EVENT_DESCRIPTION_CHANGE = 0x0009;
/**
* An object's Value property has changed.
* An object's numeric Value has changed.
*/
const unsigned long EVENT_VALUE_CHANGE = 0x000A;
@@ -412,10 +412,15 @@ interface nsIAccessibleEvent : nsISupports
*/
const unsigned long EVENT_VIRTUALCURSOR_CHANGED = 0x0056;
/**
* An object's text Value has changed.
*/
const unsigned long EVENT_TEXT_VALUE_CHANGE = 0x0057;
/**
* Help make sure event map does not get out-of-line.
*/
const unsigned long EVENT_LAST_ENTRY = 0x0057;
const unsigned long EVENT_LAST_ENTRY = 0x0058;
/**
* The type of event, based on the enumerated event values
@@ -8,7 +8,7 @@
/**
* Fired when a accessible and its subtree are removed from the tree.
*/
[scriptable, builtinclass, uuid(a2bd2eca-3afa-489b-afb2-f93ef32ad99c)]
[scriptable, builtinclass, uuid(2051709a-4e0d-4be5-873d-b49d1dee35fa)]
interface nsIAccessibleHideEvent: nsIAccessibleEvent
{
/**
@@ -11,7 +11,7 @@ interface nsIAtom;
/**
* Fired when an attribute of an accessible changes.
*/
[scriptable, builtinclass, uuid(4CA96609-23C8-4771-86E7-77C8B651CA24)]
[scriptable, builtinclass, uuid(ce41add2-096e-4606-b1ca-7408c6d5b4c3)]
interface nsIAccessibleObjectAttributeChangedEvent : nsIAccessibleEvent
{
/**
+19 -23
View File
@@ -8,7 +8,7 @@
/**
* Defines cross platform (Gecko) roles.
*/
[scriptable, uuid(55581ec3-ba6e-4805-8108-260ed34cdcbb)]
[scriptable, uuid(da0c7824-147c-11e5-917c-60a44c717042)]
interface nsIAccessibleRole : nsISupports
{
/**
@@ -920,53 +920,49 @@ interface nsIAccessibleRole : nsISupports
*/
const unsigned long ROLE_MATHML_ERROR = 157;
/**
* A MathML semantics annotation element (semantics in MathML).
*/
const unsigned long ROLE_MATHML_SEMANTICS = 158;
/**
* A MathML annotation (annotation in MathML).
*/
const unsigned long ROLE_MATHML_ANNOTATION = 159;
/**
* A MathML XML annotation (annotation-xml in MathML).
*/
const unsigned long ROLE_MATHML_XML_ANNOTATION = 160;
/**
* A MathML stacked (rows of numbers) element (mstack in MathML).
*/
const unsigned long ROLE_MATHML_STACK = 161;
const unsigned long ROLE_MATHML_STACK = 158;
/**
* A MathML long division element (mlongdiv in MathML).
*/
const unsigned long ROLE_MATHML_LONG_DIVISION = 162;
const unsigned long ROLE_MATHML_LONG_DIVISION = 159;
/**
* A MathML stack group (msgroup in MathML).
*/
const unsigned long ROLE_MATHML_STACK_GROUP = 163;
const unsigned long ROLE_MATHML_STACK_GROUP = 160;
/**
* A MathML stack row (msrow in MathML).
*/
const unsigned long ROLE_MATHML_STACK_ROW = 164;
const unsigned long ROLE_MATHML_STACK_ROW = 161;
/**
* MathML carries, borrows, or crossouts for a row (mscarries in MathML).
*/
const unsigned long ROLE_MATHML_STACK_CARRIES = 165;
const unsigned long ROLE_MATHML_STACK_CARRIES = 162;
/**
* A MathML carry, borrow, or crossout for a column (mscarry in MathML).
*/
const unsigned long ROLE_MATHML_STACK_CARRY = 166;
const unsigned long ROLE_MATHML_STACK_CARRY = 163;
/**
* A MathML line in a stack (msline in MathML).
*/
const unsigned long ROLE_MATHML_STACK_LINE = 167;
const unsigned long ROLE_MATHML_STACK_LINE = 164;
/**
* A group containing radio buttons
*/
const unsigned long ROLE_RADIO_GROUP = 165;
/**
* A text container exposing brief amount of information. See related
* TEXT_CONTAINER role.
*/
const unsigned long ROLE_TEXT = 166;
};
@@ -8,7 +8,7 @@
/**
* Fired when a state of an accessible changes.
*/
[scriptable, builtinclass, uuid(0d2d77c5-7b16-4a15-8b20-c484ceb5ac0d)]
[scriptable, builtinclass, uuid(58b74954-1835-46ed-9ccd-c906490106f6)]
interface nsIAccessibleStateChangeEvent : nsIAccessibleEvent
{
/**

Some files were not shown because too many files have changed in this diff Show More