Upstream version 7.36.149.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 "SizesAttributeParser.h"
7
8 #include "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 WebCore {
14
15 unsigned SizesAttributeParser::findEffectiveSize(const String& attribute, PassRefPtr<MediaValues> mediaValues)
16 {
17     Vector<MediaQueryToken> tokens;
18     SizesAttributeParser parser(mediaValues);
19
20     MediaQueryTokenizer::tokenize(attribute, tokens);
21     if (!parser.parse(tokens))
22         return parser.effectiveSizeDefaultValue();
23     return parser.effectiveSize();
24 }
25
26 bool SizesAttributeParser::calculateLengthInPixels(MediaQueryTokenIterator startToken, MediaQueryTokenIterator endToken, unsigned& result)
27 {
28     MediaQueryTokenType type = startToken->type();
29     if (type == DimensionToken) {
30         int length;
31         if (!CSSPrimitiveValue::isLength(startToken->unitType()))
32             return false;
33         if ((m_mediaValues->computeLength(startToken->numericValue(), startToken->unitType(), length)) && (length > 0)) {
34             result = (unsigned)length;
35             return true;
36         }
37     } else if (type == FunctionToken) {
38         return SizesCalcParser::parse(startToken, endToken, m_mediaValues, result);
39     }
40
41     return false;
42 }
43
44 static void reverseSkipIrrelevantTokens(MediaQueryTokenIterator& token, MediaQueryTokenIterator startToken)
45 {
46     MediaQueryTokenIterator endToken = token;
47     while (token != startToken && (token->type() == WhitespaceToken || token->type() == CommentToken || token->type() == EOFToken))
48         --token;
49     if (token != endToken)
50         ++token;
51 }
52
53 static void reverseSkipUntilComponentStart(MediaQueryTokenIterator& token, MediaQueryTokenIterator startToken)
54 {
55     if (token == startToken)
56         return;
57     --token;
58     if (token->blockType() != MediaQueryToken::BlockEnd)
59         return;
60     unsigned blockLevel = 0;
61     while (token != startToken) {
62         if (token->blockType() == MediaQueryToken::BlockEnd) {
63             ++blockLevel;
64         } else if (token->blockType() == MediaQueryToken::BlockStart) {
65             --blockLevel;
66             if (!blockLevel)
67                 break;
68         }
69
70         --token;
71     }
72 }
73
74 bool SizesAttributeParser::mediaConditionMatches(PassRefPtrWillBeRawPtr<MediaQuerySet> mediaCondition)
75 {
76     // FIXME: How do I handle non-screen media types here?
77     MediaQueryEvaluator mediaQueryEvaluator(MediaTypeNames::screen, *m_mediaValues);
78     return mediaQueryEvaluator.eval(mediaCondition.get());
79 }
80
81 bool SizesAttributeParser::parseMediaConditionAndLength(MediaQueryTokenIterator startToken, MediaQueryTokenIterator endToken)
82 {
83     MediaQueryTokenIterator lengthTokenStart;
84     MediaQueryTokenIterator lengthTokenEnd;
85
86     reverseSkipIrrelevantTokens(endToken, startToken);
87     lengthTokenEnd = endToken;
88     reverseSkipUntilComponentStart(endToken, startToken);
89     lengthTokenStart = endToken;
90     unsigned length;
91     if (!calculateLengthInPixels(lengthTokenStart, lengthTokenEnd, length))
92         return false;
93     RefPtrWillBeRawPtr<MediaQuerySet> mediaCondition = MediaQueryParser::parseMediaCondition(startToken, endToken);
94     if (mediaCondition && mediaConditionMatches(mediaCondition)) {
95         m_length = length;
96         return true;
97     }
98     return false;
99 }
100
101 bool SizesAttributeParser::parse(Vector<MediaQueryToken>& tokens)
102 {
103     if (tokens.isEmpty())
104         return false;
105     MediaQueryTokenIterator startToken = tokens.begin();
106     MediaQueryTokenIterator endToken;
107     // Split on a comma token, and send the result tokens to be parsed as (media-condition, length) pairs
108     for (MediaQueryTokenIterator token = tokens.begin(); token != tokens.end(); ++token) {
109         if (token->type() == CommaToken) {
110             endToken = token;
111             if (parseMediaConditionAndLength(startToken, endToken))
112                 return true;
113             startToken = token;
114             ++startToken;
115         }
116     }
117     endToken = tokens.end();
118     return parseMediaConditionAndLength(startToken, --endToken);
119 }
120
121 unsigned SizesAttributeParser::effectiveSize()
122 {
123     if (m_length)
124         return m_length;
125     return effectiveSizeDefaultValue();
126 }
127
128 unsigned SizesAttributeParser::effectiveSizeDefaultValue()
129 {
130     // Returning the equivalent of "100%"
131     return m_mediaValues->viewportWidth();
132 }
133
134 } // namespace
135