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

Side by Side Diff: Source/core/css/parser/MediaQueryCalcParser.cpp

Issue 252743004: A thread safe CSS calc parser for sizes (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: removed linespace Created 6 years, 7 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "config.h"
6 #include "core/css/parser/MediaQueryCalcParser.h"
7
8 #include "core/css/MediaValues.h"
9 #include "core/css/parser/MediaQueryToken.h"
10
11 namespace WebCore {
12
13 int MediaQueryCalcParser::parse(MediaQueryTokenIterator start, MediaQueryTokenIt erator end, unsigned fontSize, unsigned viewportWidth, unsigned viewportHeight)
14 {
15 MediaQueryCalcParser parser(fontSize, viewportWidth, viewportHeight);
16 int result = 0;
17 if (parser.calcToReversePolishNotation(start, end))
18 parser.calculate(result);
19 return result;
20 }
21
22 static bool operatorPriority(UChar cc, bool& highPriority)
23 {
24 if (cc == '+' || cc == '-')
25 highPriority = false;
26 else if (cc == '*' || cc == '/')
27 highPriority = true;
28 else
29 return false;
30 return true;
31 }
32
33 bool MediaQueryCalcParser::handleOperator(Vector<MediaQueryToken>& stack, const MediaQueryToken& token)
34 {
35 // If the token is an operator, o1, then:
36 // while there is an operator token, o2, at the top of the stack, and
37 // either o1 is left-associative and its precedence is equal to that of o2,
38 // or o1 has precedence less than that of o2,
39 // pop o2 off the stack, onto the output queue;
40 // push o1 onto the stack.
41 bool stackOperatorPriority;
42 bool incomingOperatorPriority;
43
44 if (!operatorPriority(token.delimiter(), incomingOperatorPriority))
45 return false;
46 if (!stack.isEmpty() && stack.last().type() == DelimiterToken) {
47 if (!operatorPriority(stack.last().delimiter(), stackOperatorPriority))
48 return false;
49 if (!incomingOperatorPriority || stackOperatorPriority) {
50 appendOperator(stack.last());
51 stack.removeLast();
52 }
53 }
54 stack.append(token);
55 return true;
56 }
57
58 bool MediaQueryCalcParser::appendNumber(const MediaQueryToken& token)
59 {
60 MediaQueryCalcValue value;
61 if (token.type() == PercentageToken) {
62 value.value = token.numericValue() / 100.0;
63 } else if (token.type() == NumberToken) {
64 value.value = token.numericValue();
65 } else {
66 int result = 0;
67 if (!MediaValues::computeLength(token.numericValue(), token.unitType(), m_fontSize, m_viewportWidth, m_viewportHeight, result))
68 return false;
69 value.value = result;
70 }
71 m_valueList.append(value);
72 return true;
73 }
74
75 void MediaQueryCalcParser::appendOperator(const MediaQueryToken& token)
76 {
77 MediaQueryCalcValue value;
78 value.operation = token.delimiter();
79 m_valueList.append(value);
80 }
81
82 bool MediaQueryCalcParser::calcToReversePolishNotation(MediaQueryTokenIterator s tart, MediaQueryTokenIterator end)
83 {
84 // This method implements the shunting yard algorithm, to turn the calc synt ax into a reverse polish notation.
85 // http://en.wikipedia.org/wiki/Shunting-yard_algorithm
86
87 Vector<MediaQueryToken> stack;
88 for (MediaQueryTokenIterator it = start; it != end; ++it) {
89 MediaQueryTokenType type = it->type();
90 switch (type) {
91 case NumberToken:
92 case PercentageToken:
93 case DimensionToken:
94 // If the token is a number, then add it to the output queue.
95 if (!appendNumber(*it))
96 return false;
97 break;
98 case DelimiterToken:
99 if (!handleOperator(stack, *it))
100 return false;
101 break;
102 case FunctionToken:
103 if (it->value() != "calc")
104 return false;
105 // "calc(" is the same as "("
106 case LeftParenthesisToken:
107 // If the token is a left parenthesis, then push it onto the stack.
108 stack.append(*it);
109 break;
110 case RightParenthesisToken:
111 // If the token is a right parenthesis:
112 // Until the token at the top of the stack is a left parenthesis, po p operators off the stack onto the output queue.
113 while (!stack.isEmpty() && stack.last().type() != LeftParenthesisTok en && stack.last().type() != FunctionToken) {
114 appendOperator(stack.last());
115 stack.removeLast();
116 }
117 // If the stack runs out without finding a left parenthesis, then th ere are mismatched parentheses.
118 if (stack.isEmpty())
119 return false;
120 // Pop the left parenthesis from the stack, but not onto the output queue.
121 stack.removeLast();
122 break;
123 case CommentToken:
124 case WhitespaceToken:
125 case EOFToken:
126 break;
127 case IdentToken:
128 case CommaToken:
129 case ColonToken:
130 case SemicolonToken:
131 case LeftBraceToken:
132 case LeftBracketToken:
133 case RightBraceToken:
134 case RightBracketToken:
135 case StringToken:
136 case BadStringToken:
137 return false;
138 }
139 }
140
141 // When there are no more tokens to read:
142 // While there are still operator tokens in the stack:
143 while (!stack.isEmpty()) {
144 // If the operator token on the top of the stack is a parenthesis, then there are mismatched parentheses.
145 MediaQueryTokenType type = stack.last().type();
146 if (type == LeftParenthesisToken || type == FunctionToken)
147 return false;
148 // Pop the operator onto the output queue.
149 appendOperator(stack.last());
150 stack.removeLast();
151 }
152 return true;
153 }
154
155 static bool operateOnStack(Vector<double>& stack, UChar operation)
156 {
157 if (stack.size() < 2)
158 return false;
159 double rightOperand = stack.last();
160 stack.removeLast();
161 double leftOperand = stack.last();
162 stack.removeLast();
163 switch (operation) {
164 case '+':
165 stack.append(rightOperand + leftOperand);
166 break;
167 case '-':
168 stack.append(rightOperand - leftOperand);
169 break;
170 case '*':
171 stack.append(rightOperand * leftOperand);
172 break;
173 case '/':
174 stack.append(rightOperand / leftOperand);
175 break;
176 default:
177 return false;
178 }
179 return true;
180 }
181
182 bool MediaQueryCalcParser::calculate(int& result)
183 {
184 Vector<double> stack;
185 for (Vector<MediaQueryCalcValue>::iterator it = m_valueList.begin(); it != m _valueList.end(); ++it) {
186 if (it->operation == 0) {
187 stack.append(it->value);
188 } else {
189 if (!operateOnStack(stack, it->operation))
190 return false;
191 }
192 }
193 if (stack.size() == 1) {
194 result = stack.last();
195 return true;
196 }
197 return false;
198 }
199
200 } // namespace WebCore
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698