From 958b02c358d36112ba2fcc53514955ef88e190a2 Mon Sep 17 00:00:00 2001 From: Martok Date: Sun, 5 Mar 2023 23:05:33 +0100 Subject: Issue #2143 - Implement CSS env() Environment Variables --- layout/style/nsCSSParser.cpp | 78 +++++++++++++++++++++++++++++++------------ layout/style/nsCSSScanner.cpp | 6 +++- 2 files changed, 61 insertions(+), 23 deletions(-) (limited to 'layout') diff --git a/layout/style/nsCSSParser.cpp b/layout/style/nsCSSParser.cpp index 7bb18bc810..f9f198417f 100644 --- a/layout/style/nsCSSParser.cpp +++ b/layout/style/nsCSSParser.cpp @@ -2638,6 +2638,25 @@ StopRecordingAndAppendTokens(nsString& aResult, } } +static bool +ResolveEnvironmentVariable(const nsAString& aName, + nsString& aValue, + nsCSSTokenSerializationType& aFirstToken, + nsCSSTokenSerializationType& aLastToken) +{ + // hard-code the few values of the Environment Variables spec + if (aName.EqualsLiteral("safe-area-inset-top") || + aName.EqualsLiteral("safe-area-inset-bottom") || + aName.EqualsLiteral("safe-area-inset-left") || + aName.EqualsLiteral("safe-area-inset-right")) { + aValue.AppendLiteral(" 0px"); + aFirstToken = eCSSTokenSerialization_Whitespace; + aLastToken = eCSSTokenSerialization_Dimension; + return true; + } + return false; +} + bool CSSParserImpl::ResolveValueWithVariableReferencesRec( nsString& aResult, @@ -2755,8 +2774,10 @@ CSSParserImpl::ResolveValueWithVariableReferencesRec( } case eCSSToken_Function: - if (mToken.mIdent.LowerCaseEqualsLiteral("var")) { - // Save the tokens before the "var(" to our resolved value. + if (mToken.mIdent.LowerCaseEqualsLiteral("env") || + mToken.mIdent.LowerCaseEqualsLiteral("var")) { + bool functionIsVariable = mToken.mIdent.LowerCaseEqualsLiteral("var"); + // Save the tokens before the "env(" to our resolved value. nsString recording; mScanner->StopRecording(recording); recording.Truncate(lengthBeforeVar); @@ -2766,30 +2787,43 @@ CSSParserImpl::ResolveValueWithVariableReferencesRec( recLastToken = eCSSTokenSerialization_Nothing; if (!GetToken(true) || - mToken.mType != eCSSToken_Ident || - !nsCSSProps::IsCustomPropertyName(mToken.mIdent)) { - // "var(" must be followed by an identifier, and it must be a - // custom property name. + mToken.mType != eCSSToken_Ident) { + // function must be followed by an identifier return false; } - // Turn the custom property name into a variable name by removing the - // '--' prefix. - MOZ_ASSERT(Substring(mToken.mIdent, 0, - CSS_CUSTOM_NAME_PREFIX_LENGTH). - EqualsLiteral("--")); - nsDependentString variableName(mToken.mIdent, - CSS_CUSTOM_NAME_PREFIX_LENGTH); - - // Get the value of the identified variable. Note that we - // check if the variable value is the empty string, as that means - // that the variable was invalid at computed value time due to - // unresolveable variable references or cycles. + // Expand the function call into variableValue nsString variableValue; - nsCSSTokenSerializationType varFirstToken, varLastToken; - bool valid = aVariables->Get(variableName, variableValue, - varFirstToken, varLastToken) && - !variableValue.IsEmpty(); + nsCSSTokenSerializationType varFirstToken = eCSSTokenSerialization_Nothing; + nsCSSTokenSerializationType varLastToken = eCSSTokenSerialization_Nothing; + bool valid = false; + + if (functionIsVariable) { + if (!nsCSSProps::IsCustomPropertyName(mToken.mIdent)) { + // "var(" identifier must be a custom property name. + return false; + } + + // Turn the custom property name into a variable name by removing the + // '--' prefix. + MOZ_ASSERT(Substring(mToken.mIdent, 0, + CSS_CUSTOM_NAME_PREFIX_LENGTH). + EqualsLiteral("--")); + nsDependentString variableName(mToken.mIdent, + CSS_CUSTOM_NAME_PREFIX_LENGTH); + + // Get the value of the identified variable. Note that we + // check if the variable value is the empty string, as that means + // that the variable was invalid at computed value time due to + // unresolveable variable references or cycles. + valid = aVariables->Get(variableName, variableValue, + varFirstToken, varLastToken) && + !variableValue.IsEmpty(); + } else { + valid = ResolveEnvironmentVariable(mToken.mIdent, variableValue, + varFirstToken,varLastToken) && + !variableValue.IsEmpty(); + } if (!GetToken(true) || mToken.IsSymbol(')')) { diff --git a/layout/style/nsCSSScanner.cpp b/layout/style/nsCSSScanner.cpp index b1524a3bb2..8010d86b67 100644 --- a/layout/style/nsCSSScanner.cpp +++ b/layout/style/nsCSSScanner.cpp @@ -752,7 +752,11 @@ nsCSSScanner::ScanIdent(nsCSSToken& aToken) aToken.mType = eCSSToken_Function; if (aToken.mIdent.LowerCaseEqualsLiteral("url")) { NextURL(aToken); - } else if (aToken.mIdent.LowerCaseEqualsLiteral("var")) { + } else if (aToken.mIdent.LowerCaseEqualsLiteral("var") || + aToken.mIdent.LowerCaseEqualsLiteral("env")) { + // env() queries are technically not variables, but share all the + // same handling. For the purposes of resolving the token stream later, + // pretend they are. mSeenVariableReference = true; } return true; -- cgit v1.2.3