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