OLD | NEW |
| (Empty) |
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "webkit/activex_shim/dispatch_object.h" | |
6 | |
7 #include <algorithm> | |
8 #include <string> | |
9 #include <vector> | |
10 | |
11 #include "base/logging.h" | |
12 #include "webkit/activex_shim/activex_util.h" | |
13 #include "webkit/activex_shim/npp_impl.h" | |
14 | |
15 using std::string; | |
16 using std::wstring; | |
17 | |
18 namespace activex_shim { | |
19 | |
20 // Used when the browser asks for scriptable object. | |
21 static NPClass npclass = { | |
22 1, // NP_CLASS_STRUCT_VERSION, | |
23 NPAllocate, | |
24 NPDeallocate, | |
25 NPInvalidate, | |
26 NPHasMethod, | |
27 NPInvoke, | |
28 NPInvokeDefault, | |
29 NPHasProperty, | |
30 NPGetProperty, | |
31 NPSetProperty, | |
32 NPRemoveProperty | |
33 }; | |
34 | |
35 DispatchObject::DispatchObject(DispatchObject* root) | |
36 : npobject_(NULL), | |
37 root_(root), | |
38 deleting_spawned_children_(false) { | |
39 } | |
40 | |
41 DispatchObject::~DispatchObject() { | |
42 if (npobject_) { | |
43 // We are gone, but the NPObject may still be there. So remove | |
44 // the reference to myself to avoid future trouble. | |
45 npobject_->dispatch_object = NULL; | |
46 } | |
47 } | |
48 | |
49 NPObject* DispatchObject::GetScriptableNPObject() { | |
50 if (npobject_ == NULL) { | |
51 npobject_ = static_cast<DispatchNPObject*>(NPAllocate(&npclass)); | |
52 } else { | |
53 // If it is requesting the object again, we should just return the | |
54 // object with increased reference count. | |
55 g_browser->retainobject(npobject_); | |
56 } | |
57 return npobject_; | |
58 } | |
59 | |
60 NPObject* DispatchObject::NPAllocate(NPClass* cls) { | |
61 DispatchNPObject* obj = new DispatchNPObject(); | |
62 obj->_class = cls; | |
63 obj->referenceCount = 1; | |
64 obj->dispatch_object = this; | |
65 return obj; | |
66 } | |
67 | |
68 void DispatchObject::NPInvalidate() { | |
69 } | |
70 | |
71 void DispatchObject::OnDeallocateObject(DispatchNPObject* obj) { | |
72 DCHECK_EQ(obj, npobject_); | |
73 if (obj == npobject_) { | |
74 // Just null our reference so that we won't accidentally access it | |
75 // during destruction. | |
76 npobject_ = NULL; | |
77 if (NPObjectOwnsMe()) { | |
78 delete this; | |
79 } | |
80 } | |
81 } | |
82 | |
83 bool DispatchObject::NPHasMethod(NPIdentifier name) { | |
84 wstring wname; | |
85 if (!NPIdentifierToWString(name, &wname)) | |
86 return false; | |
87 return DispIsMethodOrProperty(GetDispatch(), wname.c_str(), true); | |
88 } | |
89 | |
90 bool DispatchObject::NPHasProperty(NPIdentifier name) { | |
91 wstring wname; | |
92 if (!NPIdentifierToWString(name, &wname)) | |
93 return false; | |
94 return DispIsMethodOrProperty(GetDispatch(), wname.c_str(), false); | |
95 // Here is another way. But the problem is it can not distiguish between | |
96 // method and property. | |
97 // DISPID dispid; | |
98 // if (GetDispID(npobj->dispatch_object->GetDispatch(), wname.c_str(), &dispid
)) | |
99 // return true; | |
100 } | |
101 | |
102 bool DispatchObject::NPInvoke(NPIdentifier name, const NPVariant* args, | |
103 uint32_t argCount, NPVariant* result) { | |
104 wstring wname; | |
105 if (!NPIdentifierToWString(name, &wname)) | |
106 return false; | |
107 std::vector<ScopedVariant> vars; | |
108 ScopedVariant vtres; | |
109 bool res = false; | |
110 do { | |
111 if (argCount > 0) { | |
112 vars.resize(argCount); | |
113 unsigned int i; | |
114 for (i = 0; i < argCount; i++) { | |
115 // Note that we need to reverse the order of arguments for | |
116 // IDispatch::Invoke. | |
117 if (!NPVariantToVariant(&args[argCount - i - 1], &vars[i])) | |
118 break; | |
119 } | |
120 if (i < argCount) | |
121 break; | |
122 } | |
123 if (!DispInvoke(GetDispatch(), wname.c_str(), | |
124 argCount > 0 ? &vars[0] : NULL, | |
125 argCount, &vtres)) | |
126 break; | |
127 if (!VariantToNPVariant(this, &vtres, result)) | |
128 break; | |
129 res = true; | |
130 } while (false); | |
131 return res; | |
132 } | |
133 | |
134 bool DispatchObject::NPInvokeDefault(const NPVariant* args, uint32_t argCount, | |
135 NPVariant* result) { | |
136 return false; | |
137 } | |
138 | |
139 bool DispatchObject::NPGetProperty(NPIdentifier name, NPVariant* variant) { | |
140 wstring wname; | |
141 if (!NPIdentifierToWString(name, &wname)) | |
142 return false; | |
143 ScopedVariant result; | |
144 if (!DispInvoke(GetDispatch(), wname.c_str(), NULL, 0, &result)) | |
145 return false; | |
146 if (!VariantToNPVariant(this, &result, variant)) | |
147 return false; | |
148 return true; | |
149 } | |
150 | |
151 bool DispatchObject::NPSetProperty(NPIdentifier name, const NPVariant* variant)
{ | |
152 wstring wname; | |
153 if (!NPIdentifierToWString(name, &wname)) | |
154 return false; | |
155 ScopedVariant rvalue; | |
156 if (!NPVariantToVariant(variant, &rvalue)) | |
157 return false; | |
158 if (!DispSetProperty(GetDispatch(), wname.c_str(), rvalue)) | |
159 return false; | |
160 return true; | |
161 } | |
162 | |
163 bool DispatchObject::NPRemoveProperty(NPIdentifier propertyName) { | |
164 return false; | |
165 } | |
166 | |
167 void DispatchObject::AddSpawned(DispatchObject* obj) { | |
168 // I myself must be the root. | |
169 DCHECK(root_ == NULL); | |
170 spawned_children_.push_back(obj); | |
171 } | |
172 | |
173 void DispatchObject::RemoveSpawned(DispatchObject* obj) { | |
174 // This is to avoid problem when the root object is calling ReleaseSpawned to | |
175 // delete all spawned children. | |
176 if (deleting_spawned_children_) | |
177 return; | |
178 DCHECK(root_ == NULL); | |
179 SpawnedChildrenList::iterator it = std::find(spawned_children_.begin(), | |
180 spawned_children_.end(), obj); | |
181 if (it == spawned_children_.end()) { | |
182 DCHECK(false); | |
183 return; | |
184 } | |
185 spawned_children_.erase(it); | |
186 } | |
187 | |
188 void DispatchObject::ReleaseSpawned() { | |
189 DCHECK(root_ == NULL); | |
190 deleting_spawned_children_ = true; | |
191 for (SpawnedChildrenList::iterator it = spawned_children_.begin(); | |
192 it != spawned_children_.end(); ++it) | |
193 delete *it; | |
194 deleting_spawned_children_ = false; | |
195 spawned_children_.clear(); | |
196 } | |
197 | |
198 SpawnedDispatchObject::SpawnedDispatchObject(IDispatch* dispatch, | |
199 DispatchObject* root) | |
200 : DispatchObject(root), | |
201 dispatch_(dispatch) { | |
202 if (dispatch) | |
203 dispatch->AddRef(); | |
204 DCHECK(root != NULL); | |
205 root->AddSpawned(this); | |
206 } | |
207 | |
208 SpawnedDispatchObject::~SpawnedDispatchObject() { | |
209 if (dispatch_) | |
210 dispatch_->Release(); | |
211 DCHECK(root_ != NULL); | |
212 root_->RemoveSpawned(this); | |
213 } | |
214 | |
215 /////////////////////////////////////////////////////////////////////////////// | |
216 // Scripting object functions implementation. | |
217 | |
218 NPObject* NPAllocate(NPP npp, NPClass* theClass) { | |
219 DispatchObject* dispatch_object = static_cast<DispatchObject*>(npp->pdata); | |
220 return dispatch_object->NPAllocate(theClass); | |
221 } | |
222 | |
223 void NPDeallocate(NPObject* obj) { | |
224 DispatchNPObject* npobj = static_cast<DispatchNPObject*>(obj); | |
225 // The dispatch_object could be well gone before the NPObject is released. | |
226 if (npobj->dispatch_object != NULL) { | |
227 npobj->dispatch_object->OnDeallocateObject(npobj); | |
228 } | |
229 delete npobj; | |
230 } | |
231 | |
232 void NPInvalidate(NPObject* obj) { | |
233 DispatchNPObject* npobj = static_cast<DispatchNPObject*>(obj); | |
234 if (npobj->dispatch_object == NULL) | |
235 return; | |
236 npobj->dispatch_object->NPInvalidate(); | |
237 } | |
238 | |
239 bool NPHasMethod(NPObject* obj, NPIdentifier name) { | |
240 DispatchNPObject* npobj = static_cast<DispatchNPObject*>(obj); | |
241 if (npobj->dispatch_object == NULL) | |
242 return false; | |
243 return npobj->dispatch_object->NPHasMethod(name); | |
244 } | |
245 | |
246 bool NPInvoke(NPObject* obj, NPIdentifier name, const NPVariant* args, | |
247 uint32_t argCount, NPVariant* result) { | |
248 DispatchNPObject* npobj = static_cast<DispatchNPObject*>(obj); | |
249 if (npobj->dispatch_object == NULL) | |
250 return false; | |
251 return npobj->dispatch_object->NPInvoke(name, args, argCount, result); | |
252 } | |
253 | |
254 bool NPInvokeDefault(NPObject* obj, const NPVariant* args, uint32_t argCount, | |
255 NPVariant* result) { | |
256 DispatchNPObject* npobj = static_cast<DispatchNPObject*>(obj); | |
257 if (npobj->dispatch_object == NULL) | |
258 return false; | |
259 return npobj->dispatch_object->NPInvokeDefault(args, argCount, result); | |
260 } | |
261 | |
262 bool NPHasProperty(NPObject* obj, NPIdentifier name) { | |
263 DispatchNPObject* npobj = static_cast<DispatchNPObject*>(obj); | |
264 if (npobj->dispatch_object == NULL) | |
265 return false; | |
266 return npobj->dispatch_object->NPHasProperty(name); | |
267 } | |
268 | |
269 bool NPGetProperty(NPObject* obj, NPIdentifier name, NPVariant* variant) { | |
270 DispatchNPObject* npobj = static_cast<DispatchNPObject*>(obj); | |
271 if (npobj->dispatch_object == NULL) | |
272 return false; | |
273 return npobj->dispatch_object->NPGetProperty(name, variant); | |
274 } | |
275 | |
276 bool NPSetProperty(NPObject* obj, NPIdentifier name, const NPVariant* variant) { | |
277 DispatchNPObject* npobj = static_cast<DispatchNPObject*>(obj); | |
278 if (npobj->dispatch_object == NULL) | |
279 return false; | |
280 return npobj->dispatch_object->NPSetProperty(name, variant); | |
281 } | |
282 | |
283 bool NPRemoveProperty(NPObject* obj, NPIdentifier name) { | |
284 DispatchNPObject* npobj = static_cast<DispatchNPObject*>(obj); | |
285 if (npobj->dispatch_object == NULL) | |
286 return false; | |
287 return npobj->dispatch_object->NPRemoveProperty(name); | |
288 } | |
289 | |
290 } // namespace activex_shim | |
OLD | NEW |