Add back IE proxy handling for CheckForUpdates.
Also remove branch-info.txt inadvertently committed to trunk.
Patch by: scottb
Review by: jat
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@6390 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/jni/mac/JStringWrap.h b/jni/mac/JStringWrap.h
new file mode 100644
index 0000000..e17981f
--- /dev/null
+++ b/jni/mac/JStringWrap.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+#ifndef JSTRINGWRAP_H
+#define JSTRINGWRAP_H
+
+#include <jni.h>
+
+/*
+ * Wrap a Java String and automatically clean up temporary storage allocated
+ * for accessing its contents.
+ */
+struct JStringWrap
+{
+ JStringWrap(JNIEnv* env, jstring str): env(env), s(str), p(0), jp(0) { }
+ ~JStringWrap() {
+ if (p) env->ReleaseStringUTFChars(s, p);
+ if (jp) env->ReleaseStringChars(s, jp);
+ }
+ const char* str() { if (!p) p = env->GetStringUTFChars(s, 0); return p; }
+ const jchar* jstr() { if (!jp) jp = env->GetStringChars(s, 0); return jp; }
+ jsize length() { return env->GetStringLength(s); }
+private:
+ JNIEnv* env;
+ jstring s;
+ const char* p;
+ const jchar* jp;
+};
+
+#endif
diff --git a/jni/mac/Makefile b/jni/mac/Makefile
new file mode 100644
index 0000000..867b511
--- /dev/null
+++ b/jni/mac/Makefile
@@ -0,0 +1,89 @@
+# Copyright 2008 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
+CC = g++
+JAVAH = javah
+
+##
+# Try a GWT_TOOLS default if it isn't set
+##
+GWT_TOOLS ?= ../../../tools
+GWT_ROOT ?= ../..
+
+##
+# The location to get .class files for javah
+##
+CLASSDIR := $(GWT_ROOT)/build/out/dev/mac/bin
+
+##
+# External SWT products.
+##
+SWT_ORIGINAL_SRC = $(GWT_TOOLS)/lib/eclipse/org.eclipse.swt.carbon-macosx-3.2.1.src.zip
+SWT_PATCH_DIR = ./swt-build
+SWT_LIBS=$(SWT_PATCH_DIR)/libswt-webkit-carbon-3235.jnilib \
+ $(SWT_PATCH_DIR)/libswt-agl-carbon-3235.jnilib \
+ $(SWT_PATCH_DIR)/libswt-carbon-3235.jnilib \
+ $(SWT_PATCH_DIR)/libswt-pi-carbon-3235.jnilib
+
+GWT_LL_LIB = libgwt-ll.jnilib
+GWT_LL_OBJS = gwt-ll.o java-dispatch.o gwt-webkit.o trace.o
+GWT_LL_JNI = gwt-webkit.h
+
+TARGETS = $(GWT_LL_LIB) $(SWT_LIBS)
+ARCHS = -arch i386 -arch ppc
+CFLAGS = -I/System/Library/Frameworks/JavaScriptCore.framework/Headers -I/System/Library/Frameworks/JavaVM.framework/Headers
+LFLAGS = -bundle -framework JavaScriptCore
+
+ALL : $(TARGETS)
+
+##
+# Unpack and patch SWT source.
+##
+$(SWT_PATCH_DIR): $(SWT_ORIGINAL_SRC) ./org.eclipse.swt/webkit.c
+ unzip $(SWT_ORIGINAL_SRC) -d $(SWT_PATCH_DIR)
+ cp ./org.eclipse.swt/webkit.c $(SWT_PATCH_DIR)
+
+##
+# Build SWT.
+##
+$(SWT_LIBS):$(SWT_PATCH_DIR)
+ make -C $(SWT_PATCH_DIR) -f make_macosx.mak
+
+##
+# Build core gwt-ll object.
+##
+gwt-ll.o : ../core/gwt-ll.cpp
+ $(CC) -c -Wall -o $@ $(ARCHS) $(CFLAGS) $<
+
+##
+# General coff target.
+##
+%.o : %.cpp
+ $(CC) -c -Wall -o $@ $(ARCHS) $(CFLAGS) $<
+
+##
+# Generate JNI Header
+##
+gwt-webkit.h : $(CLASSDIR)/com/google/gwt/dev/shell/mac/LowLevelSaf.class
+ $(JAVAH) -classpath $(CLASSDIR) -o gwt-webkit.h com.google.gwt.dev.shell.mac.LowLevelSaf
+
+##
+# Build gwt-ll library.
+##
+$(GWT_LL_LIB) : $(GWT_LL_JNI) $(GWT_LL_OBJS)
+ $(CC) -Wall -o $@ $(ARCHS) $(LFLAGS) $(GWT_LL_OBJS)
+
+clean:
+ rm -f $(GWT_LL_JNI) $(GWT_LL_OBJS) $(TARGETS)
+ rm -rf $(SWT_PATCH_DIR)
diff --git a/jni/mac/build.xml b/jni/mac/build.xml
new file mode 100755
index 0000000..66b6580
--- /dev/null
+++ b/jni/mac/build.xml
@@ -0,0 +1,18 @@
+<project name="jni-mac" default="build" basedir=".">
+ <property name="gwt.root" location="../.." />
+ <property name="project.tail" value="jni/mac" />
+ <import file="${gwt.root}/common.ant.xml" />
+
+ <target name="build" description="Builds a JNI lib">
+ <mkdir dir="${project.jni}" />
+ <!-- TODO: Actually build this from source! -->
+ <copy todir="${project.jni}">
+ <fileset dir="prebuilt" />
+ </copy>
+ </target>
+
+ <target name="clean" description="Cleans this project's intermediate and output files">
+ <delete dir="${project.build}" failonerror="false" />
+ <delete dir="${project.jni}" failonerror="false" />
+ </target>
+</project>
diff --git a/jni/mac/gwt-webkit.cpp b/jni/mac/gwt-webkit.cpp
new file mode 100644
index 0000000..477b312
--- /dev/null
+++ b/jni/mac/gwt-webkit.cpp
@@ -0,0 +1,886 @@
+/*
+ * Copyright 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+#include <iostream>
+#include <JavaScriptCore/JavaScriptCore.h>
+#include "gwt-webkit.h"
+#include "JStringWrap.h"
+#include "java-dispatch.h"
+#include "trace.h"
+
+
+// http://unixjunkie.blogspot.com/2006/07/access-argc-and-argv-from-anywhere.html
+extern "C" int *_NSGetArgc(void);
+extern "C" char ***_NSGetArgv(void);
+
+/*
+ *
+ */
+JSContextRef ToJSContextRef(jint context) {
+ return reinterpret_cast<JSContextRef>(context);
+}
+
+/*
+ *
+ */
+JSValueRef ToJSValueRef(jint value) {
+ return reinterpret_cast<JSValueRef>(value);
+}
+
+/*
+ *
+ */
+JSObjectRef ToJSObjectRef(JSContextRef jsContext, jint object,
+ JSValueRef* jsException) {
+ JSValueRef jsValue = reinterpret_cast<JSValueRef>(object);
+ if (!jsValue || !JSValueIsObject(jsContext, jsValue)) {
+ return NULL;
+ }
+ return JSValueToObject(jsContext, jsValue, jsException);
+}
+
+/*
+ *
+ */
+JSObjectRef ToJSObjectRef(JSContextRef jsContext, JSValueRef jsValue,
+ JSValueRef* jsException) {
+ if (!jsValue || !JSValueIsObject(jsContext, jsValue)) {
+ return NULL;
+ }
+ return JSValueToObject(jsContext, jsValue, jsException);
+}
+
+/*
+ *
+ */
+JSObjectRef GetStringConstructor(JSContextRef jsContext,
+ JSValueRef* jsException) {
+ // This could only be cached relative to jsContext.
+ JSStringRef script = JSStringCreateWithUTF8CString("(String)");
+ JSValueRef ctorVal = JSEvaluateScript(jsContext, script, NULL, NULL, 0, jsException);
+ JSStringRelease(script);
+ return ToJSObjectRef(jsContext, ctorVal, jsException);
+}
+
+/*
+ *
+ */
+bool IsObjectOfStringConstructor(JSContextRef jsContext, JSValueRef jsValue,
+ JSValueRef* jsException) {
+ JSObjectRef jsObject = ToJSObjectRef(jsContext, jsValue, jsException);
+ if (!jsObject) {
+ return false;
+ }
+ JSObjectRef stringCtor = GetStringConstructor(jsContext, jsException);
+ if (!stringCtor) {
+ return false;
+ }
+ return JSValueIsInstanceOfConstructor(jsContext, jsObject, stringCtor,
+ jsException);
+}
+
+#if 0 // For debugging purposes only.
+void PrintJSString(JSStringRef jsString)
+{
+ size_t length = JSStringGetMaximumUTF8CStringSize(jsString);
+ char* buffer = new char[length];
+ JSStringGetUTF8CString(jsString, buffer, length);
+ std::cerr << "JSString: " << buffer << std::endl;
+ delete[] buffer;
+}
+
+void PrintJSValue(JSContextRef jsContext, JSValueRef jsValue)
+{
+ JSValueRef jsException = NULL;
+ JSStringRef jsResult = JSValueToStringCopy(jsContext, jsValue,
+ &jsException);
+ if (!jsException && jsValue) {
+ PrintJSString(jsResult);
+ } else {
+ std::cerr << "Could not convert the value to string." << std::endl;
+ }
+}
+#endif
+
+/*
+ *
+ */
+JSStringRef ToJSStringRef(JNIEnv* env, jstring jstr) {
+ if (!jstr) {
+ return NULL;
+ }
+
+ JStringWrap jstrw(env, jstr);
+ if (!jstrw.jstr()) {
+ return NULL;
+ }
+
+ return JSStringCreateWithCharacters(static_cast<const JSChar*>(jstrw.jstr()),
+ static_cast<size_t>(jstrw.length()));
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_isJsNull
+ (JNIEnv *env, jclass klass, jint context, jint value) {
+ TR_ENTER();
+ JSContextRef jsContext = ToJSContextRef(context);
+ JSValueRef jsValue = ToJSValueRef(value);
+ if (!jsContext || !jsValue) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+ TR_LEAVE();
+ return static_cast<jboolean>(JSValueIsNull(jsContext, jsValue));
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_isJsUndefined
+ (JNIEnv *env, jclass klass, jint context, jint value) {
+ TR_ENTER();
+ JSContextRef jsContext = ToJSContextRef(context);
+ JSValueRef jsValue = ToJSValueRef(value);
+ if (!jsContext || !jsValue) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+ TR_LEAVE();
+ return static_cast<jboolean>(JSValueIsUndefined(jsContext, jsValue));
+}
+
+/*
+ *
+ */
+JNIEXPORT jint JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_getJsUndefined
+ (JNIEnv *env, jclass klass, jint context) {
+ TR_ENTER();
+ JSContextRef jsContext = ToJSContextRef(context);
+ if (!jsContext) {
+ return static_cast<jint>(NULL);
+ }
+
+ JSValueRef jsUndefined = JSValueMakeUndefined(jsContext);
+ JSValueProtectChecked(jsContext, jsUndefined);
+ TR_LEAVE();
+ return reinterpret_cast<jint>(jsUndefined);
+}
+
+/*
+ *
+ */
+JNIEXPORT jint JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_getJsNull
+ (JNIEnv *env, jclass klass, jint context) {
+ TR_ENTER();
+ JSContextRef jsContext = ToJSContextRef(context);
+ if (!jsContext) {
+ return static_cast<jint>(NULL);
+ }
+ JSValueRef jsNull = JSValueMakeNull(jsContext);
+ JSValueProtectChecked(jsContext, jsNull);
+ TR_LEAVE();
+ return reinterpret_cast<jint>(jsNull);
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_isJsBoolean
+ (JNIEnv *env, jclass klass, jint context, jint value) {
+ TR_ENTER();
+ JSContextRef jsContext = ToJSContextRef(context);
+ JSValueRef jsValue = ToJSValueRef(value);
+ if (!jsContext || !jsValue) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+ TR_LEAVE();
+ return static_cast<jboolean>(JSValueIsBoolean(jsContext, jsValue));
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_isJsNumber
+ (JNIEnv *env, jclass klass, jint context, jint value) {
+ TR_ENTER();
+ JSContextRef jsContext = ToJSContextRef(context);
+ JSValueRef jsValue = ToJSValueRef(value);
+ if (!jsContext || !jsValue) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+ TR_LEAVE();
+ return static_cast<jboolean>(JSValueIsNumber(jsContext, jsValue));
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_toJsBooleanImpl
+ (JNIEnv *env, jclass klass, jint context, jboolean jValue, jintArray rval) {
+ TR_ENTER();
+ JSContextRef jsContext = ToJSContextRef(context);
+ if (!jsContext) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ JSValueRef jsValue = JSValueMakeBoolean(jsContext, static_cast<bool>(jValue));
+
+ env->SetIntArrayRegion(rval, 0, 1, reinterpret_cast<const jint*>(&jsValue));
+ if (env->ExceptionCheck()) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+ JSValueProtectChecked(jsContext, jsValue);
+
+ TR_LEAVE();
+ return JNI_TRUE;
+}
+
+/*
+ *
+ */
+JNIEXPORT void JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_gcUnprotect
+ (JNIEnv *env, jclass klass, jint context, jint value) {
+ TR_ENTER();
+ JSContextRef jsContext = ToJSContextRef(context);
+ JSValueRef jsValue = ToJSValueRef(value);
+ if (!jsContext || !jsValue) {
+ return;
+ }
+ JSValueUnprotectChecked(jsContext, jsValue);
+ TR_LEAVE();
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_toJsNumberImpl
+ (JNIEnv *env, jclass klass, jint context, jdouble jValue, jintArray rval) {
+ TR_ENTER();
+ JSContextRef jsContext = ToJSContextRef(context);
+ if (!jsContext) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ JSValueRef jsValue = JSValueMakeNumber(jsContext, static_cast<jdouble>(jValue));
+
+ env->SetIntArrayRegion(rval, 0, 1, reinterpret_cast<const jint*>(&jsValue));
+ if (env->ExceptionCheck()) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ JSValueProtectChecked(jsContext, jsValue);
+
+ TR_LEAVE();
+ return JNI_TRUE;
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_executeScriptWithInfoImpl
+ (JNIEnv *env, jclass klass, jint context, jstring jScript, jstring jUrl,
+ jint jLine, jintArray rval) {
+ TR_ENTER();
+ JSValueRef jsException = NULL;
+
+ JSContextRef jsContext = ToJSContextRef(context);
+ if (!jsContext) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ JSStringRef jsScript = ToJSStringRef(env, jScript);
+ if (!jsScript) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ JSStringRef jsUrl = ToJSStringRef(env, jUrl);
+
+ // Evaluate will set this to global object.
+ JSValueRef jsResult = JSEvaluateScript(jsContext, jsScript, NULL, jsUrl,
+ static_cast<int>(jLine), &jsException);
+ if (jsException) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ JSStringRelease(jsScript);
+ if (jsUrl) {
+ JSStringRelease(jsUrl);
+ }
+
+ env->SetIntArrayRegion(rval, 0, 1, reinterpret_cast<const jint*>(&jsResult));
+ if (env->ExceptionCheck()) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ JSValueProtectChecked(jsContext, jsResult);
+
+ TR_LEAVE();
+ return JNI_TRUE;
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_toJsStringImpl
+ (JNIEnv *env, jclass klass, jint context, jstring jValue, jintArray rval) {
+ TR_ENTER();
+ JSContextRef jsContext = ToJSContextRef(context);
+ if (!jsContext) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ JSStringRef jsString = ToJSStringRef(env, jValue);
+ if (!jsString) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ JSValueRef jsValue = JSValueMakeString(jsContext, jsString);
+ JSStringRelease(jsString);
+
+ env->SetIntArrayRegion(rval, 0, 1, reinterpret_cast<const jint*>(&jsValue));
+ if (env->ExceptionCheck()) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ JSValueProtectChecked(jsContext, jsValue);
+
+ TR_LEAVE();
+ return JNI_TRUE;
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_isJsStringImpl
+ (JNIEnv *env, jclass klass, jint context, jint value, jbooleanArray rval) {
+ TR_ENTER();
+ JSContextRef jsContext = ToJSContextRef(context);
+ JSValueRef jsValue = ToJSValueRef(value);
+ if (!jsContext || !jsValue) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ bool isString = JSValueIsString(jsContext, jsValue);
+ if (!isString) {
+ JSValueRef jsException = NULL;
+ isString = IsObjectOfStringConstructor(jsContext, jsValue, &jsException);
+ if (jsException) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+ }
+
+ jboolean jIsString = static_cast<jboolean>(isString);
+ env->SetBooleanArrayRegion(rval, 0, 1, &jIsString);
+ if (env->ExceptionCheck()) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ TR_LEAVE();
+ return JNI_TRUE;
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_invokeImpl
+ (JNIEnv *env, jclass klass, jint context, jint scriptValue,
+ jstring jMethodName, jint thisVal, jintArray jArgs, jint jArgsLength,
+ jintArray rval) {
+ TR_ENTER();
+
+ JSContextRef jsContext = ToJSContextRef(context);
+ if (!jsContext) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ JSObjectRef jsScriptObj = ToJSObjectRef(jsContext, scriptValue, NULL);
+ if (!jsScriptObj) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ JSValueRef jsThisVal = ToJSValueRef(thisVal);
+ JSObjectRef jsThisObj = NULL;
+ // If thisVal is null, jsNull, or jsUndefined use the script object
+ // as this.
+ if (!jsThisVal || JSValueIsNull(jsContext, jsThisVal)
+ || JSValueIsUndefined(jsContext, jsThisVal)) {
+ jsThisObj = jsScriptObj;
+ } else {
+ // If we are given a value, ensure that it is an object.
+ jsThisObj = ToJSObjectRef(jsContext, jsThisVal, NULL);
+ if (!jsThisObj) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+ }
+
+ JSStringRef jsMethodName = ToJSStringRef(env, jMethodName);
+ if (!jsMethodName) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ JSObjectRef jsMethod = ToJSObjectRef(jsContext, JSObjectGetProperty(jsContext,
+ jsScriptObj, jsMethodName, NULL), NULL);
+ if (!jsMethod || !JSObjectIsFunction(jsContext, jsMethod)) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ JSStringRelease(jsMethodName);
+
+ // NOTE (knorton): Fix for 64-bit.
+ JSValueRef* jsArgs = new JSValueRef[static_cast<size_t>(jArgsLength)];
+ env->GetIntArrayRegion(jArgs, 0, jArgsLength,
+ reinterpret_cast<jint*>(jsArgs));
+ if (env->ExceptionCheck()) {
+ TR_FAIL();
+ delete[] jsArgs;
+ return JNI_FALSE;
+ }
+
+ JSValueRef jsException = NULL;
+ JSValueRef jsResult = JSObjectCallAsFunction(jsContext, jsMethod, jsThisObj,
+ static_cast<size_t>(jArgsLength), jsArgs, &jsException);
+ if (jsException) {
+ TR_FAIL();
+ delete[] jsArgs;
+ return JNI_FALSE;
+ }
+ delete[] jsArgs;
+
+ env->SetIntArrayRegion(rval, 0, 1, reinterpret_cast<const jint*>(&jsResult));
+ if (env->ExceptionCheck()) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ JSValueProtectChecked(jsContext, jsResult);
+
+ TR_LEAVE();
+ return JNI_TRUE;
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_isJsObject
+ (JNIEnv *env, jclass klass, jint context, jint value) {
+ TR_ENTER();
+ JSContextRef jsContext = ToJSContextRef(context);
+ JSValueRef jsValue = ToJSValueRef(value);
+ if (!jsContext || !jsValue) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ TR_LEAVE();
+ return static_cast<jboolean>(JSValueIsObject(jsContext, jsValue));
+}
+
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_toBooleanImpl
+ (JNIEnv *env, jclass klass, jint context, jint value, jbooleanArray rval) {
+ TR_ENTER();
+ JSContextRef jsContext = ToJSContextRef(context);
+ JSValueRef jsValue = ToJSValueRef(value);
+ if (!jsContext || !jsValue) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ jboolean jResult = static_cast<jboolean>(JSValueToBoolean(jsContext, jsValue));
+ env->SetBooleanArrayRegion(rval, 0, 1, &jResult);
+ if (env->ExceptionCheck()) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ TR_LEAVE();
+ return JNI_TRUE;
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_toDoubleImpl
+ (JNIEnv *env, jclass klass, jint context, jint value, jdoubleArray rval) {
+ TR_ENTER();
+ JSContextRef jsContext = ToJSContextRef(context);
+ JSValueRef jsValue = ToJSValueRef(value);
+ if (!jsContext || !jsValue) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ JSValueRef jsException = NULL;
+ double result = JSValueToNumber(jsContext, jsValue, &jsException);
+ if (jsException) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ env->SetDoubleArrayRegion(rval, 0, 1, static_cast<jdouble*>(&result));
+ if (env->ExceptionCheck()) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ TR_LEAVE();
+ return JNI_TRUE;
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_toStringImpl
+ (JNIEnv *env, jclass klass, jint context, jint value, jobjectArray rval) {
+ TR_ENTER();
+ JSValueRef jsException = NULL;
+ JSContextRef jsContext = ToJSContextRef(context);
+ JSValueRef jsValue = ToJSValueRef(value);
+ if (!jsContext || !jsValue) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ jstring jResult = NULL;
+ // Convert all objects to their string representation, EXCEPT
+ // null and undefined which will be returned as a true NULL.
+ if (!JSValueIsNull(jsContext, jsValue) &&
+ !JSValueIsUndefined(jsContext, jsValue)) {
+ JSStringRef jsResult = JSValueToStringCopy(jsContext, jsValue, &jsException);
+ if (jsException) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ jResult = env->NewString(
+ static_cast<const jchar*>(JSStringGetCharactersPtr(jsResult)),
+ static_cast<jsize>(JSStringGetLength(jsResult)));
+ if (env->ExceptionCheck()) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ JSStringRelease(jsResult);
+ }
+
+ env->SetObjectArrayElement(rval, 0, jResult);
+ if (env->ExceptionCheck()) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ TR_LEAVE();
+ return JNI_TRUE;
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_wrapDispatchObjectImpl
+ (JNIEnv *env, jclass klass, jint context, jobject dispatch, jintArray rval) {
+ TR_ENTER();
+ JSContextRef jsContext = ToJSContextRef(context);
+ if (!jsContext) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ JSObjectRef jsDispatch = gwt::DispatchObjectCreate(jsContext, dispatch);
+ if (!jsDispatch || env->ExceptionCheck()) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ env->SetIntArrayRegion(rval, 0, 1, reinterpret_cast<jint*>(&jsDispatch));
+ if (env->ExceptionCheck()) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ JSValueProtectChecked(jsContext, jsDispatch);
+
+ TR_LEAVE();
+ return JNI_TRUE;
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_unwrapDispatchObjectImpl
+ (JNIEnv *env, jclass klass, jint context, jint value, jobjectArray rval) {
+ TR_ENTER();
+ JSContextRef jsContext = ToJSContextRef(context);
+ JSValueRef jsValue = ToJSValueRef(value);
+ if (!jsContext || !jsValue) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ if (!JSValueIsObjectOfClass(jsContext, jsValue, gwt::GetDispatchObjectClass())) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ JSObjectRef jsObject = ToJSObjectRef(jsContext, jsValue, NULL);
+ if (!jsObject) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ env->SetObjectArrayElement(rval, 0, reinterpret_cast<jobject>(JSObjectGetPrivate(jsObject)));
+ if (env->ExceptionCheck()) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ TR_LEAVE();
+ return JNI_TRUE;
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_initImpl
+ (JNIEnv *env, jclass klass, jclass dispatchObjectClass,
+ jclass dispatchMethodClass, jclass lowLevelSafClass) {
+ TR_ENTER();
+ TR_LEAVE();
+ return static_cast<jboolean>(gwt::Initialize(env, dispatchObjectClass, dispatchMethodClass, lowLevelSafClass));
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_wrapDispatchMethodImpl
+ (JNIEnv *env, jclass klass, jint context, jstring name, jobject jDispatch,
+ jintArray rval) {
+ TR_ENTER();
+ JSContextRef jsContext = ToJSContextRef(context);
+ if (!jsContext) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ JStringWrap nameWrap(env, name);
+ std::string nameStr(nameWrap.str());
+ JSObjectRef jsDispatch = gwt::DispatchMethodCreate(jsContext, nameStr,
+ jDispatch);
+ if (!jsDispatch || env->ExceptionCheck()) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ env->SetIntArrayRegion(rval, 0, 1, reinterpret_cast<jint*>(&jsDispatch));
+ if (env->ExceptionCheck()) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ JSValueProtectChecked(jsContext, jsDispatch);
+
+ TR_LEAVE();
+ return JNI_TRUE;
+}
+
+/*
+ *
+ */
+JNIEXPORT jstring JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_getTypeString
+ (JNIEnv *env, jclass klass, jint context, jint value) {
+ TR_ENTER();
+ JSContextRef jsContext = ToJSContextRef(context);
+ JSValueRef jsValue = ToJSValueRef(value);
+ if (!jsContext || !jsValue) {
+ return NULL;
+ }
+
+ switch (JSValueGetType(jsContext, jsValue)) {
+ case kJSTypeUndefined:
+ return env->NewStringUTF("undefined");
+ case kJSTypeNull:
+ return env->NewStringUTF("null");
+ case kJSTypeBoolean:
+ return env->NewStringUTF("boolean");
+ case kJSTypeNumber:
+ return env->NewStringUTF("number");
+ case kJSTypeString:
+ return env->NewStringUTF("string");
+ case kJSTypeObject:
+ return (JSValueIsObjectOfClass(jsContext, jsValue, gwt::GetDispatchObjectClass()))
+ ? env->NewStringUTF("Java object") : env->NewStringUTF("JavaScript object");
+ default:
+ return env->NewStringUTF("unknown");
+ }
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_isDispatchObjectImpl
+ (JNIEnv *env, jclass klass, jint context, jint value, jbooleanArray rval) {
+ TR_ENTER();
+ JSContextRef jsContext = ToJSContextRef(context);
+ JSValueRef jsValue = ToJSValueRef(value);
+ if (!jsContext || !jsValue) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ jboolean jIsDispatchObject = static_cast<jboolean>(JSValueIsObjectOfClass(
+ jsContext, jsValue, gwt::GetDispatchObjectClass()));
+ env->SetBooleanArrayRegion(rval, 0, 1, &jIsDispatchObject);
+ if (env->ExceptionCheck()) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ TR_LEAVE();
+ return JNI_TRUE;
+}
+
+/*
+ *
+ */
+JNIEXPORT jint JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_getArgc
+ (JNIEnv *env, jclass klass) {
+ return *_NSGetArgc();
+}
+
+/*
+ *
+ */
+JNIEXPORT jstring JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_getArgv
+ (JNIEnv *env, jclass klass, jint index) {
+ int argc = *_NSGetArgc();
+ if (index < 0 || index >= argc) {
+ return 0;
+ }
+ char **argv = *_NSGetArgv();
+ return env->NewStringUTF(argv[index]);
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_getGlobalJsObjectImpl
+ (JNIEnv *env, jclass klass, jint context, jintArray rval) {
+ TR_ENTER();
+
+ JSContextRef jsContext = ToJSContextRef(context);
+ if (!jsContext) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ JSObjectRef jsGlobalObject = JSContextGetGlobalObject(jsContext);
+ env->SetIntArrayRegion(rval, 0, 1, reinterpret_cast<jint*>(&jsGlobalObject));
+ if (env->ExceptionCheck()) {
+ TR_FAIL();
+ return JNI_FALSE;
+ }
+
+ JSValueProtectChecked(jsContext, jsGlobalObject);
+
+ TR_LEAVE();
+ return JNI_TRUE;
+}
+
+/*
+ *
+ */
+JNIEXPORT void JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_gcProtect
+ (JNIEnv *env, jclass klass, jint context, jint value) {
+ TR_ENTER();
+
+ JSContextRef jsContext = ToJSContextRef(context);
+ JSValueRef jsValue = ToJSValueRef(value);
+ if (!jsContext || !jsValue) {
+ return;
+ }
+
+ JSValueProtectChecked(jsContext, jsValue);
+ TR_LEAVE();
+}
+
+/*
+ *
+ */
+JNIEXPORT void JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_retainJsGlobalContext
+ (JNIEnv *env, jclass klass, jint context) {
+ TR_ENTER();
+ JSGlobalContextRef jsContext = reinterpret_cast<JSGlobalContextRef>(context);
+ if (!jsContext) {
+ TR_FAIL();
+ return;
+ }
+ JSGlobalContextRetain(jsContext);
+ TR_LEAVE();
+}
+
+/*
+ *
+ */
+JNIEXPORT void JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_releaseJsGlobalContext
+ (JNIEnv *env, jclass klass, jint context) {
+ TR_ENTER();
+ JSGlobalContextRef jsContext = reinterpret_cast<JSGlobalContextRef>(context);
+ if (!jsContext) {
+ TR_FAIL();
+ return;
+ }
+ JSGlobalContextRelease(jsContext);
+ TR_LEAVE();
+}
+
+/*
+ *
+ */
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_isGcProtected
+ (JNIEnv *env, jclass klass, jint value) {
+ JSValueRef jsValue = ToJSValueRef(value);
+ TR_ENTER();
+ TR_LEAVE();
+ return static_cast<jboolean>(JSValueIsProtected(jsValue));
+}
+
+JNIEXPORT jboolean JNICALL Java_com_google_gwt_dev_shell_mac_LowLevelSaf_isJsValueProtectionCheckingEnabledImpl
+ (JNIEnv *env, jclass klass) {
+ TR_ENTER();
+ TR_LEAVE();
+ return static_cast<jboolean>(JSValueProtectCheckingIsEnabled());
+}
diff --git a/jni/mac/java-dispatch.cpp b/jni/mac/java-dispatch.cpp
new file mode 100644
index 0000000..fafab11
--- /dev/null
+++ b/jni/mac/java-dispatch.cpp
@@ -0,0 +1,524 @@
+/*
+ * Copyright 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+#include <string>
+#include <sstream>
+#include "jni.h"
+#include "java-dispatch.h"
+#include "trace.h"
+#include "JStringWrap.h"
+
+namespace gwt {
+
+ /*
+ * Declarations for private functions.
+ */
+ JSClassRef DispatchObjectClassCreate();
+
+ JSClassRef DispatchMethodClassCreate();
+
+ JSValueRef DispatchObjectGetProperty(JSContextRef, JSObjectRef, JSStringRef,
+ JSValueRef*);
+
+ JSValueRef DispatchObjectToString(JSContextRef, JSObjectRef, JSObjectRef,
+ size_t, const JSValueRef*, JSValueRef*);
+
+ bool DispatchObjectSetProperty(JSContextRef, JSObjectRef, JSStringRef,
+ JSValueRef, JSValueRef*);
+
+ void DispatchObjectFinalize(JSObjectRef);
+
+ JSValueRef DispatchMethodCallAsFunction(JSContextRef, JSObjectRef,
+ JSObjectRef, size_t,
+ const JSValueRef*, JSValueRef*);
+
+ JSValueRef DispatchMethodGetToString(JSContextRef, JSObjectRef, JSStringRef,
+ JSValueRef*);
+
+ JSValueRef DispatchMethodToString(JSContextRef, JSObjectRef, JSObjectRef,
+ size_t, const JSValueRef*, JSValueRef*);
+
+ void DispatchMethodFinalize(JSObjectRef);
+
+ /*
+ * Call this when an underlying Java Object should be freed.
+ */
+ void ReleaseJavaObject(jobject jObject);
+
+
+ /*
+ * The class definition stuct for DispatchObjects.
+ */
+ static JSClassDefinition _dispatchObjectClassDef = { 0,
+ kJSClassAttributeNone, "DispatchObject", 0, 0, 0, 0,
+ DispatchObjectFinalize, 0, DispatchObjectGetProperty,
+ DispatchObjectSetProperty, 0, 0, 0, 0, 0, 0 };
+
+ /*
+ * The class definition structs for DispatchMethods.
+ */
+ static JSStaticValue _dispatchMethodStaticValues[] = {
+ { "toString", DispatchMethodGetToString, 0, kJSPropertyAttributeNone },
+ { 0, 0, 0, 0 }
+ };
+ static JSClassDefinition _dispatchMethodClassDef = { 0,
+ kJSClassAttributeNoAutomaticPrototype, "DispatchMethod", 0,
+ _dispatchMethodStaticValues, 0, 0, DispatchMethodFinalize, 0, 0, 0, 0,
+ 0, DispatchMethodCallAsFunction, 0, 0, 0 };
+
+ /*
+ * The classes used to create DispatchObjects and DispatchMethods.
+ */
+ static JSClassRef _dispatchObjectClass = DispatchObjectClassCreate();
+ static JSClassRef _dispatchMethodClass = DispatchMethodClassCreate();
+
+ /*
+ * Java class and method references needed to do delegation.
+ */
+
+ /*
+ * The main JVM, used by foreign threads to attach.
+ */
+ static JavaVM* _javaVM;
+
+ /*
+ * Only valid for the main thread! WebKit can finalized on a foreign thread.
+ */
+ static JNIEnv* _javaEnv;
+
+ static jclass _javaDispatchObjectClass;
+ static jclass _javaDispatchMethodClass;
+ static jclass _lowLevelSafClass;
+ static jmethodID _javaDispatchObjectSetFieldMethod;
+ static jmethodID _javaDispatchObjectGetFieldMethod;
+ static jmethodID _javaDispatchMethodInvokeMethod;
+ static jmethodID _javaDispatchObjectToStringMethod;
+ static jmethodID _lowLevelSafReleaseObject;
+
+ /*
+ * Structure to hold DispatchMethod private data.
+ *
+ * NOTE: utf8Name is defensively copied.
+ */
+ class DispatchMethodData {
+ public:
+ DispatchMethodData(jobject jObject, std::string& utf8Name)
+ : _jObject(jObject), _utf8Name(utf8Name) { }
+ ~DispatchMethodData() {
+ ReleaseJavaObject(_jObject);
+ }
+ jobject _jObject;
+ std::string _utf8Name;
+ };
+
+/*
+ * The following takes the prototype from the Function constructor, this allows
+ * us to easily support call and apply on our objects that support CallAsFunction.
+ *
+ * NOTE: The return value is not protected.
+ */
+JSValueRef GetFunctionPrototype(JSContextRef jsContext, JSValueRef* exception) {
+ TR_ENTER();
+ JSObjectRef globalObject = JSContextGetGlobalObject(jsContext);
+ JSStringRef fnPropName= JSStringCreateWithUTF8CString("Function");
+ JSValueRef fnCtorValue = JSObjectGetProperty(jsContext, globalObject,
+ fnPropName, exception);
+ JSStringRelease(fnPropName);
+ if (!fnCtorValue) {
+ return JSValueMakeUndefined(jsContext);
+ }
+
+ JSObjectRef fnCtorObject = JSValueToObject(jsContext, fnCtorValue, exception);
+ if (!fnCtorObject) {
+ return JSValueMakeUndefined(jsContext);
+ }
+
+ JSStringRef protoPropName = JSStringCreateWithUTF8CString("prototype");
+ JSValueRef fnPrototype = JSObjectGetProperty(jsContext, fnCtorObject,
+ protoPropName, exception);
+ JSStringRelease(protoPropName);
+ if (!fnPrototype) {
+ return JSValueMakeUndefined(jsContext);
+ }
+
+ TR_LEAVE();
+ return fnPrototype;
+}
+
+/*
+ *
+ */
+JSClassRef GetDispatchObjectClass() {
+ TR_ENTER();
+ TR_LEAVE();
+ return _dispatchObjectClass;
+}
+
+/*
+ *
+ */
+JSClassRef GetDispatchMethodClass() {
+ TR_ENTER();
+ TR_LEAVE();
+ return _dispatchMethodClass;
+}
+
+/*
+ *
+ */
+JSClassRef DispatchObjectClassCreate() {
+ TR_ENTER();
+ JSClassRef dispClass = JSClassCreate(&_dispatchObjectClassDef);
+ JSClassRetain(dispClass);
+ TR_LEAVE();
+ return dispClass;
+}
+
+/*
+ *
+ */
+JSClassRef DispatchMethodClassCreate() {
+ TR_ENTER();
+ JSClassRef dispClass = JSClassCreate(&_dispatchMethodClassDef);
+ JSClassRetain(dispClass);
+ TR_LEAVE();
+ return dispClass;
+}
+
+/*
+ * NOTE: The object returned from this function is not protected.
+ */
+JSObjectRef DispatchObjectCreate(JSContextRef jsContext, jobject jObject) {
+ TR_ENTER();
+ JSObjectRef dispInst = JSObjectMake(jsContext, _dispatchObjectClass,
+ _javaEnv->NewGlobalRef(jObject));
+ TR_LEAVE();
+ return dispInst;
+}
+
+/*
+ * NOTE: The object returned from this function is not protected.
+ */
+JSObjectRef DispatchMethodCreate(JSContextRef jsContext, std::string& name,
+ jobject jObject) {
+ TR_ENTER();
+
+ JSObjectRef dispInst = JSObjectMake(jsContext, _dispatchMethodClass,
+ new DispatchMethodData(_javaEnv->NewGlobalRef(jObject), name));
+
+ // This could only be cached relative to jsContext.
+ JSValueRef fnProtoValue = GetFunctionPrototype(jsContext, NULL);
+ JSObjectSetPrototype(jsContext, dispInst, fnProtoValue);
+ TR_LEAVE();
+ return dispInst;
+}
+
+/*
+ * NOTE: The value returned from this function is not protected, but all
+ * JSValues that are passed into Java are protected before the invocation.
+ */
+JSValueRef DispatchObjectGetProperty(JSContextRef jsContext,
+ JSObjectRef jsObject, JSStringRef jsPropertyName,
+ JSValueRef* jsException) {
+ TR_ENTER();
+
+ // If you call toString on a DispatchObject, you should get the results
+ // of the java object's toString invcation.
+ if (JSStringIsEqualToUTF8CString(jsPropertyName, "toString")) {
+ JSObjectRef jsFunction = JSObjectMakeFunctionWithCallback(jsContext,
+ jsPropertyName, DispatchObjectToString);
+ return jsFunction;
+ }
+
+ // The class check is omitted because it should not be possible to tear off
+ // a getter.
+ jobject jObject = reinterpret_cast<jobject>(JSObjectGetPrivate(jsObject));
+
+ jstring jPropertyName = _javaEnv->NewString(
+ static_cast<const jchar*>(JSStringGetCharactersPtr(jsPropertyName)),
+ static_cast<jsize>(JSStringGetLength(jsPropertyName)));
+ if (!jObject || !jPropertyName || _javaEnv->ExceptionCheck()) {
+ TR_FAIL();
+ _javaEnv->ExceptionClear();
+ return JSValueMakeUndefined(jsContext);
+ }
+
+ JSValueRef jsResult = reinterpret_cast<JSValueRef>(
+ _javaEnv->CallIntMethod(jObject, _javaDispatchObjectGetFieldMethod,
+ reinterpret_cast<jint>(jsContext),
+ jPropertyName));
+ if (!jsResult || _javaEnv->ExceptionCheck()) {
+ TR_FAIL();
+ _javaEnv->ExceptionClear();
+ return JSValueMakeUndefined(jsContext);
+ }
+
+ // Java left us an extra reference to eat.
+ JSValueUnprotectChecked(jsContext, jsResult);
+ TR_LEAVE();
+ return jsResult;
+}
+
+/*
+ *
+ */
+bool DispatchObjectSetProperty(JSContextRef jsContext, JSObjectRef jsObject,
+ JSStringRef jsPropertyName, JSValueRef jsValue, JSValueRef* jsException) {
+ TR_ENTER();
+
+ // The class check is omitted because it should not be possible to tear off
+ // a getter.
+ jobject jObject = reinterpret_cast<jobject>(JSObjectGetPrivate(jsObject));
+
+ jstring jPropertyName = _javaEnv->NewString(
+ static_cast<const jchar*>(JSStringGetCharactersPtr(jsPropertyName)),
+ static_cast<jsize>(JSStringGetLength(jsPropertyName)));
+ if (!jObject || !jPropertyName || _javaEnv->ExceptionCheck()) {
+ _javaEnv->ExceptionClear();
+ return false;
+ }
+
+ JSValueProtectChecked(jsContext, jsValue);
+
+ _javaEnv->CallIntMethod(jObject, _javaDispatchObjectSetFieldMethod,
+ reinterpret_cast<jint>(jsContext), jPropertyName,
+ reinterpret_cast<jint>(jsValue));
+ if (_javaEnv->ExceptionCheck()) {
+ _javaEnv->ExceptionClear();
+ return false;
+ }
+
+ TR_LEAVE();
+ return true;
+}
+
+/*
+ *
+ */
+void DispatchObjectFinalize(JSObjectRef jsObject) {
+ TR_ENTER();
+ jobject jObject = reinterpret_cast<jobject>(JSObjectGetPrivate(jsObject));
+ ReleaseJavaObject(jObject);
+ TR_LEAVE();
+}
+
+/*
+ *
+ */
+void DispatchMethodFinalize(JSObjectRef jsObject) {
+ TR_ENTER();
+ DispatchMethodData* data = reinterpret_cast<DispatchMethodData*>(
+ JSObjectGetPrivate(jsObject));
+ delete data;
+ TR_LEAVE();
+}
+
+/*
+ * NOTE: The value returned from this function is not protected.
+ */
+JSValueRef DispatchObjectToString(JSContextRef jsContext, JSObjectRef,
+ JSObjectRef jsThis, size_t, const JSValueRef*, JSValueRef*) {
+ TR_ENTER();
+
+ // This function cannot be torn off and applied to any JSValue. If this does
+ // not reference a DispatchObject, return undefined.
+ if (!JSValueIsObjectOfClass(jsContext, jsThis, GetDispatchObjectClass())) {
+ return JSValueMakeUndefined(jsContext);
+ }
+
+ jobject jObject = reinterpret_cast<jobject>(JSObjectGetPrivate(jsThis));
+ jstring jResult = reinterpret_cast<jstring>(
+ _javaEnv->CallObjectMethod(jObject, _javaDispatchObjectToStringMethod));
+ if (_javaEnv->ExceptionCheck()) {
+ return JSValueMakeUndefined(jsContext);
+ } else if (!jResult) {
+ return JSValueMakeNull(jsContext);
+ } else {
+ JStringWrap result(_javaEnv, jResult);
+ JSStringRef resultString = JSStringCreateWithCharacters(
+ static_cast<const JSChar*>(result.jstr()),
+ static_cast<size_t>(result.length()));
+ JSValueRef jsResultString = JSValueMakeString(jsContext, resultString);
+ JSStringRelease(resultString);
+ return jsResultString;
+ }
+ TR_LEAVE();
+}
+
+/*
+ *
+ */
+JSValueRef DispatchMethodCallAsFunction(JSContextRef jsContext,
+ JSObjectRef jsFunction, JSObjectRef jsThis, size_t argumentCount,
+ const JSValueRef arguments[], JSValueRef* exception) {
+ TR_ENTER();
+
+ // We don't need to check the class here because we take the private
+ // data from jsFunction and not jsThis.
+
+ DispatchMethodData* data = reinterpret_cast<DispatchMethodData*>(
+ JSObjectGetPrivate(jsFunction));
+ jobject jObject = data->_jObject;
+
+ jintArray jArguments = _javaEnv->NewIntArray(argumentCount);
+ if (!jArguments || _javaEnv->ExceptionCheck()) {
+ return JSValueMakeUndefined(jsContext);
+ }
+
+ // This single element int array will be passed into the java call to allow the
+ // called java method to raise an exception. We will check for a non-null value
+ // after the call is dispatched.
+ jintArray jException = _javaEnv->NewIntArray(1);
+ if (!jException || _javaEnv->ExceptionCheck()) {
+ return JNI_FALSE;
+ }
+
+ for (size_t i = 0; i < argumentCount; ++i) {
+ JSValueRef arg = arguments[i];
+ // Java will take ownership of the arguments.
+ JSValueProtectChecked(jsContext, arg);
+ _javaEnv->SetIntArrayRegion(jArguments, i, 1, reinterpret_cast<jint*>(&arg));
+ if (_javaEnv->ExceptionCheck()) {
+ return JSValueMakeUndefined(jsContext);
+ }
+ }
+
+ // Java will take ownership of this.
+ JSValueProtectChecked(jsContext, jsThis);
+
+ JSValueRef jsResult = reinterpret_cast<JSValueRef>(_javaEnv->CallIntMethod(jObject,
+ _javaDispatchMethodInvokeMethod, reinterpret_cast<jint>(jsContext),
+ reinterpret_cast<jint>(jsThis), jArguments, jException));
+ if (_javaEnv->ExceptionCheck()) {
+ return JSValueMakeUndefined(jsContext);
+ }
+
+ JSValueRef jsException = NULL;
+ _javaEnv->GetIntArrayRegion(jException, 0, 1, reinterpret_cast<jint*>(&jsException));
+ if (!_javaEnv->ExceptionCheck() && jsException) {
+ // If the java dispatch set an exception, then we pass it back to our caller.
+ if (exception) {
+ *exception = jsException;
+ }
+ // Java left us an extra reference to eat.
+ JSValueUnprotectChecked(jsContext, jsException);
+ }
+
+ // Java left us an extra reference to eat.
+ JSValueUnprotectChecked(jsContext, jsResult);
+ TR_LEAVE();
+ return jsResult;
+}
+
+/*
+ * NOTE: The object returned from this function is not protected.
+ */
+JSValueRef DispatchMethodToString(JSContextRef jsContext, JSObjectRef,
+ JSObjectRef thisObject, size_t, const JSValueRef*, JSValueRef*) {
+ TR_ENTER();
+
+ // This function cannot be torn off and applied to any JSValue. If this does
+ // not reference a DispatchMethod, return undefined.
+ if (!JSValueIsObjectOfClass(jsContext, thisObject, GetDispatchMethodClass())) {
+ return JSValueMakeUndefined(jsContext);
+ }
+
+ std::ostringstream ss;
+ DispatchMethodData* data = reinterpret_cast<DispatchMethodData*>(
+ JSObjectGetPrivate(thisObject));
+ ss << "function " << data->_utf8Name << "() {\n [native code]\n}\n";
+ JSStringRef stringRep = JSStringCreateWithUTF8CString(ss.str().c_str());
+ JSValueRef jsStringRep = JSValueMakeString(jsContext, stringRep);
+ JSStringRelease(stringRep);
+ TR_LEAVE();
+ return jsStringRep;
+}
+
+/*
+ * NOTE: The object returned from this function is not protected.
+ */
+JSValueRef DispatchMethodGetToString(JSContextRef jsContext,
+ JSObjectRef jsObject, JSStringRef jsPropertyName, JSValueRef* jsException) {
+ TR_ENTER();
+ JSObjectRef toStringFn = JSObjectMakeFunctionWithCallback(jsContext,
+ jsPropertyName, DispatchMethodToString);
+ TR_LEAVE();
+ return toStringFn;
+}
+
+/*
+ *
+ */
+bool Initialize(JNIEnv* javaEnv, jclass javaDispatchObjectClass,
+ jclass javaDispatchMethodClass, jclass lowLevelSafClass) {
+ TR_ENTER();
+ if (!javaEnv || !javaDispatchObjectClass || !javaDispatchMethodClass
+ || !lowLevelSafClass) {
+ return false;
+ }
+
+ _javaVM = 0;
+ javaEnv->GetJavaVM(&_javaVM);
+
+ _javaEnv = javaEnv;
+ _javaDispatchObjectClass = static_cast<jclass>(
+ javaEnv->NewGlobalRef(javaDispatchObjectClass));
+ _javaDispatchMethodClass = static_cast<jclass>(
+ javaEnv->NewGlobalRef(javaDispatchMethodClass));
+ _lowLevelSafClass = static_cast<jclass>(
+ javaEnv->NewGlobalRef(lowLevelSafClass));
+ _javaDispatchObjectSetFieldMethod = javaEnv->GetMethodID(
+ javaDispatchObjectClass, "setField", "(ILjava/lang/String;I)V");
+ _javaDispatchObjectGetFieldMethod = javaEnv->GetMethodID(
+ javaDispatchObjectClass, "getField", "(ILjava/lang/String;)I");
+ _javaDispatchMethodInvokeMethod = javaEnv->GetMethodID(
+ javaDispatchMethodClass, "invoke", "(II[I[I)I");
+ _javaDispatchObjectToStringMethod = javaEnv->GetMethodID(
+ javaDispatchObjectClass, "toString", "()Ljava/lang/String;");
+ _lowLevelSafReleaseObject = javaEnv->GetStaticMethodID(
+ lowLevelSafClass, "releaseObject", "(Ljava/lang/Object;)V");
+
+ if (!_javaVM
+ || !_javaDispatchObjectSetFieldMethod || !_javaDispatchObjectGetFieldMethod
+ || !_javaDispatchMethodInvokeMethod || !_javaDispatchObjectToStringMethod
+ || !_lowLevelSafReleaseObject || javaEnv->ExceptionCheck()) {
+ return false;
+ }
+
+ TR_LEAVE();
+ return true;
+}
+
+void ReleaseJavaObject(jobject jObject) {
+ // Tricky: this call may be on a foreign thread.
+ JNIEnv* javaEnv = 0;
+ if ((_javaVM->AttachCurrentThreadAsDaemon(reinterpret_cast<void**>(&javaEnv),
+ NULL) < 0) || !javaEnv) {
+ TR_FAIL();
+ return;
+ }
+
+ // Tell the Java code we're done with this object.
+ javaEnv->CallStaticVoidMethod(_lowLevelSafClass, _lowLevelSafReleaseObject,
+ jObject);
+ if (javaEnv->ExceptionCheck()) {
+ TR_FAIL();
+ return;
+ }
+ javaEnv->DeleteGlobalRef(jObject);
+}
+
+} // namespace gwt
diff --git a/jni/mac/java-dispatch.h b/jni/mac/java-dispatch.h
new file mode 100644
index 0000000..f8fa80b
--- /dev/null
+++ b/jni/mac/java-dispatch.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+#ifndef JAVA_DISPATCHER_H__
+#define JAVA_DISPATCHER_H__
+#include <iostream>
+#include <JavaScriptCore/JavaScriptCore.h>
+#include <jni.h>
+
+namespace gwt {
+
+/*
+ * Initializes static members needed by DispatchObject, DispatchMethod,
+ * and LowLevelSaf. This should be called before before calling anything
+ * else.
+ */
+bool Initialize(JNIEnv*, jclass, jclass, jclass);
+
+/*
+ * Returns a shared reference to the DispatchObject class
+ */
+JSClassRef GetDispatchObjectClass();
+
+/*
+ * Constructs a new DispatchObject.
+ *
+ * jContext - the JavaScript context
+ * jObject - the java instance of DispatchObject to which
+ * this instance will dispatch calls
+ */
+JSObjectRef DispatchObjectCreate(JSContextRef jContext, jobject jObject);
+
+/*
+ * Returns a shared reference to the DispatchMethod class
+ */
+JSClassRef GetDispatchMethodClass();
+
+/*
+ * Constructs a new DispatchMethod object.
+ *
+ * jsContext - the JavaScript context
+ * name - the name of the method (used in toString)
+ * jObject - the java instance of DispatchMethod to which this object will
+ * delegate calls.
+ */
+JSObjectRef DispatchMethodCreate(JSContextRef jsContext, std::string& name,
+ jobject jObject);
+
+
+} // namespace gwt
+
+#endif // JAVA_DISPATCHER_H__
diff --git a/jni/mac/org.eclipse.swt/webkit.c b/jni/mac/org.eclipse.swt/webkit.c
new file mode 100644
index 0000000..3b704ec
--- /dev/null
+++ b/jni/mac/org.eclipse.swt/webkit.c
@@ -0,0 +1,250 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+// Modified by Google
+#include <Carbon/Carbon.h>
+#include <WebKit/WebKit.h>
+#include <WebKit/HIWebView.h>
+
+#include "jni.h"
+
+JNIEXPORT void JNICALL Java_org_eclipse_swt_browser_WebKit_WebInitForCarbon(JNIEnv *env, jclass zz) {
+ WebInitForCarbon();
+}
+
+JNIEXPORT jint JNICALL Java_org_eclipse_swt_browser_WebKit_HIWebViewCreate(JNIEnv *env, jclass zz, jintArray outView) {
+ jint *a = (*env)->GetIntArrayElements(env, outView, NULL);
+ jint status = (jint) HIWebViewCreate((HIViewRef *)a);
+ (*env)->ReleaseIntArrayElements(env, outView, a, 0);
+ return status;
+}
+
+JNIEXPORT jint JNICALL Java_org_eclipse_swt_browser_WebKit_HIWebViewGetWebView(JNIEnv *env, jclass zz, jint viewRef) {
+ return (jint) HIWebViewGetWebView((HIViewRef)viewRef);
+}
+
+JNIEXPORT jint JNICALL Java_org_eclipse_swt_browser_WebKit_objc_1msgSend__II(JNIEnv *env, jclass zz, jint obj, jint sel) {
+ return (jint) objc_msgSend((void *)obj, (void *)sel);
+}
+
+JNIEXPORT jint JNICALL Java_org_eclipse_swt_browser_WebKit_objc_1msgSend__III(JNIEnv *env, jclass zz, jint obj, jint sel, jint arg0) {
+ return (jint) objc_msgSend((void *)obj, (void *)sel, (void *)arg0);
+}
+
+JNIEXPORT jint JNICALL Java_org_eclipse_swt_browser_WebKit_objc_1msgSend__IIII(JNIEnv *env, jclass zz, jint obj, jint sel, jint arg0, jint arg1) {
+ return (jint) objc_msgSend((void *)obj, (void *)sel, (void *)arg0, (void *)arg1);
+}
+
+JNIEXPORT jint JNICALL Java_org_eclipse_swt_browser_WebKit_objc_1msgSend__IIIII(JNIEnv *env, jclass zz, jint obj, jint sel, jint arg0, jint arg1, jint arg2) {
+ return (jint) objc_msgSend((void *)obj, (void *)sel, (void *)arg0, (void *)arg1, (void *)arg2);
+}
+
+JNIEXPORT jint JNICALL Java_org_eclipse_swt_browser_WebKit_objc_1msgSend__IIIIII(JNIEnv *env, jclass zz, jint obj, jint sel, jint arg0, jint arg1, jint arg2, jint arg3) {
+ return (jint) objc_msgSend((void *)obj, (void *)sel, (void *)arg0, (void *)arg1, (void *)arg2, (void *)arg3);
+}
+
+JNIEXPORT jint JNICALL Java_org_eclipse_swt_browser_WebKit_objc_1getClass(JNIEnv *env, jclass zz, jbyteArray name) {
+ jbyte *a = (*env)->GetByteArrayElements(env, name, NULL);
+ jint id = (jint) objc_getClass((const char *)a);
+ (*env)->ReleaseByteArrayElements(env, name, a, 0);
+ return id;
+}
+
+JNIEXPORT jint JNICALL Java_org_eclipse_swt_browser_WebKit_sel_1registerName(JNIEnv *env, jclass zz, jbyteArray name) {
+ jbyte *a= (*env)->GetByteArrayElements(env, name, NULL);
+ jint sel= (jint) sel_registerName((const char *)a);
+ (*env)->ReleaseByteArrayElements(env, name, a, 0);
+ return sel;
+}
+
+@interface WebKitDelegate : NSObject
+{
+ int user_data;
+ int (*proc) (int sender, int user_data, int selector, int arg0, int arg1, int arg2, int arg3);
+}
+@end
+
+@implementation WebKitDelegate
+
+- (id)initWithProc:(id)prc user_data:(int)data
+{
+ [super init];
+ proc= (void *) prc;
+ user_data = data;
+ return self;
+}
+
+/* WebFrameLoadDelegate */
+
+- (void)webView:(WebView *)sender didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame
+{
+ proc((int)sender, user_data, 1, (int)error, (int)frame, 0, 0);
+}
+
+- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame
+{
+ proc((int)sender, user_data, 2, (int)frame, 0, 0, 0);
+}
+
+- (void)webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame
+{
+ proc((int)sender, user_data, 3, (int)title, (int)frame, 0, 0);
+}
+
+- (void)webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame
+{
+ proc((int)sender, user_data, 4, (int)frame, 0, 0, 0);
+}
+
+- (void)webView:(WebView *)sender didCommitLoadForFrame:(WebFrame *)frame
+{
+ proc((int)sender, user_data, 10, (int)frame, 0, 0, 0);
+}
+
+/* WebResourceLoadDelegate */
+
+- (void)webView:(WebView *)sender resource:(id)identifier didFinishLoadingFromDataSource:(WebDataSource *)dataSource
+{
+ proc((int)sender, user_data, 5, (int)identifier, (int)dataSource, 0, 0);
+}
+
+- (void)webView:(WebView *)sender resource:(id)identifier didFailLoadingWithError:(NSError *)error fromDataSource:(WebDataSource *)dataSource
+{
+ proc((int)sender, user_data, 6, (int)identifier, (int)error, (int)dataSource, 0);
+}
+
+- (id)webView:(WebView *)sender identifierForInitialRequest:(NSURLRequest *)request fromDataSource:(WebDataSource *)dataSource
+{
+ return (id) proc((int)sender, user_data, 7, (int)request, (int)dataSource, 0, 0);
+}
+
+- (NSURLRequest *)webView:(WebView *)sender resource:(id)identifier willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse fromDataSource:(WebDataSource *)dataSource
+{
+ return (NSURLRequest *) proc((int)sender, user_data, 8, (int)identifier, (int)request, (int)redirectResponse, (int)dataSource);
+}
+
+/* handleNotification */
+
+- (void)handleNotification:(NSNotification *)notification
+{
+ proc((int)[notification object], user_data, 9, (int)notification, 0, 0, 0);
+}
+
+/* UIDelegate */
+
+- (WebView *)webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request
+{
+ return (WebView *) proc((int)sender, user_data, 11, (int)request, 0, 0, 0);
+}
+
+- (void)webViewShow:(WebView *)sender
+{
+ proc((int)sender, user_data, 12, 0, 0, 0, 0);
+}
+
+- (void)webView:(WebView *)sender setFrame:(NSRect)frame
+{
+ proc((int)sender, user_data, 13, (int)&frame, 0, 0, 0);
+}
+
+- (void)webViewClose:(WebView *)sender
+{
+ proc((int)sender, user_data, 14, 0, 0, 0, 0);
+}
+
+- (NSArray *)webView:(WebView *)sender contextMenuItemsForElement:(NSDictionary *)element defaultMenuItems:(NSArray *)defaultMenuItems
+{
+ return (NSArray *)proc((int)sender, user_data, 15, (int)element, (int)defaultMenuItems, 0, 0);
+}
+
+- (void)webView:(WebView *)sender setStatusBarVisible:(BOOL)visible
+{
+ proc((int)sender, user_data, 16, (int)visible, 0, 0, 0);
+}
+
+- (void)webView:(WebView *)sender setResizable:(BOOL)resizable
+{
+ proc((int)sender, user_data, 17, (int)resizable, 0, 0, 0);
+}
+
+- (void)webView:(WebView *)sender setToolbarsVisible:(BOOL)visible
+{
+ proc((int)sender, user_data, 18, (int)visible, 0, 0, 0);
+}
+
+- (void)webView:(WebView *)sender setStatusText:(NSString *)text
+{
+ proc((int)sender, user_data, 23, (int)text, 0, 0, 0);
+}
+
+- (void)webViewFocus:(WebView *)sender
+{
+ proc((int)sender, user_data, 24, 0, 0, 0, 0);
+}
+
+- (void)webViewUnfocus:(WebView *)sender
+{
+ proc((int)sender, user_data, 25, 0, 0, 0, 0);
+}
+
+- (void)webView:(WebView *)sender runJavaScriptAlertPanelWithMessage:(NSString *)message
+{
+ proc((int)sender, user_data, 26, (int)message, 0, 0, 0);
+}
+
+- (BOOL)webView:(WebView *)sender runJavaScriptConfirmPanelWithMessage:(NSString *)message
+{
+ return (BOOL) proc((int)sender, user_data, 27, (int)message, 0, 0, 0);
+}
+
+- (void)webView:(WebView *)sender runOpenPanelForFileButtonWithResultListener:(id<WebOpenPanelResultListener>)resultListener
+{
+ proc((int)sender, user_data, 28, (int)resultListener, 0, 0, 0);
+}
+
+/* WebPolicyDelegate */
+- (void)webView:(WebView *)sender decidePolicyForMIMEType:(NSString *)type request:(NSURLRequest *)request frame:(WebFrame*)frame decisionListener:(id<WebPolicyDecisionListener>)listener
+{
+ proc((int)sender, user_data, 19, (int)type, (int)request, (int)frame, (int)listener);
+}
+
+- (void)webView:(WebView *)sender decidePolicyForNavigationAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id<WebPolicyDecisionListener>)listener
+{
+ proc((int)sender, user_data, 20, (int)actionInformation, (int)request, (int)frame, (int)listener);
+}
+
+
+- (void)webView:(WebView *)sender decidePolicyForNewWindowAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request newFrameName:(NSString *)frameName decisionListener:(id<WebPolicyDecisionListener>)listener
+{
+ proc((int)sender, user_data, 21, (int)actionInformation, (int)request, (int)frameName, (int)listener);
+}
+
+
+- (void)webView:(WebView *)sender unableToImplementPolicyWithError:(NSError *)error frame:(WebFrame *)frame
+{
+ proc((int)sender, user_data, 22, (int)error, (int)frame, 0, 0);
+}
+
+/* WebDownload */
+
+- (void)download:(NSURLDownload *)download decideDestinationWithSuggestedFilename:(NSString *)filename
+{
+ proc((int)download, user_data, 29, (int)download, (int)filename, 0, 0);
+}
+
+// GOOGLE: we need a notification when the window object is available so we can
+// setup our own hooks before any JavaScript runs.
+- (void)webView:(WebView *)sender windowScriptObjectAvailable:(WebScriptObject *)windowScriptObject
+{
+ proc((int)sender, user_data, 99, (int)windowScriptObject, 0, 0, 0);
+}
+
+@end
+
diff --git a/jni/mac/prebuilt/libgwt-ll.jnilib b/jni/mac/prebuilt/libgwt-ll.jnilib
new file mode 100755
index 0000000..5a4030f
--- /dev/null
+++ b/jni/mac/prebuilt/libgwt-ll.jnilib
Binary files differ
diff --git a/jni/mac/trace.cpp b/jni/mac/trace.cpp
new file mode 100644
index 0000000..2127351
--- /dev/null
+++ b/jni/mac/trace.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+#include <iostream>
+#include <map>
+#include <JavaScriptCore/JavaScriptCore.h>
+#include "trace.h"
+
+#ifdef ENABLE_JSVALUE_PROTECTION_CHECKING
+static std::map<JSValueRef, int> _protectMap;
+#endif
+
+/*
+ *
+ */
+void JSValueProtectChecked(JSContextRef jsContext, JSValueRef jsValue) {
+ JSValueProtect(jsContext, jsValue);
+#ifdef ENABLE_JSVALUE_PROTECTION_CHECKING
+ _protectMap[jsValue]++;
+#endif
+}
+
+/*
+ *
+ */
+void JSValueUnprotectChecked(JSContextRef jsContext, JSValueRef jsValue) {
+#ifdef ENABLE_JSVALUE_PROTECTION_CHECKING
+ // Unrecord in a hash_map
+ unsigned count = _protectMap[jsValue];
+ if (count == 0) {
+ std::cerr << "[WARNING] JSValueUnprotect called on unprotected JSValueRef (0x"
+ << std::hex << ((unsigned)jsValue) << ")" << std::endl;
+ return;
+ }
+ _protectMap[jsValue] = count - 1;
+#else
+ JSValueUnprotect(jsContext, jsValue);
+#endif
+}
+
+bool JSValueIsProtected(JSValueRef jsValue) {
+#ifdef ENABLE_JSVALUE_PROTECTION_CHECKING
+ return _protectMap[jsValue] > 0;
+#else
+ return true;
+#endif
+}
+
+bool JSValueProtectCheckingIsEnabled() {
+#ifdef ENABLE_JSVALUE_PROTECTION_CHECKING
+ return true;
+#else
+ return false;
+#endif
+}
diff --git a/jni/mac/trace.h b/jni/mac/trace.h
new file mode 100644
index 0000000..e58ca96
--- /dev/null
+++ b/jni/mac/trace.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+#ifndef TRACE_H__
+#define TRACE_H__
+#include <iostream>
+#include <map>
+
+// Uncomment to trace enter, exit and fail for all native calls.
+// #define ENABLE_CALL_TRACE
+
+// Uncomment to double check that JSValueRef's are protected and
+// unprotected properly.
+// #define ENABLE_JSVALUE_PROTECTION_CHECKING
+
+#ifdef ENABLE_CALL_TRACE
+#define TR_ENTER() std::cout << "ENTER " << __PRETTY_FUNCTION__ << std::endl
+#define TR_LEAVE() std::cout << "LEAVE " << __PRETTY_FUNCTION__ << std::endl
+#define TR_FAIL() std::cout << "FAIL " << __FILE__ << "@" << __LINE__ \
+ << std::endl;
+#else
+#define TR_ENTER()
+#define TR_LEAVE()
+#define TR_FAIL()
+#endif // ENABLE_CALL_TRACE
+
+void JSValueUnprotectChecked(JSContextRef, JSValueRef);
+void JSValueProtectChecked(JSContextRef, JSValueRef);
+bool JSValueIsProtected(JSValueRef jsValue);
+bool JSValueProtectCheckingIsEnabled();
+
+#endif // TRACE_H__