| # 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; |