• 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 <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