| Index: content/test/layout_tests/runner/CppBoundClass.cpp
|
| diff --git a/content/test/layout_tests/runner/CppBoundClass.cpp b/content/test/layout_tests/runner/CppBoundClass.cpp
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..49eaedfdde94a9fc1f53b5ed1c6d7055a4850248
|
| --- /dev/null
|
| +++ b/content/test/layout_tests/runner/CppBoundClass.cpp
|
| @@ -0,0 +1,362 @@
|
| +// Copyright 2013 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +/*
|
| + * Copyright (C) 2010 Google Inc. All rights reserved.
|
| + * Copyright (C) 2009 Pawel Hajdan (phajdan.jr@chromium.org)
|
| + *
|
| + * Redistribution and use in source and binary forms, with or without
|
| + * modification, are permitted provided that the following conditions are
|
| + * met:
|
| + *
|
| + * * Redistributions of source code must retain the above copyright
|
| + * notice, this list of conditions and the following disclaimer.
|
| + * * Redistributions in binary form must reproduce the above
|
| + * copyright notice, this list of conditions and the following disclaimer
|
| + * in the documentation and/or other materials provided with the
|
| + * distribution.
|
| + * * Neither the name of Google Inc. nor the names of its
|
| + * contributors may be used to endorse or promote products derived from
|
| + * this software without specific prior written permission.
|
| + *
|
| + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
| + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
| + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
| + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
| + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
| + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
| + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
| + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
| + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
| + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| + */
|
| +
|
| +// This file contains definitions for CppBoundClass
|
| +
|
| +// Here's the control flow of a JS method getting forwarded to a class.
|
| +// - Something calls our NPObject with a function like "Invoke".
|
| +// - CppNPObject's static invoke() function forwards it to its attached
|
| +// CppBoundClass's invoke() method.
|
| +// - CppBoundClass has then overridden invoke() to look up the function
|
| +// name in its internal map of methods, and then calls the appropriate
|
| +// method.
|
| +
|
| +#include "content/test/layout_tests/runner/CppBoundClass.h"
|
| +
|
| +#include "content/test/layout_tests/runner/TestCommon.h"
|
| +#include "third_party/WebKit/public/platform/WebString.h"
|
| +#include "third_party/WebKit/public/web/WebBindings.h"
|
| +#include "third_party/WebKit/public/web/WebFrame.h"
|
| +
|
| +using namespace blink;
|
| +using namespace std;
|
| +
|
| +namespace WebTestRunner {
|
| +
|
| +namespace {
|
| +
|
| +class CppVariantPropertyCallback : public CppBoundClass::PropertyCallback {
|
| +public:
|
| + CppVariantPropertyCallback(CppVariant* value) : m_value(value) { }
|
| +
|
| + virtual bool getValue(CppVariant* value)
|
| + {
|
| + value->set(*m_value);
|
| + return true;
|
| + }
|
| +
|
| + virtual bool setValue(const CppVariant& value)
|
| + {
|
| + m_value->set(value);
|
| + return true;
|
| + }
|
| +
|
| +private:
|
| + CppVariant* m_value;
|
| +};
|
| +
|
| +class GetterPropertyCallback : public CppBoundClass::PropertyCallback {
|
| +public:
|
| + GetterPropertyCallback(WebScopedPtr<CppBoundClass::GetterCallback> callback)
|
| + : m_callback(callback)
|
| + {
|
| + }
|
| +
|
| + virtual bool getValue(CppVariant* value)
|
| + {
|
| + m_callback->run(value);
|
| + return true;
|
| + }
|
| +
|
| + virtual bool setValue(const CppVariant& value) { return false; }
|
| +
|
| +private:
|
| + WebScopedPtr<CppBoundClass::GetterCallback> m_callback;
|
| +};
|
| +
|
| +}
|
| +
|
| +// Our special NPObject type. We extend an NPObject with a pointer to a
|
| +// CppBoundClass, which is just a C++ interface that we forward all NPObject
|
| +// callbacks to.
|
| +struct CppNPObject {
|
| + NPObject parent; // This must be the first field in the struct.
|
| + CppBoundClass* boundClass;
|
| +
|
| + //
|
| + // All following objects and functions are static, and just used to interface
|
| + // with NPObject/NPClass.
|
| + //
|
| +
|
| + // An NPClass associates static functions of CppNPObject with the
|
| + // function pointers used by the JS runtime.
|
| + static NPClass npClass;
|
| +
|
| + // Allocate a new NPObject with the specified class.
|
| + static NPObject* allocate(NPP, NPClass*);
|
| +
|
| + // Free an object.
|
| + static void deallocate(NPObject*);
|
| +
|
| + // Returns true if the C++ class associated with this NPObject exposes the
|
| + // given property. Called by the JS runtime.
|
| + static bool hasProperty(NPObject*, NPIdentifier);
|
| +
|
| + // Returns true if the C++ class associated with this NPObject exposes the
|
| + // given method. Called by the JS runtime.
|
| + static bool hasMethod(NPObject*, NPIdentifier);
|
| +
|
| + // If the given method is exposed by the C++ class associated with this
|
| + // NPObject, invokes it with the given arguments and returns a result. Otherwise,
|
| + // returns "undefined" (in the JavaScript sense). Called by the JS runtime.
|
| + static bool invoke(NPObject*, NPIdentifier,
|
| + const NPVariant* arguments, uint32_t argumentCount,
|
| + NPVariant* result);
|
| +
|
| + // If the given property is exposed by the C++ class associated with this
|
| + // NPObject, returns its value. Otherwise, returns "undefined" (in the
|
| + // JavaScript sense). Called by the JS runtime.
|
| + static bool getProperty(NPObject*, NPIdentifier, NPVariant* result);
|
| +
|
| + // If the given property is exposed by the C++ class associated with this
|
| + // NPObject, sets its value. Otherwise, does nothing. Called by the JS
|
| + // runtime.
|
| + static bool setProperty(NPObject*, NPIdentifier, const NPVariant* value);
|
| +};
|
| +
|
| +// Build CppNPObject's static function pointers into an NPClass, for use
|
| +// in constructing NPObjects for the C++ classes.
|
| +NPClass CppNPObject::npClass = {
|
| + NP_CLASS_STRUCT_VERSION,
|
| + CppNPObject::allocate,
|
| + CppNPObject::deallocate,
|
| + /* NPInvalidateFunctionPtr */ 0,
|
| + CppNPObject::hasMethod,
|
| + CppNPObject::invoke,
|
| + /* NPInvokeDefaultFunctionPtr */ 0,
|
| + CppNPObject::hasProperty,
|
| + CppNPObject::getProperty,
|
| + CppNPObject::setProperty,
|
| + /* NPRemovePropertyFunctionPtr */ 0
|
| +};
|
| +
|
| +NPObject* CppNPObject::allocate(NPP npp, NPClass* aClass)
|
| +{
|
| + CppNPObject* obj = new CppNPObject;
|
| + // obj->parent will be initialized by the NPObject code calling this.
|
| + obj->boundClass = 0;
|
| + return &obj->parent;
|
| +}
|
| +
|
| +void CppNPObject::deallocate(NPObject* npObj)
|
| +{
|
| + CppNPObject* obj = reinterpret_cast<CppNPObject*>(npObj);
|
| + delete obj;
|
| +}
|
| +
|
| +bool CppNPObject::hasMethod(NPObject* npObj, NPIdentifier ident)
|
| +{
|
| + CppNPObject* obj = reinterpret_cast<CppNPObject*>(npObj);
|
| + return obj->boundClass->hasMethod(ident);
|
| +}
|
| +
|
| +bool CppNPObject::hasProperty(NPObject* npObj, NPIdentifier ident)
|
| +{
|
| + CppNPObject* obj = reinterpret_cast<CppNPObject*>(npObj);
|
| + return obj->boundClass->hasProperty(ident);
|
| +}
|
| +
|
| +bool CppNPObject::invoke(NPObject* npObj, NPIdentifier ident,
|
| + const NPVariant* arguments, uint32_t argumentCount,
|
| + NPVariant* result)
|
| +{
|
| + CppNPObject* obj = reinterpret_cast<CppNPObject*>(npObj);
|
| + return obj->boundClass->invoke(ident, arguments, argumentCount, result);
|
| +}
|
| +
|
| +bool CppNPObject::getProperty(NPObject* npObj, NPIdentifier ident, NPVariant* result)
|
| +{
|
| + CppNPObject* obj = reinterpret_cast<CppNPObject*>(npObj);
|
| + return obj->boundClass->getProperty(ident, result);
|
| +}
|
| +
|
| +bool CppNPObject::setProperty(NPObject* npObj, NPIdentifier ident, const NPVariant* value)
|
| +{
|
| + CppNPObject* obj = reinterpret_cast<CppNPObject*>(npObj);
|
| + return obj->boundClass->setProperty(ident, value);
|
| +}
|
| +
|
| +CppBoundClass::~CppBoundClass()
|
| +{
|
| + for (MethodList::iterator i = m_methods.begin(); i != m_methods.end(); ++i)
|
| + delete i->second;
|
| +
|
| + for (PropertyList::iterator i = m_properties.begin(); i != m_properties.end(); ++i)
|
| + delete i->second;
|
| +
|
| + // Unregister ourselves if we were bound to a frame.
|
| + if (m_boundToFrame)
|
| + WebBindings::unregisterObject(NPVARIANT_TO_OBJECT(m_selfVariant));
|
| +}
|
| +
|
| +bool CppBoundClass::hasMethod(NPIdentifier ident) const
|
| +{
|
| + return m_methods.find(ident) != m_methods.end();
|
| +}
|
| +
|
| +bool CppBoundClass::hasProperty(NPIdentifier ident) const
|
| +{
|
| + return m_properties.find(ident) != m_properties.end();
|
| +}
|
| +
|
| +bool CppBoundClass::invoke(NPIdentifier ident,
|
| + const NPVariant* arguments,
|
| + size_t argumentCount,
|
| + NPVariant* result) {
|
| + MethodList::const_iterator end = m_methods.end();
|
| + MethodList::const_iterator method = m_methods.find(ident);
|
| + Callback* callback;
|
| + if (method == end) {
|
| + if (!m_fallbackCallback.get()) {
|
| + VOID_TO_NPVARIANT(*result);
|
| + return false;
|
| + }
|
| + callback = m_fallbackCallback.get();
|
| + } else
|
| + callback = (*method).second;
|
| +
|
| + // Build a CppArgumentList argument vector from the NPVariants coming in.
|
| + CppArgumentList cppArguments(argumentCount);
|
| + for (size_t i = 0; i < argumentCount; i++)
|
| + cppArguments[i].set(arguments[i]);
|
| +
|
| + CppVariant cppResult;
|
| + callback->run(cppArguments, &cppResult);
|
| +
|
| + cppResult.copyToNPVariant(result);
|
| + return true;
|
| +}
|
| +
|
| +bool CppBoundClass::getProperty(NPIdentifier ident, NPVariant* result) const
|
| +{
|
| + PropertyList::const_iterator callback = m_properties.find(ident);
|
| + if (callback == m_properties.end()) {
|
| + VOID_TO_NPVARIANT(*result);
|
| + return false;
|
| + }
|
| +
|
| + CppVariant cppValue;
|
| + if (!callback->second->getValue(&cppValue))
|
| + return false;
|
| + cppValue.copyToNPVariant(result);
|
| + return true;
|
| +}
|
| +
|
| +bool CppBoundClass::setProperty(NPIdentifier ident, const NPVariant* value)
|
| +{
|
| + PropertyList::iterator callback = m_properties.find(ident);
|
| + if (callback == m_properties.end())
|
| + return false;
|
| +
|
| + CppVariant cppValue;
|
| + cppValue.set(*value);
|
| + return (*callback).second->setValue(cppValue);
|
| +}
|
| +
|
| +void CppBoundClass::bindCallback(const string& name, Callback* callback)
|
| +{
|
| + NPIdentifier ident = WebBindings::getStringIdentifier(name.c_str());
|
| + MethodList::iterator oldCallback = m_methods.find(ident);
|
| + if (oldCallback != m_methods.end()) {
|
| + delete oldCallback->second;
|
| + if (!callback) {
|
| + m_methods.erase(oldCallback);
|
| + return;
|
| + }
|
| + }
|
| +
|
| + m_methods[ident] = callback;
|
| +}
|
| +
|
| +void CppBoundClass::bindGetterCallback(const string& name, WebScopedPtr<GetterCallback> callback)
|
| +{
|
| + PropertyCallback* propertyCallback = callback.get() ? new GetterPropertyCallback(callback) : 0;
|
| + bindProperty(name, propertyCallback);
|
| +}
|
| +
|
| +void CppBoundClass::bindProperty(const string& name, CppVariant* prop)
|
| +{
|
| + PropertyCallback* propertyCallback = prop ? new CppVariantPropertyCallback(prop) : 0;
|
| + bindProperty(name, propertyCallback);
|
| +}
|
| +
|
| +void CppBoundClass::bindProperty(const string& name, PropertyCallback* callback)
|
| +{
|
| + NPIdentifier ident = WebBindings::getStringIdentifier(name.c_str());
|
| + PropertyList::iterator oldCallback = m_properties.find(ident);
|
| + if (oldCallback != m_properties.end()) {
|
| + delete oldCallback->second;
|
| + if (!callback) {
|
| + m_properties.erase(oldCallback);
|
| + return;
|
| + }
|
| + }
|
| +
|
| + m_properties[ident] = callback;
|
| +}
|
| +
|
| +bool CppBoundClass::isMethodRegistered(const string& name) const
|
| +{
|
| + NPIdentifier ident = WebBindings::getStringIdentifier(name.c_str());
|
| + MethodList::const_iterator callback = m_methods.find(ident);
|
| + return callback != m_methods.end();
|
| +}
|
| +
|
| +CppVariant* CppBoundClass::getAsCppVariant()
|
| +{
|
| + if (!m_selfVariant.isObject()) {
|
| + // Create an NPObject using our static NPClass. The first argument (a
|
| + // plugin's instance handle) is passed through to the allocate function
|
| + // directly, and we don't use it, so it's ok to be 0.
|
| + NPObject* npObj = WebBindings::createObject(0, &CppNPObject::npClass);
|
| + CppNPObject* obj = reinterpret_cast<CppNPObject*>(npObj);
|
| + obj->boundClass = this;
|
| + m_selfVariant.set(npObj);
|
| + WebBindings::releaseObject(npObj); // CppVariant takes the reference.
|
| + }
|
| + BLINK_ASSERT(m_selfVariant.isObject());
|
| + return &m_selfVariant;
|
| +}
|
| +
|
| +void CppBoundClass::bindToJavascript(WebFrame* frame, const WebString& classname)
|
| +{
|
| + // BindToWindowObject will take its own reference to the NPObject, and clean
|
| + // up after itself. It will also (indirectly) register the object with V8,
|
| + // so we must remember this so we can unregister it when we're destroyed.
|
| + frame->bindToWindowObject(classname, NPVARIANT_TO_OBJECT(*getAsCppVariant()), 0);
|
| + m_boundToFrame = true;
|
| +}
|
| +
|
| +}
|
|
|