/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* 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/. */
void nsAccUtils::SetLiveContainerAttributes(AccAttributes* aAttributes,
Accessible* aStartAcc) {
nsAutoString live, relevant, busy;
nsStaticAtom* role = nullptr;
Maybe<bool> atomic; for (Accessible* acc = aStartAcc; acc; acc = acc->Parent()) { // We only want the nearest value for each attribute. If we already got a // value, don't bother fetching it from further ancestors. constbool wasLiveEmpty = live.IsEmpty();
acc->LiveRegionAttributes(wasLiveEmpty ? &live : nullptr,
relevant.IsEmpty() ? &relevant : nullptr,
atomic ? nullptr : &atomic,
busy.IsEmpty() ? &busy : nullptr); if (wasLiveEmpty) { const nsRoleMapEntry* roleMap = acc->ARIARoleMap(); if (live.IsEmpty()) { // aria-live wasn't explicitly set. See if an aria-live value is implied // by an ARIA role or markup element. if (roleMap) {
GetLiveAttrValue(roleMap->liveAttRule, live);
} elseif (nsStaticAtom* value = GetAccService()->MarkupAttribute(
acc, nsGkAtoms::aria_live)) {
value->ToString(live);
}
} if (!live.IsEmpty() && roleMap &&
roleMap->roleAtom != nsGkAtoms::_empty) {
role = roleMap->roleAtom;
}
} if (acc->IsDoc()) { break;
}
} if (!live.IsEmpty()) {
aAttributes->SetAttribute(nsGkAtoms::containerLive, std::move(live));
} if (role) {
aAttributes->SetAttribute(nsGkAtoms::containerLiveRole, std::move(role));
} if (!relevant.IsEmpty()) {
aAttributes->SetAttribute(nsGkAtoms::containerRelevant,
std::move(relevant));
} if (atomic) {
aAttributes->SetAttribute(nsGkAtoms::containerAtomic, *atomic);
} if (!busy.IsEmpty()) {
aAttributes->SetAttribute(nsGkAtoms::containerBusy, std::move(busy));
}
}
bool nsAccUtils::HasDefinedARIAToken(nsIContent* aContent, nsAtom* aAtom) {
NS_ASSERTION(aContent, "aContent is null in call to HasDefinedARIAToken!");
if (!aContent->IsElement()) returnfalse;
dom::Element* element = aContent->AsElement(); if (auto* htmlElement = nsGenericHTMLElement::FromNode(element);
htmlElement && !element->HasAttr(aAtom)) { constauto* defaults = GetARIADefaults(htmlElement); if (!defaults) { returnfalse;
} return HasDefinedARIAToken(defaults, aAtom);
} return HasDefinedARIAToken(&element->GetAttrs(), aAtom);
}
bool nsAccUtils::IsDOMAttrTrue(const LocalAccessible* aAccessible,
nsAtom* aAttr) {
dom::Element* el = aAccessible->Elm(); return el && ARIAAttrValueIs(el, aAttr, nsGkAtoms::_true, eCaseMatters);
}
Accessible* nsAccUtils::TableFor(Accessible* aAcc) { if (!aAcc ||
(!aAcc->IsTable() && !aAcc->IsTableRow() && !aAcc->IsTableCell())) { return nullptr;
}
Accessible* table = aAcc; for (; table && !table->IsTable(); table = table->Parent()) {
} // We don't assert (table && table->IsTable()) here because // it's possible for this tree walk to yield no table at all // ex. because a table part has been moved in the tree // using aria-owns. return table;
}
switch (aCoordinateType) { // Regardless of coordinate type, the coords returned // are in dev pixels. case nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE: break;
case nsIAccessibleCoordinateType::COORDTYPE_WINDOW_RELATIVE: {
coords += GetScreenCoordsForWindow(aAccessible); break;
}
case nsIAccessibleCoordinateType::COORDTYPE_PARENT_RELATIVE: {
coords += GetScreenCoordsForParent(aAccessible); break;
}
void nsAccUtils::ConvertScreenCoordsTo(int32_t* aX, int32_t* aY,
uint32_t aCoordinateType,
Accessible* aAccessible) { switch (aCoordinateType) { // Regardless of coordinate type, the values returned for // aX and aY are in dev pixels. case nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE: break;
LayoutDeviceIntPoint nsAccUtils::GetScreenCoordsForParent(
Accessible* aAccessible) { if (!aAccessible) return LayoutDeviceIntPoint();
if (Accessible* parent = aAccessible->Parent()) {
LayoutDeviceIntRect parentBounds = parent->Bounds(); // The rect returned from Bounds() is already in dev // pixels, so we don't need to do any conversion here. return parentBounds.TopLeft();
}
return LayoutDeviceIntPoint();
}
LayoutDeviceIntPoint nsAccUtils::GetScreenCoordsForWindow(
Accessible* aAccessible) {
LayoutDeviceIntPoint coords(0, 0);
a11y::LocalAccessible* localAcc = aAccessible->AsLocal(); if (!localAcc) {
localAcc = aAccessible->AsRemote()->OuterDocOfRemoteBrowser(); if (!localAcc) { // This could be null if the tab is closing but the document is still // being shut down. return coords;
}
}
nsCOMPtr<nsIDocShellTreeItem> treeItem(
nsCoreUtils::GetDocShellFor(localAcc->GetNode())); if (!treeItem) return coords;
nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
treeItem->GetTreeOwner(getter_AddRefs(treeOwner)); if (!treeOwner) return coords;
nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(treeOwner); if (baseWindow) {
baseWindow->GetPosition(&coords.x.value,
&coords.y.value); // in device pixels
}
return coords;
}
bool nsAccUtils::GetLiveAttrValue(uint32_t aRule, nsAString& aValue) { switch (aRule) { case eOffLiveAttr:
aValue = u"off"_ns; returntrue; case ePoliteLiveAttr:
aValue = u"polite"_ns; returntrue; case eAssertiveLiveAttr:
aValue = u"assertive"_ns; returntrue;
}
returnfalse;
}
#ifdef DEBUG
bool nsAccUtils::IsTextInterfaceSupportCorrect(LocalAccessible* aAccessible) { // Don't test for accessible docs, it makes us create accessibles too // early and fire mutation events before we need to if (aAccessible->IsDoc()) returntrue;
// For list bullets (or anything other accessible which would compute its own // text. They don't have their own frame. // XXX In the future, list bullets may have frame and anon content, so // we should be able to remove this at that point
nsAutoString text;
aAccessible->AppendTextTo(text); // Get all the text return text.Length();
}
bool nsAccUtils::MustPrune(Accessible* aAccessible) {
MOZ_ASSERT(aAccessible);
roles::Role role = aAccessible->Role();
if (role == roles::SLIDER || role == roles::PROGRESSBAR) { // Always prune the tree for sliders and progressbars, as it doesn't make // sense for either to have descendants. Per the ARIA spec, children of // these elements are presentational. They also confuse NVDA. returntrue;
}
if (role != roles::MENUITEM && role != roles::COMBOBOX_OPTION &&
role != roles::OPTION && role != roles::ENTRY &&
role != roles::FLAT_EQUATION && role != roles::PASSWORD_TEXT &&
role != roles::PUSHBUTTON && role != roles::TOGGLE_BUTTON &&
role != roles::GRAPHIC && role != roles::SEPARATOR) { // If it doesn't match any of these roles, don't prune its children. returnfalse;
}
if (aAccessible->ChildCount() != 1) { // If the accessible has more than one child, don't prune it. returnfalse;
}
roles::Role childRole = aAccessible->FirstChild()->Role(); // If the accessible's child is a text leaf, prune the accessible. return childRole == roles::TEXT_LEAF || childRole == roles::STATICTEXT;
}
void nsAccUtils::GetLiveRegionSetting(Accessible* aAcc, nsAString& aLive) {
MOZ_ASSERT(aAcc);
aAcc->LiveRegionAttributes(&aLive, nullptr, nullptr, nullptr); // aria-live wasn't explicitly set. See if an aria-live value is implied // by an ARIA role or markup element. if (const nsRoleMapEntry* roleMap = aAcc->ARIARoleMap()) {
GetLiveAttrValue(roleMap->liveAttRule, aLive);
} elseif (nsStaticAtom* value =
GetAccService()->MarkupAttribute(aAcc, nsGkAtoms::aria_live)) {
value->ToString(aLive);
}
}
Accessible* nsAccUtils::GetLiveRegionRoot(Accessible* aAcc) {
MOZ_ASSERT(aAcc);
nsAutoString live;
Accessible* acc; for (acc = aAcc; acc; acc = acc->Parent()) {
GetLiveRegionSetting(acc, live); if (!live.IsEmpty()) { break;
} if (acc->IsDoc()) { // A document can be the root of a live region, but a live region cannot // cross document boundaries. return nullptr;
}
} if (live.IsEmpty() || live.EqualsLiteral("off")) { return nullptr;
} return acc;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.