/* -*- 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/. */ #include "HTMLElementAccessibles.h" #include "DocAccessible.h" #include "nsAccUtils.h" #include "nsIPersistentProperties2.h" #include "nsTextEquivUtils.h" #include "Relation.h" #include "Role.h" #include "States.h" #include "mozilla/dom/HTMLLabelElement.h" #include "mozilla/dom/HTMLDetailsElement.h" #include "mozilla/dom/HTMLSummaryElement.h" using namespace mozilla::a11y; //////////////////////////////////////////////////////////////////////////////// // HTMLHRAccessible //////////////////////////////////////////////////////////////////////////////// role HTMLHRAccessible::NativeRole() { return roles::SEPARATOR; } //////////////////////////////////////////////////////////////////////////////// // HTMLBRAccessible //////////////////////////////////////////////////////////////////////////////// role HTMLBRAccessible::NativeRole() { return roles::WHITESPACE; } uint64_t HTMLBRAccessible::NativeState() { return states::READONLY; } ENameValueFlag HTMLBRAccessible::NativeName(nsString& aName) { aName = static_cast('\n'); // Newline char return eNameOK; } //////////////////////////////////////////////////////////////////////////////// // HTMLLabelAccessible //////////////////////////////////////////////////////////////////////////////// NS_IMPL_ISUPPORTS_INHERITED0(HTMLLabelAccessible, HyperTextAccessible) ENameValueFlag HTMLLabelAccessible::NativeName(nsString& aName) { nsTextEquivUtils::GetNameFromSubtree(this, aName); return aName.IsEmpty() ? eNameOK : eNameFromSubtree; } Relation HTMLLabelAccessible::RelationByType(RelationType aType) { Relation rel = AccessibleWrap::RelationByType(aType); if (aType == RelationType::LABEL_FOR) { dom::HTMLLabelElement* label = dom::HTMLLabelElement::FromContent(mContent); rel.AppendTarget(mDoc, label->GetControl()); } return rel; } uint8_t HTMLLabelAccessible::ActionCount() { return nsCoreUtils::IsLabelWithControl(mContent) ? 1 : 0; } void HTMLLabelAccessible::ActionNameAt(uint8_t aIndex, nsAString& aName) { if (aIndex == 0) { if (nsCoreUtils::IsLabelWithControl(mContent)) aName.AssignLiteral("click"); } } bool HTMLLabelAccessible::DoAction(uint8_t aIndex) { if (aIndex != 0) return false; DoCommand(); return true; } //////////////////////////////////////////////////////////////////////////////// // nsHTMLOuputAccessible //////////////////////////////////////////////////////////////////////////////// NS_IMPL_ISUPPORTS_INHERITED0(HTMLOutputAccessible, HyperTextAccessible) Relation HTMLOutputAccessible::RelationByType(RelationType aType) { Relation rel = AccessibleWrap::RelationByType(aType); if (aType == RelationType::CONTROLLED_BY) rel.AppendIter(new IDRefsIterator(mDoc, mContent, nsGkAtoms::_for)); return rel; } //////////////////////////////////////////////////////////////////////////////// // HTMLSummaryAccessible //////////////////////////////////////////////////////////////////////////////// HTMLSummaryAccessible:: HTMLSummaryAccessible(nsIContent* aContent, DocAccessible* aDoc) : HyperTextAccessibleWrap(aContent, aDoc) { mGenericTypes |= eButton; } uint8_t HTMLSummaryAccessible::ActionCount() { return 1; } void HTMLSummaryAccessible::ActionNameAt(uint8_t aIndex, nsAString& aName) { if (aIndex != eAction_Click) { return; } dom::HTMLSummaryElement* summary = dom::HTMLSummaryElement::FromContent(mContent); if (!summary) { return; } dom::HTMLDetailsElement* details = summary->GetDetails(); if (!details) { return; } if (details->Open()) { aName.AssignLiteral("collapse"); } else { aName.AssignLiteral("expand"); } } bool HTMLSummaryAccessible::DoAction(uint8_t aIndex) { if (aIndex != eAction_Click) return false; DoCommand(); return true; } uint64_t HTMLSummaryAccessible::NativeState() { uint64_t state = HyperTextAccessibleWrap::NativeState(); dom::HTMLSummaryElement* summary = dom::HTMLSummaryElement::FromContent(mContent); if (!summary) { return state; } dom::HTMLDetailsElement* details = summary->GetDetails(); if (!details) { return state; } if (details->Open()) { state |= states::EXPANDED; } else { state |= states::COLLAPSED; } return state; } //////////////////////////////////////////////////////////////////////////////// // HTMLSummaryAccessible: Widgets bool HTMLSummaryAccessible::IsWidget() const { return true; } //////////////////////////////////////////////////////////////////////////////// // HTMLHeaderOrFooterAccessible //////////////////////////////////////////////////////////////////////////////// NS_IMPL_ISUPPORTS_INHERITED0(HTMLHeaderOrFooterAccessible, HyperTextAccessible) role HTMLHeaderOrFooterAccessible::NativeRole() { // Only map header and footer if they are direct descendants of the body tag. // If other sectioning or sectioning root elements, they become sections. nsIContent* parent = mContent->GetParent(); while (parent) { if (parent->IsAnyOfHTMLElements(nsGkAtoms::article, nsGkAtoms::aside, nsGkAtoms::nav, nsGkAtoms::section, nsGkAtoms::blockquote, nsGkAtoms::details, nsGkAtoms::dialog, nsGkAtoms::fieldset, nsGkAtoms::figure, nsGkAtoms::td)) { break; } parent = parent->GetParent(); } // No sectioning or sectioning root elements found. if (!parent) { if (mContent->IsHTMLElement(nsGkAtoms::header)) { return roles::HEADER; } if (mContent->IsHTMLElement(nsGkAtoms::footer)) { return roles::FOOTER; } } return roles::SECTION; } nsAtom* HTMLHeaderOrFooterAccessible::LandmarkRole() const { if (!HasOwnContent()) return nullptr; a11y::role r = const_cast(this)->Role(); if (r == roles::HEADER) { return nsGkAtoms::banner; } if (r == roles::FOOTER) { return nsGkAtoms::contentinfo; } return nullptr; }