DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Implementation

Mercurial (4b332005f925)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300
/* -*- 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 <ostream>
#include <type_traits>

#include "nsString.h"
#include "nsCSSPropertyID.h"
#include "nsStyleStructFwd.h"
#include "nsCSSKeywords.h"
#include "mozilla/UseCounter.h"
#include "mozilla/CSSEnabledState.h"
#include "mozilla/CSSPropFlags.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 uint16_t value
  // or a value of an enumeration type that can fit within an uint16_t.
  static constexpr uint16_t SENTINEL_VALUE = uint16_t(-1);

  constexpr nsCSSKTableEntry(nsCSSKeyword aKeyword, uint16_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<uint16_t>(aValue)) {
    static_assert(mozilla::EnumTypeFitsWithin<T, uint16_t>::value,
                  "aValue must be an enum that fits within mValue");
    MOZ_ASSERT(static_cast<uint16_t>(aValue) != SENTINEL_VALUE);
  }

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

  nsCSSKeyword mKeyword;
  uint16_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);

  // The relevant invariants are asserted in Document.cpp
  static mozilla::UseCounter UseCounterFor(nsCSSPropertyID aProperty) {
    MOZ_ASSERT(0 <= aProperty && aProperty < eCSSProperty_COUNT_with_aliases,
               "out of range");
    return mozilla::UseCounter(size_t(mozilla::eUseCounter_FirstCSSProperty) +
                               size_t(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, uint16_t>::value,
        "aValue must be an enum that fits within KTableEntry::mValue");
    return ValueToKeywordEnum(static_cast<uint16_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, uint16_t>::value,
        "aValue must be an enum that fits within KTableEntry::mValue");
    return ValueToKeyword(static_cast<uint16_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) {
    MOZ_ASSERT(!IsShorthand(aProperty));
    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];
  }

 public:
  static bool IsEnabled(nsCSSPropertyID aProperty, EnabledState aEnabled) {
    if (IsEnabled(aProperty)) {
      return true;
    }
    if (aEnabled == EnabledState::IgnoreEnabledState) {
      return true;
    }
    if ((aEnabled & EnabledState::InUASheets) &&
        PropHasFlags(aProperty, Flags::EnabledInUASheets)) {
      return true;
    }
    if ((aEnabled & EnabledState::InChrome) &&
        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 kCursorKTable[];
  static const KTableEntry kFontSmoothingKTable[];
  static const KTableEntry kTextAlignKTable[];
  static const KTableEntry kTextDecorationStyleKTable[];
};

// MOZ_DBG support for nsCSSPropertyID

inline std::ostream& operator<<(std::ostream& aOut, nsCSSPropertyID aProperty) {
  return aOut << nsCSSProps::GetStringValue(aProperty);
}

#endif /* nsCSSProps_h___ */