blob: 438ba7c2ff8b6470f728bc1a118a4017ad6f4c17 [file]
/*
* Copyright (C) 2012 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include "AXObjectRareData.h"
#include "AXTableHelpers.h"
#include "AXUtilities.h"
#include "AccessibilityObject.h"
#include "LayoutRect.h"
#include "RenderStyleConstants.h"
#include <wtf/Forward.h>
namespace WebCore {
class AXObjectCache;
class Element;
class HTMLLabelElement;
class Node;
class AccessibilityNodeObject : public AccessibilityObject {
public:
static Ref<AccessibilityNodeObject> create(AXID, Node*, AXObjectCache&);
virtual ~AccessibilityNodeObject();
void init() override;
void recomputeAriaRole() final { m_ariaRole = determineAriaRoleAttribute(); }
bool hasElementDescendant() const final;
bool isBusy() const final;
bool isDetached() const override { return !m_node; }
bool isFieldset() const final;
bool isAccessibilityList() const final;
bool isUnorderedList() const final;
bool isOrderedList() const final;
bool isDescriptionList() const final;
bool isMultiSelectable() const override;
bool isNativeImage() const;
bool isNativeTextControl() const final;
bool isSecureField() const final;
bool isSearchField() const final;
bool isChecked() const final;
bool isEnabled() const override;
bool isIndeterminate() const override;
bool isPressed() const final;
bool isRequired() const final;
bool supportsARIAOwns() const final;
bool supportsDropping() const final;
bool supportsDragging() const final;
bool isGrabbed() final;
Vector<String> determineDropEffects() const final;
bool canSetSelectedAttribute() const override;
Node* node() const final { return m_node.get(); }
CheckedPtr<Node> checkedNode() const { return node(); }
Document* document() const override;
LocalFrameView* documentFrameView() const override;
// Start table-related methods.
bool isTable() const final;
bool isAriaTable() const final { return AXTableHelpers::isTableRole(ariaRoleAttribute()); }
// isTable() check is last because it's the most expensive.
bool isExposableTable() const final { return hasRareData() && rareData()->isExposableTable() && isTable(); }
void recomputeIsExposableIfNecessary() final;
AccessibilityChildrenVector columns() final;
AccessibilityChildrenVector rows() final;
unsigned columnCount() final;
unsigned rowCount() final;
AccessibilityChildrenVector cells() final;
AccessibilityObject* cellForColumnAndRow(unsigned column, unsigned row) final;
AccessibilityChildrenVector rowHeaders() override;
AccessibilityChildrenVector visibleRows() final;
// Returns an object that contains, as children, all the objects that act as headers.
AccessibilityObject* tableHeaderContainer() final;
int axColumnCount() const final;
int axRowCount() const final;
Vector<Vector<Markable<AXID>>> cellSlots() final;
void setCellSlotsDirty();
// End table-related methods.
// Start table-row-related methods.
// FIXME: this method (and all references) should be renamed to something more accurate, like "containingTable".
AccessibilityObject* parentTable() const final;
void setRowIndex(unsigned);
unsigned rowIndex() const final { return hasRareData() ? rareData()->rowIndex() : 0; }
std::optional<unsigned> axColumnIndex() const override;
std::optional<unsigned> axRowIndex() const override;
String axRowIndexText() const final;
AccessibilityChildrenVector disclosedRows() final;
AccessibilityObject* disclosedByRow() const final;
AXCoreObject* parentTableIfExposedTableRow() const final;
bool isExposedTableRow() const final { return parentTableIfExposedTableRow(); }
bool isTableRow() const final;
// End table-row-related methods.
// Start table-cell-related methods.
bool isTableCell() const final;
bool isARIAGridCell() const;
bool isExposedTableCell() const final;
AccessibilityObject* parentTableIfTableCell() const final;
bool isTableHeaderCell() const;
bool isColumnHeader() const final;
bool isRowHeader() const final;
std::pair<unsigned, unsigned> rowIndexRange() const final;
std::pair<unsigned, unsigned> columnIndexRange() const final;
String axColumnIndexText() const final;
unsigned colSpan() const;
unsigned rowSpan() const;
void incrementEffectiveRowSpan();
void resetEffectiveRowSpan();
void setAXColIndexFromRow(int);
void setColumnIndex(unsigned);
#if USE(ATSPI)
int axColumnSpan() const;
int axRowSpan() const;
#endif
// End table-cell-related methods.
void setFocused(bool) override;
bool isFocused() const final;
bool canSetFocusAttribute() const override;
bool canSetValueAttribute() const override;
String valueDescription() const override;
float valueForRange() const override;
float maxValueForRange() const override;
float minValueForRange() const override;
float stepValueForRange() const override;
#if ENABLE(ATTACHMENT_ELEMENT)
bool hasProgress() const final;
#endif
std::optional<AccessibilityOrientation> orientationFromARIA() const;
std::optional<AccessibilityOrientation> explicitOrientation() const override { return orientationFromARIA(); }
AccessibilityButtonState checkboxOrRadioValue() const final;
URL url() const override;
String textUnderElement(TextUnderElementMode = TextUnderElementMode()) const override;
String accessibilityDescriptionForChildren() const;
String description() const override;
String helpText() const override;
String revealableText() const final;
bool isHiddenUntilFoundContainer() const final;
String text() const final;
void alternativeText(Vector<AccessibilityText>&) const;
void helpText(Vector<AccessibilityText>&) const;
String stringValue() const override;
bool isBlockFlow() const final;
std::optional<AXStitchGroup> stitchGroup(IncludeGroupMembers = IncludeGroupMembers::Yes) const final;
Vector<AXStitchGroup> stitchGroups() const final;
WallTime dateTimeValue() const final;
SRGBA<uint8_t> colorValue() const final;
String ariaLabeledByAttribute() const final;
bool hasAccNameAttribute() const;
bool hasAttributesRequiredForInclusion() const final;
bool hasClickHandler() const final;
bool hasCursorPointer() const final
{
CheckedPtr style = this->style();
return style && style->cursorType() == CursorType::Pointer && style->pointerEvents() != PointerEvents::None;
}
bool showsCursorOnHover() const final;
bool hasPointerEventsNone() const final;
void setIsExpanded(bool) final;
Element* actionElement() const override;
Element* anchorElement() const override;
RefPtr<Element> popoverTargetElement() const final;
RefPtr<Element> commandForElement() const final;
CommandType commandType() const final;
AccessibilityObject* internalLinkElement() const final;
AccessibilityChildrenVector radioButtonGroup() const final;
virtual void changeValueByPercent(float percentChange);
AccessibilityObject* firstChild() const override;
AccessibilityObject* lastChild() const override;
AccessibilityObject* previousSibling() const override;
AccessibilityObject* nextSibling() const override;
AccessibilityObject* parentObject() const override;
bool matchesTextAreaRole() const;
void increment() override;
void decrement() override;
bool toggleDetailsAncestor() final;
void revealAncestors() final;
LayoutRect elementRect() const override;
Path elementPath() const override;
bool supportsPath() const override { return isImageMapLink(); }
bool isLabelContainingOnlyStaticText() const;
bool isNativeLabel() const override;
#if ENABLE(ACCESSIBILITY_ISOLATED_TREE)
TextEmissionBehavior textEmissionBehavior() const final;
#endif
bool usesAltForTextComputation() const;
bool hasTextAlternative() const;
String ariaAccessibilityDescription() const;
protected:
explicit AccessibilityNodeObject(AXID, Node*, AXObjectCache&);
void detachRemoteParts(AccessibilityDetachmentType) override;
AccessibilityRole m_ariaRole { AccessibilityRole::Unknown };
// FIXME: These `is_` member variables should be replaced with an enum or be computed on demand.
// Only used by AccessibilitySVGObject, but placed here to use space that would otherwise be taken by padding.
bool m_isSVGRoot { false };
// Only used by isNativeLabel() objects. Placed here to use space that would otherwise be taken by padding.
mutable bool m_containsOnlyStaticTextDirty { false };
mutable bool m_containsOnlyStaticText { false };
#ifndef NDEBUG
bool m_initialized { false };
#endif
AccessibilityRole determineAccessibilityRole() override;
AccessibilityRole determineListRoleWithCleanChildren();
enum class TreatStyleFormatGroupAsInline : bool { No, Yes };
AccessibilityRole determineAccessibilityRoleFromNode(TreatStyleFormatGroupAsInline = TreatStyleFormatGroupAsInline::No) const;
AccessibilityRole roleFromInputElement(const HTMLInputElement&) const;
AccessibilityRole ariaRoleAttribute() const final { return m_ariaRole; }
virtual AccessibilityRole determineAriaRoleAttribute() const;
AccessibilityRole remapAriaRoleDueToParent(AccessibilityRole) const;
bool computeIsIgnored() const override;
void addChildren() override;
void clearChildren() override;
void updateChildrenIfNecessary() override;
bool canHaveChildren() const override;
void setSelectedChildren(const AccessibilityChildrenVector&) final;
AccessibilityChildrenVector visibleChildren() override;
bool isDescendantOfBarrenParent() const final;
void updateOwnedChildrenIfNecessary();
AccessibilityObject* ownerParentObject() const;
enum class StepAction : bool { Decrement, Increment };
void alterRangeValue(StepAction);
void changeValueByStep(StepAction);
// This returns true if it's focusable but it's not content editable and it's not a control or ARIA control.
bool isGenericFocusableElement() const;
VisiblePositionRange visiblePositionRange() const final;
VisiblePositionRange selectedVisiblePositionRange() const final;
VisiblePositionRange visiblePositionRangeForLine(unsigned) const final;
VisiblePosition visiblePositionForIndex(int) const override;
int indexForVisiblePosition(const VisiblePosition&) const override;
bool elementAttributeValue(const QualifiedName&) const;
const String explicitLiveRegionStatus() const final { return getAttribute(HTMLNames::aria_liveAttr); }
const String explicitLiveRegionRelevant() const final { return getAttribute(HTMLNames::aria_relevantAttr); }
bool liveRegionAtomic() const final;
String accessKey() const final;
bool isLabelable() const;
AccessibilityObject* controlForLabelElement() const final;
String textAsLabelFor(const AccessibilityObject&) const;
String textForLabelElements(Vector<Ref<HTMLElement>>&&) const;
HTMLLabelElement* labelElementContainer() const;
Vector<Ref<Element>> ariaLabeledByElements() const;
String descriptionForElements(const Vector<Ref<Element>>&) const;
LayoutRect boundingBoxRect() const override;
LayoutRect nonEmptyAncestorBoundingBox() const;
String ariaDescribedByAttribute() const final;
AccessibilityObject* captionForFigure() const;
virtual void labelText(Vector<AccessibilityText>&) const;
#if PLATFORM(IOS_FAMILY)
HTMLMediaElement* mediaElement() const;
HTMLVideoElement* videoElement() const;
#endif
void addTableChildrenAndCellSlots();
// Start of table-cell-related methods.
AccessibilityNodeObject* parentRow() const;
// End of table-cell-related methods.
bool isValidTree() const;
private:
bool isAccessibilityNodeObject() const final { return true; }
void accessibilityText(Vector<AccessibilityText>&) const override;
void visibleText(Vector<AccessibilityText>&) const;
String alternativeTextForWebArea() const;
void ariaLabeledByText(Vector<AccessibilityText>&) const;
bool roleIgnoresTitle() const;
bool postKeyboardKeysForValueChange(StepAction);
void setNodeValue(StepAction, float);
bool performDismissAction() final;
LayoutRect checkboxOrRadioRect() const;
void setNeedsToUpdateChildren() override { m_childrenDirty = true; }
bool needsToUpdateChildren() const final { return m_childrenDirty; }
void setNeedsToUpdateSubtree() final { m_subtreeDirty = true; }
bool isDescendantOfElementType(const HashSet<QualifiedName>&) const;
AXObjectRareData* rareDataWithCleanTableChildren();
// Returns the number of columns the table should have.
unsigned computeCellSlots();
// isDataTable / computeIsTableExposableThroughAccessibility perform heuristics to determine
// if a table should be exposed as a "semantic" data table in the accessibility API, or if
// this table is just used for layout and thus is not a "real" table.
bool computeIsTableExposableThroughAccessibility() const { return isAriaTable() || isDataTable(); }
bool isDataTable() const;
void updateRowDescendantRoles();
// Start of private table-row-related methods.
bool isARIAGridRow() const final;
bool isARIATreeGridRow() const final;
// End of private table-row-related methods.
// Start of private table-cell-related methods.
void ensureIndexesUpToDate() const;
// End of private table-cell-related methods.
protected:
WeakPtr<Node, WeakPtrImplWithEventTargetData> m_node;
};
namespace Accessibility {
RefPtr<HTMLElement> controlForLabelElement(const HTMLLabelElement&);
Vector<Ref<HTMLElement>> labelsForElement(Element*);
} // namespace Accessibility
} // namespace WebCore
SPECIALIZE_TYPE_TRAITS_ACCESSIBILITY(AccessibilityNodeObject, isAccessibilityNodeObject())