summaryrefslogtreecommitdiffstats
path: root/o3d/plugin
diff options
context:
space:
mode:
Diffstat (limited to 'o3d/plugin')
-rw-r--r--o3d/plugin/build.scons409
-rw-r--r--o3d/plugin/cross/archive_request_glue.cc214
-rw-r--r--o3d/plugin/cross/archive_request_glue.h66
-rw-r--r--o3d/plugin/cross/async_loading.cc223
-rw-r--r--o3d/plugin/cross/async_loading.h67
-rw-r--r--o3d/plugin/cross/blacklist.cc70
-rw-r--r--o3d/plugin/cross/config.h115
-rw-r--r--o3d/plugin/cross/config_common.cc215
-rw-r--r--o3d/plugin/cross/download_stream.h66
-rw-r--r--o3d/plugin/cross/main.cc160
-rw-r--r--o3d/plugin/cross/main.h143
-rw-r--r--o3d/plugin/cross/marshaling_utils.h129
-rw-r--r--o3d/plugin/cross/np_v8_bridge.cc1511
-rw-r--r--o3d/plugin/cross/np_v8_bridge.h400
-rw-r--r--o3d/plugin/cross/o3d_glue.cc856
-rw-r--r--o3d/plugin/cross/o3d_glue.h430
-rw-r--r--o3d/plugin/cross/out_of_memory.cc231
-rw-r--r--o3d/plugin/cross/out_of_memory.h44
-rw-r--r--o3d/plugin/cross/plugin_logging.h153
-rw-r--r--o3d/plugin/cross/plugin_logging_test.cc228
-rw-r--r--o3d/plugin/cross/plugin_main.h38
-rw-r--r--o3d/plugin/cross/plugin_metrics.h152
-rw-r--r--o3d/plugin/cross/stream_manager.cc356
-rw-r--r--o3d/plugin/cross/stream_manager.h169
-rw-r--r--o3d/plugin/idl/archive_request.idl170
-rw-r--r--o3d/plugin/idl/bounding_box.idl210
-rw-r--r--o3d/plugin/idl/buffer.idl482
-rw-r--r--o3d/plugin/idl/canvas.idl181
-rw-r--r--o3d/plugin/idl/canvas_paint.idl186
-rw-r--r--o3d/plugin/idl/canvas_shader.idl94
-rw-r--r--o3d/plugin/idl/clear_buffer.idl76
-rw-r--r--o3d/plugin/idl/client.idl543
-rw-r--r--o3d/plugin/idl/counter.idl238
-rw-r--r--o3d/plugin/idl/cursor.idl82
-rw-r--r--o3d/plugin/idl/curve.idl326
-rw-r--r--o3d/plugin/idl/display_mode.idl64
-rw-r--r--o3d/plugin/idl/draw_context.idl57
-rw-r--r--o3d/plugin/idl/draw_element.idl74
-rw-r--r--o3d/plugin/idl/draw_list.idl58
-rw-r--r--o3d/plugin/idl/draw_pass.idl50
-rw-r--r--o3d/plugin/idl/effect.idl230
-rw-r--r--o3d/plugin/idl/element.idl172
-rw-r--r--o3d/plugin/idl/event.idl186
-rw-r--r--o3d/plugin/idl/field.idl242
-rw-r--r--o3d/plugin/idl/file_request.idl124
-rw-r--r--o3d/plugin/idl/function.idl87
-rw-r--r--o3d/plugin/idl/material.idl59
-rw-r--r--o3d/plugin/idl/matrix4_axis_rotation.idl63
-rw-r--r--o3d/plugin/idl/matrix4_composition.idl59
-rw-r--r--o3d/plugin/idl/matrix4_scale.idl57
-rw-r--r--o3d/plugin/idl/matrix4_translation.idl57
-rw-r--r--o3d/plugin/idl/named.idl118
-rw-r--r--o3d/plugin/idl/pack.idl308
-rw-r--r--o3d/plugin/idl/param.idl326
-rw-r--r--o3d/plugin/idl/param_array.idl149
-rw-r--r--o3d/plugin/idl/param_object.idl161
-rw-r--r--o3d/plugin/idl/param_operation.idl265
-rw-r--r--o3d/plugin/idl/plugin.idl59
-rw-r--r--o3d/plugin/idl/primitive.idl93
-rw-r--r--o3d/plugin/idl/raw_data.idl88
-rw-r--r--o3d/plugin/idl/ray_intersection_info.idl64
-rw-r--r--o3d/plugin/idl/render_event.idl106
-rw-r--r--o3d/plugin/idl/render_node.idl135
-rw-r--r--o3d/plugin/idl/render_surface.idl76
-rw-r--r--o3d/plugin/idl/render_surface_set.idl63
-rw-r--r--o3d/plugin/idl/sampler.idl132
-rw-r--r--o3d/plugin/idl/shape.idl89
-rw-r--r--o3d/plugin/idl/skin.idl274
-rw-r--r--o3d/plugin/idl/standard_param.idl200
-rw-r--r--o3d/plugin/idl/state.idl277
-rw-r--r--o3d/plugin/idl/state_set.idl49
-rw-r--r--o3d/plugin/idl/stream.idl118
-rw-r--r--o3d/plugin/idl/stream_bank.idl148
-rw-r--r--o3d/plugin/idl/texture.idl312
-rw-r--r--o3d/plugin/idl/tick_event.idl49
-rw-r--r--o3d/plugin/idl/transform.idl372
-rw-r--r--o3d/plugin/idl/tree_traversal.idl71
-rw-r--r--o3d/plugin/idl/types.idl130
-rw-r--r--o3d/plugin/idl/vector.idl181
-rw-r--r--o3d/plugin/idl/vertex_source.idl70
-rw-r--r--o3d/plugin/idl/viewport.idl68
-rw-r--r--o3d/plugin/idl_list.scons91
-rw-r--r--o3d/plugin/linux/config.cc62
-rw-r--r--o3d/plugin/linux/main_linux.cc522
-rw-r--r--o3d/plugin/mac/Info.plist58
-rw-r--r--o3d/plugin/mac/Resources/English.lproj/InfoPlist.strings10
-rw-r--r--o3d/plugin/mac/Tools/fix_install_names.sh17
-rw-r--r--o3d/plugin/mac/config_mac.mm330
-rw-r--r--o3d/plugin/mac/main_mac.mm1114
-rw-r--r--o3d/plugin/mac/o3d_mac_npapi_metapackage/open_source_o3d_mac_npapi_metapackage.packproj776
-rw-r--r--o3d/plugin/mac/o3d_plugin.r15
-rw-r--r--o3d/plugin/mac/plugin_logging-mac.mm236
-rw-r--r--o3d/plugin/mac/plugin_mac.h106
-rw-r--r--o3d/plugin/mac/plugin_mac.mm822
-rw-r--r--o3d/plugin/mac/plugin_metrics-mac.cc85
-rw-r--r--o3d/plugin/npapi_host_control/build.scons100
-rw-r--r--o3d/plugin/npapi_host_control/win/dispatch_proxy.cc321
-rw-r--r--o3d/plugin/npapi_host_control/win/dispatch_proxy.h197
-rw-r--r--o3d/plugin/npapi_host_control/win/host_control.cc590
-rw-r--r--o3d/plugin/npapi_host_control/win/host_control.h268
-rw-r--r--o3d/plugin/npapi_host_control/win/host_control.rgs42
-rw-r--r--o3d/plugin/npapi_host_control/win/module.h68
-rw-r--r--o3d/plugin/npapi_host_control/win/np_browser_proxy.cc812
-rw-r--r--o3d/plugin/npapi_host_control/win/np_browser_proxy.h278
-rw-r--r--o3d/plugin/npapi_host_control/win/np_object_proxy.cc518
-rw-r--r--o3d/plugin/npapi_host_control/win/np_object_proxy.h130
-rw-r--r--o3d/plugin/npapi_host_control/win/np_object_proxy.rgs37
-rw-r--r--o3d/plugin/npapi_host_control/win/np_plugin_proxy.cc437
-rw-r--r--o3d/plugin/npapi_host_control/win/np_plugin_proxy.h153
-rw-r--r--o3d/plugin/npapi_host_control/win/npapi_host_control.cc73
-rw-r--r--o3d/plugin/npapi_host_control/win/npapi_host_control.def9
-rw-r--r--o3d/plugin/npapi_host_control/win/npapi_host_control.idl100
-rw-r--r--o3d/plugin/npapi_host_control/win/npapi_host_control.rc122
-rw-r--r--o3d/plugin/npapi_host_control/win/npapi_host_control.rgs17
-rw-r--r--o3d/plugin/npapi_host_control/win/precompile.cc33
-rw-r--r--o3d/plugin/npapi_host_control/win/precompile.h83
-rw-r--r--o3d/plugin/npapi_host_control/win/resource.h55
-rw-r--r--o3d/plugin/npapi_host_control/win/stream_operation.cc756
-rw-r--r--o3d/plugin/npapi_host_control/win/stream_operation.h271
-rw-r--r--o3d/plugin/npapi_host_control/win/variant_utils.cc207
-rw-r--r--o3d/plugin/npapi_host_control/win/variant_utils.h65
-rw-r--r--o3d/plugin/o3d_binding.py522
-rw-r--r--o3d/plugin/o3d_iface_generator.py618
-rw-r--r--o3d/plugin/win/config.cc233
-rw-r--r--o3d/plugin/win/logger_main.cc58
-rw-r--r--o3d/plugin/win/main_win.cc959
-rw-r--r--o3d/plugin/win/o3dPlugin.def6
-rw-r--r--o3d/plugin/win/o3dPlugin.rc_template106
-rw-r--r--o3d/plugin/win/o3dPlugin.sln92
-rw-r--r--o3d/plugin/win/plugin_logging-win32.cc306
-rw-r--r--o3d/plugin/win/plugin_metrics-win32.cc103
-rw-r--r--o3d/plugin/win/resource.h46
-rw-r--r--o3d/plugin/win/update_lock.cc39
-rw-r--r--o3d/plugin/win/update_lock.h100
134 files changed, 28397 insertions, 0 deletions
diff --git a/o3d/plugin/build.scons b/o3d/plugin/build.scons
new file mode 100644
index 0000000..3ff6a97
--- /dev/null
+++ b/o3d/plugin/build.scons
@@ -0,0 +1,409 @@
+# Copyright 2009, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+import os.path
+import sys
+Import('env')
+env.SConscript('$SCONSTRUCT_DIR/plugin/idl_list.scons')
+Import('O3D_IDL_SOURCES')
+
+env.Tool('replace_strings')
+env.Append(O3D_PLUGIN_DESCRIPTION=
+ '$O3D_PLUGIN_NAME version:$O3D_PLUGIN_VERSION',
+ O3D_PLUGIN_MIME_TYPE='application/vnd.o3d.auto')
+
+plugin_replace_strings = [
+ ('@@@PluginName@@@', env.subst('$O3D_PLUGIN_NAME')),
+ ('@@@ProductVersionCommas@@@',
+ env.subst('$O3D_PLUGIN_VERSION_COMMAS')),
+ ('@@@ProductVersion@@@', env.subst('$O3D_PLUGIN_VERSION')),
+ ('@@@PluginDescription@@@', env.subst('$O3D_PLUGIN_DESCRIPTION')),
+ ('@@@PluginMimeType@@@', env.subst('$O3D_PLUGIN_MIME_TYPE')),
+]
+
+# TODO: collapse these if possible.
+env.Append(GLUE_DIR = env.Dir('glue'),
+ NIXYSA_STATIC_GLUE = '$NIXYSA_DIR/static_glue/npapi')
+
+if env.Bit('windows'):
+ testing_inputs = [
+ 'win/plugin_metrics-win32.cc',
+ 'win/plugin_logging-win32.cc',
+ ]
+elif env.Bit('mac'):
+ testing_inputs = [
+ 'mac/plugin_metrics-mac.cc',
+ 'mac/plugin_logging-mac.mm',
+ ]
+
+# Add Skia include paths
+env.Append(CPPPATH=['$SKIA_DIR/include/core',
+ '$SKIA_DIR/include/effects'])
+
+# Build a library for testing.
+# Currently windows and mac.
+if env.Bit('windows') or env.Bit('mac'):
+ logging_lib = env.ComponentLibrary('o3dPlugin_logging', testing_inputs)
+
+# vista SDK provides an incompatible version of npapi.h, so make sure we
+# prepend our blessed version.
+env.Prepend(CPPPATH = ['$NPAPI_DIR/include'])
+env.Append(
+ CPPPATH = [
+ 'cross',
+ '$GLUE_DIR',
+ '$NIXYSA_STATIC_GLUE',
+ '$SCONSTRUCT_DIR/plugin/win', # for RES resource.h
+ '$WTL_71_DIR/include',
+ ],
+ LIBPATH = [
+ '$NACL_LIB_DIR',
+ ],
+ LIBS = [
+# 'o3dBreakpad',
+ 'o3dArchive',
+ 'o3dCore',
+ 'o3dArchive',
+ 'o3dCorePlatform',
+ 'o3dUtils',
+ 'google_nacl_imc',
+ 'o3d_base',
+ 'v8',
+ 'skia',
+ ],
+)
+
+
+if env.Bit('windows'):
+ env.Append(
+ LIBS = [
+ 'advapi32',
+ 'o3dBreakpad',
+ 'o3dStatsreport_Common',
+ 'o3dStatsreport',
+ 'shell32',
+ 'shlwapi',
+ ],
+ CPPDEFINES = ['XP_WIN']
+ )
+
+
+
+if env.Bit('mac'):
+ if env['DEBUG']:
+ env['MAC_BREAKPAD_CONFIG'] = 'Debug'
+ else:
+ env['MAC_BREAKPAD_CONFIG'] = 'Release'
+ env.Append(
+ MAC_BREAKPAD_SRC_DIR = '$BREAKPAD_DIR/client/mac',
+ # TODO: is there a way to tell xcodebuild to output the build in
+ # scons-out instead of the source tree ?
+ MAC_BREAKPAD_DIR = '$MAC_BREAKPAD_SRC_DIR/build/$MAC_BREAKPAD_CONFIG',
+ LIBS = [
+ 'o3dStatsreport_Common',
+ 'o3dStatsreport',
+ logging_lib,
+ ],
+ FRAMEWORKS = [
+ 'Carbon',
+ 'OpenGL',
+ 'Cg',
+ 'AGL',
+ 'Foundation',
+ 'Breakpad',
+ 'Cocoa',
+ 'IOKit',
+ ],
+ CCFLAGS = ['-F$MAC_BREAKPAD_DIR',
+ '-F$CG_DIR'],
+ CPPPATH = ['mac'],
+ CPPDEFINES = ['XP_MACOSX']
+ )
+
+if env.Bit('linux'):
+ env.Append(CPPDEFINES = ['XP_UNIX', 'MOZ_X11']);
+
+# Add libraries based on the requested renderer
+env.Append(CPPPATH = env['RENDERER_INCLUDE_PATH'],
+ LIBPATH = env['RENDERER_LIB_PATH'],
+ LIBS = env['RENDERER_LIBS'] + env['ICU_LIBS'])
+
+
+def NixysaEmitter(target, source, env):
+ bases = [os.path.splitext(s.name)[0] for s in source] + ['globals']
+ targets = ['glue/%s_glue.cc' % b for b in bases]
+ targets += ['glue/%s_glue.h' % b for b in bases]
+ return targets, source
+
+AUTOGEN_ARGS = ['$NIXYSA_DIR/codegen.py',
+ '--binding-module=o3d:plugin/o3d_binding.py',
+ '--generate=npapi',
+ '--output-dir=$GLUE_DIR',
+ '$SOURCES']
+
+env['PYTHONPATH'] = ['$NIXYSA_DIR',
+ '$GFLAGS_DIR/python',
+ '$PLY_DIR']
+env['BUILDERS']['Nixysa'] = Builder(action=env.Python(AUTOGEN_ARGS),
+ emitter=NixysaEmitter)
+AUTOGEN_OUTPUT = env.Nixysa(O3D_IDL_SOURCES)
+env.SideEffect('glue/hash', AUTOGEN_OUTPUT)
+AUTOGEN_CC_FILES = [f for f in AUTOGEN_OUTPUT if f.suffix == '.cc']
+
+inputs = AUTOGEN_CC_FILES + [
+ 'cross/async_loading.cc',
+ 'cross/archive_request_glue.cc',
+ 'cross/blacklist.cc',
+ 'cross/o3d_glue.cc',
+ 'cross/np_v8_bridge.cc',
+ 'cross/out_of_memory.cc',
+ 'cross/stream_manager.cc',
+ 'cross/config_common.cc',
+]
+
+env_version = env.Clone()
+env_version.Append(
+ CPPDEFINES = [
+ ('O3D_PLUGIN_NAME', '\\"$O3D_PLUGIN_NAME\\"'),
+ ('O3D_PLUGIN_DESCRIPTION', '\\"$O3D_PLUGIN_DESCRIPTION\\"'),
+ ('O3D_PLUGIN_MIME_TYPE', '\\"$O3D_PLUGIN_MIME_TYPE\\"')
+ ])
+
+idlglue_static_sources = [
+ 'common',
+ 'static_object',
+ 'npn_api',
+]
+env_idlglue = env.Clone()
+
+# TODO: figure out resources on the mac.
+if env.Bit('windows'):
+ env.ReplaceStrings(
+ 'win/o3dPlugin.rc', 'win/o3dPlugin.rc_template',
+ REPLACE_STRINGS = plugin_replace_strings
+ )
+ if env['DEBUG']:
+ # release v8 brings libcmt that conflicts with libcmtd
+ env.Append(LINKFLAGS=['/NODEFAULTLIB:LIBCMT'])
+ env_idlglue.Append(CPPDEFINES=['OS_WINDOWS'])
+ inputs += [env_idlglue.ComponentObject(s, '$NIXYSA_STATIC_GLUE/%s.cc' % s)
+ for s in idlglue_static_sources]
+ inputs += env_version.ComponentObject('cross/main', 'cross/main.cc')
+ inputs += [
+ logging_lib,
+ 'win/main_win.cc',
+ 'win/config.cc',
+ 'win/o3dPlugin.def',
+ 'win/update_lock.cc',
+ env.RES('win/o3dPlugin.rc'),
+ ]
+
+
+if env.Bit('linux'):
+ env_idlglue.Append(CPPDEFINES=['OS_LINUX'])
+ inputs += [env_idlglue.SharedObject(s, '$NIXYSA_STATIC_GLUE/%s.cc' % s)
+ for s in idlglue_static_sources]
+ inputs += env_version.SharedObject('cross/main', 'cross/main.cc')
+ inputs += [
+ 'linux/main_linux.cc',
+ 'linux/config.cc',
+ ]
+
+
+# SCons doesn't really know about MacOSX bundles, so we need to override a
+# lot of its behavior to make one, ie -bundle flag, no lib prefix, no .dylib suffix.
+if env.Bit('mac'):
+ breakpad_framework = env.Command(
+ env.Dir('$MAC_BREAKPAD_DIR/Breakpad.framework'),
+ env.Dir('$MAC_BREAKPAD_SRC_DIR/Breakpad.xcodeproj'),
+ ' '.join(['cd $MAC_BREAKPAD_SRC_DIR &&',
+ 'xcodebuild',
+ '-project Breakpad.xcodeproj',
+ '-target Breakpad',
+ '-configuration $MAC_BREAKPAD_CONFIG']))
+ plugin_mac_object = env.SharedObject('mac/plugin_mac', 'mac/plugin_mac.mm')
+ env.Requires(plugin_mac_object, breakpad_framework)
+
+ env_idlglue.Append(CPPDEFINES=['OS_MACOSX'])
+ inputs += [env_idlglue.SharedObject(s, '$NIXYSA_STATIC_GLUE/%s.cc' % s)
+ for s in idlglue_static_sources]
+ inputs += env_version.SharedObject('cross/main', 'cross/main.cc')
+ inputs += [
+ 'mac/main_mac.mm',
+ 'mac/config_mac.mm',
+ plugin_mac_object
+ ]
+
+ env['SHLINKFLAGS'] = ['-bundle',
+ '-F$MAC_BREAKPAD_DIR',
+ '-F$CG_DIR',
+ ]
+ env['SHLIBPREFIX'] = ['']
+ env['SHLIBSUFFIX'] = ['']
+ plugin_dll = env.SharedLibrary('o3d', inputs)
+ plugin_install = env.Replicate('$ARTIFACTS_DIR/O3D.plugin/Contents/MacOS/', plugin_dll)
+
+ # insert version number into Info.plist
+ env.ReplaceStrings(
+ 'mac/processed/Info.plist', '$SCONSTRUCT_DIR/plugin/mac/Info.plist',
+ REPLACE_STRINGS = plugin_replace_strings
+ )
+
+ # copy mac resource data
+ env.Replicate('$ARTIFACTS_DIR/O3D.plugin/Contents/',
+ '$SCONSTRUCT_DIR/plugin/mac/Resources')
+ env.Replicate('$ARTIFACTS_DIR/O3D.plugin/Contents',
+ 'mac/processed/Info.plist')
+
+ # Make a string substituted version of o3d_plugin.r in the artifacts
+ # directory.
+ env.ReplaceStrings(
+ '$ARTIFACTS_DIR/o3d_plugin.r', 'mac/o3d_plugin.r',
+ REPLACE_STRINGS = plugin_replace_strings
+ )
+ # Compile the string substituted o3d_plugin.r to make o3d.rsrc
+ env.Command('$ARTIFACTS_DIR/O3D.plugin/Contents/Resources/o3d.rsrc',
+ ['$ARTIFACTS_DIR/o3d_plugin.r'],
+ [
+ 'Rez -useDF "$ARTIFACTS_DIR/o3d_plugin.r" -o "$ARTIFACTS_DIR/O3D.plugin/Contents/Resources/o3d.rsrc"'
+ ])
+
+ if env['DEBUG']:
+ stripCmd = 'echo debug build, no strip'
+ else:
+ stripCmd = 'strip -S "$ARTIFACTS_DIR/O3D.plugin/Contents/MacOS/o3d"'
+
+ # Cleanup end result and build the installer
+ created_installer = env.Command('$ARTIFACTS_DIR/plugin_done',
+ [env.Dir('$ARTIFACTS_DIR/O3D.plugin')],
+ [
+ 'xcodebuild -project installer/mac/O3D_Stats/O3D_Stats.xcodeproj -configuration Release',
+ 'ditto "$SCONSTRUCT_DIR/installer/mac/O3D_Stats/build/Release/O3D_Stats.bundle" "$ARTIFACTS_DIR/O3D_Stats.bundle"',
+ # Because the frameworks are inside a plugin bundle (not application bundle) the plugin executable needs to be
+ # tweaked to reference their paths via @loader_path instead of @executable_path.
+ '$SCONSTRUCT_DIR/plugin/mac/Tools/fix_install_names.sh $ARTIFACTS_DIR/O3D.plugin/Contents/MacOS/o3d',
+
+ # make a copy of the executable, before we strip all the symbols
+ 'rm -f "$ARTIFACTS_DIR/o3d"',
+ 'cp -f "$ARTIFACTS_DIR/O3D.plugin/Contents/MacOS/o3d" "$ARTIFACTS_DIR/o3d"',
+ stripCmd,
+ # Delete frameworks so we start fresh, and ditto can't get confused
+ Delete("$ARTIFACTS_DIR/O3D.plugin/Contents/Frameworks/"),
+ # Use ditto, not Replicate() as Replicate mangles the symlinks.
+ # The use of ditto also lets us strip the frameworks down to just i386, which saves a lot of space.
+ 'ditto --arch i386 "$MAC_BREAKPAD_DIR/Breakpad.framework" "$ARTIFACTS_DIR/O3D.plugin/Contents/Frameworks/Breakpad.framework"',
+ '/usr/bin/install_name_tool -change '
+ '@executable_path/../Frameworks/Breakpad.framework/Resources/breakpadUtilities.dylib '
+ '@loader_path/Resources/breakpadUtilities.dylib '
+ '"$ARTIFACTS_DIR/O3D.plugin/Contents/Frameworks/Breakpad.framework/Breakpad"',
+ 'ditto --arch i386 "$CG_DIR/Cg.framework" "$ARTIFACTS_DIR/O3D.plugin/Contents/Frameworks/Cg.framework"',
+ # Delete private frameworks headers.
+ 'find "$ARTIFACTS_DIR/O3D.plugin/Contents/Frameworks" -iname "*.h" -delete',
+ 'find "$ARTIFACTS_DIR/O3D.plugin/Contents/Frameworks" -iname "Headers" -type l -delete',
+ 'find "$ARTIFACTS_DIR/O3D.plugin/Contents/Frameworks" -iname "Headers" -type d -prune -delete',
+ Touch('$ARTIFACTS_DIR/plugin_done')
+ ])
+
+
+ env['MAC_INSTALLER_PROJECT'] = 'open_source_o3d_mac_npapi_metapackage.packproj'
+ make_installer = int(ARGUMENTS.get('MAKE_INSTALLER', 0))
+
+
+
+ if make_installer:
+ if int(ARGUMENTS.get('MAC_KILLSWITCH', 0)):
+ kill_command = 'rm "$ARTIFACTS_DIR/O3D.plugin/Contents/MacOS/o3d"'
+ else:
+ kill_command = 'echo normal binary'
+ # Cleanup end result and build the installer
+ env.Command(env.Dir('$ARTIFACTS_DIR/O3D.mpkg'),
+ [
+ "$ARTIFACTS_DIR/plugin_done",
+ ],
+ [
+ # Delete first as Copy can fail to overwrite if the packproj is locked
+ Delete("$ARTIFACTS_DIR/$MAC_INSTALLER_PROJECT"),
+ # Copy installer project file into artifacts so it can operate on files local to own directory
+ # and so work on debug or release builds without change.
+ Copy("$ARTIFACTS_DIR/$MAC_INSTALLER_PROJECT",
+ '$SCONSTRUCT_DIR/plugin/mac/o3d_mac_npapi_metapackage/$MAC_INSTALLER_PROJECT'),
+ # Make the installer.
+ kill_command,
+ 'freeze "$ARTIFACTS_DIR/$MAC_INSTALLER_PROJECT"',
+ # Delete temp files in artifacts now we are done.
+ Delete("$ARTIFACTS_DIR/$MAC_INSTALLER_PROJECT")
+ ])
+
+ env.Command('$ARTIFACTS_DIR/o3d.dmg',
+ [
+ env.Dir('$ARTIFACTS_DIR/O3D.mpkg'),
+ ],
+ [
+ Delete("$ARTIFACTS_DIR/DMG_SRC"),
+ 'mkdir "$ARTIFACTS_DIR/DMG_SRC"',
+ 'ditto "$ARTIFACTS_DIR/O3D.mpkg" "$ARTIFACTS_DIR/DMG_SRC/O3D.mpkg"',
+ 'hdiutil create -srcfolder "$ARTIFACTS_DIR/DMG_SRC" -size 30mb -ov -fs HFS+ -imagekey zlib-level=9 -volname "O3D $O3D_PLUGIN_VERSION" "$ARTIFACTS_DIR/o3d.dmg"',
+ Delete("$ARTIFACTS_DIR/DMG_SRC"),
+ ])
+
+
+# else build the shared library in a platform independent way
+else:
+ plugin_dll = env.SharedLibrary('npo3dautoplugin', inputs)
+# copy to artifacts
+ plugin_install = env.Replicate('$ARTIFACTS_DIR', plugin_dll)
+
+if env.Bit('linux'):
+ env.Requires(plugin_install, env.Replicate(
+ '$ARTIFACTS_DIR', [
+ '$CG_DIR/lib/libCg.so',
+ '$CG_DIR/lib/libCgGL.so',
+ '$GLEW_DIR/lib/libGLEW.so.1.5',
+ ]
+ ))
+
+
+# alias 'plugin' to build the plug-in in artifacts
+env.Alias('plugin', plugin_install)
+
+# TODO: have a common way to do colliding installs like this.
+# Do the install step only if this variant is the first target.
+if (env['BUILD_TYPE'] == ARGUMENTS.get('MODE') or
+ (ARGUMENTS.get('MODE', 'default') == 'default' and
+ env['BUILD_TYPE'] == 'dbg-d3d')):
+ i = env.Replicate('$FIREFOX_PLUGIN_DIR', plugin_dll[0])
+ env.Alias('install', i)
+
+if env.Bit('windows'):
+ # Make the logging program
+ exe = env.ComponentProgram('statsLogger',
+ logging_lib + ['win/logger_main.cc'])
+ # Copy the resulting executable to the Artifacts directory.
+ env.Replicate('$ARTIFACTS_DIR', [exe])
diff --git a/o3d/plugin/cross/archive_request_glue.cc b/o3d/plugin/cross/archive_request_glue.cc
new file mode 100644
index 0000000..704aaa7
--- /dev/null
+++ b/o3d/plugin/cross/archive_request_glue.cc
@@ -0,0 +1,214 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "plugin/cross/archive_request_glue.h"
+
+#include "base/basictypes.h"
+#include "plugin/cross/stream_manager.h"
+#include "plugin/cross/o3d_glue.h"
+#include "import/cross/archive_request.h"
+
+namespace glue {
+namespace namespace_o3d {
+namespace class_ArchiveRequest {
+
+using _o3d::PluginObject;
+using o3d::Pack;
+using o3d::ArchiveRequest;
+
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Callbacks
+//
+// TODO : get rid of these horrible callback objects which end up just
+// dispatching to the ArchiveRequest object.
+// Need to change the StreamManager class to implement an interface:
+// WriteReadyCallback
+// WriteCallback
+// FinishedCallback
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class ArchiveNewStreamCallback : public StreamManager::NewStreamCallback {
+ public:
+ explicit ArchiveNewStreamCallback(ArchiveRequest *request)
+ : request_(request) { }
+
+ virtual void Run(DownloadStream *stream) {
+ request_->NewStreamCallback(stream);
+ }
+
+ private:
+ ArchiveRequest::Ref request_;
+ DISALLOW_COPY_AND_ASSIGN(ArchiveNewStreamCallback);
+};
+
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class ArchiveWriteReadyCallback : public StreamManager::WriteReadyCallback {
+ public:
+ explicit ArchiveWriteReadyCallback(ArchiveRequest *request)
+ : request_(request) { }
+
+ virtual int32 Run(DownloadStream *stream) {
+ return request_->WriteReadyCallback(stream);
+ }
+
+ private:
+ ArchiveRequest::Ref request_;
+ DISALLOW_COPY_AND_ASSIGN(ArchiveWriteReadyCallback);
+};
+
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class ArchiveWriteCallback : public StreamManager::WriteCallback {
+ public:
+ explicit ArchiveWriteCallback(ArchiveRequest *request) : request_(request) {
+ }
+
+ virtual int32 Run(DownloadStream *stream,
+ int32 offset,
+ int32 length,
+ void *data) {
+ return request_->WriteCallback(stream, offset, length, data);
+ }
+
+ private:
+ ArchiveRequest::Ref request_;
+ DISALLOW_COPY_AND_ASSIGN(ArchiveWriteCallback);
+};
+
+class ArchiveFinishedCallback : public StreamManager::FinishedCallback {
+ public:
+ explicit ArchiveFinishedCallback(ArchiveRequest *request)
+ : request_(request) {
+ }
+
+ virtual ~ArchiveFinishedCallback() {
+ // If the file request was interrupted (for example we moved to a new page
+ // before the file transfer was completed) then we tell the FileRequest
+ // object that the request failed. It's important to call this here since
+ // set_success() will release the pack reference that the FileRequest holds
+ // which will allow the pack to be garbage collected.
+ if (!request_->done()) {
+ request_->set_success(false);
+ }
+ }
+
+ // Loads the Archive file, calls the JS callback to notify success.
+ virtual void Run(DownloadStream *stream,
+ bool success,
+ const std::string &filename,
+ const std::string &mime_type) {
+ request_->FinishedCallback(stream, success, filename, mime_type);
+ }
+
+ private:
+ ArchiveRequest::Ref request_;
+ DISALLOW_COPY_AND_ASSIGN(ArchiveFinishedCallback);
+};
+
+// Sets up the parameters required for all ArchiveRequests.
+void userglue_method_open(void *plugin_data,
+ ArchiveRequest *request,
+ const String &method,
+ const String &uri) {
+ if (request->done()) {
+ request->set_success(false);
+ request->set_ready_state(ArchiveRequest::STATE_INIT); // not ready
+ return; // We don't yet support reusing ArchiveRequests.
+ }
+
+ String method_lower(method);
+ std::transform(method.begin(), method.end(), method_lower.begin(), ::tolower);
+ if (method_lower != "get") {
+ request->set_success(false);
+ return; // We don't yet support fetching files via POST.
+ }
+ request->set_uri(uri);
+ request->set_ready_state(ArchiveRequest::STATE_OPEN);
+}
+
+// Starts progressively downloading the requested file
+// The ArchiveRequest object will get callbacks as bytes stream in
+void userglue_method_send(void *plugin_data,
+ ArchiveRequest *request) {
+ PluginObject *plugin_object = static_cast<PluginObject *>(plugin_data);
+ StreamManager *stream_manager = plugin_object->stream_manager();
+ bool result = false;
+
+ if (request->done()) {
+ request->set_success(false);
+ return; // ArchiveRequests can't be reused.
+ }
+ if (request->ready_state() != 1) { // Forgot to call open, or other error.
+ request->set_success(false);
+ return;
+ }
+ CHECK(request->pack());
+
+ ArchiveNewStreamCallback *new_stream_callback =
+ new ArchiveNewStreamCallback(request);
+
+ ArchiveWriteReadyCallback *writeready_callback =
+ new ArchiveWriteReadyCallback(request);
+
+ ArchiveWriteCallback *write_callback =
+ new ArchiveWriteCallback(request);
+
+ ArchiveFinishedCallback *finished_callback =
+ new ArchiveFinishedCallback(request);
+
+ if (finished_callback) {
+ DownloadStream *stream = stream_manager->LoadURL(request->uri(),
+ new_stream_callback,
+ writeready_callback,
+ write_callback,
+ finished_callback,
+ NP_NORMAL);
+ if (!stream) {
+ // We don't call O3D_ERROR here because the URI may be user set
+ // so we don't want to cause an error callback when the developer
+ // may not be able to know the URI is correct.
+ request->set_error("could not create download stream");
+
+ // We need to call the callback to report failure. Because it's async, the
+ // code making the request can't know that once it has called send() that
+ // the request still exists since send() may have called the callback and
+ // the callback may have deleted the request.
+ request->FinishedCallback(NULL, false, request->uri(), std::string(""));
+ }
+
+ // If stream is not NULL request may not exist as LoadURL may already have
+ // completed and therefore called the callback which may have freed the
+ // request so we can't set anything on the request here.
+ }
+}
+
+} // namespace class_ArchiveRequest
+} // namespace namespace_o3d
+} // namespace glue
diff --git a/o3d/plugin/cross/archive_request_glue.h b/o3d/plugin/cross/archive_request_glue.h
new file mode 100644
index 0000000..f9f1384
--- /dev/null
+++ b/o3d/plugin/cross/archive_request_glue.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// This file declares the glue for FileRequest actions.
+
+#ifndef O3D_PLUGIN_ARCHIVE_REQUEST_GLUE_H_
+#define O3D_PLUGIN_ARCHIVE_REQUEST_GLUE_H_
+
+#include "core/cross/callback.h"
+#include "core/cross/types.h"
+
+namespace o3d {
+class ArchiveRequest;
+} // namespace o3d
+
+namespace glue {
+namespace namespace_o3d {
+namespace class_ArchiveRequest {
+
+using o3d::ArchiveRequest;
+using o3d::String;
+
+// Sets up the parameters required for all FileRequests.
+void userglue_method_open(void *plugin_data,
+ ArchiveRequest *request,
+ const String &method,
+ const String &uri);
+
+// Starts downloading or reading the requested file, passing in a callback that
+// will parse and incorporate the file upon success.
+void userglue_method_send(void *plugin_data,
+ ArchiveRequest *request);
+} // namespace class_FileRequest
+} // namespace namespace_o3d
+} // namespace glue
+
+#endif // O3D_PLUGIN_ARCHIVE_REQUEST_GLUE_H_
diff --git a/o3d/plugin/cross/async_loading.cc b/o3d/plugin/cross/async_loading.cc
new file mode 100644
index 0000000..6c75d82
--- /dev/null
+++ b/o3d/plugin/cross/async_loading.cc
@@ -0,0 +1,223 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// This file implements the asynchronous file-loading glue.
+
+#include <algorithm>
+
+#include "plugin/cross/async_loading.h"
+#include "plugin/cross/o3d_glue.h"
+#include "plugin/cross/stream_manager.h"
+#include "core/cross/bitmap.h"
+#include "core/cross/error_status.h"
+#include "core/cross/file_request.h"
+#include "core/cross/pack.h"
+#include "core/cross/texture.h"
+
+namespace glue {
+namespace namespace_o3d {
+namespace class_FileRequest {
+
+using _o3d::PluginObject;
+using o3d::Bitmap;
+using o3d::Pack;
+using o3d::Texture;
+
+// StreamManager::FinishedCallback
+// implementation that imports the file as a texture once downloaded.
+// When the download completes, LoadTextureURLCallback::Run() will be called,
+// which will parse and load the downloaded file. After that load is complete,
+// onreadystatechange will be run to notify the user.
+class LoadTextureURLCallback : public StreamManager::FinishedCallback {
+ public:
+ // Creates a new LoadTextureURLCallback.
+ static LoadTextureURLCallback *Create(FileRequest *request) {
+ return new LoadTextureURLCallback(request);
+ }
+
+ virtual ~LoadTextureURLCallback() {
+ // If the file request was interrupted (for example we moved to a new page
+ // before the file transfer was completed) then we tell the FileRequest
+ // object that the request failed. It's important to call this here since
+ // set_success() will release the pack reference that the FileRequest holds
+ // which will allow the pack to be garbage collected.
+ if (!request_->done()) {
+ request_->set_success(false);
+ }
+ }
+
+ // Loads the texture file, calls the JS callback to pass back the texture
+ // object.
+ virtual void Run(DownloadStream*,
+ bool success,
+ const std::string &filename,
+ const std::string &mime_type) {
+ Texture::Ref texture;
+ if (success) {
+ o3d::ErrorCollector error_collector(request_->service_locator());
+ request_->set_ready_state(FileRequest::STATE_LOADED);
+ // Try to get the image file type from the returned MIME type.
+ // Unfortunately, TGA and DDS don't have standard MIME type, so we may
+ // have to rely on the filename, or let the image loader figure it out by
+ // itself (by trying every possible type).
+ Bitmap::ImageFileType image_type =
+ Bitmap::GetFileTypeFromMimeType(mime_type.c_str());
+ texture = Texture::Ref(
+ request_->pack()->CreateTextureFromFile(
+ request_->uri(),
+ filename.c_str(),
+ image_type,
+ request_->generate_mipmaps()));
+ if (texture) {
+ texture->set_name(request_->uri());
+ request_->set_texture(texture);
+ } else {
+ success = false;
+ }
+ request_->set_error(error_collector.errors());
+ } else {
+ // No error is passed in from the stream but we MUST have an error
+ // for the request to work on the javascript side.
+ request_->set_error("Could not download texture. It could be a "
+ "permission-related issue.");
+ }
+ request_->set_success(success);
+ // Since the standard codes only go far enough to tell us that the download
+ // succeeded, we set the success [and implicitly the done] flags to give the
+ // rest of the story.
+ if (request_->onreadystatechange())
+ request_->onreadystatechange()->Run();
+ }
+
+ private:
+ FileRequest::Ref request_;
+
+ explicit LoadTextureURLCallback(FileRequest *request)
+ : request_(request) {
+ }
+};
+
+// Sets up the parameters required for all FileRequests.
+void userglue_method_open(void *plugin_data,
+ FileRequest *request,
+ const String &method,
+ const String &uri,
+ bool async) {
+ if (!async) {
+ request->set_success(false);
+ O3D_ERROR(request->service_locator())
+ << ("synchronous request not supported");
+ return; // We don't yet support synchronous requests.
+ }
+ if (request->done()) {
+ request->set_success(false);
+ request->set_ready_state(FileRequest::STATE_INIT); // Show we're unready.
+ O3D_ERROR(request->service_locator())
+ << "request can not be reused";
+ return; // We don't yet support reusing FileRequests.
+ }
+
+ String method_lower(method);
+ std::transform(method.begin(), method.end(), method_lower.begin(), ::tolower);
+ if (method_lower != "get") {
+ request->set_success(false);
+ O3D_ERROR(request->service_locator())
+ << "request does not support POST yet";
+ return; // We don't yet support fetching files via POST.
+ }
+ request->set_uri(uri);
+ request->set_ready_state(FileRequest::STATE_OPEN);
+}
+
+// Starts downloading or reading the requested file, passing in a callback that
+// will parse and incorporate the file upon success.
+void userglue_method_send(void *plugin_data,
+ FileRequest *request) {
+ PluginObject *plugin_object = static_cast<PluginObject *>(plugin_data);
+ StreamManager *stream_manager = plugin_object->stream_manager();
+ StreamManager::FinishedCallback *callback = NULL;
+ bool result = false;
+
+ if (request->done()) {
+ request->set_success(false);
+ O3D_ERROR(request->service_locator())
+ << "request can not be reused";
+ return; // FileRequests can't be reused.
+ }
+ if (request->ready_state() != 1) { // Forgot to call open, or other error.
+ request->set_success(false);
+ O3D_ERROR(request->service_locator())
+ << "open must be called before send";
+ return;
+ }
+ CHECK(request->pack());
+
+ switch (request->type()) {
+ case FileRequest::TYPE_TEXTURE:
+ callback = LoadTextureURLCallback::Create(request);
+ break;
+ default:
+ CHECK(false);
+ }
+ if (callback) {
+ DownloadStream *stream =
+ stream_manager->LoadURL(request->uri(),
+ NULL, // new stream callback
+ NULL, // write ready callback
+ NULL, // write callback
+ callback, // finished callback
+ NP_ASFILEONLY);
+
+ if (!stream) {
+ request->set_success(false);
+
+ // We don't call O3D_ERROR here because the URI may be user set
+ // so we don't want to cause an error callback when the devloper
+ // may not be able to know the URI is correct.
+ request->set_error("could not create download stream");
+
+ // We need to call the callback to report failure. Because it's async, the
+ // code making the request can't know that once it has called send() that
+ // the request still exists since send() may have called the callback and
+ // the callback may have deleted the request.
+ request->onreadystatechange()->Run();
+ }
+
+ // If stream is not NULL request may not exist as LoadURL may already have
+ // completed and therefore called the callback which may have freed the
+ // request so we can't set anything on the request here.
+ }
+}
+
+} // namespace class_FileRequest
+} // namespace namespace_o3d
+} // namespace glue
diff --git a/o3d/plugin/cross/async_loading.h b/o3d/plugin/cross/async_loading.h
new file mode 100644
index 0000000..d0df9df
--- /dev/null
+++ b/o3d/plugin/cross/async_loading.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// This file declares the glue for FileRequest actions.
+
+#ifndef EXPERIMENTAL_O3D_O3DPLUGIN_AUTOGEN_O3D_GLUE_ASYNC_LOADING_H_
+#define EXPERIMENTAL_O3D_O3DPLUGIN_AUTOGEN_O3D_GLUE_ASYNC_LOADING_H_
+
+#include "core/cross/callback.h"
+#include "core/cross/types.h"
+
+namespace o3d {
+class FileRequest;
+} // namespace o3d
+
+namespace glue {
+namespace namespace_o3d {
+namespace class_FileRequest {
+
+using o3d::FileRequest;
+using o3d::String;
+
+// Sets up the parameters required for all FileRequests.
+void userglue_method_open(void *plugin_data,
+ FileRequest *request,
+ const String &method,
+ const String &uri,
+ bool async);
+
+// Starts downloading or reading the requested file, passing in a callback that
+// will parse and incorporate the file upon success.
+void userglue_method_send(void *plugin_data,
+ FileRequest *request);
+} // namespace class_FileRequest
+} // namespace namespace_o3d
+} // namespace glue
+
+#endif // EXPERIMENTAL_O3D_O3DPLUGIN_AUTOGEN_O3D_GLUE_ASYNC_LOADING_H_
diff --git a/o3d/plugin/cross/blacklist.cc b/o3d/plugin/cross/blacklist.cc
new file mode 100644
index 0000000..270c4df
--- /dev/null
+++ b/o3d/plugin/cross/blacklist.cc
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <iostream>
+#include <fstream>
+
+#include "plugin/cross/config.h"
+#include "base/logging.h"
+
+// Checks the driver GUID against the blacklist file. Returns true if there's a
+// match [this driver is blacklisted] or if an IO error occurred. Check the
+// state of input_file to determine which it was.
+//
+// Note that this function always returns false if the guid is 0, since it will
+// be zero if we had a failure in reading it, and the user will already have
+// been warned.
+bool IsDriverBlacklisted(std::ifstream *input_file, unsigned int guid) {
+ if (!guid) {
+ return false;
+ }
+ *input_file >> std::ws;
+ while (input_file->good()) {
+ if (input_file->peek() == '#') {
+ char comment[256];
+ input_file->getline(comment, 256);
+ // If the line was too long for this to work, it'll set the failbit.
+ } else {
+ unsigned int id;
+ *input_file >> std::hex >> id;
+ if (id == guid) {
+ return true;
+ }
+ }
+ *input_file >> std::ws; // Skip whitespace here, to catch EOF cleanly.
+ }
+ if (input_file->fail()) {
+ LOG(ERROR) << "Failed to read the blacklisted driver file completely.";
+ return true;
+ }
+ CHECK(input_file->eof());
+ return false;
+}
diff --git a/o3d/plugin/cross/config.h b/o3d/plugin/cross/config.h
new file mode 100644
index 0000000..58ecc00
--- /dev/null
+++ b/o3d/plugin/cross/config.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// This file defines a few functions to check the user's hardware and software
+// configuration.
+
+#ifndef O3D_PLUGIN_CROSS_CONFIG_H_
+#define O3D_PLUGIN_CROSS_CONFIG_H_
+
+#include <fstream>
+#include <string>
+#include "plugin/cross/o3d_glue.h"
+
+// Returns the user agent string.
+// Arguments:
+// npp: plugin instance.
+// Returns:
+// The user agent string.
+std::string GetUserAgent(NPP npp);
+
+struct GPUDevice {
+ unsigned int vendor_id;
+ unsigned int device_id;
+ std::string driver;
+ std::string description;
+ std::string name;
+ unsigned int guid;
+};
+
+// Asks the user to ok a continuation
+// Arguments:
+// npp: plugin instance.
+// error: the error to signal.
+// Returns:
+// true if the error was overridden by the user, false otherwise.
+bool AskUser(NPP npp, const std::string &error);
+
+// Gets the device information.
+// Arguments:
+// device: a GPUDevice structure that will contain the vendor and device IDs.
+// name: a pointer to a string that will contain the device string.
+// Returns:
+// true if successful. If not, device and name are not modified.
+bool GetGPUDevice(NPP npp, GPUDevice *device);
+
+// Checks that the current hardware and software configuration is supported,
+// prompting the user to give him and option to run anyway.
+// Arguments:
+// npp: plugin instance.
+// Returns:
+// Whether to allow the plug-in to run.
+bool CheckConfig(NPP npp);
+
+// The following functions are platform-dependent, and are implemented in the
+// respective {platform}/config.cc files
+
+// Checks the operating system version.
+bool CheckOSVersion(NPP npp);
+
+// Checks the user agent string.
+bool CheckUserAgent(NPP npp, const std::string &user_agent);
+
+// Used to get the text file that lists blacklisted driver GUIDs.
+// Returns true on success.
+bool OpenDriverBlacklistFile(std::ifstream *input_file);
+
+// Checks the driver GUID against the blacklist file. Returns true if there's a
+// match [this driver is blacklisted] or if an IO error occurred. Check the
+// state of input_file to determine which it was.
+// Note that this function always returns false if the guid is 0, since it will
+// be 0 if we had a failure in reading it, and the user will already have been
+// warned.
+bool IsDriverBlacklisted(std::ifstream *input_file, unsigned int guid);
+
+// Checks the current hardware, software configurations and puts the values
+// into metrics.
+bool GetUserConfigMetrics();
+
+// Checks the browser version.
+// Arguments:
+// npp: plugin instance.
+bool GetUserAgentMetrics(NPP npp);
+
+bool GetOpenGLMetrics();
+
+#endif // O3D_PLUGIN_CROSS_CONFIG_H_
diff --git a/o3d/plugin/cross/config_common.cc b/o3d/plugin/cross/config_common.cc
new file mode 100644
index 0000000..de375c0
--- /dev/null
+++ b/o3d/plugin/cross/config_common.cc
@@ -0,0 +1,215 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// This file contains common code to check the hardware and software
+// configuration of the client machine:
+// - User agent (browser)
+// - OS version
+// - GPU vendor
+
+#ifdef RENDERER_D3D9
+#include <d3d9.h>
+#endif
+
+#include <iostream>
+#include <fstream>
+
+#include "base/logging.h"
+#include "core/cross/install_check.h"
+#include "plugin/cross/config.h"
+#include "plugin/cross/o3d_glue.h"
+#include "core/cross/error.h"
+#include "third_party/nixysa/files/static_glue/npapi/common.h"
+
+using glue::_o3d::GetServiceLocator;
+
+// Gets the value of "navigator.userAgent" in the JavaScript context, which
+// contains the user agent string.
+std::string GetUserAgent(NPP npp) {
+ GLUE_PROFILE_START(npp, "NPN_UserAgent");
+ const char* user_agent = NPN_UserAgent(npp);
+ GLUE_PROFILE_STOP(npp, "NPN_UserAgent");
+ std::string uagent_string;
+ if (user_agent) {
+ uagent_string = std::string(user_agent);
+ }
+ return uagent_string;
+}
+
+// Pops up a dialog box using JavaScript showing the error and gives the user a
+// chance to continue anyway.
+bool AskUser(NPP npp, const std::string &error) {
+ NPObject *global_object;
+ GLUE_PROFILE_START(npp, "NPN_GetValue");
+ NPN_GetValue(npp, NPNVWindowNPObject, &global_object);
+ GLUE_PROFILE_STOP(npp, "NPN_GetValue");
+ GLUE_PROFILE_START(npp, "NPN_GetStringIdentifier");
+ NPIdentifier alert_id = NPN_GetStringIdentifier("confirm");
+ GLUE_PROFILE_STOP(npp, "NPN_GetStringIdentifier");
+ std::string message = error;
+ // TODO: internationalize message.
+ // TODO: Should this change to call some hardcoded javascript function
+ // like "o3djs.util.confirmContinuation" or even a global name like
+ // o3djs_confirmContinuation. This would move localization outside
+ // C++ and give the developer a chance to handle it his own way.
+ message += "\nPress OK to continue anyway.";
+
+ NPVariant args[1];
+ NPVariant result;
+ STRINGN_TO_NPVARIANT(message.c_str(), message.length(), args[0]);
+ GLUE_PROFILE_START(npp, "NPN_Invoke");
+ bool temp = NPN_Invoke(npp, global_object, alert_id, args, 1, &result);
+ GLUE_PROFILE_STOP(npp, "NPN_Invoke");
+ if (temp) {
+ bool retval = NPVARIANT_IS_BOOLEAN(result) && NPVARIANT_TO_BOOLEAN(result);
+ GLUE_PROFILE_START(npp, "NPN_ReleaseVariantValue");
+ NPN_ReleaseVariantValue(&result);
+ GLUE_PROFILE_STOP(npp, "NPN_ReleaseVariantValue");
+ return retval;
+ } else {
+ return false;
+ }
+}
+
+// Gets the GPU device IDs and name, pops up a dialog box to confirm with the
+// user in case we can't get the information.
+bool GetGPUDevice(NPP npp, GPUDevice *device) {
+#if defined(RENDERER_D3D9)
+ // Check GPU vendor using D3D.
+ IDirect3D9 *d3d = Direct3DCreate9(D3D_SDK_VERSION);
+ if (!d3d) {
+ O3D_ERROR(GetServiceLocator(npp)) << "Direct3D9 is unavailable";
+ return false;
+ }
+ D3DADAPTER_IDENTIFIER9 identifier;
+ HRESULT hr = d3d->GetAdapterIdentifier(D3DADAPTER_DEFAULT, 0, &identifier);
+ d3d->Release();
+ if (hr != D3D_OK) {
+ O3D_ERROR(GetServiceLocator(npp)) << "Unable to get device ID";
+ device->vendor_id = 0;
+ device->device_id = 0;
+ device->name = "Unknown";
+ device->driver = "Unknown";
+ device->description = "Unknown";
+ device->guid = 0;
+ return false;
+ }
+ device->vendor_id = identifier.VendorId;
+ device->device_id = identifier.DeviceId;
+ device->name = identifier.DeviceName;
+ device->driver = identifier.Driver;
+ device->description = identifier.Description;
+ device->guid = identifier.DeviceIdentifier.Data1;
+ return true;
+#else
+ // TODO: check GL version, blacklisted vendors ?
+ device->vendor_id = 0;
+ device->device_id = 0;
+ device->name = "Unknown";
+ device->driver = "Unknown";
+ device->description = "Unknown";
+ device->guid = 0;
+ return true;
+#endif
+}
+
+// List of "black-listed" GPUs.
+//
+// A Vendor ID of 0 means end of the list. A device ID of 0 means the entire
+// line of devices from this vendor is black-listed.
+//
+// NOTE: Black-listed GPUs are only for GPUs that have security or stability
+// issues. GPUs that are missing required features are handled by the renderer.
+static const GPUDevice g_blacklisted_gpus[] = {
+ {0, 0, }, // End Marker
+};
+
+// Checks various configuration elements:
+// - Windows version
+// - GPU vendor
+// - User agent (browser)
+bool CheckConfig(NPP npp) {
+ if (!CheckOSVersion(npp)) return false;
+
+ GPUDevice device;
+ if (!GetGPUDevice(npp, &device)) return false;
+ for (unsigned int i = 0;
+ g_blacklisted_gpus[i].vendor_id != 0; ++i) {
+ if (device.vendor_id == g_blacklisted_gpus[i].vendor_id &&
+ (device.device_id == g_blacklisted_gpus[i].device_id ||
+ g_blacklisted_gpus[i].device_id == 0)) {
+ O3D_ERROR(GetServiceLocator(npp))
+ << "Unsupported GPU device: " + device.name;
+ return false;
+ }
+ }
+
+ {
+ std::ifstream blacklist_file;
+ std::string error;
+ if (!OpenDriverBlacklistFile(&blacklist_file)) {
+ // Allow missing blacklist file for now, or else pulse and developer
+ // builds [which don't install the file] will fail.
+ // TODO: Look into this again for the public release.
+ // error = "Failed to open driver blacklist file.\n"
+ // "Can't verify that it's safe to run O3D.";
+ } else if (IsDriverBlacklisted(&blacklist_file, device.guid)) {
+ if (blacklist_file.fail()) {
+ error = "Error reading driver blacklist file.\n"
+ "Can't verify that it's safe to run O3D.";
+ } else {
+ error = "Your driver cannot run O3D safely.";
+ }
+ }
+ if (error.length() && !AskUser(npp, error)) {
+ return false;
+ }
+ }
+
+ {
+ std::string error;
+ if (!o3d::RendererInstallCheck(&error)) {
+ if (error.length()) {
+ O3D_ERROR(GetServiceLocator(npp)) << error;
+ } else {
+ O3D_ERROR(GetServiceLocator(npp))
+ << "Could not initialize the graphics driver.";
+ }
+ return false;
+ }
+ }
+
+ // Check User agent. Only Firefox, Chrome and IE are supported.
+ std::string user_agent = GetUserAgent(npp);
+ if (!CheckUserAgent(npp, user_agent)) return false;
+ return true;
+}
diff --git a/o3d/plugin/cross/download_stream.h b/o3d/plugin/cross/download_stream.h
new file mode 100644
index 0000000..8222386
--- /dev/null
+++ b/o3d/plugin/cross/download_stream.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#ifndef O3D_PLUGIN_CROSS_DOWNLOAD_STREAM_H_
+#define O3D_PLUGIN_CROSS_DOWNLOAD_STREAM_H_
+
+#include <string>
+
+namespace glue {
+
+// Abstract interface representing a download
+class DownloadStream {
+ public:
+ enum State {
+ STREAM_REQUESTED,
+ STREAM_STARTED, // in progress
+ STREAM_FINISHED // completed successfully or terminated
+ };
+
+ virtual ~DownloadStream() {}
+
+ virtual std::string GetURL() = 0;
+
+ // Returns empty string if no cache file
+ virtual std::string GetCachedFile() = 0;
+
+ virtual State GetState() = 0;
+ virtual int GetReceivedByteCount() = 0;
+ virtual size_t GetStreamLength() = 0;
+
+ // Stops downloading
+ virtual void Cancel() = 0;
+};
+
+} // namespace glue
+
+#endif // O3D_PLUGIN_CROSS_DOWNLOAD_STREAM_H_
diff --git a/o3d/plugin/cross/main.cc b/o3d/plugin/cross/main.cc
new file mode 100644
index 0000000..6bf5aab
--- /dev/null
+++ b/o3d/plugin/cross/main.cc
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "plugin/cross/main.h"
+
+using glue::_o3d::PluginObject;
+using glue::StreamManager;
+
+int BreakpadEnabler::scope_count_ = 0;
+
+// Used for breakpad crash handling
+ExceptionManager *g_exception_manager = NULL;
+
+extern "C" {
+ char *NP_GetMIMEDescription(void) {
+ return O3D_PLUGIN_MIME_TYPE "::O3D MIME";
+ }
+
+ NPError NP_GetValue(void *instance, NPPVariable variable, void *value) {
+ switch (variable) {
+ case NPPVpluginNameString:
+ *static_cast<char **>(value) = O3D_PLUGIN_NAME;
+ break;
+ case NPPVpluginDescriptionString:
+ *static_cast<char **>(value) = O3D_PLUGIN_DESCRIPTION;
+ break;
+ default:
+ return NPERR_INVALID_PARAM;
+ break;
+ }
+ return NPERR_NO_ERROR;
+ }
+
+ NPError OSCALL NP_GetEntryPoints(NPPluginFuncs *pluginFuncs) {
+ HANDLE_CRASHES;
+ pluginFuncs->version = 11;
+ pluginFuncs->size = sizeof(pluginFuncs);
+ pluginFuncs->newp = NPP_New;
+ pluginFuncs->destroy = NPP_Destroy;
+ pluginFuncs->setwindow = NPP_SetWindow;
+ pluginFuncs->newstream = NPP_NewStream;
+ pluginFuncs->destroystream = NPP_DestroyStream;
+ pluginFuncs->asfile = NPP_StreamAsFile;
+ pluginFuncs->writeready = NPP_WriteReady;
+ pluginFuncs->write = NPP_Write;
+ pluginFuncs->print = NPP_Print;
+ pluginFuncs->event = NPP_HandleEvent;
+ pluginFuncs->urlnotify = NPP_URLNotify;
+ pluginFuncs->getvalue = NPP_GetValue;
+ pluginFuncs->setvalue = NPP_SetValue;
+
+ return NPERR_NO_ERROR;
+ }
+
+ NPError NPP_NewStream(NPP instance, NPMIMEType type, NPStream *stream,
+ NPBool seekable, uint16 *stype) {
+ HANDLE_CRASHES;
+ PluginObject *obj = static_cast<PluginObject*>(instance->pdata);
+ StreamManager *stream_manager = obj->stream_manager();
+ if (stream_manager->NewStream(stream, stype)) {
+ return NPERR_NO_ERROR;
+ } else {
+ // TODO: find out which error we should return
+ return NPERR_INVALID_PARAM;
+ }
+ }
+
+ NPError NPP_DestroyStream(NPP instance, NPStream *stream, NPReason reason) {
+ HANDLE_CRASHES;
+ PluginObject *obj = static_cast<PluginObject*>(instance->pdata);
+ StreamManager *stream_manager = obj->stream_manager();
+ if (stream_manager->DestroyStream(stream, reason)) {
+ return NPERR_NO_ERROR;
+ } else {
+ // TODO: find out which error we should return
+ return NPERR_INVALID_PARAM;
+ }
+ }
+
+ int32 NPP_WriteReady(NPP instance, NPStream *stream) {
+ HANDLE_CRASHES;
+ PluginObject *obj = static_cast<PluginObject*>(instance->pdata);
+ StreamManager *stream_manager = obj->stream_manager();
+ return stream_manager->WriteReady(stream);
+ }
+
+ int32 NPP_Write(NPP instance, NPStream *stream, int32 offset, int32 len,
+ void *buffer) {
+ HANDLE_CRASHES;
+ PluginObject *obj = static_cast<PluginObject*>(instance->pdata);
+ StreamManager *stream_manager = obj->stream_manager();
+ return stream_manager->Write(stream, offset, len, buffer);
+ }
+
+ void NPP_Print(NPP instance, NPPrint *platformPrint) {
+ HANDLE_CRASHES;
+ }
+
+ void NPP_URLNotify(NPP instance, const char *url, NPReason reason,
+ void *notifyData) {
+ HANDLE_CRASHES;
+ PluginObject *obj = static_cast<PluginObject*>(instance->pdata);
+ StreamManager *stream_manager = obj->stream_manager();
+ stream_manager->URLNotify(url, reason, notifyData);
+ }
+
+ NPError NPP_GetValue(NPP instance, NPPVariable variable, void *value) {
+ HANDLE_CRASHES;
+ switch (variable) {
+ case NPPVpluginScriptableNPObject: {
+ void **v = static_cast<void **>(value);
+ PluginObject *obj = static_cast<PluginObject *>(instance->pdata);
+ // Return value is expected to be retained
+ GLUE_PROFILE_START(instance, "retainobject");
+ NPN_RetainObject(obj);
+ GLUE_PROFILE_STOP(instance, "retainobject");
+ *v = obj;
+ break;
+ }
+ default:
+ return NP_GetValue(instance, variable, value);
+ break;
+ }
+ return NPERR_NO_ERROR;
+ }
+
+ NPError NPP_SetValue(NPP instance, NPNVariable variable, void *value) {
+ HANDLE_CRASHES;
+ return NPERR_GENERIC_ERROR;
+ }
+} // extern "C"
diff --git a/o3d/plugin/cross/main.h b/o3d/plugin/cross/main.h
new file mode 100644
index 0000000..79a657a
--- /dev/null
+++ b/o3d/plugin/cross/main.h
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// This header is used by the platform-specific portions of the plugin
+// main implementation to define the cross-platform parts of the
+// interface and global variables.
+
+#ifndef O3D_PLUGIN_CROSS_MAIN_H_
+#define O3D_PLUGIN_CROSS_MAIN_H_
+
+#include <npupp.h>
+#include <stdio.h>
+
+#include <fstream>
+#include <iostream>
+
+#include "breakpad/win/exception_handler_win32.h"
+#include "core/cross/renderer.h"
+#include "core/cross/renderer_platform.h"
+#include "plugin/cross/o3d_glue.h"
+#include "plugin/cross/config.h"
+#include "plugin/cross/stream_manager.h"
+#include "third_party/nixysa/files/static_glue/npapi/common.h"
+#include "third_party/nixysa/files/static_glue/npapi/npn_api.h"
+
+extern ExceptionManager *g_exception_manager;
+
+class RenderOnDemandCallbackHandler
+ : public o3d::Client::RenderOnDemandCallback {
+ public:
+ explicit RenderOnDemandCallbackHandler(glue::_o3d::PluginObject* obj)
+ : obj_(obj) {
+ }
+
+ // This function is implemented for each platform.
+ virtual void Run();
+ private:
+ glue::_o3d::PluginObject* obj_;
+};
+
+// BreakpadEnabler is a simple class to keep track of whether or not
+// we're executing code that we want to handle crashes for
+// (when the o3d plugin is running in Firefox, we don't want to handle
+// crashes for the Flash plugin or Firefox, just the o3d code)
+// Create a stack-based instance at the start of each function
+// where crash handling is desired.
+
+#define HANDLE_CRASHES BreakpadEnabler enabler
+
+class BreakpadEnabler {
+ public:
+ BreakpadEnabler() {
+ ++scope_count_;
+ }
+
+ virtual ~BreakpadEnabler() {
+ --scope_count_;
+ }
+
+ static bool IsEnabled() { return scope_count_ > 0; }
+
+ private:
+ static int scope_count_;
+};
+
+
+namespace o3d {
+void WriteLogString(const char* text, int length);
+} // end namespace o3d
+
+// NPAPI declarations. Some of these are only implemented in the
+// platform-specific versions of "main.cc".
+
+extern "C" {
+ NPError OSCALL NP_Shutdown(void);
+ NPError OSCALL NP_GetEntryPoints(NPPluginFuncs *pluginFuncs);
+ NPError NPP_Destroy(NPP instance, NPSavedData **save);
+ NPError NPP_DestroyStream(NPP instance, NPStream *stream, NPReason reason);
+ NPError NPP_GetValue(NPP instance, NPPVariable variable, void *value);
+
+ NPError NPP_New(NPMIMEType pluginType,
+ NPP instance,
+ uint16 mode,
+ int16 argc,
+ char *argn[],
+ char *argv[],
+ NPSavedData *saved);
+
+ NPError NPP_NewStream(NPP instance,
+ NPMIMEType type,
+ NPStream *stream,
+ NPBool seekable,
+ uint16 *stype);
+
+ NPError NPP_SetValue(NPP instance, NPNVariable variable, void *value);
+ NPError NPP_SetWindow(NPP instance, NPWindow *window);
+
+ int32 NPP_Write(NPP instance,
+ NPStream *stream,
+ int32 offset,
+ int32 len,
+ void *buffer);
+
+ int32 NPP_WriteReady(NPP instance, NPStream *stream);
+ void NPP_Print(NPP instance, NPPrint *platformPrint);
+ void NPP_StreamAsFile(NPP instance, NPStream *stream, const char *fname);
+
+ void NPP_URLNotify(NPP instance,
+ const char *url,
+ NPReason reason,
+ void *notifyData);
+}; // end extern "C"
+
+#endif // O3D_PLUGIN_CROSS_MAIN_H_
diff --git a/o3d/plugin/cross/marshaling_utils.h b/o3d/plugin/cross/marshaling_utils.h
new file mode 100644
index 0000000..1a8b4d0
--- /dev/null
+++ b/o3d/plugin/cross/marshaling_utils.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// This file contains utility functions for marshaling between
+// C++ types and dynamic types.
+
+#ifndef O3D_PLUGIN_CROSS_MARSHALING_UTILS_H_
+#define O3D_PLUGIN_CROSS_MARSHALING_UTILS_H_
+
+#include <vector>
+
+namespace o3d {
+
+// Converts a std::vector<float>, representing a JavaScript array
+// of numbers, to a FloatN, VectorN, or PointN. This template function
+// supports conversion to any type which accesses float elements using
+// operator[].
+template <typename VectorType, int dimension>
+VectorType VectorToType(void* plugin_data,
+ const std::vector<float>& dynamic_value) {
+ if (dynamic_value.size() != dimension) {
+ o3d::ServiceLocator* service_locator =
+ static_cast<glue::_o3d::PluginObject*>(
+ plugin_data)->service_locator();
+ O3D_ERROR(service_locator)
+ << "Vector type expected array of " << dimension
+ << " number values, got " << dynamic_value.size();
+ return VectorType();
+ }
+ VectorType vector_value;
+ for (int i = 0; i < dimension; ++i) {
+ vector_value[i] = dynamic_value[i];
+ }
+ return vector_value;
+}
+
+// Converts a FloatN, VectorN or PointN to an std::vector<float>.
+// This template function supports conversion from any type which
+// accesses float elements using operator[].
+template <typename VectorType, int dimension>
+std::vector<float> VectorFromType(const VectorType& vector_value) {
+ std::vector<float> dynamic_value(dimension);
+ for (int i = 0; i < dimension; ++i) {
+ dynamic_value[i] = vector_value[i];
+ }
+ return dynamic_value;
+}
+
+// Converts an std::vector<std::vector<float> > to a MatrixN.
+template <typename MatrixType, int rows, int columns>
+MatrixType VectorOfVectorToType(
+ void* plugin_data,
+ const std::vector<std::vector<float> >& dynamic_value) {
+ if (dynamic_value.size() != rows) {
+ o3d::ServiceLocator* service_locator =
+ static_cast<glue::_o3d::PluginObject*>(
+ plugin_data)->service_locator();
+ O3D_ERROR(service_locator)
+ << "Matrix type expected array of " << rows
+ << " arrays of " << columns << " number values, got "
+ << dynamic_value.size() << " rows";
+ return MatrixType();
+ }
+ MatrixType matrix_value;
+ for (int i = 0; i != rows; ++i) {
+ if (dynamic_value[i].size() != columns) {
+ o3d::ServiceLocator* service_locator =
+ static_cast<glue::_o3d::PluginObject*>(
+ plugin_data)->service_locator();
+ O3D_ERROR(service_locator)
+ << "Matrix type expected array of " << rows
+ << " arrays of " << columns << " number values, got "
+ << dynamic_value[i].size() << " columns in row "
+ << i;
+ return MatrixType();
+ }
+ for (int j = 0; j < columns; ++j) {
+ matrix_value.setElem(i, j, dynamic_value[i][j]);
+ }
+ }
+ return matrix_value;
+}
+
+// Converts a MatrixN to a std::vector<std::vector<float> >.
+template <typename MatrixType, int rows, int columns>
+std::vector<std::vector<float> > VectorOfVectorFromType(
+ const MatrixType& matrix_value) {
+ std::vector<std::vector<float> > dynamic_value(rows);
+ for (int i = 0; i < rows; ++i) {
+ dynamic_value[i].resize(columns);
+ for (int j = 0; j < columns; ++j) {
+ dynamic_value[i][j] = matrix_value.getElem(i, j);
+ }
+ }
+ return dynamic_value;
+}
+
+} // namespace o3d
+
+#endif // O3D_PLUGIN_CROSS_MARSHALING_UTILS_H_
diff --git a/o3d/plugin/cross/np_v8_bridge.cc b/o3d/plugin/cross/np_v8_bridge.cc
new file mode 100644
index 0000000..0cfcd59
--- /dev/null
+++ b/o3d/plugin/cross/np_v8_bridge.cc
@@ -0,0 +1,1511 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// Code relating to interoperation of V8 JavaScript engine with NPAPI.
+// Tests are in o3d/tests/selenium/tests/v8.html. They can be run
+// by opening the web page in a browser or as part of the selenium tests.
+
+#include <npapi.h>
+#include <sstream>
+#include <vector>
+#include "plugin/cross/np_v8_bridge.h"
+
+using v8::AccessorInfo;
+using v8::Arguments;
+using v8::Array;
+using v8::Context;
+using v8::DontDelete;
+using v8::DontEnum;
+using v8::External;
+using v8::Function;
+using v8::FunctionTemplate;
+using v8::HandleScope;
+using v8::Int32;
+using v8::Integer;
+using v8::Local;
+using v8::Message;
+using v8::Null;
+using v8::Number;
+using v8::Object;
+using v8::ObjectTemplate;
+using v8::Persistent;
+using v8::PropertyAttribute;
+using v8::ReadOnly;
+using v8::Script;
+using v8::TryCatch;
+using v8::Undefined;
+using v8::Value;
+
+namespace o3d {
+
+// Only used during debugging. Type "o3d::DebugV8String(a.val_)" in the
+// watch window to get the string representation of a V8 object.
+const char* DebugV8String(Value* value) {
+ static char buffer[4096];
+ if (value == NULL) {
+ ::base::snprintf(buffer, sizeof(buffer), "<null>");
+ } else {
+ value->ToString()->WriteUtf8(buffer);
+ }
+ return buffer;
+}
+
+namespace {
+
+// The indices of the internal fields of a V8 proxy for an NPObject.
+enum {
+ // Pointer to the bridge that created the proxy.
+ V8_NP_OBJECT_BRIDGE,
+ // Pointer to the wrapped NPObject.
+ V8_NP_OBJECT_WRAPPED,
+ V8_NP_OBJECT_NUM_INTERNAL_FIELDS
+};
+
+// The name of the "hidden" property in a V8 non-proxy object that contains
+// an External that points to the NPObject proxy for it. The property does
+// not exist if there is no associated NPObject proxy.
+const char* const kInternalProperty = "internal_property_";
+
+// Convert an NPIdentifier (NULL, string or integer) to a V8 value.
+Local<Value> NPToV8Identifier(NPIdentifier np_identifier) {
+ if (np_identifier == NULL) {
+ return Local<Value>();
+ } else if (NPN_IdentifierIsString(np_identifier)) {
+ NPUTF8* utf8_name = NPN_UTF8FromIdentifier(np_identifier);
+ Local<v8::String> v8_identifier = v8::String::New(utf8_name);
+ NPN_MemFree(utf8_name);
+ return v8_identifier;
+ } else {
+ return Integer::New(NPN_IntFromIdentifier(np_identifier));
+ }
+}
+
+// Convert a V8 value (empty, string or integer) into an NPIdentifier.
+NPIdentifier V8ToNPIdentifier(v8::Handle<Value> v8_identifier) {
+ if (v8_identifier.IsEmpty()) {
+ return NULL;
+ } else if (v8_identifier->IsNumber()) {
+ return NPN_GetIntIdentifier(v8_identifier->Int32Value());
+ } else if (v8_identifier->IsString()) {
+ return NPN_GetStringIdentifier(
+ *v8::String::Utf8Value(v8_identifier->ToString()));
+ } else {
+ return NULL;
+ }
+}
+} // namespace anonymous
+
+// The class of NPObject proxies that wrap V8 objects. These field the NPAPI
+// functions and translate them into V8 calls.
+class NPV8Object : public NPObject {
+ public:
+ static NPObjectPtr<NPV8Object> Create(NPV8Bridge* bridge,
+ Local<Object> v8_object) {
+ NPObjectPtr<NPV8Object> np_object =
+ NPObjectPtr<NPV8Object>::AttachToReturned(
+ static_cast<NPV8Object*>(NPN_CreateObject(bridge->npp(),
+ &np_class_)));
+ np_object->v8_object_ = Persistent<Object>::New(v8_object);
+ np_object->bridge_ = bridge;
+ return np_object;
+ }
+
+ v8::Handle<Object> v8_object() const {
+ return v8_object_;
+ }
+
+ // Drop references between NPObject and V8 object. Must be called before the
+ // NPObject is destroyed so V8 can garbage collect the associated V8 object.
+ void UnlinkFromV8() {
+ HandleScope handleScope;
+ if (!v8_object_.IsEmpty()) {
+ v8_object_->DeleteHiddenValue(v8::String::NewSymbol(kInternalProperty));
+ v8_object_.Dispose();
+ v8_object_.Clear();
+ }
+ }
+
+ static NPClass np_class_;
+
+ private:
+ NPV8Object() : bridge_(NULL) {
+ }
+
+ static NPObject* Allocate(NPP npp, NPClass* np_class) {
+ NPV8Object* np_v8_object = new NPV8Object();
+ np_v8_object->bridge_ = NULL;
+ return np_v8_object;
+ }
+
+ static void Deallocate(NPObject* np_object) {
+ NPV8Object* np_v8_object = static_cast<NPV8Object*> (np_object);
+ // Uncomment this line to see objects with a non-zero reference
+ // count being deallocated. For example, Firefox does this when unloading
+ // the plugin.
+ // DCHECK_EQ(0, np_v8_object_map->referenceCount);
+ np_v8_object->UnlinkFromV8();
+ delete np_v8_object;
+ }
+
+ static void Invalidate(NPObject* np_object) {
+ NPV8Object* np_v8_object = static_cast<NPV8Object*> (np_object);
+ np_v8_object->bridge_ = NULL;
+ np_v8_object->UnlinkFromV8();
+ }
+
+ static bool HasMethod(NPObject* np_object, NPIdentifier np_name) {
+ NPV8Object* np_v8_object = static_cast<NPV8Object*> (np_object);
+ NPV8Bridge* bridge = np_v8_object->bridge_;
+ if (bridge == NULL)
+ return false;
+
+ HandleScope handleScope;
+ Context::Scope scope(bridge->script_context());
+ TryCatch tryCatch;
+
+ v8::Handle<Object> v8_object = np_v8_object->v8_object_;
+ if (v8_object.IsEmpty())
+ return false;
+
+ Local<Value> v8_name = NPToV8Identifier(np_name);
+ Local<Value> value = v8_object->Get(v8_name);
+ if (tryCatch.HasCaught()) {
+ bridge->ReportV8Exception(tryCatch);
+ return false;
+ }
+
+ // Returns true iff the object has a property with the given name and
+ // the object assigned to the property is a function. This works for V8
+ // functions and assigned browser JavaScript functions (because their
+ // proxies are created from FunctionTemplates so V8 considers them to be
+ // functions).
+ return !value.IsEmpty() && value->IsFunction();
+ }
+
+ // Called when a method is invoked through "obj.m(...)".
+ static bool Invoke(NPObject* np_object, NPIdentifier np_name,
+ const NPVariant* np_args, uint32_t numArgs,
+ NPVariant* result) {
+ // This works around a bug in Chrome:
+ // http://code.google.com/p/chromium/issues/detail?id=5110
+ // NPN_InvokeDefault is transformed into a call to Invoke on the plugin with
+ // a null method name identifier.
+ if (np_name == NULL) {
+ return InvokeDefault(np_object, np_args, numArgs, result);
+ }
+
+ NPV8Object* np_v8_object = static_cast<NPV8Object*> (np_object);
+ NPV8Bridge* bridge = np_v8_object->bridge_;
+ if (bridge == NULL)
+ return false;
+
+ HandleScope handleScope;
+ Context::Scope scope(bridge->script_context());
+ TryCatch tryCatch;
+
+ v8::Handle<Object> v8_object = np_v8_object->v8_object_;
+ if (v8_object.IsEmpty())
+ return false;
+
+ Local<Value> v8_name = NPToV8Identifier(np_name);
+ Local<Value> value = v8_object->Get(v8_name);
+ if (value.IsEmpty() || !value->IsFunction())
+ return false;
+ Local<Function> function = Local<Function>::Cast(value);
+ std::vector<v8::Handle<Value> > v8_args(numArgs);
+ for (uint32_t i = 0; i != numArgs; ++i) {
+ v8_args[i] = bridge->NPToV8Variant(np_args[i]);
+ }
+
+ *result = bridge->V8ToNPVariant(
+ function->Call(v8_object, numArgs,
+ numArgs == 0 ? NULL : &v8_args.front()));
+ if (tryCatch.HasCaught()) {
+ bridge->ReportV8Exception(tryCatch);
+ return false;
+ }
+ return true;
+ }
+
+ // Called when an object is called as a function "f(...)".
+ static bool InvokeDefault(NPObject* np_object, const NPVariant* np_args,
+ uint32_t numArgs, NPVariant* result) {
+ NPV8Object* np_v8_object = static_cast<NPV8Object*> (np_object);
+ NPV8Bridge* bridge = np_v8_object->bridge_;
+ if (bridge == NULL)
+ return false;
+
+ HandleScope handleScope;
+ Context::Scope scope(bridge->script_context());
+ TryCatch tryCatch;
+
+ v8::Handle<Object> v8_object = np_v8_object->v8_object_;
+ if (v8_object.IsEmpty())
+ return false;
+
+ if (!v8_object->IsFunction())
+ return false;
+ v8::Handle<Function> function = v8::Handle<Function>::Cast(v8_object);
+
+ std::vector<v8::Handle<Value> > v8_args(numArgs);
+ for (uint32_t i = 0; i != numArgs; ++i) {
+ v8_args[i] = bridge->NPToV8Variant(np_args[i]);
+ }
+
+ *result = bridge->V8ToNPVariant(
+ function->Call(v8_object, numArgs,
+ numArgs == 0 ? NULL : &v8_args.front()));
+ if (tryCatch.HasCaught()) {
+ bridge->ReportV8Exception(tryCatch);
+ return false;
+ }
+ return true;
+ }
+
+ // Called when an object is called as a constructor "new C(...)".
+ static bool Construct(NPObject* np_object, const NPVariant* np_args,
+ uint32_t numArgs, NPVariant* result) {
+ NPV8Object* np_v8_object = static_cast<NPV8Object*> (np_object);
+ NPV8Bridge* bridge = np_v8_object->bridge_;
+ if (bridge == NULL)
+ return false;
+
+ HandleScope handleScope;
+ Context::Scope scope(bridge->script_context());
+ TryCatch tryCatch;
+
+ v8::Handle<Object> v8_object = np_v8_object->v8_object_;
+ if (v8_object.IsEmpty())
+ return false;
+
+ if (!v8_object->IsFunction())
+ return false;
+ v8::Handle<Function> function = v8::Handle<Function>::Cast(v8_object);
+
+ std::vector<v8::Handle<Value> > v8_args(numArgs);
+ for (uint32_t i = 0; i != numArgs; ++i) {
+ v8_args[i] = bridge->NPToV8Variant(np_args[i]);
+ }
+
+ Local<Object> v8_result = function->NewInstance(
+ numArgs, numArgs == 0 ? NULL : &v8_args.front());
+ if (v8_result.IsEmpty())
+ return false;
+
+ *result = bridge->V8ToNPVariant(v8_result);
+ if (tryCatch.HasCaught()) {
+ bridge->ReportV8Exception(tryCatch);
+ return false;
+ }
+ return true;
+ }
+
+ static bool HasProperty(NPObject* np_object, NPIdentifier np_name) {
+ NPV8Object* np_v8_object = static_cast<NPV8Object*> (np_object);
+ NPV8Bridge* bridge = np_v8_object->bridge_;
+ if (bridge == NULL)
+ return false;
+
+ HandleScope handleScope;
+ Context::Scope scope(bridge->script_context());
+
+ v8::Handle<Object> v8_object = np_v8_object->v8_object_;
+ if (v8_object.IsEmpty())
+ return false;
+
+ // This is a better approach than the one below. It allows functions
+ // to be retreived as first class objects. Unfortunately we can't
+ // support this yet because of a Chrome bug:
+ // http://code.google.com/p/chromium/issues/detail?id=5742
+ // if (NPN_IdentifierIsString(np_name)) {
+ // Local<v8::String> v8_name = Local<v8::String>::Cast(
+ // NPToV8Identifier(np_name));
+ // return v8_object->Has(v8_name);
+ // } else {
+ // return v8_object->Has(NPN_IntFromIdentifier(np_name));
+ // }
+
+ // Instead hide properties with function type. This ensures that Chrome
+ // will invoke them with Invoke rather than InvokeDefault. The problem
+ // with InvokeDefault is it doesn't tell us what "this" should be
+ // bound to, whereas Invoke does.
+ Local<Value> v8_name = NPToV8Identifier(np_name);
+ if (NPN_IdentifierIsString(np_name)) {
+ if (!v8_object->Has(v8_name->ToString())) {
+ return false;
+ }
+ } else {
+ if (!v8_object->Has(NPN_IntFromIdentifier(np_name))) {
+ return false;
+ }
+ }
+ Local<Value> v8_property_value = v8_object->Get(v8_name);
+ if (v8_property_value->IsFunction()) {
+ return false;
+ }
+
+ return true;
+ }
+
+ static bool GetProperty(NPObject* np_object, NPIdentifier np_name,
+ NPVariant* result) {
+ NPV8Object* np_v8_object = static_cast<NPV8Object*> (np_object);
+ NPV8Bridge* bridge = np_v8_object->bridge_;
+ if (bridge == NULL)
+ return false;
+
+ HandleScope handleScope;
+ Context::Scope scope(bridge->script_context());
+ TryCatch tryCatch;
+
+ v8::Handle<Object> v8_object = np_v8_object->v8_object_;
+ if (v8_object.IsEmpty())
+ return false;
+
+ Local<Value> v8_name = NPToV8Identifier(np_name);
+ Local<Value> v8_property_value = v8_object->Get(v8_name);
+ if (tryCatch.HasCaught()) {
+ bridge->ReportV8Exception(tryCatch);
+ return false;
+ }
+
+ // See comment in HasProperty. Do not return properties that are
+ // functions. It will prevent Chrome from invoking them as methods.
+ if (v8_property_value.IsEmpty() || v8_property_value->IsFunction())
+ return false;
+
+ *result = bridge->V8ToNPVariant(v8_property_value);
+ return true;
+ }
+
+ static bool SetProperty(NPObject* np_object, NPIdentifier np_name,
+ const NPVariant* np_value) {
+ NPV8Object* np_v8_object = static_cast<NPV8Object*> (np_object);
+ NPV8Bridge* bridge = np_v8_object->bridge_;
+ if (bridge == NULL)
+ return false;
+
+ HandleScope handleScope;
+ Context::Scope scope(bridge->script_context());
+ TryCatch tryCatch;
+
+ v8::Handle<Object> v8_object = np_v8_object->v8_object_;
+ if (v8_object.IsEmpty())
+ return false;
+
+ Local<Value> v8_name = NPToV8Identifier(np_name);
+ bool success = v8_object->Set(v8_name, bridge->NPToV8Variant(*np_value));
+
+ if (tryCatch.HasCaught()) {
+ bridge->ReportV8Exception(tryCatch);
+ return false;
+ }
+
+ return success;
+ }
+
+ static bool RemoveProperty(NPObject* np_object, NPIdentifier np_name) {
+ NPV8Object* np_v8_object = static_cast<NPV8Object*> (np_object);
+ NPV8Bridge* bridge = np_v8_object->bridge_;
+ if (bridge == NULL)
+ return false;
+
+ HandleScope handleScope;
+ Context::Scope scope(bridge->script_context());
+ TryCatch tryCatch;
+
+ v8::Handle<Object> v8_object = np_v8_object->v8_object_;
+ if (v8_object.IsEmpty())
+ return false;
+
+ bool success;
+ if (NPN_IdentifierIsString(np_name)) {
+ NPUTF8* utf8_name = NPN_UTF8FromIdentifier(np_name);
+ Local<v8::String> v8_name = v8::String::New(utf8_name);
+ NPN_MemFree(utf8_name);
+ success = v8_object->Delete(v8_name);
+ } else {
+ success = v8_object->Delete(NPN_IntFromIdentifier(np_name));
+ }
+
+ if (tryCatch.HasCaught()) {
+ bridge->ReportV8Exception(tryCatch);
+ return false;
+ }
+
+ return success;
+ }
+
+ static bool Enumerate(NPObject* np_object, NPIdentifier** np_names,
+ uint32_t* numNames) {
+ NPV8Object* np_v8_object = static_cast<NPV8Object*> (np_object);
+ NPV8Bridge* bridge = np_v8_object->bridge_;
+ if (bridge == NULL)
+ return false;
+
+ HandleScope handleScope;
+ Context::Scope scope(bridge->script_context());
+
+ v8::Handle<Object> v8_object = np_v8_object->v8_object_;
+ if (v8_object.IsEmpty())
+ return false;
+
+ Local<Array> v8_names = v8_object->GetPropertyNames();
+
+ // Due to a bug in Chrome, need to filter out any properties that
+ // are functions. See comment in HasProperty.
+ int num_non_function_properties = 0;
+ for (int i = 0; i != v8_names->Length(); ++i) {
+ Local<Value> v8_property_value =
+ v8_object->Get(v8_names->Get(Int32::New(i)));
+ if (!v8_property_value->IsFunction()) {
+ ++num_non_function_properties;
+ }
+ }
+ *numNames = num_non_function_properties;
+ *np_names = static_cast<NPIdentifier*> (
+ NPN_MemAlloc(num_non_function_properties * sizeof(NPIdentifier)));
+ int j = 0;
+ for (uint32_t i = 0; i != v8_names->Length(); ++i) {
+ Local<Value> v8_name = v8_names->Get(Int32::New(i));
+ Local<Value> v8_property_value = v8_object->Get(v8_name);
+ if (!v8_property_value->IsFunction()) {
+ (*np_names)[j++] = V8ToNPIdentifier(v8_name);
+ }
+ }
+
+ return true;
+ }
+
+ NPV8Bridge* bridge_;
+ AutoV8Persistent<Object> v8_object_;
+ DISALLOW_COPY_AND_ASSIGN(NPV8Object);
+};
+
+NPClass NPV8Object::np_class_ = {
+ NP_CLASS_STRUCT_VERSION,
+ Allocate,
+ Deallocate,
+ Invalidate,
+ HasMethod,
+ Invoke,
+ InvokeDefault,
+ HasProperty,
+ GetProperty,
+ SetProperty,
+ RemoveProperty,
+ Enumerate,
+ Construct
+};
+
+NPV8Bridge::NPV8Bridge(ServiceLocator* service_locator, NPP npp)
+ : service_locator_(service_locator),
+ error_status_(service_locator),
+ npp_(npp) {
+ np_name_identifier_ = NPN_GetStringIdentifier("name");
+ np_call_identifier_ = NPN_GetStringIdentifier("call");
+ np_length_identifier_ = NPN_GetStringIdentifier("length");
+ np_proxy_identifier_ = NPN_GetStringIdentifier("npv8_proxy_");
+}
+
+NPV8Bridge::~NPV8Bridge() {
+ // Do not call weak reference callback after the bridge is destroyed
+ // because the callbacks assume it exists. The only purpose of the callback
+ // is to remove the corresponding object entry from the NP-V8 object map
+ // and its about to get cleared anyway.
+ for (NPV8ObjectMap::iterator it = np_v8_object_map_.begin();
+ it != np_v8_object_map_.end(); ++it) {
+ it->second.ClearWeak();
+ }
+}
+
+NPObjectPtr<NPObject> NPV8Bridge::NPEvaluateObject(const char* script) {
+ NPString np_script = { script, strlen(script) };
+ NPVariant np_variant;
+ NPObjectPtr<NPObject> np_result;
+ if (NPN_Evaluate(npp_, global_np_object_.Get(), &np_script, &np_variant)) {
+ if (NPVARIANT_IS_OBJECT(np_variant)) {
+ np_result = NPObjectPtr<NPObject>(NPVARIANT_TO_OBJECT(np_variant));
+ }
+ NPN_ReleaseVariantValue(&np_variant);
+ }
+ return np_result;
+}
+
+namespace {
+// Create code that looks like this:
+// (function(func, protoArray) {
+// return function() {
+// switch (arguments.length) {
+// case 0:
+// return func.call(this);
+// case 1:
+// return func.call(this,
+// arguments[0]);
+// case 2:
+// return func.call(this,
+// arguments[0],
+// arguments[1]);
+// ...
+// default:
+// var args = protoArray.slice();
+// for (var i = 0; i < arguments.length; ++i) {
+// args[i] = arguments[i];
+// }
+// return func.apply(this, args);
+// }
+// };
+// })
+String MakeWrapFunctionScript() {
+ std::ostringstream code;
+ code << "(function(func, protoArray) {";
+ code << " return function() {";
+ code << " switch (arguments.length) {";
+ for (int i = 0; i <= 10; ++i) {
+ code << " case " << i << ": return func.call(this";
+ for (int j = 0; j < i; ++j) {
+ code << ", arguments[" << j << "]";
+ }
+ code << ");";
+ }
+ code << " default:";
+ code << " var args = protoArray.slice();";
+ code << " for (var i = 0; i < arguments.length; ++i) {";
+ code << " args.push(arguments[i]);";
+ code << " }";
+ code << " return func.apply(this, args);";
+ code << " }";
+ code << " };";
+ code << "})";
+ return code.str();
+}
+} // namespace anonymous
+
+void NPV8Bridge::Initialize(const NPObjectPtr<NPObject>& global_np_object) {
+ HandleScope handleScope;
+
+ global_np_object_ = global_np_object;
+
+ // This template is used for V8 proxies of NPObjects.
+ v8_np_constructor_template_ = Persistent<FunctionTemplate>::New(
+ FunctionTemplate::New());
+ InitializeV8ObjectTemplate(v8_np_constructor_template_->InstanceTemplate());
+
+ // This template is used for the global V8 object.
+ Local<FunctionTemplate> v8_global_template = FunctionTemplate::New();
+ InitializeV8ObjectTemplate(v8_global_template->PrototypeTemplate());
+
+ script_context_ = Context::New(NULL, v8_global_template->InstanceTemplate());
+ Context::Scope scope(script_context_);
+
+ // Give the global object a prototype that allows V8 to access global
+ // variables in another JavaScript environemnt over NPAPI.
+ Local<Object> v8_global_prototype =
+ Local<Object>::Cast(script_context_->Global()->GetPrototype());
+ Local<Object> v8_global_prototype2 =
+ Local<Object>::Cast(v8_global_prototype->GetPrototype());
+ global_prototype_ = Persistent<Object>::New(v8_global_prototype2);
+ NPToV8Object(v8_global_prototype2, global_np_object);
+
+ function_map_ = Persistent<Object>::New(Object::New());
+
+ // Create a browser JavaScript function that can later be called to get the
+ // type of an object (as the browser sees it). This is useful for determining
+ // whether an object received over NPAPI is a function (which means its
+ // proxy must be created from a FunctionTemplate rather than an
+ // ObjectTemplate).
+ static const char kIsFunctionScript[] =
+ "(function(obj) { return obj instanceof Function; })";
+ np_is_function_function_ = NPEvaluateObject(kIsFunctionScript);
+
+ // Create a browser JavaScript function that can later be used to enumerate
+ // the properties of an object. This is used as a fallback if NPN_Evaluate
+ // is not implemented by the browser (like Firefox 2) and the enumerate
+ // callback is not implemented by the NPObject.
+ static const char kEnumerateScript[] =
+ "(function(object) {"
+ " var properties = [];"
+ " for (var property in object) {"
+ " if (object.hasOwnProperty(property)) {"
+ " properties[properties.length++] = property;"
+ " }"
+ " }"
+ " return properties;"
+ "})";
+ np_enumerate_function_ = NPEvaluateObject(kEnumerateScript);
+
+ // Create a browser JavaScript function that can later be used to create
+ // a wrapper around an V8 function proxy, making it appear to be a real
+ // browser function.
+ np_wrap_function_function_ = NPEvaluateObject(
+ MakeWrapFunctionScript().c_str());
+
+ // Create an NPObject proxy for a V8 array. This is for the browser to use as
+ // a prototype for creating new V8 arrays with slice().
+ np_empty_array_ = V8ToNPObject(v8::Array::New(0));
+}
+
+void NPV8Bridge::ReleaseNPObjects() {
+ np_v8_object_map_.clear();
+ np_construct_functions_.clear();
+
+ global_np_object_.Clear();
+ np_is_function_function_.Clear();
+ np_enumerate_function_.Clear();
+ np_wrap_function_function_.Clear();
+ np_empty_array_.Clear();
+}
+
+v8::Handle<Context> NPV8Bridge::script_context() {
+ return script_context_;
+}
+
+bool NPV8Bridge::Evaluate(const NPVariant* np_args, int numArgs,
+ NPVariant* np_result) {
+ HandleScope handleScope;
+ Context::Scope scope(script_context_);
+
+ Local<Value> v8_code;
+ if (numArgs == 1) {
+ v8_code = NPToV8Variant(np_args[0]);
+ } else {
+ return false;
+ }
+
+ if (v8_code.IsEmpty() || !v8_code->IsString())
+ return false;
+
+ TryCatch tryCatch;
+
+ Local<Script> v8_script = v8::Script::Compile(v8_code->ToString());
+ if (tryCatch.HasCaught()) {
+ ReportV8Exception(tryCatch);
+ return false;
+ }
+ if (v8_script.IsEmpty())
+ return false;
+
+ Local<Value> v8_result = v8_script->Run();
+ if (tryCatch.HasCaught()) {
+ ReportV8Exception(tryCatch);
+ return false;
+ }
+ if (v8_result.IsEmpty())
+ return false;
+
+ *np_result = V8ToNPVariant(v8_result);
+ return true;
+}
+
+void NPV8Bridge::SetGlobalProperty(const String& name,
+ NPObjectPtr<NPObject>& np_object) {
+ HandleScope handleScope;
+ Context::Scope scope(script_context_);
+ script_context_->Global()->Set(v8::String::New(name.c_str()),
+ NPToV8Object(np_object));
+}
+
+NPVariant NPV8Bridge::V8ToNPVariant(Local<Value> value) {
+ HandleScope handleScope;
+ NPVariant np_variant;
+ if (value.IsEmpty() || value->IsUndefined()) {
+ VOID_TO_NPVARIANT(np_variant);
+ } else if (value->IsNull()) {
+ NULL_TO_NPVARIANT(np_variant);
+ } else if (value->IsBoolean()) {
+ BOOLEAN_TO_NPVARIANT(value->BooleanValue(), np_variant);
+ } else if (value->IsInt32()) {
+ INT32_TO_NPVARIANT(value->Int32Value(), np_variant);
+ } else if (value->IsNumber()) {
+ DOUBLE_TO_NPVARIANT(value->NumberValue(), np_variant);
+ } else if (value->IsString()) {
+ Local<v8::String> v8_string = value->ToString();
+ int utf8_length = v8_string->Length();
+ NPUTF8* utf8_chars = static_cast<NPUTF8*>(NPN_MemAlloc(utf8_length + 1));
+ v8_string->WriteUtf8(utf8_chars);
+ STRINGN_TO_NPVARIANT(utf8_chars, utf8_length, np_variant);
+ } else if (value->IsObject()) {
+ Local<Object> v8_object = value->ToObject();
+ NPObjectPtr<NPObject> np_object = V8ToNPObject(v8_object);
+ OBJECT_TO_NPVARIANT(np_object.Disown(), np_variant);
+ }
+ return np_variant;
+}
+
+Local<Value> NPV8Bridge::NPToV8Variant(const NPVariant& np_variant) {
+ Local<Value> v8_result;
+ switch (np_variant.type) {
+ case NPVariantType_Void:
+ v8_result = Local<Value>::New(Undefined());
+ break;
+ case NPVariantType_Null:
+ v8_result = Local<Value>::New(Null());
+ break;
+ case NPVariantType_Bool:
+ v8_result = Local<Value>::New(
+ v8::Boolean::New(NPVARIANT_TO_BOOLEAN(np_variant)));
+ break;
+ case NPVariantType_Int32:
+ v8_result = Local<Value>::New(
+ Int32::New(NPVARIANT_TO_INT32(np_variant)));
+ break;
+ case NPVariantType_Double:
+ v8_result = Local<Value>::New(
+ Number::New(NPVARIANT_TO_DOUBLE(np_variant)));
+ break;
+ case NPVariantType_String:
+ {
+ NPString np_string = NPVARIANT_TO_STRING(np_variant);
+ v8_result = Local<Value>::New(
+ v8::String::New(np_string.utf8characters, np_string.utf8length));
+ break;
+ }
+ case NPVariantType_Object:
+ v8_result = NPToV8Object(
+ NPObjectPtr<NPObject>(NPVARIANT_TO_OBJECT(np_variant)));
+ break;
+ default:
+ v8_result = Local<Value>();
+ break;
+ }
+ return v8_result;
+}
+
+NPObjectPtr<NPObject> NPV8Bridge::V8ToNPObject(Local<Value> v8_value) {
+ HandleScope handleScope;
+ NPObjectPtr<NPObject> np_object;
+ if (!v8_value.IsEmpty() && v8_value->IsObject()) {
+ Local<Object> v8_object = Local<Object>::Cast(v8_value);
+ if (v8_object->InternalFieldCount() == 0) {
+ // It is must be a V8 created JavaScript object (or function), a V8
+ // function proxy for an NP function or a V8 function proxy for a named
+ // native method. If it is already associated with an NP object then that
+ // will be stored in the "internal property". Return that if it's there,
+ // otherwise create a new NP proxy.
+ Local<v8::String> internal_name = v8::String::NewSymbol(
+ kInternalProperty);
+ Local<Value> v8_internal = v8_object->GetHiddenValue(internal_name);
+
+ if (v8_internal.IsEmpty() || v8_internal->IsUndefined()) {
+ // No existing NP object so create a proxy and store it in the "internal
+ // property".
+ np_object = NPV8Object::Create(this, v8_object);
+ v8_internal = External::New(np_object.Get());
+ v8_object->SetHiddenValue(internal_name, v8_internal);
+ } else {
+ np_object = NPObjectPtr<NPObject>(
+ static_cast<NPObject*>(
+ Local<External>::Cast(v8_internal)->Value()));
+ }
+
+ // If it is a V8 function then wrap it in a browser function so that its
+ // typeof will be reported as 'function' in the browser and it can be
+ // used in cases where a real function is required (rather than an
+ // object that just happens to be invocable.
+ if (v8_value->IsFunction() &&
+ np_object->_class == &NPV8Object::np_class_) {
+ np_object = WrapV8Function(np_object);
+ }
+ } else {
+ // This is a V8 object proxy. The NP object is referenced from an internal
+ // field.
+ Local<Value> internal = v8_object->GetInternalField(
+ V8_NP_OBJECT_WRAPPED);
+ np_object = NPObjectPtr<NPObject>(
+ static_cast<NPObject*>(Local<External>::Cast(internal)->Value()));
+ }
+ }
+ return np_object;
+}
+
+// Wrap NPV8Object proxying a V8 function in a browser function so that its
+// typeof will be reported as 'function' in the browser and it can be
+// used in cases where a real function is required (rather than an
+// object that just happens to be invocable.
+// A new wrapper function is created whenever a V8 function crosses into the
+// browser. So === won't do the right thing in the browser.
+NPObjectPtr<NPObject> NPV8Bridge::WrapV8Function(
+ const NPObjectPtr<NPObject>& np_object) {
+
+ NPObjectPtr<NPObject> np_result = np_object;
+ NPVariant np_args[2];
+ OBJECT_TO_NPVARIANT(np_object.Get(), np_args[0]);
+ OBJECT_TO_NPVARIANT(np_empty_array_.Get(), np_args[1]);
+ NPVariant np_variant;
+ if (NPN_InvokeDefault(npp_, np_wrap_function_function_.Get(),
+ np_args, 2, &np_variant)) {
+ if (NPVARIANT_IS_OBJECT(np_variant)) {
+ NPObjectPtr<NPObject> np_wrapper(NPVARIANT_TO_OBJECT(np_variant));
+
+ // Add a reference back to the NPV8Object so we can find it again.
+ if (NPN_SetProperty(npp_, np_wrapper.Get(), np_proxy_identifier_,
+ &np_args[0])) {
+ np_result = np_wrapper;
+ }
+ }
+ NPN_ReleaseVariantValue(&np_variant);
+ }
+ return np_result;
+}
+
+Local<Value> NPV8Bridge::NPToV8Object(const NPObjectPtr<NPObject>& np_object) {
+ if (np_object.IsNull())
+ return Local<Value>::New(Null());
+
+ // This might be a wrapper for a function. Find the actual proxy in that
+ // case.
+ NPObjectPtr<NPObject> np_real_object = np_object;
+ {
+ // NPN_GetProperty might cause an O3D NPObject to set an error if the
+ // property does not exist. Prevent that. It would be better to simply
+ // test whether the property exists by calling NPN_HasProperty but that
+ // is not supported in Mac Safari.
+ ErrorSuppressor error_suppressor(service_locator_);
+ NPVariant np_variant;
+ if (NPN_GetProperty(npp_, np_real_object.Get(), np_proxy_identifier_,
+ &np_variant)) {
+ if (NPVARIANT_IS_OBJECT(np_variant)) {
+ np_real_object = NPVARIANT_TO_OBJECT(np_variant);
+ }
+ NPN_ReleaseVariantValue(&np_variant);
+ }
+ }
+
+ if (np_real_object->_class == &NPV8Object::np_class_) {
+ NPV8Object* np_v8_object = static_cast<NPV8Object*>(np_real_object.Get());
+ return Local<Object>::New(np_v8_object->v8_object());
+ } else {
+ NPV8ObjectMap::const_iterator it = np_v8_object_map_.find(np_real_object);
+ if (it != np_v8_object_map_.end())
+ return Local<Object>::New(it->second);
+
+ if (IsNPFunction(np_real_object)) {
+ return NPToV8Function(np_real_object);
+ } else {
+ Local<Function> v8_function = v8_np_constructor_template_->GetFunction();
+ Local<Object> v8_object = v8_function->NewInstance();
+ if (!v8_object.IsEmpty()) {
+ // NewInstance sets a JavaScript exception if it fails. Eventually
+ // it'll be caught when control flow hits a TryCatch. Just make sure
+ // not to dereference it before then.
+ NPToV8Object(v8_object, np_real_object);
+ }
+ return v8_object;
+ }
+ }
+}
+
+void NPV8Bridge::NPToV8Object(v8::Local<Object> v8_target,
+ const NPObjectPtr<NPObject>& np_object) {
+ v8_target->SetInternalField(V8_NP_OBJECT_BRIDGE, External::New(this));
+ v8_target->SetInternalField(V8_NP_OBJECT_WRAPPED,
+ External::New(np_object.Get()));
+ RegisterV8Object(v8_target, np_object);
+}
+
+bool NPV8Bridge::IsNPFunction(const NPObjectPtr<NPObject>& np_object) {
+ // Before invoking the potentially expensive instanceof function (it has to
+ // go through the browser) check whether the object has a call
+ // property. If it doesn't have one then it isn't a JavaScript
+ // function.
+ if (!NPN_HasProperty(npp_, np_object.Get(), np_call_identifier_)) {
+ return false;
+ }
+
+ // If it looks like it might be a function then call the instanceof function
+ // in the browser to confirm.
+ bool is_function = false;
+ NPVariant np_object_variant;
+ OBJECT_TO_NPVARIANT(np_object.Get(), np_object_variant);
+ NPVariant np_is_function;
+ if (NPN_InvokeDefault(npp_, np_is_function_function_.Get(),
+ &np_object_variant, 1, &np_is_function)) {
+ if (NPVARIANT_IS_BOOLEAN(np_is_function)) {
+ is_function = NPVARIANT_TO_BOOLEAN(np_is_function);
+ }
+ NPN_ReleaseVariantValue(&np_is_function);
+ }
+ return is_function;
+}
+
+v8::Local<v8::Function> NPV8Bridge::NPToV8Function(
+ const NPObjectPtr<NPObject>& np_function) {
+ Local<FunctionTemplate> v8_function_template = FunctionTemplate::New(
+ V8CallFunction, External::New(this));
+
+ Local<Function> v8_function = v8_function_template->GetFunction();
+
+ Local<v8::String> internal_name = v8::String::NewSymbol(
+ kInternalProperty);
+ v8_function->SetHiddenValue(internal_name, External::New(np_function.Get()));
+
+ // Copy function name from NP function.
+ NPVariant np_name;
+ if (NPN_GetProperty(npp_, np_function.Get(), np_name_identifier_, &np_name)) {
+ Local<Value> v8_name_value = NPToV8Variant(np_name);
+ NPN_ReleaseVariantValue(&np_name);
+ if (!v8_name_value.IsEmpty() && v8_name_value->IsString()) {
+ Local<v8::String> v8_name = Local<v8::String>::Cast(v8_name_value);
+ v8_function->SetName(v8_name);
+ }
+ }
+
+ RegisterV8Object(v8_function, np_function);
+ return v8_function;
+}
+
+void NPV8Bridge::RegisterV8Object(v8::Local<v8::Object> v8_object,
+ const NPObjectPtr<NPObject>& np_object) {
+ np_v8_object_map_[np_object] = Persistent<Object>::New(v8_object);
+ np_v8_object_map_[np_object].MakeWeak(this, NPV8WeakReferenceCallback);
+}
+
+bool NPV8Bridge::IsNPObjectReferenced(NPObjectPtr<NPObject> np_object) {
+ return np_v8_object_map_.find(np_object) != np_v8_object_map_.end();
+}
+
+void NPV8Bridge::InitializeV8ObjectTemplate(
+ Local<ObjectTemplate> v8_object_template) {
+ v8_object_template->SetInternalFieldCount(
+ V8_NP_OBJECT_NUM_INTERNAL_FIELDS);
+ v8_object_template->SetNamedPropertyHandler(V8NamedPropertyGetter,
+ V8NamedPropertySetter,
+ V8NamedPropertyQuery,
+ V8NamedPropertyDeleter,
+ V8NamedPropertyEnumerator);
+ v8_object_template->SetIndexedPropertyHandler(V8IndexedPropertyGetter,
+ V8IndexedPropertySetter,
+ V8IndexedPropertyQuery,
+ V8IndexedPropertyDeleter,
+ V8IndexedPropertyEnumerator);
+ v8_object_template->SetCallAsFunctionHandler(V8CallAsFunction);
+}
+
+void NPV8Bridge::NPV8WeakReferenceCallback(Persistent<Value> v8_value,
+ void* parameter) {
+ HandleScope handleScope;
+ NPV8Bridge* bridge = static_cast<NPV8Bridge*>(parameter);
+ NPObjectPtr<NPObject> np_object = bridge->V8ToNPObject(
+ Local<Value>::New(v8_value));
+ bridge->np_v8_object_map_.erase(np_object);
+}
+
+void NPV8Bridge::ReportV8Exception(const TryCatch& v8_try_catch) {
+ if (v8_try_catch.HasCaught()) {
+ Local<Message> v8_message = v8_try_catch.Message();
+ if (v8_message.IsEmpty()) {
+ Local<Value> v8_exception = v8_try_catch.Exception();
+ if (v8_exception.IsEmpty()) {
+ error_status_->SetLastError(
+ "An unknown exception ocurred while executing V8 JavaScript code");
+ } else {
+ v8::String::Utf8Value as_utf8(v8_exception);
+ if (*as_utf8) {
+ error_status_->SetLastError(*as_utf8);
+ } else {
+ error_status_->SetLastError(
+ "An exception was thrown but its toString method failed");
+ }
+ }
+ } else {
+ String source_line(*v8::String::Utf8Value(v8_message->GetSourceLine()));
+ String text(*v8::String::Utf8Value(v8_message->Get()));
+ String message = text + " in " + source_line;
+ error_status_->SetLastError(message);
+ }
+ }
+}
+
+v8::Local<v8::Array> NPV8Bridge::NPToV8IdentifierArray(
+ const NPVariant& np_array, bool named) {
+ Local<Array> v8_array;
+ if (!NPVARIANT_IS_OBJECT(np_array))
+ return v8_array;
+
+ NPObject* np_array_object = NPVARIANT_TO_OBJECT(np_array);
+ NPVariant np_length;
+ if (NPN_GetProperty(npp_, np_array_object, np_length_identifier_,
+ &np_length)) {
+ Local<Value> v8_length = NPToV8Variant(np_length);
+ NPN_ReleaseVariantValue(&np_length);
+
+ if (v8_length.IsEmpty() || !v8_length->IsNumber())
+ return v8_array;
+
+ v8_array = Array::New();
+ int length = v8_length->Int32Value();
+ for (int i = 0; i < length; ++i) {
+ NPVariant np_element;
+ if (!NPN_GetProperty(npp_, np_array_object, NPN_GetIntIdentifier(i),
+ &np_element))
+ return Local<Array>();
+ Local<Value> v8_element = NPToV8Variant(np_element);
+ NPN_ReleaseVariantValue(&np_element);
+ if (v8_element->IsString() == named) {
+ v8_array->Set(Int32::New(v8_array->Length()), v8_element);
+ }
+ }
+ }
+
+ return v8_array;
+}
+
+Local<Array> NPV8Bridge::NPToV8IdentifierArray(const NPIdentifier* ids,
+ uint32_t id_count, bool named) {
+ Local<Array> v8_array = Array::New();
+ for (uint32_t i = 0; i < id_count; ++i) {
+ if (NPN_IdentifierIsString(ids[i]) == named) {
+ v8_array->Set(Int32::New(v8_array->Length()), NPToV8Identifier(ids[i]));
+ }
+ }
+ return v8_array;
+}
+
+Local<Array> NPV8Bridge::Enumerate(const NPObjectPtr<NPObject> np_object,
+ bool named) {
+ Local<Array> v8_array;
+ HandleScope handleScope;
+
+ // First try calling NPN_Enumerate. This will return false if the browser
+ // does not support NPN_Enumerate.
+ NPIdentifier* ids;
+ uint32_t id_count;
+ if (NPN_Enumerate(npp_, np_object.Get(), &ids, &id_count)) {
+ v8_array = NPToV8IdentifierArray(ids, id_count, named);
+ NPN_MemFree(ids);
+ } else if (np_object->_class->structVersion >= NP_CLASS_STRUCT_VERSION_ENUM &&
+ np_object->_class->enumerate != NULL &&
+ np_object->_class->enumerate(np_object.Get(), &ids, &id_count)) {
+ // Next see if the object has an enumerate callback and invoke it
+ // directly. This is the path used when V8 enumerates the
+ // properties of a native object if the browser does not support
+ // NPN_Enumerate.
+ v8_array = NPToV8IdentifierArray(ids, id_count, named);
+ NPN_MemFree(ids);
+ } else {
+ // The final fallback is to invoke a JavaScript function that
+ // enumerates all the properties into an array and returns it to
+ // the plugin.
+ NPVariant np_result;
+ NPVariant np_arg;
+ OBJECT_TO_NPVARIANT(np_object.Get(), np_arg);
+ if (NPN_InvokeDefault(npp_, np_enumerate_function_.Get(), &np_arg, 1,
+ &np_result)) {
+ v8_array = NPToV8IdentifierArray(np_result, named);
+ NPN_ReleaseVariantValue(&np_result);
+ }
+ }
+
+ return v8_array;
+}
+
+v8::Handle<Value> NPV8Bridge::V8PropertyGetter(Local<Value> v8_name,
+ const AccessorInfo& info) {
+ Local<Value> v8_result;
+ HandleScope handleScope;
+
+ Local<Object> holder = info.Holder();
+ NPV8Bridge* bridge = static_cast<NPV8Bridge*>(
+ Local<External>::Cast(
+ holder->GetInternalField(V8_NP_OBJECT_BRIDGE))->Value());
+ Context::Scope scope(bridge->script_context());
+
+ if (holder.IsEmpty())
+ return v8_result;
+
+ NPObjectPtr<NPObject> np_object = bridge->V8ToNPObject(holder);
+ if (np_object.IsNull())
+ return v8_result;
+
+ NPIdentifier np_name = V8ToNPIdentifier(v8_name);
+ if (np_name == NULL)
+ return v8_result;
+
+ NPVariant np_result;
+ if (NPN_HasProperty(bridge->npp_, np_object.Get(), np_name) &&
+ NPN_GetProperty(bridge->npp_, np_object.Get(), np_name, &np_result)) {
+ v8_result = bridge->NPToV8Variant(np_result);
+ NPN_ReleaseVariantValue(&np_result);
+ } else if (np_object->_class->hasMethod != NULL &&
+ np_object->_class->hasMethod(np_object.Get(), np_name)) {
+ // It's not calling NPN_HasMethod here because of a bug in Firefox
+ // (Mozilla bug ID 467945), where NPN_HasMethod forwards to the object's
+ // hasProperty function instead. The workaround is to sidestep npruntime.
+ v8_result = bridge->function_map_->Get(v8_name);
+ if (v8_result.IsEmpty() || v8_result->IsUndefined()) {
+ Local<FunctionTemplate> function_template =
+ FunctionTemplate::New(V8CallNamedMethod, v8_name);
+ v8_result = function_template->GetFunction();
+ bridge->function_map_->Set(v8_name, v8_result);
+ }
+ }
+
+ return v8_result;
+}
+
+v8::Handle<Value> NPV8Bridge::V8PropertySetter(
+ Local<Value> v8_name,
+ Local<Value> v8_value,
+ const AccessorInfo& info) {
+ Local<Value> v8_result;
+ HandleScope handleScope;
+
+ Local<Object> holder = info.Holder();
+ NPV8Bridge* bridge = static_cast<NPV8Bridge*>(
+ Local<External>::Cast(
+ holder->GetInternalField(V8_NP_OBJECT_BRIDGE))->Value());
+ Context::Scope scope(bridge->script_context());
+
+ NPObjectPtr<NPObject> np_object = bridge->V8ToNPObject(holder);
+ if (np_object.IsNull())
+ return v8_result;
+
+ NPIdentifier np_name = V8ToNPIdentifier(v8_name);
+ if (np_name == NULL)
+ return v8_result;
+
+ NPVariant np_value = bridge->V8ToNPVariant(v8_value);
+ NPN_SetProperty(bridge->npp_, np_object.Get(), np_name, &np_value);
+ NPN_ReleaseVariantValue(&np_value);
+
+ return v8_result;
+}
+
+v8::Handle<v8::Boolean> NPV8Bridge::V8PropertyQuery(Local<Value> v8_name,
+ const AccessorInfo& info) {
+ HandleScope handleScope;
+
+ Local<Object> holder = info.Holder();
+ NPV8Bridge* bridge = static_cast<NPV8Bridge*>(
+ Local<External>::Cast(
+ holder->GetInternalField(V8_NP_OBJECT_BRIDGE))->Value());
+ Context::Scope scope(bridge->script_context());
+
+ NPObjectPtr<NPObject> np_object = bridge->V8ToNPObject(holder);
+ if (np_object.IsNull())
+ return v8::Handle<v8::Boolean>();
+
+ NPIdentifier np_name = V8ToNPIdentifier(v8_name);
+ if (np_name == NULL)
+ return v8::Handle<v8::Boolean>();
+
+ bool has = NPN_HasProperty(bridge->npp_, np_object.Get(), np_name) ||
+ NPN_HasMethod(bridge->npp_, np_object.Get(), np_name);
+ return v8::Boolean::New(has);
+}
+
+v8::Handle<v8::Boolean> NPV8Bridge::V8PropertyDeleter(
+ Local<Value> v8_name,
+ const AccessorInfo& info) {
+ HandleScope handleScope;
+
+ Local<Object> holder = info.Holder();
+ NPV8Bridge* bridge = static_cast<NPV8Bridge*>(
+ Local<External>::Cast(
+ holder->GetInternalField(V8_NP_OBJECT_BRIDGE))->Value());
+ Context::Scope scope(bridge->script_context());
+
+ NPObjectPtr<NPObject> np_object = bridge->V8ToNPObject(holder);
+ if (np_object.IsNull())
+ return v8::Handle<v8::Boolean>();
+
+ NPIdentifier np_name = V8ToNPIdentifier(v8_name);
+ if (np_name == NULL)
+ return v8::Handle<v8::Boolean>();
+
+ // Workaround for a bug in Chrome. Chrome does not check whether the
+ // removeProperty callback is implemented before calling it, causing
+ // NPN_RemoveProperty to crash if it is not. So do the check before calling
+ // it.
+ bool deleted = np_object->_class->removeProperty != NULL &&
+ NPN_RemoveProperty(bridge->npp_, np_object.Get(), np_name);
+ return v8::Boolean::New(deleted);
+}
+
+v8::Handle<Value> NPV8Bridge::V8NamedPropertyGetter(Local<v8::String> v8_name,
+ const AccessorInfo& info) {
+ return V8PropertyGetter(v8_name, info);
+}
+
+v8::Handle<Value> NPV8Bridge::V8NamedPropertySetter(Local<v8::String> v8_name,
+ Local<Value> v8_value,
+ const AccessorInfo& info) {
+ return V8PropertySetter(v8_name, v8_value, info);
+}
+
+v8::Handle<v8::Boolean> NPV8Bridge::V8NamedPropertyQuery(
+ Local<v8::String> v8_name,
+ const AccessorInfo& info) {
+ return V8PropertyQuery(v8_name, info);
+}
+
+v8::Handle<v8::Boolean> NPV8Bridge::V8NamedPropertyDeleter(
+ Local<v8::String> v8_name,
+ const AccessorInfo& info) {
+ return V8PropertyDeleter(v8_name, info);
+}
+
+v8::Handle<Array> NPV8Bridge::V8NamedPropertyEnumerator(
+ const AccessorInfo& info) {
+ HandleScope handleScope;
+
+ Local<Object> holder = info.Holder();
+ NPV8Bridge* bridge = static_cast<NPV8Bridge*>(
+ Local<External>::Cast(
+ holder->GetInternalField(V8_NP_OBJECT_BRIDGE))->Value());
+ Context::Scope scope(bridge->script_context());
+
+ NPObjectPtr<NPObject> np_object = bridge->V8ToNPObject(holder);
+ if (np_object.IsNull())
+ return v8::Handle<Array>();
+
+ return bridge->Enumerate(np_object, true);
+}
+
+v8::Handle<Value> NPV8Bridge::V8IndexedPropertyGetter(
+ uint32_t index,
+ const AccessorInfo& info) {
+ return V8PropertyGetter(Integer::New(index), info);
+}
+
+v8::Handle<Value> NPV8Bridge::V8IndexedPropertySetter(
+ uint32_t index,
+ Local<Value> v8_value,
+ const AccessorInfo& info) {
+ return V8PropertySetter(Integer::New(index), v8_value, info);
+}
+
+v8::Handle<v8::Boolean> NPV8Bridge::V8IndexedPropertyQuery(
+ uint32_t index,
+ const AccessorInfo& info) {
+ return V8PropertyQuery(Integer::New(index), info);
+}
+
+v8::Handle<v8::Boolean> NPV8Bridge::V8IndexedPropertyDeleter(
+ uint32_t index,
+ const AccessorInfo& info) {
+ return V8PropertyDeleter(Integer::New(index), info);
+}
+
+v8::Handle<Array> NPV8Bridge::V8IndexedPropertyEnumerator(
+ const AccessorInfo& info) {
+ HandleScope handleScope;
+
+ Local<Object> holder = info.Holder();
+ NPV8Bridge* bridge = static_cast<NPV8Bridge*>(
+ Local<External>::Cast(
+ holder->GetInternalField(V8_NP_OBJECT_BRIDGE))->Value());
+ Context::Scope scope(bridge->script_context());
+
+ NPObjectPtr<NPObject> np_object = bridge->V8ToNPObject(holder);
+ if (np_object.IsNull())
+ return v8::Handle<Array>();
+
+ return bridge->Enumerate(np_object, false);
+}
+
+v8::Handle<Value> NPV8Bridge::V8CallNamedMethod(const Arguments& args) {
+ Local<Value> v8_result;
+ HandleScope handleScope;
+
+ if (args.IsConstructCall())
+ return v8_result;
+
+ Local<Object> v8_holder = args.Holder();
+ NPV8Bridge* bridge = static_cast<NPV8Bridge*>(
+ Local<External>::Cast(
+ v8_holder->GetInternalField(V8_NP_OBJECT_BRIDGE))->Value());
+ Context::Scope scope(bridge->script_context());
+
+ NPObjectPtr<NPObject> np_this = bridge->V8ToNPObject(v8_holder);
+ if (np_this.IsNull())
+ return v8_result;
+
+ v8::Handle<Value> v8_name = args.Data();
+ NPIdentifier np_name = V8ToNPIdentifier(v8_name);
+ if (np_name == NULL)
+ return v8_result;
+
+ std::vector<NPVariant> np_args(args.Length());
+ for (int i = 0; i != args.Length(); ++i) {
+ np_args[i] = bridge->V8ToNPVariant(args[i]);
+ }
+
+ NPVariant np_result;
+ if (NPN_Invoke(bridge->npp_,
+ np_this.Get(),
+ np_name,
+ args.Length() == 0 ? NULL : &np_args.front(),
+ args.Length(),
+ &np_result)) {
+ v8_result = bridge->NPToV8Variant(np_result);
+ NPN_ReleaseVariantValue(&np_result);
+ }
+
+ for (int i = 0; i != args.Length(); ++i) {
+ NPN_ReleaseVariantValue(&np_args[i]);
+ }
+
+ return v8_result;
+}
+
+v8::Handle<Value> NPV8Bridge::V8CallFunction(const Arguments& args) {
+ Local<Value> v8_result;
+ HandleScope handleScope;
+
+ NPV8Bridge* bridge = static_cast<NPV8Bridge*>(
+ Local<External>::Cast(args.Data())->Value());
+ Context::Scope scope(bridge->script_context());
+
+ Local<Function> v8_callee = args.Callee();
+ Local<Object> v8_this = args.This();
+
+ // Allocate an extra argument element for the "this" pointer. This is only
+ // used if we end up invoking a method through function.call(this, arg0, ...,
+ // argn).
+ std::vector<NPVariant> np_args(args.Length() + 1);
+ VOID_TO_NPVARIANT(np_args[0]);
+ for (int i = 0; i != args.Length(); ++i) {
+ np_args[i + 1] = bridge->V8ToNPVariant(args[i]);
+ }
+
+ // Need to determine whether the object was called as a standalone function,
+ // a method or a constructor. The constructor case is easy: args has a flag
+ // for it. If the function was called standalone then "this" will reference
+ // the global object. Otherwise assume it is a method invocation.
+ NPVariant np_result;
+ if (args.IsConstructCall()) {
+ // NPN_Construct was giving me trouble on some browsers (like Chrome). It
+ // might have better support in the future. For the time being, I'm using
+ // this alternative.
+ NPObjectPtr<NPObject> np_construct_function =
+ bridge->GetNPConstructFunction(args.Length());
+ np_args[0] = bridge->V8ToNPVariant(v8_callee);
+ if (NPN_InvokeDefault(bridge->npp_, np_construct_function.Get(),
+ &np_args[0], args.Length() + 1, &np_result)) {
+ v8_result = bridge->NPToV8Variant(np_result);
+ NPN_ReleaseVariantValue(&np_result);
+ }
+ } else if (v8_this == bridge->script_context_->Global()) {
+ // Treat standalone case specially. We use NPN_InvokeDefault rather than
+ // NPN_Invoke with the "call" method because we want to have "this" refer
+ // to the browser's global environment rather than the V8 global
+ // environment.
+ NPObjectPtr<NPObject> np_callee = bridge->V8ToNPObject(v8_callee);
+ if (NPN_InvokeDefault(bridge->npp_, np_callee.Get(), 1 + &np_args[0],
+ args.Length(), &np_result)) {
+ v8_result = bridge->NPToV8Variant(np_result);
+ NPN_ReleaseVariantValue(&np_result);
+ }
+ } else {
+ // Invoke a function as a method by invoking its "call" call method. This
+ // is not the usual way of invoking a method in runtime. The usual way would
+ // to be to call NPN_Invoke on the target object (the one to be bound to
+ // "this") with a method name. But we don't know the method name. We don't
+ // even know if the function is assigned to one of the properties of the
+ // target object. To avoid that trouble, we invoke the function's "call"
+ // method with "this" as an explicit argument.
+ NPObjectPtr<NPObject> np_callee = bridge->V8ToNPObject(v8_callee);
+ np_args[0] = bridge->V8ToNPVariant(v8_this);
+ if (NPN_Invoke(bridge->npp_, np_callee.Get(), bridge->np_call_identifier_,
+ &np_args[0], args.Length() + 1, &np_result)) {
+ v8_result = bridge->NPToV8Variant(np_result);
+ NPN_ReleaseVariantValue(&np_result);
+ }
+ }
+
+ for (int i = 0; i != args.Length() + 1; ++i) {
+ NPN_ReleaseVariantValue(&np_args[i]);
+ }
+
+ return v8_result;
+}
+
+v8::Handle<Value> NPV8Bridge::V8CallAsFunction(const Arguments& args) {
+ Local<Value> v8_result;
+ HandleScope handleScope;
+
+ Local<Object> v8_callee = args.This();
+ NPV8Bridge* bridge = static_cast<NPV8Bridge*>(
+ Local<External>::Cast(
+ v8_callee->GetInternalField(V8_NP_OBJECT_BRIDGE))->Value());
+ Context::Scope scope(bridge->script_context());
+
+ std::vector<NPVariant> np_args(args.Length());
+ for (int i = 0; i != args.Length(); ++i) {
+ np_args[i] = bridge->V8ToNPVariant(args[i]);
+ }
+
+ NPVariant np_result;
+ NPObjectPtr<NPObject> np_callee = bridge->V8ToNPObject(v8_callee);
+ if (NPN_InvokeDefault(bridge->npp_, np_callee.Get(),
+ args.Length() == 0 ? NULL : &np_args[0], args.Length(),
+ &np_result)) {
+ v8_result = bridge->NPToV8Variant(np_result);
+ NPN_ReleaseVariantValue(&np_result);
+ }
+
+ for (int i = 0; i != args.Length(); ++i) {
+ NPN_ReleaseVariantValue(&np_args[i]);
+ }
+
+ return v8_result;
+}
+
+// Evaluates and returns an NP function that will construct an object. The
+// function takes the constructor and constructor arguments as arguments.
+// I'm doing this because not all browsers seem to support calling NPN_Construct
+// on JavaScript constructor functions.
+NPObjectPtr<NPObject> NPV8Bridge::GetNPConstructFunction(int arity) {
+ NPConstructFunctionMap::const_iterator it = np_construct_functions_.find(
+ arity);
+ if (it != np_construct_functions_.end())
+ return it->second;
+
+ // Build a function that looks like:
+ // (function (c,p0,p1) { return new c(p0,p1); })
+ std::ostringstream code;
+ code << "(function(c";
+ for (int i = 0; i != arity; ++i) {
+ code << ",p" << i;
+ }
+ code << ") { return new c(";
+ String separator = "";
+ for (int i = 0; i != arity; ++i) {
+ code << separator << String("p") << i;
+ separator = ",";
+ }
+ code << "); })";
+
+ return NPEvaluateObject(code.str().c_str());
+}
+} // namespace o3d
diff --git a/o3d/plugin/cross/np_v8_bridge.h b/o3d/plugin/cross/np_v8_bridge.h
new file mode 100644
index 0000000..779a5a3
--- /dev/null
+++ b/o3d/plugin/cross/np_v8_bridge.h
@@ -0,0 +1,400 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// Code relating to interoperation of V8 JavaScript engine with NPAPI.
+
+#ifndef O3D_PLUGIN_CROSS_NP_V8_BRIDGE_H_
+#define O3D_PLUGIN_CROSS_NP_V8_BRIDGE_H_
+
+#include <npapi.h>
+#include <npruntime.h>
+#include <map>
+
+#include "base/cross/std_hash.h"
+#include "core/cross/error_status.h"
+#include "core/cross/service_dependency.h"
+#include "core/cross/types.h"
+
+// The XLib header files define these preprocessor macros which v8 uses as
+// identifiers. Need to undefine them before including v8.
+#ifdef None
+#undef None
+#endif
+
+#ifdef True
+#undef True
+#endif
+
+#ifdef False
+#undef False
+#endif
+
+#ifdef Value
+#undef Value
+#endif
+
+#include "third_party/v8/include/v8.h"
+
+namespace o3d {
+
+// Smart pointer for NPObjects that automatically retains and releases the
+// reference count.
+template <typename T>
+class NPObjectPtr {
+ public:
+ NPObjectPtr()
+ : owned(true),
+ object_(NULL) {
+ }
+
+ template <typename U>
+ explicit NPObjectPtr(U* object)
+ : object_(object) {
+ Retain();
+ }
+
+ NPObjectPtr(const NPObjectPtr& rhs)
+ : object_(rhs.object_) {
+ Retain();
+ }
+
+ template <typename U>
+ explicit NPObjectPtr(const NPObjectPtr<U>& rhs)
+ : object_(rhs.Get()) {
+ Retain();
+ }
+
+ ~NPObjectPtr() {
+ Release();
+ }
+
+ template <typename U>
+ NPObjectPtr& operator=(U* rhs) {
+ Release();
+ object_ = rhs;
+ Retain();
+ return *this;
+ }
+
+ NPObjectPtr& operator=(const NPObjectPtr& rhs) {
+ Release();
+ object_ = rhs.object_;
+ Retain();
+ return *this;
+ }
+
+ template <typename U>
+ NPObjectPtr& operator=(const NPObjectPtr<U>& rhs) {
+ Release();
+ object_ = rhs.Get();
+ Retain();
+ return *this;
+ }
+
+ bool operator<(const NPObjectPtr& rhs) const {
+ return object_ < rhs.object_;
+ }
+
+ bool operator==(const NPObjectPtr& rhs) const {
+ return object_ == rhs.object_;
+ }
+
+ T* operator->() const {
+ return object_;
+ }
+
+ T* Get() const {
+ return object_;
+ }
+
+ bool IsNull() const {
+ return object_ == NULL;
+ }
+
+ void Clear() {
+ Release();
+ object_ = NULL;
+ }
+
+ // Does not increment the reference count. When a function returns a pointer
+ // to an NPObject, the rule is that its reference count has already been
+ // incremented on behalf of the caller.
+ static NPObjectPtr AttachToReturned(T* object) {
+ NPObjectPtr result(object);
+ result.Release();
+ return result;
+ }
+
+ // Calling this prevents the NPObject's reference count from being decremented
+ // by this smart pointer when it is destroyed or a new reference is assigned.
+ T* Disown() const {
+ owned = false;
+ return object_;
+ }
+
+ private:
+ void Retain() {
+ owned = true;
+ if (object_ != NULL) {
+ NPN_RetainObject(object_);
+ }
+ }
+
+ void Release() {
+ if (owned && object_ != NULL) {
+ NPN_ReleaseObject(object_);
+ }
+ }
+
+ mutable bool owned;
+ T* object_;
+};
+
+// Hashes an NPObject so it can be used in a hash_map.
+template <typename T>
+class NPObjectPtrHash {
+ public:
+ size_t operator() (const NPObjectPtr<T>& ptr) const {
+ return o3d::base::hash<size_t>()(reinterpret_cast<size_t>(ptr.Get()));
+ }
+};
+
+// A V8 handle that automatically disposes itself when it is destroyed. There
+// must be only one of these for each persistent handle, otherwise they might
+// be disposed more than once.
+template <typename T>
+class AutoV8Persistent : public v8::Persistent<T> {
+ public:
+ AutoV8Persistent() {}
+
+ template <typename U>
+ explicit AutoV8Persistent(const v8::Persistent<U>& rhs)
+ : v8::Persistent<T>(rhs) {
+ }
+
+ template <typename U>
+ AutoV8Persistent& operator=(const v8::Persistent<U>& rhs) {
+ *(v8::Persistent<T>*)this = rhs;
+ return *this;
+ }
+
+ ~AutoV8Persistent() {
+ this->Dispose();
+ this->Clear();
+ }
+};
+
+// The bridge provides a way of evaluating JavaScript in the V8 engine and
+// marshalling between V8 and NPAPI representations of objects and values.
+class NPV8Bridge {
+ friend class NPV8Object;
+ public:
+ NPV8Bridge(ServiceLocator* service_locator, NPP npp);
+ ~NPV8Bridge();
+
+ NPP npp() { return npp_; }
+
+ // Initializes the V8 environment. The global NPObject is wrapped with a V8
+ // proxy and used as the global environment's prototype. This means that if
+ // a variable cannot be resolved in the V8 environment then it will attempt
+ // to resolve it in the NPObject. This allows V8 to read global variables in
+ // the browser environment. Note that assignments will never go to the
+ // global environment's prototype, changes will only be visible locally.
+ void Initialize(const NPObjectPtr<NPObject>& global_np_object);
+
+ // This function tells the bridge to forget and release all of the NPObjects
+ // that it knows about.
+ void ReleaseNPObjects();
+
+ v8::Handle<v8::Context> script_context();
+
+ // Evaluates some JavaScript code in V8. It currently expects only one
+ // argument in the argument array, which must be a string containing the
+ // JavaScript code to evaluate. It returns the result of the evaluation
+ // as an NPAPI variant, which must be freed using NPN_ReleaseVariantValue.
+ bool Evaluate(const NPVariant* np_args, int numArgs, NPVariant* np_result);
+
+ // Adds an object property to the V8 global environment.
+ void SetGlobalProperty(const String& name,
+ NPObjectPtr<NPObject>& np_object);
+
+ // Converts a V8 value into an NPVariant. The NPVariant must be freed with
+ // NPN_ReleaseVariantValue. Caller must enter the script context.
+ NPVariant V8ToNPVariant(v8::Local<v8::Value> value);
+
+ // Converts an NPVariant to a V8 value. Caller must enter the script context.
+ v8::Local<v8::Value> NPToV8Variant(const NPVariant& np_variant);
+
+ // Converts a V8 object to an NPObject, either by wrapping the V8 object
+ // with an NPV8Object proxy or if the V8 object is a proxy, returning the
+ // NPObject it wraps. Caller must enter the script context.
+ NPObjectPtr<NPObject> V8ToNPObject(v8::Local<v8::Value> v8_object);
+
+ // Converts an NPObject to a V8 object, either by wrapping the NPObject with
+ // a V8 proxy or if the NPObject is a proxy, returning the V8 object it wraps.
+ // Caller must enter the script context.
+ v8::Local<v8::Value> NPToV8Object(const NPObjectPtr<NPObject>& np_object);
+
+ // Determines whether the given NPObject is currently referenced by V8 through
+ // a proxy.
+ bool IsNPObjectReferenced(NPObjectPtr<NPObject> np_object);
+
+ private:
+
+ NPObjectPtr<NPObject> NPEvaluateObject(const char* script);
+
+ void NPToV8Object(v8::Local<v8::Object> v8_target,
+ const NPObjectPtr<NPObject>& np_object);
+
+ bool IsNPFunction(const NPObjectPtr<NPObject>& np_object);
+
+ v8::Local<v8::Function> NPToV8Function(
+ const NPObjectPtr<NPObject>& np_function);
+
+ void ReleaseUnreferencedWrapperFunctions();
+
+ NPObjectPtr<NPObject> WrapV8Function(const NPObjectPtr<NPObject>& np_object);
+
+ void RegisterV8Object(v8::Local<v8::Object> v8_object,
+ const NPObjectPtr<NPObject>& np_object);
+
+ void InitializeV8ObjectTemplate(
+ v8::Local<v8::ObjectTemplate> v8_object_template);
+
+ static void NPV8WeakReferenceCallback(v8::Persistent<v8::Value> value,
+ void* parameter);
+
+ void ReportV8Exception(const v8::TryCatch& tryCatch);
+
+ v8::Local<v8::Array> NPToV8IdentifierArray(
+ const NPVariant& np_array, bool named);
+
+ v8::Local<v8::Array> NPToV8IdentifierArray(
+ const NPIdentifier* ids, uint32_t id_count, bool named);
+
+ // Implements enumeration of NPObject properties using NPN_Evaluate where
+ // supported by the browser or otherwise falling back on emulation. Returns
+ // either named or indexed properties depending on named parameter.
+ v8::Local<v8::Array> Enumerate(const NPObjectPtr<NPObject> np_object,
+ bool named);
+
+ static v8::Handle<v8::Value> V8PropertyGetter(v8::Local<v8::Value> v8_name,
+ const v8::AccessorInfo& info);
+
+ static v8::Handle<v8::Value> V8PropertySetter(v8::Local<v8::Value> v8_name,
+ v8::Local<v8::Value> v8_value,
+ const v8::AccessorInfo& info);
+
+ static v8::Handle<v8::Boolean> V8PropertyQuery(v8::Local<v8::Value> v8_name,
+ const v8::AccessorInfo& info);
+
+ static v8::Handle<v8::Boolean> V8PropertyDeleter(
+ v8::Local<v8::Value> v8_name,
+ const v8::AccessorInfo& info);
+
+ static v8::Handle<v8::Value> V8NamedPropertyGetter(
+ v8::Local<v8::String> v8_name,
+ const v8::AccessorInfo& info);
+
+ static v8::Handle<v8::Value> V8NamedPropertySetter(
+ v8::Local<v8::String> v8_name,
+ v8::Local<v8::Value> v8_value,
+ const v8::AccessorInfo& info);
+
+ static v8::Handle<v8::Boolean> V8NamedPropertyQuery(
+ v8::Local<v8::String> v8_name,
+ const v8::AccessorInfo& info);
+
+ static v8::Handle<v8::Boolean> V8NamedPropertyDeleter(
+ v8::Local<v8::String> v8_name,
+ const v8::AccessorInfo& info);
+
+ static v8::Handle<v8::Array> V8NamedPropertyEnumerator(
+ const v8::AccessorInfo& info);
+
+ static v8::Handle<v8::Value> V8IndexedPropertyGetter(
+ uint32_t index,
+ const v8::AccessorInfo& info);
+
+ static v8::Handle<v8::Value> V8IndexedPropertySetter(
+ uint32_t index,
+ v8::Local<v8::Value> v8_value,
+ const v8::AccessorInfo& info);
+
+ static v8::Handle<v8::Boolean> V8IndexedPropertyQuery(
+ uint32_t index,
+ const v8::AccessorInfo& info);
+
+ static v8::Handle<v8::Boolean> V8IndexedPropertyDeleter(
+ uint32_t index,
+ const v8::AccessorInfo& info);
+
+ static v8::Handle<v8::Array> V8IndexedPropertyEnumerator(
+ const v8::AccessorInfo& info);
+
+ static v8::Handle<v8::Value> V8CallNamedMethod(const v8::Arguments& args);
+
+ static v8::Handle<v8::Value> V8CallFunction(const v8::Arguments& args);
+
+ static v8::Handle<v8::Value> V8CallAsFunction(const v8::Arguments& args);
+
+ NPObjectPtr<NPObject> GetNPConstructFunction(int arity);
+
+ typedef o3d::base::hash_map<NPObjectPtr<NPObject>,
+ AutoV8Persistent<v8::Object>,
+ NPObjectPtrHash<NPObject> > NPV8ObjectMap;
+
+ typedef std::map<int, NPObjectPtr<NPObject> > NPConstructFunctionMap;
+
+ ServiceLocator* service_locator_;
+ ServiceDependency<IErrorStatus> error_status_;
+ NPP npp_;
+ NPObjectPtr<NPObject> global_np_object_;
+ AutoV8Persistent<v8::Context> script_context_;
+ AutoV8Persistent<v8::FunctionTemplate> v8_np_constructor_template_;
+ AutoV8Persistent<v8::Object> function_map_;
+ AutoV8Persistent<v8::Object> global_prototype_;
+ NPV8ObjectMap np_v8_object_map_;
+ NPObjectPtr<NPObject> np_enumerate_function_;
+ NPObjectPtr<NPObject> np_is_function_function_;
+ NPObjectPtr<NPObject> np_wrap_function_function_;
+ NPConstructFunctionMap np_construct_functions_;
+ NPIdentifier np_name_identifier_;
+ NPIdentifier np_call_identifier_;
+ NPIdentifier np_length_identifier_;
+ NPIdentifier np_proxy_identifier_;
+ NPObjectPtr<NPObject> np_empty_array_;
+ DISALLOW_COPY_AND_ASSIGN(NPV8Bridge);
+};
+} // namespace o3d
+
+#endif // O3D_PLUGIN_CROSS_NP_V8_BRIDGE_H_
diff --git a/o3d/plugin/cross/o3d_glue.cc b/o3d/plugin/cross/o3d_glue.cc
new file mode 100644
index 0000000..0a7ddd4
--- /dev/null
+++ b/o3d/plugin/cross/o3d_glue.cc
@@ -0,0 +1,856 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include <build/build_config.h>
+#ifdef OS_WIN
+#include <windows.h>
+#include <shellapi.h>
+#endif // OS_WIN
+
+#include <string>
+#include <algorithm>
+#include "core/cross/renderer.h"
+#include "plugin/cross/o3d_glue.h"
+#include "plugin/cross/config.h"
+#include "plugin/cross/stream_manager.h"
+#include "client_glue.h"
+#include "globals_glue.h"
+#include "third_party/nixysa/files/static_glue/npapi/common.h"
+
+#ifdef OS_MACOSX
+#include "plugin_mac.h"
+#endif
+
+namespace glue {
+namespace _o3d {
+
+void RegisterType(NPP npp, const ObjectBase::Class *clientclass,
+ NPClass *npclass) {
+ PluginObject *plugin_object = static_cast<PluginObject *>(npp->pdata);
+ plugin_object->RegisterType(clientclass, npclass);
+}
+
+bool CheckObject(NPP npp, NPObject *npobject,
+ const ObjectBase::Class *clientclass) {
+ PluginObject *plugin_object = static_cast<PluginObject *>(npp->pdata);
+ return plugin_object->CheckObject(npobject, clientclass);
+}
+
+NPAPIObject *GetNPObject(NPP npp, ObjectBase *object) {
+ PluginObject *plugin_object = static_cast<PluginObject *>(npp->pdata);
+ return plugin_object->GetNPObject(object);
+}
+
+NPObject *Allocate(NPP npp, NPClass *npclass) {
+ return new NPAPIObject(npp);
+}
+void Deallocate(NPObject *object) {
+ NPAPIObject *npobject = static_cast<NPAPIObject *>(object);
+ if (npobject->mapped()) {
+ NPP npp = npobject->npp();
+ PluginObject *plugin_object = static_cast<PluginObject *>(npp->pdata);
+ plugin_object->UnmapObject(npobject);
+ }
+ delete npobject;
+}
+
+ServiceLocator *GetServiceLocator(NPP npp) {
+ PluginObject *plugin_object = static_cast<PluginObject *>(npp->pdata);
+ return plugin_object->service_locator();
+}
+
+Client *GetClient(NPP npp) {
+ PluginObject *plugin_object = static_cast<PluginObject *>(npp->pdata);
+ return plugin_object->client();
+}
+
+PluginObject::PluginObject(NPP npp)
+ : npp_(npp),
+ evaluation_counter_(&service_locator_),
+ class_manager_(&service_locator_),
+ object_manager_(&service_locator_),
+ profiler_(&service_locator_),
+ fullscreen_(false),
+ renderer_(NULL),
+ features_(NULL),
+ fullscreen_region_valid_(false),
+ renderer_init_status_(Renderer::UNINITIALIZED),
+#ifdef OS_WIN
+ hWnd_(NULL),
+ fullscreen_hWnd_(NULL),
+ parent_hWnd_(NULL),
+ plugin_hWnd_(NULL),
+ default_plugin_window_proc_(NULL),
+ got_dblclick_(false),
+ painted_once_(false),
+#endif
+#ifdef OS_MACOSX
+ renderer_is_software_(false),
+ scroll_is_in_progress_(false),
+ drawing_model_(NPDrawingModelQuickDraw),
+ event_model_(NPEventModelCarbon),
+ mac_window_(0),
+ mac_fullscreen_window_(0),
+ mac_fullscreen_overlay_window_(0),
+ mac_window_selected_tab_(0),
+ mac_cocoa_window_(0),
+ mac_surface_hidden_(0),
+ mac_2d_context_(0),
+ mac_agl_context_(0),
+ mac_cgl_context_(0),
+ last_mac_event_time_(0),
+ wants_redraw_(false),
+#endif
+#ifdef OS_LINUX
+ display_(NULL),
+ window_(0),
+ xt_widget_(NULL),
+ xt_app_context_(NULL),
+ xt_interval_(0),
+ draw_(true),
+ in_plugin_(false),
+ last_click_time_(0),
+#endif
+ np_v8_bridge_(&service_locator_, npp),
+ stream_manager_(new StreamManager(npp)),
+ cursor_type_(o3d::Cursor::DEFAULT),
+ prev_width_(0),
+ prev_height_(0) {
+#ifdef OS_WIN
+ memset(cursors_, 0, sizeof(cursors_));
+#endif
+
+#ifdef OS_MACOSX
+ memset(last_buffer_rect_, 0, sizeof(last_buffer_rect_));
+#endif
+
+ // create an O3D object
+ client_ = new Client(&service_locator_);
+
+ globals_npobject_ = glue::CreateStaticNPObject(npp);
+ client_npobject_ =
+ glue::namespace_o3d::class_Client::GetNPObject(npp, client_);
+ user_agent_ = GetUserAgent(npp);
+}
+
+PluginObject::~PluginObject() {
+}
+
+void PluginObject::Init(int argc, char* argn[], char* argv[]) {
+ DCHECK(argc == 0 || (argn != NULL && argv != NULL));
+ features_ = new Features(&service_locator_);
+
+ std::string o3d_name("o3d_features");
+
+ for (int ii = 0; ii < argc; ++ii) {
+ DCHECK(argn[ii]);
+ const char* name = argn[ii];
+ if (o3d_name.compare(name) == 0) {
+ DCHECK(argv[ii]);
+ features_->Init(argv[ii]);
+ break;
+ }
+ }
+
+ NPObject* np_window;
+ NPN_GetValue(npp_, NPNVWindowNPObject, &np_window);
+ o3d::NPObjectPtr<NPObject> np_window_ptr =
+ o3d::NPObjectPtr<NPObject>::AttachToReturned(np_window);
+ np_v8_bridge_.Initialize(np_window_ptr);
+
+ o3d::NPObjectPtr<NPObject> np_plugin_ptr(this);
+ np_v8_bridge_.SetGlobalProperty(o3d::String("plugin"),
+ np_plugin_ptr);
+}
+
+void PluginObject::TearDown() {
+#ifdef OS_WIN
+ ClearPluginProperty(hWnd_);
+#endif // OS_WIN
+#ifdef OS_MACOSX
+ ReleaseSafariBrowserWindow(mac_cocoa_window_);
+#endif
+ UnmapAll();
+
+ // Delete the StreamManager to cleanup any streams that are in midflight.
+ // This needs to happen here, before the client is deleted as the streams
+ // could be holding references to FileRequest objects.
+ stream_manager_.reset(NULL);
+
+ delete client_;
+ // Release the graphics context before deletion.
+ DeleteRenderer();
+
+ delete features_;
+
+ // There is a reference cycle between the V8 bridge and the plugin.
+ // Explicitly remove all V8 references during tear-down, so that the cycle is
+ // broken, and the reference counting system will successfully delete the
+ // plugin.
+ np_v8_bridge_.ReleaseNPObjects();
+}
+
+void PluginObject::CreateRenderer(const o3d::DisplayWindow& display_window) {
+ renderer_ = o3d::Renderer::CreateDefaultRenderer(&service_locator_);
+ DCHECK(renderer_);
+
+ if (!CheckConfig(npp_)) {
+ renderer_init_status_ = o3d::Renderer::GPU_NOT_UP_TO_SPEC;
+ } else {
+ // Attempt to initialize renderer.
+ renderer_init_status_ = renderer_->Init(display_window, false);
+ if (renderer_init_status_ != o3d::Renderer::SUCCESS) {
+ DeleteRenderer();
+ }
+ }
+}
+
+void PluginObject::DeleteRenderer() {
+ if (renderer_) {
+ delete renderer_;
+ renderer_ = NULL;
+ }
+}
+
+
+#ifdef OS_MACOSX
+
+// These following 3 methods are needed for a Safari workaround - basically it
+// does not notify us when our tab is hidden by tab switching, and just stops
+// sending us events. The workaround is to keep track of when the browser last
+// sent us an event, and what the selected tab was at that time. If we find that
+// we are no longer getting events and the selected tab value has changed,
+// DetectTabHiding() starts returning true when the timer calls it and code
+// elsewhere can take action. SafariBrowserWindowForWindowRef() and
+// SelectedTabForSafariBrowserWindow() are both written in such a way that
+// non-Safari browsers should yield NULL, so DetectTabHiding would always
+// return false and the workaround would not be triggered.
+
+
+// Function gets notified every time we receive a Mac event.
+// It records the time of the event and tries to read the selected tab value
+// from Safari (on other browsers this tab value should always be NULL).
+// Written so that last_mac_event_time_ is always valid or NULL.
+void PluginObject::MacEventReceived() {
+ CFDateRef now = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent());
+ CFDateRef previousTime = last_mac_event_time_;
+ last_mac_event_time_ = now;
+ if (previousTime != NULL) {
+ CFRelease(previousTime);
+ }
+ if (!mac_cocoa_window_) {
+ mac_cocoa_window_ = SafariBrowserWindowForWindowRef(mac_window_);
+ }
+ mac_window_selected_tab_ =
+ SelectedTabForSafariBrowserWindow(mac_cocoa_window_);
+}
+
+// Returns the time elapsed since the MacEventReceived function was last called.
+CFTimeInterval PluginObject::TimeSinceLastMacEvent() {
+ CFTimeInterval elapsed = 0.0;
+ if (last_mac_event_time_ != NULL) {
+ CFDateRef now = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent());
+ elapsed = CFDateGetTimeIntervalSinceDate(now, last_mac_event_time_);
+ CFRelease(now);
+ }
+ return elapsed;
+}
+
+// Detects if Safari has hidden our tab.
+// The heuristic is that we have not received any Mac events for a certain time
+// and also the value for selected tab is different from the value it had the
+// last time we did get a Mac event.
+bool PluginObject::DetectTabHiding() {
+ const CFTimeInterval kMacTimeOut = 0.2; // a fifth of a second
+ if (TimeSinceLastMacEvent() < kMacTimeOut)
+ return false;
+
+ if (!mac_cocoa_window_) {
+ mac_cocoa_window_ = SafariBrowserWindowForWindowRef(mac_window_);
+ }
+
+ return SelectedTabForSafariBrowserWindow(mac_cocoa_window_) !=
+ mac_window_selected_tab_;
+}
+
+
+// Pick a constant way out of Apple's 0-22 range for our "no theme cursor"
+// constant.
+const ThemeCursor kNoThemeCursorForThat = 1000;
+
+// Map o3d cursors to Mac theme cursors if possible, otherwise return
+// kNoThemeCursorForThat.
+ThemeCursor O3DToMacThemeCursor(o3d::Cursor::CursorType cursor_type) {
+ switch (cursor_type) {
+ case o3d::Cursor::DEFAULT:
+ return kThemeArrowCursor;
+ case o3d::Cursor::NONE: // There is no standard blank cursor.
+ return kNoThemeCursorForThat;
+ case o3d::Cursor::CROSSHAIR:
+ return kThemeCrossCursor;
+ case o3d::Cursor::POINTER:
+ return kThemePointingHandCursor;
+ case o3d::Cursor::E_RESIZE:
+ return kThemeResizeRightCursor;
+ case o3d::Cursor::NE_RESIZE: // No diagonal resize directions on Mac.
+ return kNoThemeCursorForThat;
+ case o3d::Cursor::NW_RESIZE: // No diagonal resize directions on Mac.
+ return kNoThemeCursorForThat;
+ case o3d::Cursor::N_RESIZE:
+ return kThemeResizeUpCursor;
+ case o3d::Cursor::SE_RESIZE: // No diagonal resize directions on Mac.
+ return kNoThemeCursorForThat;
+ case o3d::Cursor::SW_RESIZE: // No diagonal resize directions on Mac.
+ return kNoThemeCursorForThat;
+ case o3d::Cursor::S_RESIZE:
+ return kThemeResizeDownCursor;
+ case o3d::Cursor::W_RESIZE:
+ return kThemeResizeLeftCursor;
+ case o3d::Cursor::MOVE:
+ return kThemeOpenHandCursor;
+ case o3d::Cursor::TEXT:
+ return kThemeIBeamCursor;
+ case o3d::Cursor::WAIT:
+ return kThemeWatchCursor;
+ case o3d::Cursor::PROGRESS:
+ return kThemeSpinningCursor;
+ case o3d::Cursor::HELP: // No standard Help cursor.
+ return kNoThemeCursorForThat;
+ }
+
+ return kNoThemeCursorForThat;
+}
+
+
+// Set cursor to the one specified in cursor_type_.
+// TODO add support for cursors that don't have equivalent Mac
+// theme cursors.
+void PluginObject::PlatformSpecificSetCursor() {
+ if (cursor_type_ == o3d::Cursor::NONE) {
+ // hide cursor if visible
+ if (CGCursorIsVisible()) {
+ CGDisplayHideCursor(kCGDirectMainDisplay);
+ }
+ } else {
+ ThemeCursor the_id = O3DToMacThemeCursor(cursor_type_);
+
+ if (the_id != kNoThemeCursorForThat) {
+ SetThemeCursor(the_id);
+ } else {
+ // could add code here to set other cursors by other means
+ SetThemeCursor(kThemeArrowCursor);
+ }
+ // show cursor if hidden
+ if (!CGCursorIsVisible())
+ CGDisplayShowCursor(kCGDirectMainDisplay);
+ }
+}
+
+bool PluginObject::WantsRedraw() {
+ if (client()->render_mode() == o3d::Client::RENDERMODE_CONTINUOUS)
+ return true;
+
+ // If we're rendering on-demand, then a call to client->render() should
+ // only force a redraw one time
+ return wants_redraw_;
+}
+
+#endif // OS_MACOSX
+
+
+void PluginObject::RegisterType(const ObjectBase::Class *clientclass,
+ NPClass *npclass) {
+ client_to_np_class_map_[clientclass] = npclass;
+ np_to_client_class_map_[npclass] = clientclass;
+}
+
+bool PluginObject::CheckObject(NPObject *npobject,
+ const ObjectBase::Class *clientclass) const {
+ if (!npobject) return true;
+ NPClass *npclass = npobject->_class;
+ NPToClientClassMap::const_iterator it = np_to_client_class_map_.find(npclass);
+ if (it == np_to_client_class_map_.end()) return false;
+ if (static_cast<NPAPIObject *>(npobject)->npp()->pdata != this) {
+ // The object was created by another plug-in instance. Don't allow direct
+ // references to these objects, that would cause havok.
+ return false;
+ }
+ return ObjectBase::ClassIsA(it->second, clientclass);
+}
+
+NPAPIObject *PluginObject::GetNPObject(ObjectBase *object) {
+ if (!object) return NULL;
+ NPAPIObject *npobject = object_map_[object->id()];
+ if (!npobject) {
+ NPClass *npclass = GetNPClass(object->GetClass());
+ GLUE_PROFILE_START(npp_, "createobject");
+ npobject = static_cast<NPAPIObject *>(NPN_CreateObject(npp_, npclass));
+ GLUE_PROFILE_STOP(npp_, "createobject");
+ npobject->Initialize(object);
+ object_map_[object->id()] = npobject;
+ npobject->set_mapped(true);
+ } else {
+ GLUE_PROFILE_START(npp_, "retainobject");
+ NPN_RetainObject(npobject);
+ GLUE_PROFILE_STOP(npp_, "retainobject");
+ }
+ return npobject;
+}
+
+void PluginObject::UnmapObject(NPAPIObject *npobject) {
+ npobject->set_mapped(false);
+ object_map_.erase(npobject->id());
+}
+
+void PluginObject::UnmapAll() {
+ for (ClientObjectMap::iterator it = object_map_.begin();
+ it != object_map_.end(); ++it) {
+ it->second->set_mapped(false);
+ }
+ object_map_.clear();
+}
+
+NPClass *PluginObject::GetNPClass(const ObjectBase::Class *clientclass) {
+ const ObjectBase::Class *cursor = clientclass;
+ while (cursor) {
+ ClientToNPClassMap::const_iterator it =
+ client_to_np_class_map_.find(cursor);
+ if (it != client_to_np_class_map_.end()) {
+ NPClass *npclass = it->second;
+ if (cursor != clientclass) client_to_np_class_map_[clientclass] = npclass;
+ return npclass;
+ }
+ cursor = cursor->parent();
+ }
+ return NULL;
+}
+// Static function to handle log asserts in the FATAL ERROR case
+void PluginObject::LogAssertHandlerFunction(const std::string& str) {
+ DLOG(ERROR) << "FATAL LOG ERROR: " << str;
+}
+
+enum {
+ PROP_CLIENT,
+ PROP_GPU_CONFIG,
+ NUM_PROPERTY_IDS
+};
+
+static NPIdentifier property_ids[NUM_PROPERTY_IDS];
+static const NPUTF8 *property_names[NUM_PROPERTY_IDS] = {
+ "client",
+ "gpuConfig",
+};
+
+enum {
+ METHOD_EVAL,
+ NUM_METHOD_IDS,
+};
+
+static NPIdentifier method_ids[NUM_METHOD_IDS];
+static const NPUTF8 *method_names[NUM_METHOD_IDS] = {
+ "eval",
+};
+
+static NPObject *PluginAllocate(NPP npp, NPClass *npclass) {
+ return new PluginObject(npp);
+}
+
+static void PluginDeallocate(NPObject *object) {
+ delete static_cast<PluginObject *>(object);
+}
+
+static bool PluginHasMethod(NPObject *header, NPIdentifier name) {
+ DebugScopedId id(name);
+ PluginObject *plugin_object = static_cast<PluginObject *>(header);
+ if (name == method_ids[METHOD_EVAL]) {
+ return true;
+ } else {
+ NPObject *globals = plugin_object->globals_npobject();
+ return globals->_class->hasMethod(globals, name);
+ }
+}
+
+static bool PluginInvoke(NPObject *header, NPIdentifier name,
+ const NPVariant *args, uint32_t argCount,
+ NPVariant *np_result) {
+ DebugScopedId id(name);
+ PluginObject *plugin_object = static_cast<PluginObject *>(header);
+ if (name == method_ids[METHOD_EVAL]) {
+ return plugin_object->np_v8_bridge()->Evaluate(args, argCount, np_result);
+ } else {
+ NPObject *globals = plugin_object->globals_npobject();
+ return globals->_class->invoke(globals, name, args, argCount, np_result);
+ }
+}
+
+static bool PluginInvokeDefault(NPObject *header, const NPVariant *args,
+ uint32_t argCount, NPVariant *result) {
+ PluginObject *plugin_object = static_cast<PluginObject *>(header);
+ NPP npp = plugin_object->npp();
+ NPObject *globals = plugin_object->globals_npobject();
+ return globals->_class->invokeDefault(globals, args, argCount, result);
+}
+
+static bool PluginHasProperty(NPObject *header, NPIdentifier name) {
+ DebugScopedId id(name);
+ PluginObject *plugin_object = static_cast<PluginObject *>(header);
+ NPP npp = plugin_object->npp();
+ for (unsigned int i = 0; i < NUM_PROPERTY_IDS; ++i) {
+ if (name == property_ids[i]) return true;
+ }
+ NPObject *globals = plugin_object->globals_npobject();
+ return globals->_class->hasProperty(globals, name);
+}
+
+static bool PluginGetProperty(NPObject *header, NPIdentifier name,
+ NPVariant *variant) {
+ DebugScopedId id(name);
+ PluginObject *plugin_object = static_cast<PluginObject *>(header);
+ NPP npp = plugin_object->npp();
+ if (name == property_ids[PROP_GPU_CONFIG]) {
+ // Gets the GPU config (VendorID, DeviceID, name) as a string.
+ // NOTE: this should probably be removed before we ship.
+ GPUDevice device;
+ bool result = GetGPUDevice(npp, &device);
+ if (!result) return false;
+ std::string return_value = std::string("VendorID = 0x");
+ char id_text[9];
+ base::snprintf(id_text, sizeof(id_text), "%04x", device.vendor_id);
+ return_value += id_text;
+ return_value += ", DeviceID = 0x";
+ base::snprintf(id_text, sizeof(id_text), "%04x", device.device_id);
+ return_value += id_text;
+ return_value += ", DeviceName = '";
+ return_value += device.name + "'";
+ return_value += ", Driver = '";
+ return_value += device.driver + "'";
+ return_value += ", Description = '";
+ return_value += device.description + "'";
+ return_value += ", GUID = 0x";
+ base::snprintf(id_text, sizeof(id_text), "%08x", device.guid);
+ return_value += id_text;
+ GLUE_PROFILE_START(npp, "StringToNPVariant");
+ bool temp = StringToNPVariant(return_value, variant);
+ GLUE_PROFILE_STOP(npp, "StringToNPVariant");
+ return temp;
+ }
+
+ if (name == property_ids[PROP_CLIENT]) {
+ NPObject *npobject = plugin_object->client_npobject();
+ GLUE_PROFILE_START(npp, "retainobject");
+ NPN_RetainObject(npobject);
+ GLUE_PROFILE_STOP(npp, "retainobject");
+ OBJECT_TO_NPVARIANT(npobject, *variant);
+ return true;
+ }
+ NPObject *globals = plugin_object->globals_npobject();
+ return globals->_class->getProperty(globals, name, variant);
+}
+
+static bool PluginSetProperty(NPObject *header, NPIdentifier name,
+ const NPVariant *variant) {
+ DebugScopedId id(name);
+ PluginObject *plugin_object = static_cast<PluginObject *>(header);
+ NPP npp = plugin_object->npp();
+ if (name == property_ids[PROP_CLIENT]) {
+ return false;
+ }
+ NPObject *globals = plugin_object->globals_npobject();
+ return globals->_class->setProperty(globals, name, variant);
+}
+
+static bool PluginEnumerate(NPObject *header, NPIdentifier **value,
+ uint32_t *count) {
+ *count = NUM_PROPERTY_IDS + NUM_METHOD_IDS + glue::GetStaticPropertyCount();
+ PluginObject *plugin_object = static_cast<PluginObject *>(header);
+ NPP npp = plugin_object->npp();
+ GLUE_PROFILE_START(npp, "memalloc");
+ *value = static_cast<NPIdentifier *>(
+ NPN_MemAlloc(*count * sizeof(NPIdentifier)));
+ GLUE_PROFILE_STOP(npp, "memalloc");
+ memcpy(*value, property_ids, NUM_PROPERTY_IDS * sizeof(NPIdentifier));
+ memcpy(*value + NUM_PROPERTY_IDS, method_ids,
+ NUM_METHOD_IDS * sizeof(NPIdentifier));
+ glue::StaticEnumeratePropertyHelper(
+ *value + NUM_PROPERTY_IDS + NUM_METHOD_IDS);
+ return true;
+}
+
+static NPClass plugin_npclass = {
+ NP_CLASS_STRUCT_VERSION,
+ PluginAllocate,
+ PluginDeallocate,
+ 0,
+ PluginHasMethod,
+ PluginInvoke,
+ 0,
+ PluginHasProperty,
+ PluginGetProperty,
+ PluginSetProperty,
+ 0,
+ PluginEnumerate,
+};
+
+PluginObject *PluginObject::Create(NPP npp) {
+ GLUE_PROFILE_START(npp, "createobject");
+ PluginObject *plugin_object =
+ static_cast<PluginObject *>(NPN_CreateObject(npp, &plugin_npclass));
+ GLUE_PROFILE_STOP(npp, "createobject");
+ return plugin_object;
+}
+
+void InitializeGlue(NPP npp) {
+ GLUE_PROFILE_START(npp, "getstringidentifiers");
+ NPN_GetStringIdentifiers(property_names, NUM_PROPERTY_IDS, property_ids);
+ NPN_GetStringIdentifiers(method_names, NUM_METHOD_IDS, method_ids);
+ GLUE_PROFILE_STOP(npp, "getstringidentifiers");
+ glue::InitializeGlue(npp);
+}
+
+// Plugin has been resized.
+void PluginObject::Resize(int width, int height) {
+ // check that the window size has actually changed
+ if (prev_width_ != width || prev_height_ != height) {
+ prev_width_ = width;
+ prev_height_ = height;
+ if (renderer_ && !fullscreen_) {
+ // Tell the renderer and client that our window has been resized.
+ // If we're in fullscreen mode when this happens, we don't want to pass
+ // the information through; the renderer will pick it up when we switch
+ // back to plugin mode.
+ renderer_->Resize(width, height);
+ // This is just so that the client can send an event to the user.
+ client()->SendResizeEvent(width, height, fullscreen_);
+ }
+ }
+}
+
+int PluginObject::width() const {
+ if (renderer_) {
+ return renderer_->width();
+ }
+ return 0;
+}
+
+int PluginObject::height() const {
+ if (renderer_) {
+ return renderer_->height();
+ }
+ return 0;
+}
+
+void PluginObject::GetDisplayModes(std::vector<o3d::DisplayMode> *modes) {
+ if (renderer()) {
+ renderer()->GetDisplayModes(modes);
+ } else {
+ modes->clear();
+ }
+}
+
+void PluginObject::RedirectToFile(const char *url) {
+ char cmd[] = "window.location = 'file:///%s';";
+ scoped_array<char> full_cmd(new char[strlen(url) + sizeof(cmd)]);
+ sprintf(full_cmd.get(), cmd, url);
+
+ NPObject *global_object;
+ NPN_GetValue(npp(), NPNVWindowNPObject, &global_object);
+ NPString string;
+ string.utf8characters = full_cmd.get();
+ string.utf8length = strlen(string.utf8characters);
+ NPVariant result;
+ bool temp = NPN_Evaluate(npp(), global_object, &string, &result);
+ if (temp) {
+ NPN_ReleaseVariantValue(&result);
+ }
+}
+
+o3d::Cursor::CursorType PluginObject::cursor() const {
+ return cursor_type_;
+}
+
+void PluginObject::set_cursor(o3d::Cursor::CursorType cursor_type) {
+ cursor_type_ = cursor_type;
+ PlatformSpecificSetCursor();
+}
+
+#ifdef OS_WIN
+bool PluginObject::fullscreen_class_registered_ = false;
+WNDCLASSEX PluginObject::fullscreen_class_;
+
+static const wchar_t* kWindowPropertyName = L"o3d";
+
+void PluginObject::StorePluginProperty(HWND hWnd, PluginObject *obj) {
+ if (obj->GetHWnd()) { // Clear out the record from the old window first.
+ ClearPluginProperty(obj->GetHWnd());
+ }
+ StorePluginPropertyUnsafe(hWnd, obj);
+}
+
+void PluginObject::StorePluginPropertyUnsafe(HWND hWnd, PluginObject *obj) {
+ obj->SetHWnd(hWnd);
+ if (hWnd) {
+ SetProp(hWnd, kWindowPropertyName, static_cast<HANDLE>(obj));
+ ::DragAcceptFiles(hWnd, true);
+ }
+}
+
+PluginObject *PluginObject::GetPluginProperty(HWND hWnd) {
+ return static_cast<PluginObject*>(GetProp(hWnd, kWindowPropertyName));
+}
+
+void PluginObject::ClearPluginProperty(HWND hWnd) {
+ if (hWnd) {
+ RemoveProp(hWnd, kWindowPropertyName);
+ ::DragAcceptFiles(hWnd, false);
+ }
+}
+
+WNDCLASSEX *PluginObject::GetFullscreenWindowClass(HINSTANCE hInstance,
+ WNDPROC window_proc) {
+ if (!fullscreen_class_registered_) {
+ ZeroMemory(&fullscreen_class_, sizeof(WNDCLASSEX));
+ fullscreen_class_.cbSize = sizeof(WNDCLASSEX);
+ fullscreen_class_.hInstance = hInstance;
+ fullscreen_class_.lpfnWndProc = window_proc;
+ fullscreen_class_.lpszClassName = L"O3DFullScreenWindowClass";
+ fullscreen_class_.style = CS_DBLCLKS;
+
+ RegisterClassEx(&fullscreen_class_);
+ fullscreen_class_registered_ = true;
+ }
+ return &fullscreen_class_;
+}
+
+static LPCTSTR O3DToWindowsCursor(o3d::Cursor::CursorType cursor_type) {
+ switch (cursor_type) {
+ case o3d::Cursor::DEFAULT:
+ return IDC_ARROW;
+ case o3d::Cursor::NONE:
+ return NULL;
+ case o3d::Cursor::CROSSHAIR:
+ return IDC_CROSS;
+ case o3d::Cursor::POINTER:
+ return IDC_HAND;
+ case o3d::Cursor::E_RESIZE:
+ return IDC_SIZEWE;
+ case o3d::Cursor::NE_RESIZE:
+ return IDC_SIZENESW;
+ case o3d::Cursor::NW_RESIZE:
+ return IDC_SIZENWSE;
+ case o3d::Cursor::N_RESIZE:
+ return IDC_SIZENS;
+ case o3d::Cursor::SE_RESIZE:
+ return IDC_SIZENWSE;
+ case o3d::Cursor::SW_RESIZE:
+ return IDC_SIZENESW;
+ case o3d::Cursor::S_RESIZE:
+ return IDC_SIZENS;
+ case o3d::Cursor::W_RESIZE:
+ return IDC_SIZEWE;
+ case o3d::Cursor::MOVE:
+ return IDC_SIZEALL;
+ case o3d::Cursor::TEXT:
+ return IDC_IBEAM;
+ case o3d::Cursor::WAIT:
+ return IDC_WAIT;
+ case o3d::Cursor::PROGRESS:
+ return IDC_APPSTARTING;
+ case o3d::Cursor::HELP:
+ return IDC_HELP;
+ }
+ return IDC_ARROW;
+}
+
+void PluginObject::PlatformSpecificSetCursor() {
+ if (!cursors_[cursor_type_]) {
+ cursors_[cursor_type_] = ::LoadCursor(NULL,
+ O3DToWindowsCursor(cursor_type_));
+ }
+ ::SetCursor(cursors_[cursor_type_]);
+}
+
+#endif // OS_WIN
+
+#ifdef OS_LINUX
+
+void PluginObject::PlatformSpecificSetCursor() {
+ // TODO: fill this in.
+}
+
+#endif // OS_LINUX
+
+} // namespace _o3d
+
+namespace globals {
+
+using _o3d::PluginObject;
+// This implements the definition in common.h of a function to receive
+// all glue error reports.
+void SetLastError(NPP npp, const char *error) {
+ PluginObject *plugin_object = static_cast<PluginObject *>(npp->pdata);
+ O3D_ERROR(plugin_object->service_locator()) << error;
+}
+
+// These implement the definitions in common.h of functions to receive
+// all profiling calls.
+void ProfileStart(NPP npp, const std::string& key) {
+ PluginObject *plugin_object = static_cast<PluginObject *>(npp->pdata);
+ if (plugin_object) { // May not be initialized yet.
+ plugin_object->client()->ProfileStart(key);
+ }
+}
+
+void ProfileStop(NPP npp, const std::string& key) {
+ PluginObject *plugin_object = static_cast<PluginObject *>(npp->pdata);
+ if (plugin_object) { // May not be initialized yet.
+ plugin_object->client()->ProfileStop(key);
+ }
+}
+
+void ProfileReset(NPP npp) {
+ PluginObject *plugin_object = static_cast<PluginObject *>(npp->pdata);
+ if (plugin_object) { // May not be initialized yet.
+ plugin_object->client()->ProfileReset();
+ }
+}
+
+std::string ProfileToString(NPP npp) {
+ PluginObject *plugin_object = static_cast<PluginObject *>(npp->pdata);
+ if (plugin_object) { // May not be initialized yet.
+ return plugin_object->client()->ProfileToString();
+ } else {
+ return "";
+ }
+}
+
+} // namespace globals
+} // namespace glue
diff --git a/o3d/plugin/cross/o3d_glue.h b/o3d/plugin/cross/o3d_glue.h
new file mode 100644
index 0000000..019488a
--- /dev/null
+++ b/o3d/plugin/cross/o3d_glue.h
@@ -0,0 +1,430 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#ifndef O3D_PLUGIN_CROSS_O3D_GLUE_H_
+#define O3D_PLUGIN_CROSS_O3D_GLUE_H_
+
+#include <build/build_config.h>
+
+#ifdef OS_MACOSX
+#include <OpenGL/OpenGL.h>
+#include <AGL/agl.h>
+#endif
+
+#ifdef OS_LINUX
+#include <GL/glx.h>
+#include <X11/Intrinsic.h>
+#endif
+
+
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+#include "base/scoped_ptr.h"
+#include "base/cross/std_hash.h"
+#include "core/cross/display_mode.h"
+#include "core/cross/display_window.h"
+#include "core/cross/object_base.h"
+#include "core/cross/service_locator.h"
+#include "core/cross/evaluation_counter.h"
+#include "core/cross/class_manager.h"
+#include "core/cross/features.h"
+#include "core/cross/object_manager.h"
+#include "core/cross/error.h"
+#include "core/cross/profiler.h"
+#include "plugin/cross/np_v8_bridge.h"
+#include "client_glue.h"
+#include "third_party/nixysa/files/static_glue/npapi/common.h"
+
+namespace o3d {
+class Client;
+class Renderer;
+}
+
+namespace glue {
+class StreamManager;
+
+namespace _o3d {
+using o3d::Id;
+using o3d::ObjectBase;
+using o3d::Client;
+using o3d::ClassManager;
+using o3d::EvaluationCounter;
+using o3d::Features;
+using o3d::EvaluationCounter;
+using o3d::ObjectManager;
+using o3d::Profiler;
+using o3d::Renderer;
+using o3d::ServiceLocator;
+
+class NPAPIObject: public NPObject {
+ NPP npp_;
+ Id id_;
+ bool mapped_;
+ public:
+ explicit NPAPIObject(NPP npp): npp_(npp), id_(0), mapped_(false) {}
+ void Initialize(const ObjectBase *object) { id_ = object->id(); }
+ NPP npp() const { return npp_; }
+ Id id() const { return id_; }
+ bool mapped() const { return mapped_; }
+ void set_mapped(bool mapped) { mapped_ = mapped; }
+};
+void RegisterType(NPP npp, const ObjectBase::Class *clientclass,
+ NPClass *npclass);
+bool CheckObject(NPP npp, NPObject *npobject,
+ const ObjectBase::Class *clientclass);
+NPAPIObject *GetNPObject(NPP npp, ObjectBase *object);
+NPObject *Allocate(NPP npp, NPClass *npclass);
+void Deallocate(NPObject *object);
+ServiceLocator *GetServiceLocator(NPP npp);
+Client *GetClient(NPP npp);
+void InitializeGlue(NPP npp);
+
+typedef glue::namespace_o3d::class_Client::NPAPIObject ClientNPObject;
+
+class PluginObject: public NPObject {
+ typedef o3d::base::hash_map<Id, NPAPIObject *> ClientObjectMap;
+ typedef o3d::base::hash_map<const ObjectBase::Class *, NPClass *>
+ ClientToNPClassMap;
+ typedef o3d::base::hash_map<NPClass *, const ObjectBase::Class *>
+ NPToClientClassMap;
+
+ NPP npp_;
+ ServiceLocator service_locator_;
+ EvaluationCounter evaluation_counter_;
+ ClassManager class_manager_;
+ ObjectManager object_manager_;
+ Profiler profiler_;
+ bool fullscreen_; // Are we rendered fullscreen or in the plugin region?
+ Renderer *renderer_;
+ Client *client_;
+ Features* features_;
+ ClientObjectMap object_map_;
+ ClientToNPClassMap client_to_np_class_map_;
+ NPToClientClassMap np_to_client_class_map_;
+ NPObject *globals_npobject_;
+ ClientNPObject *client_npobject_;
+ std::string user_agent_;
+ Renderer::InitStatus renderer_init_status_;
+ // The current cursor type.
+ o3d::Cursor::CursorType cursor_type_;
+
+ // Last known dimensions of plugin
+ int prev_width_;
+ int prev_height_;
+
+ o3d::NPV8Bridge np_v8_bridge_;
+ scoped_ptr<StreamManager> stream_manager_;
+
+ public:
+#ifdef OS_WIN
+ void SetDefaultPluginWindowProc(WNDPROC proc) {
+ default_plugin_window_proc_ = proc;
+ }
+ WNDPROC GetDefaultPluginWindowProc() {
+ return default_plugin_window_proc_;
+ }
+ void SetHWnd(HWND hWnd) {
+ hWnd_ = hWnd;
+ }
+ HWND GetHWnd() {
+ return hWnd_;
+ }
+ void SetFullscreenHWnd(HWND hWnd) {
+ fullscreen_hWnd_ = hWnd;
+ }
+ HWND GetFullscreenHWnd() {
+ return fullscreen_hWnd_;
+ }
+ void SetParentHWnd(HWND hWnd) {
+ parent_hWnd_ = hWnd;
+ }
+ HWND GetParentHWnd() {
+ return parent_hWnd_;
+ }
+ void SetPluginHWnd(HWND hWnd) {
+ plugin_hWnd_ = hWnd;
+ }
+ HWND GetPluginHWnd() {
+ return plugin_hWnd_;
+ }
+ bool RecordPaint() {
+ bool painted = painted_once_;
+ painted_once_ = true;
+ return painted;
+ }
+ bool got_dblclick() const { return got_dblclick_; }
+ void set_got_dblclick(bool got_dblclick) { got_dblclick_ = got_dblclick; }
+#endif
+#ifdef OS_MACOSX
+
+ void SetFullscreenOverlayMacWindow(WindowRef window) {
+ mac_fullscreen_overlay_window_ = window;
+ }
+
+ WindowRef GetFullscreenOverlayMacWindow() {
+ return mac_fullscreen_overlay_window_;
+ }
+
+ void SetFullscreenMacWindow(WindowRef window) {
+ mac_fullscreen_window_ = window;
+ }
+
+ WindowRef GetFullscreenMacWindow() {
+ return mac_fullscreen_window_;
+ }
+
+ // Always returns |true| if RENDERMODE_CONTINUOUS, otherwise
+ // only if client->render() has been called and we haven't yet
+ // handled it
+ bool WantsRedraw();
+ void SetWantsRedraw(bool wants) { wants_redraw_ = wants; }
+
+ bool ScrollIsInProgress() { return scroll_is_in_progress_; }
+ void SetScrollIsInProgress(bool state) { scroll_is_in_progress_ = state; }
+ bool scroll_is_in_progress_;
+
+ bool RendererIsSoftware() {return renderer_is_software_;}
+ bool SetRendererIsSoftware(bool state) {renderer_is_software_ = state;}
+ bool renderer_is_software_;
+
+ NPDrawingModel drawing_model_;
+ NPEventModel event_model_;
+ WindowRef mac_window_; // may be NULL in the Chrome case
+ WindowRef mac_fullscreen_window_; // NULL if not in fullscreen modee
+ WindowRef mac_fullscreen_overlay_window_; // NULL if not in fullscreen mode
+ // these vars needed for the Safari tab switch detection hack
+ CFDateRef last_mac_event_time_;
+ bool wants_redraw_;
+ void * mac_cocoa_window_;
+ void* mac_window_selected_tab_;
+ bool mac_surface_hidden_;
+ // end of Safari tab detection vars
+ GLint last_buffer_rect_[4];
+ Point last_plugin_loc_;
+ // can be a CGrafPtr, a CGContextRef or NULL depending on drawing_model
+ void* mac_2d_context_;
+ // either can be NULL depending on drawing_model
+ AGLContext mac_agl_context_;
+ CGLContextObj mac_cgl_context_;
+#endif
+#ifdef OS_LINUX
+ Display *display_;
+ Window window_;
+ Widget xt_widget_;
+ XtAppContext xt_app_context_;
+ XtIntervalId xt_interval_;
+ bool draw_;
+ bool in_plugin_;
+ Time last_click_time_;
+#endif
+ explicit PluginObject(NPP npp);
+ ~PluginObject();
+ void Init(int argc, char* argn[], char* argv[]);
+ void TearDown();
+ ServiceLocator* service_locator() { return &service_locator_; }
+ Client *client() { return client_; }
+ Renderer *renderer() { return renderer_; }
+ NPP npp() { return npp_; }
+ void RegisterType(const ObjectBase::Class *clientclass, NPClass *npclass);
+ bool CheckObject(NPObject *npobject,
+ const ObjectBase::Class *clientclass) const;
+ NPAPIObject *GetNPObject(ObjectBase *object);
+ void UnmapObject(NPAPIObject *npobject);
+ void UnmapAll();
+ NPClass *GetNPClass(const ObjectBase::Class *clientclass);
+
+ NPObject *globals_npobject() { return globals_npobject_; }
+ ClientNPObject *client_npobject() { return client_npobject_; }
+
+ static const char* kOnRenderEventName;
+
+ static PluginObject *Create(NPP npp);
+
+ StreamManager *stream_manager() const { return stream_manager_.get(); }
+
+ static void LogAssertHandlerFunction(const std::string& str);
+
+ Renderer::InitStatus renderer_init_status() const {
+ return renderer_init_status_;
+ }
+
+ // Plugin has been resized.
+ void Resize(int width, int height);
+
+ int width() const;
+ int height() const;
+
+ // Fullscreen stuff
+ bool fullscreen() const {
+ return fullscreen_;
+ }
+
+ // Get a vector of the available fullscreen display modes.
+ // Clears *modes on error.
+ void GetDisplayModes(std::vector<o3d::DisplayMode> *modes);
+
+ // This isn't exposed directly to JavaScript for security reasons; it gets
+ // called by the platform-specific event-handling code if the region set by
+ // SetFullscreenClickRegion is clicked. It requests the mode previously set
+ // by SetFullscreenClickRegion(), and fails if there wasn't one.
+ bool RequestFullscreenDisplay();
+
+ // Make a region of the plugin area that will invoke fullscreen mode if
+ // clicked. The app developer is responsible for communicating this to the
+ // user, as this region has no visible marker. The user is also responsible
+ // for updating this region if the plugin gets resized, as we don't know
+ // whether or how to scale it.
+ void SetFullscreenClickRegion(int x, int y, int width, int height,
+ int mode_id) {
+ fullscreen_region_valid_ = true;
+ fullscreen_region_x_ = x;
+ fullscreen_region_y_ = y;
+ fullscreen_region_width_ = width;
+ fullscreen_region_height_ = height;
+ fullscreen_region_mode_id_ = mode_id;
+ }
+ void ClearFullscreenClickRegion() {
+ fullscreen_region_valid_ = false;
+ }
+
+ // Tests a mouse click location for a hit on the fullscreen click region.
+ bool HitFullscreenClickRegion(int x, int y) {
+ if (!fullscreen_region_valid_ || fullscreen_) {
+ return false;
+ }
+ return (x >= fullscreen_region_x_) &&
+ (x - fullscreen_region_x_ < fullscreen_region_width_) &&
+ (y >= fullscreen_region_y_) &&
+ (y - fullscreen_region_y_ < fullscreen_region_height_);
+ }
+
+ // Deactivate fullscreen mode.
+ void CancelFullscreenDisplay();
+
+ // Redirect by setting window.location to file:///<url>.
+ void RedirectToFile(const char *url);
+
+ // Get the cursor's shape.
+ o3d::Cursor::CursorType cursor() const;
+
+ // Set the cursor's shape.
+ void set_cursor(o3d::Cursor::CursorType cursor_type);
+
+ // Sets the cursor to whatever the current cursor is.
+ void PlatformSpecificSetCursor();
+
+ const std::string& user_agent() const { return user_agent_; }
+ bool IsFirefox() const {
+ return user_agent_.find("Firefox") != user_agent_.npos;
+ }
+ bool IsChrome() const {
+ return user_agent_.find("Chrome") != user_agent_.npos;
+ }
+ bool IsMSIE() const {
+ return user_agent_.find("MSIE") != user_agent_.npos;
+ }
+
+ v8::Handle<v8::Context> script_context() {
+ return np_v8_bridge_.script_context();
+ }
+
+ o3d::NPV8Bridge* np_v8_bridge() { return &np_v8_bridge_; }
+
+ // Creates the renderer.
+ void CreateRenderer(const o3d::DisplayWindow& display_window);
+
+ // Deletes the renderer.
+ void DeleteRenderer();
+
+#ifdef OS_MACOSX
+ // Methods needed for the Safari tab-switching hack.
+ void MacEventReceived();
+
+ CFTimeInterval TimeSinceLastMacEvent();
+
+ bool DetectTabHiding();
+#endif
+
+#ifdef OS_WIN
+ // Stashes a pointer to the plugin on the HWND, and keeps a corresponding
+ // pointer to the HWND on the plugin. If the plugin's already registered with
+ // an HWND, this will clear out the plugin pointer on the old HWND before
+ // setting up the new one.
+ static void StorePluginProperty(HWND hWnd, PluginObject *obj);
+ // Similar to StorePluginProperty, but doesn't clear out any old pointers.
+ static void StorePluginPropertyUnsafe(HWND hWnd, PluginObject *obj);
+ // Looks up the plugin stored on this HWND.
+ static PluginObject *GetPluginProperty(HWND hWnd);
+ // Clears out the plugin stored on this HWND.
+ static void ClearPluginProperty(HWND hWnd);
+ // WNDCLASSEX used for constructing fullscreen windows.
+ static WNDCLASSEX *GetFullscreenWindowClass(
+ HINSTANCE instance, WNDPROC window_proc);
+ // One bit of state that helps us turn the sequence of events that windows
+ // produces on a double click into what JavaScript is expecting.
+ bool got_dblclick_;
+#endif // OS_WIN
+#ifdef OS_LINUX
+ bool in_plugin() const { return in_plugin_; }
+ void set_in_plugin(bool value) { in_plugin_ = value; }
+ Time last_click_time() const { return last_click_time_; }
+ void set_last_click_time(Time value) { last_click_time_ = value; }
+#endif
+
+ private:
+ bool fullscreen_region_valid_;
+ int fullscreen_region_x_;
+ int fullscreen_region_y_;
+ int fullscreen_region_width_;
+ int fullscreen_region_height_;
+ int fullscreen_region_mode_id_;
+#ifdef OS_WIN
+ HWND hWnd_; // The window we are currenlty drawing to (use this)
+ HWND fullscreen_hWnd_; // The fullscreen window if we are fullscreen
+ HWND parent_hWnd_;
+ HWND plugin_hWnd_; // The window we were given inside the browser.
+ HCURSOR cursors_[o3d::Cursor::NUM_CURSORS]; // loaded windows cursors.
+ HCURSOR hCursor_;
+ WNDPROC default_plugin_window_proc_;
+ static WNDCLASSEX fullscreen_class_;
+ static bool fullscreen_class_registered_;
+ bool painted_once_;
+#endif // OS_WIN
+};
+
+} // namespace o3d
+} // namespace glue
+
+
+#endif // O3D_PLUGIN_CROSS_O3D_GLUE_H_
diff --git a/o3d/plugin/cross/out_of_memory.cc b/o3d/plugin/cross/out_of_memory.cc
new file mode 100644
index 0000000..47937f1
--- /dev/null
+++ b/o3d/plugin/cross/out_of_memory.cc
@@ -0,0 +1,231 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// This file implements a failure handler for the new
+// operator and malloc.
+
+// TODO: This does not currently work on linux. The replacement
+// operator new, malloc, etc do not take priority over those declared in
+// the standard libraries.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <wchar.h>
+#include <build/build_config.h>
+
+#ifdef _MSC_VER
+#include <new.h>
+#endif
+
+#ifdef OS_WIN
+#include <windows.h>
+#endif
+
+#if defined(OS_MACOSX) || defined(OS_LINUX)
+#include <dlfcn.h>
+#endif
+
+#include "plugin/cross/out_of_memory.h"
+#include "plugin/cross/plugin_metrics.h"
+
+#ifdef _MSC_VER
+extern "C" {
+ void* _getptd();
+} // _MSC_VER
+#endif
+
+namespace o3d {
+namespace {
+// The reserve is allocated just after the plugin starts.
+// In the event that an allocation fails, the reserve is
+// freed, hopefully freeing enough memory to allow any code
+// run after abort() to do its work.
+const size_t kReserveSize = 1024 * 256;
+void* g_reserve;
+} // namespace anonymous
+
+// This is called when a memory allocation fails in the plugin. Note
+// that it will not be called if a memory allocation fails in another
+// shared library, such as in the c runtime library on platforms where
+// we use a shared c runtime library. In those cases, we have to hope
+// that the allocation failed because new was called (in which case an
+// exception will be thrown but the reserve will not be freed) or that
+// the calling library correctly checks for a NULL return and does
+// something appropriate.
+int HandleOutOfMemory(size_t size) {
+ if (g_reserve != NULL) {
+ // First time round, free the reserve and exit with abort.
+ // This should allow some crash reporting before the process
+ // exits.signal
+ free(g_reserve);
+ g_reserve = NULL;
+
+ // Do this on MacOSX and Linux when they support metrics.
+ // Also, at the time of writing, the matrics logging is not
+ // hooked up to breakpad, so this metric will not get logged
+ // anywhere! Remove this comment when that is done and tested.
+#ifdef OS_WIN
+ ++metric_out_of_memory_total;
+#endif // OS_MACOSX
+
+ fprintf(stderr, "Aborting: out of memory allocating %lu bytes\n",
+ static_cast<unsigned long>(size));
+
+#ifdef OS_WIN
+ // This is different on Windows so that it is comnpatible with
+ // the way that breakpad works. On Windows, it intercepts
+ // exceptions. On unixy platforms, it handles signals. Also,
+ // on Windows, this is friendlier to the browser's own crash
+ // logging (for browsers that log crashes).
+ RaiseException(ERROR_OUTOFMEMORY,
+ EXCEPTION_NONCONTINUABLE_EXCEPTION,
+ 0, NULL);
+#else // OS_WIN
+ abort();
+#endif // OS_WIN
+ } else {
+ // If the handler is reentered, try to exit without raising
+ // SIGABRT (or executing exit handlers).
+ _exit(EXIT_FAILURE);
+ }
+ return 0;
+}
+
+bool SetupOutOfMemoryHandler() {
+#ifdef _MSC_VER
+ // Workaround for MSVC. Sometimes the runtime calls this when
+ // there is not enough memory to allocate the "per-thread
+ // data structure". Calling this forces the "per-thread data
+ // structure" to be allocated.
+ _getptd();
+
+ // This causes malloc failures to call the new handler as well.
+ // It is not necessary to replace the implementations of malloc,
+ // etc under MSVC.
+ _set_new_mode(1);
+ _set_new_handler(HandleOutOfMemory);
+#endif // _MSC_VER
+
+ g_reserve = malloc(kReserveSize);
+
+ return true;
+}
+} // namespace o3d
+
+#if defined(OS_MACOSX) || defined(OS_LINUX)
+namespace {
+void* dlsym_helper(const char* symbol_name) {
+ void* ptr = dlsym(RTLD_NEXT, symbol_name);
+ if (ptr == NULL) {
+ fprintf(stderr, "Error: could not locate symbol \"%s\"\n", symbol_name);
+ abort();
+ }
+ return ptr;
+}
+} // namespace anonymous
+
+void* operator new(size_t size) {
+ return malloc(size);
+}
+
+void operator delete(void* ptr) {
+ free(ptr);
+}
+
+extern "C" {
+void *malloc(size_t size) {
+ typedef void* (*Func)(size_t);
+ static Func func = (Func) dlsym_helper("malloc");
+ void* ptr = func(size);
+ if (ptr == NULL)
+ o3d::HandleOutOfMemory(size);
+ return ptr;
+}
+
+void *realloc(void* old_ptr, size_t new_size) {
+ typedef void* (*Func)(void*, size_t);
+ static Func func = reinterpret_cast<Func>(dlsym_helper("realloc"));
+ void* ptr = func(old_ptr, new_size);
+
+ // realloc() returns NULL when you ask for zero bytes. This differs
+ // from malloc() which returns a pointer to a zero sized allocated block.
+ if (new_size != 0 && ptr == NULL)
+ o3d::HandleOutOfMemory(new_size);
+ return ptr;
+}
+
+void *calloc(size_t num_items, size_t size) {
+ typedef void* (*Func)(size_t, size_t);
+ static Func func = reinterpret_cast<Func>(dlsym_helper("calloc"));
+ void* ptr = func(num_items, size);
+ if (ptr == NULL)
+ o3d::HandleOutOfMemory(size);
+ return ptr;
+}
+
+void *valloc(size_t size) {
+ typedef void* (*Func)(size_t);
+ static Func func = reinterpret_cast<Func>(dlsym_helper("valloc"));
+ void* ptr = func(size);
+ if (ptr == NULL)
+ o3d::HandleOutOfMemory(size);
+ return ptr;
+}
+
+void* memalign(size_t alignment, size_t size) {
+ typedef void* (*Func)(size_t, size_t);
+ static Func func = reinterpret_cast<Func>(dlsym_helper("memalign"));
+ void* ptr = func(alignment, size);
+ if (ptr == NULL)
+ o3d::HandleOutOfMemory(size);
+ return ptr;
+}
+
+char* strdup(const char* ptr) {
+ typedef char* (*Func)(const char*);
+ static Func func = reinterpret_cast<Func>(dlsym_helper("strdup"));
+ char* result = func(ptr);
+ if (ptr != NULL && result == NULL)
+ o3d::HandleOutOfMemory((strlen(ptr) + 1) * sizeof(char));
+ return result;
+}
+
+wchar_t* wcsdup(const wchar_t* ptr) {
+ typedef wchar_t* (*Func)(const wchar_t*);
+ static Func func = reinterpret_cast<Func>(dlsym_helper("wcsdup"));
+ wchar_t* result = func(ptr);
+ if (ptr != NULL && result == NULL)
+ o3d::HandleOutOfMemory((wcslen(ptr) + 1) * sizeof(wchar_t));
+ return result;
+}
+}
+#endif // defined(OS_MACOSX) || defined(OS_LINUX)
diff --git a/o3d/plugin/cross/out_of_memory.h b/o3d/plugin/cross/out_of_memory.h
new file mode 100644
index 0000000..aef1b1e
--- /dev/null
+++ b/o3d/plugin/cross/out_of_memory.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// This file declares a failure handler for the new
+// operator and malloc and a function to set it up.
+
+#ifndef O3D_PLUGIN_CROSS_OUT_OF_MEMORY_H_
+#define O3D_PLUGIN_CROSS_OUT_OF_MEMORY_H_
+
+namespace o3d {
+void HandleOutOfMemory();
+bool SetupOutOfMemoryHandler();
+}
+
+#endif // O3D_PLUGIN_CROSS_OUT_OF_MEMORY_H_
diff --git a/o3d/plugin/cross/plugin_logging.h b/o3d/plugin/cross/plugin_logging.h
new file mode 100644
index 0000000..f69c0a7
--- /dev/null
+++ b/o3d/plugin/cross/plugin_logging.h
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// This file defines the logging object which performs the metric aggregation
+// and uploading. This class takes care of the initialization of the logging
+// object and determining if the user has opted in or out to having logs sent
+// back. Furthermore, there are some helper functions to make testing easier.
+
+#ifndef O3D_PLUGIN_CROSS_PLUGIN_LOGGING_H_
+#define O3D_PLUGIN_CROSS_PLUGIN_LOGGING_H_
+
+#include "statsreport/common/highres_timer.h"
+#include "base/scoped_ptr.h"
+#include "base/basictypes.h"
+
+namespace o3d {
+
+class PluginLogging {
+ public:
+ PluginLogging();
+ virtual ~PluginLogging() {}
+
+ // Check to see if sufficient time has passed to process metrics. If such
+ // time has passed, we reset the timer and proceed with processing metrics.
+ //
+ // Returns true if the metrics were processed properly.
+ bool UpdateLogging();
+
+ // Record how much time the plugin has spent running.
+ virtual void RecordProcessTimes();
+
+ // Takes care of gathering current statistics and uploading them to the server
+ // if necessary.
+ //
+ // Parameters:
+ // exiting - whether the program is exiting
+ //
+ // Returns true if metrics were uploaded and/or aggregated successfully.
+ virtual bool ProcessMetrics(const bool exiting,
+ const bool force_report);
+
+ // A helper function to call AggregateMetrics used for testing. Calls
+ // AggregateMetrics which gathers up the current metrics, puts them in
+ // the registry and then resets them.
+ virtual void DoAggregateMetrics();
+
+ // A helper function for testing. This function calls
+ // stats_report::AggregateAndReportMetrics which will aggregate the metrics
+ // and upload to the server if sufficient time has passed.
+ //
+ // Parameters:
+ // extra_url_argument - extra url to be added after source id (O3D)
+ // and version number
+ // user_agent - eventually the client_id, currently not used
+ //
+ // Returns true if metrics were uploaded successfully. Note: false does
+ // not necessarily mean an error; just that no metrics were uploaded.
+ virtual bool DoAggregateAndReportMetrics(const char* extra_url_arguments,
+ const char* user_agent,
+ const bool force_report);
+
+ // PluginLogging assumes ownership of the timer.
+ void SetTimer(HighresTimer* timer);
+
+ // Factory method for creating the logger and taking care of initialization
+ // and checks for opt-in/out.
+ //
+ // Returns the results CreateUsageStatsLogger which will be a pointer to new
+ // PluginLogging object if the user opted in or NULL if they opted out.
+ //
+ // The existence of a PluginLogging object is used to check if logging is
+ // turned on in other parts of the code.
+ static PluginLogging* InitializeUsageStatsLogging();
+
+ // Access the key determing opt-in. Separated out for testing.
+ // Returns true if the user opted in.
+#ifdef OS_MACOSX
+ static bool GetOptInKeyValue(void);
+#else
+ static bool GetOptInKeyValue(const wchar_t* clientstate_registry_key,
+ const wchar_t* opt_in_registry_key);
+#endif
+
+ // Method for actually creating the logger. Separated out for testing.
+ //
+ // Returns the results CreateUsageStatsLogger which will be a pointer to new
+ // PluginLogging object if the user opted in or NULL if they opted out.
+ //
+ // The existence of a PluginLogging object is used to check if logging is
+ // turned on in other parts of the code.
+ template <class LoggingType>
+ static LoggingType* CreateUsageStatsLogger(const bool opt_in) {
+ if (opt_in == true) {
+ // They opted in!
+ LoggingType* logger = new LoggingType();
+ stats_report::g_global_metrics.Initialize();
+
+ // Do an initial grab of the metrics. Don't pass true for force_report.
+ // This will force an upload of the metrics the first time o3d is run
+ // since the lastTransmission metric will not exist.
+ logger->ProcessMetrics(false, false);
+ return logger;
+ }
+ // Otherwise, they opted out so we make sure the registry is clear
+ ClearLogs();
+ return NULL;
+ }
+
+ // Method for cleaning out the logs. Used if the user opts-out to make sure
+ // we don't retain any information from them.
+ static void ClearLogs();
+
+ private:
+ // Timer for determining the next time aggregation should occur.
+ scoped_ptr<HighresTimer> timer_;
+ uint64 running_time_;
+ uint64 prev_uptime_seconds_;
+ uint64 prev_cputime_seconds_;
+ DISALLOW_COPY_AND_ASSIGN(PluginLogging);
+};
+
+} // namespace o3d
+
+#endif // O3D_PLUGIN_CROSS_PLUGIN_LOGGING_H_
diff --git a/o3d/plugin/cross/plugin_logging_test.cc b/o3d/plugin/cross/plugin_logging_test.cc
new file mode 100644
index 0000000..a480604
--- /dev/null
+++ b/o3d/plugin/cross/plugin_logging_test.cc
@@ -0,0 +1,228 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "plugin/cross/plugin_logging.h"
+#include <shlwapi.h>
+#ifdef OS_WIN
+#include <atlbase.h>
+#endif
+#include "statsreport/metrics.h"
+#include "statsreport/uploader.h"
+#ifdef OS_WIN
+#include "tests/common/win/testing_common.h"
+#endif
+
+// This mock class mimics the timer so that we don't actually have to wait for
+// the timer to timeout in the tests since we're not testing the timer here.
+class MockTimer : public HighresTimer {
+ public:
+ using HighresTimer::Start;
+ MockTimer() : elapsed_ms_(0) {}
+ virtual ULONGLONG GetElapsedMs() const;
+ virtual void SetElapsedMs(const ULONGLONG ms);
+
+ private:
+ ULONGLONG elapsed_ms_;
+};
+
+ULONGLONG MockTimer::GetElapsedMs() const {
+ return elapsed_ms_;
+}
+void MockTimer::SetElapsedMs(const ULONGLONG ms) {
+ elapsed_ms_ = ms;
+}
+
+// This mock class mocks the stats uploader so we don't a) log false stats
+// and b) send hits to the server every time we run the tests.
+class MockStatsUploader : public stats_report::StatsUploader {
+ public:
+ MockStatsUploader() {}
+ ~MockStatsUploader() {}
+ virtual bool UploadMetrics(const char* extra_url_data,
+ const char* user_agent,
+ const char *content);
+};
+
+bool MockStatsUploader::UploadMetrics(const char* extra_url_data,
+ const char* user_agent,
+ const char *content) {
+ // Return true to indicate that they were uploaded successfully.
+ return true;
+}
+
+// This subclass is here just to make the protected methods public, so
+// the testing functions can call them.
+class MockPluginLogging : public o3d::PluginLogging {
+ public:
+ using o3d::PluginLogging::UpdateLogging;
+ using o3d::PluginLogging::SetTimer;
+ MockPluginLogging() : o3d::PluginLogging(),
+ aggregate_metrics_success_(0),
+ upload_metrics_success_(false) {}
+ virtual bool ProcessMetrics(const bool exiting, const bool force_report);
+ virtual void DoAggregateMetrics();
+ virtual bool DoAggregateAndReportMetrics(const char* extra_url_arguments,
+ const char* user_agent,
+ const bool force_report);
+ void SetAggregateMetricsSuccess(const int value);
+ int AggregateMetricsSuccess();
+ int UploadMetricsSuccess();
+ private:
+ int aggregate_metrics_success_;
+ bool upload_metrics_success_;
+};
+
+bool MockPluginLogging::ProcessMetrics(const bool exiting,
+ const bool force_report) {
+ return true;
+}
+
+void MockPluginLogging::DoAggregateMetrics() {
+ aggregate_metrics_success_ = 1;
+}
+
+bool MockPluginLogging::DoAggregateAndReportMetrics(
+ const char* extra_url_arguments,
+ const char* user_agent,
+ const bool force_report) {
+ aggregate_metrics_success_ = 2;
+ MockStatsUploader stats_uploader;
+ upload_metrics_success_ = TestableAggregateAndReportMetrics(
+ extra_url_arguments,
+ user_agent,
+ force_report,
+ &stats_uploader);
+ return upload_metrics_success_;
+}
+
+void MockPluginLogging::SetAggregateMetricsSuccess(const int value) {
+ aggregate_metrics_success_ = value;
+}
+
+int MockPluginLogging::AggregateMetricsSuccess() {
+ return aggregate_metrics_success_;
+}
+
+int MockPluginLogging::UploadMetricsSuccess() {
+ return upload_metrics_success_;
+}
+
+// Test fixture for the PluginLogging tests.
+class PluginLoggingTests : public testing::Test {
+ protected:
+ virtual void SetUp();
+ virtual void TearDown();
+
+ MockPluginLogging* plugin_logging() { return plugin_logging_; }
+ void SetPluginLogging(MockPluginLogging* plugin_logging_in) {
+ plugin_logging_ = plugin_logging_in;
+ }
+ MockTimer* mock_timer() { return mock_timer_; }
+
+ private:
+ MockPluginLogging* plugin_logging_;
+ MockTimer* mock_timer_;
+};
+
+void PluginLoggingTests::SetUp() {
+ HRESULT hr = CoInitialize(NULL);
+ mock_timer_ = new MockTimer();
+ plugin_logging_ = new MockPluginLogging();
+ plugin_logging_->SetTimer(mock_timer_);
+ stats_report::g_global_metrics.Initialize();
+}
+
+void PluginLoggingTests::TearDown() {
+ // Only unitialize if a plugin_logging_ exists.
+ // If it does not exist, it means we also never initialized.
+ if (plugin_logging_) {
+ delete plugin_logging_;
+ stats_report::g_global_metrics.Uninitialize();
+ }
+}
+
+// Test if the metric collection is properly initialized.
+TEST_F(PluginLoggingTests, InitializeMetricCollection) {
+ EXPECT_TRUE(stats_report::g_global_metrics.initialized());
+}
+
+// Tests the PluginLogging's metric processing functions.
+TEST_F(PluginLoggingTests, ProcessMetricsTests) {
+ EXPECT_FALSE(plugin_logging()->UpdateLogging());
+ // NOTE: This time should be greater than the desired time.
+ mock_timer()->SetElapsedMs(5 * 60 * 1000);
+ EXPECT_TRUE(plugin_logging()->UpdateLogging());
+
+ // This time should be less than the interval.
+ mock_timer()->SetElapsedMs(1000);
+ EXPECT_FALSE(plugin_logging()->UpdateLogging());
+}
+
+// Tests that the proper method to aggregate metrics was called.
+TEST_F(PluginLoggingTests, AggregateMetricsTests) {
+ // Start by initializing the variable which tells us success or not.
+ plugin_logging()->SetAggregateMetricsSuccess(0);
+ // Pass false for "exiting" parameter to call AggregateMetrics.
+ // Value does not matter for "force_report" for this testt so pass false.
+ EXPECT_TRUE(plugin_logging()->PluginLogging::ProcessMetrics(true, false));
+ EXPECT_EQ(plugin_logging()->AggregateMetricsSuccess(), 1);
+
+ plugin_logging()->SetAggregateMetricsSuccess(0);
+ // Pass true for "exiting" parameter to call AggregateAndReportMetrics.
+ // Value does not matter for "force_report" for this testt so pass false.
+ EXPECT_TRUE(plugin_logging()->PluginLogging::ProcessMetrics(false, false));
+ EXPECT_EQ(plugin_logging()->AggregateMetricsSuccess(), 2);
+}
+
+// Check that the force_report boolean forces reporting of the metrics.
+TEST_F(PluginLoggingTests, CheckForceReport) {
+ // Using this call rather than just calling TestableAggregateAndReportMetrics
+ // directly because this is the stand alone call that we want to test.
+ // Pass false for "exiting" since reporting does not happen otherwise.
+ EXPECT_TRUE(plugin_logging()->PluginLogging::ProcessMetrics(false, true));
+}
+
+// Tests that when opt_in is turned on we create a logger and process metrics.
+TEST_F(PluginLoggingTests, CheckOptIn) {
+ TearDown();
+ SetPluginLogging(
+ o3d::PluginLogging::CreateUsageStatsLogger<MockPluginLogging>(true));
+ EXPECT_TRUE(plugin_logging());
+}
+
+// Tests that when opt_in is turned OFF we do not create a logger.
+TEST_F(PluginLoggingTests, CheckOptOut) {
+ TearDown();
+ SetPluginLogging(
+ o3d::PluginLogging::CreateUsageStatsLogger<MockPluginLogging>(false));
+ EXPECT_FALSE(plugin_logging());
+}
diff --git a/o3d/plugin/cross/plugin_main.h b/o3d/plugin/cross/plugin_main.h
new file mode 100644
index 0000000..e0af989
--- /dev/null
+++ b/o3d/plugin/cross/plugin_main.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#ifndef TOOLS_IDLGLUE_NG_O3D_GLUE_PLUGIN_MAIN_H__
+#define TOOLS_IDLGLUE_NG_O3D_GLUE_PLUGIN_MAIN_H__
+
+#include "plugin/cross/o3d_glue.h"
+
+#endif // TOOLS_IDLGLUE_NG_O3D_GLUE_PLUGIN_MAIN_H__
diff --git a/o3d/plugin/cross/plugin_metrics.h b/o3d/plugin/cross/plugin_metrics.h
new file mode 100644
index 0000000..97e9807
--- /dev/null
+++ b/o3d/plugin/cross/plugin_metrics.h
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// Declares the system metrics used by the plugin.
+
+#ifndef O3D_PLUGIN_CROSS_PLUGIN_METRICS_H_
+#define O3D_PLUGIN_CROSS_PLUGIN_METRICS_H_
+
+#include "statsreport/metrics.h"
+
+namespace o3d {
+// NOTE: DO NOT REORDER THESE ENUMS!
+// This enum will be used by stats analysis code as well and they must stay in
+// sync. When this stat is reported, it only reports an integer that we compare
+// against this enum so the order is very important.
+// We start at 1, as 0 is reserved for "no value", ie we didn't check.
+enum BrowserTypeName {
+ BROWSER_NAME_UNKNOWN = 1,
+ BROWSER_NAME_CHROME,
+ BROWSER_NAME_SAFARI,
+ BROWSER_NAME_FIREFOX,
+ BROWSER_NAME_MSIE,
+ BROWSER_NAME_OPERA,
+ BROWSER_NAME_CAMINO,
+ BROWSER_NAME_OMNIWEB
+};
+
+// This enum is simply for easy viewing of data
+enum SystemType {
+ SYSTEM_NAME_WIN = 1,
+ SYSTEM_NAME_MAC,
+ SYSTEM_NAME_LINUX
+};
+
+// User operating system
+DECLARE_METRIC_integer(system_type);
+
+DECLARE_METRIC_integer(windows_major_version);
+DECLARE_METRIC_integer(windows_minor_version);
+DECLARE_METRIC_integer(windows_sp_major_version);
+DECLARE_METRIC_integer(windows_sp_minor_version);
+
+DECLARE_METRIC_integer(mac_major_version);
+DECLARE_METRIC_integer(mac_minor_version);
+DECLARE_METRIC_integer(mac_bugfix_version);
+
+DECLARE_METRIC_integer(gl_major_version);
+DECLARE_METRIC_integer(gl_minor_version);
+DECLARE_METRIC_integer(gl_hlsl_major_version);
+DECLARE_METRIC_integer(gl_hlsl_minor_version);
+
+
+DECLARE_METRIC_bool(POW2_texture_caps);
+DECLARE_METRIC_bool(NONPOW2CONDITIONAL_texture_caps);
+
+// User GPU
+DECLARE_METRIC_integer(gpu_vendor_id);
+DECLARE_METRIC_integer(gpu_device_id);
+DECLARE_METRIC_integer(gpu_driver_major_version);
+DECLARE_METRIC_integer(gpu_driver_minor_version);
+DECLARE_METRIC_integer(gpu_driver_bugfix_version);
+DECLARE_METRIC_integer(gpu_vram_size);
+DECLARE_METRIC_bool(direct3d_available);
+
+
+// Shader versions
+DECLARE_METRIC_integer(pixel_shader_main_version);
+DECLARE_METRIC_integer(pixel_shader_sub_version);
+DECLARE_METRIC_integer(vertex_shader_main_version);
+DECLARE_METRIC_integer(vertex_shader_sub_version);
+
+// Browser
+DECLARE_METRIC_integer(browser_type);
+DECLARE_METRIC_integer(browser_major_version);
+DECLARE_METRIC_integer(browser_minor_version);
+DECLARE_METRIC_integer(browser_bugfix_version);
+
+// Running time for instance of plugin
+DECLARE_METRIC_count(uptime_seconds);
+DECLARE_METRIC_count(cpu_time_seconds);
+DECLARE_METRIC_timing(running_time_seconds);
+
+// Crashes
+// How many times the plugin has crashed. Not all crashes may be reported.
+DECLARE_METRIC_count(crashes_total);
+DECLARE_METRIC_count(crashes_uploaded);
+DECLARE_METRIC_count(out_of_memory_total);
+
+// Bluescreens
+// How many times has the plugin caused a bluescreen of death
+DECLARE_METRIC_count(bluescreens_total);
+
+// D3D Caps
+DECLARE_METRIC_integer(d3d_devcaps);
+DECLARE_METRIC_integer(d3d_misccaps);
+DECLARE_METRIC_integer(d3d_rastercaps);
+DECLARE_METRIC_integer(d3d_zcmpcaps);
+DECLARE_METRIC_integer(d3d_srcblendcaps);
+DECLARE_METRIC_integer(d3d_dstblendcaps);
+DECLARE_METRIC_integer(d3d_alphacaps);
+DECLARE_METRIC_integer(d3d_texcaps);
+DECLARE_METRIC_integer(d3d_texfiltercaps);
+DECLARE_METRIC_integer(d3d_cubetexfiltercaps);
+DECLARE_METRIC_integer(d3d_texaddrcaps);
+DECLARE_METRIC_integer(d3d_linecaps);
+DECLARE_METRIC_integer(d3d_stencilcaps);
+DECLARE_METRIC_integer(d3d_texopcaps);
+DECLARE_METRIC_integer(d3d_vs20caps);
+DECLARE_METRIC_integer(d3d_vs20_dynflowctrldepth);
+DECLARE_METRIC_integer(d3d_vs20_numtemps);
+DECLARE_METRIC_integer(d3d_vs20_staticflowctrldepth);
+DECLARE_METRIC_integer(d3d_ps20caps);
+DECLARE_METRIC_integer(d3d_ps20_dynflowctrldepth);
+DECLARE_METRIC_integer(d3d_ps20_numtemps);
+DECLARE_METRIC_integer(d3d_ps20_staticflowctrldepth);
+DECLARE_METRIC_integer(d3d_ps20_numinstrslots);
+
+// Installs and uninstalls
+// TODO: Will likely need to get from Google Update
+
+} // namespace o3d
+
+#endif // O3D_PLUGIN_CROSS_PLUGIN_METRICS_H_
diff --git a/o3d/plugin/cross/stream_manager.cc b/o3d/plugin/cross/stream_manager.cc
new file mode 100644
index 0000000..07f25a2
--- /dev/null
+++ b/o3d/plugin/cross/stream_manager.cc
@@ -0,0 +1,356 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "plugin/cross/stream_manager.h"
+
+#include <algorithm>
+#include <map>
+
+#include "base/logging.h"
+#include "plugin/cross/o3d_glue.h"
+#include "third_party/nixysa/files/static_glue/npapi/common.h"
+
+namespace glue {
+
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+StreamManager::StreamManager(NPP plugin_instance)
+ : plugin_instance_(plugin_instance) {
+}
+
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+StreamManager::~StreamManager() {
+ // If the destructor gets called while streams are in mid-flight then delete
+ // them here to make sure we can garbage collect cleanly.
+ std::vector<NPDownloadStream *>::iterator it;
+ for (it = entries_.begin(); it < entries_.end(); ++it) {
+ delete (*it);
+ }
+ entries_.clear();
+}
+
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+DownloadStream *StreamManager::LoadURL(const std::string &url,
+ NewStreamCallback *new_stream_callback,
+ WriteReadyCallback *write_ready_callback,
+ WriteCallback *write_callback,
+ FinishedCallback *finished_callback,
+ uint16 stream_type) {
+ DCHECK(finished_callback != NULL);
+
+ NPDownloadStream *entry = new NPDownloadStream(url,
+ "",
+ stream_type,
+ plugin_instance_,
+ new_stream_callback,
+ write_ready_callback,
+ write_callback,
+ finished_callback);
+
+ GLUE_PROFILE_START(plugin_instance_, "geturlnotify");
+ // NPN_GetURLNotify may call-back into the plug-in before returning, so
+ // add the download stream entry before making the call.
+ entries_.push_back(entry);
+ NPError ret = NPN_GetURLNotify(plugin_instance_, url.c_str(), NULL, entry);
+ GLUE_PROFILE_STOP(plugin_instance_, "geturlnotify");
+ if (ret != NPERR_NO_ERROR) {
+ // If the operation failed, it's possible that the browser hosting
+ // environment did not call the appropriate notify routines which
+ // clean up the entries_ stack. We check if the entry is still
+ // at the top, and delete it here.
+ if (!entries_.empty() && entries_.back() == entry) {
+ entries_.pop_back();
+ // NOTE: Should we run the finished_callback here ?
+ delete entry;
+ entry = NULL;
+ }
+ }
+ return entry;
+}
+
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool StreamManager::CheckEntry(NPDownloadStream *entry) {
+ std::vector<NPDownloadStream *>::iterator it =
+ std::find(entries_.begin(), entries_.end(), entry);
+ return it != entries_.end();
+}
+
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool StreamManager::NewStream(NPStream *stream, uint16 *stype) {
+ NPDownloadStream *entry = static_cast<NPDownloadStream*>(stream->notifyData);
+ if (!CheckEntry(entry)) {
+ // We got a new stream, but we don't know about it.
+ return false;
+ }
+ return entry->NewStream(stream, stype);
+}
+
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool StreamManager::DestroyStream(NPStream *stream, NPReason reason) {
+ NPDownloadStream *entry = static_cast<NPDownloadStream*>(stream->notifyData);
+ if (!CheckEntry(entry)) {
+ // We don't know about this stream.
+ return false;
+ }
+ DCHECK_EQ(stream, entry->GetStream());
+
+ return entry->DestroyStream(reason);
+}
+
+
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool StreamManager::SetStreamFile(NPStream *stream, const char *filename) {
+ NPDownloadStream *entry = static_cast<NPDownloadStream*>(stream->notifyData);
+ if (!CheckEntry(entry)) {
+ // We don't know about this stream.
+ return false;
+ }
+ DCHECK_EQ(stream, entry->GetStream());
+
+ return entry->SetStreamFile(filename);
+}
+
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool StreamManager::URLNotify(const char *url,
+ NPReason reason,
+ void *notifyData) {
+ NPDownloadStream *entry = static_cast<NPDownloadStream *>(notifyData);
+ if (!CheckEntry(entry)) {
+ // We don't know about this stream.
+ return false;
+ }
+
+ std::vector<NPDownloadStream *>::iterator it =
+ std::find(entries_.begin(), entries_.end(), entry);
+ DCHECK(it != entries_.end());
+ entries_.erase(it);
+
+ bool result = entry->URLNotify(reason);
+ delete entry;
+ return result;
+}
+
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+int32 StreamManager::WriteReady(NPStream *stream) {
+ NPDownloadStream *entry = static_cast<NPDownloadStream*>(stream->notifyData);
+ if (!CheckEntry(entry)) {
+ // We don't know about this stream.
+ return 0;
+ }
+
+ return entry->WriteReady();
+}
+
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+int32 StreamManager::Write(NPStream *stream,
+ int32 offset,
+ int32 len,
+ void *buffer) {
+ NPDownloadStream *entry = static_cast<NPDownloadStream*>(stream->notifyData);
+ if (!CheckEntry(entry)) {
+ // We don't know about this stream.
+ return 0;
+ }
+
+ return entry->Write(offset, len, buffer);
+}
+
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// DownloadStream implementation
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+StreamManager::NPDownloadStream::~NPDownloadStream() {
+}
+
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+std::string StreamManager::NPDownloadStream::GetURL() {
+ return url_;
+}
+
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+std::string StreamManager::NPDownloadStream::GetCachedFile() {
+ return file_;
+}
+
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+DownloadStream::State StreamManager::NPDownloadStream::GetState() {
+ return state_;
+}
+
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+int StreamManager::NPDownloadStream::GetReceivedByteCount() {
+ return bytes_received_;
+}
+
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+size_t StreamManager::NPDownloadStream::GetStreamLength() {
+ return stream_ ? stream_->end : 0;
+}
+
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+void StreamManager::NPDownloadStream::Cancel() {
+ NPN_DestroyStream(plugin_instance_, stream_, NPRES_USER_BREAK);
+ state_ = STREAM_FINISHED;
+}
+
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// NPDownloadStream implementation
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+typedef std::map<std::string, std::string> StringMap;
+
+// Extracts headers from the browser-returned header string, as a name->value
+// map.
+static StringMap ExtractHeaders(const char *header_string) {
+ using std::string;
+ StringMap map;
+ if (!header_string) return map;
+ string headers = header_string;
+ // Doc says headers as returned by the browser are LF-terminated, including
+ // the last one.
+ // It's unclear if they are rewritten by the browser to be in a "canonical"
+ // form (i.e. single-line, no extra space etc.). We currently assume that
+ // they are.
+ // TODO: verify this, and/or implement correct parsing to handle RFC
+ // 1945/2616 parsing.
+ string::size_type index = 0;
+ while (index < headers.size()) {
+ string::size_type eol = std::min(headers.size(), headers.find("\n", index));
+ string line = headers.substr(index, eol-index);
+ string::size_type separator = line.find(":");
+ if (separator != string::npos) {
+ string key = line.substr(0, separator);
+ string value;
+ if (separator + 1 < line.size()) {
+ string::size_type value_index =
+ line.find_first_not_of(" \t", separator + 1);
+ if (value_index != string::npos)
+ value = line.substr(value_index);
+ }
+ map[key] = value;
+ }
+ index = eol + 1;
+ }
+
+ return map;
+}
+
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool StreamManager::NPDownloadStream::NewStream(NPStream *new_stream,
+ uint16 *stype) {
+ stream_ = new_stream;
+ state_ = DownloadStream::STREAM_STARTED;
+ *stype = stream_type_;
+
+ // callback if provided
+ if (new_stream_callback_.get()) {
+ new_stream_callback_->Run(this);
+ }
+
+ return true;
+}
+
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool StreamManager::NPDownloadStream::DestroyStream(NPReason reason) {
+ stream_ = NULL;
+ state_ = DownloadStream::STREAM_FINISHED;
+ return true;
+}
+
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool StreamManager::NPDownloadStream::SetStreamFile(const char *filename) {
+ if (finished_callback_.get()) {
+ StringMap header_map = ExtractHeaders(stream_->headers);
+ std::string mime_type = header_map["Content-Type"];
+ file_ = filename;
+ // On success, run the finished_callback.
+ if (file_.size() != 0) {
+ // finished_callback should only be called once.
+ finished_callback_->Run(this, true, file_, mime_type);
+ finished_callback_.reset(NULL);
+ }
+ }
+
+ return true;
+}
+
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool StreamManager::NPDownloadStream::URLNotify(NPReason reason) {
+ if (finished_callback_.get()) {
+ // On failure, run the finished_callback.
+ // Note that the streaming case (NP_NORMAL) does not get a file
+ // so we can't check its size
+ if ((reason != NPRES_DONE) ||
+ (stream_type_ != NP_NORMAL && file_.size() == 0)) {
+ // finished_callback should only be called once.
+ finished_callback_->Run(this, false, "", "");
+ finished_callback_.reset(NULL);
+ }
+
+ // Finished callback for streaming case
+ // where SetStreamFile() is not called
+ if (reason == NPRES_DONE && stream_type_ == NP_NORMAL) {
+ finished_callback_->Run(this, true, "", "");
+ finished_callback_.reset(NULL);
+ }
+ }
+
+ new_stream_callback_.reset(NULL);
+ write_ready_callback_.reset(NULL);
+ write_callback_.reset(NULL);
+
+ return true;
+}
+
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+int32 StreamManager::NPDownloadStream::WriteReady() {
+ if (write_ready_callback_.get()) {
+ return write_ready_callback_->Run(this);
+ }
+
+ return 4096;
+}
+
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+int32 StreamManager::NPDownloadStream::Write(int32 offset,
+ int32 len,
+ void *buffer) {
+ if (write_callback_.get()) {
+ int32 n = write_callback_->Run(this, offset, len, buffer);
+ bytes_received_ += n;
+ return n;
+ }
+
+ return len;
+}
+
+} // namespace glue
diff --git a/o3d/plugin/cross/stream_manager.h b/o3d/plugin/cross/stream_manager.h
new file mode 100644
index 0000000..f7c6723
--- /dev/null
+++ b/o3d/plugin/cross/stream_manager.h
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#ifndef EXPERIMENTAL_O3D_O3DPLUGIN_AUTOGEN_O3D_GLUE_STREAM_MANAGER_H_
+#define EXPERIMENTAL_O3D_O3DPLUGIN_AUTOGEN_O3D_GLUE_STREAM_MANAGER_H_
+
+#include <npapi.h>
+#include <string>
+#include <vector>
+#include "base/scoped_ptr.h"
+#include "core/cross/callback.h"
+#include "plugin/cross/download_stream.h"
+
+namespace glue {
+
+// Stream manager class, to help managing asynchronous loading of URLs into
+// files.
+class StreamManager {
+ public:
+ // TODO : get rid of these horrible callback objects
+ // and use an interface instead
+ typedef o3d::Callback1<DownloadStream*> NewStreamCallback;
+
+ typedef o3d::Callback4<DownloadStream*,
+ bool,
+ const std::string &,
+ const std::string &> FinishedCallback;
+
+ // The signature for these callbacks corresponds to the NPP_WriteReady()
+ // and NPP_Write() calls
+ typedef o3d::ResultCallback1<int32, DownloadStream*> WriteReadyCallback;
+
+ typedef o3d::ResultCallback4<int32,
+ DownloadStream*,
+ int32,
+ int32,
+ void*> WriteCallback;
+
+ explicit StreamManager(NPP plugin_instance);
+ ~StreamManager();
+
+ // Loads URL into a file, calls finished_callback->Run(success, filename)
+ // when done.
+ // returns a DownloadStream object (or NULL) if error
+ // filename is the name of the file where the contents of the URL are
+ // stored.
+ // LoadURL() takes ownership of new_stream_callback, write_ready_callback,
+ // write_callback, and callback: They will be deleted once the stream has
+ // completed.
+ DownloadStream *LoadURL(const std::string &url,
+ NewStreamCallback *new_stream_callback,
+ WriteReadyCallback *write_ready_callback,
+ WriteCallback *write_callback,
+ FinishedCallback *callback,
+ uint16 stream_type);
+
+ // Manages the NPP_NewStream callback.
+ bool NewStream(NPStream *stream, uint16 *stype);
+ // Manages the NPP_DestroyStream callback.
+ bool DestroyStream(NPStream *stream, NPReason reason);
+ // Manages the NPP_StreamAsFile callback.
+ bool SetStreamFile(NPStream *stream, const char *filename);
+ // Manages the NPP_URLNotify callback.
+ bool URLNotify(const char *url, NPReason reason, void *notifyData);
+
+ // Continuous streaming support
+ int32 WriteReady(NPStream *stream);
+ int32 Write(NPStream *stream, int32 offset, int32 len, void *buffer);
+
+ private:
+ class NPDownloadStream : public DownloadStream {
+ public:
+ NPDownloadStream(const std::string &url,
+ const std::string &file,
+ uint16 stream_type,
+ NPP plugin_instance,
+ NewStreamCallback *new_stream_callback,
+ WriteReadyCallback *write_ready_callback,
+ WriteCallback *write_callback,
+ FinishedCallback *callback)
+ : url_(url),
+ file_(file),
+ stream_type_(stream_type),
+ plugin_instance_(plugin_instance),
+ stream_(NULL),
+ new_stream_callback_(new_stream_callback),
+ write_ready_callback_(write_ready_callback),
+ write_callback_(write_callback),
+ finished_callback_(callback),
+ bytes_received_(0),
+ state_(STREAM_REQUESTED) {}
+
+ virtual ~NPDownloadStream();
+
+ // DownloadStream interface
+ virtual std::string GetURL();
+ virtual std::string GetCachedFile();
+ virtual State GetState();
+ virtual int GetReceivedByteCount();
+ virtual size_t GetStreamLength();
+ virtual void Cancel();
+
+ // NPAPI stream stuff
+ NPStream *GetStream() const { return stream_; }
+ bool NewStream(NPStream *new_stream, uint16 *stype);
+ bool DestroyStream(NPReason reason);
+ bool SetStreamFile(const char *filename);
+ bool URLNotify(NPReason reason);
+ int32 WriteReady();
+ int32 Write(int32 offset, int32 len, void *buffer);
+
+
+ private:
+ std::string url_;
+ std::string file_;
+
+ // stream type (as file or continuous stream)
+ uint16 stream_type_;
+
+ NPP plugin_instance_;
+ NPStream *stream_;
+
+ // callbacks
+ scoped_ptr<NewStreamCallback> new_stream_callback_;
+ scoped_ptr<WriteReadyCallback> write_ready_callback_;
+ scoped_ptr<WriteCallback> write_callback_;
+ scoped_ptr<FinishedCallback> finished_callback_;
+
+ int bytes_received_;
+ State state_;
+ };
+ bool CheckEntry(NPDownloadStream *entry);
+
+ NPP plugin_instance_;
+ std::vector<NPDownloadStream *> entries_;
+};
+
+} // namespace glue
+
+#endif // EXPERIMENTAL_O3D_O3DPLUGIN_AUTOGEN_O3D_GLUE_STREAM_MANAGER_H_
diff --git a/o3d/plugin/idl/archive_request.idl b/o3d/plugin/idl/archive_request.idl
new file mode 100644
index 0000000..1633a46
--- /dev/null
+++ b/o3d/plugin/idl/archive_request.idl
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace o3d {
+
+[include="import/cross/archive_request.h"]
+callback void ArchiveRequestCallback();
+
+%[
+ An ArchiveRequest object is used to carry out an asynchronous request for a
+ compressed archive (containing multiple files).
+
+ Note: The archive must have as its first file a file named 'aaaaaaaa.o3d'
+ who's contents is 'o3d'. This is to prevent O3D being used to open
+ archive files that were not meant for it.
+
+ \code
+ var request = pack.createArchiveRequest();
+ request.open("GET", url);
+
+ request.onfileavailable = myFileAvailableCallback;
+ request.onreadystatechange = myReadyStateChangeCallback;
+ request.send();
+
+ function myFileAvailableCallback() {
+ dump("uri: " + request.data.uri + "\n");
+ dump("content: " + request.data.stringValue + "\n");
+
+ // You can pass a RawData to various creation functions. Note: request.data
+ // is only valid during an onfileavailable callback.
+ // Examples:
+ if (request.data.uri == 'mytexture.jpg')
+ pack.createTexture2d(request.data, makeMips);
+ if (request.data.uri == 'myvertices.bin')
+ vertexBuffer.set(request.data);
+ if (request.data.uri == 'myAudio.mp3')
+ audioSystem.createSound(request.data);
+ }
+
+ function myReadyStateChangeCallback() {
+ if (request.done) {
+ if (request.success) {
+ // there were no errors trying to read the archive
+ } else {
+ dump(request.error);
+ }
+ }
+ }
+
+ // When you are done with the RawDatas loaded by the request, remove
+ // the request from the pack to free them.
+ pack.removeObject(request);
+ \endcode
+%]
+
+[nocpp, include="import/cross/archive_request.h"] class ArchiveRequest
+ : ObjectBase {
+ %[
+ A callback that gets called each time readyState changes.
+ %]
+ [setter]
+ ArchiveRequestCallback? onreadystatechange;
+
+ %[
+ A callback that gets called each time a file fully downloads and becomes
+ available.
+ %]
+ [setter]
+ ArchiveRequestCallback? onfileavailable;
+
+ %[
+ The uri of the archive being downloaded.
+ %]
+ [getter] String uri;
+
+ %[
+ A RawData object representing the file that is currently available.
+ Note: This value is only valid inside the onfileavailable callback.
+ %]
+ [getter] RawData? data;
+
+ %[
+ The length of the entire archive in bytes.
+
+ Use this value along with bytesReceived to figure out the download progress.
+ %]
+ [getter] int streamLength;
+
+ %[
+ The number of bytes downloaded so far.
+
+ You can use this value along with streamLength to figure out the download
+ progress.
+ %]
+ [getter] int bytesReceived;
+
+ %[
+ Holds the same values as in XMLHttpRequest:
+ \li 0 = uninitialized
+ \li 1 = opened
+ \li 2 = sent
+ \li 3 = receiving
+ \li 4 = loaded (the file has been downloaded, but may or may not have been
+ parsed yet)
+ %]
+ [getter] int readyState;
+
+ %[
+ Indicates whether processing for this FileRequest has finished.
+ %]
+ [getter] bool done;
+
+ %[
+ This field is only valid if done is true. It indicates whether or not the
+ request succeeded. If false see error for an error message.
+ %]
+ [getter] bool success;
+
+ %[
+ An error message.
+ If done is true and success is false this will be an error message
+ describing what went wrong.
+ %]
+ [getter] String error;
+
+ %[
+ Sets up several of the request fields.
+ \param method "GET" is the only supported method at this time
+ \param uri the location of the file to fetch
+ %]
+ [nocpp, userglue, plugin_data] void open(
+ String method, String uri);
+
+ %[
+ Send the request.
+ Unlike XMLHttpRequest the onreadystatechange callback will be called no
+ matter what, with success or failure.
+ %]
+ [nocpp, userglue, plugin_data] void send();
+};
+
+} // namespace o3d
diff --git a/o3d/plugin/idl/bounding_box.idl b/o3d/plugin/idl/bounding_box.idl
new file mode 100644
index 0000000..b8ac932
--- /dev/null
+++ b/o3d/plugin/idl/bounding_box.idl
@@ -0,0 +1,210 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// TODO: some how make this file conditionally compile different for C++
+// vs Javascript like with #ifdef CPLUSPLUS etc..
+namespace o3d {
+
+%[
+ A BoundingBox represents an Axis Aligned Bounding Box.
+%]
+[binding_model=by_value, marshaled, nocpp, include="core/cross/bounding_box.h"]
+class BoundingBox {
+ %[
+ Creates BoundingBox from min_extent and max_extent
+ \param min_extent minimum extent of the box.
+ \param max_extent maximum extent of the box.
+ %]
+ BoundingBox(Vectormath::Aos::Point3 min_extent,
+ Vectormath::Aos::Point3 max_extent);
+
+ %[
+ Assigns a JavaScript array of arrays of numbers into a BoundingBox.
+ This property is implicitly invoked whenever such an array is assigned to
+ a BoundingBox property or such an array is passed as a BoundingBox method
+ parameter.
+ %]
+ [plugin_data, userglue, userglue_setter, setter, nodocs]
+ float[][] marshaled;
+
+ %[
+ True if this boundingbox has been initialized.
+ %]
+ [getter] bool valid_;
+
+ %[
+ The min extent of the box.
+ %]
+ [getter] Vectormath::Aos::Point3 min_extent;
+
+ %[
+ The max extent of the box.
+ %]
+ [getter] Vectormath::Aos::Point3 max_extent;
+
+ %[
+ Multiplies the bounding box by the given matrix returning a new bounding
+ box.
+ \param matrix The matrix to multiply by.
+ \returns The new bounding box.
+ %]
+ [const, userglue] BoundingBox Mul(Vectormath::Aos::Matrix4 matrix);
+
+ %[
+ Adds a bounding box to this bounding box returning a bounding box that
+ encompases both.
+ \return The new bounding box.
+ %]
+ [const, userglue] BoundingBox Add(BoundingBox box);
+
+ %[
+ Checks if a ray defined in same coordinate system as this box intersects
+ this bounding box.
+ \param start position of start of ray in local space.
+ \param end position of end of ray in local space.
+ \return RayIntersectionInfo. If result.value is false then something was
+ wrong like using this function with an uninitialized bounding box. If
+ result.intersected is true then the ray intersected the box
+ and result.position is the exact point of intersection.
+ %]
+ [const, userglue]
+ o3d::RayIntersectionInfo IntersectRay(Vectormath::Aos::Point3 start,
+ Vectormath::Aos::Point3 end);
+
+ %[
+ Checks if a ray defined in same coordinate system as this box intersects
+ this bounding box.
+ \param startX The x coordinate of start of ray in local space.
+ \param startY The y coordinate of start of ray in local space.
+ \param startZ The z coordinate of start of ray in local space.
+ \param endX The x coordinate of end of ray in local space.
+ \param endY The y coordinate of end of ray in local space.
+ \param endZ The z coordinate of end of ray in local space.
+ \return RayIntersectionInfo. If result.value is false then something was
+ wrong like using this function with an uninitialized bounding box. If
+ result.intersected is true then the ray intersected the box
+ and result.position is the exact point of intersection.
+ %]
+ [const, userglue]
+ o3d::RayIntersectionInfo IntersectRay(float startX,
+ float startY,
+ float startZ,
+ float endX,
+ float endY,
+ float endZ);
+
+ %[
+ Returns true if the bounding box is inside the frustum.
+ \param matrix Matrix to transform the box from its local space to view
+ frustum space.
+ \return True if the box is in the frustum.
+ %]
+ [const] bool InFrustum(Vectormath::Aos::Matrix4 matrix);
+
+ [verbatim=cpp_glue] %{
+ void userglue_setter_marshaled(
+ void* plugin_data,
+ o3d::BoundingBox* _this,
+ const std::vector<std::vector<float> >& values) {
+ if (values.size() == 0) {
+ *_this = o3d::BoundingBox();
+ } else if (values.size() != 2) {
+ o3d::ServiceLocator* service_locator =
+ static_cast<glue::_o3d::PluginObject*>(
+ plugin_data)->service_locator();
+ O3D_ERROR(service_locator)
+ << "BoundingBox: expected 2 values, got " << values.size();
+ } else {
+ for (int i = 0; i < values.size(); ++i) {
+ if (values[i].size() != 3) {
+ o3d::ServiceLocator* service_locator =
+ static_cast<glue::_o3d::PluginObject*>(
+ plugin_data)->service_locator();
+ O3D_ERROR(service_locator)
+ << "BoundingBox: expected 3 values, got " << values.size();
+ return;
+ }
+ }
+ *_this = o3d::BoundingBox(
+ Vectormath::Aos::Point3(values[0][0], values[0][1], values[0][2]),
+ Vectormath::Aos::Point3(values[1][0], values[1][1], values[1][2]));
+ }
+ }
+ o3d::BoundingBox userglue_method_Mul(
+ o3d::BoundingBox* self,
+ const Vectormath::Aos::Matrix4 &matrix) {
+ o3d::BoundingBox bounding_box;
+ self->Mul(matrix, &bounding_box);
+ return bounding_box;
+ }
+ o3d::BoundingBox userglue_method_Add(
+ o3d::BoundingBox* self,
+ const o3d::BoundingBox& box) {
+ o3d::BoundingBox result;
+ self->Add(box, &result);
+ return result;
+ }
+ o3d::RayIntersectionInfo userglue_method_IntersectRay(
+ o3d::BoundingBox* self,
+ const Vectormath::Aos::Point3& start,
+ const Vectormath::Aos::Point3& end) {
+ o3d::RayIntersectionInfo ray_intersection_info;
+ self->IntersectRay(start, end, &ray_intersection_info);
+ return ray_intersection_info;
+ }
+ o3d::RayIntersectionInfo userglue_method_IntersectRay(
+ o3d::BoundingBox* self,
+ float startX,
+ float startY,
+ float startZ,
+ float endX,
+ float endY,
+ float endZ) {
+ o3d::RayIntersectionInfo ray_intersection_info;
+ self->IntersectRay(Vectormath::Aos::Point3(startX, startY, startZ),
+ Vectormath::Aos::Point3(endX, endY, endZ),
+ &ray_intersection_info);
+ return ray_intersection_info;
+ }
+ %}
+}; // BoundingBox
+
+%[
+ A Param which stores a BoundingBox.
+%]
+[nocpp, include="core/cross/param.h"] class ParamBoundingBox : Param {
+ %[
+ The BoundingBox stored by the Param.
+ %]
+ [getter, setter] BoundingBox value_;
+};
+
+} // namespace o3d
diff --git a/o3d/plugin/idl/buffer.idl b/o3d/plugin/idl/buffer.idl
new file mode 100644
index 0000000..0124c7b
--- /dev/null
+++ b/o3d/plugin/idl/buffer.idl
@@ -0,0 +1,482 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace o3d {
+
+%[
+ The Buffer object is a low level container for a flat list of
+ floating point or integer values. These are currently used to define
+ geometry.
+%]
+[nocpp, include="core/cross/buffer.h"]
+class Buffer : NamedObject {
+ %[
+ Allocates memory for the data to be stored in the buffer based on
+ the types of fields set on the buffer.
+
+ \param num_elements Number of elements to allocate..
+ \return True if operation was successful.
+ %]
+ [userglue] bool AllocateElements(unsigned int num_elements);
+
+ %[
+ Defines a field on this buffer.
+
+ Note: Creating a field after having allocated the buffer is an expensive
+ operation as the data currently in the buffer has to be shuffled around
+ to make room for the new field.
+
+ \param field_type type of data in the field. Valid types are "FloatField",
+ "UInt32Field", "UByteNField".
+ \param num_components number of components in the field.
+ %]
+ [userglue]
+ Field? CreateField(String field_type, unsigned int num_components);
+
+ %[
+ Removes a field from this buffer.
+
+ Note: Removing a field after having allocated the buffer is an expensive
+ operation as the data currently in the buffer has to be shuffled around
+ to remove the old field.
+
+ \param field field to remove.
+ %]
+ void RemoveField(Field field);
+
+ %[
+ Sets the values in the buffer given a RawData object.
+
+ \param raw_data contains data to assign to the Buffer data itself.
+ %]
+ bool Set(RawData raw_data);
+
+ %[
+ Sets the values in the buffer given a RawData object.
+
+ \param raw_data contains data to assign to the Buffer data itself.
+ \param offset is a byte offset from the start of raw_data
+ \param length is the byte length of the data to set
+ \return True if operation was successful.
+ %]
+ bool Set(RawData raw_data,
+ size_t offset,
+ size_t length);
+
+ %[
+ Number of elements in the buffer.
+ %]
+ [getter] unsigned int num_elements;
+
+ %[
+ The total components in all fields in this buffer.
+ %]
+ [getter] unsigned int total_components;
+
+ %[
+ The fields currently set on the buffer.
+ %]
+ [userglue_getter, getter] FieldArray fields;
+
+ [verbatim=cpp_glue] %{
+ o3d::Field* userglue_method_CreateField(
+ o3d::Buffer* buffer,
+ const o3d::String& field_type,
+ unsigned int num_components) {
+ return buffer->CreateFieldByClassName(field_type, num_components);
+ }
+ o3d::FieldArray userglue_getter_fields(o3d::Buffer* buffer) {
+ const o3d::FieldRefArray buffer_fields = buffer->fields();
+ o3d::FieldArray fields(buffer_fields.size());
+ for (size_t ii = 0; ii < buffer_fields.size(); ++ii) {
+ fields[ii] = buffer_fields[ii].Get();
+ }
+ return fields;
+ }
+ bool userglue_method_AllocateElements(o3d::Buffer* buffer,
+ unsigned int num_elements) {
+ bool result = buffer->AllocateElements(num_elements);
+ if (result) {
+ // Clear the buffer so at least from Javascript we can't get garbage.
+ o3d::BufferLockHelper locker(buffer);
+ void* data = locker.GetData(o3d::Buffer::WRITE_ONLY);
+ if (!data) {
+ O3D_ERROR(buffer->service_locator())
+ << "could not lock buffer";
+ } else {
+ memset(data, 0, buffer->GetSizeInBytes());
+ }
+ }
+ return result;
+ }
+ %}
+};
+
+%[
+ VertexBufferBase is a the base class for both VertexBuffer and SourceBuffer
+
+ \sa VertexBuffer
+ \sa SourceBuffer
+%]
+[nocpp, include="core/cross/buffer.h"]
+class VertexBufferBase : Buffer {
+ %[
+ Gets a copy of the values of the data stored in the buffer.
+ Modifying this copy has no effect on the buffer.
+
+ \return An array of values.
+ %]
+ [nocpp, userglue] float[] Get();
+
+ %[
+ Gets a copy of a sub range of the values in the data stored in the buffer.
+ Modifying this copy has no effect on the buffer.
+
+ \param start_index index of the element value to get.
+ \param num_elements the number of elements to get.
+ \return An array of values.
+ %]
+ [nocpp, userglue]
+ float[] GetAt(unsigned int start_index, unsigned int num_elements);
+
+ %[
+ Sets the values of the data stored in the buffer.
+ The number of values passed in must be a multiple of the number of
+ components needed for the fields defined on this buffer.
+
+ \param values Values to be stored in the buffer.
+ \return True if operation was successful.
+ %]
+ [nocpp, userglue] bool Set(float[] values);
+
+ %[
+ Sets the values of the data stored in the buffer. The buffer must have
+ already been created either through buffer.set or buffer.allocateElements
+
+ The number of values passed in must be a multiple of the number of
+ components needed for the fields defined on this buffer.
+
+ \param start_index index of first value to set.
+ \param values Values to be stored in the buffer starting at index.
+ \return True if operation was successful.
+ %]
+ [nocpp, userglue] void SetAt(unsigned int start_index, float[] values);
+
+ [verbatim=cpp_glue] %{
+ std::vector<float> userglue_method_Get(o3d::VertexBufferBase *buffer) {
+ std::vector<float> retval;
+ o3d::BufferLockHelper helper(buffer);
+ float* buffer_data = helper.GetDataAs<float>(
+ o3d::Buffer::READ_ONLY);
+ if (!buffer_data) {
+ O3D_ERROR(buffer->service_locator())
+ << "could not lock buffer";
+ } else {
+ retval.resize(buffer->total_components() * buffer->num_elements());
+ unsigned element_offset = 0;
+ // for each field, copy the stuff into the array.
+ const o3d::FieldRefArray& fields = buffer->fields();
+ for (unsigned ff = 0; ff < fields.size(); ++ff) {
+ o3d::Field* field = fields[ff];
+ field->GetAsFloats(0,
+ &retval[0] + element_offset,
+ field->num_components(),
+ buffer->num_elements());
+ element_offset += field->num_components();
+ }
+ }
+ return retval;
+ }
+ std::vector<float> userglue_method_GetAt(o3d::VertexBufferBase *buffer,
+ unsigned int start_index,
+ unsigned int length) {
+ std::vector<float> retval;
+ if (start_index + length > buffer->num_elements() ||
+ start_index + length < start_index) {
+ O3D_ERROR(buffer->service_locator())
+ << "number of requested values would run past end of buffer";
+ } else {
+ o3d::BufferLockHelper helper(buffer);
+ float* buffer_data = helper.GetDataAs<float>(
+ o3d::Buffer::READ_ONLY);
+ if (!buffer_data) {
+ O3D_ERROR(buffer->service_locator())
+ << "could not lock buffer";
+ } else {
+ retval.resize(length * buffer->total_components());
+ unsigned element_offset = 0;
+ // for each field, copy the stuff into the array.
+ const o3d::FieldRefArray& fields = buffer->fields();
+ for (unsigned ff = 0; ff < fields.size(); ++ff) {
+ o3d::Field* field = fields[ff];
+ field->GetAsFloats(start_index,
+ &retval[0] + element_offset,
+ field->num_components(),
+ length);
+ element_offset += field->num_components();
+ }
+ }
+ }
+ return retval;
+ }
+ bool userglue_method_Set(o3d::VertexBufferBase *buffer,
+ const std::vector<float> &values) {
+ unsigned int total_components = buffer->total_components();
+ size_t size = values.size();
+ if (total_components == 0) {
+ O3D_ERROR(buffer->service_locator())
+ << "no fields are defined on the buffer";
+ return false;
+ }
+ if (size % total_components != 0) {
+ O3D_ERROR(buffer->service_locator())
+ << "the number of values passed in is not a multiple of the number"
+ << " of components in the fields on the buffer.";
+ return false;
+ }
+
+ unsigned num_elements = size / total_components;
+
+ if (!buffer->AllocateElements(num_elements)) {
+ return false;
+ }
+
+ o3d::BufferLockHelper helper(buffer);
+ void* buffer_data = helper.GetData(o3d::Buffer::WRITE_ONLY);
+ if (!buffer_data) {
+ O3D_ERROR(buffer->service_locator())
+ << "could not lock buffer";
+ return false;
+ }
+
+ unsigned element_offset = 0;
+ // for each field, copy the stuff out of the array.
+ const o3d::FieldRefArray& fields = buffer->fields();
+ for (unsigned ff = 0; ff < fields.size(); ++ff) {
+ o3d::Field* field = fields[ff];
+ field->SetFromFloats(&values[element_offset],
+ total_components,
+ 0,
+ num_elements);
+ element_offset += field->num_components();
+ }
+ return true;
+ }
+ void userglue_method_SetAt(o3d::VertexBufferBase *buffer,
+ unsigned int start_index,
+ const std::vector<float> &values) {
+ unsigned int total_components = buffer->total_components();
+ size_t size = values.size();
+ if (total_components == 0) {
+ O3D_ERROR(buffer->service_locator())
+ << "no fields are defined on the buffer";
+ return;
+ }
+ if (size % total_components != 0) {
+ O3D_ERROR(buffer->service_locator())
+ << "the number of values passed in is not a multiple of the number"
+ << " of components in the fields on the buffer.";
+ return;
+ }
+
+ unsigned num_elements_to_set = size / total_components;
+ unsigned last_element = start_index + num_elements_to_set;
+ if (last_element > buffer->num_elements() ||
+ last_element < start_index) {
+ O3D_ERROR(buffer->service_locator())
+ << "Attempt to set elements outside of Buffer";
+ return;
+ }
+
+ o3d::BufferLockHelper helper(buffer);
+ void* buffer_data = helper.GetData(o3d::Buffer::WRITE_ONLY);
+ if (!buffer_data) {
+ O3D_ERROR(buffer->service_locator())
+ << "could not lock buffer";
+ return;
+ }
+
+ unsigned element_offset = 0;
+ // for each field, copy the stuff out of the array.
+ const o3d::FieldRefArray& fields = buffer->fields();
+ for (unsigned ff = 0; ff < fields.size(); ++ff) {
+ o3d::Field* field = fields[ff];
+ field->SetFromFloats(&values[element_offset],
+ total_components,
+ start_index,
+ num_elements_to_set);
+ element_offset += field->num_components();
+ }
+ }
+ %}
+};
+
+%[
+ VertexBuffer is a Buffer object used for storing vertex data for geometry.
+ (e.g. vertex positions, normals, colors, etc).
+ A VertexBuffer can be rendered directly by the GPU.
+
+ \sa SourceBuffer
+%]
+[nocpp, include="core/cross/buffer.h"]
+class VertexBuffer : VertexBufferBase {
+};
+
+%[
+ SourceBuffer is a Buffer object used for storing vertex data for
+ geometry. (e.g. vertex positions, normals, colors, etc).
+
+ A SourceBuffer is the source for operations like skinning and morph
+ targets. It can not be directly rendered by the GPU.
+
+ \sa VertexBuffer
+%]
+[nocpp, include="core/cross/buffer.h"]
+class SourceBuffer : VertexBufferBase {
+};
+
+%[
+ IndexBuffer is a buffer object used for storing geometry index data (e.g.
+ triangle indices).
+%]
+[nocpp, include="core/cross/buffer.h"] class IndexBuffer : Buffer {
+ %[
+ Sets the values of the data stored in the buffer.
+
+ \param values Values to be stored in the buffer.
+ \return True if operation was successful.
+ %]
+ [nocpp, userglue] bool Set(unsigned int[] values);
+
+ %[
+ Sets the values of the data stored in the buffer. The buffer must have
+ already been created either through buffer.set or buffer.allocateElements.
+
+ \param start_index index of first value to set.
+ \param values Values to be stored in the buffer starting at index.
+ \return True if operation was successful.
+ %]
+ [nocpp, userglue] void SetAt(unsigned int start_index, unsigned int[] values);
+
+ [verbatim=cpp_glue] %{
+ bool userglue_method_Set(o3d::IndexBuffer *buffer,
+ const std::vector<unsigned int> &values) {
+ unsigned int total_components = buffer->total_components();
+ size_t size = values.size();
+ if (total_components == 0) {
+ O3D_ERROR(buffer->service_locator())
+ << "no fields are defined on the buffer";
+ return false;
+ }
+ if (size % total_components != 0) {
+ O3D_ERROR(buffer->service_locator())
+ << "the number of values passed in is not a multiple of the number"
+ << " of components in the fields on the buffer.";
+ return false;
+ }
+
+ unsigned num_elements = size / total_components;
+
+ if (!buffer->AllocateElements(num_elements)) {
+ return false;
+ }
+
+ o3d::BufferLockHelper helper(buffer);
+ void* buffer_data = helper.GetData(o3d::Buffer::WRITE_ONLY);
+ if (!buffer_data) {
+ O3D_ERROR(buffer->service_locator())
+ << "could not lock buffer";
+ return false;
+ }
+
+ unsigned element_offset = 0;
+ // for each field, copy the stuff out of the array.
+ const o3d::FieldRefArray& fields = buffer->fields();
+ for (unsigned ff = 0; ff < fields.size(); ++ff) {
+ o3d::Field* field = fields[ff];
+ field->SetFromUInt32s(&values[element_offset],
+ total_components,
+ 0,
+ num_elements);
+ element_offset += field->num_components();
+ }
+ return true;
+ }
+ void userglue_method_SetAt(o3d::IndexBuffer *buffer,
+ unsigned int start_index,
+ const std::vector<unsigned int> &values) {
+ unsigned int total_components = buffer->total_components();
+ size_t size = values.size();
+ if (total_components == 0) {
+ O3D_ERROR(buffer->service_locator())
+ << "no fields are defined on the buffer";
+ return;
+ }
+ if (size % total_components != 0) {
+ O3D_ERROR(buffer->service_locator())
+ << "the number of values passed in is not a multiple of the number"
+ << " of components in the fields on the buffer.";
+ return;
+ }
+
+ unsigned num_elements_to_set = size / total_components;
+ unsigned last_element = start_index + num_elements_to_set;
+ if (last_element > buffer->num_elements() ||
+ last_element < start_index) {
+ O3D_ERROR(buffer->service_locator())
+ << "Attempt to set elements outside of Buffer";
+ return;
+ }
+
+ o3d::BufferLockHelper helper(buffer);
+ void* buffer_data = helper.GetData(o3d::Buffer::WRITE_ONLY);
+ if (!buffer_data) {
+ O3D_ERROR(buffer->service_locator())
+ << "could not lock buffer";
+ return;
+ }
+
+ unsigned element_offset = 0;
+ // for each field, copy the stuff out of the array.
+ const o3d::FieldRefArray& fields = buffer->fields();
+ for (unsigned ff = 0; ff < fields.size(); ++ff) {
+ o3d::Field* field = fields[ff];
+ field->SetFromUInt32s(&values[element_offset],
+ total_components,
+ start_index,
+ num_elements_to_set);
+ element_offset += field->num_components();
+ }
+ }
+ %}
+};
+
+} // namespace o3d
diff --git a/o3d/plugin/idl/canvas.idl b/o3d/plugin/idl/canvas.idl
new file mode 100644
index 0000000..013349a
--- /dev/null
+++ b/o3d/plugin/idl/canvas.idl
@@ -0,0 +1,181 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+namespace o3d {
+
+%[
+Canvas provides an interface for drawing text and 2D primitives on a 2D surface.
+The contents of the canvas surface can be transfered to a compatible Texture2D
+object via the copyToTexture() method. Each Canvas object maintains
+a stack of 2D transformation matrices which allow fine control over
+the placement of drawable elements. Both geometry and drawing coordinates
+provided to every draw call are transformed by the concatenation of
+all matrices in the stack.
+%]
+
+[nocpp, include="core/cross/canvas.h"]
+class Canvas : ParamObject {
+ %[
+ Sets the size of the bitmap area that the Canvas uses.
+ \param width The width of the bitmap.
+ \param height The height of the bitmap.
+ \returns true if the Canvas surface was allocated successfully.
+ %]
+ bool SetSize(int width, int height);
+
+ %[
+ Clears the bitmap's pixels with the specified color.
+ \param color The color to clear the bitmap with, provided as an array of
+ four values [red, green, blue, alpha]. All values should be between 0.0
+ and 1.0. For alpha values 0.0 is transparent and 1.0 opaque.
+ %]
+ [userglue] void Clear(Float4 color);
+
+ %[
+ Draws the specified rectangle using the specified paint. The rectangle will
+ be filled based on the color and shader in the paint.
+ \param left The left side of the rectangle to be drawn
+ \param top The top side of the rectangle to be drawn
+ \param right The right side of the rectangle to be drawn
+ \param bottom The bottom side of the rectangle to be drawn
+ \param paint The paint used to draw the rectangle
+ %]
+ void DrawRect(float left,
+ float top,
+ float right,
+ float bottom,
+ CanvasPaint paint);
+
+ %[
+ Draws the text, with origin at (x,y), using the specified paint. The origin
+ is interpreted based on the textAlign property in the paint.
+ \param text String of text to be drawn
+ \param x The x coordinate for the text origin
+ \param y The y coordinate for the text origin
+ \param paint The CanvasPaint object that specifies the text style, size, etc
+ %]
+ void DrawText(String text, float x, float y, CanvasPaint paint);
+
+ %[
+ Draws the text with its baseline along the
+ specified path. The paint's textAlign property determines where along the
+ path to start the text. The path must contain at least two positions.
+ \param text String of text to be drawn
+ \param positions An array of x,y positions making up the path.
+ \param horizontalOffset The distance along the path to add to the text
+ starting position.
+ \param verticalOffset The distance above(-) or below(+) the path to position
+ the text.
+ \param paint The CanvasPaint object that specifies the text style, size,
+ etc.
+ %]
+ void DrawTextOnPath(String text,
+ Float2[] positions,
+ float horizontalOffset,
+ float verticalOffset,
+ CanvasPaint paint);
+
+ %[
+ Draws the contents of the specified texture onto the canvas surface.
+ The bottom left corner of the bitmap will be at (x, y) and transformed by
+ the current matrix. Only ARGB8 and XRGB8 textures are supported. For XRG8
+ textures, Alpha is assumed to be 1 (opaque).
+ \param texture The Texture2D object where the bitmap is extracted from.
+ \param left The position of the left side of the bitmap.
+ \param bottom The position of the bottom side of the bitmap.
+ %]
+ void DrawBitmap(Texture2D texture, float left, float bottom);
+
+ %[
+ This call saves the current matrix and pushes a
+ copy onto a private stack. Subsequent calls to translate, scale,
+ rotate all operate on this copy.
+ When the balancing call to restoreMatrix() is made, this copy is deleted and
+ the previous matrix is restored.
+ %]
+ void SaveMatrix();
+
+ %[
+ Balances a call to saveMatrix(), and removes modifications to matrix
+ since the last save call. It is an error to call this more than
+ previous calls to saveMatrix().
+ %]
+ void RestoreMatrix();
+
+ %[
+ Adds a rotation to the current canvas matrix.
+ \param degrees The amount to rotate, in degrees
+ %]
+ void Rotate(float degrees);
+
+
+ %[
+ Adds a scale to the current canvas matrix.
+ \param sx The amount to scale in x
+ \param sy The amount to scale in y
+ %]
+ void Scale(float sx, float sy);
+
+ %[
+ Adds a translation to the current canvas matrix.
+ \param dx The amount to translate in x
+ \param dy The amount to translate in y
+ %]
+ void Translate(float dx, float dy);
+
+ %[
+ Copies the contents of the Canvas to a 2D texture object. The size of the
+ texture must match exactly the size of the Canvas set by the setSize() method.
+ The format of the texture must be set to either ARGB8 or XRGB8.
+ %]
+ void CopyToTexture(Texture2D texture);
+
+ %[
+ The width of the bitmap used by the Canvas (read only).
+ %]
+ [getter] int width_;
+
+ %[
+ The height of the bitmap used by the Canvas (read only).
+ %]
+ [getter] int height_;
+
+ [verbatim=cpp_glue] %{
+ void userglue_method_Clear(o3d::Canvas* canvas,
+ const o3d::Float4& color) {
+ canvas->Clear(color[0], color[1], color[2], color[3]);
+ }
+ %}
+
+}; // Canvas
+
+} // namespace o3d
diff --git a/o3d/plugin/idl/canvas_paint.idl b/o3d/plugin/idl/canvas_paint.idl
new file mode 100644
index 0000000..94c3812
--- /dev/null
+++ b/o3d/plugin/idl/canvas_paint.idl
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+namespace o3d {
+
+%[
+ CanvasFontMetrics is used to return values, measured in pixels, describing
+ the properties of a font used by the CanvasPaint objects. All the properties
+ of CanvasFontMetrics are read-only.
+%]
+
+[binding_model=by_value, nocpp, include="core/cross/canvas_paint.h"]
+class CanvasFontMetrics {
+ %[
+ The greatest distance above the baseline for any glyph (will be <= 0)
+ %]
+ [getter] float top_;
+
+ %[
+ The recommended distance above the baseline (will be <= 0)
+ %]
+ [getter] float ascent_;
+
+ %[
+ The recommended distance below the baseline (will be >= 0)
+ %]
+ [getter] float descent_;
+
+ %[
+ The greatest distance below the baseline for any glyph (will be >= 0)
+ %]
+ [getter] float bottom_;
+
+ %[
+ The recommended distance to add between lines of text (will be >= 0)
+ %]
+ [getter] float leading_;
+}; // CanvasFontMetrics
+
+
+%[
+ The CanvasPaint class is used for specifying how to draw objects and text to
+ a canvas.
+%]
+
+[nocpp, include="core/cross/canvas_paint.h"]
+class CanvasPaint : ParamObject {
+ %[
+ \var Style
+ \li NORMAL,
+ \li BOLD,
+ \li ITALIC,
+ \li BOLD_ITALIC
+ Text styles
+ %]
+ enum Style {
+ NORMAL,
+ BOLD,
+ ITALIC,
+ BOLD_ITALIC
+ };
+
+ %[
+ \var TextAlign
+ \li LEFT,
+ \li CENTER,
+ \li RIGHT,
+ Text alignment options
+ %]
+ enum TextAlign {
+ LEFT,
+ CENTER,
+ RIGHT
+ };
+
+ %[
+ Sets the color and radius of an outline around the text. Setting the
+ radius to 0 cancels the outline effect. The outline and shadow effects are
+ mutually exclusive.
+ \param radius Distance outward from object to draw the background
+ \param color Color of the outline
+ %]
+ void SetOutline(float radius, Float4 color);
+
+ %[
+ Create a blur shadow effect on this paint. Setting the radius to 0 cancels
+ the shadow effect.
+ \param radius radius to blur the paint
+ \param offset_y offset of the blur in X
+ \param offset_x offset of the blur in Y
+ \param color color for the blur
+ %]
+ void SetShadow(float radius,
+ float offset_x,
+ float offset_y,
+ Float4 color);
+
+ %[
+ Returns metrics describing the font currently set on this paint object.
+ %]
+ CanvasFontMetrics GetFontMetrics();
+
+ %[
+ Returns the bounds of the given text string when rendered with this paint.
+ The bounds are returned as an array containing [left, top, right, bottom]
+ values relative to (0, 0).
+ \param text The string of text to be measured.
+ %]
+ Float4 MeasureText(String text);
+
+ %[
+ The color used for all the draw operations using this paint.
+ %]
+ [getter, setter] Float4 color;
+
+ %[
+ The size of the font used for drawing text.
+ %]
+ [getter, setter] float text_size;
+
+ %[
+ The font typeface used for drawing text. Passing an empty string will
+ revert to the default font.
+ %]
+ [getter, setter] String text_typeface;
+
+ %[
+ The style applied to the text (e.g. italic, bold, etc)
+ %]
+ [getter, setter] Style text_style;
+
+ %[
+ The alignment mode used for drawing text.
+ %]
+ [getter, setter] TextAlign text_align;
+
+ %[
+ The 2D shader used by this paint. Set to null to stop using a shader.
+ %]
+ [getter, setter] CanvasShader? shader;
+
+ %[
+ Metrics of the current font used by the paint object.
+ %]
+ [userglue_getter, getter] CanvasFontMetrics font_metrics;
+
+ [verbatim=cpp_glue] %{
+ o3d::CanvasFontMetrics userglue_getter_font_metrics(
+ o3d::CanvasPaint* self) {
+ return self->GetFontMetrics();
+ }
+ %}
+
+}; // CanvasPaint
+
+} // namespace o3d
+
diff --git a/o3d/plugin/idl/canvas_shader.idl b/o3d/plugin/idl/canvas_shader.idl
new file mode 100644
index 0000000..252836b
--- /dev/null
+++ b/o3d/plugin/idl/canvas_shader.idl
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+namespace o3d {
+
+%[
+CanvasShader is the base class of 2D gradient shaders that can be applied to a
+CanvasPaint. When a shader is assigned to a CanvasPaint object, all subsequent
+drawing (text and objects) will use the shader pattern as a fill material.
+%]
+
+[nocpp, include="core/cross/canvas_shader.h"]
+class CanvasShader : ParamObject {
+ %[
+ \var TileMode
+ \li CLAMP copy the edge color if the shader draws outside of its bounds
+ \li REPEAT repeat horizontally and vertically outside its bounds
+ \li MIRROR same as above, alternating mirror images
+ %]
+ enum TileMode {
+ CLAMP, /* copy the edge color if the shader draws outside of its bounds */
+ REPEAT, /* repeat horizontally and vertically outside its bounds */
+ MIRROR /* same, alternating mirror images */
+ };
+
+}; // class CanvasShader
+
+%[
+A shader that generates a linear gradient between two specified points. Two or
+more colors need to be specified for the gradient.
+%]
+[nocpp, include="core/cross/canvas_shader.h"]
+class CanvasLinearGradient : CanvasShader {
+ %[
+ The start point of this gradient.
+ %]
+ [getter, setter] Float2 start_point;
+
+ %[
+ The end point of this gradient.
+ %]
+ [getter, setter] Float2 end_point;
+
+ %[
+ The array of colors to be distributed between the two points in RBGA format
+ stored as an array of [r, g, b, a] colors.
+ %]
+ [getter, setter] Float4[] colors;
+
+ %[
+ The relative position of each corresponding color in the color array.
+ Values must begin with 0 and end with 1.0 and there should be exactly as
+ many numbers as there are colors. If positions is set to an empty array then
+ the colors are distributed evenly between between the start and end point.
+ %]
+ [getter, setter] float[] positions;
+
+ %[
+ The TileMode of this gradient which controls how the gradient pattern
+ repeats.
+ %]
+ [getter, setter] TileMode tile_mode;
+
+}; // class CanvasLinearGradient
+} // namespace o3d
diff --git a/o3d/plugin/idl/clear_buffer.idl b/o3d/plugin/idl/clear_buffer.idl
new file mode 100644
index 0000000..8a10453
--- /dev/null
+++ b/o3d/plugin/idl/clear_buffer.idl
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace o3d {
+
+%[
+ A ClearBuffer is a render node that clears the color buffer, zbuffer and/or
+ stencil buffer of the current render target.
+%]
+
+[nocpp, include="core/cross/clear_buffer.h"] class ClearBuffer
+ : RenderNode {
+ %[
+ The color to clear the buffer in RGBA Float4 format.
+ %]
+ [getter, setter] Float4 clear_color;
+
+ %[
+ true clears the current render target's color buffer to the clear color.
+ false does not clear the color buffer.
+ %]
+ [getter, setter] bool clear_color_flag_;
+
+ %[
+ The value to clear the depth buffer (0.0 to 1.0)
+ %]
+ [getter, setter] float clear_depth_;
+
+ %[
+ true clears the current render target's depth buffer to the clear depth
+ value. false does not clear the depth buffer.
+ %]
+ [getter, setter] bool clear_depth_flag_;
+
+ %[
+ The value to clear the stencil buffer to (0 - 255).
+ %]
+ [getter, setter] int clear_stencil_;
+
+ %[
+ true clears the current render target's stencil buffer to the clear stencil
+ value. false does not clear the stencil buffer
+ %]
+ [getter, setter] bool clear_stencil_flag_;
+
+}; // ClearBuffer
+
+} // namespace o3d
diff --git a/o3d/plugin/idl/client.idl b/o3d/plugin/idl/client.idl
new file mode 100644
index 0000000..0ac3b91
--- /dev/null
+++ b/o3d/plugin/idl/client.idl
@@ -0,0 +1,543 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// This file contains the public interface specification for the client.
+
+namespace o3d {
+
+%[
+ IdArray is a typdef for an array of Ids.
+%]
+typedef Id[] IdArray;
+
+%[
+ PackArray is a typdef for an array of Packs.
+%]
+typedef Pack[] PackArray;
+
+%[
+ ObjectBaseArray is a typdef for an array of ObjectBase objects.
+%]
+typedef ObjectBase[] ObjectBaseArray;
+
+callback void LostResourcesCallback();
+
+callback void EventCallback(Event event_descriptor);
+
+[binding_model=by_pointer, include="core/cross/renderer.h", nocpp, glue_iface]
+class Renderer {
+ %[
+ The initialization status of the renderer.
+ \li UNINITIALIZED
+ \li SUCCESS The renderer is initialized.
+ \li GPU_NOT_UP_TO_SPEC The renderer determined the user's machine can not
+ run O3D
+ \li OUT_OF_RESOURCES The user's machine does not have enough graphic
+ resources available to start another instance of the O3D renderer.
+ \li INITIALIZATION_ERROR Some unknown error like possibly drivers not being
+ installed correctly.
+ %]
+ enum InitStatus {
+ UNINITIALIZED,
+ SUCCESS,
+ GPU_NOT_UP_TO_SPEC,
+ OUT_OF_RESOURCES,
+ INITIALIZATION_ERROR
+ };
+};
+
+%[
+ The Client class is the main point of entry to O3D. It defines methods
+ for creating and deleting packs. Each new object created by the Client is
+ assigned a unique ID.
+
+ The Client has a root transform for the transform graph and a root render
+ node for the render graph.
+%]
+[binding_model=by_pointer, include="core/cross/client.h",
+ nocpp, glue_iface]
+class Client {
+
+ callback void RenderCallback(RenderEvent render_event);
+ callback void TickCallback(TickEvent tick_event);
+ callback void ErrorCallback(String error_msg);
+
+ %[
+ The transform graph root Transform
+ %]
+ [getter] Transform root_;
+
+ %[
+ Call this function from window.onunload to ensure the browser does not
+ continue to call callbacks (like the render callback) after the page is
+ unloaded. It is possible that during unload the browser unloads all the
+ javascript code, but then, after that, still asks the plugin to render. The
+ browser then calls javascript functions that no longer exist which causes an
+ error. To prevent that situation you need to clear all your callbacks on
+ unload. cleanup handles that for you so you don't have to dispose each and
+ every callback by hand.
+ %]
+ void Cleanup();
+
+ %[
+ Creates a pack object.
+ \return A pack object.
+ %]
+ Pack CreatePack();
+
+ %[
+ Searches the Client for an object matching the given id.
+
+ \param id The id of the object to look for.
+ \return The object or null if a object with the given id is not found.
+ %]
+ [const] ObjectBase? GetObjectById(Id id);
+
+ %[
+ Searches the Client for objects of a particular name and type.
+ \param name name of object to look for.
+ \param class_name name of class to look for.
+ \return Array of objects found.
+ %]
+ [const] ObjectArray GetObjects(String name, String class_name);
+
+ %[
+ Searches the Client for objects of a particular type.
+ \param class_name name of class to look for.
+ \return Array of objects found.
+ %]
+ [const] ObjectArray GetObjectsByClassName(String class_name);
+
+ %[
+ \var Property,
+ \li RENDERMODE_CONTINUOUS, Draw as often as possible up to refresh rate.
+ \li RENDERMODE_ON_DEMAND, Draw once then only when the OS requests it
+ (like uncovering part of a window.)
+ %]
+ enum RenderMode {
+ RENDERMODE_CONTINUOUS, // Draw as often as possible up to refresh rate.
+ RENDERMODE_ON_DEMAND // Draw once then when the OS request it
+ // (like uncovering part of a window.)
+ };
+
+ %[
+ The current render mode. The default mode is RENDERMODE_CONTINUOUS.\n
+ Valid values are:
+ \li RENDERMODE_CONTINUOUS, Draw as often as possible up to refresh rate.
+ \li RENDERMODE_ON_DEMAND, Draw when the OS requests it (like uncovering
+ part of a window.)
+ %]
+ [getter, setter] RenderMode render_mode_;
+
+ %[
+ Forces a render of the current scene if the current render mode is
+ RENDERMODE_ON_DEMAND.
+ %]
+ void Render();
+
+ %[
+ Renders a render graph.
+
+ Normally the client calls this function automatically for you effectively
+ doing a client.renderTree(client.renderGraphRoot) but there are cases
+ where it is beneficial to be able to call this yourself and pass it
+ different roots when you need to manipulate something between calls.
+
+ This function can only be called from inside a render callback. If you call
+ it the client will not do its default call as mentioned above.
+ %]
+ void RenderTree(RenderNode render_node);
+
+ %[
+ Returns an array of DisplayModes which are available for use in fullscreen
+ mode.
+ %]
+ [userglue, plugin_data] DisplayMode[] GetDisplayModes();
+
+ %[
+ Makes a region of the plugin area that will invoke fullscreen mode if
+ clicked. The developer is responsible for communicating this to the user,
+ as this region has no visible marker. The developer is also responsible for
+ updating this region if the plugin gets resized, as we don't know whether or
+ how to scale it.
+ %]
+ [userglue, plugin_data]
+ void SetFullscreenClickRegion(int x, int y, int width, int height, int
+ mode_id);
+ %[
+ Cancels fullscreen display, reverting to displaying content only in the
+ plugin region. If the plugin is already not in fullscreen mode, this has
+ no effect.
+ %]
+ [userglue, plugin_data] void CancelFullscreenDisplay();
+
+ %[
+ Whether content is displayed in fullscreen mode or in a plugin window. The
+ default is false [not fullscreen].
+ %]
+ [userglue_getter, getter, plugin_data]
+ bool fullscreen;
+
+ %[
+ Returns the width of the current drawing area [plugin or fullscreen] in
+ pixels.
+ %]
+ [userglue_getter, getter, plugin_data]
+ int width;
+
+ %[
+ Returns the height of the current drawing area [plugin or fullscreen] in
+ pixels.
+ %]
+ [userglue_getter, getter, plugin_data]
+ int height;
+
+ %[
+ The root of the render graph.
+ %]
+ [getter] RenderNode render_graph_root_;
+
+ %[
+ Sets the per frame render callback.
+
+ Note: The callback will not be called recursively. When your callback is
+ called if you somehow manage to cause the client to render more frames
+ before you've returned from the callback you will not be called for those
+ frames.
+
+ \code
+ g_client.setRenderCallback(onrender);
+
+ function onrender(render_event) {
+ var elapsedTime = render_event.elapsedTime;
+
+ // elapsedTime is the time elasped since the last callback.
+ // You can use this value to make your application frame rate independent.
+ // For example:
+ // position = position + velocity_in_units_per_second * elapsedTime;
+ }
+ \endcode
+
+ \param render_callback The callback to call each frame.
+ %]
+ void SetRenderCallback(RenderCallback? render_callback);
+
+ %[
+ Clears the per frame render callback.
+ %]
+ void ClearRenderCallback();
+
+ %[
+ Sets a render callback to be called at the end of the
+ rendering cycle of each frame.
+
+ Note: The callback will not be called recursively. When your callback is
+ called if you somehow manage to cause the client to render more frames
+ before you've returned from the callback you will not be called for those
+ frames.
+
+ \code
+ g_client.setPostRenderCallback(onpostrender);
+
+ function onpostrender(render_event) {
+ var elapsedTime = render_event.elapsedTime;
+
+ // elapsedTime is the time elasped since the last callback.
+ // You can use this value to make your application frame rate independent.
+ // For example:
+ // position = position + velocity_in_units_per_second * elapsedTime;
+ }
+ \endcode
+
+ \param post_render_callback The callback to call each frame.
+ %]
+ void SetPostRenderCallback(RenderCallback? post_render_callback);
+
+ %[
+ Clears the post render callback.
+ %]
+ void ClearPostRenderCallback();
+
+ %[
+ Sets the lost resources callback.
+
+ The contents of certain resources, RenderSurfaces, can get discarded by the
+ system under certain circumstances. If you application needs that contents
+ to be in a certain state then you can set a callback giving your program the
+ opportunity to restore that state if and when it is lost.
+
+ \param lost_resources_callback The callback when resources are lost.
+ %]
+ void SetLostResourcesCallback(LostResourcesCallback? lost_resources_callback);
+
+ %[
+ Clears the lost resources callback.
+ %]
+ void ClearLostResourcesCallback();
+
+ %[
+ Sets a callback for a given event type. See @Event for a list of event
+ types. However, only mousedown, mousemove, mouseup, and dblclick will
+ actually do anything at present.
+
+ There can be only one callback for a given event type at a time; setting a
+ new one deletes the old one.
+ %]
+ void SetEventCallback(String type, EventCallback? handler);
+
+ %[
+ Removes the previously-registered callback for an event of the given type.
+ %]
+ void ClearEventCallback(String type);
+
+ %[
+ Sets the texture to use when a Texture or Sampler is missing while
+ rendering. The default is a red texture with a yellow no symbol.
+ <span style="color:yellow; background-color: red;">&Oslash;</span>.
+ If you set it to null you'll get an error if you try to render something
+ that is missing a needed Texture, Sampler or ParamSampler.
+
+ For example if you don't care about missing textures, setting it to a black
+ texture would be one option. Another example is if you want to write all
+ your shaders to expect a texture then set this to a white texture. If you
+ want to make sure you are not missing any textures set it null and see if
+ you get any errors using Client.setErrorCallback or Client.lastError.
+
+ \code
+ // Set the error texture to black.
+ var t = g_pack.createTexture2D('', 1, 1, g_o3d.Texture.XRGB8, 1);
+ t.set(0, [0, 0, 0]);
+ g_client.setErrorTexture(t);
+ \endcode
+
+ \param texture texture to use for missing textures or null.
+ %]
+ void SetErrorTexture(Texture? texture);
+
+ %[
+ Sets a callback for when the client ticks. The client processes some things
+ like animation timers at up to 100hz. This callback will get called before
+ each of those process ticks.
+
+ NOTE: The client takes ownership of the TickCallback you
+ pass in. It will be deleted if you call SetTickCallback a
+ second time or if you call ClearTickCallback.
+
+ Note: The callback will not be called recursively.
+
+ \param tick_callback TickCallback to call when the Client ticks.
+ %]
+ void SetTickCallback(TickCallback? tick_callback);
+
+ %[
+ Clears the tick callback
+
+ NOTE: The client takes ownership of the TickCallback you
+ pass in. It will be deleted if you call SetTickCallback a second
+ time or if you call ClearTickCallback
+ %]
+ void ClearTickCallback();
+
+ %[
+ Sets a callback for when the client gets an error. For example when a shader
+ is compiled and there is an error or if you attempt to bind a param to a
+ param of an incompatible type.
+
+ NOTE: The client takes ownership of the ErrorCallback you
+ pass in. It will be deleted if you call SetErrorCallback a
+ second time or if you call ClearErrorCallback.
+
+ NOTE: The callback will not be called recursively. If you are in a
+ callback, and do something that causes another error before you have
+ returned from the callback, your callback will not be called a second time.
+
+ NOTE: If you put up an alert in response to an error it is best if you
+ clear the error callback before you put up the alert. Otherwise you'll get
+ an alert everytime the client tries to render which is every time you close
+ the current alert which means you'll be in an infinite loop of alerts.
+
+ \param error_callback ErrorCallback to call when the Client gets an error.
+ %]
+ void SetErrorCallback(ErrorCallback? error_callback);
+
+ %[
+ Clears the Error callback
+
+ NOTE: The client takes ownership of the ErrorCallback you
+ pass in. It will be deleted if you call SetErrorCallback a second
+ time or if you call ClearErrorCallback.
+ %]
+ void ClearErrorCallback();
+
+ %[
+ Makes all parameters get re-evaluated.
+ %]
+ void InvalidateAllParameters();
+
+ %[
+ This function is only available in the test version of the plugin.
+ %]
+ bool SaveScreen(String file_name);
+
+ %[
+ Returns the status of initializing the renderer so we can display the
+ appropriate message. We require a certain minimum set of graphics
+ capabilities. If the user's computer does not have his minimum
+ set this will be GPU_NOT_UP_TO_SPEC. If the user is out of graphics
+ resources this will be OUT_OF_RESOURCES. If some other error happened this
+ will be INITIALIZATION_ERROR. Otherwise it will be SUCCESS.
+ %]
+ [userglue_getter, getter, plugin_data]
+ Renderer::InitStatus renderer_init_status;
+
+ %[
+ Gets / Sets the cursor's shape.
+ %]
+ [userglue_getter, userglue_setter, getter, setter, plugin_data]
+ Cursor::CursorType cursor;
+
+ %[
+ Returns the socket address of the IMC message queue associated with the
+ Client.
+ %]
+ [const] String GetMessageQueueAddress();
+
+ %[
+ The last error reported by the plugin.
+ %]
+ [userglue_getter, getter] String last_error_;
+
+ %[
+ All the objects managed by this client.
+
+ Each access to this field gets the entire list so it is best to get it
+ just once. For example:
+ \code
+ var objects = client.objects;
+ for (var i = 0; i < objects.length; i++) {
+ var object = objects[i];
+ }
+ \endcode
+
+ Note that modifications to this array [e.g. push()] will not affect
+ the underlying Client, while modifications to the array's members
+ <strong>will</strong> affect them.
+ %]
+ [userglue_getter, getter] ObjectBaseArray objects_;
+
+ %[
+ Clears the error returned by GetLastError.
+ %]
+ void ClearLastError();
+
+ %[
+ Resets the profiling information.
+ %]
+ void ProfileReset();
+
+ %[
+ Returns the profiling information as a string.
+ %]
+ String ProfileToString();
+
+ %[
+ A unique id for this client.
+ %]
+ [getter=id] Id client_id;
+
+ [verbatim=cpp_glue] %{
+ o3d::String userglue_getter_last_error_(
+ o3d::Client* self) {
+ return self->GetLastError();
+ }
+ o3d::ObjectBaseArray userglue_getter_objects_(
+ o3d::Client* self) {
+ return self->GetByClass<o3d::ObjectBase>();
+ }
+ std::vector<o3d::DisplayMode> userglue_method_GetDisplayModes(
+ void *plugin_data, o3d::Client *self) {
+ std::vector<o3d::DisplayMode> modes;
+ static_cast<glue::_o3d::PluginObject*>(plugin_data)->GetDisplayModes(
+ &modes);
+ return modes;
+ }
+ void userglue_method_SetFullscreenClickRegion(
+ void *plugin_data, o3d::Client *self, int x, int y, int width,
+ int height, int mode_id) {
+ static_cast<glue::_o3d::PluginObject*>(plugin_data)->
+ SetFullscreenClickRegion(x, y, width, height, mode_id);
+ }
+ void userglue_method_CancelFullscreenDisplay(
+ void *plugin_data, o3d::Client *self) {
+ static_cast<glue::_o3d::PluginObject*>(plugin_data)->
+ CancelFullscreenDisplay();
+ }
+ bool userglue_getter_fullscreen(
+ void *plugin_data,
+ o3d::Client* self) {
+ return static_cast<glue::_o3d::PluginObject*>(
+ plugin_data)->fullscreen();
+ }
+ int userglue_getter_width(
+ void *plugin_data,
+ o3d::Client* self) {
+ return static_cast<glue::_o3d::PluginObject*>(
+ plugin_data)->width();
+ }
+ int userglue_getter_height(
+ void *plugin_data,
+ o3d::Client* self) {
+ return static_cast<glue::_o3d::PluginObject*>(
+ plugin_data)->height();
+ }
+ void userglue_setter_cursor(void* plugin_data,
+ o3d::Client* self,
+ o3d::Cursor::CursorType cursor_type) {
+ static_cast<glue::_o3d::PluginObject*>(plugin_data)->set_cursor(
+ cursor_type);
+ }
+ o3d::Cursor::CursorType userglue_getter_cursor(
+ void* plugin_data,
+ o3d::Client* self) {
+ return static_cast<glue::_o3d::PluginObject*>(
+ plugin_data)->cursor();
+ }
+ o3d::Renderer::InitStatus userglue_getter_renderer_init_status(
+ void* plugin_data, o3d::Client*) {
+ return static_cast<glue::_o3d::PluginObject*>(
+ plugin_data)->renderer_init_status();
+ }
+ %}
+};
+
+
+} // namespace o3d
diff --git a/o3d/plugin/idl/counter.idl b/o3d/plugin/idl/counter.idl
new file mode 100644
index 0000000..981df37
--- /dev/null
+++ b/o3d/plugin/idl/counter.idl
@@ -0,0 +1,238 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace o3d {
+
+typedef float[] NumberArray;
+typedef NumberArray[] NumberArrayArray;
+
+%[
+ A Counter counts seconds, ticks or render frames depending on the type of
+ counter. You can set where it starts counting from and where it stops counting
+ at, whether or not it is running or paused and how it loops or does not loop.
+ You can also give it callbacks to call at specific count values.
+%]
+[nocpp, include="core/cross/counter.h"] class Counter
+ : ParamObject {
+
+ callback void CounterCallback();
+
+ %[
+ \var CountMode
+ \li CONTINUOUS, Keep running the counter forever.
+ \li ONCE, Stop at start or end depending on the direction.
+ \li CYCLE, When at end, jump back to start or visa versa.
+ \li OSCILLATE, Go from start to end back to start.
+ };
+ %]
+ enum CountMode {
+ CONTINUOUS,
+ ONCE,
+ CYCLE,
+ OSCILLATE
+ };
+
+ %[
+ Whether or not this counter is running. Default = true.
+ %]
+ [getter, setter] bool running_;
+
+ %[
+ Which direction this counter is counting. Default = true.
+ %]
+ [getter, setter] bool forward_;
+
+ %[
+ The start count for this counter. Default = 0.
+ %]
+ [getter, setter] float start_;
+
+ %[
+ The end count for this counter. Default = 0.
+ %]
+ [getter, setter] float end_;
+
+ %[
+ The current count value for this counter. Default = 0.
+ %]
+ [getter] float count_;
+
+ %[
+ The current count mode for this counter. Default = CONTINUOUS.
+ %]
+ [getter, setter] CountMode count_mode_;
+
+ %[
+ Sets the current count value for this counter as well as the resetting
+ the state of the callbacks.
+
+ In other words. Assume start = 1, end = 5, count = 1, and you have a
+ callback at 3.
+
+ <code>
+ myCounter.start = 1;
+ myCounter.end = 5;
+ myCounter.addCallback(3, myCallback);
+ myCounter.reset();
+
+ myCounter.advance(2); // count is now 3, myCallback is called.
+ myCounter.advance(2); // count is now 5
+ </code>
+
+ vs.
+
+ <code>
+ myCounter.start = 1;
+ myCounter.end = 5;
+ myCounter.addCallback(3, myCallback);
+ myCounter.reset();
+
+ myCounter.advance(2); // count is now 3, myCallback is called.
+ myCounter.setCount(3); // count is now 3, callback state has been reset.
+ myCounter.advance(2); // count is now 5, myCallback is called.
+ </code>
+
+ In the second case myCallback was called twice.
+
+ \param count Value to set the count to.
+ %]
+ void SetCount(float count);
+
+ %[
+ A multiplier used when advancing the count. The default value is 1.0.
+ For example you could set this to 0.5 to run the counter at half speed
+ or 2.0 to run it at double speed. Default = 1.
+ %]
+ [getter, setter] float multiplier_;
+
+ %[
+ Resets the counter back to the start or end time depending on the forward
+ setting and also resets the Callback state.
+ Note: Reset does not change the running state of the counter.
+ %]
+ void Reset();
+
+ %[
+ Advances the counter the given amount. The actual amount advanced depends
+ on the forward and multiplier settings. The formula is
+
+ <code>
+ new_count = count + advance_amount * multiplier * (forward ? 1.0 : -1.0);
+ </code>
+
+ Any callbacks that fall in the range between the counter's current count and
+ the amount advanced will be called.
+
+ This function is normally called automatically by the client if the counter
+ is set to running = true. but you can call it manually.
+
+ \param advance_amount Amount to advance count.
+ %]
+ [userglue] void Advance(float advance_amount);
+
+ %[
+ Adds a callback for a given count value. Only one callback can be
+ added to a specific count value. If another callback is added with the
+ same count value the previous callback for that value will be replaced.
+
+ Note: A callback at start will only get called when counting backward, a
+ callback at end will only get called counting forward.
+
+ \param count Count at which to call callback.
+ \param counter_callback Callback to call at given count.
+ %]
+ void AddCallback(float count, CounterCallback? counter_callback);
+
+ %[
+ Removes a callback for a given count value.
+
+ \param count Count to remove callback for,
+ \return true if there was a callback for that count, false if there was not
+ a callback for that count.
+ %]
+ bool RemoveCallback(float count);
+
+ %[
+ Removes all the callbacks on this counter.
+ %]
+ void RemoveAllCallbacks();
+
+ %[
+ Returns all the counts for which all callback has been added.
+ \return Array of counts.
+ %]
+ [userglue, const] NumberArray GetCallbackCounts();
+
+ [verbatim=cpp_glue] %{
+ // This is userglue because we need to force the client to call any
+ // callbacks that need to be called as a result of the advance.
+ void userglue_method_Advance(o3d::Counter* self,
+ float advance_amount) {
+ o3d::Counter::CounterCallbackQueue queue;
+ self->Advance(advance_amount, &queue);
+ queue.CallCounterCallbacks();
+ }
+ std::vector<float> userglue_method_GetCallbackCounts(
+ o3d::Counter* self) {
+ const o3d::Counter::CounterCallbackInfoArray& callbacks =
+ self->GetCallbacks();
+ std::vector<float> float_array;
+ float_array.reserve(callbacks.size());
+ for (unsigned ii = 0; ii < callbacks.size(); ++ii) {
+ float_array.push_back(callbacks[ii].count());
+ }
+ return float_array;
+ }
+ %}
+}; // Counter
+
+%[
+ A Counter that counts seconds.
+%]
+[nocpp, include="core/cross/counter.h"] class SecondCounter
+ : Counter {
+}; // SecondCounter
+
+%[
+ A Counter that counts render frames.
+%]
+[nocpp, include="core/cross/counter.h"] class RenderFrameCounter
+ : Counter {
+}; // RenderFrameCounter
+
+%[
+ A Counter that counts ticks.
+%]
+[nocpp, include="core/cross/counter.h"] class TickCounter
+ : Counter {
+}; // TickCounter
+
+} // namespace o3d
diff --git a/o3d/plugin/idl/cursor.idl b/o3d/plugin/idl/cursor.idl
new file mode 100644
index 0000000..9899bba
--- /dev/null
+++ b/o3d/plugin/idl/cursor.idl
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// This file contains the IDL declaration of the CursorType enumeration.
+
+namespace o3d {
+
+[include="core/cross/cursor.h"]
+namespace Cursor {
+
+%[
+ \var CursorType
+ \li DEFAULT
+ \li NONE
+ \li CROSSHAIR
+ \li POINTER
+ \li E_RESIZE
+ \li NE_RESIZE
+ \li NW_RESIZE
+ \li N_RESIZE
+ \li SE_RESIZE
+ \li SW_RESIZE
+ \li S_RESIZE
+ \li W_RESIZE
+ \li MOVE
+ \li TEXT
+ \li WAIT
+ \li PROGRESS
+ \li HELP
+%]
+enum CursorType {
+ DEFAULT,
+ NONE,
+ CROSSHAIR,
+ POINTER,
+ E_RESIZE,
+ NE_RESIZE,
+ NW_RESIZE,
+ N_RESIZE,
+ SE_RESIZE,
+ SW_RESIZE,
+ S_RESIZE,
+ W_RESIZE,
+ MOVE,
+ TEXT,
+ WAIT,
+ PROGRESS,
+ HELP
+};
+
+} // namespace Cursor
+
+} // namespace o3d
diff --git a/o3d/plugin/idl/curve.idl b/o3d/plugin/idl/curve.idl
new file mode 100644
index 0000000..0f876f2
--- /dev/null
+++ b/o3d/plugin/idl/curve.idl
@@ -0,0 +1,326 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace o3d {
+
+%[
+ A CurveKey prepresents a key on an Curve.
+%]
+[nocpp, include="core/cross/curve.h"]
+class CurveKey : ObjectBase {
+
+ %[
+ The input of this key.
+ %]
+ [getter, setter, userglue_setter] float input;
+
+ %[
+ The output of this key.
+ %]
+ [getter, setter, userglue_setter] float output;
+
+ %[
+ Destroys this key, removing it from its owner.
+ %]
+ void Destroy();
+
+ [verbatim=cpp_glue] %{
+ void userglue_setter_input(o3d::CurveKey* self, float value) {
+ self->SetInput(value);
+ }
+ void userglue_setter_output(o3d::CurveKey* self, float value) {
+ self->SetOutput(value);
+ }
+ %}
+}; // CurveKey
+
+typedef CurveKey[] CurveKeyArray;
+
+%[
+ An CurveKey that holds its output (is not interpolated between this key
+ and the next.)
+%]
+[nocpp, include="core/cross/curve.h"]
+class StepCurveKey : CurveKey {
+};
+
+%[
+ An CurveKey that linearly interpolates between this key and the next key.
+%]
+[nocpp, include="core/cross/curve.h"]
+class LinearCurveKey : CurveKey {
+};
+
+%[
+ An CurveKey that uses a bezier curve for interpolation between this key
+ and the next.
+%]
+[nocpp, include="core/cross/curve.h"]
+class BezierCurveKey : CurveKey {
+ %[
+ The in tangent for this key.
+ %]
+ [setter, getter, userglue_setter] Float2 in_tangent;
+
+ %[
+ The out tangent for this key.
+ %]
+ [setter, getter, userglue_setter] Float2 out_tangent;
+
+ [verbatim=cpp_glue] %{
+ void userglue_setter_in_tangent(o3d::BezierCurveKey* self,
+ const o3d::Float2& tangent) {
+ self->SetInTangent(tangent);
+ }
+ void userglue_setter_out_tangent(o3d::BezierCurveKey* self,
+ const o3d::Float2& tangent) {
+ self->SetOutTangent(tangent);
+ }
+ %}
+};
+
+%[
+ A Curve stores a bunch of CurveKeys and given a value
+ representing an input point on a curve returns the output of the curve for
+ that input. Curve is data only. It is used by 1 or more
+ FunctionEval objects or by direct use from javascript.
+%]
+[nocpp, include="core/cross/curve.h"]
+class Curve : Function {
+ %[
+ enum Infinity {
+ \li CONSTANT, Uses the output value of the first or last animation key.
+ \li LINEAR, Takes the distance between the closest animation key
+ input value and the evaluation time. Multiplies this
+ distance against the instant slope at the closest
+ animation key and offsets the result with the closest
+ animation key output value.
+ \li CYCLE, Cycles over the first and last keys using
+ input = (input - first) % (last - first) + first;
+ Note that in CYCLE mode you can never get the end output
+ because a cycle goes from start to end exclusive of end.
+ \li CYCLE_RELATIVE, Same as cycle except the offset of the entire
+ cycle is added to each consecutive cycle.
+ \li OSCILLATE, Ping Pongs between the first and last keys.
+ };
+ %]
+ enum Infinity {
+ CONSTANT,
+ LINEAR,
+ CYCLE,
+ CYCLE_RELATIVE,
+ OSCILLATE
+ };
+
+ %[
+ The behavior of the curve before the first key.
+ %]
+ [getter, setter] Infinity pre_infinity;
+
+ %[
+ The behavior of the curve after the last key.
+ %]
+ [getter, setter] Infinity post_infinity;
+
+ %[
+ Whether or not a cache is used to speed up evaluation of this Curve
+ \sa SetSampleRate
+ %]
+ [getter, setter] bool use_cache;
+
+ %[
+ Gets the sample rate for the cache. By default Animation data is
+ cached so that using the animation is fast. To do this the keys that
+ represent the animation are sampled. The higher the frequency of the
+ samples the closer the cache will match the actual keys.
+ The default is 1/30 (30hz). You can set it anywhere from 1/240th (240hz) to
+ any larger value. Note: Setting the sample rate has the side effect of
+ invalidating the cache thereby causing it to get rebuilt.
+ Must be 1/240 or greater. Default = 1/30
+ %]
+ [getter, setter, userglue_setter] float sample_rate;
+
+ %[
+ Returns whether or not the curve is discontinuous. A discontinuous curve
+ takes more time to evaluate.
+ %]
+ [const] bool IsDiscontinuous();
+
+ %[
+ The keys for this curve.
+ %]
+ [const, getter, userglue_getter] CurveKeyArray keys;
+
+ %[
+ Adds 1 or more StepKeys to this Curve.
+
+ Example:
+ \code
+ // Creates 2 keys.
+ // 1 key at 0 with an output of 10
+ // 1 key at 20 with an output of 30
+ curve.addStepKeys([0,10,20,30]);
+ \endcode.
+
+ \param keys Array of input, output pairs.
+ %]
+ [userglue] void AddStepKeys(NumberArray keys);
+
+ %[
+ Adds 1 or more LinearKeys to this Curve.
+
+ Example:
+ \code
+ // Creates 2 keys.
+ // 1 key at 0 with an output of 10
+ // 1 key at 20 with an output of 30
+ curve.addLinearKeys([0,10,20,30]);
+ \endcode.
+
+ \param keys Array of input, output pairs.
+ %]
+ [userglue] void AddLinearKeys(NumberArray keys);
+
+ %[
+ Adds 1 or more BezierKeys to this Curve.
+
+ Example:
+ \code
+ // Creates 2 keys.
+ // 1 key at 0 with an output of 10, in tangent of 1,9, out tangent 9,0.5
+ // 1 key at 20 with an output of 30, in tangent of 30, 3, out tangent 4, 28
+ curve.addBezierKeys([0,10,1,9,9,0.5,2,30,3,4,28]);
+ \endcode.
+
+ \param keys Array of input, output pairs.
+ %]
+ [userglue] void AddBezierKeys(NumberArray keys);
+
+ %[
+ Creates a new key for this curve.
+ \param key_type name of key class to create. Valid type names are:
+ \li 'o3d.StepCurveKey',
+ \li 'o3d.LinearCurveKey',
+ \li 'o3d.BezierCurveKey',
+ \return The created key.
+ %]
+ [userglue] CurveKey CreateKey(String key_type);
+
+ %[
+ Deserializes from the curve data given a RawData object.
+
+ \param raw_data contains curve data
+ \param offset is a byte offset from the start of raw_data
+ \param length is the byte length of the data to set
+ \return True if operation was successful.
+ %]
+ bool Set(o3d::RawData raw_data,
+ size_t offset,
+ size_t length);
+
+ %[
+ Deserializes from the curve data given a RawData object.
+ \param raw_data entire contents contains curve data
+ \return True if operation was successful.
+ %]
+ bool Set(o3d::RawData raw_data);
+
+ [verbatim=cpp_glue] %{
+ void userglue_setter_sample_rate(o3d::Curve* self, float rate) {
+ self->SetSampleRate(rate);
+ }
+ o3d::CurveKey* userglue_method_CreateKey(o3d::Curve* self,
+ o3d::String& key_type) {
+ return self->CreateKeyByClassName(key_type);
+ }
+ void userglue_method_AddStepKeys(o3d::Curve* self,
+ const std::vector<float>& values) {
+ const int kNumStepKeyValues = 2;
+ if (values.size() % kNumStepKeyValues != 0) {
+ O3D_ERROR(self->service_locator())
+ << "expected multiple of 2 values got " << values.size();
+ } else {
+ for (unsigned ii = 0; ii < values.size(); ii += kNumStepKeyValues) {
+ o3d::StepCurveKey* key = self->Create<o3d::StepCurveKey>();
+ key->SetInput(values[ii]);
+ key->SetOutput(values[ii + 1]);
+ }
+ }
+ }
+ void userglue_method_AddLinearKeys(o3d::Curve* self,
+ const std::vector<float>& values) {
+ const int kNumLinearKeyValues = 2;
+ if (values.size() % kNumLinearKeyValues != 0) {
+ O3D_ERROR(self->service_locator())
+ << "expected multiple of 2 values got " << values.size();
+ } else {
+ for (unsigned ii = 0; ii < values.size(); ii += kNumLinearKeyValues) {
+ o3d::LinearCurveKey* key =
+ self->Create<o3d::LinearCurveKey>();
+ key->SetInput(values[ii]);
+ key->SetOutput(values[ii + 1]);
+ }
+ }
+ }
+ void userglue_method_AddBezierKeys(o3d::Curve* self,
+ const std::vector<float>& values) {
+ const int kNumBezierKeyValues = 6;
+ if (values.size() % kNumBezierKeyValues != 0) {
+ O3D_ERROR(self->service_locator())
+ << "expected multiple of 6 values got " << values.size();
+ } else {
+ for (unsigned ii = 0; ii < values.size(); ii += kNumBezierKeyValues) {
+ o3d::BezierCurveKey* key =
+ self->Create<o3d::BezierCurveKey>();
+ key->SetInput(values[ii]);
+ key->SetOutput(values[ii + 1]);
+ key->SetInTangent(o3d::Float2(values[ii + 2],
+ values[ii + 3]));
+ key->SetOutTangent(o3d::Float2(values[ii + 4],
+ values[ii + 5]));
+ }
+ }
+ }
+ o3d::CurveKeyArray userglue_getter_keys(o3d::Curve* self) {
+ const o3d::CurveKeyRefArray& source_keys = self->keys();
+ o3d::CurveKeyArray keys;
+ keys.reserve(source_keys.size());
+ for (unsigned ii = 0; ii < source_keys.size(); ++ii) {
+ keys.push_back(source_keys[ii].Get());
+ }
+ return keys;
+ }
+ %}
+}; // Curve
+
+} // namespace o3d
+
+
diff --git a/o3d/plugin/idl/display_mode.idl b/o3d/plugin/idl/display_mode.idl
new file mode 100644
index 0000000..9f5efd7
--- /dev/null
+++ b/o3d/plugin/idl/display_mode.idl
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace o3d {
+
+%[
+ A DisplayMode describes the size and refresh rate of a display mode; it's
+ usually used in [or when transitioning into] fullscreen mode.%]
+
+[binding_model=by_value, nocpp, include="core/cross/display_mode.h"]
+class DisplayMode {
+
+ %[
+ The width in pixels of the screen when in this mode.
+ %]
+ [getter] int width;
+
+ %[
+ The height in pixels of the screen when in this mode.
+ %]
+ [getter] int height;
+
+ %[
+ The refresh rate in Hz.
+ %]
+ [getter] int refresh_rate;
+
+ %[
+ An opaque identifier used to identify the mode when requesting a fullscreen
+ transition.
+ %]
+ [getter] int id;
+
+}; // DisplayMode
+
+} // namespace o3d
diff --git a/o3d/plugin/idl/draw_context.idl b/o3d/plugin/idl/draw_context.idl
new file mode 100644
index 0000000..cf1aae4
--- /dev/null
+++ b/o3d/plugin/idl/draw_context.idl
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace o3d {
+
+%[
+ The DrawContext defines the parameters used for a particular drawing pass.
+ It contains two 4-by-4 matrix params, view and
+ projection. These correspond to the viewing and projection transformation
+ matrices.
+%]
+
+[nocpp, include="core/cross/draw_context.h"] class DrawContext
+ : ParamObject {
+ %[
+ The view matrix represents the viewing transformation, used to take vertices
+ from world space to view space.
+ %]
+ [getter, setter] Vectormath::Aos::Matrix4 view;
+
+ %[
+ The projection matrix represents the projection transformation, used to take
+ vertices from view space to screen space. This matrix is usually an
+ orthographic or perspective transformation.
+ %]
+ [getter, setter] Vectormath::Aos::Matrix4 projection;
+}; // DrawContext
+
+} // namespace o3d
diff --git a/o3d/plugin/idl/draw_element.idl b/o3d/plugin/idl/draw_element.idl
new file mode 100644
index 0000000..d07800c
--- /dev/null
+++ b/o3d/plugin/idl/draw_element.idl
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace o3d {
+
+%[
+ A DrawElement causes an Element to be Drawn with a particular material.
+ You can override other Effect parameters by adding corresponding params to
+ the DrawElement.
+
+ \sa Element
+ \sa Material
+ \sa Effect
+%]
+[nocpp, include="core/cross/material.h"] class DrawElement
+ : ParamObject {
+
+ %[
+ The Material for this Draw Element. If it is null the material of owner will
+ be used.
+ %]
+ [getter, setter] Material? material_;
+
+ %[
+ The current owner of this Draw Element. Set to null to stop being owned.
+
+ Note: DrawElements are referenced by the Pack they are created in and their
+ owner. If the DrawElement is removed from its Pack then setting the owner
+ to null will free the DrawElement. Or, visa versa, if you set the
+ DrawElement's owner to null then removing it from its Pack will free the
+ DrawElement.
+ %]
+ [getter, setter, userglue_setter] Element? owner_;
+
+ [verbatim=cpp_glue] %{
+ void userglue_setter_owner_(
+ o3d::DrawElement* _this,
+ o3d::Element* owner) {
+ _this->SetOwner(owner);
+ }
+ %}
+}; // DrawElement
+
+typedef DrawElement[] DrawElementArray;
+
+} // namespace o3d
diff --git a/o3d/plugin/idl/draw_list.idl b/o3d/plugin/idl/draw_list.idl
new file mode 100644
index 0000000..7a46e0b
--- /dev/null
+++ b/o3d/plugin/idl/draw_list.idl
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace o3d {
+
+%[
+ A DrawList gets used during rendering to collect DrawElements to
+ render. Each Material references a DrawList. Depending on the material, as
+ DrawElements get collected they will be put on different DrawLists.
+%]
+[nocpp, include="core/cross/draw_list.h"] class DrawList
+ : NamedObject {
+ %[
+ \var SortMethod,
+ \li BY_PERFORMANCE
+ \li BY_Z_ORDER
+ \li BY_PRIORITY
+
+ Method to sort DrawList by.
+ %]
+ enum SortMethod {
+ BY_PERFORMANCE = 0,
+ BY_Z_ORDER = 1,
+ BY_PRIORITY = 2
+ };
+
+ [getter] unsigned int global_index_;
+}; // DrawList
+
+} // namespace o3d
diff --git a/o3d/plugin/idl/draw_pass.idl b/o3d/plugin/idl/draw_pass.idl
new file mode 100644
index 0000000..6fd6eab
--- /dev/null
+++ b/o3d/plugin/idl/draw_pass.idl
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace o3d {
+
+%[
+ A DrawPass renders a DrawList.
+%]
+[nocpp, include="core/cross/draw_pass.h"] class DrawPass
+ : RenderNode {
+ %[
+ The DrawList for this DrawPass.
+ %]
+ [getter, setter] DrawList? draw_list_;
+
+ %[
+ The sort method for this DrawPass to draw the DrawList by.
+ %]
+ [getter, setter] DrawList::SortMethod sort_method_;
+}; // Material
+
+} // namespace o3d
diff --git a/o3d/plugin/idl/effect.idl b/o3d/plugin/idl/effect.idl
new file mode 100644
index 0000000..b6d2243
--- /dev/null
+++ b/o3d/plugin/idl/effect.idl
@@ -0,0 +1,230 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace o3d {
+
+%[
+ EffectParameterInfo holds information about the Parameters an Effect needs.
+ \sa o3d.Effect.getParameterInfo
+%]
+[binding_model=by_value, nocpp, include="core/cross/effect.h"]
+class EffectParameterInfo {
+ %[
+ The name of the parameter.
+ %]
+ [getter] String name;
+
+ %[
+ The type of the parameter.
+ %]
+ [userglue_getter, getter] String class_name;
+
+ %[
+ The number of elements. Non-zero for array types, zero for non-array types.
+ %]
+ [getter] int num_elements;
+
+ %[
+ The semantic of the parameter. This is always in UPPERCASE.
+ %]
+ [getter] String semantic;
+
+ %[
+ If this is a standard parameter (SAS) this will be the name of the type
+ of Param needed. Otherwise it will be the empty string.
+
+ Standard Parameters are generally handled automatically by o3d but you
+ can supply your own if you have a unique situation.
+ %]
+ [userglue_getter, getter] String sas_class_name;
+
+ [verbatim=cpp_glue] %{
+ o3d::String userglue_getter_class_name(
+ const o3d::EffectParameterInfo& self) {
+ return self.class_type()->name();
+ }
+ o3d::String userglue_getter_sas_class_name(
+ const o3d::EffectParameterInfo& self) {
+ return self.sas_class_type() ? self.sas_class_type()->name() : "";
+ }
+ %}
+};
+
+typedef EffectParameterInfo[] EffectParameterInfoArray;
+
+%[
+ EffectStreamInfo holds information about the Streams an Effect needs.
+ \sa o3d.Effect.getStreamInfo
+%]
+[binding_model=by_value, nocpp, include="core/cross/effect.h"]
+class EffectStreamInfo {
+ %[
+ The semantic of the stream.
+ %]
+ [getter] Stream::Semantic semantic;
+
+ %[
+ The semantic index of the stream.
+ %]
+ [getter] int semantic_index;
+};
+
+typedef EffectStreamInfo[] EffectStreamInfoArray;
+
+%[
+ An Effect contains a vertex and pixel shader.
+%]
+
+[nocpp, include="core/cross/effect.h"] class Effect : ParamObject {
+ %[
+ Loads the vertex and pixel shader programs from an string containing
+ an O3D FX description.
+
+ The string is subset of CG and HLSL. No techinques are allowed.
+
+ To define the entry points add 2 lines in the following format.
+ \code
+ "// #o3d VertexShaderEntryPoint myVertexShader\n"
+ "// #o3d PixelShaderEntryPoint myPixelShader\n"
+ \endcode
+
+ where "myVertexShader" and "myPixelShader" are the names of your
+ vertex and pixel shaders. At this time the format of those 2 lines
+ is extremely strict. You must have 1 and exactly 1 space between // and
+ #o3d, between #o3d and
+ VertexShaderEntryPoint/PixelShaderEntryPoint and between those and your
+ entry points.
+
+ You must also specify a matrix load order like this.
+
+ \code
+ // #o3d MatrixLoadOrder RowMajor
+ \endcode
+
+ Valid orders are RowMajor and ColumnMajor
+
+ Note: Currently it is possible to create effects strings that work on only
+ one platform (GL or D3D). You should test your shaders on both platforms.
+
+ By version 1.0 this function will enforce shaders
+ that only work on both platforms. That format is mostly CG.
+
+ \param effect the code of the effect.
+ %]
+ [virtual, pure] bool LoadFromFXString(String effect);
+
+ %[
+ For each of the effect's uniform parameters, creates corresponding
+ parameters on the given ParamObject. Skips SAS Parameters.
+
+ If a Param with the same name but the wrong type already exists on the
+ given ParamObject CreateUniformParameters will attempt to replace it with
+ one of the correct type.
+
+ Note: The most common thing to pass to this function is a Material but
+ depending on your application it may be more appropriate to pass in a
+ Transform, Effect, Element or DrawElement.
+
+ \param param_object The param object on which the new paramters will be
+ created.
+ \sa o3d.Effect.createSASParameters
+ %]
+ void CreateUniformParameters(ParamObject param_object);
+
+ %[
+ For each of the effect's uniform parameters, if it is a SAS parameter
+ creates corresponding StandardParamMatrix4 parameters on the given
+ ParamObject. Note that SAS parameters are handled automatically by the
+ rendering system. so except in some rare cases there is no reason to call
+ this function. Also be aware that the StandardParamMatrix4 Paramters like
+ WorldViewProjectionParamMatrix4, etc.. are only valid during rendering.
+ At all other times they will not return valid values.
+
+ If a Param with the same name but the wrong type already exists on the
+ given ParamObject CreateSASParameters will attempt to replace it with
+ one of the correct type.
+
+ \param param_object The param object on which the new paramters will be
+ created.
+ \sa o3d.Effect.createUniformParameters
+ %]
+ void CreateSASParameters(ParamObject param_object);
+
+ %[
+ Gets info about the parameters this effect needs.
+ \return an array of EffectParameterInfos.
+ %]
+ [userglue] EffectParameterInfoArray GetParameterInfo();
+
+ %[
+ Gets info about the streams this effect needs.
+ \return an array of EffectParameterInfos.
+ %]
+ [userglue] EffectStreamInfoArray GetStreamInfo();
+
+ %[
+ \var Property,
+ \li ROW_MAJOR, Matrix parameters are loaded in row-major order (DX-style).
+ \li COLUMN_MAJOR, Matrix parameters are loaded in column-major order
+ (OpenGL-style).
+ %]
+ enum MatrixLoadOrder {
+ ROW_MAJOR,
+ COLUMN_MAJOR
+ };
+
+ %[
+ The order in which matrix data is loaded to the GPU.
+ %]
+ [getter] MatrixLoadOrder matrix_load_order_;
+
+ %[
+ The source for the shaders on this Effect.
+ %]
+ [getter] String source_;
+
+ [verbatim=cpp_glue] %{
+ std::vector<o3d::EffectParameterInfo> userglue_method_GetParameterInfo(
+ o3d::Effect* self) {
+ std::vector<o3d::EffectParameterInfo> info_array;
+ self->GetParameterInfo(&info_array);
+ return info_array;
+ }
+ std::vector<o3d::EffectStreamInfo> userglue_method_GetStreamInfo(
+ o3d::Effect* self) {
+ std::vector<o3d::EffectStreamInfo> info_array;
+ self->GetStreamInfo(&info_array);
+ return info_array;
+ }
+ %}
+};
+
+} // namespace o3d
diff --git a/o3d/plugin/idl/element.idl b/o3d/plugin/idl/element.idl
new file mode 100644
index 0000000..e18ae2e
--- /dev/null
+++ b/o3d/plugin/idl/element.idl
@@ -0,0 +1,172 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace o3d {
+
+typedef DrawElement[] DrawElementArray;
+
+%[
+ An Element manages DrawElements for classes inherited from Element.
+%]
+[nocpp, include="core/cross/element.h"] class Element : ParamObject {
+
+ %[
+ The Material for this element.
+ %]
+ [getter, setter] Material? material_;
+
+ %[
+ The BoundingBox for this element. If culling is on this bounding box will be
+ tested against the view frustum of any draw context used to render this
+ Element.
+ %]
+ [getter, setter] BoundingBox bounding_box_;
+
+ %[
+ The z sort point for this element. If this Element is drawn by a DrawPass
+ that is set to sort by z order this value will be multiplied by the
+ worldViewProjection matrix to compute a z value to sort by.
+ %]
+ [getter, setter] Float3 z_sort_point;
+
+ %[
+ The priority for this element. Used to sort if this Element is drawn by a
+ DrawPass that is set to sort by priority.
+ %]
+ [getter, setter] float priority_;
+
+ %[
+ The cull settings for this element. If true this Element will be culled
+ by the bounding box above compared to the view frustum it is being rendered
+ with.
+ %]
+ [getter, setter] bool cull_;
+
+ %[
+ The current owner of this Draw Element. Pass in null to stop being owned.
+
+ Note: Elements are referenced by the Pack they are created in and their
+ owner. If the Element is removed from its Pack then setting the owner
+ to null will free the Element. Or, visa versa, if you set the
+ Element's owner to null then removing it from its Pack will free the
+ Element.
+ %]
+ [getter, setter, userglue_setter] Shape? owner_;
+
+ %[
+ Gets all the DrawElements under this Element.
+
+ Each access to this field gets the entire list so it is best to get it
+ just once. For example:
+ \code
+ var drawElements = element.drawElements;
+ for (var i = 0; i < drawElements.length; i++) {
+ var drawElement = drawElements[i];
+ }
+ \endcode
+
+ Note that modifications to this array [e.g. push()] will not affect
+ the underlying Element, while modifications to the members of the array.
+ <strong>will</strong> affect them.
+ %]
+ [userglue_getter, getter] DrawElementArray draw_elements_;
+
+ %[
+ Creates a DrawElement for this Element. Note that unlike
+ Shape.createDrawElements and Transform.createDrawElements this one will
+ create more than one element for the same material.
+
+ \param pack: pack used to manage created DrawElement.
+ \param material: material to use for DrawElement. If you pass null
+ it will use the material on this Element. This allows you to easily
+ setup the default (just draw as is) by passing null or setup a shadow
+ pass by passing in a shadow material.
+ %]
+ DrawElement CreateDrawElement(Pack pack,
+ Material? material);
+
+ %[
+ Computes the intersection of a ray in the same coordinate system as
+ the specified POSITION stream.
+ \param position_stream_index Index of POSITION stream.
+ \param cull which side of the triangles to ignore.
+ \param start position of start of ray in local space.
+ \param end position of end of ray. in local space.
+ \return RayIntersectionInfo class. If valid() is false then something
+ was wrong, Check client::GetLastError(). If intersected() is true then
+ the ray intersected a something. position() is the exact point of
+ intersection.
+ %]
+ [const, userglue] RayIntersectionInfo IntersectRay(
+ int position_stream_index,
+ State::Cull cull,
+ Vectormath::Aos::Point3 start,
+ Vectormath::Aos::Point3 end);
+
+ %[
+ Computes the bounding box in same coordinate system as the specified
+ POSITION stream.
+ \param position_stream_index Index of POSITION stream.
+ \return The boundingbox for this element in local space.
+ %]
+ [const, userglue] BoundingBox GetBoundingBox(int position_stream_index);
+
+ [verbatim=cpp_glue] %{
+ void userglue_setter_owner_(
+ o3d::Element* _this,
+ o3d::Shape* owner) {
+ _this->SetOwner(owner);
+ }
+ o3d::RayIntersectionInfo userglue_method_IntersectRay(
+ o3d::Element* self,
+ int semantic_index,
+ o3d::State::Cull cull,
+ const Vectormath::Aos::Point3& start,
+ const Vectormath::Aos::Point3& end) {
+ o3d::RayIntersectionInfo result;
+ self->IntersectRay(semantic_index, cull, start, end, &result);
+ return result;
+ }
+ o3d::BoundingBox userglue_method_GetBoundingBox(
+ o3d::Element* self,
+ int semantic_index) {
+ o3d::BoundingBox result;
+ self->GetBoundingBox(semantic_index, &result);
+ return result;
+ }
+ o3d::DrawElementArray userglue_getter_draw_elements_(
+ o3d::Element* self) {
+ return self->GetDrawElements();
+ }
+ %}
+}; // Element
+
+} // namespace o3d
diff --git a/o3d/plugin/idl/event.idl b/o3d/plugin/idl/event.idl
new file mode 100644
index 0000000..ba6f315
--- /dev/null
+++ b/o3d/plugin/idl/event.idl
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// This file contains the public interface specification for the event object
+// passed to event handlers by the client.
+
+namespace o3d {
+
+%[
+ An Event object contains information describing a JavaScript event; it's used
+ as an argument to event handlers triggered by the plugin.%]
+
+[binding_model=by_value, nocpp, include="core/cross/event.h"]
+class Event {
+
+ %[
+ String identifiers for JavaScript events.
+ \var type
+ \li invalid
+ \li click
+ \li dblclick
+ \li mousedown
+ \li mousemove
+ \li mouseup
+ \li wheel
+ \li keydown
+ \li keypress
+ \li keyup
+ \li resize
+ %]
+ enum Type {
+ TYPE_INVALID,
+ TYPE_CLICK,
+ TYPE_DBLCLICK,
+ TYPE_MOUSEDOWN,
+ TYPE_MOUSEMOVE,
+ TYPE_MOUSEUP,
+ TYPE_WHEEL,
+ TYPE_KEYDOWN,
+ TYPE_KEYPRESS,
+ TYPE_KEYUP,
+ TYPE_RESIZE
+ };
+ %[
+ The type of event this object represents.
+ \var type
+ \li invalid
+ \li click
+ \li dblclick
+ \li keydown
+ \li keypress
+ \li keyup
+ \li mousedown
+ \li mousemove
+ \li mouseup
+ \li wheel
+ \li resize
+ %]
+ [userglue_getter, getter] String type;
+ %[
+ \var Button,
+ \li BUTTON_LEFT
+ \li BUTTON_RIGHT
+ \li BUTTON_MIDDLE
+ \li BUTTON_4
+ \li BUTTON_5
+ Constants used to identify mouse buttons.
+ %]
+ enum Button {
+ BUTTON_LEFT = 0,
+ BUTTON_MIDDLE = 1,
+ BUTTON_RIGHT = 2,
+ BUTTON_4 = 3,
+ BUTTON_5 = 4
+ };
+ %[
+ Which mouse button caused the event, in the case of mousedown, mouseup,
+ click, and dblclick events. This uses the values in enum Button.
+ %]
+ [getter] int button;
+ %[
+ Whether the ctrl key was pressed at the time of the event.
+ %]
+ [getter] bool ctrl_key;
+ %[
+ Whether the alt [option, on OSX] key was pressed at the time of the event.
+ %]
+ [getter] bool alt_key;
+ %[
+ Whether the shift key was pressed at the time of the event.
+ %]
+ [getter] bool shift_key;
+ %[
+ Whether the meta [command, on OSX] key was pressed at the time of the event.
+ %]
+ [getter] bool meta_key;
+ %[
+ The key code of the key pressed or released.
+ %]
+ [getter] int key_code;
+ %[
+ The character created by a keypress event.
+ %]
+ [getter, property=r] int char_code;
+ %[
+ The x-coordinate in pixels from the left side of the plugin or fullscreen
+ display region.
+ %]
+ [getter] int x;
+ %[
+ The y-coordinate in pixels from the top of the plugin or fullscreen
+ display region.
+ %]
+ [getter] int y;
+ %[
+ The x-coordinate in pixels from the left side of the screen.
+ %]
+ [getter] int screen_x;
+ %[
+ The y-coordinate in pixels from the top of the screen.
+ %]
+ [getter] int screen_y;
+ %[
+ The horizontal scroll offset for wheel events, in arbitrary units.
+ Positive values mean right; negative mean left.
+ %]
+ [getter] int delta_x;
+ %[
+ The vertical scroll offset for wheel events, in arbitrary units.
+ Positive values mean up or away from the user; negative mean down or toward
+ the user.
+ %]
+ [getter] int delta_y;
+ %[
+ The width in pixels of the plugin or fullscreen display region as a result
+ of this event.
+ %]
+ [getter] int width;
+ %[
+ The height in pixels of the plugin or fullscreen display region as a result
+ of this event.
+ %]
+ [getter] int height;
+ %[
+ Whether we're currently displaying in fullscreen mode.
+ %]
+ [getter] bool fullscreen;
+
+ [verbatim=cpp_glue] %{
+ o3d::String userglue_getter_type(
+ const o3d::Event& self) {
+ return self.type_string();
+ }
+ %}
+}; // Event
+
+} // namespace o3d
diff --git a/o3d/plugin/idl/field.idl b/o3d/plugin/idl/field.idl
new file mode 100644
index 0000000..df3ca41
--- /dev/null
+++ b/o3d/plugin/idl/field.idl
@@ -0,0 +1,242 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace o3d {
+
+%[
+ A Field is a base class that manages a set of components in a
+ Buffer of a specific type. Fields are managed by Buffers and can not be
+ directly created. When a Buffer is destroyed or if a Field is removed from a
+ Buffer the Field's buffer property will be set to null.
+%]
+[nocpp, include="core/cross/buffer.h"]
+class Field : NamedObject {
+ %[
+ The number of components in this field.
+ %]
+ [getter] unsigned int num_components;
+
+ %[
+ The Buffer the field belongs to.
+ %]
+ [getter] Buffer? buffer;
+
+ %[
+ The offset of this field in the Buffer in bytes.
+ %]
+ [getter] unsigned int offset;
+
+ %[
+ The size of one element of this field.
+ %]
+ [getter] unsigned int size;
+};
+
+%[
+ A field that contains floating point numbers.
+%]
+[nocpp, include="core/cross/buffer.h"]
+class FloatField : Field {
+ %[
+ Sets the values of the data stored in the field.
+
+ The buffer for the field must have already been created either through
+ buffer.set or through buffer.allocateElements.
+
+ The number of values passed in must be a multiple of the number of
+ components needed for the field.
+
+ \param start_index index of first value to set.
+ \param values Values to be stored in the buffer starting at index.
+ %]
+ [userglue] void SetAt(unsigned int start_index, float[] values);
+
+ %[
+ Gets the values stored in the field.
+
+ \param start_index index of the first value to get.
+ \param num_elements number of elements to read from field.
+ %]
+ [userglue] float[] GetAt(unsigned int start_index, unsigned int num_elements);
+
+ [verbatim=cpp_glue] %{
+ void userglue_method_SetAt(o3d::FloatField* field,
+ unsigned int start_index,
+ const std::vector<float>& values) {
+ if (values.size() % field->num_components() != 0) {
+ O3D_ERROR(field->service_locator())
+ << "the number of values passed in is not a multiple of the number"
+ << " of components in the field.";
+ return;
+ }
+ if (!values.empty()) {
+ field->SetFromFloats(&values[0], field->num_components(), start_index,
+ values.size() / field->num_components());
+ }
+ }
+ std::vector<float> userglue_method_GetAt(
+ o3d::FloatField* field,
+ unsigned int start_index,
+ unsigned int num_elements) {
+ std::vector<float> retval;
+ if (field->RangeValid(start_index, num_elements)) {
+ retval.resize(num_elements * field->num_components());
+ field->GetAsFloats(start_index, &retval[0], field->num_components(),
+ num_elements);
+ }
+ return retval;
+ }
+ %}
+};
+
+%[
+ A field that contains unsigned integers.
+%]
+[nocpp, include="core/cross/buffer.h"]
+class UInt32Field : Field {
+ %[
+ Sets the values of the data stored in the field.
+
+ The buffer for the field must have already been created either through
+ buffer.set or through buffer.allocateElements.
+
+ The number of values passed in must be a multiple of the number of
+ components needed for the field.
+
+ \param start_index index of first value to set.
+ \param values Values to be stored in the buffer starting at index.
+ %]
+ [userglue] void SetAt(unsigned int start_index, unsigned int[] values);
+
+ %[
+ Gets the values stored in the field.
+
+ \param start_index index of the first value to get.
+ \param num_elements number of elements to read from field.
+ %]
+ [userglue] unsigned int[] GetAt(unsigned int start_index,
+ unsigned int num_elements);
+
+ [verbatim=cpp_glue] %{
+ void userglue_method_SetAt(o3d::UInt32Field* field,
+ unsigned int start_index,
+ const std::vector<unsigned int>& values) {
+ if (values.size() % field->num_components() != 0) {
+ O3D_ERROR(field->service_locator())
+ << "the number of values passed in is not a multiple of the number"
+ << " of components in the field.";
+ return;
+ }
+ if (!values.empty()) {
+ field->SetFromUInt32s(&values[0], field->num_components(), start_index,
+ values.size() / field->num_components());
+ }
+ }
+ std::vector<uint32> userglue_method_GetAt(
+ o3d::UInt32Field* field,
+ unsigned int start_index,
+ unsigned int num_elements) {
+ std::vector<uint32> retval;
+ if (field->RangeValid(start_index, num_elements)) {
+ retval.resize(num_elements * field->num_components());
+ field->GetAsUInt32s(start_index, &retval[0], field->num_components(),
+ num_elements);
+ }
+ return retval;
+ }
+ %}
+};
+
+%[
+ A field that contains unsigned bytes that each represent a 0 to 1 value.
+ A typical use is for vertex colors since 4 bytes per vertex color are much
+ smaller than 4 floats per vertex color.
+%]
+[nocpp, include="core/cross/buffer.h"]
+class UByteNField : Field {
+ %[
+ Sets the values of the data stored in the field.
+
+ The buffer for the field must have already been created either through
+ buffer.set or through buffer.allocateElements.
+
+ The number of values passed in must be a multiple of the number of
+ components needed for the field.
+
+ \param start_index index of first value to set.
+ \param values Values to be stored in the buffer starting at index.
+ %]
+ [userglue] void SetAt(unsigned int start_index, float[] values);
+
+ %[
+ Gets the values stored in the field.
+
+ \param start_index index of the first value to get.
+ \param num_elements number of elements to read from field.
+ %]
+ [userglue] float[] GetAt(unsigned int start_index, unsigned int num_elements);
+
+ [verbatim=cpp_glue] %{
+ void userglue_method_SetAt(o3d::UByteNField* field,
+ unsigned int start_index,
+ const std::vector<float>& values) {
+ if (values.size() % field->num_components() != 0) {
+ O3D_ERROR(field->service_locator())
+ << "the number of values passed in is not a multiple of the number"
+ << " of components in the field.";
+ return;
+ }
+ if (!values.empty()) {
+ field->SetFromFloats(&values[0], field->num_components(), start_index,
+ values.size() / field->num_components());
+ }
+ }
+ std::vector<float> userglue_method_GetAt(
+ o3d::UByteNField* field,
+ unsigned int start_index,
+ unsigned int num_elements) {
+ std::vector<float> retval;
+ if (field->RangeValid(start_index, num_elements)) {
+ retval.resize(num_elements * field->num_components());
+ field->GetAsFloats(start_index, &retval[0], field->num_components(),
+ num_elements);
+ }
+ return retval;
+ }
+ %}
+};
+
+%[
+ An array of fields.
+%]
+typedef Field[] FieldArray;
+
+} // namespace o3d
diff --git a/o3d/plugin/idl/file_request.idl b/o3d/plugin/idl/file_request.idl
new file mode 100644
index 0000000..c0d6f77
--- /dev/null
+++ b/o3d/plugin/idl/file_request.idl
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace o3d {
+
+[include="core/cross/file_request.h"] callback void FileRequestCallback();
+
+%[
+ A FileRequest object is used to carry out an asynchronous request for a file
+ to be loaded. Its use parallels that of XMLHttpRequest; you create one, call
+ open, set the onreadystatechange callback, and call send.
+ Note that unlike XMLHttpRequests, FileRequests cannot be reused.
+
+ For texture loads, on success the texture will be stored in a field of the
+ same name on the FileRequest itself.
+
+ \code
+ var request = pack.createFileRequest("TEXTURE");
+ var texture;
+ request.open("GET", url, true);
+ request.onreadystatechange = function() {
+ if (request.done) {
+ if (request.success) {
+ texture = request.texture;
+ } else {
+ dump('Load of texture file returned failure.');
+ }
+ }
+ };
+ request.send();
+ \endcode
+%]
+
+[nocpp, include="core/cross/file_request.h"] class FileRequest
+ : ObjectBase {
+ [setter=set_onreadystatechange]
+ FileRequestCallback onreadystatechange;
+ [getter=uri] String uri;
+ %[
+ On completion of successful texture file loads, this holds the loaded
+ texture.
+ %]
+ [getter=texture] Texture? texture;
+ %[
+ Whether or not to generate mip-maps on textures that are loaded (default:
+ true). Mip-maps are not generated for DXTC textures. DDS files can contain
+ pre-computed mip-maps for DXTC textures though.
+ %]
+ [getter, setter] bool generate_mipmaps;
+
+ %[
+ This holds the same values as in XMLHttpRequest:
+ \li 0 = uninitialized
+ \li 1 = opened
+ \li 2 = sent
+ \li 3 = receiving
+ \li 4 = loaded (the file has been downloaded, but may or may not have been
+ parsed yet)
+ %]
+ [getter=ready_state] int readyState;
+ %[
+ This indicates whether any further processing will be done on this
+ FileRequest.
+ %]
+ [getter=done] bool done;
+ %[
+ This field is only valid if done is true. It indicates whether or not the
+ request succeeded. If it failed error holds an error message.
+ %]
+ [getter=success] bool success;
+
+ %[
+ An error message.
+ If done is true and success is false this will be an error message
+ describing what went wrong.
+ %]
+ [getter] String error;
+
+ %[
+ Set up several of the request fields.
+ \param method "GET" is the only supported method at this time
+ \param uri the location of the file to fetch
+ \param async true is the only legal value at this time
+ %]
+ [nocpp, userglue, plugin_data] void open(
+ String method, String uri, bool async);
+
+ %[
+ Send the request.
+ Unlike XMLHttpRequest the onreadystatechange callback will be called no
+ matter what, with success or failure.
+ %]
+ [nocpp, userglue, plugin_data] void send();
+};
+
+} // namespace o3d
diff --git a/o3d/plugin/idl/function.idl b/o3d/plugin/idl/function.idl
new file mode 100644
index 0000000..a13ea38
--- /dev/null
+++ b/o3d/plugin/idl/function.idl
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace o3d {
+
+%[
+ A Function is a class that has an Evaluate method. Evaluate takes 1 input and
+ returns 1 output.
+%]
+[nocpp, include="core/cross/function.h"]
+class Function : NamedObject {
+ %[
+ Gets an output for this function for the given input.
+ \param input Input to get output at.
+ \return The output for the given input.
+ %]
+ [const, userglue] float Evaluate(float input);
+
+ [verbatim=cpp_glue] %{
+ float userglue_method_Evaluate(o3d::Function* self, float value) {
+ return self->Evaluate(value, NULL);
+ }
+ %}
+}; // Function
+
+%[
+ A Param which stores a Function.
+%]
+[nocpp, include="core/cross/function.h"] class ParamFunction : Param {
+ %[
+ The Function stored by the Param.
+ %]
+ [getter, setter] Function? value_;
+};
+
+%[
+ A FunctionEval evaluates a Function through parameters.
+%]
+[nocpp, include="core/cross/function.h"]
+class FunctionEval : ParamObject {
+ %[
+ The input to the function
+ %]
+ [getter, setter] float input;
+
+ %[
+ The output of the function for the given input.
+ %]
+ [getter] float output;
+
+ %[
+ The function to evaluate.
+ %]
+ [getter, setter] Function? function_object;
+}; // FunctionEval
+
+} // namespace o3d
+
+
diff --git a/o3d/plugin/idl/material.idl b/o3d/plugin/idl/material.idl
new file mode 100644
index 0000000..7c4374d
--- /dev/null
+++ b/o3d/plugin/idl/material.idl
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace o3d {
+
+%[
+ A Material holds the various uniform parameters an Effect needs to render.
+ For example a Lambert effect might need "diffuse", "ambient", "emissive".
+ The parameters needed on a Material will vary depending its Effect.
+ Note that a material MUST have its drawList set in order for objects using it
+ to render.
+%]
+[nocpp, include="core/cross/material.h"] class Material : ParamObject {
+
+ %[
+ The Effect for this material.
+ %]
+ [getter, setter] Effect? effect_;
+
+ %[
+ The State for this material.
+ %]
+ [getter, setter] State? state_;
+
+ %[
+ The DrawList this material will render on.
+ %]
+ [getter, setter] DrawList? draw_list_;
+}; // Material
+
+} // namespace o3d
diff --git a/o3d/plugin/idl/matrix4_axis_rotation.idl b/o3d/plugin/idl/matrix4_axis_rotation.idl
new file mode 100644
index 0000000..de364c4
--- /dev/null
+++ b/o3d/plugin/idl/matrix4_axis_rotation.idl
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace o3d {
+
+%[
+ This param operation applies a rotation to its input matrix. The
+ rotation is specified in terms of an angle and an axis of rotation.
+ It can be used, for example, to supply the local matrix of a transform.
+%]
+[nocpp, include="core/cross/matrix4_axis_rotation.h"]
+class Matrix4AxisRotation : ParamObject {
+ %[
+ The local rotation axis. This must be a unit vector.
+ %]
+ [getter, setter] Float3 axis;
+
+ %[
+ The angle of rotation in radians.
+ %]
+ [getter, setter] float angle;
+
+ %[
+ The input matrix. Identity by default.
+ %]
+ [getter, setter] Vectormath::Aos::Matrix4 input_matrix;
+
+ %[
+ The output is equal to the rotation of the input matrix.
+ %]
+ [getter] Vectormath::Aos::Matrix4 output_matrix;
+}; // Matrix4AxisRotation
+
+} // namespace o3d
+
diff --git a/o3d/plugin/idl/matrix4_composition.idl b/o3d/plugin/idl/matrix4_composition.idl
new file mode 100644
index 0000000..87bbfc6
--- /dev/null
+++ b/o3d/plugin/idl/matrix4_composition.idl
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace o3d {
+
+%[
+ This param operation composes (multiplies) a local matrix with an input
+ matrix. It can be used, for example, to supply the local matrix of a
+ transform.
+%]
+[nocpp, include="core/cross/matrix4_composition.h"]
+class Matrix4Composition : ParamObject {
+ %[
+ The local matrix.
+ %]
+ [getter, setter] Vectormath::Aos::Matrix4 local_matrix;
+
+ %[
+ The input matrix. Identity by default.
+ %]
+ [getter, setter] Vectormath::Aos::Matrix4 input_matrix;
+
+ %[
+ The output is equal to the composition (multiplication) of the inpur
+ matrix with the local matrix.
+ %]
+ [getter] Vectormath::Aos::Matrix4 output_matrix;
+}; // Matrix4Composition
+
+} // namespace o3d
+
diff --git a/o3d/plugin/idl/matrix4_scale.idl b/o3d/plugin/idl/matrix4_scale.idl
new file mode 100644
index 0000000..ec567ee
--- /dev/null
+++ b/o3d/plugin/idl/matrix4_scale.idl
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace o3d {
+
+%[
+ This param operation applies a scaling to its input matrix.
+ It can be used, for example, to supply the local matrix of a transform.
+%]
+[nocpp, include="core/cross/matrix4_scale.h"]
+class Matrix4Scale : ParamObject {
+ %[
+ The local scaling.
+ %]
+ [getter, setter] Float3 scale;
+
+ %[
+ The parent matrix. Identity by default.
+ %]
+ [getter, setter] Vectormath::Aos::Matrix4 input_matrix;
+
+ %[
+ The output is equal to the scale of the input matrix.
+ %]
+ [getter] Vectormath::Aos::Matrix4 output_matrix;
+}; // Matrix4Scale
+
+} // namespace o3d
+
diff --git a/o3d/plugin/idl/matrix4_translation.idl b/o3d/plugin/idl/matrix4_translation.idl
new file mode 100644
index 0000000..29afdc3
--- /dev/null
+++ b/o3d/plugin/idl/matrix4_translation.idl
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace o3d {
+
+%[
+ This param operation applies a translation to its input matrix.
+ It can be used, for example, to supply the local matrix of a transform.
+%]
+[nocpp, include="core/cross/matrix4_translation.h"]
+class Matrix4Translation : ParamObject {
+ %[
+ The local translation.
+ %]
+ [getter, setter] Float3 translation;
+
+ %[
+ The input matrix. Identity by default.
+ %]
+ [getter, setter] Vectormath::Aos::Matrix4 input_matrix;
+
+ %[
+ The output is equal to the translation of the input matrix.
+ %]
+ [getter] Vectormath::Aos::Matrix4 output_matrix;
+}; // Matrix4Translation
+
+} // namespace o3d
+
diff --git a/o3d/plugin/idl/named.idl b/o3d/plugin/idl/named.idl
new file mode 100644
index 0000000..f9fc4c4
--- /dev/null
+++ b/o3d/plugin/idl/named.idl
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace o3d {
+
+%[
+ The base class of most O3D run-time objects.
+%]
+
+[binding_model=o3d,include="core/cross/object_base.h"]
+class ObjectBase {
+ %[
+ Unique id of the object.
+
+ This id will be unique, even across multiple O3D clients in the same
+ page.
+ %]
+ [getter, userglue_getter] Id client_id;
+
+ [verbatim=cpp_header] %{
+ static Class *GetApparentClass() { return NULL; }
+ %}
+
+ %[
+ The concrete class name for an object derived from ObjectBase.
+
+ If you want to know if an object is of a certain type you should use
+ objectBase.isAClassName
+
+ \code
+ var t = pack.createObject('o3d.Transform');
+ t.className == 'o3d.Transform'; // true
+ \endcode
+ %]
+ [userglue_getter, getter] String class_name_;
+
+ %[
+ Takes the name of a class as an argument, and returns true if this object is
+ either an instance of that class or derives from that class.
+ \code
+ var t = pack.createObject('o3d.Transform');
+ t.isAClassName('o3d.Transform'); // true
+ t.isAClassName('o3d.ParamObject'); // true
+ t.isAClassName('o3d.Shape'); // false
+ \endcode
+ \returns true if this object is a or is derived from the given class name.
+ %]
+ bool IsAClassName(String class_name);
+
+ [verbatim=cpp_glue] %{
+ o3d::Id userglue_getter_client_id(o3d::ObjectBase* self) {
+ return self->id();
+ }
+ o3d::String userglue_getter_class_name_(o3d::ObjectBase* self) {
+ return self->GetClassName();
+ }
+ %}
+};
+
+%[
+ Base class for all objects that are identifiable by a name.
+%]
+[binding_model=o3d, include="core/cross/named_object.h"]
+class NamedObjectBase: ObjectBase {
+ %[
+ The object's name.
+ %]
+ [getter] String name;
+
+};
+
+%[
+ Base class for all objects that can have their name set.
+%]
+[binding_model=o3d, include="core/cross/named_object.h"]
+class NamedObject: NamedObjectBase {
+ %[
+ The object's name.
+
+ Setting this has no meaning to O3D, but is useful for debugging and for
+ the functions Client.getObjects, Pack.getObject,
+ RenderNode.getRenderNodesByNameInTree and
+ RenderNode.getTransformsByNameInTree
+ which search for objects by name.
+ %]
+ // NOTE: I tried putting just setter here but nixysa can't handle that.
+ [getter, setter] String name;
+};
+
+} // namespace o3d
diff --git a/o3d/plugin/idl/pack.idl b/o3d/plugin/idl/pack.idl
new file mode 100644
index 0000000..460d2c6
--- /dev/null
+++ b/o3d/plugin/idl/pack.idl
@@ -0,0 +1,308 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace o3d {
+
+typedef ObjectBase[] ObjectArray;
+
+%[
+ A Pack object functions as a container for O3D objects. The Pack
+ is used to control the lifetime scope of a collection of objects in bulk. The
+ Pack object achieves this by simply storing a set of references to its
+ contained objects, which ensures that the ref-counts for those objects never
+ reach zero while the pack is alive.
+ \sa o3d.Pack.removeObject
+ \sa o3d.Pack.destroy
+%]
+[nocpp, include="core/cross/pack.h"] class Pack : NamedObject {
+
+ %[
+ Removes all internal references to the Pack from the client.
+ The pack, and all objects contained in it are permitted to be destroyed
+ after the pack's destruction. Objects will only be destroyed after all
+ references to them have been removed.
+
+ NOTE: Calling pack.destroy does NOT free your resources. It justs releases
+ the pack's reference to those resources. An example should hopefully make
+ it clearer.
+
+ pack.destroy() is effectively almost the same as this.
+
+ \code
+ var objectsInPack = pack.getObjectsByClassName('o3d.ObjectBase');
+ for (var ii = 0; ii < objectsInPack.length; ++ii) {
+ pack.removeObject(objectsInPack[ii]);
+ }
+ \endcode
+
+ The only difference is that after all the objects are removed the pack
+ itself will be released from the client. See documenation on
+ pack.removeObject for why this is important.
+
+ It's important to note that many objects are only referenced by the pack.
+ Textures, Effects, Materials, for example. That means the moment you call
+ pack.destroy() those objects will be freed. If the client then tries to
+ render and some objects are missing you'll immediately get an error.
+
+ \return True if the pack was successfully deleted.
+ %]
+ void Destroy();
+
+ %[
+ Removes a pack's reference to an object. Any object created from
+ pack.create___ function can be removed. This releases the pack's reference
+ to that object so if nothing else is referencing that object it will be
+ deleted.
+
+ NOTE: Calling pack.removeObject does NOT automatically free your resource.
+ It just releases the pack's reference to that resource. An example should
+ hopefully make it clearer.
+
+ Suppose you make a transform like this:
+
+ \code
+ var myTransform = pack.createObject('Transform');
+ myTransform.parent = g_client.root;
+ pack.removeObject(myTransform);
+ \endcode
+
+ In the code above, myTransform is referenced twice. Once by the pack, and
+ again by g_client.root So in this case, calling pack.removeObject()
+ only releases the pack's reference leaving the reference by g_client.root.
+
+ \code
+ myTransform.parent = null;
+ \endcode
+
+ Now the last reference has been removed and myTransform will be freed.
+
+ \param object Object to remove.
+ \return True if the object was successfully removed. False if the object
+ is not part of this pack.
+
+ \sa o3d.Pack.destroy
+ %]
+ bool RemoveObject(ObjectBase object);
+
+ %[
+ Creates an Object by Class name.
+
+ Note: You may omit the 'o3d.'.
+
+ \param type_name name of Class to create. Valid type names are:
+ \li o3d.Canvas
+ \li o3d.CanvasLinearGradient
+ \li o3d.CanvasPaint
+ \li o3d.ClearBuffer
+ \li o3d.Counter
+ \li o3d.Curve
+ \li o3d.DrawContext
+ \li o3d.DrawElement
+ \li o3d.DrawList
+ \li o3d.DrawPass
+ \li o3d.Effect
+ \li o3d.FunctionEval
+ \li o3d.IndexBuffer
+ \li o3d.Material
+ \li o3d.ParamArray
+ \li o3d.ParamObject
+ \li o3d.Primitive
+ \li o3d.RenderFrameCounter
+ \li o3d.RenderNode
+ \li o3d.RenderSurfaceSet
+ \li o3d.Sampler
+ \li o3d.SecondCounter
+ \li o3d.Shape
+ \li o3d.Skin
+ \li o3d.SkinEval
+ \li o3d.SourceBuffer
+ \li o3d.State
+ \li o3d.StateSet
+ \li o3d.StreamBank
+ \li o3d.Texture2D
+ \li o3d.TextureCUBE
+ \li o3d.TickCounter
+ \li o3d.Transform
+ \li o3d.TreeTraversal
+ \li o3d.VertexBuffer
+ \li o3d.Viewport
+ \li o3d.Matrix4AxisRotation
+ \li o3d.Matrix4Composition
+ \li o3d.Matrix4Scale
+ \li o3d.Matrix4Translation
+ \li o3d.ParamOp2FloatsToFloat2
+ \li o3d.ParamOp3FloatsToFloat3
+ \li o3d.ParamOp4FloatsToFloat4
+ \li o3d.ParamOp16FloatsToMatrix4
+ \li o3d.TRSToMatrix4
+ \return The created object.
+ %]
+ ObjectBase? CreateObject(String type_name);
+
+ %[
+ Creates a new Texture2D object of the specified size and format and
+ reserves the necessary resources for it.
+
+ Note: If enable_render_surfaces is true, then the dimensions must be a
+ power of two.
+
+ \param width The width of the texture area in texels (max = 2048)
+ \param height The height of the texture area in texels (max = 2048)
+ \param format The memory format of each texel
+ \param levels The number of mipmap levels. Use zero to create the compelete
+ mipmap chain.
+ \param enable_render_surfaces: If true, the texture object will expose
+ RenderSurface objects through GetRenderSurface(...).
+ \return The Texture2D object.
+
+ %]
+ Texture2D? CreateTexture2D(int width,
+ int height,
+ Texture::Format format,
+ int levels,
+ bool enable_render_surfaces);
+
+ %[
+ Creates a new TextureCUBE object of the specified size and format and
+ reserves the necessary resources for it.
+ Note: If enable_render_surfaces is true, then the dimensions must be a
+ power of two.
+
+ \param edge_length The edge of the texture area in texels (max = 2048)
+ \param format The memory format of each texel
+ \param levels The number of mipmap levels. Use zero to create the compelete
+ mipmap chain.
+ \param enable_render_surfaces If true, the texture object will expose
+ RenderSurface objects through GetRenderSurface(...).
+ \return The TextureCUBE object.
+ %]
+ TextureCUBE? CreateTextureCUBE(int edge_length,
+ Texture::Format format,
+ int levels,
+ bool enable_render_surfaces);
+
+ %[
+ Creates a new RenderDepthStencilSurface object of a format suitable for use
+ as a depth-stencil render target.
+ Note: The dimensions of the RenderDepthStencilSurface must be a power of
+ two.
+
+ \param width The width of the RenderSurface in pixels
+ \param height The height of the RenderSurface in pixels
+ \return The RenderSurface object.
+ %]
+ RenderDepthStencilSurface? CreateDepthStencilSurface(int width, int height);
+
+ %[
+ Search the pack for all objects of a certain class with a certain name.
+
+ Note that modifications to this array [e.g. push()] will not affect
+ the underlying Pack, while modifications to the array's members
+ <strong>will</strong> affect them.
+
+ \param name Name to look for
+ \param class_type_name the Class of the object. It is okay to pass base
+ types for example "o3d.RenderNode" will return ClearBuffers,
+ DrawPasses, etc...
+ \returns Array of Objects.
+ %]
+ [const] ObjectArray GetObjects(String name, String class_type_name);
+
+ %[
+ Search the pack for all objects of a certain class
+
+ Note that modifications to this array [e.g. push()] will not affect
+ the underlying Pack, while modifications to the array's members
+ <strong>will</strong> affect them.
+
+ \param class_type_name the Class of the object. It is okay to pass base
+ types for example "o3d.RenderNode" will return ClearBuffers,
+ DrawPasses, etc...
+ \returns Array of Objects.
+ %]
+ [const] ObjectArray GetObjectsByClassName(String class_type_name);
+
+ %[
+ All the objects managed by this pack.
+
+ Each access to this field gets the entire list so it is best to get it
+ just once. For example:
+ \code
+ var objects = pack.objects;
+ for (var i = 0; i < objects.length; i++) {
+ var object = objects[i];
+ }
+ \endcode
+
+ Note that modifications to this array [e.g. push()] will not affect
+ the underlying Pack, while modifications to the array's members
+ <strong>will</strong> affect them.
+ %]
+ [userglue_getter, getter] ObjectBaseArray objects_;
+
+ %[
+ Creates a FileRequest to be used to asynchronously load a Texture.
+ \param type Must be "TEXTURE"
+ \returns a FileRequest
+ %]
+ [noccp, userglue] FileRequest? CreateFileRequest(String type);
+ [verbatim=cpp_glue, include="core/cross/file_request.h"] %{
+ o3d::FileRequest *userglue_method_CreateFileRequest(
+ o3d::Pack *pack, const o3d::String &type) {
+ return pack->CreateFileRequest(type);
+ }
+ o3d::ObjectBaseArray userglue_getter_objects_(
+ o3d::Pack* self) {
+ return self->GetByClass<o3d::ObjectBase>();
+ }
+ %}
+
+ %[
+ Creates an ArchiveRequest so we can stream in assets from an archive
+ \returns an ArchiveRequest
+ %]
+ [noccp, userglue] ArchiveRequest CreateArchiveRequest();
+ [verbatim=cpp_glue, include="import/cross/archive_request.h"] %{
+ o3d::ArchiveRequest *userglue_method_CreateArchiveRequest(
+ o3d::Pack *pack) {
+ return pack->CreateArchiveRequest();
+ }
+ %}
+
+ %[
+ Creates a Texture given a RawData object
+ \returns the Texture
+ %]
+ Texture? CreateTextureFromRawData(RawData raw_data,
+ bool generate_mips);
+}; // Pack
+
+} // namespace o3d
diff --git a/o3d/plugin/idl/param.idl b/o3d/plugin/idl/param.idl
new file mode 100644
index 0000000..f0a4705
--- /dev/null
+++ b/o3d/plugin/idl/param.idl
@@ -0,0 +1,326 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace o3d {
+
+typedef Param[] ParamVector;
+
+%[
+ Params store data defined name/value pairs on ParamObjects.
+ Each Param has a name, a type and a value that can be set and queried.
+ One of their uses is to hold "uniform constants" used to parameterize shaders.
+ Params can be connected in a source/destination fashion such that a target
+ Param gets its value from the source param.
+%]
+
+[nocpp, include="core/cross/param.h"] class Param : NamedObjectBase {
+
+ [verbatim=cpp_header] %{
+ static int data_length_[NUM_PARAM_TYPES]; // Data size requirements per type
+
+ void *data_; // Storage for Param value
+ const void *handle_; // Handle to an implementation specific object holding
+ // corresponding to the Param
+ %}
+
+ %[
+ If true, this param will make sure its input param is up to date when
+ using it as a source. Default = true.
+
+ This is for helping with Param cycles.
+
+ If paramA gets its value from paramB and paramB gets its value from
+ paramA:\n
+ If you go paramA.value, paramB will evaluate then copy to paramA.\n
+ If you go paramB.value, paramA will evaluate then copy to paramB.\n
+ If you set paramB.updateInput = false, then:\n
+ If you go paramA.value, paramB will evaluate then copy to paramA.\n
+ If you go paramB.value, paramB just copy paramA. paramA will NOT evaluate
+ when paramB asks for its value.
+ %]
+ [getter, setter, property=rw] bool update_input;
+
+ %[
+ Directly binds two Param elements such that this
+ parameter gets its value from the source parameter. The
+ source must be compatible with this parameter.
+
+ \param source_param The parameter that the value originates from. Passing in
+ null will unbind any parameter currently bound.
+ \return True if the bind succeeded.
+ %]
+ bool Bind(Param? source_param);
+
+ %[
+ Breaks any input connection coming into the Param.
+ %]
+ void UnbindInput();
+
+ %[
+ Breaks a specific param-bind output connection on this param.
+
+ \param destination_param param to unbind.
+ \return True if the param was a destination param and was unbound.
+ %]
+ void UnbindOutput(Param destination_param);
+
+ %[
+ Breaks all param-bind output connections on this param.
+ %]
+ void UnbindOutputs();
+
+ %[
+ If true the param is read only. Its value can not be set nor can it be used
+ as the destination in a ParamBind
+ %]
+ [getter, property=r] bool read_only_;
+
+ %[
+ The input connection for this param.
+ %]
+ [getter, property_r] Param? input_connection;
+
+ %[
+ The output connections for this param.
+ %]
+ [getter, property=r] ParamVector output_connections;
+};
+
+%[
+ A Param class which stores a single float.
+%]
+[nocpp, include="core/cross/param.h"] class ParamFloat : Param {
+ %[
+ The float stored by the Param.
+ %]
+ [getter, setter, property=rw] float value_;
+};
+
+%[
+ A Param class which stores a Float2.
+%]
+[nocpp, include="core/cross/param.h"] class ParamFloat2 : Param {
+ %[
+ Sets the Float2 stored by the Param by an array of 2 numbers.
+ %]
+ [setter, getter, property=rw, nocpp] Float2 value;
+
+ %[
+ Sets the value of ParamFloat2 by 2 numbers.
+ \param v0 first value.
+ \param v1 second value.
+ %]
+ [userglue] void set(float v0, float v1);
+
+ [verbatim=cpp_glue] %{
+ void userglue_method_set(o3d::ParamFloat2* self,
+ float v0,
+ float v1) {
+ self->set_value(o3d::Float2(v0, v1));
+ }
+ %}
+};
+
+%[
+ A Param class which stores a Float3.
+%]
+[nocpp, include="core/cross/param.h"] class ParamFloat3 : Param {
+ %[
+ Sets the Float3 stored by the Param by an array of 3 numbers.
+ %]
+ [setter, getter, property=rw, nocpp] Float3 value;
+
+ %[
+ Sets the entries of the value of ParamFloat3 to the 3 given numbers.
+ \param v0 first value.
+ \param v1 second value.
+ \param v2 third value.
+ %]
+ [userglue] void set(float v0, float v1, float v2);
+
+ [verbatim=cpp_glue] %{
+ void userglue_method_set(o3d::ParamFloat3* self,
+ float v0,
+ float v1,
+ float v2) {
+ self->set_value(o3d::Float3(v0, v1, v2));
+ }
+ %}
+};
+
+%[
+ A Param class which stores a Float4.
+%]
+[nocpp, include="core/cross/param.h"] class ParamFloat4 : Param {
+ %[
+ Sets the Float4 stored by the Param by an array of 4 numbers.
+ %]
+ [setter, getter, property=rw, nocpp] Float4 value;
+
+ %[
+ Sets the value of ParamFloat4 by 4 numbers.
+ \param v0 first value.
+ \param v1 second value.
+ \param v2 third value.
+ \param v3 fourth value.
+ %]
+ [userglue] void set(float v0, float v1, float v2, float v3);
+
+ [verbatim=cpp_glue] %{
+ void userglue_method_set(o3d::ParamFloat4* self,
+ float v0,
+ float v1,
+ float v2,
+ float v3) {
+ self->set_value(o3d::Float4(v0, v1, v2, v3));
+ }
+ %}
+};
+
+%[
+ A Param class which stores a 4-by-4 matrix.
+%]
+[nocpp, include="core/cross/param.h"] class ParamMatrix4 : Param {
+ %[
+ Sets the 4-by-4 matrix stored by the Param by a length-4 array of arrays of
+ 4 numbers.
+ %]
+ [getter, setter, property=rw, nocpp] Vectormath::Aos::Matrix4 value;
+};
+
+%[
+ A Param class which stores an integer.
+%]
+[nocpp, include="core/cross/param.h"] class ParamInteger : Param {
+ %[
+ The integer stored by the Param.
+ %]
+ [getter, setter, property=rw] int value_;
+};
+
+%[
+ A Param class which stores a boolean.
+%]
+[nocpp, include="core/cross/param.h"] class ParamBoolean : Param {
+ %[
+ The boolean stored by the Param.
+ %]
+ [getter, setter, property=rw] bool value_;
+};
+
+%[
+ A Param which stores a string.
+%]
+[nocpp, include="core/cross/param.h"] class ParamString : Param {
+ %[
+ The string stored by the Param.
+ %]
+ [getter, setter, property=rw] String value_;
+};
+
+%[
+ A Param which stores a Texture.
+%]
+[nocpp, include="core/cross/sampler.h"] class ParamSampler : Param {
+ %[
+ The Sampler stored by the Param.
+ %]
+ [getter, setter, property=rw] Sampler? value_;
+};
+
+[nocpp, include="core/cross/param.h"] class ParamTexture : Param {
+ %[
+ The Texture stored by the Param.
+ %]
+ [getter, setter, property=rw] Texture? value_;
+};
+
+%[
+ A Param which stores a Material.
+%]
+[nocpp, include="core/cross/param.h"] class ParamMaterial : Param {
+ %[
+ The Material stored by the Param.
+ %]
+ [getter, setter, property=rw] Material? value_;
+};
+
+%[
+ A Param which stores a State.
+%]
+[nocpp, include="core/cross/param.h"] class ParamState : Param {
+ %[
+ The State stored by the Param.
+ %]
+ [getter, setter, property=rw] State? value_;
+};
+
+%[
+ A Param which stores a Effect.
+%]
+[nocpp, include="core/cross/param.h"] class ParamEffect : Param {
+ %[
+ The Effect stored by the Param.
+ %]
+ [getter, setter, property=rw] Effect? value_;
+};
+
+%[
+ A Param which stores a Transform.
+%]
+[nocpp, include="core/cross/param.h"] class ParamTransform : Param {
+ %[
+ The Transform stored by the Param.
+ %]
+ [getter, setter, property=rw] Transform? value_;
+};
+
+%[
+ A Param which stores a DrawList.
+%]
+[nocpp, include="core/cross/param.h"] class ParamDrawList : Param {
+ %[
+ The DrawList stored by the Param.
+ %]
+ [getter, setter, property=rw] DrawList? value_;
+};
+
+%[
+ A Param which stores a DrawContext.
+%]
+[nocpp, include="core/cross/param.h"] class ParamDrawContext : Param {
+ %[
+ The DrawContext stored by the Param.
+ %]
+ [getter, setter, property=rw] DrawContext? value_;
+};
+
+} // namespace o3d
diff --git a/o3d/plugin/idl/param_array.idl b/o3d/plugin/idl/param_array.idl
new file mode 100644
index 0000000..63156d4
--- /dev/null
+++ b/o3d/plugin/idl/param_array.idl
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace o3d {
+
+%[
+ A ParamArray is an object that holds an array of Params.
+%]
+
+[nocpp, include="core/cross/param_array.h"] class ParamArray
+ : NamedObject {
+
+ %[
+ Creates a Param of the given type at the index requested. If a Param
+ already exists at that index the new param will be replace it. If the
+ index is past the end of the current array params of the requested type
+ will be created to fill out the array to the requested index.
+
+ \param index index at which to create new param.
+ \param param_type_name The type of Param to create. For a list of valid
+ types see ParamObject.createParam
+ \return Param created at index or null if failure.
+
+ %]
+ [userglue] Param? CreateParam(unsigned int index, String param_type_name);
+
+ %[
+ Gets a Param by index.
+
+ \param index Index of Param to get.
+ \return The Param at index, or null if out of range.
+ %]
+ [userglue, const] Param? GetParam(unsigned int index);
+
+ %[
+ Removes a range of params.
+
+ \param start_index Index of first param to remove.
+ \param num_to_remove The number of params to remove starting at start_index.
+ %]
+ void RemoveParams(unsigned int start_index, unsigned int num_to_remove);
+
+ %[
+ Resizes the array.
+
+ \param num_params The number of params to make the array.
+ \param param_type_name The type of Param to create if resizing
+ requires params to be created. For a list of valid types see
+ ParamObject.createParam
+ %]
+ [userglue] void Resize(unsigned int num_params, String param_type_name);
+
+ %[
+ Gets all the param on this param object.
+
+ Each access to this field gets the entire list, so it is best to get it
+ just once. For example:
+ \code
+ var params = ParamArray.params;
+ for (var i = 0; i < params.length; i++) {
+ var param = params[i];
+ }
+ \endcode
+
+ Note that modifications to this array [e.g. push()] will not affect
+ the underlying ParamObject, while modifications to the array's members
+ <strong>will</strong> affect them.
+ %]
+ [userglue_getter, getter] ParamVector params_;
+
+ %[
+ Returns the number of parameters in this ParamArray.
+ %]
+ [userglue_getter, getter] unsigned int length;
+
+ [verbatim=cpp_glue] %{
+ o3d::ParamVector userglue_getter_params_(
+ o3d::ParamArray *self) {
+ const o3d::ParamArray::ParamRefVector& src_params = self->params();
+ o3d::ParamVector params(src_params.size());
+ for (unsigned ii = 0; ii < src_params.size(); ++ii) {
+ params[ii] = src_params[ii];
+ }
+ return params;
+ }
+ unsigned int userglue_getter_length(
+ o3d::ParamArray *self) {
+ return self->size();
+ }
+ o3d::Param* userglue_method_CreateParam(
+ o3d:: ParamArray *self,
+ unsigned int index,
+ const o3d::String& param_type_name) {
+ return self->CreateParamByClassName(index, param_type_name);
+ }
+ void userglue_method_Resize(
+ o3d:: ParamArray *self,
+ unsigned int num_params,
+ const o3d::String& param_type_name) {
+ self->ResizeByClassName(num_params, param_type_name);
+ }
+ o3d::Param* userglue_method_GetParam(
+ o3d:: ParamArray *self,
+ unsigned int index) {
+ return self->GetUntypedParam(index);
+ }
+ %}
+
+}; // ParamArray
+
+%[
+ A Param which stores a ParamArray.
+%]
+[nocpp, include="core/cross/param.h"] class ParamParamArray : Param {
+ %[
+ The ParamArray stored by the Param.
+ %]
+ [getter, setter] ParamArray value_;
+};
+
+} // namespace o3d
diff --git a/o3d/plugin/idl/param_object.idl b/o3d/plugin/idl/param_object.idl
new file mode 100644
index 0000000..cac6efd
--- /dev/null
+++ b/o3d/plugin/idl/param_object.idl
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace o3d {
+
+%[
+ A ParamObject is the base class for all objects that can have Params.
+ Defines methods to add and remove params, search for params, etc.
+%]
+[nocpp, include="core/cross/param_object.h"]
+class ParamObject : NamedObject {
+ %[
+ Creates a Param with the given name and type on the ParamObject.
+ Will fail if a param with the same name already exists.
+
+ \param param_name The name of the Param to be created.
+ \param param_type_name The type of Param to create. Valid types are
+ \li 'o3d.ParamBoolean',
+ \li 'o3d.ParamBoundingBox',
+ \li 'o3d.ParamDrawContext',
+ \li 'o3d.ParamDrawList',
+ \li 'o3d.ParamEffect',
+ \li 'o3d.ParamFloat',
+ \li 'o3d.ParamFloat2',
+ \li 'o3d.ParamFloat3',
+ \li 'o3d.ParamFloat4',
+ \li 'o3d.ParamInteger',
+ \li 'o3d.ParamMaterial',
+ \li 'o3d.ParamMatrix4',
+ \li 'o3d.ParamParamArray',
+ \li 'o3d.ParamRenderSurface',
+ \li 'o3d.ParamRenderDepthStencilSurface',
+ \li 'o3d.ParamSampler',
+ \li 'o3d.ParamSkin',
+ \li 'o3d.ParamSteamBank',
+ \li 'o3d.ParamState',
+ \li 'o3d.ParamString',
+ \li 'o3d.ParamTexture',
+ \li 'o3d.ParamTransform',
+ \li 'o3d.ProjectionParamMatrix4',
+ \li 'o3d.ProjectionInverseParamMatrix4',
+ \li 'o3d.ProjectionTransposeParamMatrix4',
+ \li 'o3d.ProjectionInverseTransposeParamMatrix4',
+ \li 'o3d.ViewParamMatrix4',
+ \li 'o3d.ViewInverseParamMatrix4',
+ \li 'o3d.ViewTransposeParamMatrix4',
+ \li 'o3d.ViewInverseTransposeParamMatrix4',
+ \li 'o3d.ViewProjectionParamMatrix4',
+ \li 'o3d.ViewProjectionInverseParamMatrix4',
+ \li 'o3d.ViewProjectionTransposeParamMatrix4',
+ \li 'o3d.ViewProjectionInverseTransposeParamMatrix4',
+ \li 'o3d.WorldParamMatrix4',
+ \li 'o3d.WorldInverseParamMatrix4',
+ \li 'o3d.WorldTransposeParamMatrix4',
+ \li 'o3d.WorldInverseTransposeParamMatrix4',
+ \li 'o3d.WorldViewParamMatrix4',
+ \li 'o3d.WorldViewInverseParamMatrix4',
+ \li 'o3d.WorldViewTransposeParamMatrix4',
+ \li 'o3d.WorldViewInverseTransposeParamMatrix4',
+ \li 'o3d.WorldViewProjectionParamMatrix4',
+ \li 'o3d.WorldViewProjectionInverseParamMatrix4',
+ \li 'o3d.WorldViewProjectionTransposeParamMatrix4',
+ \li 'o3d.WorldViewProjectionInverseTransposeParamMatrix4'
+ \return The newly created Param or null on failure.
+ %]
+ [userglue] Param? CreateParam(String param_name, String param_type_name);
+
+ %[
+ Searches by name for a Param defined in the object.
+
+ \param param_name Name to search for.
+ \return The Param with the given name, or null otherwise.
+ %]
+ [userglue, const] Param? GetParam(String param_name);
+
+ %[
+ Removes a Param from a ParamObject.
+
+ This function will fail if the param does not exist on this ParamObject
+ or if the param is unremovable.
+
+ \param param param to remove.
+ \return True if the param was removed.
+ %]
+ bool RemoveParam(Param param);
+
+ %[
+ Gets all the param on this param object.
+
+ Each access to this field gets the entire list, so it is best to get it
+ just once. For example:
+ \code
+ var params = paramObject.params;
+ for (var i = 0; i < params.length; i++) {
+ var param = params[i];
+ }
+ \endcode
+
+ Note that modifications to this array [e.g. push()] will not affect
+ the underlying ParamObject, while modifications to the array's members
+ <strong>will</strong> affect them.
+ %]
+ [userglue_getter, getter, property=r] ParamVector params_;
+
+ %[
+ Copies all the params from a the given source_param_object to this param
+ object. Does not replace any currently existing params with the same name.
+
+ \param source_param_object param object to copy params from.
+ %]
+ void CopyParams(ParamObject source_param_object);
+
+ [verbatim=cpp_glue] %{
+ o3d::ParamVector userglue_getter_params_(
+ o3d::ParamObject *self) {
+ return self->GetParams();
+ }
+ o3d::Param* userglue_method_CreateParam(
+ o3d:: ParamObject *self,
+ const o3d::String& param_name,
+ const o3d::String& param_type_name) {
+ return self->CreateParamByClassName(param_name, param_type_name);
+ }
+
+ o3d::Param* userglue_method_GetParam(
+ o3d:: ParamObject *self,
+ const o3d::String& param_name) {
+ return self->GetUntypedParam(param_name);
+ }
+ %}
+};
+
+} // namespace o3d
diff --git a/o3d/plugin/idl/param_operation.idl b/o3d/plugin/idl/param_operation.idl
new file mode 100644
index 0000000..9935f93
--- /dev/null
+++ b/o3d/plugin/idl/param_operation.idl
@@ -0,0 +1,265 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace o3d {
+
+%[
+ A Param operation that takes 2 floats to produce a Float2.
+%]
+[nocpp, include="core/cross/param_operation.h"]
+class ParamOp2FloatsToFloat2 : ParamObject {
+ %[
+ The first value for the Float2.
+ %]
+ [getter, setter] float input_0;
+
+ %[
+ The second value for the Float2.
+ %]
+ [getter, setter] float input_1;
+
+ %[
+ The Float2 that results from the inputs.
+ %]
+ [getter] Float2 output;
+};
+
+%[
+ A Param operation that takes 3 floats to produce a Float3.
+%]
+[nocpp, include="core/cross/param_operation.h"]
+class ParamOp3FloatsToFloat3 : ParamObject {
+ %[
+ The first value for the Float3.
+ %]
+ [getter, setter] float input_0;
+
+ %[
+ The second value for the Float3.
+ %]
+ [getter, setter] float input_1;
+
+ %[
+ The third value for the Float3.
+ %]
+ [getter, setter] float input_2;
+
+ %[
+ The Float3 that results from the inputs.
+ %]
+ [getter] Float3 output;
+};
+
+%[
+ A Param operation that takes 4 floats to produce a Float4.
+%]
+[nocpp, include="core/cross/param_operation.h"]
+class ParamOp4FloatsToFloat4 : ParamObject {
+ %[
+ The first value for the Float4.
+ %]
+ [getter, setter] float input_0;
+
+ %[
+ The second value for the Float4.
+ %]
+ [getter, setter] float input_1;
+
+ %[
+ The third value for the Float4.
+ %]
+ [getter, setter] float input_2;
+
+ %[
+ The fourth value for the Float4.
+ %]
+ [getter, setter] float input_3;
+
+ %[
+ The Float4 that results from the inputs.
+ %]
+ [getter] Float4 output;
+};
+
+%[
+ A Param operation that takes 16 floats to produce a Matrix4.
+%]
+[nocpp, include="core/cross/param_operation.h"]
+class ParamOp16FloatsToMatrix4 : ParamObject {
+ %[
+ The first value for the Float4.
+ %]
+ [getter, setter] float input_0;
+
+ %[
+ The second value for the Float4.
+ %]
+ [getter, setter] float input_1;
+
+ %[
+ The third value for the Float4.
+ %]
+ [getter, setter] float input_2;
+
+ %[
+ The fourth value for the Float4.
+ %]
+ [getter, setter] float input_3;
+
+ %[
+ The fifth value for the Float4.
+ %]
+ [getter, setter] float input_4;
+
+ %[
+ The sixth value for the Float4.
+ %]
+ [getter, setter] float input_5;
+
+ %[
+ The seventh value for the Float4.
+ %]
+ [getter, setter] float input_6;
+
+ %[
+ The eighth value for the Float4.
+ %]
+ [getter, setter] float input_7;
+
+ %[
+ The ninth value for the Float4.
+ %]
+ [getter, setter] float input_8;
+
+ %[
+ The tenth value for the Float4.
+ %]
+ [getter, setter] float input_9;
+
+ %[
+ The eleventh value for the Float4.
+ %]
+ [getter, setter] float input_10;
+
+ %[
+ The twelfth value for the Float4.
+ %]
+ [getter, setter] float input_11;
+
+ %[
+ The thirteenth value for the Float4.
+ %]
+ [getter, setter] float input_12;
+
+ %[
+ The fourteenth value for the Float4.
+ %]
+ [getter, setter] float input_13;
+
+ %[
+ The fifteenth value for the Float4.
+ %]
+ [getter, setter] float input_14;
+
+ %[
+ The sixteenth value for the Float4.
+ %]
+ [getter, setter] float input_15;
+
+ %[
+ The Matrix4 that results from the inputs.
+ %]
+ [getter] Vectormath::Aos::Matrix4 output;
+};
+
+%[
+ A Param operation that takes 9 floats to produce a 4-by-4 matrix.
+ The 9 floats encode a translation vector, angles of rotation around the x, y,
+ and z axes, and three scaling factors. The resulting transformation scales
+ first, then then rotates around the z-axis, then the y-axis, then the x-axis,
+ then translates.
+%]
+[nocpp, include="core/cross/param_operation.h"]
+class TRSToMatrix4 : ParamObject {
+ %[
+ The x translation for the Matrix4.
+ %]
+ [getter, setter] float translate_x;
+
+ %[
+ The y translation for the Matrix4.
+ %]
+ [getter, setter] float translate_y;
+
+ %[
+ The z translation for the Matrix4.
+ %]
+ [getter, setter] float translate_z;
+
+ %[
+ The x rotation for the Matrix4.
+ %]
+ [getter, setter] float rotate_x;
+
+ %[
+ The y rotation for the Matrix4.
+ %]
+ [getter, setter] float rotate_y;
+
+ %[
+ The z rotation for the Matrix4.
+ %]
+ [getter, setter] float rotate_z;
+
+ %[
+ The x scale for the Matrix4.
+ %]
+ [getter, setter] float scale_x;
+
+ %[
+ The y scale for the Matrix4.
+ %]
+ [getter, setter] float scale_y;
+
+ %[
+ The z scale for the Matrix4.
+ %]
+ [getter, setter] float scale_z;
+
+ %[
+ The Matrix4 that results from the inputs.
+ %]
+ [getter] Vectormath::Aos::Matrix4 output;
+};
+
+} // namespace o3d
+
+
diff --git a/o3d/plugin/idl/plugin.idl b/o3d/plugin/idl/plugin.idl
new file mode 100644
index 0000000..26a00b9
--- /dev/null
+++ b/o3d/plugin/idl/plugin.idl
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// This file contains the public interface specification for the plugin.
+
+[verbatim=js_header] %{
+ /*!
+ * \mainpage API Reference
+ *
+ * O3D is a plug-in for your browser. In order to make o3d produce
+ * the graphics you see in the demos, you'll need to access the plug-in and its
+ * components from within JavaScript. You can do so through a member variable
+ * on the plug-in called \a client, representing the instance of o3d within
+ * the plug-in.
+ *
+ * Here is how to access the client itself:
+ * \code
+ * g_client = document.o3d.client;
+ * \endcode
+ *
+ * where <code>document.o3d</code>
+ * represents the plug-in (rather than the Client instance within the plug-in).
+ * Not much else can be done with the plug-in, so you will want to access
+ * the \a client as shown above.
+ *
+ * Now that you know how to access the instance of o3d from your
+ * JavaScript, check out the rest of the API for more information on how to
+ * make o3d do what you want.
+ */
+%}
diff --git a/o3d/plugin/idl/primitive.idl b/o3d/plugin/idl/primitive.idl
new file mode 100644
index 0000000..4e0547c
--- /dev/null
+++ b/o3d/plugin/idl/primitive.idl
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace o3d {
+
+%[
+ A Primitive is a type of Element that is made from a list of points,
+ lines or triangles that use a single material.
+%]
+[nocpp, include="core/cross/primitive.h"]
+class Primitive : Element {
+ %[
+ \var PrimitiveType,
+ \li POINTLIST,
+ \li LINELIST,
+ \li LINESTRIP,
+ \li TRIANGLELIST,
+ \li TRIANGLESTRIP,
+ \li TRIANGLEFAN
+
+ Type of geometric primitives used by the Primitive.
+ %]
+ enum PrimitiveType {
+ POINTLIST = 1,
+ LINELIST = 2,
+ LINESTRIP = 3,
+ TRIANGLELIST = 4,
+ TRIANGLESTRIP = 5,
+ TRIANGLEFAN = 6
+ };
+
+ %[
+ The type of primitive the primitive is (i.e., Primitive::POINTLIST,
+ Primitive::LINELIST, Primitive::TRIANGLELIST, etc.)
+ %]
+ [getter, setter] Primitive::PrimitiveType primitive_type;
+
+ %[
+ The number of vertices the primitive has.
+ %]
+ [getter, setter] unsigned int number_vertices;
+
+ %[
+ The number of rendering primitives (i.e., triangles, points, lines) the
+ primitive has.
+ %]
+ [getter, setter] unsigned int number_primitives;
+
+ %[
+ The index of the first vertex to render.
+ %]
+ [getter, setter] unsigned int start_index;
+
+ %[
+ The stream bank this primitive uses for vertices.
+ %]
+ [getter, setter] StreamBank? stream_bank;
+
+ %[
+ The index buffer for the primitive. If null the primitive is non-indexed.
+ %]
+ [getter, setter] IndexBuffer? index_buffer;
+}; // Primitive
+
+} // namespace o3d
diff --git a/o3d/plugin/idl/raw_data.idl b/o3d/plugin/idl/raw_data.idl
new file mode 100644
index 0000000..8089d71
--- /dev/null
+++ b/o3d/plugin/idl/raw_data.idl
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace o3d {
+
+%[
+ A RawData object contains raw binary data which could contain
+ image, audio, text, or other information.
+
+ \code
+ var request = g_pack.createArchiveRequest();
+
+ request.onfileavailable = function() {
+ var texture = g_pack.createTextureFromRawData(request.data, true);
+ ...
+ };
+
+ request.send();
+
+ \endcode
+%]
+
+[nocpp, include="import/cross/raw_data.h"] class RawData : ParamObject {
+ %[
+ Returns the raw data as a string. The data must be a valid utf-8 string
+ and the uri must end in .json, .txt, .xml, .ini or .csv
+ %]
+ [getter, userglue_getter, StringValue] String string_value;
+
+ %[
+ The uri of the RawData.
+ %]
+ [getter] String uri;
+
+ %[
+ The length in bytes of the RawData.
+ %]
+ [getter=GetLength] size_t length;
+
+ %[
+ Discards all the resources associated with this data object.
+ %]
+ void Discard();
+
+ %[
+ Flushes the memory resources associated with this data object,
+ but keeps a cache in case the data object is used later.
+ %]
+ void Flush();
+
+ [verbatim=cpp_glue, include="import/cross/raw_data.h"] %{
+ o3d::String userglue_getter_string_value(
+ o3d::RawData* self) {
+ return self->StringValue();
+ }
+ %}
+
+};
+
+} // namespace o3d
diff --git a/o3d/plugin/idl/ray_intersection_info.idl b/o3d/plugin/idl/ray_intersection_info.idl
new file mode 100644
index 0000000..176a46e
--- /dev/null
+++ b/o3d/plugin/idl/ray_intersection_info.idl
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace o3d {
+
+%[
+ A RayIntersectionInfo is used to return the results of ray intersection tests.
+%]
+
+[binding_model=by_value, nocpp, include="core/cross/ray_intersection_info.h"]
+class RayIntersectionInfo {
+ %[
+ True if this ray intersection info is valid. For example if you call
+ element.intersectRay on an element that has no vertex buffers the result
+ will be invalid.
+ %]
+ [getter] bool valid_;
+
+ %[
+ True if this ray intersection intersected something.
+ %]
+ [getter] bool intersected_;
+
+ %[
+ The position the ray intersected something.
+ %]
+ [getter] Vectormath::Aos::Point3 position;
+
+ %[
+ The index of the primitive that was intersected.
+ %]
+ [getter] int primitive_index_;
+
+}; // RayIntersectionInfo
+
+} // namespace o3d
diff --git a/o3d/plugin/idl/render_event.idl b/o3d/plugin/idl/render_event.idl
new file mode 100644
index 0000000..4719596
--- /dev/null
+++ b/o3d/plugin/idl/render_event.idl
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// This file defines the public interface for the RenderEvent class.
+
+namespace o3d {
+
+%[
+ This class is used to pass infomation to a registered onrender callback.
+%]
+[binding_model=by_value, include="core/cross/render_event.h",
+ nocpp,glue_iface] class RenderEvent {
+ %[
+ The elapsed time in seconds since the last frame was rendered.
+ %]
+ [getter] float elapsed_time_;
+
+ %[
+ The time it took to render.
+ %]
+ [getter] float render_time_;
+
+ %[
+ The time it took to render and process tick callbacks, render callbacks,
+ counter callbacks.
+ %]
+ [getter] float active_time_;
+
+ %[
+ The number of transforms processed last frame.
+
+ This is the number of transforms the renderer considered for traversing.
+ A Transform may not be considered for traversing either because it is not in
+ one of the subtrees the TreeTraversals are setup to traverse or because it
+ one of its parents was culled or set to visible = false.
+ %]
+ [getter] int transforms_processed_;
+
+ %[
+ The number of transforms that were culled last frame directly.
+
+ Of the transforms processed, how many were culled.
+ %]
+ [getter] int transforms_culled_;
+
+ %[
+ The number of draw elements processed last frame.
+
+ This is the number of draw elements the renderer considered for rendering.
+ If a transform is not traversed either because it is not in one of the
+ subtrees the TreeTraversals are setup to traverse or because it is marked
+ as visible = false then any draw elements in that part of the transform
+ graph are not processed.
+ %]
+ [getter] int draw_elements_processed_;
+
+ %[
+ The number of draw elements that were culled last frame directly.
+ (vs culled hierarchically)
+ %]
+ [getter] int draw_elements_culled_;
+
+ %[
+ The number of draw elements rendered last frame. Note: a draw element can
+ be rendered more than once per frame based on how many transforms it is
+ under and how many DrawPasses use the DrawLists it is put on.
+ %]
+ [getter] int draw_elements_rendered_;
+
+ %[
+ The number of low-level primitives rendered last frame. This is the sum of
+ the number primitives (triangles, lines) submitted to the renderer.
+ %]
+ [getter] int primitives_rendered_;
+};
+
+} // namespace o3d
diff --git a/o3d/plugin/idl/render_node.idl b/o3d/plugin/idl/render_node.idl
new file mode 100644
index 0000000..65bf48e
--- /dev/null
+++ b/o3d/plugin/idl/render_node.idl
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace o3d {
+
+%[
+ RenderNode is the base of all RenderNodes in the render graph. All
+ RenderNodes have o3d.priority, o3d.active parameters.
+ RenderNodes are rendered in order of priority.
+%]
+[nocpp, include="core/cross/render_node.h"]
+ class RenderNode : ParamObject {
+
+ %[
+ Sets the priority of this render node. lower priorities are rendered first.
+ %]
+ [getter, setter] float priority_;
+
+ %[
+ Setting false skips this render node. Setting true processes this render
+ node. (ie, renders
+ whatever it's supposed to render)
+ %]
+ [getter, setter] bool active_;
+
+ %[
+ Sets the parent of the node by re-parenting the node under parent_node.
+ Setting parent_node to null removes the node and the entire subtree below
+ it from the render graph.
+ %]
+ [setter, userglue_setter] RenderNode? parent_;
+
+ %[
+ The immediate children of this RenderNode.
+
+ Each access to this field gets the entire list so it is best to get it
+ just once. For example:
+ \code
+ var children = renderNode.children;
+ for (var i = 0; i < children.length; i++) {
+ var child = children[i];
+ }
+ \endcode
+
+ Note that modifications to this array [e.g. push()] will not affect
+ the underlying RenderNode, while modifications to the array's members
+ <strong>will</strong> affect them.
+ %]
+ [userglue_getter, getter] RenderNodeArray children_;
+
+ %[
+ Returns this render node and all its descendants. Note that this render node
+ might not be in the render graph.
+
+ Note that modifications to this array [e.g. push()] will not affect
+ the underlying RenderNode, while modifications to the array's members
+ <strong>will</strong> affect them.
+
+ \return An array containing all render nodes of the subtree.
+ %]
+ [nocpp] RenderNodeArray GetRenderNodesInTree();
+
+ %[
+ Searches for render nodes that match the given name in the hierarchy under
+ and including this render node. Since there can be several render nodes with
+ a given name the results are returned in an array.
+
+ Note that modifications to this array [e.g. push()] will not affect
+ the underlying RenderNode, while modifications to the array's members
+ <strong>will</strong> affect them.
+
+ \param name Rendernode name to look for.
+ \return An array containing all nodes among this node and its decendants
+ that have the given name.
+ %]
+ [nocpp] RenderNodeArray GetRenderNodesByNameInTree(String name);
+
+ %[
+ Searches for render nodes that match the given class name in the hierarchy
+ under and including this render node.
+
+ Note that modifications to this array [e.g. push()] will not affect
+ the underlying RenderNode, while modifications to the array's members
+ <strong>will</strong> affect them.
+
+ \param class_name class name to look for.
+ \return An array containing all nodes among this node and its decendants
+ whose type is class_name.
+ %]
+ RenderNodeArray GetRenderNodesByClassNameInTree(String class_name);
+
+ [verbatim=cpp_glue] %{
+ void userglue_setter_parent_(
+ o3d::RenderNode* _this,
+ o3d::RenderNode* parent) {
+ _this->SetParent(parent);
+ }
+ o3d::RenderNodeArray userglue_getter_children_(
+ o3d::RenderNode *self) {
+ return self->GetChildren();
+ }
+ %}
+}; // RenderNode
+
+typedef RenderNode[] RenderNodeArray;
+
+} // namespace o3d
diff --git a/o3d/plugin/idl/render_surface.idl b/o3d/plugin/idl/render_surface.idl
new file mode 100644
index 0000000..70a3573
--- /dev/null
+++ b/o3d/plugin/idl/render_surface.idl
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace o3d {
+
+%[
+ A RenderSurfaceBase is the base for RenderSurface and
+ RenderDepthStencilSurface.
+%]
+[nocpp, include="core/cross/render_surface.h"] class RenderSurfaceBase
+ : ParamObject {
+ %[
+ The width of the surface, in pixels.
+ %]
+ [field_access=private, getter] int width;
+
+ %[
+ The height of the surface, in pixels.
+ %]
+ [field_access=private, getter] int height;
+
+}; // RenderSurfaceBaes
+
+
+%[
+ A RenderSurface encapsulates the notion of a renderable surface.
+ When used in conjunction with a RenderSurfaceSet node in the render graph,
+ the API allows for rendering of primitives to the given surface.
+ RenderSurface objects are not constructable through the Pack API, they may
+ only be accessed through the texture getRenderSurface(...) interfaces.
+%]
+[nocpp, include="core/cross/render_surface.h"] class RenderSurface
+ : RenderSurfaceBase {
+ %[
+ The texture in which this surface is contained.
+ %]
+ [field_access=private, getter] Texture? texture;
+}; // RenderSurface
+
+%[
+ A RenderDepthStencilSurface represents a depth stencil render surface.
+%]
+[nocpp, include="core/cross/render_surface.h"]
+class RenderDepthStencilSurface
+ : RenderSurfaceBase {
+}; // RenderDepthStencilSurface
+
+} // namespace o3d
diff --git a/o3d/plugin/idl/render_surface_set.idl b/o3d/plugin/idl/render_surface_set.idl
new file mode 100644
index 0000000..e7e6585
--- /dev/null
+++ b/o3d/plugin/idl/render_surface_set.idl
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace o3d {
+
+%[
+ A RenderSurfaceSet node will bind depth and color RenderSurface nodes
+ to the current rendering context. All RenderNodes descending
+ from the given RenderSurfaceSet node will operate on the contents of
+ the bound depth and color buffers.
+ Note the following usage constraints of this node:
+ 1) If both a color and depth surface is bound, then they must be of matching
+ dimensions.
+ 2) At least one of render_surface and render_depth_surface must non-null.
+%]
+[nocpp, include="core/cross/render_surface_set.h"]
+class RenderSurfaceSet : RenderNode {
+
+ %[
+ The render surface to which the color contents of all RenderNode children
+ should be drawn.
+ %]
+ [getter, setter]
+ RenderSurface? render_surface_;
+
+ %[
+ The render depth stencil surface to which the depth contents of all
+ RenderNode children should be drawn.
+ %]
+ [getter, setter]
+ RenderDepthStencilSurface? render_depth_stencil_surface_;
+
+}; // RenderSurfaceSet
+
+} // namespace o3d
diff --git a/o3d/plugin/idl/sampler.idl b/o3d/plugin/idl/sampler.idl
new file mode 100644
index 0000000..b8d9c5e
--- /dev/null
+++ b/o3d/plugin/idl/sampler.idl
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace o3d {
+
+%[
+ Sampler is the base of all texture samplers. Texture samplers encapsulate
+ a texture reference with a set of states that define how the texture
+ gets applied to a surface. Sampler states are set either via Params defined
+ on the Sampler object or directly via one the convenience methods defined
+ on the Sampler. The following states are supported (default values are in
+ parenthesis):
+ \li 'addressModeU' (WRAP)
+ \li 'addressModeV' (WRAP)
+ \li 'addressModeW' (WRAP)
+ \li 'magFilter' (LINEAR)
+ \li 'minFilter' (LINEAR)
+ \li 'mipFilter' (POINT)
+ \li 'borderColor' ([0,0,0,0])
+ \li 'maxAnisotropy' (1)
+%]
+
+[nocpp, include="core/cross/sampler.h"]
+class Sampler : ParamObject {
+ %[
+ \var AddressMode,
+ Controls what happens with texture coordinates outside the [0..1] range.
+ \li WRAP
+ \li MIRROR
+ \li CLAMP
+ \li BORDER
+ %]
+ enum AddressMode {
+ WRAP,
+ MIRROR,
+ CLAMP,
+ BORDER
+ };
+
+ %[
+ \var FilterType,
+ Texture filtering types.
+ \li NONE
+ \li POINT
+ \li LINEAR
+ \li ANISOTROPIC
+ %]
+ enum FilterType {
+ NONE,
+ POINT,
+ LINEAR,
+ ANISOTROPIC
+ };
+
+ %[
+ The texture address mode for the u coordinate.
+ %]
+ [getter, setter] AddressMode address_mode_u_;
+
+ %[
+ The texture address mode for the v coordinate.
+ %]
+ [getter, setter] AddressMode address_mode_v_;
+
+ %[
+ The texture address mode for the w coordinate.
+ %]
+ [getter, setter] AddressMode address_mode_w_;
+
+ %[
+ The magnification filter.
+ %]
+ [getter, setter] FilterType mag_filter_;
+
+ %[
+ The minification filter.
+ %]
+ [getter, setter] FilterType min_filter_;
+
+ %[
+ The mipmap filter used during minification.
+ %]
+ [getter, setter] FilterType mip_filter_;
+
+ %[
+ Color returned for texture coordinates outside the [0,1] range when the
+ address mode is set to BORDER.
+ %]
+ [getter, setter] Float4 border_color;
+
+ %[
+ Degree of anisotropy used when the ANISOTROPIC filter type is used.
+ %]
+ [getter, setter] int max_anisotropy_;
+
+ %[
+ The Texture object used by this Sampler.
+ %]
+ [getter, setter] Texture? texture_;
+}; // Sampler
+
+
+} // namespace o3d
+
diff --git a/o3d/plugin/idl/shape.idl b/o3d/plugin/idl/shape.idl
new file mode 100644
index 0000000..1423e94
--- /dev/null
+++ b/o3d/plugin/idl/shape.idl
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace o3d {
+
+typedef Element[] ElementArray;
+
+%[
+ The Shape represents a collection of Elements. The typical example is a
+ cube with 6 faces where each face uses a different material would be
+ represented as 1 Shape with 6 Elements, one for each material.
+%]
+
+[nocpp, include="core/cross/shape.h"] class Shape : ParamObject {
+ %[
+ The elements owned by this shape.
+
+ Each access to this field gets the entire list so it is best to get it
+ just once. For example:
+ \code
+ var elements = renderNode.elements;
+ for (var i = 0; i < elements.length; i++) {
+ var element = elements[i];
+ }
+ \endcode
+
+ Note that modifications to this array [e.g. push()] will not affect
+ the underlying Shape, while modifications to the array's members
+ <strong>will</strong> affect them.
+ %]
+ [userglue_getter, getter, userglue_setter, setter]
+ ElementArray elements_;
+
+ %[
+ Creates a DrawElement for each Element owned by this Shape.
+ If an Element already has a DrawElement that uses \a material a new
+ DrawElement will not be created.
+ \param pack: pack used to manage created DrawElements.
+ \param material material to use for each DrawElement. If you pass null it
+ will use the material on the corresponding Element.
+ This allows you to easily setup the default (just draw as is) by passing
+ null or setup a shadow pass by passing in a shadow material.
+ %]
+ void CreateDrawElements(Pack pack,
+ Material? material);
+
+ [verbatim=cpp_glue] %{
+
+ o3d::ElementArray userglue_getter_elements_(
+ o3d::Shape *self) {
+ return self->GetElements();
+ }
+ void userglue_setter_elements_(
+ o3d::Shape *_this,
+ const o3d::ElementArray& elements) {
+ _this->SetElements(elements);
+ }
+ %}
+}; // Shape
+
+} // namespace o3d
diff --git a/o3d/plugin/idl/skin.idl b/o3d/plugin/idl/skin.idl
new file mode 100644
index 0000000..762358d
--- /dev/null
+++ b/o3d/plugin/idl/skin.idl
@@ -0,0 +1,274 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// This file contains the idlglue declaration of Skin and SkinEval.
+
+namespace o3d {
+
+%[
+ A Skin holds an array of matrix indices and influences for vertices in a skin.
+ A Skin is data only and can be used by one or more SkinEvals to implement
+ skinning.
+%]
+[nocpp, include="core/cross/skin.h"] class Skin
+ : NamedObject {
+
+ %[
+ Sets the influences for an individual vertex.
+
+ \param vertex_index The index of the vertex to set influences for
+ \param influences An array of pairs of numbers where the first number
+ is the index of the matrix to influence the vertex and the second
+ number is the amount of influence where 0 = no influence and 1 = 100%
+ influence.
+ %]
+ [userglue] void SetVertexInfluences(unsigned int vertex_index,
+ NumberArray influences);
+
+ %[
+ Gets the influences for an individual vertex.
+ \param vertex_index the index of the vertex to get influences from.
+ \return Returns an Array of number pairs where the first number of each
+ pair is the index of a matrix that influences this vertex and the
+ second number is the amount of influence where 0 = no influence
+ and 1 = 100% influcence.
+ %]
+ [const, userglue] NumberArray GetVertexInfluences(unsigned int vertex_index);
+
+ %[
+ An array with one element per vertex, where each element is an array of
+ influences consisting of a number pair, where the first number is a
+ matrix index and the second is the amount of influence.
+ %]
+ [getter,userglue_getter,setter,userglue_setter]
+ NumberArray[] influences_;
+
+ %[
+ Sets the inverse bind pose matrix for a particular joint/bone/transform.
+ \param index index of bone/joint/transform.
+ \param matrix Inverse bind pose matrix for that joint.
+ %]
+ void SetInverseBindPoseMatrix(unsigned int index,
+ Vectormath::Aos::Matrix4 matrix);
+
+ %[
+ The array of inverse bone matrices
+ %]
+ [getter,setter] Vectormath::Aos::Matrix4[]
+ inverse_bind_pose_matrices_;
+
+ // TODO: Add setter that takes an array of matrices and sets all
+ // of the matrix arrays.
+ // TODO: Add SetNumberInverseBindPoseMatrices
+ // TODO: Add SetNumberVertexInflucences
+
+ %[
+ Deserializes from the skin data given a RawData object.
+
+ \param raw_data contains skin data
+ \param offset is a byte offset from the start of raw_data
+ \param length is the byte length of the data to set
+ \return True if operation was successful.
+ %]
+ bool Set(o3d::RawData raw_data,
+ size_t offset,
+ size_t length);
+
+ %[
+ Deserializes from the skin data given a RawData object.
+ \param raw_data entire contents contains skin data
+ \return True if operation was successful.
+ %]
+ bool Set(o3d::RawData raw_data);
+
+ [verbatim=cpp_glue] %{
+ void userglue_method_SetVertexInfluences(o3d::Skin* self,
+ unsigned int vertex_index,
+ const std::vector<float>& values) {
+ if (values.size() % 2 != 0) {
+ O3D_ERROR(self->service_locator())
+ << "odd number of values passed into SetVertexInfluence. "
+ << "Even number required as they are pairs.";
+ } else {
+ o3d::Skin::Influences influences;
+ for (unsigned ii = 0; ii < values.size(); ii += 2) {
+ influences.push_back(o3d::Skin::Influence(
+ static_cast<unsigned int>(values[ii]),
+ values[ii + 1]));
+ }
+ self->SetVertexInfluences(vertex_index, influences);
+ }
+ }
+ std::vector<std::vector<float> > userglue_getter_influences_(
+ o3d::Skin* _this) {
+ const o3d::Skin::InfluencesArray& influences = _this->influences();
+ std::vector<std::vector<float> > result(influences.size());
+ for (int i = 0; i != influences.size(); ++i) {
+ const o3d::Skin::Influences& vertex_influences = influences[i];
+ for (int j = 0; j != vertex_influences.size(); ++j) {
+ const o3d::Skin::Influence& influence = vertex_influences[j];
+ result[i].push_back(static_cast<float>(influence.matrix_index));
+ result[i].push_back(influence.weight);
+ }
+ }
+ return result;
+ }
+ void userglue_setter_influences_(
+ o3d::Skin* _this,
+ const std::vector<std::vector<float> >& input) {
+ for (int i = 0; i != input.size(); ++i) {
+ const std::vector<float>& vertex_input = input[i];
+ o3d::Skin::Influences influences(vertex_input.size() / 2);
+ for (int j = 0; j != vertex_input.size() / 2; ++j) {
+ influences[j] = o3d::Skin::Influence(
+ static_cast<int>(vertex_input[j * 2]),
+ vertex_input[j * 2 + 1]);
+ }
+ _this->SetVertexInfluences(i, influences);
+ }
+ }
+ std::vector<float> userglue_method_GetVertexInfluences(
+ o3d::Skin* self,
+ unsigned int vertex_index) {
+ std::vector<float> values;
+ const o3d::Skin::Influences* influences =
+ self->GetVertexInfluences(vertex_index);
+ if (influences) {
+ values.resize(influences->size() * 2);
+ for (unsigned ii = 0; ii < influences->size(); ++ii) {
+ values[ii * 2 + 0] =
+ static_cast<float>((*influences)[ii].matrix_index);
+ values[ii * 2 + 1] = (*influences)[ii].weight;
+ }
+ }
+ return values;
+ }
+ %}
+
+}; // Skin
+
+%[
+ A SkinEval is a VertexSource that takes its Streams, a ParamArray of 4-by-4
+ matrices and a Skin and skins the vertices in its streams storing the results
+ in bound output streams.
+%]
+[nocpp, include="core/cross/skin.h"] class SkinEval
+ : VertexSource {
+
+ %[
+ The Skin to use for skinning.
+ %]
+ [getter, setter] Skin? skin;
+
+ %[
+ The array of matrices to use for skinning.
+ %]
+ [getter, setter] ParamArray matrices;
+
+ %[
+ The base matrix to subtract from the matrices before skinning.
+ %]
+ [getter, setter] Vectormath::Aos::Matrix4 base;
+
+ %[
+ Binds a SourceBuffer field to the SkinEval and defines how the data in the
+ field should be interpreted. The field's buffer must be of a
+ compatible type otherwise the binding fails and the function returns false.
+ \param semantic The particular use of this stream.
+ \param semantic_index Which index of a particular semantic to use.
+ \param field The field containing information for this stream.
+ \param start_index The first element to use.
+ \return True if successful.
+ %]
+ [virtual] bool SetVertexStream(Stream::Semantic semantic,
+ int semantic_index,
+ Field field,
+ unsigned int start_index);
+
+
+ %[
+ Removes a vertex stream from this SkinEval.
+ \param semantic The particular use of this stream.
+ \param semantic_index Which index of a particular semantic to use.
+ \return true if the specified stream existed.
+ %]
+ bool RemoveVertexStream(Stream::Semantic semantic, int semantic_index);
+
+ %[
+ Searches the vertex streams bound to the SkinEval for one with the given
+ stream semantic.
+ \param semantic The particular use of this stream.
+ \param semantic_index Which index of a particular semantic to use.
+ \return The found stream or NULL if it does not exist.
+ %]
+ [userglue]
+ Stream GetVertexStream(Stream::Semantic semantic, int semantic_index);
+
+ %[
+ A vector of the vertex streams on this SkinEval.
+ %]
+ [userglue_getter, getter] StreamVector vertex_streams;
+
+ [verbatim=cpp_glue] %{
+ std::vector<o3d::Stream*> userglue_getter_vertex_streams(
+ o3d::SkinEval* self) {
+ std::vector<o3d::Stream*> streams;
+ const o3d::StreamParamVector& stream_params =
+ self->vertex_stream_params();
+ streams.reserve(stream_params.size());
+ for (unsigned ii = 0; ii < stream_params.size(); ++ii) {
+ streams.push_back(
+ const_cast<o3d::Stream*>(&stream_params[ii]->stream()));
+ }
+ return streams;
+ }
+ o3d::Stream* userglue_method_GetVertexStream(
+ o3d::SkinEval* self,
+ o3d::Stream::Semantic semantic,
+ int semantic_index) {
+ return const_cast<o3d::Stream*>(
+ self->GetVertexStream(semantic, semantic_index));
+ }
+ %}
+}; // SkinEval
+
+%[
+ A Param which stores a Skin.
+%]
+[nocpp, include="core/cross/skin.h"] class ParamSkin : Param {
+ %[
+ The Skin stored by the Param.
+ %]
+ [getter, setter] Skin? value_;
+};
+
+} // namespace o3d
diff --git a/o3d/plugin/idl/standard_param.idl b/o3d/plugin/idl/standard_param.idl
new file mode 100644
index 0000000..b893bbc7
--- /dev/null
+++ b/o3d/plugin/idl/standard_param.idl
@@ -0,0 +1,200 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace o3d {
+
+%[
+ A type of ParamMatrix4 that supplies the current world matrix at render time.
+%]
+[nocpp, include="core/cross/standard_param.h"] class WorldParamMatrix4 : ParamMatrix4 {
+};
+
+%[
+ A type of ParamMatrix4 that supplies the current inverse world matrix at
+ render time.
+%]
+[nocpp, include="core/cross/standard_param.h"] class WorldInverseParamMatrix4 : ParamMatrix4 {
+};
+
+%[
+ A type of ParamMatrix4 that supplies the current world transpose matrix at
+ render time.
+%]
+[nocpp, include="core/cross/standard_param.h"] class WorldTransposeParamMatrix4 : ParamMatrix4 {
+};
+
+%[
+ A type of ParamMatrix4 that supplies the current inverse world transpose
+ matrix at render time.
+%]
+[nocpp, include="core/cross/standard_param.h"] class WorldInverseTransposeParamMatrix4 : ParamMatrix4 {
+};
+
+%[
+ A type of ParamMatrix4 that supplies the current view matrix at render time.
+%]
+[nocpp, include="core/cross/standard_param.h"] class ViewParamMatrix4 : ParamMatrix4 {
+};
+
+%[
+ A type of ParamMatrix4 that supplies the current inverse view matrix at render
+ time.
+%]
+[nocpp, include="core/cross/standard_param.h"] class ViewInverseParamMatrix4 : ParamMatrix4 {
+};
+
+%[
+ A type of ParamMatrix4 that supplies the current view transpose matrix at
+ render time.
+%]
+[nocpp, include="core/cross/standard_param.h"] class ViewTransposeParamMatrix4 : ParamMatrix4 {
+};
+
+%[
+ A type of ParamMatrix4 that supplies the current inverse view transpose matrix
+ at render time.
+%]
+[nocpp, include="core/cross/standard_param.h"] class ViewInverseTransposeParamMatrix4 : ParamMatrix4 {
+};
+
+%[
+ A type of ParamMatrix4 that supplies the current projecton matrix at render
+ time.
+%]
+[nocpp, include="core/cross/standard_param.h"] class ProjectionParamMatrix4 : ParamMatrix4 {
+};
+
+%[
+ A type of ParamMatrix4 that supplies the current inverse projection matrix at
+ render time.
+%]
+[nocpp, include="core/cross/standard_param.h"] class ProjectionInverseParamMatrix4 : ParamMatrix4 {
+};
+
+%[
+ A type of ParamMatrix4 that supplies the current projection transpose matrix
+ at render time.
+%]
+[nocpp, include="core/cross/standard_param.h"] class ProjectionTransposeParamMatrix4 : ParamMatrix4 {
+};
+
+%[
+ A type of ParamMatrix4 that supplies the current inverse projection transpose
+ matrix at render time.
+%]
+[nocpp, include="core/cross/standard_param.h"] class ProjectionInverseTransposeParamMatrix4 : ParamMatrix4 {
+};
+
+%[
+ A type of ParamMatrix4 that supplies the current world view matrix at
+ render time.
+%]
+[nocpp, include="core/cross/standard_param.h"] class WorldViewParamMatrix4 : ParamMatrix4 {
+};
+
+%[
+ A type of ParamMatrix4 that supplies the current inverse world view matrix at
+ render time.
+%]
+[nocpp, include="core/cross/standard_param.h"] class WorldViewInverseParamMatrix4 : ParamMatrix4 {
+};
+
+%[
+ A type of ParamMatrix4 that supplies the current transpose world view matrix
+ at render time.
+%]
+[nocpp, include="core/cross/standard_param.h"] class WorldViewTransposeParamMatrix4 : ParamMatrix4 {
+};
+
+%[
+ A type of ParamMatrix4 that supplies the current inverse world view
+ transpose matrix at render time.
+%]
+[nocpp, include="core/cross/standard_param.h"] class WorldViewInverseTransposeParamMatrix4 : ParamMatrix4 {
+};
+
+%[
+ A type of ParamMatrix4 that supplies the current view projection matrix at
+ render time.
+%]
+[nocpp, include="core/cross/standard_param.h"] class ViewProjectionParamMatrix4 : ParamMatrix4 {
+};
+
+%[
+ A type of ParamMatrix4 that supplies the current inverse view projection
+ matrix at render time.
+%]
+[nocpp, include="core/cross/standard_param.h"] class ViewProjectionInverseParamMatrix4 : ParamMatrix4 {
+};
+
+%[
+ A type of ParamMatrix4 that supplies the current view projection transpose
+ matrix at render time.
+%]
+[nocpp, include="core/cross/standard_param.h"] class ViewProjectionTransposeParamMatrix4 : ParamMatrix4 {
+};
+
+%[
+ A type of ParamMatrix4 that supplies the current inverse view projection
+ transpose matrix at render time.
+%]
+[nocpp, include="core/cross/standard_param.h"] class ViewProjectionInverseTransposeParamMatrix4 : ParamMatrix4 {
+};
+
+%[
+ A type of ParamMatrix4 that supplies the current world view projection matrix
+ at render time.
+%]
+[nocpp, include="core/cross/standard_param.h"] class WorldViewProjectionParamMatrix4 : ParamMatrix4 {
+};
+
+%[
+ A type of ParamMatrix4 that supplies the current inverse world view projection
+ matrix at render time.
+%]
+[nocpp, include="core/cross/standard_param.h"] class WorldViewProjectionInverseParamMatrix4 : ParamMatrix4 {
+};
+
+%[
+ A type of ParamMatrix4 that supplies the current world view projection
+ transpose matrix at render time.
+%]
+[nocpp, include="core/cross/standard_param.h"] class WorldViewProjectionTransposeParamMatrix4 : ParamMatrix4 {
+};
+
+%[
+ A type of ParamMatrix4 that supplies the current inverse world view projection
+ transpose matrix at render time.
+%]
+[nocpp, include="core/cross/standard_param.h"] class WorldViewProjectionInverseTransposeParamMatrix4 : ParamMatrix4 {
+};
+
+} // namespace o3d
diff --git a/o3d/plugin/idl/state.idl b/o3d/plugin/idl/state.idl
new file mode 100644
index 0000000..9386208
--- /dev/null
+++ b/o3d/plugin/idl/state.idl
@@ -0,0 +1,277 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace o3d {
+
+%[
+ A State object sets the RenderStates for a particular material or StateSet.
+%]
+[nocpp, include="core/cross/state.h"] class State : ParamObject {
+ %[
+ \var Comparison
+ \li CMP_NEVER (Never)
+ \li CMP_LESS (Less Than)
+ \li CMP_EQUAL (Equal To)
+ \li CMP_LEQUAL (Less Than or Equal To)
+ \li CMP_GREATER (Greater Than)
+ \li CMP_NOTEQUAL (Not Equal To)
+ \li CMP_GEQUAL (Greater Than or Equal To)
+ \li CMP_ALWAYS (Always)
+ %]
+ enum Comparison {
+ CMP_NEVER, /* Never */
+ CMP_LESS, /* Less Than */
+ CMP_EQUAL, /* Equal To */
+ CMP_LEQUAL, /* Less Than or Equal To */
+ CMP_GREATER, /* Greater Than */
+ CMP_NOTEQUAL, /* Not Equal To */
+ CMP_GEQUAL, /* Greater Than or Equal To */
+ CMP_ALWAYS /* Always */
+ };
+
+ %[
+ \var Cull
+ \li CULL_NONE Don't Cull by face
+ \li CULL_CW Cull clock-wise faces
+ \li CULL_CCW Cull counter clock-wise faces
+ %]
+ enum Cull {
+ CULL_NONE, /* Don't Cull by face */
+ CULL_CW, /* Cull clock-wise faces*/
+ CULL_CCW /* Cull counter clock-wise faces */
+ };
+
+ %[
+ \var Fill
+ \li POINT
+ \li WIREFRAME
+ \li SOLID
+ %]
+ enum Fill {
+ POINT, /* Points */
+ WIREFRAME, /* Wireframe */
+ SOLID /* Solid */
+ };
+
+ %[
+ \var BlendingFunction
+ \li BLENDFUNC_ZERO
+ \li BLENDFUNC_ONE
+ \li BLENDFUNC_SOURCE_COLOR
+ \li BLENDFUNC_INVERSE_SOURCE_COLOR
+ \li BLENDFUNC_SOURCE_ALPHA
+ \li BLENDFUNC_INVERSE_SOURCE_ALPHA
+ \li BLENDFUNC_DESTINATION_ALPHA
+ \li BLENDFUNC_INVERSE_DESTINATION_ALPHA
+ \li BLENDFUNC_DESTINATION_COLOR
+ \li BLENDFUNC_INVERSE_DESTINATION_COLOR
+ \li BLENDFUNC_SOURCE_ALPHA_SATUTRATE
+ %]
+ enum BlendingFunction {
+ BLENDFUNC_ZERO,
+ BLENDFUNC_ONE,
+ BLENDFUNC_SOURCE_COLOR,
+ BLENDFUNC_INVERSE_SOURCE_COLOR,
+ BLENDFUNC_SOURCE_ALPHA,
+ BLENDFUNC_INVERSE_SOURCE_ALPHA,
+ BLENDFUNC_DESTINATION_ALPHA,
+ BLENDFUNC_INVERSE_DESTINATION_ALPHA,
+ BLENDFUNC_DESTINATION_COLOR,
+ BLENDFUNC_INVERSE_DESTINATION_COLOR,
+ BLENDFUNC_SOURCE_ALPHA_SATUTRATE
+ };
+
+ %[
+ \var BlendingEquation
+ \li BLEND_ADD
+ \li BLEND_SUBTRACT
+ \li BLEND_REVERSE_SUBTRACT
+ \li BLEND_MIN
+ \li BLEND_MAX
+ %]
+ enum BlendingEquation {
+ BLEND_ADD,
+ BLEND_SUBTRACT,
+ BLEND_REVERSE_SUBTRACT,
+ BLEND_MIN,
+ BLEND_MAX
+ };
+
+ %[
+ \var StencilOperation
+ \li STENCIL_KEEP
+ \li STENCIL_ZERO
+ \li STENCIL_REPLACE
+ \li STENCIL_INCREMENT_SATURATE
+ \li STENCIL_DECREMENT_SATURATE
+ \li STENCIL_INVERT
+ \li STENCIL_INCREMENT
+ \li STENCIL_DECREMENT
+ %]
+ enum StencilOperation {
+ STENCIL_KEEP,
+ STENCIL_ZERO,
+ STENCIL_REPLACE,
+ STENCIL_INCREMENT_SATURATE,
+ STENCIL_DECREMENT_SATURATE,
+ STENCIL_INVERT,
+ STENCIL_INCREMENT,
+ STENCIL_DECREMENT
+ };
+
+ %[
+ Returns a Param for a given state. If the param does not already exist it
+ will be created. If the state_name is invalid it will return null.
+ \param state_name name of the state
+ \return param or null if no matching state.
+
+ Example:
+ \code
+ // Gets the client.
+ g_o3d = document.o3d.o3d;
+ ...
+ // Creates a state object.
+ var state = my_pack.createState("my_state");
+
+ // Sets some states.
+ state.getStateParam('o3d.StencilEnable').value = true;
+ state.getStateParam('o3d.StencilReference').value = 25;
+ state.getStateParam('o3d.StencilPassOperation').value =
+ g_o3d.State.STENCIL_REPLACE;
+ state.getStateParam('o3d.StencilComparisonFunction').value =
+ g_o3d.State.CMP_ALWAYS;
+ state.getStateParam('o3d.ZEnable').value = false;
+ state.getStateParam('o3d.ZWriteEnable').value = false;
+ state.getStateParam('o3d.ColorWriteEnable').value = 0;
+ \endcode
+ Valid states:
+ <table>
+ <tr><td>State Name</td><td>Type</td><td>Default Value</td></tr>
+ <tr><td>o3d.AlphaTestEnable</td><td>ParamBoolean</td>
+ <td>default = false</td></tr>
+ <tr><td>o3d.AlphaReference</td><td>ParamFloat 0-1</td>
+ <td>default = 0</td></tr>
+ <tr><td>o3d.AlphaComparisonFunction</td><td>ParamInteger,
+ State.Comparison</td><td>default = State.CMP_ALWAYS</td></tr>
+ <tr><td>o3d.CullMode</td><td>ParamInteger, State.Cull</td>
+ <td>default = State.CULL_CW</td></tr>
+ <tr><td>o3d.DitherEnable</td><td>ParamBoolean</td>
+ <td>default = false</td></tr>
+ <tr><td>o3d.LineSmoothEnable</td><td>ParamBoolean</td>
+ <td>default = false</td></tr>
+ <tr><td>o3d.PointSpriteEnable</td><td>ParamBoolean</td>
+ <td>default = false</td></tr>
+ <tr><td>o3d.PointSize</td><td>ParamFloat</td><td>TBD</td></tr>
+ <tr><td>o3d.PolygonOffset1</td><td>ParamFloat<td>TBD</td></tr>
+ <tr><td>o3d.PolygonOffset2</td><td>ParamFloat<td>TBD</td></tr>
+ <tr><td>o3d.FillMode</td><td>ParamInteger, State.Fill</td>
+ <td>default = State.SOLID</td></tr>
+ <tr><td>o3d.ZEnable</td><td>ParamBoolean</td>
+ <td>default = true</td></tr>
+ <tr><td>o3d.ZWriteEnable</td><td>ParamBoolean</td>
+ <td>default = true</td></tr>
+ <tr><td>o3d.ZComparisonFunction</td>
+ <td>ParamInteger, State.Comparison</td>
+ <td>default = State.CMP_ALWAYS</td></tr>
+ <tr><td>o3d.AlphaBlendEnable</td><td>ParamBoolean</td>
+ <td>default = false</td></tr>
+ <tr><td>o3d.SourceBlendFunction</td>
+ <td>ParamInteger, State.BlendingFunction</td>
+ <td>default = State.BLENDFUNC_ONE</td></tr>
+ <tr><td>o3d.DestinationBlendFunction</td>
+ <td>ParamInteger, State.BlendingFunction</td>
+ <td>default = State.BLENDFUNC_ZERO</td></tr>
+ <tr><td>o3d.StencilEnable</td><td>ParamBoolean</td>
+ <td>default = false</td></tr>
+ <tr><td>o3d.StencilFailOperation</td>
+ <td>ParamInteger, State.StencilOperation</td>
+ <td>default = State.STENCIL_KEEP</td></tr>
+ <tr><td>o3d.StencilZFailOperation</td>
+ <td>ParamInteger, State.StencilOperation</td>
+ <td>default = State.STENCIL_KEEP</td></tr>
+ <tr><td>o3d.StencilPassOperation</td>
+ <td>ParamInteger, State.StencilOperation</td>
+ <td>default = State.STENCIL_KEEP</td></tr>
+ <tr><td>o3d.StencilComparisonFunction</td>
+ <td>ParamInteger, State.Comparison</td>
+ <td>default = State.CMP_ALWAYS</td></tr>
+ <tr><td>o3d.StencilReference</td><td>ParamInteger 0-255</td>
+ <td>default = 0</td></tr>
+ <tr><td>o3d.StencilMask</td><td>ParamInteger 0-255</td>
+ <td>default = 255</td></tr>
+ <tr><td>o3d.StencilWriteMask</td><td>ParamInteger 0-255</td>
+ <td>default = 255</td></tr>
+ <tr><td>o3d.ColorWriteEnable</td>
+ <td>ParamInteger 0-15 bit 0 = red, bit 1 = green,
+ bit 2 = blue, bit 3 = alpha</td><td>default = 15</td></tr>
+ <tr><td>o3d.BlendEquation</td>
+ <td>ParamInteger, State.BlendingEquation</td>
+ <td>default = State.BLEND_ADD</td></tr>
+ <tr><td>o3d.TwoSidedStencilEnable</td><td>ParamBoolean</td>
+ <td>default = false</td></tr>
+ <tr><td>o3d.CCWStencilFailOperation</td>
+ <td>ParamInteger, State.StencilOperation</td>
+ <td>default = State.STENCIL_KEEP</td></tr>
+ <tr><td>o3d.CCWStencilZFailOperation</td>
+ <td>ParamInteger, State.StencilOperation</td>
+ <td>default = State.STENCIL_KEEP</td></tr>
+ <tr><td>o3d.CCWStencilPassOperation</td>
+ <td>ParamInteger, State.StencilOperation</td>
+ <td>default = State.STENCIL_KEEP</td></tr>
+ <tr><td>o3d.CCWStencilComparisonFunction</td>
+ <td>ParamInteger, State.Comparison</td>
+ <td>default = State.CMP_ALWAYS</td></tr>
+ <tr><td>o3d.SeparateAlphaBlendEnable</td><td>ParamBoolean</td>
+ <td>default = false;</td></tr>
+ <tr><td>o3d.SourceBlendAlphaFunction</td>
+ <td>ParamInteger, State.BlendingFunction</td>
+ <td>default = State.BLENDFUNC_ONE</td></tr>
+ <tr><td>o3d.DestinationBlendAlphaFunction</td>
+ <td>ParamInteger, State.BlendingFunction</td>
+ <td>default = State.BLENDFUNC_ZERO</td></tr>
+ <tr><td>o3d.BlendAlphaEquation</td>
+ <td>ParamInteger, State.BlendingEquation</td>
+ <td>default = State.BLEND_ADD</td></tr>
+ </table>
+
+ %]
+ [nocpp, userglue] Param? GetStateParam(String state_name);
+
+ [verbatim=cpp_glue] %{
+ o3d::Param* userglue_method_GetStateParam(
+ o3d::State *self,
+ const o3d::String& state_name) {
+ return self->GetUntypedStateParam(state_name);
+ }
+ %}
+};
+
+} // namespace o3d
diff --git a/o3d/plugin/idl/state_set.idl b/o3d/plugin/idl/state_set.idl
new file mode 100644
index 0000000..050c6b8
--- /dev/null
+++ b/o3d/plugin/idl/state_set.idl
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace o3d {
+
+%[
+ A StateSet is a render node that sets render states of all of its
+ children. You can make this a parent of a part of the render graph to set
+ render states in a more global way.
+%]
+[nocpp, include="core/cross/state_set.h"] class StateSet
+ : RenderNode {
+
+ %[
+ The State for this StateSet.
+ %]
+ [getter, setter] State? state_;
+
+}; // StateSet
+
+} // namespace o3d
diff --git a/o3d/plugin/idl/stream.idl b/o3d/plugin/idl/stream.idl
new file mode 100644
index 0000000..991ade3
--- /dev/null
+++ b/o3d/plugin/idl/stream.idl
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+%[
+ Namespace o3d
+%]
+namespace o3d {
+
+%[
+ A stream object defines how Buffer data is interpreted by an Effect when
+ rendering a Primitive..
+ It contains a pointer to a Field, a semantic and semantic index
+ that determine how the data is accessed.
+%]
+
+[nocpp, include="core/cross/stream.h"]
+class Stream : ObjectBase {
+ %[
+ \var Semantic,
+ \li UNKNOWN_SEMANTIC = 0,
+ \li POSITION,
+ \li NORMAL,
+ \li TANGENT,
+ \li BINORMAL,
+ \li COLOR,
+ \li TEXCOORD
+
+ Semantics used when binding buffers to the streambank. They determine how
+ the Stream links up to the shader inputs.
+ %]
+ enum Semantic {
+ UNKNOWN_SEMANTIC = 0,
+ POSITION,
+ NORMAL,
+ TANGENT,
+ BINORMAL,
+ COLOR,
+ TEXCOORD
+ };
+
+ %[
+ The associated Field.
+ %]
+ [userglue_getter, getter] Field? field;
+
+ %[
+ The semantic specified for the Stream.
+ %]
+ [getter] Semantic semantic;
+
+ %[
+ The semantic index specified for the Stream
+ (eg., TEXCOORD1 = 1, BINORMAL7 = 7, etc).
+ %]
+ [getter] int semantic_index;
+
+ %[
+ The start index for the Stream.
+ %]
+ [getter] unsigned int start_index;
+
+ [verbatim=cpp_glue] %{
+ o3d::Field* userglue_getter_field(o3d::Stream* self) {
+ return const_cast<o3d::Field*>(&self->field());
+ }
+ %}
+};
+
+%[
+ An array of Streams.
+%]
+typedef Stream[] StreamVector;
+
+%[
+ A Param which stores a Stream.
+%]
+[nocpp, include="core/cross/stream.h"] class ParamVertexBufferStream : Param {
+ %[
+ The Stream stored by the Param.
+ %]
+ [userglue_getter, getter] Stream? stream;
+ [verbatim=cpp_glue] %{
+ o3d::Stream* userglue_getter_stream(
+ o3d::ParamVertexBufferStream* self) {
+ return const_cast<o3d::Stream*>(&self->stream());
+ }
+ %}
+};
+
+} // namespace o3d
diff --git a/o3d/plugin/idl/stream_bank.idl b/o3d/plugin/idl/stream_bank.idl
new file mode 100644
index 0000000..a5f08d9
--- /dev/null
+++ b/o3d/plugin/idl/stream_bank.idl
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace o3d {
+
+%[
+ The StreamBank a collection of streams that hold vertices.
+%]
+[nocpp, include="core/cross/primitive.h"]
+class StreamBank : NamedObject {
+
+ %[
+ Binds a VertexBuffer field to the StreamBank and defines how the data in
+ the buffer should be interpreted. The field's buffer must be of a
+ compatible type otherwise the binding fails and the function returns false.
+ \param semantic The particular use of this stream.
+ \param semantic_index Which index of a particular semantic to use.
+ \param field The field containing information for this stream.
+ \param start_index The first element to use.
+ \return True if successful.
+ %]
+ bool SetVertexStream(Stream::Semantic semantic,
+ int semantic_index,
+ Field field,
+ unsigned int start_index);
+
+ %[
+ Searches the vertex streams bound to the StreamBank for one with the given
+ stream semantic. If a stream is not found then it returns null.
+ \param semantic The particular use of this stream.
+ \param semantic_index Which index of a particular semantic to use.
+ \return The found stream or null if it does not exist.
+ %]
+ [userglue]
+ Stream? GetVertexStream(Stream::Semantic semantic, int semantic_index);
+
+ %[
+ Removes a vertex stream from this StreamBank.
+ \param semantic The particular use of this stream.
+ \param semantic_index Which index of a particular semantic to use.
+ \return true if the specified stream existed.
+ %]
+ bool RemoveVertexStream(Stream::Semantic semantic, int semantic_index);
+
+ %[
+ Binds the source stream to the corresponding stream in this VertexSource.
+
+ \param source Source to get vertices from.
+ \param semantic The semantic of the vertices to get
+ \param semantic_index The semantic index of the vertices to get.
+ \return True if success. False if failure. If the requested semantic or
+ semantic index do not exist on the source or this source the bind will
+ fail.
+ %]
+ bool BindStream(VertexSource source,
+ Stream::Semantic semantic,
+ int semantic_index);
+
+ %[
+ Unbinds the requested stream.
+ \param semantic The semantic of the vertices to unbind
+ \param semantic_index The semantic index of the vertices to unbind.
+ \return True if unbound. False those vertices do not exist or were not
+ bound.
+ %]
+ bool UnbindStream(Stream::Semantic semantic, int semantic_index);
+
+ %[
+ An array of the vertex streams on this StreamBank.
+
+ Each access to this field gets the entire list so it is best to get it
+ just once. For example:
+ \code
+ var streams = streamBank.vertexStreams;
+ for (var i = 0; i < streams.length; i++) {
+ var stream = streams[i];
+ }
+ \endcode
+
+ Note that modifications to this array [e.g. push()] will not affect
+ the underlying StreamBank, while modifications to the members of the array.
+ <strong>will</strong> affect them.
+ %]
+ [userglue_getter, getter] StreamVector vertex_streams;
+
+ [verbatim=cpp_glue] %{
+ std::vector<o3d::Stream*> userglue_getter_vertex_streams(
+ o3d::StreamBank* self) {
+ std::vector<o3d::Stream*> streams;
+ const o3d::StreamParamVector& stream_params =
+ self->vertex_stream_params();
+ streams.reserve(stream_params.size());
+ for (unsigned ii = 0; ii < stream_params.size(); ++ii) {
+ streams.push_back(
+ const_cast<o3d::Stream*>(&stream_params[ii]->stream()));
+ }
+ return streams;
+ }
+ o3d::Stream* userglue_method_GetVertexStream(
+ o3d::StreamBank* self,
+ o3d::Stream::Semantic semantic,
+ int semantic_index) {
+ return const_cast<o3d::Stream*>(
+ self->GetVertexStream(semantic, semantic_index));
+ }
+ %}
+}; // StreamBank
+
+%[
+ A Param which stores a StreamBank.
+%]
+[nocpp, include="core/cross/stream_bank.h"]
+class ParamStreamBank : Param {
+ %[
+ The StreamBank stored by the Param.
+ %]
+ [getter, setter] StreamBank? value_;
+};
+
+} // namespace o3d
diff --git a/o3d/plugin/idl/texture.idl b/o3d/plugin/idl/texture.idl
new file mode 100644
index 0000000..03dc49b
--- /dev/null
+++ b/o3d/plugin/idl/texture.idl
@@ -0,0 +1,312 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace o3d {
+
+%[
+ The Texture class is a base class for image data used in texture mapping.
+%]
+[include="core/cross/texture_base.h"] class Texture : ParamObject {
+ %[
+ \var Format,
+ \li UNKNOWN_FORMAT
+ \li XRGB8
+ \li ARGB8
+ \li ABGR16F
+ \li R32F
+ \li ABGR32F
+ \li DXT1
+ \li DXT3
+ \li DXT5
+
+ The in-memory format of the texture bitmap.
+
+ NOTE: The R32F format is different on GL vs D3D. If you use it in a shader
+ you must only use the red channel. The green, blue and alpha channels are
+ undefined.
+
+ For example:
+ \code
+ ...
+
+ // The texture sampler is used to access the texture bitmap in the fragment
+ // shader.
+ sampler texSampler0;
+
+ ...
+
+ // input parameters for our vertex shader
+ struct PixelShaderInput {
+ float4 position : POSITION;
+ float2 texcoord : TEXCOORD0; // Texture coordinates
+ };
+
+ float4 pixelShaderFunction(PixelShaderInput input): COLOR {
+ // ** Use only valid channels. ** ---------+
+ // |
+ // V
+ return tex2D(texSampler0, input.texcoord).rrrr;
+ }
+ \endcode
+ %]
+ enum Format {
+ UNKNOWN_FORMAT,
+ XRGB8,
+ ARGB8,
+ ABGR16F,
+ R32F,
+ ABGR32F,
+ DXT1,
+ DXT3,
+ DXT5
+ };
+
+ %[
+ The memory format used for storing the bitmap associated with the texture
+ object.
+ %]
+ [getter] Format format;
+
+ %[
+ The number of mipmap levels used by the texture.
+ %]
+ [getter] int levels;
+
+ %[
+ True of all the alpha values in the texture are 1.0
+ %]
+ [getter, getter, setter] bool alpha_is_one;
+}; // Texture
+
+%[
+ A class for 2D textures that defines the interface for getting
+ the dimensions of the texture, its memory format and number of mipmap levels.
+%]
+[include="core/cross/texture.h"] class Texture2D : Texture {
+ %[
+ The width of the texture, in texels.
+ %]
+ [getter] int width;
+
+ %[
+ The height of the texture, in texels.
+ %]
+ [getter] int height;
+
+ %[
+ Returns a RenderSurface object associated with a mip_level of a texture.
+
+ \param mip_level: The mip-level of the surface to be returned.
+ \param pack: The pack in which the surface will reside.
+ \return The RenderSurface object.
+ %]
+ RenderSurface? GetRenderSurface(int mip_level, Pack pack);
+
+ // TODO: Add Get, GetRect, SetRect and/or expose Bitmap.
+ %[
+ Sets the values of the data stored in the texture.
+
+ It is not recommend that you call this for large textures but it is useful
+ for making simple ramps or noise textures for shaders.
+
+ NOTE: the number of values must equal the size of the texture * the number
+ of elements. In other words, for a XRGB8 texture there must be
+ width * height * 3 values. For an ARGB8, ABGR16F or ABGR32F texture there
+ must be width * height * 4 values. For an R32F texture there must be
+ width * height values.
+
+ NOTE: the order of channels is R G B for XRGB8 textures and R G B A
+ for ARGB8, ABGR16F and ABGR32F textures so for example for XRGB8 textures\n
+ \n
+ [1, 0, 0] = a red pixel\n
+ [0, 0, 1] = a blue pixel\n
+ \n
+ For ARGB8, ABGR16F, ABGR32F textures\n
+ \n
+ [1, 0, 0, 0] = a red pixel with zero alpha\n
+ [1, 0, 0, 1] = a red pixel with one alpha\n
+ [0, 0, 1, 1] = a blue pixel with one alpha\n
+
+ \param level the mip level to update.
+ \param values Values to be stored in the buffer.
+ %]
+ [nocpp, userglue, include="core/cross/math_utilities.h"]
+ void Set(int level, float[] values);
+
+ [verbatim=cpp_glue] %{
+ void userglue_method_Set(o3d::Texture2D* self,
+ int level,
+ const std::vector<float>& values) {
+ if (level < 0 || level >= self->levels()) {
+ O3D_ERROR(self->service_locator())
+ << "level (" << level << " out of range";
+ return;
+ }
+ unsigned width = std::max(self->width() >> level, 1);
+ unsigned height = std::max(self->height() >> level, 1);
+ unsigned num_elements;
+ unsigned swizzle[4] = {2, 1, 0, 3};
+ switch (self->format()) {
+ case o3d::Texture::XRGB8:
+ num_elements = 3;
+ break;
+ case o3d::Texture::R32F:
+ swizzle[0] = 0;
+ num_elements = 1;
+ break;
+ case o3d::Texture::ARGB8:
+ case o3d::Texture::ABGR16F:
+ num_elements = 4;
+ break;
+ case o3d::Texture::ABGR32F: {
+ num_elements = 4;
+ const o3d::Texture::RGBASwizzleIndices& indices =
+ self->GetABGR32FSwizzleIndices();
+ for (int ii = 0; ii < 4; ++ii) {
+ swizzle[ii] = indices[ii];
+ }
+ break;
+ }
+ default:
+ O3D_ERROR(self->service_locator())
+ << "Texture::Set not supported for this type of texture";
+ return;
+ }
+ unsigned needed = num_elements * width * height;
+ if (values.size() != needed) {
+ O3D_ERROR(self->service_locator())
+ << "needed " << needed << " values but " << values.size()
+ << " passed in.";
+ return;
+ }
+ void* data;
+ if (!self->Lock(level, &data)) {
+ O3D_ERROR(self->service_locator()) << "could not lock texture";
+ return;
+ }
+ switch (self->format()) {
+ case o3d::Texture::ABGR16F: {
+ unsigned short* destination = static_cast<unsigned short*>(data);
+ unsigned short* end = destination + width * height * num_elements;
+ const float* source = &values[0];
+ while (destination < end) {
+ for (int element = 0; element < num_elements; ++element) {
+ destination[element] = Vectormath::Aos::FloatToHalf(
+ source[swizzle[element]]);
+ }
+ destination += num_elements;
+ source += num_elements;
+ }
+ break;
+ }
+ case o3d::Texture::R32F:
+ case o3d::Texture::ABGR32F: {
+ float* destination = static_cast<float*>(data);
+ float* end = destination + width * height * num_elements;
+ const float* source = &values[0];
+ while (destination < end) {
+ for (int element = 0; element < num_elements; ++element) {
+ destination[element] = source[swizzle[element]];
+ }
+ destination += num_elements;
+ source += num_elements;
+ }
+ break;
+ }
+ default: {
+ unsigned char* destination = static_cast<unsigned char*>(data);
+ unsigned char* end = destination + width * height * 4;
+ const float* source = &values[0];
+ while (destination < end) {
+ destination[0] = static_cast<unsigned char>(
+ source[swizzle[0]] * 255.0f);
+ destination[1] = static_cast<unsigned char>(
+ source[swizzle[1]] * 255.0f);
+ destination[2] = static_cast<unsigned char>(
+ source[swizzle[2]] * 255.0f);
+ destination[3] = (num_elements == 4) ?
+ static_cast<unsigned char>(source[swizzle[3]] * 255.0f) : 255;
+ destination += 4;
+ source += num_elements;
+ }
+ break;
+ }
+ }
+ if (!self->Unlock(level)) {
+ O3D_ERROR(self->service_locator()) << "could not unlock texture";
+ }
+ }
+ %}
+}; // Texture2D
+
+
+%[
+TextureCUBE is a class for textures used for cube mapping. A cube texture
+stores bitmaps for the 6 faces of a cube and is addressed via three texture
+coordinates.
+%]
+[include="core/cross/texture.h"] class TextureCUBE : Texture {
+ %[
+ \var CubeFace,
+ \li FACE_POSITIVE_X
+ \li FACE_NEGATIVE_X
+ \li FACE_POSITIVE_Y
+ \li FACE_NEGATIVE_Y
+ \li FACE_POSITIVE_Z
+ \li FACE_NEGATIVE_Z
+
+ The names of each of the six faces of a cube map texture.
+ %]
+ enum CubeFace { FACE_POSITIVE_X,
+ FACE_NEGATIVE_X,
+ FACE_POSITIVE_Y,
+ FACE_NEGATIVE_Y,
+ FACE_POSITIVE_Z,
+ FACE_NEGATIVE_Z };
+
+ %[
+ The length of each edge of the cube, in texels.
+ %]
+ [field_access=private, getter] int edge_length;
+
+ %[
+ Returns a RenderSurface object associated with a given cube face and
+ mip_level of a texture.
+
+ \param face The cube face from which to extract the surface.
+ \param mip_level The mip-level of the surface to be returned.
+ \param pack: The pack in which the surface will reside.
+ \return The RenderSurface object.
+ %]
+ RenderSurface? GetRenderSurface(CubeFace face, int mip_level, Pack pack);
+}; // TextureCUBE
+
+} // namespace o3d
diff --git a/o3d/plugin/idl/tick_event.idl b/o3d/plugin/idl/tick_event.idl
new file mode 100644
index 0000000..840b775
--- /dev/null
+++ b/o3d/plugin/idl/tick_event.idl
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// This file defines the public interface for the TickEvent class.
+
+namespace o3d {
+
+%[
+ This class is used to pass infomation to a registered ontick callback.
+%]
+[binding_model=by_value, include="core/cross/tick_event.h",
+ nocpp,glue_iface] class TickEvent {
+ %[
+ Use this property to get the elapsed time since the last tick event
+ seconds.
+ %]
+ [getter] float elapsed_time_;
+};
+
+} // namespace o3d
diff --git a/o3d/plugin/idl/transform.idl b/o3d/plugin/idl/transform.idl
new file mode 100644
index 0000000..da0887d
--- /dev/null
+++ b/o3d/plugin/idl/transform.idl
@@ -0,0 +1,372 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace o3d {
+
+typedef Shape[] ShapeArray;
+
+%[
+ The Transform defines parent child relationship and a localMatrix..
+ A Transform can have one or no parents and
+ an arbitrary number of children.
+%]
+[nocpp, include="core/cross/transform.h"] class Transform
+ : ParamObject {
+ %[
+ The Visibility for this transform.
+ %]
+ [getter, setter] bool visible_;
+
+ %[
+ Sets the parent of the transform by re-parenting the transform under
+ parent. Setting parent to null removes the transform and the
+ entire subtree below it from the transform graph.
+ If the operation would create a cycle it fails.
+ %]
+ [setter, userglue_setter] Transform? parent_;
+
+ %[
+ The immediate children of this Transform.
+
+ Each access to this field gets the entire list, so it is best to get it
+ just once. For example:
+ \code
+ var children = transform.children;
+ for (var i = 0; i < children.length; i++) {
+ var child = children[i];
+ }
+ \endcode
+
+ Note that modifications to this array [e.g. additions to it] will not affect
+ the underlying Transform, while modifications to the members of the array
+ <strong>will</strong> affect them.
+ %]
+ [userglue_getter, getter] TransformArray children_;
+
+ %[
+ Returns all the transforms under this transform including this one.
+
+ Note that modifications to this array [e.g. additions to it] will not affect
+ the underlying Transform, while modifications to the members of the array
+ <strong>will</strong> affect them.
+
+ \return An array containing the transforms of the subtree.
+ %]
+ TransformArray GetTransformsInTree();
+
+ %[
+ Searches for transforms that match the given name in the hierarchy under and
+ including this transform. Since there can be more than one transform with a
+ given name, results are returned in an array.
+
+ Note that modifications to this array [e.g. additions to it] will not affect
+ the underlying Transform, while modifications to the members of the array
+ <strong>will</strong> affect them.
+
+ \param name Transform name to look for.
+ \return An array containing the transforms of the under and including this
+ transform matching the given name.
+ %]
+ TransformArray GetTransformsByNameInTree(String name);
+
+ %[
+ Evaluates and returns the current world matrix.
+
+ \return The updated world matrix.
+ %]
+ Vectormath::Aos::Matrix4 GetUpdatedWorldMatrix();
+
+ %[
+ Adds a shape do this transform.
+ \param shape Shape to add.
+ %]
+ void AddShape(Shape shape);
+
+ %[
+ Removes a shape from this transform.
+ \param shape Shape to remove.
+ \return true if successful, false if shape was not in this transform.
+ %]
+ bool RemoveShape(Shape shape);
+
+ %[
+ Gets the shapes owned by this transform.
+
+ Each access to this field gets the entire list so it is best to get it
+ just once. For example:
+ \code
+ var shapes = transform.shapes;
+ for (var i = 0; i < shapes.length; i++) {
+ var shape = shapes[i];
+ }
+ \endcode
+
+ Note that modifications to this array [e.g. additions to it] will not affect
+ the underlying Transform, while modifications to the members of the array
+ <strong>will</strong> affect them.
+ %]
+ [userglue_getter, getter, userglue_setter, setter]
+ ShapeArray shapes_;
+
+ %[
+ Walks the tree of transforms starting with this transform and creates
+ draw elements. If an Element already has a DrawElement that uses material a
+ new DrawElement will not be created.
+ \param pack Pack used to manage created elements.
+ \param material Material to use for each element. If you pass null, it will
+ use the material on the element to which a draw element is being added.
+ In other words, a DrawElement will use the material of the
+ corresponding Element if material is null. This allows you to easily
+ setup the default (just draw as is) by passing null or setup a shadow
+ pass by passing in a shadow material.
+ %]
+ void CreateDrawElements(Pack pack,
+ Material? material);
+
+ %[
+ World (model) matrix as it was last computed.
+ %]
+ [getter] Vectormath::Aos::Matrix4 world_matrix;
+
+ %[
+ Local transformation matrix.
+ %]
+ [getter, setter, nocpp] Vectormath::Aos::Matrix4 local_matrix;
+
+ %[
+ The cull setting for this transform. If true this Transform will be culled
+ by having its bounding box compared to the view frustum of any draw context
+ it is used with.
+ %]
+ [getter, setter] bool cull_;
+
+ %[
+ The BoundingBox for this Transform. If culling is on this bounding box will
+ be tested against the view frustum of any draw context used to with this
+ Transform.
+ %]
+ [getter, setter] BoundingBox bounding_box_;
+
+ %[
+ Sets the local matrix of this transform to the identity matrix.
+ %]
+ [userglue] void identity();
+
+ %[
+ Pre-composes the local matrix of this Transform with a translation. For
+ example, if the local matrix is a rotation then new local matrix will
+ translate by the given vector and then rotated.
+
+ \param translation vector of 3 entries by which to translate.
+ %]
+ [userglue] void translate(Vectormath::Aos::Vector3 translation);
+
+ %[
+ Pre-composes the local matrix of this Transform with a translation. For
+ example, if the local matrix is a rotation then the new local matrix will
+ translate by the given amounts and then rotate.
+
+ \param x amount to translate in x.
+ \param y amount to translate in y.
+ \param z amount to translate in z.
+ %]
+ [userglue] void translate(float x, float y, float z);
+
+ %[
+ Pre-composes the local matrix of this Transform with a rotation about the
+ x-axis. For example, if the local matrix is a tranlsation, the new local
+ matrix will rotate around the x-axis and then translate.
+
+ \param radians The number of radians to rotate around x-axis.
+ %]
+ [userglue] void rotateX(float radians);
+
+ %[
+ Pre-composes the local matrix of this Transform with a rotation about the
+ y-axis. For example, if the local matrix is a translation, the new local
+ matrix will rotate around the y-axis and then translate.
+
+ \param radians The number of radians to rotate around y-axis.
+ %]
+ [userglue] void rotateY(float radians);
+
+ %[
+ Pre-composes the local matrix of this Transform with a rotation about the
+ z-axis. For example, if the local matrix is a translation, the new local
+ matrix will rotate around the z-axis and then translate.
+
+ \param radians The number of radians to rotate around z-axis.
+ %]
+ [userglue] void rotateZ(float radians);
+
+ %[
+ Pre-composes the local matrix of this Transform with a rotation.
+ Interprets the three entries of the given vector as angles by which to
+ rotate around the x, y and z axes. Rotates around the x-axis first,
+ then the y-axis, then the z-axis.
+
+ \param radiansXYZ A vector of angles (in radians) by which to rotate
+ around the x, y and z axes.
+ %]
+ [userglue] void rotateZYX(Vectormath::Aos::Vector3 radiansXYZ);
+
+ %[
+ Pre-composes the local matrix of this Transform with a rotation around the
+ given axis. For example, if the local matrix is a translation, the new
+ local matrix will rotate around the given axis and then translate.
+
+ \param radians The number of radians to rotate.
+ \param axis a non-zero vector representing the axis around which to rotate.
+ %]
+ [userglue] void axisRotate(Vectormath::Aos::Vector3 axis, float radians);
+
+ %[
+ Pre-composes the local matrix of this Transform with a rotation defined by
+ the given quaternion.
+
+ \param unit_quat A non-zero quaternion to be interpreted as a rotation.
+ %]
+ [userglue] void quaternionRotate(Vectormath::Aos::Quat unit_quat);
+
+ %[
+ Pre-composes the local matrix of this transform by a scaling transformation.
+ For example, if the local matrix is a rotation, the new local matrix will
+ scale and then rotate.
+
+ \param scale amount to scale.
+ %]
+ [userglue] void scale(Vectormath::Aos::Vector3 scale);
+
+ %[
+ Pre-composes the local matrix of this transform by a scaling transformation.
+ For example, if the local matrix is a rotation, the new local matrix will
+ scale and then rotate.
+
+ \param x amount to scale in the x dimension.
+ \param y amount to scale in the y dimension.
+ \param z amount to scale in the z dimension.
+ %]
+ [userglue] void scale(float x, float y, float z);
+
+ [verbatim=cpp_glue] %{
+ void userglue_setter_parent_(
+ o3d::Transform* _this,
+ o3d::Transform* parent) {
+ _this->SetParent(parent);
+ }
+ o3d::TransformArray userglue_getter_children_(
+ o3d::Transform *self) {
+ return self->GetChildren();
+ }
+ o3d::ShapeArray userglue_getter_shapes_(
+ o3d::Transform *self) {
+ return self->GetShapes();
+ }
+ void userglue_setter_shapes_(
+ o3d::Transform *self,
+ const o3d::ShapeArray& shapes) {
+ self->SetShapes(shapes);
+ }
+ void userglue_method_identity(o3d::Transform* self) {
+ self->set_local_matrix(Vectormath::Aos::Matrix4::identity());
+ }
+ void userglue_method_translate(
+ o3d::Transform* self,
+ const Vectormath::Aos::Vector3& translation) {
+ self->set_local_matrix(
+ self->local_matrix() *
+ Vectormath::Aos::Matrix4::translation(translation));
+ }
+ void userglue_method_translate(o3d::Transform* self,
+ float x,
+ float y,
+ float z) {
+ self->set_local_matrix(self->local_matrix() *
+ Vectormath::Aos::Matrix4::translation(
+ Vectormath::Aos::Vector3(x, y, z)));
+ }
+ void userglue_method_rotateX(o3d::Transform* self,
+ float radians) {
+ self->set_local_matrix(self->local_matrix() *
+ Vectormath::Aos::Matrix4::rotationX(radians));
+ }
+ void userglue_method_rotateY(o3d::Transform* self,
+ float radians) {
+ self->set_local_matrix(self->local_matrix() *
+ Vectormath::Aos::Matrix4::rotationY(radians));
+ }
+ void userglue_method_rotateZ(o3d::Transform* self,
+ float radians) {
+ self->set_local_matrix(self->local_matrix() *
+ Vectormath::Aos::Matrix4::rotationZ(radians));
+ }
+ void userglue_method_rotateZYX(o3d::Transform* self,
+ const Vectormath::Aos::Vector3& radiansXYZ) {
+ self->set_local_matrix(self->local_matrix() *
+ Vectormath::Aos::Matrix4::rotationZYX(radiansXYZ));
+ }
+ void userglue_method_axisRotate(o3d::Transform* self,
+ const Vectormath::Aos::Vector3& axis,
+ float radians) {
+ self->set_local_matrix(
+ self->local_matrix() *
+ Vectormath::Aos::Matrix4::rotation(radians,
+ Vectormath::Aos::normalize(axis)));
+ }
+ void userglue_method_quaternionRotate(o3d::Transform* self,
+ const Vectormath::Aos::Quat& quat) {
+ self->set_local_matrix(self->local_matrix() *
+ Vectormath::Aos::Matrix4::rotation(
+ Vectormath::Aos::normalize(quat)));
+ }
+ void userglue_method_scale(
+ o3d::Transform* self,
+ const Vectormath::Aos::Vector3& scale) {
+ self->set_local_matrix(self->local_matrix() *
+ Vectormath::Aos::Matrix4::scale(scale));
+ }
+ void userglue_method_scale(o3d::Transform* self,
+ float x,
+ float y,
+ float z) {
+ self->set_local_matrix(
+ self->local_matrix() *
+ Vectormath::Aos::Matrix4::scale(Vectormath::Aos::Vector3(x, y, z)));
+ }
+ %}
+}; // Transform
+
+%[
+ TransformArray is a typdef for an array of Transforms.
+%]
+typedef Transform[] TransformArray;
+
+} // namespace o3d
diff --git a/o3d/plugin/idl/tree_traversal.idl b/o3d/plugin/idl/tree_traversal.idl
new file mode 100644
index 0000000..a536f21
--- /dev/null
+++ b/o3d/plugin/idl/tree_traversal.idl
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace o3d {
+
+%[
+ A TreeTraversal has multiple DrawLists registered with it. Each DrawList has
+ a DrawContext registered with it. At render time the TreeTraversal walks the
+ transform graph from the transform it's pointing at and for each DrawElement
+ it finds who's matertial matches one of its registered DrawLists it adds that
+ DrawElement to that DrawList.
+%]
+[nocpp, include="core/cross/tree_traversal.h"] class TreeTraversal
+ : RenderNode {
+
+ %[
+ The root Transform this TreeTraversal will start traversing from.
+ %]
+ [getter, setter] Transform? transform_;
+
+ %[
+ Registers a DrawList with this TreeTraversal so that when this
+ TreeTraversal traverses its tree, DrawElements using materials that use
+ this DrawList will be added though possibly culled by the view frustum of
+ the DrawContext. Note: passing in the same DrawList more than once will
+ override the previous settings for that DrawList.
+ \param draw_list DrawList to register.
+ \param draw_context DrawContext to use with the DrawList.
+ \param reset true if you want the DrawList reset before traversing.
+ %]
+ void RegisterDrawList(DrawList draw_list,
+ DrawContext draw_context,
+ bool reset);
+
+ %[
+ Unregisters a DrawList with this TreeTraversal.
+ \param draw_list DrawList to unregister.
+ \return true if unregistered. false if this draw_list was not registered.
+ %]
+ bool UnregisterDrawList(DrawList draw_list);
+}; // TreeTraversal
+
+} // namespace o3d
diff --git a/o3d/plugin/idl/types.idl b/o3d/plugin/idl/types.idl
new file mode 100644
index 0000000..5756d9e
--- /dev/null
+++ b/o3d/plugin/idl/types.idl
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// TODO: some how make this file conditionally compile different for C++
+// vs JavaScript like with #ifdef CPLUSPLUS etc..
+[verbatim=cpp_glue,include="plugin/cross/marshaling_utils.h"]
+namespace o3d {
+
+%[
+ A data type consisting of 2 numbers. A Float2 is represented in JavaScript by
+ an array containing 2 numbers: [x, y].
+%]
+[binding_model=by_value, marshaled, nocpp, include="core/cross/types.h"]
+class Float2 {
+ [plugin_data, userglue_getter, userglue_setter, getter, setter, nodocs]
+ float[] marshaled;
+
+ [verbatim=cpp_glue] %{
+ void userglue_setter_marshaled(
+ void* plugin_data,
+ o3d::Float2* self,
+ const std::vector<float>& dynamicValue) {
+ *self = o3d::VectorToType<o3d::Float2, 2>(
+ plugin_data, dynamicValue);
+ }
+
+ std::vector<float> userglue_getter_marshaled(
+ void* plugin_data,
+ const o3d::Float2& self) {
+ return o3d::VectorFromType<o3d::Float2, 2>(self);
+ }
+ %}
+};
+
+%[
+ A data type consisting of 3 numbers. A Float3 is represented in JavaScript by
+ an array containing 3 numbers: [x, y, z].
+%]
+[binding_model=by_value, marshaled, nocpp, include="core/cross/types.h"]
+class Float3 {
+ [plugin_data, userglue_getter, userglue_setter, getter, setter, nodocs]
+ float[] marshaled;
+
+ [verbatim=cpp_glue] %{
+ void userglue_setter_marshaled(
+ void* plugin_data,
+ o3d::Float3* self,
+ const std::vector<float>& dynamicValue) {
+ *self = o3d::VectorToType<o3d::Float3, 3>(
+ plugin_data, dynamicValue);
+ }
+
+ std::vector<float> userglue_getter_marshaled(
+ void* plugin_data,
+ const o3d::Float3& self) {
+ return o3d::VectorFromType<o3d::Float3, 3>(self);
+ }
+ %}
+};
+
+%[
+ A data type consisting of 4 numbers. A Float4 is represented in JavaScript by
+ an array containing 4 numbers: [x, y, z, w].
+%]
+[binding_model=by_value, marshaled, nocpp, include="core/cross/types.h"]
+class Float4 {
+ [plugin_data, userglue_getter, userglue_setter, getter, setter, nodocs]
+ float[] marshaled;
+
+ [verbatim=cpp_glue] %{
+ void userglue_setter_marshaled(
+ void* plugin_data,
+ o3d::Float4* self,
+ const std::vector<float>& dynamicValue) {
+ *self = o3d::VectorToType<o3d::Float4, 4>(
+ plugin_data, dynamicValue);
+ }
+
+ std::vector<float> userglue_getter_marshaled(
+ void* plugin_data,
+ const o3d::Float4& self) {
+ return o3d::VectorFromType<o3d::Float4, 4>(self);
+ }
+ %}
+};
+
+%[
+ Id used to uniquely identify objects.
+%]
+[include="core/cross/types.h"] typedef int Id;
+
+%[
+ Data type for passing data around in the scenegraph.
+%]
+[include="core/cross/types.h"] typedef float Float;
+
+%[
+ Data type for passing data around in the scenegraph.
+%]
+[include="core/cross/types.h"] typedef std::string String;
+
+} // namespace o3d
diff --git a/o3d/plugin/idl/vector.idl b/o3d/plugin/idl/vector.idl
new file mode 100644
index 0000000..84dd4f1
--- /dev/null
+++ b/o3d/plugin/idl/vector.idl
@@ -0,0 +1,181 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+[include="plugin/cross/marshaling_utils.h"] %{
+%}
+
+namespace Vectormath {
+namespace Aos {
+
+[binding_model=by_value, marshaled, nocpp, include=
+ "third_party/vectormath/files/vectormathlibrary/include/vectormath/scalar/cpp/vectormath_aos.h"]
+class Vector3 {
+ [plugin_data, userglue_getter, userglue_setter, getter, setter, nodocs]
+ float[] marshaled;
+
+ [verbatim=cpp_glue] %{
+ void userglue_setter_marshaled(
+ void* plugin_data,
+ Vectormath::Aos::Vector3* self,
+ const std::vector<float>& dynamicValue) {
+ *self = o3d::VectorToType<Vectormath::Aos::Vector3, 3>(
+ plugin_data, dynamicValue);
+ }
+
+ std::vector<float> userglue_getter_marshaled(
+ void* plugin_data,
+ const Vectormath::Aos::Vector3& self) {
+ return
+ o3d::VectorFromType<Vectormath::Aos::Vector3, 3>(self);
+ }
+ %}
+};
+
+[binding_model=by_value, marshaled, nocpp, include=
+ "third_party/vectormath/files/vectormathlibrary/include/vectormath/scalar/cpp/vectormath_aos.h"]
+class Point3 {
+ [plugin_data, userglue_getter, userglue_setter, getter, setter, nodocs]
+ float[] marshaled;
+
+ [verbatim=cpp_glue] %{
+ void userglue_setter_marshaled(
+ void* plugin_data,
+ Vectormath::Aos::Point3* self,
+ const std::vector<float>& dynamicValue) {
+ *self = o3d::VectorToType<Vectormath::Aos::Point3, 3>(
+ plugin_data, dynamicValue);
+ }
+
+ std::vector<float> userglue_getter_marshaled(
+ void* plugin_data,
+ const Vectormath::Aos::Point3& self) {
+ return o3d::VectorFromType<Vectormath::Aos::Point3, 3>(self);
+ }
+ %}
+};
+
+[binding_model=by_value, marshaled, nocpp, include=
+ "third_party/vectormath/files/vectormathlibrary/include/vectormath/scalar/cpp/vectormath_aos.h"]
+class Vector4 {
+ [plugin_data, userglue_getter, userglue_setter, getter, setter, nodocs]
+ float[] marshaled;
+
+ [verbatim=cpp_glue] %{
+ void userglue_setter_marshaled(
+ void* plugin_data,
+ Vectormath::Aos::Vector4* self,
+ const std::vector<float>& dynamicValue) {
+ *self = o3d::VectorToType<Vectormath::Aos::Vector4, 4>(
+ plugin_data, dynamicValue);
+ }
+
+ std::vector<float> userglue_getter_marshaled(
+ void* plugin_data,
+ const Vectormath::Aos::Vector4& self) {
+ return
+ o3d::VectorFromType<Vectormath::Aos::Vector4, 4>(self);
+ }
+ %}
+};
+
+[binding_model=by_value, marshaled, nocpp, include=
+ "third_party/vectormath/files/vectormathlibrary/include/vectormath/scalar/cpp/vectormath_aos.h"]
+class Matrix3 {
+ [plugin_data, userglue_getter, userglue_setter, getter, setter, nodocs]
+ float[][] marshaled;
+
+ [verbatim=cpp_glue] %{
+ void userglue_setter_marshaled(
+ void* plugin_data,
+ Vectormath::Aos::Matrix3* self,
+ const std::vector<std::vector<float> >& dynamicValue) {
+ *self = o3d::VectorOfVectorToType<Vectormath::Aos::Matrix3, 3, 3>(
+ plugin_data, dynamicValue);
+ }
+
+ std::vector<std::vector<float> > userglue_getter_marshaled(
+ void* plugin_data,
+ const Vectormath::Aos::Matrix3& self) {
+ return o3d::VectorOfVectorFromType<Vectormath::Aos::Matrix3, 3, 3>(
+ self);
+ }
+ %}
+};
+
+[binding_model=by_value, marshaled, nocpp, include=
+ "third_party/vectormath/files/vectormathlibrary/include/vectormath/scalar/cpp/vectormath_aos.h"]
+class Matrix4 {
+ [plugin_data, userglue_getter, userglue_setter, getter, setter, nodocs]
+ float[][] marshaled;
+
+ [verbatim=cpp_glue] %{
+ void userglue_setter_marshaled(
+ void* plugin_data,
+ Vectormath::Aos::Matrix4* self,
+ const std::vector<std::vector<float> >& dynamicValue) {
+ *self = o3d::VectorOfVectorToType<Vectormath::Aos::Matrix4, 4, 4>(
+ plugin_data, dynamicValue);
+ }
+
+ std::vector<std::vector<float> > userglue_getter_marshaled(
+ void* plugin_data,
+ const Vectormath::Aos::Matrix4& self) {
+ return o3d::VectorOfVectorFromType<Vectormath::Aos::Matrix4, 4, 4>(
+ self);
+ }
+ %}
+};
+
+[binding_model=by_value, marshaled, nocpp, include=
+ "third_party/vectormath/files/vectormathlibrary/include/vectormath/scalar/cpp/vectormath_aos.h"]
+class Quat {
+ [plugin_data, userglue_getter, userglue_setter, getter, setter, nodocs]
+ float[] marshaled;
+
+ [verbatim=cpp_glue] %{
+ void userglue_setter_marshaled(
+ void* plugin_data,
+ Vectormath::Aos::Quat* self,
+ const std::vector<float>& dynamicValue) {
+ *self = o3d::VectorToType<Vectormath::Aos::Quat, 4>(
+ plugin_data, dynamicValue);
+ }
+
+ std::vector<float> userglue_getter_marshaled(
+ void* plugin_data,
+ const Vectormath::Aos::Quat& self) {
+ return o3d::VectorFromType<Vectormath::Aos::Quat, 4>(self);
+ }
+ %}
+};
+
+}
+}
diff --git a/o3d/plugin/idl/vertex_source.idl b/o3d/plugin/idl/vertex_source.idl
new file mode 100644
index 0000000..92cfe58
--- /dev/null
+++ b/o3d/plugin/idl/vertex_source.idl
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// This file contains the idlglue declaration of VertexSource.
+
+namespace o3d {
+
+%[
+ A VertexSource is an object that allows binding Streams such that the
+ VertexSource updates the Buffers of the Streams that have been bound to it.
+ An example of a VertexSource object is a SkinEval
+%]
+[nocpp, include="core/cross/vertex_source.h"] class VertexSource
+ : ParamObject {
+
+ %[
+ Bind the source stream to the corresponding stream in this VertexSource.
+
+ \param source Source to get vertices from.
+ \param semantic The semantic of the vertices to get
+ \param semantic_index The semantic index of the vertices to get.
+ \return True if success. False if failure. If the requested semantic or
+ semantic index do not exist on the source or this source the bind will
+ fail.
+ %]
+ bool BindStream(VertexSource source,
+ Stream::Semantic semantic,
+ int semantic_index);
+
+ %[
+ Unbinds the requested stream.
+ \param semantic The semantic of the vertices to unbind
+ \param semantic_index The semantic index of the vertices to unbind.
+ \return True if unbound. False those vertices do not exist or were not
+ bound.
+ %]
+ bool UnbindStream(Stream::Semantic semantic, int semantic_index);
+}; // VertexSource
+
+} // namespace o3d
+
diff --git a/o3d/plugin/idl/viewport.idl b/o3d/plugin/idl/viewport.idl
new file mode 100644
index 0000000..6e28be6
--- /dev/null
+++ b/o3d/plugin/idl/viewport.idl
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace o3d {
+
+%[
+ A Viewport is a render node that sets the render viewport and depth range for
+ its children. It uses an array in the format [left, top, width, height] where
+ left, top, width and height are in a 0.0 to 1.0 range that represent positions
+ and dimensions relative to the size of the client's rendering area. The depth
+ range is represented by an array in the format [min Z, max Z]. The depth range
+ provides the mapping of the clip space coordinates into normalized z buffer
+ coordinates.
+%]
+[nocpp, include="core/cross/viewport.h"] class Viewport
+ : RenderNode {
+ %[
+ The position and size to set the viewport in
+ [left, top, width, height] format. The default values
+ are (0.0, 0.0, 1.0, 1.0). In other words, the full area.
+
+ Note: These values must describe a rectangle that is 100% inside the client
+ area. In other words, (0.5, 0.0, 1.0, 1.0) would describe an area that is
+ 1/2 off right side of the screen. That is an invalid value and will be
+ clipped to (0.5, 0.0, 0.5, 1.0).
+
+ \sa Viewport
+ %]
+ [getter, setter] Float4 viewport;
+
+ %[
+ The min Z and max Z depth range in [min Z, max Z] format.
+ The default values are [0.0, 1.0].
+
+ \sa Viewport
+ %]
+ [getter, setter] Float2 depth_range;
+}; // Viewport
+
+} // namespace o3d
diff --git a/o3d/plugin/idl_list.scons b/o3d/plugin/idl_list.scons
new file mode 100644
index 0000000..45eb9d3
--- /dev/null
+++ b/o3d/plugin/idl_list.scons
@@ -0,0 +1,91 @@
+# Copyright 2009, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+O3D_IDL_SOURCES = [
+ 'idl/bounding_box.idl',
+ 'idl/buffer.idl',
+ 'idl/canvas.idl',
+ 'idl/canvas_paint.idl',
+ 'idl/canvas_shader.idl',
+ 'idl/clear_buffer.idl',
+ 'idl/client.idl',
+ 'idl/counter.idl',
+ 'idl/cursor.idl',
+ 'idl/curve.idl',
+ 'idl/display_mode.idl',
+ 'idl/draw_context.idl',
+ 'idl/draw_element.idl',
+ 'idl/draw_list.idl',
+ 'idl/draw_pass.idl',
+ 'idl/effect.idl',
+ 'idl/element.idl',
+ 'idl/event.idl',
+ 'idl/field.idl',
+ 'idl/file_request.idl',
+ 'idl/function.idl',
+ 'idl/material.idl',
+ 'idl/matrix4_axis_rotation.idl',
+ 'idl/matrix4_composition.idl',
+ 'idl/matrix4_scale.idl',
+ 'idl/matrix4_translation.idl',
+ 'idl/named.idl',
+ 'idl/pack.idl',
+ 'idl/param_array.idl',
+ 'idl/param.idl',
+ 'idl/param_object.idl',
+ 'idl/param_operation.idl',
+ 'idl/plugin.idl',
+ 'idl/primitive.idl',
+ 'idl/ray_intersection_info.idl',
+ 'idl/render_event.idl',
+ 'idl/render_node.idl',
+ 'idl/render_surface.idl',
+ 'idl/render_surface_set.idl',
+ 'idl/sampler.idl',
+ 'idl/shape.idl',
+ 'idl/skin.idl',
+ 'idl/standard_param.idl',
+ 'idl/state.idl',
+ 'idl/state_set.idl',
+ 'idl/stream.idl',
+ 'idl/stream_bank.idl',
+ 'idl/texture.idl',
+ 'idl/tick_event.idl',
+ 'idl/transform.idl',
+ 'idl/tree_traversal.idl',
+ 'idl/types.idl',
+ 'idl/vector.idl',
+ 'idl/vertex_source.idl',
+ 'idl/viewport.idl',
+ 'idl/archive_request.idl',
+ 'idl/raw_data.idl',
+]
+
+Export('O3D_IDL_SOURCES')
diff --git a/o3d/plugin/linux/config.cc b/o3d/plugin/linux/config.cc
new file mode 100644
index 0000000..ce1dca5
--- /dev/null
+++ b/o3d/plugin/linux/config.cc
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// This file contains code to check the hardware and software configuration of
+// the client machine:
+// - User agent (browser)
+// - OS version
+// - GPU vendor
+
+#include "plugin/cross/config.h"
+
+#include <iostream>
+#include <fstream>
+
+// Checks OS version
+bool CheckOSVersion(NPP npp) {
+ return true;
+}
+
+bool CheckUserAgent(NPP npp, const std::string &user_agent) {
+ // TODO: check user agent.
+ return true;
+}
+
+bool OpenDriverBlacklistFile(std::ifstream *input_file) {
+ // TODO
+ return false;
+}
+
+bool GetUserConfigMetrics() {
+ // TODO: Finish this function!
+ return true;
+}
diff --git a/o3d/plugin/linux/main_linux.cc b/o3d/plugin/linux/main_linux.cc
new file mode 100644
index 0000000..7168333
--- /dev/null
+++ b/o3d/plugin/linux/main_linux.cc
@@ -0,0 +1,522 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// This file implements the platform specific parts of the plugin for
+// the Linux platform.
+
+#include <X11/keysym.h>
+#include "base/at_exit.h"
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/scoped_ptr.h"
+#include "plugin/cross/main.h"
+#include "plugin/cross/out_of_memory.h"
+
+using glue::_o3d::PluginObject;
+using glue::StreamManager;
+using o3d::DisplayWindowLinux;
+using o3d::Event;
+
+namespace {
+// We would normally make this a stack variable in main(), but in a
+// plugin, that's not possible, so we allocate it dynamically and
+// destroy it explicitly.
+scoped_ptr<base::AtExitManager> g_at_exit_manager;
+} // end anonymous namespace
+
+static void DrawPlugin(PluginObject *obj) {
+ // TODO: this draws no matter what instead of just
+ // invalidating the region, which means it will execute even if the plug-in
+ // window is invisible. Figure out a way to prevent that, possibly going
+ // through the XEmbed extension.
+ // Limit drawing to no more than once every timer tick.
+ if (!obj->draw_) return;
+ obj->client()->RenderClient();
+ obj->draw_ = false;
+}
+
+void RenderOnDemandCallbackHandler::Run() {
+ DrawPlugin(obj_);
+}
+
+void LinuxTimer(XtPointer data, XtIntervalId* id) {
+ PluginObject *obj = static_cast<PluginObject *>(data);
+ DCHECK(obj->xt_interval_ == *id);
+ obj->client()->Tick();
+ obj->draw_ = true;
+ if (obj->client()->render_mode() == o3d::Client::RENDERMODE_CONTINUOUS) {
+ DrawPlugin(obj);
+ }
+ obj->xt_interval_ =
+ XtAppAddTimeOut(obj->xt_app_context_, 10, LinuxTimer, obj);
+}
+
+void LinuxExposeHandler(Widget w,
+ XtPointer user_data,
+ XEvent *event,
+ Boolean *cont) {
+ PluginObject *obj = static_cast<PluginObject *>(user_data);
+ if (event->type != Expose) return;
+ XExposeEvent *expose_event = &event->xexpose;
+ DrawPlugin(obj);
+}
+
+static int KeySymToDOMKeyCode(KeySym key_sym) {
+ // See https://developer.mozilla.org/en/DOM/Event/UIEvent/KeyEvent for the
+ // DOM values.
+ // X keycodes are not useful, because they describe the geometry, not the
+ // associated symbol, so a 'Q' on a QWERTY (US) keyboard has the same keycode
+ // as a 'A' on an AZERTY (french) one.
+ // Key symbols are closer to what the DOM expects, but they depend on the
+ // shift/control/alt combination - the same key has several symbols ('a' vs
+ // 'A', '1' vs '!', etc.), so we do extra work so that 'a' and 'A' both
+ // generate the same DOM keycode.
+ if ((key_sym >= XK_0 && key_sym <= XK_Z)) {
+ // DOM keycode matches ASCII value, as does the keysym.
+ return key_sym;
+ } else if ((key_sym >= XK_a && key_sym <= XK_z)) {
+ return key_sym - XK_a + XK_A;
+ } else if ((key_sym >= XK_KP_0 && key_sym <= XK_KP_9)) {
+ return 0x60 + key_sym - XK_KP_0;
+ } else if ((key_sym >= XK_F1 && key_sym <= XK_F24)) {
+ return 0x70 + key_sym - XK_F1;
+ }
+ switch (key_sym) {
+ case XK_Cancel:
+ return 0x03;
+ case XK_Help:
+ return 0x06;
+ case XK_BackSpace:
+ return 0x08;
+ case XK_Tab:
+ return 0x09;
+ case XK_Clear:
+ return 0x0C;
+ case XK_Return:
+ return 0x0D;
+ case XK_KP_Enter:
+ return 0x0E;
+ case XK_Shift_L:
+ case XK_Shift_R:
+ return 0x10;
+ case XK_Control_L:
+ case XK_Control_R:
+ return 0x11;
+ case XK_Alt_L:
+ case XK_Alt_R:
+ return 0x12;
+ case XK_Pause:
+ return 0x13;
+ case XK_Caps_Lock:
+ return 0x14;
+ case XK_Escape:
+ return 0x1B;
+ case XK_space:
+ return 0x20;
+ case XK_Page_Up:
+ case XK_KP_Page_Up:
+ return 0x21;
+ case XK_Page_Down:
+ case XK_KP_Page_Down:
+ return 0x22;
+ case XK_End:
+ case XK_KP_End:
+ return 0x23;
+ case XK_Home:
+ case XK_KP_Home:
+ return 0x24;
+ case XK_Left:
+ case XK_KP_Left:
+ return 0x25;
+ case XK_Up:
+ case XK_KP_Up:
+ return 0x26;
+ case XK_Right:
+ case XK_KP_Right:
+ return 0x27;
+ case XK_Down:
+ case XK_KP_Down:
+ return 0x28;
+ case XK_Print:
+ return 0x2C;
+ case XK_Insert:
+ case XK_KP_Insert:
+ return 0x2D;
+ case XK_Delete:
+ case XK_KP_Delete:
+ return 0x2E;
+ case XK_Menu:
+ return 0x5D;
+ case XK_asterisk:
+ case XK_KP_Multiply:
+ return 0x6A;
+ case XK_plus:
+ case XK_KP_Add:
+ return 0x6B;
+ case XK_underscore:
+ return 0x6C;
+ case XK_minus:
+ case XK_KP_Subtract:
+ return 0x6E;
+ case XK_KP_Decimal:
+ return 0x6E;
+ case XK_KP_Divide:
+ return 0x6F;
+ case XK_Num_Lock:
+ return 0x90;
+ case XK_Scroll_Lock:
+ return 0x91;
+ case XK_comma:
+ return 0xBC;
+ case XK_period:
+ return 0xBE;
+ case XK_slash:
+ return 0xBF;
+ case XK_grave:
+ return 0xC0;
+ case XK_bracketleft:
+ return 0xDB;
+ case XK_backslash:
+ return 0xDC;
+ case XK_bracketright:
+ return 0xDD;
+ case XK_apostrophe:
+ return 0xDE;
+ case XK_Meta_L:
+ case XK_Meta_R:
+ return 0xE0;
+ default:
+ return 0;
+ }
+}
+
+static int GetModifierState(int x_state) {
+ int modifier_state = 0;
+ if (x_state & ControlMask) {
+ modifier_state |= Event::MODIFIER_CTRL;
+ }
+ if (x_state & ShiftMask) {
+ modifier_state |= Event::MODIFIER_SHIFT;
+ }
+ if (x_state & Mod1Mask) {
+ modifier_state |= Event::MODIFIER_ALT;
+ }
+ if (x_state & Mod2Mask) {
+ modifier_state |= Event::MODIFIER_META;
+ }
+ return modifier_state;
+}
+
+void LinuxKeyHandler(Widget w,
+ XtPointer user_data,
+ XEvent *xevent,
+ Boolean *cont) {
+ PluginObject *obj = static_cast<PluginObject *>(user_data);
+ XKeyEvent *key_event = &xevent->xkey;
+ Event::Type type;
+ switch (xevent->type) {
+ case KeyPress:
+ type = Event::TYPE_KEYDOWN;
+ break;
+ case KeyRelease:
+ type = Event::TYPE_KEYUP;
+ break;
+ default:
+ return;
+ }
+ Event event(type);
+ char char_code = 0;
+ KeySym key_sym;
+ int result = XLookupString(key_event, &char_code, sizeof(char_code),
+ &key_sym, NULL);
+ event.set_key_code(KeySymToDOMKeyCode(key_sym));
+ int modifier_state = GetModifierState(key_event->state);
+ event.set_modifier_state(modifier_state);
+ obj->client()->AddEventToQueue(event);
+ if (xevent->type == KeyPress && result > 0) {
+ event.clear_key_code();
+ event.set_char_code(char_code);
+ event.set_type(Event::TYPE_KEYPRESS);
+ obj->client()->AddEventToQueue(event);
+ }
+}
+
+// TODO: Any way to query the system for the correct value ?
+const unsigned int kDoubleClickTime = 300; // in ms
+
+void LinuxMouseButtonHandler(Widget w,
+ XtPointer user_data,
+ XEvent *xevent,
+ Boolean *cont) {
+ PluginObject *obj = static_cast<PluginObject *>(user_data);
+ XButtonEvent *button_event = &xevent->xbutton;
+ Event::Type type;
+ switch (xevent->type) {
+ case ButtonPress:
+ type = Event::TYPE_MOUSEDOWN;
+ break;
+ case ButtonRelease:
+ type = Event::TYPE_MOUSEUP;
+ break;
+ default:
+ return;
+ }
+ Event event(type);
+ switch (button_event->button) {
+ case 1:
+ event.set_button(Event::BUTTON_LEFT);
+ break;
+ case 2:
+ event.set_button(Event::BUTTON_MIDDLE);
+ break;
+ case 3:
+ event.set_button(Event::BUTTON_RIGHT);
+ break;
+ case 4:
+ case 5:
+ // Mouse wheel. 4 is up, 5 is down. Reported by X as Press/Release.
+ // Ignore the Press, report the Release as the wheel event.
+ if (xevent->type == ButtonPress)
+ return;
+ event.set_type(Event::TYPE_WHEEL);
+ event.set_delta(0, (button_event->button == 4) ? 1 : -1);
+ break;
+ default:
+ return;
+ }
+ int modifier_state = GetModifierState(button_event->state);
+ event.set_modifier_state(modifier_state);
+ event.set_position(button_event->x, button_event->y,
+ button_event->x_root, button_event->y_root,
+ obj->in_plugin());
+ obj->client()->AddEventToQueue(event);
+ if (event.type() == Event::TYPE_MOUSEUP && obj->in_plugin()) {
+ event.set_type(Event::TYPE_CLICK);
+ obj->client()->AddEventToQueue(event);
+ if (button_event->time < obj->last_click_time() + kDoubleClickTime) {
+ obj->set_last_click_time(0);
+ event.set_type(Event::TYPE_DBLCLICK);
+ } else {
+ obj->set_last_click_time(button_event->time);
+ }
+ }
+}
+
+void LinuxMouseMoveHandler(Widget w,
+ XtPointer user_data,
+ XEvent *xevent,
+ Boolean *cont) {
+ PluginObject *obj = static_cast<PluginObject *>(user_data);
+ if (xevent->type != MotionNotify)
+ return;
+ XMotionEvent *motion_event = &xevent->xmotion;
+ Event event(Event::TYPE_MOUSEMOVE);
+ int modifier_state = GetModifierState(motion_event->state);
+ event.set_modifier_state(modifier_state);
+ event.set_position(motion_event->x, motion_event->y,
+ motion_event->x_root, motion_event->y_root,
+ obj->in_plugin());
+ obj->client()->AddEventToQueue(event);
+}
+
+void LinuxEnterLeaveHandler(Widget w,
+ XtPointer user_data,
+ XEvent *xevent,
+ Boolean *cont) {
+ PluginObject *obj = static_cast<PluginObject *>(user_data);
+ switch (xevent->type) {
+ case EnterNotify:
+ obj->set_in_plugin(true);
+ break;
+ case LeaveNotify:
+ obj->set_in_plugin(false);
+ break;
+ default:
+ return;
+ }
+}
+
+// TODO: Where should this really live? It's platform-specific, but in
+// PluginObject, which mainly lives in cross/o3d_glue.h+cc.
+bool PluginObject::RequestFullscreenDisplay() {
+#ifndef NDEBUG // TODO: Remove after user-prompt feature goes in.
+#endif
+ return false;
+}
+
+void PluginObject::CancelFullscreenDisplay() {
+#ifndef NDEBUG // TODO: Remove after user-prompt feature goes in.
+#endif
+}
+
+extern "C" {
+ NPError InitializePlugin() {
+ if (!o3d::SetupOutOfMemoryHandler())
+ return NPERR_MODULE_LOAD_FAILED_ERROR;
+
+ // Initialize the AtExitManager so that base singletons can be
+ // destroyed properly.
+ g_at_exit_manager.reset(new base::AtExitManager());
+
+ CommandLine::Init(0, NULL);
+ InitLogging("debug.log",
+ logging::LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG,
+ logging::DONT_LOCK_LOG_FILE,
+ logging::APPEND_TO_OLD_LOG_FILE);
+
+ DLOG(INFO) << "NP_Initialize";
+
+ return NPERR_NO_ERROR;
+ }
+
+ NPError OSCALL NP_Initialize(NPNetscapeFuncs *browserFuncs,
+ NPPluginFuncs *pluginFuncs) {
+ NPError retval = InitializeNPNApi(browserFuncs);
+ if (retval != NPERR_NO_ERROR) return retval;
+ NP_GetEntryPoints(pluginFuncs);
+ return InitializePlugin();
+ }
+
+ NPError OSCALL NP_Shutdown(void) {
+ HANDLE_CRASHES;
+ DLOG(INFO) << "NP_Shutdown";
+
+ CommandLine::Terminate();
+
+ // Force all base singletons to be destroyed.
+ g_at_exit_manager.reset(NULL);
+
+ return NPERR_NO_ERROR;
+ }
+
+ NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc,
+ char *argn[], char *argv[], NPSavedData *saved) {
+ HANDLE_CRASHES;
+
+ PluginObject* pluginObject = glue::_o3d::PluginObject::Create(
+ instance);
+ instance->pdata = pluginObject;
+ glue::_o3d::InitializeGlue(instance);
+ pluginObject->Init(argc, argn, argv);
+
+ // Get the metrics for the system setup
+ GetUserConfigMetrics();
+ return NPERR_NO_ERROR;
+ }
+
+ NPError NPP_Destroy(NPP instance, NPSavedData **save) {
+ HANDLE_CRASHES;
+ PluginObject *obj = static_cast<PluginObject*>(instance->pdata);
+ if (obj) {
+ if (obj->xt_widget_) {
+ // NOTE: This crashes. Not sure why, possibly the widget has
+ // already been destroyed, but we haven't received a SetWindow(NULL).
+ // XtRemoveEventHandler(obj->xt_widget_, ExposureMask, False,
+ // LinuxExposeHandler, obj);
+ obj->xt_widget_ = NULL;
+ }
+ if (obj->xt_interval_) {
+ XtRemoveTimeOut(obj->xt_interval_);
+ obj->xt_interval_ = 0;
+ }
+ obj->window_ = 0;
+ obj->display_ = NULL;
+
+ obj->TearDown();
+ NPN_ReleaseObject(obj);
+ instance->pdata = NULL;
+ }
+
+ return NPERR_NO_ERROR;
+ }
+
+
+ NPError NPP_SetWindow(NPP instance, NPWindow *window) {
+ HANDLE_CRASHES;
+ PluginObject *obj = static_cast<PluginObject*>(instance->pdata);
+
+ NPSetWindowCallbackStruct *cb_struct =
+ static_cast<NPSetWindowCallbackStruct *>(window->ws_info);
+ Window xwindow = reinterpret_cast<Window>(window->window);
+ if (xwindow != obj->window_) {
+ Display *display = cb_struct->display;
+ Widget widget = XtWindowToWidget(display, xwindow);
+ if (!widget) {
+ DLOG(ERROR) << "window is not a Widget";
+ return NPERR_MODULE_LOAD_FAILED_ERROR;
+ }
+
+ // Create and assign the graphics context.
+ o3d::DisplayWindowLinux default_display;
+ default_display.set_display(display);
+ default_display.set_window(xwindow);
+
+ obj->CreateRenderer(default_display);
+ obj->client()->Init();
+ obj->client()->SetRenderOnDemandCallback(
+ new RenderOnDemandCallbackHandler(obj));
+ obj->display_ = display;
+ obj->window_ = xwindow;
+ obj->xt_widget_ = widget;
+ XtAddEventHandler(widget, ExposureMask, 0, LinuxExposeHandler, obj);
+ XtAddEventHandler(widget, KeyPressMask|KeyReleaseMask, 0,
+ LinuxKeyHandler, obj);
+ XtAddEventHandler(widget, ButtonPressMask|ButtonReleaseMask, 0,
+ LinuxMouseButtonHandler, obj);
+ XtAddEventHandler(widget, PointerMotionMask, 0,
+ LinuxMouseMoveHandler, obj);
+ XtAddEventHandler(widget, EnterWindowMask|LeaveWindowMask, 0,
+ LinuxEnterLeaveHandler, obj);
+ obj->xt_app_context_ = XtWidgetToApplicationContext(widget);
+ obj->xt_interval_ =
+ XtAppAddTimeOut(obj->xt_app_context_, 10, LinuxTimer, obj);
+ }
+ obj->Resize(window->width, window->height);
+
+ return NPERR_NO_ERROR;
+ }
+
+ // Called when the browser has finished attempting to stream data to
+ // a file as requested. If fname == NULL the attempt was not successful.
+ void NPP_StreamAsFile(NPP instance, NPStream *stream, const char *fname) {
+ HANDLE_CRASHES;
+ PluginObject *obj = static_cast<PluginObject*>(instance->pdata);
+ StreamManager *stream_manager = obj->stream_manager();
+
+ stream_manager->SetStreamFile(stream, fname);
+ }
+
+ int16 NPP_HandleEvent(NPP instance, void *event) {
+ HANDLE_CRASHES;
+ return 0;
+ }
+}; // end extern "C"
diff --git a/o3d/plugin/mac/Info.plist b/o3d/plugin/mac/Info.plist
new file mode 100644
index 0000000..78ae8e6
--- /dev/null
+++ b/o3d/plugin/mac/Info.plist
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleName</key>
+ <string>O3D Plugin</string>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleExecutable</key>
+ <string>o3d</string>
+ <key>CFBundleIconFile</key>
+ <string></string>
+ <key>CFBundleIdentifier</key>
+ <string>com.google.o3d</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundlePackageType</key>
+ <string>BRPL</string>
+ <key>CFBundleSignature</key>
+ <string>TEST</string>
+ <key>CFBundleVersion</key>
+ <string>@@@ProductVersion@@@</string>
+ <key>CFBundleShortVersionString</key>
+ <string>@@@ProductVersion@@@</string>
+ <key>CCFBundleGetInfoString</key>
+ <string>"Version @@@ProductVersion@@@, Copyright 2009, Google Inc."</string>
+ <key>CSResourcesFileMapped</key>
+ <true/>
+ <key>WebPluginDescription</key>
+ <string>@@@PluginDescription@@@</string>
+ <key>WebPluginMIMETypes</key>
+ <dict>
+ <key>@@@PluginMimeType@@@</key>
+ <dict>
+ <key>WebPluginTypeDescription</key>
+ <string>@@@PluginName@@@ Type</string>
+ </dict>
+ </dict>
+ <key>WebPluginName</key>
+ <string>@@@PluginName@@@</string>
+
+ <key>BreakpadProduct</key>
+ <string>O3D</string>
+ <key>BreakpadProductDisplay</key>
+ <string>O3D browser plugin</string>
+ <key>BreakpadVendor</key>
+ <string>Google</string>
+ <key>BreakpadVersion</key>
+ <string>@@@ProductVersion@@@ (mac)</string>
+ <key>BreakpadSendAndExit</key>
+ <string>1</string>
+ <key>BreakpadReportInterval</key>
+ <string>3600</string>
+ <key>BreakpadURL</key>
+ <string>https://clients2.google.com/cr</string>
+
+</dict>
+</plist>
diff --git a/o3d/plugin/mac/Resources/English.lproj/InfoPlist.strings b/o3d/plugin/mac/Resources/English.lproj/InfoPlist.strings
new file mode 100644
index 0000000..5cfd33d
--- /dev/null
+++ b/o3d/plugin/mac/Resources/English.lproj/InfoPlist.strings
@@ -0,0 +1,10 @@
+/*
+ File: InfoPlist.strings
+
+ Description:Finder Bundle Information
+
+ Localized versions of Info.plist keys */
+
+CFBundleName = "O3D Plugin";
+
+NSHumanReadableCopyright = "Copyright 2009, Google, Inc.";
diff --git a/o3d/plugin/mac/Tools/fix_install_names.sh b/o3d/plugin/mac/Tools/fix_install_names.sh
new file mode 100644
index 0000000..aae5c56
--- /dev/null
+++ b/o3d/plugin/mac/Tools/fix_install_names.sh
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+# Since the web-plugin is not the main executable, we need to change
+# the @executable_path reference to @loader_path for our embedded frameworks
+#
+
+# First take care of Breakpad.framework
+/usr/bin/install_name_tool -change \
+ @executable_path/../Frameworks/Breakpad.framework/Versions/A/Breakpad \
+ @loader_path/../Frameworks/Breakpad.framework/Versions/A/Breakpad \
+ "$1"
+
+# Cg.framework
+/usr/bin/install_name_tool -change \
+ @executable_path/../Library/Frameworks/Cg.framework/Cg \
+ @loader_path/../Frameworks/Cg.framework/Cg \
+ "$1"
diff --git a/o3d/plugin/mac/config_mac.mm b/o3d/plugin/mac/config_mac.mm
new file mode 100644
index 0000000..e5673b8
--- /dev/null
+++ b/o3d/plugin/mac/config_mac.mm
@@ -0,0 +1,330 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// This file contains code to check the hardware and software configuration of
+// the client machine:
+// - User agent (browser)
+// - OS version
+// - GPU vendor
+
+#include <IOKit/IOKitLib.h>
+
+#include <iostream>
+#include <fstream>
+
+#include "plugin/cross/config.h"
+#include "plugin/cross/plugin_metrics.h"
+#include "plugin_mac.h"
+
+
+// Trivial little functions to check for the OS version boundaries we care about
+// and keep the result cached so they are cheap to call repeatedly.
+
+
+// Returns whether OS is 10.4 (Tiger) or higher.
+static bool IsMacOSTenFourOrHigher() {
+ static bool isCached = false, result = false;
+ if (!isCached) {
+ SInt32 major = 0, minor = 0;
+ // These selectors don't exist pre 10.4 but as we check the error
+ // the function will correctly return NO which is the right answer.
+ result = ((Gestalt(gestaltSystemVersionMajor, &major) == noErr) &&
+ (Gestalt(gestaltSystemVersionMinor, &minor) == noErr) &&
+ ((major > 10) || (major == 10 && minor >= 4)));
+ isCached = true;
+ }
+ return result;
+}
+
+
+// Checks OS version
+bool CheckOSVersion(NPP npp) {
+ // TODO: turn this back on when ready.
+ if (!IsMacOSTenFourOrHigher()) {
+ std::string error =
+ std::string("Unsupported Mac OS X version. 10.4 is required.");
+ return AskUser(npp, error);
+ }
+ return true;
+}
+
+bool CheckUserAgent(NPP npp, const std::string &user_agent) {
+ return true;
+}
+
+bool OpenDriverBlacklistFile(std::ifstream *input_file) {
+ // TODO:
+ return false;
+}
+
+
+static CFTypeRef SearchPortForProperty(io_registry_entry_t dspPort,
+ CFStringRef propertyName) {
+ return IORegistryEntrySearchCFProperty(dspPort,
+ kIOServicePlane,
+ propertyName,
+ kCFAllocatorDefault,
+ kIORegistryIterateRecursively |
+ kIORegistryIterateParents);
+}
+
+
+static void CFReleaseIf(CFTypeRef d) {
+ if (d)
+ CFRelease(d);
+}
+
+
+static UInt32 IntValueOfCFData(CFDataRef d) {
+ UInt32 value = 0;
+
+ if (d) {
+ const UInt32 *vp = reinterpret_cast<const UInt32*>(CFDataGetBytePtr(d));
+ if (vp != NULL)
+ value = *vp;
+ }
+
+ return value;
+}
+
+
+static int IntValueOfCFNumber(CFNumberRef n) {
+ int value = 0;
+
+ if ((n != NULL) && (CFGetTypeID(n) == CFNumberGetTypeID()))
+ CFNumberGetValue(n, kCFNumberSInt32Type, &value);
+
+ return value;
+}
+
+
+static void GetVideoCardInfo(CGDirectDisplayID displayID,
+ int *vendorID,
+ int *deviceID,
+ int *vramSize) {
+ io_registry_entry_t dspPort = CGDisplayIOServicePort(displayID);
+
+ CFTypeRef vendorIDRef = SearchPortForProperty(dspPort, CFSTR("vendor-id"));
+ if (vendorID) *vendorID = IntValueOfCFData((CFDataRef)vendorIDRef);
+
+ CFTypeRef deviceIDRef = SearchPortForProperty(dspPort, CFSTR("device-id"));
+ if (deviceID) *deviceID = IntValueOfCFData((CFDataRef)deviceIDRef);
+
+ CFTypeRef typeCodeRef = SearchPortForProperty(dspPort,
+ CFSTR(kIOFBMemorySizeKey));
+ if (vramSize) *vramSize = IntValueOfCFNumber((CFNumberRef)typeCodeRef);
+
+ CFReleaseIf(vendorIDRef);
+ CFReleaseIf(deviceIDRef);
+ CFReleaseIf(typeCodeRef);
+}
+
+struct GPUInfo {
+ int vendorID;
+ int deviceID;
+};
+
+// A list of GPUs which we know will not work well in o3d
+// We want to fallback to using the software render for these
+GPUInfo softwareRenderList[] = {
+ {0x8086, 0x2a02}, // Intel GMA X3100 Macbook
+ {0x8086, 0x27a2} // Intel GMA 950 Mac Mini
+};
+
+bool UseSoftwareRenderer() {
+ static bool use_software_renderer = false;
+ static bool is_initialized = false;
+
+ if (!is_initialized) {
+ int vendorID;
+ int deviceID;
+ GetVideoCardInfo(kCGDirectMainDisplay,
+ &vendorID,
+ &deviceID,
+ NULL);
+
+ use_software_renderer = false;
+ for (int i = 0; i < arraysize(softwareRenderList); ++i) {
+ GPUInfo &softwareRenderInfo = softwareRenderList[i];
+ if (vendorID == softwareRenderInfo.vendorID
+ && deviceID == softwareRenderInfo.deviceID) {
+ use_software_renderer = true;
+ break;
+ }
+ }
+ is_initialized = true;
+ }
+
+ return use_software_renderer;
+}
+
+static bool GetVideoCardMetrics(CGDirectDisplayID displayID) {
+ int vendorID;
+ int deviceID;
+ int vramSize;
+ GetVideoCardInfo(displayID,
+ &vendorID,
+ &deviceID,
+ &vramSize);
+
+ o3d::metric_gpu_vendor_id = vendorID;
+ o3d::metric_gpu_device_id = deviceID;
+ o3d::metric_gpu_vram_size = vramSize;
+
+ return true;
+}
+
+
+// Return a pointer to the last character with value c in string s.
+// Returns NULL if c is not found.
+static char* FindLastChar(char *s, char c) {
+ char *s_found = NULL;
+
+ while (*s != '\0') {
+ if (*s == c)
+ s_found = s;
+ s++;
+ }
+
+ return s_found;
+}
+
+
+bool GetOpenGLMetrics() {
+ char *gl_version_string = (char*)glGetString(GL_VERSION);
+ char *gl_extensions_string = (char*)glGetString(GL_EXTENSIONS);
+
+ if ((gl_version_string == NULL) || (gl_extensions_string == NULL))
+ return false;
+
+ // Get the OpenGL version from the start of the string.
+ int gl_major = 0, gl_minor = 0;
+ sscanf(gl_version_string, "%u.%u", &gl_major, &gl_minor);
+ o3d::metric_gl_major_version = gl_major;
+ o3d::metric_gl_minor_version = gl_minor;
+
+ // Get the OpenGL driver version.
+ // This bit is Mac specific - Mac OpenGL drivers have the driver version
+ // at the end of the gl version string preceded by a dash.
+ char *s = FindLastChar(gl_version_string, '-');
+ if (s) {
+ char *driver_string = s + 1; // skip '-'
+ int driver_major = 0, driver_minor = 0, driver_bugfix = 0;
+ sscanf(driver_string, "%u.%u.%u",
+ &driver_major, &driver_minor, &driver_bugfix);
+ o3d::metric_gpu_driver_major_version = driver_major;
+ o3d::metric_gpu_driver_minor_version = driver_minor;
+ o3d::metric_gpu_driver_bugfix_version = driver_bugfix;
+ }
+
+ // Get the HLSL version.
+ // On OpenGL 1.x it's 1.0 if the GL_ARB_shading_language_100 extension is
+ // present.
+ // On OpenGL 2.x it's a matter of getting the GL_SHADING_LANGUAGE_VERSION
+ // string.
+ int gl_hlsl_major = 0, gl_hlsl_minor = 0;
+ if ((gl_major == 1) &&
+ strstr(gl_extensions_string, "GL_ARB_shading_language_100")) {
+ gl_hlsl_major = 1;
+ gl_hlsl_minor = 0;
+ } else if (gl_major >= 2) {
+ char* glsl_version_string = (char*)glGetString(GL_SHADING_LANGUAGE_VERSION);
+ if (glsl_version_string) {
+ sscanf(glsl_version_string, "%u.%u", &gl_hlsl_major, &gl_hlsl_minor);
+ }
+ }
+ o3d::metric_gl_hlsl_major_version = gl_hlsl_major;
+ o3d::metric_gl_hlsl_minor_version = gl_hlsl_minor;
+
+ return true;
+}
+
+
+bool GetUserConfigMetrics() {
+ // Check Mac version.
+ o3d::metric_system_type = o3d::SYSTEM_NAME_MAC;
+
+ SInt32 major = 0, minor = 0, bugfix = 0;
+
+ Gestalt(gestaltSystemVersionMajor, &major);
+ Gestalt(gestaltSystemVersionMinor, &minor);
+ Gestalt(gestaltSystemVersionBugFix, &bugfix);
+
+ o3d::metric_mac_major_version = major; // eg 10
+ o3d::metric_mac_minor_version = minor; // eg 5
+ o3d::metric_mac_bugfix_version = bugfix; // eg 6
+
+ o3d::metric_direct3d_available.Set(false);
+
+ GetVideoCardMetrics(kCGDirectMainDisplay);
+
+ return true;
+}
+
+
+bool GetUserAgentMetrics(NPP npp) {
+ // Check User agent so we can get the browser
+ // TODO: This is the best we could come up with for this in order to
+ // go from browser to string.
+ GLUE_PROFILE_START(npp, "uagent");
+ std::string user_agent = NPN_UserAgent(npp);
+ GLUE_PROFILE_STOP(npp, "uagent");
+ // The Chrome user_agent string also contains Safari. Search for Chrome first.
+ if (std::string::npos != user_agent.find("Chrome")) {
+ o3d::metric_browser_type = o3d::BROWSER_NAME_CHROME;
+ // The OmniWeb user_agent also contains Safari. Search for OminWeb first.
+ } else if (std::string::npos != user_agent.find("OmniWeb")) {
+ o3d::metric_browser_type = o3d::BROWSER_NAME_OMNIWEB;
+ // now we can safely look for Safari
+ } else if (std::string::npos != user_agent.find("Safari")) {
+ o3d::metric_browser_type = o3d::BROWSER_NAME_SAFARI;
+ } else if (std::string::npos != user_agent.find("Opera")) {
+ o3d::metric_browser_type = o3d::BROWSER_NAME_OPERA;
+ } else if (std::string::npos != user_agent.find("Firefox")) {
+ o3d::metric_browser_type = o3d::BROWSER_NAME_FIREFOX;
+ } else if (std::string::npos != user_agent.find("MSIE")) {
+ o3d::metric_browser_type = o3d::BROWSER_NAME_MSIE;
+ } else if (std::string::npos != user_agent.find("Camino")) {
+ o3d::metric_browser_type = o3d::BROWSER_NAME_CAMINO;
+ } else {
+ o3d::metric_browser_type = o3d::BROWSER_NAME_UNKNOWN;
+ }
+
+ int browser_major = 0, browser_minor = 0, browser_bugfix = 0;
+ if (GetBrowserVersionInfo(&browser_major, &browser_minor, &browser_bugfix)) {
+ o3d::metric_browser_major_version = browser_major;
+ o3d::metric_browser_minor_version = browser_minor;
+ o3d::metric_browser_bugfix_version = browser_bugfix;
+ }
+
+ return true;
+}
diff --git a/o3d/plugin/mac/main_mac.mm b/o3d/plugin/mac/main_mac.mm
new file mode 100644
index 0000000..4e94929
--- /dev/null
+++ b/o3d/plugin/mac/main_mac.mm
@@ -0,0 +1,1114 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// This file implements the platform specific parts of the plugin for
+// the Macintosh platform.
+
+#include "plugin/cross/main.h"
+
+#include "base/at_exit.h"
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/scoped_ptr.h"
+
+#import <Cocoa/Cocoa.h>
+#include <Carbon/Carbon.h>
+#include <OpenGL/OpenGL.h>
+#include <AGL/agl.h>
+#include <AGL/aglRenderers.h>
+
+#include "core/cross/event.h"
+#include "statsreport/metrics.h"
+#include "plugin/cross/plugin_logging.h"
+#include "plugin/cross/plugin_metrics.h"
+#include "plugin/cross/out_of_memory.h"
+#include "plugin/mac/plugin_mac.h"
+
+o3d::PluginLogging* g_logger = NULL;
+bool g_logging_initialized = false;
+
+using glue::_o3d::PluginObject;
+using glue::StreamManager;
+using o3d::DisplayWindowMac;
+using o3d::Event;
+
+namespace {
+// We would normally make this a stack variable in main(), but in a
+// plugin, that's not possible, so we allocate it dynamically and
+// destroy it explicitly.
+scoped_ptr<base::AtExitManager> g_at_exit_manager;
+} // end anonymous namespace
+
+// if defined, in AGL mode we do double buffered drawing
+// #define USE_AGL_DOUBLE_BUFFER
+
+#define CFTIMER
+// #define DEFERRED_DRAW_ON_NULLEVENTS
+
+// currently drawing with the timer doesn't play well with USE_AGL_DOUBLE_BUFFER
+#ifdef CFTIMER
+#undef USE_AGL_DOUBLE_BUFFER
+#endif
+
+static void DrawPlugin(PluginObject* obj) {
+ obj->client()->RenderClient();
+#ifdef USE_AGL_DOUBLE_BUFFER
+ // In AGL mode, we have to call aglSwapBuffers to guarantee that our
+ // pixels make it to the screen.
+ if (obj->mac_agl_context_ != NULL)
+ aglSwapBuffers(obj->mac_agl_context_);
+#endif
+}
+
+void RenderOnDemandCallbackHandler::Run() {
+ obj_->SetWantsRedraw(true);
+}
+
+// Cocoa key events for things like arrow key presses can have strange unicode
+// values in the 0xF700-0xF747 range, eg NSUpArrowFunctionKey is 0xF700.
+// These values are defined in NSEvent.h.
+// Map the ones we care about to the more commonly understood values in
+// the Mac system header Events.h, eg kUpArrowCharCode is 30.
+static int TranslateMacUnicodeControlChar(int theChar) {
+ switch(theChar) {
+ case NSUpArrowFunctionKey:
+ return kUpArrowCharCode;
+ case NSDownArrowFunctionKey:
+ return kDownArrowCharCode;
+ case NSLeftArrowFunctionKey:
+ return kLeftArrowCharCode;
+ case NSRightArrowFunctionKey:
+ return kRightArrowCharCode;
+ }
+ return theChar;
+}
+
+
+// The Mac standard char codes for arrow keys are different from the
+// web standard.
+// Also in the browser world the enter key gets mapped to be the same as the
+// return key.
+static int TranslateMacControlCharToWebChar(int theChar) {
+ switch(theChar) {
+ case kUpArrowCharCode:
+ return 38;
+ case kDownArrowCharCode:
+ return 40;
+ case kLeftArrowCharCode:
+ return 37;
+ case kRightArrowCharCode:
+ return 39;
+ case kEnterCharCode:
+ return kReturnCharCode;
+ }
+ return theChar;
+}
+
+
+// Given an instance, and some event data, calls Javascript methods
+// placed on the object tag so that the keystrokes can be handled in
+// Javascript.
+static void DispatchKeyboardEvent(PluginObject* obj,
+ EventKind kind,
+ int theChar,
+ int theKeyCode,
+ EventModifiers mods) {
+ theChar = TranslateMacUnicodeControlChar(theChar);
+ theChar = TranslateMacControlCharToWebChar(theChar);
+ int upperChar = (theChar >= 'a' && theChar <='z') ? theChar - 32 : theChar;
+
+ Event::Type type;
+ switch (kind) {
+ case keyDown:
+ // We'll also have to send a keypress below.
+ type = Event::TYPE_KEYDOWN;
+ break;
+ case autoKey:
+ type = Event::TYPE_KEYPRESS;
+ break;
+ case keyUp:
+ type = Event::TYPE_KEYUP;
+ break;
+ }
+ Event event(type);
+
+ switch (kind) {
+ case keyDown:
+ case keyUp:
+ event.set_key_code(upperChar);
+ break;
+ case autoKey:
+ event.set_char_code(theChar);
+ break;
+ default:
+ LOG(FATAL) << "Unknown keyboard event: " << kind;
+ }
+
+ int modifier_state = 0;
+ if (mods & controlKey) {
+ modifier_state |= Event::MODIFIER_CTRL;
+ }
+ if (mods & shiftKey) {
+ modifier_state |= Event::MODIFIER_SHIFT;
+ }
+ if (mods & optionKey) {
+ modifier_state |= Event::MODIFIER_ALT;
+ }
+ if (mods & cmdKey) {
+ modifier_state |= Event::MODIFIER_META;
+ }
+ event.set_modifier_state(modifier_state);
+ obj->client()->AddEventToQueue(event);
+ if (type == Event::TYPE_KEYDOWN) {
+ event.clear_key_code();
+ event.set_char_code(theChar);
+ event.set_type(Event::TYPE_KEYPRESS);
+ obj->client()->AddEventToQueue(event);
+ }
+}
+
+// Given an instance, and a MacOS keyboard event, calls Javascript methods
+// placed on the object tag so that the keystrokes can be handled in
+// Javascript.
+static void DispatchMacKeyboardEvent(PluginObject* obj,
+ EventRecord* the_event) {
+ unsigned char theKeyCode = (the_event->message & keyCodeMask) >> 8;
+
+ DispatchKeyboardEvent(obj,
+ the_event->what,
+ the_event->message & charCodeMask,
+ theKeyCode,
+ the_event->modifiers);
+}
+
+
+
+static void HandleMouseEvent(PluginObject* obj,
+ EventRecord* the_event) {
+ DCHECK(obj);
+ DCHECK(obj->client());
+ int screen_x = the_event->where.h;
+ int screen_y = the_event->where.v;
+ static Point last_mouse_loc = {0,0};
+
+ o3d::Event::Type type;
+ switch (the_event->what) {
+ case mouseDown:
+ type = o3d::Event::TYPE_MOUSEDOWN;
+ break;
+ case mouseUp:
+ type = o3d::Event::TYPE_MOUSEUP;
+ break;
+ case nullEvent:
+ case osEvt: // can be various things but in this context it's mouse move
+ if (last_mouse_loc.h == screen_x && last_mouse_loc.v == screen_y)
+ return;
+ type = o3d::Event::TYPE_MOUSEMOVE;
+ break;
+ default:
+ LOG(FATAL) << "Unknown mouse event: " << the_event->what;
+ return;
+ }
+
+ last_mouse_loc = the_event->where;
+ bool in_plugin = false; // Did the event happen within our drawing region?
+
+ int x, y;
+ // now make x and y plugin relative coords
+ if (obj->GetFullscreenMacWindow()) {
+ Rect wBounds;
+ GetWindowBounds(obj->GetFullscreenMacWindow(), kWindowGlobalPortRgn,
+ &wBounds);
+ x = screen_x - wBounds.left;
+ y = screen_y - wBounds.top;
+ in_plugin = true;
+ } else {
+ Rect wBounds;
+ GetWindowBounds(obj->mac_window_, kWindowGlobalPortRgn, &wBounds);
+ x = screen_x - wBounds.left - obj->last_plugin_loc_.h;
+ y = screen_y - wBounds.top - obj->last_plugin_loc_.v;
+ in_plugin = x >=0 && y >= 0 && x < obj->width() && y < obj->height();
+ }
+
+ o3d::Event event(type);
+ int modifier_state = 0;
+ if (the_event->modifiers & controlKey) {
+ modifier_state |= o3d::Event::MODIFIER_CTRL;
+ }
+ if (the_event->modifiers & shiftKey) {
+ modifier_state |= o3d::Event::MODIFIER_SHIFT;
+ }
+ if (the_event->modifiers & optionKey) {
+ modifier_state |= o3d::Event::MODIFIER_ALT;
+ }
+ if (the_event->modifiers & cmdKey) {
+ modifier_state |= o3d::Event::MODIFIER_META;
+ }
+
+ event.set_modifier_state(modifier_state);
+
+ // TODO: Figure out how to detect and set buttons properly.
+ if (the_event->modifiers & btnState) {
+ event.set_button(o3d::Event::BUTTON_LEFT);
+ }
+
+ event.set_position(x, y, screen_x, screen_y, in_plugin);
+ obj->client()->AddEventToQueue(event);
+
+ if (in_plugin && type == Event::TYPE_MOUSEDOWN &&
+ obj->HitFullscreenClickRegion(x, y)) {
+ obj->RequestFullscreenDisplay();
+ }
+}
+
+// Handle a mouse-related NPCocoaEvent.
+// These events come from the new Cocoa revision of the NPAPI spec,
+// currently implemented only in Safari.
+// See https://wiki.mozilla.org/Mac:NPAPI_Event_Models
+static void HandleCocoaMouseEvent(PluginObject* obj,
+ NPCocoaEvent* the_event) {
+ DCHECK(obj);
+ DCHECK(obj->client());
+ int screen_x = the_event->data.mouse.pluginX;
+ int screen_y = the_event->data.mouse.pluginY;
+
+ o3d::Event::Type type;
+ switch (the_event->type) {
+ case NPCocoaEventMouseDown:
+ type = o3d::Event::TYPE_MOUSEDOWN;
+ break;
+ case NPCocoaEventMouseUp:
+ type = o3d::Event::TYPE_MOUSEUP;
+ break;
+ // The Mac makes a distinction between moved and dragged (ie moved with
+ // the button down), but the O3D event model does not.
+ case NPCocoaEventMouseMoved:
+ case NPCocoaEventMouseDragged:
+ type = o3d::Event::TYPE_MOUSEMOVE;
+ break;
+ case NPCocoaEventScrollWheel:
+ type = o3d::Event::TYPE_WHEEL;
+ break;
+ // Don't care about these currently.
+ case NPCocoaEventMouseEntered:
+ case NPCocoaEventMouseExited:
+ default:
+ return;
+ }
+
+ int x = the_event->data.mouse.pluginX;
+ int y = the_event->data.mouse.pluginY;
+
+ // Did the event happen within our drawing region?
+ bool in_plugin = x >= 0 && y >= 0 && x < obj->width() && y < obj->height();
+
+ o3d::Event event(type);
+ int modifier_state = 0;
+ if (the_event->data.mouse.modifierFlags & NSControlKeyMask) {
+ modifier_state |= o3d::Event::MODIFIER_CTRL;
+ }
+ if (the_event->data.mouse.modifierFlags &
+ (NSAlphaShiftKeyMask | NSShiftKeyMask)) {
+ modifier_state |= o3d::Event::MODIFIER_SHIFT;
+ }
+ if (the_event->data.mouse.modifierFlags & NSAlternateKeyMask) {
+ modifier_state |= o3d::Event::MODIFIER_ALT;
+ }
+ if (the_event->data.mouse.modifierFlags & NSCommandKeyMask) {
+ modifier_state |= o3d::Event::MODIFIER_META;
+ }
+
+ event.set_modifier_state(modifier_state);
+
+ if (the_event->type == NPCocoaEventScrollWheel) {
+ if (the_event->data.mouse.deltaX && the_event->data.mouse.deltaY) {
+ if (abs(the_event->data.mouse.deltaX) >
+ abs(the_event->data.mouse.deltaY)) {
+ the_event->data.mouse.deltaY = 0;
+ } else {
+ the_event->data.mouse.deltaX = 0;
+ }
+ }
+ event.set_delta(the_event->data.mouse.deltaX * 10.0,
+ the_event->data.mouse.deltaY * 10.0);
+ }
+
+ if ((the_event->type == NPCocoaEventMouseDown) ||
+ (the_event->type == NPCocoaEventMouseUp)) {
+ event.set_button(
+ MacOSMouseButtonNumberToO3DButton(
+ the_event->data.mouse.buttonNumber));
+ }
+
+ event.set_position(x, y, screen_x, screen_y, in_plugin);
+ obj->client()->AddEventToQueue(event);
+
+ if (in_plugin && type == Event::TYPE_MOUSEDOWN &&
+ obj->HitFullscreenClickRegion(x, y)) {
+ obj->RequestFullscreenDisplay();
+ }
+}
+
+
+
+
+// Convert an NSEvent style modifiers field to an EventRecord style one.
+// Not all bits have a representation in the target type, eg NSFunctionKeyMask
+// but we just need to convert the basic modifiers that need to be passed on
+// to Javascript.
+static EventModifiers CocoaToEventRecordModifiers(NSUInteger inMods) {
+ EventModifiers outMods = 0;
+
+ // NSEvent distinuishes between the shift key being down and the capslock key,
+ // but the W3C event spec does not make this distinction.
+ if (inMods & (NSAlphaShiftKeyMask | NSShiftKeyMask))
+ outMods |= shiftKey;
+ if (inMods & NSControlKeyMask)
+ outMods |= controlKey;
+ if (inMods & NSAlternateKeyMask)
+ outMods |= optionKey;
+ if (inMods & NSCommandKeyMask)
+ outMods |= cmdKey;
+
+ return outMods;
+}
+
+// Handle an NPCocoaEvent style event. The Cocoa event interface is
+// a recent addition to the NAPI spec.
+// See https://wiki.mozilla.org/Mac:NPAPI_Event_Models for further details.
+// The principle advantages are that we can get scrollwheel messages,
+// mouse-moved messages, and can tell which mouse button was pressed.
+// This API will also be required for a carbon-free 64 bit version for 10.6.
+bool HandleCocoaEvent(NPP instance, NPCocoaEvent* the_event) {
+ PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
+ WindowRef fullscreen_window = obj->GetFullscreenMacWindow();
+ bool handled = false;
+
+ if (g_logger) g_logger->UpdateLogging();
+
+ obj->MacEventReceived();
+ switch (the_event->type) {
+ case NPCocoaEventDrawRect:
+ DrawPlugin(obj);
+ handled = true;
+ break;
+ case NPCocoaEventMouseDown:
+ case NPCocoaEventMouseUp:
+ case NPCocoaEventMouseMoved:
+ case NPCocoaEventMouseDragged:
+ case NPCocoaEventMouseEntered:
+ case NPCocoaEventMouseExited:
+ case NPCocoaEventScrollWheel:
+ HandleCocoaMouseEvent(obj, the_event);
+ break;
+ case NPCocoaEventKeyDown:
+ // Hard-coded trapdoor to get out of fullscreen mode if user hits escape.
+ if (fullscreen_window) {
+ NSString *chars =
+ (NSString*) the_event->data.key.charactersIgnoringModifiers;
+
+ if ([chars characterAtIndex:0] == '\e') {
+ obj->CancelFullscreenDisplay();
+ break;
+ }
+ } // otherwise fall through
+ case NPCocoaEventKeyUp: {
+ EventKind eventKind = (the_event->type == NPCocoaEventKeyUp) ? keyUp :
+ (the_event->data.key.isARepeat) ? autoKey : keyDown;
+
+ EventModifiers modifiers =
+ CocoaToEventRecordModifiers(the_event->data.key.modifierFlags);
+
+ NSString *chars =
+ (NSString*) the_event->data.key.charactersIgnoringModifiers;
+
+ DispatchKeyboardEvent(obj,
+ eventKind,
+ [chars characterAtIndex:0],
+ the_event->data.key.keyCode,
+ modifiers);
+ break;
+ }
+ case NPCocoaEventFlagsChanged:
+ case NPCocoaEventFocusChanged:
+ case NPCocoaEventWindowFocusChanged:
+ // Safari tab switching recovery code.
+ if (obj->mac_surface_hidden_) {
+ obj->mac_surface_hidden_ = false;
+ NPN_ForceRedraw(instance); // invalidate to cause a redraw
+ }
+
+ // Auto-recovery for any situation where another window comes in front
+ // of the fullscreen window and we need to exit fullscreen mode.
+ // This can happen because another browser window has come forward, or
+ // because another app has been called to the front.
+ // TODO: We'll have problems with this when dealing with e.g.
+ // Japanese text input IME windows.
+ if (fullscreen_window && fullscreen_window != ActiveNonFloatingWindow()) {
+ obj->CancelFullscreenDisplay();
+ }
+
+ break;
+ }
+
+ return handled;
+}
+
+// List of message types from mozilla's nsplugindefs.h, which is more
+// complete than the list in NPAPI.h.
+enum nsPluginEventType {
+ nsPluginEventType_GetFocusEvent = (osEvt + 16),
+ nsPluginEventType_LoseFocusEvent,
+ nsPluginEventType_AdjustCursorEvent,
+ nsPluginEventType_MenuCommandEvent,
+ nsPluginEventType_ClippingChangedEvent,
+ nsPluginEventType_ScrollingBeginsEvent,
+ nsPluginEventType_ScrollingEndsEvent,
+ nsPluginEventType_Idle = 0
+};
+
+
+bool HandleMacEvent(EventRecord* the_event, NPP instance) {
+ PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
+ bool handled = false;
+ WindowRef fullscreen_window = obj->GetFullscreenMacWindow();
+
+ if (g_logger) g_logger->UpdateLogging();
+
+ // Help the plugin keep track of when we last saw an event so the CFTimer can
+ // notice if we get cut off, eg by our tab being hidden by Safari, which there
+ // is no other way for us to detect.
+ obj->MacEventReceived();
+
+ switch (the_event->what) {
+ case nullEvent:
+#ifdef DEFERRED_DRAW_ON_NULLEVENTS
+ GLUE_PROFILE_START(instance, "forceredraw");
+ NPN_ForceRedraw(instance); // invalidate to cause a redraw
+ GLUE_PROFILE_STOP(instance, "forceredraw");
+#elif defined(CFTIMER)
+#else
+ DrawPlugin(obj);
+#endif
+ // Safari tab switching recovery code.
+ if (obj->mac_surface_hidden_) {
+ obj->mac_surface_hidden_ = false;
+ NPN_ForceRedraw(instance); // invalidate to cause a redraw
+ }
+
+ // Auto-recovery for any situation where another window comes in front
+ // of the fullscreen window and we need to exit fullscreen mode.
+ // This can happen because another browser window has come forward, or
+ // because another app has been called to the front.
+ if (fullscreen_window && fullscreen_window != ActiveNonFloatingWindow()) {
+ obj->CancelFullscreenDisplay();
+ }
+
+ // Send nullEvents to HandleMouseEvent so they can be used to simulate
+ // mouse moved events. Not needed in fullscreen mode, where we really do
+ // get mouse moved events. See the osEvt case below.
+ if (!fullscreen_window)
+ HandleMouseEvent(obj, the_event);
+
+ handled = true;
+ break;
+ case updateEvt:
+ DrawPlugin(obj);
+ handled = true;
+ break;
+ case osEvt:
+ // These are mouse moved messages when so tagged in the high byte.
+ if ((the_event->message >> 24) == mouseMovedMessage) {
+ HandleMouseEvent(obj, the_event);
+ handled = true;
+ }
+ break;
+ case mouseDown:
+ HandleMouseEvent(obj, the_event);
+ break;
+ case mouseUp:
+ HandleMouseEvent(obj, the_event);
+ handled = true;
+ break;
+ case keyDown:
+ // Hard-coded trapdoor to get out of fullscreen mode if user hits escape.
+ unsigned char theChar = the_event->message & charCodeMask;
+ if (theChar == '\e' && fullscreen_window) {
+ obj->CancelFullscreenDisplay();
+ break;
+ } // otherwise fall through
+ case autoKey:
+ case keyUp: {
+ DispatchMacKeyboardEvent(obj, the_event);
+ handled = true;
+ break;
+ }
+ case nsPluginEventType_ScrollingBeginsEvent:
+ obj->SetScrollIsInProgress(true);
+ break;
+ case nsPluginEventType_ScrollingEndsEvent:
+ obj->SetScrollIsInProgress(false);
+ break;
+ default:
+ break;
+ }
+ return handled;
+}
+
+extern "C" {
+ NPError InitializePlugin() {
+ if (!o3d::SetupOutOfMemoryHandler())
+ return NPERR_MODULE_LOAD_FAILED_ERROR;
+
+ InitializeBreakpad();
+
+#ifdef CFTIMER
+ gRenderTimer.Start();
+#endif // CFTIMER
+
+ // Initialize the AtExitManager so that base singletons can be
+ // destroyed properly.
+ g_at_exit_manager.reset(new base::AtExitManager());
+
+ // Turn on the logging.
+ CommandLine::Init(0, NULL);
+ InitLogging("debug.log",
+ logging::LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG,
+ logging::DONT_LOCK_LOG_FILE,
+ logging::APPEND_TO_OLD_LOG_FILE);
+
+ DLOG(INFO) << "NP_Initialize";
+
+ o3d::SetupOutOfMemoryHandler();
+
+ return NPERR_NO_ERROR;
+ }
+
+ NPError OSCALL NP_Initialize(NPNetscapeFuncs* browserFuncs) {
+ HANDLE_CRASHES;
+ NPError retval = InitializeNPNApi(browserFuncs);
+ if (retval != NPERR_NO_ERROR) return retval;
+ return InitializePlugin();
+ }
+
+ // Wrapper that discards the return value to match the expected type of
+ // NPP_ShutdownUPP.
+ void NPP_ShutdownWrapper() {
+ NP_Shutdown();
+ }
+
+ // This code is needed to support browsers based on a slightly dated version
+ // of the NPAPI such as Firefox 2, and Camino 1.6. These browsers expect there
+ // to be a main() to call to do basic setup.
+ int main(NPNetscapeFuncs* browserFuncs,
+ NPPluginFuncs* pluginFuncs,
+ NPP_ShutdownUPP* shutdownProc) {
+ HANDLE_CRASHES;
+ NPError error = NP_Initialize(browserFuncs);
+ if (error == NPERR_NO_ERROR)
+ error = NP_GetEntryPoints(pluginFuncs);
+ *shutdownProc = NPP_ShutdownWrapper;
+
+ return error;
+ }
+
+ NPError OSCALL NP_Shutdown(void) {
+ HANDLE_CRASHES;
+ DLOG(INFO) << "NP_Shutdown";
+
+ if (g_logger) {
+ // Do a last sweep to aggregate metrics before we shut down
+ g_logger->ProcessMetrics(true, false);
+ delete g_logger;
+ g_logger = NULL;
+ g_logging_initialized = false;
+ stats_report::g_global_metrics.Uninitialize();
+ }
+
+ CommandLine::Terminate();
+
+#ifdef CFTIMER
+ gRenderTimer.Stop();
+#endif
+
+ // Force all base singletons to be destroyed.
+ g_at_exit_manager.reset(NULL);
+
+ ShutdownBreakpad();
+
+ return NPERR_NO_ERROR;
+ }
+
+ // Negotiates the best plugin event model, sets the browser to use that,
+ // and updates the PluginObject so we can remember which one we chose.
+ // We favor the newer Cocoa-based model, but can cope with browsers that
+ // only support the original event model, or indeed can't even understand
+ // what we are asking for.
+ // Cannot actually fail -
+ static void Mac_SetBestEventModel(NPP instance, PluginObject* obj) {
+ NPError err = NPERR_NO_ERROR;
+ NPEventModel event_model = NPEventModelCarbon;
+ NPBool supportsCocoaEventModel = FALSE;
+ NPBool supportsCarbonEventModel = FALSE;
+
+ // See if browser supports Cocoa event model.
+ err = NPN_GetValue(instance,
+ NPNVsupportsCocoaBool,
+ &supportsCocoaEventModel);
+ if (err != NPERR_NO_ERROR) {
+ supportsCocoaEventModel = FALSE;
+ err = NPERR_NO_ERROR; // browser doesn't support switchable event models
+ }
+
+ // See if browser supports Carbon event model.
+ err = NPN_GetValue(instance,
+ NPNVsupportsCarbonBool,
+ &supportsCarbonEventModel);
+ if (err != NPERR_NO_ERROR) {
+ supportsCarbonEventModel = FALSE;
+ err = NPERR_NO_ERROR;
+ }
+
+ // Now we've collected our data, the decision phase begins.
+
+ // If we didn't successfully get TRUE for either question, the browser
+ // just does not know about the new switchable event models, so must only
+ // support the old Carbon event model.
+ if (!(supportsCocoaEventModel || supportsCocoaEventModel)) {
+ supportsCarbonEventModel = TRUE;
+ obj->event_model_ = NPEventModelCarbon;
+ }
+
+ if (supportsCocoaEventModel) {
+ NPN_SetValue(instance, NPPVpluginEventModel,
+ reinterpret_cast<void*>(NPEventModelCocoa));
+ obj->event_model_ = NPEventModelCocoa;
+ } else {
+ NPN_SetValue(instance, NPPVpluginEventModel,
+ reinterpret_cast<void*>(NPEventModelCocoa));
+ obj->event_model_ = NPEventModelCarbon;
+ }
+ }
+
+
+ // Negotiates the best plugin drawing model, sets the browser to use that,
+ // and updates the PluginObject so we can remember which one we chose.
+ // Returns NPERR_NO_ERROR (0) if successful, otherwise an NPError code.
+ static NPError Mac_SetBestDrawingModel(NPP instance, PluginObject* obj) {
+ NPError err = NPERR_NO_ERROR;
+ NPBool supportsCoreGraphics = FALSE;
+ NPBool supportsOpenGL = FALSE;
+ NPBool supportsQuickDraw = FALSE;
+ NPDrawingModel drawing_model = NPDrawingModelQuickDraw;
+
+ // test for direct OpenGL support
+ err = NPN_GetValue(instance,
+ NPNVsupportsOpenGLBool,
+ &supportsOpenGL);
+ if (err != NPERR_NO_ERROR)
+ supportsOpenGL = FALSE;
+
+ // test for QuickDraw support
+ err = NPN_GetValue(instance,
+ NPNVsupportsQuickDrawBool,
+ &supportsQuickDraw);
+ if (err != NPERR_NO_ERROR)
+ supportsQuickDraw = FALSE;
+
+ // Test for Core Graphics support
+ err = NPN_GetValue(instance,
+ NPNVsupportsCoreGraphicsBool,
+ &supportsCoreGraphics);
+ if (err != NPERR_NO_ERROR)
+ supportsCoreGraphics = FALSE;
+
+
+ // In order of preference. Preference is now determined by compatibility,
+ // not by modernity, and so is the opposite of the order I first used.
+ if (supportsQuickDraw && !(obj->event_model_ == NPEventModelCocoa)) {
+ drawing_model = NPDrawingModelQuickDraw;
+ } else if (supportsCoreGraphics) {
+ drawing_model = NPDrawingModelCoreGraphics;
+ } else if (supportsOpenGL) {
+ drawing_model = NPDrawingModelOpenGL;
+ } else {
+ // This case is for browsers that didn't even understand the question
+ // eg FF2, so drawing models are not supported, just assume QuickDraw.
+ obj->drawing_model_ = NPDrawingModelQuickDraw;
+ return NPERR_NO_ERROR;
+ }
+
+ err = NPN_SetValue(instance, NPPVpluginDrawingModel,
+ reinterpret_cast<void*>(drawing_model));
+ if (err != NPERR_NO_ERROR)
+ return err;
+
+ obj->drawing_model_ = drawing_model;
+
+ return NPERR_NO_ERROR;
+ }
+
+
+ NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc,
+ char* argn[], char* argv[], NPSavedData* saved) {
+ HANDLE_CRASHES;
+
+ NPError err = NPERR_NO_ERROR;
+
+ if (!g_logging_initialized) {
+ GetUserAgentMetrics(instance);
+ GetUserConfigMetrics();
+ // Create usage stats logs object
+ g_logger = o3d::PluginLogging::InitializeUsageStatsLogging();
+ g_logging_initialized = true;
+ }
+
+ PluginObject* pluginObject = glue::_o3d::PluginObject::Create(
+ instance);
+ instance->pdata = pluginObject;
+ glue::_o3d::InitializeGlue(instance);
+ pluginObject->Init(argc, argn, argv);
+
+ Mac_SetBestEventModel(instance,
+ static_cast<PluginObject*>(instance->pdata));
+
+ err = Mac_SetBestDrawingModel(
+ instance, static_cast<PluginObject*>(instance->pdata));
+ if (err != NPERR_NO_ERROR)
+ return err;
+ return NPERR_NO_ERROR;
+ }
+
+ NPError NPP_Destroy(NPP instance, NPSavedData** save) {
+ HANDLE_CRASHES;
+ PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
+ if (obj) {
+#if defined(CFTIMER)
+ gRenderTimer.RemoveInstance(instance);
+#endif
+
+ obj->TearDown();
+ NPN_ReleaseObject(obj);
+ instance->pdata = NULL;
+ }
+
+ return NPERR_NO_ERROR;
+ }
+
+ static bool CheckForAGLError() {
+ return aglGetError() != AGL_NO_ERROR;
+ }
+
+
+ NPError NPP_SetWindow(NPP instance, NPWindow* window) {
+ HANDLE_CRASHES;
+ PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
+ WindowRef new_window = NULL;
+
+ assert(window != NULL);
+
+ obj->last_plugin_loc_.h = window->x;
+ obj->last_plugin_loc_.v = window->y;
+
+ switch (obj->drawing_model_) {
+ case NPDrawingModelOpenGL: {
+ NP_GLContext* np_gl = reinterpret_cast<NP_GLContext*>(window->window);
+ if (obj->event_model_ == NPEventModelCocoa) {
+ NSWindow * ns_window = reinterpret_cast<NSWindow*>(np_gl->window);
+ new_window = reinterpret_cast<WindowRef>([ns_window windowRef]);
+ } else {
+ new_window = np_gl->window;
+ }
+ obj->mac_2d_context_ = NULL;
+ obj->mac_cgl_context_ = np_gl->context;
+ break;
+ }
+ case NPDrawingModelCoreGraphics: {
+ NP_CGContext* np_cg = reinterpret_cast<NP_CGContext*>(window->window);
+ if (obj->event_model_ == NPEventModelCocoa) {
+ NSWindow * ns_window = reinterpret_cast<NSWindow*>(np_cg->window);
+ new_window = reinterpret_cast<WindowRef>([ns_window windowRef]);
+ } else {
+ new_window = np_cg->window;
+ }
+ obj->mac_2d_context_ = np_cg->context;
+ break;
+ }
+ case NPDrawingModelQuickDraw: {
+ NP_Port* np_qd = reinterpret_cast<NP_Port*>(window->window);
+ obj->mac_2d_context_ = np_qd->port;
+ if (np_qd->port)
+ new_window = GetWindowFromPort(np_qd->port);
+ break;
+ }
+ default:
+ return NPERR_INCOMPATIBLE_VERSION_ERROR;
+ break;
+ }
+
+ // Whether the target window has changed.
+ bool window_changed = new_window != obj->mac_window_;
+
+ // Whether we already had a window before this call.
+ bool had_a_window = obj->mac_window_ != NULL;
+
+ obj->mac_window_ = new_window;
+
+ if (obj->drawing_model_ == NPDrawingModelOpenGL) {
+ CGLSetCurrentContext(obj->mac_cgl_context_);
+ } else if (obj->mac_agl_context_ == NULL) { // setup AGL context
+ AGLPixelFormat myAGLPixelFormat = NULL;
+
+ // We need to spec out a few similar but different sets of renderer
+ // specifications - define some macros to lessen the duplication.
+#define O3D_DEPTH_SETTINGS AGL_RGBA, AGL_DEPTH_SIZE, 24,
+#define O3D_STENCIL_SETTINGS AGL_STENCIL_SIZE, 8,
+#define O3D_HARDWARE_RENDERER AGL_ACCELERATED, AGL_NO_RECOVERY,
+#define O3D_SOFTWARE_RENDERER AGL_RENDERER_ID, AGL_RENDERER_GENERIC_FLOAT_ID,
+#define O3D_MULTISAMPLE AGL_MULTISAMPLE, \
+ AGL_SAMPLE_BUFFERS_ARB, 1, AGL_SAMPLES_ARB, 4, AGL_MULTISAMPLE,
+#define O3D_END AGL_NONE
+
+#ifdef USE_AGL_DOUBLE_BUFFER
+#define O3D_DOUBLE_BUFFER_SETTINGS AGL_DOUBLEBUFFER,
+#else
+#define O3D_DOUBLE_BUFFER_SETTINGS
+#endif
+
+ if (!UseSoftwareRenderer()) {
+ // Try to create a hardware context with the following
+ // specification
+ GLint attributes[] = {
+ O3D_DEPTH_SETTINGS
+ O3D_STENCIL_SETTINGS
+ O3D_DOUBLE_BUFFER_SETTINGS
+ O3D_HARDWARE_RENDERER
+ O3D_MULTISAMPLE
+ O3D_END
+ };
+ myAGLPixelFormat = aglChoosePixelFormat(NULL,
+ 0,
+ attributes);
+
+ // If this fails, then don't try to be as ambitious
+ // (so don't ask for multi-sampling), but still require hardware
+ if (myAGLPixelFormat == NULL) {
+ GLint low_end_attributes[] = {
+ O3D_DEPTH_SETTINGS
+ O3D_STENCIL_SETTINGS
+ O3D_DOUBLE_BUFFER_SETTINGS
+ O3D_HARDWARE_RENDERER
+ O3D_END
+ };
+ myAGLPixelFormat = aglChoosePixelFormat(NULL,
+ 0,
+ low_end_attributes);
+ }
+ }
+
+ if (myAGLPixelFormat == NULL) {
+ // Fallback to software renderer either if the vendorID/gpuID
+ // is known to be problematic, or if the hardware context failed
+ // to get created
+ //
+ // Note that we don't request multisampling since it's too slow.
+ GLint software_renderer_attributes[] = {
+ O3D_DEPTH_SETTINGS
+ O3D_STENCIL_SETTINGS
+ O3D_DOUBLE_BUFFER_SETTINGS
+ O3D_SOFTWARE_RENDERER
+ O3D_END
+ };
+ myAGLPixelFormat = aglChoosePixelFormat(NULL,
+ 0,
+ software_renderer_attributes);
+
+ obj->SetRendererIsSoftware(true);
+ }
+
+ if (myAGLPixelFormat == NULL || CheckForAGLError())
+ return NPERR_MODULE_LOAD_FAILED_ERROR;
+
+ obj->mac_agl_context_ = aglCreateContext(myAGLPixelFormat, NULL);
+
+ if (CheckForAGLError())
+ return NPERR_MODULE_LOAD_FAILED_ERROR;
+
+ aglDestroyPixelFormat(myAGLPixelFormat);
+
+ if (!SetWindowForAGLContext(obj->mac_agl_context_, obj->mac_window_))
+ return NPERR_MODULE_LOAD_FAILED_ERROR;
+
+ aglSetCurrentContext(obj->mac_agl_context_);
+
+ GetOpenGLMetrics();
+
+#ifdef USE_AGL_DOUBLE_BUFFER
+ GLint swapInterval = 1; // request synchronization
+ aglSetInteger(obj->mac_agl_context_, AGL_SWAP_INTERVAL, &swapInterval);
+#endif
+ }
+
+ int clipHeight = window->clipRect.bottom - window->clipRect.top;
+ int clipWidth = window->clipRect.right - window->clipRect.left;
+
+ int x_offset = window->clipRect.left - window->x;
+ int y_offset = window->clipRect.top - window->y;
+ int gl_x_origin = x_offset;
+ int gl_y_origin = window->clipRect.bottom - (window->y + window->height);
+
+ // Firefox calls us with an empty cliprect all the time, toggling our
+ // cliprect back and forth between empty and the normal value, particularly
+ // during scrolling.
+ // As we need to make our AGL surface track the clip rect, honoring all of
+ // these calls would result in spectacular flashing.
+ // The goal here is to try to spot the calls we can safely ignore.
+ // The bogus empty cliprects always have left and top of the real clip.
+ // A null cliprect should always be honored ({0,0,0,0} means a hidden tab),
+ // as should the first ever call to this function,
+ // or an attempt to change the window.
+ // The call at the end of a scroll step is also honored.
+ // Otherwise, skip this change and do not hide our context.
+ bool is_empty_cliprect = (clipHeight <= 0 || clipWidth <= 0);
+ bool is_null_cliprect = (window->clipRect.bottom == 0 &&
+ window->clipRect.top == 0 &&
+ window->clipRect.left == 0 &&
+ window->clipRect.right == 0);
+
+ if (is_empty_cliprect && (!is_null_cliprect) &&
+ had_a_window && (!window_changed) && !obj->ScrollIsInProgress()) {
+ return NPERR_NO_ERROR;
+ }
+
+ // Workaround - the Apple software renderer crashes if you set the drawing
+ // area to 0x0, so use 1x1.
+ if (is_empty_cliprect && obj->RendererIsSoftware())
+ clipWidth = clipHeight = 1;
+
+ // update size and location of the agl context
+ if (obj->mac_agl_context_) {
+
+ // We already had a window, and now we've got a different window -
+ // this can happen when the user drags out a tab in Safari into its own
+ // window.
+ if (had_a_window && window_changed)
+ SetWindowForAGLContext(obj->mac_agl_context_, obj->mac_window_);
+
+ aglSetCurrentContext(obj->mac_agl_context_);
+
+ Rect windowRect = {0, 0, 0, 0};
+ if (obj->drawing_model_ == NPDrawingModelQuickDraw)
+ GetWindowBounds(obj->mac_window_, kWindowContentRgn, &windowRect);
+ else
+ GetWindowBounds(obj->mac_window_, kWindowStructureRgn, &windowRect);
+
+ int windowHeight = windowRect.bottom - windowRect.top;
+
+ // These are in window coords, the weird bit being that agl wants the
+ // location of the bottom of the GL context in y flipped coords,
+ // eg 100 would mean the bottom of the GL context was 100 up from the
+ // bottom of the window.
+ obj->last_buffer_rect_[0] = window->x + x_offset;
+ obj->last_buffer_rect_[1] = (windowHeight - (window->y + clipHeight))
+ - y_offset; // this param is y flipped
+ obj->last_buffer_rect_[2] = clipWidth;
+ obj->last_buffer_rect_[3] = clipHeight;
+ obj->mac_surface_hidden_ = false;
+
+ aglSetInteger(obj->mac_agl_context_, AGL_BUFFER_RECT,
+ obj->last_buffer_rect_);
+ aglEnable(obj->mac_agl_context_, AGL_BUFFER_RECT);
+ }
+
+ // Renderer is already initialized from a previous call to this function,
+ // just update size and position and return.
+ if (had_a_window) {
+ obj->renderer()->SetClientOriginOffset(gl_x_origin, gl_y_origin);
+ obj->Resize(window->width, window->height);
+ return NPERR_NO_ERROR;
+ }
+
+ // Create and assign the graphics context.
+ o3d::DisplayWindowMac default_display;
+ default_display.set_agl_context(obj->mac_agl_context_);
+ default_display.set_cgl_context(obj->mac_cgl_context_);
+
+ obj->CreateRenderer(default_display);
+ obj->client()->Init();
+ obj->client()->SetRenderOnDemandCallback(
+ new RenderOnDemandCallbackHandler(obj));
+
+ obj->renderer()->SetClientOriginOffset(gl_x_origin, gl_y_origin);
+ obj->Resize(window->width, window->height);
+
+
+#ifdef CFTIMER
+ // now that the grahics context is setup, add this instance to the timer
+ // list so it gets drawn repeatedly
+ gRenderTimer.AddInstance(instance);
+#endif // CFTIMER
+
+ return NPERR_NO_ERROR;
+ }
+
+ // Called when the browser has finished attempting to stream data to
+ // a file as requested. If fname == NULL the attempt was not successful.
+ void NPP_StreamAsFile(NPP instance, NPStream* stream, const char* fname) {
+ HANDLE_CRASHES;
+ PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
+ StreamManager* stream_manager = obj->stream_manager();
+
+ // Some browsers give us an absolute HFS path in fname, some give us an
+ // absolute Posix path, so convert to Posix if needed.
+ if ((!fname) || (fname[0] == '/') || !fname[0]) {
+ stream_manager->SetStreamFile(stream, fname);
+ } else {
+ const char* converted_fname = CreatePosixFilePathFromHFSFilePath(fname);
+ if (converted_fname == NULL)
+ return; // TODO should also log error if we ever get here
+ stream_manager->SetStreamFile(stream, converted_fname);
+ delete converted_fname;
+ }
+ }
+
+ int16 NPP_HandleEvent(NPP instance, void* event) {
+ HANDLE_CRASHES;
+ PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
+ if (obj->event_model_ == NPEventModelCarbon) {
+ EventRecord* theEvent = static_cast<EventRecord*>(event);
+ return HandleMacEvent(theEvent, instance) ? 1 : 0;
+ } else if (obj->event_model_ == NPEventModelCocoa){
+ return HandleCocoaEvent(instance, (NPCocoaEvent*)event) ? 1 : 0;
+ }
+ return 0;
+ }
+}; // end extern "C"
diff --git a/o3d/plugin/mac/o3d_mac_npapi_metapackage/open_source_o3d_mac_npapi_metapackage.packproj b/o3d/plugin/mac/o3d_mac_npapi_metapackage/open_source_o3d_mac_npapi_metapackage.packproj
new file mode 100644
index 0000000..650936ae
--- /dev/null
+++ b/o3d/plugin/mac/o3d_mac_npapi_metapackage/open_source_o3d_mac_npapi_metapackage.packproj
@@ -0,0 +1,776 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>Hierarchy</key>
+ <dict>
+ <key>Attributes</key>
+ <dict>
+ <key>Components</key>
+ <array>
+ <dict>
+ <key>Attributes</key>
+ <dict>
+ <key>Documents</key>
+ <dict>
+ <key>Background Image</key>
+ <dict>
+ <key>IFPkgFlagBackgroundAlignment</key>
+ <integer>4</integer>
+ <key>IFPkgFlagBackgroundScaling</key>
+ <integer>1</integer>
+ <key>Mode</key>
+ <integer>0</integer>
+ <key>Path</key>
+ <string></string>
+ <key>Path Type</key>
+ <integer>1</integer>
+ </dict>
+ <key>License</key>
+ <dict>
+ <key>International</key>
+ <dict>
+ <key>Mode</key>
+ <integer>0</integer>
+ <key>Path</key>
+ <string></string>
+ <key>Path Type</key>
+ <integer>1</integer>
+ </dict>
+ </dict>
+ <key>ReadMe</key>
+ <dict>
+ <key>International</key>
+ <dict>
+ <key>Mode</key>
+ <integer>0</integer>
+ <key>Path</key>
+ <string></string>
+ <key>Path Type</key>
+ <integer>1</integer>
+ </dict>
+ </dict>
+ <key>Welcome</key>
+ <dict>
+ <key>International</key>
+ <dict>
+ <key>Mode</key>
+ <integer>0</integer>
+ <key>Path</key>
+ <string></string>
+ <key>Path Type</key>
+ <integer>1</integer>
+ </dict>
+ </dict>
+ </dict>
+ <key>Files</key>
+ <dict>
+ <key>Compress</key>
+ <true/>
+ <key>Hierarchy</key>
+ <dict>
+ <key>Children</key>
+ <array>
+ <dict>
+ <key>Children</key>
+ <array>
+ <dict>
+ <key>Children</key>
+ <array/>
+ <key>GID</key>
+ <integer>80</integer>
+ <key>Path</key>
+ <string>Utilities</string>
+ <key>Path Type</key>
+ <integer>1</integer>
+ <key>Privileges</key>
+ <integer>509</integer>
+ <key>Type</key>
+ <integer>1</integer>
+ <key>UID</key>
+ <integer>0</integer>
+ </dict>
+ </array>
+ <key>GID</key>
+ <integer>80</integer>
+ <key>Path</key>
+ <string>Applications</string>
+ <key>Path Type</key>
+ <integer>1</integer>
+ <key>Privileges</key>
+ <integer>509</integer>
+ <key>Type</key>
+ <integer>1</integer>
+ <key>UID</key>
+ <integer>0</integer>
+ </dict>
+ <dict>
+ <key>Children</key>
+ <array>
+ <dict>
+ <key>Children</key>
+ <array/>
+ <key>GID</key>
+ <integer>80</integer>
+ <key>Path</key>
+ <string>Application Support</string>
+ <key>Path Type</key>
+ <integer>1</integer>
+ <key>Privileges</key>
+ <integer>509</integer>
+ <key>Type</key>
+ <integer>1</integer>
+ <key>UID</key>
+ <integer>0</integer>
+ </dict>
+ <dict>
+ <key>Children</key>
+ <array/>
+ <key>GID</key>
+ <integer>80</integer>
+ <key>Path</key>
+ <string>Documentation</string>
+ <key>Path Type</key>
+ <integer>1</integer>
+ <key>Privileges</key>
+ <integer>509</integer>
+ <key>Type</key>
+ <integer>1</integer>
+ <key>UID</key>
+ <integer>0</integer>
+ </dict>
+ <dict>
+ <key>Children</key>
+ <array/>
+ <key>GID</key>
+ <integer>80</integer>
+ <key>Path</key>
+ <string>Filesystems</string>
+ <key>Path Type</key>
+ <integer>1</integer>
+ <key>Privileges</key>
+ <integer>509</integer>
+ <key>Type</key>
+ <integer>1</integer>
+ <key>UID</key>
+ <integer>0</integer>
+ </dict>
+ <dict>
+ <key>Children</key>
+ <array/>
+ <key>GID</key>
+ <integer>80</integer>
+ <key>Path</key>
+ <string>Frameworks</string>
+ <key>Path Type</key>
+ <integer>1</integer>
+ <key>Privileges</key>
+ <integer>509</integer>
+ <key>Type</key>
+ <integer>1</integer>
+ <key>UID</key>
+ <integer>0</integer>
+ </dict>
+ <dict>
+ <key>Children</key>
+ <array>
+ <dict>
+ <key>Children</key>
+ <array/>
+ <key>GID</key>
+ <integer>80</integer>
+ <key>Path</key>
+ <string>O3D.plugin</string>
+ <key>Path Type</key>
+ <integer>2</integer>
+ <key>Privileges</key>
+ <integer>509</integer>
+ <key>Type</key>
+ <integer>3</integer>
+ <key>UID</key>
+ <integer>0</integer>
+ </dict>
+ </array>
+ <key>GID</key>
+ <integer>80</integer>
+ <key>Path</key>
+ <string>Internet Plug-Ins</string>
+ <key>Path Type</key>
+ <integer>1</integer>
+ <key>Privileges</key>
+ <integer>509</integer>
+ <key>Type</key>
+ <integer>1</integer>
+ <key>UID</key>
+ <integer>0</integer>
+ </dict>
+ <dict>
+ <key>Children</key>
+ <array/>
+ <key>GID</key>
+ <integer>80</integer>
+ <key>Path</key>
+ <string>PreferencePanes</string>
+ <key>Path Type</key>
+ <integer>1</integer>
+ <key>Privileges</key>
+ <integer>509</integer>
+ <key>Type</key>
+ <integer>1</integer>
+ <key>UID</key>
+ <integer>0</integer>
+ </dict>
+ <dict>
+ <key>Children</key>
+ <array/>
+ <key>GID</key>
+ <integer>80</integer>
+ <key>Path</key>
+ <string>Printers</string>
+ <key>Path Type</key>
+ <integer>1</integer>
+ <key>Privileges</key>
+ <integer>509</integer>
+ <key>Type</key>
+ <integer>1</integer>
+ <key>UID</key>
+ <integer>0</integer>
+ </dict>
+ <dict>
+ <key>Children</key>
+ <array/>
+ <key>GID</key>
+ <integer>80</integer>
+ <key>Path</key>
+ <string>QuickTime</string>
+ <key>Path Type</key>
+ <integer>1</integer>
+ <key>Privileges</key>
+ <integer>509</integer>
+ <key>Type</key>
+ <integer>1</integer>
+ <key>UID</key>
+ <integer>0</integer>
+ </dict>
+ <dict>
+ <key>Children</key>
+ <array/>
+ <key>GID</key>
+ <integer>80</integer>
+ <key>Path</key>
+ <string>Screen Savers</string>
+ <key>Path Type</key>
+ <integer>1</integer>
+ <key>Privileges</key>
+ <integer>509</integer>
+ <key>Type</key>
+ <integer>1</integer>
+ <key>UID</key>
+ <integer>0</integer>
+ </dict>
+ <dict>
+ <key>Children</key>
+ <array/>
+ <key>GID</key>
+ <integer>80</integer>
+ <key>Path</key>
+ <string>Scripts</string>
+ <key>Path Type</key>
+ <integer>1</integer>
+ <key>Privileges</key>
+ <integer>509</integer>
+ <key>Type</key>
+ <integer>1</integer>
+ <key>UID</key>
+ <integer>0</integer>
+ </dict>
+ </array>
+ <key>GID</key>
+ <integer>80</integer>
+ <key>Path</key>
+ <string>Library</string>
+ <key>Path Type</key>
+ <integer>1</integer>
+ <key>Privileges</key>
+ <integer>1021</integer>
+ <key>Type</key>
+ <integer>1</integer>
+ <key>UID</key>
+ <integer>0</integer>
+ </dict>
+ <dict>
+ <key>Children</key>
+ <array>
+ <dict>
+ <key>Children</key>
+ <array>
+ <dict>
+ <key>Children</key>
+ <array/>
+ <key>GID</key>
+ <integer>0</integer>
+ <key>Path</key>
+ <string>Extensions</string>
+ <key>Path Type</key>
+ <integer>1</integer>
+ <key>Privileges</key>
+ <integer>493</integer>
+ <key>Type</key>
+ <integer>1</integer>
+ <key>UID</key>
+ <integer>0</integer>
+ </dict>
+ </array>
+ <key>GID</key>
+ <integer>0</integer>
+ <key>Path</key>
+ <string>Library</string>
+ <key>Path Type</key>
+ <integer>1</integer>
+ <key>Privileges</key>
+ <integer>493</integer>
+ <key>Type</key>
+ <integer>1</integer>
+ <key>UID</key>
+ <integer>0</integer>
+ </dict>
+ </array>
+ <key>GID</key>
+ <integer>0</integer>
+ <key>Path</key>
+ <string>System</string>
+ <key>Path Type</key>
+ <integer>1</integer>
+ <key>Privileges</key>
+ <integer>493</integer>
+ <key>Type</key>
+ <integer>1</integer>
+ <key>UID</key>
+ <integer>0</integer>
+ </dict>
+ </array>
+ <key>GID</key>
+ <integer>80</integer>
+ <key>Path</key>
+ <string>/</string>
+ <key>Path Type</key>
+ <integer>1</integer>
+ <key>Privileges</key>
+ <integer>1021</integer>
+ <key>Type</key>
+ <integer>1</integer>
+ <key>UID</key>
+ <integer>0</integer>
+ </dict>
+ <key>IFPkgFlagDefaultLocation</key>
+ <string>/</string>
+ <key>Imported Package</key>
+ <false/>
+ <key>Package Path</key>
+ <string></string>
+ <key>Split Forks</key>
+ <true/>
+ </dict>
+ <key>Plugins</key>
+ <dict>
+ <key>PluginsList</key>
+ <array>
+ <dict>
+ <key>Path</key>
+ <string>Introduction</string>
+ <key>Type</key>
+ <integer>0</integer>
+ </dict>
+ <dict>
+ <key>Path</key>
+ <string>ReadMe</string>
+ <key>Type</key>
+ <integer>0</integer>
+ </dict>
+ <dict>
+ <key>Path</key>
+ <string>License</string>
+ <key>Type</key>
+ <integer>0</integer>
+ </dict>
+ <dict>
+ <key>Path</key>
+ <string>Target</string>
+ <key>Type</key>
+ <integer>0</integer>
+ </dict>
+ <dict>
+ <key>Path</key>
+ <string>PackageSelection</string>
+ <key>Type</key>
+ <integer>0</integer>
+ </dict>
+ <dict>
+ <key>Path</key>
+ <string>Install</string>
+ <key>Type</key>
+ <integer>0</integer>
+ </dict>
+ <dict>
+ <key>Path</key>
+ <string>FinishUp</string>
+ <key>Type</key>
+ <integer>0</integer>
+ </dict>
+ </array>
+ </dict>
+ <key>Scripts</key>
+ <dict>
+ <key>Additional Resources</key>
+ <dict>
+ <key>International</key>
+ <array/>
+ </dict>
+ <key>Installation Scripts</key>
+ <dict>
+ <key>IFInstallationScriptsPostflight</key>
+ <dict>
+ <key>Path</key>
+ <string></string>
+ <key>Path Type</key>
+ <integer>2</integer>
+ <key>Status</key>
+ <false/>
+ </dict>
+ <key>IFInstallationScriptsPostinstall</key>
+ <dict>
+ <key>Path</key>
+ <string></string>
+ <key>Status</key>
+ <false/>
+ </dict>
+ <key>IFInstallationScriptsPostupgrade</key>
+ <dict>
+ <key>Path</key>
+ <string></string>
+ <key>Status</key>
+ <false/>
+ </dict>
+ <key>IFInstallationScriptsPreflight</key>
+ <dict>
+ <key>Path</key>
+ <string></string>
+ <key>Status</key>
+ <false/>
+ </dict>
+ <key>IFInstallationScriptsPreinstall</key>
+ <dict>
+ <key>Path</key>
+ <string></string>
+ <key>Status</key>
+ <false/>
+ </dict>
+ <key>IFInstallationScriptsPreupgrade</key>
+ <dict>
+ <key>Path</key>
+ <string></string>
+ <key>Status</key>
+ <false/>
+ </dict>
+ </dict>
+ <key>Requirements</key>
+ <array/>
+ </dict>
+ <key>Settings</key>
+ <dict>
+ <key>Description</key>
+ <dict>
+ <key>International</key>
+ <dict>
+ <key>IFPkgDescriptionDeleteWarning</key>
+ <string></string>
+ <key>IFPkgDescriptionDescription</key>
+ <string></string>
+ <key>IFPkgDescriptionTitle</key>
+ <string>O3D</string>
+ <key>IFPkgDescriptionVersion</key>
+ <string>1.0</string>
+ </dict>
+ </dict>
+ <key>Display Information</key>
+ <dict>
+ <key>CFBundleGetInfoString</key>
+ <string></string>
+ <key>CFBundleIconFile</key>
+ <string></string>
+ <key>CFBundleIconFile Path Type</key>
+ <integer>1</integer>
+ <key>CFBundleIdentifier</key>
+ <string>com.google.o3d.pkg</string>
+ <key>CFBundleName</key>
+ <string>O3D</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0a1</string>
+ </dict>
+ <key>Options</key>
+ <dict>
+ <key>IFPkgFlagAllowBackRev</key>
+ <false/>
+ <key>IFPkgFlagAuthorizationAction</key>
+ <integer>0</integer>
+ <key>IFPkgFlagFollowLinks</key>
+ <false/>
+ <key>IFPkgFlagIsRequired</key>
+ <false/>
+ <key>IFPkgFlagOverwritePermissions</key>
+ <false/>
+ <key>IFPkgFlagRelocatable</key>
+ <false/>
+ <key>IFPkgFlagRestartAction</key>
+ <integer>0</integer>
+ <key>IFPkgFlagRootVolumeOnly</key>
+ <true/>
+ <key>IFPkgFlagUpdateInstalledLanguages</key>
+ <false/>
+ </dict>
+ <key>Version</key>
+ <dict>
+ <key>IFMajorVersion</key>
+ <integer>1</integer>
+ <key>IFMinorVersion</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ </dict>
+ <key>IFPkgFlagPackageSelection</key>
+ <integer>1</integer>
+ <key>Name</key>
+ <string>O3D</string>
+ <key>Status</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <integer>1</integer>
+ </dict>
+ </array>
+ <key>Documents</key>
+ <dict>
+ <key>Background Image</key>
+ <dict>
+ <key>IFPkgFlagBackgroundAlignment</key>
+ <integer>4</integer>
+ <key>IFPkgFlagBackgroundScaling</key>
+ <integer>1</integer>
+ <key>Mode</key>
+ <integer>0</integer>
+ <key>Path</key>
+ <string></string>
+ <key>Path Type</key>
+ <integer>1</integer>
+ </dict>
+ <key>License</key>
+ <dict>
+ <key>International</key>
+ <dict>
+ <key>Mode</key>
+ <integer>0</integer>
+ <key>Path</key>
+ <string></string>
+ <key>Path Type</key>
+ <integer>1</integer>
+ </dict>
+ </dict>
+ <key>ReadMe</key>
+ <dict>
+ <key>International</key>
+ <dict>
+ <key>Mode</key>
+ <integer>0</integer>
+ <key>Path</key>
+ <string></string>
+ <key>Path Type</key>
+ <integer>1</integer>
+ </dict>
+ </dict>
+ <key>Welcome</key>
+ <dict>
+ <key>International</key>
+ <dict>
+ <key>Mode</key>
+ <integer>0</integer>
+ <key>Path</key>
+ <string></string>
+ <key>Path Type</key>
+ <integer>1</integer>
+ </dict>
+ </dict>
+ </dict>
+ <key>Plugins</key>
+ <dict>
+ <key>PluginsList</key>
+ <array>
+ <dict>
+ <key>Path</key>
+ <string>Introduction</string>
+ <key>Type</key>
+ <integer>0</integer>
+ </dict>
+ <dict>
+ <key>Path</key>
+ <string>ReadMe</string>
+ <key>Type</key>
+ <integer>0</integer>
+ </dict>
+ <dict>
+ <key>Path</key>
+ <string>License</string>
+ <key>Type</key>
+ <integer>0</integer>
+ </dict>
+ <dict>
+ <key>Path</key>
+ <string>Target</string>
+ <key>Type</key>
+ <integer>0</integer>
+ </dict>
+ <dict>
+ <key>Path</key>
+ <string>PackageSelection</string>
+ <key>Type</key>
+ <integer>0</integer>
+ </dict>
+ <dict>
+ <key>Path</key>
+ <string>Install</string>
+ <key>Type</key>
+ <integer>0</integer>
+ </dict>
+ <dict>
+ <key>Path</key>
+ <string>FinishUp</string>
+ <key>Type</key>
+ <integer>0</integer>
+ </dict>
+ </array>
+ </dict>
+ <key>Scripts</key>
+ <dict>
+ <key>Additional Resources</key>
+ <dict>
+ <key>International</key>
+ <array/>
+ </dict>
+ <key>Installation Scripts</key>
+ <dict>
+ <key>IFInstallationScriptsPostflight</key>
+ <dict>
+ <key>Path</key>
+ <string></string>
+ <key>Status</key>
+ <false/>
+ </dict>
+ <key>IFInstallationScriptsPostinstall</key>
+ <dict>
+ <key>Path</key>
+ <string></string>
+ <key>Status</key>
+ <false/>
+ </dict>
+ <key>IFInstallationScriptsPostupgrade</key>
+ <dict>
+ <key>Path</key>
+ <string></string>
+ <key>Status</key>
+ <false/>
+ </dict>
+ <key>IFInstallationScriptsPreflight</key>
+ <dict>
+ <key>Path</key>
+ <string></string>
+ <key>Status</key>
+ <false/>
+ </dict>
+ <key>IFInstallationScriptsPreinstall</key>
+ <dict>
+ <key>Path</key>
+ <string></string>
+ <key>Status</key>
+ <false/>
+ </dict>
+ <key>IFInstallationScriptsPreupgrade</key>
+ <dict>
+ <key>Path</key>
+ <string></string>
+ <key>Status</key>
+ <false/>
+ </dict>
+ </dict>
+ <key>Requirements</key>
+ <array/>
+ </dict>
+ <key>Settings</key>
+ <dict>
+ <key>Description</key>
+ <dict>
+ <key>International</key>
+ <dict>
+ <key>IFPkgDescriptionDeleteWarning</key>
+ <string></string>
+ <key>IFPkgDescriptionDescription</key>
+ <string></string>
+ <key>IFPkgDescriptionTitle</key>
+ <string>O3D</string>
+ <key>IFPkgDescriptionVersion</key>
+ <string>1.0</string>
+ </dict>
+ </dict>
+ <key>Display Information</key>
+ <dict>
+ <key>CFBundleGetInfoString</key>
+ <string>O3D 1.0 Copyright © 2008 Google Inc.</string>
+ <key>CFBundleIconFile</key>
+ <string></string>
+ <key>CFBundleIconFile Path Type</key>
+ <integer>1</integer>
+ <key>CFBundleIdentifier</key>
+ <string>com.google.pkg.o3d_mac_npapi_metapackage</string>
+ <key>CFBundleName</key>
+ <string>O3D</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0a1</string>
+ </dict>
+ <key>Version</key>
+ <dict>
+ <key>IFMajorVersion</key>
+ <integer>1</integer>
+ <key>IFMinorVersion</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ </dict>
+ <key>IFPkgFlagComponentDirectory</key>
+ <string>Contents/Resources</string>
+ <key>IFPkgFlagPackageSelection</key>
+ <integer>0</integer>
+ <key>Name</key>
+ <string>O3D</string>
+ <key>Status</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <integer>0</integer>
+ </dict>
+ <key>Name</key>
+ <string>Project</string>
+ <key>Settings</key>
+ <dict>
+ <key>10.1 Compatibility</key>
+ <true/>
+ <key>Build Path</key>
+ <string>.</string>
+ <key>Build Path Type</key>
+ <integer>2</integer>
+ <key>Comment</key>
+ <string></string>
+ <key>Remove .DS_Store</key>
+ <true/>
+ <key>Remove .pbdevelopment</key>
+ <true/>
+ <key>Remove CVS</key>
+ <true/>
+ </dict>
+</dict>
+</plist>
diff --git a/o3d/plugin/mac/o3d_plugin.r b/o3d/plugin/mac/o3d_plugin.r
new file mode 100644
index 0000000..8032bc7
--- /dev/null
+++ b/o3d/plugin/mac/o3d_plugin.r
@@ -0,0 +1,15 @@
+#include <CoreServices/CoreServices.r>
+
+resource 'STR#' (126) { {
+ "@@@PluginDescription@@@",
+ "@@@PluginName@@@"
+} };
+
+resource 'STR#' (127) { {
+ "@@@PluginName@@@"
+} };
+
+resource 'STR#' (128) { {
+ "@@@PluginMimeType@@@",
+ ""
+} };
diff --git a/o3d/plugin/mac/plugin_logging-mac.mm b/o3d/plugin/mac/plugin_logging-mac.mm
new file mode 100644
index 0000000..8466260
--- /dev/null
+++ b/o3d/plugin/mac/plugin_logging-mac.mm
@@ -0,0 +1,236 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// This file contains code to perform the necessary logging operations
+// including:
+// - initializing logging object
+// - aggregating metrics
+// - uploading metrics to the stats server
+
+#include <build/build_config.h>
+#include "statsreport/const-mac.h"
+#include "core/cross/types.h"
+#include "statsreport/metrics.h"
+#include "plugin/cross/plugin_logging.h"
+#include "plugin/cross/plugin_metrics.h"
+#include "statsreport/common/const_product.h"
+#include "statsreport/uploader.h"
+
+namespace o3d {
+
+
+#define kPrefString @"O3D_STATS"
+#define kUserKey @"Google_O3D_User"
+
+
+PluginLogging::PluginLogging() : timer_(new HighresTimer()),
+ running_time_(0),
+ prev_uptime_seconds_(0),
+ prev_cputime_seconds_(0) {
+ DLOG(INFO) << "Creating logger.";
+ timer_->Start();
+}
+
+bool PluginLogging::UpdateLogging() {
+ // Check that sufficient time has passed since last aggregation
+ // Otherwise we can just return
+ if (timer_->GetElapsedMs() < kStatsAggregationIntervalMSec) return false;
+
+ // Sufficient time has passed, let's process
+ // Reset timer
+ timer_->Start();
+ // We are not exiting just yet so pass false for that argument
+ // And we don't have to force it, so pass false for forcing
+ return ProcessMetrics(false, false);
+}
+
+
+
+void PluginLogging::RecordProcessTimes() {
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ ProcessSerialNumber myProcess = {0, kCurrentProcess};
+
+ NSDictionary* processDict = (NSDictionary*)ProcessInformationCopyDictionary(
+ &myProcess,
+ kProcessDictionaryIncludeAllInformationMask);
+
+ ProcessInfoExtendedRec info;
+ bzero(&info, sizeof(info));
+ GetProcessInformation(&myProcess, (ProcessInfoRec*)&info);
+
+ NSDate* launchDate = [processDict objectForKey:@"LSLaunchTime"];
+ NSDate* nowDate = [NSDate dateWithTimeIntervalSinceNow:0];
+ NSTimeInterval uptime = [nowDate timeIntervalSinceDate:launchDate];
+
+ uint64 additional_uptime = uptime - prev_uptime_seconds_;
+ metric_uptime_seconds += additional_uptime;
+ running_time_ += additional_uptime;
+ prev_uptime_seconds_ = uptime;
+
+ uint64 cputime = ((double)info.processActiveTime) / 60.0;
+ metric_cpu_time_seconds += (cputime - prev_cputime_seconds_);
+ prev_cputime_seconds_ = cputime;
+
+ [pool release];
+}
+
+static NSString* generateGUID() {
+ CFUUIDRef uuidRef = CFUUIDCreate(kCFAllocatorDefault);
+ NSString* returned = (NSString*)CFUUIDCreateString(kCFAllocatorDefault,
+ uuidRef);
+ CFRelease(uuidRef);
+ return returned;
+}
+
+
+// Read a pref string for current user, but global to all apps.
+static NSString* ReadGlobalPreferenceString(NSString *key) {
+ return (NSString *)CFPreferencesCopyValue((CFStringRef)key,
+ kCFPreferencesAnyApplication,
+ kCFPreferencesCurrentUser,
+ kCFPreferencesCurrentHost);
+}
+
+
+// Write a pref string for the current user, but global to all apps.
+static void WriteGlobalPreferenceString(NSString *key,
+ NSString *value) {
+ CFPreferencesSetValue((CFStringRef)key,
+ (CFPropertyListRef)value,
+ kCFPreferencesAnyApplication,
+ kCFPreferencesCurrentUser,
+ kCFPreferencesCurrentHost);
+
+ CFPreferencesSynchronize(kCFPreferencesAnyApplication,
+ kCFPreferencesCurrentUser,
+ kCFPreferencesCurrentHost);
+}
+
+
+static const char *GetUserID(void) {
+ static NSString* id_str = NULL;
+
+ if (id_str == NULL) {
+ // if not in cache, try to read it
+ id_str = ReadGlobalPreferenceString(kUserKey);
+
+ // if it was not stored, then create and store it
+ if (!id_str) {
+ id_str = generateGUID();
+ WriteGlobalPreferenceString(kUserKey, id_str);
+ }
+ }
+ return [id_str UTF8String];
+}
+
+
+bool PluginLogging::ProcessMetrics(const bool exiting,
+ const bool force_report) {
+ DLOG(INFO) << "ProcessMetrics()";
+ // Grab incremental process times, has to be done each time
+ // around the loop, because - well - time passes between
+ // iterations :)
+ RecordProcessTimes();
+
+ // This mutex protects the writing to the registry. This way,
+ // if we have multiple instances attempting to aggregate at
+ // once, they won't overwrite one another.
+
+ // 1. return if we can't get mutex
+
+
+ if (exiting) {
+ // If we're exiting, we aggregate to make sure that we record
+ // the tail activity for posterity. We don't report, because
+ // that might delay the process exit arbitrarily, and we don't
+ // want that.
+ // We also make sure to add a sample to the running time
+ metric_running_time_seconds.AddSample(running_time_);
+ DoAggregateMetrics();
+ } else {
+ // TODO: placeholder - where is this supposed to come from?
+ std::string user_id(GetUserID());
+ std::string ui_param("ui=");
+ std::string client_id_argument = ui_param + user_id;
+ std::string user_agent8 = std::string(kUserAgent) +
+ PRODUCT_VERSION_STRING;
+ DoAggregateAndReportMetrics(client_id_argument.c_str(),
+ user_agent8.c_str(), force_report);
+ }
+
+
+ // 2. release mutex
+
+ return true;
+}
+
+void PluginLogging::DoAggregateMetrics() {
+ DLOG(INFO) << "DoAggregateMetrics()";
+ stats_report::AggregateMetrics();
+}
+
+bool PluginLogging::DoAggregateAndReportMetrics(
+ const char* extra_url_arguments,
+ const char* user_agent,
+ const bool force_report) {
+ DLOG(INFO) << "DoAggregateAndReportMetrics()";
+ // AggregateAndReportMetrics returns true if metrics were uploaded
+ return stats_report::AggregateAndReportMetrics(extra_url_arguments,
+ user_agent,
+ force_report);
+}
+
+void PluginLogging::SetTimer(HighresTimer* timer) {
+ timer_.reset(timer);
+}
+
+
+PluginLogging* PluginLogging::InitializeUsageStatsLogging() {
+ bool opt_in = GetOptInKeyValue();
+
+ return CreateUsageStatsLogger<PluginLogging>(opt_in);
+}
+
+bool PluginLogging::GetOptInKeyValue(void) {
+#ifdef NDEBUG
+ NSString *value = ReadGlobalPreferenceString(kPrefString);
+ return ![value isEqualToString:@"NO"];
+#else
+ return true;
+#endif
+}
+
+void PluginLogging::ClearLogs() {
+ stats_report::ResetPersistentMetrics();
+}
+
+} // namespace o3d
diff --git a/o3d/plugin/mac/plugin_mac.h b/o3d/plugin/mac/plugin_mac.h
new file mode 100644
index 0000000..8563228
--- /dev/null
+++ b/o3d/plugin/mac/plugin_mac.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#ifndef O3D_PLUGIN_MAC_PLUGIN_MAC_H_
+#define O3D_PLUGIN_MAC_PLUGIN_MAC_H_
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <npupp.h>
+#include <AGL/agl.h>
+#include <vector>
+
+// Just for o3d::Event::Button at the moment.
+#include "core/cross/event.h"
+
+
+// RenderTimer maintains an animation timer (nominally running at 60fps)
+//
+// Keeps track of the current NPP instances running in the browser and then
+// renders each one during each timer callback.
+class RenderTimer {
+ public:
+ RenderTimer() {}
+
+ void Start();
+ void Stop();
+
+ void AddInstance(NPP instance);
+ void RemoveInstance(NPP instance);
+
+ typedef std::vector<NPP>::iterator InstanceIterator;
+
+ private:
+ RenderTimer(const RenderTimer&);
+
+ static void TimerCallback(CFRunLoopTimerRef timer, void* info);
+ CFRunLoopTimerRef timerRef_;
+ static std::vector<NPP> instances_;
+};
+
+extern RenderTimer gRenderTimer;
+
+void InitializeBreakpad();
+void ShutdownBreakpad();
+
+
+void* SafariBrowserWindowForWindowRef(WindowRef theWindow);
+
+void* SelectedTabForSafariBrowserWindow(void* cocoaWindow);
+
+void ReleaseSafariBrowserWindow(void* browserWindow);
+
+
+// Some miscellaneous helper functions...
+
+bool SetWindowForAGLContext(AGLContext context, WindowRef window);
+
+void CFReleaseIfNotNull(CFTypeRef cf);
+
+bool IsMacOSTenFiveOrHigher(void);
+
+// Converts an old style Mac HFS path eg "HD:Users:xxx:file.zip" into a standard
+// Posix path eg "/Users/xxx/file.zip" Assumes UTF8 in and out, returns a block
+// of memory allocated with new, so you'll want to delete this at some point.
+// Returns NULL in the event of an error.
+char* CreatePosixFilePathFromHFSFilePath(const char* hfsPath);
+
+bool HandleMacEvent(EventRecord* the_event, NPP instance);
+
+o3d::Event::Button MacOSMouseButtonNumberToO3DButton(int inButton);
+
+bool GetBrowserVersionInfo(int *returned_major,
+ int *returned_minor,
+ int *returned_bugfix);
+
+bool UseSoftwareRenderer();
+
+#endif // O3D_PLUGIN_MAC_PLUGIN_MAC_H_
diff --git a/o3d/plugin/mac/plugin_mac.mm b/o3d/plugin/mac/plugin_mac.mm
new file mode 100644
index 0000000..f245f3e
--- /dev/null
+++ b/o3d/plugin/mac/plugin_mac.mm
@@ -0,0 +1,822 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+
+#include "plugin_mac.h"
+#include <Breakpad/Breakpad.h>
+#include <Cocoa/Cocoa.h>
+#include "plugin/cross/o3d_glue.h"
+#include "plugin/cross/main.h"
+#include "core/mac/display_window_mac.h"
+
+BreakpadRef gBreakpadRef = NULL;
+
+using glue::_o3d::PluginObject;
+using o3d::DisplayWindowMac;
+
+// Returns the version number of the running Mac browser, as parsed from
+// the short version string in the plist of the app's bundle.
+bool GetBrowserVersionInfo(int *returned_major,
+ int *returned_minor,
+ int *returned_bugfix) {
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ int major = 0;
+ int minor = 0;
+ int bugfix = 0;
+ NSBundle *app_bundle = [NSBundle mainBundle];
+ NSString *versionString =
+ [app_bundle objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
+
+ if ([versionString length]) {
+ NSScanner *versionScanner = [NSScanner scannerWithString:versionString];
+ NSCharacterSet *dotSet =
+ [NSCharacterSet characterSetWithCharactersInString:@"."];
+ NSCharacterSet *numSet =
+ [NSCharacterSet characterSetWithCharactersInString:@"0123456789"];
+ NSCharacterSet *notNumSet = [numSet invertedSet];
+
+ // Skip anything at start that is not a number.
+ [versionScanner scanCharactersFromSet:notNumSet intoString:NULL];
+
+ // Keep reading values until we get all 3 numbers, or something isn't found.
+ if ([versionScanner scanInt:&major])
+ if ([versionScanner scanCharactersFromSet:dotSet intoString:NULL])
+ if ([versionScanner scanInt:&minor])
+ if ([versionScanner scanCharactersFromSet:dotSet intoString:NULL])
+ [versionScanner scanInt:&bugfix];
+ }
+
+ *returned_major = major;
+ *returned_minor = minor;
+ *returned_bugfix = bugfix;
+
+ [pool release];
+
+ // If we read any version numbers, then we succeeded.
+ return (major || minor || bugfix);
+}
+
+
+// Code for peeking at the selected tab object for a WindowRef in Safari. This
+// is purely so we can detect changes in active tab in Safari, since it does not
+// notify us when our tab is hidden or revealed.
+//
+// If the browser is not Safari these functions should harmlessly be NULL since
+// the walk from windowref to cocoa window (of type "BrowserWindow") to cocoa
+// windowcontroller to selectedTab should harmlessly break down somewhere along
+// the way.
+//
+// This is useful merely for peeking at Safari's internal state for a tab change
+// event, as Safari does not notify us when this happens. It coerces the value
+// to a void*, as the plain .cc files don't like the type id, and we actually
+// only care whether the value changes or not.
+
+
+@interface NSWindowController (plugin_hack)
+- (id)selectedTab;
+@end
+
+void ReleaseSafariBrowserWindow(void* browserWindow) {
+ NSWindow* cocoaWindow = (NSWindow*) browserWindow;
+ [cocoaWindow release];
+}
+
+void* SafariBrowserWindowForWindowRef(WindowRef theWindow) {
+ if (theWindow != NULL) {
+ NSWindow* cocoaWindow = [[NSWindow alloc] initWithWindowRef:theWindow];
+ if (cocoaWindow) {
+ if (strcmp(object_getClassName(cocoaWindow), "BrowserWindow") == 0) {
+ return cocoaWindow;
+ } else {
+ [cocoaWindow release];
+ }
+ }
+ }
+ return NULL;
+}
+
+void* SelectedTabForSafariBrowserWindow(void* browserWindow) {
+ id selectedTab = nil;
+ NSWindow* cocoaWindow = (NSWindow*) browserWindow;
+ if (cocoaWindow) {
+ @try {
+ selectedTab = [[cocoaWindow windowController] selectedTab];
+ } @catch(NSException* exc) {
+ }
+ }
+ return (void*) selectedTab;
+}
+
+// Detects when Safari has hidden or revealed our tab.
+// If a hide event is detected, it sets the mac_surface_hidden_ flag and hides
+// the surface.
+// Later, if the mac_surface_hidden_ flag is set but we are no longer hidden,
+// ie DetectTabHiding is now returning false, it restores the surface to the
+// previous state.
+void ManageSafariTabSwitching(PluginObject* obj) {
+ if (obj->DetectTabHiding()) {
+ if (!obj->mac_surface_hidden_) {
+ obj->mac_surface_hidden_ = true;
+ GLint rect[4] = {0,0,0,0};
+ aglSetInteger(obj->mac_agl_context_, AGL_BUFFER_RECT, rect);
+ aglEnable(obj->mac_agl_context_, AGL_BUFFER_RECT);
+ }
+ } else if (obj->mac_surface_hidden_) {
+ obj->mac_surface_hidden_ = false;
+ aglSetInteger(obj->mac_agl_context_, AGL_BUFFER_RECT,
+ obj->last_buffer_rect_);
+ aglEnable(obj->mac_agl_context_, AGL_BUFFER_RECT);
+ }
+}
+
+
+#pragma mark ____RenderTimer
+
+RenderTimer gRenderTimer;
+std::vector<NPP> RenderTimer::instances_;
+
+void RenderTimer::Start() {
+ CFRunLoopTimerContext timerContext;
+ memset(&timerContext, 0, sizeof(timerContext));
+ timerContext.info = (void*)NULL;
+
+ if (!timerRef_) {
+ timerRef_ = CFRunLoopTimerCreate(NULL,
+ 1.0,
+ 1.0 / 60.0,
+ 0,
+ 0,
+ TimerCallback,
+ &timerContext);
+
+ CFRunLoopAddTimer(CFRunLoopGetCurrent(), timerRef_, kCFRunLoopCommonModes);
+ }
+}
+
+void RenderTimer::Stop() {
+ if (timerRef_) {
+ CFRunLoopTimerInvalidate(timerRef_);
+ timerRef_ = NULL;
+ }
+ instances_.clear(); // this should already be empty, but make sure
+}
+
+void RenderTimer::AddInstance(NPP instance) {
+ // avoid adding the same instance twice!
+ InstanceIterator i = find(instances_.begin(), instances_.end(), instance);
+ if (i == instances_.end()) {
+ instances_.push_back(instance);
+ }
+}
+
+void RenderTimer::RemoveInstance(NPP instance) {
+ InstanceIterator i = find(instances_.begin(), instances_.end(), instance);
+ if (i != instances_.end()) {
+ instances_.erase(i);
+ }
+}
+
+void RenderTimer::TimerCallback(CFRunLoopTimerRef timer, void* info) {
+ HANDLE_CRASHES;
+ for (int i = 0; i < instances_.size(); ++i) {
+ NPP instance = instances_[i];
+ PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
+
+ ManageSafariTabSwitching(obj);
+ obj->client()->Tick();
+
+ // We're visible if (a) we are in fullscreen mode or (b) our cliprect
+ // height and width are both a sensible size, ie > 1 pixel.
+ // We don't check for 0 as we have to size to 1 x 1 on occasion rather than
+ // 0 x 0 to avoid crashing the Apple software renderer, but do not want to
+ // actually draw to a 1 x 1 pixel area.
+ bool plugin_visible = obj->GetFullscreenMacWindow() ||
+ (obj->last_buffer_rect_[2] > 1 && obj->last_buffer_rect_[3] > 1);
+
+ if (plugin_visible && obj->WantsRedraw()) {
+ obj->SetWantsRedraw(false); // for on-demand drawing
+
+ // Force a sync to the VBL (once per timer callback)
+ // to avoid tearing
+ GLint sync = (i == 0);
+ if (obj->mac_cgl_context_) {
+ CGLSetParameter(obj->mac_cgl_context_, kCGLCPSwapInterval, &sync);
+ } else if (obj->mac_agl_context_) {
+ aglSetInteger(obj->mac_agl_context_, AGL_SWAP_INTERVAL, &sync);
+ }
+
+ obj->client()->RenderClient();
+ }
+ }
+}
+
+#pragma mark ____BREAKPAD
+
+bool ExceptionCallback(int exception_type,
+ int exception_code,
+ mach_port_t crashing_thread) {
+ return BreakpadEnabler::IsEnabled();
+}
+
+void InitializeBreakpad() {
+ if (!gBreakpadRef) {
+ NSBundle* bundle = [NSBundle bundleWithIdentifier:@"com.google.o3d"];
+ NSDictionary* info = [bundle infoDictionary];
+
+ gBreakpadRef = BreakpadCreate(info);
+ BreakpadSetFilterCallback(gBreakpadRef, ExceptionCallback);
+ }
+}
+
+void ShutdownBreakpad() {
+ BreakpadRelease(gBreakpadRef);
+ gBreakpadRef = NULL;
+}
+
+#pragma mark ____MISCELLANEOUS_HELPER
+
+void CFReleaseIfNotNull(CFTypeRef cf) {
+ if (cf != NULL)
+ CFRelease(cf);
+}
+
+
+// Given a WindowRef and an AGLContext, make the context draw in that window.
+// Return Value: true if the window is successfully set, false otherwise.
+bool SetWindowForAGLContext(AGLContext context, WindowRef window) {
+ return (IsMacOSTenFiveOrHigher()) ?
+ aglSetWindowRef(context, window) :
+ aglSetDrawable(context, GetWindowPort(window));
+}
+
+
+// Converts an old style Mac HFS path eg "HD:Users:xxx:file.zip" into
+// a standard Posix path eg "/Users/xxx/file.zip"
+// Assumes UTF8 in and out, returns a block of memory allocated with new,
+// so you'll want to delete this at some point.
+// Returns NULL in the event of an error.
+char* CreatePosixFilePathFromHFSFilePath(const char* hfsPath) {
+ CFStringRef cfHFSPath = NULL;
+ CFStringRef cfPosixPath = NULL;
+ CFURLRef cfHFSURL = NULL;
+ char* posix_path = NULL;
+
+ if (hfsPath && hfsPath[0]) {
+ cfHFSPath = CFStringCreateWithCString(kCFAllocatorDefault,
+ hfsPath,
+ kCFStringEncodingUTF8);
+ if (cfHFSPath) {
+ cfHFSURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
+ cfHFSPath,
+ kCFURLHFSPathStyle,
+ false);
+ if (cfHFSURL) {
+ cfPosixPath = CFURLCopyFileSystemPath(cfHFSURL, kCFURLPOSIXPathStyle);
+ if (cfPosixPath) {
+ // returned value includes space for 0 terminator byte
+ int maxSize =
+ CFStringGetMaximumSizeOfFileSystemRepresentation(cfPosixPath);
+ posix_path = new char [maxSize];
+ CFStringGetFileSystemRepresentation(cfPosixPath,
+ posix_path,
+ maxSize);
+ }
+ }
+ }
+ }
+ CFReleaseIfNotNull(cfHFSPath);
+ CFReleaseIfNotNull(cfPosixPath);
+ CFReleaseIfNotNull(cfHFSURL);
+ return posix_path;
+}
+
+// Returns whether OS is 10.5 (Leopard) or higher.
+bool IsMacOSTenFiveOrHigher() {
+ static bool isCached = false, result = false;
+
+ if (!isCached) {
+ SInt32 major = 0;
+ SInt32 minor = 0;
+ // These selectors don't exist pre 10.4 but as we check the error
+ // the function will correctly return NO which is the right answer.
+ result = ((::Gestalt(gestaltSystemVersionMajor, &major) == noErr) &&
+ (::Gestalt(gestaltSystemVersionMinor, &minor) == noErr) &&
+ ((major > 10) || (major == 10 && minor >= 5)));
+ isCached = true;
+ }
+ return result;
+}
+
+
+static Rect CGRect2Rect(const CGRect &inRect) {
+ Rect outRect;
+ outRect.left = inRect.origin.x;
+ outRect.top = inRect.origin.y;
+ outRect.right = inRect.origin.x + inRect.size.width;
+ outRect.bottom = inRect.origin.y + inRect.size.height;
+ return outRect;
+}
+
+static CGRect Rect2CGRect(const Rect &inRect) {
+ CGRect outRect;
+ outRect.origin.x = inRect.left;
+ outRect.origin.y = inRect.top;
+ outRect.size.width = inRect.right - inRect.left;
+ outRect.size.height = inRect.bottom - inRect.top;
+ return outRect;
+}
+
+
+// A little wrapper for ATSUSetAttributes to make calling it with one attribute
+// less annoying.
+static void MySetAttribute(ATSUStyle style,
+ ATSUAttributeTag tag,
+ ByteCount size,
+ ATSUAttributeValuePtr value) {
+
+ ATSUAttributeTag tags[2] = {tag, 0};
+ ByteCount sizes[2] = {size, 0};
+ ATSUAttributeValuePtr values[2] = {value, 0};
+
+ ATSUSetAttributes(style, 1, tags, sizes, values);
+}
+
+// A little wrapper for ATSUSetLayoutControls to make calling it with one
+// attribute less annoying.
+static void MySetLayoutControl(ATSUTextLayout layout,
+ ATSUAttributeTag tag,
+ ByteCount size,
+ ATSUAttributeValuePtr value) {
+
+ ATSUAttributeTag tags[2] = {tag, 0};
+ ByteCount sizes[2] = {size, 0};
+ ATSUAttributeValuePtr values[2] = {value, 0};
+
+ ATSUSetLayoutControls(layout, 1, tags, sizes, values);
+}
+
+static OSStatus HandleOverlayWindow(EventHandlerCallRef inHandlerCallRef,
+ EventRef inEvent,
+ void *inUserData) {
+ return noErr;
+}
+
+static void PaintRoundedCGRect(CGContextRef context,
+ CGRect rect,
+ float radius,
+ bool fill) {
+ CGFloat lx = CGRectGetMinX(rect);
+ CGFloat cx = CGRectGetMidX(rect);
+ CGFloat rx = CGRectGetMaxX(rect);
+ CGFloat by = CGRectGetMinY(rect);
+ CGFloat cy = CGRectGetMidY(rect);
+ CGFloat ty = CGRectGetMaxY(rect);
+
+ CGContextBeginPath(context);
+ CGContextMoveToPoint(context, lx, cy);
+ CGContextAddArcToPoint(context, lx, by, cx, by, radius);
+ CGContextAddArcToPoint(context, rx, by, rx, cy, radius);
+ CGContextAddArcToPoint(context, rx, ty, cx, ty, radius);
+ CGContextAddArcToPoint(context, lx, ty, lx, cy, radius);
+ CGContextClosePath(context);
+
+ if (fill)
+ CGContextFillPath(context);
+ else
+ CGContextStrokePath(context);
+}
+
+// Convenience function for fetching SInt32 parameters from Carbon EventRefs.
+static SInt32 GetIntEventParam(EventRef inEvent, EventParamName inName) {
+ SInt32 value = 0;
+ return (GetEventParameter(inEvent, inName, typeSInt32, NULL, sizeof(value),
+ NULL, &value) == noErr) ? value : 0;
+}
+
+
+#pragma mark ____OVERLAY_WINDOW
+
+
+static void DrawToOverlayWindow(WindowRef overlayWindow) {
+#define kTextWindowHeight 40
+
+ CGContextRef overlayContext = NULL;
+ OSStatus result = noErr;
+ // TODO this will need to be a localized string
+ char * display_text = "Press Esc to exit full screen mode.";
+
+ UniChar* display_text_16 = NULL;
+ CFStringRef display_text_cfstr = NULL;
+ int textLength = 0;
+
+ QDBeginCGContext(GetWindowPort(overlayWindow), &overlayContext);
+
+ display_text_cfstr = CFStringCreateWithCString(kCFAllocatorDefault,
+ display_text,
+ kCFStringEncodingUTF8);
+ textLength = CFStringGetLength(display_text_cfstr);
+ display_text_16 = (UniChar*)calloc(textLength + 1, sizeof(*display_text_16));
+ CFStringGetCharacters(display_text_cfstr,
+ CFRangeMake(0, textLength),
+ display_text_16);
+
+#define kOverlayWindowFontName "Helvetica"
+
+ CGFloat kWhiteOpaque[] = {1.0, 1.0, 1.0, 1.0};
+ CGFloat kBlackOpaque[] = {0.0, 0.0, 0.0, 1.0};
+ CGFloat kGreyNotOpaque[] = {0.5, 0.5, 0.5, 0.5};
+
+ Rect bounds = {0,0,100,100};
+ GetWindowBounds(overlayWindow, kWindowContentRgn, &bounds);
+
+ CGRect cgTotalRect = Rect2CGRect(bounds);
+
+ CGContextSetShouldSmoothFonts(overlayContext, true);
+ CGContextClearRect(overlayContext, cgTotalRect);
+
+ CGColorSpaceRef myColorSpace = CGColorSpaceCreateDeviceRGB();
+ CGColorRef textShadow = CGColorCreate(myColorSpace, kBlackOpaque);
+ CGColorRef roundRectBackColor = CGColorCreate(myColorSpace, kGreyNotOpaque);
+ CGSize shadowOffset = {0.0,0.0};
+
+ CGContextSetFillColor(overlayContext, kWhiteOpaque);
+ CGContextSetStrokeColor(overlayContext, kWhiteOpaque);
+
+ if (strlen(display_text)) {
+ ATSUStyle style;
+ ATSUTextLayout layout;
+ ATSUFontID font;
+ Fixed pointSize = Long2Fix(36);
+
+ ATSUCreateStyle(&style);
+ ATSUFindFontFromName(kOverlayWindowFontName, strlen(kOverlayWindowFontName),
+ kFontFullName, kFontNoPlatformCode, kFontNoScriptCode,
+ kFontNoLanguageCode, &font);
+
+ MySetAttribute(style, kATSUFontTag, sizeof(font), &font);
+ MySetAttribute(style, kATSUSizeTag, sizeof(pointSize), &pointSize);
+
+ ATSUCreateTextLayout(&layout);
+ ATSUSetTextPointerLocation(layout, display_text_16,
+ kATSUFromTextBeginning, kATSUToTextEnd,
+ textLength);
+ ATSUSetRunStyle(layout, style, kATSUFromTextBeginning, kATSUToTextEnd);
+
+ MySetLayoutControl(layout, kATSUCGContextTag,
+ sizeof(CGContextRef), &overlayContext);
+
+ // Need to enable this for languages like Japanese to draw as something
+ // other than a series of squares.
+ ATSUSetTransientFontMatching(layout, true);
+
+ CGContextSetFillColorWithColor(overlayContext, roundRectBackColor);
+ CGRect mine = CGRectMake((bounds.right/2.0) - 400.0,
+ (bounds.bottom/2.0)-30.0, 800.0, 80.0);
+ PaintRoundedCGRect(overlayContext, mine, 16.0, true);
+
+ CGContextSetFillColor(overlayContext, kWhiteOpaque);
+
+ CGContextSaveGState(overlayContext);
+ CGContextSetShadowWithColor(overlayContext, shadowOffset, 4.0, textShadow);
+ ATSUDrawText(layout, kATSUFromTextBeginning, kATSUToTextEnd,
+ X2Fix((bounds.right/2.0) - 300.0), X2Fix(bounds.bottom/2.0));
+ CGContextRestoreGState(overlayContext);
+
+ ATSUDisposeStyle(style);
+ ATSUDisposeTextLayout(layout);
+ }
+
+
+ CGColorRelease(roundRectBackColor);
+ CGColorRelease (textShadow);
+ CGColorSpaceRelease (myColorSpace);
+ CFReleaseIfNotNull(display_text_cfstr);
+
+ QDEndCGContext(GetWindowPort(overlayWindow), &overlayContext);
+}
+
+
+static WindowRef CreateOverlayWindow(void) {
+ Rect bounds = CGRect2Rect(CGDisplayBounds(CGMainDisplayID()));
+ WindowClass wClass = kOverlayWindowClass;
+ WindowRef window = NULL;
+ OSStatus err = noErr;
+ WindowAttributes overlayAttributes = kWindowNoShadowAttribute |
+ kWindowIgnoreClicksAttribute |
+ kWindowNoActivatesAttribute |
+ kWindowStandardHandlerAttribute;
+ EventTypeSpec eventTypes[] = {
+ kEventClassWindow, kEventWindowDrawContent,
+ kEventClassWindow, kEventWindowShown
+ };
+
+
+ err = CreateNewWindow(wClass,
+ overlayAttributes,
+ &bounds,
+ &window);
+ if (err)
+ return NULL;
+
+ ShowWindow(window);
+ InstallEventHandler(GetWindowEventTarget(window), HandleOverlayWindow,
+ sizeof(eventTypes)/sizeof(eventTypes[0]), eventTypes,
+ NULL, NULL);
+ return window;
+}
+
+
+// Maps the MacOS button numbers to the constants used by our
+// event mechanism. Not quite as obvious as you might think, as the Mac
+// thinks the numbering should go left, right, middle and our W3C-influenced
+// system goes left, middle, right.
+// Defaults to left-button if passed a strange value. Pass Cocoa mouse button
+// codes as-is (they start at 0), pass Carbon button codes - 1.
+o3d::Event::Button MacOSMouseButtonNumberToO3DButton(int inButton) {
+
+ switch(inButton) {
+ case 0:
+ return o3d::Event::BUTTON_LEFT;
+ case 1:
+ return o3d::Event::BUTTON_RIGHT;
+ case 2:
+ return o3d::Event::BUTTON_MIDDLE;
+ case 3:
+ return o3d::Event::BUTTON_4;
+ case 4:
+ return o3d::Event::BUTTON_5;
+ }
+
+ return o3d::Event::BUTTON_LEFT;
+}
+
+
+#pragma mark ____FULLSCREEN_WINDOW
+
+
+// Handles the CarbonEvents that we get sent for the fullscreen mode window.
+// Most of these can be converted to EventRecord events and handled by the
+// HandleMacEvent() function in main_mac.mm, but some have no equivalent in
+// that space, scroll-wheel events for example, and so must be handled here.
+static OSStatus HandleFullscreenWindow(EventHandlerCallRef inHandlerCallRef,
+ EventRef inEvent,
+ void *inUserData) {
+ OSStatus err = noErr;
+ OSType event_class = GetEventClass(inEvent);
+ OSType event_kind = GetEventKind(inEvent);
+ NPP instance = (NPP)inUserData;
+ PluginObject* obj = (PluginObject*)(instance->pdata);
+ HIPoint mouse_loc = { 0.0, 0.0 };
+ bool is_scroll_event = event_class == kEventClassMouse &&
+ (event_kind == kEventMouseScroll ||
+ event_kind == kEventMouseWheelMoved);
+
+ // If it's any kind of mouse event, get the global mouse loc.
+ if (event_class == kEventClassMouse) {
+ GetEventParameter(inEvent, kEventParamMouseLocation,
+ typeHIPoint, NULL,
+ sizeof(mouse_loc), NULL,
+ &mouse_loc);
+ }
+
+ // Handle the two kinds of scroll message we understand.
+ if (is_scroll_event) {
+ SInt32 x_scroll = 0;
+ SInt32 y_scroll = 0;
+ EventMouseWheelAxis axis = kEventMouseWheelAxisY;
+
+ switch (event_kind) {
+ // The newer kind of scroll event, as sent when two-finger
+ // dragging on a touchpad.
+ case kEventMouseScroll:
+ x_scroll = GetIntEventParam(inEvent,
+ kEventParamMouseWheelSmoothHorizontalDelta);
+ y_scroll = GetIntEventParam(inEvent,
+ kEventParamMouseWheelSmoothVerticalDelta);
+
+ // only pass x or y value - pass whichever is larger
+ if (x_scroll && y_scroll) {
+ if (abs(x_scroll) > abs(y_scroll))
+ y_scroll = 0;
+ else
+ x_scroll = 0;
+ }
+ break;
+ // The older kind of scroll event, as sent when using the wheel on
+ // a third-party mouse.
+ case kEventMouseWheelMoved:
+ GetEventParameter(inEvent, kEventParamMouseWheelAxis,
+ typeMouseWheelAxis, NULL,
+ sizeof(axis), NULL,
+ &axis);
+
+ if (axis == kEventMouseWheelAxisY) {
+ y_scroll = GetIntEventParam(inEvent,
+ kEventParamMouseWheelDelta);
+ } else {
+ x_scroll = GetIntEventParam(inEvent,
+ kEventParamMouseWheelDelta);
+ }
+ break;
+ }
+
+ // Dispatch the event now that we have all the data.
+ if (x_scroll || y_scroll) {
+ o3d::Event event(o3d::Event::TYPE_WHEEL);
+ event.set_delta(x_scroll, y_scroll);
+ // Global and local locs are the same, in this case,
+ // as we have a fullscreen window at 0,0.
+ event.set_position(mouse_loc.x, mouse_loc.y,
+ mouse_loc.x, mouse_loc.y, true);
+ obj->client()->AddEventToQueue(event);
+ }
+ return noErr;
+ } else if (event_class == kEventClassMouse &&
+ (event_kind == kEventMouseDown || event_kind == kEventMouseUp)) {
+
+ o3d::Event::Type type = (event_kind == kEventMouseDown) ?
+ o3d::Event::TYPE_MOUSEDOWN :
+ o3d::Event::TYPE_MOUSEUP;
+ o3d::Event event(type);
+ event.set_position(mouse_loc.x, mouse_loc.y,
+ mouse_loc.x, mouse_loc.y, true);
+
+ EventMouseButton button = 0;
+ GetEventParameter(inEvent, kEventParamMouseButton,
+ typeMouseButton, NULL,
+ sizeof(button), NULL,
+ &button);
+ // Carbon mouse button numbers start at 1, so subtract 1 here -
+ // Cocoa mouse buttons, by contrast, start at 0).
+ event.set_button(MacOSMouseButtonNumberToO3DButton(button - 1));
+
+ // add the modifiers to the event, if any
+ UInt32 carbonMods = GetIntEventParam(inEvent,
+ kEventParamKeyModifiers);
+ if (carbonMods) {
+ int modifier_state = 0;
+ if (carbonMods & controlKey) {
+ modifier_state |= o3d::Event::MODIFIER_CTRL;
+ }
+ if (carbonMods & shiftKey) {
+ modifier_state |= o3d::Event::MODIFIER_SHIFT;
+ }
+ if (carbonMods & optionKey) {
+ modifier_state |= o3d::Event::MODIFIER_ALT;
+ }
+ if (carbonMods & cmdKey) {
+ modifier_state |= o3d::Event::MODIFIER_META;
+ }
+
+ event.set_modifier_state(modifier_state);
+ }
+
+ obj->client()->AddEventToQueue(event);
+ } else { // not a scroll event or a click
+
+ // All other events are currently handled by being converted to an
+ // old-style EventRecord as passed by the classic NPAPI interface
+ // and dispatched through our common routine.
+ EventRecord eventRecord;
+
+ if (ConvertEventRefToEventRecord(inEvent, &eventRecord)) {
+ HandleMacEvent(&eventRecord, (NPP)inUserData);
+ return noErr;
+ } else {
+ return eventNotHandledErr;
+ }
+ }
+}
+
+static WindowRef CreateFullscreenWindow(PluginObject *obj,
+ int mode_id) {
+ Rect bounds = CGRect2Rect(CGDisplayBounds(CGMainDisplayID()));
+ WindowRef window = NULL;
+ OSStatus err = noErr;
+ EventTypeSpec eventTypes[] = {
+ kEventClassKeyboard, kEventRawKeyDown,
+ kEventClassKeyboard, kEventRawKeyRepeat,
+ kEventClassKeyboard, kEventRawKeyUp,
+ kEventClassMouse, kEventMouseDown,
+ kEventClassMouse, kEventMouseUp,
+ kEventClassMouse, kEventMouseMoved,
+ kEventClassMouse, kEventMouseDragged,
+ kEventClassMouse, kEventMouseScroll,
+ kEventClassMouse, kEventMouseWheelMoved
+ };
+
+ err = CreateNewWindow(kSimpleWindowClass,
+ kWindowStandardHandlerAttribute,
+ &bounds,
+ &window);
+ if (err)
+ return NULL;
+
+ InstallEventHandler(GetWindowEventTarget(window), HandleFullscreenWindow,
+ sizeof(eventTypes)/sizeof(eventTypes[0]), eventTypes,
+ obj->npp(), NULL);
+ ShowWindow(window);
+ return window;
+}
+
+void CleanupFullscreenWindow(PluginObject *obj) {
+ if (obj->GetFullscreenMacWindow()) {
+ DisposeWindow(obj->GetFullscreenMacWindow());
+ obj->SetFullscreenMacWindow(NULL);
+ }
+
+ if (obj->GetFullscreenOverlayMacWindow()) {
+ DisposeWindow(obj->GetFullscreenOverlayMacWindow());
+ obj->SetFullscreenOverlayMacWindow(NULL);
+ }
+}
+
+
+bool PluginObject::RequestFullscreenDisplay() {
+#ifndef NDEBUG // TODO: Remove after all security is in.
+ // If already in fullscreen mode, do nothing.
+ if (GetFullscreenMacWindow())
+ return false;
+
+ SetSystemUIMode(kUIModeAllSuppressed, kUIOptionAutoShowMenuBar);
+ SetFullscreenMacWindow(
+ CreateFullscreenWindow(this, fullscreen_region_mode_id_));
+
+ Rect bounds = {0,0,0,0};
+ GetWindowBounds(GetFullscreenMacWindow(), kWindowContentRgn, &bounds);
+
+ SetWindowForAGLContext(mac_agl_context_, GetFullscreenMacWindow());
+ aglDisable(mac_agl_context_, AGL_BUFFER_RECT);
+ renderer()->SetClientOriginOffset(0, 0);
+ renderer_->Resize(bounds.right - bounds.left, bounds.bottom - bounds.top);
+
+ const double kFadeOutTime = 3.0;
+ SetFullscreenOverlayMacWindow(CreateOverlayWindow());
+ DrawToOverlayWindow(GetFullscreenOverlayMacWindow());
+ TransitionWindowOptions options = {0, kFadeOutTime, NULL, NULL};
+ TransitionWindowWithOptions(GetFullscreenOverlayMacWindow(),
+ kWindowFadeTransitionEffect,
+ kWindowHideTransitionAction,
+ NULL, true, &options);
+ return true;
+#else
+ return false;
+#endif
+}
+
+void PluginObject::CancelFullscreenDisplay() {
+#ifndef NDEBUG // TODO: Remove after user-prompt feature goes in.
+
+ // if not in fullscreen mode, do nothing
+ if (!GetFullscreenMacWindow())
+ return;
+
+ //fullscreen_ = false;
+ SetWindowForAGLContext(mac_agl_context_, mac_window_);
+ aglSetInteger(mac_agl_context_, AGL_BUFFER_RECT, last_buffer_rect_);
+ aglEnable(mac_agl_context_, AGL_BUFFER_RECT);
+ renderer_->Resize(prev_width_, prev_height_);
+ CleanupFullscreenWindow(this);
+
+ // Somehow the browser window does not automatically activate again
+ // when we close the fullscreen window, so explicitly reactivate it.
+ if (mac_cocoa_window_) {
+ NSWindow* browser_window = (NSWindow*) mac_cocoa_window_;
+ [browser_window makeKeyAndOrderFront:browser_window];
+ } else {
+ SelectWindow(mac_window_);
+ }
+
+ SetSystemUIMode(kUIModeNormal, 0);
+#endif
+}
+
diff --git a/o3d/plugin/mac/plugin_metrics-mac.cc b/o3d/plugin/mac/plugin_metrics-mac.cc
new file mode 100644
index 0000000..56c3a14
--- /dev/null
+++ b/o3d/plugin/mac/plugin_metrics-mac.cc
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "statsreport/metrics.h"
+#include "plugin/cross/plugin_metrics.h"
+
+namespace o3d {
+DEFINE_METRIC_integer(system_type);
+
+DEFINE_METRIC_integer(mac_major_version);
+DEFINE_METRIC_integer(mac_minor_version);
+DEFINE_METRIC_integer(mac_bugfix_version);
+
+// User GPU
+DEFINE_METRIC_integer(gpu_vendor_id);
+DEFINE_METRIC_integer(gpu_device_id);
+DEFINE_METRIC_integer(gpu_driver_major_version);
+DEFINE_METRIC_integer(gpu_driver_minor_version);
+DEFINE_METRIC_integer(gpu_driver_bugfix_version);
+DEFINE_METRIC_integer(gpu_vram_size);
+DEFINE_METRIC_bool(direct3d_available);
+
+
+// Shader versions
+DEFINE_METRIC_integer(pixel_shader_main_version);
+DEFINE_METRIC_integer(pixel_shader_sub_version);
+DEFINE_METRIC_integer(vertex_shader_main_version);
+DEFINE_METRIC_integer(vertex_shader_sub_version);
+
+DEFINE_METRIC_bool(POW2_texture_caps);
+DEFINE_METRIC_bool(NONPOW2CONDITIONAL_texture_caps);
+
+DEFINE_METRIC_integer(browser_type);
+DEFINE_METRIC_integer(browser_major_version);
+DEFINE_METRIC_integer(browser_minor_version);
+DEFINE_METRIC_integer(browser_bugfix_version);
+
+DEFINE_METRIC_timing(running_time);
+
+DEFINE_METRIC_count(uptime_seconds);
+DEFINE_METRIC_count(cpu_time_seconds);
+DEFINE_METRIC_timing(running_time_seconds);
+
+DEFINE_METRIC_count(crashes_total);
+DEFINE_METRIC_count(crashes_uploaded);
+DEFINE_METRIC_count(out_of_memory_total);
+
+DEFINE_METRIC_count(bluescreens_total);
+
+// OpenGL Caps - insert more here
+DEFINE_METRIC_integer(gl_major_version);
+DEFINE_METRIC_integer(gl_minor_version);
+DEFINE_METRIC_integer(gl_hlsl_major_version);
+DEFINE_METRIC_integer(gl_hlsl_minor_version);
+
+} // namespace o3d
diff --git a/o3d/plugin/npapi_host_control/build.scons b/o3d/plugin/npapi_host_control/build.scons
new file mode 100644
index 0000000..74597a6
--- /dev/null
+++ b/o3d/plugin/npapi_host_control/build.scons
@@ -0,0 +1,100 @@
+# Copyright 2009, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+Import('env')
+
+env.Append(
+ CPPDEFINES = [
+ '_MIDL_USE_GUIDDEF_',
+ 'DLL_NPAPI_HOST_CONTROL_EXPORT'
+ ],
+ CCFLAGS = [
+ '/Wp64',
+ '/TP',
+ '/FIplugin/npapi_host_control/win/precompile.h'
+ ],
+ CPPPATH = [
+ 'win',
+ '$SCONSTRUCT_DIR/plugin/npapi_host_control/win',
+ ],
+ LINKFLAGS = [
+ '/DEF:$SCONSTRUCT_DIR/plugin/npapi_host_control/win/npapi_host_control.def'
+ ],
+)
+
+env.Append(
+ CPPDEFINES = [
+ ('O3D_PLUGIN_NAME', '\\"$O3D_PLUGIN_NAME\\"'),
+ ('O3D_PLUGIN_DESCRIPTION', '\\"$O3D_PLUGIN_DESCRIPTION\\"'),
+ ('O3D_PLUGIN_VERSION', '\\"$O3D_PLUGIN_VERSION\\"')
+ ])
+
+resource_files = env.RES('win/npapi_host_control.rc'),
+
+inputs = [
+ 'win/npapi_host_control_i.c',
+ 'win/npapi_host_control.cc',
+ 'win/host_control.cc',
+ 'win/np_browser_proxy.cc',
+ 'win/np_object_proxy.cc',
+ 'win/np_plugin_proxy.cc',
+ 'win/dispatch_proxy.cc',
+ 'win/stream_operation.cc',
+ 'win/variant_utils.cc',
+ resource_files,
+]
+
+if env['TARGET_PLATFORM'] == 'WINDOWS':
+ env['PCH'], obj = env.PCH('win/precompile.cc')
+ env['PCHSTOP'] = 'plugin/npapi_host_control/win/precompile.h'
+ inputs += [obj]
+else:
+ inputs += ['precompile.cc']
+
+
+type_lib = env.TypeLibrary(source=['win/npapi_host_control.idl'])
+
+# Must not register the plugin while building. Only installing should
+# register the plugin.
+o3d_host_control = env.SharedLibrary('o3d_host', inputs)
+env.Requires(o3d_host_control, type_lib)
+env.Requires(resource_files, type_lib)
+
+env.Replicate('$ARTIFACTS_DIR', o3d_host_control)
+
+# TODO: have a common way to do colliding installs like this.
+# Do the install step only if this variant is the first target.
+if env.Bit('windows'):
+ if (env['BUILD_TYPE'] == ARGUMENTS.get('MODE') or
+ (ARGUMENTS.get('MODE', 'default') == 'default' and
+ env['BUILD_TYPE'] == 'dbg-d3d')):
+ i = env.Replicate('$IE_PLUGIN_DIR', o3d_host_control[0])
+ c = env.AddPostAction(i, '$REGSVR $REGSVRFLAGS $TARGET')
+ env.Alias('install', c)
diff --git a/o3d/plugin/npapi_host_control/win/dispatch_proxy.cc b/o3d/plugin/npapi_host_control/win/dispatch_proxy.cc
new file mode 100644
index 0000000..334bda4
--- /dev/null
+++ b/o3d/plugin/npapi_host_control/win/dispatch_proxy.cc
@@ -0,0 +1,321 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "plugin/npapi_host_control/win/dispatch_proxy.h"
+
+#include <atlstr.h>
+#include <dispex.h>
+#include <oaidl.h>
+
+#include <base/scoped_ptr.h>
+#include <algorithm>
+#include <vector>
+
+#include "plugin/npapi_host_control/win/np_browser_proxy.h"
+#include "plugin/npapi_host_control/win/variant_utils.h"
+
+namespace {
+
+// Helper routine that invokes an IDispatchEx interface with argument values
+// provided by NPAPI variant objects.
+HRESULT DispatchInvoke(NPBrowserProxy* browser_proxy,
+ IDispatchEx *dispatch,
+ DWORD flags,
+ DISPID member,
+ const NPVariant* arguments,
+ int arg_count,
+ NPVariant* result) {
+ // Convert the NPAPI arguments to COM variant objects.
+ scoped_array<CComVariant> local_args(new CComVariant[arg_count]);
+ for (int x = 0; x < arg_count; ++x) {
+ // Note that IDispatch expects arguments in reverse order.
+ NPVariantToVariant(browser_proxy,
+ &arguments[x],
+ &local_args[arg_count - x - 1]);
+ }
+
+ HRESULT hr = S_OK;
+ CComVariant return_arg;
+ DISPPARAMS disp_arguments = {0};
+ disp_arguments.cArgs = arg_count;
+ disp_arguments.rgvarg = local_args.get();
+ hr = dispatch->InvokeEx(member, LOCALE_SYSTEM_DEFAULT,
+ flags, &disp_arguments, &return_arg, NULL,
+ NULL);
+
+ // If the invoke succeeded, then convert and store the return argument.
+ if (SUCCEEDED(hr)) {
+ VariantToNPVariant(browser_proxy, &return_arg, result);
+ }
+
+ return hr;
+}
+
+} // unnamed namespace
+
+DispatchProxy::DispatchProxy(IDispatchEx* dispatch,
+ NPBrowserProxy* browser_proxy)
+ : dispatch_(dispatch),
+ browser_proxy_(browser_proxy) {
+ _class = &kNPClass;
+ referenceCount = 1;
+}
+
+DispatchProxy::~DispatchProxy() {
+ ATLASSERT(referenceCount == 0);
+ CComPtr<IDispatchEx> dispatchex_object;
+ if (browser_proxy_) {
+ browser_proxy_->UnregisterDispatchProxy(dispatch_);
+ }
+}
+
+DISPID DispatchProxy::GetDispatchId(NPIdentifier name, DWORD flags) const {
+ DISPID dispatch_id = -1;
+
+ NPUTF8* method_name =
+ browser_proxy_->GetBrowserFunctions()->utf8fromidentifier(name);
+
+ // Convert the UTF8-NPAPI string to a wide string.
+ int required_size = 0;
+ required_size = MultiByteToWideChar(CP_UTF8, 0, method_name,
+ -1, NULL, 0);
+
+ CComBSTR wide_name(required_size - 1);
+ MultiByteToWideChar(CP_UTF8, 0, method_name,
+ -1, (BSTR) wide_name, required_size);
+ dispatch_->GetDispID(wide_name, flags, &dispatch_id);
+
+ browser_proxy_->GetBrowserFunctions()->memfree(method_name);
+
+ return dispatch_id;
+}
+
+bool DispatchProxy::HasMethod(NPObject *header, NPIdentifier name) {
+ DispatchProxy *proxy = static_cast<DispatchProxy*>(header);
+ return proxy->GetDispatchId(name, 0) != -1;
+}
+
+bool DispatchProxy::InvokeEntry(NPObject *header,
+ NPIdentifier name,
+ const NPVariant *args,
+ uint32_t arg_count,
+ NPVariant *result) {
+ DispatchProxy *proxy = static_cast<DispatchProxy*>(header);
+
+ DISPID entry_dispid = proxy->GetDispatchId(name, 0);
+ if (entry_dispid == -1) {
+ return false;
+ }
+
+ HRESULT hr = DispatchInvoke(proxy->browser_proxy_, proxy->dispatch_,
+ DISPATCH_METHOD, entry_dispid, args, arg_count,
+ result);
+
+ return SUCCEEDED(hr);
+}
+
+bool DispatchProxy::InvokeDefault(NPObject *header,
+ const NPVariant *args,
+ uint32_t arg_count,
+ NPVariant *result) {
+ DispatchProxy *proxy = static_cast<DispatchProxy*>(header);
+
+ HRESULT hr = DispatchInvoke(proxy->browser_proxy_, proxy->dispatch_,
+ DISPATCH_METHOD, DISPID_VALUE, args,
+ arg_count, result);
+
+ return SUCCEEDED(hr);
+}
+
+bool DispatchProxy::Construct(NPObject *header,
+ const NPVariant *args,
+ uint32_t arg_count,
+ NPVariant *result) {
+ DispatchProxy *proxy = static_cast<DispatchProxy*>(header);
+
+ HRESULT hr = DispatchInvoke(proxy->browser_proxy_, proxy->dispatch_,
+ DISPATCH_CONSTRUCT, DISPID_VALUE, args,
+ arg_count, result);
+
+ return SUCCEEDED(hr);
+}
+
+bool DispatchProxy::HasProperty(NPObject *header, NPIdentifier name) {
+ DispatchProxy *proxy = static_cast<DispatchProxy*>(header);
+ return proxy->GetDispatchId(name, 0) != -1;
+}
+
+bool DispatchProxy::GetPropertyEntry(NPObject *header,
+ NPIdentifier name,
+ NPVariant *variant) {
+ DispatchProxy *proxy = static_cast<DispatchProxy*>(header);
+ DISPID dispatch_id = proxy->GetDispatchId(name, 0);
+ if (dispatch_id == -1) {
+ return false;
+ }
+
+ CComVariant result_value;
+ DISPPARAMS invoke_args = {0};
+ HRESULT hr = proxy->dispatch_->Invoke(dispatch_id, IID_NULL,
+ LOCALE_SYSTEM_DEFAULT,
+ DISPATCH_PROPERTYGET,
+ &invoke_args,
+ &result_value, NULL, 0);
+ if (SUCCEEDED(hr)) {
+ VariantToNPVariant(proxy->browser_proxy_, &result_value, variant);
+ }
+
+ return SUCCEEDED(hr);
+}
+
+bool DispatchProxy::SetPropertyEntry(NPObject *header,
+ NPIdentifier name,
+ const NPVariant *variant) {
+ DispatchProxy *proxy = static_cast<DispatchProxy*>(header);
+ DISPID dispatch_id = proxy->GetDispatchId(name, fdexNameEnsure);
+
+ // Indicate failure if the property does not exist.
+ if (dispatch_id == -1) {
+ return false;
+ }
+
+ CComVariant dispatch_variant;
+ NPVariantToVariant(proxy->browser_proxy_, const_cast<NPVariant*>(variant),
+ &dispatch_variant);
+
+ // Prepare the dispatch arguments for the call. Note that the named
+ // argument DISPID_PROPERTYPUT is required.
+ DISPID put_id = DISPID_PROPERTYPUT;
+ DISPPARAMS invoke_args = {0};
+ invoke_args.cArgs = 1;
+ invoke_args.rgvarg = &dispatch_variant;
+ invoke_args.cNamedArgs = 1;
+ invoke_args.rgdispidNamedArgs = &put_id;
+
+ CComVariant return_arg;
+ HRESULT hr = proxy->dispatch_->Invoke(dispatch_id, IID_NULL,
+ LOCALE_SYSTEM_DEFAULT,
+ DISPATCH_PROPERTYPUT, &invoke_args,
+ &return_arg, NULL, NULL);
+
+ return SUCCEEDED(hr);
+}
+
+bool DispatchProxy::RemovePropertyEntry(NPObject *header,
+ NPIdentifier name) {
+ DispatchProxy *proxy = static_cast<DispatchProxy*>(header);
+ DISPID dispatch_id = proxy->GetDispatchId(name, 0);
+ if (dispatch_id == -1) {
+ return true;
+ }
+
+ HRESULT hr = proxy->dispatch_->DeleteMemberByDispID(dispatch_id);
+
+ return SUCCEEDED(hr);
+}
+
+bool DispatchProxy::EnumeratePropertyEntries(NPObject *header,
+ NPIdentifier **result,
+ uint32_t *count) {
+ DispatchProxy *proxy = static_cast<DispatchProxy*>(header);
+ *result = NULL;
+ *count = 0;
+
+ std::vector<NPIdentifier> np_identifiers;
+ DISPID dispatch_id = DISPID_STARTENUM;
+ for (;;) {
+ HRESULT hr = proxy->dispatch_->GetNextDispID(fdexEnumAll, dispatch_id,
+ &dispatch_id);
+ if (hr == S_FALSE) {
+ *count = np_identifiers.size();
+ *result = static_cast<NPIdentifier*>(
+ proxy->browser_proxy_->GetBrowserFunctions()->memalloc(
+ np_identifiers.size() * sizeof(NPIdentifier)));
+ std::copy(np_identifiers.begin(), np_identifiers.end(), *result);
+ return true;
+ }
+
+ if (FAILED(hr))
+ break;
+
+ CComBSTR name_bstr;
+ hr = proxy->dispatch_->GetMemberName(dispatch_id, &name_bstr);
+ if (FAILED(hr))
+ break;
+
+ CString name_wide((BSTR) name_bstr);
+
+ int utf8_bytes = WideCharToMultiByte(CP_UTF8, 0, name_wide.GetBuffer(),
+ name_wide.GetLength() + 1,
+ NULL, 0, NULL, NULL);
+ scoped_array<NPUTF8> name_utf8(new NPUTF8[utf8_bytes]);
+ WideCharToMultiByte(CP_UTF8, 0, name_wide.GetBuffer(),
+ name_wide.GetLength() + 1,
+ name_utf8.get(), utf8_bytes, NULL, NULL);
+
+ NPIdentifier np_identifier =
+ proxy->browser_proxy_->GetBrowserFunctions()->
+ getstringidentifier(name_utf8.get());
+ np_identifiers.push_back(np_identifier);
+ }
+
+ return false;
+}
+
+NPObject * DispatchProxy::Allocate(NPP npp, NPClass *aClass) {
+ DispatchProxy *instance = new DispatchProxy();
+ instance->_class = aClass;
+ instance->referenceCount = 1;
+ return instance;
+}
+
+void DispatchProxy::Deallocate(NPObject *obj) {
+ DispatchProxy *proxy = static_cast<DispatchProxy*>(obj);
+ ATLASSERT(proxy->referenceCount == 0);
+ delete proxy;
+}
+
+NPClass DispatchProxy::kNPClass = {
+ NP_CLASS_STRUCT_VERSION,
+ Allocate,
+ Deallocate,
+ NULL,
+ HasMethod,
+ InvokeEntry,
+ InvokeDefault,
+ HasProperty,
+ GetPropertyEntry,
+ SetPropertyEntry,
+ RemovePropertyEntry,
+ EnumeratePropertyEntries,
+ Construct
+};
diff --git a/o3d/plugin/npapi_host_control/win/dispatch_proxy.h b/o3d/plugin/npapi_host_control/win/dispatch_proxy.h
new file mode 100644
index 0000000..bb12cc8
--- /dev/null
+++ b/o3d/plugin/npapi_host_control/win/dispatch_proxy.h
@@ -0,0 +1,197 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// File declaring a class providing a wrapper between the NPAPI NPObject
+// interface, and COM's IDispatchEx interface.
+
+#ifndef O3D_PLUGIN_NPAPI_HOST_CONTROL_WIN_DISPATCH_PROXY_H_
+#define O3D_PLUGIN_NPAPI_HOST_CONTROL_WIN_DISPATCH_PROXY_H_
+
+#include <atlctl.h>
+#include <dispex.h>
+
+#include "third_party/npapi/files/include/npupp.h"
+#include "plugin/npapi_host_control/win/np_browser_proxy.h"
+
+class NPBrowserProxy;
+
+// Class implementing a NPAPI interface wrapper around IDispatchEx automation
+// objects.
+class DispatchProxy : public NPObject {
+ public:
+ DispatchProxy(IDispatchEx* dispatch,
+ NPBrowserProxy* browser_proxy);
+ virtual ~DispatchProxy();
+
+ // Returns the NPAPI interface for accessing the instance of the object.
+ static NPClass* GetNPClass() {
+ return &kNPClass;
+ }
+
+ CComPtr<IDispatchEx> GetDispatchEx() const {
+ return dispatch_;
+ }
+
+ void SetBrowserProxy(NPBrowserProxy* browser_proxy) {
+ browser_proxy_ = browser_proxy;
+ }
+
+ private:
+ DispatchProxy() : browser_proxy_(NULL) {}
+
+ // COM object of which this is a proxy.
+ CComPtr<IDispatchEx> dispatch_;
+
+ // Back pointer to the NPAPI browser environment in which the plugin resides.
+ NPBrowserProxy* browser_proxy_;
+
+ // Function to convert NPAPI automation identifiers to COM dispatch ID's.
+ // Parameters:
+ // name: NPAPI identifier for which we are to find the corresponding
+ // dispatch ID.
+ // flags: Flags to pass to GetDispID.
+ // Returns:
+ // A valid dispatch-id if the corresponding member or property exists on
+ // the hosted automation object, -1 otherwise.
+ DISPID GetDispatchId(NPIdentifier name, DWORD flags) const;
+
+ // The following set of static methods implement the NPAPI object interface
+ // for DispatchProxy objects.
+
+ // Function to determine the existance of a scriptable method.
+ // Parameters:
+ // header: 'this' for the function call.
+ // name: NPAPI dispatch identifier associated with the method name.
+ // Returns:
+ // true if the method is found.
+ static bool HasMethod(NPObject *header, NPIdentifier name);
+
+ // Invokes a scriptable method on the object with the given arguments, and
+ // returns a variant result.
+ // Parameters:
+ // header: 'this' for the function call.
+ // name: NPAPI dispatch identifier associated with the method name.
+ // args: Array of NPVariant objects used as arguments for the method call.
+ // arg_count: Number of arguments in args.
+ // result: Pointer to variant receiving the return value of the method.
+ // Returns:
+ // true on successfull invocation of an existing method, false otherwise.
+ static bool InvokeEntry(NPObject *header, NPIdentifier name,
+ const NPVariant *args, uint32_t arg_count,
+ NPVariant *result);
+
+ // Invokes the object with the given arguments, and returns a variant result.
+ // Parameters:
+ // header: function object to call.
+ // args: Array of NPVariant objects used as arguments for the method call.
+ // arg_count: Number of arguments in args.
+ // result: Pointer to variant receiving the return value of the method.
+ // Returns:
+ // true on successfull invocation of an existing method, false otherwise.
+ static bool InvokeDefault(NPObject *header, const NPVariant *args,
+ uint32_t argument_count, NPVariant *result);
+
+ // Invokes an object as a constructor function with the given arguments, and
+ // returns a variant result.
+ // Parameters:
+ // header: function object to call.
+ // args: Array of NPVariant objects used as arguments for the method call.
+ // arg_count: Number of arguments in args.
+ // result: Pointer to variant receiving the return value of the method.
+ // Returns:
+ // true on successfull invocation of an existing method, false otherwise.
+ static bool Construct(NPObject *header, const NPVariant *args,
+ uint32_t argument_count, NPVariant *result);
+
+ // Determines the existence of a scriptable property on the object instance.
+ // Parameters:
+ // header: 'this' for the function call.
+ // name: NPAPI dispatch identifier associated with the propertyname.
+ // Returns:
+ // true if the property exists.
+ static bool HasProperty(NPObject *header, NPIdentifier name);
+
+ // Returns the value of a scriptable property.
+ // Parameters:
+ // header: 'this' for the function call.
+ // name: NPAPI dispatch identifier associated with the propertyname.
+ // variant: Contains the value of the property upon return.
+ // Returns:
+ // true if the property is successfully assigned.
+ static bool GetPropertyEntry(NPObject *header, NPIdentifier name,
+ NPVariant *variant);
+
+ // Assigns the value of a scriptable property.
+ // Parameters:
+ // header: 'this' for the function call.
+ // name: NPAPI dispatch identifier associated with the propertyname.
+ // variant: Value to which the property is to be assigned.
+ // Returns:
+ // true if the property is successfully assigned.
+ static bool SetPropertyEntry(NPObject *header, NPIdentifier name,
+ const NPVariant *variant);
+
+ // Removes a scriptable property.
+ // Parameters:
+ // header: object to remove property from.
+ // name: NPAPI dispatch identifier associated with the propertyname.
+ // Returns:
+ // true if the property is successfully assigned.
+ static bool RemovePropertyEntry(NPObject *header, NPIdentifier name);
+
+ // Returns an enumeration of all properties present on the instance object.
+ // Parameters:
+ // header: 'this' for the function call.
+ // value: Returned pointer to an array of NPidentifers for all of the
+ // properties on the object.
+ // count: The number of elements in the value array.
+ // Returns:
+ // false always. This routine is not implemented.
+ static bool EnumeratePropertyEntries(NPObject *header, NPIdentifier **value,
+ uint32_t *count);
+
+ // Custom class allocation routine.
+ // Parameters:
+ // npp: The plugin instance data.
+ // class_functions: The NPClass function table for the class to construct.
+ static NPObject * Allocate(NPP npp, NPClass *class_functions);
+
+ // Custom destruction routine.
+ static void Deallocate(NPObject *obj);
+
+ // Static V-Table instance for the NPAPI interface for DispatchProxy objects.
+ static NPClass kNPClass;
+
+ DISALLOW_COPY_AND_ASSIGN(DispatchProxy);
+};
+
+#endif // O3D_PLUGIN_NPAPI_HOST_CONTROL_WIN_DISPATCH_PROXY_H_
diff --git a/o3d/plugin/npapi_host_control/win/host_control.cc b/o3d/plugin/npapi_host_control/win/host_control.cc
new file mode 100644
index 0000000..87f2303
--- /dev/null
+++ b/o3d/plugin/npapi_host_control/win/host_control.cc
@@ -0,0 +1,590 @@
+// Copyright 2009, Google Inc. All rights reserved.
+// Portions of this file were adapted from the Mozilla project.
+// See https://developer.mozilla.org/en/ActiveX_Control_for_Hosting_Netscape_Plug-ins_in_IE
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Adam Lock <adamlock@eircom.net>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "plugin/npapi_host_control/win/host_control.h"
+
+#include <mshtml.h>
+
+#include "plugin/npapi_host_control/win/np_plugin_proxy.h"
+#include "plugin/npapi_host_control/win/np_object_proxy.h"
+#include "plugin/npapi_host_control/win/stream_operation.h"
+
+namespace {
+
+// Helper function converting UTF-8 encoded input-string to a NULL-terminated
+// wide-character array.
+HRESULT ConvertMultiByteToWideChar(const char* input_string,
+ scoped_array<wchar_t>* wide_string) {
+ if (!wide_string || !input_string) {
+ return E_INVALIDARG;
+ }
+
+ int required_size = 0;
+ required_size = MultiByteToWideChar(CP_UTF8, 0, input_string, -1, NULL, 0);
+ // Add one extra element so that we may explicitly null-terminate the string.
+ wide_string->reset(new wchar_t[required_size + 1]);
+ if (!wide_string->get()) {
+ return E_FAIL;
+ }
+ MultiByteToWideChar(CP_UTF8, 0, input_string, -1, wide_string->get(),
+ required_size + 1);
+ (*wide_string)[required_size] = 0;
+ return S_OK;
+}
+
+// Helper function that checks a user agent string for 'MSIE', the indicator for
+// Internet Explorer.
+bool IsMSIE(const char* user_agent) {
+ ATLASSERT(user_agent);
+ if (!user_agent) {
+ return false;
+ }
+ static const char* kMSIETag = "MSIE";
+ return strstr(user_agent, kMSIETag) != NULL;
+}
+
+} // unnamed namespace
+
+CHostControl::CHostControl()
+ : browser_proxy_(NULL),
+ plugin_proxy_(NULL),
+ embedded_name_(NULL),
+ user_agent_(NULL) {
+ // Request that this control be windowed.
+ m_bWindowOnly = true;
+}
+
+CHostControl::~CHostControl() {
+}
+
+STDMETHODIMP CHostControl::InterfaceSupportsErrorInfo(REFIID riid) {
+ static const IID* arr[] = {
+ &IID_IHostControl,
+ };
+
+ for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++) {
+ if (InlineIsEqualGUID(*arr[i], riid)) {
+ return S_OK;
+ }
+ }
+ return S_FALSE;
+}
+
+
+const char* CHostControl::GetUserAgent() const {
+ // Capture the user agent on the first call.
+ if (!user_agent_.get()) {
+ CComBSTR user_agent;
+ HRESULT hr = E_FAIL;
+ if (NULL != static_cast<IOmNavigator*>(navigator_)) {
+ hr = navigator_->get_userAgent(&user_agent);
+ }
+ if (SUCCEEDED(hr)) {
+ // Convert to UTF-8 and null terminate the string.
+ int size_required = WideCharToMultiByte(CP_UTF8, 0, user_agent, -1,
+ NULL, NULL, NULL, NULL);
+ user_agent_.reset(new char[size_required + 1]);
+ WideCharToMultiByte(CP_UTF8, 0, user_agent, -1,
+ user_agent_.get(), size_required + 1, NULL, NULL);
+ user_agent_[size_required] = 0;
+ }
+ }
+
+ return user_agent_.get();
+}
+
+LRESULT CHostControl::OnCreate(UINT uMsg,
+ WPARAM wParam,
+ LPARAM lParam,
+ BOOL &bHandled) {
+ NPWindow window = {0};
+ window.window = m_hWnd;
+ CREATESTRUCT *create_struct = reinterpret_cast<CREATESTRUCT*>(lParam);
+ window.type = NPWindowTypeWindow;
+ window.x = create_struct->x;
+ window.y = create_struct->y;
+ window.width = create_struct->cx;
+ window.height = create_struct->cy;
+
+ // Get the web browser through the site the control is attached to.
+ // Note: The control could be running in some other container than IE
+ // so code shouldn't expect this function to work all the time.
+ service_provider_ = m_spClientSite;
+ if (service_provider_ == NULL)
+ return -1;
+
+ if (FAILED(service_provider_->QueryService(IID_IWebBrowserApp,
+ &web_browser_app_))) {
+ return -1;
+ }
+
+ // Navigate the ActiveX interface hierarchy to the IOmNavigator interface.
+ CComPtr<IDispatch> dispatch;
+ if (FAILED(web_browser_app_->get_Document(&dispatch))) {
+ return -1;
+ }
+
+ if (FAILED(dispatch->QueryInterface(&document_dispatch_))) {
+ return -1;
+ }
+
+ if (FAILED(document_dispatch_->QueryInterface(&html_document2_))) {
+ return -1;
+ }
+
+ if (FAILED(document_dispatch_->QueryInterface(&html_document3_))) {
+ return -1;
+ }
+
+ if (FAILED(html_document2_->get_parentWindow(&html_window_))) {
+ return -1;
+ }
+
+ if (FAILED(html_window_->get_navigator(&navigator_))) {
+ return -1;
+ }
+
+ // Only permit the control to create an instance of the hosted plug-in iff
+ // we are presently running in Internet Explorer.
+ if (!IsMSIE(GetUserAgent())) {
+ TearDown();
+ return -1;
+ }
+
+ if (FAILED(html_window_->QueryInterface(&window_dispatch_))) {
+ return -1;
+ }
+
+ // Construct and cache a moniker for the url of the page where the plugin
+ // is hosted.
+ CComBSTR url_string;
+ if (FAILED(html_document2_->get_URL(&url_string))) {
+ return -1;
+ }
+
+ if (FAILED(CreateURLMonikerEx(NULL, url_string, &url_moniker_,
+ URL_MK_UNIFORM))) {
+ return -1;
+ }
+
+ browser_proxy_.reset(new NPBrowserProxy(this, window_dispatch_));
+ if (!plugin_proxy_->Init(browser_proxy_.get(),
+ window,
+ plugin_argument_names_,
+ plugin_argument_values_)) {
+ browser_proxy_.reset();
+ return -1;
+ }
+
+ return 0;
+}
+
+void CHostControl::TearDown() {
+ if (embedded_name_) {
+ SysFreeString(embedded_name_);
+ embedded_name_ = NULL;
+ }
+
+ // Note: We do not delete the plug-in instance here, because we can
+ // re-initialize it on the subsequent WM_CREATE message.
+ if (plugin_proxy_.get()) {
+ plugin_proxy_->TearDown();
+ }
+
+ if (browser_proxy_.get()) {
+ browser_proxy_->TearDown();
+ }
+
+ browser_proxy_.reset();
+ user_agent_.reset();
+
+ url_moniker_ = NULL;
+ window_dispatch_ = NULL;
+ navigator_ = NULL;
+ html_window_ = NULL;
+ html_document3_ = NULL;
+ html_document2_ = NULL;
+ document_dispatch_ = NULL;
+ web_browser_app_ = NULL;
+ service_provider_.Release();
+}
+
+LRESULT CHostControl::OnDestroy(UINT uMsg,
+ WPARAM wParam,
+ LPARAM lParam,
+ BOOL &bHandled) {
+ // OnDestroy processing does not imply that the plug-in is to be permanently
+ // destroyed - IE will send WM_CREATE, WM_DESTROY message pairs multiple times
+ // to the same control instance as it is moved throughout the DOM.
+ // We tear-down the object entirely here, so that it can be fully
+ // reconstructed, if necessary, on the next WM_CREATE.
+ TearDown();
+
+ return 0;
+}
+
+
+HRESULT CHostControl::FinalConstruct() {
+ return ConstructPluginProxy();
+}
+
+
+void CHostControl::FinalRelease() {
+ plugin_proxy_.reset();
+}
+
+HRESULT CHostControl::OpenUrlStream(const wchar_t *url, void *notify_data) {
+ return StreamOperation::OpenURL(plugin_proxy_.get(), url, notify_data);
+}
+
+STDMETHODIMP CHostControl::GetTypeInfoCount(UINT *pctinfo) {
+ if (!pctinfo) {
+ return E_POINTER;
+ } else {
+ *pctinfo = 0;
+ }
+ return S_OK;
+}
+
+STDMETHODIMP CHostControl::GetTypeInfo(UINT itinfo,
+ LCID lcid,
+ ITypeInfo **pptinfo) {
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP CHostControl::GetIDsOfNames(REFIID riid,
+ LPOLESTR *rgszNames,
+ UINT cNames,
+ LCID lcid,
+ DISPID *rgdispid) {
+ // Forward all requests through the typelib before defaulting to the
+ // NPAPI plugin.
+ HRESULT hr = DispatchImpl::GetIDsOfNames(riid, rgszNames, cNames,
+ lcid, rgdispid);
+ if (SUCCEEDED(hr)) {
+ return hr;
+ }
+
+ if (plugin_proxy_.get()) {
+ CComPtr<INPObjectProxy> script_object;
+ hr = plugin_proxy_->GetScriptableObject(&script_object);
+ if (SUCCEEDED(hr)) {
+ return script_object->GetIDsOfNames(riid, rgszNames, cNames, lcid,
+ rgdispid);
+ } else {
+ return hr;
+ }
+ } else {
+ return E_FAIL;
+ }
+}
+
+STDMETHODIMP CHostControl::Invoke(DISPID dispidMember,
+ REFIID riid,
+ LCID lcid,
+ WORD wFlags,
+ DISPPARAMS *pdispparams,
+ VARIANT *pvarResult,
+ EXCEPINFO *pexcepinfo,
+ UINT *puArgErr) {
+ // Forward all Invoke requests through the typelib first.
+ HRESULT hr = DispatchImpl::Invoke(dispidMember, riid, lcid, wFlags,
+ pdispparams, pvarResult, pexcepinfo,
+ puArgErr);
+ if (SUCCEEDED(hr)) {
+ return hr;
+ }
+
+ // Disregard reserved dispatch-ids corresponding to VB/OLE.
+ if (static_cast<int>(dispidMember) < 0)
+ return E_FAIL;
+
+ if (plugin_proxy_.get()) {
+ CComPtr<INPObjectProxy> script_object;
+ hr = plugin_proxy_->GetScriptableObject(&script_object);
+ if (SUCCEEDED(hr)) {
+ return script_object->Invoke(dispidMember, riid, lcid, wFlags,
+ pdispparams, pvarResult, pexcepinfo,
+ puArgErr);
+ } else {
+ return hr;
+ }
+ } else {
+ return E_FAIL;
+ }
+}
+
+STDMETHODIMP CHostControl::DeleteMemberByDispID(DISPID id) {
+ HRESULT hr;
+ if (plugin_proxy_.get()) {
+ CComPtr<INPObjectProxy> script_object;
+ hr = plugin_proxy_->GetScriptableObject(&script_object);
+ if (SUCCEEDED(hr)) {
+ return script_object->DeleteMemberByDispID(id);
+ } else {
+ return hr;
+ }
+ } else {
+ return E_FAIL;
+ }
+}
+
+STDMETHODIMP CHostControl::DeleteMemberByName(BSTR bstrName, DWORD grfdex) {
+ HRESULT hr;
+ if (plugin_proxy_.get()) {
+ CComPtr<INPObjectProxy> script_object;
+ hr = plugin_proxy_->GetScriptableObject(&script_object);
+ if (SUCCEEDED(hr)) {
+ return script_object->DeleteMemberByName(bstrName, grfdex);
+ } else {
+ return hr;
+ }
+ } else {
+ return E_FAIL;
+ }
+}
+
+STDMETHODIMP CHostControl::GetDispID(BSTR bstrName,
+ DWORD grfdex,
+ DISPID* pid) {
+ // Forward all DISPID requests through the typelib before defaulting to the
+ // to the NPAPI plugin.
+ HRESULT hr;
+ if (SUCCEEDED(hr = DispatchImpl::GetIDsOfNames(IID_NULL,
+ &bstrName,
+ 1,
+ LOCALE_SYSTEM_DEFAULT,
+ pid))) {
+ return hr;
+ }
+
+ if (plugin_proxy_.get()) {
+ CComPtr<INPObjectProxy> script_object;
+ hr = plugin_proxy_->GetScriptableObject(&script_object);
+ if (SUCCEEDED(hr)) {
+ return script_object->GetDispID(bstrName, grfdex, pid);
+ } else {
+ return hr;
+ }
+ } else {
+ return E_FAIL;
+ }
+}
+
+STDMETHODIMP CHostControl::GetMemberName(DISPID id,
+ BSTR* pbstrName) {
+ HRESULT hr;
+ if (plugin_proxy_.get()) {
+ CComPtr<INPObjectProxy> script_object;
+ hr = plugin_proxy_->GetScriptableObject(&script_object);
+ if (SUCCEEDED(hr)) {
+ return script_object->GetMemberName(id, pbstrName);
+ } else {
+ return hr;
+ }
+ } else {
+ return E_FAIL;
+ }
+}
+
+STDMETHODIMP CHostControl::GetMemberProperties(DISPID id,
+ DWORD grfdexFetch,
+ DWORD* pgrfdex) {
+ HRESULT hr;
+ if (plugin_proxy_.get()) {
+ CComPtr<INPObjectProxy> script_object;
+ hr = plugin_proxy_->GetScriptableObject(&script_object);
+ if (SUCCEEDED(hr)) {
+ return script_object->GetMemberProperties(id, grfdexFetch, pgrfdex);
+ } else {
+ return hr;
+ }
+ } else {
+ return E_FAIL;
+ }
+}
+
+STDMETHODIMP CHostControl::GetNameSpaceParent(IUnknown** punk) {
+ HRESULT hr;
+ if (plugin_proxy_.get()) {
+ CComPtr<INPObjectProxy> script_object;
+ hr = plugin_proxy_->GetScriptableObject(&script_object);
+ if (SUCCEEDED(hr)) {
+ return script_object->GetNameSpaceParent(punk);
+ } else {
+ return hr;
+ }
+ } else {
+ return E_FAIL;
+ }
+}
+
+STDMETHODIMP CHostControl::GetNextDispID(DWORD grfdex,
+ DISPID id,
+ DISPID* pid) {
+ HRESULT hr;
+ if (plugin_proxy_.get()) {
+ CComPtr<INPObjectProxy> script_object;
+ hr = plugin_proxy_->GetScriptableObject(&script_object);
+ if (SUCCEEDED(hr)) {
+ return script_object->GetNextDispID(grfdex, id, pid);
+ } else {
+ return hr;
+ }
+ } else {
+ return E_FAIL;
+ }
+}
+
+STDMETHODIMP CHostControl::InvokeEx(DISPID id,
+ LCID lcid,
+ WORD wFlags,
+ DISPPARAMS* pdb,
+ VARIANT* pVarRes,
+ EXCEPINFO* pei,
+ IServiceProvider* pspCaller) {
+ // Forward all InvokeEx requests through the typelib
+ HRESULT hr = DispatchImpl::Invoke(id, IID_NULL, lcid, wFlags,
+ pdb, pVarRes, pei,
+ NULL);
+ if (SUCCEEDED(hr)) {
+ return hr;
+ }
+
+ if (plugin_proxy_.get()) {
+ CComPtr<INPObjectProxy> script_object;
+ hr = plugin_proxy_->GetScriptableObject(&script_object);
+ if (SUCCEEDED(hr)) {
+ return script_object->InvokeEx(id, lcid, wFlags, pdb, pVarRes, pei,
+ pspCaller);
+ } else {
+ return hr;
+ }
+ } else {
+ return E_FAIL;
+ }
+}
+
+// Receive the arguments provided to the plug-in in the param-tag.
+STDMETHODIMP CHostControl::Load(IPropertyBag* property_bag,
+ IErrorLog* error_log) {
+ if (!property_bag) {
+ return E_INVALIDARG;
+ }
+
+ // Iterate through all of the properties provided, and register them, in
+ // ASCII-string form with the control.
+ CComQIPtr<IPropertyBag2> property_bag2 = property_bag;
+ if (property_bag2) {
+ ULONG property_count;
+ if (SUCCEEDED(property_bag2->CountProperties(&property_count))) {
+ for (int x = 0; x < property_count; ++x) {
+ PROPBAG2 property = {0};
+ ULONG properties_read = 0;
+ if (SUCCEEDED(property_bag2->GetPropertyInfo(x, 1, &property,
+ &properties_read))) {
+ CComVariant variant;
+ HRESULT prop_hr;
+ if (SUCCEEDED(property_bag2->Read(1, &property, NULL,
+ &variant, &prop_hr))) {
+ if (SUCCEEDED(variant.ChangeType(VT_BSTR))) {
+ USES_CONVERSION;
+ RegisterPluginParameter(OLE2A(property.pstrName),
+ OLE2A(variant.bstrVal));
+ }
+ }
+ // According to the msdn documentation, the name of the property
+ // must be freed through CoTaskMemFree.
+ // See: http://msdn.microsoft.com/en-us/library/aa768191(VS.85).aspx
+ CoTaskMemFree(property.pstrName);
+ }
+ }
+ }
+ }
+
+ return IPersistPropertyBagImpl<CHostControl>::Load(property_bag, error_log);
+}
+
+HRESULT CHostControl::GetStringProperty(NPPVariable np_property_variable,
+ BSTR* string) {
+ HRESULT hr;
+ if (FAILED(hr = ConstructPluginProxy())) {
+ return hr;
+ }
+
+ char* property = NULL;
+ if (NPERR_NO_ERROR != plugin_proxy_->GetPluginFunctions()->getvalue(
+ NULL,
+ np_property_variable,
+ &property)) {
+ return E_FAIL;
+ }
+
+ scoped_array<wchar_t> wide_property;
+ if (FAILED(hr = ConvertMultiByteToWideChar(property, &wide_property))) {
+ return hr;
+ }
+ *string = SysAllocString(wide_property.get());
+ return S_OK;
+}
+
+STDMETHODIMP CHostControl::get_description(BSTR *returned_description) {
+ return GetStringProperty(NPPVpluginDescriptionString, returned_description);
+}
+
+STDMETHODIMP CHostControl::get_name(BSTR *returned_name) {
+ return GetStringProperty(NPPVpluginNameString, returned_name);
+}
+
+HRESULT CHostControl::ConstructPluginProxy() {
+ // If the plugin has already been constructed, then exit early.
+ if (plugin_proxy_.get()) {
+ return S_OK;
+ }
+
+ HRESULT hr;
+ NPPluginProxy* plugin_proxy = NULL;
+ if (FAILED(hr = NPPluginProxy::Create(&plugin_proxy))) {
+ return hr;
+ }
+
+ plugin_proxy_.reset(plugin_proxy);
+ return S_OK;
+}
diff --git a/o3d/plugin/npapi_host_control/win/host_control.h b/o3d/plugin/npapi_host_control/win/host_control.h
new file mode 100644
index 0000000..0cb0075
--- /dev/null
+++ b/o3d/plugin/npapi_host_control/win/host_control.h
@@ -0,0 +1,268 @@
+// Copyright 2009, Google Inc. All rights reserved.
+// Portions of this file were adapted from the Mozilla project.
+// See https://developer.mozilla.org/en/ActiveX_Control_for_Hosting_Netscape_Plug-ins_in_IE
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Adam Lock <adamlock@eircom.net>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+
+// Declares a COM class implementing an ActiveX control capable of hosting
+// an NPAPI plugin on an OLE site.
+
+#ifndef O3D_PLUGIN_NPAPI_HOST_CONTROL_WIN_HOST_CONTROL_H_
+#define O3D_PLUGIN_NPAPI_HOST_CONTROL_WIN_HOST_CONTROL_H_
+
+#include <atlctl.h>
+#include <dispex.h>
+#include <vector>
+
+#include "base/scoped_ptr.h"
+
+// Directory not included, as this file is auto-generated from the
+// type library.
+#include "npapi_host_control.h"
+#include "plugin/npapi_host_control/win/np_browser_proxy.h"
+
+class NPPluginProxy;
+
+// Class implementing an ActiveX control for containing NPAPI plugin-objects.
+class ATL_NO_VTABLE CHostControl
+ : public CComObjectRootEx<CComSingleThreadModel>,
+ public CComCoClass<CHostControl, &CLSID_HostControl>,
+ public CComControl<CHostControl>,
+ // IMPORTANT IMPLEMENTATION NOTE:
+ // Pass 0xFFFF to the major and minor versions of the IDispatchImpl
+ // for trigger the behaviour in CComTypeInfoHolder::GetTI that forces
+ // the type-library to be loaded from the module, not through the
+ // registry.
+ // Without this behaviour, the plug-in fails to load on Vista with UAC
+ // disabled. This is because all processes run at elevated integrity
+ // with UAC disabled. Because the plug-in is registered as a per-user
+ // control (under HKCU), it will fail to load the type-library through
+ // the registry: Elevated processes do not view the contents of the HKCU
+ // hive, so it will appear as if the control was not installed properly.
+ public IDispatchImpl<IHostControl, &IID_IHostControl,
+ &LIBID_npapi_host_controlLib,
+ 0xFFFF,
+ 0xFFFF>,
+ public IOleControlImpl<CHostControl>,
+ public IOleObjectImpl<CHostControl>,
+ public IOleInPlaceActiveObjectImpl<CHostControl>,
+ public IOleInPlaceObjectWindowlessImpl<CHostControl>,
+ public ISupportErrorInfo,
+ public IProvideClassInfo2Impl<&CLSID_HostControl, NULL,
+ &LIBID_npapi_host_controlLib>,
+ public IObjectSafetyImpl<CHostControl,
+ INTERFACESAFE_FOR_UNTRUSTED_CALLER |
+ INTERFACESAFE_FOR_UNTRUSTED_DATA>,
+ public IPersistStreamInitImpl<CHostControl>,
+ public IPersistPropertyBagImpl<CHostControl>,
+ public IPersistStorageImpl<CHostControl>,
+ public IConnectionPointContainerImpl<CHostControl>,
+ public IPropertyNotifySinkCP<CHostControl> {
+ public:
+ CHostControl();
+ virtual ~CHostControl();
+
+DECLARE_OLEMISC_STATUS(OLEMISC_RECOMPOSEONRESIZE |
+ OLEMISC_CANTLINKINSIDE |
+ OLEMISC_INSIDEOUT |
+ OLEMISC_ACTIVATEWHENVISIBLE |
+ OLEMISC_SETCLIENTSITEFIRST
+)
+
+DECLARE_REGISTRY_RESOURCEID(IDR_HOSTCONTROL)
+
+BEGIN_MSG_MAP(CHostControl)
+ MESSAGE_HANDLER(WM_CREATE, OnCreate)
+ MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
+END_MSG_MAP()
+
+BEGIN_CONNECTION_POINT_MAP(CHostControl)
+ CONNECTION_POINT_ENTRY(IID_IPropertyNotifySink)
+END_CONNECTION_POINT_MAP()
+
+// Register this control as safe for initialization and scripting. If these
+// categories are skipped, IE will force the user to permit the control to
+// allow scripting at every page view.
+BEGIN_CATEGORY_MAP(CHostControl)
+ IMPLEMENTED_CATEGORY(CATID_SafeForScripting)
+ IMPLEMENTED_CATEGORY(CATID_SafeForInitializing)
+END_CATEGORY_MAP()
+
+BEGIN_COM_MAP(CHostControl)
+ COM_INTERFACE_ENTRY(IHostControl)
+ COM_INTERFACE_ENTRY(IDispatch)
+ COM_INTERFACE_ENTRY(IDispatchEx)
+ COM_INTERFACE_ENTRY(IOleInPlaceObject)
+ COM_INTERFACE_ENTRY2(IOleWindow, IOleInPlaceObjectWindowless)
+ COM_INTERFACE_ENTRY(IOleInPlaceActiveObject)
+ COM_INTERFACE_ENTRY(IOleControl)
+ COM_INTERFACE_ENTRY(IOleObject)
+ COM_INTERFACE_ENTRY(ISupportErrorInfo)
+ COM_INTERFACE_ENTRY(IProvideClassInfo)
+ COM_INTERFACE_ENTRY(IProvideClassInfo2)
+ COM_INTERFACE_ENTRY(IPersistStreamInit)
+ COM_INTERFACE_ENTRY2(IPersist, IPersistStreamInit)
+ COM_INTERFACE_ENTRY(IPersistPropertyBag)
+ COM_INTERFACE_ENTRY(IPersistStorage)
+ COM_INTERFACE_ENTRY(IConnectionPointContainer)
+END_COM_MAP()
+
+BEGIN_PROP_MAP(CHostControl)
+END_PROP_MAP()
+
+ STDMETHOD(GetTypeInfoCount)(UINT* pctinfo);
+ STDMETHOD(GetTypeInfo)(UINT itinfo, LCID lcid, ITypeInfo** pptinfo);
+ STDMETHOD(GetIDsOfNames)(REFIID riid, LPOLESTR* rgszNames, UINT cNames,
+ LCID lcid, DISPID* rgdispid);
+ STDMETHOD(Invoke)(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags,
+ DISPPARAMS* pdispparams, VARIANT* pvarResult,
+ EXCEPINFO* pexcepinfo, UINT* puArgErr);
+ STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid);
+
+ STDMETHOD(DeleteMemberByDispID)(DISPID id);
+ STDMETHOD(DeleteMemberByName)(BSTR bstrName, DWORD grfdex);
+ STDMETHOD(GetDispID)(BSTR bstrName, DWORD grfdex, DISPID* pid);
+ STDMETHOD(GetMemberName)(DISPID id, BSTR* pbstrName);
+ STDMETHOD(GetMemberProperties)(DISPID id, DWORD grfdexFertch, DWORD* pgrfdex);
+ STDMETHOD(GetNameSpaceParent)(IUnknown** ppunk);
+ STDMETHOD(GetNextDispID)(DWORD grfdex, DISPID id, DISPID* pid);
+ STDMETHOD(InvokeEx)(DISPID id, LCID lcid, WORD wFlags, DISPPARAMS* pdp,
+ VARIANT* pVarRes, EXCEPINFO* pei,
+ IServiceProvider* pspCaller);
+
+ // Method overridden from IPersistPropertyBagImpl.
+ STDMETHOD(Load(IPropertyBag *pPropBag, IErrorLog *pErrorLog));
+
+ // Returns the properties associated with the NPPVpluginNameString, and
+ // NPPVpluginDescriptionString identifiers of the loaded plug-in. These
+ // properties can be used for plug-in introspection and version-dependent
+ // behaviour.
+ STDMETHOD(get_description)(BSTR *returned_description);
+ STDMETHOD(get_name)(BSTR *returned_name);
+
+ LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
+ LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
+
+ // Initiates a data transfer, calling back into the hosted plug-in instance
+ // on status updates. Does not block on the transfer.
+ // Parameters:
+ // url: The url from which to receive data.
+ // notify_data: Opaque handle to data provided by the plug-in instance.
+ // This data will be passed back to the plug-in during
+ // all call-backs.
+ // Returns:
+ // S_OK on success.
+ HRESULT OpenUrlStream(const wchar_t *url, void *notify_data);
+
+ // Returns the user-agent string of the browser hosting the control.
+ // Returns NULL on failure.
+ const char* GetUserAgent() const;
+
+ // Return a moniker representing the url of the page in which the plugin is
+ // contained.
+ IMoniker* GetURLMoniker() const {
+ return url_moniker_;
+ }
+
+ DECLARE_PROTECT_FINAL_CONSTRUCT()
+ HRESULT FinalConstruct();
+ void FinalRelease();
+
+ private:
+ // Performs all of the basic construction of the hosted NPPluginProxy object,
+ // but does not initialize an active instance of the plug-in.
+ HRESULT ConstructPluginProxy();
+
+ // Returns an NPAPI property from the hosted plug-in.
+ // Parameters:
+ // np_property_variable: NPPVariable value corresponding to the property
+ // to return.
+ // string: Pointer to BString that receives the property.
+ // Returns:
+ // S_OK on success.
+ HRESULT GetStringProperty(NPPVariable np_property_variable, BSTR* string);
+
+ // Free all resources allocated when constructing the windowed instance
+ // of the hosted plug-in in OnCreate(...).
+ void TearDown();
+
+ void RegisterPluginParameter(const char *name, const char *value) {
+ ATLASSERT(name && value);
+ plugin_argument_names_.push_back(CStringA(name));
+ plugin_argument_values_.push_back(CStringA(value));
+ }
+
+ // Browser proxy instance used to communicate with the hosted NPAPI plugin.
+ scoped_ptr<NPBrowserProxy> browser_proxy_;
+
+ // Pointer to the plugin being hosted by the control.
+ scoped_ptr<NPPluginProxy> plugin_proxy_;
+
+ // Cached value of the name of the control as it exists in the HTML DOM.
+ BSTR embedded_name_;
+
+ // Cached string representation of the user-agent, initialized by first call
+ // to GetUserAgent.
+ mutable scoped_array<char> user_agent_;
+
+ CComPtr<IWebBrowserApp> web_browser_app_;
+ CComQIPtr<IServiceProvider, &IID_IServiceProvider> service_provider_;
+ CComPtr<IDispatchEx> document_dispatch_;
+ CComPtr<IHTMLDocument2> html_document2_;
+ CComPtr<IHTMLDocument3> html_document3_;
+ CComPtr<IDispatchEx> window_dispatch_;
+ CComPtr<IHTMLWindow2> html_window_;
+ CComPtr<IOmNavigator> navigator_;
+ CComPtr<IMoniker> url_moniker_;
+
+ // Array of strings to be passed as name/value arguments to the NPAPI
+ // plug-in instance during construction in NPP_New.
+ std::vector<CStringA> plugin_argument_names_;
+ std::vector<CStringA> plugin_argument_values_;
+
+ typedef IDispatchImpl<IHostControl, &IID_IHostControl,
+ &LIBID_npapi_host_controlLib,
+ 0xFFFF, 0xFFFF> DispatchImpl;
+
+ DISALLOW_COPY_AND_ASSIGN(CHostControl);
+};
+
+// Register this COM class with the COM module.
+OBJECT_ENTRY_AUTO(__uuidof(HostControl), CHostControl);
+
+#endif // O3D_PLUGIN_NPAPI_HOST_CONTROL_WIN_HOST_CONTROL_H_
diff --git a/o3d/plugin/npapi_host_control/win/host_control.rgs b/o3d/plugin/npapi_host_control/win/host_control.rgs
new file mode 100644
index 0000000..5aa4a7e
--- /dev/null
+++ b/o3d/plugin/npapi_host_control/win/host_control.rgs
@@ -0,0 +1,42 @@
+HKCU
+{
+ Software
+ {
+ Classes
+ {
+ o3d_host.O3DHostControl.1 = s 'O3DHostControl Class'
+ {
+ CLSID = s '{9666A772-407E-4F90-BC37-982E8160EB2D}'
+ 'Insertable'
+ }
+ o3d_host.O3DHostControl = s 'O3DHostControl Class'
+ {
+ CLSID = s '{9666A772-407E-4F90-BC37-982E8160EB2D}'
+ CurVer = s 'o3d_host.O3DHostControl.1'
+ }
+ NoRemove CLSID
+ {
+ ForceRemove {9666A772-407E-4F90-BC37-982E8160EB2D} = s 'O3DHostControl Class'
+ {
+ ProgID = s 'o3d_host.O3DHostControl.1'
+ VersionIndependentProgID = s 'o3d_host.O3DHostControl'
+ ForceRemove 'Programmable'
+ InprocServer32 = s '%MODULE%'
+ {
+ val ThreadingModel = s 'Apartment'
+ }
+ val AppID = s '%APPID%'
+ ForceRemove 'Control'
+ ForceRemove 'Insertable'
+ ForceRemove 'ToolboxBitmap32' = s '%MODULE%, 102'
+ 'MiscStatus' = s '0'
+ {
+ '1' = s '%OLEMISC%'
+ }
+ 'TypeLib' = s '{D4F6E31C-E952-48FE-9833-6AE308BD79C6}'
+ 'Version' = s '1.0'
+ }
+ }
+ }
+ }
+}
diff --git a/o3d/plugin/npapi_host_control/win/module.h b/o3d/plugin/npapi_host_control/win/module.h
new file mode 100644
index 0000000..5074504
--- /dev/null
+++ b/o3d/plugin/npapi_host_control/win/module.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// This file contains the ATL module class used by the O3D host ActiveX control.
+
+#ifndef O3D_PLUGIN_NPAPI_HOST_CONTROL_WIN_MODULE_H_
+#define O3D_PLUGIN_NPAPI_HOST_CONTROL_WIN_MODULE_H_
+
+#include "npapi_host_control.h"
+
+class NPAPIHostControlModule : public CAtlDllModuleT<NPAPIHostControlModule> {
+ public:
+ NPAPIHostControlModule() { InitializeCriticalSection(&cs_); }
+ virtual ~NPAPIHostControlModule() { DeleteCriticalSection(&cs_); }
+
+ // Routine used to serialize threads executing within the control. Enters
+ // a critical section shared for the process hosting the control.
+ static void LockModule() {
+ EnterCriticalSection(&GetGlobalInstance()->cs_);
+ }
+
+ // Routine used to serialize threads executing within the control. Leaves
+ // the critical section entered in lock_module().
+ static void UnlockModule() {
+ LeaveCriticalSection(&GetGlobalInstance()->cs_);
+ }
+
+ // Accessor routine for the global pointer _pAtlModule maintained by ATL.
+ static NPAPIHostControlModule* GetGlobalInstance() {
+ return static_cast<NPAPIHostControlModule*>(_pAtlModule);
+ }
+
+ DECLARE_LIBID(LIBID_npapi_host_controlLib)
+ private:
+ CRITICAL_SECTION cs_;
+ DISALLOW_COPY_AND_ASSIGN(NPAPIHostControlModule);
+};
+
+#endif // O3D_PLUGIN_NPAPI_HOST_CONTROL_WIN_MODULE_H_
diff --git a/o3d/plugin/npapi_host_control/win/np_browser_proxy.cc b/o3d/plugin/npapi_host_control/win/np_browser_proxy.cc
new file mode 100644
index 0000000..8d93be9
--- /dev/null
+++ b/o3d/plugin/npapi_host_control/win/np_browser_proxy.cc
@@ -0,0 +1,812 @@
+// Copyright 2009, Google Inc. All rights reserved.
+// Portions of this file were adapted from the Mozilla project.
+// See https://developer.mozilla.org/en/ActiveX_Control_for_Hosting_Netscape_Plug-ins_in_IE
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Adam Lock <adamlock@eircom.net>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include <atlstr.h>
+
+#include <string>
+#include <set>
+
+#include "plugin/npapi_host_control/win/host_control.h"
+#include "plugin/npapi_host_control/win/variant_utils.h"
+
+namespace {
+
+// Helper routine that invokes the host-control stream request function.
+NPError OpenURL(NPBrowserProxy* browser_proxy,
+ const char *szURL,
+ const char *szTarget,
+ void *pNotifyData) {
+ CHostControl* host_control = browser_proxy->GetHostingControl();
+
+ USES_CONVERSION;
+ HRESULT hr = host_control->OpenUrlStream(A2CW(szURL), pNotifyData);
+ return SUCCEEDED(hr) ? NPERR_NO_ERROR : NPERR_GENERIC_ERROR;
+}
+} // unnamed namespace
+
+NPNetscapeFuncs NPBrowserProxy::kNetscapeFunctions = {
+ sizeof(kNetscapeFunctions),
+ NP_VERSION_MAJOR << 8 | NP_VERSION_MINOR,
+ NPN_GetURL,
+ NPN_PostURL,
+ NPN_RequestRead,
+ NPN_NewStream,
+ NPN_Write,
+ NPN_DestroyStream,
+ NPN_Status,
+ NPN_UserAgent,
+ NPN_MemAlloc,
+ NPN_MemFree,
+ NPN_MemFlush,
+ NPN_ReloadPlugins,
+ NPN_GetJavaEnv,
+ NPN_GetJavaPeer,
+ NPN_GetURLNotify,
+ NPN_PostURLNotify,
+ NPN_GetValue,
+ NPN_SetValue,
+ NPN_InvalidateRect,
+ NPN_InvalidateRegion,
+ NPN_ForceRedraw,
+ NPN_GetStringIdentifier,
+ NPN_GetStringIdentifiers,
+ NPN_GetIntIdentifier,
+ NPN_IdentifierIsString,
+ NPN_UTF8FromIdentifier,
+ NPN_IntFromIdentifier,
+ NPN_CreateObject,
+ NPN_RetainObject,
+ NPN_ReleaseObject,
+ NPN_Invoke,
+ NPN_InvokeDefault,
+ NPN_Evaluate,
+ NPN_GetProperty,
+ NPN_SetProperty,
+ NPN_RemoveProperty,
+ NPN_HasProperty,
+ NPN_HasMethod,
+ NPN_ReleaseVariantValue,
+ NPN_SetException,
+ NULL,
+ NULL,
+ NPN_Enumerate,
+};
+
+NPBrowserProxy::NPBrowserProxy(CHostControl* host, IDispatchEx* window_dispatch)
+ : host_control_(host) {
+ vwindow_object_ = new DispatchProxy(window_dispatch, this);
+
+ CComPtr<IUnknown> unknown_identity;
+ HRESULT hr = window_dispatch->QueryInterface(&unknown_identity);
+ ATLASSERT(SUCCEEDED(hr));
+
+ dispatch_proxy_map_[unknown_identity] = vwindow_object_;
+ call_identifier_ = NPN_GetStringIdentifier("call");
+}
+
+NPBrowserProxy::~NPBrowserProxy() {
+ for (NPObjectProxyMap::iterator it = np_object_proxy_map_.begin();
+ it != np_object_proxy_map_.end(); ++it) {
+ it->second->SetBrowserProxy(NULL);
+ }
+ for (DispatchProxyMap::iterator it = dispatch_proxy_map_.begin();
+ it != dispatch_proxy_map_.end(); ++it) {
+ it->second->SetBrowserProxy(NULL);
+ GetBrowserFunctions()->releaseobject(it->second);
+ }
+}
+
+CComPtr<IDispatchEx> NPBrowserProxy::GetDispatchObject(NPObject* np_object) {
+ if (np_object == NULL) {
+ return CComPtr<IDispatchEx>();
+ }
+
+ // If the NPObject is already wrapping an IDispatchEx interface, then
+ // return that interface directly.
+ if (np_object->_class == DispatchProxy::GetNPClass()) {
+ DispatchProxy *dispatch_proxy =
+ static_cast<DispatchProxy*>(np_object);
+ return dispatch_proxy->GetDispatchEx();
+ } else {
+ // If the NPObject already has a proxy then return that.
+ NPObjectProxyMap::iterator it = np_object_proxy_map_.find(np_object);
+ if (it != np_object_proxy_map_.end()) {
+ CComPtr<IDispatchEx> dispatch_ex(NULL);
+ HRESULT hr = it->second.QueryInterface(&dispatch_ex);
+ if (SUCCEEDED(hr)) {
+ return dispatch_ex;
+ } else {
+ return NULL;
+ }
+ }
+
+ // Create a new NPObject proxy, register it for future use and return it.
+ CComPtr<INPObjectProxy> proxy_wrapper;
+ HRESULT hr = NPObjectProxy::CreateInstance(&proxy_wrapper);
+ if (SUCCEEDED(hr)) {
+ proxy_wrapper->SetBrowserProxy(this);
+ proxy_wrapper->SetHostedObject(np_object);
+ RegisterNPObjectProxy(np_object, proxy_wrapper);
+
+ CComPtr<IDispatchEx> dispatch_proxy_wrapper;
+ hr = proxy_wrapper.QueryInterface(&dispatch_proxy_wrapper);
+ ATLASSERT(SUCCEEDED(hr));
+ return dispatch_proxy_wrapper;
+ }
+ }
+ return CComPtr<IDispatchEx>();
+}
+
+NPObject* NPBrowserProxy::GetNPObject(IDispatch* dispatch_object) {
+ if (dispatch_object == NULL)
+ return NULL;
+
+ // If the COM object is already wrapping an NPObject then return that NPObject
+ // directly.
+ NPObject* np_object;
+ CComPtr<INPObjectProxy> np_object_proxy;
+ if (SUCCEEDED(dispatch_object->QueryInterface(&np_object_proxy))) {
+ if (SUCCEEDED(np_object_proxy->GetNPObjectInstance(
+ reinterpret_cast<void**>(&np_object))))
+ return np_object;
+ else
+ return NULL;
+ } else {
+ CComPtr<IUnknown> unknown_identity;
+ if (FAILED(dispatch_object->QueryInterface(&unknown_identity))) {
+ return NULL;
+ }
+
+ // If the COM object already has a proxy then return that. Note that the
+ // map is keyed on IUnknown ptrs - this is because COM explicitly states
+ // that the IUnknown interface is the only reliable identity mechanism.
+ DispatchProxyMap::iterator it = dispatch_proxy_map_.find(unknown_identity);
+ if (it != dispatch_proxy_map_.end()) {
+ GetBrowserFunctions()->retainobject(it->second);
+ return it->second;
+ }
+
+ // Create a new DispatchProxy.
+ CComPtr<IDispatchEx> dispatchex_object;
+ if (FAILED(dispatch_object->QueryInterface(&dispatchex_object))) {
+ return NULL;
+ }
+ DispatchProxy* dispatch_proxy = new DispatchProxy(dispatchex_object,
+ this);
+ dispatch_proxy_map_[unknown_identity] = dispatch_proxy;
+ return dispatch_proxy;
+ }
+}
+
+void NPBrowserProxy::RegisterNPObjectProxy(
+ NPObject* np_object,
+ const CComPtr<INPObjectProxy>& proxy_wrapper) {
+ np_object_proxy_map_[np_object] = proxy_wrapper;
+}
+
+void NPBrowserProxy::UnregisterNPObjectProxy(NPObject* np_object) {
+ np_object_proxy_map_.erase(np_object);
+}
+
+void NPBrowserProxy::UnregisterDispatchProxy(IDispatchEx* dispatch_object) {
+ CComPtr<IUnknown> unknown_identity;
+ HRESULT hr = dispatch_object->QueryInterface(&unknown_identity);
+ ATLASSERT(SUCCEEDED(hr));
+ if (!SUCCEEDED(hr)) {
+ return;
+ }
+
+ DispatchProxyMap::iterator it = dispatch_proxy_map_.find(unknown_identity);
+ ATLASSERT(it != dispatch_proxy_map_.end());
+ GetBrowserFunctions()->releaseobject(it->second);
+ dispatch_proxy_map_.erase(it);
+}
+
+NPError NPBrowserProxy::NPN_GetURL(NPP npp,
+ const char* relativeURL,
+ const char* target) {
+ if (!npp) {
+ return NPERR_INVALID_INSTANCE_ERROR;
+ }
+ ATLASSERT(false && "NPN_GetURL not implemented");
+ return NPERR_NO_ERROR;
+}
+
+
+NPError NPBrowserProxy::NPN_GetURLNotify(NPP npp,
+ const char* relativeURL,
+ const char* target,
+ void* notifyData) {
+ if (!npp) {
+ return NPERR_INVALID_INSTANCE_ERROR;
+ }
+
+ NPBrowserProxy *browser_proxy = static_cast<NPBrowserProxy*>(npp->ndata);
+ return OpenURL(browser_proxy, relativeURL, target, notifyData);
+}
+
+
+
+NPError NPBrowserProxy::NPN_PostURLNotify(NPP npp,
+ const char *relativeURL,
+ const char *target,
+ uint32 len,
+ const char *buf,
+ NPBool file,
+ void *notifyData) {
+ if (!npp) {
+ return NPERR_INVALID_INSTANCE_ERROR;
+ }
+ ATLASSERT(false && "NPN_PostURLNotify not implemented.");
+ return NPERR_NO_ERROR;
+}
+
+NPError NPBrowserProxy::NPN_PostURL(NPP npp,
+ const char *relativeURL,
+ const char *target,
+ uint32 len,
+ const char *buf,
+ NPBool file) {
+ if (!npp) {
+ return NPERR_INVALID_INSTANCE_ERROR;
+ }
+ ATLASSERT(false && "NPN_PostURL not implemented.");
+ return NPERR_NO_ERROR;
+}
+
+NPError NPBrowserProxy::NPN_NewStream(NPP npp,
+ NPMIMEType type,
+ const char* window,
+ NPStream* *result) {
+ if (!npp) {
+ return NPERR_INVALID_INSTANCE_ERROR;
+ }
+ ATLASSERT(false && "NPN_NewStream not implemented.");
+ return NPERR_GENERIC_ERROR;
+}
+
+
+int32 NPBrowserProxy::NPN_Write(NPP npp,
+ NPStream *pstream,
+ int32 len,
+ void *buffer) {
+ if (!npp) {
+ return NPERR_INVALID_INSTANCE_ERROR;
+ }
+ ATLASSERT(false && "NPN_Write not implemented.");
+ return NPERR_GENERIC_ERROR;
+}
+
+NPError NPBrowserProxy::NPN_DestroyStream(NPP npp,
+ NPStream *pstream,
+ NPError reason) {
+ if (!npp) {
+ return NPERR_INVALID_INSTANCE_ERROR;
+ }
+ ATLASSERT(false && "NPN_DestroyStream not implemented.");
+ return NPERR_GENERIC_ERROR;
+}
+
+void NPBrowserProxy::NPN_Status(NPP npp, const char *message) {
+ if (!npp) {
+ return;
+ }
+}
+
+void *NPBrowserProxy::NPN_MemAlloc(uint32 size) {
+ return malloc(size);
+}
+
+void NPBrowserProxy::NPN_MemFree(void *ptr) {
+ if (ptr) {
+ free(ptr);
+ }
+}
+
+uint32 NPBrowserProxy::NPN_MemFlush(uint32 size) {
+ return 0;
+}
+
+void NPBrowserProxy::NPN_ReloadPlugins(NPBool reloadPages) {
+ ATLASSERT(false && "NPN_ReloadPlugins not implemented.");
+}
+
+void NPBrowserProxy::NPN_InvalidateRect(NPP npp, NPRect *invalidRect) {
+ if (!npp) {
+ return;
+ }
+ ATLASSERT(false && "NPN_InvalidateRect not implemented.");
+}
+
+void NPBrowserProxy::NPN_InvalidateRegion(NPP npp, NPRegion invalidRegion) {
+ if (!npp) {
+ return;
+ }
+ ATLASSERT(false && "NPN_InvalidateRect not implemented.");
+}
+
+void NPBrowserProxy::NPN_ForceRedraw(NPP npp) {
+ if (!npp) {
+ return;
+ }
+ ATLASSERT(false && "NPN_ForceRedraw not implemented.");
+}
+
+NPError NPBrowserProxy::NPN_GetValue(NPP npp,
+ NPNVariable variable,
+ void *result) {
+ if (!npp) {
+ return NPERR_INVALID_INSTANCE_ERROR;
+ }
+
+ if (!result) {
+ return NPERR_INVALID_PARAM;
+ }
+
+ NPBrowserProxy *browser_proxy = static_cast<NPBrowserProxy*>(npp->ndata);
+ ATLASSERT(browser_proxy);
+
+ switch (variable) {
+ case NPNVxDisplay :
+ return NPERR_GENERIC_ERROR;
+ case NPNVnetscapeWindow:
+ *(static_cast<HWND*>(result)) =
+ browser_proxy->GetHostingControl()->m_hWnd;
+ break;
+ case NPNVjavascriptEnabledBool :
+ *(static_cast<NPBool*>(result)) = TRUE;
+ break;
+ case NPNVasdEnabledBool :
+ *(static_cast<NPBool*>(result)) = FALSE;
+ break;
+ case NPNVisOfflineBool :
+ *(reinterpret_cast<NPBool*>(result)) = FALSE;
+ break;
+ case NPNVWindowNPObject :
+ ++browser_proxy->GetVWindowObject()->referenceCount;
+ *(static_cast<NPObject**>(result)) =
+ browser_proxy->GetVWindowObject();
+ break;
+ case NPNVPluginElementNPObject :
+ ATLASSERT(false && "NPNVPluginElementNPObject not supported.");
+ return NPERR_GENERIC_ERROR;
+ default:
+ ATLASSERT(false && "Unrecognized NPN_GetValue request.");
+ return NPERR_GENERIC_ERROR;
+ }
+
+ return NPERR_NO_ERROR;
+}
+
+NPError NPBrowserProxy::NPN_SetValue(NPP npp,
+ NPPVariable variable,
+ void *result) {
+ if (!npp) {
+ return NPERR_INVALID_INSTANCE_ERROR;
+ }
+ ATLASSERT(false && "NPN_SetValue not implemented.");
+ return NPERR_GENERIC_ERROR;
+}
+
+NPError NPBrowserProxy::NPN_RequestRead(NPStream *pstream,
+ NPByteRange *rangeList) {
+ if (!pstream || !rangeList || !pstream->ndata) {
+ return NPERR_INVALID_PARAM;
+ }
+ ATLASSERT(false && "NPN_RequestRead not implemented.");
+ return NPERR_GENERIC_ERROR;
+}
+
+void* NPBrowserProxy::NPN_GetJavaEnv() {
+ return NULL;
+}
+
+
+const char* NPBrowserProxy::NPN_UserAgent(NPP npp) {
+ if (!npp) {
+ return "";
+ }
+
+ NPBrowserProxy *browser_proxy = static_cast<NPBrowserProxy*>(npp->ndata);
+ ATLASSERT(browser_proxy);
+ return browser_proxy->GetHostingControl()->GetUserAgent();
+}
+
+void* NPBrowserProxy::NPN_GetJavaClass(void* handle) {
+ return NULL;
+}
+
+void* NPBrowserProxy::NPN_GetJavaPeer(NPP npp) {
+ return NULL;
+}
+
+NPObject* NPBrowserProxy::NPN_CreateObject(NPP npp,
+ NPClass *aClass) {
+ if (!npp || !aClass) {
+ return NULL;
+ }
+
+ NPObject *new_object = NULL;
+
+ // If the class exports a custom allocation routine, then invoke that.
+ if (aClass->allocate) {
+ new_object = aClass->allocate(npp, aClass);
+ new_object->_class = aClass;
+ } else {
+ new_object = new NPObject;
+ new_object->_class = aClass;
+ }
+
+ new_object->referenceCount = 1;
+
+ return new_object;
+}
+
+NPObject * NPBrowserProxy::NPN_RetainObject(NPObject *obj) {
+ if (obj) {
+ ++obj->referenceCount;
+ }
+ return obj;
+}
+
+
+void NPBrowserProxy::NPN_ReleaseObject(NPObject *object) {
+ if (object) {
+ if (0 == --object->referenceCount) {
+ if (object->_class->deallocate) {
+ object->_class->deallocate(object);
+ } else {
+ delete object;
+ }
+ }
+ }
+}
+
+// Disable warnings concerning reinterpret casts to un-related pointer types
+// for the below functions.
+#pragma warning(push)
+#pragma warning(disable:4312)
+#pragma warning(disable:4311)
+
+namespace {
+const uint32_t kNPIdentifierIntFlag = 0x1;
+}
+
+NPIdentifier NPBrowserProxy::NPN_GetStringIdentifier(const NPUTF8 *name) {
+ // Note that this routine returns the address of the string as it is stored
+ // in a set. This implies that any virtual address value could be the
+ // returned identifier. The name & description properties of the CHostControl
+ // object will not conflict with these, because they are within the VMA region
+ // that is unmapped.
+ static std::set<std::string> identifiers;
+ std::string std_name(name);
+ std::pair<std::set<std::string>::iterator, bool> result =
+ identifiers.insert(std_name);
+ const std::string& key = *(result.first);
+ uint32_t tag = reinterpret_cast<uint32_t>(&key);
+ ATLASSERT(0 == (tag & kNPIdentifierIntFlag));
+ return reinterpret_cast<NPIdentifier>(tag);
+}
+
+void NPBrowserProxy::NPN_GetStringIdentifiers(const NPUTF8 **names,
+ int32_t nameCount,
+ NPIdentifier *identifiers) {
+ for (int x = 0; x < nameCount; ++x) {
+ identifiers[x] = NPN_GetStringIdentifier(names[x]);
+ }
+}
+
+NPUTF8 * NPBrowserProxy::NPN_UTF8FromIdentifier(NPIdentifier identifier) {
+ ATLASSERT(identifier != NULL);
+ int32_t tag = reinterpret_cast<uint32_t>(identifier);
+ if (0 == (tag & kNPIdentifierIntFlag)) {
+ const std::string* key = reinterpret_cast<const std::string*>(tag);
+ NPUTF8* identifier_value = static_cast<NPUTF8*>(
+ NPN_MemAlloc(static_cast<uint32_t>(key->length() + 1)));
+ memcpy(identifier_value, key->c_str(), key->length() + 1);
+ return identifier_value;
+ } else {
+ // This is not a standard feature of NPN_UTF8FromIdentifier. Normally you
+ // cannot convert an integer identifier to a string. We support it here
+ // because IE and COM represent integer identifiers as strings in places.
+ // For example, if IDispathEx::GetMemberName is invoked with an id for
+ // an integer indexed property, the only things to do are return a
+ // string representation of the integer or an error.
+ CStringA string;
+ string.Format("%d", tag >> 1);
+ NPUTF8* identifier_value = static_cast<NPUTF8*>(
+ NPN_MemAlloc(string.GetLength() + 1));
+ memcpy(identifier_value, string.GetBuffer(), string.GetLength() + 1);
+ return identifier_value;
+ }
+}
+
+NPIdentifier NPBrowserProxy::NPN_GetIntIdentifier(int32_t intid) {
+ ATLASSERT(intid <= 0x7FFFFFFF);
+ return reinterpret_cast<NPIdentifier>((intid << 1) | kNPIdentifierIntFlag);
+}
+
+int32_t NPBrowserProxy::NPN_IntFromIdentifier(NPIdentifier identifier) {
+ ATLASSERT(identifier != NULL);
+ int32_t tag = reinterpret_cast<int32_t>(identifier);
+ ATLASSERT(kNPIdentifierIntFlag == (tag & kNPIdentifierIntFlag));
+ return tag >> 1;
+}
+
+bool NPBrowserProxy::NPN_IdentifierIsString(NPIdentifier identifier) {
+ ATLASSERT(identifier != NULL);
+ uint32_t tag = reinterpret_cast<uint32_t>(identifier);
+ return (tag & kNPIdentifierIntFlag) == 0;
+}
+
+#pragma warning(pop)
+
+void NPBrowserProxy::NPN_ReleaseVariantValue(NPVariant *variant) {
+ switch (variant->type) {
+ case NPVariantType_Void:
+ case NPVariantType_Null:
+ case NPVariantType_Bool:
+ case NPVariantType_Int32:
+ case NPVariantType_Double:
+ break;
+ case NPVariantType_String:
+ NPN_MemFree(
+ const_cast<NPUTF8*>(variant->value.stringValue.utf8characters));
+ break;
+ case NPVariantType_Object:
+ NPN_ReleaseObject(variant->value.objectValue);
+ break;
+ default:
+ ATLASSERT(false && "Unrecognized NPVariant type.");
+ break;
+ }
+}
+
+bool NPBrowserProxy::NPN_GetProperty(NPP npp,
+ NPObject *obj,
+ NPIdentifier propertyName,
+ NPVariant *result) {
+ if (!npp || !obj || !obj->_class->getProperty) {
+ return false;
+ }
+ return obj->_class->getProperty(obj, propertyName, result);
+}
+
+bool NPBrowserProxy::NPN_SetProperty(NPP npp,
+ NPObject *obj,
+ NPIdentifier propertyName,
+ const NPVariant *value) {
+ if (!npp || !obj || !obj->_class->setProperty) {
+ return false;
+ }
+ return obj->_class->setProperty(obj, propertyName, value);
+}
+
+bool NPBrowserProxy::NPN_HasProperty(NPP npp,
+ NPObject *npobj,
+ NPIdentifier propertyName) {
+ if (!npp || !npobj || !npobj->_class->hasProperty) {
+ return false;
+ }
+ return npobj->_class->hasProperty(npobj, propertyName);
+}
+
+bool NPBrowserProxy::NPN_RemoveProperty(NPP npp,
+ NPObject *npobj,
+ NPIdentifier propertyName) {
+ if (!npp || !npobj || !npobj->_class->removeProperty) {
+ return false;
+ }
+ return npobj->_class->removeProperty(npobj, propertyName);
+}
+
+bool NPBrowserProxy::NPN_HasMethod(NPP npp,
+ NPObject *npobj,
+ NPIdentifier methodName) {
+ if (!npp || !npobj || !npobj->_class->hasMethod) {
+ return false;
+ }
+ return npobj->_class->hasMethod(npobj, methodName);
+}
+
+bool NPBrowserProxy::NPN_Invoke(NPP npp,
+ NPObject *obj,
+ NPIdentifier methodName,
+ const NPVariant *args,
+ unsigned argCount,
+ NPVariant *result) {
+ if (!npp || !obj || !obj->_class->invoke) {
+ return false;
+ }
+ return obj->_class->invoke(obj, methodName, args, argCount, result);
+}
+
+bool NPBrowserProxy::NPN_InvokeDefault(NPP npp,
+ NPObject *obj,
+ const NPVariant *args,
+ unsigned argCount,
+ NPVariant *result) {
+ if (!npp || !obj || !obj->_class->invokeDefault) {
+ return false;
+ }
+ return obj->_class->invokeDefault(obj, args, argCount, result);
+}
+
+bool NPBrowserProxy::NPN_Construct(NPP npp,
+ NPObject *obj,
+ const NPVariant *args,
+ unsigned argCount,
+ NPVariant *result) {
+ if (!npp || !obj || !obj->_class->construct) {
+ return false;
+ }
+ return obj->_class->construct(obj, args, argCount, result);
+}
+
+bool NPBrowserProxy::NPN_Enumerate(NPP npp,
+ NPObject* obj,
+ NPIdentifier** ids,
+ uint32_t* idCount) {
+ if (!npp || !obj || !obj->_class->enumerate || !ids || !idCount) {
+ return false;
+ }
+ return obj->_class->enumerate(obj, ids, idCount);
+}
+
+// Construct a new JavaScript object using the given global constructor
+// and argument values.
+bool NPBrowserProxy::ConstructObject(NPP npp,
+ NPObject* window_object,
+ NPUTF8* constructor_name,
+ NPVariant* args,
+ uint32_t numArgs,
+ NPObject** result) {
+ bool success = false;
+ NPIdentifier constructor_identifier = NPN_GetStringIdentifier(
+ constructor_name);
+ NPVariant constructor_variant;
+ if (NPN_GetProperty(npp, window_object, constructor_identifier,
+ &constructor_variant)) {
+ if (NPVARIANT_IS_OBJECT(constructor_variant)) {
+ NPObject* constructor_object = NPVARIANT_TO_OBJECT(constructor_variant);
+ if (constructor_object != NULL) {
+ NPVariant object_variant;
+ if (NPN_InvokeDefault(npp, constructor_object, args, numArgs,
+ &object_variant)) {
+ if (NPVARIANT_IS_OBJECT(object_variant)) {
+ *result = NPVARIANT_TO_OBJECT(object_variant);
+ NPN_RetainObject(*result);
+ success = true;
+ }
+ NPN_ReleaseVariantValue(&object_variant);
+ }
+ }
+ }
+ NPN_ReleaseVariantValue(&constructor_variant);
+ }
+ return success;
+}
+
+bool NPBrowserProxy::NPN_Evaluate(NPP npp,
+ NPObject *obj,
+ NPString *script,
+ NPVariant *result) {
+ if (!npp || !obj || !script) {
+ return false;
+ }
+
+ NPBrowserProxy *browser_proxy = static_cast<NPBrowserProxy*>(npp->ndata);
+ CHostControl *host_control = browser_proxy->GetHostingControl();
+ ATLASSERT(host_control);
+
+ NPObject* window_object = browser_proxy->GetVWindowObject();
+ if (obj != window_object) {
+ return false;
+ }
+
+ // Causing IE to run JavaScript code is straightforward if you don't need the
+ // result of the evaluation. You can just call IHTMLWindow::execScript. It
+ // does not return a valid result though (it specifically says that on MSDN).
+ //
+ // I tried two other approaches, both of which had the same issue: they didn't
+ // return the result. The first unsuccessul approach was to get the "eval"
+ // propery of the window object and invoke it as a function with the JS code
+ // as the argument. That returns no result. The second unsuccessful approach
+ // was to get the "Function" constructor from the window object and invoke it
+ // with the JS code as an argument. That should give you a function object and
+ // invoking it should evaluate the JS code and return the result. It does not
+ // return a result.
+ //
+ // The final approach (which worked) is to create a Function that additionally
+ // takes a temporary object as an argument. The JS code is modified to assign
+ // its result to a property of that temporary object called "result". After
+ // evaluating the function, the result can then be retrieved from the
+ // temporary object.
+ bool success = false;
+ NPObject* result_object;
+ if (ConstructObject(npp, window_object, "Object", NULL, 0, &result_object)) {
+ CStringA function_code;
+ function_code.Format("result_object.result = (%s);",
+ script->utf8characters);
+
+ NPVariant args[2];
+ STRINGZ_TO_NPVARIANT("result_object", args[0]);
+ STRINGN_TO_NPVARIANT(function_code.GetBuffer(),
+ (uint32_t) function_code.GetLength(),
+ args[1]);
+ NPObject* function_object;
+ if (ConstructObject(npp, window_object, "Function", args, 2,
+ &function_object)) {
+ OBJECT_TO_NPVARIANT(result_object, args[0]);
+ NPVariant dummy_result;
+ if (NPN_InvokeDefault(npp, function_object, args, 1, &dummy_result)) {
+ NPIdentifier result_identifier = NPN_GetStringIdentifier("result");
+ if (NPN_GetProperty(npp, result_object, result_identifier, result)) {
+ success = true;
+ }
+ NPN_ReleaseVariantValue(&dummy_result);
+ }
+ NPN_ReleaseObject(function_object);
+ }
+ NPN_ReleaseObject(result_object);
+ }
+ return success;
+}
+
+void NPBrowserProxy::NPN_SetException(NPObject *obj,
+ const NPUTF8 *message) {
+ ATLASSERT(false && "NPN_SetException not implemented");
+}
+
+NPNetscapeFuncs* NPBrowserProxy::GetBrowserFunctions() {
+ return &kNetscapeFunctions;
+}
+
+void NPBrowserProxy::TearDown() {
+ // All NPObjectProxy instances stored in the java-script environment must
+ // be marked so that scripted operations on these operations fail after
+ // the plug-in has been torn down. We release the hosted object on all of
+ // these wrappers to prevent access, and allow deletion of the NPAPI objects.
+ NPObjectProxyMap::iterator np_object_iter(np_object_proxy_map_.begin()),
+ np_object_end(np_object_proxy_map_.end());
+ for (; np_object_iter != np_object_end; ++np_object_iter) {
+ np_object_iter->second->ReleaseHosted();
+ }
+}
diff --git a/o3d/plugin/npapi_host_control/win/np_browser_proxy.h b/o3d/plugin/npapi_host_control/win/np_browser_proxy.h
new file mode 100644
index 0000000..19f3245
--- /dev/null
+++ b/o3d/plugin/npapi_host_control/win/np_browser_proxy.h
@@ -0,0 +1,278 @@
+// Copyright 2009, Google Inc. All rights reserved.
+// Portions of this file were adapted from the Mozilla project.
+// See https://developer.mozilla.org/en/ActiveX_Control_for_Hosting_Netscape_Plug-ins_in_IE
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Adam Lock <adamlock@eircom.net>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+
+// File declaring NPBrowserProxy class providing a subset of the NPAPI browser
+// entry points for hosting Mozilla NPAPI plugin objects.
+
+#ifndef O3D_PLUGIN_NPAPI_HOST_CONTROL_WIN_NP_BROWSER_PROXY_H_
+#define O3D_PLUGIN_NPAPI_HOST_CONTROL_WIN_NP_BROWSER_PROXY_H_
+
+#include <dispex.h>
+#include <map>
+#include "third_party/npapi/files/include/npupp.h"
+#include "plugin/npapi_host_control/win/dispatch_proxy.h"
+#include "plugin/npapi_host_control/win/np_object_proxy.h"
+
+class CHostControl;
+class DispatchProxy;
+
+// Class implementing the NPAPI browser interface for an ActiveX environment.
+class NPBrowserProxy {
+ public:
+ explicit NPBrowserProxy(CHostControl* host, IDispatchEx* window_dispatch);
+ ~NPBrowserProxy();
+
+ // Returns the 'v-table' object for interacting with the NPAPI interface
+ // of the hosted browser environment.
+ static NPNetscapeFuncs* GetBrowserFunctions();
+
+ // Returns the hosting COM control.
+ CHostControl* GetHostingControl() {
+ return host_control_;
+ }
+
+ // Returns a place-holder object for the browser property. Used in
+ // conjunction with NPN_GetValue and NPNVWindowNPObject.
+ DispatchProxy* GetVWindowObject() {
+ return vwindow_object_;
+ }
+
+ // Create or get the existing COM object for the given NPObject. Ensures
+ // each NPObject only has a single proxy.
+ CComPtr<IDispatchEx> GetDispatchObject(NPObject* np_object);
+
+ // Create or get the existing NPObject for the given COM object. Ensures
+ // each COM object only has a single proxy. Caller must release the object.
+ NPObject* GetNPObject(IDispatch* dispatch_object);
+
+ // Registers an NPObject with its associated INPObjectProxy.
+ void RegisterNPObjectProxy(
+ NPObject* np_object,
+ const CComPtr<INPObjectProxy>& proxy_wrapper);
+
+ // Called by the NPObjectProxy when it is destroyed.
+ void UnregisterNPObjectProxy(NPObject* np_object);
+
+ // Called by the DispatchProxy when it is destroyed.
+ void UnregisterDispatchProxy(IDispatchEx* dispatch_object);
+
+ NPIdentifier call_identifier() const { return call_identifier_; }
+
+ // Prepares all allocated resources for the destruction of the NPBrowserProxy
+ // instance. Ensures that all objects returned to the IE scripting
+ // environment become unaccessable.
+ void TearDown();
+
+ private:
+ typedef std::map<NPObject*, CComPtr<INPObjectProxy> > NPObjectProxyMap;
+
+ typedef std::map<IUnknown*, DispatchProxy*> DispatchProxyMap;
+
+ // Back-pointer to the COM control hosting the NPAPI plug-in.
+ CHostControl* host_control_;
+
+ // Pointer to place-holder object for the NPNVWindowNPObject value
+ // accessible through NPN_GetValue.
+ DispatchProxy* vwindow_object_;
+
+ // Map of all NPObjects wrapped with NPObjectProxys.
+ NPObjectProxyMap np_object_proxy_map_;
+
+ // Map of all IDispatchEx objects wrapped with DispatchProxies.
+ DispatchProxyMap dispatch_proxy_map_;
+
+ NPIdentifier call_identifier_;
+
+ // The following functions implement a sub-set of the NPAPI browser object
+ // interface. The function naming has been preserved from that in the
+ // NPAPI interface headers. For documentation on the expected behaviour
+ // of these routines, please refer to the following:
+ // http://developer.mozilla.org/en/Gecko_Plugin_API_Reference/Plug-in_Side_Plug-in_API
+ static NPError NPN_RequestRead(NPStream *pstream, NPByteRange *rangeList);
+
+ static NPError NPN_GetURLNotify(NPP npp,
+ const char* relativeURL,
+ const char* target,
+ void* notifyData);
+
+ static NPError NPN_GetValue(NPP npp, NPNVariable variable, void *r_value);
+
+ static NPError NPN_SetValue(NPP npp, NPPVariable variable, void *r_value);
+
+ static NPError NPN_GetURL(NPP npp,
+ const char* relativeURL,
+ const char* target);
+
+ static NPError NPN_PostURLNotify(NPP npp,
+ const char* relativeURL,
+ const char *target,
+ uint32 len,
+ const char *buf,
+ NPBool file,
+ void* notifyData);
+
+ static NPError NPN_PostURL(NPP npp,
+ const char* relativeURL,
+ const char *target,
+ uint32 len,
+ const char *buf,
+ NPBool file);
+
+ static NPError NPN_NewStream(NPP npp,
+ NPMIMEType type,
+ const char* window,
+ NPStream **pstream);
+
+ static int32 NPN_Write(NPP npp, NPStream *pstream, int32 len, void *buffer);
+
+ static NPError NPN_DestroyStream(NPP npp, NPStream *pstream, NPError reason);
+
+ static void NPN_Status(NPP npp, const char *message);
+
+ static void* NPN_MemAlloc(uint32 size);
+
+ static void NPN_MemFree(void *ptr);
+
+ static uint32 NPN_MemFlush(uint32 size);
+
+ static void NPN_ReloadPlugins(NPBool reloadPages);
+
+ static void NPN_InvalidateRect(NPP npp, NPRect *invalidRect);
+
+ static void NPN_InvalidateRegion(NPP npp, NPRegion invalidRegion);
+
+ static const char* NPN_UserAgent(NPP npp);
+
+ static void* NPN_GetJavaEnv(void);
+
+ static void* NPN_GetJavaPeer(NPP npp);
+
+ static void* NPN_GetJavaClass(void* handle);
+
+ static void NPN_ForceRedraw(NPP npp);
+
+ static NPObject* NPN_CreateObject(NPP npp, NPClass *aClass);
+
+ static NPObject* NPN_RetainObject(NPObject *object);
+
+ static void NPN_ReleaseObject(NPObject *object);
+
+ static NPIdentifier NPN_GetStringIdentifier(const NPUTF8 *name);
+
+ static void NPN_GetStringIdentifiers(const NPUTF8 **names,
+ int32_t nameCount,
+ NPIdentifier *identifiers);
+
+ static NPUTF8* NPN_UTF8FromIdentifier(NPIdentifier identifier);
+
+ static NPIdentifier NPN_GetIntIdentifier(int32_t intid);
+ static int32_t NPN_IntFromIdentifier(NPIdentifier identifier);
+ static bool NPN_IdentifierIsString(NPIdentifier identifier);
+
+ static void NPN_ReleaseVariantValue(NPVariant *variant);
+
+ static bool NPN_GetProperty(NPP npp, NPObject *obj,
+ NPIdentifier propertyName,
+ NPVariant *result);
+
+ static bool NPN_SetProperty(NPP npp,
+ NPObject *obj,
+ NPIdentifier propertyName,
+ const NPVariant *value);
+
+ static bool NPN_HasProperty(NPP npp,
+ NPObject *npobj,
+ NPIdentifier propertyName);
+
+ static bool NPN_RemoveProperty(NPP npp,
+ NPObject *npobj,
+ NPIdentifier propertyName);
+
+ static bool NPN_HasMethod(NPP npp,
+ NPObject *npobj,
+ NPIdentifier methodName);
+
+ static bool NPN_Invoke(NPP npp,
+ NPObject *obj,
+ NPIdentifier methodName,
+ const NPVariant *args,
+ unsigned argCount,
+ NPVariant *result);
+
+ static bool NPN_InvokeDefault(NPP npp,
+ NPObject *obj,
+ const NPVariant *args,
+ unsigned argCount,
+ NPVariant *result);
+
+ static bool NPN_Construct(NPP npp,
+ NPObject *obj,
+ const NPVariant *args,
+ unsigned argCount,
+ NPVariant *result);
+
+ static bool NPN_Enumerate(NPP npp,
+ NPObject* obj,
+ NPIdentifier** ids,
+ uint32_t* idCOunt);
+
+ static bool ConstructObject(NPP npp,
+ NPObject* window_object,
+ NPUTF8* constructor_name,
+ NPVariant* args,
+ uint32_t numArgs,
+ NPObject** result);
+
+ static bool NPN_Evaluate(NPP npp,
+ NPObject *obj,
+ NPString *script,
+ NPVariant *result);
+
+ static void NPN_SetException(NPObject *obj, const NPUTF8 *message);
+
+ // Static table of function pointers to the member function entry points
+ // for the NPAPI browser environment interface.
+ static NPNetscapeFuncs kNetscapeFunctions;
+
+ DISALLOW_COPY_AND_ASSIGN(NPBrowserProxy);
+};
+
+#endif // O3D_PLUGIN_NPAPI_HOST_CONTROL_WIN_NP_BROWSER_PROXY_H_
diff --git a/o3d/plugin/npapi_host_control/win/np_object_proxy.cc b/o3d/plugin/npapi_host_control/win/np_object_proxy.cc
new file mode 100644
index 0000000..da7f018
--- /dev/null
+++ b/o3d/plugin/npapi_host_control/win/np_object_proxy.cc
@@ -0,0 +1,518 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include <oaidl.h>
+#include <atlstr.h>
+#include <vector>
+
+#include "base/scoped_ptr.h"
+#include "plugin/npapi_host_control/win/np_object_proxy.h"
+#include "plugin/npapi_host_control/win/np_browser_proxy.h"
+#include "plugin/npapi_host_control/win/variant_utils.h"
+#include "third_party/npapi/files/include/npupp.h"
+
+namespace {
+
+// Helper routine copying NPVariant object to a destination COM Variant.
+// Both arguments may be null. Argument com_result must be a properly
+// initialized VARIANT instance.
+void CopyToCOMResult(NPBrowserProxy* browser_proxy,
+ NPVariant* np_result,
+ VARIANT* com_result) {
+ if (com_result && np_result) {
+ CComVariant intermediate_result;
+ NPVariantToVariant(browser_proxy, np_result, &intermediate_result);
+ VariantCopy(com_result, &intermediate_result);
+ }
+}
+
+} // unnamed namespace
+
+
+NPObjectProxy::NPObjectProxy()
+ : hosted_(NULL),
+ browser_proxy_(NULL) {
+}
+
+NPObjectProxy::~NPObjectProxy() {
+ if (hosted_) {
+ if (browser_proxy_) {
+ browser_proxy_->UnregisterNPObjectProxy(hosted_);
+ }
+ NPBrowserProxy::GetBrowserFunctions()->releaseobject(hosted_);
+ }
+}
+
+STDMETHODIMP NPObjectProxy::SetHostedObject(void* hosted) {
+ ATLASSERT(hosted);
+ if (hosted_) {
+ NPBrowserProxy::GetBrowserFunctions()->releaseobject(hosted_);
+ }
+ hosted_ = static_cast<NPObject*>(hosted);
+ NPBrowserProxy::GetBrowserFunctions()->retainobject(hosted_);
+ return S_OK;
+}
+
+STDMETHODIMP NPObjectProxy::ReleaseHosted() {
+ if (hosted_) {
+ NPBrowserProxy::GetBrowserFunctions()->releaseobject(hosted_);
+ hosted_ = NULL;
+ }
+ return S_OK;
+}
+
+STDMETHODIMP NPObjectProxy::GetTypeInfoCount(UINT* pctinfo) {
+ // This class does not support type info.
+ if (!pctinfo) {
+ return E_POINTER;
+ } else {
+ *pctinfo = 0;
+ }
+ return S_OK;
+}
+
+STDMETHODIMP NPObjectProxy::GetTypeInfo(UINT itinfo,
+ LCID lcid,
+ ITypeInfo** pptinfo) {
+ // This class does not support type info.
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP NPObjectProxy::GetIDsOfNames(REFIID riid,
+ LPOLESTR* rgszNames,
+ UINT cNames,
+ LCID lcid,
+ DISPID* rgdispid) {
+ if (!hosted_) {
+ return E_FAIL;
+ }
+
+ // Use the ids from the plugin to return dispatch ids
+ NPIdentifier *supported_ids = NULL;
+ uint32 id_count = 0;
+
+ if (!hosted_->_class->enumerate(hosted_, &supported_ids, &id_count)) {
+ return E_FAIL;
+ }
+
+ // Convert all of the wide string arguments to UTF-8.
+ scoped_array<char *> utf8_names(new char*[cNames]);
+ for (int x = 0; x < cNames; ++x) {
+ size_t name_length = wcstombs(NULL, rgszNames[x], 0) + 1;
+ utf8_names[x] = new char[name_length];
+ wcstombs(utf8_names[x], rgszNames[x], name_length);
+ rgdispid[x] = DISPID_UNKNOWN;
+ }
+
+ int ids_found = 0;
+ // For each string in the input arguments, look for a match in the set of
+ // ids supported by the object instance.
+ NPUTF8 *string_id = NULL;
+ for (int x = 0; x < id_count; ++x) {
+ string_id = NPBrowserProxy::GetBrowserFunctions()->
+ utf8fromidentifier(supported_ids[x]);
+ ATLASSERT(string_id);
+ for (int y = 0; y < cNames; ++y) {
+ if (strcmp(utf8_names[y], string_id) == 0) {
+ // Return the ADDRESS of the supported ids string as the DISPID
+ // for the method.
+ rgdispid[y] = reinterpret_cast<DISPID>(supported_ids[x]);
+ ++ids_found;
+ break;
+ }
+ }
+ NPBrowserProxy::GetBrowserFunctions()->memfree(string_id);
+ }
+
+ // Free all intermediate string resources.
+ for (int x = 0; x < cNames; ++x) {
+ delete[] utf8_names[x];
+ }
+ NPBrowserProxy::GetBrowserFunctions()->memfree(supported_ids);
+
+ return (ids_found == cNames) ? S_OK : DISP_E_UNKNOWNNAME;
+}
+
+STDMETHODIMP NPObjectProxy::Invoke(DISPID dispidMember,
+ REFIID riid,
+ LCID lcid,
+ WORD wFlags,
+ DISPPARAMS* pdispparams,
+ VARIANT* pvarResult,
+ EXCEPINFO* pexcepinfo,
+ UINT* puArgErr) {
+ if (!hosted_) {
+ return E_FAIL;
+ }
+
+ return InvokeEx(dispidMember, lcid, wFlags, pdispparams, pvarResult,
+ pexcepinfo, NULL);
+}
+
+STDMETHODIMP NPObjectProxy::DeleteMemberByDispID(DISPID id) {
+ if (!hosted_) {
+ return E_FAIL;
+ }
+
+ NPIdentifier np_identifier = reinterpret_cast<NPIdentifier>(id);
+ if (hosted_->_class->removeProperty != NULL &&
+ hosted_->_class->removeProperty(hosted_, np_identifier)) {
+ return S_OK;
+ }
+ return S_FALSE;
+}
+
+STDMETHODIMP NPObjectProxy::DeleteMemberByName(BSTR bstrName, DWORD grfdex) {
+ if (!hosted_) {
+ return E_FAIL;
+ }
+ DISPID id;
+ HRESULT hr = GetDispID(bstrName, grfdex, &id);
+ if (hr == DISP_E_UNKNOWNNAME) {
+ // The semantics of JavaScript are that deleting a property that does not
+ // exist succeeds.
+ return S_OK;
+ } else if (FAILED(hr)) {
+ // Otherwise fail.
+ return S_FALSE;
+ } else {
+ return DeleteMemberByDispID(id);
+ }
+}
+
+STDMETHODIMP NPObjectProxy::GetDispID(BSTR bstrName,
+ DWORD grfdex,
+ DISPID* pid) {
+ if (!hosted_) {
+ return E_FAIL;
+ }
+
+ *pid = NULL;
+ CString name(bstrName);
+ int num_utf8_bytes = WideCharToMultiByte(CP_UTF8, 0, name.GetBuffer(),
+ name.GetLength() + 1, NULL, 0,
+ NULL, NULL);
+ std::vector<NPUTF8> utf8_name(num_utf8_bytes);
+ WideCharToMultiByte(CP_UTF8, 0, name.GetBuffer(), name.GetLength() + 1,
+ &utf8_name[0], num_utf8_bytes, NULL, NULL);
+
+ NPIdentifier np_identifier =
+ NPBrowserProxy::GetBrowserFunctions()->getstringidentifier(
+ &utf8_name[0]);
+
+ // This method can be called to determine whether an object has a property
+ // with the given name. So check that before converting to an NPIdentifier.
+ if (!HasPropertyOrMethod(np_identifier))
+ return DISP_E_UNKNOWNNAME;
+
+ *pid = reinterpret_cast<DISPID>(np_identifier);
+ return S_OK;
+}
+
+STDMETHODIMP NPObjectProxy::GetMemberName(DISPID id,
+ BSTR* pbstrName) {
+ if (!hosted_) {
+ return E_FAIL;
+ }
+ NPIdentifier np_identifier = reinterpret_cast<NPIdentifier>(id);
+
+ // Make sure the id is valid on this object. It might have been deleted since
+ // it was returned by GetDispID.
+ if (!HasPropertyOrMethod(np_identifier))
+ return DISP_E_UNKNOWNNAME;
+
+ NPUTF8* utf8_name = NPBrowserProxy::GetBrowserFunctions()->utf8fromidentifier(
+ np_identifier);
+ int num_wide_chars = MultiByteToWideChar(CP_UTF8, 0, utf8_name, -1, NULL, 0);
+ CString name;
+ MultiByteToWideChar(CP_UTF8, 0, utf8_name, -1,
+ name.GetBuffer(num_wide_chars), num_wide_chars);
+ name.ReleaseBuffer(num_wide_chars - 1);
+ *pbstrName = name.AllocSysString();
+ NPBrowserProxy::GetBrowserFunctions()->memfree(utf8_name);
+ return S_OK;
+}
+
+STDMETHODIMP NPObjectProxy::GetMemberProperties(DISPID id,
+ DWORD grfdexFetch,
+ DWORD* pgrfdex) {
+ if (!hosted_) {
+ return E_FAIL;
+ }
+
+ // NPAPI does not provide a way to get all the information this function
+ // expects to be returned. This is what IE7 returns for some native objects.
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP NPObjectProxy::GetNameSpaceParent(IUnknown** punk) {
+ if (!hosted_) {
+ return E_FAIL;
+ }
+
+ // JavaScript does not have namespaces. An alternative would be to return
+ // an error code.
+ *punk = NULL;
+ return S_OK;
+}
+
+STDMETHODIMP NPObjectProxy::GetNextDispID(DWORD grfdex,
+ DISPID id,
+ DISPID* pid) {
+ if (!hosted_) {
+ return E_FAIL;
+ }
+
+ HRESULT hr = S_FALSE;
+ NPIdentifier* ids;
+ uint32_t num_ids = 0;
+ if (hosted_->_class->enumerate != NULL &&
+ hosted_->_class->enumerate(hosted_, &ids, &num_ids)) {
+ if (id == DISPID_STARTENUM && num_ids > 0) {
+ *pid = reinterpret_cast<DISPID>(ids[0]);
+ hr = S_OK;
+ } else {
+ if (!ids) {
+ return S_FALSE;
+ }
+ uint32_t i;
+ for (i = 0; i != num_ids; ++i) {
+ if (ids[i] == reinterpret_cast<NPIdentifier>(id))
+ break;
+ }
+ if (i + 1 < num_ids) {
+ *pid = reinterpret_cast<DISPID>(ids[i + 1]);
+ hr = S_OK;
+ }
+ }
+ NPBrowserProxy::GetBrowserFunctions()->memfree(ids);
+ }
+ return hr;
+}
+
+STDMETHODIMP NPObjectProxy::InvokeEx(DISPID id,
+ LCID lcid,
+ WORD wFlags,
+ DISPPARAMS* pdb,
+ VARIANT* pVarRes,
+ EXCEPINFO* pei,
+ IServiceProvider* pspCaller) {
+ if (!hosted_) {
+ return E_FAIL;
+ }
+ HRESULT hr = E_FAIL;
+ NPIdentifier np_identifier = reinterpret_cast<NPIdentifier>(id);
+
+ if (wFlags & (DISPATCH_METHOD | DISPATCH_CONSTRUCT)) {
+ // Get the "this" pointer if provided or default to the hosted object.
+ // We cannot support more general bindings for "this" through npruntime.
+ // This might arise if the function is invoked through
+ // my_function.call(my_this, args) from JScript.
+ if (pdb->cNamedArgs == 1 && pdb->rgdispidNamedArgs[0] == DISPID_THIS) {
+ NPVariant np_this_variant;
+ VariantToNPVariant(
+ browser_proxy_,
+ &pdb->rgvarg[0],
+ &np_this_variant);
+ NPObject* np_this_object = NULL;
+ if (NPVARIANT_IS_OBJECT(np_this_variant)) {
+ np_this_object = NPVARIANT_TO_OBJECT(np_this_variant);
+ }
+ NPBrowserProxy::GetBrowserFunctions()->releasevariantvalue(
+ &np_this_variant);
+ if (np_this_object != hosted_) {
+ return E_FAIL;
+ }
+ } else if (pdb->cNamedArgs != 0) {
+ return DISP_E_NONAMEDARGS;
+ }
+
+ // Convert the arguments to NPVariants.
+ int num_unnamed_arguments = pdb->cArgs - pdb->cNamedArgs;
+ scoped_array<NPVariant> np_arguments(new NPVariant[num_unnamed_arguments]);
+ for (int x = 0; x < num_unnamed_arguments; ++x) {
+ // Note that IDispatch expects arguments in the reverse order.
+ VariantToNPVariant(
+ browser_proxy_,
+ &pdb->rgvarg[pdb->cArgs - x - 1],
+ &np_arguments[x]);
+ }
+
+ // IDispatch supports the notion of default methods with the DISPID value
+ // DISPID_VALUE.
+ NPVariant result;
+ if (DISPID_VALUE == id) {
+ if (wFlags & DISPATCH_CONSTRUCT) {
+ if (hosted_->_class->construct != NULL &&
+ hosted_->_class->construct(hosted_,
+ np_arguments.get(),
+ num_unnamed_arguments,
+ &result)) {
+ CopyToCOMResult(browser_proxy_, &result, pVarRes);
+ NPBrowserProxy::GetBrowserFunctions()->releasevariantvalue(&result);
+ hr = S_OK;
+ }
+ } else {
+ if (hosted_->_class->invokeDefault != NULL &&
+ hosted_->_class->invokeDefault(hosted_,
+ np_arguments.get(),
+ num_unnamed_arguments,
+ &result)) {
+ CopyToCOMResult(browser_proxy_, &result, pVarRes);
+ NPBrowserProxy::GetBrowserFunctions()->releasevariantvalue(&result);
+ hr = S_OK;
+ }
+ }
+ } else if (hosted_->_class->hasMethod != NULL &&
+ hosted_->_class->hasMethod(hosted_, np_identifier)) {
+ if (hosted_->_class->invoke != NULL &&
+ hosted_->_class->invoke(hosted_,
+ np_identifier,
+ np_arguments.get(),
+ num_unnamed_arguments,
+ &result)) {
+ CopyToCOMResult(browser_proxy_, &result, pVarRes);
+ NPBrowserProxy::GetBrowserFunctions()->releasevariantvalue(&result);
+ hr = S_OK;
+ }
+ } else if (hosted_->_class->hasProperty != NULL &&
+ hosted_->_class->hasProperty(hosted_, np_identifier)) {
+ // If the object does not have a method with the given identifier,
+ // it may have a property with that id that we can invoke the default
+ // method upon.
+ NPVariant np_property_variant;
+ if (hosted_->_class->getProperty != NULL &&
+ hosted_->_class->getProperty(hosted_, np_identifier,
+ &np_property_variant)) {
+ if (NPVARIANT_IS_OBJECT(np_property_variant)) {
+ NPObject* np_property_object = NPVARIANT_TO_OBJECT(
+ np_property_variant);
+ if (np_property_object->_class->invokeDefault != NULL) {
+ if (np_property_object->_class->invokeDefault(
+ np_property_object,
+ np_arguments.get(),
+ num_unnamed_arguments,
+ &result)) {
+ CopyToCOMResult(browser_proxy_, &result, pVarRes);
+ NPBrowserProxy::GetBrowserFunctions()->releasevariantvalue(
+ &result);
+ hr = S_OK;
+ }
+ } else {
+ hr = DISP_E_TYPEMISMATCH;
+ }
+ } else {
+ hr = DISP_E_TYPEMISMATCH;
+ }
+ NPBrowserProxy::GetBrowserFunctions()->
+ releasevariantvalue(&np_property_variant);
+ }
+ } else {
+ hr = DISP_E_MEMBERNOTFOUND;
+ }
+
+ // Release all of the converted arguments.
+ for (int x = 0; x < num_unnamed_arguments; ++x) {
+ NPBrowserProxy::GetBrowserFunctions()->releasevariantvalue(
+ &np_arguments[x]);
+ }
+ } else if (wFlags & DISPATCH_PROPERTYPUT) {
+ if (pdb->cArgs == 1) {
+ if (id == DISPID_VALUE) {
+ hr = DISP_E_MEMBERNOTFOUND;
+ } else {
+ // Convert the COM variant to the corresponding NPVariant.
+ NPVariant property_in;
+ VariantToNPVariant(browser_proxy_, &pdb->rgvarg[0], &property_in);
+ if (hosted_->_class->setProperty != NULL &&
+ hosted_->_class->setProperty(hosted_,
+ np_identifier,
+ &property_in)) {
+ hr = S_OK;
+ }
+ NPBrowserProxy::GetBrowserFunctions()->releasevariantvalue(
+ &property_in);
+ }
+ } else {
+ hr = DISP_E_BADPARAMCOUNT;
+ }
+ } else if (wFlags & DISPATCH_PROPERTYGET) {
+ if (pdb->cArgs == 0) {
+ // Sometimes JScript asks an object for its default value. Returning
+ // itself appears to be ther right thing to do.
+ if (id == DISPID_VALUE) {
+ pVarRes->vt = VT_DISPATCH;
+ pVarRes->pdispVal = this;
+ AddRef();
+ hr = S_OK;
+ } else {
+ NPVariant property_out;
+ if (hosted_->_class->hasProperty != NULL &&
+ !hosted_->_class->hasProperty(hosted_, np_identifier)) {
+ hr = DISP_E_MEMBERNOTFOUND;
+ } else if (hosted_->_class->getProperty != NULL &&
+ hosted_->_class->getProperty(hosted_,
+ np_identifier,
+ &property_out)) {
+ CopyToCOMResult(browser_proxy_, &property_out, pVarRes);
+ NPBrowserProxy::GetBrowserFunctions()->releasevariantvalue(
+ &property_out);
+ hr = S_OK;
+ }
+ }
+ } else {
+ hr = DISP_E_BADPARAMCOUNT;
+ }
+ }
+ return hr;
+}
+
+STDMETHODIMP NPObjectProxy::GetNPObjectInstance(void **np_instance) {
+ if (!hosted_) {
+ return E_FAIL;
+ }
+
+ *np_instance = hosted_;
+ NPBrowserProxy::GetBrowserFunctions()->retainobject(hosted_);
+ return S_OK;
+}
+
+bool NPObjectProxy::HasPropertyOrMethod(NPIdentifier np_identifier) {
+ if (!hosted_) {
+ return E_FAIL;
+ }
+
+ return (hosted_->_class->hasProperty != NULL &&
+ hosted_->_class->hasProperty(hosted_, np_identifier)) ||
+ (hosted_->_class->hasMethod != NULL &&
+ hosted_->_class->hasMethod(hosted_, np_identifier));
+}
diff --git a/o3d/plugin/npapi_host_control/win/np_object_proxy.h b/o3d/plugin/npapi_host_control/win/np_object_proxy.h
new file mode 100644
index 0000000..4d80676
--- /dev/null
+++ b/o3d/plugin/npapi_host_control/win/np_object_proxy.h
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// File declaring NPObjectProxy class. This class wraps the NPAPI scripting
+// interface with a COM IDispatchEx interface to allow interop between ActiveX
+// and NPObject instances.
+
+#ifndef O3D_PLUGIN_NPAPI_HOST_CONTROL_WIN_NP_OBJECT_PROXY_H_
+#define O3D_PLUGIN_NPAPI_HOST_CONTROL_WIN_NP_OBJECT_PROXY_H_
+
+#include <atlctl.h>
+#include <dispex.h>
+
+// File included without directory because it is auto-generated by the
+// type-lib.
+#include "npapi_host_control.h"
+
+#include "third_party/npapi/files/include/npupp.h"
+
+struct NPObject;
+class NPBrowserProxy;
+
+// COM class implementing a basic IDispatchEx interface that wraps the NPAPI
+// NPObject scripting functionality.
+class ATL_NO_VTABLE NPObjectProxy :
+ public CComObjectRootEx<CComSingleThreadModel>,
+ public CComCoClass<NPObjectProxy, &CLSID_NPObjectProxy>,
+ public IDispatchImpl<INPObjectProxy, &IID_INPObjectProxy,
+ &LIBID_npapi_host_controlLib>,
+ public IObjectSafetyImpl<NPObjectProxy,
+ INTERFACESAFE_FOR_UNTRUSTED_CALLER> {
+ public:
+ NPObjectProxy();
+ virtual ~NPObjectProxy();
+
+DECLARE_REGISTRY_RESOURCEID(IDR_NPOBJECTPROXY)
+
+BEGIN_COM_MAP(NPObjectProxy)
+ COM_INTERFACE_ENTRY(INPObjectProxy)
+ COM_INTERFACE_ENTRY(IDispatch)
+ COM_INTERFACE_ENTRY(IDispatchEx)
+END_COM_MAP()
+
+ STDMETHOD(SetBrowserProxy)(void* browser_proxy) {
+ browser_proxy_ = static_cast<NPBrowserProxy*>(browser_proxy);
+ return S_OK;
+ }
+
+ // Routine implementing INPObjectProxy interface method, returning a raw
+ // pointer to a NPObject instance. Note that the reference count of the
+ // returned NPObject has been incremented. The returned object should
+ // be released by the hosting browser proxy to prevent memory leaks.
+ STDMETHOD(GetNPObjectInstance)(void **np_instance);
+ STDMETHOD(SetHostedObject)(void* hosted_object);
+ STDMETHOD(ReleaseHosted)();
+
+ // Routines implementing the IDispatchEx COM interface.
+ STDMETHOD(GetTypeInfoCount)(UINT* pctinfo);
+ STDMETHOD(GetTypeInfo)(UINT itinfo, LCID lcid, ITypeInfo** pptinfo);
+ STDMETHOD(GetIDsOfNames)(REFIID riid,
+ LPOLESTR* rgszNames,
+ UINT cNames,
+ LCID lcid,
+ DISPID* rgdispid);
+ STDMETHOD(Invoke)(DISPID dispidMember,
+ REFIID riid,
+ LCID lcid,
+ WORD wFlags,
+ DISPPARAMS* pdispparams,
+ VARIANT* pvarResult,
+ EXCEPINFO* pexcepinfo,
+ UINT* puArgErr);
+
+ STDMETHOD(DeleteMemberByDispID)(DISPID id);
+ STDMETHOD(DeleteMemberByName)(BSTR bstrName, DWORD grfdex);
+ STDMETHOD(GetDispID)(BSTR bstrName, DWORD grfdex, DISPID* pid);
+ STDMETHOD(GetMemberName)(DISPID id, BSTR* pbstrName);
+ STDMETHOD(GetMemberProperties)(DISPID id, DWORD grfdexFetch, DWORD* pgrfdex);
+ STDMETHOD(GetNameSpaceParent)(IUnknown** ppunk);
+ STDMETHOD(GetNextDispID)(DWORD grfdex, DISPID id, DISPID* pid);
+ STDMETHOD(InvokeEx)(DISPID id, LCID lcid, WORD wFlags, DISPPARAMS* pdp,
+ VARIANT* pVarRes, EXCEPINFO* pei,
+ IServiceProvider* pspCaller);
+
+ DECLARE_PROTECT_FINAL_CONSTRUCT();
+ private:
+ bool HasPropertyOrMethod(NPIdentifier np_identifier);
+
+ // Pointer to NPObject for which this instance is a proxy IDispatchEx.
+ NPObject *hosted_;
+
+ // Back-pointer to the NPAPI browser proxy.
+ NPBrowserProxy* browser_proxy_;
+
+ DISALLOW_COPY_AND_ASSIGN(NPObjectProxy);
+};
+
+// Register this COM class with the COM module.
+OBJECT_ENTRY_AUTO(__uuidof(NPObjectProxy), NPObjectProxy);
+
+#endif // O3D_PLUGIN_NPAPI_HOST_CONTROL_WIN_NP_OBJECT_PROXY_H_
diff --git a/o3d/plugin/npapi_host_control/win/np_object_proxy.rgs b/o3d/plugin/npapi_host_control/win/np_object_proxy.rgs
new file mode 100644
index 0000000..3660c52
--- /dev/null
+++ b/o3d/plugin/npapi_host_control/win/np_object_proxy.rgs
@@ -0,0 +1,37 @@
+HKCU
+{
+ Software
+ {
+ Classes
+ {
+ o3d_host.NPObjectProxy.1 = s 'NPObjectProxy Class'
+ {
+ CLSID = s '{1D68424D-7A71-4b61-AE5C-56DBCD8B0E53}'
+ 'Insertable'
+ }
+ o3d_host.NPObjectProxy = s 'NPObjectProxy Class'
+ {
+ CLSID = s '{1D68424D-7A71-4b61-AE5C-56DBCD8B0E53}'
+ CurVer = s 'o3d_host.NPObjectProxy.1'
+ }
+ NoRemove CLSID
+ {
+ ForceRemove {1D68424D-7A71-4b61-AE5C-56DBCD8B0E53} = s 'NPObjectProxy Class'
+ {
+ ProgID = s 'o3d_host.NPObjectProxy.1'
+ VersionIndependentProgID = s 'o3d_host.NPObjectProxy'
+ ForceRemove 'Programmable'
+ InprocServer32 = s '%MODULE%'
+ {
+ val ThreadingModel = s 'Apartment'
+ }
+ val AppID = s '%APPID%'
+ ForceRemove 'Control'
+ ForceRemove 'Insertable'
+ 'TypeLib' = s '{D4F6E31C-E952-48FE-9833-6AE308BD79C6}'
+ 'Version' = s '1.0'
+ }
+ }
+ }
+ }
+}
diff --git a/o3d/plugin/npapi_host_control/win/np_plugin_proxy.cc b/o3d/plugin/npapi_host_control/win/np_plugin_proxy.cc
new file mode 100644
index 0000000..449e6b7
--- /dev/null
+++ b/o3d/plugin/npapi_host_control/win/np_plugin_proxy.cc
@@ -0,0 +1,437 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "plugin/npapi_host_control/win/np_plugin_proxy.h"
+
+#include <shlobj.h>
+#include <shlwapi.h>
+
+#include <algorithm>
+#include "base/scoped_ptr.h"
+#include "plugin/npapi_host_control/win/module.h"
+#include "plugin/npapi_host_control/win/np_browser_proxy.h"
+#include "plugin/npapi_host_control/win/np_object_proxy.h"
+#include "plugin/npapi_host_control/win/stream_operation.h"
+
+namespace {
+
+const wchar_t kPluginName[] = L"npo3dautoplugin.dll";
+const wchar_t kAppDataPluginLocation[] =
+ L"Mozilla\\plugins\\npo3dautoplugin.dll";
+
+// Returns the path to the O3D plug-in located in the current user's
+// Application Data directory. Returns NULL on failure.
+// Note: The caller does not need to free the returned string.
+const wchar_t* GetApplicationDataPluginPath() {
+ static wchar_t kAppDataPath[MAX_PATH] = {0};
+ HRESULT hr = SHGetFolderPath(0, CSIDL_APPDATA, NULL, 0, kAppDataPath);
+ if (SUCCEEDED(hr)) {
+ PathAppend(kAppDataPath, kAppDataPluginLocation);
+ return kAppDataPath;
+ } else {
+ return NULL;
+ }
+}
+
+// Returns a path to the O3D plug-in corresponding to the value of the
+// MOZ_PLUGIN_PATH environment variable. This variable is used to override
+// the default directory where FireFox will search for plug-ins.
+// Note: The caller does not need to free the returned string.
+const wchar_t* GetMozillaPluginPath() {
+ static wchar_t kMozillaPluginPath[MAX_PATH] = {0};
+ DWORD chars_written = GetEnvironmentVariable(L"MOZ_PLUGIN_PATH",
+ kMozillaPluginPath,
+ MAX_PATH);
+ if (chars_written == 0) {
+ return NULL;
+ } else if (chars_written > MAX_PATH) {
+ ATLASSERT(false && "MOZ_PLUGIN_PATH too large to represent a path.");
+ return NULL;
+ } else {
+ PathAppend(kMozillaPluginPath, kPluginName);
+ return kMozillaPluginPath;
+ }
+}
+
+const wchar_t kProgramFilesPluginLocation[] =
+ L"Mozilla Firefox\\plugins\\npo3dautoplugin.dll";
+
+// Returns the path to the O3D plug-in located in the Program
+// Files directory. Returns NULL on failure.
+// Note: The caller does not need to free the returned string.
+const wchar_t* GetProgramFilesPluginPath() {
+ static wchar_t kProgramFilesPath[MAX_PATH] = {0};
+ HRESULT hr = SHGetFolderPath(0,
+ CSIDL_PROGRAM_FILES,
+ NULL,
+ 0,
+ kProgramFilesPath);
+ if (SUCCEEDED(hr)) {
+ PathAppend(kProgramFilesPath, kProgramFilesPluginLocation);
+ return kProgramFilesPath;
+ } else {
+ return NULL;
+ }
+}
+
+// Helper class implementing RAII semantics for locking the ATL module.
+class AutoModuleLock {
+ public:
+ AutoModuleLock() {
+ NPAPIHostControlModule::LockModule();
+ }
+ ~AutoModuleLock() {
+ NPAPIHostControlModule::UnlockModule();
+ }
+ private:
+ DISALLOW_COPY_AND_ASSIGN(AutoModuleLock);
+};
+
+// Helper routine that populates nested scoped arrays of characters
+// from std vectors of CStringA objects. This routine is used to make
+// a local copy of the name/value arguments to the plug-in instance,
+// so that any local modifications on the arguments performed during
+// plug-in initialization won't propagate to future instantiations of
+// the plug-in.
+void ConstructLocalPluginArgs(const std::vector<CStringA>& names,
+ const std::vector<CStringA>& values,
+ short* argc,
+ scoped_array<scoped_array<char> >* argn,
+ scoped_array<scoped_array<char> >* argv) {
+ ATLASSERT(argc && argn && argv);
+ ATLASSERT(names.size() == values.size());
+
+ *argc = static_cast<short>(names.size());
+ if (names.empty()) {
+ argn->reset(NULL);
+ argv->reset(NULL);
+ return;
+ }
+
+ // Copy the contents of the name and value arrays to the scoped_array
+ // parameters.
+ argn->reset(new scoped_array<char>[*argc]);
+ argv->reset(new scoped_array<char>[*argc]);
+ for (int x = 0; x < *argc; ++x) {
+ char* name = new char[names[x].GetLength() + 1];
+ char* value = new char[values[x].GetLength() + 1];
+
+ strcpy(name, static_cast<const char*>(names[x]));
+ strcpy(value, static_cast<const char*>(values[x]));
+
+ (*argn)[x].reset(name);
+ (*argv)[x].reset(value);
+ }
+}
+
+} // unnamed namespace
+
+int NPPluginProxy::kPluginInstanceCount = 0;
+
+NPPluginProxy::NPPluginProxy()
+ : browser_proxy_(NULL),
+ scriptable_object_(NULL),
+ NP_Initialize_(NULL),
+ NP_GetEntryPoints_(NULL),
+ NP_Shutdown_(NULL),
+ plugin_module_(0) {
+ npp_data_.ndata = npp_data_.pdata = NULL;
+ memset(&plugin_funcs_, NULL, sizeof(plugin_funcs_));
+}
+
+NPPluginProxy::~NPPluginProxy() {
+ // Serialize the destruction of instances so that there are no races on
+ // the instance count, and library loads.
+ AutoModuleLock lock;
+ if (0 == --kPluginInstanceCount) {
+ if (NP_Shutdown_) {
+ NP_Shutdown_();
+ }
+ }
+
+ FreeLibrary(plugin_module_);
+ ATLASSERT(active_stream_ops_.empty() &&
+ "Destruction of plugin proxy with still-pending streaming ops.");
+}
+
+bool NPPluginProxy::MapEntryPoints(HMODULE loaded_module) {
+ // Initialize the function pointers to the plugin entry points.
+ NP_Initialize_ = reinterpret_cast<NP_InitializeFunc>(
+ GetProcAddress(loaded_module, "NP_Initialize"));
+ NP_GetEntryPoints_ = reinterpret_cast<NP_GetEntryPointsFunc>(
+ GetProcAddress(loaded_module, "NP_GetEntryPoints"));
+ NP_Shutdown_ = reinterpret_cast<NP_ShutdownFunc>(
+ GetProcAddress(loaded_module, "NP_Shutdown"));
+
+ if (!NP_Initialize_ || !NP_GetEntryPoints_ || !NP_Shutdown_) {
+ ATLASSERT(false && "NPAPI DLL exports not present.");
+ return false;
+ }
+
+ // Plugin-initialization is to be performed once, at initial plug-in
+ // loading time. Note that this routine must be accessed serially to
+ // protect against races on kPluginInstanceCount.
+ if (0 == kPluginInstanceCount) {
+ if (NPERR_NO_ERROR != NP_Initialize_(
+ browser_proxy_->GetBrowserFunctions())) {
+ ATLASSERT(false && "NPAPI initialization failure.");
+ return false;
+ }
+ }
+ ++kPluginInstanceCount;
+
+ if (NPERR_NO_ERROR != NP_GetEntryPoints_(&plugin_funcs_)) {
+ ATLASSERT(false && "Unknown failure getting NPAPI entry points.");
+ return false;
+ }
+
+ plugin_module_ = loaded_module;
+ return true;
+}
+
+bool NPPluginProxy::Init(NPBrowserProxy* browser_proxy,
+ const NPWindow& window,
+ const std::vector<CStringA>& argument_names,
+ const std::vector<CStringA>& argument_values) {
+ ATLASSERT(plugin_module_ &&
+ "Plugin module not loaded before initialization.");
+ ATLASSERT(browser_proxy && "Browser environment required for plugin init.");
+ browser_proxy_ = browser_proxy;
+
+ // Store a pointer to the browser proxy instance in the netscape data
+ // of the plugin data. This will be the only access point to the browser
+ // instance from within the NPBrowserProxy NPAPI functions.
+ npp_data_.ndata = static_cast<void*>(browser_proxy_);
+
+ scoped_array<scoped_array<char> > argn, argv;
+ short argc;
+
+ // Build a local-copy of the plug-in arguments, so that any modifications
+ // on the name/value pairs will not be propagated to future instantiations.
+ ConstructLocalPluginArgs(argument_names,
+ argument_values,
+ &argc,
+ &argn,
+ &argv);
+
+ if (NPERR_NO_ERROR != plugin_funcs_.newp(
+ "No mime type",
+ GetNPP(),
+ NP_EMBED,
+ argc,
+ reinterpret_cast<char**>(argn.get()),
+ reinterpret_cast<char**>(argv.get()),
+ NULL)) {
+ NP_Shutdown_();
+ ATLASSERT(false && "Unknown failure creating NPAPI plugin instance.");
+ return false;
+ }
+
+ if (NPERR_NO_ERROR != plugin_funcs_.setwindow(
+ GetNPP(),
+ const_cast<NPWindow*>(&window))) {
+ plugin_funcs_.destroy(GetNPP(), NULL);
+ NP_Shutdown_();
+ ATLASSERT(false && "Unknown failure binding plugin window.");
+ return false;
+ }
+
+ // We assume that the plugin is scripted, so get the scripting entry points
+ // from the plugin.
+ NPObject *np_object = NULL;
+ if (NPERR_NO_ERROR != plugin_funcs_.getvalue(
+ GetNPP(),
+ NPPVpluginScriptableNPObject,
+ static_cast<void*>(&np_object))) {
+ plugin_funcs_.destroy(GetNPP(), NULL);
+ NP_Shutdown_();
+ ATLASSERT(false && "Unable to initialize NPAPI scripting interface.");
+ return false;
+ }
+ ATLASSERT(np_object);
+
+ HRESULT hr = NPObjectProxy::CreateInstance(&scriptable_object_);
+ ATLASSERT(SUCCEEDED(hr));
+
+ scriptable_object_->SetBrowserProxy(browser_proxy_);
+ scriptable_object_->SetHostedObject(np_object);
+
+ browser_proxy_->RegisterNPObjectProxy(np_object, scriptable_object_);
+
+ NPBrowserProxy::GetBrowserFunctions()->releaseobject(np_object);
+
+ return true;
+}
+
+void NPPluginProxy::TearDown() {
+ // Block until all stream operations requested by this plug-in have
+ // completed.
+ HRESULT hr;
+ std::vector<HANDLE> stream_handles;
+ for (int x = 0; x < active_stream_ops_.size(); ++x) {
+ // Request that the stream finish early - so that large file transfers do
+ // not block leaving the page.
+ hr = active_stream_ops_[x]->RequestCancellation();
+ ATLASSERT(SUCCEEDED(hr) &&
+ "Failed to request cancellation of pending data stream.");
+ stream_handles.push_back(active_stream_ops_[x]->GetThreadHandle());
+ }
+
+ static const unsigned int kWaitTimeOut = 120000;
+ while (!stream_handles.empty()) {
+ DWORD wait_code = MsgWaitForMultipleObjects(
+ static_cast<DWORD>(stream_handles.size()),
+ &stream_handles[0],
+ FALSE,
+ kWaitTimeOut,
+ QS_ALLINPUT);
+ wait_code -= WAIT_OBJECT_0;
+ if (wait_code == stream_handles.size()) {
+ MSG msg;
+ GetMessage(&msg, NULL, 0, 0);
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ } else if (wait_code >= 0 && wait_code < stream_handles.size()) {
+ // A thread has completed, so remove the handle and continue.
+ stream_handles.erase(stream_handles.begin() + wait_code);
+ } else {
+ if (wait_code == WAIT_TIMEOUT + WAIT_OBJECT_0) {
+ ATLASSERT(false &&
+ "Time-out waiting for completion of streaming operation.");
+ } else {
+ ATLASSERT(false &&
+ "Unknown error waiting on streaming operation completion.");
+ }
+ // There has been a catastropic error waiting for the pending transfers.
+ // Kill all of the threads and leave the loop.
+ // Note: This approach will potentially leak resources allocated by
+ // the plug-in, but it prevents access to stale data by the threads
+ // once the plug-in has been unloaded.
+ for (int x = 0; x < active_stream_ops_.size(); ++x) {
+ BOOL thread_kill = TerminateThread(stream_handles[x], 0);
+ ATLASSERT(thread_kill && "Failure killing stalled download thread.");
+ }
+ break;
+ }
+ }
+
+ if (plugin_module_) {
+ scriptable_object_ = NULL;
+ plugin_funcs_.destroy(GetNPP(), NULL);
+ }
+}
+
+void NPPluginProxy::RegisterStreamOperation(StreamOperation* stream_op) {
+#ifndef NDEBUG
+ StreamOpArray::iterator iter = std::find(active_stream_ops_.begin(),
+ active_stream_ops_.end(),
+ stream_op);
+ ATLASSERT(iter == active_stream_ops_.end() &&
+ "Duplicate registration of a StreamOperation.");
+#endif
+ active_stream_ops_.push_back(stream_op);
+}
+
+void NPPluginProxy::UnregisterStreamOperation(StreamOperation* stream_op) {
+ StreamOpArray::iterator iter = std::find(active_stream_ops_.begin(),
+ active_stream_ops_.end(),
+ stream_op);
+ ATLASSERT(iter != active_stream_ops_.end() &&
+ "Unregistration of an unrecognized StreamOperation.");
+ active_stream_ops_.erase(iter);
+}
+
+HRESULT NPPluginProxy::GetScriptableObject(
+ INPObjectProxy** scriptable_object) const {
+ ATLASSERT(scriptable_object);
+
+ if (!scriptable_object_) {
+ return E_FAIL;
+ }
+
+ *scriptable_object = scriptable_object_;
+ (*scriptable_object)->AddRef();
+ return S_OK;
+}
+
+HRESULT NPPluginProxy::Create(NPPluginProxy** proxy_instance) {
+ ATLASSERT(proxy_instance);
+ // Lock the module so that there are no races against the NP_Initialize
+ // and NP_Shutdown calls. NP_Initialize and NP_Shutdown parallel the
+ // behaviour of DLL_PROCESS_ATTACH and DLL_PROCESS_DETACH.
+ // We serialize all construction and destruction to ensure that any
+ // plug-in initialization mimics this behaviour.
+ AutoModuleLock lock;
+
+ // First attempt to load the plug-in from the directory specified by the
+ // MOZ_PLUGIN_PATH directory.
+ HMODULE np_plugin = NULL;
+ const wchar_t *plugin_path = GetMozillaPluginPath();
+ if (plugin_path) {
+ np_plugin = LoadLibrary(plugin_path);
+ }
+
+ if (!np_plugin) {
+ // Attempt to load the plug-in from the installation directory.
+ plugin_path = GetApplicationDataPluginPath();
+ if (plugin_path) {
+ np_plugin = LoadLibrary(plugin_path);
+ }
+
+ if (!np_plugin) {
+ plugin_path = GetProgramFilesPluginPath();
+ if (plugin_path) {
+ np_plugin = LoadLibrary(plugin_path);
+ }
+
+ if (!np_plugin) {
+ // As a last-ditch attempt, try to load the plug-in using the system
+ // library path.
+ np_plugin = LoadLibrary(kPluginName);
+ if (!np_plugin) {
+ ATLASSERT(false && "Unable to load plugin module.");
+ return E_FAIL;
+ }
+ }
+ }
+ }
+
+ // Load and initialize the plug-in with the current window settings.
+ scoped_ptr<NPPluginProxy> plugin_proxy(new NPPluginProxy);
+ if (!plugin_proxy->MapEntryPoints(np_plugin)) {
+ FreeLibrary(np_plugin);
+ return E_FAIL;
+ }
+
+ *proxy_instance = plugin_proxy.release();
+ return S_OK;
+}
diff --git a/o3d/plugin/npapi_host_control/win/np_plugin_proxy.h b/o3d/plugin/npapi_host_control/win/np_plugin_proxy.h
new file mode 100644
index 0000000..0c81367
--- /dev/null
+++ b/o3d/plugin/npapi_host_control/win/np_plugin_proxy.h
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// File declaring a class wrapping the raw npapi interface as exported from
+// a Mozilla plug-in.
+
+#ifndef O3D_PLUGIN_NPAPI_HOST_CONTROL_WIN_NP_PLUGIN_PROXY_H_
+#define O3D_PLUGIN_NPAPI_HOST_CONTROL_WIN_NP_PLUGIN_PROXY_H_
+
+#include <vector>
+#include "third_party/npapi/files/include/npupp.h"
+
+class NPBrowserProxy;
+struct INPObjectProxy;
+class StreamOperation;
+
+typedef NPError (__stdcall *NP_InitializeFunc)(NPNetscapeFuncs* functions);
+typedef NPError (__stdcall *NP_GetEntryPointsFunc)(NPPluginFuncs* functions);
+typedef NPError (__stdcall *NP_ShutdownFunc)();
+
+class NPPluginProxy {
+ public:
+ ~NPPluginProxy();
+
+ // Initializes and binds this instance to the npapi plugin exported by
+ // the given module. Note that the object takes control of the lifetime of
+ // module, and will unload it at instance destruction time.
+ // Parameters:
+ // browser_proxy: Browser environment in which the plug-in will reside.
+ // window: NPWindow structure initialized for the plug-in.
+ // argument_names: Array of string-argument names to be passed to the
+ // construction routine NPP_New.
+ // argument_values: Array of string-argument values to be passed to the
+ // construction routine NPP_New.
+ // Returns:
+ // true if the plugin successfully loaded and initialized in the provided
+ // window.
+ bool Init(NPBrowserProxy* browser_proxy,
+ const NPWindow& window,
+ const std::vector<CStringA>& argument_names,
+ const std::vector<CStringA>& argument_values);
+
+ // Frees all resources allocated in Init, and blocks on all pending stream
+ // operations.
+ void TearDown();
+
+ // Get the 'v-table' interface for the hosted plugin member functions.
+ const NPPluginFuncs* GetPluginFunctions() const {
+ return &plugin_funcs_;
+ }
+
+ // Get the plugin data associated with this instance.
+ NPP_t* GetNPP() {
+ return &npp_data_;
+ }
+
+ // Return the NPAPI object containing the scripting entry points for the
+ // plugin.
+ HRESULT GetScriptableObject(INPObjectProxy** scriptable_object) const;
+
+ // Return a pointer to the NPAPI browser environment hosting the plugin.
+ NPBrowserProxy* browser_proxy() const {
+ return browser_proxy_;
+ }
+
+ // Registers stream_op with the list of active stream operations.
+ void RegisterStreamOperation(StreamOperation* stream_op);
+
+ // Removes stream_op from the set of active stream operations.
+ void UnregisterStreamOperation(StreamOperation* stream_op);
+
+ static HRESULT Create(NPPluginProxy** instance);
+
+ private:
+ // Basic constructor that does not perform any plugin-specific operations.
+ // Simply prepares the structure for initialization.
+ NPPluginProxy();
+
+ // Stores pointers to the NPAPI entry points present in the passed in module.
+ // This routine also performs one-time initialization of the plug-in,
+ // but does not create a live instance.
+ // loaded_module: Handle to a loaded module containing exports for a npapi
+ // plugin.
+ // Returns:
+ // true if the NPAPI plugin entry points were present in the module.
+ bool MapEntryPoints(HMODULE loaded_module);
+
+ // Pointer to the npapi browser environment in which the plugin lives.
+ // A smart pointer is not used, as this is a back-pointer.
+ NPBrowserProxy* browser_proxy_;
+
+ // Cached scritable object for interacting with the plugin.
+ CComPtr<INPObjectProxy> scriptable_object_;
+
+ // Cache of plugin instance member functions.
+ NPPluginFuncs plugin_funcs_;
+
+ // Pointers to the three main entry points of the plug-in.
+ NP_InitializeFunc NP_Initialize_;
+ NP_GetEntryPointsFunc NP_GetEntryPoints_;
+ NP_ShutdownFunc NP_Shutdown_;
+
+ // The handle to the loaded plugin module. The plugin unloads this module
+ // upon destruction.
+ HMODULE plugin_module_;
+
+ // Plugin instance data passed to all plugin-calls.
+ NPP_t npp_data_;
+
+ typedef std::vector<StreamOperation*> StreamOpArray;
+
+ // The set of currently pending/downloading streaming operations spawned
+ // by the plugin.
+ StreamOpArray active_stream_ops_;
+
+ // Global count of the number of currently live plugin instances. Used
+ // to ensure that NP_Initialize and NP_Shutdown are called only once
+ // per loading of the plugin module.
+ static int kPluginInstanceCount;
+
+ DISALLOW_COPY_AND_ASSIGN(NPPluginProxy);
+};
+
+#endif // O3D_PLUGIN_NPAPI_HOST_CONTROL_WIN_NP_PLUGIN_PROXY_H_
diff --git a/o3d/plugin/npapi_host_control/win/npapi_host_control.cc b/o3d/plugin/npapi_host_control/win/npapi_host_control.cc
new file mode 100644
index 0000000..4d1223e
--- /dev/null
+++ b/o3d/plugin/npapi_host_control/win/npapi_host_control.cc
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// File implements the ActiveX entry points and module class for the
+// NPAPI ActiveX host control
+
+#include "plugin/npapi_host_control/win/module.h"
+#include "plugin/npapi_host_control/win/resource.h"
+
+namespace {
+NPAPIHostControlModule atl_module;
+} // unnamed namespace
+
+extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason,
+ LPVOID lpReserved) {
+ return atl_module.DllMain(dwReason, lpReserved);
+}
+
+
+// Used to determine whether the DLL can be unloaded by OLE.
+STDAPI DllCanUnloadNow(void) {
+ return atl_module.DllCanUnloadNow();
+}
+
+
+// Returns a class factory to create an object of the requested type
+STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) {
+ return atl_module.DllGetClassObject(rclsid, riid, ppv);
+}
+
+
+// Adds entries to the system registry.
+STDAPI DllRegisterServer(void) {
+ // Registers object, typelib and all interfaces in typelib
+ HRESULT hr = atl_module.DllRegisterServer();
+ return hr;
+}
+
+
+// DllUnregisterServer - Removes entries from the system registry
+STDAPI DllUnregisterServer(void) {
+ HRESULT hr = atl_module.DllUnregisterServer();
+ return hr;
+}
diff --git a/o3d/plugin/npapi_host_control/win/npapi_host_control.def b/o3d/plugin/npapi_host_control/win/npapi_host_control.def
new file mode 100644
index 0000000..fe80c77
--- /dev/null
+++ b/o3d/plugin/npapi_host_control/win/npapi_host_control.def
@@ -0,0 +1,9 @@
+; npapi_host_control.def : Declares the module parameters.
+
+LIBRARY "o3d_host.DLL"
+
+EXPORTS
+ DllCanUnloadNow PRIVATE
+ DllGetClassObject PRIVATE
+ DllRegisterServer PRIVATE
+ DllUnregisterServer PRIVATE
diff --git a/o3d/plugin/npapi_host_control/win/npapi_host_control.idl b/o3d/plugin/npapi_host_control/win/npapi_host_control.idl
new file mode 100644
index 0000000..f1f079b
--- /dev/null
+++ b/o3d/plugin/npapi_host_control/win/npapi_host_control.idl
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// npapi_host2.idl : IDL source for npapi_host2
+//
+
+// This file will be processed by the MIDL tool to
+// produce the type library (npapi_host2.tlb) and marshalling code.
+
+#include "olectl.h"
+import "dispex.idl";
+import "oaidl.idl";
+import "ocidl.idl";
+
+[
+ object,
+ uuid(56D79537-181C-4A38-ADF5-E12EC24D7FC7),
+ dual,
+ nonextensible,
+ helpstring("IHostControl Interface"),
+ pointer_default(unique)
+]
+interface IHostControl : IDispatchEx {
+ // Note the assignement of the ids here: These values will not conflict
+ // with the auto-generated ids for the hosted NPAPI plugin object.
+ [propget, helpstring("The description of the installed plugin."), id(1)]
+ HRESULT description([out, retval] BSTR* returned_description);
+ [propget, helpstring("The name of the installed plugin."), id(2)]
+ HRESULT name([out, retval] BSTR* returned_name);
+};
+
+[
+ object,
+ uuid(89681DED-6CE8-407f-989C-C4FEDE5330A8),
+ pointer_default(unique)
+]
+interface INPObjectProxy : IDispatchEx {
+ // The following set of routines are not remoteable, as they all reference
+ // a void pointer, which is relevant to the in-proc instance of classes
+ // implementing this interface.
+ [local] HRESULT GetNPObjectInstance([out] void ** instance);
+ [local] HRESULT SetBrowserProxy([in] void* browser_proxy);
+ [local] HRESULT SetHostedObject([in] void* hosted_object);
+ [local] HRESULT ReleaseHosted();
+};
+
+[
+ uuid(D4F6E31C-E952-48FE-9833-6AE308BD79C6),
+ version(1.0),
+ helpstring("npapi_host2 1.0 Type Library")
+]
+library npapi_host_controlLib
+{
+ importlib("stdole2.tlb");
+ [
+ uuid(9666A772-407E-4F90-BC37-982E8160EB2D),
+ //control,
+ helpstring("HostControl Class")
+ ]
+ coclass HostControl
+ {
+ [default] interface IHostControl;
+ };
+
+ [
+ uuid(1D68424D-7A71-4b61-AE5C-56DBCD8B0E53),
+ ]
+ coclass NPObjectProxy
+ {
+ [default] interface INPObjectProxy;
+ };
+};
diff --git a/o3d/plugin/npapi_host_control/win/npapi_host_control.rc b/o3d/plugin/npapi_host_control/win/npapi_host_control.rc
new file mode 100644
index 0000000..5eee891
--- /dev/null
+++ b/o3d/plugin/npapi_host_control/win/npapi_host_control.rc
@@ -0,0 +1,122 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "winres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""winres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "1 TYPELIB ""npapi_host_control.tlb""\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 1,0,0,1
+ PRODUCTVERSION 1,0,0,1
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904e4"
+ BEGIN
+ VALUE "CompanyName", "Google Inc."
+ VALUE "FileDescription", O3D_PLUGIN_DESCRIPTION
+ VALUE "FileVersion", "1.0.0.0"
+ VALUE "LegalCopyright", "Copyright 2009 Google Inc. All Rights Reserved."
+ VALUE "InternalName", "o3d_host.dll"
+ VALUE "OriginalFilename", "o3d_host.dll"
+ VALUE "ProductName", O3D_PLUGIN_NAME
+ VALUE "ProductVersion", O3D_PLUGIN_VERSION
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1252
+ END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// REGISTRY
+//
+
+IDR_NPAPI_HOST_CONTROL REGISTRY "npapi_host_control.rgs"
+IDR_HOSTCONTROL REGISTRY "host_control.rgs"
+IDR_NPOBJECTPROXY REGISTRY "np_object_proxy.rgs"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE
+BEGIN
+ IDS_PROJNAME "npapi_host_control"
+END
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+1 TYPELIB "npapi_host_control.tlb"
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/o3d/plugin/npapi_host_control/win/npapi_host_control.rgs b/o3d/plugin/npapi_host_control/win/npapi_host_control.rgs
new file mode 100644
index 0000000..1db1fc5
--- /dev/null
+++ b/o3d/plugin/npapi_host_control/win/npapi_host_control.rgs
@@ -0,0 +1,17 @@
+HKCU
+{
+ Software
+ {
+ Classes
+ {
+ NoRemove AppID
+ {
+ '%APPID%' = s 'o3d_host'
+ 'o3d_host.DLL'
+ {
+ val AppID = s '%APPID%'
+ }
+ }
+ }
+ }
+}
diff --git a/o3d/plugin/npapi_host_control/win/precompile.cc b/o3d/plugin/npapi_host_control/win/precompile.cc
new file mode 100644
index 0000000..832211b
--- /dev/null
+++ b/o3d/plugin/npapi_host_control/win/precompile.cc
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "plugin/npapi_host_control/win/precompile.h"
diff --git a/o3d/plugin/npapi_host_control/win/precompile.h b/o3d/plugin/npapi_host_control/win/precompile.h
new file mode 100644
index 0000000..ef3d0b0
--- /dev/null
+++ b/o3d/plugin/npapi_host_control/win/precompile.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// Precompiled header generated by Visual Studio 2008.
+
+#ifndef O3D_PLUGIN_NPAPI_HOST_CONTROL_WIN_PRECOMPILE_H_
+#define O3D_PLUGIN_NPAPI_HOST_CONTROL_WIN_PRECOMPILE_H_
+
+#ifndef STRICT
+#define STRICT
+#endif
+
+// Modify the following defines if you have to target a platform prior to the
+// ones specified below.
+// Refer to MSDN for the latest info on corresponding values for
+// different platforms.
+#ifndef WINVER // Allow use of features specific to Windows XP or later.
+#define WINVER 0x0501 // Change this to the appropriate value to target
+ // other versions of Windows.
+#endif
+
+#ifndef _WIN32_WINNT // Allow use of features specific to Windows XP or later.
+#define _WIN32_WINNT 0x0501 // Change this to the appropriate value to target
+ // other versions of Windows.
+#endif
+
+#ifndef _WIN32_WINDOWS // Allow use of features specific to Windows 98 or
+ // later.
+#define _WIN32_WINDOWS 0x0410 // Change this to the appropriate value to
+ // target Windows Me or later.
+#endif
+
+#ifndef _WIN32_IE // Allow use of features specific to IE 6.0 or later.
+#define _WIN32_IE 0x0600 // Change this to the appropriate value to target
+ // other versions of IE.
+#endif
+
+#define _ATL_APARTMENT_THREADED
+#define _ATL_NO_AUTOMATIC_NAMESPACE
+
+// Some CString constructors will be explicit.
+#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS
+
+
+#include <atlbase.h>
+#include <atlcom.h>
+#include <atlstr.h>
+
+#include "base/basictypes.h"
+#include "plugin/npapi_host_control/win/resource.h"
+
+using namespace ATL;
+
+#endif // O3D_PLUGIN_NPAPI_HOST_CONTROL_WIN_PRECOMPILE_H_
diff --git a/o3d/plugin/npapi_host_control/win/resource.h b/o3d/plugin/npapi_host_control/win/resource.h
new file mode 100644
index 0000000..010ae5e
--- /dev/null
+++ b/o3d/plugin/npapi_host_control/win/resource.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#ifndef O3D_PLUGIN_NPAPI_HOST_CONTROL_WIN_RESOURCE_H_
+#define O3D_PLUGIN_NPAPI_HOST_CONTROL_WIN_RESOURCE_H_
+
+// Microsoft Visual C++ generated include file. Used by npapi_host2.rc
+#define IDS_PROJNAME 100
+#define IDR_NPAPI_HOST_CONTROL 101
+#define IDB_HOSTCONTROL 102
+#define IDR_HOSTCONTROL 103
+#define IDB_NPOBJECTPROXY 104
+#define IDR_NPOBJECTPROXY 105
+
+
+// Next default values for new objects.
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 201
+#define _APS_NEXT_COMMAND_VALUE 32768
+#define _APS_NEXT_CONTROL_VALUE 201
+#define _APS_NEXT_SYMED_VALUE 106
+#endif
+#endif
+
+#endif // O3D_PLUGIN_NPAPI_HOST_CONTROL_WIN_RESOURCE_H_
diff --git a/o3d/plugin/npapi_host_control/win/stream_operation.cc b/o3d/plugin/npapi_host_control/win/stream_operation.cc
new file mode 100644
index 0000000..9cfed9e
--- /dev/null
+++ b/o3d/plugin/npapi_host_control/win/stream_operation.cc
@@ -0,0 +1,756 @@
+// Copyright 2009, Google Inc. All rights reserved.
+// Portions of this file were adapted from the Mozilla project.
+// See https://developer.mozilla.org/en/ActiveX_Control_for_Hosting_Netscape_Plug-ins_in_IE
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Adam Lock <adamlock@eircom.net>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+
+#include "plugin/npapi_host_control/win/stream_operation.h"
+#include "plugin/npapi_host_control/win/host_control.h"
+#include "plugin/npapi_host_control/win/np_plugin_proxy.h"
+
+namespace {
+
+// The following classes are used to package arguments for interacting with
+// the hosted NPAPI plug-in.
+struct NPPDestroyStreamArgs {
+ NPP npp_;
+ NPStream *stream_;
+ NPReason reason_;
+ NPError *return_code_;
+};
+
+struct NPPNewStreamArgs {
+ NPP npp_;
+ NPMIMEType type_;
+ NPStream *stream_;
+ NPBool seekable_;
+ uint16 *stype_;
+ NPError *return_code_;
+};
+
+struct NPPAsFileArgs {
+ NPP npp_;
+ NPStream *stream_;
+ const char* fname_;
+};
+
+struct NPPUrlNotifyArgs {
+ NPP npp_;
+ const char* url_;
+ NPReason reason_;
+ void *notify_data_;
+};
+
+struct NPPWriteReadyArgs {
+ NPP npp_;
+ NPStream *stream_;
+ int32 *return_value_;
+};
+
+struct NPPWriteArgs {
+ NPP npp_;
+ NPStream *stream_;
+ int32 offset_;
+ int32 len_;
+ void* buffer_;
+ int32 *return_value_;
+};
+
+// Helper function that constructs the full url from a moniker associated with
+// a base 'left-side' url prefix, and a stream operation.
+HRESULT ConstructFullURLPath(const StreamOperation& stream_operation,
+ IMoniker* base_moniker,
+ CString* out_string) {
+ ATLASSERT(base_moniker && out_string);
+
+ HRESULT hr = S_OK;
+ CComPtr<IMoniker> full_url_moniker;
+ if (FAILED(hr = CreateURLMonikerEx(base_moniker,
+ stream_operation.GetURL(),
+ &full_url_moniker,
+ URL_MK_UNIFORM))) {
+ return hr;
+ }
+
+ // Determine if the monikers share a common prefix. If they do, then
+ // we can allow the data fetch to proceed - The same origin criteria has been
+ // satisfied.
+ CComPtr<IMoniker> prefix_moniker;
+ bool urls_contain_prefix = false;
+ hr = MonikerCommonPrefixWith(base_moniker, full_url_moniker, &prefix_moniker);
+ if (SUCCEEDED(hr)) {
+ urls_contain_prefix = true;
+ }
+
+ CComPtr<IBindCtx> bind_context;
+ if (FAILED(hr = CreateBindCtx(0, &bind_context))) {
+ return hr;
+ }
+
+ CComPtr<IMalloc> malloc_interface;
+ if (FAILED(hr = CoGetMalloc(1, &malloc_interface))) {
+ return hr;
+ }
+
+ LPOLESTR full_url_path = NULL;
+ if (FAILED(hr = full_url_moniker->GetDisplayName(bind_context,
+ NULL,
+ &full_url_path))) {
+ return hr;
+ }
+
+ if (!urls_contain_prefix) {
+ // If the urls do not contain a common prefix, validate the access request
+ // based on the fully qualified uri's.
+ LPOLESTR base_path_name = NULL;
+ if (FAILED(hr = base_moniker->GetDisplayName(bind_context,
+ NULL,
+ &base_path_name))) {
+ malloc_interface->Free(full_url_path);
+ return hr;
+ }
+ }
+
+ *out_string = full_url_path;
+ malloc_interface->Free(full_url_path);
+
+ return S_OK;
+}
+
+// Helper routine implementing a custom version of SendMessage(...).
+// The StreamingOperation class uses windows messages to communicate transfer
+// notifications to the plug-in. This is required so that the plug-in will
+// receive notifications synchronously on the main-browser thread.
+// SendMessage is not appropriate, because messages 'sent' to a window are NOT
+// processed during DispatchMessage, but instead during GetMessage, PeekMessage
+// and others. Because the JScript engine periodically peeks the message
+// queue during JavaScript evaluation, the plug-in would be notified, and
+// potentially call back into the JavaScript environment causing unexpected
+// reentrancy.
+HRESULT CustomSendMessage(HWND window_handle, UINT message, LPARAM l_param) {
+ // Mimic the behaviour of SendMessage by posting to the window, and then
+ // blocking on an event. Note that the message handlers must set
+ // the event.
+ HANDLE local_event = CreateEvent(NULL, TRUE, FALSE, NULL);
+ if (!local_event) {
+ return E_FAIL;
+ }
+
+ if (!PostMessage(window_handle, message,
+ reinterpret_cast<WPARAM>(&local_event), l_param)) {
+ CloseHandle(local_event);
+ return E_FAIL;
+ }
+
+ HRESULT hr;
+ static const unsigned int kWaitTimeOut = 120000;
+ bool done = false;
+ while (!done) {
+ DWORD wait_code = MsgWaitForMultipleObjects(1,
+ &local_event,
+ FALSE,
+ kWaitTimeOut,
+ QS_ALLINPUT);
+ switch (wait_code) {
+ case WAIT_OBJECT_0:
+ hr = S_OK;
+ done = true;
+ break;
+ case WAIT_OBJECT_0 + 1:
+ MSG msg;
+ GetMessage(&msg, NULL, 0, 0);
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ break;
+ case WAIT_TIMEOUT:
+ // If the plug-in is busy processing JavaScript code, it's possible
+ // that we may time-out here. We don't break out of the loop, because
+ // the event will eventually be signaled when the JS is done
+ // processing.
+ ATLASSERT(false && "Time out waiting for response from main thread.");
+ break;
+ default:
+ ATLASSERT(false &&
+ "Critical failure waiting for response from main thread.");
+ hr = E_FAIL;
+ done = true;
+ break;
+ }
+ }
+
+ CloseHandle(local_event);
+ return hr;
+}
+
+} // unnamed namespace
+
+StreamOperation::StreamOperation()
+ : stream_size_(0),
+ stream_received_(0),
+ stream_type_(NP_NORMAL),
+ temp_file_(NULL),
+ thread_handle_(NULL),
+ cancel_requested_(false) {
+ memset(&np_stream_, 0, sizeof(np_stream_));
+}
+
+StreamOperation::~StreamOperation() {
+}
+
+void StreamOperation::OnFinalMessage(HWND hWnd) {
+ CWindowImplBase::OnFinalMessage(hWnd);
+ if (owner_) {
+ owner_->UnregisterStreamOperation(this);
+ }
+
+ // The binding holds a reference to the stream operation, which forms
+ // a cyclic reference chain. Release the binding so that both objects
+ // can be destroyed.
+ binding_ = NULL;
+
+ // The object has an artificially boosted reference count to ensure that it
+ // stays alive as long as it may receive window messages. Release this
+ // reference here, and potentially free the instance.
+ Release();
+}
+
+HRESULT STDMETHODCALLTYPE StreamOperation::OnStartBinding(DWORD dwReserved,
+ IBinding *pib) {
+ binding_ = pib;
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE StreamOperation::GetPriority(LONG *pnPriority) {
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE StreamOperation::OnLowResource(DWORD reserved) {
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE StreamOperation::OnProgress(ULONG ulProgress,
+ ULONG ulProgressMax,
+ ULONG ulStatusCode,
+ LPCWSTR szStatusText) {
+ // Capture URL re-directs and MIME-type status notifications.
+ switch (ulStatusCode) {
+ case BINDSTATUS_BEGINDOWNLOADDATA:
+ case BINDSTATUS_REDIRECTING:
+ url_ = szStatusText;
+ break;
+ case BINDSTATUS_MIMETYPEAVAILABLE:
+ content_type_ = szStatusText;
+ break;
+ default:
+ break;
+ }
+
+ // Track the current progress of the streaming transfer.
+ stream_size_ = ulProgressMax;
+ stream_received_ = ulProgress;
+
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE StreamOperation::OnStopBinding(HRESULT hresult,
+ LPCWSTR szError) {
+ NPReason reason = SUCCEEDED(hresult) ? NPRES_DONE : NPRES_NETWORK_ERR;
+ USES_CONVERSION;
+
+ // Notify the calling plug-in that the transfer has completed.
+ if (stream_type_ == NP_ASFILE || stream_type_ == NP_ASFILEONLY) {
+ if (temp_file_) {
+ fclose(temp_file_);
+ }
+
+ if (reason == NPRES_DONE) {
+ NPPAsFileArgs arguments = {
+ owner_->GetNPP(),
+ GetNPStream(),
+ W2A(temp_file_name_)
+ };
+ CustomSendMessage(m_hWnd, WM_NPP_ASFILE,
+ reinterpret_cast<LPARAM>(&arguments));
+ }
+ }
+
+ if (reason == NPRES_DONE) {
+ NPError error_return;
+ NPPDestroyStreamArgs destroy_stream_args = {
+ owner_->GetNPP(),
+ GetNPStream(),
+ reason,
+ &error_return
+ };
+ CustomSendMessage(m_hWnd, WM_NPP_DESTROYSTREAM,
+ reinterpret_cast<LPARAM>(&destroy_stream_args));
+ ATLASSERT(NPERR_NO_ERROR == error_return);
+ }
+
+ NPPUrlNotifyArgs url_args = {
+ owner_->GetNPP(),
+ W2A(url_),
+ reason,
+ GetNotifyData()
+ };
+ CustomSendMessage(m_hWnd, WM_NPP_URLNOTIFY,
+ reinterpret_cast<LPARAM>(&url_args));
+
+ // Clear the intermediate file from the cache.
+ _wremove(temp_file_name_);
+ temp_file_name_ = L"";
+
+ // The operation has completed, so tear-down the intermediate window, and
+ // exit the worker thread.
+ CustomSendMessage(m_hWnd, WM_TEAR_DOWN, 0);
+ PostQuitMessage(0);
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE StreamOperation::GetBindInfo(DWORD *grfBINDF,
+ BINDINFO *pbindinfo) {
+ // Request an asynchronous transfer of the data.
+ *grfBINDF = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE |
+ BINDF_GETNEWESTVERSION;
+
+ int cbSize = pbindinfo->cbSize;
+ memset(pbindinfo, 0, cbSize);
+ pbindinfo->cbSize = cbSize;
+ pbindinfo->dwBindVerb = BINDVERB_GET;
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE StreamOperation::OnDataAvailable(
+ DWORD grfBSCF,
+ DWORD dwSize,
+ FORMATETC *pformatetc,
+ STGMEDIUM *pstgmed) {
+ if (pstgmed->tymed != TYMED_ISTREAM || !pstgmed->pstm) {
+ return S_OK;
+ }
+
+ // Don't bother processing any data if the stream has been canceled.
+ if (cancel_requested_) {
+ return S_OK;
+ }
+
+ // Notify the plugin that a new stream has been opened.
+ if (grfBSCF & BSCF_FIRSTDATANOTIFICATION) {
+ USES_CONVERSION;
+ np_stream_.url = W2CA(url_);
+ np_stream_.end = stream_size_;
+ np_stream_.lastmodified = 0;
+ np_stream_.notifyData = GetNotifyData();
+
+ uint16 stream_type = NP_NORMAL;
+
+ NPError np_error;
+ NPPNewStreamArgs new_stream_args = {
+ owner_->GetNPP(),
+ const_cast<char*>(W2CA(GetContentType())),
+ GetNPStream(),
+ FALSE,
+ &stream_type,
+ &np_error
+ };
+ CustomSendMessage(m_hWnd, WM_NPP_NEWSTREAM,
+ reinterpret_cast<LPARAM>(&new_stream_args));
+ if (np_error != NPERR_NO_ERROR) {
+ return E_FAIL;
+ }
+
+ // Cache the stream type requested by the plug-in.
+ stream_type_ = stream_type;
+ }
+
+ if (grfBSCF & BSCF_INTERMEDIATEDATANOTIFICATION ||
+ grfBSCF & BSCF_LASTDATANOTIFICATION) {
+ // Read all of the available data, and pass it to the plug-in, if requested.
+ HRESULT hr;
+ char local_data[16384];
+ int bytes_received_total = 0;
+ // If a large number of bytes have been received, then this loop can
+ // take a long time to complete - which will block the user from leaving
+ // the page as the plug-in waits for all transfers to complete. We
+ // add a check on cancel_requested_ to allow for early bail-out.
+ while (bytes_received_total < dwSize &&
+ !cancel_requested_) {
+ int bytes_to_read = dwSize - bytes_received_total;
+ unsigned long bytes_read = 0;
+
+ if (bytes_to_read > sizeof(local_data)) {
+ bytes_to_read = sizeof(local_data);
+ }
+
+ if (stream_type_ == NP_NORMAL || stream_type_ == NP_ASFILE) {
+ int32 bytes_to_accept;
+ NPPWriteReadyArgs write_ready_args = {
+ owner_->GetNPP(),
+ GetNPStream(),
+ &bytes_to_accept
+ };
+ CustomSendMessage(m_hWnd, WM_NPP_WRITEREADY,
+ reinterpret_cast<LPARAM>(&write_ready_args));
+
+ if (bytes_to_read > bytes_to_accept) {
+ bytes_to_read = bytes_to_accept;
+ }
+ }
+
+ // If the plug-in has indicated that it is not prepared to read any data,
+ // then bail early.
+ if (bytes_to_read == 0) {
+ break;
+ }
+
+ hr = pstgmed->pstm->Read(local_data, bytes_to_read, &bytes_read);
+ if (FAILED(hr) || S_FALSE == hr) {
+ break;
+ }
+
+ // Pass the data to the plug-in.
+ if (stream_type_ == NP_NORMAL || stream_type_ == NP_ASFILE) {
+ int consumed_bytes;
+ NPPWriteArgs write_args = {
+ owner_->GetNPP(),
+ GetNPStream(),
+ bytes_received_total,
+ bytes_read,
+ local_data,
+ &consumed_bytes
+ };
+ CustomSendMessage(m_hWnd, WM_NPP_WRITE,
+ reinterpret_cast<LPARAM>(&write_args));
+ ATLASSERT(consumed_bytes == bytes_read);
+ }
+
+ if (stream_type_ == NP_ASFILE || stream_type_ == NP_ASFILEONLY) {
+ // If the plug-in requested access to the data through a file, then
+ // create a temporary file and write the data to it.
+ if (!temp_file_) {
+ temp_file_name_= _wtempnam(NULL, L"npapi_host_temp");
+ _wfopen_s(&temp_file_, temp_file_name_, L"wb");
+ }
+ fwrite(local_data, bytes_read, 1, temp_file_);
+ }
+ bytes_received_total += bytes_read;
+ }
+ }
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE StreamOperation::OnObjectAvailable(REFIID riid,
+ IUnknown *punk) {
+ return S_OK;
+}
+
+HRESULT StreamOperation::OpenURL(NPPluginProxy *owning_plugin,
+ const wchar_t *url,
+ void *notify_data) {
+ // The StreamOperation instance is created with a ref-count of zero,
+ // so we explicitly attach a CComPtr to the object to boost the count, and
+ // manage the lifetime of the object.
+ CComObject<StreamOperation> *stream_ptr;
+ CComObject<StreamOperation>::CreateInstance(&stream_ptr);
+ CComPtr<CComObject<StreamOperation> > stream_object = stream_ptr;
+ if (!stream_object) {
+ return E_OUTOFMEMORY;
+ }
+
+ CComPtr<CHostControl> host_control =
+ owning_plugin->browser_proxy()->GetHostingControl();
+ CComPtr<IMoniker> base_url_moniker = host_control->GetURLMoniker();
+
+ stream_object->SetURL(url);
+ stream_object->SetNotifyData(notify_data);
+ stream_object->SetOwner(owning_plugin);
+
+ CString full_path;
+ HRESULT hr;
+ if (FAILED(hr = ConstructFullURLPath(*stream_object,
+ base_url_moniker,
+ &full_path))) {
+ return hr;
+ }
+
+ stream_object->SetFullURL(full_path);
+
+ // Create an object window on this thread that will be sent messages when
+ // something happens on the worker thread.
+ HWND temporary_window = stream_object->Create(HWND_DESKTOP);
+ ATLASSERT(temporary_window);
+ if (!temporary_window) {
+ return E_FAIL;
+ }
+
+ // Artificially increment the reference count of the stream_object instance
+ // to ensure that the object will not be deleted until WM_NC_DESTROY is
+ // processed and OnFinalMessage is invoked.
+ // Note: The operator-> is not used, because it returns a type overloading
+ // the public access of AddRef/Release.
+ (*stream_object).AddRef();
+
+ stream_object->thread_handle_ = reinterpret_cast<HANDLE>(
+ _beginthreadex(NULL,
+ 0,
+ WorkerProc,
+ static_cast<void*>(stream_object),
+ CREATE_SUSPENDED,
+ NULL));
+ ATLASSERT(stream_object->thread_handle_);
+ if (!stream_object->thread_handle_) {
+ stream_object->DestroyWindow();
+ return E_FAIL;
+ }
+
+ owning_plugin->RegisterStreamOperation(stream_object);
+ if (!ResumeThread(stream_object->thread_handle_)) {
+ owning_plugin->UnregisterStreamOperation(stream_object);
+ stream_object->DestroyWindow();
+ // If the thread never resumed, then we can safely terminate it here - it
+ // has not had a chance to allocate any resources that would be leaked.
+ TerminateThread(stream_object->thread_handle_, 0);
+ return E_FAIL;
+ }
+
+ return S_OK;
+}
+
+unsigned int __stdcall StreamOperation::WorkerProc(void* worker_arguments) {
+ CComObject<StreamOperation> *stream_object =
+ static_cast<CComObject<StreamOperation> *>(worker_arguments);
+ ATLASSERT(stream_object);
+
+ // Initialize the COM run-time for this new thread.
+ HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
+ ATLASSERT(SUCCEEDED(hr) && "Failure to initialize worker COM apartment.");
+ if (FAILED(hr)) {
+ CustomSendMessage(stream_object->m_hWnd, WM_TEAR_DOWN, 0);
+ CoUninitialize();
+ return 0;
+ }
+
+ {
+ // Get the ActiveX control so the request is within the context of the
+ // plugin. Among other things, this lets the browser reject file:// uris
+ // when the page is loaded over http://.
+ CComPtr<IUnknown> caller;
+ stream_object->owner_->browser_proxy()->GetHostingControl()->QueryInterface(
+ IID_IUnknown,
+ reinterpret_cast<void**>(&caller));
+
+ // Note that the OnStopBinding(...) routine, which is always called, will
+ // post WM_QUIT to this thread.
+ hr = URLOpenStream(caller, stream_object->GetFullURL(), 0,
+ static_cast<IBindStatusCallback*>(stream_object));
+
+ // Pump messages until WM_QUIT arrives
+ MSG msg;
+ while (GetMessage(&msg, NULL, 0, 0)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+
+ CoUninitialize();
+ return 0;
+}
+
+LRESULT StreamOperation::OnNPPNewStream(UINT uMsg,
+ WPARAM wParam,
+ LPARAM lParam,
+ BOOL& bHandled) {
+ NPPNewStreamArgs *args = reinterpret_cast<NPPNewStreamArgs*>(lParam);
+ ATLASSERT(args);
+
+ // If the stream was canceled, don't pass the notification to the plug-in.
+ if (!cancel_requested_) {
+ *args->return_code_ = owner_->GetPluginFunctions()->newstream(
+ args->npp_,
+ args->type_,
+ args->stream_,
+ args->seekable_,
+ args->stype_);
+ } else {
+ *args->return_code_ = NPERR_GENERIC_ERROR;
+ }
+
+ if (wParam) {
+ HANDLE* event_handle = reinterpret_cast<HANDLE*>(wParam);
+ SetEvent(*event_handle);
+ }
+ return 0;
+}
+
+LRESULT StreamOperation::OnNPPDestroyStream(UINT uMsg,
+ WPARAM wParam,
+ LPARAM lParam,
+ BOOL& bHandled) {
+ NPPDestroyStreamArgs *args = reinterpret_cast<NPPDestroyStreamArgs*>(lParam);
+ ATLASSERT(args);
+
+ // If the stream was canceled, don't pass the notification to the plug-in.
+ if (!cancel_requested_) {
+ *args->return_code_ = owner_->GetPluginFunctions()->destroystream(
+ args->npp_,
+ args->stream_,
+ args->reason_);
+ } else {
+ *args->return_code_ = NPERR_NO_ERROR;
+ }
+
+ if (wParam) {
+ HANDLE* event_handle = reinterpret_cast<HANDLE*>(wParam);
+ SetEvent(*event_handle);
+ }
+ return 0;
+}
+
+LRESULT StreamOperation::OnNPPAsFile(UINT uMsg,
+ WPARAM wParam,
+ LPARAM lParam,
+ BOOL& bHandled) {
+ NPPAsFileArgs *args = reinterpret_cast<NPPAsFileArgs*>(lParam);
+ ATLASSERT(args);
+
+ // If the stream was canceled, don't pass the notification to the plug-in.
+ if (!cancel_requested_) {
+ owner_->GetPluginFunctions()->asfile(args->npp_, args->stream_,
+ args->fname_);
+ }
+
+ if (wParam) {
+ HANDLE* event_handle = reinterpret_cast<HANDLE*>(wParam);
+ SetEvent(*event_handle);
+ }
+ return 0;
+}
+
+LRESULT StreamOperation::OnNPPUrlNotify(UINT uMsg,
+ WPARAM wParam,
+ LPARAM lParam,
+ BOOL& bHandled) {
+ NPPUrlNotifyArgs *args = reinterpret_cast<NPPUrlNotifyArgs*>(lParam);
+ ATLASSERT(args);
+
+ // If the stream was canceled, don't pass the notification to the plug-in.
+ if (!cancel_requested_) {
+ owner_->GetPluginFunctions()->urlnotify(args->npp_, args->url_,
+ args->reason_, args->notify_data_);
+ }
+ if (wParam) {
+ HANDLE* event_handle = reinterpret_cast<HANDLE*>(wParam);
+ SetEvent(*event_handle);
+ }
+ return 0;
+}
+
+LRESULT StreamOperation::OnNPPWriteReady(UINT uMsg,
+ WPARAM wParam,
+ LPARAM lParam,
+ BOOL& bHandled) {
+ NPPWriteReadyArgs *args = reinterpret_cast<NPPWriteReadyArgs*>(lParam);
+ ATLASSERT(args);
+
+ // If the stream was canceled, don't pass the notification to the plug-in.
+ if (!cancel_requested_) {
+ *args->return_value_ = owner_->GetPluginFunctions()->writeready(
+ args->npp_,
+ args->stream_);
+ } else {
+ // Indicate to the download thread that 0 bytes are ready to be received.
+ *args->return_value_ = 0;
+ }
+
+ if (wParam) {
+ HANDLE* event_handle = reinterpret_cast<HANDLE*>(wParam);
+ SetEvent(*event_handle);
+ }
+ return 0;
+}
+
+LRESULT StreamOperation::OnNPPWrite(UINT uMsg,
+ WPARAM wParam,
+ LPARAM lParam,
+ BOOL& bHandled) {
+ NPPWriteArgs *args = reinterpret_cast<NPPWriteArgs*>(lParam);
+ ATLASSERT(args);
+
+ // If the stream was canceled, don't pass the notification to the plug-in.
+ if (!cancel_requested_) {
+ *args->return_value_ = owner_->GetPluginFunctions()->write(
+ args->npp_,
+ args->stream_,
+ args->offset_,
+ args->len_,
+ args->buffer_);
+ } else {
+ *args->return_value_ = args->len_;
+ }
+
+ if (wParam) {
+ HANDLE* event_handle = reinterpret_cast<HANDLE*>(wParam);
+ SetEvent(*event_handle);
+ }
+ return 0;
+}
+
+LRESULT StreamOperation::OnTearDown(UINT uMsg,
+ WPARAM wParam,
+ LPARAM lParam,
+ BOOL& bHandled) {
+ // DestroyWindow must be called on the same thread as where the window was
+ // constructed, so make the call here.
+ DestroyWindow();
+
+ if (wParam) {
+ HANDLE* event_handle = reinterpret_cast<HANDLE*>(wParam);
+ SetEvent(*event_handle);
+ }
+ return 0;
+}
+
+HRESULT StreamOperation::RequestCancellation() {
+ ATLASSERT(binding_ &&
+ "Cancellation request on a stream that has not been bound.");
+ cancel_requested_ = true;
+ if (binding_) {
+ return binding_->Abort();
+ }
+ return S_OK;
+}
diff --git a/o3d/plugin/npapi_host_control/win/stream_operation.h b/o3d/plugin/npapi_host_control/win/stream_operation.h
new file mode 100644
index 0000000..8149b81
--- /dev/null
+++ b/o3d/plugin/npapi_host_control/win/stream_operation.h
@@ -0,0 +1,271 @@
+// Copyright 2009, Google Inc. All rights reserved.
+// Portions of this file were adapted from the Mozilla project.
+// See https://developer.mozilla.org/en/ActiveX_Control_for_Hosting_Netscape_Plug-ins_in_IE
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Adam Lock <adamlock@eircom.net>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+
+// File declaring StreamOperation class encapsulating basic support
+// for the NPAPI GetURL streaming interface.
+
+#ifndef O3D_PLUGIN_NPAPI_HOST_CONTROL_WIN_STREAM_OPERATION_H_
+#define O3D_PLUGIN_NPAPI_HOST_CONTROL_WIN_STREAM_OPERATION_H_
+
+#include <atlwin.h>
+#include <atlstr.h>
+#include <urlmon.h>
+
+#include "third_party/npapi/files/include/npupp.h"
+
+class NPPluginProxy;
+
+#define WM_NPP_NEWSTREAM WM_USER
+#define WM_NPP_ASFILE WM_USER + 1
+#define WM_NPP_DESTROYSTREAM WM_USER + 2
+#define WM_NPP_URLNOTIFY WM_USER + 3
+#define WM_NPP_WRITEREADY WM_USER + 4
+#define WM_NPP_WRITE WM_USER + 5
+
+#define WM_TEAR_DOWN WM_USER + 10
+
+// StreamOperation class used to provide a subset of the NPAPI GetURL* API.
+// Class makes use of urlmon's IBindStatusCallback to receive notifications
+// from urlmon as data is transferred. Refer to the MSDN documentation
+// for information on the usage model of IBindStatusCallback.
+class ATL_NO_VTABLE StreamOperation :
+ public CComObjectRootEx<CComMultiThreadModel>,
+ public CWindowImpl<StreamOperation, CWindow, CNullTraits>,
+ public CComCoClass<StreamOperation, &CLSID_NULL>,
+ public IBindStatusCallback {
+ public:
+ typedef CWindowImpl<StreamOperation, CWindow, CNullTraits> CWindowImplBase;
+
+ StreamOperation();
+ ~StreamOperation();
+
+ // Assign/Retrieve the url from which to stream the data.
+ void SetURL(const wchar_t* url) {
+ url_ = url;
+ }
+
+ const ATL::CStringW& GetURL() const {
+ return url_;
+ }
+
+ void SetFullURL(const wchar_t* url) {
+ full_url_ = url;
+ }
+
+ const ATL::CStringW& GetFullURL() const {
+ return full_url_;
+ }
+
+ // Returns the MIME-type of the data stream.
+ const ATL::CStringW& GetContentType() const {
+ return content_type_;
+ }
+
+ NPStream* GetNPStream() {
+ return &np_stream_;
+ }
+
+ HANDLE GetThreadHandle() const {
+ return thread_handle_;
+ }
+
+ // Assign the owning plugin pointer that spawned this operation.
+ void SetOwner(NPPluginProxy* plugin) {
+ owner_ = plugin;
+ }
+
+ // Assign/Retrieve the opaque NPAPI-provided callback data for the
+ // stream-operation.
+ void SetNotifyData(void *notify_data) {
+ notify_data_ = notify_data;
+ }
+
+ void* GetNotifyData() {
+ return notify_data_;
+ }
+
+ // Call to request that the streaming operation terminate early. After this
+ // has been called, no further data notifications will take place. The next,
+ // and last notification will be through
+ // IBindStatusCallback::OnStopBinding(...).
+ HRESULT RequestCancellation();
+
+BEGIN_COM_MAP(StreamOperation)
+ COM_INTERFACE_ENTRY(IBindStatusCallback)
+END_COM_MAP()
+
+ // To allow interaction with non-thread-safe NPAPI plug-in modules, the
+ // streaming code uses Windows message pumps to serialize the interactions
+ // calling back into the plug-in on the thread in which the plug-in resides.
+ // When information about the state of the streaming request is provided
+ // through a IBindStatusCallback routine, the thread will post a message
+ // to the window created by the StreamOperation instance. Because this
+ // window will reside in the same thread as the calling plug-in, we are
+ // guaranteed serialization and mutual exclusion of the handling of the
+ // routines below.
+BEGIN_MSG_MAP(StreamOperation)
+ MESSAGE_HANDLER(WM_NPP_NEWSTREAM, OnNPPNewStream)
+ MESSAGE_HANDLER(WM_NPP_ASFILE, OnNPPAsFile)
+ MESSAGE_HANDLER(WM_NPP_DESTROYSTREAM, OnNPPDestroyStream)
+ MESSAGE_HANDLER(WM_NPP_URLNOTIFY, OnNPPUrlNotify)
+ MESSAGE_HANDLER(WM_NPP_WRITEREADY, OnNPPWriteReady)
+ MESSAGE_HANDLER(WM_NPP_WRITE, OnNPPWrite)
+ MESSAGE_HANDLER(WM_TEAR_DOWN, OnTearDown);
+END_MSG_MAP()
+
+ // Helper function called in response to WM_TEAR_DOWN to destroy class
+ // resources on the appropriate thread.
+ LRESULT OnTearDown(UINT uMsg,
+ WPARAM wParam,
+ LPARAM lParam,
+ BOOL& bHandled);
+
+ // The following OnNPP... routines forward the respective notification to
+ // the plugin that spawned the data transmission.
+ LRESULT OnNPPNewStream(UINT uMsg,
+ WPARAM wParam,
+ LPARAM lParam,
+ BOOL& bHandled);
+
+ LRESULT OnNPPDestroyStream(UINT uMsg,
+ WPARAM wParam,
+ LPARAM lParam,
+ BOOL& bHandled);
+
+ LRESULT OnNPPAsFile(UINT uMsg,
+ WPARAM wParam,
+ LPARAM lParam,
+ BOOL& bHandled);
+
+ LRESULT OnNPPUrlNotify(UINT uMsg,
+ WPARAM wParam,
+ LPARAM lParam,
+ BOOL& bHandled);
+
+ LRESULT OnNPPWriteReady(UINT uMsg,
+ WPARAM wParam,
+ LPARAM lParam,
+ BOOL& bHandled);
+
+ LRESULT OnNPPWrite(UINT uMsg,
+ WPARAM wParam,
+ LPARAM lParam,
+ BOOL& bHandled);
+
+ // Methods implementing the IBindStatusCallback interface. Refer to
+ // the MSDN documentation for the expected behaviour of these routines.
+ virtual HRESULT STDMETHODCALLTYPE OnStartBinding(DWORD dwReserved,
+ IBinding *pib);
+
+ virtual HRESULT STDMETHODCALLTYPE GetPriority(LONG *pnPriority);
+
+ virtual HRESULT STDMETHODCALLTYPE OnLowResource(DWORD reserved);
+
+ virtual HRESULT STDMETHODCALLTYPE OnProgress(ULONG ulProgress,
+ ULONG ulProgressMax,
+ ULONG ulStatusCode,
+ LPCWSTR szStatusText);
+
+ virtual HRESULT STDMETHODCALLTYPE OnStopBinding(HRESULT hresult,
+ LPCWSTR szError);
+
+ virtual HRESULT STDMETHODCALLTYPE GetBindInfo(DWORD *grfBINDF,
+ BINDINFO *pbindinfo);
+
+ virtual HRESULT STDMETHODCALLTYPE OnDataAvailable(DWORD grfBSCF,
+ DWORD dwSize,
+ FORMATETC *pformatetc,
+ STGMEDIUM *pstgmed);
+
+ virtual HRESULT STDMETHODCALLTYPE OnObjectAvailable(REFIID riid,
+ IUnknown *punk);
+
+ static HRESULT OpenURL(NPPluginProxy *owning_plugin, const wchar_t* url,
+ void *notify_data);
+
+ virtual void OnFinalMessage(HWND hWnd);
+
+ DECLARE_PROTECT_FINAL_CONSTRUCT();
+ private:
+ // Callback object for interacting with the urlmon streaming manager.
+ ATL::CComPtr<IBinding> binding_;
+
+ // The url from which the data is fetched, and the associated MIME-type.
+ ATL::CStringW url_;
+ ATL::CStringW full_url_;
+ ATL::CStringW content_type_;
+
+ // Back-pointer to the plug-in instance requesting the data transfer.
+ NPPluginProxy *owner_;
+
+ // Opaque data specified at request initiation that is passed back to the
+ // plug-in during call-back invocation.
+ void *notify_data_;
+
+ NPStream np_stream_;
+
+ int stream_size_;
+ int stream_received_;
+
+ // Cache of the type of stream requested by the plug-in. May be one of:
+ // NP_NORMAL, NP_ASFILE, NP_ASFILEONLY.
+ int stream_type_;
+
+ // Pointer to file handle used to save incoming data if the stream type is
+ // NP_ASFILE or NP_ASFILEONLY.
+ FILE* temp_file_;
+
+ // Temporary file name.
+ CStringW temp_file_name_;
+
+ // Handle to the worker-thread where the streaming notifications are received.
+ HANDLE thread_handle_;
+
+ // Value used to indicate the streaming operation should stop processing
+ // input data.
+ bool cancel_requested_;
+
+ static unsigned int __stdcall WorkerProc(void *worker_arguments);
+
+ DISALLOW_COPY_AND_ASSIGN(StreamOperation);
+};
+
+#endif // O3D_PLUGIN_NPAPI_HOST_CONTROL_WIN_STREAM_OPERATION_H_
diff --git a/o3d/plugin/npapi_host_control/win/variant_utils.cc b/o3d/plugin/npapi_host_control/win/variant_utils.cc
new file mode 100644
index 0000000..fd0e441
--- /dev/null
+++ b/o3d/plugin/npapi_host_control/win/variant_utils.cc
@@ -0,0 +1,207 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "plugin/npapi_host_control/win/variant_utils.h"
+#include "base/scoped_ptr.h"
+#include "plugin/npapi_host_control/win/dispatch_proxy.h"
+
+void VariantToNPVariant(NPBrowserProxy* browser_proxy,
+ const VARIANT* source,
+ NPVariant* destination) {
+ ATLASSERT(!(source->vt & VT_ARRAY));
+
+ switch (source->vt) {
+ case VT_EMPTY:
+ VOID_TO_NPVARIANT(*destination);
+ break;
+ case VT_NULL:
+ NULL_TO_NPVARIANT(*destination);
+ break;
+ case VT_I2:
+ INT32_TO_NPVARIANT(source->iVal, *destination);
+ break;
+ case VT_I4:
+ INT32_TO_NPVARIANT(source->intVal, *destination);
+ break;
+ case VT_R4:
+ DOUBLE_TO_NPVARIANT(source->fltVal, *destination);
+ break;
+ case VT_R8:
+ DOUBLE_TO_NPVARIANT(source->dblVal, *destination);
+ break;
+ case VT_CY:
+ case VT_DATE:
+ ATLASSERT(false);
+ break;
+ case VT_BSTR: {
+ // BSTR objects may be NULL to indicate an empty string.
+ if (source->bstrVal) {
+ int required_size = WideCharToMultiByte(CP_UTF8, 0, source->bstrVal,
+ -1, NULL, 0, NULL, NULL);
+ ATLASSERT(required_size != 0);
+
+ char* string_contents = static_cast<char*>(
+ browser_proxy->GetBrowserFunctions()->memalloc(required_size));
+ WideCharToMultiByte(CP_UTF8, 0, source->bstrVal, -1, string_contents,
+ required_size, NULL, NULL);
+ STRINGN_TO_NPVARIANT(string_contents, required_size - 1,
+ *destination);
+ } else {
+ char* string_contents = static_cast<char*>(
+ browser_proxy->GetBrowserFunctions()->memalloc(1));
+ string_contents[0] = 0;
+ STRINGN_TO_NPVARIANT(string_contents, 0, *destination);
+ }
+ break;
+ }
+ case VT_DISPATCH:
+ OBJECT_TO_NPVARIANT(browser_proxy->GetNPObject(source->pdispVal),
+ *destination);
+ break;
+ case VT_ERROR:
+ ATLASSERT(false);
+ break;
+ case VT_BOOL:
+ BOOLEAN_TO_NPVARIANT(source->boolVal, *destination);
+ break;
+ case VT_VARIANT:
+ case VT_UNKNOWN:
+ case VT_DECIMAL:
+ ATLASSERT(false);
+ break;
+ case VT_I1:
+ INT32_TO_NPVARIANT(source->iVal, *destination);
+ break;
+ case VT_UI1:
+ INT32_TO_NPVARIANT(source->iVal, *destination);
+ break;
+ case VT_UI2:
+ INT32_TO_NPVARIANT(source->iVal, *destination);
+ break;
+ case VT_UI4:
+ INT32_TO_NPVARIANT(source->iVal, *destination);
+ break;
+ case VT_I8:
+ case VT_UI8:
+ ATLASSERT(false);
+ break;
+ case VT_INT:
+ INT32_TO_NPVARIANT(source->iVal, *destination);
+ break;
+ case VT_UINT:
+ INT32_TO_NPVARIANT(source->iVal, *destination);
+ break;
+ case VT_VOID:
+ VOID_TO_NPVARIANT(*destination);
+ break;
+ case VT_HRESULT:
+ case VT_PTR:
+ case VT_SAFEARRAY:
+ case VT_CARRAY:
+ case VT_USERDEFINED:
+ case VT_LPSTR:
+ case VT_LPWSTR:
+ case VT_RECORD:
+ case VT_INT_PTR:
+ case VT_UINT_PTR:
+ case VT_FILETIME:
+ case VT_BLOB:
+ case VT_STREAM:
+ case VT_STORAGE:
+ case VT_STREAMED_OBJECT:
+ case VT_STORED_OBJECT:
+ case VT_BLOB_OBJECT:
+ case VT_CF:
+ case VT_CLSID:
+ case VT_VERSIONED_STREAM:
+ case VT_BSTR_BLOB:
+ case VT_VECTOR:
+ case VT_ARRAY:
+ case VT_BYREF:
+ case VT_RESERVED:
+ case VT_ILLEGAL:
+ ATLASSERT(false);
+ break;
+ default:
+ break;
+ }
+}
+
+void NPVariantToVariant(NPBrowserProxy* browser_proxy,
+ const NPVariant* source,
+ CComVariant* destination) {
+ if (!destination) {
+ return;
+ }
+
+ switch (source->type) {
+ case NPVariantType_Void:
+ destination->ChangeType(VT_VOID, NULL);
+ break;
+ case NPVariantType_Null:
+ destination->ChangeType(VT_NULL, NULL);
+ break;
+ case NPVariantType_Bool:
+ *destination = source->value.boolValue;
+ break;
+ case NPVariantType_Int32:
+ *destination = source->value.intValue;
+ break;
+ case NPVariantType_Double:
+ *destination = source->value.doubleValue;
+ break;
+ case NPVariantType_String: {
+ int required_size = 0;
+ required_size = MultiByteToWideChar(
+ CP_UTF8, 0,
+ source->value.stringValue.utf8characters,
+ source->value.stringValue.utf8length, NULL, 0);
+
+ scoped_array<wchar_t> wide_value(new wchar_t[required_size + 1]);
+ MultiByteToWideChar(
+ CP_UTF8, 0,
+ source->value.stringValue.utf8characters,
+ source->value.stringValue.utf8length, wide_value.get(),
+ required_size + 1);
+ wide_value[required_size] = 0;
+
+ *destination = wide_value.get();
+ break;
+ }
+ case NPVariantType_Object:
+ *destination = browser_proxy->GetDispatchObject(
+ source->value.objectValue);
+ break;
+ default:
+ ATLASSERT(false);
+ }
+}
diff --git a/o3d/plugin/npapi_host_control/win/variant_utils.h b/o3d/plugin/npapi_host_control/win/variant_utils.h
new file mode 100644
index 0000000..88bf18a
--- /dev/null
+++ b/o3d/plugin/npapi_host_control/win/variant_utils.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// File declaring helper functions for conversion between ActiveX and
+// NPAPI variant types.
+
+#ifndef O3D_PLUGIN_NPAPI_HOST_CONTROL_WIN_VARIANT_UTILS_H_
+#define O3D_PLUGIN_NPAPI_HOST_CONTROL_WIN_VARIANT_UTILS_H_
+
+#include "plugin/npapi_host_control/win/np_browser_proxy.h"
+#include "plugin/npapi_host_control/win/np_object_proxy.h"
+
+// Converts an ActiveX variant to an NPAPI variant.
+// Parameters:
+// browser_proxy: The emulated NPAPI browser environment, required for
+// managing NPAPI string resource construction, etc.
+// source: The source COM VARIANT.
+// destination: The NPAPI variant to receive the value stored in the source.
+// On failure, the destination will be empty.
+void VariantToNPVariant(NPBrowserProxy* browser_proxy,
+ const VARIANT* source,
+ NPVariant* destination);
+
+
+// Converts a NPAPI variant to an ActiveX variant.
+// Parameters:
+// browser_proxy: The emulated NPAPI browser environment, required for
+// managing NPAPI string resource construction, etc.
+// source: The source NPAPI variant.
+// destination: The COM VARIANT to receive the value stored in the source.
+// On failure, the destination will be empty.
+void NPVariantToVariant(NPBrowserProxy* browser_proxy,
+ const NPVariant* source,
+ CComVariant* destination);
+
+#endif // O3D_PLUGIN_NPAPI_HOST_CONTROL_WIN_VARIANT_UTILS_H_
diff --git a/o3d/plugin/o3d_binding.py b/o3d/plugin/o3d_binding.py
new file mode 100644
index 0000000..7d7490c
--- /dev/null
+++ b/o3d/plugin/o3d_binding.py
@@ -0,0 +1,522 @@
+#!/usr/bin/python2.4
+# Copyright 2009, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+"""o3d binding model module.
+
+This module implements the glue functions for the o3d binding model, binding
+O3D objects.
+
+In C++, objects using this binding model are passed and returned by pointer.
+For example
+void SetValue(Class *value);
+Class *GetValue();
+
+For JS bindings, the browser object holds an id, representing the C++ object
+through that can be accessed through the Client object.
+"""
+
+
+import string
+
+import cpp_utils
+import java_utils
+
+
+class CallingConstructor(Exception):
+ """Raised when trying to call a constructor on an O3D object."""
+ pass
+
+
+def JavaMemberString(scope, type_defn):
+ """Gets the representation of a member name in Java.
+
+ Args:
+ scope: a Definition for the scope in which the expression will be written.
+ type_defn: a Definition for the type.
+
+ Returns:
+ a string representing the type
+ """
+ return java_utils.GetScopedName(scope, type_defn)
+
+
+def CppTypedefString(scope, type_defn):
+ """Gets the representation of a type when used in a C++ typedef.
+
+ Args:
+ scope: a Definition for the scope in which the expression will be written.
+ type_defn: a Definition for the type.
+
+ Returns:
+ a (string, boolean) pair, the first element being the representation of
+ the type, the second element indicating whether or not the definition of
+ the type is needed for the expression to be valid.
+ """
+ return cpp_utils.GetScopedName(scope, type_defn), False
+
+
+def CppMemberString(scope, type_defn):
+ """Gets the representation of a type when used as a C++ class member.
+
+ Args:
+ scope: a Definition for the scope in which the expression will be written.
+ type_defn: a Definition for the type.
+
+ Returns:
+ a (string, boolean) pair, the first element being the representation of
+ the type, the second element indicating whether or not the definition of
+ the type is needed for the expression to be valid.
+ """
+ return '%s*' % cpp_utils.GetScopedName(scope, type_defn), False
+
+
+def CppReturnValueString(scope, type_defn):
+ """Gets the representation of a type when used as a C++ function return value.
+
+ Args:
+ scope: a Definition for the scope in which the expression will be written.
+ type_defn: a Definition for the type.
+
+ Returns:
+ a (string, boolean) pair, the first element being the representation of
+ the type, the second element indicating whether or not the definition of
+ the type is needed for the expression to be valid.
+ """
+ return '%s*' % cpp_utils.GetScopedName(scope, type_defn), False
+
+
+def CppParameterString(scope, type_defn):
+ """Gets the representation of a type when used for a function parameter.
+
+ Args:
+ scope: a Definition for the scope in which the expression will be written.
+ type_defn: a Definition for the type.
+
+ Returns:
+ a (string, boolean) pair, the first element being the representation of
+ the type, the second element indicating whether or not the definition of
+ the type is needed for the expression to be valid.
+ """
+ return '%s*' % cpp_utils.GetScopedName(scope, type_defn), False
+
+
+def CppMutableParameterString(scope, type_defn):
+ """Gets the representation of a type for a mutable function parameter.
+
+ Args:
+ scope: a Definition for the scope in which the expression will be written.
+ type_defn: a Definition for the type.
+
+ Returns:
+ a (string, boolean) pair, the first element being the string representing
+ the type, the second element indicating whether or not the definition of
+ the type is needed for the expression to be valid.
+ """
+ return '%s*' % cpp_utils.GetScopedName(scope, type_defn), False
+
+
+def CppMutableToNonMutable(scope, type_defn, expr):
+ """Gets the string converting a mutable expression to a non-mutable one.
+
+ Args:
+ scope: a Definition for the scope in which the expression will be written.
+ type_defn: a Definition for the type.
+ expr: a string for the mutable expression.
+
+ Returns:
+ a string, which is the non-mutable expression.
+ """
+ (scope, type_defn) = (scope, type_defn) # silence gpylint.
+ return expr
+
+
+def CppBaseClassString(scope, type_defn):
+ """Gets the representation of a type for a base class.
+
+ Args:
+ scope: a Definition for the scope in which the expression will be written.
+ type_defn: a Definition for the type.
+
+ Returns:
+ a (string, boolean) pair, the first element being the string representing
+ the type, the second element indicating whether or not the definition of
+ the type is needed for the expression to be valid.
+ """
+ return cpp_utils.GetScopedName(scope, type_defn)
+
+
+def CppCallMethod(scope, type_defn, object_expr, mutable, method, param_exprs):
+ """Gets the representation of a member function call.
+
+ Args:
+ scope: a Definition for the scope in which the expression will be written.
+ type_defn: a Definition, representing the type of the object being called.
+ object_expr: a string, which is the expression for the object being called.
+ mutable: a boolean, whether or not the 'object_expr' expression is mutable
+ or not
+ method: a Function, representing the function to call.
+ param_exprs: a list of strings, each being the expression for the value of
+ each parameter.
+
+ Returns:
+ a string, which is the expression for the function call.
+ """
+ (scope, type_defn, mutable) = (scope, type_defn, mutable) # silence gpylint.
+ return '%s->%s(%s)' % (object_expr, method.name, ', '.join(param_exprs))
+
+
+def CppCallStaticMethod(scope, type_defn, method, param_exprs):
+ """Gets the representation of a static function call.
+
+ Args:
+ scope: a Definition for the scope in which the expression will be written.
+ type_defn: a Definition, representing the type of the object being called.
+ method: a Function, representing the function to call.
+ param_exprs: a list of strings, each being the expression for the value of
+ each parameter.
+
+ Returns:
+ a string, which is the expression for the function call.
+ """
+ return '%s::%s(%s)' % (cpp_utils.GetScopedName(scope, type_defn),
+ method.name, ', '.join(param_exprs))
+
+
+def CppCallConstructor(scope, type_defn, method, param_exprs):
+ """Gets the representation of a constructor call.
+
+ Args:
+ scope: a Definition for the scope in which the expression will be written.
+ type_defn: a Definition, representing the type of the object being called.
+ method: a Function, representing the constructor to call.
+ param_exprs: a list of strings, each being the expression for the value of
+ each parameter.
+
+ Returns:
+ a string, which is the expression for the constructor call.
+
+ Raises:
+ CallingConstructor: always. O3D objects can't be constructed directly.
+ """
+ raise CallingConstructor
+
+
+def CppSetField(scope, type_defn, object_expr, field, param_expr):
+ """Gets the representation of an expression setting a field in an object.
+
+ Args:
+ scope: a Definition for the scope in which the expression will be written.
+ type_defn: a Definition, representing the type of the object containing the
+ field being set.
+ object_expr: a string, which is the expression for the object containing
+ the field being set.
+ field: a string, the name of the field to be set.
+ param_expr: a strings, being the expression for the value to be set.
+
+ Returns:
+ a string, which is the expression for setting the field.
+ """
+ (scope, type_defn) = (scope, type_defn) # silence gpylint.
+ return '%s->%s(%s)' % (object_expr, cpp_utils.GetSetterName(field),
+ param_expr)
+
+
+def CppGetField(scope, type_defn, object_expr, field):
+ """Gets the representation of an expression getting a field in an object.
+
+ Args:
+ scope: a Definition for the scope in which the expression will be written.
+ type_defn: a Definition, representing the type of the object containing the
+ field being retrieved.
+ object_expr: a string, which is the expression for the object containing
+ the field being retrieved.
+ field: a string, the name of the field to be retrieved.
+
+ Returns:
+ a string, which is the expression for getting the field.
+ """
+ (scope, type_defn) = (scope, type_defn) # silence gpylint.
+ return '%s->%s()' % (object_expr, cpp_utils.GetGetterName(field))
+
+
+def CppSetStatic(scope, type_defn, field, param_expr):
+ """Gets the representation of an expression setting a static field.
+
+ Args:
+ scope: a Definition for the scope in which the expression will be written.
+ type_defn: a Definition, representing the type of the object containing the
+ field being set.
+ field: a string, the name of the field to be set.
+ param_expr: a strings, being the expression for the value to be set.
+
+ Returns:
+ a string, which is the expression for setting the field.
+ """
+ return '%s::%s(%s)' % (cpp_utils.GetScopedName(scope, type_defn),
+ cpp_utils.GetSetterName(field), param_expr)
+
+
+def CppGetStatic(scope, type_defn, field):
+ """Gets the representation of an expression getting a static field.
+
+ Args:
+ scope: a Definition for the scope in which the expression will be written.
+ type_defn: a Definition, representing the type of the object containing the
+ field being retrieved.
+ field: a string, the name of the field to be retrieved.
+
+ Returns:
+ a string, which is the expression for getting the field.
+ """
+ return '%s::%s()' % (cpp_utils.GetScopedName(scope, type_defn),
+ cpp_utils.GetGetterName(field))
+
+
+_binding_glue_header_template = string.Template('')
+
+
+def NpapiBindingGlueHeader(scope, type_defn):
+ """Gets the NPAPI glue header for a given type.
+
+ Args:
+ scope: a Definition for the scope in which the glue will be written.
+ type_defn: a Definition, representing the type.
+
+ Returns:
+ a string, the glue header.
+ """
+ class_name = cpp_utils.GetScopedName(scope, type_defn)
+ return _binding_glue_header_template.substitute(Class=class_name)
+
+
+_binding_glue_cpp_template = string.Template("""
+void InitializeGlue(NPP npp) {
+ InitializeIds(npp);
+ glue::_o3d::RegisterType(npp, ${Class}::GetApparentClass(), &npclass);
+}
+
+glue::_o3d::NPAPIObject *GetNPObject(NPP npp, ${Class}* object) {
+ return glue::_o3d::GetNPObject(npp, object);
+}
+
+static NPObject *Allocate(NPP npp, NPClass *theClass) {
+ return glue::_o3d::Allocate(npp, theClass);
+}
+
+static void Deallocate(NPObject *header) {
+ return glue::_o3d::Deallocate(header);
+}
+""")
+
+
+def NpapiBindingGlueCpp(scope, type_defn):
+ """Gets the NPAPI glue implementation for a given type.
+
+ Args:
+ scope: a Definition for the scope in which the glue will be written.
+ type_defn: a Definition, representing the type.
+
+ Returns:
+ a string, the glue implementation.
+ """
+ class_name = cpp_utils.GetScopedName(scope, type_defn)
+ return _binding_glue_cpp_template.substitute(Class=class_name)
+
+
+dispatch_function_header_template = string.Template("""
+glue::_o3d::NPAPIObject *${variable_npobject} =
+ static_cast<glue::_o3d::NPAPIObject *>(header);
+NPP ${npp} = ${variable_npobject}->npp();
+${Class} *${variable} = glue::_o3d::GetClient(
+ ${npp})->GetById<${Class}>(${variable_npobject}->id());
+${result} = (${variable} != NULL);
+if (!${result}) {
+ O3D_ERROR(glue::_o3d::GetServiceLocator(${npp})) <<
+ "Invalid object; perhaps it's been destroyed already?";
+}
+""")
+
+
+def NpapiDispatchFunctionHeader(scope, type_defn, variable, npp, success):
+ """Gets a header for NPAPI glue dispatch functions.
+
+ This function creates a string containing a C++ code snippet that should be
+ included at the beginning of NPAPI glue dispatch functions like Invoke or
+ GetProperty. This code snippet will declare and initialize certain variables
+ that will be used in the dispatch functions, like the NPObject representing
+ the object, or a pointer to the NPP instance.
+
+ Args:
+ scope: a Definition for the scope in which the glue will be written.
+ type_defn: a Definition, representing the type.
+ variable: a string, representing a name of a variable that can be used to
+ store a reference to the object.
+ npp: a string, representing the name of the variable that holds the pointer
+ to the NPP instance. Will be declared by the code snippet.
+ success: the name of a bool variable containing the current success status.
+ (is not declared by the code snippet).
+
+ Returns:
+ a (string, string) pair, the first string being the code snippet, and the
+ second string being an expression to access the object.
+ """
+ class_name = cpp_utils.GetScopedName(scope, type_defn)
+ variable_npobject = '%s_npobject' % variable
+ text = dispatch_function_header_template.substitute(
+ variable_npobject=variable_npobject, npp=npp, variable=variable,
+ Class=class_name, result=success)
+ return text, variable
+
+
+from_npvariant_template = string.Template("""
+${Class} *${variable} = NULL;
+if (NPVARIANT_IS_OBJECT(${input})) {
+ NPObject *npobject = NPVARIANT_TO_OBJECT(${input});
+ if (glue::_o3d::CheckObject(npp, npobject,
+ ${Class}::GetApparentClass())) {
+ glue::_o3d::NPAPIObject *client_object =
+ static_cast<glue::_o3d::NPAPIObject *>(npobject);
+ ${variable} =
+ glue::_o3d::GetClient(${npp})->GetById<${Class}>(
+ client_object->id());
+ if (${variable} == NULL) {
+ ${result} = false;
+ *error_handle = "Error in " ${context}
+ ": input wasn't a valid object from this plugin instance.";
+ } else {
+ ${result} = true;
+ }
+ } else {
+ *error_handle = "Error in " ${context}
+ ": invalid type.";
+ ${result} = false;
+ }
+} else {
+ *error_handle = "Error in " ${context}
+ ": was expecting an object.";
+ ${result} = false;
+}
+""")
+
+
+def NpapiFromNPVariant(scope, type_defn, input_expr, variable, success,
+ exception_context, npp):
+ """Gets the string to get a value from a NPVariant.
+
+ This function creates a string containing a C++ code snippet that is used to
+ retrieve a value from a NPVariant. If an error occurs, like if the NPVariant
+ is not of the correct type, the snippet will set the success status variable
+ to false and set *error_handle with an appropriate error message.
+
+ Args:
+ scope: a Definition for the scope in which the glue will be written.
+ type_defn: a Definition, representing the type of the value.
+ input_expr: an expression representing the NPVariant to get the value from.
+ variable: a string, representing a name of a variable that can be used to
+ store a reference to the value.
+ success: the name of a bool variable containing the current success status.
+ exception_context: the name of a string containing context information, for
+ use in exception reporting.
+ npp: a string, representing the name of the variable that holds the pointer
+ to the NPP instance.
+
+ Returns:
+ a (string, string) pair, the first string being the code snippet and the
+ second one being the expression to access that value.
+ """
+ class_name = cpp_utils.GetScopedName(scope, type_defn)
+ text = from_npvariant_template.substitute(Class=class_name,
+ variable=variable,
+ input=input_expr,
+ npp=npp,
+ result=success,
+ context=exception_context)
+ return (text, variable)
+
+
+expr_to_npobject_template = string.Template("""
+glue::_o3d::NPAPIObject *${variable} =
+ glue::_o3d::GetNPObject(${npp}, ${expr});
+if (!${variable}) {
+ *error_handle = "Error : type cannot be null.";
+ ${result} = false;
+}
+""")
+
+npobject_to_npvariant_template = string.Template("""
+OBJECT_TO_NPVARIANT(${variable}, *${output});
+""")
+
+
+def NpapiExprToNPVariant(scope, type_defn, variable, expression, output,
+ success, npp):
+ """Gets the string to store a value into a NPVariant.
+
+ This function creates a string containing a C++ code snippet that is used to
+ store a value into a NPVariant. That operation takes two phases, one that
+ allocates necessary NPAPI resources, and that can fail, and one that actually
+ sets the NPVariant (that can't fail). If an error occurs, the snippet will
+ set the success status variable to false.
+
+ Args:
+ scope: a Definition for the scope in which the glue will be written.
+ type_defn: a Definition, representing the type of the value.
+ variable: a string, representing a name of a variable that can be used to
+ store a reference to the value.
+ expression: a string representing the expression that yields the value to
+ be stored.
+ output: an expression representing a pointer to the NPVariant to store the
+ value into.
+ success: the name of a bool variable containing the current success status.
+ npp: a string, representing the name of the variable that holds the pointer
+ to the NPP instance.
+
+ Returns:
+ a (string, string) pair, the first string being the code snippet for the
+ first phase, and the second one being the code snippet for the second phase.
+ """
+ (scope, type_defn) = (scope, type_defn) # silence gpylint.
+ phase_1_text = expr_to_npobject_template.substitute(variable=variable,
+ npp=npp,
+ expr=expression,
+ result=success)
+ phase_2_text = npobject_to_npvariant_template.substitute(
+ variable=variable,
+ output=output,
+ result=success)
+ return phase_1_text, phase_2_text
+
+
+def main():
+ pass
+
+if __name__ == '__main__':
+ main()
diff --git a/o3d/plugin/o3d_iface_generator.py b/o3d/plugin/o3d_iface_generator.py
new file mode 100644
index 0000000..82092bf
--- /dev/null
+++ b/o3d/plugin/o3d_iface_generator.py
@@ -0,0 +1,618 @@
+#!/usr/bin/python2.4
+# Copyright 2009, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+"""O3D interface class generator.
+
+This module generates the O3D interface classes.
+"""
+
+
+import os
+import syntax_tree
+import cpp_utils
+import naming
+
+class CircularDefinition(Exception):
+ """Raised when a circular type definition is found."""
+
+ def __init__(self, type_defn):
+ Exception.__init__(self)
+ self.type = type_defn
+
+
+class BadForwardDeclaration(Exception):
+ """Raised when an impossible forward declaration is required."""
+
+
+def ForwardDecl(section, type_defn):
+ """Emits the forward declaration of a type, if possible.
+
+ Inner types (declared inside a class) cannot be forward-declared.
+ Only classes can be forward-declared.
+
+ Args:
+ section: the section to emit to.
+ type_defn: the Definition for the type to forward-declare.
+
+ Raises:
+ BadForwardDeclaration: an inner type or a non-class was passed as an
+ argument.
+ """
+ # inner types cannot be forward-declared
+ if type_defn.parent.defn_type != 'Namespace':
+ raise BadForwardDeclaration
+ stack = type_defn.GetParentScopeStack()
+ if type_defn.defn_type == 'Class':
+ for scope in stack:
+ if scope.name:
+ section.PushNamespace(scope.name)
+ section.EmitCode('class %s;' % type_defn.name)
+ for scope in stack[::-1]:
+ if scope.name:
+ section.PopNamespace()
+ else:
+ raise BadForwardDeclaration
+
+
+class O3DInterfaceGenerator(object):
+ """Header generator class.
+
+ This class takes care of the details of generating a C++ header file
+ containing all the definitions from a syntax tree.
+
+ It contains a list of functions named after each of the Definition classes in
+ syntax_tree, with a common signature. The appropriate function will be called
+ for each definition, to generate the code for that definition.
+ """
+
+ class GenerationContext(object):
+ def __init__(self, header_scope, cpp_scope, header_section, cpp_section):
+ self.header_scope = header_scope
+ self.header_section = header_section
+ self.cpp_scope = cpp_scope
+ self.cpp_section = cpp_section
+ self.needed_decl = set()
+ self.needed_defn = set()
+ self.emitted_defn = set()
+
+ def Fork(self, header_scope, cpp_scope, header_section, cpp_section):
+ new_context = type(self)(header_scope, cpp_scope, header_section,
+ cpp_section)
+ new_context.needed_decl = self.needed_decl
+ new_context.needed_defn = self.needed_defn
+ new_context.emitted_defn = self.emitted_defn
+ return new_context
+
+ def CheckType(self, need_defn, type_defn):
+ """Checks for the definition or declaration of a type.
+
+ This function helps keeping track of which types are needed to be defined
+ or declared in the C++ file before other definitions can happen. If the
+ definition is needed (and is not in this C++ header file), the proper
+ include will be generated. If the type only needs to be forward-declared,
+ the forward declaration will be output (if the type is not otherwise
+ defined).
+
+ Args:
+ need_defn: a boolean, True if the C++ definition of the type is needed,
+ False if only the declaration is needed.
+ type_defn: the Definition of the type to check.
+ """
+ while type_defn.defn_type == 'Array':
+ # arrays are implicitly defined with their data type
+ type_defn = type_defn.data_type
+ if need_defn:
+ if type_defn not in self.emitted_defn:
+ self.needed_defn.add(type_defn)
+ else:
+ if type_defn in self.emitted_defn:
+ return
+ if type_defn.parent and type_defn.parent.defn_type != 'Namespace':
+ # inner type: need the definition of the parent.
+ self.CheckType(True, type_defn.parent)
+ else:
+ # only forward-declare classes.
+ # typedefs could be forward-declared by emitting the definition again,
+ # but this necessitates the source type to be forward-declared before.
+ # TODO: see if it is possible to find a proper ordering that let
+ # us forward-declare typedefs instead of needing to include the
+ # definition.
+ if type_defn.defn_type == 'Class':
+ self.needed_decl.add(type_defn)
+ else:
+ self.needed_defn.add(type_defn)
+
+ def __init__(self, output_dir, namespace):
+ self._output_dir = output_dir
+ self._void_type = namespace.LookupTypeRecursive('void')
+
+ def GetHeaderFile(self, idl_file):
+ return idl_file.source.split('.')[0] + '.h'
+
+ def GetCppFile(self, idl_file):
+ return idl_file.source.split('.')[0] + '.cc'
+
+ def GetInterfaceInclude(self, type_defn):
+ if self.NeedsGlue(type_defn):
+ return self.GetHeaderFile(type_defn.source.file)
+ else:
+ return type_defn.GetDefinitionInclude()
+
+ def GetImplementationInclude(self, type_defn):
+ return type_defn.GetDefinitionInclude()
+
+ def IsVoid(self, type_defn):
+ return type_defn.GetFinalType() == self._void_type
+
+ def NeedsGlue(self, obj):
+ return obj.LookupBindingModel() == 'o3d' or 'glue_iface' in obj.attributes
+
+ def GetSectionFromAttributes(self, parent_section, defn):
+ """Gets the code section appropriate for a given definition.
+
+ Classes have 3 definition sections: private, protected and public. This
+ function will pick one of the sections, based on the attributes of the
+ definition, if its parent is a class. For other scopes (namespaces) it will
+ return the parent scope main section.
+
+ Args:
+ parent_section: the main section for the parent scope.
+ defn: the definition.
+
+ Returns:
+ the appropriate section.
+ """
+ if defn.parent and defn.parent.defn_type == 'Class':
+ if 'private' in defn.attributes:
+ return parent_section.GetSection('private:') or parent_section
+ elif 'protected' in defn.attributes:
+ return parent_section.GetSection('protected:') or parent_section
+ else:
+ return parent_section.GetSection('public:') or parent_section
+ else:
+ return parent_section
+
+ def Verbatim(self, context, obj):
+ """Generates the code for a Verbatim definition.
+
+ Verbatim definitions being written for a particular type of output file,
+ this function will check the 'verbatim' attribute, and only emit the
+ verbatim code if it is 'cpp_header'.
+
+ Args:
+ parent_section: the main section of the parent scope.
+ obj: the Verbatim definition.
+ """
+ try:
+ verbatim_attr = obj.attributes['verbatim']
+ except KeyError:
+ source = obj.source
+ print ('%s:%d ignoring verbatim with no verbatim attribute' %
+ (source.file.source, source.line))
+ return
+ if verbatim_attr == 'o3d_iface_header':
+ section = self.GetSectionFromAttributes(context.header_section, obj)
+ section.EmitCode(obj.text)
+ elif verbatim_attr == 'o3d_iface_cpp':
+ context.cpp_section.EmitCode(obj.text)
+
+ def Typedef(self, context, obj):
+ """Generates the code for a Typedef definition.
+
+ Args:
+ parent_section: the main section of the parent scope.
+ obj: the Typedef definition.
+
+ Returns:
+ a list of (boolean, Definition) pairs, of all the types that need
+ to be declared (boolean is False) or defined (boolean is True) before
+ this definition.
+ """
+ section = self.GetSectionFromAttributes(context.header_section, obj)
+ bm = obj.type.binding_model
+ type_string, unused_need_defn = bm.CppTypedefString(context.header_scope,
+ obj.type)
+ context.CheckType(True, obj.type)
+ section.EmitCode('typedef %s %s;' % (type_string, obj.name))
+
+ def Variable(self, context, obj):
+ """Generates the code for a Variable definition.
+
+ This function will generate the member/global variable declaration, as well
+ as the setter/getter functions if specified in the attributes.
+
+ Args:
+ parent_section: the main section of the parent scope.
+ obj: the Variable definition.
+ """
+ bm = obj.type.binding_model
+ type_string, need_defn = bm.CppMemberString(context.header_scope, obj.type)
+ context.CheckType(need_defn, obj.type)
+ need_glue = self.NeedsGlue(obj) or (obj.parent.is_type and
+ self.NeedsGlue(obj.parent));
+
+ getter_attributes = {}
+ if 'static' in obj.attributes:
+ getter_attributes['static'] = obj.attributes['static']
+ static = 'static '
+ else:
+ static = ''
+ for attr in ['public', 'protected', 'private']:
+ if attr in obj.attributes:
+ getter_attributes[attr] = obj.attributes[attr]
+
+ if not need_glue:
+ if obj.parent.defn_type == 'Class':
+ if 'field_access' in obj.attributes:
+ member_section = context.header_section.GetSection(
+ obj.attributes['field_access'] + ':')
+ else:
+ member_section = context.header_section.GetSection('private:')
+ else:
+ member_section = context.header_section
+ field_name = naming.Normalize(obj.name, naming.LowerTrailing)
+ member_section.EmitCode('%s%s %s;' % (static, type_string, field_name))
+
+ if 'getter' in obj.attributes:
+ func = obj.MakeGetter(getter_attributes, cpp_utils.GetGetterName(obj))
+ if need_glue:
+ self.FunctionGlue(context, func)
+ impl = None
+ else:
+ impl = ' { return %s; }' % field_name
+ self.FunctionDecl(context, func, impl)
+ if 'setter' in obj.attributes:
+ func = obj.MakeSetter(getter_attributes, cpp_utils.GetSetterName(obj))
+ if need_glue:
+ self.FunctionGlue(context, func)
+ impl = None
+ else:
+ impl = ' { %s = %s; }' % (field_name, obj.name)
+ self.FunctionDecl(context, func, impl)
+
+ def GetParamsDecls(self, scope, obj, context=None):
+ param_strings = []
+ for p in obj.params:
+ bm = p.type.binding_model
+ if p.mutable:
+ text, need_defn = bm.CppMutableParameterString(scope, p.type)
+ else:
+ text, need_defn = bm.CppParameterString(scope, p.type)
+ if context:
+ context.CheckType(need_defn, p.type)
+ param_strings += ['%s %s' % (text, p.name)]
+ return ', '.join(param_strings)
+
+ def FunctionDecl(self, context, obj, impl_string=None):
+ section = self.GetSectionFromAttributes(context.header_section, obj)
+ if not impl_string:
+ impl_string = ';'
+ params_string = self.GetParamsDecls(context.header_scope, obj, context)
+ prefix_strings = []
+ suffix_strings = []
+ for attrib in ['static', 'virtual', 'inline']:
+ if attrib in obj.attributes:
+ prefix_strings.append(attrib)
+ if prefix_strings:
+ prefix_strings.append('')
+ if 'const' in obj.attributes:
+ suffix_strings.append('const')
+ if 'pure' in obj.attributes:
+ suffix_strings.append('= 0')
+ if suffix_strings:
+ suffix_strings.insert(0, '')
+ prefix = ' '.join(prefix_strings)
+ suffix = ' '.join(suffix_strings)
+ if obj.type:
+ bm = obj.type.binding_model
+ return_type, need_defn = bm.CppReturnValueString(context.header_scope,
+ obj.type)
+ context.CheckType(need_defn, obj.type)
+ section.EmitCode('%s%s %s(%s)%s%s' % (prefix, return_type, obj.name,
+ params_string, suffix, impl_string))
+ else:
+ section.EmitCode('%s%s(%s)%s%s' % (prefix, obj.name, params_string,
+ suffix, impl_string))
+
+ def FunctionGlue(self, context, obj):
+ if not obj.type:
+ # TODO autogen a factory
+ return
+ if 'pure' in obj.attributes:
+ return
+
+ if obj.parent.is_type:
+ func_name = '%s::%s' % (obj.parent.name, obj.name)
+ if 'static' in obj.attributes:
+ call_prefix = 'impl::' + func_name
+ else:
+ # this_call
+ if self.NeedsGlue(obj.parent):
+ call_prefix = 'GetImpl()->'
+ else:
+ call_prefix = ''
+ else:
+ call_prefix = ''
+ func_name = obj.name
+
+ params_string = self.GetParamsDecls(context.cpp_scope, obj)
+ param_exprs = []
+ for p in obj.params:
+ if self.NeedsGlue(p.type):
+ param_exprs.append('%s->GetImpl()' % p.name)
+ else:
+ param_exprs.append(p.name)
+
+ if not self.IsVoid(obj.type):
+ return_prefix = 'return '
+ if self.NeedsGlue(obj.type):
+ return_suffix = '->GetIface()'
+ else:
+ return_suffix = ''
+ else:
+ return_prefix = ''
+ return_suffix = ''
+
+ bm = obj.type.binding_model
+ return_type, unused = bm.CppReturnValueString(context.header_scope,
+ obj.type)
+ if 'const' in obj.attributes:
+ func_suffix = ' const'
+ else:
+ func_suffix = ''
+
+ section = context.cpp_section
+ section.EmitCode('%s %s(%s)%s {' % (return_type, func_name, params_string,
+ func_suffix))
+ section.EmitCode('%s%s%s(%s)%s;' % (return_prefix, call_prefix, obj.name,
+ ', '.join(param_exprs), return_suffix))
+ section.EmitCode('}')
+
+ def Function(self, context, obj):
+ """Generates the code for a Function definition.
+
+ Args:
+ parent_section: the main section of the parent scope.
+ obj: the Function definition.
+ """
+ self.FunctionDecl(context, obj)
+ if self.NeedsGlue(obj) or (obj.parent.is_type and
+ self.NeedsGlue(obj.parent)):
+ self.FunctionGlue(context, obj)
+
+ def Class(self, context, obj):
+ """Generates the code for a Class definition.
+
+ This function will recursively generate the code for all the definitions
+ inside the class. These definitions will be output into one of 3 sections
+ (private, protected, public), depending on their attributes. These
+ individual sections will only be output if they are not empty.
+
+ Args:
+ parent_section: the main section of the parent scope.
+ obj: the Class definition.
+ """
+ h_section = self.GetSectionFromAttributes(context.header_section,
+ obj).CreateSection(obj.name)
+ c_section = context.cpp_section
+
+ need_glue = self.NeedsGlue(obj)
+ if need_glue:
+ h_section.PushNamespace('impl')
+ h_section.EmitCode('class %s;' % obj.name)
+ h_section.PopNamespace()
+ h_section.EmitCode('')
+ if obj.base_type:
+ bm = obj.base_type.binding_model
+ h_section.EmitCode('class %s : public %s {' %
+ (obj.name, bm.CppBaseClassString(context.header_scope,
+ obj.base_type)))
+ context.CheckType(True, obj.base_type)
+ else:
+ h_section.EmitCode('class %s {' % obj.name)
+ public_section = h_section.CreateSection('public:')
+ protected_section = h_section.CreateSection('protected:')
+ private_section = h_section.CreateSection('private:')
+
+ new_context = context.Fork(obj, context.cpp_scope, h_section, c_section)
+ self.DefinitionList(new_context, obj.defn_list)
+
+ if need_glue:
+ public_section.EmitCode('impl::%s *GetImpl();' % obj.name)
+ c_section.EmitCode('impl::%s *%s::GetImpl() {' % (obj.name, obj.name))
+ c_section.EmitCode('return static_cast<impl::%s *>(impl_);' % obj.name)
+ c_section.EmitCode('}')
+
+ if not public_section.IsEmpty():
+ public_section.AddPrefix('public:')
+ if not protected_section.IsEmpty():
+ protected_section.AddPrefix('protected:')
+ if not private_section.IsEmpty():
+ private_section.AddPrefix('private:')
+ h_section.EmitCode('};')
+
+ def Namespace(self, context, obj):
+ """Generates the code for a Namespace definition.
+
+ This function will recursively generate the code for all the definitions
+ inside the namespace.
+
+ Args:
+ parent_section: the main section of the parent scope.
+ obj: the Namespace definition.
+ """
+ context.header_section.PushNamespace(obj.name)
+ context.cpp_section.PushNamespace(obj.name)
+ new_context = context.Fork(obj, obj, context.header_section,
+ context.cpp_section)
+ self.DefinitionList(new_context, obj.defn_list)
+ context.header_section.PopNamespace()
+ context.cpp_section.PopNamespace()
+
+ def Typename(self, context, obj):
+ """Generates the code for a Typename definition.
+
+ Since typenames (undefined types) cannot be expressed in C++, this function
+ will not output code. The definition may be output with a verbatim section.
+
+ Args:
+ parent_section: the main section of the parent scope.
+ scope: the parent scope.
+ obj: the Typename definition.
+ """
+
+ def Enum(self, context, obj):
+ """Generates the code for an Enum definition.
+
+ Args:
+ parent_section: the main section of the parent scope.
+ scope: the parent scope.
+ obj: the Enum definition.
+ """
+ section = self.GetSectionFromAttributes(context.header_section, obj)
+ section.EmitCode('enum %s {' % obj.name)
+ for value in obj.values:
+ if value.value is None:
+ section.EmitCode('%s,' % value.name)
+ else:
+ section.EmitCode('%s = %s,' % (value.name, value.value))
+ section.EmitCode('};')
+
+ def DefinitionList(self, context, defn_list):
+ """Generates the code for all the definitions in a list.
+
+ Args:
+ parent_section: the main section of the parent scope.
+ scope: the parent scope.
+ defn_list: the list of definitions.
+ """
+ for obj in defn_list:
+ context.emitted_defn.add(obj)
+ # array types are implicitly defined
+ for k in obj.array_defns:
+ context.emitted_defn.add(obj.array_defns[k])
+ getattr(self, obj.defn_type)(context, obj)
+
+ def Generate(self, idl_file, namespace, defn_list):
+ """Generates the header file.
+
+ Args:
+ idl_file: the source IDL file containing the definitions, as a
+ idl_parser.File instance.
+ namespace: a Definition for the global namespace.
+ defn_list: the list of top-level definitions.
+
+ Returns:
+ a cpp_utils.CppFileWriter that contains the C++ header file code.
+
+ Raises:
+ CircularDefinition: circular definitions were found in the file.
+ """
+ all_defn = syntax_tree.GetObjectsRecursive(defn_list)
+ need_glue = False
+ for defn in all_defn:
+ if self.NeedsGlue(defn):
+ need_glue = True
+ break
+ if not need_glue:
+ return []
+
+ header_writer = cpp_utils.CppFileWriter(
+ '%s/%s' % (self._output_dir, self.GetHeaderFile(idl_file)), True)
+
+ cpp_writer = cpp_utils.CppFileWriter(
+ '%s/%s' % (self._output_dir, self.GetCppFile(idl_file)), True)
+
+ h_decl_section = header_writer.CreateSection('decls')
+ h_code_section = header_writer.CreateSection('defns')
+ c_code_section = cpp_writer.CreateSection('glue')
+
+ context = self.GenerationContext(namespace, namespace, h_code_section,
+ c_code_section)
+
+ self.DefinitionList(context, defn_list)
+
+ context.needed_decl -= context.needed_defn
+ if context.needed_decl:
+ for type_defn in context.needed_decl:
+ # TODO: sort by namespace so that we don't open and close them
+ # more than necessary.
+ ForwardDecl(h_decl_section, type_defn)
+ h_decl_section.EmitCode('')
+
+ for type_defn in context.needed_defn:
+ if type_defn.source.file == idl_file:
+ raise CircularDefinition(type_defn)
+
+ h_includes = set(self.GetInterfaceInclude(type_defn)
+ for type_defn in context.needed_defn)
+ c_includes = set(self.GetImplementationInclude(type_defn)
+ for type_defn in context.emitted_defn
+ if self.NeedsGlue(type_defn))
+ c_includes.add(self.GetHeaderFile(idl_file))
+
+ for include_file in h_includes:
+ if include_file is not None:
+ header_writer.AddInclude(include_file)
+ for include_file in c_includes:
+ if include_file is not None:
+ cpp_writer.AddInclude(include_file)
+ return [header_writer, cpp_writer]
+
+
+def ProcessFiles(output_dir, pairs, namespace):
+ """Generates the headers for all input files.
+
+ Args:
+ output_dir: the output directory.
+ pairs: a list of (idl_parser.File, syntax_tree.Definition list) describing
+ the list of top-level definitions in each source file.
+ namespace: a syntax_tree.Namespace for the global namespace.
+
+ Returns:
+ a list of cpp_utils.CppFileWriter, one for each output file.
+ """
+ output_dir = output_dir + '/iface'
+ if not os.access(output_dir + '/', os.F_OK):
+ os.makedirs(output_dir)
+
+ generator = O3DInterfaceGenerator(output_dir, namespace)
+ writer_list = []
+ for (f, defn) in pairs:
+ writer_list += generator.Generate(f, namespace, defn)
+ return writer_list
+
+
+def main():
+ pass
+
+if __name__ == '__main__':
+ main()
diff --git a/o3d/plugin/win/config.cc b/o3d/plugin/win/config.cc
new file mode 100644
index 0000000..ef1fb39
--- /dev/null
+++ b/o3d/plugin/win/config.cc
@@ -0,0 +1,233 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// This file contains code to check the hardware and software configuration of
+// the client machine:
+// - User agent (browser)
+// - Windows version
+// - GPU vendor
+
+// TODO: Waiting on posix updates to be able to include this in order
+// to parse the useragent string for browser version.
+// #include <regex.h>
+#include <shlobj.h>
+#include <shlwapi.h>
+#include <tchar.h>
+#include <windows.h>
+#ifdef RENDERER_D3D9
+#include <d3d9.h>
+#endif
+
+#include <string>
+#include <iostream>
+#include <fstream>
+
+#include "base/logging.h"
+#include "plugin/cross/config.h"
+#include "plugin/cross/plugin_metrics.h"
+#include "core/cross/install_check.h"
+#include "third_party/nixysa/files/static_glue/npapi/common.h"
+
+// Check Windows version.
+bool CheckOSVersion(NPP npp) {
+ OSVERSIONINFOEX version = {sizeof(OSVERSIONINFOEX)}; // NOLINT
+ GetVersionEx(reinterpret_cast<OSVERSIONINFO *>(&version));
+ if (version.dwMajorVersion == 5 && version.dwMinorVersion == 1) {
+ // NT 5.1 = Windows XP
+ if (version.wServicePackMajor < 2) {
+ // TODO: internationalize messages.
+ std::string error = std::string("Windows XP Service Pack 2 is required.");
+ if (!AskUser(npp, error)) return false;
+ }
+ } else if (version.dwMajorVersion == 6 && version.dwMinorVersion == 0) {
+ // 6.0 is Vista or Server 2008; it's now worth a try.
+ } else {
+ std::string error = std::string("Unsupported Windows version.");
+ if (!AskUser(npp, error)) return false;
+ }
+ return true;
+}
+
+// Checks user agent string. We only allow Firefox, Chrome, and IE.
+bool CheckUserAgent(NPP npp, const std::string &user_agent) {
+ if (user_agent.find("Firefox") == user_agent.npos &&
+ user_agent.find("Chrome") == user_agent.npos &&
+ user_agent.find("MSIE") == user_agent.npos) {
+ std::string error = std::string("Unsupported user agent: ") + user_agent;
+ return AskUser(npp, error);
+ }
+ return true;
+}
+
+bool OpenDriverBlacklistFile(std::ifstream *input_file) {
+ CHECK(input_file);
+ CHECK(!input_file->is_open());
+
+ // Determine the full path.
+ // It will look something like:
+ // "c:\Documents and Settings\username\Application Data\Google\O3D\
+ // driver_blacklist.txt"
+
+ TCHAR app_data_path[MAX_PATH];
+ HRESULT result = SHGetFolderPath(
+ NULL,
+ CSIDL_APPDATA,
+ NULL,
+ 0,
+ app_data_path);
+
+ if (result != 0) {
+ return false;
+ }
+
+ PathAppend(app_data_path, _T("Google\\O3D\\driver_blacklist.txt"));
+ if (!PathFileExists(app_data_path)) {
+ return false;
+ }
+ input_file->open(app_data_path, std::ifstream::in);
+ return input_file->good();
+}
+
+bool GetUserConfigMetrics() {
+ // Check Windows version.
+ o3d::metric_system_type = o3d::SYSTEM_NAME_WIN;
+
+ OSVERSIONINFOEX version = {sizeof(OSVERSIONINFOEX)}; // NOLINT
+ GetVersionEx(reinterpret_cast<OSVERSIONINFO *>(&version));
+ o3d::metric_windows_major_version = version.dwMajorVersion;
+ o3d::metric_windows_minor_version = version.dwMinorVersion;
+ o3d::metric_windows_sp_major_version = version.wServicePackMajor;
+ o3d::metric_windows_sp_minor_version = version.wServicePackMinor;
+
+ // Check the device capabilities.
+#ifdef RENDERER_D3D9
+ // Check GPU vendor using D3D.
+ IDirect3D9 *d3d = Direct3DCreate9(D3D_SDK_VERSION);
+ if (!d3d) {
+ o3d::metric_direct3d_available.Set(false);
+ DLOG(ERROR) << "Direct3D9 is unavailable";
+ return false;
+ }
+ o3d::metric_direct3d_available.Set(true);
+ D3DADAPTER_IDENTIFIER9 identifier;
+ HRESULT hr = d3d->GetAdapterIdentifier(D3DADAPTER_DEFAULT, 0, &identifier);
+ D3DCAPS9 d3d_caps;
+ HRESULT caps_result = d3d->GetDeviceCaps(D3DADAPTER_DEFAULT,
+ D3DDEVTYPE_HAL,
+ &d3d_caps);
+ // Get GPU device information
+ if (hr != D3D_OK) {
+ DLOG(ERROR) << "Unable to get device ID";
+ return false;
+ }
+ o3d::metric_gpu_vendor_id = identifier.VendorId;
+ o3d::metric_gpu_device_id = identifier.DeviceId;
+ o3d::metric_gpu_driver_major_version = identifier.DriverVersion.LowPart;
+ o3d::metric_gpu_driver_minor_version = identifier.DriverVersion.HighPart;
+
+ // Need to release after we get the vram size
+ d3d->Release();
+
+ // Get shader versions
+ DWORD pixel_shader = d3d_caps.PixelShaderVersion;
+ o3d::metric_pixel_shader_main_version =
+ D3DSHADER_VERSION_MAJOR(pixel_shader);
+ o3d::metric_pixel_shader_sub_version =
+ D3DSHADER_VERSION_MINOR(pixel_shader);
+ DWORD vertex_shader = d3d_caps.VertexShaderVersion;
+ o3d::metric_vertex_shader_main_version =
+ D3DSHADER_VERSION_MAJOR(vertex_shader);
+ o3d::metric_vertex_shader_sub_version =
+ D3DSHADER_VERSION_MINOR(vertex_shader);
+
+ // Detemine if device can handle NPoT textures
+ o3d::metric_POW2_texture_caps.Set(
+ (d3d_caps.TextureCaps & D3DPTEXTURECAPS_POW2) != 0);
+ o3d::metric_NONPOW2CONDITIONAL_texture_caps.Set(
+ (d3d_caps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL) != 0);
+
+ o3d::metric_d3d_devcaps = d3d_caps.DevCaps;
+ o3d::metric_d3d_misccaps = d3d_caps.PrimitiveMiscCaps;
+ o3d::metric_d3d_rastercaps = d3d_caps.RasterCaps;
+ o3d::metric_d3d_zcmpcaps = d3d_caps.ZCmpCaps;
+ o3d::metric_d3d_srcblendcaps = d3d_caps.SrcBlendCaps;
+ o3d::metric_d3d_dstblendcaps = d3d_caps.DestBlendCaps;
+ o3d::metric_d3d_alphacaps = d3d_caps.AlphaCmpCaps;
+ o3d::metric_d3d_texcaps = d3d_caps.TextureCaps;
+ o3d::metric_d3d_texfiltercaps = d3d_caps.TextureFilterCaps;
+ o3d::metric_d3d_cubetexfiltercaps = d3d_caps.CubeTextureFilterCaps;
+ o3d::metric_d3d_texaddrcaps = d3d_caps.TextureAddressCaps;
+ o3d::metric_d3d_linecaps = d3d_caps.LineCaps;
+ o3d::metric_d3d_stencilcaps = d3d_caps.StencilCaps;
+ o3d::metric_d3d_texopcaps = d3d_caps.TextureOpCaps;
+ o3d::metric_d3d_vs20caps = d3d_caps.VS20Caps.Caps;
+ o3d::metric_d3d_vs20_dynflowctrldepth =
+ d3d_caps.VS20Caps.DynamicFlowControlDepth;
+ o3d::metric_d3d_vs20_numtemps = d3d_caps.VS20Caps.NumTemps;
+ o3d::metric_d3d_vs20_staticflowctrldepth =
+ d3d_caps.VS20Caps.StaticFlowControlDepth;
+ o3d::metric_d3d_ps20caps = d3d_caps.PS20Caps.Caps;
+ o3d::metric_d3d_ps20_dynflowctrldepth =
+ d3d_caps.PS20Caps.DynamicFlowControlDepth;
+ o3d::metric_d3d_ps20_numtemps = d3d_caps.PS20Caps.NumTemps;
+ o3d::metric_d3d_ps20_staticflowctrldepth =
+ d3d_caps.PS20Caps.StaticFlowControlDepth;
+ o3d::metric_d3d_ps20_numinstrslots = d3d_caps.PS20Caps.NumInstructionSlots;
+#else
+ o3d::metric_direct3d_available.Set(false);
+#endif
+ return true;
+}
+
+bool GetUserAgentMetrics(NPP npp) {
+ // Check User agent so we can get the browser
+ // TODO: This is the best we could come up with for this in order to
+ // go from browser to string.
+ GLUE_PROFILE_START(npp, "uagent");
+ std::string user_agent = NPN_UserAgent(npp);
+ GLUE_PROFILE_STOP(npp, "uagent");
+ // The Chrome user_agent string also contains Safari. Search for Chrome first.
+ if (std::string::npos != user_agent.find("Chrome")) {
+ o3d::metric_browser_type = o3d::BROWSER_NAME_CHROME;
+ } else if (std::string::npos != user_agent.find("Safari")) {
+ o3d::metric_browser_type = o3d::BROWSER_NAME_SAFARI;
+ } else if (std::string::npos != user_agent.find("Opera")) {
+ o3d::metric_browser_type = o3d::BROWSER_NAME_OPERA;
+ } else if (std::string::npos != user_agent.find("Firefox")) {
+ o3d::metric_browser_type = o3d::BROWSER_NAME_FIREFOX;
+ } else if (std::string::npos != user_agent.find("MSIE")) {
+ o3d::metric_browser_type = o3d::BROWSER_NAME_MSIE;
+ } else {
+ o3d::metric_browser_type = o3d::BROWSER_NAME_UNKNOWN;
+ }
+ return true;
+}
diff --git a/o3d/plugin/win/logger_main.cc b/o3d/plugin/win/logger_main.cc
new file mode 100644
index 0000000..4ff94a9
--- /dev/null
+++ b/o3d/plugin/win/logger_main.cc
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// This file contains the main function for a small program which calls
+// the logging code and initiate an upload of logs.
+
+#include <windows.h>
+#include <stdlib.h>
+#include <shlwapi.h>
+#include "plugin/cross/plugin_logging.h"
+#include "statsreport/metrics.h"
+
+//-----------------------------------------------------------------------------
+// Name: main()
+// Desc: The application's entry point
+//-----------------------------------------------------------------------------
+int main(int argc, wchar_t **argv) {
+ printf("Starting stats logging.\n");
+ HRESULT hr = CoInitialize(NULL);
+ o3d::PluginLogging g_logger;
+ stats_report::g_global_metrics.Initialize();
+ if (!g_logger.ProcessMetrics(false, true)) {
+ printf("Error with stats logging.'n");
+ exit(1);
+ }
+ printf("Stats logging successful.\n");
+ stats_report::g_global_metrics.Uninitialize();
+ exit(0);
+}
diff --git a/o3d/plugin/win/main_win.cc b/o3d/plugin/win/main_win.cc
new file mode 100644
index 0000000..01f8704
--- /dev/null
+++ b/o3d/plugin/win/main_win.cc
@@ -0,0 +1,959 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// This file implements the platform specific parts of the plugin for
+// the Windows platform.
+
+#include "plugin/cross/main.h"
+
+#include <windows.h>
+#include <windowsx.h>
+#include <shellapi.h>
+
+#include "base/at_exit.h"
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "core/cross/display_mode.h"
+#include "core/cross/event.h"
+#include "plugin/cross/plugin_logging.h"
+#include "plugin/cross/out_of_memory.h"
+#include "statsreport/metrics.h"
+#include "breakpad/win/bluescreen_detector.h"
+
+using glue::_o3d::PluginObject;
+using glue::StreamManager;
+using o3d::DisplayWindowWindows;
+using o3d::Event;
+
+o3d::PluginLogging* g_logger = NULL;
+bool g_logging_initialized = false;
+o3d::BluescreenDetector *g_bluescreen_detector = NULL;
+
+namespace {
+// We would normally make this a stack variable in main(), but in a
+// plugin, that's not possible, so we allocate it dynamically and
+// destroy it explicitly.
+scoped_ptr<base::AtExitManager> g_at_exit_manager;
+} // end anonymous namespace
+
+void RenderOnDemandCallbackHandler::Run() {
+ ::InvalidateRect(obj_->GetHWnd(), NULL, TRUE);
+}
+
+static int HandleKeyboardEvent(PluginObject *obj,
+ HWND hWnd,
+ UINT Msg,
+ WPARAM wParam,
+ LPARAM lParam) {
+ DCHECK(obj);
+ DCHECK(obj->client());
+ Event::Type type;
+ // First figure out which kind of event to create, and do any event-specific
+ // processing that can be done prior to creating it.
+ switch (Msg) {
+ case WM_KEYDOWN:
+ case WM_SYSKEYDOWN:
+ type = Event::TYPE_KEYDOWN;
+ if (wParam == VK_ESCAPE) {
+ obj->CancelFullscreenDisplay();
+ }
+ break;
+ case WM_KEYUP:
+ case WM_SYSKEYUP:
+ type = Event::TYPE_KEYUP;
+ break;
+ case WM_CHAR:
+ case WM_SYSCHAR:
+ type = Event::TYPE_KEYPRESS;
+ break;
+ default:
+ LOG(FATAL) << "Unknown keyboard event: " << Msg;
+ }
+ Event event(type);
+ switch (Msg) {
+ case WM_KEYDOWN:
+ case WM_SYSKEYDOWN:
+ case WM_KEYUP:
+ case WM_SYSKEYUP:
+ event.set_key_code(wParam);
+ break;
+ case WM_CHAR:
+ case WM_SYSCHAR:
+ event.set_char_code(wParam);
+ break;
+ default:
+ LOG(FATAL) << "Unknown keyboard event: " << Msg;
+ }
+ // TODO: Try out TranslateAccelerator to see if that causes
+ // accelerators to start working. They would then evade JavaScript handlers,
+ // though, so perhaps we'd have to check to see if we want to handle them
+ // first? That would require going around the event queue, at least
+ // partially. OTOH I see hints in blog posts that only Firefox allows
+ // handlers to suppress syskeys anyway, so maybe it's not that big a
+ // deal...unless apps want to use those keys...and depending on what happens
+ // in other browsers.
+
+ unsigned char keyboard_state[256];
+ if (!::GetKeyboardState(static_cast<PBYTE>(keyboard_state))) {
+ LOG(ERROR) << "GetKeyboardState failed.";
+ return 1;
+ }
+
+ int modifier_state = 0;
+ if (keyboard_state[VK_CONTROL] < 0) {
+ modifier_state |= Event::MODIFIER_CTRL;
+ }
+ if (keyboard_state[VK_SHIFT] < 0) {
+ modifier_state |= Event::MODIFIER_SHIFT;
+ }
+ if (keyboard_state[VK_MENU] < 0) {
+ modifier_state |= Event::MODIFIER_ALT;
+ }
+ event.set_modifier_state(modifier_state);
+ obj->client()->AddEventToQueue(event);
+ return 0;
+}
+
+static void HandleMouseEvent(PluginObject *obj,
+ HWND hWnd,
+ UINT Msg,
+ WPARAM wParam,
+ LPARAM lParam) {
+ DCHECK(obj);
+ DCHECK(obj->client());
+ bool fake_dblclick = false;
+ Event::Type type;
+ int x = GET_X_LPARAM(lParam);
+ int y = GET_Y_LPARAM(lParam);
+ int screen_x, screen_y;
+ bool in_plugin = false;
+ {
+ RECT rect;
+ if (!::GetWindowRect(hWnd, &rect)) {
+ DCHECK(false);
+ return;
+ }
+ if (Msg == WM_MOUSEWHEEL || Msg == WM_MOUSEHWHEEL ||
+ Msg == WM_CONTEXTMENU) {
+ // These messages return screen-relative coordinates, not
+ // window-relative coordinates.
+ screen_x = x;
+ screen_y = y;
+ x -= rect.left;
+ y -= rect.top;
+ } else {
+ screen_x = x + rect.left;
+ screen_y = y + rect.top;
+ }
+ if (x >= 0 && x < rect.right - rect.left &&
+ y >= 0 && y < rect.bottom - rect.top) {
+ // x, y are 0-based from the top-left corner of the plugin. Rect is in
+ // screen coordinates, with bottom > top, right > left.
+ in_plugin = true;
+ }
+ }
+ // First figure out which kind of event to create, and do any event-specific
+ // processing that can be done prior to creating it.
+ switch (Msg) {
+ case WM_MOUSEMOVE:
+ type = Event::TYPE_MOUSEMOVE;
+ break;
+
+ case WM_LBUTTONDOWN:
+ case WM_RBUTTONDOWN:
+ case WM_MBUTTONDOWN:
+#if (_WIN32_WINNT >= 0x0500)
+ case WM_XBUTTONDOWN:
+#endif
+ type = Event::TYPE_MOUSEDOWN;
+ obj->set_got_dblclick(false);
+ SetCapture(hWnd); // Capture mouse to make sure we get the mouseup.
+ break;
+
+ case WM_LBUTTONUP:
+ case WM_RBUTTONUP:
+ case WM_MBUTTONUP:
+#if (_WIN32_WINNT >= 0x0500)
+ case WM_XBUTTONUP:
+#endif
+ type = Event::TYPE_MOUSEUP;
+ if (obj->got_dblclick()) {
+ fake_dblclick = in_plugin;
+ obj->set_got_dblclick(false);
+ }
+ ReleaseCapture();
+ break;
+
+ case WM_LBUTTONDBLCLK:
+ case WM_RBUTTONDBLCLK:
+ case WM_MBUTTONDBLCLK:
+#if (_WIN32_WINNT >= 0x0500)
+ case WM_XBUTTONDBLCLK:
+#endif
+ // On a double-click, windows produces: down, up, move, dblclick, up.
+ // JavaScript should receive: down, up, [optional move, ] click, down,
+ // up, click, dblclick.
+ // The EventManager turns (down, up) into click, since we need that on all
+ // platforms. Windows then has to turn (dblclick, up) into (down, up,
+ // click, dblclick) IFF both events took place in the plugin. If only the
+ // dblclick did, it just turns into a down. If only the up did, it's just
+ // an up, and we shouldn't be passing along the down/dblclick anyway. So
+ // we turn the doubleclick into a mousedown, store the fact that it was a
+ // doubleclick, and wait for the corresponding mouseup to finish off the
+ // sequence. If we get anything that indicates that we missed the mouseup
+ // [because it went to a different window or element], we forget about the
+ // dblclick.
+ DCHECK(in_plugin);
+ obj->set_got_dblclick(true);
+ type = Event::TYPE_MOUSEDOWN;
+ SetCapture(hWnd); // Capture mouse to make sure we get the mouseup.
+ break;
+
+ case WM_MOUSEWHEEL:
+ case WM_MOUSEHWHEEL:
+ type = Event::TYPE_WHEEL;
+ break;
+
+ case WM_CONTEXTMENU:
+ type = Event::TYPE_CONTEXTMENU;
+ break;
+
+ default:
+ LOG(FATAL) << "Unknown mouse event: " << Msg;
+ }
+ Event event(type);
+ // Now do any event-specific code that requires an Event object.
+ switch (Msg) {
+ case WM_LBUTTONDOWN:
+ case WM_LBUTTONUP:
+ case WM_LBUTTONDBLCLK:
+ event.set_button(Event::BUTTON_LEFT);
+ break;
+
+ case WM_RBUTTONDOWN:
+ case WM_RBUTTONUP:
+ case WM_RBUTTONDBLCLK:
+ event.set_button(Event::BUTTON_RIGHT);
+ break;
+
+ case WM_MBUTTONDOWN:
+ case WM_MBUTTONUP:
+ case WM_MBUTTONDBLCLK:
+ event.set_button(Event::BUTTON_MIDDLE);
+ break;
+
+#if (_WIN32_WINNT >= 0x0500)
+ case WM_XBUTTONDOWN:
+ case WM_XBUTTONUP:
+ case WM_XBUTTONDBLCLK:
+ if (GET_XBUTTON_WPARAM(wParam) == XBUTTON1) {
+ event.set_button(Event::BUTTON_4);
+ } else {
+ event.set_button(Event::BUTTON_5);
+ }
+ break;
+#endif
+ case WM_MOUSEWHEEL:
+ event.set_delta(0, GET_WHEEL_DELTA_WPARAM(wParam));
+ break;
+ case WM_MOUSEHWHEEL:
+ event.set_delta(GET_WHEEL_DELTA_WPARAM(wParam), 0);
+ break;
+
+ default:
+ break;
+ }
+
+ if (event.type() != WM_CONTEXTMENU) {
+ // Only the context menu event doesn't get this information.
+ int modifier_state = 0;
+ if (wParam & MK_CONTROL) {
+ modifier_state |= Event::MODIFIER_CTRL;
+ }
+ if (wParam & MK_SHIFT) {
+ modifier_state |= Event::MODIFIER_SHIFT;
+ }
+ if (::GetKeyState(VK_MENU) < 0) {
+ modifier_state |= Event::MODIFIER_ALT;
+ }
+ event.set_modifier_state(modifier_state);
+ }
+
+ event.set_position(x, y, screen_x, screen_y, in_plugin);
+ obj->client()->AddEventToQueue(event);
+ if (fake_dblclick) {
+ event.set_type(Event::TYPE_DBLCLICK);
+ obj->client()->AddEventToQueue(event);
+ }
+ if (in_plugin && type == Event::TYPE_MOUSEDOWN &&
+ obj->HitFullscreenClickRegion(x, y)) {
+ obj->RequestFullscreenDisplay();
+ }
+}
+
+// This returns 0 on success, 1 on failure, to match WindowProc.
+static LRESULT ForwardEvent(PluginObject *obj,
+ HWND hWnd,
+ UINT Msg,
+ WPARAM wParam,
+ LPARAM lParam,
+ bool translateCoords) {
+ DCHECK(obj);
+ DCHECK(obj->GetPluginHWnd());
+ HWND dest_hwnd = obj->GetParentHWnd();
+ DCHECK(hWnd);
+ DCHECK(dest_hwnd);
+ bool fullscreen = hWnd == obj->GetFullscreenHWnd();
+ if (fullscreen) {
+ dest_hwnd = obj->GetPluginHWnd();
+ } else if (obj->IsChrome()) {
+ // When trying to find the parent window of the Chrome plugin, new Chrome is
+ // different than old Chrome; it's got an extra wrapper window around the
+ // plugin that didn't used to be there. The wrapper won't listen to events,
+ // so if we see it, we have to go one window up the tree from there in order
+ // to find someone who'll listen to us. The new behavior is seen in nightly
+ // builds of Chromium as of 2.0.163.0 (9877) [but went in some time before
+ // that]; the old behavior is still exhibited by Chrome as of 1.0.154.48.
+ wchar_t chrome_class_name[] = L"WrapperNativeWindowClass";
+ wchar_t buffer[sizeof(chrome_class_name) / sizeof(chrome_class_name[0])];
+ if (!GetClassName(dest_hwnd, buffer, sizeof(buffer) / sizeof(buffer[0]))) {
+ return 1;
+ }
+ if (!wcscmp(chrome_class_name, buffer)) {
+ dest_hwnd = ::GetParent(dest_hwnd);
+ }
+ }
+ if (translateCoords) {
+ int x = GET_X_LPARAM(lParam);
+ int y = GET_Y_LPARAM(lParam);
+
+ RECT rect0, rect1;
+ if (!::GetWindowRect(hWnd, &rect0)) {
+ DCHECK(false);
+ return 1;
+ }
+ if (!::GetWindowRect(dest_hwnd, &rect1)) {
+ DCHECK(false);
+ return 1;
+ }
+ int width = rect0.right - rect0.left;
+ int width_1 = rect1.right - rect1.left;
+
+ int x_1;
+ int y_1;
+
+ if (!fullscreen) { // Translate from plugin to browser offset coords.
+ x_1 = x - rect1.left + rect0.left;
+ } else { // Translate from screen to plugin offset coords.
+ // The plugin and the fullscreen window each fill their respective entire
+ // window, so there aren't any offsets to add or subtract.
+ x_1 = x * width_1 / width;
+ }
+ int height = rect0.bottom - rect0.top;
+ int height_1 = rect1.bottom - rect1.top;
+ if (!fullscreen) { // Translate from plugin to browser offset coords.
+ y_1 = y - rect1.top + rect0.top;
+ } else { // Translate from screen to plugin offset coords.
+ // The plugin and the fullscreen window each fill their respective entire
+ // window, so there aren't any offsets to add or subtract.
+ y_1 = y * height_1 / height;
+ }
+
+ lParam = MAKELPARAM(x_1, y_1);
+ }
+ return !::PostMessage(dest_hwnd, Msg, wParam, lParam);
+}
+
+static LRESULT HandleDragAndDrop(PluginObject *obj, WPARAM wParam) {
+ HDROP hDrop = reinterpret_cast<HDROP>(wParam);
+ UINT num_files = ::DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0);
+ if (!num_files) {
+ ::DragFinish(hDrop);
+ return 0;
+ }
+ UINT path_len = ::DragQueryFile(hDrop, 0, NULL, 0);
+ // Let's limit that length, just in case.
+ if (!path_len || path_len > 4096) {
+ ::DragFinish(hDrop);
+ return 0;
+ }
+ scoped_array<TCHAR> path(new TCHAR[path_len + 1]); // Add 1 for the NUL.
+ UINT num_chars = ::DragQueryFile(hDrop, 0, path.get(), path_len + 1);
+ DCHECK(num_chars == path_len);
+ ::DragFinish(hDrop);
+
+ char *path_to_use = NULL;
+#ifdef UNICODE // TCHAR is WCHAR
+ // TODO: We definitely need to move this to a string utility class.
+ int bytes_needed = ::WideCharToMultiByte(CP_UTF8,
+ 0,
+ path.get(),
+ num_chars + 1,
+ NULL,
+ 0,
+ NULL,
+ NULL);
+ // Let's limit that length, just in case.
+ if (!bytes_needed || bytes_needed > 4096) {
+ return 0;
+ }
+ scoped_array<char> utf8_path(new char[bytes_needed]);
+ int bytes_conv = ::WideCharToMultiByte(CP_UTF8,
+ 0,
+ path.get(),
+ num_chars + 1,
+ utf8_path.get(),
+ bytes_needed,
+ NULL,
+ NULL);
+ DCHECK(bytes_conv == bytes_needed);
+ path_to_use = utf8_path.get();
+ num_chars = bytes_conv;
+#else
+ path_to_use = path.get();
+#endif
+
+ for (int i = 0; i < num_chars; ++i) {
+ if (path_to_use[i] == '\\') {
+ path_to_use[i] = '/';
+ }
+ }
+ obj->RedirectToFile(path_to_use);
+
+ return 1;
+}
+
+static LRESULT CALLBACK
+WindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) {
+ PluginObject *obj = PluginObject::GetPluginProperty(hWnd);
+ if (obj == NULL) { // It's not my window
+ return 1; // 0 often means we handled it.
+ }
+
+ // Limit the ways in which we can be reentrant. Note that this WindowProc
+ // may be called by different threads. For example, IE will register plugin
+ // instances on separate threads.
+ o3d::Client::ScopedIncrement reentrance_count(obj->client());
+
+ switch (Msg) {
+ case WM_PAINT: {
+ if (reentrance_count.get() > 1) {
+ break; // Ignore this message; we're reentrant.
+ }
+ PAINTSTRUCT paint_struct;
+ HDC hdc = ::BeginPaint(hWnd, &paint_struct);
+ if (paint_struct.rcPaint.right - paint_struct.rcPaint.left != 0 ||
+ paint_struct.rcPaint.bottom - paint_struct.rcPaint.top != 0) {
+ if (obj->renderer()) {
+ // It appears to be necessary to use GDI to paint something at least
+ // once before D3D rendering will work in Vista with Aero.
+ if (!obj->RecordPaint()) {
+ ::SetPixelV(hdc, 0, 0, RGB(0, 0, 0));
+ }
+
+ obj->client()->RenderClient();
+ } else {
+ // If there Client has no Renderer associated with it, paint the draw
+ // area gray.
+ ::SelectObject(paint_struct.hdc, GetStockObject(DKGRAY_BRUSH));
+ ::Rectangle(paint_struct.hdc,
+ paint_struct.rcPaint.left,
+ paint_struct.rcPaint.top,
+ paint_struct.rcPaint.right,
+ paint_struct.rcPaint.bottom);
+ }
+ }
+ ::EndPaint(hWnd, &paint_struct);
+ break;
+ }
+ case WM_SETCURSOR: {
+ obj->set_cursor(obj->cursor());
+ return 1;
+ }
+ case WM_ERASEBKGND: {
+ return 1; // tell windows we don't need the background cleared
+ }
+ case WM_SIZE: {
+ // Resize event called
+ if (reentrance_count.get() > 1) {
+ break; // Ignore this message; we're reentrant.
+ }
+
+ // get new dimensions of window
+ int window_width = LOWORD(lParam);
+ int window_height = HIWORD(lParam);
+
+ // Tell the plugin that it has been resized
+ obj->Resize(window_width, window_height);
+ break;
+ }
+ case WM_TIMER: {
+ if (reentrance_count.get() > 1) {
+ break; // Ignore this message; we're reentrant.
+ }
+ // DoOnFrameCallback(obj);
+
+ // TODO: Only logging for windows until we figure out the proper
+ // mac way
+ if (g_logger) g_logger->UpdateLogging();
+
+ obj->client()->Tick();
+ if (obj->client()->render_mode() ==
+ o3d::Client::RENDERMODE_CONTINUOUS) {
+ // Must invalidate GetHWnd()'s drawing area, no matter which window is
+ // receiving this event. It turns out that we have to set the timer on
+ // the window we're using for drawing anyway, whichever that is, but
+ // it's possible that an extra event will slip through.
+ ::InvalidateRect(obj->GetHWnd(), NULL, TRUE);
+ }
+ // Calling UpdateWindow to force a WM_PAINT here causes problems in
+ // Firefox 2 if rendering takes too long. WM_PAINT will be sent anyway
+ // when there are no other messages to process.
+ break;
+ }
+ case WM_NCDESTROY: {
+ // Win32 docs say we must remove all our properties before destruction.
+ // However, this message doesn't appear to come early enough to be useful
+ // when running in Chrome, at least.
+ PluginObject::ClearPluginProperty(hWnd);
+ break;
+ }
+ case WM_LBUTTONDOWN:
+ case WM_LBUTTONDBLCLK:
+ case WM_RBUTTONDOWN:
+ case WM_RBUTTONDBLCLK:
+ case WM_MBUTTONDOWN:
+ case WM_MBUTTONDBLCLK:
+#if (_WIN32_WINNT >= 0x0500)
+ case WM_XBUTTONDOWN:
+ case WM_XBUTTONDBLCLK:
+#endif
+ case WM_MOUSEWHEEL:
+ case WM_MOUSEHWHEEL:
+ // Without this SetFocus, if you alt+tab away from Firefox, then click
+ // back in the plugin, Firefox will get keyboard focus but we won't.
+ // However, if we do it on mouseup as well, then the click that triggers
+ // fullscreen, and is followed by a mouseup in the plugin, which will grab
+ // the focus back from the fullscreen window.
+ ::SetFocus(hWnd);
+ // FALL THROUGH
+ case WM_LBUTTONUP:
+ case WM_RBUTTONUP:
+ case WM_MBUTTONUP:
+#if (_WIN32_WINNT >= 0x0500)
+ case WM_XBUTTONUP:
+#endif
+ case WM_MOUSEMOVE:
+ case WM_CONTEXTMENU:
+ HandleMouseEvent(obj, hWnd, Msg, wParam, lParam);
+ break;
+
+ case WM_DEADCHAR:
+ case WM_SYSDEADCHAR:
+ case WM_UNICHAR:
+ // I believe these are redundant; TODO: Test this on a non-US
+ // keyboard.
+ break;
+
+ case WM_CHAR:
+ case WM_SYSCHAR:
+ case WM_KEYDOWN:
+ case WM_KEYUP:
+ case WM_SYSKEYDOWN:
+ case WM_SYSKEYUP:
+ return HandleKeyboardEvent(obj, hWnd, Msg, wParam, lParam);
+
+#if(_WIN32_WINNT >= 0x0500)
+ case WM_APPCOMMAND:
+#endif /* _WIN32_WINNT >= 0x0500 */
+ return ForwardEvent(obj, hWnd, Msg, wParam, lParam, false);
+
+ case WM_DROPFILES:
+ return HandleDragAndDrop(obj, wParam);
+
+ case WM_KILLFOCUS:
+ // If we lose focus [which also happens on alt+f4 killing the fullscreen
+ // window] fall back to plugin mode to avoid lost-device awkwardness.
+ // TODO: We'll have problems with this when dealing with e.g.
+ // Japanese text input IME windows.
+ if (hWnd == obj->GetFullscreenHWnd()) {
+ obj->CancelFullscreenDisplay();
+ return 0;
+ }
+ // FALL THROUGH
+ case WM_SETFOCUS:
+ default:
+ // Decrement reentrance_count here. It's OK if this call
+ // boomerangs back to us, given that we're not in the middle of doing
+ // anything caused by this message. Since we decrement reentrance_count
+ // manually, its destructor will know not to.
+ reentrance_count.decrement();
+
+ if (hWnd == obj->GetFullscreenHWnd()) {
+ return ::CallWindowProc(::DefWindowProc,
+ hWnd,
+ Msg,
+ wParam,
+ lParam);
+ } else {
+ return ::CallWindowProc(obj->GetDefaultPluginWindowProc(),
+ hWnd,
+ Msg,
+ wParam,
+ lParam);
+ }
+ }
+ return 0;
+}
+
+extern "C" {
+ NPError InitializePlugin() {
+ if (!o3d::SetupOutOfMemoryHandler())
+ return NPERR_MODULE_LOAD_FAILED_ERROR;
+
+ // Setup crash handler
+ if (!g_exception_manager) {
+ g_exception_manager = new ExceptionManager(false);
+ g_exception_manager->StartMonitoring();
+ }
+
+ // Initialize the AtExitManager so that base singletons can be
+ // destroyed properly.
+ g_at_exit_manager.reset(new base::AtExitManager());
+
+ // Turn on the logging.
+ CommandLine::Init(0, NULL);
+ InitLogging(L"debug.log",
+ logging::LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG,
+ logging::DONT_LOCK_LOG_FILE,
+ logging::APPEND_TO_OLD_LOG_FILE);
+
+ DLOG(INFO) << "NP_Initialize";
+
+ // Limit the current thread to one processor (the current one). This ensures
+ // that timing code runs on only one processor, and will not suffer any ill
+ // effects from power management. See "Game Timing and Multicore Processors"
+ // in the DirectX docs for more details
+ {
+ HANDLE current_process_handle = GetCurrentProcess();
+
+ // Get the processor affinity mask for this process
+ DWORD_PTR process_affinity_mask = 0;
+ DWORD_PTR system_affinity_mask = 0;
+
+ if (GetProcessAffinityMask(current_process_handle,
+ &process_affinity_mask,
+ &system_affinity_mask) != 0 &&
+ process_affinity_mask) {
+ // Find the lowest processor that our process is allows to run against
+ DWORD_PTR affinity_mask = (process_affinity_mask &
+ ((~process_affinity_mask) + 1));
+
+ // Set this as the processor that our thread must always run against
+ // This must be a subset of the process affinity mask
+ HANDLE hCurrentThread = GetCurrentThread();
+ if (INVALID_HANDLE_VALUE != hCurrentThread) {
+ SetThreadAffinityMask(hCurrentThread, affinity_mask);
+ CloseHandle(hCurrentThread);
+ }
+ }
+
+ CloseHandle(current_process_handle);
+ }
+
+ return NPERR_NO_ERROR;
+ }
+
+ NPError OSCALL NP_Initialize(NPNetscapeFuncs *browserFuncs) {
+ HANDLE_CRASHES;
+ NPError retval = InitializeNPNApi(browserFuncs);
+ if (retval != NPERR_NO_ERROR) return retval;
+ return InitializePlugin();
+ }
+
+ NPError OSCALL NP_Shutdown(void) {
+ HANDLE_CRASHES;
+ DLOG(INFO) << "NP_Shutdown";
+ if (g_logger) {
+ // Do a last sweep to aggregate metrics before we shut down
+ g_logger->ProcessMetrics(true, false);
+ delete g_logger;
+ g_logger = NULL;
+ g_logging_initialized = false;
+ stats_report::g_global_metrics.Uninitialize();
+ }
+
+ CommandLine::Terminate();
+
+ // Force all base singletons to be destroyed.
+ g_at_exit_manager.reset(NULL);
+
+ // TODO : This is commented out until we can determine if
+ // it's safe to shutdown breakpad at this stage (Gears, for
+ // example, never deletes...)
+ // Shutdown breakpad
+ // delete g_exception_manager;
+
+ // Strictly speaking, on windows, it's not really necessary to call
+ // Stop(), but we do so for completeness
+ if (g_bluescreen_detector) {
+ g_bluescreen_detector->Stop();
+ delete g_bluescreen_detector;
+ g_bluescreen_detector = NULL;
+ }
+
+ return NPERR_NO_ERROR;
+ }
+
+ NPError NPP_New(NPMIMEType pluginType,
+ NPP instance,
+ uint16 mode,
+ int16 argc,
+ char *argn[],
+ char *argv[],
+ NPSavedData *saved) {
+ HANDLE_CRASHES;
+
+ if (!g_logging_initialized) {
+ // Get user config metrics. These won't be stored though unless the user
+ // opts-in for usagestats logging
+ GetUserAgentMetrics(instance);
+ GetUserConfigMetrics();
+ // Create usage stats logs object
+ g_logger = o3d::PluginLogging::InitializeUsageStatsLogging();
+ if (g_logger) {
+ // Setup blue-screen detection
+ g_bluescreen_detector = new o3d::BluescreenDetector();
+ g_bluescreen_detector->Start();
+ }
+ g_logging_initialized = true;
+ }
+ PluginObject* pluginObject = glue::_o3d::PluginObject::Create(
+ instance);
+ instance->pdata = pluginObject;
+ glue::_o3d::InitializeGlue(instance);
+ pluginObject->Init(argc, argn, argv);
+ return NPERR_NO_ERROR;
+ }
+
+ void CleanupFullscreenWindow(PluginObject *obj) {
+ DCHECK(obj->GetFullscreenHWnd());
+ obj->StorePluginProperty(obj->GetPluginHWnd(), obj);
+ ::DestroyWindow(obj->GetFullscreenHWnd());
+ obj->SetFullscreenHWnd(NULL);
+ }
+
+ void CleanupAllWindows(PluginObject *obj) {
+ DCHECK(obj->GetHWnd());
+ DCHECK(obj->GetPluginHWnd());
+ ::KillTimer(obj->GetHWnd(), 0);
+ if (obj->GetFullscreenHWnd()) {
+ CleanupFullscreenWindow(obj);
+ }
+ PluginObject::ClearPluginProperty(obj->GetHWnd());
+ ::SetWindowLongPtr(obj->GetPluginHWnd(),
+ GWL_WNDPROC,
+ reinterpret_cast<LONG_PTR>(
+ obj->GetDefaultPluginWindowProc()));
+ obj->SetPluginHWnd(NULL);
+ obj->SetHWnd(NULL);
+ }
+
+ NPError NPP_Destroy(NPP instance, NPSavedData **save) {
+ HANDLE_CRASHES;
+ PluginObject *obj = static_cast<PluginObject*>(instance->pdata);
+ if (obj) {
+ if (obj->GetHWnd()) {
+ CleanupAllWindows(obj);
+ }
+
+ obj->TearDown();
+ NPN_ReleaseObject(obj);
+ instance->pdata = NULL;
+ }
+
+ return NPERR_NO_ERROR;
+ }
+
+ HWND CreateFullscreenWindow(PluginObject *obj,
+ int mode_id) {
+ o3d::DisplayMode mode;
+ if (!obj->renderer()->GetDisplayMode(mode_id, &mode)) {
+ return NULL;
+ }
+ CHECK(mode.width() > 0 && mode.height() > 0);
+
+ HINSTANCE instance =
+ reinterpret_cast<HINSTANCE>(
+ ::GetWindowLongPtr(obj->GetPluginHWnd(), GWLP_HINSTANCE));
+ WNDCLASSEX *wcx = obj->GetFullscreenWindowClass(instance, WindowProc);
+ HWND hWnd = CreateWindowEx(NULL,
+ wcx->lpszClassName,
+ L"O3D Test Fullscreen Window",
+ WS_POPUP,
+ 0, 0,
+ mode.width(),
+ mode.height(),
+ NULL,
+ NULL,
+ instance,
+ NULL);
+
+ ShowWindow(hWnd, SW_SHOW);
+ return hWnd;
+ }
+
+ // TODO: Where should this really live? It's platform-specific, but in
+ // PluginObject, which mainly lives in cross/o3d_glue.h+cc.
+ bool PluginObject::RequestFullscreenDisplay() {
+ bool success = false;
+#ifndef NDEBUG // TODO: Remove after user-prompt feature goes in.
+ DCHECK(GetPluginHWnd());
+ if (!fullscreen_ && renderer_ && fullscreen_region_valid_) {
+ DCHECK(renderer_->fullscreen() == fullscreen_);
+ DCHECK(!GetFullscreenHWnd());
+ HWND drawing_hwnd =
+ CreateFullscreenWindow(this, fullscreen_region_mode_id_);
+ if (drawing_hwnd) {
+ ::KillTimer(GetHWnd(), 0);
+ SetFullscreenHWnd(drawing_hwnd);
+ StorePluginPropertyUnsafe(drawing_hwnd, this);
+
+ DisplayWindowWindows display;
+ display.set_hwnd(GetHWnd());
+ if (renderer_->SetFullscreen(true, display,
+ fullscreen_region_mode_id_)) {
+ fullscreen_ = true;
+ client()->SendResizeEvent(renderer_->width(), renderer_->height(),
+ true);
+ success = true;
+ } else {
+ CleanupFullscreenWindow(this);
+ }
+ prev_width_ = renderer_->width();
+ prev_height_ = renderer_->height();
+ ::SetTimer(GetHWnd(), 0, 10, NULL);
+ } else {
+ LOG(ERROR) << "Failed to create fullscreen window.";
+ }
+ }
+#endif
+ return success;
+ }
+
+ void PluginObject::CancelFullscreenDisplay() {
+#ifndef NDEBUG // TODO: Remove after user-prompt feature goes in.
+ DCHECK(GetPluginHWnd());
+ if (fullscreen_) {
+ DCHECK(renderer());
+ DCHECK(renderer()->fullscreen());
+ ::KillTimer(GetHWnd(), 0);
+ DisplayWindowWindows display;
+ display.set_hwnd(GetPluginHWnd());
+ if (!renderer_->SetFullscreen(false, display, 0)) {
+ LOG(FATAL) << "Failed to get the renderer out of fullscreen mode!";
+ }
+ CleanupFullscreenWindow(this);
+ prev_width_ = renderer_->width();
+ prev_height_ = renderer_->height();
+ client()->SendResizeEvent(prev_width_, prev_height_, false);
+ ::SetTimer(GetHWnd(), 0, 10, NULL);
+ fullscreen_ = false;
+ }
+#endif
+ }
+
+ NPError NPP_SetWindow(NPP instance, NPWindow *window) {
+ HANDLE_CRASHES;
+ PluginObject *obj = static_cast<PluginObject*>(instance->pdata);
+
+ HWND hWnd = static_cast<HWND>(window->window);
+ if (!hWnd) {
+ // Chrome calls us this way before NPP_Destroy.
+ if (obj->GetHWnd()) {
+ CleanupAllWindows(obj);
+ }
+ return NPERR_NO_ERROR;
+ }
+ if (obj->GetHWnd() == hWnd) {
+ return NPERR_NO_ERROR;
+ }
+ if (obj->fullscreen()) {
+ // We can get here if the user alt+tabs away from the fullscreen plugin
+ // window or JavaScript resizes the plugin window.
+ DCHECK(obj->GetPluginHWnd());
+ DCHECK(obj->GetFullscreenHWnd());
+ DCHECK(obj->GetPluginHWnd() == hWnd);
+ return NPERR_NO_ERROR;
+ }
+ DCHECK(!obj->GetPluginHWnd());
+ obj->SetPluginHWnd(hWnd);
+ obj->SetParentHWnd(::GetParent(hWnd));
+ PluginObject::StorePluginProperty(hWnd, obj);
+ obj->SetDefaultPluginWindowProc(
+ reinterpret_cast<WNDPROC>(
+ ::SetWindowLongPtr(hWnd,
+ GWL_WNDPROC,
+ reinterpret_cast<LONG_PTR>(WindowProc))));
+
+ // create and assign the graphics context
+ DisplayWindowWindows default_display;
+ default_display.set_hwnd(obj->GetHWnd());
+
+ obj->CreateRenderer(default_display);
+ obj->client()->Init();
+ obj->client()->SetRenderOnDemandCallback(
+ new RenderOnDemandCallbackHandler(obj));
+
+ // we set the timer to 10ms or 100fps. At the time of this comment
+ // the renderer does a vsync the max fps it will run will be the refresh
+ // rate of the monitor or 100fps, which ever is lower.
+ ::SetTimer(obj->GetHWnd(), 0, 10, NULL);
+
+ return NPERR_NO_ERROR;
+ }
+
+ // Called when the browser has finished attempting to stream data to
+ // a file as requested. If fname == NULL the attempt was not successful.
+ void NPP_StreamAsFile(NPP instance, NPStream *stream, const char *fname) {
+ HANDLE_CRASHES;
+ PluginObject *obj = static_cast<PluginObject*>(instance->pdata);
+ StreamManager *stream_manager = obj->stream_manager();
+
+ stream_manager->SetStreamFile(stream, fname);
+ }
+
+ int16 NPP_HandleEvent(NPP instance, void *event) {
+ HANDLE_CRASHES;
+ return 0;
+ }
+} // end extern "C"
diff --git a/o3d/plugin/win/o3dPlugin.def b/o3d/plugin/win/o3dPlugin.def
new file mode 100644
index 0000000..9685d16
--- /dev/null
+++ b/o3d/plugin/win/o3dPlugin.def
@@ -0,0 +1,6 @@
+LIBRARY npo3dautoplugin
+
+EXPORTS
+ NP_GetEntryPoints @1
+ NP_Initialize @2
+ NP_Shutdown @3
diff --git a/o3d/plugin/win/o3dPlugin.rc_template b/o3d/plugin/win/o3dPlugin.rc_template
new file mode 100644
index 0000000..8085cf9
--- /dev/null
+++ b/o3d/plugin/win/o3dPlugin.rc_template
@@ -0,0 +1,106 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION @@@ProductVersionCommas@@@
+ PRODUCTVERSION @@@ProductVersionCommas@@@
+ FILEFLAGSMASK 0x17L
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904e4"
+ BEGIN
+ // This value must not change format as it is used by javascript
+ // to find the plugin. See o3d/main.scons
+ VALUE "FileDescription", "@@@PluginDescription@@@"
+ VALUE "FileVersion", "@@@ProductVersionCommas@@@"
+ VALUE "InternalName", "npo3dautoplugin"
+ VALUE "LegalCopyright", "Copyright (C) 2007"
+ VALUE "MIMEType", "@@@PluginMimeType@@@"
+ VALUE "OriginalFilename", "npo3dautoplugin.dll"
+ // This value must not change as it is used by javascript
+ // to find the plugin. See o3d/main.scons
+ VALUE "ProductName", "@@@PluginName@@@"
+ VALUE "ProductVersion", "@@@ProductVersionCommas@@@"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1252
+ END
+END
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/o3d/plugin/win/o3dPlugin.sln b/o3d/plugin/win/o3dPlugin.sln
new file mode 100644
index 0000000..d4ab270
--- /dev/null
+++ b/o3d/plugin/win/o3dPlugin.sln
@@ -0,0 +1,92 @@
+
+Microsoft Visual Studio Solution File, Format Version 9.00
+# Visual Studio 2005
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "o3dPlugin", "o3dPlugin.vcproj", "{F431F75C-5EA2-4E96-BA23-B44A951A9276}"
+ ProjectSection(WebsiteProperties) = preProject
+ Debug.AspNetCompiler.Debug = "True"
+ Release.AspNetCompiler.Debug = "False"
+ EndProjectSection
+ ProjectSection(ProjectDependencies) = postProject
+ {B57C4010-AE66-47A2-8B1F-F839B6E6A67B} = {B57C4010-AE66-47A2-8B1F-F839B6E6A67B}
+ {7D7B36BE-B994-4BE2-A60C-753C19E5A9EA} = {7D7B36BE-B994-4BE2-A60C-753C19E5A9EA}
+ {6028E8C8-F1DC-4248-9961-B0CADFEA244C} = {6028E8C8-F1DC-4248-9961-B0CADFEA244C}
+ {E1978291-230F-4F95-A227-84A13F22833C} = {E1978291-230F-4F95-A227-84A13F22833C}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "o3dImport", "..\..\..\..\o3d\import\win\import.vcproj", "{6028E8C8-F1DC-4248-9961-B0CADFEA244C}"
+ ProjectSection(WebsiteProperties) = preProject
+ Debug.AspNetCompiler.Debug = "True"
+ Release.AspNetCompiler.Debug = "False"
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "o3dCore", "..\..\..\..\o3d\core\win\core_win.vcproj", "{B57C4010-AE66-47A2-8B1F-F839B6E6A67B}"
+ ProjectSection(WebsiteProperties) = preProject
+ Debug.AspNetCompiler.Debug = "True"
+ Release.AspNetCompiler.Debug = "False"
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "o3d_base", "..\..\..\..\o3d\base\win\o3d_base.vcproj", "{E1978291-230F-4F95-A227-84A13F22833C}"
+ ProjectSection(WebsiteProperties) = preProject
+ Debug.AspNetCompiler.Debug = "True"
+ Release.AspNetCompiler.Debug = "False"
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "google_nacl_imc", "..\..\..\..\native_client\intermodule_comm\google_nacl_imc\google_nacl_imc.vcproj", "{7D7B36BE-B994-4BE2-A60C-753C19E5A9EA}"
+ ProjectSection(WebsiteProperties) = preProject
+ Debug.AspNetCompiler.Debug = "True"
+ Release.AspNetCompiler.Debug = "False"
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ DebugD3D9|Win32 = DebugD3D9|Win32
+ DebugGL|Win32 = DebugGL|Win32
+ ReleaseD3D9|Win32 = ReleaseD3D9|Win32
+ ReleaseGL|Win32 = ReleaseGL|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {F431F75C-5EA2-4E96-BA23-B44A951A9276}.DebugD3D9|Win32.ActiveCfg = DebugD3D9|Win32
+ {F431F75C-5EA2-4E96-BA23-B44A951A9276}.DebugD3D9|Win32.Build.0 = DebugD3D9|Win32
+ {F431F75C-5EA2-4E96-BA23-B44A951A9276}.DebugGL|Win32.ActiveCfg = DebugGL|Win32
+ {F431F75C-5EA2-4E96-BA23-B44A951A9276}.DebugGL|Win32.Build.0 = DebugGL|Win32
+ {F431F75C-5EA2-4E96-BA23-B44A951A9276}.ReleaseD3D9|Win32.ActiveCfg = ReleaseD3D9|Win32
+ {F431F75C-5EA2-4E96-BA23-B44A951A9276}.ReleaseD3D9|Win32.Build.0 = ReleaseD3D9|Win32
+ {F431F75C-5EA2-4E96-BA23-B44A951A9276}.ReleaseGL|Win32.ActiveCfg = ReleaseGL|Win32
+ {F431F75C-5EA2-4E96-BA23-B44A951A9276}.ReleaseGL|Win32.Build.0 = ReleaseGL|Win32
+ {6028E8C8-F1DC-4248-9961-B0CADFEA244C}.DebugD3D9|Win32.ActiveCfg = DebugD3D9|Win32
+ {6028E8C8-F1DC-4248-9961-B0CADFEA244C}.DebugD3D9|Win32.Build.0 = DebugD3D9|Win32
+ {6028E8C8-F1DC-4248-9961-B0CADFEA244C}.DebugGL|Win32.ActiveCfg = DebugGL|Win32
+ {6028E8C8-F1DC-4248-9961-B0CADFEA244C}.DebugGL|Win32.Build.0 = DebugGL|Win32
+ {6028E8C8-F1DC-4248-9961-B0CADFEA244C}.ReleaseD3D9|Win32.ActiveCfg = ReleaseD3D9|Win32
+ {6028E8C8-F1DC-4248-9961-B0CADFEA244C}.ReleaseD3D9|Win32.Build.0 = ReleaseD3D9|Win32
+ {6028E8C8-F1DC-4248-9961-B0CADFEA244C}.ReleaseGL|Win32.ActiveCfg = ReleaseGL|Win32
+ {6028E8C8-F1DC-4248-9961-B0CADFEA244C}.ReleaseGL|Win32.Build.0 = ReleaseGL|Win32
+ {B57C4010-AE66-47A2-8B1F-F839B6E6A67B}.DebugD3D9|Win32.ActiveCfg = DebugD3D9|Win32
+ {B57C4010-AE66-47A2-8B1F-F839B6E6A67B}.DebugD3D9|Win32.Build.0 = DebugD3D9|Win32
+ {B57C4010-AE66-47A2-8B1F-F839B6E6A67B}.DebugGL|Win32.ActiveCfg = DebugGL|Win32
+ {B57C4010-AE66-47A2-8B1F-F839B6E6A67B}.DebugGL|Win32.Build.0 = DebugGL|Win32
+ {B57C4010-AE66-47A2-8B1F-F839B6E6A67B}.ReleaseD3D9|Win32.ActiveCfg = ReleaseD3D9|Win32
+ {B57C4010-AE66-47A2-8B1F-F839B6E6A67B}.ReleaseD3D9|Win32.Build.0 = ReleaseD3D9|Win32
+ {B57C4010-AE66-47A2-8B1F-F839B6E6A67B}.ReleaseGL|Win32.ActiveCfg = ReleaseGL|Win32
+ {B57C4010-AE66-47A2-8B1F-F839B6E6A67B}.ReleaseGL|Win32.Build.0 = ReleaseGL|Win32
+ {E1978291-230F-4F95-A227-84A13F22833C}.DebugD3D9|Win32.ActiveCfg = Debug|Win32
+ {E1978291-230F-4F95-A227-84A13F22833C}.DebugD3D9|Win32.Build.0 = Debug|Win32
+ {E1978291-230F-4F95-A227-84A13F22833C}.DebugGL|Win32.ActiveCfg = Debug|Win32
+ {E1978291-230F-4F95-A227-84A13F22833C}.DebugGL|Win32.Build.0 = Debug|Win32
+ {E1978291-230F-4F95-A227-84A13F22833C}.ReleaseD3D9|Win32.ActiveCfg = Release|Win32
+ {E1978291-230F-4F95-A227-84A13F22833C}.ReleaseD3D9|Win32.Build.0 = Release|Win32
+ {E1978291-230F-4F95-A227-84A13F22833C}.ReleaseGL|Win32.ActiveCfg = Release|Win32
+ {E1978291-230F-4F95-A227-84A13F22833C}.ReleaseGL|Win32.Build.0 = Release|Win32
+ {7D7B36BE-B994-4BE2-A60C-753C19E5A9EA}.DebugD3D9|Win32.ActiveCfg = Debug|Win32
+ {7D7B36BE-B994-4BE2-A60C-753C19E5A9EA}.DebugD3D9|Win32.Build.0 = Debug|Win32
+ {7D7B36BE-B994-4BE2-A60C-753C19E5A9EA}.DebugGL|Win32.ActiveCfg = Debug|Win32
+ {7D7B36BE-B994-4BE2-A60C-753C19E5A9EA}.DebugGL|Win32.Build.0 = Debug|Win32
+ {7D7B36BE-B994-4BE2-A60C-753C19E5A9EA}.ReleaseD3D9|Win32.ActiveCfg = Release|Win32
+ {7D7B36BE-B994-4BE2-A60C-753C19E5A9EA}.ReleaseD3D9|Win32.Build.0 = Release|Win32
+ {7D7B36BE-B994-4BE2-A60C-753C19E5A9EA}.ReleaseGL|Win32.ActiveCfg = Release|Win32
+ {7D7B36BE-B994-4BE2-A60C-753C19E5A9EA}.ReleaseGL|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/o3d/plugin/win/plugin_logging-win32.cc b/o3d/plugin/win/plugin_logging-win32.cc
new file mode 100644
index 0000000..c1f389f
--- /dev/null
+++ b/o3d/plugin/win/plugin_logging-win32.cc
@@ -0,0 +1,306 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// This file contains code to perform the necessary logging operations
+// including initializing logging object, aggregating metrics, and uploading
+// metrics to the stats server.
+
+#include <build/build_config.h>
+#ifdef OS_WIN
+#include <atlbase.h>
+#include "statsreport/const-win32.h"
+#endif
+#include "core/cross/types.h"
+#include "plugin/cross/plugin_logging.h"
+#include "plugin/cross/plugin_metrics.h"
+#include "statsreport/common/const_product.h"
+#include "statsreport/metrics.h"
+#include "statsreport/uploader.h"
+namespace o3d {
+
+
+HRESULT StringEscape(const CString& str_in,
+ bool segment_only,
+ CString* escaped_string);
+HRESULT GetRegStringValue(bool is_machine_key,
+ const CString& relative_key_path,
+ const CString& value_name,
+ CString* value);
+
+PluginLogging::PluginLogging() : timer_(new HighresTimer()),
+ running_time_(0),
+ prev_uptime_seconds_(0),
+ prev_cputime_seconds_(0) {
+ DLOG(INFO) << "Creating logger.";
+ timer_->Start();
+}
+
+bool PluginLogging::UpdateLogging() {
+ // If sufficient time has not passed since last aggregation, we can just
+ // return until next time.
+ if (timer_->GetElapsedMs() < kStatsAggregationIntervalMSec) return false;
+
+ // Reset timer.
+ timer_->Start();
+ // We are not exiting just yet so pass false for that argument.
+ // We don't have to force stats reporting, so pass false for forcing, too.
+ return ProcessMetrics(false, false);
+}
+
+static uint64 ToSeconds(FILETIME time) {
+ ULARGE_INTEGER t;
+ t.u.HighPart = time.dwHighDateTime;
+ t.u.LowPart = time.dwLowDateTime;
+
+ return t.QuadPart / 10000000L;
+}
+
+void PluginLogging::RecordProcessTimes() {
+ FILETIME creation_time, exit_time, kernel_time, user_time;
+ if (!::GetProcessTimes(::GetCurrentProcess(), &creation_time, &exit_time,
+ &kernel_time, &user_time)) {
+ return;
+ }
+ FILETIME now;
+ ::GetSystemTimeAsFileTime(&now);
+ uint64 uptime = ToSeconds(now) - ToSeconds(creation_time);
+ uint64 additional_uptime = uptime - prev_uptime_seconds_;
+ metric_uptime_seconds += additional_uptime;
+ running_time_ += additional_uptime;
+ prev_uptime_seconds_ = uptime;
+
+ uint64 cputime = ToSeconds(kernel_time) + ToSeconds(user_time);
+ metric_cpu_time_seconds += (cputime - prev_cputime_seconds_);
+ prev_cputime_seconds_ = cputime;
+}
+
+bool PluginLogging::ProcessMetrics(const bool exiting,
+ const bool force_report) {
+ DLOG(INFO) << "ProcessMetrics()";
+ // Grab incremental process times. This has to be done each time
+ // around the loop since time passes between iterations.
+ RecordProcessTimes();
+
+ // This mutex protects the writing to the registry. This way,
+ // if we have multiple instances attempting to aggregate at
+ // once, they won't overwrite one another.
+ CHandle mutex(::CreateMutexA(NULL, FALSE, kMetricsLockName));
+ if (NULL == mutex.m_h) {
+ DLOG(WARNING) << "Unable to create metrics mutex";
+ return false;
+ }
+
+ // If we can't get the mutex in 3 seconds, let's go around again.
+ DWORD wait_result = ::WaitForSingleObject(mutex, 3000);
+ if (WAIT_OBJECT_0 != wait_result) {
+ DLOG(WARNING) << "Unable to get metrics mutex, error "
+ << std::hex << wait_result;
+ return false;
+ }
+ if (exiting) {
+ // If we're exiting, we aggregate to make sure that we record
+ // the tail activity for posterity. We don't report, because
+ // that might delay the process exit.
+ // We also make sure to add a sample to the total running time.
+ metric_running_time_seconds.AddSample(running_time_);
+ DoAggregateMetrics();
+ } else {
+ CString user_id;
+ if (FAILED(GetRegStringValue(true, // is_machine_key
+ CString(kRelativeGoopdateRegPath),
+ CString(kRegValueUserId),
+ &user_id))) {
+ user_id = CString("unknown user_id");
+ }
+ CString user_id_escaped;
+ StringEscape(user_id, true, &user_id_escaped);
+ CStringA client_id_argument = CString("ui=")
+ + user_id_escaped.GetString();
+ DLOG(INFO) << "client id " << client_id_argument;
+
+ std::string user_agent8 = std::string(kUserAgent) +
+ PRODUCT_VERSION_STRING;
+ DoAggregateAndReportMetrics(client_id_argument,
+ user_agent8.c_str(), force_report);
+ }
+
+ ::ReleaseMutex(mutex);
+
+ return true;
+}
+
+void PluginLogging::DoAggregateMetrics() {
+ DLOG(INFO) << "DoAggregateMetrics()";
+ stats_report::AggregateMetrics();
+}
+
+bool PluginLogging::DoAggregateAndReportMetrics(
+ const char* extra_url_arguments,
+ const char* user_agent,
+ const bool force_report) {
+ DLOG(INFO) << "DoAggregateAndReportMetrics()";
+ // This eturns true if metrics were uploaded.
+ return stats_report::AggregateAndReportMetrics(extra_url_arguments,
+ user_agent,
+ force_report);
+}
+
+// This method is used for testing.
+void PluginLogging::SetTimer(HighresTimer* timer) {
+ timer_.reset(timer);
+}
+
+// Reads the specified string value from the specified registry key.
+// Only supports value types REG_SZ and REG_EXPAND_SZ.
+// REG_EXPAND_SZ strings are not expanded.
+HRESULT GetRegStringValue(bool is_machine_key,
+ const CString& relative_key_path,
+ const CString& value_name,
+ CString* value) {
+ if (!value) {
+ return E_INVALIDARG;
+ }
+
+ value->Empty();
+ HKEY root_key = is_machine_key ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
+ HKEY key = NULL;
+ LONG res = ::RegOpenKeyEx(root_key, relative_key_path, 0, KEY_READ, &key);
+ if (res != ERROR_SUCCESS) {
+ return HRESULT_FROM_WIN32(res);
+ }
+
+ // First get the size of the string buffer.
+ DWORD type = 0;
+ DWORD byte_count = 0;
+ res = ::RegQueryValueEx(key, value_name, NULL, &type, NULL, &byte_count);
+ if (ERROR_SUCCESS != res) {
+ return HRESULT_FROM_WIN32(res);
+ }
+ if ((type != REG_SZ && type != REG_EXPAND_SZ) || (0 == byte_count)) {
+ return E_FAIL;
+ }
+
+ CString local_value;
+ // GetBuffer throws when not able to allocate the requested buffer.
+ TCHAR* buffer = local_value.GetBuffer(byte_count / sizeof(TCHAR));
+ res = ::RegQueryValueEx(key,
+ value_name,
+ NULL,
+ NULL,
+ reinterpret_cast<byte*>(buffer),
+ &byte_count);
+ if (ERROR_SUCCESS == res) {
+ local_value.ReleaseBufferSetLength(byte_count / sizeof(TCHAR));
+ *value = local_value;
+ }
+
+ return HRESULT_FROM_WIN32(res);
+}
+
+HRESULT StringEscape(const CString& str_in,
+ bool segment_only,
+ CString* escaped_string) {
+ if (!escaped_string) {
+ return E_INVALIDARG;
+ }
+
+ DWORD buf_len = INTERNET_MAX_URL_LENGTH + 1;
+ HRESULT hr = ::UrlEscape(str_in,
+ escaped_string->GetBufferSetLength(buf_len),
+ &buf_len,
+ segment_only ?
+ URL_ESCAPE_PERCENT | URL_ESCAPE_SEGMENT_ONLY :
+ URL_ESCAPE_PERCENT);
+ if (SUCCEEDED(hr)) {
+ escaped_string->ReleaseBuffer();
+ }
+ return hr;
+}
+
+PluginLogging* PluginLogging::InitializeUsageStatsLogging() {
+ HKEY hkcu;
+ ::RegOpenKeyEx(HKEY_CURRENT_USER,
+ kClientstateRegistryKey,
+ 0,
+ KEY_SET_VALUE,
+ &hkcu);
+ ::RegSetValueEx(hkcu, L"dr", 0, REG_SZ, (LPBYTE)"1\0", 2);
+ ::RegCloseKey(hkcu);
+
+ bool opt_in = GetOptInKeyValue(kClientstateRegistryKey, kOptInRegistryKey);
+
+ return CreateUsageStatsLogger<PluginLogging>(opt_in);
+}
+
+bool PluginLogging::GetOptInKeyValue(const wchar_t* clientstate_registry_key,
+ const wchar_t* opt_in_registry_key) {
+#ifdef NDEBUG
+ HKEY hkcu_opt;
+ if (::RegOpenKeyEx(HKEY_CURRENT_USER,
+ clientstate_registry_key,
+ 0,
+ KEY_QUERY_VALUE,
+ &hkcu_opt) != ERROR_SUCCESS) {
+ return false;
+ }
+ DWORD opt_value;
+ DWORD value_type;
+ ULONG value_len = sizeof(opt_value);
+ if (::RegQueryValueEx(hkcu_opt, opt_in_registry_key, 0,
+ &value_type, reinterpret_cast<BYTE *>(&opt_value),
+ &value_len) != ERROR_SUCCESS) {
+ return false;
+ }
+ ::RegCloseKey(hkcu_opt);
+
+ return opt_value == 1;
+#else
+ // If we are debugging, always return true.
+ return true;
+#endif
+ // Default to opt-out for situations we don't handle.
+ return false;
+}
+
+void PluginLogging::ClearLogs() {
+ CRegKey key;
+ CString key_name;
+ key_name.Format(stats_report::kStatsKeyFormatString,
+ PRODUCT_NAME_STRING_WIDE);
+ LONG err = key.Create(HKEY_CURRENT_USER, key_name);
+ if (ERROR_SUCCESS != err) {
+ DLOG(WARNING) << "Unable to open metrics key";
+ }
+ stats_report::ResetPersistentMetrics(&key);
+}
+
+} // namespace o3d
diff --git a/o3d/plugin/win/plugin_metrics-win32.cc b/o3d/plugin/win/plugin_metrics-win32.cc
new file mode 100644
index 0000000..f183595
--- /dev/null
+++ b/o3d/plugin/win/plugin_metrics-win32.cc
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "statsreport/metrics.h"
+#include "plugin/cross/plugin_metrics.h"
+
+namespace o3d {
+DEFINE_METRIC_integer(system_type);
+
+DEFINE_METRIC_integer(windows_major_version);
+DEFINE_METRIC_integer(windows_minor_version);
+DEFINE_METRIC_integer(windows_sp_major_version);
+DEFINE_METRIC_integer(windows_sp_minor_version);
+
+// User GPU
+DEFINE_METRIC_integer(gpu_vendor_id);
+DEFINE_METRIC_integer(gpu_device_id);
+DEFINE_METRIC_integer(gpu_driver_major_version);
+DEFINE_METRIC_integer(gpu_driver_minor_version);
+DEFINE_METRIC_integer(gpu_vram_size);
+DEFINE_METRIC_bool(direct3d_available);
+
+// Shader versions
+DEFINE_METRIC_integer(pixel_shader_main_version);
+DEFINE_METRIC_integer(pixel_shader_sub_version);
+DEFINE_METRIC_integer(vertex_shader_main_version);
+DEFINE_METRIC_integer(vertex_shader_sub_version);
+
+DEFINE_METRIC_bool(POW2_texture_caps);
+DEFINE_METRIC_bool(NONPOW2CONDITIONAL_texture_caps);
+
+DEFINE_METRIC_integer(browser_type);
+DEFINE_METRIC_integer(browser_major_version);
+DEFINE_METRIC_integer(browser_minor_version);
+DEFINE_METRIC_integer(browser_bugfix_version);
+
+DEFINE_METRIC_timing(running_time);
+
+DEFINE_METRIC_count(uptime_seconds);
+DEFINE_METRIC_count(cpu_time_seconds);
+DEFINE_METRIC_timing(running_time_seconds);
+
+DEFINE_METRIC_count(crashes_total);
+DEFINE_METRIC_count(crashes_uploaded);
+DEFINE_METRIC_count(out_of_memory_total);
+
+DEFINE_METRIC_count(bluescreens_total);
+
+// D3D Caps
+DEFINE_METRIC_integer(d3d_devcaps);
+DEFINE_METRIC_integer(d3d_misccaps);
+DEFINE_METRIC_integer(d3d_rastercaps);
+DEFINE_METRIC_integer(d3d_zcmpcaps);
+DEFINE_METRIC_integer(d3d_srcblendcaps);
+DEFINE_METRIC_integer(d3d_dstblendcaps);
+DEFINE_METRIC_integer(d3d_alphacaps);
+DEFINE_METRIC_integer(d3d_texcaps);
+DEFINE_METRIC_integer(d3d_texfiltercaps);
+DEFINE_METRIC_integer(d3d_cubetexfiltercaps);
+DEFINE_METRIC_integer(d3d_texaddrcaps);
+DEFINE_METRIC_integer(d3d_linecaps);
+DEFINE_METRIC_integer(d3d_stencilcaps);
+DEFINE_METRIC_integer(d3d_texopcaps);
+DEFINE_METRIC_integer(d3d_vs20caps);
+DEFINE_METRIC_integer(d3d_vs20_dynflowctrldepth);
+DEFINE_METRIC_integer(d3d_vs20_numtemps);
+DEFINE_METRIC_integer(d3d_vs20_staticflowctrldepth);
+DEFINE_METRIC_integer(d3d_ps20caps);
+DEFINE_METRIC_integer(d3d_ps20_dynflowctrldepth);
+DEFINE_METRIC_integer(d3d_ps20_numtemps);
+DEFINE_METRIC_integer(d3d_ps20_staticflowctrldepth);
+DEFINE_METRIC_integer(d3d_ps20_numinstrslots);
+
+} // namespace o3d
diff --git a/o3d/plugin/win/resource.h b/o3d/plugin/win/resource.h
new file mode 100644
index 0000000..f4b98ca
--- /dev/null
+++ b/o3d/plugin/win/resource.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by o3d_plugin.rc
+//
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 421
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1001
+#define _APS_NEXT_SYMED_VALUE 421
+#endif
+#endif
diff --git a/o3d/plugin/win/update_lock.cc b/o3d/plugin/win/update_lock.cc
new file mode 100644
index 0000000..3900365
--- /dev/null
+++ b/o3d/plugin/win/update_lock.cc
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "update_lock.h"
+
+namespace {
+// Instantiate a global object to indicate that the application is running.
+update_lock::HandleWrapper g_update_lock(update_lock::LockFromUpdates());
+
+} // anonymous namespace
diff --git a/o3d/plugin/win/update_lock.h b/o3d/plugin/win/update_lock.h
new file mode 100644
index 0000000..dcf78ad
--- /dev/null
+++ b/o3d/plugin/win/update_lock.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#ifndef O3D_PLUGIN_WIN_UPDATE_LOCK_H_
+#define O3D_PLUGIN_WIN_UPDATE_LOCK_H_
+
+#include <windows.h>
+#include "base/basictypes.h"
+
+namespace update_lock {
+
+const TCHAR kRunningEventName[] =
+ L"Global\\{AA4817F6-5DB2-482f-92E9-6BD2FF9F3B14}";
+
+class HandleWrapper {
+ public:
+ HandleWrapper(HANDLE handle) {
+ handle_ = handle;
+ }
+ ~HandleWrapper() {
+ CloseHandle(handle_);
+ }
+ HANDLE handle() {
+ return handle_;
+ }
+ private:
+ HANDLE handle_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(HandleWrapper);
+}; // HandleWrapper
+
+// Returns true if the software is currently not running and can be updated.
+bool CanUpdate() {
+ // Look for Global kernel object created when application is running
+ HandleWrapper running_event(
+ OpenEvent(EVENT_ALL_ACCESS, FALSE, kRunningEventName));
+ if (NULL != running_event.handle()) {
+ return false;
+ }
+ return true;
+}
+
+// Returns a HANDLE that should be closed when the software is shutting down.
+HANDLE LockFromUpdates() {
+ SECURITY_ATTRIBUTES* security_attributes = NULL;
+ SECURITY_ATTRIBUTES security_attributes_buffer;
+ SECURITY_DESCRIPTOR security_descriptor;
+
+ ZeroMemory(&security_attributes_buffer, sizeof(security_attributes_buffer));
+ security_attributes_buffer.nLength = sizeof(security_attributes_buffer);
+ security_attributes_buffer.bInheritHandle = FALSE;
+
+ // initialize the security descriptor and give it a NULL DACL
+ if (InitializeSecurityDescriptor(&security_descriptor,
+ SECURITY_DESCRIPTOR_REVISION)) {
+ if (SetSecurityDescriptorDacl(&security_descriptor, TRUE,
+ (PACL)NULL, FALSE)) {
+ security_attributes_buffer.lpSecurityDescriptor = &security_descriptor;
+ security_attributes = &security_attributes_buffer;
+ }
+ }
+ // An event is used to lock out updates since events are closed by the OS
+ // if their process dies. So, updates can still happen if an O3D executable
+ // crashes (as long as all instances of the running event are closed, either
+ // properly or due to a crash).
+ return CreateEvent(security_attributes, FALSE, FALSE, kRunningEventName);
+}
+} // namespace update_lock
+
+#endif // O3D_PLUGIN_WIN_UPDATE_LOCK_H_
+