--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -53,16 +53,17 @@
#include "nsLayoutUtils.h"
#include "mozilla/Preferences.h"
#include "nsRuleData.h"
#include "mozilla/CSSVariableRegistrations.h"
#include "mozilla/CSSVariableValues.h"
#include "mozilla/dom/AnimationEffectReadOnlyBinding.h"
#include "mozilla/dom/URL.h"
#include "gfxFontFamilyList.h"
+#include "mozilla/CSSVariableSyntax.h"
using namespace mozilla;
using namespace mozilla::css;
typedef nsCSSProps::KTableEntry KTableEntry;
// pref-backed bool values (hooked up in nsCSSParser::Startup)
static bool sOpentypeSVGEnabled;
@@ -270,16 +271,24 @@ public:
nsIURI* aSheetURL,
nsIURI* aBaseURL,
nsIPrincipal* aSheetPrincipal,
nsCSSValue& aValue);
bool IsValueValidForProperty(const nsCSSPropertyID aPropID,
const nsAString& aPropValue);
+ bool ParseTypedValue(const CSSVariableSyntax& aSyntax,
+ const nsAString& aPropValue,
+ nsIURI* aSheetURL,
+ nsIURI* aBaseURL,
+ nsIPrincipal* aSheetPrincipal,
+ nsCSSValue& aValue,
+ mozilla::CSSValueType& aType);
+
typedef nsCSSParser::VariableEnumFunc VariableEnumFunc;
/**
* Parses a CSS token stream value and invokes a callback function for each
* variable reference that is encountered.
*
* @param aPropertyValue The CSS token stream value.
* @param aFunc The callback function to invoke; its parameters are the
@@ -293,17 +302,17 @@ public:
void* aData);
/**
* Parses aPropertyValue as a CSS token stream value and resolves any
* variable references using the variables in aVariables.
*
* @param aPropertyValue The CSS token stream value.
* @param aVariables The set of variable values to use when resolving variable
- * references.
+ * references. Can be null, in which case no variables will be resolved.
* @param aResult Out parameter that gets the resolved value.
* @param aFirstToken Out parameter that gets the type of the first token in
* aResult.
* @param aLastToken Out parameter that gets the type of the last token in
* aResult.
* @return Whether aResult could be parsed successfully and variable reference
* substitution succeeded.
*/
@@ -1358,16 +1367,23 @@ protected:
/* Functions for transform-origin/perspective-origin Parsing */
bool ParseTransformOrigin(bool aPerspective);
/* Functions for filter parsing */
bool ParseFilter();
bool ParseSingleFilter(nsCSSValue* aValue);
bool ParseDropShadow(nsCSSValue* aValue);
+ bool ParseSingleTypedValue(const CSSVariableSyntax::Term& aTerm,
+ nsCSSValue& aValue);
+ bool ParseTypedValue(const CSSVariableSyntax& aSyntax,
+ bool aAllowVariableReferences,
+ nsCSSValue& aValue,
+ mozilla::CSSValueType& aType);
+
/* Find and return the namespace ID associated with aPrefix.
If aPrefix has not been declared in an @namespace rule, returns
kNameSpaceID_Unknown. */
int32_t GetNamespaceIdForPrefix(const nsString& aPrefix);
/* Find the correct default namespace, and set it on aSelector. */
void SetDefaultNamespaceOnSelector(nsCSSSelector& aSelector);
@@ -3119,16 +3135,187 @@ CSSParserImpl::ParseFontFaceDescriptor(n
!GetToken(true);
OUTPUT_ERROR();
ReleaseScanner();
return success;
}
+static bool
+TryParseInherit(nsCSSToken aToken, nsCSSValue& aValue)
+{
+ // TODO(jyc) Add support for the 'revert' keyword here and in the resolver.
+ if (aToken.mType == eCSSToken_Ident) {
+ if (aToken.mIdent.Equals(NS_LITERAL_STRING("initial"))) {
+ aValue.SetInitialValue();
+ return true;
+ }
+ if (aToken.mIdent.Equals(NS_LITERAL_STRING("inherit"))) {
+ aValue.SetInheritValue();
+ return true;
+ }
+ if (aToken.mIdent.Equals(NS_LITERAL_STRING("unset"))) {
+ aValue.SetUnsetValue();
+ return true;
+ }
+ }
+ return false;
+}
+
+
+bool
+CSSParserImpl::ParseSingleTypedValue(const CSSVariableSyntax::Term& aTerm,
+ nsCSSValue& aValue)
+{
+ if (aTerm.GetType() == CSSValueType::SpecificIdent) {
+ if (!GetToken(true)) {
+ return false;
+ }
+ if (mToken.mType == eCSSToken_Ident &&
+ mToken.mIdent.Equals(aTerm.GetIdentifier())) {
+ aValue.SetStringValue(mToken.mIdent, eCSSUnit_Ident);
+ return true;
+ }
+ return TryParseInherit(mToken, aValue);
+ } else if (aTerm.GetType() == CSSValueType::CustomIdent) {
+ if (!GetToken(true)) {
+ return false;
+ }
+ if (mToken.mType == eCSSToken_Ident) {
+ aValue.SetStringValue(mToken.mIdent, eCSSUnit_Ident);
+ return true;
+ }
+ return TryParseInherit(mToken, aValue);
+ } else if (aTerm.GetType() == CSSValueType::Resolution) {
+ return ParseResolution(aValue) || TryParseInherit(mToken, aValue);
+ } else if (aTerm.GetType() == CSSValueType::TransformFunction) {
+ // Try to parse with aIsPrefixed = false then true.
+ return ParseSingleTransform(false, false, aValue) ||
+ ParseSingleTransform(true, false, aValue) ||
+ TryParseInherit(mToken, aValue);
+ }
+
+ uint32_t variant = aTerm.GetVariant();
+ MOZ_ASSERT(variant);
+
+ // VARIANT_INHERIT to allow for inherit, initial, and unset.
+ // In the future, need to allow revert too.
+ return ParseVariant(aValue, variant | VARIANT_INHERIT, nullptr) == CSSParseResult::Ok;
+}
+
+bool
+CSSParserImpl::ParseTypedValue(const CSSVariableSyntax& aSyntax,
+ bool aAllowVariableReferences,
+ nsCSSValue& aValue,
+ mozilla::CSSValueType& aType)
+{
+ CSSVariableSyntax::Type syntaxType = aSyntax.GetType();
+
+ if (syntaxType == CSSVariableSyntax::Type::Anything) {
+ CSSVariableDeclarations::Type type;
+ nsString result;
+ if (!ParseVariableDeclaration(&type, aAllowVariableReferences, result)) {
+ return false;
+ }
+ if (type != CSSVariableDeclarations::Type::eTokenStream) {
+ return false;
+ }
+ nsCSSValueTokenStream* tokenStream = new nsCSSValueTokenStream;
+ // Can't use eCSSPropertyExtra_UNKNOWN because that would cause
+ // KeyframeUtils::IsInvalidValuePair to think these values were invalid.
+ tokenStream->mPropertyID = eCSSPropertyExtra_variable;
+ tokenStream->mTokenStream = result;
+ tokenStream->mBaseURI = mBaseURI;
+ tokenStream->mSheetURI = mSheetURI;
+ tokenStream->mSheetPrincipal = mSheetPrincipal;
+ // XXX Should store sheet here (see bug 952338).
+ // tokenStream->mSheet = mSheet;
+ tokenStream->mLineNumber = 0;
+ tokenStream->mLineOffset = 0;
+ aValue.SetTokenStreamValue(tokenStream);
+ aType = CSSValueType::TokenStream;
+ return true;
+ }
+
+ MOZ_ASSERT(syntaxType == CSSVariableSyntax::Type::Disjunction);
+
+ CSSParserInputState state;
+ SaveInputState(state);
+
+ nsCSSValue result;
+
+ for (const CSSVariableSyntax::Term& term : aSyntax.GetTerms()) {
+ bool ok = false;
+ if (term.IsList()) {
+ nsCSSValueList* item = nullptr;
+ for (;;) {
+ nsCSSValue value;
+ if (!GetToken(/* aSkipWS = */ true)) {
+ // If at EOF, stop.
+ if (item) {
+ item->mNext = nullptr;
+ }
+ break;
+ }
+ UngetToken();
+ if (!ParseSingleTypedValue(term, value)) {
+ ok = false;
+ break;
+ }
+ if (!item) {
+ ok = true;
+ item = result.SetListValue();
+ } else {
+ item->mNext = new nsCSSValueList;
+ item = item->mNext;
+ }
+ item->mValue = value;
+ }
+ } else {
+ if (ParseSingleTypedValue(term, result)) {
+ ok = true;
+ }
+ // If we are in a disjunction (<A> | <B> | ...) and this one failed, we
+ // need to keep trying.
+ }
+ if (ok) {
+ aValue = result;
+ aType = term.GetType();
+ return true;
+ }
+ RestoreSavedInputState(state);
+ result.Reset();
+ }
+
+ return false;
+}
+
+bool
+CSSParserImpl::ParseTypedValue(const CSSVariableSyntax& aSyntax,
+ const nsAString& aBuffer,
+ nsIURI* aSheetURL,
+ nsIURI* aBaseURL,
+ nsIPrincipal* aSheetPrincipal,
+ nsCSSValue& aValue,
+ mozilla::CSSValueType& aType)
+{
+ nsCSSScanner scanner(aBuffer, 0);
+ css::ErrorReporter reporter(scanner, mSheet, mChildLoader, aSheetURL);
+ InitScanner(scanner, reporter, aSheetURL, aBaseURL, aSheetPrincipal);
+
+ bool success = ParseTypedValue(aSyntax, false, aValue, aType) &&
+ !GetToken(true);
+
+ OUTPUT_ERROR();
+ ReleaseScanner();
+
+ return success;
+}
+
//----------------------------------------------------------------------
bool
CSSParserImpl::GetToken(bool aSkipWS)
{
if (mHavePushBack) {
mHavePushBack = false;
if (!aSkipWS || mToken.mType != eCSSToken_Whitespace) {
@@ -18066,8 +18253,22 @@ nsCSSParser::SetVariableRegistrations(
CSSParserImpl *impl = static_cast<CSSParserImpl*>(mImpl);
MOZ_ASSERT(impl->GetDocument() == nullptr,
"If impl->mSheet is not null, then there should be no need for "
"SetVariableRegistrations.");
impl->mVariableRegistrations = aRegistrations;
}
+
+bool
+nsCSSParser::ParseTypedValue(const CSSVariableSyntax& aSyntax,
+ const nsAString& aPropValue,
+ nsIURI* aSheetURL,
+ nsIURI* aBaseURL,
+ nsIPrincipal* aSheetPrincipal,
+ nsCSSValue& aValue,
+ mozilla::CSSValueType& aType)
+{
+ return static_cast<CSSParserImpl*>(mImpl)->
+ ParseTypedValue(aSyntax, aPropValue, aSheetURL, aBaseURL, aSheetPrincipal,
+ aValue, aType);
+}
--- a/layout/style/nsCSSParser.h
+++ b/layout/style/nsCSSParser.h
@@ -4,16 +4,17 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* parsing of CSS stylesheets, based on a token stream from the CSS scanner */
#ifndef nsCSSParser_h___
#define nsCSSParser_h___
#include "mozilla/Attributes.h"
+#include "mozilla/CSSValueType.h"
#include "mozilla/css/Loader.h"
#include "nsCSSPropertyID.h"
#include "nsCSSScanner.h"
#include "nsCOMPtr.h"
#include "nsAutoPtr.h"
#include "nsStringFwd.h"
#include "nsTArrayForwardDeclare.h"
@@ -25,16 +26,17 @@ class nsMediaList;
class nsMediaQuery;
class nsCSSKeyframeRule;
class nsCSSValue;
struct nsRuleData;
namespace mozilla {
class CSSStyleSheet;
struct CSSVariableRegistrations;
+class CSSVariableSyntax;
class CSSVariableValues;
namespace css {
class Rule;
class Declaration;
class StyleRule;
} // namespace css
} // namespace mozilla
@@ -315,16 +317,24 @@ public:
nsIURI* aBaseURL,
nsIPrincipal* aSheetPrincipal,
nsCSSValue& aValue);
// Check whether a given value can be applied to a property.
bool IsValueValidForProperty(const nsCSSPropertyID aPropID,
const nsAString& aPropValue);
+ bool ParseTypedValue(const mozilla::CSSVariableSyntax& aSyntax,
+ const nsAString& aBuffer,
+ nsIURI* aSheetURL,
+ nsIURI* aBaseURL,
+ nsIPrincipal* aSheetPrincipal,
+ nsCSSValue& aValue,
+ mozilla::CSSValueType& aType);
+
// Return the default value to be used for -moz-control-character-visibility,
// from preferences (cached by our Startup(), so that both nsStyleText and
// nsRuleNode can have fast access to it).
static uint8_t ControlCharVisibilityDefault();
void SetVariableRegistrations(
const mozilla::CSSVariableRegistrations* aRegistrations);