WebKitTools/DumpRenderTree/chromium/CppBoundClass.cpp
changeset 2 303757a437d3
parent 0 4f2f89ce4247
equal deleted inserted replaced
0:4f2f89ce4247 2:303757a437d3
     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 // This file contains definitions for CppBoundClass
       
    33 
       
    34 // Here's the control flow of a JS method getting forwarded to a class.
       
    35 // - Something calls our NPObject with a function like "Invoke".
       
    36 // - CppNPObject's static invoke() function forwards it to its attached
       
    37 //   CppBoundClass's invoke() method.
       
    38 // - CppBoundClass has then overridden invoke() to look up the function
       
    39 //   name in its internal map of methods, and then calls the appropriate
       
    40 //   method.
       
    41 
       
    42 #include "config.h"
       
    43 #include "CppBoundClass.h"
       
    44 
       
    45 #include "public/WebBindings.h"
       
    46 #include "public/WebFrame.h"
       
    47 #include "public/WebString.h"
       
    48 #include <wtf/Assertions.h>
       
    49 #include <wtf/OwnPtr.h>
       
    50 
       
    51 using namespace WebKit;
       
    52 using namespace std;
       
    53 
       
    54 class CppVariantPropertyCallback : public CppBoundClass::PropertyCallback {
       
    55 public:
       
    56     CppVariantPropertyCallback(CppVariant* value) : m_value(value) { }
       
    57 
       
    58     virtual bool getValue(CppVariant* value)
       
    59     {
       
    60         value->set(*m_value);
       
    61         return true;
       
    62     }
       
    63 
       
    64     virtual bool setValue(const CppVariant& value)
       
    65     {
       
    66         m_value->set(value);
       
    67         return true;
       
    68     }
       
    69 
       
    70 private:
       
    71     CppVariant* m_value;
       
    72 };
       
    73 
       
    74 class GetterPropertyCallback : public CppBoundClass::PropertyCallback {
       
    75 public:
       
    76     GetterPropertyCallback(CppBoundClass::GetterCallback* callback)
       
    77         : m_callback(callback) { }
       
    78 
       
    79     virtual bool getValue(CppVariant* value)
       
    80     {
       
    81         m_callback->run(value);
       
    82         return true;
       
    83     }
       
    84 
       
    85     virtual bool setValue(const CppVariant& value) { return false; }
       
    86 
       
    87 private:
       
    88     OwnPtr<CppBoundClass::GetterCallback> m_callback;
       
    89 };
       
    90 
       
    91 // Our special NPObject type.  We extend an NPObject with a pointer to a
       
    92 // CppBoundClass, which is just a C++ interface that we forward all NPObject
       
    93 // callbacks to.
       
    94 struct CppNPObject {
       
    95     NPObject parent; // This must be the first field in the struct.
       
    96     CppBoundClass* boundClass;
       
    97 
       
    98     //
       
    99     // All following objects and functions are static, and just used to interface
       
   100     // with NPObject/NPClass.
       
   101     //
       
   102 
       
   103     // An NPClass associates static functions of CppNPObject with the
       
   104     // function pointers used by the JS runtime.
       
   105     static NPClass npClass;
       
   106 
       
   107     // Allocate a new NPObject with the specified class.
       
   108     static NPObject* allocate(NPP, NPClass*);
       
   109 
       
   110     // Free an object.
       
   111     static void deallocate(NPObject*);
       
   112 
       
   113     // Returns true if the C++ class associated with this NPObject exposes the
       
   114     // given property.  Called by the JS runtime.
       
   115     static bool hasProperty(NPObject*, NPIdentifier);
       
   116 
       
   117     // Returns true if the C++ class associated with this NPObject exposes the
       
   118     // given method.  Called by the JS runtime.
       
   119     static bool hasMethod(NPObject*, NPIdentifier);
       
   120 
       
   121     // If the given method is exposed by the C++ class associated with this
       
   122     // NPObject, invokes it with the given arguments and returns a result.  Otherwise,
       
   123     // returns "undefined" (in the JavaScript sense).  Called by the JS runtime.
       
   124     static bool invoke(NPObject*, NPIdentifier,
       
   125                        const NPVariant* arguments, uint32_t argumentCount,
       
   126                        NPVariant* result);
       
   127 
       
   128     // If the given property is exposed by the C++ class associated with this
       
   129     // NPObject, returns its value.  Otherwise, returns "undefined" (in the
       
   130     // JavaScript sense).  Called by the JS runtime.
       
   131     static bool getProperty(NPObject*, NPIdentifier, NPVariant* result);
       
   132 
       
   133     // If the given property is exposed by the C++ class associated with this
       
   134     // NPObject, sets its value.  Otherwise, does nothing. Called by the JS
       
   135     // runtime.
       
   136     static bool setProperty(NPObject*, NPIdentifier, const NPVariant* value);
       
   137 };
       
   138 
       
   139 // Build CppNPObject's static function pointers into an NPClass, for use
       
   140 // in constructing NPObjects for the C++ classes.
       
   141 NPClass CppNPObject::npClass = {
       
   142     NP_CLASS_STRUCT_VERSION,
       
   143     CppNPObject::allocate,
       
   144     CppNPObject::deallocate,
       
   145     /* NPInvalidateFunctionPtr */ 0,
       
   146     CppNPObject::hasMethod,
       
   147     CppNPObject::invoke,
       
   148     /* NPInvokeDefaultFunctionPtr */ 0,
       
   149     CppNPObject::hasProperty,
       
   150     CppNPObject::getProperty,
       
   151     CppNPObject::setProperty,
       
   152     /* NPRemovePropertyFunctionPtr */ 0
       
   153 };
       
   154 
       
   155 NPObject* CppNPObject::allocate(NPP npp, NPClass* aClass)
       
   156 {
       
   157     CppNPObject* obj = new CppNPObject;
       
   158     // obj->parent will be initialized by the NPObject code calling this.
       
   159     obj->boundClass = 0;
       
   160     return &obj->parent;
       
   161 }
       
   162 
       
   163 void CppNPObject::deallocate(NPObject* npObj)
       
   164 {
       
   165     CppNPObject* obj = reinterpret_cast<CppNPObject*>(npObj);
       
   166     delete obj;
       
   167 }
       
   168 
       
   169 bool CppNPObject::hasMethod(NPObject* npObj, NPIdentifier ident)
       
   170 {
       
   171     CppNPObject* obj = reinterpret_cast<CppNPObject*>(npObj);
       
   172     return obj->boundClass->hasMethod(ident);
       
   173 }
       
   174 
       
   175 bool CppNPObject::hasProperty(NPObject* npObj, NPIdentifier ident)
       
   176 {
       
   177     CppNPObject* obj = reinterpret_cast<CppNPObject*>(npObj);
       
   178     return obj->boundClass->hasProperty(ident);
       
   179 }
       
   180 
       
   181 bool CppNPObject::invoke(NPObject* npObj, NPIdentifier ident,
       
   182                          const NPVariant* arguments, uint32_t argumentCount,
       
   183                          NPVariant* result)
       
   184 {
       
   185     CppNPObject* obj = reinterpret_cast<CppNPObject*>(npObj);
       
   186     return obj->boundClass->invoke(ident, arguments, argumentCount, result);
       
   187 }
       
   188 
       
   189 bool CppNPObject::getProperty(NPObject* npObj, NPIdentifier ident, NPVariant* result)
       
   190 {
       
   191     CppNPObject* obj = reinterpret_cast<CppNPObject*>(npObj);
       
   192     return obj->boundClass->getProperty(ident, result);
       
   193 }
       
   194 
       
   195 bool CppNPObject::setProperty(NPObject* npObj, NPIdentifier ident, const NPVariant* value)
       
   196 {
       
   197     CppNPObject* obj = reinterpret_cast<CppNPObject*>(npObj);
       
   198     return obj->boundClass->setProperty(ident, value);
       
   199 }
       
   200 
       
   201 CppBoundClass::~CppBoundClass()
       
   202 {
       
   203     for (MethodList::iterator i = m_methods.begin(); i != m_methods.end(); ++i)
       
   204         delete i->second;
       
   205 
       
   206     for (PropertyList::iterator i = m_properties.begin(); i != m_properties.end(); ++i)
       
   207         delete i->second;
       
   208 
       
   209     // Unregister ourselves if we were bound to a frame.
       
   210     if (m_boundToFrame)
       
   211         WebBindings::unregisterObject(NPVARIANT_TO_OBJECT(m_selfVariant));
       
   212 }
       
   213 
       
   214 bool CppBoundClass::hasMethod(NPIdentifier ident) const
       
   215 {
       
   216     return m_methods.find(ident) != m_methods.end();
       
   217 }
       
   218 
       
   219 bool CppBoundClass::hasProperty(NPIdentifier ident) const
       
   220 {
       
   221     return m_properties.find(ident) != m_properties.end();
       
   222 }
       
   223 
       
   224 bool CppBoundClass::invoke(NPIdentifier ident,
       
   225                            const NPVariant* arguments,
       
   226                            size_t argumentCount,
       
   227                            NPVariant* result) {
       
   228     MethodList::const_iterator end = m_methods.end();
       
   229     MethodList::const_iterator method = m_methods.find(ident);
       
   230     Callback* callback;
       
   231     if (method == end) {
       
   232         if (!m_fallbackCallback.get()) {
       
   233             VOID_TO_NPVARIANT(*result);
       
   234             return false;
       
   235         }
       
   236         callback = m_fallbackCallback.get();
       
   237     } else
       
   238         callback = (*method).second;
       
   239 
       
   240     // Build a CppArgumentList argument vector from the NPVariants coming in.
       
   241     CppArgumentList cppArguments(argumentCount);
       
   242     for (size_t i = 0; i < argumentCount; i++)
       
   243         cppArguments[i].set(arguments[i]);
       
   244 
       
   245     CppVariant cppResult;
       
   246     callback->run(cppArguments, &cppResult);
       
   247 
       
   248     cppResult.copyToNPVariant(result);
       
   249     return true;
       
   250 }
       
   251 
       
   252 bool CppBoundClass::getProperty(NPIdentifier ident, NPVariant* result) const
       
   253 {
       
   254     PropertyList::const_iterator callback = m_properties.find(ident);
       
   255     if (callback == m_properties.end()) {
       
   256         VOID_TO_NPVARIANT(*result);
       
   257         return false;
       
   258     }
       
   259 
       
   260     CppVariant cppValue;
       
   261     if (!callback->second->getValue(&cppValue))
       
   262         return false;
       
   263     cppValue.copyToNPVariant(result);
       
   264     return true;
       
   265 }
       
   266 
       
   267 bool CppBoundClass::setProperty(NPIdentifier ident, const NPVariant* value)
       
   268 {
       
   269     PropertyList::iterator callback = m_properties.find(ident);
       
   270     if (callback == m_properties.end())
       
   271         return false;
       
   272 
       
   273     CppVariant cppValue;
       
   274     cppValue.set(*value);
       
   275     return (*callback).second->setValue(cppValue);
       
   276 }
       
   277 
       
   278 void CppBoundClass::bindCallback(const string& name, Callback* callback)
       
   279 {
       
   280     NPIdentifier ident = WebBindings::getStringIdentifier(name.c_str());
       
   281     MethodList::iterator oldCallback = m_methods.find(ident);
       
   282     if (oldCallback != m_methods.end()) {
       
   283         delete oldCallback->second;
       
   284         if (!callback) {
       
   285             m_methods.remove(oldCallback);
       
   286             return;
       
   287         }
       
   288     }
       
   289 
       
   290     m_methods.set(ident, callback);
       
   291 }
       
   292 
       
   293 void CppBoundClass::bindGetterCallback(const string& name, GetterCallback* callback)
       
   294 {
       
   295     PropertyCallback* propertyCallback = callback ? new GetterPropertyCallback(callback) : 0;
       
   296     bindProperty(name, propertyCallback);
       
   297 }
       
   298 
       
   299 void CppBoundClass::bindProperty(const string& name, CppVariant* prop)
       
   300 {
       
   301     PropertyCallback* propertyCallback = prop ? new CppVariantPropertyCallback(prop) : 0;
       
   302     bindProperty(name, propertyCallback);
       
   303 }
       
   304 
       
   305 void CppBoundClass::bindProperty(const string& name, PropertyCallback* callback)
       
   306 {
       
   307     NPIdentifier ident = WebBindings::getStringIdentifier(name.c_str());
       
   308     PropertyList::iterator oldCallback = m_properties.find(ident);
       
   309     if (oldCallback != m_properties.end()) {
       
   310         delete oldCallback->second;
       
   311         if (!callback) {
       
   312             m_properties.remove(oldCallback);
       
   313             return;
       
   314         }
       
   315     }
       
   316 
       
   317     m_properties.set(ident, callback);
       
   318 }
       
   319 
       
   320 bool CppBoundClass::isMethodRegistered(const string& name) const
       
   321 {
       
   322     NPIdentifier ident = WebBindings::getStringIdentifier(name.c_str());
       
   323     MethodList::const_iterator callback = m_methods.find(ident);
       
   324     return callback != m_methods.end();
       
   325 }
       
   326 
       
   327 CppVariant* CppBoundClass::getAsCppVariant()
       
   328 {
       
   329     if (!m_selfVariant.isObject()) {
       
   330         // Create an NPObject using our static NPClass.  The first argument (a
       
   331         // plugin's instance handle) is passed through to the allocate function
       
   332         // directly, and we don't use it, so it's ok to be 0.
       
   333         NPObject* npObj = WebBindings::createObject(0, &CppNPObject::npClass);
       
   334         CppNPObject* obj = reinterpret_cast<CppNPObject*>(npObj);
       
   335         obj->boundClass = this;
       
   336         m_selfVariant.set(npObj);
       
   337         WebBindings::releaseObject(npObj); // CppVariant takes the reference.
       
   338     }
       
   339     ASSERT(m_selfVariant.isObject());
       
   340     return &m_selfVariant;
       
   341 }
       
   342 
       
   343 void CppBoundClass::bindToJavascript(WebFrame* frame, const WebString& classname)
       
   344 {
       
   345     // BindToWindowObject will take its own reference to the NPObject, and clean
       
   346     // up after itself.  It will also (indirectly) register the object with V8,
       
   347     // so we must remember this so we can unregister it when we're destroyed.
       
   348     frame->bindToWindowObject(classname, NPVARIANT_TO_OBJECT(*getAsCppVariant()));
       
   349     m_boundToFrame = true;
       
   350 }