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 "public/platform/WebNonCopyable.h" 48 #include "public/testing/WebScopedPtr.h" 49 #include <map> 50 #include <vector> 51 52 namespace blink { 53 class WebFrame; 54 class WebString; 55 } 56 57 namespace WebTestRunner { 58 59 typedef std::vector<CppVariant> CppArgumentList; 60 61 // CppBoundClass lets you map Javascript method calls and property accesses 62 // directly to C++ method calls and CppVariant* variable access. 63 class CppBoundClass : public blink::WebNonCopyable { 64 public: 65 class PropertyCallback { 66 public: ~PropertyCallback()67 virtual ~PropertyCallback() { } 68 69 // Sets |value| to the value of the property. Returns false in case of 70 // failure. |value| is always non-0. 71 virtual bool getValue(CppVariant* result) = 0; 72 73 // sets the property value to |value|. Returns false in case of failure. 74 virtual bool setValue(const CppVariant&) = 0; 75 }; 76 77 // Callback class for "void function(CppVariant*)" 78 class GetterCallback { 79 public: ~GetterCallback()80 virtual ~GetterCallback() { } 81 virtual void run(CppVariant*) = 0; 82 }; 83 84 // The constructor should call BindMethod, BindProperty, and 85 // SetFallbackMethod as needed to set up the methods, properties, and 86 // fallback method. CppBoundClass()87 CppBoundClass() : m_boundToFrame(false) { } 88 virtual ~CppBoundClass(); 89 90 // Return a CppVariant representing this class, for use with BindProperty(). 91 // The variant type is guaranteed to be NPVariantType_Object. 92 CppVariant* getAsCppVariant(); 93 94 // Given a WebFrame, BindToJavascript builds the NPObject that will represent 95 // the class and binds it to the frame's window under the given name. This 96 // should generally be called from the WebView delegate's 97 // WindowObjectCleared(). A class so bound will be accessible to JavaScript 98 // as window.<classname>. The owner of the CppBoundObject is responsible for 99 // keeping the object around while the frame is alive, and for destroying it 100 // afterwards. 101 void bindToJavascript(blink::WebFrame*, const blink::WebString& classname); 102 103 // Used by a test. Returns true if a method with the specified name exists, 104 // regardless of whether a fallback is registered. 105 bool isMethodRegistered(const std::string&) const; 106 107 protected: 108 // Callback for "void function(const CppArguemntList&, CppVariant*)" 109 class Callback { 110 public: ~Callback()111 virtual ~Callback() { } 112 virtual void run(const CppArgumentList&, CppVariant*) = 0; 113 }; 114 115 // Callback for "void T::method(const CppArguemntList&, CppVariant*)" 116 template <class T> class MemberCallback : public Callback { 117 public: 118 typedef void (T::*MethodType)(const CppArgumentList&, CppVariant*); MemberCallback(T * object,MethodType method)119 MemberCallback(T* object, MethodType method) 120 : m_object(object) 121 , m_method(method) { } ~MemberCallback()122 virtual ~MemberCallback() { } 123 run(const CppArgumentList & arguments,CppVariant * result)124 virtual void run(const CppArgumentList& arguments, CppVariant* result) 125 { 126 (m_object->*m_method)(arguments, result); 127 } 128 129 private: 130 T* m_object; 131 MethodType m_method; 132 }; 133 134 // Callback class for "void T::method(CppVariant*)" 135 template <class T> class MemberGetterCallback : public GetterCallback { 136 public: 137 typedef void (T::*MethodType)(CppVariant*); MemberGetterCallback(T * object,MethodType method)138 MemberGetterCallback(T* object, MethodType method) 139 : m_object(object) 140 , m_method(method) { } ~MemberGetterCallback()141 virtual ~MemberGetterCallback() { } 142 run(CppVariant * result)143 virtual void run(CppVariant* result) { (m_object->*m_method)(result); } 144 145 private: 146 T* m_object; 147 MethodType m_method; 148 }; 149 150 // Bind the Javascript method called the string parameter to the C++ method. 151 void bindCallback(const std::string&, Callback*); 152 153 // A wrapper for bindCallback, to simplify the common case of binding a 154 // method on the current object. Though not verified here, the method parameter 155 // must be a method of this CppBoundClass subclass. 156 template<class T> bindMethod(const std::string & name,void (T::* method)(const CppArgumentList &,CppVariant *))157 void bindMethod(const std::string& name, void (T::*method)(const CppArgumentList&, CppVariant*)) 158 { 159 Callback* callback = new MemberCallback<T>(static_cast<T*>(this), method); 160 bindCallback(name, callback); 161 } 162 163 // Bind Javascript property |name| to the C++ getter callback |callback|. 164 // This can be used to create read-only properties. 165 void bindGetterCallback(const std::string&, WebScopedPtr<GetterCallback>); 166 167 // A wrapper for BindGetterCallback, to simplify the common case of binding a 168 // property on the current object. Though not verified here, the method parameter 169 // must be a method of this CppBoundClass subclass. 170 template<class T> bindProperty(const std::string & name,void (T::* method)(CppVariant *))171 void bindProperty(const std::string& name, void (T::*method)(CppVariant*)) 172 { 173 WebScopedPtr<GetterCallback> callback(new MemberGetterCallback<T>(static_cast<T*>(this), method)); 174 bindGetterCallback(name, callback); 175 } 176 177 // Bind the Javascript property called |name| to a CppVariant. 178 void bindProperty(const std::string&, CppVariant*); 179 180 // Bind Javascript property called |name| to a PropertyCallback. 181 // CppBoundClass assumes control over the life time of the callback. 182 void bindProperty(const std::string&, PropertyCallback*); 183 184 // Set the fallback callback, which is called when when a callback is 185 // invoked that isn't bound. 186 // If it is 0 (its default value), a JavaScript exception is thrown in 187 // that case (as normally expected). If non 0, the fallback method is 188 // invoked and the script continues its execution. 189 // Passing 0 clears out any existing binding. 190 // It is used for tests and should probably only be used in such cases 191 // as it may cause unexpected behaviors (a JavaScript object with a 192 // fallback always returns true when checked for a method's 193 // existence). bindFallbackCallback(WebScopedPtr<Callback> fallbackCallback)194 void bindFallbackCallback(WebScopedPtr<Callback> fallbackCallback) 195 { 196 m_fallbackCallback = fallbackCallback; 197 } 198 199 // A wrapper for BindFallbackCallback, to simplify the common case of 200 // binding a method on the current object. Though not verified here, 201 // |method| must be a method of this CppBoundClass subclass. 202 // Passing 0 for |method| clears out any existing binding. 203 template<class T> bindFallbackMethod(void (T::* method)(const CppArgumentList &,CppVariant *))204 void bindFallbackMethod(void (T::*method)(const CppArgumentList&, CppVariant*)) 205 { 206 if (method) 207 bindFallbackCallback(WebScopedPtr<Callback>(new MemberCallback<T>(static_cast<T*>(this), method))); 208 else 209 bindFallbackCallback(WebScopedPtr<Callback>()); 210 } 211 212 // Some fields are protected because some tests depend on accessing them, 213 // but otherwise they should be considered private. 214 215 typedef std::map<NPIdentifier, PropertyCallback*> PropertyList; 216 typedef std::map<NPIdentifier, Callback*> MethodList; 217 // These maps associate names with property and method pointers to be 218 // exposed to JavaScript. 219 PropertyList m_properties; 220 MethodList m_methods; 221 222 // The callback gets invoked when a call is made to an nonexistent method. 223 WebScopedPtr<Callback> m_fallbackCallback; 224 225 private: 226 // NPObject callbacks. 227 friend struct CppNPObject; 228 bool hasMethod(NPIdentifier) const; 229 bool invoke(NPIdentifier, const NPVariant* args, size_t argCount, 230 NPVariant* result); 231 bool hasProperty(NPIdentifier) const; 232 bool getProperty(NPIdentifier, NPVariant* result) const; 233 bool setProperty(NPIdentifier, const NPVariant*); 234 235 // A lazily-initialized CppVariant representing this class. We retain 1 236 // reference to this object, and it is released on deletion. 237 CppVariant m_selfVariant; 238 239 // True if our np_object has been bound to a WebFrame, in which case it must 240 // be unregistered with V8 when we delete it. 241 bool m_boundToFrame; 242 }; 243 244 } 245 246 #endif // CppBoundClass_h 247