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