Home | History | Annotate | Download | only in win
      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 
     45 using namespace WebCore;
     46 using namespace WTF;
     47 
     48 // WebIconDatabase ----------------------------------------------------------------
     49 
     50 WebIconDatabase* WebIconDatabase::m_sharedWebIconDatabase = 0;
     51 
     52 WebIconDatabase::WebIconDatabase()
     53 : m_refCount(0)
     54 , m_deliveryRequested(false)
     55 {
     56     gClassCount++;
     57     gClassNameCount.add("WebIconDatabase");
     58 }
     59 
     60 WebIconDatabase::~WebIconDatabase()
     61 {
     62     gClassCount--;
     63     gClassNameCount.remove("WebIconDatabase");
     64 }
     65 
     66 void 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 
     81 void 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 
    104 void WebIconDatabase::shutDownIconDatabase()
    105 {
    106 }
    107 
    108 WebIconDatabase* WebIconDatabase::createInstance()
    109 {
    110     WebIconDatabase* instance = new WebIconDatabase();
    111     instance->AddRef();
    112     return instance;
    113 }
    114 
    115 WebIconDatabase* 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 
    128 HRESULT 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 
    142 ULONG STDMETHODCALLTYPE WebIconDatabase::AddRef(void)
    143 {
    144     return ++m_refCount;
    145 }
    146 
    147 ULONG 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 
    158 HRESULT STDMETHODCALLTYPE WebIconDatabase::sharedIconDatabase(
    159         /* [retval][out] */ IWebIconDatabase** result)
    160 {
    161     *result = sharedWebIconDatabase();
    162     return S_OK;
    163 }
    164 
    165 HRESULT 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 
    191 HRESULT 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 
    199 HRESULT STDMETHODCALLTYPE WebIconDatabase::retainIconForURL(
    200         /* [in] */ BSTR url)
    201 {
    202     iconDatabase()->retainIconForPageURL(String(url, SysStringLen(url)));
    203     return S_OK;
    204 }
    205 
    206 HRESULT STDMETHODCALLTYPE WebIconDatabase::releaseIconForURL(
    207         /* [in] */ BSTR url)
    208 {
    209     iconDatabase()->releaseIconForPageURL(String(url, SysStringLen(url)));
    210     return S_OK;
    211 }
    212 
    213 HRESULT STDMETHODCALLTYPE WebIconDatabase::removeAllIcons(void)
    214 {
    215     iconDatabase()->removeAllIcons();
    216     return S_OK;
    217 }
    218 
    219 HRESULT STDMETHODCALLTYPE WebIconDatabase::delayDatabaseCleanup(void)
    220 {
    221     IconDatabase::delayDatabaseCleanup();
    222     return S_OK;
    223 }
    224 
    225 HRESULT STDMETHODCALLTYPE WebIconDatabase::allowDatabaseCleanup(void)
    226 {
    227     IconDatabase::allowDatabaseCleanup();
    228     return S_OK;
    229 }
    230 
    231 HRESULT 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 
    242 HRESULT STDMETHODCALLTYPE WebIconDatabase::isEnabled(
    243         /* [retval][out] */ BOOL *result)
    244 {
    245     *result = iconDatabase()->isEnabled();
    246     return S_OK;
    247 }
    248 
    249 HRESULT STDMETHODCALLTYPE WebIconDatabase::setEnabled(
    250         /* [in] */ BOOL flag)
    251 {
    252     BOOL currentlyEnabled;
    253     isEnabled(&currentlyEnabled);
    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 
    264 HBITMAP createDIB(LPSIZE size)
    265 {
    266     BitmapInfo bmInfo = BitmapInfo::create(IntSize(*size));
    267 
    268     HDC dc = GetDC(0);
    269     HBITMAP result = CreateDIBSection(dc, &bmInfo, DIB_RGB_COLORS, 0, 0, 0);
    270     ReleaseDC(0, dc);
    271 
    272     return result;
    273 }
    274 
    275 HBITMAP WebIconDatabase::getOrCreateSharedBitmap(LPSIZE size)
    276 {
    277     HBITMAP result = m_sharedIconMap.get(*size);
    278     if (result)
    279         return result;
    280     result = createDIB(size);
    281     m_sharedIconMap.set(*size, result);
    282     return result;
    283 }
    284 
    285 HBITMAP WebIconDatabase::getOrCreateDefaultIconBitmap(LPSIZE size)
    286 {
    287     HBITMAP result = m_defaultIconMap.get(*size);
    288     if (result)
    289         return result;
    290 
    291     result = createDIB(size);
    292 
    293     m_defaultIconMap.set(*size, result);
    294     if (!iconDatabase()->defaultIcon(*size)->getHBITMAPOfSize(result, size)) {
    295         LOG_ERROR("Failed to draw Image to HBITMAP");
    296         return 0;
    297     }
    298     return result;
    299 }
    300 
    301 // IconDatabaseClient
    302 
    303 void WebIconDatabase::dispatchDidRemoveAllIcons()
    304 {
    305     // Queueing the empty string is a special way of saying "this queued notification is the didRemoveAllIcons notification"
    306     MutexLocker locker(m_notificationMutex);
    307     m_notificationQueue.append(String());
    308     scheduleNotificationDelivery();
    309 }
    310 
    311 void WebIconDatabase::dispatchDidAddIconForPageURL(const String& pageURL)
    312 {
    313     MutexLocker locker(m_notificationMutex);
    314     m_notificationQueue.append(pageURL.threadsafeCopy());
    315     scheduleNotificationDelivery();
    316 }
    317 
    318 void WebIconDatabase::scheduleNotificationDelivery()
    319 {
    320     // Caller of this method must hold the m_notificationQueue lock
    321     ASSERT(!m_notificationMutex.tryLock());
    322 
    323     if (!m_deliveryRequested) {
    324         m_deliveryRequested = true;
    325         callOnMainThread(deliverNotifications, 0);
    326     }
    327 }
    328 
    329 BSTR WebIconDatabase::iconDatabaseDidAddIconNotification()
    330 {
    331     static BSTR didAddIconName = SysAllocString(WebIconDatabaseDidAddIconNotification);
    332     return didAddIconName;
    333 }
    334 
    335 CFStringRef WebIconDatabase::iconDatabaseNotificationUserInfoURLKey()
    336 {
    337     static CFStringRef iconUserInfoURLKey = String(WebIconNotificationUserInfoURLKey).createCFString();
    338     return iconUserInfoURLKey;
    339 }
    340 
    341 BSTR WebIconDatabase::iconDatabaseDidRemoveAllIconsNotification()
    342 {
    343     static BSTR didRemoveAllIconsName = SysAllocString(WebIconDatabaseDidRemoveAllIconsNotification);
    344     return didRemoveAllIconsName;
    345 }
    346 
    347 static void postDidRemoveAllIconsNotification(WebIconDatabase* iconDB)
    348 {
    349     IWebNotificationCenter* notifyCenter = WebNotificationCenter::defaultCenterInternal();
    350     notifyCenter->postNotificationName(WebIconDatabase::iconDatabaseDidRemoveAllIconsNotification(), static_cast<IWebIconDatabase*>(iconDB), 0);
    351 }
    352 
    353 static void postDidAddIconNotification(const String& pageURL, WebIconDatabase* iconDB)
    354 {
    355     RetainPtr<CFMutableDictionaryRef> dictionary(AdoptCF,
    356     CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
    357 
    358     RetainPtr<CFStringRef> url(AdoptCF, pageURL.createCFString());
    359     CFDictionaryAddValue(dictionary.get(), WebIconDatabase::iconDatabaseNotificationUserInfoURLKey(), url.get());
    360 
    361     COMPtr<CFDictionaryPropertyBag> userInfo = CFDictionaryPropertyBag::createInstance();
    362     userInfo->setDictionary(dictionary.get());
    363 
    364     IWebNotificationCenter* notifyCenter = WebNotificationCenter::defaultCenterInternal();
    365     notifyCenter->postNotificationName(WebIconDatabase::iconDatabaseDidAddIconNotification(), static_cast<IWebIconDatabase*>(iconDB), userInfo.get());
    366 }
    367 
    368 void WebIconDatabase::deliverNotifications(void*)
    369 {
    370     ASSERT(m_sharedWebIconDatabase);
    371     if (!m_sharedWebIconDatabase)
    372         return;
    373 
    374     ASSERT(m_sharedWebIconDatabase->m_deliveryRequested);
    375 
    376     Vector<String> queue;
    377     {
    378         MutexLocker locker(m_sharedWebIconDatabase->m_notificationMutex);
    379         queue.swap(m_sharedWebIconDatabase->m_notificationQueue);
    380         m_sharedWebIconDatabase->m_deliveryRequested = false;
    381     }
    382 
    383     for (unsigned i = 0; i < queue.size(); ++i) {
    384         if (queue[i].isNull())
    385             postDidRemoveAllIconsNotification(m_sharedWebIconDatabase);
    386         else
    387             postDidAddIconNotification(queue[i], m_sharedWebIconDatabase);
    388     }
    389 }
    390