summaryrefslogtreecommitdiffstats
path: root/ppapi/generators
diff options
context:
space:
mode:
authorteravest@chromium.org <teravest@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-11-17 16:01:32 +0000
committerteravest@chromium.org <teravest@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-11-17 16:01:32 +0000
commit8c311f064c0ad5a70049f771bd15677bf7c9b098 (patch)
tree2a2727243475ff72eec47736e2567db064bba953 /ppapi/generators
parentd68206fcca8a719e5152a09c6e9d235cdbcdeec3 (diff)
downloadchromium_src-8c311f064c0ad5a70049f771bd15677bf7c9b098.zip
chromium_src-8c311f064c0ad5a70049f771bd15677bf7c9b098.tar.gz
chromium_src-8c311f064c0ad5a70049f771bd15677bf7c9b098.tar.bz2
Add support for generating thunk source from IDL.
This introduces a few new IDL attributes: generate_thunk - Enables thunk generation for an IDL file. create_func - Overrides the guessed create function name. on_failure - Overrides the default return value on failure. report_errors - Allows error reporting to be disabled. By using these attributes, we can generate _thunk.cc files for many IDL files. I'll send CLs for moving the thunks separately, as I found it tiring to review them all in a big lump. I have PPB_Widget_Dev here as an example. BUG= Review URL: https://chromiumcodereview.appspot.com/11417010 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@168450 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ppapi/generators')
-rwxr-xr-xppapi/generators/generator.py3
-rwxr-xr-xppapi/generators/idl_c_header.py1
-rwxr-xr-xppapi/generators/idl_c_proto.py75
-rwxr-xr-xppapi/generators/idl_generator.py1
-rwxr-xr-xppapi/generators/idl_thunk.py403
-rw-r--r--ppapi/generators/test_thunk/basic_test_types.idl58
-rw-r--r--ppapi/generators/test_thunk/simple.idl34
-rw-r--r--ppapi/generators/test_thunk/simple_thunk.cc96
8 files changed, 643 insertions, 28 deletions
diff --git a/ppapi/generators/generator.py b/ppapi/generators/generator.py
index 4511cd9..a71893c 100755
--- a/ppapi/generators/generator.py
+++ b/ppapi/generators/generator.py
@@ -13,6 +13,7 @@ from idl_option import ParseOptions
from idl_outfile import IDLOutFile
from idl_parser import ParseFiles
from idl_c_header import HGen
+from idl_thunk import TGen
from idl_gen_pnacl import PnaclGen
@@ -25,6 +26,7 @@ def Main(args):
'--wnone', '--cgen', '--range=start,end',
'--pnacl', '--pnaclshim',
'../native_client/src/untrusted/pnacl_irt_shim/pnacl_shim.c',
+ '--tgen',
]
current_dir = os.path.abspath(os.getcwd())
script_dir = os.path.abspath(os.path.dirname(__file__))
@@ -53,4 +55,3 @@ def Main(args):
if __name__ == '__main__':
sys.exit(Main(sys.argv[1:]))
-
diff --git a/ppapi/generators/idl_c_header.py b/ppapi/generators/idl_c_header.py
index c1e6071..43b1745 100755
--- a/ppapi/generators/idl_c_header.py
+++ b/ppapi/generators/idl_c_header.py
@@ -21,7 +21,6 @@ from idl_generator import Generator, GeneratorByFile
Option('dstroot', 'Base directory of output', default=os.path.join('..', 'c'))
Option('guard', 'Include guard prefix', default=os.path.join('ppapi', 'c'))
-Option('out', 'List of output files', default='')
def GetOutFileName(filenode, relpath=None, prefix=None):
diff --git a/ppapi/generators/idl_c_proto.py b/ppapi/generators/idl_c_proto.py
index c522bab..fea5615 100755
--- a/ppapi/generators/idl_c_proto.py
+++ b/ppapi/generators/idl_c_proto.py
@@ -426,12 +426,15 @@ class CGen(object):
# include_name - If true, include member name in the signature.
# If false, leave it out. In any case, prefix and ptr_prefix
# are always included.
+ # include_version - if True, include version in the member name
#
def GetSignature(self, node, release, mode, prefix='', func_as_ptr=True,
- ptr_prefix='', include_name=True):
+ ptr_prefix='', include_name=True, include_version=False):
self.LogEnter('GetSignature %s %s as func=%s' %
(node, mode, func_as_ptr))
rtype, name, arrayspec, callspec = self.GetComponents(node, release, mode)
+ if include_version:
+ name = self.GetStructName(node, release, True)
out = self.Compose(rtype, name, arrayspec, callspec, prefix,
func_as_ptr, ptr_prefix, include_name)
self.LogExit('Exit GetSignature: %s' % out)
@@ -562,9 +565,49 @@ class CGen(object):
#
# Generate a comment or copyright block
#
- def Copyright(self, node, tabs=0):
+ def Copyright(self, node, cpp_style=False):
lines = node.GetName().split('\n')
- return CommentLines(lines, tabs)
+ if cpp_style:
+ return '//' + '\n//'.join(filter(lambda f: f != '', lines)) + '\n'
+ return CommentLines(lines)
+
+
+ def Indent(self, data, tabs=0):
+ """Handles indentation and 80-column line wrapping."""
+ tab = ' ' * tabs
+ lines = []
+ for line in data.split('\n'):
+ # Add indentation
+ line = tab + line
+ if len(line) <= 80:
+ lines.append(line.rstrip())
+ else:
+ left = line.rfind('(') + 1
+ args = line[left:].split(',')
+ orig_args = args
+ orig_left = left
+ # Try to split on '(arg1)' or '(arg1, arg2)', not '()'
+ while args[0][0] == ')':
+ left = line.rfind('(', 0, left - 1) + 1
+ if left == 0: # No more parens, take the original option
+ args = orig_args
+ left = orig_left
+ break
+ args = line[left:].split(',')
+
+ line_max = 0
+ for arg in args:
+ if len(arg) > line_max: line_max = len(arg)
+
+ if left + line_max >= 80:
+ indent = '%s ' % tab
+ args = (',\n%s' % indent).join([arg.strip() for arg in args])
+ lines.append('%s\n%s%s' % (line[:left], indent, args))
+ else:
+ indent = ' ' * (left - 1)
+ args = (',\n%s' % indent).join(args)
+ lines.append('%s%s' % (line[:left], args))
+ return '\n'.join(lines)
# Define a top level object.
@@ -596,30 +639,10 @@ class CGen(object):
out += comment_txt
out += define_txt
- tab = ' ' * tabs
- lines = []
- for line in out.split('\n'):
- # Add indentation
- line = tab + line
- if len(line) > 80:
- left = line.rfind('(') + 1
- args = line[left:].split(',')
- line_max = 0
- for arg in args:
- if len(arg) > line_max: line_max = len(arg)
-
- if left + line_max >= 80:
- space = '%s ' % tab
- args = (',\n%s' % space).join([arg.strip() for arg in args])
- lines.append('%s\n%s%s' % (line[:left], space, args))
- else:
- space = ' ' * (left - 1)
- args = (',\n%s' % space).join(args)
- lines.append('%s%s' % (line[:left], args))
- else:
- lines.append(line.rstrip())
+ indented_out = self.Indent(out, tabs)
self.LogExit('Exit Define')
- return '\n'.join(lines)
+ return indented_out
+
# Clean a string representing an object definition and return then string
# as a single space delimited set of tokens.
diff --git a/ppapi/generators/idl_generator.py b/ppapi/generators/idl_generator.py
index 218b6b4..63277d2 100755
--- a/ppapi/generators/idl_generator.py
+++ b/ppapi/generators/idl_generator.py
@@ -11,6 +11,7 @@ from idl_parser import ParseFiles
GeneratorList = []
+Option('out', 'List of output files', default='')
Option('release', 'Which release to generate.', default='')
Option('range', 'Which ranges in the form of MIN,MAX.', default='start,end')
diff --git a/ppapi/generators/idl_thunk.py b/ppapi/generators/idl_thunk.py
new file mode 100755
index 0000000..eb41f01
--- /dev/null
+++ b/ppapi/generators/idl_thunk.py
@@ -0,0 +1,403 @@
+#!/usr/bin/env python
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+""" Generator for C++ style thunks """
+
+import glob
+import os
+import re
+import sys
+
+from idl_log import ErrOut, InfoOut, WarnOut
+from idl_node import IDLAttribute, IDLNode
+from idl_ast import IDLAst
+from idl_option import GetOption, Option, ParseOptions
+from idl_outfile import IDLOutFile
+from idl_parser import ParseFiles
+from idl_c_proto import CGen, GetNodeComments, CommentLines, Comment
+from idl_generator import Generator, GeneratorByFile
+
+Option('thunkroot', 'Base directory of output',
+ default=os.path.join('..', 'thunk'))
+
+
+class TGenError(Exception):
+ def __init__(self, msg):
+ self.value = msg
+
+ def __str__(self):
+ return repr(self.value)
+
+
+def _GetBaseFileName(filenode):
+ """Returns the base name for output files, given the filenode.
+
+ Examples:
+ 'dev/ppb_find_dev.h' -> 'ppb_find'
+ 'trusted/ppb_buffer_trusted.h' -> 'ppb_buffer_trusted'
+ """
+ path, name = os.path.split(filenode.GetProperty('NAME'))
+ name = os.path.splitext(name)[0]
+ if name.endswith('_dev'):
+ # Clip off _dev suffix.
+ name = name[:-len('_dev')]
+ return name
+
+
+def _GetHeaderFileName(filenode):
+ """Returns the name for the header for this file."""
+ path, name = os.path.split(filenode.GetProperty('NAME'))
+ name = os.path.splitext(name)[0]
+ if path:
+ header = "ppapi/c/%s/%s.h" % (path, name)
+ else:
+ header = "ppapi/c/%s.h" % name
+ return header
+
+
+def _GetThunkFileName(filenode, relpath):
+ """Returns the thunk file name."""
+ path = os.path.split(filenode.GetProperty('NAME'))[0]
+ name = _GetBaseFileName(filenode)
+ # We don't reattach the path for thunk.
+ if relpath: name = os.path.join(relpath, name)
+ name = '%s%s' % (name, '_thunk.cc')
+ return name
+
+
+def _MakeEnterLine(filenode, interface, arg, handle_errors, callback):
+ """Returns an EnterInstance/EnterResource string for a function."""
+ if arg[0] == 'PP_Instance':
+ if callback is None:
+ return 'EnterInstance enter(%s);' % arg[1]
+ else:
+ return 'EnterInstance enter(%s, %s);' % (arg[1], callback)
+ elif arg[0] == 'PP_Resource':
+ api_name = interface.GetName()
+ if api_name.endswith('_Dev'):
+ api_name = api_name[:-len('_Dev')]
+ api_name += '_API'
+
+ enter_type = 'EnterResource<%s>' % api_name
+ if callback is None:
+ return '%s enter(%s, %s);' % (enter_type, arg[1],
+ str(handle_errors).lower())
+ else:
+ return '%s enter(%s, %s, %s);' % (enter_type, arg[1],
+ callback,
+ str(handle_errors).lower())
+ else:
+ raise TGenError("Unknown type for _MakeEnterLine: %s" % arg[0])
+
+
+def _GetShortName(interface, filter_suffixes):
+ """Return a shorter interface name that matches Is* and Create* functions."""
+ parts = interface.GetName().split('_')[1:]
+ tail = parts[len(parts) - 1]
+ if tail in filter_suffixes:
+ parts = parts[:-1]
+ return ''.join(parts)
+
+
+def _IsTypeCheck(interface, node):
+ """Returns true if node represents a type-checking function."""
+ return node.GetName() == 'Is%s' % _GetShortName(interface, ['Dev', 'Private'])
+
+
+def _GetCreateFuncName(interface):
+ """Returns the creation function name for an interface."""
+ return 'Create%s' % _GetShortName(interface, ['Dev'])
+
+
+def _GetDefaultFailureValue(t):
+ """Returns the default failure value for a given type.
+
+ Returns None if no default failure value exists for the type.
+ """
+ values = {
+ 'PP_Bool': 'PP_FALSE',
+ 'PP_Resource': '0',
+ 'struct PP_Var': 'PP_MakeUndefined()',
+ 'int32_t': 'enter.retval()',
+ 'uint16_t': '0',
+ 'uint32_t': '0',
+ 'uint64_t': '0',
+ }
+ if t in values:
+ return values[t]
+ return None
+
+
+def _MakeCreateMemberBody(interface, member, args):
+ """Returns the body of a Create() function.
+
+ Args:
+ interface - IDLNode for the interface
+ member - IDLNode for member function
+ args - List of arguments for the Create() function
+ """
+ if args[0][0] == 'PP_Resource':
+ body = ' Resource* object =\n'
+ body += ' PpapiGlobals::Get()->GetResourceTracker()->'
+ body += 'GetResource(%s);\n' % args[0][1]
+ body += ' if (!object)\n'
+ body += ' return 0;\n'
+ body += ' EnterResourceCreation enter(object->pp_instance());\n'
+ elif args[0][0] == 'PP_Instance':
+ body = ' EnterResourceCreation enter(%s);\n' % args[0][1]
+ else:
+ raise TGenError('Unknown arg type for Create(): %s' % args[0][0])
+
+ body += ' if (enter.failed())\n'
+ body += ' return 0;\n'
+ arg_list = ', '.join([a[1] for a in args])
+ if member.GetProperty('create_func'):
+ create_func = member.GetProperty('create_func')
+ else:
+ create_func = _GetCreateFuncName(interface)
+ body += ' return enter.functions()->%s(%s);' % (create_func,
+ arg_list)
+ return body
+
+
+def _MakeNormalMemberBody(filenode, node, member, rtype, args):
+ """Returns the body of a typical function.
+
+ Args:
+ filenode - IDLNode for the file
+ node - IDLNode for the interface
+ member - IDLNode for the member function
+ rtype - Return type for the member function
+ args - List of 4-tuple arguments for the member function
+ """
+ is_callback_func = args[len(args) - 1][0] == 'struct PP_CompletionCallback'
+
+ if is_callback_func:
+ call_args = args[:-1] + [('', 'enter.callback()', '', '')]
+ else:
+ call_args = args
+
+ if args[0][0] == 'PP_Instance':
+ call_arglist = ', '.join(a[1] for a in call_args)
+ function_container = 'functions'
+ else:
+ call_arglist = ', '.join(a[1] for a in call_args[1:])
+ function_container = 'object'
+
+ invocation = 'enter.%s()->%s(%s)' % (function_container,
+ member.GetName(),
+ call_arglist)
+
+ handle_errors = not (member.GetProperty('report_errors') == 'False')
+ if is_callback_func:
+ body = ' %s\n' % _MakeEnterLine(filenode, node, args[0], handle_errors,
+ args[len(args) - 1][1])
+ body += ' if (enter.failed())\n'
+ value = member.GetProperty('on_failure')
+ if value is None:
+ value = 'enter.retval()'
+ body += ' return %s;\n' % value
+ body += ' return enter.SetResult(%s);\n' % invocation
+ elif rtype == 'void':
+ body = ' %s\n' % _MakeEnterLine(filenode, node, args[0], handle_errors,
+ None)
+ body += ' if (enter.succeeded())\n'
+ body += ' %s;' % invocation
+ else:
+ value = member.GetProperty('on_failure')
+ if value is None:
+ value = _GetDefaultFailureValue(rtype)
+ if value is None:
+ raise TGenError('No default value for rtype %s' % rtype)
+
+ body = ' %s\n' % _MakeEnterLine(filenode, node, args[0], handle_errors,
+ None)
+ body += ' if (enter.failed())\n'
+ body += ' return %s;\n' % value
+ body += ' return %s;' % invocation
+ return body
+
+
+def DefineMember(filenode, node, member, release, include_version):
+ """Returns a definition for a member function of an interface.
+
+ Args:
+ filenode - IDLNode for the file
+ node - IDLNode for the interface
+ member - IDLNode for the member function
+ release - release to generate
+ include_version - include the version in emitted function name.
+ Returns:
+ A string with the member definition.
+ """
+ cgen = CGen()
+ rtype, name, arrays, args = cgen.GetComponents(member, release, 'return')
+
+ if _IsTypeCheck(node, member):
+ body = ' %s\n' % _MakeEnterLine(filenode, node, args[0], False, None)
+ body += ' return PP_FromBool(enter.succeeded());'
+ elif member.GetName() == 'Create':
+ body = _MakeCreateMemberBody(node, member, args)
+ else:
+ body = _MakeNormalMemberBody(filenode, node, member, rtype, args)
+
+ signature = cgen.GetSignature(member, release, 'return', func_as_ptr=False,
+ include_version=include_version)
+ member_code = '%s {\n%s\n}' % (signature, body)
+ return cgen.Indent(member_code, tabs=0)
+
+
+class TGen(GeneratorByFile):
+ def __init__(self):
+ Generator.__init__(self, 'Thunk', 'tgen', 'Generate the C++ thunk.')
+
+ def GenerateFile(self, filenode, releases, options):
+ savename = _GetThunkFileName(filenode, GetOption('thunkroot'))
+ my_min, my_max = filenode.GetMinMax(releases)
+ if my_min > releases[-1] or my_max < releases[0]:
+ if os.path.isfile(savename):
+ print "Removing stale %s for this range." % filenode.GetName()
+ os.remove(os.path.realpath(savename))
+ return False
+ do_generate = filenode.GetProperty('generate_thunk')
+ if not do_generate:
+ return False
+
+ thunk_out = IDLOutFile(savename)
+ self.GenerateHead(thunk_out, filenode, releases, options)
+ self.GenerateBody(thunk_out, filenode, releases, options)
+ self.GenerateTail(thunk_out, filenode, releases, options)
+ return thunk_out.Close()
+
+ def GenerateHead(self, out, filenode, releases, options):
+ __pychecker__ = 'unusednames=options'
+ cgen = CGen()
+
+ cright_node = filenode.GetChildren()[0]
+ assert(cright_node.IsA('Copyright'))
+ out.Write('%s\n' % cgen.Copyright(cright_node, cpp_style=True))
+
+ # Wrap the From ... modified ... comment if it would be >80 characters.
+ from_text = 'From %s' % (
+ filenode.GetProperty('NAME').replace(os.sep,'/'))
+ modified_text = 'modified %s.' % (
+ filenode.GetProperty('DATETIME'))
+ if len(from_text) + len(modified_text) < 74:
+ out.Write('// %s %s\n\n' % (from_text, modified_text))
+ else:
+ out.Write('// %s,\n// %s\n\n' % (from_text, modified_text))
+
+
+ # TODO(teravest): Don't emit includes we don't need.
+ includes = ['ppapi/c/pp_errors.h',
+ 'ppapi/shared_impl/tracked_callback.h',
+ 'ppapi/thunk/enter.h',
+ 'ppapi/thunk/ppb_instance_api.h',
+ 'ppapi/thunk/resource_creation_api.h',
+ 'ppapi/thunk/thunk.h']
+ includes.append(_GetHeaderFileName(filenode))
+ includes.append('ppapi/thunk/%s_api.h' % _GetBaseFileName(filenode))
+ for include in sorted(includes):
+ out.Write('#include "%s"\n' % include)
+ out.Write('\n')
+ out.Write('namespace ppapi {\n')
+ out.Write('namespace thunk {\n')
+ out.Write('\n')
+ out.Write('namespace {\n')
+ out.Write('\n')
+
+ def GenerateBody(self, out, filenode, releases, options):
+ __pychecker__ = 'unusednames=options'
+ for node in filenode.GetListOf('Interface'):
+ # Skip if this node is not in this release
+ if not node.InReleases(releases):
+ print "Skipping %s" % node
+ continue
+
+ # Generate Member functions
+ if node.IsA('Interface'):
+ members = []
+ for child in node.GetListOf('Member'):
+ build_list = child.GetUniqueReleases(releases)
+ # We have to filter out releases this node isn't in.
+ build_list = filter(lambda r: child.InReleases([r]), build_list)
+ if len(build_list) == 0:
+ continue
+ release = build_list[-1] # Pick the newest release.
+ member = DefineMember(filenode, node, child, release, False)
+ if not member:
+ continue
+ members.append(member)
+ for build in build_list[:-1]:
+ member = DefineMember(filenode, node, child, build, True)
+ if not member:
+ continue
+ members.append(member)
+ out.Write('\n\n'.join(members))
+
+ def GenerateTail(self, out, filenode, releases, options):
+ __pychecker__ = 'unusednames=options'
+ cgen = CGen()
+
+ version_list = []
+ out.Write('\n\n')
+ for node in filenode.GetListOf('Interface'):
+ build_list = node.GetUniqueReleases(releases)
+ for build in build_list:
+ version = node.GetVersion(build).replace('.', '_')
+ thunk_name = 'g_' + node.GetName().lower() + '_thunk_' + \
+ version
+ thunk_type = '_'.join((node.GetName(), version))
+ version_list.append((thunk_type, thunk_name))
+
+ out.Write('const %s %s = {\n' % (thunk_type, thunk_name))
+ for child in node.GetListOf('Member'):
+ rtype, name, arrays, args = cgen.GetComponents(
+ child, build, 'return')
+ if child.InReleases([build]): # TEST
+ out.Write(' &%s,\n' % name)
+ out.Write('};\n\n')
+
+ out.Write('} // namespace\n')
+ out.Write('\n')
+ for thunk_type, thunk_name in version_list:
+ thunk_decl = 'const %s* Get%s_Thunk() {\n' % (thunk_type, thunk_type)
+ if len(thunk_decl) > 80:
+ thunk_decl = 'const %s*\n Get%s_Thunk() {\n' % (thunk_type,
+ thunk_type)
+ out.Write(thunk_decl)
+ out.Write(' return &%s;\n' % thunk_name)
+ out.Write('}\n')
+ out.Write('\n')
+ out.Write('} // namespace thunk\n')
+ out.Write('} // namespace ppapi\n')
+
+
+tgen = TGen()
+
+
+def Main(args):
+ # Default invocation will verify the golden files are unchanged.
+ failed = 0
+ if not args:
+ args = ['--wnone', '--diff', '--test', '--thunkroot=.']
+
+ ParseOptions(args)
+
+ idldir = os.path.split(sys.argv[0])[0]
+ idldir = os.path.join(idldir, 'test_thunk', '*.idl')
+ filenames = glob.glob(idldir)
+ ast = ParseFiles(filenames)
+ if tgen.GenerateRange(ast, ['M13', 'M14'], {}):
+ print "Golden file for M13-M14 failed."
+ failed = 1
+ else:
+ print "Golden file for M13-M14 passed."
+
+ return failed
+
+
+if __name__ == '__main__':
+ sys.exit(Main(sys.argv[1:]))
diff --git a/ppapi/generators/test_thunk/basic_test_types.idl b/ppapi/generators/test_thunk/basic_test_types.idl
new file mode 100644
index 0000000..0f42466
--- /dev/null
+++ b/ppapi/generators/test_thunk/basic_test_types.idl
@@ -0,0 +1,58 @@
+/* Copyright (c) 2011 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/**
+ * This file defines some basic types for use in testing.
+ */
+
+label Chrome {
+ M13 = 0.0,
+ M14 = 1.0,
+ M15 = 2.0
+};
+
+[version=0.0]
+describe {
+ /** Standard Ints. */
+ int8_t;
+ int16_t;
+ int32_t;
+ int64_t;
+ uint8_t;
+ uint16_t;
+ uint32_t;
+ uint64_t;
+ /** Small and large floats. */
+ double_t;
+ float_t;
+
+ /** Native file handle (int). */
+ handle_t;
+
+ /** Interface object (void *). */
+ interface_t;
+
+ /** Used for padding, should be (u)int8_t */
+ char;
+
+ /** Pointer to memory (void *). */
+ mem_t;
+
+ /** Pointer to null terminated string (char *). */
+ str_t;
+
+ /** No return value. */
+ void;
+
+ /** Pointer to pointer to memory (void **). */
+ blob_t;
+
+ /** Pepper types */
+ PP_Bool;
+ PP_Instance;
+ PP_Resource;
+ PP_Var;
+};
+
diff --git a/ppapi/generators/test_thunk/simple.idl b/ppapi/generators/test_thunk/simple.idl
new file mode 100644
index 0000000..30beace
--- /dev/null
+++ b/ppapi/generators/test_thunk/simple.idl
@@ -0,0 +1,34 @@
+/* Copyright (c) 2012 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+[generate_thunk]
+
+/**
+ * This file defines the <code>PPB_Simple</code> interface.
+ */
+
+label Chrome {
+ M13 = 0.5,
+ M14 = 1.0
+};
+
+interface PPB_Simple {
+ PP_Resource Create([in] PP_Instance instance);
+
+ PP_Bool IsSimple([in] PP_Resource resource);
+
+ [deprecate=1.0]
+ void PostMessage([in] PP_Instance instance, [in] PP_Var message);
+
+ uint32_t DoUint32Instance([in] PP_Instance instance);
+
+ uint32_t DoUint32Resource([in] PP_Resource instance);
+
+ [report_errors=False]
+ uint32_t DoUint32ResourceNoErrors([in] PP_Resource instance);
+
+ [version=1.0, on_failure="12"]
+ int32_t OnFailure12([in] PP_Instance instance);
+};
diff --git a/ppapi/generators/test_thunk/simple_thunk.cc b/ppapi/generators/test_thunk/simple_thunk.cc
new file mode 100644
index 0000000..e6418f0
--- /dev/null
+++ b/ppapi/generators/test_thunk/simple_thunk.cc
@@ -0,0 +1,96 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// From ../test_thunk/simple.idl modified Fri Nov 16 11:26:06 2012.
+
+#include "ppapi/c/../test_thunk/simple.h"
+#include "ppapi/c/pp_errors.h"
+#include "ppapi/shared_impl/tracked_callback.h"
+#include "ppapi/thunk/enter.h"
+#include "ppapi/thunk/ppb_instance_api.h"
+#include "ppapi/thunk/resource_creation_api.h"
+#include "ppapi/thunk/simple_api.h"
+#include "ppapi/thunk/thunk.h"
+
+namespace ppapi {
+namespace thunk {
+
+namespace {
+
+PP_Resource Create(PP_Instance instance) {
+ EnterResourceCreation enter(instance);
+ if (enter.failed())
+ return 0;
+ return enter.functions()->CreateSimple(instance);
+}
+
+PP_Bool IsSimple(PP_Resource resource) {
+ EnterResource<PPB_Simple_API> enter(resource, false);
+ return PP_FromBool(enter.succeeded());
+}
+
+void PostMessage(PP_Instance instance, PP_Var message) {
+ EnterInstance enter(instance);
+ if (enter.succeeded())
+ enter.functions()->PostMessage(instance, message);
+}
+
+uint32_t DoUint32Instance(PP_Instance instance) {
+ EnterInstance enter(instance);
+ if (enter.failed())
+ return 0;
+ return enter.functions()->DoUint32Instance(instance);
+}
+
+uint32_t DoUint32Resource(PP_Resource instance) {
+ EnterResource<PPB_Simple_API> enter(instance, true);
+ if (enter.failed())
+ return 0;
+ return enter.object()->DoUint32Resource();
+}
+
+uint32_t DoUint32ResourceNoErrors(PP_Resource instance) {
+ EnterResource<PPB_Simple_API> enter(instance, false);
+ if (enter.failed())
+ return 0;
+ return enter.object()->DoUint32ResourceNoErrors();
+}
+
+int32_t OnFailure12(PP_Instance instance) {
+ EnterInstance enter(instance);
+ if (enter.failed())
+ return 12;
+ return enter.functions()->OnFailure12(instance);
+}
+
+const PPB_Simple_0_5 g_ppb_simple_thunk_0_5 = {
+ &Create,
+ &IsSimple,
+ &PostMessage,
+ &DoUint32Instance,
+ &DoUint32Resource,
+ &DoUint32ResourceNoErrors,
+};
+
+const PPB_Simple_1_0 g_ppb_simple_thunk_1_0 = {
+ &Create,
+ &IsSimple,
+ &DoUint32Instance,
+ &DoUint32Resource,
+ &DoUint32ResourceNoErrors,
+ &OnFailure12,
+};
+
+} // namespace
+
+const PPB_Simple_0_5* GetPPB_Simple_0_5_Thunk() {
+ return &g_ppb_simple_thunk_0_5;
+}
+
+const PPB_Simple_1_0* GetPPB_Simple_1_0_Thunk() {
+ return &g_ppb_simple_thunk_1_0;
+}
+
+} // namespace thunk
+} // namespace ppapi