5

最初に、私が Firebreath で何をしているかについての背景を説明します。

  1. firebreath を使用してブラウザでレンダリング ビューアー プラグインを開発しています。
  2. プラグインで 2 つの MIME タイプを定義します。1 つはメイン ビューア用で、もう 1 つは 2D 平面図用です。
  3. 各ページでは、1 つのメイン ビューアーのみが許可されますが、複数の 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)

問題は、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を含む)は、NPObjectをラップしてから、別の関数呼び出しに渡させます。このため、最初にブラウザに渡した基になる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 に答える