1 // Copyright (c) 2011 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 /* 6 CppBoundClass class: 7 This base class serves as a parent for C++ classes designed to be bound to 8 JavaScript objects. 9 10 Subclasses should define the constructor to build the property and method 11 lists needed to bind this class to a JS object. They should also declare 12 and define member variables and methods to be exposed to JS through 13 that object. 14 15 See cpp_binding_example.{h|cc} for an example. 16 */ 17 18 #ifndef WEBKIT_GLUE_CPP_BOUNDCLASS_H__ 19 #define WEBKIT_GLUE_CPP_BOUNDCLASS_H__ 20 21 #include <map> 22 #include <vector> 23 24 #include "webkit/glue/cpp_variant.h" 25 26 #include "base/callback.h" 27 #include "base/memory/scoped_ptr.h" 28 29 namespace WebKit { 30 class WebFrame; 31 } 32 33 typedef std::vector<CppVariant> CppArgumentList; 34 35 // CppBoundClass lets you map Javascript method calls and property accesses 36 // directly to C++ method calls and CppVariant* variable access. 37 class CppBoundClass { 38 public: 39 class PropertyCallback { 40 public: ~PropertyCallback()41 virtual ~PropertyCallback() { } 42 43 // Sets |value| to the value of the property. Returns false in case of 44 // failure. |value| is always non-NULL. 45 virtual bool GetValue(CppVariant* value) = 0; 46 47 // sets the property value to |value|. Returns false in case of failure. 48 virtual bool SetValue(const CppVariant& value) = 0; 49 }; 50 51 // The constructor should call BindMethod, BindProperty, and 52 // SetFallbackMethod as needed to set up the methods, properties, and 53 // fallback method. 54 CppBoundClass(); 55 virtual ~CppBoundClass(); 56 57 // Return a CppVariant representing this class, for use with BindProperty(). 58 // The variant type is guaranteed to be NPVariantType_Object. 59 CppVariant* GetAsCppVariant(); 60 61 // Given a WebFrame, BindToJavascript builds the NPObject that will represent 62 // the class and binds it to the frame's window under the given name. This 63 // should generally be called from the WebView delegate's 64 // WindowObjectCleared(). A class so bound will be accessible to JavaScript 65 // as window.<classname>. The owner of the CppBoundObject is responsible for 66 // keeping the object around while the frame is alive, and for destroying it 67 // afterwards. 68 void BindToJavascript(WebKit::WebFrame* frame, const std::string& classname); 69 70 // The type of callbacks. 71 typedef Callback2<const CppArgumentList&, CppVariant*>::Type Callback; 72 typedef Callback1<CppVariant*>::Type GetterCallback; 73 74 // Used by a test. Returns true if a method with name |name| exists, 75 // regardless of whether a fallback is registered. 76 bool IsMethodRegistered(const std::string& name) const; 77 78 protected: 79 // Bind the Javascript method called |name| to the C++ callback |callback|. 80 void BindCallback(const std::string& name, Callback* callback); 81 82 // A wrapper for BindCallback, to simplify the common case of binding a 83 // method on the current object. Though not verified here, |method| 84 // must be a method of this CppBoundClass subclass. 85 template<typename T> BindMethod(const std::string & name,void (T::* method)(const CppArgumentList &,CppVariant *))86 void BindMethod(const std::string& name, 87 void (T::*method)(const CppArgumentList&, CppVariant*)) { 88 Callback* callback = 89 NewCallback<T, const CppArgumentList&, CppVariant*>( 90 static_cast<T*>(this), method); 91 BindCallback(name, callback); 92 } 93 94 // Bind Javascript property |name| to the C++ getter callback |callback|. 95 // This can be used to create read-only properties. 96 void BindGetterCallback(const std::string& name, GetterCallback* callback); 97 98 // A wrapper for BindGetterCallback, to simplify the common case of binding a 99 // property on the current object. Though not verified here, |method| 100 // must be a method of this CppBoundClass subclass. 101 template<typename T> BindProperty(const std::string & name,void (T::* method)(CppVariant *))102 void BindProperty(const std::string& name, void (T::*method)(CppVariant*)) { 103 GetterCallback* callback = 104 NewCallback<T, CppVariant*>(static_cast<T*>(this), method); 105 BindGetterCallback(name, callback); 106 } 107 108 // Bind the Javascript property called |name| to a CppVariant |prop|. 109 void BindProperty(const std::string& name, CppVariant* prop); 110 111 // Bind Javascript property called |name| to a PropertyCallback |callback|. 112 // CppBoundClass assumes control over the life time of the |callback|. 113 void BindProperty(const std::string& name, PropertyCallback* callback); 114 115 // Set the fallback callback, which is called when when a callback is 116 // invoked that isn't bound. 117 // If it is NULL (its default value), a JavaScript exception is thrown in 118 // that case (as normally expected). If non NULL, the fallback method is 119 // invoked and the script continues its execution. 120 // Passing NULL for |callback| clears out any existing binding. 121 // It is used for tests and should probably only be used in such cases 122 // as it may cause unexpected behaviors (a JavaScript object with a 123 // fallback always returns true when checked for a method's 124 // existence). BindFallbackCallback(Callback * fallback_callback)125 void BindFallbackCallback(Callback* fallback_callback) { 126 fallback_callback_.reset(fallback_callback); 127 } 128 129 // A wrapper for BindFallbackCallback, to simplify the common case of 130 // binding a method on the current object. Though not verified here, 131 // |method| must be a method of this CppBoundClass subclass. 132 // Passing NULL for |method| clears out any existing binding. 133 template<typename T> BindFallbackMethod(void (T::* method)(const CppArgumentList &,CppVariant *))134 void BindFallbackMethod( 135 void (T::*method)(const CppArgumentList&, CppVariant*)) { 136 if (method) { 137 Callback* callback = 138 NewCallback<T, const CppArgumentList&, CppVariant*>( 139 static_cast<T*>(this), method); 140 BindFallbackCallback(callback); 141 } else { 142 BindFallbackCallback(NULL); 143 } 144 } 145 146 // Some fields are protected because some tests depend on accessing them, 147 // but otherwise they should be considered private. 148 149 typedef std::map<NPIdentifier, PropertyCallback*> PropertyList; 150 typedef std::map<NPIdentifier, Callback*> MethodList; 151 // These maps associate names with property and method pointers to be 152 // exposed to JavaScript. 153 PropertyList properties_; 154 MethodList methods_; 155 156 // The callback gets invoked when a call is made to an nonexistent method. 157 scoped_ptr<Callback> fallback_callback_; 158 159 private: 160 // NPObject callbacks. 161 friend struct CppNPObject; 162 bool HasMethod(NPIdentifier ident) const; 163 bool Invoke(NPIdentifier ident, const NPVariant* args, size_t arg_count, 164 NPVariant* result); 165 bool HasProperty(NPIdentifier ident) const; 166 bool GetProperty(NPIdentifier ident, NPVariant* result) const; 167 bool SetProperty(NPIdentifier ident, const NPVariant* value); 168 169 // A lazily-initialized CppVariant representing this class. We retain 1 170 // reference to this object, and it is released on deletion. 171 CppVariant self_variant_; 172 173 // True if our np_object has been bound to a WebFrame, in which case it must 174 // be unregistered with V8 when we delete it. 175 bool bound_to_frame_; 176 177 DISALLOW_COPY_AND_ASSIGN(CppBoundClass); 178 }; 179 180 #endif // CPP_BOUNDCLASS_H__ 181