2009-04-18 19:00:33 +02:00
|
|
|
/* Copyright (C) 2009 Wildfire Games.
|
|
|
|
* This file is part of 0 A.D.
|
|
|
|
*
|
|
|
|
* 0 A.D. is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* 0 A.D. is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2004-10-07 21:23:35 +02:00
|
|
|
// ScriptableObject.h
|
|
|
|
//
|
|
|
|
// A quick way to add (mostly) sensibly-behaving JavaScript interfaces to native classes.
|
|
|
|
//
|
|
|
|
|
|
|
|
#include "scripting/ScriptingHost.h"
|
|
|
|
#include "JSConversions.h"
|
|
|
|
|
2007-05-07 18:33:24 +02:00
|
|
|
#ifndef INCLUDED_SCRIPTABLEOBJECT
|
|
|
|
#define INCLUDED_SCRIPTABLEOBJECT
|
2004-10-07 21:23:35 +02:00
|
|
|
|
2005-04-22 09:12:55 +02:00
|
|
|
#define ALLOW_NONSHARED_NATIVES
|
|
|
|
|
2005-03-30 18:14:19 +02:00
|
|
|
class IJSObject;
|
|
|
|
|
2004-10-07 21:23:35 +02:00
|
|
|
class IJSProperty
|
|
|
|
{
|
|
|
|
public:
|
2005-05-09 06:52:55 +02:00
|
|
|
virtual ~IJSProperty() {};
|
2005-04-22 09:12:55 +02:00
|
|
|
virtual jsval Get( JSContext* cx, IJSObject* obj ) = 0;
|
|
|
|
virtual void Set( JSContext* cx, IJSObject* obj, jsval value ) = 0;
|
2004-10-07 21:23:35 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
class IJSObject
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
typedef STL_HASH_MAP<CStrW, IJSProperty*, CStrW_hash_compare> PropertyTable;
|
|
|
|
|
2004-11-11 08:09:32 +01:00
|
|
|
// Property getters and setters
|
2005-10-24 04:32:44 +02:00
|
|
|
typedef jsval (IJSObject::*GetFn)( JSContext* cx );
|
|
|
|
typedef void (IJSObject::*SetFn)( JSContext* cx, jsval value );
|
2004-10-07 21:23:35 +02:00
|
|
|
|
2005-04-22 09:12:55 +02:00
|
|
|
// Return a pointer to a property, if it exists
|
2006-07-18 00:18:37 +02:00
|
|
|
virtual IJSProperty* HasProperty( const CStrW& PropertyName ) = 0;
|
2004-10-07 21:23:35 +02:00
|
|
|
|
2005-04-15 06:23:33 +02:00
|
|
|
// Retrieve the value of a property (returning false if that property is not defined)
|
2006-07-18 00:18:37 +02:00
|
|
|
virtual bool GetProperty( JSContext* cx, const CStrW& PropertyName, jsval* vp ) = 0;
|
2004-10-07 21:23:35 +02:00
|
|
|
|
|
|
|
// Add a property (with immediate value)
|
2006-07-18 00:18:37 +02:00
|
|
|
virtual void AddProperty( const CStrW& PropertyName, jsval Value ) = 0;
|
2006-07-20 16:37:58 +02:00
|
|
|
virtual void AddProperty( const CStrW& PropertyName, const CStrW& Value ) = 0;
|
2005-01-23 02:36:47 +01:00
|
|
|
|
|
|
|
inline IJSObject() {}
|
2004-10-07 21:23:35 +02:00
|
|
|
};
|
|
|
|
|
2004-11-11 08:09:32 +01:00
|
|
|
template<typename T, bool ReadOnly = false> class CJSObject;
|
2004-10-07 21:23:35 +02:00
|
|
|
|
2005-04-22 09:12:55 +02:00
|
|
|
template<typename T, bool ReadOnly> class CJSProperty : public IJSProperty
|
2005-03-30 18:14:19 +02:00
|
|
|
{
|
|
|
|
T IJSObject::*m_Data;
|
|
|
|
|
|
|
|
public:
|
2005-04-22 09:12:55 +02:00
|
|
|
CJSProperty( T IJSObject::*Data )
|
2005-03-30 18:14:19 +02:00
|
|
|
{
|
|
|
|
m_Data = Data;
|
|
|
|
}
|
2005-08-09 17:55:44 +02:00
|
|
|
jsval Get( JSContext* UNUSED(cx), IJSObject* owner )
|
2005-03-30 18:14:19 +02:00
|
|
|
{
|
|
|
|
return( ToJSVal( owner->*m_Data ) );
|
|
|
|
}
|
|
|
|
void Set( JSContext* cx, IJSObject* owner, jsval Value )
|
|
|
|
{
|
|
|
|
if( !ReadOnly )
|
2005-04-22 09:12:55 +02:00
|
|
|
ToPrimitive( cx, Value, owner->*m_Data );
|
2005-03-30 18:14:19 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2005-04-22 09:12:55 +02:00
|
|
|
#ifdef ALLOW_NONSHARED_NATIVES
|
|
|
|
|
|
|
|
template<typename T, bool ReadOnly> class CJSNonsharedProperty : public IJSProperty
|
2004-10-07 21:23:35 +02:00
|
|
|
{
|
|
|
|
T* m_Data;
|
|
|
|
|
|
|
|
public:
|
2005-04-22 09:12:55 +02:00
|
|
|
CJSNonsharedProperty( T* Data )
|
2004-10-07 21:23:35 +02:00
|
|
|
{
|
|
|
|
m_Data = Data;
|
|
|
|
}
|
2005-08-09 17:55:44 +02:00
|
|
|
jsval Get( JSContext* UNUSED(cx), IJSObject* UNUSED(owner) )
|
2004-10-07 21:23:35 +02:00
|
|
|
{
|
2004-11-11 08:09:32 +01:00
|
|
|
return( ToJSVal( *m_Data ) );
|
2004-10-07 21:23:35 +02:00
|
|
|
}
|
2005-08-09 17:55:44 +02:00
|
|
|
void Set( JSContext* cx, IJSObject* UNUSED(owner), jsval Value )
|
2004-10-07 21:23:35 +02:00
|
|
|
{
|
2004-11-11 08:09:32 +01:00
|
|
|
if( !ReadOnly )
|
2005-04-22 09:12:55 +02:00
|
|
|
ToPrimitive( cx, Value, *m_Data );
|
2004-10-07 21:23:35 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2005-04-22 09:12:55 +02:00
|
|
|
#endif /* ALLOW_NONSHARED_NATIVES */
|
2004-11-11 08:09:32 +01:00
|
|
|
|
2005-04-22 09:12:55 +02:00
|
|
|
class CJSFunctionProperty : public IJSProperty
|
2004-11-11 08:09:32 +01:00
|
|
|
{
|
2005-04-22 09:12:55 +02:00
|
|
|
// Function on Owner to get the value
|
|
|
|
IJSObject::GetFn m_Getter;
|
|
|
|
|
|
|
|
// Function on Owner to set the value
|
|
|
|
IJSObject::SetFn m_Setter;
|
2004-10-07 21:23:35 +02:00
|
|
|
|
2004-11-11 08:09:32 +01:00
|
|
|
public:
|
2005-04-22 09:12:55 +02:00
|
|
|
CJSFunctionProperty( IJSObject::GetFn Getter, IJSObject::SetFn Setter )
|
2004-11-11 08:09:32 +01:00
|
|
|
{
|
2005-04-22 09:12:55 +02:00
|
|
|
m_Getter = Getter;
|
|
|
|
m_Setter = Setter;
|
|
|
|
// Must at least be able to read
|
2005-06-28 06:06:25 +02:00
|
|
|
debug_assert( m_Getter );
|
2005-04-22 09:12:55 +02:00
|
|
|
}
|
2005-10-24 04:32:44 +02:00
|
|
|
jsval Get( JSContext* cx, IJSObject* obj )
|
2005-04-22 09:12:55 +02:00
|
|
|
{
|
2005-10-24 04:32:44 +02:00
|
|
|
return( (obj->*m_Getter)(cx) );
|
2005-04-22 09:12:55 +02:00
|
|
|
}
|
2005-10-24 04:32:44 +02:00
|
|
|
void Set( JSContext* cx, IJSObject* obj, jsval value )
|
2005-04-22 09:12:55 +02:00
|
|
|
{
|
|
|
|
if( m_Setter )
|
2005-10-24 04:32:44 +02:00
|
|
|
(obj->*m_Setter)( cx, value );
|
2004-11-11 08:09:32 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2005-04-22 09:12:55 +02:00
|
|
|
class CJSValProperty : public IJSProperty
|
2004-11-11 08:09:32 +01:00
|
|
|
{
|
|
|
|
template<typename Q, bool ReadOnly> friend class CJSObject;
|
|
|
|
|
|
|
|
jsval m_Data;
|
2004-10-07 21:23:35 +02:00
|
|
|
|
|
|
|
public:
|
2005-04-22 09:12:55 +02:00
|
|
|
CJSValProperty( jsval Data )
|
2004-10-07 21:23:35 +02:00
|
|
|
{
|
|
|
|
m_Data = Data;
|
|
|
|
Root();
|
|
|
|
}
|
|
|
|
~CJSValProperty()
|
|
|
|
{
|
|
|
|
Uproot();
|
|
|
|
}
|
|
|
|
void Root()
|
|
|
|
{
|
|
|
|
if( JSVAL_IS_GCTHING( m_Data ) )
|
2005-05-10 09:13:25 +02:00
|
|
|
JS_AddNamedRoot( g_ScriptingHost.GetContext(), (void*)&m_Data, "ScriptableObjectProperty" );
|
2004-10-07 21:23:35 +02:00
|
|
|
}
|
|
|
|
void Uproot()
|
|
|
|
{
|
2005-05-18 07:32:09 +02:00
|
|
|
if( JSVAL_IS_GCTHING( m_Data ))
|
2004-11-11 08:09:32 +01:00
|
|
|
JS_RemoveRoot( g_ScriptingHost.GetContext(), (void*)&m_Data );
|
2004-10-07 21:23:35 +02:00
|
|
|
}
|
2005-08-09 17:55:44 +02:00
|
|
|
jsval Get( JSContext* UNUSED(cx), IJSObject* UNUSED(object))
|
2004-10-07 21:23:35 +02:00
|
|
|
{
|
|
|
|
return( m_Data );
|
|
|
|
}
|
2005-08-09 17:55:44 +02:00
|
|
|
void Set( JSContext* UNUSED(cx), IJSObject* UNUSED(owner), jsval value )
|
2004-10-07 21:23:35 +02:00
|
|
|
{
|
|
|
|
Uproot();
|
2005-04-22 09:12:55 +02:00
|
|
|
m_Data = value;
|
2004-10-07 21:23:35 +02:00
|
|
|
Root();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// Wrapper around native functions that are attached to CJSObjects
|
|
|
|
|
2005-01-17 05:52:02 +01:00
|
|
|
template<typename T, bool ReadOnly, typename RType, RType (T::*NativeFunction)( JSContext* cx, uintN argc, jsval* argv )> class CNativeFunction
|
2004-10-07 21:23:35 +02:00
|
|
|
{
|
|
|
|
public:
|
|
|
|
static JSBool JSFunction( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval )
|
|
|
|
{
|
2005-02-21 18:13:31 +01:00
|
|
|
T* Native = ToNative<T>( cx, obj );
|
2004-10-07 21:23:35 +02:00
|
|
|
if( !Native )
|
|
|
|
return( JS_TRUE );
|
|
|
|
|
|
|
|
*rval = ToJSVal<RType>( (Native->*NativeFunction)( cx, argc, argv ) );
|
|
|
|
|
|
|
|
return( JS_TRUE );
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2007-05-29 21:01:21 +02:00
|
|
|
// Special case for void functions
|
|
|
|
template<typename T, bool ReadOnly, void (T::*NativeFunction)( JSContext* cx, uintN argc, jsval* argv )>
|
|
|
|
class CNativeFunction<T, ReadOnly, void, NativeFunction>
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
static JSBool JSFunction( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* UNUSED(rval) )
|
|
|
|
{
|
|
|
|
T* Native = ToNative<T>( cx, obj );
|
|
|
|
if( !Native )
|
|
|
|
return( JS_TRUE );
|
|
|
|
|
|
|
|
(Native->*NativeFunction)( cx, argc, argv );
|
|
|
|
|
|
|
|
return( JS_TRUE );
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2004-11-11 08:09:32 +01:00
|
|
|
template<typename T, bool ReadOnly> class CJSObject : public IJSObject
|
2004-10-07 21:23:35 +02:00
|
|
|
{
|
2005-04-22 09:12:55 +02:00
|
|
|
// This object
|
2004-10-07 21:23:35 +02:00
|
|
|
JSObject* m_JS;
|
2005-04-15 06:23:33 +02:00
|
|
|
|
2005-04-22 09:12:55 +02:00
|
|
|
protected:
|
|
|
|
// The properties defined by the engine
|
|
|
|
static PropertyTable m_NativeProperties;
|
|
|
|
#ifdef ALLOW_NONSHARED_NATIVES
|
|
|
|
PropertyTable m_NonsharedProperties;
|
|
|
|
#endif
|
|
|
|
// Properties added by script
|
|
|
|
PropertyTable m_ScriptProperties;
|
2005-04-15 06:23:33 +02:00
|
|
|
|
2004-11-11 08:09:32 +01:00
|
|
|
// Whether native code is responsible for managing this object.
|
|
|
|
// Script constructors should clear this *BEFORE* creating a JS
|
|
|
|
// mirror (otherwise it'll be rooted).
|
|
|
|
|
|
|
|
bool m_EngineOwned;
|
2004-10-07 21:23:35 +02:00
|
|
|
|
2005-04-22 09:12:55 +02:00
|
|
|
public:
|
|
|
|
// Property getters and setters
|
2005-10-24 04:32:44 +02:00
|
|
|
typedef jsval (T::*TGetFn)( JSContext* );
|
|
|
|
typedef void (T::*TSetFn)( JSContext*, jsval value );
|
2005-04-22 09:12:55 +02:00
|
|
|
|
|
|
|
static JSClass JSI_class;
|
|
|
|
|
|
|
|
static void ScriptingInit( const char* ClassName, JSNative Constructor = NULL, uintN ConstructorMinArgs = 0 )
|
|
|
|
{
|
|
|
|
JSFunctionSpec* JSI_methods = new JSFunctionSpec[ m_Methods.size() + 1 ];
|
had to remove uint and ulong from lib/types.h due to conflict with other library.
this snowballed into a massive search+destroy of the hodgepodge of
mostly equivalent types we had in use (int, uint, unsigned, unsigned
int, i32, u32, ulong, uintN).
it is more efficient to use 64-bit types in 64-bit mode, so the
preferred default is size_t (for anything remotely resembling a size or
index). tile coordinates are ssize_t to allow more efficient conversion
to/from floating point. flags are int because we almost never need more
than 15 distinct bits, bit test/set is not slower and int is fastest to
type. finally, some data that is pretty much directly passed to OpenGL
is now typed accordingly.
after several hours, the code now requires fewer casts and less
guesswork.
other changes:
- unit and player IDs now have an "invalid id" constant in the
respective class to avoid casting and -1
- fix some endian/64-bit bugs in the map (un)packing. added a
convenience function to write/read a size_t.
- ia32: change CPUID interface to allow passing in ecx (required for
cache topology detection, which I need at work). remove some unneeded
functions from asm, replace with intrinsics where possible.
This was SVN commit r5942.
2008-05-11 20:48:32 +02:00
|
|
|
size_t MethodID;
|
2005-04-22 09:12:55 +02:00
|
|
|
for( MethodID = 0; MethodID < m_Methods.size(); MethodID++ )
|
|
|
|
JSI_methods[MethodID] = m_Methods[MethodID];
|
|
|
|
|
|
|
|
JSI_methods[MethodID].name = 0;
|
|
|
|
|
|
|
|
JSI_class.name = ClassName;
|
|
|
|
g_ScriptingHost.DefineCustomObjectType( &JSI_class, Constructor, ConstructorMinArgs, JSI_props, JSI_methods, NULL, NULL );
|
|
|
|
|
|
|
|
delete[]( JSI_methods );
|
|
|
|
|
|
|
|
atexit( ScriptingShutdown );
|
|
|
|
}
|
|
|
|
static void ScriptingShutdown()
|
|
|
|
{
|
|
|
|
PropertyTable::iterator it;
|
|
|
|
for( it = m_NativeProperties.begin(); it != m_NativeProperties.end(); it++ )
|
|
|
|
delete( it->second );
|
|
|
|
}
|
|
|
|
|
2004-10-07 21:23:35 +02:00
|
|
|
// JS Property access
|
2006-07-18 00:18:37 +02:00
|
|
|
bool GetProperty( JSContext* cx, const CStrW& PropertyName, jsval* vp )
|
2005-04-22 09:12:55 +02:00
|
|
|
{
|
|
|
|
IJSProperty* Property = HasProperty( PropertyName );
|
|
|
|
if( Property )
|
|
|
|
*vp = Property->Get( cx, this );
|
|
|
|
|
|
|
|
return( true );
|
|
|
|
}
|
2006-07-18 00:18:37 +02:00
|
|
|
void SetProperty( JSContext* cx, const CStrW& PropertyName, jsval* vp )
|
2004-10-07 21:23:35 +02:00
|
|
|
{
|
2004-10-23 16:39:28 +02:00
|
|
|
if( !ReadOnly )
|
2004-10-07 21:23:35 +02:00
|
|
|
{
|
2004-10-23 16:39:28 +02:00
|
|
|
IJSProperty* prop = HasProperty( PropertyName );
|
|
|
|
|
|
|
|
if( prop )
|
2004-10-07 21:23:35 +02:00
|
|
|
{
|
2004-10-23 16:39:28 +02:00
|
|
|
// Already exists
|
2005-03-30 18:14:19 +02:00
|
|
|
prop->Set( cx, this, *vp );
|
2004-10-07 21:23:35 +02:00
|
|
|
}
|
2004-10-23 16:39:28 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
// Need to add it
|
|
|
|
AddProperty( PropertyName, *vp );
|
|
|
|
}
|
2004-10-07 21:23:35 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-07-18 00:18:37 +02:00
|
|
|
IJSProperty* HasProperty( const CStrW& PropertyName )
|
2004-10-07 21:23:35 +02:00
|
|
|
{
|
2005-04-22 09:12:55 +02:00
|
|
|
PropertyTable::iterator it;
|
2004-10-07 21:23:35 +02:00
|
|
|
|
2005-04-22 09:12:55 +02:00
|
|
|
// Engine-defined properties take precedence
|
|
|
|
it = m_NativeProperties.find( PropertyName );
|
|
|
|
if( it != m_NativeProperties.end() )
|
|
|
|
return( it->second );
|
|
|
|
// Next are the object-local engine-defined properties
|
|
|
|
// (if they're compiled in)
|
|
|
|
#ifdef ALLOW_NONSHARED_NATIVES
|
|
|
|
it = m_NonsharedProperties.find( PropertyName );
|
|
|
|
if( it != m_NonsharedProperties.end() )
|
|
|
|
return( it->second );
|
|
|
|
#endif
|
|
|
|
// Then check in script properties
|
|
|
|
it = m_ScriptProperties.find( PropertyName );
|
|
|
|
if( it != m_ScriptProperties.end() )
|
|
|
|
return( it->second );
|
2004-10-07 21:23:35 +02:00
|
|
|
|
2005-04-22 09:12:55 +02:00
|
|
|
// Otherwise not found
|
|
|
|
return( NULL );
|
2004-10-07 21:23:35 +02:00
|
|
|
}
|
|
|
|
|
2006-07-18 00:18:37 +02:00
|
|
|
void AddProperty( const CStrW& PropertyName, jsval Value )
|
2005-04-22 09:12:55 +02:00
|
|
|
{
|
2005-06-28 06:06:25 +02:00
|
|
|
debug_assert( !HasProperty( PropertyName ) );
|
2005-04-22 09:12:55 +02:00
|
|
|
CJSValProperty* newProp = new CJSValProperty( Value );
|
|
|
|
m_ScriptProperties[PropertyName] = newProp;
|
2004-10-07 21:23:35 +02:00
|
|
|
}
|
2006-07-20 16:37:58 +02:00
|
|
|
void AddProperty( const CStrW& PropertyName, const CStrW& Value )
|
2004-10-07 21:23:35 +02:00
|
|
|
{
|
2005-04-22 09:12:55 +02:00
|
|
|
AddProperty( PropertyName, JSParseString( Value ) );
|
2004-10-07 21:23:35 +02:00
|
|
|
}
|
2006-07-18 00:18:37 +02:00
|
|
|
static void AddProperty( const CStrW& PropertyName, TGetFn Getter, TSetFn Setter = NULL )
|
2005-03-30 18:14:19 +02:00
|
|
|
{
|
2005-04-22 09:12:55 +02:00
|
|
|
m_NativeProperties[PropertyName] = new CJSFunctionProperty( (GetFn)Getter, (SetFn)Setter );
|
2005-03-30 18:14:19 +02:00
|
|
|
}
|
2005-04-22 09:12:55 +02:00
|
|
|
template<typename ReturnType, ReturnType (T::*NativeFunction)( JSContext* cx, uintN argc, jsval* argv )>
|
|
|
|
static void AddMethod( const char* Name, uintN MinArgs )
|
2004-10-07 21:23:35 +02:00
|
|
|
{
|
2005-08-09 17:55:44 +02:00
|
|
|
JSFunctionSpec FnInfo = { Name, CNativeFunction<T, ReadOnly, ReturnType, NativeFunction>::JSFunction, (uint8)MinArgs, 0, 0 };
|
2005-04-22 09:12:55 +02:00
|
|
|
m_Methods.push_back( FnInfo );
|
2004-10-07 21:23:35 +02:00
|
|
|
}
|
2006-07-18 00:18:37 +02:00
|
|
|
template<typename PropType> static void AddProperty( const CStrW& PropertyName, PropType T::*Native, bool PropReadOnly = ReadOnly )
|
2005-04-22 09:12:55 +02:00
|
|
|
{
|
|
|
|
IJSProperty* prop;
|
|
|
|
if( PropReadOnly )
|
|
|
|
{
|
|
|
|
prop = new CJSProperty<PropType, true>( (PropType IJSObject::*)Native );
|
|
|
|
}
|
|
|
|
else
|
2005-05-09 06:52:55 +02:00
|
|
|
{
|
2005-04-22 09:12:55 +02:00
|
|
|
prop = new CJSProperty<PropType, ReadOnly>( (PropType IJSObject::*)Native );
|
2005-05-09 06:52:55 +02:00
|
|
|
}
|
2005-04-22 09:12:55 +02:00
|
|
|
m_NativeProperties[PropertyName] = prop;
|
|
|
|
}
|
|
|
|
#ifdef ALLOW_NONSHARED_NATIVES
|
2006-07-18 00:18:37 +02:00
|
|
|
template<typename PropType> void AddLocalProperty( const CStrW& PropertyName, PropType* Native, bool PropReadOnly = ReadOnly )
|
2005-04-22 09:12:55 +02:00
|
|
|
{
|
|
|
|
IJSProperty* prop;
|
|
|
|
if( PropReadOnly )
|
|
|
|
{
|
|
|
|
prop = new CJSNonsharedProperty<PropType, true>( Native );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
prop = new CJSNonsharedProperty<PropType, ReadOnly>( Native );
|
|
|
|
m_NonsharedProperties[PropertyName] = prop;
|
|
|
|
}
|
|
|
|
#endif
|
2004-11-11 08:09:32 +01:00
|
|
|
|
2005-04-22 09:12:55 +02:00
|
|
|
// Object operations
|
2004-10-07 21:23:35 +02:00
|
|
|
JSObject* GetScript()
|
|
|
|
{
|
|
|
|
if( !m_JS )
|
|
|
|
CreateScriptObject();
|
|
|
|
return( m_JS );
|
|
|
|
}
|
2004-11-11 08:09:32 +01:00
|
|
|
// Creating and releasing script objects is done automatically most of the time, but you
|
|
|
|
// can do it explicitly.
|
|
|
|
void CreateScriptObject()
|
|
|
|
{
|
|
|
|
if( !m_JS )
|
|
|
|
{
|
|
|
|
m_JS = JS_NewObject( g_ScriptingHost.GetContext(), &JSI_class, NULL, NULL );
|
|
|
|
if( m_EngineOwned )
|
2005-05-10 09:13:25 +02:00
|
|
|
JS_AddNamedRoot( g_ScriptingHost.GetContext(), (void*)&m_JS, JSI_class.name );
|
2005-04-22 09:12:55 +02:00
|
|
|
|
2005-02-21 18:13:31 +01:00
|
|
|
JS_SetPrivate( g_ScriptingHost.GetContext(), m_JS, (T*)this );
|
2004-11-11 08:09:32 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
void ReleaseScriptObject()
|
|
|
|
{
|
|
|
|
if( m_JS )
|
|
|
|
{
|
|
|
|
JS_SetPrivate( g_ScriptingHost.GetContext(), m_JS, NULL );
|
|
|
|
if( m_EngineOwned )
|
|
|
|
JS_RemoveRoot( g_ScriptingHost.GetContext(), &m_JS );
|
|
|
|
m_JS = NULL;
|
|
|
|
}
|
|
|
|
}
|
2005-04-22 09:12:55 +02:00
|
|
|
|
|
|
|
//
|
|
|
|
// Functions and data that must be provided to JavaScript
|
|
|
|
//
|
2004-10-07 21:23:35 +02:00
|
|
|
private:
|
2005-04-22 09:12:55 +02:00
|
|
|
static JSBool JSGetProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp )
|
|
|
|
{
|
|
|
|
T* Instance = ToNative<T>( cx, obj );
|
|
|
|
if( !Instance )
|
|
|
|
return( JS_TRUE );
|
|
|
|
|
|
|
|
CStrW PropName = g_ScriptingHost.ValueToUCString( id );
|
|
|
|
|
|
|
|
if( !Instance->GetProperty( cx, PropName, vp ) )
|
|
|
|
return( JS_TRUE );
|
|
|
|
|
|
|
|
return( JS_TRUE );
|
|
|
|
}
|
|
|
|
static JSBool JSSetProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp )
|
|
|
|
{
|
|
|
|
T* Instance = ToNative<T>( cx, obj );
|
|
|
|
if( !Instance )
|
|
|
|
return( JS_TRUE );
|
|
|
|
|
|
|
|
CStrW PropName = g_ScriptingHost.ValueToUCString( id );
|
|
|
|
|
|
|
|
Instance->SetProperty( cx, PropName, vp );
|
|
|
|
|
|
|
|
return( JS_TRUE );
|
|
|
|
}
|
|
|
|
static void DefaultFinalize( JSContext *cx, JSObject *obj )
|
|
|
|
{
|
|
|
|
T* Instance = ToNative<T>( cx, obj );
|
|
|
|
if( !Instance || Instance->m_EngineOwned )
|
|
|
|
return;
|
|
|
|
|
|
|
|
delete( Instance );
|
|
|
|
JS_SetPrivate( cx, obj, NULL );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-10-07 21:23:35 +02:00
|
|
|
static JSPropertySpec JSI_props[];
|
|
|
|
static std::vector<JSFunctionSpec> m_Methods;
|
|
|
|
|
|
|
|
public:
|
2005-04-22 09:12:55 +02:00
|
|
|
// Standard constructors/destructors
|
2004-10-07 21:23:35 +02:00
|
|
|
CJSObject()
|
|
|
|
{
|
|
|
|
m_JS = NULL;
|
2004-11-11 08:09:32 +01:00
|
|
|
m_EngineOwned = true;
|
|
|
|
}
|
|
|
|
virtual ~CJSObject()
|
|
|
|
{
|
|
|
|
Shutdown();
|
2004-10-07 21:23:35 +02:00
|
|
|
}
|
2004-11-11 08:09:32 +01:00
|
|
|
void Shutdown()
|
2004-10-07 21:23:35 +02:00
|
|
|
{
|
|
|
|
PropertyTable::iterator it;
|
2005-04-22 09:12:55 +02:00
|
|
|
for( it = m_ScriptProperties.begin(); it != m_ScriptProperties.end(); it++ )
|
2004-10-07 21:23:35 +02:00
|
|
|
delete( it->second );
|
2005-04-22 09:12:55 +02:00
|
|
|
m_ScriptProperties.clear();
|
2004-11-11 08:09:32 +01:00
|
|
|
ReleaseScriptObject();
|
2005-04-22 09:12:55 +02:00
|
|
|
#ifdef ALLOW_NONSHARED_NATIVES
|
|
|
|
for( it = m_NonsharedProperties.begin(); it != m_NonsharedProperties.end(); it++ )
|
2004-11-11 08:09:32 +01:00
|
|
|
delete( it->second );
|
2005-04-22 09:12:55 +02:00
|
|
|
m_NonsharedProperties.clear();
|
|
|
|
#endif
|
2004-10-07 21:23:35 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2004-11-11 08:09:32 +01:00
|
|
|
template<typename T, bool ReadOnly> JSClass CJSObject<T, ReadOnly>::JSI_class = {
|
2004-10-07 21:23:35 +02:00
|
|
|
NULL, JSCLASS_HAS_PRIVATE,
|
|
|
|
JS_PropertyStub, JS_PropertyStub,
|
|
|
|
JSGetProperty, JSSetProperty,
|
|
|
|
JS_EnumerateStub, JS_ResolveStub,
|
2004-11-11 08:09:32 +01:00
|
|
|
JS_ConvertStub, DefaultFinalize,
|
2009-07-27 20:32:59 +02:00
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL
|
2004-10-07 21:23:35 +02:00
|
|
|
};
|
|
|
|
|
2004-11-11 08:09:32 +01:00
|
|
|
template<typename T, bool ReadOnly> JSPropertySpec CJSObject<T, ReadOnly>::JSI_props[] = {
|
2009-07-27 20:32:59 +02:00
|
|
|
{ NULL, 0, 0, NULL, NULL },
|
2004-10-07 21:23:35 +02:00
|
|
|
};
|
|
|
|
|
2004-11-11 08:09:32 +01:00
|
|
|
template<typename T, bool ReadOnly> std::vector<JSFunctionSpec> CJSObject<T, ReadOnly>::m_Methods;
|
|
|
|
|
2005-05-18 07:32:09 +02:00
|
|
|
template<typename T, bool ReadOnly> typename CJSObject<T, ReadOnly>::PropertyTable CJSObject<T, ReadOnly>::m_NativeProperties;
|
2004-10-07 21:23:35 +02:00
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2007-05-07 18:33:24 +02:00
|
|
|
|