summaryrefslogtreecommitdiffstats
path: root/accessible/html/HTMLElementAccessibles.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'accessible/html/HTMLElementAccessibles.cpp')
-rw-r--r--accessible/html/HTMLElementAccessibles.cpp244
1 files changed, 244 insertions, 0 deletions
diff --git a/accessible/html/HTMLElementAccessibles.cpp b/accessible/html/HTMLElementAccessibles.cpp
new file mode 100644
index 0000000000..f19c49e1db
--- /dev/null
+++ b/accessible/html/HTMLElementAccessibles.cpp
@@ -0,0 +1,244 @@
+/* -*- 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 "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() const { return roles::SEPARATOR; }
+
+////////////////////////////////////////////////////////////////////////////////
+// HTMLBRAccessible
+////////////////////////////////////////////////////////////////////////////////
+
+role HTMLBRAccessible::NativeRole() const { return roles::WHITESPACE; }
+
+uint64_t HTMLBRAccessible::NativeState() const { return states::READONLY; }
+
+ENameValueFlag HTMLBRAccessible::NativeName(nsString& aName) const {
+ aName = static_cast<char16_t>('\n'); // Newline char
+ return eNameOK;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// HTMLLabelAccessible
+////////////////////////////////////////////////////////////////////////////////
+
+ENameValueFlag HTMLLabelAccessible::NativeName(nsString& aName) const {
+ nsTextEquivUtils::GetNameFromSubtree(this, aName);
+ return aName.IsEmpty() ? eNameOK : eNameFromSubtree;
+}
+
+Relation HTMLLabelAccessible::RelationByType(RelationType aType) const {
+ Relation rel = AccessibleWrap::RelationByType(aType);
+ if (aType == RelationType::LABEL_FOR) {
+ dom::HTMLLabelElement* label = dom::HTMLLabelElement::FromNode(mContent);
+ rel.AppendTarget(mDoc, label->GetControl());
+ }
+
+ return rel;
+}
+
+uint8_t HTMLLabelAccessible::ActionCount() const {
+ 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) const {
+ if (aIndex != 0) return false;
+
+ DoCommand();
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// nsHTMLOuputAccessible
+////////////////////////////////////////////////////////////////////////////////
+
+Relation HTMLOutputAccessible::RelationByType(RelationType aType) const {
+ 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() const { return 1; }
+
+void HTMLSummaryAccessible::ActionNameAt(uint8_t aIndex, nsAString& aName) {
+ if (aIndex != eAction_Click) {
+ return;
+ }
+
+ dom::HTMLSummaryElement* summary =
+ dom::HTMLSummaryElement::FromNode(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) const {
+ if (aIndex != eAction_Click) return false;
+
+ DoCommand();
+ return true;
+}
+
+uint64_t HTMLSummaryAccessible::NativeState() const {
+ uint64_t state = HyperTextAccessibleWrap::NativeState();
+
+ dom::HTMLSummaryElement* summary =
+ dom::HTMLSummaryElement::FromNode(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* HTMLSummaryAccessible::FromDetails(Accessible* details) {
+ if (!dom::HTMLDetailsElement::FromNodeOrNull(details->GetContent())) {
+ return nullptr;
+ }
+
+ HTMLSummaryAccessible* summaryAccessible = nullptr;
+ for (uint32_t i = 0; i < details->ChildCount(); i++) {
+ // Iterate through the children of our details accessible to locate main
+ // summary. This iteration includes the anonymous summary if the details
+ // element was not explicitly created with one.
+ Accessible* child = details->GetChildAt(i);
+ auto* summary =
+ mozilla::dom::HTMLSummaryElement::FromNodeOrNull(child->GetContent());
+ if (summary && summary->IsMainSummary()) {
+ summaryAccessible = static_cast<HTMLSummaryAccessible*>(child);
+ break;
+ }
+ }
+
+ return summaryAccessible;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// HTMLSummaryAccessible: Widgets
+
+bool HTMLSummaryAccessible::IsWidget() const { return true; }
+
+////////////////////////////////////////////////////////////////////////////////
+// HTMLHeaderOrFooterAccessible
+////////////////////////////////////////////////////////////////////////////////
+
+role HTMLHeaderOrFooterAccessible::NativeRole() const {
+ // 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::main, 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) {
+ return roles::LANDMARK;
+ }
+
+ return roles::SECTION;
+}
+
+nsAtom* HTMLHeaderOrFooterAccessible::LandmarkRole() const {
+ if (!HasOwnContent()) return nullptr;
+
+ a11y::role r = const_cast<HTMLHeaderOrFooterAccessible*>(this)->Role();
+ if (r == roles::LANDMARK) {
+ if (mContent->IsHTMLElement(nsGkAtoms::header)) {
+ return nsGkAtoms::banner;
+ }
+
+ if (mContent->IsHTMLElement(nsGkAtoms::footer)) {
+ return nsGkAtoms::contentinfo;
+ }
+ }
+
+ return HyperTextAccessibleWrap::LandmarkRole();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// HTMLSectionAccessible
+////////////////////////////////////////////////////////////////////////////////
+
+role HTMLSectionAccessible::NativeRole() const {
+ nsAutoString name;
+ const_cast<HTMLSectionAccessible*>(this)->Name(name);
+ return name.IsEmpty() ? roles::SECTION : roles::REGION;
+}
+
+nsAtom* HTMLSectionAccessible::LandmarkRole() const {
+ if (!HasOwnContent()) {
+ return nullptr;
+ }
+
+ // Only return xml-roles "region" if the section has an accessible name.
+ nsAutoString name;
+ const_cast<HTMLSectionAccessible*>(this)->Name(name);
+ return name.IsEmpty() ? HyperTextAccessibleWrap::LandmarkRole()
+ : nsGkAtoms::region;
+}