• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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