Bug Summary

File:Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/css/StyleSheetContents.cpp
Warning:line 568, column 23
Local variable 'cachedResource' is uncounted and unsafe

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple arm64-apple-ios26.2.0-simulator -O3 -Wundef-prefix=TARGET_OS_ -Werror=undef-prefix -Wdeprecated-objc-isa-usage -Werror=deprecated-objc-isa-usage -Werror=implicit-function-declaration -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name UnifiedSource150.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=osx -analyzer-checker=security.insecureAPI.decodeValueOfObjCType -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -mframe-pointer=non-leaf -ffp-contract=on -fno-rounding-math -target-sdk-version=26.2 -fdepfile-entry=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/SDKSettings.json -fcompatibility-qualified-id-block-type-checking -fvisibility-inlines-hidden-static-local-var -fno-modulemap-allow-subdirectory-search -fdefine-target-os-macros -enable-tlsdesc -target-cpu apple-m1 -target-feature +v8.4a -target-feature +aes -target-feature +altnzcv -target-feature +ccdp -target-feature +ccpp -target-feature +complxnum -target-feature +crc -target-feature +dotprod -target-feature +flagm -target-feature +fp-armv8 -target-feature +fp16fml -target-feature +fptoint -target-feature +fullfp16 -target-feature +jsconv -target-feature +lse -target-feature +neon -target-feature +pauth -target-feature +perfmon -target-feature +predres -target-feature +ras -target-feature +rcpc -target-feature +rdm -target-feature +sb -target-feature +sha2 -target-feature +sha3 -target-feature +specrestrict -target-feature +ssbs -target-abi darwinpcs -dwarf-ext-refs -fmodule-format=obj -debug-info-kind=standalone -dwarf-version=5 -debugger-tuning=lldb -fdebug-compilation-dir=/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore -target-linker-version 1230.1 -fcoverage-compilation-dir=/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore -resource-dir /Users/buildbot/Library/Developer/Toolchains/swift-webkit.xctoolchain/usr/lib/clang/21 -dependency-file /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/scan-build-output/StaticAnalyzer/WebCore/WebCore/normal/arm64/UnifiedSource150.d -skip-unused-modulemap-deps -MT dependencies -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk -iquote /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release-iphonesimulator/WebCore.build/WebCore-generated-files.hmap -iquote /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release-iphonesimulator/WebCore.build/WebCore-project-headers.hmap -isystem /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/PAL/ThirdParty/dav1d/include -isystem /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/SDKAdditions/usr/include -iframework /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/SDKAdditions/System/Library/Frameworks -iframework /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitLibraries/SDKs/iphonesimulator26.0-additions.sdk/System/Library/PrivateFrameworks -iframework /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/System/Library/Frameworks -include-pch /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/PrecompiledHeaders/SharedPrecompiledHeaders/11721353671419897710/WebCorePrefix.h.gch -D _LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_EXTENSIVE -D NDEBUG -D BUILDING_WEBKIT -D GL_SILENCE_DEPRECATION=1 -D GLES_SILENCE_DEPRECATION=1 -D __clang_analyzer__ -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release-iphonesimulator/WebCore.build/WebCore-own-target-headers.hmap -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release-iphonesimulator/WebCore.build/WebCore-all-target-headers.hmap -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/include -I PAL -I ForwardingHeaders -I /usr/include/libxslt -I /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/usr/include/libxml2 -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/DerivedSources/WebCore -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/usr/local/include -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/usr/local/include/WebKitAdditions -I /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/usr/local/include/WebKitAdditions -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/usr/local/include -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitLibraries/SDKs/iphonesimulator26.0-additions.sdk/usr/local/include -I /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/usr/local/include -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/usr/local/include/webrtc -I /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/usr/local/include/webrtc -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/usr/local/include/webm -I /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/usr/local/include/webm -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/PAL.build/PAL.build/DerivedSources -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/PAL.build/Release-iphonesimulator/PAL.build/DerivedSources -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release-iphonesimulator/WebCore.build/DerivedSources-normal/arm64 -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release-iphonesimulator/WebCore.build/DerivedSources/arm64 -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release-iphonesimulator/WebCore.build/DerivedSources -F/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator -F/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator -I/usr/local/include -stdlib=libc++ -internal-isystem /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/usr/include/c++/v1 -internal-isystem /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/usr/local/include -internal-isystem /Users/buildbot/Library/Developer/Toolchains/swift-webkit.xctoolchain/usr/lib/clang/21/include -internal-externc-isystem /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/usr/include -internal-iframework /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/System/Library/Frameworks -internal-iframework /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/System/Library/SubFrameworks -internal-iframework /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/Library/Frameworks -Wno-trigraphs -Werror -Wno-missing-field-initializers -Wmissing-prototypes -Wunreachable-code -Wnon-virtual-dtor -Wno-overloaded-virtual -Wno-exit-time-destructors -Wno-missing-braces -Wparentheses -Wswitch -Wunused-function -Wno-unused-label -Wno-unused-parameter -Wunused-variable -Wunused-value -Wempty-body -Wuninitialized -Wno-unknown-pragmas -Wno-shadow -Wno-four-char-constants -Wno-conversion -Wconstant-conversion -Wint-conversion -Wbool-conversion -Wenum-conversion -Wno-float-conversion -Wnon-literal-null-conversion -Wobjc-literal-conversion -Wsign-compare -Wno-shorten-64-to-32 -Wnewline-eof -Wno-c++11-extensions -Wno-implicit-fallthrough -Wdeprecated-declarations -Winvalid-offsetof -Wno-sign-conversion -Winfinite-recursion -Wmove -Wcomma -Wblock-capture-autoreleasing -Wstrict-prototypes -Wrange-loop-analysis -Wno-semicolon-before-method-body -Wall -Wc99-designator -Wconditional-uninitialized -Wextra -Wdeprecated-enum-enum-conversion -Wdeprecated-enum-float-conversion -Wenum-float-conversion -Wfinal-dtor-non-final-class -Wformat=2 -Wmisleading-indentation -Wpointer-to-int-cast -Wreorder-init-list -Wundef -Wunused-but-set-variable -Wvla -Werror=unguarded-availability -Wno-elaborated-enum-base -Wcast-qual -Wchar-subscripts -Wextra-tokens -Winit-self -Wmissing-noreturn -Wpacked -Wpointer-arith -Wredundant-decls -Wwrite-strings -Wexit-time-destructors -Wglobal-constructors -Wtautological-compare -Wimplicit-fallthrough -Wvla -Wno-unknown-warning-option -Wliteral-conversion -Wthread-safety -Wno-profile-instr-out-of-date -Wno-profile-instr-unprofiled -Wno-backend-plugin -Wunsafe-buffer-usage -std=c++2b -fdeprecated-macro -ferror-limit 19 -fmacro-backtrace-limit=0 -fvisibility=hidden -fvisibility-inlines-hidden -stack-protector 1 -fblocks -fencode-extended-block-signature -fno-rtti -fregister-global-dtors-with-atexit -fgnuc-version=4.2.1 -fno-cxx-modules -fno-implicit-modules -fskip-odr-check-in-gmf -fpascal-strings -fmax-type-align=16 -fdiagnostics-show-note-include-stack -vectorize-loops -vectorize-slp -fsafe-buffer-usage-suggestions -analyzer-output=html -analyzer-config report-in-main-source-file=true -analyzer-config nullability:NoDiagnoseCallsToSystemHeaders=true -analyzer-checker optin.osx.cocoa.localizability.NonLocalizedStringChecker -analyzer-checker security.insecureAPI.UncheckedReturn -analyzer-checker security.insecureAPI.getpw -analyzer-checker security.insecureAPI.gets -analyzer-checker security.insecureAPI.mkstemp -analyzer-checker security.insecureAPI.mktemp -analyzer-disable-checker security.insecureAPI.rand -analyzer-disable-checker security.insecureAPI.strcpy -analyzer-checker security.insecureAPI.vfork -analyzer-disable-checker alpha,apiModeling,core,cplusplus,deadcode,debug,fuchsia,nullability,optin,osx,security,unix,webkit -analyzer-checker alpha.webkit.ForwardDeclChecker,alpha.webkit.MemoryUnsafeCastChecker,alpha.webkit.NoDeleteChecker,alpha.webkit.NoUncheckedPtrMemberChecker,alpha.webkit.NoUnretainedMemberChecker,alpha.webkit.RetainPtrCtorAdoptChecker,alpha.webkit.UncheckedCallArgsChecker,alpha.webkit.UncheckedLocalVarsChecker,alpha.webkit.UncountedCallArgsChecker,alpha.webkit.UncountedLocalVarsChecker,alpha.webkit.UnretainedCallArgsChecker,alpha.webkit.UnretainedLambdaCapturesChecker,alpha.webkit.UnretainedLocalVarsChecker,webkit.NoUncountedMemberChecker,webkit.RefCntblBaseVirtualDtor,webkit.UncountedLambdaCapturesChecker -analyzer-config max-nodes=10000000 -analyzer-config verbose-report-filename=true -fdwarf2-cfi-asm -o /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/scan-build-output/StaticAnalyzer/WebCore/WebCore/normal/arm64/UnifiedSource150.plist -x c++ /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/DerivedSources/WebCore/unified-sources/UnifiedSource150.cpp
1/*
2 * (C) 1999-2003 Lars Knoll (knoll@kde.org)
3 * Copyright (C) 2004-2025 Apple Inc. All rights reserved.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public License
16 * along with this library; see the file COPYING.LIB. If not, write to
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21#include "config.h"
22#include "StyleSheetContents.h"
23
24#include "CSSImportRule.h"
25#include "CSSParser.h"
26#include "CSSStyleSheet.h"
27#include "CachePolicy.h"
28#include "CachedCSSStyleSheet.h"
29#include "CommonAtomStrings.h"
30#include "DocumentPage.h"
31#include "FrameConsoleClient.h"
32#include "FrameDestructionObserverInlines.h"
33#include "FrameLoader.h"
34#include "LocalFrame.h"
35#include "MediaList.h"
36#include "NodeDocument.h"
37#include "OriginAccessPatterns.h"
38#include "ResourceLoadInfo.h"
39#include "RuleSet.h"
40#include "SecurityOrigin.h"
41#include "StyleProperties.h"
42#include "StyleRule.h"
43#include "StyleRuleImport.h"
44#include "UserContentProvider.h"
45#include <wtf/Deque.h>
46#include <wtf/NeverDestroyed.h>
47#include <wtf/Ref.h>
48#include <wtf/text/MakeString.h>
49
50#if ENABLE(CONTENT_EXTENSIONS)(defined 1 && 1)
51#include "ContentRuleListResults.h"
52#include "UserContentController.h"
53#endif
54
55namespace WebCore {
56
57// Rough size estimate for the memory cache.
58unsigned StyleSheetContents::estimatedSizeInBytes() const
59{
60 // Note that this does not take into account size of the strings hanging from various objects.
61 // The assumption is that nearly all of of them are atoms that would exist anyway.
62 unsigned size = sizeof(*this);
63
64 // FIXME: This ignores the children of media and region rules.
65 // Most rules are StyleRules.
66 size += ruleCount() * StyleRule::averageSizeInBytes();
67
68 for (unsigned i = 0; i < m_importRules.size(); ++i) {
69 if (RefPtr sheet = m_importRules[i]->styleSheet())
70 size += sheet->estimatedSizeInBytes();
71 }
72 return size;
73}
74
75StyleSheetContents::StyleSheetContents(StyleRuleImport* ownerRule, const String& originalURL, const CSSParserContext& context)
76 : m_ownerRule(ownerRule)
77 , m_originalURL(originalURL)
78 , m_defaultNamespace(starAtom())
79 , m_isUserStyleSheet(ownerRule && ownerRule->parentStyleSheet() && ownerRule->parentStyleSheet()->isUserStyleSheet())
80 , m_parserContext(context)
81{
82}
83
84StyleSheetContents::StyleSheetContents(const StyleSheetContents& o)
85 : m_originalURL(o.m_originalURL)
86 , m_encodingFromCharsetRule(o.m_encodingFromCharsetRule)
87 , m_layerRulesBeforeImportRules(o.m_layerRulesBeforeImportRules.size())
88 , m_importRules(o.m_importRules.size())
89 , m_namespaceRules(o.m_namespaceRules.size())
90 , m_childRules(o.m_childRules.size())
91 , m_namespaces(o.m_namespaces)
92 , m_defaultNamespace(o.m_defaultNamespace)
93 , m_isUserStyleSheet(o.m_isUserStyleSheet)
94 , m_loadCompleted(true)
95 , m_hasSyntacticallyValidCSSHeader(o.m_hasSyntacticallyValidCSSHeader)
96 , m_usesStyleBasedEditability(o.m_usesStyleBasedEditability)
97 , m_hasNestingRulesCache(o.m_hasNestingRulesCache)
98 , m_parserContext(o.m_parserContext)
99{
100 ASSERT(o.isCacheable())((void)0);
101
102 // FIXME: Copy import rules.
103 ASSERT(o.m_importRules.isEmpty())((void)0);
104
105 // FIXME: Copy namespace rules.
106 ASSERT(o.m_namespaceRules.isEmpty())((void)0);
107
108 for (size_t i = 0; i < m_layerRulesBeforeImportRules.size(); ++i)
109 m_layerRulesBeforeImportRules[i] = o.m_layerRulesBeforeImportRules[i]->copy();
110
111 for (size_t i = 0; i < m_childRules.size(); ++i)
112 m_childRules[i] = o.m_childRules[i]->copy();
113}
114
115StyleSheetContents::~StyleSheetContents()
116{
117 clearRules();
118}
119
120bool StyleSheetContents::isCacheable() const
121{
122 // FIXME: Support copying import rules.
123 if (!m_importRules.isEmpty())
124 return false;
125 // FIXME: Support copying namespace rules.
126 if (!m_namespaceRules.isEmpty())
127 return false;
128 // FIXME: Support cached stylesheets in import rules.
129 if (m_ownerRule)
130 return false;
131 // This would require dealing with multiple clients for load callbacks.
132 if (!m_loadCompleted)
133 return false;
134 if (m_didLoadErrorOccur)
135 return false;
136 // It is not the original sheet anymore.
137 if (m_isMutable)
138 return false;
139 // If the header is valid we are not going to need to check the SecurityOrigin.
140 // FIXME: Valid mime type avoids the check too.
141 if (!m_hasSyntacticallyValidCSSHeader)
142 return false;
143 if (hasNestingRules())
144 return false;
145 return true;
146}
147
148bool StyleSheetContents::isCacheableWithNoBaseURLDependency() const
149{
150 if (!isCacheable())
151 return false;
152 if (mayDependOnBaseURL())
153 return false;
154 return true;
155}
156
157void StyleSheetContents::parserAppendRule(Ref<StyleRuleBase>&& rule)
158{
159 ASSERT(!rule->isCharsetRule())((void)0);
160
161 if (auto* layerRule = dynamicDowncast<StyleRuleLayer>(rule.get()); layerRule && m_importRules.isEmpty() && m_childRules.isEmpty() && m_namespaceRules.isEmpty()) {
162 if (layerRule->isStatement()) {
163 m_layerRulesBeforeImportRules.append(*layerRule);
164 return;
165 }
166 }
167
168 if (auto* importRule = dynamicDowncast<StyleRuleImport>(rule.get())) {
169 // Parser enforces that @import rules come before anything else except @charset.
170 ASSERT(m_childRules.isEmpty())((void)0);
171 m_importRules.append(*importRule);
172 m_importRules.last()->setParentStyleSheet(this);
173 m_importRules.last()->requestStyleSheet();
174 return;
175 }
176
177 if (auto* namespaceRule = dynamicDowncast<StyleRuleNamespace>(rule.get())) {
178 // Parser enforces that @namespace rules come before all rules other than
179 // import/charset rules
180 ASSERT(m_childRules.isEmpty())((void)0);
181 parserAddNamespace(namespaceRule->prefix(), namespaceRule->uri());
182 m_namespaceRules.append(*namespaceRule);
183 return;
184 }
185
186 // NOTE: The selector list has to fit into RuleData. <http://webkit.org/b/118369>
187 // We don't support nested rules with too many selectors
188 if (auto* styleRuleWithNesting = dynamicDowncast<StyleRuleWithNesting>(rule.get())) {
189 if (styleRuleWithNesting->originalSelectorList().componentCount() > Style::RuleData::maximumSelectorComponentCount)
190 return;
191 }
192
193 if (auto* styleRule = dynamicDowncast<StyleRule>(rule.get()); styleRule && styleRule->selectorList().componentCount() > Style::RuleData::maximumSelectorComponentCount) {
194 // If we're adding a rule with a huge number of selectors, split it up into multiple rules
195 m_childRules.appendVector(styleRule->splitIntoMultipleRulesWithMaximumSelectorComponentCount(Style::RuleData::maximumSelectorComponentCount));
196 return;
197 }
198
199 m_childRules.append(WTF::move(rule));
200}
201
202StyleRuleBase* StyleSheetContents::ruleAt(unsigned index) const
203{
204 ASSERT_WITH_SECURITY_IMPLICATION(index < ruleCount())((void)0);
205
206 unsigned childVectorIndex = index;
207 if (childVectorIndex < m_layerRulesBeforeImportRules.size())
208 return m_layerRulesBeforeImportRules[childVectorIndex].ptr();
209
210 childVectorIndex -= m_layerRulesBeforeImportRules.size();
211
212 if (childVectorIndex < m_importRules.size())
213 return m_importRules[childVectorIndex].ptr();
214
215 childVectorIndex -= m_importRules.size();
216
217 if (childVectorIndex < m_namespaceRules.size())
218 return m_namespaceRules[childVectorIndex].ptr();
219
220 childVectorIndex -= m_namespaceRules.size();
221
222 return m_childRules[childVectorIndex].ptr();
223}
224
225unsigned StyleSheetContents::ruleCount() const
226{
227 unsigned result = 0;
228 result += m_layerRulesBeforeImportRules.size();
229 result += m_importRules.size();
230 result += m_namespaceRules.size();
231 result += m_childRules.size();
232 return result;
233}
234
235void StyleSheetContents::clearCharsetRule()
236{
237 m_encodingFromCharsetRule = String();
238}
239
240void StyleSheetContents::clearRules()
241{
242 for (unsigned i = 0; i < m_importRules.size(); ++i) {
243 ASSERT(m_importRules.at(i)->parentStyleSheet() == this)((void)0);
244 m_importRules[i]->clearParentStyleSheet();
245 }
246 m_layerRulesBeforeImportRules.clear();
247 m_importRules.clear();
248 m_namespaceRules.clear();
249 m_childRules.clear();
250 clearCharsetRule();
251}
252
253void StyleSheetContents::parserSetEncodingFromCharsetRule(const String& encoding)
254{
255 // Parser enforces that there is ever only one @charset.
256 ASSERT(m_encodingFromCharsetRule.isNull())((void)0);
257 m_encodingFromCharsetRule = encoding;
258}
259
260bool StyleSheetContents::wrapperInsertRule(Ref<StyleRuleBase>&& rule, unsigned index)
261{
262 ASSERT(m_isMutable)((void)0);
263 ASSERT_WITH_SECURITY_IMPLICATION(index <= ruleCount())((void)0);
264 // Parser::parseRule doesn't currently allow @charset so we don't need to deal with it.
265 ASSERT(!rule->isCharsetRule())((void)0);
266
267 // Maybe the insert will be legal if we treat early layer statement rules as normal child rules?
268 auto shouldMoveLayerRulesBeforeImportToNormalChildRules = [&] {
269 if (index >= m_layerRulesBeforeImportRules.size())
270 return false;
271 if (!m_importRules.isEmpty() || !m_namespaceRules.isEmpty())
272 return false;
273 auto* layerRule = dynamicDowncast<StyleRuleLayer>(rule.get());
274 bool isLayerStatement = layerRule && layerRule->isStatement();
275 return !rule->isImportRule() && !rule->isNamespaceRule() && !isLayerStatement;
276 };
277
278 if (shouldMoveLayerRulesBeforeImportToNormalChildRules())
279 m_childRules.insertVector(0, std::exchange(m_layerRulesBeforeImportRules, { }));
280
281 unsigned childVectorIndex = index;
282 if (childVectorIndex < m_layerRulesBeforeImportRules.size() || (childVectorIndex == m_layerRulesBeforeImportRules.size() && is<StyleRuleLayer>(rule))) {
283 auto* layerRule = dynamicDowncast<StyleRuleLayer>(rule.get());
284 if (!layerRule)
285 return false;
286 if (layerRule->isStatement()) {
287 m_layerRulesBeforeImportRules.insert(childVectorIndex, *layerRule);
288 return true;
289 }
290 if (childVectorIndex < m_layerRulesBeforeImportRules.size())
291 return false;
292 }
293 childVectorIndex -= m_layerRulesBeforeImportRules.size();
294
295 if (childVectorIndex < m_importRules.size() || (childVectorIndex == m_importRules.size() && rule->isImportRule())) {
296 // Inserting non-import rule before @import is not allowed.
297 auto* importRule = dynamicDowncast<StyleRuleImport>(rule.get());
298 if (!importRule)
299 return false;
300 m_importRules.insert(childVectorIndex, *importRule);
301 m_importRules[childVectorIndex]->setParentStyleSheet(this);
302 m_importRules[childVectorIndex]->requestStyleSheet();
303 // FIXME: Stylesheet doesn't actually change meaningfully before the imported sheets are loaded.
304 return true;
305 }
306 // Inserting @import rule after a non-import rule is not allowed.
307 if (is<StyleRuleImport>(rule))
308 return false;
309 childVectorIndex -= m_importRules.size();
310
311 if (childVectorIndex < m_namespaceRules.size() || (childVectorIndex == m_namespaceRules.size() && rule->isNamespaceRule())) {
312 // Inserting non-namespace rules other than import and layer statement rules before @namespace is
313 // not allowed.
314 auto* namespaceRule = dynamicDowncast<StyleRuleNamespace>(rule.get());
315 if (!namespaceRule)
316 return false;
317 // Inserting @namespace rule when rules other than import/namespace/charset
318 // are present is not allowed.
319 if (!m_childRules.isEmpty() || !m_layerRulesBeforeImportRules.isEmpty())
320 return false;
321
322 m_namespaceRules.insert(index, *namespaceRule);
323
324 // For now to be compatible with IE and Firefox if a namespace rule with the same
325 // prefix is added, it overwrites previous ones.
326 // FIXME: The eventual correct behavior would be to ensure that the last value in
327 // the list wins.
328 parserAddNamespace(namespaceRule->prefix(), namespaceRule->uri());
329 return true;
330 }
331 if (is<StyleRuleNamespace>(rule))
332 return false;
333 childVectorIndex -= m_namespaceRules.size();
334
335 // If the number of selectors would overflow RuleData, we drop the operation.
336 if (auto* styleRuleWithNesting = dynamicDowncast<StyleRuleWithNesting>(rule.get())) {
337 if (styleRuleWithNesting->originalSelectorList().componentCount() > Style::RuleData::maximumSelectorComponentCount)
338 return false;
339 }
340 if (auto* styleRule = dynamicDowncast<StyleRule>(rule.get())) {
341 if (styleRule->selectorList().componentCount() > Style::RuleData::maximumSelectorComponentCount)
342 return false;
343 }
344
345 m_childRules.insert(childVectorIndex, WTF::move(rule));
346 return true;
347}
348
349bool StyleSheetContents::wrapperDeleteRule(unsigned index)
350{
351 ASSERT(m_isMutable)((void)0);
352 ASSERT_WITH_SECURITY_IMPLICATION(index < ruleCount())((void)0);
353
354 unsigned childVectorIndex = index;
355 if (childVectorIndex < m_layerRulesBeforeImportRules.size()) {
356 m_layerRulesBeforeImportRules.removeAt(childVectorIndex);
357 return true;
358 }
359 childVectorIndex -= m_layerRulesBeforeImportRules.size();
360
361 if (childVectorIndex < m_importRules.size()) {
362 m_importRules[childVectorIndex]->cancelLoad();
363 m_importRules[childVectorIndex]->clearParentStyleSheet();
364 m_importRules.removeAt(childVectorIndex);
365 return true;
366 }
367 childVectorIndex -= m_importRules.size();
368
369 if (childVectorIndex < m_namespaceRules.size()) {
370 // Deleting @namespace rule when list contains anything other than @import or @namespace rules is not allowed.
371 if (!m_childRules.isEmpty())
372 return false;
373 m_namespaceRules.removeAt(childVectorIndex);
374 return true;
375 }
376 childVectorIndex -= m_namespaceRules.size();
377
378 m_childRules.removeAt(childVectorIndex);
379 return true;
380}
381
382void StyleSheetContents::parserAddNamespace(const AtomString& prefix, const AtomString& uri)
383{
384 ASSERT(!uri.isNull())((void)0);
385 if (prefix.isNull()) {
386 m_defaultNamespace = uri;
387 return;
388 }
389 PrefixNamespaceURIMap::AddResult result = m_namespaces.add(prefix, uri);
390 if (result.isNewEntry)
391 return;
392 result.iterator->value = uri;
393}
394
395const AtomString& StyleSheetContents::namespaceURIFromPrefix(const AtomString& prefix)
396{
397 PrefixNamespaceURIMap::const_iterator it = m_namespaces.find(prefix);
398 if (it == m_namespaces.end())
399 return nullAtom();
400 return it->value;
401}
402
403bool StyleSheetContents::parseAuthorStyleSheet(const CachedCSSStyleSheet* cachedStyleSheet, const SecurityOrigin* securityOrigin)
404{
405 bool isSameOriginRequest = securityOrigin && securityOrigin->canRequest(baseURL(), OriginAccessPatternsForWebProcess::singleton());
406 CachedCSSStyleSheet::MIMETypeCheckHint mimeTypeCheckHint = isStrictParserMode(m_parserContext.mode) || !isSameOriginRequest ? CachedCSSStyleSheet::MIMETypeCheckHint::Strict : CachedCSSStyleSheet::MIMETypeCheckHint::Lax;
407 bool hasValidMIMEType = true;
408 bool hasHTTPStatusOK = true;
409 String sheetText = cachedStyleSheet->sheetText(mimeTypeCheckHint, &hasValidMIMEType, &hasHTTPStatusOK);
410
411 if (!hasHTTPStatusOK) {
412 ASSERT(sheetText.isNull())((void)0);
413 return false;
414 }
415 if (!hasValidMIMEType) {
416 ASSERT(sheetText.isNull())((void)0);
417 if (RefPtr document = singleOwnerDocument()) {
418 if (RefPtr frame = document->frame()) {
419 if (isStrictParserMode(m_parserContext.mode))
420 frame->console().addMessage(MessageSource::Security, MessageLevel::Error, makeString("Did not parse stylesheet at '"_s, cachedStyleSheet->url().stringCenterEllipsizedToLength(), "' because non CSS MIME types are not allowed in strict mode."_s));
421 else if (!cachedStyleSheet->mimeTypeAllowedByNosniff())
422 frame->console().addMessage(MessageSource::Security, MessageLevel::Error, makeString("Did not parse stylesheet at '"_s, cachedStyleSheet->url().stringCenterEllipsizedToLength(), "' because non CSS MIME types are not allowed when 'X-Content-Type-Options: nosniff' is given."_s));
423 else
424 frame->console().addMessage(MessageSource::Security, MessageLevel::Error, makeString("Did not parse stylesheet at '"_s, cachedStyleSheet->url().stringCenterEllipsizedToLength(), "' because non CSS MIME types are not allowed for cross-origin stylesheets."_s));
425 }
426 }
427 return false;
428 }
429
430 CSSParser::parseStyleSheet(sheetText, parserContext(), *this);
431 return true;
432}
433
434bool StyleSheetContents::parseString(const String& sheetText)
435{
436 CSSParser::parseStyleSheet(sheetText, parserContext(), *this);
437 return true;
438}
439
440bool StyleSheetContents::isLoading() const
441{
442 for (unsigned i = 0; i < m_importRules.size(); ++i) {
443 if (m_importRules[i]->isLoading())
444 return true;
445 }
446 return false;
447}
448
449void StyleSheetContents::checkLoaded()
450{
451 if (isLoading())
452 return;
453
454 Ref<StyleSheetContents> protectedThis(*this);
455 RefPtr parentSheet = parentStyleSheet();
456 if (parentSheet) {
457 parentSheet->checkLoaded();
458 m_loadCompleted = true;
459 return;
460 }
461 RefPtr<Node> ownerNode = singleOwnerNode();
462 if (!ownerNode) {
463 m_loadCompleted = true;
464 return;
465 }
466 m_loadCompleted = ownerNode->sheetLoaded();
467 if (m_loadCompleted)
468 ownerNode->notifyLoadedSheetAndAllCriticalSubresources(m_didLoadErrorOccur);
469}
470
471void StyleSheetContents::notifyLoadedSheet(const CachedCSSStyleSheet* sheet)
472{
473 ASSERT(sheet)((void)0);
474 m_didLoadErrorOccur |= sheet->errorOccurred();
475 m_didLoadErrorOccur |= !sheet->mimeTypeAllowedByNosniff();
476}
477
478void StyleSheetContents::startLoadingDynamicSheet()
479{
480 if (RefPtr owner = singleOwnerNode())
481 owner->startLoadingDynamicSheet();
482}
483
484StyleSheetContents* StyleSheetContents::rootStyleSheet() const
485{
486 const StyleSheetContents* root = this;
487 while (root->parentStyleSheet())
488 root = root->parentStyleSheet();
489 return const_cast<StyleSheetContents*>(root);
490}
491
492Node* StyleSheetContents::singleOwnerNode() const
493{
494 RefPtr root = rootStyleSheet();
495 if (!root)
496 return nullptr;
497 if (root->m_clients.isEmpty())
498 return nullptr;
499 ASSERT(root->m_clients.size() == 1)((void)0);
500 return root->m_clients[0]->ownerNode();
501}
502
503Document* StyleSheetContents::singleOwnerDocument() const
504{
505 RefPtr ownerNode = singleOwnerNode();
506 return ownerNode ? &ownerNode->document() : nullptr;
507}
508
509static bool traverseRulesInVector(const Vector<Ref<StyleRuleBase>>& rules, NOESCAPE[[clang::noescape]] const Function<bool(const StyleRuleBase&)>& handler)
510{
511 for (auto& rule : rules) {
512 if (handler(rule))
513 return true;
514 if (RefPtr styleRuleWithNesting = dynamicDowncast<StyleRuleWithNesting>(rule.ptr())) {
515 if (traverseRulesInVector(styleRuleWithNesting->nestedRules(), handler))
516 return true;
517 }
518 RefPtr groupRule = dynamicDowncast<StyleRuleGroup>(rule.get());
519 if (!groupRule)
520 continue;
521 if (traverseRulesInVector(groupRule->childRules(), handler))
522 return true;
523 }
524 return false;
525}
526
527bool StyleSheetContents::traverseRules(NOESCAPE[[clang::noescape]] const Function<bool(const StyleRuleBase&)>& handler) const
528{
529 for (auto& importRule : m_importRules) {
530 if (handler(importRule))
531 return true;
532 RefPtr importedStyleSheet = importRule->styleSheet();
533 if (importedStyleSheet && importedStyleSheet->traverseRules(handler))
534 return true;
535 }
536 return traverseRulesInVector(m_childRules, handler);
537}
538
539bool StyleSheetContents::hasNestingRules() const
540{
541 if (m_hasNestingRulesCache)
542 return *m_hasNestingRulesCache;
543
544 m_hasNestingRulesCache = traverseRulesInVector(m_childRules, [&] (const auto& rule) {
545 if (rule.isStyleRuleWithNesting())
546 return true;
547 if (rule.isNestedDeclarationsRule())
548 return true;
549 return false;
550 });
551
552 return *m_hasNestingRulesCache;
553}
554
555bool StyleSheetContents::traverseSubresources(NOESCAPE[[clang::noescape]] const Function<bool(const CachedResource&)>& handler) const
556{
557 return traverseRules([&] (const StyleRuleBase& rule) {
558 switch (rule.type()) {
559 case StyleRuleType::Style:
560 return uncheckedDowncast<StyleRule>(rule).properties().traverseSubresources(handler);
561 case StyleRuleType::StyleWithNesting:
562 return uncheckedDowncast<StyleRuleWithNesting>(rule).properties().traverseSubresources(handler);
563 case StyleRuleType::NestedDeclarations:
564 return uncheckedDowncast<StyleRuleNestedDeclarations>(rule).properties().traverseSubresources(handler);
565 case StyleRuleType::FontFace:
566 return uncheckedDowncast<StyleRuleFontFace>(rule).properties().traverseSubresources(handler);
567 case StyleRuleType::Import:
568 if (auto* cachedResource = uncheckedDowncast<StyleRuleImport>(rule).cachedCSSStyleSheet())
Local variable 'cachedResource' is uncounted and unsafe
569 return handler(*cachedResource);
570 return false;
571 case StyleRuleType::CounterStyle:
572 return m_parserContext.counterStyleAtRuleImageSymbolsEnabled;
573 case StyleRuleType::Media:
574 case StyleRuleType::Page:
575 case StyleRuleType::Keyframes:
576 case StyleRuleType::Namespace:
577 case StyleRuleType::Charset:
578 case StyleRuleType::Keyframe:
579 case StyleRuleType::Supports:
580 case StyleRuleType::LayerBlock:
581 case StyleRuleType::LayerStatement:
582 case StyleRuleType::Container:
583 case StyleRuleType::FontFeatureValues:
584 case StyleRuleType::FontFeatureValuesBlock:
585 case StyleRuleType::FontPaletteValues:
586 case StyleRuleType::Margin:
587 case StyleRuleType::Property:
588 case StyleRuleType::Scope:
589 case StyleRuleType::StartingStyle:
590 case StyleRuleType::ViewTransition:
591 case StyleRuleType::PositionTry:
592 case StyleRuleType::Function:
593 case StyleRuleType::FunctionDeclarations:
594 return false;
595 };
596 ASSERT_NOT_REACHED()((void)0);
597 return false;
598 });
599}
600
601bool StyleSheetContents::subresourcesAllowReuse(CachePolicy cachePolicy, FrameLoader& loader) const
602{
603 RefPtr userContentProvider = loader.frame().userContentProvider();
604
605 bool hasFailedOrExpiredResources = traverseSubresources([cachePolicy, userContentProvider, &loader](const CachedResource& resource) {
606 if (resource.loadFailedOrCanceled())
607 return true;
608 // We can't revalidate subresources individually so don't use reuse the parsed sheet if they need revalidation.
609 if (resource.makeRevalidationDecision(cachePolicy) != CachedResource::RevalidationDecision::No)
610 return true;
611
612#if ENABLE(CONTENT_EXTENSIONS)(defined 1 && 1)
613 // If a cached subresource is blocked or made HTTPS by a content blocker, we cannot reuse the cached stylesheet.
614 RefPtr page = loader.frame().page();
615 auto* documentLoader = loader.documentLoader();
616 if (page && documentLoader) {
617 const auto& request = resource.resourceRequest();
618 auto results = userContentProvider->processContentRuleListsForLoad(*page, request.url(), ContentExtensions::toResourceType(resource.type(), resource.resourceRequest().requester(), loader.frame().isMainFrame()), *documentLoader);
619 if (results.shouldBlock() || results.summary.madeHTTPS)
620 return true;
621 }
622#else
623 UNUSED_PARAM(loader)(void)loader;
624#endif
625
626 return false;
627 });
628 return !hasFailedOrExpiredResources;
629}
630
631bool StyleSheetContents::isLoadingSubresources() const
632{
633 return traverseSubresources([](const CachedResource& resource) {
634 return resource.isLoading();
635 });
636}
637
638bool StyleSheetContents::mayDependOnBaseURL() const
639{
640 return traverseRules([&](const StyleRuleBase& rule) -> bool {
641 switch (rule.type()) {
642 case StyleRuleType::Style:
643 return uncheckedDowncast<StyleRule>(rule).properties().mayDependOnBaseURL();
644 case StyleRuleType::StyleWithNesting:
645 return uncheckedDowncast<StyleRuleWithNesting>(rule).properties().mayDependOnBaseURL();
646 case StyleRuleType::NestedDeclarations:
647 return uncheckedDowncast<StyleRule>(rule).properties().mayDependOnBaseURL();
648 case StyleRuleType::FontFace:
649 return uncheckedDowncast<StyleRuleFontFace>(rule).properties().mayDependOnBaseURL();
650 case StyleRuleType::Import:
651 case StyleRuleType::CounterStyle:
652 case StyleRuleType::Media:
653 case StyleRuleType::Page:
654 case StyleRuleType::Keyframes:
655 case StyleRuleType::Namespace:
656 case StyleRuleType::Charset:
657 case StyleRuleType::Keyframe:
658 case StyleRuleType::Supports:
659 case StyleRuleType::LayerBlock:
660 case StyleRuleType::LayerStatement:
661 case StyleRuleType::Container:
662 case StyleRuleType::FontFeatureValues:
663 case StyleRuleType::FontFeatureValuesBlock:
664 case StyleRuleType::FontPaletteValues:
665 case StyleRuleType::Margin:
666 case StyleRuleType::Property:
667 case StyleRuleType::Scope:
668 case StyleRuleType::StartingStyle:
669 case StyleRuleType::ViewTransition:
670 case StyleRuleType::PositionTry:
671 case StyleRuleType::Function:
672 case StyleRuleType::FunctionDeclarations:
673 return false;
674 };
675 ASSERT_NOT_REACHED()((void)0);
676 return false;
677 });
678}
679
680StyleSheetContents* StyleSheetContents::parentStyleSheet() const
681{
682 return m_ownerRule ? m_ownerRule->parentStyleSheet() : nullptr;
683}
684
685void StyleSheetContents::registerClient(CSSStyleSheet* sheet)
686{
687 ASSERT(!m_clients.contains(sheet))((void)0);
688 m_clients.append(sheet);
689}
690
691void StyleSheetContents::unregisterClient(CSSStyleSheet* sheet)
692{
693 bool removed = m_clients.removeFirst(sheet);
694 ASSERT_UNUSED(removed, removed)((void)removed);
695}
696
697void StyleSheetContents::addedToMemoryCache()
698{
699 ASSERT(isCacheable())((void)0);
700 ++m_inMemoryCacheCount;
701}
702
703void StyleSheetContents::removedFromMemoryCache()
704{
705 ASSERT(m_inMemoryCacheCount)((void)0);
706 ASSERT(isCacheable())((void)0);
707 --m_inMemoryCacheCount;
708}
709
710void StyleSheetContents::shrinkToFit()
711{
712 m_importRules.shrinkToFit();
713 m_childRules.shrinkToFit();
714}
715
716} // namespace WebCore