Index: Source/core/css/CSSParser.h |
diff --git a/Source/core/css/CSSParser.h b/Source/core/css/CSSParser.h |
index a28c3f6250f51e649bd0fc39d6955bbfe76675af..99d1d108773dc57be0c382759ffb0f8a7bc26342 100644 |
--- a/Source/core/css/CSSParser.h |
+++ b/Source/core/css/CSSParser.h |
@@ -3,6 +3,7 @@ |
* Copyright (C) 2004, 2005, 2006, 2008, 2009, 2010 Apple Inc. All rights reserved. |
* Copyright (C) 2008 Eric Seidel <eric@webkit.org> |
* Copyright (C) 2009 - 2010 Torch Mobile (Beijing) Co. Ltd. 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 |
@@ -67,6 +68,68 @@ class WebKitCSSArrayFunctionValue; |
class WebKitCSSMixFunctionValue; |
class WebKitCSSShaderValue; |
+// Keep track of matching parentheses using a stack of opening brackets. |
+// Needed for correct error recovery. |
+class BracketStack { |
+public: |
+ inline void push(int bracket) { m_stack.append(bracket); } |
+ |
+ inline void pop(int bracket) |
+ { |
+ if (m_stack.size() > 0) { |
+ switch (bracket) { |
+ case '}': |
+ if (m_stack.last() == '{') |
+ m_stack.removeLast(); |
+ break; |
+ case ')': |
+ if (m_stack.last() == '(') |
+ m_stack.removeLast(); |
+ break; |
+ case ']': |
+ if (m_stack.last() == '[') |
+ m_stack.removeLast(); |
+ break; |
+ default: |
+ ASSERT_NOT_REACHED(); |
+ break; |
+ } |
+ } |
+ } |
+ |
+ inline int pop() |
+ { |
+ if (!m_stack.size()) |
+ return 0; |
+ |
+ int ret = 0; |
+ switch (top()) { |
+ case '{': |
+ ret = '}'; |
+ break; |
+ case '(': |
+ ret = ')'; |
+ break; |
+ case '[': |
+ ret = ']'; |
+ break; |
+ default: |
+ ASSERT_NOT_REACHED(); |
+ break; |
+ } |
+ m_stack.removeLast(); |
+ return ret; |
+ } |
+ |
+ int top() const { return m_stack.last(); } |
+ |
+ inline size_t level() const { return m_stack.size(); } |
+ |
+private: |
+ // Make room for 16 levels deep nesting of parentheses initially. |
+ Vector<int, 16> m_stack; |
+}; |
+ |
class CSSParser { |
friend inline int cssyylex(void*, CSSParser*); |
@@ -405,6 +468,12 @@ public: |
PassRefPtr<CSSPrimitiveValue> createPrimitiveStringValue(CSSParserValue*); |
PassRefPtr<CSSPrimitiveValue> createPrimitiveVariableNameValue(CSSParserValue*); |
+ // Store block level. |
+ void markMediaListStart(); |
+ |
+ // Error token reached while parsing a media_query, synchronized at current token. |
+ MediaQuery* recoverMediaQuery(); |
+ |
static KURL completeURL(const CSSParserContext&, const String& url); |
Location currentLocation(); |
@@ -553,6 +622,18 @@ private: |
bool m_inViewport; |
#endif |
+ enum ReEmissionState { |
+ DontEmit, |
+ ReEmit, |
+ DidReEmit |
+ }; |
+ |
+ inline void markCurrentTokenForReEmission(); |
+ |
+ ReEmissionState m_reEmissionState; |
+ BracketStack m_brackets; |
+ size_t m_storedBlockLevel; |
+ |
int (CSSParser::*m_lexFunc)(void*); |
Vector<RefPtr<StyleRuleBase> > m_parsedRules; |
@@ -705,6 +786,18 @@ inline int cssyylex(void* yylval, CSSParser* parser) |
return parser->lex(yylval); |
} |
+inline void CSSParser::markCurrentTokenForReEmission() |
+{ |
+ // Sanity check. |
+ // Re-emitting a token which has just been re-emitted may cause an infinite |
+ // loop. Also, marking a token for re-emit twice also doesn't make sense. |
+ ASSERT(m_reEmissionState == DontEmit); |
+ |
+ // Make sure we don't enter an infinite loop if the assert triggers. |
+ if (m_reEmissionState == DontEmit) |
+ m_reEmissionState = ReEmit; |
+} |
+ |
} // namespace WebCore |
#endif // CSSParser_h |