5

首先介绍一下我在使用 Firebreath 所做的事情的背景。

  1. 我正在使用 firebreath 在浏览器中开发渲染查看器插​​件。
  2. 我在插件中定义了两种 MIME 类型,一种用于主查看器,另一种用于 2D 平面视图。
  3. 在每个页面中,只允许一个主查看器,但可以有多个 2D 平面视图。它们都共享在主查看器中打开的同一个模型文档。
  4. 因此,在实例化 2D 平面视图之后,我需要将文档对象(一个 firebreath JSAPI)传递给 2D 平面视图。

然后,假设主查看器和平面视图都被加载,命名为“mainviewer”和“planview”,我会将文档附加到平面查看器,如下所示,

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

ISSUE是在firefox中,通过调用无法将传递的JSObject识别为JSAPI

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

仅当主机浏览器为 firefox,IE/Chrome 运行良好时才会出现此问题。

那么,在使用 firefox 时,传递过来的 JSAPI 发生了什么?

4

1 回答 1

4

事实证明,大多数浏览器(包括 FireFox)在将 NPObjects 传递给另一个函数调用之前都会对其进行包装。因此,您无法访问最初传递给浏览器的底层 C++ 类。因为 FireBreath 无法获取真正的 NPJavascriptObject(FireBreath 用来包装 JSAPI 对象以提供给浏览器的 NPObject),它也无法获取原始 JSAPI 对象。

考虑为 JSAPI 对象的每个实例创建一个静态 ID。然后,您可以将 instance_id 公开为 JSAPI 属性,然后创建一个全局 std::map ,您可以使用它来存储地图以获取您的对象。

// 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();
}

如果您从不浏览地图并清除过期的弱ptr,这当然最终会泄漏少量内存,但它应该可以满足您的需求。当你得到一个应该是 JSAPIPtr 对象的对象时,你可以期望它是一个 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
        }
    }
}

我没有测试上面的代码,但它应该非常接近。

于 2013-03-08T05:53:34.767 回答