source: webkit/trunk/Source/WebCore/css/CSSStyleSheet.cpp

Last change on this file was 294886, checked in by Sam Sneddon, 3 years ago

Remove resolution media feature dpi/dpcm unit warning
https://bugs.webkit.org/show_bug.cgi?id=240907

Reviewed by Simon Fraser.

  • LayoutTests/fast/media/mq-resolution-dpi-dpcm-warning-expected.txt:
  • LayoutTests/fast/media/mq-resolution-expected.txt:
  • LayoutTests/imported/w3c/web-platform-tests/css/mediaqueries/test_media_queries-expected.txt:
  • LayoutTests/platform/gtk/imported/w3c/web-platform-tests/css/mediaqueries/test_media_queries-expected.txt:
  • LayoutTests/platform/wpe/imported/w3c/web-platform-tests/css/mediaqueries/test_media_queries-expected.txt:
  • Source/WebCore/css/CSSStyleSheet.cpp:

(WebCore::CSSStyleSheet::setMediaQueries):

  • Source/WebCore/css/MediaList.cpp:

(WebCore::addResolutionWarningMessageToConsole): Deleted.
(WebCore::reportMediaQueryWarningIfNeeded): Deleted.

  • Source/WebCore/css/MediaList.h:
  • Source/WebCore/css/MediaQueryMatcher.cpp:

(WebCore::MediaQueryMatcher::matchMedia):

  • Source/WebCore/css/StyleSheetContents.cpp:

(WebCore::StyleSheetContents::parserAppendRule):

Canonical link: https://commits.webkit.org/251014@main

  • Property svn:eol-style set to native
File size: 13.4 KB
Line 
1/*
2 * (C) 1999-2003 Lars Knoll ([email protected])
3 * Copyright (C) 2004, 2006, 2007, 2012, 2013 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 "CSSStyleSheet.h"
23
24#include "CSSImportRule.h"
25#include "CSSKeyframesRule.h"
26#include "CSSParser.h"
27#include "CSSRuleList.h"
28#include "Document.h"
29#include "HTMLLinkElement.h"
30#include "HTMLStyleElement.h"
31#include "Logging.h"
32#include "MediaList.h"
33#include "Node.h"
34#include "SVGElementTypeHelpers.h"
35#include "SVGStyleElement.h"
36#include "SecurityOrigin.h"
37#include "StyleResolver.h"
38#include "StyleRule.h"
39#include "StyleScope.h"
40#include "StyleSheetContents.h"
41
42#include <wtf/HexNumber.h>
43#include <wtf/text/StringBuilder.h>
44
45namespace WebCore {
46
47class StyleSheetCSSRuleList final : public CSSRuleList {
48public:
49 StyleSheetCSSRuleList(CSSStyleSheet* sheet) : m_styleSheet(sheet) { }
50
51private:
52 void ref() final { m_styleSheet->ref(); }
53 void deref() final { m_styleSheet->deref(); }
54
55 unsigned length() const final { return m_styleSheet->length(); }
56 CSSRule* item(unsigned index) const final { return m_styleSheet->item(index); }
57
58 CSSStyleSheet* styleSheet() const final { return m_styleSheet; }
59
60 CSSStyleSheet* m_styleSheet;
61};
62
63#if ASSERT_ENABLED
64static bool isAcceptableCSSStyleSheetParent(Node* parentNode)
65{
66 // Only these nodes can be parents of StyleSheets, and they need to call clearOwnerNode() when moved out of document.
67 return !parentNode
68 || parentNode->isDocumentNode()
69 || is<HTMLLinkElement>(*parentNode)
70 || is<HTMLStyleElement>(*parentNode)
71 || is<SVGStyleElement>(*parentNode)
72 || parentNode->nodeType() == Node::PROCESSING_INSTRUCTION_NODE;
73}
74#endif // ASSERT_ENABLED
75
76Ref<CSSStyleSheet> CSSStyleSheet::create(Ref<StyleSheetContents>&& sheet, CSSImportRule* ownerRule)
77{
78 return adoptRef(*new CSSStyleSheet(WTFMove(sheet), ownerRule));
79}
80
81Ref<CSSStyleSheet> CSSStyleSheet::create(Ref<StyleSheetContents>&& sheet, Node& ownerNode, const std::optional<bool>& isCleanOrigin)
82{
83 return adoptRef(*new CSSStyleSheet(WTFMove(sheet), ownerNode, TextPosition(), false, isCleanOrigin));
84}
85
86Ref<CSSStyleSheet> CSSStyleSheet::createInline(Ref<StyleSheetContents>&& sheet, Element& owner, const TextPosition& startPosition)
87{
88 return adoptRef(*new CSSStyleSheet(WTFMove(sheet), owner, startPosition, true, true));
89}
90
91CSSStyleSheet::CSSStyleSheet(Ref<StyleSheetContents>&& contents, CSSImportRule* ownerRule)
92 : m_contents(WTFMove(contents))
93 , m_ownerRule(ownerRule)
94{
95 if (auto* parent = parentStyleSheet())
96 m_styleScope = parent->styleScope();
97
98 m_contents->registerClient(this);
99}
100
101CSSStyleSheet::CSSStyleSheet(Ref<StyleSheetContents>&& contents, Node& ownerNode, const TextPosition& startPosition, bool isInlineStylesheet, const std::optional<bool>& isOriginClean)
102 : m_contents(WTFMove(contents))
103 , m_isInlineStylesheet(isInlineStylesheet)
104 , m_isOriginClean(isOriginClean)
105 , m_styleScope(Style::Scope::forNode(ownerNode))
106 , m_ownerNode(&ownerNode)
107 , m_startPosition(startPosition)
108{
109 ASSERT(isAcceptableCSSStyleSheetParent(&ownerNode));
110 m_contents->registerClient(this);
111}
112
113CSSStyleSheet::~CSSStyleSheet()
114{
115 // For style rules outside the document, .parentStyleSheet can become null even if the style rule
116 // is still observable from JavaScript. This matches the behavior of .parentNode for nodes, but
117 // it's not ideal because it makes the CSSOM's behavior depend on the timing of garbage collection.
118 for (unsigned i = 0; i < m_childRuleCSSOMWrappers.size(); ++i) {
119 if (m_childRuleCSSOMWrappers[i])
120 m_childRuleCSSOMWrappers[i]->setParentStyleSheet(0);
121 }
122 if (m_mediaCSSOMWrapper)
123 m_mediaCSSOMWrapper->clearParentStyleSheet();
124
125 m_contents->unregisterClient(this);
126}
127
128CSSStyleSheet::WhetherContentsWereClonedForMutation CSSStyleSheet::willMutateRules()
129{
130 // If we are the only client it is safe to mutate.
131 if (m_contents->hasOneClient() && !m_contents->isInMemoryCache()) {
132 m_contents->setMutable();
133 return ContentsWereNotClonedForMutation;
134 }
135 // Only cacheable stylesheets should have multiple clients.
136 ASSERT(m_contents->isCacheable());
137
138 // Copy-on-write.
139 m_contents->unregisterClient(this);
140 m_contents = m_contents->copy();
141 m_contents->registerClient(this);
142
143 m_contents->setMutable();
144
145 // Any existing CSSOM wrappers need to be connected to the copied child rules.
146 reattachChildRuleCSSOMWrappers();
147
148 return ContentsWereClonedForMutation;
149}
150
151void CSSStyleSheet::didMutateRuleFromCSSStyleDeclaration()
152{
153 ASSERT(m_contents->isMutable());
154 ASSERT(m_contents->hasOneClient());
155 didMutate();
156}
157
158void CSSStyleSheet::didMutateRules(RuleMutationType mutationType, WhetherContentsWereClonedForMutation contentsWereClonedForMutation, StyleRuleKeyframes* insertedKeyframesRule, const String& modifiedKeyframesRuleName)
159{
160 ASSERT(m_contents->isMutable());
161 ASSERT(m_contents->hasOneClient());
162
163 auto* scope = styleScope();
164 if (!scope)
165 return;
166
167 if (mutationType == RuleInsertion && !contentsWereClonedForMutation && !scope->activeStyleSheetsContains(this)) {
168 if (insertedKeyframesRule) {
169 if (auto* resolver = scope->resolverIfExists())
170 resolver->addKeyframeStyle(*insertedKeyframesRule);
171 return;
172 }
173 scope->didChangeActiveStyleSheetCandidates();
174 return;
175 }
176
177 if (mutationType == KeyframesRuleMutation) {
178 if (auto* ownerDocument = this->ownerDocument())
179 ownerDocument->keyframesRuleDidChange(modifiedKeyframesRuleName);
180 }
181
182 scope->didChangeStyleSheetContents();
183
184 m_mutatedRules = true;
185}
186
187void CSSStyleSheet::didMutate()
188{
189 auto* scope = styleScope();
190 if (!scope)
191 return;
192 scope->didChangeStyleSheetContents();
193}
194
195void CSSStyleSheet::clearOwnerNode()
196{
197 m_ownerNode = nullptr;
198}
199
200void CSSStyleSheet::reattachChildRuleCSSOMWrappers()
201{
202 for (unsigned i = 0; i < m_childRuleCSSOMWrappers.size(); ++i) {
203 if (!m_childRuleCSSOMWrappers[i])
204 continue;
205 m_childRuleCSSOMWrappers[i]->reattach(*m_contents->ruleAt(i));
206 }
207}
208
209void CSSStyleSheet::setDisabled(bool disabled)
210{
211 if (disabled == m_isDisabled)
212 return;
213 m_isDisabled = disabled;
214
215 if (auto* scope = styleScope())
216 scope->didChangeActiveStyleSheetCandidates();
217}
218
219void CSSStyleSheet::setMediaQueries(Ref<MediaQuerySet>&& mediaQueries)
220{
221 m_mediaQueries = WTFMove(mediaQueries);
222 if (m_mediaCSSOMWrapper && m_mediaQueries)
223 m_mediaCSSOMWrapper->reattach(m_mediaQueries.get());
224}
225
226unsigned CSSStyleSheet::length() const
227{
228 return m_contents->ruleCount();
229}
230
231CSSRule* CSSStyleSheet::item(unsigned index)
232{
233 unsigned ruleCount = length();
234 if (index >= ruleCount)
235 return nullptr;
236
237 ASSERT(m_childRuleCSSOMWrappers.isEmpty() || m_childRuleCSSOMWrappers.size() == ruleCount);
238 if (m_childRuleCSSOMWrappers.size() < ruleCount)
239 m_childRuleCSSOMWrappers.grow(ruleCount);
240
241 RefPtr<CSSRule>& cssRule = m_childRuleCSSOMWrappers[index];
242 if (!cssRule)
243 cssRule = m_contents->ruleAt(index)->createCSSOMWrapper(this);
244 return cssRule.get();
245}
246
247bool CSSStyleSheet::canAccessRules() const
248{
249 if (m_isOriginClean)
250 return m_isOriginClean.value();
251
252 URL baseURL = m_contents->baseURL();
253 if (baseURL.isEmpty())
254 return true;
255 Document* document = ownerDocument();
256 if (!document)
257 return true;
258 return document->securityOrigin().canRequest(baseURL);
259}
260
261ExceptionOr<unsigned> CSSStyleSheet::insertRule(const String& ruleString, unsigned index)
262{
263 LOG_WITH_STREAM(StyleSheets, stream << "CSSStyleSheet " << this << " insertRule() " << ruleString << " at " << index);
264
265 ASSERT(m_childRuleCSSOMWrappers.isEmpty() || m_childRuleCSSOMWrappers.size() == m_contents->ruleCount());
266
267 if (index > length())
268 return Exception { IndexSizeError };
269 RefPtr<StyleRuleBase> rule = CSSParser::parseRule(m_contents.get().parserContext(), m_contents.ptr(), ruleString);
270
271 if (!rule)
272 return Exception { SyntaxError };
273
274 RuleMutationScope mutationScope(this, RuleInsertion, dynamicDowncast<StyleRuleKeyframes>(*rule));
275
276 bool success = m_contents.get().wrapperInsertRule(rule.releaseNonNull(), index);
277 if (!success)
278 return Exception { HierarchyRequestError };
279 if (!m_childRuleCSSOMWrappers.isEmpty())
280 m_childRuleCSSOMWrappers.insert(index, RefPtr<CSSRule>());
281
282 return index;
283}
284
285ExceptionOr<void> CSSStyleSheet::deleteRule(unsigned index)
286{
287 LOG_WITH_STREAM(StyleSheets, stream << "CSSStyleSheet " << this << " deleteRule(" << index << ")");
288
289 ASSERT(m_childRuleCSSOMWrappers.isEmpty() || m_childRuleCSSOMWrappers.size() == m_contents->ruleCount());
290
291 if (index >= length())
292 return Exception { IndexSizeError };
293 RuleMutationScope mutationScope(this);
294
295 m_contents->wrapperDeleteRule(index);
296
297 if (!m_childRuleCSSOMWrappers.isEmpty()) {
298 if (m_childRuleCSSOMWrappers[index])
299 m_childRuleCSSOMWrappers[index]->setParentStyleSheet(nullptr);
300 m_childRuleCSSOMWrappers.remove(index);
301 }
302
303 return { };
304}
305
306ExceptionOr<int> CSSStyleSheet::addRule(const String& selector, const String& style, std::optional<unsigned> index)
307{
308 LOG_WITH_STREAM(StyleSheets, stream << "CSSStyleSheet " << this << " addRule() selector " << selector << " style " << style << " at " << index);
309
310 auto text = makeString(selector, " { ", style, !style.isEmpty() ? " " : "", '}');
311 auto insertRuleResult = insertRule(text, index.value_or(length()));
312 if (insertRuleResult.hasException())
313 return insertRuleResult.releaseException();
314 // As per Microsoft documentation, always return -1.
315 return -1;
316}
317
318ExceptionOr<Ref<CSSRuleList>> CSSStyleSheet::cssRulesForBindings()
319{
320 auto cssRules = this->cssRules();
321 if (!cssRules)
322 return Exception { SecurityError, "Not allowed to access cross-origin stylesheet"_s };
323 return cssRules.releaseNonNull();
324}
325
326RefPtr<CSSRuleList> CSSStyleSheet::cssRules()
327{
328 if (!canAccessRules())
329 return nullptr;
330 if (!m_ruleListCSSOMWrapper)
331 m_ruleListCSSOMWrapper = makeUnique<StyleSheetCSSRuleList>(this);
332 return m_ruleListCSSOMWrapper.get();
333}
334
335String CSSStyleSheet::href() const
336{
337 return m_contents->originalURL();
338}
339
340URL CSSStyleSheet::baseURL() const
341{
342 return m_contents->baseURL();
343}
344
345bool CSSStyleSheet::isLoading() const
346{
347 return m_contents->isLoading();
348}
349
350MediaList* CSSStyleSheet::media() const
351{
352 if (!m_mediaQueries)
353 return nullptr;
354 if (!m_mediaCSSOMWrapper)
355 m_mediaCSSOMWrapper = MediaList::create(m_mediaQueries.get(), const_cast<CSSStyleSheet*>(this));
356 return m_mediaCSSOMWrapper.get();
357}
358
359CSSStyleSheet* CSSStyleSheet::parentStyleSheet() const
360{
361 return m_ownerRule ? m_ownerRule->parentStyleSheet() : nullptr;
362}
363
364CSSStyleSheet& CSSStyleSheet::rootStyleSheet()
365{
366 auto* root = this;
367 while (root->parentStyleSheet())
368 root = root->parentStyleSheet();
369 return *root;
370}
371
372const CSSStyleSheet& CSSStyleSheet::rootStyleSheet() const
373{
374 return const_cast<CSSStyleSheet&>(*this).rootStyleSheet();
375}
376
377Document* CSSStyleSheet::ownerDocument() const
378{
379 auto& root = rootStyleSheet();
380 return root.ownerNode() ? &root.ownerNode()->document() : nullptr;
381}
382
383Style::Scope* CSSStyleSheet::styleScope()
384{
385 return m_styleScope.get();
386}
387
388void CSSStyleSheet::clearChildRuleCSSOMWrappers()
389{
390 m_childRuleCSSOMWrappers.clear();
391}
392
393String CSSStyleSheet::debugDescription() const
394{
395 return makeString("CSSStyleSheet "_s, "0x"_s, hex(reinterpret_cast<uintptr_t>(this), Lowercase), ' ', href());
396}
397
398CSSStyleSheet::RuleMutationScope::RuleMutationScope(CSSStyleSheet* sheet, RuleMutationType mutationType, StyleRuleKeyframes* insertedKeyframesRule)
399 : m_styleSheet(sheet)
400 , m_mutationType(mutationType)
401 , m_insertedKeyframesRule(insertedKeyframesRule)
402{
403 ASSERT(m_styleSheet);
404 m_contentsWereClonedForMutation = m_styleSheet->willMutateRules();
405}
406
407CSSStyleSheet::RuleMutationScope::RuleMutationScope(CSSRule* rule)
408 : m_styleSheet(rule ? rule->parentStyleSheet() : nullptr)
409 , m_mutationType(is<CSSKeyframesRule>(rule) ? KeyframesRuleMutation : OtherMutation)
410 , m_contentsWereClonedForMutation(ContentsWereNotClonedForMutation)
411 , m_insertedKeyframesRule(nullptr)
412 , m_modifiedKeyframesRuleName(is<CSSKeyframesRule>(rule) ? downcast<CSSKeyframesRule>(*rule).name() : emptyAtom())
413{
414 if (m_styleSheet)
415 m_contentsWereClonedForMutation = m_styleSheet->willMutateRules();
416}
417
418CSSStyleSheet::RuleMutationScope::~RuleMutationScope()
419{
420 if (m_styleSheet)
421 m_styleSheet->didMutateRules(m_mutationType, m_contentsWereClonedForMutation, m_insertedKeyframesRule.get(), m_modifiedKeyframesRuleName);
422}
423
424}
Note: See TracBrowser for help on using the repository browser.