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 "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