a191d82e3a0b22424f58c4234b39b55159dcd6b8
[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 @txtInstallProps = ();
35 my @txtSetProps = ();
36 my @txtGetProps = ();
37
38 my $className = "";
39
40 # FIXME: this should be replaced with a function that recurses up the tree
41 # to find the actual base type.
42 my %baseTypeHash = ("Object" => 1, "Node" => 1, "NodeList" => 1, "NamedNodeMap" => 1, "DOMImplementation" => 1,
43                     "Event" => 1, "CSSRule" => 1, "CSSValue" => 1, "StyleSheet" => 1, "MediaList" => 1,
44                     "Counter" => 1, "Rect" => 1, "RGBColor" => 1, "XPathExpression" => 1, "XPathResult" => 1,
45                     "NodeIterator" => 1, "TreeWalker" => 1, "AbstractView" => 1, "Blob" => 1, "DOMTokenList" => 1,
46                     "HTMLCollection" => 1, "TextTrackCue" => 1);
47
48 # List of function parameters that are allowed to be NULL
49 my $canBeNullParams = {
50     'webkit_dom_document_create_attribute_ns' => ['namespaceURI'],
51     'webkit_dom_document_create_element_ns' => ['namespaceURI'],
52     'webkit_dom_document_create_entity_reference' => ['name'],
53     'webkit_dom_document_evaluate' => ['inResult', 'resolver'],
54     'webkit_dom_document_get_override_style' => ['pseudoElement'],
55     'webkit_dom_dom_implementation_create_document' => ['namespaceURI', 'doctype'],
56     'webkit_dom_dom_window_get_computed_style' => ['pseudoElement'],
57     'webkit_dom_element_set_attribute_ns' => ['namespaceURI'],
58     'webkit_dom_node_insert_before' => ['refChild'],
59 };
60
61 # Default constructor
62 sub new {
63     my $object = shift;
64     my $reference = { };
65
66     $codeGenerator = shift;
67
68     bless($reference, $object);
69 }
70
71 my $licenceTemplate = << "EOF";
72 /*
73  *  This file is part of the WebKit open source project.
74  *  This file has been generated by generate-bindings.pl. DO NOT MODIFY!
75  *
76  *  This library is free software; you can redistribute it and/or
77  *  modify it under the terms of the GNU Library General Public
78  *  License as published by the Free Software Foundation; either
79  *  version 2 of the License, or (at your option) any later version.
80  *
81  *  This library is distributed in the hope that it will be useful,
82  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
83  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
84  *  Library General Public License for more details.
85  *
86  *  You should have received a copy of the GNU Library General Public License
87  *  along with this library; see the file COPYING.LIB.  If not, write to
88  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
89  *  Boston, MA 02110-1301, USA.
90  */
91 EOF
92
93 sub GetParentClassName {
94     my $interface = shift;
95
96     return "WebKitDOMObject" unless $interface->parent;
97     return "WebKitDOM" . $interface->parent;
98 }
99
100 sub GetParentImplClassName {
101     my $interface = shift;
102
103     return "Object" unless $interface->parent;
104     return $interface->parent;
105 }
106
107 sub IsBaseType
108 {
109     my $type = shift;
110
111     return 1 if $baseTypeHash{$type};
112     return 0;
113 }
114
115 sub GetBaseClass
116 {
117     $parent = shift;
118     $interface = shift;
119
120     return $parent if $parent eq "Object" or IsBaseType($parent);
121     return "Event" if $codeGenerator->InheritsInterface($interface, "Event");
122     return "CSSValue" if $parent eq "SVGColor" or $parent eq "CSSValueList";
123     return "Node";
124 }
125
126
127 # From String::CamelCase 0.01
128 sub camelize
129 {
130         my $s = shift;
131         join('', map{ ucfirst $_ } split(/(?<=[A-Za-z])_(?=[A-Za-z])|\b/, $s));
132 }
133
134 sub decamelize
135 {
136         my $s = shift;
137         $s =~ s{([^a-zA-Z]?)([A-Z]*)([A-Z])([a-z]?)}{
138                 my $fc = pos($s)==0;
139                 my ($p0,$p1,$p2,$p3) = ($1,lc$2,lc$3,$4);
140                 my $t = $p0 || $fc ? $p0 : '_';
141                 $t .= $p3 ? $p1 ? "${p1}_$p2$p3" : "$p2$p3" : "$p1$p2";
142                 $t;
143         }ge;
144
145         # Some strings are not correctly decamelized, apply fix ups
146         for ($s) {
147             s/domcss/dom_css/;
148             s/domhtml/dom_html/;
149             s/domdom/dom_dom/;
150             s/domcdata/dom_cdata/;
151             s/domui/dom_ui/;
152             s/x_path/xpath/;
153             s/web_kit/webkit/;
154             s/htmli_frame/html_iframe/;
155         }
156         return $s;
157 }
158
159 sub HumanReadableConditional {
160     my @conditional = split('_', shift);
161     my @upperCaseExceptions = ("SQL", "API");
162     my @humanReadable;
163
164     for $part (@conditional) {
165         if (!grep {$_ eq $part} @upperCaseExceptions) {
166             $part = camelize(lc($part));
167         }
168         push(@humanReadable, $part);
169     }
170
171     return join(' ', @humanReadable);
172 }
173
174 sub GetParentGObjType {
175     my $interface = shift;
176
177     return "WEBKIT_TYPE_DOM_OBJECT" unless $interface->parent;
178     return "WEBKIT_TYPE_DOM_" . uc(decamelize(($interface->parent)));
179 }
180
181 sub GetClassName {
182     my $name = shift;
183
184     return "WebKitDOM$name";
185 }
186
187 sub GetCoreObject {
188     my ($interfaceName, $name, $parameter) = @_;
189
190     return "WebCore::${interfaceName}* $name = WebKit::core($parameter);";
191 }
192
193 sub SkipAttribute {
194     my $attribute = shift;
195
196     if ($attribute->signature->extendedAttributes->{"Custom"}
197         || $attribute->signature->extendedAttributes->{"CustomGetter"}) {
198         return 1;
199     }
200
201     my $propType = $attribute->signature->type;
202     if ($propType =~ /Constructor$/) {
203         return 1;
204     }
205
206     return 1 if $attribute->isStatic;
207     return 1 if $codeGenerator->IsTypedArrayType($propType);
208
209     $codeGenerator->AssertNotSequenceType($propType);
210
211     if ($codeGenerator->GetArrayType($propType)) {
212         return 1;
213     }
214
215     if ($codeGenerator->IsEnumType($propType)) {
216         return 1;
217     }
218
219     # This is for DOMWindow.idl location attribute
220     if ($attribute->signature->name eq "location") {
221         return 1;
222     }
223
224     # This is for HTMLInput.idl valueAsDate
225     if ($attribute->signature->name eq "valueAsDate") {
226         return 1;
227     }
228
229     # This is for DOMWindow.idl Crypto attribute
230     if ($attribute->signature->type eq "Crypto") {
231         return 1;
232     }
233
234     if ($attribute->signature->type eq "EventListener") {
235         return 1;
236     }
237
238     if ($attribute->signature->type eq "MediaQueryListListener") {
239         return 1;
240     }
241
242     # Skip indexed database attributes for now, they aren't yet supported for the GObject generator.
243     if ($attribute->signature->name =~ /^(?:webkit)?[Ii]ndexedDB/ or $attribute->signature->name =~ /^(?:webkit)?IDB/) {
244         return 1;
245     }
246
247     return 0;
248 }
249
250 sub SkipFunction {
251     my $object = shift;
252     my $function = shift;
253     my $parentNode = shift;
254     my $decamelize = shift;
255     my $prefix = shift;
256
257     my $functionName = "webkit_dom_" . $decamelize . "_" . $prefix . decamelize($function->signature->name);
258     my $functionReturnType = $prefix eq "set_" ? "void" : $function->signature->type;
259     my $isCustomFunction = $function->signature->extendedAttributes->{"Custom"};
260     my $callWith = $function->signature->extendedAttributes->{"CallWith"};
261     my $isUnsupportedCallWith = $codeGenerator->ExtendedAttributeContains($callWith, "ScriptArguments") || $codeGenerator->ExtendedAttributeContains($callWith, "CallStack");
262
263     if (($isCustomFunction || $isUnsupportedCallWith) &&
264         $functionName ne "webkit_dom_node_replace_child" &&
265         $functionName ne "webkit_dom_node_insert_before" &&
266         $functionName ne "webkit_dom_node_remove_child" &&
267         $functionName ne "webkit_dom_node_append_child" &&
268         $functionName ne "webkit_dom_html_collection_item" &&
269         $functionName ne "webkit_dom_html_collection_named_item") {
270         return 1;
271     }
272
273     # Skip functions that have callback parameters, because this code generator doesn't know
274     # how to auto-generate callbacks.  Skip functions that have "MediaQueryListListener" or
275     # sequence<T> parameters, because this code generator doesn't know how to auto-generate
276     # MediaQueryListListener or sequence<T>. Skip EventListeners because they are handled elsewhere.
277     foreach my $param (@{$function->parameters}) {
278         if ($codeGenerator->IsCallbackInterface($param->type) ||
279             $param->extendedAttributes->{"Clamp"} ||
280             $param->type eq "MediaQueryListListener" ||
281             $param->type eq "EventListener" ||
282             $codeGenerator->GetSequenceType($param->type)) {
283             return 1;
284         }
285     }
286
287     # Skip functions for which we have a custom implementation due to API breaks
288     if ($functionName eq "webkit_dom_html_media_element_set_current_time") {
289         return 1;
290     }
291
292     # This is for DataTransferItemList.idl add(File) method
293     if ($functionName eq "webkit_dom_data_transfer_item_list_add" && @{$function->parameters} == 1) {
294         return 1;
295     }
296
297     # Skip dispatch_event methods.
298     if ($parentNode->extendedAttributes->{"EventTarget"} && $function->signature->name eq "dispatchEvent") {
299         return 1;
300     }
301
302     # Skip Console::profile() and Console::profileEnd() as they're not correctly generated for the moment.
303     if ($functionName eq "webkit_dom_console_profile" || $functionName eq "webkit_dom_console_profile_end") {
304         return 1;
305     }
306
307     if ($function->signature->name eq "set" and $parentNode->extendedAttributes->{"TypedArray"}) {
308         return 1;
309     }
310
311     if ($object eq "MediaQueryListListener") {
312         return 1;
313     }
314
315     if ($function->signature->name eq "getSVGDocument") {
316         return 1;
317     }
318
319     if ($function->signature->name eq "getCSSCanvasContext") {
320         return 1;
321     }
322
323     if ($function->signature->name eq "setRangeText" && @{$function->parameters} == 1) {
324         return 1;
325     }
326
327     if ($function->signature->name eq "timeEnd") {
328         return 1;
329     }
330
331     if ($codeGenerator->GetSequenceType($functionReturnType)) {
332         return 1;
333     }
334
335     if ($function->signature->name eq "supports" && @{$function->parameters} == 1) {
336         return 1;
337     }
338
339     return 0;
340 }
341
342 # Name type used in the g_value_{set,get}_* functions
343 sub GetGValueTypeName {
344     my $type = shift;
345
346     my %types = ("DOMString", "string",
347                  "DOMTimeStamp", "uint",
348                  "float", "float",
349                  "unrestricted float", "float",
350                  "double", "double",
351                  "unrestricted double", "double",
352                  "boolean", "boolean",
353                  "char", "char",
354                  "long", "long",
355                  "long long", "int64",
356                  "byte", "int8",
357                  "octet", "uint8",
358                  "short", "int",
359                  "uchar", "uchar",
360                  "unsigned", "uint",
361                  "int", "int",
362                  "unsigned int", "uint",
363                  "unsigned long long", "uint64", 
364                  "unsigned long", "ulong",
365                  "unsigned short", "uint");
366
367     return $types{$type} ? $types{$type} : "object";
368 }
369
370 # Name type used in C declarations
371 sub GetGlibTypeName {
372     my $type = shift;
373     my $name = GetClassName($type);
374
375     my %types = ("DOMString", "gchar*",
376                  "DOMTimeStamp", "guint32",
377                  "CompareHow", "gushort",
378                  "float", "gfloat",
379                  "unrestricted float", "gfloat",
380                  "double", "gdouble",
381                  "unrestricted double", "gdouble",
382                  "boolean", "gboolean",
383                  "char", "gchar",
384                  "long", "glong",
385                  "long long", "gint64",
386                  "byte", "gint8",
387                  "octet", "guint8",
388                  "short", "gshort",
389                  "uchar", "guchar",
390                  "unsigned", "guint",
391                  "int", "gint",
392                  "unsigned int", "guint",
393                  "unsigned long", "gulong",
394                  "unsigned long long", "guint64",
395                  "unsigned short", "gushort",
396                  "void", "void");
397
398     return $types{$type} ? $types{$type} : "$name*";
399 }
400
401 sub IsGDOMClassType {
402     my $type = shift;
403
404     return 0 if $codeGenerator->IsNonPointerType($type) || $codeGenerator->IsStringType($type);
405     return 1;
406 }
407
408 sub IsPropertyReadable {
409     my $property = shift;
410     return !SkipAttribute($property);
411 }
412
413 sub IsPropertyWriteable {
414     my $property = shift;
415
416     if (!IsPropertyReadable($property)) {
417         return 0;
418     }
419
420     if ($property->isReadOnly) {
421         return 0;
422     }
423
424     my $gtype = GetGValueTypeName($property->signature->type);
425     my $hasGtypeSignature = $gtype eq "boolean" || $gtype eq "float" || $gtype eq "double" ||
426                             $gtype eq "int64" || $gtype eq "uint64" ||
427                             $gtype eq "long" || $gtype eq "ulong" ||
428                             $gtype eq "int" || $gtype eq "uint" ||
429                             $gtype eq "short" || $gtype eq "ushort" ||
430                             $gtype eq "int8" || $gtype eq "uint8" ||
431                             $gtype eq "char" || $gtype eq "uchar" ||
432                             $gtype eq "string";
433     if (!$hasGtypeSignature) {
434         return 0;
435     }
436
437     # FIXME: We are not generating setters for 'Replaceable' attributes now, but we should somehow.
438     if ($property->signature->extendedAttributes->{"Replaceable"}) {
439         return 0;
440     }
441
442     if ($property->signature->extendedAttributes->{"CustomSetter"}) {
443         return 0;
444     }
445
446     return 1;
447 }
448
449 sub GenerateConditionalWarning
450 {
451     my $node = shift;
452     my $indentSize = shift;
453     if (!$indentSize) {
454         $indentSize = 4;
455     }
456
457     my $conditional = $node->extendedAttributes->{"Conditional"};
458     my @warn;
459
460     if ($conditional) {
461         if ($conditional =~ /&/) {
462             my @splitConditionals = split(/&/, $conditional);
463             foreach $condition (@splitConditionals) {
464                 push(@warn, "#if !ENABLE($condition)\n");
465                 push(@warn, ' ' x $indentSize . "WEBKIT_WARN_FEATURE_NOT_PRESENT(\"" . HumanReadableConditional($condition) . "\")\n");
466                 push(@warn, "#endif\n");
467             }
468         } elsif ($conditional =~ /\|/) {
469             foreach $condition (split(/\|/, $conditional)) {
470                 push(@warn, ' ' x $indentSize . "WEBKIT_WARN_FEATURE_NOT_PRESENT(\"" . HumanReadableConditional($condition) . "\")\n");
471             }
472         } else {
473             push(@warn, ' ' x $indentSize . "WEBKIT_WARN_FEATURE_NOT_PRESENT(\"" . HumanReadableConditional($conditional) . "\")\n");
474         }
475     }
476
477     return @warn;
478 }
479
480 sub GenerateProperty {
481     my $attribute = shift;
482     my $interfaceName = shift;
483     my @writeableProperties = @{shift @_};
484     my $parentNode = shift;
485
486     my $conditionalString = $codeGenerator->GenerateConditionalString($attribute->signature);
487     my @conditionalWarn = GenerateConditionalWarning($attribute->signature, 8);
488     my $parentConditionalString = $codeGenerator->GenerateConditionalString($parentNode);
489     my @parentConditionalWarn = GenerateConditionalWarning($parentNode, 8);
490     my $camelPropName = $attribute->signature->name;
491     my $setPropNameFunction = $codeGenerator->WK_ucfirst($camelPropName);
492     my $getPropNameFunction = $codeGenerator->WK_lcfirst($camelPropName);
493     my $hasGetterException = $attribute->signature->extendedAttributes->{"GetterRaisesException"};
494     my $hasSetterException = $attribute->signature->extendedAttributes->{"SetterRaisesException"};
495
496     my $propName = decamelize($camelPropName);
497     my $propNameCaps = uc($propName);
498     $propName =~ s/_/-/g;
499     my ${propEnum} = "PROP_${propNameCaps}";
500     push(@cBodyProperties, "    ${propEnum},\n");
501
502     my $propType = $attribute->signature->type;
503     my ${propGType} = decamelize($propType);
504     my ${ucPropGType} = uc($propGType);
505
506     my $gtype = GetGValueTypeName($propType);
507     my $gparamflag = "WEBKIT_PARAM_READABLE";
508     my $writeable = IsPropertyWriteable($attribute);
509
510     my $mutableString = "read-only";
511     my $hasCustomSetter = $attribute->signature->extendedAttributes->{"CustomSetter"};
512     if ($writeable && $hasCustomSetter) {
513         $mutableString = "read-only (due to custom functions needed in webkitdom)";
514     } elsif ($writeable) {
515         $gparamflag = "WEBKIT_PARAM_READWRITE";
516         $mutableString = "read-write";
517     }
518
519     my $convertFunction = "";
520     if ($gtype eq "string") {
521         $convertFunction = "WTF::String::fromUTF8";
522     }
523
524     my ($getterFunctionName, @getterArguments) = $codeGenerator->GetterExpression(\%implIncludes, $interfaceName, $attribute);
525     my ($setterFunctionName, @setterArguments) = $codeGenerator->SetterExpression(\%implIncludes, $interfaceName, $attribute);
526
527     if ($attribute->signature->extendedAttributes->{"ImplementedBy"}) {
528         my $implementedBy = $attribute->signature->extendedAttributes->{"ImplementedBy"};
529         $implIncludes{"${implementedBy}.h"} = 1;
530         push(@setterArguments, "${convertFunction}(g_value_get_$gtype(value))");
531         unshift(@getterArguments, "coreSelf");
532         unshift(@setterArguments, "coreSelf");
533         $getterFunctionName = "WebCore::${implementedBy}::$getterFunctionName";
534         $setterFunctionName = "WebCore::${implementedBy}::$setterFunctionName";
535     } else {
536         push(@setterArguments, "${convertFunction}(g_value_get_$gtype(value))");
537         $getterFunctionName = "coreSelf->$getterFunctionName";
538         $setterFunctionName = "coreSelf->$setterFunctionName";
539     }
540     push(@getterArguments, "isNull") if $attribute->signature->isNullable;
541     push(@getterArguments, "ec") if $hasGetterException;
542     push(@setterArguments, "ec") if $hasSetterException;
543
544     if (grep {$_ eq $attribute} @writeableProperties) {
545         push(@txtSetProps, "    case ${propEnum}: {\n");
546         push(@txtSetProps, "#if ${parentConditionalString}\n") if $parentConditionalString;
547         push(@txtSetProps, "#if ${conditionalString}\n") if $conditionalString;
548         push(@txtSetProps, "        WebCore::ExceptionCode ec = 0;\n") if $hasSetterException;
549         push(@txtSetProps, "        ${setterFunctionName}(" . join(", ", @setterArguments) . ");\n");
550         push(@txtSetProps, "#else\n") if $conditionalString;
551         push(@txtSetProps, @conditionalWarn) if scalar(@conditionalWarn);
552         push(@txtSetProps, "#endif /* ${conditionalString} */\n") if $conditionalString;
553         push(@txtSetProps, "#else\n") if $parentConditionalString;
554         push(@txtSetProps, @parentConditionalWarn) if scalar(@parentConditionalWarn);
555         push(@txtSetProps, "#endif /* ${parentConditionalString} */\n") if $parentConditionalString;
556         push(@txtSetProps, "        break;\n    }\n");
557     }
558
559     push(@txtGetProps, "    case ${propEnum}: {\n");
560     push(@txtGetProps, "#if ${parentConditionalString}\n") if $parentConditionalString;
561     push(@txtGetProps, "#if ${conditionalString}\n") if $conditionalString;
562     push(@txtGetProps, "        bool isNull = false;\n") if $attribute->signature->isNullable;
563     push(@txtGetProps, "        WebCore::ExceptionCode ec = 0;\n") if $hasGetterException;
564
565     # FIXME: Should we return a default value when isNull == true?
566
567     my $postConvertFunction = "";
568     if ($gtype eq "string") {
569         push(@txtGetProps, "        g_value_take_string(value, convertToUTF8String(${getterFunctionName}(" . join(", ", @getterArguments) . ")));\n");
570     } elsif ($gtype eq "object") {
571         push(@txtGetProps, "        RefPtr<WebCore::${propType}> ptr = ${getterFunctionName}(" . join(", ", @getterArguments) . ");\n");
572         push(@txtGetProps, "        g_value_set_object(value, WebKit::kit(ptr.get()));\n");
573     } else {
574         push(@txtGetProps, "        g_value_set_$gtype(value, ${convertFunction}${getterFunctionName}(" . join(", ", @getterArguments) . ")${postConvertFunction});\n");
575     }
576
577     push(@txtGetProps, "#else\n") if $conditionalString;
578     push(@txtGetProps, @conditionalWarn) if scalar(@conditionalWarn);
579     push(@txtGetProps, "#endif /* ${conditionalString} */\n") if $conditionalString;
580     push(@txtGetProps, "#else\n") if $parentConditionalString;
581     push(@txtGetProps, @parentConditionalWarn) if scalar(@parentConditionalWarn);
582     push(@txtGetProps, "#endif /* ${parentConditionalString} */\n") if $parentConditionalString;
583     push(@txtGetProps, "        break;\n    }\n");
584
585     my %parameterSpecOptions = ("int" =>     [ "G_MININT", "G_MAXINT", "0" ],
586                                 "int8" =>    [ "G_MININT8", "G_MAXINT8", "0" ],
587                                 "boolean" => [ "FALSE" ],
588                                 "float" =>   [ "-G_MAXFLOAT", "G_MAXFLOAT", "0" ],
589                                 "double" =>  [ "-G_MAXDOUBLE", "G_MAXDOUBLE", "0" ],
590                                 "uint64" =>  [ "0", "G_MAXUINT64", "0" ],
591                                 "long" =>    [ "G_MINLONG", "G_MAXLONG", "0" ],
592                                 "int64" =>   [ "G_MININT64", "G_MAXINT64", "0" ],
593                                 "ulong" =>   [ "0", "G_MAXULONG", "0" ],
594                                 "uint" =>    [ "0", "G_MAXUINT", "0" ],
595                                 "uint8" =>   [ "0", "G_MAXUINT8", "0" ],
596                                 "ushort" =>  [ "0", "G_MAXUINT16", "0" ],
597                                 "uchar" =>   [ "G_MININT8", "G_MAXINT8", "0" ],
598                                 "char" =>    [ "0", "G_MAXUINT8", "0" ],
599                                 "string" =>  [ '""', ],
600                                 "object" =>  [ "WEBKIT_TYPE_DOM_${ucPropGType}" ]);
601
602     my $extraParameters = join(", ", @{$parameterSpecOptions{$gtype}});
603     my $glibTypeName = GetGlibTypeName($propType);
604     my $txtInstallProp = << "EOF";
605     g_object_class_install_property(
606         gobjectClass,
607         $propEnum,
608         g_param_spec_$gtype(
609             "$propName",
610             "$interfaceName:$propName",
611             "$mutableString $glibTypeName $interfaceName:$propName",
612             $extraParameters,
613             $gparamflag));
614
615 EOF
616     push(@txtInstallProps, $txtInstallProp);
617 }
618
619 sub GenerateProperties {
620     my ($object, $interfaceName, $interface) = @_;
621
622     my $decamelize = decamelize($interfaceName);
623     my $clsCaps = uc($decamelize);
624     my $lowerCaseIfaceName = "webkit_dom_$decamelize";
625     my $parentImplClassName = GetParentImplClassName($interface);
626
627     my $conditionGuardStart = "";
628     my $conditionGuardEnd = "";
629     my $conditionalString = $codeGenerator->GenerateConditionalString($interface);
630     if ($conditionalString) {
631         $conditionGuardStart = "#if ${conditionalString}";
632         $conditionGuardEnd = "#endif // ${conditionalString}";
633     }
634
635     # Properties
636     my $implContent = "";
637     my @readableProperties = grep { IsPropertyReadable($_) } @{$interface->attributes};
638     my @writeableProperties = grep { IsPropertyWriteable($_) } @{$interface->attributes};
639     my $numProperties = scalar @readableProperties;
640
641     # Properties
642     my $privFunction = GetCoreObject($interfaceName, "coreSelf", "self");
643     if ($numProperties > 0) {
644         $implContent = << "EOF";
645 enum {
646     PROP_0,
647 EOF
648         push(@cBodyProperties, $implContent);
649
650         push(@txtGetProps, "static void ${lowerCaseIfaceName}_get_property(GObject* object, guint propertyId, GValue* value, GParamSpec* pspec)\n");
651         push(@txtGetProps, "{\n");
652         push(@txtGetProps, "    WebCore::JSMainThreadNullState state;\n");
653         push(@txtGetProps, "${conditionGuardStart}\n") if $conditionalString;
654         push(@txtGetProps, "    ${className}* self = WEBKIT_DOM_${clsCaps}(object);\n");
655         push(@txtGetProps, "    ${privFunction}\n");
656         if ($conditionalString) {
657             push(@txtGetProps, "#else\n");
658             push(@txtGetProps, "    UNUSED_PARAM(value);\n");
659             push(@txtGetProps, "${conditionGuardEnd}\n");
660         }
661         push(@txtGetProps, "\n");
662         push(@txtGetProps, "    switch (propertyId) {\n");
663
664         if (scalar @writeableProperties > 0) {
665             push(@txtSetProps, "static void ${lowerCaseIfaceName}_set_property(GObject* object, guint propertyId, const GValue* value, GParamSpec* pspec)\n");
666             push(@txtSetProps, "{\n");
667             push(@txtSetProps, "    WebCore::JSMainThreadNullState state;\n");
668             push(@txtSetProps, "${conditionGuardStart}\n") if $conditionalString;
669             push(@txtSetProps, "    ${className}* self = WEBKIT_DOM_${clsCaps}(object);\n");
670             push(@txtSetProps, "    ${privFunction}\n");
671             if ($conditionalString) {
672                 push(@txtSetProps, "#else\n");
673                 push(@txtSetProps, "    UNUSED_PARAM(value);\n");
674                 push(@txtSetProps, "${conditionGuardEnd}\n");
675             }
676             push(@txtSetProps, "\n");
677             push(@txtSetProps, "    switch (propertyId) {\n");
678         }
679
680         foreach my $attribute (@readableProperties) {
681             GenerateProperty($attribute, $interfaceName, \@writeableProperties, $interface);
682         }
683
684         push(@cBodyProperties, "};\n\n");
685
686         $txtGetProp = << "EOF";
687     default:
688         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propertyId, pspec);
689         break;
690     }
691 }
692 EOF
693         push(@txtGetProps, $txtGetProp);
694
695         if (scalar @writeableProperties > 0) {
696             $txtSetProps = << "EOF";
697     default:
698         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propertyId, pspec);
699         break;
700     }
701 }
702 EOF
703             push(@txtSetProps, $txtSetProps);
704         }
705     }
706
707     # Do not insert extra spaces when interpolating array variables
708     $" = "";
709
710     if ($parentImplClassName eq "Object") {
711         $implContent = << "EOF";
712 static void ${lowerCaseIfaceName}_finalize(GObject* object)
713 {
714     ${className}Private* priv = WEBKIT_DOM_${clsCaps}_GET_PRIVATE(object);
715 $conditionGuardStart
716     WebKit::DOMObjectCache::forget(priv->coreObject.get());
717 $conditionGuardEnd
718     priv->~${className}Private();
719     G_OBJECT_CLASS(${lowerCaseIfaceName}_parent_class)->finalize(object);
720 }
721
722 EOF
723         push(@cBodyProperties, $implContent);
724     }
725
726     if ($numProperties > 0) {
727         if (scalar @writeableProperties > 0) {
728             push(@cBodyProperties, @txtSetProps);
729             push(@cBodyProperties, "\n");
730         }
731         push(@cBodyProperties, @txtGetProps);
732         push(@cBodyProperties, "\n");
733     }
734
735     # Add a constructor implementation only for direct subclasses of Object to make sure
736     # that the WebCore wrapped object is added only once to the DOM cache. The DOM garbage
737     # collector works because Node is a direct subclass of Object and the version of
738     # DOMObjectCache::put() that receives a Node (which is the one setting the frame) is
739     # always called for DOM objects derived from Node.
740     if ($parentImplClassName eq "Object") {
741         $implContent = << "EOF";
742 static GObject* ${lowerCaseIfaceName}_constructor(GType type, guint constructPropertiesCount, GObjectConstructParam* constructProperties)
743 {
744     GObject* object = G_OBJECT_CLASS(${lowerCaseIfaceName}_parent_class)->constructor(type, constructPropertiesCount, constructProperties);
745 $conditionGuardStart
746     ${className}Private* priv = WEBKIT_DOM_${clsCaps}_GET_PRIVATE(object);
747     priv->coreObject = static_cast<WebCore::${interfaceName}*>(WEBKIT_DOM_OBJECT(object)->coreObject);
748     WebKit::DOMObjectCache::put(priv->coreObject.get(), object);
749 $conditionGuardEnd
750     return object;
751 }
752
753 EOF
754         push(@cBodyProperties, $implContent);
755     }
756
757     $implContent = << "EOF";
758 static void ${lowerCaseIfaceName}_class_init(${className}Class* requestClass)
759 {
760 EOF
761     push(@cBodyProperties, $implContent);
762
763     if ($parentImplClassName eq "Object" || $numProperties > 0) {
764         push(@cBodyProperties, "    GObjectClass* gobjectClass = G_OBJECT_CLASS(requestClass);\n");
765
766         if ($parentImplClassName eq "Object") {
767             push(@cBodyProperties, "    g_type_class_add_private(gobjectClass, sizeof(${className}Private));\n");
768             push(@cBodyProperties, "    gobjectClass->constructor = ${lowerCaseIfaceName}_constructor;\n");
769             push(@cBodyProperties, "    gobjectClass->finalize = ${lowerCaseIfaceName}_finalize;\n");
770         }
771
772         if ($numProperties > 0) {
773             if (scalar @writeableProperties > 0) {
774                 push(@cBodyProperties, "    gobjectClass->set_property = ${lowerCaseIfaceName}_set_property;\n");
775             }
776             push(@cBodyProperties, "    gobjectClass->get_property = ${lowerCaseIfaceName}_get_property;\n");
777             push(@cBodyProperties, "\n");
778             push(@cBodyProperties, @txtInstallProps);
779         }
780     } else {
781         push(@cBodyProperties, "    UNUSED_PARAM(requestClass);\n");
782     }
783     $implContent = << "EOF";
784 }
785
786 static void ${lowerCaseIfaceName}_init(${className}* request)
787 {
788 EOF
789     push(@cBodyProperties, $implContent);
790
791     if ($parentImplClassName eq "Object") {
792         $implContent = << "EOF";
793     ${className}Private* priv = WEBKIT_DOM_${clsCaps}_GET_PRIVATE(request);
794     new (priv) ${className}Private();
795 EOF
796         push(@cBodyProperties, $implContent);
797     } else {
798         push(@cBodyProperties, "    UNUSED_PARAM(request);\n");
799     }
800     $implContent = << "EOF";
801 }
802
803 EOF
804     push(@cBodyProperties, $implContent);
805 }
806
807 sub GenerateHeader {
808     my ($object, $interfaceName, $parentClassName) = @_;
809
810     my $implContent = "";
811
812     # Add the default header template
813     @hPrefix = split("\r", $licenceTemplate);
814     push(@hPrefix, "\n");
815
816     # Force single header include.
817     my $headerCheck = << "EOF";
818 #if !defined(__WEBKITDOM_H_INSIDE__) && !defined(BUILDING_WEBKIT)
819 #error "Only <webkitdom/webkitdom.h> can be included directly."
820 #endif
821
822 EOF
823     push(@hPrefix, $headerCheck);
824
825     # Header guard
826     my $guard = $className . "_h";
827
828     @hPrefixGuard = << "EOF";
829 #ifndef $guard
830 #define $guard
831
832 EOF
833
834     $implContent = << "EOF";
835 G_BEGIN_DECLS
836
837 EOF
838
839     push(@hBodyPre, $implContent);
840
841     my $decamelize = decamelize($interfaceName);
842     my $clsCaps = uc($decamelize);
843     my $lowerCaseIfaceName = "webkit_dom_$decamelize";
844
845     $implContent = << "EOF";
846 #define WEBKIT_TYPE_DOM_${clsCaps}            (${lowerCaseIfaceName}_get_type())
847 #define WEBKIT_DOM_${clsCaps}(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), WEBKIT_TYPE_DOM_${clsCaps}, ${className}))
848 #define WEBKIT_DOM_${clsCaps}_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass),  WEBKIT_TYPE_DOM_${clsCaps}, ${className}Class)
849 #define WEBKIT_DOM_IS_${clsCaps}(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), WEBKIT_TYPE_DOM_${clsCaps}))
850 #define WEBKIT_DOM_IS_${clsCaps}_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),  WEBKIT_TYPE_DOM_${clsCaps}))
851 #define WEBKIT_DOM_${clsCaps}_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj),  WEBKIT_TYPE_DOM_${clsCaps}, ${className}Class))
852
853 struct _${className} {
854     ${parentClassName} parent_instance;
855 };
856
857 struct _${className}Class {
858     ${parentClassName}Class parent_class;
859 };
860
861 WEBKIT_API GType
862 ${lowerCaseIfaceName}_get_type (void);
863
864 EOF
865
866     push(@hBody, $implContent);
867 }
868
869 sub GetGReturnMacro {
870     my ($paramName, $paramIDLType, $returnType, $functionName) = @_;
871
872     my $condition;
873     if ($paramIDLType eq "GError") {
874         $condition = "!$paramName || !*$paramName";
875     } elsif (IsGDOMClassType($paramIDLType)) {
876         my $paramTypeCaps = uc(decamelize($paramIDLType));
877         $condition = "WEBKIT_DOM_IS_${paramTypeCaps}($paramName)";
878         if (ParamCanBeNull($functionName, $paramName)) {
879             $condition = "!$paramName || $condition";
880         }
881     } else {
882         if (ParamCanBeNull($functionName, $paramName)) {
883             return "";
884         }
885         $condition = "$paramName";
886     }
887
888     my $macro;
889     if ($returnType ne "void") {
890         $defaultReturn = $returnType eq "gboolean" ? "FALSE" : 0;
891         $macro = "    g_return_val_if_fail($condition, $defaultReturn);\n";
892     } else {
893         $macro = "    g_return_if_fail($condition);\n";
894     }
895
896     return $macro;
897 }
898
899 sub ParamCanBeNull {
900     my($functionName, $paramName) = @_;
901
902     if (defined($functionName)) {
903         return scalar(grep {$_ eq $paramName} @{$canBeNullParams->{$functionName}});
904     }
905     return 0;
906 }
907
908 sub GenerateFunction {
909     my ($object, $interfaceName, $function, $prefix, $parentNode) = @_;
910
911     my $decamelize = decamelize($interfaceName);
912
913     if (SkipFunction($object, $function, $parentNode, $decamelize, $prefix)) {
914         return;
915     }
916
917     my $functionSigType = $prefix eq "set_" ? "void" : $function->signature->type;
918     my $functionName = "webkit_dom_" . $decamelize . "_" . $prefix . decamelize($function->signature->name);
919     my $returnType = GetGlibTypeName($functionSigType);
920     my $returnValueIsGDOMType = IsGDOMClassType($functionSigType);
921     my $raisesException = $function->signature->extendedAttributes->{"RaisesException"};
922
923     my $conditionalString = $codeGenerator->GenerateConditionalString($function->signature);
924     my $parentConditionalString = $codeGenerator->GenerateConditionalString($parentNode);
925     my @conditionalWarn = GenerateConditionalWarning($function->signature);
926     my @parentConditionalWarn = GenerateConditionalWarning($parentNode);
927
928     my $functionSig = "${className}* self";
929     my $symbolSig = "${className}*";
930
931     my @callImplParams;
932     foreach my $param (@{$function->parameters}) {
933         my $paramIDLType = $param->type;
934         my $paramType = GetGlibTypeName($paramIDLType);
935         my $const = $paramType eq "gchar*" ? "const " : "";
936         my $paramName = $param->name;
937
938         $functionSig .= ", ${const}$paramType $paramName";
939         $symbolSig .= ", ${const}$paramType";
940
941         my $paramIsGDOMType = IsGDOMClassType($paramIDLType);
942         if ($paramIsGDOMType) {
943             if ($paramIDLType ne "any") {
944                 $implIncludes{"WebKitDOM${paramIDLType}Private.h"} = 1;
945             }
946         }
947         if ($paramIsGDOMType || ($paramIDLType eq "DOMString") || ($paramIDLType eq "CompareHow")) {
948             $paramName = "converted" . $codeGenerator->WK_ucfirst($paramName);
949         }
950         push(@callImplParams, $paramName);
951     }
952
953     if ($returnType ne "void" && $returnValueIsGDOMType && $functionSigType ne "any") {
954         $implIncludes{"WebKitDOM${functionSigType}Private.h"} = 1;
955     }
956
957     $functionSig .= ", GError** error" if $raisesException;
958     $symbolSig .= ", GError**" if $raisesException;
959
960     push(@symbols, "$returnType $functionName($symbolSig)\n");
961
962     # Insert introspection annotations
963     push(@hBody, "/**\n");
964     push(@hBody, " * ${functionName}:\n");
965     push(@hBody, " * \@self: A #${className}\n");
966
967     foreach my $param (@{$function->parameters}) {
968         my $paramType = GetGlibTypeName($param->type);
969         # $paramType can have a trailing * in some cases
970         $paramType =~ s/\*$//;
971         my $paramName = $param->name;
972         my $paramAnnotations = "";
973         if (ParamCanBeNull($functionName, $paramName)) {
974             $paramAnnotations = " (allow-none):";
975         }
976         push(@hBody, " * \@${paramName}:${paramAnnotations} A #${paramType}\n");
977     }
978     push(@hBody, " * \@error: #GError\n") if $raisesException;
979     push(@hBody, " *\n");
980     my $returnTypeName = $returnType;
981     $returnTypeName =~ s/\*$//;
982     if ($returnValueIsGDOMType) {
983         push(@hBody, " * Returns: (transfer none): A #${returnTypeName}\n");
984     } elsif ($returnType ne "void") {
985         push(@hBody, " * Returns: A #${returnTypeName}\n");
986     }
987     push(@hBody, "**/\n");
988
989     push(@hBody, "WEBKIT_API $returnType\n$functionName($functionSig);\n");
990     push(@hBody, "\n");
991
992     push(@cBody, "$returnType $functionName($functionSig)\n{\n");
993     push(@cBody, "#if ${parentConditionalString}\n") if $parentConditionalString;
994     push(@cBody, "#if ${conditionalString}\n") if $conditionalString;
995
996     push(@cBody, "    WebCore::JSMainThreadNullState state;\n");
997
998     # g_return macros to check parameters of public methods.
999     $gReturnMacro = GetGReturnMacro("self", $interfaceName, $returnType);
1000     push(@cBody, $gReturnMacro);
1001
1002     foreach my $param (@{$function->parameters}) {
1003         my $paramName = $param->name;
1004         my $paramIDLType = $param->type;
1005         my $paramTypeIsPointer = !$codeGenerator->IsNonPointerType($paramIDLType);
1006         if ($paramTypeIsPointer) {
1007             $gReturnMacro = GetGReturnMacro($paramName, $paramIDLType, $returnType, $functionName);
1008             push(@cBody, $gReturnMacro);
1009         }
1010     }
1011
1012     if ($raisesException) {
1013         $gReturnMacro = GetGReturnMacro("error", "GError", $returnType);
1014         push(@cBody, $gReturnMacro);
1015     }
1016
1017     # The WebKit::core implementations check for null already; no need to duplicate effort.
1018     push(@cBody, "    WebCore::${interfaceName}* item = WebKit::core(self);\n");
1019
1020     $returnParamName = "";
1021     foreach my $param (@{$function->parameters}) {
1022         my $paramIDLType = $param->type;
1023         my $paramName = $param->name;
1024
1025         my $paramIsGDOMType = IsGDOMClassType($paramIDLType);
1026         $convertedParamName = "converted" . $codeGenerator->WK_ucfirst($paramName);
1027         if ($paramIDLType eq "DOMString") {
1028             push(@cBody, "    WTF::String ${convertedParamName} = WTF::String::fromUTF8($paramName);\n");
1029         } elsif ($paramIDLType eq "CompareHow") {
1030             push(@cBody, "    WebCore::Range::CompareHow ${convertedParamName} = static_cast<WebCore::Range::CompareHow>($paramName);\n");
1031         } elsif ($paramIsGDOMType) {
1032             push(@cBody, "    WebCore::${paramIDLType}* ${convertedParamName} = WebKit::core($paramName);\n");
1033         }
1034         $returnParamName = $convertedParamName if $param->extendedAttributes->{"CustomReturn"};
1035     }
1036
1037     my $assign = "";
1038     my $assignPre = "";
1039     my $assignPost = "";
1040
1041     # We need to special-case these Node methods because their C++
1042     # signature is different from what we'd expect given their IDL
1043     # description; see Node.h.
1044     my $functionHasCustomReturn = $functionName eq "webkit_dom_node_append_child" ||
1045         $functionName eq "webkit_dom_node_insert_before" ||
1046         $functionName eq "webkit_dom_node_replace_child" ||
1047         $functionName eq "webkit_dom_node_remove_child";
1048          
1049     if ($returnType ne "void" && !$functionHasCustomReturn) {
1050         if ($returnValueIsGDOMType) {
1051             $assign = "RefPtr<WebCore::${functionSigType}> gobjectResult = ";
1052             $assignPre = "WTF::getPtr(";
1053             $assignPost = ")";
1054         } else {
1055             $assign = "${returnType} result = ";
1056         }
1057     }
1058
1059     # FIXME: Should we return a default value when isNull == true?
1060     if ($function->signature->isNullable) {
1061         push(@cBody, "    bool isNull = false;\n");
1062         push(@callImplParams, "isNull");
1063     }
1064
1065     if ($raisesException) {
1066         push(@cBody, "    WebCore::ExceptionCode ec = 0;\n");
1067         push(@callImplParams, "ec");
1068     }
1069
1070     my $functionImplementationName = $function->signature->extendedAttributes->{"ImplementedAs"} || $function->signature->name;
1071
1072     if ($functionHasCustomReturn) {
1073         push(@cBody, "    bool ok = item->${functionImplementationName}(" . join(", ", @callImplParams) . ");\n");
1074         my $customNodeAppendChild = << "EOF";
1075     if (ok)
1076         return WebKit::kit($returnParamName);
1077 EOF
1078         push(@cBody, $customNodeAppendChild);
1079     
1080         if($raisesException) {
1081             my $exceptionHandling = << "EOF";
1082
1083     WebCore::ExceptionCodeDescription ecdesc(ec);
1084     g_set_error_literal(error, g_quark_from_string("WEBKIT_DOM"), ecdesc.code, ecdesc.name);
1085 EOF
1086             push(@cBody, $exceptionHandling);
1087         }
1088         push(@cBody, "    return 0;\n");
1089         push(@cBody, "}\n\n");
1090         return;
1091     } elsif ($functionSigType eq "DOMString") {
1092         my $getterContentHead;
1093         if ($prefix) {
1094             my ($functionName, @arguments) = $codeGenerator->GetterExpression(\%implIncludes, $interfaceName, $function);
1095             push(@arguments, @callImplParams);
1096             if ($function->signature->extendedAttributes->{"ImplementedBy"}) {
1097                 my $implementedBy = $function->signature->extendedAttributes->{"ImplementedBy"};
1098                 $implIncludes{"${implementedBy}.h"} = 1;
1099                 unshift(@arguments, "item");
1100                 $functionName = "WebCore::${implementedBy}::${functionName}";
1101             } else {
1102                 $functionName = "item->${functionName}";
1103             }
1104             $getterContentHead = "${assign}convertToUTF8String(${functionName}(" . join(", ", @arguments) . "));\n";
1105         } else {
1106             my @arguments = @callImplParams;
1107             if ($function->signature->extendedAttributes->{"ImplementedBy"}) {
1108                 my $implementedBy = $function->signature->extendedAttributes->{"ImplementedBy"};
1109                 $implIncludes{"${implementedBy}.h"} = 1;
1110                 unshift(@arguments, "item");
1111                 $getterContentHead = "${assign}convertToUTF8String(WebCore::${implementedBy}::${functionImplementationName}(" . join(", ", @arguments) . "));\n";
1112             } else {
1113                 $getterContentHead = "${assign}convertToUTF8String(item->${functionImplementationName}(" . join(", ", @arguments) . "));\n";
1114             }
1115         }
1116         push(@cBody, "    ${getterContentHead}");
1117     } else {
1118         my $contentHead;
1119         if ($prefix eq "get_") {
1120             my ($functionName, @arguments) = $codeGenerator->GetterExpression(\%implIncludes, $interfaceName, $function);
1121             push(@arguments, @callImplParams);
1122             if ($function->signature->extendedAttributes->{"ImplementedBy"}) {
1123                 my $implementedBy = $function->signature->extendedAttributes->{"ImplementedBy"};
1124                 $implIncludes{"${implementedBy}.h"} = 1;
1125                 unshift(@arguments, "item");
1126                 $functionName = "WebCore::${implementedBy}::${functionName}";
1127             } else {
1128                 $functionName = "item->${functionName}";
1129             }
1130             $contentHead = "${assign}${assignPre}${functionName}(" . join(", ", @arguments) . "${assignPost});\n";
1131         } elsif ($prefix eq "set_") {
1132             my ($functionName, @arguments) = $codeGenerator->SetterExpression(\%implIncludes, $interfaceName, $function);
1133             push(@arguments, @callImplParams);
1134             if ($function->signature->extendedAttributes->{"ImplementedBy"}) {
1135                 my $implementedBy = $function->signature->extendedAttributes->{"ImplementedBy"};
1136                 $implIncludes{"${implementedBy}.h"} = 1;
1137                 unshift(@arguments, "item");
1138                 $functionName = "WebCore::${implementedBy}::${functionName}";
1139                 $contentHead = "${assign}${assignPre}${functionName}(" . join(", ", @arguments) . "${assignPost});\n";
1140             } else {
1141                 $functionName = "item->${functionName}";
1142                 $contentHead = "${assign}${assignPre}${functionName}(" . join(", ", @arguments) . "${assignPost});\n";
1143             }
1144         } else {
1145             my @arguments = @callImplParams;
1146             if ($function->signature->extendedAttributes->{"ImplementedBy"}) {
1147                 my $implementedBy = $function->signature->extendedAttributes->{"ImplementedBy"};
1148                 $implIncludes{"${implementedBy}.h"} = 1;
1149                 unshift(@arguments, "item");
1150                 $contentHead = "${assign}${assignPre}WebCore::${implementedBy}::${functionImplementationName}(" . join(", ", @arguments) . "${assignPost});\n";
1151             } else {
1152                 $contentHead = "${assign}${assignPre}item->${functionImplementationName}(" . join(", ", @arguments) . "${assignPost});\n";
1153             }
1154         }
1155         push(@cBody, "    ${contentHead}");
1156         
1157         if($raisesException) {
1158             my $exceptionHandling = << "EOF";
1159     if (ec) {
1160         WebCore::ExceptionCodeDescription ecdesc(ec);
1161         g_set_error_literal(error, g_quark_from_string("WEBKIT_DOM"), ecdesc.code, ecdesc.name);
1162     }
1163 EOF
1164             push(@cBody, $exceptionHandling);
1165         }
1166     }
1167
1168     if ($returnType ne "void" && !$functionHasCustomReturn) {
1169         if ($functionSigType ne "any") {
1170             if ($returnValueIsGDOMType) {
1171                 push(@cBody, "    return WebKit::kit(gobjectResult.get());\n");
1172             } else {
1173                 push(@cBody, "    return result;\n");
1174             }
1175         } else {
1176             push(@cBody, "    return 0; // TODO: return canvas object\n");
1177         }
1178     }
1179
1180     if ($conditionalString) {
1181         push(@cBody, "#else\n");
1182
1183         push(@cBody, "    UNUSED_PARAM(self);\n");
1184         foreach my $param (@{$function->parameters}) {
1185             push(@cBody, "    UNUSED_PARAM(" . $param->name . ");\n");
1186         }
1187         push(@cBody, "    UNUSED_PARAM(error);\n") if $raisesException;
1188
1189         push(@cBody, @conditionalWarn) if scalar(@conditionalWarn);
1190         if ($returnType ne "void") {
1191             if ($codeGenerator->IsNonPointerType($functionSigType)) {
1192                 push(@cBody, "    return static_cast<${returnType}>(0);\n");
1193             } else {
1194                 push(@cBody, "    return 0;\n");
1195             }
1196         }
1197         push(@cBody, "#endif /* ${conditionalString} */\n");
1198     }
1199
1200     if ($parentConditionalString) {
1201         push(@cBody, "#else\n");
1202
1203         push(@cBody, "    UNUSED_PARAM(self);\n");
1204         foreach my $param (@{$function->parameters}) {
1205             push(@cBody, "    UNUSED_PARAM(" . $param->name . ");\n");
1206         }
1207         push(@cBody, "    UNUSED_PARAM(error);\n") if $raisesException;
1208
1209         push(@cBody, @parentConditionalWarn) if scalar(@parentConditionalWarn);
1210         if ($returnType ne "void") {
1211             if ($codeGenerator->IsNonPointerType($functionSigType)) {
1212                 push(@cBody, "    return static_cast<${returnType}>(0);\n");
1213             } else {
1214                 push(@cBody, "    return 0;\n");
1215             }
1216         }
1217         push(@cBody, "#endif /* ${parentConditionalString} */\n");
1218     }
1219
1220     push(@cBody, "}\n\n");
1221 }
1222
1223 sub ClassHasFunction {
1224     my ($class, $name) = @_;
1225
1226     foreach my $function (@{$class->functions}) {
1227         if ($function->signature->name eq $name) {
1228             return 1;
1229         }
1230     }
1231
1232     return 0;
1233 }
1234
1235 sub GenerateFunctions {
1236     my ($object, $interfaceName, $interface) = @_;
1237
1238     foreach my $function (@{$interface->functions}) {
1239         $object->GenerateFunction($interfaceName, $function, "", $interface);
1240     }
1241
1242     TOP:
1243     foreach my $attribute (@{$interface->attributes}) {
1244         if (SkipAttribute($attribute)) {
1245             next TOP;
1246         }
1247
1248         if ($attribute->signature->name eq "type") {
1249             # This will conflict with the get_type() function we define to return a GType
1250             # according to GObject conventions.  Skip this for now.
1251             next TOP;
1252         }
1253             
1254         my $attrNameUpper = $codeGenerator->WK_ucfirst($attribute->signature->name);
1255         my $getname = "get${attrNameUpper}";
1256         my $setname = "set${attrNameUpper}";
1257         if (ClassHasFunction($interface, $getname) || ClassHasFunction($interface, $setname)) {
1258             # Very occasionally an IDL file defines getter/setter functions for one of its
1259             # attributes; in this case we don't need to autogenerate the getter/setter.
1260             next TOP;
1261         }
1262         
1263         # Generate an attribute getter.  For an attribute "foo", this is a function named
1264         # "get_foo" which calls a DOM class method named foo().
1265         my $function = new domFunction();
1266         $function->signature($attribute->signature);
1267         $function->signature->extendedAttributes({%{$attribute->signature->extendedAttributes}});
1268         if ($attribute->signature->extendedAttributes->{"GetterRaisesException"}) {
1269             $function->signature->extendedAttributes->{"RaisesException"} = "VALUE_IS_MISSING";
1270         }
1271         $object->GenerateFunction($interfaceName, $function, "get_", $interface);
1272
1273         # FIXME: We are not generating setters for 'Replaceable'
1274         # attributes now, but we should somehow.
1275         my $custom = $attribute->signature->extendedAttributes->{"CustomSetter"};
1276         if ($attribute->isReadOnly || $attribute->signature->extendedAttributes->{"Replaceable"} || $custom) {
1277             next TOP;
1278         }
1279         
1280         # Generate an attribute setter.  For an attribute, "foo", this is a function named
1281         # "set_foo" which calls a DOM class method named setFoo().
1282         $function = new domFunction();
1283         
1284         $function->signature(new domSignature());
1285         $function->signature->name($attribute->signature->name);
1286         $function->signature->type($attribute->signature->type);
1287         $function->signature->extendedAttributes({%{$attribute->signature->extendedAttributes}});
1288         
1289         my $param = new domSignature();
1290         $param->name("value");
1291         $param->type($attribute->signature->type);
1292         my %attributes = ();
1293         $param->extendedAttributes(\%attributes);
1294         my $arrayRef = $function->parameters;
1295         push(@$arrayRef, $param);
1296         
1297         if ($attribute->signature->extendedAttributes->{"SetterRaisesException"}) {
1298             $function->signature->extendedAttributes->{"RaisesException"} = "VALUE_IS_MISSING";
1299         } else {
1300             delete $function->signature->extendedAttributes->{"RaisesException"};
1301         }
1302         
1303         $object->GenerateFunction($interfaceName, $function, "set_", $interface);
1304     }
1305 }
1306
1307 sub GenerateCFile {
1308     my ($object, $interfaceName, $parentClassName, $parentGObjType, $interface) = @_;
1309
1310     if ($interface->extendedAttributes->{"EventTarget"}) {
1311         $object->GenerateEventTargetIface($interface);
1312     }
1313
1314     my $implContent = "";
1315
1316     my $decamelize = decamelize($interfaceName);
1317     my $clsCaps = uc($decamelize);
1318     my $lowerCaseIfaceName = "webkit_dom_$decamelize";
1319     my $parentImplClassName = GetParentImplClassName($interface);
1320     my $baseClassName = GetBaseClass($parentImplClassName, $interface);
1321
1322     # Add a private struct only for direct subclasses of Object so that we can use RefPtr
1323     # for the WebCore wrapped object and make sure we only increment the reference counter once.
1324     if ($parentImplClassName eq "Object") {
1325         my $conditionalString = $codeGenerator->GenerateConditionalString($interface);
1326         push(@cStructPriv, "#define WEBKIT_DOM_${clsCaps}_GET_PRIVATE(obj) G_TYPE_INSTANCE_GET_PRIVATE(obj, WEBKIT_TYPE_DOM_${clsCaps}, ${className}Private)\n\n");
1327         push(@cStructPriv, "typedef struct _${className}Private {\n");
1328         push(@cStructPriv, "#if ${conditionalString}\n") if $conditionalString;
1329         push(@cStructPriv, "    RefPtr<WebCore::${interfaceName}> coreObject;\n");
1330         push(@cStructPriv, "#endif // ${conditionalString}\n") if $conditionalString;
1331         push(@cStructPriv, "} ${className}Private;\n\n");
1332     }
1333
1334     $implContent = << "EOF";
1335 ${defineTypeMacro}(${className}, ${lowerCaseIfaceName}, ${parentGObjType}${defineTypeInterfaceImplementation}
1336
1337 EOF
1338     push(@cBodyProperties, $implContent);
1339
1340     if ($parentImplClassName eq "Object") {
1341         push(@cBodyPriv, "${className}* kit(WebCore::$interfaceName* obj)\n");
1342         push(@cBodyPriv, "{\n");
1343         push(@cBodyPriv, "    if (!obj)\n");
1344         push(@cBodyPriv, "        return 0;\n\n");
1345         push(@cBodyPriv, "    if (gpointer ret = DOMObjectCache::get(obj))\n");
1346         push(@cBodyPriv, "        return WEBKIT_DOM_${clsCaps}(ret);\n\n");
1347         if (IsPolymorphic($interfaceName)) {
1348             push(@cBodyPriv, "    return wrap(obj);\n");
1349         } else {
1350             push(@cBodyPriv, "    return wrap${interfaceName}(obj);\n");
1351         }
1352         push(@cBodyPriv, "}\n\n");
1353     } else {
1354         push(@cBodyPriv, "${className}* kit(WebCore::$interfaceName* obj)\n");
1355         push(@cBodyPriv, "{\n");
1356         if (!IsPolymorphic($baseClassName)) {
1357             push(@cBodyPriv, "    if (!obj)\n");
1358             push(@cBodyPriv, "        return 0;\n\n");
1359             push(@cBodyPriv, "    if (gpointer ret = DOMObjectCache::get(obj))\n");
1360             push(@cBodyPriv, "        return WEBKIT_DOM_${clsCaps}(ret);\n\n");
1361             push(@cBodyPriv, "    return wrap${interfaceName}(obj);\n");
1362         } else {
1363             push(@cBodyPriv, "    return WEBKIT_DOM_${clsCaps}(kit(static_cast<WebCore::$baseClassName*>(obj)));\n");
1364         }
1365         push(@cBodyPriv, "}\n\n");
1366     }
1367
1368     $implContent = << "EOF";
1369 WebCore::${interfaceName}* core(${className}* request)
1370 {
1371     return request ? static_cast<WebCore::${interfaceName}*>(WEBKIT_DOM_OBJECT(request)->coreObject) : 0;
1372 }
1373
1374 ${className}* wrap${interfaceName}(WebCore::${interfaceName}* coreObject)
1375 {
1376     ASSERT(coreObject);
1377     return WEBKIT_DOM_${clsCaps}(g_object_new(WEBKIT_TYPE_DOM_${clsCaps}, "core-object", coreObject, NULL));
1378 }
1379
1380 EOF
1381     push(@cBodyPriv, $implContent);
1382
1383     $object->GenerateProperties($interfaceName, $interface);
1384     $object->GenerateFunctions($interfaceName, $interface);
1385 }
1386
1387 sub GenerateEndHeader {
1388     my ($object) = @_;
1389
1390     #Header guard
1391     my $guard = $className . "_h";
1392
1393     push(@hBody, "G_END_DECLS\n\n");
1394     push(@hPrefixGuardEnd, "#endif /* $guard */\n");
1395 }
1396
1397 sub IsPolymorphic {
1398     my $type = shift;
1399
1400     return scalar(grep {$_ eq $type} qw(Blob Event HTMLCollection Node StyleSheet TextTrackCue));
1401 }
1402
1403 sub GenerateEventTargetIface {
1404     my $object = shift;
1405     my $interface = shift;
1406
1407     my $interfaceName = $interface->name;
1408     my $decamelize = decamelize($interfaceName);
1409     my $conditionalString = $codeGenerator->GenerateConditionalString($interface);
1410     my @conditionalWarn = GenerateConditionalWarning($interface);
1411
1412     $implIncludes{"GObjectEventListener.h"} = 1;
1413     $implIncludes{"WebKitDOMEventTarget.h"} = 1;
1414     $implIncludes{"WebKitDOMEventPrivate.h"} = 1;
1415
1416     push(@cBodyProperties, "static gboolean webkit_dom_${decamelize}_dispatch_event(WebKitDOMEventTarget* target, WebKitDOMEvent* event, GError** error)\n{\n");
1417     push(@cBodyProperties, "#if ${conditionalString}\n") if $conditionalString;
1418     push(@cBodyProperties, "    WebCore::Event* coreEvent = WebKit::core(event);\n");
1419     push(@cBodyProperties, "    WebCore::${interfaceName}* coreTarget = static_cast<WebCore::${interfaceName}*>(WEBKIT_DOM_OBJECT(target)->coreObject);\n\n");
1420     push(@cBodyProperties, "    WebCore::ExceptionCode ec = 0;\n");
1421     push(@cBodyProperties, "    gboolean result = coreTarget->dispatchEvent(coreEvent, ec);\n");
1422     push(@cBodyProperties, "    if (ec) {\n        WebCore::ExceptionCodeDescription description(ec);\n");
1423     push(@cBodyProperties, "        g_set_error_literal(error, g_quark_from_string(\"WEBKIT_DOM\"), description.code, description.name);\n    }\n");
1424     push(@cBodyProperties, "    return result;\n");
1425     if ($conditionalString) {
1426         push(@cBodyProperties, "#else\n");
1427         push(@cBodyProperties, "    UNUSED_PARAM(target);\n");
1428         push(@cBodyProperties, "    UNUSED_PARAM(event);\n");
1429         push(@cBodyProperties, "    UNUSED_PARAM(error);\n");
1430         push(@cBodyProperties, @conditionalWarn) if scalar(@conditionalWarn);
1431         push(@cBodyProperties, "    return false;\n#endif // ${conditionalString}\n");
1432     }
1433     push(@cBodyProperties, "}\n\n");
1434
1435     push(@cBodyProperties, "static gboolean webkit_dom_${decamelize}_add_event_listener(WebKitDOMEventTarget* target, const char* eventName, GClosure* handler, gboolean useCapture)\n{\n");
1436     push(@cBodyProperties, "#if ${conditionalString}\n") if $conditionalString;
1437     push(@cBodyProperties, "    WebCore::${interfaceName}* coreTarget = static_cast<WebCore::${interfaceName}*>(WEBKIT_DOM_OBJECT(target)->coreObject);\n");
1438     push(@cBodyProperties, "    return WebCore::GObjectEventListener::addEventListener(G_OBJECT(target), coreTarget, eventName, handler, useCapture);\n");
1439     if ($conditionalString) {
1440         push(@cBodyProperties, "#else\n");
1441         push(@cBodyProperties, "    UNUSED_PARAM(target);\n");
1442         push(@cBodyProperties, "    UNUSED_PARAM(eventName);\n");
1443         push(@cBodyProperties, "    UNUSED_PARAM(handler);\n");
1444         push(@cBodyProperties, "    UNUSED_PARAM(useCapture);\n");
1445         push(@cBodyProperties, @conditionalWarn) if scalar(@conditionalWarn);
1446         push(@cBodyProperties, "    return false;\n#endif // ${conditionalString}\n");
1447     }
1448     push(@cBodyProperties, "}\n\n");
1449
1450     push(@cBodyProperties, "static gboolean webkit_dom_${decamelize}_remove_event_listener(WebKitDOMEventTarget* target, const char* eventName, GClosure* handler, gboolean useCapture)\n{\n");
1451     push(@cBodyProperties, "#if ${conditionalString}\n") if $conditionalString;
1452     push(@cBodyProperties, "    WebCore::${interfaceName}* coreTarget = static_cast<WebCore::${interfaceName}*>(WEBKIT_DOM_OBJECT(target)->coreObject);\n");
1453     push(@cBodyProperties, "    return WebCore::GObjectEventListener::removeEventListener(G_OBJECT(target), coreTarget, eventName, handler, useCapture);\n");
1454     if ($conditionalString) {
1455         push(@cBodyProperties, "#else\n");
1456         push(@cBodyProperties, "    UNUSED_PARAM(target);\n");
1457         push(@cBodyProperties, "    UNUSED_PARAM(eventName);\n");
1458         push(@cBodyProperties, "    UNUSED_PARAM(handler);\n");
1459         push(@cBodyProperties, "    UNUSED_PARAM(useCapture);\n");
1460         push(@cBodyProperties, @conditionalWarn) if scalar(@conditionalWarn);
1461         push(@cBodyProperties, "    return false;\n#endif // ${conditionalString}\n");
1462     }
1463     push(@cBodyProperties, "}\n\n");
1464
1465     push(@cBodyProperties, "static void webkit_dom_event_target_init(WebKitDOMEventTargetIface* iface)\n{\n");
1466     push(@cBodyProperties, "    iface->dispatch_event = webkit_dom_${decamelize}_dispatch_event;\n");
1467     push(@cBodyProperties, "    iface->add_event_listener = webkit_dom_${decamelize}_add_event_listener;\n");
1468     push(@cBodyProperties, "    iface->remove_event_listener = webkit_dom_${decamelize}_remove_event_listener;\n}\n\n");
1469
1470     $defineTypeMacro = "G_DEFINE_TYPE_WITH_CODE";
1471     $defineTypeInterfaceImplementation = ", G_IMPLEMENT_INTERFACE(WEBKIT_TYPE_DOM_EVENT_TARGET, webkit_dom_event_target_init))";
1472 }
1473
1474 sub Generate {
1475     my ($object, $interface) = @_;
1476
1477     my $parentClassName = GetParentClassName($interface);
1478     my $parentGObjType = GetParentGObjType($interface);
1479     my $interfaceName = $interface->name;
1480     my $parentImplClassName = GetParentImplClassName($interface);
1481     my $baseClassName = GetBaseClass($parentImplClassName, $interface);
1482
1483     # Add the default impl header template
1484     @cPrefix = split("\r", $licenceTemplate);
1485     push(@cPrefix, "\n");
1486
1487     $implIncludes{"DOMObjectCache.h"} = 1;
1488     $implIncludes{"WebKitDOMPrivate.h"} = 1;
1489     $implIncludes{"gobject/ConvertToUTF8String.h"} = 1;
1490     $implIncludes{"${className}Private.h"} = 1;
1491     $implIncludes{"Document.h"} = 1;
1492     $implIncludes{"JSMainThreadExecState.h"} = 1;
1493     $implIncludes{"ExceptionCode.h"} = 1;
1494     $implIncludes{"CSSImportRule.h"} = 1;
1495     if ($parentImplClassName ne "Object" and IsPolymorphic($baseClassName)) {
1496         $implIncludes{"WebKitDOM${baseClassName}Private.h"} = 1;
1497     }
1498
1499     $hdrIncludes{"webkitdom/${parentClassName}.h"} = 1;
1500
1501     $object->GenerateHeader($interfaceName, $parentClassName);
1502     $object->GenerateCFile($interfaceName, $parentClassName, $parentGObjType, $interface);
1503     $object->GenerateEndHeader();
1504 }
1505
1506 sub WriteData {
1507     my $object = shift;
1508     my $interface = shift;
1509     my $outputDir = shift;
1510     mkdir $outputDir;
1511
1512     # Write a private header.
1513     my $interfaceName = $interface->name;
1514     my $filename = "$outputDir/" . $className . "Private.h";
1515     my $guard = "${className}Private_h";
1516
1517     # Add the guard if the 'Conditional' extended attribute exists
1518     my $conditionalString = $codeGenerator->GenerateConditionalString($interface);
1519
1520     open(PRIVHEADER, ">$filename") or die "Couldn't open file $filename for writing";
1521
1522     print PRIVHEADER split("\r", $licenceTemplate);
1523     print PRIVHEADER "\n";
1524
1525     my $text = << "EOF";
1526 #ifndef $guard
1527 #define $guard
1528
1529 #include "${interfaceName}.h"
1530 #include <webkitdom/${className}.h>
1531 EOF
1532
1533     print PRIVHEADER $text;
1534     print PRIVHEADER "#if ${conditionalString}\n" if $conditionalString;
1535     print PRIVHEADER "\n";
1536     $text = << "EOF";
1537 namespace WebKit {
1538 ${className}* wrap${interfaceName}(WebCore::${interfaceName}*);
1539 ${className}* kit(WebCore::${interfaceName}*);
1540 WebCore::${interfaceName}* core(${className}*);
1541 EOF
1542
1543     print PRIVHEADER $text;
1544
1545     $text = << "EOF";
1546 } // namespace WebKit
1547
1548 EOF
1549
1550     print PRIVHEADER $text;
1551     print PRIVHEADER "#endif /* ${conditionalString} */\n\n" if $conditionalString;
1552     print PRIVHEADER "#endif /* ${guard} */\n";
1553
1554     close(PRIVHEADER);
1555
1556     my $basename = FileNamePrefix . $interfaceName;
1557     $basename =~ s/_//g;
1558
1559     # Write public header.
1560     my $fullHeaderFilename = "$outputDir/" . $basename . ".h";
1561     my $installedHeaderFilename = "${basename}.h";
1562     open(HEADER, ">$fullHeaderFilename") or die "Couldn't open file $fullHeaderFilename";
1563
1564     print HEADER @hPrefix;
1565     print HEADER @hPrefixGuard;
1566     print HEADER "#include <glib-object.h>\n";
1567     print HEADER map { "#include <$_>\n" } sort keys(%hdrIncludes);
1568     print HEADER "#include <webkitdom/webkitdomdefines.h>\n\n";
1569     print HEADER @hBodyPre;
1570     print HEADER @hBody;
1571     print HEADER @hPrefixGuardEnd;
1572
1573     close(HEADER);
1574
1575     # Write the implementation sources
1576     my $implFileName = "$outputDir/" . $basename . ".cpp";
1577     open(IMPL, ">$implFileName") or die "Couldn't open file $implFileName";
1578
1579     print IMPL @cPrefix;
1580     print IMPL "#include \"config.h\"\n";
1581     print IMPL "#include \"$installedHeaderFilename\"\n\n";
1582
1583     # Remove the implementation header from the list of included files.
1584     %includesCopy = %implIncludes;
1585     print IMPL map { "#include \"$_\"\n" } sort keys(%includesCopy);
1586
1587     print IMPL "#include <wtf/GetPtr.h>\n";
1588     print IMPL "#include <wtf/RefPtr.h>\n\n";
1589     print IMPL @cStructPriv;
1590     print IMPL "#if ${conditionalString}\n\n" if $conditionalString;
1591
1592     print IMPL "namespace WebKit {\n\n";
1593     print IMPL @cBodyPriv;
1594     print IMPL "} // namespace WebKit\n\n";
1595     print IMPL "#endif // ${conditionalString}\n\n" if $conditionalString;
1596
1597     print IMPL @cBodyProperties;
1598     print IMPL @cBody;
1599
1600     close(IMPL);
1601
1602     # Write a symbols file.
1603     my $symbolsFileName = "$outputDir/" . $basename . ".symbols";
1604     open(SYM, ">$symbolsFileName") or die "Couldn't open file $symbolsFileName";
1605     print SYM @symbols;
1606     close(SYM);
1607
1608     %implIncludes = ();
1609     %hdrIncludes = ();
1610     @hPrefix = ();
1611     @hBody = ();
1612
1613     @cPrefix = ();
1614     @cBody = ();
1615     @cBodyPriv = ();
1616     @cBodyProperties = ();
1617     @cStructPriv = ();
1618
1619     @symbols = ();
1620 }
1621
1622 sub GenerateInterface {
1623     my ($object, $interface, $defines) = @_;
1624
1625     # Set up some global variables
1626     $className = GetClassName($interface->name);
1627
1628     $object->Generate($interface);
1629 }
1630
1631 1;