2 * Copyright (C) 2012 Intel Corporation. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
27 #include "ewk_favicon_database.h"
29 #include "WKAPICast.h"
31 #include "WebIconDatabase.h"
33 #include "ewk_favicon_database_private.h"
34 #include <WebCore/CairoUtilitiesEfl.h>
35 #include <WebCore/RefPtrCairo.h>
36 #include <wtf/text/CString.h>
37 #include <wtf/text/WTFString.h>
39 using namespace WebKit;
41 Ewk_Favicon_Database::Ewk_Favicon_Database(WKIconDatabaseRef iconDatabaseRef)
42 : m_wkIconDatabase(iconDatabaseRef)
44 WKIconDatabaseClient iconDatabaseClient;
45 memset(&iconDatabaseClient, 0, sizeof(WKIconDatabaseClient));
46 iconDatabaseClient.version = kWKIconDatabaseClientCurrentVersion;
47 iconDatabaseClient.clientInfo = this;
48 iconDatabaseClient.didChangeIconForPageURL = didChangeIconForPageURL;
49 iconDatabaseClient.iconDataReadyForPageURL = iconDataReadyForPageURL;
50 WKIconDatabaseSetIconDatabaseClient(m_wkIconDatabase.get(), &iconDatabaseClient);
53 String Ewk_Favicon_Database::iconURLForPageURL(const String& pageURL) const
56 toImpl(m_wkIconDatabase.get())->synchronousIconURLForPageURL(pageURL, iconURL);
61 void Ewk_Favicon_Database::watchChanges(const IconChangeCallbackData& callbackData)
63 ASSERT(callbackData.callback);
64 if (m_changeListeners.contains(callbackData.callback))
67 m_changeListeners.add(callbackData.callback, callbackData);
70 void Ewk_Favicon_Database::unwatchChanges(Ewk_Favicon_Database_Icon_Change_Cb callback)
73 m_changeListeners.remove(callback);
76 struct AsyncIconRequestResponse {
78 RefPtr<cairo_surface_t> surface;
79 IconRequestCallbackData callbackData;
81 AsyncIconRequestResponse(const String& pageURL, PassRefPtr<cairo_surface_t> surface, const IconRequestCallbackData& callbackData)
84 , callbackData(callbackData)
88 static Eina_Bool respond_icon_request_idle(void* data)
90 AsyncIconRequestResponse* response = static_cast<AsyncIconRequestResponse*>(data);
92 RefPtr<Evas_Object> icon = response->surface ? WebCore::evasObjectFromCairoImageSurface(response->callbackData.evas, response->surface.get()) : 0;
93 response->callbackData.callback(response->pageURL.utf8().data(), icon.get(), response->callbackData.userData);
97 return ECORE_CALLBACK_DONE;
100 void Ewk_Favicon_Database::iconForPageURL(const String& pageURL, const IconRequestCallbackData& callbackData)
102 WebIconDatabase* webIconDatabase = toImpl(m_wkIconDatabase.get());
104 // We ask for the icon directly. If we don't get the icon data now,
105 // we'll be notified later (even if the database is still importing icons).
106 RefPtr<cairo_surface_t> surface = getIconSurfaceSynchronously(pageURL);
108 // If there's no valid icon, but there's an iconURL registered,
109 // or it's still not registered but the import process hasn't
110 // finished yet, we need to wait for iconDataReadyForPageURL to be
111 // called before making and informed decision.
112 String iconURL = iconURLForPageURL(pageURL);
113 if (!surface && (!iconURL.isEmpty() || !webIconDatabase->isUrlImportCompleted())) {
114 PendingIconRequestVector requests = m_iconRequests.get(pageURL);
115 requests.append(callbackData);
116 m_iconRequests.set(pageURL, requests);
120 // Respond when idle.
121 AsyncIconRequestResponse* response = new AsyncIconRequestResponse(pageURL, surface.release(), callbackData);
122 ecore_idler_add(respond_icon_request_idle, response);
125 void Ewk_Favicon_Database::didChangeIconForPageURL(WKIconDatabaseRef, WKURLRef pageURLRef, const void* clientInfo)
127 const Ewk_Favicon_Database* ewkIconDatabase = static_cast<const Ewk_Favicon_Database*>(clientInfo);
129 if (ewkIconDatabase->m_changeListeners.isEmpty())
132 CString pageURL = toImpl(pageURLRef)->string().utf8();
134 ChangeListenerMap::const_iterator it = ewkIconDatabase->m_changeListeners.begin();
135 ChangeListenerMap::const_iterator end = ewkIconDatabase->m_changeListeners.end();
136 for (; it != end; ++it)
137 it->second.callback(pageURL.data(), it->second.userData);
140 PassRefPtr<cairo_surface_t> Ewk_Favicon_Database::getIconSurfaceSynchronously(const String& pageURL) const
142 WebIconDatabase* webIconDatabase = toImpl(m_wkIconDatabase.get());
144 webIconDatabase->retainIconForPageURL(pageURL);
146 WebCore::NativeImagePtr icon = webIconDatabase->nativeImageForPageURL(pageURL);
148 webIconDatabase->releaseIconForPageURL(pageURL);
152 RefPtr<cairo_surface_t> surface = icon->surface();
154 return surface.release();
157 void Ewk_Favicon_Database::iconDataReadyForPageURL(WKIconDatabaseRef, WKURLRef pageURL, const void* clientInfo)
159 Ewk_Favicon_Database* ewkIconDatabase = const_cast<Ewk_Favicon_Database*>(static_cast<const Ewk_Favicon_Database*>(clientInfo));
161 String urlString = toImpl(pageURL)->string();
162 if (!ewkIconDatabase->m_iconRequests.contains(urlString))
165 RefPtr<cairo_surface_t> surface = ewkIconDatabase->getIconSurfaceSynchronously(urlString);
167 PendingIconRequestVector requestsForURL = ewkIconDatabase->m_iconRequests.take(urlString);
168 size_t requestCount = requestsForURL.size();
169 for (size_t i = 0; i < requestCount; ++i) {
170 const IconRequestCallbackData& callbackData = requestsForURL[i];
171 RefPtr<Evas_Object> icon = surface ? WebCore::evasObjectFromCairoImageSurface(callbackData.evas, surface.get()) : 0;
172 callbackData.callback(urlString.utf8().data(), icon.get(), callbackData.userData);
176 const char* ewk_favicon_database_icon_url_get(Ewk_Favicon_Database* ewkIconDatabase, const char* pageURL)
178 EINA_SAFETY_ON_NULL_RETURN_VAL(ewkIconDatabase, 0);
179 EINA_SAFETY_ON_NULL_RETURN_VAL(pageURL, 0);
181 String iconURL = ewkIconDatabase->iconURLForPageURL(String::fromUTF8(pageURL));
183 return eina_stringshare_add(iconURL.utf8().data());
186 Eina_Bool ewk_favicon_database_async_icon_get(Ewk_Favicon_Database* ewkIconDatabase, const char* page_url, Evas* evas, Ewk_Favicon_Database_Async_Icon_Get_Cb callback, void* userData)
188 EINA_SAFETY_ON_NULL_RETURN_VAL(ewkIconDatabase, false);
189 EINA_SAFETY_ON_NULL_RETURN_VAL(page_url, false);
190 EINA_SAFETY_ON_NULL_RETURN_VAL(evas, false);
191 EINA_SAFETY_ON_NULL_RETURN_VAL(callback, false);
193 ewkIconDatabase->iconForPageURL(String::fromUTF8(page_url), IconRequestCallbackData(callback, userData, evas));
198 void ewk_favicon_database_icon_change_callback_add(Ewk_Favicon_Database* ewkIconDatabase, Ewk_Favicon_Database_Icon_Change_Cb callback, void* userData)
200 EINA_SAFETY_ON_NULL_RETURN(ewkIconDatabase);
201 EINA_SAFETY_ON_NULL_RETURN(callback);
203 ewkIconDatabase->watchChanges(IconChangeCallbackData(callback, userData));
206 void ewk_favicon_database_icon_change_callback_del(Ewk_Favicon_Database* ewkIconDatabase, Ewk_Favicon_Database_Icon_Change_Cb callback)
208 EINA_SAFETY_ON_NULL_RETURN(ewkIconDatabase);
209 EINA_SAFETY_ON_NULL_RETURN(callback);
211 ewkIconDatabase->unwatchChanges(callback);