/* 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/. */

#ifndef CacheConstants_h_
#define CacheConstants_h_

#include "mozilla/a11y/RelationType.h"
#include "nsGkAtoms.h"

namespace mozilla {
namespace a11y {

class CacheDomain {
 public:
  static constexpr uint64_t None = 0;
  static constexpr uint64_t NameAndDescription = ((uint64_t)0x1) << 0;
  static constexpr uint64_t Value = ((uint64_t)0x1) << 1;
  static constexpr uint64_t Bounds = ((uint64_t)0x1) << 2;
  static constexpr uint64_t Resolution = ((uint64_t)0x1) << 3;
  static constexpr uint64_t Text = ((uint64_t)0x1) << 4;
  static constexpr uint64_t DOMNodeIDAndClass = ((uint64_t)0x1) << 5;
  static constexpr uint64_t State = ((uint64_t)0x1) << 6;
  static constexpr uint64_t GroupInfo = ((uint64_t)0x1) << 7;
  static constexpr uint64_t Actions = ((uint64_t)0x1) << 8;
  static constexpr uint64_t Style = ((uint64_t)0x1) << 9;
  static constexpr uint64_t TransformMatrix = ((uint64_t)0x1) << 10;
  static constexpr uint64_t ScrollPosition = ((uint64_t)0x1) << 11;
  static constexpr uint64_t Table = ((uint64_t)0x1) << 12;
  static constexpr uint64_t TextOffsetAttributes = ((uint64_t)0x1) << 13;
  static constexpr uint64_t Viewport = ((uint64_t)0x1) << 14;
  static constexpr uint64_t ARIA = ((uint64_t)0x1) << 15;
  static constexpr uint64_t Relations = ((uint64_t)0x1) << 16;
#ifdef XP_WIN
  // Used for MathML.
  static constexpr uint64_t InnerHTML = ((uint64_t)0x1) << 17;
#endif
  static constexpr uint64_t TextBounds = ((uint64_t)0x1) << 18;
  static constexpr uint64_t APZ = ((uint64_t)0x1) << 19;
  static constexpr uint64_t All = ~((uint64_t)0x0);
};

// Cache domains needed by PdfStructTreeBuilder to walk an accessibility tree
// and produce a tagged PDF struct tree. These are all the domains required by
// calls from PdfStructTreeBuilder::BuildStructSubtree.
static constexpr uint64_t kPdfCacheDomains =
    // RemoteAccessible::Name
    CacheDomain::NameAndDescription | CacheDomain::Text |
    CacheDomain::Relations |
    // Accessible::GroupPosition
    CacheDomain::ARIA | CacheDomain::GroupInfo | CacheDomain::State |
    CacheDomain::Viewport |
    // TableCellAccessible headers/spans
    CacheDomain::Table;

enum class CacheUpdateType {
  /*
   * An initial cache push of a loaded document or inserted subtree.
   */
  Initial,

  /*
   * An incremental cache push of one or more fields that have changed.
   */
  Update,
};

struct RelationData {
  nsStaticAtom* const mAtom;
  nsStaticAtom* const mValidTag;
  RelationType mType;
  RelationType mReverseType;
};

/**
 * This array of RelationData lists our relation types (explicit and reverse)
 * and the cache attribute atoms that store their targets. Attributes may
 * describe different kinds of relations, depending on the element they
 * originate on. For example, an <output> element's `for` attribute describes a
 * CONTROLLER_FOR relation, while the `for` attribute of a <label> describes a
 * LABEL_FOR relation. To ensure we process these attributes appropriately,
 * RelationData.mValidTag contains the atom for the tag this attribute/relation
 * type pairing is valid on. If the pairing is valid for all tag types, this
 * field is null.
 */
static constexpr RelationData kRelationTypeAtoms[] = {
    {nsGkAtoms::aria_labelledby, nullptr, RelationType::LABELLED_BY,
     RelationType::LABEL_FOR},
    {nsGkAtoms::_for, nsGkAtoms::label, RelationType::LABEL_FOR,
     RelationType::LABELLED_BY},
    {nsGkAtoms::aria_controls, nullptr, RelationType::CONTROLLER_FOR,
     RelationType::CONTROLLED_BY},
    {nsGkAtoms::_for, nsGkAtoms::output, RelationType::CONTROLLED_BY,
     RelationType::CONTROLLER_FOR},
    {nsGkAtoms::aria_describedby, nullptr, RelationType::DESCRIBED_BY,
     RelationType::DESCRIPTION_FOR},
    {nsGkAtoms::commandfor, nullptr, RelationType::DESCRIBED_BY,
     RelationType::DESCRIPTION_FOR},
    {nsGkAtoms::popovertarget, nullptr, RelationType::DESCRIBED_BY,
     RelationType::DESCRIPTION_FOR},
    {nsGkAtoms::aria_flowto, nullptr, RelationType::FLOWS_TO,
     RelationType::FLOWS_FROM},
    {nsGkAtoms::aria_details, nullptr, RelationType::DETAILS,
     RelationType::DETAILS_FOR},
    {nsGkAtoms::commandfor, nullptr, RelationType::DETAILS,
     RelationType::DETAILS_FOR},
    {nsGkAtoms::popovertarget, nullptr, RelationType::DETAILS,
     RelationType::DETAILS_FOR},
    {nsGkAtoms::target, nullptr, RelationType::DETAILS,
     RelationType::DETAILS_FOR},
    {nsGkAtoms::aria_errormessage, nullptr, RelationType::ERRORMSG,
     RelationType::ERRORMSG_FOR},
    {nsGkAtoms::aria_actions, nullptr, RelationType::ACTION,
     RelationType::ACTION_FOR},
};

// The count of numbers needed to serialize an nsRect. This is used when
// flattening character rects into an array of ints.
constexpr int32_t kNumbersInRect = 4;

/**
 * RemoteAccessible cache keys.
 * Cache keys are nsAtoms, but this is mostly an implementation detail. Rather
 * than creating new atoms specific to the RemoteAccessible cache, we often
 * reuse existing atoms which are a reasonably close match for the value we're
 * caching, though the choices aren't always clear or intuitive. For clarity, we
 * alias the cache keys to atoms below. Code dealing with the RemoteAccessible
 * cache should generally use these aliases rather than using nsAtoms directly.
 * There are two exceptions:
 * 1. Some ARIA attributes are copied directly from the DOM node, so these
 * aren't aliased. Specifically, aria-level, aria-posinset and aria-setsize
 * are copied as separate cache keys as part of CacheDomain::GroupInfo.
 * 2. Keys for relations are defined in kRelationTypeAtoms above.
 */
class CacheKey {
 public:
  // uint64_t, CacheDomain::Actions
  // As returned by Accessible::AccessKey.
  static constexpr nsStaticAtom* AccessKey = nsGkAtoms::accesskey;
  // int32_t, no domain
  static constexpr nsStaticAtom* AppUnitsPerDevPixel =
      nsGkAtoms::_moz_device_pixel_ratio;
  // nsTArray<uint32_t>, CacheDomain::APZ
  // The difference between the layout viewport and the visual viewport in app
  // units. This is stored as a two-element (x, y) array and is unscaled by zoom
  // or resolution.
  static constexpr nsStaticAtom* VisualViewportOffset = nsGkAtoms::voffset;
  // AccAttributes, CacheDomain::ARIA
  // ARIA attributes that are exposed as object attributes; i.e. returned in
  // Accessible::Attributes.
  static constexpr nsStaticAtom* ARIAAttributes = nsGkAtoms::aria;
  // nsString, CacheUpdateType::Initial
  // The ARIA role attribute if the role is unknown or if there are multiple
  // roles.
  static constexpr nsStaticAtom* ARIARole = nsGkAtoms::role;
  // bool, CacheDomain::State
  // The aria-selected attribute.
  static constexpr nsStaticAtom* ARIASelected = nsGkAtoms::aria_selected;
  // nsTArray<uint64_t>, CacheDomain::Table
  // The explicit headers of an HTML table cell.
  static constexpr nsStaticAtom* CellHeaders = nsGkAtoms::headers;
  // int32_t, CacheDomain::Table
  // The colspan of an HTML table cell.
  static constexpr nsStaticAtom* ColSpan = nsGkAtoms::colspan;
  // nsTArray<int32_t, 2>, CacheDomain::Bounds
  // The offset from an OuterDocAccessible (iframe) to its embedded document.
  static constexpr nsStaticAtom* CrossDocOffset = nsGkAtoms::crossorigin;
  // nsAtom, CacheDomain::Style
  // CSS display; block, inline, etc.
  static constexpr nsStaticAtom* CSSDisplay = nsGkAtoms::display;
  // nsAtom, CacheDomain::Style
  // CSS overflow; e.g. hidden.
  static constexpr nsStaticAtom* CSSOverflow = nsGkAtoms::overflow;
  // nsAtom, CacheDomain::Style
  // CSS position; e.g. fixed.
  static constexpr nsStaticAtom* CssPosition = nsGkAtoms::position;
  // nsString, CacheDomain::NameAndDescription
  static constexpr nsStaticAtom* CssAltContent = nsGkAtoms::content;
  // nsString, CacheDomain::NameAndDescription
  static constexpr nsStaticAtom* Description = nsGkAtoms::description;
  // EDescriptionValueFlag, CacheDomain::NameAndDescription
  // Returned by Accessible::Description.
  static constexpr nsStaticAtom* DescriptionValueFlag =
      nsGkAtoms::aria_description;
  // nsString, CacheDomain::Relations
  // The "name" DOM attribute.
  static constexpr nsStaticAtom* DOMName = nsGkAtoms::attributeName;
  // nsAtom, CacheDomain::DOMNodeIDAndClass
  // The "class" DOM attribute.
  static constexpr nsStaticAtom* DOMNodeClass = nsGkAtoms::_class;
  // nsAtom, CacheDomain::DOMNodeIDAndClass
  static constexpr nsStaticAtom* DOMNodeID = nsGkAtoms::id;
  // AccGroupInfo, no domain, not sent from content
  static constexpr nsStaticAtom* GroupInfo = nsGkAtoms::group;
  // nsTArray<int32_t>, no domain, not sent from content
  // As returned by HyperTextAccessibleBase::CachedHyperTextOffsets.
  static constexpr nsStaticAtom* HyperTextOffsets = nsGkAtoms::offset;
  // bool, CacheDomain::ARIA
  // Accessible has aria-actions
  static constexpr nsStaticAtom* HasActions = nsGkAtoms::hasActions;
  // bool, CacheDomain::Actions
  // Whether this image has a longdesc.
  static constexpr nsStaticAtom* HasLongdesc = nsGkAtoms::longdesc;
  // nsString, CacheDomain::NameAndDescription
  static constexpr nsStaticAtom* HTMLPlaceholder = nsGkAtoms::placeholder;
  // int32_t, CacheDomain::GroupInfo
  static constexpr nsStaticAtom* HeadingLevel = nsGkAtoms::level;
#ifdef XP_WIN
  // nsString, CacheDomain::InnerHTML
  static constexpr nsStaticAtom* InnerHTML = nsGkAtoms::html;
#endif
  // nsAtom, CacheUpdateType::Initial
  // The type of an <input> element; tel, email, etc.
  static constexpr nsStaticAtom* InputType = nsGkAtoms::textInputType;
  // bool, CacheDomain::Bounds
  // Whether the Accessible is fully clipped.
  static constexpr nsStaticAtom* IsClipped = nsGkAtoms::clip_rule;
  // nsAtom, CacheDomain::Text
  // As returned by Accessible::Language.
  static constexpr nsStaticAtom* Language = nsGkAtoms::language;
  // nsString, CacheUpdateType::Initial
  static constexpr nsStaticAtom* MimeType = nsGkAtoms::headerContentType;
  // double, CacheDomain::Value
  static constexpr nsStaticAtom* MaxValue = nsGkAtoms::max;
  // double, CacheDomain::Value
  static constexpr nsStaticAtom* MinValue = nsGkAtoms::min;
  // nsString, CacheDomain::NameAndDescription
  static constexpr nsStaticAtom* Name = nsGkAtoms::name;
  // double, CacheDomain::Value
  // The numeric value returned by Accessible::CurValue.
  static constexpr nsStaticAtom* NumericValue = nsGkAtoms::value;
  // float, CacheDomain::Style
  static constexpr nsStaticAtom* Opacity = nsGkAtoms::opacity;
  // nsTArray<int32_t, 4>, CacheDomain::Bounds
  // The screen bounds relative  to the parent Accessible
  // as returned by LocalAccessible::ParentRelativeBounds.
  static constexpr nsStaticAtom* ParentRelativeBounds =
      nsGkAtoms::relativeBounds;
  // nsAtom, CacheUpdateType::Initial
  // The type of a popup (used for HTML popover).
  static constexpr nsStaticAtom* PopupType = nsGkAtoms::ispopup;
  // bool, CacheDomain::Relations
  // Whether popovertarget/commandfor should expose a DETAILS relation (true)
  // or DESCRIBED_BY relation (false). Only meaningful when popovertarget or
  // commandfor is cached.
  static constexpr nsStaticAtom* PopoverInvokerIsDetails = nsGkAtoms::details;
  // nsAtom, CacheDomain::Actions
  static constexpr nsStaticAtom* PrimaryAction = nsGkAtoms::action;
  // float, no domain
  // Document resolution.
  static constexpr nsStaticAtom* Resolution = nsGkAtoms::resolution;
  // int32_t, CacheDomain::Table
  // The rowspan of an HTML table cell.
  static constexpr nsStaticAtom* RowSpan = nsGkAtoms::rowspan;
  // nsTArray<int32_t, 2>, CacheDomain::ScrollPosition
  static constexpr nsStaticAtom* ScrollPosition = nsGkAtoms::scrollPosition;
  // nsTArray<TextOffsetAttribute>,
  // CacheDomain::TextOffsetAttributes | CacheDomain::Text
  // Text offset attributes such as spelling errors.
  static constexpr nsStaticAtom* TextOffsetAttributes = nsGkAtoms::spelling;
  // nsString, CacheDomain::Value
  // The src URL of images.
  static constexpr nsStaticAtom* SrcURL = nsGkAtoms::src;
  // uint64_t, CacheDomain::State
  // As returned by Accessible::State.
  static constexpr nsStaticAtom* State = nsGkAtoms::state;
  // double, CacheDomain::Value
  // The value step returned by Accessible::Step.
  static constexpr nsStaticAtom* Step = nsGkAtoms::step;
  // nsAtom, CacheUpdateType::Initial
  // The tag name of the element.
  static constexpr nsStaticAtom* TagName = nsGkAtoms::tag;
  // bool, CacheDomain::Table
  // Whether this is a layout table.
  static constexpr nsStaticAtom* TableLayoutGuess = nsGkAtoms::layout_guess;
  // nsString, CacheDomain::Text
  // The text of TextLeafAccessibles.
  static constexpr nsStaticAtom* Text = nsGkAtoms::text;
  // AccAttributes, CacheDomain::Text
  // Text attributes; font, etc.
  static constexpr nsStaticAtom* TextAttributes = nsGkAtoms::style;
  // nsTArray<int32_t, 4 * n>, CacheDomain::TextBounds
  // The bounds of each character in a text leaf.
  static constexpr nsStaticAtom* TextBounds = nsGkAtoms::characterData;
  // nsTArray<int32_t>, CacheDomain::TextBounds
  // The text offsets where new lines start.
  static constexpr nsStaticAtom* TextLineStarts = nsGkAtoms::line;
  // nsString, CacheDomain::Value
  // The textual value returned by Accessible::Value (as opposed to
  // the numeric value returned by Accessible::CurValue).
  static constexpr nsStaticAtom* TextValue = nsGkAtoms::aria_valuetext;
  // nsString, CacheDomain::NameAndDescription
  static constexpr nsStaticAtom* Tooltip = nsGkAtoms::tooltip;
  // gfx::Matrix4x4, CacheDomain::TransformMatrix
  static constexpr nsStaticAtom* TransformMatrix = nsGkAtoms::transform;
  // int32_t, CacheDomain::Value
  static constexpr nsStaticAtom* ValueRegion = nsGkAtoms::valuetype;
  // nsTArray<uint64_t>, CacheDomain::Viewport
  // The list of Accessibles in the viewport used for hit testing and on-screen
  // determination.
  static constexpr nsStaticAtom* Viewport = nsGkAtoms::viewport;
  // Computed writing mode
  static constexpr nsStaticAtom* WritingMode = nsGkAtoms::writing_mode;
};

// Return true if the given cache domains are already globally active. This
// doesn't account for documents which use a specific set of cache domains that
// is different to the global set. Core, cross-platform code should generally
// use DocAccessibleParent::CacheDomainsAreActive instead.
bool DomainsAreActive(uint64_t aRequiredCacheDomains);

// Get the set of cache domains required by the given cache domains. The
// returned value is always equal to or a superset of the input. Used by
// DocAccessibleParent::RequestDomainsIfInactive when escalating.
uint64_t GetCacheDomainSuperset(uint64_t aCacheDomains);

#define ASSERT_DOMAINS_ACTIVE(aCacheDomains, aAcc)                           \
  MOZ_ASSERT(                                                                \
      (GetAccService() && !GetAccService()->ShouldAllowNewCacheDomains()) || \
          (aAcc)->Document()->DomainsAreActive(aCacheDomains),               \
      "Required domain(s) are not currently active.")

}  // namespace a11y
}  // namespace mozilla

#endif
