blob: 5d8af4a0eb5ef56f5e01b9f9be3aeda093de072f [file] [log] [blame]
# Copyright (C) 2008 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
# Copyright (C) 2008 Martin Soto <soto@freedesktop.org>
# Copyright (C) 2008 Alp Toker <alp@atoker.com>
# Copyright (C) 2009 Adam Dingle <adam@yorba.org>
# Copyright (C) 2009 Jim Nelson <jim@yorba.org>
# 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;
}
return 1 if $codeGenerator->IsTypedArrayType($propType);
$codeGenerator->AssertNotSequenceType($propType);
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;
}
# Skip indexed database attributes for now, they aren't yet supported for the GObject generator.
if ($attribute->signature->name =~ /^(?:webkit)?[Ii]ndexedDB/ or $attribute->signature->name =~ /^(?:webkit)?IDB/) {
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->GetSequenceType($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<T> parameters, because this
# code generator doesn't know how to auto-generate MediaQueryListListener or sequence<T>.
foreach my $param (@{$function->parameters}) {
if ($param->extendedAttributes->{"Callback"} ||
$param->extendedAttributes->{"Clamp"} ||
$param->type eq "MediaQueryListListener" ||
$codeGenerator->GetSequenceType($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<WebCore::${propType}> 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";
$conditionGuardStart
${className}* self = WEBKIT_DOM_${clsCaps}(object);
$privFunction
$conditionGuardEnd
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";
$conditionGuardStart
${className}* self = WEBKIT_DOM_${clsCaps}(object);
$privFunction
$conditionGuardEnd
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<WebCore::${interfaceName}*>(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;
}
return if ($function->signature->name eq "set" and $parentNode->extendedAttributes->{"TypedArray"});
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<WebCore::Range::CompareHow>($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<WebCore::${functionSigType}> 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<WebCore::${interfaceName}*>(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<WebCore::${interfaceName}*>(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<WebCore::${interfaceName}*>(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<WebCore::${interfaceName}*>(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 <glib-object.h>
#include <webkit/${parentClassName}.h>
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 <glib-object.h>\n";
print HEADER map { "#include <$_>\n" } sort keys(%hdrIncludes);
print HEADER "#include <webkit/webkitdefines.h>\n";
print HEADER "#include <webkit/webkitdomdefines.h>\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 <glib-object.h>\n";
print IMPL "#include <wtf/GetPtr.h>\n";
print IMPL "#include <wtf/RefPtr.h>\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;