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