• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 /*
6   CppBoundClass class:
7   This base class serves as a parent for C++ classes designed to be bound to
8   JavaScript objects.
9 
10   Subclasses should define the constructor to build the property and method
11   lists needed to bind this class to a JS object.  They should also declare
12   and define member variables and methods to be exposed to JS through
13   that object.
14 
15   See cpp_binding_example.{h|cc} for an example.
16 */
17 
18 #ifndef WEBKIT_GLUE_CPP_BOUNDCLASS_H__
19 #define WEBKIT_GLUE_CPP_BOUNDCLASS_H__
20 
21 #include <map>
22 #include <vector>
23 
24 #include "webkit/glue/cpp_variant.h"
25 
26 #include "base/callback.h"
27 #include "base/memory/scoped_ptr.h"
28 
29 namespace WebKit {
30 class WebFrame;
31 }
32 
33 typedef std::vector<CppVariant> CppArgumentList;
34 
35 // CppBoundClass lets you map Javascript method calls and property accesses
36 // directly to C++ method calls and CppVariant* variable access.
37 class CppBoundClass {
38  public:
39   class PropertyCallback {
40    public:
~PropertyCallback()41     virtual ~PropertyCallback() { }
42 
43     // Sets |value| to the value of the property. Returns false in case of
44     // failure. |value| is always non-NULL.
45     virtual bool GetValue(CppVariant* value) = 0;
46 
47     // sets the property value to |value|. Returns false in case of failure.
48     virtual bool SetValue(const CppVariant& value) = 0;
49   };
50 
51   // The constructor should call BindMethod, BindProperty, and
52   // SetFallbackMethod as needed to set up the methods, properties, and
53   // fallback method.
54   CppBoundClass();
55   virtual ~CppBoundClass();
56 
57   // Return a CppVariant representing this class, for use with BindProperty().
58   // The variant type is guaranteed to be NPVariantType_Object.
59   CppVariant* GetAsCppVariant();
60 
61   // Given a WebFrame, BindToJavascript builds the NPObject that will represent
62   // the class and binds it to the frame's window under the given name.  This
63   // should generally be called from the WebView delegate's
64   // WindowObjectCleared(). A class so bound will be accessible to JavaScript
65   // as window.<classname>. The owner of the CppBoundObject is responsible for
66   // keeping the object around while the frame is alive, and for destroying it
67   // afterwards.
68   void BindToJavascript(WebKit::WebFrame* frame, const std::string& classname);
69 
70   // The type of callbacks.
71   typedef Callback2<const CppArgumentList&, CppVariant*>::Type Callback;
72   typedef Callback1<CppVariant*>::Type GetterCallback;
73 
74   // Used by a test.  Returns true if a method with name |name| exists,
75   // regardless of whether a fallback is registered.
76   bool IsMethodRegistered(const std::string& name) const;
77 
78  protected:
79   // Bind the Javascript method called |name| to the C++ callback |callback|.
80   void BindCallback(const std::string& name, Callback* callback);
81 
82   // A wrapper for BindCallback, to simplify the common case of binding a
83   // method on the current object.  Though not verified here, |method|
84   // must be a method of this CppBoundClass subclass.
85   template<typename T>
BindMethod(const std::string & name,void (T::* method)(const CppArgumentList &,CppVariant *))86   void BindMethod(const std::string& name,
87       void (T::*method)(const CppArgumentList&, CppVariant*)) {
88     Callback* callback =
89         NewCallback<T, const CppArgumentList&, CppVariant*>(
90             static_cast<T*>(this), method);
91     BindCallback(name, callback);
92   }
93 
94   // Bind Javascript property |name| to the C++ getter callback |callback|.
95   // This can be used to create read-only properties.
96   void BindGetterCallback(const std::string& name, GetterCallback* callback);
97 
98   // A wrapper for BindGetterCallback, to simplify the common case of binding a
99   // property on the current object.  Though not verified here, |method|
100   // must be a method of this CppBoundClass subclass.
101   template<typename T>
BindProperty(const std::string & name,void (T::* method)(CppVariant *))102   void BindProperty(const std::string& name, void (T::*method)(CppVariant*)) {
103     GetterCallback* callback =
104         NewCallback<T, CppVariant*>(static_cast<T*>(this), method);
105     BindGetterCallback(name, callback);
106   }
107 
108   // Bind the Javascript property called |name| to a CppVariant |prop|.
109   void BindProperty(const std::string& name, CppVariant* prop);
110 
111   // Bind Javascript property called |name| to a PropertyCallback |callback|.
112   // CppBoundClass assumes control over the life time of the |callback|.
113   void BindProperty(const std::string& name, PropertyCallback* callback);
114 
115   // Set the fallback callback, which is called when when a callback is
116   // invoked that isn't bound.
117   // If it is NULL (its default value), a JavaScript exception is thrown in
118   // that case (as normally expected). If non NULL, the fallback method is
119   // invoked and the script continues its execution.
120   // Passing NULL for |callback| clears out any existing binding.
121   // It is used for tests and should probably only be used in such cases
122   // as it may cause unexpected behaviors (a JavaScript object with a
123   // fallback always returns true when checked for a method's
124   // existence).
BindFallbackCallback(Callback * fallback_callback)125   void BindFallbackCallback(Callback* fallback_callback) {
126     fallback_callback_.reset(fallback_callback);
127   }
128 
129   // A wrapper for BindFallbackCallback, to simplify the common case of
130   // binding a method on the current object.  Though not verified here,
131   // |method| must be a method of this CppBoundClass subclass.
132   // Passing NULL for |method| clears out any existing binding.
133   template<typename T>
BindFallbackMethod(void (T::* method)(const CppArgumentList &,CppVariant *))134   void BindFallbackMethod(
135       void (T::*method)(const CppArgumentList&, CppVariant*)) {
136     if (method) {
137       Callback* callback =
138           NewCallback<T, const CppArgumentList&, CppVariant*>(
139               static_cast<T*>(this), method);
140       BindFallbackCallback(callback);
141     } else {
142       BindFallbackCallback(NULL);
143     }
144   }
145 
146   // Some fields are protected because some tests depend on accessing them,
147   // but otherwise they should be considered private.
148 
149   typedef std::map<NPIdentifier, PropertyCallback*> PropertyList;
150   typedef std::map<NPIdentifier, Callback*> MethodList;
151   // These maps associate names with property and method pointers to be
152   // exposed to JavaScript.
153   PropertyList properties_;
154   MethodList methods_;
155 
156   // The callback gets invoked when a call is made to an nonexistent method.
157   scoped_ptr<Callback> fallback_callback_;
158 
159  private:
160   // NPObject callbacks.
161   friend struct CppNPObject;
162   bool HasMethod(NPIdentifier ident) const;
163   bool Invoke(NPIdentifier ident, const NPVariant* args, size_t arg_count,
164               NPVariant* result);
165   bool HasProperty(NPIdentifier ident) const;
166   bool GetProperty(NPIdentifier ident, NPVariant* result) const;
167   bool SetProperty(NPIdentifier ident, const NPVariant* value);
168 
169   // A lazily-initialized CppVariant representing this class.  We retain 1
170   // reference to this object, and it is released on deletion.
171   CppVariant self_variant_;
172 
173   // True if our np_object has been bound to a WebFrame, in which case it must
174   // be unregistered with V8 when we delete it.
175   bool bound_to_frame_;
176 
177   DISALLOW_COPY_AND_ASSIGN(CppBoundClass);
178 };
179 
180 #endif  // CPP_BOUNDCLASS_H__
181