Adding DoNotRunWith annotation to failing JUnit test; possible HtmlUnit bug.
Review at http://gwt-code-reviews.appspot.com/1469803

Review by: conroy@google.com

git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@10438 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/plugins/npapi/LocalObjectTable.h b/plugins/npapi/LocalObjectTable.h
index acfbf2f..57a5887 100644
--- a/plugins/npapi/LocalObjectTable.h
+++ b/plugins/npapi/LocalObjectTable.h
@@ -21,24 +21,43 @@
 #include "Debug.h"
 
 #include "mozincludes.h"
+#include "NPVariantUtil.h"
 
 class LocalObjectTable {
 private:
+  /* The host expects Value objects to have int's for JSO id's, hence the
+   * dual mapping.  ObjectMap is for host communication (Value.getJsObjectId)
+   * and the IdMap is for browser communication (NPObject to ID).
+   */
   typedef std::map<int, NPObject*> ObjectMap;
+  typedef std::map<NPObject*,int> IdMap;
+
+  NPP npp;
 
   int nextId;
   ObjectMap objects;
+  IdMap ids;
   bool dontFree;
 
+  bool jsIdentitySafe;
+
+  const NPIdentifier gwtId;
+
   void setFree(int id) {
-    if (objects.erase(id) != 1) {
+    NPObject *obj = getById(id);
+    if(!obj) {
       Debug::log(Debug::Error) << "setFree(id=" << id << "): object not in table"
         << Debug::flush;
+      return;
     }
+    ids.erase(obj);
+    objects.erase(id);
   }
 
 public:
-  LocalObjectTable(): nextId(0), dontFree(false) {
+  LocalObjectTable(NPP npp, bool jsIdentitySafe):
+    nextId(0), dontFree(false), jsIdentitySafe(jsIdentitySafe),
+    gwtId(NPN_GetStringIdentifier("__gwt_ObjectId")) {
   }
 
   virtual ~LocalObjectTable();
@@ -49,29 +68,67 @@
   int add(NPObject* obj) {
     int id = nextId++;
     set(id, obj);
+
+    if (!jsIdentitySafe) {
+      NPVariant idVariant;
+      Debug::log(Debug::Debugging) << "LocalObjectTable::set(): setting expando("
+          << id << ")" << Debug::flush;
+      INT32_TO_NPVARIANT(id,idVariant);
+      if (!NPN_SetProperty(npp, obj, gwtId, &idVariant)) {
+        Debug::log(Debug::Error) << "Setting GWT id on object failed" << Debug::flush;
+      }
+    }
+
     return id;
   }
 
   void set(int id, NPObject* obj) {
-    Debug::log(Debug::Spam) << "LocalObjectTable::set(id=" << id << ",obj=" << (void*)obj
+    Debug::log(Debug::Debugging) << "LocalObjectTable::set(id=" << id << ",obj=" << (void*)obj
         << ")" << Debug::flush;
+    if (!jsIdentitySafe) {
+      ObjectMap::iterator it;
+      it = objects.find(id);
+      if( it != objects.end() ) {
+        if (it->second != obj) {
+          //The JSO has changed and we need to update the map, releasing
+          //the old and remembering the new object.
+          ids.erase(it->second);
+          NPN_ReleaseObject(it->second);
+          NPN_RetainObject(obj);
+        } else {
+          //do nothing; object exists and is already mapped
+          return;
+        }
+      } else {
+        //New insertion, retain the object in the table
+        NPN_RetainObject(obj);
+      }
+    } else {
+      //Not dealing with identity hack, retain
+      NPN_RetainObject(obj);
+    }
     objects[id] = obj;
+    ids[obj] = id;
+
     // keep track that we hold a reference in the table
-    NPN_RetainObject(obj);
   }
 
   void free(int id) {
-    Debug::log(Debug::Spam) << "LocalObjectTable::free(id=" << id << ")" << Debug::flush;
+    Debug::log(Debug::Debugging) << "LocalObjectTable::free(id=" << id << ")" << Debug::flush;
     ObjectMap::iterator it = objects.find(id);
     if (it == objects.end()) {
       Debug::log(Debug::Error) << "Freeing freed object slot " << id << Debug::flush;
       return;
     }
+    if (!jsIdentitySafe) {
+      Debug::log(Debug::Debugging) << "removing expando!" << Debug::flush;
+      NPN_RemoveProperty(npp, it->second, gwtId);
+    }
+    setFree(id);
     if (!dontFree) {
       NPObject* obj = it->second;
       NPN_ReleaseObject(obj);
     }
-    setFree(id);
   }
 
   void freeAll() {
@@ -85,7 +142,7 @@
     objects.clear();
   }
 
-  NPObject* get(int id) {
+  NPObject* getById(int id) {
     ObjectMap::iterator it = objects.find(id);
     if (it == objects.end()) {
       Debug::log(Debug::Error) << "LocalObjectTable::get(id=" << id
@@ -94,6 +151,30 @@
     return it->second;
   }
 
+  int getObjectId(NPObject* jsObject) {
+    int id = -1;
+    if(!jsIdentitySafe) {
+      NPVariant idVariant;
+      VOID_TO_NPVARIANT(idVariant);
+      Debug::log(Debug::Debugging) << "LocalObjectTable::get(): expando test"
+          << Debug::flush;
+      if (NPN_GetProperty(npp, jsObject, gwtId, &idVariant) &&
+          NPVariantUtil::isInt(idVariant)) {
+        id = NPVariantUtil::getAsInt(idVariant);
+        Debug::log(Debug::Debugging) << "LocalObjectTable::get(): expando: "
+            << id << Debug::flush;
+        set(id, jsObject);
+      }
+      NPN_ReleaseVariantValue(&idVariant);
+    } else {
+      IdMap::iterator it = ids.find(jsObject);
+      if (it != ids.end()) {
+        id = it->second;
+      }
+    }
+    return id;
+  }
+
   void setDontFree(bool dontFree) {
     this->dontFree = dontFree;
   }