[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
This commit is contained in:
native_client_sdk
doc_generated
.buildinfofaq.htmlglossary.htmlhelp.htmlpublications-and-presentations.htmlquick-start.html
_static
community
devguide
coding
3D-graphics.htmlapplication-structure.htmlaudio.htmlfile-io.htmlindex.htmlmessage-system.htmlnacl_io.htmlnative-client-modules.htmlprogress-events.htmlurl-loading.htmlview-focus-input-events.html
devcycle
distributing.htmlindex.htmltutorial
images
3d-graphics-render-loop.pngNaclBlock.pngcalendar-32.gifcheck-red.pngcode-32.gifextensions-management.pngfileioexample.pnggear-icon.pnggift-32.gificon128.pngicon16.pngmedal-64_1st.pngmedal-64_2nd.pngmedal-64_3rd.pngmedal-64_4th.pngmenu-icon.pngnacl-in-a-web-app.pngnacl-pnacl-component-diagram.pngnacl_io1.pngnew-tab-apps.pngpepper-audio-api.pngpepper-audio-buffer.pngpepper-urlloader-api.pngpuzzle.pngvisualstudio1.pngvisualstudio2.pngvisualstudio4.pngweb-app-with-nacl.png
index.htmlnacl-and-pnacl.htmloverview.htmlpepper_beta
c
globals_defs.htmlgroup___enums.htmlgroup___functions.htmlgroup___interfaces.htmlgroup___structs.htmlgroup___typedefs.htmlindex.htmlindex.rstpp__array__output_8h.htmlpp__array__output_8h__incl.pngpp__bool_8h.htmlpp__bool_8h__incl.pngpp__completion__callback_8h.htmlpp__completion__callback_8h__incl.pngpp__directory__entry_8h.htmlpp__directory__entry_8h__incl.pngpp__errors_8h.htmlpp__errors_8h__incl.pngpp__file__info_8h.htmlpp__file__info_8h__incl.pngpp__graphics__3d_8h.htmlpp__graphics__3d_8h__incl.pngpp__input__event_8h.htmlpp__input__event_8h__incl.pngpp__instance_8h.htmlpp__instance_8h__incl.pngpp__module_8h.htmlpp__module_8h__incl.pngpp__point_8h.htmlpp__point_8h__incl.pngpp__rect_8h.htmlpp__rect_8h__incl.pngpp__resource_8h.htmlpp__resource_8h__incl.pngpp__size_8h.htmlpp__size_8h__incl.pngpp__stdint_8h.htmlpp__stdint_8h__incl.pngpp__time_8h.htmlpp__time_8h__incl.pngpp__touch__point_8h.htmlpp__touch__point_8h__incl.pngpp__var_8h.htmlpp__var_8h__incl.pngppb_8h.htmlppb_8h__incl.pngppb__audio_8h.htmlppb__audio_8h__incl.pngppb__audio__config_8h.htmlppb__audio__config_8h__incl.pngppb__console_8h.htmlppb__console_8h__incl.pngppb__core_8h.htmlppb__core_8h__incl.pngppb__file__io_8h.htmlppb__file__io_8h__incl.pngppb__file__ref_8h.htmlppb__file__ref_8h__incl.pngppb__file__system_8h.htmlppb__file__system_8h__incl.pngppb__fullscreen_8h.htmlppb__fullscreen_8h__incl.pngppb__gamepad_8h.htmlppb__gamepad_8h__incl.pngppb__graphics__2d_8h.htmlppb__graphics__2d_8h__incl.pngppb__graphics__3d_8h.htmlppb__graphics__3d_8h__incl.pngppb__host__resolver_8h.htmlppb__host__resolver_8h__incl.pngppb__image__data_8h.htmlppb__image__data_8h__incl.pngppb__input__event_8h.htmlppb__input__event_8h__incl.pngppb__instance_8h.htmlppb__instance_8h__incl.pngppb__message__loop_8h.htmlppb__message__loop_8h__incl.pngppb__messaging_8h.htmlppb__messaging_8h__incl.pngppb__mouse__cursor_8h.htmlppb__mouse__cursor_8h__incl.pngppb__mouse__lock_8h.htmlppb__mouse__lock_8h__incl.pngppb__net__address_8h.htmlppb__net__address_8h__incl.pngppb__network__list_8h.htmlppb__network__list_8h__incl.pngppb__network__monitor_8h.htmlppb__network__monitor_8h__incl.pngppb__network__proxy_8h.htmlppb__network__proxy_8h__incl.pngppb__tcp__socket_8h.htmlppb__tcp__socket_8h__incl.pngppb__text__input__controller_8h.htmlppb__text__input__controller_8h__incl.pngppb__udp__socket_8h.htmlppb__udp__socket_8h__incl.pngppb__url__loader_8h.htmlppb__url__loader_8h__incl.pngppb__url__request__info_8h.htmlppb__url__request__info_8h__incl.pngppb__url__response__info_8h.htmlppb__url__response__info_8h__incl.pngppb__var_8h.htmlppb__var_8h__incl.pngppb__var__array_8h.htmlppb__var__array_8h__incl.pngppb__var__array__buffer_8h.htmlppb__var__array__buffer_8h__incl.pngppb__var__dictionary_8h.htmlppb__var__dictionary_8h__incl.pngppb__view_8h.htmlppb__view_8h__incl.pngppb__websocket_8h.htmlppb__websocket_8h__incl.pngppp_8h.htmlppp_8h__incl.pngppp__graphics__3d_8h.htmlppp__graphics__3d_8h__incl.pngppp__input__event_8h.htmlppp__input__event_8h__incl.pngppp__instance_8h.htmlppp__instance_8h__incl.pngppp__messaging_8h.htmlppp__messaging_8h__incl.pngppp__mouse__lock_8h.htmlppp__mouse__lock_8h__incl.pngstruct_p_p___array_output.htmlstruct_p_p___completion_callback.htmlstruct_p_p___directory_entry.htmlstruct_p_p___file_info.htmlstruct_p_p___float_point.htmlstruct_p_p___gamepad_sample_data.htmlstruct_p_p___gamepads_sample_data.htmlstruct_p_p___host_resolver___hint.htmlstruct_p_p___image_data_desc.htmlstruct_p_p___input_event___character.htmlstruct_p_p___input_event___key.htmlstruct_p_p___input_event___mouse.htmlstruct_p_p___input_event___wheel.htmlstruct_p_p___net_address___i_pv4.htmlstruct_p_p___net_address___i_pv6.htmlstruct_p_p___point.htmlstruct_p_p___rect.htmlstruct_p_p___size.htmlstruct_p_p___touch_point.htmlstruct_p_p___var.htmlstruct_p_p_b___audio__1__1.htmlstruct_p_p_b___audio_config__1__1.htmlstruct_p_p_b___console__1__0.htmlstruct_p_p_b___core__1__0.htmlstruct_p_p_b___file_i_o__1__1.htmlstruct_p_p_b___file_ref__1__1.htmlstruct_p_p_b___file_system__1__0.htmlstruct_p_p_b___fullscreen__1__0.htmlstruct_p_p_b___gamepad__1__0.htmlstruct_p_p_b___graphics2_d__1__1.htmlstruct_p_p_b___graphics3_d__1__0.htmlstruct_p_p_b___host_resolver__1__0.htmlstruct_p_p_b___i_m_e_input_event__1__0.htmlstruct_p_p_b___image_data__1__0.htmlstruct_p_p_b___input_event__1__0.htmlstruct_p_p_b___instance__1__0.htmlstruct_p_p_b___keyboard_input_event__1__0.htmlstruct_p_p_b___message_loop__1__0.htmlstruct_p_p_b___messaging__1__0.htmlstruct_p_p_b___mouse_cursor__1__0.htmlstruct_p_p_b___mouse_input_event__1__1.htmlstruct_p_p_b___mouse_lock__1__0.htmlstruct_p_p_b___net_address__1__0.htmlstruct_p_p_b___network_list__1__0.htmlstruct_p_p_b___network_monitor__1__0.htmlstruct_p_p_b___network_proxy__1__0.htmlstruct_p_p_b___t_c_p_socket__1__1.htmlstruct_p_p_b___text_input_controller__1__0.htmlstruct_p_p_b___touch_input_event__1__0.htmlstruct_p_p_b___u_d_p_socket__1__0.htmlstruct_p_p_b___u_r_l_loader__1__0.htmlstruct_p_p_b___u_r_l_request_info__1__0.htmlstruct_p_p_b___u_r_l_response_info__1__0.htmlstruct_p_p_b___var__1__1.htmlstruct_p_p_b___var_array__1__0.htmlstruct_p_p_b___var_array_buffer__1__0.htmlstruct_p_p_b___var_dictionary__1__0.htmlstruct_p_p_b___view__1__1.htmlstruct_p_p_b___web_socket__1__0.htmlstruct_p_p_b___wheel_input_event__1__0.htmlstruct_p_p_p___graphics3_d__1__0.htmlstruct_p_p_p___input_event__0__1.htmlstruct_p_p_p___instance__1__1.htmlstruct_p_p_p___messaging__1__0.htmlstruct_p_p_p___mouse_lock__1__0.htmlunion_p_p___var_value.html
cpp
audio_8h.htmlaudio_8h__incl.pngaudio__config_8h.htmlaudio__config_8h__incl.pngclasspp_1_1_audio-members.htmlclasspp_1_1_audio.htmlclasspp_1_1_audio__inherit__graph.pngclasspp_1_1_audio_config-members.htmlclasspp_1_1_audio_config.htmlclasspp_1_1_audio_config__inherit__graph.pngclasspp_1_1_completion_callback-members.htmlclasspp_1_1_completion_callback.htmlclasspp_1_1_completion_callback__inherit__graph.pngclasspp_1_1_completion_callback_factory-members.htmlclasspp_1_1_completion_callback_factory.htmlclasspp_1_1_completion_callback_with_output-members.htmlclasspp_1_1_completion_callback_with_output.htmlclasspp_1_1_completion_callback_with_output__inherit__graph.pngclasspp_1_1_core-members.htmlclasspp_1_1_core.htmlclasspp_1_1_directory_entry-members.htmlclasspp_1_1_directory_entry.htmlclasspp_1_1_file_i_o-members.htmlclasspp_1_1_file_i_o.htmlclasspp_1_1_file_i_o__inherit__graph.pngclasspp_1_1_file_ref-members.htmlclasspp_1_1_file_ref.htmlclasspp_1_1_file_ref__inherit__graph.pngclasspp_1_1_file_system-members.htmlclasspp_1_1_file_system.htmlclasspp_1_1_file_system__inherit__graph.pngclasspp_1_1_float_point-members.htmlclasspp_1_1_float_point.htmlclasspp_1_1_fullscreen-members.htmlclasspp_1_1_fullscreen.htmlclasspp_1_1_graphics2_d-members.htmlclasspp_1_1_graphics2_d.htmlclasspp_1_1_graphics2_d__inherit__graph.pngclasspp_1_1_graphics3_d-members.htmlclasspp_1_1_graphics3_d.htmlclasspp_1_1_graphics3_d__inherit__graph.pngclasspp_1_1_graphics3_d_client-members.htmlclasspp_1_1_graphics3_d_client.htmlclasspp_1_1_host_resolver-members.htmlclasspp_1_1_host_resolver.htmlclasspp_1_1_host_resolver__inherit__graph.pngclasspp_1_1_i_m_e_input_event-members.htmlclasspp_1_1_i_m_e_input_event.htmlclasspp_1_1_i_m_e_input_event__inherit__graph.pngclasspp_1_1_image_data-members.htmlclasspp_1_1_image_data.htmlclasspp_1_1_image_data__inherit__graph.pngclasspp_1_1_input_event-members.htmlclasspp_1_1_input_event.htmlclasspp_1_1_input_event__inherit__graph.pngclasspp_1_1_instance-members.htmlclasspp_1_1_instance.htmlclasspp_1_1_instance_handle-members.htmlclasspp_1_1_instance_handle.htmlclasspp_1_1_keyboard_input_event-members.htmlclasspp_1_1_keyboard_input_event.htmlclasspp_1_1_keyboard_input_event__inherit__graph.pngclasspp_1_1_message_loop-members.htmlclasspp_1_1_message_loop.htmlclasspp_1_1_message_loop__inherit__graph.pngclasspp_1_1_module-members.htmlclasspp_1_1_module.htmlclasspp_1_1_mouse_cursor-members.htmlclasspp_1_1_mouse_cursor.htmlclasspp_1_1_mouse_input_event-members.htmlclasspp_1_1_mouse_input_event.htmlclasspp_1_1_mouse_input_event__inherit__graph.pngclasspp_1_1_mouse_lock-members.htmlclasspp_1_1_mouse_lock.htmlclasspp_1_1_net_address-members.htmlclasspp_1_1_net_address.htmlclasspp_1_1_net_address__inherit__graph.pngclasspp_1_1_network_list-members.htmlclasspp_1_1_network_list.htmlclasspp_1_1_network_list__inherit__graph.pngclasspp_1_1_network_monitor-members.htmlclasspp_1_1_network_monitor.htmlclasspp_1_1_network_monitor__inherit__graph.pngclasspp_1_1_network_proxy-members.htmlclasspp_1_1_network_proxy.htmlclasspp_1_1_point-members.htmlclasspp_1_1_point.htmlclasspp_1_1_rect-members.htmlclasspp_1_1_rect.htmlclasspp_1_1_resource-members.htmlclasspp_1_1_resource.htmlclasspp_1_1_resource__inherit__graph.pngclasspp_1_1_size-members.htmlclasspp_1_1_size.htmlclasspp_1_1_t_c_p_socket-members.htmlclasspp_1_1_t_c_p_socket.htmlclasspp_1_1_t_c_p_socket__inherit__graph.pngclasspp_1_1_text_input_controller-members.htmlclasspp_1_1_text_input_controller.htmlclasspp_1_1_touch_input_event-members.htmlclasspp_1_1_touch_input_event.htmlclasspp_1_1_touch_input_event__inherit__graph.pngclasspp_1_1_touch_point-members.htmlclasspp_1_1_touch_point.htmlclasspp_1_1_u_d_p_socket-members.htmlclasspp_1_1_u_d_p_socket.htmlclasspp_1_1_u_d_p_socket__inherit__graph.pngclasspp_1_1_u_r_l_loader-members.htmlclasspp_1_1_u_r_l_loader.htmlclasspp_1_1_u_r_l_loader__inherit__graph.pngclasspp_1_1_u_r_l_request_info-members.htmlclasspp_1_1_u_r_l_request_info.htmlclasspp_1_1_u_r_l_request_info__inherit__graph.pngclasspp_1_1_u_r_l_response_info-members.htmlclasspp_1_1_u_r_l_response_info.htmlclasspp_1_1_u_r_l_response_info__inherit__graph.pngclasspp_1_1_var-members.htmlclasspp_1_1_var.htmlclasspp_1_1_var_1_1_out_exception-members.htmlclasspp_1_1_var_1_1_out_exception.htmlclasspp_1_1_var__inherit__graph.pngclasspp_1_1_var_array-members.htmlclasspp_1_1_var_array.htmlclasspp_1_1_var_array__inherit__graph.pngclasspp_1_1_var_array_buffer-members.htmlclasspp_1_1_var_array_buffer.htmlclasspp_1_1_var_array_buffer__inherit__graph.pngclasspp_1_1_var_dictionary-members.htmlclasspp_1_1_var_dictionary.htmlclasspp_1_1_var_dictionary__inherit__graph.pngclasspp_1_1_view-members.htmlclasspp_1_1_view.htmlclasspp_1_1_view__inherit__graph.pngclasspp_1_1_web_socket-members.htmlclasspp_1_1_web_socket.htmlclasspp_1_1_web_socket__inherit__graph.pngclasspp_1_1_wheel_input_event-members.htmlclasspp_1_1_wheel_input_event.htmlclasspp_1_1_wheel_input_event__inherit__graph.pngclasspp_1_1ext_1_1_ext_completion_callback_with_output-members.htmlclasspp_1_1ext_1_1_ext_completion_callback_with_output.htmlclasspp_1_1ext_1_1_ext_completion_callback_with_output__inherit__graph.pngclasspp_1_1internal_1_1_completion_callback_with_output_base-members.htmlclasspp_1_1internal_1_1_completion_callback_with_output_base.htmlclasspp_1_1internal_1_1_completion_callback_with_output_base__inherit__graph.pngclasspp_1_1internal_1_1_directory_entry_array_output_adapter_with_storage-members.htmlclasspp_1_1internal_1_1_directory_entry_array_output_adapter_with_storage.htmlcompletion__callback_8h.htmlcompletion__callback_8h__incl.pngcompletion__callback__factory_8h.htmlcompletion__callback__factory_8h__incl.pngcore_8h.htmlcore_8h__incl.pngdirectory__entry_8h.htmldirectory__entry_8h__incl.pngfile__io_8h.htmlfile__io_8h__incl.pngfile__ref_8h.htmlfile__ref_8h__incl.pngfile__system_8h.htmlfile__system_8h__incl.pngfullscreen_8h.htmlfullscreen_8h__incl.pngglobals_defs.htmlgraphics__2d_8h.htmlgraphics__2d_8h__incl.pnggraphics__3d_8h.htmlgraphics__3d_8h__incl.pnggraphics__3d__client_8h.htmlgraphics__3d__client_8h__incl.pnghost__resolver_8h.htmlhost__resolver_8h__incl.pngimage__data_8h.htmlimage__data_8h__incl.pngindex.htmlindex.rstinherit_graph_0.pnginherit_graph_1.pnginherit_graph_10.pnginherit_graph_11.pnginherit_graph_12.pnginherit_graph_13.pnginherit_graph_14.pnginherit_graph_15.pnginherit_graph_16.pnginherit_graph_17.pnginherit_graph_18.pnginherit_graph_19.pnginherit_graph_2.pnginherit_graph_20.pnginherit_graph_21.pnginherit_graph_22.pnginherit_graph_23.pnginherit_graph_24.pnginherit_graph_25.pnginherit_graph_26.pnginherit_graph_27.pnginherit_graph_3.pnginherit_graph_4.pnginherit_graph_5.pnginherit_graph_6.pnginherit_graph_7.pnginherit_graph_8.pnginherit_graph_9.pnginherits.htmlinput__event_8h.htmlinput__event_8h__incl.pnginstance_8h.htmlinstance_8h__incl.pnginstance__handle_8h.htmlinstance__handle_8h__incl.pnglogging_8h.htmllogging_8h__incl.pngmessage__loop_8h.htmlmessage__loop_8h__incl.pngmodule_8h.htmlmodule_8h__incl.pngmodule__embedder_8h.htmlmodule__embedder_8h__incl.pngmodule__impl_8h.htmlmodule__impl_8h__incl.pngmouse__cursor_8h.htmlmouse__cursor_8h__incl.pngmouse__lock_8h.htmlmouse__lock_8h__incl.pngnamespacemembers_enum.htmlnamespacemembers_eval.htmlnamespacepp.htmlnamespacepp_1_1ext.htmlnamespacepp_1_1internal.htmlnet__address_8h.htmlnet__address_8h__incl.pngnetwork__list_8h.htmlnetwork__list_8h__incl.pngnetwork__monitor_8h.htmlnetwork__monitor_8h__incl.pngnetwork__proxy_8h.htmlnetwork__proxy_8h__incl.pngpass__ref_8h.htmlpoint_8h.htmlpoint_8h__incl.pngrect_8h.htmlrect_8h__incl.pngresource_8h.htmlresource_8h__incl.pngsize_8h.htmlsize_8h__incl.pngstructpp_1_1_var_1_1_dont_manage.htmlstructpp_1_1_var_1_1_null.htmlstructpp_1_1internal_1_1_callback_output_traits_3_01std_1_1vector_3_01_directory_entry_01_4_01_4-members.htmlstructpp_1_1internal_1_1_callback_output_traits_3_01std_1_1vector_3_01_directory_entry_01_4_01_4.htmlstructpp_1_1internal_1_1_type_unwrapper-members.htmlstructpp_1_1internal_1_1_type_unwrapper.htmlstructpp_1_1internal_1_1_type_unwrapper_3_01_t_01_6_01_4-members.htmlstructpp_1_1internal_1_1_type_unwrapper_3_01_t_01_6_01_4.htmlstructpp_1_1internal_1_1_type_unwrapper_3_01const_01_t_01_6_01_4-members.htmlstructpp_1_1internal_1_1_type_unwrapper_3_01const_01_t_01_6_01_4.htmltcp__socket_8h.htmltcp__socket_8h__incl.pngtext__input__controller_8h.htmltext__input__controller_8h__incl.pngtouch__point_8h.htmltouch__point_8h__incl.pngudp__socket_8h.htmludp__socket_8h__incl.pngurl__loader_8h.htmlurl__loader_8h__incl.pngurl__request__info_8h.htmlurl__request__info_8h__incl.pngurl__response__info_8h.htmlurl__response__info_8h__incl.pngvar_8h.htmlvar_8h__incl.pngvar__array_8h.htmlvar__array_8h__incl.pngvar__array__buffer_8h.htmlvar__array__buffer_8h__incl.pngvar__dictionary_8h.htmlvar__dictionary_8h__incl.pngview_8h.htmlview_8h__incl.pngwebsocket_8h.htmlwebsocket_8h__incl.png
index.htmlpepper_dev
c
globals_defs.htmlgroup___enums.htmlgroup___functions.htmlgroup___interfaces.htmlgroup___structs.htmlgroup___typedefs.htmlindex.htmlindex.rstpp__array__output_8h.htmlpp__array__output_8h__incl.pngpp__bool_8h.htmlpp__bool_8h__incl.pngpp__completion__callback_8h.htmlpp__completion__callback_8h__incl.pngpp__directory__entry_8h.htmlpp__directory__entry_8h__incl.pngpp__errors_8h.htmlpp__errors_8h__incl.pngpp__file__info_8h.htmlpp__file__info_8h__incl.pngpp__graphics__3d_8h.htmlpp__graphics__3d_8h__incl.pngpp__input__event_8h.htmlpp__input__event_8h__incl.pngpp__instance_8h.htmlpp__instance_8h__incl.pngpp__module_8h.htmlpp__module_8h__incl.pngpp__point_8h.htmlpp__point_8h__incl.pngpp__rect_8h.htmlpp__rect_8h__incl.pngpp__resource_8h.htmlpp__resource_8h__incl.pngpp__size_8h.htmlpp__size_8h__incl.pngpp__stdint_8h.htmlpp__stdint_8h__incl.pngpp__time_8h.htmlpp__time_8h__incl.pngpp__touch__point_8h.htmlpp__touch__point_8h__incl.pngpp__var_8h.htmlpp__var_8h__incl.pngppb_8h.htmlppb_8h__incl.pngppb__audio_8h.htmlppb__audio_8h__incl.pngppb__audio__config_8h.htmlppb__audio__config_8h__incl.pngppb__audio__frame_8h.htmlppb__audio__frame_8h__incl.pngppb__console_8h.htmlppb__console_8h__incl.pngppb__core_8h.htmlppb__core_8h__incl.pngppb__file__io_8h.htmlppb__file__io_8h__incl.pngppb__file__ref_8h.htmlppb__file__ref_8h__incl.pngppb__file__system_8h.htmlppb__file__system_8h__incl.pngppb__fullscreen_8h.htmlppb__fullscreen_8h__incl.pngppb__gamepad_8h.htmlppb__gamepad_8h__incl.pngppb__graphics__2d_8h.htmlppb__graphics__2d_8h__incl.pngppb__graphics__3d_8h.htmlppb__graphics__3d_8h__incl.pngppb__host__resolver_8h.htmlppb__host__resolver_8h__incl.pngppb__image__data_8h.htmlppb__image__data_8h__incl.pngppb__input__event_8h.htmlppb__input__event_8h__incl.pngppb__instance_8h.htmlppb__instance_8h__incl.pngppb__media__stream__audio__track_8h.htmlppb__media__stream__audio__track_8h__incl.pngppb__media__stream__video__track_8h.htmlppb__media__stream__video__track_8h__incl.pngppb__message__loop_8h.htmlppb__message__loop_8h__incl.pngppb__messaging_8h.htmlppb__messaging_8h__incl.pngppb__mouse__cursor_8h.htmlppb__mouse__cursor_8h__incl.pngppb__mouse__lock_8h.htmlppb__mouse__lock_8h__incl.pngppb__net__address_8h.htmlppb__net__address_8h__incl.pngppb__network__list_8h.htmlppb__network__list_8h__incl.pngppb__network__monitor_8h.htmlppb__network__monitor_8h__incl.pngppb__network__proxy_8h.htmlppb__network__proxy_8h__incl.pngppb__tcp__socket_8h.htmlppb__tcp__socket_8h__incl.pngppb__text__input__controller_8h.htmlppb__text__input__controller_8h__incl.pngppb__udp__socket_8h.htmlppb__udp__socket_8h__incl.pngppb__url__loader_8h.htmlppb__url__loader_8h__incl.pngppb__url__request__info_8h.htmlppb__url__request__info_8h__incl.pngppb__url__response__info_8h.htmlppb__url__response__info_8h__incl.pngppb__var_8h.htmlppb__var_8h__incl.pngppb__var__array_8h.htmlppb__var__array_8h__incl.pngppb__var__array__buffer_8h.htmlppb__var__array__buffer_8h__incl.pngppb__var__dictionary_8h.htmlppb__var__dictionary_8h__incl.pngppb__video__frame_8h.htmlppb__video__frame_8h__incl.pngppb__view_8h.htmlppb__view_8h__incl.pngppb__websocket_8h.htmlppb__websocket_8h__incl.pngppp_8h.htmlppp_8h__incl.pngppp__graphics__3d_8h.htmlppp__graphics__3d_8h__incl.pngppp__input__event_8h.htmlppp__input__event_8h__incl.pngppp__instance_8h.htmlppp__instance_8h__incl.pngppp__messaging_8h.htmlppp__messaging_8h__incl.pngppp__mouse__lock_8h.htmlppp__mouse__lock_8h__incl.pngstruct_p_p___array_output.htmlstruct_p_p___completion_callback.htmlstruct_p_p___directory_entry.htmlstruct_p_p___file_info.htmlstruct_p_p___float_point.htmlstruct_p_p___gamepad_sample_data.htmlstruct_p_p___gamepads_sample_data.htmlstruct_p_p___host_resolver___hint.htmlstruct_p_p___image_data_desc.htmlstruct_p_p___input_event___character.htmlstruct_p_p___input_event___key.htmlstruct_p_p___input_event___mouse.htmlstruct_p_p___input_event___wheel.htmlstruct_p_p___net_address___i_pv4.htmlstruct_p_p___net_address___i_pv6.htmlstruct_p_p___point.htmlstruct_p_p___rect.htmlstruct_p_p___size.htmlstruct_p_p___touch_point.htmlstruct_p_p___var.htmlstruct_p_p_b___audio__1__1.htmlstruct_p_p_b___audio_config__1__1.htmlstruct_p_p_b___audio_frame__0__1.htmlstruct_p_p_b___console__1__0.htmlstruct_p_p_b___core__1__0.htmlstruct_p_p_b___file_i_o__1__1.htmlstruct_p_p_b___file_ref__1__2.htmlstruct_p_p_b___file_system__1__0.htmlstruct_p_p_b___fullscreen__1__0.htmlstruct_p_p_b___gamepad__1__0.htmlstruct_p_p_b___graphics2_d__1__1.htmlstruct_p_p_b___graphics3_d__1__0.htmlstruct_p_p_b___host_resolver__1__0.htmlstruct_p_p_b___i_m_e_input_event__1__0.htmlstruct_p_p_b___image_data__1__0.htmlstruct_p_p_b___input_event__1__0.htmlstruct_p_p_b___instance__1__0.htmlstruct_p_p_b___keyboard_input_event__1__0.htmlstruct_p_p_b___media_stream_audio_track__0__1.htmlstruct_p_p_b___media_stream_video_track__0__1.htmlstruct_p_p_b___message_loop__1__0.htmlstruct_p_p_b___messaging__1__0.htmlstruct_p_p_b___mouse_cursor__1__0.htmlstruct_p_p_b___mouse_input_event__1__1.htmlstruct_p_p_b___mouse_lock__1__0.htmlstruct_p_p_b___net_address__1__0.htmlstruct_p_p_b___network_list__1__0.htmlstruct_p_p_b___network_monitor__1__0.htmlstruct_p_p_b___network_proxy__1__0.htmlstruct_p_p_b___t_c_p_socket__1__1.htmlstruct_p_p_b___text_input_controller__1__0.htmlstruct_p_p_b___touch_input_event__1__0.htmlstruct_p_p_b___u_d_p_socket__1__0.htmlstruct_p_p_b___u_r_l_loader__1__0.htmlstruct_p_p_b___u_r_l_request_info__1__0.htmlstruct_p_p_b___u_r_l_response_info__1__0.htmlstruct_p_p_b___var__1__1.htmlstruct_p_p_b___var_array__1__0.htmlstruct_p_p_b___var_array_buffer__1__0.htmlstruct_p_p_b___var_dictionary__1__0.htmlstruct_p_p_b___video_frame__0__1.htmlstruct_p_p_b___view__1__1.htmlstruct_p_p_b___web_socket__1__0.htmlstruct_p_p_b___wheel_input_event__1__0.htmlstruct_p_p_p___graphics3_d__1__0.htmlstruct_p_p_p___input_event__0__1.htmlstruct_p_p_p___instance__1__1.htmlstruct_p_p_p___messaging__1__0.htmlstruct_p_p_p___mouse_lock__1__0.htmlunion_p_p___var_value.html
cpp
audio_8h.htmlaudio_8h__incl.pngaudio__config_8h.htmlaudio__config_8h__incl.pngaudio__frame_8h.htmlaudio__frame_8h__incl.pngclasspp_1_1_audio-members.htmlclasspp_1_1_audio.htmlclasspp_1_1_audio__inherit__graph.pngclasspp_1_1_audio_config-members.htmlclasspp_1_1_audio_config.htmlclasspp_1_1_audio_config__inherit__graph.pngclasspp_1_1_audio_frame-members.htmlclasspp_1_1_audio_frame.htmlclasspp_1_1_audio_frame__inherit__graph.pngclasspp_1_1_completion_callback-members.htmlclasspp_1_1_completion_callback.htmlclasspp_1_1_completion_callback__inherit__graph.pngclasspp_1_1_completion_callback_factory-members.htmlclasspp_1_1_completion_callback_factory.htmlclasspp_1_1_completion_callback_with_output-members.htmlclasspp_1_1_completion_callback_with_output.htmlclasspp_1_1_completion_callback_with_output__inherit__graph.pngclasspp_1_1_core-members.htmlclasspp_1_1_core.htmlclasspp_1_1_directory_entry-members.htmlclasspp_1_1_directory_entry.htmlclasspp_1_1_file_i_o-members.htmlclasspp_1_1_file_i_o.htmlclasspp_1_1_file_i_o__inherit__graph.pngclasspp_1_1_file_ref-members.htmlclasspp_1_1_file_ref.htmlclasspp_1_1_file_ref__inherit__graph.pngclasspp_1_1_file_system-members.htmlclasspp_1_1_file_system.htmlclasspp_1_1_file_system__inherit__graph.pngclasspp_1_1_float_point-members.htmlclasspp_1_1_float_point.htmlclasspp_1_1_fullscreen-members.htmlclasspp_1_1_fullscreen.htmlclasspp_1_1_graphics2_d-members.htmlclasspp_1_1_graphics2_d.htmlclasspp_1_1_graphics2_d__inherit__graph.pngclasspp_1_1_graphics3_d-members.htmlclasspp_1_1_graphics3_d.htmlclasspp_1_1_graphics3_d__inherit__graph.pngclasspp_1_1_graphics3_d_client-members.htmlclasspp_1_1_graphics3_d_client.htmlclasspp_1_1_host_resolver-members.htmlclasspp_1_1_host_resolver.htmlclasspp_1_1_host_resolver__inherit__graph.pngclasspp_1_1_i_m_e_input_event-members.htmlclasspp_1_1_i_m_e_input_event.htmlclasspp_1_1_i_m_e_input_event__inherit__graph.pngclasspp_1_1_image_data-members.htmlclasspp_1_1_image_data.htmlclasspp_1_1_image_data__inherit__graph.pngclasspp_1_1_input_event-members.htmlclasspp_1_1_input_event.htmlclasspp_1_1_input_event__inherit__graph.pngclasspp_1_1_instance-members.htmlclasspp_1_1_instance.htmlclasspp_1_1_instance_handle-members.htmlclasspp_1_1_instance_handle.htmlclasspp_1_1_keyboard_input_event-members.htmlclasspp_1_1_keyboard_input_event.htmlclasspp_1_1_keyboard_input_event__inherit__graph.pngclasspp_1_1_media_stream_audio_track-members.htmlclasspp_1_1_media_stream_audio_track.htmlclasspp_1_1_media_stream_audio_track__inherit__graph.pngclasspp_1_1_media_stream_video_track-members.htmlclasspp_1_1_media_stream_video_track.htmlclasspp_1_1_media_stream_video_track__inherit__graph.pngclasspp_1_1_message_loop-members.htmlclasspp_1_1_message_loop.htmlclasspp_1_1_message_loop__inherit__graph.pngclasspp_1_1_module-members.htmlclasspp_1_1_module.htmlclasspp_1_1_mouse_cursor-members.htmlclasspp_1_1_mouse_cursor.htmlclasspp_1_1_mouse_input_event-members.htmlclasspp_1_1_mouse_input_event.htmlclasspp_1_1_mouse_input_event__inherit__graph.pngclasspp_1_1_mouse_lock-members.htmlclasspp_1_1_mouse_lock.htmlclasspp_1_1_net_address-members.htmlclasspp_1_1_net_address.htmlclasspp_1_1_net_address__inherit__graph.pngclasspp_1_1_network_list-members.htmlclasspp_1_1_network_list.htmlclasspp_1_1_network_list__inherit__graph.pngclasspp_1_1_network_monitor-members.htmlclasspp_1_1_network_monitor.htmlclasspp_1_1_network_monitor__inherit__graph.pngclasspp_1_1_network_proxy-members.htmlclasspp_1_1_network_proxy.htmlclasspp_1_1_point-members.htmlclasspp_1_1_point.htmlclasspp_1_1_rect-members.htmlclasspp_1_1_rect.htmlclasspp_1_1_resource-members.htmlclasspp_1_1_resource.htmlclasspp_1_1_resource__inherit__graph.pngclasspp_1_1_size-members.htmlclasspp_1_1_size.htmlclasspp_1_1_t_c_p_socket-members.htmlclasspp_1_1_t_c_p_socket.htmlclasspp_1_1_t_c_p_socket__inherit__graph.pngclasspp_1_1_text_input_controller-members.htmlclasspp_1_1_text_input_controller.htmlclasspp_1_1_touch_input_event-members.htmlclasspp_1_1_touch_input_event.htmlclasspp_1_1_touch_input_event__inherit__graph.pngclasspp_1_1_touch_point-members.htmlclasspp_1_1_touch_point.htmlclasspp_1_1_u_d_p_socket-members.htmlclasspp_1_1_u_d_p_socket.htmlclasspp_1_1_u_d_p_socket__inherit__graph.pngclasspp_1_1_u_r_l_loader-members.htmlclasspp_1_1_u_r_l_loader.htmlclasspp_1_1_u_r_l_loader__inherit__graph.pngclasspp_1_1_u_r_l_request_info-members.htmlclasspp_1_1_u_r_l_request_info.htmlclasspp_1_1_u_r_l_request_info__inherit__graph.pngclasspp_1_1_u_r_l_response_info-members.htmlclasspp_1_1_u_r_l_response_info.htmlclasspp_1_1_u_r_l_response_info__inherit__graph.pngclasspp_1_1_var-members.htmlclasspp_1_1_var.htmlclasspp_1_1_var_1_1_out_exception-members.htmlclasspp_1_1_var_1_1_out_exception.htmlclasspp_1_1_var__inherit__graph.pngclasspp_1_1_var_array-members.htmlclasspp_1_1_var_array.htmlclasspp_1_1_var_array__inherit__graph.pngclasspp_1_1_var_array_buffer-members.htmlclasspp_1_1_var_array_buffer.htmlclasspp_1_1_var_array_buffer__inherit__graph.pngclasspp_1_1_var_dictionary-members.htmlclasspp_1_1_var_dictionary.htmlclasspp_1_1_var_dictionary__inherit__graph.pngclasspp_1_1_video_frame-members.htmlclasspp_1_1_video_frame.htmlclasspp_1_1_video_frame__inherit__graph.pngclasspp_1_1_view-members.htmlclasspp_1_1_view.htmlclasspp_1_1_view__inherit__graph.pngclasspp_1_1_web_socket-members.htmlclasspp_1_1_web_socket.htmlclasspp_1_1_web_socket__inherit__graph.pngclasspp_1_1_wheel_input_event-members.htmlclasspp_1_1_wheel_input_event.htmlclasspp_1_1_wheel_input_event__inherit__graph.pngclasspp_1_1ext_1_1_ext_completion_callback_with_output-members.htmlclasspp_1_1ext_1_1_ext_completion_callback_with_output.htmlclasspp_1_1ext_1_1_ext_completion_callback_with_output__inherit__graph.pngclasspp_1_1internal_1_1_completion_callback_with_output_base-members.htmlclasspp_1_1internal_1_1_completion_callback_with_output_base.htmlclasspp_1_1internal_1_1_completion_callback_with_output_base__inherit__graph.pngclasspp_1_1internal_1_1_directory_entry_array_output_adapter_with_storage-members.htmlclasspp_1_1internal_1_1_directory_entry_array_output_adapter_with_storage.htmlcompletion__callback_8h.htmlcompletion__callback_8h__incl.pngcompletion__callback__factory_8h.htmlcompletion__callback__factory_8h__incl.pngcore_8h.htmlcore_8h__incl.pngdirectory__entry_8h.htmldirectory__entry_8h__incl.pngfile__io_8h.htmlfile__io_8h__incl.pngfile__ref_8h.htmlfile__ref_8h__incl.pngfile__system_8h.htmlfile__system_8h__incl.pngfullscreen_8h.htmlfullscreen_8h__incl.pngglobals_defs.htmlgraphics__2d_8h.htmlgraphics__2d_8h__incl.pnggraphics__3d_8h.htmlgraphics__3d_8h__incl.pnggraphics__3d__client_8h.htmlgraphics__3d__client_8h__incl.pnghost__resolver_8h.htmlhost__resolver_8h__incl.pngimage__data_8h.htmlimage__data_8h__incl.pngindex.htmlindex.rstinherit_graph_0.pnginherit_graph_1.pnginherit_graph_10.pnginherit_graph_11.pnginherit_graph_12.pnginherit_graph_13.pnginherit_graph_14.pnginherit_graph_15.pnginherit_graph_16.pnginherit_graph_17.pnginherit_graph_18.pnginherit_graph_19.pnginherit_graph_2.pnginherit_graph_20.pnginherit_graph_21.pnginherit_graph_22.pnginherit_graph_23.pnginherit_graph_24.pnginherit_graph_25.pnginherit_graph_26.pnginherit_graph_27.pnginherit_graph_3.pnginherit_graph_4.pnginherit_graph_5.pnginherit_graph_6.pnginherit_graph_7.pnginherit_graph_8.pnginherit_graph_9.pnginherits.htmlinput__event_8h.htmlinput__event_8h__incl.pnginstance_8h.htmlinstance_8h__incl.pnginstance__handle_8h.htmlinstance__handle_8h__incl.pnglogging_8h.htmllogging_8h__incl.pngmedia__stream__audio__track_8h.htmlmedia__stream__audio__track_8h__incl.pngmedia__stream__video__track_8h.htmlmedia__stream__video__track_8h__incl.pngmessage__loop_8h.htmlmessage__loop_8h__incl.pngmodule_8h.htmlmodule_8h__incl.pngmodule__embedder_8h.htmlmodule__embedder_8h__incl.pngmodule__impl_8h.htmlmodule__impl_8h__incl.pngmouse__cursor_8h.htmlmouse__cursor_8h__incl.pngmouse__lock_8h.htmlmouse__lock_8h__incl.pngnamespacemembers_enum.htmlnamespacemembers_eval.htmlnamespacepp.htmlnamespacepp_1_1ext.htmlnamespacepp_1_1internal.htmlnet__address_8h.htmlnet__address_8h__incl.pngnetwork__list_8h.htmlnetwork__list_8h__incl.pngnetwork__monitor_8h.htmlnetwork__monitor_8h__incl.pngnetwork__proxy_8h.htmlnetwork__proxy_8h__incl.pngpass__ref_8h.htmlpoint_8h.htmlpoint_8h__incl.pngrect_8h.htmlrect_8h__incl.pngresource_8h.htmlresource_8h__incl.pngsize_8h.htmlsize_8h__incl.pngstructpp_1_1_var_1_1_dont_manage.htmlstructpp_1_1_var_1_1_null.htmlstructpp_1_1internal_1_1_callback_output_traits_3_01std_1_1vector_3_01_directory_entry_01_4_01_4-members.htmlstructpp_1_1internal_1_1_callback_output_traits_3_01std_1_1vector_3_01_directory_entry_01_4_01_4.htmlstructpp_1_1internal_1_1_type_unwrapper-members.htmlstructpp_1_1internal_1_1_type_unwrapper.htmlstructpp_1_1internal_1_1_type_unwrapper_3_01_t_01_6_01_4-members.htmlstructpp_1_1internal_1_1_type_unwrapper_3_01_t_01_6_01_4.htmlstructpp_1_1internal_1_1_type_unwrapper_3_01const_01_t_01_6_01_4-members.htmlstructpp_1_1internal_1_1_type_unwrapper_3_01const_01_t_01_6_01_4.htmltcp__socket_8h.htmltcp__socket_8h__incl.pngtext__input__controller_8h.htmltext__input__controller_8h__incl.pngtouch__point_8h.htmltouch__point_8h__incl.pngudp__socket_8h.htmludp__socket_8h__incl.pngurl__loader_8h.htmlurl__loader_8h__incl.pngurl__request__info_8h.htmlurl__request__info_8h__incl.pngurl__response__info_8h.htmlurl__response__info_8h__incl.pngvar_8h.htmlvar_8h__incl.pngvar__array_8h.htmlvar__array_8h__incl.pngvar__array__buffer_8h.htmlvar__array__buffer_8h__incl.pngvar__dictionary_8h.htmlvar__dictionary_8h__incl.pngvideo__frame_8h.htmlvideo__frame_8h__incl.pngview_8h.htmlview_8h__incl.pngwebsocket_8h.htmlwebsocket_8h__incl.png
index.htmlpepper_stable
c
globals_defs.htmlgroup___enums.htmlgroup___functions.htmlgroup___interfaces.htmlgroup___structs.htmlgroup___typedefs.htmlindex.htmlindex.rstpp__array__output_8h.htmlpp__array__output_8h__incl.pngpp__bool_8h.htmlpp__bool_8h__incl.pngpp__completion__callback_8h.htmlpp__completion__callback_8h__incl.pngpp__directory__entry_8h.htmlpp__directory__entry_8h__incl.pngpp__errors_8h.htmlpp__errors_8h__incl.pngpp__file__info_8h.htmlpp__file__info_8h__incl.pngpp__graphics__3d_8h.htmlpp__graphics__3d_8h__incl.pngpp__input__event_8h.htmlpp__input__event_8h__incl.pngpp__instance_8h.htmlpp__instance_8h__incl.pngpp__module_8h.htmlpp__module_8h__incl.pngpp__point_8h.htmlpp__point_8h__incl.pngpp__rect_8h.htmlpp__rect_8h__incl.pngpp__resource_8h.htmlpp__resource_8h__incl.pngpp__size_8h.htmlpp__size_8h__incl.pngpp__stdint_8h.htmlpp__stdint_8h__incl.pngpp__time_8h.htmlpp__time_8h__incl.pngpp__touch__point_8h.htmlpp__touch__point_8h__incl.pngpp__var_8h.htmlpp__var_8h__incl.pngppb_8h.htmlppb_8h__incl.pngppb__audio_8h.htmlppb__audio_8h__incl.pngppb__audio__config_8h.htmlppb__audio__config_8h__incl.pngppb__console_8h.htmlppb__console_8h__incl.pngppb__core_8h.htmlppb__core_8h__incl.pngppb__file__io_8h.htmlppb__file__io_8h__incl.pngppb__file__ref_8h.htmlppb__file__ref_8h__incl.pngppb__file__system_8h.htmlppb__file__system_8h__incl.pngppb__fullscreen_8h.htmlppb__fullscreen_8h__incl.pngppb__gamepad_8h.htmlppb__gamepad_8h__incl.pngppb__graphics__2d_8h.htmlppb__graphics__2d_8h__incl.pngppb__graphics__3d_8h.htmlppb__graphics__3d_8h__incl.pngppb__host__resolver_8h.htmlppb__host__resolver_8h__incl.pngppb__image__data_8h.htmlppb__image__data_8h__incl.pngppb__input__event_8h.htmlppb__input__event_8h__incl.pngppb__instance_8h.htmlppb__instance_8h__incl.pngppb__message__loop_8h.htmlppb__message__loop_8h__incl.pngppb__messaging_8h.htmlppb__messaging_8h__incl.pngppb__mouse__cursor_8h.htmlppb__mouse__cursor_8h__incl.pngppb__mouse__lock_8h.htmlppb__mouse__lock_8h__incl.pngppb__net__address_8h.htmlppb__net__address_8h__incl.pngppb__network__list_8h.htmlppb__network__list_8h__incl.pngppb__network__monitor_8h.htmlppb__network__monitor_8h__incl.pngppb__network__proxy_8h.htmlppb__network__proxy_8h__incl.pngppb__tcp__socket_8h.htmlppb__tcp__socket_8h__incl.pngppb__text__input__controller_8h.htmlppb__text__input__controller_8h__incl.pngppb__udp__socket_8h.htmlppb__udp__socket_8h__incl.pngppb__url__loader_8h.htmlppb__url__loader_8h__incl.pngppb__url__request__info_8h.htmlppb__url__request__info_8h__incl.pngppb__url__response__info_8h.htmlppb__url__response__info_8h__incl.pngppb__var_8h.htmlppb__var_8h__incl.pngppb__var__array_8h.htmlppb__var__array_8h__incl.pngppb__var__array__buffer_8h.htmlppb__var__array__buffer_8h__incl.pngppb__var__dictionary_8h.htmlppb__var__dictionary_8h__incl.pngppb__view_8h.htmlppb__view_8h__incl.pngppb__websocket_8h.htmlppb__websocket_8h__incl.pngppp_8h.htmlppp_8h__incl.pngppp__graphics__3d_8h.htmlppp__graphics__3d_8h__incl.pngppp__input__event_8h.htmlppp__input__event_8h__incl.pngppp__instance_8h.htmlppp__instance_8h__incl.pngppp__messaging_8h.htmlppp__messaging_8h__incl.pngppp__mouse__lock_8h.htmlppp__mouse__lock_8h__incl.pngstruct_p_p___array_output.htmlstruct_p_p___completion_callback.htmlstruct_p_p___directory_entry.htmlstruct_p_p___file_info.htmlstruct_p_p___float_point.htmlstruct_p_p___gamepad_sample_data.htmlstruct_p_p___gamepads_sample_data.htmlstruct_p_p___host_resolver___hint.htmlstruct_p_p___image_data_desc.htmlstruct_p_p___input_event___character.htmlstruct_p_p___input_event___key.htmlstruct_p_p___input_event___mouse.htmlstruct_p_p___input_event___wheel.htmlstruct_p_p___net_address___i_pv4.htmlstruct_p_p___net_address___i_pv6.htmlstruct_p_p___point.htmlstruct_p_p___rect.htmlstruct_p_p___size.htmlstruct_p_p___touch_point.htmlstruct_p_p___var.htmlstruct_p_p_b___audio__1__1.htmlstruct_p_p_b___audio_config__1__1.htmlstruct_p_p_b___console__1__0.htmlstruct_p_p_b___core__1__0.htmlstruct_p_p_b___file_i_o__1__1.htmlstruct_p_p_b___file_ref__1__1.htmlstruct_p_p_b___file_system__1__0.htmlstruct_p_p_b___fullscreen__1__0.htmlstruct_p_p_b___gamepad__1__0.htmlstruct_p_p_b___graphics2_d__1__1.htmlstruct_p_p_b___graphics3_d__1__0.htmlstruct_p_p_b___host_resolver__1__0.htmlstruct_p_p_b___i_m_e_input_event__1__0.htmlstruct_p_p_b___image_data__1__0.htmlstruct_p_p_b___input_event__1__0.htmlstruct_p_p_b___instance__1__0.htmlstruct_p_p_b___keyboard_input_event__1__0.htmlstruct_p_p_b___message_loop__1__0.htmlstruct_p_p_b___messaging__1__0.htmlstruct_p_p_b___mouse_cursor__1__0.htmlstruct_p_p_b___mouse_input_event__1__1.htmlstruct_p_p_b___mouse_lock__1__0.htmlstruct_p_p_b___net_address__1__0.htmlstruct_p_p_b___network_list__1__0.htmlstruct_p_p_b___network_monitor__1__0.htmlstruct_p_p_b___network_proxy__1__0.htmlstruct_p_p_b___t_c_p_socket__1__1.htmlstruct_p_p_b___text_input_controller__1__0.htmlstruct_p_p_b___touch_input_event__1__0.htmlstruct_p_p_b___u_d_p_socket__1__0.htmlstruct_p_p_b___u_r_l_loader__1__0.htmlstruct_p_p_b___u_r_l_request_info__1__0.htmlstruct_p_p_b___u_r_l_response_info__1__0.htmlstruct_p_p_b___var__1__1.htmlstruct_p_p_b___var_array__1__0.htmlstruct_p_p_b___var_array_buffer__1__0.htmlstruct_p_p_b___var_dictionary__1__0.htmlstruct_p_p_b___view__1__1.htmlstruct_p_p_b___web_socket__1__0.htmlstruct_p_p_b___wheel_input_event__1__0.htmlstruct_p_p_p___graphics3_d__1__0.htmlstruct_p_p_p___input_event__0__1.htmlstruct_p_p_p___instance__1__1.htmlstruct_p_p_p___messaging__1__0.htmlstruct_p_p_p___mouse_lock__1__0.htmlunion_p_p___var_value.html
cpp
audio_8h.htmlaudio_8h__incl.pngaudio__config_8h.htmlaudio__config_8h__incl.pngclasspp_1_1_audio-members.htmlclasspp_1_1_audio.htmlclasspp_1_1_audio__inherit__graph.pngclasspp_1_1_audio_config-members.htmlclasspp_1_1_audio_config.htmlclasspp_1_1_audio_config__inherit__graph.pngclasspp_1_1_completion_callback-members.htmlclasspp_1_1_completion_callback.htmlclasspp_1_1_completion_callback__inherit__graph.pngclasspp_1_1_completion_callback_factory-members.htmlclasspp_1_1_completion_callback_factory.htmlclasspp_1_1_completion_callback_with_output-members.htmlclasspp_1_1_completion_callback_with_output.htmlclasspp_1_1_completion_callback_with_output__inherit__graph.pngclasspp_1_1_core-members.htmlclasspp_1_1_core.htmlclasspp_1_1_directory_entry-members.htmlclasspp_1_1_directory_entry.htmlclasspp_1_1_file_i_o-members.htmlclasspp_1_1_file_i_o.htmlclasspp_1_1_file_i_o__inherit__graph.pngclasspp_1_1_file_ref-members.htmlclasspp_1_1_file_ref.htmlclasspp_1_1_file_ref__inherit__graph.pngclasspp_1_1_file_system-members.htmlclasspp_1_1_file_system.htmlclasspp_1_1_file_system__inherit__graph.pngclasspp_1_1_float_point-members.htmlclasspp_1_1_float_point.htmlclasspp_1_1_fullscreen-members.htmlclasspp_1_1_fullscreen.htmlclasspp_1_1_graphics2_d-members.htmlclasspp_1_1_graphics2_d.htmlclasspp_1_1_graphics2_d__inherit__graph.pngclasspp_1_1_graphics3_d-members.htmlclasspp_1_1_graphics3_d.htmlclasspp_1_1_graphics3_d__inherit__graph.pngclasspp_1_1_graphics3_d_client-members.htmlclasspp_1_1_graphics3_d_client.htmlclasspp_1_1_host_resolver-members.htmlclasspp_1_1_host_resolver.htmlclasspp_1_1_host_resolver__inherit__graph.pngclasspp_1_1_i_m_e_input_event-members.htmlclasspp_1_1_i_m_e_input_event.htmlclasspp_1_1_i_m_e_input_event__inherit__graph.pngclasspp_1_1_image_data-members.htmlclasspp_1_1_image_data.htmlclasspp_1_1_image_data__inherit__graph.pngclasspp_1_1_input_event-members.htmlclasspp_1_1_input_event.htmlclasspp_1_1_input_event__inherit__graph.pngclasspp_1_1_instance-members.htmlclasspp_1_1_instance.htmlclasspp_1_1_instance_handle-members.htmlclasspp_1_1_instance_handle.htmlclasspp_1_1_keyboard_input_event-members.htmlclasspp_1_1_keyboard_input_event.htmlclasspp_1_1_keyboard_input_event__inherit__graph.pngclasspp_1_1_message_loop-members.htmlclasspp_1_1_message_loop.htmlclasspp_1_1_message_loop__inherit__graph.pngclasspp_1_1_module-members.htmlclasspp_1_1_module.htmlclasspp_1_1_mouse_cursor-members.htmlclasspp_1_1_mouse_cursor.htmlclasspp_1_1_mouse_input_event-members.htmlclasspp_1_1_mouse_input_event.htmlclasspp_1_1_mouse_input_event__inherit__graph.pngclasspp_1_1_mouse_lock-members.htmlclasspp_1_1_mouse_lock.htmlclasspp_1_1_net_address-members.htmlclasspp_1_1_net_address.htmlclasspp_1_1_net_address__inherit__graph.pngclasspp_1_1_network_list-members.htmlclasspp_1_1_network_list.htmlclasspp_1_1_network_list__inherit__graph.pngclasspp_1_1_network_monitor-members.htmlclasspp_1_1_network_monitor.htmlclasspp_1_1_network_monitor__inherit__graph.pngclasspp_1_1_network_proxy-members.htmlclasspp_1_1_network_proxy.htmlclasspp_1_1_point-members.htmlclasspp_1_1_point.htmlclasspp_1_1_rect-members.htmlclasspp_1_1_rect.htmlclasspp_1_1_resource-members.htmlclasspp_1_1_resource.htmlclasspp_1_1_resource__inherit__graph.pngclasspp_1_1_size-members.htmlclasspp_1_1_size.htmlclasspp_1_1_t_c_p_socket-members.htmlclasspp_1_1_t_c_p_socket.htmlclasspp_1_1_t_c_p_socket__inherit__graph.pngclasspp_1_1_text_input_controller-members.htmlclasspp_1_1_text_input_controller.htmlclasspp_1_1_touch_input_event-members.htmlclasspp_1_1_touch_input_event.htmlclasspp_1_1_touch_input_event__inherit__graph.pngclasspp_1_1_touch_point-members.htmlclasspp_1_1_touch_point.htmlclasspp_1_1_u_d_p_socket-members.htmlclasspp_1_1_u_d_p_socket.htmlclasspp_1_1_u_d_p_socket__inherit__graph.pngclasspp_1_1_u_r_l_loader-members.htmlclasspp_1_1_u_r_l_loader.htmlclasspp_1_1_u_r_l_loader__inherit__graph.pngclasspp_1_1_u_r_l_request_info-members.htmlclasspp_1_1_u_r_l_request_info.htmlclasspp_1_1_u_r_l_request_info__inherit__graph.pngclasspp_1_1_u_r_l_response_info-members.htmlclasspp_1_1_u_r_l_response_info.htmlclasspp_1_1_u_r_l_response_info__inherit__graph.pngclasspp_1_1_var-members.htmlclasspp_1_1_var.htmlclasspp_1_1_var_1_1_out_exception-members.htmlclasspp_1_1_var_1_1_out_exception.htmlclasspp_1_1_var__inherit__graph.pngclasspp_1_1_var_array-members.htmlclasspp_1_1_var_array.htmlclasspp_1_1_var_array__inherit__graph.pngclasspp_1_1_var_array_buffer-members.htmlclasspp_1_1_var_array_buffer.htmlclasspp_1_1_var_array_buffer__inherit__graph.pngclasspp_1_1_var_dictionary-members.htmlclasspp_1_1_var_dictionary.htmlclasspp_1_1_var_dictionary__inherit__graph.pngclasspp_1_1_view-members.htmlclasspp_1_1_view.htmlclasspp_1_1_view__inherit__graph.pngclasspp_1_1_web_socket-members.htmlclasspp_1_1_web_socket.htmlclasspp_1_1_web_socket__inherit__graph.pngclasspp_1_1_wheel_input_event-members.htmlclasspp_1_1_wheel_input_event.htmlclasspp_1_1_wheel_input_event__inherit__graph.pngclasspp_1_1ext_1_1_ext_completion_callback_with_output-members.htmlclasspp_1_1ext_1_1_ext_completion_callback_with_output.htmlclasspp_1_1ext_1_1_ext_completion_callback_with_output__inherit__graph.pngclasspp_1_1internal_1_1_completion_callback_with_output_base-members.htmlclasspp_1_1internal_1_1_completion_callback_with_output_base.htmlclasspp_1_1internal_1_1_completion_callback_with_output_base__inherit__graph.pngclasspp_1_1internal_1_1_directory_entry_array_output_adapter_with_storage-members.htmlclasspp_1_1internal_1_1_directory_entry_array_output_adapter_with_storage.htmlcompletion__callback_8h.htmlcompletion__callback_8h__incl.pngcompletion__callback__factory_8h.htmlcompletion__callback__factory_8h__incl.pngcore_8h.htmlcore_8h__incl.pngdirectory__entry_8h.htmldirectory__entry_8h__incl.pngfile__io_8h.htmlfile__io_8h__incl.pngfile__ref_8h.htmlfile__ref_8h__incl.pngfile__system_8h.htmlfile__system_8h__incl.pngfullscreen_8h.htmlfullscreen_8h__incl.pngglobals_defs.htmlgraphics__2d_8h.htmlgraphics__2d_8h__incl.pnggraphics__3d_8h.htmlgraphics__3d_8h__incl.pnggraphics__3d__client_8h.htmlgraphics__3d__client_8h__incl.pnghost__resolver_8h.htmlhost__resolver_8h__incl.pngimage__data_8h.htmlimage__data_8h__incl.pngindex.htmlindex.rstinherit_graph_0.pnginherit_graph_1.pnginherit_graph_10.pnginherit_graph_11.pnginherit_graph_12.pnginherit_graph_13.pnginherit_graph_14.pnginherit_graph_15.pnginherit_graph_16.pnginherit_graph_17.pnginherit_graph_18.pnginherit_graph_19.pnginherit_graph_2.pnginherit_graph_20.pnginherit_graph_21.pnginherit_graph_22.pnginherit_graph_23.pnginherit_graph_24.pnginherit_graph_25.pnginherit_graph_26.pnginherit_graph_27.pnginherit_graph_3.pnginherit_graph_4.pnginherit_graph_5.pnginherit_graph_6.pnginherit_graph_7.pnginherit_graph_8.pnginherit_graph_9.pnginherits.htmlinput__event_8h.htmlinput__event_8h__incl.pnginstance_8h.htmlinstance_8h__incl.pnginstance__handle_8h.htmlinstance__handle_8h__incl.pnglogging_8h.htmllogging_8h__incl.pngmessage__loop_8h.htmlmessage__loop_8h__incl.pngmodule_8h.htmlmodule_8h__incl.pngmodule__embedder_8h.htmlmodule__embedder_8h__incl.pngmodule__impl_8h.htmlmodule__impl_8h__incl.pngmouse__cursor_8h.htmlmouse__cursor_8h__incl.pngmouse__lock_8h.htmlmouse__lock_8h__incl.pngnamespacemembers_enum.htmlnamespacemembers_eval.htmlnamespacepp.htmlnamespacepp_1_1ext.htmlnamespacepp_1_1internal.htmlnet__address_8h.htmlnet__address_8h__incl.pngnetwork__list_8h.htmlnetwork__list_8h__incl.pngnetwork__monitor_8h.htmlnetwork__monitor_8h__incl.pngnetwork__proxy_8h.htmlnetwork__proxy_8h__incl.pngpass__ref_8h.htmlpoint_8h.htmlpoint_8h__incl.pngrect_8h.htmlrect_8h__incl.pngresource_8h.htmlresource_8h__incl.pngsize_8h.htmlsize_8h__incl.pngstructpp_1_1_var_1_1_dont_manage.htmlstructpp_1_1_var_1_1_null.htmlstructpp_1_1internal_1_1_callback_output_traits_3_01std_1_1vector_3_01_directory_entry_01_4_01_4-members.htmlstructpp_1_1internal_1_1_callback_output_traits_3_01std_1_1vector_3_01_directory_entry_01_4_01_4.htmlstructpp_1_1internal_1_1_type_unwrapper-members.htmlstructpp_1_1internal_1_1_type_unwrapper.htmlstructpp_1_1internal_1_1_type_unwrapper_3_01_t_01_6_01_4-members.htmlstructpp_1_1internal_1_1_type_unwrapper_3_01_t_01_6_01_4.htmlstructpp_1_1internal_1_1_type_unwrapper_3_01const_01_t_01_6_01_4-members.htmlstructpp_1_1internal_1_1_type_unwrapper_3_01const_01_t_01_6_01_4.htmltcp__socket_8h.htmltcp__socket_8h__incl.pngtext__input__controller_8h.htmltext__input__controller_8h__incl.pngtouch__point_8h.htmltouch__point_8h__incl.pngudp__socket_8h.htmludp__socket_8h__incl.pngurl__loader_8h.htmlurl__loader_8h__incl.pngurl__request__info_8h.htmlurl__request__info_8h__incl.pngurl__response__info_8h.htmlurl__response__info_8h__incl.pngvar_8h.htmlvar_8h__incl.pngvar__array_8h.htmlvar__array_8h__incl.pngvar__array__buffer_8h.htmlvar__array__buffer_8h__incl.pngvar__dictionary_8h.htmlvar__dictionary_8h__incl.pngview_8h.htmlview_8h__incl.pngwebsocket_8h.htmlwebsocket_8h__incl.png
index.htmlreference
rest-devsite-examples.htmlsdk
sitemap.htmlversion.htmlsrc
doc
442
native_client_sdk/doc_generated/devguide/coding/3D-graphics.html
Normal file
442
native_client_sdk/doc_generated/devguide/coding/3D-graphics.html
Normal file
@@ -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}}
|
@@ -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}}
|
352
native_client_sdk/doc_generated/devguide/coding/audio.html
Normal file
352
native_client_sdk/doc_generated/devguide/coding/audio.html
Normal file
@@ -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}}
|
498
native_client_sdk/doc_generated/devguide/coding/file-io.html
Normal file
498
native_client_sdk/doc_generated/devguide/coding/file-io.html
Normal file
@@ -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}}
|
10
native_client_sdk/doc_generated/devguide/coding/index.html
Normal file
10
native_client_sdk/doc_generated/devguide/coding/index.html
Normal file
@@ -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}}
|
@@ -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}}
|
225
native_client_sdk/doc_generated/devguide/coding/nacl_io.html
Normal file
225
native_client_sdk/doc_generated/devguide/coding/nacl_io.html
Normal file
@@ -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}}
|
@@ -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}}
|
@@ -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}}
|
232
native_client_sdk/doc_generated/devguide/coding/url-loading.html
Normal file
232
native_client_sdk/doc_generated/devguide/coding/url-loading.html
Normal file
@@ -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}}
|
@@ -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}}
|
Reference in New Issue
Block a user