First goes some background about what I am doing with Firebreath.
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?
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With