michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "XULElementAccessibles.h" michael@0: michael@0: #include "Accessible-inl.h" michael@0: #include "BaseAccessibles.h" michael@0: #include "DocAccessible-inl.h" michael@0: #include "nsAccUtils.h" michael@0: #include "nsCoreUtils.h" michael@0: #include "nsTextEquivUtils.h" michael@0: #include "Relation.h" michael@0: #include "Role.h" michael@0: #include "States.h" michael@0: #include "TextUpdater.h" michael@0: michael@0: #ifdef A11Y_LOG michael@0: #include "Logging.h" michael@0: #endif michael@0: michael@0: #include "nsIAccessibleRelation.h" michael@0: #include "nsIDOMXULDescriptionElement.h" michael@0: #include "nsNameSpaceManager.h" michael@0: #include "nsNetUtil.h" michael@0: #include "nsString.h" michael@0: #include "nsTextBoxFrame.h" michael@0: michael@0: using namespace mozilla::a11y; michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // XULLabelAccessible michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: XULLabelAccessible:: michael@0: XULLabelAccessible(nsIContent* aContent, DocAccessible* aDoc) : michael@0: HyperTextAccessibleWrap(aContent, aDoc) michael@0: { michael@0: mType = eXULLabelType; michael@0: michael@0: // If @value attribute is given then it's rendered instead text content. In michael@0: // this case we need to create a text leaf accessible to make @value attribute michael@0: // accessible. michael@0: // XXX: text interface doesn't let you get the text by words. michael@0: nsTextBoxFrame* textBoxFrame = do_QueryFrame(mContent->GetPrimaryFrame()); michael@0: if (textBoxFrame) { michael@0: mValueTextLeaf = new XULLabelTextLeafAccessible(mContent, mDoc); michael@0: mDoc->BindToDocument(mValueTextLeaf, nullptr); michael@0: michael@0: nsAutoString text; michael@0: textBoxFrame->GetCroppedTitle(text); michael@0: mValueTextLeaf->SetText(text); michael@0: } michael@0: } michael@0: michael@0: void michael@0: XULLabelAccessible::Shutdown() michael@0: { michael@0: mValueTextLeaf = nullptr; michael@0: HyperTextAccessibleWrap::Shutdown(); michael@0: } michael@0: michael@0: ENameValueFlag michael@0: XULLabelAccessible::NativeName(nsString& aName) michael@0: { michael@0: // if the value attr doesn't exist, the screen reader must get the accessible text michael@0: // from the accessible text interface or from the children michael@0: if (mValueTextLeaf) michael@0: return mValueTextLeaf->Name(aName); michael@0: michael@0: return eNameOK; michael@0: } michael@0: michael@0: role michael@0: XULLabelAccessible::NativeRole() michael@0: { michael@0: return roles::LABEL; michael@0: } michael@0: michael@0: uint64_t michael@0: XULLabelAccessible::NativeState() michael@0: { michael@0: // Labels and description have read only state michael@0: // They are not focusable or selectable michael@0: return HyperTextAccessibleWrap::NativeState() | states::READONLY; michael@0: } michael@0: michael@0: Relation michael@0: XULLabelAccessible::RelationByType(RelationType aType) michael@0: { michael@0: Relation rel = HyperTextAccessibleWrap::RelationByType(aType); michael@0: if (aType == RelationType::LABEL_FOR) { michael@0: // Caption is the label for groupbox michael@0: nsIContent* parent = mContent->GetFlattenedTreeParent(); michael@0: if (parent && parent->Tag() == nsGkAtoms::caption) { michael@0: Accessible* parent = Parent(); michael@0: if (parent && parent->Role() == roles::GROUPING) michael@0: rel.AppendTarget(parent); michael@0: } michael@0: } michael@0: michael@0: return rel; michael@0: } michael@0: michael@0: void michael@0: XULLabelAccessible::UpdateLabelValue(const nsString& aValue) michael@0: { michael@0: #ifdef A11Y_LOG michael@0: if (logging::IsEnabled(logging::eText)) { michael@0: logging::MsgBegin("TEXT", "text may be changed (xul:label @value update)"); michael@0: logging::Node("container", mContent); michael@0: logging::MsgEntry("old text '%s'", michael@0: NS_ConvertUTF16toUTF8(mValueTextLeaf->Text()).get()); michael@0: logging::MsgEntry("new text: '%s'", michael@0: NS_ConvertUTF16toUTF8(aValue).get()); michael@0: logging::MsgEnd(); michael@0: } michael@0: #endif michael@0: michael@0: TextUpdater::Run(mDoc, mValueTextLeaf, aValue); michael@0: } michael@0: michael@0: void michael@0: XULLabelAccessible::CacheChildren() michael@0: { michael@0: if (mValueTextLeaf) { michael@0: AppendChild(mValueTextLeaf); michael@0: return; michael@0: } michael@0: michael@0: // Cache children from subtree. michael@0: AccessibleWrap::CacheChildren(); michael@0: } michael@0: michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // XULLabelTextLeafAccessible michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: role michael@0: XULLabelTextLeafAccessible::NativeRole() michael@0: { michael@0: return roles::TEXT_LEAF; michael@0: } michael@0: michael@0: uint64_t michael@0: XULLabelTextLeafAccessible::NativeState() michael@0: { michael@0: return TextLeafAccessibleWrap::NativeState() | states::READONLY; michael@0: } michael@0: michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // XULTooltipAccessible michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: XULTooltipAccessible:: michael@0: XULTooltipAccessible(nsIContent* aContent, DocAccessible* aDoc) : michael@0: LeafAccessible(aContent, aDoc) michael@0: { michael@0: } michael@0: michael@0: uint64_t michael@0: XULTooltipAccessible::NativeState() michael@0: { michael@0: return LeafAccessible::NativeState() | states::READONLY; michael@0: } michael@0: michael@0: role michael@0: XULTooltipAccessible::NativeRole() michael@0: { michael@0: return roles::TOOLTIP; michael@0: } michael@0: michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // XULLinkAccessible michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: XULLinkAccessible:: michael@0: XULLinkAccessible(nsIContent* aContent, DocAccessible* aDoc) : michael@0: XULLabelAccessible(aContent, aDoc) michael@0: { michael@0: } michael@0: michael@0: // Expose nsIAccessibleHyperLink unconditionally michael@0: NS_IMPL_ISUPPORTS_INHERITED(XULLinkAccessible, XULLabelAccessible, michael@0: nsIAccessibleHyperLink) michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // XULLinkAccessible. nsIAccessible michael@0: michael@0: void michael@0: XULLinkAccessible::Value(nsString& aValue) michael@0: { michael@0: aValue.Truncate(); michael@0: michael@0: mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::href, aValue); michael@0: } michael@0: michael@0: ENameValueFlag michael@0: XULLinkAccessible::NativeName(nsString& aName) michael@0: { michael@0: mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::value, aName); michael@0: if (!aName.IsEmpty()) michael@0: return eNameOK; michael@0: michael@0: nsTextEquivUtils::GetNameFromSubtree(this, aName); michael@0: return aName.IsEmpty() ? eNameOK : eNameFromSubtree; michael@0: } michael@0: michael@0: role michael@0: XULLinkAccessible::NativeRole() michael@0: { michael@0: return roles::LINK; michael@0: } michael@0: michael@0: michael@0: uint64_t michael@0: XULLinkAccessible::NativeLinkState() const michael@0: { michael@0: return states::LINKED; michael@0: } michael@0: michael@0: uint8_t michael@0: XULLinkAccessible::ActionCount() michael@0: { michael@0: return 1; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: XULLinkAccessible::GetActionName(uint8_t aIndex, nsAString& aName) michael@0: { michael@0: aName.Truncate(); michael@0: michael@0: if (aIndex != eAction_Jump) michael@0: return NS_ERROR_INVALID_ARG; michael@0: michael@0: aName.AssignLiteral("jump"); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: XULLinkAccessible::DoAction(uint8_t aIndex) michael@0: { michael@0: if (aIndex != eAction_Jump) michael@0: return NS_ERROR_INVALID_ARG; michael@0: michael@0: if (IsDefunct()) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: DoCommand(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // XULLinkAccessible: HyperLinkAccessible michael@0: michael@0: bool michael@0: XULLinkAccessible::IsLink() michael@0: { michael@0: // Expose HyperLinkAccessible unconditionally. michael@0: return true; michael@0: } michael@0: michael@0: uint32_t michael@0: XULLinkAccessible::StartOffset() michael@0: { michael@0: // If XUL link accessible is not contained by hypertext accessible then michael@0: // start offset matches index in parent because the parent doesn't contains michael@0: // a text. michael@0: // XXX: accessible parent of XUL link accessible should be a hypertext michael@0: // accessible. michael@0: if (Accessible::IsLink()) michael@0: return Accessible::StartOffset(); michael@0: return IndexInParent(); michael@0: } michael@0: michael@0: uint32_t michael@0: XULLinkAccessible::EndOffset() michael@0: { michael@0: if (Accessible::IsLink()) michael@0: return Accessible::EndOffset(); michael@0: return IndexInParent() + 1; michael@0: } michael@0: michael@0: already_AddRefed michael@0: XULLinkAccessible::AnchorURIAt(uint32_t aAnchorIndex) michael@0: { michael@0: if (aAnchorIndex != 0) michael@0: return nullptr; michael@0: michael@0: nsAutoString href; michael@0: mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::href, href); michael@0: michael@0: nsCOMPtr baseURI = mContent->GetBaseURI(); michael@0: nsIDocument* document = mContent->OwnerDoc(); michael@0: michael@0: nsCOMPtr anchorURI; michael@0: NS_NewURI(getter_AddRefs(anchorURI), href, michael@0: document->GetDocumentCharacterSet().get(), michael@0: baseURI); michael@0: michael@0: return anchorURI.forget(); michael@0: }