diff options
8 files changed, 139 insertions, 17 deletions
diff --git a/Source/WebCore/bridge/jni/v8/JNIUtilityPrivate.cpp b/Source/WebCore/bridge/jni/v8/JNIUtilityPrivate.cpp index 15b4bda..c6e0a6c 100644 --- a/Source/WebCore/bridge/jni/v8/JNIUtilityPrivate.cpp +++ b/Source/WebCore/bridge/jni/v8/JNIUtilityPrivate.cpp @@ -206,7 +206,7 @@ JavaValue convertNPVariantToJavaValue(NPVariant value, const String& javaClass) break; } - result.m_objectValue = adoptRef(new JavaInstanceJobject(javaArray)); + result.m_objectValue = adoptRef(new JavaInstanceJobject(javaArray, false)); env->DeleteLocalRef(javaArray); } break; @@ -421,7 +421,11 @@ void convertJavaValueToNPVariant(JavaValue value, NPVariant* result) } } +#if PLATFORM(ANDROID) +JavaValue jvalueToJavaValue(const jvalue& value, const JavaType& type, bool requireAnnotation) +#else JavaValue jvalueToJavaValue(const jvalue& value, const JavaType& type) +#endif { JavaValue result; result.m_type = type; @@ -429,7 +433,11 @@ JavaValue jvalueToJavaValue(const jvalue& value, const JavaType& type) case JavaTypeVoid: break; case JavaTypeObject: +#if PLATFORM(ANDROID) + result.m_objectValue = new JavaInstanceJobject(value.l, requireAnnotation); +#else result.m_objectValue = new JavaInstanceJobject(value.l); +#endif break; case JavaTypeString: { diff --git a/Source/WebCore/bridge/jni/v8/JNIUtilityPrivate.h b/Source/WebCore/bridge/jni/v8/JNIUtilityPrivate.h index 0282904..47ee45a 100644 --- a/Source/WebCore/bridge/jni/v8/JNIUtilityPrivate.h +++ b/Source/WebCore/bridge/jni/v8/JNIUtilityPrivate.h @@ -41,7 +41,11 @@ class JavaValue; JavaValue convertNPVariantToJavaValue(NPVariant, const String& javaClass); void convertJavaValueToNPVariant(JavaValue, NPVariant*); +#if PLATFORM(ANDROID) +JavaValue jvalueToJavaValue(const jvalue&, const JavaType&, bool requireAnnotation); +#else JavaValue jvalueToJavaValue(const jvalue&, const JavaType&); +#endif jvalue javaValueToJvalue(const JavaValue&); } // namespace Bindings diff --git a/Source/WebCore/bridge/jni/v8/JavaClassJobjectV8.cpp b/Source/WebCore/bridge/jni/v8/JavaClassJobjectV8.cpp index 40bfd63..669eb49 100644 --- a/Source/WebCore/bridge/jni/v8/JavaClassJobjectV8.cpp +++ b/Source/WebCore/bridge/jni/v8/JavaClassJobjectV8.cpp @@ -33,7 +33,18 @@ using namespace JSC::Bindings; +#if PLATFORM(ANDROID) +const char kJavaScriptInterfaceAnnotation[] = "android/webkit/JavascriptInterface"; +const char kIsAnnotationPresent[] = "isAnnotationPresent"; +const char kGetMethods[] = "getMethods"; + +static jclass safeAnnotationClazz = NULL; + +JavaClassJobject::JavaClassJobject(jobject anInstance, bool requireAnnotation) + : m_requireAnnotation(requireAnnotation) +#else JavaClassJobject::JavaClassJobject(jobject anInstance) +#endif { jobject aClass = callJNIMethod<jobject>(anInstance, "getClass", "()Ljava/lang/Class;"); @@ -57,15 +68,28 @@ JavaClassJobject::JavaClassJobject(jobject anInstance) // Get the methods jarray methods = static_cast<jarray>(callJNIMethod<jobject>(aClass, "getMethods", "()[Ljava/lang/reflect/Method;")); int numMethods = env->GetArrayLength(methods); +#if PLATFORM(ANDROID) + jmethodID isAnnotationPresentMethodID = getAnnotationMethodID(env); + if (!isAnnotationPresentMethodID) { + LOG_ERROR("unable to find method %s on instance %p", kIsAnnotationPresent, anInstance); + return; + } +#endif for (int i = 0; i < numMethods; i++) { jobject aJMethod = env->GetObjectArrayElement(static_cast<jobjectArray>(methods), i); - JavaMethod* aMethod = new JavaMethodJobject(env, aJMethod); // deleted in the JavaClass destructor - MethodList* methodList = m_methods.get(aMethod->name()); - if (!methodList) { - methodList = new MethodList(); - m_methods.set(aMethod->name(), methodList); +#if PLATFORM(ANDROID) + if (jsAccessAllowed(env, isAnnotationPresentMethodID, aJMethod)) { +#endif + JavaMethod* aMethod = new JavaMethodJobject(env, aJMethod); // deleted in the JavaClass destructor + MethodList* methodList = m_methods.get(aMethod->name()); + if (!methodList) { + methodList = new MethodList(); + m_methods.set(aMethod->name(), methodList); + } + methodList->append(aMethod); +#if PLATFORM(ANDROID) } - methodList->append(aMethod); +#endif env->DeleteLocalRef(aJMethod); } env->DeleteLocalRef(fields); @@ -87,6 +111,44 @@ JavaClassJobject::~JavaClassJobject() m_methods.clear(); } +#if PLATFORM(ANDROID) +bool JavaClassJobject::jsAccessAllowed(JNIEnv* env, jmethodID mid, jobject aJMethod) +{ + if (!m_requireAnnotation) + return true; + bool accessAllowed = env->CallBooleanMethod(aJMethod, mid, safeAnnotationClazz); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + env->ExceptionClear(); + return false; + } + return accessAllowed; +} + +jmethodID JavaClassJobject::getAnnotationMethodID(JNIEnv* env) +{ + jclass methodClass = env->FindClass("java/lang/reflect/Method"); + jmethodID mid = 0; + if (methodClass) + mid = env->GetMethodID(methodClass, kIsAnnotationPresent, "(Ljava/lang/Class;)Z"); + if (!methodClass || !mid) { + env->ExceptionDescribe(); + env->ExceptionClear(); + } + env->DeleteLocalRef(methodClass); + return mid; +} + +bool JavaClassJobject::RegisterJavaClassJobject(JNIEnv* env) { + safeAnnotationClazz = reinterpret_cast<jclass>(env->NewGlobalRef(env->FindClass(kJavaScriptInterfaceAnnotation))); + if (!safeAnnotationClazz) { + LOG_ERROR("failed to register %s", kJavaScriptInterfaceAnnotation); + return false; + } + return true; +} +#endif + MethodList JavaClassJobject::methodsNamed(const char* name) const { MethodList* methodList = m_methods.get(name); diff --git a/Source/WebCore/bridge/jni/v8/JavaClassJobjectV8.h b/Source/WebCore/bridge/jni/v8/JavaClassJobjectV8.h index d27ca97..e4035aa 100644 --- a/Source/WebCore/bridge/jni/v8/JavaClassJobjectV8.h +++ b/Source/WebCore/bridge/jni/v8/JavaClassJobjectV8.h @@ -37,17 +37,33 @@ namespace Bindings { class JavaClassJobject : public JavaClass { public: +#if PLATFORM(ANDROID) + JavaClassJobject(jobject, bool); +#else JavaClassJobject(jobject); +#endif virtual ~JavaClassJobject(); // JavaClass implementation virtual MethodList methodsNamed(const char* name) const; virtual JavaField* fieldNamed(const char* name) const; +#if PLATFORM(ANDROID) + static bool RegisterJavaClassJobject(JNIEnv* env); +#endif + private: +#if PLATFORM(ANDROID) + bool jsAccessAllowed(JNIEnv* env, jmethodID mid, jobject aJMethod); + jmethodID getAnnotationMethodID(JNIEnv* env); +#endif + typedef HashMap<WTF::String, MethodList*> MethodListMap; MethodListMap m_methods; FieldMap m_fields; +#if PLATFORM(ANDROID) + bool m_requireAnnotation; +#endif }; } // namespace Bindings diff --git a/Source/WebCore/bridge/jni/v8/JavaInstanceJobjectV8.cpp b/Source/WebCore/bridge/jni/v8/JavaInstanceJobjectV8.cpp index e7b854d..c97a67f 100644 --- a/Source/WebCore/bridge/jni/v8/JavaInstanceJobjectV8.cpp +++ b/Source/WebCore/bridge/jni/v8/JavaInstanceJobjectV8.cpp @@ -41,8 +41,15 @@ using namespace JSC::Bindings; +#if PLATFORM(ANDROID) +JavaInstanceJobject::JavaInstanceJobject(jobject instance, bool requireAnnotation) +#else JavaInstanceJobject::JavaInstanceJobject(jobject instance) +#endif : m_instance(new JobjectWrapper(instance)) +#if PLATFORM(ANDROID) + , m_requireAnnotation(requireAnnotation) +#endif { } @@ -61,7 +68,11 @@ void JavaInstanceJobject::end() JavaClass* JavaInstanceJobject::getClass() const { if (!m_class) +#if PLATFORM(ANDROID) + m_class = adoptPtr(new JavaClassJobject(javaInstance(), m_requireAnnotation)); +#else m_class = adoptPtr(new JavaClassJobject(javaInstance())); +#endif return m_class.get(); } @@ -86,7 +97,7 @@ JavaValue JavaInstanceJobject::invokeMethod(const JavaMethod* method, JavaValue* return JavaValue(); } - return jvalueToJavaValue(result, method->returnType()); + return jvalueToJavaValue(result, method->returnType(), m_requireAnnotation); // END ANDROID } @@ -113,7 +124,11 @@ JavaValue JavaInstanceJobject::getField(const JavaField* field) appendClassName(signature, field->typeClassName()); signature.append(';'); } +#if PLATFORM(ANDROID) + return jvalueToJavaValue(getJNIField(javaInstance(), field->type(), field->name().utf8().data(), signature.toString().utf8().data()), field->type(), m_requireAnnotation); +#else return jvalueToJavaValue(getJNIField(javaInstance(), field->type(), field->name().utf8().data(), signature.toString().utf8().data()), field->type()); +#endif } #endif // ENABLE(JAVA_BRIDGE) diff --git a/Source/WebCore/bridge/jni/v8/JavaInstanceJobjectV8.h b/Source/WebCore/bridge/jni/v8/JavaInstanceJobjectV8.h index 255c190..77dcf28 100644 --- a/Source/WebCore/bridge/jni/v8/JavaInstanceJobjectV8.h +++ b/Source/WebCore/bridge/jni/v8/JavaInstanceJobjectV8.h @@ -48,8 +48,11 @@ namespace Bindings { class JavaInstanceJobject : public JavaInstance { public: +#if PLATFORM(ANDROID) + JavaInstanceJobject(jobject instance, bool requireAnnotation); +#else JavaInstanceJobject(jobject instance); - +#endif // JavaInstance implementation virtual JavaClass* getClass() const; // ANDROID @@ -64,6 +67,9 @@ public: protected: RefPtr<JobjectWrapper> m_instance; mutable OwnPtr<JavaClass> m_class; +#if PLATFORM(ANDROID) + bool m_requireAnnotation; +#endif }; } // namespace Bindings diff --git a/Source/WebCore/platform/graphics/android/context/PlatformGraphicsContextRecording.cpp b/Source/WebCore/platform/graphics/android/context/PlatformGraphicsContextRecording.cpp index 3237a80..03d9b81 100644 --- a/Source/WebCore/platform/graphics/android/context/PlatformGraphicsContextRecording.cpp +++ b/Source/WebCore/platform/graphics/android/context/PlatformGraphicsContextRecording.cpp @@ -47,8 +47,14 @@ #define NEW_OP(X) new (heap()) GraphicsOperation::X #define USE_CLIPPING_PAINTER true + +// Operations smaller than this area aren't considered opaque, and thus don't +// clip operations below. Chosen empirically. #define MIN_TRACKED_OPAQUE_AREA 750 +// Cap on ClippingPainter's recursive depth. Chosen empirically. +#define MAX_CLIPPING_RECURSION_COUNT 400 + namespace WebCore { static FloatRect approximateTextBounds(size_t numGlyphs, @@ -445,7 +451,8 @@ void Recording::draw(SkCanvas* canvas) nonCopyingSort(nodes.begin(), nodes.end(), CompareRecordingDataOrder); PlatformGraphicsContextSkia context(canvas); #if USE_CLIPPING_PAINTER - if (canvas->getDevice() && canvas->getDevice()->config() != SkBitmap::kNo_Config) { + if (canvas->getDevice() && canvas->getDevice()->config() != SkBitmap::kNo_Config + && count < MAX_CLIPPING_RECURSION_COUNT) { ClippingPainter painter(recording(), context, canvas->getTotalMatrix(), nodes); painter.draw(canvas->getTotalClip().getBounds()); } else diff --git a/Source/WebKit/android/jni/WebCoreFrameBridge.cpp b/Source/WebKit/android/jni/WebCoreFrameBridge.cpp index 61ffd29..ecda831 100644 --- a/Source/WebKit/android/jni/WebCoreFrameBridge.cpp +++ b/Source/WebKit/android/jni/WebCoreFrameBridge.cpp @@ -61,6 +61,7 @@ #include "IconDatabase.h" #include "Image.h" #include "InspectorClientAndroid.h" +#include "JavaClassJobjectV8.h" #include "JavaNPObjectV8.h" #include "JavaInstanceJobjectV8.h" #include "KURL.h" @@ -1504,14 +1505,14 @@ static jobject StringByEvaluatingJavaScriptFromString(JNIEnv *env, jobject obj, // and virtualEnd and swap the weak reference for the real object. class WeakJavaInstance : public JavaInstanceJobject { public: - static PassRefPtr<WeakJavaInstance> create(jobject obj) + static PassRefPtr<WeakJavaInstance> create(jobject obj, bool requireAnnotation) { - return adoptRef(new WeakJavaInstance(obj)); + return adoptRef(new WeakJavaInstance(obj, requireAnnotation)); } private: - WeakJavaInstance(jobject instance) - : JavaInstanceJobject(instance) + WeakJavaInstance(jobject instance, bool requireAnnotation) + : JavaInstanceJobject(instance, requireAnnotation) , m_beginEndDepth(0) { JNIEnv* env = getJNIEnv(); @@ -1568,7 +1569,7 @@ private: }; static void AddJavascriptInterface(JNIEnv *env, jobject obj, jint nativeFramePointer, - jobject javascriptObj, jstring interfaceName) + jobject javascriptObj, jstring interfaceName, jboolean requireAnnotation) { WebCore::Frame* pFrame = 0; if (nativeFramePointer == 0) @@ -1582,7 +1583,8 @@ static void AddJavascriptInterface(JNIEnv *env, jobject obj, jint nativeFramePoi ALOGV("::WebCore:: addJSInterface: %p", pFrame); if (pFrame) { - RefPtr<JavaInstance> addedObject = WeakJavaInstance::create(javascriptObj); + RefPtr<JavaInstance> addedObject = WeakJavaInstance::create(javascriptObj, + requireAnnotation); const char* name = getCharactersFromJStringInEnv(env, interfaceName); // Pass ownership of the added object to bindToWindowObject. NPObject* npObject = JavaInstanceToNPObject(addedObject.get()); @@ -1950,7 +1952,7 @@ static JNINativeMethod gBrowserFrameNativeMethods[] = { (void*) Reload }, { "nativeGoBackOrForward", "(I)V", (void*) GoBackOrForward }, - { "nativeAddJavascriptInterface", "(ILjava/lang/Object;Ljava/lang/String;)V", + { "nativeAddJavascriptInterface", "(ILjava/lang/Object;Ljava/lang/String;Z)V", (void*) AddJavascriptInterface }, { "stringByEvaluatingJavaScriptFromString", "(Ljava/lang/String;)Ljava/lang/String;", @@ -1985,6 +1987,8 @@ static JNINativeMethod gBrowserFrameNativeMethods[] = { int registerWebFrame(JNIEnv* env) { + JavaClassJobject::RegisterJavaClassJobject(env); + jclass clazz = env->FindClass("android/webkit/BrowserFrame"); ALOG_ASSERT(clazz, "Cannot find BrowserFrame"); gFrameField = env->GetFieldID(clazz, "mNativeFrame", "I"); |