--- a/accessible/generic/Accessible.cpp
+++ b/accessible/generic/Accessible.cpp
@@ -437,18 +437,19 @@ Accessible::NativeState()
}
// Check if a XUL element has the popup attribute (an attached popup menu).
if (HasOwnContent() && mContent->IsXULElement() &&
mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::popup))
state |= states::HASPOPUP;
// Bypass the link states specialization for non links.
- if (!mRoleMapEntry || mRoleMapEntry->roleRule == kUseNativeRole ||
- mRoleMapEntry->role == roles::LINK)
+ const nsRoleMapEntry* roleMapEntry = ARIARoleMap();
+ if (!roleMapEntry || roleMapEntry->roleRule == kUseNativeRole ||
+ roleMapEntry->role == roles::LINK)
state |= NativeLinkState();
return state;
}
uint64_t
Accessible::NativeInteractiveState() const
{
@@ -685,17 +686,17 @@ void
Accessible::SetSelected(bool aSelect)
{
if (!HasOwnContent())
return;
Accessible* select = nsAccUtils::GetSelectableContainer(this, State());
if (select) {
if (select->State() & states::MULTISELECTABLE) {
- if (mRoleMapEntry) {
+ if (ARIARoleMap()) {
if (aSelect) {
mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::aria_selected,
NS_LITERAL_STRING("true"), true);
} else {
mContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::aria_selected, true);
}
}
return;
@@ -924,26 +925,27 @@ Accessible::Attributes()
if (IsARIAHidden()) {
nsAccUtils::SetAccAttr(attributes, nsGkAtoms::hidden,
NS_LITERAL_STRING("true"));
}
// If there is no aria-live attribute then expose default value of 'live'
// object attribute used for ARIA role of this accessible.
- if (mRoleMapEntry) {
- if (mRoleMapEntry->Is(nsGkAtoms::searchbox)) {
+ const nsRoleMapEntry* roleMapEntry = ARIARoleMap();
+ if (roleMapEntry) {
+ if (roleMapEntry->Is(nsGkAtoms::searchbox)) {
nsAccUtils::SetAccAttr(attributes, nsGkAtoms::textInputType,
NS_LITERAL_STRING("search"));
}
nsAutoString live;
nsAccUtils::GetAccAttr(attributes, nsGkAtoms::live, live);
if (live.IsEmpty()) {
- if (nsAccUtils::GetLiveAttrValue(mRoleMapEntry->liveAttRule, live))
+ if (nsAccUtils::GetLiveAttrValue(roleMapEntry->liveAttRule, live))
nsAccUtils::SetAccAttr(attributes, nsGkAtoms::live, live);
}
}
return attributes.forget();
}
already_AddRefed<nsIPersistentProperties>
@@ -1138,23 +1140,24 @@ Accessible::State()
uint64_t state = NativeState();
// Apply ARIA states to be sure accessible states will be overridden.
ApplyARIAState(&state);
// If this is an ARIA item of the selectable widget and if it's focused and
// not marked unselected explicitly (i.e. aria-selected="false") then expose
// it as selected to make ARIA widget authors life easier.
- if (mRoleMapEntry && !(state & states::SELECTED) &&
+ const nsRoleMapEntry* roleMapEntry = ARIARoleMap();
+ if (roleMapEntry && !(state & states::SELECTED) &&
!mContent->AttrValueIs(kNameSpaceID_None,
nsGkAtoms::aria_selected,
nsGkAtoms::_false, eCaseMatters)) {
// Special case for tabs: focused tab or focus inside related tab panel
// implies selected state.
- if (mRoleMapEntry->role == roles::PAGETAB) {
+ if (roleMapEntry->role == roles::PAGETAB) {
if (state & states::FOCUSED) {
state |= states::SELECTED;
} else {
// If focus is in a child of the tab panel surely the tab is selected!
Relation rel = RelationByType(RelationType::LABEL_FOR);
Accessible* relTarget = nullptr;
while ((relTarget = rel.Next())) {
if (relTarget->Role() == roles::PROPERTYPAGE &&
@@ -1217,22 +1220,23 @@ Accessible::ApplyARIAState(uint64_t* aSt
if (!mContent->IsElement())
return;
dom::Element* element = mContent->AsElement();
// Test for universal states first
*aState |= aria::UniversalStatesFor(element);
- if (mRoleMapEntry) {
+ const nsRoleMapEntry* roleMapEntry = ARIARoleMap();
+ if (roleMapEntry) {
// We only force the readonly bit off if we have a real mapping for the aria
// role. This preserves the ability for screen readers to use readonly
// (primarily on the document) as the hint for creating a virtual buffer.
- if (mRoleMapEntry->role != roles::NOTHING)
+ if (roleMapEntry->role != roles::NOTHING)
*aState &= ~states::READONLY;
if (mContent->HasID()) {
// 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();
@@ -1258,31 +1262,31 @@ Accessible::ApplyARIAState(uint64_t* aSt
}
}
// special case: A native button element whose role got transformed by ARIA to a toggle button
// Also applies to togglable button menus, like in the Dev Tools Web Console.
if (IsButton() || IsMenuButton())
aria::MapToState(aria::eARIAPressed, element, aState);
- if (!mRoleMapEntry)
+ if (!roleMapEntry)
return;
- *aState |= mRoleMapEntry->state;
-
- if (aria::MapToState(mRoleMapEntry->attributeMap1, element, aState) &&
- aria::MapToState(mRoleMapEntry->attributeMap2, element, aState) &&
- aria::MapToState(mRoleMapEntry->attributeMap3, element, aState))
- aria::MapToState(mRoleMapEntry->attributeMap4, element, aState);
+ *aState |= roleMapEntry->state;
+
+ if (aria::MapToState(roleMapEntry->attributeMap1, element, aState) &&
+ aria::MapToState(roleMapEntry->attributeMap2, element, aState) &&
+ aria::MapToState(roleMapEntry->attributeMap3, element, aState))
+ aria::MapToState(roleMapEntry->attributeMap4, element, aState);
// ARIA gridcell inherits editable/readonly states from the grid until it's
// overridden.
- if ((mRoleMapEntry->Is(nsGkAtoms::gridcell) ||
- mRoleMapEntry->Is(nsGkAtoms::columnheader) ||
- mRoleMapEntry->Is(nsGkAtoms::rowheader)) &&
+ if ((roleMapEntry->Is(nsGkAtoms::gridcell) ||
+ roleMapEntry->Is(nsGkAtoms::columnheader) ||
+ roleMapEntry->Is(nsGkAtoms::rowheader)) &&
!(*aState & (states::READONLY | states::EDITABLE))) {
const TableCellAccessible* cell = AsTableCell();
if (cell) {
TableAccessible* table = cell->Table();
if (table) {
Accessible* grid = table->AsAccessible();
uint64_t gridState = 0;
grid->ApplyARIAState(&gridState);
@@ -1290,39 +1294,40 @@ Accessible::ApplyARIAState(uint64_t* aSt
}
}
}
}
void
Accessible::Value(nsString& aValue)
{
- if (!mRoleMapEntry)
+ const nsRoleMapEntry* roleMapEntry = ARIARoleMap();
+ if (!roleMapEntry)
return;
- if (mRoleMapEntry->valueRule != eNoValue) {
+ if (roleMapEntry->valueRule != eNoValue) {
// aria-valuenow is a number, and aria-valuetext is the optional text
// equivalent. For the string value, we will try the optional text
// equivalent first.
if (!mContent->GetAttr(kNameSpaceID_None,
nsGkAtoms::aria_valuetext, aValue)) {
mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::aria_valuenow,
aValue);
}
return;
}
// Value of textbox is a textified subtree.
- if (mRoleMapEntry->Is(nsGkAtoms::textbox)) {
+ if (roleMapEntry->Is(nsGkAtoms::textbox)) {
nsTextEquivUtils::GetTextEquivFromSubtree(this, aValue);
return;
}
// Value of combobox is a text of current or selected item.
- if (mRoleMapEntry->Is(nsGkAtoms::combobox)) {
+ if (roleMapEntry->Is(nsGkAtoms::combobox)) {
Accessible* option = CurrentItem();
if (!option) {
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;
@@ -1357,17 +1362,18 @@ double
Accessible::CurValue() const
{
return AttrNumericValue(nsGkAtoms::aria_valuenow);
}
bool
Accessible::SetCurValue(double aValue)
{
- if (!mRoleMapEntry || mRoleMapEntry->valueRule == eNoValue)
+ const nsRoleMapEntry* roleMapEntry = ARIARoleMap();
+ if (!roleMapEntry || roleMapEntry->valueRule == eNoValue)
return false;
const uint32_t kValueCannotChange = states::READONLY | states::UNAVAILABLE;
if (State() & kValueCannotChange)
return false;
double checkValue = MinValue();
if (!IsNaN(checkValue) && aValue < checkValue)
@@ -1431,18 +1437,19 @@ Accessible::ARIATransformRole(role aRole
}
return aRole;
}
nsIAtom*
Accessible::LandmarkRole() const
{
- return mRoleMapEntry && mRoleMapEntry->IsOfType(eLandmark) ?
- *(mRoleMapEntry->roleAtom) : nullptr;
+ const nsRoleMapEntry* roleMapEntry = ARIARoleMap();
+ return roleMapEntry && roleMapEntry->IsOfType(eLandmark) ?
+ *(roleMapEntry->roleAtom) : nullptr;
}
role
Accessible::NativeRole()
{
return roles::NOTHING;
}
@@ -1545,16 +1552,18 @@ Accessible::GetAtomicRegion() const
}
Relation
Accessible::RelationByType(RelationType aType)
{
if (!HasOwnContent())
return Relation();
+ const nsRoleMapEntry* roleMapEntry = ARIARoleMap();
+
// Relationships are defined on the same content node that the role would be
// defined on.
switch (aType) {
case RelationType::LABELLED_BY: {
Relation rel(new IDRefsIterator(mDoc, mContent,
nsGkAtoms::aria_labelledby));
if (mContent->IsHTMLElement()) {
rel.AppendIter(new HTMLLabelIterator(Document(), this));
@@ -1596,19 +1605,19 @@ Accessible::RelationByType(RelationType
return rel;
}
case RelationType::NODE_CHILD_OF: {
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 ||
- mRoleMapEntry->role == roles::LISTITEM ||
- mRoleMapEntry->role == roles::ROW)) {
+ if (roleMapEntry && (roleMapEntry->role == roles::OUTLINEITEM ||
+ roleMapEntry->role == roles::LISTITEM ||
+ roleMapEntry->role == roles::ROW)) {
rel.AppendTarget(GetGroupInfo()->ConceptualParent());
}
// If accessible is in its own Window, or is the root of a document,
// then we should provide NODE_CHILD_OF relation so that MSAA clients
// can easily get to true parent instead of getting to oleacc's
// ROLE_WINDOW accessible which will prevent us from going up further
// (because it is system generated and has no idea about the hierarchy
@@ -1624,23 +1633,23 @@ Accessible::RelationByType(RelationType
}
return rel;
}
case RelationType::NODE_PARENT_OF: {
// ARIA tree or treegrid can do the hierarchy by @aria-level, ARIA trees
// also can be organized by groups.
- if (mRoleMapEntry &&
- (mRoleMapEntry->role == roles::OUTLINEITEM ||
- mRoleMapEntry->role == roles::LISTITEM ||
- mRoleMapEntry->role == roles::ROW ||
- mRoleMapEntry->role == roles::OUTLINE ||
- mRoleMapEntry->role == roles::LIST ||
- mRoleMapEntry->role == roles::TREE_TABLE)) {
+ if (roleMapEntry &&
+ (roleMapEntry->role == roles::OUTLINEITEM ||
+ roleMapEntry->role == roles::LISTITEM ||
+ roleMapEntry->role == roles::ROW ||
+ roleMapEntry->role == roles::OUTLINE ||
+ roleMapEntry->role == roles::LIST ||
+ roleMapEntry->role == roles::TREE_TABLE)) {
return Relation(new ItemIterator(this));
}
return Relation();
}
case RelationType::CONTROLLED_BY:
return Relation(new RelatedAccIterator(Document(), mContent,
@@ -2438,17 +2447,18 @@ Accessible::IsWidget() const
bool
Accessible::IsActiveWidget() const
{
if (FocusMgr()->HasDOMFocus(mContent))
return true;
// If text entry of combobox widget has a focus then the combobox widget is
// active.
- if (mRoleMapEntry && mRoleMapEntry->Is(nsGkAtoms::combobox)) {
+ const nsRoleMapEntry* roleMapEntry = ARIARoleMap();
+ if (roleMapEntry && roleMapEntry->Is(nsGkAtoms::combobox)) {
uint32_t childCount = ChildCount();
for (uint32_t idx = 0; idx < childCount; idx++) {
Accessible* child = mChildren.ElementAt(idx);
if (child->Role() == roles::ENTRY)
return FocusMgr()->HasDOMFocus(child->GetContent());
}
}
@@ -2567,17 +2577,18 @@ Accessible::GetSiblingAtOffset(int32_t a
*aError = NS_ERROR_UNEXPECTED;
return child;
}
double
Accessible::AttrNumericValue(nsIAtom* aAttr) const
{
- if (!mRoleMapEntry || mRoleMapEntry->valueRule == eNoValue)
+ const nsRoleMapEntry* roleMapEntry = ARIARoleMap();
+ if (!roleMapEntry || roleMapEntry->valueRule == eNoValue)
return UnspecifiedNaN<double>();
nsAutoString attrValue;
if (!mContent->GetAttr(kNameSpaceID_None, aAttr, attrValue))
return UnspecifiedNaN<double>();
nsresult error = NS_OK;
double value = attrValue.ToDouble(&error);
@@ -2597,19 +2608,20 @@ Accessible::GetActionRule() const
// Has registered 'click' event handler.
bool isOnclick = nsCoreUtils::HasClickListener(mContent);
if (isOnclick)
return eClickAction;
// Get an action based on ARIA role.
- if (mRoleMapEntry &&
- mRoleMapEntry->actionRule != eNoAction)
- return mRoleMapEntry->actionRule;
+ const nsRoleMapEntry* roleMapEntry = ARIARoleMap();
+ if (roleMapEntry &&
+ roleMapEntry->actionRule != eNoAction)
+ return roleMapEntry->actionRule;
// Get an action based on ARIA attribute.
if (nsAccUtils::HasDefinedARIAToken(mContent,
nsGkAtoms::aria_expanded))
return eExpandAction;
return eNoAction;
}