nacl/plugin.cc

Go to the documentation of this file.
00001 // Copyright (c) 2011 The Native Client Authors. All rights reserved.
00002 // Use of this source code is governed by a BSD-style license that can be
00003 // found in the NaCl-LICENSE file.
00004 
00005 #include <pthread.h>
00006 #include <stdio.h>
00007 #include <stdlib.h>
00008 
00009 #include <ppapi/cpp/instance.h>
00010 #include <ppapi/cpp/module.h>
00011 #include <ppapi/cpp/rect.h>
00012 #include <ppapi/cpp/size.h>
00013 #include <ppapi/cpp/file_system.h>
00014 
00015 #include <SDL_video.h>
00016 extern int wesnoth_main(int argc, char **argv);
00017 #include <SDL.h>
00018 #include <SDL_nacl.h>
00019 
00020 #include <nacl-mounts/base/KernelProxy.h>
00021 #include <nacl-mounts/base/MainThreadRunner.h>
00022 #include <nacl-mounts/http2/HTTP2Mount.h>
00023 #include <nacl-mounts/pepper/PepperMount.h>
00024 
00025 
00026 const char* http_dirs[] = {
00027 #include <dir_list.h>
00028 };
00029 
00030 struct http_file_info {
00031   const char* path;
00032   size_t size;
00033 } http_files[] = {
00034 #include <file_list.h>
00035 };
00036 
00037 struct http_pack_info {
00038   const char* path;
00039   const char* pack_path;
00040   off_t offset;
00041 } http_packs[] = {
00042 #include <pack_list.h>
00043 };
00044 
00045 
00046 class PluginInstance : public pp::Instance {
00047  public:
00048   explicit PluginInstance(PP_Instance instance) : pp::Instance(instance),
00049                                                   sdl_main_thread_(0),
00050                                                   width_(0),
00051                                                   height_(0),
00052                                                   progress_handler_(this),
00053                                                   directory_reader_(this) {
00054     RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE);
00055     RequestFilteringInputEvents(PP_INPUTEVENT_CLASS_KEYBOARD);
00056 
00057     proxy_ = KernelProxy::KPInstance();
00058     runner_ = new MainThreadRunner(this);
00059 
00060     fprintf(stderr, "Requesting an HTML5 local persistent filesystem.\n");
00061     fflush(stderr);
00062     fs_ = new pp::FileSystem(this, PP_FILESYSTEMTYPE_LOCALPERSISTENT);
00063   }
00064 
00065   ~PluginInstance() {
00066     if (sdl_main_thread_) {
00067       pthread_join(sdl_main_thread_, NULL);
00068     }
00069   }
00070 
00071   virtual void DidChangeView(const pp::Rect& position, const pp::Rect& clip) {
00072     fprintf(stderr, "did change view, new %dx%d, old %dx%d\n",
00073         position.size().width(), position.size().height(),
00074         width_, height_);
00075     fflush(stderr);
00076 
00077     width_ = position.size().width();
00078     height_ = position.size().height();
00079 
00080     SDL_NACL_SetInstance(pp_instance(), width_, height_);
00081 
00082     if (sdl_thread_started_ == false) {
00083       // It seems this call to SDL_Init is required. Calling from
00084       // sdl_main() isn't good enough.
00085       // Perhaps it must be called from the main thread?
00086       int lval = SDL_Init(SDL_INIT_AUDIO);
00087       assert(lval >= 0);
00088       if (0 == pthread_create(&sdl_main_thread_, NULL, sdl_thread_static, this)) {
00089         sdl_thread_started_ = true;
00090       }
00091     }
00092   }
00093 
00094   bool HandleInputEvent(const pp::InputEvent& event) {
00095     SDL_NACL_PushEvent(event);
00096     return true;
00097   }
00098 
00099   void HandleMessage(const pp::Var& message) {
00100     std::string s = message.AsString();
00101     directory_reader_.HandleResponse(s);
00102   }
00103 
00104   bool Init(int argc, const char* argn[], const char* argv[]) {
00105     return true;
00106   }
00107 
00108  private:
00109   bool sdl_thread_started_;
00110   pthread_t sdl_main_thread_;
00111   int width_;
00112   int height_;
00113   KernelProxy* proxy_;
00114   MainThreadRunner* runner_;
00115   pp::FileSystem* fs_;
00116 
00117   static void* sdl_thread_static(void* param) {
00118     return reinterpret_cast<PluginInstance*>(param)->sdl_thread();
00119   }
00120 
00121   void* sdl_thread() {
00122     fprintf(stderr, "Initializing nacl-mounts.\n");
00123     fflush(stderr);
00124 
00125     // Setup writable homedir.
00126     PepperMount* pepper_mount = new PepperMount(runner_, fs_, 20 * 1024 * 1024);
00127     pepper_mount->SetDirectoryReader(&directory_reader_);
00128     pepper_mount->SetPathPrefix("/wesnoth-userdata");
00129 
00130     proxy_->mkdir("/wesnoth-userdata", 0777);
00131     int res = proxy_->mount("/wesnoth-userdata", pepper_mount);
00132 
00133     // The following lines can be removed when nacl-mounts starts intercepting mkdir() calls.
00134     proxy_->mkdir("/wesnoth-userdata/saves", 0777);
00135 
00136     // Setup r/o data directory in /usr/local/share/wesnoth
00137     HTTP2Mount* http2_mount = new HTTP2Mount(runner_, "./usr/local/share/wesnoth");
00138     http2_mount->SetLocalCache(fs_, 350*1024*1024, "/wesnoth0", true);
00139     http2_mount->SetProgressHandler(&progress_handler_);
00140  
00141     fprintf(stderr, "Registering known files.\n");
00142     fflush(stderr);
00143     for (int i = 0; i < sizeof(http_dirs) / sizeof(*http_dirs); ++i) {
00144       char* path = (char*)http_dirs[i];
00145       if (path && *path)
00146         http2_mount->AddDir(path);
00147     }
00148 
00149     for (int i = 0; i < sizeof(http_files) / sizeof(*http_files); ++i) {
00150       char* path = (char*)http_files[i].path;
00151       size_t size = http_files[i].size;
00152       if (path && *path)
00153         http2_mount->AddFile(path, size);
00154     }
00155 
00156     for (int i = 0; i < sizeof(http_packs) / sizeof(*http_packs); ++i) {
00157       char* path = (char*)http_packs[i].path;
00158       char* pack_path = (char*)http_packs[i].pack_path;
00159       off_t offset = http_packs[i].offset;
00160       if (path && *path) {
00161         http2_mount->SetInPack(path, pack_path, offset);
00162       }
00163     }
00164 
00165     http2_mount->SetInMemory("/fonts/Andagii.ttf", true);
00166     http2_mount->SetInMemory("/fonts/DejaVuSans.ttf", true);
00167     http2_mount->SetInMemory("/fonts/wqy-zenhei.ttc", true);
00168 
00169     fprintf(stderr, "Mounting the filesystem.\n");
00170     fflush(stderr);
00171     proxy_->mkdir("/usr", 0777);
00172     proxy_->mkdir("/usr/local", 0777);
00173     proxy_->mkdir("/usr/local/share", 0777);
00174     res = proxy_->mount("/usr/local/share/wesnoth", http2_mount);
00175     if (!res) {
00176       fprintf(stderr, "FS initialization success.\n");
00177     } else {
00178       fprintf(stderr, "FS initialization failure.\n");
00179     }
00180     fflush(stderr);
00181 
00182     // Finally, launch the game.
00183     char res_s[100];
00184     snprintf(res_s, sizeof(res_s), "%dx%d", width_, height_);
00185     static char const * argv[] = {"wesnoth", "-r", res_s, NULL};
00186     printf("starting game thread: %s\n", res_s);
00187     wesnoth_main(sizeof(argv) / sizeof(*argv) - 1, (char**)argv);
00188     return NULL;
00189   }
00190 
00191   class ProgressHandler : public HTTP2ProgressHandler {
00192   public:
00193     pp::Instance* instance_;
00194 
00195     ProgressHandler(pp::Instance* instance) : instance_(instance) {}
00196 
00197     void HandleProgress(std::string& path, int64_t bytes, int64_t size) {
00198       char buf[100];
00199       snprintf(buf, sizeof(buf), "%llu,%llu", (unsigned long long)bytes,
00200           (unsigned long long)size);
00201       std::string message = "[\"" + path + "\"," + buf + "]";
00202       instance_->PostMessage(message);
00203     }
00204   };
00205 
00206   ProgressHandler progress_handler_;
00207 
00208   class JSDirectoryReader: public DirectoryReader {
00209   public:
00210     pp::Instance* instance_;
00211     pp::CompletionCallback cc_;
00212     std::set<std::string>* entries_;
00213 
00214     JSDirectoryReader(pp::Instance* instance) : instance_(instance) {}
00215 
00216     int ReadDirectory(const std::string& path, std::set<std::string>* entries, const pp::CompletionCallback& cc) {
00217       cc_ = cc;
00218       entries_ = entries;
00219       std::string message = "[\"ReadDirectory\",\"" + path + "\"]";
00220       instance_->PostMessage(message);
00221     }
00222 
00223     void HandleResponse(const std::string& response) {
00224       fprintf(stderr, "response: %s\n", response.c_str());
00225       std::string::const_iterator ind = response.begin();
00226       std::string::const_iterator next = response.begin();
00227       while (ind != response.end() && next != response.end()) {
00228         if (*next == '\n' && ind != next) {
00229           if (*ind == '\n') {
00230             ++ind;
00231           }
00232           if (ind != next) {
00233             entries_->insert(std::string(ind, next));
00234           }
00235           ind = next;
00236         }
00237         ++next;
00238       }
00239       if (ind != next) {
00240     std::string last(ind, next-1);
00241         if (!last.empty()) {
00242           entries_->insert(last);
00243         }
00244       }
00245       cc_.Run(PP_OK);
00246     }
00247   };
00248 
00249   JSDirectoryReader directory_reader_;
00250 };
00251 
00252 class PepperModule : public pp::Module {
00253 public:
00254   // Create and return a PluginInstanceInstance object.
00255   virtual pp::Instance* CreateInstance(PP_Instance instance) {
00256     return new PluginInstance(instance);
00257   }
00258 };
00259 
00260 namespace pp {
00261   Module* CreateModule() {
00262     return new PepperModule();
00263   }
00264 }  // namespace pp
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated by doxygen 1.7.1 on Fri May 25 2012 01:03:06 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs