/* * 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 #include #include #include using namespace WebCore; namespace WebKit { PassRefPtr 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(); 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(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(callbackID)); if (!m_processPool) return; if (!m_iconDatabaseImpl || !m_iconDatabaseImpl->isOpen() || iconURL.isEmpty()) { // FIXME (Multi-WebProcess): We need to know which connection to send this message to. m_processPool->sendToAllProcesses(Messages::WebIconDatabaseProxy::ReceivedIconLoadDecision(static_cast(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): 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): We need to know which connection to send this message to. m_processPool->sendToAllProcesses(Messages::WebIconDatabaseProxy::ReceivedIconLoadDecision(static_cast(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 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(sharedBuffer->data()), sharedBuffer->size(), [](unsigned char*, const void* untypedSharedBuffer) { // Balanced by ref() above. static_cast(const_cast(untypedSharedBuffer))->deref(); }, sharedBuffer); } } // namespace WebKit