|
1 /* |
|
2 * Copyright (C) 2006, 2007 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/BString.h> |
|
36 #include <WebCore/IconDatabase.h> |
|
37 #include <WebCore/Image.h> |
|
38 #include <WebCore/PlatformString.h> |
|
39 #pragma warning(pop) |
|
40 #include "shlobj.h" |
|
41 |
|
42 using namespace WebCore; |
|
43 using namespace WTF; |
|
44 |
|
45 // WebIconDatabase ---------------------------------------------------------------- |
|
46 |
|
47 WebIconDatabase* WebIconDatabase::m_sharedWebIconDatabase = 0; |
|
48 |
|
49 WebIconDatabase::WebIconDatabase() |
|
50 : m_refCount(0) |
|
51 , m_deliveryRequested(false) |
|
52 { |
|
53 gClassCount++; |
|
54 } |
|
55 |
|
56 WebIconDatabase::~WebIconDatabase() |
|
57 { |
|
58 gClassCount--; |
|
59 } |
|
60 |
|
61 // FIXME - <rdar://problem/4721579> |
|
62 // This is code ripped directly from FileUtilities.cpp - it may be extremely useful |
|
63 // to have it in a centralized location in WebKit. But also, getting the icon database |
|
64 // path should use the WebPreferences system before it falls back to some reasonable default |
|
65 HRESULT userIconDatabasePath(String& path) |
|
66 { |
|
67 // get the path to the user's non-roaming application data folder (Example: C:\Documents and Settings\{username}\Local Settings\Application Data\) |
|
68 TCHAR appDataPath[MAX_PATH]; |
|
69 HRESULT hr = SHGetFolderPath(0, CSIDL_LOCAL_APPDATA | CSIDL_FLAG_CREATE, 0, 0, appDataPath); |
|
70 if (FAILED(hr)) |
|
71 return hr; |
|
72 |
|
73 // make the Apple Computer and WebKit subfolder |
|
74 path = String(appDataPath) + "\\Apple Computer\\"; |
|
75 |
|
76 WebCore::String appName = "WebKit"; |
|
77 CFBundleRef bundle = CFBundleGetMainBundle(); |
|
78 if (bundle) { |
|
79 CFStringRef bundleExecutable = (CFStringRef)CFBundleGetValueForInfoDictionaryKey(bundle, kCFBundleExecutableKey); |
|
80 if (bundleExecutable) |
|
81 appName = bundleExecutable; |
|
82 } |
|
83 path += appName; |
|
84 |
|
85 if (!CreateDirectory(path.charactersWithNullTermination(), 0)) { |
|
86 DWORD err = GetLastError(); |
|
87 if (err != ERROR_ALREADY_EXISTS) |
|
88 return (HRESULT_FROM_WIN32(err)); |
|
89 } |
|
90 |
|
91 return S_OK; |
|
92 } |
|
93 |
|
94 void WebIconDatabase::init() |
|
95 { |
|
96 WebPreferences* standardPrefs = WebPreferences::sharedStandardPreferences(); |
|
97 BOOL enabled = FALSE; |
|
98 if (FAILED(standardPrefs->iconDatabaseEnabled(&enabled))) { |
|
99 enabled = FALSE; |
|
100 LOG_ERROR("Unable to get icon database enabled preference"); |
|
101 } |
|
102 iconDatabase()->setEnabled(!!enabled); |
|
103 |
|
104 iconDatabase()->setClient(this); |
|
105 |
|
106 BSTR prefDatabasePath = 0; |
|
107 if (FAILED(standardPrefs->iconDatabaseLocation(&prefDatabasePath))) |
|
108 LOG_ERROR("Unable to get icon database location preference"); |
|
109 |
|
110 String databasePath(prefDatabasePath, SysStringLen(prefDatabasePath)); |
|
111 SysFreeString(prefDatabasePath); |
|
112 if (databasePath.isEmpty()) |
|
113 if (FAILED(userIconDatabasePath(databasePath))) |
|
114 LOG_ERROR("Failed to construct default icon database path"); |
|
115 |
|
116 if (!iconDatabase()->open(databasePath)) |
|
117 LOG_ERROR("Failed to open icon database path"); |
|
118 } |
|
119 |
|
120 WebIconDatabase* WebIconDatabase::createInstance() |
|
121 { |
|
122 WebIconDatabase* instance = new WebIconDatabase(); |
|
123 instance->AddRef(); |
|
124 return instance; |
|
125 } |
|
126 |
|
127 WebIconDatabase* WebIconDatabase::sharedWebIconDatabase() |
|
128 { |
|
129 if (m_sharedWebIconDatabase) { |
|
130 m_sharedWebIconDatabase->AddRef(); |
|
131 return m_sharedWebIconDatabase; |
|
132 } |
|
133 m_sharedWebIconDatabase = createInstance(); |
|
134 m_sharedWebIconDatabase->init(); |
|
135 return m_sharedWebIconDatabase; |
|
136 } |
|
137 |
|
138 // IUnknown ------------------------------------------------------------------- |
|
139 |
|
140 HRESULT STDMETHODCALLTYPE WebIconDatabase::QueryInterface(REFIID riid, void** ppvObject) |
|
141 { |
|
142 *ppvObject = 0; |
|
143 if (IsEqualGUID(riid, IID_IUnknown)) |
|
144 *ppvObject = static_cast<IWebIconDatabase*>(this); |
|
145 else if (IsEqualGUID(riid, IID_IWebIconDatabase)) |
|
146 *ppvObject = static_cast<IWebIconDatabase*>(this); |
|
147 else |
|
148 return E_NOINTERFACE; |
|
149 |
|
150 AddRef(); |
|
151 return S_OK; |
|
152 } |
|
153 |
|
154 ULONG STDMETHODCALLTYPE WebIconDatabase::AddRef(void) |
|
155 { |
|
156 return ++m_refCount; |
|
157 } |
|
158 |
|
159 ULONG STDMETHODCALLTYPE WebIconDatabase::Release(void) |
|
160 { |
|
161 ULONG newRef = --m_refCount; |
|
162 if (!newRef) |
|
163 delete(this); |
|
164 |
|
165 return newRef; |
|
166 } |
|
167 |
|
168 // IWebIconDatabase -------------------------------------------------------------------- |
|
169 |
|
170 HRESULT STDMETHODCALLTYPE WebIconDatabase::sharedIconDatabase( |
|
171 /* [retval][out] */ IWebIconDatabase** result) |
|
172 { |
|
173 *result = sharedWebIconDatabase(); |
|
174 return S_OK; |
|
175 } |
|
176 |
|
177 HRESULT STDMETHODCALLTYPE WebIconDatabase::iconForURL( |
|
178 /* [in] */ BSTR url, |
|
179 /* [optional][in] */ LPSIZE size, |
|
180 /* [optional][in] */ BOOL /*cache*/, |
|
181 /* [retval][out] */ OLE_HANDLE* bitmap) |
|
182 { |
|
183 IntSize intSize(*size); |
|
184 |
|
185 Image* icon = 0; |
|
186 if (url) |
|
187 icon = iconDatabase()->iconForPageURL(String(url, SysStringLen(url)), intSize); |
|
188 |
|
189 // Make sure we check for the case of an "empty image" |
|
190 if (icon && icon->width()) { |
|
191 *bitmap = (OLE_HANDLE)(ULONG64)getOrCreateSharedBitmap(size); |
|
192 if (!icon->getHBITMAPOfSize((HBITMAP)(ULONG64)*bitmap, size)) { |
|
193 LOG_ERROR("Failed to draw Image to HBITMAP"); |
|
194 *bitmap = 0; |
|
195 return E_FAIL; |
|
196 } |
|
197 return S_OK; |
|
198 } |
|
199 |
|
200 return defaultIconWithSize(size, bitmap); |
|
201 } |
|
202 |
|
203 HRESULT STDMETHODCALLTYPE WebIconDatabase::defaultIconWithSize( |
|
204 /* [in] */ LPSIZE size, |
|
205 /* [retval][out] */ OLE_HANDLE* result) |
|
206 { |
|
207 *result = (OLE_HANDLE)(ULONG64)getOrCreateDefaultIconBitmap(size); |
|
208 return S_OK; |
|
209 } |
|
210 |
|
211 HRESULT STDMETHODCALLTYPE WebIconDatabase::retainIconForURL( |
|
212 /* [in] */ BSTR url) |
|
213 { |
|
214 iconDatabase()->retainIconForPageURL(String(url, SysStringLen(url))); |
|
215 return S_OK; |
|
216 } |
|
217 |
|
218 HRESULT STDMETHODCALLTYPE WebIconDatabase::releaseIconForURL( |
|
219 /* [in] */ BSTR url) |
|
220 { |
|
221 iconDatabase()->releaseIconForPageURL(String(url, SysStringLen(url))); |
|
222 return S_OK; |
|
223 } |
|
224 |
|
225 HRESULT STDMETHODCALLTYPE WebIconDatabase::removeAllIcons(void) |
|
226 { |
|
227 iconDatabase()->removeAllIcons(); |
|
228 return S_OK; |
|
229 } |
|
230 |
|
231 HRESULT STDMETHODCALLTYPE WebIconDatabase::delayDatabaseCleanup(void) |
|
232 { |
|
233 IconDatabase::delayDatabaseCleanup(); |
|
234 return S_OK; |
|
235 } |
|
236 |
|
237 HRESULT STDMETHODCALLTYPE WebIconDatabase::allowDatabaseCleanup(void) |
|
238 { |
|
239 IconDatabase::allowDatabaseCleanup(); |
|
240 return S_OK; |
|
241 } |
|
242 |
|
243 HRESULT STDMETHODCALLTYPE WebIconDatabase::iconURLForURL( |
|
244 /* [in] */ BSTR url, |
|
245 /* [retval][out] */ BSTR* iconURL) |
|
246 { |
|
247 if (!url || !iconURL) |
|
248 return E_POINTER; |
|
249 BString iconURLBSTR(iconDatabase()->iconURLForPageURL(String(url, SysStringLen(url)))); |
|
250 *iconURL = iconURLBSTR.release(); |
|
251 return S_OK; |
|
252 } |
|
253 |
|
254 HBITMAP createDIB(LPSIZE size) |
|
255 { |
|
256 HBITMAP result; |
|
257 |
|
258 BITMAPINFO bmInfo = {0}; |
|
259 bmInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); |
|
260 bmInfo.bmiHeader.biWidth = size->cx; |
|
261 bmInfo.bmiHeader.biHeight = size->cy; |
|
262 bmInfo.bmiHeader.biPlanes = 1; |
|
263 bmInfo.bmiHeader.biBitCount = 32; |
|
264 bmInfo.bmiHeader.biCompression = BI_RGB; |
|
265 |
|
266 HDC dc = GetDC(0); |
|
267 result = CreateDIBSection(dc, &bmInfo, DIB_RGB_COLORS, 0, 0, 0); |
|
268 ReleaseDC(0, dc); |
|
269 |
|
270 return result; |
|
271 } |
|
272 |
|
273 HBITMAP WebIconDatabase::getOrCreateSharedBitmap(LPSIZE size) |
|
274 { |
|
275 HBITMAP result = m_sharedIconMap.get(*size); |
|
276 if (result) |
|
277 return result; |
|
278 result = createDIB(size); |
|
279 m_sharedIconMap.set(*size, result); |
|
280 return result; |
|
281 } |
|
282 |
|
283 HBITMAP WebIconDatabase::getOrCreateDefaultIconBitmap(LPSIZE size) |
|
284 { |
|
285 HBITMAP result = m_defaultIconMap.get(*size); |
|
286 if (result) |
|
287 return result; |
|
288 |
|
289 result = createDIB(size); |
|
290 static Image* defaultIconImage = 0; |
|
291 if (!defaultIconImage) { |
|
292 defaultIconImage = Image::loadPlatformResource("urlIcon"); |
|
293 } |
|
294 m_defaultIconMap.set(*size, result); |
|
295 if (!defaultIconImage->getHBITMAPOfSize(result, size)) { |
|
296 LOG_ERROR("Failed to draw Image to HBITMAP"); |
|
297 return 0; |
|
298 } |
|
299 return result; |
|
300 } |
|
301 |
|
302 // IconDatabaseClient |
|
303 |
|
304 void WebIconDatabase::dispatchDidRemoveAllIcons() |
|
305 { |
|
306 // Queueing the empty string is a special way of saying "this queued notification is the didRemoveAllIcons notification" |
|
307 MutexLocker locker(m_notificationMutex); |
|
308 m_notificationQueue.append(String()); |
|
309 scheduleNotificationDelivery(); |
|
310 } |
|
311 |
|
312 void WebIconDatabase::dispatchDidAddIconForPageURL(const String& pageURL) |
|
313 { |
|
314 MutexLocker locker(m_notificationMutex); |
|
315 m_notificationQueue.append(pageURL.copy()); |
|
316 scheduleNotificationDelivery(); |
|
317 } |
|
318 |
|
319 void WebIconDatabase::scheduleNotificationDelivery() |
|
320 { |
|
321 // Caller of this method must hold the m_notificationQueue lock |
|
322 ASSERT(m_notificationMutex.tryLock() == EBUSY); |
|
323 |
|
324 if (!m_deliveryRequested) { |
|
325 m_deliveryRequested = true; |
|
326 callOnMainThread(WebIconDatabase::deliverNotifications); |
|
327 } |
|
328 } |
|
329 |
|
330 BSTR WebIconDatabase::iconDatabaseDidAddIconNotification() |
|
331 { |
|
332 static BSTR didAddIconName = SysAllocString(WebIconDatabaseDidAddIconNotification); |
|
333 return didAddIconName; |
|
334 } |
|
335 |
|
336 CFStringRef WebIconDatabase::iconDatabaseNotificationUserInfoURLKey() |
|
337 { |
|
338 static CFStringRef iconUserInfoURLKey = String(WebIconNotificationUserInfoURLKey).createCFString(); |
|
339 return iconUserInfoURLKey; |
|
340 } |
|
341 |
|
342 BSTR WebIconDatabase::iconDatabaseDidRemoveAllIconsNotification() |
|
343 { |
|
344 static BSTR didRemoveAllIconsName = SysAllocString(WebIconDatabaseDidRemoveAllIconsNotification); |
|
345 return didRemoveAllIconsName; |
|
346 } |
|
347 |
|
348 static void postDidRemoveAllIconsNotification(WebIconDatabase* iconDB) |
|
349 { |
|
350 IWebNotificationCenter* notifyCenter = WebNotificationCenter::defaultCenterInternal(); |
|
351 notifyCenter->postNotificationName(WebIconDatabase::iconDatabaseDidRemoveAllIconsNotification(), static_cast<IWebIconDatabase*>(iconDB), 0); |
|
352 } |
|
353 |
|
354 static void postDidAddIconNotification(const String& pageURL, WebIconDatabase* iconDB) |
|
355 { |
|
356 RetainPtr<CFMutableDictionaryRef> dictionary(AdoptCF, |
|
357 CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); |
|
358 |
|
359 RetainPtr<CFStringRef> url(AdoptCF, pageURL.createCFString()); |
|
360 CFDictionaryAddValue(dictionary.get(), WebIconDatabase::iconDatabaseNotificationUserInfoURLKey(), url.get()); |
|
361 |
|
362 COMPtr<CFDictionaryPropertyBag> userInfo = CFDictionaryPropertyBag::createInstance(); |
|
363 userInfo->setDictionary(dictionary.get()); |
|
364 |
|
365 IWebNotificationCenter* notifyCenter = WebNotificationCenter::defaultCenterInternal(); |
|
366 notifyCenter->postNotificationName(WebIconDatabase::iconDatabaseDidAddIconNotification(), static_cast<IWebIconDatabase*>(iconDB), userInfo.get()); |
|
367 } |
|
368 |
|
369 void WebIconDatabase::deliverNotifications() |
|
370 { |
|
371 ASSERT(m_sharedWebIconDatabase); |
|
372 if (!m_sharedWebIconDatabase) |
|
373 return; |
|
374 |
|
375 ASSERT(m_sharedWebIconDatabase->m_deliveryRequested); |
|
376 |
|
377 Vector<String> queue; |
|
378 { |
|
379 MutexLocker locker(m_sharedWebIconDatabase->m_notificationMutex); |
|
380 queue.swap(m_sharedWebIconDatabase->m_notificationQueue); |
|
381 m_sharedWebIconDatabase->m_deliveryRequested = false; |
|
382 } |
|
383 |
|
384 for (unsigned i = 0; i < queue.size(); ++i) { |
|
385 if (queue[i].isNull()) |
|
386 postDidRemoveAllIconsNotification(m_sharedWebIconDatabase); |
|
387 else |
|
388 postDidAddIconNotification(queue[i], m_sharedWebIconDatabase); |
|
389 } |
|
390 } |