blob: 56f5da1a2013a09a69a5fbea24fe4a6bbbb0a004 [file] [log] [blame]
/*
* Copyright (C) 2011 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. AND ITS CONTRIBUTORS ``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 ITS 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 "WebIconDatabase.h"
#include "Logging.h"
#include "WebIconDatabaseMessages.h"
#include "WebIconDatabaseProxyMessages.h"
#include "WebProcessPool.h"
#include <WebCore/FileSystem.h>
#include <WebCore/IconDatabase.h>
#include <WebCore/Image.h>
#include <WebCore/SharedBuffer.h>
using namespace WebCore;
namespace WebKit {
PassRefPtr<WebIconDatabase> WebIconDatabase::create(WebProcessPool* processPool)
{
return adoptRef(new WebIconDatabase(*processPool));
}
WebIconDatabase::~WebIconDatabase()
{
}
WebIconDatabase::WebIconDatabase(WebProcessPool& processPool)
: m_processPool(&processPool)
, m_urlImportCompleted(false)
, m_databaseCleanupDisabled(false)
, m_shouldDerefWhenAppropriate(false)
{
m_processPool->addMessageReceiver(Messages::WebIconDatabase::messageReceiverName(), *this);
}
void WebIconDatabase::invalidate()
{
setGlobalIconDatabase(nullptr);
}
void WebIconDatabase::setDatabasePath(const String& path)
{
if (isOpen()) {
LOG_ERROR("Icon database already has a path and is already open. We don't currently support changing its path and reopening.");
return;
}
m_iconDatabaseImpl = std::make_unique<IconDatabase>();
m_iconDatabaseImpl->setClient(this);
IconDatabase::delayDatabaseCleanup();
m_databaseCleanupDisabled = true;
m_iconDatabaseImpl->setEnabled(true);
// FIXME: WebIconDatabases are per-ProcessPool but ProcessPools's don't have their own notion of the current private browsing setting.
// As we clean up private browsing throughout the stack we need to clean it up here.
m_iconDatabaseImpl->setPrivateBrowsingEnabled(WebPreferences::anyPagesAreUsingPrivateBrowsing());
if (!m_iconDatabaseImpl->open(directoryName(path), pathGetFileName(path))) {
LOG_ERROR("Unable to open WebKit2 icon database on disk");
m_iconDatabaseImpl = nullptr;
setGlobalIconDatabase(nullptr);
IconDatabase::allowDatabaseCleanup();
m_databaseCleanupDisabled = false;
}
setGlobalIconDatabase(m_iconDatabaseImpl.get());
}
void WebIconDatabase::enableDatabaseCleanup()
{
if (!m_iconDatabaseImpl) {
LOG_ERROR("Cannot enabled Icon Database cleanup - it hasn't been opened yet.");
return;
}
if (!m_databaseCleanupDisabled) {
LOG_ERROR("Attempt to enable database cleanup, but it's already enabled.");
ASSERT_NOT_REACHED();
return;
}
IconDatabase::allowDatabaseCleanup();
m_databaseCleanupDisabled = false;
}
void WebIconDatabase::retainIconForPageURL(const String& pageURL)
{
if (m_iconDatabaseImpl)
m_iconDatabaseImpl->retainIconForPageURL(pageURL);
}
void WebIconDatabase::releaseIconForPageURL(const String& pageURL)
{
if (m_iconDatabaseImpl)
m_iconDatabaseImpl->releaseIconForPageURL(pageURL);
}
void WebIconDatabase::setIconURLForPageURL(const String& iconURL, const String& pageURL)
{
LOG(IconDatabase, "WK2 UIProcess setting icon URL %s for page URL %s", iconURL.ascii().data(), pageURL.ascii().data());
if (m_iconDatabaseImpl)
m_iconDatabaseImpl->setIconURLForPageURL(iconURL, pageURL);
}
void WebIconDatabase::setIconDataForIconURL(const IPC::DataReference& iconData, const String& iconURL)
{
LOG(IconDatabase, "WK2 UIProcess setting icon data (%i bytes) for page URL %s", (int)iconData.size(), iconURL.ascii().data());
if (!m_iconDatabaseImpl)
return;
m_iconDatabaseImpl->setIconDataForIconURL(SharedBuffer::create(iconData.data(), iconData.size()), iconURL);
}
void WebIconDatabase::synchronousIconDataForPageURL(const String&, IPC::DataReference& iconData)
{
iconData = IPC::DataReference();
}
void WebIconDatabase::synchronousIconURLForPageURL(const String& pageURL, String& iconURL)
{
if (!m_iconDatabaseImpl) {
iconURL = String();
return;
}
iconURL = m_iconDatabaseImpl->synchronousIconURLForPageURL(pageURL);
}
void WebIconDatabase::synchronousIconDataKnownForIconURL(const String&, bool& iconDataKnown) const
{
iconDataKnown = false;
}
void WebIconDatabase::synchronousLoadDecisionForIconURL(const String&, int& loadDecision) const
{
loadDecision = static_cast<int>(IconLoadNo);
}
void WebIconDatabase::getLoadDecisionForIconURL(const String& iconURL, uint64_t callbackID)
{
LOG(IconDatabase, "WK2 UIProcess getting load decision for icon URL %s with callback ID %lli", iconURL.ascii().data(), static_cast<long long>(callbackID));
if (!m_processPool)
return;
if (!m_iconDatabaseImpl || !m_iconDatabaseImpl->isOpen() || iconURL.isEmpty()) {
// FIXME (Multi-WebProcess): <rdar://problem/12240223> We need to know which connection to send this message to.
m_processPool->sendToAllProcesses(Messages::WebIconDatabaseProxy::ReceivedIconLoadDecision(static_cast<int>(IconLoadNo), callbackID));
return;
}
// If the decision hasn't been read from disk yet, set this url and callback ID aside to be notifed later
IconLoadDecision decision = m_iconDatabaseImpl->synchronousLoadDecisionForIconURL(iconURL, 0);
if (decision == IconLoadUnknown) {
// We should never get an unknown load decision after the URL import has completed.
ASSERT(!m_urlImportCompleted);
m_pendingLoadDecisionURLMap.set(callbackID, iconURL);
return;
}
// FIXME (Multi-WebProcess): <rdar://problem/12240223> We need to know which connection to send this message to.
m_processPool->sendToAllProcesses(Messages::WebIconDatabaseProxy::ReceivedIconLoadDecision((int)decision, callbackID));
}
void WebIconDatabase::didReceiveIconForPageURL(const String& pageURL)
{
notifyIconDataReadyForPageURL(pageURL);
}
Image* WebIconDatabase::imageForPageURL(const String& pageURL, const IntSize& iconSize)
{
if (!m_processPool || !m_iconDatabaseImpl || !m_iconDatabaseImpl->isOpen() || pageURL.isEmpty())
return nullptr;
// The WebCore IconDatabase ignores the passed in size parameter.
// If that changes we'll need to rethink how this API is exposed.
return m_iconDatabaseImpl->synchronousIconForPageURL(pageURL, iconSize);
}
NativeImagePtr WebIconDatabase::nativeImageForPageURL(const String& pageURL, const IntSize& iconSize)
{
if (!m_processPool || !m_iconDatabaseImpl || !m_iconDatabaseImpl->isOpen() || pageURL.isEmpty())
return nullptr;
return m_iconDatabaseImpl->synchronousNativeIconForPageURL(pageURL, iconSize);
}
bool WebIconDatabase::isOpen()
{
return m_iconDatabaseImpl && m_iconDatabaseImpl->isOpen();
}
bool WebIconDatabase::isUrlImportCompleted()
{
return m_urlImportCompleted;
}
void WebIconDatabase::removeAllIcons()
{
m_iconDatabaseImpl->removeAllIcons();
}
void WebIconDatabase::checkIntegrityBeforeOpening()
{
IconDatabase::checkIntegrityBeforeOpening();
}
void WebIconDatabase::close()
{
if (m_iconDatabaseImpl)
m_iconDatabaseImpl->close();
}
void WebIconDatabase::initializeIconDatabaseClient(const WKIconDatabaseClientBase* client)
{
m_iconDatabaseClient.initialize(client);
}
// WebCore::IconDatabaseClient
void WebIconDatabase::didImportIconURLForPageURL(const String& pageURL)
{
didChangeIconForPageURL(pageURL);
}
void WebIconDatabase::didImportIconDataForPageURL(const String& pageURL)
{
notifyIconDataReadyForPageURL(pageURL);
}
void WebIconDatabase::didChangeIconForPageURL(const String& pageURL)
{
m_iconDatabaseClient.didChangeIconForPageURL(this, API::URL::create(pageURL).ptr());
}
void WebIconDatabase::didRemoveAllIcons()
{
m_iconDatabaseClient.didRemoveAllIcons(this);
}
void WebIconDatabase::didFinishURLImport()
{
if (!m_processPool)
return;
ASSERT(!m_urlImportCompleted);
LOG(IconDatabase, "WK2 UIProcess URL import complete, notifying all %i pending page URL load decisions", m_pendingLoadDecisionURLMap.size());
for (auto& slot : m_pendingLoadDecisionURLMap) {
LOG(IconDatabase, "WK2 UIProcess performing delayed callback on callback ID %i for page url %s", (int)slot.key, slot.value.ascii().data());
IconLoadDecision decision = m_iconDatabaseImpl->synchronousLoadDecisionForIconURL(slot.value, nullptr);
// Decisions should never be unknown after the inital import is complete.
ASSERT(decision != IconLoadUnknown);
// FIXME (Multi-WebProcess): <rdar://problem/12240223> We need to know which connection to send this message to.
m_processPool->sendToAllProcesses(Messages::WebIconDatabaseProxy::ReceivedIconLoadDecision(static_cast<int>(decision), slot.key));
}
m_pendingLoadDecisionURLMap.clear();
m_urlImportCompleted = true;
}
void WebIconDatabase::didClose()
{
if (!m_shouldDerefWhenAppropriate)
return;
deref();
}
void WebIconDatabase::derefWhenAppropriate()
{
if (m_iconDatabaseImpl && m_iconDatabaseImpl->isOpen()) {
m_shouldDerefWhenAppropriate = true;
return;
}
deref();
}
void WebIconDatabase::notifyIconDataReadyForPageURL(const String& pageURL)
{
m_iconDatabaseClient.iconDataReadyForPageURL(this, API::URL::create(pageURL).ptr());
didChangeIconForPageURL(pageURL);
}
void WebIconDatabase::setPrivateBrowsingEnabled(bool privateBrowsingEnabled)
{
if (m_iconDatabaseImpl)
m_iconDatabaseImpl->setPrivateBrowsingEnabled(privateBrowsingEnabled);
}
PassRefPtr<API::Data> WebIconDatabase::iconDataForPageURL(const String& pageURL)
{
auto* image = imageForPageURL(pageURL);
if (!image)
return nullptr;
SharedBuffer* sharedBuffer = image->data();
if (!sharedBuffer)
return nullptr;
// Balanced by deref() below.
sharedBuffer->ref();
return API::Data::createWithoutCopying(reinterpret_cast<const unsigned char*>(sharedBuffer->data()), sharedBuffer->size(),
[](unsigned char*, const void* untypedSharedBuffer) {
// Balanced by ref() above.
static_cast<SharedBuffer*>(const_cast<void*>(untypedSharedBuffer))->deref();
}, sharedBuffer);
}
} // namespace WebKit