Initial checkin of OOPHM plugins into trunk. Testing of non-XPCOM plugins
is still required, and more platforms need to be built.
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@5868 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/plugins/npapi/NPVariantWrapper.h b/plugins/npapi/NPVariantWrapper.h
new file mode 100644
index 0000000..0a469c9
--- /dev/null
+++ b/plugins/npapi/NPVariantWrapper.h
@@ -0,0 +1,567 @@
+#ifndef _H_NPVariantWrapper
+#define _H_NPVariantWrapper
+
+#include <string>
+#include <ostream>
+
+#ifdef sun
+// Sun's cstring doesn't define strlen/etc
+#include <string.h>
+#endif
+#include <cstring>
+#include <stdio.h>
+
+#include "Debug.h"
+#include "Platform.h"
+
+#include "mozincludes.h"
+
+#include "Value.h"
+#include "LocalObjectTable.h"
+#include "Plugin.h"
+#include "JavaObject.h"
+
+/**
+ * Contains NPVariantProxy, NPVariantWrapper, and NPVariantArray
+ */
+
+/**
+ * Wraps an NPVariant and provides various conversion functions. The variant
+ * provided retained at create time.
+ */
+class NPVariantProxy {
+ friend class NPVariantArray;
+private:
+ ScriptableInstance& plugin;
+ NPVariant& variant;
+public:
+ NPVariantProxy(ScriptableInstance& plugin, NPVariant& variant)
+ : plugin(plugin), variant(variant)
+ {
+ VOID_TO_NPVARIANT(variant);
+ }
+
+ NPVariantProxy(ScriptableInstance& plugin, NPVariant& variant, bool noinit)
+ : plugin(plugin), variant(variant)
+ {
+ }
+
+ ~NPVariantProxy() {
+ }
+
+ operator NPVariant() const {
+ return variant;
+ }
+
+ const NPVariant* operator->() const {
+ return &variant;
+ }
+
+ const NPVariant* address() const {
+ return &variant;
+ }
+
+ int isInt() const {
+ return isInt(variant);
+ }
+
+ static int isInt(const NPVariant& variant) {
+ return NPVARIANT_IS_INT32(variant);
+ }
+
+ int getAsInt() const {
+ return getAsInt(variant);
+ }
+
+ static int getAsInt(const NPVariant& variant) {
+ if (NPVARIANT_IS_INT32(variant)) {
+ return NPVARIANT_TO_INT32(variant);
+ }
+ Debug::log(Debug::Error) << "getAsInt: variant not int" << Debug::flush;
+ return 0;
+ }
+
+ int isNull() const {
+ return isNull(variant);
+ }
+
+ static int isNull(const NPVariant& variant) {
+ return NPVARIANT_IS_NULL(variant);
+ }
+
+ int isObject() const {
+ return isObject(variant);
+ }
+
+ static int isObject(const NPVariant& variant) {
+ return NPVARIANT_IS_OBJECT(variant);
+ }
+
+ NPObject* getAsObject() const {
+ return getAsObject(variant);
+ }
+
+ static NPObject* getAsObject(const NPVariant& variant) {
+ if (NPVARIANT_IS_OBJECT(variant)) {
+ return NPVARIANT_TO_OBJECT(variant);
+ }
+ Debug::log(Debug::Error) << "getAsObject: variant not object" << Debug::flush;
+ return 0;
+ }
+
+ int isString() const {
+ return isString(variant);
+ }
+
+ static int isString(const NPVariant& variant) {
+ return NPVARIANT_IS_STRING(variant);
+ }
+
+ const NPString* getAsNPString() const {
+ return getAsNPString(variant);
+ }
+
+ static const NPString* getAsNPString(const NPVariant& variant) {
+ if (NPVARIANT_IS_STRING(variant)) {
+ return &NPVARIANT_TO_STRING(variant);
+ }
+ Debug::log(Debug::Error) << "getAsNPString: variant not string" << Debug::flush;
+ return 0;
+ }
+
+ Value getAsValue(ScriptableInstance& scriptInstance, bool unwrapJava = true) const {
+ return getAsValue(variant, scriptInstance, unwrapJava);
+ }
+
+ static Value getAsValue(const NPVariant& variant, ScriptableInstance& scriptInstance,
+ bool unwrapJava = true) {
+ Value val;
+ if (NPVARIANT_IS_VOID(variant)) {
+ val.setUndefined();
+ } else if (NPVARIANT_IS_NULL(variant)) {
+ val.setNull();
+ } else if (NPVARIANT_IS_BOOLEAN(variant)) {
+ val.setBoolean(NPVARIANT_TO_BOOLEAN(variant));
+ } else if (NPVARIANT_IS_INT32(variant)) {
+ val.setInt(NPVARIANT_TO_INT32(variant));
+ } else if (NPVARIANT_IS_DOUBLE(variant)) {
+ val.setDouble(NPVARIANT_TO_DOUBLE(variant));
+ } else if (NPVARIANT_IS_STRING(variant)) {
+ NPString str = NPVARIANT_TO_STRING(variant);
+ val.setString(GetNPStringUTF8Characters(str), GetNPStringUTF8Length(str));
+ } else if (NPVARIANT_IS_OBJECT(variant)) {
+ NPObject* obj = NPVARIANT_TO_OBJECT(variant);
+ if (unwrapJava && JavaObject::isInstance(obj)) {
+ JavaObject* jObj = static_cast<JavaObject*>(obj);
+ val.setJavaObject(jObj->getObjectId());
+ } else {
+ NPVariant result;
+ VOID_TO_NPVARIANT(result);
+ if (scriptInstance.tryGetStringPrimitive(obj, result)) {
+ NPString str = NPVARIANT_TO_STRING(result);
+ val.setString(GetNPStringUTF8Characters(str), GetNPStringUTF8Length(str));
+ release(result);
+ } else {
+ val.setJsObjectId(scriptInstance.getLocalObjectRef(obj));
+ }
+ }
+ } else {
+ Debug::log(Debug::Error) << "Unsupported NPVariant type " << variant.type << Debug::flush;
+ }
+ return val;
+ }
+
+ /**
+ * The incoming variant is not altered, and is not even required to have
+ * its contents retained. Any object will get an extra refcount on it
+ * when copied to this variant, and strings will be copied.
+ */
+ NPVariantProxy& operator=(const NPVariant& newval) {
+ assignFrom(variant, newval);
+ return *this;
+ }
+
+ /**
+ * The incoming variant is not altered, and is not even required to have
+ * its contents retained. Any object will get an extra refcount on it
+ * when copied to this variant, and strings will be copied.
+ */
+ static void assignFrom(NPVariant& variant, const NPVariant& newval) {
+ release(variant);
+ variant = newval;
+ if (NPVARIANT_IS_STRING(newval)) {
+ int n = variant.value.stringValue.UTF8Length;
+ char* strBytes = reinterpret_cast<char*>(NPN_MemAlloc(n));
+ memcpy(strBytes, variant.value.stringValue.UTF8Characters, n);
+ variant.value.stringValue.UTF8Characters = strBytes;
+ } else {
+ retain(variant);
+ }
+ }
+
+ NPVariantProxy& operator=(NPObject* obj) {
+ assignFrom(variant, obj);
+ return *this;
+ }
+
+ static void assignFrom(NPVariant& variant, NPObject* obj) {
+ release(variant);
+ OBJECT_TO_NPVARIANT(obj, variant);
+ retain(variant);
+ }
+
+ // Convenience method for C++ code
+ NPVariantProxy& operator=(int intVal) {
+ assignFrom(variant, intVal);
+ return *this;
+ }
+
+ // Convenience method for C++ code
+ static void assignFrom(NPVariant& variant, int intVal) {
+ NPVariant newvar;
+ INT32_TO_NPVARIANT(intVal, newvar);
+ assignFrom(variant, newvar);
+ }
+
+ // Convenience method for C++ code
+ NPVariantProxy& operator=(const std::string& strval) {
+ assignFrom(variant, strval);
+ return *this;
+ }
+
+ // Convenience method for C++ code
+ static void assignFrom(NPVariant& variant, const std::string& strval) {
+ NPVariant newvar;
+ STDSTRING_TO_NPVARIANT(strval, newvar);
+ assignFrom(variant, newvar);
+ }
+
+ // Convenience method for C++ code
+ NPVariantProxy& operator=(const char* strval) {
+ assignFrom(variant, strval);
+ return *this;
+ }
+
+ // Convenience method for C++ code
+ static void assignFrom(NPVariant& variant, const char* strval) {
+ NPVariant newvar;
+ STRINGZ_TO_NPVARIANT(strval, newvar);
+ assignFrom(variant, newvar);
+ }
+
+ NPVariantProxy& operator=(const Value& newval) {
+ assignFrom(plugin, variant, newval);
+ return *this;
+ }
+
+ static void assignFrom(ScriptableInstance& plugin, NPVariant& variant, const Value& newval) {
+ NPVariant newvar;
+ VOID_TO_NPVARIANT(newvar);
+ if (newval.isBoolean()) {
+ BOOLEAN_TO_NPVARIANT(newval.getBoolean(), newvar);
+ } else if (newval.isByte()) {
+ INT32_TO_NPVARIANT(newval.getByte(), newvar);
+ } else if (newval.isChar()) {
+ INT32_TO_NPVARIANT(newval.getChar(), newvar);
+ } else if (newval.isShort()) {
+ INT32_TO_NPVARIANT(newval.getShort(), newvar);
+ } else if (newval.isInt()) {
+ int value = newval.getInt();
+ // Firefox NPAPI bug: 32-bit ints get mapped to int jsvals, regardless of range.
+ // However, int jsvals are 31 bits, so we need to use a double if the value is
+ // not representable in a 31 bit signed 2's-complement value.
+ if (value >= 0x40000000 || value < -0x40000000) {
+ DOUBLE_TO_NPVARIANT(static_cast<double>(value), newvar);
+ } else {
+ INT32_TO_NPVARIANT(value, newvar);
+ }
+ } else if (newval.isFloat()) {
+ DOUBLE_TO_NPVARIANT(newval.getFloat(), newvar);
+ } else if (newval.isDouble()) {
+ DOUBLE_TO_NPVARIANT(newval.getDouble(), newvar);
+ } else if (newval.isNull()) {
+ NULL_TO_NPVARIANT(newvar);
+ } else if (newval.isUndefined()) {
+ VOID_TO_NPVARIANT(newvar);
+ } else if (newval.isString()) {
+ assignFrom(variant, newval.getString());
+ return;
+ } else if (newval.isJavaObject()) {
+ if (1) {
+ JavaObject* jObj = plugin.createJavaWrapper(newval.getJavaObjectId());
+ NPObject* obj = jObj;
+ OBJECT_TO_NPVARIANT(obj, newvar);
+ } else {
+ VOID_TO_NPVARIANT(newvar);
+ }
+ } else if (newval.isJsObject()) {
+ OBJECT_TO_NPVARIANT(plugin.getLocalObject(newval.getJsObjectId()),
+ newvar);
+ } else {
+ Debug::log(Debug::Error) << "Unsupported NPVariant type " << newval.getType() << Debug::flush;
+ }
+ assignFrom(variant, newvar);
+ }
+
+ std::string toString() const {
+ return toString(variant);
+ }
+
+ static std::string toString(const NPVariant& variant) {
+ std::string retval;
+ // TODO(jat): remove sprintfs
+ char buf[40];
+ NPObject* npObj;
+ switch (variant.type) {
+ case NPVariantType_Void:
+ retval = "undef";
+ break;
+ case NPVariantType_Null:
+ retval = "null";
+ break;
+ case NPVariantType_Bool:
+ retval = "bool(";
+ retval += (NPVARIANT_TO_BOOLEAN(variant) ? "true" : "false");
+ retval += ')';
+ break;
+ case NPVariantType_Int32:
+ retval = "int(";
+ snprintf(buf, sizeof(buf), "%d)", NPVARIANT_TO_INT32(variant));
+ retval += buf;
+ break;
+ case NPVariantType_Double:
+ retval = "double(";
+ snprintf(buf, sizeof(buf), "%g)", NPVARIANT_TO_DOUBLE(variant));
+ retval += buf;
+ break;
+ case NPVariantType_String:
+ {
+ retval = "string(";
+ NPString str = NPVARIANT_TO_STRING(variant);
+ retval += std::string(str.UTF8Characters, str.UTF8Length);
+ retval += ')';
+ }
+ break;
+ case NPVariantType_Object:
+ npObj = NPVARIANT_TO_OBJECT(variant);
+ if (JavaObject::isInstance(npObj)) {
+ JavaObject* javaObj = static_cast<JavaObject*>(npObj);
+ snprintf(buf, sizeof(buf), "javaObj(id=%d, ", javaObj->getObjectId());
+ } else {
+ snprintf(buf, sizeof(buf), "jsObj(class=%p, ", npObj->_class);
+ }
+ retval = buf;
+ snprintf(buf, sizeof(buf), "%p)", npObj);
+ retval += buf;
+ break;
+ default:
+ snprintf(buf, sizeof(buf), "Unknown type %d", variant.type);
+ retval = buf;
+ break;
+ }
+ return retval;
+ }
+
+public:
+ void release() {
+ release(variant);
+ }
+
+ static void release(NPVariant& variant) {
+ NPN_ReleaseVariantValue(&variant);
+ }
+
+ void retain() {
+ retain(variant);
+ }
+
+ static void retain(NPVariant& variant) {
+ if (NPVARIANT_IS_OBJECT(variant)) {
+ NPN_RetainObject(NPVARIANT_TO_OBJECT(variant));
+ }
+ }
+};
+
+inline Debug::DebugStream& operator<<(Debug::DebugStream& dbg, const NPVariant& var) {
+ return dbg << NPVariantProxy::toString(var);
+}
+
+inline Debug::DebugStream& operator<<(Debug::DebugStream& dbg, const NPVariantProxy& var) {
+ return dbg << var.toString();
+}
+
+/**
+ * Variation of NPVariantProxy that provides its own variant and always frees it
+ * when the wrapper goes away.
+ */
+class NPVariantWrapper {
+private:
+ ScriptableInstance& plugin;
+ NPVariant variant;
+public:
+ NPVariantWrapper(ScriptableInstance& plugin) : plugin(plugin) {
+ VOID_TO_NPVARIANT(variant);
+ }
+
+ ~NPVariantWrapper() {
+ release();
+ }
+
+ operator NPVariant() const {
+ return variant;
+ }
+
+ const NPVariant* operator->() const {
+ return &variant;
+ }
+
+ const NPVariant* address() const {
+ return &variant;
+ }
+
+ /**
+ * Get the address for use as a return value. Since the value can be trashed,
+ * we need to release any data we currently hold.
+ */
+ NPVariant* addressForReturn() {
+ NPVariantProxy::release(variant);
+ VOID_TO_NPVARIANT(variant);
+ NPVariantProxy::retain(variant); // does nothing, present for consistency
+ return &variant;
+ }
+
+ int isInt() const {
+ return NPVariantProxy::isInt(variant);
+ }
+
+ int isObject() const {
+ return NPVariantProxy::isObject(variant);
+ }
+
+ int isString() const {
+ return NPVariantProxy::isString(variant);
+ }
+
+ int getAsInt() const {
+ return NPVariantProxy::getAsInt(variant);
+ }
+
+ NPObject* getAsObject() const {
+ return NPVariantProxy::getAsObject(variant);
+ }
+
+ const NPString* getAsNPString() const {
+ return NPVariantProxy::getAsNPString(variant);
+ }
+
+ Value getAsValue(ScriptableInstance& scriptInstance, bool unwrapJava = true) const {
+ return NPVariantProxy::getAsValue(variant, scriptInstance, unwrapJava);
+ }
+
+ /**
+ * The incoming variant is not altered, and is not even required to have
+ * its contents retained. Any object will get an extra refcount on it
+ * when copied to this variant, and strings will be copied.
+ */
+ NPVariantWrapper& operator=(const NPVariant& newval) {
+ NPVariantProxy::assignFrom(variant, newval);
+ return *this;
+ }
+
+ NPVariantWrapper& operator=(const Value& newval) {
+ NPVariantProxy::assignFrom(plugin, variant, newval);
+ return *this;
+ }
+
+ NPVariantWrapper& operator=(NPObject* obj) {
+ NPVariantProxy::assignFrom(variant, obj);
+ return *this;
+ }
+
+ // Convenience method for C++ code
+ NPVariantWrapper& operator=(const std::string& strval) {
+ NPVariantProxy::assignFrom(variant, strval);
+ return *this;
+ }
+
+ // Convenience method for C++ code
+ NPVariantWrapper& operator=(const char* strval) {
+ NPVariantProxy::assignFrom(variant, strval);
+ return *this;
+ }
+
+ void release() {
+ NPVariantProxy::release(variant);
+ }
+
+ void retain() {
+ NPVariantProxy::retain(variant);
+ }
+
+ std::string toString() const {
+ return NPVariantProxy::toString(variant);
+ }
+};
+
+inline Debug::DebugStream& operator<<(Debug::DebugStream& dbg, const NPVariantWrapper& var) {
+ dbg << var.toString();
+ return dbg;
+}
+
+/**
+ * Maintains an array of NPVariants and cleans them up when it is destroyed.
+ */
+class NPVariantArray {
+private:
+ ScriptableInstance& plugin;
+ int size;
+ NPVariant* args;
+
+public:
+ NPVariantArray(ScriptableInstance& plugin, int size) : plugin(plugin), size(size) {
+ args = new NPVariant[size];
+ for (int i = 0; i < size; ++i) {
+ VOID_TO_NPVARIANT(args[i]);
+ }
+ }
+
+ ~NPVariantArray() {
+ for (int i = 0; i < size; ++i) {
+ NPN_ReleaseVariantValue(&args[i]);
+ }
+ delete [] args;
+ }
+
+ const NPVariant* getArray() const {
+ return args;
+ }
+
+ int getSize() const {
+ return size;
+ }
+
+ const NPVariant& operator[](int idx) const {
+ if (idx >= size) {
+ printf("NPVariantArray[idx=%d] const: size=%d\n", idx, size);
+ }
+ return args[idx];
+ }
+
+ NPVariantProxy operator[](int idx) {
+ if (idx >= size) {
+ printf("NPVariantArray[idx=%d]: size=%d\n", idx, size);
+ }
+ return NPVariantProxy(plugin, args[idx], true);
+ }
+};
+
+inline Debug::DebugStream& operator<<(Debug::DebugStream& dbg, const NPVariantArray& var) {
+ dbg << "[";
+ for (int i = 0; i < var.getSize(); ++i) {
+ dbg << " " << var[i];
+ }
+ dbg << " ]";
+ return dbg;
+}
+
+#endif