/*
 * Copyright (C) 2008, 2009, 2011 Apple Inc. All rights reserved.
 * Copyright (C) 2008 Nuanti Ltd.
 *
 * 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 Computer, 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.
 */

#ifndef AXObject_h
#define AXObject_h

#include "core/editing/VisiblePosition.h"
#include "core/editing/markers/DocumentMarker.h"
#include "core/inspector/protocol/Accessibility.h"
#include "modules/ModulesExport.h"
#include "modules/accessibility/AXEnums.h"
#include "platform/geometry/FloatQuad.h"
#include "platform/geometry/LayoutRect.h"
#include "platform/graphics/Color.h"
#include "platform/wtf/Forward.h"
#include "platform/wtf/Vector.h"

class SkMatrix44;

namespace blink {

class AccessibleNodeList;
class AXObject;
class AXObjectCacheImpl;
class Element;
class IntPoint;
class LayoutObject;
class LocalFrameView;
class Node;
class ScrollableArea;

enum class AOMBooleanProperty;
enum class AOMStringProperty;
enum class AOMUIntProperty;
enum class AOMIntProperty;
enum class AOMFloatProperty;
enum class AOMRelationProperty;
enum class AOMRelationListProperty;

typedef unsigned AXID;

enum AccessibilityTextSource {
  kAlternativeText,
  kChildrenText,
  kSummaryText,
  kHelpText,
  kVisibleText,
  kTitleTagText,
  kPlaceholderText,
  kLabelByElementText,
};

class AccessibilityText final
    : public GarbageCollectedFinalized<AccessibilityText> {
  WTF_MAKE_NONCOPYABLE(AccessibilityText);

 public:
  DEFINE_INLINE_TRACE() { visitor->Trace(text_element_); }

 private:
  AccessibilityText(const String& text,
                    const AccessibilityTextSource& source,
                    AXObject* element)
      : text_(text), text_element_(element) {}

  String text_;
  Member<AXObject> text_element_;
};

enum AXObjectInclusion {
  kIncludeObject,
  kIgnoreObject,
  kDefaultBehavior,
};

enum AccessibilityCheckedState {
  kCheckedStateUndefined = 0,
  kCheckedStateFalse,
  kCheckedStateTrue,
  kCheckedStateMixed
};

enum AccessibilityOptionalBool {
  kOptionalBoolUndefined = 0,
  kOptionalBoolTrue,
  kOptionalBoolFalse
};

enum TextUnderElementMode {
  kTextUnderElementAll,
  kTextUnderElementAny  // If the text is unimportant, just whether or not it's
                        // present
};

enum class AXBoolAttribute {};

class AXSparseAttributeClient {
 public:
  virtual void AddBoolAttribute(AXBoolAttribute, bool) = 0;
  virtual void AddStringAttribute(AXStringAttribute, const String&) = 0;
  virtual void AddObjectAttribute(AXObjectAttribute, AXObject&) = 0;
  virtual void AddObjectVectorAttribute(AXObjectVectorAttribute,
                                        HeapVector<Member<AXObject>>&) = 0;
};

// The potential native HTML-based text (name, description or placeholder)
// sources for an element.  See
// http://rawgit.com/w3c/aria/master/html-aam/html-aam.html#accessible-name-and-description-calculation
enum AXTextFromNativeHTML {
  kAXTextFromNativeHTMLUninitialized = -1,
  kAXTextFromNativeHTMLFigcaption,
  kAXTextFromNativeHTMLLabel,
  kAXTextFromNativeHTMLLabelFor,
  kAXTextFromNativeHTMLLabelWrapped,
  kAXTextFromNativeHTMLLegend,
  kAXTextFromNativeHTMLTableCaption,
  kAXTextFromNativeHTMLTitleElement,
};

enum AXIgnoredReason {
  kAXActiveModalDialog,
  kAXAncestorDisallowsChild,
  kAXAncestorIsLeafNode,
  kAXAriaHiddenElement,
  kAXAriaHiddenSubtree,
  kAXEmptyAlt,
  kAXEmptyText,
  kAXInertElement,
  kAXInertSubtree,
  kAXInheritsPresentation,
  kAXLabelContainer,
  kAXLabelFor,
  kAXNotRendered,
  kAXNotVisible,
  kAXPresentationalRole,
  kAXProbablyPresentational,
  kAXStaticTextUsedAsNameFor,
  kAXUninteresting
};

class IgnoredReason {
  DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();

 public:
  AXIgnoredReason reason;
  Member<const AXObject> related_object;

  explicit IgnoredReason(AXIgnoredReason reason)
      : reason(reason), related_object(nullptr) {}

  IgnoredReason(AXIgnoredReason r, const AXObject* obj)
      : reason(r), related_object(obj) {}

  DEFINE_INLINE_TRACE() { visitor->Trace(related_object); }
};

class NameSourceRelatedObject
    : public GarbageCollectedFinalized<NameSourceRelatedObject> {
  WTF_MAKE_NONCOPYABLE(NameSourceRelatedObject);

 public:
  WeakMember<AXObject> object;
  String text;

  NameSourceRelatedObject(AXObject* object, String text)
      : object(object), text(text) {}

  DEFINE_INLINE_TRACE() { visitor->Trace(object); }
};

typedef HeapVector<Member<NameSourceRelatedObject>> AXRelatedObjectVector;
class NameSource {
  DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();

 public:
  String text;
  bool superseded = false;
  bool invalid = false;
  AXNameFrom type = kAXNameFromUninitialized;
  const QualifiedName& attribute;
  AtomicString attribute_value;
  AXTextFromNativeHTML native_source = kAXTextFromNativeHTMLUninitialized;
  AXRelatedObjectVector related_objects;

  NameSource(bool superseded, const QualifiedName& attr)
      : superseded(superseded), attribute(attr) {}

  explicit NameSource(bool superseded)
      : superseded(superseded), attribute(QualifiedName::Null()) {}

  DEFINE_INLINE_TRACE() { visitor->Trace(related_objects); }
};

class DescriptionSource {
  DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();

 public:
  String text;
  bool superseded = false;
  bool invalid = false;
  AXDescriptionFrom type = kAXDescriptionFromUninitialized;
  const QualifiedName& attribute;
  AtomicString attribute_value;
  AXTextFromNativeHTML native_source = kAXTextFromNativeHTMLUninitialized;
  AXRelatedObjectVector related_objects;

  DescriptionSource(bool superseded, const QualifiedName& attr)
      : superseded(superseded), attribute(attr) {}

  explicit DescriptionSource(bool superseded)
      : superseded(superseded), attribute(QualifiedName::Null()) {}

  DEFINE_INLINE_TRACE() { visitor->Trace(related_objects); }
};

}  // namespace blink

WTF_ALLOW_INIT_WITH_MEM_FUNCTIONS(blink::IgnoredReason);
WTF_ALLOW_INIT_WITH_MEM_FUNCTIONS(blink::NameSource);
WTF_ALLOW_INIT_WITH_MEM_FUNCTIONS(blink::DescriptionSource);

namespace blink {

class MODULES_EXPORT AXObject : public GarbageCollectedFinalized<AXObject> {
  WTF_MAKE_NONCOPYABLE(AXObject);

 public:
  typedef HeapVector<Member<AXObject>> AXObjectVector;

  struct AXRange {
    DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
    // The deepest descendant in which the range starts.
    // (nullptr means the current object.)
    Persistent<AXObject> anchor_object;
    // The number of characters and child objects in the anchor object
    // before the range starts.
    int anchor_offset;
    // When the same character offset could correspond to two possible
    // cursor positions, upstream means it's on the previous line rather
    // than the next line.
    TextAffinity anchor_affinity;

    // The deepest descendant in which the range ends.
    // (nullptr means the current object.)
    Persistent<AXObject> focus_object;
    // The number of characters and child objects in the focus object
    // before the range ends.
    int focus_offset;
    // When the same character offset could correspond to two possible
    // cursor positions, upstream means it's on the previous line rather
    // than the next line.
    TextAffinity focus_affinity;

    AXRange()
        : anchor_object(nullptr),
          anchor_offset(-1),
          anchor_affinity(TextAffinity::kUpstream),
          focus_object(nullptr),
          focus_offset(-1),
          focus_affinity(TextAffinity::kDownstream) {}

    AXRange(int start_offset, int end_offset)
        : anchor_object(nullptr),
          anchor_offset(start_offset),
          anchor_affinity(TextAffinity::kUpstream),
          focus_object(nullptr),
          focus_offset(end_offset),
          focus_affinity(TextAffinity::kDownstream) {}

    AXRange(AXObject* anchor_object,
            int anchor_offset,
            TextAffinity anchor_affinity,
            AXObject* focus_object,
            int focus_offset,
            TextAffinity focus_affinity)
        : anchor_object(anchor_object),
          anchor_offset(anchor_offset),
          anchor_affinity(anchor_affinity),
          focus_object(focus_object),
          focus_offset(focus_offset),
          focus_affinity(focus_affinity) {}

    bool IsValid() const {
      return ((anchor_object && focus_object) ||
              (!anchor_object && !focus_object)) &&
             anchor_offset >= 0 && focus_offset >= 0;
    }

    // Determines if the range only refers to text offsets under the current
    // object.
    bool IsSimple() const {
      return anchor_object == focus_object || !anchor_object || !focus_object;
    }
  };

 protected:
  AXObject(AXObjectCacheImpl&);

 public:
  virtual ~AXObject();
  DECLARE_VIRTUAL_TRACE();

  static unsigned NumberOfLiveAXObjects() { return number_of_live_ax_objects_; }

  // After constructing an AXObject, it must be given a
  // unique ID, then added to AXObjectCacheImpl, and finally init() must
  // be called last.
  void SetAXObjectID(AXID ax_object_id) { id_ = ax_object_id; }
  virtual void Init() {}

  // When the corresponding WebCore object that this AXObject
  // wraps is deleted, it must be detached.
  virtual void Detach();
  virtual bool IsDetached() const;

  // If the parent of this object is known, this can be faster than using
  // computeParent().
  virtual void SetParent(AXObject* parent) { parent_ = parent; }

  // The AXObjectCacheImpl that owns this object, and its unique ID within this
  // cache.
  AXObjectCacheImpl& AxObjectCache() const {
    DCHECK(ax_object_cache_);
    return *ax_object_cache_;
  }

  AXID AxObjectID() const { return id_; }

  // Wrappers that retrieve either an Accessibility Object Model property,
  // or the equivalent ARIA attribute, in that order.
  const AtomicString& GetAOMPropertyOrARIAAttribute(AOMStringProperty) const;
  Element* GetAOMPropertyOrARIAAttribute(AOMRelationProperty) const;
  bool HasAOMProperty(AOMRelationListProperty,
                      HeapVector<Member<Element>>& result) const;
  bool HasAOMPropertyOrARIAAttribute(AOMRelationListProperty,
                                     HeapVector<Member<Element>>& result) const;
  bool HasAOMPropertyOrARIAAttribute(AOMBooleanProperty, bool& result) const;
  bool AOMPropertyOrARIAAttributeIsTrue(AOMBooleanProperty) const;
  bool AOMPropertyOrARIAAttributeIsFalse(AOMBooleanProperty) const;
  bool HasAOMPropertyOrARIAAttribute(AOMUIntProperty, uint32_t& result) const;
  bool HasAOMPropertyOrARIAAttribute(AOMIntProperty, int32_t& result) const;
  bool HasAOMPropertyOrARIAAttribute(AOMFloatProperty, float& result) const;

  virtual void GetSparseAXAttributes(AXSparseAttributeClient&) const {}

  // Determine subclass type.
  virtual bool IsAXNodeObject() const { return false; }
  virtual bool IsAXLayoutObject() const { return false; }
  virtual bool IsAXInlineTextBox() const { return false; }
  virtual bool IsAXListBox() const { return false; }
  virtual bool IsAXListBoxOption() const { return false; }
  virtual bool IsAXRadioInput() const { return false; }
  virtual bool IsAXSVGRoot() const { return false; }

  // Check object role or purpose.
  virtual AccessibilityRole RoleValue() const { return role_; }
  bool IsARIATextControl() const;
  virtual bool IsARIATreeGridRow() const { return false; }
  virtual bool IsAXTable() const { return false; }
  virtual bool IsAnchor() const { return false; }
  bool IsButton() const;
  bool IsCanvas() const { return RoleValue() == kCanvasRole; }
  bool IsCheckbox() const { return RoleValue() == kCheckBoxRole; }
  bool IsCheckboxOrRadio() const { return IsCheckbox() || IsRadioButton(); }
  bool IsColorWell() const { return RoleValue() == kColorWellRole; }
  bool IsComboBox() const { return RoleValue() == kComboBoxRole; }
  virtual bool IsControl() const { return false; }
  virtual bool IsDataTable() const { return false; }
  virtual bool IsEmbeddedObject() const { return false; }
  virtual bool IsFieldset() const { return false; }
  virtual bool IsHeading() const { return false; }
  virtual bool IsImage() const { return false; }
  virtual bool IsImageMapLink() const { return false; }
  virtual bool IsInputImage() const { return false; }
  bool IsLandmarkRelated() const;
  virtual bool IsLink() const { return false; }
  virtual bool IsInPageLinkTarget() const { return false; }
  virtual bool IsList() const { return false; }
  virtual bool IsMenu() const { return false; }
  virtual bool IsMenuButton() const { return false; }
  virtual bool IsMenuList() const { return false; }
  virtual bool IsMenuListOption() const { return false; }
  virtual bool IsMenuListPopup() const { return false; }
  bool IsMenuRelated() const;
  virtual bool IsMeter() const { return false; }
  virtual bool IsMockObject() const { return false; }
  virtual bool IsNativeSpinButton() const { return false; }
  virtual bool IsNativeTextControl() const {
    return false;
  }  // input or textarea
  virtual bool IsNonNativeTextControl() const {
    return false;
  }  // contenteditable or role=textbox
  virtual bool IsPasswordField() const { return false; }
  virtual bool IsPasswordFieldAndShouldHideValue() const;
  bool IsPresentational() const {
    return RoleValue() == kNoneRole || RoleValue() == kPresentationalRole;
  }
  virtual bool IsProgressIndicator() const { return false; }
  bool IsRadioButton() const { return RoleValue() == kRadioButtonRole; }
  bool IsRange() const {
    return RoleValue() == kProgressIndicatorRole ||
           RoleValue() == kScrollBarRole || RoleValue() == kSliderRole ||
           RoleValue() == kSpinButtonRole || IsMoveableSplitter();
  }
  bool IsScrollbar() const { return RoleValue() == kScrollBarRole; }
  virtual bool IsSlider() const { return false; }
  virtual bool IsNativeSlider() const { return false; }
  virtual bool IsMoveableSplitter() const { return false; }
  virtual bool IsSpinButton() const { return RoleValue() == kSpinButtonRole; }
  virtual bool IsSpinButtonPart() const { return false; }
  bool IsTabItem() const { return RoleValue() == kTabRole; }
  virtual bool IsTableCell() const { return false; }
  virtual bool IsTableRow() const { return false; }
  virtual bool IsTextControl() const { return false; }
  virtual bool IsTableCol() const { return false; }
  bool IsTree() const { return RoleValue() == kTreeRole; }
  bool IsWebArea() const { return RoleValue() == kWebAreaRole; }

  // Check object state.
  virtual bool IsClickable() const;
  virtual bool IsCollapsed() const { return false; }
  virtual AccessibilityExpanded IsExpanded() const {
    return kExpandedUndefined;
  }
  virtual bool IsFocused() const { return false; }
  virtual bool IsHovered() const { return false; }
  virtual bool IsLinked() const { return false; }
  virtual bool IsLoaded() const { return false; }
  virtual bool IsModal() const { return false; }
  virtual bool IsMultiSelectable() const { return false; }
  virtual bool IsOffScreen() const { return false; }
  virtual bool IsRequired() const { return false; }
  virtual bool IsSelected() const { return false; }
  virtual bool IsSelectedOptionActive() const { return false; }
  virtual bool IsVisible() const { return true; }
  virtual bool IsVisited() const { return false; }

  // Check whether certain properties can be modified.
  virtual bool CanSetFocusAttribute() const;
  bool CanSetValueAttribute() const;
  virtual bool CanSetSelectedAttribute() const;

  // Whether objects are ignored, i.e. not included in the tree.
  bool AccessibilityIsIgnored();
  typedef HeapVector<IgnoredReason> IgnoredReasons;
  virtual bool ComputeAccessibilityIsIgnored(IgnoredReasons* = nullptr) const {
    return true;
  }
  bool AccessibilityIsIgnoredByDefault(IgnoredReasons* = nullptr) const;
  AXObjectInclusion AccessibilityPlatformIncludesObject() const;
  virtual AXObjectInclusion DefaultObjectInclusion(
      IgnoredReasons* = nullptr) const;
  bool IsInertOrAriaHidden() const;
  const AXObject* AriaHiddenRoot() const;
  bool ComputeIsInertOrAriaHidden(IgnoredReasons* = nullptr) const;
  bool IsDescendantOfLeafNode() const;
  AXObject* LeafNodeAncestor() const;
  bool IsDescendantOfDisabledNode() const;
  const AXObject* DisabledAncestor() const;
  bool LastKnownIsIgnoredValue();
  void SetLastKnownIsIgnoredValue(bool);
  bool HasInheritedPresentationalRole() const;
  bool IsPresentationalChild() const;
  bool AncestorExposesActiveDescendant() const;
  bool ComputeAncestorExposesActiveDescendant() const;

  //
  // Accessible name calculation
  //

  // Retrieves the accessible name of the object, an enum indicating where the
  // name was derived from, and a list of objects that were used to derive the
  // name, if any.
  virtual String GetName(AXNameFrom&, AXObjectVector* name_objects) const;

  typedef HeapVector<NameSource> NameSources;
  // Retrieves the accessible name of the object and a list of all potential
  // sources for the name, indicating which were used.
  virtual String GetName(NameSources*) const;

  typedef HeapVector<DescriptionSource> DescriptionSources;
  // Takes the result of nameFrom from calling |name|, above, and retrieves the
  // accessible description of the object, which is secondary to |name|, an enum
  // indicating where the description was derived from, and a list of objects
  // that were used to derive the description, if any.
  virtual String Description(AXNameFrom,
                             AXDescriptionFrom&,
                             AXObjectVector* description_objects) const {
    return String();
  }

  // Same as above, but returns a list of all potential sources for the
  // description, indicating which were used.
  virtual String Description(AXNameFrom,
                             AXDescriptionFrom&,
                             DescriptionSources*,
                             AXRelatedObjectVector*) const {
    return String();
  }

  // Takes the result of nameFrom and descriptionFrom from calling |name| and
  // |description|, above, and retrieves the placeholder of the object, if
  // present and if it wasn't already exposed by one of the two functions above.
  virtual String Placeholder(AXNameFrom) const { return String(); }

  // Internal functions used by name and description, above.
  typedef HeapHashSet<Member<const AXObject>> AXObjectSet;
  virtual String TextAlternative(bool recursive,
                                 bool in_aria_labelled_by_traversal,
                                 AXObjectSet& visited,
                                 AXNameFrom& name_from,
                                 AXRelatedObjectVector* related_objects,
                                 NameSources* name_sources) const {
    return String();
  }
  virtual String TextFromDescendants(AXObjectSet& visited,
                                     bool recursive) const {
    return String();
  }

  // Returns result of Accessible Name Calculation algorithm.
  // This is a simpler high-level interface to |name| used by Inspector.
  String ComputedName() const;

  // Internal function used to determine whether the result of calling |name| on
  // this object would return text that came from the an HTML label element or
  // not. This is intended to be faster than calling |name| or
  // |textAlternative|, and without side effects (it won't call
  // axObjectCache->getOrCreate).
  virtual bool NameFromLabelElement() const { return false; }

  //
  // Properties of static elements.
  //

  virtual const AtomicString& AccessKey() const { return g_null_atom; }
  RGBA32 BackgroundColor() const;
  virtual RGBA32 ComputeBackgroundColor() const { return Color::kTransparent; }
  virtual RGBA32 GetColor() const { return Color::kBlack; }
  // Used by objects of role ColorWellRole.
  virtual RGBA32 ColorValue() const { return Color::kTransparent; }
  virtual bool CanvasHasFallbackContent() const { return false; }
  virtual String FontFamily() const { return g_null_atom; }
  // Font size is in pixels.
  virtual float FontSize() const { return 0.0f; }
  // Value should be 1-based. 0 means not supported.
  virtual int HeadingLevel() const { return 0; }
  // Value should be 1-based. 0 means not supported.
  virtual unsigned HierarchicalLevel() const { return 0; }
  // Return the content of an image or canvas as an image data url in
  // PNG format. If |maxSize| is not empty and if the image is larger than
  // those dimensions, the image will be resized proportionally first to fit.
  virtual String ImageDataUrl(const IntSize& max_size) const {
    return g_null_atom;
  }
  virtual AXObject* InPageLinkTarget() const { return nullptr; }
  virtual AccessibilityOrientation Orientation() const;
  virtual String GetText() const { return String(); }
  virtual AccessibilityTextDirection GetTextDirection() const {
    return kAccessibilityTextDirectionLTR;
  }
  virtual int TextLength() const { return 0; }
  virtual TextStyle GetTextStyle() const { return kTextStyleNone; }
  virtual AXObjectVector RadioButtonsInGroup() const {
    return AXObjectVector();
  }
  virtual KURL Url() const { return KURL(); }

  // Load inline text boxes for just this node, even if
  // settings->inlineTextBoxAccessibilityEnabled() is false.
  virtual void LoadInlineTextBoxes() {}

  // Walk the AXObjects on the same line. This is supported on any
  // object type but primarily intended to be used for inline text boxes.
  virtual AXObject* NextOnLine() const { return nullptr; }
  virtual AXObject* PreviousOnLine() const { return nullptr; }

  // For all node objects. The start and end character offset of each
  // marker, such as spelling or grammar error.
  virtual void Markers(Vector<DocumentMarker::MarkerType>&,
                       Vector<AXRange>&) const {}
  // For an inline text box.
  // The integer horizontal pixel offset of each character in the string;
  // negative values for RTL.
  virtual void TextCharacterOffsets(Vector<int>&) const {}
  // The start and end character offset of each word in the object's text.
  virtual void GetWordBoundaries(Vector<AXRange>&) const {}

  // Properties of interactive elements.
  AXDefaultActionVerb Action() const;
  AccessibilityCheckedState CheckedState() const;
  virtual AriaCurrentState GetAriaCurrentState() const {
    return kAriaCurrentStateUndefined;
  }
  virtual InvalidState GetInvalidState() const {
    return kInvalidStateUndefined;
  }
  // Only used when invalidState() returns InvalidStateOther.
  virtual String AriaInvalidValue() const { return String(); }
  virtual String ValueDescription() const { return String(); }
  virtual float ValueForRange() const { return 0.0f; }
  virtual float MaxValueForRange() const { return 0.0f; }
  virtual float MinValueForRange() const { return 0.0f; }
  virtual String StringValue() const { return String(); }
  virtual AXRestriction Restriction() const { return kNone; }

  // ARIA attributes.
  virtual AXObject* ActiveDescendant() { return nullptr; }
  virtual String AriaAutoComplete() const { return String(); }
  virtual void AriaOwnsElements(AXObjectVector& owns) const {}
  virtual void AriaDescribedbyElements(AXObjectVector&) const {}
  virtual void AriaLabelledbyElements(AXObjectVector&) const {}
  virtual bool AriaHasPopup() const { return false; }
  virtual bool IsEditable() const { return false; }
  virtual bool IsMultiline() const { return false; }
  virtual bool IsRichlyEditable() const { return false; }
  bool AriaCheckedIsPresent() const;
  bool AriaPressedIsPresent() const;
  virtual AccessibilityRole AriaRoleAttribute() const { return kUnknownRole; }
  virtual bool AriaRoleHasPresentationalChildren() const { return false; }
  virtual AXObject* AncestorForWhichThisIsAPresentationalChild() const {
    return 0;
  }
  bool SupportsActiveDescendant() const;
  bool SupportsARIAAttributes() const;
  virtual bool SupportsARIADragging() const { return false; }
  virtual bool SupportsARIADropping() const { return false; }
  virtual bool SupportsARIAFlowTo() const { return false; }
  virtual bool SupportsARIAOwns() const { return false; }
  bool SupportsRangeValue() const;
  virtual SortDirection GetSortDirection() const {
    return kSortDirectionUndefined;
  }

  // Returns 0-based index.
  int IndexInParent() const;

  // Value should be 1-based. 0 means not supported.
  virtual int PosInSet() const { return 0; }
  virtual int SetSize() const { return 0; }
  bool SupportsSetSizeAndPosInSet() const;

  // ARIA live-region features.
  bool IsLiveRegion() const;
  AXObject* LiveRegionRoot() const;
  virtual const AtomicString& LiveRegionStatus() const { return g_null_atom; }
  virtual const AtomicString& LiveRegionRelevant() const { return g_null_atom; }
  virtual bool LiveRegionAtomic() const { return false; }
  virtual bool LiveRegionBusy() const { return false; }

  const AtomicString& ContainerLiveRegionStatus() const;
  const AtomicString& ContainerLiveRegionRelevant() const;
  bool ContainerLiveRegionAtomic() const;
  bool ContainerLiveRegionBusy() const;

  // Every object's bounding box is returned relative to a
  // container object (which is guaranteed to be an ancestor) and
  // optionally a transformation matrix that needs to be applied too.
  // To compute the absolute bounding box of an element, start with its
  // boundsInContainer and apply the transform. Then as long as its container is
  // not null, walk up to its container and offset by the container's offset
  // from origin, the container's scroll position if any, and apply the
  // container's transform.  Do this until you reach the root of the tree.
  virtual void GetRelativeBounds(AXObject** out_container,
                                 FloatRect& out_bounds_in_container,
                                 SkMatrix44& out_container_transform) const;

  // Get the bounds in frame-relative coordinates as a LayoutRect.
  LayoutRect GetBoundsInFrameCoordinates() const;

  // Explicitly set an object's bounding rect and offset container.
  void SetElementRect(LayoutRect r, AXObject* container) {
    explicit_element_rect_ = r;
    explicit_container_id_ = container->AxObjectID();
  }

  // Hit testing.
  // Called on the root AX object to return the deepest available element.
  virtual AXObject* AccessibilityHitTest(const IntPoint&) const { return 0; }
  // Called on the AX object after the layout tree determines which is the right
  // AXLayoutObject.
  virtual AXObject* ElementAccessibilityHitTest(const IntPoint&) const;

  // High-level accessibility tree access. Other modules should only use these
  // functions.
  const AXObjectVector& Children();
  AXObject* ParentObject() const;
  AXObject* ParentObjectIfExists() const;
  virtual AXObject* ComputeParent() const = 0;
  virtual AXObject* ComputeParentIfExists() const { return 0; }
  AXObject* CachedParentObject() const { return parent_; }
  AXObject* ParentObjectUnignored() const;
  AXObject* ContainerWidget() const;
  bool IsContainerWidget() const;

  // Low-level accessibility tree exploration, only for use within the
  // accessibility module.
  virtual AXObject* RawFirstChild() const { return 0; }
  virtual AXObject* RawNextSibling() const { return 0; }
  virtual void AddChildren() {}
  virtual bool CanHaveChildren() const { return true; }
  bool HasChildren() const { return have_children_; }
  virtual void UpdateChildrenIfNecessary();
  virtual bool NeedsToUpdateChildren() const { return false; }
  virtual void SetNeedsToUpdateChildren() {}
  virtual void ClearChildren();
  virtual void DetachFromParent() { parent_ = 0; }
  virtual AXObject* ScrollBar(AccessibilityOrientation) { return 0; }

  // Properties of the object's owning document or page.
  virtual double EstimatedLoadingProgress() const { return 0; }

  // DOM and layout tree access.
  virtual Node* GetNode() const { return nullptr; }
  virtual Element* GetElement() const;  // Same as GetNode, if it's an Element.
  virtual LayoutObject* GetLayoutObject() const { return nullptr; }
  virtual Document* GetDocument() const;
  virtual LocalFrameView* DocumentFrameView() const;
  virtual Element* AnchorElement() const { return nullptr; }
  virtual Element* ActionElement() const { return nullptr; }
  String Language() const;
  bool HasAttribute(const QualifiedName&) const;
  const AtomicString& GetAttribute(const QualifiedName&) const;

  // Methods that retrieve or manipulate the current selection.

  // Get the current selection from anywhere in the accessibility tree.
  virtual AXRange Selection() const { return AXRange(); }
  // Gets only the start and end offsets of the selection computed using the
  // current object as the starting point. Returns a null selection if there is
  // no selection in the subtree rooted at this object.
  virtual AXRange SelectionUnderObject() const { return AXRange(); }
  virtual void SetSelection(const AXRange&) {}

  // Scrollable containers.
  bool IsScrollableContainer() const;
  IntPoint GetScrollOffset() const;
  IntPoint MinimumScrollOffset() const;
  IntPoint MaximumScrollOffset() const;
  void SetScrollOffset(const IntPoint&) const;

  // If this object itself scrolls, return its ScrollableArea.
  virtual ScrollableArea* GetScrollableAreaIfScrollable() const { return 0; }

  // Modify or take an action on an object.
  virtual void Increment() {}
  virtual void Decrement() {}
  bool PerformDefaultAction() { return Press(); }
  virtual bool Press();
  // Make this object visible by scrolling as many nested scrollable views as
  // needed.
  void ScrollToMakeVisible() const;
  // Same, but if the whole object can't be made visible, try for this subrect,
  // in local coordinates.
  void ScrollToMakeVisibleWithSubFocus(const IntRect&) const;
  // Scroll this object to a given point in global coordinates of the top-level
  // window.
  void ScrollToGlobalPoint(const IntPoint&) const;
  virtual void SetFocused(bool) {}
  virtual void SetSelected(bool) {}
  virtual void SetSequentialFocusNavigationStartingPoint();
  virtual void SetValue(const String&) {}
  virtual void SetValue(float) {}

  // Notifications that this object may have changed.
  virtual void ChildrenChanged() {}
  virtual void HandleActiveDescendantChanged() {}
  virtual void HandleAriaExpandedChanged() {}
  void NotifyIfIgnoredValueChanged();
  virtual void SelectionChanged();
  virtual void TextChanged() {}
  virtual void UpdateAccessibilityRole() {}

  // Text metrics. Most of these should be deprecated, needs major cleanup.
  virtual VisiblePosition VisiblePositionForIndex(int) const {
    return VisiblePosition();
  }
  int LineForPosition(const VisiblePosition&) const;
  virtual int Index(const VisiblePosition&) const { return -1; }
  virtual void LineBreaks(Vector<int>&) const {}

  // Static helper functions.
  static bool IsARIAControl(AccessibilityRole);
  static bool IsARIAInput(AccessibilityRole);
  // Is this a widget that requires container widget
  static bool IsSubWidget(AccessibilityRole);
  static AccessibilityRole AriaRoleToWebCoreRole(const String&);
  static const AtomicString& RoleName(AccessibilityRole);
  static const AtomicString& InternalRoleName(AccessibilityRole);
  static void AccessibleNodeListToElementVector(const AccessibleNodeList&,
                                                HeapVector<Member<Element>>&);

 protected:
  AXID id_;
  AXObjectVector children_;
  mutable bool have_children_;
  AccessibilityRole role_;
  AXObjectInclusion last_known_is_ignored_value_;
  LayoutRect explicit_element_rect_;
  AXID explicit_container_id_;

  // Used only inside textAlternative():
  static String CollapseWhitespace(const String&);
  static String RecursiveTextAlternative(const AXObject&,
                                         bool in_aria_labelled_by_traversal,
                                         AXObjectSet& visited);
  bool IsHiddenForTextAlternativeCalculation() const;
  String AriaTextAlternative(bool recursive,
                             bool in_aria_labelled_by_traversal,
                             AXObjectSet& visited,
                             AXNameFrom&,
                             AXRelatedObjectVector*,
                             NameSources*,
                             bool* found_text_alternative) const;
  String TextFromElements(bool in_aria_labelled_by_traversal,
                          AXObjectSet& visited,
                          HeapVector<Member<Element>>& elements,
                          AXRelatedObjectVector* related_objects) const;
  void TokenVectorFromAttribute(Vector<String>&, const QualifiedName&) const;
  void ElementsFromAttribute(HeapVector<Member<Element>>& elements,
                             const QualifiedName&) const;
  void AriaLabelledbyElementVector(HeapVector<Member<Element>>& elements) const;
  String TextFromAriaLabelledby(AXObjectSet& visited,
                                AXRelatedObjectVector* related_objects) const;
  String TextFromAriaDescribedby(AXRelatedObjectVector* related_objects) const;
  virtual const AXObject* InheritsPresentationalRoleFrom() const { return 0; }

  bool CanReceiveAccessibilityFocus() const;
  bool NameFromContents(bool recursive) const;

  AccessibilityRole ButtonRoleType() const;

  virtual LayoutObject* LayoutObjectForRelativeBounds() const {
    return nullptr;
  }

  const AXObject* InertRoot() const;

  mutable Member<AXObject> parent_;

  // The following cached attribute values (the ones starting with m_cached*)
  // are only valid if m_lastModificationCount matches
  // AXObjectCacheImpl::modificationCount().
  mutable int last_modification_count_;
  mutable RGBA32 cached_background_color_;
  mutable bool cached_is_ignored_ : 1;
  mutable bool cached_is_inert_or_aria_hidden_ : 1;
  mutable bool cached_is_descendant_of_leaf_node_ : 1;
  mutable bool cached_is_descendant_of_disabled_node_ : 1;
  mutable bool cached_has_inherited_presentational_role_ : 1;
  mutable bool cached_is_presentational_child_ : 1;
  mutable bool cached_ancestor_exposes_active_descendant_ : 1;
  mutable Member<AXObject> cached_live_region_root_;

  Member<AXObjectCacheImpl> ax_object_cache_;

  // Updates the cached attribute values. This may be recursive, so to prevent
  // deadlocks,
  // functions called here may only search up the tree (ancestors), not down.
  void UpdateCachedAttributeValuesIfNeeded() const;

 private:
  bool IsCheckable() const;
  static bool IsNativeCheckboxInMixedState(const Node*);
  static bool IncludesARIAWidgetRole(const String&);
  static bool HasInteractiveARIAAttribute(const Element&);

  static unsigned number_of_live_ax_objects_;
};

#define DEFINE_AX_OBJECT_TYPE_CASTS(thisType, predicate)           \
  DEFINE_TYPE_CASTS(thisType, AXObject, object, object->predicate, \
                    object.predicate)

}  // namespace blink

#endif  // AXObject_h
