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 13 matching lines...) Expand all Loading... |
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
29 */ | 29 */ |
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 "core/html/parser/HTMLParserIdioms.h" | 35 #include "core/html/parser/HTMLParserIdioms.h" |
35 #include "platform/ParsingUtilities.h" | 36 #include "platform/ParsingUtilities.h" |
36 | 37 |
37 namespace WebCore { | 38 namespace WebCore { |
38 | 39 |
39 static bool compareByScaleFactor(const ImageCandidate& first, const ImageCandida
te& second) | 40 static bool compareByScaleFactor(const ImageCandidate& first, const ImageCandida
te& second) |
40 { | 41 { |
41 return first.scaleFactor() < second.scaleFactor(); | 42 return first.scaleFactor() < second.scaleFactor(); |
42 } | 43 } |
43 | 44 |
44 template<typename CharType> | 45 template<typename CharType> |
45 inline bool isComma(CharType character) | 46 inline bool isComma(CharType character) |
46 { | 47 { |
47 return character == ','; | 48 return character == ','; |
48 } | 49 } |
49 | 50 |
50 template<typename CharType> | 51 template<typename CharType> |
51 static bool parseDescriptors(const CharType* descriptorsStart, const CharType* d
escriptorsEnd, float& imgScaleFactor) | 52 static bool parseDescriptors(const CharType* descriptorsStart, const CharType* d
escriptorsEnd, DescriptorParsingResult& result) |
52 { | 53 { |
53 const CharType* position = descriptorsStart; | 54 const CharType* position = descriptorsStart; |
54 bool isValid = false; | 55 bool isValid = false; |
55 bool isFoundScaleFactor = false; | |
56 bool isEmptyDescriptor = !(descriptorsEnd > descriptorsStart); | 56 bool isEmptyDescriptor = !(descriptorsEnd > descriptorsStart); |
57 while (position < descriptorsEnd) { | 57 while (position < descriptorsEnd) { |
58 // 13.1. Let descriptor list be the result of splitting unparsed descrip
tors on spaces. | 58 // 13.1. Let descriptor list be the result of splitting unparsed descrip
tors on spaces. |
59 skipWhile<CharType, isHTMLSpace<CharType> >(position, descriptorsEnd); | 59 skipWhile<CharType, isHTMLSpace<CharType> >(position, descriptorsEnd); |
60 const CharType* currentDescriptorStart = position; | 60 const CharType* currentDescriptorStart = position; |
61 skipWhile<CharType, isNotHTMLSpace<CharType> >(position, descriptorsEnd)
; | 61 skipWhile<CharType, isNotHTMLSpace<CharType> >(position, descriptorsEnd)
; |
62 const CharType* currentDescriptorEnd = position; | 62 const CharType* currentDescriptorEnd = position; |
63 | 63 |
64 ++position; | 64 ++position; |
65 ASSERT(currentDescriptorEnd > currentDescriptorStart); | 65 ASSERT(currentDescriptorEnd > currentDescriptorStart); |
66 --currentDescriptorEnd; | 66 --currentDescriptorEnd; |
67 unsigned descriptorLength = currentDescriptorEnd - currentDescriptorStar
t; | 67 unsigned descriptorLength = currentDescriptorEnd - currentDescriptorStar
t; |
68 if (*currentDescriptorEnd == 'x') { | 68 if (*currentDescriptorEnd == 'x') { |
69 if (isFoundScaleFactor) | 69 if (result.foundDescriptor()) |
70 return false; | 70 return false; |
71 imgScaleFactor = charactersToFloat(currentDescriptorStart, descripto
rLength, &isValid); | 71 result.scaleFactor = charactersToFloat(currentDescriptorStart, descr
iptorLength, &isValid); |
72 isFoundScaleFactor = true; | 72 if (!isValid || result.scaleFactor < 0) |
73 } else { | 73 return false; |
74 continue; | 74 } else if (RuntimeEnabledFeatures::pictureSizesEnabled() && *currentDesc
riptorEnd == 'w') { |
| 75 if (result.foundDescriptor()) |
| 76 return false; |
| 77 result.resourceWidth = charactersToInt(currentDescriptorStart, descr
iptorLength, &isValid); |
| 78 if (!isValid || result.resourceWidth < 0) |
| 79 return false; |
75 } | 80 } |
76 } | 81 } |
77 return isEmptyDescriptor || isValid; | 82 if (isEmptyDescriptor) |
| 83 result.scaleFactor = 1.0; |
| 84 return result.foundDescriptor(); |
78 } | 85 } |
79 | 86 |
80 // http://www.whatwg.org/specs/web-apps/current-work/multipage/embedded-content-
1.html#processing-the-image-candidates | 87 // http://www.whatwg.org/specs/web-apps/current-work/multipage/embedded-content-
1.html#processing-the-image-candidates |
81 template<typename CharType> | 88 template<typename CharType> |
82 static void parseImageCandidatesFromSrcsetAttribute(const String& attribute, con
st CharType* attributeStart, unsigned length, Vector<ImageCandidate>& imageCandi
dates) | 89 static void parseImageCandidatesFromSrcsetAttribute(const String& attribute, con
st CharType* attributeStart, unsigned length, Vector<ImageCandidate>& imageCandi
dates) |
83 { | 90 { |
84 const CharType* position = attributeStart; | 91 const CharType* position = attributeStart; |
85 const CharType* attributeEnd = position + length; | 92 const CharType* attributeEnd = position + length; |
86 | 93 |
87 while (position < attributeEnd) { | 94 while (position < attributeEnd) { |
88 float imgScaleFactor = 1.0; | 95 DescriptorParsingResult result; |
89 | |
90 // 4. Splitting loop: Skip whitespace. | 96 // 4. Splitting loop: Skip whitespace. |
91 skipWhile<CharType, isHTMLSpace<CharType> >(position, attributeEnd); | 97 skipWhile<CharType, isHTMLSpace<CharType> >(position, attributeEnd); |
92 if (position == attributeEnd) | 98 if (position == attributeEnd) |
93 break; | 99 break; |
94 const CharType* imageURLStart = position; | 100 const CharType* imageURLStart = position; |
95 | 101 |
96 // If The current candidate is either totally empty or only contains spa
ce, skipping. | 102 // If The current candidate is either totally empty or only contains spa
ce, skipping. |
97 if (*position == ',') { | 103 if (*position == ',') { |
98 ++position; | 104 ++position; |
99 continue; | 105 continue; |
100 } | 106 } |
101 | 107 |
102 // 5. Collect a sequence of characters that are not space characters, an
d let that be url. | 108 // 5. Collect a sequence of characters that are not space characters, an
d let that be url. |
103 skipUntil<CharType, isHTMLSpace<CharType> >(position, attributeEnd); | 109 skipUntil<CharType, isHTMLSpace<CharType> >(position, attributeEnd); |
104 const CharType* imageURLEnd = position; | 110 const CharType* imageURLEnd = position; |
105 | 111 |
106 if (position != attributeEnd && *(position - 1) == ',') { | 112 if (position != attributeEnd && *(position - 1) == ',') { |
107 --imageURLEnd; | 113 --imageURLEnd; |
| 114 result.scaleFactor = 1.0; |
108 } else { | 115 } else { |
109 // 7. Collect a sequence of characters that are not "," (U+002C) cha
racters, and let that be descriptors. | 116 // 7. Collect a sequence of characters that are not "," (U+002C) cha
racters, and let that be descriptors. |
110 skipWhile<CharType, isHTMLSpace<CharType> >(position, attributeEnd); | 117 skipWhile<CharType, isHTMLSpace<CharType> >(position, attributeEnd); |
111 const CharType* descriptorsStart = position; | 118 const CharType* descriptorsStart = position; |
112 skipUntil<CharType, isComma<CharType> >(position, attributeEnd); | 119 skipUntil<CharType, isComma<CharType> >(position, attributeEnd); |
113 const CharType* descriptorsEnd = position; | 120 const CharType* descriptorsEnd = position; |
114 if (!parseDescriptors(descriptorsStart, descriptorsEnd, imgScaleFact
or)) | 121 if (!parseDescriptors(descriptorsStart, descriptorsEnd, result)) |
115 continue; | 122 continue; |
116 } | 123 } |
117 | 124 |
118 imageCandidates.append(ImageCandidate(attribute, imageURLStart - attribu
teStart, imageURLEnd - imageURLStart, imgScaleFactor)); | 125 imageCandidates.append(ImageCandidate(attribute, imageURLStart - attribu
teStart, imageURLEnd - imageURLStart, result)); |
119 // 11. Return to the step labeled splitting loop. | 126 // 11. Return to the step labeled splitting loop. |
120 } | 127 } |
121 } | 128 } |
122 | 129 |
123 static void parseImageCandidatesFromSrcsetAttribute(const String& attribute, Vec
tor<ImageCandidate>& imageCandidates) | 130 static void parseImageCandidatesFromSrcsetAttribute(const String& attribute, Vec
tor<ImageCandidate>& imageCandidates) |
124 { | 131 { |
125 if (attribute.isNull()) | 132 if (attribute.isNull()) |
126 return; | 133 return; |
127 | 134 |
128 if (attribute.is8Bit()) | 135 if (attribute.is8Bit()) |
129 parseImageCandidatesFromSrcsetAttribute<LChar>(attribute, attribute.char
acters8(), attribute.length(), imageCandidates); | 136 parseImageCandidatesFromSrcsetAttribute<LChar>(attribute, attribute.char
acters8(), attribute.length(), imageCandidates); |
130 else | 137 else |
131 parseImageCandidatesFromSrcsetAttribute<UChar>(attribute, attribute.char
acters16(), attribute.length(), imageCandidates); | 138 parseImageCandidatesFromSrcsetAttribute<UChar>(attribute, attribute.char
acters16(), attribute.length(), imageCandidates); |
132 } | 139 } |
133 | 140 |
134 static ImageCandidate pickBestImageCandidate(float deviceScaleFactor, Vector<Ima
geCandidate>& imageCandidates) | 141 static ImageCandidate pickBestImageCandidate(float deviceScaleFactor, int effect
iveSize, Vector<ImageCandidate>& imageCandidates) |
135 { | 142 { |
136 if (imageCandidates.isEmpty()) | 143 if (imageCandidates.isEmpty()) |
137 return ImageCandidate(); | 144 return ImageCandidate(); |
138 | 145 |
| 146 // http://picture.responsiveimages.org/#normalize-source-densities |
| 147 for (Vector<ImageCandidate>::iterator it = imageCandidates.begin(); it != im
ageCandidates.end(); ++it) { |
| 148 if (it->scaleFactor() < 0) |
| 149 it->setScaleFactor((float)it->resourceWidth() / (float)effectiveSize
); |
| 150 } |
| 151 |
139 std::stable_sort(imageCandidates.begin(), imageCandidates.end(), compareBySc
aleFactor); | 152 std::stable_sort(imageCandidates.begin(), imageCandidates.end(), compareBySc
aleFactor); |
140 | 153 |
141 unsigned i; | 154 unsigned i; |
142 for (i = 0; i < imageCandidates.size() - 1; ++i) | 155 for (i = 0; i < imageCandidates.size() - 1; ++i) { |
143 if (imageCandidates[i].scaleFactor() >= deviceScaleFactor) | 156 if (imageCandidates[i].scaleFactor() >= deviceScaleFactor) |
144 break; | 157 break; |
| 158 } |
145 | 159 |
146 float winningScaleFactor = imageCandidates[i].scaleFactor(); | 160 float winningScaleFactor = imageCandidates[i].scaleFactor(); |
147 unsigned winner = i; | 161 unsigned winner = i; |
148 // 16. If an entry b in candidates has the same associated ... pixel density
as an earlier entry a in candidates, | 162 // 16. If an entry b in candidates has the same associated ... pixel density
as an earlier entry a in candidates, |
149 // then remove entry b | 163 // then remove entry b |
150 while ((i > 0) && (imageCandidates[--i].scaleFactor() == winningScaleFactor)
) | 164 while ((i > 0) && (imageCandidates[--i].scaleFactor() == winningScaleFactor)
) |
151 winner = i; | 165 winner = i; |
152 | 166 |
153 return imageCandidates[winner]; | 167 return imageCandidates[winner]; |
154 } | 168 } |
155 | 169 |
156 ImageCandidate bestFitSourceForSrcsetAttribute(float deviceScaleFactor, const St
ring& srcsetAttribute) | 170 ImageCandidate bestFitSourceForSrcsetAttribute(float deviceScaleFactor, int effe
ctiveSize, const String& srcsetAttribute) |
157 { | 171 { |
158 Vector<ImageCandidate> imageCandidates; | 172 Vector<ImageCandidate> imageCandidates; |
159 | 173 |
160 parseImageCandidatesFromSrcsetAttribute(srcsetAttribute, imageCandidates); | 174 parseImageCandidatesFromSrcsetAttribute(srcsetAttribute, imageCandidates); |
161 | 175 |
162 return pickBestImageCandidate(deviceScaleFactor, imageCandidates); | 176 return pickBestImageCandidate(deviceScaleFactor, effectiveSize, imageCandida
tes); |
163 } | 177 } |
164 | 178 |
165 ImageCandidate bestFitSourceForImageAttributes(float deviceScaleFactor, const St
ring& srcAttribute, const String& srcsetAttribute) | 179 ImageCandidate bestFitSourceForImageAttributes(float deviceScaleFactor, int effe
ctiveSize, const String& srcAttribute, const String& srcsetAttribute) |
166 { | 180 { |
| 181 DescriptorParsingResult defaultResult; |
| 182 defaultResult.scaleFactor = 1.0; |
| 183 |
167 if (srcsetAttribute.isNull()) { | 184 if (srcsetAttribute.isNull()) { |
168 if (srcAttribute.isNull()) | 185 if (srcAttribute.isNull()) |
169 return ImageCandidate(); | 186 return ImageCandidate(); |
170 return ImageCandidate(srcAttribute, 0, srcAttribute.length(), 1); | 187 return ImageCandidate(srcAttribute, 0, srcAttribute.length(), defaultRes
ult); |
171 } | 188 } |
172 | 189 |
173 Vector<ImageCandidate> imageCandidates; | 190 Vector<ImageCandidate> imageCandidates; |
174 | 191 |
175 parseImageCandidatesFromSrcsetAttribute(srcsetAttribute, imageCandidates); | 192 parseImageCandidatesFromSrcsetAttribute(srcsetAttribute, imageCandidates); |
176 | 193 |
177 if (!srcAttribute.isEmpty()) | 194 if (!srcAttribute.isEmpty()) |
178 imageCandidates.append(ImageCandidate(srcAttribute, 0, srcAttribute.leng
th(), 1.0)); | 195 imageCandidates.append(ImageCandidate(srcAttribute, 0, srcAttribute.leng
th(), defaultResult)); |
179 | 196 |
180 return pickBestImageCandidate(deviceScaleFactor, imageCandidates); | 197 return pickBestImageCandidate(deviceScaleFactor, effectiveSize, imageCandida
tes); |
181 } | 198 } |
182 | 199 |
183 String bestFitSourceForImageAttributes(float deviceScaleFactor, const String& sr
cAttribute, ImageCandidate& srcsetImageCandidate) | 200 String bestFitSourceForImageAttributes(float deviceScaleFactor, int effectiveSiz
e, const String& srcAttribute, ImageCandidate& srcsetImageCandidate) |
184 { | 201 { |
| 202 DescriptorParsingResult defaultResult; |
| 203 defaultResult.scaleFactor = 1.0; |
| 204 |
185 if (srcsetImageCandidate.isEmpty()) | 205 if (srcsetImageCandidate.isEmpty()) |
186 return srcAttribute; | 206 return srcAttribute; |
187 | 207 |
188 Vector<ImageCandidate> imageCandidates; | 208 Vector<ImageCandidate> imageCandidates; |
189 imageCandidates.append(srcsetImageCandidate); | 209 imageCandidates.append(srcsetImageCandidate); |
190 | 210 |
191 if (!srcAttribute.isEmpty()) | 211 if (!srcAttribute.isEmpty()) |
192 imageCandidates.append(ImageCandidate(srcAttribute, 0, srcAttribute.leng
th(), 1.0)); | 212 imageCandidates.append(ImageCandidate(srcAttribute, 0, srcAttribute.leng
th(), defaultResult)); |
193 | 213 |
194 return pickBestImageCandidate(deviceScaleFactor, imageCandidates).toString()
; | 214 return pickBestImageCandidate(deviceScaleFactor, effectiveSize, imageCandida
tes).toString(); |
195 } | 215 } |
196 | 216 |
197 } | 217 } |
OLD | NEW |