Bug 1750871 - run mochitest-remote on fission everywhere. r=releng-reviewers,aki
[gecko.git] / dom / base / nsStyledElement.cpp
blob1a3d1547d3a510dee2eeb7950f79e8ec179b5470
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/. */
7 #include "nsStyledElement.h"
8 #include "mozAutoDocUpdate.h"
9 #include "nsGkAtoms.h"
10 #include "nsAttrValue.h"
11 #include "nsAttrValueInlines.h"
12 #include "mozilla/dom/CustomElementRegistry.h"
13 #include "mozilla/dom/ElementInlines.h"
14 #include "mozilla/dom/MutationEventBinding.h"
15 #include "mozilla/dom/MutationObservers.h"
16 #include "mozilla/InternalMutationEvent.h"
17 #include "mozilla/StaticPrefs_dom.h"
18 #include "nsDOMCSSDeclaration.h"
19 #include "nsDOMCSSAttrDeclaration.h"
20 #include "nsServiceManagerUtils.h"
21 #include "mozilla/dom/Document.h"
22 #include "mozilla/DeclarationBlock.h"
23 #include "mozilla/css/Loader.h"
24 #include "nsXULElement.h"
25 #include "nsContentUtils.h"
26 #include "nsStyleUtil.h"
28 using namespace mozilla;
29 using namespace mozilla::dom;
31 // Use the CC variant of this, even though this class does not define
32 // a new CC participant, to make QIing to the CC interfaces faster.
33 NS_IMPL_QUERY_INTERFACE_CYCLE_COLLECTION_INHERITED(nsStyledElement,
34 nsStyledElementBase,
35 nsStyledElement)
37 //----------------------------------------------------------------------
38 // nsIContent methods
40 bool nsStyledElement::ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute,
41 const nsAString& aValue,
42 nsIPrincipal* aMaybeScriptedPrincipal,
43 nsAttrValue& aResult) {
44 if (aAttribute == nsGkAtoms::style && aNamespaceID == kNameSpaceID_None) {
45 ParseStyleAttribute(aValue, aMaybeScriptedPrincipal, aResult, false);
46 return true;
49 return nsStyledElementBase::ParseAttribute(aNamespaceID, aAttribute, aValue,
50 aMaybeScriptedPrincipal, aResult);
53 nsresult nsStyledElement::BeforeSetAttr(int32_t aNamespaceID, nsAtom* aName,
54 const nsAttrValueOrString* aValue,
55 bool aNotify) {
56 if (aNamespaceID == kNameSpaceID_None) {
57 if (aName == nsGkAtoms::style) {
58 if (aValue) {
59 SetMayHaveStyle();
64 return nsStyledElementBase::BeforeSetAttr(aNamespaceID, aName, aValue,
65 aNotify);
68 void nsStyledElement::InlineStyleDeclarationWillChange(
69 MutationClosureData& aData) {
70 MOZ_ASSERT(!nsContentUtils::IsSafeToRunScript());
71 MOZ_ASSERT(OwnerDoc()->UpdateNestingLevel() > 0,
72 "Should be inside document update!");
73 bool modification = false;
74 if (MayHaveStyle()) {
75 bool needsOldValue = !StaticPrefs::dom_mutation_events_cssom_disabled() &&
76 nsContentUtils::HasMutationListeners(
77 this, NS_EVENT_BITS_MUTATION_ATTRMODIFIED, this);
79 if (!needsOldValue) {
80 CustomElementDefinition* definition = GetCustomElementDefinition();
81 if (definition &&
82 definition->IsInObservedAttributeList(nsGkAtoms::style)) {
83 needsOldValue = true;
87 if (needsOldValue) {
88 nsAutoString oldValueStr;
89 modification = GetAttr(kNameSpaceID_None, nsGkAtoms::style, oldValueStr);
90 if (modification) {
91 aData.mOldValue.emplace();
92 aData.mOldValue->SetTo(oldValueStr);
94 } else {
95 modification = HasAttr(kNameSpaceID_None, nsGkAtoms::style);
99 aData.mModType =
100 modification ? static_cast<uint8_t>(MutationEvent_Binding::MODIFICATION)
101 : static_cast<uint8_t>(MutationEvent_Binding::ADDITION);
102 MutationObservers::NotifyAttributeWillChange(
103 this, kNameSpaceID_None, nsGkAtoms::style, aData.mModType);
105 // XXXsmaug In order to make attribute handling more consistent, consider to
106 // call BeforeSetAttr and pass kCallAfterSetAttr to
107 // SetAttrAndNotify in SetInlineStyleDeclaration.
108 // Handling of mozAutoDocUpdate may require changes in that case.
111 nsresult nsStyledElement::SetInlineStyleDeclaration(
112 DeclarationBlock& aDeclaration, MutationClosureData& aData) {
113 MOZ_ASSERT(OwnerDoc()->UpdateNestingLevel(),
114 "Should be inside document update!");
116 bool hasListeners = !StaticPrefs::dom_mutation_events_cssom_disabled() &&
117 nsContentUtils::HasMutationListeners(
118 this, NS_EVENT_BITS_MUTATION_ATTRMODIFIED, this);
120 nsAttrValue attrValue(do_AddRef(&aDeclaration), nullptr);
121 SetMayHaveStyle();
123 Document* document = GetComposedDoc();
124 mozAutoDocUpdate updateBatch(document, true);
125 return SetAttrAndNotify(kNameSpaceID_None, nsGkAtoms::style, nullptr,
126 aData.mOldValue.ptrOr(nullptr), attrValue, nullptr,
127 aData.mModType, hasListeners, true,
128 kDontCallAfterSetAttr, document, updateBatch);
131 // ---------------------------------------------------------------
132 // Others and helpers
134 nsICSSDeclaration* nsStyledElement::Style() {
135 Element::nsDOMSlots* slots = DOMSlots();
137 if (!slots->mStyle) {
138 // Just in case...
139 ReparseStyleAttribute(/* aForceInDataDoc */ true);
141 slots->mStyle = new nsDOMCSSAttributeDeclaration(this, false);
142 SetMayHaveStyle();
145 return slots->mStyle;
148 nsresult nsStyledElement::ReparseStyleAttribute(bool aForceInDataDoc) {
149 if (!MayHaveStyle()) {
150 return NS_OK;
152 const nsAttrValue* oldVal = mAttrs.GetAttr(nsGkAtoms::style);
153 if (oldVal && oldVal->Type() != nsAttrValue::eCSSDeclaration) {
154 nsAttrValue attrValue;
155 nsAutoString stringValue;
156 oldVal->ToString(stringValue);
157 ParseStyleAttribute(stringValue, nullptr, attrValue, aForceInDataDoc);
158 // Don't bother going through SetInlineStyleDeclaration; we don't
159 // want to fire off mutation events or document notifications anyway
160 bool oldValueSet;
161 nsresult rv =
162 mAttrs.SetAndSwapAttr(nsGkAtoms::style, attrValue, &oldValueSet);
163 NS_ENSURE_SUCCESS(rv, rv);
166 return NS_OK;
169 nsICSSDeclaration* nsStyledElement::GetExistingStyle() {
170 Element::nsDOMSlots* slots = GetExistingDOMSlots();
171 if (!slots) {
172 return nullptr;
175 return slots->mStyle;
178 void nsStyledElement::ParseStyleAttribute(const nsAString& aValue,
179 nsIPrincipal* aMaybeScriptedPrincipal,
180 nsAttrValue& aResult,
181 bool aForceInDataDoc) {
182 Document* doc = OwnerDoc();
183 bool isNativeAnon = IsInNativeAnonymousSubtree();
185 if (!isNativeAnon &&
186 !nsStyleUtil::CSPAllowsInlineStyle(this, doc, aMaybeScriptedPrincipal, 0,
187 0, aValue, nullptr))
188 return;
190 if (aForceInDataDoc || !doc->IsLoadedAsData() || GetExistingStyle() ||
191 doc->IsStaticDocument()) {
192 bool isCSS = true; // assume CSS until proven otherwise
194 if (!isNativeAnon) { // native anonymous content always assumes CSS
195 nsAutoString styleType;
196 doc->GetHeaderData(nsGkAtoms::headerContentStyleType, styleType);
197 if (!styleType.IsEmpty()) {
198 static const char textCssStr[] = "text/css";
199 isCSS =
200 (styleType.EqualsIgnoreCase(textCssStr, sizeof(textCssStr) - 1));
204 if (isCSS &&
205 aResult.ParseStyleAttribute(aValue, aMaybeScriptedPrincipal, this)) {
206 return;
210 aResult.SetTo(aValue);