layout/style/nsCSSProps.h
author Cosmin Sabou <csabou@mozilla.com>
Thu, 02 Aug 2018 19:59:53 +0300
changeset 484986 f7f4ba3486b5e44b6ccdc3b150f5aa0aab76ffb7
parent 484467 cbaa8e0834cad35084d2675d9400b3e28a47ab7c
child 486797 0214ed222b79d41b0b53bccb383115c4de74e045
permissions -rw-r--r--
Backed out changeset 5950c9d63c3b (bug 1090497) for build bustages on several files. CLOSED TREE

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */

/*
 * methods for dealing with CSS properties and tables of the keyword
 * values they accept
 */

#ifndef nsCSSProps_h___
#define nsCSSProps_h___

#include <limits>
#include <type_traits>
#include "nsString.h"
#include "nsCSSPropertyID.h"
#include "nsStyleStructFwd.h"
#include "nsCSSKeywords.h"
#include "mozilla/CSSEnabledState.h"
#include "mozilla/CSSPropFlags.h"
#include "mozilla/UseCounter.h"
#include "mozilla/EnumTypeTraits.h"
#include "mozilla/Preferences.h"
#include "nsXULAppAPI.h"

// Length of the "--" prefix on custom names (such as custom property names,
// and, in the future, custom media query names).
#define CSS_CUSTOM_NAME_PREFIX_LENGTH 2

namespace mozilla {
class ComputedStyle;
}

extern "C" {
  nsCSSPropertyID Servo_ResolveLogicalProperty(nsCSSPropertyID,
                                               const mozilla::ComputedStyle*);
  nsCSSPropertyID Servo_Property_LookupEnabledForAllContent(const nsACString*);
  const uint8_t* Servo_Property_GetName(nsCSSPropertyID, uint32_t* aLength);
}

struct nsCSSKTableEntry
{
  // nsCSSKTableEntry objects can be initialized either with an int16_t value
  // or a value of an enumeration type that can fit within an int16_t.

  constexpr nsCSSKTableEntry(nsCSSKeyword aKeyword, int16_t aValue)
    : mKeyword(aKeyword)
    , mValue(aValue)
  {
  }

  template<typename T,
           typename = typename std::enable_if<std::is_enum<T>::value>::type>
  constexpr nsCSSKTableEntry(nsCSSKeyword aKeyword, T aValue)
    : mKeyword(aKeyword)
    , mValue(static_cast<int16_t>(aValue))
  {
    static_assert(mozilla::EnumTypeFitsWithin<T, int16_t>::value,
                  "aValue must be an enum that fits within mValue");
  }

  bool IsSentinel() const
  {
    return mKeyword == eCSSKeyword_UNKNOWN && mValue == -1;
  }

  nsCSSKeyword mKeyword;
  int16_t mValue;
};

class nsCSSProps {
public:
  typedef mozilla::CSSEnabledState EnabledState;
  typedef mozilla::CSSPropFlags Flags;
  typedef nsCSSKTableEntry KTableEntry;

  static void AddRefTable(void);
  static void ReleaseTable(void);

  // Looks up the property with name aProperty and returns its corresponding
  // nsCSSPropertyID value.  If aProperty is the name of a custom property,
  // then eCSSPropertyExtra_variable will be returned.
  //
  // This only returns properties enabled for all content, and resolves aliases
  // to return the aliased property.
  static nsCSSPropertyID LookupProperty(const nsACString& aProperty)
  {
    return Servo_Property_LookupEnabledForAllContent(&aProperty);
  }

  static nsCSSPropertyID LookupProperty(const nsAString& aProperty)
  {
    NS_ConvertUTF16toUTF8 utf8(aProperty);
    return LookupProperty(utf8);
  }

  // As above, but looked up using a property's IDL name.
  // eCSSPropertyExtra_variable won't be returned from these methods.
  static nsCSSPropertyID LookupPropertyByIDLName(
      const nsAString& aPropertyIDLName,
      EnabledState aEnabled);
  static nsCSSPropertyID LookupPropertyByIDLName(
      const nsACString& aPropertyIDLName,
      EnabledState aEnabled);

  // Returns whether aProperty is a custom property name, i.e. begins with
  // "--".  This assumes that the CSS Variables pref has been enabled.
  static bool IsCustomPropertyName(const nsAString& aProperty);

  static bool IsShorthand(nsCSSPropertyID aProperty)
  {
    MOZ_ASSERT(0 <= aProperty && aProperty < eCSSProperty_COUNT,
               "out of range");
    return (aProperty >= eCSSProperty_COUNT_no_shorthands);
  }

  // Same but for @font-face descriptors
  static nsCSSFontDesc LookupFontDesc(const nsAString& aProperty);

  // Given a property enum, get the string value
  //
  // This string is static.
  static const nsDependentCSubstring GetStringValue(nsCSSPropertyID aProperty)
  {
    uint32_t len;
    const uint8_t* chars = Servo_Property_GetName(aProperty, &len);
    return nsDependentCSubstring(reinterpret_cast<const char*>(chars), len);
  }

  static const nsCString& GetStringValue(nsCSSFontDesc aFontDesc);
  static const nsCString& GetStringValue(nsCSSCounterDesc aCounterDesc);

  // Returns the index of |aKeyword| in |aTable|, if it exists there;
  // otherwise, returns -1.
  // NOTE: Generally, clients should call FindKeyword() instead of this method.
  static int32_t FindIndexOfKeyword(nsCSSKeyword aKeyword,
                                    const KTableEntry aTable[]);

  // Find |aKeyword| in |aTable|, if found set |aValue| to its corresponding value.
  // If not found, return false and do not set |aValue|.
  static bool FindKeyword(nsCSSKeyword aKeyword, const KTableEntry aTable[],
                          int32_t& aValue);
  // Return the first keyword in |aTable| that has the corresponding value |aValue|.
  // Return |eCSSKeyword_UNKNOWN| if not found.
  static nsCSSKeyword ValueToKeywordEnum(int32_t aValue,
                                         const KTableEntry aTable[]);
  template<typename T,
           typename = typename std::enable_if<std::is_enum<T>::value>::type>
  static nsCSSKeyword ValueToKeywordEnum(T aValue,
                                         const KTableEntry aTable[])
  {
    static_assert(mozilla::EnumTypeFitsWithin<T, int16_t>::value,
                  "aValue must be an enum that fits within KTableEntry::mValue");
    return ValueToKeywordEnum(static_cast<int16_t>(aValue), aTable);
  }
  // Ditto but as a string, return "" when not found.
  static const nsCString& ValueToKeyword(int32_t aValue,
                                         const KTableEntry aTable[]);
  template<typename T,
           typename = typename std::enable_if<std::is_enum<T>::value>::type>
  static const nsCString& ValueToKeyword(T aValue, const KTableEntry aTable[])
  {
    static_assert(mozilla::EnumTypeFitsWithin<T, int16_t>::value,
                  "aValue must be an enum that fits within KTableEntry::mValue");
    return ValueToKeyword(static_cast<int16_t>(aValue), aTable);
  }

private:
  static const Flags kFlagsTable[eCSSProperty_COUNT];

public:
  static bool PropHasFlags(nsCSSPropertyID aProperty, Flags aFlags)
  {
    MOZ_ASSERT(0 <= aProperty && aProperty < eCSSProperty_COUNT,
               "out of range");
    return (nsCSSProps::kFlagsTable[aProperty] & aFlags) == aFlags;
  }

  static nsCSSPropertyID Physicalize(nsCSSPropertyID aProperty,
                                     const mozilla::ComputedStyle& aStyle)
  {
    if (PropHasFlags(aProperty, Flags::IsLogical)) {
      return Servo_ResolveLogicalProperty(aProperty, &aStyle);
    }
    return aProperty;
  }

private:
  // A table for shorthand properties.  The appropriate index is the
  // property ID minus eCSSProperty_COUNT_no_shorthands.
  static const nsCSSPropertyID* const
    kSubpropertyTable[eCSSProperty_COUNT - eCSSProperty_COUNT_no_shorthands];

public:
  static const nsCSSPropertyID* SubpropertyEntryFor(nsCSSPropertyID aProperty)
  {
    MOZ_ASSERT(eCSSProperty_COUNT_no_shorthands <= aProperty &&
               aProperty < eCSSProperty_COUNT,
               "out of range");
    return nsCSSProps::kSubpropertyTable[aProperty -
                                         eCSSProperty_COUNT_no_shorthands];
  }

private:
  static bool gPropertyEnabled[eCSSProperty_COUNT_with_aliases];

private:
  // Defined in the generated nsCSSPropsGenerated.inc.
  static const char* const kIDLNameTable[eCSSProperty_COUNT];

public:
  /**
   * Returns the IDL name of the specified property, which must be a
   * longhand, logical or shorthand property.  The IDL name is the property
   * name with any hyphen-lowercase character pairs replaced by an
   * uppercase character:
   * https://drafts.csswg.org/cssom/#css-property-to-idl-attribute
   *
   * As a special case, the string "cssFloat" is returned for the float
   * property.  nullptr is returned for internal properties.
   */
  static const char* PropertyIDLName(nsCSSPropertyID aProperty)
  {
    MOZ_ASSERT(0 <= aProperty && aProperty < eCSSProperty_COUNT,
               "out of range");
    return kIDLNameTable[aProperty];
  }

private:
  static const int32_t kIDLNameSortPositionTable[eCSSProperty_COUNT];

public:
  /**
   * Returns the position of the specified property in a list of all
   * properties sorted by their IDL name.
   */
  static int32_t PropertyIDLNameSortPosition(nsCSSPropertyID aProperty)
  {
    MOZ_ASSERT(0 <= aProperty && aProperty < eCSSProperty_COUNT,
               "out of range");
    return kIDLNameSortPositionTable[aProperty];
  }

  static bool IsEnabled(nsCSSPropertyID aProperty) {
    MOZ_ASSERT(0 <= aProperty && aProperty < eCSSProperty_COUNT_with_aliases,
               "out of range");
    // In the child process, assert that we're not trying to parse stylesheets
    // before we've gotten all our prefs.
    MOZ_ASSERT_IF(!XRE_IsParentProcess(),
                  mozilla::Preferences::ArePrefsInitedInContentProcess());
    return gPropertyEnabled[aProperty];
  }

  // A table for the use counter associated with each CSS property.  If a
  // property does not have a use counter defined in UseCounters.conf, then
  // its associated entry is |eUseCounter_UNKNOWN|.
  static const mozilla::UseCounter gPropertyUseCounter[eCSSProperty_COUNT_no_shorthands];

public:

  static mozilla::UseCounter UseCounterFor(nsCSSPropertyID aProperty) {
    MOZ_ASSERT(0 <= aProperty && aProperty < eCSSProperty_COUNT_no_shorthands,
               "out of range");
    return gPropertyUseCounter[aProperty];
  }

  static bool IsEnabled(nsCSSPropertyID aProperty, EnabledState aEnabled)
  {
    if (IsEnabled(aProperty)) {
      return true;
    }
    if (aEnabled == EnabledState::eIgnoreEnabledState) {
      return true;
    }
    if ((aEnabled & EnabledState::eInUASheets) &&
        PropHasFlags(aProperty, Flags::EnabledInUASheets))
    {
      return true;
    }
    if ((aEnabled & EnabledState::eInChrome) &&
        PropHasFlags(aProperty, Flags::EnabledInChrome))
    {
      return true;
    }
    return false;
  }

public:
  struct PropertyPref
  {
    nsCSSPropertyID mPropID;
    const char* mPref;
  };
  static const PropertyPref kPropertyPrefTable[];

// Storing the enabledstate_ value in an nsCSSPropertyID variable is a small hack
// to avoid needing a separate variable declaration for its real type
// (CSSEnabledState), which would then require using a block and
// therefore a pair of macros by consumers for the start and end of the loop.
#define CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(it_, prop_, enabledstate_)   \
  for (const nsCSSPropertyID *it_ = nsCSSProps::SubpropertyEntryFor(prop_), \
                            es_ = (nsCSSPropertyID)((enabledstate_) |       \
                                                  CSSEnabledState(0));    \
       *it_ != eCSSProperty_UNKNOWN; ++it_)                               \
    if (nsCSSProps::IsEnabled(*it_, (mozilla::CSSEnabledState) es_))

  // Keyword/Enum value tables
  static const KTableEntry kTransformStyleKTable[];
  static const KTableEntry kImageLayerRepeatKTable[];
  // Not const because we modify its entries when the pref
  // "layout.css.background-clip.text" changes:
  static const KTableEntry kBorderImageRepeatKTable[];
  static const KTableEntry kBorderStyleKTable[];
  static const KTableEntry kClipPathGeometryBoxKTable[];
  static const KTableEntry kShapeRadiusKTable[];
  static const KTableEntry kFilterFunctionKTable[];
  static const KTableEntry kShapeOutsideShapeBoxKTable[];
  static const KTableEntry kBoxShadowTypeKTable[];
  static const KTableEntry kCursorKTable[];
  // Not const because we modify its entries when various
  // "layout.css.*.enabled" prefs changes:
  static KTableEntry kDisplayKTable[];
  // -- tables for parsing the {align,justify}-{content,items,self} properties --
  static const KTableEntry kAlignAllKeywords[];
  static const KTableEntry kAlignOverflowPosition[]; // <overflow-position>
  static const KTableEntry kAlignSelfPosition[];     // <self-position>
  static const KTableEntry kAlignLegacy[];           // 'legacy'
  static const KTableEntry kAlignLegacyPosition[];   // 'left/right/center'
  static const KTableEntry kAlignAutoNormalStretchBaseline[]; // 'auto/normal/stretch/baseline'
  static const KTableEntry kAlignNormalStretchBaseline[]; // 'normal/stretch/baseline'
  static const KTableEntry kAlignNormalBaseline[]; // 'normal/baseline'
  static const KTableEntry kAlignContentDistribution[]; // <content-distribution>
  static const KTableEntry kAlignContentPosition[]; // <content-position>
  // -- tables for auto-completion of the {align,justify}-{content,items,self} properties --
  static const KTableEntry kAutoCompletionAlignJustifySelf[];
  static const KTableEntry kAutoCompletionAlignItems[];
  static const KTableEntry kAutoCompletionAlignJustifyContent[];
  // ------------------------------------------------------------------
  static const KTableEntry kFontSmoothingKTable[];
  static const KTableEntry kFontVariantAlternatesFuncsKTable[];
  static const KTableEntry kGridAutoFlowKTable[];
  static const KTableEntry kGridTrackBreadthKTable[];
  static const KTableEntry kLineHeightKTable[];
  static const KTableEntry kContainKTable[];
  static const KTableEntry kOutlineStyleKTable[];
  static const KTableEntry kOverflowKTable[];
  static const KTableEntry kOverflowSubKTable[];
  static const KTableEntry kOverflowClipBoxKTable[];
  static const KTableEntry kRadialGradientSizeKTable[];
  static const KTableEntry kOverscrollBehaviorKTable[];
  static const KTableEntry kScrollSnapTypeKTable[];
  // Not const because we modify its entries when the pref
  // "layout.css.text-align-unsafe-value.enabled" changes:
  static KTableEntry kTextAlignKTable[];
  static const KTableEntry kTextDecorationLineKTable[];
  static const KTableEntry kTextDecorationStyleKTable[];
  static const KTableEntry kTextEmphasisStyleShapeKTable[];
  static const KTableEntry kTextOverflowKTable[];
  static const KTableEntry kTouchActionKTable[];
  static const KTableEntry kTransitionTimingFunctionKTable[];
  static const KTableEntry kVerticalAlignKTable[];
  static const KTableEntry kWidthKTable[]; // also min-width, max-width
  static const KTableEntry kFlexBasisKTable[];
};

#endif /* nsCSSProps_h___ */