Chrome Extension開発を勉強してみる (7) - NPAPI -

2012-07-13T00:00:00+09:00 C++ Chrome Extension JavaScript NPAPI Python

nixysaを使ってNPAPIのC++なコードを拡張で使えるようにしてみる

準備

http://code.google.com/p/nixysa っていうのを使うとNPAPIによるプラグイン開発が非常に楽になるので、これをチェックアウトしておく。んでとりあえずどっかに置いとく(今回は/opt内に配置)

hoge.h

#ifndef HOGE_H
#define HOGE_H

#include <string>

class Hoge {
    public:
        Hoge() {}
        std::string say();
};

#endif

hoge.cc

#include <string>
#include "hoge.h"

std::string Hoge::say() {
    std::string s;
    s = "hoge";

    return s;
}

な感じで。まぁとりあえず適当に文字列を返すだけのメソッド定義するだけにしときます

hoge.idl

[binding_model=by_value, include="hoge.h"]
class Hoge {
    Hoge();
    std::string say();
};

IDLファイルとか久々に見たので書き方こんなだっけ的なのを忘れてるのですが(ry どうでも良いのでさっと

plugin.cc

#include <npapi.h>

extern "C" {
    const char *NP_GetMIMEDescription(void) {
        return "application/x-hoge::Hoge Plugin";
    }

    NPError NP_GetValue(NPP instance, NPPVariable variable, void *value) {
        switch (variable) {
            case NPPVpluginNameString:
                *static_cast<const char **>(value) = "x-hoge";
                break;

            case NPPVpluginDescriptionString:
                *static_cast<const char **>(value) = "Hoge Plugin";
                break;

            default:
                return NPERR_INVALID_PARAM;

                break;
        }

        return NPERR_NO_ERROR;
    }
}

ただプラグイン名とかの情報を定義するだけなようで。でこれで下準備完了。これにより少なくても拡張機能でNPAPIを使うのであれば、4つくらいはファイル必要になるような感じっぽい。でビルドしないといけないのですが、それをやるのにsconsを使います

SConstruct

import os
import sys

IDL_SOURCES=["hoge.idl"]
SOURCES=["hoge.cc", "plugin.cc"]
STATIC_GLUE_SOURCES=["common.cc", "npn_api.cc", "static_object.cc", "main.cc"]

env = Environment(
    ROOT = "/opt/nixysa",
    NIXYSA_DIR = "$ROOT/nixysa",
    STATIC_GLUE_DIR = "$NIXYSA_DIR/static_glue/npapi",
    NPAPI_DIR = "$ROOT/third_party/npapi/include",
    GLUE_DIR = "glue",
    CPPPATH=[".", "$STATIC_GLUE_DIR", "$NPAPI_DIR", "$GLUE_DIR"]
)
env.Append(ENV={"PYTHON": sys.executable})
if sys.platform == "win32":
  env.Append(CODEGEN = "codegen.bat",
             CPPDEFINES = ["WIN32", "OS_WINDOWS"])
else:
  env.Append(CODEGEN = "codegen.sh",
             CPPDEFINES = ["OS_LINUX"])

def NixysaEmitter(target, source, env):
  bases = [os.path.splitext(s.name)[0] for s in source] + ["globals"]
  targets = ["$GLUE_DIR/%s_glue.cc" % b for b in bases]
  targets += ["$GLUE_DIR/%s_glue.h" % b for b in bases]
  targets += ["$GLUE_DIR/hash", "$GLUE_DIR/parsetab.py"]
  return targets, source

NIXYSA_CMDLINE = " ".join([env.File("$NIXYSA_DIR/$CODEGEN").abspath,
                           "--output-dir=$GLUE_DIR",
                           "--generate=npapi",
                           "$SOURCES"])

env["BUILDERS"]["Nixysa"] = Builder(action=NIXYSA_CMDLINE,
                                    emitter=NixysaEmitter)

AUTOGEN_OUTPUT = env.Nixysa(IDL_SOURCES)
AUTOGEN_CC_FILES = [f for f in AUTOGEN_OUTPUT if f.suffix == ".cc"]

env.SharedLibrary("hoge", AUTOGEN_CC_FILES + SOURCES +
                  ["$STATIC_GLUE_DIR/" + f for f in STATIC_GLUE_SOURCES])

書き換える所は、IDL_SOURCESSOURCESと最後の行のenv.SharedLibraryの第1引数を変える。んでROOTっていう所もチェックアウトしたnixysaのディレクトリを指定する。あとは普通にsconsを実行したら、ディレクトリにlibhoge.soが出来る。でこれからChrome開発的な事をする

manifest.json

{
  "name": "test",
  "version": "0.1",
  "background_page": "background.html",
  "plugins": [
    { "path": "libhoge.so"  }
  ],
}

pluginsで指定出来る。pathの他にpublicを設定するとどっからでもプラグインが使えるようになっちゃうらしいのでそれは止めておく

background.html

<html>
  <head>
    <script type="text/javascript">
function init() {
  var plugin = document.getElementById("plugin");
  var o = plugin.Hoge();

  if (o) {
    alert(o.say());
  }
}
    </script>
  </head>
  <body onload="init()">
    <object id="plugin" type="application/x-hoge"></object>
  </body>
</html>

みたいな感じで、<object>でプラグイン読み込んで、それからC++なクラスにアクセス出来るようになる模様。ってな感じみたいっすね。もろnixysaのドキュメントそのままやっただけなのであれですけど

Chrome Extension開発を勉強してみる (8) - ominibox - Chrome Extension開発を勉強してみる (6) - Page Action -