Bug 1842773 - Part 5: Add ArrayBuffer.prototype.{maxByteLength,resizable} getters...
[gecko.git] / dom / base / nsStyledElement.cpp
blob5fc7f6b3bc9f8af0090db630480399aa1a9d24c4
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/BindContext.h"
13 #include "mozilla/dom/CustomElementRegistry.h"
14 #include "mozilla/dom/ElementInlines.h"
15 #include "mozilla/dom/MutationEventBinding.h"
16 #include "mozilla/dom/MutationObservers.h"
17 #include "mozilla/InternalMutationEvent.h"
18 #include "mozilla/StaticPrefs_dom.h"
19 #include "nsDOMCSSDeclaration.h"
20 #include "nsDOMCSSAttrDeclaration.h"
21 #include "nsServiceManagerUtils.h"
22 #include "mozilla/dom/Document.h"
23 #include "mozilla/DeclarationBlock.h"
24 #include "mozilla/css/Loader.h"
25 #include "nsXULElement.h"
26 #include "nsContentUtils.h"
27 #include "nsStyleUtil.h"
29 using namespace mozilla;
30 using namespace mozilla::dom;
32 // Use the CC variant of this, even though this class does not define
33 // a new CC participant, to make QIing to the CC interfaces faster.
34 NS_IMPL_QUERY_INTERFACE_CYCLE_COLLECTION_INHERITED(nsStyledElement,
35 nsStyledElementBase,
36 nsStyledElement)
38 //----------------------------------------------------------------------
39 // nsIContent methods
41 bool nsStyledElement::ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute,
42 const nsAString& aValue,
43 nsIPrincipal* aMaybeScriptedPrincipal,
44 nsAttrValue& aResult) {
45 if (aAttribute == nsGkAtoms::style && aNamespaceID == kNameSpaceID_None) {
46 ParseStyleAttribute(aValue, aMaybeScriptedPrincipal, aResult, false);
47 return true;
50 return nsStyledElementBase::ParseAttribute(aNamespaceID, aAttribute, aValue,
51 aMaybeScriptedPrincipal, aResult);
54 void nsStyledElement::BeforeSetAttr(int32_t aNamespaceID, nsAtom* aName,
55 const nsAttrValue* aValue, bool aNotify) {
56 if (aNamespaceID == kNameSpaceID_None && aName == nsGkAtoms::style &&
57 aValue) {
58 SetMayHaveStyle();
61 return nsStyledElementBase::BeforeSetAttr(aNamespaceID, aName, aValue,
62 aNotify);
65 void nsStyledElement::InlineStyleDeclarationWillChange(
66 MutationClosureData& aData) {
67 MOZ_ASSERT(!nsContentUtils::IsSafeToRunScript());
68 MOZ_ASSERT(OwnerDoc()->UpdateNestingLevel() > 0,
69 "Should be inside document update!");
70 bool modification = false;
71 if (MayHaveStyle()) {
72 bool needsOldValue = !StaticPrefs::dom_mutation_events_cssom_disabled() &&
73 nsContentUtils::HasMutationListeners(
74 this, NS_EVENT_BITS_MUTATION_ATTRMODIFIED, this);
76 if (!needsOldValue) {
77 CustomElementDefinition* definition = GetCustomElementDefinition();
78 if (definition &&
79 definition->IsInObservedAttributeList(nsGkAtoms::style)) {
80 needsOldValue = true;
84 if (needsOldValue) {
85 nsAutoString oldValueStr;
86 modification = GetAttr(nsGkAtoms::style, oldValueStr);
87 if (modification) {
88 aData.mOldValue.emplace();
89 aData.mOldValue->SetTo(oldValueStr);
91 } else {
92 modification = HasAttr(nsGkAtoms::style);
96 aData.mModType =
97 modification ? static_cast<uint8_t>(MutationEvent_Binding::MODIFICATION)
98 : static_cast<uint8_t>(MutationEvent_Binding::ADDITION);
99 MutationObservers::NotifyAttributeWillChange(
100 this, kNameSpaceID_None, nsGkAtoms::style, aData.mModType);
102 // XXXsmaug In order to make attribute handling more consistent, consider to
103 // call BeforeSetAttr and pass kCallAfterSetAttr to
104 // SetAttrAndNotify in SetInlineStyleDeclaration.
105 // Handling of mozAutoDocUpdate may require changes in that case.
108 nsresult nsStyledElement::SetInlineStyleDeclaration(
109 DeclarationBlock& aDeclaration, MutationClosureData& aData) {
110 MOZ_ASSERT(OwnerDoc()->UpdateNestingLevel(),
111 "Should be inside document update!");
113 bool hasListeners = !StaticPrefs::dom_mutation_events_cssom_disabled() &&
114 nsContentUtils::HasMutationListeners(
115 this, NS_EVENT_BITS_MUTATION_ATTRMODIFIED, this);
117 nsAttrValue attrValue(do_AddRef(&aDeclaration), nullptr);
118 SetMayHaveStyle();
120 Document* document = GetComposedDoc();
121 mozAutoDocUpdate updateBatch(document, true);
122 return SetAttrAndNotify(kNameSpaceID_None, nsGkAtoms::style, nullptr,
123 aData.mOldValue.ptrOr(nullptr), attrValue, nullptr,
124 aData.mModType, hasListeners, true,
125 kDontCallAfterSetAttr, document, updateBatch);
128 // ---------------------------------------------------------------
129 // Others and helpers
131 nsICSSDeclaration* nsStyledElement::Style() {
132 Element::nsDOMSlots* slots = DOMSlots();
134 if (!slots->mStyle) {
135 // Just in case...
136 ReparseStyleAttribute(/* aForceInDataDoc */ true);
138 slots->mStyle = new nsDOMCSSAttributeDeclaration(this, false);
139 SetMayHaveStyle();
142 return slots->mStyle;
145 nsresult nsStyledElement::ReparseStyleAttribute(bool aForceInDataDoc) {
146 if (!MayHaveStyle()) {
147 return NS_OK;
149 const nsAttrValue* oldVal = mAttrs.GetAttr(nsGkAtoms::style);
150 if (oldVal && oldVal->Type() != nsAttrValue::eCSSDeclaration) {
151 nsAttrValue attrValue;
152 nsAutoString stringValue;
153 oldVal->ToString(stringValue);
154 ParseStyleAttribute(stringValue, nullptr, attrValue, aForceInDataDoc);
155 // Don't bother going through SetInlineStyleDeclaration; we don't
156 // want to fire off mutation events or document notifications anyway
157 bool oldValueSet;
158 nsresult rv =
159 mAttrs.SetAndSwapAttr(nsGkAtoms::style, attrValue, &oldValueSet);
160 NS_ENSURE_SUCCESS(rv, rv);
163 return NS_OK;
166 nsICSSDeclaration* nsStyledElement::GetExistingStyle() {
167 Element::nsDOMSlots* slots = GetExistingDOMSlots();
168 if (!slots) {
169 return nullptr;
172 return slots->mStyle;
175 void nsStyledElement::ParseStyleAttribute(const nsAString& aValue,
176 nsIPrincipal* aMaybeScriptedPrincipal,
177 nsAttrValue& aResult,
178 bool aForceInDataDoc) {
179 Document* doc = OwnerDoc();
180 bool isNativeAnon = IsInNativeAnonymousSubtree();
182 if (!isNativeAnon &&
183 !nsStyleUtil::CSPAllowsInlineStyle(this, doc, aMaybeScriptedPrincipal, 0,
184 1, aValue, nullptr))
185 return;
187 if (aForceInDataDoc || !doc->IsLoadedAsData() || GetExistingStyle() ||
188 doc->IsStaticDocument()) {
189 bool isCSS = true; // assume CSS until proven otherwise
191 if (!isNativeAnon) { // native anonymous content always assumes CSS
192 nsAutoString styleType;
193 doc->GetHeaderData(nsGkAtoms::headerContentStyleType, styleType);
194 if (!styleType.IsEmpty()) {
195 isCSS = StringBeginsWith(styleType, u"text/css"_ns,
196 nsASCIICaseInsensitiveStringComparator);
200 if (isCSS &&
201 aResult.ParseStyleAttribute(aValue, aMaybeScriptedPrincipal, this)) {
202 return;
206 aResult.SetTo(aValue);
209 nsresult nsStyledElement::BindToTree(BindContext& aContext, nsINode& aParent) {
210 nsresult rv = nsStyledElementBase::BindToTree(aContext, aParent);
211 NS_ENSURE_SUCCESS(rv, rv);
213 if (HasAttr(nsGkAtoms::autofocus) && aContext.AllowsAutoFocus() &&
214 (!IsSVGElement() || IsFocusableWithoutStyle())) {
215 aContext.OwnerDoc().ElementWithAutoFocusInserted(this);
218 return NS_OK;