Create string tightly when retrive string from cbhm callback event
[framework/web/webkit-efl.git] / Source / WebKit2 / UIProcess / API / efl / ewk_favicon_database.cpp
1 /*
2  * Copyright (C) 2012 Intel Corporation. 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 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.
24  */
25
26 #include "config.h"
27 #include "ewk_favicon_database.h"
28
29 #include "WKAPICast.h"
30 #include "WKURL.h"
31 #include "WebIconDatabase.h"
32 #include "WebURL.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>
38
39 using namespace WebKit;
40
41 Ewk_Favicon_Database::Ewk_Favicon_Database(WKIconDatabaseRef iconDatabaseRef)
42     :  m_wkIconDatabase(iconDatabaseRef)
43 {
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);
51 }
52
53 String Ewk_Favicon_Database::iconURLForPageURL(const String& pageURL) const
54 {
55     String iconURL;
56     toImpl(m_wkIconDatabase.get())->synchronousIconURLForPageURL(pageURL, iconURL);
57
58     return iconURL;
59 }
60
61 void Ewk_Favicon_Database::watchChanges(const IconChangeCallbackData& callbackData)
62 {
63     ASSERT(callbackData.callback);
64     if (m_changeListeners.contains(callbackData.callback))
65         return;
66
67     m_changeListeners.add(callbackData.callback, callbackData);
68 }
69
70 void Ewk_Favicon_Database::unwatchChanges(Ewk_Favicon_Database_Icon_Change_Cb callback)
71 {
72     ASSERT(callback);
73     m_changeListeners.remove(callback);
74 }
75
76 struct AsyncIconRequestResponse {
77     String pageURL;
78     RefPtr<cairo_surface_t> surface;
79     IconRequestCallbackData callbackData;
80
81     AsyncIconRequestResponse(const String& pageURL, PassRefPtr<cairo_surface_t> surface, const IconRequestCallbackData& callbackData)
82         : pageURL(pageURL)
83         , surface(surface)
84         , callbackData(callbackData)
85     { }
86 };
87
88 static Eina_Bool respond_icon_request_idle(void* data)
89 {
90     AsyncIconRequestResponse* response = static_cast<AsyncIconRequestResponse*>(data);
91
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);
94
95     delete response;
96
97     return ECORE_CALLBACK_DONE;
98 }
99
100 void Ewk_Favicon_Database::iconForPageURL(const String& pageURL, const IconRequestCallbackData& callbackData)
101 {
102     WebIconDatabase* webIconDatabase = toImpl(m_wkIconDatabase.get());
103
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);
107
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);
117         return;
118     }
119
120     // Respond when idle.
121     AsyncIconRequestResponse* response = new AsyncIconRequestResponse(pageURL, surface.release(), callbackData);
122     ecore_idler_add(respond_icon_request_idle, response);
123 }
124
125 void Ewk_Favicon_Database::didChangeIconForPageURL(WKIconDatabaseRef, WKURLRef pageURLRef, const void* clientInfo)
126 {
127     const Ewk_Favicon_Database* ewkIconDatabase = static_cast<const Ewk_Favicon_Database*>(clientInfo);
128
129     if (ewkIconDatabase->m_changeListeners.isEmpty())
130         return;
131
132     CString pageURL = toImpl(pageURLRef)->string().utf8();
133
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);
138 }
139
140 PassRefPtr<cairo_surface_t> Ewk_Favicon_Database::getIconSurfaceSynchronously(const String& pageURL) const
141 {
142     WebIconDatabase* webIconDatabase = toImpl(m_wkIconDatabase.get());
143
144     webIconDatabase->retainIconForPageURL(pageURL);
145
146     WebCore::NativeImagePtr icon = webIconDatabase->nativeImageForPageURL(pageURL);
147     if (!icon) {
148         webIconDatabase->releaseIconForPageURL(pageURL);
149         return 0;
150     }
151
152     RefPtr<cairo_surface_t> surface = icon->surface();
153
154     return surface.release();
155 }
156
157 void Ewk_Favicon_Database::iconDataReadyForPageURL(WKIconDatabaseRef, WKURLRef pageURL, const void* clientInfo)
158 {
159     Ewk_Favicon_Database* ewkIconDatabase = const_cast<Ewk_Favicon_Database*>(static_cast<const Ewk_Favicon_Database*>(clientInfo));
160
161     String urlString = toImpl(pageURL)->string();
162     if (!ewkIconDatabase->m_iconRequests.contains(urlString))
163         return;
164
165     RefPtr<cairo_surface_t> surface = ewkIconDatabase->getIconSurfaceSynchronously(urlString);
166
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);
173     }
174 }
175
176 const char* ewk_favicon_database_icon_url_get(Ewk_Favicon_Database* ewkIconDatabase, const char* pageURL)
177 {
178     EINA_SAFETY_ON_NULL_RETURN_VAL(ewkIconDatabase, 0);
179     EINA_SAFETY_ON_NULL_RETURN_VAL(pageURL, 0);
180
181     String iconURL = ewkIconDatabase->iconURLForPageURL(String::fromUTF8(pageURL));
182
183     return eina_stringshare_add(iconURL.utf8().data());
184 }
185
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)
187 {
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);
192
193     ewkIconDatabase->iconForPageURL(String::fromUTF8(page_url), IconRequestCallbackData(callback, userData, evas));
194
195     return true;
196 }
197
198 void ewk_favicon_database_icon_change_callback_add(Ewk_Favicon_Database* ewkIconDatabase, Ewk_Favicon_Database_Icon_Change_Cb callback, void* userData)
199 {
200     EINA_SAFETY_ON_NULL_RETURN(ewkIconDatabase);
201     EINA_SAFETY_ON_NULL_RETURN(callback);
202
203     ewkIconDatabase->watchChanges(IconChangeCallbackData(callback, userData));
204 }
205
206 void ewk_favicon_database_icon_change_callback_del(Ewk_Favicon_Database* ewkIconDatabase, Ewk_Favicon_Database_Icon_Change_Cb callback)
207 {
208     EINA_SAFETY_ON_NULL_RETURN(ewkIconDatabase);
209     EINA_SAFETY_ON_NULL_RETURN(callback);
210
211     ewkIconDatabase->unwatchChanges(callback);
212 }