diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/loader/icon | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/WebCore/loader/icon')
-rw-r--r-- | Source/WebCore/loader/icon/IconController.cpp | 170 | ||||
-rw-r--r-- | Source/WebCore/loader/icon/IconController.h | 21 | ||||
-rw-r--r-- | Source/WebCore/loader/icon/IconDatabase.cpp | 559 | ||||
-rw-r--r-- | Source/WebCore/loader/icon/IconDatabase.h | 187 | ||||
-rw-r--r-- | Source/WebCore/loader/icon/IconDatabaseBase.cpp | 8 | ||||
-rw-r--r-- | Source/WebCore/loader/icon/IconDatabaseBase.h | 76 | ||||
-rw-r--r-- | Source/WebCore/loader/icon/IconDatabaseClient.h | 8 | ||||
-rw-r--r-- | Source/WebCore/loader/icon/IconLoader.cpp | 84 | ||||
-rw-r--r-- | Source/WebCore/loader/icon/IconLoader.h | 21 | ||||
-rw-r--r-- | Source/WebCore/loader/icon/IconRecord.cpp | 8 | ||||
-rw-r--r-- | Source/WebCore/loader/icon/IconRecord.h | 15 | ||||
-rw-r--r-- | Source/WebCore/loader/icon/PageURLRecord.cpp | 16 | ||||
-rw-r--r-- | Source/WebCore/loader/icon/PageURLRecord.h | 16 |
13 files changed, 530 insertions, 659 deletions
diff --git a/Source/WebCore/loader/icon/IconController.cpp b/Source/WebCore/loader/icon/IconController.cpp index 06c7a5e45..9a1a93148 100644 --- a/Source/WebCore/loader/icon/IconController.cpp +++ b/Source/WebCore/loader/icon/IconController.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved. + * Copyright (C) 2006-2011, 2015 Apple Inc. All rights reserved. * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) * Copyright (C) 2008 Alp Toker <alp@atoker.com> @@ -16,7 +16,7 @@ * 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. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * 3. Neither the name of Apple Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * @@ -37,12 +37,14 @@ #include "Document.h" #include "DocumentLoader.h" +#include "ElementChildIterator.h" #include "FrameLoader.h" #include "FrameLoaderClient.h" +#include "HTMLHeadElement.h" +#include "HTMLLinkElement.h" #include "IconDatabase.h" -#include "IconDatabaseBase.h" #include "IconLoader.h" -#include "IconURL.h" +#include "LinkIconType.h" #include "Logging.h" #include "MainFrame.h" #include "Page.h" @@ -53,7 +55,6 @@ namespace WebCore { IconController::IconController(Frame& frame) : m_frame(frame) - , m_waitingForLoadDecision(false) { } @@ -61,63 +62,57 @@ IconController::~IconController() { } -URL IconController::url() +static URL iconFromLinkElements(Frame& frame) { - IconURLs iconURLs = urlsForTypes(Favicon); - return iconURLs.isEmpty() ? URL() : iconURLs[0].m_iconURL; -} - -IconURL IconController::iconURL(IconType iconType) const -{ - IconURL result; - const Vector<IconURL>& iconURLs = m_frame.document()->iconURLs(iconType); - Vector<IconURL>::const_iterator iter(iconURLs.begin()); - for (; iter != iconURLs.end(); ++iter) { - if (result.m_iconURL.isEmpty() || !iter->m_mimeType.isEmpty()) - result = *iter; + // This function returns the first icon with a mime type. + // If no icon with mime type exists, the last icon is returned. + // It may make more sense to always return the last icon, + // but this implementation is consistent with previous behavior. + + URL result; + + auto* document = frame.document(); + if (!document) + return result; + + auto* head = document->head(); + if (!head) + return result; + + for (auto& linkElement : childrenOfType<HTMLLinkElement>(*head)) { + if (!linkElement.iconType()) + continue; + if (*linkElement.iconType() != LinkIconType::Favicon) + continue; + if (linkElement.href().isEmpty()) + continue; + result = linkElement.href(); + if (!linkElement.type().isEmpty()) + break; } return result; } -IconURLs IconController::urlsForTypes(int iconTypesMask) +URL IconController::url() { - IconURLs iconURLs; - if (m_frame.tree().parent()) - return iconURLs; - - if (iconTypesMask & Favicon && !appendToIconURLs(Favicon, &iconURLs)) - iconURLs.append(defaultURL(Favicon)); - -#if ENABLE(TOUCH_ICON_LOADING) - int missedIcons = 0; - if (iconTypesMask & TouchPrecomposedIcon) - missedIcons += appendToIconURLs(TouchPrecomposedIcon, &iconURLs) ? 0:1; - - if (iconTypesMask & TouchIcon) - missedIcons += appendToIconURLs(TouchIcon, &iconURLs) ? 0:1; - - // Only return the default touch icons when the both were required and neither was gotten. - if (missedIcons == 2) { - iconURLs.append(defaultURL(TouchPrecomposedIcon)); - iconURLs.append(defaultURL(TouchIcon)); - } -#endif - - // Finally, append all remaining icons of this type. - const Vector<IconURL>& allIconURLs = m_frame.document()->iconURLs(iconTypesMask); - for (Vector<IconURL>::const_iterator iter = allIconURLs.begin(); iter != allIconURLs.end(); ++iter) { - int i; - int iconCount = iconURLs.size(); - for (i = 0; i < iconCount; ++i) { - if (*iter == iconURLs.at(i)) - break; - } - if (i == iconCount) - iconURLs.append(*iter); + if (!m_frame.isMainFrame()) + return URL(); + + auto icon = iconFromLinkElements(m_frame); + if (!icon.isEmpty()) + return icon; + + icon = m_frame.document()->completeURL(ASCIILiteral("/favicon.ico")); + if (icon.protocolIsInHTTPFamily()) { + // FIXME: Not sure we need to remove credentials like this. + // However this preserves behavior this code path has historically had. + icon.setUser(String()); + icon.setPass(String()); + return icon; } - return iconURLs; + return URL(); } void IconController::commitToDatabase(const URL& icon) @@ -142,9 +137,8 @@ void IconController::startLoader() if (!documentCanHaveIcon(m_frame.document()->url())) return; - URL iconURL(url()); - String urlString(iconURL.string()); - if (urlString.isEmpty()) + URL iconURL = url(); + if (iconURL.isEmpty()) return; // People who want to avoid loading images generally want to avoid loading all images, unless an exception has been made for site icons. @@ -154,30 +148,30 @@ void IconController::startLoader() // If we're reloading the page, always start the icon load now. // FIXME: How can this condition ever be true? - if (m_frame.loader().loadType() == FrameLoadTypeReload && m_frame.loader().loadType() == FrameLoadTypeReloadFromOrigin) { + if (m_frame.loader().loadType() == FrameLoadType::Reload && m_frame.loader().loadType() == FrameLoadType::ReloadFromOrigin) { continueLoadWithDecision(IconLoadYes); return; } if (iconDatabase().supportsAsynchronousMode()) { // FIXME (<rdar://problem/9168605>) - We should support in-memory-only private browsing icons in asynchronous icon database mode. - if (m_frame.page() && m_frame.page()->settings().privateBrowsingEnabled()) + if (m_frame.page() && m_frame.page()->usesEphemeralSession()) return; - m_frame.loader().documentLoader()->getIconLoadDecisionForIconURL(urlString); + m_frame.loader().documentLoader()->getIconLoadDecisionForIconURL(iconURL.string()); // Commit the icon url mapping to the database just in case we don't end up loading later. commitToDatabase(iconURL); return; } - IconLoadDecision decision = iconDatabase().synchronousLoadDecisionForIconURL(urlString, m_frame.loader().documentLoader()); + IconLoadDecision decision = iconDatabase().synchronousLoadDecisionForIconURL(iconURL.string(), m_frame.loader().documentLoader()); if (decision == IconLoadUnknown) { // In this case, we may end up loading the icon later, but we still want to commit the icon url mapping to the database // just in case we don't end up loading later - if we commit the mapping a second time after the load, that's no big deal // We also tell the client to register for the notification that the icon is received now so it isn't missed in case the // icon is later read in from disk - LOG(IconDatabase, "IconController %p might load icon %s later", this, urlString.ascii().data()); + LOG(IconDatabase, "IconController %p might load icon %s later", this, iconURL.string().utf8().data()); m_waitingForLoadDecision = true; m_frame.loader().client().registerForIconNotification(); commitToDatabase(iconURL); @@ -208,16 +202,15 @@ void IconController::continueLoadWithDecision(IconLoadDecision iconLoadDecision) ASSERT(iconLoadDecision != IconLoadUnknown); if (iconLoadDecision == IconLoadNo) { - URL iconURL(url()); - String urlString(iconURL.string()); - if (urlString.isEmpty()) + URL iconURL = url(); + if (iconURL.isEmpty()) return; - LOG(IconDatabase, "IconController::startLoader() - Told not to load this icon, committing iconURL %s to database for pageURL mapping", urlString.ascii().data()); + LOG(IconDatabase, "IconController::startLoader() - Told not to load this icon, committing iconURL %s to database for pageURL mapping", iconURL.string().utf8().data()); commitToDatabase(iconURL); if (iconDatabase().supportsAsynchronousMode()) { - m_frame.loader().documentLoader()->getIconDataForIconURL(urlString); + m_frame.loader().documentLoader()->getIconDataForIconURL(iconURL.string()); return; } @@ -225,8 +218,8 @@ void IconController::continueLoadWithDecision(IconLoadDecision iconLoadDecision) // If the icon data hasn't been read in from disk yet, kick off the read of the icon from the database to make sure someone // has done it. This is after registering for the notification so the WebView can call the appropriate delegate method. // Otherwise if the icon data *is* available, notify the delegate - if (!iconDatabase().synchronousIconDataKnownForIconURL(urlString)) { - LOG(IconDatabase, "Told not to load icon %s but icon data is not yet available - registering for notification and requesting load from disk", urlString.ascii().data()); + if (!iconDatabase().synchronousIconDataKnownForIconURL(iconURL.string())) { + LOG(IconDatabase, "Told not to load icon %s but icon data is not yet available - registering for notification and requesting load from disk", iconURL.string().ascii().data()); m_frame.loader().client().registerForIconNotification(); iconDatabase().synchronousIconForPageURL(m_frame.document()->url().string(), IntSize(0, 0)); iconDatabase().synchronousIconForPageURL(m_frame.loader().initialRequest().url().string(), IntSize(0, 0)); @@ -242,45 +235,4 @@ void IconController::continueLoadWithDecision(IconLoadDecision iconLoadDecision) m_iconLoader->startLoading(); } -bool IconController::appendToIconURLs(IconType iconType, IconURLs* iconURLs) -{ - IconURL faviconURL = iconURL(iconType); - if (faviconURL.m_iconURL.isEmpty()) - return false; - - iconURLs->append(faviconURL); - return true; -} - -IconURL IconController::defaultURL(IconType iconType) -{ - // Don't return a favicon iconURL unless we're http or https - URL documentURL = m_frame.document()->url(); - if (!documentURL.protocolIsInHTTPFamily()) - return IconURL(); - - URL url; - bool couldSetProtocol = url.setProtocol(documentURL.protocol()); - ASSERT_UNUSED(couldSetProtocol, couldSetProtocol); - url.setHost(documentURL.host()); - if (documentURL.hasPort()) - url.setPort(documentURL.port()); - - if (iconType == Favicon) { - url.setPath("/favicon.ico"); - return IconURL::defaultIconURL(url, Favicon); - } -#if ENABLE(TOUCH_ICON_LOADING) - if (iconType == TouchPrecomposedIcon) { - url.setPath("/apple-touch-icon-precomposed.png"); - return IconURL::defaultIconURL(url, TouchPrecomposedIcon); - } - if (iconType == TouchIcon) { - url.setPath("/apple-touch-icon.png"); - return IconURL::defaultIconURL(url, TouchIcon); - } -#endif - return IconURL(); -} - } diff --git a/Source/WebCore/loader/icon/IconController.h b/Source/WebCore/loader/icon/IconController.h index 83844b9d4..31b1562a1 100644 --- a/Source/WebCore/loader/icon/IconController.h +++ b/Source/WebCore/loader/icon/IconController.h @@ -12,7 +12,7 @@ * 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. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * 3. Neither the name of Apple Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * @@ -28,28 +28,23 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef IconController_h -#define IconController_h +#pragma once #include "IconDatabaseBase.h" -#include "IconURL.h" -#include "URL.h" namespace WebCore { class Frame; class IconLoader; +class URL; class IconController { - WTF_MAKE_NONCOPYABLE(IconController); WTF_MAKE_FAST_ALLOCATED; public: explicit IconController(Frame&); ~IconController(); - URL url(); - IconURLs urlsForTypes(int iconTypesMask); - IconURL iconURL(IconType) const; + WEBCORE_EXPORT URL url(); void startLoader(); void stopLoader(); @@ -60,15 +55,9 @@ public: void commitToDatabase(const URL& icon); private: - bool appendToIconURLs(IconType, IconURLs*); - IconURL defaultURL(IconType); - Frame& m_frame; - std::unique_ptr<IconLoader> m_iconLoader; - bool m_waitingForLoadDecision; + bool m_waitingForLoadDecision { false }; }; } // namespace WebCore - -#endif diff --git a/Source/WebCore/loader/icon/IconDatabase.cpp b/Source/WebCore/loader/icon/IconDatabase.cpp index 39272e4d6..4cdcfaad6 100644 --- a/Source/WebCore/loader/icon/IconDatabase.cpp +++ b/Source/WebCore/loader/icon/IconDatabase.cpp @@ -11,10 +11,10 @@ * 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 COMPUTER, INC. ``AS IS'' AND ANY + * 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 COMPUTER, INC. OR + * 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 @@ -34,16 +34,14 @@ #include "IconDatabaseClient.h" #include "IconRecord.h" #include "Image.h" -#include "IntSize.h" #include "Logging.h" #include "SQLiteStatement.h" #include "SQLiteTransaction.h" #include "SuddenTermination.h" #include <wtf/AutodrainedPool.h> -#include <wtf/CurrentTime.h> #include <wtf/MainThread.h> +#include <wtf/NeverDestroyed.h> #include <wtf/StdLibExtras.h> -#include <wtf/text/CString.h> // For methods that are meant to support API from the main thread - should not be called internally #define ASSERT_NOT_SYNC_THREAD() ASSERT(!m_syncThreadRunning || !IS_ICON_SYNC_THREAD()) @@ -82,7 +80,7 @@ static const int notUsedIconExpirationTime = 60*60*24*30; #if !LOG_DISABLED || !ERROR_DISABLED static String urlForLogging(const String& url) { - static unsigned urlTruncationLength = 120; + static const unsigned urlTruncationLength = 120; if (url.length() < urlTruncationLength) return url; @@ -90,19 +88,19 @@ static String urlForLogging(const String& url) } #endif -class DefaultIconDatabaseClient : public IconDatabaseClient { +class DefaultIconDatabaseClient final : public IconDatabaseClient { WTF_MAKE_FAST_ALLOCATED; public: - virtual void didImportIconURLForPageURL(const String&) { } - virtual void didImportIconDataForPageURL(const String&) { } - virtual void didChangeIconForPageURL(const String&) { } - virtual void didRemoveAllIcons() { } - virtual void didFinishURLImport() { } + void didImportIconURLForPageURL(const String&) override { } + void didImportIconDataForPageURL(const String&) override { } + void didChangeIconForPageURL(const String&) override { } + void didRemoveAllIcons() override { } + void didFinishURLImport() override { } }; static IconDatabaseClient* defaultClient() { - static IconDatabaseClient* defaultClient = new DefaultIconDatabaseClient(); + static IconDatabaseClient* defaultClient = new DefaultIconDatabaseClient; return defaultClient; } @@ -171,7 +169,11 @@ void IconDatabase::close() m_removeIconsRequested = false; m_syncDB.close(); - ASSERT(!isOpen()); + + // If there are still main thread callbacks in flight then the database might not actually be closed yet. + // But if it is closed, notify the client now. + if (!isOpen() && m_client) + m_client->didClose(); } void IconDatabase::removeAllIcons() @@ -185,28 +187,26 @@ void IconDatabase::removeAllIcons() // Clear the in-memory record of every IconRecord, anything waiting to be read from disk, and anything waiting to be written to disk { - MutexLocker locker(m_urlAndIconLock); + LockHolder locker(m_urlAndIconLock); // Clear the IconRecords for every page URL - RefCounting will cause the IconRecords themselves to be deleted // We don't delete the actual PageRecords because we have the "retain icon for url" count to keep track of - HashMap<String, PageURLRecord*>::iterator iter = m_pageURLToRecordMap.begin(); - HashMap<String, PageURLRecord*>::iterator end = m_pageURLToRecordMap.end(); - for (; iter != end; ++iter) - (*iter).value->setIconRecord(0); - + for (auto& pageURL : m_pageURLToRecordMap.values()) + pageURL->setIconRecord(nullptr); + // Clear the iconURL -> IconRecord map m_iconURLToRecordMap.clear(); // Clear all in-memory records of things that need to be synced out to disk { - MutexLocker locker(m_pendingSyncLock); + LockHolder locker(m_pendingSyncLock); m_pageURLsPendingSync.clear(); m_iconsPendingSync.clear(); } // Clear all in-memory records of things that need to be read in from disk { - MutexLocker locker(m_pendingReadingLock); + LockHolder locker(m_pendingReadingLock); m_pageURLsPendingImport.clear(); m_pageURLsInterestedInIcons.clear(); m_iconsPendingReading.clear(); @@ -226,9 +226,9 @@ Image* IconDatabase::synchronousIconForPageURL(const String& pageURLOriginal, co // We should go our of our way to only copy it if we have to store it if (!isOpen() || !documentCanHaveIcon(pageURLOriginal)) - return 0; + return nullptr; - MutexLocker locker(m_urlAndIconLock); + LockHolder locker(m_urlAndIconLock); performPendingRetainAndReleaseOperations(); @@ -244,14 +244,14 @@ Image* IconDatabase::synchronousIconForPageURL(const String& pageURLOriginal, co // 1 - The initial url import is incomplete and this pageURL was marked to be notified once it is complete if an iconURL exists // 2 - The initial url import IS complete and this pageURL has no icon if (!pageRecord) { - MutexLocker locker(m_pendingReadingLock); + LockHolder locker(m_pendingReadingLock); // Import is ongoing, there might be an icon. In this case, register to be notified when the icon comes in // If we ever reach this condition, we know we've already made the pageURL copy if (!m_iconURLImportComplete) m_pageURLsInterestedInIcons.add(pageURLCopy); - return 0; + return nullptr; } IconRecord* iconRecord = pageRecord->iconRecord(); @@ -260,14 +260,14 @@ Image* IconDatabase::synchronousIconForPageURL(const String& pageURLOriginal, co // In this case, the pageURL is already in the set to alert the client when the iconURL mapping is complete so // we can just bail now if (!m_iconURLImportComplete && !iconRecord) - return 0; + return nullptr; // Assuming we're done initializing and cleanup is allowed, // the only way we should *not* have an icon record is if this pageURL is retained but has no icon yet. ASSERT(iconRecord || databaseCleanupCounter || m_retainedPageURLs.contains(pageURLOriginal)); if (!iconRecord) - return 0; + return nullptr; // If it's a new IconRecord object that doesn't have its imageData set yet, // mark it to be read by the background thread @@ -275,17 +275,17 @@ Image* IconDatabase::synchronousIconForPageURL(const String& pageURLOriginal, co if (pageURLCopy.isNull()) pageURLCopy = pageURLOriginal.isolatedCopy(); - MutexLocker locker(m_pendingReadingLock); + LockHolder locker(m_pendingReadingLock); m_pageURLsInterestedInIcons.add(pageURLCopy); m_iconsPendingReading.add(iconRecord); wakeSyncThread(); - return 0; + return nullptr; } // If the size parameter was (0, 0) that means the caller of this method just wanted the read from disk to be kicked off // and isn't actually interested in the image return value if (size == IntSize(0, 0)) - return 0; + return nullptr; // PARANOID DISCUSSION: This method makes some assumptions. It returns a WebCore::image which the icon database might dispose of at anytime in the future, // and Images aren't ref counted. So there is no way for the client to guarantee continued existence of the image. @@ -300,13 +300,13 @@ Image* IconDatabase::synchronousIconForPageURL(const String& pageURLOriginal, co return iconRecord->image(size); } -PassNativeImagePtr IconDatabase::synchronousNativeIconForPageURL(const String& pageURLOriginal, const IntSize& size) +NativeImagePtr IconDatabase::synchronousNativeIconForPageURL(const String& pageURLOriginal, const IntSize& size) { Image* icon = synchronousIconForPageURL(pageURLOriginal, size); if (!icon) - return 0; + return nullptr; - MutexLocker locker(m_urlAndIconLock); + LockHolder locker(m_urlAndIconLock); return icon->nativeImageForCurrentFrame(); } @@ -328,7 +328,7 @@ String IconDatabase::synchronousIconURLForPageURL(const String& pageURLOriginal) if (!isOpen() || !documentCanHaveIcon(pageURLOriginal)) return String(); - MutexLocker locker(m_urlAndIconLock); + LockHolder locker(m_urlAndIconLock); PageURLRecord* pageRecord = m_pageURLToRecordMap.get(pageURLOriginal); if (!pageRecord) @@ -390,8 +390,8 @@ static inline void loadDefaultIconRecord(IconRecord* defaultIconRecord) 0x00, 0x00, 0x01, 0x52, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x0A, 0xFC, 0x80, 0x00, 0x00, 0x27, 0x10, 0x00, 0x0A, 0xFC, 0x80, 0x00, 0x00, 0x27, 0x10 }; - static SharedBuffer* defaultIconBuffer = SharedBuffer::create(defaultIconData, sizeof(defaultIconData)).leakRef(); - defaultIconRecord->setImageData(defaultIconBuffer); + static auto& defaultIconBuffer = SharedBuffer::create(defaultIconData, sizeof(defaultIconData)).leakRef(); + defaultIconRecord->setImageData(&defaultIconBuffer); } #endif @@ -416,7 +416,7 @@ void IconDatabase::retainIconForPageURL(const String& pageURL) return; { - MutexLocker locker(m_urlsToRetainOrReleaseLock); + LockHolder locker(m_urlsToRetainOrReleaseLock); m_urlsToRetain.add(pageURL.isolatedCopy()); m_retainOrReleaseIconRequested = true; } @@ -449,7 +449,7 @@ void IconDatabase::performRetainIconForPageURL(const String& pageURLOriginal, in if (!m_iconURLImportComplete) return; - MutexLocker locker(m_pendingSyncLock); + LockHolder locker(m_pendingSyncLock); // If this pageURL waiting to be sync'ed, update the sync record // This saves us in the case where a page was ready to be deleted from the database but was just retained - so theres no need to delete it! if (!m_privateBrowsingEnabled && m_pageURLsPendingSync.contains(pageURL)) { @@ -469,7 +469,7 @@ void IconDatabase::releaseIconForPageURL(const String& pageURL) return; { - MutexLocker locker(m_urlsToRetainOrReleaseLock); + LockHolder locker(m_urlsToRetainOrReleaseLock); m_urlsToRelease.add(pageURL.isolatedCopy()); m_retainOrReleaseIconRequested = true; } @@ -505,7 +505,7 @@ void IconDatabase::performReleaseIconForPageURL(const String& pageURLOriginal, i ASSERT(!iconRecord || (iconRecord && m_iconURLToRecordMap.get(iconRecord->iconURL()) == iconRecord)); { - MutexLocker locker(m_pendingReadingLock); + LockHolder locker(m_pendingReadingLock); // Since this pageURL is going away, there's no reason anyone would ever be interested in its read results if (!m_iconURLImportComplete) @@ -521,7 +521,7 @@ void IconDatabase::performReleaseIconForPageURL(const String& pageURLOriginal, i // Mark stuff for deletion from the database only if we're not in private browsing if (!m_privateBrowsingEnabled) { - MutexLocker locker(m_pendingSyncLock); + LockHolder locker(m_pendingSyncLock); m_pageURLsPendingSync.set(pageURLOriginal.isolatedCopy(), pageRecord->snapshot(true)); // If this page is the last page to refer to a particular IconRecord, that IconRecord needs to @@ -533,7 +533,7 @@ void IconDatabase::performReleaseIconForPageURL(const String& pageURLOriginal, i delete pageRecord; } -void IconDatabase::setIconDataForIconURL(PassRefPtr<SharedBuffer> dataOriginal, const String& iconURLOriginal) +void IconDatabase::setIconDataForIconURL(SharedBuffer* dataOriginal, const String& iconURLOriginal) { ASSERT_NOT_SYNC_THREAD(); @@ -542,23 +542,23 @@ void IconDatabase::setIconDataForIconURL(PassRefPtr<SharedBuffer> dataOriginal, if (!isOpen() || iconURLOriginal.isEmpty()) return; - RefPtr<SharedBuffer> data = dataOriginal ? dataOriginal->copy() : PassRefPtr<SharedBuffer>(0); + auto data = dataOriginal ? RefPtr<SharedBuffer> { dataOriginal->copy() } : nullptr; String iconURL = iconURLOriginal.isolatedCopy(); Vector<String> pageURLs; { - MutexLocker locker(m_urlAndIconLock); + LockHolder locker(m_urlAndIconLock); // If this icon was pending a read, remove it from that set because this new data should override what is on disk RefPtr<IconRecord> icon = m_iconURLToRecordMap.get(iconURL); if (icon) { - MutexLocker locker(m_pendingReadingLock); + LockHolder locker(m_pendingReadingLock); m_iconsPendingReading.remove(icon.get()); } else icon = getOrCreateIconRecord(iconURL); // Update the data and set the time stamp - icon->setImageData(data.release()); + icon->setImageData(WTFMove(data)); icon->setTimestamp((int)currentTime()); // Copy the current retaining pageURLs - if any - to notify them of the change @@ -566,7 +566,7 @@ void IconDatabase::setIconDataForIconURL(PassRefPtr<SharedBuffer> dataOriginal, // Mark the IconRecord as requiring an update to the database only if private browsing is disabled if (!m_privateBrowsingEnabled) { - MutexLocker locker(m_pendingSyncLock); + LockHolder locker(m_pendingSyncLock); m_iconsPendingSync.set(iconURL, icon->snapshot()); } @@ -584,11 +584,11 @@ void IconDatabase::setIconDataForIconURL(PassRefPtr<SharedBuffer> dataOriginal, // Start the timer to commit this change - or further delay the timer if it was already started scheduleOrDeferSyncTimer(); - for (unsigned i = 0; i < pageURLs.size(); ++i) { + for (auto& pageURL : pageURLs) { AutodrainedPool pool; - LOG(IconDatabase, "Dispatching notification that retaining pageURL %s has a new icon", urlForLogging(pageURLs[i]).ascii().data()); - m_client->didChangeIconForPageURL(pageURLs[i]); + LOG(IconDatabase, "Dispatching notification that retaining pageURL %s has a new icon", urlForLogging(pageURL).ascii().data()); + m_client->didChangeIconForPageURL(pageURL); } } } @@ -607,7 +607,7 @@ void IconDatabase::setIconURLForPageURL(const String& iconURLOriginal, const Str String iconURL, pageURL; { - MutexLocker locker(m_urlAndIconLock); + LockHolder locker(m_urlAndIconLock); PageURLRecord* pageRecord = m_pageURLToRecordMap.get(pageURLOriginal); @@ -635,13 +635,13 @@ void IconDatabase::setIconURLForPageURL(const String& iconURLOriginal, const Str ASSERT(iconRecord->retainingPageURLs().size() == 0); LOG(IconDatabase, "Icon for icon url %s is about to be destroyed - removing mapping for it", urlForLogging(iconRecord->iconURL()).ascii().data()); m_iconURLToRecordMap.remove(iconRecord->iconURL()); - MutexLocker locker(m_pendingReadingLock); + LockHolder locker(m_pendingReadingLock); m_iconsPendingReading.remove(iconRecord.get()); } // And mark this mapping to be added to the database if (!m_privateBrowsingEnabled) { - MutexLocker locker(m_pendingSyncLock); + LockHolder locker(m_pendingSyncLock); m_pageURLsPendingSync.set(pageURL, pageRecord->snapshot()); // If the icon is on its last ref, mark it for deletion @@ -673,7 +673,7 @@ IconLoadDecision IconDatabase::synchronousLoadDecisionForIconURL(const String& i // 1 - When we read the icon urls from disk, getting the timeStamp at the same time // 2 - When we get a new icon from the loader, in which case the timestamp is set at that time { - MutexLocker locker(m_urlAndIconLock); + LockHolder locker(m_urlAndIconLock); if (IconRecord* icon = m_iconURLToRecordMap.get(iconURL)) { LOG(IconDatabase, "Found expiration time on a present icon based on existing IconRecord"); return static_cast<int>(currentTime()) - static_cast<int>(icon->getTimestamp()) > iconExpirationTime ? IconLoadYes : IconLoadNo; @@ -681,7 +681,7 @@ IconLoadDecision IconDatabase::synchronousLoadDecisionForIconURL(const String& i } // If we don't have a record for it, but we *have* imported all iconURLs from disk, then we should load it now - MutexLocker readingLocker(m_pendingReadingLock); + LockHolder readingLocker(m_pendingReadingLock); if (m_iconURLImportComplete) return IconLoadYes; @@ -698,7 +698,7 @@ bool IconDatabase::synchronousIconDataKnownForIconURL(const String& iconURL) { ASSERT_NOT_SYNC_THREAD(); - MutexLocker locker(m_urlAndIconLock); + LockHolder locker(m_urlAndIconLock); if (IconRecord* icon = m_iconURLToRecordMap.get(iconURL)) return icon->imageDataStatus() != ImageDataStatusUnknown; @@ -753,39 +753,36 @@ void IconDatabase::checkIntegrityBeforeOpening() size_t IconDatabase::pageURLMappingCount() { - MutexLocker locker(m_urlAndIconLock); + LockHolder locker(m_urlAndIconLock); return m_pageURLToRecordMap.size(); } size_t IconDatabase::retainedPageURLCount() { - MutexLocker locker(m_urlAndIconLock); + LockHolder locker(m_urlAndIconLock); performPendingRetainAndReleaseOperations(); return m_retainedPageURLs.size(); } size_t IconDatabase::iconRecordCount() { - MutexLocker locker(m_urlAndIconLock); + LockHolder locker(m_urlAndIconLock); return m_iconURLToRecordMap.size(); } size_t IconDatabase::iconRecordCountWithData() { - MutexLocker locker(m_urlAndIconLock); + LockHolder locker(m_urlAndIconLock); size_t result = 0; - - HashMap<String, IconRecord*>::iterator i = m_iconURLToRecordMap.begin(); - HashMap<String, IconRecord*>::iterator end = m_iconURLToRecordMap.end(); - - for (; i != end; ++i) - result += ((*i).value->imageDataStatus() == ImageDataStatusPresent); - + + for (auto& iconRecord : m_iconURLToRecordMap.values()) + result += (iconRecord->imageDataStatus() == ImageDataStatusPresent); + return result; } IconDatabase::IconDatabase() - : m_syncTimer(this, &IconDatabase::syncTimerFired) + : m_syncTimer(*this, &IconDatabase::syncTimerFired) , m_syncThreadRunning(false) , m_scheduleOrDeferSyncTimerRequested(false) , m_isEnabled(false) @@ -796,6 +793,7 @@ IconDatabase::IconDatabase() , m_syncThreadHasWorkToDo(false) , m_retainOrReleaseIconRequested(false) , m_initialPruningComplete(false) + , m_mainThreadCallbackCount(0) , m_client(defaultClient()) { LOG(IconDatabase, "Creating IconDatabase %p", this); @@ -807,11 +805,6 @@ IconDatabase::~IconDatabase() ASSERT(!isOpen()); } -void IconDatabase::notifyPendingLoadDecisionsOnMainThread(void* context) -{ - static_cast<IconDatabase*>(context)->notifyPendingLoadDecisions(); -} - void IconDatabase::notifyPendingLoadDecisions() { ASSERT_NOT_SYNC_THREAD(); @@ -819,37 +812,24 @@ void IconDatabase::notifyPendingLoadDecisions() // This method should only be called upon completion of the initial url import from the database ASSERT(m_iconURLImportComplete); LOG(IconDatabase, "Notifying all DocumentLoaders that were waiting on a load decision for their icons"); - - HashSet<RefPtr<DocumentLoader>>::iterator i = m_loadersPendingDecision.begin(); - HashSet<RefPtr<DocumentLoader>>::iterator end = m_loadersPendingDecision.end(); - - for (; i != end; ++i) - if ((*i)->refCount() > 1) - (*i)->iconLoadDecisionAvailable(); - + + for (auto& loader : m_loadersPendingDecision) { + if (loader->refCount() > 1) + loader->iconLoadDecisionAvailable(); + } + m_loadersPendingDecision.clear(); } void IconDatabase::wakeSyncThread() { - MutexLocker locker(m_syncLock); + LockHolder locker(m_syncLock); if (!m_disableSuddenTerminationWhileSyncThreadHasWorkToDo) m_disableSuddenTerminationWhileSyncThreadHasWorkToDo = std::make_unique<SuddenTerminationDisabler>(); m_syncThreadHasWorkToDo = true; - m_syncCondition.signal(); -} - -void IconDatabase::performScheduleOrDeferSyncTimer() -{ - m_syncTimer.startOneShot(updateTimerDelay); - m_scheduleOrDeferSyncTimerRequested = false; -} - -void IconDatabase::performScheduleOrDeferSyncTimerOnMainThread(void* context) -{ - static_cast<IconDatabase*>(context)->performScheduleOrDeferSyncTimer(); + m_syncCondition.notifyOne(); } void IconDatabase::scheduleOrDeferSyncTimer() @@ -863,10 +843,13 @@ void IconDatabase::scheduleOrDeferSyncTimer() m_disableSuddenTerminationWhileSyncTimerScheduled = std::make_unique<SuddenTerminationDisabler>(); m_scheduleOrDeferSyncTimerRequested = true; - callOnMainThread(performScheduleOrDeferSyncTimerOnMainThread, this); + callOnMainThread([this] { + m_syncTimer.startOneShot(updateTimerDelay); + m_scheduleOrDeferSyncTimerRequested = false; + }); } -void IconDatabase::syncTimerFired(Timer<IconDatabase>&) +void IconDatabase::syncTimerFired() { ASSERT_NOT_SYNC_THREAD(); wakeSyncThread(); @@ -880,35 +863,39 @@ void IconDatabase::syncTimerFired(Timer<IconDatabase>&) bool IconDatabase::isOpen() const { - MutexLocker locker(m_syncLock); - return m_syncDB.isOpen(); + return isOpenBesidesMainThreadCallbacks() || m_mainThreadCallbackCount; +} + +bool IconDatabase::isOpenBesidesMainThreadCallbacks() const +{ + LockHolder locker(m_syncLock); + return m_syncThreadRunning || m_syncDB.isOpen(); } String IconDatabase::databasePath() const { - MutexLocker locker(m_syncLock); + LockHolder locker(m_syncLock); return m_completeDatabasePath.isolatedCopy(); } String IconDatabase::defaultDatabaseFilename() { - DEFINE_STATIC_LOCAL(String, defaultDatabaseFilename, (ASCIILiteral("WebpageIcons.db"))); - return defaultDatabaseFilename.isolatedCopy(); + static NeverDestroyed<String> defaultDatabaseFilename(ASCIILiteral("WebpageIcons.db")); + return defaultDatabaseFilename.get().isolatedCopy(); } // Unlike getOrCreatePageURLRecord(), getOrCreateIconRecord() does not mark the icon as "interested in import" -PassRefPtr<IconRecord> IconDatabase::getOrCreateIconRecord(const String& iconURL) +Ref<IconRecord> IconDatabase::getOrCreateIconRecord(const String& iconURL) { // Clients of getOrCreateIconRecord() are required to acquire the m_urlAndIconLock before calling this method ASSERT(!m_urlAndIconLock.tryLock()); - if (IconRecord* icon = m_iconURLToRecordMap.get(iconURL)) - return icon; + if (auto* icon = m_iconURLToRecordMap.get(iconURL)) + return *icon; - RefPtr<IconRecord> newIcon = IconRecord::create(iconURL); - m_iconURLToRecordMap.set(iconURL, newIcon.get()); - - return newIcon.release(); + auto newIcon = IconRecord::create(iconURL); + m_iconURLToRecordMap.set(iconURL, newIcon.ptr()); + return newIcon; } // This method retrieves the existing PageURLRecord, or creates a new one and marks it as "interested in the import" for later notification @@ -918,11 +905,11 @@ PageURLRecord* IconDatabase::getOrCreatePageURLRecord(const String& pageURL) ASSERT(!m_urlAndIconLock.tryLock()); if (!documentCanHaveIcon(pageURL)) - return 0; + return nullptr; PageURLRecord* pageRecord = m_pageURLToRecordMap.get(pageURL); - MutexLocker locker(m_pendingReadingLock); + LockHolder locker(m_pendingReadingLock); if (!m_iconURLImportComplete) { // If the initial import of all URLs hasn't completed and we have no page record, we assume we *might* know about this later and create a record for it if (!pageRecord) { @@ -935,7 +922,7 @@ PageURLRecord* IconDatabase::getOrCreatePageURLRecord(const String& pageURL) // Mark the URL as "interested in the result of the import" then bail if (!pageRecord->iconRecord()) { m_pageURLsPendingImport.add(pageURL); - return 0; + return nullptr; } } @@ -991,7 +978,7 @@ void IconDatabase::iconDatabaseSyncThread() } { - MutexLocker locker(m_syncLock); + LockHolder locker(m_syncLock); if (!m_syncDB.open(m_completeDatabasePath)) { LOG_ERROR("Unable to open icon database at path %s - %s", m_completeDatabasePath.ascii().data(), m_syncDB.lastErrorMsg()); return; @@ -1119,7 +1106,7 @@ void IconDatabase::performOpenInitialization() m_syncDB.close(); { - MutexLocker locker(m_syncLock); + LockHolder locker(m_syncLock); // Should've been consumed by SQLite, delete just to make sure we don't see it again in the future; deleteFile(m_completeDatabasePath + "-journal"); deleteFile(m_completeDatabasePath); @@ -1165,16 +1152,16 @@ bool IconDatabase::checkIntegrity() ASSERT_ICON_SYNC_THREAD(); SQLiteStatement integrity(m_syncDB, "PRAGMA integrity_check;"); - if (integrity.prepare() != SQLResultOk) { + if (integrity.prepare() != SQLITE_OK) { LOG_ERROR("checkIntegrity failed to execute"); return false; } int resultCode = integrity.step(); - if (resultCode == SQLResultOk) + if (resultCode == SQLITE_OK) return true; - - if (resultCode != SQLResultRow) + + if (resultCode != SQLITE_ROW) return false; int columns = integrity.columnCount(); @@ -1209,25 +1196,25 @@ void IconDatabase::performURLImport() SQLiteStatement query(m_syncDB, importQuery); - if (query.prepare() != SQLResultOk) { + if (query.prepare() != SQLITE_OK) { LOG_ERROR("Unable to prepare icon url import query"); return; } int result = query.step(); - while (result == SQLResultRow) { + while (result == SQLITE_ROW) { AutodrainedPool pool; String pageURL = query.getColumnText(0); String iconURL = query.getColumnText(1); { - MutexLocker locker(m_urlAndIconLock); + LockHolder locker(m_urlAndIconLock); PageURLRecord* pageRecord = m_pageURLToRecordMap.get(pageURL); // If the pageRecord doesn't exist in this map, then no one has retained this pageURL // If the s_databaseCleanupCounter count is non-zero, then we're not supposed to be pruning the database in any manner, - // so go ahead and actually create a pageURLRecord for this url even though it's not retained. + // so actually create a pageURLRecord for this url even though it's not retained. // If database cleanup *is* allowed, we don't want to bother pulling in a page url from disk that noone is actually interested // in - we'll prune it later instead! if (!pageRecord && databaseCleanupCounter && documentCanHaveIcon(pageURL)) { @@ -1254,7 +1241,7 @@ void IconDatabase::performURLImport() // one for the URL and one for the Image itself // Note that WebIconDatabase is not neccessarily API so we might be able to make this change { - MutexLocker locker(m_pendingReadingLock); + LockHolder locker(m_pendingReadingLock); if (m_pageURLsPendingImport.contains(pageURL)) { dispatchDidImportIconURLForPageURLOnMainThread(pageURL); m_pageURLsPendingImport.remove(pageURL); @@ -1270,14 +1257,14 @@ void IconDatabase::performURLImport() result = query.step(); } - if (result != SQLResultDone) + if (result != SQLITE_DONE) LOG(IconDatabase, "Error reading page->icon url mappings from database"); // Clear the m_pageURLsPendingImport set - either the page URLs ended up with an iconURL (that we'll notify about) or not, // but after m_iconURLImportComplete is set to true, we don't care about this set anymore Vector<String> urls; { - MutexLocker locker(m_pendingReadingLock); + LockHolder locker(m_pendingReadingLock); urls.appendRange(m_pageURLsPendingImport.begin(), m_pageURLsPendingImport.end()); m_pageURLsPendingImport.clear(); @@ -1290,15 +1277,15 @@ void IconDatabase::performURLImport() // Remove unretained ones if database cleanup is allowed // Keep a set of ones that are retained and pending notification { - MutexLocker locker(m_urlAndIconLock); + LockHolder locker(m_urlAndIconLock); performPendingRetainAndReleaseOperations(); - for (unsigned i = 0; i < urls.size(); ++i) { - if (!m_retainedPageURLs.contains(urls[i])) { - PageURLRecord* record = m_pageURLToRecordMap.get(urls[i]); + for (auto& url : urls) { + if (!m_retainedPageURLs.contains(url)) { + PageURLRecord* record = m_pageURLToRecordMap.get(url); if (record && !databaseCleanupCounter) { - m_pageURLToRecordMap.remove(urls[i]); + m_pageURLToRecordMap.remove(url); IconRecord* iconRecord = record->iconRecord(); // If this page is the only remaining retainer of its icon, mark that icon for deletion and don't bother @@ -1307,12 +1294,12 @@ void IconDatabase::performURLImport() m_iconURLToRecordMap.remove(iconRecord->iconURL()); { - MutexLocker locker(m_pendingReadingLock); - m_pageURLsInterestedInIcons.remove(urls[i]); + LockHolder locker(m_pendingReadingLock); + m_pageURLsInterestedInIcons.remove(url); m_iconsPendingReading.remove(iconRecord); } { - MutexLocker locker(m_pendingSyncLock); + LockHolder locker(m_pendingSyncLock); m_iconsPendingSync.set(iconRecord->iconURL(), iconRecord->snapshot(true)); } } @@ -1320,18 +1307,18 @@ void IconDatabase::performURLImport() delete record; } } else { - urlsToNotify.append(urls[i]); + urlsToNotify.append(url); } } } LOG(IconDatabase, "Notifying %lu interested page URLs that their icon URL is known due to the import", static_cast<unsigned long>(urlsToNotify.size())); // Now that we don't hold any locks, perform the actual notifications - for (unsigned i = 0; i < urlsToNotify.size(); ++i) { + for (auto& url : urlsToNotify) { AutodrainedPool pool; - LOG(IconDatabase, "Notifying icon info known for pageURL %s", urlsToNotify[i].ascii().data()); - dispatchDidImportIconURLForPageURLOnMainThread(urlsToNotify[i]); + LOG(IconDatabase, "Notifying icon info known for pageURL %s", url.ascii().data()); + dispatchDidImportIconURLForPageURLOnMainThread(url); if (shouldStopThreadActivity()) return; } @@ -1340,7 +1327,9 @@ void IconDatabase::performURLImport() dispatchDidFinishURLImportOnMainThread(); // Notify all DocumentLoaders that were waiting for an icon load decision on the main thread - callOnMainThread(notifyPendingLoadDecisionsOnMainThread, this); + callOnMainThread([this] { + notifyPendingLoadDecisions(); + }); } void IconDatabase::syncThreadMainLoop() @@ -1349,7 +1338,7 @@ void IconDatabase::syncThreadMainLoop() m_syncLock.lock(); - std::unique_ptr<SuddenTerminationDisabler> disableSuddenTermination = std::move(m_disableSuddenTerminationWhileSyncThreadHasWorkToDo); + std::unique_ptr<SuddenTerminationDisabler> disableSuddenTermination = WTFMove(m_disableSuddenTerminationWhileSyncThreadHasWorkToDo); // We'll either do any pending work on our first pass through the loop, or we'll terminate // without doing any work. Either way we're dealing with any currently-pending work. @@ -1371,11 +1360,13 @@ void IconDatabase::syncThreadMainLoop() } // Then, if the thread should be quitting, quit now! - if (m_threadTerminationRequested) - break; + if (m_threadTerminationRequested) { + cleanupSyncThread(); + return; + } { - MutexLocker locker(m_urlAndIconLock); + LockHolder locker(m_urlAndIconLock); performPendingRetainAndReleaseOperations(); } @@ -1437,7 +1428,7 @@ void IconDatabase::syncThreadMainLoop() m_syncThreadHasWorkToDo = false; ASSERT(m_disableSuddenTerminationWhileSyncThreadHasWorkToDo); - disableSuddenTermination = std::move(m_disableSuddenTerminationWhileSyncThreadHasWorkToDo); + disableSuddenTermination = WTFMove(m_disableSuddenTerminationWhileSyncThreadHasWorkToDo); } m_syncLock.unlock(); @@ -1455,7 +1446,7 @@ void IconDatabase::performPendingRetainAndReleaseOperations() HashCountedSet<String> toRelease; { - MutexLocker pendingWorkLocker(m_urlsToRetainOrReleaseLock); + LockHolder pendingWorkLocker(m_urlsToRetainOrReleaseLock); if (!m_retainOrReleaseIconRequested) return; @@ -1467,14 +1458,14 @@ void IconDatabase::performPendingRetainAndReleaseOperations() m_retainOrReleaseIconRequested = false; } - for (HashCountedSet<String>::const_iterator it = toRetain.begin(), end = toRetain.end(); it != end; ++it) { - ASSERT(!it->key.impl() || it->key.impl()->hasOneRef()); - performRetainIconForPageURL(it->key, it->value); + for (auto& entry : toRetain) { + ASSERT(!entry.key.impl() || entry.key.impl()->hasOneRef()); + performRetainIconForPageURL(entry.key, entry.value); } - for (HashCountedSet<String>::const_iterator it = toRelease.begin(), end = toRelease.end(); it != end; ++it) { - ASSERT(!it->key.impl() || it->key.impl()->hasOneRef()); - performReleaseIconForPageURL(it->key, it->value); + for (auto& entry : toRelease) { + ASSERT(!entry.key.impl() || entry.key.impl()->hasOneRef()); + performReleaseIconForPageURL(entry.key, entry.value); } } @@ -1492,7 +1483,7 @@ bool IconDatabase::readFromDatabase() // This way we won't hold the lock for a long period of time Vector<IconRecord*> icons; { - MutexLocker locker(m_pendingReadingLock); + LockHolder locker(m_pendingReadingLock); icons.appendRange(m_iconsPendingReading.begin(), m_iconsPendingReading.end()); } @@ -1501,17 +1492,17 @@ bool IconDatabase::readFromDatabase() for (unsigned i = 0; i < icons.size(); ++i) { didAnyWork = true; - RefPtr<SharedBuffer> imageData = getImageDataForIconURLFromSQLDatabase(icons[i]->iconURL()); + auto imageData = getImageDataForIconURLFromSQLDatabase(icons[i]->iconURL()); // Verify this icon still wants to be read from disk { - MutexLocker urlLocker(m_urlAndIconLock); + LockHolder urlLocker(m_urlAndIconLock); { - MutexLocker readLocker(m_pendingReadingLock); + LockHolder readLocker(m_pendingReadingLock); if (m_iconsPendingReading.contains(icons[i])) { // Set the new data - icons[i]->setImageData(imageData.release()); + icons[i]->setImageData(WTFMove(imageData)); // Remove this icon from the set that needs to be read m_iconsPendingReading.remove(icons[i]); @@ -1530,12 +1521,10 @@ bool IconDatabase::readFromDatabase() outerHash = &(icons[i]->retainingPageURLs()); } - HashSet<String>::const_iterator iter = outerHash->begin(); - HashSet<String>::const_iterator end = outerHash->end(); - for (; iter != end; ++iter) { - if (innerHash->contains(*iter)) { - LOG(IconDatabase, "%s is interested in the icon we just read. Adding it to the notification list and removing it from the interested set", urlForLogging(*iter).ascii().data()); - urlsToNotify.add(*iter); + for (auto& outer : *outerHash) { + if (innerHash->contains(outer)) { + LOG(IconDatabase, "%s is interested in the icon we just read. Adding it to the notification list and removing it from the interested set", urlForLogging(outer).ascii().data()); + urlsToNotify.add(outer); } // If we ever get to the point were we've seen every url interested in this icon, break early @@ -1547,10 +1536,8 @@ bool IconDatabase::readFromDatabase() if (urlsToNotify.size() == m_pageURLsInterestedInIcons.size()) m_pageURLsInterestedInIcons.clear(); else { - iter = urlsToNotify.begin(); - end = urlsToNotify.end(); - for (; iter != end; ++iter) - m_pageURLsInterestedInIcons.remove(*iter); + for (auto& url : urlsToNotify) + m_pageURLsInterestedInIcons.remove(url); } } } @@ -1595,11 +1582,11 @@ bool IconDatabase::writeToDatabase() // we'll pick it up on the next pass. This greatly simplifies the locking strategy for this method and remains cohesive with changes // asked for by the database on the main thread { - MutexLocker locker(m_urlAndIconLock); + LockHolder locker(m_urlAndIconLock); Vector<IconSnapshot> iconSnapshots; Vector<PageURLSnapshot> pageSnapshots; { - MutexLocker locker(m_pendingSyncLock); + LockHolder locker(m_pendingSyncLock); iconSnapshots.appendRange(m_iconsPendingSync.begin().values(), m_iconsPendingSync.end().values()); m_iconsPendingSync.clear(); @@ -1614,19 +1601,19 @@ bool IconDatabase::writeToDatabase() SQLiteTransaction syncTransaction(m_syncDB); syncTransaction.begin(); - for (unsigned i = 0; i < iconSnapshots.size(); ++i) { - writeIconSnapshotToSQLDatabase(iconSnapshots[i]); - LOG(IconDatabase, "Wrote IconRecord for IconURL %s with timeStamp of %i to the DB", urlForLogging(iconSnapshots[i].iconURL()).ascii().data(), iconSnapshots[i].timestamp()); + for (auto& snapshot : iconSnapshots) { + writeIconSnapshotToSQLDatabase(snapshot); + LOG(IconDatabase, "Wrote IconRecord for IconURL %s with timeStamp of %i to the DB", urlForLogging(snapshot.iconURL()).ascii().data(), snapshot.timestamp()); } - for (unsigned i = 0; i < pageSnapshots.size(); ++i) { + for (auto& snapshot : pageSnapshots) { // If the icon URL is empty, this page is meant to be deleted // ASSERTs are sanity checks to make sure the mappings exist if they should and don't if they shouldn't - if (pageSnapshots[i].iconURL().isEmpty()) - removePageURLFromSQLDatabase(pageSnapshots[i].pageURL()); + if (snapshot.iconURL().isEmpty()) + removePageURLFromSQLDatabase(snapshot.pageURL()); else - setIconURLForPageURLInSQLDatabase(pageSnapshots[i].iconURL(), pageSnapshots[i].pageURL()); - LOG(IconDatabase, "Committed IconURL for PageURL %s to database", urlForLogging(pageSnapshots[i].pageURL()).ascii().data()); + setIconURLForPageURLInSQLDatabase(snapshot.iconURL(), snapshot.pageURL()); + LOG(IconDatabase, "Committed IconURL for PageURL %s to database", urlForLogging(snapshot.pageURL()).ascii().data()); } syncTransaction.commit(); @@ -1661,13 +1648,13 @@ void IconDatabase::pruneUnretainedIcons() pageSQL.prepare(); int result; - while ((result = pageSQL.step()) == SQLResultRow) { - MutexLocker locker(m_urlAndIconLock); + while ((result = pageSQL.step()) == SQLITE_ROW) { + LockHolder locker(m_urlAndIconLock); if (!m_pageURLToRecordMap.contains(pageSQL.getColumnText(1))) pageIDsToDelete.append(pageSQL.getColumnInt64(0)); } - if (result != SQLResultDone) + if (result != SQLITE_DONE) LOG_ERROR("Error reading PageURL table from on-disk DB"); pageSQL.finalize(); @@ -1683,7 +1670,7 @@ void IconDatabase::pruneUnretainedIcons() LOG(IconDatabase, "Pruning page with rowid %lli from disk", static_cast<long long>(pageIDsToDelete[i])); pageDeleteSQL.bindInt64(1, pageIDsToDelete[i]); int result = pageDeleteSQL.step(); - if (result != SQLResultDone) + if (result != SQLITE_DONE) LOG_ERROR("Unabled to delete page with id %lli from disk", static_cast<long long>(pageIDsToDelete[i])); pageDeleteSQL.reset(); @@ -1762,20 +1749,20 @@ void IconDatabase::deleteAllPreparedStatements() { ASSERT_ICON_SYNC_THREAD(); - m_setIconIDForPageURLStatement.clear(); - m_removePageURLStatement.clear(); - m_getIconIDForIconURLStatement.clear(); - m_getImageDataForIconURLStatement.clear(); - m_addIconToIconInfoStatement.clear(); - m_addIconToIconDataStatement.clear(); - m_getImageDataStatement.clear(); - m_deletePageURLsForIconURLStatement.clear(); - m_deleteIconFromIconInfoStatement.clear(); - m_deleteIconFromIconDataStatement.clear(); - m_updateIconInfoStatement.clear(); - m_updateIconDataStatement.clear(); - m_setIconInfoStatement.clear(); - m_setIconDataStatement.clear(); + m_setIconIDForPageURLStatement = nullptr; + m_removePageURLStatement = nullptr; + m_getIconIDForIconURLStatement = nullptr; + m_getImageDataForIconURLStatement = nullptr; + m_addIconToIconInfoStatement = nullptr; + m_addIconToIconDataStatement = nullptr; + m_getImageDataStatement = nullptr; + m_deletePageURLsForIconURLStatement = nullptr; + m_deleteIconFromIconInfoStatement = nullptr; + m_deleteIconFromIconDataStatement = nullptr; + m_updateIconInfoStatement = nullptr; + m_updateIconDataStatement = nullptr; + m_setIconInfoStatement = nullptr; + m_setIconDataStatement = nullptr; } void* IconDatabase::cleanupSyncThread() @@ -1795,7 +1782,7 @@ void* IconDatabase::cleanupSyncThread() writeToDatabase(); // Close the database - MutexLocker locker(m_syncLock); + LockHolder locker(m_syncLock); m_databaseDirectory = String(); m_completeDatabasePath = String(); @@ -1807,23 +1794,23 @@ void* IconDatabase::cleanupSyncThread() #endif m_syncThreadRunning = false; - return 0; + return nullptr; } // readySQLiteStatement() handles two things // 1 - If the SQLDatabase& argument is different, the statement must be destroyed and remade. This happens when the user // switches to and from private browsing // 2 - Lazy construction of the Statement in the first place, in case we've never made this query before -inline void readySQLiteStatement(OwnPtr<SQLiteStatement>& statement, SQLiteDatabase& db, const String& str) +inline void readySQLiteStatement(std::unique_ptr<SQLiteStatement>& statement, SQLiteDatabase& db, const String& str) { - if (statement && (statement->database() != &db || statement->isExpired())) { + if (statement && (&statement->database() != &db || statement->isExpired())) { if (statement->isExpired()) LOG(IconDatabase, "SQLiteStatement associated with %s is expired", str.ascii().data()); - statement.clear(); + statement = nullptr; } if (!statement) { - statement = adoptPtr(new SQLiteStatement(db, str)); - if (statement->prepare() != SQLResultOk) + statement = std::make_unique<SQLiteStatement>(db, str); + if (statement->prepare() != SQLITE_OK) LOG_ERROR("Preparing statement %s failed", str.ascii().data()); } } @@ -1855,7 +1842,7 @@ void IconDatabase::setIconIDForPageURLInSQLDatabase(int64_t iconID, const String m_setIconIDForPageURLStatement->bindInt64(2, iconID); int result = m_setIconIDForPageURLStatement->step(); - if (result != SQLResultDone) { + if (result != SQLITE_DONE) { ASSERT_NOT_REACHED(); LOG_ERROR("setIconIDForPageURLQuery failed for url %s", urlForLogging(pageURL).ascii().data()); } @@ -1870,7 +1857,7 @@ void IconDatabase::removePageURLFromSQLDatabase(const String& pageURL) readySQLiteStatement(m_removePageURLStatement, m_syncDB, "DELETE FROM PageURL WHERE url = (?);"); m_removePageURLStatement->bindText(1, pageURL); - if (m_removePageURLStatement->step() != SQLResultDone) + if (m_removePageURLStatement->step() != SQLITE_DONE) LOG_ERROR("removePageURLFromSQLDatabase failed for url %s", urlForLogging(pageURL).ascii().data()); m_removePageURLStatement->reset(); @@ -1885,10 +1872,10 @@ int64_t IconDatabase::getIconIDForIconURLFromSQLDatabase(const String& iconURL) m_getIconIDForIconURLStatement->bindText(1, iconURL); int64_t result = m_getIconIDForIconURLStatement->step(); - if (result == SQLResultRow) + if (result == SQLITE_ROW) result = m_getIconIDForIconURLStatement->getColumnInt64(0); else { - if (result != SQLResultDone) + if (result != SQLITE_DONE) LOG_ERROR("getIconIDForIconURLFromSQLDatabase failed for url %s", urlForLogging(iconURL).ascii().data()); result = 0; } @@ -1910,7 +1897,7 @@ int64_t IconDatabase::addIconURLToSQLDatabase(const String& iconURL) int result = m_addIconToIconInfoStatement->step(); m_addIconToIconInfoStatement->reset(); - if (result != SQLResultDone) { + if (result != SQLITE_DONE) { LOG_ERROR("addIconURLToSQLDatabase failed to insert %s into IconInfo", urlForLogging(iconURL).ascii().data()); return 0; } @@ -1921,7 +1908,7 @@ int64_t IconDatabase::addIconURLToSQLDatabase(const String& iconURL) result = m_addIconToIconDataStatement->step(); m_addIconToIconDataStatement->reset(); - if (result != SQLResultDone) { + if (result != SQLITE_DONE) { LOG_ERROR("addIconURLToSQLDatabase failed to insert %s into IconData", urlForLogging(iconURL).ascii().data()); return 0; } @@ -1929,7 +1916,7 @@ int64_t IconDatabase::addIconURLToSQLDatabase(const String& iconURL) return iconID; } -PassRefPtr<SharedBuffer> IconDatabase::getImageDataForIconURLFromSQLDatabase(const String& iconURL) +RefPtr<SharedBuffer> IconDatabase::getImageDataForIconURLFromSQLDatabase(const String& iconURL) { ASSERT_ICON_SYNC_THREAD(); @@ -1939,16 +1926,16 @@ PassRefPtr<SharedBuffer> IconDatabase::getImageDataForIconURLFromSQLDatabase(con m_getImageDataForIconURLStatement->bindText(1, iconURL); int result = m_getImageDataForIconURLStatement->step(); - if (result == SQLResultRow) { + if (result == SQLITE_ROW) { Vector<char> data; m_getImageDataForIconURLStatement->getColumnBlobAsVector(0, data); imageData = SharedBuffer::create(data.data(), data.size()); - } else if (result != SQLResultDone) + } else if (result != SQLITE_DONE) LOG_ERROR("getImageDataForIconURLFromSQLDatabase failed for url %s", urlForLogging(iconURL).ascii().data()); m_getImageDataForIconURLStatement->reset(); - return imageData.release(); + return imageData; } void IconDatabase::removeIconFromSQLDatabase(const String& iconURL) @@ -1970,21 +1957,21 @@ void IconDatabase::removeIconFromSQLDatabase(const String& iconURL) readySQLiteStatement(m_deletePageURLsForIconURLStatement, m_syncDB, "DELETE FROM PageURL WHERE PageURL.iconID = (?);"); m_deletePageURLsForIconURLStatement->bindInt64(1, iconID); - if (m_deletePageURLsForIconURLStatement->step() != SQLResultDone) + if (m_deletePageURLsForIconURLStatement->step() != SQLITE_DONE) LOG_ERROR("m_deletePageURLsForIconURLStatement failed for url %s", urlForLogging(iconURL).ascii().data()); readySQLiteStatement(m_deleteIconFromIconInfoStatement, m_syncDB, "DELETE FROM IconInfo WHERE IconInfo.iconID = (?);"); m_deleteIconFromIconInfoStatement->bindInt64(1, iconID); - if (m_deleteIconFromIconInfoStatement->step() != SQLResultDone) + if (m_deleteIconFromIconInfoStatement->step() != SQLITE_DONE) LOG_ERROR("m_deleteIconFromIconInfoStatement failed for url %s", urlForLogging(iconURL).ascii().data()); - + readySQLiteStatement(m_deleteIconFromIconDataStatement, m_syncDB, "DELETE FROM IconData WHERE IconData.iconID = (?);"); m_deleteIconFromIconDataStatement->bindInt64(1, iconID); - if (m_deleteIconFromIconDataStatement->step() != SQLResultDone) + if (m_deleteIconFromIconDataStatement->step() != SQLITE_DONE) LOG_ERROR("m_deleteIconFromIconDataStatement failed for url %s", urlForLogging(iconURL).ascii().data()); - + m_deletePageURLsForIconURLStatement->reset(); m_deleteIconFromIconInfoStatement->reset(); m_deleteIconFromIconDataStatement->reset(); @@ -2018,7 +2005,7 @@ void IconDatabase::writeIconSnapshotToSQLDatabase(const IconSnapshot& snapshot) m_updateIconInfoStatement->bindText(2, snapshot.iconURL()); m_updateIconInfoStatement->bindInt64(3, iconID); - if (m_updateIconInfoStatement->step() != SQLResultDone) + if (m_updateIconInfoStatement->step() != SQLITE_DONE) LOG_ERROR("Failed to update icon info for url %s", urlForLogging(snapshot.iconURL()).ascii().data()); m_updateIconInfoStatement->reset(); @@ -2033,7 +2020,7 @@ void IconDatabase::writeIconSnapshotToSQLDatabase(const IconSnapshot& snapshot) else m_updateIconDataStatement->bindNull(1); - if (m_updateIconDataStatement->step() != SQLResultDone) + if (m_updateIconDataStatement->step() != SQLITE_DONE) LOG_ERROR("Failed to update icon data for url %s", urlForLogging(snapshot.iconURL()).ascii().data()); m_updateIconDataStatement->reset(); @@ -2042,7 +2029,7 @@ void IconDatabase::writeIconSnapshotToSQLDatabase(const IconSnapshot& snapshot) m_setIconInfoStatement->bindText(1, snapshot.iconURL()); m_setIconInfoStatement->bindInt64(2, snapshot.timestamp()); - if (m_setIconInfoStatement->step() != SQLResultDone) + if (m_setIconInfoStatement->step() != SQLITE_DONE) LOG_ERROR("Failed to set icon info for url %s", urlForLogging(snapshot.iconURL()).ascii().data()); m_setIconInfoStatement->reset(); @@ -2059,7 +2046,7 @@ void IconDatabase::writeIconSnapshotToSQLDatabase(const IconSnapshot& snapshot) else m_setIconDataStatement->bindNull(2); - if (m_setIconDataStatement->step() != SQLResultDone) + if (m_setIconDataStatement->step() != SQLITE_DONE) LOG_ERROR("Failed to set icon data for url %s", urlForLogging(snapshot.iconURL()).ascii().data()); m_setIconDataStatement->reset(); @@ -2080,133 +2067,71 @@ void IconDatabase::setWasExcludedFromBackup() SQLiteStatement(m_syncDB, "INSERT INTO IconDatabaseInfo (key, value) VALUES ('ExcludedFromBackup', 1)").executeCommand(); } -class ClientWorkItem { - WTF_MAKE_FAST_ALLOCATED; -public: - ClientWorkItem(IconDatabaseClient* client) - : m_client(client) - { } - virtual void performWork() = 0; - virtual ~ClientWorkItem() { } - -protected: - IconDatabaseClient* m_client; -}; - -class ImportedIconURLForPageURLWorkItem : public ClientWorkItem { -public: - ImportedIconURLForPageURLWorkItem(IconDatabaseClient* client, const String& pageURL) - : ClientWorkItem(client) - , m_pageURL(new String(pageURL.isolatedCopy())) - { } - - virtual ~ImportedIconURLForPageURLWorkItem() - { - delete m_pageURL; - } - - virtual void performWork() - { - ASSERT(m_client); - m_client->didImportIconURLForPageURL(*m_pageURL); - m_client = 0; - } - -private: - String* m_pageURL; -}; - -class ImportedIconDataForPageURLWorkItem : public ClientWorkItem { -public: - ImportedIconDataForPageURLWorkItem(IconDatabaseClient* client, const String& pageURL) - : ClientWorkItem(client) - , m_pageURL(new String(pageURL.isolatedCopy())) - { } - - virtual ~ImportedIconDataForPageURLWorkItem() - { - delete m_pageURL; - } - - virtual void performWork() - { - ASSERT(m_client); - m_client->didImportIconDataForPageURL(*m_pageURL); - m_client = 0; - } - -private: - String* m_pageURL; -}; - -class RemovedAllIconsWorkItem : public ClientWorkItem { -public: - RemovedAllIconsWorkItem(IconDatabaseClient* client) - : ClientWorkItem(client) - { } - - virtual void performWork() - { - ASSERT(m_client); - m_client->didRemoveAllIcons(); - m_client = 0; - } -}; +void IconDatabase::checkClosedAfterMainThreadCallback() +{ + ASSERT_NOT_SYNC_THREAD(); -class FinishedURLImport : public ClientWorkItem { -public: - FinishedURLImport(IconDatabaseClient* client) - : ClientWorkItem(client) - { } + // If there are still callbacks in flight from the sync thread we cannot possibly be closed. + if (--m_mainThreadCallbackCount) + return; - virtual void performWork() - { - ASSERT(m_client); - m_client->didFinishURLImport(); - m_client = 0; - } -}; + // Even if there's no more pending callbacks the database might otherwise still be open. + if (isOpenBesidesMainThreadCallbacks()) + return; -static void performWorkItem(void* context) -{ - ClientWorkItem* item = static_cast<ClientWorkItem*>(context); - item->performWork(); - delete item; + // This database is now actually closed! But first notify the client. + if (m_client) + m_client->didClose(); } void IconDatabase::dispatchDidImportIconURLForPageURLOnMainThread(const String& pageURL) { ASSERT_ICON_SYNC_THREAD(); + ++m_mainThreadCallbackCount; - ImportedIconURLForPageURLWorkItem* work = new ImportedIconURLForPageURLWorkItem(m_client, pageURL); - callOnMainThread(performWorkItem, work); + callOnMainThread([this, pageURL = pageURL.isolatedCopy()] { + if (m_client) + m_client->didImportIconURLForPageURL(pageURL); + checkClosedAfterMainThreadCallback(); + }); } void IconDatabase::dispatchDidImportIconDataForPageURLOnMainThread(const String& pageURL) { ASSERT_ICON_SYNC_THREAD(); + ++m_mainThreadCallbackCount; - ImportedIconDataForPageURLWorkItem* work = new ImportedIconDataForPageURLWorkItem(m_client, pageURL); - callOnMainThread(performWorkItem, work); + callOnMainThread([this, pageURL = pageURL.isolatedCopy()] { + if (m_client) + m_client->didImportIconDataForPageURL(pageURL); + checkClosedAfterMainThreadCallback(); + }); } void IconDatabase::dispatchDidRemoveAllIconsOnMainThread() { ASSERT_ICON_SYNC_THREAD(); + ++m_mainThreadCallbackCount; - RemovedAllIconsWorkItem* work = new RemovedAllIconsWorkItem(m_client); - callOnMainThread(performWorkItem, work); + callOnMainThread([this] { + if (m_client) + m_client->didRemoveAllIcons(); + checkClosedAfterMainThreadCallback(); + }); } void IconDatabase::dispatchDidFinishURLImportOnMainThread() { ASSERT_ICON_SYNC_THREAD(); + ++m_mainThreadCallbackCount; - FinishedURLImport* work = new FinishedURLImport(m_client); - callOnMainThread(performWorkItem, work); + callOnMainThread([this] { + if (m_client) + m_client->didFinishURLImport(); + checkClosedAfterMainThreadCallback(); + }); } - } // namespace WebCore #endif // ENABLE(ICONDATABASE) diff --git a/Source/WebCore/loader/icon/IconDatabase.h b/Source/WebCore/loader/icon/IconDatabase.h index 04db323a7..061af4a12 100644 --- a/Source/WebCore/loader/icon/IconDatabase.h +++ b/Source/WebCore/loader/icon/IconDatabase.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2006, 2007, 2008, 2009, 2014 Apple Inc. All rights reserved. * Copyright (C) 2007 Justin Haygood (jhaygood@reaktix.com) * * Redistribution and use in source and binary forms, with or without @@ -11,10 +11,10 @@ * 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 COMPUTER, INC. ``AS IS'' AND ANY + * 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 COMPUTER, INC. OR + * 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 @@ -24,113 +24,101 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef IconDatabase_h -#define IconDatabase_h +#pragma once #include "IconDatabaseBase.h" -#include "Timer.h" -#include <wtf/HashCountedSet.h> -#include <wtf/HashMap.h> -#include <wtf/HashSet.h> -#include <wtf/Noncopyable.h> -#include <wtf/OwnPtr.h> -#include <wtf/PassOwnPtr.h> -#include <wtf/text/StringHash.h> #include <wtf/text/WTFString.h> #if ENABLE(ICONDATABASE) #include "SQLiteDatabase.h" -#include <wtf/Threading.h> -#endif // ENABLE(ICONDATABASE) +#include "Timer.h" +#include <wtf/Condition.h> +#include <wtf/HashCountedSet.h> +#include <wtf/HashMap.h> +#include <wtf/HashSet.h> +#endif namespace WebCore { -class DocumentLoader; -class Image; -class IntSize; -class IconDatabaseClient; -class IconRecord; -class IconSnapshot; -class URL; -class PageURLRecord; -class PageURLSnapshot; -class SharedBuffer; -class SuddenTerminationDisabler; +#if !ENABLE(ICONDATABASE) -#if ENABLE(ICONDATABASE) -class SQLTransaction; -#endif +// Dummy version of IconDatabase that does nothing. +class IconDatabase final : public IconDatabaseBase { + WTF_MAKE_FAST_ALLOCATED; -#if !ENABLE(ICONDATABASE) -// For builds with IconDatabase disabled, they'll just use a default derivation of IconDatabaseBase. Which does nothing. -class IconDatabase : public IconDatabaseBase { public: - static PassOwnPtr<IconDatabase> create() { return adoptPtr(new IconDatabase); } static void delayDatabaseCleanup() { } static void allowDatabaseCleanup() { } static void checkIntegrityBeforeOpening() { } - static String defaultDatabaseFilename() { return "WebpageIcons.db"; } + + // FIXME: Is it really helpful to return a filename here rather than just the null string? + static String defaultDatabaseFilename() { return ASCIILiteral("WebpageIcons.db"); } }; -#else -class IconDatabase : public IconDatabaseBase { +#else + +class IconRecord; +class IconSnapshot; +class PageURLRecord; +class PageURLSnapshot; +class SuddenTerminationDisabler; + +class IconDatabase final : public IconDatabaseBase { WTF_MAKE_FAST_ALLOCATED; // *** Main Thread Only *** public: - static PassOwnPtr<IconDatabase> create() { return adoptPtr(new IconDatabase); } + WEBCORE_EXPORT IconDatabase(); ~IconDatabase(); - virtual void setClient(IconDatabaseClient*); + WEBCORE_EXPORT void setClient(IconDatabaseClient*) final; - virtual bool open(const String& directory, const String& filename); - virtual void close(); + WEBCORE_EXPORT bool open(const String& directory, const String& filename) final; + WEBCORE_EXPORT void close() final; - virtual void removeAllIcons(); + WEBCORE_EXPORT void removeAllIcons() final; void readIconForPageURLFromDisk(const String&); - virtual Image* defaultIcon(const IntSize&); + WEBCORE_EXPORT Image* defaultIcon(const IntSize&) final; - virtual void retainIconForPageURL(const String&); - virtual void releaseIconForPageURL(const String&); - virtual void setIconDataForIconURL(PassRefPtr<SharedBuffer> data, const String&); - virtual void setIconURLForPageURL(const String& iconURL, const String& pageURL); + WEBCORE_EXPORT void retainIconForPageURL(const String&) final; + WEBCORE_EXPORT void releaseIconForPageURL(const String&) final; + WEBCORE_EXPORT void setIconDataForIconURL(SharedBuffer* data, const String& iconURL) final; + WEBCORE_EXPORT void setIconURLForPageURL(const String& iconURL, const String& pageURL) final; - virtual Image* synchronousIconForPageURL(const String&, const IntSize&); - virtual PassNativeImagePtr synchronousNativeIconForPageURL(const String& pageURLOriginal, const IntSize&); - virtual String synchronousIconURLForPageURL(const String&); - virtual bool synchronousIconDataKnownForIconURL(const String&); - virtual IconLoadDecision synchronousLoadDecisionForIconURL(const String&, DocumentLoader*); - - virtual void setEnabled(bool); - virtual bool isEnabled() const; - - virtual void setPrivateBrowsingEnabled(bool flag); + WEBCORE_EXPORT Image* synchronousIconForPageURL(const String&, const IntSize&) final; + NativeImagePtr synchronousNativeIconForPageURL(const String& pageURLOriginal, const IntSize&) final; + WEBCORE_EXPORT String synchronousIconURLForPageURL(const String&) final; + bool synchronousIconDataKnownForIconURL(const String&) final; + WEBCORE_EXPORT IconLoadDecision synchronousLoadDecisionForIconURL(const String&, DocumentLoader*) final; + + WEBCORE_EXPORT void setEnabled(bool); + WEBCORE_EXPORT bool isEnabled() const final; + + WEBCORE_EXPORT void setPrivateBrowsingEnabled(bool flag) final; bool isPrivateBrowsingEnabled() const; - - static void delayDatabaseCleanup(); - static void allowDatabaseCleanup(); - static void checkIntegrityBeforeOpening(); - + + WEBCORE_EXPORT static void delayDatabaseCleanup(); + WEBCORE_EXPORT static void allowDatabaseCleanup(); + WEBCORE_EXPORT static void checkIntegrityBeforeOpening(); + // Support for WebCoreStatistics in WebKit - virtual size_t pageURLMappingCount(); - virtual size_t retainedPageURLCount(); - virtual size_t iconRecordCount(); - virtual size_t iconRecordCountWithData(); + WEBCORE_EXPORT size_t pageURLMappingCount() final; + WEBCORE_EXPORT size_t retainedPageURLCount() final; + WEBCORE_EXPORT size_t iconRecordCount() final; + WEBCORE_EXPORT size_t iconRecordCountWithData() final; private: - IconDatabase(); friend IconDatabaseBase& iconDatabase(); - static void notifyPendingLoadDecisionsOnMainThread(void*); void notifyPendingLoadDecisions(); void wakeSyncThread(); void scheduleOrDeferSyncTimer(); - void syncTimerFired(Timer<IconDatabase>&); + void syncTimerFired(); - Timer<IconDatabase> m_syncTimer; + Timer m_syncTimer; ThreadIdentifier m_syncThread; bool m_syncThreadRunning; @@ -138,27 +126,24 @@ private: RefPtr<IconRecord> m_defaultIconRecord; - static void performScheduleOrDeferSyncTimerOnMainThread(void*); - void performScheduleOrDeferSyncTimer(); - bool m_scheduleOrDeferSyncTimerRequested; std::unique_ptr<SuddenTerminationDisabler> m_disableSuddenTerminationWhileSyncTimerScheduled; // *** Any Thread *** public: - virtual bool isOpen() const; - virtual String databasePath() const; - static String defaultDatabaseFilename(); + WEBCORE_EXPORT bool isOpen() const final; + WEBCORE_EXPORT String databasePath() const final; + WEBCORE_EXPORT static String defaultDatabaseFilename(); private: - PassRefPtr<IconRecord> getOrCreateIconRecord(const String& iconURL); + Ref<IconRecord> getOrCreateIconRecord(const String& iconURL); PageURLRecord* getOrCreatePageURLRecord(const String& pageURL); bool m_isEnabled; bool m_privateBrowsingEnabled; - mutable Mutex m_syncLock; - ThreadCondition m_syncCondition; + mutable Lock m_syncLock; + Condition m_syncCondition; String m_databaseDirectory; // Holding m_syncLock is required when accessing m_completeDatabasePath String m_completeDatabasePath; @@ -169,24 +154,24 @@ private: bool m_syncThreadHasWorkToDo; std::unique_ptr<SuddenTerminationDisabler> m_disableSuddenTerminationWhileSyncThreadHasWorkToDo; - Mutex m_urlAndIconLock; + Lock m_urlAndIconLock; // Holding m_urlAndIconLock is required when accessing any of the following data structures or the objects they contain HashMap<String, IconRecord*> m_iconURLToRecordMap; HashMap<String, PageURLRecord*> m_pageURLToRecordMap; HashSet<String> m_retainedPageURLs; - Mutex m_pendingSyncLock; + Lock m_pendingSyncLock; // Holding m_pendingSyncLock is required when accessing any of the following data structures HashMap<String, PageURLSnapshot> m_pageURLsPendingSync; HashMap<String, IconSnapshot> m_iconsPendingSync; - Mutex m_pendingReadingLock; + Lock m_pendingReadingLock; // Holding m_pendingSyncLock is required when accessing any of the following data structures - when dealing with IconRecord*s, holding m_urlAndIconLock is also required HashSet<String> m_pageURLsPendingImport; HashSet<String> m_pageURLsInterestedInIcons; HashSet<IconRecord*> m_iconsPendingReading; - Mutex m_urlsToRetainOrReleaseLock; + Lock m_urlsToRetainOrReleaseLock; // Holding m_urlsToRetainOrReleaseLock is required when accessing any of the following data structures. HashCountedSet<String> m_urlsToRetain; HashCountedSet<String> m_urlsToRelease; @@ -194,7 +179,7 @@ private: // *** Sync Thread Only *** public: - virtual bool shouldStopThreadActivity() const; + WEBCORE_EXPORT bool shouldStopThreadActivity() const final; private: static void iconDatabaseSyncThreadStart(void *); @@ -219,6 +204,9 @@ private: bool wasExcludedFromBackup(); void setWasExcludedFromBackup(); + bool isOpenBesidesMainThreadCallbacks() const; + void checkClosedAfterMainThreadCallback(); + bool m_initialPruningComplete; void setIconURLForPageURLInSQLDatabase(const String&, const String&); @@ -226,7 +214,7 @@ private: void removePageURLFromSQLDatabase(const String& pageURL); int64_t getIconIDForIconURLFromSQLDatabase(const String& iconURL); int64_t addIconURLToSQLDatabase(const String&); - PassRefPtr<SharedBuffer> getImageDataForIconURLFromSQLDatabase(const String& iconURL); + RefPtr<SharedBuffer> getImageDataForIconURLFromSQLDatabase(const String& iconURL); void removeIconFromSQLDatabase(const String& iconURL); void writeIconSnapshotToSQLDatabase(const IconSnapshot&); @@ -237,30 +225,29 @@ private: void dispatchDidImportIconDataForPageURLOnMainThread(const String&); void dispatchDidRemoveAllIconsOnMainThread(); void dispatchDidFinishURLImportOnMainThread(); + std::atomic<uint32_t> m_mainThreadCallbackCount; // The client is set by the main thread before the thread starts, and from then on is only used by the sync thread IconDatabaseClient* m_client; SQLiteDatabase m_syncDB; - OwnPtr<SQLiteStatement> m_setIconIDForPageURLStatement; - OwnPtr<SQLiteStatement> m_removePageURLStatement; - OwnPtr<SQLiteStatement> m_getIconIDForIconURLStatement; - OwnPtr<SQLiteStatement> m_getImageDataForIconURLStatement; - OwnPtr<SQLiteStatement> m_addIconToIconInfoStatement; - OwnPtr<SQLiteStatement> m_addIconToIconDataStatement; - OwnPtr<SQLiteStatement> m_getImageDataStatement; - OwnPtr<SQLiteStatement> m_deletePageURLsForIconURLStatement; - OwnPtr<SQLiteStatement> m_deleteIconFromIconInfoStatement; - OwnPtr<SQLiteStatement> m_deleteIconFromIconDataStatement; - OwnPtr<SQLiteStatement> m_updateIconInfoStatement; - OwnPtr<SQLiteStatement> m_updateIconDataStatement; - OwnPtr<SQLiteStatement> m_setIconInfoStatement; - OwnPtr<SQLiteStatement> m_setIconDataStatement; + std::unique_ptr<SQLiteStatement> m_setIconIDForPageURLStatement; + std::unique_ptr<SQLiteStatement> m_removePageURLStatement; + std::unique_ptr<SQLiteStatement> m_getIconIDForIconURLStatement; + std::unique_ptr<SQLiteStatement> m_getImageDataForIconURLStatement; + std::unique_ptr<SQLiteStatement> m_addIconToIconInfoStatement; + std::unique_ptr<SQLiteStatement> m_addIconToIconDataStatement; + std::unique_ptr<SQLiteStatement> m_getImageDataStatement; + std::unique_ptr<SQLiteStatement> m_deletePageURLsForIconURLStatement; + std::unique_ptr<SQLiteStatement> m_deleteIconFromIconInfoStatement; + std::unique_ptr<SQLiteStatement> m_deleteIconFromIconDataStatement; + std::unique_ptr<SQLiteStatement> m_updateIconInfoStatement; + std::unique_ptr<SQLiteStatement> m_updateIconDataStatement; + std::unique_ptr<SQLiteStatement> m_setIconInfoStatement; + std::unique_ptr<SQLiteStatement> m_setIconDataStatement; }; #endif // !ENABLE(ICONDATABASE) } // namespace WebCore - -#endif // IconDatabase_h diff --git a/Source/WebCore/loader/icon/IconDatabaseBase.cpp b/Source/WebCore/loader/icon/IconDatabaseBase.cpp index 51ccb3b27..4c6931071 100644 --- a/Source/WebCore/loader/icon/IconDatabaseBase.cpp +++ b/Source/WebCore/loader/icon/IconDatabaseBase.cpp @@ -10,10 +10,10 @@ * 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 COMPUTER, INC. ``AS IS'' AND ANY + * 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 COMPUTER, INC. OR + * 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 @@ -47,7 +47,7 @@ bool IconDatabaseBase::open(const String&, const String&) return false; } -static IconDatabaseBase* vmbase = 0; +static IconDatabaseBase* vmbase = nullptr; // Functions to get/set the global icon database. IconDatabaseBase& iconDatabase() @@ -55,7 +55,7 @@ IconDatabaseBase& iconDatabase() if (vmbase) return *vmbase; - static IconDatabaseBase* defaultDatabase = 0; + static IconDatabaseBase* defaultDatabase = nullptr; if (!defaultDatabase) defaultDatabase = new IconDatabase; diff --git a/Source/WebCore/loader/icon/IconDatabaseBase.h b/Source/WebCore/loader/icon/IconDatabaseBase.h index e1f63af94..d4051b936 100644 --- a/Source/WebCore/loader/icon/IconDatabaseBase.h +++ b/Source/WebCore/loader/icon/IconDatabaseBase.h @@ -10,10 +10,10 @@ * 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 COMPUTER, INC. ``AS IS'' AND ANY + * 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 COMPUTER, INC. OR + * 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 @@ -23,15 +23,12 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef IconDatabaseBase_h -#define IconDatabaseBase_h - -#include "ImageSource.h" -#include "SharedBuffer.h" +#pragma once +#include "NativeImage.h" #include <wtf/Forward.h> #include <wtf/Noncopyable.h> -#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> namespace WebCore { @@ -39,12 +36,9 @@ class DocumentLoader; class IconDatabaseClient; class Image; class IntSize; +class SharedBuffer; -enum IconLoadDecision { - IconLoadYes, - IconLoadNo, - IconLoadUnknown -}; +enum IconLoadDecision { IconLoadYes, IconLoadNo, IconLoadUnknown }; class CallbackBase : public RefCounted<CallbackBase> { public: @@ -79,9 +73,9 @@ class EnumCallback : public CallbackBase { public: typedef void (*CallbackFunction)(EnumType, void*); - static PassRefPtr<EnumCallback> create(void* context, CallbackFunction callback) + static Ref<EnumCallback> create(void* context, CallbackFunction callback) { - return adoptRef(new EnumCallback(context, callback)); + return adoptRef(*new EnumCallback(context, callback)); } virtual ~EnumCallback() @@ -94,12 +88,12 @@ public: if (!m_callback) return; m_callback(result, context()); - m_callback = 0; + m_callback = nullptr; } void invalidate() { - m_callback = 0; + m_callback = nullptr; } private: @@ -118,9 +112,9 @@ class ObjectCallback : public CallbackBase { public: typedef void (*CallbackFunction)(ObjectType, void*); - static PassRefPtr<ObjectCallback> create(void* context, CallbackFunction callback) + static Ref<ObjectCallback> create(void* context, CallbackFunction callback) { - return adoptRef(new ObjectCallback(context, callback)); + return adoptRef(*new ObjectCallback(context, callback)); } virtual ~ObjectCallback() @@ -133,12 +127,12 @@ public: if (!m_callback) return; m_callback(result, context()); - m_callback = 0; + m_callback = nullptr; } - + void invalidate() { - m_callback = 0; + m_callback = nullptr; } private: @@ -152,46 +146,42 @@ private: CallbackFunction m_callback; }; -typedef EnumCallback<IconLoadDecision> IconLoadDecisionCallback; -typedef ObjectCallback<SharedBuffer*> IconDataCallback; +using IconLoadDecisionCallback = EnumCallback<IconLoadDecision>; +using IconDataCallback = ObjectCallback<SharedBuffer*>; -class IconDatabaseBase { +class WEBCORE_EXPORT IconDatabaseBase { WTF_MAKE_NONCOPYABLE(IconDatabaseBase); -protected: - IconDatabaseBase() { } - public: virtual ~IconDatabaseBase() { } - // Used internally by WebCore virtual bool isEnabled() const { return false; } - + virtual void retainIconForPageURL(const String&) { } virtual void releaseIconForPageURL(const String&) { } - virtual void setIconURLForPageURL(const String&, const String&) { } - virtual void setIconDataForIconURL(PassRefPtr<SharedBuffer>, const String&) { } + virtual void setIconURLForPageURL(const String& /*iconURL*/, const String& /*pageURL*/) { } + virtual void setIconDataForIconURL(SharedBuffer*, const String& /*iconURL*/) { } // Synchronous calls used internally by WebCore. // Usage should be replaced by asynchronous calls. virtual String synchronousIconURLForPageURL(const String&); virtual bool synchronousIconDataKnownForIconURL(const String&) { return false; } virtual IconLoadDecision synchronousLoadDecisionForIconURL(const String&, DocumentLoader*) { return IconLoadNo; } - virtual Image* synchronousIconForPageURL(const String&, const IntSize&) { return 0; } - virtual PassNativeImagePtr synchronousNativeIconForPageURL(const String&, const IntSize&) { return 0; } + virtual Image* synchronousIconForPageURL(const String&, const IntSize&) { return nullptr; } + virtual NativeImagePtr synchronousNativeIconForPageURL(const String&, const IntSize&) { return nullptr; } // Asynchronous calls we should use to replace the above when supported. virtual bool supportsAsynchronousMode() { return false; } - virtual void loadDecisionForIconURL(const String&, PassRefPtr<IconLoadDecisionCallback>) { } - virtual void iconDataForIconURL(const String&, PassRefPtr<IconDataCallback>) { } - + virtual void loadDecisionForIconURL(const String&, IconLoadDecisionCallback&) { } + virtual void iconDataForIconURL(const String&, IconDataCallback&) { } // Used within one or more WebKit ports. // We should try to remove these dependencies from the IconDatabaseBase class. + virtual void setEnabled(bool) { } - virtual Image* defaultIcon(const IntSize&) { return 0; } + virtual Image* defaultIcon(const IntSize&) { return nullptr; } virtual size_t pageURLMappingCount() { return 0; } virtual size_t retainedPageURLCount() { return 0; } @@ -206,17 +196,17 @@ public: virtual void setPrivateBrowsingEnabled(bool) { } virtual void setClient(IconDatabaseClient*) { } - + virtual bool isOpen() const { return false; } virtual String databasePath() const; +protected: + IconDatabaseBase() = default; }; // Functions to get/set the global icon database. -IconDatabaseBase& iconDatabase(); -void setGlobalIconDatabase(IconDatabaseBase*); +WEBCORE_EXPORT IconDatabaseBase& iconDatabase(); +WEBCORE_EXPORT void setGlobalIconDatabase(IconDatabaseBase*); bool documentCanHaveIcon(const String&); } // namespace WebCore - -#endif // IconDatabaseBase_h diff --git a/Source/WebCore/loader/icon/IconDatabaseClient.h b/Source/WebCore/loader/icon/IconDatabaseClient.h index 70494ec11..33e5413a8 100644 --- a/Source/WebCore/loader/icon/IconDatabaseClient.h +++ b/Source/WebCore/loader/icon/IconDatabaseClient.h @@ -10,7 +10,7 @@ * 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. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * 3. Neither the name of Apple Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * @@ -26,8 +26,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef IconDatabaseClient_h -#define IconDatabaseClient_h +#pragma once #include <wtf/Forward.h> @@ -42,8 +41,7 @@ public: virtual void didChangeIconForPageURL(const String&) = 0; virtual void didRemoveAllIcons() = 0; virtual void didFinishURLImport() = 0; + virtual void didClose() { } }; } // namespace WebCore - -#endif diff --git a/Source/WebCore/loader/icon/IconLoader.cpp b/Source/WebCore/loader/icon/IconLoader.cpp index 819bfb7e6..ab6385e55 100644 --- a/Source/WebCore/loader/icon/IconLoader.cpp +++ b/Source/WebCore/loader/icon/IconLoader.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,10 +10,10 @@ * 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 COMPUTER, INC. ``AS IS'' AND ANY + * 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 COMPUTER, INC. OR + * 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 @@ -37,14 +37,21 @@ #include "IconController.h" #include "IconDatabase.h" #include "Logging.h" -#include "ResourceBuffer.h" #include "ResourceRequest.h" +#include "SharedBuffer.h" #include <wtf/text/CString.h> namespace WebCore { IconLoader::IconLoader(Frame& frame) - : m_frame(frame) + : m_frame(&frame) + , m_url(frame.loader().icon().url()) +{ +} + +IconLoader::IconLoader(DocumentLoader& documentLoader, const URL& url) + : m_documentLoader(&documentLoader) + , m_url(url) { } @@ -55,54 +62,83 @@ IconLoader::~IconLoader() void IconLoader::startLoading() { - if (m_resource || !m_frame.document()) + ASSERT(m_frame || m_documentLoader); + + if (m_resource) return; - CachedResourceRequest request(ResourceRequest(m_frame.loader().icon().url()), ResourceLoaderOptions(SendCallbacks, SniffContent, BufferData, DoNotAllowStoredCredentials, DoNotAskClientForAnyCredentials, DoSecurityCheck, UseDefaultOriginRestrictionsForType)); + if (m_frame && !m_frame->document()) + return; + + + if (m_documentLoader && !m_documentLoader->frame()) + return; + + ResourceRequest resourceRequest = m_documentLoader ? m_url : m_frame->loader().icon().url(); + resourceRequest.setPriority(ResourceLoadPriority::Low); +#if !ERROR_DISABLED + // Copy this because we may want to access it after transferring the + // `resourceRequest` to the `request`. If we don't, then the LOG_ERROR + // below won't print a URL. + auto resourceRequestURL = resourceRequest.url(); +#endif + + // ContentSecurityPolicyImposition::DoPolicyCheck is a placeholder value. It does not affect the request since Content Security Policy does not apply to raw resources. + CachedResourceRequest request(WTFMove(resourceRequest), ResourceLoaderOptions(SendCallbacks, SniffContent, BufferData, DoNotAllowStoredCredentials, ClientCredentialPolicy::CannotAskClientForCredentials, FetchOptions::Credentials::Omit, DoSecurityCheck, FetchOptions::Mode::NoCors, DoNotIncludeCertificateInfo, ContentSecurityPolicyImposition::DoPolicyCheck, DefersLoadingPolicy::AllowDefersLoading, CachingPolicy::AllowCaching)); - request.mutableResourceRequest().setPriority(ResourceLoadPriorityLow); request.setInitiator(cachedResourceRequestInitiators().icon); - m_resource = m_frame.document()->cachedResourceLoader()->requestRawResource(request); + auto* frame = m_frame ? m_frame : m_documentLoader->frame(); + m_resource = frame->document()->cachedResourceLoader().requestRawResource(WTFMove(request)); if (m_resource) - m_resource->addClient(this); + m_resource->addClient(*this); else - LOG_ERROR("Failed to start load for icon at url %s", m_frame.loader().icon().url().string().ascii().data()); + LOG_ERROR("Failed to start load for icon at url %s", resourceRequestURL.string().ascii().data()); } void IconLoader::stopLoading() { if (m_resource) { - m_resource->removeClient(this); - m_resource = 0; + m_resource->removeClient(*this); + m_resource = nullptr; } } -void IconLoader::notifyFinished(CachedResource* resource) +void IconLoader::notifyFinished(CachedResource& resource) { - ASSERT(resource == m_resource); + ASSERT_UNUSED(resource, &resource == m_resource); // If we got a status code indicating an invalid response, then lets // ignore the data and not try to decode the error page as an icon. - RefPtr<ResourceBuffer> data = resource->resourceBuffer(); - int status = resource->response().httpStatusCode(); + auto* data = m_resource->resourceBuffer(); + int status = m_resource->response().httpStatusCode(); if (status && (status < 200 || status > 299)) - data = 0; + data = nullptr; static const char pdfMagicNumber[] = "%PDF"; static unsigned pdfMagicNumberLength = sizeof(pdfMagicNumber) - 1; if (data && data->size() >= pdfMagicNumberLength && !memcmp(data->data(), pdfMagicNumber, pdfMagicNumberLength)) { - LOG(IconDatabase, "IconLoader::finishLoading() - Ignoring icon at %s because it appears to be a PDF", resource->url().string().ascii().data()); - data = 0; + LOG(IconDatabase, "IconLoader::finishLoading() - Ignoring icon at %s because it appears to be a PDF", m_resource->url().string().ascii().data()); + data = nullptr; + } + + LOG(IconDatabase, "IconLoader::finishLoading() - Committing iconURL %s to database", m_resource->url().string().ascii().data()); + + if (!m_frame) { + // DocumentLoader::finishedLoadingIcon destroys this IconLoader as it finishes. This will automatically + // trigger IconLoader::stopLoading() during destruction, so we should just return here. + m_documentLoader->finishedLoadingIcon(*this, data); + return; } - LOG(IconDatabase, "IconLoader::finishLoading() - Committing iconURL %s to database", resource->url().string().ascii().data()); - m_frame.loader().icon().commitToDatabase(resource->url()); + m_frame->loader().icon().commitToDatabase(m_resource->url()); + // Setting the icon data only after committing to the database ensures that the data is // kept in memory (so it does not have to be read from the database asynchronously), since // there is a page URL referencing it. - iconDatabase().setIconDataForIconURL(data ? data->sharedBuffer() : 0, resource->url().string()); - m_frame.loader().client().dispatchDidReceiveIcon(); + iconDatabase().setIconDataForIconURL(data, m_resource->url().string()); + m_frame->loader().client().dispatchDidReceiveIcon(); + stopLoading(); } diff --git a/Source/WebCore/loader/icon/IconLoader.h b/Source/WebCore/loader/icon/IconLoader.h index 2fb79dc34..2de53e8e2 100644 --- a/Source/WebCore/loader/icon/IconLoader.h +++ b/Source/WebCore/loader/icon/IconLoader.h @@ -10,49 +10,50 @@ * 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 COMPUTER, INC. ``AS IS'' AND ANY + * 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 COMPUTER, INC. OR + * 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. + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef IconLoader_h -#define IconLoader_h +#pragma once #include "CachedRawResourceClient.h" #include "CachedResourceHandle.h" +#include "URL.h" #include <wtf/Forward.h> #include <wtf/Noncopyable.h> -#include <wtf/RefPtr.h> namespace WebCore { class CachedRawResource; +class DocumentLoader; class Frame; class IconLoader final : private CachedRawResourceClient { WTF_MAKE_NONCOPYABLE(IconLoader); WTF_MAKE_FAST_ALLOCATED; public: explicit IconLoader(Frame&); + IconLoader(DocumentLoader&, const URL&); virtual ~IconLoader(); void startLoading(); void stopLoading(); private: - virtual void notifyFinished(CachedResource*) override; + void notifyFinished(CachedResource&) final; - Frame& m_frame; + Frame* m_frame { nullptr }; + DocumentLoader* m_documentLoader { nullptr }; + URL m_url; CachedResourceHandle<CachedRawResource> m_resource; }; } // namespace WebCore - -#endif diff --git a/Source/WebCore/loader/icon/IconRecord.cpp b/Source/WebCore/loader/icon/IconRecord.cpp index 7e90d8e8c..b20c26a32 100644 --- a/Source/WebCore/loader/icon/IconRecord.cpp +++ b/Source/WebCore/loader/icon/IconRecord.cpp @@ -10,7 +10,7 @@ * 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. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * 3. Neither the name of Apple Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * @@ -62,16 +62,16 @@ Image* IconRecord::image(const IntSize&) return m_image.get(); } -void IconRecord::setImageData(PassRefPtr<SharedBuffer> data) +void IconRecord::setImageData(RefPtr<SharedBuffer>&& data) { // It's okay to delete the raw image here. Any existing clients using this icon will be // managing an image that was created with a copy of this raw image data. m_image = BitmapImage::create(); // Copy the provided data into the buffer of the new Image object. - if (!m_image->setData(data, true)) { + if (!m_image->setData(WTFMove(data), true)) { LOG(IconDatabase, "Manual image data for iconURL '%s' FAILED - it was probably invalid image data", m_iconURL.ascii().data()); - m_image.clear(); + m_image = nullptr; } m_dataSet = true; diff --git a/Source/WebCore/loader/icon/IconRecord.h b/Source/WebCore/loader/icon/IconRecord.h index e5a47f76e..f2105a39a 100644 --- a/Source/WebCore/loader/icon/IconRecord.h +++ b/Source/WebCore/loader/icon/IconRecord.h @@ -10,7 +10,7 @@ * 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. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * 3. Neither the name of Apple Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * @@ -26,13 +26,11 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef IconRecord_h -#define IconRecord_h +#pragma once #include "PageURLRecord.h" #include "SharedBuffer.h" #include <wtf/HashSet.h> -#include <wtf/OwnPtr.h> #include <wtf/RefCounted.h> #include <wtf/text/StringHash.h> #include <wtf/text/WTFString.h> @@ -75,16 +73,16 @@ private: class IconRecord : public RefCounted<IconRecord> { friend class PageURLRecord; public: - static PassRefPtr<IconRecord> create(const String& url) + static Ref<IconRecord> create(const String& url) { - return adoptRef(new IconRecord(url)); + return adoptRef(*new IconRecord(url)); } ~IconRecord(); time_t getTimestamp() { return m_stamp; } void setTimestamp(time_t stamp) { m_stamp = stamp; } - void setImageData(PassRefPtr<SharedBuffer> data); + void setImageData(RefPtr<SharedBuffer>&&); Image* image(const IntSize&); String iconURL() { return m_iconURL; } @@ -119,7 +117,4 @@ private: // SizeImageMap m_images; }; - } //namespace WebCore - -#endif diff --git a/Source/WebCore/loader/icon/PageURLRecord.cpp b/Source/WebCore/loader/icon/PageURLRecord.cpp index 09d649f83..99dded8f2 100644 --- a/Source/WebCore/loader/icon/PageURLRecord.cpp +++ b/Source/WebCore/loader/icon/PageURLRecord.cpp @@ -10,7 +10,7 @@ * 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. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * 3. Neither the name of Apple Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * @@ -35,29 +35,29 @@ namespace WebCore { PageURLRecord::PageURLRecord(const String& pageURL) : m_pageURL(pageURL) - , m_retainCount(0) { } PageURLRecord::~PageURLRecord() { - setIconRecord(0); + if (m_iconRecord) + m_iconRecord->m_retainingPageURLs.remove(m_pageURL); } -void PageURLRecord::setIconRecord(PassRefPtr<IconRecord> icon) +void PageURLRecord::setIconRecord(RefPtr<IconRecord>&& icon) { if (m_iconRecord) m_iconRecord->m_retainingPageURLs.remove(m_pageURL); - - m_iconRecord = icon; - + + m_iconRecord = WTFMove(icon); + if (m_iconRecord) m_iconRecord->m_retainingPageURLs.add(m_pageURL); } PageURLSnapshot PageURLRecord::snapshot(bool forDeletion) const { - return PageURLSnapshot(m_pageURL, (m_iconRecord && !forDeletion) ? m_iconRecord->iconURL() : String()); + return { m_pageURL, (m_iconRecord && !forDeletion) ? m_iconRecord->iconURL() : String() }; } } // namespace WebCore diff --git a/Source/WebCore/loader/icon/PageURLRecord.h b/Source/WebCore/loader/icon/PageURLRecord.h index 2b33808d3..189875e32 100644 --- a/Source/WebCore/loader/icon/PageURLRecord.h +++ b/Source/WebCore/loader/icon/PageURLRecord.h @@ -10,7 +10,7 @@ * 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. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * 3. Neither the name of Apple Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * @@ -26,8 +26,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef PageURLRecord_h -#define PageURLRecord_h +#pragma once #include <wtf/Noncopyable.h> #include <wtf/RefPtr.h> @@ -62,7 +61,7 @@ public: inline String url() const { return m_pageURL; } - void setIconRecord(PassRefPtr<IconRecord>); + void setIconRecord(RefPtr<IconRecord>&&); IconRecord* iconRecord() { return m_iconRecord.get(); } PageURLSnapshot snapshot(bool forDeletion = false) const; @@ -83,13 +82,12 @@ public: return m_retainCount > 0; } - inline int retainCount() const { return m_retainCount; } + int retainCount() const { return m_retainCount; } + private: String m_pageURL; RefPtr<IconRecord> m_iconRecord; - int m_retainCount; + int m_retainCount { 0 }; }; -} - -#endif // PageURLRecord_h +} // namespace WebCore |