Fix playing of 8-bit sample files via webaudio.
[chromium-blink-merge.git] / webkit / glue / cpp_bound_class.cc
blob9688e4df03b03113c06412aeac932a67912c7263
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.
5 // This file contains definitions for CppBoundClass
7 // Here's the control flow of a JS method getting forwarded to a class.
8 // - Something calls our NPObject with a function like "Invoke".
9 // - CppNPObject's static invoke() function forwards it to its attached
10 // CppBoundClass's Invoke() method.
11 // - CppBoundClass has then overridden Invoke() to look up the function
12 // name in its internal map of methods, and then calls the appropriate
13 // method.
15 #include "base/compiler_specific.h"
16 #include "base/logging.h"
17 #include "base/utf_string_conversions.h"
18 #include "third_party/WebKit/Source/WebKit/chromium/public/WebBindings.h"
19 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
20 #include "third_party/WebKit/Source/WebKit/chromium/public/WebString.h"
21 #include "webkit/glue/cpp_bound_class.h"
23 using WebKit::WebBindings;
24 using WebKit::WebFrame;
26 namespace {
28 class CppVariantPropertyCallback : public CppBoundClass::PropertyCallback {
29 public:
30 CppVariantPropertyCallback(CppVariant* value) : value_(value) { }
32 virtual bool GetValue(CppVariant* value) {
33 value->Set(*value_);
34 return true;
36 virtual bool SetValue(const CppVariant& value) {
37 value_->Set(value);
38 return true;
41 private:
42 CppVariant* value_;
45 class GetterPropertyCallback : public CppBoundClass::PropertyCallback {
46 public:
47 GetterPropertyCallback(CppBoundClass::GetterCallback* callback)
48 : callback_(callback) { }
50 virtual bool GetValue(CppVariant* value) {
51 callback_->Run(value);
52 return true;
55 virtual bool SetValue(const CppVariant& value) {
56 return false;
59 private:
60 scoped_ptr<CppBoundClass::GetterCallback> callback_;
65 // Our special NPObject type. We extend an NPObject with a pointer to a
66 // CppBoundClass, which is just a C++ interface that we forward all NPObject
67 // callbacks to.
68 struct CppNPObject {
69 NPObject parent; // This must be the first field in the struct.
70 CppBoundClass* bound_class;
73 // All following objects and functions are static, and just used to interface
74 // with NPObject/NPClass.
77 // An NPClass associates static functions of CppNPObject with the
78 // function pointers used by the JS runtime.
79 static NPClass np_class_;
81 // Allocate a new NPObject with the specified class.
82 static NPObject* allocate(NPP npp, NPClass* aClass);
84 // Free an object.
85 static void deallocate(NPObject* obj);
87 // Returns true if the C++ class associated with this NPObject exposes the
88 // given property. Called by the JS runtime.
89 static bool hasProperty(NPObject *obj, NPIdentifier ident);
91 // Returns true if the C++ class associated with this NPObject exposes the
92 // given method. Called by the JS runtime.
93 static bool hasMethod(NPObject *obj, NPIdentifier ident);
95 // If the given method is exposed by the C++ class associated with this
96 // NPObject, invokes it with the given args and returns a result. Otherwise,
97 // returns "undefined" (in the JavaScript sense). Called by the JS runtime.
98 static bool invoke(NPObject *obj, NPIdentifier ident,
99 const NPVariant *args, uint32_t arg_count,
100 NPVariant *result);
102 // If the given property is exposed by the C++ class associated with this
103 // NPObject, returns its value. Otherwise, returns "undefined" (in the
104 // JavaScript sense). Called by the JS runtime.
105 static bool getProperty(NPObject *obj, NPIdentifier ident,
106 NPVariant *result);
108 // If the given property is exposed by the C++ class associated with this
109 // NPObject, sets its value. Otherwise, does nothing. Called by the JS
110 // runtime.
111 static bool setProperty(NPObject *obj, NPIdentifier ident,
112 const NPVariant *value);
115 // Build CppNPObject's static function pointers into an NPClass, for use
116 // in constructing NPObjects for the C++ classes.
117 NPClass CppNPObject::np_class_ = {
118 NP_CLASS_STRUCT_VERSION,
119 CppNPObject::allocate,
120 CppNPObject::deallocate,
121 /* NPInvalidateFunctionPtr */ NULL,
122 CppNPObject::hasMethod,
123 CppNPObject::invoke,
124 /* NPInvokeDefaultFunctionPtr */ NULL,
125 CppNPObject::hasProperty,
126 CppNPObject::getProperty,
127 CppNPObject::setProperty,
128 /* NPRemovePropertyFunctionPtr */ NULL
131 /* static */ NPObject* CppNPObject::allocate(NPP npp, NPClass* aClass) {
132 CppNPObject* obj = new CppNPObject;
133 // obj->parent will be initialized by the NPObject code calling this.
134 obj->bound_class = NULL;
135 return &obj->parent;
138 /* static */ void CppNPObject::deallocate(NPObject* np_obj) {
139 CppNPObject* obj = reinterpret_cast<CppNPObject*>(np_obj);
140 delete obj;
143 /* static */ bool CppNPObject::hasMethod(NPObject* np_obj,
144 NPIdentifier ident) {
145 CppNPObject* obj = reinterpret_cast<CppNPObject*>(np_obj);
146 return obj->bound_class->HasMethod(ident);
149 /* static */ bool CppNPObject::hasProperty(NPObject* np_obj,
150 NPIdentifier ident) {
151 CppNPObject* obj = reinterpret_cast<CppNPObject*>(np_obj);
152 return obj->bound_class->HasProperty(ident);
155 /* static */ bool CppNPObject::invoke(NPObject* np_obj, NPIdentifier ident,
156 const NPVariant* args, uint32_t arg_count,
157 NPVariant* result) {
158 CppNPObject* obj = reinterpret_cast<CppNPObject*>(np_obj);
159 return obj->bound_class->Invoke(ident, args, arg_count, result);
162 /* static */ bool CppNPObject::getProperty(NPObject* np_obj,
163 NPIdentifier ident,
164 NPVariant* result) {
165 CppNPObject* obj = reinterpret_cast<CppNPObject*>(np_obj);
166 return obj->bound_class->GetProperty(ident, result);
169 /* static */ bool CppNPObject::setProperty(NPObject* np_obj,
170 NPIdentifier ident,
171 const NPVariant* value) {
172 CppNPObject* obj = reinterpret_cast<CppNPObject*>(np_obj);
173 return obj->bound_class->SetProperty(ident, value);
176 CppBoundClass::CppBoundClass()
177 : bound_to_frame_(false) {
180 CppBoundClass::~CppBoundClass() {
181 for (MethodList::iterator i = methods_.begin(); i != methods_.end(); ++i)
182 delete i->second;
184 for (PropertyList::iterator i = properties_.begin(); i != properties_.end();
185 ++i) {
186 delete i->second;
189 // Unregister ourselves if we were bound to a frame.
190 if (bound_to_frame_)
191 WebBindings::unregisterObject(NPVARIANT_TO_OBJECT(self_variant_));
194 bool CppBoundClass::HasMethod(NPIdentifier ident) const {
195 return (methods_.find(ident) != methods_.end());
198 bool CppBoundClass::HasProperty(NPIdentifier ident) const {
199 return (properties_.find(ident) != properties_.end());
202 bool CppBoundClass::Invoke(NPIdentifier ident,
203 const NPVariant* args,
204 size_t arg_count,
205 NPVariant* result) {
206 MethodList::const_iterator method = methods_.find(ident);
207 Callback* callback;
208 if (method == methods_.end()) {
209 if (fallback_callback_.get()) {
210 callback = fallback_callback_.get();
211 } else {
212 VOID_TO_NPVARIANT(*result);
213 return false;
215 } else {
216 callback = (*method).second;
219 // Build a CppArgumentList argument vector from the NPVariants coming in.
220 CppArgumentList cpp_args(arg_count);
221 for (size_t i = 0; i < arg_count; i++)
222 cpp_args[i].Set(args[i]);
224 CppVariant cpp_result;
225 callback->Run(cpp_args, &cpp_result);
227 cpp_result.CopyToNPVariant(result);
228 return true;
231 bool CppBoundClass::GetProperty(NPIdentifier ident, NPVariant* result) const {
232 PropertyList::const_iterator callback = properties_.find(ident);
233 if (callback == properties_.end()) {
234 VOID_TO_NPVARIANT(*result);
235 return false;
238 CppVariant cpp_value;
239 if (!callback->second->GetValue(&cpp_value))
240 return false;
241 cpp_value.CopyToNPVariant(result);
242 return true;
245 bool CppBoundClass::SetProperty(NPIdentifier ident,
246 const NPVariant* value) {
247 PropertyList::iterator callback = properties_.find(ident);
248 if (callback == properties_.end())
249 return false;
251 CppVariant cpp_value;
252 cpp_value.Set(*value);
253 return (*callback).second->SetValue(cpp_value);
256 void CppBoundClass::BindCallback(const std::string& name, Callback* callback) {
257 NPIdentifier ident = WebBindings::getStringIdentifier(name.c_str());
258 MethodList::iterator old_callback = methods_.find(ident);
259 if (old_callback != methods_.end()) {
260 delete old_callback->second;
261 if (callback == NULL) {
262 methods_.erase(old_callback);
263 return;
267 methods_[ident] = callback;
270 void CppBoundClass::BindGetterCallback(const std::string& name,
271 GetterCallback* callback) {
272 PropertyCallback* property_callback = callback == NULL ?
273 NULL : new GetterPropertyCallback(callback);
275 BindProperty(name, property_callback);
278 void CppBoundClass::BindProperty(const std::string& name, CppVariant* prop) {
279 PropertyCallback* property_callback = prop == NULL ?
280 NULL : new CppVariantPropertyCallback(prop);
282 BindProperty(name, property_callback);
285 void CppBoundClass::BindProperty(const std::string& name,
286 PropertyCallback* callback) {
287 NPIdentifier ident = WebBindings::getStringIdentifier(name.c_str());
288 PropertyList::iterator old_callback = properties_.find(ident);
289 if (old_callback != properties_.end()) {
290 delete old_callback->second;
291 if (callback == NULL) {
292 properties_.erase(old_callback);
293 return;
297 properties_[ident] = callback;
300 bool CppBoundClass::IsMethodRegistered(const std::string& name) const {
301 NPIdentifier ident = WebBindings::getStringIdentifier(name.c_str());
302 MethodList::const_iterator callback = methods_.find(ident);
303 return (callback != methods_.end());
306 CppVariant* CppBoundClass::GetAsCppVariant() {
307 if (!self_variant_.isObject()) {
308 // Create an NPObject using our static NPClass. The first argument (a
309 // plugin's instance handle) is passed through to the allocate function
310 // directly, and we don't use it, so it's ok to be 0.
311 NPObject* np_obj = WebBindings::createObject(0, &CppNPObject::np_class_);
312 CppNPObject* obj = reinterpret_cast<CppNPObject*>(np_obj);
313 obj->bound_class = this;
314 self_variant_.Set(np_obj);
315 WebBindings::releaseObject(np_obj); // CppVariant takes the reference.
317 DCHECK(self_variant_.isObject());
318 return &self_variant_;
321 void CppBoundClass::BindToJavascript(WebFrame* frame,
322 const std::string& classname) {
323 #if WEBKIT_USING_JSC
324 #error "This is not going to work anymore...but it's not clear what the solution is...or if it's still necessary."
325 JSC::JSLock lock(false);
326 #endif
328 // BindToWindowObject will take its own reference to the NPObject, and clean
329 // up after itself. It will also (indirectly) register the object with V8,
330 // so we must remember this so we can unregister it when we're destroyed.
331 frame->bindToWindowObject(ASCIIToUTF16(classname),
332 NPVARIANT_TO_OBJECT(*GetAsCppVariant()));
333 bound_to_frame_ = true;