| Index: Source/core/css/parser/SizesAttributeParser.cpp
 | 
| diff --git a/Source/core/css/parser/SizesAttributeParser.cpp b/Source/core/css/parser/SizesAttributeParser.cpp
 | 
| new file mode 100644
 | 
| index 0000000000000000000000000000000000000000..dca1ace194f1a8c0483646db3c29e4f76235657c
 | 
| --- /dev/null
 | 
| +++ b/Source/core/css/parser/SizesAttributeParser.cpp
 | 
| @@ -0,0 +1,134 @@
 | 
| +// Copyright 2014 The Chromium Authors. All rights reserved.
 | 
| +// Use of this source code is governed by a BSD-style license that can be
 | 
| +// found in the LICENSE file.
 | 
| +
 | 
| +#include "config.h"
 | 
| +#include "SizesAttributeParser.h"
 | 
| +
 | 
| +#include "MediaTypeNames.h"
 | 
| +#include "core/css/MediaQueryEvaluator.h"
 | 
| +#include "core/css/parser/MediaQueryTokenizer.h"
 | 
| +
 | 
| +namespace WebCore {
 | 
| +
 | 
| +unsigned SizesAttributeParser::findEffectiveSize(const String& attribute, PassRefPtr<MediaValues> mediaValues)
 | 
| +{
 | 
| +    Vector<MediaQueryToken> tokens;
 | 
| +    SizesAttributeParser parser(mediaValues);
 | 
| +
 | 
| +    MediaQueryTokenizer::tokenize(attribute, tokens);
 | 
| +    if (!parser.parse(tokens))
 | 
| +        return parser.effectiveSizeDefaultValue();
 | 
| +    return parser.effectiveSize();
 | 
| +}
 | 
| +
 | 
| +bool SizesAttributeParser::calculateLengthInPixels(TokenIterator startToken, TokenIterator endToken, unsigned& result)
 | 
| +{
 | 
| +    MediaQueryTokenType type = startToken->type();
 | 
| +    if (type == DimensionToken) {
 | 
| +        int length;
 | 
| +        if (!CSSPrimitiveValue::isLength(startToken->unitType()))
 | 
| +            return false;
 | 
| +        if (m_mediaValues->computeLength(startToken->numericValue(), startToken->unitType(), length)) {
 | 
| +            if (length > 0) {
 | 
| +                result = (unsigned)length;
 | 
| +                return true;
 | 
| +            }
 | 
| +        }
 | 
| +    }
 | 
| +    if (type == FunctionToken) {
 | 
| +        // FIXME - Handle calc() functions here!
 | 
| +    }
 | 
| +    return false;
 | 
| +}
 | 
| +
 | 
| +static void reverseSkipIrrelevantTokens(TokenIterator& token, TokenIterator startToken)
 | 
| +{
 | 
| +    TokenIterator endToken = token;
 | 
| +    while (token != startToken && (token->type() == WhitespaceToken || token->type() == CommentToken || token->type() == EOFToken))
 | 
| +        --token;
 | 
| +    if (token != endToken)
 | 
| +        ++token;
 | 
| +}
 | 
| +
 | 
| +static void reverseSkipUntilComponentStart(TokenIterator& token, TokenIterator startToken)
 | 
| +{
 | 
| +    if (token == startToken)
 | 
| +        return;
 | 
| +    --token;
 | 
| +    if (token->blockType() != MediaQueryToken::BlockEnd)
 | 
| +        return;
 | 
| +    unsigned blockLevel = 0;
 | 
| +    while (token != startToken) {
 | 
| +        if (token->blockType() == MediaQueryToken::BlockEnd) {
 | 
| +            ++blockLevel;
 | 
| +        } else if (token->blockType() == MediaQueryToken::BlockStart) {
 | 
| +            --blockLevel;
 | 
| +            if (!blockLevel)
 | 
| +                break;
 | 
| +        }
 | 
| +
 | 
| +        --token;
 | 
| +    }
 | 
| +}
 | 
| +
 | 
| +bool SizesAttributeParser::mediaConditionMatches(PassRefPtr<MediaQuerySet> mediaCondition)
 | 
| +{
 | 
| +    // FIXME: How do I handle non-screen media types here?
 | 
| +    MediaQueryEvaluator mediaQueryEvaluator(MediaTypeNames::screen, *m_mediaValues);
 | 
| +    return mediaQueryEvaluator.eval(mediaCondition.get());
 | 
| +}
 | 
| +
 | 
| +bool SizesAttributeParser::parseMediaConditionAndLength(TokenIterator startToken, TokenIterator endToken)
 | 
| +{
 | 
| +    TokenIterator lengthTokenStart;
 | 
| +    TokenIterator lengthTokenEnd;
 | 
| +
 | 
| +    reverseSkipIrrelevantTokens(endToken, startToken);
 | 
| +    lengthTokenEnd = endToken;
 | 
| +    reverseSkipUntilComponentStart(endToken, startToken);
 | 
| +    lengthTokenStart = endToken;
 | 
| +    unsigned length;
 | 
| +    if (!calculateLengthInPixels(lengthTokenStart, lengthTokenEnd, length))
 | 
| +        return false;
 | 
| +    RefPtr<MediaQuerySet> mediaCondition = MediaQueryParser::parseMediaCondition(startToken, endToken);
 | 
| +    if (mediaCondition && mediaConditionMatches(mediaCondition)) {
 | 
| +        m_length = length;
 | 
| +        return true;
 | 
| +    }
 | 
| +    return false;
 | 
| +}
 | 
| +
 | 
| +bool SizesAttributeParser::parse(Vector<MediaQueryToken>& tokens)
 | 
| +{
 | 
| +    TokenIterator startToken = tokens.begin();
 | 
| +    TokenIterator endToken;
 | 
| +    // Split on a comma token, and send the result tokens to be parsed as (media-condition, length) pairs
 | 
| +    for (TokenIterator token = tokens.begin(); token != tokens.end(); ++token) {
 | 
| +        if (token->type() == CommaToken) {
 | 
| +            endToken = token;
 | 
| +            if (parseMediaConditionAndLength(startToken, endToken))
 | 
| +                return true;
 | 
| +            startToken = token;
 | 
| +            ++startToken;
 | 
| +        }
 | 
| +    }
 | 
| +    endToken = tokens.end();
 | 
| +    return parseMediaConditionAndLength(startToken, --endToken);
 | 
| +}
 | 
| +
 | 
| +unsigned SizesAttributeParser::effectiveSize()
 | 
| +{
 | 
| +    if (m_length)
 | 
| +        return m_length;
 | 
| +    return effectiveSizeDefaultValue();
 | 
| +}
 | 
| +
 | 
| +unsigned SizesAttributeParser::effectiveSizeDefaultValue()
 | 
| +{
 | 
| +    // Returning the equivalent of "100%"
 | 
| +    return m_mediaValues->viewportWidth();
 | 
| +}
 | 
| +
 | 
| +} // namespace
 | 
| +
 | 
| 
 |