Remove [LegacyParent] from CodeGeneratorGObject.pm, and rename it to [JSLegacyParent]
[WebKit-https.git] / Source / WebCore / bindings / scripts / CodeGeneratorGObject.pm
1 # Copyright (C) 2008 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
2 # Copyright (C) 2008 Martin Soto <soto@freedesktop.org>
3 # Copyright (C) 2008 Alp Toker <alp@atoker.com>
4 # Copyright (C) 2009 Adam Dingle <adam@yorba.org>
5 # Copyright (C) 2009 Jim Nelson <jim@yorba.org>
6 # Copyright (C) 2009, 2010 Igalia S.L.
7 #
8 # This library is free software; you can redistribute it and/or
9 # modify it under the terms of the GNU Library General Public
10 # License as published by the Free Software Foundation; either
11 # version 2 of the License, or (at your option) any later version.
12 #
13 # This library is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 # Library General Public License for more details.
17 #
18 # You should have received a copy of the GNU Library General Public License
19 # along with this library; see the file COPYING.LIB.  If not, write to
20 # the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 # Boston, MA 02111-1307, USA.
22
23 package CodeGeneratorGObject;
24
25 use constant FileNamePrefix => "WebKitDOM";
26
27 # Global Variables
28 my %implIncludes = ();
29 my %hdrIncludes = ();
30
31 my $defineTypeMacro = "G_DEFINE_TYPE";
32 my $defineTypeInterfaceImplementation = ")";
33 my @txtEventListeners = ();
34 my @txtInstallEventListeners = ();
35 my @txtInstallSignals = ();
36 my @txtInstallProps = ();
37 my @txtSetProps = ();
38 my @txtGetProps = ();
39
40 my $className = "";
41
42 # Default constructor
43 sub new {
44     my $object = shift;
45     my $reference = { };
46
47     $codeGenerator = shift;
48     $outputDir = shift;
49     mkdir $outputDir;
50
51     bless($reference, $object);
52 }
53
54 my $licenceTemplate = << "EOF";
55 /*
56     This file is part of the WebKit open source project.
57     This file has been generated by generate-bindings.pl. DO NOT MODIFY!
58
59     This library is free software; you can redistribute it and/or
60     modify it under the terms of the GNU Library General Public
61     License as published by the Free Software Foundation; either
62     version 2 of the License, or (at your option) any later version.
63
64     This library is distributed in the hope that it will be useful,
65     but WITHOUT ANY WARRANTY; without even the implied warranty of
66     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
67     Library General Public License for more details.
68
69     You should have received a copy of the GNU Library General Public License
70     along with this library; see the file COPYING.LIB.  If not, write to
71     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
72     Boston, MA 02110-1301, USA.
73 */
74 EOF
75
76 sub GenerateModule {
77 }
78
79 sub GetParentClassName {
80     my $dataNode = shift;
81
82     return "WebKitDOMObject" if @{$dataNode->parents} eq 0;
83     return "WebKitDOM" . $codeGenerator->StripModule($dataNode->parents(0));
84 }
85
86 # From String::CamelCase 0.01
87 sub camelize
88 {
89         my $s = shift;
90         join('', map{ ucfirst $_ } split(/(?<=[A-Za-z])_(?=[A-Za-z])|\b/, $s));
91 }
92
93 sub decamelize
94 {
95         my $s = shift;
96         $s =~ s{([^a-zA-Z]?)([A-Z]*)([A-Z])([a-z]?)}{
97                 my $fc = pos($s)==0;
98                 my ($p0,$p1,$p2,$p3) = ($1,lc$2,lc$3,$4);
99                 my $t = $p0 || $fc ? $p0 : '_';
100                 $t .= $p3 ? $p1 ? "${p1}_$p2$p3" : "$p2$p3" : "$p1$p2";
101                 $t;
102         }ge;
103         $s;
104 }
105
106 sub FixUpDecamelizedName {
107     my $classname = shift;
108
109     # FIXME: try to merge this somehow with the fixes in ClassNameToGobjectType
110     $classname =~ s/x_path/xpath/;
111     $classname =~ s/web_kit/webkit/;
112     $classname =~ s/htmli_frame/html_iframe/;
113
114     return $classname;
115 }
116
117 sub ClassNameToGObjectType {
118     my $className = shift;
119     my $CLASS_NAME = uc(decamelize($className));
120     # Fixup: with our prefix being 'WebKitDOM' decamelize can't get
121     # WebKitDOMCSS and similar names right, so we have to fix it
122     # manually.
123     $CLASS_NAME =~ s/DOMCSS/DOM_CSS/;
124     $CLASS_NAME =~ s/DOMHTML/DOM_HTML/;
125     $CLASS_NAME =~ s/DOMDOM/DOM_DOM/;
126     $CLASS_NAME =~ s/DOMCDATA/DOM_CDATA/;
127     $CLASS_NAME =~ s/DOMX_PATH/DOM_XPATH/;
128     $CLASS_NAME =~ s/DOM_WEB_KIT/DOM_WEBKIT/;
129     $CLASS_NAME =~ s/DOMUI/DOM_UI/;
130     $CLASS_NAME =~ s/HTMLI_FRAME/HTML_IFRAME/;
131     return $CLASS_NAME;
132 }
133
134 sub GetParentGObjType {
135     my $dataNode = shift;
136
137     return "WEBKIT_TYPE_DOM_OBJECT" if @{$dataNode->parents} eq 0;
138     return "WEBKIT_TYPE_DOM_" . ClassNameToGObjectType($codeGenerator->StripModule($dataNode->parents(0)));
139 }
140
141 sub GetClassName {
142     my $name = $codeGenerator->StripModule(shift);
143
144     return "WebKitDOM$name";
145 }
146
147 sub GetCoreObject {
148     my ($interfaceName, $name, $parameter) = @_;
149
150     return "WebCore::${interfaceName}* $name = WebKit::core($parameter);";
151 }
152
153 sub SkipAttribute {
154     my $attribute = shift;
155     
156     if ($attribute->signature->extendedAttributes->{"CustomGetter"} ||
157         $attribute->signature->extendedAttributes->{"CustomSetter"}) {
158         return 1;
159     }
160
161     my $propType = $attribute->signature->type;
162     if ($propType =~ /Constructor$/) {
163         return 1;
164     }
165
166     # This is for DOMWindow.idl location attribute
167     if ($attribute->signature->name eq "location") {
168         return 1;
169     }
170
171     # This is for HTMLInput.idl valueAsDate
172     if ($attribute->signature->name eq "valueAsDate") {
173         return 1;
174     }
175
176     # This is for DOMWindow.idl Crypto attribute
177     if ($attribute->signature->type eq "Crypto") {
178         return 1;
179     }
180
181     return 0;
182 }
183
184 sub SkipFunction {
185     my $function = shift;
186     my $decamelize = shift;
187     my $prefix = shift;
188
189     my $functionName = "webkit_dom_" . $decamelize . "_" . $prefix . decamelize($function->signature->name);
190     my $isCustomFunction = $function->signature->extendedAttributes->{"Custom"} ||
191         $function->signature->extendedAttributes->{"CustomArgumentHandling"};
192
193     if ($isCustomFunction &&
194         $functionName ne "webkit_dom_node_replace_child" &&
195         $functionName ne "webkit_dom_node_insert_before" &&
196         $functionName ne "webkit_dom_node_remove_child" &&
197         $functionName ne "webkit_dom_node_append_child" &&
198         $functionName ne "webkit_dom_html_collection_item" &&
199         $functionName ne "webkit_dom_html_collection_named_item") {
200         return 1;
201     }
202
203     if ($function->signature->name eq "getSVGDocument") {
204         return 1;
205     }
206
207     if ($function->signature->name eq "getCSSCanvasContext") {
208         return 1;
209     }
210
211     # Skip functions that have ["Callback"] parameters, because this
212     # code generator doesn't know how to auto-generate callbacks.
213     # Skip functions that have "MediaQueryListListener" parameters, because this
214     # code generator doesn't know how to auto-generate MediaQueryListListener.
215     foreach my $param (@{$function->parameters}) {
216         if ($param->extendedAttributes->{"Callback"} ||
217             $param->type eq "MediaQueryListListener") {
218             return 1;
219         }
220     }
221
222     return 0;
223 }
224
225 # Name type used in the g_value_{set,get}_* functions
226 sub GetGValueTypeName {
227     my $type = shift;
228
229     my %types = ("DOMString", "string",
230                  "DOMTimeStamp", "uint",
231                  "float", "float",
232                  "double", "double",
233                  "boolean", "boolean",
234                  "char", "char",
235                  "long", "long",
236                  "long long", "int64",
237                  "short", "int",
238                  "uchar", "uchar",
239                  "unsigned", "uint",
240                  "int", "int",
241                  "unsigned int", "uint",
242                  "unsigned long long", "uint64", 
243                  "unsigned long", "ulong",
244                  "unsigned short", "uint");
245
246     return $types{$type} ? $types{$type} : "object";
247 }
248
249 # Name type used in C declarations
250 sub GetGlibTypeName {
251     my $type = shift;
252     my $name = GetClassName($type);
253
254     my %types = ("DOMString", "gchar*",
255                  "DOMTimeStamp", "guint32",
256                  "CompareHow", "gushort",
257                  "float", "gfloat",
258                  "double", "gdouble",
259                  "boolean", "gboolean",
260                  "char", "gchar",
261                  "long", "glong",
262                  "long long", "gint64",
263                  "short", "gshort",
264                  "uchar", "guchar",
265                  "unsigned", "guint",
266                  "int", "gint",
267                  "unsigned int", "guint",
268                  "unsigned long", "gulong",
269                  "unsigned long long", "guint64",
270                  "unsigned short", "gushort",
271                  "void", "void");
272
273     return $types{$type} ? $types{$type} : "$name*";
274 }
275
276 sub IsGDOMClassType {
277     my $type = shift;
278
279     return 0 if $codeGenerator->IsNonPointerType($type) || $codeGenerator->IsStringType($type);
280     return 1;
281 }
282
283 sub GetReadableProperties {
284     my $properties = shift;
285
286     my @result = ();
287
288     foreach my $property (@{$properties}) {
289         if (!SkipAttribute($property)) {
290             push(@result, $property);
291         }
292     }
293
294     return @result;
295 }
296
297 sub GetWriteableProperties {
298     my $properties = shift;
299     my @result = ();
300
301     foreach my $property (@{$properties}) {
302         my $writeable = $property->type !~ /^readonly/;
303         my $gtype = GetGValueTypeName($property->signature->type);
304         my $hasGtypeSignature = ($gtype eq "boolean" || $gtype eq "float" || $gtype eq "double" ||
305                                  $gtype eq "uint64" || $gtype eq "ulong" || $gtype eq "long" || 
306                                  $gtype eq "uint" || $gtype eq "ushort" || $gtype eq "uchar" ||
307                                  $gtype eq "char" || $gtype eq "string");
308         # FIXME: We are not generating setters for 'Replaceable'
309         # attributes now, but we should somehow.
310         my $replaceable = $property->signature->extendedAttributes->{"Replaceable"};
311         if ($writeable && $hasGtypeSignature && !$replaceable) {
312             push(@result, $property);
313         }
314     }
315
316     return @result;
317 }
318
319 sub GenerateConditionalString
320 {
321     my $node = shift;
322     my $conditional = $node->extendedAttributes->{"Conditional"};
323     if ($conditional) {
324         if ($conditional =~ /&/) {
325             return "ENABLE(" . join(") && ENABLE(", split(/&/, $conditional)) . ")";
326         } elsif ($conditional =~ /\|/) {
327             return "ENABLE(" . join(") || ENABLE(", split(/\|/, $conditional)) . ")";
328         } else {
329             return "ENABLE(" . $conditional . ")";
330         }
331     } else {
332         return "";
333     }
334 }
335
336 sub GenerateProperty {
337     my $attribute = shift;
338     my $interfaceName = shift;
339     my @writeableProperties = @{shift @_};
340
341     my $conditionalString = GenerateConditionalString($attribute->signature);
342     my $camelPropName = $attribute->signature->name;
343     my $setPropNameFunction = $codeGenerator->WK_ucfirst($camelPropName);
344     my $getPropNameFunction = $codeGenerator->WK_lcfirst($camelPropName);
345
346     my $propName = decamelize($camelPropName);
347     my $propNameCaps = uc($propName);
348     $propName =~ s/_/-/g;
349     my ${propEnum} = "PROP_${propNameCaps}";
350     push(@cBodyPriv, "#if ${conditionalString}\n") if $conditionalString;
351     push(@cBodyPriv, "    ${propEnum},\n");
352     push(@cBodyPriv, "#endif /* ${conditionalString} */\n") if $conditionalString;
353
354     my $propType = $attribute->signature->type;
355     my ${propGType} = decamelize($propType);
356     my ${ucPropGType} = uc($propGType);
357
358     my $gtype = GetGValueTypeName($propType);
359     my $gparamflag = "WEBKIT_PARAM_READABLE";
360     my $writeable = $attribute->type !~ /^readonly/;
361     my $const = "read-only ";
362     my $custom = $attribute->signature->extendedAttributes->{"Custom"};
363     if ($writeable && $custom) {
364         $const = "read-only (due to custom functions needed in webkitdom)";
365         return;
366     }
367     if ($writeable && !$custom) {
368         $gparamflag = "WEBKIT_PARAM_READWRITE";
369         $const = "read-write ";
370     }
371
372     my $type = GetGlibTypeName($propType);
373     $nick = decamelize("${interfaceName}_${propName}");
374     $long = "${const} ${type} ${interfaceName}.${propName}";
375
376     my $convertFunction = "";
377     if ($gtype eq "string") {
378         $convertFunction = "WTF::String::fromUTF8";
379     }
380
381     my ($getterFunctionName, @getterArguments) = $codeGenerator->GetterExpression(\%implIncludes, $interfaceName, $attribute);
382     my ($setterFunctionName, @setterArguments) = $codeGenerator->SetterExpression(\%implIncludes, $interfaceName, $attribute);
383
384     if ($attribute->signature->extendedAttributes->{"ImplementedBy"}) {
385         my $implementedBy = $attribute->signature->extendedAttributes->{"ImplementedBy"};
386         $implIncludes{"${implementedBy}.h"} = 1;
387         push(@setterArguments, "${convertFunction}(g_value_get_$gtype(value))");
388         unshift(@getterArguments, "coreSelf");
389         unshift(@setterArguments, "coreSelf");
390         $getterFunctionName = "${implementedBy}::$getterFunctionName";
391         $setterFunctionName = "${implementedBy}::$setterFunctionName";
392     } else {
393         push(@setterArguments, "${convertFunction}(g_value_get_$gtype(value))");
394         $getterFunctionName = "coreSelf->$getterFunctionName";
395         $setterFunctionName = "coreSelf->$setterFunctionName";
396     }
397     push(@getterArguments, "ec") if @{$attribute->getterExceptions};
398     push(@setterArguments, "ec") if @{$attribute->setterExceptions};
399
400     if (grep {$_ eq $attribute} @writeableProperties) {
401         push(@txtSetProps, "#if ${conditionalString}\n") if $conditionalString;
402         push(@txtSetProps, "    case ${propEnum}:\n    {\n");
403         push(@txtSetProps, "        WebCore::ExceptionCode ec = 0;\n") if @{$attribute->setterExceptions};
404         push(@txtSetProps, "        ${setterFunctionName}(" . join(", ", @setterArguments) . ");\n");
405         push(@txtSetProps, "        break;\n    }\n");
406         push(@txtSetProps, "#endif /* ${conditionalString} */\n") if $conditionalString;
407     }
408
409     push(@txtGetProps, "#if ${conditionalString}\n") if $conditionalString;
410     push(@txtGetProps, "    case ${propEnum}:\n    {\n");
411     push(@txtGetProps, "        WebCore::ExceptionCode ec = 0;\n") if @{$attribute->getterExceptions};
412
413     my $postConvertFunction = "";
414     my $done = 0;
415     if ($gtype eq "string") {
416         push(@txtGetProps, "        g_value_take_string(value, convertToUTF8String(${getterFunctionName}(" . join(", ", @getterArguments) . ")));\n");
417         $done = 1;
418     } elsif ($gtype eq "object") {
419         push(@txtGetProps, "        RefPtr<WebCore::${propType}> ptr = coreSelf->${getPropNameFunction}(" . (@{$attribute->getterExceptions} ? "ec" : "") . ");\n");
420         push(@txtGetProps, "        g_value_set_object(value, WebKit::kit(ptr.get()));\n");
421         $done = 1;
422     }
423
424     # FIXME: get rid of this glitch?
425     my $_gtype = $gtype;
426     if ($gtype eq "ushort") {
427         $_gtype = "uint";
428     }
429
430     if (!$done) {
431         if ($attribute->signature->extendedAttributes->{"ImplementedBy"}) {
432             my $implementedBy = $attribute->signature->extendedAttributes->{"ImplementedBy"};
433             $implIncludes{"${implementedBy}.h"} = 1;
434             push(@txtGetProps, "        g_value_set_$_gtype(value, ${convertFunction}${getterFunctionName}(" . join(", ", @getterArguments) .  ")${postConvertFunction});\n");
435         } else {
436             push(@txtGetProps, "        g_value_set_$_gtype(value, ${convertFunction}${getterFunctionName}(" . join(", ", @getterArguments) . ")${postConvertFunction});\n");
437         }
438     }
439
440     push(@txtGetProps, "        break;\n    }\n");
441     push(@txtGetProps, "#endif /* ${conditionalString} */\n") if $conditionalString;
442
443     my %param_spec_options = ("int", "G_MININT, /* min */\nG_MAXINT, /* max */\n0, /* default */",
444                               "boolean", "FALSE, /* default */",
445                               "float", "-G_MAXFLOAT, /* min */\nG_MAXFLOAT, /* max */\n0.0, /* default */",
446                               "double", "-G_MAXDOUBLE, /* min */\nG_MAXDOUBLE, /* max */\n0.0, /* default */",
447                               "uint64", "0, /* min */\nG_MAXUINT64, /* min */\n0, /* default */",
448                               "long", "G_MINLONG, /* min */\nG_MAXLONG, /* max */\n0, /* default */",
449                               "int64", "G_MININT64, /* min */\nG_MAXINT64, /* max */\n0, /* default */",
450                               "ulong", "0, /* min */\nG_MAXULONG, /* max */\n0, /* default */",
451                               "uint", "0, /* min */\nG_MAXUINT, /* max */\n0, /* default */",
452                               "ushort", "0, /* min */\nG_MAXUINT16, /* max */\n0, /* default */",
453                               "uchar", "G_MININT8, /* min */\nG_MAXINT8, /* max */\n0, /* default */",
454                               "char", "0, /* min */\nG_MAXUINT8, /* max */\n0, /* default */",
455                               "string", "\"\", /* default */",
456                               "object", "WEBKIT_TYPE_DOM_${ucPropGType}, /* gobject type */");
457
458     my $txtInstallProp = << "EOF";
459     g_object_class_install_property(gobjectClass,
460                                     ${propEnum},
461                                     g_param_spec_${_gtype}("${propName}", /* name */
462                                                            "$nick", /* short description */
463                                                            "$long", /* longer - could do with some extra doc stuff here */
464                                                            $param_spec_options{$gtype}
465                                                            ${gparamflag}));
466 EOF
467     push(@txtInstallProps, "#if ${conditionalString}\n") if $conditionalString;
468     push(@txtInstallProps, $txtInstallProp);
469     push(@txtInstallProps, "#endif /* ${conditionalString} */\n") if $conditionalString;
470 }
471
472 sub GenerateProperties {
473     my ($object, $interfaceName, $dataNode) = @_;
474
475     my $clsCaps = substr(ClassNameToGObjectType($className), 12);
476     my $lowerCaseIfaceName = "webkit_dom_" . (FixUpDecamelizedName(decamelize($interfaceName)));
477
478     # Properties
479     my $implContent = "";
480
481     # Properties
482     $implContent = << "EOF";
483 enum {
484     PROP_0,
485 EOF
486     push(@cBodyPriv, $implContent);
487
488     my @readableProperties = GetReadableProperties($dataNode->attributes);
489
490     my $privFunction = GetCoreObject($interfaceName, "coreSelf", "self");
491
492     my $txtGetProp = << "EOF";
493 static void ${lowerCaseIfaceName}_get_property(GObject* object, guint prop_id, GValue* value, GParamSpec* pspec)
494 {
495     WebCore::JSMainThreadNullState state;
496 EOF
497     push(@txtGetProps, $txtGetProp);
498     if (scalar @readableProperties > 0) {
499         $txtGetProp = << "EOF";
500     ${className}* self = WEBKIT_DOM_${clsCaps}(object);
501     $privFunction
502 EOF
503     push(@txtGetProps, $txtGetProp);
504     }
505
506     $txtGetProp = << "EOF";
507     switch (prop_id) {
508 EOF
509     push(@txtGetProps, $txtGetProp);
510
511     my @writeableProperties = GetWriteableProperties(\@readableProperties);
512
513     my $txtSetProps = << "EOF";
514 static void ${lowerCaseIfaceName}_set_property(GObject* object, guint prop_id, const GValue* value, GParamSpec* pspec)
515 {
516     WebCore::JSMainThreadNullState state;
517 EOF
518     push(@txtSetProps, $txtSetProps);
519
520     if (scalar @writeableProperties > 0) {
521         $txtSetProps = << "EOF";
522     ${className}* self = WEBKIT_DOM_${clsCaps}(object);
523     $privFunction
524 EOF
525         push(@txtSetProps, $txtSetProps);
526     }
527
528     $txtSetProps = << "EOF";
529     switch (prop_id) {
530 EOF
531     push(@txtSetProps, $txtSetProps);
532
533     foreach my $attribute (@readableProperties) {
534         if ($attribute->signature->type ne "EventListener" &&
535             $attribute->signature->type ne "MediaQueryListListener") {
536             GenerateProperty($attribute, $interfaceName, \@writeableProperties);
537         }
538     }
539
540     push(@cBodyPriv, "};\n\n");
541
542     $txtGetProp = << "EOF";
543     default:
544         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
545         break;
546     }
547 }
548 EOF
549     push(@txtGetProps, $txtGetProp);
550
551     $txtSetProps = << "EOF";
552     default:
553         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
554         break;
555     }
556 }
557 EOF
558     push(@txtSetProps, $txtSetProps);
559
560     # Do not insert extra spaces when interpolating array variables
561     $" = "";
562
563     $implContent = << "EOF";
564
565 static void ${lowerCaseIfaceName}_finalize(GObject* object)
566 {
567     WebKitDOMObject* dom_object = WEBKIT_DOM_OBJECT(object);
568     
569     if (dom_object->coreObject) {
570         WebCore::${interfaceName}* coreObject = static_cast<WebCore::${interfaceName} *>(dom_object->coreObject);
571
572         WebKit::DOMObjectCache::forget(coreObject);
573         coreObject->deref();
574
575         dom_object->coreObject = NULL;
576     }
577
578     G_OBJECT_CLASS(${lowerCaseIfaceName}_parent_class)->finalize(object);
579 }
580
581 @txtSetProps
582
583 @txtGetProps
584
585 static void ${lowerCaseIfaceName}_constructed(GObject* object)
586 {
587 EOF
588     push(@cBodyPriv, $implContent);
589
590     $implContent = << "EOF";
591 @txtInstallEventListeners
592     if (G_OBJECT_CLASS(${lowerCaseIfaceName}_parent_class)->constructed)
593         G_OBJECT_CLASS(${lowerCaseIfaceName}_parent_class)->constructed(object);
594 }
595
596 static void ${lowerCaseIfaceName}_class_init(${className}Class* requestClass)
597 {
598     GObjectClass *gobjectClass = G_OBJECT_CLASS(requestClass);
599     gobjectClass->finalize = ${lowerCaseIfaceName}_finalize;
600     gobjectClass->set_property = ${lowerCaseIfaceName}_set_property;
601     gobjectClass->get_property = ${lowerCaseIfaceName}_get_property;
602     gobjectClass->constructed = ${lowerCaseIfaceName}_constructed;
603
604 @txtInstallProps
605 @txtInstallSignals
606 }
607
608 static void ${lowerCaseIfaceName}_init(${className}* request)
609 {
610 }
611
612 EOF
613     push(@cBodyPriv, $implContent);
614 }
615
616 sub GenerateHeader {
617     my ($object, $interfaceName, $parentClassName) = @_;
618
619     my $implContent = "";
620
621     # Add the default header template
622     @hPrefix = split("\r", $licenceTemplate);
623     push(@hPrefix, "\n");
624
625     #Header guard
626     my $guard = $className . "_h";
627
628     @hPrefixGuard = << "EOF";
629 #ifndef $guard
630 #define $guard
631
632 EOF
633
634     $implContent = << "EOF";
635 G_BEGIN_DECLS
636 EOF
637
638     push(@hBodyPre, $implContent);
639
640     my $decamelize = FixUpDecamelizedName(decamelize($interfaceName));
641     my $clsCaps = uc($decamelize);
642     my $lowerCaseIfaceName = "webkit_dom_" . ($decamelize);
643
644     $implContent = << "EOF";
645 #define WEBKIT_TYPE_DOM_${clsCaps}            (${lowerCaseIfaceName}_get_type())
646 #define WEBKIT_DOM_${clsCaps}(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), WEBKIT_TYPE_DOM_${clsCaps}, ${className}))
647 #define WEBKIT_DOM_${clsCaps}_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass),  WEBKIT_TYPE_DOM_${clsCaps}, ${className}Class)
648 #define WEBKIT_DOM_IS_${clsCaps}(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), WEBKIT_TYPE_DOM_${clsCaps}))
649 #define WEBKIT_DOM_IS_${clsCaps}_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),  WEBKIT_TYPE_DOM_${clsCaps}))
650 #define WEBKIT_DOM_${clsCaps}_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj),  WEBKIT_TYPE_DOM_${clsCaps}, ${className}Class))
651
652 struct _${className} {
653     ${parentClassName} parent_instance;
654 };
655
656 struct _${className}Class {
657     ${parentClassName}Class parent_class;
658 };
659
660 WEBKIT_API GType
661 ${lowerCaseIfaceName}_get_type (void);
662
663 EOF
664
665     push(@hBody, $implContent);
666 }
667
668 sub getIncludeHeader {
669     my $type = shift;
670     my $name = GetClassName($type);
671
672     return "" if $type eq "int";
673     return "" if $type eq "long";
674     return "" if $type eq "long long";
675     return "" if $type eq "short";
676     return "" if $type eq "char";
677     return "" if $type eq "float";
678     return "" if $type eq "double";
679     return "" if $type eq "unsigned";
680     return "" if $type eq "unsigned int";
681     return "" if $type eq "unsigned long";
682     return "" if $type eq "unsigned long long";
683     return "" if $type eq "unsigned short";
684     return "" if $type eq "DOMTimeStamp";
685     return "" if $type eq "EventListener";
686     return "" if $type eq "MediaQueryListListener";
687     return "" if $type eq "unsigned char";
688     return "" if $type eq "DOMString";
689     return "" if $type eq "float";
690     return "" if $type eq "boolean";
691     return "" if $type eq "void";
692     return "" if $type eq "CompareHow";
693
694     return "$name.h";
695 }
696
697 sub addIncludeInBody {
698     my $type = shift;
699
700     if ($type eq "DOMObject") {
701         return;
702     }
703
704     my $header = getIncludeHeader($type);
705     if ($header eq "") {
706         return;
707     }
708     
709     if (IsGDOMClassType($type)) {
710         $implIncludes{"webkit/$header"} = 1;
711     } else {
712         $implIncludes{$header} = 1
713     }
714 }
715
716 sub GenerateFunction {
717     my ($object, $interfaceName, $function, $prefix) = @_;
718
719     my $decamelize = FixUpDecamelizedName(decamelize($interfaceName));
720
721     if ($object eq "MediaQueryListListener") {
722         return;
723     }
724
725     if (SkipFunction($function, $decamelize, $prefix)) {
726         return;
727     }
728
729     my $functionSigName = $function->signature->name;
730     my $functionSigType = $prefix eq "set_" ? "void" : $function->signature->type;
731     my $functionName = "webkit_dom_" . $decamelize . "_" . $prefix . decamelize($functionSigName);
732     my $returnType = GetGlibTypeName($functionSigType);
733     my $returnValueIsGDOMType = IsGDOMClassType($functionSigType);
734     my $conditionalString = GenerateConditionalString($function->signature);
735
736     my $functionSig = "${className}* self";
737
738     my @callImplParams;
739
740     # skip some custom functions for now
741     my $isCustomFunction = $function->signature->extendedAttributes->{"Custom"} ||
742                        $function->signature->extendedAttributes->{"CustomArgumentHandling"};
743
744     foreach my $param (@{$function->parameters}) {
745         my $paramIDLType = $param->type;
746         if ($paramIDLType eq "EventListener" || $paramIDLType eq "MediaQueryListListener") {
747             # EventListeners are handled elsewhere.
748             return;
749         }
750         addIncludeInBody($paramIDLType);
751         my $paramType = GetGlibTypeName($paramIDLType);
752         my $const = $paramType eq "gchar*" ? "const " : "";
753         my $paramName = decamelize($param->name);
754
755         $functionSig .= ", ${const}$paramType $paramName";
756
757         my $paramIsGDOMType = IsGDOMClassType($paramIDLType);
758         if ($paramIsGDOMType) {
759             if ($paramIDLType ne "DOMObject") {
760                 $implIncludes{"webkit/WebKitDOM${paramIDLType}Private.h"} = 1;
761             }
762         }
763         if ($paramIsGDOMType || ($paramIDLType eq "DOMString") || ($paramIDLType eq "CompareHow")) {
764             $paramName = "converted_" . $paramName;
765         }
766         push(@callImplParams, $paramName);
767     }
768
769     if ($returnType ne "void" && $returnValueIsGDOMType && $functionSigType ne "DOMObject") {
770         if ($functionSigType ne "EventTarget") {
771             $implIncludes{"webkit/WebKitDOM${functionSigType}Private.h"} = 1;
772             $implIncludes{"webkit/WebKitDOM${functionSigType}.h"} = 1;
773         } else {
774             $implIncludes{"WebKitDOM${functionSigType}.h"} = 1;
775         }
776
777         $implIncludes{"${functionSigType}.h"} = 1;
778     }
779
780     if(@{$function->raisesExceptions}) {
781         $functionSig .= ", GError **error";
782     }
783
784     # Insert introspection annotations
785     push(@hBody, "/**\n");
786     push(@hBody, " * ${functionName}:\n");
787     push(@hBody, " * \@self: A #${className}\n");
788
789     foreach my $param (@{$function->parameters}) {
790         my $paramType = GetGlibTypeName($param->type);
791         # $paramType can have a trailing * in some cases
792         $paramType =~ s/\*$//;
793         my $paramName = decamelize($param->name);
794         push(@hBody, " * \@${paramName}: A #${paramType}\n");
795     }
796     if(@{$function->raisesExceptions}) {
797         push(@hBody, " * \@error: #GError\n");
798     }
799     push(@hBody, " *\n");
800     if (IsGDOMClassType($function->signature->type)) {
801         push(@hBody, " * Returns: (transfer none):\n");
802     } else {
803         push(@hBody, " * Returns:\n");
804     }
805     push(@hBody, " *\n");
806     push(@hBody, "**/\n");
807
808     push(@hBody, "WEBKIT_API $returnType\n$functionName($functionSig);\n");
809     push(@hBody, "\n");
810
811     push(@cBody, "$returnType\n$functionName($functionSig)\n{\n");
812     push(@cBody, "#if ${conditionalString}\n") if $conditionalString;
813
814     if ($returnType ne "void") {
815         # TODO: return proper default result
816         push(@cBody, "    g_return_val_if_fail(self, 0);\n");
817     } else {
818         push(@cBody, "    g_return_if_fail(self);\n");
819     }
820
821     push(@cBody, "    WebCore::JSMainThreadNullState state;\n");
822
823     # The WebKit::core implementations check for NULL already; no need to
824     # duplicate effort.
825     push(@cBody, "    WebCore::${interfaceName} * item = WebKit::core(self);\n");
826
827     foreach my $param (@{$function->parameters}) {
828         my $paramName = decamelize($param->name);
829         my $paramIDLType = $param->type;
830         my $paramTypeIsPrimitive = $codeGenerator->IsPrimitiveType($paramIDLType);
831         my $paramIsGDOMType = IsGDOMClassType($paramIDLType);
832         if (!$paramTypeIsPrimitive) {
833             if ($returnType ne "void") {
834                 # TODO: return proper default result
835                 # FIXME: Temporary hack for generating a proper implementation
836                 #        of the webkit_dom_document_evaluate function (Bug-ID: 42115)
837                 if (!(($functionName eq "webkit_dom_document_evaluate") && ($paramIDLType eq "XPathResult"))) {
838                     push(@cBody, "    g_return_val_if_fail($paramName, 0);\n");
839                 }
840             } else {
841                 push(@cBody, "    g_return_if_fail($paramName);\n");
842             }
843         }
844     }
845
846     $returnParamName = "";
847     foreach my $param (@{$function->parameters}) {
848         my $paramIDLType = $param->type;
849         my $paramName = decamelize($param->name);
850
851         my $paramIsGDOMType = IsGDOMClassType($paramIDLType);
852         if ($paramIDLType eq "DOMString") {
853             push(@cBody, "    WTF::String converted_${paramName} = WTF::String::fromUTF8($paramName);\n");
854         } elsif ($paramIDLType eq "CompareHow") {
855             push(@cBody, "    WebCore::Range::CompareHow converted_${paramName} = static_cast<WebCore::Range::CompareHow>($paramName);\n");
856         } elsif ($paramIsGDOMType) {
857             push(@cBody, "    WebCore::${paramIDLType} * converted_${paramName} = NULL;\n");
858             push(@cBody, "    if (${paramName} != NULL) {\n");
859             push(@cBody, "        converted_${paramName} = WebKit::core($paramName);\n");
860
861             if ($returnType ne "void") {
862                 # TODO: return proper default result
863                 push(@cBody, "        g_return_val_if_fail(converted_${paramName}, 0);\n");
864             } else {
865                 push(@cBody, "        g_return_if_fail(converted_${paramName});\n");
866             }
867
868             push(@cBody, "    }\n");
869         }
870         $returnParamName = "converted_".$paramName if $param->extendedAttributes->{"Return"};
871     }
872
873     my $assign = "";
874     my $assignPre = "";
875     my $assignPost = "";
876
877     # We need to special-case these Node methods because their C++
878     # signature is different from what we'd expect given their IDL
879     # description; see Node.h.
880     my $functionHasCustomReturn = $functionName eq "webkit_dom_node_append_child" ||
881         $functionName eq "webkit_dom_node_insert_before" ||
882         $functionName eq "webkit_dom_node_replace_child" ||
883         $functionName eq "webkit_dom_node_remove_child";
884         
885     if ($returnType ne "void" && !$functionHasCustomReturn) {
886         if ($returnValueIsGDOMType) {
887             $assign = "PassRefPtr<WebCore::${functionSigType}> g_res = ";
888             $assignPre = "WTF::getPtr(";
889             $assignPost = ")";
890         } else {
891             $assign = "${returnType} res = ";
892         }
893     }
894
895     if (@{$function->raisesExceptions}) {
896         push(@cBody, "    WebCore::ExceptionCode ec = 0;\n") ;
897         push(@callImplParams, "ec");
898     }
899
900     if ($functionHasCustomReturn) {
901         push(@cBody, "    bool ok = item->${functionSigName}(" . join(", ", @callImplParams) . ");\n");
902         my $customNodeAppendChild = << "EOF";
903     if (ok)
904     {
905         ${returnType} res = WebKit::kit($returnParamName);
906         return res;
907     }
908 EOF
909         push(@cBody, $customNodeAppendChild);
910     
911         if(@{$function->raisesExceptions}) {
912             my $exceptionHandling = << "EOF";
913
914     WebCore::ExceptionCodeDescription ecdesc(ec);
915     g_set_error_literal(error, g_quark_from_string("WEBKIT_DOM"), ecdesc.code, ecdesc.name);
916 EOF
917             push(@cBody, $exceptionHandling);
918         }
919         push(@cBody, "return NULL;");
920         push(@cBody, "}\n\n");
921         return;
922     } elsif ($functionSigType eq "DOMString") {
923         my $getterContentHead;
924         if ($prefix) {
925             my ($functionName, @arguments) = $codeGenerator->GetterExpression(\%implIncludes, $interfaceName, $function);
926             push(@arguments, @callImplParams);
927             if ($function->signature->extendedAttributes->{"ImplementedBy"}) {
928                 my $implementedBy = $function->signature->extendedAttributes->{"ImplementedBy"};
929                 $implIncludes{"${implementedBy}.h"} = 1;
930                 unshift(@arguments, "item");
931                 $functionName = "${implementedBy}::${functionName}";
932             } else {
933                 $functionName = "item->${functionName}";
934             }
935             $getterContentHead = "${assign}convertToUTF8String(${functionName}(" . join(", ", @arguments) . "));\n";
936         } else {
937             my @arguments = @callImplParams;
938             if ($function->signature->extendedAttributes->{"ImplementedBy"}) {
939                 my $implementedBy = $function->signature->extendedAttributes->{"ImplementedBy"};
940                 $implIncludes{"${implementedBy}.h"} = 1;
941                 unshift(@arguments, "item");
942                 $getterContentHead = "${assign}convertToUTF8String(${implementedBy}::${functionSigName}(" . join(", ", @arguments) . "));\n";
943             } else {
944                 $getterContentHead = "${assign}convertToUTF8String(item->${functionSigName}(" . join(", ", @arguments) . "));\n";
945             }
946         }
947         push(@cBody, "    ${getterContentHead}");
948     } else {
949         my $contentHead;
950         if ($prefix eq "get_") {
951             my ($functionName, @arguments) = $codeGenerator->GetterExpression(\%implIncludes, $interfaceName, $function);
952             push(@arguments, @callImplParams);
953             if ($function->signature->extendedAttributes->{"ImplementedBy"}) {
954                 my $implementedBy = $function->signature->extendedAttributes->{"ImplementedBy"};
955                 $implIncludes{"${implementedBy}.h"} = 1;
956                 unshift(@arguments, "item");
957                 $functionName = "${implementedBy}::${functionName}";
958             } else {
959                 $functionName = "item->${functionName}";
960             }
961             $contentHead = "${assign}${assignPre}${functionName}(" . join(", ", @arguments) . "${assignPost});\n";
962         } elsif ($prefix eq "set_") {
963             my ($functionName, @arguments) = $codeGenerator->SetterExpression(\%implIncludes, $interfaceName, $function);
964             push(@arguments, @callImplParams);
965             if ($function->signature->extendedAttributes->{"ImplementedBy"}) {
966                 my $implementedBy = $function->signature->extendedAttributes->{"ImplementedBy"};
967                 $implIncludes{"${implementedBy}.h"} = 1;
968                 unshift(@arguments, "item");
969                 $functionName = "${implementedBy}::${functionName}";
970                 $contentHead = "${assign}${assignPre}${functionName}(" . join(", ", @arguments) . "${assignPost});\n";
971             } else {
972                 $functionName = "item->${functionName}";
973                 $contentHead = "${assign}${assignPre}${functionName}(" . join(", ", @arguments) . "${assignPost});\n";
974             }
975         } else {
976             my @arguments = @callImplParams;
977             if ($function->signature->extendedAttributes->{"ImplementedBy"}) {
978                 my $implementedBy = $function->signature->extendedAttributes->{"ImplementedBy"};
979                 $implIncludes{"${implementedBy}.h"} = 1;
980                 unshift(@arguments, "item");
981                 $contentHead = "${assign}${assignPre}${implementedBy}::${functionSigName}(" . join(", ", @arguments) . "${assignPost});\n";
982             } else {
983                 $contentHead = "${assign}${assignPre}item->${functionSigName}(" . join(", ", @arguments) . "${assignPost});\n";
984             }
985         }
986         push(@cBody, "    ${contentHead}");
987         
988         if(@{$function->raisesExceptions}) {
989             my $exceptionHandling = << "EOF";
990     if (ec) {
991         WebCore::ExceptionCodeDescription ecdesc(ec);
992         g_set_error_literal(error, g_quark_from_string("WEBKIT_DOM"), ecdesc.code, ecdesc.name);
993     }
994 EOF
995             push(@cBody, $exceptionHandling);
996         }
997     }
998
999     if ($returnType ne "void" && !$functionHasCustomReturn) {
1000         if ($functionSigType ne "DOMObject") {
1001             if ($returnValueIsGDOMType) {
1002                 push(@cBody, "    ${returnType} res = WebKit::kit(g_res.get());\n");
1003             }
1004         }
1005         if ($functionSigType eq "DOMObject") {
1006             push(@cBody, "    return NULL; /* TODO: return canvas object */\n");
1007         } else {
1008             push(@cBody, "    return res;\n");
1009         }
1010     }
1011
1012     if ($conditionalString) {
1013         if ($returnType ne "void") {
1014             push(@cBody, "#else\n");
1015             if ($codeGenerator->IsNonPointerType($functionSigType)) {
1016                 push(@cBody, "    return static_cast<${returnType}>(0);\n");
1017             } else {
1018                 push(@cBody, "    return NULL;\n");
1019             }
1020         }
1021         push(@cBody, "#endif /* ${conditionalString} */\n") if $conditionalString;
1022     }
1023
1024     push(@cBody, "}\n\n");
1025 }
1026
1027 sub ClassHasFunction {
1028     my ($class, $name) = @_;
1029
1030     foreach my $function (@{$class->functions}) {
1031         if ($function->signature->name eq $name) {
1032             return 1;
1033         }
1034     }
1035
1036     return 0;
1037 }
1038
1039 sub GenerateFunctions {
1040     my ($object, $interfaceName, $dataNode) = @_;
1041
1042     foreach my $function (@{$dataNode->functions}) {
1043         $object->GenerateFunction($interfaceName, $function, "");
1044     }
1045
1046     TOP:
1047     foreach my $attribute (@{$dataNode->attributes}) {
1048         if (SkipAttribute($attribute) ||
1049             $attribute->signature->type eq "EventListener" ||
1050             $attribute->signature->type eq "MediaQueryListListener") {
1051             next TOP;
1052         }
1053         
1054         if ($attribute->signature->name eq "type"
1055             # This will conflict with the get_type() function we define to return a GType
1056             # according to GObject conventions.  Skip this for now.
1057             || $attribute->signature->name eq "URL"     # TODO: handle this
1058             ) {
1059             next TOP;
1060         }
1061             
1062         my $attrNameUpper = $codeGenerator->WK_ucfirst($attribute->signature->name);
1063         my $getname = "get${attrNameUpper}";
1064         my $setname = "set${attrNameUpper}";
1065         if (ClassHasFunction($dataNode, $getname) || ClassHasFunction($dataNode, $setname)) {
1066             # Very occasionally an IDL file defines getter/setter functions for one of its
1067             # attributes; in this case we don't need to autogenerate the getter/setter.
1068             next TOP;
1069         }
1070         
1071         # Generate an attribute getter.  For an attribute "foo", this is a function named
1072         # "get_foo" which calls a DOM class method named foo().
1073         my $function = new domFunction();
1074         $function->signature($attribute->signature);
1075         $function->raisesExceptions($attribute->getterExceptions);
1076         $object->GenerateFunction($interfaceName, $function, "get_");
1077
1078         # FIXME: We are not generating setters for 'Replaceable'
1079         # attributes now, but we should somehow.
1080         if ($attribute->type =~ /^readonly/ ||
1081             $attribute->signature->extendedAttributes->{"Replaceable"}) {
1082             next TOP;
1083         }
1084         
1085         # Generate an attribute setter.  For an attribute, "foo", this is a function named
1086         # "set_foo" which calls a DOM class method named setFoo().
1087         $function = new domFunction();
1088         
1089         $function->signature(new domSignature());
1090         $function->signature->name($attribute->signature->name);
1091         $function->signature->type($attribute->signature->type);
1092         $function->signature->extendedAttributes($attribute->signature->extendedAttributes);
1093         
1094         my $param = new domSignature();
1095         $param->name("value");
1096         $param->type($attribute->signature->type);
1097         my %attributes = ();
1098         $param->extendedAttributes("attributes");
1099         my $arrayRef = $function->parameters;
1100         push(@$arrayRef, $param);
1101         
1102         $function->raisesExceptions($attribute->setterExceptions);
1103         
1104         $object->GenerateFunction($interfaceName, $function, "set_");
1105     }
1106 }
1107
1108 sub GenerateCFile {
1109     my ($object, $interfaceName, $parentClassName, $parentGObjType, $dataNode) = @_;
1110
1111     if ($dataNode->extendedAttributes->{"EventTarget"}) {
1112         $object->GenerateEventTargetIface($dataNode);
1113     }
1114
1115     my $implContent = "";
1116
1117     my $clsCaps = uc(FixUpDecamelizedName(decamelize($interfaceName)));
1118     my $lowerCaseIfaceName = "webkit_dom_" . FixUpDecamelizedName(decamelize($interfaceName));
1119
1120     $implContent = << "EOF";
1121 ${defineTypeMacro}(${className}, ${lowerCaseIfaceName}, ${parentGObjType}${defineTypeInterfaceImplementation}
1122
1123 namespace WebKit {
1124
1125 WebCore::${interfaceName}* core(${className}* request)
1126 {
1127     g_return_val_if_fail(request, 0);
1128
1129     WebCore::${interfaceName}* coreObject = static_cast<WebCore::${interfaceName}*>(WEBKIT_DOM_OBJECT(request)->coreObject);
1130     g_return_val_if_fail(coreObject, 0);
1131
1132     return coreObject;
1133 }
1134
1135 } // namespace WebKit
1136 EOF
1137
1138     push(@cBodyPriv, $implContent);
1139     $object->GenerateProperties($interfaceName, $dataNode);
1140     $object->GenerateFunctions($interfaceName, $dataNode);
1141
1142     my $wrapMethod = << "EOF";
1143 namespace WebKit {
1144 ${className}* wrap${interfaceName}(WebCore::${interfaceName}* coreObject)
1145 {
1146     g_return_val_if_fail(coreObject, 0);
1147
1148     /* We call ref() rather than using a C++ smart pointer because we can't store a C++ object
1149      * in a C-allocated GObject structure.  See the finalize() code for the
1150      * matching deref().
1151      */
1152     coreObject->ref();
1153
1154     return  WEBKIT_DOM_${clsCaps}(g_object_new(WEBKIT_TYPE_DOM_${clsCaps},
1155                                                "core-object", coreObject, NULL));
1156 }
1157 } // namespace WebKit
1158 EOF
1159     push(@cBodyPriv, $wrapMethod);
1160 }
1161
1162 sub GenerateEndHeader {
1163     my ($object) = @_;
1164
1165     #Header guard
1166     my $guard = $className . "_h";
1167
1168     push(@hBody, "G_END_DECLS\n\n");
1169     push(@hPrefixGuardEnd, "#endif /* $guard */\n");
1170 }
1171
1172 sub UsesManualKitImplementation {
1173     my $type = shift;
1174
1175     return 1 if $type eq "Node" or $type eq "Element" or $type eq "Event";
1176     return 0;
1177 }
1178
1179 sub GenerateEventTargetIface {
1180     my $object = shift;
1181     my $dataNode = shift;
1182
1183     my $interfaceName = $dataNode->name;
1184     my $decamelize = FixUpDecamelizedName(decamelize($interfaceName));
1185
1186     $implIncludes{"GObjectEventListener.h"} = 1;
1187     $implIncludes{"WebKitDOMEventTarget.h"} = 1;
1188     $implIncludes{"WebKitDOMEventPrivate.h"} = 1;
1189
1190     my $impl = << "EOF";
1191 static void webkit_dom_${decamelize}_dispatch_event(WebKitDOMEventTarget* target, WebKitDOMEvent* event, GError** error)
1192 {
1193     WebCore::Event* coreEvent = WebKit::core(event);
1194     WebCore::${interfaceName}* coreTarget = static_cast<WebCore::${interfaceName}*>(WEBKIT_DOM_OBJECT(target)->coreObject);
1195
1196     WebCore::ExceptionCode ec = 0;
1197     coreTarget->dispatchEvent(coreEvent, ec);
1198     if (ec) {
1199         WebCore::ExceptionCodeDescription description(ec);
1200         g_set_error_literal(error, g_quark_from_string("WEBKIT_DOM"), description.code, description.name);
1201     }
1202 }
1203
1204 static gboolean webkit_dom_${decamelize}_add_event_listener(WebKitDOMEventTarget* target, const char* eventName, GCallback handler, gboolean bubble, gpointer userData)
1205 {
1206     WebCore::${interfaceName}* coreTarget = static_cast<WebCore::${interfaceName}*>(WEBKIT_DOM_OBJECT(target)->coreObject);
1207     return WebCore::GObjectEventListener::addEventListener(G_OBJECT(target), coreTarget, eventName, handler, bubble, userData);
1208 }
1209
1210 static gboolean webkit_dom_${decamelize}_remove_event_listener(WebKitDOMEventTarget* target, const char* eventName, GCallback handler, gboolean bubble)
1211 {
1212     WebCore::${interfaceName}* coreTarget = static_cast<WebCore::${interfaceName}*>(WEBKIT_DOM_OBJECT(target)->coreObject);
1213     return WebCore::GObjectEventListener::removeEventListener(G_OBJECT(target), coreTarget, eventName, handler, bubble);
1214 }
1215
1216 static void webkit_dom_event_target_init(WebKitDOMEventTargetIface* iface)
1217 {
1218     iface->dispatch_event = webkit_dom_${decamelize}_dispatch_event;
1219     iface->add_event_listener = webkit_dom_${decamelize}_add_event_listener;
1220     iface->remove_event_listener = webkit_dom_${decamelize}_remove_event_listener;
1221 }
1222
1223 EOF
1224
1225     push(@cBody, $impl);
1226
1227     $defineTypeMacro = "G_DEFINE_TYPE_WITH_CODE";
1228     $defineTypeInterfaceImplementation = ", G_IMPLEMENT_INTERFACE(WEBKIT_TYPE_DOM_EVENT_TARGET, webkit_dom_event_target_init))";
1229 }
1230
1231 sub Generate {
1232     my ($object, $dataNode) = @_;
1233
1234     my $parentClassName = GetParentClassName($dataNode);
1235     my $parentGObjType = GetParentGObjType($dataNode);
1236     my $interfaceName = $dataNode->name;
1237
1238     # Add the guard if the 'Conditional' extended attribute exists
1239     my $conditionalString = GenerateConditionalString($dataNode);
1240     push(@conditionGuardStart, "#if ${conditionalString}\n\n") if $conditionalString;
1241     push(@conditionGuardEnd, "#endif /* ${conditionalString} */\n") if $conditionalString;
1242
1243     # Add the default impl header template
1244     @cPrefix = split("\r", $licenceTemplate);
1245     push(@cPrefix, "\n");
1246
1247     $implIncludes{"webkitdefines.h"} = 1;
1248     $implIncludes{"webkitglobalsprivate.h"} = 1;
1249     $implIncludes{"webkitmarshal.h"} = 1;
1250     $implIncludes{"DOMObjectCache.h"} = 1;
1251     $implIncludes{"WebKitDOMBinding.h"} = 1;
1252     $implIncludes{"gobject/ConvertToUTF8String.h"} = 1;
1253     $implIncludes{"webkit/$className.h"} = 1;
1254     $implIncludes{"webkit/${className}Private.h"} = 1;
1255     $implIncludes{"${interfaceName}.h"} = 1;
1256     $implIncludes{"JSMainThreadExecState.h"} = 1;
1257     $implIncludes{"ExceptionCode.h"} = 1;
1258
1259     $hdrIncludes{"webkit/${parentClassName}.h"} = 1;
1260
1261     if (!UsesManualKitImplementation($interfaceName)) {
1262         my $converter = << "EOF";
1263 namespace WebKit {
1264     
1265 ${className}* kit(WebCore::$interfaceName* obj)
1266 {
1267     g_return_val_if_fail(obj, 0);
1268
1269     if (gpointer ret = DOMObjectCache::get(obj))
1270         return static_cast<${className}*>(ret);
1271
1272     return static_cast<${className}*>(DOMObjectCache::put(obj, WebKit::wrap${interfaceName}(obj)));
1273 }
1274     
1275 } // namespace WebKit //
1276
1277 EOF
1278     push(@cBody, $converter);
1279     }
1280
1281     $object->GenerateHeader($interfaceName, $parentClassName);
1282     $object->GenerateCFile($interfaceName, $parentClassName, $parentGObjType, $dataNode);
1283     $object->GenerateEndHeader();
1284 }
1285
1286 # Internal helper
1287 sub WriteData {
1288     my $object = shift;
1289     my $dataNode = shift;
1290
1291     # Write a private header.
1292     my $interfaceName = $dataNode->name;
1293     my $filename = "$outputDir/" . $className . "Private.h";
1294     my $guard = uc(decamelize($className)) . "_PRIVATE_H";
1295     my $parentClassName = GetParentClassName($dataNode);
1296
1297     open(PRIVHEADER, ">$filename") or die "Couldn't open file $filename for writing";
1298
1299     print PRIVHEADER split("\r", $licenceTemplate);
1300     print PRIVHEADER "\n";
1301
1302     my $text = << "EOF";
1303 #ifndef $guard
1304 #define $guard
1305
1306 #include <glib-object.h>
1307 #include <webkit/${parentClassName}.h>
1308 #include "${interfaceName}.h"
1309 EOF
1310
1311     print PRIVHEADER $text;
1312     print PRIVHEADER map { "#include \"$_\"\n" } sort keys(%hdrPropIncludes);
1313     print PRIVHEADER "\n" if keys(%hdrPropIncludes);
1314     $text = << "EOF";
1315 namespace WebKit {
1316     ${className} *
1317     wrap${interfaceName}(WebCore::${interfaceName} *coreObject);
1318
1319     WebCore::${interfaceName} *
1320     core(${className} *request);
1321
1322 EOF
1323
1324     print PRIVHEADER $text;
1325
1326     if ($className ne "WebKitDOMNode") {
1327         $text = << "EOF";
1328     ${className}*
1329     kit(WebCore::${interfaceName}* node);
1330
1331 EOF
1332         print PRIVHEADER $text;
1333     }
1334
1335     $text = << "EOF";
1336 } // namespace WebKit
1337
1338 #endif /* ${guard} */
1339 EOF
1340     print PRIVHEADER $text;
1341
1342     close(PRIVHEADER);
1343
1344     my $basename = FileNamePrefix . $interfaceName;
1345     $basename =~ s/_//g;
1346
1347     # Write public header.
1348     my $hdrFName = "$outputDir/" . $basename . ".h";
1349     open(HEADER, ">$hdrFName") or die "Couldn't open file $hdrFName";
1350
1351     print HEADER @hPrefix;
1352     print HEADER @hPrefixGuard;
1353     print HEADER "#include \"webkit/webkitdomdefines.h\"\n";
1354     print HEADER "#include <glib-object.h>\n";
1355     print HEADER "#include <webkit/webkitdefines.h>\n";
1356     print HEADER map { "#include \"$_\"\n" } sort keys(%hdrIncludes);
1357     print HEADER "\n" if keys(%hdrIncludes);
1358     print HEADER "\n";
1359     print HEADER @hBodyPre;
1360     print HEADER @hBody;
1361     print HEADER @hPrefixGuardEnd;
1362
1363     close(HEADER);
1364
1365     # Write the implementation sources
1366     my $implFileName = "$outputDir/" . $basename . ".cpp";
1367     open(IMPL, ">$implFileName") or die "Couldn't open file $implFileName";
1368
1369     print IMPL @cPrefix;
1370     print IMPL "#include <glib-object.h>\n";
1371     print IMPL "#include \"config.h\"\n\n";
1372     print IMPL @conditionGuardStart;
1373     print IMPL "#include <wtf/GetPtr.h>\n";
1374     print IMPL "#include <wtf/RefPtr.h>\n";
1375     print IMPL map { "#include \"$_\"\n" } sort keys(%implIncludes);
1376     print IMPL "\n" if keys(%implIncludes);
1377     print IMPL @cBody;
1378
1379     print IMPL "\n";
1380     print IMPL @cBodyPriv;
1381     print IMPL @conditionGuardEnd;
1382
1383     close(IMPL);
1384
1385     %implIncludes = ();
1386     %hdrIncludes = ();
1387     @hPrefix = ();
1388     @hBody = ();
1389
1390     @cPrefix = ();
1391     @cBody = ();
1392     @cBodyPriv = ();
1393 }
1394
1395 sub GenerateInterface {
1396     my ($object, $dataNode, $defines) = @_;
1397
1398     # Set up some global variables
1399     $className = GetClassName($dataNode->name);
1400
1401     $object->Generate($dataNode);
1402     $object->WriteData($dataNode);
1403 }
1404
1405 1;