tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

nsAttrValueInlines.h (8813B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifndef nsAttrValueInlines_h__
      8 #define nsAttrValueInlines_h__
      9 
     10 #include <stdint.h>
     11 
     12 #include "mozilla/Atomics.h"
     13 #include "mozilla/ServoUtils.h"
     14 #include "mozilla/dom/DOMString.h"
     15 #include "nsAttrValue.h"
     16 
     17 namespace mozilla {
     18 class ShadowParts;
     19 }
     20 
     21 struct MiscContainer final {
     22  using ValueType = nsAttrValue::ValueType;
     23 
     24  ValueType mType;
     25  // mStringBits points to either nsAtom* or mozilla::StringBuffer* and is used
     26  // when mType isn't eCSSDeclaration. Note eStringBase and eAtomBase is used
     27  // also to handle the type of mStringBits.
     28  //
     29  // Note that we use an atomic here so that we can use Compare-And-Swap
     30  // to cache the serialization during the parallel servo traversal. This case
     31  // (which happens when the main thread is blocked) is the only case where
     32  // mStringBits is mutated off-main-thread. The Atomic needs to be
     33  // ReleaseAcquire so that the pointer to the serialization does not become
     34  // observable to other threads before the initialization of the pointed-to
     35  // memory is also observable.
     36  mozilla::Atomic<uintptr_t, mozilla::ReleaseAcquire> mStringBits;
     37  union {
     38    struct {
     39      union {
     40        int32_t mInteger;
     41        nscolor mColor;
     42        uint32_t mEnumValue;
     43        mozilla::DeclarationBlock* mCSSDeclaration;
     44        nsIURI* mURL;
     45        const mozilla::AttrAtomArray* mAtomArray;
     46        const mozilla::ShadowParts* mShadowParts;
     47        const mozilla::SVGAnimatedIntegerPair* mSVGAnimatedIntegerPair;
     48        const mozilla::SVGAnimatedLength* mSVGLength;
     49        const mozilla::SVGAnimatedNumberPair* mSVGAnimatedNumberPair;
     50        const mozilla::SVGAnimatedOrient* mSVGAnimatedOrient;
     51        const mozilla::SVGAnimatedPreserveAspectRatio*
     52            mSVGAnimatedPreserveAspectRatio;
     53        const mozilla::SVGAnimatedViewBox* mSVGAnimatedViewBox;
     54        const mozilla::SVGLengthList* mSVGLengthList;
     55        const mozilla::SVGNumberList* mSVGNumberList;
     56        const mozilla::SVGPathData* mSVGPathData;
     57        const mozilla::SVGPointList* mSVGPointList;
     58        const mozilla::SVGStringList* mSVGStringList;
     59        const mozilla::SVGTransformList* mSVGTransformList;
     60      };
     61      uint32_t mRefCount : 31;
     62      uint32_t mCached : 1;
     63    } mValue;
     64    double mDoubleValue;
     65  };
     66 
     67  MiscContainer() : mType(nsAttrValue::eColor), mStringBits(0) {
     68    MOZ_COUNT_CTOR(MiscContainer);
     69    mValue.mColor = 0;
     70    mValue.mRefCount = 0;
     71    mValue.mCached = 0;
     72  }
     73 
     74 protected:
     75  // Only nsAttrValue should be able to delete us.
     76  friend class nsAttrValue;
     77 
     78  ~MiscContainer() {
     79    if (IsRefCounted()) {
     80      MOZ_ASSERT(mValue.mRefCount == 0);
     81      MOZ_ASSERT(!mValue.mCached);
     82    }
     83    MOZ_COUNT_DTOR(MiscContainer);
     84  }
     85 
     86 public:
     87  bool GetString(nsAString& aString) const;
     88 
     89  void* GetStringOrAtomPtr(bool& aIsString) const {
     90    uintptr_t bits = mStringBits;
     91    aIsString =
     92        nsAttrValue::ValueBaseType(mStringBits & NS_ATTRVALUE_BASETYPE_MASK) ==
     93        nsAttrValue::eStringBase;
     94    return reinterpret_cast<void*>(bits & NS_ATTRVALUE_POINTERVALUE_MASK);
     95  }
     96 
     97  nsAtom* GetStoredAtom() const {
     98    bool isString = false;
     99    void* ptr = GetStringOrAtomPtr(isString);
    100    return isString ? nullptr : static_cast<nsAtom*>(ptr);
    101  }
    102 
    103  mozilla::StringBuffer* GetStoredStringBuffer() const {
    104    bool isString = false;
    105    void* ptr = GetStringOrAtomPtr(isString);
    106    return isString ? static_cast<mozilla::StringBuffer*>(ptr) : nullptr;
    107  }
    108 
    109  void SetStringBitsMainThread(uintptr_t aBits) {
    110    // mStringBits is atomic, but the callers of this function are
    111    // single-threaded so they don't have to worry about it.
    112    MOZ_ASSERT(!mozilla::IsInServoTraversal());
    113    MOZ_ASSERT(NS_IsMainThread());
    114    mStringBits = aBits;
    115  }
    116 
    117  inline bool IsRefCounted() const {
    118    // Nothing stops us from refcounting (and sharing) other types of
    119    // MiscContainer (except eDoubleValue types) but there's no compelling
    120    // reason to.
    121    return mType == nsAttrValue::eAtomArray ||
    122           mType == nsAttrValue::eCSSDeclaration ||
    123           mType == nsAttrValue::eShadowParts;
    124  }
    125 
    126  inline int32_t AddRef() {
    127    MOZ_ASSERT(IsRefCounted());
    128    return ++mValue.mRefCount;
    129  }
    130 
    131  inline int32_t Release() {
    132    MOZ_ASSERT(IsRefCounted());
    133    return --mValue.mRefCount;
    134  }
    135 
    136  void Cache();
    137  void Evict();
    138 };
    139 
    140 /**
    141 * Implementation of inline methods
    142 */
    143 
    144 inline int32_t nsAttrValue::GetIntegerValue() const {
    145  MOZ_ASSERT(Type() == eInteger, "wrong type");
    146  return (BaseType() == eIntegerBase) ? GetIntInternal()
    147                                      : GetMiscContainer()->mValue.mInteger;
    148 }
    149 
    150 inline int16_t nsAttrValue::GetEnumValue() const {
    151  MOZ_ASSERT(Type() == eEnum, "wrong type");
    152  // We don't need to worry about sign extension here since we're
    153  // returning an int16_t which will cut away the top bits.
    154  return static_cast<int16_t>(((BaseType() == eIntegerBase)
    155                                   ? static_cast<uint32_t>(GetIntInternal())
    156                                   : GetMiscContainer()->mValue.mEnumValue) >>
    157                              NS_ATTRVALUE_ENUMTABLEINDEX_BITS);
    158 }
    159 
    160 inline double nsAttrValue::GetPercentValue() const {
    161  MOZ_ASSERT(Type() == ePercent, "wrong type");
    162  if (BaseType() == eIntegerBase) {
    163    return GetIntInternal() / 100.0f;
    164  }
    165  return GetMiscContainer()->mDoubleValue / 100.0f;
    166 }
    167 
    168 inline const mozilla::AttrAtomArray* nsAttrValue::GetAtomArrayValue() const {
    169  MOZ_ASSERT(Type() == eAtomArray, "wrong type");
    170  return GetMiscContainer()->mValue.mAtomArray;
    171 }
    172 
    173 inline mozilla::DeclarationBlock* nsAttrValue::GetCSSDeclarationValue() const {
    174  MOZ_ASSERT(Type() == eCSSDeclaration, "wrong type");
    175  return GetMiscContainer()->mValue.mCSSDeclaration;
    176 }
    177 
    178 inline nsIURI* nsAttrValue::GetURLValue() const {
    179  MOZ_ASSERT(Type() == eURL, "wrong type");
    180  return GetMiscContainer()->mValue.mURL;
    181 }
    182 
    183 inline double nsAttrValue::GetDoubleValue() const {
    184  MOZ_ASSERT(Type() == eDoubleValue, "wrong type");
    185  return GetMiscContainer()->mDoubleValue;
    186 }
    187 
    188 inline bool nsAttrValue::IsSVGType(ValueType aType) const {
    189  return aType >= eSVGTypesBegin && aType <= eSVGTypesEnd;
    190 }
    191 
    192 inline bool nsAttrValue::StoresOwnData() const {
    193  if (BaseType() != eOtherBase) {
    194    return true;
    195  }
    196  ValueType t = Type();
    197  return t != eCSSDeclaration && !IsSVGType(t);
    198 }
    199 
    200 inline void nsAttrValue::SetPtrValueAndType(void* aValue, ValueBaseType aType) {
    201  NS_ASSERTION(!(NS_PTR_TO_INT32(aValue) & ~NS_ATTRVALUE_POINTERVALUE_MASK),
    202               "pointer not properly aligned, this will crash");
    203  mBits = reinterpret_cast<intptr_t>(aValue) | aType;
    204 }
    205 
    206 inline void nsAttrValue::ResetIfSet() {
    207  if (mBits) {
    208    Reset();
    209  }
    210 }
    211 
    212 inline MiscContainer* nsAttrValue::GetMiscContainer() const {
    213  NS_ASSERTION(BaseType() == eOtherBase, "wrong type");
    214  return static_cast<MiscContainer*>(GetPtr());
    215 }
    216 
    217 inline int32_t nsAttrValue::GetIntInternal() const {
    218  NS_ASSERTION(BaseType() == eIntegerBase, "getting integer from non-integer");
    219  // Make sure we get a signed value.
    220  // Lets hope the optimizer optimizes this into a shift. Unfortunatly signed
    221  // bitshift right is implementaion dependant.
    222  return static_cast<int32_t>(mBits & ~NS_ATTRVALUE_INTEGERTYPE_MASK) /
    223         NS_ATTRVALUE_INTEGERTYPE_MULTIPLIER;
    224 }
    225 
    226 inline nsAttrValue::ValueType nsAttrValue::Type() const {
    227  switch (BaseType()) {
    228    case eIntegerBase: {
    229      return static_cast<ValueType>(mBits & NS_ATTRVALUE_INTEGERTYPE_MASK);
    230    }
    231    case eOtherBase: {
    232      return GetMiscContainer()->mType;
    233    }
    234    default: {
    235      return static_cast<ValueType>(static_cast<uint16_t>(BaseType()));
    236    }
    237  }
    238 }
    239 
    240 inline nsAtom* nsAttrValue::GetAtomValue() const {
    241  MOZ_ASSERT(Type() == eAtom, "wrong type");
    242  return reinterpret_cast<nsAtom*>(GetPtr());
    243 }
    244 
    245 inline void nsAttrValue::ToString(mozilla::dom::DOMString& aResult) const {
    246  switch (Type()) {
    247    case eString: {
    248      if (auto* str = static_cast<mozilla::StringBuffer*>(GetPtr())) {
    249        aResult.SetKnownLiveStringBuffer(
    250            str, str->StorageSize() / sizeof(char16_t) - 1);
    251      }
    252      // else aResult is already empty
    253      return;
    254    }
    255    case eAtom: {
    256      nsAtom* atom = static_cast<nsAtom*>(GetPtr());
    257      aResult.SetKnownLiveAtom(atom, mozilla::dom::DOMString::eNullNotExpected);
    258      break;
    259    }
    260    default: {
    261      ToString(aResult.AsAString());
    262    }
    263  }
    264 }
    265 
    266 inline const mozilla::ShadowParts& nsAttrValue::GetShadowPartsValue() const {
    267  MOZ_ASSERT(Type() == eShadowParts);
    268  return *GetMiscContainer()->mValue.mShadowParts;
    269 }
    270 
    271 #endif