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