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