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