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