2 * Copyright (C) 2008 Apple Inc. All Rights Reserved.
3 * Copyright (C) 2009 Torch Mobile, Inc. http://www.torchmobile.com/
4 * Copyright (C) 2010 Google Inc. All Rights Reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
16 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
19 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
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.
29 #include "core/html/parser/HTMLPreloadScanner.h"
31 #include "core/HTMLNames.h"
32 #include "core/InputTypeNames.h"
33 #include "core/css/MediaList.h"
34 #include "core/css/MediaQueryEvaluator.h"
35 #include "core/css/MediaValuesCached.h"
36 #include "core/css/parser/SizesAttributeParser.h"
37 #include "core/dom/Document.h"
38 #include "core/frame/Settings.h"
39 #include "core/html/HTMLImageElement.h"
40 #include "core/html/HTMLMetaElement.h"
41 #include "core/html/LinkRelAttribute.h"
42 #include "core/html/parser/HTMLParserIdioms.h"
43 #include "core/html/parser/HTMLSrcsetParser.h"
44 #include "core/html/parser/HTMLTokenizer.h"
45 #include "platform/RuntimeEnabledFeatures.h"
46 #include "platform/TraceEvent.h"
47 #include "wtf/MainThread.h"
51 using namespace HTMLNames
;
53 static bool match(const StringImpl
* impl
, const QualifiedName
& qName
)
55 return impl
== qName
.localName().impl();
58 static bool match(const AtomicString
& name
, const QualifiedName
& qName
)
60 ASSERT(isMainThread());
61 return qName
.localName() == name
;
64 static bool match(const String
& name
, const QualifiedName
& qName
)
66 return threadSafeMatch(name
, qName
);
69 static const StringImpl
* tagImplFor(const HTMLToken::DataVector
& data
)
71 AtomicString
tagName(data
);
72 const StringImpl
* result
= tagName
.impl();
73 if (result
->isStatic())
78 static const StringImpl
* tagImplFor(const String
& tagName
)
80 const StringImpl
* result
= tagName
.impl();
81 if (result
->isStatic())
86 static String
initiatorFor(const StringImpl
* tagImpl
)
89 if (match(tagImpl
, imgTag
))
90 return imgTag
.localName();
91 if (match(tagImpl
, inputTag
))
92 return inputTag
.localName();
93 if (match(tagImpl
, linkTag
))
94 return linkTag
.localName();
95 if (match(tagImpl
, scriptTag
))
96 return scriptTag
.localName();
97 if (match(tagImpl
, videoTag
))
98 return videoTag
.localName();
100 return emptyString();
103 static bool mediaAttributeMatches(const MediaValues
& mediaValues
, const String
& attributeValue
)
105 RefPtrWillBeRawPtr
<MediaQuerySet
> mediaQueries
= MediaQuerySet::createOffMainThread(attributeValue
);
106 MediaQueryEvaluator
mediaQueryEvaluator(mediaValues
);
107 return mediaQueryEvaluator
.eval(mediaQueries
.get());
110 class TokenPreloadScanner::StartTagScanner
{
113 StartTagScanner(const StringImpl
* tagImpl
, PassRefPtrWillBeRawPtr
<MediaValues
> mediaValues
)
115 , m_linkIsStyleSheet(false)
116 , m_linkIsPreconnect(false)
117 , m_linkIsImport(false)
118 , m_matchedMediaAttribute(true)
119 , m_inputIsImage(false)
121 , m_sourceSizeSet(false)
122 , m_isCORSEnabled(false)
123 , m_defer(FetchRequest::NoDefer
)
124 , m_allowCredentials(DoNotAllowStoredCredentials
)
125 , m_mediaValues(mediaValues
)
126 , m_referrerPolicySet(false)
127 , m_referrerPolicy(ReferrerPolicyDefault
)
129 ASSERT(m_mediaValues
->isCached());
130 if (match(m_tagImpl
, imgTag
)
131 || match(m_tagImpl
, sourceTag
)) {
132 m_sourceSize
= SizesAttributeParser(m_mediaValues
, String()).length();
135 if ( !match(m_tagImpl
, inputTag
)
136 && !match(m_tagImpl
, linkTag
)
137 && !match(m_tagImpl
, scriptTag
)
138 && !match(m_tagImpl
, videoTag
))
142 enum URLReplacement
{
144 DisallowURLReplacement
147 void processAttributes(const HTMLToken::AttributeList
& attributes
)
149 ASSERT(isMainThread());
152 for (const HTMLToken::Attribute
& htmlTokenAttribute
: attributes
) {
153 AtomicString
attributeName(htmlTokenAttribute
.name
);
154 String attributeValue
= StringImpl::create8BitIfPossible(htmlTokenAttribute
.value
);
155 processAttribute(attributeName
, attributeValue
);
159 void processAttributes(const Vector
<CompactHTMLToken::Attribute
>& attributes
)
163 for (const CompactHTMLToken::Attribute
& htmlTokenAttribute
: attributes
)
164 processAttribute(htmlTokenAttribute
.name
, htmlTokenAttribute
.value
);
167 void handlePictureSourceURL(PictureData
& pictureData
)
169 if (match(m_tagImpl
, sourceTag
) && m_matchedMediaAttribute
&& pictureData
.sourceURL
.isEmpty()) {
170 pictureData
.sourceURL
= m_srcsetImageCandidate
.toString();
171 pictureData
.sourceSizeSet
= m_sourceSizeSet
;
172 pictureData
.sourceSize
= m_sourceSize
;
173 pictureData
.picked
= true;
174 } else if (match(m_tagImpl
, imgTag
) && !pictureData
.sourceURL
.isEmpty()) {
175 setUrlToLoad(pictureData
.sourceURL
, AllowURLReplacement
);
179 PassOwnPtr
<PreloadRequest
> createPreloadRequest(const KURL
& predictedBaseURL
, const SegmentedString
& source
, const ClientHintsPreferences
& clientHintsPreferences
, const PictureData
& pictureData
, const ReferrerPolicy documentReferrerPolicy
)
181 PreloadRequest::RequestType requestType
= PreloadRequest::RequestTypePreload
;
182 if (shouldPreconnect())
183 requestType
= PreloadRequest::RequestTypePreconnect
;
184 else if (!shouldPreload() || !m_matchedMediaAttribute
)
187 TextPosition position
= TextPosition(source
.currentLine(), source
.currentColumn());
188 FetchRequest::ResourceWidth resourceWidth
;
189 float sourceSize
= m_sourceSize
;
190 bool sourceSizeSet
= m_sourceSizeSet
;
191 if (pictureData
.picked
) {
192 sourceSizeSet
= pictureData
.sourceSizeSet
;
193 sourceSize
= pictureData
.sourceSize
;
196 resourceWidth
.width
= sourceSize
;
197 resourceWidth
.isSet
= true;
200 // The element's 'referrerpolicy' attribute (if present) takes precedence over the document's referrer policy.
201 ReferrerPolicy referrerPolicy
= (m_referrerPolicy
!= ReferrerPolicyDefault
&& RuntimeEnabledFeatures::referrerPolicyAttributeEnabled()) ? m_referrerPolicy
: documentReferrerPolicy
;
202 OwnPtr
<PreloadRequest
> request
= PreloadRequest::create(initiatorFor(m_tagImpl
), position
, m_urlToLoad
, predictedBaseURL
, resourceType(), referrerPolicy
, resourceWidth
, clientHintsPreferences
, requestType
);
204 request
->setCrossOriginEnabled(allowStoredCredentials());
205 request
->setCharset(charset());
206 request
->setDefer(m_defer
);
207 return request
.release();
211 template<typename NameType
>
212 void processScriptAttribute(const NameType
& attributeName
, const String
& attributeValue
)
214 // FIXME - Don't set crossorigin multiple times.
215 if (match(attributeName
, srcAttr
))
216 setUrlToLoad(attributeValue
, DisallowURLReplacement
);
217 else if (match(attributeName
, crossoriginAttr
))
218 setCrossOriginAllowed(attributeValue
);
219 else if (match(attributeName
, asyncAttr
))
220 setDefer(FetchRequest::LazyLoad
);
221 else if (match(attributeName
, deferAttr
))
222 setDefer(FetchRequest::LazyLoad
);
225 template<typename NameType
>
226 void processImgAttribute(const NameType
& attributeName
, const String
& attributeValue
)
228 if (match(attributeName
, srcAttr
) && m_imgSrcUrl
.isNull()) {
229 m_imgSrcUrl
= attributeValue
;
230 setUrlToLoad(bestFitSourceForImageAttributes(m_mediaValues
->devicePixelRatio(), m_sourceSize
, attributeValue
, m_srcsetImageCandidate
), AllowURLReplacement
);
231 } else if (match(attributeName
, crossoriginAttr
)) {
232 setCrossOriginAllowed(attributeValue
);
233 } else if (match(attributeName
, srcsetAttr
) && m_srcsetImageCandidate
.isEmpty()) {
234 m_srcsetAttributeValue
= attributeValue
;
235 m_srcsetImageCandidate
= bestFitSourceForSrcsetAttribute(m_mediaValues
->devicePixelRatio(), m_sourceSize
, attributeValue
);
236 setUrlToLoad(bestFitSourceForImageAttributes(m_mediaValues
->devicePixelRatio(), m_sourceSize
, m_imgSrcUrl
, m_srcsetImageCandidate
), AllowURLReplacement
);
237 } else if (match(attributeName
, sizesAttr
) && !m_sourceSizeSet
) {
238 m_sourceSize
= SizesAttributeParser(m_mediaValues
, attributeValue
).length();
239 m_sourceSizeSet
= true;
240 if (!m_srcsetImageCandidate
.isEmpty()) {
241 m_srcsetImageCandidate
= bestFitSourceForSrcsetAttribute(m_mediaValues
->devicePixelRatio(), m_sourceSize
, m_srcsetAttributeValue
);
242 setUrlToLoad(bestFitSourceForImageAttributes(m_mediaValues
->devicePixelRatio(), m_sourceSize
, m_imgSrcUrl
, m_srcsetImageCandidate
), AllowURLReplacement
);
244 } else if (!m_referrerPolicySet
&& RuntimeEnabledFeatures::referrerPolicyAttributeEnabled() && match(attributeName
, referrerpolicyAttr
) && !attributeValue
.isNull()) {
245 m_referrerPolicySet
= true;
246 SecurityPolicy::referrerPolicyFromString(attributeValue
, &m_referrerPolicy
);
250 template<typename NameType
>
251 void processLinkAttribute(const NameType
& attributeName
, const String
& attributeValue
)
253 // FIXME - Don't set rel/media/crossorigin multiple times.
254 if (match(attributeName
, hrefAttr
)) {
255 setUrlToLoad(attributeValue
, DisallowURLReplacement
);
256 } else if (match(attributeName
, relAttr
)) {
257 LinkRelAttribute
rel(attributeValue
);
258 m_linkIsStyleSheet
= rel
.isStyleSheet() && !rel
.isAlternate() && rel
.iconType() == InvalidIcon
&& !rel
.isDNSPrefetch();
259 m_linkIsPreconnect
= rel
.isPreconnect();
260 m_linkIsImport
= rel
.isImport();
261 } else if (match(attributeName
, mediaAttr
)) {
262 m_matchedMediaAttribute
= mediaAttributeMatches(*m_mediaValues
, attributeValue
);
263 } else if (match(attributeName
, crossoriginAttr
)) {
264 setCrossOriginAllowed(attributeValue
);
268 template<typename NameType
>
269 void processInputAttribute(const NameType
& attributeName
, const String
& attributeValue
)
271 // FIXME - Don't set type multiple times.
272 if (match(attributeName
, srcAttr
))
273 setUrlToLoad(attributeValue
, DisallowURLReplacement
);
274 else if (match(attributeName
, typeAttr
))
275 m_inputIsImage
= equalIgnoringCase(attributeValue
, InputTypeNames::image
);
278 template<typename NameType
>
279 void processSourceAttribute(const NameType
& attributeName
, const String
& attributeValue
)
281 if (match(attributeName
, srcsetAttr
) && m_srcsetImageCandidate
.isEmpty()) {
282 m_srcsetAttributeValue
= attributeValue
;
283 m_srcsetImageCandidate
= bestFitSourceForSrcsetAttribute(m_mediaValues
->devicePixelRatio(), m_sourceSize
, attributeValue
);
284 } else if (match(attributeName
, sizesAttr
) && !m_sourceSizeSet
) {
285 m_sourceSize
= SizesAttributeParser(m_mediaValues
, attributeValue
).length();
286 m_sourceSizeSet
= true;
287 if (!m_srcsetImageCandidate
.isEmpty()) {
288 m_srcsetImageCandidate
= bestFitSourceForSrcsetAttribute(m_mediaValues
->devicePixelRatio(), m_sourceSize
, m_srcsetAttributeValue
);
290 } else if (match(attributeName
, mediaAttr
)) {
291 // FIXME - Don't match media multiple times.
292 m_matchedMediaAttribute
= mediaAttributeMatches(*m_mediaValues
, attributeValue
);
296 template<typename NameType
>
297 void processVideoAttribute(const NameType
& attributeName
, const String
& attributeValue
)
299 if (match(attributeName
, posterAttr
))
300 setUrlToLoad(attributeValue
, DisallowURLReplacement
);
303 template<typename NameType
>
304 void processAttribute(const NameType
& attributeName
, const String
& attributeValue
)
306 if (match(attributeName
, charsetAttr
))
307 m_charset
= attributeValue
;
309 if (match(m_tagImpl
, scriptTag
))
310 processScriptAttribute(attributeName
, attributeValue
);
311 else if (match(m_tagImpl
, imgTag
))
312 processImgAttribute(attributeName
, attributeValue
);
313 else if (match(m_tagImpl
, linkTag
))
314 processLinkAttribute(attributeName
, attributeValue
);
315 else if (match(m_tagImpl
, inputTag
))
316 processInputAttribute(attributeName
, attributeValue
);
317 else if (match(m_tagImpl
, sourceTag
))
318 processSourceAttribute(attributeName
, attributeValue
);
319 else if (match(m_tagImpl
, videoTag
))
320 processVideoAttribute(attributeName
, attributeValue
);
323 void setUrlToLoad(const String
& value
, URLReplacement replacement
)
325 // We only respect the first src/href, per HTML5:
326 // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#attribute-name-state
327 if (replacement
== DisallowURLReplacement
&& !m_urlToLoad
.isEmpty())
329 String url
= stripLeadingAndTrailingHTMLSpaces(value
);
335 const String
& charset() const
337 // FIXME: Its not clear that this if is needed, the loader probably ignores charset for image requests anyway.
338 if (match(m_tagImpl
, imgTag
) || match(m_tagImpl
, videoTag
))
339 return emptyString();
343 Resource::Type
resourceType() const
345 if (match(m_tagImpl
, scriptTag
))
346 return Resource::Script
;
347 if (match(m_tagImpl
, imgTag
) || match(m_tagImpl
, videoTag
) || (match(m_tagImpl
, inputTag
) && m_inputIsImage
))
348 return Resource::Image
;
349 if (match(m_tagImpl
, linkTag
) && m_linkIsStyleSheet
)
350 return Resource::CSSStyleSheet
;
351 if (m_linkIsPreconnect
)
352 return Resource::Raw
;
353 if (match(m_tagImpl
, linkTag
) && m_linkIsImport
)
354 return Resource::ImportResource
;
355 ASSERT_NOT_REACHED();
356 return Resource::Raw
;
359 bool shouldPreconnect() const
361 return match(m_tagImpl
, linkTag
) && m_linkIsPreconnect
&& !m_urlToLoad
.isEmpty();
364 bool shouldPreload() const
366 if (m_urlToLoad
.isEmpty())
368 if (match(m_tagImpl
, linkTag
) && !m_linkIsStyleSheet
&& !m_linkIsImport
)
370 if (match(m_tagImpl
, inputTag
) && !m_inputIsImage
)
375 bool isCORSEnabled() const
377 return m_isCORSEnabled
;
380 StoredCredentials
allowStoredCredentials() const
382 return m_allowCredentials
;
385 void setCrossOriginAllowed(const String
& corsSetting
)
387 m_isCORSEnabled
= true;
388 if (!corsSetting
.isNull() && equalIgnoringCase(stripLeadingAndTrailingHTMLSpaces(corsSetting
), "use-credentials"))
389 m_allowCredentials
= AllowStoredCredentials
;
391 m_allowCredentials
= DoNotAllowStoredCredentials
;
394 void setDefer(FetchRequest::DeferOption defer
)
404 const StringImpl
* m_tagImpl
;
406 ImageCandidate m_srcsetImageCandidate
;
408 bool m_linkIsStyleSheet
;
409 bool m_linkIsPreconnect
;
411 bool m_matchedMediaAttribute
;
414 String m_srcsetAttributeValue
;
416 bool m_sourceSizeSet
;
417 bool m_isCORSEnabled
;
418 FetchRequest::DeferOption m_defer
;
419 StoredCredentials m_allowCredentials
;
420 RefPtrWillBeMember
<MediaValues
> m_mediaValues
;
421 bool m_referrerPolicySet
;
422 ReferrerPolicy m_referrerPolicy
;
425 TokenPreloadScanner::TokenPreloadScanner(const KURL
& documentURL
, PassOwnPtr
<CachedDocumentParameters
> documentParameters
)
426 : m_documentURL(documentURL
)
429 , m_isAppCacheEnabled(false)
430 , m_isCSPEnabled(false)
432 , m_documentParameters(documentParameters
)
434 ASSERT(m_documentParameters
.get());
435 ASSERT(m_documentParameters
->mediaValues
.get());
436 ASSERT(m_documentParameters
->mediaValues
->isCached());
439 TokenPreloadScanner::~TokenPreloadScanner()
443 TokenPreloadScannerCheckpoint
TokenPreloadScanner::createCheckpoint()
445 TokenPreloadScannerCheckpoint checkpoint
= m_checkpoints
.size();
446 m_checkpoints
.append(Checkpoint(m_predictedBaseElementURL
, m_inStyle
, m_isAppCacheEnabled
, m_isCSPEnabled
, m_templateCount
));
450 void TokenPreloadScanner::rewindTo(TokenPreloadScannerCheckpoint checkpointIndex
)
452 ASSERT(checkpointIndex
< m_checkpoints
.size()); // If this ASSERT fires, checkpointIndex is invalid.
453 const Checkpoint
& checkpoint
= m_checkpoints
[checkpointIndex
];
454 m_predictedBaseElementURL
= checkpoint
.predictedBaseElementURL
;
455 m_inStyle
= checkpoint
.inStyle
;
456 m_isAppCacheEnabled
= checkpoint
.isAppCacheEnabled
;
457 m_isCSPEnabled
= checkpoint
.isCSPEnabled
;
458 m_templateCount
= checkpoint
.templateCount
;
459 m_cssScanner
.reset();
460 m_checkpoints
.clear();
463 void TokenPreloadScanner::scan(const HTMLToken
& token
, const SegmentedString
& source
, PreloadRequestStream
& requests
)
465 scanCommon(token
, source
, requests
);
468 void TokenPreloadScanner::scan(const CompactHTMLToken
& token
, const SegmentedString
& source
, PreloadRequestStream
& requests
)
470 scanCommon(token
, source
, requests
);
473 static void handleMetaViewport(const String
& attributeValue
, CachedDocumentParameters
* documentParameters
)
475 if (!documentParameters
->viewportMetaEnabled
)
477 ViewportDescription
description(ViewportDescription::ViewportMeta
);
478 HTMLMetaElement::getViewportDescriptionFromContentAttribute(attributeValue
, description
, nullptr, documentParameters
->viewportMetaZeroValuesQuirk
);
479 FloatSize
initialViewport(documentParameters
->mediaValues
->deviceWidth(), documentParameters
->mediaValues
->deviceHeight());
480 PageScaleConstraints constraints
= description
.resolve(initialViewport
, documentParameters
->defaultViewportMinWidth
);
481 MediaValuesCached
* cachedMediaValues
= static_cast<MediaValuesCached
*>(documentParameters
->mediaValues
.get());
482 cachedMediaValues
->setViewportHeight(constraints
.layoutSize
.height());
483 cachedMediaValues
->setViewportWidth(constraints
.layoutSize
.width());
486 static void handleMetaReferrer(const String
& attributeValue
, CachedDocumentParameters
* documentParameters
, CSSPreloadScanner
* cssScanner
)
488 if (attributeValue
.isEmpty() || attributeValue
.isNull() || !SecurityPolicy::referrerPolicyFromString(attributeValue
, &documentParameters
->referrerPolicy
)) {
489 documentParameters
->referrerPolicy
= ReferrerPolicyDefault
;
491 cssScanner
->setReferrerPolicy(documentParameters
->referrerPolicy
);
494 template <typename Token
>
495 static void handleMetaNameAttribute(const Token
& token
, CachedDocumentParameters
* documentParameters
, CSSPreloadScanner
* cssScanner
)
497 const typename
Token::Attribute
* nameAttribute
= token
.getAttributeItem(nameAttr
);
501 String
nameAttributeValue(nameAttribute
->value
);
502 const typename
Token::Attribute
* contentAttribute
= token
.getAttributeItem(contentAttr
);
503 if (!contentAttribute
)
506 String
contentAttributeValue(contentAttribute
->value
);
507 if (equalIgnoringCase(nameAttributeValue
, "viewport")) {
508 handleMetaViewport(contentAttributeValue
, documentParameters
);
512 if (equalIgnoringCase(nameAttributeValue
, "referrer")) {
513 handleMetaReferrer(contentAttributeValue
, documentParameters
, cssScanner
);
517 template <typename Token
>
518 void TokenPreloadScanner::scanCommon(const Token
& token
, const SegmentedString
& source
, PreloadRequestStream
& requests
)
520 if (!m_documentParameters
->doHtmlPreloadScanning
)
523 // Disable preload for documents with AppCache.
524 if (m_isAppCacheEnabled
)
527 // http://crbug.com/434230 Disable preload for documents with CSP <meta> tags
531 switch (token
.type()) {
532 case HTMLToken::Character
: {
535 m_cssScanner
.scan(token
.data(), source
, requests
);
538 case HTMLToken::EndTag
: {
539 const StringImpl
* tagImpl
= tagImplFor(token
.data());
540 if (match(tagImpl
, templateTag
)) {
545 if (match(tagImpl
, styleTag
)) {
547 m_cssScanner
.reset();
551 if (match(tagImpl
, pictureTag
))
555 case HTMLToken::StartTag
: {
558 const StringImpl
* tagImpl
= tagImplFor(token
.data());
559 if (match(tagImpl
, templateTag
)) {
563 if (match(tagImpl
, styleTag
)) {
567 if (match(tagImpl
, baseTag
)) {
568 // The first <base> element is the one that wins.
569 if (!m_predictedBaseElementURL
.isEmpty())
571 updatePredictedBaseURL(token
);
574 if (match(tagImpl
, htmlTag
) && token
.getAttributeItem(manifestAttr
)) {
575 m_isAppCacheEnabled
= true;
578 if (match(tagImpl
, metaTag
)) {
579 const typename
Token::Attribute
* equivAttribute
= token
.getAttributeItem(http_equivAttr
);
580 if (equivAttribute
) {
581 String
equivAttributeValue(equivAttribute
->value
);
582 if (equalIgnoringCase(equivAttributeValue
, "content-security-policy")) {
583 m_isCSPEnabled
= true;
584 } else if (equalIgnoringCase(equivAttributeValue
, "accept-ch")) {
585 const typename
Token::Attribute
* contentAttribute
= token
.getAttributeItem(contentAttr
);
586 if (contentAttribute
)
587 m_clientHintsPreferences
.updateFromAcceptClientHintsHeader(String(contentAttribute
->value
), nullptr);
592 handleMetaNameAttribute(token
, m_documentParameters
.get(), &m_cssScanner
);
595 if (match(tagImpl
, pictureTag
)) {
597 m_pictureData
= PictureData();
601 StartTagScanner
scanner(tagImpl
, m_documentParameters
->mediaValues
);
602 scanner
.processAttributes(token
.attributes());
604 scanner
.handlePictureSourceURL(m_pictureData
);
605 OwnPtr
<PreloadRequest
> request
= scanner
.createPreloadRequest(m_predictedBaseElementURL
, source
, m_clientHintsPreferences
, m_pictureData
, m_documentParameters
->referrerPolicy
);
607 requests
.append(request
.release());
616 template<typename Token
>
617 void TokenPreloadScanner::updatePredictedBaseURL(const Token
& token
)
619 ASSERT(m_predictedBaseElementURL
.isEmpty());
620 if (const typename
Token::Attribute
* hrefAttribute
= token
.getAttributeItem(hrefAttr
)) {
621 KURL
url(m_documentURL
, stripLeadingAndTrailingHTMLSpaces(hrefAttribute
->value
));
622 m_predictedBaseElementURL
= url
.isValid() ? url
.copy() : KURL();
626 HTMLPreloadScanner::HTMLPreloadScanner(const HTMLParserOptions
& options
, const KURL
& documentURL
, PassOwnPtr
<CachedDocumentParameters
> documentParameters
)
627 : m_scanner(documentURL
, documentParameters
)
628 , m_tokenizer(HTMLTokenizer::create(options
))
632 HTMLPreloadScanner::~HTMLPreloadScanner()
636 void HTMLPreloadScanner::appendToEnd(const SegmentedString
& source
)
638 m_source
.append(source
);
641 void HTMLPreloadScanner::scan(ResourcePreloader
* preloader
, const KURL
& startingBaseElementURL
)
643 ASSERT(isMainThread()); // HTMLTokenizer::updateStateFor only works on the main thread.
645 TRACE_EVENT1("blink", "HTMLPreloadScanner::scan", "source_length", m_source
.length());
647 // When we start scanning, our best prediction of the baseElementURL is the real one!
648 if (!startingBaseElementURL
.isEmpty())
649 m_scanner
.setPredictedBaseElementURL(startingBaseElementURL
);
651 PreloadRequestStream requests
;
653 while (m_tokenizer
->nextToken(m_source
, m_token
)) {
654 if (m_token
.type() == HTMLToken::StartTag
)
655 m_tokenizer
->updateStateFor(attemptStaticStringCreation(m_token
.name(), Likely8Bit
));
656 m_scanner
.scan(m_token
, m_source
, requests
);
660 preloader
->takeAndPreload(requests
);
663 CachedDocumentParameters::CachedDocumentParameters(Document
* document
, PassRefPtrWillBeRawPtr
<MediaValues
> givenMediaValues
)
665 ASSERT(isMainThread());
667 doHtmlPreloadScanning
= !document
->settings() || document
->settings()->doHtmlPreloadScanning();
668 if (givenMediaValues
)
669 mediaValues
= givenMediaValues
;
671 mediaValues
= MediaValuesCached::create(*document
);
672 ASSERT(mediaValues
->isSafeToSendToAnotherThread());
673 defaultViewportMinWidth
= document
->viewportDefaultMinWidth();
674 viewportMetaZeroValuesQuirk
= document
->settings() && document
->settings()->viewportMetaZeroValuesQuirk();
675 viewportMetaEnabled
= document
->settings() && document
->settings()->viewportMetaEnabled();
676 referrerPolicy
= ReferrerPolicyDefault
;