SpiderMonkeyの学習

20838 ワード

ルール:
js論理コードで使用されるjsvalタイプの計算結果と渡される行パラメータは、RootedValueタイプ、RootedObject、JSSString、Numberまたはその他のタイプの値がRootedValueタイプの変数に保存されます.
jsonはRootedObjectタイプ配列でもRootedObjectタイプ用JS_IsArrayObjectは配列配列配列長がJS_を通過するか否かを判定するGetArrayLength取得要素JS_を介してGetElement取得
js to c++ value.isNumber(),JS::ToNumber() isObject(),JS_ValueToObject() v.isString();      JSString *tmp =JS::ToString(cx, v);      JSStringWrapper str(tmp);      *ret = str.get(); jsonタイプ値を読み込みます.
bool jsval_to_vector2(JSContext *cx, JS::HandleValue vp/*  js    ,        js       js  */, cocos2d::Vec2* ret/*  */)
{
    //  js  
    JS::RootedObject tmp(cx);
    //  js  
    JS::RootedValue jsx(cx);
    JS::RootedValue jsy(cx);
    double x, y;
    bool ok = vp.isObject() &&//vp       
    JS_ValueToObject(cx, vp, &tmp) &&//vp    
    JS_GetProperty(cx, tmp, "x", &jsx) &&//  json     js   
    JS_GetProperty(cx, tmp, "y", &jsy) &&
    JS::ToNumber(cx, jsx, &x) &&//js   C++  
    JS::ToNumber(cx, jsy, &y);
    
    JSB_PRECONDITION3(ok, cx, false, "Error processing arguments");
    
    ret->x = (float)x;//  
    ret->y = (float)y;
    return true;
}
js配列を読み込みます.
bool jsval_to_std_vector_int( JSContext *cx, JS::HandleValue vp, std::vector<int>* ret)
{
    //  js   
    JS::RootedObject jsobj(cx);
    //                         RootedValue,  RootedObject, JSString, Number            RootedValue 
    bool ok = vp.isObject() && JS_ValueToObject( cx, vp, &jsobj );
    JSB_PRECONDITION3( ok, cx, false, "Error converting value to object");
    JSB_PRECONDITION3( jsobj && JS_IsArrayObject( cx, jsobj),  cx, false, "Object must be an array");
    
    uint32_t len = 0;
    //         
    JS_GetArrayLength(cx, jsobj, &len);
    
    for (uint32_t i=0; i < len; i++)
    {
        //  js    
        JS::RootedValue value(cx);
        if (JS_GetElement(cx, jsobj, i, &value))
        {
            if (value.isNumber())
            {
                double number = 0.0;
                //   
                ok = JS::ToNumber(cx, value, &number);
                if (ok)
                {
                    ret->push_back(static_cast<int>(number));
                }
            }
            else
            {
                JS_ReportError(cx, "not supported type in array");
                return false;
            }
        }
    }
    
    return true;
}

c++to js obj JS_NewObject     JS_DefineProperty    OBJECT_TO_JSVAL Array JS_NewArrayObject     JS_SetElement    OBJECT_TO_JSVAL int32_to_jsval std_string_to_jsvalはjsonタイプ値を作成します.
jsval vector2_to_jsval(JSContext *cx, const cocos2d::Vec2& v)
{
    //    js  
    JS::RootedObject proto(cx);
    JS::RootedObject parent(cx);
    JS::RootedObject tmp(cx, JS_NewObject(cx, NULL, proto, parent));
    if (!tmp) return JSVAL_NULL;
    //       x y
    bool ok = JS_DefineProperty(cx, tmp, "x", v.x, JSPROP_ENUMERATE | JSPROP_PERMANENT) &&
    JS_DefineProperty(cx, tmp, "y", v.y, JSPROP_ENUMERATE | JSPROP_PERMANENT);
    if (ok) {
        //    jsval 
        return OBJECT_TO_JSVAL(tmp);
    }
    return JSVAL_NULL;
}

js配列を作成する
jsval std_vector_int_to_jsval( JSContext *cx, const std::vector<int>& v)
{
    JS::RootedObject jsretArr(cx, JS_NewArrayObject(cx, 0));
    
    int i = 0;
    for (const int obj : v)
    {
        JS::RootedValue arrElement(cx);
        arrElement = int32_to_jsval(cx, obj);
        
        if (!JS_SetElement(cx, jsretArr, i, arrElement)) {
            break;
        }
        ++i;
    }
    return OBJECT_TO_JSVAL(jsretArr);
}

グローバル関数c++変調js js変調c++
//
//  jsb_kenko_auto.h
//  Fishing2d36JSB
//
//  Created by TinyUlt on 11/16/15.
//
//

#ifndef jsb_jsb_kenko_auto_h
#define jsb_jsb_kenko_auto_h

#include "cocos2d.h"
#include "jsapi.h"
#include "jsfriendapi.h"

std::string os_info();
bool jsb_os_info(JSContext *cx, uint32_t argc, JS::Value *vp);
bool jsb_callback(JSContext *cx, uint32_t argc, JS::Value *vp);
void register_jsb_kenko_all(JSContext* cx, JS::HandleObject obj);

#endif
//
//  jsb_kenko_auto.cpp
//  Fishing2d36JSB
//
//  Created by TinyUlt on 11/16/15.
//
//

#include "jsb_kenko_auto.h"
#include "cocos2d_specifics.hpp"

std::string os_info() {
    CCLOG("it's c++ os_info here");
    return "os_info";
}


bool jsb_os_info(JSContext *cx, uint32_t argc, JS::Value *vp) {
    JS::CallArgs args = JS::CallArgsFromVp(argc, vp);

    if (argc == 0) {
        std::string ret = os_info();
        jsval jsret = JSVAL_NULL;
        jsret = std_string_to_jsval(cx, ret);
        args.rval().set(jsret);
        return true;
    }
    
    JS_ReportError(cx, "js_FishAlg_FishAlg_getOutRotation3D : wrong number of arguments: %d, was expecting %d", argc, 0);
    return false;
}
bool jsb_callback(JSContext *cx, uint32_t argc, JS::Value *vp) {
    CCLOG("it's c++ testCallback here");
    JSContext* jc = ScriptingCore::getInstance()->getGlobalContext();
    //              
    //   :http://www.tairan.com/archives/4902
    //jsval v[2];
    //v[0] = int32_to_jsval(jc, 32);
    //v[1] = int32_to_jsval(jc, 12);
    
    //    ScriptingCore           ,                
    //js_proxy_t * p = jsb_get_native_proxy();
    //return ScriptingCore::getInstance()->executeFunctionWithOwner(OBJECT_TO_JSVAL(p->obj), "cpp_callback", 2, v);        //2     ,v     
    
    //              
    jsval ret;
    return ScriptingCore::getInstance()->evalString("cpp_callback(2,3)", &ret);
}
void register_jsb_kenko_all(JSContext *cx, JS::HandleObject obj) {
    JS_DefineFunction(cx, obj, "os_Info", jsb_os_info, 0, 0);  //    osInfo js    
    JS_DefineFunction(cx, obj, "test_cpp_callback", jsb_callback, 0, 0);
//     JS_DefineFunction(cx, tmpObj, "getInstance", js_PlistParser_getInstance, 0, JSPROP_READONLY | JSPROP_PERMANENT);
}
function cpp_callback(a, b) {
    cc.log("cpp return two integer: " + a + " " + b);
}
cc.log("js get from c++: " + os_Info());
        test_cpp_callback();

c++クラスのコールバック関数
//
//  Network.h
//  cocos2d_libs
//
//  Created by TinyUlt on 11/16/15.
//
//

#ifndef __cocos2d_libs__Network__
#define __cocos2d_libs__Network__

#include <stdio.h>
class Network{
public:
    Network();
    ~Network();
    bool OnMessage();
};
#endif /* defined(__cocos2d_libs__Network__) */
//
//  Network.cpp
//  cocos2d_libs
//
//  Created by TinyUlt on 11/16/15.
//
//

#include "Network.h"
#include "cocos2d.h"
#include "jsapi.h"
#include "jsfriendapi.h"
#include "cocos2d_specifics.hpp"
Network::Network(){
    
}
Network::~Network(){
    
}
bool Network::OnMessage(){
    js_proxy_t * p = jsb_get_native_proxy(this);
    jsval retval;
    JSContext* jc = ScriptingCore::getInstance()->getGlobalContext();
    //      ,     
    jsval v[] = {
        v[0] = int32_to_jsval(jc, 32),
        v[1] =UINT_TO_JSVAL(88)
    };
    //    ScriptingCore           ,                
    ScriptingCore::getInstance()->executeFunctionWithOwner(OBJECT_TO_JSVAL(p->obj), "callback", 2, v);
    return true;
}
 network.callback = function (i, j) {
            log("network.callback " + i + j);
        }
        network.OnMessage();

js関数はc++に渡され、関数コールバックに使用されます.
//
//  jsb_JS_APP_CB.hpp
//  cocos2d_js_bindings
//
//  Created by TinyUlt on 1/9/16.
//
//

#ifndef jsb_JS_APP_CB_hpp
#define jsb_JS_APP_CB_hpp

#include "jsapi.h"
#include "jsfriendapi.h"

void register_all_js_cpp_cb(JSContext* cx, JS::HandleObject global);

#endif /* jsb_JS_APP_CB_hpp */
//
//  jsb_JS_APP_CB.cpp
//  cocos2d_js_bindings
//
//  Created by TinyUlt on 1/9/16.
//
//

#include "jsb_JS_APP_CB.hpp"
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID || CC_TARGET_PLATFORM == CC_PLATFORM_IOS || CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)

#include "ScriptingCore.h"
#include "cocos2d_specifics.hpp"

#include "jsb_TinyJSWork.hpp"
#include "TinyJSWork.h"
using namespace cocos2d;


static bool jsb_applyStorePay(JSContext *cx, uint32_t argc, jsval *vp)
{
    JSObject *obj = JS_THIS_OBJECT(cx, vp);
    js_proxy_t *proxy = jsb_get_js_proxy(obj);
    TinyJSWork* cobj = (TinyJSWork *)(proxy ? proxy->ptr : NULL);
    JSB_PRECONDITION2( cobj, cx, false, "Invalid Native Object");
    
    if(true){
        JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
        
        int _type;
        jsval_to_int32(cx, args.get(0),  &_type);

        int _proID;
        jsval_to_int32(cx, args.get(1),  &_proID);

        int _gameID;
        jsval_to_int32(cx, args.get(2),  &_gameID);
        
        std::shared_ptr<JSFunctionWrapper> func(new JSFunctionWrapper(cx, obj, args.get(3)));
        
        cobj->applyStorePay((PurchasePlatform)_type, (ProductID)_proID, _gameID,[=](int purType, int proID, int gameID,bool paySuc)->bool{
            Director::getInstance()->getScheduler()->performFunctionInCocosThread([=] {
                JSB_AUTOCOMPARTMENT_WITH_GLOBAL_OBJCET
                jsval arg[4];
                
                arg[0] = int32_to_jsval(cx, purType);
                arg[1] = int32_to_jsval(cx, proID);
                arg[2] = int32_to_jsval(cx, gameID);
                arg[3] = bool_to_jsval(cx, paySuc);
                JS::RootedValue rval(cx);
                
                CCLOG("  js   applyStorePay        ");
                bool ok = func->invoke(4, arg, &rval);
                if (!ok && JS_IsExceptionPending(cx)) {
                    JS_ReportPendingException(cx);
                }
            });
            return true;
        });
        return true;
    }
}

extern JSObject* jsb_TinyJSWork_prototype;

void register_all_js_cpp_cb(JSContext* cx, JS::HandleObject global)
{
    JS_DefineFunction(cx, JS::RootedObject(cx, jsb_TinyJSWork_prototype), "applyStorePay", jsb_applyStorePay, 4, JSPROP_ENUMERATE | JSPROP_PERMANENT);
}

#endif
typedef void TinyJSStoreCallback(int purType, int proID, int gameID,bool paySuc);
    //    
    void applyStorePay(PurchasePlatform type, ProductID proID,int gameID, std::function<TinyJSStoreCallback> jsCallback);

テスト1
void SwimAlg::test1(){
    
}
bool js_SwimAlg_SwimAlg_test1(JSContext *cx, uint32_t argc/*    */, jsval *vp)
{
    //      
    JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
    //js     c++  
    JS::RootedObject obj(cx, args.thisv().toObjectOrNull());
    js_proxy_t *proxy = jsb_get_js_proxy(obj);
    SwimAlg* cobj = (SwimAlg *)(proxy ? proxy->ptr : NULL);
    //      ,   
    JSB_PRECONDITION2( cobj, cx, false, "js_SwimAlg_SwimAlg_test1 : Invalid Native Object");
    ///
    //       0
    if (argc == 0) {
    //  c++  
        cobj->test1();
        //           
        args.rval().setUndefined();
        return true;
    }
    //          0    
    JS_ReportError(cx, "js_SwimAlg_SwimAlg_test1 : wrong number of arguments: %d, was expecting %d", argc, 0);
    return false;
}

テスト2
void SwimAlg::test2(int i){
    
}
bool js_SwimAlg_SwimAlg_test2(JSContext *cx, uint32_t argc, jsval *vp)
{
    JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
    bool ok = true;
    JS::RootedObject obj(cx, args.thisv().toObjectOrNull());
    js_proxy_t *proxy = jsb_get_js_proxy(obj);
    SwimAlg* cobj = (SwimAlg *)(proxy ? proxy->ptr : NULL);
    JSB_PRECONDITION2( cobj, cx, false, "js_SwimAlg_SwimAlg_test2 : Invalid Native Object");
    //     1 
    if (argc == 1) {
        int arg0;
        //js    c++  
        ok &= jsval_to_int32(cx, args.get(0), (int32_t *)&arg0);
        JSB_PRECONDITION2(ok, cx, false, "js_SwimAlg_SwimAlg_test2 : Error processing arguments");
        //    
        cobj->test2(arg0);
        args.rval().setUndefined();
        return true;
    }

    JS_ReportError(cx, "js_SwimAlg_SwimAlg_test2 : wrong number of arguments: %d, was expecting %d", argc, 1);
    return false;
}

テスト3
void SwimAlg::test3(int i, float f){
    
}
bool js_SwimAlg_SwimAlg_test3(JSContext *cx, uint32_t argc, jsval *vp)
{
    JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
    bool ok = true;
    JS::RootedObject obj(cx, args.thisv().toObjectOrNull());
    js_proxy_t *proxy = jsb_get_js_proxy(obj);
    SwimAlg* cobj = (SwimAlg *)(proxy ? proxy->ptr : NULL);
    JSB_PRECONDITION2( cobj, cx, false, "js_SwimAlg_SwimAlg_test3 : Invalid Native Object");
    //     2 
    if (argc == 2) {
        int arg0;
        double arg1;
        ok &= jsval_to_int32(cx, args.get(0), (int32_t *)&arg0);
        //js     c++   
        ok &= JS::ToNumber( cx, args.get(1), &arg1) && !isnan(arg1);
        JSB_PRECONDITION2(ok, cx, false, "js_SwimAlg_SwimAlg_test3 : Error processing arguments");
        cobj->test3(arg0, arg1);
        args.rval().setUndefined();
        return true;
    }

    JS_ReportError(cx, "js_SwimAlg_SwimAlg_test3 : wrong number of arguments: %d, was expecting %d", argc, 2);
    return false;
}

テスト4
void SwimAlg::test4(double d, Vec2 v){
    
}
bool js_SwimAlg_SwimAlg_test4(JSContext *cx, uint32_t argc, jsval *vp)
{
    JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
    bool ok = true;
    JS::RootedObject obj(cx, args.thisv().toObjectOrNull());
    js_proxy_t *proxy = jsb_get_js_proxy(obj);
    SwimAlg* cobj = (SwimAlg *)(proxy ? proxy->ptr : NULL);
    JSB_PRECONDITION2( cobj, cx, false, "js_SwimAlg_SwimAlg_test4 : Invalid Native Object");
    if (argc == 2) {
        double arg0;
        cocos2d::Vec2 arg1;
        ok &= JS::ToNumber( cx, args.get(0), &arg0) && !isnan(arg0);
        //js cc.p()    c++ Vec2()   
        ok &= jsval_to_vector2(cx, args.get(1), &arg1);
        JSB_PRECONDITION2(ok, cx, false, "js_SwimAlg_SwimAlg_test4 : Error processing arguments");
        cobj->test4(arg0, arg1);
        args.rval().setUndefined();
        return true;
    }

    JS_ReportError(cx, "js_SwimAlg_SwimAlg_test4 : wrong number of arguments: %d, was expecting %d", argc, 2);
    return false;
}
bool jsval_to_vector2(JSContext *cx, JS::HandleValue vp/*  js    ,        js       js  */, cocos2d::Vec2* ret/*  */)
{
    //  js  
    JS::RootedObject tmp(cx);
    //  js  
    JS::RootedValue jsx(cx);
    JS::RootedValue jsy(cx);
    double x, y;
    bool ok = vp.isObject() &&//vp       
    JS_ValueToObject(cx, vp, &tmp) &&//vp    
    JS_GetProperty(cx, tmp, "x", &jsx) &&//  json     js   
    JS_GetProperty(cx, tmp, "y", &jsy) &&
    JS::ToNumber(cx, jsx, &x) &&//js   C++  
    JS::ToNumber(cx, jsy, &y);
    
    JSB_PRECONDITION3(ok, cx, false, "Error processing arguments");
    
    ret->x = (float)x;//  
    ret->y = (float)y;
    return true;
}

テスト5
int SwimAlg::test5(){
    return 0;
}
bool js_SwimAlg_SwimAlg_test5(JSContext *cx, uint32_t argc, jsval *vp)
{
    JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
    JS::RootedObject obj(cx, args.thisv().toObjectOrNull());
    js_proxy_t *proxy = jsb_get_js_proxy(obj);
    SwimAlg* cobj = (SwimAlg *)(proxy ? proxy->ptr : NULL);
    JSB_PRECONDITION2( cobj, cx, false, "js_SwimAlg_SwimAlg_test5 : Invalid Native Object");
    if (argc == 0) {
        //     
        int ret = cobj->test5();
        //c++   js  
        jsval jsret = JSVAL_NULL;
        jsret = int32_to_jsval(cx, ret);
        //     
        args.rval().set(jsret);
        return true;
    }

    JS_ReportError(cx, "js_SwimAlg_SwimAlg_test5 : wrong number of arguments: %d, was expecting %d", argc, 0);
    return false;
}

テスト6
Vec2 SwimAlg::test6(){
    return Vec2::ZERO;
}
bool js_SwimAlg_SwimAlg_test6(JSContext *cx, uint32_t argc, jsval *vp)
{
    JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
    JS::RootedObject obj(cx, args.thisv().toObjectOrNull());
    js_proxy_t *proxy = jsb_get_js_proxy(obj);
    SwimAlg* cobj = (SwimAlg *)(proxy ? proxy->ptr : NULL);
    JSB_PRECONDITION2( cobj, cx, false, "js_SwimAlg_SwimAlg_test6 : Invalid Native Object");
    if (argc == 0) {
        cocos2d::Vec2 ret = cobj->test6();
        jsval jsret = JSVAL_NULL;
        //Vec2 cc.p();
        jsret = vector2_to_jsval(cx, ret);
        //     
        args.rval().set(jsret);
        return true;
    }

    JS_ReportError(cx, "js_SwimAlg_SwimAlg_test6 : wrong number of arguments: %d, was expecting %d", argc, 0);
    return false;
}
jsval vector2_to_jsval(JSContext *cx, const cocos2d::Vec2& v)
{
    //    js  
    JS::RootedObject proto(cx);
    JS::RootedObject parent(cx);
    JS::RootedObject tmp(cx, JS_NewObject(cx, NULL, proto, parent));
    if (!tmp) return JSVAL_NULL;
    //       x y
    bool ok = JS_DefineProperty(cx, tmp, "x", v.x, JSPROP_ENUMERATE | JSPROP_PERMANENT) &&
    JS_DefineProperty(cx, tmp, "y", v.y, JSPROP_ENUMERATE | JSPROP_PERMANENT);
    if (ok) {
        //    jsval 
        return OBJECT_TO_JSVAL(tmp);
    }
    return JSVAL_NULL;
}

テスト7
void SwimAlg::test7(std::vector<int> v){
    
}
bool jsval_to_std_vector_int( JSContext *cx, JS::HandleValue vp, std::vector<int>* ret)
{
    //  js   
    JS::RootedObject jsobj(cx);
    //                         RootedValue,  RootedObject, JSString, Number            RootedValue 
    bool ok = vp.isObject() && JS_ValueToObject( cx, vp, &jsobj );
    JSB_PRECONDITION3( ok, cx, false, "Error converting value to object");
    JSB_PRECONDITION3( jsobj && JS_IsArrayObject( cx, jsobj),  cx, false, "Object must be an array");
    
    uint32_t len = 0;
    //         
    JS_GetArrayLength(cx, jsobj, &len);
    
    for (uint32_t i=0; i < len; i++)
    {
        //  js    
        JS::RootedValue value(cx);
        if (JS_GetElement(cx, jsobj, i, &value))
        {
            if (value.isNumber())
            {
                double number = 0.0;
                //   
                ok = JS::ToNumber(cx, value, &number);
                if (ok)
                {
                    ret->push_back(static_cast<int>(number));
                }
            }
            else
            {
                JS_ReportError(cx, "not supported type in array");
                return false;
            }
        }
    }
    
    return true;
}

テスト8
void SwimAlg::test8(std::vector<Vec2> v){
    
}
bool js_SwimAlg_SwimAlg_test8(JSContext *cx, uint32_t argc, jsval *vp)
{
    JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
    bool ok = true;
    JS::RootedObject obj(cx, args.thisv().toObjectOrNull());
    js_proxy_t *proxy = jsb_get_js_proxy(obj);
    SwimAlg* cobj = (SwimAlg *)(proxy ? proxy->ptr : NULL);
    JSB_PRECONDITION2( cobj, cx, false, "js_SwimAlg_SwimAlg_test8 : Invalid Native Object");
    if (argc == 1) {
        std::vector<cocos2d::Vec2> arg0;
        ok &= jsval_to_std_vector_ccvec2(cx, args.get(0), &arg0);
        JSB_PRECONDITION2(ok, cx, false, "js_SwimAlg_SwimAlg_test8 : Error processing arguments");
        cobj->test8(arg0);
        args.rval().setUndefined();
        return true;
    }

    JS_ReportError(cx, "js_SwimAlg_SwimAlg_test8 : wrong number of arguments: %d, was expecting %d", argc, 1);
    return false;
}