Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / css / parser / SizesAttributeParser.cpp
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/SizesAttributeParser.h"
7
8 #include "core/MediaTypeNames.h"
9 #include "core/css/MediaQueryEvaluator.h"
10 #include "core/css/parser/MediaQueryTokenizer.h"
11 #include "core/css/parser/SizesCalcParser.h"
12
13 namespace blink {
14
15 SizesAttributeParser::SizesAttributeParser(PassRefPtr<MediaValues> mediaValues, const String& attribute)
16     : m_mediaValues(mediaValues)
17     , m_length(0)
18     , m_lengthWasSet(false)
19     , m_viewportDependant(false)
20 {
21     MediaQueryTokenizer::tokenize(attribute, m_tokens);
22     m_isValid = parse(m_tokens);
23 }
24
25 unsigned SizesAttributeParser::length()
26 {
27     if (m_isValid)
28         return effectiveSize();
29     return effectiveSizeDefaultValue();
30 }
31
32 bool SizesAttributeParser::calculateLengthInPixels(MediaQueryTokenIterator startToken, MediaQueryTokenIterator endToken, unsigned& result)
33 {
34     if (startToken == endToken)
35         return false;
36     MediaQueryTokenType type = startToken->type();
37     if (type == DimensionToken) {
38         int length;
39         if (!CSSPrimitiveValue::isLength(startToken->unitType()))
40             return false;
41         m_viewportDependant = CSSPrimitiveValue::isViewportPercentageLength(startToken->unitType());
42         if ((m_mediaValues->computeLength(startToken->numericValue(), startToken->unitType(), length)) && (length > 0)) {
43             result = (unsigned)length;
44             return true;
45         }
46     } else if (type == FunctionToken) {
47         SizesCalcParser calcParser(startToken, endToken, m_mediaValues);
48         if (!calcParser.isValid())
49             return false;
50         m_viewportDependant = calcParser.viewportDependant();
51         result = calcParser.result();
52         return true;
53     } else if (type == NumberToken && !startToken->numericValue()) {
54         result = 0;
55         return true;
56     }
57
58     return false;
59 }
60
61 static void reverseSkipIrrelevantTokens(MediaQueryTokenIterator& token, MediaQueryTokenIterator startToken)
62 {
63     MediaQueryTokenIterator endToken = token;
64     while (token != startToken && (token->type() == WhitespaceToken || token->type() == CommentToken || token->type() == EOFToken))
65         --token;
66     if (token != endToken)
67         ++token;
68 }
69
70 static void reverseSkipUntilComponentStart(MediaQueryTokenIterator& token, MediaQueryTokenIterator startToken)
71 {
72     if (token == startToken)
73         return;
74     --token;
75     if (token->blockType() != MediaQueryToken::BlockEnd)
76         return;
77     unsigned blockLevel = 0;
78     while (token != startToken) {
79         if (token->blockType() == MediaQueryToken::BlockEnd) {
80             ++blockLevel;
81         } else if (token->blockType() == MediaQueryToken::BlockStart) {
82             --blockLevel;
83             if (!blockLevel)
84                 break;
85         }
86
87         --token;
88     }
89 }
90
91 bool SizesAttributeParser::mediaConditionMatches(PassRefPtrWillBeRawPtr<MediaQuerySet> mediaCondition)
92 {
93     // A Media Condition cannot have a media type other then screen.
94     MediaQueryEvaluator mediaQueryEvaluator(*m_mediaValues);
95     return mediaQueryEvaluator.eval(mediaCondition.get());
96 }
97
98 bool SizesAttributeParser::parseMediaConditionAndLength(MediaQueryTokenIterator startToken, MediaQueryTokenIterator endToken)
99 {
100     MediaQueryTokenIterator lengthTokenStart;
101     MediaQueryTokenIterator lengthTokenEnd;
102
103     reverseSkipIrrelevantTokens(endToken, startToken);
104     lengthTokenEnd = endToken;
105     reverseSkipUntilComponentStart(endToken, startToken);
106     lengthTokenStart = endToken;
107     unsigned length;
108     if (!calculateLengthInPixels(lengthTokenStart, lengthTokenEnd, length))
109         return false;
110     RefPtrWillBeRawPtr<MediaQuerySet> mediaCondition = MediaQueryParser::parseMediaCondition(startToken, endToken);
111     if (mediaCondition && mediaConditionMatches(mediaCondition)) {
112         m_length = length;
113         m_lengthWasSet = true;
114         return true;
115     }
116     return false;
117 }
118
119 bool SizesAttributeParser::parse(Vector<MediaQueryToken>& tokens)
120 {
121     if (tokens.isEmpty())
122         return false;
123     MediaQueryTokenIterator startToken = tokens.begin();
124     MediaQueryTokenIterator endToken;
125     // Split on a comma token, and send the result tokens to be parsed as (media-condition, length) pairs
126     for (MediaQueryTokenIterator token = tokens.begin(); token != tokens.end(); ++token) {
127         if (token->type() == CommaToken) {
128             endToken = token;
129             if (parseMediaConditionAndLength(startToken, endToken))
130                 return true;
131             startToken = token;
132             ++startToken;
133         }
134     }
135     endToken = tokens.end();
136     return parseMediaConditionAndLength(startToken, --endToken);
137 }
138
139 unsigned SizesAttributeParser::effectiveSize()
140 {
141     if (m_lengthWasSet)
142         return m_length;
143     return effectiveSizeDefaultValue();
144 }
145
146 unsigned SizesAttributeParser::effectiveSizeDefaultValue()
147 {
148     // Returning the equivalent of "100vw"
149     m_viewportDependant = true;
150     return m_mediaValues->viewportWidth();
151 }
152
153 } // namespace
154