/* -*- 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 "BaseAccessibles.h" #include "Accessible-inl.h" #include "HyperTextAccessibleWrap.h" #include "nsAccessibilityService.h" #include "nsAccUtils.h" #include "nsCoreUtils.h" #include "Role.h" #include "States.h" #include "nsIURI.h" using namespace mozilla::a11y; //////////////////////////////////////////////////////////////////////////////// // LeafAccessible //////////////////////////////////////////////////////////////////////////////// LeafAccessible:: LeafAccessible(nsIContent* aContent, DocAccessible* aDoc) : AccessibleWrap(aContent, aDoc) { mStateFlags |= eNoKidsFromDOM; } NS_IMPL_ISUPPORTS_INHERITED0(LeafAccessible, Accessible) //////////////////////////////////////////////////////////////////////////////// // LeafAccessible: Accessible public Accessible* LeafAccessible::ChildAtPoint(int32_t aX, int32_t aY, EWhichChildAtPoint aWhichChild) { // Don't walk into leaf accessibles. return this; } bool LeafAccessible::InsertChildAt(uint32_t aIndex, Accessible* aChild) { NS_NOTREACHED("InsertChildAt called on leaf accessible!"); return false; } bool LeafAccessible::RemoveChild(Accessible* aChild) { NS_NOTREACHED("RemoveChild called on leaf accessible!"); return false; } bool LeafAccessible::IsAcceptableChild(nsIContent* aEl) const { // No children for leaf accessible. return false; } //////////////////////////////////////////////////////////////////////////////// // LinkableAccessible //////////////////////////////////////////////////////////////////////////////// NS_IMPL_ISUPPORTS_INHERITED0(LinkableAccessible, AccessibleWrap) //////////////////////////////////////////////////////////////////////////////// // LinkableAccessible. nsIAccessible void LinkableAccessible::TakeFocus() { if (Accessible* actionAcc = ActionWalk()) { actionAcc->TakeFocus(); } else { AccessibleWrap::TakeFocus(); } } uint64_t LinkableAccessible::NativeLinkState() const { bool isLink; Accessible* actionAcc = const_cast<LinkableAccessible*>(this)->ActionWalk(&isLink); if (isLink) { return states::LINKED | (actionAcc->LinkState() & states::TRAVERSED); } return 0; } void LinkableAccessible::Value(nsString& aValue) { aValue.Truncate(); Accessible::Value(aValue); if (!aValue.IsEmpty()) { return; } bool isLink; Accessible* actionAcc = ActionWalk(&isLink); if (isLink) { actionAcc->Value(aValue); } } uint8_t LinkableAccessible::ActionCount() { bool isLink, isOnclick, isLabelWithControl; ActionWalk(&isLink, &isOnclick, &isLabelWithControl); return (isLink || isOnclick || isLabelWithControl) ? 1 : 0; } Accessible* LinkableAccessible::ActionWalk(bool* aIsLink, bool* aIsOnclick, bool* aIsLabelWithControl) { if (aIsOnclick) { *aIsOnclick = false; } if (aIsLink) { *aIsLink = false; } if (aIsLabelWithControl) { *aIsLabelWithControl = false; } if (nsCoreUtils::HasClickListener(mContent)) { if (aIsOnclick) { *aIsOnclick = true; } return nullptr; } // XXX: The logic looks broken since the click listener may be registered // on non accessible node in parent chain but this node is skipped when tree // is traversed. Accessible* walkUpAcc = this; while ((walkUpAcc = walkUpAcc->Parent()) && !walkUpAcc->IsDoc()) { if (walkUpAcc->LinkState() & states::LINKED) { if (aIsLink) { *aIsLink = true; } return walkUpAcc; } if (nsCoreUtils::HasClickListener(walkUpAcc->GetContent())) { if (aIsOnclick) { *aIsOnclick = true; } return walkUpAcc; } if (nsCoreUtils::IsLabelWithControl(walkUpAcc->GetContent())) { if (aIsLabelWithControl) { *aIsLabelWithControl = true; } return walkUpAcc; } } return nullptr; } void LinkableAccessible::ActionNameAt(uint8_t aIndex, nsAString& aName) { aName.Truncate(); // Action 0 (default action): Jump to link if (aIndex == eAction_Jump) { bool isOnclick, isLink, isLabelWithControl; ActionWalk(&isLink, &isOnclick, &isLabelWithControl); if (isLink) { aName.AssignLiteral("jump"); } else if (isOnclick || isLabelWithControl) { aName.AssignLiteral("click"); } } } bool LinkableAccessible::DoAction(uint8_t aIndex) { if (aIndex != eAction_Jump) { return false; } if (Accessible* actionAcc = ActionWalk()) { return actionAcc->DoAction(aIndex); } return AccessibleWrap::DoAction(aIndex); } KeyBinding LinkableAccessible::AccessKey() const { if (const Accessible* actionAcc = const_cast<LinkableAccessible*>(this)->ActionWalk()) { return actionAcc->AccessKey(); } return Accessible::AccessKey(); } //////////////////////////////////////////////////////////////////////////////// // LinkableAccessible: HyperLinkAccessible already_AddRefed<nsIURI> LinkableAccessible::AnchorURIAt(uint32_t aAnchorIndex) { bool isLink; Accessible* actionAcc = ActionWalk(&isLink); if (isLink) { NS_ASSERTION(actionAcc->IsLink(), "HyperLink isn't implemented."); if (actionAcc->IsLink()) { return actionAcc->AnchorURIAt(aAnchorIndex); } } return nullptr; } //////////////////////////////////////////////////////////////////////////////// // DummyAccessible //////////////////////////////////////////////////////////////////////////////// uint64_t DummyAccessible::NativeState() { return 0; } uint64_t DummyAccessible::NativeInteractiveState() const { return 0; } uint64_t DummyAccessible::NativeLinkState() const { return 0; } bool DummyAccessible::NativelyUnavailable() const { return false; } void DummyAccessible::ApplyARIAState(uint64_t* aState) const { }