CodeGeneratorGObject.pm [plain text]
package CodeGeneratorGObject;
use constant FileNamePrefix => "WebKitDOM";
use File::Basename;
use FindBin;
my %implIncludes = ();
my %hdrIncludes = ();
my @stableSymbols = ();
my $defineTypeMacro = "G_DEFINE_TYPE";
my $defineTypeInterfaceImplementation = ")";
my @txtEventListeners = ();
my @txtInstallProps = ();
my @txtSetProps = ();
my @txtGetProps = ();
my $className = "";
my %baseTypeHash = ("Object" => 1, "Node" => 1, "NodeList" => 1, "NamedNodeMap" => 1, "DOMImplementation" => 1,
"Event" => 1, "CSSRule" => 1, "CSSValue" => 1, "StyleSheet" => 1, "MediaList" => 1,
"Counter" => 1, "Rect" => 1, "RGBColor" => 1, "XPathExpression" => 1, "XPathResult" => 1,
"NodeIterator" => 1, "TreeWalker" => 1, "AbstractView" => 1, "Blob" => 1, "DOMTokenList" => 1,
"HTMLCollection" => 1, "TextTrackCue" => 1);
my $canBeNullParams = {
'webkit_dom_document_create_attribute_ns' => ['namespaceURI'],
'webkit_dom_document_create_element_ns' => ['namespaceURI'],
'webkit_dom_document_create_entity_reference' => ['name'],
'webkit_dom_document_create_node_iterator' => ['filter'],
'webkit_dom_document_create_tree_walker' => ['filter'],
'webkit_dom_document_evaluate' => ['inResult', 'resolver'],
'webkit_dom_document_get_override_style' => ['pseudoElement'],
'webkit_dom_dom_implementation_create_document' => ['namespaceURI', 'doctype'],
'webkit_dom_dom_window_get_computed_style' => ['pseudoElement'],
'webkit_dom_element_set_attribute_ns' => ['namespaceURI'],
'webkit_dom_node_insert_before' => ['refChild'],
};
sub new {
my $object = shift;
my $reference = { };
$codeGenerator = shift;
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 GetParentClassName {
my $interface = shift;
return "WebKitDOMObject" unless $interface->parent;
return "WebKitDOM" . $interface->parent;
}
sub GetParentImplClassName {
my $interface = shift;
return "Object" unless $interface->parent;
return $interface->parent;
}
sub IsBaseType
{
my $type = shift;
return 1 if $baseTypeHash{$type};
return 0;
}
sub GetBaseClass
{
$parent = shift;
$interface = shift;
return $parent if $parent eq "Object" or IsBaseType($parent);
return "Event" if $codeGenerator->InheritsInterface($interface, "Event");
return "CSSValue" if $parent eq "SVGColor" or $parent eq "CSSValueList";
return "Node";
}
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;
for ($s) {
s/domcss/dom_css/;
s/domhtml/dom_html/;
s/domdom/dom_dom/;
s/domcdata/dom_cdata/;
s/domui/dom_ui/;
s/x_path/xpath/;
s/web_kit/webkit/;
s/htmli_frame/html_iframe/;
s/htmlbr/html_br/;
s/htmlli/html_li/;
s/htmlhr/html_hr/;
s/htmld/html_d/;
s/htmlo/html_o/;
s/htmlu/html_u/;
}
return $s;
}
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 GetParentGObjType {
my $interface = shift;
return "WEBKIT_DOM_TYPE_OBJECT" unless $interface->parent;
return "WEBKIT_DOM_TYPE_" . uc(decamelize(($interface->parent)));
}
sub GetClassName {
my $name = shift;
return "WebKitDOM$name";
}
sub SkipAttribute {
my $attribute = shift;
if ($attribute->signature->extendedAttributes->{"Custom"}
|| $attribute->signature->extendedAttributes->{"CustomGetter"}) {
return 1;
}
my $propType = $attribute->signature->type;
if ($propType =~ /Constructor$/) {
return 1;
}
return 1 if $attribute->isStatic;
return 1 if $codeGenerator->IsTypedArrayType($propType);
$codeGenerator->AssertNotSequenceType($propType);
if ($codeGenerator->GetArrayType($propType)) {
return 1;
}
if ($codeGenerator->IsEnumType($propType)) {
return 1;
}
if ($attribute->signature->name eq "location") {
return 1;
}
if ($attribute->signature->name eq "valueAsDate") {
return 1;
}
if ($attribute->signature->type eq "Crypto") {
return 1;
}
if ($attribute->signature->type eq "EventListener") {
return 1;
}
if ($attribute->signature->type eq "MediaQueryListListener") {
return 1;
}
if ($attribute->signature->name =~ /^(?:webkit)?[Ii]ndexedDB/ or $attribute->signature->name =~ /^(?:webkit)?IDB/) {
return 1;
}
return 0;
}
sub SkipFunction {
my $object = shift;
my $function = shift;
my $parentNode = 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;
}
foreach my $param (@{$function->parameters}) {
if ($codeGenerator->IsCallbackInterface($param->type) ||
$param->extendedAttributes->{"Clamp"} ||
$param->type eq "MediaQueryListListener" ||
$param->type eq "EventListener" ||
$codeGenerator->GetSequenceType($param->type)) {
return 1;
}
}
if ($functionName eq "webkit_dom_data_transfer_item_list_add" && @{$function->parameters} == 1) {
return 1;
}
if ($parentNode->extendedAttributes->{"EventTarget"} && $function->signature->name eq "dispatchEvent") {
return 1;
}
if ($functionName eq "webkit_dom_console_profile" || $functionName eq "webkit_dom_console_profile_end") {
return 1;
}
if ($codeGenerator->IsTypedArrayType($function->signature->type) || $codeGenerator->GetArrayType($function->signature->type)) {
return 1;
}
if ($function->signature->name eq "set" and $parentNode->extendedAttributes->{"TypedArray"}) {
return 1;
}
if ($object eq "MediaQueryListListener") {
return 1;
}
if ($function->signature->name eq "getSVGDocument") {
return 1;
}
if ($function->signature->name eq "getCSSCanvasContext") {
return 1;
}
if ($function->signature->name eq "setRangeText" && @{$function->parameters} == 1) {
return 1;
}
if ($function->signature->name eq "timeEnd") {
return 1;
}
if ($codeGenerator->GetSequenceType($functionReturnType)) {
return 1;
}
if ($function->signature->name eq "supports" && @{$function->parameters} == 1) {
return 1;
}
return 0;
}
sub GetGValueTypeName {
my $type = shift;
my %types = ("DOMString", "string",
"DOMTimeStamp", "uint",
"float", "float",
"unrestricted float", "float",
"double", "double",
"unrestricted double", "double",
"boolean", "boolean",
"char", "char",
"long", "long",
"long long", "int64",
"byte", "int8",
"octet", "uint8",
"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";
}
sub GetGlibTypeName {
my $type = shift;
my $name = GetClassName($type);
my %types = ("DOMString", "gchar*",
"DOMTimeStamp", "guint32",
"CompareHow", "gushort",
"float", "gfloat",
"unrestricted float", "gfloat",
"double", "gdouble",
"unrestricted double", "gdouble",
"boolean", "gboolean",
"char", "gchar",
"long", "glong",
"long long", "gint64",
"byte", "gint8",
"octet", "guint8",
"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 IsPropertyReadable {
my $property = shift;
return !SkipAttribute($property);
}
sub IsPropertyWriteable {
my $property = shift;
if (!IsPropertyReadable($property)) {
return 0;
}
if ($property->isReadOnly) {
return 0;
}
my $gtype = GetGValueTypeName($property->signature->type);
my $hasGtypeSignature = $gtype eq "boolean" || $gtype eq "float" || $gtype eq "double" ||
$gtype eq "int64" || $gtype eq "uint64" ||
$gtype eq "long" || $gtype eq "ulong" ||
$gtype eq "int" || $gtype eq "uint" ||
$gtype eq "short" || $gtype eq "ushort" ||
$gtype eq "int8" || $gtype eq "uint8" ||
$gtype eq "char" || $gtype eq "uchar" ||
$gtype eq "string";
if (!$hasGtypeSignature) {
return 0;
}
if ($property->signature->extendedAttributes->{"Replaceable"}) {
return 0;
}
if ($property->signature->extendedAttributes->{"CustomSetter"}) {
return 0;
}
return 1;
}
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 $hasGetterException = $attribute->signature->extendedAttributes->{"GetterRaisesException"};
my $hasSetterException = $attribute->signature->extendedAttributes->{"SetterRaisesException"};
my $decamelizeInterfaceName = decamelize($interfaceName);
my $propName = decamelize($attribute->signature->name);
my $propFunctionName = GetFunctionSignatureName($interfaceName, $attribute);
my $propNameCaps = uc($propName);
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 = IsPropertyWriteable($attribute);
my $mutableString = "read-only";
my $hasCustomSetter = $attribute->signature->extendedAttributes->{"CustomSetter"};
if ($writeable && $hasCustomSetter) {
$mutableString = "read-only (due to custom functions needed in webkitdom)";
} elsif ($writeable) {
$gparamflag = "WEBKIT_PARAM_READWRITE";
$mutableString = "read-write";
}
my @getterArguments = ();
push(@getterArguments, "self");
push(@getterArguments, "nullptr") if $hasGetterException;
my @setterArguments = ();
push(@setterArguments, "self, g_value_get_$gtype(value)");
push(@setterArguments, "nullptr") if $hasSetterException;
if (grep {$_ eq $attribute} @writeableProperties) {
push(@txtSetProps, " case ${propEnum}:\n");
push(@txtSetProps, " webkit_dom_${decamelizeInterfaceName}_set_" . $propFunctionName . "(" . join(", ", @setterArguments) . ");\n");
push(@txtSetProps, " break;\n");
}
push(@txtGetProps, " case ${propEnum}:\n");
my $postConvertFunction = "";
if ($gtype eq "string") {
push(@txtGetProps, " g_value_take_string(value, webkit_dom_${decamelizeInterfaceName}_get_" . $propFunctionName . "(" . join(", ", @getterArguments) . "));\n");
} else {
push(@txtGetProps, " g_value_set_$gtype(value, webkit_dom_${decamelizeInterfaceName}_get_" . $propFunctionName . "(" . join(", ", @getterArguments) . "));\n");
}
push(@txtGetProps, " break;\n");
my %parameterSpecOptions = ("int" => [ "G_MININT", "G_MAXINT", "0" ],
"int8" => [ "G_MININT8", "G_MAXINT8", "0" ],
"boolean" => [ "FALSE" ],
"float" => [ "-G_MAXFLOAT", "G_MAXFLOAT", "0" ],
"double" => [ "-G_MAXDOUBLE", "G_MAXDOUBLE", "0" ],
"uint64" => [ "0", "G_MAXUINT64", "0" ],
"long" => [ "G_MINLONG", "G_MAXLONG", "0" ],
"int64" => [ "G_MININT64", "G_MAXINT64", "0" ],
"ulong" => [ "0", "G_MAXULONG", "0" ],
"uint" => [ "0", "G_MAXUINT", "0" ],
"uint8" => [ "0", "G_MAXUINT8", "0" ],
"ushort" => [ "0", "G_MAXUINT16", "0" ],
"uchar" => [ "G_MININT8", "G_MAXINT8", "0" ],
"char" => [ "0", "G_MAXUINT8", "0" ],
"string" => [ '""', ],
"object" => [ "WEBKIT_DOM_TYPE_${ucPropGType}" ]);
my $extraParameters = join(", ", @{$parameterSpecOptions{$gtype}});
my $glibTypeName = GetGlibTypeName($propType);
$propName =~ s/_/-/g;
my $txtInstallProp = << "EOF";
g_object_class_install_property(
gobjectClass,
$propEnum,
g_param_spec_$gtype(
"$propName",
"$interfaceName:$propName",
"$mutableString $glibTypeName $interfaceName:$propName",
$extraParameters,
$gparamflag));
EOF
push(@txtInstallProps, $txtInstallProp);
}
sub GenerateProperties {
my ($object, $interfaceName, $interface) = @_;
my $decamelize = decamelize($interfaceName);
my $clsCaps = uc($decamelize);
my $lowerCaseIfaceName = "webkit_dom_$decamelize";
my $parentImplClassName = GetParentImplClassName($interface);
my $conditionGuardStart = "";
my $conditionGuardEnd = "";
my $conditionalString = $codeGenerator->GenerateConditionalString($interface);
if ($conditionalString) {
$conditionGuardStart = "#if ${conditionalString}";
$conditionGuardEnd = "#endif // ${conditionalString}";
}
my $implContent = "";
my @readableProperties = grep { IsPropertyReadable($_) } @{$interface->attributes};
my @writeableProperties = grep { IsPropertyWriteable($_) } @{$interface->attributes};
my $numProperties = scalar @readableProperties;
if ($numProperties > 0) {
$implContent = << "EOF";
enum {
PROP_0,
EOF
push(@cBodyProperties, $implContent);
push(@txtGetProps, "static void ${lowerCaseIfaceName}_get_property(GObject* object, guint propertyId, GValue* value, GParamSpec* pspec)\n");
push(@txtGetProps, "{\n");
push(@txtGetProps, " ${className}* self = WEBKIT_DOM_${clsCaps}(object);\n");
push(@txtGetProps, "\n");
push(@txtGetProps, " switch (propertyId) {\n");
if (scalar @writeableProperties > 0) {
push(@txtSetProps, "static void ${lowerCaseIfaceName}_set_property(GObject* object, guint propertyId, const GValue* value, GParamSpec* pspec)\n");
push(@txtSetProps, "{\n");
push(@txtSetProps, " ${className}* self = WEBKIT_DOM_${clsCaps}(object);\n");
push(@txtSetProps, "\n");
push(@txtSetProps, " switch (propertyId) {\n");
}
foreach my $attribute (@readableProperties) {
GenerateProperty($attribute, $interfaceName, \@writeableProperties, $interface);
}
push(@cBodyProperties, "};\n\n");
$txtGetProp = << "EOF";
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propertyId, pspec);
break;
}
}
EOF
push(@txtGetProps, $txtGetProp);
if (scalar @writeableProperties > 0) {
$txtSetProps = << "EOF";
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propertyId, pspec);
break;
}
}
EOF
push(@txtSetProps, $txtSetProps);
}
}
$" = "";
if ($parentImplClassName eq "Object") {
$implContent = << "EOF";
static void ${lowerCaseIfaceName}_finalize(GObject* object)
{
${className}Private* priv = WEBKIT_DOM_${clsCaps}_GET_PRIVATE(object);
$conditionGuardStart
WebKit::DOMObjectCache::forget(priv->coreObject.get());
$conditionGuardEnd
priv->~${className}Private();
G_OBJECT_CLASS(${lowerCaseIfaceName}_parent_class)->finalize(object);
}
EOF
push(@cBodyProperties, $implContent);
}
if ($numProperties > 0) {
if (scalar @writeableProperties > 0) {
push(@cBodyProperties, @txtSetProps);
push(@cBodyProperties, "\n");
}
push(@cBodyProperties, @txtGetProps);
push(@cBodyProperties, "\n");
}
# Add a constructor implementation only for direct subclasses of Object to make sure
# that the WebCore wrapped object is added only once to the DOM cache. The DOM garbage
# collector works because Node is a direct subclass of Object and the version of
# DOMObjectCache::put() that receives a Node (which is the one setting the frame) is
# always called for DOM objects derived from Node.
if ($parentImplClassName eq "Object") {
$implContent = << "EOF";
static GObject* ${lowerCaseIfaceName}_constructor(GType type, guint constructPropertiesCount, GObjectConstructParam* constructProperties)
{
GObject* object = G_OBJECT_CLASS(${lowerCaseIfaceName}_parent_class)->constructor(type, constructPropertiesCount, constructProperties);
$conditionGuardStart
${className}Private* priv = WEBKIT_DOM_${clsCaps}_GET_PRIVATE(object);
priv->coreObject = static_cast<WebCore::${interfaceName}*>(WEBKIT_DOM_OBJECT(object)->coreObject);
WebKit::DOMObjectCache::put(priv->coreObject.get(), object);
$conditionGuardEnd
return object;
}
EOF
push(@cBodyProperties, $implContent);
}
$implContent = << "EOF";
static void ${lowerCaseIfaceName}_class_init(${className}Class* requestClass)
{
EOF
push(@cBodyProperties, $implContent);
if ($parentImplClassName eq "Object" || $numProperties > 0) {
push(@cBodyProperties, " GObjectClass* gobjectClass = G_OBJECT_CLASS(requestClass);\n");
if ($parentImplClassName eq "Object") {
push(@cBodyProperties, " g_type_class_add_private(gobjectClass, sizeof(${className}Private));\n");
push(@cBodyProperties, " gobjectClass->constructor = ${lowerCaseIfaceName}_constructor;\n");
push(@cBodyProperties, " gobjectClass->finalize = ${lowerCaseIfaceName}_finalize;\n");
}
if ($numProperties > 0) {
if (scalar @writeableProperties > 0) {
push(@cBodyProperties, " gobjectClass->set_property = ${lowerCaseIfaceName}_set_property;\n");
}
push(@cBodyProperties, " gobjectClass->get_property = ${lowerCaseIfaceName}_get_property;\n");
push(@cBodyProperties, "\n");
push(@cBodyProperties, @txtInstallProps);
}
} else {
push(@cBodyProperties, " UNUSED_PARAM(requestClass);\n");
}
$implContent = << "EOF";
}
static void ${lowerCaseIfaceName}_init(${className}* request)
{
EOF
push(@cBodyProperties, $implContent);
if ($parentImplClassName eq "Object") {
$implContent = << "EOF";
${className}Private* priv = WEBKIT_DOM_${clsCaps}_GET_PRIVATE(request);
new (priv) ${className}Private();
EOF
push(@cBodyProperties, $implContent);
} else {
push(@cBodyProperties, " UNUSED_PARAM(request);\n");
}
$implContent = << "EOF";
}
EOF
push(@cBodyProperties, $implContent);
}
sub GenerateConstants {
my ($interface, $prefix) = @_;
my $isStableClass = scalar(@stableSymbols);
if (@{$interface->constants}) {
my @constants = @{$interface->constants};
foreach my $constant (@constants) {
my $conditionalString = $codeGenerator->GenerateConditionalString($constant);
my $constantName = $prefix . $constant->name;
my $constantValue = $constant->value;
my $isStableSymbol = grep {$_ eq $constantName} @stableSymbols;
if ($isStableSymbol) {
push(@symbols, "$constantName\n");
}
my @constantHeader = ();
push(@constantHeader, " push(@constantHeader, "/**");
push(@constantHeader, " * ${constantName}:");
push(@constantHeader, " */");
push(@constantHeader, "#define $constantName $constantValue");
push(@constantHeader, "#endif /* ${conditionalString} */") if $conditionalString;
push(@constantHeader, "\n");
if ($isStableSymbol or !$isStableClass) {
push(@hBody, join("\n", @constantHeader));
} else {
push(@hBodyUnstable, join("\n", @constantHeader));
}
}
}
}
sub GenerateHeader {
my ($object, $interfaceName, $parentClassName, $interface) = @_;
my $implContent = "";
@hPrefix = split("\r", $licenceTemplate);
push(@hPrefix, "\n");
my $isStableClass = scalar(@stableSymbols);
if ($isStableClass) {
my $headerCheck = << "EOF";
EOF
push(@hPrefix, $headerCheck);
}
my $guard = $className . "_h";
@hPrefixGuard = << "EOF";
EOF
if (!$isStableClass) {
push(@hPrefixGuard, "#ifdef WEBKIT_DOM_USE_UNSTABLE_API\n\n");
}
$implContent = << "EOF";
G_BEGIN_DECLS
EOF
push(@hBodyPre, $implContent);
my $decamelize = decamelize($interfaceName);
my $clsCaps = uc($decamelize);
my $lowerCaseIfaceName = "webkit_dom_$decamelize";
$implContent = << "EOF";
EOF
push(@hBody, $implContent);
if ($isStableClass) {
push(@symbols, "GType ${lowerCaseIfaceName}_get_type(void)\n");
}
GenerateConstants($interface, "WEBKIT_DOM_${clsCaps}_");
$implContent = << "EOF";
struct _${className} {
${parentClassName} parent_instance;
};
struct _${className}Class {
${parentClassName}Class parent_class;
};
EOF
push(@hBody, $implContent);
push(@hBody, "WEBKIT_API GType\n${lowerCaseIfaceName}_get_type(void);\n");
push(@hBody, "\n");
}
sub GetGReturnMacro {
my ($paramName, $paramIDLType, $returnType, $functionName) = @_;
my $condition;
if ($paramIDLType eq "GError") {
$condition = "!$paramName || !*$paramName";
} elsif (IsGDOMClassType($paramIDLType)) {
my $paramTypeCaps = uc(decamelize($paramIDLType));
$condition = "WEBKIT_DOM_IS_${paramTypeCaps}($paramName)";
if (ParamCanBeNull($functionName, $paramName)) {
$condition = "!$paramName || $condition";
}
} else {
if (ParamCanBeNull($functionName, $paramName)) {
return "";
}
$condition = "$paramName";
}
my $macro;
if ($returnType ne "void") {
$defaultReturn = $returnType eq "gboolean" ? "FALSE" : 0;
$macro = " g_return_val_if_fail($condition, $defaultReturn);\n";
} else {
$macro = " g_return_if_fail($condition);\n";
}
return $macro;
}
sub ParamCanBeNull {
my($functionName, $paramName) = @_;
if (defined($functionName)) {
return scalar(grep {$_ eq $paramName} @{$canBeNullParams->{$functionName}});
}
return 0;
}
sub GetFunctionSignatureName {
my ($interfaceName, $function) = @_;
my $signatureName = decamelize($function->signature->name);
return $signatureName if $signatureName ne "type";
my $contentAttributeName = $codeGenerator->ContentAttributeName(\%implIncludes, $interfaceName, $function);
if ($contentAttributeName) {
return "type_attr" if $contentAttributeName eq "WebCore::HTMLNames::typeAttr";
}
if ($interfaceName eq "StyleSheet" || $interfaceName eq "DOMMimeType") {
return "content_type";
}
if ($interfaceName eq "HTMLFieldSet") {
return "field_set_type";
}
my @nameTokens = split('_', decamelize($interfaceName));
my $name = $nameTokens[-1];
if (scalar(@nameTokens) > 1 && $name eq "element") {
$name = $nameTokens[-2];
}
return "${name}_type";
}
sub GenerateFunction {
my ($object, $interfaceName, $function, $prefix, $parentNode) = @_;
my $decamelize = decamelize($interfaceName);
if (SkipFunction($object, $function, $parentNode, $decamelize, $prefix)) {
return;
}
my $functionSigType = $prefix eq "set_" ? "void" : $function->signature->type;
my $functionSigName = GetFunctionSignatureName($interfaceName, $function);
my $functionName = "webkit_dom_" . $decamelize . "_" . $prefix . $functionSigName;
my $returnType = GetGlibTypeName($functionSigType);
my $returnValueIsGDOMType = IsGDOMClassType($functionSigType);
my $raisesException = $function->signature->extendedAttributes->{"RaisesException"};
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 $symbolSig = "${className}*";
my @callImplParams;
foreach my $param (@{$function->parameters}) {
my $paramIDLType = $param->type;
my $paramType = GetGlibTypeName($paramIDLType);
my $const = $paramType eq "gchar*" ? "const " : "";
my $paramName = $param->name;
$functionSig .= ", ${const}$paramType $paramName";
$symbolSig .= ", ${const}$paramType";
my $paramIsGDOMType = IsGDOMClassType($paramIDLType);
if ($paramIsGDOMType) {
if ($paramIDLType ne "any") {
$implIncludes{"WebKitDOM${paramIDLType}Private.h"} = 1;
}
}
if ($paramIsGDOMType || ($paramIDLType eq "DOMString") || ($paramIDLType eq "CompareHow")) {
$paramName = "converted" . $codeGenerator->WK_ucfirst($paramName);
}
if ($paramIDLType eq "NodeFilter" || $paramIDLType eq "XPathNSResolver") {
$paramName = "WTF::getPtr(" . $paramName . ")";
}
push(@callImplParams, $paramName);
}
if ($returnType ne "void" && $returnValueIsGDOMType && $functionSigType ne "any") {
$implIncludes{"WebKitDOM${functionSigType}Private.h"} = 1;
}
$functionSig .= ", GError** error" if $raisesException;
$symbolSig .= ", GError**" if $raisesException;
my $symbol = "$returnType $functionName($symbolSig)";
my $isStableClass = scalar(@stableSymbols);
my $isStableSymbol = grep {$_ eq $symbol} @stableSymbols;
if ($isStableSymbol and $isStableClass) {
push(@symbols, "$symbol\n");
}
my @functionHeader = ();
push(@functionHeader, "/**");
push(@functionHeader, " * ${functionName}:");
push(@functionHeader, " * \@self: A #${className}");
foreach my $param (@{$function->parameters}) {
my $paramType = GetGlibTypeName($param->type);
$paramType =~ s/\*$//;
my $paramName = $param->name;
my $paramAnnotations = "";
if (ParamCanBeNull($functionName, $paramName)) {
$paramAnnotations = " (allow-none):";
}
push(@functionHeader, " * \@${paramName}:${paramAnnotations} A #${paramType}");
}
push(@functionHeader, " * \@error: #GError") if $raisesException;
push(@functionHeader, " *");
my $returnTypeName = $returnType;
my $hasReturnTag = 0;
$returnTypeName =~ s/\*$//;
if ($returnValueIsGDOMType) {
push(@functionHeader, " * Returns: (transfer none): A #${returnTypeName}");
$hasReturnTag = 1;
} elsif ($returnType ne "void") {
push(@functionHeader, " * Returns: A #${returnTypeName}");
$hasReturnTag = 1;
}
if (!$isStableSymbol) {
if ($hasReturnTag) {
push(@functionHeader, " *");
}
push(@functionHeader, " * Stability: Unstable");
}
push(@functionHeader, "**/");
push(@functionHeader, "WEBKIT_API $returnType\n$functionName($functionSig);");
push(@functionHeader, "\n");
if ($isStableSymbol or !$isStableClass) {
push(@hBody, join("\n", @functionHeader));
} else {
push(@hBodyUnstable, join("\n", @functionHeader));
}
push(@cBody, "$returnType $functionName($functionSig)\n{\n");
push(@cBody, "#if ${parentConditionalString}\n") if $parentConditionalString;
push(@cBody, "#if ${conditionalString}\n") if $conditionalString;
push(@cBody, " WebCore::JSMainThreadNullState state;\n");
$gReturnMacro = GetGReturnMacro("self", $interfaceName, $returnType);
push(@cBody, $gReturnMacro);
foreach my $param (@{$function->parameters}) {
my $paramName = $param->name;
my $paramIDLType = $param->type;
my $paramTypeIsPointer = !$codeGenerator->IsNonPointerType($paramIDLType);
if ($paramTypeIsPointer) {
$gReturnMacro = GetGReturnMacro($paramName, $paramIDLType, $returnType, $functionName);
push(@cBody, $gReturnMacro);
}
}
if ($raisesException) {
$gReturnMacro = GetGReturnMacro("error", "GError", $returnType);
push(@cBody, $gReturnMacro);
}
push(@cBody, " WebCore::${interfaceName}* item = WebKit::core(self);\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 ($paramIDLType eq "NodeFilter" || $paramIDLType eq "XPathNSResolver") {
push(@cBody, " RefPtr<WebCore::$paramIDLType> ${convertedParamName} = WebKit::core($paramName);\n");
} elsif ($paramIsGDOMType) {
push(@cBody, " WebCore::${paramIDLType}* ${convertedParamName} = WebKit::core($paramName);\n");
}
$returnParamName = $convertedParamName if $param->extendedAttributes->{"CustomReturn"};
}
my $assign = "";
my $assignPre = "";
my $assignPost = "";
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->signature->isNullable) {
push(@cBody, " bool isNull = false;\n");
push(@callImplParams, "isNull");
}
if ($raisesException) {
push(@cBody, " WebCore::ExceptionCode ec = 0;\n");
push(@callImplParams, "ec");
}
my $functionImplementationName = $function->signature->extendedAttributes->{"ImplementedAs"} || $function->signature->name;
if ($functionHasCustomReturn) {
push(@cBody, " bool ok = item->${functionImplementationName}(" . join(", ", @callImplParams) . ");\n");
my $customNodeAppendChild = << "EOF";
if (ok)
return WebKit::kit($returnParamName);
EOF
push(@cBody, $customNodeAppendChild);
if($raisesException) {
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;\n");
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}::${functionImplementationName}(" . join(", ", @arguments) . "));\n";
} else {
$getterContentHead = "${assign}convertToUTF8String(item->${functionImplementationName}(" . 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}::${functionImplementationName}(" . join(", ", @arguments) . "${assignPost});\n";
} else {
$contentHead = "${assign}${assignPre}item->${functionImplementationName}(" . join(", ", @arguments) . "${assignPost});\n";
}
}
push(@cBody, " ${contentHead}");
if($raisesException) {
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 "any") {
if ($returnValueIsGDOMType) {
push(@cBody, " return WebKit::kit(gobjectResult.get());\n");
} else {
push(@cBody, " return result;\n");
}
} else {
push(@cBody, " return 0; // TODO: return canvas object\n");
}
}
if ($conditionalString) {
push(@cBody, "#else\n");
push(@cBody, " UNUSED_PARAM(self);\n");
foreach my $param (@{$function->parameters}) {
push(@cBody, " UNUSED_PARAM(" . $param->name . ");\n");
}
push(@cBody, " UNUSED_PARAM(error);\n") if $raisesException;
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, " UNUSED_PARAM(self);\n");
foreach my $param (@{$function->parameters}) {
push(@cBody, " UNUSED_PARAM(" . $param->name . ");\n");
}
push(@cBody, " UNUSED_PARAM(error);\n") if $raisesException;
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, $interface) = @_;
foreach my $function (@{$interface->functions}) {
$object->GenerateFunction($interfaceName, $function, "", $interface);
}
TOP:
foreach my $attribute (@{$interface->attributes}) {
if (SkipAttribute($attribute)) {
next TOP;
}
my $attrNameUpper = $codeGenerator->WK_ucfirst($attribute->signature->name);
my $getname = "get${attrNameUpper}";
my $setname = "set${attrNameUpper}";
if (ClassHasFunction($interface, $getname) || ClassHasFunction($interface, $setname)) {
next TOP;
}
my $function = new domFunction();
$function->signature($attribute->signature);
$function->signature->extendedAttributes({%{$attribute->signature->extendedAttributes}});
if ($attribute->signature->extendedAttributes->{"GetterRaisesException"}) {
$function->signature->extendedAttributes->{"RaisesException"} = "VALUE_IS_MISSING";
}
$object->GenerateFunction($interfaceName, $function, "get_", $interface);
my $custom = $attribute->signature->extendedAttributes->{"CustomSetter"};
if ($attribute->isReadOnly || $attribute->signature->extendedAttributes->{"Replaceable"} || $custom) {
next TOP;
}
$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);
if ($attribute->signature->extendedAttributes->{"SetterRaisesException"}) {
$function->signature->extendedAttributes->{"RaisesException"} = "VALUE_IS_MISSING";
} else {
delete $function->signature->extendedAttributes->{"RaisesException"};
}
$object->GenerateFunction($interfaceName, $function, "set_", $interface);
}
}
sub GenerateCFile {
my ($object, $interfaceName, $parentClassName, $parentGObjType, $interface) = @_;
if ($interface->extendedAttributes->{"EventTarget"}) {
$object->GenerateEventTargetIface($interface);
}
my $implContent = "";
my $decamelize = decamelize($interfaceName);
my $clsCaps = uc($decamelize);
my $lowerCaseIfaceName = "webkit_dom_$decamelize";
my $parentImplClassName = GetParentImplClassName($interface);
my $baseClassName = GetBaseClass($parentImplClassName, $interface);
if ($parentImplClassName eq "Object") {
my $conditionalString = $codeGenerator->GenerateConditionalString($interface);
push(@cStructPriv, "#define WEBKIT_DOM_${clsCaps}_GET_PRIVATE(obj) G_TYPE_INSTANCE_GET_PRIVATE(obj, WEBKIT_DOM_TYPE_${clsCaps}, ${className}Private)\n\n");
push(@cStructPriv, "typedef struct _${className}Private {\n");
push(@cStructPriv, "#if ${conditionalString}\n") if $conditionalString;
push(@cStructPriv, " RefPtr<WebCore::${interfaceName}> coreObject;\n");
push(@cStructPriv, "#endif // ${conditionalString}\n") if $conditionalString;
push(@cStructPriv, "} ${className}Private;\n\n");
}
$implContent = << "EOF";
${defineTypeMacro}(${className}, ${lowerCaseIfaceName}, ${parentGObjType}${defineTypeInterfaceImplementation}
EOF
push(@cBodyProperties, $implContent);
if ($parentImplClassName eq "Object") {
push(@cBodyPriv, "${className}* kit(WebCore::$interfaceName* obj)\n");
push(@cBodyPriv, "{\n");
push(@cBodyPriv, " if (!obj)\n");
push(@cBodyPriv, " return 0;\n\n");
push(@cBodyPriv, " if (gpointer ret = DOMObjectCache::get(obj))\n");
push(@cBodyPriv, " return WEBKIT_DOM_${clsCaps}(ret);\n\n");
if (IsPolymorphic($interfaceName)) {
push(@cBodyPriv, " return wrap(obj);\n");
} else {
push(@cBodyPriv, " return wrap${interfaceName}(obj);\n");
}
push(@cBodyPriv, "}\n\n");
} else {
push(@cBodyPriv, "${className}* kit(WebCore::$interfaceName* obj)\n");
push(@cBodyPriv, "{\n");
if (!IsPolymorphic($baseClassName)) {
push(@cBodyPriv, " if (!obj)\n");
push(@cBodyPriv, " return 0;\n\n");
push(@cBodyPriv, " if (gpointer ret = DOMObjectCache::get(obj))\n");
push(@cBodyPriv, " return WEBKIT_DOM_${clsCaps}(ret);\n\n");
push(@cBodyPriv, " return wrap${interfaceName}(obj);\n");
} else {
push(@cBodyPriv, " return WEBKIT_DOM_${clsCaps}(kit(static_cast<WebCore::$baseClassName*>(obj)));\n");
}
push(@cBodyPriv, "}\n\n");
}
$implContent = << "EOF";
WebCore::${interfaceName}* core(${className}* request)
{
return request ? static_cast<WebCore::${interfaceName}*>(WEBKIT_DOM_OBJECT(request)->coreObject) : 0;
}
${className}* wrap${interfaceName}(WebCore::${interfaceName}* coreObject)
{
ASSERT(coreObject);
return WEBKIT_DOM_${clsCaps}(g_object_new(WEBKIT_DOM_TYPE_${clsCaps}, "core-object", coreObject, nullptr));
}
EOF
push(@cBodyPriv, $implContent);
$object->GenerateProperties($interfaceName, $interface);
$object->GenerateFunctions($interfaceName, $interface);
}
sub GenerateEndHeader {
my ($object) = @_;
my $isStableClass = scalar(@stableSymbols);
if (!$isStableClass) {
push(@hPrefixGuardEnd, "#endif /* WEBKIT_DOM_USE_UNSTABLE_API */\n");
}
my $guard = $className . "_h";
push(@hBody, "G_END_DECLS\n\n");
push(@hPrefixGuardEnd, "#endif /* $guard */\n");
}
sub IsPolymorphic {
my $type = shift;
return scalar(grep {$_ eq $type} qw(Blob Event HTMLCollection Node StyleSheet TextTrackCue));
}
sub GenerateEventTargetIface {
my $object = shift;
my $interface = shift;
my $interfaceName = $interface->name;
my $decamelize = decamelize($interfaceName);
my $conditionalString = $codeGenerator->GenerateConditionalString($interface);
my @conditionalWarn = GenerateConditionalWarning($interface);
$implIncludes{"GObjectEventListener.h"} = 1;
$implIncludes{"WebKitDOMEventTarget.h"} = 1;
$implIncludes{"WebKitDOMEventPrivate.h"} = 1;
push(@cBodyProperties, "static gboolean webkit_dom_${decamelize}_dispatch_event(WebKitDOMEventTarget* target, WebKitDOMEvent* event, GError** error)\n{\n");
push(@cBodyProperties, "#if ${conditionalString}\n") if $conditionalString;
push(@cBodyProperties, " WebCore::Event* coreEvent = WebKit::core(event);\n");
push(@cBodyProperties, " WebCore::${interfaceName}* coreTarget = static_cast<WebCore::${interfaceName}*>(WEBKIT_DOM_OBJECT(target)->coreObject);\n\n");
push(@cBodyProperties, " WebCore::ExceptionCode ec = 0;\n");
push(@cBodyProperties, " gboolean result = coreTarget->dispatchEvent(coreEvent, ec);\n");
push(@cBodyProperties, " if (ec) {\n WebCore::ExceptionCodeDescription description(ec);\n");
push(@cBodyProperties, " g_set_error_literal(error, g_quark_from_string(\"WEBKIT_DOM\"), description.code, description.name);\n }\n");
push(@cBodyProperties, " return result;\n");
if ($conditionalString) {
push(@cBodyProperties, "#else\n");
push(@cBodyProperties, " UNUSED_PARAM(target);\n");
push(@cBodyProperties, " UNUSED_PARAM(event);\n");
push(@cBodyProperties, " UNUSED_PARAM(error);\n");
push(@cBodyProperties, @conditionalWarn) if scalar(@conditionalWarn);
push(@cBodyProperties, " return false;\n#endif // ${conditionalString}\n");
}
push(@cBodyProperties, "}\n\n");
push(@cBodyProperties, "static gboolean webkit_dom_${decamelize}_add_event_listener(WebKitDOMEventTarget* target, const char* eventName, GClosure* handler, gboolean useCapture)\n{\n");
push(@cBodyProperties, "#if ${conditionalString}\n") if $conditionalString;
push(@cBodyProperties, " WebCore::${interfaceName}* coreTarget = static_cast<WebCore::${interfaceName}*>(WEBKIT_DOM_OBJECT(target)->coreObject);\n");
push(@cBodyProperties, " return WebCore::GObjectEventListener::addEventListener(G_OBJECT(target), coreTarget, eventName, handler, useCapture);\n");
if ($conditionalString) {
push(@cBodyProperties, "#else\n");
push(@cBodyProperties, " UNUSED_PARAM(target);\n");
push(@cBodyProperties, " UNUSED_PARAM(eventName);\n");
push(@cBodyProperties, " UNUSED_PARAM(handler);\n");
push(@cBodyProperties, " UNUSED_PARAM(useCapture);\n");
push(@cBodyProperties, @conditionalWarn) if scalar(@conditionalWarn);
push(@cBodyProperties, " return false;\n#endif // ${conditionalString}\n");
}
push(@cBodyProperties, "}\n\n");
push(@cBodyProperties, "static gboolean webkit_dom_${decamelize}_remove_event_listener(WebKitDOMEventTarget* target, const char* eventName, GClosure* handler, gboolean useCapture)\n{\n");
push(@cBodyProperties, "#if ${conditionalString}\n") if $conditionalString;
push(@cBodyProperties, " WebCore::${interfaceName}* coreTarget = static_cast<WebCore::${interfaceName}*>(WEBKIT_DOM_OBJECT(target)->coreObject);\n");
push(@cBodyProperties, " return WebCore::GObjectEventListener::removeEventListener(G_OBJECT(target), coreTarget, eventName, handler, useCapture);\n");
if ($conditionalString) {
push(@cBodyProperties, "#else\n");
push(@cBodyProperties, " UNUSED_PARAM(target);\n");
push(@cBodyProperties, " UNUSED_PARAM(eventName);\n");
push(@cBodyProperties, " UNUSED_PARAM(handler);\n");
push(@cBodyProperties, " UNUSED_PARAM(useCapture);\n");
push(@cBodyProperties, @conditionalWarn) if scalar(@conditionalWarn);
push(@cBodyProperties, " return false;\n#endif // ${conditionalString}\n");
}
push(@cBodyProperties, "}\n\n");
push(@cBodyProperties, "static void webkit_dom_event_target_init(WebKitDOMEventTargetIface* iface)\n{\n");
push(@cBodyProperties, " iface->dispatch_event = webkit_dom_${decamelize}_dispatch_event;\n");
push(@cBodyProperties, " iface->add_event_listener = webkit_dom_${decamelize}_add_event_listener;\n");
push(@cBodyProperties, " iface->remove_event_listener = webkit_dom_${decamelize}_remove_event_listener;\n}\n\n");
$defineTypeMacro = "G_DEFINE_TYPE_WITH_CODE";
$defineTypeInterfaceImplementation = ", G_IMPLEMENT_INTERFACE(WEBKIT_DOM_TYPE_EVENT_TARGET, webkit_dom_event_target_init))";
}
sub Generate {
my ($object, $interface) = @_;
my $parentClassName = GetParentClassName($interface);
my $parentGObjType = GetParentGObjType($interface);
my $interfaceName = $interface->name;
my $parentImplClassName = GetParentImplClassName($interface);
my $baseClassName = GetBaseClass($parentImplClassName, $interface);
@cPrefix = split("\r", $licenceTemplate);
push(@cPrefix, "\n");
$implIncludes{"DOMObjectCache.h"} = 1;
$implIncludes{"WebKitDOMPrivate.h"} = 1;
$implIncludes{"gobject/ConvertToUTF8String.h"} = 1;
$implIncludes{"${className}Private.h"} = 1;
$implIncludes{"Document.h"} = 1;
$implIncludes{"JSMainThreadExecState.h"} = 1;
$implIncludes{"ExceptionCode.h"} = 1;
$implIncludes{"CSSImportRule.h"} = 1;
if ($parentImplClassName ne "Object" and IsPolymorphic($baseClassName)) {
$implIncludes{"WebKitDOM${baseClassName}Private.h"} = 1;
}
$hdrIncludes{"webkitdom/${parentClassName}.h"} = 1;
$object->GenerateHeader($interfaceName, $parentClassName, $interface);
$object->GenerateCFile($interfaceName, $parentClassName, $parentGObjType, $interface);
$object->GenerateEndHeader();
}
sub WriteData {
my $object = shift;
my $interface = shift;
my $outputDir = shift;
mkdir $outputDir;
my $isStableClass = scalar(@stableSymbols);
my $interfaceName = $interface->name;
my $filename = "$outputDir/" . $className . "Private.h";
my $guard = "${className}Private_h";
my $conditionalString = $codeGenerator->GenerateConditionalString($interface);
open(PRIVHEADER, ">$filename") or die "Couldn't open file $filename for writing";
print PRIVHEADER split("\r", $licenceTemplate);
print PRIVHEADER "\n";
my $text = << "EOF";
EOF
print PRIVHEADER $text;
print PRIVHEADER "#if ${conditionalString}\n" if $conditionalString;
print PRIVHEADER "\n";
$text = << "EOF";
namespace WebKit {
${className}* wrap${interfaceName}(WebCore::${interfaceName}*);
${className}* kit(WebCore::${interfaceName}*);
WebCore::${interfaceName}* core(${className}*);
EOF
print PRIVHEADER $text;
$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;
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);
if ($isStableClass) {
print HEADER "#include <webkitdom/webkitdomdefines.h>\n\n";
} else {
print HEADER "#include <webkitdom/webkitdomdefines-unstable.h>\n\n";
}
print HEADER @hBodyPre;
print HEADER @hBody;
print HEADER @hPrefixGuardEnd;
close(HEADER);
if ($isStableClass and scalar(@hBodyUnstable)) {
my $fullUnstableHeaderFilename = "$outputDir/" . $className . "Unstable.h";
open(UNSTABLE, ">$fullUnstableHeaderFilename") or die "Couldn't open file $fullUnstableHeaderFilename";
print UNSTABLE split("\r", $licenceTemplate);
print UNSTABLE "\n";
$guard = "${className}Unstable_h";
$text = << "EOF";
EOF
print UNSTABLE $text;
print UNSTABLE "\n";
print UNSTABLE "#if ${conditionalString}\n\n" if $conditionalString;
print UNSTABLE "G_BEGIN_DECLS\n";
print UNSTABLE "\n";
print UNSTABLE @hBodyUnstable;
print UNSTABLE "\n";
print UNSTABLE "G_END_DECLS\n";
print UNSTABLE "\n";
print UNSTABLE "#endif /* ${conditionalString} */\n\n" if $conditionalString;
print UNSTABLE "#endif /* WEBKIT_DOM_USE_UNSTABLE_API */\n";
print UNSTABLE "#endif /* ${guard} */\n";
close(UNSTABLE);
}
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";
%includesCopy = %implIncludes;
print IMPL map { "#include \"$_\"\n" } sort keys(%includesCopy);
if ($isStableClass and scalar(@hBodyUnstable)) {
print IMPL "#include \"${className}Unstable.h\"\n";
}
print IMPL "#include <wtf/GetPtr.h>\n";
print IMPL "#include <wtf/RefPtr.h>\n\n";
print IMPL @cStructPriv;
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);
if ($isStableClass) {
my $symbolsFileName = "$outputDir/" . $basename . ".symbols";
open(SYM, ">$symbolsFileName") or die "Couldn't open file $symbolsFileName";
print SYM @symbols;
close(SYM);
}
%implIncludes = ();
%hdrIncludes = ();
@hPrefix = ();
@hBody = ();
@hBodyUnstable = ();
@cPrefix = ();
@cBody = ();
@cBodyPriv = ();
@cBodyProperties = ();
@cStructPriv = ();
@symbols = ();
@stableSymbols = ();
}
sub IsInterfaceSymbol {
my ($line, $lowerCaseIfaceName) = @_;
return 1 if $line =~ /^[a-zA-Z0-9\*]+\s${lowerCaseIfaceName}_.+$/;
my $prefix = uc($lowerCaseIfaceName);
return 1 if $line =~ /^${prefix}_[A-Z_]+$/;
return 0;
}
sub ReadStableSymbols {
my $interfaceName = shift;
@stableSymbols = ();
my $bindingsDir = dirname($FindBin::Bin);
my $fileName = "$bindingsDir/gobject/webkitdom.symbols";
open FILE, "<", $fileName or die "Could not open $fileName";
my @lines = <FILE>;
close FILE;
my $decamelize = decamelize($interfaceName);
my $lowerCaseIfaceName = "webkit_dom_$decamelize";
foreach $line (@lines) {
$line =~ s/\n$//;
if ($line eq "GType ${lowerCaseIfaceName}_get_type(void)") {
push(@stableSymbols, $line);
next;
}
if (scalar(@stableSymbols) and IsInterfaceSymbol($line, $lowerCaseIfaceName) and $line !~ /^GType/) {
push(@stableSymbols, $line);
next;
}
if (scalar(@stableSymbols) and $line !~ /^GType/) {
warn "Symbol %line found, but a get_type was expected";
}
last if scalar(@stableSymbols);
}
}
sub GenerateInterface {
my ($object, $interface, $defines) = @_;
$className = GetClassName($interface->name);
ReadStableSymbols($interface->name);
$object->Generate($interface);
}
1;