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