tor-browser

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

nsDOMCSSDeclaration.cpp (12737B)


      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 /* base class for DOM objects for element.style and cssStyleRule.style */
      8 
      9 #include "nsDOMCSSDeclaration.h"
     10 
     11 #include "mozAutoDocUpdate.h"
     12 #include "mozilla/DeclarationBlock.h"
     13 #include "mozilla/ProfilerLabels.h"
     14 #include "mozilla/StyleSheetInlines.h"
     15 #include "mozilla/css/Rule.h"
     16 #include "mozilla/dom/BindingUtils.h"
     17 #include "mozilla/dom/CSSStylePropertiesBinding.h"
     18 #include "nsCOMPtr.h"
     19 #include "nsCSSProps.h"
     20 #include "nsQueryObject.h"
     21 
     22 using namespace mozilla;
     23 using namespace mozilla::dom;
     24 
     25 nsDOMCSSDeclaration::~nsDOMCSSDeclaration() = default;
     26 
     27 /* virtual */
     28 JSObject* nsDOMCSSDeclaration::WrapObject(JSContext* aCx,
     29                                          JS::Handle<JSObject*> aGivenProto) {
     30  return CSSStyleProperties_Binding::Wrap(aCx, this, aGivenProto);
     31 }
     32 
     33 NS_IMPL_QUERY_INTERFACE(nsDOMCSSDeclaration, nsICSSDeclaration)
     34 
     35 void nsDOMCSSDeclaration::GetPropertyValue(const NonCustomCSSPropertyId aPropId,
     36                                           nsACString& aValue) {
     37  MOZ_ASSERT(aPropId != eCSSProperty_UNKNOWN,
     38             "Should never pass eCSSProperty_UNKNOWN around");
     39  MOZ_ASSERT(aValue.IsEmpty());
     40 
     41  if (DeclarationBlock* decl =
     42          GetOrCreateCSSDeclaration(Operation::Read, nullptr)) {
     43    decl->GetPropertyValueById(aPropId, aValue);
     44  }
     45 }
     46 
     47 void nsDOMCSSDeclaration::SetPropertyValue(const NonCustomCSSPropertyId aPropId,
     48                                           const nsACString& aValue,
     49                                           nsIPrincipal* aSubjectPrincipal,
     50                                           ErrorResult& aRv) {
     51  if (IsReadOnly()) {
     52    return;
     53  }
     54 
     55  if (aValue.IsEmpty()) {
     56    // If the new value of the property is an empty string we remove the
     57    // property.
     58    return RemovePropertyInternal(aPropId, aRv);
     59  }
     60 
     61  aRv = ParsePropertyValue(aPropId, aValue, false, aSubjectPrincipal);
     62 }
     63 
     64 void nsDOMCSSDeclaration::GetCssText(nsACString& aCssText) {
     65  MOZ_ASSERT(aCssText.IsEmpty());
     66 
     67  if (auto* decl = GetOrCreateCSSDeclaration(Operation::Read, nullptr)) {
     68    decl->ToString(aCssText);
     69  }
     70 }
     71 
     72 void nsDOMCSSDeclaration::SetCssText(const nsACString& aCssText,
     73                                     nsIPrincipal* aSubjectPrincipal,
     74                                     ErrorResult& aRv) {
     75  if (IsReadOnly()) {
     76    return;
     77  }
     78 
     79  // We don't need to *do* anything with the old declaration, but we need
     80  // to ensure that it exists, or else SetCSSDeclaration may crash.
     81  RefPtr<DeclarationBlock> created;
     82  DeclarationBlock* olddecl =
     83      GetOrCreateCSSDeclaration(Operation::Modify, getter_AddRefs(created));
     84  if (!olddecl) {
     85    aRv.Throw(NS_ERROR_NOT_AVAILABLE);
     86    return;
     87  }
     88 
     89  // For nsDOMCSSAttributeDeclaration, SetCSSDeclaration will lead to
     90  // Attribute setting code, which leads in turn to BeginUpdate.  We
     91  // need to start the update now so that the old rule doesn't get used
     92  // between when we mutate the declaration and when we set the new
     93  // rule (see stack in bug 209575).
     94  mozAutoDocUpdate autoUpdate(DocToUpdate(), true);
     95  DeclarationBlockMutationClosure closure = {};
     96  MutationClosureData closureData;
     97  GetPropertyChangeClosure(&closure, &closureData);
     98 
     99  ParsingEnvironment servoEnv = GetParsingEnvironment(aSubjectPrincipal);
    100  if (!servoEnv.mUrlExtraData) {
    101    aRv.Throw(NS_ERROR_NOT_AVAILABLE);
    102    return;
    103  }
    104 
    105  // Need to special case closure calling here, since parsing css text
    106  // doesn't modify any existing declaration and that is why the callback isn't
    107  // called implicitly.
    108  if (closure.function && !closureData.mWasCalled) {
    109    closure.function(&closureData, eCSSProperty_UNKNOWN);
    110  }
    111 
    112  RefPtr<DeclarationBlock> newdecl = DeclarationBlock::FromCssText(
    113      aCssText, servoEnv.mUrlExtraData, servoEnv.mCompatMode, servoEnv.mLoader,
    114      servoEnv.mRuleType);
    115 
    116  aRv = SetCSSDeclaration(newdecl, &closureData);
    117 }
    118 
    119 uint32_t nsDOMCSSDeclaration::Length() {
    120  DeclarationBlock* decl = GetOrCreateCSSDeclaration(Operation::Read, nullptr);
    121 
    122  if (decl) {
    123    return decl->Count();
    124  }
    125 
    126  return 0;
    127 }
    128 
    129 void nsDOMCSSDeclaration::IndexedGetter(uint32_t aIndex, bool& aFound,
    130                                        nsACString& aPropName) {
    131  DeclarationBlock* decl = GetOrCreateCSSDeclaration(Operation::Read, nullptr);
    132  aFound = decl && decl->GetNthProperty(aIndex, aPropName);
    133 }
    134 
    135 void nsDOMCSSDeclaration::GetPropertyValue(const nsACString& aPropertyName,
    136                                           nsACString& aReturn) {
    137  MOZ_ASSERT(aReturn.IsEmpty());
    138  if (auto* decl = GetOrCreateCSSDeclaration(Operation::Read, nullptr)) {
    139    decl->GetPropertyValue(aPropertyName, aReturn);
    140  }
    141 }
    142 
    143 bool nsDOMCSSDeclaration::HasLonghandProperty(const nsACString& aPropertyName) {
    144  if (auto* decl = GetOrCreateCSSDeclaration(Operation::Read, nullptr)) {
    145    return Servo_DeclarationBlock_HasLonghandProperty(decl->Raw(),
    146                                                      &aPropertyName);
    147  }
    148 
    149  return false;
    150 }
    151 
    152 void nsDOMCSSDeclaration::GetPropertyPriority(const nsACString& aPropertyName,
    153                                              nsACString& aPriority) {
    154  MOZ_ASSERT(aPriority.IsEmpty());
    155  DeclarationBlock* decl = GetOrCreateCSSDeclaration(Operation::Read, nullptr);
    156  if (decl && decl->GetPropertyIsImportant(aPropertyName)) {
    157    aPriority.AssignLiteral("important");
    158  }
    159 }
    160 
    161 void nsDOMCSSDeclaration::SetProperty(const nsACString& aPropertyName,
    162                                      const nsACString& aValue,
    163                                      const nsACString& aPriority,
    164                                      nsIPrincipal* aSubjectPrincipal,
    165                                      ErrorResult& aRv) {
    166  if (IsReadOnly()) {
    167    return;
    168  }
    169 
    170  if (aValue.IsEmpty()) {
    171    // If the new value of the property is an empty string we remove the
    172    // property.
    173    // XXX this ignores the priority string, should it?
    174    return RemovePropertyInternal(aPropertyName, aRv);
    175  }
    176 
    177  // In the common (and fast) cases we can use the property id
    178  NonCustomCSSPropertyId propId = nsCSSProps::LookupProperty(aPropertyName);
    179  if (propId == eCSSProperty_UNKNOWN) {
    180    return;
    181  }
    182 
    183  bool important;
    184  if (aPriority.IsEmpty()) {
    185    important = false;
    186  } else if (aPriority.LowerCaseEqualsASCII("important")) {
    187    important = true;
    188  } else {
    189    // XXX silent failure?
    190    return;
    191  }
    192 
    193  if (propId == eCSSPropertyExtra_variable) {
    194    aRv = ParseCustomPropertyValue(aPropertyName, aValue, important,
    195                                   aSubjectPrincipal);
    196    return;
    197  }
    198  aRv = ParsePropertyValue(propId, aValue, important, aSubjectPrincipal);
    199 }
    200 
    201 void nsDOMCSSDeclaration::RemoveProperty(const nsACString& aPropertyName,
    202                                         nsACString& aReturn,
    203                                         ErrorResult& aRv) {
    204  if (IsReadOnly()) {
    205    return;
    206  }
    207  GetPropertyValue(aPropertyName, aReturn);
    208  RemovePropertyInternal(aPropertyName, aRv);
    209 }
    210 
    211 /* static */ nsDOMCSSDeclaration::ParsingEnvironment
    212 nsDOMCSSDeclaration::GetParsingEnvironmentForRule(const css::Rule* aRule,
    213                                                  StyleCssRuleType aRuleType) {
    214  if (!aRule) {
    215    return {};
    216  }
    217 
    218  MOZ_ASSERT(aRule->Type() == aRuleType);
    219 
    220  StyleSheet* sheet = aRule->GetStyleSheet();
    221  if (!sheet) {
    222    return {};
    223  }
    224 
    225  if (Document* document = sheet->GetAssociatedDocument()) {
    226    return {
    227        sheet->URLData(),
    228        document->GetCompatibilityMode(),
    229        document->GetExistingCSSLoader(),
    230        aRuleType,
    231    };
    232  }
    233 
    234  return {
    235      sheet->URLData(),
    236      eCompatibility_FullStandards,
    237      nullptr,
    238      aRuleType,
    239  };
    240 }
    241 
    242 template <typename Func>
    243 nsresult nsDOMCSSDeclaration::ModifyDeclaration(
    244    nsIPrincipal* aSubjectPrincipal, MutationClosureData* aClosureData,
    245    Func aFunc) {
    246  RefPtr<DeclarationBlock> created;
    247  DeclarationBlock* olddecl =
    248      GetOrCreateCSSDeclaration(Operation::Modify, getter_AddRefs(created));
    249  if (!olddecl) {
    250    return NS_ERROR_NOT_AVAILABLE;
    251  }
    252 
    253  // For nsDOMCSSAttributeDeclaration, SetCSSDeclaration will lead to
    254  // Attribute setting code, which leads in turn to BeginUpdate.  We
    255  // need to start the update now so that the old rule doesn't get used
    256  // between when we mutate the declaration and when we set the new
    257  // rule (see stack in bug 209575).
    258  mozAutoDocUpdate autoUpdate(DocToUpdate(), true);
    259  RefPtr<DeclarationBlock> decl = olddecl->EnsureMutable();
    260 
    261  bool changed;
    262  ParsingEnvironment servoEnv = GetParsingEnvironment(aSubjectPrincipal);
    263  if (!servoEnv.mUrlExtraData) {
    264    return NS_ERROR_NOT_AVAILABLE;
    265  }
    266 
    267  changed = aFunc(decl, servoEnv);
    268 
    269  if (!changed) {
    270    // Parsing failed -- but we don't throw an exception for that.
    271    return NS_OK;
    272  }
    273 
    274  return SetCSSDeclaration(decl, aClosureData);
    275 }
    276 
    277 nsresult nsDOMCSSDeclaration::ParsePropertyValue(
    278    const NonCustomCSSPropertyId aPropId, const nsACString& aPropValue,
    279    bool aIsImportant, nsIPrincipal* aSubjectPrincipal) {
    280  AUTO_PROFILER_LABEL_CATEGORY_PAIR_RELEVANT_FOR_JS(LAYOUT_CSSParsing);
    281 
    282  if (IsReadOnly()) {
    283    return NS_OK;
    284  }
    285 
    286  DeclarationBlockMutationClosure closure = {};
    287  MutationClosureData closureData;
    288  GetPropertyChangeClosure(&closure, &closureData);
    289 
    290  return ModifyDeclaration(
    291      aSubjectPrincipal, &closureData,
    292      [&](DeclarationBlock* decl, ParsingEnvironment& env) {
    293        return Servo_DeclarationBlock_SetPropertyById(
    294            decl->Raw(), aPropId, &aPropValue, aIsImportant, env.mUrlExtraData,
    295            StyleParsingMode::DEFAULT, env.mCompatMode, env.mLoader,
    296            env.mRuleType, closure);
    297      });
    298 }
    299 
    300 nsresult nsDOMCSSDeclaration::ParseCustomPropertyValue(
    301    const nsACString& aPropertyName, const nsACString& aPropValue,
    302    bool aIsImportant, nsIPrincipal* aSubjectPrincipal) {
    303  MOZ_ASSERT(nsCSSProps::IsCustomPropertyName(aPropertyName));
    304 
    305  if (IsReadOnly()) {
    306    return NS_OK;
    307  }
    308 
    309  DeclarationBlockMutationClosure closure = {};
    310  MutationClosureData closureData;
    311  GetPropertyChangeClosure(&closure, &closureData);
    312 
    313  return ModifyDeclaration(
    314      aSubjectPrincipal, &closureData,
    315      [&](DeclarationBlock* decl, ParsingEnvironment& env) {
    316        return Servo_DeclarationBlock_SetProperty(
    317            decl->Raw(), &aPropertyName, &aPropValue, aIsImportant,
    318            env.mUrlExtraData, StyleParsingMode::DEFAULT, env.mCompatMode,
    319            env.mLoader, env.mRuleType, closure);
    320      });
    321 }
    322 
    323 void nsDOMCSSDeclaration::RemovePropertyInternal(NonCustomCSSPropertyId aPropId,
    324                                                 ErrorResult& aRv) {
    325  DeclarationBlock* olddecl =
    326      GetOrCreateCSSDeclaration(Operation::RemoveProperty, nullptr);
    327  if (IsReadOnly()) {
    328    return;
    329  }
    330 
    331  if (!olddecl) {
    332    return;  // no decl, so nothing to remove
    333  }
    334 
    335  // For nsDOMCSSAttributeDeclaration, SetCSSDeclaration will lead to
    336  // Attribute setting code, which leads in turn to BeginUpdate.  We
    337  // need to start the update now so that the old rule doesn't get used
    338  // between when we mutate the declaration and when we set the new
    339  // rule (see stack in bug 209575).
    340  mozAutoDocUpdate autoUpdate(DocToUpdate(), true);
    341 
    342  DeclarationBlockMutationClosure closure = {};
    343  MutationClosureData closureData;
    344  GetPropertyChangeClosure(&closure, &closureData);
    345 
    346  RefPtr<DeclarationBlock> decl = olddecl->EnsureMutable();
    347  if (!decl->RemovePropertyById(aPropId, closure)) {
    348    return;
    349  }
    350  aRv = SetCSSDeclaration(decl, &closureData);
    351 }
    352 
    353 void nsDOMCSSDeclaration::RemovePropertyInternal(
    354    const nsACString& aPropertyName, ErrorResult& aRv) {
    355  if (IsReadOnly()) {
    356    return;
    357  }
    358 
    359  DeclarationBlock* olddecl =
    360      GetOrCreateCSSDeclaration(Operation::RemoveProperty, nullptr);
    361  if (!olddecl) {
    362    return;  // no decl, so nothing to remove
    363  }
    364 
    365  // For nsDOMCSSAttributeDeclaration, SetCSSDeclaration will lead to
    366  // Attribute setting code, which leads in turn to BeginUpdate.  We
    367  // need to start the update now so that the old rule doesn't get used
    368  // between when we mutate the declaration and when we set the new
    369  // rule (see stack in bug 209575).
    370  mozAutoDocUpdate autoUpdate(DocToUpdate(), true);
    371 
    372  DeclarationBlockMutationClosure closure = {};
    373  MutationClosureData closureData;
    374  GetPropertyChangeClosure(&closure, &closureData);
    375 
    376  RefPtr<DeclarationBlock> decl = olddecl->EnsureMutable();
    377  if (!decl->RemoveProperty(aPropertyName, closure)) {
    378    return;
    379  }
    380  aRv = SetCSSDeclaration(decl, &closureData);
    381 }