Merge pull request #1531 from dumganhar/iss1530-js-improvements

issue #1530: Picked some JSBinding improvements in PR #1499
This commit is contained in:
James Chen 2012-11-01 01:09:39 -07:00
commit 84b642d186
4 changed files with 131 additions and 95 deletions

View File

@ -1,3 +1,3 @@
APP_STL := gnustl_static
APP_CPPFLAGS := -frtti -DCOCOS2D_JAVASCRIPT=1
APP_CPPFLAGS += -DCOCOS2D_DEBUG=2
APP_CPPFLAGS += -DCOCOS2D_DEBUG=1

View File

@ -597,7 +597,7 @@ JSBool ScriptingCore::removeRootJS(JSContext *cx, uint32_t argc, jsval *vp)
void ScriptingCore::pauseSchedulesAndActions(CCNode *node) {
CCArray * arr = JSSchedule::getTargetForNativeNode(node);
CCArray * arr = JSScheduleWrapper::getTargetForNativeNode(node);
if(! arr) return;
for(unsigned int i = 0; i < arr->count(); ++i) {
if(arr->objectAtIndex(i)) {
@ -609,7 +609,7 @@ void ScriptingCore::pauseSchedulesAndActions(CCNode *node) {
void ScriptingCore::resumeSchedulesAndActions(CCNode *node) {
CCArray * arr = JSSchedule::getTargetForNativeNode(node);
CCArray * arr = JSScheduleWrapper::getTargetForNativeNode(node);
if(!arr) return;
for(unsigned int i = 0; i < arr->count(); ++i) {
if(!arr->objectAtIndex(i)) continue;
@ -619,12 +619,12 @@ void ScriptingCore::resumeSchedulesAndActions(CCNode *node) {
void ScriptingCore::cleanupSchedulesAndActions(CCNode *node) {
CCArray * arr = JSCallFunc::getTargetForNativeNode(node);
CCArray * arr = JSCallFuncWrapper::getTargetForNativeNode(node);
if(arr) {
arr->removeAllObjects();
}
arr = JSSchedule::getTargetForNativeNode(node);
arr = JSScheduleWrapper::getTargetForNativeNode(node);
if(arr) {
arr->removeAllObjects();
}
@ -1016,20 +1016,26 @@ CCArray* jsval_to_ccarray(JSContext* cx, jsval v) {
jsval ccarray_to_jsval(JSContext* cx, CCArray *arr) {
JSObject *jsretArr = JS_NewArrayObject(cx, 0, NULL);
for(int i = 0; i < arr->count(); ++i) {
CCObject *obj = arr->objectAtIndex(i);
js_proxy_t *proxy = js_get_or_create_proxy<cocos2d::CCObject>(cx, obj);
jsval arrElement = OBJECT_TO_JSVAL(proxy->obj);
if(!JS_SetElement(cx, jsretArr, i, &arrElement)) {
break;
JSObject *jsretArr = JS_NewArrayObject(cx, 0, NULL);
for(int i = 0; i < arr->count(); ++i) {
jsval arrElement;
CCObject *obj = arr->objectAtIndex(i);
CCString *testString = dynamic_cast<cocos2d::CCString *>(obj);
if(testString) {
arrElement = c_string_to_jsval(cx, testString->getCString());
} else {
js_proxy_t *proxy = js_get_or_create_proxy<cocos2d::CCObject>(cx, obj);
arrElement = OBJECT_TO_JSVAL(proxy->obj);
}
if(!JS_SetElement(cx, jsretArr, i, &arrElement)) {
break;
}
}
}
return OBJECT_TO_JSVAL(jsretArr);
return OBJECT_TO_JSVAL(jsretArr);
}
jsval long_long_to_jsval(JSContext* cx, long long v) {

View File

@ -545,19 +545,19 @@ JSBool js_platform(JSContext *cx, uint32_t argc, jsval *vp)
}
void JSCallFunc::setJSCallbackFunc(jsval func) {
void JSCallbackWrapper::setJSCallbackFunc(jsval func) {
jsCallback = func;
}
void JSCallFunc::setJSCallbackThis(jsval thisObj) {
void JSCallbackWrapper::setJSCallbackThis(jsval thisObj) {
jsThisObj = thisObj;
}
void JSCallFunc::setExtraDataField(jsval data) {
void JSCallbackWrapper::setJSExtraData(jsval data) {
extraData = data;
}
void JSCallFunc::setTargetForNativeNode(CCNode *pNode, JSCallFunc *target) {
void JSCallFuncWrapper::setTargetForNativeNode(CCNode *pNode, JSCallFuncWrapper *target) {
callfuncTarget_proxy_t *t;
HASH_FIND_PTR(_callfuncTarget_native_ht, &pNode, t);
@ -577,7 +577,7 @@ void JSCallFunc::setTargetForNativeNode(CCNode *pNode, JSCallFunc *target) {
HASH_ADD_PTR(_callfuncTarget_native_ht, ptr, p);
}
CCArray * JSCallFunc::getTargetForNativeNode(CCNode *pNode) {
CCArray * JSCallFuncWrapper::getTargetForNativeNode(CCNode *pNode) {
schedTarget_proxy_t *t;
HASH_FIND_PTR(_callfuncTarget_native_ht, &pNode, t);
@ -596,18 +596,18 @@ JSBool js_callFunc(JSContext *cx, uint32_t argc, jsval *vp)
if (argc >= 1) {
jsval *argv = JS_ARGV(cx, vp);
JSCallFunc *tmpCobj = new JSCallFunc();
JSCallFuncWrapper *tmpCobj = new JSCallFuncWrapper();
tmpCobj->autorelease();
tmpCobj->setJSCallbackThis(argv[0]);
if(argc >= 2) {
tmpCobj->setJSCallbackFunc(argv[1]);
} if(argc == 3) {
tmpCobj->setExtraDataField(argv[2]);
tmpCobj->setJSExtraData(argv[2]);
}
CCCallFunc *ret = (CCCallFunc *)CCCallFuncN::create((CCObject *)tmpCobj,
callfuncN_selector(JSCallFunc::callbackFunc));
callfuncN_selector(JSCallFuncWrapper::callbackFunc));
js_proxy_t *proxy = js_get_or_create_proxy<cocos2d::CCCallFunc>(cx, ret);
JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(proxy->obj));
@ -624,7 +624,8 @@ JSBool js_callFunc(JSContext *cx, uint32_t argc, jsval *vp)
}
void JSSchedule::setTargetForSchedule(jsval sched, JSSchedule *target) {
void JSScheduleWrapper::setTargetForSchedule(jsval sched, JSScheduleWrapper *target) {
do {
schedFunc_proxy_t *p = (schedFunc_proxy_t *)malloc(sizeof(schedFunc_proxy_t));
assert(p);
@ -634,7 +635,7 @@ void JSSchedule::setTargetForSchedule(jsval sched, JSSchedule *target) {
} while(0);
}
JSSchedule * JSSchedule::getTargetForSchedule(jsval sched) {
JSScheduleWrapper * JSScheduleWrapper::getTargetForSchedule(jsval sched) {
schedFunc_proxy_t *t;
JSObject *o = JSVAL_TO_OBJECT(sched);
HASH_FIND_PTR(_schedFunc_target_ht, &o, t);
@ -642,7 +643,7 @@ JSSchedule * JSSchedule::getTargetForSchedule(jsval sched) {
}
void JSSchedule::setTargetForNativeNode(CCNode *pNode, JSSchedule *target) {
void JSScheduleWrapper::setTargetForNativeNode(CCNode *pNode, JSScheduleWrapper *target) {
schedTarget_proxy_t *t;
HASH_FIND_PTR(_schedTarget_native_ht, &pNode, t);
@ -662,7 +663,7 @@ void JSSchedule::setTargetForNativeNode(CCNode *pNode, JSSchedule *target) {
HASH_ADD_PTR(_schedTarget_native_ht, ptr, p);
}
CCArray * JSSchedule::getTargetForNativeNode(CCNode *pNode) {
CCArray * JSScheduleWrapper::getTargetForNativeNode(CCNode *pNode) {
schedTarget_proxy_t *t;
HASH_FIND_PTR(_schedTarget_native_ht, &pNode, t);
@ -673,15 +674,6 @@ CCArray * JSSchedule::getTargetForNativeNode(CCNode *pNode) {
}
void JSSchedule::setJSScheduleFunc(jsval func) {
jsSchedule = func;
}
void JSSchedule::setJSScheduleThis(jsval thisObj) {
jsThisObj = thisObj;
}
JSBool js_CCNode_unschedule(JSContext *cx, uint32_t argc, jsval *vp)
{
@ -698,9 +690,9 @@ JSBool js_CCNode_unschedule(JSContext *cx, uint32_t argc, jsval *vp)
CCScheduler *sched = node->getScheduler();
JSSchedule *tmpCobj = JSSchedule::getTargetForSchedule(argv[0]);
JSScheduleWrapper *tmpCobj = JSScheduleWrapper::getTargetForSchedule(argv[0]);
sched->unscheduleSelector(schedule_selector(JSSchedule::scheduleFunc), tmpCobj);
sched->unscheduleSelector(schedule_selector(JSScheduleWrapper::scheduleFunc), tmpCobj);
JS_SET_RVAL(cx, vp, JSVAL_VOID);
}
@ -722,8 +714,8 @@ JSBool js_CCNode_scheduleOnce(JSContext *cx, uint32_t argc, jsval *vp)
CCScheduler *sched = node->getScheduler();
JSSchedule *tmpCobj = new JSSchedule();
JSScheduleWrapper *tmpCobj = new JSScheduleWrapper();
tmpCobj->autorelease();
//
// delay
@ -734,16 +726,16 @@ JSBool js_CCNode_scheduleOnce(JSContext *cx, uint32_t argc, jsval *vp)
return JS_FALSE;
}
tmpCobj->setJSScheduleThis(OBJECT_TO_JSVAL(obj));
tmpCobj->setJSScheduleFunc(argv[0]);
tmpCobj->setJSCallbackThis(OBJECT_TO_JSVAL(obj));
tmpCobj->setJSCallbackFunc(argv[0]);
JSSchedule::setTargetForSchedule(argv[0], tmpCobj);
JSSchedule::setTargetForNativeNode(node, tmpCobj);
JSScheduleWrapper::setTargetForSchedule(argv[0], tmpCobj);
JSScheduleWrapper::setTargetForNativeNode(node, tmpCobj);
if(argc == 1) {
sched->scheduleSelector(schedule_selector(JSSchedule::scheduleFunc), tmpCobj, 0, node->isRunning(), 0, 0);
sched->scheduleSelector(schedule_selector(JSScheduleWrapper::scheduleFunc), tmpCobj, 0, node->isRunning(), 0, 0);
} else {
sched->scheduleSelector(schedule_selector(JSSchedule::scheduleFunc), tmpCobj, interval, node->isRunning(), 0, 0);
sched->scheduleSelector(schedule_selector(JSScheduleWrapper::scheduleFunc), tmpCobj, interval, node->isRunning(), 0, 0);
}
JS_SET_RVAL(cx, vp, JSVAL_VOID);
@ -770,8 +762,9 @@ JSBool js_CCNode_schedule(JSContext *cx, uint32_t argc, jsval *vp)
CCScheduler *sched = node->getScheduler();
js_proxy_t *p = js_get_or_create_proxy<cocos2d::CCScheduler>(cx, sched);
JSSchedule *tmpCobj = new JSSchedule();
JSScheduleWrapper *tmpCobj = new JSScheduleWrapper();
tmpCobj->autorelease();
double interval;
if( argc >= 2 ) {
if( ! JS_ValueToNumber(cx, argv[1], &interval ) )
@ -796,20 +789,20 @@ JSBool js_CCNode_schedule(JSContext *cx, uint32_t argc, jsval *vp)
return JS_FALSE;
}
tmpCobj->setJSScheduleThis(OBJECT_TO_JSVAL(obj));
tmpCobj->setJSScheduleFunc(argv[0]);
tmpCobj->setJSCallbackThis(OBJECT_TO_JSVAL(obj));
tmpCobj->setJSCallbackFunc(argv[0]);
JSSchedule::setTargetForSchedule(argv[0], tmpCobj);
JSSchedule::setTargetForNativeNode(node, tmpCobj);
JSScheduleWrapper::setTargetForSchedule(argv[0], tmpCobj);
JSScheduleWrapper::setTargetForNativeNode(node, tmpCobj);
if(argc == 1) {
sched->scheduleSelector(schedule_selector(JSSchedule::scheduleFunc), tmpCobj, 0, node->isRunning());
sched->scheduleSelector(schedule_selector(JSScheduleWrapper::scheduleFunc), tmpCobj, 0, node->isRunning());
} if(argc == 2) {
sched->scheduleSelector(schedule_selector(JSSchedule::scheduleFunc), tmpCobj, interval, node->isRunning());
sched->scheduleSelector(schedule_selector(JSScheduleWrapper::scheduleFunc), tmpCobj, interval, node->isRunning());
} if(argc == 3) {
sched->scheduleSelector(schedule_selector(JSSchedule::scheduleFunc), tmpCobj, 0, node->isRunning(), repeat, 0);
sched->scheduleSelector(schedule_selector(JSScheduleWrapper::scheduleFunc), tmpCobj, 0, node->isRunning(), repeat, 0);
} if (argc == 4) {
sched->scheduleSelector(schedule_selector(JSSchedule::scheduleFunc), tmpCobj, 0, node->isRunning(), repeat, delay);
sched->scheduleSelector(schedule_selector(JSScheduleWrapper::scheduleFunc), tmpCobj, 0, node->isRunning(), repeat, delay);
}
@ -1143,6 +1136,27 @@ JSBool js_cocos2dx_ccpAdd(JSContext *cx, uint32_t argc, jsval *vp)
return JS_FALSE;
}
JSBool js_cocos2dx_ccpDistance(JSContext *cx, uint32_t argc, jsval *vp)
{
jsval *argv = JS_ARGV(cx, vp);
if (argc == 2) {
cocos2d::CCPoint arg0;
arg0 = jsval_to_ccpoint(cx, argv[0]);
cocos2d::CCPoint arg1;
arg1 = jsval_to_ccpoint(cx, argv[1]);
float ret = ccpDistance(arg0, arg1);
jsval jsret = DOUBLE_TO_JSVAL(ret);
JS_SET_RVAL(cx, vp, jsret);
return JS_TRUE;
}
JS_ReportError(cx, "wrong number of arguments: %d, was expecting %d", argc, 1);
return JS_FALSE;
}
JSBool js_cocos2dx_ccpClamp(JSContext *cx, uint32_t argc, jsval *vp)
{
jsval *argv = JS_ARGV(cx, vp);
@ -1596,6 +1610,7 @@ void register_cocos2dx_js_extensions(JSContext* cx, JSObject* global)
JS_DefineFunction(cx, tmpObj, "garbageCollect", js_forceGC, 1, JSPROP_READONLY | JSPROP_PERMANENT);
JS_DefineFunction(cx, ns, "pAdd", js_cocos2dx_ccpAdd, 1, JSPROP_READONLY | JSPROP_PERMANENT);
JS_DefineFunction(cx, ns, "pDistance", js_cocos2dx_ccpDistance, 1, JSPROP_READONLY | JSPROP_PERMANENT);
JS_DefineFunction(cx, ns, "pSub", js_cocos2dx_ccpSub, 0, JSPROP_READONLY | JSPROP_PERMANENT);
JS_DefineFunction(cx, ns, "pNeg", js_cocos2dx_ccpNeg, 0, JSPROP_READONLY | JSPROP_PERMANENT);
JS_DefineFunction(cx, ns, "pMult", js_cocos2dx_ccpMult, 0, JSPROP_READONLY | JSPROP_PERMANENT);

View File

@ -4,11 +4,11 @@
#include "jsapi.h"
#include "ScriptingCore.h"
class JSSchedule;
class JSScheduleWrapper;
typedef struct jsScheduleFunc_proxy {
void * ptr;
JSSchedule *obj;
JSScheduleWrapper *obj;
UT_hash_handle hh;
} schedFunc_proxy_t;
@ -79,19 +79,48 @@ inline js_proxy_t *js_get_or_create_proxy(JSContext *cx, T *native_obj) {
jsval anonEvaluate(JSContext *cx, JSObject *thisObj, const char* string);
void register_cocos2dx_js_extensions(JSContext* cx, JSObject* obj);
class JSCallFunc: public CCObject {
class JSCallbackWrapper: public CCObject {
public:
JSCallFunc(jsval func): jsCallback(func) {}
JSCallFunc() {extraData = JSVAL_VOID;}
virtual ~JSCallFunc() {
return;
}
JSCallbackWrapper() : jsCallback(JSVAL_VOID), jsThisObj(JSVAL_VOID), extraData(JSVAL_VOID) {}
virtual ~JSCallbackWrapper(void) {}
void setJSCallbackFunc(jsval obj);
void setJSCallbackThis(jsval thisObj);
void setExtraDataField(jsval data);
static void dumpNamedRoot(const char *name, void *addr, JSGCRootType type, void *data);
static void setTargetForNativeNode(CCNode *pNode, JSCallFunc *target);
void setJSExtraData(jsval data);
protected:
jsval jsCallback;
jsval jsThisObj;
jsval extraData;
};
class JSCCBAnimationWrapper: public JSCallbackWrapper {
public:
JSCCBAnimationWrapper() {}
virtual ~JSCCBAnimationWrapper() {}
void animationCompleteCallback() const {
JSContext *cx = ScriptingCore::getInstance()->getGlobalContext();
jsval retval = JSVAL_NULL;
if(!JSVAL_IS_VOID(jsCallback) && !JSVAL_IS_VOID(jsThisObj)) {
JS_CallFunctionValue(cx, JSVAL_TO_OBJECT(jsThisObj), jsCallback, 0, NULL, &retval);
}
}
};
class JSCallFuncWrapper: public JSCallbackWrapper {
public:
JSCallFuncWrapper() {}
virtual ~JSCallFuncWrapper(void) {
return;
}
static void setTargetForNativeNode(CCNode *pNode, JSCallFuncWrapper *target);
static CCArray * getTargetForNativeNode(CCNode *pNode);
void callbackFunc(CCNode *node) const {
@ -115,35 +144,28 @@ public:
JS_CallFunctionValue(cx, JSVAL_TO_OBJECT(jsThisObj), jsCallback, 2, valArr, &retval);
}
JSCallFunc::setTargetForNativeNode(node, (JSCallFunc *)this);
JSCallFuncWrapper::setTargetForNativeNode(node, (JSCallFuncWrapper *)this);
JS_RemoveValueRoot(cx, valArr);
}
private:
jsval jsCallback;
jsval jsThisObj;
jsval extraData;
};
class JSSchedule: public CCObject {
class JSScheduleWrapper: public JSCallbackWrapper {
public:
JSSchedule(jsval func): jsSchedule(func) {}
JSSchedule() {jsSchedule = JSVAL_VOID; jsThisObj = JSVAL_VOID;}
virtual ~JSSchedule() {
JSScheduleWrapper() {}
virtual ~JSScheduleWrapper() {
return;
}
static void setTargetForSchedule(jsval sched, JSSchedule *target);
static JSSchedule * getTargetForSchedule(jsval sched);
static void setTargetForNativeNode(CCNode *pNode, JSSchedule *target);
static void setTargetForSchedule(jsval sched, JSScheduleWrapper *target);
static JSScheduleWrapper * getTargetForSchedule(jsval sched);
static void setTargetForNativeNode(CCNode *pNode, JSScheduleWrapper *target);
static CCArray * getTargetForNativeNode(CCNode *pNode);
void setJSScheduleFunc(jsval obj);
void setJSScheduleThis(jsval thisObj);
void pause();
void scheduleFunc(float dt) const {
@ -156,20 +178,13 @@ public:
return;
}
if(!JSVAL_IS_VOID(jsSchedule) && !JSVAL_IS_VOID(jsThisObj)) {
ScriptingCore::dumpRoot(cx, 0, NULL);
JS_CallFunctionValue(cx, JSVAL_TO_OBJECT(jsThisObj), jsSchedule, 1, &data, &retval);
if(!JSVAL_IS_VOID(jsCallback) && !JSVAL_IS_VOID(jsThisObj)) {
JS_CallFunctionValue(cx, JSVAL_TO_OBJECT(jsThisObj), jsCallback, 1, &data, &retval);
}
JS_RemoveValueRoot(cx, &data);
}
private:
jsval jsSchedule;
jsval jsThisObj;
};