106f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)/*
2f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) * Copyright (C) 2013 Apple Inc. All rights reserved.
306f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles) * Copyright (C) 2013 Google Inc. All rights reserved.
406f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles) *
506f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles) * Redistribution and use in source and binary forms, with or without
606f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles) * modification, are permitted provided that the following conditions are
706f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles) * met:
806f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles) *
906f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles) *     * Redistributions of source code must retain the above copyright
1006f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles) * notice, this list of conditions and the following disclaimer.
1106f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles) *     * Redistributions in binary form must reproduce the above
1206f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles) * copyright notice, this list of conditions and the following disclaimer
1306f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles) * in the documentation and/or other materials provided with the
1406f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles) * distribution.
1506f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles) *     * Neither the name of Google Inc. nor the names of its
1606f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles) * contributors may be used to endorse or promote products derived from
1706f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles) * this software without specific prior written permission.
1806f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles) *
1906f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles) * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2006f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles) * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2106f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles) * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2206f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles) * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2306f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles) * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2406f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles) * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2506f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles) * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2606f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles) * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2706f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles) * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2806f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles) * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2906f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles) * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3006f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles) */
3106f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)
3206f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)#include "config.h"
3306f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)#include "core/html/parser/HTMLSrcsetParser.h"
3406f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)
3506f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)#include "core/html/parser/HTMLParserIdioms.h"
36f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)#include "platform/ParsingUtilities.h"
375d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles)#include "platform/RuntimeEnabledFeatures.h"
3806f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)
39c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)namespace blink {
4006f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)
41f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)static bool compareByDensity(const ImageCandidate& first, const ImageCandidate& second)
4206f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles){
43f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    return first.density() < second.density();
4406f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)}
4506f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)
46f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)enum DescriptorTokenizerState {
47f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    Start,
48f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    InParenthesis,
49f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    AfterToken,
50f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)};
51f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)
52f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)struct DescriptorToken {
53f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    unsigned start;
54f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    unsigned length;
55f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)
56f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    DescriptorToken(unsigned start, unsigned length)
57f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        : start(start)
58f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        , length(length)
59f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    {
60f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    }
61f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)
62f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    unsigned lastIndex()
63f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    {
64f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        return start + length - 1;
65f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    }
66f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)
67f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    template<typename CharType>
68f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    int toInt(const CharType* attribute, bool& isValid)
69f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    {
70197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch        return charactersToIntStrict(attribute + start, length - 1, &isValid);
71f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    }
72f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)
73f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    template<typename CharType>
74f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    float toFloat(const CharType* attribute, bool& isValid)
75f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    {
76f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        return charactersToFloat(attribute + start, length - 1, &isValid);
77f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    }
78f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)};
79f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)
8006f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)template<typename CharType>
81f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)static void appendDescriptorAndReset(const CharType* attributeStart, const CharType*& descriptorStart, const CharType* position, Vector<DescriptorToken>& descriptors)
8206f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles){
83f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    if (position > descriptorStart)
84f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        descriptors.append(DescriptorToken(descriptorStart - attributeStart, position - descriptorStart));
85f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    descriptorStart = 0;
8606f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)}
8706f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)
88f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)// The following is called appendCharacter to match the spec's terminology.
8906f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)template<typename CharType>
90f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)static void appendCharacter(const CharType* descriptorStart, const CharType* position)
9106f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles){
92f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    // Since we don't copy the tokens, this just set the point where the descriptor tokens start.
93f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    if (!descriptorStart)
94f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        descriptorStart = position;
95f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)}
9606f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)
97f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)template<typename CharType>
98f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)static bool isEOF(const CharType* position, const CharType* end)
99f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles){
100f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    return position >= end;
101f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)}
102f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)
103f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)template<typename CharType>
104f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)static void tokenizeDescriptors(const CharType* attributeStart,
105f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    const CharType*& position,
106f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    const CharType* attributeEnd,
107f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    Vector<DescriptorToken>& descriptors)
108f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles){
109f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    DescriptorTokenizerState state = Start;
110f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    const CharType* descriptorsStart = position;
111f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    const CharType* currentDescriptorStart = descriptorsStart;
112f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    while (true) {
113f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        switch (state) {
114f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        case Start:
115f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)            if (isEOF(position, attributeEnd)) {
116f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)                appendDescriptorAndReset(attributeStart, currentDescriptorStart, attributeEnd, descriptors);
117f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)                return;
118f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)            }
119f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)            if (isComma(*position)) {
120f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)                appendDescriptorAndReset(attributeStart, currentDescriptorStart, position, descriptors);
121f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)                ++position;
122f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)                return;
123f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)            }
124f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)            if (isHTMLSpace(*position)) {
125f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)                appendDescriptorAndReset(attributeStart, currentDescriptorStart, position, descriptors);
126f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)                currentDescriptorStart = position + 1;
127f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)                state = AfterToken;
128f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)            } else if (*position == '(') {
129f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)                appendCharacter(currentDescriptorStart, position);
130f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)                state = InParenthesis;
131f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)            } else {
132f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)                appendCharacter(currentDescriptorStart, position);
133f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)            }
134f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)            break;
135f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        case InParenthesis:
136f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)            if (isEOF(position, attributeEnd)) {
137f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)                appendDescriptorAndReset(attributeStart, currentDescriptorStart, attributeEnd, descriptors);
138f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)                return;
139f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)            }
140f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)            if (*position == ')') {
141f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)                appendCharacter(currentDescriptorStart, position);
142f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)                state = Start;
143f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)            } else {
144f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)                appendCharacter(currentDescriptorStart, position);
145f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)            }
146f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)            break;
147f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        case AfterToken:
148f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)            if (isEOF(position, attributeEnd))
149f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)                return;
150f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)            if (!isHTMLSpace(*position)) {
151f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)                state = Start;
152f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)                currentDescriptorStart = position;
153f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)                --position;
154f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)            }
155f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)            break;
156f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        }
15706f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)        ++position;
158f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    }
159f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)}
160f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)
161f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)template<typename CharType>
162f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)static bool parseDescriptors(const CharType* attribute, Vector<DescriptorToken>& descriptors, DescriptorParsingResult& result)
163f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles){
164f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    for (Vector<DescriptorToken>::iterator it = descriptors.begin(); it != descriptors.end(); ++it) {
165f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        if (it->length == 0)
166f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)            continue;
167f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        CharType c = attribute[it->lastIndex()];
168f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        bool isValid = false;
169f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        if (RuntimeEnabledFeatures::pictureSizesEnabled() && c == 'w') {
170f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)            if (result.hasDensity() || result.hasWidth())
171f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)                return false;
172f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)            int resourceWidth = it->toInt(attribute, isValid);
173f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)            if (!isValid || resourceWidth <= 0)
174f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)                return false;
175f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)            result.setResourceWidth(resourceWidth);
176f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        } else if (RuntimeEnabledFeatures::pictureSizesEnabled() && c == 'h') {
177f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)            // This is here only for future compat purposes.
178f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)            // The value of the 'h' descriptor is not used.
179f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)            if (result.hasDensity() || result.hasHeight())
1806f543c786fc42989f552b4daa774ca5ff32fa697Ben Murdoch                return false;
181f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)            int resourceHeight = it->toInt(attribute, isValid);
182f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)            if (!isValid || resourceHeight <= 0)
1836f543c786fc42989f552b4daa774ca5ff32fa697Ben Murdoch                return false;
184f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)            result.setResourceHeight(resourceHeight);
185f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        } else if (c == 'x') {
186f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)            if (result.hasDensity() || result.hasHeight() || result.hasWidth())
1876f543c786fc42989f552b4daa774ca5ff32fa697Ben Murdoch                return false;
188f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)            float density = it->toFloat(attribute, isValid);
189f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)            if (!isValid || density < 0)
19006f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)                return false;
191f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)            result.setDensity(density);
19206f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)        }
19306f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)    }
194f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    return true;
19506f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)}
19606f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)
197f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)static bool parseDescriptors(const String& attribute, Vector<DescriptorToken>& descriptors, DescriptorParsingResult& result)
198f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles){
199f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    // FIXME: See if StringView can't be extended to replace DescriptorToken here.
200f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    if (attribute.is8Bit()) {
201f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        return parseDescriptors(attribute.characters8(), descriptors, result);
202f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    }
203f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    return parseDescriptors(attribute.characters16(), descriptors, result);
204f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)}
205f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)
206f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)// http://picture.responsiveimages.org/#parse-srcset-attr
20706f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)template<typename CharType>
20806f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)static void parseImageCandidatesFromSrcsetAttribute(const String& attribute, const CharType* attributeStart, unsigned length, Vector<ImageCandidate>& imageCandidates)
20906f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles){
21006f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)    const CharType* position = attributeStart;
21106f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)    const CharType* attributeEnd = position + length;
21206f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)
21306f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)    while (position < attributeEnd) {
214f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        // 4. Splitting loop: Collect a sequence of characters that are space characters or U+002C COMMA characters.
215f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        skipWhile<CharType, isHTMLSpaceOrComma<CharType> >(position, attributeEnd);
216f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        if (position == attributeEnd) {
217f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)            // Contrary to spec language - descriptor parsing happens on each candidate, so when we reach the attributeEnd, we can exit.
21806f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)            break;
21906f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)        }
220f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        const CharType* imageURLStart = position;
221f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        // 6. Collect a sequence of characters that are not space characters, and let that be url.
22206f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)
22306f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)        skipUntil<CharType, isHTMLSpace<CharType> >(position, attributeEnd);
22406f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)        const CharType* imageURLEnd = position;
22506f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)
226f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        DescriptorParsingResult result;
227f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)
228f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        // 8. If url ends with a U+002C COMMA character (,)
229f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        if (isComma(*(position - 1))) {
230f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)            // Remove all trailing U+002C COMMA characters from url.
231f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)            imageURLEnd = position - 1;
232f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)            reverseSkipWhile<CharType, isComma>(imageURLEnd, imageURLStart);
233f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)            ++imageURLEnd;
234f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)            // If url is empty, then jump to the step labeled splitting loop.
235f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)            if (imageURLStart == imageURLEnd)
236f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)                continue;
23706f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)        } else {
238f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)            // Advancing position here (contrary to spec) to avoid an useless extra state machine step.
239f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)            // Filed a spec bug: https://github.com/ResponsiveImagesCG/picture-element/issues/189
240f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)            ++position;
241f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)            Vector<DescriptorToken> descriptorTokens;
242f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)            tokenizeDescriptors(attributeStart, position, attributeEnd, descriptorTokens);
243f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)            // Contrary to spec language - descriptor parsing happens on each candidate.
244f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)            // This is a black-box equivalent, to avoid storing descriptor lists for each candidate.
245f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)            if (!parseDescriptors(attribute, descriptorTokens, result))
24606f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)                continue;
24706f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)        }
24806f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)
2496f543c786fc42989f552b4daa774ca5ff32fa697Ben Murdoch        ASSERT(imageURLEnd > attributeStart);
2506f543c786fc42989f552b4daa774ca5ff32fa697Ben Murdoch        unsigned imageURLStartingPosition = imageURLStart - attributeStart;
2516f543c786fc42989f552b4daa774ca5ff32fa697Ben Murdoch        ASSERT(imageURLEnd > imageURLStart);
2526f543c786fc42989f552b4daa774ca5ff32fa697Ben Murdoch        unsigned imageURLLength = imageURLEnd - imageURLStart;
2536f543c786fc42989f552b4daa774ca5ff32fa697Ben Murdoch        imageCandidates.append(ImageCandidate(attribute, imageURLStartingPosition, imageURLLength, result, ImageCandidate::SrcsetOrigin));
25406f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)        // 11. Return to the step labeled splitting loop.
25506f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)    }
25606f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)}
25706f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)
25806f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)static void parseImageCandidatesFromSrcsetAttribute(const String& attribute, Vector<ImageCandidate>& imageCandidates)
25906f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles){
26006f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)    if (attribute.isNull())
26106f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)        return;
26206f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)
26306f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)    if (attribute.is8Bit())
26406f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)        parseImageCandidatesFromSrcsetAttribute<LChar>(attribute, attribute.characters8(), attribute.length(), imageCandidates);
26506f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)    else
26606f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)        parseImageCandidatesFromSrcsetAttribute<UChar>(attribute, attribute.characters16(), attribute.length(), imageCandidates);
26706f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)}
26806f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)
26910f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdochstatic ImageCandidate pickBestImageCandidate(float deviceScaleFactor, unsigned sourceSize, Vector<ImageCandidate>& imageCandidates)
27006f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles){
271f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    const float defaultDensityValue = 1.0;
2726f543c786fc42989f552b4daa774ca5ff32fa697Ben Murdoch    bool ignoreSrc = false;
27306f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)    if (imageCandidates.isEmpty())
27406f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)        return ImageCandidate();
27506f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)
2766f543c786fc42989f552b4daa774ca5ff32fa697Ben Murdoch    // http://picture.responsiveimages.org/#normalize-source-densities
2776f543c786fc42989f552b4daa774ca5ff32fa697Ben Murdoch    for (Vector<ImageCandidate>::iterator it = imageCandidates.begin(); it != imageCandidates.end(); ++it) {
2786f543c786fc42989f552b4daa774ca5ff32fa697Ben Murdoch        if (it->resourceWidth() > 0) {
279f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)            it->setDensity((float)it->resourceWidth() / (float)sourceSize);
2806f543c786fc42989f552b4daa774ca5ff32fa697Ben Murdoch            ignoreSrc = true;
281f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        } else if (it->density() < 0) {
282f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)            it->setDensity(defaultDensityValue);
2836f543c786fc42989f552b4daa774ca5ff32fa697Ben Murdoch        }
2846f543c786fc42989f552b4daa774ca5ff32fa697Ben Murdoch    }
2856f543c786fc42989f552b4daa774ca5ff32fa697Ben Murdoch
286f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    std::stable_sort(imageCandidates.begin(), imageCandidates.end(), compareByDensity);
28706f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)
28806f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)    unsigned i;
2896f543c786fc42989f552b4daa774ca5ff32fa697Ben Murdoch    for (i = 0; i < imageCandidates.size() - 1; ++i) {
290f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        if ((imageCandidates[i].density() >= deviceScaleFactor) && (!ignoreSrc || !imageCandidates[i].srcOrigin()))
29106f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)            break;
2926f543c786fc42989f552b4daa774ca5ff32fa697Ben Murdoch    }
293d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
294f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu    if (imageCandidates[i].srcOrigin() && ignoreSrc) {
295f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu        ASSERT(i > 0);
296f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu        --i;
297f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu    }
298f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    float winningDensity = imageCandidates[i].density();
299f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liu
300d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    unsigned winner = i;
301d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    // 16. If an entry b in candidates has the same associated ... pixel density as an earlier entry a in candidates,
302d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    // then remove entry b
303f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)    while ((i > 0) && (imageCandidates[--i].density() == winningDensity))
304d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        winner = i;
305d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
306d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    return imageCandidates[winner];
30706f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)}
30806f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)
30910f88d5669dbd969c059d61ba09fa37dd72ac559Ben MurdochImageCandidate bestFitSourceForSrcsetAttribute(float deviceScaleFactor, unsigned sourceSize, const String& srcsetAttribute)
31006f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles){
31106f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)    Vector<ImageCandidate> imageCandidates;
31206f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)
31306f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)    parseImageCandidatesFromSrcsetAttribute(srcsetAttribute, imageCandidates);
31406f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)
31510f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch    return pickBestImageCandidate(deviceScaleFactor, sourceSize, imageCandidates);
31606f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)}
31706f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)
31810f88d5669dbd969c059d61ba09fa37dd72ac559Ben MurdochImageCandidate bestFitSourceForImageAttributes(float deviceScaleFactor, unsigned sourceSize, const String& srcAttribute, const String& srcsetAttribute)
31906f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles){
3201e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    if (srcsetAttribute.isNull()) {
3211e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)        if (srcAttribute.isNull())
3221e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)            return ImageCandidate();
323f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        return ImageCandidate(srcAttribute, 0, srcAttribute.length(), DescriptorParsingResult(), ImageCandidate::SrcOrigin);
3241e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    }
32506f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)
32606f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)    Vector<ImageCandidate> imageCandidates;
32706f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)
32806f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)    parseImageCandidatesFromSrcsetAttribute(srcsetAttribute, imageCandidates);
32906f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)
33006f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)    if (!srcAttribute.isEmpty())
331f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        imageCandidates.append(ImageCandidate(srcAttribute, 0, srcAttribute.length(), DescriptorParsingResult(), ImageCandidate::SrcOrigin));
33206f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)
33310f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch    return pickBestImageCandidate(deviceScaleFactor, sourceSize, imageCandidates);
33406f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)}
33506f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)
33610f88d5669dbd969c059d61ba09fa37dd72ac559Ben MurdochString bestFitSourceForImageAttributes(float deviceScaleFactor, unsigned sourceSize, const String& srcAttribute, ImageCandidate& srcsetImageCandidate)
33706f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles){
33806f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)    if (srcsetImageCandidate.isEmpty())
33906f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)        return srcAttribute;
34006f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)
34106f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)    Vector<ImageCandidate> imageCandidates;
34206f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)    imageCandidates.append(srcsetImageCandidate);
34306f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)
34406f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)    if (!srcAttribute.isEmpty())
345f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)        imageCandidates.append(ImageCandidate(srcAttribute, 0, srcAttribute.length(), DescriptorParsingResult(), ImageCandidate::SrcOrigin));
34606f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)
34710f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch    return pickBestImageCandidate(deviceScaleFactor, sourceSize, imageCandidates).toString();
34806f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)}
34906f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)
35006f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)}
351