|
1 #!/usr/bin/env python |
|
2 # header.py - Generate C++ header files from IDL. |
|
3 # |
|
4 # This Source Code Form is subject to the terms of the Mozilla Public |
|
5 # License, v. 2.0. If a copy of the MPL was not distributed with this |
|
6 # file, You can obtain one at http://mozilla.org/MPL/2.0/. |
|
7 |
|
8 import sys, os, xpidl, makeutils |
|
9 |
|
10 def strip_end(text, suffix): |
|
11 if not text.endswith(suffix): |
|
12 return text |
|
13 return text[:-len(suffix)] |
|
14 |
|
15 def findIDL(includePath, interfaceFileName): |
|
16 for d in includePath: |
|
17 # Not os.path.join: we need a forward slash even on Windows because |
|
18 # this filename ends up in makedepend output. |
|
19 path = d + '/' + interfaceFileName |
|
20 if os.path.exists(path): |
|
21 return path |
|
22 raise BaseException("No IDL file found for interface %s " |
|
23 "in include path %r" |
|
24 % (interfaceFileName, includePath)) |
|
25 |
|
26 eventFileNameToIdl = {}; |
|
27 |
|
28 def loadIDL(parser, includePath, filename): |
|
29 global eventFileNameToIdl |
|
30 if filename in eventFileNameToIdl: |
|
31 return eventFileNameToIdl[filename] |
|
32 |
|
33 idlFile = findIDL(includePath, filename) |
|
34 if not idlFile in makeutils.dependencies: |
|
35 makeutils.dependencies.append(idlFile) |
|
36 idl = p.parse(open(idlFile).read(), idlFile) |
|
37 idl.resolve(includePath, p) |
|
38 eventFileNameToIdl[filename] = idl |
|
39 return idl |
|
40 |
|
41 def loadEventIDL(parser, includePath, eventname): |
|
42 eventidl = ("nsIDOM%s.idl" % eventname) |
|
43 return loadIDL(parser, includePath, eventidl) |
|
44 |
|
45 class Configuration: |
|
46 def __init__(self, filename): |
|
47 config = {} |
|
48 execfile(filename, config) |
|
49 self.simple_events = config.get('simple_events', []) |
|
50 self.special_includes = config.get('special_includes', []) |
|
51 self.exclude_automatic_type_include = config.get('exclude_automatic_type_include', []) |
|
52 self.xpidl_to_native = config.get('xpidl_to_native', []) |
|
53 |
|
54 def readConfigFile(filename): |
|
55 return Configuration(filename) |
|
56 |
|
57 def firstCap(str): |
|
58 return str[0].upper() + str[1:] |
|
59 |
|
60 def getBaseName(iface): |
|
61 return ("%s" % iface.base[6:]) |
|
62 |
|
63 def print_header_file(fd, conf): |
|
64 fd.write("#ifndef _gen_mozilla_idl_generated_events_h_\n" |
|
65 "#define _gen_mozilla_idl_generated_events_h_\n\n") |
|
66 fd.write("/* THIS FILE IS AUTOGENERATED - DO NOT EDIT */\n") |
|
67 fd.write("#include \"nscore.h\"\n") |
|
68 fd.write("class nsIDOMEvent;\n") |
|
69 fd.write("class nsPresContext;\n") |
|
70 fd.write("namespace mozilla {\n"); |
|
71 fd.write("class WidgetEvent;\n") |
|
72 fd.write("namespace dom {\n"); |
|
73 fd.write("class EventTarget;\n") |
|
74 fd.write("}\n"); |
|
75 fd.write("}\n\n"); |
|
76 for e in conf.simple_events: |
|
77 fd.write("nsresult\n") |
|
78 fd.write("NS_NewDOM%s(nsIDOMEvent** aInstance, " % e) |
|
79 fd.write("mozilla::dom::EventTarget* aOwner, ") |
|
80 fd.write("nsPresContext* aPresContext, mozilla::WidgetEvent* aEvent);\n") |
|
81 |
|
82 fd.write("\n#endif\n") |
|
83 |
|
84 def print_classes_file(fd, conf): |
|
85 fd.write("#ifndef _gen_mozilla_idl_generated_event_declarations_h_\n") |
|
86 fd.write("#define _gen_mozilla_idl_generated_event_declarations_h_\n\n") |
|
87 |
|
88 fd.write("#include \"mozilla/dom/Event.h\"\n"); |
|
89 includes = [] |
|
90 for s in conf.special_includes: |
|
91 if not s in includes: |
|
92 includes.append(strip_end(s, ".h")) |
|
93 |
|
94 for e in conf.simple_events: |
|
95 if not e in includes: |
|
96 includes.append(("nsIDOM%s" % e)) |
|
97 |
|
98 attrnames = [] |
|
99 for e in conf.simple_events: |
|
100 idl = loadEventIDL(p, options.incdirs, e) |
|
101 collect_names_and_non_primitive_attribute_types(idl, attrnames, includes) |
|
102 |
|
103 for c in includes: |
|
104 if not c in conf.exclude_automatic_type_include: |
|
105 fd.write("#include \"%s.h\"\n" % c) |
|
106 |
|
107 for e in conf.simple_events: |
|
108 fd.write('#include "mozilla/dom/%sBinding.h"\n' % e); |
|
109 |
|
110 fd.write("namespace mozilla {\n") |
|
111 fd.write("namespace dom {\n") |
|
112 for e in conf.simple_events: |
|
113 idl = loadEventIDL(p, options.incdirs, e) |
|
114 for pr in idl.productions: |
|
115 if pr.kind == 'interface': |
|
116 print_class_declaration(e, pr, fd, conf) |
|
117 fd.write("} // namespace dom\n") |
|
118 fd.write("} // namespace mozilla\n\n") |
|
119 fd.write("#endif\n"); |
|
120 |
|
121 def print_class_declaration(eventname, iface, fd, conf): |
|
122 classname = ("%s" % eventname) |
|
123 basename = getBaseName(iface) |
|
124 attributes = [] |
|
125 ccattributes = [] |
|
126 for member in iface.members: |
|
127 if isinstance(member, xpidl.Attribute): |
|
128 attributes.append(member) |
|
129 if (member.realtype.nativeType('in').endswith('*')): |
|
130 ccattributes.append(member); |
|
131 |
|
132 baseinterfaces = [] |
|
133 baseiface = iface.idl.getName(iface.base, iface.location) |
|
134 while baseiface.name != "nsIDOMEvent": |
|
135 baseinterfaces.append(baseiface) |
|
136 baseiface = baseiface.idl.getName(baseiface.base, baseiface.location) |
|
137 baseinterfaces.reverse() |
|
138 |
|
139 allattributes = [] |
|
140 for baseiface in baseinterfaces: |
|
141 for member in baseiface.members: |
|
142 if isinstance(member, xpidl.Attribute): |
|
143 allattributes.append(member) |
|
144 allattributes.extend(attributes); |
|
145 |
|
146 fd.write("\nclass %s MOZ_FINAL : public %s, public %s\n" % (classname, basename, iface.name)) |
|
147 fd.write("{\n") |
|
148 fd.write("public:\n") |
|
149 fd.write(" %s(mozilla::dom::EventTarget* aOwner, " % classname) |
|
150 fd.write("nsPresContext* aPresContext = nullptr, mozilla::WidgetEvent* aEvent = nullptr);\n"); |
|
151 fd.write(" virtual ~%s();\n\n" % classname) |
|
152 fd.write(" NS_DECL_ISUPPORTS_INHERITED\n") |
|
153 fd.write(" NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(%s, %s)\n" % (classname, basename)) |
|
154 fd.write(" NS_FORWARD_TO_EVENT\n") |
|
155 |
|
156 for baseiface in baseinterfaces: |
|
157 baseimpl = ("%s" % baseiface.name[6:]) |
|
158 fd.write(" NS_FORWARD_%s(%s::)\n" % (baseiface.name.upper(), baseimpl)) |
|
159 |
|
160 fd.write(" NS_DECL_%s\n" % iface.name.upper()) |
|
161 |
|
162 hasVariant = False |
|
163 for a in allattributes: |
|
164 if a.type == "nsIVariant": |
|
165 hasVariant = True |
|
166 break; |
|
167 fd.write(" static already_AddRefed<%s> Constructor(const GlobalObject& aGlobal, " % eventname) |
|
168 if hasVariant: |
|
169 fd.write("JSContext* aCx, ") |
|
170 fd.write("const nsAString& aType, ") |
|
171 fd.write("const %sInit& aParam, " % eventname) |
|
172 fd.write("ErrorResult& aRv);\n\n") |
|
173 |
|
174 fd.write(" virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE\n") |
|
175 fd.write(" {\n") |
|
176 fd.write(" return mozilla::dom::%sBinding::Wrap(aCx, this);\n" % eventname) |
|
177 fd.write(" }\n\n") |
|
178 |
|
179 for a in attributes: |
|
180 """xpidl methods take care of string member variables!""" |
|
181 firstCapName = firstCap(a.name) |
|
182 cleanNativeType = a.realtype.nativeType('in').strip('* ') |
|
183 if a.realtype.nativeType('in').count("nsAString"): |
|
184 continue |
|
185 elif a.realtype.nativeType('in').count("nsIVariant"): |
|
186 fd.write(" void Get%s(JSContext* aCx, JS::MutableHandle<JS::Value> aRetval, ErrorResult& aRv);\n\n" % firstCapName); |
|
187 elif a.realtype.nativeType('in').endswith('*'): |
|
188 fd.write(" already_AddRefed<%s> Get%s()\n" % (xpidl_to_native(cleanNativeType, conf), firstCapName)) |
|
189 fd.write(" {\n"); |
|
190 fd.write(" nsCOMPtr<%s> %s = do_QueryInterface(m%s);\n" % (xpidl_to_canonical(cleanNativeType, conf), a.name, firstCapName)) |
|
191 fd.write(" return %s.forget().downcast<%s>();\n" % (a.name, xpidl_to_native(cleanNativeType, conf))) |
|
192 fd.write(" }\n\n"); |
|
193 else: |
|
194 fd.write(" %s %s()\n" % (cleanNativeType, firstCapName)) |
|
195 fd.write(" {\n"); |
|
196 fd.write(" return m%s;\n" % firstCapName) |
|
197 fd.write(" }\n\n"); |
|
198 |
|
199 fd.write(" void ") |
|
200 fd.write("Init%s(" % eventname) |
|
201 if hasVariant: |
|
202 fd.write("JSContext* aCx, ") |
|
203 fd.write("const nsAString& aType, bool aCanBubble, bool aCancelable") |
|
204 for a in allattributes: |
|
205 writeNativeAttributeParams(fd, a, conf) |
|
206 fd.write(", ErrorResult& aRv);\n\n") |
|
207 |
|
208 fd.write("protected:\n") |
|
209 for a in attributes: |
|
210 fd.write(" %s\n" % attributeVariableTypeAndName(a)) |
|
211 fd.write("};\n") |
|
212 |
|
213 def collect_names_and_non_primitive_attribute_types(idl, attrnames, forwards): |
|
214 for p in idl.productions: |
|
215 if p.kind == 'interface' or p.kind == 'dictionary': |
|
216 interfaces = [] |
|
217 base = p.base |
|
218 baseiface = p |
|
219 while base is not None: |
|
220 baseiface = baseiface.idl.getName(baseiface.base, baseiface.location) |
|
221 interfaces.append(baseiface) |
|
222 base = baseiface.base |
|
223 |
|
224 interfaces.reverse() |
|
225 interfaces.append(p) |
|
226 |
|
227 for iface in interfaces: |
|
228 collect_names_and_non_primitive_attribute_types_from_interface(iface, attrnames, forwards) |
|
229 |
|
230 def collect_names_and_non_primitive_attribute_types_from_interface(iface, attrnames, forwards): |
|
231 for member in iface.members: |
|
232 if isinstance(member, xpidl.Attribute): |
|
233 if not member.name in attrnames: |
|
234 attrnames.append(member.name) |
|
235 if member.realtype.nativeType('in').endswith('*'): |
|
236 t = member.realtype.nativeType('in').strip('* ') |
|
237 if not t in forwards: |
|
238 forwards.append(t) |
|
239 |
|
240 def print_cpp(idl, fd, conf, eventname): |
|
241 for p in idl.productions: |
|
242 if p.kind == 'interface': |
|
243 write_cpp(eventname, p, fd, conf) |
|
244 |
|
245 def print_cpp_file(fd, conf): |
|
246 fd.write("/* THIS FILE IS AUTOGENERATED - DO NOT EDIT */\n\n") |
|
247 fd.write('#include "GeneratedEventClasses.h"\n') |
|
248 fd.write('#include "xpcprivate.h"\n'); |
|
249 fd.write('#include "mozilla/dom/Event.h"\n'); |
|
250 fd.write('#include "mozilla/dom/EventTarget.h"\n'); |
|
251 |
|
252 for e in conf.simple_events: |
|
253 idl = loadEventIDL(p, options.incdirs, e) |
|
254 print_cpp(idl, fd, conf, e) |
|
255 |
|
256 def init_value(attribute): |
|
257 realtype = attribute.realtype.nativeType('in') |
|
258 realtype = realtype.strip(' ') |
|
259 if realtype.endswith('*'): |
|
260 return "nullptr" |
|
261 if realtype == "bool": |
|
262 return "false" |
|
263 if realtype.count("nsAString"): |
|
264 return "" |
|
265 if realtype.count("nsACString"): |
|
266 return "" |
|
267 if realtype.count("JS::Value"): |
|
268 raise BaseException("JS::Value not supported in simple events!") |
|
269 return "0" |
|
270 |
|
271 def attributeVariableTypeAndName(a): |
|
272 if a.realtype.nativeType('in').endswith('*'): |
|
273 l = ["nsCOMPtr<%s> m%s;" % (a.realtype.nativeType('in').strip('* '), |
|
274 firstCap(a.name))] |
|
275 elif a.realtype.nativeType('in').count("nsAString"): |
|
276 l = ["nsString m%s;" % firstCap(a.name)] |
|
277 elif a.realtype.nativeType('in').count("nsACString"): |
|
278 l = ["nsCString m%s;" % firstCap(a.name)] |
|
279 else: |
|
280 l = ["%sm%s;" % (a.realtype.nativeType('in'), |
|
281 firstCap(a.name))] |
|
282 return ", ".join(l) |
|
283 |
|
284 def writeAttributeGetter(fd, classname, a): |
|
285 fd.write("NS_IMETHODIMP\n") |
|
286 fd.write("%s::Get%s(" % (classname, firstCap(a.name))) |
|
287 if a.realtype.nativeType('in').endswith('*'): |
|
288 fd.write("%s** a%s" % (a.realtype.nativeType('in').strip('* '), firstCap(a.name))) |
|
289 elif a.realtype.nativeType('in').count("nsAString"): |
|
290 fd.write("nsAString& a%s" % firstCap(a.name)) |
|
291 elif a.realtype.nativeType('in').count("nsACString"): |
|
292 fd.write("nsACString& a%s" % firstCap(a.name)) |
|
293 else: |
|
294 fd.write("%s*a%s" % (a.realtype.nativeType('in'), firstCap(a.name))) |
|
295 fd.write(")\n"); |
|
296 fd.write("{\n"); |
|
297 if a.realtype.nativeType('in').endswith('*'): |
|
298 fd.write(" NS_IF_ADDREF(*a%s = m%s);\n" % (firstCap(a.name), firstCap(a.name))) |
|
299 elif a.realtype.nativeType('in').count("nsAString"): |
|
300 fd.write(" a%s = m%s;\n" % (firstCap(a.name), firstCap(a.name))) |
|
301 elif a.realtype.nativeType('in').count("nsACString"): |
|
302 fd.write(" a%s = m%s;\n" % (firstCap(a.name), firstCap(a.name))) |
|
303 else: |
|
304 fd.write(" *a%s = %s();\n" % (firstCap(a.name), firstCap(a.name))) |
|
305 fd.write(" return NS_OK;\n"); |
|
306 fd.write("}\n\n"); |
|
307 if a.realtype.nativeType('in').count("nsIVariant"): |
|
308 fd.write("void\n") |
|
309 fd.write("%s::Get%s(JSContext* aCx, JS::MutableHandle<JS::Value> aRetval, ErrorResult& aRv)\n" % (classname, firstCap(a.name))) |
|
310 fd.write("{\n") |
|
311 fd.write(" nsresult rv = NS_ERROR_UNEXPECTED;\n") |
|
312 fd.write(" if (!m%s) {\n" % firstCap(a.name)) |
|
313 fd.write(" aRetval.setNull();\n") |
|
314 fd.write(" } else if (!XPCVariant::VariantDataToJS(m%s, &rv, aRetval)) {\n" % (firstCap(a.name))) |
|
315 fd.write(" aRv.Throw(NS_ERROR_FAILURE);\n") |
|
316 fd.write(" }\n") |
|
317 fd.write("}\n\n") |
|
318 |
|
319 def writeAttributeParams(fd, a): |
|
320 if a.realtype.nativeType('in').endswith('*'): |
|
321 fd.write(", %s* a%s" % (a.realtype.nativeType('in').strip('* '), firstCap(a.name))) |
|
322 elif a.realtype.nativeType('in').count("nsAString"): |
|
323 fd.write(", const nsAString& a%s" % firstCap(a.name)) |
|
324 elif a.realtype.nativeType('in').count("nsACString"): |
|
325 fd.write(", const nsACString& a%s" % firstCap(a.name)) |
|
326 else: |
|
327 fd.write(", %s a%s" % (a.realtype.nativeType('in'), firstCap(a.name))) |
|
328 |
|
329 def writeNativeAttributeParams(fd, a, conf): |
|
330 if a.type == "nsIVariant": |
|
331 fd.write(", JS::Value a%s" % firstCap(a.name)); |
|
332 elif a.realtype.nativeType('in').endswith('*'): |
|
333 fd.write(", %s* a%s" % (xpidl_to_native(a.realtype.nativeType('in').strip('* '), conf), firstCap(a.name))) |
|
334 elif a.realtype.nativeType('in').count("nsAString"): |
|
335 fd.write(", const nsAString& a%s" % firstCap(a.name)) |
|
336 elif a.realtype.nativeType('in').count("nsACString"): |
|
337 fd.write(", const nsACString& a%s" % firstCap(a.name)) |
|
338 else: |
|
339 fd.write(", %s a%s" % (a.realtype.nativeType('in'), firstCap(a.name))) |
|
340 |
|
341 def write_cpp(eventname, iface, fd, conf): |
|
342 classname = ("%s" % eventname) |
|
343 basename = getBaseName(iface) |
|
344 attributes = [] |
|
345 ccattributes = [] |
|
346 for member in iface.members: |
|
347 if isinstance(member, xpidl.Attribute): |
|
348 attributes.append(member) |
|
349 if (member.realtype.nativeType('in').endswith('*')): |
|
350 ccattributes.append(member); |
|
351 |
|
352 baseinterfaces = [] |
|
353 baseiface = iface.idl.getName(iface.base, iface.location) |
|
354 while baseiface.name != "nsIDOMEvent": |
|
355 baseinterfaces.append(baseiface) |
|
356 baseiface = baseiface.idl.getName(baseiface.base, baseiface.location) |
|
357 baseinterfaces.reverse() |
|
358 |
|
359 baseattributes = [] |
|
360 for baseiface in baseinterfaces: |
|
361 for member in baseiface.members: |
|
362 if isinstance(member, xpidl.Attribute): |
|
363 baseattributes.append(member) |
|
364 |
|
365 allattributes = [] |
|
366 allattributes.extend(baseattributes); |
|
367 allattributes.extend(attributes); |
|
368 |
|
369 fd.write("namespace mozilla {\n") |
|
370 fd.write("namespace dom {\n\n") |
|
371 |
|
372 fd.write("%s::%s(mozilla::dom::EventTarget* aOwner, " % (classname, classname)) |
|
373 fd.write("nsPresContext* aPresContext, mozilla::WidgetEvent* aEvent)\n"); |
|
374 fd.write(": %s(aOwner, aPresContext, aEvent)" % basename) |
|
375 for a in attributes: |
|
376 fd.write(",\n m%s(%s)" % (firstCap(a.name), init_value(a))) |
|
377 fd.write("\n{\n") |
|
378 fd.write("}\n\n") |
|
379 |
|
380 fd.write("%s::~%s() {}\n\n" % (classname, classname)) |
|
381 |
|
382 fd.write("NS_IMPL_CYCLE_COLLECTION_CLASS(%s)\n" % (classname)) |
|
383 fd.write("NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(%s, %s)\n" % (classname, basename)) |
|
384 for c in ccattributes: |
|
385 fd.write(" NS_IMPL_CYCLE_COLLECTION_UNLINK(m%s)\n" % firstCap(c.name)) |
|
386 fd.write("NS_IMPL_CYCLE_COLLECTION_UNLINK_END\n\n"); |
|
387 fd.write("NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(%s, %s)\n" % (classname, basename)) |
|
388 for c in ccattributes: |
|
389 fd.write(" NS_IMPL_CYCLE_COLLECTION_TRAVERSE(m%s)\n" % firstCap(c.name)) |
|
390 fd.write("NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END\n\n"); |
|
391 |
|
392 fd.write("NS_IMPL_ADDREF_INHERITED(%s, %s)\n" % (classname, basename)) |
|
393 fd.write("NS_IMPL_RELEASE_INHERITED(%s, %s)\n\n" % (classname, basename)) |
|
394 |
|
395 fd.write("NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(%s)\n" % classname) |
|
396 fd.write(" NS_INTERFACE_MAP_ENTRY(nsIDOM%s)\n" % eventname) |
|
397 fd.write("NS_INTERFACE_MAP_END_INHERITING(%s)\n\n" % basename) |
|
398 |
|
399 hasVariant = False |
|
400 for a in allattributes: |
|
401 if a.type == "nsIVariant": |
|
402 hasVariant = True |
|
403 break; |
|
404 |
|
405 fd.write("already_AddRefed<%s>\n" % eventname) |
|
406 fd.write("%s::Constructor(const GlobalObject& aGlobal, " % eventname) |
|
407 if hasVariant: |
|
408 fd.write("JSContext* aCx, "); |
|
409 fd.write("const nsAString& aType, ") |
|
410 fd.write("const %sInit& aParam, " % eventname) |
|
411 fd.write("ErrorResult& aRv)\n") |
|
412 fd.write("{\n") |
|
413 fd.write(" nsCOMPtr<mozilla::dom::EventTarget> t = do_QueryInterface(aGlobal.GetAsSupports());\n") |
|
414 fd.write(" nsRefPtr<%s> e = new %s(t, nullptr, nullptr);\n" % (eventname, eventname)) |
|
415 fd.write(" bool trusted = e->Init(t);\n") |
|
416 fd.write(" e->Init%s(" % eventname) |
|
417 if hasVariant: |
|
418 fd.write("aCx, "); |
|
419 fd.write("aType, aParam.mBubbles, aParam.mCancelable") |
|
420 for a in allattributes: |
|
421 fd.write(", aParam.m%s" % firstCap(a.name)) |
|
422 fd.write(", aRv);\n") |
|
423 fd.write(" e->SetTrusted(trusted);\n") |
|
424 fd.write(" return e.forget();\n") |
|
425 fd.write("}\n\n") |
|
426 |
|
427 fd.write("NS_IMETHODIMP\n") |
|
428 fd.write("%s::Init%s(" % (classname, eventname)) |
|
429 fd.write("const nsAString& aType, bool aCanBubble, bool aCancelable") |
|
430 for a in allattributes: |
|
431 writeAttributeParams(fd, a) |
|
432 fd.write(")\n{\n") |
|
433 fd.write(" nsresult rv = %s::Init%s(aType, aCanBubble, aCancelable" % (basename, ("%s" % iface.base[6:]))) |
|
434 for a in baseattributes: |
|
435 fd.write(", a%s" % firstCap(a.name)) |
|
436 fd.write(");\n"); |
|
437 fd.write(" NS_ENSURE_SUCCESS(rv, rv);\n") |
|
438 for a in attributes: |
|
439 if a.realtype.nativeType("in").count("nsAString"): |
|
440 fd.write(" if (!m%s.Assign(a%s, fallible_t())) {\n" % (firstCap(a.name), firstCap(a.name))) |
|
441 fd.write(" return NS_ERROR_OUT_OF_MEMORY;\n") |
|
442 fd.write(" }\n") |
|
443 else: |
|
444 fd.write(" m%s = a%s;\n" % (firstCap(a.name), firstCap(a.name))) |
|
445 fd.write(" return NS_OK;\n") |
|
446 fd.write("}\n\n") |
|
447 |
|
448 fd.write("void\n") |
|
449 fd.write("%s::Init%s(" % (classname, eventname)) |
|
450 if hasVariant: |
|
451 fd.write("JSContext* aCx, ") |
|
452 fd.write("const nsAString& aType, bool aCanBubble, bool aCancelable") |
|
453 for a in allattributes: |
|
454 writeNativeAttributeParams(fd, a, conf) |
|
455 fd.write(", ErrorResult& aRv") |
|
456 fd.write(")\n") |
|
457 fd.write("{\n"); |
|
458 for a in allattributes: |
|
459 if a.type == "nsIVariant": |
|
460 fd.write(" nsCOMPtr<nsIVariant> %s = dont_AddRef(XPCVariant::newVariant(aCx, a%s));\n" % (a.name, firstCap(a.name))) |
|
461 fd.write(" if (!%s) {\n" % a.name) |
|
462 fd.write(" aRv.Throw(NS_ERROR_FAILURE);\n") |
|
463 fd.write(" return;\n") |
|
464 fd.write(" }\n") |
|
465 elif a.realtype.nativeType('in').endswith('*'): |
|
466 xpidl_t = a.realtype.nativeType('in').strip('* ') |
|
467 native_t = xpidl_to_native(xpidl_t, conf) |
|
468 if xpidl_t != native_t: |
|
469 fd.write(" nsCOMPtr<%s> %s = do_QueryInterface(static_cast<%s*>(a%s));\n" % (xpidl_t, a.name, xpidl_to_canonical(xpidl_t, conf), firstCap(a.name))) |
|
470 fd.write(" aRv = Init%s(" % classname); |
|
471 fd.write("aType, aCanBubble, aCancelable") |
|
472 for a in allattributes: |
|
473 if a.realtype.nativeType('in').endswith('*'): |
|
474 xpidl_t = a.realtype.nativeType('in').strip('* ') |
|
475 native_t = xpidl_to_native(xpidl_t, conf) |
|
476 if xpidl_t != native_t or a.type == "nsIVariant": |
|
477 fd.write(", %s" % a.name) |
|
478 continue |
|
479 fd.write(", a%s" % firstCap(a.name)) |
|
480 fd.write(");\n}\n\n"); |
|
481 |
|
482 for a in attributes: |
|
483 writeAttributeGetter(fd, classname, a) |
|
484 |
|
485 fd.write("} // namespace dom\n") |
|
486 fd.write("} // namespace mozilla\n\n") |
|
487 |
|
488 fd.write("nsresult\n") |
|
489 fd.write("NS_NewDOM%s(nsIDOMEvent** aInstance, " % eventname) |
|
490 fd.write("mozilla::dom::EventTarget* aOwner, nsPresContext* aPresContext = nullptr, mozilla::WidgetEvent* aEvent = nullptr)\n") |
|
491 fd.write("{\n") |
|
492 fd.write(" mozilla::dom::%s* it = new mozilla::dom::%s(aOwner, aPresContext, aEvent);\n" % (classname, classname)) |
|
493 fd.write(" NS_ADDREF(it);\n") |
|
494 fd.write(" *aInstance = static_cast<mozilla::dom::Event*>(it);\n") |
|
495 fd.write(" return NS_OK;\n"); |
|
496 fd.write("}\n\n") |
|
497 |
|
498 def toWebIDLType(attribute, inType=False, onlyInterface=False): |
|
499 if attribute.type == "nsIVariant": |
|
500 return "any"; |
|
501 if attribute.type == "nsISupports": |
|
502 return "%s%s" % (attribute.type, "" if onlyInterface else "?") |
|
503 if attribute.type.count("nsIDOM"): |
|
504 return "%s%s" % (attribute.type[6:], "" if onlyInterface else "?") |
|
505 if attribute.type.count("nsI"): |
|
506 return "%s%s" % (attribute.type[3:], "" if onlyInterface else "?") |
|
507 if attribute.realtype.nativeType('in').endswith('*') or attribute.realtype.nativeType('in').count("nsAString"): |
|
508 return "%s%s" % (attribute.type, "" if onlyInterface else "?") |
|
509 return attribute.type |
|
510 |
|
511 def write_webidl(eventname, iface, fd, conf, idl): |
|
512 basename = ("%s" % iface.base[6:]) |
|
513 attributes = [] |
|
514 ccattributes = [] |
|
515 consts = [] |
|
516 hasInit = False |
|
517 initMethod = "init%s" % eventname; |
|
518 for member in iface.members: |
|
519 if isinstance(member, xpidl.Attribute): |
|
520 attributes.append(member) |
|
521 if (member.realtype.nativeType('in').endswith('*')): |
|
522 ccattributes.append(member); |
|
523 elif isinstance(member, xpidl.Method) and member.name == initMethod: |
|
524 if not member.noscript and not member.notxpcom: |
|
525 hasInit = True |
|
526 elif isinstance(member, xpidl.ConstMember): |
|
527 consts.append(member); |
|
528 else: |
|
529 raise BaseException("Unsupported idl member %s::%s" % (eventname, member.name)) |
|
530 |
|
531 baseinterfaces = [] |
|
532 baseiface = iface.idl.getName(iface.base, iface.location) |
|
533 while baseiface.name != "nsIDOMEvent": |
|
534 baseinterfaces.append(baseiface) |
|
535 baseiface = baseiface.idl.getName(baseiface.base, baseiface.location) |
|
536 baseinterfaces.reverse() |
|
537 |
|
538 allattributes = [] |
|
539 for baseiface in baseinterfaces: |
|
540 for member in baseiface.members: |
|
541 if isinstance(member, xpidl.Attribute): |
|
542 allattributes.append(member) |
|
543 allattributes.extend(attributes) |
|
544 |
|
545 fd.write( |
|
546 """/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
547 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
548 * License, v. 2.0. If a copy of the MPL was not distributed with this file, |
|
549 * You can obtain one at http://mozilla.org/MPL/2.0/. |
|
550 */ |
|
551 """) |
|
552 |
|
553 neededInterfaces = [] |
|
554 for a in attributes: |
|
555 if a.realtype.nativeType('in').endswith('*'): |
|
556 nativeType = a.realtype.nativeType('in').strip('* ') |
|
557 mappingForWebIDL = False |
|
558 for xp in conf.xpidl_to_native: |
|
559 if xp[0] == nativeType: |
|
560 mappingForWebIDL = True |
|
561 break; |
|
562 if not mappingForWebIDL: |
|
563 webidlType = toWebIDLType(a, False, True) |
|
564 if (not webidlType in neededInterfaces and webidlType != "any"): |
|
565 neededInterfaces.append(webidlType); |
|
566 |
|
567 for i in neededInterfaces: |
|
568 fd.write("interface %s;\n" % i) |
|
569 |
|
570 fd.write("\n"); |
|
571 fd.write("[Constructor(DOMString type, optional %sInit eventInitDict), HeaderFile=\"GeneratedEventClasses.h\"]\n" % eventname); |
|
572 fd.write("interface %s : %s\n" % (eventname, basename)) |
|
573 fd.write("{\n") |
|
574 |
|
575 for c in consts: |
|
576 fd.write(" const %s %s = %s;\n" % (c.type, c.name, c.getValue())) |
|
577 if len(consts): |
|
578 fd.write("\n") |
|
579 |
|
580 for a in attributes: |
|
581 if a.realtype.nativeType('in').count("nsIVariant"): |
|
582 fd.write(" [Throws]\n") |
|
583 fd.write(" readonly attribute %s %s;\n" % (toWebIDLType(a), a.name)) |
|
584 elif a.realtype.nativeType('in').endswith('*') or a.realtype.nativeType('in').count("nsAString"): |
|
585 fd.write(" readonly attribute %s %s;\n" % (toWebIDLType(a), a.name)) |
|
586 else: |
|
587 fd.write(" readonly attribute %s %s;\n" % (a.type, a.name)) |
|
588 if hasInit: |
|
589 fd.write("\n [Throws]\n") |
|
590 m = " void %s(" % initMethod |
|
591 fd.write(m) |
|
592 indent = "".join(" " for i in range(len(m))) |
|
593 indent = ",\n%s" % indent |
|
594 fd.write("DOMString type") |
|
595 fd.write(indent); |
|
596 fd.write("boolean canBubble") |
|
597 fd.write(indent); |
|
598 fd.write("boolean cancelable") |
|
599 for a in baseattributes + attributes: |
|
600 fd.write(indent); |
|
601 fd.write("%s %s" % (toWebIDLType(a, True), a.name)) |
|
602 fd.write(");\n"); |
|
603 fd.write("};\n\n") |
|
604 |
|
605 dname = "%sInit" % eventname |
|
606 for p in idl.productions: |
|
607 if p.kind == "dictionary" and p.name == dname: |
|
608 fd.write("dictionary %s : %sInit\n" % (dname, basename)) |
|
609 fd.write("{\n") |
|
610 # We want to keep the same ordering what interface has. |
|
611 for ifaceattribute in attributes: |
|
612 for member in p.members: |
|
613 if member.name == ifaceattribute.name: |
|
614 a = member |
|
615 if a.realtype.nativeType('in').endswith('*'): |
|
616 fd.write(" %s %s = null;\n" % (toWebIDLType(a, True), a.name)) |
|
617 elif a.realtype.nativeType('in').count("nsAString"): |
|
618 if a.defvalue is None: |
|
619 if a.nullable: |
|
620 fd.write(" %s? %s = null;\n" % (a.type, a.name)) |
|
621 else: |
|
622 fd.write(" %s %s = \"\";\n" % (a.type, a.name)) |
|
623 else: |
|
624 if a.nullable: |
|
625 fd.write(" %s? %s = \"%s\";\n" % (a.type, a.name, a.defvalue)) |
|
626 else: |
|
627 fd.write(" %s %s = \"%s\";\n" % (a.type, a.name, a.defvalue)) |
|
628 else: |
|
629 if a.defvalue is None: |
|
630 if a.type == "boolean": |
|
631 fd.write(" %s %s = false;\n" % (a.type, a.name)) |
|
632 else: |
|
633 fd.write(" %s %s = 0;\n" % (a.type, a.name)) |
|
634 # Infinity is not supported by all the types, but |
|
635 # WebIDL parser will then complain about the wrong values. |
|
636 elif a.defvalue == "Infinity": |
|
637 fd.write(" unrestricted %s %s = Infinity;\n" % (a.type, a.name)) |
|
638 elif a.defvalue == "-Infinity": |
|
639 fd.write(" unrestricted %s %s = -Infinity;\n" % (a.type, a.name)) |
|
640 else: |
|
641 fd.write(" %s %s = %s;\n" % (a.type, a.name, a.defvalue)) |
|
642 continue |
|
643 fd.write("};\n") |
|
644 return |
|
645 |
|
646 # There is no dictionary defined in the .idl file. Generate one based on |
|
647 # the interface. |
|
648 fd.write("dictionary %s : %sInit\n" % (dname, basename)) |
|
649 fd.write("{\n") |
|
650 for a in attributes: |
|
651 if a.realtype.nativeType('in').endswith('*'): |
|
652 fd.write(" %s %s = null;\n" % (toWebIDLType(a, True), a.name)) |
|
653 elif a.realtype.nativeType('in').count("nsAString"): |
|
654 fd.write(" %s? %s = \"\";\n" % (a.type, a.name)) |
|
655 elif a.type == "boolean": |
|
656 fd.write(" %s %s = false;\n" % (a.type, a.name)) |
|
657 else: |
|
658 fd.write(" %s %s = 0;\n" % (a.type, a.name)) |
|
659 fd.write("};\n") |
|
660 |
|
661 def print_webidl_file(idl, fd, conf, eventname): |
|
662 for p in idl.productions: |
|
663 if p.kind == 'interface': |
|
664 write_webidl(eventname, p, fd, conf, idl) |
|
665 |
|
666 def xpidl_to_native(xpidl, conf): |
|
667 for x in conf.xpidl_to_native: |
|
668 if x[0] == xpidl: |
|
669 return x[1] |
|
670 return xpidl |
|
671 |
|
672 def xpidl_to_canonical(xpidl, conf): |
|
673 for x in conf.xpidl_to_native: |
|
674 if x[0] == xpidl: |
|
675 return x[2] |
|
676 return xpidl |
|
677 |
|
678 def native_to_xpidl(native, conf): |
|
679 for x in conf.xpidl_to_native: |
|
680 if x[1] == native: |
|
681 return x[0] |
|
682 return native |
|
683 |
|
684 def print_webidl_files(webidlDir, conf): |
|
685 for e in conf.simple_events: |
|
686 idl = loadEventIDL(p, options.incdirs, e) |
|
687 webidl = "%s/%s.webidl" % (webidlDir, e) |
|
688 if not os.path.exists(webidl): |
|
689 fd = open(webidl, 'w') |
|
690 print_webidl_file(idl, fd, conf, e) |
|
691 fd.close(); |
|
692 |
|
693 if __name__ == '__main__': |
|
694 from optparse import OptionParser |
|
695 o = OptionParser(usage="usage: %prog [options] configfile") |
|
696 o.add_option('-I', action='append', dest='incdirs', default=['.'], |
|
697 help="Directory to search for imported files") |
|
698 o.add_option('-o', "--stub-output", |
|
699 type='string', dest='stub_output', default=None, |
|
700 help="Quick stub C++ source output file", metavar="FILE") |
|
701 o.add_option('--header-output', type='string', default=None, |
|
702 help="Quick stub header output file", metavar="FILE") |
|
703 o.add_option('--makedepend-output', type='string', default=None, |
|
704 help="gnumake dependencies output file", metavar="FILE") |
|
705 o.add_option('--cachedir', dest='cachedir', default=None, |
|
706 help="Directory in which to cache lex/parse tables.") |
|
707 o.add_option('--class-declarations', type='string', default=None, |
|
708 help="Class declarations", metavar="FILE") |
|
709 o.add_option('--webidltarget', dest='webidltarget', default=None, |
|
710 help="Directory in which to store generated WebIDL files.") |
|
711 (options, filenames) = o.parse_args() |
|
712 if len(filenames) != 1: |
|
713 o.error("Exactly one config filename is needed.") |
|
714 filename = filenames[0] |
|
715 |
|
716 if options.cachedir is not None: |
|
717 if not os.path.isdir(options.cachedir): |
|
718 os.mkdir(options.cachedir) |
|
719 sys.path.append(options.cachedir) |
|
720 |
|
721 # Instantiate the parser. |
|
722 p = xpidl.IDLParser(outputdir=options.cachedir) |
|
723 |
|
724 conf = readConfigFile(filename) |
|
725 |
|
726 if options.header_output is not None: |
|
727 outfd = open(options.header_output, 'w') |
|
728 print_header_file(outfd, conf) |
|
729 outfd.close() |
|
730 if options.class_declarations is not None: |
|
731 outfd = open(options.class_declarations, 'w') |
|
732 print_classes_file(outfd, conf) |
|
733 outfd.close() |
|
734 if options.stub_output is not None: |
|
735 makeutils.targets.append(options.stub_output) |
|
736 outfd = open(options.stub_output, 'w') |
|
737 print_cpp_file(outfd, conf) |
|
738 outfd.close() |
|
739 if options.makedepend_output is not None: |
|
740 makeutils.writeMakeDependOutput(options.makedepend_output) |
|
741 |
|
742 if options.webidltarget is not None: |
|
743 print_webidl_files(options.webidltarget, conf) |
|
744 |