WebCore/loader/icon/IconFetcher.cpp
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     1 /*
       
     2  * Copyright (C) 2008 Apple Inc. All Rights Reserved.
       
     3  *
       
     4  * Redistribution and use in source and binary forms, with or without
       
     5  * modification, are permitted provided that the following conditions
       
     6  * are met:
       
     7  * 1. Redistributions of source code must retain the above copyright
       
     8  *    notice, this list of conditions and the following disclaimer.
       
     9  * 2. Redistributions in binary form must reproduce the above copyright
       
    10  *    notice, this list of conditions and the following disclaimer in the
       
    11  *    documentation and/or other materials provided with the distribution.
       
    12  *
       
    13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
       
    14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
       
    15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
       
    16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
       
    17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
       
    18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
       
    19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
       
    20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
       
    21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
       
    22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
       
    23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
       
    24  */
       
    25 
       
    26 #include "config.h"
       
    27 #include "IconFetcher.h"
       
    28 
       
    29 #include "Frame.h"
       
    30 #include "HTMLHeadElement.h"
       
    31 #include "HTMLLinkElement.h"
       
    32 #include "HTMLNames.h"
       
    33 #include "ResourceHandle.h"
       
    34 #include "ResourceRequest.h"
       
    35 #include "SharedBuffer.h"
       
    36 
       
    37 namespace WebCore {
       
    38 
       
    39 using namespace HTMLNames;
       
    40 
       
    41 struct IconLinkEntry {
       
    42 public:
       
    43     enum IconType {
       
    44         Unknown,
       
    45         ICNS,
       
    46         ICO,
       
    47     };
       
    48     
       
    49     IconLinkEntry(IconType type, const KURL& url) 
       
    50         : m_type(type)
       
    51         , m_url(url)
       
    52     {
       
    53     }
       
    54     
       
    55     IconType type() const { return m_type; }
       
    56     const KURL& url() const { return m_url; }
       
    57 
       
    58     SharedBuffer* buffer() 
       
    59     {
       
    60         if (!m_buffer)
       
    61             m_buffer = SharedBuffer::create();
       
    62         
       
    63         return m_buffer.get();
       
    64     }
       
    65     
       
    66 private:
       
    67     RefPtr<SharedBuffer> m_buffer;
       
    68     IconType m_type;
       
    69     KURL m_url;
       
    70 };
       
    71     
       
    72 #if PLATFORM(MAC)
       
    73 static const IconLinkEntry::IconType NativeIconType = IconLinkEntry::ICNS;
       
    74 #elif PLATFORM(WIN)
       
    75 static const IconLinkEntry::IconType NativeIconType = IconLinkEntry::ICO;
       
    76 #else
       
    77 static const IconLinkEntry::IconType NativeIconType = IconLinkEntry::Unknown;
       
    78 #endif
       
    79 
       
    80 static void parseIconLink(HTMLLinkElement* link, Vector<IconLinkEntry>& entries)
       
    81 {
       
    82     // FIXME: Parse the size attribute too.
       
    83     
       
    84     IconLinkEntry::IconType type = IconLinkEntry::Unknown;
       
    85     const KURL& url = link->href();
       
    86 
       
    87     // Try to determine the file type.
       
    88     String path = url.path();
       
    89     
       
    90     int pos = path.reverseFind('.');
       
    91     if (pos >= 0) {
       
    92         String extension = path.substring(pos + 1);
       
    93         if (equalIgnoringCase(extension, "icns"))
       
    94             type = IconLinkEntry::ICNS;
       
    95         else if (equalIgnoringCase(extension, "ico"))
       
    96             type = IconLinkEntry::ICO;
       
    97     }
       
    98     
       
    99     entries.append(IconLinkEntry(type, url));
       
   100 }
       
   101     
       
   102 PassRefPtr<IconFetcher> IconFetcher::create(Frame* frame, IconFetcherClient* client)
       
   103 {
       
   104     Document* document = frame->document();
       
   105     
       
   106     HTMLHeadElement* head = document->head();
       
   107     if (!head)
       
   108         return 0;
       
   109     
       
   110     Vector<IconLinkEntry> entries;
       
   111     
       
   112     for (Node* n = head; n; n = n->traverseNextNode()) {
       
   113         if (!n->hasTagName(linkTag))    
       
   114             continue;
       
   115             
       
   116         HTMLLinkElement* link = static_cast<HTMLLinkElement*>(n);
       
   117         if (!link->isIcon())
       
   118             continue;
       
   119 
       
   120         parseIconLink(link, entries);
       
   121     }
       
   122     
       
   123     if (entries.isEmpty())
       
   124         return 0;
       
   125     
       
   126     // Check if any of the entries have the same type as the native icon type.
       
   127 
       
   128     // FIXME: This should be way more sophisticated, and handle conversion
       
   129     // of multisize formats for example.
       
   130     for (unsigned i = 0; i < entries.size(); i++) {
       
   131         const IconLinkEntry& entry = entries[i];
       
   132         if (entry.type() == NativeIconType) {
       
   133             RefPtr<IconFetcher> iconFetcher = adoptRef(new IconFetcher(frame, client));
       
   134             
       
   135             iconFetcher->m_entries.append(entry);
       
   136             iconFetcher->loadEntry();
       
   137             
       
   138             return iconFetcher.release();
       
   139         }
       
   140     }
       
   141 
       
   142     return 0;
       
   143 }    
       
   144 
       
   145 IconFetcher::IconFetcher(Frame* frame, IconFetcherClient* client)
       
   146     : m_frame(frame)
       
   147     , m_client(client)
       
   148     , m_currentEntry(0)
       
   149 {
       
   150 }
       
   151     
       
   152 IconFetcher::~IconFetcher()
       
   153 {
       
   154     cancel();
       
   155 }
       
   156 
       
   157 void IconFetcher::cancel()
       
   158 {
       
   159     if (m_handle)
       
   160         m_handle->cancel();
       
   161 }
       
   162 
       
   163 PassRefPtr<SharedBuffer> IconFetcher::createIcon()
       
   164 {
       
   165     ASSERT(!m_entries.isEmpty());
       
   166     
       
   167     // For now, just return the data of the first entry.
       
   168     return m_entries.first().buffer();
       
   169 }
       
   170 
       
   171 void IconFetcher::loadEntry()
       
   172 {
       
   173     ASSERT(m_currentEntry < m_entries.size());
       
   174     ASSERT(!m_handle);
       
   175     
       
   176     m_handle = ResourceHandle::create(m_entries[m_currentEntry].url(), this, m_frame, false, false);
       
   177 }
       
   178     
       
   179 void IconFetcher::loadFailed()
       
   180 {
       
   181     m_handle = 0;
       
   182     
       
   183     m_client->finishedFetchingIcon(0);
       
   184 }    
       
   185     
       
   186 void IconFetcher::didReceiveResponse(ResourceHandle* handle, const ResourceResponse& response)
       
   187 {
       
   188     ASSERT_UNUSED(handle, m_handle == handle);
       
   189     
       
   190     int statusCode = response.httpStatusCode() / 100;
       
   191     if (statusCode == 4 || statusCode == 5) {
       
   192         loadFailed();
       
   193         return;
       
   194     }    
       
   195 }
       
   196     
       
   197 void IconFetcher::didReceiveData(ResourceHandle* handle, const char* data, int length, int)
       
   198 {
       
   199     ASSERT_UNUSED(handle, m_handle == handle);
       
   200     
       
   201     m_entries[m_currentEntry].buffer()->append(data, length);
       
   202 }
       
   203 
       
   204 void IconFetcher::didFinishLoading(ResourceHandle* handle)
       
   205 {
       
   206     ASSERT_UNUSED(handle, m_handle == handle);
       
   207     
       
   208     if (m_currentEntry == m_entries.size() - 1) {
       
   209         // We finished loading, create the icon
       
   210         RefPtr<SharedBuffer> iconData = createIcon();
       
   211         
       
   212         m_client->finishedFetchingIcon(iconData.release());
       
   213         return;
       
   214     }
       
   215     
       
   216     // Load the next entry
       
   217     m_currentEntry++;
       
   218 
       
   219     loadEntry();
       
   220 }
       
   221     
       
   222 void IconFetcher::didFail(ResourceHandle* handle, const ResourceError&)
       
   223 {
       
   224     ASSERT_UNUSED(handle, m_handle == handle);
       
   225     
       
   226     loadFailed();
       
   227 }
       
   228 
       
   229 } // namespace WebCore