diff --git a/CHANGELOG b/CHANGELOG index 3903f0262e..0272832222 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -5,13 +5,14 @@ coocs2d-x-3.14 Dec 19 2016 [NEW] Action: new actions: ResizeBy and ResizeTo [NEW] Button: can set title label [NEW] Can disable multi touch on Android +[NEW] EventDispatcher: Add hasEventListener to check listener existance [NEW] EditBox: add horizontal text alignment [NEW] Sprite: support scale9 feature [NEW] Slider: add methods to get _slidBallNormalRenderer [NEW] Desktop: add a method to toggle between fullscreen and windowed [NEW] Desktop: add events for window resize, focus and unfocus [NEW] Mac: supports game controller -[NEW] JSB: add perfromance.now() +[NEW] JSB: add cc.sys.now() and perfromance.now(), the last one is more accurate [NEW] Lua: add cc.vec3 functions: add, sub and dot [NEW] Lua: use luajit 2.1.0-beta2 @@ -25,6 +26,18 @@ coocs2d-x-3.14 Dec 19 2016 [REFINE] Mac: system font enhancement [REFINE] Linux: build shared lib with -fPIC [REFINE] Android: use SharedPreferences.apply() to store data +[REFINE] JSB: Increase default JS heap to 32 mb +[REFINE] JSB: Support more system languages +[REFINE] JSB: Direct log/error for better understantding problems +[REFINE] JSB: Separate FinalizeHook for ref objects and non ref objects +[REFINE] Web: Improve overall node construction performance +[REFINE] Web: Improve overall loading process performance +[REFINE] Web: Reduce overall memory usage +[REFINE] Web: Made cc.LabelBMFont and cc.LabelAtlas support texture packing and auto batching +[REFINE] Web: Reimplement a much faster ccui.Scale9Sprite +[REFINE] Web: Reimplement a much faster cc.DrawNode WebGL renderer +[REFINE] Web: Use stack to avoid recursive call in transform, onEnter, onExit etc, reduce call stack depth + [FIX] AsstsManagerEx: project.manifest may be downloaded twice [FIX] AudioEngine: can not play large ogg file @@ -74,11 +87,25 @@ coocs2d-x-3.14 Dec 19 2016 [FIX] Linux: Application::openURL can not work [FIX] Desktop: crash upon exit when NotificationNode exists [FIX] Spine: color bug +[FIX] Console: doesn't support `--ap` parameter [FIX] Lua: result of radian2angle is wrong [FIX] Lua: iskindof_ doesn't work correctly [FIX] Lua: new lua project crashes compiling with VS2015 release mode [FIX] JSB: `jsb.addRoot is not a function` error caused by cc.GLProgramState.setUniformCallback -[FIX] Console: doesn't support `--ap` parameter +[FIX] JSB: Fix spine TrackEntry conversion crash issue +[FIX] JSB: Fix CallbackWrapper and FunctionWrapper crash during deallocation in new memory model +[FIX] JSB: Fix event object memory issue by manually bind EventDispatcher::addCustomEventListener +[FIX] JSB: Fix chipmunk crash issues when using setDefaultCollisionHandler +[FIX] JSB: Fix compilation issues when COCOS_DEBUG = 2 +[FIX] JSB: Unify function name of Texture2D::releaseTexture +[FIX] Web: Fix spine blend function inconsistency between web and jsb +[FIX] Web: Fix particle system load from plist generated by x-studio365 +[FIX] Web: Fix doEnumerateRecursive(node, name, callback) always return undefined issue +[FIX] Web: Change bright style on 'setEnabled' call of ccui.Widget +[FIX] Web: Fix Editbox can't input in full screen mode +[FIX] Web: Fix texture issue on some Android devices by always set vertexAttribPointer +[FIX] Web: Made xhr ontimeout callback work on all browsers +[FIX] Web: Fix clear color not normalized issue cocos2d-x-3.13.1 Sep 13 2016 diff --git a/cocos/platform/CCGLView.cpp b/cocos/platform/CCGLView.cpp index 199f1a306b..421e88de5b 100644 --- a/cocos/platform/CCGLView.cpp +++ b/cocos/platform/CCGLView.cpp @@ -365,7 +365,7 @@ void GLView::handleTouchesMove(int num, intptr_t ids[], float xs[], float ys[], continue; } - CCLOGINFO("Moving touches with id: %d, x=%f, y=%f, force=%f, maxFource=%f", id, x, y, force, maxForce); + CCLOGINFO("Moving touches with id: %d, x=%f, y=%f, force=%f, maxFource=%f", (int)id, x, y, force, maxForce); Touch* touch = g_touches[iter->second]; if (touch) { @@ -417,7 +417,7 @@ void GLView::handleTouchesOfEndOrCancel(EventTouch::EventCode eventCode, int num Touch* touch = g_touches[iter->second]; if (touch) { - CCLOGINFO("Ending touches with id: %d, x=%f, y=%f", id, x, y); + CCLOGINFO("Ending touches with id: %d, x=%f, y=%f", (int)id, x, y); touch->setTouchInfo(iter->second, (x - _viewPortRect.origin.x) / _scaleX, (y - _viewPortRect.origin.y) / _scaleY); diff --git a/cocos/scripting/js-bindings/manual/ScriptingCore.cpp b/cocos/scripting/js-bindings/manual/ScriptingCore.cpp index 1b647f75d1..f8c7a48cff 100644 --- a/cocos/scripting/js-bindings/manual/ScriptingCore.cpp +++ b/cocos/scripting/js-bindings/manual/ScriptingCore.cpp @@ -631,14 +631,14 @@ void ScriptingCore::createGlobalContext() { // Removed from Spidermonkey 19. //JS_SetCStringsAreUTF8(); - _rt = JS_NewRuntime(8L * 1024L * 1024L); + _rt = JS_NewRuntime(32L * 1024L * 1024L); JS_SetGCParameter(_rt, JSGC_MAX_BYTES, 0xffffffff); JS_SetTrustedPrincipals(_rt, &shellTrustedPrincipals); JS_SetSecurityCallbacks(_rt, &securityCallbacks); JS_SetNativeStackQuota(_rt, JSB_MAX_STACK_QUOTA); - _cx = JS_NewContext(_rt, 8192); + _cx = JS_NewContext(_rt, 32 * 1024); // Removed in Firefox v27 // JS_SetOptions(this->_cx, JSOPTION_TYPE_INFERENCE); @@ -1438,7 +1438,7 @@ bool ScriptingCore::handleTouchesEvent(void* nativeObj, cocos2d::EventTouch::Eve for (const auto& touch : touches) { - JS::RootedValue jsret(_cx, OBJECT_TO_JSVAL(jsb_get_or_create_weak_jsobject(_cx, touch, typeClassTouch, "cocos2d::Touch"))); + JS::RootedValue jsret(_cx, OBJECT_TO_JSVAL(jsb_get_or_create_weak_jsobject(_cx, touch, typeClassTouch))); if (!JS_SetElement(_cx, jsretArr, count, jsret)) { break; @@ -1451,7 +1451,7 @@ bool ScriptingCore::handleTouchesEvent(void* nativeObj, cocos2d::EventTouch::Eve { jsval dataVal[2]; dataVal[0] = OBJECT_TO_JSVAL(jsretArr); - dataVal[1] = OBJECT_TO_JSVAL(jsb_get_or_create_weak_jsobject(_cx, event, typeClassEvent, "cocos2d::EventTouch")); + dataVal[1] = OBJECT_TO_JSVAL(jsb_get_or_create_weak_jsobject(_cx, event, typeClassEvent)); ret = executeFunctionWithOwner(OBJECT_TO_JSVAL(p->obj), funcName.c_str(), 2, dataVal, jsvalRet); } @@ -1459,7 +1459,6 @@ bool ScriptingCore::handleTouchesEvent(void* nativeObj, cocos2d::EventTouch::Eve { removeJSObject(_cx, touch); } - removeJSObject(_cx, event); return ret; @@ -1485,8 +1484,8 @@ bool ScriptingCore::handleTouchEvent(void* nativeObj, cocos2d::EventTouch::Event js_type_class_t *typeClassEvent = js_get_type_from_native((cocos2d::EventTouch*)event); jsval dataVal[2]; - dataVal[0] = OBJECT_TO_JSVAL(jsb_get_or_create_weak_jsobject(_cx, touch, typeClassTouch, "cocos2d::Touch")); - dataVal[1] = OBJECT_TO_JSVAL(jsb_get_or_create_weak_jsobject(_cx, event, typeClassEvent, "cocos2d::EventTouch")); + dataVal[0] = OBJECT_TO_JSVAL(jsb_get_or_create_weak_jsobject(_cx, touch, typeClassTouch)); + dataVal[1] = OBJECT_TO_JSVAL(jsb_get_or_create_weak_jsobject(_cx, event, typeClassEvent)); ret = executeFunctionWithOwner(OBJECT_TO_JSVAL(p->obj), funcName.c_str(), 2, dataVal, jsvalRet); } @@ -1514,7 +1513,7 @@ bool ScriptingCore::handleMouseEvent(void* nativeObj, cocos2d::EventMouse::Mouse if (p) { js_type_class_t *typeClass = js_get_type_from_native((cocos2d::EventMouse*)event); - jsval dataVal = OBJECT_TO_JSVAL(jsb_get_or_create_weak_jsobject(_cx, event, typeClass, "cocos2d::EventMouse")); + jsval dataVal = OBJECT_TO_JSVAL(jsb_get_or_create_weak_jsobject(_cx, event, typeClass)); ret = executeFunctionWithOwner(OBJECT_TO_JSVAL(p->obj), funcName.c_str(), 1, &dataVal, jsvalRet); removeJSObject(_cx, event); @@ -1611,7 +1610,7 @@ bool ScriptingCore::handleKeyboardEvent(void* nativeObj, cocos2d::EventKeyboard: js_type_class_t *typeClass = js_get_type_from_native((cocos2d::EventKeyboard*)event); jsval args[2] = { int32_to_jsval(_cx, (int32_t)keyCode), - OBJECT_TO_JSVAL(jsb_get_or_create_weak_jsobject(_cx, event, typeClass, "cocos2d::EventKeyboard")) + OBJECT_TO_JSVAL(jsb_get_or_create_weak_jsobject(_cx, event, typeClass)) }; if (isPressed) @@ -1662,7 +1661,7 @@ int ScriptingCore::executeCustomTouchesEvent(EventTouch::EventCode eventType, { js_type_class_t *typeClass = js_get_type_from_native(touch); - jsval jsret = OBJECT_TO_JSVAL(jsb_get_or_create_weak_jsobject(this->_cx, touch, typeClass, "cocos2d::Touch")); + jsval jsret = OBJECT_TO_JSVAL(jsb_get_or_create_weak_jsobject(this->_cx, touch, typeClass)); JS::RootedValue jsval(_cx, jsret); if (!JS_SetElement(this->_cx, jsretArr, count, jsval)) { break; @@ -1690,7 +1689,7 @@ int ScriptingCore::executeCustomTouchEvent(EventTouch::EventCode eventType, Touc std::string funcName = getTouchFuncName(eventType); js_type_class_t *typeClass = js_get_type_from_native(touch); - jsval jsTouch = OBJECT_TO_JSVAL(jsb_get_or_create_weak_jsobject(this->_cx, touch, typeClass, "cocos2d::Touch")); + jsval jsTouch = OBJECT_TO_JSVAL(jsb_get_or_create_weak_jsobject(this->_cx, touch, typeClass)); executeFunctionWithOwner(OBJECT_TO_JSVAL(obj), funcName.c_str(), 1, &jsTouch, &retval); @@ -1709,7 +1708,7 @@ int ScriptingCore::executeCustomTouchEvent(EventTouch::EventCode eventType, std::string funcName = getTouchFuncName(eventType); js_type_class_t *typeClass = js_get_type_from_native(touch); - jsval jsTouch = OBJECT_TO_JSVAL(jsb_get_or_create_weak_jsobject(this->_cx, touch, typeClass, "cocos2d::Touch")); + jsval jsTouch = OBJECT_TO_JSVAL(jsb_get_or_create_weak_jsobject(this->_cx, touch, typeClass)); executeFunctionWithOwner(OBJECT_TO_JSVAL(obj), funcName.c_str(), 1, &jsTouch, retval); @@ -2308,12 +2307,16 @@ JSObject* jsb_create_weak_jsobject(JSContext *cx, void *native, js_type_class_t JS::RootedObject parent(cx, typeClass->parentProto.ref()); JS::RootedObject jsObj(cx, JS_NewObject(cx, typeClass->jsclass, proto, parent)); auto proxy = jsb_new_proxy(native, jsObj); + js_add_FinalizeHook(cx, jsObj, false); #if ! CC_ENABLE_GC_FOR_NATIVE_OBJECTS JS::AddNamedObjectRoot(cx, &proxy->obj, debug); #else #if COCOS2D_DEBUG > 1 - CCLOG("++++++WEAK_REF++++++ Cpp(%s): %p - JS: %p", debug, native, jsObj.get()); + if (debug != nullptr) + { + CCLOG("++++++WEAK_REF++++++ Cpp(%s): %p - JS: %p", debug, native, jsObj.get()); + } #endif // COCOS2D_DEBUG #endif // CC_ENABLE_GC_FOR_NATIVE_OBJECTS return jsObj; @@ -2336,7 +2339,7 @@ JSObject* jsb_ref_get_or_create_jsobject(JSContext *cx, cocos2d::Ref *ref, js_ty js_proxy_t* newproxy = jsb_new_proxy(ref, jsObj); #if CC_ENABLE_GC_FOR_NATIVE_OBJECTS ref->retain(); - js_add_FinalizeHook(cx, jsObj); + js_add_FinalizeHook(cx, jsObj, true); #if COCOS2D_DEBUG > 1 CCLOG("++++++RETAINED++++++ Cpp(%s): %p - JS: %p", debug, ref, jsObj.get()); #endif // COCOS2D_DEBUG @@ -2398,7 +2401,7 @@ void jsb_ref_init(JSContext* cx, JS::Heap *obj, Ref* ref, const char* #if CC_ENABLE_GC_FOR_NATIVE_OBJECTS (void)ref; JS::RootedObject jsObj(cx, *obj); - js_add_FinalizeHook(cx, jsObj); + js_add_FinalizeHook(cx, jsObj, true); // don't retain it, already retained #if COCOS2D_DEBUG > 1 CCLOG("++++++RETAINED++++++ Cpp(%s): %p - JS: %p", debug, ref, jsObj.get()); @@ -2418,7 +2421,7 @@ void jsb_ref_autoreleased_init(JSContext* cx, JS::Heap *obj, Ref* ref (void)obj; ref->retain(); JS::RootedObject jsObj(cx, *obj); - js_add_FinalizeHook(cx, jsObj); + js_add_FinalizeHook(cx, jsObj, true); #else // don't autorelease it, since it is already autoreleased JS::AddNamedObjectRoot(cx, obj, debug); @@ -2440,7 +2443,9 @@ void jsb_ref_rebind(JSContext* cx, JS::HandleObject jsobj, js_proxy_t *proxy, co // Rebind js obj with new action js_proxy_t* newProxy = jsb_new_proxy(newRef, jsobj); -#if !CC_ENABLE_GC_FOR_NATIVE_OBJECTS +#if CC_ENABLE_GC_FOR_NATIVE_OBJECTS + CC_UNUSED_PARAM(newProxy); +#else JS::AddNamedObjectRoot(cx, &newProxy->obj, debug); #endif } diff --git a/cocos/scripting/js-bindings/manual/ScriptingCore.h b/cocos/scripting/js-bindings/manual/ScriptingCore.h index 4c933e686a..e67fc6f7e9 100644 --- a/cocos/scripting/js-bindings/manual/ScriptingCore.h +++ b/cocos/scripting/js-bindings/manual/ScriptingCore.h @@ -41,7 +41,7 @@ #include #include -#define ENGINE_VERSION "Cocos2d-JS v3.13" +#define ENGINE_VERSION "Cocos2d-JS v3.14" void js_log(const char *format, ...); @@ -665,7 +665,7 @@ JSObject* jsb_ref_get_or_create_jsobject(JSContext *cx, cocos2d::Ref *ref, js_ty * If it can't find it, it will create a new one associating it to Ref * Call this function for objects that might return an already existing copy when you create them. For example, `Animation3D::create()`; */ -JSObject* jsb_ref_autoreleased_get_or_create_jsobject(JSContext *cx, cocos2d::Ref *ref, js_type_class_t *typeClass, const char* debug); +JSObject* jsb_ref_autoreleased_get_or_create_jsobject(JSContext *cx, cocos2d::Ref *ref, js_type_class_t *typeClass, const char* debug=nullptr); /** * It will try to get the associated JSObjct for the native object. @@ -673,7 +673,7 @@ JSObject* jsb_ref_autoreleased_get_or_create_jsobject(JSContext *cx, cocos2d::Re * The reference created from JSObject to native object is weak because it won't retain it. * The behavior is exactly the same with 'jsb_ref_get_or_create_jsobject' when CC_ENABLE_GC_FOR_NATIVE_OBJECTS deactivated. */ -CC_JS_DLL JSObject* jsb_get_or_create_weak_jsobject(JSContext *cx, void *native, js_type_class_t *typeClass, const char* debug); +CC_JS_DLL JSObject* jsb_get_or_create_weak_jsobject(JSContext *cx, void *native, js_type_class_t *typeClass, const char* debug=nullptr); /** * Register finalize hook and its owner as an entry in _js_hook_owner_map, diff --git a/cocos/scripting/js-bindings/manual/chipmunk/js_bindings_chipmunk_manual.cpp b/cocos/scripting/js-bindings/manual/chipmunk/js_bindings_chipmunk_manual.cpp index 791de2c25f..a048125b8d 100644 --- a/cocos/scripting/js-bindings/manual/chipmunk/js_bindings_chipmunk_manual.cpp +++ b/cocos/scripting/js-bindings/manual/chipmunk/js_bindings_chipmunk_manual.cpp @@ -824,6 +824,7 @@ jsval cpSegmentQueryInfo_to_jsval(JSContext *cx, cpSegmentQueryInfo segmentQuery return OBJECT_TO_JSVAL(object); } + #pragma mark - Collision Handler struct collision_handler { @@ -845,39 +846,72 @@ struct collision_handler { unsigned int is_oo; // Objected oriented API ? UT_hash_handle hh; + + bool is_default; - collision_handler() + collision_handler () { begin = nullptr; pre = nullptr; post = nullptr; separate = nullptr; jsthis = nullptr; + is_default = false; + } + + ~collision_handler () + { + JS::RootedValue jsspace(cx, OBJECT_TO_JSVAL(jsthis)); + if (!is_default && jsspace.isObject()) + { + JS::RootedValue callback(cx); + callback.set(OBJECT_TO_JSVAL(begin)); + if (callback.isObject()) + { + js_remove_object_reference(jsspace, callback); + } + callback.set(OBJECT_TO_JSVAL(pre)); + if (callback.isObject()) + { + js_remove_object_reference(jsspace, callback); + } + callback.set(OBJECT_TO_JSVAL(post)); + if (callback.isObject()) + { + js_remove_object_reference(jsspace, callback); + } + callback.set(OBJECT_TO_JSVAL(separate)); + if (callback.isObject()) + { + js_remove_object_reference(jsspace, callback); + } + } } + // Space must be set after set handles void setJSSpace(JS::HandleValue jsspace) { - if (!jsspace.isNullOrUndefined()) + if (jsspace.isObject()) { jsthis = jsspace.toObjectOrNull(); - JS::RootedValue callback(ScriptingCore::getInstance()->getGlobalContext()); + JS::RootedValue callback(cx); callback.set(OBJECT_TO_JSVAL(begin)); - if (!callback.isNullOrUndefined()) + if (callback.isObject()) { js_add_object_reference(jsspace, callback); } callback.set(OBJECT_TO_JSVAL(pre)); - if (!callback.isNullOrUndefined()) + if (callback.isObject()) { js_add_object_reference(jsspace, callback); } callback.set(OBJECT_TO_JSVAL(post)); - if (!callback.isNullOrUndefined()) + if (callback.isObject()) { js_add_object_reference(jsspace, callback); } callback.set(OBJECT_TO_JSVAL(separate)); - if (!callback.isNullOrUndefined()) + if (callback.isObject()) { js_add_object_reference(jsspace, callback); } @@ -900,7 +934,12 @@ static unsigned long pair_ints( unsigned long A, unsigned long B ) static cpBool myCollisionBegin(cpArbiter *arb, cpSpace *space, void *data) { + if (data == nullptr) { + return cpTrue; + } struct collision_handler *handler = (struct collision_handler*) data; + + JSB_AUTOCOMPARTMENT_WITH_GLOBAL_OBJCET jsval args[2]; if( handler->is_oo ) { @@ -913,8 +952,6 @@ static cpBool myCollisionBegin(cpArbiter *arb, cpSpace *space, void *data) args[1] = opaque_to_jsval(handler->cx, space ); } - JSB_AUTOCOMPARTMENT_WITH_GLOBAL_OBJCET - JS::RootedValue rval(handler->cx); JS::RootedObject jsthis(handler->cx, handler->jsthis); JS::RootedValue jsbegin(handler->cx, OBJECT_TO_JSVAL(handler->begin)); @@ -930,7 +967,12 @@ static cpBool myCollisionBegin(cpArbiter *arb, cpSpace *space, void *data) static cpBool myCollisionPre(cpArbiter *arb, cpSpace *space, void *data) { + if (data == nullptr) { + return cpTrue; + } struct collision_handler *handler = (struct collision_handler*) data; + + JSB_AUTOCOMPARTMENT_WITH_GLOBAL_OBJCET jsval args[2]; if( handler->is_oo ) { @@ -943,8 +985,6 @@ static cpBool myCollisionPre(cpArbiter *arb, cpSpace *space, void *data) args[1] = opaque_to_jsval( handler->cx, space ); } - JSB_AUTOCOMPARTMENT_WITH_GLOBAL_OBJCET - JS::RootedValue rval(handler->cx); JS::RootedObject jsthis(handler->cx, handler->jsthis); JS::RootedValue jspre(handler->cx, OBJECT_TO_JSVAL(handler->pre)); @@ -960,7 +1000,12 @@ static cpBool myCollisionPre(cpArbiter *arb, cpSpace *space, void *data) static void myCollisionPost(cpArbiter *arb, cpSpace *space, void *data) { + if (data == nullptr) { + return; + } struct collision_handler *handler = (struct collision_handler*) data; + + JSB_AUTOCOMPARTMENT_WITH_GLOBAL_OBJCET jsval args[2]; @@ -974,8 +1019,6 @@ static void myCollisionPost(cpArbiter *arb, cpSpace *space, void *data) args[1] = opaque_to_jsval( handler->cx, space ); } - JSB_AUTOCOMPARTMENT_WITH_GLOBAL_OBJCET - JS::RootedValue ignore(handler->cx); JS::RootedObject jsthis(handler->cx, handler->jsthis); JS::RootedValue jspost(handler->cx, OBJECT_TO_JSVAL(handler->post)); @@ -986,27 +1029,35 @@ static void myCollisionPost(cpArbiter *arb, cpSpace *space, void *data) static void myCollisionSeparate(cpArbiter *arb, cpSpace *space, void *data) { struct collision_handler *handler = (struct collision_handler*) data; - if(! handler->cx || !handler->space) + if (handler == nullptr || !handler->cx || !handler->space) return; - + + JSB_AUTOCOMPARTMENT_WITH_GLOBAL_OBJCET + + JS::RootedValue jssep(handler->cx, OBJECT_TO_JSVAL(handler->separate)); + if (!jssep.isObject()) + { + return; + } + jsval args[2]; - if( handler->is_oo ) { + if (handler->is_oo) + { JS::RootedObject arbiterProto(handler->cx, JSB_cpArbiter_object); JS::RootedObject spaceProto(handler->cx, JSB_cpSpace_object); args[0] = c_class_to_jsval(handler->cx, arb, arbiterProto, JSB_cpArbiter_class, "cpArbiter"); args[1] = c_class_to_jsval(handler->cx, space, spaceProto, JSB_cpSpace_class, "cpArbiter"); - } else { + } else + { args[0] = opaque_to_jsval( handler->cx, arb); args[1] = opaque_to_jsval( handler->cx, space ); } - JSB_AUTOCOMPARTMENT_WITH_GLOBAL_OBJCET - JS::RootedValue ignore(handler->cx); JS::RootedObject jsthis(handler->cx, handler->jsthis); - JS::RootedValue jssep(handler->cx, OBJECT_TO_JSVAL(handler->separate)); bool ok = JS_CallFunctionValue( handler->cx, jsthis, jssep, JS::HandleValueArray::fromMarkedLocation(2, args), &ignore); - JSB_PRECONDITION2(ok, handler->cx, , "Error calling collision callback: Separate");} + JSB_PRECONDITION2(ok, handler->cx, , "Error calling collision callback: Separate"); +} #pragma mark - cpSpace @@ -1015,22 +1066,33 @@ static void myCollisionSeparate(cpArbiter *arb, cpSpace *space, void *data) void JSB_cpSpace_finalize(JSFreeOp *fop, JSObject *jsthis) { struct jsb_c_proxy_s *proxy = jsb_get_c_proxy_for_jsobject(jsthis); - if ( proxy ) { + if ( proxy ) + { CCLOGINFO("jsbindings: finalizing JS object %p (cpSpace), handle: %p", jsthis, proxy->handle); // space cpSpace *space = (cpSpace*) proxy->handle; - // Remove collision handlers, since the user might have forgotten to manually remove them struct collision_handler *current = nullptr, *tmp = nullptr; - HASH_ITER(hh, collision_handler_hash, current, tmp) { - if( current->space == space ) { + HASH_ITER(hh, collision_handler_hash, current, tmp) + { + if( current->space == space ) + { + if (current->is_default) + { + cpCollisionHandler* defaultHandler = cpSpaceAddDefaultCollisionHandler(space); + defaultHandler->userData = nullptr; + defaultHandler->beginFunc = cpCollisionHandlerDoNothing.beginFunc; + defaultHandler->preSolveFunc = cpCollisionHandlerDoNothing.preSolveFunc; + defaultHandler->postSolveFunc = cpCollisionHandlerDoNothing.postSolveFunc; + defaultHandler->separateFunc = cpCollisionHandlerDoNothing.separateFunc; + } HASH_DEL(collision_handler_hash,current); /* delete; users advances to next */ delete current; /* optional- if you want to free */ } } - + // Free Space Children freeSpaceChildren(space); @@ -1064,13 +1126,13 @@ bool __jsb_cpSpace_addCollisionHandler(JSContext *cx, jsval *vp, jsval *argvp, J ok &= jsval_to_int(cx, jstypeA, (int32_t*) &handler->typeA ); ok &= jsval_to_int(cx, jstypeB, (int32_t*) &handler->typeB ); - handler->begin = argvp->toObjectOrNull(); + handler->begin = argvp->isObject() ? argvp->toObjectOrNull() : nullptr; argvp++; - handler->pre = argvp->toObjectOrNull(); + handler->pre = argvp->isObject() ? argvp->toObjectOrNull() : nullptr; argvp++; - handler->post = argvp->toObjectOrNull(); + handler->post = argvp->isObject() ? argvp->toObjectOrNull() : nullptr; argvp++; - handler->separate = argvp->toObjectOrNull(); + handler->separate = argvp->isObject() ? argvp->toObjectOrNull() : nullptr; argvp++; JS::RootedValue spaceVal(cx, OBJECT_TO_JSVAL(jsspace)); @@ -1154,25 +1216,27 @@ bool JSB_cpSpace_setDefaultCollisionHandler(JSContext *cx, uint32_t argc, jsval handler->typeA = 0; handler->typeB = 0; - handler->begin = args.get(0).toObjectOrNull(); - handler->pre = args.get(1).toObjectOrNull(); - handler->post = args.get(2).toObjectOrNull(); - handler->separate = args.get(3).toObjectOrNull(); + handler->begin = args.get(0).isObject() ? args.get(0).toObjectOrNull() : nullptr; + handler->pre = args.get(1).isObject() ? args.get(1).toObjectOrNull() : nullptr; + handler->post = args.get(2).isObject() ? args.get(2).toObjectOrNull() : nullptr; + handler->separate = args.get(3).isObject() ? args.get(3).toObjectOrNull() : nullptr; JS::RootedValue spaceVal(cx, OBJECT_TO_JSVAL(jsthis)); + // Space must be set after set handles handler->setJSSpace(spaceVal); - // Object Oriented API ? handler->is_oo = 1; + // Default handler shouldn't be removed + handler->is_default = true; // owner of the collision handler handler->space = space; handler->cx = cx; cpCollisionHandler* defaultHandler = cpSpaceAddDefaultCollisionHandler(space); - defaultHandler->beginFunc = !handler->begin ? NULL : &myCollisionBegin; - defaultHandler->preSolveFunc = !handler->pre ? NULL : &myCollisionPre; - defaultHandler->postSolveFunc = !handler->post ? NULL : &myCollisionPost; - defaultHandler->separateFunc = !handler->separate ? NULL : &myCollisionSeparate; + defaultHandler->beginFunc = !handler->begin ? cpCollisionHandlerDoNothing.beginFunc : &myCollisionBegin; + defaultHandler->preSolveFunc = !handler->pre ? cpCollisionHandlerDoNothing.preSolveFunc : &myCollisionPre; + defaultHandler->postSolveFunc = !handler->post ? cpCollisionHandlerDoNothing.postSolveFunc : &myCollisionPost; + defaultHandler->separateFunc = !handler->separate ? cpCollisionHandlerDoNothing.separateFunc : &myCollisionSeparate; defaultHandler->userData = handler; // // Already added ? If so, remove it. @@ -2554,7 +2618,7 @@ static void unroot_jsobject_from_handle(void *handle) static void shapeFreeWrap(cpSpace *space, cpShape *shape, void *unused){ cpSpaceRemoveShape(space, shape); unroot_jsobject_from_handle(shape); - // cpShapeFree(shape); +// cpShapeFree(shape); } static void postShapeFree(cpShape *shape, cpSpace *space){ @@ -2564,7 +2628,7 @@ static void postShapeFree(cpShape *shape, cpSpace *space){ static void constraintFreeWrap(cpSpace *space, cpConstraint *constraint, void *unused){ cpSpaceRemoveConstraint(space, constraint); unroot_jsobject_from_handle(constraint); - // cpConstraintFree(constraint); +// cpConstraintFree(constraint); } static void postConstraintFree(cpConstraint *constraint, cpSpace *space){ @@ -2574,7 +2638,7 @@ static void postConstraintFree(cpConstraint *constraint, cpSpace *space){ static void bodyFreeWrap(cpSpace *space, cpBody *body, void *unused){ cpSpaceRemoveBody(space, body); unroot_jsobject_from_handle(body); - // cpBodyFree(body); +// cpBodyFree(body); } static void postBodyFree(cpBody *body, cpSpace *space){ @@ -2587,7 +2651,6 @@ void static freeSpaceChildren(cpSpace *space) // Must remove these BEFORE freeing the body or you will access dangling pointers. cpSpaceEachShape(space, (cpSpaceShapeIteratorFunc)postShapeFree, space); cpSpaceEachConstraint(space, (cpSpaceConstraintIteratorFunc)postConstraintFree, space); - cpSpaceEachBody(space, (cpSpaceBodyIteratorFunc)postBodyFree, space); } @@ -2620,4 +2683,4 @@ bool JSB_cpMomentForSegment(JSContext *cx, uint32_t argc, jsval *vp) { } -#endif // JSB_INCLUDE_CHIPMUNK \ No newline at end of file +#endif // JSB_INCLUDE_CHIPMUNK diff --git a/cocos/scripting/js-bindings/manual/cocos2d_specifics.cpp b/cocos/scripting/js-bindings/manual/cocos2d_specifics.cpp index f494ff97e9..d103d61e97 100644 --- a/cocos/scripting/js-bindings/manual/cocos2d_specifics.cpp +++ b/cocos/scripting/js-bindings/manual/cocos2d_specifics.cpp @@ -562,10 +562,19 @@ js_type_class_t *js_get_type_from_node(cocos2d::Node* native_obj) return js_get_type_from_native(native_obj); } -void js_add_FinalizeHook(JSContext *cx, JS::HandleObject target) +void js_add_FinalizeHook(JSContext *cx, JS::HandleObject target, bool isRef) { - JS::RootedObject proto(cx, jsb_FinalizeHook_prototype); - JS::RootedObject hook(cx, JS_NewObject(cx, jsb_FinalizeHook_class, proto, JS::NullPtr())); + JS::RootedObject hook(cx); + if (isRef) + { + JS::RootedObject proto(cx, jsb_RefFinalizeHook_prototype); + hook = JS_NewObject(cx, jsb_RefFinalizeHook_class, proto, JS::NullPtr()); + } + else + { + JS::RootedObject proto(cx, jsb_ObjFinalizeHook_prototype); + hook = JS_NewObject(cx, jsb_ObjFinalizeHook_class, proto, JS::NullPtr()); + } jsb_register_finalize_hook(hook.get(), target.get()); JS::RootedValue hookVal(cx, OBJECT_TO_JSVAL(hook)); JS_SetProperty(cx, target, "__hook", hookVal); @@ -591,6 +600,7 @@ void js_add_object_reference(JS::HandleValue owner, JS::HandleValue target) ScriptingCore *engine = ScriptingCore::getInstance(); JSContext *cx = engine->getGlobalContext(); JS::RootedObject global(cx, engine->getGlobalObject()); + JSAutoCompartment(cx, global); JS::RootedObject jsbObj(cx); get_or_create_js_obj(cx, global, "jsb", &jsbObj); JS::RootedValue jsbVal(cx, OBJECT_TO_JSVAL(jsbObj)); @@ -615,10 +625,11 @@ void js_remove_object_reference(JS::HandleValue owner, JS::HandleValue target) } ScriptingCore *engine = ScriptingCore::getInstance(); JSContext *cx = engine->getGlobalContext(); + JS::RootedObject global(cx, engine->getGlobalObject()); + JSAutoCompartment(cx, global); JS::RootedObject ownerObj(cx, owner.toObjectOrNull()); JS::RootedObject targetObj(cx, target.toObjectOrNull()); - - JS::RootedObject global(cx, engine->getGlobalObject()); + JS::RootedObject jsbObj(cx); get_or_create_js_obj(cx, global, "jsb", &jsbObj); JS::RootedValue jsbVal(cx, OBJECT_TO_JSVAL(jsbObj)); @@ -645,6 +656,7 @@ void js_add_object_root(JS::HandleValue target) ScriptingCore *engine = ScriptingCore::getInstance(); JSContext *cx = engine->getGlobalContext(); JS::RootedObject global(cx, engine->getGlobalObject()); + JSAutoCompartment(cx, global); JS::RootedObject jsbObj(cx); get_or_create_js_obj(cx, global, "jsb", &jsbObj); JS::RootedValue jsbVal(cx, OBJECT_TO_JSVAL(jsbObj)); @@ -673,6 +685,8 @@ void js_remove_object_root(JS::HandleValue target) } ScriptingCore *engine = ScriptingCore::getInstance(); JSContext *cx = engine->getGlobalContext(); + JS::RootedObject global(cx, engine->getGlobalObject()); + JSAutoCompartment(cx, global); JS::RootedObject targetObj(cx, target.toObjectOrNull()); js_proxy_t *pTarget = jsb_get_js_proxy(targetObj); if (!pTarget) @@ -680,7 +694,6 @@ void js_remove_object_root(JS::HandleValue target) return; } - JS::RootedObject global(cx, engine->getGlobalObject()); JS::RootedObject jsbObj(cx); get_or_create_js_obj(cx, global, "jsb", &jsbObj); JS::RootedValue jsbVal(cx, OBJECT_TO_JSVAL(jsbObj)); @@ -703,6 +716,7 @@ void js_remove_object_root(JS::HandleValue target) } JSCallbackWrapper::JSCallbackWrapper() +: _rooted(true) { JSContext* cx = ScriptingCore::getInstance()->getGlobalContext(); _jsCallback = JS::NullValue(); @@ -716,6 +730,7 @@ JSCallbackWrapper::JSCallbackWrapper() } JSCallbackWrapper::JSCallbackWrapper(JS::HandleValue owner) +: _rooted(true) { _owner = owner; _jsCallback = JS::NullValue(); @@ -727,7 +742,7 @@ JSCallbackWrapper::~JSCallbackWrapper() { JSContext* cx = ScriptingCore::getInstance()->getGlobalContext(); JS::RootedValue ownerVal(cx, _owner); - if (!ownerVal.isNullOrUndefined()) + if (_rooted && !ownerVal.isNullOrUndefined()) { JS::RootedValue target(cx, _jsCallback); if (!target.isNullOrUndefined()) @@ -1229,7 +1244,7 @@ void JSScheduleWrapper::dump() schedFunc_proxy_t *current_func, *tmp_func; int jsfuncTargetCount = 0; HASH_ITER(hh, _schedFunc_target_ht, current_func, tmp_func) { - auto targets = current->targets; + auto targets = current_func->targets; for (const auto& pObj : *targets) { CCLOG("js func ( %p ), native target[%d]=( %p )", current_func->jsfuncObj, jsfuncTargetCount, pObj); @@ -1328,7 +1343,7 @@ bool js_CCNode_unschedule(JSContext *cx, uint32_t argc, jsval *vp) auto targetArray = JSScheduleWrapper::getTargetForSchedule(args.get(0)); if (targetArray) { - CCLOGINFO("unschedule target number: %ld", static_cast(targetArray->count())); + CCLOGINFO("unschedule target number: %ld", static_cast(targetArray->size())); for (const auto& tmp : *targetArray) { @@ -1707,7 +1722,7 @@ bool js_cocos2dx_CCNode_scheduleUpdate(JSContext *cx, uint32_t argc, jsval *vp) if (!bFound) { - tmpCobj = new (std::nothrow) JSScheduleWrapper(thisValue); + tmpCobj = new (std::nothrow) JSScheduleWrapper(JS::NullHandleValue); tmpCobj->autorelease(); tmpCobj->setJSCallbackThis(thisValue); tmpCobj->setJSCallbackFunc(jsUpdateFunc); @@ -5876,15 +5891,17 @@ bool js_cocos2dx_ComponentJS_getScriptObject(JSContext *cx, uint32_t argc, jsval return false; } -JSClass *jsb_FinalizeHook_class; -JSObject *jsb_FinalizeHook_prototype; +JSClass *jsb_RefFinalizeHook_class; +JSObject *jsb_RefFinalizeHook_prototype; +JSClass *jsb_ObjFinalizeHook_class; +JSObject *jsb_ObjFinalizeHook_prototype; -static bool jsb_FinalizeHook_constructor(JSContext *cx, uint32_t argc, jsval *vp) +static bool jsb_RefFinalizeHook_constructor(JSContext *cx, uint32_t argc, jsval *vp) { JS::CallArgs args = JS::CallArgsFromVp(argc, vp); // Create new object - JS::RootedObject proto(cx, jsb_FinalizeHook_prototype); - JS::RootedObject obj(cx, JS_NewObject(cx, jsb_FinalizeHook_class, proto, JS::NullPtr())); + JS::RootedObject proto(cx, jsb_RefFinalizeHook_prototype); + JS::RootedObject obj(cx, JS_NewObject(cx, jsb_RefFinalizeHook_class, proto, JS::NullPtr())); // Register arguments[0] as owner if (!args.get(0).isNullOrUndefined()) { @@ -5893,7 +5910,7 @@ static bool jsb_FinalizeHook_constructor(JSContext *cx, uint32_t argc, jsval *vp args.rval().set(OBJECT_TO_JSVAL(obj)); return true; } -void jsb_FinalizeHook_finalize(JSFreeOp *fop, JSObject *obj) +void jsb_RefFinalizeHook_finalize(JSFreeOp *fop, JSObject *obj) { ScriptingCore *sc = ScriptingCore::getInstance(); JSContext *cx = sc->getGlobalContext(); @@ -5902,7 +5919,7 @@ void jsb_FinalizeHook_finalize(JSFreeOp *fop, JSObject *obj) if (ownerPtr) { JS::RootedObject owner(cx, ownerPtr); - CCLOGINFO("jsbindings: finalizing JS object via Finalizehook %p", owner.get()); + CCLOGINFO("jsbindings: finalizing JS object via RefFinalizehook %p", owner.get()); js_proxy_t* nproxy = nullptr; js_proxy_t* jsproxy = nullptr; jsproxy = jsb_get_js_proxy(owner); @@ -5931,11 +5948,6 @@ void jsb_FinalizeHook_finalize(JSFreeOp *fop, JSObject *obj) CCLOG("------RELEASED------ Cpp: %p - JS: %p", refObj, ownerPtr); #endif // COCOS2D_DEBUG } -#if COCOS2D_DEBUG > 1 - else { - CCLOG("A non ref object have registered finalize hook: %p", nproxy->ptr); - } -#endif // COCOS2D_DEBUG sc->setFinalizing(nullptr); } #if COCOS2D_DEBUG > 1 @@ -5945,24 +5957,83 @@ void jsb_FinalizeHook_finalize(JSFreeOp *fop, JSObject *obj) #endif // COCOS2D_DEBUG } } +static bool jsb_ObjFinalizeHook_constructor(JSContext *cx, uint32_t argc, jsval *vp) +{ + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); + // Create new object + JS::RootedObject proto(cx, jsb_ObjFinalizeHook_prototype); + JS::RootedObject obj(cx, JS_NewObject(cx, jsb_ObjFinalizeHook_class, proto, JS::NullPtr())); + // Register arguments[0] as owner + if (!args.get(0).isNullOrUndefined()) + { + jsb_register_finalize_hook(obj.get(), args.get(0).toObjectOrNull()); + } + args.rval().set(OBJECT_TO_JSVAL(obj)); + return true; +} +void jsb_ObjFinalizeHook_finalize(JSFreeOp *fop, JSObject *obj) +{ + ScriptingCore *sc = ScriptingCore::getInstance(); + JSContext *cx = sc->getGlobalContext(); + JS::RootedObject jsobj(cx, obj); + JSObject *ownerPtr = jsb_get_and_remove_hook_owner(obj); + if (ownerPtr) + { + JS::RootedObject owner(cx, ownerPtr); + CCLOGINFO("jsbindings: finalizing JS object via ObjFinalizehook %p", owner.get()); + js_proxy_t* nproxy = nullptr; + js_proxy_t* jsproxy = nullptr; + jsproxy = jsb_get_js_proxy(owner); + if (jsproxy) + { + sc->setFinalizing(ownerPtr); + + nproxy = jsb_get_native_proxy(jsproxy->ptr); + jsb_remove_proxy(nproxy, jsproxy); +#if COCOS2D_DEBUG > 1 + CCLOG("------WEAK_REF------ Cpp: %p - JS: %p", nproxy->ptr, ownerPtr); +#endif // COCOS2D_DEBUG + sc->setFinalizing(nullptr); + } + } +} -void jsb_register_FinalizeHook(JSContext *cx, JS::HandleObject global) { - jsb_FinalizeHook_class = (JSClass *)calloc(1, sizeof(JSClass)); - jsb_FinalizeHook_class->name = "FinalizeHook"; - jsb_FinalizeHook_class->addProperty = JS_PropertyStub; - jsb_FinalizeHook_class->delProperty = JS_DeletePropertyStub; - jsb_FinalizeHook_class->getProperty = JS_PropertyStub; - jsb_FinalizeHook_class->setProperty = JS_StrictPropertyStub; - jsb_FinalizeHook_class->enumerate = JS_EnumerateStub; - jsb_FinalizeHook_class->resolve = JS_ResolveStub; - jsb_FinalizeHook_class->convert = JS_ConvertStub; - jsb_FinalizeHook_class->finalize = jsb_FinalizeHook_finalize; - jsb_FinalizeHook_class->flags = JSCLASS_HAS_RESERVED_SLOTS(2); +void jsb_register_RefFinalizeHook(JSContext *cx, JS::HandleObject global) { + jsb_RefFinalizeHook_class = (JSClass *)calloc(1, sizeof(JSClass)); + jsb_RefFinalizeHook_class->name = "RefFinalizeHook"; + jsb_RefFinalizeHook_class->addProperty = JS_PropertyStub; + jsb_RefFinalizeHook_class->delProperty = JS_DeletePropertyStub; + jsb_RefFinalizeHook_class->getProperty = JS_PropertyStub; + jsb_RefFinalizeHook_class->setProperty = JS_StrictPropertyStub; + jsb_RefFinalizeHook_class->enumerate = JS_EnumerateStub; + jsb_RefFinalizeHook_class->resolve = JS_ResolveStub; + jsb_RefFinalizeHook_class->convert = JS_ConvertStub; + jsb_RefFinalizeHook_class->finalize = jsb_RefFinalizeHook_finalize; + jsb_RefFinalizeHook_class->flags = JSCLASS_HAS_RESERVED_SLOTS(2); - jsb_FinalizeHook_prototype = JS_InitClass(cx, global, + jsb_RefFinalizeHook_prototype = JS_InitClass(cx, global, JS::NullPtr(), // parent proto - jsb_FinalizeHook_class, - jsb_FinalizeHook_constructor, 0, // constructor + jsb_RefFinalizeHook_class, + jsb_RefFinalizeHook_constructor, 0, // constructor + NULL, NULL, NULL, NULL); +} +void jsb_register_ObjFinalizeHook(JSContext *cx, JS::HandleObject global) { + jsb_ObjFinalizeHook_class = (JSClass *)calloc(1, sizeof(JSClass)); + jsb_ObjFinalizeHook_class->name = "ObjFinalizeHook"; + jsb_ObjFinalizeHook_class->addProperty = JS_PropertyStub; + jsb_ObjFinalizeHook_class->delProperty = JS_DeletePropertyStub; + jsb_ObjFinalizeHook_class->getProperty = JS_PropertyStub; + jsb_ObjFinalizeHook_class->setProperty = JS_StrictPropertyStub; + jsb_ObjFinalizeHook_class->enumerate = JS_EnumerateStub; + jsb_ObjFinalizeHook_class->resolve = JS_ResolveStub; + jsb_ObjFinalizeHook_class->convert = JS_ConvertStub; + jsb_ObjFinalizeHook_class->finalize = jsb_ObjFinalizeHook_finalize; + jsb_ObjFinalizeHook_class->flags = JSCLASS_HAS_RESERVED_SLOTS(2); + + jsb_ObjFinalizeHook_prototype = JS_InitClass(cx, global, + JS::NullPtr(), // parent proto + jsb_ObjFinalizeHook_class, + jsb_ObjFinalizeHook_constructor, 0, // constructor NULL, NULL, NULL, NULL); } @@ -5976,7 +6047,8 @@ void register_cocos2dx_js_core(JSContext* cx, JS::HandleObject global) get_or_create_js_obj(cx, global, "jsb", &jsbObj); // Memory management related - jsb_register_FinalizeHook(cx, jsbObj); + jsb_register_RefFinalizeHook(cx, jsbObj); + jsb_register_ObjFinalizeHook(cx, jsbObj); js_register_cocos2dx_PolygonInfo(cx, jsbObj); js_register_cocos2dx_AutoPolygon(cx, jsbObj); diff --git a/cocos/scripting/js-bindings/manual/cocos2d_specifics.hpp b/cocos/scripting/js-bindings/manual/cocos2d_specifics.hpp index 52c8d94b1a..307c64e013 100644 --- a/cocos/scripting/js-bindings/manual/cocos2d_specifics.hpp +++ b/cocos/scripting/js-bindings/manual/cocos2d_specifics.hpp @@ -79,8 +79,10 @@ extern schedFunc_proxy_t *_schedFunc_target_ht; extern schedTarget_proxy_t *_schedObj_target_ht; extern callfuncTarget_proxy_t *_callfuncTarget_native_ht; -extern JSClass *jsb_FinalizeHook_class; -extern JSObject *jsb_FinalizeHook_prototype; +extern JSClass *jsb_RefFinalizeHook_class; +extern JSObject *jsb_RefFinalizeHook_prototype; +extern JSClass *jsb_ObjFinalizeHook_class; +extern JSObject *jsb_ObjFinalizeHook_prototype; /** * You don't need to manage the returned pointer. They live for the whole life of @@ -142,7 +144,7 @@ JSObject* js_get_or_create_jsobject(JSContext *cx, typename std::enable_if _jsCallback; JS::Heap _jsThisObj; JS::Heap _extraData; + bool _rooted; }; diff --git a/cocos/scripting/js-bindings/manual/cocosbuilder/cocosbuilder_specifics.hpp b/cocos/scripting/js-bindings/manual/cocosbuilder/cocosbuilder_specifics.hpp index 6f9b95cb65..05f6386a74 100644 --- a/cocos/scripting/js-bindings/manual/cocosbuilder/cocosbuilder_specifics.hpp +++ b/cocos/scripting/js-bindings/manual/cocosbuilder/cocosbuilder_specifics.hpp @@ -30,7 +30,6 @@ class JSCCBAnimationWrapper: public JSCallbackWrapper { public: JSCCBAnimationWrapper(JS::HandleValue owner) : JSCallbackWrapper(owner) {} - virtual ~JSCCBAnimationWrapper() {} void animationCompleteCallback() { diff --git a/cocos/scripting/js-bindings/manual/js_manual_conversions.cpp b/cocos/scripting/js-bindings/manual/js_manual_conversions.cpp index 8b23c81a9a..dffa6feca9 100644 --- a/cocos/scripting/js-bindings/manual/js_manual_conversions.cpp +++ b/cocos/scripting/js-bindings/manual/js_manual_conversions.cpp @@ -107,6 +107,7 @@ const char* JSStringWrapper::get() // JSFunctionWrapper JSFunctionWrapper::JSFunctionWrapper(JSContext* cx, JS::HandleObject jsthis, JS::HandleValue fval) : _cx(cx) +, _rooted(false) { _jsthis = jsthis; _fval = fval; @@ -128,10 +129,12 @@ JSFunctionWrapper::JSFunctionWrapper(JSContext* cx, JS::HandleObject jsthis, JS: { js_add_object_reference(valRoot, funcVal); } + _rooted = true; } } JSFunctionWrapper::JSFunctionWrapper(JSContext* cx, JS::HandleObject jsthis, JS::HandleValue fval, JS::HandleValue owner) : _cx(cx) +, _rooted(false) { _jsthis = jsthis; _fval = fval; @@ -154,7 +157,7 @@ JSFunctionWrapper::~JSFunctionWrapper() { JS::RootedValue ownerVal(_cx, _owner); - if (!ownerVal.isNullOrUndefined() && ScriptingCore::getInstance()->getFinalizing() != ownerVal.toObjectOrNull()) + if (_rooted && !ownerVal.isNullOrUndefined()) { JS::RootedValue thisVal(_cx, OBJECT_TO_JSVAL(_jsthis)); if (!thisVal.isNullOrUndefined()) diff --git a/cocos/scripting/js-bindings/manual/js_manual_conversions.h b/cocos/scripting/js-bindings/manual/js_manual_conversions.h index 4ea249f341..9090246045 100644 --- a/cocos/scripting/js-bindings/manual/js_manual_conversions.h +++ b/cocos/scripting/js-bindings/manual/js_manual_conversions.h @@ -85,6 +85,7 @@ private: JS::Heap _jsthis; JS::Heap _fval; JS::Heap _owner; + bool _rooted; private: CC_DISALLOW_COPY_AND_ASSIGN(JSFunctionWrapper); }; diff --git a/cocos/scripting/js-bindings/manual/jsb_event_dispatcher_manual.cpp b/cocos/scripting/js-bindings/manual/jsb_event_dispatcher_manual.cpp index d5649977d6..39edaa6018 100644 --- a/cocos/scripting/js-bindings/manual/jsb_event_dispatcher_manual.cpp +++ b/cocos/scripting/js-bindings/manual/jsb_event_dispatcher_manual.cpp @@ -179,7 +179,7 @@ bool js_EventListenerAcceleration_create(JSContext *cx, uint32_t argc, jsval *vp largv[0] = ccacceleration_to_jsval(cx, *acc); if (event) { js_type_class_t *typeClassEvent = js_get_type_from_native(event); - largv[1] = OBJECT_TO_JSVAL(jsb_get_or_create_weak_jsobject(cx, event, typeClassEvent, "cocos2d::EventAcceleration")); + largv[1] = OBJECT_TO_JSVAL(jsb_get_or_create_weak_jsobject(cx, event, typeClassEvent)); } else { largv[1] = JSVAL_NULL; }; @@ -246,7 +246,7 @@ bool js_EventListenerCustom_create(JSContext *cx, uint32_t argc, jsval *vp) jsval largv[1]; if (event) { js_type_class_t *typeClassEvent = js_get_type_from_native(event); - largv[0] = OBJECT_TO_JSVAL(jsb_get_or_create_weak_jsobject(cx, event, typeClassEvent, "cocos2d::EventCustom")); + largv[0] = OBJECT_TO_JSVAL(jsb_get_or_create_weak_jsobject(cx, event, typeClassEvent)); } else { largv[0] = JSVAL_NULL; }; @@ -298,7 +298,7 @@ bool js_EventDispatcher_addCustomEventListener(JSContext *cx, uint32_t argc, jsv jsval largv[1]; if (event) { js_type_class_t *typeClassEvent = js_get_type_from_native(event); - largv[0] = OBJECT_TO_JSVAL(jsb_get_or_create_weak_jsobject(cx, event, typeClassEvent, "cocos2d::EventCustom")); + largv[0] = OBJECT_TO_JSVAL(jsb_get_or_create_weak_jsobject(cx, event, typeClassEvent)); } else { largv[0] = JSVAL_NULL; }; diff --git a/cocos/scripting/js-bindings/manual/network/XMLHTTPRequest.cpp b/cocos/scripting/js-bindings/manual/network/XMLHTTPRequest.cpp index 47da1f0bc7..929ae7feac 100644 --- a/cocos/scripting/js-bindings/manual/network/XMLHTTPRequest.cpp +++ b/cocos/scripting/js-bindings/manual/network/XMLHTTPRequest.cpp @@ -400,7 +400,7 @@ JS_BINDED_CONSTRUCTOR_IMPL(MinXmlHttpRequest) js_proxy_t *p = jsb_new_proxy(req, obj); #if CC_ENABLE_GC_FOR_NATIVE_OBJECTS - js_add_FinalizeHook(cx, obj); + js_add_FinalizeHook(cx, obj, true); // don't retain it, already retained #if COCOS2D_DEBUG > 1 CCLOG("++++++RETAINED++++++ Cpp(XMLHttpRequest): %p - JS: %p", req, obj.get()); diff --git a/cocos/scripting/js-bindings/manual/spine/jsb_cocos2dx_spine_manual.cpp b/cocos/scripting/js-bindings/manual/spine/jsb_cocos2dx_spine_manual.cpp index e1b288dc86..efbffa2758 100644 --- a/cocos/scripting/js-bindings/manual/spine/jsb_cocos2dx_spine_manual.cpp +++ b/cocos/scripting/js-bindings/manual/spine/jsb_cocos2dx_spine_manual.cpp @@ -28,8 +28,6 @@ using namespace spine; -std::unordered_map _spTrackEntryMap; - jsval speventdata_to_jsval(JSContext* cx, spEventData& v) { JS::RootedObject tmp(cx, JS_NewObject(cx, nullptr, JS::NullPtr(), JS::NullPtr())); @@ -279,45 +277,68 @@ jsval spanimation_to_jsval(JSContext* cx, spAnimation& v) return JSVAL_NULL; } +bool jsb_spine_TrackEntry_get_next(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleValue vp) +{ + JS::RootedObject jsthis(cx, obj); + js_proxy_t *proxy = jsb_get_js_proxy(jsthis); + spTrackEntry* cobj = (spTrackEntry *)(proxy ? proxy->ptr : NULL); + if (cobj) { + JS::RootedValue jsret(cx, JS::NullValue()); + if (cobj->next) + { + jsret = sptrackentry_to_jsval(cx, *cobj->next); + } + vp.set(jsret); + return true; + } + else { + CCLOGERROR("jsb_spine_TrackEntry_get_next : Invalid Native Object"); + return false; + } +} + +bool jsb_spine_TrackEntry_get_previous(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleValue vp) +{ + JS::RootedObject jsthis(cx, obj); + js_proxy_t *proxy = jsb_get_js_proxy(jsthis); + spTrackEntry* cobj = (spTrackEntry *)(proxy ? proxy->ptr : NULL); + if (cobj) { + JS::RootedValue jsret(cx, JS::NullValue()); + if (cobj->previous) + { + jsret = sptrackentry_to_jsval(cx, *cobj->previous); + } + vp.set(jsret); + return true; + } + else { + CCLOGERROR("jsb_spine_TrackEntry_get_previous : Invalid Native Object"); + return false; + } +} + jsval sptrackentry_to_jsval(JSContext* cx, spTrackEntry& v) { - JS::RootedObject tmp(cx, JS_NewObject(cx, nullptr, JS::NullPtr(), JS::NullPtr())); - if (!tmp) return JSVAL_NULL; - - JS::RootedValue nextVal(cx); - if (v.next) + js_proxy_t *proxy = jsb_get_native_proxy(&v); + if (proxy) { - auto nextPtr = v.next; - auto entry = _spTrackEntryMap.find(nextPtr); - if (entry == _spTrackEntryMap.end()) - { - _spTrackEntryMap.emplace(nextPtr, nextVal.get()); - nextVal = sptrackentry_to_jsval(cx, *v.next); - } - else - { - nextVal.set(entry->second); - } + JS::RootedObject entry(cx, proxy->obj); + return OBJECT_TO_JSVAL(entry); } - - JS::RootedValue previousVal(cx); - if (v.previous) + else { - auto previousPtr = v.previous; - auto entry = _spTrackEntryMap.find(previousPtr); - if (entry == _spTrackEntryMap.end()) - { - _spTrackEntryMap.emplace(previousPtr, previousVal.get()); - previousVal = sptrackentry_to_jsval(cx, *previousPtr); - } - else - { - previousVal.set(entry->second); - } - } - - JS::RootedValue jsanimation(cx, spanimation_to_jsval(cx, *v.animation)); - bool ok = JS_DefineProperty(cx, tmp, "delay", v.delay, JSPROP_ENUMERATE | JSPROP_PERMANENT) && + JS::RootedObject tmp(cx, JS_NewObject(cx, nullptr, JS::NullPtr(), JS::NullPtr())); + if (!tmp) return JSVAL_NULL; + + jsb_new_proxy(&v, tmp); + js_add_FinalizeHook(cx, tmp, false); + +#if COCOS2D_DEBUG > 1 + CCLOG("++++++WEAK_REF++++++ Cpp(spine::TrackEntry): %p - JS: %p", &v, tmp.get()); +#endif // COCOS2D_DEBUG + + JS::RootedValue jsanimation(cx, spanimation_to_jsval(cx, *v.animation)); + bool ok = JS_DefineProperty(cx, tmp, "delay", v.delay, JSPROP_ENUMERATE | JSPROP_PERMANENT) && JS_DefineProperty(cx, tmp, "time", v.time, JSPROP_ENUMERATE | JSPROP_PERMANENT) && JS_DefineProperty(cx, tmp, "lastTime", v.lastTime, JSPROP_ENUMERATE | JSPROP_PERMANENT) && JS_DefineProperty(cx, tmp, "endTime", v.endTime, JSPROP_ENUMERATE | JSPROP_PERMANENT) && @@ -325,15 +346,16 @@ jsval sptrackentry_to_jsval(JSContext* cx, spTrackEntry& v) JS_DefineProperty(cx, tmp, "mixTime", v.mixTime, JSPROP_ENUMERATE | JSPROP_PERMANENT) && JS_DefineProperty(cx, tmp, "mixDuration", v.mixDuration, JSPROP_ENUMERATE | JSPROP_PERMANENT) && JS_DefineProperty(cx, tmp, "animation", jsanimation, JSPROP_ENUMERATE | JSPROP_PERMANENT) && - JS_DefineProperty(cx, tmp, "next", nextVal, JSPROP_ENUMERATE | JSPROP_PERMANENT) && - JS_DefineProperty(cx, tmp, "previous", previousVal, JSPROP_ENUMERATE | JSPROP_PERMANENT); - - if (ok) - { - return OBJECT_TO_JSVAL(tmp); + JS_DefineProperty(cx, tmp, "next", JS::UndefinedHandleValue, JSPROP_ENUMERATE | JSPROP_PERMANENT, jsb_spine_TrackEntry_get_next) && + JS_DefineProperty(cx, tmp, "previous", JS::UndefinedHandleValue, JSPROP_ENUMERATE | JSPROP_PERMANENT, jsb_spine_TrackEntry_get_previous); + + if (ok) + { + return OBJECT_TO_JSVAL(tmp); + } + + return JSVAL_NULL; } - - return JSVAL_NULL; } bool jsb_cocos2dx_spine_findBone(JSContext *cx, uint32_t argc, jsval *vp) @@ -481,7 +503,6 @@ bool jsb_cocos2dx_spine_getCurrent(JSContext *cx, uint32_t argc, jsval *vp) if (ret) { jsret = sptrackentry_to_jsval(cx, *ret); - _spTrackEntryMap.clear(); } } while (0); @@ -495,7 +516,6 @@ bool jsb_cocos2dx_spine_getCurrent(JSContext *cx, uint32_t argc, jsval *vp) if (ret) { jsret = sptrackentry_to_jsval(cx, *ret); - _spTrackEntryMap.clear(); } } while (0); @@ -532,7 +552,6 @@ bool jsb_cocos2dx_spine_setAnimation(JSContext *cx, uint32_t argc, jsval *vp) if (ret) { jsret = sptrackentry_to_jsval(cx, *ret); - _spTrackEntryMap.clear(); } } while(0); @@ -570,7 +589,6 @@ bool jsb_cocos2dx_spine_addAnimation(JSContext *cx, uint32_t argc, jsval *vp) if (ret) { jsret = sptrackentry_to_jsval(cx, *ret); - _spTrackEntryMap.clear(); } } while(0); @@ -596,7 +614,6 @@ bool jsb_cocos2dx_spine_addAnimation(JSContext *cx, uint32_t argc, jsval *vp) if (ret) { jsret = sptrackentry_to_jsval(cx, *ret); - _spTrackEntryMap.clear(); } } while(0); diff --git a/cocos/scripting/js-bindings/script/ccui/jsb_ccui_create_apis.js b/cocos/scripting/js-bindings/script/ccui/jsb_ccui_create_apis.js index 7cb5811da1..c79a660edd 100644 --- a/cocos/scripting/js-bindings/script/ccui/jsb_ccui_create_apis.js +++ b/cocos/scripting/js-bindings/script/ccui/jsb_ccui_create_apis.js @@ -38,7 +38,7 @@ ccui.Widget.prototype._ctor = ccui.ScrollView.prototype._ctor = function(){ this.init(); - } + }; ccui.Button.prototype._ctor = function (normalImage, selectedImage, disableImage, texType) { if(texType !== undefined) @@ -80,7 +80,7 @@ ccui.ImageView.prototype._ctor = function(imageFileName, texType){ } else ccui.Widget.prototype.init.call(this); -} +}; ccui.LoadingBar.prototype._ctor = function(textureName, percentage){ ccui.Widget.prototype.init.call(this); diff --git a/cocos/scripting/js-bindings/script/jsb_boot.js b/cocos/scripting/js-bindings/script/jsb_boot.js index 863b1b40a4..5d6aaed075 100644 --- a/cocos/scripting/js-bindings/script/jsb_boot.js +++ b/cocos/scripting/js-bindings/script/jsb_boot.js @@ -737,35 +737,32 @@ cc.defineGetterSetter(cc.loader, "audioPath", function(){ cc.formatStr = function(){ var args = arguments; var l = args.length; - if(l < 1) - return ""; + if (l < 1) return ''; + var REGEXP_NUM_OR_STR = /(%d)|(%s)/; + var i = 1; var str = args[0]; - var needToFormat = true; - if(typeof str === "object"){ - needToFormat = false; + var hasSubstitution = typeof str === 'string' && REGEXP_NUM_OR_STR.test(str); + if (hasSubstitution) { + var REGEXP_STR = /%s/; + for (; i < l; ++i) { + var arg = args[i]; + var regExpToTest = typeof arg === 'number' ? REGEXP_NUM_OR_STR : REGEXP_STR; + if (regExpToTest.test(str)) + str = str.replace(regExpToTest, arg); + else + str += ' ' + arg; + } } - for(var i = 1; i < l; ++i){ - var arg = args[i]; - if(needToFormat){ - while(true){ - var result = null; - if(typeof arg === "number"){ - result = str.match(/(%d)|(%s)/); - if(result){ - str = str.replace(/(%d)|(%s)/, arg); - break; - } - } - result = str.match(/%s/); - if(result) - str = str.replace(/%s/, arg); - else - str += " " + arg; - break; + else { + if (l > 1) { + for (; i < l; ++i) { + str += ' ' + args[i]; } - }else - str += " " + arg; + } + else { + str = '' + str; + } } return str; }; diff --git a/cocos/scripting/js-bindings/script/jsb_cocos2d.js b/cocos/scripting/js-bindings/script/jsb_cocos2d.js index 8dffa64cbf..16f3d4bf6b 100644 --- a/cocos/scripting/js-bindings/script/jsb_cocos2d.js +++ b/cocos/scripting/js-bindings/script/jsb_cocos2d.js @@ -26,7 +26,7 @@ // CCConfig.js // -cc.ENGINE_VERSION = "Cocos2d-JS v3.13"; +cc.ENGINE_VERSION = "Cocos2d-JS v3.14"; cc.FIX_ARTIFACTS_BY_STRECHING_TEXEL = 0; cc.DIRECTOR_STATS_POSITION = {x: 0, y: 0}; diff --git a/extensions/GUI/CCControlExtension/CCControlSwitch.cpp b/extensions/GUI/CCControlExtension/CCControlSwitch.cpp index e386808fc6..4b9e0060f6 100644 --- a/extensions/GUI/CCControlExtension/CCControlSwitch.cpp +++ b/extensions/GUI/CCControlExtension/CCControlSwitch.cpp @@ -214,7 +214,7 @@ bool ControlSwitchSprite::initWithMaskSprite( return false; } -void ControlSwitchSprite::updateTweenAction(float value, const std::string& /*key*/) +void ControlSwitchSprite::updateTweenAction(float value, const std::string& key) { CCLOGINFO("key = %s, value = %f", key.c_str(), value); setSliderXPosition(value); diff --git a/web b/web index 6404318146..e5fe5bbf4f 160000 --- a/web +++ b/web @@ -1 +1 @@ -Subproject commit 640431814638f732a4b886182820cc8a88a75e87 +Subproject commit e5fe5bbf4f8e1016d58c56ee7079f38f38b2bfb1