Chromium Code Reviews| Index: native_client_sdk/src/libraries/ppapi_simple/ppapi_simple_instance.cc |
| diff --git a/native_client_sdk/src/libraries/ppapi_simple/ppapi_simple_instance.cc b/native_client_sdk/src/libraries/ppapi_simple/ppapi_simple_instance.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..d831cc30de4a0a018eb651314d2a407cd942874b |
| --- /dev/null |
| +++ b/native_client_sdk/src/libraries/ppapi_simple/ppapi_simple_instance.cc |
| @@ -0,0 +1,353 @@ |
| +// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include <fcntl.h> |
| +#include <pthread.h> |
| +#include <stdarg.h> |
| +#include <stdio.h> |
| +#include <stdlib.h> |
| +#include <sys/types.h> |
| +#include <sys/stat.h> |
| + |
| +#include <cstdlib> |
| +#include <cstring> |
| +#include <map> |
| +#include <string> |
| +#include <vector> |
| + |
| +#include "nacl_io/kernel_wrap.h" |
| +#include "nacl_io/nacl_io.h" |
| + |
| +#include "ppapi/c/ppb_var.h" |
| + |
| +#include "ppapi/cpp/input_event.h" |
| +#include "ppapi/cpp/message_loop.h" |
| +#include "ppapi/cpp/module.h" |
| +#include "ppapi/cpp/rect.h" |
| +#include "ppapi/cpp/size.h" |
| +#include "ppapi/cpp/touch_point.h" |
| +#include "ppapi/cpp/var.h" |
| + |
| +#include "ppapi_simple/ppapi_event.h" |
| +#include "ppapi_simple/ppapi_simple_instance.h" |
| +#include "ppapi_simple/ppapi_simple_main.h" |
| + |
| +static PSInstance* s_InstanceObject = NULL; |
| + |
| +PSInstance* PSInstance::GetInstance() { |
| + return s_InstanceObject; |
| +} |
| + |
| +struct StartInfo { |
| + PSInstance* inst_; |
| + uint32_t argc_; |
| + const char** argv_; |
| +}; |
| + |
| + |
| +// The starting point for 'main'. We create this thread to hide the real |
| +// main pepper thread which must never be blocked. |
| +void* PSInstance::MainThreadThunk(void *info) { |
| + s_InstanceObject->Log("Got MainThreadThunk.\n"); |
| + StartInfo* si = static_cast<StartInfo*>(info); |
| + si->inst_->main_loop_ = new pp::MessageLoop(si->inst_); |
| + si->inst_->main_loop_->AttachToCurrentThread(); |
| + |
| + int ret = si->inst_->MainThread(si->argc_, si->argv_); |
| + for (uint32_t i = 0; i < si->argc_; i++) { |
| + delete[] si->argv_[i]; |
| + } |
| + delete[] si->argv_; |
| + delete si; |
| + |
| + return NULL; |
| +} |
| + |
| +// |
| +// The default implementation supports running a 'C' main. |
| +// |
| +int PSInstance::MainThread(int argc, const char *argv[]) { |
| + if (main_cb_) { |
| + Log("Starting MAIN.\n"); |
| + int ret = main_cb_(argc, argv); |
| + Log("Main thread returned with %d.\n", ret); |
| + return ret; |
| + } |
| + |
| + Error("No main defined.\n"); |
| + return 0; |
| +} |
| + |
| +PSInstance::PSInstance(PP_Instance instance, const char *argv[]) |
| + : pp::Instance(instance), |
| + main_loop_(NULL), |
| + verbosity_(PS_LOG_VERBOSITY), |
| + events_enabled_(PS_NO_EVENTS) { |
| + // Set the single Instance object |
| + s_InstanceObject = this; |
| + |
| +#ifdef DEBUG |
| + SetVerbosity(PS_LOG_VERBOSITY); |
| +#endif |
| + |
| + // Place PPAPI_MAIN_USE arguments into properties map |
| + while (*argv) { |
| + std::string key = *argv++; |
| + std::string val = *argv++; |
| + properties_[key] = val; |
| + } |
| + |
| + RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE | |
| + PP_INPUTEVENT_CLASS_KEYBOARD | |
| + PP_INPUTEVENT_CLASS_WHEEL | |
| + PP_INPUTEVENT_CLASS_TOUCH); |
| + |
| + ppb_core_ = reinterpret_cast<const PPB_Core*>( |
|
binji
2013/05/23 18:06:49
why reinterpret_cast? static_cast should work.
noelallen1
2013/05/23 22:01:24
Done.
|
| + pp::Module::Get()->GetBrowserInterface(PPB_CORE_INTERFACE)); |
| + |
| + ppb_var_ = reinterpret_cast<const PPB_Var*>( |
| + pp::Module::Get()->GetBrowserInterface(PPB_VAR_INTERFACE)); |
| + |
| + ppb_view_ = reinterpret_cast<const PPB_View*>( |
| + pp::Module::Get()->GetBrowserInterface(PPB_VIEW_INTERFACE)); |
| +} |
| + |
| +PSInstance::~PSInstance() {} |
| + |
| +void PSInstance::SetMain(PSMainFunc_t main) { |
| + main_cb_ = main; |
| +} |
| + |
| +bool PSInstance::Init(uint32_t arg, |
| + const char* argn[], |
| + const char* argv[]) { |
| + StartInfo* si = new StartInfo; |
| + |
| + si->inst_ = this; |
| + si->argc_ = 1; |
| + si->argv_ = new const char *[arg*2+1]; |
| + si->argv_[0] = NULL; |
| + |
| + // Process arguments passed into Module INIT from JavaScript |
| + for (uint32_t i=0; i < arg; i++) { |
| + if (argv[i]) { |
| + Log("ARG %s=%s\n", argn[i], argv[i]); |
| + } else { |
| + Log("ARG %s\n", argn[i]); |
| + } |
| + |
| + // If we start with PM prefix set the instance argument map |
| + if (0 == strncmp(argn[i], "pm_", 3)) { |
|
binji
2013/05/23 18:06:49
for legacy support? or should it be ps_ now
noelallen1
2013/05/23 22:01:24
Done.
|
| + std::string key = argn[i]; |
| + std::string val = argv[i]; |
| + properties_[key] = val; |
| + continue; |
| + } |
| + |
| + // If this is the 'src' tag, then get the NMF name. |
| + if (!strcmp("src", argn[i])) { |
| + char *name = new char[strlen(argv[i]) + 1]; |
| + strcpy(name, argv[i]); |
| + si->argv_[0] = name; |
| + } |
| + else { |
| + // Otherwise turn it into arguments |
| + char *key = new char[strlen(argn[i]) + 3]; |
| + key[0] = '-'; |
| + key[1] = '-'; |
| + strcpy(&key[2], argn[i]); |
| + |
| + si->argv_[si->argc_++] = key; |
| + if (argv[i] && argv[i][0]) { |
| + char *val = new char[strlen(argv[i]) + 1]; |
| + strcpy(val, argv[i]); |
| + si->argv_[si->argc_++] = val; |
| + } |
| + } |
| + } |
| + |
| + // If src was not found, set the first arg to something |
| + if (NULL == si->argv_[0]) { |
| + char *name = new char[5]; |
| + strcpy(name, "NMF?"); |
| + si->argv_[0] = name; |
| + } |
| + |
| + if (ProcessProperties()) { |
| + pthread_t main_thread; |
| + int ret = pthread_create(&main_thread, NULL, MainThreadThunk, |
| + static_cast<void*>(si)); |
| + Log("Created thread: %d.\n", ret); |
| + return ret == 0; |
| + } |
| + |
| + Log("Skipping create thread.\n"); |
| + return false; |
| +} |
| + |
| +const char* PSInstance::GetProperty(const char* key, const char* def) { |
| + PropertyMap_t::iterator it = properties_.find(key); |
| + if (it != properties_.end()) { |
| + return it->second.c_str(); |
| + } |
| + return def; |
| +} |
| + |
| +bool PSInstance::ProcessProperties() { |
| + const char* stdin_path = GetProperty("pm_stdin", "/dev/stdin"); |
| + const char* stdout_path = GetProperty("pm_stdout", "/dev/stdout"); |
| + const char* stderr_path = GetProperty("pm_stderr", "/dev/console3"); |
| + const char* verbosity = GetProperty("pm_verbosity", NULL); |
| + |
| + // Reset verbosity if passed in |
| + if (verbosity) SetVerbosity(static_cast<Verbosity>(atoi(verbosity))); |
| + |
| + // Enable NaCl IO to map STDIN, STDOUT, and STDERR |
| + nacl_io_init_ppapi(PSGetInstanceId(), PSGetInterface); |
| + int fd0 = open(stdin_path, O_RDONLY); |
| + dup2(fd0, 0); |
| + |
| + int fd1 = open(stdout_path, O_WRONLY); |
| + dup2(fd1, 1); |
| + |
| + int fd2 = open(stderr_path, O_WRONLY); |
| + dup2(fd2, 2); |
| + |
| + setvbuf(stderr, NULL, _IOLBF, 0); |
| + setvbuf(stdout, NULL, _IOLBF, 0); |
| + |
| + return true; |
| +} |
| + |
| +// |
| +// Logging Functions |
| +// |
| +void PSInstance::SetVerbosity(Verbosity verbosity) { |
| + verbosity_ = verbosity; |
| +} |
| + |
| +void PSInstance::Log(const char *fmt, ...) { |
| + if (verbosity_ >= PS_LOG_VERBOSITY) { |
| + va_list ap; |
| + va_start(ap, fmt); |
| + vfprintf(stdout, fmt, ap); |
| + } |
| +} |
| + |
| +void PSInstance::Warn(const char *fmt, ...) { |
| + if (verbosity_ >= PS_WARN_VERBOSITY) { |
| + va_list ap; |
| + va_start(ap, fmt); |
| + vfprintf(stdout, fmt, ap); |
| + } |
| +} |
| + |
| +void PSInstance::Error(const char *fmt, ...) { |
| + if (verbosity_ >= PS_ERROR_VERBOSITY) { |
| + va_list ap; |
| + va_start(ap, fmt); |
| + vfprintf(stderr, fmt, ap); |
| + } |
| +} |
| + |
| +// |
| +// Event Functions |
| +// |
| +void PSInstance::SetEnabledEvents(uint32_t mask) { |
| + events_enabled_ = mask; |
| +} |
| + |
| +void PSInstance::PostEvent(PSEventType type) { |
| + assert(PS_LOST_EVENT == type); |
| + |
| + if (events_enabled_ & type) { |
| + PSEvent *env = (PSEvent *) malloc(sizeof(PSEvent)); |
| + memset(env, 0, sizeof(*env)); |
| + env->type_ = type; |
| + event_queue_.Add(env); |
| + } |
| +} |
| + |
| +void PSInstance::PostEvent(PSEventType type, PP_Bool bool_value) { |
| + assert(PS_FOCUS_EVENT == type); |
| + |
| + if (events_enabled_ & type) { |
| + PSEvent *env = (PSEvent *) malloc(sizeof(PSEvent)); |
| + env->type_ = type; |
| + env->bool_ = bool_value; |
| + event_queue_.Add(env); |
| + } |
| +} |
| + |
| +void PSInstance::PostEvent(PSEventType type, PP_Resource resource) { |
| + assert(PS_INPUT_EVENT == type || PS_VIEW_EVENT == type); |
| + |
| + if (events_enabled_ & type) { |
| + if (resource) { |
| + ppb_core_->AddRefResource(resource); |
| + } |
| + PSEvent *env = (PSEvent *) malloc(sizeof(PSEvent)); |
| + env->type_ = type; |
| + env->resource_ = resource; |
| + event_queue_.Add(env); |
| + } |
| +} |
| + |
| +void PSInstance::PostEvent(PSEventType type, const PP_Var& var) { |
| + assert(PS_MESSAGE_EVENT == type); |
| + |
| + if (events_enabled_ & type) { |
| + ppb_var_->AddRef(var); |
| + PSEvent *env = (PSEvent *) malloc(sizeof(PSEvent)); |
| + env->type_ = type; |
| + env->var_ = var; |
| + event_queue_.Add(env); |
| + } |
| +} |
| + |
| +PSEvent* PSInstance::AcquireEvent(bool block) { |
| + return event_queue_.Get(block); |
| +} |
| + |
| +void PSInstance::ReleaseEvent(PSEvent* event) { |
| + if (event) { |
| + switch(event->type_) { |
| + case PS_MESSAGE_EVENT: |
| + ppb_var_->Release(event->var_); |
| + break; |
| + case PS_INPUT_EVENT: |
| + case PS_VIEW_EVENT: |
| + if (event->resource_) { |
| + ppb_core_->ReleaseResource(event->resource_); |
| + } |
| + break; |
| + default: |
| + break; |
| + } |
| + free(event); |
| + } |
| +} |
| + |
| +void PSInstance::HandleMessage(const pp::Var& message) { |
| + Log("Got Message: \n"); |
| + PSPostVarEvent(PS_MESSAGE_EVENT, message.pp_var()); |
| +} |
| + |
| +bool PSInstance::HandleInputEvent(const pp::InputEvent& event) { |
| + Log("Got Input\n"); |
| + PostEvent(PS_INPUT_EVENT, event.pp_resource()); |
| + return true; |
| +} |
| + |
| +void PSInstance::DidChangeView(const pp::View& view) { |
| + pp::Size new_size = view.GetRect().size(); |
| + Log("Got View change: %d,%d\n", new_size.width(), new_size.height()); |
| + PostEvent(PS_VIEW_EVENT, view.pp_resource()); |
| +} |
| + |
| +void PSInstance::DidChangeFocus(bool focus) { |
| + Log("Got Focus change: %s\n", focus ? "FOCUS ON" : "FOCUS OFF"); |
| + PostEvent(PS_FOCUS_EVENT, focus ? PP_TRUE : PP_FALSE); |
| +} |
| + |