1 /* 2 * Copyright (C) 2010 Google Inc. All rights reserved. 3 * Copyright (C) 2009 Pawel Hajdan (phajdan.jr@chromium.org) 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: 8 * 9 * * Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * * Redistributions in binary form must reproduce the above 12 * copyright notice, this list of conditions and the following disclaimer 13 * in the documentation and/or other materials provided with the 14 * distribution. 15 * * Neither the name of Google Inc. nor the names of its 16 * contributors may be used to endorse or promote products derived from 17 * this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 CppBoundClass class: 34 This base class serves as a parent for C++ classes designed to be bound to 35 JavaScript objects. 36 37 Subclasses should define the constructor to build the property and method 38 lists needed to bind this class to a JS object. They should also declare 39 and define member variables and methods to be exposed to JS through 40 that object. 41 */ 42 43 #ifndef CppBoundClass_h 44 #define CppBoundClass_h 45 46 #include "CppVariant.h" 47 #include <wtf/HashMap.h> 48 #include <wtf/Noncopyable.h> 49 #include <wtf/OwnPtr.h> 50 #include <wtf/Vector.h> 51 52 namespace WebKit { 53 class WebFrame; 54 class WebString; 55 } 56 57 typedef Vector<CppVariant> CppArgumentList; 58 59 // CppBoundClass lets you map Javascript method calls and property accesses 60 // directly to C++ method calls and CppVariant* variable access. 61 class CppBoundClass { 62 WTF_MAKE_NONCOPYABLE(CppBoundClass); 63 public: 64 class PropertyCallback { 65 public: ~PropertyCallback()66 virtual ~PropertyCallback() { } 67 68 // Sets |value| to the value of the property. Returns false in case of 69 // failure. |value| is always non-0. 70 virtual bool getValue(CppVariant* result) = 0; 71 72 // sets the property value to |value|. Returns false in case of failure. 73 virtual bool setValue(const CppVariant&) = 0; 74 }; 75 76 // Callback class for "void function(CppVariant*)" 77 class GetterCallback { 78 public: ~GetterCallback()79 virtual ~GetterCallback() {} 80 virtual void run(CppVariant*) = 0; 81 }; 82 83 // The constructor should call BindMethod, BindProperty, and 84 // SetFallbackMethod as needed to set up the methods, properties, and 85 // fallback method. CppBoundClass()86 CppBoundClass() : m_boundToFrame(false) {} 87 virtual ~CppBoundClass(); 88 89 // Return a CppVariant representing this class, for use with BindProperty(). 90 // The variant type is guaranteed to be NPVariantType_Object. 91 CppVariant* getAsCppVariant(); 92 93 // Given a WebFrame, BindToJavascript builds the NPObject that will represent 94 // the class and binds it to the frame's window under the given name. This 95 // should generally be called from the WebView delegate's 96 // WindowObjectCleared(). A class so bound will be accessible to JavaScript 97 // as window.<classname>. The owner of the CppBoundObject is responsible for 98 // keeping the object around while the frame is alive, and for destroying it 99 // afterwards. 100 void bindToJavascript(WebKit::WebFrame*, const WebKit::WebString& classname); 101 102 // Used by a test. Returns true if a method with name |name| exists, 103 // regardless of whether a fallback is registered. 104 bool isMethodRegistered(const std::string&) const; 105 106 protected: 107 // Callback for "void function(const CppArguemntList&, CppVariant*)" 108 class Callback { 109 public: ~Callback()110 virtual ~Callback() {} 111 virtual void run(const CppArgumentList&, CppVariant*) = 0; 112 }; 113 114 // Callback for "void T::method(const CppArguemntList&, CppVariant*)" 115 template <class T> class MemberCallback : public Callback { 116 public: 117 typedef void (T::*MethodType)(const CppArgumentList&, CppVariant*); MemberCallback(T * object,MethodType method)118 MemberCallback(T* object, MethodType method) 119 : m_object(object) 120 , m_method(method) {} ~MemberCallback()121 virtual ~MemberCallback() {} 122 run(const CppArgumentList & arguments,CppVariant * result)123 virtual void run(const CppArgumentList& arguments, CppVariant* result) 124 { 125 (m_object->*m_method)(arguments, result); 126 } 127 private: 128 T* m_object; 129 MethodType m_method; 130 }; 131 132 // Callback class for "void T::method(CppVariant*)" 133 template <class T> class MemberGetterCallback : public GetterCallback { 134 public: 135 typedef void (T::*MethodType)(CppVariant*); MemberGetterCallback(T * object,MethodType method)136 MemberGetterCallback(T* object, MethodType method) 137 : m_object(object) 138 , m_method(method) {} ~MemberGetterCallback()139 virtual ~MemberGetterCallback() {} 140 run(CppVariant * result)141 virtual void run(CppVariant* result) { (m_object->*m_method)(result); } 142 private: 143 T* m_object; 144 MethodType m_method; 145 }; 146 147 // Bind the Javascript method called the string parameter to the C++ method. 148 void bindCallback(const std::string&, Callback*); 149 150 // A wrapper for bindCallback, to simplify the common case of binding a 151 // method on the current object. Though not verified here, |method| 152 // must be a method of this CppBoundClass subclass. 153 template<class T> bindMethod(const std::string & name,void (T::* method)(const CppArgumentList &,CppVariant *))154 void bindMethod(const std::string& name, void (T::*method)(const CppArgumentList&, CppVariant*)) 155 { 156 Callback* callback = new MemberCallback<T>(static_cast<T*>(this), method); 157 bindCallback(name, callback); 158 } 159 160 // Bind Javascript property |name| to the C++ getter callback |callback|. 161 // This can be used to create read-only properties. 162 void bindGetterCallback(const std::string&, GetterCallback*); 163 164 // A wrapper for BindGetterCallback, to simplify the common case of binding a 165 // property on the current object. Though not verified here, |method| 166 // must be a method of this CppBoundClass subclass. 167 template<class T> bindProperty(const std::string & name,void (T::* method)(CppVariant *))168 void bindProperty(const std::string& name, void (T::*method)(CppVariant*)) 169 { 170 GetterCallback* callback = new MemberGetterCallback<T>(static_cast<T*>(this), method); 171 bindGetterCallback(name, callback); 172 } 173 174 // Bind the Javascript property called |name| to a CppVariant. 175 void bindProperty(const std::string&, CppVariant*); 176 177 // Bind Javascript property called |name| to a PropertyCallback. 178 // CppBoundClass assumes control over the life time of the callback. 179 void bindProperty(const std::string&, PropertyCallback*); 180 181 // Set the fallback callback, which is called when when a callback is 182 // invoked that isn't bound. 183 // If it is 0 (its default value), a JavaScript exception is thrown in 184 // that case (as normally expected). If non 0, the fallback method is 185 // invoked and the script continues its execution. 186 // Passing 0 clears out any existing binding. 187 // It is used for tests and should probably only be used in such cases 188 // as it may cause unexpected behaviors (a JavaScript object with a 189 // fallback always returns true when checked for a method's 190 // existence). bindFallbackCallback(Callback * fallbackCallback)191 void bindFallbackCallback(Callback* fallbackCallback) 192 { 193 m_fallbackCallback.set(fallbackCallback); 194 } 195 196 // A wrapper for BindFallbackCallback, to simplify the common case of 197 // binding a method on the current object. Though not verified here, 198 // |method| must be a method of this CppBoundClass subclass. 199 // Passing 0 for |method| clears out any existing binding. 200 template<class T> bindFallbackMethod(void (T::* method)(const CppArgumentList &,CppVariant *))201 void bindFallbackMethod(void (T::*method)(const CppArgumentList&, CppVariant*)) 202 { 203 if (method) { 204 Callback* callback = new MemberCallback<T>(static_cast<T*>(this), method); 205 bindFallbackCallback(callback); 206 } else 207 bindFallbackCallback(0); 208 } 209 210 // Some fields are protected because some tests depend on accessing them, 211 // but otherwise they should be considered private. 212 213 typedef HashMap<NPIdentifier, PropertyCallback*> PropertyList; 214 typedef HashMap<NPIdentifier, Callback*> MethodList; 215 // These maps associate names with property and method pointers to be 216 // exposed to JavaScript. 217 PropertyList m_properties; 218 MethodList m_methods; 219 220 // The callback gets invoked when a call is made to an nonexistent method. 221 OwnPtr<Callback> m_fallbackCallback; 222 223 private: 224 // NPObject callbacks. 225 friend struct CppNPObject; 226 bool hasMethod(NPIdentifier) const; 227 bool invoke(NPIdentifier, const NPVariant* args, size_t argCount, 228 NPVariant* result); 229 bool hasProperty(NPIdentifier) const; 230 bool getProperty(NPIdentifier, NPVariant* result) const; 231 bool setProperty(NPIdentifier, const NPVariant*); 232 233 // A lazily-initialized CppVariant representing this class. We retain 1 234 // reference to this object, and it is released on deletion. 235 CppVariant m_selfVariant; 236 237 // True if our np_object has been bound to a WebFrame, in which case it must 238 // be unregistered with V8 when we delete it. 239 bool m_boundToFrame; 240 }; 241 242 #endif // CppBoundClass_h 243