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 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 
     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 
     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
     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 
    103 void WebIconDatabase::didImportIconDataForPageURL(const WTF::String& pageURL)
    104 {
    105     // WebKit1 only has a single "icon did change" notification.
    106     didImportIconURLForPageURL(pageURL);
    107 }
    108 
    109 void WebIconDatabase::didChangeIconForPageURL(const WTF::String& pageURL)
    110 {
    111     // WebKit1 only has a single "icon did change" notification.
    112     didImportIconURLForPageURL(pageURL);
    113 }
    114 
    115 void WebIconDatabase::didRemoveAllIcons()
    116 {
    117 }
    118 
    119 void WebIconDatabase::didFinishURLImport()
    120 {
    121 }
    122 
    123 // Called in the WebCore thread
    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
    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
    148 void WebIconDatabase::DeliverNotifications(void* v)
    149 {
    150     ASSERT(v);
    151     ((WebIconDatabase*)v)->deliverNotifications();
    152 }
    153 
    154 // Called in the WebCore thread
    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 
    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 
    209 static void Close(JNIEnv* env, jobject obj)
    210 {
    211     WebCore::iconDatabase().close();
    212 }
    213 
    214 static void RemoveAllIcons(JNIEnv* env, jobject obj)
    215 {
    216     ALOGV("Removing all icons");
    217     WebCore::iconDatabase().removeAllIcons();
    218 }
    219 
    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 
    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 
    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 
    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