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
23package CodeGeneratorGObject;
24
25# Global Variables
26my %implIncludes = ();
27my %hdrIncludes = ();
28
29my $defineTypeMacro = "G_DEFINE_TYPE";
30my $defineTypeInterfaceImplementation = ")";
31my @txtEventListeners = ();
32my @txtInstallEventListeners = ();
33my @txtInstallSignals = ();
34my @txtInstallProps = ();
35my @txtSetProps = ();
36my @txtGetProps = ();
37
38my $className = "";
39
40# Default constructor
41sub new {
42    my $object = shift;
43    my $reference = { };
44
45    $codeGenerator = shift;
46    $outputDir = shift;
47    mkdir $outputDir;
48
49    bless($reference, $object);
50}
51
52sub finish {
53}
54
55my $licenceTemplate = << "EOF";
56/*
57    This file is part of the WebKit open source project.
58    This file has been generated by generate-bindings.pl. DO NOT MODIFY!
59
60    This library is free software; you can redistribute it and/or
61    modify it under the terms of the GNU Library General Public
62    License as published by the Free Software Foundation; either
63    version 2 of the License, or (at your option) any later version.
64
65    This library is distributed in the hope that it will be useful,
66    but WITHOUT ANY WARRANTY; without even the implied warranty of
67    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
68    Library General Public License for more details.
69
70    You should have received a copy of the GNU Library General Public License
71    along with this library; see the file COPYING.LIB.  If not, write to
72    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
73    Boston, MA 02110-1301, USA.
74*/
75EOF
76
77sub GenerateModule {
78}
79
80sub GetParentClassName {
81    my $dataNode = shift;
82
83    return "WebKitDOMObject" if @{$dataNode->parents} eq 0;
84    return "WebKitDOM" . $codeGenerator->StripModule($dataNode->parents(0));
85}
86
87# From String::CamelCase 0.01
88sub camelize
89{
90        my $s = shift;
91        join('', map{ ucfirst $_ } split(/(?<=[A-Za-z])_(?=[A-Za-z])|\b/, $s));
92}
93
94sub decamelize
95{
96        my $s = shift;
97        $s =~ s{([^a-zA-Z]?)([A-Z]*)([A-Z])([a-z]?)}{
98                my $fc = pos($s)==0;
99                my ($p0,$p1,$p2,$p3) = ($1,lc$2,lc$3,$4);
100                my $t = $p0 || $fc ? $p0 : '_';
101                $t .= $p3 ? $p1 ? "${p1}_$p2$p3" : "$p2$p3" : "$p1$p2";
102                $t;
103        }ge;
104        $s;
105}
106
107sub FixUpDecamelizedName {
108    my $classname = shift;
109
110    # FIXME: try to merge this somehow with the fixes in ClassNameToGobjectType
111    $classname =~ s/x_path/xpath/;
112    $classname =~ s/web_kit/webkit/;
113    $classname =~ s/htmli_frame/html_iframe/;
114
115    return $classname;
116}
117
118sub ClassNameToGObjectType {
119    my $className = shift;
120    my $CLASS_NAME = uc(decamelize($className));
121    # Fixup: with our prefix being 'WebKitDOM' decamelize can't get
122    # WebKitDOMCSS and similar names right, so we have to fix it
123    # manually.
124    $CLASS_NAME =~ s/DOMCSS/DOM_CSS/;
125    $CLASS_NAME =~ s/DOMHTML/DOM_HTML/;
126    $CLASS_NAME =~ s/DOMDOM/DOM_DOM/;
127    $CLASS_NAME =~ s/DOMCDATA/DOM_CDATA/;
128    $CLASS_NAME =~ s/DOMX_PATH/DOM_XPATH/;
129    $CLASS_NAME =~ s/DOM_WEB_KIT/DOM_WEBKIT/;
130    $CLASS_NAME =~ s/DOMUI/DOM_UI/;
131    $CLASS_NAME =~ s/HTMLI_FRAME/HTML_IFRAME/;
132    return $CLASS_NAME;
133}
134
135sub GetParentGObjType {
136    my $dataNode = shift;
137
138    return "WEBKIT_TYPE_DOM_OBJECT" if @{$dataNode->parents} eq 0;
139    return "WEBKIT_TYPE_DOM_" . ClassNameToGObjectType($codeGenerator->StripModule($dataNode->parents(0)));
140}
141
142sub GetClassName {
143    my $name = $codeGenerator->StripModule(shift);
144
145    return "WebKitDOM$name";
146}
147
148sub GetCoreObject {
149    my ($interfaceName, $name, $parameter) = @_;
150
151    return "WebCore::${interfaceName}* $name = WebKit::core($parameter);";
152}
153
154sub SkipAttribute {
155    my $attribute = shift;
156
157    if ($attribute->signature->extendedAttributes->{"CustomGetter"} ||
158        $attribute->signature->extendedAttributes->{"CustomSetter"} ||
159        $attribute->signature->extendedAttributes->{"Replaceable"}) {
160        return 1;
161    }
162
163    my $propType = $attribute->signature->type;
164    if ($propType =~ /Constructor$/) {
165        return 1;
166    }
167
168    # This is for DOMWindow.idl location attribute
169    if ($attribute->signature->name eq "location") {
170        return 1;
171    }
172
173    # This is for HTMLInput.idl valueAsDate
174    if ($attribute->signature->name eq "valueAsDate") {
175        return 1;
176    }
177
178    # This is for DOMWindow.idl Crypto attribute
179    if ($attribute->signature->type eq "Crypto") {
180        return 1;
181    }
182
183    return 0;
184}
185
186sub SkipFunction {
187    my $function = shift;
188    my $decamelize = shift;
189    my $prefix = shift;
190
191    my $functionName = "webkit_dom_" . $decamelize . "_" . $prefix . decamelize($function->signature->name);
192    my $isCustomFunction = $function->signature->extendedAttributes->{"Custom"} ||
193        $function->signature->extendedAttributes->{"CustomArgumentHandling"};
194
195    if ($isCustomFunction &&
196        $functionName ne "webkit_dom_node_replace_child" &&
197        $functionName ne "webkit_dom_node_insert_before" &&
198        $functionName ne "webkit_dom_node_remove_child" &&
199        $functionName ne "webkit_dom_node_append_child" &&
200        $functionName ne "webkit_dom_html_collection_item" &&
201        $functionName ne "webkit_dom_html_collection_named_item") {
202        return 1;
203    }
204
205    if ($function->signature->name eq "getSVGDocument") {
206        return 1;
207    }
208
209    if ($function->signature->name eq "getCSSCanvasContext") {
210        return 1;
211    }
212
213    # Skip functions that have ["Callback"] parameters, because this
214    # code generator doesn't know how to auto-generate callbacks.
215    # Skip functions that have "MediaQueryListListener" parameters, because this
216    # code generator doesn't know how to auto-generate MediaQueryListListener.
217    foreach my $param (@{$function->parameters}) {
218        if ($param->extendedAttributes->{"Callback"} ||
219            $param->type eq "MediaQueryListListener") {
220            return 1;
221        }
222    }
223
224    return 0;
225}
226
227# Name type used in the g_value_{set,get}_* functions
228sub GetGValueTypeName {
229    my $type = shift;
230
231    my %types = ("DOMString", "string",
232                 "DOMTimeStamp", "uint",
233                 "float", "float",
234                 "double", "double",
235                 "boolean", "boolean",
236                 "char", "char",
237                 "long", "long",
238                 "long long", "int64",
239                 "short", "int",
240                 "uchar", "uchar",
241                 "unsigned", "uint",
242                 "int", "int",
243                 "unsigned int", "uint",
244                 "unsigned long long", "uint64",
245                 "unsigned long", "ulong",
246                 "unsigned short", "ushort");
247
248    return $types{$type} ? $types{$type} : "object";
249}
250
251# Name type used in C declarations
252sub GetGlibTypeName {
253    my $type = shift;
254    my $name = GetClassName($type);
255
256    my %types = ("DOMString", "gchar*",
257                 "DOMTimeStamp", "guint32",
258                 "CompareHow", "gushort",
259                 "float", "gfloat",
260                 "double", "gdouble",
261                 "boolean", "gboolean",
262                 "char", "gchar",
263                 "long", "glong",
264                 "long long", "gint64",
265                 "short", "gshort",
266                 "uchar", "guchar",
267                 "unsigned", "guint",
268                 "int", "gint",
269                 "unsigned int", "guint",
270                 "unsigned long", "gulong",
271                 "unsigned long long", "guint64",
272                 "unsigned short", "gushort",
273                 "void", "void");
274
275    return $types{$type} ? $types{$type} : "$name*";
276}
277
278sub IsGDOMClassType {
279    my $type = shift;
280
281    return 0 if $codeGenerator->IsNonPointerType($type) || $codeGenerator->IsStringType($type);
282    return 1;
283}
284
285sub GetReadableProperties {
286    my $properties = shift;
287
288    my @result = ();
289
290    foreach my $property (@{$properties}) {
291        if (!SkipAttribute($property)) {
292            push(@result, $property);
293        }
294    }
295
296    return @result;
297}
298
299sub GetWriteableProperties {
300    my $properties = shift;
301    my @result = ();
302
303    foreach my $property (@{$properties}) {
304        my $writeable = $property->type !~ /^readonly/;
305        my $gtype = GetGValueTypeName($property->signature->type);
306        my $hasGtypeSignature = ($gtype eq "boolean" || $gtype eq "float" || $gtype eq "double" ||
307                                 $gtype eq "uint64" || $gtype eq "ulong" || $gtype eq "long" ||
308                                 $gtype eq "uint" || $gtype eq "ushort" || $gtype eq "uchar" ||
309                                 $gtype eq "char" || $gtype eq "string");
310        if ($writeable && $hasGtypeSignature) {
311            push(@result, $property);
312        }
313    }
314
315    return @result;
316}
317
318sub GenerateConditionalString
319{
320    my $node = shift;
321    my $conditional = $node->extendedAttributes->{"Conditional"};
322    if ($conditional) {
323        if ($conditional =~ /&/) {
324            return "ENABLE(" . join(") && ENABLE(", split(/&/, $conditional)) . ")";
325        } elsif ($conditional =~ /\|/) {
326            return "ENABLE(" . join(") || ENABLE(", split(/\|/, $conditional)) . ")";
327        } else {
328            return "ENABLE(" . $conditional . ")";
329        }
330    } else {
331        return "";
332    }
333}
334
335sub GenerateProperty {
336    my $attribute = shift;
337    my $interfaceName = shift;
338    my @writeableProperties = @{shift @_};
339
340    my $conditionalString = GenerateConditionalString($attribute->signature);
341    my $camelPropName = $attribute->signature->name;
342    my $setPropNameFunction = $codeGenerator->WK_ucfirst($camelPropName);
343    my $getPropNameFunction = $codeGenerator->WK_lcfirst($camelPropName);
344
345    my $propName = decamelize($camelPropName);
346    my $propNameCaps = uc($propName);
347    $propName =~ s/_/-/g;
348    my ${propEnum} = "PROP_${propNameCaps}";
349    push(@cBodyPriv, "#if ${conditionalString}\n") if $conditionalString;
350    push(@cBodyPriv, "    ${propEnum},\n");
351    push(@cBodyPriv, "#endif /* ${conditionalString} */\n") if $conditionalString;
352
353    my $propType = $attribute->signature->type;
354    my ${propGType} = decamelize($propType);
355    my ${ucPropGType} = uc($propGType);
356
357    my $gtype = GetGValueTypeName($propType);
358    my $gparamflag = "WEBKIT_PARAM_READABLE";
359    my $writeable = $attribute->type !~ /^readonly/;
360    my $const = "read-only ";
361    my $custom = $attribute->signature->extendedAttributes->{"Custom"};
362    if ($writeable && $custom) {
363        $const = "read-only (due to custom functions needed in webkitdom)";
364        return;
365    }
366    if ($writeable && !$custom) {
367        $gparamflag = "WEBKIT_PARAM_READWRITE";
368        $const = "read-write ";
369    }
370
371    my $type = GetGlibTypeName($propType);
372    $nick = decamelize("${interfaceName}_${propName}");
373    $long = "${const} ${type} ${interfaceName}.${propName}";
374
375    my $convertFunction = "";
376    if ($gtype eq "string") {
377        $convertFunction = "WTF::String::fromUTF8";
378    }
379
380    my $getterExpressionPrefix = $codeGenerator->GetterExpressionPrefix(\%implIncludes, $interfaceName, $attribute);
381    my $setterExpressionPrefix = $codeGenerator->SetterExpressionPrefix(\%implIncludes, $interfaceName, $attribute);
382
383    my $getterContentHead = "coreSelf->$getterExpressionPrefix";
384    my $setterContentHead = "coreSelf->$setterExpressionPrefix${convertFunction}(g_value_get_$gtype(value))";
385
386    if (grep {$_ eq $attribute} @writeableProperties) {
387        push(@txtSetProps, "#if ${conditionalString}\n") if $conditionalString;
388        push(@txtSetProps, "    case ${propEnum}:\n    {\n");
389        push(@txtSetProps, "        WebCore::ExceptionCode ec = 0;\n") if @{$attribute->setterExceptions};
390        push(@txtSetProps, "        ${setterContentHead}");
391        push(@txtSetProps, ", ec") if @{$attribute->setterExceptions};
392        push(@txtSetProps, ");\n");
393        push(@txtSetProps, "        break;\n    }\n");
394        push(@txtSetProps, "#endif /* ${conditionalString} */\n") if $conditionalString;
395    }
396
397    push(@txtGetProps, "#if ${conditionalString}\n") if $conditionalString;
398    push(@txtGetProps, "    case ${propEnum}:\n    {\n");
399
400    my $exception = "";
401    if (@{$attribute->getterExceptions}) {
402        $exception = "ec";
403        push(@txtGetProps, "        WebCore::ExceptionCode ec = 0;\n");
404    }
405
406    my $postConvertFunction = "";
407    my $done = 0;
408    if ($gtype eq "string") {
409        push(@txtGetProps, "        g_value_take_string(value, convertToUTF8String(${getterContentHead}${exception})));\n");
410        $done = 1;
411    } elsif ($gtype eq "object") {
412        $txtGetProp = << "EOF";
413        RefPtr<WebCore::${propType}> ptr = coreSelf->${getPropNameFunction}(${exception});
414        g_value_set_object(value, WebKit::kit(ptr.get()));
415EOF
416        push(@txtGetProps, $txtGetProp);
417        $done = 1;
418    }
419
420    # FIXME: get rid of this glitch?
421    my $_gtype = $gtype;
422    if ($gtype eq "ushort") {
423        $_gtype = "uint";
424    }
425
426    if (!$done) {
427        push(@txtGetProps, "        g_value_set_$_gtype(value, ${convertFunction}coreSelf->${getterExpressionPrefix}${exception})${postConvertFunction});\n");
428    }
429
430    push(@txtGetProps, "        break;\n    }\n");
431    push(@txtGetProps, "#endif /* ${conditionalString} */\n") if $conditionalString;
432
433    my %param_spec_options = ("int", "G_MININT, /* min */\nG_MAXINT, /* max */\n0, /* default */",
434                              "boolean", "FALSE, /* default */",
435                              "float", "-G_MAXFLOAT, /* min */\nG_MAXFLOAT, /* max */\n0.0, /* default */",
436                              "double", "-G_MAXDOUBLE, /* min */\nG_MAXDOUBLE, /* max */\n0.0, /* default */",
437                              "uint64", "0, /* min */\nG_MAXUINT64, /* min */\n0, /* default */",
438                              "long", "G_MINLONG, /* min */\nG_MAXLONG, /* max */\n0, /* default */",
439                              "int64", "G_MININT64, /* min */\nG_MAXINT64, /* max */\n0, /* default */",
440                              "ulong", "0, /* min */\nG_MAXULONG, /* max */\n0, /* default */",
441                              "uint", "0, /* min */\nG_MAXUINT, /* max */\n0, /* default */",
442                              "ushort", "0, /* min */\nG_MAXUINT16, /* max */\n0, /* default */",
443                              "uchar", "G_MININT8, /* min */\nG_MAXINT8, /* max */\n0, /* default */",
444                              "char", "0, /* min */\nG_MAXUINT8, /* max */\n0, /* default */",
445                              "string", "\"\", /* default */",
446                              "object", "WEBKIT_TYPE_DOM_${ucPropGType}, /* gobject type */");
447
448    my $txtInstallProp = << "EOF";
449    g_object_class_install_property(gobjectClass,
450                                    ${propEnum},
451                                    g_param_spec_${_gtype}("${propName}", /* name */
452                                                           "$nick", /* short description */
453                                                           "$long", /* longer - could do with some extra doc stuff here */
454                                                           $param_spec_options{$gtype}
455                                                           ${gparamflag}));
456EOF
457    push(@txtInstallProps, "#if ${conditionalString}\n") if $conditionalString;
458    push(@txtInstallProps, $txtInstallProp);
459    push(@txtInstallProps, "#endif /* ${conditionalString} */\n") if $conditionalString;
460}
461
462sub GenerateProperties {
463    my ($object, $interfaceName, $dataNode) = @_;
464
465    my $clsCaps = substr(ClassNameToGObjectType($className), 12);
466    my $lowerCaseIfaceName = "webkit_dom_" . (FixUpDecamelizedName(decamelize($interfaceName)));
467
468    # Properties
469    my $implContent = "";
470
471    # Properties
472    $implContent = << "EOF";
473enum {
474    PROP_0,
475EOF
476    push(@cBodyPriv, $implContent);
477
478    my @readableProperties = GetReadableProperties($dataNode->attributes);
479
480    my $privFunction = GetCoreObject($interfaceName, "coreSelf", "self");
481
482    my $txtGetProp = << "EOF";
483static void ${lowerCaseIfaceName}_get_property(GObject* object, guint prop_id, GValue* value, GParamSpec* pspec)
484{
485    WebCore::JSMainThreadNullState state;
486EOF
487    push(@txtGetProps, $txtGetProp);
488    if (scalar @readableProperties > 0) {
489        $txtGetProp = << "EOF";
490    ${className}* self = WEBKIT_DOM_${clsCaps}(object);
491    $privFunction
492EOF
493    push(@txtGetProps, $txtGetProp);
494    }
495
496    $txtGetProp = << "EOF";
497    switch (prop_id) {
498EOF
499    push(@txtGetProps, $txtGetProp);
500
501    my @writeableProperties = GetWriteableProperties(\@readableProperties);
502
503    my $txtSetProps = << "EOF";
504static void ${lowerCaseIfaceName}_set_property(GObject* object, guint prop_id, const GValue* value, GParamSpec* pspec)
505{
506    WebCore::JSMainThreadNullState state;
507EOF
508    push(@txtSetProps, $txtSetProps);
509
510    if (scalar @writeableProperties > 0) {
511        $txtSetProps = << "EOF";
512    ${className}* self = WEBKIT_DOM_${clsCaps}(object);
513    $privFunction
514EOF
515        push(@txtSetProps, $txtSetProps);
516    }
517
518    $txtSetProps = << "EOF";
519    switch (prop_id) {
520EOF
521    push(@txtSetProps, $txtSetProps);
522
523    foreach my $attribute (@readableProperties) {
524        if ($attribute->signature->type ne "EventListener" &&
525            $attribute->signature->type ne "MediaQueryListListener") {
526            GenerateProperty($attribute, $interfaceName, \@writeableProperties);
527        }
528    }
529
530    push(@cBodyPriv, "};\n\n");
531
532    $txtGetProp = << "EOF";
533    default:
534        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
535        break;
536    }
537}
538EOF
539    push(@txtGetProps, $txtGetProp);
540
541    $txtSetProps = << "EOF";
542    default:
543        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
544        break;
545    }
546}
547EOF
548    push(@txtSetProps, $txtSetProps);
549
550    # Do not insert extra spaces when interpolating array variables
551    $" = "";
552
553    $implContent = << "EOF";
554
555static void ${lowerCaseIfaceName}_finalize(GObject* object)
556{
557    WebKitDOMObject* dom_object = WEBKIT_DOM_OBJECT(object);
558
559    if (dom_object->coreObject) {
560        WebCore::${interfaceName}* coreObject = static_cast<WebCore::${interfaceName} *>(dom_object->coreObject);
561
562        WebKit::DOMObjectCache::forget(coreObject);
563        coreObject->deref();
564
565        dom_object->coreObject = NULL;
566    }
567
568    G_OBJECT_CLASS(${lowerCaseIfaceName}_parent_class)->finalize(object);
569}
570
571@txtSetProps
572
573@txtGetProps
574
575static void ${lowerCaseIfaceName}_constructed(GObject* object)
576{
577EOF
578    push(@cBodyPriv, $implContent);
579
580    $implContent = << "EOF";
581@txtInstallEventListeners
582    if (G_OBJECT_CLASS(${lowerCaseIfaceName}_parent_class)->constructed)
583        G_OBJECT_CLASS(${lowerCaseIfaceName}_parent_class)->constructed(object);
584}
585
586static void ${lowerCaseIfaceName}_class_init(${className}Class* requestClass)
587{
588    GObjectClass *gobjectClass = G_OBJECT_CLASS(requestClass);
589    gobjectClass->finalize = ${lowerCaseIfaceName}_finalize;
590    gobjectClass->set_property = ${lowerCaseIfaceName}_set_property;
591    gobjectClass->get_property = ${lowerCaseIfaceName}_get_property;
592    gobjectClass->constructed = ${lowerCaseIfaceName}_constructed;
593
594@txtInstallProps
595@txtInstallSignals
596}
597
598static void ${lowerCaseIfaceName}_init(${className}* request)
599{
600}
601
602EOF
603    push(@cBodyPriv, $implContent);
604}
605
606sub GenerateHeader {
607    my ($object, $interfaceName, $parentClassName) = @_;
608
609    my $implContent = "";
610
611    # Add the default header template
612    @hPrefix = split("\r", $licenceTemplate);
613    push(@hPrefix, "\n");
614
615    #Header guard
616    my $guard = $className . "_h";
617
618    @hPrefixGuard = << "EOF";
619#ifndef $guard
620#define $guard
621
622EOF
623
624    $implContent = << "EOF";
625G_BEGIN_DECLS
626EOF
627
628    push(@hBodyPre, $implContent);
629
630    my $decamelize = FixUpDecamelizedName(decamelize($interfaceName));
631    my $clsCaps = uc($decamelize);
632    my $lowerCaseIfaceName = "webkit_dom_" . ($decamelize);
633
634    $implContent = << "EOF";
635#define WEBKIT_TYPE_DOM_${clsCaps}            (${lowerCaseIfaceName}_get_type())
636#define WEBKIT_DOM_${clsCaps}(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), WEBKIT_TYPE_DOM_${clsCaps}, ${className}))
637#define WEBKIT_DOM_${clsCaps}_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass),  WEBKIT_TYPE_DOM_${clsCaps}, ${className}Class)
638#define WEBKIT_DOM_IS_${clsCaps}(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), WEBKIT_TYPE_DOM_${clsCaps}))
639#define WEBKIT_DOM_IS_${clsCaps}_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),  WEBKIT_TYPE_DOM_${clsCaps}))
640#define WEBKIT_DOM_${clsCaps}_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj),  WEBKIT_TYPE_DOM_${clsCaps}, ${className}Class))
641
642struct _${className} {
643    ${parentClassName} parent_instance;
644};
645
646struct _${className}Class {
647    ${parentClassName}Class parent_class;
648};
649
650WEBKIT_API GType
651${lowerCaseIfaceName}_get_type (void);
652
653EOF
654
655    push(@hBody, $implContent);
656}
657
658sub getIncludeHeader {
659    my $type = shift;
660    my $name = GetClassName($type);
661
662    return "" if $type eq "int";
663    return "" if $type eq "long";
664    return "" if $type eq "long long";
665    return "" if $type eq "short";
666    return "" if $type eq "char";
667    return "" if $type eq "float";
668    return "" if $type eq "double";
669    return "" if $type eq "unsigned";
670    return "" if $type eq "unsigned int";
671    return "" if $type eq "unsigned long";
672    return "" if $type eq "unsigned long long";
673    return "" if $type eq "unsigned short";
674    return "" if $type eq "DOMTimeStamp";
675    return "" if $type eq "EventListener";
676    return "" if $type eq "MediaQueryListListener";
677    return "" if $type eq "unsigned char";
678    return "" if $type eq "DOMString";
679    return "" if $type eq "float";
680    return "" if $type eq "boolean";
681    return "" if $type eq "void";
682    return "" if $type eq "CompareHow";
683
684    return "$name.h";
685}
686
687sub addIncludeInBody {
688    my $type = shift;
689
690    if ($type eq "DOMObject") {
691        return;
692    }
693
694    my $header = getIncludeHeader($type);
695    if ($header eq "") {
696        return;
697    }
698
699    if (IsGDOMClassType($type)) {
700        $implIncludes{"webkit/$header"} = 1;
701    } else {
702        $implIncludes{$header} = 1
703    }
704}
705
706sub GenerateFunction {
707    my ($object, $interfaceName, $function, $prefix) = @_;
708
709    my $decamelize = FixUpDecamelizedName(decamelize($interfaceName));
710
711    if ($object eq "MediaQueryListListener") {
712        return;
713    }
714
715    if (SkipFunction($function, $decamelize, $prefix)) {
716        return;
717    }
718
719    my $functionSigName = $function->signature->name;
720    my $functionSigType = $prefix eq "set_" ? "void" : $function->signature->type;
721    my $functionName = "webkit_dom_" . $decamelize . "_" . $prefix . decamelize($functionSigName);
722    my $returnType = GetGlibTypeName($functionSigType);
723    my $returnValueIsGDOMType = IsGDOMClassType($functionSigType);
724    my $conditionalString = GenerateConditionalString($function->signature);
725
726    my $functionSig = "${className}* self";
727
728    my $callImplParams = "";
729
730    # skip some custom functions for now
731    my $isCustomFunction = $function->signature->extendedAttributes->{"Custom"} ||
732                       $function->signature->extendedAttributes->{"CustomArgumentHandling"};
733
734    foreach my $param (@{$function->parameters}) {
735        my $paramIDLType = $param->type;
736        if ($paramIDLType eq "EventListener" || $paramIDLType eq "MediaQueryListListener") {
737            # EventListeners are handled elsewhere.
738            return;
739        }
740        addIncludeInBody($paramIDLType);
741        my $paramType = GetGlibTypeName($paramIDLType);
742        my $const = $paramType eq "gchar*" ? "const " : "";
743        my $paramName = decamelize($param->name);
744
745        $functionSig .= ", ${const}$paramType $paramName";
746
747        my $paramIsGDOMType = IsGDOMClassType($paramIDLType);
748        if ($paramIsGDOMType) {
749            if ($paramIDLType ne "DOMObject") {
750                $implIncludes{"webkit/WebKitDOM${paramIDLType}Private.h"} = 1;
751            }
752        }
753        if ($paramIsGDOMType || ($paramIDLType eq "DOMString") || ($paramIDLType eq "CompareHow")) {
754            $paramName = "converted_" . $paramName;
755        }
756        if ($callImplParams) {
757            $callImplParams .= ", $paramName";
758        } else {
759            $callImplParams = "$paramName";
760        }
761    }
762
763    # Not quite sure what to do with this yet, but we need to take into
764    # account the difference in parameters between the IDL file and the
765    # actual implementation.
766    if ($function->signature->extendedAttributes->{"NeedsUserGestureCheck"}) {
767        $functionSig .= ", gboolean isUserGesture";
768        $callImplParams .= ", " if $callImplParams;
769        $callImplParams .= "false";
770    }
771
772    if ($returnType ne "void" && $returnValueIsGDOMType && $functionSigType ne "DOMObject") {
773        if ($functionSigType ne "EventTarget") {
774            $implIncludes{"webkit/WebKitDOM${functionSigType}Private.h"} = 1;
775            $implIncludes{"webkit/WebKitDOM${functionSigType}.h"} = 1;
776        } else {
777            $implIncludes{"WebKitDOM${functionSigType}.h"} = 1;
778        }
779
780        $implIncludes{"${functionSigType}.h"} = 1;
781    }
782
783    if(@{$function->raisesExceptions}) {
784        $functionSig .= ", GError **error";
785    }
786
787    push(@hBody, "WEBKIT_API $returnType\n$functionName($functionSig);\n");
788    push(@hBody, "\n");
789
790    push(@cBody, "$returnType\n$functionName($functionSig)\n{\n");
791    push(@cBody, "#if ${conditionalString}\n") if $conditionalString;
792
793    if ($returnType ne "void") {
794        # TODO: return proper default result
795        push(@cBody, "    g_return_val_if_fail(self, 0);\n");
796    } else {
797        push(@cBody, "    g_return_if_fail(self);\n");
798    }
799
800    push(@cBody, "    WebCore::JSMainThreadNullState state;\n");
801
802    # The WebKit::core implementations check for NULL already; no need to
803    # duplicate effort.
804    push(@cBody, "    WebCore::${interfaceName} * item = WebKit::core(self);\n");
805
806    foreach my $param (@{$function->parameters}) {
807        my $paramName = decamelize($param->name);
808        my $paramIDLType = $param->type;
809        my $paramTypeIsPrimitive = $codeGenerator->IsPrimitiveType($paramIDLType);
810        my $paramIsGDOMType = IsGDOMClassType($paramIDLType);
811        if (!$paramTypeIsPrimitive) {
812            if ($returnType ne "void") {
813                # TODO: return proper default result
814                # FIXME: Temporary hack for generating a proper implementation
815                #        of the webkit_dom_document_evaluate function (Bug-ID: 42115)
816                if (!(($functionName eq "webkit_dom_document_evaluate") && ($paramIDLType eq "XPathResult"))) {
817                    push(@cBody, "    g_return_val_if_fail($paramName, 0);\n");
818                }
819            } else {
820                push(@cBody, "    g_return_if_fail($paramName);\n");
821            }
822        }
823    }
824
825    $returnParamName = "";
826    foreach my $param (@{$function->parameters}) {
827        my $paramIDLType = $param->type;
828        my $paramName = decamelize($param->name);
829
830        my $paramIsGDOMType = IsGDOMClassType($paramIDLType);
831        if ($paramIDLType eq "DOMString") {
832            push(@cBody, "    WTF::String converted_${paramName} = WTF::String::fromUTF8($paramName);\n");
833        } elsif ($paramIDLType eq "CompareHow") {
834            push(@cBody, "    WebCore::Range::CompareHow converted_${paramName} = static_cast<WebCore::Range::CompareHow>($paramName);\n");
835        } elsif ($paramIsGDOMType) {
836            push(@cBody, "    WebCore::${paramIDLType} * converted_${paramName} = NULL;\n");
837            push(@cBody, "    if (${paramName} != NULL) {\n");
838            push(@cBody, "        converted_${paramName} = WebKit::core($paramName);\n");
839
840            if ($returnType ne "void") {
841                # TODO: return proper default result
842                push(@cBody, "        g_return_val_if_fail(converted_${paramName}, 0);\n");
843            } else {
844                push(@cBody, "        g_return_if_fail(converted_${paramName});\n");
845            }
846
847            push(@cBody, "    }\n");
848        }
849        $returnParamName = "converted_".$paramName if $param->extendedAttributes->{"Return"};
850    }
851
852    my $assign = "";
853    my $assignPre = "";
854    my $assignPost = "";
855
856    # We need to special-case these Node methods because their C++
857    # signature is different from what we'd expect given their IDL
858    # description; see Node.h.
859    my $functionHasCustomReturn = $functionName eq "webkit_dom_node_append_child" ||
860        $functionName eq "webkit_dom_node_insert_before" ||
861        $functionName eq "webkit_dom_node_replace_child" ||
862        $functionName eq "webkit_dom_node_remove_child";
863
864    if ($returnType ne "void" && !$functionHasCustomReturn) {
865        if ($returnValueIsGDOMType) {
866            $assign = "PassRefPtr<WebCore::${functionSigType}> g_res = ";
867            $assignPre = "WTF::getPtr(";
868            $assignPost = ")";
869        } else {
870            $assign = "${returnType} res = ";
871        }
872    }
873    my $exceptions = "";
874    if (@{$function->raisesExceptions}) {
875        push(@cBody, "    WebCore::ExceptionCode ec = 0;\n");
876        if (${callImplParams} ne "") {
877            $exceptions = ", ec";
878        } else {
879            $exceptions = "ec";
880        }
881    }
882
883    if ($functionHasCustomReturn) {
884        my $customNodeAppendChild = << "EOF";
885    bool ok = item->${functionSigName}(${callImplParams}${exceptions});
886    if (ok)
887    {
888        ${returnType} res = WebKit::kit($returnParamName);
889        return res;
890    }
891EOF
892        push(@cBody, $customNodeAppendChild);
893
894        if(@{$function->raisesExceptions}) {
895            my $exceptionHandling = << "EOF";
896
897    WebCore::ExceptionCodeDescription ecdesc;
898    WebCore::getExceptionCodeDescription(ec, ecdesc);
899    g_set_error_literal(error, g_quark_from_string("WEBKIT_DOM"), ecdesc.code, ecdesc.name);
900EOF
901            push(@cBody, $exceptionHandling);
902        }
903        push(@cBody, "return NULL;");
904        push(@cBody, "}\n\n");
905        return;
906    } elsif ($functionSigType eq "DOMString") {
907        my $getterContentHead;
908        if ($prefix) {
909            my $getterExpressionPrefix = $codeGenerator->GetterExpressionPrefix(\%implIncludes, $interfaceName, $function);
910            $getterContentHead = "${assign}convertToUTF8String(item->$getterExpressionPrefix${exceptions}));\n";
911        } else {
912            $getterContentHead = "${assign}convertToUTF8String(item->${functionSigName}(${callImplParams}${exceptions}));\n";
913        }
914        push(@cBody, "    ${getterContentHead}");
915    } else {
916        my $contentHead;
917        if ($prefix eq "get_") {
918            my $getterExpressionPrefix = $codeGenerator->GetterExpressionPrefix(\%implIncludes, $interfaceName, $function);
919            $contentHead = "${assign}${assignPre}item->$getterExpressionPrefix${callImplParams}${exceptions}${assignPost});\n";
920        } elsif ($prefix eq "set_") {
921            my $setterExpressionPrefix = $codeGenerator->SetterExpressionPrefix(\%implIncludes, $interfaceName, $function);
922            $contentHead = "${assign}${assignPre}item->$setterExpressionPrefix${callImplParams}${exceptions}${assignPost});\n";
923        } else {
924            $contentHead = "${assign}${assignPre}item->${functionSigName}(${callImplParams}${exceptions}${assignPost});\n";
925        }
926        push(@cBody, "    ${contentHead}");
927
928        if(@{$function->raisesExceptions}) {
929            my $exceptionHandling = << "EOF";
930    if (ec) {
931        WebCore::ExceptionCodeDescription ecdesc;
932        WebCore::getExceptionCodeDescription(ec, ecdesc);
933        g_set_error_literal(error, g_quark_from_string("WEBKIT_DOM"), ecdesc.code, ecdesc.name);
934    }
935EOF
936            push(@cBody, $exceptionHandling);
937        }
938    }
939
940    if ($returnType ne "void" && !$functionHasCustomReturn) {
941        if ($functionSigType ne "DOMObject") {
942            if ($returnValueIsGDOMType) {
943                push(@cBody, "    ${returnType} res = WebKit::kit(g_res.get());\n");
944            }
945        }
946        if ($functionSigType eq "DOMObject") {
947            push(@cBody, "    return NULL; /* TODO: return canvas object */\n");
948        } else {
949            push(@cBody, "    return res;\n");
950        }
951    }
952
953    if ($conditionalString) {
954        if ($returnType ne "void") {
955            push(@cBody, "#else\n");
956            if ($codeGenerator->IsNonPointerType($functionSigType)) {
957                push(@cBody, "    return static_cast<${returnType}>(0);\n");
958            } else {
959                push(@cBody, "    return NULL;\n");
960            }
961        }
962        push(@cBody, "#endif /* ${conditionalString} */\n") if $conditionalString;
963    }
964
965    push(@cBody, "}\n\n");
966}
967
968sub ClassHasFunction {
969    my ($class, $name) = @_;
970
971    foreach my $function (@{$class->functions}) {
972        if ($function->signature->name eq $name) {
973            return 1;
974        }
975    }
976
977    return 0;
978}
979
980sub GenerateFunctions {
981    my ($object, $interfaceName, $dataNode) = @_;
982
983    foreach my $function (@{$dataNode->functions}) {
984        $object->GenerateFunction($interfaceName, $function, "");
985    }
986
987    TOP:
988    foreach my $attribute (@{$dataNode->attributes}) {
989        if (SkipAttribute($attribute) ||
990            $attribute->signature->type eq "EventListener" ||
991            $attribute->signature->type eq "MediaQueryListListener") {
992            next TOP;
993        }
994
995        if ($attribute->signature->name eq "type"
996            # This will conflict with the get_type() function we define to return a GType
997            # according to GObject conventions.  Skip this for now.
998            || $attribute->signature->name eq "URL"     # TODO: handle this
999            ) {
1000            next TOP;
1001        }
1002
1003        my $attrNameUpper = $codeGenerator->WK_ucfirst($attribute->signature->name);
1004        my $getname = "get${attrNameUpper}";
1005        my $setname = "set${attrNameUpper}";
1006        if (ClassHasFunction($dataNode, $getname) || ClassHasFunction($dataNode, $setname)) {
1007            # Very occasionally an IDL file defines getter/setter functions for one of its
1008            # attributes; in this case we don't need to autogenerate the getter/setter.
1009            next TOP;
1010        }
1011
1012        # Generate an attribute getter.  For an attribute "foo", this is a function named
1013        # "get_foo" which calls a DOM class method named foo().
1014        my $function = new domFunction();
1015        $function->signature($attribute->signature);
1016        $function->raisesExceptions($attribute->getterExceptions);
1017        $object->GenerateFunction($interfaceName, $function, "get_");
1018
1019        if ($attribute->type =~ /^readonly/) {
1020            next TOP;
1021        }
1022
1023        # Generate an attribute setter.  For an attribute, "foo", this is a function named
1024        # "set_foo" which calls a DOM class method named setFoo().
1025        $function = new domFunction();
1026
1027        $function->signature(new domSignature());
1028        $function->signature->name($attribute->signature->name);
1029        $function->signature->type($attribute->signature->type);
1030        $function->signature->extendedAttributes($attribute->signature->extendedAttributes);
1031
1032        my $param = new domSignature();
1033        $param->name("value");
1034        $param->type($attribute->signature->type);
1035        my %attributes = ();
1036        $param->extendedAttributes(attributes);
1037        my $arrayRef = $function->parameters;
1038        push(@$arrayRef, $param);
1039
1040        $function->raisesExceptions($attribute->setterExceptions);
1041
1042        $object->GenerateFunction($interfaceName, $function, "set_");
1043    }
1044}
1045
1046sub GenerateCFile {
1047    my ($object, $interfaceName, $parentClassName, $parentGObjType, $dataNode) = @_;
1048
1049    if ($dataNode->extendedAttributes->{"EventTarget"}) {
1050        $object->GenerateEventTargetIface($dataNode);
1051    }
1052
1053    my $implContent = "";
1054
1055    my $clsCaps = uc(FixUpDecamelizedName(decamelize($interfaceName)));
1056    my $lowerCaseIfaceName = "webkit_dom_" . FixUpDecamelizedName(decamelize($interfaceName));
1057
1058    $implContent = << "EOF";
1059${defineTypeMacro}(${className}, ${lowerCaseIfaceName}, ${parentGObjType}${defineTypeInterfaceImplementation}
1060
1061namespace WebKit {
1062
1063WebCore::${interfaceName}* core(${className}* request)
1064{
1065    g_return_val_if_fail(request, 0);
1066
1067    WebCore::${interfaceName}* coreObject = static_cast<WebCore::${interfaceName}*>(WEBKIT_DOM_OBJECT(request)->coreObject);
1068    g_return_val_if_fail(coreObject, 0);
1069
1070    return coreObject;
1071}
1072
1073} // namespace WebKit
1074EOF
1075
1076    push(@cBodyPriv, $implContent);
1077    $object->GenerateProperties($interfaceName, $dataNode);
1078    $object->GenerateFunctions($interfaceName, $dataNode);
1079
1080    my $wrapMethod = << "EOF";
1081namespace WebKit {
1082${className}* wrap${interfaceName}(WebCore::${interfaceName}* coreObject)
1083{
1084    g_return_val_if_fail(coreObject, 0);
1085
1086    /* We call ref() rather than using a C++ smart pointer because we can't store a C++ object
1087     * in a C-allocated GObject structure.  See the finalize() code for the
1088     * matching deref().
1089     */
1090    coreObject->ref();
1091
1092    return  WEBKIT_DOM_${clsCaps}(g_object_new(WEBKIT_TYPE_DOM_${clsCaps},
1093                                               "core-object", coreObject, NULL));
1094}
1095} // namespace WebKit
1096EOF
1097    push(@cBodyPriv, $wrapMethod);
1098}
1099
1100sub GenerateEndHeader {
1101    my ($object) = @_;
1102
1103    #Header guard
1104    my $guard = $className . "_h";
1105
1106    push(@hBody, "G_END_DECLS\n\n");
1107    push(@hPrefixGuardEnd, "#endif /* $guard */\n");
1108}
1109
1110sub GeneratePrivateHeader {
1111    my $object = shift;
1112    my $dataNode = shift;
1113
1114    my $interfaceName = $dataNode->name;
1115    my $filename = "$outputDir/" . $className . "Private.h";
1116    my $guard = uc(decamelize($className)) . "_PRIVATE_H";
1117    my $parentClassName = GetParentClassName($dataNode);
1118    my $hasLegacyParent = $dataNode->extendedAttributes->{"LegacyParent"};
1119    my $hasRealParent = @{$dataNode->parents} > 0;
1120    my $hasParent = $hasLegacyParent || $hasRealParent;
1121
1122    open(PRIVHEADER, ">$filename") or die "Couldn't open file $filename for writing";
1123
1124    print PRIVHEADER split("\r", $licenceTemplate);
1125    print PRIVHEADER "\n";
1126
1127    my $text = << "EOF";
1128#ifndef $guard
1129#define $guard
1130
1131#include <glib-object.h>
1132#include <webkit/${parentClassName}.h>
1133#include "${interfaceName}.h"
1134EOF
1135
1136    print PRIVHEADER $text;
1137
1138    print PRIVHEADER map { "#include \"$_\"\n" } sort keys(%hdrPropIncludes);
1139    print PRIVHEADER "\n" if keys(%hdrPropIncludes);
1140
1141    $text = << "EOF";
1142namespace WebKit {
1143    ${className} *
1144    wrap${interfaceName}(WebCore::${interfaceName} *coreObject);
1145
1146    WebCore::${interfaceName} *
1147    core(${className} *request);
1148
1149EOF
1150
1151    print PRIVHEADER $text;
1152
1153    if ($className ne "WebKitDOMNode") {
1154        $text = << "EOF";
1155    ${className}*
1156    kit(WebCore::${interfaceName}* node);
1157
1158EOF
1159        print PRIVHEADER $text;
1160    }
1161
1162    $text = << "EOF";
1163} // namespace WebKit
1164
1165#endif /* ${guard} */
1166EOF
1167    print PRIVHEADER $text;
1168
1169    close(PRIVHEADER);
1170}
1171
1172sub UsesManualKitImplementation {
1173    my $type = shift;
1174
1175    return 1 if $type eq "Node" or $type eq "Element" or $type eq "Event";
1176    return 0;
1177}
1178
1179sub GenerateEventTargetIface {
1180    my $object = shift;
1181    my $dataNode = shift;
1182
1183    my $interfaceName = $dataNode->name;
1184    my $decamelize = FixUpDecamelizedName(decamelize($interfaceName));
1185
1186    $implIncludes{"GObjectEventListener.h"} = 1;
1187    $implIncludes{"WebKitDOMEventTarget.h"} = 1;
1188    $implIncludes{"WebKitDOMEventPrivate.h"} = 1;
1189
1190    my $impl = << "EOF";
1191static void webkit_dom_${decamelize}_dispatch_event(WebKitDOMEventTarget* target, WebKitDOMEvent* event, GError** error)
1192{
1193    WebCore::Event* coreEvent = WebKit::core(event);
1194    WebCore::${interfaceName}* coreTarget = static_cast<WebCore::${interfaceName}*>(WEBKIT_DOM_OBJECT(target)->coreObject);
1195
1196    WebCore::ExceptionCode ec = 0;
1197    coreTarget->dispatchEvent(coreEvent, ec);
1198    if (ec) {
1199        WebCore::ExceptionCodeDescription description;
1200        WebCore::getExceptionCodeDescription(ec, description);
1201        g_set_error_literal(error, g_quark_from_string("WEBKIT_DOM"), description.code, description.name);
1202    }
1203}
1204
1205static gboolean webkit_dom_${decamelize}_add_event_listener(WebKitDOMEventTarget* target, const char* eventName, GCallback handler, gboolean bubble, gpointer userData)
1206{
1207    WebCore::${interfaceName}* coreTarget = static_cast<WebCore::${interfaceName}*>(WEBKIT_DOM_OBJECT(target)->coreObject);
1208    return WebCore::GObjectEventListener::addEventListener(G_OBJECT(target), coreTarget, eventName, handler, bubble, userData);
1209}
1210
1211static gboolean webkit_dom_${decamelize}_remove_event_listener(WebKitDOMEventTarget* target, const char* eventName, GCallback handler, gboolean bubble)
1212{
1213    WebCore::${interfaceName}* coreTarget = static_cast<WebCore::${interfaceName}*>(WEBKIT_DOM_OBJECT(target)->coreObject);
1214    return WebCore::GObjectEventListener::removeEventListener(G_OBJECT(target), coreTarget, eventName, handler, bubble);
1215}
1216
1217static void webkit_dom_event_target_init(WebKitDOMEventTargetIface* iface)
1218{
1219    iface->dispatch_event = webkit_dom_${decamelize}_dispatch_event;
1220    iface->add_event_listener = webkit_dom_${decamelize}_add_event_listener;
1221    iface->remove_event_listener = webkit_dom_${decamelize}_remove_event_listener;
1222}
1223
1224EOF
1225
1226    push(@cBody, $impl);
1227
1228    $defineTypeMacro = "G_DEFINE_TYPE_WITH_CODE";
1229    $defineTypeInterfaceImplementation = ", G_IMPLEMENT_INTERFACE(WEBKIT_TYPE_DOM_EVENT_TARGET, webkit_dom_event_target_init))";
1230}
1231
1232sub Generate {
1233    my ($object, $dataNode) = @_;
1234
1235    my $hasLegacyParent = $dataNode->extendedAttributes->{"LegacyParent"};
1236    my $hasRealParent = @{$dataNode->parents} > 0;
1237    my $hasParent = $hasLegacyParent || $hasRealParent;
1238    my $parentClassName = GetParentClassName($dataNode);
1239    my $parentGObjType = GetParentGObjType($dataNode);
1240    my $interfaceName = $dataNode->name;
1241
1242    # Add the guard if the 'Conditional' extended attribute exists
1243    my $conditionalString = GenerateConditionalString($dataNode);
1244    push(@conditionGuardStart, "#if ${conditionalString}\n\n") if $conditionalString;
1245    push(@conditionGuardEnd, "#endif /* ${conditionalString} */\n") if $conditionalString;
1246
1247    # Add the default impl header template
1248    @cPrefix = split("\r", $licenceTemplate);
1249    push(@cPrefix, "\n");
1250
1251    $implIncludes{"webkitdefines.h"} = 1;
1252    $implIncludes{"webkitglobalsprivate.h"} = 1;
1253    $implIncludes{"webkitmarshal.h"} = 1;
1254    $implIncludes{"DOMObjectCache.h"} = 1;
1255    $implIncludes{"WebKitDOMBinding.h"} = 1;
1256    $implIncludes{"gobject/ConvertToUTF8String.h"} = 1;
1257    $implIncludes{"webkit/$className.h"} = 1;
1258    $implIncludes{"webkit/${className}Private.h"} = 1;
1259    $implIncludes{"${interfaceName}.h"} = 1;
1260    $implIncludes{"JSMainThreadExecState.h"} = 1;
1261    $implIncludes{"ExceptionCode.h"} = 1;
1262
1263    $hdrIncludes{"webkit/${parentClassName}.h"} = 1;
1264
1265    if (!UsesManualKitImplementation($interfaceName)) {
1266        my $converter = << "EOF";
1267namespace WebKit {
1268
1269${className}* kit(WebCore::$interfaceName* obj)
1270{
1271    g_return_val_if_fail(obj, 0);
1272
1273    if (gpointer ret = DOMObjectCache::get(obj))
1274        return static_cast<${className}*>(ret);
1275
1276    return static_cast<${className}*>(DOMObjectCache::put(obj, WebKit::wrap${interfaceName}(obj)));
1277}
1278
1279} // namespace WebKit //
1280
1281EOF
1282    push(@cBody, $converter);
1283    }
1284
1285    $object->GenerateHeader($interfaceName, $parentClassName);
1286    $object->GenerateCFile($interfaceName, $parentClassName, $parentGObjType, $dataNode);
1287    $object->GenerateEndHeader();
1288    $object->GeneratePrivateHeader($dataNode);
1289
1290}
1291
1292# Internal helper
1293sub WriteData {
1294    my ($object, $name) = @_;
1295
1296    # Write public header.
1297    my $hdrFName = "$outputDir/" . $name . ".h";
1298    open(HEADER, ">$hdrFName") or die "Couldn't open file $hdrFName";
1299
1300    print HEADER @hPrefix;
1301    print HEADER @hPrefixGuard;
1302    print HEADER "#include \"webkit/webkitdomdefines.h\"\n";
1303    print HEADER "#include <glib-object.h>\n";
1304    print HEADER "#include <webkit/webkitdefines.h>\n";
1305    print HEADER map { "#include \"$_\"\n" } sort keys(%hdrIncludes);
1306    print HEADER "\n" if keys(%hdrIncludes);
1307    print HEADER "\n";
1308    print HEADER @hBodyPre;
1309    print HEADER @hBody;
1310    print HEADER @hPrefixGuardEnd;
1311
1312    close(HEADER);
1313
1314    # Write the implementation sources
1315    my $implFileName = "$outputDir/" . $name . ".cpp";
1316    open(IMPL, ">$implFileName") or die "Couldn't open file $implFileName";
1317
1318    print IMPL @cPrefix;
1319    print IMPL "#include <glib-object.h>\n";
1320    print IMPL "#include \"config.h\"\n\n";
1321    print IMPL @conditionGuardStart;
1322    print IMPL "#include <wtf/GetPtr.h>\n";
1323    print IMPL "#include <wtf/RefPtr.h>\n";
1324    print IMPL map { "#include \"$_\"\n" } sort keys(%implIncludes);
1325    print IMPL "\n" if keys(%implIncludes);
1326    print IMPL @cBody;
1327
1328    print IMPL "\n";
1329    print IMPL @cBodyPriv;
1330    print IMPL @conditionGuardEnd;
1331
1332    close(IMPL);
1333
1334    %implIncludes = ();
1335    %hdrIncludes = ();
1336    @hPrefix = ();
1337    @hBody = ();
1338
1339    @cPrefix = ();
1340    @cBody = ();
1341    @cBodyPriv = ();
1342}
1343
1344sub GenerateInterface {
1345    my ($object, $dataNode, $defines) = @_;
1346    my $name = $dataNode->name;
1347
1348    # Set up some global variables
1349    $className = GetClassName($dataNode->name);
1350    $object->Generate($dataNode);
1351
1352    # Write changes
1353    my $fname = "WebKitDOM_" . $name;
1354    $fname =~ s/_//g;
1355    $object->WriteData($fname);
1356}
1357