The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
plugin.cc
Go to the documentation of this file.
1 // Copyright (c) 2011 The Native Client Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the NaCl-LICENSE file.
4 
5 #include <pthread.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 
9 #include <ppapi/cpp/instance.h>
10 #include <ppapi/cpp/module.h>
11 #include <ppapi/cpp/rect.h>
12 #include <ppapi/cpp/size.h>
13 #include <ppapi/cpp/file_system.h>
14 
15 #include <SDL_video.h>
16 extern int wesnoth_main(int argc, char **argv);
17 #include <SDL.h>
18 #include <SDL_nacl.h>
19 
20 #include <nacl-mounts/base/KernelProxy.h>
21 #include <nacl-mounts/base/MainThreadRunner.h>
22 #include <nacl-mounts/http2/HTTP2Mount.h>
23 #include <nacl-mounts/pepper/PepperMount.h>
24 
25 
26 const char* http_dirs[] = {
27 #include <dir_list.h>
28 };
29 
31  const char* path;
32  size_t size;
33 } http_files[] = {
34 #include <file_list.h>
35 };
36 
38  const char* path;
39  const char* pack_path;
40  off_t offset;
41 } http_packs[] = {
42 #include <pack_list.h>
43 };
44 
45 
46 class PluginInstance : public pp::Instance {
47  public:
48  explicit PluginInstance(PP_Instance instance) : pp::Instance(instance),
50  width_(0),
51  height_(0),
52  progress_handler_(this),
53  directory_reader_(this) {
54  RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE);
55  RequestFilteringInputEvents(PP_INPUTEVENT_CLASS_KEYBOARD);
56 
57  proxy_ = KernelProxy::KPInstance();
58  runner_ = new MainThreadRunner(this);
59 
60  fprintf(stderr, "Requesting an HTML5 local persistent filesystem.\n");
61  fflush(stderr);
62  fs_ = new pp::FileSystem(this, PP_FILESYSTEMTYPE_LOCALPERSISTENT);
63  }
64 
66  if (sdl_main_thread_) {
67  pthread_join(sdl_main_thread_, nullptr);
68  }
69  }
70 
71  virtual void DidChangeView(const pp::Rect& position, const pp::Rect& clip) {
72  fprintf(stderr, "did change view, new %dx%d, old %dx%d\n",
73  position.size().width(), position.size().height(),
74  width_, height_);
75  fflush(stderr);
76 
77  width_ = position.size().width();
78  height_ = position.size().height();
79 
80  SDL_NACL_SetInstance(pp_instance(), width_, height_);
81 
82  if (sdl_thread_started_ == false) {
83  // It seems this call to SDL_Init is required. Calling from
84  // sdl_main() isn't good enough.
85  // Perhaps it must be called from the main thread?
86  int lval = SDL_Init(SDL_INIT_AUDIO);
87  assert(lval >= 0);
88  if (0 == pthread_create(&sdl_main_thread_, nullptr, sdl_thread_static, this)) {
89  sdl_thread_started_ = true;
90  }
91  }
92  }
93 
94  bool HandleInputEvent(const pp::InputEvent& event) {
95  SDL_NACL_PushEvent(event);
96  return true;
97  }
98 
99  void HandleMessage(const pp::Var& message) {
100  std::string s = message.AsString();
102  }
103 
104  bool Init(int argc, const char* argn[], const char* argv[]) {
105  return true;
106  }
107 
108  private:
110  pthread_t sdl_main_thread_;
111  int width_;
112  int height_;
113  KernelProxy* proxy_;
114  MainThreadRunner* runner_;
115  pp::FileSystem* fs_;
116 
117  static void* sdl_thread_static(void* param) {
118  return reinterpret_cast<PluginInstance*>(param)->sdl_thread();
119  }
120 
121  void* sdl_thread() {
122  fprintf(stderr, "Initializing nacl-mounts.\n");
123  fflush(stderr);
124 
125  // Setup writable homedir.
126  PepperMount* pepper_mount = new PepperMount(runner_, fs_, 20 * 1024 * 1024);
127  pepper_mount->SetDirectoryReader(&directory_reader_);
128  pepper_mount->SetPathPrefix("/wesnoth-userdata");
129 
130  proxy_->mkdir("/wesnoth-userdata", 0777);
131  int res = proxy_->mount("/wesnoth-userdata", pepper_mount);
132 
133  // The following lines can be removed when nacl-mounts starts intercepting mkdir() calls.
134  proxy_->mkdir("/wesnoth-userdata/saves", 0777);
135 
136  // Setup r/o data directory in /usr/local/share/wesnoth
137  HTTP2Mount* http2_mount = new HTTP2Mount(runner_, "./usr/local/share/wesnoth");
138  http2_mount->SetLocalCache(fs_, 350*1024*1024, "/wesnoth0", true);
139  http2_mount->SetProgressHandler(&progress_handler_);
140 
141  fprintf(stderr, "Registering known files.\n");
142  fflush(stderr);
143  for (int i = 0; i < sizeof(http_dirs) / sizeof(*http_dirs); ++i) {
144  char* path = (char*)http_dirs[i];
145  if (path && *path)
146  http2_mount->AddDir(path);
147  }
148 
149  for (int i = 0; i < sizeof(http_files) / sizeof(*http_files); ++i) {
150  char* path = (char*)http_files[i].path;
151  size_t size = http_files[i].size;
152  if (path && *path)
153  http2_mount->AddFile(path, size);
154  }
155 
156  for (int i = 0; i < sizeof(http_packs) / sizeof(*http_packs); ++i) {
157  char* path = (char*)http_packs[i].path;
158  char* pack_path = (char*)http_packs[i].pack_path;
159  off_t offset = http_packs[i].offset;
160  if (path && *path) {
161  http2_mount->SetInPack(path, pack_path, offset);
162  }
163  }
164 
165  http2_mount->SetInMemory("/fonts/Andagii.ttf", true);
166  http2_mount->SetInMemory("/fonts/DejaVuSans.ttf", true);
167  http2_mount->SetInMemory("/fonts/wqy-zenhei.ttc", true);
168 
169  fprintf(stderr, "Mounting the filesystem.\n");
170  fflush(stderr);
171  proxy_->mkdir("/usr", 0777);
172  proxy_->mkdir("/usr/local", 0777);
173  proxy_->mkdir("/usr/local/share", 0777);
174  res = proxy_->mount("/usr/local/share/wesnoth", http2_mount);
175  if (!res) {
176  fprintf(stderr, "FS initialization success.\n");
177  } else {
178  fprintf(stderr, "FS initialization failure.\n");
179  }
180  fflush(stderr);
181 
182  // Finally, launch the game.
183  char res_s[100];
184  snprintf(res_s, sizeof(res_s), "%dx%d", width_, height_);
185  static char const * argv[] = {"wesnoth", "-r", res_s, nullptr};
186  printf("starting game thread: %s\n", res_s);
187  wesnoth_main(sizeof(argv) / sizeof(*argv) - 1, (char**)argv);
188  return nullptr;
189  }
190 
191  class ProgressHandler : public HTTP2ProgressHandler {
192  public:
193  pp::Instance* instance_;
194 
195  ProgressHandler(pp::Instance* instance) : instance_(instance) {}
196 
197  void HandleProgress(std::string& path, int64_t bytes, int64_t size) {
198  char buf[100];
199  snprintf(buf, sizeof(buf), "%llu,%llu", (unsigned long long)bytes,
200  (unsigned long long)size);
201  std::string message = "[\"" + path + "\"," + buf + "]";
202  instance_->PostMessage(message);
203  }
204  };
205 
207 
208  class JSDirectoryReader: public DirectoryReader {
209  public:
210  pp::Instance* instance_;
211  pp::CompletionCallback cc_;
212  std::set<std::string>* entries_;
213 
214  JSDirectoryReader(pp::Instance* instance) : instance_(instance) {}
215 
216  int ReadDirectory(const std::string& path, std::set<std::string>* entries, const pp::CompletionCallback& cc) {
217  cc_ = cc;
218  entries_ = entries;
219  std::string message = "[\"ReadDirectory\",\"" + path + "\"]";
220  instance_->PostMessage(message);
221  }
222 
223  void HandleResponse(const std::string& response) {
224  fprintf(stderr, "response: %s\n", response.c_str());
225  std::string::const_iterator ind = response.begin();
226  std::string::const_iterator next = response.begin();
227  while (ind != response.end() && next != response.end()) {
228  if (*next == '\n' && ind != next) {
229  if (*ind == '\n') {
230  ++ind;
231  }
232  if (ind != next) {
233  entries_->insert(std::string(ind, next));
234  }
235  ind = next;
236  }
237  ++next;
238  }
239  if (ind != next) {
240  std::string last(ind, next-1);
241  if (!last.empty()) {
242  entries_->insert(last);
243  }
244  }
245  cc_.Run(PP_OK);
246  }
247  };
248 
250 };
251 
252 class PepperModule : public pp::Module {
253 public:
254  // Create and return a PluginInstanceInstance object.
255  virtual pp::Instance* CreateInstance(PP_Instance instance) {
256  return new PluginInstance(instance);
257  }
258 };
259 
260 namespace pp {
261  Module* CreateModule() {
262  return new PepperModule();
263  }
264 } // namespace pp
PluginInstance(PP_Instance instance)
Definition: plugin.cc:48
Definition: plugin.cc:260
int ReadDirectory(const std::string &path, std::set< std::string > *entries, const pp::CompletionCallback &cc)
Definition: plugin.cc:216
const char * path
Definition: plugin.cc:31
void HandleProgress(std::string &path, int64_t bytes, int64_t size)
Definition: plugin.cc:197
pp::CompletionCallback cc_
Definition: plugin.cc:211
JSDirectoryReader directory_reader_
Definition: plugin.cc:249
struct http_pack_info http_packs[]
KernelProxy * proxy_
Definition: plugin.cc:113
bool sdl_thread_started_
Definition: plugin.cc:109
const char * http_dirs[]
Definition: plugin.cc:26
GLintptr offset
Definition: glew.h:1650
JSDirectoryReader(pp::Instance *instance)
Definition: plugin.cc:214
GLsizei const char ** path
Definition: glew.h:4654
const char * path
Definition: plugin.cc:38
static void * sdl_thread_static(void *param)
Definition: plugin.cc:117
GLenum GLuint GLsizei const char * buf
Definition: glew.h:2498
void HandleResponse(const std::string &response)
Definition: plugin.cc:223
int wesnoth_main(int argc, char **argv)
GLuint res
Definition: glew.h:9258
virtual void DidChangeView(const pp::Rect &position, const pp::Rect &clip)
Definition: plugin.cc:71
~PluginInstance()
Definition: plugin.cc:65
ProgressHandler(pp::Instance *instance)
Definition: plugin.cc:195
const char * pack_path
Definition: plugin.cc:39
size_t i
Definition: function.cpp:1057
struct http_file_info http_files[]
off_t offset
Definition: plugin.cc:40
pthread_t sdl_main_thread_
Definition: plugin.cc:110
void * sdl_thread()
Definition: plugin.cc:121
#define next(ls)
Definition: llex.cpp:27
GLsizeiptr size
Definition: glew.h:1649
ProgressHandler progress_handler_
Definition: plugin.cc:206
std::set< std::string > * entries_
Definition: plugin.cc:212
pp::FileSystem * fs_
Definition: plugin.cc:115
cl_event event
Definition: glew.h:3070
GLfloat param
Definition: glew.h:1498
GLsizei GLenum GLuint GLuint GLsizei char * message
Definition: glew.h:2499
MainThreadRunner * runner_
Definition: plugin.cc:114
bool HandleInputEvent(const pp::InputEvent &event)
Definition: plugin.cc:94
size_t size
Definition: plugin.cc:32
GLdouble s
Definition: glew.h:1358
Module * CreateModule()
Definition: plugin.cc:261
GLsizei const GLcharARB ** string
Definition: glew.h:4503
bool Init(int argc, const char *argn[], const char *argv[])
Definition: plugin.cc:104
void HandleMessage(const pp::Var &message)
Definition: plugin.cc:99
virtual pp::Instance * CreateInstance(PP_Instance instance)
Definition: plugin.cc:255