WebCore/html/HTMLPreloadScanner.cpp
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     1 /*
       
     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.
       
     5  *
       
     6  * Redistribution and use in source and binary forms, with or without
       
     7  * modification, are permitted provided that the following conditions
       
     8  * are met:
       
     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.
       
    14  *
       
    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. 
       
    26  */
       
    27 
       
    28 #include "config.h"
       
    29 #include "HTMLPreloadScanner.h"
       
    30 
       
    31 #include "CSSHelper.h"
       
    32 #include "DocLoader.h"
       
    33 #include "Document.h"
       
    34 #include "HTMLTreeBuilder.h"
       
    35 #include "HTMLLinkElement.h"
       
    36 #include "HTMLNames.h"
       
    37 
       
    38 namespace WebCore {
       
    39 
       
    40 using namespace HTMLNames;
       
    41 
       
    42 namespace {
       
    43 
       
    44 class PreloadTask {
       
    45 public:
       
    46     PreloadTask(const HTMLToken& token)
       
    47         : m_tagName(token.name().data(), token.name().size())
       
    48         , m_linkIsStyleSheet(false)
       
    49     {
       
    50         processAttributes(token.attributes());
       
    51     }
       
    52 
       
    53     void processAttributes(const HTMLToken::AttributeList& attributes)
       
    54     {
       
    55         if (m_tagName != scriptTag && m_tagName != imgTag && m_tagName != linkTag)
       
    56             return;
       
    57 
       
    58         for (HTMLToken::AttributeList::const_iterator iter = attributes.begin();
       
    59              iter != attributes.end(); ++iter) {
       
    60             AtomicString attributeName(iter->m_name.data(), iter->m_name.size());
       
    61             String attributeValue(iter->m_value.data(), iter->m_value.size());
       
    62 
       
    63             if (attributeName == charsetAttr)
       
    64                 m_charset = attributeValue;
       
    65 
       
    66             if (m_tagName == scriptTag || m_tagName == imgTag) {
       
    67                 if (attributeName == srcAttr)
       
    68                     setUrlToLoad(attributeValue);
       
    69             } else if (m_tagName == linkTag) {
       
    70                 if (attributeName == hrefAttr)
       
    71                     setUrlToLoad(attributeValue);
       
    72                 else if (attributeName == relAttr)
       
    73                     m_linkIsStyleSheet = relAttributeIsStyleSheet(attributeValue);
       
    74             }
       
    75         }
       
    76     }
       
    77 
       
    78     bool relAttributeIsStyleSheet(const String& attributeValue)
       
    79     {
       
    80         ASSERT(m_tagName == linkTag);
       
    81         HTMLLinkElement::RelAttribute rel;
       
    82         HTMLLinkElement::tokenizeRelAttribute(attributeValue, rel);
       
    83         return rel.m_isStyleSheet && !rel.m_isAlternate && !rel.m_isIcon && !rel.m_isDNSPrefetch;
       
    84     }
       
    85 
       
    86     void setUrlToLoad(const String& attributeValue)
       
    87     {
       
    88         // We only respect the first src/href, per HTML5:
       
    89         // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#attribute-name-state
       
    90         if (!m_urlToLoad.isEmpty())
       
    91             return;
       
    92         m_urlToLoad = deprecatedParseURL(attributeValue);
       
    93     }
       
    94 
       
    95     void preload(Document* document, bool scanningBody)
       
    96     {
       
    97         if (m_urlToLoad.isEmpty())
       
    98             return;
       
    99 
       
   100         DocLoader* docLoader = document->docLoader();
       
   101         if (m_tagName == scriptTag)
       
   102             docLoader->preload(CachedResource::Script, m_urlToLoad, m_charset, scanningBody);
       
   103         else if (m_tagName == imgTag) 
       
   104             docLoader->preload(CachedResource::ImageResource, m_urlToLoad, String(), scanningBody);
       
   105         else if (m_tagName == linkTag && m_linkIsStyleSheet) 
       
   106             docLoader->preload(CachedResource::CSSStyleSheet, m_urlToLoad, m_charset, scanningBody);
       
   107     }
       
   108 
       
   109     const AtomicString& tagName() const { return m_tagName; }
       
   110 
       
   111 private:
       
   112     AtomicString m_tagName;
       
   113     String m_urlToLoad;
       
   114     String m_charset;
       
   115     bool m_linkIsStyleSheet;
       
   116 };
       
   117 
       
   118 } // namespace
       
   119 
       
   120 HTMLPreloadScanner::HTMLPreloadScanner(Document* document)
       
   121     : m_document(document)
       
   122     , m_cssScanner(document)
       
   123     , m_bodySeen(false)
       
   124     , m_inStyle(false)
       
   125 {
       
   126 }
       
   127 
       
   128 void HTMLPreloadScanner::appendToEnd(const SegmentedString& source)
       
   129 {
       
   130     m_source.append(source);
       
   131 }
       
   132 
       
   133 void HTMLPreloadScanner::scan()
       
   134 {
       
   135     // FIXME: We should save and re-use these tokens in HTMLDocumentParser if
       
   136     // the pending script doesn't end up calling document.write.
       
   137     while (m_tokenizer.nextToken(m_source, m_token)) {
       
   138         processToken();
       
   139         m_token.clear();
       
   140     }
       
   141 }
       
   142 
       
   143 void HTMLPreloadScanner::processToken()
       
   144 {
       
   145     if (m_inStyle) {
       
   146         if (m_token.type() == HTMLToken::Character)
       
   147             m_cssScanner.scan(m_token, scanningBody());
       
   148         else if (m_token.type() == HTMLToken::EndTag) {
       
   149             m_inStyle = false;
       
   150             m_cssScanner.reset();
       
   151         }
       
   152     }
       
   153 
       
   154     if (m_token.type() != HTMLToken::StartTag)
       
   155         return;
       
   156 
       
   157     PreloadTask task(m_token);
       
   158     m_tokenizer.setState(HTMLTreeBuilder::adjustedLexerState(m_tokenizer.state(), task.tagName(), m_document->frame()));
       
   159     if (task.tagName() == scriptTag) {
       
   160         // The tree builder handles scriptTag separately from the other tokenizer
       
   161         // state adjustments, so we need to handle it separately too.
       
   162         ASSERT(m_tokenizer.state() == HTMLTokenizer::DataState);
       
   163         m_tokenizer.setState(HTMLTokenizer::ScriptDataState);
       
   164     }
       
   165 
       
   166     if (task.tagName() == bodyTag)
       
   167         m_bodySeen = true;
       
   168 
       
   169     if (task.tagName() == styleTag)
       
   170         m_inStyle = true;
       
   171 
       
   172     task.preload(m_document, scanningBody());
       
   173 }
       
   174 
       
   175 bool HTMLPreloadScanner::scanningBody() const
       
   176 {
       
   177     return m_document->body() || m_bodySeen;
       
   178 }
       
   179 
       
   180 }