Skip to content

Commit 72e9a6a

Browse files
committed
Cache complex CSS variable values
https://bugs.webkit.org/show_bug.cgi?id=264250 rdar://117996144 Reviewed by Alan Baradlay. Cache the final CSSValue for variable references in all cases. * Source/WebCore/Sources.txt: * Source/WebCore/WebCore.xcodeproj/project.pbxproj: * Source/WebCore/css/CSSPendingSubstitutionValue.cpp: Added. (WebCore::CSSPendingSubstitutionValue::resolveValue const): For shortcut references cache each individual longhand. * Source/WebCore/css/CSSPendingSubstitutionValue.h: * Source/WebCore/css/CSSVariableReferenceValue.cpp: (WebCore::CSSVariableReferenceValue::cacheSimpleReference): (WebCore::CSSVariableReferenceValue::resolveSingleValue const): (WebCore::CSSVariableReferenceValue::resolveAndCacheValue const): Deleted. (WebCore::CSSVariableReferenceValue::resolveSubstitutionValue const): Deleted. * Source/WebCore/css/CSSVariableReferenceValue.h: (WebCore::CSSVariableReferenceValue::resolveAndCacheValue const): Cache also in non-simple reference case. In these cases we still resolve the tokens and use their equaivalence to test the validity of the cached value. * Source/WebCore/style/StyleBuilder.cpp: (WebCore::Style::Builder::resolveVariableReferences): Canonical link: https://commits.webkit.org/270376@main
1 parent a4e3641 commit 72e9a6a

File tree

7 files changed

+107
-56
lines changed

7 files changed

+107
-56
lines changed

Source/WebCore/Sources.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -859,6 +859,7 @@ css/CSSNamespaceRule.cpp
859859
css/CSSOffsetRotateValue.cpp
860860
css/CSSPageRule.cpp
861861
css/CSSPaintImageValue.cpp
862+
css/CSSPendingSubstitutionValue.cpp
862863
css/CSSPrimitiveValue.cpp
863864
css/CSSProperty.cpp
864865
css/CSSPropertyRule.cpp

Source/WebCore/WebCore.xcodeproj/project.pbxproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19650,6 +19650,7 @@
1965019650
E4F819C526FB4EBF0094E162 /* InlineBoxPainter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InlineBoxPainter.h; sourceTree = "<group>"; };
1965119651
E4F9EEF0156D84C400D23E7E /* StyleSheetContents.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StyleSheetContents.cpp; sourceTree = "<group>"; };
1965219652
E4F9EEF1156D84C400D23E7E /* StyleSheetContents.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StyleSheetContents.h; sourceTree = "<group>"; };
19653+
E4FA70FF2AF8EEB700D32FEA /* CSSPendingSubstitutionValue.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CSSPendingSubstitutionValue.cpp; sourceTree = "<group>"; };
1965319654
E4FB4B35239BEB10003C336A /* LayoutIntegrationInlineContent.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = LayoutIntegrationInlineContent.cpp; sourceTree = "<group>"; };
1965419655
E4FFCEB82760AC0000A68B03 /* CSSLayerStatementRule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSSLayerStatementRule.h; sourceTree = "<group>"; };
1965519656
E4FFCEB92760AC0000A68B03 /* CSSLayerStatementRule.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CSSLayerStatementRule.cpp; sourceTree = "<group>"; };
@@ -35444,6 +35445,7 @@
3544435445
4B6E87682176D69200420E5E /* CSSPaintImageValue.h */,
3544535446
4BAFD0CA2190EBD600C0AB64 /* CSSPaintSize.h */,
3544635447
4BAFD0CD2190EBE900C0AB64 /* CSSPaintSize.idl */,
35448+
E4FA70FF2AF8EEB700D32FEA /* CSSPendingSubstitutionValue.cpp */,
3544735449
9418278D1D8CAE9500492764 /* CSSPendingSubstitutionValue.h */,
3544835450
A80E6CDB0A1989CA007FB8C5 /* CSSPrimitiveValue.cpp */,
3544935451
A80E6CBC0A1989CA007FB8C5 /* CSSPrimitiveValue.h */,
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
* Copyright (C) 2023 Apple Inc. All rights reserved.
3+
*
4+
* Redistribution and use in source and binary forms, with or without
5+
* modification, are permitted provided that the following conditions
6+
* are met:
7+
* 1. Redistributions of source code must retain the above copyright
8+
* notice, this list of conditions and the following disclaimer.
9+
* 2. Redistributions in binary form must reproduce the above copyright
10+
* notice, this list of conditions and the following disclaimer in the
11+
* documentation and/or other materials provided with the distribution.
12+
*
13+
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15+
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16+
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17+
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23+
* THE POSSIBILITY OF SUCH DAMAGE.
24+
*/
25+
26+
#include "config.h"
27+
#include "CSSPendingSubstitutionValue.h"
28+
29+
#include "CSSPropertyParser.h"
30+
31+
namespace WebCore {
32+
33+
RefPtr<CSSValue> CSSPendingSubstitutionValue::resolveValue(Style::BuilderState& builderState, CSSPropertyID propertyID) const
34+
{
35+
auto cacheValue = [&](auto data) {
36+
ParsedPropertyVector parsedProperties;
37+
if (!CSSPropertyParser::parseValue(m_shorthandPropertyId, false, data->tokens(), data->context(), parsedProperties, StyleRuleType::Style)) {
38+
m_cachedPropertyValues = { };
39+
return;
40+
}
41+
42+
m_cachedPropertyValues = parsedProperties;
43+
};
44+
45+
if (!m_shorthandValue->resolveAndCacheValue(builderState, cacheValue))
46+
return nullptr;
47+
48+
for (auto& property : m_cachedPropertyValues) {
49+
if (property.id() == propertyID)
50+
return property.value();
51+
}
52+
53+
return nullptr;
54+
}
55+
56+
}

Source/WebCore/css/CSSPendingSubstitutionValue.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434

3535
namespace WebCore {
3636

37+
class CSSProperty;
38+
3739
class CSSPendingSubstitutionValue : public CSSValue {
3840
public:
3941
static Ref<CSSPendingSubstitutionValue> create(CSSPropertyID shorthandPropertyId, Ref<CSSVariableReferenceValue>&& shorthandValue)
@@ -47,6 +49,8 @@ class CSSPendingSubstitutionValue : public CSSValue {
4749
bool equals(const CSSPendingSubstitutionValue& other) const { return m_shorthandValue.ptr() == other.m_shorthandValue.ptr(); }
4850
static String customCSSText() { return emptyString(); }
4951

52+
RefPtr<CSSValue> resolveValue(Style::BuilderState&, CSSPropertyID) const;
53+
5054
private:
5155
CSSPendingSubstitutionValue(CSSPropertyID shorthandPropertyId, Ref<CSSVariableReferenceValue>&& shorthandValue)
5256
: CSSValue(PendingSubstitutionValueClass)
@@ -57,6 +61,8 @@ class CSSPendingSubstitutionValue : public CSSValue {
5761

5862
const CSSPropertyID m_shorthandPropertyId;
5963
Ref<CSSVariableReferenceValue> m_shorthandValue;
64+
65+
mutable Vector<CSSProperty> m_cachedPropertyValues;
6066
};
6167

6268
} // namespace WebCore

Source/WebCore/css/CSSVariableReferenceValue.cpp

Lines changed: 11 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ void CSSVariableReferenceValue::cacheSimpleReference()
177177
ASSERT(!m_simpleReference);
178178

179179
auto range = m_data->tokenRange();
180+
180181
auto functionId = range.peek().functionId();
181182
if (functionId != CSSValueVar && functionId != CSSValueEnv)
182183
return;
@@ -225,53 +226,20 @@ RefPtr<CSSVariableData> CSSVariableReferenceValue::resolveVariableReferences(Sty
225226
return CSSVariableData::create(*resolvedTokens, context());
226227
}
227228

228-
template<typename ParseFunction>
229-
RefPtr<CSSValue> CSSVariableReferenceValue::resolveAndCacheValue(Style::BuilderState& builderState, CSSPropertyID propertyID, CSSPropertyID shorthandID, ParseFunction&& parseFunction) const
230-
{
231-
if (auto data = tryResolveSimpleReference(builderState)) {
232-
// FIXME: Also cache the complex case.
233-
auto hasValidCachedValue = m_cachedResolvedValue
234-
&& arePointingToEqualData(m_cachedResolvedValue->dependencyData, data)
235-
&& m_cachedResolvedValue->propertyID == propertyID
236-
&& m_cachedResolvedValue->shorthandID == shorthandID;
237-
238-
if (hasValidCachedValue) {
239-
// Update in case the object changed but data stayed the same.
240-
m_cachedResolvedValue->dependencyData = data;
241-
} else {
242-
auto value = parseFunction(data->tokenRange());
243-
m_cachedResolvedValue = makeUnique<ResolvedValue>(ResolvedValue { value, propertyID, shorthandID, data });
244-
}
245-
return m_cachedResolvedValue->value;
246-
}
247-
248-
auto resolvedTokens = resolveTokenRange(m_data->tokenRange(), builderState);
249-
if (!resolvedTokens)
250-
return nullptr;
251-
252-
return parseFunction(CSSParserTokenRange { *resolvedTokens });
253-
}
254-
255229
RefPtr<CSSValue> CSSVariableReferenceValue::resolveSingleValue(Style::BuilderState& builderState, CSSPropertyID propertyID) const
256230
{
257-
return resolveAndCacheValue(builderState, propertyID, CSSPropertyInvalid, [&](auto tokens) -> RefPtr<CSSValue> {
258-
return CSSPropertyParser::parseSingleValue(propertyID, tokens, context());
259-
});
260-
}
231+
auto cacheValue = [&](auto data) {
232+
m_cachedValue = CSSPropertyParser::parseSingleValue(propertyID, data->tokens(), context());
233+
#if ASSERT_ENABLED
234+
m_cachePropertyID = propertyID;
235+
#endif
236+
};
261237

262-
RefPtr<CSSValue> CSSVariableReferenceValue::resolveSubstitutionValue(Style::BuilderState& builderState, CSSPropertyID propertyID, CSSPropertyID shorthandID) const
263-
{
264-
return resolveAndCacheValue(builderState, propertyID, shorthandID, [&](auto tokens) -> RefPtr<CSSValue> {
265-
ParsedPropertyVector parsedProperties;
266-
if (!CSSPropertyParser::parseValue(shorthandID, false, tokens, context(), parsedProperties, StyleRuleType::Style))
267-
return nullptr;
268-
269-
for (auto& property : parsedProperties) {
270-
if (property.id() == propertyID)
271-
return property.value();
272-
}
238+
if (!resolveAndCacheValue(builderState, cacheValue))
273239
return nullptr;
274-
});
240+
241+
ASSERT(m_cachePropertyID == propertyID);
242+
return m_cachedValue;
275243
}
276244

277245
} // namespace WebCore

Source/WebCore/css/CSSVariableReferenceValue.h

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131

3232
#include "CSSValue.h"
3333
#include "CSSValueKeywords.h"
34+
#include <wtf/PointerComparison.h>
3435
#include <wtf/text/WTFString.h>
3536

3637
namespace WebCore {
@@ -58,14 +59,15 @@ class CSSVariableReferenceValue : public CSSValue {
5859
const CSSParserContext& context() const;
5960

6061
RefPtr<CSSValue> resolveSingleValue(Style::BuilderState&, CSSPropertyID) const;
61-
RefPtr<CSSValue> resolveSubstitutionValue(Style::BuilderState&, CSSPropertyID, CSSPropertyID shorthandID) const;
6262

6363
// The maximum number of tokens that may be produced by a var() reference or var() fallback value.
6464
// https://drafts.csswg.org/css-variables/#long-variables
6565
static constexpr size_t maxSubstitutionTokens = 65536;
6666

6767
const CSSVariableData& data() const { return m_data.get(); }
6868

69+
template<typename CacheFunction> bool resolveAndCacheValue(Style::BuilderState&, CacheFunction&&) const;
70+
6971
private:
7072
explicit CSSVariableReferenceValue(Ref<CSSVariableData>&&);
7173

@@ -77,8 +79,6 @@ class CSSVariableReferenceValue : public CSSValue {
7779
void cacheSimpleReference();
7880
RefPtr<CSSVariableData> tryResolveSimpleReference(Style::BuilderState&) const;
7981

80-
template<typename ParseFunction> RefPtr<CSSValue> resolveAndCacheValue(Style::BuilderState&, CSSPropertyID, CSSPropertyID shorthandID, ParseFunction&&) const;
81-
8282
Ref<CSSVariableData> m_data;
8383
mutable String m_stringValue;
8484

@@ -89,17 +89,35 @@ class CSSVariableReferenceValue : public CSSValue {
8989
};
9090
std::optional<SimpleReference> m_simpleReference;
9191

92-
struct ResolvedValue {
93-
WTF_MAKE_STRUCT_FAST_ALLOCATED;
94-
95-
RefPtr<CSSValue> value;
96-
CSSPropertyID propertyID;
97-
CSSPropertyID shorthandID;
98-
RefPtr<CSSVariableData> dependencyData;
99-
};
100-
mutable std::unique_ptr<ResolvedValue> m_cachedResolvedValue;
92+
mutable RefPtr<CSSVariableData> m_cacheDependencyData;
93+
mutable RefPtr<CSSValue> m_cachedValue;
94+
#if ASSERT_ENABLED
95+
mutable CSSPropertyID m_cachePropertyID { CSSPropertyInvalid };
96+
#endif
10197
};
10298

99+
template<typename CacheFunction>
100+
bool CSSVariableReferenceValue::resolveAndCacheValue(Style::BuilderState& builderState, CacheFunction&& cacheFunction) const
101+
102+
{
103+
if (auto data = tryResolveSimpleReference(builderState)) {
104+
if (!arePointingToEqualData(m_cacheDependencyData, data))
105+
cacheFunction(data);
106+
m_cacheDependencyData = WTFMove(data);
107+
return true;
108+
}
109+
110+
auto resolvedTokens = resolveTokenRange(m_data->tokenRange(), builderState);
111+
if (!resolvedTokens)
112+
return false;
113+
114+
if (!m_cacheDependencyData || m_cacheDependencyData->tokens() != *resolvedTokens) {
115+
m_cacheDependencyData = CSSVariableData::create(*resolvedTokens, context());
116+
cacheFunction(m_cacheDependencyData);
117+
}
118+
return true;
119+
}
120+
103121
} // namespace WebCore
104122

105123
SPECIALIZE_TYPE_TRAITS_CSS_VALUE(CSSVariableReferenceValue, isVariableReferenceValue())

Source/WebCore/style/StyleBuilder.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,7 @@ Ref<CSSValue> Builder::resolveVariableReferences(CSSPropertyID propertyID, CSSVa
376376
auto variableValue = [&]() -> RefPtr<CSSValue> {
377377
if (is<CSSPendingSubstitutionValue>(value)) {
378378
auto& substitution = downcast<CSSPendingSubstitutionValue>(value);
379-
return substitution.shorthandValue().resolveSubstitutionValue(m_state, propertyID, substitution.shorthandPropertyId());
379+
return substitution.resolveValue(m_state, propertyID);
380380
}
381381

382382
auto& variableReferenceValue = downcast<CSSVariableReferenceValue>(value);

0 commit comments

Comments
 (0)