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 "HTMLLinkAccessible.h" michael@0: michael@0: #include "nsCoreUtils.h" michael@0: #include "DocAccessible.h" michael@0: #include "Role.h" michael@0: #include "States.h" michael@0: michael@0: #include "nsContentUtils.h" michael@0: #include "mozilla/EventStates.h" michael@0: #include "mozilla/dom/Element.h" michael@0: michael@0: using namespace mozilla; michael@0: using namespace mozilla::a11y; michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // HTMLLinkAccessible michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: HTMLLinkAccessible:: michael@0: HTMLLinkAccessible(nsIContent* aContent, DocAccessible* aDoc) : michael@0: HyperTextAccessibleWrap(aContent, aDoc) michael@0: { michael@0: } michael@0: michael@0: // Expose nsIAccessibleHyperLink unconditionally michael@0: NS_IMPL_ISUPPORTS_INHERITED(HTMLLinkAccessible, HyperTextAccessibleWrap, michael@0: nsIAccessibleHyperLink) michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // nsIAccessible michael@0: michael@0: role michael@0: HTMLLinkAccessible::NativeRole() michael@0: { michael@0: return roles::LINK; michael@0: } michael@0: michael@0: uint64_t michael@0: HTMLLinkAccessible::NativeState() michael@0: { michael@0: return HyperTextAccessibleWrap::NativeState() & ~states::READONLY; michael@0: } michael@0: michael@0: uint64_t michael@0: HTMLLinkAccessible::NativeLinkState() const michael@0: { michael@0: EventStates eventState = mContent->AsElement()->State(); michael@0: if (eventState.HasState(NS_EVENT_STATE_UNVISITED)) michael@0: return states::LINKED; michael@0: michael@0: if (eventState.HasState(NS_EVENT_STATE_VISITED)) michael@0: return states::LINKED | states::TRAVERSED; michael@0: michael@0: // This is a either named anchor (a link with also a name attribute) or michael@0: // it doesn't have any attributes. Check if 'click' event handler is michael@0: // registered, otherwise bail out. michael@0: return nsCoreUtils::HasClickListener(mContent) ? states::LINKED : 0; michael@0: } michael@0: michael@0: uint64_t michael@0: HTMLLinkAccessible::NativeInteractiveState() const michael@0: { michael@0: uint64_t state = HyperTextAccessibleWrap::NativeInteractiveState(); michael@0: michael@0: // This is how we indicate it is a named anchor. In other words, this anchor michael@0: // can be selected as a location :) There is no other better state to use to michael@0: // indicate this. michael@0: if (mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::name)) michael@0: state |= states::SELECTABLE; michael@0: michael@0: return state; michael@0: } michael@0: michael@0: void michael@0: HTMLLinkAccessible::Value(nsString& aValue) michael@0: { michael@0: aValue.Truncate(); michael@0: michael@0: HyperTextAccessible::Value(aValue); michael@0: if (aValue.IsEmpty()) michael@0: nsContentUtils::GetLinkLocation(mContent->AsElement(), aValue); michael@0: } michael@0: michael@0: uint8_t michael@0: HTMLLinkAccessible::ActionCount() michael@0: { michael@0: return IsLinked() ? 1 : HyperTextAccessible::ActionCount(); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: HTMLLinkAccessible::GetActionName(uint8_t aIndex, nsAString& aName) michael@0: { michael@0: aName.Truncate(); michael@0: michael@0: if (!IsLinked()) michael@0: return HyperTextAccessible::GetActionName(aIndex, aName); michael@0: michael@0: // Action 0 (default action): Jump to link 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: HTMLLinkAccessible::DoAction(uint8_t aIndex) michael@0: { michael@0: if (!IsLinked()) michael@0: return HyperTextAccessible::DoAction(aIndex); michael@0: michael@0: // Action 0 (default action): Jump to link 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: // HyperLinkAccessible michael@0: michael@0: bool michael@0: HTMLLinkAccessible::IsLink() michael@0: { michael@0: // Expose HyperLinkAccessible unconditionally. michael@0: return true; michael@0: } michael@0: michael@0: already_AddRefed michael@0: HTMLLinkAccessible::AnchorURIAt(uint32_t aAnchorIndex) michael@0: { michael@0: return aAnchorIndex == 0 ? mContent->GetHrefURI() : nullptr; michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // Protected members michael@0: michael@0: bool michael@0: HTMLLinkAccessible::IsLinked() michael@0: { michael@0: if (IsDefunct()) michael@0: return false; michael@0: michael@0: EventStates state = mContent->AsElement()->State(); michael@0: return state.HasAtLeastOneOfStates(NS_EVENT_STATE_VISITED | michael@0: NS_EVENT_STATE_UNVISITED); michael@0: }