Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (C) 2013 Google Inc. All rights reserved. | 2 * Copyright (C) 2013 Google Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
| 6 * met: | 6 * met: |
| 7 * | 7 * |
| 8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 30 | 30 |
| 31 #include "config.h" | 31 #include "config.h" |
| 32 #include "core/html/parser/HTMLSrcsetParser.h" | 32 #include "core/html/parser/HTMLSrcsetParser.h" |
| 33 | 33 |
| 34 #include "RuntimeEnabledFeatures.h" | 34 #include "RuntimeEnabledFeatures.h" |
| 35 #include "core/html/parser/HTMLParserIdioms.h" | 35 #include "core/html/parser/HTMLParserIdioms.h" |
| 36 #include "platform/ParsingUtilities.h" | 36 #include "platform/ParsingUtilities.h" |
| 37 | 37 |
| 38 namespace WebCore { | 38 namespace WebCore { |
| 39 | 39 |
| 40 static bool compareByScaleFactor(const ImageCandidate& first, const ImageCandida te& second) | 40 static bool compareByDensity(const ImageCandidate& first, const ImageCandidate& second) |
| 41 { | 41 { |
| 42 return first.scaleFactor() < second.scaleFactor(); | 42 return first.density() < second.density(); |
| 43 } | |
| 44 | |
| 45 enum DescriptorTokenizerState { | |
| 46 Start, | |
| 47 InParenthesis, | |
| 48 AfterToken, | |
| 49 }; | |
| 50 | |
| 51 struct DescriptorToken { | |
| 52 unsigned start; | |
| 53 unsigned length; | |
| 54 DescriptorToken(unsigned start, unsigned length) | |
| 55 : start(start) | |
| 56 , length(length) | |
| 57 { | |
| 58 } | |
| 59 }; | |
| 60 | |
| 61 template<typename CharType> | |
| 62 static void appendDescriptorAndReset(const CharType* attributeStart, const CharT ype*& descriptorStart, const CharType* position, Vector<DescriptorToken>& descri ptors) | |
| 63 { | |
| 64 if (position > descriptorStart) | |
| 65 descriptors.append(DescriptorToken(descriptorStart - attributeStart, pos ition - descriptorStart)); | |
| 66 descriptorStart = 0; | |
| 67 } | |
| 68 | |
| 69 // The following is called appendCharacter to match the spec's terminology. | |
| 70 template<typename CharType> | |
| 71 static void appendCharacter(const CharType* descriptorStart, const CharType* pos ition) | |
| 72 { | |
| 73 // Since we don't copy the tokens, this just set the point where the descrip tor tokens start. | |
| 74 if (!descriptorStart) | |
| 75 descriptorStart = position; | |
| 43 } | 76 } |
| 44 | 77 |
| 45 template<typename CharType> | 78 template<typename CharType> |
| 46 inline bool isComma(CharType character) | 79 static bool isEOF(const CharType* position, const CharType* end) |
| 47 { | 80 { |
| 48 return character == ','; | 81 return position >= end; |
| 49 } | 82 } |
| 50 | 83 |
| 51 template<typename CharType> | 84 template<typename CharType> |
| 52 static bool parseDescriptors(const CharType* descriptorsStart, const CharType* d escriptorsEnd, DescriptorParsingResult& result) | 85 static void tokenizeDescriptors(const CharType* attributeStart, |
| 86 const CharType*& position, | |
| 87 const CharType* attributeEnd, | |
| 88 Vector<DescriptorToken>& descriptors) | |
| 53 { | 89 { |
| 54 const CharType* position = descriptorsStart; | 90 DescriptorTokenizerState state = Start; |
| 55 bool isValid = false; | 91 const CharType* descriptorsStart = position; |
| 56 bool isEmptyDescriptor = !(descriptorsEnd > descriptorsStart); | 92 const CharType* currentDescriptorStart = descriptorsStart; |
| 57 while (position < descriptorsEnd) { | 93 while (true) { |
| 58 // 13.1. Let descriptor list be the result of splitting unparsed descrip tors on spaces. | 94 switch (state) { |
| 59 skipWhile<CharType, isHTMLSpace<CharType> >(position, descriptorsEnd); | 95 case Start: |
| 60 const CharType* currentDescriptorStart = position; | 96 if (isEOF(position, attributeEnd)) { |
| 61 skipWhile<CharType, isNotHTMLSpace<CharType> >(position, descriptorsEnd) ; | 97 appendDescriptorAndReset(attributeStart, currentDescriptorStart, attributeEnd, descriptors); |
| 62 const CharType* currentDescriptorEnd = position; | 98 return; |
| 99 } | |
| 100 if (isComma(*position)) { | |
| 101 appendDescriptorAndReset(attributeStart, currentDescriptorStart, position, descriptors); | |
| 102 ++position; | |
| 103 return; | |
| 104 } | |
| 105 if (isHTMLSpace(*position)) { | |
| 106 appendDescriptorAndReset(attributeStart, currentDescriptorStart, position, descriptors); | |
| 107 currentDescriptorStart = position + 1; | |
| 108 state = AfterToken; | |
| 109 } else if (*position == '(') { | |
| 110 appendCharacter(currentDescriptorStart, position); | |
| 111 state = InParenthesis; | |
| 112 } else { | |
| 113 appendCharacter(currentDescriptorStart, position); | |
| 114 } | |
| 115 break; | |
| 116 case InParenthesis: | |
| 117 if (isEOF(position, attributeEnd)) { | |
| 118 appendDescriptorAndReset(attributeStart, currentDescriptorStart, attributeEnd, descriptors); | |
| 119 return; | |
| 120 } | |
| 121 if (*position == ')') { | |
| 122 appendCharacter(currentDescriptorStart, position); | |
| 123 state = Start; | |
| 124 } else { | |
| 125 appendCharacter(currentDescriptorStart, position); | |
| 126 } | |
| 127 break; | |
| 128 case AfterToken: | |
| 129 if (isEOF(position, attributeEnd)) | |
| 130 return; | |
| 131 if (!isHTMLSpace(*position)) { | |
| 132 state = Start; | |
| 133 currentDescriptorStart = position; | |
| 134 --position; | |
| 135 } | |
| 136 break; | |
| 137 } | |
| 138 ++position; | |
| 139 } | |
| 140 } | |
| 63 | 141 |
| 64 ++position; | 142 template<typename CharType> |
| 65 ASSERT(currentDescriptorEnd > currentDescriptorStart); | 143 static bool parseDescriptors(const CharType* attribute, Vector<DescriptorToken>& descriptors, DescriptorParsingResult& result) |
| 66 --currentDescriptorEnd; | 144 { |
| 67 unsigned descriptorLength = currentDescriptorEnd - currentDescriptorStar t; | 145 for (Vector<DescriptorToken>::iterator it = descriptors.begin(); it != descr iptors.end(); ++it) { |
| 68 if (*currentDescriptorEnd == 'x') { | 146 if (it->length == 0) |
| 69 if (result.foundDescriptor()) | 147 continue; |
| 148 CharType c = attribute[it->start + it->length - 1]; | |
|
eseidel
2014/05/29 06:59:53
Should DescriptorToken have a helper for this valu
| |
| 149 bool isValid = false; | |
| 150 if (RuntimeEnabledFeatures::pictureSizesEnabled() && c == 'w') { | |
| 151 if (result.hasDensity() || result.hasWidth()) | |
| 70 return false; | 152 return false; |
| 71 result.scaleFactor = charactersToFloat(currentDescriptorStart, descr iptorLength, &isValid); | 153 int resourceWidth = charactersToInt(attribute + it->start, it->lengt h - 1, &isValid); |
|
eseidel
2014/05/29 06:59:53
Should charactersToInt be a member on DescriptorTo
| |
| 72 if (!isValid || result.scaleFactor < 0) | 154 if (!isValid || resourceWidth <= 0) |
| 73 return false; | 155 return false; |
| 74 } else if (RuntimeEnabledFeatures::pictureSizesEnabled() && *currentDesc riptorEnd == 'w') { | 156 result.setResourceWidth(resourceWidth); |
| 75 if (result.foundDescriptor()) | 157 } else if (RuntimeEnabledFeatures::pictureSizesEnabled() && c == 'h') { |
| 158 // This is here only for future compat purposes. | |
| 159 // The value of the 'h' descriptor is not used. | |
| 160 if (result.hasDensity() || result.hasHeight()) | |
| 76 return false; | 161 return false; |
| 77 result.resourceWidth = charactersToInt(currentDescriptorStart, descr iptorLength, &isValid); | 162 int resourceHeight = charactersToInt(attribute + it->start, it->leng th - 1, &isValid); |
| 78 if (!isValid || result.resourceWidth <= 0) | 163 if (!isValid || resourceHeight <= 0) |
| 79 return false; | 164 return false; |
| 165 result.setResourceHeight(resourceHeight); | |
| 166 } else if (c == 'x') { | |
| 167 if (result.hasDensity() || result.hasHeight() || result.hasWidth()) | |
| 168 return false; | |
| 169 int density = charactersToFloat(attribute + it->start, it->length - 1, &isValid); | |
| 170 if (!isValid || density < 0) | |
| 171 return false; | |
| 172 result.setDensity(density); | |
| 80 } | 173 } |
| 81 } | 174 } |
| 82 if (isEmptyDescriptor) | 175 return true; |
| 83 result.scaleFactor = 1.0; | |
| 84 return result.foundDescriptor(); | |
| 85 } | 176 } |
| 86 | 177 |
| 87 // http://www.whatwg.org/specs/web-apps/current-work/multipage/embedded-content- 1.html#processing-the-image-candidates | 178 static bool parseDescriptors(const String& attribute, Vector<DescriptorToken>& d escriptors, DescriptorParsingResult& result) |
| 179 { | |
| 180 // FIXME: See if StringView can't be extended to replace DescriptorToken her e. | |
| 181 if (attribute.is8Bit()) { | |
| 182 return parseDescriptors(attribute.characters8(), descriptors, result); | |
| 183 } | |
| 184 return parseDescriptors(attribute.characters16(), descriptors, result); | |
| 185 } | |
| 186 | |
| 187 // http://picture.responsiveimages.org/#parse-srcset-attr | |
| 88 template<typename CharType> | 188 template<typename CharType> |
| 89 static void parseImageCandidatesFromSrcsetAttribute(const String& attribute, con st CharType* attributeStart, unsigned length, Vector<ImageCandidate>& imageCandi dates) | 189 static void parseImageCandidatesFromSrcsetAttribute(const String& attribute, con st CharType* attributeStart, unsigned length, Vector<ImageCandidate>& imageCandi dates) |
| 90 { | 190 { |
| 91 const CharType* position = attributeStart; | 191 const CharType* position = attributeStart; |
| 92 const CharType* attributeEnd = position + length; | 192 const CharType* attributeEnd = position + length; |
| 93 | 193 |
| 94 while (position < attributeEnd) { | 194 while (position < attributeEnd) { |
| 95 DescriptorParsingResult result; | 195 // 4. Splitting loop: Collect a sequence of characters that are space ch aracters or U+002C COMMA characters. |
| 96 // 4. Splitting loop: Skip whitespace. | 196 skipWhile<CharType, isHTMLSpaceOrComma<CharType> >(position, attributeEn d); |
| 97 skipWhile<CharType, isHTMLSpace<CharType> >(position, attributeEnd); | 197 if (position == attributeEnd) { |
| 98 if (position == attributeEnd) | 198 // Contrary to spec language - descriptor parsing happens on each ca ndidate, so when we reach the attributeEnd, we can exit. |
| 99 break; | 199 break; |
| 200 } | |
| 100 const CharType* imageURLStart = position; | 201 const CharType* imageURLStart = position; |
| 202 // 6. Collect a sequence of characters that are not space characters, an d let that be url. | |
| 101 | 203 |
| 102 // If The current candidate is either totally empty or only contains spa ce, skipping. | |
| 103 if (*position == ',') { | |
| 104 ++position; | |
| 105 continue; | |
| 106 } | |
| 107 | |
| 108 // 5. Collect a sequence of characters that are not space characters, an d let that be url. | |
| 109 skipUntil<CharType, isHTMLSpace<CharType> >(position, attributeEnd); | 204 skipUntil<CharType, isHTMLSpace<CharType> >(position, attributeEnd); |
| 110 const CharType* imageURLEnd = position; | 205 const CharType* imageURLEnd = position; |
| 111 | 206 |
| 112 if (position != attributeEnd && *(position - 1) == ',') { | 207 DescriptorParsingResult result; |
| 113 --imageURLEnd; | 208 |
| 114 result.scaleFactor = 1.0; | 209 // 8. If url ends with a U+002C COMMA character (,) |
| 210 if (isComma(*(position - 1))) { | |
| 211 // Remove all trailing U+002C COMMA characters from url. | |
| 212 imageURLEnd = position - 1; | |
| 213 reverseSkipWhile<CharType, isComma>(imageURLEnd, imageURLStart); | |
| 214 ++imageURLEnd; | |
| 215 // If url is empty, then jump to the step labeled splitting loop. | |
| 216 if (imageURLStart == imageURLEnd) | |
| 217 continue; | |
| 115 } else { | 218 } else { |
| 116 // 7. Collect a sequence of characters that are not "," (U+002C) cha racters, and let that be descriptors. | 219 // Advancing position here (contrary to spec) to avoid an useless ex tra state machine step. |
| 117 skipWhile<CharType, isHTMLSpace<CharType> >(position, attributeEnd); | 220 // Filed a spec bug: https://github.com/ResponsiveImagesCG/picture-e lement/issues/189 |
| 118 const CharType* descriptorsStart = position; | 221 ++position; |
| 119 skipUntil<CharType, isComma<CharType> >(position, attributeEnd); | 222 Vector<DescriptorToken> descriptorTokens; |
| 120 const CharType* descriptorsEnd = position; | 223 tokenizeDescriptors(attributeStart, position, attributeEnd, descript orTokens); |
| 121 if (!parseDescriptors(descriptorsStart, descriptorsEnd, result)) | 224 // Contrary to spec language - descriptor parsing happens on each ca ndidate. |
| 225 // This is a black-box equivalent, to avoid storing descriptor lists for each candidate. | |
| 226 if (!parseDescriptors(attribute, descriptorTokens, result)) | |
| 122 continue; | 227 continue; |
| 123 } | 228 } |
| 124 | 229 |
| 125 ASSERT(imageURLEnd > attributeStart); | 230 ASSERT(imageURLEnd > attributeStart); |
| 126 unsigned imageURLStartingPosition = imageURLStart - attributeStart; | 231 unsigned imageURLStartingPosition = imageURLStart - attributeStart; |
| 127 ASSERT(imageURLEnd > imageURLStart); | 232 ASSERT(imageURLEnd > imageURLStart); |
| 128 unsigned imageURLLength = imageURLEnd - imageURLStart; | 233 unsigned imageURLLength = imageURLEnd - imageURLStart; |
| 129 imageCandidates.append(ImageCandidate(attribute, imageURLStartingPositio n, imageURLLength, result, ImageCandidate::SrcsetOrigin)); | 234 imageCandidates.append(ImageCandidate(attribute, imageURLStartingPositio n, imageURLLength, result, ImageCandidate::SrcsetOrigin)); |
| 130 // 11. Return to the step labeled splitting loop. | 235 // 11. Return to the step labeled splitting loop. |
| 131 } | 236 } |
| 132 } | 237 } |
| 133 | 238 |
| 134 static void parseImageCandidatesFromSrcsetAttribute(const String& attribute, Vec tor<ImageCandidate>& imageCandidates) | 239 static void parseImageCandidatesFromSrcsetAttribute(const String& attribute, Vec tor<ImageCandidate>& imageCandidates) |
| 135 { | 240 { |
| 136 if (attribute.isNull()) | 241 if (attribute.isNull()) |
| 137 return; | 242 return; |
| 138 | 243 |
| 139 if (attribute.is8Bit()) | 244 if (attribute.is8Bit()) |
| 140 parseImageCandidatesFromSrcsetAttribute<LChar>(attribute, attribute.char acters8(), attribute.length(), imageCandidates); | 245 parseImageCandidatesFromSrcsetAttribute<LChar>(attribute, attribute.char acters8(), attribute.length(), imageCandidates); |
| 141 else | 246 else |
| 142 parseImageCandidatesFromSrcsetAttribute<UChar>(attribute, attribute.char acters16(), attribute.length(), imageCandidates); | 247 parseImageCandidatesFromSrcsetAttribute<UChar>(attribute, attribute.char acters16(), attribute.length(), imageCandidates); |
| 143 } | 248 } |
| 144 | 249 |
| 145 static ImageCandidate pickBestImageCandidate(float deviceScaleFactor, unsigned s ourceSize, Vector<ImageCandidate>& imageCandidates) | 250 static ImageCandidate pickBestImageCandidate(float deviceScaleFactor, unsigned s ourceSize, Vector<ImageCandidate>& imageCandidates) |
| 146 { | 251 { |
| 252 const float defaultDensityValue = 1.0; | |
| 147 bool ignoreSrc = false; | 253 bool ignoreSrc = false; |
| 148 if (imageCandidates.isEmpty()) | 254 if (imageCandidates.isEmpty()) |
| 149 return ImageCandidate(); | 255 return ImageCandidate(); |
| 150 | 256 |
| 151 // http://picture.responsiveimages.org/#normalize-source-densities | 257 // http://picture.responsiveimages.org/#normalize-source-densities |
| 152 for (Vector<ImageCandidate>::iterator it = imageCandidates.begin(); it != im ageCandidates.end(); ++it) { | 258 for (Vector<ImageCandidate>::iterator it = imageCandidates.begin(); it != im ageCandidates.end(); ++it) { |
| 153 if (it->resourceWidth() > 0) { | 259 if (it->resourceWidth() > 0) { |
| 154 it->setScaleFactor((float)it->resourceWidth() / (float)sourceSize); | 260 it->setDensity((float)it->resourceWidth() / (float)sourceSize); |
| 155 ignoreSrc = true; | 261 ignoreSrc = true; |
| 262 } else if (it->density() < 0) { | |
| 263 it->setDensity(defaultDensityValue); | |
| 156 } | 264 } |
| 157 } | 265 } |
| 158 | 266 |
| 159 std::stable_sort(imageCandidates.begin(), imageCandidates.end(), compareBySc aleFactor); | 267 std::stable_sort(imageCandidates.begin(), imageCandidates.end(), compareByDe nsity); |
| 160 | 268 |
| 161 unsigned i; | 269 unsigned i; |
| 162 for (i = 0; i < imageCandidates.size() - 1; ++i) { | 270 for (i = 0; i < imageCandidates.size() - 1; ++i) { |
| 163 if ((imageCandidates[i].scaleFactor() >= deviceScaleFactor) && (!ignoreS rc || !imageCandidates[i].srcOrigin())) | 271 if ((imageCandidates[i].density() >= deviceScaleFactor) && (!ignoreSrc | | !imageCandidates[i].srcOrigin())) |
| 164 break; | 272 break; |
| 165 } | 273 } |
| 166 | 274 |
| 167 if (imageCandidates[i].srcOrigin() && ignoreSrc) { | 275 if (imageCandidates[i].srcOrigin() && ignoreSrc) { |
| 168 ASSERT(i > 0); | 276 ASSERT(i > 0); |
| 169 --i; | 277 --i; |
| 170 } | 278 } |
| 171 float winningScaleFactor = imageCandidates[i].scaleFactor(); | 279 float winningDensity = imageCandidates[i].density(); |
| 172 | 280 |
| 173 unsigned winner = i; | 281 unsigned winner = i; |
| 174 // 16. If an entry b in candidates has the same associated ... pixel density as an earlier entry a in candidates, | 282 // 16. If an entry b in candidates has the same associated ... pixel density as an earlier entry a in candidates, |
| 175 // then remove entry b | 283 // then remove entry b |
| 176 while ((i > 0) && (imageCandidates[--i].scaleFactor() == winningScaleFactor) ) | 284 while ((i > 0) && (imageCandidates[--i].density() == winningDensity)) |
| 177 winner = i; | 285 winner = i; |
| 178 | 286 |
| 179 return imageCandidates[winner]; | 287 return imageCandidates[winner]; |
| 180 } | 288 } |
| 181 | 289 |
| 182 ImageCandidate bestFitSourceForSrcsetAttribute(float deviceScaleFactor, unsigned sourceSize, const String& srcsetAttribute) | 290 ImageCandidate bestFitSourceForSrcsetAttribute(float deviceScaleFactor, unsigned sourceSize, const String& srcsetAttribute) |
| 183 { | 291 { |
| 184 Vector<ImageCandidate> imageCandidates; | 292 Vector<ImageCandidate> imageCandidates; |
| 185 | 293 |
| 186 parseImageCandidatesFromSrcsetAttribute(srcsetAttribute, imageCandidates); | 294 parseImageCandidatesFromSrcsetAttribute(srcsetAttribute, imageCandidates); |
| 187 | 295 |
| 188 return pickBestImageCandidate(deviceScaleFactor, sourceSize, imageCandidates ); | 296 return pickBestImageCandidate(deviceScaleFactor, sourceSize, imageCandidates ); |
| 189 } | 297 } |
| 190 | 298 |
| 191 ImageCandidate bestFitSourceForImageAttributes(float deviceScaleFactor, unsigned sourceSize, const String& srcAttribute, const String& srcsetAttribute) | 299 ImageCandidate bestFitSourceForImageAttributes(float deviceScaleFactor, unsigned sourceSize, const String& srcAttribute, const String& srcsetAttribute) |
| 192 { | 300 { |
| 193 DescriptorParsingResult defaultResult; | |
| 194 defaultResult.scaleFactor = 1.0; | |
| 195 | |
| 196 if (srcsetAttribute.isNull()) { | 301 if (srcsetAttribute.isNull()) { |
| 197 if (srcAttribute.isNull()) | 302 if (srcAttribute.isNull()) |
| 198 return ImageCandidate(); | 303 return ImageCandidate(); |
| 199 return ImageCandidate(srcAttribute, 0, srcAttribute.length(), defaultRes ult, ImageCandidate::SrcOrigin); | 304 return ImageCandidate(srcAttribute, 0, srcAttribute.length(), Descriptor ParsingResult(), ImageCandidate::SrcOrigin); |
| 200 } | 305 } |
| 201 | 306 |
| 202 Vector<ImageCandidate> imageCandidates; | 307 Vector<ImageCandidate> imageCandidates; |
| 203 | 308 |
| 204 parseImageCandidatesFromSrcsetAttribute(srcsetAttribute, imageCandidates); | 309 parseImageCandidatesFromSrcsetAttribute(srcsetAttribute, imageCandidates); |
| 205 | 310 |
| 206 if (!srcAttribute.isEmpty()) | 311 if (!srcAttribute.isEmpty()) |
| 207 imageCandidates.append(ImageCandidate(srcAttribute, 0, srcAttribute.leng th(), defaultResult, ImageCandidate::SrcOrigin)); | 312 imageCandidates.append(ImageCandidate(srcAttribute, 0, srcAttribute.leng th(), DescriptorParsingResult(), ImageCandidate::SrcOrigin)); |
| 208 | 313 |
| 209 return pickBestImageCandidate(deviceScaleFactor, sourceSize, imageCandidates ); | 314 return pickBestImageCandidate(deviceScaleFactor, sourceSize, imageCandidates ); |
| 210 } | 315 } |
| 211 | 316 |
| 212 String bestFitSourceForImageAttributes(float deviceScaleFactor, unsigned sourceS ize, const String& srcAttribute, ImageCandidate& srcsetImageCandidate) | 317 String bestFitSourceForImageAttributes(float deviceScaleFactor, unsigned sourceS ize, const String& srcAttribute, ImageCandidate& srcsetImageCandidate) |
| 213 { | 318 { |
| 214 DescriptorParsingResult defaultResult; | |
| 215 defaultResult.scaleFactor = 1.0; | |
| 216 | |
| 217 if (srcsetImageCandidate.isEmpty()) | 319 if (srcsetImageCandidate.isEmpty()) |
| 218 return srcAttribute; | 320 return srcAttribute; |
| 219 | 321 |
| 220 Vector<ImageCandidate> imageCandidates; | 322 Vector<ImageCandidate> imageCandidates; |
| 221 imageCandidates.append(srcsetImageCandidate); | 323 imageCandidates.append(srcsetImageCandidate); |
| 222 | 324 |
| 223 if (!srcAttribute.isEmpty()) | 325 if (!srcAttribute.isEmpty()) |
| 224 imageCandidates.append(ImageCandidate(srcAttribute, 0, srcAttribute.leng th(), defaultResult, ImageCandidate::SrcOrigin)); | 326 imageCandidates.append(ImageCandidate(srcAttribute, 0, srcAttribute.leng th(), DescriptorParsingResult(), ImageCandidate::SrcOrigin)); |
| 225 | 327 |
| 226 return pickBestImageCandidate(deviceScaleFactor, sourceSize, imageCandidates ).toString(); | 328 return pickBestImageCandidate(deviceScaleFactor, sourceSize, imageCandidates ).toString(); |
| 227 } | 329 } |
| 228 | 330 |
| 229 } | 331 } |
| OLD | NEW |