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_outfile
import IDLOutFile
20 def ChoosePPFunc(iface
, ppb_func
, ppp_func
):
21 name
= iface
.node
.GetName()
22 if name
.startswith("PPP"):
24 elif name
.startswith("PPB"):
27 raise Exception('Unknown PPKind for ' + name
)
30 class Interface(object):
31 """Tracks information about a particular interface version.
33 - struct_name: the struct type used by the ppapi headers to hold the
34 method pointers (the vtable).
35 - needs_wrapping: True if a method in the interface needs wrapping.
36 - header_file: the name of the header file that defined this interface.
38 def __init__(self
, interface_node
, release
, version
,
39 struct_name
, needs_wrapping
, header_file
):
40 self
.node
= interface_node
41 self
.release
= release
42 self
.version
= version
43 self
.struct_name
= struct_name
44 # We may want finer grained filtering (method level), but it is not
45 # yet clear how to actually do that.
46 self
.needs_wrapping
= needs_wrapping
47 self
.header_file
= header_file
50 class WrapperGen(Generator
):
51 """WrapperGen - An abstract class that generates wrappers for PPAPI methods.
53 This generates a wrapper PPB and PPP GetInterface, which directs users
54 to wrapper PPAPI methods. Wrapper PPAPI methods may perform arbitrary
55 work before invoking the real PPAPI method (supplied by the original
56 GetInterface functions).
58 Subclasses must implement GenerateWrapperForPPBMethod (and PPP).
59 Optionally, subclasses can implement InterfaceNeedsWrapper to
60 filter out interfaces that do not actually need wrappers (those
61 interfaces can jump directly to the original interface functions).
64 def __init__(self
, wrapper_prefix
, s1
, s2
, s3
):
65 Generator
.__init
__(self
, s1
, s2
, s3
)
66 self
.wrapper_prefix
= wrapper_prefix
67 self
._skip
_opt
= False
68 self
.output_file
= None
71 def SetOutputFile(self
, fname
):
72 self
.output_file
= fname
75 def GenerateRelease(self
, ast
, release
, options
):
76 return self
.GenerateRange(ast
, [release
], options
)
80 def GetHeaderName(name
):
81 """Get the corresponding ppapi .h file from each IDL filename.
83 name
= os
.path
.splitext(name
)[0] + '.h'
84 name
= name
.replace(os
.sep
, '/')
85 return 'ppapi/c/' + name
88 def WriteCopyrightGeneratedTime(self
, out
):
90 c
= """/* Copyright (c) %s The Chromium Authors. All rights reserved.
91 * Use of this source code is governed by a BSD-style license that can be
92 * found in the LICENSE file.
95 /* Last generated from IDL: %s. */
96 """ % (now
.year
, datetime
.ctime(now
))
99 def GetWrapperMetadataName(self
):
100 return '__%sWrapperInfo' % self
.wrapper_prefix
103 def GenerateHelperFunctions(self
, out
):
104 """Generate helper functions to avoid dependencies on libc.
106 out
.Write("""/* Use local strcmp to avoid dependency on libc. */
107 static int mystrcmp(const char* s1, const char *s2) {
108 while((*s1 && *s2) && (*s1++ == *s2++));
109 return *(--s1) - *(--s2);
114 def GenerateFixedFunctions(self
, out
):
115 """Write out the set of constant functions (those that do not depend on
116 the current Pepper IDL).
120 static PPB_GetInterface __real_PPBGetInterface;
121 static PPP_GetInterface_Type __real_PPPGetInterface;
123 void __set_real_%(wrapper_prefix)s_PPBGetInterface(PPB_GetInterface real) {
124 __real_PPBGetInterface = real;
127 void __set_real_%(wrapper_prefix)s_PPPGetInterface(PPP_GetInterface_Type real) {
128 __real_PPPGetInterface = real;
131 /* Map interface string -> wrapper metadata */
132 static struct %(wrapper_struct)s *%(wrapper_prefix)sPPBShimIface(
134 struct %(wrapper_struct)s **next = s_ppb_wrappers;
135 while (*next != NULL) {
136 if (mystrcmp(name, (*next)->iface_macro) == 0) return *next;
142 /* Map interface string -> wrapper metadata */
143 static struct %(wrapper_struct)s *%(wrapper_prefix)sPPPShimIface(
145 struct %(wrapper_struct)s **next = s_ppp_wrappers;
146 while (*next != NULL) {
147 if (mystrcmp(name, (*next)->iface_macro) == 0) return *next;
153 const void *__%(wrapper_prefix)s_PPBGetInterface(const char *name) {
154 struct %(wrapper_struct)s *wrapper = %(wrapper_prefix)sPPBShimIface(name);
155 if (wrapper == NULL) {
156 /* We don't have an IDL for this, for some reason. Take our chances. */
157 return (*__real_PPBGetInterface)(name);
160 /* Initialize the real_iface if it hasn't been. The wrapper depends on it. */
161 if (wrapper->real_iface == NULL) {
162 const void *iface = (*__real_PPBGetInterface)(name);
163 if (NULL == iface) return NULL;
164 wrapper->real_iface = iface;
167 if (wrapper->wrapped_iface) {
168 return wrapper->wrapped_iface;
170 return wrapper->real_iface;
174 const void *__%(wrapper_prefix)s_PPPGetInterface(const char *name) {
175 struct %(wrapper_struct)s *wrapper = %(wrapper_prefix)sPPPShimIface(name);
176 if (wrapper == NULL) {
177 /* We don't have an IDL for this, for some reason. Take our chances. */
178 return (*__real_PPPGetInterface)(name);
181 /* Initialize the real_iface if it hasn't been. The wrapper depends on it. */
182 if (wrapper->real_iface == NULL) {
183 const void *iface = (*__real_PPPGetInterface)(name);
184 if (NULL == iface) return NULL;
185 wrapper->real_iface = iface;
188 if (wrapper->wrapped_iface) {
189 return wrapper->wrapped_iface;
191 return wrapper->real_iface;
194 """ % { 'wrapper_struct' : self
.GetWrapperMetadataName(),
195 'wrapper_prefix' : self
.wrapper_prefix
,
199 ############################################################
201 def InterfaceNeedsWrapper(self
, iface
, releases
):
202 """Return true if the interface has ANY methods that need wrapping.
207 def OwnHeaderFile(self
):
208 """Return the header file that specifies the API of this wrapper.
209 We do not generate the header files. """
210 raise Exception('Child class must implement this')
213 ############################################################
215 def DetermineInterfaces(self
, ast
, releases
):
216 """Get a list of interfaces along with whatever metadata we need.
219 for filenode
in ast
.GetListOf('File'):
220 # If this file has errors, skip it
221 if filenode
in self
.skip_list
:
222 InfoOut
.Log('WrapperGen: Skipping %s due to errors\n' %
226 file_name
= self
.GetHeaderName(filenode
.GetName())
227 ifaces
= filenode
.GetListOf('Interface')
229 releases_for_iface
= iface
.GetUniqueReleases(releases
)
230 for release
in releases_for_iface
:
231 version
= iface
.GetVersion(release
)
232 struct_name
= self
.cgen
.GetStructName(iface
, release
,
233 include_version
=True)
234 needs_wrap
= self
.InterfaceVersionNeedsWrapping(iface
, version
)
236 InfoOut
.Log('Interface %s ver %s does not need wrapping' %
237 (struct_name
, version
))
238 iface_releases
.append(
239 Interface(iface
, release
, version
,
240 struct_name
, needs_wrap
, file_name
))
241 return iface_releases
244 def GenerateIncludes(self
, iface_releases
, out
):
245 """Generate the list of #include that define the original interfaces.
247 self
.WriteCopyrightGeneratedTime(out
)
248 # First include own header.
249 out
.Write('#include "%s"\n\n' % self
.OwnHeaderFile())
251 # Get typedefs for PPB_GetInterface.
252 out
.Write('#include "%s"\n' % self
.GetHeaderName('ppb.h'))
254 # Get a conservative list of all #includes that are needed,
255 # whether it requires wrapping or not. We currently depend on the macro
256 # string for comparison, even when it is not wrapped, to decide when
257 # to use the original/real interface.
259 for iface
in iface_releases
:
260 header_files
.add(iface
.header_file
)
261 for header
in sorted(header_files
):
262 out
.Write('#include "%s"\n' % header
)
266 def WrapperMethodPrefix(self
, iface
, release
):
267 return '%s_%s_%s_' % (self
.wrapper_prefix
, release
, iface
.GetName())
270 def GetReturnArgs(self
, ret_type
, args_spec
):
271 if ret_type
!= 'void':
277 for arg
in args_spec
:
279 args
= ', '.join(args
)
285 def GenerateWrapperForPPBMethod(self
, iface
, member
):
287 func_prefix
= self
.WrapperMethodPrefix(iface
.node
, iface
.release
)
288 sig
= self
.cgen
.GetSignature(member
, iface
.release
, 'store',
290 result
.append('static %s {\n' % sig
)
291 result
.append(' while(1) { /* Not implemented */ } \n')
296 def GenerateWrapperForPPPMethod(self
, iface
, member
):
298 func_prefix
= self
.WrapperMethodPrefix(iface
.node
, iface
.release
)
299 sig
= self
.cgen
.GetSignature(member
, iface
.release
, 'store',
301 result
.append('static %s {\n' % sig
)
302 result
.append(' while(1) { /* Not implemented */ } \n')
307 def GenerateWrapperForMethods(self
, iface_releases
, comments
=True):
308 """Return a string representing the code for each wrapper method
309 (using a string rather than writing to the file directly for testing.)
312 for iface
in iface_releases
:
313 if not iface
.needs_wrapping
:
315 result
.append('/* Not generating wrapper methods for %s */\n\n' %
319 result
.append('/* Begin wrapper methods for %s */\n\n' %
321 generator
= PPKind
.ChoosePPFunc(iface
,
322 self
.GenerateWrapperForPPBMethod
,
323 self
.GenerateWrapperForPPPMethod
)
324 for member
in iface
.node
.GetListOf('Member'):
325 # Skip the method if it's not actually in the release.
326 if not member
.InReleases([iface
.release
]):
328 result
.extend(generator(iface
, member
))
330 result
.append('/* End wrapper methods for %s */\n\n' %
332 return ''.join(result
)
335 def GenerateWrapperInterfaces(self
, iface_releases
, out
):
336 for iface
in iface_releases
:
337 if not iface
.needs_wrapping
:
338 out
.Write('/* Not generating wrapper interface for %s */\n\n' %
342 out
.Write('struct %s %s_Wrappers_%s = {\n' % (iface
.struct_name
,
346 for member
in iface
.node
.GetListOf('Member'):
347 # Skip the method if it's not actually in the release.
348 if not member
.InReleases([iface
.release
]):
350 prefix
= self
.WrapperMethodPrefix(iface
.node
, iface
.release
)
351 cast
= self
.cgen
.GetSignature(member
, iface
.release
, 'return',
356 methods
.append(' .%s = (%s)&%s%s' % (member
.GetName(),
360 out
.Write(' ' + ',\n '.join(methods
) + '\n')
364 def GetWrapperInfoName(self
, iface
):
365 return '%s_WrapperInfo_%s' % (self
.wrapper_prefix
, iface
.struct_name
)
368 def GenerateWrapperInfoAndCollection(self
, iface_releases
, out
):
369 for iface
in iface_releases
:
370 iface_macro
= self
.cgen
.GetInterfaceMacro(iface
.node
, iface
.version
)
371 if iface
.needs_wrapping
:
372 wrap_iface
= '(void *) &%s_Wrappers_%s' % (self
.wrapper_prefix
,
375 wrap_iface
= 'NULL /* Still need slot for real_iface */'
376 out
.Write("""static struct %s %s = {
380 };\n\n""" % (self
.GetWrapperMetadataName(),
381 self
.GetWrapperInfoName(iface
),
385 # Now generate NULL terminated arrays of the above wrapper infos.
386 ppb_wrapper_infos
= []
387 ppp_wrapper_infos
= []
388 for iface
in iface_releases
:
389 appender
= PPKind
.ChoosePPFunc(iface
,
390 ppb_wrapper_infos
.append
,
391 ppp_wrapper_infos
.append
)
392 appender(' &%s' % self
.GetWrapperInfoName(iface
))
393 ppb_wrapper_infos
.append(' NULL')
394 ppp_wrapper_infos
.append(' NULL')
396 'static struct %s *s_ppb_wrappers[] = {\n%s\n};\n\n' %
397 (self
.GetWrapperMetadataName(), ',\n'.join(ppb_wrapper_infos
)))
399 'static struct %s *s_ppp_wrappers[] = {\n%s\n};\n\n' %
400 (self
.GetWrapperMetadataName(), ',\n'.join(ppp_wrapper_infos
)))
403 def DeclareWrapperInfos(self
, iface_releases
, out
):
404 """The wrapper methods usually need access to the real_iface, so we must
405 declare these wrapper infos ahead of time (there is a circular dependency).
407 out
.Write('/* BEGIN Declarations for all Wrapper Infos */\n\n')
408 for iface
in iface_releases
:
409 out
.Write('static struct %s %s;\n' %
410 (self
.GetWrapperMetadataName(), self
.GetWrapperInfoName(iface
)))
411 out
.Write('/* END Declarations for all Wrapper Infos. */\n\n')
414 def GenerateRange(self
, ast
, releases
, options
):
415 """Generate shim code for a range of releases.
418 # Remember to set the output filename before running this.
419 out_filename
= self
.output_file
420 if out_filename
is None:
421 ErrOut
.Log('Did not set filename for writing out wrapper\n')
424 InfoOut
.Log("Generating %s for %s" % (out_filename
, self
.wrapper_prefix
))
426 out
= IDLOutFile(out_filename
)
428 # Get a list of all the interfaces along with metadata.
429 iface_releases
= self
.DetermineInterfaces(ast
, releases
)
431 # Generate the includes.
432 self
.GenerateIncludes(iface_releases
, out
)
434 out
.Write(self
.GetGuardStart())
436 # Write out static helper functions (mystrcmp).
437 self
.GenerateHelperFunctions(out
)
439 # Declare list of WrapperInfo before actual wrapper methods, since
440 # they reference each other.
441 self
.DeclareWrapperInfos(iface_releases
, out
)
443 # Generate wrapper functions for each wrapped method in the interfaces.
444 result
= self
.GenerateWrapperForMethods(iface_releases
)
447 # Collect all the wrapper functions into interface structs.
448 self
.GenerateWrapperInterfaces(iface_releases
, out
)
450 # Generate a table of the wrapped interface structs that can be looked up.
451 self
.GenerateWrapperInfoAndCollection(iface_releases
, out
)
453 # Write out the IDL-invariant functions.
454 self
.GenerateFixedFunctions(out
)
456 out
.Write(self
.GetGuardEnd())