Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(95)

Side by Side Diff: sky/engine/core/html/parser/HTMLSrcsetParser.cpp

Issue 1215103007: Remove remaining HTML elements (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * Copyright (C) 2013 Apple Inc. All rights reserved.
3 * Copyright (C) 2013 Google Inc. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
14 * distribution.
15 * * Neither the name of Google Inc. nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include "sky/engine/core/html/parser/HTMLSrcsetParser.h"
33
34 #include "gen/sky/platform/RuntimeEnabledFeatures.h"
35 #include "sky/engine/core/html/parser/HTMLParserIdioms.h"
36 #include "sky/engine/platform/ParsingUtilities.h"
37
38 namespace blink {
39
40 static bool compareByDensity(const ImageCandidate& first, const ImageCandidate& second)
41 {
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
55 DescriptorToken(unsigned start, unsigned length)
56 : start(start)
57 , length(length)
58 {
59 }
60
61 unsigned lastIndex()
62 {
63 return start + length - 1;
64 }
65
66 template<typename CharType>
67 int toInt(const CharType* attribute, bool& isValid)
68 {
69 return charactersToIntStrict(attribute + start, length - 1, &isValid);
70 }
71
72 template<typename CharType>
73 float toFloat(const CharType* attribute, bool& isValid)
74 {
75 return charactersToFloat(attribute + start, length - 1, &isValid);
76 }
77 };
78
79 template<typename CharType>
80 static void appendDescriptorAndReset(const CharType* attributeStart, const CharT ype*& descriptorStart, const CharType* position, Vector<DescriptorToken>& descri ptors)
81 {
82 if (position > descriptorStart)
83 descriptors.append(DescriptorToken(descriptorStart - attributeStart, pos ition - descriptorStart));
84 descriptorStart = 0;
85 }
86
87 // The following is called appendCharacter to match the spec's terminology.
88 template<typename CharType>
89 static void appendCharacter(const CharType* descriptorStart, const CharType* pos ition)
90 {
91 // Since we don't copy the tokens, this just set the point where the descrip tor tokens start.
92 if (!descriptorStart)
93 descriptorStart = position;
94 }
95
96 template<typename CharType>
97 static bool isEOF(const CharType* position, const CharType* end)
98 {
99 return position >= end;
100 }
101
102 template<typename CharType>
103 static void tokenizeDescriptors(const CharType* attributeStart,
104 const CharType*& position,
105 const CharType* attributeEnd,
106 Vector<DescriptorToken>& descriptors)
107 {
108 DescriptorTokenizerState state = Start;
109 const CharType* descriptorsStart = position;
110 const CharType* currentDescriptorStart = descriptorsStart;
111 while (true) {
112 switch (state) {
113 case Start:
114 if (isEOF(position, attributeEnd)) {
115 appendDescriptorAndReset(attributeStart, currentDescriptorStart, attributeEnd, descriptors);
116 return;
117 }
118 if (isComma(*position)) {
119 appendDescriptorAndReset(attributeStart, currentDescriptorStart, position, descriptors);
120 ++position;
121 return;
122 }
123 if (isHTMLSpace(*position)) {
124 appendDescriptorAndReset(attributeStart, currentDescriptorStart, position, descriptors);
125 currentDescriptorStart = position + 1;
126 state = AfterToken;
127 } else if (*position == '(') {
128 appendCharacter(currentDescriptorStart, position);
129 state = InParenthesis;
130 } else {
131 appendCharacter(currentDescriptorStart, position);
132 }
133 break;
134 case InParenthesis:
135 if (isEOF(position, attributeEnd)) {
136 appendDescriptorAndReset(attributeStart, currentDescriptorStart, attributeEnd, descriptors);
137 return;
138 }
139 if (*position == ')') {
140 appendCharacter(currentDescriptorStart, position);
141 state = Start;
142 } else {
143 appendCharacter(currentDescriptorStart, position);
144 }
145 break;
146 case AfterToken:
147 if (isEOF(position, attributeEnd))
148 return;
149 if (!isHTMLSpace(*position)) {
150 state = Start;
151 currentDescriptorStart = position;
152 --position;
153 }
154 break;
155 }
156 ++position;
157 }
158 }
159
160 template<typename CharType>
161 static bool parseDescriptors(const CharType* attribute, Vector<DescriptorToken>& descriptors, DescriptorParsingResult& result)
162 {
163 for (Vector<DescriptorToken>::iterator it = descriptors.begin(); it != descr iptors.end(); ++it) {
164 if (it->length == 0)
165 continue;
166 CharType c = attribute[it->lastIndex()];
167 bool isValid = false;
168 if (RuntimeEnabledFeatures::pictureSizesEnabled() && c == 'w') {
169 if (result.hasDensity() || result.hasWidth())
170 return false;
171 int resourceWidth = it->toInt(attribute, isValid);
172 if (!isValid || resourceWidth <= 0)
173 return false;
174 result.setResourceWidth(resourceWidth);
175 } else if (RuntimeEnabledFeatures::pictureSizesEnabled() && c == 'h') {
176 // This is here only for future compat purposes.
177 // The value of the 'h' descriptor is not used.
178 if (result.hasDensity() || result.hasHeight())
179 return false;
180 int resourceHeight = it->toInt(attribute, isValid);
181 if (!isValid || resourceHeight <= 0)
182 return false;
183 result.setResourceHeight(resourceHeight);
184 } else if (c == 'x') {
185 if (result.hasDensity() || result.hasHeight() || result.hasWidth())
186 return false;
187 float density = it->toFloat(attribute, isValid);
188 if (!isValid || density < 0)
189 return false;
190 result.setDensity(density);
191 }
192 }
193 return true;
194 }
195
196 static bool parseDescriptors(const String& attribute, Vector<DescriptorToken>& d escriptors, DescriptorParsingResult& result)
197 {
198 // FIXME: See if StringView can't be extended to replace DescriptorToken her e.
199 if (attribute.is8Bit()) {
200 return parseDescriptors(attribute.characters8(), descriptors, result);
201 }
202 return parseDescriptors(attribute.characters16(), descriptors, result);
203 }
204
205 // http://picture.responsiveimages.org/#parse-srcset-attr
206 template<typename CharType>
207 static void parseImageCandidatesFromSrcsetAttribute(const String& attribute, con st CharType* attributeStart, unsigned length, Vector<ImageCandidate>& imageCandi dates)
208 {
209 const CharType* position = attributeStart;
210 const CharType* attributeEnd = position + length;
211
212 while (position < attributeEnd) {
213 // 4. Splitting loop: Collect a sequence of characters that are space ch aracters or U+002C COMMA characters.
214 skipWhile<CharType, isHTMLSpaceOrComma<CharType> >(position, attributeEn d);
215 if (position == attributeEnd) {
216 // Contrary to spec language - descriptor parsing happens on each ca ndidate, so when we reach the attributeEnd, we can exit.
217 break;
218 }
219 const CharType* imageURLStart = position;
220 // 6. Collect a sequence of characters that are not space characters, an d let that be url.
221
222 skipUntil<CharType, isHTMLSpace<CharType> >(position, attributeEnd);
223 const CharType* imageURLEnd = position;
224
225 DescriptorParsingResult result;
226
227 // 8. If url ends with a U+002C COMMA character (,)
228 if (isComma(*(position - 1))) {
229 // Remove all trailing U+002C COMMA characters from url.
230 imageURLEnd = position - 1;
231 reverseSkipWhile<CharType, isComma>(imageURLEnd, imageURLStart);
232 ++imageURLEnd;
233 // If url is empty, then jump to the step labeled splitting loop.
234 if (imageURLStart == imageURLEnd)
235 continue;
236 } else {
237 // Advancing position here (contrary to spec) to avoid an useless ex tra state machine step.
238 // Filed a spec bug: https://github.com/ResponsiveImagesCG/picture-e lement/issues/189
239 ++position;
240 Vector<DescriptorToken> descriptorTokens;
241 tokenizeDescriptors(attributeStart, position, attributeEnd, descript orTokens);
242 // Contrary to spec language - descriptor parsing happens on each ca ndidate.
243 // This is a black-box equivalent, to avoid storing descriptor lists for each candidate.
244 if (!parseDescriptors(attribute, descriptorTokens, result))
245 continue;
246 }
247
248 ASSERT(imageURLEnd > attributeStart);
249 unsigned imageURLStartingPosition = imageURLStart - attributeStart;
250 ASSERT(imageURLEnd > imageURLStart);
251 unsigned imageURLLength = imageURLEnd - imageURLStart;
252 imageCandidates.append(ImageCandidate(attribute, imageURLStartingPositio n, imageURLLength, result, ImageCandidate::SrcsetOrigin));
253 // 11. Return to the step labeled splitting loop.
254 }
255 }
256
257 static void parseImageCandidatesFromSrcsetAttribute(const String& attribute, Vec tor<ImageCandidate>& imageCandidates)
258 {
259 if (attribute.isNull())
260 return;
261
262 if (attribute.is8Bit())
263 parseImageCandidatesFromSrcsetAttribute<LChar>(attribute, attribute.char acters8(), attribute.length(), imageCandidates);
264 else
265 parseImageCandidatesFromSrcsetAttribute<UChar>(attribute, attribute.char acters16(), attribute.length(), imageCandidates);
266 }
267
268 static ImageCandidate pickBestImageCandidate(float deviceScaleFactor, unsigned s ourceSize, Vector<ImageCandidate>& imageCandidates)
269 {
270 const float defaultDensityValue = 1.0;
271 bool ignoreSrc = false;
272 if (imageCandidates.isEmpty())
273 return ImageCandidate();
274
275 // http://picture.responsiveimages.org/#normalize-source-densities
276 for (Vector<ImageCandidate>::iterator it = imageCandidates.begin(); it != im ageCandidates.end(); ++it) {
277 if (it->resourceWidth() > 0) {
278 it->setDensity((float)it->resourceWidth() / (float)sourceSize);
279 ignoreSrc = true;
280 } else if (it->density() < 0) {
281 it->setDensity(defaultDensityValue);
282 }
283 }
284
285 std::stable_sort(imageCandidates.begin(), imageCandidates.end(), compareByDe nsity);
286
287 unsigned i;
288 for (i = 0; i < imageCandidates.size() - 1; ++i) {
289 if ((imageCandidates[i].density() >= deviceScaleFactor) && (!ignoreSrc | | !imageCandidates[i].srcOrigin()))
290 break;
291 }
292
293 if (imageCandidates[i].srcOrigin() && ignoreSrc) {
294 ASSERT(i > 0);
295 --i;
296 }
297 float winningDensity = imageCandidates[i].density();
298
299 unsigned winner = i;
300 // 16. If an entry b in candidates has the same associated ... pixel density as an earlier entry a in candidates,
301 // then remove entry b
302 while ((i > 0) && (imageCandidates[--i].density() == winningDensity))
303 winner = i;
304
305 return imageCandidates[winner];
306 }
307
308 ImageCandidate bestFitSourceForSrcsetAttribute(float deviceScaleFactor, unsigned sourceSize, const String& srcsetAttribute)
309 {
310 Vector<ImageCandidate> imageCandidates;
311
312 parseImageCandidatesFromSrcsetAttribute(srcsetAttribute, imageCandidates);
313
314 return pickBestImageCandidate(deviceScaleFactor, sourceSize, imageCandidates );
315 }
316
317 ImageCandidate bestFitSourceForImageAttributes(float deviceScaleFactor, unsigned sourceSize, const String& srcAttribute, const String& srcsetAttribute)
318 {
319 if (srcsetAttribute.isNull()) {
320 if (srcAttribute.isNull())
321 return ImageCandidate();
322 return ImageCandidate(srcAttribute, 0, srcAttribute.length(), Descriptor ParsingResult(), ImageCandidate::SrcOrigin);
323 }
324
325 Vector<ImageCandidate> imageCandidates;
326
327 parseImageCandidatesFromSrcsetAttribute(srcsetAttribute, imageCandidates);
328
329 if (!srcAttribute.isEmpty())
330 imageCandidates.append(ImageCandidate(srcAttribute, 0, srcAttribute.leng th(), DescriptorParsingResult(), ImageCandidate::SrcOrigin));
331
332 return pickBestImageCandidate(deviceScaleFactor, sourceSize, imageCandidates );
333 }
334
335 String bestFitSourceForImageAttributes(float deviceScaleFactor, unsigned sourceS ize, const String& srcAttribute, ImageCandidate& srcsetImageCandidate)
336 {
337 if (srcsetImageCandidate.isEmpty())
338 return srcAttribute;
339
340 Vector<ImageCandidate> imageCandidates;
341 imageCandidates.append(srcsetImageCandidate);
342
343 if (!srcAttribute.isEmpty())
344 imageCandidates.append(ImageCandidate(srcAttribute, 0, srcAttribute.leng th(), DescriptorParsingResult(), ImageCandidate::SrcOrigin));
345
346 return pickBestImageCandidate(deviceScaleFactor, sourceSize, imageCandidates ).toString();
347 }
348
349 }
OLDNEW
« no previous file with comments | « sky/engine/core/html/parser/HTMLSrcsetParser.h ('k') | sky/engine/core/html/parser/HTMLSrcsetParserTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698