1 /* 2 * Copyright (C) 2010 Google Inc. All rights reserved. 3 * Copyright (C) 2009 Pawel Hajdan (phajdan.jr (at) 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 <map> 48 #include <memory> 49 #include <vector> 50 51 namespace WebKit { 52 class WebFrame; 53 class WebString; 54 } 55 56 namespace WebTestRunner { 57 58 typedef std::vector<CppVariant> CppArgumentList; 59 60 // CppBoundClass lets you map Javascript method calls and property accesses 61 // directly to C++ method calls and CppVariant* variable access. 62 class CppBoundClass { 63 public: 64 class PropertyCallback { 65 public: 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: 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. 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 the specified 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: 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*); 118 MemberCallback(T* object, MethodType method) 119 : m_object(object) 120 , m_method(method) { } 121 virtual ~MemberCallback() { } 122 123 virtual void run(const CppArgumentList& arguments, CppVariant* result) 124 { 125 (m_object->*m_method)(arguments, result); 126 } 127 128 private: 129 T* m_object; 130 MethodType m_method; 131 }; 132 133 // Callback class for "void T::method(CppVariant*)" 134 template <class T> class MemberGetterCallback : public GetterCallback { 135 public: 136 typedef void (T::*MethodType)(CppVariant*); 137 MemberGetterCallback(T* object, MethodType method) 138 : m_object(object) 139 , m_method(method) { } 140 virtual ~MemberGetterCallback() { } 141 142 virtual void run(CppVariant* result) { (m_object->*m_method)(result); } 143 144 private: 145 T* m_object; 146 MethodType m_method; 147 }; 148 149 // Bind the Javascript method called the string parameter to the C++ method. 150 void bindCallback(const std::string&, Callback*); 151 152 // A wrapper for bindCallback, to simplify the common case of binding a 153 // method on the current object. Though not verified here, the method parameter 154 // must be a method of this CppBoundClass subclass. 155 template<class T> 156 void bindMethod(const std::string& name, void (T::*method)(const CppArgumentList&, CppVariant*)) 157 { 158 Callback* callback = new MemberCallback<T>(static_cast<T*>(this), method); 159 bindCallback(name, callback); 160 } 161 162 // Bind Javascript property |name| to the C++ getter callback |callback|. 163 // This can be used to create read-only properties. 164 void bindGetterCallback(const std::string&, std::auto_ptr<GetterCallback>); 165 166 // A wrapper for BindGetterCallback, to simplify the common case of binding a 167 // property on the current object. Though not verified here, the method parameter 168 // must be a method of this CppBoundClass subclass. 169 template<class T> 170 void bindProperty(const std::string& name, void (T::*method)(CppVariant*)) 171 { 172 std::auto_ptr<GetterCallback> callback(new MemberGetterCallback<T>(static_cast<T*>(this), method)); 173 bindGetterCallback(name, callback); 174 } 175 176 // Bind the Javascript property called |name| to a CppVariant. 177 void bindProperty(const std::string&, CppVariant*); 178 179 // Bind Javascript property called |name| to a PropertyCallback. 180 // CppBoundClass assumes control over the life time of the callback. 181 void bindProperty(const std::string&, PropertyCallback*); 182 183 // Set the fallback callback, which is called when when a callback is 184 // invoked that isn't bound. 185 // If it is 0 (its default value), a JavaScript exception is thrown in 186 // that case (as normally expected). If non 0, the fallback method is 187 // invoked and the script continues its execution. 188 // Passing 0 clears out any existing binding. 189 // It is used for tests and should probably only be used in such cases 190 // as it may cause unexpected behaviors (a JavaScript object with a 191 // fallback always returns true when checked for a method's 192 // existence). 193 void bindFallbackCallback(std::auto_ptr<Callback> fallbackCallback) 194 { 195 m_fallbackCallback = fallbackCallback; 196 } 197 198 // A wrapper for BindFallbackCallback, to simplify the common case of 199 // binding a method on the current object. Though not verified here, 200 // |method| must be a method of this CppBoundClass subclass. 201 // Passing 0 for |method| clears out any existing binding. 202 template<class T> 203 void bindFallbackMethod(void (T::*method)(const CppArgumentList&, CppVariant*)) 204 { 205 if (method) 206 bindFallbackCallback(std::auto_ptr<Callback>(new MemberCallback<T>(static_cast<T*>(this), method))); 207 else 208 bindFallbackCallback(std::auto_ptr<Callback>()); 209 } 210 211 // Some fields are protected because some tests depend on accessing them, 212 // but otherwise they should be considered private. 213 214 typedef std::map<NPIdentifier, PropertyCallback*> PropertyList; 215 typedef std::map<NPIdentifier, Callback*> MethodList; 216 // These maps associate names with property and method pointers to be 217 // exposed to JavaScript. 218 PropertyList m_properties; 219 MethodList m_methods; 220 221 // The callback gets invoked when a call is made to an nonexistent method. 222 std::auto_ptr<Callback> m_fallbackCallback; 223 224 private: 225 // NPObject callbacks. 226 friend struct CppNPObject; 227 bool hasMethod(NPIdentifier) const; 228 bool invoke(NPIdentifier, const NPVariant* args, size_t argCount, 229 NPVariant* result); 230 bool hasProperty(NPIdentifier) const; 231 bool getProperty(NPIdentifier, NPVariant* result) const; 232 bool setProperty(NPIdentifier, const NPVariant*); 233 234 // A lazily-initialized CppVariant representing this class. We retain 1 235 // reference to this object, and it is released on deletion. 236 CppVariant m_selfVariant; 237 238 // True if our np_object has been bound to a WebFrame, in which case it must 239 // be unregistered with V8 when we delete it. 240 bool m_boundToFrame; 241 242 private: 243 CppBoundClass(CppBoundClass&); 244 CppBoundClass& operator=(const CppBoundClass&); 245 }; 246 247 } 248 249 #endif // CppBoundClass_h 250