summaryrefslogtreecommitdiffstats
path: root/o3d/plugin
diff options
context:
space:
mode:
authorgspencer@google.com <gspencer@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-05-27 23:15:42 +0000
committergspencer@google.com <gspencer@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-05-27 23:15:42 +0000
commit05b47f7a8c5451f858dc220df0e3a97542edace6 (patch)
treea2273d619f0625c9d44d40842845ccce2eac1045 /o3d/plugin
parent5cdc8bdb4c847cefe7f4542bd10c9880c2c557a0 (diff)
downloadchromium_src-05b47f7a8c5451f858dc220df0e3a97542edace6.zip
chromium_src-05b47f7a8c5451f858dc220df0e3a97542edace6.tar.gz
chromium_src-05b47f7a8c5451f858dc220df0e3a97542edace6.tar.bz2
This is the O3D source tree's initial commit to the Chromium tree. It
is not built or referenced at all by the chrome build yet, and doesn't yet build in it's new home. We'll change that shortly. git-svn-id: svn://svn.chromium.org/chrome/trunk/src@17035 0039d316-1c4b-4281-b951-d872f2087c98
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_
+