A firebreath JSAPI will not be recognized in firefox

主宰稳场 提交于 2019-12-05 00:47:41

问题


First goes some background about what I am doing with Firebreath.

  1. I am developing a rendering viewer plugin in browser by using firebreath.
  2. I define two MIME type in my plugin, one is for the main viewer, and the other is for 2D plan view.
  3. In each page, only one main viewer is allowed, but can have multiple 2D plan view. And they all share the same model document opened in main viewer.
  4. So, after instantiating 2D plan view, I need to pass the document object (a firebreath JSAPI) to the 2d plan view.

Then, assume the main viewer and plan view are both loaded named as 'mainviewer' and 'planview', and I will attch the document to plan viewer as below,

planview.attach(mainviewer.doc); 
(the signature is "bool attach(const FB::JSObjectPtr& myDoc)" and 
The mainviewer.doc is just a firebreath JSAPI)

The ISSUE is that in firefox, the passed JSObject can't be recognized as a JSAPI by calling

FB::JSAPIPtr jsAPI = myDoc->getJSAPI(); // THIS WILL RETURN **NULL**.
m_main_doc = FB::ptr_cast<LcFbViewerDocumentAPI>(jsAPI); // Cast to my document API.

This issue only happens when the host browser is firefox, IE/Chrome works well.

So, what happened to the passed JSAPI when using firefox?


回答1:


As it turns out, most browsers (including FireFox) wrap NPObjects before letting them be passed into another function call; because of this, you can't get at the underlying C++ class that you originally passed to the browser. Because FireBreath can't get to the real NPJavascriptObject (the NPObject that FireBreath uses to wrap JSAPI objects to give to the browser) it can't get to the original JSAPI object either.

Consider creating a static id for each instance of your JSAPI object. You can then expose the instance_id as a JSAPI property and then create a global std::map that you can use to store a map to get at your object.

// in the class def
static int counter;
int instance_id;

// In the .cpp file
int MyPluginAPI::counter(0);

std::map<int, FB::JSAPIWeakPtr> apiMap;
FB::JSAPIPtr getJSAPIObjectById(int id) {
    std::map<int, FB::JSAPIWeakPtr> fnd = apiMap.find(id);
    if (fnd != apiMap.end()) {
        return fnd.second->lock(); // it's a weak pointer, lock to get the shared_ptr
    } else {
        return FB::JSAPIPtr(); // Alternately throw an exception
    }
}

MyPluginAPI::MyPluginAPI() {
    instance_id = counter++;
    // Note that you can't get at the shared_ptr in the constructor,
    // so you'll have to call an init function after creating the JSAPI object

    registerProperty("instance_id",
                 make_property(this,
                    &FBTestPluginAPI::get_instId));
}

int MyPluginAPI::get_instId() { return instance_id; }

void MyPluginAPI::init() {
    apiMap[instance_id] = shared_from_this();
}

This would of course eventually leak a small amount of memory if you don't ever go through the map and clear out expired weak ptrs, but it should give you what you need. When you get an object that should be a JSAPIPtr object you can expect it as a JSObjectPtr.

void doSomethingWithAnAPI(const FB::JSObjectPtr& obj) {
    if (obj) {
        int id = obj->GetProperty("instance_id");
        FB::JSAPIPtr ptr = getJSAPIObjectById(id);
        if (ptr) {
            // Hurray! We have the object
        }
    }
}

I haven't tested the above code, but it should be pretty close.



来源:https://stackoverflow.com/questions/15286464/a-firebreath-jsapi-will-not-be-recognized-in-firefox

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!