blob: 57a5887bcce286ee1dd3202dc3d119c97c717da2 [file] [log] [blame]
jat@google.com134be542009-08-03 15:30:11 +00001#ifndef H_LocalObjectTable
2#define H_LocalObjectTable
3/*
4 * Copyright 2008 Google Inc.
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
7 * use this file except in compliance with the License. You may obtain a copy of
8 * the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15 * License for the specific language governing permissions and limitations under
16 * the License.
17 */
18
jat@google.comfa9d4d22009-11-10 00:00:39 +000019#include <map>
jat@google.com134be542009-08-03 15:30:11 +000020
21#include "Debug.h"
22
23#include "mozincludes.h"
codefu@google.comf722fe22011-07-11 13:15:51 +000024#include "NPVariantUtil.h"
jat@google.com134be542009-08-03 15:30:11 +000025
26class LocalObjectTable {
27private:
codefu@google.comf722fe22011-07-11 13:15:51 +000028 /* The host expects Value objects to have int's for JSO id's, hence the
29 * dual mapping. ObjectMap is for host communication (Value.getJsObjectId)
30 * and the IdMap is for browser communication (NPObject to ID).
31 */
jat@google.comfa9d4d22009-11-10 00:00:39 +000032 typedef std::map<int, NPObject*> ObjectMap;
codefu@google.comf722fe22011-07-11 13:15:51 +000033 typedef std::map<NPObject*,int> IdMap;
34
35 NPP npp;
jat@google.com134be542009-08-03 15:30:11 +000036
jat@google.comfa9d4d22009-11-10 00:00:39 +000037 int nextId;
38 ObjectMap objects;
codefu@google.comf722fe22011-07-11 13:15:51 +000039 IdMap ids;
jat@google.com134be542009-08-03 15:30:11 +000040 bool dontFree;
41
codefu@google.comf722fe22011-07-11 13:15:51 +000042 bool jsIdentitySafe;
43
44 const NPIdentifier gwtId;
45
jat@google.com134be542009-08-03 15:30:11 +000046 void setFree(int id) {
codefu@google.comf722fe22011-07-11 13:15:51 +000047 NPObject *obj = getById(id);
48 if(!obj) {
jat@google.comfa9d4d22009-11-10 00:00:39 +000049 Debug::log(Debug::Error) << "setFree(id=" << id << "): object not in table"
50 << Debug::flush;
codefu@google.comf722fe22011-07-11 13:15:51 +000051 return;
jat@google.comfa9d4d22009-11-10 00:00:39 +000052 }
codefu@google.comf722fe22011-07-11 13:15:51 +000053 ids.erase(obj);
54 objects.erase(id);
jat@google.com134be542009-08-03 15:30:11 +000055 }
jat@google.com97dcbe02009-09-08 23:09:51 +000056
jat@google.com134be542009-08-03 15:30:11 +000057public:
codefu@google.comf722fe22011-07-11 13:15:51 +000058 LocalObjectTable(NPP npp, bool jsIdentitySafe):
59 nextId(0), dontFree(false), jsIdentitySafe(jsIdentitySafe),
60 gwtId(NPN_GetStringIdentifier("__gwt_ObjectId")) {
jat@google.com134be542009-08-03 15:30:11 +000061 }
62
63 virtual ~LocalObjectTable();
64
jat@google.comf78175f2009-09-09 21:57:53 +000065 /**
66 * Add a new object, which must not be in the table, and return a new id for it.
67 */
jat@google.com134be542009-08-03 15:30:11 +000068 int add(NPObject* obj) {
jat@google.comfa9d4d22009-11-10 00:00:39 +000069 int id = nextId++;
70 set(id, obj);
codefu@google.comf722fe22011-07-11 13:15:51 +000071
72 if (!jsIdentitySafe) {
73 NPVariant idVariant;
74 Debug::log(Debug::Debugging) << "LocalObjectTable::set(): setting expando("
75 << id << ")" << Debug::flush;
76 INT32_TO_NPVARIANT(id,idVariant);
77 if (!NPN_SetProperty(npp, obj, gwtId, &idVariant)) {
78 Debug::log(Debug::Error) << "Setting GWT id on object failed" << Debug::flush;
79 }
80 }
81
jat@google.com134be542009-08-03 15:30:11 +000082 return id;
83 }
84
jat@google.comfa9d4d22009-11-10 00:00:39 +000085 void set(int id, NPObject* obj) {
codefu@google.comf722fe22011-07-11 13:15:51 +000086 Debug::log(Debug::Debugging) << "LocalObjectTable::set(id=" << id << ",obj=" << (void*)obj
jat@google.comfa9d4d22009-11-10 00:00:39 +000087 << ")" << Debug::flush;
codefu@google.comf722fe22011-07-11 13:15:51 +000088 if (!jsIdentitySafe) {
89 ObjectMap::iterator it;
90 it = objects.find(id);
91 if( it != objects.end() ) {
92 if (it->second != obj) {
93 //The JSO has changed and we need to update the map, releasing
94 //the old and remembering the new object.
95 ids.erase(it->second);
96 NPN_ReleaseObject(it->second);
97 NPN_RetainObject(obj);
98 } else {
99 //do nothing; object exists and is already mapped
100 return;
101 }
102 } else {
103 //New insertion, retain the object in the table
104 NPN_RetainObject(obj);
105 }
106 } else {
107 //Not dealing with identity hack, retain
108 NPN_RetainObject(obj);
109 }
jat@google.comfa9d4d22009-11-10 00:00:39 +0000110 objects[id] = obj;
codefu@google.comf722fe22011-07-11 13:15:51 +0000111 ids[obj] = id;
112
jat@google.comfa9d4d22009-11-10 00:00:39 +0000113 // keep track that we hold a reference in the table
jat@google.comfa9d4d22009-11-10 00:00:39 +0000114 }
115
jat@google.com134be542009-08-03 15:30:11 +0000116 void free(int id) {
codefu@google.comf722fe22011-07-11 13:15:51 +0000117 Debug::log(Debug::Debugging) << "LocalObjectTable::free(id=" << id << ")" << Debug::flush;
jat@google.comfa9d4d22009-11-10 00:00:39 +0000118 ObjectMap::iterator it = objects.find(id);
119 if (it == objects.end()) {
jat@google.com134be542009-08-03 15:30:11 +0000120 Debug::log(Debug::Error) << "Freeing freed object slot " << id << Debug::flush;
121 return;
122 }
codefu@google.comf722fe22011-07-11 13:15:51 +0000123 if (!jsIdentitySafe) {
124 Debug::log(Debug::Debugging) << "removing expando!" << Debug::flush;
125 NPN_RemoveProperty(npp, it->second, gwtId);
126 }
127 setFree(id);
jat@google.com134be542009-08-03 15:30:11 +0000128 if (!dontFree) {
jat@google.comfa9d4d22009-11-10 00:00:39 +0000129 NPObject* obj = it->second;
jat@google.com134be542009-08-03 15:30:11 +0000130 NPN_ReleaseObject(obj);
131 }
132 }
133
134 void freeAll() {
jat@google.comfa9d4d22009-11-10 00:00:39 +0000135 Debug::log(Debug::Info) << "LocalObjectTable::freeAll()" << Debug::flush;
136 for (ObjectMap::const_iterator it = objects.begin(); it != objects.end(); ++it) {
137 NPObject* obj = it->second;
138 if (!dontFree) {
139 NPN_ReleaseObject(obj);
jat@google.com134be542009-08-03 15:30:11 +0000140 }
141 }
jat@google.comfa9d4d22009-11-10 00:00:39 +0000142 objects.clear();
jat@google.com134be542009-08-03 15:30:11 +0000143 }
144
codefu@google.comf722fe22011-07-11 13:15:51 +0000145 NPObject* getById(int id) {
jat@google.comfa9d4d22009-11-10 00:00:39 +0000146 ObjectMap::iterator it = objects.find(id);
147 if (it == objects.end()) {
148 Debug::log(Debug::Error) << "LocalObjectTable::get(id=" << id
149 << "): no object found" << Debug::flush;
jat@google.com134be542009-08-03 15:30:11 +0000150 }
jat@google.comfa9d4d22009-11-10 00:00:39 +0000151 return it->second;
jat@google.com134be542009-08-03 15:30:11 +0000152 }
153
codefu@google.comf722fe22011-07-11 13:15:51 +0000154 int getObjectId(NPObject* jsObject) {
155 int id = -1;
156 if(!jsIdentitySafe) {
157 NPVariant idVariant;
158 VOID_TO_NPVARIANT(idVariant);
159 Debug::log(Debug::Debugging) << "LocalObjectTable::get(): expando test"
160 << Debug::flush;
161 if (NPN_GetProperty(npp, jsObject, gwtId, &idVariant) &&
162 NPVariantUtil::isInt(idVariant)) {
163 id = NPVariantUtil::getAsInt(idVariant);
164 Debug::log(Debug::Debugging) << "LocalObjectTable::get(): expando: "
165 << id << Debug::flush;
166 set(id, jsObject);
167 }
168 NPN_ReleaseVariantValue(&idVariant);
169 } else {
170 IdMap::iterator it = ids.find(jsObject);
171 if (it != ids.end()) {
172 id = it->second;
173 }
174 }
175 return id;
176 }
177
jat@google.com134be542009-08-03 15:30:11 +0000178 void setDontFree(bool dontFree) {
179 this->dontFree = dontFree;
180 }
181};
182
183#endif