# Copyright (C) 2008 Luke Kenneth Casson Leighton # Copyright (C) 2008 Martin Soto # Copyright (C) 2008 Alp Toker # Copyright (C) 2009 Adam Dingle # Copyright (C) 2009 Jim Nelson # Copyright (C) 2009, 2010 Igalia S.L. # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Library General Public # License as published by the Free Software Foundation; either # version 2 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Library General Public License for more details. # # You should have received a copy of the GNU Library General Public License # along with this library; see the file COPYING.LIB. If not, write to # the Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. package CodeGeneratorGObject; use constant FileNamePrefix => "WebKitDOM"; # Global Variables my %implIncludes = (); my %hdrIncludes = (); my $defineTypeMacro = "G_DEFINE_TYPE"; my $defineTypeInterfaceImplementation = ")"; my @txtEventListeners = (); my @txtInstallEventListeners = (); my @txtInstallSignals = (); my @txtInstallProps = (); my @txtSetProps = (); my @txtGetProps = (); my $className = ""; # Default constructor sub new { my $object = shift; my $reference = { }; $codeGenerator = shift; $outputDir = shift; mkdir $outputDir; bless($reference, $object); } my $licenceTemplate = << "EOF"; /* This file is part of the WebKit open source project. This file has been generated by generate-bindings.pl. DO NOT MODIFY! This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ EOF sub GenerateModule { } sub GetParentClassName { my $dataNode = shift; return "WebKitDOMObject" if @{$dataNode->parents} eq 0; return "WebKitDOM" . $codeGenerator->StripModule($dataNode->parents(0)); } # From String::CamelCase 0.01 sub camelize { my $s = shift; join('', map{ ucfirst $_ } split(/(?<=[A-Za-z])_(?=[A-Za-z])|\b/, $s)); } sub decamelize { my $s = shift; $s =~ s{([^a-zA-Z]?)([A-Z]*)([A-Z])([a-z]?)}{ my $fc = pos($s)==0; my ($p0,$p1,$p2,$p3) = ($1,lc$2,lc$3,$4); my $t = $p0 || $fc ? $p0 : '_'; $t .= $p3 ? $p1 ? "${p1}_$p2$p3" : "$p2$p3" : "$p1$p2"; $t; }ge; $s; } sub FixUpDecamelizedName { my $classname = shift; # FIXME: try to merge this somehow with the fixes in ClassNameToGobjectType $classname =~ s/x_path/xpath/; $classname =~ s/web_kit/webkit/; $classname =~ s/htmli_frame/html_iframe/; return $classname; } sub HumanReadableConditional { my @conditional = split('_', shift); my @upperCaseExceptions = ("SQL", "API"); my @humanReadable; for $part (@conditional) { if (!grep {$_ eq $part} @upperCaseExceptions) { $part = camelize(lc($part)); } push(@humanReadable, $part); } return join(' ', @humanReadable); } sub ClassNameToGObjectType { my $className = shift; my $CLASS_NAME = uc(decamelize($className)); # Fixup: with our prefix being 'WebKitDOM' decamelize can't get # WebKitDOMCSS and similar names right, so we have to fix it # manually. $CLASS_NAME =~ s/DOMCSS/DOM_CSS/; $CLASS_NAME =~ s/DOMHTML/DOM_HTML/; $CLASS_NAME =~ s/DOMDOM/DOM_DOM/; $CLASS_NAME =~ s/DOMCDATA/DOM_CDATA/; $CLASS_NAME =~ s/DOMX_PATH/DOM_XPATH/; $CLASS_NAME =~ s/DOM_WEB_KIT/DOM_WEBKIT/; $CLASS_NAME =~ s/DOMUI/DOM_UI/; $CLASS_NAME =~ s/HTMLI_FRAME/HTML_IFRAME/; return $CLASS_NAME; } sub GetParentGObjType { my $dataNode = shift; return "WEBKIT_TYPE_DOM_OBJECT" if @{$dataNode->parents} eq 0; return "WEBKIT_TYPE_DOM_" . ClassNameToGObjectType($codeGenerator->StripModule($dataNode->parents(0))); } sub GetClassName { my $name = $codeGenerator->StripModule(shift); return "WebKitDOM$name"; } sub GetCoreObject { my ($interfaceName, $name, $parameter) = @_; return "WebCore::${interfaceName}* $name = WebKit::core($parameter);"; } sub SkipAttribute { my $attribute = shift; if ($attribute->signature->extendedAttributes->{"Custom"} || $attribute->signature->extendedAttributes->{"CustomGetter"} || $attribute->signature->extendedAttributes->{"CustomSetter"}) { return 1; } my $propType = $attribute->signature->type; if ($propType =~ /Constructor$/) { return 1; } if ($codeGenerator->GetArrayType($propType)) { return 1; } # This is for DOMWindow.idl location attribute if ($attribute->signature->name eq "location") { return 1; } # This is for HTMLInput.idl valueAsDate if ($attribute->signature->name eq "valueAsDate") { return 1; } # This is for DOMWindow.idl Crypto attribute if ($attribute->signature->type eq "Crypto") { return 1; } return 0; } sub SkipFunction { my $function = shift; my $decamelize = shift; my $prefix = shift; my $functionName = "webkit_dom_" . $decamelize . "_" . $prefix . decamelize($function->signature->name); my $functionReturnType = $prefix eq "set_" ? "void" : $function->signature->type; my $isCustomFunction = $function->signature->extendedAttributes->{"Custom"}; my $callWith = $function->signature->extendedAttributes->{"CallWith"}; my $isUnsupportedCallWith = $codeGenerator->ExtendedAttributeContains($callWith, "ScriptArguments") || $codeGenerator->ExtendedAttributeContains($callWith, "CallStack"); if (($isCustomFunction || $isUnsupportedCallWith) && $functionName ne "webkit_dom_node_replace_child" && $functionName ne "webkit_dom_node_insert_before" && $functionName ne "webkit_dom_node_remove_child" && $functionName ne "webkit_dom_node_append_child" && $functionName ne "webkit_dom_html_collection_item" && $functionName ne "webkit_dom_html_collection_named_item") { return 1; } if ($function->signature->name eq "getSVGDocument") { return 1; } if ($function->signature->name eq "getCSSCanvasContext") { return 1; } if ($codeGenerator->GetArrayType($functionReturnType)) { return 1; } # Skip functions that have ["Callback"] parameters, because this # code generator doesn't know how to auto-generate callbacks. # Skip functions that have "MediaQueryListListener" or sequence parameters, because this # code generator doesn't know how to auto-generate MediaQueryListListener or sequence. foreach my $param (@{$function->parameters}) { if ($param->extendedAttributes->{"Callback"} || $param->type eq "MediaQueryListListener" || $codeGenerator->GetArrayType($param->type)) { return 1; } } return 0; } # Name type used in the g_value_{set,get}_* functions sub GetGValueTypeName { my $type = shift; my %types = ("DOMString", "string", "DOMTimeStamp", "uint", "float", "float", "double", "double", "boolean", "boolean", "char", "char", "long", "long", "long long", "int64", "short", "int", "uchar", "uchar", "unsigned", "uint", "int", "int", "unsigned int", "uint", "unsigned long long", "uint64", "unsigned long", "ulong", "unsigned short", "uint"); return $types{$type} ? $types{$type} : "object"; } # Name type used in C declarations sub GetGlibTypeName { my $type = shift; my $name = GetClassName($type); my %types = ("DOMString", "gchar*", "DOMTimeStamp", "guint32", "CompareHow", "gushort", "float", "gfloat", "double", "gdouble", "boolean", "gboolean", "char", "gchar", "long", "glong", "long long", "gint64", "short", "gshort", "uchar", "guchar", "unsigned", "guint", "int", "gint", "unsigned int", "guint", "unsigned long", "gulong", "unsigned long long", "guint64", "unsigned short", "gushort", "void", "void"); return $types{$type} ? $types{$type} : "$name*"; } sub IsGDOMClassType { my $type = shift; return 0 if $codeGenerator->IsNonPointerType($type) || $codeGenerator->IsStringType($type); return 1; } sub GetReadableProperties { my $properties = shift; my @result = (); foreach my $property (@{$properties}) { if (!SkipAttribute($property)) { push(@result, $property); } } return @result; } sub GetWriteableProperties { my $properties = shift; my @result = (); foreach my $property (@{$properties}) { my $writeable = $property->type !~ /^readonly/; my $gtype = GetGValueTypeName($property->signature->type); my $hasGtypeSignature = ($gtype eq "boolean" || $gtype eq "float" || $gtype eq "double" || $gtype eq "uint64" || $gtype eq "ulong" || $gtype eq "long" || $gtype eq "uint" || $gtype eq "ushort" || $gtype eq "uchar" || $gtype eq "char" || $gtype eq "string"); # FIXME: We are not generating setters for 'Replaceable' # attributes now, but we should somehow. my $replaceable = $property->signature->extendedAttributes->{"Replaceable"}; if ($writeable && $hasGtypeSignature && !$replaceable) { push(@result, $property); } } return @result; } sub GenerateConditionalWarning { my $node = shift; my $indentSize = shift; if (!$indentSize) { $indentSize = 4; } my $conditional = $node->extendedAttributes->{"Conditional"}; my @warn; if ($conditional) { if ($conditional =~ /&/) { my @splitConditionals = split(/&/, $conditional); foreach $condition (@splitConditionals) { push(@warn, "#if !ENABLE($condition)\n"); push(@warn, ' ' x $indentSize . "WEBKIT_WARN_FEATURE_NOT_PRESENT(\"" . HumanReadableConditional($condition) . "\")\n"); push(@warn, "#endif\n"); } } elsif ($conditional =~ /\|/) { foreach $condition (split(/\|/, $conditional)) { push(@warn, ' ' x $indentSize . "WEBKIT_WARN_FEATURE_NOT_PRESENT(\"" . HumanReadableConditional($condition) . "\")\n"); } } else { push(@warn, ' ' x $indentSize . "WEBKIT_WARN_FEATURE_NOT_PRESENT(\"" . HumanReadableConditional($conditional) . "\")\n"); } } return @warn; } sub GenerateProperty { my $attribute = shift; my $interfaceName = shift; my @writeableProperties = @{shift @_}; my $parentNode = shift; my $conditionalString = $codeGenerator->GenerateConditionalString($attribute->signature); my @conditionalWarn = GenerateConditionalWarning($attribute->signature, 8); my $parentConditionalString = $codeGenerator->GenerateConditionalString($parentNode); my @parentConditionalWarn = GenerateConditionalWarning($parentNode, 8); my $camelPropName = $attribute->signature->name; my $setPropNameFunction = $codeGenerator->WK_ucfirst($camelPropName); my $getPropNameFunction = $codeGenerator->WK_lcfirst($camelPropName); my $propName = decamelize($camelPropName); my $propNameCaps = uc($propName); $propName =~ s/_/-/g; my ${propEnum} = "PROP_${propNameCaps}"; push(@cBodyProperties, " ${propEnum},\n"); my $propType = $attribute->signature->type; my ${propGType} = decamelize($propType); my ${ucPropGType} = uc($propGType); my $gtype = GetGValueTypeName($propType); my $gparamflag = "WEBKIT_PARAM_READABLE"; my $writeable = $attribute->type !~ /^readonly/; my $const = "read-only "; my $custom = $attribute->signature->extendedAttributes->{"Custom"}; if ($writeable && $custom) { $const = "read-only (due to custom functions needed in webkitdom)"; return; } if ($writeable && !$custom) { $gparamflag = "WEBKIT_PARAM_READWRITE"; $const = "read-write "; } my $type = GetGlibTypeName($propType); $nick = decamelize("${interfaceName}_${propName}"); $long = "${const} ${type} ${interfaceName}.${propName}"; my $convertFunction = ""; if ($gtype eq "string") { $convertFunction = "WTF::String::fromUTF8"; } my ($getterFunctionName, @getterArguments) = $codeGenerator->GetterExpression(\%implIncludes, $interfaceName, $attribute); my ($setterFunctionName, @setterArguments) = $codeGenerator->SetterExpression(\%implIncludes, $interfaceName, $attribute); if ($attribute->signature->extendedAttributes->{"ImplementedBy"}) { my $implementedBy = $attribute->signature->extendedAttributes->{"ImplementedBy"}; $implIncludes{"${implementedBy}.h"} = 1; push(@setterArguments, "${convertFunction}(g_value_get_$gtype(value))"); unshift(@getterArguments, "coreSelf"); unshift(@setterArguments, "coreSelf"); $getterFunctionName = "WebCore::${implementedBy}::$getterFunctionName"; $setterFunctionName = "WebCore::${implementedBy}::$setterFunctionName"; } else { push(@setterArguments, "${convertFunction}(g_value_get_$gtype(value))"); $getterFunctionName = "coreSelf->$getterFunctionName"; $setterFunctionName = "coreSelf->$setterFunctionName"; } push(@getterArguments, "ec") if @{$attribute->getterExceptions}; push(@setterArguments, "ec") if @{$attribute->setterExceptions}; if (grep {$_ eq $attribute} @writeableProperties) { push(@txtSetProps, " case ${propEnum}: {\n"); push(@txtSetProps, "#if ${parentConditionalString}\n") if $parentConditionalString; push(@txtSetProps, "#if ${conditionalString}\n") if $conditionalString; push(@txtSetProps, " WebCore::ExceptionCode ec = 0;\n") if @{$attribute->setterExceptions}; push(@txtSetProps, " ${setterFunctionName}(" . join(", ", @setterArguments) . ");\n"); push(@txtSetProps, "#else\n") if $conditionalString; push(@txtSetProps, @conditionalWarn) if scalar(@conditionalWarn); push(@txtSetProps, "#endif /* ${conditionalString} */\n") if $conditionalString; push(@txtSetProps, "#else\n") if $parentConditionalString; push(@txtSetProps, @parentConditionalWarn) if scalar(@parentConditionalWarn); push(@txtSetProps, "#endif /* ${parentConditionalString} */\n") if $parentConditionalString; push(@txtSetProps, " break;\n }\n"); } push(@txtGetProps, " case ${propEnum}: {\n"); push(@txtGetProps, "#if ${parentConditionalString}\n") if $parentConditionalString; push(@txtGetProps, "#if ${conditionalString}\n") if $conditionalString; push(@txtGetProps, " WebCore::ExceptionCode ec = 0;\n") if @{$attribute->getterExceptions}; my $postConvertFunction = ""; my $done = 0; if ($gtype eq "string") { push(@txtGetProps, " g_value_take_string(value, convertToUTF8String(${getterFunctionName}(" . join(", ", @getterArguments) . ")));\n"); $done = 1; } elsif ($gtype eq "object") { push(@txtGetProps, " RefPtr ptr = ${getterFunctionName}(" . join(", ", @getterArguments) . ");\n"); push(@txtGetProps, " g_value_set_object(value, WebKit::kit(ptr.get()));\n"); $done = 1; } # FIXME: get rid of this glitch? my $_gtype = $gtype; if ($gtype eq "ushort") { $_gtype = "uint"; } if (!$done) { if ($attribute->signature->extendedAttributes->{"ImplementedBy"}) { my $implementedBy = $attribute->signature->extendedAttributes->{"ImplementedBy"}; $implIncludes{"${implementedBy}.h"} = 1; push(@txtGetProps, " g_value_set_$_gtype(value, ${convertFunction}${getterFunctionName}(" . join(", ", @getterArguments) . ")${postConvertFunction});\n"); } else { push(@txtGetProps, " g_value_set_$_gtype(value, ${convertFunction}${getterFunctionName}(" . join(", ", @getterArguments) . ")${postConvertFunction});\n"); } } push(@txtGetProps, "#else\n") if $conditionalString; push(@txtGetProps, @conditionalWarn) if scalar(@conditionalWarn); push(@txtGetProps, "#endif /* ${conditionalString} */\n") if $conditionalString; push(@txtGetProps, "#else\n") if $parentConditionalString; push(@txtGetProps, @parentConditionalWarn) if scalar(@parentConditionalWarn); push(@txtGetProps, "#endif /* ${parentConditionalString} */\n") if $parentConditionalString; push(@txtGetProps, " break;\n }\n"); my %param_spec_options = ("int", "G_MININT, /* min */\nG_MAXINT, /* max */\n0, /* default */", "boolean", "FALSE, /* default */", "float", "-G_MAXFLOAT, /* min */\nG_MAXFLOAT, /* max */\n0.0, /* default */", "double", "-G_MAXDOUBLE, /* min */\nG_MAXDOUBLE, /* max */\n0.0, /* default */", "uint64", "0, /* min */\nG_MAXUINT64, /* min */\n0, /* default */", "long", "G_MINLONG, /* min */\nG_MAXLONG, /* max */\n0, /* default */", "int64", "G_MININT64, /* min */\nG_MAXINT64, /* max */\n0, /* default */", "ulong", "0, /* min */\nG_MAXULONG, /* max */\n0, /* default */", "uint", "0, /* min */\nG_MAXUINT, /* max */\n0, /* default */", "ushort", "0, /* min */\nG_MAXUINT16, /* max */\n0, /* default */", "uchar", "G_MININT8, /* min */\nG_MAXINT8, /* max */\n0, /* default */", "char", "0, /* min */\nG_MAXUINT8, /* max */\n0, /* default */", "string", "\"\", /* default */", "object", "WEBKIT_TYPE_DOM_${ucPropGType}, /* gobject type */"); my $txtInstallProp = << "EOF"; g_object_class_install_property(gobjectClass, ${propEnum}, g_param_spec_${_gtype}("${propName}", /* name */ "$nick", /* short description */ "$long", /* longer - could do with some extra doc stuff here */ $param_spec_options{$gtype} ${gparamflag})); EOF push(@txtInstallProps, $txtInstallProp); } sub GenerateProperties { my ($object, $interfaceName, $dataNode) = @_; my $clsCaps = substr(ClassNameToGObjectType($className), 12); my $lowerCaseIfaceName = "webkit_dom_" . (FixUpDecamelizedName(decamelize($interfaceName))); my $conditionGuardStart = ""; my $conditionGuardEnd = ""; my $conditionalString = $codeGenerator->GenerateConditionalString($dataNode); if ($conditionalString) { $conditionGuardStart = "#if ${conditionalString}"; $conditionGuardEnd = "#endif // ${conditionalString}"; } # Properties my $implContent = ""; # Properties $implContent = << "EOF"; enum { PROP_0, EOF push(@cBodyProperties, $implContent); my @readableProperties = GetReadableProperties($dataNode->attributes); my $privFunction = GetCoreObject($interfaceName, "coreSelf", "self"); my $txtGetProp = << "EOF"; static void ${lowerCaseIfaceName}_get_property(GObject* object, guint propertyId, GValue* value, GParamSpec* pspec) { WebCore::JSMainThreadNullState state; EOF push(@txtGetProps, $txtGetProp); if (scalar @readableProperties > 0) { $txtGetProp = << "EOF"; ${className}* self = WEBKIT_DOM_${clsCaps}(object); $privFunction EOF push(@txtGetProps, $txtGetProp); } $txtGetProp = << "EOF"; switch (propertyId) { EOF push(@txtGetProps, $txtGetProp); my @writeableProperties = GetWriteableProperties(\@readableProperties); my $txtSetProps = << "EOF"; static void ${lowerCaseIfaceName}_set_property(GObject* object, guint propertyId, const GValue* value, GParamSpec* pspec) { WebCore::JSMainThreadNullState state; EOF push(@txtSetProps, $txtSetProps); if (scalar @writeableProperties > 0) { $txtSetProps = << "EOF"; ${className}* self = WEBKIT_DOM_${clsCaps}(object); $privFunction EOF push(@txtSetProps, $txtSetProps); } $txtSetProps = << "EOF"; switch (propertyId) { EOF push(@txtSetProps, $txtSetProps); foreach my $attribute (@readableProperties) { if ($attribute->signature->type ne "EventListener" && $attribute->signature->type ne "MediaQueryListListener") { GenerateProperty($attribute, $interfaceName, \@writeableProperties, $dataNode); } } push(@cBodyProperties, "};\n\n"); $txtGetProp = << "EOF"; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propertyId, pspec); break; } } EOF push(@txtGetProps, $txtGetProp); $txtSetProps = << "EOF"; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propertyId, pspec); break; } } EOF push(@txtSetProps, $txtSetProps); # Do not insert extra spaces when interpolating array variables $" = ""; $implContent = << "EOF"; static void ${lowerCaseIfaceName}_finalize(GObject* object) { $conditionGuardStart WebKitDOMObject* domObject = WEBKIT_DOM_OBJECT(object); if (domObject->coreObject) { WebCore::${interfaceName}* coreObject = static_cast(domObject->coreObject); WebKit::DOMObjectCache::forget(coreObject); coreObject->deref(); domObject->coreObject = 0; } $conditionGuardEnd G_OBJECT_CLASS(${lowerCaseIfaceName}_parent_class)->finalize(object); } @txtSetProps @txtGetProps static void ${lowerCaseIfaceName}_constructed(GObject* object) { EOF push(@cBodyProperties, $implContent); $implContent = << "EOF"; @txtInstallEventListeners if (G_OBJECT_CLASS(${lowerCaseIfaceName}_parent_class)->constructed) G_OBJECT_CLASS(${lowerCaseIfaceName}_parent_class)->constructed(object); } static void ${lowerCaseIfaceName}_class_init(${className}Class* requestClass) { GObjectClass* gobjectClass = G_OBJECT_CLASS(requestClass); gobjectClass->finalize = ${lowerCaseIfaceName}_finalize; gobjectClass->set_property = ${lowerCaseIfaceName}_set_property; gobjectClass->get_property = ${lowerCaseIfaceName}_get_property; gobjectClass->constructed = ${lowerCaseIfaceName}_constructed; @txtInstallProps @txtInstallSignals } static void ${lowerCaseIfaceName}_init(${className}* request) { } EOF push(@cBodyProperties, $implContent); } sub GenerateHeader { my ($object, $interfaceName, $parentClassName) = @_; my $implContent = ""; # Add the default header template @hPrefix = split("\r", $licenceTemplate); push(@hPrefix, "\n"); #Header guard my $guard = $className . "_h"; @hPrefixGuard = << "EOF"; #ifndef $guard #define $guard EOF $implContent = << "EOF"; G_BEGIN_DECLS EOF push(@hBodyPre, $implContent); my $decamelize = FixUpDecamelizedName(decamelize($interfaceName)); my $clsCaps = uc($decamelize); my $lowerCaseIfaceName = "webkit_dom_" . ($decamelize); $implContent = << "EOF"; #define WEBKIT_TYPE_DOM_${clsCaps} (${lowerCaseIfaceName}_get_type()) #define WEBKIT_DOM_${clsCaps}(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), WEBKIT_TYPE_DOM_${clsCaps}, ${className})) #define WEBKIT_DOM_${clsCaps}_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), WEBKIT_TYPE_DOM_${clsCaps}, ${className}Class) #define WEBKIT_DOM_IS_${clsCaps}(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), WEBKIT_TYPE_DOM_${clsCaps})) #define WEBKIT_DOM_IS_${clsCaps}_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), WEBKIT_TYPE_DOM_${clsCaps})) #define WEBKIT_DOM_${clsCaps}_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), WEBKIT_TYPE_DOM_${clsCaps}, ${className}Class)) struct _${className} { ${parentClassName} parent_instance; }; struct _${className}Class { ${parentClassName}Class parent_class; }; WEBKIT_API GType ${lowerCaseIfaceName}_get_type (void); EOF push(@hBody, $implContent); } sub getIncludeHeader { my $type = shift; my $name = GetClassName($type); return "" if $type eq "int"; return "" if $type eq "long"; return "" if $type eq "long long"; return "" if $type eq "short"; return "" if $type eq "char"; return "" if $type eq "float"; return "" if $type eq "double"; return "" if $type eq "unsigned"; return "" if $type eq "unsigned int"; return "" if $type eq "unsigned long"; return "" if $type eq "unsigned long long"; return "" if $type eq "unsigned short"; return "" if $type eq "DOMTimeStamp"; return "" if $type eq "EventListener"; return "" if $type eq "MediaQueryListListener"; return "" if $type eq "unsigned char"; return "" if $type eq "DOMString"; return "" if $type eq "float"; return "" if $type eq "boolean"; return "" if $type eq "void"; return "" if $type eq "CompareHow"; return "$name.h"; } sub addIncludeInBody { my $type = shift; if ($type eq "DOMObject") { return; } my $header = getIncludeHeader($type); if ($header eq "") { return; } if (IsGDOMClassType($type)) { $implIncludes{"webkit/$header"} = 1; } else { $implIncludes{$header} = 1 } } sub GenerateFunction { my ($object, $interfaceName, $function, $prefix, $parentNode) = @_; my $decamelize = FixUpDecamelizedName(decamelize($interfaceName)); if ($object eq "MediaQueryListListener") { return; } if (SkipFunction($function, $decamelize, $prefix)) { return; } my $functionSigName = $function->signature->name; my $functionSigType = $prefix eq "set_" ? "void" : $function->signature->type; my $functionName = "webkit_dom_" . $decamelize . "_" . $prefix . decamelize($functionSigName); my $returnType = GetGlibTypeName($functionSigType); my $returnValueIsGDOMType = IsGDOMClassType($functionSigType); my $conditionalString = $codeGenerator->GenerateConditionalString($function->signature); my $parentConditionalString = $codeGenerator->GenerateConditionalString($parentNode); my @conditionalWarn = GenerateConditionalWarning($function->signature); my @parentConditionalWarn = GenerateConditionalWarning($parentNode); my $functionSig = "${className}* self"; my @callImplParams; foreach my $param (@{$function->parameters}) { my $paramIDLType = $param->type; if ($paramIDLType eq "EventListener" || $paramIDLType eq "MediaQueryListListener") { # EventListeners are handled elsewhere. return; } addIncludeInBody($paramIDLType); my $paramType = GetGlibTypeName($paramIDLType); my $const = $paramType eq "gchar*" ? "const " : ""; my $paramName = $param->name; $functionSig .= ", ${const}$paramType $paramName"; my $paramIsGDOMType = IsGDOMClassType($paramIDLType); if ($paramIsGDOMType) { if ($paramIDLType ne "DOMObject") { $implIncludes{"webkit/WebKitDOM${paramIDLType}Private.h"} = 1; } } if ($paramIsGDOMType || ($paramIDLType eq "DOMString") || ($paramIDLType eq "CompareHow")) { $paramName = "converted" . $codeGenerator->WK_ucfirst($paramName); } push(@callImplParams, $paramName); } if ($returnType ne "void" && $returnValueIsGDOMType && $functionSigType ne "DOMObject") { if ($functionSigType ne "EventTarget") { $implIncludes{"webkit/WebKitDOM${functionSigType}Private.h"} = 1; $implIncludes{"webkit/WebKitDOM${functionSigType}.h"} = 1; } else { $implIncludes{"WebKitDOM${functionSigType}.h"} = 1; } $implIncludes{"${functionSigType}.h"} = 1; } if (@{$function->raisesExceptions}) { $functionSig .= ", GError** error"; } # Insert introspection annotations push(@hBody, "/**\n"); push(@hBody, " * ${functionName}:\n"); push(@hBody, " * \@self: A #${className}\n"); foreach my $param (@{$function->parameters}) { my $paramType = GetGlibTypeName($param->type); # $paramType can have a trailing * in some cases $paramType =~ s/\*$//; my $paramName = $param->name; push(@hBody, " * \@${paramName}: A #${paramType}\n"); } if(@{$function->raisesExceptions}) { push(@hBody, " * \@error: #GError\n"); } push(@hBody, " *\n"); if (IsGDOMClassType($function->signature->type)) { push(@hBody, " * Returns: (transfer none):\n"); } else { push(@hBody, " * Returns:\n"); } push(@hBody, " *\n"); push(@hBody, "**/\n"); push(@hBody, "WEBKIT_API $returnType\n$functionName($functionSig);\n"); push(@hBody, "\n"); push(@cBody, "$returnType\n$functionName($functionSig)\n{\n"); push(@cBody, "#if ${parentConditionalString}\n") if $parentConditionalString; push(@cBody, "#if ${conditionalString}\n") if $conditionalString; if ($returnType ne "void") { # TODO: return proper default result push(@cBody, " g_return_val_if_fail(self, 0);\n"); } else { push(@cBody, " g_return_if_fail(self);\n"); } push(@cBody, " WebCore::JSMainThreadNullState state;\n"); # The WebKit::core implementations check for null already; no need to duplicate effort. push(@cBody, " WebCore::${interfaceName}* item = WebKit::core(self);\n"); foreach my $param (@{$function->parameters}) { my $paramName = $param->name; my $paramIDLType = $param->type; my $paramTypeIsPrimitive = $codeGenerator->IsPrimitiveType($paramIDLType); my $paramIsGDOMType = IsGDOMClassType($paramIDLType); if (!$paramTypeIsPrimitive) { if ($returnType ne "void") { # TODO: return proper default result # FIXME: Temporary hack for generating a proper implementation # of the webkit_dom_document_evaluate function (Bug-ID: 42115) if (!(($functionName eq "webkit_dom_document_evaluate") && ($paramIDLType eq "XPathResult"))) { push(@cBody, " g_return_val_if_fail($paramName, 0);\n"); } } else { push(@cBody, " g_return_if_fail($paramName);\n"); } } } $returnParamName = ""; foreach my $param (@{$function->parameters}) { my $paramIDLType = $param->type; my $paramName = $param->name; my $paramIsGDOMType = IsGDOMClassType($paramIDLType); $convertedParamName = "converted" . $codeGenerator->WK_ucfirst($paramName); if ($paramIDLType eq "DOMString") { push(@cBody, " WTF::String ${convertedParamName} = WTF::String::fromUTF8($paramName);\n"); } elsif ($paramIDLType eq "CompareHow") { push(@cBody, " WebCore::Range::CompareHow ${convertedParamName} = static_cast($paramName);\n"); } elsif ($paramIsGDOMType) { push(@cBody, " WebCore::${paramIDLType}* ${convertedParamName} = 0;\n"); push(@cBody, " if (${paramName}) {\n"); push(@cBody, " ${convertedParamName} = WebKit::core($paramName);\n"); if ($returnType ne "void") { # TODO: return proper default result push(@cBody, " g_return_val_if_fail(${convertedParamName}, 0);\n"); } else { push(@cBody, " g_return_if_fail(${convertedParamName});\n"); } push(@cBody, " }\n"); } $returnParamName = $convertedParamName if $param->extendedAttributes->{"CustomReturn"}; } my $assign = ""; my $assignPre = ""; my $assignPost = ""; # We need to special-case these Node methods because their C++ # signature is different from what we'd expect given their IDL # description; see Node.h. my $functionHasCustomReturn = $functionName eq "webkit_dom_node_append_child" || $functionName eq "webkit_dom_node_insert_before" || $functionName eq "webkit_dom_node_replace_child" || $functionName eq "webkit_dom_node_remove_child"; if ($returnType ne "void" && !$functionHasCustomReturn) { if ($returnValueIsGDOMType) { $assign = "RefPtr gobjectResult = "; $assignPre = "WTF::getPtr("; $assignPost = ")"; } else { $assign = "${returnType} result = "; } } if (@{$function->raisesExceptions}) { push(@cBody, " WebCore::ExceptionCode ec = 0;\n") ; push(@callImplParams, "ec"); } if ($functionHasCustomReturn) { push(@cBody, " bool ok = item->${functionSigName}(" . join(", ", @callImplParams) . ");\n"); my $customNodeAppendChild = << "EOF"; if (ok) { ${returnType} result = WebKit::kit($returnParamName); return result; } EOF push(@cBody, $customNodeAppendChild); if(@{$function->raisesExceptions}) { my $exceptionHandling = << "EOF"; WebCore::ExceptionCodeDescription ecdesc(ec); g_set_error_literal(error, g_quark_from_string("WEBKIT_DOM"), ecdesc.code, ecdesc.name); EOF push(@cBody, $exceptionHandling); } push(@cBody, "return 0;"); push(@cBody, "}\n\n"); return; } elsif ($functionSigType eq "DOMString") { my $getterContentHead; if ($prefix) { my ($functionName, @arguments) = $codeGenerator->GetterExpression(\%implIncludes, $interfaceName, $function); push(@arguments, @callImplParams); if ($function->signature->extendedAttributes->{"ImplementedBy"}) { my $implementedBy = $function->signature->extendedAttributes->{"ImplementedBy"}; $implIncludes{"${implementedBy}.h"} = 1; unshift(@arguments, "item"); $functionName = "WebCore::${implementedBy}::${functionName}"; } else { $functionName = "item->${functionName}"; } $getterContentHead = "${assign}convertToUTF8String(${functionName}(" . join(", ", @arguments) . "));\n"; } else { my @arguments = @callImplParams; if ($function->signature->extendedAttributes->{"ImplementedBy"}) { my $implementedBy = $function->signature->extendedAttributes->{"ImplementedBy"}; $implIncludes{"${implementedBy}.h"} = 1; unshift(@arguments, "item"); $getterContentHead = "${assign}convertToUTF8String(WebCore::${implementedBy}::${functionSigName}(" . join(", ", @arguments) . "));\n"; } else { $getterContentHead = "${assign}convertToUTF8String(item->${functionSigName}(" . join(", ", @arguments) . "));\n"; } } push(@cBody, " ${getterContentHead}"); } else { my $contentHead; if ($prefix eq "get_") { my ($functionName, @arguments) = $codeGenerator->GetterExpression(\%implIncludes, $interfaceName, $function); push(@arguments, @callImplParams); if ($function->signature->extendedAttributes->{"ImplementedBy"}) { my $implementedBy = $function->signature->extendedAttributes->{"ImplementedBy"}; $implIncludes{"${implementedBy}.h"} = 1; unshift(@arguments, "item"); $functionName = "WebCore::${implementedBy}::${functionName}"; } else { $functionName = "item->${functionName}"; } $contentHead = "${assign}${assignPre}${functionName}(" . join(", ", @arguments) . "${assignPost});\n"; } elsif ($prefix eq "set_") { my ($functionName, @arguments) = $codeGenerator->SetterExpression(\%implIncludes, $interfaceName, $function); push(@arguments, @callImplParams); if ($function->signature->extendedAttributes->{"ImplementedBy"}) { my $implementedBy = $function->signature->extendedAttributes->{"ImplementedBy"}; $implIncludes{"${implementedBy}.h"} = 1; unshift(@arguments, "item"); $functionName = "WebCore::${implementedBy}::${functionName}"; $contentHead = "${assign}${assignPre}${functionName}(" . join(", ", @arguments) . "${assignPost});\n"; } else { $functionName = "item->${functionName}"; $contentHead = "${assign}${assignPre}${functionName}(" . join(", ", @arguments) . "${assignPost});\n"; } } else { my @arguments = @callImplParams; if ($function->signature->extendedAttributes->{"ImplementedBy"}) { my $implementedBy = $function->signature->extendedAttributes->{"ImplementedBy"}; $implIncludes{"${implementedBy}.h"} = 1; unshift(@arguments, "item"); $contentHead = "${assign}${assignPre}WebCore::${implementedBy}::${functionSigName}(" . join(", ", @arguments) . "${assignPost});\n"; } else { $contentHead = "${assign}${assignPre}item->${functionSigName}(" . join(", ", @arguments) . "${assignPost});\n"; } } push(@cBody, " ${contentHead}"); if(@{$function->raisesExceptions}) { my $exceptionHandling = << "EOF"; if (ec) { WebCore::ExceptionCodeDescription ecdesc(ec); g_set_error_literal(error, g_quark_from_string("WEBKIT_DOM"), ecdesc.code, ecdesc.name); } EOF push(@cBody, $exceptionHandling); } } if ($returnType ne "void" && !$functionHasCustomReturn) { if ($functionSigType ne "DOMObject") { if ($returnValueIsGDOMType) { push(@cBody, " ${returnType} result = WebKit::kit(gobjectResult.get());\n"); } } if ($functionSigType eq "DOMObject") { push(@cBody, " return 0; // TODO: return canvas object\n"); } else { push(@cBody, " return result;\n"); } } if ($conditionalString) { push(@cBody, "#else\n"); push(@cBody, @conditionalWarn) if scalar(@conditionalWarn); if ($returnType ne "void") { if ($codeGenerator->IsNonPointerType($functionSigType)) { push(@cBody, " return static_cast<${returnType}>(0);\n"); } else { push(@cBody, " return 0;\n"); } } push(@cBody, "#endif /* ${conditionalString} */\n"); } if ($parentConditionalString) { push(@cBody, "#else\n"); push(@cBody, @parentConditionalWarn) if scalar(@parentConditionalWarn); if ($returnType ne "void") { if ($codeGenerator->IsNonPointerType($functionSigType)) { push(@cBody, " return static_cast<${returnType}>(0);\n"); } else { push(@cBody, " return 0;\n"); } } push(@cBody, "#endif /* ${parentConditionalString} */\n"); } push(@cBody, "}\n\n"); } sub ClassHasFunction { my ($class, $name) = @_; foreach my $function (@{$class->functions}) { if ($function->signature->name eq $name) { return 1; } } return 0; } sub GenerateFunctions { my ($object, $interfaceName, $dataNode) = @_; foreach my $function (@{$dataNode->functions}) { $object->GenerateFunction($interfaceName, $function, "", $dataNode); } TOP: foreach my $attribute (@{$dataNode->attributes}) { if (SkipAttribute($attribute) || $attribute->signature->type eq "EventListener" || $attribute->signature->type eq "MediaQueryListListener") { next TOP; } if ($attribute->signature->name eq "type" # This will conflict with the get_type() function we define to return a GType # according to GObject conventions. Skip this for now. || $attribute->signature->name eq "URL" # TODO: handle this ) { next TOP; } my $attrNameUpper = $codeGenerator->WK_ucfirst($attribute->signature->name); my $getname = "get${attrNameUpper}"; my $setname = "set${attrNameUpper}"; if (ClassHasFunction($dataNode, $getname) || ClassHasFunction($dataNode, $setname)) { # Very occasionally an IDL file defines getter/setter functions for one of its # attributes; in this case we don't need to autogenerate the getter/setter. next TOP; } # Generate an attribute getter. For an attribute "foo", this is a function named # "get_foo" which calls a DOM class method named foo(). my $function = new domFunction(); $function->signature($attribute->signature); $function->raisesExceptions($attribute->getterExceptions); $object->GenerateFunction($interfaceName, $function, "get_", $dataNode); # FIXME: We are not generating setters for 'Replaceable' # attributes now, but we should somehow. if ($attribute->type =~ /^readonly/ || $attribute->signature->extendedAttributes->{"Replaceable"}) { next TOP; } # Generate an attribute setter. For an attribute, "foo", this is a function named # "set_foo" which calls a DOM class method named setFoo(). $function = new domFunction(); $function->signature(new domSignature()); $function->signature->name($attribute->signature->name); $function->signature->type($attribute->signature->type); $function->signature->extendedAttributes($attribute->signature->extendedAttributes); my $param = new domSignature(); $param->name("value"); $param->type($attribute->signature->type); my %attributes = (); $param->extendedAttributes(\%attributes); my $arrayRef = $function->parameters; push(@$arrayRef, $param); $function->raisesExceptions($attribute->setterExceptions); $object->GenerateFunction($interfaceName, $function, "set_", $dataNode); } } sub GenerateCFile { my ($object, $interfaceName, $parentClassName, $parentGObjType, $dataNode) = @_; if ($dataNode->extendedAttributes->{"EventTarget"}) { $object->GenerateEventTargetIface($dataNode); } my $implContent = ""; my $clsCaps = uc(FixUpDecamelizedName(decamelize($interfaceName))); my $lowerCaseIfaceName = "webkit_dom_" . FixUpDecamelizedName(decamelize($interfaceName)); $implContent = << "EOF"; ${defineTypeMacro}(${className}, ${lowerCaseIfaceName}, ${parentGObjType}${defineTypeInterfaceImplementation} EOF push(@cBodyProperties, $implContent); $implContent = << "EOF"; WebCore::${interfaceName}* core(${className}* request) { g_return_val_if_fail(request, 0); WebCore::${interfaceName}* coreObject = static_cast(WEBKIT_DOM_OBJECT(request)->coreObject); g_return_val_if_fail(coreObject, 0); return coreObject; } EOF push(@cBodyPriv, $implContent); $object->GenerateProperties($interfaceName, $dataNode); $object->GenerateFunctions($interfaceName, $dataNode); my $wrapMethod = << "EOF"; ${className}* wrap${interfaceName}(WebCore::${interfaceName}* coreObject) { g_return_val_if_fail(coreObject, 0); // We call ref() rather than using a C++ smart pointer because we can't store a C++ object // in a C-allocated GObject structure. See the finalize() code for the matching deref(). coreObject->ref(); return WEBKIT_DOM_${clsCaps}(g_object_new(WEBKIT_TYPE_DOM_${clsCaps}, "core-object", coreObject, NULL)); } EOF push(@cBodyPriv, $wrapMethod); } sub GenerateEndHeader { my ($object) = @_; #Header guard my $guard = $className . "_h"; push(@hBody, "G_END_DECLS\n\n"); push(@hPrefixGuardEnd, "#endif /* $guard */\n"); } sub UsesManualKitImplementation { my $type = shift; return 1 if $type eq "Node" or $type eq "Element" or $type eq "Event"; return 0; } sub GenerateEventTargetIface { my $object = shift; my $dataNode = shift; my $interfaceName = $dataNode->name; my $decamelize = FixUpDecamelizedName(decamelize($interfaceName)); $implIncludes{"GObjectEventListener.h"} = 1; $implIncludes{"WebKitDOMEventTarget.h"} = 1; $implIncludes{"WebKitDOMEventPrivate.h"} = 1; my $impl = << "EOF"; static void webkit_dom_${decamelize}_dispatch_event(WebKitDOMEventTarget* target, WebKitDOMEvent* event, GError** error) { WebCore::Event* coreEvent = WebKit::core(event); WebCore::${interfaceName}* coreTarget = static_cast(WEBKIT_DOM_OBJECT(target)->coreObject); WebCore::ExceptionCode ec = 0; coreTarget->dispatchEvent(coreEvent, ec); if (ec) { WebCore::ExceptionCodeDescription description(ec); g_set_error_literal(error, g_quark_from_string("WEBKIT_DOM"), description.code, description.name); } } static gboolean webkit_dom_${decamelize}_add_event_listener(WebKitDOMEventTarget* target, const char* eventName, GCallback handler, gboolean bubble, gpointer userData) { WebCore::${interfaceName}* coreTarget = static_cast(WEBKIT_DOM_OBJECT(target)->coreObject); return WebCore::GObjectEventListener::addEventListener(G_OBJECT(target), coreTarget, eventName, handler, bubble, userData); } static gboolean webkit_dom_${decamelize}_remove_event_listener(WebKitDOMEventTarget* target, const char* eventName, GCallback handler, gboolean bubble) { WebCore::${interfaceName}* coreTarget = static_cast(WEBKIT_DOM_OBJECT(target)->coreObject); return WebCore::GObjectEventListener::removeEventListener(G_OBJECT(target), coreTarget, eventName, handler, bubble); } static void webkit_dom_event_target_init(WebKitDOMEventTargetIface* iface) { iface->dispatch_event = webkit_dom_${decamelize}_dispatch_event; iface->add_event_listener = webkit_dom_${decamelize}_add_event_listener; iface->remove_event_listener = webkit_dom_${decamelize}_remove_event_listener; } EOF push(@cBodyProperties, $impl); $defineTypeMacro = "G_DEFINE_TYPE_WITH_CODE"; $defineTypeInterfaceImplementation = ", G_IMPLEMENT_INTERFACE(WEBKIT_TYPE_DOM_EVENT_TARGET, webkit_dom_event_target_init))"; } sub Generate { my ($object, $dataNode) = @_; my $parentClassName = GetParentClassName($dataNode); my $parentGObjType = GetParentGObjType($dataNode); my $interfaceName = $dataNode->name; # Add the default impl header template @cPrefix = split("\r", $licenceTemplate); push(@cPrefix, "\n"); $implIncludes{"webkitdefines.h"} = 1; $implIncludes{"webkitglobalsprivate.h"} = 1; $implIncludes{"webkitmarshal.h"} = 1; $implIncludes{"DOMObjectCache.h"} = 1; $implIncludes{"WebKitDOMBinding.h"} = 1; $implIncludes{"gobject/ConvertToUTF8String.h"} = 1; $implIncludes{"webkit/$className.h"} = 1; $implIncludes{"webkit/${className}Private.h"} = 1; $implIncludes{"${interfaceName}.h"} = 1; $implIncludes{"JSMainThreadExecState.h"} = 1; $implIncludes{"ExceptionCode.h"} = 1; $hdrIncludes{"webkit/${parentClassName}.h"} = 1; if (!UsesManualKitImplementation($interfaceName)) { my $converter = << "EOF"; ${className}* kit(WebCore::$interfaceName* obj) { g_return_val_if_fail(obj, 0); if (gpointer ret = DOMObjectCache::get(obj)) return static_cast<${className}*>(ret); return static_cast<${className}*>(DOMObjectCache::put(obj, WebKit::wrap${interfaceName}(obj))); } EOF push(@cBodyPriv, $converter); } $object->GenerateHeader($interfaceName, $parentClassName); $object->GenerateCFile($interfaceName, $parentClassName, $parentGObjType, $dataNode); $object->GenerateEndHeader(); } # Internal helper sub WriteData { my $object = shift; my $dataNode = shift; # Write a private header. my $interfaceName = $dataNode->name; my $filename = "$outputDir/" . $className . "Private.h"; my $guard = "${className}Private_h"; my $parentClassName = GetParentClassName($dataNode); # Add the guard if the 'Conditional' extended attribute exists my $conditionalString = $codeGenerator->GenerateConditionalString($dataNode); open(PRIVHEADER, ">$filename") or die "Couldn't open file $filename for writing"; print PRIVHEADER split("\r", $licenceTemplate); print PRIVHEADER "\n"; my $text = << "EOF"; #ifndef $guard #define $guard #include "${interfaceName}.h" #include #include EOF print PRIVHEADER $text; print PRIVHEADER "#if ${conditionalString}\n" if $conditionalString; print PRIVHEADER map { "#include \"$_\"\n" } sort keys(%hdrPropIncludes); print PRIVHEADER "\n"; $text = << "EOF"; namespace WebKit { ${className}* wrap${interfaceName}(WebCore::${interfaceName}*); WebCore::${interfaceName}* core(${className}* request); EOF print PRIVHEADER $text; if ($className ne "WebKitDOMNode") { print PRIVHEADER "${className}* kit(WebCore::${interfaceName}* node);\n" } $text = << "EOF"; } // namespace WebKit EOF print PRIVHEADER $text; print PRIVHEADER "#endif /* ${conditionalString} */\n\n" if $conditionalString; print PRIVHEADER "#endif /* ${guard} */\n"; close(PRIVHEADER); my $basename = FileNamePrefix . $interfaceName; $basename =~ s/_//g; # Write public header. my $fullHeaderFilename = "$outputDir/" . $basename . ".h"; my $installedHeaderFilename = "${basename}.h"; open(HEADER, ">$fullHeaderFilename") or die "Couldn't open file $fullHeaderFilename"; print HEADER @hPrefix; print HEADER @hPrefixGuard; print HEADER "#include \n"; print HEADER map { "#include <$_>\n" } sort keys(%hdrIncludes); print HEADER "#include \n"; print HEADER "#include \n\n"; print HEADER @hBodyPre; print HEADER @hBody; print HEADER @hPrefixGuardEnd; close(HEADER); # Write the implementation sources my $implFileName = "$outputDir/" . $basename . ".cpp"; open(IMPL, ">$implFileName") or die "Couldn't open file $implFileName"; print IMPL @cPrefix; print IMPL "#include \"config.h\"\n"; print IMPL "#include \"$installedHeaderFilename\"\n\n"; # Remove the implementation header from the list of included files. %includesCopy = %implIncludes; delete ($includesCopy{"webkit/$installedHeaderFilename"}); print IMPL map { "#include \"$_\"\n" } sort keys(%includesCopy); print IMPL "#include \n"; print IMPL "#include \n"; print IMPL "#include \n\n"; print IMPL "#if ${conditionalString}\n\n" if $conditionalString; print IMPL "namespace WebKit {\n\n"; print IMPL @cBodyPriv; print IMPL "} // namespace WebKit\n\n"; print IMPL "#endif // ${conditionalString}\n\n" if $conditionalString; print IMPL @cBodyProperties; print IMPL @cBody; close(IMPL); %implIncludes = (); %hdrIncludes = (); @hPrefix = (); @hBody = (); @cPrefix = (); @cBody = (); @cBodyPriv = (); @cBodyProperties = (); } sub GenerateInterface { my ($object, $dataNode, $defines) = @_; # Set up some global variables $className = GetClassName($dataNode->name); $object->Generate($dataNode); $object->WriteData($dataNode); } 1;