/* -*- 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 "AccEvent.h" #include "LocalAccessible-inl.h" #include "EmbeddedObjCollector.h" #include "AccGroupInfo.h" #include "AccIterator.h" #include "CachedTableAccessible.h" #include "DocAccessible-inl.h" #include "mozilla/a11y/AccAttributes.h" #include "mozilla/a11y/DocAccessibleChild.h" #include "mozilla/a11y/Platform.h" #include "nsAccUtils.h" #include "nsAccessibilityService.h" #include "ApplicationAccessible.h" #include "nsGenericHTMLElement.h" #include "NotificationController.h" #include "nsEventShell.h" #include "nsTextEquivUtils.h" #include "EventTree.h" #include "OuterDocAccessible.h" #include "Pivot.h" #include "Relation.h" #include "mozilla/a11y/Role.h" #include "RootAccessible.h" #include "States.h" #include "TextLeafRange.h" #include "TextRange.h" #include "HTMLElementAccessibles.h" #include "HTMLSelectAccessible.h" #include "HTMLTableAccessible.h" #include "ImageAccessible.h" #include "nsComputedDOMStyle.h" #include "nsGkAtoms.h" #include "nsIDOMXULButtonElement.h" #include "nsIDOMXULSelectCntrlEl.h" #include "nsIDOMXULSelectCntrlItemEl.h" #include "nsINodeList.h" #include "mozilla/dom/Document.h" #include "mozilla/dom/HTMLFormElement.h" #include "mozilla/dom/HTMLAnchorElement.h" #include "mozilla/gfx/Matrix.h" #include "nsIContent.h" #include "nsIFormControl.h" #include "nsDisplayList.h" #include "nsLayoutUtils.h" #include "nsPresContext.h" #include "nsIFrame.h" #include "nsTextFrame.h" #include "nsView.h" #include "nsIDocShellTreeItem.h" #include "nsIScrollableFrame.h" #include "nsStyleStructInlines.h" #include "nsFocusManager.h" #include "nsString.h" #include "nsAtom.h" #include "nsContainerFrame.h" #include "mozilla/Assertions.h" #include "mozilla/BasicEvents.h" #include "mozilla/ErrorResult.h" #include "mozilla/FloatingPoint.h" #include "mozilla/PresShell.h" #include "mozilla/ProfilerMarkers.h" #include "mozilla/StaticPrefs_ui.h" #include "mozilla/dom/Element.h" #include "mozilla/dom/HTMLLabelElement.h" #include "mozilla/dom/KeyboardEventBinding.h" #include "mozilla/dom/TreeWalker.h" #include "mozilla/dom/UserActivation.h" #include "mozilla/dom/MutationEventBinding.h" using namespace mozilla; using namespace mozilla::a11y; //////////////////////////////////////////////////////////////////////////////// // LocalAccessible: nsISupports and cycle collection NS_IMPL_CYCLE_COLLECTION_CLASS(LocalAccessible) NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(LocalAccessible) tmp->Shutdown(); NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(LocalAccessible) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContent, mDoc) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(LocalAccessible) NS_INTERFACE_MAP_ENTRY_CONCRETE(LocalAccessible) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, LocalAccessible) NS_INTERFACE_MAP_END NS_IMPL_CYCLE_COLLECTING_ADDREF(LocalAccessible) NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_DESTROY(LocalAccessible, LastRelease()) LocalAccessible::LocalAccessible(nsIContent* aContent, DocAccessible* aDoc) : mContent(aContent), mDoc(aDoc), mParent(nullptr), mIndexInParent(-1), mFirstLineStart(-1), mStateFlags(0), mContextFlags(0), mReorderEventTarget(false), mShowEventTarget(false), mHideEventTarget(false), mIndexOfEmbeddedChild(-1), mGroupInfo(nullptr) {} LocalAccessible::~LocalAccessible() { NS_ASSERTION(!mDoc, "LastRelease was never called!?!"); } ENameValueFlag LocalAccessible::Name(nsString& aName) const { aName.Truncate(); if (!HasOwnContent()) return eNameOK; ARIAName(aName); if (!aName.IsEmpty()) return eNameOK; ENameValueFlag nameFlag = NativeName(aName); nsCoreUtils::TrimNonBreakingSpaces(aName); if (!aName.IsEmpty()) return nameFlag; // In the end get the name from tooltip. if (mContent->IsHTMLElement()) { if (mContent->AsElement()->GetAttr(nsGkAtoms::title, aName)) { aName.CompressWhitespace(); return eNameFromTooltip; } } else if (mContent->IsXULElement()) { if (mContent->AsElement()->GetAttr(nsGkAtoms::tooltiptext, aName)) { aName.CompressWhitespace(); return eNameFromTooltip; } } else if (mContent->IsSVGElement()) { // If user agents need to choose among multiple 'desc' or 'title' // elements for processing, the user agent shall choose the first one. for (nsIContent* childElm = mContent->GetFirstChild(); childElm; childElm = childElm->GetNextSibling()) { if (childElm->IsSVGElement(nsGkAtoms::desc)) { nsTextEquivUtils::AppendTextEquivFromContent(this, childElm, &aName); return eNameFromTooltip; } } } aName.SetIsVoid(true); return nameFlag; } void LocalAccessible::Description(nsString& aDescription) const { // There are 4 conditions that make an accessible have no accDescription: // 1. it's a text node; or // 2. It has no ARIA describedby or description property // 3. it doesn't have an accName; or // 4. its title attribute already equals to its accName nsAutoString name; if (!HasOwnContent() || mContent->IsText()) return; ARIADescription(aDescription); if (aDescription.IsEmpty()) { NativeDescription(aDescription); if (aDescription.IsEmpty()) { // Keep the Name() method logic. if (mContent->IsHTMLElement()) { mContent->AsElement()->GetAttr(nsGkAtoms::title, aDescription); } else if (mContent->IsXULElement()) { mContent->AsElement()->GetAttr(nsGkAtoms::tooltiptext, aDescription); } else if (mContent->IsSVGElement()) { for (nsIContent* childElm = mContent->GetFirstChild(); childElm; childElm = childElm->GetNextSibling()) { if (childElm->IsSVGElement(nsGkAtoms::desc)) { nsTextEquivUtils::AppendTextEquivFromContent(this, childElm, &aDescription); break; } } } } } if (!aDescription.IsEmpty()) { aDescription.CompressWhitespace(); nsAutoString name; Name(name); // Don't expose a description if it is the same as the name. if (aDescription.Equals(name)) aDescription.Truncate(); } } KeyBinding LocalAccessible::AccessKey() const { if (!HasOwnContent()) return KeyBinding(); uint32_t key = nsCoreUtils::GetAccessKeyFor(mContent); if (!key && mContent->IsElement()) { LocalAccessible* label = nullptr; // Copy access key from label node. if (mContent->IsHTMLElement()) { // Unless it is labeled via an ancestor