1
0
forked from 0ad/0ad

Support new SpiderMonkey API.

wposix: Define int8_t compatibly with SpiderMonkey.
Remove unused camera, lightenv JS interfaces.
Remove most of vector JS interface.
Remove some of the redundant JS string conversion functions.
Remove unneeded vmem, _lodBias functions.
Clean up some formatting.

This was SVN commit r8629.
This commit is contained in:
Ykkrosh 2010-11-16 23:00:52 +00:00
parent 9c521ceb3b
commit bd3bd084c0
83 changed files with 1125 additions and 2149 deletions

View File

@ -2,8 +2,14 @@ function TestScript1A() {}
TestScript1A.prototype.GetX = function() {
// Test that .entity is readonly
delete this.entity;
this.entity = -1;
try {
delete this.entity;
Engine.TS_FAIL("Missed exception");
} catch (e) { }
try {
this.entity = -1;
Engine.TS_FAIL("Missed exception");
} catch (e) { }
// and return the value
return this.entity;

View File

@ -19,8 +19,14 @@ function TestScript1_entity() {}
TestScript1_entity.prototype.GetX = function() {
// Test that .entity is readonly
delete this.entity;
this.entity = -1;
try {
delete this.entity;
Engine.TS_FAIL("Missed exception");
} catch (e) { }
try {
this.entity = -1;
Engine.TS_FAIL("Missed exception");
} catch (e) { }
// and return the value
return this.entity;

View File

@ -76,6 +76,7 @@ function TerrainPreviewPage(panel, name)
this.previewReloadTimer = null;
}
TerrainPreviewPage.prototype = {
reloadPreviews: function() {
this.panel.freeze();
@ -108,7 +109,6 @@ TerrainPreviewPage.prototype = {
imgSizer.add(label, 1, wxAlignment.CENTRE);
this.itemSizer.add(imgSizer, 0, wxAlignment.CENTRE | wxStretch.EXPAND);
}
this.itemSizer.layout();
this.panel.layout();
this.panel.thaw();
@ -143,8 +143,9 @@ TerrainPreviewPage.prototype = {
scrolled.sizer = itemSizer;
// Adjust the number of columns to fit in the available area
var w = this.w;
scrolled.onSize = function (evt) {
var numCols = Math.max(1, Math.floor(evt.size.width / (this.w+16)));
var numCols = Math.max(1, Math.floor(evt.size.width / (w+16)));
if (itemSizer.cols != numCols)
itemSizer.cols = numCols;
};

View File

@ -676,7 +676,7 @@ void CGameView::Update(float DeltaTime)
cmpPosition->GetInterpolatedPosition2D(frameOffset, x, z, angle);
float height = 4.f;
m->ViewCamera.m_Orientation.SetIdentity();
m->ViewCamera.m_Orientation.RotateX(M_PI/24.f);
m->ViewCamera.m_Orientation.RotateX((float)M_PI/24.f);
m->ViewCamera.m_Orientation.RotateY(angle);
m->ViewCamera.m_Orientation.Translate(pos.X, pos.Y + height, pos.Z);

View File

@ -1,310 +0,0 @@
/* 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/>.
*/
#include "precompiled.h"
#include "JSInterface_Camera.h"
#include "scripting/JSConversions.h"
#include "maths/scripting/JSInterface_Vector3D.h"
#include "graphics/Camera.h"
#include "maths/Vector3D.h"
#include "maths/Matrix3D.h"
#include "maths/MathUtil.h"
#include "graphics/Terrain.h"
#include "ps/Game.h"
#include "graphics/GameView.h"
JSClass JSI_Camera::JSI_class = {
"Camera", JSCLASS_HAS_PRIVATE,
JS_PropertyStub, JS_PropertyStub,
JSI_Camera::getProperty, JSI_Camera::setProperty,
JS_EnumerateStub, JS_ResolveStub,
JS_ConvertStub, JSI_Camera::finalize,
NULL, NULL, NULL, NULL
};
JSPropertySpec JSI_Camera::JSI_props[] =
{
{ "position", JSI_Camera::vector_position, JSPROP_ENUMERATE },
{ "orientation", JSI_Camera::vector_orientation, JSPROP_ENUMERATE },
{ "up", JSI_Camera::vector_up, JSPROP_ENUMERATE },
{ 0 },
};
JSFunctionSpec JSI_Camera::JSI_methods[] =
{
{ "lookAt", JSI_Camera::lookAt, 2, 0, 0 },
{ "getFocus", JSI_Camera::getFocus, 0, 0, 0 },
{ 0 }
};
void JSI_Camera::init()
{
g_ScriptingHost.DefineCustomObjectType( &JSI_class, JSI_Camera::construct, 0, JSI_props, JSI_methods, NULL, NULL );
}
JSI_Camera::Camera_Info::Camera_Info()
{
Initialise();
}
JSI_Camera::Camera_Info::Camera_Info( const CVector3D& Position )
{
CMatrix3D Orient;
Orient.SetXRotation( DEGTORAD( 30 ) );
Orient.RotateY( DEGTORAD( -45 ) );
Orient.Translate( Position );
Initialise( (const CMatrix3D&)Orient );
}
JSI_Camera::Camera_Info::Camera_Info( const CVector3D& Position, const CVector3D& Orientation )
{
Initialise();
m_Data->LookAlong( Position, Orientation, CVector3D( 0.0f, 1.0f, 0.0f ) );
}
JSI_Camera::Camera_Info::Camera_Info( const CVector3D& Position, const CVector3D& Orientation, const CVector3D& Up )
{
Initialise();
m_Data->LookAlong( Position, Orientation, Up );
}
JSI_Camera::Camera_Info::Camera_Info( const CMatrix3D& Orientation )
{
Initialise( Orientation );
}
JSI_Camera::Camera_Info::Camera_Info( CCamera* Reference )
{
m_Data = Reference;
m_EngineOwned = true;
}
JSI_Camera::Camera_Info::~Camera_Info()
{
if( !m_EngineOwned )
delete( m_Data );
}
void JSI_Camera::Camera_Info::Initialise()
{
CMatrix3D Orient;
Orient.SetXRotation( DEGTORAD( 30 ) );
Orient.RotateY( DEGTORAD( -45 ) );
Orient.Translate( 100, 150, -100 );
Initialise( (const CMatrix3D&)Orient );
}
void JSI_Camera::Camera_Info::Initialise( const CMatrix3D& Orientation )
{
m_Data = new CCamera();
m_EngineOwned = false;
m_Data->LookAlong( Orientation.GetTranslation(), Orientation.GetIn(), Orientation.GetUp() );
}
void JSI_Camera::Camera_Info::Freshen()
{
m_sv_Position = m_Data->m_Orientation.GetTranslation();
m_sv_Orientation = m_Data->m_Orientation.GetIn();
m_sv_Up = m_Data->m_Orientation.GetUp();
}
void JSI_Camera::Camera_Info::Update()
{
m_Data->LookAlong( m_sv_Position, m_sv_Orientation, m_sv_Up );
}
void JSI_Camera::Camera_Info::FreshenTarget()
{
m_sv_Target = m_Data->GetFocus();
}
JSBool JSI_Camera::getCamera( JSContext* cx, JSObject* UNUSED(obj), jsval UNUSED(id), jsval* vp )
{
if( g_Game && g_Game->GetView()->GetCamera() )
{
JSObject* camera = JS_NewObject( cx, &JSI_Camera::JSI_class, NULL, NULL );
JS_SetPrivate( cx, camera, new Camera_Info( g_Game->GetView()->GetCamera() ) );
*vp = OBJECT_TO_JSVAL( camera );
}
else
{
*vp = JSVAL_NULL;
}
return( JS_TRUE );
}
JSBool JSI_Camera::setCamera( JSContext* cx, JSObject* UNUSED(obj), jsval UNUSED(id), jsval* vp )
{
JSObject* camera = JSVAL_TO_OBJECT( *vp );
Camera_Info* cameraInfo;
if( !JSVAL_IS_OBJECT( *vp ) || NULL == ( cameraInfo = (Camera_Info*)JS_GetInstancePrivate( cx, camera, &JSI_Camera::JSI_class, NULL ) ) )
{
JS_ReportError( cx, "[Camera] Invalid object" );
}
else
{
g_Game->GetView()->GetCamera()->m_Orientation = cameraInfo->m_Data->m_Orientation;
}
return( JS_TRUE );
}
JSBool JSI_Camera::getProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp )
{
if( !JSVAL_IS_INT( id ) )
return( JS_TRUE );
Camera_Info* cameraInfo = (Camera_Info*)JS_GetPrivate( cx, obj );
if( !cameraInfo )
{
JS_ReportError( cx, "[Camera] Invalid Reference" );
return( JS_TRUE );
}
CVector3D* d;
switch( ToPrimitive<int>( id ) )
{
case vector_position: d = &cameraInfo->m_sv_Position; break;
case vector_orientation: d = &cameraInfo->m_sv_Orientation; break;
case vector_up: d = &cameraInfo->m_sv_Up; break;
default: return( JS_TRUE );
}
JSObject* vector3d = JS_NewObject( g_ScriptingHost.getContext(), &JSI_Vector3D::JSI_class, NULL, NULL );
JS_SetPrivate( g_ScriptingHost.getContext(), vector3d, new JSI_Vector3D::Vector3D_Info( d, cameraInfo, ( void( IPropertyOwner::* )() )&Camera_Info::Update, ( void( IPropertyOwner::* )() )&Camera_Info::Freshen ) );
*vp = OBJECT_TO_JSVAL( vector3d );
return( JS_TRUE );
}
JSBool JSI_Camera::setProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp )
{
if( !JSVAL_IS_INT( id ) )
return( JS_TRUE );
Camera_Info* cameraInfo = (Camera_Info*)JS_GetPrivate( cx, obj );
if( !cameraInfo )
{
JS_ReportError( cx, "[Camera] Invalid reference" );
return( JS_TRUE );
}
JSObject* vector3d = JSVAL_TO_OBJECT( *vp );
JSI_Vector3D::Vector3D_Info* v = NULL;
if( JSVAL_IS_OBJECT( *vp ) && NULL != ( v = (JSI_Vector3D::Vector3D_Info*)JS_GetInstancePrivate( g_ScriptingHost.getContext(), vector3d, &JSI_Vector3D::JSI_class, NULL ) ) )
{
cameraInfo->Freshen();
switch( ToPrimitive<int>( id ) )
{
case vector_position: cameraInfo->m_sv_Position = *( v->vector ); break;
case vector_orientation: cameraInfo->m_sv_Orientation = *( v->vector ); break;
case vector_up: cameraInfo->m_sv_Up = *( v->vector ); break;
}
cameraInfo->Update();
}
return( JS_TRUE );
}
#define GETVECTOR( jv ) ( ( JSVAL_IS_OBJECT( jv ) && NULL != ( v = (JSI_Vector3D::Vector3D_Info*)JS_GetInstancePrivate( g_ScriptingHost.getContext(), JSVAL_TO_OBJECT( jv ), &JSI_Vector3D::JSI_class, NULL ) ) ) ? *(v->vector) : CVector3D() )
JSBool JSI_Camera::lookAt( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval )
{
JSI_Vector3D::Vector3D_Info* v = NULL;
Camera_Info* cameraInfo = (Camera_Info*)JS_GetPrivate( cx, obj );
JSU_REQUIRE_PARAM_RANGE(2, 3);
cameraInfo->m_sv_Position = GETVECTOR( argv[0] );
cameraInfo->m_sv_Orientation = GETVECTOR( argv[1] ) - cameraInfo->m_sv_Position;
cameraInfo->m_sv_Orientation.Normalize();
if( argc == 2 )
{
cameraInfo->m_sv_Up = CVector3D( 0.0f, 1.0f, 0.0f );
}
else if( argc == 3 )
{
cameraInfo->m_sv_Up = GETVECTOR( argv[2] );
}
cameraInfo->Update();
*rval = JSVAL_TRUE;
return( JS_TRUE );
}
JSBool JSI_Camera::getFocus( JSContext* cx, JSObject* obj,
uintN UNUSED(argc), jsval* UNUSED(argv), jsval* rval )
{
// Largely copied from the equivalent method in CCamera
Camera_Info* cameraInfo = (Camera_Info*)JS_GetPrivate( cx, obj );
JSObject* vector3d = JS_NewObject( g_ScriptingHost.getContext(), &JSI_Vector3D::JSI_class, NULL, NULL );
JS_SetPrivate( g_ScriptingHost.getContext(), vector3d, new JSI_Vector3D::Vector3D_Info( &( cameraInfo->m_sv_Target ), cameraInfo, NULL, ( void( IPropertyOwner::* )() )&Camera_Info::FreshenTarget ) );
*rval = OBJECT_TO_JSVAL( vector3d );
return( JS_TRUE );
}
JSBool JSI_Camera::construct( JSContext* cx, JSObject* UNUSED(obj),
uintN argc, jsval* argv, jsval* rval )
{
JSI_Vector3D::Vector3D_Info* v = NULL;
JSObject* camera = JS_NewObject( cx, &JSI_Camera::JSI_class, NULL, NULL );
JSU_REQUIRE_MAX_PARAMS(3);
Camera_Info* camera_info = 0;
switch(argc)
{
case 0:
camera_info = new Camera_Info();
break;
case 1:
camera_info = new Camera_Info( GETVECTOR( argv[0] ) );
break;
case 2:
camera_info = new Camera_Info( GETVECTOR( argv[0] ), GETVECTOR( argv[1] ) );
break;
case 3:
camera_info = new Camera_Info( GETVECTOR( argv[0] ), GETVECTOR( argv[1] ), GETVECTOR( argv[2] ) );
break;
NODEFAULT;
}
#undef GET_VECTOR
JS_SetPrivate( cx, camera, camera_info );
*rval = OBJECT_TO_JSVAL( camera );
return( JS_TRUE );
}
void JSI_Camera::finalize( JSContext* cx, JSObject* obj )
{
delete( (Camera_Info*)JS_GetPrivate( cx, obj ) );
}

View File

@ -1,101 +0,0 @@
/* 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/>.
*/
// JSInterface_Camera.h
//
// A JavaScript wrapper around a camera object.
//
// Usage: When manipulating objects of type 'Camera' in JavaScript
#include "scripting/ScriptingHost.h"
#include "maths/Vector3D.h"
#include "graphics/Camera.h"
#include "graphics/HFTracer.h"
#ifndef INCLUDED_JSI_CAMERA
#define INCLUDED_JSI_CAMERA
namespace JSI_Camera
{
enum
{
vector_position,
vector_orientation,
vector_up
};
enum
{
lookat
};
struct Camera_Info : public IPropertyOwner
{
CCamera* m_Data;
bool m_EngineOwned;
CVector3D m_sv_Position;
CVector3D m_sv_Orientation;
CVector3D m_sv_Up;
CVector3D m_sv_Target;
Camera_Info(); // Create a camera set to the initial view
Camera_Info( const CVector3D& Position );
Camera_Info( const CVector3D& Position, const CVector3D& Orientation );
Camera_Info( const CVector3D& Position, const CVector3D& Orientation, const CVector3D& Up );
Camera_Info( const CMatrix3D& Orientation );
Camera_Info( CCamera* copy );
void Initialise();
void Initialise( const CMatrix3D& Orientation );
void Freshen();
void Update();
void FreshenTarget();
~Camera_Info();
/*
Camera_Info( const CVector3D& _position );
Camera_Info( const CVector3D& _position, const CVector3D& _orientation );
Camera_Info( const CVector3D& _position, const CVector3D& _orientation, const CVector3D& _up );
Camera_Info( CCamera* _copy );
void update();
*/
};
extern JSClass JSI_class;
extern JSPropertySpec JSI_props[];
extern JSFunctionSpec JSI_methods[];
JSBool getProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp );
JSBool setProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp );
JSBool getCamera( JSContext* cx, JSObject* obj, jsval id, jsval* vp );
JSBool setCamera( JSContext* cx, JSObject* obj, jsval id, jsval* vp );
JSBool construct( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
void finalize( JSContext* cx, JSObject* obj );
JSBool lookAt( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
JSBool getFocus( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
void init();
}
#endif

View File

@ -1,250 +0,0 @@
/* 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/>.
*/
/*
* Provide the LightEnv object type for JavaScript
*/
#include "precompiled.h"
#include "maths/scripting/JSInterface_Vector3D.h"
#include "graphics/scripting/JSInterface_LightEnv.h"
#include "graphics/LightEnv.h"
#include "ps/World.h"
#include "scripting/JSConversions.h"
namespace JSI_LightEnv {
namespace {
extern JSClass JSI_class;
/**
* This enumeration is used to index properties with the JavaScript implementation.
*/
enum
{
lightenv_elevation,
lightenv_rotation,
lightenv_terrainShadowTransparency,
lightenv_sun,
lightenv_terrainAmbient,
lightenv_unitsAmbient
};
///////////////////////////////////////////////////////////////////////////////////////////////
// LightEnv_Info, the private structure that holds data for individual LightEnv objects
struct LightEnv_Info : public IPropertyOwner
{
CLightEnv* m_Data;
bool m_EngineOwned;
// Create a new LightEnv that will only be used by JavaScript
LightEnv_Info()
{
m_Data = new CLightEnv;
m_EngineOwned = false;
}
// Use the given CLightEnv from the engine. The caller must guarantee that
// the copy object will not be deleted.
LightEnv_Info(CLightEnv* copy)
{
m_Data = copy;
m_EngineOwned = true;
}
~LightEnv_Info()
{
if (!m_EngineOwned)
delete m_Data;
}
};
///////////////////////////////////////////////////////////////////////////////////////////////
// Construction and finalization of LightEnvs
/**
* construct: the LightEnv constructor has been called from JavaScript, so create a new
* LightEnv object
*/
JSBool construct(JSContext* cx, JSObject* UNUSED(obj), uintN argc, jsval* argv, jsval* rval)
{
JSObject* lightenv = JS_NewObject(cx, &JSI_class, NULL, NULL);
JSU_REQUIRE_NO_PARAMS();
JS_SetPrivate(cx, lightenv, new LightEnv_Info);
*rval = OBJECT_TO_JSVAL(lightenv);
return JS_TRUE;
}
/**
* finalize: callback from the JS engine to indicate we should free our private data
*/
void finalize(JSContext* cx, JSObject* obj)
{
delete (LightEnv_Info*)JS_GetPrivate(cx, obj);
}
///////////////////////////////////////////////////////////////////////////////////////////////
// Accessing properties of a LightEnv object
// Can't use ToJSVal here because we need live updates from the vectors
JSBool getVectorProperty(JSContext* cx, LightEnv_Info* lightenvInfo, CVector3D* vec, jsval* vp)
{
JSObject* vector3d = JS_NewObject(cx, &JSI_Vector3D::JSI_class, NULL, NULL);
JS_SetPrivate(cx, vector3d, new JSI_Vector3D::Vector3D_Info(vec, lightenvInfo));
*vp = OBJECT_TO_JSVAL(vector3d);
return JS_TRUE;
}
JSBool getProperty(JSContext* cx, JSObject* obj, jsval id, jsval* vp)
{
if (!JSVAL_IS_INT(id))
return JS_TRUE ;
LightEnv_Info* lightenvInfo = (LightEnv_Info*)JS_GetPrivate(cx, obj);
if (!lightenvInfo)
{
JS_ReportError(cx, "[LightEnv] Invalid Reference");
return JS_TRUE;
}
CLightEnv* lightenv = lightenvInfo->m_Data;
switch(ToPrimitive<int>(id)) {
case lightenv_elevation: *vp = ToJSVal(lightenv->GetElevation()); break;
case lightenv_rotation: *vp = ToJSVal(lightenv->GetRotation()); break;
case lightenv_terrainShadowTransparency: *vp = ToJSVal(lightenv->GetTerrainShadowTransparency()); break;
case lightenv_sun: return getVectorProperty(cx, lightenvInfo, &lightenv->m_SunColor, vp);
case lightenv_terrainAmbient: return getVectorProperty(cx, lightenvInfo, &lightenv->m_TerrainAmbientColor, vp);
case lightenv_unitsAmbient: return getVectorProperty(cx, lightenvInfo, &lightenv->m_UnitsAmbientColor, vp);
default: break;
}
return JS_TRUE;
}
JSBool setProperty(JSContext* cx, JSObject* obj, jsval id, jsval* vp)
{
if (!JSVAL_IS_INT(id))
return( JS_TRUE );
LightEnv_Info* lightenvInfo = (LightEnv_Info*)JS_GetPrivate(cx, obj);
if (!lightenvInfo)
{
JS_ReportError(cx, "[LightEnv] Invalid reference");
return JS_TRUE;
}
CLightEnv* lightenv = lightenvInfo->m_Data;
switch(ToPrimitive<int>(id)) {
case lightenv_elevation: lightenv->SetElevation(ToPrimitive<float>(*vp)); break;
case lightenv_rotation: lightenv->SetRotation(ToPrimitive<float>(*vp)); break;
case lightenv_terrainShadowTransparency: lightenv->SetTerrainShadowTransparency(ToPrimitive<float>(*vp)); break;
case lightenv_sun: lightenv->m_SunColor = ToPrimitive<CVector3D>(*vp); break;
case lightenv_terrainAmbient: lightenv->m_TerrainAmbientColor = ToPrimitive<CVector3D>(*vp); break;
case lightenv_unitsAmbient: lightenv->m_UnitsAmbientColor = ToPrimitive<CVector3D>(*vp); break;
default: break;
}
return JS_TRUE;
}
///////////////////////////////////////////////////////////////////////////////////////////////
// Registration of LightEnv class with JavaScript
JSClass JSI_class = {
"LightEnv", JSCLASS_HAS_PRIVATE,
JS_PropertyStub, JS_PropertyStub,
getProperty, setProperty,
JS_EnumerateStub, JS_ResolveStub,
JS_ConvertStub, finalize,
NULL, NULL, NULL, NULL
};
JSPropertySpec JSI_props[] =
{
{ "elevation", lightenv_elevation, JSPROP_ENUMERATE },
{ "rotation", lightenv_rotation, JSPROP_ENUMERATE },
{ "terrainShadowTransparency", lightenv_terrainShadowTransparency, JSPROP_ENUMERATE },
{ "sun", lightenv_sun, JSPROP_ENUMERATE },
{ "terrainAmbient", lightenv_terrainAmbient, JSPROP_ENUMERATE },
{ "unitsAmbient", lightenv_unitsAmbient, JSPROP_ENUMERATE },
{ 0 },
};
JSFunctionSpec JSI_methods[] =
{
{ 0 }
};
} // anonymous namespace
/**
* init: called by GameSetup to register the LightEnv class with the JS engine.
*/
void init()
{
g_ScriptingHost.DefineCustomObjectType( &JSI_class, construct, 0, JSI_props, JSI_methods, NULL, NULL );
}
///////////////////////////////////////////////////////////////////////////////////////////////
// Accessing the global lightenv
JSBool getLightEnv(JSContext* cx, JSObject* UNUSED(obj), jsval UNUSED(id), jsval* vp)
{
JSObject* lightenv = JS_NewObject(cx, &JSI_class, NULL, NULL);
JS_SetPrivate(cx, lightenv, new LightEnv_Info(&g_LightEnv));
*vp = OBJECT_TO_JSVAL(lightenv);
return JS_TRUE;
}
JSBool setLightEnv(JSContext* cx, JSObject* UNUSED(obj), jsval UNUSED(id), jsval* vp)
{
JSObject* lightenv = JSVAL_TO_OBJECT(*vp);
LightEnv_Info* lightenvInfo;
if (!JSVAL_IS_OBJECT(*vp) || NULL == (lightenvInfo = (LightEnv_Info*)JS_GetInstancePrivate(cx, lightenv, &JSI_class, NULL)))
{
JS_ReportError( cx, "[LightEnv] Invalid object" );
}
else
{
g_LightEnv = *lightenvInfo->m_Data;
}
return JS_TRUE;
}
} // namespace JSI_LightEnv

View File

@ -1,34 +0,0 @@
/* 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/>.
*/
/*
* Provide the LightEnv object type for JavaScript
*/
#ifndef INCLUDED_JSI_LIGHTENV
#define INCLUDED_JSI_LIGHTENV
#include "scripting/ScriptingHost.h"
namespace JSI_LightEnv
{
void init();
JSBool getLightEnv( JSContext* cx, JSObject* obj, jsval id, jsval* vp );
JSBool setLightEnv( JSContext* cx, JSObject* obj, jsval id, jsval* vp );
}
#endif

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2009 Wildfire Games.
/* Copyright (C) 2010 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -57,6 +57,7 @@ CGUI
#include "ps/Profile.h"
#include "scripting/ScriptingHost.h"
#include "scriptinterface/ScriptInterface.h"
#include "ps/Hotkey.h"
#include "ps/Globals.h"
#include "ps/Filesystem.h"
@ -347,10 +348,15 @@ CGUI::CGUI() : m_MouseButtons(0), m_FocusedObject(NULL), m_InternalNameNumber(0)
m_BaseObject = new CGUIDummyObject;
m_BaseObject->SetGUI(this);
// Construct the parent object for all GUI JavaScript things
m_ScriptObject = JS_NewObject(g_ScriptingHost.getContext(), NULL, g_ScriptingHost.GetGlobalObject(), NULL);
debug_assert(m_ScriptObject != NULL); // How should it handle errors?
JS_AddRoot(g_ScriptingHost.getContext(), &m_ScriptObject);
// Construct the root object for all GUI JavaScript things.
// (We need an object with no parent, so functions defined by scripts get
// put onto this object and not its parent. In the current version of SpiderMonkey
// that means it must be a global object. Then we adjust its prototype so it
// can still read standard properties from the context's standard global object.)
m_ScriptObject = JS_NewGlobalObject(g_ScriptingHost.getContext(), g_ScriptingHost.GetScriptInterface().GetGlobalClass());
JS_AddObjectRoot(g_ScriptingHost.getContext(), &m_ScriptObject);
JS_SetPrototype(g_ScriptingHost.getContext(), m_ScriptObject, g_ScriptingHost.GetGlobalObject());
}
CGUI::~CGUI()
@ -363,7 +369,7 @@ CGUI::~CGUI()
if (m_ScriptObject)
{
// Let it be garbage-collected
JS_RemoveRoot(g_ScriptingHost.getContext(), &m_ScriptObject);
JS_RemoveObjectRoot(g_ScriptingHost.getContext(), &m_ScriptObject);
}
}

View File

@ -48,22 +48,6 @@ InReaction gui_handler(const SDL_Event_* ev)
return g_GUI->HandleEvent(ev);
}
CGUIManager::SGUIPage::SGUIPage()
{
JS_AddNamedRoot(g_ScriptingHost.GetContext(), &initData, "SGUIPage initData");
}
CGUIManager::SGUIPage::SGUIPage(const SGUIPage& page)
{
*this = page;
JS_AddNamedRoot(g_ScriptingHost.GetContext(), &initData, "SGUIPage initData copy");
}
CGUIManager::SGUIPage::~SGUIPage()
{
JS_RemoveRoot(g_ScriptingHost.GetContext(), &initData);
}
CGUIManager::CGUIManager(ScriptInterface& scriptInterface) :
m_ScriptInterface(scriptInterface)
{
@ -90,7 +74,7 @@ void CGUIManager::PushPage(const CStrW& pageName, CScriptVal initData)
{
m_PageStack.push_back(SGUIPage());
m_PageStack.back().name = pageName;
m_PageStack.back().initData = initData;
m_PageStack.back().initData = CScriptValRooted(m_ScriptInterface.GetContext(), initData);
LoadPage(m_PageStack.back());
}

View File

@ -135,15 +135,11 @@ public:
private:
struct SGUIPage
{
SGUIPage();
SGUIPage(const SGUIPage&);
~SGUIPage();
CStrW name;
std::set<VfsPath> inputs; // for hotloading
JSContext* cx;
CScriptVal initData; // data to be passed to the init() function
CScriptValRooted initData; // data to be passed to the init() function
shared_ptr<CGUI> gui; // the actual GUI page
};

View File

@ -90,13 +90,13 @@ IGUIObject::~IGUIObject()
std::map<CStr, JSObject**>::iterator it;
for (it = m_ScriptHandlers.begin(); it != m_ScriptHandlers.end(); ++it)
{
JS_RemoveRoot(g_ScriptingHost.getContext(), it->second);
JS_RemoveObjectRoot(g_ScriptingHost.getContext(), it->second);
delete it->second;
}
}
if (m_JSObject)
JS_RemoveRoot(g_ScriptingHost.getContext(), &m_JSObject);
JS_RemoveObjectRoot(g_ScriptingHost.getContext(), &m_JSObject);
}
//-------------------------------------------------------------------
@ -488,11 +488,11 @@ void IGUIObject::SetScriptHandler(const CStr& Action, JSObject* Function)
{
JSObject** obj = new JSObject*;
*obj = Function;
JS_AddRoot(g_ScriptingHost.getContext(), obj);
JS_AddObjectRoot(g_ScriptingHost.getContext(), obj);
if (m_ScriptHandlers[Action])
{
JS_RemoveRoot(g_ScriptingHost.getContext(), m_ScriptHandlers[Action]);
JS_RemoveObjectRoot(g_ScriptingHost.getContext(), m_ScriptHandlers[Action]);
delete m_ScriptHandlers[Action];
}
m_ScriptHandlers[Action] = obj;
@ -504,10 +504,6 @@ void IGUIObject::ScriptEvent(const CStr& Action)
if (it == m_ScriptHandlers.end())
return;
// PRIVATE_TO_JSVAL assumes two-byte alignment,
// so make sure that's always true
debug_assert(! ((jsval)this & JSVAL_INT));
// The IGUIObject needs to be stored inside the script's object
jsval guiObject = PRIVATE_TO_JSVAL(this);
@ -517,9 +513,6 @@ void IGUIObject::ScriptEvent(const CStr& Action)
// TODO: why don't we use GetJSObject here?
// Prevent it from being garbage-collected before it's passed into the function
JS_AddRoot(g_ScriptingHost.getContext(), &jsGuiObject);
// Set up the 'mouse' parameter
jsval mouseParams[3];
mouseParams[0] = INT_TO_JSVAL(m_pGUI->m_MousePos.x);
@ -528,9 +521,6 @@ void IGUIObject::ScriptEvent(const CStr& Action)
JSObject* mouseObj = JS_ConstructObjectWithArguments(g_ScriptingHost.getContext(), &JSI_GUIMouse::JSI_class, m_pGUI->m_ScriptObject, NULL, 3, mouseParams);
debug_assert(mouseObj); // TODO: Handle errors
// Don't garbage collect the mouse
JS_AddRoot(g_ScriptingHost.getContext(), &mouseObj);
jsval paramData[] = { OBJECT_TO_JSVAL(mouseObj) };
jsval result;
@ -539,10 +529,6 @@ void IGUIObject::ScriptEvent(const CStr& Action)
{
JS_ReportError(g_ScriptingHost.getContext(), "Errors executing script action \"%s\"", Action.c_str());
}
// Allow the temporary parameters to be garbage-collected
JS_RemoveRoot(g_ScriptingHost.getContext(), &mouseObj);
JS_RemoveRoot(g_ScriptingHost.getContext(), &jsGuiObject);
}
void IGUIObject::ScriptEvent(const CStr& Action, const CScriptValRooted& Argument)
@ -571,7 +557,7 @@ JSObject* IGUIObject::GetJSObject()
if (! m_JSObject)
{
m_JSObject = JS_NewObject(g_ScriptingHost.getContext(), &JSI_IGUIObject::JSI_class, NULL, NULL);
JS_AddRoot(g_ScriptingHost.getContext(), &m_JSObject);
JS_AddObjectRoot(g_ScriptingHost.getContext(), &m_JSObject);
JS_SetPrivate(g_ScriptingHost.getContext(), m_JSObject, this);
}
return m_JSObject;

View File

@ -145,8 +145,8 @@ class IGUIObject
friend class GUITooltip;
// Allow getProperty to access things like GetParent()
friend JSBool JSI_IGUIObject::getProperty(JSContext* cx, JSObject* obj, jsval id, jsval* vp);
friend JSBool JSI_IGUIObject::setProperty(JSContext* cx, JSObject* obj, jsval id, jsval* vp);
friend JSBool JSI_IGUIObject::getProperty(JSContext* cx, JSObject* obj, jsid id, jsval* vp);
friend JSBool JSI_IGUIObject::setProperty(JSContext* cx, JSObject* obj, jsid id, jsval* vp);
public:
IGUIObject();

View File

@ -46,10 +46,6 @@ template<> jsval ScriptInterface::ToJSVal<SDL_Event_>(JSContext* cx, SDL_Event_
default: typeName = "(unknown)"; break;
}
ScriptInterface::LocalRootScope scope(cx);
if (! scope.OK())
return JSVAL_VOID;
JSObject* obj = JS_NewObject(cx, NULL, NULL, NULL);
if (! obj)
return JSVAL_VOID;
@ -123,7 +119,6 @@ template<> jsval ScriptInterface::ToJSVal<SDL_Event_>(JSContext* cx, SDL_Event_
jsval rval = OBJECT_TO_JSVAL(obj);
scope.LeaveWithResult(rval);
return rval;
}

View File

@ -45,30 +45,32 @@ JSPropertySpec JSI_GUISize::JSI_props[] =
JSFunctionSpec JSI_GUISize::JSI_methods[] =
{
{ "toString", JSI_GUISize::toString, 0, 0, 0 },
{ "toString", JSI_GUISize::toString, 0, 0 },
{ 0 }
};
JSBool JSI_GUISize::construct(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* UNUSED(rval))
JSBool JSI_GUISize::construct(JSContext* cx, uintN argc, jsval* vp)
{
JSObject* obj = JS_NewObject(cx, &JSI_GUISize::JSI_class, NULL, NULL);
if (argc == 8)
{
JS_SetProperty(cx, obj, "left", &argv[0]);
JS_SetProperty(cx, obj, "top", &argv[1]);
JS_SetProperty(cx, obj, "right", &argv[2]);
JS_SetProperty(cx, obj, "bottom", &argv[3]);
JS_SetProperty(cx, obj, "rleft", &argv[4]);
JS_SetProperty(cx, obj, "rtop", &argv[5]);
JS_SetProperty(cx, obj, "rright", &argv[6]);
JS_SetProperty(cx, obj, "rbottom", &argv[7]);
JS_SetProperty(cx, obj, "left", &JS_ARGV(cx, vp)[0]);
JS_SetProperty(cx, obj, "top", &JS_ARGV(cx, vp)[1]);
JS_SetProperty(cx, obj, "right", &JS_ARGV(cx, vp)[2]);
JS_SetProperty(cx, obj, "bottom", &JS_ARGV(cx, vp)[3]);
JS_SetProperty(cx, obj, "rleft", &JS_ARGV(cx, vp)[4]);
JS_SetProperty(cx, obj, "rtop", &JS_ARGV(cx, vp)[5]);
JS_SetProperty(cx, obj, "rright", &JS_ARGV(cx, vp)[6]);
JS_SetProperty(cx, obj, "rbottom", &JS_ARGV(cx, vp)[7]);
}
else if (argc == 4)
{
jsval zero = JSVAL_ZERO;
JS_SetProperty(cx, obj, "left", &argv[0]);
JS_SetProperty(cx, obj, "top", &argv[1]);
JS_SetProperty(cx, obj, "right", &argv[2]);
JS_SetProperty(cx, obj, "bottom", &argv[3]);
JS_SetProperty(cx, obj, "left", &JS_ARGV(cx, vp)[0]);
JS_SetProperty(cx, obj, "top", &JS_ARGV(cx, vp)[1]);
JS_SetProperty(cx, obj, "right", &JS_ARGV(cx, vp)[2]);
JS_SetProperty(cx, obj, "bottom", &JS_ARGV(cx, vp)[3]);
JS_SetProperty(cx, obj, "rleft", &zero);
JS_SetProperty(cx, obj, "rtop", &zero);
JS_SetProperty(cx, obj, "rright", &zero);
@ -87,6 +89,7 @@ JSBool JSI_GUISize::construct(JSContext* cx, JSObject* obj, uintN argc, jsval* a
JS_SetProperty(cx, obj, "rbottom", &zero);
}
JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(obj));
return JS_TRUE;
}
@ -99,13 +102,15 @@ CStr ToPercentString(double pix, double per)
return CStr(per)+CStr("%")+( pix == 0.0 ? CStr() : pix > 0.0 ? CStr("+")+CStr(pix) : CStr(pix) );
}
JSBool JSI_GUISize::toString(JSContext* cx, JSObject* obj, uintN UNUSED(argc), jsval* UNUSED(argv), jsval* rval)
JSBool JSI_GUISize::toString(JSContext* cx, uintN argc, jsval* vp)
{
UNUSED2(argc);
CStr buffer;
try
{
#define SIDE(side) buffer += ToPercentString(g_ScriptingHost.GetObjectProperty_Double(obj, #side), g_ScriptingHost.GetObjectProperty_Double(obj, "r"#side));
#define SIDE(side) buffer += ToPercentString(g_ScriptingHost.GetObjectProperty_Double(JS_THIS_OBJECT(cx, vp), #side), g_ScriptingHost.GetObjectProperty_Double(JS_THIS_OBJECT(cx, vp), "r"#side));
SIDE(left);
buffer += " ";
SIDE(top);
@ -117,11 +122,11 @@ JSBool JSI_GUISize::toString(JSContext* cx, JSObject* obj, uintN UNUSED(argc), j
}
catch (PSERROR_Scripting_ConversionFailed)
{
*rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, "<Error converting value to numbers>"));
JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(JS_NewStringCopyZ(cx, "<Error converting value to numbers>")));
return JS_TRUE;
}
*rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, buffer.c_str()));
JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(JS_NewStringCopyZ(cx, buffer.c_str())));
return JS_TRUE;
}
@ -149,45 +154,57 @@ JSPropertySpec JSI_GUIColor::JSI_props[] =
JSFunctionSpec JSI_GUIColor::JSI_methods[] =
{
{ "toString", JSI_GUIColor::toString, 0, 0, 0 },
{ "toString", JSI_GUIColor::toString, 0, 0 },
{ 0 }
};
JSBool JSI_GUIColor::construct(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* UNUSED(rval))
JSBool JSI_GUIColor::construct(JSContext* cx, uintN argc, jsval* vp)
{
JSObject* obj = JS_NewObject(cx, &JSI_GUIColor::JSI_class, NULL, NULL);
if (argc == 4)
{
JS_SetProperty(cx, obj, "r", &argv[0]);
JS_SetProperty(cx, obj, "g", &argv[1]);
JS_SetProperty(cx, obj, "b", &argv[2]);
JS_SetProperty(cx, obj, "a", &argv[3]);
JS_SetProperty(cx, obj, "r", &JS_ARGV(cx, vp)[0]);
JS_SetProperty(cx, obj, "g", &JS_ARGV(cx, vp)[1]);
JS_SetProperty(cx, obj, "b", &JS_ARGV(cx, vp)[2]);
JS_SetProperty(cx, obj, "a", &JS_ARGV(cx, vp)[3]);
}
else
{
// Nice magenta:
jsval r = DOUBLE_TO_JSVAL(JS_NewDouble(cx, 1.0));
JS_SetProperty(cx, obj, "r", &r);
jsval g = DOUBLE_TO_JSVAL(JS_NewDouble(cx, 0.0));
JS_SetProperty(cx, obj, "g", &g);
jsval b = DOUBLE_TO_JSVAL(JS_NewDouble(cx, 1.0));
JS_SetProperty(cx, obj, "b", &b);
jsval a = DOUBLE_TO_JSVAL(JS_NewDouble(cx, 1.0));
JS_SetProperty(cx, obj, "a", &a);
jsval c;
if (!JS_NewNumberValue(cx, 1.0, &c))
return JS_FALSE;
JS_SetProperty(cx, obj, "r", &c);
JS_SetProperty(cx, obj, "b", &c);
JS_SetProperty(cx, obj, "a", &c);
if (!JS_NewNumberValue(cx, 0.0, &c))
return JS_FALSE;
JS_SetProperty(cx, obj, "g", &c);
}
JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(obj));
return JS_TRUE;
}
JSBool JSI_GUIColor::toString(JSContext* cx, JSObject* obj,
uintN UNUSED(argc), jsval* UNUSED(argv), jsval* rval)
JSBool JSI_GUIColor::toString(JSContext* cx, uintN argc, jsval* vp)
{
UNUSED2(argc);
jsdouble r, g, b, a;
if (!JS_ValueToNumber(cx, g_ScriptingHost.GetObjectProperty(JS_THIS_OBJECT(cx, vp), "r"), &r)) return JS_FALSE;
if (!JS_ValueToNumber(cx, g_ScriptingHost.GetObjectProperty(JS_THIS_OBJECT(cx, vp), "g"), &g)) return JS_FALSE;
if (!JS_ValueToNumber(cx, g_ScriptingHost.GetObjectProperty(JS_THIS_OBJECT(cx, vp), "b"), &b)) return JS_FALSE;
if (!JS_ValueToNumber(cx, g_ScriptingHost.GetObjectProperty(JS_THIS_OBJECT(cx, vp), "a"), &a)) return JS_FALSE;
char buffer[256];
// Convert to integers, to be compatible with the GUI's string SetSetting
snprintf(buffer, 256, "%d %d %d %d",
(int)( 255.0 * *JSVAL_TO_DOUBLE(g_ScriptingHost.GetObjectProperty(obj, "r")) ),
(int)( 255.0 * *JSVAL_TO_DOUBLE(g_ScriptingHost.GetObjectProperty(obj, "g")) ),
(int)( 255.0 * *JSVAL_TO_DOUBLE(g_ScriptingHost.GetObjectProperty(obj, "b")) ),
(int)( 255.0 * *JSVAL_TO_DOUBLE(g_ScriptingHost.GetObjectProperty(obj, "a")) ));
*rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, buffer));
(int)(255.0 * r),
(int)(255.0 * g),
(int)(255.0 * b),
(int)(255.0 * a));
JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(JS_NewStringCopyZ(cx, buffer)));
return JS_TRUE;
}
@ -213,17 +230,19 @@ JSPropertySpec JSI_GUIMouse::JSI_props[] =
JSFunctionSpec JSI_GUIMouse::JSI_methods[] =
{
{ "toString", JSI_GUIMouse::toString, 0, 0, 0 },
{ "toString", JSI_GUIMouse::toString, 0, 0 },
{ 0 }
};
JSBool JSI_GUIMouse::construct(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* UNUSED(rval))
JSBool JSI_GUIMouse::construct(JSContext* cx, uintN argc, jsval* vp)
{
JSObject* obj = JS_NewObject(cx, &JSI_GUIMouse::JSI_class, NULL, NULL);
if (argc == 3)
{
JS_SetProperty(cx, obj, "x", &argv[0]);
JS_SetProperty(cx, obj, "y", &argv[1]);
JS_SetProperty(cx, obj, "buttons", &argv[2]);
JS_SetProperty(cx, obj, "x", &JS_ARGV(cx, vp)[0]);
JS_SetProperty(cx, obj, "y", &JS_ARGV(cx, vp)[1]);
JS_SetProperty(cx, obj, "buttons", &JS_ARGV(cx, vp)[2]);
}
else
{
@ -232,17 +251,23 @@ JSBool JSI_GUIMouse::construct(JSContext* cx, JSObject* obj, uintN argc, jsval*
JS_SetProperty(cx, obj, "y", &zero);
JS_SetProperty(cx, obj, "buttons", &zero);
}
JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(obj));
return JS_TRUE;
}
JSBool JSI_GUIMouse::toString(JSContext* cx, JSObject* obj, uintN UNUSED(argc), jsval* UNUSED(argv), jsval* rval)
JSBool JSI_GUIMouse::toString(JSContext* cx, uintN argc, jsval* vp)
{
UNUSED2(argc);
int32 x, y, buttons;
if (!JS_ValueToECMAInt32(cx, g_ScriptingHost.GetObjectProperty(JS_THIS_OBJECT(cx, vp), "x"), &x)) return JS_FALSE;
if (!JS_ValueToECMAInt32(cx, g_ScriptingHost.GetObjectProperty(JS_THIS_OBJECT(cx, vp), "y"), &y)) return JS_FALSE;
if (!JS_ValueToECMAInt32(cx, g_ScriptingHost.GetObjectProperty(JS_THIS_OBJECT(cx, vp), "buttons"), &buttons)) return JS_FALSE;
char buffer[256];
snprintf(buffer, 256, "%d %d %d",
JSVAL_TO_INT(g_ScriptingHost.GetObjectProperty(obj, "x")),
JSVAL_TO_INT(g_ScriptingHost.GetObjectProperty(obj, "y")),
JSVAL_TO_INT(g_ScriptingHost.GetObjectProperty(obj, "buttons")) );
*rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, buffer));
snprintf(buffer, 256, "%d %d %d", x, y, buttons);
JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(JS_NewStringCopyZ(cx, buffer)));
return JS_TRUE;
}

View File

@ -26,8 +26,8 @@
extern JSClass JSI_class; \
extern JSPropertySpec JSI_props[]; \
extern JSFunctionSpec JSI_methods[]; \
JSBool construct( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval ); \
JSBool toString( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval ); \
JSBool construct(JSContext* cx, uintN argc, jsval* vp); \
JSBool toString(JSContext* cx, uintN argc, jsval* vp); \
}
GUISTDTYPE(Size)

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2009 Wildfire Games.
/* Copyright (C) 2010 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -28,7 +28,7 @@
#include "ps/CLogger.h"
#include "ps/StringConvert.h"
#include "scriptinterface/ScriptInterface.h"
JSClass JSI_IGUIObject::JSI_class = {
"GUIObject", JSCLASS_HAS_PRIVATE,
@ -46,15 +46,25 @@ JSPropertySpec JSI_IGUIObject::JSI_props[] =
JSFunctionSpec JSI_IGUIObject::JSI_methods[] =
{
{ "toString", JSI_IGUIObject::toString, 0, 0, 0 },
{ "focus", JSI_IGUIObject::focus, 0, 0, 0 },
{ "blur", JSI_IGUIObject::blur, 0, 0, 0 },
{ "toString", JSI_IGUIObject::toString, 0, 0 },
{ "focus", JSI_IGUIObject::focus, 0, 0 },
{ "blur", JSI_IGUIObject::blur, 0, 0 },
{ 0 }
};
JSBool JSI_IGUIObject::getProperty(JSContext* cx, JSObject* obj, jsval id, jsval* vp)
JSBool JSI_IGUIObject::getProperty(JSContext* cx, JSObject* obj, jsid id, jsval* vp)
{
CStr propName = JS_GetStringBytes(JS_ValueToString(cx, id));
IGUIObject* e = (IGUIObject*)JS_GetInstancePrivate(cx, obj, &JSI_IGUIObject::JSI_class, NULL);
if (!e)
return JS_FALSE;
jsval idval;
if (!JS_IdToValue(cx, id, &idval))
return JS_FALSE;
std::string propName;
if (!ScriptInterface::FromJSVal(cx, idval, propName))
return JS_FALSE;
// Skip some things which are known to be functions rather than properties.
// ("constructor" *must* be here, else it'll try to GetSettingType before
@ -69,10 +79,8 @@ JSBool JSI_IGUIObject::getProperty(JSContext* cx, JSObject* obj, jsval id, jsval
)
return JS_TRUE;
IGUIObject* e = (IGUIObject*)JS_GetPrivate(cx, obj);
// Use onWhatever to access event handlers
if (propName.Left(2) == "on")
if (propName.substr(0, 2) == "on")
{
CStr eventName (CStr(propName.substr(2)).LowerCase());
std::map<CStr, JSObject**>::iterator it = e->m_ScriptHandlers.find(eventName);
@ -143,8 +151,7 @@ JSBool JSI_IGUIObject::getProperty(JSContext* cx, JSObject* obj, jsval id, jsval
float value;
GUI<float>::GetSetting(e, propName, value);
// Create a garbage-collectable double
*vp = DOUBLE_TO_JSVAL(JS_NewDouble(cx, value) );
break;
return JS_NewNumberValue(cx, value, vp);
}
case GUIST_CColor:
@ -154,8 +161,9 @@ JSBool JSI_IGUIObject::getProperty(JSContext* cx, JSObject* obj, jsval id, jsval
JSObject* obj = JS_NewObject(cx, &JSI_GUIColor::JSI_class, NULL, NULL);
*vp = OBJECT_TO_JSVAL(obj); // root it
jsval c;
// Attempt to minimise ugliness through macrosity
#define P(x) jsval x = DOUBLE_TO_JSVAL(JS_NewDouble(cx, colour.x)); JS_SetProperty(cx, obj, #x, &x)
#define P(x) if (!JS_NewNumberValue(cx, colour.x, &c)) return JS_FALSE; JS_SetProperty(cx, obj, #x, &c)
P(r);
P(g);
P(b);
@ -197,8 +205,7 @@ JSBool JSI_IGUIObject::getProperty(JSContext* cx, JSObject* obj, jsval id, jsval
{
CGUIString value;
GUI<CGUIString>::GetSetting(e, propName, value);
JSString* s = StringConvert::wchars_to_jsstring(cx, value.GetRawString().c_str());
*vp = STRING_TO_JSVAL(s);
*vp = ScriptInterface::ToJSVal(cx, value.GetRawString());
break;
}
@ -206,7 +213,7 @@ JSBool JSI_IGUIObject::getProperty(JSContext* cx, JSObject* obj, jsval id, jsval
{
CStr value;
GUI<CStr>::GetSetting(e, propName, value);
*vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, value));
*vp = ScriptInterface::ToJSVal(cx, value);
break;
}
@ -214,7 +221,7 @@ JSBool JSI_IGUIObject::getProperty(JSContext* cx, JSObject* obj, jsval id, jsval
{
CStrW value;
GUI<CStrW>::GetSetting(e, propName, value);
*vp = STRING_TO_JSVAL(JS_NewUCStringCopyZ(cx, value.utf16().c_str()));
*vp = ScriptInterface::ToJSVal(cx, value);
break;
}
@ -222,7 +229,7 @@ JSBool JSI_IGUIObject::getProperty(JSContext* cx, JSObject* obj, jsval id, jsval
{
CGUISpriteInstance *value;
GUI<CGUISpriteInstance>::GetSettingPointer(e, propName, value);
*vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, value->GetName()));
*vp = ScriptInterface::ToJSVal(cx, value->GetName());
break;
}
@ -238,7 +245,7 @@ JSBool JSI_IGUIObject::getProperty(JSContext* cx, JSObject* obj, jsval id, jsval
case EAlign_Center: word = "center"; break;
default: debug_warn(L"Invalid EAlign!"); word = "error"; break;
}
*vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, word));
*vp = ScriptInterface::ToJSVal(cx, word);
break;
}
@ -254,7 +261,7 @@ JSBool JSI_IGUIObject::getProperty(JSContext* cx, JSObject* obj, jsval id, jsval
case EVAlign_Center: word = "center"; break;
default: debug_warn(L"Invalid EVAlign!"); word = "error"; break;
}
*vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, word));
*vp = ScriptInterface::ToJSVal(cx, word);
break;
}
@ -268,8 +275,7 @@ JSBool JSI_IGUIObject::getProperty(JSContext* cx, JSObject* obj, jsval id, jsval
for (size_t i = 0; i < value.m_Items.size(); ++i)
{
JSString* s = StringConvert::wchars_to_jsstring(cx, value.m_Items[i].GetRawString().c_str());
jsval val = STRING_TO_JSVAL(s);
jsval val = ScriptInterface::ToJSVal(cx, value.m_Items[i].GetRawString());
JS_SetElement(cx, obj, (jsint)i, &val);
}
@ -286,20 +292,31 @@ JSBool JSI_IGUIObject::getProperty(JSContext* cx, JSObject* obj, jsval id, jsval
}
}
JSBool JSI_IGUIObject::setProperty(JSContext* cx, JSObject* obj, jsval id, jsval* vp)
JSBool JSI_IGUIObject::setProperty(JSContext* cx, JSObject* obj, jsid id, jsval* vp)
{
IGUIObject* e = (IGUIObject*)JS_GetPrivate(cx, obj);
CStr propName = g_ScriptingHost.ValueToString(id);
IGUIObject* e = (IGUIObject*)JS_GetInstancePrivate(cx, obj, &JSI_IGUIObject::JSI_class, NULL);
if (!e)
return JS_FALSE;
jsval idval;
if (!JS_IdToValue(cx, id, &idval))
return JS_FALSE;
std::string propName;
if (!ScriptInterface::FromJSVal(cx, idval, propName))
return JS_FALSE;
if (propName == "name")
{
CStr propValue = JS_GetStringBytes(JS_ValueToString(cx, *vp));
e->SetName(propValue);
std::string value;
if (!ScriptInterface::FromJSVal(cx, *vp, value))
return JS_FALSE;
e->SetName(value);
return JS_TRUE;
}
// Use onWhatever to set event handlers
if (propName.Left(2) == "on")
if (propName.substr(0, 2) == "on")
{
if (!JSVAL_IS_OBJECT(*vp) || !JS_ObjectIsFunction(cx, JSVAL_TO_OBJECT(*vp)))
{
@ -326,29 +343,39 @@ JSBool JSI_IGUIObject::setProperty(JSContext* cx, JSObject* obj, jsval id, jsval
case GUIST_CStr:
{
CStr value (JS_GetStringBytes(JS_ValueToString(cx, *vp)));
std::string value;
if (!ScriptInterface::FromJSVal(cx, *vp, value))
return JS_FALSE;
GUI<CStr>::SetSetting(e, propName, value);
break;
}
case GUIST_CStrW:
{
utf16string value (JS_GetStringChars(JS_ValueToString(cx, *vp)));
std::wstring value;
if (!ScriptInterface::FromJSVal(cx, *vp, value))
return JS_FALSE;
GUI<CStrW>::SetSetting(e, propName, value);
break;
}
case GUIST_CGUISpriteInstance:
{
CStr value (JS_GetStringBytes(JS_ValueToString(cx, *vp)));
GUI<CGUISpriteInstance>::SetSetting(e, propName, value);
std::string value;
if (!ScriptInterface::FromJSVal(cx, *vp, value))
return JS_FALSE;
GUI<CGUISpriteInstance>::SetSetting(e, propName, CGUISpriteInstance(value));
break;
}
case GUIST_CGUIString:
{
std::wstring value;
StringConvert::jsstring_to_wstring(JS_ValueToString(cx, *vp), value);
if (!ScriptInterface::FromJSVal(cx, *vp, value))
return JS_FALSE;
CGUIString str;
str.SetValue(value);
@ -358,7 +385,10 @@ JSBool JSI_IGUIObject::setProperty(JSContext* cx, JSObject* obj, jsval id, jsval
case GUIST_EAlign:
{
CStr value (JS_GetStringBytes(JS_ValueToString(cx, *vp)));
std::string value;
if (!ScriptInterface::FromJSVal(cx, *vp, value))
return JS_FALSE;
EAlign a;
if (value == "left") a = EAlign_Left;
else if (value == "right") a = EAlign_Right;
@ -374,7 +404,10 @@ JSBool JSI_IGUIObject::setProperty(JSContext* cx, JSObject* obj, jsval id, jsval
case GUIST_EVAlign:
{
CStr value (JS_GetStringBytes(JS_ValueToString(cx, *vp)));
std::string value;
if (!ScriptInterface::FromJSVal(cx, *vp, value))
return JS_FALSE;
EVAlign a;
if (value == "top") a = EVAlign_Top;
else if (value == "bottom") a = EVAlign_Bottom;
@ -432,7 +465,8 @@ JSBool JSI_IGUIObject::setProperty(JSContext* cx, JSObject* obj, jsval id, jsval
if (JSVAL_IS_STRING(*vp))
{
std::wstring value;
StringConvert::jsstring_to_wstring(JS_ValueToString(cx, *vp), value);
if (!ScriptInterface::FromJSVal(cx, *vp, value))
return JS_FALSE;
if (e->SetSetting(propName, value) != PSRETURN_OK)
{
@ -472,7 +506,8 @@ JSBool JSI_IGUIObject::setProperty(JSContext* cx, JSObject* obj, jsval id, jsval
if (JSVAL_IS_STRING(*vp))
{
std::wstring value;
StringConvert::jsstring_to_wstring(JS_ValueToString(cx, *vp), value);
if (!ScriptInterface::FromJSVal(cx, *vp, value))
return JS_FALSE;
if (e->SetSetting(propName, value) != PSRETURN_OK)
{
@ -519,8 +554,8 @@ JSBool JSI_IGUIObject::setProperty(JSContext* cx, JSObject* obj, jsval id, jsval
}
std::wstring value;
JSString* string = JS_ValueToString(cx, element);
StringConvert::jsstring_to_wstring(string, value);
if (!ScriptInterface::FromJSVal(cx, element, value))
return JS_FALSE;
CGUIString str;
str.SetValue(value);
@ -549,7 +584,7 @@ JSBool JSI_IGUIObject::setProperty(JSContext* cx, JSObject* obj, jsval id, jsval
}
JSBool JSI_IGUIObject::construct(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* UNUSED(rval))
JSBool JSI_IGUIObject::construct(JSContext* cx, uintN argc, jsval* vp)
{
if (argc == 0)
{
@ -557,12 +592,13 @@ JSBool JSI_IGUIObject::construct(JSContext* cx, JSObject* obj, uintN argc, jsval
return JS_FALSE;
}
debug_assert(argc == 1);
JSObject* obj = JS_NewObject(cx, &JSI_IGUIObject::JSI_class, NULL, NULL);
// Store the IGUIObject in the JS object's 'private' area
IGUIObject* guiObject = (IGUIObject*)JSVAL_TO_PRIVATE(argv[0]);
IGUIObject* guiObject = (IGUIObject*)JSVAL_TO_PRIVATE(JS_ARGV(cx, vp)[0]);
JS_SetPrivate(cx, obj, guiObject);
JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(obj));
return JS_TRUE;
}
@ -571,29 +607,45 @@ void JSI_IGUIObject::init()
g_ScriptingHost.DefineCustomObjectType(&JSI_class, construct, 1, JSI_props, JSI_methods, NULL, NULL);
}
JSBool JSI_IGUIObject::toString(JSContext* cx, JSObject* obj, uintN UNUSED(argc), jsval* UNUSED(argv), jsval* rval)
JSBool JSI_IGUIObject::toString(JSContext* cx, uintN argc, jsval* vp)
{
IGUIObject* e = (IGUIObject*)JS_GetPrivate( cx, obj );
UNUSED2(argc);
IGUIObject* e = (IGUIObject*)JS_GetInstancePrivate(cx, JS_THIS_OBJECT(cx, vp), &JSI_IGUIObject::JSI_class, NULL);
if (!e)
return JS_FALSE;
char buffer[256];
snprintf(buffer, 256, "[GUIObject: %s]", e->GetName().c_str());
buffer[255] = 0;
*rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, buffer));
JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(JS_NewStringCopyZ(cx, buffer)));
return JS_TRUE;
}
JSBool JSI_IGUIObject::focus(JSContext* cx, JSObject* obj, uintN UNUSED(argc), jsval* UNUSED(argv), jsval* UNUSED(rval))
JSBool JSI_IGUIObject::focus(JSContext* cx, uintN argc, jsval* vp)
{
IGUIObject* e = (IGUIObject*)JS_GetPrivate( cx, obj );
UNUSED2(argc);
IGUIObject* e = (IGUIObject*)JS_GetInstancePrivate(cx, JS_THIS_OBJECT(cx, vp), &JSI_IGUIObject::JSI_class, NULL);
if (!e)
return JS_FALSE;
e->GetGUI()->SetFocusedObject(e);
JS_SET_RVAL(cx, vp, JSVAL_VOID);
return JS_TRUE;
}
JSBool JSI_IGUIObject::blur(JSContext* cx, JSObject* obj, uintN UNUSED(argc), jsval* UNUSED(argv), jsval* UNUSED(rval))
JSBool JSI_IGUIObject::blur(JSContext* cx, uintN argc, jsval* vp)
{
IGUIObject* e = (IGUIObject*)JS_GetPrivate( cx, obj );
UNUSED2(argc);
IGUIObject* e = (IGUIObject*)JS_GetInstancePrivate(cx, JS_THIS_OBJECT(cx, vp), &JSI_IGUIObject::JSI_class, NULL);
if (!e)
return JS_FALSE;
e->GetGUI()->SetFocusedObject(NULL);
JS_SET_RVAL(cx, vp, JSVAL_VOID);
return JS_TRUE;
}

View File

@ -25,14 +25,12 @@ namespace JSI_IGUIObject
extern JSClass JSI_class;
extern JSPropertySpec JSI_props[];
extern JSFunctionSpec JSI_methods[];
JSBool addProperty(JSContext* cx, JSObject* obj, jsval id, jsval* vp);
JSBool delProperty(JSContext* cx, JSObject* obj, jsval id, jsval* vp);
JSBool getProperty(JSContext* cx, JSObject* obj, jsval id, jsval* vp);
JSBool setProperty(JSContext* cx, JSObject* obj, jsval id, jsval* vp);
JSBool construct(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval);
JSBool toString(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval);
JSBool focus(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval);
JSBool blur(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval);
JSBool getProperty(JSContext* cx, JSObject* obj, jsid id, jsval* vp);
JSBool setProperty(JSContext* cx, JSObject* obj, jsid id, jsval* vp);
JSBool construct(JSContext* cx, uintN argc, jsval* vp);
JSBool toString(JSContext* cx, uintN argc, jsval* vp);
JSBool focus(JSContext* cx, uintN argc, jsval* vp);
JSBool blur(JSContext* cx, uintN argc, jsval* vp);
void init();
}

View File

@ -34,7 +34,7 @@
// <inttypes.h>
//
typedef signed char int8_t;
typedef __int8 int8_t;
typedef short int16_t;
// already defined by MinGW

View File

@ -21,11 +21,6 @@
#include "scripting/JSConversions.h"
#include "scripting/ScriptingHost.h"
namespace JSI_Vector3D
{
static CVector3D* GetVector( JSContext* cx, JSObject* obj );
}
JSClass JSI_Vector3D::JSI_class = {
"Vector3D", JSCLASS_HAS_PRIVATE,
JS_PropertyStub, JS_PropertyStub,
@ -45,24 +40,13 @@ JSPropertySpec JSI_Vector3D::JSI_props[] =
JSFunctionSpec JSI_Vector3D::JSI_methods[] =
{
{ "toString", JSI_Vector3D::toString, 0, 0, 0 },
{ "add", JSI_Vector3D::add, 1, 0, 0 },
{ "subtract", JSI_Vector3D::subtract, 1, 0, 0 },
{ "minus", JSI_Vector3D::subtract, 1, 0, 0 },
{ "negate", JSI_Vector3D::negate, 1, 0, 0 },
{ "scale", JSI_Vector3D::scale, 1, 0, 0 },
{ "multiply", JSI_Vector3D::scale, 1, 0, 0 },
{ "divide", JSI_Vector3D::divide, 1, 0, 0 },
{ "dot", JSI_Vector3D::dot, 1, 0, 0 },
{ "cross", JSI_Vector3D::cross, 1, 0, 0 },
{ "length", JSI_Vector3D::length, 0, 0, 0 },
{ "normalize", JSI_Vector3D::normalize, 0, 0, 0 },
{ "toString", JSI_Vector3D::toString, 0, 0 },
{ 0 }
};
void JSI_Vector3D::init()
{
g_ScriptingHost.DefineCustomObjectType( &JSI_class, JSI_Vector3D::construct, 0, JSI_props, JSI_methods, NULL, NULL );
g_ScriptingHost.DefineCustomObjectType(&JSI_class, JSI_Vector3D::construct, 0, JSI_props, JSI_methods, NULL, NULL);
}
JSI_Vector3D::Vector3D_Info::Vector3D_Info()
@ -71,19 +55,19 @@ JSI_Vector3D::Vector3D_Info::Vector3D_Info()
vector = new CVector3D();
}
JSI_Vector3D::Vector3D_Info::Vector3D_Info( float x, float y, float z )
JSI_Vector3D::Vector3D_Info::Vector3D_Info(float x, float y, float z)
{
owner = NULL;
vector = new CVector3D( x, y, z );
vector = new CVector3D(x, y, z);
}
JSI_Vector3D::Vector3D_Info::Vector3D_Info( const CVector3D& copy )
JSI_Vector3D::Vector3D_Info::Vector3D_Info(const CVector3D& copy)
{
owner = NULL;
vector = new CVector3D( copy.X, copy.Y, copy.Z );
vector = new CVector3D(copy.X, copy.Y, copy.Z);
}
JSI_Vector3D::Vector3D_Info::Vector3D_Info( CVector3D* attach, IPropertyOwner* _owner )
JSI_Vector3D::Vector3D_Info::Vector3D_Info(CVector3D* attach, IPropertyOwner* _owner)
{
owner = _owner;
updateFn = NULL;
@ -91,7 +75,7 @@ JSI_Vector3D::Vector3D_Info::Vector3D_Info( CVector3D* attach, IPropertyOwner* _
vector = attach;
}
JSI_Vector3D::Vector3D_Info::Vector3D_Info( CVector3D* attach, IPropertyOwner* _owner, void( IPropertyOwner::*_updateFn )(void) )
JSI_Vector3D::Vector3D_Info::Vector3D_Info(CVector3D* attach, IPropertyOwner* _owner, void(IPropertyOwner::*_updateFn)(void))
{
owner = _owner;
updateFn = _updateFn;
@ -99,7 +83,8 @@ JSI_Vector3D::Vector3D_Info::Vector3D_Info( CVector3D* attach, IPropertyOwner* _
vector = attach;
}
JSI_Vector3D::Vector3D_Info::Vector3D_Info( CVector3D* attach, IPropertyOwner* _owner, void( IPropertyOwner::*_updateFn )(void), void( IPropertyOwner::*_freshenFn )(void) )
JSI_Vector3D::Vector3D_Info::Vector3D_Info(CVector3D* attach, IPropertyOwner* _owner, void(IPropertyOwner::*_updateFn)(void),
void(IPropertyOwner::*_freshenFn)(void))
{
owner = _owner;
updateFn = _updateFn;
@ -109,245 +94,116 @@ JSI_Vector3D::Vector3D_Info::Vector3D_Info( CVector3D* attach, IPropertyOwner* _
JSI_Vector3D::Vector3D_Info::~Vector3D_Info()
{
if( !owner ) delete( vector );
if (!owner)
delete (vector);
}
JSBool JSI_Vector3D::getProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp )
JSBool JSI_Vector3D::getProperty(JSContext* cx, JSObject* obj, jsid id, jsval* vp)
{
if( !JSVAL_IS_INT( id ) )
return( JS_TRUE );
if (!JSID_IS_INT(id))
return JS_TRUE;
Vector3D_Info* vectorInfo = (Vector3D_Info*)JS_GetPrivate( cx, obj );
if( !vectorInfo )
{
JS_ReportError( cx, "[Vector3D] Invalid reference" );
return( JS_TRUE );
}
Vector3D_Info* vectorInfo = (Vector3D_Info*)JS_GetInstancePrivate(cx, obj, &JSI_Vector3D::JSI_class, NULL);
if (!vectorInfo)
return JS_FALSE;
CVector3D* vectorData = vectorInfo->vector;
if( vectorInfo->owner && vectorInfo->freshenFn ) ( (vectorInfo->owner)->*(vectorInfo->freshenFn) )();
switch( ToPrimitive<int>( id ) )
{
case component_x: *vp = DOUBLE_TO_JSVAL( JS_NewDouble( cx, vectorData->X ) ); return( JS_TRUE );
case component_y: *vp = DOUBLE_TO_JSVAL( JS_NewDouble( cx, vectorData->Y ) ); return( JS_TRUE );
case component_z: *vp = DOUBLE_TO_JSVAL( JS_NewDouble( cx, vectorData->Z ) ); return( JS_TRUE );
}
return( JS_FALSE );
}
JSBool JSI_Vector3D::setProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp )
{
if( !JSVAL_IS_INT( id ) )
return( JS_TRUE );
Vector3D_Info* vectorInfo = (Vector3D_Info*)JS_GetPrivate( cx, obj );
if( !vectorInfo )
{
JS_ReportError( cx, "[Vector3D] Invalid reference" );
return( JS_TRUE );
}
CVector3D* vectorData = vectorInfo->vector;
if( vectorInfo->owner && vectorInfo->freshenFn ) ( (vectorInfo->owner)->*(vectorInfo->freshenFn) )();
if (vectorInfo->owner && vectorInfo->freshenFn)
((vectorInfo->owner)->*(vectorInfo->freshenFn))();
switch( ToPrimitive<int>( id ) )
switch (JSID_TO_INT(id))
{
case component_x: vectorData->X = ToPrimitive<float>( *vp ); break;
case component_y: vectorData->Y = ToPrimitive<float>( *vp ); break;
case component_z: vectorData->Z = ToPrimitive<float>( *vp ); break;
case component_x:
return JS_NewNumberValue(cx, vectorData->X, vp);
case component_y:
return JS_NewNumberValue(cx, vectorData->Y, vp);
case component_z:
return JS_NewNumberValue(cx, vectorData->Z, vp);
}
if( vectorInfo->owner && vectorInfo->updateFn ) ( (vectorInfo->owner)->*(vectorInfo->updateFn) )();
return( JS_TRUE );
return JS_FALSE;
}
JSBool JSI_Vector3D::construct( JSContext* cx, JSObject* UNUSED(obj), uintN argc, jsval* argv, jsval* rval )
JSBool JSI_Vector3D::setProperty(JSContext* cx, JSObject* obj, jsid id, jsval* vp)
{
JSObject* vector = JS_NewObject( cx, &JSI_Vector3D::JSI_class, NULL, NULL );
if( argc == 0 )
if (!JSID_IS_INT(id))
return JS_TRUE;
Vector3D_Info* vectorInfo = (Vector3D_Info*)JS_GetInstancePrivate(cx, obj, &JSI_Vector3D::JSI_class, NULL);
if (!vectorInfo)
return JS_FALSE;
CVector3D* vectorData = vectorInfo->vector;
if (vectorInfo->owner && vectorInfo->freshenFn)
((vectorInfo->owner)->*(vectorInfo->freshenFn))();
switch (JSID_TO_INT(id))
{
JS_SetPrivate( cx, vector, new Vector3D_Info() );
*rval = OBJECT_TO_JSVAL( vector );
return( JS_TRUE );
case component_x:
vectorData->X = ToPrimitive<float> (*vp);
break;
case component_y:
vectorData->Y = ToPrimitive<float> (*vp);
break;
case component_z:
vectorData->Z = ToPrimitive<float> (*vp);
break;
}
if (vectorInfo->owner && vectorInfo->updateFn)
((vectorInfo->owner)->*(vectorInfo->updateFn))();
return JS_TRUE;
}
JSBool JSI_Vector3D::construct(JSContext* cx, uintN argc, jsval* vp)
{
JSObject* vector = JS_NewObject(cx, &JSI_Vector3D::JSI_class, NULL, NULL);
if (argc == 0)
{
JS_SetPrivate(cx, vector, new Vector3D_Info());
JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(vector));
return JS_TRUE;
}
JSU_REQUIRE_PARAMS(3);
try
{
float x = ToPrimitive<float>( argv[0] );
float y = ToPrimitive<float>( argv[1] );
float z = ToPrimitive<float>( argv[2] );
JS_SetPrivate( cx, vector, new Vector3D_Info( x, y, z ) );
*rval = OBJECT_TO_JSVAL( vector );
return( JS_TRUE );
float x = ToPrimitive<float> (JS_ARGV(cx, vp)[0]);
float y = ToPrimitive<float> (JS_ARGV(cx, vp)[1]);
float z = ToPrimitive<float> (JS_ARGV(cx, vp)[2]);
JS_SetPrivate(cx, vector, new Vector3D_Info(x, y, z));
JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(vector));
return JS_TRUE;
}
catch (PSERROR_Scripting_ConversionFailed)
{
// Invalid input (i.e. can't be coerced into doubles) - fail
JS_ReportError( cx, "Invalid parameters to Vector3D constructor" );
*rval = JSVAL_NULL;
return( JS_FALSE );
JS_ReportError(cx, "Invalid parameters to Vector3D constructor");
return JS_FALSE;
}
}
void JSI_Vector3D::finalize( JSContext* cx, JSObject* obj )
void JSI_Vector3D::finalize(JSContext* cx, JSObject* obj)
{
delete( (Vector3D_Info*)JS_GetPrivate( cx, obj ) );
delete ((Vector3D_Info*)JS_GetPrivate(cx, obj));
}
JSBool JSI_Vector3D::toString( JSContext* cx, JSObject* obj,
uintN UNUSED(argc), jsval* UNUSED(argv), jsval* rval )
JSBool JSI_Vector3D::toString(JSContext* cx, uintN UNUSED(argc), jsval* vp)
{
char buffer[256];
Vector3D_Info* vectorInfo = (Vector3D_Info*)JS_GetPrivate( cx, obj );
Vector3D_Info* vectorInfo = (Vector3D_Info*)JS_GetInstancePrivate(cx, JS_THIS_OBJECT(cx, vp), &JSI_Vector3D::JSI_class, NULL);
if (!vectorInfo)
return JS_FALSE;
if( !vectorInfo ) return( JS_TRUE );
if (vectorInfo->owner && vectorInfo->freshenFn)
((vectorInfo->owner)->*(vectorInfo->freshenFn))();
if( vectorInfo->owner && vectorInfo->freshenFn ) ( (vectorInfo->owner)->*(vectorInfo->freshenFn) )();
CVector3D* vectorData = vectorInfo->vector;
sprintf_s( buffer, ARRAY_SIZE(buffer), "[object Vector3D: ( %f, %f, %f )]", vectorData->X, vectorData->Y, vectorData->Z );
*rval = STRING_TO_JSVAL( JS_NewStringCopyZ( cx, buffer ) );
return( JS_TRUE );
}
CVector3D* JSI_Vector3D::GetVector( JSContext* cx, JSObject* obj )
{
Vector3D_Info* vectorInfo = (Vector3D_Info*)JS_GetInstancePrivate( cx, obj, &JSI_class, NULL );
if( !vectorInfo )
{
JS_ReportError( cx, "[Vector3D] Invalid reference" );
return( NULL );
}
if( vectorInfo->owner && vectorInfo->freshenFn ) ( (vectorInfo->owner)->*(vectorInfo->freshenFn) )();
return( vectorInfo->vector );
}
#define GET_VECTORS\
CVector3D* a = GetVector( cx, obj );\
if(!a)\
return( JS_TRUE );\
if( ( argc == 0 ) || !JSVAL_IS_OBJECT( argv[0] ) )\
{\
invalid_param:\
JS_ReportError( cx, "[Vector3D] Invalid parameter" );\
return( JS_TRUE );\
}\
CVector3D* b = GetVector( cx, JSVAL_TO_OBJECT( argv[0] ) );\
if(!b)\
goto invalid_param;
#define GET_VECTOR_AND_FLOAT\
CVector3D* v = GetVector( cx, obj );\
if(!v)\
return( JS_TRUE );\
float f;\
if( ( argc == 0 ) || !ToPrimitive( cx, argv[0], f ) )\
{\
JS_ReportError( cx, "Invalid parameter" );\
return( JS_TRUE );\
}
JSBool JSI_Vector3D::add( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval )
{
GET_VECTORS;
JSObject* vector3d = JS_NewObject( g_ScriptingHost.getContext(), &JSI_Vector3D::JSI_class, NULL, NULL );
JS_SetPrivate( g_ScriptingHost.getContext(), vector3d, new JSI_Vector3D::Vector3D_Info( *a + *b ) );
*rval = OBJECT_TO_JSVAL( vector3d );
return( JS_TRUE );
}
JSBool JSI_Vector3D::subtract( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval )
{
GET_VECTORS;
JSObject* vector3d = JS_NewObject( g_ScriptingHost.getContext(), &JSI_Vector3D::JSI_class, NULL, NULL );
JS_SetPrivate( g_ScriptingHost.getContext(), vector3d, new JSI_Vector3D::Vector3D_Info( *a - *b ) );
*rval = OBJECT_TO_JSVAL( vector3d );
return( JS_TRUE );
}
JSBool JSI_Vector3D::negate( JSContext* cx, JSObject* obj,
uintN UNUSED(argc), jsval* UNUSED(argv), jsval* rval )
{
CVector3D* v = GetVector( cx, obj );
if(!v)
return( JS_TRUE );
*rval = ToJSVal( -( *v ) );
return( JS_TRUE );
}
JSBool JSI_Vector3D::scale( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval )
{
GET_VECTOR_AND_FLOAT;
JSObject* vector3d = JS_NewObject( g_ScriptingHost.getContext(), &JSI_Vector3D::JSI_class, NULL, NULL );
JS_SetPrivate( g_ScriptingHost.getContext(), vector3d, new JSI_Vector3D::Vector3D_Info( *v * f ) );
*rval = OBJECT_TO_JSVAL( vector3d );
return( JS_TRUE );
}
JSBool JSI_Vector3D::divide( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval )
{
GET_VECTOR_AND_FLOAT;
JSObject* vector3d = JS_NewObject( g_ScriptingHost.getContext(), &JSI_Vector3D::JSI_class, NULL, NULL );
JS_SetPrivate( g_ScriptingHost.getContext(), vector3d, new JSI_Vector3D::Vector3D_Info( *v * ( 1.0f / f ) ) );
*rval = OBJECT_TO_JSVAL( vector3d );
return( JS_TRUE );
}
JSBool JSI_Vector3D::dot( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval )
{
GET_VECTORS;
*rval = ToJSVal( a->Dot( *b ) );
return( JS_TRUE );
}
JSBool JSI_Vector3D::cross( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval )
{
GET_VECTORS;
*rval = ToJSVal( a->Cross( *b ) );
return( JS_TRUE );
}
JSBool JSI_Vector3D::length( JSContext* cx, JSObject* obj,
uintN UNUSED(argc), jsval* UNUSED(argv), jsval* rval )
{
CVector3D* v = GetVector( cx, obj );
if(!v)
return( JS_TRUE );
*rval = ToJSVal( v->Length() );
return( JS_TRUE );
}
JSBool JSI_Vector3D::normalize( JSContext* cx, JSObject* obj,
uintN UNUSED(argc), jsval* UNUSED(argv), jsval* rval )
{
CVector3D* v = GetVector( cx, obj );
if(!v)
return( JS_TRUE );
CVector3D r( v->X, v->Y, v->Z );
r.Normalize();
*rval = ToJSVal( r );
return( JS_TRUE );
CVector3D* vectorData = vectorInfo->vector;
sprintf_s(buffer, ARRAY_SIZE(buffer), "[object Vector3D: ( %f, %f, %f )]", vectorData->X, vectorData->Y, vectorData->Z);
JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(JS_NewStringCopyZ(cx, buffer)));
return JS_TRUE;
}

View File

@ -36,42 +36,31 @@ namespace JSI_Vector3D
component_y,
component_z
};
JSBool toString( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
JSBool add( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
JSBool subtract( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
JSBool negate( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
JSBool scale( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
JSBool divide( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
JSBool dot( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
JSBool cross( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
JSBool length( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
JSBool normalize( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
JSBool toString(JSContext* cx, uintN argc, jsval* vp);
struct Vector3D_Info
{
IPropertyOwner* owner;
void ( IPropertyOwner::*updateFn )();
void ( IPropertyOwner::*freshenFn )();
void (IPropertyOwner::*updateFn)();
void (IPropertyOwner::*freshenFn)();
CVector3D* vector;
Vector3D_Info();
Vector3D_Info( float x, float y, float z );
Vector3D_Info( const CVector3D& copy );
Vector3D_Info( CVector3D* attach, IPropertyOwner* _owner );
Vector3D_Info( CVector3D* attach, IPropertyOwner* _owner, void (IPropertyOwner::*_updateFn)(void) );
Vector3D_Info( CVector3D* attach, IPropertyOwner* _owner, void (IPropertyOwner::*_updateFn)(void), void (IPropertyOwner::*_freshenFn)(void) );
Vector3D_Info(float x, float y, float z);
Vector3D_Info(const CVector3D& copy);
Vector3D_Info(CVector3D* attach, IPropertyOwner* _owner);
Vector3D_Info(CVector3D* attach, IPropertyOwner* _owner, void(IPropertyOwner::*_updateFn)(void));
Vector3D_Info(CVector3D* attach, IPropertyOwner* _owner, void(IPropertyOwner::*_updateFn)(void), void(IPropertyOwner::*_freshenFn)(void));
~Vector3D_Info();
};
extern JSClass JSI_class;
extern JSPropertySpec JSI_props[];
extern JSFunctionSpec JSI_methods[];
JSBool getProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp );
JSBool setProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp );
void finalize( JSContext* cx, JSObject* obj );
JSBool construct( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
void init();
JSBool getProperty(JSContext* cx, JSObject* obj, jsid id, jsval* vp);
JSBool setProperty(JSContext* cx, JSObject* obj, jsid id, jsval* vp);
void finalize(JSContext* cx, JSObject* obj);
JSBool construct(JSContext* cx, uintN argc, jsval* vp);
void init();
}
#endif

View File

@ -24,6 +24,8 @@
#include "Filesystem.h"
#include "scripting/ScriptingHost.h"
#include "scriptinterface/ScriptInterface.h"
#include <boost/algorithm/string.hpp>
typedef std::map <CStr, CConfigValueSet> TConfigMap;
@ -35,38 +37,49 @@ bool CConfigDB::m_UseVFS[CFG_LAST];
namespace ConfigNamespace_JS
{
JSBool GetProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp )
JSBool GetProperty(JSContext* cx, JSObject* obj, jsid id, jsval* vp)
{
EConfigNamespace cfgNs = GET_NS_PRIVATE(cx, obj);
if (cfgNs < 0 || cfgNs >= CFG_LAST)
return JS_FALSE;
CStr propName = g_ScriptingHost.ValueToString(id);
CConfigValue *val=g_ConfigDB.GetValue(cfgNs, propName);
jsval idval;
if (!JS_IdToValue(cx, id, &idval))
return JS_FALSE;
std::string propName;
if (!ScriptInterface::FromJSVal(cx, idval, propName))
return JS_FALSE;
CConfigValue *val = g_ConfigDB.GetValue(cfgNs, propName);
if (val)
{
JSString *js_str=JS_NewStringCopyN(cx, val->m_String.c_str(), val->m_String.size());
JSString *js_str = JS_NewStringCopyN(cx, val->m_String.c_str(), val->m_String.size());
*vp = STRING_TO_JSVAL(js_str);
}
return JS_TRUE;
}
JSBool SetProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp )
JSBool SetProperty(JSContext* cx, JSObject* obj, jsid id, jsval* vp)
{
EConfigNamespace cfgNs = GET_NS_PRIVATE(cx, obj);
if (cfgNs < 0 || cfgNs >= CFG_LAST)
return JS_FALSE;
CStr propName = g_ScriptingHost.ValueToString(id);
CConfigValue *val=g_ConfigDB.CreateValue(cfgNs, propName);
char *str;
if (JS_ConvertArguments(cx, 1, vp, "s", &str))
{
val->m_String=str;
return JS_TRUE;
}
else
jsval idval;
if (!JS_IdToValue(cx, id, &idval))
return JS_FALSE;
std::string propName;
if (!ScriptInterface::FromJSVal(cx, idval, propName))
return JS_FALSE;
CConfigValue *val = g_ConfigDB.CreateValue(cfgNs, propName);
if (!ScriptInterface::FromJSVal(cx, *vp, val->m_String))
return JS_FALSE;
return JS_TRUE;
}
JSClass Class = {
@ -77,13 +90,12 @@ namespace ConfigNamespace_JS
JS_ConvertStub, JS_FinalizeStub
};
JSBool Construct( JSContext* cx, JSObject* obj, uintN argc, jsval* UNUSED(argv), jsval* rval )
JSBool Construct(JSContext* cx, uintN argc, jsval* vp)
{
if (argc != 0)
return JS_FALSE;
UNUSED2(argc);
JSObject *newObj=JS_NewObject(cx, &Class, NULL, obj);
*rval=OBJECT_TO_JSVAL(newObj);
JSObject *newObj = JS_NewObject(cx, &Class, NULL, NULL);
JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(newObj));
return JS_TRUE;
}
@ -92,65 +104,70 @@ namespace ConfigNamespace_JS
JS_SetPrivate(cx, obj, (void *)((uintptr_t)cfgNs << 1)); // JS requires bottom bit = 0
}
JSBool WriteFile( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval )
JSBool WriteFile(JSContext* cx, uintN argc, jsval* vp)
{
EConfigNamespace cfgNs = GET_NS_PRIVATE(cx, obj);
EConfigNamespace cfgNs = GET_NS_PRIVATE(cx, JS_THIS_OBJECT(cx, vp));
if (cfgNs < 0 || cfgNs >= CFG_LAST)
return JS_FALSE;
if (argc != 2)
return JS_FALSE;
JSBool useVFS;
char *path;
if (JS_ConvertArguments(cx, 2, argv, "bs", &useVFS, &path))
{
JSBool res=g_ConfigDB.WriteFile(cfgNs, useVFS?true:false, CStrW(path));
*rval = BOOLEAN_TO_JSVAL(res);
return JS_TRUE;
}
else
return JS_FALSE;
}
JSBool Reload( JSContext* cx, JSObject* obj, uintN argc, jsval* UNUSED(argv), jsval* rval )
{
if (argc != 0)
bool useVFS;
if (!ScriptInterface::FromJSVal(cx, JS_ARGV(cx, vp)[0], useVFS))
return JS_FALSE;
EConfigNamespace cfgNs = GET_NS_PRIVATE(cx, obj);
if (cfgNs < 0 || cfgNs >= CFG_LAST)
std::wstring path;
if (!ScriptInterface::FromJSVal(cx, JS_ARGV(cx, vp)[1], path))
return JS_FALSE;
JSBool ret=g_ConfigDB.Reload(cfgNs);
*rval = BOOLEAN_TO_JSVAL(ret);
bool res = g_ConfigDB.WriteFile(cfgNs, useVFS, path);
JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(res));
return JS_TRUE;
}
JSBool SetFile( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* UNUSED(rval) )
JSBool Reload(JSContext* cx, uintN argc, jsval* vp)
{
if (argc != 0)
return JS_FALSE;
EConfigNamespace cfgNs = GET_NS_PRIVATE(cx, obj);
EConfigNamespace cfgNs = GET_NS_PRIVATE(cx, JS_THIS_OBJECT(cx, vp));
if (cfgNs < 0 || cfgNs >= CFG_LAST)
return JS_FALSE;
JSBool useVFS;
char *path;
if (JS_ConvertArguments(cx, 2, argv, "bs", &useVFS, &path))
{
g_ConfigDB.SetConfigFile(cfgNs, useVFS?true:false, CStrW(path));
return JS_TRUE;
}
else
JSBool ret = g_ConfigDB.Reload(cfgNs);
JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(ret));
return JS_TRUE;
}
JSBool SetFile(JSContext* cx, uintN argc, jsval* vp)
{
EConfigNamespace cfgNs = GET_NS_PRIVATE(cx, JS_THIS_OBJECT(cx, vp));
if (cfgNs < 0 || cfgNs >= CFG_LAST)
return JS_FALSE;
if (argc != 2)
return JS_FALSE;
bool useVFS;
if (!ScriptInterface::FromJSVal(cx, JS_ARGV(cx, vp)[0], useVFS))
return JS_FALSE;
std::wstring path;
if (!ScriptInterface::FromJSVal(cx, JS_ARGV(cx, vp)[1], path))
return JS_FALSE;
g_ConfigDB.SetConfigFile(cfgNs, useVFS, path);
JS_SET_RVAL(cx, vp, JSVAL_VOID);
return JS_TRUE;
}
JSFunctionSpec Funcs[] = {
{ "writeFile", WriteFile, 2, 0, 0},
{ "reload", Reload, 0, 0, 0},
{ "setFile", SetFile, 2, 0, 0},
{ "writeFile", WriteFile, 2, 0 },
{ "reload", Reload, 0, 0 },
{ "setFile", SetFile, 2, 0 },
{0}
};
};
@ -173,13 +190,12 @@ namespace ConfigDB_JS
{0}
};
JSBool Construct( JSContext* cx, JSObject* obj, uintN argc, jsval* UNUSED(argv), jsval* rval )
JSBool Construct(JSContext* cx, uintN argc, jsval* vp)
{
if (argc != 0)
return JS_FALSE;
UNUSED2(argc);
JSObject *newObj=JS_NewObject(cx, &Class, NULL, obj);
*rval=OBJECT_TO_JSVAL(newObj);
JSObject *newObj = JS_NewObject(cx, &Class, NULL, NULL);
JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(newObj));
int flags=JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT;
#define cfg_ns(_propname, _enum) STMT (\
@ -204,15 +220,16 @@ CConfigDB::CConfigDB()
{
g_ScriptingHost.DefineCustomObjectType(&ConfigDB_JS::Class, ConfigDB_JS::Construct, 0, ConfigDB_JS::Props, ConfigDB_JS::Funcs, NULL, NULL);
g_ScriptingHost.DefineCustomObjectType(&ConfigNamespace_JS::Class, ConfigNamespace_JS::Construct, 0, NULL, ConfigNamespace_JS::Funcs, NULL, NULL);
JSObject *js_ConfigDB=g_ScriptingHost.CreateCustomObject("ConfigDB");
JSObject *js_ConfigDB = g_ScriptingHost.CreateCustomObject("ConfigDB");
g_ScriptingHost.SetGlobal("g_ConfigDB", OBJECT_TO_JSVAL(js_ConfigDB));
}
CConfigValue *CConfigDB::GetValue(EConfigNamespace ns, const CStr& name)
{
CConfigValueSet* values = GetValues( ns, name );
if( !values ) return( NULL );
return &( (*values)[0] );
CConfigValueSet* values = GetValues(ns, name);
if (!values)
return (NULL);
return &((*values)[0]);
}
CConfigValueSet *CConfigDB::GetValues(EConfigNamespace ns, const CStr& name)
@ -223,18 +240,18 @@ CConfigValueSet *CConfigDB::GetValues(EConfigNamespace ns, const CStr& name)
return NULL;
}
TConfigMap::iterator it = m_Map[CFG_COMMAND].find( name );
if( it != m_Map[CFG_COMMAND].end() )
return &( it->second );
TConfigMap::iterator it = m_Map[CFG_COMMAND].find(name);
if (it != m_Map[CFG_COMMAND].end())
return &(it->second);
for( int search_ns = ns; search_ns >= 0; search_ns-- )
for (int search_ns = ns; search_ns >= 0; search_ns--)
{
TConfigMap::iterator it = m_Map[search_ns].find(name);
if (it != m_Map[search_ns].end())
return &( it->second );
return &(it->second);
}
return( NULL );
return NULL;
}
std::vector<std::pair<CStr, CConfigValueSet> > CConfigDB::GetValuesWithPrefix(EConfigNamespace ns, const CStr& prefix)

View File

@ -48,7 +48,6 @@
#include "ps/Overlay.h"
#include "ps/Profile.h"
#include "ps/ProfileViewer.h"
#include "ps/StringConvert.h"
#include "ps/Util.h"
#include "ps/VideoMode.h"
#include "ps/World.h"
@ -76,9 +75,6 @@
#include "maths/scripting/JSInterface_Vector3D.h"
#include "graphics/scripting/JSInterface_Camera.h"
#include "graphics/scripting/JSInterface_LightEnv.h"
#include "ps/scripting/JSInterface_Console.h"
#include "gui/GUI.h"
@ -184,9 +180,8 @@ retry:
// display progress / description in loading screen
void GUI_DisplayLoadProgress(int percent, const wchar_t* pending_task)
{
JSString* js_desc = StringConvert::wstring_to_jsstring(g_ScriptingHost.getContext(), pending_task);
g_ScriptingHost.SetGlobal("g_Progress", INT_TO_JSVAL(percent));
g_ScriptingHost.SetGlobal("g_LoadDescription", STRING_TO_JSVAL(js_desc));
g_ScriptingHost.GetScriptInterface().SetGlobal("g_Progress", percent, true);
g_ScriptingHost.GetScriptInterface().SetGlobal("g_LoadDescription", pending_task, true);
g_GUI->SendEventToAll("progress");
}
@ -306,8 +301,6 @@ static void RegisterJavascriptInterfaces()
JSI_Vector3D::init();
// graphics
JSI_Camera::init();
JSI_LightEnv::init();
CGameView::ScriptingInit();
// renderer

View File

@ -1,83 +0,0 @@
/* 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/>.
*/
#include "precompiled.h"
#include "StringConvert.h"
#include "lib/external_libraries/sdl.h"
#include "scripting/SpiderMonkey.h"
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
#define ucs2le_to_wchart(ptr) (wchar_t)( (u16) ((u8*)ptr)[0] | (u16) ( ((u8*)ptr)[1] << 8) )
#else
#define ucs2le_to_wchart(ptr) (wchar_t)(*ptr);
#endif
JSString* StringConvert::wchars_to_jsstring(JSContext* cx, const wchar_t* chars, size_t len)
{
if (len == 0)
return JSVAL_TO_STRING(JS_GetEmptyStringValue(cx));
jschar* data = (jschar*)JS_malloc(cx, len*sizeof(jschar));
if (!data)
return NULL;
// Copy the string data, doing wchar_t->jschar conversion (since they're not equal in GCC)
for (size_t i=0; i<len; ++i)
data[i] = chars[i];
return JS_NewUCString(cx, data, len);
}
JSString* StringConvert::wchars_to_jsstring(JSContext* cx, const wchar_t* chars)
{
return wchars_to_jsstring(cx, chars, wcslen(chars));
}
JSString* StringConvert::wstring_to_jsstring(JSContext* cx, const std::wstring& str)
{
return wchars_to_jsstring(cx, str.data(), str.length());
}
void StringConvert::jsstring_to_wstring(JSString* str, std::wstring& result)
{
jschars_to_wstring(JS_GetStringChars(str), JS_GetStringLength(str), result);
}
void StringConvert::jschars_to_wstring(const jschar* chars, size_t len, std::wstring& result)
{
debug_assert(result.empty());
result.resize(len);
for (size_t i = 0; i < len; ++i)
result[i] = chars[i];
}
void StringConvert::ucs2le_to_wstring(const char* start, const char* end, std::wstring& result)
{
debug_assert(result.empty());
result.resize((end-start)/2);
size_t i = 0;
for (const char* pos = start; pos < end; pos += 2)
result[i++] = ucs2le_to_wchart(pos);
}

View File

@ -1,43 +0,0 @@
/* 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/>.
*/
#ifndef INCLUDED_STRINGCONVERT
#define INCLUDED_STRINGCONVERT
typedef unsigned short jschar;
typedef unsigned short ucs2char;
struct JSString;
struct JSContext;
#include <string>
namespace StringConvert
{
// A random collection of conversion functions:
JSString* wstring_to_jsstring(JSContext* cx, const std::wstring& str);
JSString* wchars_to_jsstring(JSContext* cx, const wchar_t* chars);
JSString* wchars_to_jsstring(JSContext* cx, const wchar_t* chars, size_t len);
void jsstring_to_wstring(JSString* str, std::wstring& result);
void jschars_to_wstring(const jschar* chars, size_t len, std::wstring& result);
void ucs2le_to_wstring(const char* start, const char* end, std::wstring& result);
}
#endif // INCLUDED_STRINGCONVERT

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2009 Wildfire Games.
/* Copyright (C) 2010 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -40,81 +40,85 @@ JSPropertySpec JSI_Console::JSI_props[] =
JSFunctionSpec JSI_Console::JSI_methods[] =
{
{ "write", JSI_Console::writeConsole, 1, 0, 0 },
{ "write", JSI_Console::writeConsole, 1, 0 },
{ 0 },
};
JSBool JSI_Console::getProperty( JSContext* UNUSED(cx), JSObject* UNUSED(obj), jsval id, jsval* vp )
JSBool JSI_Console::getProperty(JSContext* UNUSED(cx), JSObject* UNUSED(obj), jsid id, jsval* vp)
{
if( !JSVAL_IS_INT( id ) )
return( JS_TRUE );
if (!JSID_IS_INT(id))
return JS_TRUE;
int i = JSVAL_TO_INT( id );
int i = JSID_TO_INT(id);
switch( i )
switch (i)
{
case console_visible:
*vp = BOOLEAN_TO_JSVAL( g_Console->IsActive() ); return( JS_TRUE );
*vp = BOOLEAN_TO_JSVAL(g_Console->IsActive());
return JS_TRUE;
default:
*vp = JSVAL_NULL; return( JS_TRUE );
}
*vp = JSVAL_NULL;
return JS_TRUE;
}
}
JSBool JSI_Console::setProperty( JSContext* UNUSED(cx), JSObject* UNUSED(obj), jsval id, jsval* vp )
JSBool JSI_Console::setProperty(JSContext* UNUSED(cx), JSObject* UNUSED(obj), jsid id, jsval* vp)
{
if( !JSVAL_IS_INT( id ) )
return( JS_TRUE );
if (!JSID_IS_INT(id))
return JS_TRUE;
int i = JSVAL_TO_INT( id );
int i = JSID_TO_INT(id);
switch( i )
switch (i)
{
case console_visible:
try
{
g_Console->SetVisible( ToPrimitive<bool>( *vp ) );
return( JS_TRUE );
g_Console->SetVisible(ToPrimitive<bool> (*vp));
return JS_TRUE;
}
catch( PSERROR_Scripting_ConversionFailed )
catch (PSERROR_Scripting_ConversionFailed)
{
return( JS_TRUE );
return JS_TRUE;
}
default:
return( JS_TRUE );
}
return JS_TRUE;
}
}
void JSI_Console::init()
{
g_ScriptingHost.DefineCustomObjectType( &JSI_class, NULL, 0, JSI_props, JSI_methods, NULL, NULL );
g_ScriptingHost.DefineCustomObjectType(&JSI_class, NULL, 0, JSI_props, JSI_methods, NULL, NULL);
}
JSBool JSI_Console::getConsole( JSContext* cx, JSObject* UNUSED(obj), jsval UNUSED(id), jsval* vp )
JSBool JSI_Console::getConsole(JSContext* cx, JSObject* UNUSED(obj), jsid UNUSED(id), jsval* vp)
{
JSObject* console = JS_NewObject( cx, &JSI_Console::JSI_class, NULL, NULL );
*vp = OBJECT_TO_JSVAL( console );
return( JS_TRUE );
JSObject* console = JS_NewObject(cx, &JSI_Console::JSI_class, NULL, NULL);
*vp = OBJECT_TO_JSVAL(console);
return JS_TRUE;
}
JSBool JSI_Console::writeConsole( JSContext* UNUSED(context), JSObject* UNUSED(globalObject), uintN argc, jsval* argv, jsval* UNUSED(rval) )
JSBool JSI_Console::writeConsole(JSContext* cx, uintN argc, jsval* vp)
{
debug_assert( argc >= 1 );
UNUSED2(cx);
CStrW output;
for( unsigned int i = 0; i < argc; i++ )
for (uintN i = 0; i < argc; i++)
{
try
{
CStrW arg = g_ScriptingHost.ValueToUCString( argv[i] );
CStrW arg = g_ScriptingHost.ValueToUCString(JS_ARGV(cx, vp)[i]);
output += arg;
}
catch( PSERROR_Scripting_ConversionFailed )
catch (PSERROR_Scripting_ConversionFailed)
{
}
}
// TODO: What if the console has been destroyed already?
if (g_Console)
g_Console->InsertMessage( L"%ls", output.c_str() );
g_Console->InsertMessage(L"%ls", output.c_str());
return( JS_TRUE );
JS_SET_RVAL(cx, vp, JSVAL_VOID);
return JS_TRUE;
}

View File

@ -34,14 +34,14 @@ namespace JSI_Console
extern JSPropertySpec JSI_props[];
extern JSFunctionSpec JSI_methods[];
JSBool getProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp );
JSBool setProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp );
JSBool getProperty(JSContext* cx, JSObject* obj, jsid id, jsval* vp);
JSBool setProperty(JSContext* cx, JSObject* obj, jsid id, jsval* vp);
JSBool getConsole( JSContext* context, JSObject* obj, jsval id, jsval* vp );
JSBool getConsole(JSContext* context, JSObject* obj, jsid id, jsval* vp);
void init();
JSBool writeConsole( JSContext* context, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
JSBool writeConsole(JSContext* cx, uintN argc, jsval* vp);
}
#endif

View File

@ -29,15 +29,15 @@
// shared error handling code
#define JS_CHECK_FILE_ERR(err)\
/* this is liable to happen often, so don't complain */\
if(err == ERR::VFS_FILE_NOT_FOUND)\
if (err == ERR::VFS_FILE_NOT_FOUND)\
{\
*rval = JSVAL_NULL;\
return( JS_TRUE );\
JS_SET_RVAL(cx, vp, JSVAL_NULL);\
return JS_TRUE;\
}\
/* unknown failure. we return an error (akin to an exception in JS) that
stops the script to make sure this error is noticed. */\
else if(err < 0)\
return( JS_FALSE );\
else if (err < 0)\
return JS_FALSE;\
/* else: success */
@ -54,13 +54,13 @@ struct BuildDirEntListState
: cx(cx_)
{
filename_array = JS_NewArrayObject(cx, 0, NULL);
JS_AddRoot(cx, &filename_array);
JS_AddObjectRoot(cx, &filename_array);
cur_idx = 0;
}
~BuildDirEntListState()
{
JS_RemoveRoot(cx, &filename_array);
JS_RemoveObjectRoot(cx, &filename_array);
}
};
@ -85,44 +85,45 @@ static LibError BuildDirEntListCB(const VfsPath& pathname, const FileInfo& UNUSE
//
// note: full pathnames of each file/subdirectory are returned,
// ready for use as a "filename" for the other functions.
JSBool JSI_VFS::BuildDirEntList( JSContext* cx, JSObject* UNUSED(obj), uintN argc, jsval* argv, jsval* rval )
JSBool JSI_VFS::BuildDirEntList(JSContext* cx, uintN argc, jsval* vp)
{
//
// get arguments
//
debug_assert( argc >= 1 );
JSU_REQUIRE_MIN_PARAMS(1);
CStr path;
if( !ToPrimitive<CStr>( cx, argv[0], path ) )
return( JS_FALSE );
if (!ToPrimitive<CStr> (cx, JS_ARGV(cx, vp)[0], path))
return JS_FALSE;
CStrW filter_str = L"";
if(argc >= 2)
if (argc >= 2)
{
if( !ToPrimitive<CStrW>( cx, argv[1], filter_str ) )
return( JS_FALSE );
if (!ToPrimitive<CStrW> (cx, JS_ARGV(cx, vp)[1], filter_str))
return JS_FALSE;
}
// convert to const wchar_t*; if there's no filter, pass 0 for speed
// (interpreted as: "accept all files without comparing").
const wchar_t* filter = 0;
if(!filter_str.empty())
if (!filter_str.empty())
filter = filter_str.c_str();
bool recursive = false;
if(argc >= 3)
if (argc >= 3)
{
if( !ToPrimitive<bool>( cx, argv[2], recursive ) )
return( JS_FALSE );
if (!ToPrimitive<bool> (cx, JS_ARGV(cx, vp)[2], recursive))
return JS_FALSE;
}
int flags = recursive? fs_util::DIR_RECURSIVE : 0;
int flags = recursive ? fs_util::DIR_RECURSIVE : 0;
// build array in the callback function
BuildDirEntListState state(cx);
fs_util::ForEachFile(g_VFS, CStrW(path), BuildDirEntListCB, (uintptr_t)&state, filter, flags);
*rval = OBJECT_TO_JSVAL( state.filename_array );
return( JS_TRUE );
JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(state.filename_array));
return JS_TRUE;
}
@ -130,19 +131,20 @@ JSBool JSI_VFS::BuildDirEntList( JSContext* cx, JSObject* UNUSED(obj), uintN arg
//
// mtime = getFileMTime(filename);
// filename: VFS filename (may include path)
JSBool JSI_VFS::GetFileMTime( JSContext* cx, JSObject* UNUSED(obj), uintN argc, jsval* argv, jsval* rval )
JSBool JSI_VFS::GetFileMTime(JSContext* cx, uintN argc, jsval* vp)
{
debug_assert( argc >= 1 );
JSU_REQUIRE_MIN_PARAMS(1);
CStr filename;
if( !ToPrimitive<CStr>( cx, argv[0], filename ) )
return( JS_FALSE );
if (!ToPrimitive<CStr> (cx, JS_ARGV(cx, vp)[0], filename))
return JS_FALSE;
FileInfo fileInfo;
LibError err = g_VFS->GetFileInfo(CStrW(filename), &fileInfo);
JS_CHECK_FILE_ERR( err );
JS_CHECK_FILE_ERR(err);
*rval = ToJSVal( (double)fileInfo.MTime() );
return( JS_TRUE );
JS_SET_RVAL(cx, vp, ToJSVal((double)fileInfo.MTime()));
return JS_TRUE;
}
@ -150,19 +152,20 @@ JSBool JSI_VFS::GetFileMTime( JSContext* cx, JSObject* UNUSED(obj), uintN argc,
//
// size = getFileSize(filename);
// filename: VFS filename (may include path)
JSBool JSI_VFS::GetFileSize( JSContext* cx, JSObject* UNUSED(obj), uintN argc, jsval* argv, jsval* rval )
JSBool JSI_VFS::GetFileSize(JSContext* cx, uintN argc, jsval* vp)
{
debug_assert( argc >= 1 );
JSU_REQUIRE_MIN_PARAMS(1);
CStr filename;
if( !ToPrimitive<CStr>( cx, argv[0], filename ) )
return( JS_FALSE );
if (!ToPrimitive<CStr> (cx, JS_ARGV(cx, vp)[0], filename))
return JS_FALSE;
FileInfo fileInfo;
LibError err = g_VFS->GetFileInfo(CStrW(filename), &fileInfo);
JS_CHECK_FILE_ERR(err);
*rval = ToJSVal( (unsigned)fileInfo.Size() );
return( JS_TRUE );
JS_SET_RVAL(cx, vp, ToJSVal( (unsigned)fileInfo.Size() ));
return JS_TRUE;
}
@ -170,25 +173,27 @@ JSBool JSI_VFS::GetFileSize( JSContext* cx, JSObject* UNUSED(obj), uintN argc, j
//
// contents = readFile(filename);
// filename: VFS filename (may include path)
JSBool JSI_VFS::ReadFile( JSContext* cx, JSObject* UNUSED(obj), uintN argc, jsval* argv, jsval* rval )
JSBool JSI_VFS::ReadFile(JSContext* cx, uintN argc, jsval* vp)
{
debug_assert( argc >= 1 );
CStr filename;
if( !ToPrimitive<CStr>( cx, argv[0], filename ) )
return( JS_FALSE );
JSU_REQUIRE_MIN_PARAMS(1);
shared_ptr<u8> buf; size_t size;
LibError err = g_VFS->LoadFile( CStrW(filename), buf, size );
CStr filename;
if (!ToPrimitive<CStr> (cx, JS_ARGV(cx, vp)[0], filename))
return JS_FALSE;
shared_ptr<u8> buf;
size_t size;
LibError err = g_VFS->LoadFile(CStrW(filename), buf, size);
JS_CHECK_FILE_ERR( err );
CStr contents( (const char*)buf.get(), size );
CStr contents((const char*)buf.get(), size);
// Fix CRLF line endings. (This function will only ever be used on text files.)
contents.Replace("\r\n", "\n");
// Decode as UTF-8
*rval = ToJSVal( contents.FromUTF8() );
return( JS_TRUE );
JS_SET_RVAL(cx, vp, ToJSVal( contents.FromUTF8() ));
return JS_TRUE;
}
@ -196,22 +201,24 @@ JSBool JSI_VFS::ReadFile( JSContext* cx, JSObject* UNUSED(obj), uintN argc, jsva
//
// lines = readFileLines(filename);
// filename: VFS filename (may include path)
JSBool JSI_VFS::ReadFileLines( JSContext* cx, JSObject* UNUSED(obj), uintN argc, jsval* argv, jsval* rval )
JSBool JSI_VFS::ReadFileLines(JSContext* cx, uintN argc, jsval* vp)
{
debug_assert( argc >= 1 );
JSU_REQUIRE_MIN_PARAMS(1);
CStr filename;
if( !ToPrimitive<CStr>( cx, argv[0], filename ) )
return( JS_FALSE );
if (!ToPrimitive<CStr> (cx, JS_ARGV(cx, vp)[0], filename))
return (JS_FALSE);
//
// read file
//
shared_ptr<u8> buf; size_t size;
LibError err = g_VFS->LoadFile( CStrW(filename), buf, size );
shared_ptr<u8> buf;
size_t size;
LibError err = g_VFS->LoadFile(CStrW(filename), buf, size);
JS_CHECK_FILE_ERR( err );
CStr contents( (const char*)buf.get(), size );
CStr contents((const char*)buf.get(), size);
// Fix CRLF line endings. (This function will only ever be used on text files.)
contents.Replace("\r\n", "\n");
@ -220,32 +227,33 @@ JSBool JSI_VFS::ReadFileLines( JSContext* cx, JSObject* UNUSED(obj), uintN argc,
// split into array of strings (one per line)
//
std::stringstream ss( contents );
std::stringstream ss(contents);
JSObject* line_array = JS_NewArrayObject( cx, 0, NULL );
JS_AddRoot(cx, &line_array);
JSObject* line_array = JS_NewArrayObject(cx, 0, NULL);
std::string line;
int cur_line = 0;
while( std::getline( ss, line ) )
while (std::getline(ss, line))
{
// Decode each line as UTF-8
jsval val = ToJSVal( CStr( line ).FromUTF8() );
JS_SetElement( cx, line_array, cur_line++, &val );
jsval val = ToJSVal(CStr(line).FromUTF8());
JS_SetElement(cx, line_array, cur_line++, &val);
}
JS_RemoveRoot(cx, &line_array);
*rval = OBJECT_TO_JSVAL( line_array );
return( JS_TRUE );
JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL( line_array ));
return JS_TRUE ;
}
// vfs_optimizer
JSBool JSI_VFS::ArchiveBuilderCancel(JSContext* UNUSED(cx), JSObject* UNUSED(obj), uintN argc, jsval* UNUSED(argv), jsval* UNUSED(rval) )
JSBool JSI_VFS::ArchiveBuilderCancel(JSContext* cx, uintN argc, jsval* vp)
{
debug_assert( argc == 0 );
UNUSED2(cx);
UNUSED2(argc);
// vfs_opt_auto_build_cancel();
return( JS_TRUE );
JS_SET_RVAL(cx, vp, JSVAL_VOID);
return JS_TRUE;
}

View File

@ -38,36 +38,36 @@ namespace JSI_VFS
//
// note: full pathnames of each file/subdirectory are returned,
// ready for use as a "filename" for the other functions.
JSBool BuildDirEntList( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
JSBool BuildDirEntList(JSContext* cx, uintN argc, jsval* vp);
// Return time [seconds since 1970] of the last modification to the specified file.
//
// mtime = getFileMTime(filename);
// filename: VFS filename (may include path)
JSBool GetFileMTime( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
JSBool GetFileMTime(JSContext* cx, uintN argc, jsval* vp);
// Return current size of file.
//
// size = getFileSize(filename);
// filename: VFS filename (may include path)
JSBool GetFileSize( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
JSBool GetFileSize(JSContext* cx, uintN argc, jsval* vp);
// Return file contents in a string.
//
// contents = readFile(filename);
// filename: VFS filename (may include path)
JSBool ReadFile( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
JSBool ReadFile(JSContext* cx, uintN argc, jsval* vp);
// Return file contents as an array of lines.
//
// lines = readFileLines(filename);
// filename: VFS filename (may include path)
JSBool ReadFileLines( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
JSBool ReadFileLines(JSContext* cx, uintN argc, jsval* vp);
// Abort the current archive build operation (no-op if not currently active).
//
// archiveBuilderCancel();
JSBool ArchiveBuilderCancel(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
JSBool ArchiveBuilderCancel(JSContext* cx, uintN argc, jsval* vp);
}
#endif

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2009 Wildfire Games.
/* Copyright (C) 2010 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -22,6 +22,7 @@
#include "maths/scripting/JSInterface_Vector3D.h"
#include "ps/Parser.h"
#include "lib/sysdep/sysdep.h" // isfinite
#include "scriptinterface/ScriptInterface.h"
#include <math.h>
#include <cfloat>
@ -180,12 +181,16 @@ template<> bool ToPrimitive<ssize_t>( JSContext* cx, jsval v, ssize_t& Storage )
template<> jsval ToJSVal<double>( const double& Native )
{
return( DOUBLE_TO_JSVAL( JS_NewDouble( g_ScriptingHost.getContext(), Native ) ) );
jsval val = JSVAL_VOID;
JS_NewNumberValue( g_ScriptingHost.getContext(), Native, &val );
return val;
}
template<> jsval ToJSVal<double>( double& Native )
{
return( DOUBLE_TO_JSVAL( JS_NewDouble( g_ScriptingHost.getContext(), Native ) ) );
jsval val = JSVAL_VOID;
JS_NewNumberValue( g_ScriptingHost.getContext(), Native, &val );
return val;
}
template<> bool ToPrimitive<double>( JSContext* cx, jsval v, double& Storage )
@ -200,12 +205,16 @@ template<> bool ToPrimitive<double>( JSContext* cx, jsval v, double& Storage )
template<> jsval ToJSVal<float>( const float& Native )
{
return( DOUBLE_TO_JSVAL( JS_NewDouble( g_ScriptingHost.getContext(), Native ) ) );
jsval val = JSVAL_VOID;
JS_NewNumberValue( g_ScriptingHost.getContext(), Native, &val );
return val;
}
template<> jsval ToJSVal<float>( float& Native )
{
return( DOUBLE_TO_JSVAL( JS_NewDouble( g_ScriptingHost.getContext(), Native ) ) );
jsval val = JSVAL_VOID;
JS_NewNumberValue( g_ScriptingHost.getContext(), Native, &val );
return val;
}
template<> bool ToPrimitive<float>( JSContext* cx, jsval v, float& Storage )
@ -256,27 +265,23 @@ template<> bool ToPrimitive<CStrW>( JSContext* UNUSED(cx), jsval v, CStrW& Stora
template<> jsval ToJSVal<CStrW>( const CStrW& Native )
{
return( STRING_TO_JSVAL( JS_NewUCStringCopyZ( g_ScriptingHost.GetContext(), Native.utf16().c_str() ) ) );
return( STRING_TO_JSVAL( JS_NewUCStringCopyZ( g_ScriptingHost.GetContext(), reinterpret_cast<const jschar*>(Native.utf16().c_str()) ) ) );
}
template<> jsval ToJSVal<CStrW>( CStrW& Native )
{
return( STRING_TO_JSVAL( JS_NewUCStringCopyZ( g_ScriptingHost.GetContext(), Native.utf16().c_str() ) ) );
return( STRING_TO_JSVAL( JS_NewUCStringCopyZ( g_ScriptingHost.GetContext(), reinterpret_cast<const jschar*>(Native.utf16().c_str()) ) ) );
}
// CStr/CStr8
template<> bool ToPrimitive<CStr8>( JSContext* UNUSED(cx), jsval v, CStr8& Storage )
template<> bool ToPrimitive<CStr8>( JSContext* cx, jsval v, CStr8& Storage )
{
try
{
Storage = g_ScriptingHost.ValueToString( v );
}
catch( PSERROR_Scripting_ConversionFailed )
{
return( false );
}
return( true );
std::string str;
if (!ScriptInterface::FromJSVal(cx, v, str))
return false;
Storage = str;
return true;
}
template<> jsval ToJSVal<CStr8>( const CStr8& Native )
@ -304,18 +309,12 @@ jsval JSParseString( const CStrW& Native )
stringParser.InputTaskType( "string", "_$value_" );
CParserLine result;
result.ParseString( stringParser, CStr(Native) );
bool boolResult; int intResult; float floatResult;
bool boolResult;
float floatResult;
if( result.GetArgFloat( 0, floatResult ) )
{
if( floatResult == floor( floatResult ) )
{
intResult = (int)floatResult;
if( INT_FITS_IN_JSVAL( intResult ) )
return( ToJSVal( intResult ) );
}
return( ToJSVal( floatResult ) );
}
if( result.GetArgBool( 0, boolResult ) )
return( BOOLEAN_TO_JSVAL( boolResult ) );

View File

@ -19,12 +19,12 @@
#include "SpiderMonkey.h"
jsval jsu_report_param_error(JSContext* cx, jsval* rval)
JSBool jsu_report_param_error(JSContext* cx, jsval* vp)
{
JS_ReportError(cx, "Invalid parameter(s) or count");
if(rval)
*rval = JSVAL_NULL;
if (vp)
JS_SET_RVAL(cx, vp, JSVAL_NULL);
// yes, we had an error, but returning JS_FALSE would cause SpiderMonkey
// to abort. that would be hard to debug.

View File

@ -17,7 +17,7 @@
// included from SpiderMonkey.h
extern jsval jsu_report_param_error(JSContext* cx, jsval* rval);
extern JSBool jsu_report_param_error(JSContext* cx, jsval* vp);
// consistent argc checking for normal function wrappers: reports an
@ -25,24 +25,23 @@ extern jsval jsu_report_param_error(JSContext* cx, jsval* rval);
// .. require exact number (most common case)
#define JSU_REQUIRE_PARAMS(exact_number)\
if(argc != exact_number)\
return jsu_report_param_error(cx, rval);
return jsu_report_param_error(cx, vp);
// .. require 0 params (avoids L4 warning "unused argv param")
#define JSU_REQUIRE_NO_PARAMS()\
UNUSED2(argv);\
if(argc != 0)\
return jsu_report_param_error(cx, rval);
return jsu_report_param_error(cx, vp);
// .. require a certain range (e.g. due to optional params)
#define JSU_REQUIRE_PARAM_RANGE(min_number, max_number)\
if(!(min_number <= argc && argc <= max_number))\
return jsu_report_param_error(cx, rval);
return jsu_report_param_error(cx, vp);
// .. require at most a certain count
#define JSU_REQUIRE_MAX_PARAMS(max_number)\
if(argc > max_number)\
return jsu_report_param_error(cx, rval);
return jsu_report_param_error(cx, vp);
// .. require at least a certain count (rarely needed)
#define JSU_REQUIRE_MIN_PARAMS(min_number)\
if(argc < min_number)\
return jsu_report_param_error(cx, rval);
return jsu_report_param_error(cx, vp);
// same as JSU_REQUIRE_PARAMS, but used from C++ functions that are
// a bit further removed from SpiderMonkey, i.e. return a

View File

@ -31,8 +31,6 @@
#include "graphics/MapWriter.h"
#include "graphics/Unit.h"
#include "graphics/UnitManager.h"
#include "graphics/scripting/JSInterface_Camera.h"
#include "graphics/scripting/JSInterface_LightEnv.h"
#include "gui/GUIManager.h"
#include "gui/IGUIObject.h"
#include "lib/frequency_filter.h"
@ -109,24 +107,26 @@ static void InitJsTimers()
js_timer_clients[0].sum.SetToZero();
}
JSBool StartJsTimer(JSContext* cx, JSObject*, uintN argc, jsval* argv, jsval* rval)
JSBool StartJsTimer(JSContext* cx, uintN argc, jsval* vp)
{
ONCE(InitJsTimers());
JSU_REQUIRE_PARAMS(1);
size_t slot = ToPrimitive<size_t>(argv[0]);
size_t slot = ToPrimitive<size_t>(JS_ARGV(cx, vp)[0]);
if (slot >= MAX_JS_TIMERS)
return JS_FALSE;
js_start_times[slot].SetFromTimer();
JS_SET_RVAL(cx, vp, JSVAL_VOID);
return JS_TRUE;
}
JSBool StopJsTimer(JSContext* cx, JSObject*, uintN argc, jsval* argv, jsval* rval)
JSBool StopJsTimer(JSContext* cx, uintN argc, jsval* vp)
{
JSU_REQUIRE_PARAMS(1);
size_t slot = ToPrimitive<size_t>(argv[0]);
size_t slot = ToPrimitive<size_t>(JS_ARGV(cx, vp)[0]);
if (slot >= MAX_JS_TIMERS)
return JS_FALSE;
@ -135,6 +135,8 @@ JSBool StopJsTimer(JSContext* cx, JSObject*, uintN argc, jsval* argv, jsval* rva
now.Subtract(js_timer_overhead);
BillingPolicy_Default()(&js_timer_clients[slot], js_start_times[slot], now);
js_start_times[slot].SetToZero();
JS_SET_RVAL(cx, vp, JSVAL_VOID);
return JS_TRUE;
}
@ -146,11 +148,13 @@ JSBool StopJsTimer(JSContext* cx, JSObject*, uintN argc, jsval* argv, jsval* rva
// Immediately ends the current game (if any).
// params:
// returns:
JSBool EndGame(JSContext* cx, JSObject*, uintN argc, jsval* argv, jsval* rval)
JSBool EndGame(JSContext* cx, uintN argc, jsval* vp)
{
JSU_REQUIRE_NO_PARAMS();
EndGame();
JS_SET_RVAL(cx, vp, JSVAL_VOID);
return JS_TRUE;
}
@ -164,13 +168,13 @@ JSBool EndGame(JSContext* cx, JSObject*, uintN argc, jsval* argv, jsval* rval)
// notes:
// - This value is recalculated once a frame. We take special care to
// filter it, so it is both accurate and free of jitter.
JSBool GetFps( JSContext* cx, JSObject*, uintN argc, jsval* argv, jsval* rval )
JSBool GetFps(JSContext* cx, uintN argc, jsval* vp)
{
JSU_REQUIRE_NO_PARAMS();
int freq = 0;
if (g_frequencyFilter)
freq = g_frequencyFilter->StableFrequency();
*rval = INT_TO_JSVAL(freq);
JS_SET_RVAL(cx, vp, INT_TO_JSVAL(freq));
return JS_TRUE;
}
@ -181,28 +185,13 @@ JSBool GetFps( JSContext* cx, JSObject*, uintN argc, jsval* argv, jsval* rval )
// notes:
// - Exit happens after the current main loop iteration ends
// (since this only sets a flag telling it to end)
JSBool ExitProgram( JSContext* cx, JSObject*, uintN argc, jsval* argv, jsval* rval )
JSBool ExitProgram(JSContext* cx, uintN argc, jsval* vp)
{
JSU_REQUIRE_NO_PARAMS();
kill_mainloop();
return JS_TRUE;
}
// Write an indication of total video RAM to console.
// params:
// returns:
// notes:
// - May not be supported on all platforms.
// - Only a rough approximation; do not base low-level decisions
// ("should I allocate one more texture?") on this.
JSBool WriteVideoMemToConsole( JSContext* cx, JSObject*, uintN argc, jsval* argv, jsval* rval )
{
JSU_REQUIRE_NO_PARAMS();
const SDL_VideoInfo* videoInfo = SDL_GetVideoInfo();
g_Console->InsertMessage(L"VRAM: total %d", videoInfo->video_mem);
JS_SET_RVAL(cx, vp, JSVAL_VOID);
return JS_TRUE;
}
@ -212,38 +201,27 @@ JSBool WriteVideoMemToConsole( JSContext* cx, JSObject*, uintN argc, jsval* argv
// returns:
// notes:
// - Cursors are stored in "art\textures\cursors"
JSBool SetCursor( JSContext* cx, JSObject*, uintN argc, jsval* argv, jsval* rval )
JSBool SetCursor(JSContext* cx, uintN argc, jsval* vp)
{
JSU_REQUIRE_PARAMS(1);
g_CursorName = g_ScriptingHost.ValueToUCString(argv[0]);
g_CursorName = g_ScriptingHost.ValueToUCString(JS_ARGV(cx, vp)[0]);
JS_SET_RVAL(cx, vp, JSVAL_VOID);
return JS_TRUE;
}
// Change the LOD bias.
// params: LOD bias [float]
// returns:
// notes:
// - value is as required by GL_TEXTURE_LOD_BIAS.
// - useful for adjusting image "sharpness" (since it affects which mipmap level is chosen)
JSBool _LodBias( JSContext* cx, JSObject*, uintN argc, jsval* argv, jsval* rval )
JSBool GetGUIObjectByName(JSContext* cx, uintN argc, jsval* vp)
{
JSU_REQUIRE_PARAMS(1);
g_Renderer.SetOptionFloat(CRenderer::OPT_LODBIAS, ToPrimitive<float>(argv[0]));
return JS_TRUE;
}
JSBool GetGUIObjectByName(JSContext* cx, JSObject* UNUSED(obj), uintN UNUSED(argc), jsval* argv, jsval* rval)
{
try
{
CStr name = ToPrimitive<CStr>(cx, argv[0]);
CStr name = ToPrimitive<CStr>(cx, JS_ARGV(cx, vp)[0]);
IGUIObject* guiObj = g_GUI->FindObjectByName(name);
if (guiObj)
*rval = OBJECT_TO_JSVAL(guiObj->GetJSObject());
JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(guiObj->GetJSObject()));
else
*rval = JSVAL_NULL;
JS_SET_RVAL(cx, vp, JSVAL_NULL);
return JS_TRUE;
}
catch (PSERROR_Scripting&)
@ -270,14 +248,14 @@ JSBool GetGUIObjectByName(JSContext* cx, JSObject* UNUSED(obj), uintN UNUSED(arg
// lib/svn_revision.cpp. it is useful to know when attempting to
// reproduce bugs (the main EXE and PDB should be temporarily reverted to
// that revision so that they match user-submitted crashdumps).
JSBool GetBuildTimestamp( JSContext* cx, JSObject*, uintN argc, jsval* argv, jsval* rval )
JSBool GetBuildTimestamp(JSContext* cx, uintN argc, jsval* vp)
{
JSU_REQUIRE_MAX_PARAMS(1);
char buf[200];
// see function documentation
const int mode = argc? JSVAL_TO_INT(argv[0]) : -1;
const int mode = argc? JSVAL_TO_INT(JS_ARGV(cx, vp)[0]) : -1;
switch(mode)
{
case -1:
@ -294,7 +272,7 @@ JSBool GetBuildTimestamp( JSContext* cx, JSObject*, uintN argc, jsval* argv, jsv
break;
}
*rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, buf));
JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(JS_NewStringCopyZ(cx, buf)));
return JS_TRUE;
}
@ -311,8 +289,11 @@ void DumpHeap(const char* name, int idx, JSContext* cx)
}
#endif
JSBool DumpHeaps(JSContext* UNUSED(cx), JSObject* UNUSED(globalObject), uintN UNUSED(argc), jsval* UNUSED(argv), jsval* UNUSED(rval) )
JSBool DumpHeaps(JSContext* cx, uintN argc, jsval* vp)
{
UNUSED2(cx);
UNUSED2(argc);
#ifdef DEBUG
static int i = 0;
@ -325,47 +306,50 @@ JSBool DumpHeaps(JSContext* UNUSED(cx), JSObject* UNUSED(globalObject), uintN UN
#else
debug_warn(L"DumpHeaps only available in DEBUG mode");
#endif
JS_SET_RVAL(cx, vp, JSVAL_VOID);
return JS_TRUE;
}
//-----------------------------------------------------------------------------
// Is the game paused?
JSBool IsPaused( JSContext* cx, JSObject* UNUSED(globalObject), uintN argc, jsval* argv, jsval* rval )
JSBool IsPaused(JSContext* cx, uintN argc, jsval* vp)
{
JSU_REQUIRE_NO_PARAMS();
if( !g_Game )
if (!g_Game)
{
JS_ReportError( cx, "Game is not started" );
JS_ReportError(cx, "Game is not started");
return JS_FALSE;
}
*rval = g_Game->m_Paused ? JSVAL_TRUE : JSVAL_FALSE;
return JS_TRUE ;
JS_SET_RVAL(cx, vp, g_Game->m_Paused ? JSVAL_TRUE : JSVAL_FALSE);
return JS_TRUE;
}
// Pause/unpause the game
JSBool SetPaused( JSContext* cx, JSObject* UNUSED(globalObject), uintN argc, jsval* argv, jsval* rval )
JSBool SetPaused(JSContext* cx, uintN argc, jsval* vp)
{
JSU_REQUIRE_PARAMS( 1 );
if( !g_Game )
if (!g_Game)
{
JS_ReportError( cx, "Game is not started" );
JS_ReportError(cx, "Game is not started");
return JS_FALSE;
}
try
{
g_Game->m_Paused = ToPrimitive<bool>( argv[0] );
g_Game->m_Paused = ToPrimitive<bool> (JS_ARGV(cx, vp)[0]);
}
catch( PSERROR_Scripting_ConversionFailed )
catch (PSERROR_Scripting_ConversionFailed)
{
JS_ReportError( cx, "Invalid parameter to SetPaused" );
JS_ReportError(cx, "Invalid parameter to SetPaused");
}
return JS_TRUE;
JS_SET_RVAL(cx, vp, JSVAL_VOID);
return JS_TRUE;
}
@ -381,7 +365,7 @@ JSBool SetPaused( JSContext* cx, JSObject* UNUSED(globalObject), uintN argc, jsv
// - Extra (reserved for future use, always zero)
//
// we simplify this a bit with a macro:
#define JS_FUNC(script_name, cpp_function, min_params) { script_name, cpp_function, min_params, 0, 0 },
#define JS_FUNC(script_name, cpp_function, min_params) { script_name, cpp_function, min_params, 0 },
JSFunctionSpec ScriptFunctionTable[] =
{
@ -404,8 +388,6 @@ JSFunctionSpec ScriptFunctionTable[] =
JS_FUNC("exit", ExitProgram, 0)
JS_FUNC("isPaused", IsPaused, 0)
JS_FUNC("setPaused", SetPaused, 1)
JS_FUNC("vmem", WriteVideoMemToConsole, 0)
JS_FUNC("_lodBias", _LodBias, 0)
JS_FUNC("setCursor", SetCursor, 1)
JS_FUNC("getFPS", GetFps, 0)
JS_FUNC("getGUIObjectByName", GetGUIObjectByName, 1)
@ -415,7 +397,7 @@ JSFunctionSpec ScriptFunctionTable[] =
JS_FUNC("dumpHeaps", DumpHeaps, 0)
// end of table marker
{0, 0, 0, 0, 0}
{0}
};
#undef JS_FUNC
@ -424,23 +406,22 @@ JSFunctionSpec ScriptFunctionTable[] =
// property accessors
//-----------------------------------------------------------------------------
JSBool GetGameView( JSContext* UNUSED(cx), JSObject* UNUSED(obj), jsval UNUSED(id), jsval* vp )
JSBool GetGameView(JSContext* UNUSED(cx), JSObject* UNUSED(obj), jsid UNUSED(id), jsval* vp)
{
if (g_Game)
*vp = OBJECT_TO_JSVAL( g_Game->GetView()->GetScript() );
*vp = OBJECT_TO_JSVAL(g_Game->GetView()->GetScript());
else
*vp = JSVAL_NULL;
return( JS_TRUE );
return JS_TRUE;
}
JSBool GetRenderer( JSContext* UNUSED(cx), JSObject* UNUSED(obj), jsval UNUSED(id), jsval* vp )
JSBool GetRenderer(JSContext* UNUSED(cx), JSObject* UNUSED(obj), jsid UNUSED(id), jsval* vp)
{
if (CRenderer::IsInitialised())
*vp = OBJECT_TO_JSVAL( g_Renderer.GetScript() );
*vp = OBJECT_TO_JSVAL(g_Renderer.GetScript());
else
*vp = JSVAL_NULL;
return( JS_TRUE );
return JS_TRUE;
}
@ -455,9 +436,7 @@ enum ScriptGlobalTinyIDs
JSPropertySpec ScriptGlobalTable[] =
{
{ "camera" , GLOBAL_CAMERA, JSPROP_PERMANENT, JSI_Camera::getCamera, JSI_Camera::setCamera },
{ "console" , GLOBAL_CONSOLE, JSPROP_PERMANENT|JSPROP_READONLY, JSI_Console::getConsole, 0 },
{ "lightenv" , GLOBAL_LIGHTENV, JSPROP_PERMANENT, JSI_LightEnv::getLightEnv, JSI_LightEnv::setLightEnv },
{ "gameView" , 0, JSPROP_PERMANENT|JSPROP_READONLY, GetGameView, 0 },
{ "renderer" , 0, JSPROP_PERMANENT|JSPROP_READONLY, GetRenderer, 0 },

View File

@ -155,12 +155,12 @@ public:
void Root()
{
if( JSVAL_IS_GCTHING( m_Data ) )
JS_AddNamedRoot( g_ScriptingHost.GetContext(), (void*)&m_Data, "ScriptableObjectProperty" );
JS_AddNamedValueRoot( g_ScriptingHost.GetContext(), &m_Data, "ScriptableObjectProperty" );
}
void Uproot()
{
if( JSVAL_IS_GCTHING( m_Data ))
JS_RemoveRoot( g_ScriptingHost.GetContext(), (void*)&m_Data );
JS_RemoveValueRoot( g_ScriptingHost.GetContext(), &m_Data );
}
jsval Get( JSContext* UNUSED(cx), IJSObject* UNUSED(object))
{
@ -179,14 +179,14 @@ public:
template<typename T, bool ReadOnly, typename RType, RType (T::*NativeFunction)( JSContext* cx, uintN argc, jsval* argv )> class CNativeFunction
{
public:
static JSBool JSFunction( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval )
static JSBool JSFunction( JSContext* cx, uintN argc, jsval* vp )
{
T* Native = ToNative<T>( cx, obj );
T* Native = ToNative<T>( cx, JS_THIS_OBJECT( cx, vp ) );
if( !Native )
return( JS_TRUE );
*rval = ToJSVal<RType>( (Native->*NativeFunction)( cx, argc, argv ) );
return( JS_FALSE );
jsval rval = ToJSVal<RType>( (Native->*NativeFunction)( cx, argc, JS_ARGV(cx, vp) ) );
JS_SET_RVAL( cx, vp, rval );
return( JS_TRUE );
}
};
@ -196,14 +196,15 @@ template<typename T, bool ReadOnly, void (T::*NativeFunction)( JSContext* cx, ui
class CNativeFunction<T, ReadOnly, void, NativeFunction>
{
public:
static JSBool JSFunction( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* UNUSED(rval) )
static JSBool JSFunction( JSContext* cx, uintN argc, jsval* vp )
{
T* Native = ToNative<T>( cx, obj );
T* Native = ToNative<T>( cx, JS_THIS_OBJECT( cx, vp ) );
if( !Native )
return( JS_TRUE );
return( JS_FALSE );
(Native->*NativeFunction)( cx, argc, argv );
(Native->*NativeFunction)( cx, argc, JS_ARGV(cx, vp) );
JS_SET_RVAL( cx, vp, JSVAL_VOID );
return( JS_TRUE );
}
};
@ -328,7 +329,7 @@ public:
template<typename ReturnType, ReturnType (T::*NativeFunction)( JSContext* cx, uintN argc, jsval* argv )>
static void AddMethod( const char* Name, uintN MinArgs )
{
JSFunctionSpec FnInfo = { Name, CNativeFunction<T, ReadOnly, ReturnType, NativeFunction>::JSFunction, (uint8)MinArgs, 0, 0 };
JSFunctionSpec FnInfo = { Name, CNativeFunction<T, ReadOnly, ReturnType, NativeFunction>::JSFunction, (uint8)MinArgs, 0 };
m_Methods.push_back( FnInfo );
}
template<typename PropType> static void AddProperty( const CStrW& PropertyName, PropType T::*Native, bool PropReadOnly = ReadOnly )
@ -373,7 +374,7 @@ public:
{
m_JS = JS_NewObject( g_ScriptingHost.GetContext(), &JSI_class, NULL, NULL );
if( m_EngineOwned )
JS_AddNamedRoot( g_ScriptingHost.GetContext(), (void*)&m_JS, JSI_class.name );
JS_AddNamedObjectRoot( g_ScriptingHost.GetContext(), &m_JS, JSI_class.name );
JS_SetPrivate( g_ScriptingHost.GetContext(), m_JS, (T*)this );
}
@ -384,7 +385,7 @@ public:
{
JS_SetPrivate( g_ScriptingHost.GetContext(), m_JS, NULL );
if( m_EngineOwned )
JS_RemoveRoot( g_ScriptingHost.GetContext(), &m_JS );
JS_RemoveObjectRoot( g_ScriptingHost.GetContext(), &m_JS );
m_JS = NULL;
}
}
@ -393,26 +394,34 @@ public:
// Functions and data that must be provided to JavaScript
//
private:
static JSBool JSGetProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp )
static JSBool JSGetProperty( JSContext* cx, JSObject* obj, jsid id, jsval* vp )
{
T* Instance = ToNative<T>( cx, obj );
if( !Instance )
return( JS_TRUE );
CStrW PropName = g_ScriptingHost.ValueToUCString( id );
jsval idval;
if( !JS_IdToValue( cx, id, &idval ) )
return( JS_FALSE );
CStrW PropName = g_ScriptingHost.ValueToUCString( idval );
if( !Instance->GetProperty( cx, PropName, vp ) )
return( JS_TRUE );
return( JS_TRUE );
}
static JSBool JSSetProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp )
static JSBool JSSetProperty( JSContext* cx, JSObject* obj, jsid id, jsval* vp )
{
T* Instance = ToNative<T>( cx, obj );
if( !Instance )
return( JS_TRUE );
CStrW PropName = g_ScriptingHost.ValueToUCString( id );
jsval idval;
if( !JS_IdToValue( cx, id, &idval ) )
return( JS_FALSE );
CStrW PropName = g_ScriptingHost.ValueToUCString( idval );
Instance->SetProperty( cx, PropName, vp );

View File

@ -94,7 +94,9 @@ void ScriptingHost::RunScript(const VfsPath& pathname, JSObject* globalObject)
utf16string script(scriptw.begin(), scriptw.end());
jsval rval;
JSBool ok = JS_EvaluateUCScript(m_Context, globalObject, script.c_str(), (uintN)script.size(), CStr(pathname.string()).c_str(), 1, &rval);
JSBool ok = JS_EvaluateUCScript(m_Context, globalObject,
reinterpret_cast<const jschar*>(script.c_str()), (uintN)script.size(),
CStr(pathname.string()).c_str(), 1, &rval);
if (ok == JS_FALSE)
throw PSERROR_Scripting_LoadFile_EvalErrors();
@ -105,7 +107,8 @@ jsval ScriptingHost::ExecuteScript(const CStrW& script, const CStrW& calledFrom,
jsval rval;
JSBool ok = JS_EvaluateUCScript(m_Context, contextObject ? contextObject : m_GlobalObject,
script.utf16().c_str(), (int)script.length(), CStr(calledFrom), 1, &rval);
reinterpret_cast<const jschar*>(script.utf16().c_str()), (int)script.length(),
CStr(calledFrom), 1, &rval);
if (!ok) return JSVAL_NULL;
@ -168,12 +171,10 @@ jsval ScriptingHost::GetObjectProperty( JSObject* object, const std::string& pro
void ScriptingHost::SetObjectProperty_Double(JSObject* object, const char* propertyName, double value)
{
jsdouble* d = JS_NewDouble(m_Context, value);
if (! d)
jsval v;
if (! JS_NewNumberValue(m_Context, value, &v))
throw PSERROR_Scripting_ConversionFailed();
jsval v = DOUBLE_TO_JSVAL(d);
if (! JS_SetProperty(m_Context, object, propertyName, &v))
throw PSERROR_Scripting_ConversionFailed();
}
@ -203,15 +204,6 @@ void ScriptingHost::SetGlobal(const std::string &globalName, jsval value)
// conversions
//----------------------------------------------------------------------------
std::string ScriptingHost::ValueToString(const jsval value)
{
JSString* string = JS_ValueToString(m_Context, value);
if (string == NULL)
throw PSERROR_Scripting_ConversionFailed();
return std::string(JS_GetStringBytes(string), JS_GetStringLength(string));
}
CStrW ScriptingHost::ValueToUCString( const jsval value )
{
JSString* string = JS_ValueToString(m_Context, value);

View File

@ -111,7 +111,6 @@ public:
void SetGlobal(const std::string& globalName, jsval value);
std::string ValueToString(const jsval value);
CStrW ValueToUCString(const jsval value);
};

View File

@ -30,27 +30,10 @@
// (notably precompiled.h and i18n/ScriptInterface.cpp) want only these
// definitions without pulling in the whole of ScriptingHost.
// jstypes.h (included via jsapi.h) requires we define
// "one of XP_BEOS, XP_MAC, XP_OS2, XP_WIN or XP_UNIX".
#include "lib/config.h"
#if OS_WIN
# define XP_WIN
#elif OS_MAC
# define XP_MAC
#elif OS_BEOS
# define XP_BEOS
#else
# define XP_UNIX
#endif
// (Actually that XP_* stuff is handled by the newer scriptinterface
// code instead; this file no longer does anything interesting)
#include <js/jsapi.h>
#ifndef NDEBUG
// Used by ScriptingHost::jshook_{script,function}
# include <js/jsdbgapi.h>
#endif
// include any further required headers here
#include "scriptinterface/ScriptTypes.h"
#include "JSUtil.h"

View File

@ -47,4 +47,15 @@ void AutoGCRooter::Trace(JSTracer* trc)
{
JS_CALL_VALUE_TRACER(trc, m_Vals[i], "AutoGCRooter val");
}
for (size_t i = 0; i < m_IdArrays.size(); ++i)
{
for (jsint j = 0; j < m_IdArrays[i]->length; ++j)
{
jsval val = JSVAL_VOID;
JS_IdToValue(m_ScriptInterface.GetContext(), m_IdArrays[i]->vector[j], &val);
JS_CALL_VALUE_TRACER(trc, val, "AutoGCRooter id array");
}
}
}

View File

@ -22,30 +22,6 @@
#include "js/jsapi.h"
// Exception-safety and GC-safety wrapper for JSIdArray
// (TODO: it'd be nicer to use the existing js::AutoIdArray but currently that
// requires a load of semi-private SpiderMonkey headers that cause a load of compile warnings)
class IdArrayWrapper
{
JSContext* m_cx;
JSIdArray* m_ida;
public:
IdArrayWrapper(JSContext* cx, JSIdArray* ida) :
m_cx(cx), m_ida(ida)
{
for (jsint i = 0; i < m_ida->length; ++i)
if (!JS_AddRoot(m_cx, &m_ida->vector[i]))
debug_warn(L"JS_AddRoot failed");
}
~IdArrayWrapper()
{
for (jsint i = 0; i < m_ida->length; ++i)
if (!JS_RemoveRoot(m_cx, &m_ida->vector[i]))
debug_warn(L"JS_RemoveRoot failed");
JS_DestroyIdArray(m_cx, m_ida);
}
};
/**
* Helper for rooting large groups of script values.
* Construct this object, push values into it, and they will all be rooted until this
@ -61,6 +37,7 @@ public:
void Push(JSObject* obj) { m_Objects.push_back(obj); }
void Push(jsval val) { m_Vals.push_back(val); }
void Push(JSIdArray* ida) { m_IdArrays.push_back(ida); }
void Trace(JSTracer* trc);
private:
@ -69,6 +46,7 @@ private:
std::vector<JSObject*> m_Objects;
std::vector<jsval> m_Vals;
std::vector<JSIdArray*> m_IdArrays;
// TODO: add vectors of other value types
};

View File

@ -21,18 +21,19 @@
#include "ps/utf16string.h"
#include "ps/CLogger.h"
#include "ps/CStr.h"
#include "js/jsapi.h"
#define FAIL(msg) STMT(JS_ReportError(cx, msg); return false)
// Implicit type conversions often hide bugs, so warn about them
#define WARN_IF_NOT(c) STMT(if (!(c)) { JS_ReportWarning(cx, "Script value conversion check failed: %s", #c); })
#define WARN_IF_NOT(c, v) STMT(if (!(c)) { JS_ReportWarning(cx, "Script value conversion check failed: %s (got type %s)", #c, JS_GetTypeName(cx, JS_TypeOfValue(cx, v))); })
template<> bool ScriptInterface::FromJSVal<bool>(JSContext* cx, jsval v, bool& out)
{
JSBool ret;
WARN_IF_NOT(JSVAL_IS_BOOLEAN(v));
WARN_IF_NOT(JSVAL_IS_BOOLEAN(v), v);
if (!JS_ValueToBoolean(cx, v, &ret))
return false;
out = (ret ? true : false);
@ -42,7 +43,7 @@ template<> bool ScriptInterface::FromJSVal<bool>(JSContext* cx, jsval v, bool& o
template<> bool ScriptInterface::FromJSVal<float>(JSContext* cx, jsval v, float& out)
{
jsdouble ret;
WARN_IF_NOT(JSVAL_IS_NUMBER(v));
WARN_IF_NOT(JSVAL_IS_NUMBER(v), v);
if (!JS_ValueToNumber(cx, v, &ret))
return false;
out = ret;
@ -52,7 +53,7 @@ template<> bool ScriptInterface::FromJSVal<float>(JSContext* cx, jsval v, float&
template<> bool ScriptInterface::FromJSVal<double>(JSContext* cx, jsval v, double& out)
{
jsdouble ret;
WARN_IF_NOT(JSVAL_IS_NUMBER(v));
WARN_IF_NOT(JSVAL_IS_NUMBER(v), v);
if (!JS_ValueToNumber(cx, v, &ret))
return false;
out = ret;
@ -62,7 +63,7 @@ template<> bool ScriptInterface::FromJSVal<double>(JSContext* cx, jsval v, doubl
template<> bool ScriptInterface::FromJSVal<i32>(JSContext* cx, jsval v, i32& out)
{
int32 ret;
WARN_IF_NOT(JSVAL_IS_INT(v));
WARN_IF_NOT(JSVAL_IS_NUMBER(v), v);
if (!JS_ValueToECMAInt32(cx, v, &ret))
return false;
out = ret;
@ -72,7 +73,7 @@ template<> bool ScriptInterface::FromJSVal<i32>(JSContext* cx, jsval v, i32& out
template<> bool ScriptInterface::FromJSVal<u32>(JSContext* cx, jsval v, u32& out)
{
uint32 ret;
WARN_IF_NOT(JSVAL_IS_INT(v));
WARN_IF_NOT(JSVAL_IS_NUMBER(v), v);
if (!JS_ValueToECMAUint32(cx, v, &ret))
return false;
out = ret;
@ -94,7 +95,7 @@ template<> bool ScriptInterface::FromJSVal<CScriptValRooted>(JSContext* cx, jsva
template<> bool ScriptInterface::FromJSVal<std::wstring>(JSContext* cx, jsval v, std::wstring& out)
{
WARN_IF_NOT(JSVAL_IS_STRING(v));
WARN_IF_NOT(JSVAL_IS_STRING(v) || JSVAL_IS_NUMBER(v), v); // allow implicit number conversions
JSString* ret = JS_ValueToString(cx, v);
if (!ret)
FAIL("Argument must be convertible to a string");
@ -105,15 +106,15 @@ template<> bool ScriptInterface::FromJSVal<std::wstring>(JSContext* cx, jsval v,
template<> bool ScriptInterface::FromJSVal<std::string>(JSContext* cx, jsval v, std::string& out)
{
WARN_IF_NOT(JSVAL_IS_STRING(v));
WARN_IF_NOT(JSVAL_IS_STRING(v) || JSVAL_IS_NUMBER(v), v); // allow implicit number conversions
JSString* ret = JS_ValueToString(cx, v);
if (!ret)
FAIL("Argument must be convertible to a string");
char* ch = JS_GetStringBytes(ret);
char* ch = JS_EncodeString(cx, ret); // chops off high byte of each jschar
if (!ch)
FAIL("JS_EncodeString failed"); // out of memory
out = std::string(ch, ch + JS_GetStringLength(ret));
// TODO: if JS_GetStringBytes fails it'll return a zero-length string
// and we'll overflow its bounds by using JS_GetStringLength - should
// use one of the new SpiderMonkey 1.8 functions instead
JS_free(cx, ch);
return true;
}
@ -139,13 +140,10 @@ template<> jsval ScriptInterface::ToJSVal<double>(JSContext* cx, const double& v
return rval;
}
template<> jsval ScriptInterface::ToJSVal<i32>(JSContext* cx, const i32& val)
template<> jsval ScriptInterface::ToJSVal<i32>(JSContext* UNUSED(cx), const i32& val)
{
if (INT_FITS_IN_JSVAL(val))
return INT_TO_JSVAL(val);
jsval rval = JSVAL_VOID;
JS_NewNumberValue(cx, val, &rval); // ignore return value
return rval;
cassert(JSVAL_INT_BITS == 32);
return INT_TO_JSVAL(val);
}
template<> jsval ScriptInterface::ToJSVal<u32>(JSContext* cx, const u32& val)
@ -185,6 +183,11 @@ template<> jsval ScriptInterface::ToJSVal<std::string>(JSContext* cx, const std:
return JSVAL_VOID;
}
template<> jsval ScriptInterface::ToJSVal<const wchar_t*>(JSContext* cx, const wchar_t* const& val)
{
return ToJSVal(cx, std::wstring(val));
}
template<> jsval ScriptInterface::ToJSVal<const char*>(JSContext* cx, const char* const& val)
{
JSString* str = JS_NewStringCopyZ(cx, val);
@ -193,6 +196,16 @@ template<> jsval ScriptInterface::ToJSVal<const char*>(JSContext* cx, const char
return JSVAL_VOID;
}
template<> jsval ScriptInterface::ToJSVal<CStrW>(JSContext* cx, const CStrW& val)
{
return ToJSVal(cx, static_cast<const std::wstring&>(val));
}
template<> jsval ScriptInterface::ToJSVal<CStr8>(JSContext* cx, const CStr8& val)
{
return ToJSVal(cx, static_cast<const std::string&>(val));
}
////////////////////////////////////////////////////////////////
// Compound types:
@ -201,13 +214,11 @@ template<typename T> static jsval ToJSVal_vector(JSContext* cx, const std::vecto
JSObject* obj = JS_NewArrayObject(cx, 0, NULL);
if (!obj)
return JSVAL_VOID;
JS_AddRoot(cx, &obj);
for (size_t i = 0; i < val.size(); ++i)
{
jsval el = ScriptInterface::ToJSVal<T>(cx, val[i]);
JS_SetElement(cx, obj, (jsint)i, &el);
}
JS_RemoveRoot(cx, &obj);
return OBJECT_TO_JSVAL(obj);
}

View File

@ -40,7 +40,9 @@ const int RUNTIME_SIZE = 16 * 1024 * 1024; // TODO: how much memory is needed?
const int STACK_CHUNK_SIZE = 8192;
#if ENABLE_SCRIPT_PROFILING
#include "js/jsdbgapi.h"
# define signbit std::signbit
# include "js/jsdbgapi.h"
# undef signbit
#endif
////////////////////////////////////////////////////////////////
@ -49,7 +51,7 @@ struct ScriptInterface_impl
{
ScriptInterface_impl(const char* nativeScopeName, JSContext* cx);
~ScriptInterface_impl();
void Register(const char* name, JSFastNative fptr, uintN nargs);
void Register(const char* name, JSNative fptr, uintN nargs);
JSRuntime* m_rt; // NULL if m_cx is shared; non-NULL if we own m_cx
JSContext* m_cx;
@ -109,7 +111,7 @@ void ErrorReporter(JSContext* cx, const char* message, JSErrorReport* report)
LOGERROR(L"%hs", msg.str().c_str());
// When running under Valgrind, print more information in the error message
VALGRIND_PRINTF_BACKTRACE("->");
// VALGRIND_PRINTF_BACKTRACE("->");
}
// Functions in the global namespace:
@ -276,7 +278,11 @@ ScriptInterface_impl::ScriptInterface_impl(const char* nativeScopeName, JSContex
JS_SetOptions(m_cx, JSOPTION_STRICT // "warn on dubious practice"
| JSOPTION_XML // "ECMAScript for XML support: parse <!-- --> as a token"
| JSOPTION_VAROBJFIX // "recommended" (fixes variable scoping)
// Enable all the JIT features:
// | JSOPTION_JIT
// | JSOPTION_METHODJIT
// | JSOPTION_PROFILING
);
JS_SetVersion(m_cx, JSVERSION_LATEST);
@ -286,7 +292,7 @@ ScriptInterface_impl::ScriptInterface_impl(const char* nativeScopeName, JSContex
// Threadsafe SpiderMonkey requires that we have a request before doing anything much
JS_BeginRequest(m_cx);
m_glob = JS_NewObject(m_cx, &global_class, NULL, NULL);
m_glob = JS_NewGlobalObject(m_cx, &global_class);
ok = JS_InitStandardClasses(m_cx, m_glob);
JS_DefineProperty(m_cx, m_glob, "global", OBJECT_TO_JSVAL(m_glob), NULL, NULL, JSPROP_ENUMERATE | JSPROP_READONLY
@ -296,10 +302,10 @@ ScriptInterface_impl::ScriptInterface_impl(const char* nativeScopeName, JSContex
m_nativeScope = JS_DefineObject(m_cx, m_glob, nativeScopeName, NULL, NULL, JSPROP_ENUMERATE | JSPROP_READONLY
| JSPROP_PERMANENT);
JS_DefineFunction(m_cx, m_glob, "print", (JSNative)::print, 0, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT | JSFUN_FAST_NATIVE);
JS_DefineFunction(m_cx, m_glob, "log", (JSNative)::logmsg, 1, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT | JSFUN_FAST_NATIVE);
JS_DefineFunction(m_cx, m_glob, "warn", (JSNative)::warn, 1, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT | JSFUN_FAST_NATIVE);
JS_DefineFunction(m_cx, m_glob, "error", (JSNative)::error, 1, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT | JSFUN_FAST_NATIVE);
JS_DefineFunction(m_cx, m_glob, "print", ::print, 0, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT);
JS_DefineFunction(m_cx, m_glob, "log", ::logmsg, 1, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT);
JS_DefineFunction(m_cx, m_glob, "warn", ::warn, 1, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT);
JS_DefineFunction(m_cx, m_glob, "error", ::error, 1, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT);
}
ScriptInterface_impl::~ScriptInterface_impl()
@ -312,9 +318,9 @@ ScriptInterface_impl::~ScriptInterface_impl()
}
}
void ScriptInterface_impl::Register(const char* name, JSFastNative fptr, uintN nargs)
void ScriptInterface_impl::Register(const char* name, JSNative fptr, uintN nargs)
{
JS_DefineFunction(m_cx, m_nativeScope, name, reinterpret_cast<JSNative>(fptr), nargs, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT | JSFUN_FAST_NATIVE);
JS_DefineFunction(m_cx, m_nativeScope, name, fptr, nargs, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT);
}
ScriptInterface::ScriptInterface(const char* nativeScopeName, const char* debugName) :
@ -361,8 +367,8 @@ void ScriptInterface::ReplaceNondeterministicFunctions(boost::rand48& rng)
return;
}
JSFunction* random = JS_DefineFunction(m->m_cx, JSVAL_TO_OBJECT(math), "random", (JSNative)Math_random, 0,
JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT | JSFUN_FAST_NATIVE);
JSFunction* random = JS_DefineFunction(m->m_cx, JSVAL_TO_OBJECT(math), "random", Math_random, 0,
JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT);
if (!random)
{
LOGERROR(L"ReplaceNondeterministicFunctions: failed to replace Math.random");
@ -372,7 +378,7 @@ void ScriptInterface::ReplaceNondeterministicFunctions(boost::rand48& rng)
JS_SetReservedSlot(m->m_cx, JS_GetFunctionObject(random), 0, PRIVATE_TO_JSVAL(&rng));
}
void ScriptInterface::Register(const char* name, JSFastNative fptr, size_t nargs)
void ScriptInterface::Register(const char* name, JSNative fptr, size_t nargs)
{
m->Register(name, fptr, (uintN)nargs);
}
@ -387,16 +393,6 @@ JSRuntime* ScriptInterface::GetRuntime() const
return m->m_rt;
}
bool ScriptInterface::AddRoot(void* ptr, const char* name)
{
return JS_AddNamedRoot(m->m_cx, ptr, name) ? true : false;
}
bool ScriptInterface::RemoveRoot(void* ptr)
{
return JS_RemoveRoot(m->m_cx, ptr) ? true : false;
}
AutoGCRooter* ScriptInterface::ReplaceAutoGCRooter(AutoGCRooter* rooter)
{
debug_assert(m->m_rt); // this class must own the runtime, else the rooter won't work
@ -405,30 +401,6 @@ AutoGCRooter* ScriptInterface::ReplaceAutoGCRooter(AutoGCRooter* rooter)
return ret;
}
ScriptInterface::LocalRootScope::LocalRootScope(JSContext* cx) :
m_cx(cx)
{
m_OK = JS_EnterLocalRootScope(m_cx) ? true : false;
}
ScriptInterface::LocalRootScope::~LocalRootScope()
{
if (m_OK)
JS_LeaveLocalRootScope(m_cx);
}
bool ScriptInterface::LocalRootScope::OK()
{
return m_OK;
}
void ScriptInterface::LocalRootScope::LeaveWithResult(jsval val)
{
if (m_OK)
JS_LeaveLocalRootScopeWithResult(m_cx, val);
m_OK = false;
}
jsval ScriptInterface::CallConstructor(jsval ctor)
{
@ -494,19 +466,14 @@ bool ScriptInterface::CallFunction_(jsval val, const char* name, size_t argc, js
JSObject* obj;
if (!JS_ValueToObject(m->m_cx, val, &obj) || obj == NULL)
return false;
JS_AddRoot(m->m_cx, &obj);
// Check that the named function actually exists, to avoid ugly JS error reports
// when calling an undefined value
JSBool found;
if (!JS_HasProperty(m->m_cx, obj, name, &found) || !found)
{
JS_RemoveRoot(m->m_cx, &obj);
return false;
}
JSBool ok = JS_CallFunctionName(m->m_cx, obj, name, (uintN)argc, argv, &ret);
JS_RemoveRoot(m->m_cx, &obj);
return ok ? true : false;
}
@ -516,6 +483,11 @@ jsval ScriptInterface::GetGlobalObject()
return OBJECT_TO_JSVAL(JS_GetGlobalObject(m->m_cx));
}
JSClass* ScriptInterface::GetGlobalClass()
{
return &global_class;
}
bool ScriptInterface::SetGlobal_(const char* name, jsval value, bool replace)
{
if (!replace)
@ -577,8 +549,6 @@ bool ScriptInterface::HasProperty(jsval obj, const char* name)
bool ScriptInterface::EnumeratePropertyNamesWithPrefix(jsval obj, const char* prefix, std::vector<std::string>& out)
{
LOCAL_ROOT_SCOPE;
utf16string prefix16 (prefix, prefix+strlen(prefix));
if (! JSVAL_IS_OBJECT(obj))
@ -638,10 +608,8 @@ bool ScriptInterface::LoadScript(const std::wstring& filename, const std::wstrin
if (!func)
return false;
JS_AddRoot(m->m_cx, &func); // TODO: do we need to root this?
jsval scriptRval;
JSBool ok = JS_CallFunction(m->m_cx, NULL, func, 0, NULL, &scriptRval);
JS_RemoveRoot(m->m_cx, &func);
return ok ? true : false;
}
@ -687,7 +655,7 @@ CScriptValRooted ScriptInterface::ParseJSON(const utf16string& string)
return CScriptValRooted();
}
if (!JS_ConsumeJSONText(m->m_cx, parser, string.c_str(), (uint32)string.size()))
if (!JS_ConsumeJSONText(m->m_cx, parser, reinterpret_cast<const jschar*>(string.c_str()), (uint32)string.size()))
{
LOGERROR(L"ParseJSON failed to consume");
return CScriptValRooted();
@ -786,7 +754,7 @@ class ValueCloner
{
public:
ValueCloner(ScriptInterface& from, ScriptInterface& to) :
cxFrom(from.GetContext()), cxTo(to.GetContext()), m_RooterFrom(from), m_RooterTo(to)
scriptInterfaceFrom(from), cxFrom(from.GetContext()), cxTo(to.GetContext()), m_RooterFrom(from), m_RooterTo(to)
{
}
@ -796,7 +764,7 @@ public:
if (!JSVAL_IS_GCTHING(val) || JSVAL_IS_NULL(val))
return val;
std::map<jsval, jsval>::iterator it = m_Mapping.find(val);
std::map<void*, jsval>::iterator it = m_Mapping.find(JSVAL_TO_GCTHING(val));
if (it != m_Mapping.end())
return it->second;
@ -815,8 +783,7 @@ private:
if (JSVAL_IS_DOUBLE(val))
{
jsval rval;
CLONE_REQUIRE(JS_NewNumberValue(cxTo, *JSVAL_TO_DOUBLE(val), &rval), L"JS_NewNumberValue");
m_Mapping[val] = rval;
CLONE_REQUIRE(JS_NewNumberValue(cxTo, JSVAL_TO_DOUBLE(val), &rval), L"JS_NewNumberValue");
m_RooterTo.Push(rval);
return rval;
}
@ -826,7 +793,7 @@ private:
JSString* str = JS_NewUCStringCopyN(cxTo, JS_GetStringChars(JSVAL_TO_STRING(val)), JS_GetStringLength(JSVAL_TO_STRING(val)));
CLONE_REQUIRE(str, L"JS_NewUCStringCopyN");
jsval rval = STRING_TO_JSVAL(str);
m_Mapping[val] = rval;
m_Mapping[JSVAL_TO_GCTHING(val)] = rval;
m_RooterTo.Push(rval);
return rval;
}
@ -847,17 +814,18 @@ private:
CLONE_REQUIRE(newObj, L"JS_NewObject");
}
m_Mapping[val] = OBJECT_TO_JSVAL(newObj);
m_Mapping[JSVAL_TO_GCTHING(val)] = OBJECT_TO_JSVAL(newObj);
m_RooterTo.Push(newObj);
JSIdArray* ida = JS_Enumerate(cxFrom, JSVAL_TO_OBJECT(val));
CLONE_REQUIRE(ida, L"JS_Enumerate");
AutoJSIdArray ida (cxFrom, JS_Enumerate(cxFrom, JSVAL_TO_OBJECT(val)));
CLONE_REQUIRE(ida.get(), L"JS_Enumerate");
IdArrayWrapper idaWrapper(cxFrom, ida);
AutoGCRooter idaRooter(scriptInterfaceFrom);
idaRooter.Push(ida.get());
for (jsint i = 0; i < ida->length; ++i)
for (size_t i = 0; i < ida.length(); ++i)
{
jsid id = ida->vector[i];
jsid id = ida[i];
jsval idval, propval;
CLONE_REQUIRE(JS_IdToValue(cxFrom, id, &idval), L"JS_IdToValue");
CLONE_REQUIRE(JS_GetPropertyById(cxFrom, JSVAL_TO_OBJECT(val), id, &propval), L"JS_GetPropertyById");
@ -884,9 +852,10 @@ private:
return OBJECT_TO_JSVAL(newObj);
}
ScriptInterface& scriptInterfaceFrom;
JSContext* cxFrom;
JSContext* cxTo;
std::map<jsval, jsval> m_Mapping;
std::map<void*, jsval> m_Mapping;
AutoGCRooter m_RooterFrom;
AutoGCRooter m_RooterTo;
};

View File

@ -18,10 +18,6 @@
#ifndef INCLUDED_SCRIPTINTERFACE
#define INCLUDED_SCRIPTINTERFACE
// XXX: This is largely copied from tools/atlas/AtlasScript
// Duplication is bad - they should use a shared version of the common code,
// and just add their own extensions individually
#include <memory>
#include <vector>
#include <string>
@ -144,6 +140,8 @@ public:
jsval GetGlobalObject();
JSClass* GetGlobalClass();
/**
* Set the named property on the global object.
* If @p replace is true, an existing property will be overwritten; otherwise attempts
@ -223,9 +221,6 @@ public:
*/
template<typename T> static jsval ToJSVal(JSContext* cx, T const& val);
bool AddRoot(void* ptr, const char* name);
bool RemoveRoot(void* ptr);
AutoGCRooter* ReplaceAutoGCRooter(AutoGCRooter* rooter);
/**
@ -233,26 +228,6 @@ public:
*/
void DumpHeap();
// Helper class for automatically rooting values
class LocalRootScope
{
JSContext* m_cx;
bool m_OK;
public:
// Tries to enter local root scope, so newly created
// values won't be GCed. This might fail, so check OK()
LocalRootScope(JSContext* cx);
// Returns true if the local root scope was successfully entered
bool OK();
// Leaves the local root scope, but keeps the given return value rooted
void LeaveWithResult(jsval val);
// Leaves the local root scope
~LocalRootScope();
private:
LocalRootScope& operator=(const LocalRootScope&);
};
#define LOCAL_ROOT_SCOPE LocalRootScope scope(GetContext()); if (! scope.OK()) return false
void MaybeGC();
private:
@ -266,7 +241,7 @@ private:
static JSClass* GetClass(JSContext* cx, JSObject* obj);
static void* GetPrivate(JSContext* cx, JSObject* obj);
void Register(const char* name, JSFastNative fptr, size_t nargs);
void Register(const char* name, JSNative fptr, size_t nargs);
std::auto_ptr<ScriptInterface_impl> m;
// The nasty macro/template bits are split into a separate file so you don't have to look at them
@ -278,10 +253,10 @@ public:
// void RegisterFunction(const char* functionName);
//
// template <R, T0..., TR (*fptr) (void* cbdata, T0...)>
// static JSFastNative call;
// static JSNative call;
//
// template <R, T0..., JSClass*, TC, TR (TC:*fptr) (T0...)>
// static JSFastNative callMethod;
// static JSNative callMethod;
//
// template <dummy, T0...>
// static size_t nargs();
@ -293,7 +268,6 @@ public:
template<typename R>
bool ScriptInterface::CallFunction(jsval val, const char* name, R& ret)
{
LOCAL_ROOT_SCOPE;
jsval jsRet;
bool ok = CallFunction_(val, name, 0, NULL, jsRet);
if (!ok)
@ -304,7 +278,6 @@ bool ScriptInterface::CallFunction(jsval val, const char* name, R& ret)
template<typename T0>
bool ScriptInterface::CallFunctionVoid(jsval val, const char* name, const T0& a0)
{
LOCAL_ROOT_SCOPE;
jsval jsRet;
jsval argv[1];
argv[0] = ToJSVal(GetContext(), a0);
@ -314,7 +287,6 @@ bool ScriptInterface::CallFunctionVoid(jsval val, const char* name, const T0& a0
template<typename T0, typename T1>
bool ScriptInterface::CallFunctionVoid(jsval val, const char* name, const T0& a0, const T1& a1)
{
LOCAL_ROOT_SCOPE;
jsval jsRet;
jsval argv[2];
argv[0] = ToJSVal(GetContext(), a0);
@ -325,7 +297,6 @@ bool ScriptInterface::CallFunctionVoid(jsval val, const char* name, const T0& a0
template<typename T0, typename T1, typename T2>
bool ScriptInterface::CallFunctionVoid(jsval val, const char* name, const T0& a0, const T1& a1, const T2& a2)
{
LOCAL_ROOT_SCOPE;
jsval jsRet;
jsval argv[3];
argv[0] = ToJSVal(GetContext(), a0);
@ -337,7 +308,6 @@ bool ScriptInterface::CallFunctionVoid(jsval val, const char* name, const T0& a0
template<typename T0, typename R>
bool ScriptInterface::CallFunction(jsval val, const char* name, const T0& a0, R& ret)
{
LOCAL_ROOT_SCOPE;
jsval jsRet;
jsval argv[1];
argv[0] = ToJSVal(GetContext(), a0);
@ -350,7 +320,6 @@ bool ScriptInterface::CallFunction(jsval val, const char* name, const T0& a0, R&
template<typename T0, typename T1, typename R>
bool ScriptInterface::CallFunction(jsval val, const char* name, const T0& a0, const T1& a1, R& ret)
{
LOCAL_ROOT_SCOPE;
jsval jsRet;
jsval argv[2];
argv[0] = ToJSVal(GetContext(), a0);
@ -364,7 +333,6 @@ bool ScriptInterface::CallFunction(jsval val, const char* name, const T0& a0, co
template<typename T0, typename T1, typename T2, typename R>
bool ScriptInterface::CallFunction(jsval val, const char* name, const T0& a0, const T1& a1, const T2& a2, R& ret)
{
LOCAL_ROOT_SCOPE;
jsval jsRet;
jsval argv[3];
argv[0] = ToJSVal(GetContext(), a0);
@ -379,14 +347,12 @@ bool ScriptInterface::CallFunction(jsval val, const char* name, const T0& a0, co
template<typename T>
bool ScriptInterface::SetGlobal(const char* name, const T& value, bool replace)
{
LOCAL_ROOT_SCOPE;
return SetGlobal_(name, ToJSVal(GetContext(), value), replace);
}
template<typename T>
bool ScriptInterface::SetProperty(jsval obj, const char* name, const T& value, bool readonly)
{
LOCAL_ROOT_SCOPE;
return SetProperty_(obj, name, ToJSVal(GetContext(), value), readonly);
}

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2009 Wildfire Games.
/* Copyright (C) 2010 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -20,13 +20,19 @@
#ifdef _WIN32
# define XP_WIN
# define WIN32 // SpiderMonkey expects this
// The jsval struct type causes crashes due to weird miscompilation
// issues in (at least) VC2008, so force it to be the less-type-safe
// non-struct type instead
# define JS_NO_JSVAL_JSID_STRUCT_TYPES
#else
# define XP_UNIX
#endif
// (we don't support XP_OS2 or XP_BEOS)
#include "js/jspubtd.h"
#include "js/jsversion.h"
#include "js/jsapi.h"
#if JS_VERSION != 185
#error Your compiler is trying to use an incorrect version of the SpiderMonkey library.

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2009 Wildfire Games.
/* Copyright (C) 2010 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -24,21 +24,21 @@
struct Unrooter
{
Unrooter(JSContext* cx) : cx(cx) { }
void operator()(jsval* p) { JS_RemoveRoot(cx, p); delete p; }
void operator()(jsval* p) { JS_RemoveValueRoot(cx, p); delete p; }
JSContext* cx;
};
CScriptValRooted::CScriptValRooted(JSContext* cx, jsval val)
{
jsval* p = new jsval(val);
JS_AddNamedRoot(cx, p, "CScriptValRooted");
JS_AddNamedValueRoot(cx, p, "CScriptValRooted");
m_Val = boost::shared_ptr<jsval>(p, Unrooter(cx));
}
CScriptValRooted::CScriptValRooted(JSContext* cx, CScriptVal val)
{
jsval* p = new jsval(val.get());
JS_AddNamedRoot(cx, p, "CScriptValRooted");
JS_AddNamedValueRoot(cx, p, "CScriptValRooted");
m_Val = boost::shared_ptr<jsval>(p, Unrooter(cx));
}
@ -49,12 +49,47 @@ jsval CScriptValRooted::get() const
return *m_Val;
}
jsval& CScriptValRooted::getRef() const
{
debug_assert(m_Val);
return *m_Val;
}
bool CScriptValRooted::undefined() const
{
return (!m_Val || *m_Val == JSVAL_VOID);
return (!m_Val || JSVAL_IS_VOID(*m_Val));
}
bool CScriptValRooted::uninitialised() const
{
return !m_Val;
}
AutoJSIdArray::AutoJSIdArray(JSContext* cx, JSIdArray* ida) :
m_Context(cx), m_IdArray(ida)
{
}
AutoJSIdArray::~AutoJSIdArray()
{
if (m_IdArray)
JS_DestroyIdArray(m_Context, m_IdArray);
}
JSIdArray* AutoJSIdArray::get() const
{
return m_IdArray;
}
size_t AutoJSIdArray::length() const
{
debug_assert(m_IdArray);
return m_IdArray->length;
}
jsid AutoJSIdArray::operator[](size_t i) const
{
debug_assert(m_IdArray);
debug_assert(i < (size_t)m_IdArray->length);
return m_IdArray->vector[i];
}

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2009 Wildfire Games.
/* Copyright (C) 2010 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -29,10 +29,10 @@
class CScriptVal
{
public:
CScriptVal() : m_Val(0) { }
CScriptVal() : m_Val(JSVAL_VOID) { }
CScriptVal(jsval val) : m_Val(val) { }
jsval get() const { return m_Val; }
const jsval& get() const { return m_Val; }
private:
jsval m_Val;
@ -45,14 +45,48 @@ public:
CScriptValRooted(JSContext* cx, jsval val);
CScriptValRooted(JSContext* cx, CScriptVal val);
/**
* Returns the current value (or JSVAL_VOID if uninitialised).
*/
jsval get() const;
/**
* Returns reference to the current value.
* Fails if the value is not yet initialised.
*/
jsval& getRef() const;
/**
* Returns whether the value is uninitialised or is JSVAL_VOID.
*/
bool undefined() const;
/**
* Returns whether the value is uninitialised.
*/
bool uninitialised() const;
private:
boost::shared_ptr<jsval> m_Val;
};
/**
* RAII wrapper for JSIdArray*
*/
class AutoJSIdArray
{
NONCOPYABLE(AutoJSIdArray);
public:
AutoJSIdArray(JSContext* cx, JSIdArray* ida);
~AutoJSIdArray();
JSIdArray* get() const;
size_t length() const;
jsid operator[](size_t i) const;
private:
JSContext* m_Context;
JSIdArray* m_IdArray;
};
#endif // INCLUDED_SCRIPTVAL

View File

@ -34,7 +34,6 @@ class TestScriptConversions : public CxxTest::TestSuite
JSContext* cx = script.GetContext();
jsval v1 = ScriptInterface::ToJSVal(cx, value);
JS_AddRoot(cx, &v1);
// We want to convert values to strings, but can't just call toSource() on them
// since they might not be objects. So just use uneval.
@ -42,8 +41,6 @@ class TestScriptConversions : public CxxTest::TestSuite
TS_ASSERT(script.CallFunction(OBJECT_TO_JSVAL(JS_GetGlobalObject(cx)), "uneval", CScriptVal(v1), source));
TS_ASSERT_STR_EQUALS(source, expected);
JS_RemoveRoot(cx, &v1);
}
template <typename T>
@ -53,7 +50,6 @@ class TestScriptConversions : public CxxTest::TestSuite
JSContext* cx = script.GetContext();
jsval v1 = ScriptInterface::ToJSVal(cx, value);
JS_AddRoot(cx, &v1);
std::string source;
TS_ASSERT(script.CallFunction(OBJECT_TO_JSVAL(JS_GetGlobalObject(cx)), "uneval", CScriptVal(v1), source));
@ -64,8 +60,6 @@ class TestScriptConversions : public CxxTest::TestSuite
T v2 = T();
TS_ASSERT(ScriptInterface::FromJSVal(script.GetContext(), v1, v2));
TS_ASSERT_EQUALS(value, v2);
JS_RemoveRoot(cx, &v1);
}
public:
@ -132,18 +126,16 @@ public:
TS_ASSERT(JSVAL_IS_INT(ScriptInterface::ToJSVal<i32>(cx, 0)));
TS_ASSERT(JSVAL_IS_INT(ScriptInterface::ToJSVal<i32>(cx, 1073741822))); // JSVAL_INT_MAX-1
TS_ASSERT(JSVAL_IS_INT(ScriptInterface::ToJSVal<i32>(cx, 1073741823))); // JSVAL_INT_MAX
TS_ASSERT(JSVAL_IS_DOUBLE(ScriptInterface::ToJSVal<i32>(cx, 1073741824))); // JSVAL_INT_MAX+1
TS_ASSERT(JSVAL_IS_INT(ScriptInterface::ToJSVal<i32>(cx, -1073741823))); // JSVAL_INT_MIN+1
TS_ASSERT(JSVAL_IS_INT(ScriptInterface::ToJSVal<i32>(cx, -1073741824))); // JSVAL_INT_MIN
TS_ASSERT(JSVAL_IS_DOUBLE(ScriptInterface::ToJSVal<i32>(cx, -1073741825))); // JSVAL_INT_MIN-1
TS_ASSERT(JSVAL_IS_INT(ScriptInterface::ToJSVal<i32>(cx, 2147483646))); // JSVAL_INT_MAX-1
TS_ASSERT(JSVAL_IS_INT(ScriptInterface::ToJSVal<i32>(cx, 2147483647))); // JSVAL_INT_MAX
TS_ASSERT(JSVAL_IS_INT(ScriptInterface::ToJSVal<i32>(cx, -2147483647))); // JSVAL_INT_MIN+1
TS_ASSERT(JSVAL_IS_INT(ScriptInterface::ToJSVal<i32>(cx, -(i64)2147483648))); // JSVAL_INT_MIN
TS_ASSERT(JSVAL_IS_INT(ScriptInterface::ToJSVal<u32>(cx, 0)));
TS_ASSERT(JSVAL_IS_INT(ScriptInterface::ToJSVal<u32>(cx, 1073741822))); // JSVAL_INT_MAX-1
TS_ASSERT(JSVAL_IS_INT(ScriptInterface::ToJSVal<u32>(cx, 1073741823))); // JSVAL_INT_MAX
TS_ASSERT(JSVAL_IS_DOUBLE(ScriptInterface::ToJSVal<u32>(cx, 1073741824))); // JSVAL_INT_MAX+1
TS_ASSERT(JSVAL_IS_INT(ScriptInterface::ToJSVal<u32>(cx, 2147483646))); // JSVAL_INT_MAX-1
TS_ASSERT(JSVAL_IS_INT(ScriptInterface::ToJSVal<u32>(cx, 2147483647))); // JSVAL_INT_MAX
TS_ASSERT(JSVAL_IS_DOUBLE(ScriptInterface::ToJSVal<u32>(cx, 2147483648))); // JSVAL_INT_MAX+1
}
void test_nonfinite()

View File

@ -136,7 +136,7 @@ public:
TS_ASSERT(script.Eval(input.c_str(), val));
std::string stringified = script.StringifyJSON(val.get());
TS_ASSERT_STR_EQUALS(stringified, "{\n \"x\":1,\n \"z\":[2,\n \"3\xE2\x98\xBA\xEF\xBF\xBD\"\n ],\n \"y\":true\n}");
TS_ASSERT_STR_EQUALS(stringified, "{\n \"x\": 1,\n \"z\": [\n 2,\n \"3\xE2\x98\xBA\xEF\xBF\xBD\"\n ],\n \"y\": true\n}");
val = script.ParseJSON(stringified);
TS_ASSERT_WSTR_EQUALS(script.ToString(val.get()), L"({x:1, z:[2, \"3\\u263A\\uFFFD\"], y:true})");

View File

@ -32,10 +32,6 @@ CScriptVal ICmpFootprint::GetShape_wrapper()
JSContext* cx = GetSimContext().GetScriptInterface().GetContext();
ScriptInterface::LocalRootScope scope(cx);
if (!scope.OK())
return JSVAL_VOID;
JSObject* obj = JS_NewObject(cx, NULL, NULL, NULL);
if (!obj)
return JSVAL_VOID;

View File

@ -37,7 +37,7 @@ template<> jsval ScriptInterface::ToJSVal<IComponent*>(JSContext* cx, IComponent
// If this is a scripted component, just return the JS object directly
jsval instance = val->GetJSInstance();
if (instance)
if (!JSVAL_IS_NULL(instance))
return instance;
// Otherwise we need to construct a wrapper object
@ -72,7 +72,7 @@ static jsval ConvertCParamNode(JSContext* cx, CParamNode const& val)
// Just a string
utf16string text(val.ToString().begin(), val.ToString().end());
JSString* str = JS_InternUCStringN(cx, text.data(), text.length());
JSString* str = JS_InternUCStringN(cx, reinterpret_cast<const jschar*>(text.data()), text.length());
if (str)
return STRING_TO_JSVAL(str);
// TODO: report error
@ -97,7 +97,7 @@ static jsval ConvertCParamNode(JSContext* cx, CParamNode const& val)
if (!val.ToString().empty())
{
utf16string text(val.ToString().begin(), val.ToString().end());
JSString* str = JS_InternUCStringN(cx, text.data(), text.length());
JSString* str = JS_InternUCStringN(cx, reinterpret_cast<const jschar*>(text.data()), text.length());
if (!str)
return JSVAL_VOID; // TODO: report error
jsval childVal = STRING_TO_JSVAL(str);
@ -135,10 +135,6 @@ template<> jsval ScriptInterface::ToJSVal<const CParamNode*>(JSContext* cx, cons
template<> bool ScriptInterface::FromJSVal<CColor>(JSContext* cx, jsval v, CColor& out)
{
ScriptInterface::LocalRootScope scope(cx);
if (!scope.OK())
return false;
if (!JSVAL_IS_OBJECT(v))
return false; // TODO: report type error
JSObject* obj = JSVAL_TO_OBJECT(v);
@ -160,10 +156,6 @@ template<> bool ScriptInterface::FromJSVal<CColor>(JSContext* cx, jsval v, CColo
template<> jsval ScriptInterface::ToJSVal<CColor>(JSContext* cx, CColor const& val)
{
ScriptInterface::LocalRootScope scope(cx);
if (!scope.OK())
return JSVAL_VOID;
JSObject* obj = JS_NewObject(cx, NULL, NULL, NULL);
if (!obj)
return JSVAL_VOID;
@ -201,10 +193,6 @@ template<> jsval ScriptInterface::ToJSVal<fixed>(JSContext* cx, const fixed& val
template<> bool ScriptInterface::FromJSVal<CFixedVector3D>(JSContext* cx, jsval v, CFixedVector3D& out)
{
ScriptInterface::LocalRootScope scope(cx);
if (!scope.OK())
return false;
if (!JSVAL_IS_OBJECT(v))
return false; // TODO: report type error
JSObject* obj = JSVAL_TO_OBJECT(v);
@ -225,10 +213,6 @@ template<> bool ScriptInterface::FromJSVal<CFixedVector3D>(JSContext* cx, jsval
template<> jsval ScriptInterface::ToJSVal<CFixedVector3D>(JSContext* cx, const CFixedVector3D& val)
{
ScriptInterface::LocalRootScope scope(cx);
if (!scope.OK())
return JSVAL_VOID;
JSObject* obj = JS_NewObject(cx, NULL, NULL, NULL);
if (!obj)
return JSVAL_VOID;
@ -246,10 +230,6 @@ template<> jsval ScriptInterface::ToJSVal<CFixedVector3D>(JSContext* cx, const C
template<> bool ScriptInterface::FromJSVal<CFixedVector2D>(JSContext* cx, jsval v, CFixedVector2D& out)
{
ScriptInterface::LocalRootScope scope(cx);
if (!scope.OK())
return false;
if (!JSVAL_IS_OBJECT(v))
return false; // TODO: report type error
JSObject* obj = JSVAL_TO_OBJECT(v);

View File

@ -23,9 +23,6 @@
#include "js/jsapi.h"
#define TOJSVAL_SETUP() \
ScriptInterface::LocalRootScope scope(scriptInterface.GetContext()); \
if (! scope.OK()) \
return JSVAL_VOID; \
JSObject* obj = JS_NewObject(scriptInterface.GetContext(), NULL, NULL, NULL); \
if (! obj) \
return JSVAL_VOID

View File

@ -23,30 +23,22 @@
#include "simulation2/serialization/IDeserializer.h"
CComponentTypeScript::CComponentTypeScript(ScriptInterface& scriptInterface, jsval instance) :
m_ScriptInterface(scriptInterface), m_Instance(instance)
m_ScriptInterface(scriptInterface), m_Instance(CScriptValRooted(scriptInterface.GetContext(), instance))
{
debug_assert(instance);
m_ScriptInterface.AddRoot(&m_Instance, "CComponentTypeScript.m_Instance");
// Cache the property detection for efficiency
m_HasCustomSerialize = m_ScriptInterface.HasProperty(m_Instance, "Serialize");
}
CComponentTypeScript::~CComponentTypeScript()
{
m_ScriptInterface.RemoveRoot(&m_Instance);
m_HasCustomSerialize = m_ScriptInterface.HasProperty(m_Instance.get(), "Serialize");
}
void CComponentTypeScript::Init(const CSimContext& UNUSED(context), const CParamNode& paramNode, entity_id_t ent)
{
m_ScriptInterface.SetProperty(m_Instance, "entity", (int)ent, true);
m_ScriptInterface.SetProperty(m_Instance, "template", paramNode, true);
m_ScriptInterface.CallFunctionVoid(m_Instance, "Init");
m_ScriptInterface.SetProperty(m_Instance.get(), "entity", (int)ent, true);
m_ScriptInterface.SetProperty(m_Instance.get(), "template", paramNode, true);
m_ScriptInterface.CallFunctionVoid(m_Instance.get(), "Init");
}
void CComponentTypeScript::Deinit(const CSimContext& UNUSED(context))
{
m_ScriptInterface.CallFunctionVoid(m_Instance, "Deinit");
m_ScriptInterface.CallFunctionVoid(m_Instance.get(), "Deinit");
}
void CComponentTypeScript::HandleMessage(const CSimContext& UNUSED(context), const CMessage& msg, bool global)
@ -55,7 +47,7 @@ void CComponentTypeScript::HandleMessage(const CSimContext& UNUSED(context), con
CScriptVal msgVal = msg.ToJSValCached(m_ScriptInterface);
if (!m_ScriptInterface.CallFunctionVoid(m_Instance, name, msgVal))
if (!m_ScriptInterface.CallFunctionVoid(m_Instance.get(), name, msgVal))
LOGERROR(L"Script message handler %hs failed", name);
}
@ -66,13 +58,13 @@ void CComponentTypeScript::Serialize(ISerializer& serialize)
if (m_HasCustomSerialize)
{
CScriptValRooted val;
if (!m_ScriptInterface.CallFunction(m_Instance, "Serialize", val))
if (!m_ScriptInterface.CallFunction(m_Instance.get(), "Serialize", val))
LOGERROR(L"Script Serialize call failed");
serialize.ScriptVal("object", val);
}
else
{
serialize.ScriptVal("object", m_Instance);
serialize.ScriptVal("object", m_Instance.get());
}
}
@ -82,8 +74,8 @@ void CComponentTypeScript::Deserialize(const CSimContext& UNUSED(context), const
// Use ScriptObjectAppend so we don't lose the carefully-constructed
// prototype/parent of this object
deserialize.ScriptObjectAppend("object", m_Instance);
deserialize.ScriptObjectAppend("object", m_Instance.getRef());
m_ScriptInterface.SetProperty(m_Instance, "entity", (int)ent, true);
m_ScriptInterface.SetProperty(m_Instance, "template", paramNode, true);
m_ScriptInterface.SetProperty(m_Instance.get(), "entity", (int)ent, true);
m_ScriptInterface.SetProperty(m_Instance.get(), "template", paramNode, true);
}

View File

@ -35,9 +35,8 @@ class CComponentTypeScript
{
public:
CComponentTypeScript(ScriptInterface& scriptInterface, jsval instance);
~CComponentTypeScript();
jsval GetInstance() const { return m_Instance; }
jsval GetInstance() const { return m_Instance.get(); }
void Init(const CSimContext& context, const CParamNode& paramNode, entity_id_t ent);
void Deinit(const CSimContext& context);
@ -58,7 +57,7 @@ public:
R Call(const char* funcname BOOST_PP_ENUM_TRAILING_BINARY_PARAMS(i, const T, &a)) \
{ \
R ret; \
if (m_ScriptInterface.CallFunction(m_Instance, funcname BOOST_PP_ENUM_TRAILING_PARAMS(i, a), ret)) \
if (m_ScriptInterface.CallFunction(m_Instance.get(), funcname BOOST_PP_ENUM_TRAILING_PARAMS(i, a), ret)) \
return ret; \
LOGERROR(L"Error calling component script function %hs", funcname); \
return R(); \
@ -66,7 +65,7 @@ public:
BOOST_PP_IF(i, template<, ) BOOST_PP_ENUM_PARAMS(i, typename T) BOOST_PP_IF(i, >, ) \
void CallVoid(const char* funcname BOOST_PP_ENUM_TRAILING_BINARY_PARAMS(i, const T, &a)) \
{ \
if (m_ScriptInterface.CallFunctionVoid(m_Instance, funcname BOOST_PP_ENUM_TRAILING_PARAMS(i, a))) \
if (m_ScriptInterface.CallFunctionVoid(m_Instance.get(), funcname BOOST_PP_ENUM_TRAILING_PARAMS(i, a))) \
return; \
LOGERROR(L"Error calling component script function %hs", funcname); \
}
@ -75,7 +74,7 @@ BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~)
private:
ScriptInterface& m_ScriptInterface;
jsval m_Instance;
CScriptValRooted m_Instance;
bool m_HasCustomSerialize;
NONCOPYABLE(CComponentTypeScript);

View File

@ -25,18 +25,9 @@
#include "scriptinterface/ScriptInterface.h"
// Shut up some warnings triggered by jsobj.h
#if MSC_VERSION
# pragma warning(push)
# pragma warning(disable:4512) // assignment operator could not be generated
# pragma warning(disable:4800) // forcing value to bool 'true' or 'false' (performance warning)
#endif
#include "js/jsobj.h"
#if MSC_VERSION
# pragma warning(pop)
#endif
#define signbit std::signbit
#include "js/jsvalue.h" // for JSDOUBLE_IS_INT32
#undef signbit
CBinarySerializerScriptImpl::CBinarySerializerScriptImpl(ScriptInterface& scriptInterface, ISerializer& serializer) :
m_ScriptInterface(scriptInterface), m_Serializer(serializer), m_Rooter(m_ScriptInterface),
@ -100,43 +91,18 @@ void CBinarySerializerScriptImpl::HandleScriptVal(jsval val)
// Find all properties (ordered by insertion time)
// JS_Enumerate is a bit slow (lots of memory allocation), so do the enumeration manually
// (based on the code from JS_Enumerate, using the probably less stable JSObject API):
//
// Correction: Actually array_enumerate returns an incorrect num_properties so we can't
// trust it and have to iterate over all ids before we know how many there are, so
// actually this probably isn't any faster than JS_Enumerate. Also it's less compatible
// with future JSAPI updates. This probably wasn't a great idea.
// (Note that we don't do any rooting, because we assume nothing is going to trigger GC.
// I'm not absolute certain that's necessarily a valid assumption.)
jsval iter_state, num_properties;
if (!obj->enumerate(cx, JSENUMERATE_INIT, &iter_state, &num_properties))
throw PSERROR_Serialize_ScriptError("enumerate INIT failed");
debug_assert(JSVAL_IS_INT(num_properties));
debug_assert(JSVAL_TO_INT(num_properties) >= 0);
AutoJSIdArray ida (cx, JS_Enumerate(cx, obj));
if (!ida.get())
throw PSERROR_Serialize_ScriptError("JS_Enumerate failed");
std::vector<jsid> ids;
ids.reserve(JSVAL_TO_INT(num_properties));
m_Serializer.NumberU32_Unbounded("num props", (uint32_t)ida.length());
while (true)
for (size_t i = 0; i < ida.length(); ++i)
{
jsval id;
if (!obj->enumerate(cx, JSENUMERATE_NEXT, &iter_state, &id))
throw PSERROR_Serialize_ScriptError("enumerate NEXT failed");
if (JSVAL_IS_NULL(iter_state))
break;
ids.push_back(id);
}
m_Serializer.NumberU32_Unbounded("num props", (uint32_t)ids.size());
for (size_t i = 0; i < ids.size(); ++i)
{
jsval id = ids[i];
jsid id = ida[i];
jsval idval, propval;
@ -176,15 +142,26 @@ void CBinarySerializerScriptImpl::HandleScriptVal(jsval val)
if (JSVAL_IS_INT(val))
{
m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_INT);
// jsvals are limited to JSVAL_INT_BITS == 31 bits, even on 64-bit platforms
m_Serializer.NumberI32("value", (int32_t)JSVAL_TO_INT(val), JSVAL_INT_MIN, JSVAL_INT_MAX);
m_Serializer.NumberI32_Unbounded("value", (int32_t)JSVAL_TO_INT(val));
}
else
{
debug_assert(JSVAL_IS_DOUBLE(val));
m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_DOUBLE);
jsdouble* dbl = JSVAL_TO_DOUBLE(val);
m_Serializer.NumberDouble_Unbounded("value", *dbl);
// If the value fits in an int, serialise as an int
jsdouble d = JSVAL_TO_DOUBLE(val);
int32_t i;
if (JSDOUBLE_IS_INT32(d, &i))
{
m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_INT);
m_Serializer.NumberI32_Unbounded("value", i);
}
// Otherwise serialise as a double
else
{
m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_DOUBLE);
m_Serializer.NumberDouble_Unbounded("value", d);
}
}
break;
}

View File

@ -46,7 +46,7 @@ void CStdDeserializer::AddScriptBackref(JSObject* obj)
{
std::pair<std::map<u32, JSObject*>::iterator, bool> it = m_ScriptBackrefs.insert(std::make_pair((u32)m_ScriptBackrefs.size()+1, obj));
debug_assert(it.second);
if (!JS_AddRoot(m_ScriptInterface.GetContext(), (void*)&it.first->second))
if (!JS_AddObjectRoot(m_ScriptInterface.GetContext(), &it.first->second))
throw PSERROR_Deserialize_ScriptError("JS_AddRoot failed");
}
@ -63,7 +63,7 @@ void CStdDeserializer::FreeScriptBackrefs()
std::map<u32, JSObject*>::iterator it = m_ScriptBackrefs.begin();
for (; it != m_ScriptBackrefs.end(); ++it)
{
if (!JS_RemoveRoot(m_ScriptInterface.GetContext(), (void*)&it->second))
if (!JS_RemoveObjectRoot(m_ScriptInterface.GetContext(), &it->second))
throw PSERROR_Deserialize_ScriptError("JS_RemoveRoot failed");
}
m_ScriptBackrefs.clear();

View File

@ -100,12 +100,6 @@ CComponentManager::CComponentManager(CSimContext& context, bool skipScriptFuncti
CComponentManager::~CComponentManager()
{
ResetState();
// Release GC roots
std::map<ComponentTypeId, ComponentType>::iterator it = m_ComponentTypesById.begin();
for (; it != m_ComponentTypesById.end(); ++it)
if (it->second.type == CT_Script)
m_ScriptInterface.RemoveRoot(&it->second.ctor);
}
void CComponentManager::LoadComponentTypes()
@ -194,10 +188,7 @@ void CComponentManager::Script_RegisterComponentType(void* cbdata, int iid, std:
}
}
// Clean up the old component type
componentManager->m_ScriptInterface.RemoveRoot(&componentManager->m_ComponentTypesById[cid].ctor);
// Remove its old message subscriptions
// Remove the old component type's message subscriptions
std::map<MessageTypeId, std::vector<ComponentTypeId> >::iterator it;
for (it = componentManager->m_LocalMessageSubscriptions.begin(); it != componentManager->m_LocalMessageSubscriptions.end(); ++it)
{
@ -228,15 +219,19 @@ void CComponentManager::Script_RegisterComponentType(void* cbdata, int iid, std:
}
// Construct a new ComponentType, using the wrapper's alloc functions
ComponentType ct = { CT_Script, iid, ctWrapper.alloc, ctWrapper.dealloc, cname, schema, ctor.get() };
ComponentType ct = {
CT_Script,
iid,
ctWrapper.alloc,
ctWrapper.dealloc,
cname,
schema,
CScriptValRooted(componentManager->m_ScriptInterface.GetContext(), ctor)
};
componentManager->m_ComponentTypesById[cid] = ct;
componentManager->m_CurrentComponent = cid; // needed by Subscribe
// Stop the ctor getting GCed
componentManager->m_ScriptInterface.AddRoot(&componentManager->m_ComponentTypesById[cid].ctor, "ComponentType ctor");
// TODO: check carefully that roots will never get leaked etc
// Find all the ctor prototype's On* methods, and subscribe to the appropriate messages:
@ -285,7 +280,7 @@ void CComponentManager::Script_RegisterComponentType(void* cbdata, int iid, std:
for (; eit != comps.end(); ++eit)
{
jsval instance = eit->second->GetJSInstance();
if (instance)
if (!JSVAL_IS_NULL(instance))
componentManager->m_ScriptInterface.SetPrototype(instance, proto.get());
}
}
@ -458,7 +453,7 @@ void CComponentManager::ResetState()
void CComponentManager::RegisterComponentType(InterfaceId iid, ComponentTypeId cid, AllocFunc alloc, DeallocFunc dealloc,
const char* name, const std::string& schema)
{
ComponentType c = { CT_Native, iid, alloc, dealloc, name, schema, 0 };
ComponentType c = { CT_Native, iid, alloc, dealloc, name, schema, CScriptValRooted() };
m_ComponentTypesById.insert(std::make_pair(cid, c));
m_ComponentTypeIdsByName[name] = cid;
}
@ -466,7 +461,7 @@ void CComponentManager::RegisterComponentType(InterfaceId iid, ComponentTypeId c
void CComponentManager::RegisterComponentTypeScriptWrapper(InterfaceId iid, ComponentTypeId cid, AllocFunc alloc,
DeallocFunc dealloc, const char* name, const std::string& schema)
{
ComponentType c = { CT_ScriptWrapper, iid, alloc, dealloc, name, schema, 0 };
ComponentType c = { CT_ScriptWrapper, iid, alloc, dealloc, name, schema, CScriptValRooted() };
m_ComponentTypesById.insert(std::make_pair(cid, c));
m_ComponentTypeIdsByName[name] = cid;
// TODO: merge with RegisterComponentType
@ -584,11 +579,11 @@ IComponent* CComponentManager::ConstructComponent(entity_id_t ent, ComponentType
std::map<entity_id_t, IComponent*>& emap2 = m_ComponentsByTypeId[cid];
// If this is a scripted component, construct the appropriate JS object first
jsval obj = 0;
jsval obj = JSVAL_NULL;
if (ct.type == CT_Script)
{
obj = m_ScriptInterface.CallConstructor(ct.ctor);
if (!obj)
obj = m_ScriptInterface.CallConstructor(ct.ctor.get());
if (JSVAL_IS_VOID(obj))
{
LOGERROR(L"Script component constructor failed");
return NULL;

View File

@ -66,7 +66,7 @@ private:
DeallocFunc dealloc;
std::string name;
std::string schema; // RelaxNG fragment
jsval ctor; // only valid if type == CT_Script
CScriptValRooted ctor; // only valid if type == CT_Script
};
public:

View File

@ -40,5 +40,5 @@ JSClass* IComponent::GetJSClass() const
jsval IComponent::GetJSInstance() const
{
return 0;
return JSVAL_NULL;
}

View File

@ -45,38 +45,38 @@
#define DEFINE_INTERFACE_METHOD_0(scriptname, rettype, classname, methodname) \
{ scriptname, \
reinterpret_cast<JSNative>(static_cast<JSFastNative>(ScriptInterface::callMethod<rettype, &class_##classname, classname, &classname::methodname>)), \
ScriptInterface::callMethod<rettype, &class_##classname, classname, &classname::methodname>, \
0, \
JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT|JSFUN_FAST_NATIVE, 0 },
JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT },
#define DEFINE_INTERFACE_METHOD_1(scriptname, rettype, classname, methodname, arg1) \
{ scriptname, \
reinterpret_cast<JSNative>(static_cast<JSFastNative>(ScriptInterface::callMethod<rettype, arg1, &class_##classname, classname, &classname::methodname>)), \
ScriptInterface::callMethod<rettype, arg1, &class_##classname, classname, &classname::methodname>, \
1, \
JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT|JSFUN_FAST_NATIVE, 0 },
JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT },
#define DEFINE_INTERFACE_METHOD_2(scriptname, rettype, classname, methodname, arg1, arg2) \
{ scriptname, \
reinterpret_cast<JSNative>(static_cast<JSFastNative>(ScriptInterface::callMethod<rettype, arg1, arg2, &class_##classname, classname, &classname::methodname>)), \
ScriptInterface::callMethod<rettype, arg1, arg2, &class_##classname, classname, &classname::methodname>, \
2, \
JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT|JSFUN_FAST_NATIVE, 0 },
JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT },
#define DEFINE_INTERFACE_METHOD_3(scriptname, rettype, classname, methodname, arg1, arg2, arg3) \
{ scriptname, \
reinterpret_cast<JSNative>(static_cast<JSFastNative>(ScriptInterface::callMethod<rettype, arg1, arg2, arg3, &class_##classname, classname, &classname::methodname>)), \
ScriptInterface::callMethod<rettype, arg1, arg2, arg3, &class_##classname, classname, &classname::methodname>, \
3, \
JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT|JSFUN_FAST_NATIVE, 0 },
JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT },
#define DEFINE_INTERFACE_METHOD_4(scriptname, rettype, classname, methodname, arg1, arg2, arg3, arg4) \
{ scriptname, \
reinterpret_cast<JSNative>(static_cast<JSFastNative>(ScriptInterface::callMethod<rettype, arg1, arg2, arg3, arg4, &class_##classname, classname, &classname::methodname>)), \
ScriptInterface::callMethod<rettype, arg1, arg2, arg3, arg4, &class_##classname, classname, &classname::methodname>, \
4, \
JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT|JSFUN_FAST_NATIVE, 0 },
JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT },
#define DEFINE_INTERFACE_METHOD_5(scriptname, rettype, classname, methodname, arg1, arg2, arg3, arg4, arg5) \
{ scriptname, \
reinterpret_cast<JSNative>(static_cast<JSFastNative>(ScriptInterface::callMethod<rettype, arg1, arg2, arg3, arg4, arg5, &class_##classname, classname, &classname::methodname>)), \
ScriptInterface::callMethod<rettype, arg1, arg2, arg3, arg4, arg5, &class_##classname, classname, &classname::methodname>, \
5, \
JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT|JSFUN_FAST_NATIVE, 0 },
JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT },
#endif // INCLUDED_INTERFACE_SCRIPTED

View File

@ -325,6 +325,7 @@ public:
{
CSimContext context;
CComponentManager man(context);
ScriptTestSetup(man.m_ScriptInterface);
man.LoadComponentTypes();
TS_ASSERT(man.LoadScript(L"simulation/components/test-entityid.js"));
@ -334,10 +335,8 @@ public:
man.AddComponent(ent1, man.LookupCID("TestScript1A"), noParam);
man.AddComponent(ent2, man.LookupCID("TestScript1A"), noParam);
TestLogger log;
TS_ASSERT_EQUALS(static_cast<ICmpTest1*> (man.QueryInterface(ent1, IID_Test1))->GetX(), (int)ent1);
TS_ASSERT_EQUALS(static_cast<ICmpTest1*> (man.QueryInterface(ent2, IID_Test1))->GetX(), (int)ent2);
TS_ASSERT_WSTR_CONTAINS(log.GetOutput(), L"this.entity is read-only");
}
void test_script_QueryInterface()
@ -632,6 +631,7 @@ public:
{
CSimContext context;
CComponentManager man(context);
ScriptTestSetup(man.m_ScriptInterface);
man.LoadComponentTypes();
TS_ASSERT(man.LoadScript(L"simulation/components/test-serialize.js"));

View File

@ -372,17 +372,17 @@ public:
const char stream[] = "\x02" // SCRIPT_TYPE_ARRAY
"\x04\0\0\0" // num props
"\x01\0\0\0" "0\0" // "0"
"\x05" "\x00\0\0\xC0" // SCRIPT_TYPE_INT -1073741824 (JS_INT_MIN)
"\x05" "\0\0\0\x80" // SCRIPT_TYPE_INT -2147483648 (JS_INT_MIN)
"\x01\0\0\0" "1\0" // "1"
"\x06" "\0\0\x40\0\0\0\xD0\xC1" // SCRIPT_TYPE_DOUBLE -1073741825 (JS_INT_MIN-1)
"\x06" "\0\0\x20\0\0\0\xE0\xC1" // SCRIPT_TYPE_DOUBLE -2147483649 (JS_INT_MIN-1)
"\x01\0\0\0" "2\0" // "2"
"\x05" "\xFF\xFF\xFF\x3F" // SCRIPT_TYPE_INT 1073741823
"\x05" "\xFF\xFF\xFF\x7F" // SCRIPT_TYPE_INT 2147483647 (JS_INT_MAX)
"\x01\0\0\0" "3\0" // "3"
"\x06" "\0\0\0\0\0\0\xD0\x41" // SCRIPT_TYPE_DOUBLE 1073741824
"\x06" "\0\0\0\0\0\0\xE0\x41" // SCRIPT_TYPE_DOUBLE 2147483648 (JS_INT_MAX+1)
;
helper_script_roundtrip("numbers", "[-1073741824, -1073741825, 1.073741823e+9, 1073741824]",
"[-1073741824, -1073741825, 1073741823, 1073741824]", sizeof(stream) - 1, stream);
helper_script_roundtrip("numbers", "[-2147483648, -2147483649, 2.147483647e+9, 2147483648]",
"[-2147483648, -2147483649, 2147483647, 2147483648]", sizeof(stream) - 1, stream);
}
void test_script_exceptions()

View File

@ -28,21 +28,14 @@ JSI_Sound::JSI_Sound(const VfsPath& pathname)
{
m_Handle = snd_open(g_VFS, pathname);
// special-case to avoid throwing exceptions if quickstart has
// disabled sound: set a flag queried by Construct; the object will
// then immediately be freed.
if (m_Handle == ERR::AGAIN)
// if open failed, we still have to return a valid non-null object to
// the script, so just reset the handle to 0 so all subsequent method
// calls will do nothing
if (m_Handle < 0)
{
m_SoundDisabled = true;
m_Handle = 0;
return;
}
m_SoundDisabled = false;
// if open failed, raise an exception - it's the only way to
// report errors, since we're in the ctor and don't want to move
// the open call elsewhere (by requiring an explicit open() call).
if (m_Handle < 0)
throw std::exception(); // caught by JSI_Sound::Construct.
(void)snd_set_pos(m_Handle, 0,0,0, true);
}
@ -190,35 +183,17 @@ CStr JSI_Sound::ToString(JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSE
return "[object Sound: " + CStr(h_filename(m_Handle).string()) + "]";
}
JSBool JSI_Sound::Construct(JSContext* cx, JSObject* UNUSED(obj), uintN argc, jsval* argv, jsval* rval)
JSBool JSI_Sound::Construct(JSContext* cx, uintN argc, jsval* vp)
{
debug_assert(argc >= 1); // FIXME
JSU_REQUIRE_MIN_PARAMS(1);
CStrW filename;
if (! ToPrimitive<CStrW>(cx, argv[0], filename))
if (! ToPrimitive<CStrW>(cx, JS_ARGV(cx, vp)[0], filename))
return JS_FALSE;
try
{
JSI_Sound* newObject = new JSI_Sound(filename);
// somewhat of a hack to avoid throwing exceptions if
// sound was disabled due to quickstart. see JSI_Sound().
if (newObject->m_SoundDisabled)
{
delete newObject;
*rval = JSVAL_NULL;
return JS_TRUE;
}
newObject->m_EngineOwned = false;
*rval = OBJECT_TO_JSVAL(newObject->GetScript());
}
catch (std::exception)
{
// failed, but this can happen easily enough that we don't want to
// return JS_FALSE (since that stops the script).
*rval = JSVAL_NULL;
}
JSI_Sound* newObject = new JSI_Sound(filename);
newObject->m_EngineOwned = false;
JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(newObject->GetScript()));
return JS_TRUE;
}

View File

@ -48,34 +48,31 @@ public:
// Script-bound functions
CStr ToString( JSContext* cx, uintN argc, jsval* argv );
CStr ToString(JSContext* cx, uintN argc, jsval* argv);
// start playing the sound (one-shot).
// it will automatically be freed when done.
bool Play( JSContext* cx, uintN argc, jsval* argv );
bool Play(JSContext* cx, uintN argc, jsval* argv);
// request the sound be played until free() is called. returns immediately.
bool Loop( JSContext* cx, uintN argc, jsval* argv );
bool Loop(JSContext* cx, uintN argc, jsval* argv);
// stop sound if currently playing and free resources.
// doesn't need to be called unless played via loop() -
// sounds are freed automatically when done playing.
bool Free( JSContext* cx, uintN argc, jsval* argv );
bool Free(JSContext* cx, uintN argc, jsval* argv);
bool SetGain( JSContext* cx, uintN argc, jsval* argv );
bool SetGain(JSContext* cx, uintN argc, jsval* argv);
bool SetPitch( JSContext* cx, uintN argc, jsval* argv );
bool SetPitch(JSContext* cx, uintN argc, jsval* argv);
bool SetPosition( JSContext* cx, uintN argc, jsval* argv );
bool SetPosition(JSContext* cx, uintN argc, jsval* argv);
bool Fade ( JSContext* cx, uintN argc, jsval* argv );
bool Fade(JSContext* cx, uintN argc, jsval* argv);
static JSBool Construct( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
static JSBool Construct(JSContext* cx, uintN argc, jsval* vp);
static void ScriptingInit();
private:
bool m_SoundDisabled; // see constructor and JSI_Sound::Construct
};
#endif // #ifndef INCLUDED_JSI_SOUND

View File

@ -29,7 +29,7 @@ public:
#define NUMBERED_LIST_BALANCED(z, i, data) BOOST_PP_COMMA_IF(i) data##i
// Some other things
#define TYPED_ARGS(z, i, data) , T##i a##i
#define CONVERT_ARG(z, i, data) T##i a##i; if (! ScriptInterface::FromJSVal<T##i>(cx, argv[i], a##i)) return JS_FALSE;
#define CONVERT_ARG(z, i, data) T##i a##i; if (! ScriptInterface::FromJSVal<T##i>(cx, i < argc ? JS_ARGV(cx, vp)[i] : JSVAL_VOID, a##i)) return JS_FALSE;
// List-generating macros, named roughly after their first list item
#define TYPENAME_T0_HEAD(z, i) BOOST_PP_REPEAT_##z (i, NUMBERED_LIST_HEAD, typename T)
@ -56,7 +56,7 @@ private:
// (Definition comes later, since it depends on some things we haven't defined yet)
#define OVERLOADS(z, i, data) \
template <typename TR, TYPENAME_T0_HEAD(z,i) TR (*fptr) ( void* T0_TAIL(z,i) )> \
static JSBool call(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval);
static JSBool call(JSContext* cx, uintN argc, jsval* vp);
BOOST_PP_REPEAT(MAX_ARGS, OVERLOADS, ~)
#undef OVERLOADS
@ -102,10 +102,12 @@ struct ScriptInterface_NativeWrapper<void> {
// JSNative-compatible function that wraps the function identified in the template argument list
#define OVERLOADS(z, i, data) \
template <typename TR, TYPENAME_T0_HEAD(z,i) TR (*fptr) ( void* T0_TAIL(z,i) )> \
JSBool ScriptInterface::call(JSContext* cx, JSObject* /*obj*/, uintN /*argc*/, jsval* argv, jsval* rval) { \
(void)argv; /* avoid 'unused parameter' warnings */ \
JSBool ScriptInterface::call(JSContext* cx, uintN argc, jsval* vp) { \
(void)cx; (void)argc; /* avoid 'unused parameter' warnings */ \
BOOST_PP_REPEAT_##z (i, CONVERT_ARG, ~) \
ScriptInterface_NativeWrapper<TR>::call(cx, *rval, fptr A0_TAIL(z,i)); \
jsval rval = JSVAL_VOID; \
ScriptInterface_NativeWrapper<TR>::call(cx, rval, fptr A0_TAIL(z,i)); \
JS_SET_RVAL(cx, vp, rval); \
return JS_TRUE; \
}
BOOST_PP_REPEAT(MAX_ARGS, OVERLOADS, ~)

View File

@ -166,8 +166,11 @@ namespace
JSString* ret = JS_ValueToString(cx, v);
if (! ret)
FAIL("Argument must be convertible to a string");
char* ch = JS_GetStringBytes(ret);
out = std::string(ch);
char* ch = JS_EncodeString(cx, ret); // chops off high byte of each jschar
if (! ch)
FAIL("JS_EncodeString failed"); // out of memory
out = std::string(ch, ch + JS_GetStringLength(ret));
JS_free(cx, ch);
return true;
}
};
@ -241,7 +244,7 @@ namespace
static jsval Convert(JSContext* cx, const float& val)
{
jsval rval = JSVAL_VOID;
JS_NewDoubleValue(cx, val, &rval); // ignore return value
JS_NewNumberValue(cx, val, &rval); // ignore return value
return rval;
}
};
@ -326,13 +329,11 @@ namespace
{
JSObject* obj = JS_NewArrayObject(cx, 0, NULL);
if (! obj) return JSVAL_VOID;
JS_AddRoot(cx, &obj);
for (size_t i = 0; i < val.size(); ++i)
{
jsval el = ToJSVal<T>::Convert(cx, val[i]);
JS_SetElement(cx, obj, (jsint)i, &el);
}
JS_RemoveRoot(cx, &obj);
return OBJECT_TO_JSVAL(obj);
}
};
@ -382,7 +383,6 @@ namespace
{
JSObject* obj = JS_NewObject(cx, NULL, NULL, NULL);
if (! obj) return JSVAL_VOID;
JS_AddRoot(cx, &obj);
JS_DefineProperty(cx, obj, "name", ToJSVal<std::wstring>::Convert(cx, *val.name), NULL, NULL, JSPROP_ENUMERATE);
@ -393,8 +393,6 @@ namespace
jsval bmp = wxjs::gui::Bitmap::CreateObject(cx, new wxBitmap (wxImage(val.imagewidth, val.imageheight, buf)));
JS_DefineProperty(cx, obj, "imagedata", bmp, NULL, NULL, JSPROP_ENUMERATE);
JS_RemoveRoot(cx, &obj);
return OBJECT_TO_JSVAL(obj);
}
};
@ -405,11 +403,9 @@ namespace
{
JSObject* obj = JS_NewObject(cx, NULL, NULL, NULL);
if (! obj) return JSVAL_VOID;
JS_AddRoot(cx, &obj);
JS_DefineProperty(cx, obj, "id", ToJSVal<std::wstring>::Convert(cx, *val.id), NULL, NULL, JSPROP_ENUMERATE);
JS_DefineProperty(cx, obj, "name", ToJSVal<std::wstring>::Convert(cx, *val.name), NULL, NULL, JSPROP_ENUMERATE);
JS_DefineProperty(cx, obj, "type", ToJSVal<int>::Convert(cx, val.type), NULL, NULL, JSPROP_ENUMERATE);
JS_RemoveRoot(cx, &obj);
return OBJECT_TO_JSVAL(obj);
}
};
@ -420,11 +416,9 @@ namespace
{
JSObject* obj = JS_NewObject(cx, NULL, NULL, NULL);
if (! obj) return JSVAL_VOID;
JS_AddRoot(cx, &obj);
JS_DefineProperty(cx, obj, "player", ToJSVal<size_t>::Convert(cx, val.player), NULL, NULL, JSPROP_ENUMERATE);
JS_DefineProperty(cx, obj, "selections", ToJSVal<std::vector<std::wstring> >::Convert(cx, *val.selections), NULL, NULL, JSPROP_ENUMERATE);
JS_DefineProperty(cx, obj, "variantgroups", ToJSVal<std::vector<std::vector<std::wstring> > >::Convert(cx, *val.variantgroups), NULL, NULL, JSPROP_ENUMERATE);
JS_RemoveRoot(cx, &obj);
return OBJECT_TO_JSVAL(obj);
}
};
@ -531,37 +525,47 @@ namespace
// Functions in the Atlas.* namespace:
JSBool ForceGC(JSContext* cx, JSObject* WXUNUSED(obj), uintN WXUNUSED(argc), jsval* WXUNUSED(argv), jsval* WXUNUSED(rval))
JSBool ForceGC(JSContext* cx, uintN WXUNUSED(argc), jsval* vp)
{
JS_GC(cx);
JS_SET_RVAL(cx, vp, JSVAL_VOID);
return JS_TRUE;
}
JSBool LoadScript(JSContext* cx, JSObject* WXUNUSED(obj), uintN WXUNUSED(argc), jsval* argv, jsval* rval)
JSBool LoadScript(JSContext* cx, uintN argc, jsval* vp)
{
if (! ( JSVAL_IS_STRING(argv[0]) && JSVAL_IS_STRING(argv[1]) ))
if (argc < 2 || !JSVAL_IS_STRING(JS_ARGV(cx, vp)[0]) || !JSVAL_IS_STRING(JS_ARGV(cx, vp)[1]))
return JS_FALSE;
JSString* name = JSVAL_TO_STRING(argv[0]);
JSString* code = JSVAL_TO_STRING(argv[1]);
std::string name;
if (!ScriptInterface::FromJSVal(cx, JS_ARGV(cx, vp)[0], name))
return JS_FALSE;
JSString* code = JSVAL_TO_STRING(JS_ARGV(cx, vp)[1]);
return ScriptInterface_impl::LoadScript(cx,
jsval rval = JSVAL_VOID;
if (!ScriptInterface_impl::LoadScript(cx,
JS_GetStringChars(code), (uintN)JS_GetStringLength(code),
JS_GetStringBytes(name), rval);
name.c_str(), &rval))
return JS_FALSE;
JS_SET_RVAL(cx, vp, rval);
return JS_TRUE;
}
// Functions in the global namespace:
JSBool print(JSContext* cx, JSObject* WXUNUSED(obj), uintN argc, jsval* argv, jsval* WXUNUSED(rval))
JSBool print(JSContext* cx, uintN argc, jsval* vp)
{
for (uintN i = 0; i < argc; ++i)
{
std::string str;
if (! ScriptInterface::FromJSVal(cx, argv[i], str))
if (! ScriptInterface::FromJSVal(cx, JS_ARGV(cx, vp)[i], str))
return JS_FALSE;
printf("%s", str.c_str());
}
fflush(stdout);
JS_SET_RVAL(cx, vp, JSVAL_VOID);
return JS_TRUE;
}
}
@ -588,7 +592,7 @@ ScriptInterface_impl::ScriptInterface_impl()
| JSOPTION_XML // "ECMAScript for XML support: parse <!-- --> as a token"
);
m_glob = JS_NewObject(m_cx, &global_class, NULL, NULL);
m_glob = JS_NewGlobalObject(m_cx, &global_class);
ok = JS_InitStandardClasses(m_cx, m_glob);
JS_DefineProperty(m_cx, m_glob, "global", OBJECT_TO_JSVAL(m_glob), NULL, NULL, JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT);
@ -666,31 +670,14 @@ JSContext* ScriptInterface::GetContext()
return m->m_cx;
}
bool ScriptInterface::AddRoot(void* ptr)
bool ScriptInterface::AddRoot(jsval* ptr)
{
return JS_AddRoot(m->m_cx, ptr) ? true : false;
return JS_AddValueRoot(m->m_cx, ptr) ? true : false;
}
bool ScriptInterface::RemoveRoot(void* ptr)
bool ScriptInterface::RemoveRoot(jsval* ptr)
{
return JS_RemoveRoot(m->m_cx, ptr) ? true : false;
}
ScriptInterface::LocalRootScope::LocalRootScope(ScriptInterface& scriptInterface)
: m_ScriptInterface(scriptInterface)
{
m_OK = JS_EnterLocalRootScope(m_ScriptInterface.m->m_cx) ? true : false;
}
ScriptInterface::LocalRootScope::~LocalRootScope()
{
if (m_OK)
JS_LeaveLocalRootScope(m_ScriptInterface.m->m_cx);
}
bool ScriptInterface::LocalRootScope::OK()
{
return m_OK;
return JS_RemoveValueRoot(m->m_cx, ptr) ? true : false;
}
@ -813,7 +800,7 @@ std::pair<wxPanel*, wxPanel*> ScriptInterface::LoadScriptAsSidebar(const wxStrin
#define CONVERT_ARGS(r, data, i, elem) \
TYPE(elem) a##i; \
if (! ScriptInterface::FromJSVal< TYPE(elem) >(cx, argv[i], a##i)) \
if (! ScriptInterface::FromJSVal< TYPE(elem) >(cx, i < argc ? JS_ARGV(cx, vp)[i] : JSVAL_VOID, a##i)) \
return JS_FALSE;
#define CONVERT_OUTPUTS(r, data, i, elem) \
@ -823,33 +810,35 @@ std::pair<wxPanel*, wxPanel*> ScriptInterface::LoadScriptAsSidebar(const wxStrin
#define ARG_LIST(r, data, i, elem) BOOST_PP_COMMA_IF(i) a##i
#define MESSAGE(name, vals) \
JSBool call_##name(JSContext* cx, JSObject* WXUNUSED(obj), uintN WXUNUSED(argc), jsval* argv, jsval* WXUNUSED(rval)) \
JSBool call_##name(JSContext* cx, uintN argc, jsval* vp) \
{ \
(void)cx; (void)argv; /* avoid 'unused parameter' warnings */ \
(void)cx; (void)argc; /* avoid 'unused parameter' warnings */ \
BOOST_PP_SEQ_FOR_EACH_I(CONVERT_ARGS, ~, vals) \
g_MessagePasser->Add(SHAREABLE_NEW(m##name, ( BOOST_PP_SEQ_FOR_EACH_I(ARG_LIST, ~, vals) ))); \
JS_SET_RVAL(cx, vp, JSVAL_VOID); \
return JS_TRUE; \
}
#define COMMAND(name, merge, vals) \
JSBool call_##name(JSContext* cx, JSObject* WXUNUSED(obj), uintN WXUNUSED(argc), jsval* argv, jsval* WXUNUSED(rval)) \
JSBool call_##name(JSContext* cx, uintN argc, jsval* vp) \
{ \
(void)cx; (void)argv; /* avoid 'unused parameter' warnings */ \
(void)cx; (void)argc; /* avoid 'unused parameter' warnings */ \
BOOST_PP_SEQ_FOR_EACH_I(CONVERT_ARGS, ~, vals) \
g_SubmitCommand(new AtlasMessage::m##name (AtlasMessage::d##name ( BOOST_PP_SEQ_FOR_EACH_I(ARG_LIST, ~, vals) ))); \
JS_SET_RVAL(cx, vp, JSVAL_VOID); \
return JS_TRUE; \
}
#define QUERY(name, in_vals, out_vals) \
JSBool call_##name(JSContext* cx, JSObject* WXUNUSED(obj), uintN WXUNUSED(argc), jsval* argv, jsval* rval) \
JSBool call_##name(JSContext* cx, uintN argc, jsval* vp) \
{ \
(void)argv; /* avoid 'unused parameter' warnings */ \
(void)cx; (void)argc; /* avoid 'unused parameter' warnings */ \
BOOST_PP_SEQ_FOR_EACH_I(CONVERT_ARGS, ~, in_vals) \
q##name q = q##name( BOOST_PP_SEQ_FOR_EACH_I(ARG_LIST, ~, in_vals) ); \
q.Post(); \
JSObject* ret = JS_NewObject(cx, NULL, NULL, NULL); \
if (! ret) return JS_FALSE; \
*rval = OBJECT_TO_JSVAL(ret); \
JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(ret)); \
BOOST_PP_SEQ_FOR_EACH_I(CONVERT_OUTPUTS, ~, out_vals) \
return JS_TRUE; \
}
@ -898,4 +887,3 @@ void ScriptInterface_impl::RegisterMessages(JSObject* parent)
#undef COMMAND
#undef QUERY
}

View File

@ -20,11 +20,18 @@
#ifdef _WIN32
# define XP_WIN
# define WIN32 // SpiderMonkey expects this
// The jsval struct type causes crashes due to weird miscompilation
// issues in (at least) VC2008, so force it to be the less-type-safe
// non-struct type instead
# define JS_NO_JSVAL_JSID_STRUCT_TYPES
#else
# define XP_UNIX
#endif // (we don't support XP_OS2 or XP_BEOS)
#include "js/jspubtd.h"
#include "js/jsapi.h"
class wxWindow;
class wxString;
@ -70,26 +77,8 @@ public:
// value must be rooted if you don't want it to be collected.)
template <typename T> static jsval ToJSVal(JSContext* cx, const T& val);
bool AddRoot(void* ptr);
bool RemoveRoot(void* ptr);
// Helper class for automatically rooting values
class LocalRootScope
{
ScriptInterface& m_ScriptInterface;
bool m_OK;
public:
// Tries to enter local root scope, so newly created
// values won't be GCed. This might fail, so check OK()
LocalRootScope(ScriptInterface& scriptInterface);
// Returns true if the local root scope was successfully entered
bool OK();
// Leaves the local root scope
~LocalRootScope();
private:
LocalRootScope& operator=(const LocalRootScope&);
};
#define LOCAL_ROOT_SCOPE LocalRootScope scope(*this); if (! scope.OK()) return false
bool AddRoot(jsval* ptr);
bool RemoveRoot(jsval* ptr);
private:
JSContext* GetContext();
@ -113,7 +102,6 @@ bool ScriptInterface::SetValue(const wxString& name, const T& val)
template <typename T>
bool ScriptInterface::GetValue(const wxString& name, T& ret)
{
LOCAL_ROOT_SCOPE;
jsval jsRet;
if (! GetValue_(name, jsRet)) return false;
return FromJSVal(GetContext(), jsRet, ret);
@ -122,7 +110,6 @@ bool ScriptInterface::GetValue(const wxString& name, T& ret)
template <typename T, typename R>
bool ScriptInterface::CallFunction(jsval val, const char* name, const T& a, R& ret)
{
LOCAL_ROOT_SCOPE;
jsval jsRet;
std::vector<jsval> argv;
argv.push_back(ToJSVal(GetContext(), a));
@ -134,7 +121,6 @@ bool ScriptInterface::CallFunction(jsval val, const char* name, const T& a, R& r
template <typename T, typename S, typename R>
bool ScriptInterface::CallFunction(jsval val, const char* name, const T& a, const S& b, R& ret)
{
LOCAL_ROOT_SCOPE;
jsval jsRet;
std::vector<jsval> argv;
argv.push_back(ToJSVal(GetContext(), a));
@ -147,7 +133,6 @@ bool ScriptInterface::CallFunction(jsval val, const char* name, const T& a, cons
template <typename T>
bool ScriptInterface::Eval(const wxString& script, T& ret)
{
LOCAL_ROOT_SCOPE;
jsval jsRet;
if (! Eval_(script, jsRet)) return false;
return FromJSVal(GetContext(), jsRet, ret);
@ -161,7 +146,7 @@ bool ScriptInterface::Eval(const wxString& script, T& ret)
class CScriptVal
{
public:
CScriptVal() : m_Val(0) { }
CScriptVal() : m_Val(JSVAL_VOID) { }
CScriptVal(jsval val) : m_Val(val) { }
jsval get() const { return m_Val; }

View File

@ -431,26 +431,26 @@ namespace wxjs
static JSBool JSGetStaticProperty(JSContext* cx,
JSObject* WXUNUSED(obj),
jsval id,
jsid id,
jsval* vp)
{
if ( JSVAL_IS_INT(id) )
if ( JSID_IS_INT(id) )
{
return T_Port::GetStaticProperty(cx, JSVAL_TO_INT(id), vp) ? JS_TRUE
: JS_FALSE;
return T_Port::GetStaticProperty(cx, JSID_TO_INT(id), vp) ? JS_TRUE
: JS_FALSE;
}
return JS_TRUE;
}
static JSBool JSSetStaticProperty(JSContext* cx,
JSObject* WXUNUSED(obj),
jsval id,
jsid id,
jsval *vp)
{
if ( JSVAL_IS_INT(id) )
if ( JSID_IS_INT(id) )
{
return T_Port::SetStaticProperty(cx, JSVAL_TO_INT(id), vp) ? JS_TRUE
: JS_FALSE;
return T_Port::SetStaticProperty(cx, JSID_TO_INT(id), vp) ? JS_TRUE
: JS_FALSE;
}
return JS_TRUE;
}
@ -516,16 +516,19 @@ namespace wxjs
*/
static JSBool JSAddProperty(JSContext *cx,
JSObject *obj,
jsval id,
jsid id,
jsval *vp)
{
if (JSVAL_IS_STRING(id))
if (JSID_IS_STRING(id))
{
T_Priv *p = (T_Priv *) GetPrivate(cx, obj, false);
if ( p != NULL )
{
jsval idval;
if (!JS_IdToValue(cx, id, &idval))
return JS_FALSE;
wxString str;
FromJS(cx, id, str);
FromJS(cx, idval, str);
JSBool res = T_Port::AddProperty(p, cx, obj, str, vp) ? JS_TRUE
: JS_FALSE;
return res;
@ -540,16 +543,19 @@ namespace wxjs
*/
static JSBool JSDeleteProperty(JSContext *cx,
JSObject *obj,
jsval id,
jsid id,
jsval* WXUNUSED(vp))
{
if (JSVAL_IS_STRING(id))
if (JSID_IS_STRING(id))
{
T_Priv *p = (T_Priv *) GetPrivate(cx, obj, false);
if ( p != NULL )
{
wxString str;
FromJS(cx, id, str);
jsval idval;
if (!JS_IdToValue(cx, id, &idval))
return JS_FALSE;
FromJS(cx, idval, str);
JSBool res = T_Port::DeleteProperty(p, cx, obj, str) ? JS_TRUE
: JS_FALSE;
return res;
@ -564,21 +570,24 @@ namespace wxjs
*/
static JSBool JSGetProperty(JSContext *cx,
JSObject *obj,
jsval id,
jsid id,
jsval *vp)
{
T_Priv *p = (T_Priv *) GetPrivate(cx, obj, false);
if (JSVAL_IS_INT(id))
if (JSID_IS_INT(id))
{
return T_Port::GetProperty(p, cx, obj, JSVAL_TO_INT(id), vp)
return T_Port::GetProperty(p, cx, obj, JSID_TO_INT(id), vp)
? JS_TRUE : JS_FALSE;
}
else
{
if (JSVAL_IS_STRING(id))
if (JSID_IS_STRING(id))
{
wxString s;
FromJS(cx, id, s);
jsval idval;
if (!JS_IdToValue(cx, id, &idval))
return JS_FALSE;
FromJS(cx, idval, s);
JSBool res = T_Port::GetStringProperty(p, cx, obj, s, vp) ? JS_TRUE
: JS_FALSE;
return res;
@ -593,21 +602,24 @@ namespace wxjs
*/
static JSBool JSSetProperty(JSContext *cx,
JSObject *obj,
jsval id,
jsid id,
jsval *vp)
{
T_Priv *p = (T_Priv *) GetPrivate(cx, obj, false);
if (JSVAL_IS_INT(id))
if (JSID_IS_INT(id))
{
return T_Port::SetProperty(p, cx, obj, JSVAL_TO_INT(id), vp)
return T_Port::SetProperty(p, cx, obj, JSID_TO_INT(id), vp)
? JS_TRUE : JS_FALSE;
}
else
{
if (JSVAL_IS_STRING(id))
if (JSID_IS_STRING(id))
{
wxString s;
FromJS(cx, id, s);
jsval idval;
if (!JS_IdToValue(cx, id, &idval))
return JS_FALSE;
FromJS(cx, idval, s);
JSBool res = T_Port::SetStringProperty(p, cx, obj, s, vp)
? JS_TRUE : JS_FALSE;
return res;
@ -616,9 +628,12 @@ namespace wxjs
return JS_TRUE;
}
static JSBool JSResolve(JSContext *cx, JSObject *obj, jsval id)
static JSBool JSResolve(JSContext *cx, JSObject *obj, jsid id)
{
return T_Port::Resolve(cx, obj, id) ? JS_TRUE : JS_FALSE;
jsval idval;
if (!JS_IdToValue(cx, id, &idval))
return JS_FALSE;
return T_Port::Resolve(cx, obj, idval) ? JS_TRUE : JS_FALSE;
}
/**
@ -628,19 +643,19 @@ namespace wxjs
* with a new statement in JavaScript.
*/
static JSBool JSConstructor(JSContext *cx,
JSObject *obj,
uintN argc,
jsval *argv,
jsval* WXUNUSED(rval))
jsval *vp)
{
T_Priv *p = T_Port::Construct(cx, obj, argc, argv,
JS_IsConstructing(cx) == JS_TRUE);
JSObject* obj = JS_NewObject(cx, &wxjs_class, m_classProto, NULL);
T_Priv *p = T_Port::Construct(cx, obj, argc, JS_ARGV(cx, vp),
JS_IsConstructing(cx, vp) == JS_TRUE);
if ( p == NULL )
{
JS_ReportError(cx, "Class %s can't be constructed", m_jsClassName);
return JS_FALSE;
}
JS_SetPrivate(cx, obj, p);
JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(obj));
return JS_TRUE;
}
@ -765,13 +780,23 @@ JSClass wxjs::ApiWrapper<T_Port, T_Priv>::wxjs_class =
{
#define WXJS_END_METHOD_MAP() \
{ 0, 0, 0, 0, 0 } \
{ 0, 0, 0, 0 } \
}; \
JS_DefineFunctions(cx, obj, methods); \
}
template<JSBool (*fptr)(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)>
static JSBool methodInterfaceWrapper(JSContext* cx, uintN argc, jsval* vp)
{
jsval rval = JSVAL_VOID;
if (!fptr(cx, JS_THIS_OBJECT(cx, vp), argc, JS_ARGV(cx, vp), &rval))
return JS_FALSE;
JS_SET_RVAL(cx, vp, rval);
return JS_TRUE;
}
#define WXJS_METHOD(name, fun, args) \
{ name, fun, args, 0, 0 },
{ name, methodInterfaceWrapper<fun>, args, 0 },
// A macro to reduce the size of the ported classes header.
#define WXJS_DECLARE_METHOD(name) static JSBool name(JSContext *cx, \

View File

@ -69,12 +69,12 @@ namespace wxjs
if ( m_protected
&& ! protect )
{
JS_RemoveRoot(m_cx, &m_obj);
JS_RemoveObjectRoot(m_cx, &m_obj);
}
else if ( protect
&& ! m_protected )
{
JS_AddRoot(m_cx, &m_obj);
JS_AddObjectRoot(m_cx, &m_obj);
}
m_protected = protect;
}

View File

@ -261,7 +261,7 @@ template<>
jsval wxjs::ToJS<unsigned long>(JSContext* cx, const unsigned long&from)
{
jsval v;
JS_NewDoubleValue(cx, from, &v);
JS_NewNumberValue(cx, from, &v);
return v;
}
@ -269,7 +269,7 @@ template<>
jsval wxjs::ToJS<float>(JSContext* cx, const float &from)
{
jsval v;
JS_NewDoubleValue(cx, from, &v);
JS_NewNumberValue(cx, from, &v);
return v;
}
@ -277,7 +277,7 @@ template<>
jsval wxjs::ToJS<double>(JSContext* cx, const double &from)
{
jsval v;
JS_NewDoubleValue(cx, from, &v);
JS_NewNumberValue(cx, from, &v);
return v;
}
@ -324,13 +324,11 @@ template<>
jsval wxjs::ToJS<wxArrayString>(JSContext *cx, const wxArrayString &from)
{
JSObject *objArray = JS_NewArrayObject(cx, 0, NULL);
JS_AddRoot(cx, &objArray);
for(size_t i = 0; i < from.GetCount(); i++)
{
jsval element = ToJS(cx, from.Item(i));
JS_SetElement(cx, objArray, i, &element);
}
JS_RemoveRoot(cx, &objArray);
return OBJECT_TO_JSVAL(objArray);
}
@ -338,7 +336,6 @@ template<>
jsval wxjs::ToJS<wxStringList>(JSContext *cx, const wxStringList &from)
{
JSObject *objArray = JS_NewArrayObject(cx, 0, NULL);
JS_AddRoot(cx, &objArray);
int i = 0;
wxStringListNode *node = from.GetFirst();
@ -351,6 +348,5 @@ jsval wxjs::ToJS<wxStringList>(JSContext *cx, const wxStringList &from)
node = node->GetNext();
}
JS_RemoveRoot(cx, &objArray);
return OBJECT_TO_JSVAL(objArray);
}

View File

@ -221,13 +221,13 @@ namespace wxjs
ListObjectData(JSContext *cx, jsval v) : m_cx(cx), m_val(v)
{
if ( JSVAL_IS_GCTHING(m_val) ) {}
JS_AddRoot(m_cx, &m_val);
JS_AddValueRoot(m_cx, &m_val);
}
virtual ~ListObjectData()
{
if ( JSVAL_IS_GCTHING(m_val) ) {}
JS_RemoveRoot(m_cx, &m_val);
JS_RemoveValueRoot(m_cx, &m_val);
}
jsval GetJSVal()

View File

@ -200,7 +200,7 @@ wxMenu* Menu::Construct(JSContext *cx,
break;
}
case 1:
if ( JSVAL_IS_INT(argv[0]) )
if ( JSVAL_IS_NUMBER(argv[0]) )
{
int style = 0;
if ( FromJS(cx, argv[0], style) )

View File

@ -396,7 +396,7 @@ JSBool ToolBar::create(JSContext *cx,
if ( p->Create(parent, id, *pt, *size, style) )
{
*rval = JS_TRUE;
*rval = JSVAL_TRUE;
p->SetClientObject(new JavaScriptClientData(cx, obj, true, false));
JSObject *objActionArray = JS_NewArrayObject(cx, 0, NULL);
JS_DefineProperty(cx, obj, "actions", OBJECT_TO_JSVAL(objActionArray),

View File

@ -260,7 +260,7 @@ bool TreeCtrl::SetProperty(wxTreeCtrl *p,
case P_INDENT:
{
int indent;
if ( FromJS(cx, p->GetIndent(), indent))
if ( FromJS(cx, *vp, indent))
p->SetIndent(indent);
break;
}

View File

@ -195,13 +195,13 @@ namespace wxjs
, m_val(v)
{
if ( JSVAL_IS_GCTHING(m_val) )
JS_AddRoot(m_cx, &m_val);
JS_AddValueRoot(m_cx, &m_val);
}
virtual ~ObjectTreeData()
{
if ( JSVAL_IS_GCTHING(m_val) )
JS_RemoveRoot(m_cx, &m_val);
JS_RemoveValueRoot(m_cx, &m_val);
}
inline jsval GetJSVal()

View File

@ -82,17 +82,17 @@ bool SplitterEvent::GetProperty(PrivSplitterEvent* p,
{
case P_SASH_POSITION:
{
*vp = event->GetSashPosition();
*vp = ToJS(cx, event->GetSashPosition());
break;
}
case P_X:
{
*vp = event->GetX();
*vp = ToJS(cx, event->GetX());
break;
}
case P_Y:
{
*vp = event->GetY();
*vp = ToJS(cx, event->GetY());
break;
}
case P_WINDOW_BEING_REMOVED:

View File

@ -64,13 +64,14 @@ static JSFunctionSpec Functions[] =
* </desc>
* </method>
*/
JSBool wxjs::gui::MessageBox(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
JSBool wxjs::gui::MessageBox(JSContext *cx, uintN argc, jsval *vp)
{
if ( argc == 1 )
{
wxString msg;
FromJS(cx, argv[0], msg);
FromJS(cx, JS_ARGV(cx, vp)[0], msg);
wxMessageBox(msg);
JS_SET_RVAL(cx, vp, JSVAL_VOID);
return JS_TRUE;
}
return JS_FALSE;
@ -90,18 +91,19 @@ JSBool wxjs::gui::MessageBox(JSContext *cx, JSObject *obj, uintN argc, jsval *ar
* </desc>
* </method>
*/
JSBool wxjs::gui::InitAllImageHandlers(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
JSBool wxjs::gui::InitAllImageHandlers(JSContext *cx, uintN argc, jsval *vp)
{
wxInitAllImageHandlers();
JS_SET_RVAL(cx, vp, JSVAL_VOID);
return JS_TRUE;
}
JSBool wxjs::gui::GetKeyState(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
JSBool wxjs::gui::GetKeyState(JSContext *cx, uintN argc, jsval *vp)
{
int key;
if (! FromJS(cx, argv[0], key))
if (! FromJS(cx, JS_ARGV(cx, vp)[0], key))
return JS_FALSE;
*rval = (wxGetKeyState((wxKeyCode)key) ? JSVAL_TRUE : JSVAL_FALSE);
JS_SET_RVAL(cx, vp, wxGetKeyState((wxKeyCode)key) ? JSVAL_TRUE : JSVAL_FALSE);
return JS_TRUE;
}

View File

@ -46,9 +46,9 @@ namespace wxjs
/**
* Implements wxMessageBox
*/
JSBool MessageBox(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
JSBool InitAllImageHandlers(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
JSBool GetKeyState(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
JSBool MessageBox(JSContext *cx, uintN argc, jsval *vp);
JSBool InitAllImageHandlers(JSContext *cx, uintN argc, jsval *vp);
JSBool GetKeyState(JSContext *cx, uintN argc, jsval *vp);
void DefineGlobals(JSContext *cx, JSObject *global);
}; // namespace gui

View File

@ -287,7 +287,7 @@ wxImage* Image::Construct(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
if ( argc > 1 )
{
if ( JSVAL_IS_INT(argv[1]) )
if ( JSVAL_IS_NUMBER(argv[1]) )
{
if ( ! FromJS(cx, argv[1], type) )
return NULL;
@ -1123,7 +1123,7 @@ JSBool Image::loadFile(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, js
return JS_FALSE;
}
if ( JSVAL_IS_INT(argv[1]) )
if ( JSVAL_IS_NUMBER(argv[1]) )
{
long type = wxBITMAP_TYPE_ANY;
if ( ! FromJS(cx, argv[1], type) )
@ -1145,7 +1145,7 @@ JSBool Image::loadFile(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, js
if ( argc > 1 )
{
if ( JSVAL_IS_INT(argv[1]) )
if ( JSVAL_IS_NUMBER(argv[1]) )
{
long type = wxBITMAP_TYPE_ANY;
if ( ! FromJS(cx, argv[1], type) )
@ -1222,7 +1222,7 @@ JSBool Image::saveFile(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, js
return JS_FALSE;
}
if ( JSVAL_IS_INT(argv[1]) )
if ( JSVAL_IS_NUMBER(argv[1]) )
{
long type = wxBITMAP_TYPE_ANY;
if ( ! FromJS(cx, argv[1], type) )
@ -1242,7 +1242,7 @@ JSBool Image::saveFile(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, js
wxString name;
FromJS(cx, argv[0], name);
if ( JSVAL_IS_INT(argv[1]) )
if ( JSVAL_IS_NUMBER(argv[1]) )
{
long type;
if ( ! FromJS(cx, argv[1], type) )

View File

@ -355,7 +355,7 @@ JSBool File::create(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval
return JS_FALSE;
}
*rval = p->Create(fileName, overwrite, access);
*rval = ToJS(cx, p->Create(fileName, overwrite, access));
return JS_TRUE;
}

View File

@ -472,7 +472,7 @@ wxFileName* FileName::Construct(JSContext *cx, JSObject *obj, uintN argc, jsval
// Argc > 1
int format = wxPATH_NATIVE;
uintN stringCount = argc;
if ( JSVAL_IS_INT(argv[argc-1]) )
if ( JSVAL_IS_NUMBER(argv[argc-1]) )
{
FromJS(cx, argv[argc-1], format);
stringCount--;
@ -615,7 +615,7 @@ JSBool FileName::assign(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, j
// Argc > 1
int format = wxPATH_NATIVE;
uintN stringCount = argc;
if ( JSVAL_IS_INT(argv[argc-1]) )
if ( JSVAL_IS_NUMBER(argv[argc-1]) )
{
FromJS(cx, argv[argc-1], format);
stringCount--;

View File

@ -448,7 +448,7 @@ JSBool io::execute(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval
return JS_TRUE;
}
if ( JSVAL_IS_INT(argv[1]) )
if ( JSVAL_IS_NUMBER(argv[1]) )
{
wxProcess *p = NULL;
if ( argc > 2 )
@ -472,7 +472,7 @@ JSBool io::execute(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval
return JS_FALSE;
}
if ( argc > 2
&& JSVAL_IS_INT(argv[2]) )
&& JSVAL_IS_NUMBER(argv[2]) )
{
if ( ! FromJS(cx, argv[2], flags) )
return JS_FALSE;

View File

@ -301,24 +301,24 @@ bool io::InitClass(JSContext *cx, JSObject *global)
if (! obj )
return false;
JS_DefineFunction(cx, global, "wxConcatFiles", concatFiles, 3, 0);
JS_DefineFunction(cx, global, "wxCopyFile", copyFile, 2, 0);
JS_DefineFunction(cx, global, "wxFileExists", fileExists, 1, 0);
JS_DefineFunction(cx, global, "wxRenameFile", renameFile, 2, 0);
JS_DefineFunction(cx, global, "wxGetCwd", getCwd, 0, 0);
JS_DefineFunction(cx, global, "wxGetFreeDiskSpace", getFreeDiskSpace, 1, 0);
JS_DefineFunction(cx, global, "wxGetTotalDiskSpace", getTotalDiskSpace, 1, 0);
JS_DefineFunction(cx, global, "wxGetOSDirectory", getOSDirectory, 0, 0);
JS_DefineFunction(cx, global, "wxIsAbsolutePath", isAbsolutePath, 1, 0);
JS_DefineFunction(cx, global, "wxIsWild", isWild, 1, 0);
JS_DefineFunction(cx, global, "wxDirExists", dirExists, 1, 0);
JS_DefineFunction(cx, global, "wxMatchWild", matchWild, 3, 0);
JS_DefineFunction(cx, global, "wxMkDir", mkDir, 2, 0);
JS_DefineFunction(cx, global, "wxRemoveFile", removeFile, 1, 0);
JS_DefineFunction(cx, global, "wxRmDir", rmDir, 1, 0);
JS_DefineFunction(cx, global, "wxSetWorkingDirectory", setWorkingDirectory, 1, 0);
JS_DefineFunction(cx, global, "wxExecute", execute, 1, 0);
JS_DefineFunction(cx, global, "wxShell", shell, 1, 0);
JS_DefineFunction(cx, global, "wxConcatFiles", methodInterfaceWrapper<concatFiles>, 3, 0);
JS_DefineFunction(cx, global, "wxCopyFile", methodInterfaceWrapper<copyFile>, 2, 0);
JS_DefineFunction(cx, global, "wxFileExists", methodInterfaceWrapper<fileExists>, 1, 0);
JS_DefineFunction(cx, global, "wxRenameFile", methodInterfaceWrapper<renameFile>, 2, 0);
JS_DefineFunction(cx, global, "wxGetCwd", methodInterfaceWrapper<getCwd>, 0, 0);
JS_DefineFunction(cx, global, "wxGetFreeDiskSpace", methodInterfaceWrapper<getFreeDiskSpace>, 1, 0);
JS_DefineFunction(cx, global, "wxGetTotalDiskSpace", methodInterfaceWrapper<getTotalDiskSpace>, 1, 0);
JS_DefineFunction(cx, global, "wxGetOSDirectory", methodInterfaceWrapper<getOSDirectory>, 0, 0);
JS_DefineFunction(cx, global, "wxIsAbsolutePath", methodInterfaceWrapper<isAbsolutePath>, 1, 0);
JS_DefineFunction(cx, global, "wxIsWild", methodInterfaceWrapper<isWild>, 1, 0);
JS_DefineFunction(cx, global, "wxDirExists", methodInterfaceWrapper<dirExists>, 1, 0);
JS_DefineFunction(cx, global, "wxMatchWild", methodInterfaceWrapper<matchWild>, 3, 0);
JS_DefineFunction(cx, global, "wxMkDir", methodInterfaceWrapper<mkDir>, 2, 0);
JS_DefineFunction(cx, global, "wxRemoveFile", methodInterfaceWrapper<removeFile>, 1, 0);
JS_DefineFunction(cx, global, "wxRmDir", methodInterfaceWrapper<rmDir>, 1, 0);
JS_DefineFunction(cx, global, "wxSetWorkingDirectory", methodInterfaceWrapper<setWorkingDirectory>, 1, 0);
JS_DefineFunction(cx, global, "wxExecute", methodInterfaceWrapper<execute>, 1, 0);
JS_DefineFunction(cx, global, "wxShell", methodInterfaceWrapper<shell>, 1, 0);
return true;
}

View File

@ -157,7 +157,7 @@ bool TextLine::Enumerate(Index *p, JSContext *cx, JSObject *obj, JSIterateOp enu
{
*statep = JSVAL_NULL;
if (idp)
*idp = INT_TO_JSVAL(0);
*idp = INT_TO_JSID(0);
return true;
}
@ -166,7 +166,7 @@ bool TextLine::Enumerate(Index *p, JSContext *cx, JSObject *obj, JSIterateOp enu
{
*statep = JSVAL_NULL;
if (idp)
*idp = INT_TO_JSVAL(0);
*idp = INT_TO_JSID(0);
return true;
}
@ -177,7 +177,7 @@ bool TextLine::Enumerate(Index *p, JSContext *cx, JSObject *obj, JSIterateOp enu
case JSENUMERATE_INIT:
*statep = ToJS(cx, 0);
if ( idp )
*idp = INT_TO_JSVAL(file->GetLineCount());
*idp = INT_TO_JSID(file->GetLineCount());
break;
case JSENUMERATE_NEXT:
{

View File

@ -5,6 +5,13 @@
#ifdef _WIN32
# define XP_WIN
# define WIN32 // SpiderMonkey expects this
// The jsval struct type causes crashes due to weird miscompilation
// issues in (at least) VC2008, so force it to be the less-type-safe
// non-struct type instead
# define JS_NO_JSVAL_JSID_STRUCT_TYPES
#else
# define XP_UNIX
#endif // (we don't support XP_OS2 or XP_BEOS)