tor-browser

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

ServoCSSRuleList.cpp (11887B)


      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 /* representation of CSSRuleList for stylo */
      8 
      9 #include "mozilla/ServoCSSRuleList.h"
     10 
     11 #include "mozilla/ServoBindings.h"
     12 #include "mozilla/StyleSheet.h"
     13 #include "mozilla/dom/CSSContainerRule.h"
     14 #include "mozilla/dom/CSSCounterStyleRule.h"
     15 #include "mozilla/dom/CSSCustomMediaRule.h"
     16 #include "mozilla/dom/CSSFontFaceRule.h"
     17 #include "mozilla/dom/CSSFontFeatureValuesRule.h"
     18 #include "mozilla/dom/CSSFontPaletteValuesRule.h"
     19 #include "mozilla/dom/CSSImportRule.h"
     20 #include "mozilla/dom/CSSKeyframesRule.h"
     21 #include "mozilla/dom/CSSLayerBlockRule.h"
     22 #include "mozilla/dom/CSSLayerStatementRule.h"
     23 #include "mozilla/dom/CSSMarginRule.h"
     24 #include "mozilla/dom/CSSMediaRule.h"
     25 #include "mozilla/dom/CSSMozDocumentRule.h"
     26 #include "mozilla/dom/CSSNamespaceRule.h"
     27 #include "mozilla/dom/CSSNestedDeclarations.h"
     28 #include "mozilla/dom/CSSPageRule.h"
     29 #include "mozilla/dom/CSSPositionTryRule.h"
     30 #include "mozilla/dom/CSSPropertyRule.h"
     31 #include "mozilla/dom/CSSScopeRule.h"
     32 #include "mozilla/dom/CSSStartingStyleRule.h"
     33 #include "mozilla/dom/CSSStyleRule.h"
     34 #include "mozilla/dom/CSSSupportsRule.h"
     35 #include "mozilla/dom/Document.h"
     36 
     37 using namespace mozilla::dom;
     38 
     39 namespace mozilla {
     40 
     41 ServoCSSRuleList::ServoCSSRuleList(
     42    already_AddRefed<StyleLockedCssRules> aRawRules, StyleSheet* aSheet,
     43    css::GroupRule* aParentRule)
     44    : mStyleSheet(aSheet), mParentRule(aParentRule), mRawRules(aRawRules) {
     45  ResetRules();
     46 }
     47 
     48 // QueryInterface implementation for ServoCSSRuleList
     49 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ServoCSSRuleList)
     50 NS_INTERFACE_MAP_END_INHERITING(dom::CSSRuleList)
     51 
     52 NS_IMPL_ADDREF_INHERITED(ServoCSSRuleList, dom::CSSRuleList)
     53 NS_IMPL_RELEASE_INHERITED(ServoCSSRuleList, dom::CSSRuleList)
     54 
     55 NS_IMPL_CYCLE_COLLECTION_CLASS(ServoCSSRuleList)
     56 
     57 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ServoCSSRuleList)
     58  tmp->DropAllRules();
     59 NS_IMPL_CYCLE_COLLECTION_UNLINK_END_INHERITED(dom::CSSRuleList)
     60 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ServoCSSRuleList,
     61                                                  dom::CSSRuleList)
     62  tmp->EnumerateInstantiatedRules([&](css::Rule* aRule, uint32_t) {
     63    if (!aRule->IsCCLeaf()) {
     64      NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mRules[i]");
     65      cb.NoteXPCOMChild(aRule);
     66    }
     67  });
     68 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
     69 
     70 css::Rule* ServoCSSRuleList::GetRule(uint32_t aIndex) {
     71  uintptr_t rule = mRules[aIndex];
     72  if (rule <= kMaxRuleType) {
     73    RefPtr<css::Rule> ruleObj = nullptr;
     74    switch (StyleCssRuleType(rule)) {
     75 #define CASE_RULE_WITH_PREFIX(const_, prefix_, name_)                         \
     76  case StyleCssRuleType::const_: {                                            \
     77    uint32_t line = 0, column = 0;                                            \
     78    RefPtr<Style##prefix_##const_##Rule> raw =                                \
     79        Servo_CssRules_Get##const_##RuleAt(mRawRules, aIndex, &line, &column) \
     80            .Consume();                                                       \
     81    MOZ_ASSERT(raw);                                                          \
     82    ruleObj = new CSS##name_##Rule(raw.forget(), mStyleSheet, mParentRule,    \
     83                                   line, column);                             \
     84    MOZ_ASSERT(ruleObj->Type() == StyleCssRuleType(rule));                    \
     85    break;                                                                    \
     86  }
     87 #define CASE_RULE_LOCKED(const_, name_) \
     88  CASE_RULE_WITH_PREFIX(const_, Locked, name_)
     89 #define CASE_RULE_UNLOCKED(const_, name_) CASE_RULE_WITH_PREFIX(const_, , name_)
     90      CASE_RULE_LOCKED(Style, Style)
     91      CASE_RULE_LOCKED(Keyframes, Keyframes)
     92      CASE_RULE_UNLOCKED(Media, Media)
     93      CASE_RULE_UNLOCKED(Namespace, Namespace)
     94      CASE_RULE_UNLOCKED(Margin, Margin)
     95      CASE_RULE_LOCKED(Page, Page)
     96      CASE_RULE_UNLOCKED(Property, Property)
     97      CASE_RULE_UNLOCKED(Supports, Supports)
     98      CASE_RULE_UNLOCKED(Document, MozDocument)
     99      CASE_RULE_LOCKED(Import, Import)
    100      CASE_RULE_UNLOCKED(FontFeatureValues, FontFeatureValues)
    101      CASE_RULE_UNLOCKED(FontPaletteValues, FontPaletteValues)
    102      CASE_RULE_LOCKED(FontFace, FontFace)
    103      CASE_RULE_LOCKED(CounterStyle, CounterStyle)
    104      CASE_RULE_UNLOCKED(LayerBlock, LayerBlock)
    105      CASE_RULE_UNLOCKED(LayerStatement, LayerStatement)
    106      CASE_RULE_UNLOCKED(Container, Container)
    107      CASE_RULE_UNLOCKED(Scope, Scope)
    108      CASE_RULE_UNLOCKED(StartingStyle, StartingStyle)
    109      CASE_RULE_LOCKED(PositionTry, PositionTry)
    110      CASE_RULE_LOCKED(NestedDeclarations, NestedDeclarations)
    111      CASE_RULE_UNLOCKED(CustomMedia, CustomMedia)
    112 #undef CASE_RULE_LOCKED
    113 #undef CASE_RULE_UNLOCKED
    114 #undef CASE_RULE_WITH_PREFIX
    115      case StyleCssRuleType::Keyframe:
    116        MOZ_ASSERT_UNREACHABLE("keyframe rule cannot be here");
    117        return nullptr;
    118    }
    119    rule = CastToUint(ruleObj.forget().take());
    120    mRules[aIndex] = rule;
    121  }
    122  return CastToPtr(rule);
    123 }
    124 
    125 css::Rule* ServoCSSRuleList::IndexedGetter(uint32_t aIndex, bool& aFound) {
    126  if (aIndex >= mRules.Length()) {
    127    aFound = false;
    128    return nullptr;
    129  }
    130  aFound = true;
    131  return GetRule(aIndex);
    132 }
    133 
    134 template <typename Func>
    135 void ServoCSSRuleList::EnumerateInstantiatedRules(Func aCallback) {
    136  uint32_t index = 0;
    137  for (uintptr_t rule : mRules) {
    138    if (rule > kMaxRuleType) {
    139      aCallback(CastToPtr(rule), index);
    140    }
    141    index++;
    142  }
    143 }
    144 
    145 static void DropRule(already_AddRefed<css::Rule> aRule) {
    146  RefPtr<css::Rule> rule = aRule;
    147  rule->DropReferences();
    148 }
    149 
    150 void ServoCSSRuleList::ResetRules() {
    151  // DropRule could reenter here via the cycle collector.
    152  auto rules = std::move(mRules);
    153  for (uintptr_t rule : rules) {
    154    if (rule > kMaxRuleType) {
    155      DropRule(already_AddRefed<css::Rule>(CastToPtr(rule)));
    156    }
    157  }
    158  MOZ_ASSERT(mRules.IsEmpty());
    159  if (mRawRules) {
    160    Servo_CssRules_ListTypes(mRawRules, &mRules);
    161  }
    162 }
    163 
    164 void ServoCSSRuleList::DropAllRules() {
    165  mStyleSheet = nullptr;
    166  mParentRule = nullptr;
    167  mRawRules = nullptr;
    168 
    169  ResetRules();
    170 }
    171 
    172 void ServoCSSRuleList::DropSheetReference() {
    173  // If mStyleSheet is not set on this rule list, then it is not set on any of
    174  // its instantiated rules either.  To avoid O(N^2) beavhior in the depth of
    175  // group rule nesting, which can happen if we are unlinked starting from the
    176  // deepest nested group rule, skip recursing into the rule list if we know we
    177  // don't need to.
    178  if (!mStyleSheet) {
    179    return;
    180  }
    181  mStyleSheet = nullptr;
    182  EnumerateInstantiatedRules(
    183      [](css::Rule* rule, uint32_t) { rule->DropSheetReference(); });
    184 }
    185 
    186 void ServoCSSRuleList::DropParentRuleReference() {
    187  mParentRule = nullptr;
    188  EnumerateInstantiatedRules(
    189      [](css::Rule* rule, uint32_t) { rule->DropParentRuleReference(); });
    190 }
    191 
    192 nsresult ServoCSSRuleList::InsertRule(const nsACString& aRule,
    193                                      uint32_t aIndex) {
    194  MOZ_ASSERT(mStyleSheet,
    195             "Caller must ensure that "
    196             "the list is not unlinked from stylesheet");
    197 
    198  if (!mRawRules || IsReadOnly()) {
    199    return NS_OK;
    200  }
    201 
    202  mStyleSheet->WillDirty();
    203 
    204  css::Loader* loader = nullptr;
    205  auto allowImportRules = mStyleSheet->SelfOrAncestorIsConstructed()
    206                              ? StyleAllowImportRules::No
    207                              : StyleAllowImportRules::Yes;
    208 
    209  // TODO(emilio, bug 1535456): Should probably always be able to get a handle
    210  // to some loader if we're parsing an @import rule, but which one?
    211  //
    212  // StyleSheet::ReparseSheet just mints a new loader, but that'd be wrong in
    213  // this case I think, since such a load will bypass CSP checks.
    214  if (Document* doc = mStyleSheet->GetAssociatedDocument()) {
    215    loader = &doc->EnsureCSSLoader();
    216  }
    217  auto containingState = css::Rule::ContainingRuleState::From(mParentRule);
    218  StyleCssRuleType type;
    219  nsresult rv = Servo_CssRules_InsertRule(
    220      mRawRules, mStyleSheet->RawContents(), &aRule, aIndex,
    221      containingState.mContainingTypes,
    222      containingState.mParseRelativeType.ptrOr(nullptr), loader,
    223      allowImportRules, mStyleSheet, &type);
    224  NS_ENSURE_SUCCESS(rv, rv);
    225  mRules.InsertElementAt(aIndex, uintptr_t(type));
    226  return rv;
    227 }
    228 
    229 nsresult ServoCSSRuleList::DeleteRule(uint32_t aIndex) {
    230  if (!mRawRules || IsReadOnly()) {
    231    return NS_OK;
    232  }
    233 
    234  nsresult rv = Servo_CssRules_DeleteRule(mRawRules, aIndex);
    235  if (!NS_FAILED(rv)) {
    236    uintptr_t rule = mRules[aIndex];
    237    mRules.RemoveElementAt(aIndex);
    238    if (rule > kMaxRuleType) {
    239      DropRule(already_AddRefed<css::Rule>(CastToPtr(rule)));
    240    }
    241  }
    242  return rv;
    243 }
    244 
    245 void ServoCSSRuleList::SetRawContents(RefPtr<StyleLockedCssRules> aNewRules,
    246                                      bool aFromClone) {
    247  mRawRules = std::move(aNewRules);
    248  if (!aFromClone) {
    249    ResetRules();
    250    return;
    251  }
    252 
    253  EnumerateInstantiatedRules([&](css::Rule* aRule, uint32_t aIndex) {
    254 #define RULE_CASE_WITH_PREFIX(constant_, prefix_, type_)                \
    255  case StyleCssRuleType::constant_: {                                   \
    256    uint32_t line = 0, column = 0;                                      \
    257    RefPtr<Style##prefix_##constant_##Rule> raw =                       \
    258        Servo_CssRules_Get##constant_##RuleAt(mRawRules, aIndex, &line, \
    259                                              &column)                  \
    260            .Consume();                                                 \
    261    static_cast<dom::CSS##type_##Rule*>(aRule)->SetRawAfterClone(       \
    262        std::move(raw));                                                \
    263    break;                                                              \
    264  }
    265 #define RULE_CASE_LOCKED(constant_, type_) \
    266  RULE_CASE_WITH_PREFIX(constant_, Locked, type_)
    267 #define RULE_CASE_UNLOCKED(constant_, type_) \
    268  RULE_CASE_WITH_PREFIX(constant_, , type_)
    269    switch (aRule->Type()) {
    270      RULE_CASE_LOCKED(Style, Style)
    271      RULE_CASE_LOCKED(Keyframes, Keyframes)
    272      RULE_CASE_UNLOCKED(Media, Media)
    273      RULE_CASE_UNLOCKED(Namespace, Namespace)
    274      RULE_CASE_UNLOCKED(Margin, Margin)
    275      RULE_CASE_LOCKED(Page, Page)
    276      RULE_CASE_UNLOCKED(Property, Property)
    277      RULE_CASE_UNLOCKED(Supports, Supports)
    278      RULE_CASE_UNLOCKED(Document, MozDocument)
    279      RULE_CASE_LOCKED(Import, Import)
    280      RULE_CASE_UNLOCKED(FontFeatureValues, FontFeatureValues)
    281      RULE_CASE_UNLOCKED(FontPaletteValues, FontPaletteValues)
    282      RULE_CASE_LOCKED(FontFace, FontFace)
    283      RULE_CASE_LOCKED(CounterStyle, CounterStyle)
    284      RULE_CASE_UNLOCKED(LayerBlock, LayerBlock)
    285      RULE_CASE_UNLOCKED(LayerStatement, LayerStatement)
    286      RULE_CASE_UNLOCKED(Container, Container)
    287      RULE_CASE_UNLOCKED(Scope, Scope)
    288      RULE_CASE_UNLOCKED(StartingStyle, StartingStyle)
    289      RULE_CASE_LOCKED(PositionTry, PositionTry)
    290      RULE_CASE_LOCKED(NestedDeclarations, NestedDeclarations)
    291      RULE_CASE_UNLOCKED(CustomMedia, CustomMedia)
    292      case StyleCssRuleType::Keyframe:
    293        MOZ_ASSERT_UNREACHABLE("keyframe rule cannot be here");
    294        break;
    295    }
    296 #undef RULE_CASE_WITH_PREFIX
    297 #undef RULE_CASE_LOCKED
    298 #undef RULE_CASE_UNLOCKED
    299  });
    300 }
    301 
    302 ServoCSSRuleList::~ServoCSSRuleList() {
    303  MOZ_ASSERT(!mStyleSheet, "Backpointer should have been cleared");
    304  MOZ_ASSERT(!mParentRule, "Backpointer should have been cleared");
    305  DropAllRules();
    306 }
    307 
    308 bool ServoCSSRuleList::IsReadOnly() const {
    309  MOZ_ASSERT(!mStyleSheet || !mParentRule ||
    310                 mStyleSheet->IsReadOnly() == mParentRule->IsReadOnly(),
    311             "a parent rule should be read only iff the owning sheet is "
    312             "read only");
    313  return mStyleSheet && mStyleSheet->IsReadOnly();
    314 }
    315 
    316 }  // namespace mozilla