• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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