Home | History | Annotate | Download | only in glue
      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:
     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