OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2008 Apple Inc. All Rights Reserved. | 2 * Copyright (C) 2008 Apple Inc. All Rights Reserved. |
3 * Copyright (C) 2009 Torch Mobile, Inc. http://www.torchmobile.com/ | 3 * Copyright (C) 2009 Torch Mobile, Inc. http://www.torchmobile.com/ |
4 * Copyright (C) 2010 Google Inc. All Rights Reserved. | 4 * Copyright (C) 2010 Google Inc. All Rights Reserved. |
5 * | 5 * |
6 * Redistribution and use in source and binary forms, with or without | 6 * Redistribution and use in source and binary forms, with or without |
7 * modification, are permitted provided that the following conditions | 7 * modification, are permitted provided that the following conditions |
8 * are met: | 8 * are met: |
9 * 1. Redistributions of source code must retain the above copyright | 9 * 1. Redistributions of source code must retain the above copyright |
10 * notice, this list of conditions and the following disclaimer. | 10 * notice, this list of conditions and the following disclaimer. |
(...skipping 11 matching lines...) Expand all Loading... |
22 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | 22 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
23 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 23 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 */ | 26 */ |
27 | 27 |
28 #include "config.h" | 28 #include "config.h" |
29 #include "core/html/parser/HTMLPreloadScanner.h" | 29 #include "core/html/parser/HTMLPreloadScanner.h" |
30 | 30 |
31 #include "HTMLNames.h" | 31 #include "HTMLNames.h" |
| 32 #include "RuntimeEnabledFeatures.h" |
32 #include "core/html/LinkRelAttribute.h" | 33 #include "core/html/LinkRelAttribute.h" |
33 #include "core/html/forms/InputTypeNames.h" | 34 #include "core/html/forms/InputTypeNames.h" |
34 #include "core/html/parser/HTMLParserIdioms.h" | 35 #include "core/html/parser/HTMLParserIdioms.h" |
| 36 #include "core/html/parser/HTMLSrcsetParser.h" |
35 #include "core/html/parser/HTMLTokenizer.h" | 37 #include "core/html/parser/HTMLTokenizer.h" |
36 #include "core/platform/chromium/TraceEvent.h" | 38 #include "core/platform/chromium/TraceEvent.h" |
37 #include "wtf/MainThread.h" | 39 #include "wtf/MainThread.h" |
38 | 40 |
39 namespace WebCore { | 41 namespace WebCore { |
40 | 42 |
41 using namespace HTMLNames; | 43 using namespace HTMLNames; |
42 | 44 |
43 static bool match(const StringImpl* impl, const QualifiedName& qName) | 45 static bool match(const StringImpl* impl, const QualifiedName& qName) |
44 { | 46 { |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
83 if (match(tagImpl, linkTag)) | 85 if (match(tagImpl, linkTag)) |
84 return linkTag.localName(); | 86 return linkTag.localName(); |
85 if (match(tagImpl, scriptTag)) | 87 if (match(tagImpl, scriptTag)) |
86 return scriptTag.localName(); | 88 return scriptTag.localName(); |
87 ASSERT_NOT_REACHED(); | 89 ASSERT_NOT_REACHED(); |
88 return emptyString(); | 90 return emptyString(); |
89 } | 91 } |
90 | 92 |
91 class TokenPreloadScanner::StartTagScanner { | 93 class TokenPreloadScanner::StartTagScanner { |
92 public: | 94 public: |
93 explicit StartTagScanner(const StringImpl* tagImpl) | 95 StartTagScanner(const StringImpl* tagImpl, float deviceScaleFactor) |
94 : m_tagImpl(tagImpl) | 96 : m_tagImpl(tagImpl) |
95 , m_linkIsStyleSheet(false) | 97 , m_linkIsStyleSheet(false) |
96 , m_inputIsImage(false) | 98 , m_inputIsImage(false) |
| 99 , m_deviceScaleFactor(deviceScaleFactor) |
| 100 , m_encounteredImgSrc(false) |
97 { | 101 { |
98 if (!match(m_tagImpl, imgTag) | 102 if (!match(m_tagImpl, imgTag) |
99 && !match(m_tagImpl, inputTag) | 103 && !match(m_tagImpl, inputTag) |
100 && !match(m_tagImpl, linkTag) | 104 && !match(m_tagImpl, linkTag) |
101 && !match(m_tagImpl, scriptTag)) | 105 && !match(m_tagImpl, scriptTag)) |
102 m_tagImpl = 0; | 106 m_tagImpl = 0; |
103 } | 107 } |
104 | 108 |
| 109 enum URLReplacement { |
| 110 AllowURLReplacement, |
| 111 DisallowURLReplacement |
| 112 }; |
| 113 |
105 void processAttributes(const HTMLToken::AttributeList& attributes) | 114 void processAttributes(const HTMLToken::AttributeList& attributes) |
106 { | 115 { |
107 ASSERT(isMainThread()); | 116 ASSERT(isMainThread()); |
108 if (!m_tagImpl) | 117 if (!m_tagImpl) |
109 return; | 118 return; |
110 for (HTMLToken::AttributeList::const_iterator iter = attributes.begin();
iter != attributes.end(); ++iter) { | 119 for (HTMLToken::AttributeList::const_iterator iter = attributes.begin();
iter != attributes.end(); ++iter) { |
111 AtomicString attributeName(iter->name); | 120 AtomicString attributeName(iter->name); |
112 String attributeValue = StringImpl::create8BitIfPossible(iter->value
); | 121 String attributeValue = StringImpl::create8BitIfPossible(iter->value
); |
113 processAttribute(attributeName, attributeValue); | 122 processAttribute(attributeName, attributeValue); |
114 } | 123 } |
(...skipping 20 matching lines...) Expand all Loading... |
135 return request.release(); | 144 return request.release(); |
136 } | 145 } |
137 | 146 |
138 private: | 147 private: |
139 template<typename NameType> | 148 template<typename NameType> |
140 void processAttribute(const NameType& attributeName, const String& attribute
Value) | 149 void processAttribute(const NameType& attributeName, const String& attribute
Value) |
141 { | 150 { |
142 if (match(attributeName, charsetAttr)) | 151 if (match(attributeName, charsetAttr)) |
143 m_charset = attributeValue; | 152 m_charset = attributeValue; |
144 | 153 |
145 if (match(m_tagImpl, scriptTag) || match(m_tagImpl, imgTag)) { | 154 if (match(m_tagImpl, scriptTag)) { |
146 if (match(attributeName, srcAttr)) | 155 if (match(attributeName, srcAttr)) |
147 setUrlToLoad(attributeValue); | 156 setUrlToLoad(attributeValue, DisallowURLReplacement); |
148 else if (match(attributeName, crossoriginAttr) && !attributeValue.is
Null()) | 157 else if (match(attributeName, crossoriginAttr) && !attributeValue.is
Null()) |
149 m_crossOriginMode = stripLeadingAndTrailingHTMLSpaces(attributeV
alue); | 158 m_crossOriginMode = stripLeadingAndTrailingHTMLSpaces(attributeV
alue); |
| 159 } else if (match(m_tagImpl, imgTag)) { |
| 160 if (match(attributeName, srcAttr) && !m_encounteredImgSrc) { |
| 161 m_encounteredImgSrc = true; |
| 162 setUrlToLoad(bestFitSourceForImageAttributes(m_deviceScaleFactor
, attributeValue, m_srcsetImageCandidate), AllowURLReplacement); |
| 163 } else if (match(attributeName, crossoriginAttr) && !attributeValue.
isNull()) { |
| 164 m_crossOriginMode = stripLeadingAndTrailingHTMLSpaces(attributeV
alue); |
| 165 } else if (RuntimeEnabledFeatures::srcsetEnabled() |
| 166 && match(attributeName, srcsetAttr) |
| 167 && m_srcsetImageCandidate.isEmpty()) { |
| 168 m_srcsetImageCandidate = bestFitSourceForSrcsetAttribute(m_devic
eScaleFactor, attributeValue); |
| 169 setUrlToLoad(bestFitSourceForImageAttributes(m_deviceScaleFactor
, m_urlToLoad, m_srcsetImageCandidate), AllowURLReplacement); |
| 170 } |
150 } else if (match(m_tagImpl, linkTag)) { | 171 } else if (match(m_tagImpl, linkTag)) { |
151 if (match(attributeName, hrefAttr)) | 172 if (match(attributeName, hrefAttr)) |
152 setUrlToLoad(attributeValue); | 173 setUrlToLoad(attributeValue, DisallowURLReplacement); |
153 else if (match(attributeName, relAttr)) | 174 else if (match(attributeName, relAttr)) |
154 m_linkIsStyleSheet = relAttributeIsStyleSheet(attributeValue); | 175 m_linkIsStyleSheet = relAttributeIsStyleSheet(attributeValue); |
155 else if (match(attributeName, mediaAttr)) | 176 else if (match(attributeName, mediaAttr)) |
156 m_mediaAttribute = attributeValue; | 177 m_mediaAttribute = attributeValue; |
157 } else if (match(m_tagImpl, inputTag)) { | 178 } else if (match(m_tagImpl, inputTag)) { |
158 if (match(attributeName, srcAttr)) | 179 if (match(attributeName, srcAttr)) |
159 setUrlToLoad(attributeValue); | 180 setUrlToLoad(attributeValue, DisallowURLReplacement); |
160 else if (match(attributeName, typeAttr)) | 181 else if (match(attributeName, typeAttr)) |
161 m_inputIsImage = equalIgnoringCase(attributeValue, InputTypeName
s::image()); | 182 m_inputIsImage = equalIgnoringCase(attributeValue, InputTypeName
s::image()); |
162 } | 183 } |
163 } | 184 } |
164 | 185 |
165 static bool relAttributeIsStyleSheet(const String& attributeValue) | 186 static bool relAttributeIsStyleSheet(const String& attributeValue) |
166 { | 187 { |
167 LinkRelAttribute rel(attributeValue); | 188 LinkRelAttribute rel(attributeValue); |
168 return rel.isStyleSheet() && !rel.isAlternate() && rel.iconType() == Inv
alidIcon && !rel.isDNSPrefetch(); | 189 return rel.isStyleSheet() && !rel.isAlternate() && rel.iconType() == Inv
alidIcon && !rel.isDNSPrefetch(); |
169 } | 190 } |
170 | 191 |
171 void setUrlToLoad(const String& attributeValue) | 192 void setUrlToLoad(const String& value, URLReplacement replacement) |
172 { | 193 { |
173 // We only respect the first src/href, per HTML5: | 194 // We only respect the first src/href, per HTML5: |
174 // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenizat
ion.html#attribute-name-state | 195 // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenizat
ion.html#attribute-name-state |
175 if (!m_urlToLoad.isEmpty()) | 196 if (replacement == DisallowURLReplacement && !m_urlToLoad.isEmpty()) |
176 return; | 197 return; |
177 m_urlToLoad = stripLeadingAndTrailingHTMLSpaces(attributeValue); | 198 String url = stripLeadingAndTrailingHTMLSpaces(value); |
| 199 if (url.isEmpty()) |
| 200 return; |
| 201 m_urlToLoad = url; |
178 } | 202 } |
179 | 203 |
180 const String& charset() const | 204 const String& charset() const |
181 { | 205 { |
182 // FIXME: Its not clear that this if is needed, the loader probably igno
res charset for image requests anyway. | 206 // FIXME: Its not clear that this if is needed, the loader probably igno
res charset for image requests anyway. |
183 if (match(m_tagImpl, imgTag)) | 207 if (match(m_tagImpl, imgTag)) |
184 return emptyString(); | 208 return emptyString(); |
185 return m_charset; | 209 return m_charset; |
186 } | 210 } |
187 | 211 |
(...skipping 20 matching lines...) Expand all Loading... |
208 return true; | 232 return true; |
209 } | 233 } |
210 | 234 |
211 bool crossOriginModeAllowsCookies() | 235 bool crossOriginModeAllowsCookies() |
212 { | 236 { |
213 return m_crossOriginMode.isNull() || equalIgnoringCase(m_crossOriginMode
, "use-credentials"); | 237 return m_crossOriginMode.isNull() || equalIgnoringCase(m_crossOriginMode
, "use-credentials"); |
214 } | 238 } |
215 | 239 |
216 const StringImpl* m_tagImpl; | 240 const StringImpl* m_tagImpl; |
217 String m_urlToLoad; | 241 String m_urlToLoad; |
| 242 ImageCandidate m_srcsetImageCandidate; |
218 String m_charset; | 243 String m_charset; |
219 String m_crossOriginMode; | 244 String m_crossOriginMode; |
220 bool m_linkIsStyleSheet; | 245 bool m_linkIsStyleSheet; |
221 String m_mediaAttribute; | 246 String m_mediaAttribute; |
222 bool m_inputIsImage; | 247 bool m_inputIsImage; |
| 248 float m_deviceScaleFactor; |
| 249 bool m_encounteredImgSrc; |
223 }; | 250 }; |
224 | 251 |
225 TokenPreloadScanner::TokenPreloadScanner(const KURL& documentURL) | 252 TokenPreloadScanner::TokenPreloadScanner(const KURL& documentURL, float deviceSc
aleFactor) |
226 : m_documentURL(documentURL) | 253 : m_documentURL(documentURL) |
227 , m_inStyle(false) | 254 , m_inStyle(false) |
| 255 , m_deviceScaleFactor(deviceScaleFactor) |
228 , m_templateCount(0) | 256 , m_templateCount(0) |
229 { | 257 { |
230 } | 258 } |
231 | 259 |
232 TokenPreloadScanner::~TokenPreloadScanner() | 260 TokenPreloadScanner::~TokenPreloadScanner() |
233 { | 261 { |
234 } | 262 } |
235 | 263 |
236 TokenPreloadScannerCheckpoint TokenPreloadScanner::createCheckpoint() | 264 TokenPreloadScannerCheckpoint TokenPreloadScanner::createCheckpoint() |
237 { | 265 { |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
298 return; | 326 return; |
299 } | 327 } |
300 if (match(tagImpl, baseTag)) { | 328 if (match(tagImpl, baseTag)) { |
301 // The first <base> element is the one that wins. | 329 // The first <base> element is the one that wins. |
302 if (!m_predictedBaseElementURL.isEmpty()) | 330 if (!m_predictedBaseElementURL.isEmpty()) |
303 return; | 331 return; |
304 updatePredictedBaseURL(token); | 332 updatePredictedBaseURL(token); |
305 return; | 333 return; |
306 } | 334 } |
307 | 335 |
308 StartTagScanner scanner(tagImpl); | 336 StartTagScanner scanner(tagImpl, m_deviceScaleFactor); |
309 scanner.processAttributes(token.attributes()); | 337 scanner.processAttributes(token.attributes()); |
310 OwnPtr<PreloadRequest> request = scanner.createPreloadRequest(m_predicte
dBaseElementURL, source); | 338 OwnPtr<PreloadRequest> request = scanner.createPreloadRequest(m_predicte
dBaseElementURL, source); |
311 if (request) | 339 if (request) |
312 requests.append(request.release()); | 340 requests.append(request.release()); |
313 return; | 341 return; |
314 } | 342 } |
315 default: { | 343 default: { |
316 return; | 344 return; |
317 } | 345 } |
318 } | 346 } |
319 } | 347 } |
320 | 348 |
321 template<typename Token> | 349 template<typename Token> |
322 void TokenPreloadScanner::updatePredictedBaseURL(const Token& token) | 350 void TokenPreloadScanner::updatePredictedBaseURL(const Token& token) |
323 { | 351 { |
324 ASSERT(m_predictedBaseElementURL.isEmpty()); | 352 ASSERT(m_predictedBaseElementURL.isEmpty()); |
325 if (const typename Token::Attribute* hrefAttribute = token.getAttributeItem(
hrefAttr)) | 353 if (const typename Token::Attribute* hrefAttribute = token.getAttributeItem(
hrefAttr)) |
326 m_predictedBaseElementURL = KURL(m_documentURL, stripLeadingAndTrailingH
TMLSpaces(hrefAttribute->value)).copy(); | 354 m_predictedBaseElementURL = KURL(m_documentURL, stripLeadingAndTrailingH
TMLSpaces(hrefAttribute->value)).copy(); |
327 } | 355 } |
328 | 356 |
329 HTMLPreloadScanner::HTMLPreloadScanner(const HTMLParserOptions& options, const K
URL& documentURL) | 357 HTMLPreloadScanner::HTMLPreloadScanner(const HTMLParserOptions& options, const K
URL& documentURL, float deviceScaleFactor) |
330 : m_scanner(documentURL) | 358 : m_scanner(documentURL, deviceScaleFactor) |
331 , m_tokenizer(HTMLTokenizer::create(options)) | 359 , m_tokenizer(HTMLTokenizer::create(options)) |
332 { | 360 { |
333 } | 361 } |
334 | 362 |
335 HTMLPreloadScanner::~HTMLPreloadScanner() | 363 HTMLPreloadScanner::~HTMLPreloadScanner() |
336 { | 364 { |
337 } | 365 } |
338 | 366 |
339 void HTMLPreloadScanner::appendToEnd(const SegmentedString& source) | 367 void HTMLPreloadScanner::appendToEnd(const SegmentedString& source) |
340 { | 368 { |
(...skipping 14 matching lines...) Expand all Loading... |
355 if (m_token.type() == HTMLToken::StartTag) | 383 if (m_token.type() == HTMLToken::StartTag) |
356 m_tokenizer->updateStateFor(AtomicString(m_token.name())); | 384 m_tokenizer->updateStateFor(AtomicString(m_token.name())); |
357 m_scanner.scan(m_token, m_source, requests); | 385 m_scanner.scan(m_token, m_source, requests); |
358 m_token.clear(); | 386 m_token.clear(); |
359 } | 387 } |
360 | 388 |
361 preloader->takeAndPreload(requests); | 389 preloader->takeAndPreload(requests); |
362 } | 390 } |
363 | 391 |
364 } | 392 } |
OLD | NEW |