blob: eefeea513f21e25c6e132d4f42ac99debd59af41 [file] [log] [blame]
/*
* Copyright 2006, The Android Open Source Project
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#define LOG_TAG "webcoreglue"
#include <config.h>
#include <wtf/Platform.h>
#include "Cache.h"
#include "CookieClient.h"
#include "JavaSharedClient.h"
#include "KURL.h"
#include "NetworkStateNotifier.h"
#include "Timer.h"
#include "TimerClient.h"
#include "jni_utility.h"
#include "WebCoreJni.h"
#ifdef ANDROID_INSTRUMENT
#include "TimeCounter.h"
#endif
#include <jni.h>
#include <JNIHelp.h>
#include <SkImageRef_GlobalPool.h>
#include <SkUtils.h>
#include <utils/misc.h>
// maximum bytes used to cache decoded images
// (not including big images using ashmem)
#define IMAGE_POOL_BUDGET (512 * 1024)
namespace android {
// ----------------------------------------------------------------------------
static jfieldID gJavaBridge_ObjectID;
// ----------------------------------------------------------------------------
class JavaBridge : public TimerClient, public CookieClient
{
public:
JavaBridge(JNIEnv* env, jobject obj);
virtual ~JavaBridge();
/*
* WebCore -> Java API
*/
virtual void setSharedTimer(long long timemillis);
virtual void stopSharedTimer();
virtual void setCookies(WebCore::KURL const& url, WebCore::KURL const& docURL, WebCore::String const& value);
virtual WebCore::String cookies(WebCore::KURL const& url);
virtual bool cookiesEnabled();
////////////////////////////////////////////
virtual void setSharedTimerCallback(void (*f)());
////////////////////////////////////////////
void signalServiceFuncPtrQueue();
// jni functions
static void Constructor(JNIEnv* env, jobject obj);
static void Finalize(JNIEnv* env, jobject obj);
static void SharedTimerFired(JNIEnv* env, jobject);
static void SetCacheSize(JNIEnv* env, jobject obj, jint bytes);
static void SetNetworkOnLine(JNIEnv* env, jobject obj, jboolean online);
static void SetDeferringTimers(JNIEnv* env, jobject obj, jboolean defer);
static void ServiceFuncPtrQueue(JNIEnv*);
private:
jobject mJavaObject;
jmethodID mSetSharedTimer;
jmethodID mStopSharedTimer;
jmethodID mSetCookies;
jmethodID mCookies;
jmethodID mCookiesEnabled;
jmethodID mSignalFuncPtrQueue;
};
static void (*sSharedTimerFiredCallback)();
static JavaBridge* gJavaBridge;
JavaBridge::JavaBridge(JNIEnv* env, jobject obj)
{
mJavaObject = adoptGlobalRef(env, obj);
jclass clazz = env->GetObjectClass(obj);
mSetSharedTimer = env->GetMethodID(clazz, "setSharedTimer", "(J)V");
mStopSharedTimer = env->GetMethodID(clazz, "stopSharedTimer", "()V");
mSetCookies = env->GetMethodID(clazz, "setCookies", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
mCookies = env->GetMethodID(clazz, "cookies", "(Ljava/lang/String;)Ljava/lang/String;");
mCookiesEnabled = env->GetMethodID(clazz, "cookiesEnabled", "()Z");
mSignalFuncPtrQueue = env->GetMethodID(clazz, "signalServiceFuncPtrQueue", "()V");
LOG_ASSERT(mSetSharedTimer, "Could not find method setSharedTimer");
LOG_ASSERT(mStopSharedTimer, "Could not find method stopSharedTimer");
LOG_ASSERT(mSetCookies, "Could not find method setCookies");
LOG_ASSERT(mCookies, "Could not find method cookies");
LOG_ASSERT(mCookiesEnabled, "Could not find method cookiesEnabled");
JavaSharedClient::SetTimerClient(this);
JavaSharedClient::SetCookieClient(this);
gJavaBridge = this;
}
JavaBridge::~JavaBridge()
{
if (mJavaObject) {
JNIEnv* env = JSC::Bindings::getJNIEnv();
env->DeleteGlobalRef(mJavaObject);
mJavaObject = 0;
}
JavaSharedClient::SetTimerClient(NULL);
JavaSharedClient::SetCookieClient(NULL);
}
void
JavaBridge::setSharedTimer(long long timemillis)
{
JNIEnv* env = JSC::Bindings::getJNIEnv();
AutoJObject obj = getRealObject(env, mJavaObject);
env->CallVoidMethod(obj.get(), mSetSharedTimer, timemillis);
}
void
JavaBridge::stopSharedTimer()
{
JNIEnv* env = JSC::Bindings::getJNIEnv();
AutoJObject obj = getRealObject(env, mJavaObject);
env->CallVoidMethod(obj.get(), mStopSharedTimer);
}
void
JavaBridge::setCookies(WebCore::KURL const& url, WebCore::KURL const& docUrl, WebCore::String const& value)
{
JNIEnv* env = JSC::Bindings::getJNIEnv();
const WebCore::String& urlStr = url.string();
jstring jUrlStr = env->NewString(urlStr.characters(), urlStr.length());
const WebCore::String& docUrlStr = docUrl.string();
jstring jDocUrlStr = env->NewString(docUrlStr.characters(), docUrlStr.length());
jstring jValueStr = env->NewString(value.characters(), value.length());
AutoJObject obj = getRealObject(env, mJavaObject);
env->CallVoidMethod(obj.get(), mSetCookies, jUrlStr, jDocUrlStr, jValueStr);
env->DeleteLocalRef(jUrlStr);
env->DeleteLocalRef(jDocUrlStr);
env->DeleteLocalRef(jValueStr);
}
WebCore::String
JavaBridge::cookies(WebCore::KURL const& url)
{
JNIEnv* env = JSC::Bindings::getJNIEnv();
const WebCore::String& urlStr = url.string();
jstring jUrlStr = env->NewString(urlStr.characters(), urlStr.length());
AutoJObject obj = getRealObject(env, mJavaObject);
jstring string = (jstring)(env->CallObjectMethod(obj.get(), mCookies, jUrlStr));
WebCore::String ret = to_string(env, string);
env->DeleteLocalRef(jUrlStr);
env->DeleteLocalRef(string);
return ret;
}
bool
JavaBridge::cookiesEnabled()
{
JNIEnv* env = JSC::Bindings::getJNIEnv();
AutoJObject obj = getRealObject(env, mJavaObject);
jboolean ret = env->CallBooleanMethod(obj.get(), mCookiesEnabled);
return (ret != 0);
}
void
JavaBridge::setSharedTimerCallback(void (*f)())
{
LOG_ASSERT(!sSharedTimerFiredCallback || sSharedTimerFiredCallback==f,
"Shared timer callback may already be set or null!");
sSharedTimerFiredCallback = f;
}
void JavaBridge::signalServiceFuncPtrQueue()
{
// In order to signal the main thread we must go through JNI. This
// is the only usage on most threads, so we need to ensure a JNI
// environment is setup.
JNIEnv* env = JSC::Bindings::getJNIEnv();
AutoJObject obj = getRealObject(env, mJavaObject);
env->CallVoidMethod(obj.get(), mSignalFuncPtrQueue);
}
// ----------------------------------------------------------------------------
// visible to Shared
void AndroidSignalServiceFuncPtrQueue()
{
gJavaBridge->signalServiceFuncPtrQueue();
}
// ----------------------------------------------------------------------------
void JavaBridge::Constructor(JNIEnv* env, jobject obj)
{
JavaBridge* javaBridge = new JavaBridge(env, obj);
env->SetIntField(obj, gJavaBridge_ObjectID, (jint)javaBridge);
}
void JavaBridge::Finalize(JNIEnv* env, jobject obj)
{
JavaBridge* javaBridge = (JavaBridge*)
(env->GetIntField(obj, gJavaBridge_ObjectID));
LOG_ASSERT(javaBridge, "Finalize should not be called twice for the same java bridge!");
LOGV("webcore_javabridge::nativeFinalize(%p)\n", javaBridge);
delete javaBridge;
env->SetIntField(obj, gJavaBridge_ObjectID, 0);
}
// we don't use the java bridge object, as we're just looking at a global
void JavaBridge::SharedTimerFired(JNIEnv* env, jobject)
{
if (sSharedTimerFiredCallback)
{
#ifdef ANDROID_INSTRUMENT
TimeCounter::start(TimeCounter::SharedTimerTimeCounter);
#endif
SkAutoMemoryUsageProbe mup("JavaBridge::sharedTimerFired");
sSharedTimerFiredCallback();
#ifdef ANDROID_INSTRUMENT
TimeCounter::record(TimeCounter::SharedTimerTimeCounter, __FUNCTION__);
#endif
}
}
void JavaBridge::SetCacheSize(JNIEnv* env, jobject obj, jint bytes)
{
WebCore::cache()->setCapacities(0, bytes/2, bytes);
SkImageRef_GlobalPool::SetRAMBudget(IMAGE_POOL_BUDGET);
LOGV("--- set ImageRef budget %d\n", SkImageRef_GlobalPool::GetRAMBudget());
}
void JavaBridge::SetNetworkOnLine(JNIEnv* env, jobject obj, jboolean online)
{
WebCore::networkStateNotifier().networkStateChange(online);
}
void JavaBridge::SetDeferringTimers(JNIEnv* env, jobject obj, jboolean defer)
{
WebCore::setDeferringTimers(defer);
}
void JavaBridge::ServiceFuncPtrQueue(JNIEnv*)
{
JavaSharedClient::ServiceFunctionPtrQueue();
}
// ----------------------------------------------------------------------------
/*
* JNI registration.
*/
static JNINativeMethod gWebCoreJavaBridgeMethods[] = {
/* name, signature, funcPtr */
{ "nativeConstructor", "()V",
(void*) JavaBridge::Constructor },
{ "nativeFinalize", "()V",
(void*) JavaBridge::Finalize },
{ "sharedTimerFired", "()V",
(void*) JavaBridge::SharedTimerFired },
{ "setCacheSize", "(I)V",
(void*) JavaBridge::SetCacheSize },
{ "setNetworkOnLine", "(Z)V",
(void*) JavaBridge::SetNetworkOnLine },
{ "setDeferringTimers", "(Z)V",
(void*) JavaBridge::SetDeferringTimers },
{ "nativeServiceFuncPtrQueue", "()V",
(void*) JavaBridge::ServiceFuncPtrQueue },
};
int register_javabridge(JNIEnv* env)
{
jclass javaBridge = env->FindClass("android/webkit/JWebCoreJavaBridge");
LOG_FATAL_IF(javaBridge == NULL, "Unable to find class android/webkit/JWebCoreJavaBridge");
gJavaBridge_ObjectID = env->GetFieldID(javaBridge, "mNativeBridge", "I");
LOG_FATAL_IF(gJavaBridge_ObjectID == NULL, "Unable to find android/webkit/JWebCoreJavaBridge.mNativeBridge");
return jniRegisterNativeMethods(env, "android/webkit/JWebCoreJavaBridge",
gWebCoreJavaBridgeMethods, NELEM(gWebCoreJavaBridgeMethods));
}
} /* namespace android */