Index: webkit/glue/plugins/pepper_var.cc |
=================================================================== |
--- webkit/glue/plugins/pepper_var.cc (revision 47484) |
+++ webkit/glue/plugins/pepper_var.cc (working copy) |
@@ -11,13 +11,69 @@ |
#include "third_party/ppapi/c/ppb_var.h" |
#include "third_party/WebKit/WebKit/chromium/public/WebBindings.h" |
#include "webkit/glue/plugins/pepper_string.h" |
+#include "v8/include/v8.h" |
+// Uncomment to enable catching JS exceptions |
+// #define HAVE_WEBBINDINGS_EXCEPTION_HANDLER 1 |
+ |
using WebKit::WebBindings; |
namespace pepper { |
namespace { |
+PP_Var VarFromUtf8(const char* data, uint32_t len); |
+ |
+// --------------------------------------------------------------------------- |
+// Exceptions |
+ |
+class TryCatch { |
+ public: |
+ TryCatch(PP_Var* exception) : exception_(exception) { |
+#ifdef HAVE_WEBBINDINGS_EXCEPTION_HANDLER |
+ WebBindings::pushExceptionHandler(&TryCatch::Catch, this); |
+#endif |
+ } |
+ |
+ ~TryCatch() { |
+#ifdef HAVE_WEBBINDINGS_EXCEPTION_HANDLER |
+ WebBindings::popExceptionHandler(); |
+#endif |
+ } |
+ |
+ bool HasException() const { |
+ return exception_ && exception_->type != PP_VarType_Void; |
+ } |
+ |
+ void SetException(const char* message) { |
+ DCHECK(!HasException()); |
+ if (exception_) |
+ *exception_ = VarFromUtf8(message, strlen(message)); |
+ } |
+ |
+ private: |
+ static void Catch(void* self, const NPUTF8* message) { |
+ static_cast<TryCatch*>(self)->SetException(message); |
+ } |
+ |
+ // May be null if the consumer isn't interesting in catching exceptions. |
+ PP_Var* exception_; |
+}; |
+ |
+const char kInvalidObjectException[] = "Error: Invalid object"; |
+const char kInvalidPropertyException[] = "Error: Invalid property"; |
+const char kUnableToGetPropertyException[] = "Error: Unable to get property"; |
+const char kUnableToSetPropertyException[] = "Error: Unable to set property"; |
+const char kUnableToRemovePropertyException[] = |
+ "Error: Unable to remove property"; |
+const char kUnableToGetAllPropertiesException[] = |
+ "Error: Unable to get all properties"; |
+const char kUnableToCallMethodException[] = "Error: Unable to call method"; |
+const char kUnableToConstructException[] = "Error: Unable to construct"; |
+ |
+// --------------------------------------------------------------------------- |
+// Utilities |
+ |
String* GetStringUnchecked(PP_Var var) { |
return reinterpret_cast<String*>(var.value.as_id); |
} |
@@ -32,6 +88,116 @@ |
return GetNPObjectUnchecked(var); |
} |
+// Returns a PP_Var that corresponds to the given NPVariant. The contents of |
+// the NPVariant will be copied unless the NPVariant corresponds to an object. |
+PP_Var NPVariantToPPVar(NPVariant* variant) { |
+ switch (variant->type) { |
+ case NPVariantType_Void: |
+ return PP_MakeVoid(); |
+ case NPVariantType_Null: |
+ return PP_MakeNull(); |
+ case NPVariantType_Bool: |
+ return PP_MakeBool(NPVARIANT_TO_BOOLEAN(*variant)); |
+ case NPVariantType_Int32: |
+ return PP_MakeInt32(NPVARIANT_TO_INT32(*variant)); |
+ case NPVariantType_Double: |
+ return PP_MakeDouble(NPVARIANT_TO_DOUBLE(*variant)); |
+ case NPVariantType_String: |
+ return VarFromUtf8(NPVARIANT_TO_STRING(*variant).UTF8Characters, |
+ NPVARIANT_TO_STRING(*variant).UTF8Length); |
+ case NPVariantType_Object: |
+ return NPObjectToPPVar(NPVARIANT_TO_OBJECT(*variant)); |
+ } |
+ NOTREACHED(); |
+ return PP_MakeVoid(); |
+} |
+ |
+// Returns a NPVariant that corresponds to the given PP_Var. The contents of |
+// the PP_Var will be copied unless the PP_Var corresponds to an object. |
+NPVariant PPVarToNPVariant(PP_Var var) { |
+ NPVariant ret; |
+ switch (var.type) { |
+ case PP_VarType_Void: |
+ VOID_TO_NPVARIANT(ret); |
+ break; |
+ case PP_VarType_Null: |
+ NULL_TO_NPVARIANT(ret); |
+ break; |
+ case PP_VarType_Bool: |
+ BOOLEAN_TO_NPVARIANT(var.value.as_bool, ret); |
+ break; |
+ case PP_VarType_Int32: |
+ INT32_TO_NPVARIANT(var.value.as_int, ret); |
+ break; |
+ case PP_VarType_Double: |
+ DOUBLE_TO_NPVARIANT(var.value.as_double, ret); |
+ break; |
+ case PP_VarType_String: { |
+ const std::string& value = GetStringUnchecked(var)->value(); |
+ STRINGN_TO_NPVARIANT(base::strdup(value.c_str()), value.size(), ret); |
+ break; |
+ } |
+ case PP_VarType_Object: { |
+ NPObject* object = GetNPObjectUnchecked(var); |
+ OBJECT_TO_NPVARIANT(WebBindings::retainObject(object), ret); |
+ break; |
+ } |
+ } |
+ return ret; |
+} |
+ |
+// Returns a NPVariant that corresponds to the given PP_Var. The contents of |
+// the PP_Var will NOT be copied, so you need to ensure that the PP_Var remains |
+// valid while the resultant NPVariant is in use. |
+NPVariant PPVarToNPVariantNoCopy(PP_Var var) { |
+ NPVariant ret; |
+ switch (var.type) { |
+ case PP_VarType_Void: |
+ VOID_TO_NPVARIANT(ret); |
+ break; |
+ case PP_VarType_Null: |
+ NULL_TO_NPVARIANT(ret); |
+ break; |
+ case PP_VarType_Bool: |
+ BOOLEAN_TO_NPVARIANT(var.value.as_bool, ret); |
+ break; |
+ case PP_VarType_Int32: |
+ INT32_TO_NPVARIANT(var.value.as_int, ret); |
+ break; |
+ case PP_VarType_Double: |
+ DOUBLE_TO_NPVARIANT(var.value.as_double, ret); |
+ break; |
+ case PP_VarType_String: { |
+ const std::string& value = GetStringUnchecked(var)->value(); |
+ STRINGN_TO_NPVARIANT(value.c_str(), value.size(), ret); |
+ break; |
+ } |
+ case PP_VarType_Object: { |
+ OBJECT_TO_NPVARIANT(GetNPObjectUnchecked(var), ret); |
+ break; |
+ } |
+ } |
+ return ret; |
+} |
+ |
+// Returns a NPIdentifier that corresponds to the given PP_Var. The contents |
+// of the PP_Var will be copied. Returns NULL if the given PP_Var is not a a |
+// string or integer type. |
+NPIdentifier PPVarToNPIdentifier(PP_Var var) { |
+ switch (var.type) { |
+ case PP_VarType_String: |
+ return WebBindings::getStringIdentifier( |
+ GetStringUnchecked(var)->value().c_str()); |
+ case PP_VarType_Int32: |
+ return WebBindings::getIntIdentifier(var.value.as_int); |
+ default: |
+ return NULL; |
+ } |
+} |
+ |
+// --------------------------------------------------------------------------- |
+// PPB_Var methods |
+ |
void AddRef(PP_Var var) { |
if (var.type == PP_VarType_String) { |
GetStringUnchecked(var)->AddRef(); |
@@ -74,18 +240,19 @@ |
bool HasProperty(PP_Var var, |
PP_Var name, |
PP_Var* exception) { |
- if (exception && exception->type != PP_VarType_Void) |
+ TryCatch try_catch(exception); |
+ if (try_catch.HasException()) |
return false; |
NPObject* object = GetNPObject(var); |
if (!object) { |
- // TODO(darin): raise exception |
+ try_catch.SetException(kInvalidObjectException); |
return false; |
} |
NPIdentifier identifier = PPVarToNPIdentifier(name); |
if (!identifier) { |
- // TODO(darin): raise exception |
+ try_catch.SetException(kInvalidPropertyException); |
return false; |
} |
@@ -95,24 +262,27 @@ |
PP_Var GetProperty(PP_Var var, |
PP_Var name, |
PP_Var* exception) { |
- if (exception && exception->type != PP_VarType_Void) |
+ TryCatch try_catch(exception); |
+ if (try_catch.HasException()) |
return PP_MakeVoid(); |
NPObject* object = GetNPObject(var); |
if (!object) { |
- // TODO(darin): raise exception |
+ try_catch.SetException(kInvalidObjectException); |
return PP_MakeVoid(); |
} |
NPIdentifier identifier = PPVarToNPIdentifier(name); |
if (!identifier) { |
- // TODO(darin): raise exception |
+ try_catch.SetException(kInvalidPropertyException); |
return PP_MakeVoid(); |
} |
NPVariant result; |
if (!WebBindings::getProperty(NULL, object, identifier, &result)) { |
- // TODO(darin): raise exception |
+ // An exception may have been raised. |
+ if (!try_catch.HasException()) |
+ try_catch.SetException(kUnableToGetPropertyException); |
return PP_MakeVoid(); |
} |
@@ -125,54 +295,64 @@ |
uint32_t* property_count, |
PP_Var** properties, |
PP_Var* exception) { |
- if (exception && exception->type != PP_VarType_Void) |
+ TryCatch try_catch(exception); |
+ if (try_catch.HasException()) |
return; |
- // TODO(darin) |
+ // TODO(darin): Implement this method! |
+ try_catch.SetException(kUnableToGetAllPropertiesException); |
} |
void SetProperty(PP_Var var, |
PP_Var name, |
PP_Var value, |
PP_Var* exception) { |
- if (exception && exception->type != PP_VarType_Void) |
+ TryCatch try_catch(exception); |
+ if (try_catch.HasException()) |
return; |
NPObject* object = GetNPObject(var); |
if (!object) { |
- // TODO(darin): raise exception |
+ try_catch.SetException(kInvalidObjectException); |
return; |
} |
NPIdentifier identifier = PPVarToNPIdentifier(name); |
if (!identifier) { |
- // TODO(darin): raise exception |
+ try_catch.SetException(kInvalidPropertyException); |
return; |
} |
NPVariant variant = PPVarToNPVariantNoCopy(value); |
- WebBindings::setProperty(NULL, object, identifier, &variant); |
+ if (!WebBindings::setProperty(NULL, object, identifier, &variant)) { |
+ if (!try_catch.HasException()) |
+ try_catch.SetException(kUnableToSetPropertyException); |
+ } |
} |
void RemoveProperty(PP_Var var, |
PP_Var name, |
PP_Var* exception) { |
- if (exception && exception->type != PP_VarType_Void) |
+ TryCatch try_catch(exception); |
+ if (try_catch.HasException()) |
return; |
NPObject* object = GetNPObject(var); |
if (!object) { |
- // TODO(darin): raise exception |
+ try_catch.SetException(kInvalidObjectException); |
return; |
} |
NPIdentifier identifier = PPVarToNPIdentifier(name); |
if (!identifier) { |
- // TODO(darin): raise exception |
+ try_catch.SetException(kInvalidPropertyException); |
return; |
} |
- WebBindings::removeProperty(NULL, object, identifier); |
+ if (!WebBindings::removeProperty(NULL, object, identifier)) { |
+ if (!try_catch.HasException()) |
+ try_catch.SetException(kUnableToRemovePropertyException); |
+ } |
} |
PP_Var Call(PP_Var var, |
@@ -180,12 +360,13 @@ |
int32_t argc, |
PP_Var* argv, |
PP_Var* exception) { |
- if (exception && exception->type != PP_VarType_Void) |
+ TryCatch try_catch(exception); |
+ if (try_catch.HasException()) |
return PP_MakeVoid(); |
NPObject* object = GetNPObject(var); |
if (!object) { |
- // TODO(darin): raise exception |
+ try_catch.SetException(kInvalidObjectException); |
return PP_MakeVoid(); |
} |
@@ -195,7 +376,7 @@ |
} else { |
identifier = PPVarToNPIdentifier(method_name); |
if (!identifier) { |
- // TODO(darin): raise exception |
+ try_catch.SetException(kInvalidPropertyException); |
return PP_MakeVoid(); |
} |
} |
@@ -218,7 +399,9 @@ |
} |
if (!ok) { |
- // TODO(darin): raise exception |
+ // An exception may have been raised. |
+ if (!try_catch.HasException()) |
+ try_catch.SetException(kUnableToCallMethodException); |
return PP_MakeVoid(); |
} |
@@ -231,12 +414,13 @@ |
int32_t argc, |
PP_Var* argv, |
PP_Var* exception) { |
- if (exception && exception->type != PP_VarType_Void) |
+ TryCatch try_catch(exception); |
+ if (try_catch.HasException()) |
return PP_MakeVoid(); |
NPObject* object = GetNPObject(var); |
if (!object) { |
- // TODO(darin): raise exception |
+ try_catch.SetException(kInvalidObjectException); |
return PP_MakeVoid(); |
} |
@@ -249,7 +433,9 @@ |
NPVariant result; |
if (!WebBindings::construct(NULL, object, args.get(), argc, &result)) { |
- // TODO(darin): raise exception |
+ // An exception may have been raised. |
+ if (!try_catch.HasException()) |
+ try_catch.SetException(kUnableToConstructException); |
return PP_MakeVoid(); |
} |
@@ -260,7 +446,7 @@ |
PP_Var CreateObject(const PPP_Class* object_class, |
void* object_data) { |
- return PP_MakeVoid(); // TODO(darin) |
+ return PP_MakeVoid(); // TODO(darin): Implement this method! |
} |
const PPB_Var var_interface = { |
@@ -292,101 +478,4 @@ |
return ret; |
} |
-PP_Var NPVariantToPPVar(NPVariant* variant) { |
- switch (variant->type) { |
- case NPVariantType_Void: |
- return PP_MakeVoid(); |
- case NPVariantType_Null: |
- return PP_MakeNull(); |
- case NPVariantType_Bool: |
- return PP_MakeBool(NPVARIANT_TO_BOOLEAN(*variant)); |
- case NPVariantType_Int32: |
- return PP_MakeInt32(NPVARIANT_TO_INT32(*variant)); |
- case NPVariantType_Double: |
- return PP_MakeDouble(NPVARIANT_TO_DOUBLE(*variant)); |
- case NPVariantType_String: |
- return VarFromUtf8(NPVARIANT_TO_STRING(*variant).UTF8Characters, |
- NPVARIANT_TO_STRING(*variant).UTF8Length); |
- case NPVariantType_Object: |
- return NPObjectToPPVar(NPVARIANT_TO_OBJECT(*variant)); |
- } |
- NOTREACHED(); |
- return PP_MakeVoid(); |
-} |
- |
-NPVariant PPVarToNPVariant(PP_Var var) { |
- NPVariant ret; |
- switch (var.type) { |
- case PP_VarType_Void: |
- VOID_TO_NPVARIANT(ret); |
- break; |
- case PP_VarType_Null: |
- NULL_TO_NPVARIANT(ret); |
- break; |
- case PP_VarType_Bool: |
- BOOLEAN_TO_NPVARIANT(var.value.as_bool, ret); |
- break; |
- case PP_VarType_Int32: |
- INT32_TO_NPVARIANT(var.value.as_int, ret); |
- break; |
- case PP_VarType_Double: |
- DOUBLE_TO_NPVARIANT(var.value.as_double, ret); |
- break; |
- case PP_VarType_String: { |
- const std::string& value = GetStringUnchecked(var)->value(); |
- STRINGN_TO_NPVARIANT(base::strdup(value.c_str()), value.size(), ret); |
- break; |
- } |
- case PP_VarType_Object: { |
- NPObject* object = GetNPObjectUnchecked(var); |
- OBJECT_TO_NPVARIANT(WebBindings::retainObject(object), ret); |
- break; |
- } |
- } |
- return ret; |
-} |
- |
-NPVariant PPVarToNPVariantNoCopy(PP_Var var) { |
- NPVariant ret; |
- switch (var.type) { |
- case PP_VarType_Void: |
- VOID_TO_NPVARIANT(ret); |
- break; |
- case PP_VarType_Null: |
- NULL_TO_NPVARIANT(ret); |
- break; |
- case PP_VarType_Bool: |
- BOOLEAN_TO_NPVARIANT(var.value.as_bool, ret); |
- break; |
- case PP_VarType_Int32: |
- INT32_TO_NPVARIANT(var.value.as_int, ret); |
- break; |
- case PP_VarType_Double: |
- DOUBLE_TO_NPVARIANT(var.value.as_double, ret); |
- break; |
- case PP_VarType_String: { |
- const std::string& value = GetStringUnchecked(var)->value(); |
- STRINGN_TO_NPVARIANT(value.c_str(), value.size(), ret); |
- break; |
- } |
- case PP_VarType_Object: { |
- OBJECT_TO_NPVARIANT(GetNPObjectUnchecked(var), ret); |
- break; |
- } |
- } |
- return ret; |
-} |
- |
-NPIdentifier PPVarToNPIdentifier(PP_Var var) { |
- switch (var.type) { |
- case PP_VarType_String: |
- return WebBindings::getStringIdentifier( |
- GetStringUnchecked(var)->value().c_str()); |
- case PP_VarType_Int32: |
- return WebBindings::getIntIdentifier(var.value.as_int); |
- default: |
- return NULL; |
- } |
-} |
- |
} // namespace pepper |