Native Client(NaCl)をやってみる (6) - pp::URLLoader -

2012-10-21T00:00:00+00:00 C++ Native Client

まぁ使い方だけですし。概要として「画像ファイルを取得して、それをメッセージングでArrayBufferにして返す。」っていうのだけ。

index.html

<html>
  <body>
    <canvas id="canvas"></canvas>
    <embed id="plugin" width="0" height="0" src="/sample.nmf" type="application/x-nacl" />
    <script type="text/javascript">
(function(undefined) {
  var plugin = document.querySelector("#plugin");

  plugin.addEventListener("message", function(msg) {
    var data = msg.data;

    console.log(data); // やんなくて良い

    var bb = new WebKitBlobBuilder();
    bb.append(data);

    var image = new Image();
    image.src = window.webkitURL.createObjectURL(bb.getBlob());
    image.onload = function() {
      var canvas = document.querySelector("#canvas");
      var ctx = canvas.getContext("2d");

      ctx.canvas.width = image.width;
      ctx.canvas.height = image.height;
      ctx.drawImage(image, 0, 0);

      window.webkitURL.revokeObjectURL(this.src);
    };
  });
})();
    </script>
  <body>
</html>

まぁ特に説明する必要なさそうなので(ry

sample.nmf

{
  "program": {
    "x86-32": {
      "url": "sample.nexe"
    }
  }
}

まぁここまでは通常のNative Clientを使う場合の処理と同様

sample.cc

#include <cstring>

#include "ppapi/cpp/instance.h"
#include "ppapi/cpp/module.h"
#include "ppapi/cpp/var.h"
#include "ppapi/cpp/var_array_buffer.h"
#include "ppapi/cpp/url_loader.h"
#include "ppapi/cpp/url_request_info.h"
#include "ppapi/utility/completion_callback_factory.h"

#include "ppapi/c/pp_errors.h"

#define BUFFER_SIZE 4096

class SampleURLLoader {

  private:
    pp::Instance* instance_;
    pp::URLLoader loader_;
    pp::URLRequestInfo request_;
    pp::CompletionCallbackFactory<SampleURLLoader> callback_;

    char* buffer;
    std::string response;

    void OnOpen(int32_t result) {
      if (result != PP_OK) {
        instance_->PostMessage(pp::Var("NG"));

        return;
      }

      readBody();
    }

    void readBody() {
      pp::CompletionCallback cc = callback_.NewCallback(&SampleURLLoader::OnRead);

      int32_t status = PP_OK;

      do {
        status = loader_.ReadResponseBody(buffer, BUFFER_SIZE, cc);

        if (status > 0) {
          readBody();
        }
      } while (status > 0);

      if (status != PP_OK_COMPLETIONPENDING) {
        cc.Run(status);
      }
    }

    void writeData(const char* buffer, int32_t num_bytes) {
      if (num_bytes <= 0) {
        return;
      }

      num_bytes = std::min(BUFFER_SIZE, num_bytes);

      response.insert(response.end(), buffer, buffer + num_bytes);
    }

    void OnRead(int32_t result) {
      if (result == PP_OK) {
        pp::VarArrayBuffer vab = pp::VarArrayBuffer(response.size());

        char* data = static_cast<char*>(vab.Map());
        memcpy(data, response.c_str(), response.size());

        instance_->PostMessage(vab);
      } else if (result > 0) {
        writeData(buffer, result);
        readBody();
      }
    }

    SampleURLLoader(pp::Instance* instance) :
      instance_(instance),
      loader_(instance),
      request_(instance),
      callback_(this),
      buffer(new char[BUFFER_SIZE]) {

      request_.SetURL("test.jpg");
      request_.SetMethod("GET");
    }

  public:
    static SampleURLLoader* create(pp::Instance* instance) {
      return new SampleURLLoader(instance);
    }

    void start() {
      pp::CompletionCallback cc = callback_.NewCallback(&SampleURLLoader::OnOpen);

      loader_.Open(request_, cc);
    }
};

class SampleInstance : public pp::Instance {
  public:
    explicit SampleInstance(PP_Instance instance) : pp::Instance(instance) {
      SampleURLLoader* loader = SampleURLLoader::create(this);
      loader->start();
    }
};

class SampleModule : public pp::Module {
  public:
    SampleModule() : pp::Module() {
    }

    virtual pp::Instance* CreateInstance(PP_Instance instance) {
      return new SampleInstance(instance);
    }
};

namespace pp {
  Module* CreateModule() {
    return new SampleModule();
  }
}

実はほとんどpepper examplesにあるgeturlサンプルとほぼ同じ感じ。だけど、こっちはPostMessageをするデータはVarArrayBufferをぶっ飛ばしてる

まぁこれ、デストラクタ辺りでバッファを飛ばしてない辺りがご了承ください。まぁあくまで使い方なんで...

とりあえずgeturlなサンプル読んだ方が早そうな気もするのですけど

Native Client(NaCl)をやってみる (7) - pp::WebSocket - RubyOnRailsの標準テストをやってみる