1 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
5 """Base class for generating wrapper functions for PPAPI methods.
8 from datetime
import datetime
12 from idl_c_proto
import CGen
13 from idl_generator
import Generator
14 from idl_log
import ErrOut
, InfoOut
, WarnOut
15 from idl_option
import GetOption
16 from idl_outfile
import IDLOutFile
21 def ChoosePPFunc(iface
, ppb_func
, ppp_func
):
22 name
= iface
.node
.GetName()
23 if name
.startswith("PPP"):
25 elif name
.startswith("PPB"):
28 raise Exception('Unknown PPKind for ' + name
)
31 class Interface(object):
32 """Tracks information about a particular interface version.
34 - struct_name: the struct type used by the ppapi headers to hold the
35 method pointers (the vtable).
36 - needs_wrapping: True if a method in the interface needs wrapping.
37 - header_file: the name of the header file that defined this interface.
39 def __init__(self
, interface_node
, release
, version
,
40 struct_name
, needs_wrapping
, header_file
):
41 self
.node
= interface_node
42 self
.release
= release
43 self
.version
= version
44 self
.struct_name
= struct_name
45 # We may want finer grained filtering (method level), but it is not
46 # yet clear how to actually do that.
47 self
.needs_wrapping
= needs_wrapping
48 self
.header_file
= header_file
51 class WrapperGen(Generator
):
52 """WrapperGen - An abstract class that generates wrappers for PPAPI methods.
54 This generates a wrapper PPB and PPP GetInterface, which directs users
55 to wrapper PPAPI methods. Wrapper PPAPI methods may perform arbitrary
56 work before invoking the real PPAPI method (supplied by the original
57 GetInterface functions).
59 Subclasses must implement GenerateWrapperForPPBMethod (and PPP).
60 Optionally, subclasses can implement InterfaceNeedsWrapper to
61 filter out interfaces that do not actually need wrappers (those
62 interfaces can jump directly to the original interface functions).
65 def __init__(self
, wrapper_prefix
, s1
, s2
, s3
):
66 Generator
.__init
__(self
, s1
, s2
, s3
)
67 self
.wrapper_prefix
= wrapper_prefix
68 self
._skip
_opt
= False
69 self
.output_file
= None
72 def SetOutputFile(self
, fname
):
73 self
.output_file
= fname
76 def GenerateRelease(self
, ast
, release
, options
):
77 return self
.GenerateRange(ast
, [release
], options
)
81 def GetHeaderName(name
):
82 """Get the corresponding ppapi .h file from each IDL filename.
84 name
= os
.path
.splitext(name
)[0] + '.h'
85 name
= name
.replace(os
.sep
, '/')
86 return 'ppapi/c/' + name
89 def WriteCopyright(self
, out
):
91 c
= """/* Copyright (c) %s The Chromium Authors. All rights reserved.
92 * Use of this source code is governed by a BSD-style license that can be
93 * found in the LICENSE file.
96 /* NOTE: this is auto-generated from IDL */
100 def GetWrapperMetadataName(self
):
101 return '__%sWrapperInfo' % self
.wrapper_prefix
104 def GenerateHelperFunctions(self
, out
):
105 """Generate helper functions to avoid dependencies on libc.
107 out
.Write("""/* Use local strcmp to avoid dependency on libc. */
108 static int mystrcmp(const char* s1, const char *s2) {
112 if (*s1 != *s2) break;
116 return (int)(*s1) - (int)(*s2);
121 def GenerateFixedFunctions(self
, out
):
122 """Write out the set of constant functions (those that do not depend on
123 the current Pepper IDL).
127 static PPB_GetInterface __real_PPBGetInterface;
128 static PPP_GetInterface_Type __real_PPPGetInterface;
130 void __set_real_%(wrapper_prefix)s_PPBGetInterface(PPB_GetInterface real) {
131 __real_PPBGetInterface = real;
134 void __set_real_%(wrapper_prefix)s_PPPGetInterface(PPP_GetInterface_Type real) {
135 __real_PPPGetInterface = real;
138 /* Map interface string -> wrapper metadata */
139 static struct %(wrapper_struct)s *%(wrapper_prefix)sPPBShimIface(
141 struct %(wrapper_struct)s **next = s_ppb_wrappers;
142 while (*next != NULL) {
143 if (mystrcmp(name, (*next)->iface_macro) == 0) return *next;
149 /* Map interface string -> wrapper metadata */
150 static struct %(wrapper_struct)s *%(wrapper_prefix)sPPPShimIface(
152 struct %(wrapper_struct)s **next = s_ppp_wrappers;
153 while (*next != NULL) {
154 if (mystrcmp(name, (*next)->iface_macro) == 0) return *next;
160 const void *__%(wrapper_prefix)s_PPBGetInterface(const char *name) {
161 struct %(wrapper_struct)s *wrapper = %(wrapper_prefix)sPPBShimIface(name);
162 if (wrapper == NULL) {
163 /* We don't have an IDL for this, for some reason. Take our chances. */
164 return (*__real_PPBGetInterface)(name);
167 /* Initialize the real_iface if it hasn't been. The wrapper depends on it. */
168 if (wrapper->real_iface == NULL) {
169 const void *iface = (*__real_PPBGetInterface)(name);
170 if (NULL == iface) return NULL;
171 wrapper->real_iface = iface;
174 if (wrapper->wrapped_iface) {
175 return wrapper->wrapped_iface;
177 return wrapper->real_iface;
181 const void *__%(wrapper_prefix)s_PPPGetInterface(const char *name) {
182 struct %(wrapper_struct)s *wrapper = %(wrapper_prefix)sPPPShimIface(name);
183 if (wrapper == NULL) {
184 /* We don't have an IDL for this, for some reason. Take our chances. */
185 return (*__real_PPPGetInterface)(name);
188 /* Initialize the real_iface if it hasn't been. The wrapper depends on it. */
189 if (wrapper->real_iface == NULL) {
190 const void *iface = (*__real_PPPGetInterface)(name);
191 if (NULL == iface) return NULL;
192 wrapper->real_iface = iface;
195 if (wrapper->wrapped_iface) {
196 return wrapper->wrapped_iface;
198 return wrapper->real_iface;
201 """ % { 'wrapper_struct' : self
.GetWrapperMetadataName(),
202 'wrapper_prefix' : self
.wrapper_prefix
,
206 ############################################################
208 def InterfaceNeedsWrapper(self
, iface
, releases
):
209 """Return true if the interface has ANY methods that need wrapping.
214 def OwnHeaderFile(self
):
215 """Return the header file that specifies the API of this wrapper.
216 We do not generate the header files. """
217 raise Exception('Child class must implement this')
220 ############################################################
222 def DetermineInterfaces(self
, ast
, releases
):
223 """Get a list of interfaces along with whatever metadata we need.
226 for filenode
in ast
.GetListOf('File'):
227 # If this file has errors, skip it
228 if filenode
in self
.skip_list
:
229 if GetOption('verbose'):
230 InfoOut
.Log('WrapperGen: Skipping %s due to errors\n' %
234 file_name
= self
.GetHeaderName(filenode
.GetName())
235 ifaces
= filenode
.GetListOf('Interface')
237 releases_for_iface
= iface
.GetUniqueReleases(releases
)
238 for release
in releases_for_iface
:
239 version
= iface
.GetVersion(release
)
240 struct_name
= self
.cgen
.GetStructName(iface
, release
,
241 include_version
=True)
242 needs_wrap
= self
.InterfaceVersionNeedsWrapping(iface
, version
)
244 if GetOption('verbose'):
245 InfoOut
.Log('Interface %s ver %s does not need wrapping' %
246 (struct_name
, version
))
247 iface_releases
.append(
248 Interface(iface
, release
, version
,
249 struct_name
, needs_wrap
, file_name
))
250 return iface_releases
253 def GenerateIncludes(self
, iface_releases
, out
):
254 """Generate the list of #include that define the original interfaces.
256 self
.WriteCopyright(out
)
257 # First include own header.
258 out
.Write('#include "%s"\n\n' % self
.OwnHeaderFile())
260 # Get typedefs for PPB_GetInterface.
261 out
.Write('#include "%s"\n' % self
.GetHeaderName('ppb.h'))
263 # Get a conservative list of all #includes that are needed,
264 # whether it requires wrapping or not. We currently depend on the macro
265 # string for comparison, even when it is not wrapped, to decide when
266 # to use the original/real interface.
268 for iface
in iface_releases
:
269 header_files
.add(iface
.header_file
)
270 for header
in sorted(header_files
):
271 out
.Write('#include "%s"\n' % header
)
275 def WrapperMethodPrefix(self
, iface
, release
):
276 return '%s_%s_%s_' % (self
.wrapper_prefix
, release
, iface
.GetName())
279 def GetReturnArgs(self
, ret_type
, args_spec
):
280 if ret_type
!= 'void':
286 for arg
in args_spec
:
288 args
= ', '.join(args
)
294 def GenerateWrapperForPPBMethod(self
, iface
, member
):
296 func_prefix
= self
.WrapperMethodPrefix(iface
.node
, iface
.release
)
297 sig
= self
.cgen
.GetSignature(member
, iface
.release
, 'store',
299 result
.append('static %s {\n' % sig
)
300 result
.append(' while(1) { /* Not implemented */ } \n')
305 def GenerateWrapperForPPPMethod(self
, iface
, member
):
307 func_prefix
= self
.WrapperMethodPrefix(iface
.node
, iface
.release
)
308 sig
= self
.cgen
.GetSignature(member
, iface
.release
, 'store',
310 result
.append('static %s {\n' % sig
)
311 result
.append(' while(1) { /* Not implemented */ } \n')
316 def GenerateWrapperForMethods(self
, iface_releases
, comments
=True):
317 """Return a string representing the code for each wrapper method
318 (using a string rather than writing to the file directly for testing.)
321 for iface
in iface_releases
:
322 if not iface
.needs_wrapping
:
324 result
.append('/* Not generating wrapper methods for %s */\n\n' %
328 result
.append('/* Begin wrapper methods for %s */\n\n' %
330 generator
= PPKind
.ChoosePPFunc(iface
,
331 self
.GenerateWrapperForPPBMethod
,
332 self
.GenerateWrapperForPPPMethod
)
333 for member
in iface
.node
.GetListOf('Member'):
334 # Skip the method if it's not actually in the release.
335 if not member
.InReleases([iface
.release
]):
337 result
.extend(generator(iface
, member
))
339 result
.append('/* End wrapper methods for %s */\n\n' %
341 return ''.join(result
)
344 def GenerateWrapperInterfaces(self
, iface_releases
, out
):
345 for iface
in iface_releases
:
346 if not iface
.needs_wrapping
:
347 out
.Write('/* Not generating wrapper interface for %s */\n\n' %
351 out
.Write('struct %s %s_Wrappers_%s = {\n' % (iface
.struct_name
,
355 for member
in iface
.node
.GetListOf('Member'):
356 # Skip the method if it's not actually in the release.
357 if not member
.InReleases([iface
.release
]):
359 prefix
= self
.WrapperMethodPrefix(iface
.node
, iface
.release
)
360 cast
= self
.cgen
.GetSignature(member
, iface
.release
, 'return',
365 methods
.append(' .%s = (%s)&%s%s' % (member
.GetName(),
369 out
.Write(' ' + ',\n '.join(methods
) + '\n')
373 def GetWrapperInfoName(self
, iface
):
374 return '%s_WrapperInfo_%s' % (self
.wrapper_prefix
, iface
.struct_name
)
377 def GenerateWrapperInfoAndCollection(self
, iface_releases
, out
):
378 for iface
in iface_releases
:
379 iface_macro
= self
.cgen
.GetInterfaceMacro(iface
.node
, iface
.version
)
380 if iface
.needs_wrapping
:
381 wrap_iface
= '(void *) &%s_Wrappers_%s' % (self
.wrapper_prefix
,
384 wrap_iface
= 'NULL /* Still need slot for real_iface */'
385 out
.Write("""static struct %s %s = {
389 };\n\n""" % (self
.GetWrapperMetadataName(),
390 self
.GetWrapperInfoName(iface
),
394 # Now generate NULL terminated arrays of the above wrapper infos.
395 ppb_wrapper_infos
= []
396 ppp_wrapper_infos
= []
397 for iface
in iface_releases
:
398 appender
= PPKind
.ChoosePPFunc(iface
,
399 ppb_wrapper_infos
.append
,
400 ppp_wrapper_infos
.append
)
401 appender(' &%s' % self
.GetWrapperInfoName(iface
))
402 ppb_wrapper_infos
.append(' NULL')
403 ppp_wrapper_infos
.append(' NULL')
405 'static struct %s *s_ppb_wrappers[] = {\n%s\n};\n\n' %
406 (self
.GetWrapperMetadataName(), ',\n'.join(ppb_wrapper_infos
)))
408 'static struct %s *s_ppp_wrappers[] = {\n%s\n};\n\n' %
409 (self
.GetWrapperMetadataName(), ',\n'.join(ppp_wrapper_infos
)))
412 def DeclareWrapperInfos(self
, iface_releases
, out
):
413 """The wrapper methods usually need access to the real_iface, so we must
414 declare these wrapper infos ahead of time (there is a circular dependency).
416 out
.Write('/* BEGIN Declarations for all Wrapper Infos */\n\n')
417 for iface
in iface_releases
:
418 out
.Write('static struct %s %s;\n' %
419 (self
.GetWrapperMetadataName(), self
.GetWrapperInfoName(iface
)))
420 out
.Write('/* END Declarations for all Wrapper Infos. */\n\n')
423 def GenerateRange(self
, ast
, releases
, options
):
424 """Generate shim code for a range of releases.
427 # Remember to set the output filename before running this.
428 out_filename
= self
.output_file
429 if out_filename
is None:
430 ErrOut
.Log('Did not set filename for writing out wrapper\n')
433 InfoOut
.Log("Generating %s for %s" % (out_filename
, self
.wrapper_prefix
))
435 out
= IDLOutFile(out_filename
)
437 # Get a list of all the interfaces along with metadata.
438 iface_releases
= self
.DetermineInterfaces(ast
, releases
)
440 # Generate the includes.
441 self
.GenerateIncludes(iface_releases
, out
)
443 out
.Write(self
.GetGuardStart())
445 # Write out static helper functions (mystrcmp).
446 self
.GenerateHelperFunctions(out
)
448 # Declare list of WrapperInfo before actual wrapper methods, since
449 # they reference each other.
450 self
.DeclareWrapperInfos(iface_releases
, out
)
452 # Generate wrapper functions for each wrapped method in the interfaces.
453 result
= self
.GenerateWrapperForMethods(iface_releases
)
456 # Collect all the wrapper functions into interface structs.
457 self
.GenerateWrapperInterfaces(iface_releases
, out
)
459 # Generate a table of the wrapped interface structs that can be looked up.
460 self
.GenerateWrapperInfoAndCollection(iface_releases
, out
)
462 # Write out the IDL-invariant functions.
463 self
.GenerateFixedFunctions(out
)
465 out
.Write(self
.GetGuardEnd())