/* -*- 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 "Accessible-inl.h" #include "nsIXBLAccessible.h" #include "EmbeddedObjCollector.h" #include "AccGroupInfo.h" #include "AccIterator.h" #include "nsAccUtils.h" #include "nsAccessibilityService.h" #include "ApplicationAccessible.h" #include "NotificationController.h" #include "nsEventShell.h" #include "nsTextEquivUtils.h" #include "DocAccessibleChild.h" #include "EventTree.h" #include "Relation.h" #include "Role.h" #include "RootAccessible.h" #include "States.h" #include "StyleInfo.h" #include "TableAccessible.h" #include "TableCellAccessible.h" #include "TreeWalker.h" #include "nsIDOMElement.h" #include "nsIDOMNodeFilter.h" #include "nsIDOMHTMLElement.h" #include "nsIDOMKeyEvent.h" #include "nsIDOMTreeWalker.h" #include "nsIDOMXULButtonElement.h" #include "nsIDOMXULDocument.h" #include "nsIDOMXULElement.h" #include "nsIDOMXULLabelElement.h" #include "nsIDOMXULSelectCntrlEl.h" #include "nsIDOMXULSelectCntrlItemEl.h" #include "nsPIDOMWindow.h" #include "nsIDocument.h" #include "nsIContent.h" #include "nsIForm.h" #include "nsIFormControl.h" #include "nsDeckFrame.h" #include "nsLayoutUtils.h" #include "nsIPersistentProperties2.h" #include "nsIPresShell.h" #include "nsIStringBundle.h" #include "nsPresContext.h" #include "nsIFrame.h" #include "nsView.h" #include "nsIDocShellTreeItem.h" #include "nsIScrollableFrame.h" #include "nsFocusManager.h" #include "nsXPIDLString.h" #include "nsUnicharUtils.h" #include "nsReadableUtils.h" #include "prdtoa.h" #include "nsIAtom.h" #include "nsIURI.h" #include "nsArrayUtils.h" #include "nsIMutableArray.h" #include "nsIObserverService.h" #include "nsIServiceManager.h" #include "nsWhitespaceTokenizer.h" #include "nsAttrName.h" #ifdef DEBUG #include "nsIDOMCharacterData.h" #endif #include "mozilla/Assertions.h" #include "mozilla/BasicEvents.h" #include "mozilla/EventStates.h" #include "mozilla/FloatingPoint.h" #include "mozilla/MouseEvents.h" #include "mozilla/Unused.h" #include "mozilla/Preferences.h" #include "mozilla/dom/CanvasRenderingContext2D.h" #include "mozilla/dom/Element.h" #include "mozilla/dom/HTMLCanvasElement.h" #include "mozilla/dom/HTMLBodyElement.h" #include "mozilla/dom/TreeWalker.h" using namespace mozilla; using namespace mozilla::a11y; //////////////////////////////////////////////////////////////////////////////// // Accessible: nsISupports and cycle collection NS_IMPL_CYCLE_COLLECTION_CLASS(Accessible) NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Accessible) tmp->Shutdown(); NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Accessible) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContent, mDoc) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Accessible) if (aIID.Equals(NS_GET_IID(Accessible))) foundInterface = this; else NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, Accessible) NS_INTERFACE_MAP_END NS_IMPL_CYCLE_COLLECTING_ADDREF(Accessible) NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_DESTROY(Accessible, LastRelease()) Accessible::Accessible(nsIContent* aContent, DocAccessible* aDoc) : mContent(aContent), mDoc(aDoc), mParent(nullptr), mIndexInParent(-1), mRoleMapEntryIndex(aria::NO_ROLE_MAP_ENTRY_INDEX), mStateFlags(0), mContextFlags(0), mType(0), mGenericTypes(0), mReorderEventTarget(false), mShowEventTarget(false), mHideEventTarget(false) { mBits.groupInfo = nullptr; mInt.mIndexOfEmbeddedChild = -1; } Accessible::~Accessible() { NS_ASSERTION(!mDoc, "LastRelease was never called!?!"); } ENameValueFlag Accessible::Name(nsString& aName) { aName.Truncate(); if (!HasOwnContent()) return eNameOK; ARIAName(aName); if (!aName.IsEmpty()) return eNameOK; nsCOMPtr xblAccessible(do_QueryInterface(mContent)); if (xblAccessible) { xblAccessible->GetAccessibleName(aName); if (!aName.IsEmpty()) return eNameOK; } ENameValueFlag nameFlag = NativeName(aName); if (!aName.IsEmpty()) return nameFlag; // In the end get the name from tooltip. if (mContent->IsHTMLElement()) { if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::title, aName)) { aName.CompressWhitespace(); return eNameFromTooltip; } } else if (mContent->IsXULElement()) { if (mContent->GetAttr(kNameSpaceID_None, 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; } } } if (nameFlag != eNoNameOnPurpose) aName.SetIsVoid(true); return nameFlag; } void Accessible::Description(nsString& aDescription) { // There are 4 conditions that make an accessible have no accDescription: // 1. it's a text node; or // 2. It has no DHTML describedby property // 3. it doesn't have an accName; or // 4. its title attribute already equals to its accName nsAutoString name; if (!HasOwnContent() || mContent->IsNodeOfType(nsINode::eTEXT)) return; nsTextEquivUtils:: GetTextEquivFromIDRefs(this, nsGkAtoms::aria_describedby, aDescription); if (aDescription.IsEmpty()) { NativeDescription(aDescription); if (aDescription.IsEmpty()) { // Keep the Name() method logic. if (mContent->IsHTMLElement()) { mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::title, aDescription); } else if (mContent->IsXULElement()) { mContent->GetAttr(kNameSpaceID_None, 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 Accessible::AccessKey() const { if (!HasOwnContent()) return KeyBinding(); uint32_t key = nsCoreUtils::GetAccessKeyFor(mContent); if (!key && mContent->IsElement()) { Accessible* label = nullptr; // Copy access key from label node. if (mContent->IsHTMLElement()) { // Unless it is labeled via an ancestor