Skip to content

Commit 92b83dd

Browse files
committed
perf(css): reduce pure Dart style application overhead
1 parent e535b95 commit 92b83dd

12 files changed

Lines changed: 1377 additions & 169 deletions

webf/lib/src/css/cascade.dart

Lines changed: 75 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
* Licensed under GNU GPL with Enterprise exception.
44
*/
55

6+
import 'package:quiver/collection.dart';
67
import 'package:webf/css.dart';
78

89
/// Internal segment appended to layered rules that are directly inside a layer
@@ -14,6 +15,57 @@ import 'package:webf/css.dart';
1415
const String kWebFImplicitLayerSegment = '__webf__implicit_layer__';
1516

1617
const int _kImplicitLayerSiblingIndex = 1 << 30;
18+
const int _kCascadeDeclarationCacheSize = 512;
19+
20+
final LinkedLruHashMap<_CascadeCacheKey, CSSStyleDeclaration>
21+
_cascadeDeclarationCache = LinkedLruHashMap<_CascadeCacheKey,
22+
CSSStyleDeclaration>(maximumSize: _kCascadeDeclarationCacheSize);
23+
24+
class _CascadeCacheKey {
25+
final int version;
26+
final List<CSSStyleRule> rules;
27+
final int _hashCode;
28+
29+
_CascadeCacheKey._(this.version, this.rules, this._hashCode);
30+
31+
factory _CascadeCacheKey.lookup(int version, List<CSSStyleRule> rules) {
32+
return _CascadeCacheKey._(version, rules, _computeHash(version, rules));
33+
}
34+
35+
factory _CascadeCacheKey.stored(int version, List<CSSStyleRule> rules) {
36+
return _CascadeCacheKey._(version,
37+
List<CSSStyleRule>.of(rules, growable: false), _computeHash(version, rules));
38+
}
39+
40+
static int _computeHash(int version, List<CSSStyleRule> rules) {
41+
int hash = 0x1fffffff & (version + rules.length);
42+
for (final CSSStyleRule rule in rules) {
43+
hash = 0x1fffffff & (hash + identityHashCode(rule));
44+
hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
45+
hash ^= (hash >> 6);
46+
}
47+
hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
48+
hash ^= (hash >> 11);
49+
hash = 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
50+
return hash;
51+
}
52+
53+
@override
54+
int get hashCode => _hashCode;
55+
56+
@override
57+
bool operator ==(Object other) {
58+
if (identical(this, other)) return true;
59+
if (other is! _CascadeCacheKey) return false;
60+
if (version != other.version || rules.length != other.rules.length) {
61+
return false;
62+
}
63+
for (int i = 0; i < rules.length; i++) {
64+
if (!identical(rules[i], other.rules[i])) return false;
65+
}
66+
return true;
67+
}
68+
}
1769

1870
class CascadeLayerTree {
1971
final _LayerNode _root = _LayerNode(name: '<root>', siblingIndex: -1);
@@ -107,12 +159,22 @@ int compareStyleRulesForCascade(CSSStyleRule a, CSSStyleRule b,
107159
return a.position.compareTo(b.position);
108160
}
109161

110-
CSSStyleDeclaration cascadeMatchedStyleRules(List<CSSStyleRule> rules) {
162+
CSSStyleDeclaration cascadeMatchedStyleRules(List<CSSStyleRule> rules,
163+
{int? cacheVersion, bool copyResult = false}) {
111164
final declaration = CSSStyleDeclaration();
112165
if (rules.isEmpty) return declaration;
113166
if (rules.length == 1) {
114167
declaration.union(rules.first.declaration);
115-
return declaration;
168+
return copyResult ? declaration.cloneEffective() : declaration;
169+
}
170+
171+
if (cacheVersion != null) {
172+
final _CascadeCacheKey lookupKey =
173+
_CascadeCacheKey.lookup(cacheVersion, rules);
174+
final CSSStyleDeclaration? cached = _cascadeDeclarationCache[lookupKey];
175+
if (cached != null) {
176+
return copyResult ? cached.cloneEffective() : cached;
177+
}
116178
}
117179

118180
final normalOrder = List<CSSStyleRule>.from(rules)
@@ -124,7 +186,11 @@ CSSStyleDeclaration cascadeMatchedStyleRules(List<CSSStyleRule> rules) {
124186
for (final r in normalOrder) {
125187
declaration.union(r.declaration);
126188
}
127-
return declaration;
189+
if (cacheVersion != null) {
190+
_cascadeDeclarationCache[
191+
_CascadeCacheKey.stored(cacheVersion, rules)] = declaration;
192+
}
193+
return copyResult ? declaration.cloneEffective() : declaration;
128194
}
129195

130196
for (final r in normalOrder) {
@@ -140,5 +206,10 @@ CSSStyleDeclaration cascadeMatchedStyleRules(List<CSSStyleRule> rules) {
140206
declaration.unionByImportance(r.declaration, important: true);
141207
}
142208

143-
return declaration;
209+
if (cacheVersion != null) {
210+
_cascadeDeclarationCache[
211+
_CascadeCacheKey.stored(cacheVersion, rules)] = declaration;
212+
}
213+
214+
return copyResult ? declaration.cloneEffective() : declaration;
144215
}

0 commit comments

Comments
 (0)