| 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)
|
| {
|
|
|