| #ifndef H_LocalObjectTable | 
 | #define H_LocalObjectTable | 
 | /* | 
 |  * 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 <map> | 
 |  | 
 | #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) { | 
 |     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(NPP npp, bool jsIdentitySafe): | 
 |     nextId(0), dontFree(false), jsIdentitySafe(jsIdentitySafe), | 
 |     gwtId(NPN_GetStringIdentifier("__gwt_ObjectId")) { | 
 |   } | 
 |  | 
 |   virtual ~LocalObjectTable(); | 
 |  | 
 |   /** | 
 |    * Add a new object, which must not be in the table, and return a new id for it. | 
 |    */ | 
 |   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::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 | 
 |   } | 
 |  | 
 |   void free(int id) { | 
 |     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); | 
 |     } | 
 |   } | 
 |  | 
 |   void freeAll() { | 
 |     Debug::log(Debug::Info) << "LocalObjectTable::freeAll()" << Debug::flush; | 
 |     for (ObjectMap::const_iterator it = objects.begin(); it != objects.end(); ++it) { | 
 |       NPObject* obj = it->second; | 
 |       if (!dontFree) { | 
 |         NPN_ReleaseObject(obj); | 
 |       } | 
 |     } | 
 |     objects.clear(); | 
 |   } | 
 |  | 
 |   NPObject* getById(int id) { | 
 |     ObjectMap::iterator it = objects.find(id); | 
 |     if (it == objects.end()) { | 
 |       Debug::log(Debug::Error) << "LocalObjectTable::get(id=" << id | 
 |           << "): no object found" << Debug::flush; | 
 |     } | 
 |     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; | 
 |   } | 
 | }; | 
 |  | 
 | #endif |