Home | History | Annotate | Download | only in runner
      1 /*
      2  * Copyright (C) 2010 Google Inc. All rights reserved.
      3  * Copyright (C) 2009 Pawel Hajdan (phajdan.jr (at) 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 <map>
     48 #include <memory>
     49 #include <vector>
     50 
     51 namespace WebKit {
     52 class WebFrame;
     53 class WebString;
     54 }
     55 
     56 namespace WebTestRunner {
     57 
     58 typedef std::vector<CppVariant> CppArgumentList;
     59 
     60 // CppBoundClass lets you map Javascript method calls and property accesses
     61 // directly to C++ method calls and CppVariant* variable access.
     62 class CppBoundClass {
     63 public:
     64     class PropertyCallback {
     65     public:
     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:
     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.
     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 the specified 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:
    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*);
    118         MemberCallback(T* object, MethodType method)
    119             : m_object(object)
    120             , m_method(method) { }
    121         virtual ~MemberCallback() { }
    122 
    123         virtual void run(const CppArgumentList& arguments, CppVariant* result)
    124         {
    125             (m_object->*m_method)(arguments, result);
    126         }
    127 
    128     private:
    129         T* m_object;
    130         MethodType m_method;
    131     };
    132 
    133     // Callback class for "void T::method(CppVariant*)"
    134     template <class T> class MemberGetterCallback : public GetterCallback {
    135     public:
    136         typedef void (T::*MethodType)(CppVariant*);
    137         MemberGetterCallback(T* object, MethodType method)
    138             : m_object(object)
    139             , m_method(method) { }
    140         virtual ~MemberGetterCallback() { }
    141 
    142         virtual void run(CppVariant* result) { (m_object->*m_method)(result); }
    143 
    144     private:
    145         T* m_object;
    146         MethodType m_method;
    147     };
    148 
    149     // Bind the Javascript method called the string parameter to the C++ method.
    150     void bindCallback(const std::string&, Callback*);
    151 
    152     // A wrapper for bindCallback, to simplify the common case of binding a
    153     // method on the current object. Though not verified here, the method parameter
    154     // must be a method of this CppBoundClass subclass.
    155     template<class T>
    156     void bindMethod(const std::string& name, void (T::*method)(const CppArgumentList&, CppVariant*))
    157     {
    158         Callback* callback = new MemberCallback<T>(static_cast<T*>(this), method);
    159         bindCallback(name, callback);
    160     }
    161 
    162     // Bind Javascript property |name| to the C++ getter callback |callback|.
    163     // This can be used to create read-only properties.
    164     void bindGetterCallback(const std::string&, std::auto_ptr<GetterCallback>);
    165 
    166     // A wrapper for BindGetterCallback, to simplify the common case of binding a
    167     // property on the current object. Though not verified here, the method parameter
    168     // must be a method of this CppBoundClass subclass.
    169     template<class T>
    170     void bindProperty(const std::string& name, void (T::*method)(CppVariant*))
    171     {
    172         std::auto_ptr<GetterCallback> callback(new MemberGetterCallback<T>(static_cast<T*>(this), method));
    173         bindGetterCallback(name, callback);
    174     }
    175 
    176     // Bind the Javascript property called |name| to a CppVariant.
    177     void bindProperty(const std::string&, CppVariant*);
    178 
    179     // Bind Javascript property called |name| to a PropertyCallback.
    180     // CppBoundClass assumes control over the life time of the callback.
    181     void bindProperty(const std::string&, PropertyCallback*);
    182 
    183     // Set the fallback callback, which is called when when a callback is
    184     // invoked that isn't bound.
    185     // If it is 0 (its default value), a JavaScript exception is thrown in
    186     // that case (as normally expected). If non 0, the fallback method is
    187     // invoked and the script continues its execution.
    188     // Passing 0 clears out any existing binding.
    189     // It is used for tests and should probably only be used in such cases
    190     // as it may cause unexpected behaviors (a JavaScript object with a
    191     // fallback always returns true when checked for a method's
    192     // existence).
    193     void bindFallbackCallback(std::auto_ptr<Callback> fallbackCallback)
    194     {
    195         m_fallbackCallback = fallbackCallback;
    196     }
    197 
    198     // A wrapper for BindFallbackCallback, to simplify the common case of
    199     // binding a method on the current object. Though not verified here,
    200     // |method| must be a method of this CppBoundClass subclass.
    201     // Passing 0 for |method| clears out any existing binding.
    202     template<class T>
    203     void bindFallbackMethod(void (T::*method)(const CppArgumentList&, CppVariant*))
    204     {
    205         if (method)
    206             bindFallbackCallback(std::auto_ptr<Callback>(new MemberCallback<T>(static_cast<T*>(this), method)));
    207         else
    208             bindFallbackCallback(std::auto_ptr<Callback>());
    209     }
    210 
    211     // Some fields are protected because some tests depend on accessing them,
    212     // but otherwise they should be considered private.
    213 
    214     typedef std::map<NPIdentifier, PropertyCallback*> PropertyList;
    215     typedef std::map<NPIdentifier, Callback*> MethodList;
    216     // These maps associate names with property and method pointers to be
    217     // exposed to JavaScript.
    218     PropertyList m_properties;
    219     MethodList m_methods;
    220 
    221     // The callback gets invoked when a call is made to an nonexistent method.
    222     std::auto_ptr<Callback> m_fallbackCallback;
    223 
    224 private:
    225     // NPObject callbacks.
    226     friend struct CppNPObject;
    227     bool hasMethod(NPIdentifier) const;
    228     bool invoke(NPIdentifier, const NPVariant* args, size_t argCount,
    229                 NPVariant* result);
    230     bool hasProperty(NPIdentifier) const;
    231     bool getProperty(NPIdentifier, NPVariant* result) const;
    232     bool setProperty(NPIdentifier, const NPVariant*);
    233 
    234     // A lazily-initialized CppVariant representing this class. We retain 1
    235     // reference to this object, and it is released on deletion.
    236     CppVariant m_selfVariant;
    237 
    238     // True if our np_object has been bound to a WebFrame, in which case it must
    239     // be unregistered with V8 when we delete it.
    240     bool m_boundToFrame;
    241 
    242 private:
    243     CppBoundClass(CppBoundClass&);
    244     CppBoundClass& operator=(const CppBoundClass&);
    245 };
    246 
    247 }
    248 
    249 #endif // CppBoundClass_h
    250