Make certificate viewer a tab-modal dialog.
[chromium-blink-merge.git] / ppapi / generators / idl_gen_wrapper.py
blob5dcafbf50d58f80af5b872fe5f72e494a886abf4
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.
6 """
8 from datetime import datetime
9 import os
10 import sys
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
19 class PPKind(object):
20 @staticmethod
21 def ChoosePPFunc(iface, ppb_func, ppp_func):
22 name = iface.node.GetName()
23 if name.startswith("PPP"):
24 return ppp_func
25 elif name.startswith("PPB"):
26 return ppb_func
27 else:
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.
38 """
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).
63 """
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
70 self.cgen = CGen()
72 def SetOutputFile(self, fname):
73 self.output_file = fname
76 def GenerateRelease(self, ast, release, options):
77 return self.GenerateRange(ast, [release], options)
80 @staticmethod
81 def GetHeaderName(name):
82 """Get the corresponding ppapi .h file from each IDL filename.
83 """
84 name = os.path.splitext(name)[0] + '.h'
85 name = name.replace(os.sep, '/')
86 return 'ppapi/c/' + name
89 def WriteCopyright(self, out):
90 now = datetime.now()
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 */
97 """ % now.year
98 out.Write(c)
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) {
109 while (1) {
110 if (*s1 == 0) break;
111 if (*s2 == 0) break;
112 if (*s1 != *s2) break;
113 ++s1;
114 ++s2;
116 return (int)(*s1) - (int)(*s2);
118 """)
121 def GenerateFixedFunctions(self, out):
122 """Write out the set of constant functions (those that do not depend on
123 the current Pepper IDL).
125 out.Write("""
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(
140 const char *name) {
141 struct %(wrapper_struct)s **next = s_ppb_wrappers;
142 while (*next != NULL) {
143 if (mystrcmp(name, (*next)->iface_macro) == 0) return *next;
144 ++next;
146 return NULL;
149 /* Map interface string -> wrapper metadata */
150 static struct %(wrapper_struct)s *%(wrapper_prefix)sPPPShimIface(
151 const char *name) {
152 struct %(wrapper_struct)s **next = s_ppp_wrappers;
153 while (*next != NULL) {
154 if (mystrcmp(name, (*next)->iface_macro) == 0) return *next;
155 ++next;
157 return NULL;
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;
176 } else {
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;
197 } else {
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.
211 return True
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.
225 iface_releases = []
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' %
231 filenode.GetName())
232 continue
234 file_name = self.GetHeaderName(filenode.GetName())
235 ifaces = filenode.GetListOf('Interface')
236 for iface in ifaces:
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)
243 if not needs_wrap:
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.
267 header_files = set()
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)
272 out.Write('\n')
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':
281 ret = 'return '
282 else:
283 ret = ''
284 if args_spec:
285 args = []
286 for arg in args_spec:
287 args.append(arg[1])
288 args = ', '.join(args)
289 else:
290 args = ''
291 return (ret, args)
294 def GenerateWrapperForPPBMethod(self, iface, member):
295 result = []
296 func_prefix = self.WrapperMethodPrefix(iface.node, iface.release)
297 sig = self.cgen.GetSignature(member, iface.release, 'store',
298 func_prefix, False)
299 result.append('static %s {\n' % sig)
300 result.append(' while(1) { /* Not implemented */ } \n')
301 result.append('}\n')
302 return result
305 def GenerateWrapperForPPPMethod(self, iface, member):
306 result = []
307 func_prefix = self.WrapperMethodPrefix(iface.node, iface.release)
308 sig = self.cgen.GetSignature(member, iface.release, 'store',
309 func_prefix, False)
310 result.append('static %s {\n' % sig)
311 result.append(' while(1) { /* Not implemented */ } \n')
312 result.append('}\n')
313 return result
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.)
320 result = []
321 for iface in iface_releases:
322 if not iface.needs_wrapping:
323 if comments:
324 result.append('/* Not generating wrapper methods for %s */\n\n' %
325 iface.struct_name)
326 continue
327 if comments:
328 result.append('/* Begin wrapper methods for %s */\n\n' %
329 iface.struct_name)
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]):
336 continue
337 result.extend(generator(iface, member))
338 if comments:
339 result.append('/* End wrapper methods for %s */\n\n' %
340 iface.struct_name)
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' %
348 iface.struct_name)
349 continue
351 out.Write('struct %s %s_Wrappers_%s = {\n' % (iface.struct_name,
352 self.wrapper_prefix,
353 iface.struct_name))
354 methods = []
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]):
358 continue
359 prefix = self.WrapperMethodPrefix(iface.node, iface.release)
360 cast = self.cgen.GetSignature(member, iface.release, 'return',
361 prefix='',
362 func_as_ptr=True,
363 ptr_prefix='',
364 include_name=False)
365 methods.append(' .%s = (%s)&%s%s' % (member.GetName(),
366 cast,
367 prefix,
368 member.GetName()))
369 out.Write(' ' + ',\n '.join(methods) + '\n')
370 out.Write('};\n\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,
382 iface.struct_name)
383 else:
384 wrap_iface = 'NULL /* Still need slot for real_iface */'
385 out.Write("""static struct %s %s = {
386 .iface_macro = %s,
387 .wrapped_iface = %s,
388 .real_iface = NULL
389 };\n\n""" % (self.GetWrapperMetadataName(),
390 self.GetWrapperInfoName(iface),
391 iface_macro,
392 wrap_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')
404 out.Write(
405 'static struct %s *s_ppb_wrappers[] = {\n%s\n};\n\n' %
406 (self.GetWrapperMetadataName(), ',\n'.join(ppb_wrapper_infos)))
407 out.Write(
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')
431 return 1
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)
454 out.Write(result)
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())
466 out.Close()
467 return 0