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