tor-browser

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

nsStyledElement.cpp (7711B)


      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 #include "nsStyledElement.h"
      8 
      9 #include "mozAutoDocUpdate.h"
     10 #include "mozilla/DeclarationBlock.h"
     11 #include "mozilla/RefPtr.h"
     12 #include "mozilla/css/Loader.h"
     13 #include "mozilla/dom/BindContext.h"
     14 #include "mozilla/dom/CustomElementRegistry.h"
     15 #include "mozilla/dom/Document.h"
     16 #include "mozilla/dom/ElementInlines.h"
     17 #include "mozilla/dom/MutationObservers.h"
     18 #include "mozilla/dom/StylePropertyMap.h"
     19 #include "nsAttrValue.h"
     20 #include "nsAttrValueInlines.h"
     21 #include "nsContentUtils.h"
     22 #include "nsDOMCSSAttrDeclaration.h"
     23 #include "nsDOMCSSDeclaration.h"
     24 #include "nsGkAtoms.h"
     25 #include "nsIMutationObserver.h"
     26 #include "nsServiceManagerUtils.h"
     27 #include "nsStyleUtil.h"
     28 #include "nsXULElement.h"
     29 
     30 using namespace mozilla;
     31 using namespace mozilla::dom;
     32 
     33 // Use the CC variant of this, even though this class does not define
     34 // a new CC participant, to make QIing to the CC interfaces faster.
     35 NS_IMPL_QUERY_INTERFACE_CYCLE_COLLECTION_INHERITED(nsStyledElement,
     36                                                   nsStyledElementBase,
     37                                                   nsStyledElement)
     38 
     39 //----------------------------------------------------------------------
     40 // nsIContent methods
     41 
     42 bool nsStyledElement::ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute,
     43                                     const nsAString& aValue,
     44                                     nsIPrincipal* aMaybeScriptedPrincipal,
     45                                     nsAttrValue& aResult) {
     46  if (aAttribute == nsGkAtoms::style && aNamespaceID == kNameSpaceID_None) {
     47    ParseStyleAttribute(aValue, aMaybeScriptedPrincipal, aResult, false);
     48    return true;
     49  }
     50 
     51  return nsStyledElementBase::ParseAttribute(aNamespaceID, aAttribute, aValue,
     52                                             aMaybeScriptedPrincipal, aResult);
     53 }
     54 
     55 void nsStyledElement::BeforeSetAttr(int32_t aNamespaceID, nsAtom* aName,
     56                                    const nsAttrValue* aValue, bool aNotify) {
     57  if (aNamespaceID == kNameSpaceID_None && aName == nsGkAtoms::style &&
     58      aValue) {
     59    SetMayHaveStyle();
     60  }
     61 
     62  return nsStyledElementBase::BeforeSetAttr(aNamespaceID, aName, aValue,
     63                                            aNotify);
     64 }
     65 
     66 void nsStyledElement::InlineStyleDeclarationWillChange(
     67    MutationClosureData& aData) {
     68  MOZ_ASSERT(!nsContentUtils::IsSafeToRunScript());
     69  MOZ_ASSERT(OwnerDoc()->UpdateNestingLevel() > 0,
     70             "Should be inside document update!");
     71  bool modification = false;
     72  if (MayHaveStyle()) {
     73    CustomElementDefinition* definition = GetCustomElementDefinition();
     74    if (definition && definition->IsInObservedAttributeList(nsGkAtoms::style)) {
     75      nsAutoString oldValueStr;
     76      modification = GetAttr(nsGkAtoms::style, oldValueStr);
     77      if (modification) {
     78        aData.mOldValue.emplace();
     79        aData.mOldValue->SetTo(oldValueStr);
     80      }
     81    } else {
     82      modification = HasAttr(nsGkAtoms::style);
     83    }
     84  }
     85 
     86  aData.mModType =
     87      modification ? AttrModType::Modification : AttrModType::Addition;
     88  MutationObservers::NotifyAttributeWillChange(
     89      this, kNameSpaceID_None, nsGkAtoms::style, aData.mModType);
     90 
     91  // XXXsmaug In order to make attribute handling more consistent, consider to
     92  //         call BeforeSetAttr and pass kCallAfterSetAttr to
     93  //         SetAttrAndNotify in SetInlineStyleDeclaration.
     94  //         Handling of mozAutoDocUpdate may require changes in that case.
     95 }
     96 
     97 nsresult nsStyledElement::SetInlineStyleDeclaration(
     98    DeclarationBlock& aDeclaration, MutationClosureData& aData) {
     99  MOZ_ASSERT(OwnerDoc()->UpdateNestingLevel(),
    100             "Should be inside document update!");
    101 
    102  nsAttrValue attrValue(do_AddRef(&aDeclaration), nullptr);
    103  SetMayHaveStyle();
    104 
    105  Document* document = GetComposedDoc();
    106  mozAutoDocUpdate updateBatch(document, true);
    107  return SetAttrAndNotify(kNameSpaceID_None, nsGkAtoms::style, nullptr,
    108                          aData.mOldValue.ptrOr(nullptr), attrValue, nullptr,
    109                          aData.mModType, true, kDontCallAfterSetAttr, document,
    110                          updateBatch);
    111 }
    112 
    113 // ---------------------------------------------------------------
    114 // Others and helpers
    115 
    116 nsDOMCSSDeclaration* nsStyledElement::Style() {
    117  Element::nsDOMSlots* slots = DOMSlots();
    118 
    119  if (!slots->mStyle) {
    120    // Just in case...
    121    ReparseStyleAttribute(/* aForceInDataDoc */ true);
    122 
    123    slots->mStyle = new nsDOMCSSAttributeDeclaration(this, false);
    124    SetMayHaveStyle();
    125  }
    126 
    127  return slots->mStyle;
    128 }
    129 
    130 StylePropertyMap* nsStyledElement::AttributeStyleMap() {
    131  nsDOMSlots* slots = DOMSlots();
    132 
    133  if (!slots->mAttributeStyleMap) {
    134    slots->mAttributeStyleMap =
    135        MakeRefPtr<StylePropertyMap>(this, /* aComputed */ false);
    136  }
    137 
    138  return slots->mAttributeStyleMap;
    139 }
    140 
    141 nsresult nsStyledElement::ReparseStyleAttribute(bool aForceInDataDoc) {
    142  if (!MayHaveStyle()) {
    143    return NS_OK;
    144  }
    145  const nsAttrValue* oldVal = mAttrs.GetAttr(nsGkAtoms::style);
    146  if (oldVal && oldVal->Type() != nsAttrValue::eCSSDeclaration) {
    147    nsAttrValue attrValue;
    148    nsAutoString stringValue;
    149    oldVal->ToString(stringValue);
    150    if (!stringValue.IsEmpty()) {
    151      // Prevent CSP errors from re-parsing a style that was already blocked.
    152      ParseStyleAttribute(stringValue, nullptr, attrValue, aForceInDataDoc);
    153    }
    154    // Don't bother going through SetInlineStyleDeclaration; we don't
    155    // want to fire off mutation events or document notifications anyway
    156    bool oldValueSet;
    157    nsresult rv = SetAndSwapAttr(nsGkAtoms::style, attrValue, &oldValueSet);
    158    NS_ENSURE_SUCCESS(rv, rv);
    159  }
    160 
    161  return NS_OK;
    162 }
    163 
    164 nsDOMCSSDeclaration* nsStyledElement::GetExistingStyle() {
    165  Element::nsDOMSlots* slots = GetExistingDOMSlots();
    166  if (!slots) {
    167    return nullptr;
    168  }
    169 
    170  return slots->mStyle;
    171 }
    172 
    173 void nsStyledElement::ParseStyleAttribute(const nsAString& aValue,
    174                                          nsIPrincipal* aMaybeScriptedPrincipal,
    175                                          nsAttrValue& aResult,
    176                                          bool aForceInDataDoc) {
    177  Document* doc = OwnerDoc();
    178  bool isNativeAnon = IsInNativeAnonymousSubtree();
    179 
    180  if (!isNativeAnon &&
    181      !nsStyleUtil::CSPAllowsInlineStyle(this, doc, aMaybeScriptedPrincipal, 0,
    182                                         1, aValue, nullptr)) {
    183    return;
    184  }
    185 
    186  if (aForceInDataDoc || !doc->IsLoadedAsData() || GetExistingStyle() ||
    187      doc->IsStaticDocument()) {
    188    bool isCSS = true;  // assume CSS until proven otherwise
    189 
    190    if (!isNativeAnon) {  // native anonymous content always assumes CSS
    191      nsAutoString styleType;
    192      doc->GetHeaderData(nsGkAtoms::headerContentStyleType, styleType);
    193      if (!styleType.IsEmpty()) {
    194        isCSS = StringBeginsWith(styleType, u"text/css"_ns,
    195                                 nsASCIICaseInsensitiveStringComparator);
    196      }
    197    }
    198 
    199    if (isCSS &&
    200        aResult.ParseStyleAttribute(aValue, aMaybeScriptedPrincipal, this)) {
    201      return;
    202    }
    203  }
    204 
    205  aResult.SetTo(aValue);
    206 }
    207 
    208 nsresult nsStyledElement::BindToTree(BindContext& aContext, nsINode& aParent) {
    209  nsresult rv = nsStyledElementBase::BindToTree(aContext, aParent);
    210  NS_ENSURE_SUCCESS(rv, rv);
    211 
    212  if (HasAttr(nsGkAtoms::autofocus) && aContext.AllowsAutoFocus() &&
    213      (!IsSVGElement() || IsFocusableWithoutStyle())) {
    214    aContext.OwnerDoc().ElementWithAutoFocusInserted(this);
    215  }
    216 
    217  return NS_OK;
    218 }