• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
36 namespace WebCore {
37 
38 using namespace HTMLNames;
39 
40 struct IconLinkEntry {
41 public:
42     enum IconType {
43         Unknown,
44         ICNS,
45         ICO,
46     };
47 
IconLinkEntryWebCore::IconLinkEntry48     IconLinkEntry(IconType type, const KURL& url)
49         : m_type(type)
50         , m_url(url)
51     {
52     }
53 
typeWebCore::IconLinkEntry54     IconType type() const { return m_type; }
urlWebCore::IconLinkEntry55     const KURL& url() const { return m_url; }
56 
bufferWebCore::IconLinkEntry57     SharedBuffer* buffer()
58     {
59         if (!m_buffer)
60             m_buffer = SharedBuffer::create();
61 
62         return m_buffer.get();
63     }
64 
65 private:
66     RefPtr<SharedBuffer> m_buffer;
67     IconType m_type;
68     KURL m_url;
69 };
70 
71 #if PLATFORM(MAC)
72 static const IconLinkEntry::IconType NativeIconType = IconLinkEntry::ICNS;
73 #elif PLATFORM(WIN)
74 static const IconLinkEntry::IconType NativeIconType = IconLinkEntry::ICO;
75 #else
76 static const IconLinkEntry::IconType NativeIconType = IconLinkEntry::Unknown;
77 #endif
78 
parseIconLink(HTMLLinkElement * link,Vector<IconLinkEntry> & entries)79 static void parseIconLink(HTMLLinkElement* link, Vector<IconLinkEntry>& entries)
80 {
81     // FIXME: Parse the size attribute too.
82 
83     IconLinkEntry::IconType type = IconLinkEntry::Unknown;
84     const KURL& url = link->href();
85 
86     // Try to determine the file type.
87     String path = url.path();
88 
89     int pos = path.reverseFind('.');
90     if (pos >= 0) {
91         String extension = path.substring(pos + 1);
92         if (equalIgnoringCase(extension, "icns"))
93             type = IconLinkEntry::ICNS;
94         else if (equalIgnoringCase(extension, "ico"))
95             type = IconLinkEntry::ICO;
96     }
97 
98     entries.append(IconLinkEntry(type, url));
99 }
100 
create(Frame * frame,IconFetcherClient * client)101 PassRefPtr<IconFetcher> IconFetcher::create(Frame* frame, IconFetcherClient* client)
102 {
103     Document* document = frame->document();
104     if (!document)
105         return 0;
106 
107     HTMLHeadElement* head = document->head();
108     if (!head)
109         return 0;
110 
111     Vector<IconLinkEntry> entries;
112 
113     for (Node* n = head; n; n = n->traverseNextNode()) {
114         if (!n->hasTagName(linkTag))
115             continue;
116 
117         HTMLLinkElement* link = static_cast<HTMLLinkElement*>(n);
118         if (!link->isIcon())
119             continue;
120 
121         parseIconLink(link, entries);
122     }
123 
124     if (entries.isEmpty())
125         return 0;
126 
127     // Check if any of the entries have the same type as the native icon type.
128 
129     // FIXME: This should be way more sophisticated, and handle conversion
130     // of multisize formats for example.
131     for (unsigned i = 0; i < entries.size(); i++) {
132         const IconLinkEntry& entry = entries[i];
133         if (entry.type() == NativeIconType) {
134             RefPtr<IconFetcher> iconFetcher = adoptRef(new IconFetcher(frame, client));
135 
136             iconFetcher->m_entries.append(entry);
137             iconFetcher->loadEntry();
138 
139             return iconFetcher.release();
140         }
141     }
142 
143     return 0;
144 }
145 
IconFetcher(Frame * frame,IconFetcherClient * client)146 IconFetcher::IconFetcher(Frame* frame, IconFetcherClient* client)
147     : m_frame(frame)
148     , m_client(client)
149     , m_currentEntry(0)
150 {
151 }
152 
~IconFetcher()153 IconFetcher::~IconFetcher()
154 {
155     cancel();
156 }
157 
cancel()158 void IconFetcher::cancel()
159 {
160     if (m_handle)
161         m_handle->cancel();
162 }
163 
createIcon()164 PassRefPtr<SharedBuffer> IconFetcher::createIcon()
165 {
166     ASSERT(!m_entries.isEmpty());
167 
168     // For now, just return the data of the first entry.
169     return m_entries.first().buffer();
170 }
171 
loadEntry()172 void IconFetcher::loadEntry()
173 {
174     ASSERT(m_currentEntry < m_entries.size());
175     ASSERT(!m_handle);
176 
177     m_handle = ResourceHandle::create(m_entries[m_currentEntry].url(), this, m_frame, false, false);
178 }
179 
loadFailed()180 void IconFetcher::loadFailed()
181 {
182     m_handle = 0;
183 
184     m_client->finishedFetchingIcon(0);
185 }
186 
didReceiveResponse(ResourceHandle * handle,const ResourceResponse & response)187 void IconFetcher::didReceiveResponse(ResourceHandle* handle, const ResourceResponse& response)
188 {
189     ASSERT_UNUSED(handle, m_handle == handle);
190 
191     int statusCode = response.httpStatusCode() / 100;
192     if (statusCode == 4 || statusCode == 5) {
193         loadFailed();
194         return;
195     }
196 }
197 
didReceiveData(ResourceHandle * handle,const char * data,int length,int)198 void IconFetcher::didReceiveData(ResourceHandle* handle, const char* data, int length, int)
199 {
200     ASSERT_UNUSED(handle, m_handle == handle);
201 
202     m_entries[m_currentEntry].buffer()->append(data, length);
203 }
204 
didFinishLoading(ResourceHandle * handle)205 void IconFetcher::didFinishLoading(ResourceHandle* handle)
206 {
207     ASSERT_UNUSED(handle, m_handle == handle);
208 
209     if (m_currentEntry == m_entries.size() - 1) {
210         // We finished loading, create the icon
211         RefPtr<SharedBuffer> iconData = createIcon();
212 
213         m_client->finishedFetchingIcon(iconData.release());
214         return;
215     }
216 
217     // Load the next entry
218     m_currentEntry++;
219 
220     loadEntry();
221 }
222 
didFail(ResourceHandle * handle,const ResourceError &)223 void IconFetcher::didFail(ResourceHandle* handle, const ResourceError&)
224 {
225     ASSERT_UNUSED(handle, m_handle == handle);
226 
227     loadFailed();
228 }
229 
230 } // namespace WebCore
231