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 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 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 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 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 105 void WebIconDatabase::DeliverNotifications(void* v) 106 { 107 ASSERT(v); 108 ((WebIconDatabase*)v)->deliverNotifications(); 109 } 110 111 // Called in the WebCore thread 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 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 166 static void Close(JNIEnv* env, jobject obj) 167 { 168 WebCore::iconDatabase()->close(); 169 } 170 171 static void RemoveAllIcons(JNIEnv* env, jobject obj) 172 { 173 LOGV("Removing all icons"); 174 WebCore::iconDatabase()->removeAllIcons(); 175 } 176 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 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 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 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