• 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 "CString.h"
32 #include "FileSystem.h"
33 #include "GraphicsJNI.h"
34 #include "IconDatabase.h"
35 #include "Image.h"
36 #include "IntRect.h"
37 #include "JavaSharedClient.h"
38 #include "KURL.h"
39 #include "WebCoreJni.h"
40 
41 #include <JNIHelp.h>
42 #include <JNIUtility.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 
50 namespace android {
51 
webcoreImageToJavaBitmap(JNIEnv * env,WebCore::Image * icon)52 jobject webcoreImageToJavaBitmap(JNIEnv* env, WebCore::Image* icon)
53 {
54     if (!icon)
55         return NULL;
56     SkBitmap bm;
57     WebCore::SharedBuffer* buffer = icon->data();
58     if (!buffer || !SkImageDecoder::DecodeMemory(buffer->data(), buffer->size(),
59                                                  &bm, SkBitmap::kNo_Config,
60                                             SkImageDecoder::kDecodePixels_Mode))
61         return NULL;
62 
63     return GraphicsJNI::createBitmap(env, new SkBitmap(bm), false, NULL);
64 }
65 
66 static WebIconDatabase* gIconDatabaseClient = new WebIconDatabase();
67 
68 // XXX: Called by the IconDatabase thread
dispatchDidAddIconForPageURL(const WebCore::String & pageURL)69 void WebIconDatabase::dispatchDidAddIconForPageURL(const WebCore::String& pageURL)
70 {
71     mNotificationsMutex.lock();
72     mNotifications.append(pageURL);
73     if (!mDeliveryRequested) {
74         mDeliveryRequested = true;
75         JavaSharedClient::EnqueueFunctionPtr(DeliverNotifications, this);
76     }
77     mNotificationsMutex.unlock();
78 }
79 
80 // Called in the WebCore thread
RegisterForIconNotification(WebIconDatabaseClient * client)81 void WebIconDatabase::RegisterForIconNotification(WebIconDatabaseClient* client)
82 {
83     WebIconDatabase* db = gIconDatabaseClient;
84     for (unsigned i = 0; i < db->mClients.size(); ++i) {
85         // Do not add the same client twice.
86         if (db->mClients[i] == client)
87             return;
88     }
89     gIconDatabaseClient->mClients.append(client);
90 }
91 
92 // Called in the WebCore thread
UnregisterForIconNotification(WebIconDatabaseClient * client)93 void WebIconDatabase::UnregisterForIconNotification(WebIconDatabaseClient* client)
94 {
95     WebIconDatabase* db = gIconDatabaseClient;
96     for (unsigned i = 0; i < db->mClients.size(); ++i) {
97         if (db->mClients[i] == client) {
98             db->mClients.remove(i);
99             break;
100         }
101     }
102 }
103 
104 // Called in the WebCore thread
DeliverNotifications(void * v)105 void WebIconDatabase::DeliverNotifications(void* v)
106 {
107     ASSERT(v);
108     ((WebIconDatabase*)v)->deliverNotifications();
109 }
110 
111 // Called in the WebCore thread
deliverNotifications()112 void WebIconDatabase::deliverNotifications()
113 {
114     ASSERT(mDeliveryRequested);
115 
116     // Swap the notifications queue
117     Vector<WebCore::String> queue;
118     mNotificationsMutex.lock();
119     queue.swap(mNotifications);
120     mDeliveryRequested = false;
121     mNotificationsMutex.unlock();
122 
123     // Swap the clients queue
124     Vector<WebIconDatabaseClient*> clients;
125     clients.swap(mClients);
126 
127     for (unsigned i = 0; i < queue.size(); ++i) {
128         for (unsigned j = 0; j < clients.size(); ++j) {
129             clients[j]->didAddIconForPageUrl(queue[i]);
130         }
131     }
132 }
133 
Open(JNIEnv * env,jobject obj,jstring path)134 static void Open(JNIEnv* env, jobject obj, jstring path)
135 {
136     WebCore::IconDatabase* iconDb = WebCore::iconDatabase();
137     if (iconDb->isOpen())
138         return;
139     iconDb->setEnabled(true);
140     iconDb->setClient(gIconDatabaseClient);
141     LOG_ASSERT(path, "No path given to nativeOpen");
142     WebCore::String pathStr = to_string(env, path);
143     WebCore::CString fullPath = WebCore::pathByAppendingComponent(pathStr,
144             WebCore::IconDatabase::defaultDatabaseFilename()).utf8();
145     mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
146     bool didSetPermissions = false;
147     if (access(fullPath.data(), F_OK) == 0) {
148         if (chmod(fullPath.data(), mode) == 0)
149             didSetPermissions = true;
150     } else {
151         int fd = open(fullPath.data(), O_CREAT, mode);
152         if (fd >= 0) {
153             close(fd);
154             didSetPermissions = true;
155         }
156     }
157     if (didSetPermissions) {
158         LOGV("Opening WebIconDatabase file '%s'", pathStr.latin1().data());
159         bool res = iconDb->open(pathStr);
160         if (!res)
161             LOGE("Open failed!");
162     } else
163         LOGE("Failed to set permissions on '%s'", fullPath.data());
164 }
165 
Close(JNIEnv * env,jobject obj)166 static void Close(JNIEnv* env, jobject obj)
167 {
168     WebCore::iconDatabase()->close();
169 }
170 
RemoveAllIcons(JNIEnv * env,jobject obj)171 static void RemoveAllIcons(JNIEnv* env, jobject obj)
172 {
173     LOGV("Removing all icons");
174     WebCore::iconDatabase()->removeAllIcons();
175 }
176 
IconForPageUrl(JNIEnv * env,jobject obj,jstring url)177 static jobject IconForPageUrl(JNIEnv* env, jobject obj, jstring url)
178 {
179     LOG_ASSERT(url, "No url given to iconForPageUrl");
180     WebCore::String urlStr = to_string(env, url);
181 
182     WebCore::Image* icon = WebCore::iconDatabase()->iconForPageURL(urlStr,
183             WebCore::IntSize(16, 16));
184     LOGV("Retrieving icon for '%s' %p", urlStr.latin1().data(), icon);
185     return webcoreImageToJavaBitmap(env, icon);
186 }
187 
RetainIconForPageUrl(JNIEnv * env,jobject obj,jstring url)188 static void RetainIconForPageUrl(JNIEnv* env, jobject obj, jstring url)
189 {
190     LOG_ASSERT(url, "No url given to retainIconForPageUrl");
191     WebCore::String urlStr = to_string(env, url);
192 
193     LOGV("Retaining icon for '%s'", urlStr.latin1().data());
194     WebCore::iconDatabase()->retainIconForPageURL(urlStr);
195 }
196 
ReleaseIconForPageUrl(JNIEnv * env,jobject obj,jstring url)197 static void ReleaseIconForPageUrl(JNIEnv* env, jobject obj, jstring url)
198 {
199     LOG_ASSERT(url, "No url given to releaseIconForPageUrl");
200     WebCore::String urlStr = to_string(env, url);
201 
202     LOGV("Releasing icon for '%s'", urlStr.latin1().data());
203     WebCore::iconDatabase()->releaseIconForPageURL(urlStr);
204 }
205 
206 /*
207  * JNI registration
208  */
209 static JNINativeMethod gWebIconDatabaseMethods[] = {
210     { "nativeOpen", "(Ljava/lang/String;)V",
211         (void*) Open },
212     { "nativeClose", "()V",
213         (void*) Close },
214     { "nativeRemoveAllIcons", "()V",
215         (void*) RemoveAllIcons },
216     { "nativeIconForPageUrl", "(Ljava/lang/String;)Landroid/graphics/Bitmap;",
217         (void*) IconForPageUrl },
218     { "nativeRetainIconForPageUrl", "(Ljava/lang/String;)V",
219         (void*) RetainIconForPageUrl },
220     { "nativeReleaseIconForPageUrl", "(Ljava/lang/String;)V",
221         (void*) ReleaseIconForPageUrl }
222 };
223 
register_webicondatabase(JNIEnv * env)224 int register_webicondatabase(JNIEnv* env)
225 {
226     jclass webIconDB = env->FindClass("android/webkit/WebIconDatabase");
227     LOG_ASSERT(webIconDB, "Unable to find class android.webkit.WebIconDatabase");
228 
229     return jniRegisterNativeMethods(env, "android/webkit/WebIconDatabase",
230             gWebIconDatabaseMethods, NELEM(gWebIconDatabaseMethods));
231 }
232 
233 }
234