cpp_bound_class.h revision ddb351dbec246cf1fab5ec20d2d5520909041de1
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
29namespace WebKit {
30class WebFrame;
31}
32
33typedef 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.
37class CppBoundClass {
38 public:
39  class PropertyCallback {
40   public:
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>
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>
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).
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>
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