106ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen/* 206ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen * Copyright (C) 2008 Apple Inc. All Rights Reserved. 306ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen * Copyright (C) 2009 Torch Mobile, Inc. http://www.torchmobile.com/ 406ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen * Copyright (C) 2010 Google Inc. All Rights Reserved. 506ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen * 606ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen * Redistribution and use in source and binary forms, with or without 706ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen * modification, are permitted provided that the following conditions 806ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen * are met: 906ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen * 1. Redistributions of source code must retain the above copyright 1006ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen * notice, this list of conditions and the following disclaimer. 1106ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen * 2. Redistributions in binary form must reproduce the above copyright 1206ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen * notice, this list of conditions and the following disclaimer in the 1306ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen * documentation and/or other materials provided with the distribution. 1406ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen * 1506ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 1606ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1706ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 1806ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 1906ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 2006ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 2106ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 2206ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 2306ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2406ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 2506ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2606ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen */ 2706ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen 2806ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen#include "config.h" 2906ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen#include "HTMLPreloadScanner.h" 3006ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen 315abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick#include "CachedResourceLoader.h" 3206ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen#include "Document.h" 332bde8e466a4451c7319e3a072d118917957d6554Steve Block#include "InputType.h" 3468513a70bcd92384395513322f1b801e7bf9c729Steve Block#include "HTMLDocumentParser.h" 35e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block#include "HTMLTokenizer.h" 3606ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen#include "HTMLLinkElement.h" 3706ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen#include "HTMLNames.h" 38a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#include "HTMLParserIdioms.h" 39f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch#include "MediaList.h" 40f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch#include "MediaQueryEvaluator.h" 4106ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen 4206ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsennamespace WebCore { 4306ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen 4406ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsenusing namespace HTMLNames; 4506ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen 4606ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsennamespace { 4706ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen 4806ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsenclass PreloadTask { 4906ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsenpublic: 5006ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen PreloadTask(const HTMLToken& token) 5106ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen : m_tagName(token.name().data(), token.name().size()) 5206ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen , m_linkIsStyleSheet(false) 53f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch , m_linkMediaAttributeIsScreen(true) 542bde8e466a4451c7319e3a072d118917957d6554Steve Block , m_inputIsImage(false) 5506ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen { 5606ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen processAttributes(token.attributes()); 5706ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen } 5806ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen 5906ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen void processAttributes(const HTMLToken::AttributeList& attributes) 6006ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen { 612bde8e466a4451c7319e3a072d118917957d6554Steve Block if (m_tagName != imgTag 622bde8e466a4451c7319e3a072d118917957d6554Steve Block && m_tagName != inputTag 632bde8e466a4451c7319e3a072d118917957d6554Steve Block && m_tagName != linkTag 642bde8e466a4451c7319e3a072d118917957d6554Steve Block && m_tagName != scriptTag) 6506ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen return; 6606ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen 6706ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen for (HTMLToken::AttributeList::const_iterator iter = attributes.begin(); 6806ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen iter != attributes.end(); ++iter) { 6906ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen AtomicString attributeName(iter->m_name.data(), iter->m_name.size()); 7006ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen String attributeValue(iter->m_value.data(), iter->m_value.size()); 7106ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen 7206ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen if (attributeName == charsetAttr) 7306ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen m_charset = attributeValue; 7406ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen 7506ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen if (m_tagName == scriptTag || m_tagName == imgTag) { 7606ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen if (attributeName == srcAttr) 7706ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen setUrlToLoad(attributeValue); 7806ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen } else if (m_tagName == linkTag) { 7906ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen if (attributeName == hrefAttr) 8006ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen setUrlToLoad(attributeValue); 8106ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen else if (attributeName == relAttr) 8206ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen m_linkIsStyleSheet = relAttributeIsStyleSheet(attributeValue); 83f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch else if (attributeName == mediaAttr) 84f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch m_linkMediaAttributeIsScreen = linkMediaAttributeIsScreen(attributeValue); 852bde8e466a4451c7319e3a072d118917957d6554Steve Block } else if (m_tagName == inputTag) { 862bde8e466a4451c7319e3a072d118917957d6554Steve Block if (attributeName == srcAttr) 872bde8e466a4451c7319e3a072d118917957d6554Steve Block setUrlToLoad(attributeValue); 882bde8e466a4451c7319e3a072d118917957d6554Steve Block else if (attributeName == typeAttr) 892bde8e466a4451c7319e3a072d118917957d6554Steve Block m_inputIsImage = equalIgnoringCase(attributeValue, InputTypeNames::image()); 9006ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen } 9106ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen } 9206ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen } 9306ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen 94f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch static bool relAttributeIsStyleSheet(const String& attributeValue) 9506ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen { 9606ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen HTMLLinkElement::RelAttribute rel; 9706ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen HTMLLinkElement::tokenizeRelAttribute(attributeValue, rel); 9806ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen return rel.m_isStyleSheet && !rel.m_isAlternate && !rel.m_isIcon && !rel.m_isDNSPrefetch; 9906ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen } 1002bde8e466a4451c7319e3a072d118917957d6554Steve Block 101f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch static bool linkMediaAttributeIsScreen(const String& attributeValue) 102f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch { 103f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch if (attributeValue.isEmpty()) 104f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch return true; 105f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch RefPtr<MediaList> mediaList = MediaList::createAllowingDescriptionSyntax(attributeValue); 106f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch 107f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch // Only preload screen media stylesheets. Used this way, the evaluator evaluates to true for any 108f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch // rules containing complex queries (full evaluation is possible but it requires a frame and a style selector which 109f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch // may be problematic here). 110f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch MediaQueryEvaluator mediaQueryEvaluator("screen"); 111f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch return mediaQueryEvaluator.eval(mediaList.get()); 112f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch } 11306ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen 11406ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen void setUrlToLoad(const String& attributeValue) 11506ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen { 11606ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen // We only respect the first src/href, per HTML5: 11706ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#attribute-name-state 11806ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen if (!m_urlToLoad.isEmpty()) 11906ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen return; 120a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch m_urlToLoad = stripLeadingAndTrailingHTMLSpaces(attributeValue); 12106ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen } 12206ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen 12306ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen void preload(Document* document, bool scanningBody) 12406ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen { 12506ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen if (m_urlToLoad.isEmpty()) 12606ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen return; 12706ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen 1285abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick CachedResourceLoader* cachedResourceLoader = document->cachedResourceLoader(); 12906ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen if (m_tagName == scriptTag) 1305abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick cachedResourceLoader->preload(CachedResource::Script, m_urlToLoad, m_charset, scanningBody); 1312bde8e466a4451c7319e3a072d118917957d6554Steve Block else if (m_tagName == imgTag || (m_tagName == inputTag && m_inputIsImage)) 1325abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick cachedResourceLoader->preload(CachedResource::ImageResource, m_urlToLoad, String(), scanningBody); 133f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch else if (m_tagName == linkTag && m_linkIsStyleSheet && m_linkMediaAttributeIsScreen) 1345abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick cachedResourceLoader->preload(CachedResource::CSSStyleSheet, m_urlToLoad, m_charset, scanningBody); 13506ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen } 13606ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen 13706ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen const AtomicString& tagName() const { return m_tagName; } 13806ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen 13906ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsenprivate: 14006ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen AtomicString m_tagName; 14106ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen String m_urlToLoad; 14206ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen String m_charset; 14306ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen bool m_linkIsStyleSheet; 144f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch bool m_linkMediaAttributeIsScreen; 1452bde8e466a4451c7319e3a072d118917957d6554Steve Block bool m_inputIsImage; 14606ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen}; 14706ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen 14806ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen} // namespace 14906ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen 15006ea8e899e48f1f2f396b70e63fae369f2f23232Kristian MonsenHTMLPreloadScanner::HTMLPreloadScanner(Document* document) 15106ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen : m_document(document) 15206ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen , m_cssScanner(document) 15368513a70bcd92384395513322f1b801e7bf9c729Steve Block , m_tokenizer(HTMLTokenizer::create(HTMLDocumentParser::usePreHTML5ParserQuirks(document))) 15406ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen , m_bodySeen(false) 15506ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen , m_inStyle(false) 15606ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen{ 15706ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen} 15806ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen 15906ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsenvoid HTMLPreloadScanner::appendToEnd(const SegmentedString& source) 16006ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen{ 16106ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen m_source.append(source); 16206ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen} 16306ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen 16406ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsenvoid HTMLPreloadScanner::scan() 16506ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen{ 16606ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen // FIXME: We should save and re-use these tokens in HTMLDocumentParser if 16706ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen // the pending script doesn't end up calling document.write. 168e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block while (m_tokenizer->nextToken(m_source, m_token)) { 16906ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen processToken(); 17006ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen m_token.clear(); 17106ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen } 17206ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen} 17306ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen 17406ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsenvoid HTMLPreloadScanner::processToken() 17506ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen{ 17606ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen if (m_inStyle) { 17706ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen if (m_token.type() == HTMLToken::Character) 17806ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen m_cssScanner.scan(m_token, scanningBody()); 17906ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen else if (m_token.type() == HTMLToken::EndTag) { 18006ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen m_inStyle = false; 18106ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen m_cssScanner.reset(); 18206ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen } 18306ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen } 18406ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen 18506ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen if (m_token.type() != HTMLToken::StartTag) 18606ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen return; 18706ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen 18806ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen PreloadTask task(m_token); 18968513a70bcd92384395513322f1b801e7bf9c729Steve Block m_tokenizer->updateStateFor(task.tagName(), m_document->frame()); 19006ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen 19106ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen if (task.tagName() == bodyTag) 19206ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen m_bodySeen = true; 19306ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen 19406ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen if (task.tagName() == styleTag) 19506ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen m_inStyle = true; 19606ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen 19706ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen task.preload(m_document, scanningBody()); 19806ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen} 19906ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen 20006ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsenbool HTMLPreloadScanner::scanningBody() const 20106ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen{ 20206ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen return m_document->body() || m_bodySeen; 20306ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen} 20406ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen 20506ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen} 206