diff options
author | binji@chromium.org <binji@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-01-23 19:26:04 +0000 |
---|---|---|
committer | binji@chromium.org <binji@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-01-23 19:26:04 +0000 |
commit | bde3d5d020db4aa60e8b1812902209efd322818e (patch) | |
tree | 7386b2c7951bb72a3c216ed5d538755e3a2f2d55 /native_client_sdk/doc_generated/devguide/coding | |
parent | 9fd50a93951dcc2034d1f86dd7358e0f18de1b0d (diff) | |
download | chromium_src-bde3d5d020db4aa60e8b1812902209efd322818e.zip chromium_src-bde3d5d020db4aa60e8b1812902209efd322818e.tar.gz chromium_src-bde3d5d020db4aa60e8b1812902209efd322818e.tar.bz2 |
[NaCl SDK Docs] Check in the generated NaCl SDK Documentation.
This is necessary so that the Chromesite server can poll for changes and
automatically update.
I can't upload the full docs/images to Rietveld, so this review will
just be empty and I'll manually commit.
BUG=none
R=awatson@chromium.org, sbc@chromium.org
Review URL: https://codereview.chromium.org/140993006
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@246665 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'native_client_sdk/doc_generated/devguide/coding')
11 files changed, 3308 insertions, 0 deletions
diff --git a/native_client_sdk/doc_generated/devguide/coding/3D-graphics.html b/native_client_sdk/doc_generated/devguide/coding/3D-graphics.html new file mode 100644 index 0000000..0e7cdb1 --- /dev/null +++ b/native_client_sdk/doc_generated/devguide/coding/3D-graphics.html @@ -0,0 +1,442 @@ +{{+bindTo:partials.standard_nacl_article}} + +<section id="d-graphics"> +<span id="devguide-coding-3d-graphics"></span><h1 id="d-graphics"><span id="devguide-coding-3d-graphics"></span>3D Graphics</h1> +<p>Native Client applications use the <a class="reference external" href="http://en.wikipedia.org/wiki/OpenGL_ES">OpenGL ES 2.0</a> API for 3D rendering. This document +describes how to call the OpenGL ES 2.0 interface in a Native Client module and +how to build an efficient rendering loop. It also explains how to validate GPU +drivers and test for specific GPU capabilities, and provides tips to help ensure +your rendering code runs efficiently.</p> +<aside class="note"> +<strong>Note</strong>: 3D drawing and OpenGL are complex topics. This document deals only +with issues directly related to programming in the Native Client +environment. To learn more about OpenGL ES 2.0 itself, see the <a class="reference external" href="http://opengles-book.com/">OpenGL ES 2.0 +Programming Guide</a>. +</aside> +<section id="validating-the-client-graphics-platform"> +<h2 id="validating-the-client-graphics-platform">Validating the client graphics platform</h2> +<p>Native Client is a software technology that lets you code an application once +and run it on multiple platforms without worrying about the implementation +details on every possible target platform. It’s difficult to provide the same +support at the hardware level. Graphics hardware comes from many different +manufacturers and is controlled by drivers of varying quality. A particular GPU +driver may not support every OpenGL ES 2.0 feature, and some drivers are known +to have vulnerabilities that can be exploited.</p> +<p>Even if the GPU driver is safe to use, your program should perform a validation +check before you launch your application to ensure that the driver supports all +the features you need.</p> +<section id="vetting-the-driver-in-javascript"> +<h3 id="vetting-the-driver-in-javascript">Vetting the driver in JavaScript</h3> +<p>At startup, the application should perform a few additional tests that can be +implemented in JavaScript on its hosting web page. The script that performs +these tests should be included before the module’s <code>embed</code> tag, and ideally +the <code>embed</code> tag should appear on the hosting page only if these tests succeed.</p> +<p>The first thing to check is whether you can create a graphics context. If you +can, use the context to confirm the existence of any required OpenGL ES 2.0 +extensions. You may want to refer to the <a class="reference external" href="http://www.khronos.org/registry/webgl/extensions/">extension registry</a> and include <a class="reference external" href="https://developer.mozilla.org/en-US/docs/WebGL/Using_Extensions">vendor +prefixes</a> +when checking for extensions.</p> +</section><section id="vetting-the-driver-in-native-client"> +<h3 id="vetting-the-driver-in-native-client">Vetting the driver in Native Client</h3> +<section id="create-a-context"> +<h4 id="create-a-context">Create a context</h4> +<p>Once you’ve passed the JavaScript validation tests, it’s safe to add a Native +Client embed tag to the hosting web page and load the module. As part of the +module initialization code, you must create a graphics context for the app by +either creating a C++ <code>Graphics3D</code> object or calling <code>PPB_Graphics3D</code> API +function <code>Create</code>. Don’t assume this will always succeed; you still might have +problems creating the context. If you are in development mode and can’t create +the context, try creating a simpler version to see if you’re asking for an +unsupported feature or exceeding a driver resource limit. Your production code +should always check that the context was created and fail gracefully if that’s +not the case.</p> +</section><section id="check-for-extensions-and-capabilities"> +<h4 id="check-for-extensions-and-capabilities">Check for extensions and capabilities</h4> +<p>Not every GPU supports every extension or has the same amount of texture units, +vertex attributes, etc. On startup, call <code>glGetString(GL_EXTENSIONS)</code> and +check for the extensions and the features you need. For example:</p> +<ul class="small-gap"> +<li>If you are using non power-of-2 texture with mipmaps, make sure +<code>GL_OES_texture_npot</code> exists.</li> +<li>If you are using floating point textures, make sure <code>GL_OES_texture_float</code> +exists.</li> +<li>If you are using DXT1, DXT3, or DXT5 textures, make sure the corresponding +extensions <code>EXT_texture_compression_dxt1</code>, +<code>GL_CHROMIUM_texture_compression_dxt3</code>, and +<code>GL_CHROMIUM_texture_compression_dxt5</code> exist.</li> +<li>If you are using the functions <code>glDrawArraysInstancedANGLE</code>, +<code>glDrawElementsInstancedANGLE</code>, <code>glVertexAttribDivisorANGLE</code>, or the PPAPI +interface <code>PPB_OpenGLES2InstancedArrays</code>, make sure the corresponding +extension <code>GL_ANGLE_instanced_arrays</code> exists.</li> +<li>If you are using the function <code>glRenderbufferStorageMultisampleEXT</code>, or the +PPAPI interface <code>PPB_OpenGLES2FramebufferMultisample</code>, make sure the +corresponding extension <code>GL_CHROMIUM_framebuffer_multisample</code> exists.</li> +<li>If you are using the functions <code>glGenQueriesEXT</code>, <code>glDeleteQueriesEXT</code>, +<code>glIsQueryEXT</code>, <code>glBeginQueryEXT</code>, <code>glEndQueryEXT</code>, <code>glGetQueryivEXT</code>, +<code>glGetQueryObjectuivEXT</code>, or the PPAPI interface <code>PPB_OpenGLES2Query</code>, +make sure the corresponding extension <code>GL_EXT_occlusion_query_boolean</code> +exists.</li> +<li>If you are using the functions <code>glMapBufferSubDataCHROMIUM</code>, +<code>glUnmapBufferSubDataCHROMIUM</code>, <code>glMapTexSubImage2DCHROMIUM</code>, +<code>glUnmapTexSubImage2DCHROMIUM</code>, or the PPAPI interface +<code>PPB_OpenGLES2ChromiumMapSub</code>, make sure the corresponding extension +<code>GL_CHROMIUM_map_sub</code> exists.</li> +</ul> +<p>Check for system capabilites with <code>glGetIntegerv</code> and adjust shader programs +as well as texture and vertex data accordingly:</p> +<ul class="small-gap"> +<li>If you are using textures in vertex shaders, make sure +<code>glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, ...)</code> and +<code>glGetIntegerv(GL_MAX_TEXTURE_SIZE, ...)</code> return values greater than 0.</li> +<li>If you are using more than 8 textures in a single shader, make sure +<code>glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, ...)</code> returns a value greater +than or equal to the number of simultaneous textures you need.</li> +</ul> +</section></section><section id="vetting-the-driver-in-the-chrome-web-store"> +<h3 id="vetting-the-driver-in-the-chrome-web-store">Vetting the driver in the Chrome Web Store</h3> +<p>If you choose to place your application in the <a class="reference external" href="https://developers.google.com/chrome/web-store/docs/">Chrome Web +Store</a>, its Web Store +<a class="reference external" href="http://code.google.com/chrome/extensions/manifest.html">manifest file</a> can +include the <code>webgl</code> feature in the requirements parameter. It looks like this:</p> +<pre class="prettyprint"> +"requirements": { + "3D": { + "features": ["webgl"] + } +} +</pre> +<p>While WebGL is technically a JavaScript API, specifying the <code>webgl</code> feature +also works for OpenGL ES 2.0 because both interfaces use the same driver.</p> +<p>This manifest item is not required, but if you include it, the Chrome Web Store +will prevent a user from installing the application if the browser is running on +a machine that does not support OpenGL ES 2.0 or that is using a known +blacklisted GPU driver that could invite an attack.</p> +<p>If the Web Store determines that the user’s driver is deficient, the app won’t +appear on the store’s tile display. However, it will appear in store search +results or if the user links to it directly, in which case the user could still +download it. But the manifest requirements will be checked when the user reaches +the install page, and if there is a problem, the browser will display the +message “This application is not supported on this computer. Installation has +been disabled.”</p> +<p>The manifest-based check applies only to downloads directly from the Chrome Web +Store. It is not performed when an application is loaded via <a class="reference external" href="https://developers.google.com/chrome/web-store/docs/inline_installation">inline +installation</a>.</p> +</section><section id="what-to-do-when-there-are-problems"> +<h3 id="what-to-do-when-there-are-problems">What to do when there are problems</h3> +<p>Using the vetting procedure described above, you should be able to detect the +most common problems before your application runs. If there are problems, your +code should describe the issue as clearly as possible. That’s easy if there is a +missing feature. Failure to create a graphics context is tougher to diagnose. At +the very least, you can suggest that the user try to update the driver. You +might want to linke to the Chrome page that describes <a class="reference external" href="http://support.google.com/chrome/bin/answer.py?hl=en&answer=1202946">how to do updates</a>.</p> +<p>If a user can’t update the driver, or their problem persists, be sure to gather +information about their graphics environment. Ask for the contents of the Chrome +<code>about:gpu</code> page.</p> +</section><section id="document-unreliable-drivers"> +<h3 id="document-unreliable-drivers">Document unreliable drivers</h3> +<p>It can be helpful to include information about known dubious drivers in your +user documentation. This might help identify if a rogue driver is the cause of a +problem. There are many sources of GPU driver blacklists. Two such lists can be +found at the <a class="reference external" href="http://src.chromium.org/viewvc/chrome/trunk/deps/gpu/software_rendering_list/software_rendering_list.json">Chromium project</a> +and <a class="reference external" href="http://www.khronos.org/webgl/wiki/BlacklistsAndWhitelists">Khronos</a>. You +can use these lists to include information in your documentation that warns +users about dangerous drivers.</p> +</section><section id="test-your-defenses"> +<h3 id="test-your-defenses">Test your defenses</h3> +<p>You can test your driver validation code by running Chrome with the following +flags (all at once) and watching how your application responds:</p> +<ul class="small-gap"> +<li><code>--disable-webgl</code></li> +<li><code>--disable-pepper-3d</code></li> +<li><code>--disable-gl-multisampling</code></li> +<li><code>--disable-accelerated-compositing</code></li> +<li><code>--disable-accelerated-2d-canvas</code></li> +</ul> +</section></section><section id="calling-opengl-es-2-0-commands"> +<h2 id="calling-opengl-es-2-0-commands">Calling OpenGL ES 2.0 commands</h2> +<p>There are three ways to write OpenGL ES 2.0 calls in Native Client.</p> +<section id="use-pure-opengl-es-2-0-function-calls"> +<h3 id="use-pure-opengl-es-2-0-function-calls">Use “pure” OpenGL ES 2.0 function calls</h3> +<p>You can make OpenGL ES 2.0 calls through a Pepper extension library. The SDK +example <code>examples/api/graphics_3d</code> works this way. In the file +<code>graphics_3d.cc</code>, the key initialization steps are as follows:</p> +<ul class="small-gap"> +<li><p class="first">Add these includes at the top of the file:</p> +<pre class="prettyprint"> +#include <GLES2/gl2.h> +#include "ppapi/lib/gl/gles2/gl2ext_ppapi.h" +</pre> +</li> +<li><p class="first">Define the function <code>InitGL</code>. The exact specification of <code>attrib_list</code> +will be application specific.</p> +<pre class="prettyprint"> +bool InitGL(int32_t new_width, int32_t new_height) { + if (!glInitializePPAPI(pp::Module::Get()->get_browser_interface())) { + fprintf(stderr, "Unable to initialize GL PPAPI!\n"); + return false; + } + + const int32_t attrib_list[] = { + PP_GRAPHICS3DATTRIB_ALPHA_SIZE, 8, + PP_GRAPHICS3DATTRIB_DEPTH_SIZE, 24, + PP_GRAPHICS3DATTRIB_WIDTH, new_width, + PP_GRAPHICS3DATTRIB_HEIGHT, new_height, + PP_GRAPHICS3DATTRIB_NONE + }; + + context_ = pp::Graphics3D(this, attrib_list); + if (!BindGraphics(context_)) { + fprintf(stderr, "Unable to bind 3d context!\n"); + context_ = pp::Graphics3D(); + glSetCurrentContextPPAPI(0); + return false; + } + + glSetCurrentContextPPAPI(context_.pp_resource()); + return true; +} +</pre> +</li> +<li>Include logic in <code>Instance::DidChangeView</code> to call <code>InitGL</code> whenever +necessary: upon application launch (when the graphics context is NULL) and +whenever the module’s View changes size.</li> +</ul> +</section><section id="use-regal"> +<h3 id="use-regal">Use Regal</h3> +<p>If you are porting an OpenGL ES 2.0 application, or are comfortable writing in +OpenGL ES 2.0, you should stick with the Pepper APIs or pure OpenGL ES 2.0 calls +described above. If you are porting an application that uses features not in +OpenGL ES 2.0, consider using Regal. Regal is an open source library that +supports many versions of OpenGL. Regal recently added support for Native +Client. Regal forwards most OpenGL calls directly to the underlying graphics +library, but it can also emulate other calls that are not included (when +hardware support exists). See <a class="reference external" href="http://www.altdevblogaday.com/2012/09/04/bringing-regal-opengl-to-native-client/">libregal</a> +for more info.</p> +</section><section id="use-the-pepper-api"> +<h3 id="use-the-pepper-api">Use the Pepper API</h3> +<p>Your code can call the Pepper <a class="reference external" href="https://developers.google.com/native-client/pepperc/struct_p_p_b___open_g_l_e_s2">PPB_OpenGLES2</a> +API directly, as with any Pepper interface. When you write in this way, each +invocation of an OpenGL ES 2.0 function must begin with a reference to the +Pepper interface, and the first argument is the graphics context. To invoke the +function <code>glCompileShader</code>, your code might look like:</p> +<pre class="prettyprint"> +ppb_g3d_interface->CompileShader(graphicsContext, shader); +</pre> +<p>This approach specifically targets the Pepper APIs. Each call corresponds to a +OpenGL ES 2.0 function, but the syntax is unique to Native Client, so the source +file is not portable.</p> +</section></section><section id="implementing-a-rendering-loop"> +<h2 id="implementing-a-rendering-loop">Implementing a rendering loop</h2> +<p>Graphics applications require a continuous frame render-and-redraw cycle that +runs at a high frequency. To achieve the best frame rate, is important to +understand how the OpenGL ES 2.0 code in a Native Client module interacts with +Chrome.</p> +<section id="the-chrome-and-native-client-processes"> +<h3 id="the-chrome-and-native-client-processes">The Chrome and Native Client processes</h3> +<p>Chrome is a multi-process browser. Each Chrome tab is a separate process that is +running an application with its own main thread (we’ll call it the Chrome main +thread). When an application launches a Native Client module, the module runs in +a new, separate sandboxed process. The module’s process has its own main thread +(the Native Client thread). The Chrome and Native Client processes communicate +with each other using Pepper API calls on their main threads.</p> +<p>When the Chrome main thread calls the Native Client thread (keyboard and mouse +callbacks, for example), the Chrome main thread will block. This means that +lengthy operations on the Native Client thread can steal cycles from Chrome, and +performing blocking operations on the Native Client thread can bring your app to +a standstill.</p> +<p>Native Client uses callback functions to synchronize the main threads of the two +processes. Only certain Pepper functions use callbacks; <a class="reference external" href="https://developers.google.com/native-client/pepperc/struct_p_p_b___graphics3_d__1__0#a293c6941c0da084267ffba3954793497">SwapBuffers</a> +is one.</p> +</section><section id="swapbuffers-and-its-callback-function"> +<h3 id="swapbuffers-and-its-callback-function"><code>SwapBuffers</code> and its callback function</h3> +<p><code>SwapBuffers</code> is non-blocking; it is called from the Native Client thread and +returns immediately. When <code>SwapBuffers</code> is called, it runs asynchronously on +the Chrome main thread. It switches the graphics data buffers, handles any +needed compositing operations, and redraws the screen. When the screen update is +complete, the callback function that was included as one of <code>SwapBuffer</code>‘s +arguments will be called from the Chrome thread and executed on the Native +Client thread.</p> +<p>To create a rendering loop, your Native Client module should include a function +that does the rendering work and then executes <code>SwapBuffers</code>, passing itself +as the <code>SwapBuffer</code> callback. If your rendering code is efficient and runs +quickly, this scheme will achieve the highest frame rate possible. The +documentation for <code>SwapBuffers</code> explains why this is optimal: because the +callback is executed only when the plugin’s current state is actually on the +screen, this function provides a way to rate-limit animations. By waiting until +the image is on the screen before painting the next frame, you can ensure you’re +not generating updates faster than the screen can be updated.</p> +<p>The following diagram illustrates the interaction between the Chrome and Native +Client processes. The application-specific rendering code runs in the function +called <code>Draw</code> on the Native Client thread. Blue down-arrows are blocking calls +from the main thread to Native Client, green up-arrows are non-blocking +<code>SwapBuffers</code> calls from Native Client to the main thread. All OpenGL ES 2.0 +calls are made from <code>Draw</code> in the Native Client thread.</p> +<img alt="/native-client/images/3d-graphics-render-loop.png" src="/native-client/images/3d-graphics-render-loop.png" /> +</section><section id="sdk-example-graphics-3d"> +<h3 id="sdk-example-graphics-3d">SDK example <code>graphics_3d</code></h3> +<p>The SDK example <code>graphics_3d</code> uses the function <code>MainLoop</code> (in +<code>hello_world.cc</code>) to create a rendering loop as described above. <code>MainLoop</code> +calls <code>Render</code> to do the rendering work, and then invokes <code>SwapBuffers</code>, +passing itself as the callback.</p> +<pre class="prettyprint"> +void MainLoop(void* foo, int bar) { + if (g_LoadCnt == 3) { + InitProgram(); + g_LoadCnt++; + } + if (g_LoadCnt > 3) { + Render(); + PP_CompletionCallback cc = PP_MakeCompletionCallback(MainLoop, 0); + ppb_g3d_interface->SwapBuffers(g_context, cc); + } else { + PP_CompletionCallback cc = PP_MakeCompletionCallback(MainLoop, 0); + ppb_core_interface->CallOnMainThread(0, cc, 0); + } +} +</pre> +</section></section><section id="managing-the-opengl-es-2-0-pipeline"> +<h2 id="managing-the-opengl-es-2-0-pipeline">Managing the OpenGL ES 2.0 pipeline</h2> +<p>OpenGL ES 2.0 commands do not run in the Chrome or Native Client processes. They +are passed into a FIFO queue in shared memory which is best understood as a <a class="reference external" href="http://www.chromium.org/developers/design-documents/gpu-command-buffer">GPU +command buffer</a>. The +command buffer is shared by a dedicated GPU process. By using a separate GPU +process, Chrome implements another layer of runtime security, vetting all OpenGL +ES 2.0 commands and their arguments before they are sent on to the +GPU. Buffering commands through the FIFO also speeds up your code, since each +OpenGL ES 2.0 call in your Native Client thread returns immediately, while the +processing may be delayed as the GPU works down the commands queued up in the +FIFO.</p> +<p>Before the screen is updated, all the intervening OpenGL ES 2.0 commands must be +processed by the GPU. Programmers often try to ensure this by using the +<code>glFlush</code> and <code>glFinish</code> commands in their rendering code. In the case of +Native Client this is usually unnecessary. The <code>SwapBuffers</code> command does an +implicit flush, and the Chrome team is continually tweaking the GPU code to +consume the OpenGL ES 2.0 FIFO as fast as possible.</p> +<p>Sometimes a 3D application can write to the FIFO in a way that’s difficult to +handle. The command pipeline may fill up and your code will have to wait for the +GPU to flush the FIFO. If this is the case, you may be able to add <code>glFlush</code> +calls to speed up the flow of the OpenGL ES 2.0 command FIFO. Before you start +to add your own flushes, first try to determine if pipeline saturation is really +the problem by monitoring the rendering time per frame and looking for irregular +spikes that do not consistently fall on the same OpenGL ES 2.0 call. If you’re +convinced the pipeline needs to be accelerated, insert <code>glFlush</code> calls in your +code before starting blocks of processing that do not generate OpenGL ES 2.0 +commands. For example, issue a flush before you begin any multithreaded particle +work, so that the command buffer will be clear when you start doing OpenGL ES +2.0 calls again. Determining where and how often to call <code>glFlush</code> can be +tricky, you will need to experiment to find the sweet spot.</p> +</section><section id="rendering-and-inactive-tabs"> +<h2 id="rendering-and-inactive-tabs">Rendering and inactive tabs</h2> +<p>Users will often switch between tabs in a multi-tab browser. A well-behaved +application that’s performing 3D rendering should pause any real-time processing +and yield cycles to other processes when its tab becomes inactive.</p> +<p>In Chrome, an inactive tab will continue to execute timed functions (such as +<code>setInterval</code> and <code>setTimeout</code>) but the timer interval will be automatically +overridden and limited to not less than one second while the tab is inactive. In +addition, any callback associated with a <code>SwapBuffers</code> call will not be sent +until the tab is active again. You may receive asynchronous callbacks from +functions other than <code>SwapBuffers</code> while a tab is inactive. Depending on the +design of your application, you might choose to handle them as they arrive, or +to queue them in a buffer and process them when the tab becomes active.</p> +<p>The time that passes while a tab is inactive can be considerable. If your main +thread pulse is based on the <code>SwapBuffers</code> callback, your app won’t update +while a tab is inactive. A Native Client module should be able to detect and +respond to the state of the tab in which it’s running. For example, when a tab +becomes inactive, you can set an atomic flag in the Native Client thread that +will skip the 3D rendering and <code>SwapBuffers</code> calls and continue to call the +main thread every 30 msec or so. This provides time to update features that +should still run in the background, like audio. It may also be helpful to call +<code>sched_yield</code> or <code>usleep</code> on any worker threads to release resources and +cede cycles to the OS.</p> +<section id="handling-tab-activation-from-the-main-thread"> +<h3 id="handling-tab-activation-from-the-main-thread">Handling tab activation from the main thread</h3> +<p>You can detect and respond to the activation or deactivation of a tab with +JavaScript on your hosting page. Add an EventListener for <code>visibilitychange</code> +that sends a message to the Native Client module, as in this example:</p> +<pre class="prettyprint"> +document.addEventListener('visibilitychange', function(){ + if (document.hidden) { + // PostMessage to your Native Client module + document.nacl_module.postMessage('INACTIVE'); + } else { + // PostMessage to your Native Client module + document.nacl_module.postMessage('ACTIVE'); + } + +}, false); +</pre> +</section><section id="handling-tab-activation-from-the-native-client-thread"> +<h3 id="handling-tab-activation-from-the-native-client-thread">Handling tab activation from the Native Client thread</h3> +<p>You can also detect and respond to the activation or deactivation of a tab +directly from your Native Client module by including code in the function +<code>pp::Instance::DidChangeView</code>, which is called whenever a change in the +module’s view occurs. The code can call <code>ppb::View::IsPageVisible</code> to +determine if the page is visible or not. The most common cause of invisible +pages is that the page is in a background tab.</p> +</section></section><section id="tips-and-best-practices"> +<h2 id="tips-and-best-practices">Tips and best practices</h2> +<p>Here are some suggestions for writing safe code and getting the maximum +performance with the Pepper 3D API.</p> +<section id="do-s"> +<h3 id="do-s">Do’s</h3> +<ul class="small-gap"> +<li><p class="first"><strong>Make sure to enable attrib 0.</strong> OpenGL requires that you enable attrib 0, +but OpenGL ES 2.0 does not. For example, you can define a vertex shader with 2 +attributes, numbered like this:</p> +<pre class="prettyprint"> +glBindAttribLocation(program, "positions", 1); +glBindAttribLocation(program, "normals", 2); +</pre> +<p>In this case the shader is not using attrib 0 and Chrome may have to perform +some additional work if it is emulating OpenGL ES 2.0 on top of OpenGL. It’s +always more efficient to enable attrib 0, even if you do not use it.</p> +</li> +<li><strong>Check how shaders compile.</strong> Shaders can compile differently on different +systems, which can result in <code>glGetAttrib*</code> functions returning different +results. Be sure that the vertex attribute indices match the corresponding +name each time you recompile a shader.</li> +<li><strong>Update indices sparingly.</strong> For security reasons, all indices must be +validated. If you change indices, Native Client will validate them +again. Structure your code so indices are not updated often.</li> +<li><strong>Use a smaller plugin and let CSS scale it.</strong> If you’re running into fillrate +issues, it may be beneficial to perform scaling via CSS. The size your plugin +renders is determined by the width and height attributes of the <code><embed></code> +element for the module. The actual size displayed on the web page is +controlled by the CSS styles applied to the element.</li> +<li><strong>Avoid matrix-to-matrix conversions.</strong> With some versions of Mac OS, there is +a driver problem when compiling shaders. If you get compiler errors for matrix +transforms, avoid matrix-to-matrix conversions. For instance, upres a vec3 to +a vec4 before transforming it by a mat4, rather than converting the mat4 to a +mat3.</li> +</ul> +</section><section id="don-ts"> +<h3 id="don-ts">Don’ts</h3> +<ul class="small-gap"> +<li><strong>Don’t use client side buffers.</strong> OpenGL ES 2.0 can use client side data with +<code>glVertexAttribPointer</code> and <code>glDrawElements</code>, but this is really slow. Try +to avoid client side buffers. Use Vertex Buffer Objects (VBOs) instead.</li> +<li><strong>Don’t mix vertex data and index data.</strong> By default, Pepper 3D binds buffers +to a single point. You could create a buffer and bind it to both +<code>GL_ARRAY_BUFFER</code> and <code>GL_ELEMENT_ARRAY_BUFFER</code>, but that would be +expensive overhead and it is not recommended.</li> +<li><strong>Don’t call ``glGet*`` or ``glCheck*`` during rendering.</strong> This is normal +advice for OpenGL programs, but is particularly important for 3D on +Chrome. Calls to any OpenGL ES 2.0 function whose name begins with these +strings blocks the Native Client thread. This includes <code>glGetError</code>; avoid +calling it in release builds.</li> +<li><strong>Don’t use fixed point (``GL_FIXED``) vertex attributes.</strong> Fixed point +attributes are not supported in OpenGL ES 2.0, so emulating them in OpenGL ES +2.0 is slow. By default, <code>GL_FIXED</code> support is turned off in the Pepper 3D +API.</li> +<li><strong>Don’t read data from the GPU.</strong> Don’t call <code>glReadPixels</code>, as it is slow.</li> +<li><strong>Don’t update a small portion of a large buffer.</strong> In the current OpenGL ES +2.0 implementation when you update a portion of a buffer (with +<code>glSubBufferData</code> for example) the entire buffer must be reprocessed. To +avoid this problem, keep static and dynamic data in different buffers.</li> +<li><strong>Don’t call ``glDisable(GL_TEXTURE_2D)``.</strong> This is an OpenGL ES 2.0 +error. Each time it is called, an error messages will appear in Chrome’s +<code>about:gpu</code> tab.</li> +</ul> +</section></section></section> + +{{/partials.standard_nacl_article}} diff --git a/native_client_sdk/doc_generated/devguide/coding/application-structure.html b/native_client_sdk/doc_generated/devguide/coding/application-structure.html new file mode 100644 index 0000000..89ee979 --- /dev/null +++ b/native_client_sdk/doc_generated/devguide/coding/application-structure.html @@ -0,0 +1,216 @@ +{{+bindTo:partials.standard_nacl_article}} + +<section id="application-structure"> +<span id="devcycle-application-structure"></span><h1 id="application-structure"><span id="devcycle-application-structure"></span>Application Structure</h1> +<div class="contents local topic" id="contents"> +<ul class="small-gap"> +<li><a class="reference internal" href="#application-components" id="id1">Application components</a></li> +<li><a class="reference internal" href="#html-file-and-the-embed-element" id="id2">HTML file and the <embed> element</a></li> +<li><a class="reference internal" href="#manifest-files" id="id3">Manifest Files</a></li> +<li><a class="reference internal" href="#modules-and-instances" id="id4">Modules and instances</a></li> +<li><a class="reference internal" href="#native-client-modules-a-closer-look" id="id5">Native Client modules: A closer look</a></li> +</ul> +</div> +<p>This chapter of the Developer’s Guide describes the general structure of a +Native Client application. The chapter assumes you are familiar with the +material presented in the <a class="reference internal" href="/native-client/overview.html"><em>Technical Overview</em></a>.</p> +<aside class="note"> +The “Hello, World” example is used here to illustrate basic +Native Client programming techniques. You can find this code in the +<em>/getting_started/part1</em> directory in the Native Client SDK download. +</aside> +<section id="application-components"> +<h2 id="application-components">Application components</h2> +<p>A Native Client application typically contains the following components:</p> +<ul class="small-gap"> +<li>an HTML file;</li> +<li>JavaScript code, which can be included in the HTML file or contained in one or +more separate .js files;</li> +<li>CSS styles, which can be included in the HTML file or contained in one or more +separate .css files;</li> +<li>a Native Client manifest file (with a .nmf extension) that specifies how to +load a Native Client module for different processors; and</li> +<li>a Native Client module, written in C or C++, and compiled into a portable +executable file (with a .pexe extension) or (if using the Chrome Web Store), +architecture-specific executable files (with .nexe extensions).</li> +</ul> +<p>Applications that are published in the <a class="reference external" href="https://chrome.google.com/webstore/search?q=%22Native+Client%22+OR+NativeClient+OR+NaCl">Chrome Web Store</a> +also include a Chrome +Web Store manifest file <code>(manifest.json)</code> and one or more icon files.</p> +</section><section id="html-file-and-the-embed-element"> +<span id="html-file"></span><h2 id="html-file-and-the-embed-element"><span id="html-file"></span>HTML file and the <embed> element</h2> +<p>The <code><embed></code> element in an HTML file triggers the loading of a Native Client +module and specifies the rectangle on the web page that is managed by the +module. Here is the <embed> element from the “Hello, World” application:</p> +<pre class="prettyprint"> +<embed id="hello_tutorial" + width=0 height=0 + src="hello_tutorial.nmf" + type="application/x-pnacl" /> +</pre> +<p>In the <code><embed></code> element:</p> +<dl class="docutils"> +<dt>name</dt> +<dd>is the DOM name attribute for the Native Client module +(“nacl_module” is often used as a convention)</dd> +<dt>id</dt> +<dd>specifies the DOM ID for the Native Client module</dd> +<dt>width, height</dt> +<dd>specify the size in pixels of the rectangle on the web page that is +managed by the Native Client module (if the module does not have a +visible area, these values can be 0)</dd> +<dt>src</dt> +<dd>refers to the Native Client manifest file that is used to determine +which version of a module to load based on the architecture of the +user’s computer (see the following section for more information)</dd> +<dt>type</dt> +<dd>specifies the MIME type of the embedded content; for Portable Native Client +modules the type must be “application/x-pnacl”. For architecture-specific +Native Client modules the type must be “application/x-nacl”</dd> +</dl> +</section><section id="manifest-files"> +<span id="manifest-file"></span><h2 id="manifest-files"><span id="manifest-file"></span>Manifest Files</h2> +<p>Native Client applications have two types of manifest files: a Chrome Web Store +manifest file and a Native Client manifest file.</p> +<p>A <strong>Chrome Web Store manifest file</strong> is a file with information about a web +application that is published in the Chrome Web Store. This file, named +<code>manifest.json</code>, is required for applications that are published in the Chrome +Web Store. For more information about this file see <a class="reference internal" href="/native-client/devguide/distributing.html"><em>Distributing Your +Application</em></a>. and the <a class="reference external" href="http://code.google.com/chrome/extensions/manifest.html">Chrome Web Store manifest file format</a>.</p> +<p>A <strong>Native Client manifest file</strong> is a file that specifies which Native Client +module (executable) to load. For PNaCl it specifies a single portable +executable; otherwise it specifies one for each of the supported end-user +computer architectures (for example x86-32, x86-64, or ARM). This file is +required for all Native Client applications. The extension for this file is +.nmf.</p> +<p>Manifest files for applications that use PNaCl are simple. Here is the manifest +for the hello world example:</p> +<pre class="prettyprint"> +{ + "program": { + "portable": { + "pnacl-translate": { + "url": "hello_tutorial.pexe" + } + } + } +} +</pre> +<p>For Chrome Web Store applications that do not use PNaCl, a typical manifest file +contains a <a class="reference external" href="http://www.json.org/">JSON</a> dictionary with a single top-level +key/value pair: the “program” key and a value consisting of a nested +dictionary. The nested dictionary contains keys corresponding to the names of +the supported computer architectures, and values referencing the file to load +for a given architecture—specifically, the URL of the .nexe file, given by the +<code>"url"</code> key. URLs are specified relative to the location of the manifest file. +Here is an example:</p> +<pre class="prettyprint"> +{ + "program": { + "x86-32": { + "url": "hello_tutorial_x86_32.nexe" + }, + "x86-64": { + "url": "hello_tutorial_x86_64.nexe" + }, + "arm": { + "url": "hello_tutorial_arm.nexe" + } + } +} +</pre> +<p>For applications that use the <a class="reference internal" href="/native-client/devguide/devcycle/dynamic-loading.html#c-libraries"><em>glibc</em></a> +library, the manifest file must also contain a “files” key that specifies the +shared libraries that the applications use. This is discussed in detail in +<a class="reference internal" href="/native-client/devguide/devcycle/dynamic-loading.html"><em>Dynamic Linking and Loading with glibc</em></a>. To +see some example manifest files, build some of the example applications in the +SDK (run <code>make</code> in the example subdirectories) and look at the generated +manifest files.</p> +<p>In most cases, you can simply use the Python script provided with the SDK, +<code>create_nmf.py</code>, to create a manifest file for your application as part of the +compilation step (see the Makefile in any of the SDK examples for an +illustration of how to do so). The manifest file format is also +<a class="reference internal" href="/native-client/reference/nacl-manifest-format.html"><em>documented</em></a>.</p> +</section><section id="modules-and-instances"> +<h2 id="modules-and-instances">Modules and instances</h2> +<p>A Native Client <strong>module</strong> is C or C++ code compiled into a PNaCl .pexe file or +a NaCl .nexe file.</p> +<p>An <strong>instance</strong> is a rectangle on a web page that is managed by a module. An +instance may have a dimension of width=0 and height=0, meaning that the instance +does not have any visible component on the web page. An instance is created by +including an <code><embed></code> element in a web page. The <code><embed></code> element +references a Native Client manifest file that loads the appropriate version of +the module (either portable, or specific to the end-user’s architecture). A +module may be included in a web page multiple times by using multiple +<code><embed></code> elements that refer to the module; in this case the Native Client +runtime system loads the module once and creates multiple instances that are +managed by the module.</p> +</section><section id="native-client-modules-a-closer-look"> +<h2 id="native-client-modules-a-closer-look">Native Client modules: A closer look</h2> +<p>A Native Client module must include three components:</p> +<ul class="small-gap"> +<li>a factory function called <code>CreateModule()</code></li> +<li>a Module class (derived from the <code>pp::Module</code> class)</li> +<li>an Instance class (derived from the <code>pp:Instance</code> class)</li> +</ul> +<p>In the “Hello tutorial” example (in the <code>getting_started/part1</code> directory of +the NaCl SDK), these three components are specified in the file +<code>hello_tutorial.cc</code>. Here is the factory function:</p> +<pre class="prettyprint"> +Module* CreateModule() { + return new HelloTutorialModule(); +} +</pre> +<p>Native Client modules do not have a <code>main()</code> function. The <code>CreateModule()</code> +factory function is the main binding point between a module and the browser, and +serves as the entry point into the module. The browser calls <code>CreateModule()</code> +when a module is first loaded; this function returns a Module object derived +from the <code>pp::Module</code> class. The browser keeps a singleton of the Module +object.</p> +<p>Below is the Module class from the “Hello tutorial” example:</p> +<pre class="prettyprint"> +class HelloTutorialModule : public pp::Module { + public: + HelloTutorialModule() : pp::Module() {} + virtual ~HelloTutorialModule() {} + + virtual pp::Instance* CreateInstance(PP_Instance instance) { + return new HelloTutorialInstance(instance); + } +}; +</pre> +<p>The Module class must include a <code>CreateInstance()</code> method. The browser calls +the <code>CreateInstance()</code> method every time it encounters an <code><embed></code> element +on a web page that references the same module. The <code>CreateInstance()</code> function +creates and returns an Instance object derived from the <code>pp::Instance</code> class.</p> +<p>Below is the Instance class from the “Hello tutorial” example:</p> +<pre class="prettyprint"> +class HelloTutorialInstance : public pp::Instance { + public: + explicit HelloTutorialInstance(PP_Instance instance) : pp::Instance(instance) {} + virtual ~HelloTutorialInstance() {} + + virtual void HandleMessage(const pp::Var& var_message) {} +}; +</pre> +<p>As in the example above, the Instance class for your module will likely include +an implementation of the <code>HandleMessage()</code> function. The browser calls an +instance’s <code>HandleMessage()</code> function every time the JavaScript code in an +application calls <code>postMessage()</code> to send a message to the instance. See the +<a class="reference internal" href="/native-client/devguide/coding/message-system.html"><em>Native Client messaging system</em></a> for more information about +how to send messages between JavaScript code and Native Client modules.</p> +<p>The NaCl code is only invoked to handle various browser-issued +events and callbacks. There is no need to shut down the NaCl instance by +calling the <code>exit()</code> function. NaCl modules will be shut down when the user +leaves the web page, or the NaCl module’s <code><embed></code> is otherwise destroyed. +If the NaCl module does call the <code>exit()</code> function, the instance will +issue a <code>crash</code> event +<a class="reference internal" href="/native-client/devguide/coding/progress-events.html"><em>which can be handled in Javascript</em></a>.</p> +<p>While the <code>CreateModule()</code> factory function, the <code>Module</code> class, and the +<code>Instance</code> class are required for a Native Client application, the code +samples shown above don’t actually do anything. Subsequent chapters in the +Developer’s Guide build on these code samples and add more interesting +functionality.</p> +</section></section> + +{{/partials.standard_nacl_article}} diff --git a/native_client_sdk/doc_generated/devguide/coding/audio.html b/native_client_sdk/doc_generated/devguide/coding/audio.html new file mode 100644 index 0000000..a4b65bb --- /dev/null +++ b/native_client_sdk/doc_generated/devguide/coding/audio.html @@ -0,0 +1,352 @@ +{{+bindTo:partials.standard_nacl_article}} + +<section id="audio"> +<span id="devguide-coding-audio"></span><h1 id="audio"><span id="devguide-coding-audio"></span>Audio</h1> +<div class="contents local topic" id="contents"> +<ul class="small-gap"> +<li><a class="reference internal" href="#reference-information" id="id1">Reference information</a></li> +<li><a class="reference internal" href="#about-the-pepper-audio-api" id="id2">About the Pepper audio API</a></li> +<li><a class="reference internal" href="#digital-audio-concepts" id="id3">Digital audio concepts</a></li> +<li><a class="reference internal" href="#setting-up-the-module" id="id4">Setting up the module</a></li> +<li><p class="first"><a class="reference internal" href="#creating-an-audio-configuration-resource" id="id5">Creating an audio configuration resource</a></p> +<ul class="small-gap"> +<li><a class="reference internal" href="#resources" id="id6">Resources</a></li> +<li><a class="reference internal" href="#sample-frame-count" id="id7">Sample frame count</a></li> +<li><a class="reference internal" href="#supported-audio-configurations" id="id8">Supported audio configurations</a></li> +</ul> +</li> +<li><a class="reference internal" href="#creating-an-audio-resource" id="id9">Creating an audio resource</a></li> +<li><p class="first"><a class="reference internal" href="#implementing-a-callback-function" id="id10">Implementing a callback function</a></p> +<ul class="small-gap"> +<li><a class="reference internal" href="#application-threads-and-real-time-requirements" id="id11">Application threads and real-time requirements</a></li> +</ul> +</li> +<li><a class="reference internal" href="#starting-and-stopping-playback" id="id12">Starting and stopping playback</a></li> +</ul> +</div> +<p>This chapter describes how to use the Pepper audio API to play an audio +stream. The Pepper audio API provides a low-level means of playing a stream of +audio samples generated by a Native Client module. The API generally works as +follows: A Native Client module creates an audio resource that represents an +audio stream, and tells the browser to start or stop playing the audio +resource. The browser calls a function in the Native Client module to fill a +buffer with audio samples every time it needs data to play from the audio +stream.</p> +<p>The code examples in this chapter describe a simple Native Client module that +generates audio samples using a sine wave with a frequency of 440 Hz. The module +starts playing the audio samples as soon as it is loaded into the browser. For a +slightly more sophisticated example, see the <code>audio</code> example (source code in +the SDK directory <code>examples/api/audio</code>), which lets users specify a frequency +for the sine wave and click buttons to start and stop audio playback.</p> +<section id="reference-information"> +<h2 id="reference-information">Reference information</h2> +<p>For reference information related to the Pepper audio API, see the following +documentation:</p> +<ul class="small-gap"> +<li><a class="reference external" href="https://developers.google.com/native-client/peppercpp/classpp_1_1_audio_config">pp::AudioConfig class</a></li> +<li><a class="reference external" href="https://developers.google.com/native-client/peppercpp/classpp_1_1_audio">pp::Audio class</a></li> +<li><a class="reference external" href="https://developers.google.com/native-client/peppercpp/audio__config_8h">audio_config.h</a></li> +<li><a class="reference external" href="https://developers.google.com/native-client/peppercpp/audio_8h">audio.h</a></li> +<li><a class="reference external" href="https://developers.google.com/native-client/pepperc/group___enums.html#gaee750c350655f2fb0fe04c04029e0ff8">PP_AudioSampleRate</a></li> +</ul> +</section><section id="about-the-pepper-audio-api"> +<h2 id="about-the-pepper-audio-api">About the Pepper audio API</h2> +<p>The Pepper audio API lets Native Client modules play audio streams in a +browser. To play an audio stream, a module generates audio samples and writes +them into a buffer. The browser reads the audio samples from the buffer and +plays them using an audio device on the client computer.</p> +<img alt="/native-client/images/pepper-audio-buffer.png" src="/native-client/images/pepper-audio-buffer.png" /> +<p>This mechanism is simple but low-level. If you want to play plain sound files in +a web application, you may want to consider higher-level alternatives such as +using the HTML <code><audio></code> tag, JavaScript, or the new <a class="reference external" href="http://chromium.googlecode.com/svn/trunk/samples/audio/index.html">Web Audio API</a>.</p> +<p>The Pepper audio API is a good option for playing audio data if you want to do +audio processing in your web application. You might use the audio API, for +example, if you want to apply audio effects to sounds, synthesize your own +sounds, or do any other type of CPU-intensive processing of audio +samples. Another likely use case is gaming applications: you might use a gaming +library to process audio data, and then simply use the audio API to output the +processed data.</p> +<p>The Pepper audio API is straightforward to use:</p> +<ol class="arabic simple"> +<li>Your module creates an audio configuration resource and an audio resource.</li> +<li>Your module implements a callback function that fills an audio buffer with +data.</li> +<li>Your module invokes the StartPlayback and StopPlayback methods of the audio +resource (e.g., when certain events occur).</li> +<li>The browser invokes your callback function whenever it needs audio data to +play. Your callback function can generate the audio data in a number of +ways—e.g., it can generate new data, or it can copy pre-mixed data into the +audio buffer.</li> +</ol> +<p>This basic interaction is illustrated below, and described in detail in the +sections that follow.</p> +<img alt="/native-client/images/pepper-audio-api.png" src="/native-client/images/pepper-audio-api.png" /> +</section><section id="digital-audio-concepts"> +<h2 id="digital-audio-concepts">Digital audio concepts</h2> +<p>Before you use the Pepper audio API, it’s helpful to understand a few concepts +that are fundamental to how digital audio is recorded and played back:</p> +<dl class="docutils"> +<dt>sample rate</dt> +<dd>the number of times an input sound source is sampled per second; +correspondingly, the number of samples that are played back per second</dd> +<dt>bit depth</dt> +<dd>the number of bits used to represent a sample</dd> +<dt>channels</dt> +<dd>the number of input sources recorded in each sampling interval; +correspondingly, the number of outputs that are played back simultaneously +(typically using different speakers)</dd> +</dl> +<p>The higher the sample rate and bit depth used to record a sound wave, the more +accurately the sound wave can be reproduced, since it will have been sampled +more frequently and stored using a higher level of quantization. Common sampling +rates include 44,100 Hz (44,100 samples/second, the sample rate used on CDs), +and 48,000 Hz (the sample rate used on DVDs and Digital Audio Tapes). A common +bit depth is 16 bits per sample, and a common number of channels is 2 (left and +right channels for stereo sound).</p> +<p id="pepper-audio-configurations">The Pepper audio API currently lets Native Client modules play audio streams +with the following configurations:</p> +<ul class="small-gap"> +<li><strong>sample rate</strong>: 44,100 Hz or 48,000 Hz</li> +<li><strong>bit depth</strong>: 16</li> +<li><strong>channels</strong>: 2 (stereo)</li> +</ul> +</section><section id="setting-up-the-module"> +<h2 id="setting-up-the-module">Setting up the module</h2> +<p>The code examples below describe a simple Native Client module that generates +audio samples using a sine wave with a frequency of 440 Hz. The module starts +playing the audio samples as soon as it is loaded into the browser.</p> +<p>The Native Client module is set up by implementing subclasses of the +<code>pp::Module</code> and <code>pp::Instance</code> classes, as normal.</p> +<pre class="prettyprint"> +class SineSynthInstance : public pp::Instance { + public: + explicit SineSynthInstance(PP_Instance instance); + virtual ~SineSynthInstance() {} + + // Called by the browser once the NaCl module is loaded and ready to + // initialize. Creates a Pepper audio context and initializes it. Returns + // true on success. Returning false causes the NaCl module to be deleted + // and no other functions to be called. + virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]); + + private: + // Function called by the browser when it needs more audio samples. + static void SineWaveCallback(void* samples, + uint32_t buffer_size, + void* data); + + // Audio resource. + pp::Audio audio_; + + ... + +}; + +class SineSynthModule : public pp::Module { + public: + SineSynthModule() : pp::Module() {} + ~SineSynthModule() {} + + // Create and return a SineSynthInstance object. + virtual pp::Instance* CreateInstance(PP_Instance instance) { + return new SineSynthInstance(instance); + } +}; +</pre> +</section><section id="creating-an-audio-configuration-resource"> +<h2 id="creating-an-audio-configuration-resource">Creating an audio configuration resource</h2> +<section id="resources"> +<h3 id="resources">Resources</h3> +<p>Before the module can play an audio stream, it must create two resources: an +audio configuration resource and an audio resource. Resources are handles to +objects that the browser provides to module instances. An audio resource is an +object that represents the state of an audio stream, including whether the +stream is paused or being played back, and which callback function to invoke +when the samples in the stream’s buffer run out. An audio configuration resource +is an object that stores configuration data for an audio resource, including the +sampling frequency of the audio samples, and the number of samples that the +callback function must provide when the browser invokes it.</p> +</section><section id="sample-frame-count"> +<h3 id="sample-frame-count">Sample frame count</h3> +<p>Prior to creating an audio configuration resource, the module should call +<code>RecommendSampleFrameCount</code> to obtain a <em>sample frame count</em> from the +browser. The sample frame count is the number of samples that the callback +function must provide per channel each time the browser invokes the callback +function. For example, if the sample frame count is 4096 for a stereo audio +stream, the callback function must provide a 8192 samples (4096 for the left +channel and 4096 for the right channel).</p> +<p>The module can request a specific sample frame count, but the browser may return +a different sample frame count depending on the capabilities of the client +device. At present, <code>RecommendSampleFrameCount</code> simply bound-checks the +requested sample frame count (see <code>include/ppapi/c/ppb_audio_config.h</code> for the +minimum and maximum sample frame counts, currently 64 and 32768). In the future, +<code>RecommendSampleFrameCount</code> may perform a more sophisticated calculation, +particularly if there is an intrinsic buffer size for the client device.</p> +<p>Selecting a sample frame count for an audio stream involves a tradeoff between +latency and CPU usage. If you want your module to have short audio latency so +that it can rapidly change what’s playing in the audio stream, you should +request a small sample frame count. That could be useful in gaming applications, +for example, where sounds have to change frequently in response to game +action. However, a small sample frame count results in higher CPU usage, since +the browser must invoke the callback function frequently to refill the audio +buffer. Conversely, a large sample frame count results in higher latency but +lower CPU usage. You should request a large sample frame count if your module +will play long, uninterrupted audio segments.</p> +</section><section id="supported-audio-configurations"> +<h3 id="supported-audio-configurations">Supported audio configurations</h3> +<p>After the module obtains a sample frame count, it can create an audio +configuration resource. Currently the Pepper audio API supports audio streams +with the configuration settings shown <a class="reference internal" href="#pepper-audio-configurations"><em>above</em></a>. +C++ modules can create a configuration resource by instantiating a +<code>pp::AudioConfig</code> object. Check <code>audio_config.h</code> for the latest +configurations that are supported.</p> +<pre class="prettyprint"> +bool SineSynthInstance::Init(uint32_t argc, + const char* argn[], + const char* argv[]) { + + // Ask the browser/device for an appropriate sample frame count size. + sample_frame_count_ = + pp::AudioConfig::RecommendSampleFrameCount(PP_AUDIOSAMPLERATE_44100, + kSampleFrameCount); + + // Create an audio configuration resource. + pp::AudioConfig audio_config = pp::AudioConfig(this, + PP_AUDIOSAMPLERATE_44100, + sample_frame_count_); + + // Create an audio resource. + audio_ = pp::Audio(this, + audio_config, + SineWaveCallback, + this); + + // Start playback when the module instance is initialized. + return audio_.StartPlayback(); +} +</pre> +</section></section><section id="creating-an-audio-resource"> +<h2 id="creating-an-audio-resource">Creating an audio resource</h2> +<p>Once the module has created an audio configuration resource, it can create an +audio resource. To do so, it instantiates a <code>pp::Audio</code> object, passing in a +pointer to the module instance, the audio configuration resource, a callback +function, and a pointer to user data (data that is used in the callback +function). See the example above.</p> +</section><section id="implementing-a-callback-function"> +<h2 id="implementing-a-callback-function">Implementing a callback function</h2> +<p>The browser calls the callback function associated with an audio resource every +time it needs more samples to play. The callback function can generate new +samples (e.g., by applying sound effects), or copy pre-mixed samples into the +audio buffer. The example below generates new samples by computing values of a +sine wave.</p> +<p>The last parameter passed to the callback function is generic user data that the +function can use in processing samples. In the example below, the user data is a +pointer to the module instance, which includes member variables +<code>sample_frame_count_</code> (the sample frame count obtained from the browser) and +<code>theta_</code> (the last angle that was used to compute a sine value in the previous +callback; this lets the function generate a smooth sine wave by starting at that +angle plus a small delta).</p> +<pre class="prettyprint"> +class SineSynthInstance : public pp::Instance { + public: + ... + + private: + static void SineWaveCallback(void* samples, + uint32_t buffer_size, + void* data) { + + // The user data in this example is a pointer to the module instance. + SineSynthInstance* sine_synth_instance = + reinterpret_cast<SineSynthInstance*>(data); + + // Delta by which to increase theta_ for each sample. + const double delta = kTwoPi * kFrequency / PP_AUDIOSAMPLERATE_44100; + // Amount by which to scale up the computed sine value. + const int16_t max_int16 = std::numeric_limits<int16_t>::max(); + + int16_t* buff = reinterpret_cast<int16_t*>(samples); + + // Make sure we can't write outside the buffer. + assert(buffer_size >= (sizeof(*buff) * kChannels * + sine_synth_instance->sample_frame_count_)); + + for (size_t sample_i = 0; + sample_i < sine_synth_instance->sample_frame_count_; + ++sample_i, sine_synth_instance->theta_ += delta) { + + // Keep theta_ from going beyond 2*Pi. + if (sine_synth_instance->theta_ > kTwoPi) { + sine_synth_instance->theta_ -= kTwoPi; + } + + // Compute the sine value for the current theta_, scale it up, + // and write it into the buffer once for each channel. + double sin_value(std::sin(sine_synth_instance->theta_)); + int16_t scaled_value = static_cast<int16_t>(sin_value * max_int16); + for (size_t channel = 0; channel < kChannels; ++channel) { + *buff++ = scaled_value; + } + } + } + + ... +}; +</pre> +<section id="application-threads-and-real-time-requirements"> +<h3 id="application-threads-and-real-time-requirements">Application threads and real-time requirements</h3> +<p>The callback function runs in a background application thread. This allows audio +processing to continue even when the application is busy doing something +else. If the main application thread and the callback thread access the same +data, you may be tempted to use a lock to control access to that data. You +should avoid the use of locks in the callback thread, however, as attempting to +acquire a lock may cause the thread to get swapped out, resulting in audio +dropouts.</p> +<p>In general, you must program the callback thread carefully, as the Pepper audio +API is a very low level API that needs to meet hard real-time requirements. If +the callback thread spends too much time processing, it can easily miss the +real-time deadline, resulting in audio dropouts. One way the callback thread can +miss the deadline is by taking too much time doing computation. Another way the +callback thread can miss the deadline is by executing a function call that swaps +out the callback thread. Unfortunately, such function calls include just about +all C Run-Time (CRT) library calls and Pepper API calls. The callback thread +should therefore avoid calls to malloc, gettimeofday, mutex, condvars, critical +sections, and so forth; any such calls could attempt to take a lock and swap out +the callback thread, which would be disastrous for audio playback. Similarly, +the callback thread should avoid Pepper API calls. Audio dropouts due to thread +swapping can be very rare and very hard to track down and debug—it’s best to +avoid making system/Pepper calls in the first place. In short, the audio +(callback) thread should use “lock-free” techniques and avoid making CRT library +calls.</p> +<p>One other issue to be aware of is that the <code>StartPlayback</code> function (discussed +below) is an asynchronous RPC; i.e., it does not block. That means that the +callback function may not be called immediately after the call to +<code>StartPlayback</code>. If it’s important to synchronize the callback thread with +another thread so that the audio stream starts playing simultaneously with +another action in your application, you must handle such synchronization +manually.</p> +</section></section><section id="starting-and-stopping-playback"> +<h2 id="starting-and-stopping-playback">Starting and stopping playback</h2> +<p>To start and stop audio playback, the module simply reacts to JavaScript +messages.</p> +<pre class="prettyprint"> +const char* const kPlaySoundId = "playSound"; +const char* const kStopSoundId = "stopSound"; + +void SineSynthInstance::HandleMessage(const pp::Var& var_message) { + if (!var_message.is_string()) { + return; + } + std::string message = var_message.AsString(); + if (message == kPlaySoundId) { + audio_.StartPlayback(); + } else if (message == kStopSoundId) { + audio_.StopPlayback(); + } else if (...) { + ... + } +} +</pre> +</section></section> + +{{/partials.standard_nacl_article}} diff --git a/native_client_sdk/doc_generated/devguide/coding/file-io.html b/native_client_sdk/doc_generated/devguide/coding/file-io.html new file mode 100644 index 0000000..46e4d77 --- /dev/null +++ b/native_client_sdk/doc_generated/devguide/coding/file-io.html @@ -0,0 +1,498 @@ +{{+bindTo:partials.standard_nacl_article}} + +<section id="file-i-o"> +<span id="devguide-coding-fileio"></span><h1 id="file-i-o"><span id="devguide-coding-fileio"></span>File I/O</h1> +<div class="contents local topic" id="contents"> +<ul class="small-gap"> +<li><a class="reference internal" href="#introduction" id="id2">Introduction</a></li> +<li><a class="reference internal" href="#reference-information" id="id3">Reference information</a></li> +<li><p class="first"><a class="reference internal" href="#local-file-i-o" id="id4">Local file I/O</a></p> +<ul class="small-gap"> +<li><a class="reference internal" href="#enabling-local-file-i-o" id="id5">Enabling local file I/O</a></li> +<li><a class="reference internal" href="#testing-local-file-i-o" id="id6">Testing local file I/O</a></li> +</ul> +</li> +<li><p class="first"><a class="reference internal" href="#the-file-io-example" id="id7">The <code>file_io</code> example</a></p> +<ul class="small-gap"> +<li><a class="reference internal" href="#file-i-o-overview" id="id8">File I/O overview</a></li> +<li><a class="reference internal" href="#creating-and-writing-a-file" id="id9">Creating and writing a file</a></li> +<li><a class="reference internal" href="#opening-and-reading-a-file" id="id10">Opening and reading a file</a></li> +<li><a class="reference internal" href="#deleting-a-file" id="id11">Deleting a file</a></li> +<li><a class="reference internal" href="#making-a-directory" id="id12">Making a directory</a></li> +<li><a class="reference internal" href="#listing-the-contents-of-a-directory" id="id13">Listing the contents of a directory</a></li> +</ul> +</li> +<li><p class="first"><a class="reference internal" href="#file-io-deep-dive" id="id14"><code>file_io</code> deep dive</a></p> +<ul class="small-gap"> +<li><a class="reference internal" href="#opening-a-file-system-and-preparing-for-file-i-o" id="id15">Opening a file system and preparing for file I/O</a></li> +<li><a class="reference internal" href="#handling-messages-from-javascript" id="id16">Handling messages from JavaScript</a></li> +<li><a class="reference internal" href="#saving-a-file" id="id17">Saving a file</a></li> +<li><a class="reference internal" href="#loading-a-file" id="id18">Loading a file</a></li> +<li><a class="reference internal" href="#id1" id="id19">Deleting a file</a></li> +<li><a class="reference internal" href="#listing-files-in-a-directory" id="id20">Listing files in a directory</a></li> +<li><a class="reference internal" href="#making-a-new-directory" id="id21">Making a new directory</a></li> +</ul> +</li> +</ul> +</div> +<section id="introduction"> +<h2 id="introduction">Introduction</h2> +<p>This chapter describes how to use the <a class="reference external" href="https://developers.google.com/native-client/peppercpp/classpp_1_1_file_i_o">FileIO API</a> +to read and write files using a local secure data store.</p> +<p>You might use the File IO API with the URL Loading APIs to create an overall +data download and caching solution for your NaCl applications. For example:</p> +<ol class="arabic simple"> +<li>Use the File IO APIs to check the local disk to see if a file exists that +your program needs.</li> +<li>If the file exists locally, load it into memory using the File IO API. If +the file doesn’t exist locally, use the URL Loading API to retrieve the +file from the server.</li> +<li>Use the File IO API to write the file to disk.</li> +<li>Load the file into memory using the File IO API when needed by your +application.</li> +</ol> +<p>The example discussed in this chapter is included in the SDK in the directory +<code>examples/api/file_io</code>.</p> +</section><section id="reference-information"> +<h2 id="reference-information">Reference information</h2> +<p>For reference information related to FileIO, see the following documentation:</p> +<ul class="small-gap"> +<li><a class="reference external" href="https://developers.google.com/native-client/peppercpp/file__io_8h">file_io.h</a> - API +to create a FileIO object</li> +<li><a class="reference external" href="https://developers.google.com/native-client/peppercpp/file__ref_8h">file_ref.h</a> - API +to create a file reference or “weak pointer” to a file in a file system</li> +<li><a class="reference external" href="https://developers.google.com/native-client/peppercpp/file__system_8h">file_system.h</a> - +API to create a file system associated with a file</li> +</ul> +</section><section id="local-file-i-o"> +<h2 id="local-file-i-o">Local file I/O</h2> +<p>Chrome provides an obfuscated, restricted area on disk to which a web app can +safely <a class="reference external" href="https://developers.google.com/chrome/whitepapers/storage#persistent">read and write files</a>. The +Pepper FileIO, FileRef, and FileSystem APIs (collectively called the File IO +APIs) allow you to access this sandboxed local disk so you can read and write +files and manage caching yourself. The data is persistent between launches of +Chrome, and is not removed unless your application deletes it or the user +manually deletes it. There is no limit to the amount of local data you can +use, other than the actual space available on the local drive.</p> +<section id="enabling-local-file-i-o"> +<span id="enabling-file-access"></span><span id="quota-management"></span><h3 id="enabling-local-file-i-o"><span id="enabling-file-access"></span><span id="quota-management"></span>Enabling local file I/O</h3> +<p>The easiest way to enable the writing of persistent local data is to include +the <a class="reference external" href="http://developer.chrome.com/extensions/declare_permissions.html#unlimitedStorage">unlimitedStorage permission</a> +in your Chrome Web Store manifest file. With this permission you can use the +Pepper FileIO API without the need to request disk space at run time. When +the user installs the app Chrome displays a message announcing that the app +writes to the local disk.</p> +<p>If you do not use the <code>unlimitedStorage</code> permission you must include +JavaScript code that calls the <a class="reference external" href="http://updates.html5rocks.com/2011/11/Quota-Management-API-Fast-Facts">HTML5 Quota Management API</a> to +explicitly request local disk space before using the FileIO API. In this case +Chrome will prompt the user to accept a requestQuota call every time one is +made.</p> +</section><section id="testing-local-file-i-o"> +<h3 id="testing-local-file-i-o">Testing local file I/O</h3> +<p>You should be aware that using the <code>unlimitedStorage</code> manifest permission +constrains the way you can test your app. Three of the four techniques +described in <a class="reference internal" href="/native-client/devguide/devcycle/running.html"><em>Running Native Client Applications</em></a> +read the Chrome Web Store manifest file and enable the <code>unlimitedStorage</code> +permission when it appears, but the first technique (local server) does not. +If you want to test the file IO portion of your app with a simple local server, +you need to include JavaScript code that calls the HTML5 Quota Management API. +When you deliver your application you can replace this code with the +<code>unlimitedStorage</code> manifest permission.</p> +</section></section><section id="the-file-io-example"> +<h2 id="the-file-io-example">The <code>file_io</code> example</h2> +<p>The Native Client SDK includes an example, <code>file_io</code>, that demonstrates how +to read and write a local disk file. Since you will probably run the example +from a local server without a Chrome Web Store manifest file, the example’s +index file uses JavaScript to perform the Quota Management setup as described +above. The example has these primary files:</p> +<ul class="small-gap"> +<li><code>index.html</code> - The HTML code that launches the Native Client module and +displays the user interface.</li> +<li><code>example.js</code> - JavaScript code that requests quota (as described above). It +also listens for user interaction with the user interface, and forwards the +requests to the Native Client module.</li> +<li><code>file_io.cc</code> - The code that sets up and provides an entry point to the +Native Client module.</li> +</ul> +<p>The remainder of this section covers the code in the <code>file_io.cc</code> file for +reading and writing files.</p> +<section id="file-i-o-overview"> +<h3 id="file-i-o-overview">File I/O overview</h3> +<p>Like many Pepper APIs, the File IO API includes a set of methods that execute +asynchronously and that invoke callback functions in your Native Client module. +Unlike most other examples, the <code>file_io</code> example also demonstrates how to +make Pepper calls synchronously on a worker thread.</p> +<p>It is illegal to make blocking calls to Pepper on the module’s main thread. +This restriction is lifted when running on a worker thread—this is called +“calling Pepper off the main thread”. This often simplifies the logic of your +code; multiple asynchronous Pepper functions can be called from one function on +your worker thread, so you can use the stack and standard control flow +structures normally.</p> +<p>The high-level flow for the <code>file_io</code> example is described below. Note that +methods in the namespace <code>pp</code> are part of the Pepper C++ API.</p> +</section><section id="creating-and-writing-a-file"> +<h3 id="creating-and-writing-a-file">Creating and writing a file</h3> +<p>Following are the high-level steps involved in creating and writing to a +file:</p> +<ol class="arabic simple"> +<li><code>pp::FileIO::Open</code> is called with the <code>PP_FILEOPEN_FLAG_CREATE</code> flag to +create a file. Because the callback function is <code>pp::BlockUntilComplete</code>, +this thread is blocked until <code>Open</code> succeeds or fails.</li> +<li><code>pp::FileIO::Write</code> is called to write the contents. Again, the thread is +blocked until the call to <code>Write</code> completes. If there is more data to +write, <code>Write</code> is called again.</li> +<li>When there is no more data to write, call <code>pp::FileIO::Flush</code>.</li> +</ol> +</section><section id="opening-and-reading-a-file"> +<h3 id="opening-and-reading-a-file">Opening and reading a file</h3> +<p>Following are the high-level steps involved in opening and reading a file:</p> +<ol class="arabic simple"> +<li><code>pp::FileIO::Open</code> is called to open the file. Because the callback +function is <code>pp::BlockUntilComplete</code>, this thread is blocked until Open +succeeds or fails.</li> +<li><code>pp::FileIO::Query</code> is called to query information about the file, such as +its file size. The thread is blocked until <code>Query</code> completes.</li> +<li><code>pp::FileIO::Read</code> is called to read the contents. The thread is blocked +until <code>Read</code> completes. If there is more data to read, <code>Read</code> is called +again.</li> +</ol> +</section><section id="deleting-a-file"> +<h3 id="deleting-a-file">Deleting a file</h3> +<p>Deleting a file is straightforward: call <code>pp::FileRef::Delete</code>. The thread is +blocked until <code>Delete</code> completes.</p> +</section><section id="making-a-directory"> +<h3 id="making-a-directory">Making a directory</h3> +<p>Making a directory is also straightforward: call <code>pp::File::MakeDirectory</code>. +The thread is blocked until <code>MakeDirectory</code> completes.</p> +</section><section id="listing-the-contents-of-a-directory"> +<h3 id="listing-the-contents-of-a-directory">Listing the contents of a directory</h3> +<p>Following are the high-level steps involved in listing a directory:</p> +<ol class="arabic simple"> +<li><code>pp::FileRef::ReadDirectoryEntries</code> is called, and given a directory entry +to list. A callback is given as well; many of the other functions use +<code>pp::BlockUntilComplete</code>, but <code>ReadDirectoryEntries</code> returns results in +its callback, so it must be specified.</li> +<li>When the call to <code>ReadDirectoryEntries</code> completes, it calls +<code>ListCallback</code> which packages up the results into a string message, and +sends it to JavaScript.</li> +</ol> +</section></section><section id="file-io-deep-dive"> +<h2 id="file-io-deep-dive"><code>file_io</code> deep dive</h2> +<p>The <code>file_io</code> example displays a user interface with a couple of fields and +several buttons. Following is a screenshot of the <code>file_io</code> example:</p> +<img alt="/native-client/images/fileioexample.png" src="/native-client/images/fileioexample.png" /> +<p>Each radio button is a file operation you can perform, with some reasonable +default values for filenames. Try typing a message in the large input box and +clicking <code>Save</code>, then switching to the <code>Load File</code> operation, and +clicking <code>Load</code>.</p> +<p>Let’s take a look at what is going on under the hood.</p> +<section id="opening-a-file-system-and-preparing-for-file-i-o"> +<h3 id="opening-a-file-system-and-preparing-for-file-i-o">Opening a file system and preparing for file I/O</h3> +<p><code>pp::Instance::Init</code> is called when an instance of a module is created. In +this example, <code>Init</code> starts a new thread (via the <code>pp::SimpleThread</code> +class), and tells it to open the filesystem:</p> +<pre class="prettyprint"> +virtual bool Init(uint32_t /*argc*/, + const char * /*argn*/ [], + const char * /*argv*/ []) { + file_thread_.Start(); + // Open the file system on the file_thread_. Since this is the first + // operation we perform there, and because we do everything on the + // file_thread_ synchronously, this ensures that the FileSystem is open + // before any FileIO operations execute. + file_thread_.message_loop().PostWork( + callback_factory_.NewCallback(&FileIoInstance::OpenFileSystem)); + return true; +} +</pre> +<p>When the file thread starts running, it will call <code>OpenFileSystem</code>. This +calls <code>pp::FileSystem::Open</code> and blocks the file thread until the function +returns.</p> +<aside class="note"> +Note that the call to <code>pp::FileSystem::Open</code> uses +<code>pp::BlockUntilComplete</code> as its callback. This is only possible because we +are running off the main thread; if you try to make a blocking call from the +main thread, the function will return the error +<code>PP_ERROR_BLOCKS_MAIN_THREAD</code>. +</aside> +<pre class="prettyprint"> +void OpenFileSystem(int32_t /*result*/) { + int32_t rv = file_system_.Open(1024 * 1024, pp::BlockUntilComplete()); + if (rv == PP_OK) { + file_system_ready_ = true; + // Notify the user interface that we're ready + PostMessage("READY|"); + } else { + ShowErrorMessage("Failed to open file system", rv); + } +} +</pre> +</section><section id="handling-messages-from-javascript"> +<h3 id="handling-messages-from-javascript">Handling messages from JavaScript</h3> +<p>When you click the <code>Save</code> button, JavaScript posts a message to the NaCl +module with the file operation to perform sent as a string (See <a class="reference internal" href="/native-client/devguide/coding/message-system.html"><em>Messaging +System</em></a> for more details on message passing). The string is +parsed by <code>HandleMessage</code>, and new work is added to the file thread:</p> +<pre class="prettyprint"> +virtual void HandleMessage(const pp::Var& var_message) { + if (!var_message.is_string()) + return; + + // Parse message into: instruction file_name_length file_name [file_text] + std::string message = var_message.AsString(); + std::string instruction; + std::string file_name; + std::stringstream reader(message); + int file_name_length; + + reader >> instruction >> file_name_length; + file_name.resize(file_name_length); + reader.ignore(1); // Eat the delimiter + reader.read(&file_name[0], file_name_length); + + ... + + // Dispatch the instruction + if (instruction == kLoadPrefix) { + file_thread_.message_loop().PostWork( + callback_factory_.NewCallback(&FileIoInstance::Load, file_name)); + } else if (instruction == kSavePrefix) { + ... + } +} +</pre> +</section><section id="saving-a-file"> +<h3 id="saving-a-file">Saving a file</h3> +<p><code>FileIoInstance::Save</code> is called when the <code>Save</code> button is pressed. First, +it checks to see that the FileSystem has been successfully opened:</p> +<pre class="prettyprint"> +if (!file_system_ready_) { + ShowErrorMessage("File system is not open", PP_ERROR_FAILED); + return; +} +</pre> +<p>It then creates a <code>pp::FileRef</code> resource with the name of the file. A +<code>FileRef</code> resource is a weak reference to a file in the FileSystem; that is, +a file can still be deleted even if there are outstanding <code>FileRef</code> +resources.</p> +<pre class="prettyprint"> +pp::FileRef ref(file_system_, file_name.c_str()); +</pre> +<p>Next, a <code>pp::FileIO</code> resource is created and opened. The call to +<code>pp::FileIO::Open</code> passes <code>PP_FILEOPEFLAG_WRITE</code> to open the file for +writing, <code>PP_FILEOPENFLAG_CREATE</code> to create a new file if it doesn’t already +exist and <code>PP_FILEOPENFLAG_TRUNCATE</code> to clear the file of any previous +content:</p> +<pre class="prettyprint"> +pp::FileIO file(this); + +int32_t open_result = + file.Open(ref, + PP_FILEOPENFLAG_WRITE | PP_FILEOPENFLAG_CREATE | + PP_FILEOPENFLAG_TRUNCATE, + pp::BlockUntilComplete()); +if (open_result != PP_OK) { + ShowErrorMessage("File open for write failed", open_result); + return; +} +</pre> +<p>Now that the file is opened, it is written to in chunks. In an asynchronous +model, this would require writing a separate function, storing the current +state on the free store and a chain of callbacks. Because this function is +called off the main thread, <code>pp::FileIO::Write</code> can be called synchronously +and a conventional do/while loop can be used:</p> +<pre class="prettyprint"> +int64_t offset = 0; +int32_t bytes_written = 0; +do { + bytes_written = file.Write(offset, + file_contents.data() + offset, + file_contents.length(), + pp::BlockUntilComplete()); + if (bytes_written > 0) { + offset += bytes_written; + } else { + ShowErrorMessage("File write failed", bytes_written); + return; + } +} while (bytes_written < static_cast<int64_t>(file_contents.length())); +</pre> +<p>Finally, the file is flushed to push all changes to disk:</p> +<pre class="prettyprint"> +int32_t flush_result = file.Flush(pp::BlockUntilComplete()); +if (flush_result != PP_OK) { + ShowErrorMessage("File fail to flush", flush_result); + return; +} +</pre> +</section><section id="loading-a-file"> +<h3 id="loading-a-file">Loading a file</h3> +<p><code>FileIoInstance::Load</code> is called when the <code>Load</code> button is pressed. Like +the <code>Save</code> function, <code>Load</code> first checks to see if the FileSystem has been +successfully opened, and creates a new <code>FileRef</code>:</p> +<pre class="prettyprint"> +if (!file_system_ready_) { + ShowErrorMessage("File system is not open", PP_ERROR_FAILED); + return; +} +pp::FileRef ref(file_system_, file_name.c_str()); +</pre> +<p>Next, <code>Load</code> creates and opens a new <code>FileIO</code> resource, passing +<code>PP_FILEOPENFLAG_READ</code> to open the file for reading. The result is compared +to <code>PP_ERROR_FILENOTFOUND</code> to give a better error message when the file +doesn’t exist:</p> +<pre class="prettyprint"> +int32_t open_result = + file.Open(ref, PP_FILEOPENFLAG_READ, pp::BlockUntilComplete()); +if (open_result == PP_ERROR_FILENOTFOUND) { + ShowErrorMessage("File not found", open_result); + return; +} else if (open_result != PP_OK) { + ShowErrorMessage("File open for read failed", open_result); + return; +} +</pre> +<p>Then <code>Load</code> calls <code>pp::FileIO::Query</code> to get metadata about the file, such +as its size. This is used to allocate a <code>std::vector</code> buffer that holds the +data from the file in memory:</p> +<pre class="prettyprint"> +int32_t query_result = file.Query(&info, pp::BlockUntilComplete()); +if (query_result != PP_OK) { + ShowErrorMessage("File query failed", query_result); + return; +} + +... + +std::vector<char> data(info.size); +</pre> +<p>Similar to <code>Save</code>, a conventional while loop is used to read the file into +the newly allocated buffer:</p> +<pre class="prettyprint"> +int64_t offset = 0; +int32_t bytes_read = 0; +int32_t bytes_to_read = info.size; +while (bytes_to_read > 0) { + bytes_read = file.Read(offset, + &data[offset], + data.size() - offset, + pp::BlockUntilComplete()); + if (bytes_read > 0) { + offset += bytes_read; + bytes_to_read -= bytes_read; + } else if (bytes_read < 0) { + // If bytes_read < PP_OK then it indicates the error code. + ShowErrorMessage("File read failed", bytes_read); + return; + } +} +</pre> +<p>Finally, the contents of the file are sent back to JavaScript, to be displayed +on the page. This example uses “<code>DISP|</code>” as a prefix command for display +information:</p> +<pre class="prettyprint"> +std::string string_data(data.begin(), data.end()); +PostMessage("DISP|" + string_data); +ShowStatusMessage("Load success"); +</pre> +</section><section id="id1"> +<h3 id="id1">Deleting a file</h3> +<p><code>FileIoInstance::Delete</code> is called when the <code>Delete</code> button is pressed. +First, it checks whether the FileSystem has been opened, and creates a new +<code>FileRef</code>:</p> +<pre class="prettyprint"> +if (!file_system_ready_) { + ShowErrorMessage("File system is not open", PP_ERROR_FAILED); + return; +} +pp::FileRef ref(file_system_, file_name.c_str()); +</pre> +<p>Unlike <code>Save</code> and <code>Load</code>, <code>Delete</code> is called on the <code>FileRef</code> resource, +not a <code>FileIO</code> resource. Note that the result is checked for +<code>PP_ERROR_FILENOTFOUND</code> to give a better error message when trying to delete +a non-existent file:</p> +<pre class="prettyprint"> +int32_t result = ref.Delete(pp::BlockUntilComplete()); +if (result == PP_ERROR_FILENOTFOUND) { + ShowStatusMessage("File/Directory not found"); + return; +} else if (result != PP_OK) { + ShowErrorMessage("Deletion failed", result); + return; +} +</pre> +</section><section id="listing-files-in-a-directory"> +<h3 id="listing-files-in-a-directory">Listing files in a directory</h3> +<p><code>FileIoInstance::List</code> is called when the <code>List Directory</code> button is +pressed. Like all other operations, it checks whether the FileSystem has been +opened and creates a new <code>FileRef</code>:</p> +<pre class="prettyprint"> +if (!file_system_ready_) { + ShowErrorMessage("File system is not open", PP_ERROR_FAILED); + return; +} + +pp::FileRef ref(file_system_, dir_name.c_str()); +</pre> +<p>Unlike the other operations, it does not make a blocking call to +<code>pp::FileRef::ReadDirectoryEntries</code>. Since <code>ReadDirectoryEntries</code> returns +the resulting directory entries in its callback, a new callback object is +created pointing to <code>FileIoInstance::ListCallback</code>.</p> +<p>The <code>pp::CompletionCallbackFactory</code> template class is used to instantiate a +new callback. Notice that the <code>FileRef</code> resource is passed as a parameter; +this will add a reference count to the callback object, to keep the <code>FileRef</code> +resource from being destroyed when the function finishes.</p> +<pre class="prettyprint"> +// Pass ref along to keep it alive. +ref.ReadDirectoryEntries(callback_factory_.NewCallbackWithOutput( + &FileIoInstance::ListCallback, ref)); +</pre> +<p><code>FileIoInstance::ListCallback</code> then gets the results passed as a +<code>std::vector</code> of <code>pp::DirectoryEntry</code> objects, and sends them to +JavaScript:</p> +<pre class="prettyprint"> +void ListCallback(int32_t result, + const std::vector<pp::DirectoryEntry>& entries, + pp::FileRef /*unused_ref*/) { + if (result != PP_OK) { + ShowErrorMessage("List failed", result); + return; + } + + std::stringstream ss; + ss << "LIST"; + for (size_t i = 0; i < entries.size(); ++i) { + pp::Var name = entries[i].file_ref().GetName(); + if (name.is_string()) { + ss << "|" << name.AsString(); + } + } + PostMessage(ss.str()); + ShowStatusMessage("List success"); +} +</pre> +</section><section id="making-a-new-directory"> +<h3 id="making-a-new-directory">Making a new directory</h3> +<p><code>FileIoInstance::MakeDir</code> is called when the <code>Make Directory</code> button is +pressed. Like all other operations, it checks whether the FileSystem has been +opened and creates a new <code>FileRef</code>:</p> +<pre class="prettyprint"> +if (!file_system_ready_) { + ShowErrorMessage("File system is not open", PP_ERROR_FAILED); + return; +} +pp::FileRef ref(file_system_, dir_name.c_str()); +</pre> +<p>Then the <code>pp::FileRef::MakeDirectory</code> function is called.</p> +<pre class="prettyprint"> +int32_t result = ref.MakeDirectory( + PP_MAKEDIRECTORYFLAG_NONE, pp::BlockUntilComplete()); +if (result != PP_OK) { + ShowErrorMessage("Make directory failed", result); + return; +} +ShowStatusMessage("Make directory success"); +</pre> +</section></section></section> + +{{/partials.standard_nacl_article}} diff --git a/native_client_sdk/doc_generated/devguide/coding/index.html b/native_client_sdk/doc_generated/devguide/coding/index.html new file mode 100644 index 0000000..376f505 --- /dev/null +++ b/native_client_sdk/doc_generated/devguide/coding/index.html @@ -0,0 +1,10 @@ +{{+bindTo:partials.standard_nacl_article}} + +<section id="coding-your-application"> +<span id="coding"></span><h1 id="coding-your-application"><span id="coding"></span>Coding Your Application</h1> +<p>This section of the Developer’s Guide describes important concepts that would be +useful to understand in order to code your application—e.g., how an +application is structured, and how to use the Pepper APIs.</p> +</section> + +{{/partials.standard_nacl_article}} diff --git a/native_client_sdk/doc_generated/devguide/coding/message-system.html b/native_client_sdk/doc_generated/devguide/coding/message-system.html new file mode 100644 index 0000000..c28cef4a --- /dev/null +++ b/native_client_sdk/doc_generated/devguide/coding/message-system.html @@ -0,0 +1,376 @@ +{{+bindTo:partials.standard_nacl_article}} + +<section id="messaging-system"> +<span id="message-system"></span><h1 id="messaging-system"><span id="message-system"></span>Messaging System</h1> +<div class="contents local topic" id="contents"> +<ul class="small-gap"> +<li><a class="reference internal" href="#reference-information" id="id2">Reference information</a></li> +<li><p class="first"><a class="reference internal" href="#introduction-to-the-messaging-system" id="id3">Introduction to the messaging system</a></p> +<ul class="small-gap"> +<li><a class="reference internal" href="#design-of-the-messaging-system" id="id4">Design of the messaging system</a></li> +</ul> +</li> +<li><p class="first"><a class="reference internal" href="#communication-tasks-in-the-hello-world-example" id="id5">Communication tasks in the “Hello, World” example</a></p> +<ul class="small-gap"> +<li><a class="reference internal" href="#javascript-code" id="id6">JavaScript code</a></li> +<li><a class="reference internal" href="#native-client-module" id="id7">Native Client module</a></li> +</ul> +</li> +<li><p class="first"><a class="reference internal" href="#messaging-in-javascript-code-more-details" id="id8">Messaging in JavaScript code: More details.</a></p> +<ul class="small-gap"> +<li><a class="reference internal" href="#setting-up-an-event-listener-and-handler" id="id9">Setting up an event listener and handler</a></li> +</ul> +</li> +<li><p class="first"><a class="reference internal" href="#messaging-in-the-native-client-module-more-details" id="id10">Messaging in the Native Client module: More details.</a></p> +<ul class="small-gap"> +<li><a class="reference internal" href="#implementing-handlemessage" id="id11">Implementing HandleMessage()</a></li> +<li><a class="reference internal" href="#implementing-application-specific-functions" id="id12">Implementing application-specific functions</a></li> +<li><a class="reference internal" href="#sending-messages-back-to-the-javascript-code" id="id13">Sending messages back to the JavaScript code</a></li> +<li><a class="reference internal" href="#sending-and-receiving-other-pp-var-types" id="id14">Sending and receiving other <code>pp::Var</code> types</a></li> +</ul> +</li> +</ul> +</div> +<p>This chapter describes the messaging system used to communicate between the +JavaScript code and the Native Client module’s C or C++ code in a +Native Client application. It introduces the concept of asynchronous +programming and the basic steps required to set up a Native Client module +that sends messages to and receive messages from JavaScript. This chapter +assumes you are familiar with the material presented in the +<a class="reference internal" href="/native-client/devguide/coding/application-structure.html"><em>Application Structure</em></a> chapter.</p> +<aside class="note"> +The “Hello, World” example for getting started with NaCl is used here to +illustrate basic programming techniques. You can find this code in +the <code>/getting_started/part2</code> directory in the Native Client SDK download. +</aside> +<section id="reference-information"> +<h2 id="reference-information">Reference information</h2> +<p>For reference information related to the Pepper messaging API, see the +following documentation:</p> +<ul class="small-gap"> +<li><a class="reference external" href="https://developers.google.com/native-client/peppercpp/classpp_1_1_instance">pp::Instance class</a> HandleMessage(), PostMessage())</li> +<li><a class="reference external" href="https://developers.google.com/native-client/peppercpp/classpp_1_1_module">pp::Module class</a></li> +<li><a class="reference external" href="https://developers.google.com/native-client/peppercpp/classpp_1_1_var">pp::Var class</a></li> +</ul> +</section><section id="introduction-to-the-messaging-system"> +<h2 id="introduction-to-the-messaging-system">Introduction to the messaging system</h2> +<p>Native Client modules and JavaScript communicate by sending messages +to each other. The most basic form of a message is a string. Messages +support many JavaScript types, including ints, arrays, array buffers, +and dictionaries (see <a class="reference external" href="https://developers.google.com/native-client/peppercpp/classpp_1_1_var">pp::Var</a>, +<a class="reference external" href="https://developers.google.com/native-client/peppercpp/classpp_1_1_var_array_buffer">pp:VarArrayBuffer</a>, +and the general <a class="reference external" href="https://developers.google.com/native-client/pepperc/struct_p_p_b___messaging__1__0">messaging system documentation</a>). +It’s up to you to decide on the type of message and define how to +process the messages on both the JavaScript and Native Client +side. For the “Hello, World” example, we will work with string-typed +messages only.</p> +<p>When JavaScript posts a message to the Native Client module, the +Pepper <code>HandleMessage()</code> function is invoked on the module +side. Similarly, the Native Client module can post a message to +JavaScript, and this message triggers a JavaScript event listener for +<code>message</code> events in the DOM. (See the W3C specification on +<a class="reference external" href="http://www.w3.org/TR/DOM-Level-2-Events/events.html">Document Object Model Events</a> for more +information.) In the “Hello, World” example, the JavaScript functions for +posting and handling messages are named <code>postMessage()</code> and +<code>handleMessage()</code> (but any names could be used). On the Native Client +C++ side, the Pepper Library functions for posting and handling +messages are:</p> +<ul class="small-gap"> +<li><code>void pp::Instance::PostMessage(const Var &message)</code></li> +<li><code>virtual void pp::Instance::HandleMessage(const Var &message)</code></li> +</ul> +<p>If you want to receive messages from JavaScript, you need to implement the +<code>pp::Instance::HandleMessage()</code> function in your Native Client module.</p> +<section id="design-of-the-messaging-system"> +<h3 id="design-of-the-messaging-system">Design of the messaging system</h3> +<p>The Native Client messaging system is analogous to the system used by +the browser to allow web workers to communicate (see the <a class="reference external" href="http://www.w3.org/TR/workers">W3 web +worker specification</a>). The Native +Client messaging system is designed to keep the web page responsive while the +Native Client module is performing potentially heavy processing in the +background. When JavaScript sends a message to the Native Client +module, the <code>postMessage()</code> call returns as soon as it sends its message +to the Native Client module. The JavaScript does not wait for a reply +from Native Client, thus avoiding bogging down the main JavaScript +thread. On the JavaScript side, you set up an event listener to +respond to the message sent by the Native Client module when it has +finished the requested processing and returns a message.</p> +<p>This asynchronous processing model keeps the main thread free while +avoiding the following problems:</p> +<ul class="small-gap"> +<li>The JavaScript engine hangs while waiting for a synchronous call to return.</li> +<li>The browser pops up a dialog when a JavaScript entry point takes longer +than a few moments.</li> +<li>The application hangs while waiting for an unresponsive Native Client module.</li> +</ul> +</section></section><section id="communication-tasks-in-the-hello-world-example"> +<h2 id="communication-tasks-in-the-hello-world-example">Communication tasks in the “Hello, World” example</h2> +<p>The following sections describe how the “Hello, World” example posts +and handles messages on both the JavaScript side and the Native Client +side of the application.</p> +<section id="javascript-code"> +<h3 id="javascript-code">JavaScript code</h3> +<p>The JavaScript code and HTML in the “Hello, World” example can be +found in the <code>example.js</code>, <code>common.js</code>, and <code>index.html</code> files. +The important steps are:</p> +<ol class="arabic simple"> +<li>Sets up an event listener to listen for <code>message</code> events from the +Native Client module.</li> +<li>Implements an event handler that the event listener invokes to handle +incoming <code>message</code> events.</li> +<li>Calls <code>postMessage()</code> to communicate with the NaCl module, +after the page loads.</li> +</ol> +<section id="step-1-from-common-js"> +<h4 id="step-1-from-common-js">Step 1: From common.js</h4> +<pre class="prettyprint"> +function attachDefaultListeners() { + // The NaCl module embed is created within the listenerDiv + var listenerDiv = document.getElementById('listener'); + // ... + + // register the handleMessage function as the message event handler. + listenerDiv.addEventListener('message', handleMessage, true); + // ... +} +</pre> +</section><section id="step-2-from-example-js"> +<h4 id="step-2-from-example-js">Step 2: From example.js</h4> +<pre class="prettyprint"> +// This function is called by common.js when a message is received from the +// NaCl module. +function handleMessage(message) { + // In the example, we simply log the data that's received in the message. + var logEl = document.getElementById('log'); + logEl.textContent += message.data; +} + +// In the index.html we have set up the appropriate divs: +<body {attrs}> + <!-- ... --> + <div id="listener"></div> + <div id="log"></div> +</body> +</pre> +</section><section id="step-3-from-example-js"> +<h4 id="step-3-from-example-js">Step 3: From example.js</h4> +<pre class="prettyprint"> +// From example.js, Step 3: +function moduleDidLoad() { + // After the NaCl module has loaded, common.naclModule is a reference to the + // NaCl module's <embed> element. + // + // postMessage sends a message to it. + common.naclModule.postMessage('hello'); +} +</pre> +</section></section><section id="native-client-module"> +<h3 id="native-client-module">Native Client module</h3> +<p>The C++ code in the Native Client module of the “Hello, World” example:</p> +<ol class="arabic simple"> +<li>Implements <code>pp::Instance::HandleMessage()</code> to handle messages sent +by the JavaScript.</li> +<li>Processes incoming messages. This example simply checks that JavaScript +has sent a “hello” message and not some other message.</li> +<li>Calls <code>PostMessage()</code> to send an acknowledgement back to the +JavaScript code. The acknowledgement is a string in the form of a <code>Var</code> +that the JavaScript code can process. In general, a <code>pp::Var</code> can be +several JavaScript types, see the +<a class="reference external" href="https://developers.google.com/native-client/pepperc/struct_p_p_b___messaging__1__0">messaging system documentation</a>.</li> +</ol> +<pre class="prettyprint"> +class HelloTutorialInstance : public pp::Instance { + public: + // ... + + // === Step 1: Implement the HandleMessage function. === + virtual void HandleMessage(const pp::Var& var_message) { + + // === Step 2: Process the incoming message. === + // Ignore the message if it is not a string. + if (!var_message.is_string()) + return; + + // Get the string message and compare it to "hello". + std::string message = var_message.AsString(); + if (message == kHelloString) { + // === Step 3: Send the reply. === + // If it matches, send our response back to JavaScript. + pp::Var var_reply(kReplyString); + PostMessage(var_reply); + } + } +}; +</pre> +</section></section><section id="messaging-in-javascript-code-more-details"> +<h2 id="messaging-in-javascript-code-more-details">Messaging in JavaScript code: More details.</h2> +<p>This section describes in more detail the messaging system code in the +JavaScript portion of the “Hello, World” example.</p> +<section id="setting-up-an-event-listener-and-handler"> +<h3 id="setting-up-an-event-listener-and-handler">Setting up an event listener and handler</h3> +<p>The following JavaScript code sets up an event listener for messages +posted by the Native Client module. It then defines a message handler +that simply logs the content of messages received from the module.</p> +<section id="setting-up-the-message-handler-on-load"> +<h4 id="setting-up-the-message-handler-on-load">Setting up the ‘message’ handler on load</h4> +<pre class="prettyprint"> +// From common.js + +// Listen for the DOM content to be loaded. This event is fired when +// parsing of the page's document has finished. +document.addEventListener('DOMContentLoaded', function() { + var body = document.body; + // ... + var loadFunction = common.domContentLoaded; + // ... set up parameters ... + loadFunction(...); +} + +// This function is exported as common.domContentLoaded. +function domContentLoaded(...) { + // ... + if (common.naclModule == null) { + // ... + attachDefaultListeners(); + // initialize common.naclModule ... + } else { + // ... + } +} + +function attachDefaultListeners() { + var listenerDiv = document.getElementById('listener'); + // ... + listenerDiv.addEventListener('message', handleMessage, true); + // ... +} +</pre> +</section><section id="implementing-the-handler"> +<h4 id="implementing-the-handler">Implementing the handler</h4> +<pre class="prettyprint"> +// From example.js +function handleMessage(message) { + var logEl = document.getElementById('log'); + logEl.textContent += message.data; +} +</pre> +<p>Note that the <code>handleMessage()</code> function is handed a message_event +containing <code>data</code> that you can display or manipulate in JavaScript. The +“Hello, World” application simply logs this data to the <code>log</code> div.</p> +</section></section></section><section id="messaging-in-the-native-client-module-more-details"> +<h2 id="messaging-in-the-native-client-module-more-details">Messaging in the Native Client module: More details.</h2> +<p>This section describes in more detail the messaging system code in +the Native Client module portion of the “Hello, World” example.</p> +<section id="implementing-handlemessage"> +<h3 id="implementing-handlemessage">Implementing HandleMessage()</h3> +<p>If you want the Native Client module to receive and handle messages +from JavaScript, you need to implement a <code>HandleMessage()</code> function +for your module’s <code>pp::Instance</code> class. The +<code>HelloWorldInstance::HandleMessage()</code> function examines the message +posted from JavaScript. First it examines that the type of the +<code>pp::Var</code> is indeed a string (not a double, etc.). It then +interprets the data as a string with <code>var_message.AsString()</code>, and +checks that the string matches <code>kHelloString</code>. After examining the +message received from JavaScript, the code calls <code>PostMessage()</code> to +send a reply message back to the JavaScript side.</p> +<pre class="prettyprint"> +namespace { + +// The expected string sent by the JavaScript. +const char* const kHelloString = "hello"; +// The string sent back to the JavaScript code upon receipt of a message +// containing "hello". +const char* const kReplyString = "hello from NaCl"; + +} // namespace + +class HelloTutorialInstance : public pp::Instance { + public: + // ... + virtual void HandleMessage(const pp::Var& var_message) { + // Ignore the message if it is not a string. + if (!var_message.is_string()) + return; + + // Get the string message and compare it to "hello". + std::string message = var_message.AsString(); + if (message == kHelloString) { + // If it matches, send our response back to JavaScript. + pp::Var var_reply(kReplyString); + PostMessage(var_reply); + } + } +}; +</pre> +</section><section id="implementing-application-specific-functions"> +<h3 id="implementing-application-specific-functions">Implementing application-specific functions</h3> +<p>While the “Hello, World” example is very simple, your Native Client +module will likely include application-specific functions to perform +custom tasks in response to messages. For example the application +could be a compression and decompression service (two functions +exported). The application could set up an application-specific +convention that messages coming from JavaScript are colon-separated +pairs of the form <code><command>:<data></code>. The Native Client module +message handler can then split the incoming string along the <code>:</code> +character to determine which command to execute. If the command is +“compress”, then data to process is an uncompressed string. If the +command is “uncompress”, then data to process is an already-compressed +string. After processing the data asynchronously, the application then +returns the result to JavaScript.</p> +</section><section id="sending-messages-back-to-the-javascript-code"> +<h3 id="sending-messages-back-to-the-javascript-code">Sending messages back to the JavaScript code</h3> +<p>The Native Client module sends messages back to the JavaScript code +using <code>PostMessage()</code>. The Native Client module always returns +its values in the form of a <code>pp::Var</code> that can be processed by the +browser’s JavaScript. In this example, the message is posted at the +end of the Native Client module’s <code>HandleMessage()</code> function:</p> +<pre class="prettyprint"> +PostMessage(var_reply); +</pre> +</section><section id="sending-and-receiving-other-pp-var-types"> +<h3 id="sending-and-receiving-other-pp-var-types">Sending and receiving other <code>pp::Var</code> types</h3> +<p>Besides strings, <code>pp::Var</code> can represent other types of JavaScript +objects. For example, messages can be JavaScript objects. These +richer types can make it easier to implement an application’s +messaging protocol.</p> +<p>To send a dictionary from the NaCl module to JavaScript simply create +a <code>pp::VarDictionary</code> and then call <code>PostMessage</code> with the +dictionary.</p> +<pre class="prettyprint"> +pp::VarDictionary dictionary; +dictionary.Set(pp::Var("command"), pp::Var(next_command)); +dictionary.Set(pp::Var("param_int"), pp::Var(123)); +pp::VarArray an_array; +an_array.Set(0, pp::Var("string0")); +an_array.Set(1, pp::Var("string1")) +dictionary.Set(pp::Var("param_array"), an_array); +PostMessage(dictionary); +</pre> +<p>Here is how to create a similar object in JavaScript and send it to +the NaCl module:</p> +<pre class="prettyprint"> +var dictionary = { + command: next_command, + param_int: 123, + param_array: ['string0', 'string1'] +} +nacl_module.postMessage(dictionary); +</pre> +<p>To receive a dictionary-typed message in the NaCl module, test that +the message is truly a dictionary type, then convert the message +with the <code>pp::VarDictionary</code> class.</p> +<pre class="prettyprint"> +virtual void HandleMessage(const pp::Var& var) { + if (var.is_dictionary()) { + pp::VarDictionary dictionary(var); + // Use the dictionary + pp::VarArray keys = dictionary.GetKeys(); + // ... + } else { + // ... + } +} +</pre> +</section></section></section> + +{{/partials.standard_nacl_article}} diff --git a/native_client_sdk/doc_generated/devguide/coding/nacl_io.html b/native_client_sdk/doc_generated/devguide/coding/nacl_io.html new file mode 100644 index 0000000..ca10522 --- /dev/null +++ b/native_client_sdk/doc_generated/devguide/coding/nacl_io.html @@ -0,0 +1,225 @@ +{{+bindTo:partials.standard_nacl_article}} + +<section id="the-nacl-io-library"> +<span id="nacl-io"></span><h1 id="the-nacl-io-library"><span id="nacl-io"></span>The nacl_io Library</h1> +<div class="contents local topic" id="contents"> +<ul class="small-gap"> +<li><a class="reference internal" href="#introduction" id="id1">Introduction</a></li> +<li><a class="reference internal" href="#using-nacl-io" id="id2">Using nacl_io</a></li> +<li><p class="first"><a class="reference internal" href="#the-nacl-io-demo" id="id3">The nacl_io demo</a></p> +<ul class="small-gap"> +<li><a class="reference internal" href="#building-and-running-the-demo" id="id4">Building and running the demo</a></li> +<li><a class="reference internal" href="#a-look-at-the-code" id="id5">A look at the code</a></li> +</ul> +</li> +<li><a class="reference internal" href="#reference-information" id="id6">Reference information</a></li> +</ul> +</div> +<section id="introduction"> +<h2 id="introduction">Introduction</h2> +<p><code>nacl_io</code> is a utility library that provides implementations of standard +C APIs such as POSIX I/O (<code>stdio.h</code>) and BSD sockets (<code>sys/socket.h</code>). +Its primary function is to allow code that uses these standard APIs to be +compiled and used in a Native Client module. The library is included as part +of Native Client SDK and is implemented in on top of Pepper API.</p> +<p>Since Native Client modules cannot access the host machine’s file system +directly, nacl_io provides several alternative filesystem types which +can be used by the application. For example, the Chrome browser supports the +<a class="reference external" href="http://www.html5rocks.com/en/tutorials/file/filesystem/">HTML5 File System API</a> which provides +access to a protected area of the local file system. This filesystem can +be accessed by an HTML page using JavaScript commands, and also by a Native +Client module using the Pepper <a class="reference internal" href="/native-client/devguide/coding/file-io.html"><em>File IO API</em></a>. With nacl_io +a Native Client application can mount an HTML5 filesystem and access it via +standard POSIX I/O function such as <code>fopen</code>, <code>fseek</code>, <code>fread</code>, +<code>fwrite</code>, and <code>fclose</code>, or their low level UNIX counterparts <code>open</code>, +<code>lseek</code>, <code>read</code>, <code>write</code> and <code>close</code>.</p> +<p>As well as the HTML5 file system, nacl_io provides several other file system +types which are described in the table below:</p> +<table border="1" class="docutils"> +<colgroup> +</colgroup> +<thead valign="bottom"> +<tr class="row-odd"><th class="head">File System</th> +<th class="head">Description</th> +</tr> +</thead> +<tbody valign="top"> +<tr class="row-even"><td>memfs</td> +<td>An in-memory file system</td> +</tr> +<tr class="row-odd"><td>html5fs</td> +<td>An HTML5 local file system, which can be persistent or temporary</td> +</tr> +<tr class="row-even"><td>http</td> +<td>Maps files on a remote webserver into the local filesystem.</td> +</tr> +<tr class="row-odd"><td>dev</td> +<td>A file system containing special files (e.g.: <code>/dev/null</code>)</td> +</tr> +</tbody> +</table> +</section><section id="using-nacl-io"> +<h2 id="using-nacl-io">Using nacl_io</h2> +<p>Using nacl_io is mostly just a matter of using the standard POSIX C library +functions. However, there are some steps required to initialize the library +and setup the filesystem mounts. In general the following steps will be needed +to use nacl_io in a NaCl application:</p> +<ol class="arabic simple"> +<li>Link the application with the nacl_io library (<code>-lnacl_io</code>)</li> +<li>Initialize nacl_io at startup using the <code>nacl_io_init_ppapi</code> or +<code>nacl_io_init</code> functions.</li> +<li>Mount any desired filesystems using the <code>mount</code> function. The arguments +to <code>mount</code> for the different filesystem types are detailed in +<code>include/nacl_io/nacl_io.h</code>.</li> +<li>If you are going to mount an HTML5 file system, be sure to allocate space +for it. You can either set the <code>unlimitedStorage</code> permission in the app’s +Web Store manifest file, or call the HTML5 QuotaManagement API. These +options are explained in the <a class="reference internal" href="/native-client/devguide/coding/file-io.html#quota-management"><em>File IO documentation</em></a>.</li> +<li>Make sure that file and socket API calls are all made from the background +thread. This is because the main Pepper thread does not support the blocking +behavior needed by the POSIX I/O operations.</li> +</ol> +</section><section id="the-nacl-io-demo"> +<h2 id="the-nacl-io-demo">The nacl_io demo</h2> +<section id="building-and-running-the-demo"> +<h3 id="building-and-running-the-demo">Building and running the demo</h3> +<p>The demo application launches a Native Client module that mounts three file +systems and displays a set of controls that let you work with them:</p> +<img alt="/native-client/images/nacl_io1.png" src="/native-client/images/nacl_io1.png" /> +<p>Follow these steps to build and run the demo:</p> +<ul class="small-gap"> +<li><p class="first">Open a terminal in the demo directory:</p> +<pre class="prettyprint"> +$ cd $NACL_SDK_ROOT/examples/demo/nacl_io +</pre> +</li> +<li><p class="first">run the demo:</p> +<pre class="prettyprint"> +$ make run +</pre> +</li> +</ul> +<p>Once the demo is running, try these operations:</p> +<ol class="arabic simple"> +<li>select the fopen command (when you select a command the fields in the line +below will change according to the command)</li> +<li>type in the filename <code>/persistent/test</code></li> +<li>check the write checkbox and press the fopen button</li> +<li>select the fwrite command and select the file <code>/persistent/test</code> in the +menu that appears below on the left</li> +<li>enter some data and press the fwrite button</li> +<li>select the fclose command, be sure the file <code>/persistent/test</code> is selected +in the menu, and press the fclose button</li> +<li>select the fopen command</li> +<li>type in the filename <code>/persistent/test</code></li> +<li>check the fread checkbox and press the fopen button</li> +<li>select the fread command, be sure the file /persistent/test is selected in +the menu, enter a byte count, and press the fread button</li> +</ol> +</section><section id="a-look-at-the-code"> +<h3 id="a-look-at-the-code">A look at the code</h3> +<p>The demo is written C and comprises three files.</p> +<section id="nacl-io-demo-c"> +<h4 id="nacl-io-demo-c">nacl_io_demo.c</h4> +<p>This is the demo’s main file. The code here creates and initializes the Native +Client module instance. The Pepper function <code>Instance_DidCreate</code> initializes +nacl_io and mounts an HTML5 filesystem at <code>/persistent</code>.</p> +<pre class="prettyprint"> +static PP_Bool Instance_DidCreate(PP_Instance instance, + uint32_t argc, + const char* argn[], + const char* argv[]) { + g_instance = instance; + nacl_io_init_ppapi(instance, get_browser_interface); + mount( + "", /* source */ + "/persistent", /* target */ + "html5fs", /* filesystemtype */ + 0, /* mountflags */ + "type=PERSISTENT,expected_size=1048576"); /* data specific to the html5fs type */ + + pthread_create(&g_handle_message_thread, NULL, &HandleMessageThread, NULL); + InitializeMessageQueue(); + + return PP_TRUE; +} +</pre> +<p>Space is allocated to the <code>/persistent</code> file system after the module is +initialized. This is accomplished by the <code>domContentLoaded</code> function in +the file <code>example.js</code>. This script is included in the module’s html page (see +<code>examples/demo/index.html</code>):</p> +<pre class="prettyprint"> +function domContentLoaded(name, tc, config, width, height) { + navigator.webkitPersistentStorage.requestQuota(window.PERSISTENT, 1024 * 1024, + function(bytes) { + common.updateStatus( + 'Allocated ' + bytes + ' bytes of persistant storage.'); + common.createNaClModule(name, tc, config, width, height); + common.attachDefaultListeners(); + }, + function(e) { alert('Failed to allocate space') }); +} +</pre> +<p>The <code>Instance_DidCreate</code> function also creates a worker thread that receives +messages sent from the html page and performs the specified file system +operations. The logic for the worker thread is encoded in the other two files, +described below.</p> +</section><section id="queue-c"> +<h4 id="queue-c">queue.c</h4> +<p>This file implements a circular queue that is used to receive messages from the +browser UI to the Native Client module. The file system commands in the +enqueued messages are executed on the worker thread. This keeps blocking calls +(like fread) off the main Native Client thread, which is a good thing. The +queue is initialized in nacl_io_demo.c <code>Instance_DidCreate</code>.</p> +</section><section id="handlers-c"> +<h4 id="handlers-c">handlers.c</h4> +<p>This file implements the stdio calls associated with the commands sent from the +browser. There is a separate <code>Handle*</code> function for each command: fopen, +fclose, fseek, fread, fwrite. The handlers are called from the +<code>HandleMessage</code> function in nacl_io_demo.c, which runs in the worker +thread managing the message queue. The code for the <code>fwrite</code> handler appears +below. Notice that it does not contain any PPAPI calls and looks like +“ordinary” C code.</p> +<pre class="prettyprint"> +int HandleFwrite(int num_params, char** params, char** output) { + FILE* file; + const char* file_index_string; + const char* data; + size_t data_len; + size_t bytes_written; + + if (num_params != 2) { + *output = PrintfToNewString("Error: fwrite takes 2 parameters."); + return 1; + } + + file_index_string = params[0]; + file = GetFileFromIndexString(file_index_string, NULL); + data = params[1]; + data_len = strlen(data); + + if (!file) { + *output = PrintfToNewString("Error: Unknown file handle %s.", + file_index_string); + return 2; + } + + bytes_written = fwrite(data, 1, data_len, file); + + *output = PrintfToNewString("fwrite\1%s\1%d", file_index_string, + bytes_written); + return 0; +} +</pre> +</section></section></section><section id="reference-information"> +<h2 id="reference-information">Reference information</h2> +<p>The example discussed here is included in the SDK in the directory +<code>examples/demo/nacl_io</code>.</p> +<p>The nacl_io library is included in the SDK toolchain and is not a part of the +Pepper API. For reference information related to the nacl_io interface see +its header file in the SDK directory, located at +<code>include/nacl_io/nacl_io.h</code>.</p> +<p>For more about the HTML5 file system read the <a class="reference external" href="http://dev.w3.org/2009/dap/file-system/pub/FileSystem/">specification</a>.</p> +</section></section> + +{{/partials.standard_nacl_article}} diff --git a/native_client_sdk/doc_generated/devguide/coding/native-client-modules.html b/native_client_sdk/doc_generated/devguide/coding/native-client-modules.html new file mode 100644 index 0000000..7c063f1 --- /dev/null +++ b/native_client_sdk/doc_generated/devguide/coding/native-client-modules.html @@ -0,0 +1,178 @@ +{{+bindTo:partials.standard_nacl_article}} + +<section id="native-client-modules"> +<span id="devcycle-native-client-modules"></span><h1 id="native-client-modules"><span id="devcycle-native-client-modules"></span>Native Client Modules</h1> +<p>This document describes the classes and functions that you need to implement in +a Native Client module in order for Chrome to load, initialize, and run it. The +requirements are the same regardless of whether or not the module uses PNaCl, +but depend on whether the module is written in C or C++.</p> +<div class="contents local topic" id="contents"> +<ul class="small-gap"> +<li><a class="reference internal" href="#introduction" id="id2">Introduction</a></li> +<li><a class="reference internal" href="#writing-modules-in-c" id="id3">Writing modules in C</a></li> +<li><a class="reference internal" href="#id1" id="id4">Writing modules in C++</a></li> +</ul> +</div> +<section id="introduction"> +<h2 id="introduction">Introduction</h2> +<p>Native Client modules do not have a <code>main()</code> function. When a module loads, +the Native Client runtime calls the code in the module to create an instance and +initialize the interfaces for the APIs the module uses. This initialization +sequence depends on whether the module is written in C or C++ and requires that +you implement specific functions in each case.</p> +</section><section id="writing-modules-in-c"> +<h2 id="writing-modules-in-c">Writing modules in C</h2> +<p>The C API uses a prefix convention to show whether an interface is implemented +in the browser or in a module. Interfaces starting with <code>PPB_</code> (which can be +read as “Pepper <em>browser</em>”) are implemented in the browser and they are called +from your module. Interfaces starting with <code>PPP_</code> (“Pepper <em>plugin</em>”) are +implemented in the module; they are called from the browser and will execute on +the main thread of the module instance.</p> +<p>When you implement a Native Client module in C you must include these components:</p> +<ul class="small-gap"> +<li>The functions <code>PPP_InitializeModule</code> and <code>PPP_GetInterface</code></li> +<li>Code that implements the interface <code>PPP_Instance</code> and any other C interfaces +that your module uses</li> +</ul> +<p>For each PPP interface, you must implement all of its functions, create the +struct through which the browser calls the interface, and insure that the +function <code>PPP_GetInterface</code> returns the appropriate struct for the interface.</p> +<p>For each PPB interface, you must declare a pointer to the interface and +initialize the pointer with a call to <code>get_browser</code> inside +<code>PPP_InitializeModule</code>.</p> +<p>These steps are illustrated in the code excerpt below, which shows the +implementation and initialization of the required <code>PPP_Instance</code> +interface. The code excerpt also shows the initialization of three additional +interfaces which are not required: <code>PPB_Instance</code> (through which the Native +Client module calls back to the browser) and <code>PPB_InputEvent</code> and +<code>PPP_InputEvent</code>.</p> +<pre class="prettyprint"> +#include <stdlib.h> +#include <string.h> +#include "ppapi/c/pp_errors.h" +#include "ppapi/c/ppp.h" +// Include the interface headers. +// PPB APIs describe calls from the module to the browser. +// PPP APIs describe calls from the browser to the functions defined in your module. +#include "ppapi/c/ppb_instance.h" +#include "ppapi/c/ppp_instance.h" +#include "ppapi/c/ppb_input_event.h" +#include "ppapi/c/ppp_input_event.h" + +// Create pointers for each PPB interface that your module uses. +static PPB_Instance* ppb_instance_interface = NULL; +static PPB_InputEvent* ppb_input_event_interface = NULL; + +// Define all the functions for each PPP interface that your module uses. +// Here is a stub for the first function in PPP_Instance. +static PP_Bool Instance_DidCreate(PP_Instance instance, + uint32_t argc, + const char* argn[], + const char* argv[]) { + return PP_TRUE; +} +// ... more API functions ... + +// Define PPP_GetInterface. +// This function should return a non-NULL value for every interface you are using. +// The string for the name of the interface is defined in the interface's header file. +// The browser calls this function to get pointers to the interfaces that your module implements. +PP_EXPORT const void* PPP_GetInterface(const char* interface_name) { + // Create structs for each PPP interface. + // Assign the interface functions to the data fields. + if (strcmp(interface_name, PPP_INSTANCE_INTERFACE) == 0) { + static PPP_Instance instance_interface = { + &Instance_DidCreate, + // The definitions of these functions are not shown + &Instance_DidDestroy, + &Instance_DidChangeView, + &Instance_DidChangeFocus, + &Instance_HandleDocumentLoad + }; + return &instance_interface; + } + + if (strcmp(interface_name, PPP_INPUT_EVENT_INTERFACE) == 0) { + static PPP_InputEvent input_interface = { + // The definition of this function is not shown. + &Instance_HandleInput, + }; + return &input_interface; + } + // Return NULL for interfaces that you do not implement. + return NULL; +} + +// Define PPP_InitializeModule, the entry point of your module. +// Retrieve the API for the browser-side (PPB) interfaces you will use. +PP_EXPORT int32_t PPP_InitializeModule(PP_Module a_module_id, PPB_GetInterface get_browser) { + ppb_instance_interface = (PPB_Instance*)(get_browser(PPB_INSTANCE_INTERFACE)); + ppb_input_event_interface = (PPB_InputEvent*)(get_browser(PPB_INPUT_EVENT_INTERFACE)); + return PP_OK; +} +</pre> +</section><section id="id1"> +<h2 id="id1">Writing modules in C++</h2> +<p>When you implement a Native Client module in C++ you must include these components:</p> +<ul class="small-gap"> +<li>The factory function called <code>CreateModule()</code></li> +<li>Code that defines your own Module class (derived from the <code>pp::Module</code> +class)</li> +<li>Code that defines your own Instance class (derived from the <code>pp:Instance</code> +class)</li> +</ul> +<p>In the “Hello tutorial” example (in the <code>getting_started/part1</code> directory of +the NaCl SDK), these three components are specified in the file +<code>hello_tutorial.cc</code>. Here is the factory function:</p> +<pre class="prettyprint"> +namespace pp { +Module* CreateModule() { + return new HelloTutorialModule(); +} +} +</pre> +<p>The <code>CreateModule()</code> factory function is the main binding point between a +module and the browser, and serves as the entry point into the module. The +browser calls <code>CreateModule()</code> when a module is first loaded; this function +returns a Module object derived from the <code>pp::Module</code> class. The browser keeps +a singleton of the Module object.</p> +<p>Below is the Module class from the “Hello tutorial” example:</p> +<pre class="prettyprint"> +class HelloTutorialModule : public pp::Module { + public: + HelloTutorialModule() : pp::Module() {} + virtual ~HelloTutorialModule() {} + + virtual pp::Instance* CreateInstance(PP_Instance instance) { + return new HelloTutorialInstance(instance); + } +}; +</pre> +<p>The Module class must include a <code>CreateInstance()</code> method. The browser calls +the <code>CreateInstance()</code> method every time it encounters an <code><embed></code> element +on a web page that references the same module. The <code>CreateInstance()</code> function +creates and returns an Instance object derived from the <code>pp::Instance</code> class.</p> +<p>Below is the Instance class from the “Hello tutorial” example:</p> +<pre class="prettyprint"> +class HelloTutorialInstance : public pp::Instance { + public: + explicit HelloTutorialInstance(PP_Instance instance) : pp::Instance(instance) {} + virtual ~HelloTutorialInstance() {} + + virtual void HandleMessage(const pp::Var& var_message) {} +}; +</pre> +<p>As in the example above, the Instance class for your module will likely include +an implementation of the <code>HandleMessage()</code> function. The browser calls an +instance’s <code>HandleMessage()</code> function every time the JavaScript code in an +application calls <code>postMessage()</code> to send a message to the instance. See the +<a class="reference internal" href="/native-client/devguide/coding/message-system.html"><em>Native Client messaging system</em></a> for more information about +how to send messages between JavaScript code and Native Client modules.</p> +<p>While the <code>CreateModule()</code> factory function, the <code>Module</code> class, and the +<code>Instance</code> class are required for a Native Client application, the code +samples shown above don’t actually do anything. Subsequent documents in the +Developer’s Guide build on these code samples and add more interesting +functionality.</p> +</section></section> + +{{/partials.standard_nacl_article}} diff --git a/native_client_sdk/doc_generated/devguide/coding/progress-events.html b/native_client_sdk/doc_generated/devguide/coding/progress-events.html new file mode 100644 index 0000000..07721f9 --- /dev/null +++ b/native_client_sdk/doc_generated/devguide/coding/progress-events.html @@ -0,0 +1,434 @@ +{{+bindTo:partials.standard_nacl_article}} + +<section id="progress-events"> +<span id="devcycle-progress-events"></span><h1 id="progress-events"><span id="devcycle-progress-events"></span>Progress Events</h1> +<div class="contents local topic" id="contents"> +<ul class="small-gap"> +<li><a class="reference internal" href="#module-loading-and-progress-events" id="id3">Module loading and progress events</a></li> +<li><a class="reference internal" href="#handling-progress-events" id="id4">Handling progress events</a></li> +<li><a class="reference internal" href="#displaying-load-status" id="id5">Displaying load status</a></li> +<li><a class="reference internal" href="#the-lasterror-attribute" id="id6">The <code>lastError</code> attribute</a></li> +<li><a class="reference internal" href="#the-readystate-attribute" id="id7">The <code>readyState</code> attribute</a></li> +<li><a class="reference internal" href="#the-exitstatus-attribute" id="id8">The <code>exitStatus</code> attribute</a></li> +</ul> +</div> +<p>There are five types of events that developers can respond to in Native Client: +progress, message, view change, focus, and input events (each described in the +glossary below). This chapter describes how to monitor progress events (events +that occur during the loading and execution of a Native Client module). This +chapter assumes you are familiar with the material presented in the +<a class="reference internal" href="/native-client/overview.html"><em>Technical Overview</em></a>.</p> +<aside class="note"> +The load_progress example illustrates progress event handling. You can find +this code in the <code>/examples/tutorial/load_progress/</code> directory in the Native +Client SDK download. +</aside> +<section id="module-loading-and-progress-events"> +<h2 id="module-loading-and-progress-events">Module loading and progress events</h2> +<p>The Native Client runtime reports a set of state changes during the module +loading process by means of DOM progress events. This set of events is a direct +port of the proposed W3C <a class="reference external" href="http://www.w3.org/TR/progress-events/">Progress Events</a> standard (except for the <code>crash</code> +event which is an extension of the W3C standard). The following table lists the +events types reported by the Native Client runtime:</p> +<table border="1" class="docutils"> +<colgroup> +</colgroup> +<thead valign="bottom"> +<tr class="row-odd"><th class="head">Event</th> +<th class="head">Description</th> +<th class="head">Number of +times +triggered</th> +<th class="head">When event is +triggered</th> +<th class="head">How you might +react to +event</th> +</tr> +</thead> +<tbody valign="top"> +<tr class="row-even"><td><code>loadstart</code></td> +<td>Native Client has +started to load a +Native Client +module.</td> +<td>once</td> +<td>This is the +first +progress +event +triggered +after the +Native Client +module is +instantiated +and +initialized.</td> +<td>Display a +status +message, such +as +“Loading...”</td> +</tr> +<tr class="row-odd"><td><code>progress</code></td> +<td>Part of the module +has been loaded.</td> +<td>zero or +more</td> +<td>After +<code>loadstart</code> +has been +dispatched.</td> +<td>Display a +progress bar.</td> +</tr> +<tr class="row-even"><td><code>error</code></td> +<td>The Native Client +module failed to +start execution +(includes any +error before or +during +initialization of +the module). The +<code>lastError</code> +attribute +(mentioned later) +provides details +on the error +(initialization +failed, sel_ldr +did not start, +and so on).</td> +<td>zero or +once</td> +<td>After the +last +<code>progress</code> +event has +been +dispatched, +or after +<code>loadstart</code> +if no +<code>progress</code> +event was +dispatched.</td> +<td>Inform user +that the +application +failed to +load.</td> +</tr> +<tr class="row-odd"><td><code>abort</code></td> +<td>Loading of the +Native Client +module was +aborted by the +user.</td> +<td>zero or +once</td> +<td>After the +last +<code>progress</code> +event has +been +dispatched, +or after +<code>loadstart</code> +if no +<code>progress</code> +event was +dispatched.</td> +<td>It’s not +likely you +will want to +respond to +this event.</td> +</tr> +<tr class="row-even"><td><code>load</code></td> +<td>The Native Client +module was +successfully +loaded, and +execution was +started. (The +module was +initialized +successfully.)</td> +<td>zero or +once</td> +<td>After the +last +<code>progress</code> +event has +been +dispatched, +or after +<code>loadstart</code> +if no +<code>progress</code> +event was +dispatched.</td> +<td>Remove the +progress bar.</td> +</tr> +<tr class="row-odd"><td><code>loadend</code></td> +<td>Loading of the +Native Client +module has +stopped. Load +succeeded +(<code>load</code>), +failed +(<code>error</code>), or +was aborted +(<code>abort</code>).</td> +<td>once</td> +<td>After an +<code>error</code>, +<code>abort</code>, or +<code>load</code> +event was +dispatched.</td> +<td>Indicate +loading is +over +(regardless +of failure or +not).</td> +</tr> +<tr class="row-even"><td><code>crash</code></td> +<td>The Native Client +module is not +responding (died +on an +<code>assert()</code> or +<code>exit()</code>) after +a successful +load. This event +is unique to +Native Client and +is not part of +the W3C Progress +Events standard. +The <code>exitStatus</code> +attribute provides +the numeric exit +status value.</td> +<td>zero or +once</td> +<td>After a +<code>loadend</code>.</td> +<td>Notify user +that the +module did +something +illegal.</td> +</tr> +</tbody> +</table> +<p>The sequence of events for a successful module load is as follows:</p> +<table border="1" class="docutils"> +<colgroup> +</colgroup> +<thead valign="bottom"> +<tr class="row-odd"><th class="head">Event is dispatched</th> +<th class="head">... then this task is attempted</th> +</tr> +</thead> +<tbody valign="top"> +<tr class="row-even"><td><code>loadstart</code></td> +<td>load the manifest file</td> +</tr> +<tr class="row-odd"><td><code>progress</code> (first time)</td> +<td>load the module</td> +</tr> +<tr class="row-even"><td><code>progress</code> (subsequent times)</td> +<td> </td> +</tr> +<tr class="row-odd"><td><code>load</code></td> +<td>start executing the module</td> +</tr> +<tr class="row-even"><td><code>loadend</code></td> +<td> </td> +</tr> +</tbody> +</table> +<p>Errors that occur during loading are logged to the JavaScript console in Google +Chrome (select the menu icon <img alt="menu-icon" src="/native-client/images/menu-icon.png" /> > Tools > JavaScript console).</p> +</section><section id="handling-progress-events"> +<h2 id="handling-progress-events">Handling progress events</h2> +<p>You should add event listeners in a <code><script></code> element to listen for these +events before the <code><embed></code> element is parsed. For example, the following code +adds a listener for the <code>load</code> event to a parent <code><div></code> element that also +contains the Native Client <code><embed></code> element. First, the listener is +attached. Then, when the listener <code><div></code> receives the <code>load</code> event, the +JavaScript <code>moduleDidLoad()</code> function is called. The following code is +excerpted from the example in <code>getting_started/part1/</code>:</p> +<pre class="prettyprint"> +<!-- +Load the published pexe. +Note: Since this module does not use any real-estate in the browser, its +width and height are set to 0. + +Note: The <embed> element is wrapped inside a <div>, which has both a 'load' +and a 'message' event listener attached. This wrapping method is used +instead of attaching the event listeners directly to the <embed> element to +ensure that the listeners are active before the NaCl module 'load' event +fires. This also allows you to use PPB_Messaging.PostMessage() (in C) or +pp::Instance.PostMessage() (in C++) from within the initialization code in +your module. +--> +<div id="listener"> + <script type="text/javascript"> + var listener = document.getElementById('listener'); + listener.addEventListener('load', moduleDidLoad, true); + listener.addEventListener('message', handleMessage, true); + </script> + + <embed id="hello_tutorial" + width=0 height=0 + src="hello_tutorial.nmf" + type="application/x-pnacl" /> +</div> +</pre> +<p>Event listeners can be added to any DOM object. Since listeners set at the +outermost scope capture events for their contained elements, you can set +listeners on outer elements (including the <code><body></code> element) to handle events +from inner elements. For more information, see the W3 specifications for <a class="reference external" href="http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-flow-capture">event +flow capture</a> and +<a class="reference external" href="http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-registration">event listener registration</a>.</p> +</section><section id="displaying-load-status"> +<h2 id="displaying-load-status">Displaying load status</h2> +<p>One common response to progress events is to display the percentage of the +module that has been loaded. In the load_progress example, when the <code>progress</code> +event is triggered the <code>moduleLoadProgress</code> function is called. This function +uses the <code>lengthComputable</code>, <code>loaded</code>, and <code>total</code> attributes (described +in the proposed W3C <a class="reference external" href="http://www.w3.org/TR/progress-events/">Progress Events</a> +standard) of the event to calculate the percentage of the module that has +loaded.</p> +<pre class="prettyprint"> +function moduleLoadProgress(event) { + var loadPercent = 0.0; + var loadPercentString; + if (event.lengthComputable && event.total > 0) { + loadPercent = event.loaded / event.total * 100.0; + loadPercentString = loadPercent + '%'; + common.logMessage('progress: ' + event.url + ' ' + loadPercentString + + ' (' + event.loaded + ' of ' + event.total + ' bytes)'); + } else { + // The total length is not yet known. + common.logMessage('progress: Computing...'); + } +} +</pre> +</section><section id="the-lasterror-attribute"> +<h2 id="the-lasterror-attribute">The <code>lastError</code> attribute</h2> +<p>The <code><embed></code> element has a <code>lastError</code> attribute that is set to an +informative string whenever a load failure (an <code>error</code> or <code>abort</code> event) +occurs.</p> +<p>The following code adds an event listener before the <code><embed></code> element to +capture and handle an error in loading the Native Client module. The +<code>handleError()</code> function listens for an <code>error</code> event. When an error occurs, +this function prints the contents of the <code>lastError</code> attribute +(<code>embed_element.lastError</code>) as an alert.</p> +<pre class="prettyprint"> +function domContentLoaded(name, tc, config, width, height) { + var listener = document.getElementById('listener'); + ... + listener.addEventListener('error', moduleLoadError, true); + ... + common.createNaClModule(name, tc, config, width, height); +} + +function moduleLoadError() { + common.logMessage('error: ' + common.naclModule.lastError); +} +</pre> +</section><section id="the-readystate-attribute"> +<h2 id="the-readystate-attribute">The <code>readyState</code> attribute</h2> +<p>You can use the <code>readyState</code> attribute to monitor the loading process. This +attribute is particularly useful if you don’t care about the details of +individual progress events or when you want to poll for current load state +without registering listeners. The value of <code>readyState</code> progresses as follows +for a successful load:</p> +<table border="1" class="docutils"> +<colgroup> +</colgroup> +<thead valign="bottom"> +<tr class="row-odd"><th class="head">Event</th> +<th class="head"><code>readyState</code> value</th> +</tr> +</thead> +<tbody valign="top"> +<tr class="row-even"><td>(before any events)</td> +<td><code>undefined</code></td> +</tr> +<tr class="row-odd"><td><code>loadstart</code></td> +<td>1</td> +</tr> +<tr class="row-even"><td><code>progress</code></td> +<td>3</td> +</tr> +<tr class="row-odd"><td><code>load</code></td> +<td>4</td> +</tr> +<tr class="row-even"><td><code>loadend</code></td> +<td>4</td> +</tr> +</tbody> +</table> +<p>The following code demonstrates how to monitor the loading process using the +<code>readyState</code> attribute. As before, the script that adds the event listeners +precedes the <code><embed></code> element so that the event listeners are in place before +the progress events are generated.</p> +<pre class="prettyprint"> +<html> +... + <body id="body"> + <div id="status_div"> + </div> + <div id="listener_div"> + <script type="text/javascript"> + var stat = document.getElementById('status_div'); + function handleEvent(e) { + var embed_element = document.getElementById('my_embed'); + stat.innerHTML += + '<br>' + e.type + ': readyState = ' + embed_element.readyState; + } + var listener_element = document.getElementById('listener_div'); + listener_element.addEventListener('loadstart', handleEvent, true); + listener_element.addEventListener('progress', handleEvent, true); + listener_element.addEventListener('load', handleEvent, true); + listener_element.addEventListener('loadend', handleEvent, true); + </script> + <embed + name="naclModule" + id="my_embed" + width=0 height=0 + src="my_example.nmf" + type="application/x-pnacl" /> + </div> + </body> +</html> +</pre> +</section><section id="the-exitstatus-attribute"> +<h2 id="the-exitstatus-attribute">The <code>exitStatus</code> attribute</h2> +<p>This read-only attribute is set if the application calls <code>exit(n)</code>, +<code>abort()</code>, or crashes. Since NaCl modules are event handlers, there is no +need to call <code>exit(n)</code> in normal execution. If the module does exit or +crash, the <code>crash</code> progress event is issued and the <code>exitStatus</code> attribute +will contain the numeric value of the exit status:</p> +<ul class="small-gap"> +<li>In the case of explicit calls to <code>exit(n)</code>, the numeric value will be +<code>n</code> (between 0 and 255).</li> +<li>In the case of crashes and calls to <code>abort()</code>, the numeric value will +be non-zero, but the exact value will depend on the chosen libc and the +target architecture, and may change in the future. Applications should not +rely on the <code>exitStatus</code> value being stable in these cases, but the value +may nevertheless be useful for temporary debugging.</li> +</ul> +</section></section> + +{{/partials.standard_nacl_article}} diff --git a/native_client_sdk/doc_generated/devguide/coding/url-loading.html b/native_client_sdk/doc_generated/devguide/coding/url-loading.html new file mode 100644 index 0000000..a99b214 --- /dev/null +++ b/native_client_sdk/doc_generated/devguide/coding/url-loading.html @@ -0,0 +1,232 @@ +{{+bindTo:partials.standard_nacl_article}} + +<section id="url-loading"> +<span id="devguide-coding-url-loading"></span><h1 id="url-loading"><span id="devguide-coding-url-loading"></span>URL Loading</h1> +<div class="contents local topic" id="contents"> +<ul class="small-gap"> +<li><a class="reference internal" href="#introduction" id="id1">Introduction</a></li> +<li><a class="reference internal" href="#reference-information" id="id2">Reference information</a></li> +<li><a class="reference internal" href="#background" id="id3">Background</a></li> +<li><p class="first"><a class="reference internal" href="#the-url-loader-example" id="id4">The <code>url_loader</code> example</a></p> +<ul class="small-gap"> +<li><a class="reference internal" href="#url-loading-overview" id="id5">URL loading overview</a></li> +</ul> +</li> +<li><p class="first"><a class="reference internal" href="#url-loader-deep-dive" id="id6"><code>url_loader</code> deep dive</a></p> +<ul class="small-gap"> +<li><a class="reference internal" href="#setting-up-the-request" id="id7">Setting up the request</a></li> +<li><a class="reference internal" href="#downloading-the-data" id="id8">Downloading the data</a></li> +<li><a class="reference internal" href="#displaying-a-result" id="id9">Displaying a result</a></li> +</ul> +</li> +</ul> +</div> +<section id="introduction"> +<h2 id="introduction">Introduction</h2> +<p>This chapter describes how to use the <a class="reference external" href="https://developers.google.com/native-client/peppercpp/classpp_1_1_u_r_l_loader">URLLoader API</a> +to load resources such as images and sound files from a server into your +application.</p> +<p>The example discussed in this chapter is included in the SDK in the directory +<code>examples/api/url_loader</code>.</p> +</section><section id="reference-information"> +<h2 id="reference-information">Reference information</h2> +<p>For reference information related to loading data from URLs, see the +following documentation:</p> +<ul class="small-gap"> +<li><a class="reference external" href="https://developers.google.com/native-client/peppercpp/url__loader_8h">url_loader.h</a> - +Contains <code>URLLoader</code> class for loading data from URLs</li> +<li><a class="reference external" href="https://developers.google.com/native-client/peppercpp/url__request__info_8h">url_request_info.h</a> +- Contains <code>URLRequest</code> class for creating and manipulating URL requests</li> +<li><a class="reference external" href="https://developers.google.com/native-client/peppercpp/url__response__info_8h">url_response_info.h</a> +- Contains <code>URLResponse</code> class for examaning URL responses</li> +</ul> +</section><section id="background"> +<h2 id="background">Background</h2> +<p>When a user launches your Native Client web application, Chrome downloads and +caches your application’s HTML file, manifest file (.nmf), and Native Client +module (.pexe or .nexe). If your application needs additional assets, such as +images and sound files, it must explicitly load those assets. You can use the +Pepper APIs described in this chapter to load assets from a URL into your +application.</p> +<p>After you’ve loaded assets into your application, Chrome will cache those +assets. To avoid being at the whim of the Chrome cache, however, you may want +to use the <a class="reference external" href="https://developers.google.com/native-client/peppercpp/classpp_1_1_file_i_o">Pepper FileIO API</a> +to write those assets to a persistent, sandboxed location on the user’s file +system.</p> +</section><section id="the-url-loader-example"> +<h2 id="the-url-loader-example">The <code>url_loader</code> example</h2> +<p>The SDK includes an example called <code>url_loader</code> demonstrating downloading +files from a server. This example has these primary files:</p> +<ul class="small-gap"> +<li><code>index.html</code> - The HTML code that launches the Native Client module.</li> +<li><code>example.js</code> - The JavaScript file for index.html. It has code that sends +a PostMessage request to the Native Client module when the “Get URL” button +is clicked.</li> +<li><code>url_loader_success.html</code> - An HTML file on the server whose contents are +being retrieved using the <code>URLLoader</code> API.</li> +<li><code>url_loader.cc</code> - The code that sets up and provides and entry point into +the Native client module.</li> +<li><code>url_loader_handler.cc</code> - The code that retrieves the contents of the +url_loader_success.html file and returns the results (this is where the +bulk of the work is done).</li> +</ul> +<p>The remainder of this document covers the code in the <code>url_loader.cc</code> and +<code>url_loader_handler.cc</code> files.</p> +<section id="url-loading-overview"> +<h3 id="url-loading-overview">URL loading overview</h3> +<p>Like many Pepper APIs, the <code>URLLoader</code> API includes a set of methods that +execute asynchronously and that invoke callback functions in your Native Client +module. The high-level flow for the <code>url_loader</code> example is described below. +Note that methods in the namespace <code>pp::URLLoader</code> are part of the Pepper +<code>URLLoader</code> API, while the rest of the functions are part of the code in the +Native Client module (specifically in the file <code>url_loader_handler.cc</code>). The +following image shows the flow of the <code>url_loader_handler</code> code:</p> +<img alt="/native-client/images/pepper-urlloader-api.png" src="/native-client/images/pepper-urlloader-api.png" /> +<p>Following are the high-level steps involved in URL loading.</p> +<ol class="arabic simple"> +<li>The Native Client module calls <code>pp::URLLoader::Open</code> to begin opening the +URL.</li> +<li>When <code>Open</code> completes, it invokes a callback function in the Native Client +module (in this case, <code>OnOpen</code>).</li> +<li>The Native Client module calls the Pepper function +<code>URLLoader::ReadResponseBody</code> to begin reading the response body with the +data. <code>ReadResponseBody</code> is passed an optional callback function in the +Native Client module (in this case, On <code>Read</code>). The callback function is +an optional callback because <code>ReadResponseBody</code> may read data and return +synchronously if data is available (this improves performance for large +files and fast connections).</li> +</ol> +<p>The remainder of this document demonstrates how the previous steps are +implemented in the <code>url_loader</code> example.</p> +</section></section><section id="url-loader-deep-dive"> +<h2 id="url-loader-deep-dive"><code>url_loader</code> deep dive</h2> +<section id="setting-up-the-request"> +<h3 id="setting-up-the-request">Setting up the request</h3> +<p><code>HandleMessage</code> in <code>url_loader.cc</code> creates a <code>URLLoaderHandler</code> instance +and passes it the URL of the asset to be retrieved. Then <code>HandleMessage</code> +calls <code>Start</code> to start retrieving the asset from the server:</p> +<pre class="prettyprint"> +void URLLoaderInstance::HandleMessage(const pp::Var& var_message) { + if (!var_message.is_string()) { + return; + } + std::string message = var_message.AsString(); + if (message.find(kLoadUrlMethodId) == 0) { + // The argument to getUrl is everything after the first ':'. + size_t sep_pos = message.find_first_of(kMessageArgumentSeparator); + if (sep_pos != std::string::npos) { + std::string url = message.substr(sep_pos + 1); + printf("URLLoaderInstance::HandleMessage('%s', '%s')\n", + message.c_str(), + url.c_str()); + fflush(stdout); + URLLoaderHandler* handler = URLLoaderHandler::Create(this, url); + if (handler != NULL) { + // Starts asynchronous download. When download is finished or when an + // error occurs, |handler| posts the results back to the browser + // vis PostMessage and self-destroys. + handler->Start(); + } + } + } +} +</pre> +<p>Notice that the constructor for <code>URLLoaderHandler</code> in +<code>url_loader_handler.cc</code> sets up the parameters of the URL request (using +<code>SetURL,</code> <code>SetMethod</code>, and <code>SetRecordDownloadProgress</code>):</p> +<pre class="prettyprint"> +URLLoaderHandler::URLLoaderHandler(pp::Instance* instance, + const std::string& url) + : instance_(instance), + url_(url), + url_request_(instance), + url_loader_(instance), + buffer_(new char[READ_BUFFER_SIZE]), + cc_factory_(this) { + url_request_.SetURL(url); + url_request_.SetMethod("GET"); + url_request_.SetRecordDownloadProgress(true); +} +</pre> +</section><section id="downloading-the-data"> +<h3 id="downloading-the-data">Downloading the data</h3> +<p><code>Start</code> in <code>url_loader_handler.cc</code> creates a callback (<code>cc</code>) using a +<code>CompletionCallbackFactory</code>. The callback is passed to <code>Open</code> to be called +upon its completion. <code>Open</code> begins loading the <code>URLRequestInfo</code>.</p> +<pre class="prettyprint"> +void URLLoaderHandler::Start() { + pp::CompletionCallback cc = + cc_factory_.NewCallback(&URLLoaderHandler::OnOpen); + url_loader_.Open(url_request_, cc); +} +</pre> +<p><code>OnOpen</code> ensures that the Open call was successful and, if so, calls +<code>GetDownloadProgress</code> to determine the amount of data to be downloaded so it +can allocate memory for the response body.</p> +<p>Note that the amount of data to be downloaded may be unknown, in which case +<code>GetDownloadProgress</code> sets <code>total_bytes_to_be_received</code> to -1. It is not a +problem if <code>total_bytes_to_be_received</code> is set to -1 or if +<code>GetDownloadProgress</code> fails; in these scenarios memory for the read buffer +can’t be allocated in advance and must be allocated as data is received.</p> +<p>Finally, <code>OnOpen</code> calls <code>ReadBody.</code></p> +<pre class="prettyprint"> +void URLLoaderHandler::OnOpen(int32_t result) { + if (result != PP_OK) { + ReportResultAndDie(url_, "pp::URLLoader::Open() failed", false); + return; + } + int64_t bytes_received = 0; + int64_t total_bytes_to_be_received = 0; + if (url_loader_.GetDownloadProgress(&bytes_received, + &total_bytes_to_be_received)) { + if (total_bytes_to_be_received > 0) { + url_response_body_.reserve(total_bytes_to_be_received); + } + } + url_request_.SetRecordDownloadProgress(false); + ReadBody(); +} +</pre> +<p><code>ReadBody</code> creates another <code>CompletionCallback</code> (a <code>NewOptionalCallback</code>) +and passes it to <code>ReadResponseBody,</code> which reads the response body, and +<code>AppendDataBytes,</code> which appends the resulting data to the previously read +data.</p> +<pre class="prettyprint"> +void URLLoaderHandler::ReadBody() { + pp::CompletionCallback cc = + cc_factory_.NewOptionalCallback(&URLLoaderHandler::OnRead); + int32_t result = PP_OK; + do { + result = url_loader_.ReadResponseBody(buffer_, READ_BUFFER_SIZE, cc); + if (result > 0) { + AppendDataBytes(buffer_, result); + } + } while (result > 0); + + if (result != PP_OK_COMPLETIONPENDING) { + cc.Run(result); + } +} + +void URLLoaderHandler::AppendDataBytes(const char* buffer, int32_t num_bytes) { + if (num_bytes <= 0) + return; + num_bytes = std::min(READ_BUFFER_SIZE, num_bytes); + url_response_body_.insert( + url_response_body_.end(), buffer, buffer + num_bytes); +} +</pre> +<p>Eventually either all the bytes have been read for the entire file (resulting +in <code>PP_OK</code> or 0), all the bytes have been read for what has been +downloaded, but more is to be downloaded (<code>PP_OK_COMPLETIONPENDING</code> or -1), +or there is an error (less than -1). <code>OnRead</code> is called in the event of an +error or <code>PP_OK</code>.</p> +</section><section id="displaying-a-result"> +<h3 id="displaying-a-result">Displaying a result</h3> +<p>OnRead calls <code>ReportResultAndDie</code> when either an error or <code>PP_OK</code> is +returned to indicate streaming of file is complete. <code>ReportResultAndDie</code> then +calls <code>ReportResult,</code> which calls <code>PostMessage</code> to send the result back to +the HTML page.</p> +</section></section></section> + +{{/partials.standard_nacl_article}} diff --git a/native_client_sdk/doc_generated/devguide/coding/view-focus-input-events.html b/native_client_sdk/doc_generated/devguide/coding/view-focus-input-events.html new file mode 100644 index 0000000..9c23179 --- /dev/null +++ b/native_client_sdk/doc_generated/devguide/coding/view-focus-input-events.html @@ -0,0 +1,345 @@ +{{+bindTo:partials.standard_nacl_article}} + +<section id="view-change-focus-and-input-events"> +<span id="view-focus-input-events"></span><h1 id="view-change-focus-and-input-events"><span id="view-focus-input-events"></span>View Change, Focus, and Input Events</h1> +<div class="contents local topic" id="contents"> +<ul class="small-gap"> +<li><a class="reference internal" href="#overview" id="id2">Overview</a></li> +<li><p class="first"><a class="reference internal" href="#handling-browser-events" id="id3">Handling browser events</a></p> +<ul class="small-gap"> +<li><a class="reference internal" href="#didchangeview" id="id4">DidChangeView()</a></li> +<li><a class="reference internal" href="#didchangefocus" id="id5">DidChangeFocus()</a></li> +</ul> +</li> +<li><p class="first"><a class="reference internal" href="#handling-input-events" id="id6">Handling input events</a></p> +<ul class="small-gap"> +<li><a class="reference internal" href="#registering-a-module-to-accept-input-events" id="id7">Registering a module to accept input events</a></li> +<li><a class="reference internal" href="#determining-and-branching-on-event-types" id="id8">Determining and branching on event types</a></li> +<li><a class="reference internal" href="#threading-and-blocking" id="id9">Threading and blocking</a></li> +</ul> +</li> +</ul> +</div> +<p>This chapter describes view change, focus, and input event handling for a +Native Client module. The chapter assumes you are familiar with the +material presented in the <a class="reference internal" href="/native-client/overview.html"><em>Technical Overview</em></a>.</p> +<p>There are two examples used in this chapter to illustrate basic +programming techniques. The <code>input_events</code> example is used to +illustrate how your module can react to keyboard and mouse input +event. The <code>mouse_lock</code> example is used to illustrate how your module +can react to view change events. You can find these examples in the +<code>/examples/api/input_events</code> and <code>/examples/api/mouse_lock</code> +directories in the Native Client SDK. There is also the +ppapi_simple library that can be used to to implement most of the +boiler plate. The <code>pi_generator</code> example in +<code>/examples/demo/pi_generator</code> uses ppapi_simple to manage view +change events and 2D graphics.</p> +<section id="overview"> +<h2 id="overview">Overview</h2> +<p>When a user interacts with the web page using a keyboard, mouse or +some other input device, the browser generates input events. +In a traditional web application, these input events are +passed to and handled in JavaScript, typically through event listeners +and event handlers. In a Native Client application, user interaction +with an instance of a module (e.g., clicking inside the rectangle +managed by a module) also generates input events, which are passed to +the module. The browser also passes view change and focus events that +affect a module’s instance to the module. Native Client modules can +override certain functions in the <a class="reference external" href="https://developers.google.com/native-client/peppercpp/classpp_1_1_instance">pp::Instance</a> +class to handle input and browser events. These functions are listed in +the table below:</p> +<table border="1" class="docutils"> +<colgroup> +</colgroup> +<thead valign="bottom"> +<tr class="row-odd"><th class="head">Function</th> +<th class="head">Event</th> +<th class="head">Use</th> +</tr> +</thead> +<tbody valign="top"> +<tr class="row-even"><td><code>DidChangeView</code></td> +<td>Called when the position, +size, or clip rectangle +of the module’s instance in +the browser has changed. +This event also occurs +when browser window is +resized or mouse wheel +is scrolled.</td> +<td>An implementation +of this function +might check the size +of the module +instance’s rectangle +has changed and +reallocate the +graphics context +when a different +size is received.</td> +</tr> +<tr class="row-odd"><td><code>DidChangeFocus</code></td> +<td>Called when the module’s +instance in the browser +has gone in or out of +focus (usually by +clicking inside or +outside the module +instance). Having focus +means that keyboard +events will be sent to +the module instance. +An instance’s default +condition is that it +does not have focus.</td> +<td>An implementation +of this function +might start or stop +an animation or a +blinking cursor.</td> +</tr> +<tr class="row-even"><td><code>HandleDocumentLoad</code></td> +<td>Called after +<code>pp::Instance::Init()</code> +for a full-frame module +instance that was +instantiated based on +the MIME type of a +DOMWindow navigation. +This situation only +applies to modules that +are pre-registered to +handle certain MIME +types. If you haven’t +specifically registered +to handle a MIME type or +aren’t positive this +applies to you, your +implementation of this +function can just return +false.</td> +<td>This API is only +applicable when you +are writing an +extension to enhance +the abilities of +the Chrome web +browser. For +example, a PDF +viewer might +implement this +function to download +and display a PDF +file.</td> +</tr> +<tr class="row-odd"><td><code>HandleInputEvent</code></td> +<td>Called when a user +interacts with the +module’s instance in the +browser using an input +device such as a mouse +or keyboard. You must +register your module to +accept input events +using +<code>RequestInputEvents()</code> +for mouse events and +<code>RequestFilteringInputEvents</code> +for keyboard events +prior to overriding this +function.</td> +<td>An implementation of +this function +examines the input +event type and +branches accordingly.</td> +</tr> +</tbody> +</table> +<p>These interfaces are found in the <a class="reference external" href="https://developers.google.com/native-client/dev/peppercpp/classpp_1_1_instance">pp::Instance class</a>. +The sections below provide examples of how to handle these events.</p> +</section><section id="handling-browser-events"> +<h2 id="handling-browser-events">Handling browser events</h2> +<section id="didchangeview"> +<h3 id="didchangeview">DidChangeView()</h3> +<p>In the <code>mouse_lock</code> example, <code>DidChangeView()</code> checks the previous size +of instance’s rectangle versus the new size. It also compares +other state such as whether or not the app is running in full screen mode. +If none of the state has actually changed, no action is needed. +However, if the size of the view or other state has changed, it frees the +old graphics context and allocates a new one.</p> +<pre class="prettyprint"> +void MouseLockInstance::DidChangeView(const pp::View& view) { + // DidChangeView can get called for many reasons, so we only want to + // rebuild the device context if we really need to. + if ((size_ == view.GetRect().size()) && + (was_fullscreen_ == view.IsFullscreen()) && is_context_bound_) { + return; + } + + // ... + + // Reallocate the graphics context. + size_ = view.GetRect().size(); + device_context_ = pp::Graphics2D(this, size_, false); + waiting_for_flush_completion_ = false; + + is_context_bound_ = BindGraphics(device_context_); + // ... + + // Remember if we are fullscreen or not + was_fullscreen_ = view.IsFullscreen(); + // ... +} +</pre> +<p>For more information about graphics contexts and how to manipulate images, see:</p> +<ul class="small-gap"> +<li><a class="reference external" href="https://developers.google.com/native-client/dev/peppercpp/classpp_1_1_image_data">pp::ImageData class</a></li> +<li><a class="reference external" href="https://developers.google.com/native-client/dev/peppercpp/classpp_1_1_graphics2_d">pp::Graphics2D class</a></li> +</ul> +</section><section id="didchangefocus"> +<h3 id="didchangefocus">DidChangeFocus()</h3> +<p><code>DidChangeFocus()</code> is called when you click inside or outside of a +module’s instance in the web page. When the instance goes out +of focus (click outside of the instance), you might do something +like stop an animation. When the instance regains focus, you can +restart the animation.</p> +<pre class="prettyprint"> +void DidChangeFocus(bool focus) { + // Do something like stopping animation or a blinking cursor in + // the instance. +} +</pre> +</section></section><section id="handling-input-events"> +<h2 id="handling-input-events">Handling input events</h2> +<p>Input events are events that occur when the user interacts with a +module instance using the mouse, keyboard, or other input device +(e.g., touch screen). This section describes how the <code>input_events</code> +example handles input events.</p> +<section id="registering-a-module-to-accept-input-events"> +<h3 id="registering-a-module-to-accept-input-events">Registering a module to accept input events</h3> +<p>Before your module can handle these events, you must register your +module to accept input events using <code>RequestInputEvents()</code> for mouse +events and <code>RequestFilteringInputEvents()</code> for keyboard events. For the +<code>input_events</code> example, this is done in the constructor of the +<code>InputEventInstance</code> class:</p> +<pre class="prettyprint"> +class InputEventInstance : public pp::Instance { + public: + explicit InputEventInstance(PP_Instance instance) + : pp::Instance(instance), event_thread_(NULL), callback_factory_(this) { + RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE | PP_INPUTEVENT_CLASS_WHEEL | + PP_INPUTEVENT_CLASS_TOUCH); + RequestFilteringInputEvents(PP_INPUTEVENT_CLASS_KEYBOARD); + } + // ... +}; +</pre> +<p><code>RequestInputEvents()</code> and <code>RequestFilteringInputEvents()</code> accept a +combination of flags that identify the class of events that the +instance is requesting to receive. Input event classes are defined in +the <a class="reference external" href="https://developers.google.com/native-client/dev/pepperc/group___enums.html#gafe68e3c1031daa4a6496845ff47649cd">PP_InputEvent_Class</a> +enumeration in <a class="reference external" href="https://developers.google.com/native-client/dev/pepperc/ppb__input__event_8h">ppb_input_event.h</a>.</p> +</section><section id="determining-and-branching-on-event-types"> +<h3 id="determining-and-branching-on-event-types">Determining and branching on event types</h3> +<p>In a typical implementation, the <code>HandleInputEvent()</code> function +determines the type of each event using the <code>GetType()</code> function found +in the <code>InputEvent</code> class. The <code>HandleInputEvent()</code> function then uses a +switch statement to branch on the type of input event. Input events +are defined in the <a class="reference external" href="https://developers.google.com/native-client/dev/pepperc/group___enums.html#gaca7296cfec99fcb6646b7144d1d6a0c5">PP_InputEvent_Type</a> +enumeration in <a class="reference external" href="https://developers.google.com/native-client/dev/pepperc/ppb__input__event_8h">ppb_input_event.h</a>.</p> +<pre class="prettyprint"> +virtual bool HandleInputEvent(const pp::InputEvent& event) { + Event* event_ptr = NULL; + switch (event.GetType()) { + case PP_INPUTEVENT_TYPE_UNDEFINED: + break; + case PP_INPUTEVENT_TYPE_MOUSEDOWN: + case PP_INPUTEVENT_TYPE_MOUSEUP: + case PP_INPUTEVENT_TYPE_MOUSEMOVE: + case PP_INPUTEVENT_TYPE_MOUSEENTER: + case PP_INPUTEVENT_TYPE_MOUSELEAVE: + case PP_INPUTEVENT_TYPE_CONTEXTMENU: { + pp::MouseInputEvent mouse_event(event); + PP_InputEvent_MouseButton pp_button = mouse_event.GetButton(); + MouseEvent::MouseButton mouse_button = MouseEvent::kNone; + switch (pp_button) { + case PP_INPUTEVENT_MOUSEBUTTON_NONE: + mouse_button = MouseEvent::kNone; + break; + case PP_INPUTEVENT_MOUSEBUTTON_LEFT: + mouse_button = MouseEvent::kLeft; + break; + case PP_INPUTEVENT_MOUSEBUTTON_MIDDLE: + mouse_button = MouseEvent::kMiddle; + break; + case PP_INPUTEVENT_MOUSEBUTTON_RIGHT: + mouse_button = MouseEvent::kRight; + break; + } + event_ptr = + new MouseEvent(ConvertEventModifier(mouse_event.GetModifiers()), + mouse_button, + mouse_event.GetPosition().x(), + mouse_event.GetPosition().y(), + mouse_event.GetClickCount(), + mouse_event.GetTimeStamp(), + event.GetType() == PP_INPUTEVENT_TYPE_CONTEXTMENU); + } break; + case PP_INPUTEVENT_TYPE_WHEEL: { + pp::WheelInputEvent wheel_event(event); + event_ptr = + new WheelEvent(ConvertEventModifier(wheel_event.GetModifiers()), + wheel_event.GetDelta().x(), + wheel_event.GetDelta().y(), + wheel_event.GetTicks().x(), + wheel_event.GetTicks().y(), + wheel_event.GetScrollByPage(), + wheel_event.GetTimeStamp()); + } break; + case PP_INPUTEVENT_TYPE_RAWKEYDOWN: + case PP_INPUTEVENT_TYPE_KEYDOWN: + case PP_INPUTEVENT_TYPE_KEYUP: + case PP_INPUTEVENT_TYPE_CHAR: { + pp::KeyboardInputEvent key_event(event); + event_ptr = new KeyEvent(ConvertEventModifier(key_event.GetModifiers()), + key_event.GetKeyCode(), + key_event.GetTimeStamp(), + key_event.GetCharacterText().DebugString()); + } break; + default: { + // For any unhandled events, send a message to the browser + // so that the user is aware of these and can investigate. + std::stringstream oss; + oss << "Default (unhandled) event, type=" << event.GetType(); + PostMessage(oss.str()); + } break; + } + event_queue_.Push(event_ptr); + return true; +} +</pre> +<p>Notice that the generic <code>InputEvent</code> received by <code>HandleInputEvent()</code> is +converted into a specific type after the event type is +determined. The event types handled in the example code are +<code>MouseInputEvent</code>, <code>WheelInputEvent</code>, and <code>KeyboardInputEvent</code>. +There are also <code>TouchInputEvents</code>. For the latest list of event types, +see the <a class="reference external" href="https://developers.google.com/native-client/dev/peppercpp/classpp_1_1_input_event">InputEvent documentation</a>. +For reference information related to the these event classes, see the +following documentation:</p> +<ul class="small-gap"> +<li><a class="reference external" href="https://developers.google.com/native-client/dev/peppercpp/classpp_1_1_mouse_input_event">pp::MouseInputEvent class</a></li> +<li><a class="reference external" href="https://developers.google.com/native-client/dev/peppercpp/classpp_1_1_wheel_input_event">pp::WheelInputEvent class</a></li> +<li><a class="reference external" href="https://developers.google.com/native-client/dev/peppercpp/classpp_1_1_keyboard_input_event">pp::KeyboardInputEvent class</a></li> +</ul> +</section><section id="threading-and-blocking"> +<h3 id="threading-and-blocking">Threading and blocking</h3> +<p><code>HandleInputEvent()</code> in this example runs on the main module thread. +However, the bulk of the work happens on a separate worker thread (see +<code>ProcessEventOnWorkerThread</code>). <code>HandleInputEvent()</code> puts events in +the <code>event_queue_</code> and the worker thread takes events from the +<code>event_queue_</code>. This processing happens independently of the main +thread, so as not to slow down the browser.</p> +</section></section></section> + +{{/partials.standard_nacl_article}} |