diff options
Diffstat (limited to 'WebCore/loader/icon/IconFetcher.cpp')
-rw-r--r-- | WebCore/loader/icon/IconFetcher.cpp | 236 |
1 files changed, 236 insertions, 0 deletions
diff --git a/WebCore/loader/icon/IconFetcher.cpp b/WebCore/loader/icon/IconFetcher.cpp new file mode 100644 index 0000000..efa7e14 --- /dev/null +++ b/WebCore/loader/icon/IconFetcher.cpp @@ -0,0 +1,236 @@ +/* + * 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 "Document.h" +#include "Frame.h" +#include "HTMLHeadElement.h" +#include "HTMLLinkElement.h" +#include "HTMLNames.h" +#include "MIMETypeRegistry.h" +#include "ResourceHandle.h" +#include "ResourceRequest.h" +#include "SharedBuffer.h" +#include <wtf/PassRefPtr.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<SharedBuffer> 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<IconLinkEntry>& 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> IconFetcher::create(Frame* frame, IconFetcherClient* client) +{ + Document* document = frame->document(); + if (!document) + return 0; + + HTMLHeadElement* head = document->head(); + if (!head) + return 0; + + Vector<IconLinkEntry> entries; + + for (Node* n = head; n; n = n->traverseNextNode()) { + if (!n->hasTagName(linkTag)) + continue; + + HTMLLinkElement* link = static_cast<HTMLLinkElement*>(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> 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<SharedBuffer> 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(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 lengthReceived) +{ + ASSERT(m_handle == handle); + + m_entries[m_currentEntry].buffer()->append(data, length); +} + +void IconFetcher::didFinishLoading(ResourceHandle* handle) +{ + ASSERT(m_handle == handle); + + if (m_currentEntry == m_entries.size() - 1) { + // We finished loading, create the icon + RefPtr<SharedBuffer> iconData = createIcon(); + + m_client->finishedFetchingIcon(iconData.release()); + return; + } + + // Load the next entry + m_currentEntry++; + + loadEntry(); +} + +void IconFetcher::didFail(ResourceHandle* handle, const ResourceError&) +{ + ASSERT(m_handle == handle); + + loadFailed(); +} + + +} // namespace WebCore |