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