Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(579)

Unified Diff: Source/core/css/CSSParser.cpp

Issue 14065029: Improved parse error handling for CSSMQ. (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « Source/core/css/CSSParser.h ('k') | Source/core/css/MediaList.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: Source/core/css/CSSParser.cpp
diff --git a/Source/core/css/CSSParser.cpp b/Source/core/css/CSSParser.cpp
index 6e82eb085957a8461fbd244cdca13925f97cec6c..e93cfed27a075408e0069529a44bba2a8c48dcdf 100644
--- a/Source/core/css/CSSParser.cpp
+++ b/Source/core/css/CSSParser.cpp
@@ -7,6 +7,7 @@
* Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
* Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved.
* Copyright (C) 2012 Intel Corporation. All rights reserved.
+ * Copyright (C) 2013 Opera Software ASA. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -319,6 +320,8 @@ CSSParser::CSSParser(const CSSParserContext& context)
#if ENABLE(CSS_DEVICE_ADAPTATION)
, m_inViewport(false)
#endif
+ , m_reEmissionState(DontEmit)
+ , m_storedBlockLevel(0)
{
#if YYDEBUG > 0
cssyydebug = 1;
@@ -1437,9 +1440,10 @@ PassOwnPtr<MediaQuery> CSSParser::parseMediaQuery(const String& string)
ASSERT(!m_mediaQuery);
- // can't use { because tokenizer state switches from mediaquery to initial state when it sees { token.
- // instead insert one " " (which is WHITESPACE in CSSGrammar.y)
- setupParser("@-webkit-mediaquery ", string, "} ");
+ // Can't use { because tokenizer state switches from mediaquery to initial
+ // state when it sees { token. instead insert one " " (which is WHITESPACE
+ // in CSSGrammar.y). Also, can't use } because of error handling.
+ setupParser("@-webkit-mediaquery ", string, "");
cssyyparse(this);
return m_mediaQuery.release();
@@ -9242,6 +9246,8 @@ enum CharacterType {
CharacterXor,
CharacterVerticalBar,
CharacterTilde,
+ CharacterOpeningBracket,
+ CharacterClosingBracket
};
// 128 ASCII codes
@@ -9286,7 +9292,7 @@ static const CharacterType typesOfASCIICharacters[128] = {
/* 37 - % */ CharacterOther,
/* 38 - & */ CharacterOther,
/* 39 - ' */ CharacterQuote,
-/* 40 - ( */ CharacterOther,
+/* 40 - ( */ CharacterOpeningBracket,
/* 41 - ) */ CharacterEndNthChild,
/* 42 - * */ CharacterAsterisk,
/* 43 - + */ CharacterPlus,
@@ -9337,9 +9343,9 @@ static const CharacterType typesOfASCIICharacters[128] = {
/* 88 - X */ CharacterIdentifierStart,
/* 89 - Y */ CharacterIdentifierStart,
/* 90 - Z */ CharacterIdentifierStart,
-/* 91 - [ */ CharacterOther,
+/* 91 - [ */ CharacterOpeningBracket,
/* 92 - \ */ CharacterBackSlash,
-/* 93 - ] */ CharacterOther,
+/* 93 - ] */ CharacterClosingBracket,
/* 94 - ^ */ CharacterXor,
/* 95 - _ */ CharacterIdentifierStart,
/* 96 - ` */ CharacterOther,
@@ -9371,7 +9377,7 @@ static const CharacterType typesOfASCIICharacters[128] = {
/* 122 - z */ CharacterIdentifierStart,
/* 123 - { */ CharacterEndMediaQuery,
/* 124 - | */ CharacterVerticalBar,
-/* 125 - } */ CharacterOther,
+/* 125 - } */ CharacterClosingBracket,
/* 126 - ~ */ CharacterTilde,
/* 127 - Delete */ CharacterOther,
};
@@ -10331,6 +10337,14 @@ inline void CSSParser::detectSupportsToken(int length)
template <typename SrcCharacterType>
int CSSParser::realLex(void* yylvalWithoutType)
{
+ if (m_reEmissionState == ReEmit) {
+ m_reEmissionState = DidReEmit;
+ return token();
+ }
+
+ if (m_reEmissionState == DidReEmit)
+ m_reEmissionState = DontEmit;
+
YYSTYPE* yylval = static_cast<YYSTYPE*>(yylvalWithoutType);
// Write pointer for the next character.
SrcCharacterType* result;
@@ -10374,22 +10388,12 @@ restartAfterComment:
}
m_token = FUNCTION;
- bool shouldSkipParenthesis = true;
- if (!hasEscape) {
- bool detected = detectFunctionTypeToken<SrcCharacterType>(result - tokenStart<SrcCharacterType>());
- if (!detected && m_parsingMode == MediaQueryMode) {
- // ... and(max-width: 480px) ... looks like a function, but in fact it is not,
- // so run more detection code in the MediaQueryMode.
- detectMediaQueryToken<SrcCharacterType>(result - tokenStart<SrcCharacterType>());
- shouldSkipParenthesis = false;
- }
- }
- if (LIKELY(shouldSkipParenthesis)) {
- ++currentCharacter<SrcCharacterType>();
- ++result;
- ++yylval->string.m_length;
- }
+ if (!hasEscape)
+ detectFunctionTypeToken<SrcCharacterType>(result - tokenStart<SrcCharacterType>());
+ ++currentCharacter<SrcCharacterType>();
+ ++result;
+ ++yylval->string.m_length;
if (token() == URI) {
m_token = FUNCTION;
@@ -10399,6 +10403,12 @@ restartAfterComment:
else
parseURI<UChar>(yylval->string);
}
+
+ // URI consumes the ')'. For other function tokens, push the
+ // opening parenthesis to match the closing one when it comes.
+ if (token() != URI)
+ m_brackets.push('(');
+
} else if (UNLIKELY(m_parsingMode != NormalMode) && !hasEscape) {
if (m_parsingMode == MediaQueryMode)
detectMediaQueryToken<SrcCharacterType>(result - tokenStart<SrcCharacterType>());
@@ -10516,6 +10526,7 @@ restartAfterComment:
m_token = VAR_DEFINITION;
else if (*currentCharacter<SrcCharacterType>() == '(') {
m_token = FUNCTION;
+ m_brackets.push('(');
if (!hasEscape)
detectDashToken<SrcCharacterType>(result - tokenStart<SrcCharacterType>());
++currentCharacter<SrcCharacterType>();
@@ -10561,6 +10572,8 @@ restartAfterComment:
break;
case CharacterNull:
+ if (m_brackets.level() > 0)
+ m_token = m_brackets.pop();
// Do not advance pointer at the end of input.
--currentCharacter<SrcCharacterType>();
break;
@@ -10579,11 +10592,14 @@ restartAfterComment:
case CharacterEndMediaQuery:
if (m_parsingMode == MediaQueryMode)
m_parsingMode = NormalMode;
+ if (m_token == '{')
+ m_brackets.push('{');
break;
case CharacterEndNthChild:
if (m_parsingMode == NthChildMode)
m_parsingMode = NormalMode;
+ m_brackets.pop(')');
break;
case CharacterQuote:
@@ -10731,6 +10747,14 @@ restartAfterComment:
}
break;
+ case CharacterOpeningBracket:
+ m_brackets.push(m_token);
+ break;
+
+ case CharacterClosingBracket:
+ m_brackets.pop(m_token);
+ break;
+
default:
ASSERT_NOT_REACHED();
break;
@@ -11479,6 +11503,50 @@ bool CSSParser::parseViewportShorthand(CSSPropertyID propId, CSSPropertyID first
}
#endif
+void CSSParser::markMediaListStart()
+{
+ m_storedBlockLevel = m_brackets.level();
+ if (m_storedBlockLevel > 0 && token() == m_brackets.top()) {
+ // Don't take the currently pushed lookahead token into account.
+ // This could happen for "@media{}", "@media()", etc.
+ --m_storedBlockLevel;
+ }
+}
+
+MediaQuery* CSSParser::recoverMediaQuery()
+{
+ size_t blockLevel = m_brackets.level();
+ if (blockLevel >= m_storedBlockLevel) {
+ YYSTYPE yyval;
+
+ while (token() != TOKEN_EOF) {
+ // End media query at ',', ';', or '{' at the same block level as the
+ // media list started.
+ if (blockLevel == m_storedBlockLevel && (token() == ',' || token() == ';'))
+ break;
+ // The '{' token will have increased the block level by 1 already.
+ if (blockLevel == m_storedBlockLevel + 1 && token() == '{')
+ break;
+
+ lex(&yyval);
+ blockLevel = m_brackets.level();
+ }
+ } else {
+ // Recovering from error token when we are at a block level above the
+ // block level where the media list started. That should only happen
+ // when synchronizing on a closing '}' just one level above the stored
+ // level. Typically happens when an @media rule is terminated
+ // prematurely:
+ //
+ // "@supports (color: red) { @media all and }"
+ ASSERT(token() == '}' && blockLevel == m_storedBlockLevel - 1);
+ }
+
+ markCurrentTokenForReEmission();
+
+ return createFloatingMediaQuery(MediaQuery::Not, "all", sinkFloatingMediaQueryExpList(createFloatingMediaQueryExpList()));
+}
+
template <typename CharacterType>
static CSSPropertyID cssPropertyID(const CharacterType* propertyName, unsigned length)
{
« no previous file with comments | « Source/core/css/CSSParser.h ('k') | Source/core/css/MediaList.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698