110f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch// Copyright 2014 The Chromium Authors. All rights reserved.
210f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch// Use of this source code is governed by a BSD-style license that can be
310f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch// found in the LICENSE file.
410f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch
510f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch#include "config.h"
65d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles)#include "core/css/parser/SizesAttributeParser.h"
710f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch
85d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles)#include "core/MediaTypeNames.h"
910f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch#include "core/css/MediaQueryEvaluator.h"
1010f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch#include "core/css/parser/MediaQueryTokenizer.h"
11f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu#include "core/css/parser/SizesCalcParser.h"
1210f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch
13c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)namespace blink {
1410f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch
15c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)SizesAttributeParser::SizesAttributeParser(PassRefPtr<MediaValues> mediaValues, const String& attribute)
16c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    : m_mediaValues(mediaValues)
17c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    , m_length(0)
18c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    , m_lengthWasSet(false)
19c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    , m_viewportDependant(false)
2010f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch{
21c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    MediaQueryTokenizer::tokenize(attribute, m_tokens);
22c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    m_isValid = parse(m_tokens);
23c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)}
2410f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch
25c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)unsigned SizesAttributeParser::length()
26c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles){
27c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    if (m_isValid)
28c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)        return effectiveSize();
29c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    return effectiveSizeDefaultValue();
3010f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch}
3110f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch
32f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liubool SizesAttributeParser::calculateLengthInPixels(MediaQueryTokenIterator startToken, MediaQueryTokenIterator endToken, unsigned& result)
3310f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch{
34f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    if (startToken == endToken)
35f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        return false;
3610f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch    MediaQueryTokenType type = startToken->type();
3710f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch    if (type == DimensionToken) {
3810f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch        int length;
3910f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch        if (!CSSPrimitiveValue::isLength(startToken->unitType()))
4010f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch            return false;
41c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)        m_viewportDependant = CSSPrimitiveValue::isViewportPercentageLength(startToken->unitType());
4210f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch        if ((m_mediaValues->computeLength(startToken->numericValue(), startToken->unitType(), length)) && (length > 0)) {
4310f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch            result = (unsigned)length;
4410f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch            return true;
4510f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch        }
46f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu    } else if (type == FunctionToken) {
47c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)        SizesCalcParser calcParser(startToken, endToken, m_mediaValues);
48c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)        if (!calcParser.isValid())
49c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)            return false;
50c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)        m_viewportDependant = calcParser.viewportDependant();
51c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)        result = calcParser.result();
52c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)        return true;
53f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    } else if (type == NumberToken && !startToken->numericValue()) {
54f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        result = 0;
55f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        return true;
5610f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch    }
57f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu
5810f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch    return false;
5910f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch}
6010f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch
61f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liustatic void reverseSkipIrrelevantTokens(MediaQueryTokenIterator& token, MediaQueryTokenIterator startToken)
6210f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch{
63f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu    MediaQueryTokenIterator endToken = token;
6410f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch    while (token != startToken && (token->type() == WhitespaceToken || token->type() == CommentToken || token->type() == EOFToken))
6510f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch        --token;
6610f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch    if (token != endToken)
6710f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch        ++token;
6810f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch}
6910f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch
70f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liustatic void reverseSkipUntilComponentStart(MediaQueryTokenIterator& token, MediaQueryTokenIterator startToken)
7110f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch{
7210f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch    if (token == startToken)
7310f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch        return;
7410f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch    --token;
7510f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch    if (token->blockType() != MediaQueryToken::BlockEnd)
7610f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch        return;
7710f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch    unsigned blockLevel = 0;
7810f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch    while (token != startToken) {
7910f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch        if (token->blockType() == MediaQueryToken::BlockEnd) {
8010f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch            ++blockLevel;
8110f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch        } else if (token->blockType() == MediaQueryToken::BlockStart) {
8210f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch            --blockLevel;
8310f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch            if (!blockLevel)
8410f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch                break;
8510f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch        }
8610f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch
8710f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch        --token;
8810f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch    }
8910f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch}
9010f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch
9110f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdochbool SizesAttributeParser::mediaConditionMatches(PassRefPtrWillBeRawPtr<MediaQuerySet> mediaCondition)
9210f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch{
93d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    // A Media Condition cannot have a media type other then screen.
94197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    MediaQueryEvaluator mediaQueryEvaluator(*m_mediaValues);
9510f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch    return mediaQueryEvaluator.eval(mediaCondition.get());
9610f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch}
9710f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch
98f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liubool SizesAttributeParser::parseMediaConditionAndLength(MediaQueryTokenIterator startToken, MediaQueryTokenIterator endToken)
9910f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch{
100f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu    MediaQueryTokenIterator lengthTokenStart;
101f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu    MediaQueryTokenIterator lengthTokenEnd;
10210f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch
10310f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch    reverseSkipIrrelevantTokens(endToken, startToken);
10410f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch    lengthTokenEnd = endToken;
10510f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch    reverseSkipUntilComponentStart(endToken, startToken);
10610f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch    lengthTokenStart = endToken;
10710f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch    unsigned length;
10810f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch    if (!calculateLengthInPixels(lengthTokenStart, lengthTokenEnd, length))
10910f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch        return false;
11010f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch    RefPtrWillBeRawPtr<MediaQuerySet> mediaCondition = MediaQueryParser::parseMediaCondition(startToken, endToken);
11110f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch    if (mediaCondition && mediaConditionMatches(mediaCondition)) {
11210f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch        m_length = length;
113f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        m_lengthWasSet = true;
11410f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch        return true;
11510f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch    }
11610f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch    return false;
11710f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch}
11810f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch
11910f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdochbool SizesAttributeParser::parse(Vector<MediaQueryToken>& tokens)
12010f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch{
12110f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch    if (tokens.isEmpty())
12210f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch        return false;
123f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu    MediaQueryTokenIterator startToken = tokens.begin();
124f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu    MediaQueryTokenIterator endToken;
12510f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch    // Split on a comma token, and send the result tokens to be parsed as (media-condition, length) pairs
126f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu    for (MediaQueryTokenIterator token = tokens.begin(); token != tokens.end(); ++token) {
12710f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch        if (token->type() == CommaToken) {
12810f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch            endToken = token;
12910f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch            if (parseMediaConditionAndLength(startToken, endToken))
13010f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch                return true;
13110f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch            startToken = token;
13210f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch            ++startToken;
13310f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch        }
13410f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch    }
13510f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch    endToken = tokens.end();
13610f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch    return parseMediaConditionAndLength(startToken, --endToken);
13710f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch}
13810f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch
13910f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdochunsigned SizesAttributeParser::effectiveSize()
14010f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch{
141f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    if (m_lengthWasSet)
14210f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch        return m_length;
14310f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch    return effectiveSizeDefaultValue();
14410f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch}
14510f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch
14610f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdochunsigned SizesAttributeParser::effectiveSizeDefaultValue()
14710f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch{
148c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    // Returning the equivalent of "100vw"
149c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    m_viewportDependant = true;
15010f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch    return m_mediaValues->viewportWidth();
15110f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch}
15210f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch
15310f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch} // namespace
15410f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch
155