// Copyright (c) 2011 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.
/*
CppBoundClass class:
This base class serves as a parent for C++ classes designed to be bound to
JavaScript objects.
Subclasses should define the constructor to build the property and method
lists needed to bind this class to a JS object. They should also declare
and define member variables and methods to be exposed to JS through
that object.
See cpp_binding_example.{h|cc} for an example.
*/
#ifndef WEBKIT_GLUE_CPP_BOUNDCLASS_H__
#define WEBKIT_GLUE_CPP_BOUNDCLASS_H__
#include <map>
#include <vector>
#include "webkit/glue/cpp_variant.h"
#include "base/callback.h"
#include "base/memory/scoped_ptr.h"
namespace WebKit {
class WebFrame;
}
typedef std::vector<CppVariant> CppArgumentList;
// CppBoundClass lets you map Javascript method calls and property accesses
// directly to C++ method calls and CppVariant* variable access.
class CppBoundClass {
public:
class PropertyCallback {
public:
virtual ~PropertyCallback() { }
// Sets |value| to the value of the property. Returns false in case of
// failure. |value| is always non-NULL.
virtual bool GetValue(CppVariant* value) = 0;
// sets the property value to |value|. Returns false in case of failure.
virtual bool SetValue(const CppVariant& value) = 0;
};
// The constructor should call BindMethod, BindProperty, and
// SetFallbackMethod as needed to set up the methods, properties, and
// fallback method.
CppBoundClass();
virtual ~CppBoundClass();
// Return a CppVariant representing this class, for use with BindProperty().
// The variant type is guaranteed to be NPVariantType_Object.
CppVariant* GetAsCppVariant();
// Given a WebFrame, BindToJavascript builds the NPObject that will represent
// the class and binds it to the frame's window under the given name. This
// should generally be called from the WebView delegate's
// WindowObjectCleared(). A class so bound will be accessible to JavaScript
// as window.<classname>. The owner of the CppBoundObject is responsible for
// keeping the object around while the frame is alive, and for destroying it
// afterwards.
void BindToJavascript(WebKit::WebFrame* frame, const std::string& classname);
// The type of callbacks.
typedef Callback2<const CppArgumentList&, CppVariant*>::Type Callback;
typedef Callback1<CppVariant*>::Type GetterCallback;
// Used by a test. Returns true if a method with name |name| exists,
// regardless of whether a fallback is registered.
bool IsMethodRegistered(const std::string& name) const;
protected:
// Bind the Javascript method called |name| to the C++ callback |callback|.
void BindCallback(const std::string& name, Callback* callback);
// A wrapper for BindCallback, to simplify the common case of binding a
// method on the current object. Though not verified here, |method|
// must be a method of this CppBoundClass subclass.
template<typename T>
void BindMethod(const std::string& name,
void (T::*method)(const CppArgumentList&, CppVariant*)) {
Callback* callback =
NewCallback<T, const CppArgumentList&, CppVariant*>(
static_cast<T*>(this), method);
BindCallback(name, callback);
}
// Bind Javascript property |name| to the C++ getter callback |callback|.
// This can be used to create read-only properties.
void BindGetterCallback(const std::string& name, GetterCallback* callback);
// A wrapper for BindGetterCallback, to simplify the common case of binding a
// property on the current object. Though not verified here, |method|
// must be a method of this CppBoundClass subclass.
template<typename T>
void BindProperty(const std::string& name, void (T::*method)(CppVariant*)) {
GetterCallback* callback =
NewCallback<T, CppVariant*>(static_cast<T*>(this), method);
BindGetterCallback(name, callback);
}
// Bind the Javascript property called |name| to a CppVariant |prop|.
void BindProperty(const std::string& name, CppVariant* prop);
// Bind Javascript property called |name| to a PropertyCallback |callback|.
// CppBoundClass assumes control over the life time of the |callback|.
void BindProperty(const std::string& name, PropertyCallback* callback);
// Set the fallback callback, which is called when when a callback is
// invoked that isn't bound.
// If it is NULL (its default value), a JavaScript exception is thrown in
// that case (as normally expected). If non NULL, the fallback method is
// invoked and the script continues its execution.
// Passing NULL for |callback| clears out any existing binding.
// It is used for tests and should probably only be used in such cases
// as it may cause unexpected behaviors (a JavaScript object with a
// fallback always returns true when checked for a method's
// existence).
void BindFallbackCallback(Callback* fallback_callback) {
fallback_callback_.reset(fallback_callback);
}
// A wrapper for BindFallbackCallback, to simplify the common case of
// binding a method on the current object. Though not verified here,
// |method| must be a method of this CppBoundClass subclass.
// Passing NULL for |method| clears out any existing binding.
template<typename T>
void BindFallbackMethod(
void (T::*method)(const CppArgumentList&, CppVariant*)) {
if (method) {
Callback* callback =
NewCallback<T, const CppArgumentList&, CppVariant*>(
static_cast<T*>(this), method);
BindFallbackCallback(callback);
} else {
BindFallbackCallback(NULL);
}
}
// Some fields are protected because some tests depend on accessing them,
// but otherwise they should be considered private.
typedef std::map<NPIdentifier, PropertyCallback*> PropertyList;
typedef std::map<NPIdentifier, Callback*> MethodList;
// These maps associate names with property and method pointers to be
// exposed to JavaScript.
PropertyList properties_;
MethodList methods_;
// The callback gets invoked when a call is made to an nonexistent method.
scoped_ptr<Callback> fallback_callback_;
private:
// NPObject callbacks.
friend struct CppNPObject;
bool HasMethod(NPIdentifier ident) const;
bool Invoke(NPIdentifier ident, const NPVariant* args, size_t arg_count,
NPVariant* result);
bool HasProperty(NPIdentifier ident) const;
bool GetProperty(NPIdentifier ident, NPVariant* result) const;
bool SetProperty(NPIdentifier ident, const NPVariant* value);
// A lazily-initialized CppVariant representing this class. We retain 1
// reference to this object, and it is released on deletion.
CppVariant self_variant_;
// True if our np_object has been bound to a WebFrame, in which case it must
// be unregistered with V8 when we delete it.
bool bound_to_frame_;
DISALLOW_COPY_AND_ASSIGN(CppBoundClass);
};
#endif // CPP_BOUNDCLASS_H__