@@ -19,6 +19,7 @@ import {
1919 BinOpMatcher ,
2020 ColorMatcher ,
2121 ColorMixMatcher ,
22+ EnvFunctionMatcher ,
2223 FlexGridMatcher ,
2324 GridTemplateMatcher ,
2425 LengthMatcher ,
@@ -296,6 +297,7 @@ export class CSSMatchedStyles {
296297 #functionRules: CSSFunctionRule [ ] ;
297298 #functionRuleMap = new Map < string , CSSFunctionRule > ( ) ;
298299 readonly #fontPaletteValuesRule: CSSFontPaletteValuesRule | undefined ;
300+ #environmentVariables: Record < string , string > = { } ;
299301
300302 static async create ( payload : CSSMatchedStylesPayload ) : Promise < CSSMatchedStyles > {
301303 const cssMatchedStyles = new CSSMatchedStyles ( payload ) ;
@@ -349,6 +351,8 @@ export class CSSMatchedStyles {
349351 inheritedResult . matchedCSSRules = cleanUserAgentPayload ( inheritedResult . matchedCSSRules ) ;
350352 }
351353
354+ this . #environmentVariables = await this . cssModel ( ) . getEnvironmentVariales ( ) ;
355+
352356 this . #mainDOMCascade = await this . buildMainCascade (
353357 inlinePayload , attributesPayload , matchedPayload , inheritedPayload , animationStylesPayload ,
354358 transitionsStylePayload , inheritedAnimatedPayload ) ;
@@ -504,7 +508,7 @@ export class CSSMatchedStyles {
504508 nodeCascades . push ( new NodeCascade ( this , inheritedStyles , true /* #isInherited */ ) ) ;
505509 }
506510
507- return new DOMInheritanceCascade ( nodeCascades , this . #registeredProperties) ;
511+ return new DOMInheritanceCascade ( this , nodeCascades , this . #registeredProperties) ;
508512 }
509513
510514 /**
@@ -632,12 +636,13 @@ export class CSSMatchedStyles {
632636 // Now that we've built the arrays of NodeCascades for each pseudo type, convert them into
633637 // DOMInheritanceCascades.
634638 for ( const [ pseudoType , nodeCascade ] of pseudoCascades . entries ( ) ) {
635- pseudoInheritanceCascades . set ( pseudoType , new DOMInheritanceCascade ( nodeCascade , this . #registeredProperties) ) ;
639+ pseudoInheritanceCascades . set (
640+ pseudoType , new DOMInheritanceCascade ( this , nodeCascade , this . #registeredProperties) ) ;
636641 }
637642
638643 for ( const [ highlightName , nodeCascade ] of customHighlightPseudoCascades . entries ( ) ) {
639644 customHighlightPseudoInheritanceCascades . set (
640- highlightName , new DOMInheritanceCascade ( nodeCascade , this . #registeredProperties) ) ;
645+ highlightName , new DOMInheritanceCascade ( this , nodeCascade , this . #registeredProperties) ) ;
641646 }
642647
643648 return [ pseudoInheritanceCascades , customHighlightPseudoInheritanceCascades ] ;
@@ -904,8 +909,13 @@ export class CSSMatchedStyles {
904909 new AutoBaseMatcher ( ) ,
905910 new BinOpMatcher ( ) ,
906911 new RelativeColorChannelMatcher ( ) ,
912+ new EnvFunctionMatcher ( this ) ,
907913 ] ;
908914 }
915+
916+ environmentVariable ( name : string ) : string | undefined {
917+ return this . #environmentVariables[ name ] ;
918+ }
909919}
910920
911921class NodeCascade {
@@ -1085,8 +1095,11 @@ class DOMInheritanceCascade {
10851095 #initialized = false ;
10861096 readonly #nodeCascades: NodeCascade [ ] ;
10871097 #registeredProperties: CSSRegisteredProperty [ ] ;
1088- constructor ( nodeCascades : NodeCascade [ ] , registeredProperties : CSSRegisteredProperty [ ] ) {
1098+ readonly #matchedStyles: CSSMatchedStyles ;
1099+ constructor (
1100+ matchedStyles : CSSMatchedStyles , nodeCascades : NodeCascade [ ] , registeredProperties : CSSRegisteredProperty [ ] ) {
10891101 this . #nodeCascades = nodeCascades ;
1102+ this . #matchedStyles = matchedStyles ;
10901103 this . #registeredProperties = registeredProperties ;
10911104
10921105 for ( const nodeCascade of nodeCascades ) {
@@ -1267,47 +1280,49 @@ class DOMInheritanceCascade {
12671280 // bubbling up the minimum discovery time whenever we close a cycle.
12681281 const record = sccRecord . add ( nodeCascade , variableName ) ;
12691282
1270- const matching = PropertyParser . BottomUpTreeMatching . walk (
1271- ast , [ new BaseVariableMatcher ( match => {
1272- const parentStyle = definedValue . declaration . style ;
1273- const nodeCascade = this . #styleToNodeCascade. get ( parentStyle ) ;
1274- if ( ! nodeCascade ) {
1283+ const matching = PropertyParser . BottomUpTreeMatching . walk ( ast , [
1284+ new BaseVariableMatcher ( match => {
1285+ const parentStyle = definedValue . declaration . style ;
1286+ const nodeCascade = this . #styleToNodeCascade. get ( parentStyle ) ;
1287+ if ( ! nodeCascade ) {
1288+ return null ;
1289+ }
1290+ const childRecord = sccRecord . get ( nodeCascade , match . name ) ;
1291+ if ( childRecord ) {
1292+ if ( sccRecord . isInInProgressSCC ( childRecord ) ) {
1293+ // Cycle detected, update the root.
1294+ record . updateRoot ( childRecord ) ;
12751295 return null ;
12761296 }
1277- const childRecord = sccRecord . get ( nodeCascade , match . name ) ;
1278- if ( childRecord ) {
1279- if ( sccRecord . isInInProgressSCC ( childRecord ) ) {
1280- // Cycle detected, update the root.
1281- record . updateRoot ( childRecord ) ;
1282- return null ;
1283- }
12841297
1285- // We've seen the variable before, so we can look up the text directly.
1286- return this . #computedCSSVariables. get ( nodeCascade ) ?. get ( match . name ) ?. value ?? null ;
1287- }
1298+ // We've seen the variable before, so we can look up the text directly.
1299+ return this . #computedCSSVariables. get ( nodeCascade ) ?. get ( match . name ) ?. value ?? null ;
1300+ }
12881301
1289- const cssVariableValue = this . innerComputeCSSVariable ( nodeCascade , match . name , sccRecord ) ;
1290- // Variable reference is resolved, so return it.
1291- const newChildRecord = sccRecord . get ( nodeCascade , match . name ) ;
1292- // The SCC record for the referenced variable may not exist if the var was already computed in a previous
1293- // iteration. That means it's in a different SCC.
1294- newChildRecord && record . updateRoot ( newChildRecord ) ;
1295- if ( cssVariableValue ?. value !== undefined ) {
1296- return cssVariableValue . value ;
1297- }
1302+ const cssVariableValue = this . innerComputeCSSVariable ( nodeCascade , match . name , sccRecord ) ;
1303+ // Variable reference is resolved, so return it.
1304+ const newChildRecord = sccRecord . get ( nodeCascade , match . name ) ;
1305+ // The SCC record for the referenced variable may not exist if the var was already computed in a previous
1306+ // iteration. That means it's in a different SCC.
1307+ newChildRecord && record . updateRoot ( newChildRecord ) ;
1308+ if ( cssVariableValue ?. value !== undefined ) {
1309+ return cssVariableValue . value ;
1310+ }
12981311
1299- // Variable reference is not resolved, use the fallback.
1300- if ( ! match . fallback ) {
1301- return null ;
1302- }
1303- if ( match . fallback . length === 0 ) {
1304- return '' ;
1305- }
1306- if ( match . matching . hasUnresolvedVarsRange ( match . fallback [ 0 ] , match . fallback [ match . fallback . length - 1 ] ) ) {
1307- return null ;
1308- }
1309- return match . matching . getComputedTextRange ( match . fallback [ 0 ] , match . fallback [ match . fallback . length - 1 ] ) ;
1310- } ) ] ) ;
1312+ // Variable reference is not resolved, use the fallback.
1313+ if ( ! match . fallback ) {
1314+ return null ;
1315+ }
1316+ if ( match . fallback . length === 0 ) {
1317+ return '' ;
1318+ }
1319+ if ( match . matching . hasUnresolvedVarsRange ( match . fallback [ 0 ] , match . fallback [ match . fallback . length - 1 ] ) ) {
1320+ return null ;
1321+ }
1322+ return match . matching . getComputedTextRange ( match . fallback [ 0 ] , match . fallback [ match . fallback . length - 1 ] ) ;
1323+ } ) ,
1324+ new EnvFunctionMatcher ( this . #matchedStyles)
1325+ ] ) ;
13111326
13121327 const decl = PropertyParser . ASTUtils . siblings ( PropertyParser . ASTUtils . declValue ( matching . ast . tree ) ) ;
13131328 const computedText = decl . length > 0 ? matching . getComputedTextRange ( decl [ 0 ] , decl [ decl . length - 1 ] ) : '' ;
0 commit comments