📄 icondatabase.cpp
字号:
/* * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. * Copyright (C) 2007 Justin Haygood (jhaygood@reaktix.com) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, 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 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */#include "config.h"#include "IconDatabase.h"#include "AutodrainedPool.h"#include "CString.h"#include "DocumentLoader.h"#include "FileSystem.h"#include "IconDatabaseClient.h"#include "IconRecord.h"#include "Image.h"#include "IntSize.h"#include "KURL.h"#include "Logging.h"#include "PageURLRecord.h"#include "SQLiteStatement.h"#include "SQLiteTransaction.h"#include <runtime/InitializeThreading.h>#include <wtf/CurrentTime.h>#include <wtf/MainThread.h>#include <wtf/StdLibExtras.h>#if PLATFORM(WIN_OS)#include <windows.h>#include <winbase.h>#include <shlobj.h>#else#include <sys/stat.h>#endif#if PLATFORM(DARWIN)#include <pthread.h>#endif// 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())// For methods that are meant to support the sync thread ONLY#define IS_ICON_SYNC_THREAD() (m_syncThread == currentThread())#define ASSERT_ICON_SYNC_THREAD() ASSERT(IS_ICON_SYNC_THREAD())#if PLATFORM(QT)#define CAN_THEME_URL_ICON#endifnamespace WebCore {static IconDatabase* sharedIconDatabase = 0;static int databaseCleanupCounter = 0;// This version number is in the DB and marks the current generation of the schema// Currently, a mismatched schema causes the DB to be wiped and reset. This isn't // so bad during development but in the future, we would need to write a conversion// function to advance older released schemas to "current"const int currentDatabaseVersion = 6;// Icons expire once every 4 daysconst int iconExpirationTime = 60*60*24*4; const int updateTimerDelay = 5; static bool checkIntegrityOnOpen = false;#ifndef NDEBUGstatic String urlForLogging(const String& url){ static unsigned urlTruncationLength = 120; if (url.length() < urlTruncationLength) return url; return url.substring(0, urlTruncationLength) + "...";}#endifstatic IconDatabaseClient* defaultClient() { static IconDatabaseClient* defaultClient = new IconDatabaseClient(); return defaultClient;}IconDatabase* iconDatabase(){ if (!sharedIconDatabase) { JSC::initializeThreading(); sharedIconDatabase = new IconDatabase; } return sharedIconDatabase;}// ************************// *** Main Thread Only ***// ************************void IconDatabase::setClient(IconDatabaseClient* client){ // We don't allow a null client, because we never null check it anywhere in this code // Also don't allow a client change after the thread has already began // (setting the client should occur before the database is opened) ASSERT(client); ASSERT(!m_syncThreadRunning); if (!client || m_syncThreadRunning) return; m_client = client;}bool IconDatabase::open(const String& databasePath){ ASSERT_NOT_SYNC_THREAD(); if (!m_isEnabled) return false; if (isOpen()) { LOG_ERROR("Attempt to reopen the IconDatabase which is already open. Must close it first."); return false; } m_databaseDirectory = databasePath.copy(); // Formulate the full path for the database file m_completeDatabasePath = pathByAppendingComponent(m_databaseDirectory, defaultDatabaseFilename()); // Lock here as well as first thing in the thread so the thread doesn't actually commence until the createThread() call // completes and m_syncThreadRunning is properly set m_syncLock.lock(); m_syncThread = createThread(IconDatabase::iconDatabaseSyncThreadStart, this, "WebCore::IconDatabase"); m_syncLock.unlock(); if (!m_syncThread) return false; return true;}void IconDatabase::close(){ ASSERT_NOT_SYNC_THREAD(); if (m_syncThreadRunning) { // Set the flag to tell the sync thread to wrap it up m_threadTerminationRequested = true; // Wake up the sync thread if it's waiting wakeSyncThread(); // Wait for the sync thread to terminate waitForThreadCompletion(m_syncThread, 0); } m_syncThreadRunning = false; m_threadTerminationRequested = false; m_removeIconsRequested = false; m_syncDB.close(); ASSERT(!isOpen());}void IconDatabase::removeAllIcons(){ ASSERT_NOT_SYNC_THREAD(); if (!isOpen()) return; LOG(IconDatabase, "Requesting background thread to remove all icons"); // 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); // 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).second->setIconRecord(0); // 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); 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); m_pageURLsPendingImport.clear(); m_pageURLsInterestedInIcons.clear(); m_iconsPendingReading.clear(); m_loadersPendingDecision.clear(); } } m_removeIconsRequested = true; wakeSyncThread();}Image* IconDatabase::iconForPageURL(const String& pageURLOriginal, const IntSize& size){ ASSERT_NOT_SYNC_THREAD(); // pageURLOriginal cannot be stored without being deep copied first. // We should go our of our way to only copy it if we have to store it if (!isOpen() || pageURLOriginal.isEmpty()) return defaultIcon(size); MutexLocker locker(m_urlAndIconLock); String pageURLCopy; // Creates a null string for easy testing PageURLRecord* pageRecord = m_pageURLToRecordMap.get(pageURLOriginal); if (!pageRecord) { pageURLCopy = pageURLOriginal.copy(); pageRecord = getOrCreatePageURLRecord(pageURLCopy); } // If pageRecord is NULL, one of two things is true - // 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); // 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; } IconRecord* iconRecord = pageRecord->iconRecord(); // If the initial URL import isn't complete, it's possible to have a PageURL record without an associated icon // 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; // The only way we should *not* have an icon record is if this pageURL is retained but has no icon yet - make sure of that ASSERT(iconRecord || m_retainedPageURLs.contains(pageURLOriginal)); if (!iconRecord) return 0; // If it's a new IconRecord object that doesn't have its imageData set yet, // mark it to be read by the background thread if (iconRecord->imageDataStatus() == ImageDataStatusUnknown) { if (pageURLCopy.isNull()) pageURLCopy = pageURLOriginal.copy(); MutexLocker locker(m_pendingReadingLock); m_pageURLsInterestedInIcons.add(pageURLCopy); m_iconsPendingReading.add(iconRecord); wakeSyncThread(); return 0; } // 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; // 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. // This has *always* been the case, but in practice clients would always create some other platform specific representation of the image // and drop the raw Image*. On Mac an NSImage, and on windows drawing into an HBITMAP. // The async aspect adds a huge question - what if the image is deleted before the platform specific API has a chance to create its own // representation out of it? // If an image is read in from the icondatabase, we do *not* overwrite any image data that exists in the in-memory cache. // This is because we make the assumption that anything in memory is newer than whatever is in the database. // So the only time the data will be set from the second thread is when it is INITIALLY being read in from the database, but we would never // delete the image on the secondary thread if the image already exists. return iconRecord->image(size);}void IconDatabase::readIconForPageURLFromDisk(const String& pageURL){ // The effect of asking for an Icon for a pageURL automatically queues it to be read from disk // if it hasn't already been set in memory. The special IntSize (0, 0) is a special way of telling // that method "I don't care about the actual Image, i just want you to make sure you're getting it from disk. iconForPageURL(pageURL, IntSize(0,0));}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -