/scripting/javascript/bindings/ScriptingCore.cpp

https://bitbucket.org/Tsiannian/cocos2d-x · C++ · 881 lines · 731 code · 129 blank · 21 comment · 120 complexity · 5cf93de195795fbdcd52d9d8b5078426 MD5 · raw file

  1. //
  2. // ScriptingCore.cpp
  3. // testmonkey
  4. //
  5. // Created by Rolando Abarca on 3/14/12.
  6. // Copyright (c) 2012 Zynga Inc. All rights reserved.
  7. //
  8. #include <iostream>
  9. #include <stdio.h>
  10. #include <stdlib.h>
  11. #include <sys/stat.h>
  12. #include <fcntl.h>
  13. #include <vector>
  14. #include "ScriptingCore.h"
  15. #include "cocos2d.h"
  16. #ifdef ANDROID
  17. #include <android/log.h>
  18. #include <jni/JniHelper.h>
  19. #endif
  20. #ifdef ANDROID
  21. #define LOG_TAG "ScriptingCore.cpp"
  22. #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)
  23. #else
  24. #define LOGD(...) js_log(__VA_ARGS__)
  25. #endif
  26. js_proxy_t *_native_js_global_ht = NULL;
  27. js_proxy_t *_js_native_global_ht = NULL;
  28. js_type_class_t *_js_global_type_ht = NULL;
  29. char *_js_log_buf = NULL;
  30. std::vector<sc_register_sth> registrationList;
  31. static void executeJSFunctionFromReservedSpot(JSContext *cx, JSObject *obj,
  32. jsval &dataVal, jsval &retval) {
  33. // if(p->jsclass->JSCLASS_HAS_RESERVED_SLOTS(1)) {
  34. jsval func = JS_GetReservedSlot(obj, 0);
  35. if(func == JSVAL_VOID) { return; }
  36. jsval thisObj = JS_GetReservedSlot(obj, 1);
  37. if(thisObj == JSVAL_VOID) {
  38. JS_CallFunctionValue(cx, obj, func, 1, &dataVal, &retval);
  39. } else {
  40. assert(!JSVAL_IS_PRIMITIVE(thisObj));
  41. JS_CallFunctionValue(cx, JSVAL_TO_OBJECT(thisObj), func, 1, &dataVal, &retval);
  42. }
  43. // }
  44. }
  45. static void getTouchesFuncName(int eventType, std::string &funcName) {
  46. switch(eventType) {
  47. case CCTOUCHBEGAN:
  48. funcName = "onTouchesBegan";
  49. break;
  50. case CCTOUCHENDED:
  51. funcName = "onTouchesEnded";
  52. break;
  53. case CCTOUCHMOVED:
  54. funcName = "onTouchesMoved";
  55. break;
  56. case CCTOUCHCANCELLED:
  57. funcName = "onTouchesCancelled";
  58. break;
  59. }
  60. }
  61. static void getTouchFuncName(int eventType, std::string &funcName) {
  62. switch(eventType) {
  63. case CCTOUCHBEGAN:
  64. funcName = "onTouchBegan";
  65. break;
  66. case CCTOUCHENDED:
  67. funcName = "onTouchEnded";
  68. break;
  69. case CCTOUCHMOVED:
  70. funcName = "onTouchMoved";
  71. break;
  72. case CCTOUCHCANCELLED:
  73. funcName = "onTouchCancelled";
  74. break;
  75. }
  76. }
  77. static void rootObject(JSContext *cx, JSObject *obj) {
  78. JS_AddNamedObjectRoot(cx, &obj, "unnamed");
  79. }
  80. static void unRootObject(JSContext *cx, JSObject *obj) {
  81. JS_RemoveObjectRoot(cx, &obj);
  82. }
  83. static void getJSTouchObject(JSContext *cx, CCTouch *x, jsval &jsret) {
  84. js_type_class_t *classType;
  85. TypeTest<cocos2d::CCTouch> t;
  86. uint32_t typeId = t.s_id();
  87. HASH_FIND_INT(_js_global_type_ht, &typeId, classType);
  88. assert(classType);
  89. JSObject *_tmp = JS_NewObject(cx, classType->jsclass, classType->proto, classType->parentProto);
  90. js_proxy_t *proxy, *nproxy;
  91. JS_NEW_PROXY(proxy, x, _tmp);
  92. void *ptr = x;
  93. JS_GET_PROXY(nproxy, ptr);
  94. JS_AddNamedObjectRoot(cx, &nproxy->obj, "CCTouch");
  95. jsret = OBJECT_TO_JSVAL(_tmp);
  96. }
  97. static void removeJSTouchObject(JSContext *cx, CCTouch *x, jsval &jsret) {
  98. js_proxy_t* nproxy;
  99. js_proxy_t* jsproxy;
  100. void *ptr = x;
  101. JS_GET_PROXY(nproxy, ptr);
  102. if (nproxy) {
  103. JS_RemoveObjectRoot(cx, &nproxy->obj);
  104. JS_GET_NATIVE_PROXY(jsproxy, nproxy->obj);
  105. JS_REMOVE_PROXY(nproxy, jsproxy);
  106. }
  107. }
  108. void ScriptingCore::executeJSFunctionWithThisObj(jsval thisObj, jsval callback,
  109. jsval data) {
  110. jsval retval;
  111. if(callback != JSVAL_VOID || thisObj != JSVAL_VOID) {
  112. JS_CallFunctionValue(cx, JSVAL_TO_OBJECT(thisObj), callback, 1, &data, &retval);
  113. }
  114. }
  115. static void executeJSFunctionWithName(JSContext *cx, JSObject *obj,
  116. const char *funcName, jsval &dataVal,
  117. jsval &retval) {
  118. JSBool hasAction;
  119. jsval temp_retval;
  120. if (JS_HasProperty(cx, obj, funcName, &hasAction) && hasAction) {
  121. if(!JS_GetProperty(cx, obj, funcName, &temp_retval)) {
  122. return;
  123. }
  124. if(temp_retval == JSVAL_VOID) {
  125. return;
  126. }
  127. JS_CallFunctionName(cx, obj, funcName,
  128. 1, &dataVal, &retval);
  129. }
  130. }
  131. void js_log(const char *format, ...) {
  132. if (_js_log_buf == NULL) {
  133. _js_log_buf = (char *)calloc(sizeof(char), 257);
  134. }
  135. va_list vl;
  136. va_start(vl, format);
  137. int len = vsnprintf(_js_log_buf, 256, format, vl);
  138. va_end(vl);
  139. if (len) {
  140. CCLOG("JS: %s\n", _js_log_buf);
  141. }
  142. }
  143. void registerDefaultClasses(JSContext* cx, JSObject* global) {
  144. if (!JS_InitStandardClasses(cx, global)) {
  145. js_log("error initializing the standard classes");
  146. }
  147. //
  148. // Javascript controller (__jsc__)
  149. //
  150. JSObject *jsc = JS_NewObject(cx, NULL, NULL, NULL);
  151. jsval jscVal = OBJECT_TO_JSVAL(jsc);
  152. JS_SetProperty(cx, global, "__jsc__", &jscVal);
  153. JS_DefineFunction(cx, jsc, "garbageCollect", ScriptingCore::forceGC, 0, JSPROP_READONLY | JSPROP_PERMANENT | JSPROP_ENUMERATE );
  154. JS_DefineFunction(cx, jsc, "dumpRoot", ScriptingCore::dumpRoot, 0, JSPROP_READONLY | JSPROP_PERMANENT | JSPROP_ENUMERATE );
  155. JS_DefineFunction(cx, jsc, "addGCRootObject", ScriptingCore::addRootJS, 1, JSPROP_READONLY | JSPROP_PERMANENT | JSPROP_ENUMERATE );
  156. JS_DefineFunction(cx, jsc, "removeGCRootObject", ScriptingCore::removeRootJS, 1, JSPROP_READONLY | JSPROP_PERMANENT | JSPROP_ENUMERATE );
  157. JS_DefineFunction(cx, jsc, "executeScript", ScriptingCore::executeScript, 1, JSPROP_READONLY | JSPROP_PERMANENT | JSPROP_ENUMERATE );
  158. // register some global functions
  159. JS_DefineFunction(cx, global, "require", ScriptingCore::executeScript, 1, JSPROP_READONLY | JSPROP_PERMANENT);
  160. JS_DefineFunction(cx, global, "log", ScriptingCore::log, 0, JSPROP_READONLY | JSPROP_PERMANENT);
  161. JS_DefineFunction(cx, global, "executeScript", ScriptingCore::executeScript, 1, JSPROP_READONLY | JSPROP_PERMANENT);
  162. JS_DefineFunction(cx, global, "forceGC", ScriptingCore::forceGC, 0, JSPROP_READONLY | JSPROP_PERMANENT);
  163. }
  164. void sc_finalize(JSFreeOp *freeOp, JSObject *obj) {
  165. return;
  166. }
  167. static JSClass global_class = {
  168. "global", JSCLASS_GLOBAL_FLAGS,
  169. JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
  170. JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, sc_finalize,
  171. JSCLASS_NO_OPTIONAL_MEMBERS
  172. };
  173. #if !defined(JS_NewCompartmentAndGlobalObject)
  174. #if defined(JS_NewGlobalObject)
  175. # undef(JS_NewGlobalObject)
  176. #endif
  177. //#define JS_NewCompartmentAndGlobalObject(cx, clasp, ppals) JS_NewGlobalObject(cx, clasp, ppals)
  178. #endif
  179. ScriptingCore::ScriptingCore()
  180. : rt(NULL)
  181. , cx(NULL)
  182. , global(NULL)
  183. {
  184. // set utf8 strings internally (we don't need utf16)
  185. JS_SetCStringsAreUTF8();
  186. this->addRegisterCallback(registerDefaultClasses);
  187. }
  188. void ScriptingCore::string_report(jsval val) {
  189. if (JSVAL_IS_NULL(val)) {
  190. LOGD("val : (JSVAL_IS_NULL(val)");
  191. // return 1;
  192. } else if ((JSVAL_IS_BOOLEAN(val)) &&
  193. (JS_FALSE == (JSVAL_TO_BOOLEAN(val)))) {
  194. LOGD("val : (return value is JS_FALSE");
  195. // return 1;
  196. } else if (JSVAL_IS_STRING(val)) {
  197. JSString *str = JS_ValueToString(this->getGlobalContext(), val);
  198. if (NULL == str) {
  199. LOGD("val : return string is NULL");
  200. } else {
  201. LOGD("val : return string =\n%s\n",
  202. JS_EncodeString(this->getGlobalContext(), str));
  203. }
  204. } else if (JSVAL_IS_NUMBER(val)) {
  205. double number;
  206. if (JS_FALSE ==
  207. JS_ValueToNumber(this->getGlobalContext(), val, &number)) {
  208. LOGD("val : return number could not be converted");
  209. } else {
  210. LOGD("val : return number =\n%f", number);
  211. }
  212. }
  213. }
  214. JSBool ScriptingCore::evalString(const char *string, jsval *outVal, const char *filename)
  215. {
  216. jsval rval;
  217. const char *fname = (filename ? filename : "noname");
  218. uint32_t lineno = 1;
  219. if (outVal == NULL) {
  220. outVal = &rval;
  221. }
  222. JSBool evaluatedOK = JS_EvaluateScript(cx, global,
  223. string, strlen(string),
  224. fname, lineno, outVal);
  225. if (JS_FALSE == evaluatedOK) {
  226. LOGD("(evaluatedOK == JS_FALSE)");
  227. } else {
  228. this->string_report(*outVal);
  229. }
  230. return evaluatedOK;
  231. }
  232. void ScriptingCore::start() {
  233. // for now just this
  234. this->createGlobalContext();
  235. }
  236. void ScriptingCore::addRegisterCallback(sc_register_sth callback) {
  237. registrationList.push_back(callback);
  238. }
  239. void ScriptingCore::createGlobalContext() {
  240. if (this->cx && this->rt) {
  241. JS_DestroyContext(this->cx);
  242. JS_DestroyRuntime(this->rt);
  243. this->cx = NULL;
  244. this->rt = NULL;
  245. }
  246. this->rt = JS_NewRuntime(10 * 1024 * 1024);
  247. this->cx = JS_NewContext(rt, 10240);
  248. JS_SetOptions(this->cx, JSOPTION_TYPE_INFERENCE);
  249. JS_SetVersion(this->cx, JSVERSION_LATEST);
  250. JS_SetOptions(this->cx, JS_GetOptions(this->cx) & ~JSOPTION_METHODJIT);
  251. JS_SetOptions(this->cx, JS_GetOptions(this->cx) & ~JSOPTION_METHODJIT_ALWAYS);
  252. JS_SetErrorReporter(this->cx, ScriptingCore::reportError);
  253. this->global = JS_NewCompartmentAndGlobalObject(cx, &global_class, NULL);
  254. for (std::vector<sc_register_sth>::iterator it = registrationList.begin(); it != registrationList.end(); it++) {
  255. sc_register_sth callback = *it;
  256. callback(this->cx, this->global);
  257. }
  258. }
  259. JSBool ScriptingCore::runScript(const char *path)
  260. {
  261. CCLOG("ScriptingCore::runScript(%s)", path);
  262. cocos2d::CCFileUtils *futil = cocos2d::CCFileUtils::sharedFileUtils();
  263. const char *realPath = futil->fullPathFromRelativePath(path);
  264. if (!realPath) {
  265. CCLOG("!realPath. returning JS_FALSE");
  266. return JS_FALSE;
  267. }
  268. unsigned char *content = NULL;
  269. unsigned long contentSize = 0;
  270. content = (unsigned char*)CCString::createWithContentsOfFile(realPath)->getCString();
  271. contentSize = strlen((char*)content);
  272. JSBool ret = JS_FALSE;
  273. if (content && contentSize) {
  274. jsval rval;
  275. ret = this->evalString((const char *)content, &rval, path);
  276. } else {
  277. CCLOG("!(content && contentSize)");
  278. }
  279. return ret;
  280. }
  281. ScriptingCore::~ScriptingCore()
  282. {
  283. JS_DestroyContext(cx);
  284. JS_DestroyRuntime(rt);
  285. JS_ShutDown();
  286. if (_js_log_buf) {
  287. free(_js_log_buf);
  288. _js_log_buf = NULL;
  289. }
  290. }
  291. void ScriptingCore::reportError(JSContext *cx, const char *message, JSErrorReport *report)
  292. {
  293. js_log("%s:%u:%s\n",
  294. report->filename ? report->filename : "<no filename=\"filename\">",
  295. (unsigned int) report->lineno,
  296. message);
  297. };
  298. JSBool ScriptingCore::log(JSContext* cx, uint32_t argc, jsval *vp)
  299. {
  300. if (argc > 0) {
  301. JSString *string = NULL;
  302. JS_ConvertArguments(cx, argc, JS_ARGV(cx, vp), "S", &string);
  303. if (string) {
  304. char *cstr = JS_EncodeString(cx, string);
  305. js_log(cstr);
  306. }
  307. }
  308. return JS_TRUE;
  309. }
  310. void ScriptingCore::removeScriptObjectByCCObject(CCObject* pObj)
  311. {
  312. js_proxy_t* nproxy;
  313. js_proxy_t* jsproxy;
  314. void *ptr = (void*)pObj;
  315. JS_GET_PROXY(nproxy, ptr);
  316. if (nproxy) {
  317. JSContext *cx = ScriptingCore::getInstance()->getGlobalContext();
  318. JS_RemoveObjectRoot(cx, &nproxy->obj);
  319. JS_GET_NATIVE_PROXY(jsproxy, nproxy->obj);
  320. JS_REMOVE_PROXY(nproxy, jsproxy);
  321. }
  322. }
  323. JSBool ScriptingCore::setReservedSpot(uint32_t i, JSObject *obj, jsval value) {
  324. JS_SetReservedSlot(obj, i, value);
  325. return JS_TRUE;
  326. }
  327. JSBool ScriptingCore::executeScript(JSContext *cx, uint32_t argc, jsval *vp)
  328. {
  329. JSBool ret = JS_FALSE;
  330. if (argc == 1) {
  331. JSString *string;
  332. if (JS_ConvertArguments(cx, argc, JS_ARGV(cx, vp), "S", &string) == JS_TRUE) {
  333. ret = ScriptingCore::getInstance()->runScript(JS_EncodeString(cx, string));
  334. }
  335. }
  336. return ret;
  337. }
  338. JSBool ScriptingCore::forceGC(JSContext *cx, uint32_t argc, jsval *vp)
  339. {
  340. JSRuntime *rt = JS_GetRuntime(cx);
  341. JS_GC(rt);
  342. return JS_TRUE;
  343. }
  344. static void dumpNamedRoot(const char *name, void *addr, JSGCRootType type, void *data)
  345. {
  346. printf("Root: '%s' at %p\n", name, addr);
  347. }
  348. JSBool ScriptingCore::dumpRoot(JSContext *cx, uint32_t argc, jsval *vp)
  349. {
  350. // JS_DumpNamedRoots is only available on DEBUG versions of SpiderMonkey.
  351. // Mac and Simulator versions were compiled with DEBUG.
  352. #if DEBUG
  353. JSContext *_cx = ScriptingCore::getInstance()->getGlobalContext();
  354. JSRuntime *rt = JS_GetRuntime(_cx);
  355. JS_DumpNamedRoots(rt, dumpNamedRoot, NULL);
  356. #endif
  357. return JS_TRUE;
  358. }
  359. JSBool ScriptingCore::addRootJS(JSContext *cx, uint32_t argc, jsval *vp)
  360. {
  361. if (argc == 1) {
  362. JSObject *o = NULL;
  363. if (JS_ConvertArguments(cx, argc, JS_ARGV(cx, vp), "o", &o) == JS_TRUE) {
  364. if (JS_AddNamedObjectRoot(cx, &o, "from-js") == JS_FALSE) {
  365. LOGD("something went wrong when setting an object to the root");
  366. }
  367. }
  368. return JS_TRUE;
  369. }
  370. return JS_FALSE;
  371. }
  372. JSBool ScriptingCore::removeRootJS(JSContext *cx, uint32_t argc, jsval *vp)
  373. {
  374. if (argc == 1) {
  375. JSObject *o = NULL;
  376. if (JS_ConvertArguments(cx, argc, JS_ARGV(cx, vp), "o", &o) == JS_TRUE) {
  377. JS_RemoveObjectRoot(cx, &o);
  378. }
  379. return JS_TRUE;
  380. }
  381. return JS_FALSE;
  382. }
  383. int ScriptingCore::executeNodeEvent(CCNode* pNode, int nAction)
  384. {
  385. js_proxy_t * p;
  386. JS_GET_PROXY(p, pNode);
  387. if (!p) return 0;
  388. jsval retval;
  389. jsval dataVal = INT_TO_JSVAL(1);
  390. js_proxy_t *proxy;
  391. JS_GET_PROXY(proxy, pNode);
  392. if(nAction == kCCNodeOnEnter)
  393. {
  394. executeJSFunctionWithName(this->cx, p->obj, "onEnter", dataVal, retval);
  395. }
  396. else if(nAction == kCCNodeOnExit)
  397. {
  398. executeJSFunctionWithName(this->cx, p->obj, "onExit", dataVal, retval);
  399. }
  400. else if(nAction == kCCNodeOnEnterTransitionDidFinish)
  401. {
  402. executeJSFunctionWithName(this->cx, p->obj, "onEnterTransitionDidFinish", dataVal, retval);
  403. }
  404. else if(nAction == kCCNodeOnExitTransitionDidStart)
  405. {
  406. executeJSFunctionWithName(this->cx, p->obj, "onExitTransitionDidStart", dataVal, retval);
  407. }
  408. return 1;
  409. }
  410. int ScriptingCore::executeMenuItemEvent(CCMenuItem* pMenuItem)
  411. {
  412. js_proxy_t * p;
  413. JS_GET_PROXY(p, pMenuItem);
  414. if (!p) return 0;
  415. jsval retval;
  416. jsval dataVal;
  417. js_proxy_t *proxy;
  418. JS_GET_PROXY(proxy, pMenuItem);
  419. dataVal = (proxy ? OBJECT_TO_JSVAL(proxy->obj) : JSVAL_NULL);
  420. executeJSFunctionFromReservedSpot(this->cx, p->obj, dataVal, retval);
  421. return 1;
  422. }
  423. int ScriptingCore::executeNotificationEvent(CCNotificationCenter* pNotificationCenter, const char* pszName)
  424. {
  425. return 1;
  426. }
  427. int ScriptingCore::executeCallFuncActionEvent(CCCallFunc* pAction, CCObject* pTarget/* = NULL*/)
  428. {
  429. return 1;
  430. }
  431. int ScriptingCore::executeSchedule(CCTimer* pTimer, float dt, CCNode* pNode/* = NULL*/)
  432. {
  433. js_proxy_t * p;
  434. JS_GET_PROXY(p, pNode);
  435. if (!p) return 0;
  436. jsval retval;
  437. jsval dataVal = DOUBLE_TO_JSVAL(dt);
  438. executeJSFunctionWithName(this->cx, p->obj, "update", dataVal, retval);
  439. return 1;
  440. }
  441. int ScriptingCore::executeLayerTouchesEvent(CCLayer* pLayer, int eventType, CCSet *pTouches)
  442. {
  443. std::string funcName = "";
  444. getTouchesFuncName(eventType, funcName);
  445. JSObject *jsretArr = JS_NewArrayObject(this->cx, 0, NULL);
  446. JS_AddNamedObjectRoot(this->cx, &jsretArr, "touchArray");
  447. int count = 0;
  448. for(CCSetIterator it = pTouches->begin(); it != pTouches->end(); ++it, ++count) {
  449. jsval jsret;
  450. getJSTouchObject(this->cx, (CCTouch *) *it, jsret);
  451. if(!JS_SetElement(this->cx, jsretArr, count, &jsret)) {
  452. break;
  453. }
  454. }
  455. executeFunctionWithObjectData(pLayer, funcName.c_str(), jsretArr);
  456. JS_RemoveObjectRoot(this->cx, &jsretArr);
  457. for(CCSetIterator it = pTouches->begin(); it != pTouches->end(); ++it, ++count) {
  458. jsval jsret;
  459. removeJSTouchObject(this->cx, (CCTouch *) *it, jsret);
  460. }
  461. return 1;
  462. }
  463. int ScriptingCore::executeLayerTouchEvent(CCLayer* pLayer, int eventType, CCTouch *pTouch)
  464. {
  465. return 0;
  466. }
  467. int ScriptingCore::executeFunctionWithObjectData(CCNode *self, const char *name, JSObject *obj) {
  468. js_proxy_t * p;
  469. JS_GET_PROXY(p, self);
  470. if (!p) return 0;
  471. jsval retval;
  472. jsval dataVal = OBJECT_TO_JSVAL(obj);
  473. executeJSFunctionWithName(this->cx, p->obj, name, dataVal, retval);
  474. return 1;
  475. }
  476. int ScriptingCore::executeCustomTouchesEvent(int eventType,
  477. CCSet *pTouches, JSObject *obj)
  478. {
  479. jsval retval;
  480. std::string funcName;
  481. getTouchesFuncName(eventType, funcName);
  482. JSObject *jsretArr = JS_NewArrayObject(this->cx, 0, NULL);
  483. JS_AddNamedObjectRoot(this->cx, &jsretArr, "touchArray");
  484. int count = 0;
  485. for(CCSetIterator it = pTouches->begin(); it != pTouches->end(); ++it, ++count) {
  486. jsval jsret;
  487. getJSTouchObject(this->cx, (CCTouch *) *it, jsret);
  488. if(!JS_SetElement(this->cx, jsretArr, count, &jsret)) {
  489. break;
  490. }
  491. }
  492. jsval jsretArrVal = OBJECT_TO_JSVAL(jsretArr);
  493. executeJSFunctionWithName(this->cx, obj, funcName.c_str(), jsretArrVal, retval);
  494. JS_RemoveObjectRoot(this->cx, &jsretArr);
  495. for(CCSetIterator it = pTouches->begin(); it != pTouches->end(); ++it, ++count) {
  496. jsval jsret;
  497. removeJSTouchObject(this->cx, (CCTouch *) *it, jsret);
  498. }
  499. return 1;
  500. }
  501. int ScriptingCore::executeCustomTouchEvent(int eventType,
  502. CCTouch *pTouch, JSObject *obj) {
  503. jsval retval;
  504. std::string funcName;
  505. getTouchFuncName(eventType, funcName);
  506. jsval jsTouch;
  507. getJSTouchObject(this->cx, pTouch, jsTouch);
  508. executeJSFunctionWithName(this->cx, obj, funcName.c_str(), jsTouch, retval);
  509. return 1;
  510. }
  511. int ScriptingCore::executeCustomTouchEvent(int eventType,
  512. CCTouch *pTouch, JSObject *obj,
  513. jsval &retval) {
  514. std::string funcName;
  515. getTouchFuncName(eventType, funcName);
  516. jsval jsTouch;
  517. getJSTouchObject(this->cx, pTouch, jsTouch);
  518. executeJSFunctionWithName(this->cx, obj, funcName.c_str(), jsTouch, retval);
  519. return 1;
  520. }
  521. long long jsval_to_long_long(JSContext *cx, jsval v) {
  522. JSObject *tmp = JSVAL_TO_OBJECT(v);
  523. if (JS_IsTypedArrayObject(tmp, cx) && JS_GetTypedArrayByteLength(tmp, cx) == 8) {
  524. uint32_t *data = (uint32_t *)JS_GetUint32ArrayData(tmp, cx);
  525. long long r = (long long)(*data);
  526. return r;
  527. }
  528. return 0;
  529. }
  530. std::string jsval_to_std_string(JSContext *cx, jsval v) {
  531. JSString *tmp = JS_ValueToString(cx, v);
  532. char *rawStr = JS_EncodeString(cx, tmp);
  533. std::string ret = std::string(rawStr);
  534. JS_free(cx, rawStr);
  535. return ret;
  536. }
  537. const char* jsval_to_c_string(JSContext *cx, jsval v) {
  538. JSString *tmp = JS_ValueToString(cx, v);
  539. return JS_EncodeString(cx, tmp);
  540. }
  541. CCPoint jsval_to_ccpoint(JSContext *cx, jsval v) {
  542. JSObject *tmp;
  543. jsval jsx, jsy;
  544. double x, y;
  545. JSBool ok = JS_ValueToObject(cx, v, &tmp) &&
  546. JS_GetProperty(cx, tmp, "x", &jsx) &&
  547. JS_GetProperty(cx, tmp, "y", &jsy) &&
  548. JS_ValueToNumber(cx, jsx, &x) &&
  549. JS_ValueToNumber(cx, jsy, &y);
  550. assert(ok == JS_TRUE);
  551. return cocos2d::CCPoint(x, y);
  552. }
  553. CCRect jsval_to_ccrect(JSContext *cx, jsval v) {
  554. JSObject *tmp;
  555. jsval jsx, jsy, jswidth, jsheight;
  556. double x, y, width, height;
  557. JSBool ok = JS_ValueToObject(cx, v, &tmp) &&
  558. JS_GetProperty(cx, tmp, "x", &jsx) &&
  559. JS_GetProperty(cx, tmp, "y", &jsy) &&
  560. JS_GetProperty(cx, tmp, "width", &jswidth) &&
  561. JS_GetProperty(cx, tmp, "height", &jsheight) &&
  562. JS_ValueToNumber(cx, jsx, &x) &&
  563. JS_ValueToNumber(cx, jsy, &y) &&
  564. JS_ValueToNumber(cx, jswidth, &width) &&
  565. JS_ValueToNumber(cx, jsheight, &height);
  566. assert(ok == JS_TRUE);
  567. return cocos2d::CCRect(x, y, width, height);
  568. }
  569. CCSize jsval_to_ccsize(JSContext *cx, jsval v) {
  570. JSObject *tmp;
  571. jsval jsw, jsh;
  572. double w, h;
  573. JSBool ok = JS_ValueToObject(cx, v, &tmp) &&
  574. JS_GetProperty(cx, tmp, "width", &jsw) &&
  575. JS_GetProperty(cx, tmp, "height", &jsh) &&
  576. JS_ValueToNumber(cx, jsw, &w) &&
  577. JS_ValueToNumber(cx, jsh, &h);
  578. assert(ok == JS_TRUE);
  579. return cocos2d::CCSize(w, h);
  580. }
  581. ccGridSize jsval_to_ccgridsize(JSContext *cx, jsval v) {
  582. JSObject *tmp;
  583. jsval jsx, jsy;
  584. double x, y;
  585. JSBool ok = JS_ValueToObject(cx, v, &tmp) &&
  586. JS_GetProperty(cx, tmp, "x", &jsx) &&
  587. JS_GetProperty(cx, tmp, "y", &jsy) &&
  588. JS_ValueToNumber(cx, jsx, &x) &&
  589. JS_ValueToNumber(cx, jsy, &y);
  590. assert(ok == JS_TRUE);
  591. return cocos2d::ccg(x, y);
  592. }
  593. ccColor4B jsval_to_cccolor4b(JSContext *cx, jsval v) {
  594. JSObject *tmp;
  595. jsval jsr, jsg, jsb, jsa;
  596. double r, g, b, a;
  597. JSBool ok = JS_ValueToObject(cx, v, &tmp) &&
  598. JS_GetProperty(cx, tmp, "r", &jsr) &&
  599. JS_GetProperty(cx, tmp, "g", &jsg) &&
  600. JS_GetProperty(cx, tmp, "b", &jsb) &&
  601. JS_GetProperty(cx, tmp, "a", &jsa) &&
  602. JS_ValueToNumber(cx, jsr, &r) &&
  603. JS_ValueToNumber(cx, jsg, &g) &&
  604. JS_ValueToNumber(cx, jsb, &b) &&
  605. JS_ValueToNumber(cx, jsa, &a);
  606. assert(ok == JS_TRUE);
  607. return cocos2d::ccc4(r, g, b, a);
  608. }
  609. ccColor4F jsval_to_cccolor4f(JSContext *cx, jsval v) {
  610. JSObject *tmp;
  611. jsval jsr, jsg, jsb, jsa;
  612. double r, g, b, a;
  613. JSBool ok = JS_ValueToObject(cx, v, &tmp) &&
  614. JS_GetProperty(cx, tmp, "r", &jsr) &&
  615. JS_GetProperty(cx, tmp, "g", &jsg) &&
  616. JS_GetProperty(cx, tmp, "b", &jsb) &&
  617. JS_GetProperty(cx, tmp, "a", &jsa) &&
  618. JS_ValueToNumber(cx, jsr, &r) &&
  619. JS_ValueToNumber(cx, jsg, &g) &&
  620. JS_ValueToNumber(cx, jsb, &b) &&
  621. JS_ValueToNumber(cx, jsa, &a);
  622. assert(ok == JS_TRUE);
  623. return cocos2d::ccc4f(r, g, b, a);
  624. }
  625. ccColor3B jsval_to_cccolor3b(JSContext *cx, jsval v) {
  626. JSObject *tmp;
  627. jsval jsr, jsg, jsb;
  628. double r, g, b;
  629. JSBool ok = JS_ValueToObject(cx, v, &tmp) &&
  630. JS_GetProperty(cx, tmp, "r", &jsr) &&
  631. JS_GetProperty(cx, tmp, "g", &jsg) &&
  632. JS_GetProperty(cx, tmp, "b", &jsb) &&
  633. JS_ValueToNumber(cx, jsr, &r) &&
  634. JS_ValueToNumber(cx, jsg, &g) &&
  635. JS_ValueToNumber(cx, jsb, &b);
  636. assert(ok == JS_TRUE);
  637. return cocos2d::ccc3(r, g, b);
  638. }
  639. CCArray* jsval_to_ccarray(JSContext* cx, jsval v) {
  640. JSObject *arr;
  641. if (JS_ValueToObject(cx, v, &arr) && JS_IsArrayObject(cx, arr)) {
  642. uint32_t len = 0;
  643. JS_GetArrayLength(cx, arr, &len);
  644. CCArray* ret = CCArray::createWithCapacity(len);
  645. for (int i=0; i < len; i++) {
  646. jsval elt;
  647. JSObject *elto;
  648. if (JS_GetElement(cx, arr, i, &elt) && JS_ValueToObject(cx, elt, &elto)) {
  649. js_proxy_t *proxy;
  650. JS_GET_NATIVE_PROXY(proxy, elto);
  651. if (proxy) {
  652. ret->addObject((CCObject *)proxy->ptr);
  653. }
  654. }
  655. }
  656. return ret;
  657. }
  658. return NULL;
  659. }
  660. // from native
  661. jsval long_long_to_jsval(JSContext* cx, long long v) {
  662. JSObject *tmp = JS_NewUint32Array(cx, 2);
  663. uint32_t *data = (uint32_t *)JS_GetArrayBufferViewData(tmp, cx);
  664. data[0] = ((uint32_t *)(&v))[0];
  665. data[1] = ((uint32_t *)(&v))[1];
  666. return OBJECT_TO_JSVAL(tmp);
  667. }
  668. jsval std_string_to_jsval(JSContext* cx, std::string& v) {
  669. JSString *str = JS_NewStringCopyZ(cx, v.c_str());
  670. return STRING_TO_JSVAL(str);
  671. }
  672. jsval c_string_to_jsval(JSContext* cx, const char* v) {
  673. JSString *str = JS_NewStringCopyZ(cx, v);
  674. return STRING_TO_JSVAL(str);
  675. }
  676. jsval ccpoint_to_jsval(JSContext* cx, CCPoint& v) {
  677. JSObject *tmp = JS_NewObject(cx, NULL, NULL, NULL);
  678. if (!tmp) return JSVAL_NULL;
  679. JSBool ok = JS_DefineProperty(cx, tmp, "x", DOUBLE_TO_JSVAL(v.x), NULL, NULL, JSPROP_ENUMERATE | JSPROP_PERMANENT) &&
  680. JS_DefineProperty(cx, tmp, "y", DOUBLE_TO_JSVAL(v.y), NULL, NULL, JSPROP_ENUMERATE | JSPROP_PERMANENT);
  681. if (ok) {
  682. return OBJECT_TO_JSVAL(tmp);
  683. }
  684. return JSVAL_NULL;
  685. }
  686. jsval ccrect_to_jsval(JSContext* cx, CCRect& v) {
  687. JSObject *tmp = JS_NewObject(cx, NULL, NULL, NULL);
  688. if (!tmp) return JSVAL_NULL;
  689. JSBool ok = JS_DefineProperty(cx, tmp, "x", DOUBLE_TO_JSVAL(v.origin.x), NULL, NULL, JSPROP_ENUMERATE | JSPROP_PERMANENT) &&
  690. JS_DefineProperty(cx, tmp, "y", DOUBLE_TO_JSVAL(v.origin.y), NULL, NULL, JSPROP_ENUMERATE | JSPROP_PERMANENT) &&
  691. JS_DefineProperty(cx, tmp, "width", DOUBLE_TO_JSVAL(v.size.width), NULL, NULL, JSPROP_ENUMERATE | JSPROP_PERMANENT) &&
  692. JS_DefineProperty(cx, tmp, "height", DOUBLE_TO_JSVAL(v.size.height), NULL, NULL, JSPROP_ENUMERATE | JSPROP_PERMANENT);
  693. if (ok) {
  694. return OBJECT_TO_JSVAL(tmp);
  695. }
  696. return JSVAL_NULL;
  697. }
  698. jsval ccsize_to_jsval(JSContext* cx, CCSize& v) {
  699. JSObject *tmp = JS_NewObject(cx, NULL, NULL, NULL);
  700. if (!tmp) return JSVAL_NULL;
  701. JSBool ok = JS_DefineProperty(cx, tmp, "width", DOUBLE_TO_JSVAL(v.width), NULL, NULL, JSPROP_ENUMERATE | JSPROP_PERMANENT) &&
  702. JS_DefineProperty(cx, tmp, "height", DOUBLE_TO_JSVAL(v.height), NULL, NULL, JSPROP_ENUMERATE | JSPROP_PERMANENT);
  703. if (ok) {
  704. return OBJECT_TO_JSVAL(tmp);
  705. }
  706. return JSVAL_NULL;
  707. }
  708. jsval ccgridsize_to_jsval(JSContext* cx, ccGridSize& v) {
  709. JSObject *tmp = JS_NewObject(cx, NULL, NULL, NULL);
  710. if (!tmp) return JSVAL_NULL;
  711. JSBool ok = JS_DefineProperty(cx, tmp, "x", DOUBLE_TO_JSVAL(v.x), NULL, NULL, JSPROP_ENUMERATE | JSPROP_PERMANENT) &&
  712. JS_DefineProperty(cx, tmp, "y", DOUBLE_TO_JSVAL(v.y), NULL, NULL, JSPROP_ENUMERATE | JSPROP_PERMANENT);
  713. if (ok) {
  714. return OBJECT_TO_JSVAL(tmp);
  715. }
  716. return JSVAL_NULL;
  717. }
  718. jsval cccolor4b_to_jsval(JSContext* cx, ccColor4B& v) {
  719. JSObject *tmp = JS_NewObject(cx, NULL, NULL, NULL);
  720. if (!tmp) return JSVAL_NULL;
  721. JSBool ok = JS_DefineProperty(cx, tmp, "r", INT_TO_JSVAL(v.r), NULL, NULL, JSPROP_ENUMERATE | JSPROP_PERMANENT) &&
  722. JS_DefineProperty(cx, tmp, "g", INT_TO_JSVAL(v.g), NULL, NULL, JSPROP_ENUMERATE | JSPROP_PERMANENT) &&
  723. JS_DefineProperty(cx, tmp, "b", INT_TO_JSVAL(v.g), NULL, NULL, JSPROP_ENUMERATE | JSPROP_PERMANENT) &&
  724. JS_DefineProperty(cx, tmp, "a", INT_TO_JSVAL(v.g), NULL, NULL, JSPROP_ENUMERATE | JSPROP_PERMANENT);
  725. if (ok) {
  726. return OBJECT_TO_JSVAL(tmp);
  727. }
  728. return JSVAL_NULL;
  729. }
  730. jsval cccolor4f_to_jsval(JSContext* cx, ccColor4F& v) {
  731. JSObject *tmp = JS_NewObject(cx, NULL, NULL, NULL);
  732. if (!tmp) return JSVAL_NULL;
  733. JSBool ok = JS_DefineProperty(cx, tmp, "r", DOUBLE_TO_JSVAL(v.r), NULL, NULL, JSPROP_ENUMERATE | JSPROP_PERMANENT) &&
  734. JS_DefineProperty(cx, tmp, "g", DOUBLE_TO_JSVAL(v.g), NULL, NULL, JSPROP_ENUMERATE | JSPROP_PERMANENT) &&
  735. JS_DefineProperty(cx, tmp, "b", DOUBLE_TO_JSVAL(v.g), NULL, NULL, JSPROP_ENUMERATE | JSPROP_PERMANENT) &&
  736. JS_DefineProperty(cx, tmp, "a", DOUBLE_TO_JSVAL(v.g), NULL, NULL, JSPROP_ENUMERATE | JSPROP_PERMANENT);
  737. if (ok) {
  738. return OBJECT_TO_JSVAL(tmp);
  739. }
  740. return JSVAL_NULL;
  741. }
  742. jsval cccolor3b_to_jsval(JSContext* cx, ccColor3B& v) {
  743. JSObject *tmp = JS_NewObject(cx, NULL, NULL, NULL);
  744. if (!tmp) return JSVAL_NULL;
  745. JSBool ok = JS_DefineProperty(cx, tmp, "r", INT_TO_JSVAL(v.r), NULL, NULL, JSPROP_ENUMERATE | JSPROP_PERMANENT) &&
  746. JS_DefineProperty(cx, tmp, "g", INT_TO_JSVAL(v.g), NULL, NULL, JSPROP_ENUMERATE | JSPROP_PERMANENT) &&
  747. JS_DefineProperty(cx, tmp, "b", INT_TO_JSVAL(v.g), NULL, NULL, JSPROP_ENUMERATE | JSPROP_PERMANENT);
  748. if (ok) {
  749. return OBJECT_TO_JSVAL(tmp);
  750. }
  751. return JSVAL_NULL;
  752. }