1/*
2 * Copyright (C) 2011 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. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "WebIconDatabase.h"
28
29#include "DataReference.h"
30#include "Logging.h"
31#include "WebContext.h"
32#include "WebIconDatabaseProxyMessages.h"
33#include <WebCore/FileSystem.h>
34#include <WebCore/IconDatabase.h>
35#include <WebCore/IconDatabaseBase.h>
36#include <wtf/text/WTFString.h>
37
38using namespace WebCore;
39
40namespace WebKit {
41
42PassRefPtr<WebIconDatabase> WebIconDatabase::create(WebContext* context)
43{
44    return adoptRef(new WebIconDatabase(context));
45}
46
47WebIconDatabase::~WebIconDatabase()
48{
49}
50
51WebIconDatabase::WebIconDatabase(WebContext* context)
52    : m_webContext(context)
53    , m_urlImportCompleted(false)
54    , m_databaseCleanupDisabled(false)
55{
56}
57
58void WebIconDatabase::invalidate()
59{
60}
61
62void WebIconDatabase::setDatabasePath(const String& path)
63{
64    if (m_iconDatabaseImpl && m_iconDatabaseImpl->isOpen()) {
65        LOG_ERROR("Icon database already has a path and is already open. We don't currently support changing its path and reopening.");
66        return;
67    }
68
69    m_iconDatabaseImpl =  IconDatabase::create();
70    m_iconDatabaseImpl->setClient(this);
71    IconDatabase::delayDatabaseCleanup();
72    m_databaseCleanupDisabled = true;
73    m_iconDatabaseImpl->setEnabled(true);
74    if (!m_iconDatabaseImpl->open(directoryName(path), pathGetFileName(path))) {
75        LOG_ERROR("Unable to open WebKit2 icon database on disk");
76        m_iconDatabaseImpl.clear();
77        setGlobalIconDatabase(0);
78        IconDatabase::allowDatabaseCleanup();
79        m_databaseCleanupDisabled = false;
80    }
81    setGlobalIconDatabase(m_iconDatabaseImpl.get());
82}
83
84void WebIconDatabase::enableDatabaseCleanup()
85{
86    if (!m_iconDatabaseImpl) {
87        LOG_ERROR("Cannot enabled Icon Database cleanup - it hasn't been opened yet.");
88        return;
89    }
90
91    if (!m_databaseCleanupDisabled) {
92        LOG_ERROR("Attempt to enable database cleanup, but it's already enabled.");
93        ASSERT_NOT_REACHED();
94        return;
95    }
96
97    IconDatabase::allowDatabaseCleanup();
98    m_databaseCleanupDisabled = false;
99}
100
101void WebIconDatabase::retainIconForPageURL(const String& pageURL)
102{
103    if (m_iconDatabaseImpl)
104        m_iconDatabaseImpl->retainIconForPageURL(pageURL);
105}
106
107void WebIconDatabase::releaseIconForPageURL(const String& pageURL)
108{
109    if (m_iconDatabaseImpl)
110        m_iconDatabaseImpl->releaseIconForPageURL(pageURL);
111}
112
113void WebIconDatabase::setIconURLForPageURL(const String& iconURL, const String& pageURL)
114{
115    LOG(IconDatabase, "WK2 UIProcess setting icon URL %s for page URL %s", iconURL.ascii().data(), pageURL.ascii().data());
116    if (m_iconDatabaseImpl)
117        m_iconDatabaseImpl->setIconURLForPageURL(iconURL, pageURL);
118}
119
120void WebIconDatabase::setIconDataForIconURL(const CoreIPC::DataReference& iconData, const String& iconURL)
121{
122    LOG(IconDatabase, "WK2 UIProcess setting icon data (%i bytes) for page URL %s", (int)iconData.size(), iconURL.ascii().data());
123    if (!m_iconDatabaseImpl)
124        return;
125
126    RefPtr<SharedBuffer> buffer = SharedBuffer::create(iconData.data(), iconData.size());
127    m_iconDatabaseImpl->setIconDataForIconURL(buffer.release(), iconURL);
128}
129
130void WebIconDatabase::synchronousIconDataForPageURL(const String&, CoreIPC::DataReference& iconData)
131{
132    iconData = CoreIPC::DataReference();
133}
134
135void WebIconDatabase::synchronousIconURLForPageURL(const String&, String& iconURL)
136{
137    iconURL = String();
138}
139
140void WebIconDatabase::synchronousIconDataKnownForIconURL(const String&, bool& iconDataKnown) const
141{
142    iconDataKnown = false;
143}
144
145void WebIconDatabase::synchronousLoadDecisionForIconURL(const String&, int& loadDecision) const
146{
147    loadDecision = static_cast<int>(IconLoadNo);
148}
149
150void WebIconDatabase::getLoadDecisionForIconURL(const String& iconURL, uint64_t callbackID)
151{
152    LOG(IconDatabase, "WK2 UIProcess getting load decision for icon URL %s with callback ID %lli", iconURL.ascii().data(), static_cast<long long>(callbackID));
153
154    if (!m_webContext)
155        return;
156
157    if (!m_iconDatabaseImpl || !m_iconDatabaseImpl->isOpen() || iconURL.isEmpty()) {
158        // FIXME (Multi-WebProcess): We need to know which connection to send this message to.
159        m_webContext->sendToAllProcesses(Messages::WebIconDatabaseProxy::ReceivedIconLoadDecision(static_cast<int>(IconLoadNo), callbackID));
160        return;
161    }
162
163    // If the decision hasn't been read from disk yet, set this url and callback ID aside to be notifed later
164    IconLoadDecision decision = m_iconDatabaseImpl->synchronousLoadDecisionForIconURL(iconURL, 0);
165    if (decision == IconLoadUnknown) {
166        // We should never get an unknown load decision after the URL import has completed.
167        ASSERT(!m_urlImportCompleted);
168
169        m_pendingLoadDecisionURLMap.set(callbackID, iconURL);
170        return;
171    }
172
173    // FIXME (Multi-WebProcess): We need to know which connection to send this message to.
174    m_webContext->sendToAllProcesses(Messages::WebIconDatabaseProxy::ReceivedIconLoadDecision((int)decision, callbackID));
175}
176
177Image* WebIconDatabase::imageForPageURL(const String& pageURL)
178{
179    if (!m_webContext || !m_iconDatabaseImpl || !m_iconDatabaseImpl->isOpen() || pageURL.isEmpty())
180        return 0;
181
182    // The WebCore IconDatabase ignores the passed in size parameter.
183    // If that changes we'll need to rethink how this API is exposed.
184    return m_iconDatabaseImpl->synchronousIconForPageURL(pageURL, WebCore::IntSize(32, 32));
185}
186
187void WebIconDatabase::removeAllIcons()
188{
189    m_iconDatabaseImpl->removeAllIcons();
190}
191
192void WebIconDatabase::checkIntegrityBeforeOpening()
193{
194    IconDatabase::checkIntegrityBeforeOpening();
195}
196
197void WebIconDatabase::close()
198{
199    m_iconDatabaseImpl->close();
200}
201
202void WebIconDatabase::initializeIconDatabaseClient(const WKIconDatabaseClient* client)
203{
204    m_iconDatabaseClient.initialize(client);
205}
206
207// WebCore::IconDatabaseClient
208bool WebIconDatabase::performImport()
209{
210    // WebKit2 icon database doesn't currently support importing any old icon database formats.
211    return true;
212}
213
214void WebIconDatabase::didImportIconURLForPageURL(const String& pageURL)
215{
216    didChangeIconForPageURL(pageURL);
217}
218
219void WebIconDatabase::didImportIconDataForPageURL(const String& pageURL)
220{
221    didChangeIconForPageURL(pageURL);
222}
223
224void WebIconDatabase::didChangeIconForPageURL(const String& pageURL)
225{
226    m_iconDatabaseClient.didChangeIconForPageURL(this, WebURL::create(pageURL).get());
227}
228
229void WebIconDatabase::didRemoveAllIcons()
230{
231    m_iconDatabaseClient.didRemoveAllIcons(this);
232}
233
234void WebIconDatabase::didFinishURLImport()
235{
236    if (!m_webContext)
237        return;
238
239    ASSERT(!m_urlImportCompleted);
240
241    LOG(IconDatabase, "WK2 UIProcess URL import complete, notifying all %i pending page URL load decisions", m_pendingLoadDecisionURLMap.size());
242
243    HashMap<uint64_t, String>::iterator i = m_pendingLoadDecisionURLMap.begin();
244    HashMap<uint64_t, String>::iterator end = m_pendingLoadDecisionURLMap.end();
245
246    for (; i != end; ++i) {
247        LOG(IconDatabase, "WK2 UIProcess performing delayed callback on callback ID %i for page url %s", (int)i->first, i->second.ascii().data());
248        IconLoadDecision decision = m_iconDatabaseImpl->synchronousLoadDecisionForIconURL(i->second, 0);
249
250        // Decisions should never be unknown after the inital import is complete
251        ASSERT(decision != IconLoadUnknown);
252
253        // FIXME (Multi-WebProcess): We need to know which connection to send this message to.
254        m_webContext->sendToAllProcesses(Messages::WebIconDatabaseProxy::ReceivedIconLoadDecision(static_cast<int>(decision), i->first));
255    }
256
257    m_pendingLoadDecisionURLMap.clear();
258
259    m_urlImportCompleted = true;
260}
261
262void WebIconDatabase::didReceiveMessage(CoreIPC::Connection* connection, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* decoder)
263{
264    didReceiveWebIconDatabaseMessage(connection, messageID, decoder);
265}
266
267CoreIPC::SyncReplyMode WebIconDatabase::didReceiveSyncMessage(CoreIPC::Connection* connection, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* decoder, CoreIPC::ArgumentEncoder* reply)
268{
269    return didReceiveSyncWebIconDatabaseMessage(connection, messageID, decoder, reply);
270}
271
272} // namespace WebKit
273