tor-browser

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

DeclarationBlock.h (8408B)


      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 /*
      8 * representation of a declaration block in a CSS stylesheet, or of
      9 * a style attribute
     10 */
     11 
     12 #ifndef mozilla_DeclarationBlock_h
     13 #define mozilla_DeclarationBlock_h
     14 
     15 #include "NonCustomCSSPropertyId.h"
     16 #include "mozilla/Atomics.h"
     17 #include "mozilla/ServoBindings.h"
     18 #include "nsString.h"
     19 
     20 namespace mozilla {
     21 
     22 class AttributeStyles;
     23 struct CSSPropertyId;
     24 
     25 namespace css {
     26 class Declaration;
     27 class Rule;
     28 }  // namespace css
     29 
     30 class DeclarationBlock final {
     31  DeclarationBlock(const DeclarationBlock& aCopy)
     32      : mRaw(Servo_DeclarationBlock_Clone(aCopy.mRaw).Consume()),
     33        mImmutable(false),
     34        mIsDirty(false) {
     35    mContainer.mRaw = 0;
     36  }
     37 
     38 public:
     39  explicit DeclarationBlock(
     40      already_AddRefed<const StyleLockedDeclarationBlock> aRaw)
     41      : mRaw(aRaw), mImmutable(false), mIsDirty(false) {
     42    mContainer.mRaw = 0;
     43  }
     44 
     45  DeclarationBlock()
     46      : DeclarationBlock(Servo_DeclarationBlock_CreateEmpty().Consume()) {}
     47 
     48  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DeclarationBlock)
     49 
     50  already_AddRefed<DeclarationBlock> Clone() const {
     51    return do_AddRef(new DeclarationBlock(*this));
     52  }
     53 
     54  /**
     55   * Return whether |this| may be modified.
     56   */
     57  bool IsMutable() const { return !mImmutable; }
     58 
     59  /**
     60   * Crash in debug builds if |this| cannot be modified.
     61   */
     62  void AssertMutable() const {
     63    MOZ_ASSERT(IsMutable(), "someone forgot to call EnsureMutable");
     64    MOZ_ASSERT(!OwnerIsReadOnly(), "User Agent sheets shouldn't be modified");
     65  }
     66 
     67  /**
     68   * Mark this declaration as unmodifiable.
     69   */
     70  void SetImmutable() { mImmutable = true; }
     71 
     72  /**
     73   * Return whether |this| has been restyled after modified.
     74   */
     75  bool IsDirty() const { return mIsDirty; }
     76 
     77  /**
     78   * Mark this declaration as dirty.
     79   */
     80  void SetDirty() { mIsDirty = true; }
     81 
     82  /**
     83   * Mark this declaration as not dirty.
     84   */
     85  void UnsetDirty() { mIsDirty = false; }
     86 
     87  /**
     88   * Copy |this|, if necessary to ensure that it can be modified.
     89   */
     90  already_AddRefed<DeclarationBlock> EnsureMutable() {
     91    MOZ_ASSERT(!OwnerIsReadOnly());
     92 
     93    if (!IsDirty()) {
     94      // In stylo, the old DeclarationBlock is stored in element's rule node
     95      // tree directly, to avoid new values replacing the DeclarationBlock in
     96      // the tree directly, we need to copy the old one here if we haven't yet
     97      // copied. As a result the new value does not replace rule node tree until
     98      // traversal happens.
     99      //
    100      // FIXME(emilio, bug 1606413): This is a hack for ::first-line and
    101      // transitions starting due to CSSOM changes when other transitions are
    102      // already running. Try to simplify this setup, so that rule tree updates
    103      // find the mutated declaration block properly rather than having to
    104      // insert the cloned declaration in the tree.
    105      return Clone();
    106    }
    107 
    108    if (!IsMutable()) {
    109      return Clone();
    110    }
    111 
    112    return do_AddRef(this);
    113  }
    114 
    115  void SetOwningRule(css::Rule* aRule) {
    116    MOZ_ASSERT(!mContainer.mOwningRule || !aRule,
    117               "should never overwrite one rule with another");
    118    mContainer.mOwningRule = aRule;
    119  }
    120 
    121  css::Rule* GetOwningRule() const {
    122    if (mContainer.mRaw & 0x1) {
    123      return nullptr;
    124    }
    125    return mContainer.mOwningRule;
    126  }
    127 
    128  void SetAttributeStyles(AttributeStyles* aAttributeStyles) {
    129    MOZ_ASSERT(!mContainer.mAttributeStyles || !aAttributeStyles,
    130               "should never overwrite one sheet with another");
    131    mContainer.mAttributeStyles = aAttributeStyles;
    132    if (aAttributeStyles) {
    133      mContainer.mRaw |= uintptr_t(1);
    134    }
    135  }
    136 
    137  AttributeStyles* GetAttributeStyles() const {
    138    if (!(mContainer.mRaw & 0x1)) {
    139      return nullptr;
    140    }
    141    auto c = mContainer;
    142    c.mRaw &= ~uintptr_t(1);
    143    return c.mAttributeStyles;
    144  }
    145 
    146  bool IsReadOnly() const;
    147 
    148  size_t SizeofIncludingThis(MallocSizeOf);
    149 
    150  static already_AddRefed<DeclarationBlock> FromCssText(
    151      const nsACString& aCssText, URLExtraData* aExtraData,
    152      nsCompatibility aMode, css::Loader* aLoader, StyleCssRuleType aRuleType) {
    153    RefPtr<StyleLockedDeclarationBlock> raw =
    154        Servo_ParseStyleAttribute(&aCssText, aExtraData, aMode, aLoader,
    155                                  aRuleType)
    156            .Consume();
    157    return MakeAndAddRef<DeclarationBlock>(raw.forget());
    158  }
    159 
    160  static already_AddRefed<DeclarationBlock> FromCssText(
    161      const nsAString& aCssText, URLExtraData* aExtraData,
    162      nsCompatibility aMode, css::Loader* aLoader, StyleCssRuleType aRuleType) {
    163    NS_ConvertUTF16toUTF8 value(aCssText);
    164    return FromCssText(value, aExtraData, aMode, aLoader, aRuleType);
    165  }
    166 
    167  const StyleLockedDeclarationBlock* Raw() const { return mRaw; }
    168 
    169  void ToString(nsACString& aResult) const {
    170    Servo_DeclarationBlock_GetCssText(mRaw, &aResult);
    171  }
    172 
    173  uint32_t Count() const { return Servo_DeclarationBlock_Count(mRaw); }
    174 
    175  bool GetNthProperty(uint32_t aIndex, nsACString& aReturn) const {
    176    aReturn.Truncate();
    177    return Servo_DeclarationBlock_GetNthProperty(mRaw, aIndex, &aReturn);
    178  }
    179 
    180  void GetPropertyValue(const nsACString& aProperty, nsACString& aValue) const {
    181    Servo_DeclarationBlock_GetPropertyValue(mRaw, &aProperty, &aValue);
    182  }
    183 
    184  void GetPropertyValueById(NonCustomCSSPropertyId aPropId,
    185                            nsACString& aValue) const {
    186    Servo_DeclarationBlock_GetPropertyValueByNonCustomId(mRaw, aPropId,
    187                                                         &aValue);
    188  }
    189 
    190  void GetPropertyValueById(const CSSPropertyId& aPropId,
    191                            nsACString& aValue) const {
    192    Servo_DeclarationBlock_GetPropertyValueById(mRaw, &aPropId, &aValue);
    193  }
    194 
    195  bool GetPropertyIsImportant(const nsACString& aProperty) const {
    196    return Servo_DeclarationBlock_GetPropertyIsImportant(mRaw, &aProperty);
    197  }
    198 
    199  bool GetPropertyTypedValue(const nsACString& aProperty,
    200                             StylePropertyTypedValueResult& aResult) const {
    201    return Servo_DeclarationBlock_GetPropertyTypedValue(mRaw, &aProperty,
    202                                                        &aResult);
    203  }
    204 
    205  // Returns whether the property was removed.
    206  bool RemoveProperty(const nsACString& aProperty,
    207                      DeclarationBlockMutationClosure aClosure = {}) {
    208    AssertMutable();
    209    return Servo_DeclarationBlock_RemoveProperty(mRaw, &aProperty, aClosure);
    210  }
    211 
    212  // Returns whether the property was removed.
    213  bool RemovePropertyById(NonCustomCSSPropertyId aProperty,
    214                          DeclarationBlockMutationClosure aClosure = {}) {
    215    AssertMutable();
    216    return Servo_DeclarationBlock_RemovePropertyById(mRaw, aProperty, aClosure);
    217  }
    218 
    219 private:
    220  ~DeclarationBlock() = default;
    221 
    222  bool OwnerIsReadOnly() const;
    223 
    224  union {
    225    // We only ever have one of these since we have a AttributeStyles only for
    226    // style attributes, and style attributes never have an owning rule. It's a
    227    // AttributeStyles if the low bit is set.
    228 
    229    uintptr_t mRaw;
    230 
    231    // The style rule that owns this declaration.  May be null.
    232    css::Rule* mOwningRule;
    233 
    234    // The AttributeStyles that is responsible for this declaration. Only
    235    // non-null for style attributes.
    236    AttributeStyles* mAttributeStyles;
    237  } mContainer;
    238 
    239  RefPtr<const StyleLockedDeclarationBlock> mRaw;
    240 
    241  // set when declaration put in the rule tree;
    242  bool mImmutable;
    243 
    244  // True if this declaration has not been restyled after modified.
    245  //
    246  // Since we can clear this flag from style worker threads, we use an Atomic.
    247  //
    248  // Note that although a single DeclarationBlock can be shared between
    249  // different rule nodes (due to the style="" attribute cache), whenever a
    250  // DeclarationBlock has its mIsDirty flag set to true, we always clone it to
    251  // a unique object first. So when we clear this flag during Servo traversal,
    252  // we know that we are clearing it on a DeclarationBlock that has a single
    253  // reference, and there is no problem with another user of the same
    254  // DeclarationBlock thinking that it is not dirty.
    255  Atomic<bool, MemoryOrdering::Relaxed> mIsDirty;
    256 };
    257 
    258 }  // namespace mozilla
    259 
    260 #endif  // mozilla_DeclarationBlock_h