diff -r 000000000000 -r 4f2f89ce4247 WebCore/loader/icon/IconFetcher.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebCore/loader/icon/IconFetcher.cpp Fri Sep 17 09:02:29 2010 +0300 @@ -0,0 +1,229 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "IconFetcher.h" + +#include "Frame.h" +#include "HTMLHeadElement.h" +#include "HTMLLinkElement.h" +#include "HTMLNames.h" +#include "ResourceHandle.h" +#include "ResourceRequest.h" +#include "SharedBuffer.h" + +namespace WebCore { + +using namespace HTMLNames; + +struct IconLinkEntry { +public: + enum IconType { + Unknown, + ICNS, + ICO, + }; + + IconLinkEntry(IconType type, const KURL& url) + : m_type(type) + , m_url(url) + { + } + + IconType type() const { return m_type; } + const KURL& url() const { return m_url; } + + SharedBuffer* buffer() + { + if (!m_buffer) + m_buffer = SharedBuffer::create(); + + return m_buffer.get(); + } + +private: + RefPtr m_buffer; + IconType m_type; + KURL m_url; +}; + +#if PLATFORM(MAC) +static const IconLinkEntry::IconType NativeIconType = IconLinkEntry::ICNS; +#elif PLATFORM(WIN) +static const IconLinkEntry::IconType NativeIconType = IconLinkEntry::ICO; +#else +static const IconLinkEntry::IconType NativeIconType = IconLinkEntry::Unknown; +#endif + +static void parseIconLink(HTMLLinkElement* link, Vector& entries) +{ + // FIXME: Parse the size attribute too. + + IconLinkEntry::IconType type = IconLinkEntry::Unknown; + const KURL& url = link->href(); + + // Try to determine the file type. + String path = url.path(); + + int pos = path.reverseFind('.'); + if (pos >= 0) { + String extension = path.substring(pos + 1); + if (equalIgnoringCase(extension, "icns")) + type = IconLinkEntry::ICNS; + else if (equalIgnoringCase(extension, "ico")) + type = IconLinkEntry::ICO; + } + + entries.append(IconLinkEntry(type, url)); +} + +PassRefPtr IconFetcher::create(Frame* frame, IconFetcherClient* client) +{ + Document* document = frame->document(); + + HTMLHeadElement* head = document->head(); + if (!head) + return 0; + + Vector entries; + + for (Node* n = head; n; n = n->traverseNextNode()) { + if (!n->hasTagName(linkTag)) + continue; + + HTMLLinkElement* link = static_cast(n); + if (!link->isIcon()) + continue; + + parseIconLink(link, entries); + } + + if (entries.isEmpty()) + return 0; + + // Check if any of the entries have the same type as the native icon type. + + // FIXME: This should be way more sophisticated, and handle conversion + // of multisize formats for example. + for (unsigned i = 0; i < entries.size(); i++) { + const IconLinkEntry& entry = entries[i]; + if (entry.type() == NativeIconType) { + RefPtr iconFetcher = adoptRef(new IconFetcher(frame, client)); + + iconFetcher->m_entries.append(entry); + iconFetcher->loadEntry(); + + return iconFetcher.release(); + } + } + + return 0; +} + +IconFetcher::IconFetcher(Frame* frame, IconFetcherClient* client) + : m_frame(frame) + , m_client(client) + , m_currentEntry(0) +{ +} + +IconFetcher::~IconFetcher() +{ + cancel(); +} + +void IconFetcher::cancel() +{ + if (m_handle) + m_handle->cancel(); +} + +PassRefPtr IconFetcher::createIcon() +{ + ASSERT(!m_entries.isEmpty()); + + // For now, just return the data of the first entry. + return m_entries.first().buffer(); +} + +void IconFetcher::loadEntry() +{ + ASSERT(m_currentEntry < m_entries.size()); + ASSERT(!m_handle); + + m_handle = ResourceHandle::create(m_entries[m_currentEntry].url(), this, m_frame, false, false); +} + +void IconFetcher::loadFailed() +{ + m_handle = 0; + + m_client->finishedFetchingIcon(0); +} + +void IconFetcher::didReceiveResponse(ResourceHandle* handle, const ResourceResponse& response) +{ + ASSERT_UNUSED(handle, m_handle == handle); + + int statusCode = response.httpStatusCode() / 100; + if (statusCode == 4 || statusCode == 5) { + loadFailed(); + return; + } +} + +void IconFetcher::didReceiveData(ResourceHandle* handle, const char* data, int length, int) +{ + ASSERT_UNUSED(handle, m_handle == handle); + + m_entries[m_currentEntry].buffer()->append(data, length); +} + +void IconFetcher::didFinishLoading(ResourceHandle* handle) +{ + ASSERT_UNUSED(handle, m_handle == handle); + + if (m_currentEntry == m_entries.size() - 1) { + // We finished loading, create the icon + RefPtr iconData = createIcon(); + + m_client->finishedFetchingIcon(iconData.release()); + return; + } + + // Load the next entry + m_currentEntry++; + + loadEntry(); +} + +void IconFetcher::didFail(ResourceHandle* handle, const ResourceError&) +{ + ASSERT_UNUSED(handle, m_handle == handle); + + loadFailed(); +} + +} // namespace WebCore