WebIconDatabase.cpp revision 81bc750723a18f21cd17d1b173cd2a4dda9cea6e
1/* 2 * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include "config.h" 27#include "WebKitDLL.h" 28#include "WebIconDatabase.h" 29 30#include "CFDictionaryPropertyBag.h" 31#include "COMPtr.h" 32#include "WebPreferences.h" 33#include "WebNotificationCenter.h" 34#pragma warning(push, 0) 35#include <WebCore/BitmapInfo.h> 36#include <WebCore/BString.h> 37#include <WebCore/FileSystem.h> 38#include <WebCore/IconDatabase.h> 39#include <WebCore/Image.h> 40#include <WebCore/PlatformString.h> 41#pragma warning(pop) 42#include <wtf/MainThread.h> 43#include "shlobj.h" 44 45using namespace WebCore; 46using namespace WTF; 47 48// WebIconDatabase ---------------------------------------------------------------- 49 50WebIconDatabase* WebIconDatabase::m_sharedWebIconDatabase = 0; 51 52WebIconDatabase::WebIconDatabase() 53: m_refCount(0) 54, m_deliveryRequested(false) 55{ 56 gClassCount++; 57 gClassNameCount.add("WebIconDatabase"); 58} 59 60WebIconDatabase::~WebIconDatabase() 61{ 62 gClassCount--; 63 gClassNameCount.remove("WebIconDatabase"); 64} 65 66void WebIconDatabase::init() 67{ 68 WebPreferences* standardPrefs = WebPreferences::sharedStandardPreferences(); 69 BOOL enabled = FALSE; 70 if (FAILED(standardPrefs->iconDatabaseEnabled(&enabled))) { 71 enabled = FALSE; 72 LOG_ERROR("Unable to get icon database enabled preference"); 73 } 74 iconDatabase().setEnabled(!!enabled); 75 if (!(!!enabled)) 76 return; 77 78 startUpIconDatabase(); 79} 80 81void WebIconDatabase::startUpIconDatabase() 82{ 83 WebPreferences* standardPrefs = WebPreferences::sharedStandardPreferences(); 84 85 iconDatabase().setClient(this); 86 87 BSTR prefDatabasePath = 0; 88 if (FAILED(standardPrefs->iconDatabaseLocation(&prefDatabasePath))) 89 LOG_ERROR("Unable to get icon database location preference"); 90 91 String databasePath(prefDatabasePath, SysStringLen(prefDatabasePath)); 92 SysFreeString(prefDatabasePath); 93 94 if (databasePath.isEmpty()) { 95 databasePath = localUserSpecificStorageDirectory(); 96 if (databasePath.isEmpty()) 97 LOG_ERROR("Failed to construct default icon database path"); 98 } 99 100 if (!iconDatabase().open(databasePath)) 101 LOG_ERROR("Failed to open icon database path"); 102} 103 104void WebIconDatabase::shutDownIconDatabase() 105{ 106} 107 108WebIconDatabase* WebIconDatabase::createInstance() 109{ 110 WebIconDatabase* instance = new WebIconDatabase(); 111 instance->AddRef(); 112 return instance; 113} 114 115WebIconDatabase* WebIconDatabase::sharedWebIconDatabase() 116{ 117 if (m_sharedWebIconDatabase) { 118 m_sharedWebIconDatabase->AddRef(); 119 return m_sharedWebIconDatabase; 120 } 121 m_sharedWebIconDatabase = createInstance(); 122 m_sharedWebIconDatabase->init(); 123 return m_sharedWebIconDatabase; 124} 125 126// IUnknown ------------------------------------------------------------------- 127 128HRESULT STDMETHODCALLTYPE WebIconDatabase::QueryInterface(REFIID riid, void** ppvObject) 129{ 130 *ppvObject = 0; 131 if (IsEqualGUID(riid, IID_IUnknown)) 132 *ppvObject = static_cast<IWebIconDatabase*>(this); 133 else if (IsEqualGUID(riid, IID_IWebIconDatabase)) 134 *ppvObject = static_cast<IWebIconDatabase*>(this); 135 else 136 return E_NOINTERFACE; 137 138 AddRef(); 139 return S_OK; 140} 141 142ULONG STDMETHODCALLTYPE WebIconDatabase::AddRef(void) 143{ 144 return ++m_refCount; 145} 146 147ULONG STDMETHODCALLTYPE WebIconDatabase::Release(void) 148{ 149 ULONG newRef = --m_refCount; 150 if (!newRef) 151 delete(this); 152 153 return newRef; 154} 155 156// IWebIconDatabase -------------------------------------------------------------------- 157 158HRESULT STDMETHODCALLTYPE WebIconDatabase::sharedIconDatabase( 159 /* [retval][out] */ IWebIconDatabase** result) 160{ 161 *result = sharedWebIconDatabase(); 162 return S_OK; 163} 164 165HRESULT STDMETHODCALLTYPE WebIconDatabase::iconForURL( 166 /* [in] */ BSTR url, 167 /* [optional][in] */ LPSIZE size, 168 /* [optional][in] */ BOOL /*cache*/, 169 /* [retval][out] */ OLE_HANDLE* bitmap) 170{ 171 IntSize intSize(*size); 172 173 Image* icon = 0; 174 if (url) 175 icon = iconDatabase().iconForPageURL(String(url, SysStringLen(url)), intSize); 176 177 // Make sure we check for the case of an "empty image" 178 if (icon && icon->width()) { 179 *bitmap = (OLE_HANDLE)(ULONG64)getOrCreateSharedBitmap(size); 180 if (!icon->getHBITMAPOfSize((HBITMAP)(ULONG64)*bitmap, size)) { 181 LOG_ERROR("Failed to draw Image to HBITMAP"); 182 *bitmap = 0; 183 return E_FAIL; 184 } 185 return S_OK; 186 } 187 188 return defaultIconWithSize(size, bitmap); 189} 190 191HRESULT STDMETHODCALLTYPE WebIconDatabase::defaultIconWithSize( 192 /* [in] */ LPSIZE size, 193 /* [retval][out] */ OLE_HANDLE* result) 194{ 195 *result = (OLE_HANDLE)(ULONG64)getOrCreateDefaultIconBitmap(size); 196 return S_OK; 197} 198 199HRESULT STDMETHODCALLTYPE WebIconDatabase::retainIconForURL( 200 /* [in] */ BSTR url) 201{ 202 iconDatabase().retainIconForPageURL(String(url, SysStringLen(url))); 203 return S_OK; 204} 205 206HRESULT STDMETHODCALLTYPE WebIconDatabase::releaseIconForURL( 207 /* [in] */ BSTR url) 208{ 209 iconDatabase().releaseIconForPageURL(String(url, SysStringLen(url))); 210 return S_OK; 211} 212 213HRESULT STDMETHODCALLTYPE WebIconDatabase::removeAllIcons(void) 214{ 215 iconDatabase().removeAllIcons(); 216 return S_OK; 217} 218 219HRESULT STDMETHODCALLTYPE WebIconDatabase::delayDatabaseCleanup(void) 220{ 221 IconDatabase::delayDatabaseCleanup(); 222 return S_OK; 223} 224 225HRESULT STDMETHODCALLTYPE WebIconDatabase::allowDatabaseCleanup(void) 226{ 227 IconDatabase::allowDatabaseCleanup(); 228 return S_OK; 229} 230 231HRESULT STDMETHODCALLTYPE WebIconDatabase::iconURLForURL( 232 /* [in] */ BSTR url, 233 /* [retval][out] */ BSTR* iconURL) 234{ 235 if (!url || !iconURL) 236 return E_POINTER; 237 BString iconURLBSTR(iconDatabase().iconURLForPageURL(String(url, SysStringLen(url)))); 238 *iconURL = iconURLBSTR.release(); 239 return S_OK; 240} 241 242HRESULT STDMETHODCALLTYPE WebIconDatabase::isEnabled( 243 /* [retval][out] */ BOOL *result) 244{ 245 *result = iconDatabase().isEnabled(); 246 return S_OK; 247} 248 249HRESULT STDMETHODCALLTYPE WebIconDatabase::setEnabled( 250 /* [in] */ BOOL flag) 251{ 252 BOOL currentlyEnabled; 253 isEnabled(¤tlyEnabled); 254 if (currentlyEnabled && !flag) { 255 iconDatabase().setEnabled(false); 256 shutDownIconDatabase(); 257 } else if (!currentlyEnabled && flag) { 258 iconDatabase().setEnabled(true); 259 startUpIconDatabase(); 260 } 261 return S_OK; 262} 263 264HRESULT STDMETHODCALLTYPE WebIconDatabase::hasIconForURL( 265 /* [in] */ BSTR url, 266 /* [out][retval] */ BOOL* result) 267{ 268 if (!url || !result) 269 return E_POINTER; 270 271 String urlString(url, SysStringLen(url)); 272 273 // Passing a size parameter of 0, 0 means we don't care about the result of the image, we just 274 // want to make sure the read from disk to load the icon is kicked off. 275 iconDatabase().iconForPageURL(urlString, IntSize(0, 0)); 276 277 // Check to see if we have a non-empty icon URL for the page, and if we do, we have an icon for 278 // the page. 279 *result = !(iconDatabase().iconURLForPageURL(urlString).isEmpty()); 280 281 return S_OK; 282} 283 284HBITMAP createDIB(LPSIZE size) 285{ 286 BitmapInfo bmInfo = BitmapInfo::create(IntSize(*size)); 287 288 HDC dc = GetDC(0); 289 HBITMAP result = CreateDIBSection(dc, &bmInfo, DIB_RGB_COLORS, 0, 0, 0); 290 ReleaseDC(0, dc); 291 292 return result; 293} 294 295HBITMAP WebIconDatabase::getOrCreateSharedBitmap(LPSIZE size) 296{ 297 HBITMAP result = m_sharedIconMap.get(*size); 298 if (result) 299 return result; 300 result = createDIB(size); 301 m_sharedIconMap.set(*size, result); 302 return result; 303} 304 305HBITMAP WebIconDatabase::getOrCreateDefaultIconBitmap(LPSIZE size) 306{ 307 HBITMAP result = m_defaultIconMap.get(*size); 308 if (result) 309 return result; 310 311 result = createDIB(size); 312 313 m_defaultIconMap.set(*size, result); 314 if (!iconDatabase().defaultIcon(*size)->getHBITMAPOfSize(result, size)) { 315 LOG_ERROR("Failed to draw Image to HBITMAP"); 316 return 0; 317 } 318 return result; 319} 320 321// IconDatabaseClient 322 323void WebIconDatabase::dispatchDidRemoveAllIcons() 324{ 325 // Queueing the empty string is a special way of saying "this queued notification is the didRemoveAllIcons notification" 326 MutexLocker locker(m_notificationMutex); 327 m_notificationQueue.append(String()); 328 scheduleNotificationDelivery(); 329} 330 331void WebIconDatabase::dispatchDidAddIconForPageURL(const String& pageURL) 332{ 333 MutexLocker locker(m_notificationMutex); 334 m_notificationQueue.append(pageURL.threadsafeCopy()); 335 scheduleNotificationDelivery(); 336} 337 338void WebIconDatabase::scheduleNotificationDelivery() 339{ 340 // Caller of this method must hold the m_notificationQueue lock 341 ASSERT(!m_notificationMutex.tryLock()); 342 343 if (!m_deliveryRequested) { 344 m_deliveryRequested = true; 345 callOnMainThread(deliverNotifications, 0); 346 } 347} 348 349BSTR WebIconDatabase::iconDatabaseDidAddIconNotification() 350{ 351 static BSTR didAddIconName = SysAllocString(WebIconDatabaseDidAddIconNotification); 352 return didAddIconName; 353} 354 355CFStringRef WebIconDatabase::iconDatabaseNotificationUserInfoURLKey() 356{ 357 static CFStringRef iconUserInfoURLKey = String(WebIconNotificationUserInfoURLKey).createCFString(); 358 return iconUserInfoURLKey; 359} 360 361BSTR WebIconDatabase::iconDatabaseDidRemoveAllIconsNotification() 362{ 363 static BSTR didRemoveAllIconsName = SysAllocString(WebIconDatabaseDidRemoveAllIconsNotification); 364 return didRemoveAllIconsName; 365} 366 367static void postDidRemoveAllIconsNotification(WebIconDatabase* iconDB) 368{ 369 IWebNotificationCenter* notifyCenter = WebNotificationCenter::defaultCenterInternal(); 370 notifyCenter->postNotificationName(WebIconDatabase::iconDatabaseDidRemoveAllIconsNotification(), static_cast<IWebIconDatabase*>(iconDB), 0); 371} 372 373static void postDidAddIconNotification(const String& pageURL, WebIconDatabase* iconDB) 374{ 375 RetainPtr<CFMutableDictionaryRef> dictionary(AdoptCF, 376 CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); 377 378 RetainPtr<CFStringRef> url(AdoptCF, pageURL.createCFString()); 379 CFDictionaryAddValue(dictionary.get(), WebIconDatabase::iconDatabaseNotificationUserInfoURLKey(), url.get()); 380 381 COMPtr<CFDictionaryPropertyBag> userInfo = CFDictionaryPropertyBag::createInstance(); 382 userInfo->setDictionary(dictionary.get()); 383 384 IWebNotificationCenter* notifyCenter = WebNotificationCenter::defaultCenterInternal(); 385 notifyCenter->postNotificationName(WebIconDatabase::iconDatabaseDidAddIconNotification(), static_cast<IWebIconDatabase*>(iconDB), userInfo.get()); 386} 387 388void WebIconDatabase::deliverNotifications(void*) 389{ 390 ASSERT(m_sharedWebIconDatabase); 391 if (!m_sharedWebIconDatabase) 392 return; 393 394 ASSERT(m_sharedWebIconDatabase->m_deliveryRequested); 395 396 Vector<String> queue; 397 { 398 MutexLocker locker(m_sharedWebIconDatabase->m_notificationMutex); 399 queue.swap(m_sharedWebIconDatabase->m_notificationQueue); 400 m_sharedWebIconDatabase->m_deliveryRequested = false; 401 } 402 403 for (unsigned i = 0; i < queue.size(); ++i) { 404 if (queue[i].isNull()) 405 postDidRemoveAllIconsNotification(m_sharedWebIconDatabase); 406 else 407 postDidAddIconNotification(queue[i], m_sharedWebIconDatabase); 408 } 409} 410