1 /*
2 * Copyright 2006, The Android Open Source Project
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 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * 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 THE COPYRIGHT HOLDERS ``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 THE COPYRIGHT OWNER 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 #define LOG_TAG "favicons"
27
28 #include "config.h"
29 #include "WebIconDatabase.h"
30
31 #include "FileSystem.h"
32 #include "GraphicsJNI.h"
33 #include "IconDatabase.h"
34 #include "Image.h"
35 #include "IntRect.h"
36 #include "JavaSharedClient.h"
37 #include "KURL.h"
38 #include "WebCoreJni.h"
39
40 #include <JNIHelp.h>
41 #include <JNIUtility.h>
42 #include <SharedBuffer.h>
43 #include <SkBitmap.h>
44 #include <SkImageDecoder.h>
45 #include <SkTemplates.h>
46 #include <pthread.h>
47 #include <utils/misc.h>
48 #include <wtf/Platform.h>
49 #include <wtf/text/CString.h>
50
51 namespace android {
52
webcoreImageToJavaBitmap(JNIEnv * env,WebCore::Image * icon)53 jobject webcoreImageToJavaBitmap(JNIEnv* env, WebCore::Image* icon)
54 {
55 if (!icon)
56 return NULL;
57 SkBitmap bm;
58 WebCore::SharedBuffer* buffer = icon->data();
59 if (!buffer || !SkImageDecoder::DecodeMemory(buffer->data(), buffer->size(),
60 &bm, SkBitmap::kNo_Config,
61 SkImageDecoder::kDecodePixels_Mode))
62 return NULL;
63
64 return GraphicsJNI::createBitmap(env, new SkBitmap(bm), false, NULL);
65 }
66
67 static WebIconDatabase* gIconDatabaseClient = new WebIconDatabase();
68
performImport()69 bool WebIconDatabase::performImport()
70 {
71 // We don't do do any old-style database importing.
72 return true;
73 }
74
75 // Called on the WebCore thread
didImportIconURLForPageURL(const WTF::String & pageURL)76 void WebIconDatabase::didImportIconURLForPageURL(const WTF::String& pageURL)
77 {
78 // FIXME: After http://trac.webkit.org/changeset/81719 this method is called
79 // on the WebCore thread, so switching threads via this queue is superfluous
80 // and should be removed. http://b/4565022
81 mNotificationsMutex.lock();
82 mNotifications.append(pageURL);
83 if (!mDeliveryRequested) {
84 mDeliveryRequested = true;
85 JavaSharedClient::EnqueueFunctionPtr(DeliverNotifications, this);
86 }
87 mNotificationsMutex.unlock();
88 }
89
didImportIconDataForPageURL(const WTF::String & pageURL)90 void WebIconDatabase::didImportIconDataForPageURL(const WTF::String& pageURL)
91 {
92 // WebKit1 only has a single "icon did change" notification.
93 didImportIconURLForPageURL(pageURL);
94 }
95
didChangeIconForPageURL(const WTF::String & pageURL)96 void WebIconDatabase::didChangeIconForPageURL(const WTF::String& pageURL)
97 {
98 // WebKit1 only has a single "icon did change" notification.
99 didImportIconURLForPageURL(pageURL);
100 }
101
didRemoveAllIcons()102 void WebIconDatabase::didRemoveAllIcons()
103 {
104 }
105
didFinishURLImport()106 void WebIconDatabase::didFinishURLImport()
107 {
108 }
109
110 // Called in the WebCore thread
RegisterForIconNotification(WebIconDatabaseClient * client)111 void WebIconDatabase::RegisterForIconNotification(WebIconDatabaseClient* client)
112 {
113 WebIconDatabase* db = gIconDatabaseClient;
114 for (unsigned i = 0; i < db->mClients.size(); ++i) {
115 // Do not add the same client twice.
116 if (db->mClients[i] == client)
117 return;
118 }
119 gIconDatabaseClient->mClients.append(client);
120 }
121
122 // Called in the WebCore thread
UnregisterForIconNotification(WebIconDatabaseClient * client)123 void WebIconDatabase::UnregisterForIconNotification(WebIconDatabaseClient* client)
124 {
125 WebIconDatabase* db = gIconDatabaseClient;
126 for (unsigned i = 0; i < db->mClients.size(); ++i) {
127 if (db->mClients[i] == client) {
128 db->mClients.remove(i);
129 break;
130 }
131 }
132 }
133
134 // Called in the WebCore thread
DeliverNotifications(void * v)135 void WebIconDatabase::DeliverNotifications(void* v)
136 {
137 ASSERT(v);
138 ((WebIconDatabase*)v)->deliverNotifications();
139 }
140
141 // Called in the WebCore thread
deliverNotifications()142 void WebIconDatabase::deliverNotifications()
143 {
144 ASSERT(mDeliveryRequested);
145
146 // Swap the notifications queue
147 Vector<WTF::String> queue;
148 mNotificationsMutex.lock();
149 queue.swap(mNotifications);
150 mDeliveryRequested = false;
151 mNotificationsMutex.unlock();
152
153 // Swap the clients queue
154 Vector<WebIconDatabaseClient*> clients;
155 clients.swap(mClients);
156
157 for (unsigned i = 0; i < queue.size(); ++i) {
158 for (unsigned j = 0; j < clients.size(); ++j) {
159 clients[j]->didAddIconForPageUrl(queue[i]);
160 }
161 }
162 }
163
Open(JNIEnv * env,jobject obj,jstring path)164 static void Open(JNIEnv* env, jobject obj, jstring path)
165 {
166 WebCore::IconDatabaseBase& iconDb = WebCore::iconDatabase();
167 if (iconDb.isOpen())
168 return;
169 iconDb.setEnabled(true);
170 iconDb.setClient(gIconDatabaseClient);
171 LOG_ASSERT(path, "No path given to nativeOpen");
172 WTF::String pathStr = jstringToWtfString(env, path);
173 WTF::CString fullPath = WebCore::pathByAppendingComponent(pathStr,
174 WebCore::IconDatabase::defaultDatabaseFilename()).utf8();
175 mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
176 bool didSetPermissions = false;
177 if (access(fullPath.data(), F_OK) == 0) {
178 if (chmod(fullPath.data(), mode) == 0)
179 didSetPermissions = true;
180 } else {
181 int fd = open(fullPath.data(), O_CREAT, mode);
182 if (fd >= 0) {
183 close(fd);
184 didSetPermissions = true;
185 }
186 }
187 if (didSetPermissions) {
188 LOGV("Opening WebIconDatabase file '%s'", pathStr.latin1().data());
189 bool res = iconDb.open(pathStr, WebCore::IconDatabase::defaultDatabaseFilename());
190 if (!res)
191 LOGE("Open failed!");
192 } else
193 LOGE("Failed to set permissions on '%s'", fullPath.data());
194 }
195
Close(JNIEnv * env,jobject obj)196 static void Close(JNIEnv* env, jobject obj)
197 {
198 WebCore::iconDatabase().close();
199 }
200
RemoveAllIcons(JNIEnv * env,jobject obj)201 static void RemoveAllIcons(JNIEnv* env, jobject obj)
202 {
203 LOGV("Removing all icons");
204 WebCore::iconDatabase().removeAllIcons();
205 }
206
IconForPageUrl(JNIEnv * env,jobject obj,jstring url)207 static jobject IconForPageUrl(JNIEnv* env, jobject obj, jstring url)
208 {
209 LOG_ASSERT(url, "No url given to iconForPageUrl");
210 WTF::String urlStr = jstringToWtfString(env, url);
211
212 // FIXME: This method should not be used from outside WebCore and will be removed.
213 // http://trac.webkit.org/changeset/81484
214 WebCore::Image* icon = WebCore::iconDatabase().synchronousIconForPageURL(urlStr, WebCore::IntSize(16, 16));
215 LOGV("Retrieving icon for '%s' %p", urlStr.latin1().data(), icon);
216 return webcoreImageToJavaBitmap(env, icon);
217 }
218
RetainIconForPageUrl(JNIEnv * env,jobject obj,jstring url)219 static void RetainIconForPageUrl(JNIEnv* env, jobject obj, jstring url)
220 {
221 LOG_ASSERT(url, "No url given to retainIconForPageUrl");
222 WTF::String urlStr = jstringToWtfString(env, url);
223
224 LOGV("Retaining icon for '%s'", urlStr.latin1().data());
225 WebCore::iconDatabase().retainIconForPageURL(urlStr);
226 }
227
ReleaseIconForPageUrl(JNIEnv * env,jobject obj,jstring url)228 static void ReleaseIconForPageUrl(JNIEnv* env, jobject obj, jstring url)
229 {
230 LOG_ASSERT(url, "No url given to releaseIconForPageUrl");
231 WTF::String urlStr = jstringToWtfString(env, url);
232
233 LOGV("Releasing icon for '%s'", urlStr.latin1().data());
234 WebCore::iconDatabase().releaseIconForPageURL(urlStr);
235 }
236
237 /*
238 * JNI registration
239 */
240 static JNINativeMethod gWebIconDatabaseMethods[] = {
241 { "nativeOpen", "(Ljava/lang/String;)V",
242 (void*) Open },
243 { "nativeClose", "()V",
244 (void*) Close },
245 { "nativeRemoveAllIcons", "()V",
246 (void*) RemoveAllIcons },
247 { "nativeIconForPageUrl", "(Ljava/lang/String;)Landroid/graphics/Bitmap;",
248 (void*) IconForPageUrl },
249 { "nativeRetainIconForPageUrl", "(Ljava/lang/String;)V",
250 (void*) RetainIconForPageUrl },
251 { "nativeReleaseIconForPageUrl", "(Ljava/lang/String;)V",
252 (void*) ReleaseIconForPageUrl }
253 };
254
registerWebIconDatabase(JNIEnv * env)255 int registerWebIconDatabase(JNIEnv* env)
256 {
257 #ifndef NDEBUG
258 jclass webIconDatabase = env->FindClass("android/webkit/WebIconDatabase");
259 LOG_ASSERT(webIconDatabase, "Unable to find class android.webkit.WebIconDatabase");
260 env->DeleteLocalRef(webIconDatabase);
261 #endif
262
263 return jniRegisterNativeMethods(env, "android/webkit/WebIconDatabase",
264 gWebIconDatabaseMethods, NELEM(gWebIconDatabaseMethods));
265 }
266
267 }
268