Home | History | Annotate | Download | only in jni
      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 
     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 
     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
     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 
     90 void WebIconDatabase::didImportIconDataForPageURL(const WTF::String& pageURL)
     91 {
     92     // WebKit1 only has a single "icon did change" notification.
     93     didImportIconURLForPageURL(pageURL);
     94 }
     95 
     96 void WebIconDatabase::didChangeIconForPageURL(const WTF::String& pageURL)
     97 {
     98     // WebKit1 only has a single "icon did change" notification.
     99     didImportIconURLForPageURL(pageURL);
    100 }
    101 
    102 void WebIconDatabase::didRemoveAllIcons()
    103 {
    104 }
    105 
    106 void WebIconDatabase::didFinishURLImport()
    107 {
    108 }
    109 
    110 // Called in the WebCore thread
    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
    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
    135 void WebIconDatabase::DeliverNotifications(void* v)
    136 {
    137     ASSERT(v);
    138     ((WebIconDatabase*)v)->deliverNotifications();
    139 }
    140 
    141 // Called in the WebCore thread
    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 
    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 
    196 static void Close(JNIEnv* env, jobject obj)
    197 {
    198     WebCore::iconDatabase().close();
    199 }
    200 
    201 static void RemoveAllIcons(JNIEnv* env, jobject obj)
    202 {
    203     LOGV("Removing all icons");
    204     WebCore::iconDatabase().removeAllIcons();
    205 }
    206 
    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 
    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 
    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 
    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