1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "HTMLLinkAccessible.h"
8 #include "CacheConstants.h"
9 #include "nsCoreUtils.h"
10 #include "mozilla/a11y/Role.h"
13 #include "nsContentUtils.h"
14 #include "mozilla/a11y/DocAccessible.h"
15 #include "mozilla/dom/Element.h"
16 #include "mozilla/dom/MutationEventBinding.h"
18 using namespace mozilla
;
19 using namespace mozilla::a11y
;
21 ////////////////////////////////////////////////////////////////////////////////
23 ////////////////////////////////////////////////////////////////////////////////
25 HTMLLinkAccessible::HTMLLinkAccessible(nsIContent
* aContent
,
27 : HyperTextAccessible(aContent
, aDoc
) {
28 mType
= eHTMLLinkType
;
31 ////////////////////////////////////////////////////////////////////////////////
34 role
HTMLLinkAccessible::NativeRole() const { return roles::LINK
; }
36 uint64_t HTMLLinkAccessible::NativeState() const {
37 return HyperTextAccessible::NativeState() & ~states::READONLY
;
40 uint64_t HTMLLinkAccessible::NativeLinkState() const {
41 dom::ElementState state
= mContent
->AsElement()->State();
42 if (state
.HasState(dom::ElementState::UNVISITED
)) {
43 return states::LINKED
;
46 if (state
.HasState(dom::ElementState::VISITED
)) {
47 return states::LINKED
| states::TRAVERSED
;
50 // This is a either named anchor (a link with also a name attribute) or
51 // it doesn't have any attributes. Check if 'click' event handler is
52 // registered, otherwise bail out.
53 return nsCoreUtils::HasClickListener(mContent
) ? states::LINKED
: 0;
56 uint64_t HTMLLinkAccessible::NativeInteractiveState() const {
57 uint64_t state
= HyperTextAccessible::NativeInteractiveState();
59 // This is how we indicate it is a named anchor. In other words, this anchor
60 // can be selected as a location :) There is no other better state to use to
62 if (mContent
->AsElement()->HasAttr(nsGkAtoms::name
)) {
63 state
|= states::SELECTABLE
;
69 void HTMLLinkAccessible::Value(nsString
& aValue
) const {
72 HyperTextAccessible::Value(aValue
);
73 if (aValue
.IsEmpty()) {
74 nsContentUtils::GetLinkLocation(mContent
->AsElement(), aValue
);
78 bool HTMLLinkAccessible::HasPrimaryAction() const {
79 return IsLinked() || HyperTextAccessible::HasPrimaryAction();
83 void HTMLLinkAccessible::ActionNameAt(uint8_t aIndex
, nsAString
& aName
) {
87 HyperTextAccessible::ActionNameAt(aIndex
, aName
);
91 // Action 0 (default action): Jump to link
92 if (aIndex
== eAction_Jump
) aName
.AssignLiteral("jump");
95 bool HTMLLinkAccessible::AttributeChangesState(nsAtom
* aAttribute
) {
96 return aAttribute
== nsGkAtoms::href
||
97 HyperTextAccessible::AttributeChangesState(aAttribute
);
100 void HTMLLinkAccessible::DOMAttributeChanged(int32_t aNameSpaceID
,
103 const nsAttrValue
* aOldValue
,
104 uint64_t aOldState
) {
105 HyperTextAccessible::DOMAttributeChanged(aNameSpaceID
, aAttribute
, aModType
,
106 aOldValue
, aOldState
);
108 if (aAttribute
== nsGkAtoms::href
&&
109 (aModType
== dom::MutationEvent_Binding::ADDITION
||
110 aModType
== dom::MutationEvent_Binding::REMOVAL
)) {
111 mDoc
->QueueCacheUpdate(this, CacheDomain::Actions
);
115 ////////////////////////////////////////////////////////////////////////////////
116 // HyperLinkAccessible
118 bool HTMLLinkAccessible::IsLink() const {
119 // Expose HyperLinkAccessible unconditionally.
123 ////////////////////////////////////////////////////////////////////////////////
124 // HTMLLinkAccessible
126 bool HTMLLinkAccessible::IsLinked() const {
127 dom::ElementState state
= mContent
->AsElement()->State();
128 return state
.HasAtLeastOneOfStates(dom::ElementState::VISITED_OR_UNVISITED
);