Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Native Client Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 /// @file | 5 /// @file |
| 6 /// This example demonstrates loading, running and scripting a very simple NaCl | 6 /// This example demonstrates loading, running and scripting a very simple NaCl |
| 7 /// module. To load the NaCl module, the browser first looks for the | 7 /// module. To load the NaCl module, the browser first looks for the |
| 8 /// CreateModule() factory method (at the end of this file). It calls | 8 /// CreateModule() factory method (at the end of this file). It calls |
| 9 /// CreateModule() once to load the module code from your .nexe. After the | 9 /// CreateModule() once to load the module code from your .nexe. After the |
| 10 /// .nexe code is loaded, CreateModule() is not called again. | 10 /// .nexe code is loaded, CreateModule() is not called again. |
| 11 /// | 11 /// |
| 12 /// Once the .nexe code is loaded, the browser then calls the | 12 /// Once the .nexe code is loaded, the browser then calls the |
| 13 /// HelloWorldModule::CreateInstance() | 13 /// HelloWorldModule::CreateInstance() |
| 14 /// method on the object returned by CreateModule(). It calls CreateInstance() | 14 /// method on the object returned by CreateModule(). It calls CreateInstance() |
| 15 /// each time it encounters an <embed> tag that references your NaCl module. | 15 /// each time it encounters an <embed> tag that references your NaCl module. |
| 16 /// | 16 /// |
| 17 /// When the browser encounters JavaScript that references your NaCl module, it | 17 /// When the browser encounters JavaScript that references your NaCl module, it |
| 18 /// calls the GetInstanceObject() method on the object returned from | 18 /// calls the GetInstanceObject() method on the object returned from |
| 19 /// CreateInstance(). In this example, the returned object is a subclass of | 19 /// CreateInstance(). In this example, the returned object is a subclass of |
| 20 /// ScriptableObject, which handles the scripting support. | 20 /// ScriptableObject, which handles the scripting support. |
| 21 | 21 |
| 22 #include <ppapi/cpp/instance.h> | 22 #include <ppapi/cpp/instance.h> |
| 23 #include <ppapi/cpp/module.h> | 23 #include <ppapi/cpp/module.h> |
| 24 #include <ppapi/cpp/dev/scriptable_object_deprecated.h> | 24 #include <ppapi/cpp/dev/scriptable_object_deprecated.h> |
|
garianov
2011/05/18 15:45:19
Do we need this header?
David Springer
2011/05/18 18:01:42
Uh no. Gone.
| |
| 25 #include <ppapi/cpp/var.h> | 25 #include <ppapi/cpp/var.h> |
|
dmichael(do not use this one)
2011/05/18 18:46:10
Whoops, just noticed... if we're using "" for ppa
| |
| 26 #include <cstdio> | 26 #include <cstdio> |
| 27 #include <cstring> | |
| 27 #include <string> | 28 #include <string> |
| 28 #include <algorithm> // for reverse | 29 #include <algorithm> // for reverse |
| 29 | 30 |
| 30 #include "examples/hello_world/helper_functions.h" | 31 #include "examples/hello_world/helper_functions.h" |
| 31 | 32 |
| 32 namespace { | |
| 33 // Helper function to set the scripting exception. Both |exception| and | |
| 34 // |except_string| can be NULL. If |exception| is NULL, this function does | |
| 35 // nothing. | |
| 36 void SetExceptionString(pp::Var* exception, const std::string& except_string) { | |
| 37 if (exception) { | |
| 38 *exception = except_string; | |
| 39 } | |
| 40 } | |
| 41 | |
| 42 // Exception strings. These are passed back to the browser when errors | |
| 43 // happen during property accesses or method calls. | |
| 44 const char* const kExceptionMethodNotAString = "Method name is not a string"; | |
| 45 const char* const kExceptionNoMethodName = "No method named "; | |
| 46 } // namespace | |
| 47 | |
| 48 namespace hello_world { | 33 namespace hello_world { |
| 49 /// method name for ReverseText, as seen by JavaScript code. | 34 /// Method name for ReverseText, as seen by JavaScript code. |
| 50 const char* const kReverseTextMethodId = "reverseText"; | 35 const char* const kReverseTextMethodId = "reverseText"; |
| 51 | 36 |
| 52 /// method name for FortyTwo, as seen by Javascript code. @see FortyTwo() | 37 /// Method name for FortyTwo, as seen by Javascript code. @see FortyTwo() |
| 53 const char* const kFortyTwoMethodId = "fortyTwo"; | 38 const char* const kFortyTwoMethodId = "fortyTwo"; |
| 54 | 39 |
| 40 /// Separator charater for the reverseText method. | |
|
dmichael (off chromium)
2011/05/18 15:43:56
charater->character
David Springer
2011/05/18 18:01:42
Done.
| |
| 41 static const char kMessageArgumentSeparator = ':'; | |
| 42 | |
| 55 /// This is the module's function that invokes FortyTwo and converts the return | 43 /// This is the module's function that invokes FortyTwo and converts the return |
| 56 /// value from an int32_t to a pp::Var for return. | 44 /// value from an int32_t to a pp::Var for return. |
| 57 pp::Var MarshallFortyTwo() { | 45 pp::Var MarshallFortyTwo() { |
| 58 return pp::Var(FortyTwo()); | 46 return pp::Var(FortyTwo()); |
| 59 } | 47 } |
| 60 | 48 |
| 61 /// This function is passed the arg list from the JavaScript call to | 49 /// This function is passed the arg list from the JavaScript call to |
| 62 /// @a reverseText. | 50 /// @a reverseText. |
| 63 /// It makes sure that there is one argument and that it is a string, returning | 51 /// It makes sure that there is one argument and that it is a string, returning |
| 64 /// an error message if it is not. | 52 /// an error message if it is not. |
| 65 /// On good input, it calls ReverseText and returns the result. The | 53 /// On good input, it calls ReverseText and returns the result. The |
| 66 /// ScriptableObject that called this function returns this string back to the | 54 /// ScriptableObject that called this function returns this string back to the |
| 67 /// browser as a JavaScript value. | 55 /// browser as a JavaScript value. |
| 68 pp::Var MarshallReverseText(const std::vector<pp::Var>& args) { | 56 pp::Var MarshallReverseText(const std::string& text) { |
|
dmichael (off chromium)
2011/05/18 15:43:56
Did you update the unit test? For what it's worth
David Springer
2011/05/18 18:01:42
Oh - whoops. I spaced that. Done.
dmichael(do not use this one)
2011/05/18 18:46:10
Could you add it to the CL please? And... did th
| |
| 69 // There should be exactly one arg, which should be an object | 57 return pp::Var(ReverseText(text)); |
| 70 if (args.size() != 1) { | |
| 71 printf("Unexpected number of args\n"); | |
| 72 return "Unexpected number of args"; | |
| 73 } | |
| 74 if (!args[0].is_string()) { | |
| 75 printf("Arg %s is NOT a string\n", args[0].DebugString().c_str()); | |
| 76 return "Arg from Javascript is not a string!"; | |
| 77 } | |
| 78 return pp::Var(ReverseText(args[0].AsString())); | |
| 79 } | |
| 80 | |
| 81 /// This class exposes the scripting interface for this NaCl module. The | |
| 82 /// HasMethod() method is called by the browser when executing a method call on | |
| 83 /// the @a helloWorldModule object (see the reverseText() function in | |
| 84 /// hello_world.html). The name of the JavaScript function (e.g. "fortyTwo") is | |
| 85 /// passed in the @a method parameter as a string pp::Var. If HasMethod() | |
| 86 /// returns @a true, then the browser will call the Call() method to actually | |
| 87 /// invoke the method. | |
| 88 class HelloWorldScriptableObject : public pp::deprecated::ScriptableObject { | |
| 89 public: | |
| 90 /// Determines whether a given method is implemented in this object. | |
| 91 /// @param[in] method A JavaScript string containing the method name to check | |
| 92 /// @param exception Unused | |
| 93 /// @return @a true if @a method is one of the exposed method names. | |
| 94 virtual bool HasMethod(const pp::Var& method, pp::Var* exception); | |
| 95 | |
| 96 /// Invoke the function associated with @a method. The argument list passed | |
| 97 /// via JavaScript is marshaled into a vector of pp::Vars. None of the | |
| 98 /// functions in this example take arguments, so this vector is always empty. | |
| 99 /// @param[in] method A JavaScript string with the name of the method to call | |
| 100 /// @param[in] args A list of the JavaScript parameters passed to this method | |
| 101 /// @param exception unused | |
| 102 /// @return the return value of the invoked method | |
| 103 virtual pp::Var Call(const pp::Var& method, | |
| 104 const std::vector<pp::Var>& args, | |
| 105 pp::Var* exception); | |
| 106 }; | |
| 107 | |
| 108 bool HelloWorldScriptableObject::HasMethod(const pp::Var& method, | |
| 109 pp::Var* exception) { | |
| 110 if (!method.is_string()) { | |
| 111 SetExceptionString(exception, kExceptionMethodNotAString); | |
| 112 return false; | |
| 113 } | |
| 114 std::string method_name = method.AsString(); | |
| 115 return method_name == kReverseTextMethodId || | |
| 116 method_name == kFortyTwoMethodId; | |
| 117 } | |
| 118 | |
| 119 pp::Var HelloWorldScriptableObject::Call(const pp::Var& method, | |
| 120 const std::vector<pp::Var>& args, | |
| 121 pp::Var* exception) { | |
| 122 if (!method.is_string()) { | |
| 123 SetExceptionString(exception, kExceptionMethodNotAString); | |
| 124 return pp::Var(); | |
| 125 } | |
| 126 std::string method_name = method.AsString(); | |
| 127 if (method_name == kReverseTextMethodId) { | |
| 128 // note that the vector of pp::Var |args| is passed to ReverseText | |
| 129 return MarshallReverseText(args); | |
| 130 } else if (method_name == kFortyTwoMethodId) { | |
| 131 // note that no arguments are passed in to FortyTwo. | |
| 132 return MarshallFortyTwo(); | |
| 133 } else { | |
| 134 SetExceptionString(exception, | |
| 135 std::string(kExceptionNoMethodName) + method_name); | |
| 136 } | |
| 137 return pp::Var(); | |
| 138 } | 58 } |
| 139 | 59 |
| 140 /// The Instance class. One of these exists for each instance of your NaCl | 60 /// The Instance class. One of these exists for each instance of your NaCl |
| 141 /// module on the web page. The browser will ask the Module object to create | 61 /// module on the web page. The browser will ask the Module object to create |
| 142 /// a new Instance for each occurrence of the <embed> tag that has these | 62 /// a new Instance for each occurrence of the <embed> tag that has these |
| 143 /// attributes: | 63 /// attributes: |
| 144 /// <pre> | 64 /// <pre> |
| 145 /// type="application/x-nacl" | 65 /// type="application/x-nacl" |
| 146 /// nacl="hello_world.nmf" | 66 /// nacl="hello_world.nmf" |
| 147 /// </pre> | 67 /// </pre> |
| 148 /// The Instance can return a ScriptableObject representing itself. When the | 68 /// The Instance can return a ScriptableObject representing itself. When the |
| 149 /// browser encounters JavaScript that wants to access the Instance, it calls | 69 /// browser encounters JavaScript that wants to access the Instance, it calls |
| 150 /// the GetInstanceObject() method. All the scripting work is done through | 70 /// the GetInstanceObject() method. All the scripting work is done through |
| 151 /// the returned ScriptableObject. | 71 /// the returned ScriptableObject. |
| 152 class HelloWorldInstance : public pp::Instance { | 72 class HelloWorldInstance : public pp::Instance { |
| 153 public: | 73 public: |
| 154 explicit HelloWorldInstance(PP_Instance instance) : pp::Instance(instance) {} | 74 explicit HelloWorldInstance(PP_Instance instance) : pp::Instance(instance) {} |
| 155 virtual ~HelloWorldInstance() {} | 75 virtual ~HelloWorldInstance() {} |
| 156 | 76 |
| 157 /// @return a new pp::deprecated::ScriptableObject as a JavaScript @a Var | 77 /// Called by the browser to handle the postMessage() call in Javascript. |
| 158 /// @note The pp::Var takes over ownership of the HelloWorldScriptableObject | 78 /// Detects which method is being called from the message contents, and |
| 159 /// and is responsible for deallocating memory. | 79 /// calls the appropriate function. Posts the resutl back to the browser |
|
dmichael (off chromium)
2011/05/18 15:43:56
resutl->result
David Springer
2011/05/18 18:01:42
Done.
| |
| 160 virtual pp::Var GetInstanceObject() { | 80 /// asynchronously. |
| 161 HelloWorldScriptableObject* hw_object = new HelloWorldScriptableObject(); | 81 /// @param[in] var_message The message posted by the browser. |
|
garianov
2011/05/18 15:45:19
It would be nice to provide example of the possibl
David Springer
2011/05/18 18:01:42
Done.
| |
| 162 return pp::Var(this, hw_object); | 82 virtual void HandleMessage(const pp::Var& var_message); |
| 83 }; | |
| 84 | |
| 85 void HelloWorldInstance::HandleMessage(const pp::Var& var_message) { | |
| 86 if (!var_message.is_string()) { | |
| 87 return; | |
| 163 } | 88 } |
| 164 }; | 89 std::string message = var_message.AsString(); |
| 90 pp::Var return_var; | |
| 91 if (message == kFortyTwoMethodId) { | |
| 92 // Note that no arguments are passed in to FortyTwo. | |
| 93 return_var = MarshallFortyTwo(); | |
| 94 } else if (message.find(kReverseTextMethodId, | |
| 95 0, | |
| 96 strlen(kReverseTextMethodId)) != std::string::npos) { | |
|
dmichael (off chromium)
2011/05/18 15:43:56
You don't really need the latter 2 arguments, sinc
David Springer
2011/05/18 18:01:42
Done.
| |
| 97 // The argument to reverseText is everything after the first ':'. | |
| 98 size_t sep_pos = message.find_first_of(kMessageArgumentSeparator); | |
| 99 if (sep_pos != std::string::npos) { | |
| 100 std::string string_arg = message.substr(sep_pos + 1); | |
| 101 return_var = MarshallReverseText(string_arg); | |
| 102 } | |
| 103 } | |
| 104 // Post the return result back to the browser. Note that HandleMessage() is | |
| 105 // always called on the main thread, so it's OK to post the return message | |
| 106 // directly from here. The return post is asynhronous: PostMessage returns | |
| 107 // immediately. | |
| 108 PostMessage(return_var); | |
| 109 } | |
| 165 | 110 |
| 166 /// The Module class. The browser calls the CreateInstance() method to create | 111 /// The Module class. The browser calls the CreateInstance() method to create |
| 167 /// an instance of you NaCl module on the web page. The browser creates a new | 112 /// an instance of you NaCl module on the web page. The browser creates a new |
| 168 /// instance for each <embed> tag with | 113 /// instance for each <embed> tag with |
| 169 /// <code>type="application/x-ppapi-nacl-srpc"</code>. | 114 /// <code>type="application/x-ppapi-nacl-srpc"</code>. |
| 170 class HelloWorldModule : public pp::Module { | 115 class HelloWorldModule : public pp::Module { |
| 171 public: | 116 public: |
| 172 HelloWorldModule() : pp::Module() {} | 117 HelloWorldModule() : pp::Module() {} |
| 173 virtual ~HelloWorldModule() {} | 118 virtual ~HelloWorldModule() {} |
| 174 | 119 |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 188 /// The browser keeps a singleton of this module. It calls the | 133 /// The browser keeps a singleton of this module. It calls the |
| 189 /// CreateInstance() method on the object you return to make instances. There | 134 /// CreateInstance() method on the object you return to make instances. There |
| 190 /// is one instance per <embed> tag on the page. This is the main binding | 135 /// is one instance per <embed> tag on the page. This is the main binding |
| 191 /// point for your NaCl module with the browser. | 136 /// point for your NaCl module with the browser. |
| 192 /// @return new HelloWorldModule. | 137 /// @return new HelloWorldModule. |
| 193 /// @note The browser is responsible for deleting returned @a Module. | 138 /// @note The browser is responsible for deleting returned @a Module. |
| 194 Module* CreateModule() { | 139 Module* CreateModule() { |
| 195 return new hello_world::HelloWorldModule(); | 140 return new hello_world::HelloWorldModule(); |
| 196 } | 141 } |
| 197 } // namespace pp | 142 } // namespace pp |
| OLD | NEW |