33 * Licensed under GNU GPL with Enterprise exception.
44 */
55
6+ import 'package:quiver/collection.dart' ;
67import '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';
1415const String kWebFImplicitLayerSegment = '__webf__implicit_layer__' ;
1516
1617const 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
1870class 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