HTMLStyleElement.cpp (8495B)
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 #include "mozilla/dom/HTMLStyleElement.h" 7 8 #include "mozilla/dom/Document.h" 9 #include "mozilla/dom/FetchPriority.h" 10 #include "mozilla/dom/HTMLStyleElementBinding.h" 11 #include "mozilla/dom/ReferrerInfo.h" 12 #include "nsContentUtils.h" 13 #include "nsDOMTokenList.h" 14 #include "nsGkAtoms.h" 15 #include "nsStubMutationObserver.h" 16 #include "nsStyleConsts.h" 17 #include "nsThreadUtils.h" 18 #include "nsUnicharUtils.h" 19 20 NS_IMPL_NS_NEW_HTML_ELEMENT(Style) 21 22 namespace mozilla::dom { 23 24 HTMLStyleElement::HTMLStyleElement( 25 already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo) 26 : nsGenericHTMLElement(std::move(aNodeInfo)) { 27 AddMutationObserver(this); 28 } 29 30 HTMLStyleElement::~HTMLStyleElement() = default; 31 32 NS_IMPL_CYCLE_COLLECTION_CLASS(HTMLStyleElement) 33 34 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLStyleElement, 35 nsGenericHTMLElement) 36 tmp->LinkStyle::Traverse(cb); 37 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBlocking) 38 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END 39 40 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLStyleElement, 41 nsGenericHTMLElement) 42 tmp->LinkStyle::Unlink(); 43 NS_IMPL_CYCLE_COLLECTION_UNLINK(mBlocking) 44 NS_IMPL_CYCLE_COLLECTION_UNLINK_END 45 46 NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED(HTMLStyleElement, 47 nsGenericHTMLElement, 48 nsIMutationObserver) 49 50 NS_IMPL_ELEMENT_CLONE(HTMLStyleElement) 51 52 bool HTMLStyleElement::Disabled() const { 53 StyleSheet* ss = GetSheet(); 54 return ss && ss->Disabled(); 55 } 56 57 void HTMLStyleElement::SetDisabled(bool aDisabled) { 58 if (StyleSheet* ss = GetSheet()) { 59 ss->SetDisabled(aDisabled); 60 } 61 } 62 63 void HTMLStyleElement::CharacterDataChanged(nsIContent* aContent, 64 const CharacterDataChangeInfo&) { 65 ContentChanged(aContent); 66 } 67 68 void HTMLStyleElement::ContentAppended(nsIContent* aFirstNewContent, 69 const ContentAppendInfo&) { 70 ContentChanged(aFirstNewContent->GetParent()); 71 } 72 73 void HTMLStyleElement::ContentInserted(nsIContent* aChild, 74 const ContentInsertInfo&) { 75 ContentChanged(aChild); 76 } 77 78 void HTMLStyleElement::ContentWillBeRemoved(nsIContent* aChild, 79 const ContentRemoveInfo& aInfo) { 80 mTriggeringPrincipal = nullptr; 81 if (!nsContentUtils::IsInSameAnonymousTree(this, aChild)) { 82 return; 83 } 84 if (aInfo.mBatchRemovalState && !aInfo.mBatchRemovalState->mIsFirst) { 85 return; 86 } 87 // Make sure to run this once the removal has taken place. 88 nsContentUtils::AddScriptRunner(NS_NewRunnableFunction( 89 "HTMLStyleElement::ContentWillBeRemoved", 90 [self = RefPtr{this}] { self->UpdateStyleSheetInternal(); })); 91 } 92 93 void HTMLStyleElement::ContentChanged(nsIContent* aContent) { 94 mTriggeringPrincipal = nullptr; 95 if (nsContentUtils::IsInSameAnonymousTree(this, aContent)) { 96 (void)UpdateStyleSheetInternal(nullptr, nullptr); 97 } 98 } 99 100 nsresult HTMLStyleElement::BindToTree(BindContext& aContext, nsINode& aParent) { 101 nsresult rv = nsGenericHTMLElement::BindToTree(aContext, aParent); 102 NS_ENSURE_SUCCESS(rv, rv); 103 LinkStyle::BindToTree(); 104 return rv; 105 } 106 107 void HTMLStyleElement::UnbindFromTree(UnbindContext& aContext) { 108 RefPtr<Document> oldDoc = GetUncomposedDoc(); 109 ShadowRoot* oldShadow = GetContainingShadow(); 110 111 nsGenericHTMLElement::UnbindFromTree(aContext); 112 113 (void)UpdateStyleSheetInternal(oldDoc, oldShadow); 114 } 115 116 bool HTMLStyleElement::ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute, 117 const nsAString& aValue, 118 nsIPrincipal* aMaybeScriptedPrincipal, 119 nsAttrValue& aResult) { 120 if (aNamespaceID == kNameSpaceID_None && aAttribute == nsGkAtoms::blocking && 121 StaticPrefs::dom_element_blocking_enabled()) { 122 aResult.ParseAtomArray(aValue); 123 return true; 124 } 125 126 return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue, 127 aMaybeScriptedPrincipal, aResult); 128 } 129 130 void HTMLStyleElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName, 131 const nsAttrValue* aValue, 132 const nsAttrValue* aOldValue, 133 nsIPrincipal* aSubjectPrincipal, 134 bool aNotify) { 135 if (aNameSpaceID == kNameSpaceID_None) { 136 if (aName == nsGkAtoms::title || aName == nsGkAtoms::media || 137 aName == nsGkAtoms::type) { 138 (void)UpdateStyleSheetInternal(nullptr, nullptr, ForceUpdate::Yes); 139 } 140 } 141 142 return nsGenericHTMLElement::AfterSetAttr( 143 aNameSpaceID, aName, aValue, aOldValue, aSubjectPrincipal, aNotify); 144 } 145 146 void HTMLStyleElement::GetInnerHTML(nsAString& aInnerHTML, 147 OOMReporter& aError) { 148 if (!nsContentUtils::GetNodeTextContent(this, false, aInnerHTML, fallible)) { 149 aError.ReportOOM(); 150 } 151 } 152 153 void HTMLStyleElement::SetInnerHTMLTrusted(const nsAString& aInnerHTML, 154 nsIPrincipal* aSubjectPrincipal, 155 ErrorResult& aError) { 156 SetTextContentInternal(aInnerHTML, aSubjectPrincipal, aError); 157 } 158 159 void HTMLStyleElement::SetTextContentInternal(const nsAString& aTextContent, 160 nsIPrincipal* aScriptedPrincipal, 161 ErrorResult& aError, 162 MutationEffectOnScript) { 163 // Per spec, if we're setting text content to an empty string and don't 164 // already have any children, we should not trigger any mutation observers, or 165 // re-parse the stylesheet. 166 if (aTextContent.IsEmpty() && !GetFirstChild()) { 167 nsIPrincipal* principal = 168 mTriggeringPrincipal ? mTriggeringPrincipal.get() : NodePrincipal(); 169 if (principal == aScriptedPrincipal) { 170 return; 171 } 172 } 173 174 const bool updatesWereEnabled = mUpdatesEnabled; 175 DisableUpdates(); 176 177 aError = nsContentUtils::SetNodeTextContent(this, aTextContent, true); 178 if (updatesWereEnabled) { 179 mTriggeringPrincipal = aScriptedPrincipal; 180 (void)EnableUpdatesAndUpdateStyleSheet(nullptr); 181 } 182 } 183 184 void HTMLStyleElement::SetDevtoolsAsTriggeringPrincipal() { 185 mTriggeringPrincipal = CreateDevtoolsPrincipal(); 186 } 187 188 Maybe<LinkStyle::SheetInfo> HTMLStyleElement::GetStyleSheetInfo() { 189 if (!IsCSSMimeTypeAttributeForStyleElement(*this)) { 190 return Nothing(); 191 } 192 193 nsAutoString title; 194 nsAutoString media; 195 GetTitleAndMediaForElement(*this, title, media); 196 197 return Some(SheetInfo{ 198 *OwnerDoc(), 199 this, 200 nullptr, 201 do_AddRef(mTriggeringPrincipal), 202 MakeAndAddRef<ReferrerInfo>(*this), 203 CORS_NONE, 204 title, 205 media, 206 /* integrity = */ u""_ns, 207 /* nsStyleUtil::CSPAllowsInlineStyle takes care of nonce checking for 208 inline styles. Bug 1607011 */ 209 /* nonce = */ u""_ns, 210 HasAlternateRel::No, 211 IsInline::Yes, 212 IsExplicitlyEnabled::No, 213 FetchPriority::Auto, 214 }); 215 } 216 217 JSObject* HTMLStyleElement::WrapNode(JSContext* aCx, 218 JS::Handle<JSObject*> aGivenProto) { 219 return HTMLStyleElement_Binding::Wrap(aCx, this, aGivenProto); 220 } 221 222 nsDOMTokenList* HTMLStyleElement::Blocking() { 223 if (!mBlocking) { 224 mBlocking = 225 new nsDOMTokenList(this, nsGkAtoms::blocking, sSupportedBlockingValues); 226 } 227 return mBlocking; 228 } 229 230 bool HTMLStyleElement::IsPotentiallyRenderBlocking() { 231 return BlockingContainsRender(); 232 233 // TODO: handle implicitly potentially render blocking 234 // https://html.spec.whatwg.org/#implicitly-potentially-render-blocking 235 // A style element is implicitly potentially render-blocking if the element 236 // was created by its node document's parser. 237 } 238 239 nsresult HTMLStyleElement::CopyInnerTo(HTMLStyleElement* aDest) { 240 nsresult rv = Element::CopyInnerTo(aDest); 241 NS_ENSURE_SUCCESS(rv, rv); 242 MaybeStartCopyStyleSheetTo(aDest, aDest->OwnerDoc()); 243 return NS_OK; 244 } 245 246 } // namespace mozilla::dom