diff --git a/binaries/data/mods/_test.sim/simulation/components/test-entityid.js b/binaries/data/mods/_test.sim/simulation/components/test-entityid.js index e0541699d9..b6cf0da9e8 100644 --- a/binaries/data/mods/_test.sim/simulation/components/test-entityid.js +++ b/binaries/data/mods/_test.sim/simulation/components/test-entityid.js @@ -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; diff --git a/binaries/data/mods/_test.sim/simulation/components/test-serialize.js b/binaries/data/mods/_test.sim/simulation/components/test-serialize.js index be8cba461d..9893d6d794 100644 --- a/binaries/data/mods/_test.sim/simulation/components/test-serialize.js +++ b/binaries/data/mods/_test.sim/simulation/components/test-serialize.js @@ -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; diff --git a/binaries/data/tools/atlas/scripts/section/terrain.js b/binaries/data/tools/atlas/scripts/section/terrain.js index 7b852f0ea0..8978390e7b 100644 --- a/binaries/data/tools/atlas/scripts/section/terrain.js +++ b/binaries/data/tools/atlas/scripts/section/terrain.js @@ -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; }; diff --git a/source/graphics/GameView.cpp b/source/graphics/GameView.cpp index 6c2d36fe01..838bdfec5b 100644 --- a/source/graphics/GameView.cpp +++ b/source/graphics/GameView.cpp @@ -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); diff --git a/source/graphics/scripting/JSInterface_Camera.cpp b/source/graphics/scripting/JSInterface_Camera.cpp deleted file mode 100644 index 6a3c2adc3c..0000000000 --- a/source/graphics/scripting/JSInterface_Camera.cpp +++ /dev/null @@ -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 . - */ - -#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( 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( 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 ) ); -} - diff --git a/source/graphics/scripting/JSInterface_Camera.h b/source/graphics/scripting/JSInterface_Camera.h deleted file mode 100644 index f7ded003fb..0000000000 --- a/source/graphics/scripting/JSInterface_Camera.h +++ /dev/null @@ -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 . - */ - -// 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 diff --git a/source/graphics/scripting/JSInterface_LightEnv.cpp b/source/graphics/scripting/JSInterface_LightEnv.cpp deleted file mode 100644 index ac17ec8132..0000000000 --- a/source/graphics/scripting/JSInterface_LightEnv.cpp +++ /dev/null @@ -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 . - */ - -/* - * 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(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(id)) { - case lightenv_elevation: lightenv->SetElevation(ToPrimitive(*vp)); break; - case lightenv_rotation: lightenv->SetRotation(ToPrimitive(*vp)); break; - case lightenv_terrainShadowTransparency: lightenv->SetTerrainShadowTransparency(ToPrimitive(*vp)); break; - case lightenv_sun: lightenv->m_SunColor = ToPrimitive(*vp); break; - case lightenv_terrainAmbient: lightenv->m_TerrainAmbientColor = ToPrimitive(*vp); break; - case lightenv_unitsAmbient: lightenv->m_UnitsAmbientColor = ToPrimitive(*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 - - diff --git a/source/graphics/scripting/JSInterface_LightEnv.h b/source/graphics/scripting/JSInterface_LightEnv.h deleted file mode 100644 index c2da76c229..0000000000 --- a/source/graphics/scripting/JSInterface_LightEnv.h +++ /dev/null @@ -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 . - */ - -/* - * 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 diff --git a/source/gui/CGUI.cpp b/source/gui/CGUI.cpp index cd67124206..b51947b4ed 100644 --- a/source/gui/CGUI.cpp +++ b/source/gui/CGUI.cpp @@ -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); } } diff --git a/source/gui/GUIManager.cpp b/source/gui/GUIManager.cpp index 5c0423817b..5db258443a 100644 --- a/source/gui/GUIManager.cpp +++ b/source/gui/GUIManager.cpp @@ -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()); } diff --git a/source/gui/GUIManager.h b/source/gui/GUIManager.h index d6b456e2f6..4957e621e4 100644 --- a/source/gui/GUIManager.h +++ b/source/gui/GUIManager.h @@ -135,15 +135,11 @@ public: private: struct SGUIPage { - SGUIPage(); - SGUIPage(const SGUIPage&); - ~SGUIPage(); - CStrW name; std::set 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 gui; // the actual GUI page }; diff --git a/source/gui/IGUIObject.cpp b/source/gui/IGUIObject.cpp index 5ef7752533..cabf002e91 100644 --- a/source/gui/IGUIObject.cpp +++ b/source/gui/IGUIObject.cpp @@ -90,13 +90,13 @@ IGUIObject::~IGUIObject() std::map::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; diff --git a/source/gui/IGUIObject.h b/source/gui/IGUIObject.h index 2e6e8292f2..24ce4afabf 100644 --- a/source/gui/IGUIObject.h +++ b/source/gui/IGUIObject.h @@ -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(); diff --git a/source/gui/scripting/GuiScriptConversions.cpp b/source/gui/scripting/GuiScriptConversions.cpp index be30568833..c77e39749a 100644 --- a/source/gui/scripting/GuiScriptConversions.cpp +++ b/source/gui/scripting/GuiScriptConversions.cpp @@ -46,10 +46,6 @@ template<> jsval ScriptInterface::ToJSVal(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(JSContext* cx, SDL_Event_ jsval rval = OBJECT_TO_JSVAL(obj); - scope.LeaveWithResult(rval); return rval; } diff --git a/source/gui/scripting/JSInterface_GUITypes.cpp b/source/gui/scripting/JSInterface_GUITypes.cpp index 0d09e6937a..b197ace95c 100644 --- a/source/gui/scripting/JSInterface_GUITypes.cpp +++ b/source/gui/scripting/JSInterface_GUITypes.cpp @@ -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, "")); + JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(JS_NewStringCopyZ(cx, ""))); 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; } diff --git a/source/gui/scripting/JSInterface_GUITypes.h b/source/gui/scripting/JSInterface_GUITypes.h index 7dbbe4e0f1..c8e74c1524 100644 --- a/source/gui/scripting/JSInterface_GUITypes.h +++ b/source/gui/scripting/JSInterface_GUITypes.h @@ -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) diff --git a/source/gui/scripting/JSInterface_IGUIObject.cpp b/source/gui/scripting/JSInterface_IGUIObject.cpp index 4205af01be..da0b72ee57 100644 --- a/source/gui/scripting/JSInterface_IGUIObject.cpp +++ b/source/gui/scripting/JSInterface_IGUIObject.cpp @@ -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::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::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::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::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::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::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::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::SetSetting(e, propName, value); break; } case GUIST_CGUISpriteInstance: { - CStr value (JS_GetStringBytes(JS_ValueToString(cx, *vp))); - GUI::SetSetting(e, propName, value); + std::string value; + if (!ScriptInterface::FromJSVal(cx, *vp, value)) + return JS_FALSE; + + GUI::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; } diff --git a/source/gui/scripting/JSInterface_IGUIObject.h b/source/gui/scripting/JSInterface_IGUIObject.h index 28ae20e051..d971bb158b 100644 --- a/source/gui/scripting/JSInterface_IGUIObject.h +++ b/source/gui/scripting/JSInterface_IGUIObject.h @@ -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(); } diff --git a/source/lib/sysdep/os/win/wposix/wposix_types.h b/source/lib/sysdep/os/win/wposix/wposix_types.h index 3b52051dd9..58afcd6c0e 100644 --- a/source/lib/sysdep/os/win/wposix/wposix_types.h +++ b/source/lib/sysdep/os/win/wposix/wposix_types.h @@ -34,7 +34,7 @@ // // -typedef signed char int8_t; +typedef __int8 int8_t; typedef short int16_t; // already defined by MinGW diff --git a/source/maths/scripting/JSInterface_Vector3D.cpp b/source/maths/scripting/JSInterface_Vector3D.cpp index d7e8569502..2d17e838e9 100644 --- a/source/maths/scripting/JSInterface_Vector3D.cpp +++ b/source/maths/scripting/JSInterface_Vector3D.cpp @@ -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( 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( id ) ) + switch (JSID_TO_INT(id)) { - case component_x: vectorData->X = ToPrimitive( *vp ); break; - case component_y: vectorData->Y = ToPrimitive( *vp ); break; - case component_z: vectorData->Z = ToPrimitive( *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 (*vp); + break; + case component_y: + vectorData->Y = ToPrimitive (*vp); + break; + case component_z: + vectorData->Z = ToPrimitive (*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( argv[0] ); - float y = ToPrimitive( argv[1] ); - float z = ToPrimitive( argv[2] ); - JS_SetPrivate( cx, vector, new Vector3D_Info( x, y, z ) ); - *rval = OBJECT_TO_JSVAL( vector ); - return( JS_TRUE ); + float x = ToPrimitive (JS_ARGV(cx, vp)[0]); + float y = ToPrimitive (JS_ARGV(cx, vp)[1]); + float z = ToPrimitive (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; } diff --git a/source/maths/scripting/JSInterface_Vector3D.h b/source/maths/scripting/JSInterface_Vector3D.h index f2486bacae..ab08ec9adf 100644 --- a/source/maths/scripting/JSInterface_Vector3D.h +++ b/source/maths/scripting/JSInterface_Vector3D.h @@ -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 - - diff --git a/source/ps/ConfigDB.cpp b/source/ps/ConfigDB.cpp index 88876750b5..8091d6de7e 100644 --- a/source/ps/ConfigDB.cpp +++ b/source/ps/ConfigDB.cpp @@ -24,6 +24,8 @@ #include "Filesystem.h" #include "scripting/ScriptingHost.h" +#include "scriptinterface/ScriptInterface.h" + #include typedef std::map 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 > CConfigDB::GetValuesWithPrefix(EConfigNamespace ns, const CStr& prefix) diff --git a/source/ps/GameSetup/GameSetup.cpp b/source/ps/GameSetup/GameSetup.cpp index cf89b40aeb..695e2ff2d7 100644 --- a/source/ps/GameSetup/GameSetup.cpp +++ b/source/ps/GameSetup/GameSetup.cpp @@ -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 diff --git a/source/ps/StringConvert.cpp b/source/ps/StringConvert.cpp deleted file mode 100644 index a859de777d..0000000000 --- a/source/ps/StringConvert.cpp +++ /dev/null @@ -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 . - */ - -#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. - */ - -#ifndef INCLUDED_STRINGCONVERT -#define INCLUDED_STRINGCONVERT - -typedef unsigned short jschar; -typedef unsigned short ucs2char; - -struct JSString; -struct JSContext; - -#include - -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 diff --git a/source/ps/scripting/JSInterface_Console.cpp b/source/ps/scripting/JSInterface_Console.cpp index 31541d5441..79b3005ece 100644 --- a/source/ps/scripting/JSInterface_Console.cpp +++ b/source/ps/scripting/JSInterface_Console.cpp @@ -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( *vp ) ); - return( JS_TRUE ); + g_Console->SetVisible(ToPrimitive (*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; } diff --git a/source/ps/scripting/JSInterface_Console.h b/source/ps/scripting/JSInterface_Console.h index ae99c05581..2512bcb63e 100644 --- a/source/ps/scripting/JSInterface_Console.h +++ b/source/ps/scripting/JSInterface_Console.h @@ -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 diff --git a/source/ps/scripting/JSInterface_VFS.cpp b/source/ps/scripting/JSInterface_VFS.cpp index 9ed49f3fbe..0176e9eb93 100644 --- a/source/ps/scripting/JSInterface_VFS.cpp +++ b/source/ps/scripting/JSInterface_VFS.cpp @@ -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( cx, argv[0], path ) ) - return( JS_FALSE ); + if (!ToPrimitive (cx, JS_ARGV(cx, vp)[0], path)) + return JS_FALSE; CStrW filter_str = L""; - if(argc >= 2) + if (argc >= 2) { - if( !ToPrimitive( cx, argv[1], filter_str ) ) - return( JS_FALSE ); + if (!ToPrimitive (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( cx, argv[2], recursive ) ) - return( JS_FALSE ); + if (!ToPrimitive (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( cx, argv[0], filename ) ) - return( JS_FALSE ); + if (!ToPrimitive (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( cx, argv[0], filename ) ) - return( JS_FALSE ); + if (!ToPrimitive (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( cx, argv[0], filename ) ) - return( JS_FALSE ); + JSU_REQUIRE_MIN_PARAMS(1); - shared_ptr buf; size_t size; - LibError err = g_VFS->LoadFile( CStrW(filename), buf, size ); + CStr filename; + if (!ToPrimitive (cx, JS_ARGV(cx, vp)[0], filename)) + return JS_FALSE; + + shared_ptr 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( cx, argv[0], filename ) ) - return( JS_FALSE ); + if (!ToPrimitive (cx, JS_ARGV(cx, vp)[0], filename)) + return (JS_FALSE); // // read file // - shared_ptr buf; size_t size; - LibError err = g_VFS->LoadFile( CStrW(filename), buf, size ); + shared_ptr 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; } diff --git a/source/ps/scripting/JSInterface_VFS.h b/source/ps/scripting/JSInterface_VFS.h index 1e8fe8e0b0..603622198b 100644 --- a/source/ps/scripting/JSInterface_VFS.h +++ b/source/ps/scripting/JSInterface_VFS.h @@ -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 diff --git a/source/scripting/JSConversions.cpp b/source/scripting/JSConversions.cpp index b9bfb602bf..856e39ec33 100644 --- a/source/scripting/JSConversions.cpp +++ b/source/scripting/JSConversions.cpp @@ -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 #include @@ -180,12 +181,16 @@ template<> bool ToPrimitive( JSContext* cx, jsval v, ssize_t& Storage ) template<> jsval ToJSVal( 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& 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( JSContext* cx, jsval v, double& Storage ) @@ -200,12 +205,16 @@ template<> bool ToPrimitive( JSContext* cx, jsval v, double& Storage ) template<> jsval ToJSVal( 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& 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( JSContext* cx, jsval v, float& Storage ) @@ -256,27 +265,23 @@ template<> bool ToPrimitive( JSContext* UNUSED(cx), jsval v, CStrW& Stora template<> jsval ToJSVal( 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(Native.utf16().c_str()) ) ) ); } template<> jsval ToJSVal( 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(Native.utf16().c_str()) ) ) ); } // CStr/CStr8 -template<> bool ToPrimitive( JSContext* UNUSED(cx), jsval v, CStr8& Storage ) +template<> bool ToPrimitive( 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( 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 ) ); diff --git a/source/scripting/JSUtil.cpp b/source/scripting/JSUtil.cpp index 4061a9fe67..bc7fb75d09 100644 --- a/source/scripting/JSUtil.cpp +++ b/source/scripting/JSUtil.cpp @@ -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. diff --git a/source/scripting/JSUtil.h b/source/scripting/JSUtil.h index 3cc3f2ee1c..574b9a2f6f 100644 --- a/source/scripting/JSUtil.h +++ b/source/scripting/JSUtil.h @@ -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 diff --git a/source/scripting/ScriptGlue.cpp b/source/scripting/ScriptGlue.cpp index 430d40bdb4..e0185836b5 100644 --- a/source/scripting/ScriptGlue.cpp +++ b/source/scripting/ScriptGlue.cpp @@ -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(argv[0]); + size_t slot = ToPrimitive(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(argv[0]); + size_t slot = ToPrimitive(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(argv[0])); - return JS_TRUE; -} - - -JSBool GetGUIObjectByName(JSContext* cx, JSObject* UNUSED(obj), uintN UNUSED(argc), jsval* argv, jsval* rval) -{ try { - CStr name = ToPrimitive(cx, argv[0]); + CStr name = ToPrimitive(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( argv[0] ); + g_Game->m_Paused = ToPrimitive (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 }, diff --git a/source/scripting/ScriptableObject.h b/source/scripting/ScriptableObject.h index c1347bbf74..bebd790587 100644 --- a/source/scripting/ScriptableObject.h +++ b/source/scripting/ScriptableObject.h @@ -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 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( cx, obj ); + T* Native = ToNative( cx, JS_THIS_OBJECT( cx, vp ) ); if( !Native ) - return( JS_TRUE ); - - *rval = ToJSVal( (Native->*NativeFunction)( cx, argc, argv ) ); + return( JS_FALSE ); + jsval rval = ToJSVal( (Native->*NativeFunction)( cx, argc, JS_ARGV(cx, vp) ) ); + JS_SET_RVAL( cx, vp, rval ); return( JS_TRUE ); } }; @@ -196,14 +196,15 @@ template { 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( cx, obj ); + T* Native = ToNative( 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 static void AddMethod( const char* Name, uintN MinArgs ) { - JSFunctionSpec FnInfo = { Name, CNativeFunction::JSFunction, (uint8)MinArgs, 0, 0 }; + JSFunctionSpec FnInfo = { Name, CNativeFunction::JSFunction, (uint8)MinArgs, 0 }; m_Methods.push_back( FnInfo ); } template 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( 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( 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 ); diff --git a/source/scripting/ScriptingHost.cpp b/source/scripting/ScriptingHost.cpp index 4a835415cf..36b961e88e 100644 --- a/source/scripting/ScriptingHost.cpp +++ b/source/scripting/ScriptingHost.cpp @@ -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(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(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); diff --git a/source/scripting/ScriptingHost.h b/source/scripting/ScriptingHost.h index 1327c8a8dc..732c464a66 100644 --- a/source/scripting/ScriptingHost.h +++ b/source/scripting/ScriptingHost.h @@ -111,7 +111,6 @@ public: void SetGlobal(const std::string& globalName, jsval value); - std::string ValueToString(const jsval value); CStrW ValueToUCString(const jsval value); }; diff --git a/source/scripting/SpiderMonkey.h b/source/scripting/SpiderMonkey.h index f3563dc482..ed9a0e839f 100644 --- a/source/scripting/SpiderMonkey.h +++ b/source/scripting/SpiderMonkey.h @@ -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 - -#ifndef NDEBUG -// Used by ScriptingHost::jshook_{script,function} -# include -#endif - -// include any further required headers here +#include "scriptinterface/ScriptTypes.h" #include "JSUtil.h" diff --git a/source/scriptinterface/AutoRooters.cpp b/source/scriptinterface/AutoRooters.cpp index a6047d5547..7b7097c88e 100644 --- a/source/scriptinterface/AutoRooters.cpp +++ b/source/scriptinterface/AutoRooters.cpp @@ -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"); + } + } + } diff --git a/source/scriptinterface/AutoRooters.h b/source/scriptinterface/AutoRooters.h index acdf8740b5..3cf94ad256 100644 --- a/source/scriptinterface/AutoRooters.h +++ b/source/scriptinterface/AutoRooters.h @@ -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 m_Objects; std::vector m_Vals; + std::vector m_IdArrays; // TODO: add vectors of other value types }; diff --git a/source/scriptinterface/ScriptConversions.cpp b/source/scriptinterface/ScriptConversions.cpp index d2ec1df494..66e86a5a8f 100644 --- a/source/scriptinterface/ScriptConversions.cpp +++ b/source/scriptinterface/ScriptConversions.cpp @@ -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(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(JSContext* cx, jsval v, bool& o template<> bool ScriptInterface::FromJSVal(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(JSContext* cx, jsval v, float& template<> bool ScriptInterface::FromJSVal(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(JSContext* cx, jsval v, doubl template<> bool ScriptInterface::FromJSVal(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(JSContext* cx, jsval v, i32& out template<> bool ScriptInterface::FromJSVal(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(JSContext* cx, jsva template<> bool ScriptInterface::FromJSVal(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(JSContext* cx, jsval v, template<> bool ScriptInterface::FromJSVal(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(JSContext* cx, const double& v return rval; } -template<> jsval ScriptInterface::ToJSVal(JSContext* cx, const i32& val) +template<> jsval ScriptInterface::ToJSVal(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(JSContext* cx, const u32& val) @@ -185,6 +183,11 @@ template<> jsval ScriptInterface::ToJSVal(JSContext* cx, const std: return JSVAL_VOID; } +template<> jsval ScriptInterface::ToJSVal(JSContext* cx, const wchar_t* const& val) +{ + return ToJSVal(cx, std::wstring(val)); +} + template<> jsval ScriptInterface::ToJSVal(JSContext* cx, const char* const& val) { JSString* str = JS_NewStringCopyZ(cx, val); @@ -193,6 +196,16 @@ template<> jsval ScriptInterface::ToJSVal(JSContext* cx, const char return JSVAL_VOID; } +template<> jsval ScriptInterface::ToJSVal(JSContext* cx, const CStrW& val) +{ + return ToJSVal(cx, static_cast(val)); +} + +template<> jsval ScriptInterface::ToJSVal(JSContext* cx, const CStr8& val) +{ + return ToJSVal(cx, static_cast(val)); +} + //////////////////////////////////////////////////////////////// // Compound types: @@ -201,13 +214,11 @@ template 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(cx, val[i]); JS_SetElement(cx, obj, (jsint)i, &el); } - JS_RemoveRoot(cx, &obj); return OBJECT_TO_JSVAL(obj); } diff --git a/source/scriptinterface/ScriptInterface.cpp b/source/scriptinterface/ScriptInterface.cpp index 416de46c4c..25e9c6a5b8 100644 --- a/source/scriptinterface/ScriptInterface.cpp +++ b/source/scriptinterface/ScriptInterface.cpp @@ -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(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& 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(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::iterator it = m_Mapping.find(val); + std::map::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 m_Mapping; + std::map m_Mapping; AutoGCRooter m_RooterFrom; AutoGCRooter m_RooterTo; }; diff --git a/source/scriptinterface/ScriptInterface.h b/source/scriptinterface/ScriptInterface.h index bcc24b0f18..fb99a61459 100644 --- a/source/scriptinterface/ScriptInterface.h +++ b/source/scriptinterface/ScriptInterface.h @@ -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 #include #include @@ -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 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 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 - // static JSFastNative call; + // static JSNative call; // // template - // static JSFastNative callMethod; + // static JSNative callMethod; // // template // static size_t nargs(); @@ -293,7 +268,6 @@ public: template 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 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 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 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 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 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 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 bool ScriptInterface::SetGlobal(const char* name, const T& value, bool replace) { - LOCAL_ROOT_SCOPE; return SetGlobal_(name, ToJSVal(GetContext(), value), replace); } template bool ScriptInterface::SetProperty(jsval obj, const char* name, const T& value, bool readonly) { - LOCAL_ROOT_SCOPE; return SetProperty_(obj, name, ToJSVal(GetContext(), value), readonly); } diff --git a/source/scriptinterface/ScriptTypes.h b/source/scriptinterface/ScriptTypes.h index e29ce40087..c73f8a9119 100644 --- a/source/scriptinterface/ScriptTypes.h +++ b/source/scriptinterface/ScriptTypes.h @@ -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. diff --git a/source/scriptinterface/ScriptVal.cpp b/source/scriptinterface/ScriptVal.cpp index b62ce51a75..00fa704395 100644 --- a/source/scriptinterface/ScriptVal.cpp +++ b/source/scriptinterface/ScriptVal.cpp @@ -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(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(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]; +} diff --git a/source/scriptinterface/ScriptVal.h b/source/scriptinterface/ScriptVal.h index 8a7c3b8222..5ac1e452c3 100644 --- a/source/scriptinterface/ScriptVal.h +++ b/source/scriptinterface/ScriptVal.h @@ -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 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 diff --git a/source/scriptinterface/tests/test_ScriptConversions.h b/source/scriptinterface/tests/test_ScriptConversions.h index a9154f9e45..3d2827d8a0 100644 --- a/source/scriptinterface/tests/test_ScriptConversions.h +++ b/source/scriptinterface/tests/test_ScriptConversions.h @@ -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 @@ -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(cx, 0))); - TS_ASSERT(JSVAL_IS_INT(ScriptInterface::ToJSVal(cx, 1073741822))); // JSVAL_INT_MAX-1 - TS_ASSERT(JSVAL_IS_INT(ScriptInterface::ToJSVal(cx, 1073741823))); // JSVAL_INT_MAX - TS_ASSERT(JSVAL_IS_DOUBLE(ScriptInterface::ToJSVal(cx, 1073741824))); // JSVAL_INT_MAX+1 - TS_ASSERT(JSVAL_IS_INT(ScriptInterface::ToJSVal(cx, -1073741823))); // JSVAL_INT_MIN+1 - TS_ASSERT(JSVAL_IS_INT(ScriptInterface::ToJSVal(cx, -1073741824))); // JSVAL_INT_MIN - TS_ASSERT(JSVAL_IS_DOUBLE(ScriptInterface::ToJSVal(cx, -1073741825))); // JSVAL_INT_MIN-1 + TS_ASSERT(JSVAL_IS_INT(ScriptInterface::ToJSVal(cx, 2147483646))); // JSVAL_INT_MAX-1 + TS_ASSERT(JSVAL_IS_INT(ScriptInterface::ToJSVal(cx, 2147483647))); // JSVAL_INT_MAX + TS_ASSERT(JSVAL_IS_INT(ScriptInterface::ToJSVal(cx, -2147483647))); // JSVAL_INT_MIN+1 + TS_ASSERT(JSVAL_IS_INT(ScriptInterface::ToJSVal(cx, -(i64)2147483648))); // JSVAL_INT_MIN TS_ASSERT(JSVAL_IS_INT(ScriptInterface::ToJSVal(cx, 0))); - TS_ASSERT(JSVAL_IS_INT(ScriptInterface::ToJSVal(cx, 1073741822))); // JSVAL_INT_MAX-1 - TS_ASSERT(JSVAL_IS_INT(ScriptInterface::ToJSVal(cx, 1073741823))); // JSVAL_INT_MAX - TS_ASSERT(JSVAL_IS_DOUBLE(ScriptInterface::ToJSVal(cx, 1073741824))); // JSVAL_INT_MAX+1 + TS_ASSERT(JSVAL_IS_INT(ScriptInterface::ToJSVal(cx, 2147483646))); // JSVAL_INT_MAX-1 + TS_ASSERT(JSVAL_IS_INT(ScriptInterface::ToJSVal(cx, 2147483647))); // JSVAL_INT_MAX + TS_ASSERT(JSVAL_IS_DOUBLE(ScriptInterface::ToJSVal(cx, 2147483648))); // JSVAL_INT_MAX+1 } void test_nonfinite() diff --git a/source/scriptinterface/tests/test_ScriptInterface.h b/source/scriptinterface/tests/test_ScriptInterface.h index ff8b71f9ce..4008631390 100644 --- a/source/scriptinterface/tests/test_ScriptInterface.h +++ b/source/scriptinterface/tests/test_ScriptInterface.h @@ -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})"); diff --git a/source/simulation2/components/ICmpFootprint.cpp b/source/simulation2/components/ICmpFootprint.cpp index 9e09dbe860..056c810965 100644 --- a/source/simulation2/components/ICmpFootprint.cpp +++ b/source/simulation2/components/ICmpFootprint.cpp @@ -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; diff --git a/source/simulation2/scripting/EngineScriptConversions.cpp b/source/simulation2/scripting/EngineScriptConversions.cpp index f06db98b34..3d523e82b1 100644 --- a/source/simulation2/scripting/EngineScriptConversions.cpp +++ b/source/simulation2/scripting/EngineScriptConversions.cpp @@ -37,7 +37,7 @@ template<> jsval ScriptInterface::ToJSVal(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(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(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(JSContext* cx, cons template<> bool ScriptInterface::FromJSVal(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(JSContext* cx, jsval v, CColo template<> jsval ScriptInterface::ToJSVal(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(JSContext* cx, const fixed& val template<> bool ScriptInterface::FromJSVal(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(JSContext* cx, jsval template<> jsval ScriptInterface::ToJSVal(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(JSContext* cx, const C template<> bool ScriptInterface::FromJSVal(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); diff --git a/source/simulation2/scripting/MessageTypeConversions.cpp b/source/simulation2/scripting/MessageTypeConversions.cpp index e9f31d650c..8491ceb34d 100644 --- a/source/simulation2/scripting/MessageTypeConversions.cpp +++ b/source/simulation2/scripting/MessageTypeConversions.cpp @@ -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 diff --git a/source/simulation2/scripting/ScriptComponent.cpp b/source/simulation2/scripting/ScriptComponent.cpp index fe957a40a3..246a42acc5 100644 --- a/source/simulation2/scripting/ScriptComponent.cpp +++ b/source/simulation2/scripting/ScriptComponent.cpp @@ -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); } diff --git a/source/simulation2/scripting/ScriptComponent.h b/source/simulation2/scripting/ScriptComponent.h index 4ebac2affd..e7e45f1ec8 100644 --- a/source/simulation2/scripting/ScriptComponent.h +++ b/source/simulation2/scripting/ScriptComponent.h @@ -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); diff --git a/source/simulation2/serialization/BinarySerializer.cpp b/source/simulation2/serialization/BinarySerializer.cpp index 1a2426f62a..62921d63b3 100644 --- a/source/simulation2/serialization/BinarySerializer.cpp +++ b/source/simulation2/serialization/BinarySerializer.cpp @@ -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 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; } diff --git a/source/simulation2/serialization/StdDeserializer.cpp b/source/simulation2/serialization/StdDeserializer.cpp index 43b2844130..aafe20e5aa 100644 --- a/source/simulation2/serialization/StdDeserializer.cpp +++ b/source/simulation2/serialization/StdDeserializer.cpp @@ -46,7 +46,7 @@ void CStdDeserializer::AddScriptBackref(JSObject* obj) { std::pair::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::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(); diff --git a/source/simulation2/system/ComponentManager.cpp b/source/simulation2/system/ComponentManager.cpp index c677bd9313..3ce162f52e 100644 --- a/source/simulation2/system/ComponentManager.cpp +++ b/source/simulation2/system/ComponentManager.cpp @@ -100,12 +100,6 @@ CComponentManager::CComponentManager(CSimContext& context, bool skipScriptFuncti CComponentManager::~CComponentManager() { ResetState(); - - // Release GC roots - std::map::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 >::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& 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; diff --git a/source/simulation2/system/ComponentManager.h b/source/simulation2/system/ComponentManager.h index 88059cf191..4609991e77 100644 --- a/source/simulation2/system/ComponentManager.h +++ b/source/simulation2/system/ComponentManager.h @@ -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: diff --git a/source/simulation2/system/IComponent.cpp b/source/simulation2/system/IComponent.cpp index 195b6982b2..67ce2de6fc 100644 --- a/source/simulation2/system/IComponent.cpp +++ b/source/simulation2/system/IComponent.cpp @@ -40,5 +40,5 @@ JSClass* IComponent::GetJSClass() const jsval IComponent::GetJSInstance() const { - return 0; + return JSVAL_NULL; } diff --git a/source/simulation2/system/InterfaceScripted.h b/source/simulation2/system/InterfaceScripted.h index 9554b9731a..4731c286be 100644 --- a/source/simulation2/system/InterfaceScripted.h +++ b/source/simulation2/system/InterfaceScripted.h @@ -45,38 +45,38 @@ #define DEFINE_INTERFACE_METHOD_0(scriptname, rettype, classname, methodname) \ { scriptname, \ - reinterpret_cast(static_cast(ScriptInterface::callMethod)), \ + ScriptInterface::callMethod, \ 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(static_cast(ScriptInterface::callMethod)), \ + ScriptInterface::callMethod, \ 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(static_cast(ScriptInterface::callMethod)), \ + ScriptInterface::callMethod, \ 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(static_cast(ScriptInterface::callMethod)), \ + ScriptInterface::callMethod, \ 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(static_cast(ScriptInterface::callMethod)), \ + ScriptInterface::callMethod, \ 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(static_cast(ScriptInterface::callMethod)), \ + ScriptInterface::callMethod, \ 5, \ - JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT|JSFUN_FAST_NATIVE, 0 }, + JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT }, #endif // INCLUDED_INTERFACE_SCRIPTED diff --git a/source/simulation2/tests/test_ComponentManager.h b/source/simulation2/tests/test_ComponentManager.h index 662b833fe5..fabaea0251 100644 --- a/source/simulation2/tests/test_ComponentManager.h +++ b/source/simulation2/tests/test_ComponentManager.h @@ -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 (man.QueryInterface(ent1, IID_Test1))->GetX(), (int)ent1); TS_ASSERT_EQUALS(static_cast (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")); diff --git a/source/simulation2/tests/test_Serializer.h b/source/simulation2/tests/test_Serializer.h index 96c2d58ae3..a7e2593995 100644 --- a/source/simulation2/tests/test_Serializer.h +++ b/source/simulation2/tests/test_Serializer.h @@ -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() diff --git a/source/sound/JSI_Sound.cpp b/source/sound/JSI_Sound.cpp index a527394bd9..a1141f28c0 100644 --- a/source/sound/JSI_Sound.cpp +++ b/source/sound/JSI_Sound.cpp @@ -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(cx, argv[0], filename)) + if (! ToPrimitive(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; } diff --git a/source/sound/JSI_Sound.h b/source/sound/JSI_Sound.h index 2b6c3ca2ec..17739805bb 100644 --- a/source/sound/JSI_Sound.h +++ b/source/sound/JSI_Sound.h @@ -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 diff --git a/source/tools/atlas/AtlasScript/NativeWrapper.inl b/source/tools/atlas/AtlasScript/NativeWrapper.inl index 00df75f072..148c98cc5e 100644 --- a/source/tools/atlas/AtlasScript/NativeWrapper.inl +++ b/source/tools/atlas/AtlasScript/NativeWrapper.inl @@ -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(cx, argv[i], a##i)) return JS_FALSE; + #define CONVERT_ARG(z, i, data) T##i a##i; if (! ScriptInterface::FromJSVal(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 \ - 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 { // JSNative-compatible function that wraps the function identified in the template argument list #define OVERLOADS(z, i, data) \ template \ - 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::call(cx, *rval, fptr A0_TAIL(z,i)); \ + jsval rval = JSVAL_VOID; \ + ScriptInterface_NativeWrapper::call(cx, rval, fptr A0_TAIL(z,i)); \ + JS_SET_RVAL(cx, vp, rval); \ return JS_TRUE; \ } BOOST_PP_REPEAT(MAX_ARGS, OVERLOADS, ~) diff --git a/source/tools/atlas/AtlasScript/ScriptInterface.cpp b/source/tools/atlas/AtlasScript/ScriptInterface.cpp index a31c99231b..a98b42efbe 100644 --- a/source/tools/atlas/AtlasScript/ScriptInterface.cpp +++ b/source/tools/atlas/AtlasScript/ScriptInterface.cpp @@ -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::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::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::Convert(cx, *val.id), NULL, NULL, JSPROP_ENUMERATE); JS_DefineProperty(cx, obj, "name", ToJSVal::Convert(cx, *val.name), NULL, NULL, JSPROP_ENUMERATE); JS_DefineProperty(cx, obj, "type", ToJSVal::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::Convert(cx, val.player), NULL, NULL, JSPROP_ENUMERATE); JS_DefineProperty(cx, obj, "selections", ToJSVal >::Convert(cx, *val.selections), NULL, NULL, JSPROP_ENUMERATE); JS_DefineProperty(cx, obj, "variantgroups", ToJSVal > >::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 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 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 } - diff --git a/source/tools/atlas/AtlasScript/ScriptInterface.h b/source/tools/atlas/AtlasScript/ScriptInterface.h index d2f2237d72..9e7d2e8401 100644 --- a/source/tools/atlas/AtlasScript/ScriptInterface.h +++ b/source/tools/atlas/AtlasScript/ScriptInterface.h @@ -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 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 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 bool ScriptInterface::CallFunction(jsval val, const char* name, const T& a, R& ret) { - LOCAL_ROOT_SCOPE; jsval jsRet; std::vector 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 bool ScriptInterface::CallFunction(jsval val, const char* name, const T& a, const S& b, R& ret) { - LOCAL_ROOT_SCOPE; jsval jsRet; std::vector argv; argv.push_back(ToJSVal(GetContext(), a)); @@ -147,7 +133,6 @@ bool ScriptInterface::CallFunction(jsval val, const char* name, const T& a, cons template 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; } diff --git a/source/tools/atlas/wxJS/common/apiwrap.h b/source/tools/atlas/wxJS/common/apiwrap.h index b6d2ae2ab7..ad2c4dccb3 100644 --- a/source/tools/atlas/wxJS/common/apiwrap.h +++ b/source/tools/atlas/wxJS/common/apiwrap.h @@ -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::wxjs_class = { #define WXJS_END_METHOD_MAP() \ - { 0, 0, 0, 0, 0 } \ + { 0, 0, 0, 0 } \ }; \ JS_DefineFunctions(cx, obj, methods); \ } - + +template +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, args, 0 }, // A macro to reduce the size of the ported classes header. #define WXJS_DECLARE_METHOD(name) static JSBool name(JSContext *cx, \ diff --git a/source/tools/atlas/wxJS/common/clntdata.h b/source/tools/atlas/wxJS/common/clntdata.h index 93760a1bf8..88b6ae7b14 100644 --- a/source/tools/atlas/wxJS/common/clntdata.h +++ b/source/tools/atlas/wxJS/common/clntdata.h @@ -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; } diff --git a/source/tools/atlas/wxJS/common/type.cpp b/source/tools/atlas/wxJS/common/type.cpp index 21bf7acb12..32f570acba 100644 --- a/source/tools/atlas/wxJS/common/type.cpp +++ b/source/tools/atlas/wxJS/common/type.cpp @@ -261,7 +261,7 @@ template<> jsval wxjs::ToJS(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(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(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(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(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(JSContext *cx, const wxStringList &from) node = node->GetNext(); } - JS_RemoveRoot(cx, &objArray); return OBJECT_TO_JSVAL(objArray); } diff --git a/source/tools/atlas/wxJS/gui/control/listctrl.h b/source/tools/atlas/wxJS/gui/control/listctrl.h index 572900c3c8..5d2675d70c 100644 --- a/source/tools/atlas/wxJS/gui/control/listctrl.h +++ b/source/tools/atlas/wxJS/gui/control/listctrl.h @@ -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() diff --git a/source/tools/atlas/wxJS/gui/control/menu.cpp b/source/tools/atlas/wxJS/gui/control/menu.cpp index 4ec2e11019..5496db2cb3 100644 --- a/source/tools/atlas/wxJS/gui/control/menu.cpp +++ b/source/tools/atlas/wxJS/gui/control/menu.cpp @@ -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) ) diff --git a/source/tools/atlas/wxJS/gui/control/toolbar.cpp b/source/tools/atlas/wxJS/gui/control/toolbar.cpp index 27881a93b7..8d313862ff 100644 --- a/source/tools/atlas/wxJS/gui/control/toolbar.cpp +++ b/source/tools/atlas/wxJS/gui/control/toolbar.cpp @@ -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), diff --git a/source/tools/atlas/wxJS/gui/control/treectrl.cpp b/source/tools/atlas/wxJS/gui/control/treectrl.cpp index b9ca09619f..a2b627f6e2 100644 --- a/source/tools/atlas/wxJS/gui/control/treectrl.cpp +++ b/source/tools/atlas/wxJS/gui/control/treectrl.cpp @@ -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; } diff --git a/source/tools/atlas/wxJS/gui/control/treectrl.h b/source/tools/atlas/wxJS/gui/control/treectrl.h index 01ad94c46a..69409b0eea 100644 --- a/source/tools/atlas/wxJS/gui/control/treectrl.h +++ b/source/tools/atlas/wxJS/gui/control/treectrl.h @@ -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() diff --git a/source/tools/atlas/wxJS/gui/event/split.cpp b/source/tools/atlas/wxJS/gui/event/split.cpp index caf14d9e67..aaaa4b7541 100644 --- a/source/tools/atlas/wxJS/gui/event/split.cpp +++ b/source/tools/atlas/wxJS/gui/event/split.cpp @@ -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: diff --git a/source/tools/atlas/wxJS/gui/misc/globfun.cpp b/source/tools/atlas/wxJS/gui/misc/globfun.cpp index 1fb7a88c1d..d4e9be37d3 100644 --- a/source/tools/atlas/wxJS/gui/misc/globfun.cpp +++ b/source/tools/atlas/wxJS/gui/misc/globfun.cpp @@ -64,13 +64,14 @@ static JSFunctionSpec Functions[] = * * */ -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 * * */ -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; } diff --git a/source/tools/atlas/wxJS/gui/misc/globfun.h b/source/tools/atlas/wxJS/gui/misc/globfun.h index 048a052d4a..c08d458802 100644 --- a/source/tools/atlas/wxJS/gui/misc/globfun.h +++ b/source/tools/atlas/wxJS/gui/misc/globfun.h @@ -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 diff --git a/source/tools/atlas/wxJS/gui/misc/image.cpp b/source/tools/atlas/wxJS/gui/misc/image.cpp index b1722c6912..9d6d718f31 100644 --- a/source/tools/atlas/wxJS/gui/misc/image.cpp +++ b/source/tools/atlas/wxJS/gui/misc/image.cpp @@ -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) ) diff --git a/source/tools/atlas/wxJS/io/file.cpp b/source/tools/atlas/wxJS/io/file.cpp index f261b8338e..3e4981e3cd 100644 --- a/source/tools/atlas/wxJS/io/file.cpp +++ b/source/tools/atlas/wxJS/io/file.cpp @@ -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; } diff --git a/source/tools/atlas/wxJS/io/filename.cpp b/source/tools/atlas/wxJS/io/filename.cpp index 4526bf8cbb..92d078798f 100644 --- a/source/tools/atlas/wxJS/io/filename.cpp +++ b/source/tools/atlas/wxJS/io/filename.cpp @@ -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--; diff --git a/source/tools/atlas/wxJS/io/fn.cpp b/source/tools/atlas/wxJS/io/fn.cpp index d57a0b6acf..dcea0a938d 100644 --- a/source/tools/atlas/wxJS/io/fn.cpp +++ b/source/tools/atlas/wxJS/io/fn.cpp @@ -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; diff --git a/source/tools/atlas/wxJS/io/io_init.cpp b/source/tools/atlas/wxJS/io/io_init.cpp index 01d3075c0a..96eaae4ab9 100644 --- a/source/tools/atlas/wxJS/io/io_init.cpp +++ b/source/tools/atlas/wxJS/io/io_init.cpp @@ -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, 3, 0); + JS_DefineFunction(cx, global, "wxCopyFile", methodInterfaceWrapper, 2, 0); + JS_DefineFunction(cx, global, "wxFileExists", methodInterfaceWrapper, 1, 0); + JS_DefineFunction(cx, global, "wxRenameFile", methodInterfaceWrapper, 2, 0); + JS_DefineFunction(cx, global, "wxGetCwd", methodInterfaceWrapper, 0, 0); + JS_DefineFunction(cx, global, "wxGetFreeDiskSpace", methodInterfaceWrapper, 1, 0); + JS_DefineFunction(cx, global, "wxGetTotalDiskSpace", methodInterfaceWrapper, 1, 0); + JS_DefineFunction(cx, global, "wxGetOSDirectory", methodInterfaceWrapper, 0, 0); + JS_DefineFunction(cx, global, "wxIsAbsolutePath", methodInterfaceWrapper, 1, 0); + JS_DefineFunction(cx, global, "wxIsWild", methodInterfaceWrapper, 1, 0); + JS_DefineFunction(cx, global, "wxDirExists", methodInterfaceWrapper, 1, 0); + JS_DefineFunction(cx, global, "wxMatchWild", methodInterfaceWrapper, 3, 0); + JS_DefineFunction(cx, global, "wxMkDir", methodInterfaceWrapper, 2, 0); + JS_DefineFunction(cx, global, "wxRemoveFile", methodInterfaceWrapper, 1, 0); + JS_DefineFunction(cx, global, "wxRmDir", methodInterfaceWrapper, 1, 0); + JS_DefineFunction(cx, global, "wxSetWorkingDirectory", methodInterfaceWrapper, 1, 0); + JS_DefineFunction(cx, global, "wxExecute", methodInterfaceWrapper, 1, 0); + JS_DefineFunction(cx, global, "wxShell", methodInterfaceWrapper, 1, 0); return true; } diff --git a/source/tools/atlas/wxJS/io/textline.cpp b/source/tools/atlas/wxJS/io/textline.cpp index 221f0e076d..4e6e98457c 100644 --- a/source/tools/atlas/wxJS/io/textline.cpp +++ b/source/tools/atlas/wxJS/io/textline.cpp @@ -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: { diff --git a/source/tools/atlas/wxJS/precompiled.h b/source/tools/atlas/wxJS/precompiled.h index af34c26bf1..80778b1eaa 100644 --- a/source/tools/atlas/wxJS/precompiled.h +++ b/source/tools/atlas/wxJS/precompiled.h @@ -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)