diff options
Diffstat (limited to 'WebCore/bindings/scripts/CodeGeneratorCOM.pm')
-rw-r--r-- | WebCore/bindings/scripts/CodeGeneratorCOM.pm | 1313 |
1 files changed, 1313 insertions, 0 deletions
diff --git a/WebCore/bindings/scripts/CodeGeneratorCOM.pm b/WebCore/bindings/scripts/CodeGeneratorCOM.pm new file mode 100644 index 0000000..f2b1cdd --- /dev/null +++ b/WebCore/bindings/scripts/CodeGeneratorCOM.pm @@ -0,0 +1,1313 @@ +# +# Copyright (C) 2005, 2006 Nikolas Zimmermann <zimmermann@kde.org> +# Copyright (C) 2006 Anders Carlsson <andersca@mac.com> +# Copyright (C) 2006, 2007 Samuel Weinig <sam@webkit.org> +# Copyright (C) 2006 Alexey Proskuryakov <ap@webkit.org> +# Copyright (C) 2006, 2007 Apple Inc. All rights reserved. +# +# 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 +# aint 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 CodeGeneratorCOM; + +use File::stat; + +# Global Variables +my $module = ""; +my $outputDir = ""; + +my @IDLHeader = (); +my @IDLContent = (); +my %IDLIncludes = (); +my %IDLForwardDeclarations = (); +my %IDLDontForwardDeclare = (); +my %IDLImports = (); +my %IDLDontImport = (); + +my @CPPInterfaceHeader = (); + +my @CPPHeaderHeader = (); +my @CPPHeaderContent = (); +my %CPPHeaderIncludes = (); +my %CPPHeaderIncludesAngle = (); +my %CPPHeaderForwardDeclarations = (); +my %CPPHeaderDontForwardDeclarations = (); + +my @CPPImplementationHeader = (); +my @CPPImplementationContent = (); +my %CPPImplementationIncludes = (); +my %CPPImplementationWebCoreIncludes = (); +my %CPPImplementationIncludesAngle = (); +my %CPPImplementationDontIncludes = (); + +my @additionalInterfaceDefinitions = (); + +my $DASHES = "----------------------------------------"; +my $TEMP_PREFIX = "GEN_"; + +# Hashes + +my %includeCorrector = map {($_, 1)} qw{UIEvent KeyboardEvent MouseEvent + MutationEvent OverflowEvent WheelEvent}; + +my %conflictMethod = ( + # FIXME: Add C language keywords? +); + +# Default License Templates +my @licenseTemplate = split(/\r/, << "EOF"); +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +EOF + +# Default constructor +sub new +{ + my $object = shift; + my $reference = { }; + + $codeGenerator = shift; + $outputDir = shift; + + bless($reference, $object); + return $reference; +} + +sub finish +{ + my $object = shift; +} + +# Params: 'domClass' struct +sub GenerateInterface +{ + my $object = shift; + my $dataNode = shift; + my $defines = shift; + + my $name = $dataNode->name; + + my $pureInterface = $dataNode->extendedAttributes->{"PureInterface"}; + + # Start actual generation.. + $object->GenerateIDL($dataNode, $pureInterface); + if ($pureInterface) { + $object->GenerateInterfaceHeader($dataNode); + } else { + $object->GenerateCPPHeader($dataNode); + $object->GenerateCPPImplementation($dataNode); + } + + # Write changes. + $object->WriteData($name, $pureInterface); +} + +# Params: 'idlDocument' struct +sub GenerateModule +{ + my $object = shift; + my $dataNode = shift; + + $module = $dataNode->module; +} + +sub GetInterfaceName +{ + my $name = $codeGenerator->StripModule(shift); + + die "GetInterfaceName should only be used on interfaces." if ($codeGenerator->IsStringType($name) or $codeGenerator->IsPrimitiveType($name)); + + # special cases + return "I" . $TEMP_PREFIX . "DOMAbstractView" if $name eq "DOMWindow"; + return "I" . $TEMP_PREFIX . $name if $name eq "DOMImplementation" or $name eq "DOMTimeStamp"; + + # Default, assume COM type has the same type name as + # idl type prefixed with "IDOM". + return "I" . $TEMP_PREFIX . "DOM" . $name; +} + +sub GetClassName +{ + my $name = $codeGenerator->StripModule(shift); + + # special cases + return "BSTR" if $codeGenerator->IsStringType($name); + return "BOOL" if $name eq "boolean"; + return "unsigned" if $name eq "unsigned long"; + return "int" if $name eq "long"; + return $name if $codeGenerator->IsPrimitiveType($name); + return $TEMP_PREFIX . "DOMAbstractView" if $name eq "DOMWindow"; + return $TEMP_PREFIX . $name if $name eq "DOMImplementation" or $name eq "DOMTimeStamp"; + + # Default, assume COM type has the same type name as + # idl type prefixed with "DOM". + return $TEMP_PREFIX . "DOM" . $name; +} + +sub GetCOMType +{ + my ($type) = @_; + + die "Don't use GetCOMType for string types, use one of In/Out variants instead." if $codeGenerator->IsStringType($type); + + return "BOOL" if $type eq "boolean"; + return "UINT" if $type eq "unsigned long"; + return "INT" if $type eq "long"; + return $type if $codeGenerator->IsPrimitiveType($type) or $type eq "DOMTimeStamp"; + # return "unsigned short" if $type eq "CompareHow" or $type eq "SVGPaintType"; + + return GetInterfaceName($type) . "*"; +} + +sub GetCOMTypeIn +{ + my ($type) = @_; + return "LPCTSTR" if $codeGenerator->IsStringType($type); + return GetCOMType($type); +} + +sub GetCOMTypeOut +{ + my ($type) = @_; + return "BSTR" if $codeGenerator->IsStringType($type); + return GetCOMType($type); +} + +sub IDLTypeToImplementationType +{ + my $type = $codeGenerator->StripModule(shift); + + return "bool" if $type eq "boolean"; + return "unsigned" if $type eq "unsigned long"; + return "int" if $type eq "long"; + return $type if $codeGenerator->IsPrimitiveType($type); + + return "WebCore::String" if $codeGenerator->IsStringType($type); + return "WebCore::${type}"; +} + +sub StripNamespace +{ + my ($type) = @_; + + $type =~ s/^WebCore:://; + + return $type; +} + +sub GetParentInterface +{ + my ($dataNode) = @_; + return "I" . $TEMP_PREFIX . "DOMObject" if (@{$dataNode->parents} == 0); + return "I" . $TEMP_PREFIX . "DOMNode" if $codeGenerator->StripModule($dataNode->parents(0)) eq "EventTargetNode"; + return GetInterfaceName($codeGenerator->StripModule($dataNode->parents(0))); +} + +sub GetParentClass +{ + my ($dataNode) = @_; + return $TEMP_PREFIX . "DOMObject" if (@{$dataNode->parents} == 0); + return $TEMP_PREFIX . "DOMNode" if $codeGenerator->StripModule($dataNode->parents(0)) eq "EventTargetNode"; + return GetClassName($codeGenerator->StripModule($dataNode->parents(0))); +} + +sub AddForwardDeclarationsForTypeInIDL +{ + my $type = $codeGenerator->StripModule(shift); + + return if $codeGenerator->IsNonPointerType($type) or $codeGenerator->IsStringType($type); + + my $interface = GetInterfaceName($type); + $IDLForwardDeclarations{$interface} = 1; + $IDLImports{$interface} = 1; +} + +sub AddIncludesForTypeInCPPHeader +{ + my $type = $codeGenerator->StripModule(shift); + my $useAngleBrackets = shift; + + return if $codeGenerator->IsNonPointerType($type); + + # Add special Cases HERE + + if ($type =~ m/^I/) { + $type = "WebKit"; + } + + if ($useAngleBrackets) { + $CPPHeaderIncludesAngle{"$type.h"} = 1; + return; + } + + if ($type eq "GEN_DOMImplementation") { + $CPPHeaderIncludes{"GEN_DOMDOMImplementation.h"} = 1; + return; + } + + if ($type eq "IGEN_DOMImplementation") { + $CPPHeaderIncludes{"IGEN_DOMDOMImplementation.h"} = 1; + return; + } + + $CPPHeaderIncludes{"$type.h"} = 1; +} + +sub AddForwardDeclarationsForTypeInCPPHeader +{ + my $type = $codeGenerator->StripModule(shift); + + return if $codeGenerator->IsNonPointerType($type) or $codeGenerator->IsStringType($type); + + my $interface = GetInterfaceName($type); + $CPPHeaderForwardDeclarations{$interface} = 1; +} + +sub AddIncludesForTypeInCPPImplementation +{ + my $type = $codeGenerator->StripModule(shift); + + die "Include type not supported!" if $includeCorrector{$type}; + + return if $codeGenerator->IsNonPointerType($type); + + if ($codeGenerator->IsStringType($type)) { + $CPPImplementationWebCoreIncludes{"AtomicString.h"} = 1; + $CPPImplementationWebCoreIncludes{"BString.h"} = 1; + $CPPImplementationWebCoreIncludes{"KURL.h"} = 1; + return; + } + + # Special casing + $CPPImplementationWebCoreIncludes{"EventTargetNode.h"} = 1 if $type eq "Node"; + $CPPImplementationWebCoreIncludes{"NameNodeList.h"} = 1 if $type eq "NodeList"; + $CPPImplementationWebCoreIncludes{"CSSMutableStyleDeclaration.h"} = 1 if $type eq "CSSStyleDeclaration"; + + # Add implementation type + $CPPImplementationWebCoreIncludes{StripNamespace(IDLTypeToImplementationType($type)) . ".h"} = 1; + + my $COMClassName = GetClassName($type); + $CPPImplementationIncludes{"${COMClassName}.h"} = 1; +} + +sub GetAdditionalInterfaces +{ + my $type = $codeGenerator->StripModule(shift); + + return ("EventTarget") if $type eq "Node"; + return (); +} + +sub GenerateIDL +{ + my ($object, $dataNode, $pureInterface) = @_; + + my $inInterfaceName = $dataNode->name; + my $outInterfaceName = GetInterfaceName($inInterfaceName); + my $uuid = $dataNode->extendedAttributes->{"InterfaceUUID"} || die "All classes require an InterfaceUUID extended attribute."; + + my $parentInterfaceName = ($pureInterface) ? "IUnknown" : GetParentInterface($dataNode); + + my $numConstants = @{$dataNode->constants}; + my $numAttributes = @{$dataNode->attributes}; + my $numFunctions = @{$dataNode->functions}; + + # - Add default header template + @IDLHeader = @licenseTemplate; + push(@IDLHeader, "\n"); + + # - INCLUDES - + push(@IDLHeader, "#ifndef DO_NO_IMPORTS\n"); + push(@IDLHeader, "import \"oaidl.idl\";\n"); + push(@IDLHeader, "import \"ocidl.idl\";\n"); + push(@IDLHeader, "#endif\n\n"); + + unless ($pureInterface) { + push(@IDLHeader, "#ifndef DO_NO_IMPORTS\n"); + push(@IDLHeader, "import \"${parentInterfaceName}.idl\";\n"); + push(@IDLHeader, "#endif\n\n"); + + $IDLDontForwardDeclare{$outInterfaceName} = 1; + $IDLDontImport{$outInterfaceName} = 1; + $IDLDontForwardDeclare{$parentInterfaceName} = 1; + $IDLDontImport{$parentInterfaceName} = 1; + } + + # - Begin + # -- Attributes + push(@IDLContent, "[\n"); + push(@IDLContent, " object,\n"); + push(@IDLContent, " oleautomation,\n"); + push(@IDLContent, " uuid(" . $uuid . "),\n"); + push(@IDLContent, " pointer_default(unique)\n"); + push(@IDLContent, "]\n"); + + # -- Interface + push(@IDLContent, "interface " . $outInterfaceName . " : " . $parentInterfaceName . "\n"); + push(@IDLContent, "{\n"); + + + # - FIXME: Add constants. + + + # - Add attribute getters/setters. + if ($numAttributes > 0) { + foreach my $attribute (@{$dataNode->attributes}) { + my $attributeName = $attribute->signature->name; + my $attributeIDLType = $attribute->signature->type; + my $attributeTypeIn = GetCOMTypeIn($attributeIDLType); + my $attributeTypeOut = GetCOMTypeOut($attributeIDLType); + my $attributeIsReadonly = ($attribute->type =~ /^readonly/); + + AddForwardDeclarationsForTypeInIDL($attributeIDLType); + + unless ($attributeIsReadonly) { + # Setter + my $setterName = "set" . $codeGenerator->WK_ucfirst($attributeName); + my $setter = " HRESULT " . $setterName . "([in] " . $attributeTypeIn . ");\n"; + push(@IDLContent, $setter); + } + + # Getter + my $getter = " HRESULT " . $attributeName . "([out, retval] " . $attributeTypeOut . "*);\n\n"; + push(@IDLContent, $getter); + } + } + + # - Add functions. + if ($numFunctions > 0) { + foreach my $function (@{$dataNode->functions}) { + my $functionName = $function->signature->name; + my $returnIDLType = $function->signature->type; + my $returnType = GetCOMTypeOut($returnIDLType); + my $noReturn = ($returnType eq "void"); + + AddForwardDeclarationsForTypeInIDL($returnIDLType); + + my @paramArgList = (); + foreach my $param (@{$function->parameters}) { + my $paramName = $param->name; + my $paramIDLType = $param->type; + my $paramType = GetCOMTypeIn($param->type); + + AddForwardDeclarationsForTypeInIDL($paramIDLType); + + # Form parameter + my $parameter = "[in] ${paramType} ${paramName}"; + + # Add parameter to function signature + push(@paramArgList, $parameter); + } + + unless ($noReturn) { + my $resultParameter = "[out, retval] " . $returnType . "* result"; + push(@paramArgList, $resultParameter); + } + + my $functionSig = " HRESULT " . $functionName . "("; + $functionSig .= join(", ", @paramArgList); + $functionSig .= ");\n\n"; + push(@IDLContent, $functionSig); + } + } + + # - End + push(@IDLContent, "}\n\n"); +} + +sub GenerateInterfaceHeader +{ + my ($object, $dataNode) = @_; + + my $IDLType = $dataNode->name; + my $implementationClass = IDLTypeToImplementationType($IDLType); + my $implementationClassWithoutNamespace = StripNamespace($implementationClass); + my $className = GetClassName($IDLType); + my $interfaceName = GetInterfaceName($IDLType); + + # - Add default header template + @CPPInterfaceHeader = @licenseTemplate; + push(@CPPInterfaceHeader, "\n"); + + # - Header gaurds - + push(@CPPInterfaceHeader, "#ifndef " . $className . "_h\n"); + push(@CPPInterfaceHeader, "#define " . $className . "_h\n\n"); + + # - Forward Declarations - + push(@CPPInterfaceHeader, "interface ${interfaceName};\n\n"); + push(@CPPInterfaceHeader, "namespace WebCore {\n"); + push(@CPPInterfaceHeader, " class ${implementationClassWithoutNamespace};\n"); + push(@CPPInterfaceHeader, "}\n\n"); + + # - Default Interface Creator - + push(@CPPInterfaceHeader, "${interfaceName}* to${interfaceName}(${implementationClass}*) { return 0; }\n\n"); + + push(@CPPInterfaceHeader, "#endif // " . $className . "_h\n"); +} + +# ----------------------------------------------------------------------------- +# CPP Helper Functions +# ----------------------------------------------------------------------------- + +sub GenerateCPPAttributeSignature +{ + my ($attribute, $className, $options) = @_; + + my $attributeName = $attribute->signature->name; + my $isReadonly = ($attribute->type =~ /^readonly/); + + my $newline = $$options{"NewLines"} ? "\n" : ""; + my $indent = $$options{"Indent"} ? " " x $$options{"Indent"} : ""; + my $semicolon = $$options{"IncludeSemiColon"} ? ";" : ""; + my $virtual = $$options{"AddVirtualKeyword"} ? "virtual " : ""; + my $class = $$options{"UseClassName"} ? "${className}::" : ""; + my $forwarder = $$options{"Forwarder"} ? 1 : 0; + my $joiner = ($$options{"NewLines"} ? "\n" . $indent . " " : ""); + + my %attributeSignatures = (); + + unless ($isReadonly) { + my $attributeTypeIn = GetCOMTypeIn($attribute->signature->type); + my $setterName = "set" . $codeGenerator->WK_ucfirst($attributeName); + my $setter = $indent . $virtual . "HRESULT STDMETHODCALLTYPE ". $class . $setterName . "("; + $setter .= $joiner . "/* [in] */ ${attributeTypeIn} ${attributeName})" . $semicolon . $newline; + if ($forwarder) { + $setter .= " { return " . $$options{"Forwarder"} . "::" . $setterName . "(${attributeName}); }\n"; + } + $attributeSignatures{"Setter"} = $setter; + } + + my $attributeTypeOut = GetCOMTypeOut($attribute->signature->type); + my $getter = $indent . $virtual . "HRESULT STDMETHODCALLTYPE " . $class . $attributeName . "("; + $getter .= $joiner . "/* [retval][out] */ ${attributeTypeOut}* result)" . $semicolon . $newline; + if ($forwarder) { + $getter .= " { return " . $$options{"Forwarder"} . "::" . $attributeName . "(result); }\n"; + } + $attributeSignatures{"Getter"} = $getter; + + return %attributeSignatures; +} + + +sub GenerateCPPAttribute +{ + my ($attribute, $className, $implementationClass) = @_; + + my $implementationClassWithoutNamespace = StripNamespace($implementationClass); + + my $attributeName = $attribute->signature->name; + my $attributeIDLType = $attribute->signature->type; + my $hasSetterException = @{$attribute->setterExceptions}; + my $hasGetterException = @{$attribute->getterExceptions}; + my $isReadonly = ($attribute->type =~ /^readonly/); + my $attributeTypeIsPrimitive = $codeGenerator->IsPrimitiveType($attributeIDLType); + my $attributeTypeIsString = $codeGenerator->IsStringType($attributeIDLType); + my $attributeImplementationType = IDLTypeToImplementationType($attributeIDLType); + my $attributeImplementationTypeWithoutNamespace = StripNamespace($attributeImplementationType); + my $attributeTypeCOMClassName = GetClassName($attributeIDLType); + + $CPPImplementationWebCoreIncludes{"ExceptionCode.h"} = 1 if $hasSetterException or $hasGetterException; + + my %signatures = GenerateCPPAttributeSignature($attribute, $className, { "NewLines" => 1, + "Indent" => 0, + "IncludeSemiColon" => 0, + "UseClassName" => 1, + "AddVirtualKeyword" => 0 }); + + my %attrbutesToReturn = (); + + unless ($isReadonly) { + my @setterImplementation = (); + push(@setterImplementation, $signatures{"Setter"}); + push(@setterImplementation, "{\n"); + + my $setterName = "set" . $codeGenerator->WK_ucfirst($attributeName); + + my @setterParams = (); + if ($attributeTypeIsString) { + push(@setterParams, $attributeName); + if ($hasSetterException) { + push(@setterImplementation, " WebCore::ExceptionCode ec = 0;\n"); + push(@setterParams, "ec"); + } + } elsif ($attributeTypeIsPrimitive) { + if ($attribute->signature->extendedAttributes->{"ConvertFromString"}) { + push(@setterParams, "WebCore::String::number(${attributeName})"); + } elsif ($attributeIDLType eq "boolean") { + push(@setterParams, "!!${attributeName}"); + } else { + my $primitiveImplementationType = IDLTypeToImplementationType($attributeIDLType); + push(@setterParams, "static_cast<${primitiveImplementationType}>(${attributeName})"); + } + + if ($hasSetterException) { + push(@setterImplementation, " WebCore::ExceptionCode ec = 0;\n"); + push(@setterParams, "ec"); + } + } else { + $CPPImplementationWebCoreIncludes{"COMPtr.h"} = 1; + + push(@setterImplementation, " if (!${attributeName})\n"); + push(@setterImplementation, " return E_POINTER;\n\n"); + push(@setterImplementation, " COMPtr<${attributeTypeCOMClassName}> ptr(Query, ${attributeName});\n"); + push(@setterImplementation, " if (!ptr)\n"); + push(@setterImplementation, " return E_NOINTERFACE;\n"); + + push(@setterParams, "ptr->impl${attributeImplementationTypeWithoutNamespace}()"); + if ($hasSetterException) { + push(@setterImplementation, " WebCore::ExceptionCode ec = 0;\n"); + push(@setterParams, "ec"); + } + } + + # FIXME: CHECK EXCEPTION AND DO SOMETHING WITH IT + + my $setterCall = " impl${implementationClassWithoutNamespace}()->${setterName}(" . join(", ", @setterParams) . ");\n"; + + push(@setterImplementation, $setterCall); + push(@setterImplementation, " return S_OK;\n"); + push(@setterImplementation, "}\n\n"); + + $attrbutesToReturn{"Setter"} = join("", @setterImplementation); + } + + my @getterImplementation = (); + push(@getterImplementation, $signatures{"Getter"}); + push(@getterImplementation, "{\n"); + push(@getterImplementation, " if (!result)\n"); + push(@getterImplementation, " return E_POINTER;\n\n"); + + my $implementationGetter = "impl${implementationClassWithoutNamespace}()->" . $codeGenerator->WK_lcfirst($attributeName) . "(" . ($hasGetterException ? "ec" : ""). ")"; + + push(@getterImplementation, " WebCore::ExceptionCode ec = 0;\n") if $hasGetterException; + + if ($attributeTypeIsString) { + push(@getterImplementation, " *result = WebCore::BString(${implementationGetter}).release();\n"); + } elsif ($attributeTypeIsPrimitive) { + if ($attribute->signature->extendedAttributes->{"ConvertFromString"}) { + push(@getterImplementation, " *result = static_cast<${attributeTypeCOMClassName}>(${implementationGetter}.toInt());\n"); + } else { + push(@getterImplementation, " *result = static_cast<${attributeTypeCOMClassName}>(${implementationGetter});\n"); + } + } else { + $CPPImplementationIncludesAngle{"wtf/GetPtr.h"} = 1; + my $attributeTypeCOMInterfaceName = GetInterfaceName($attributeIDLType); + push(@getterImplementation, " *result = 0;\n"); + push(@getterImplementation, " ${attributeImplementationType}* resultImpl = WTF::getPtr(${implementationGetter});\n"); + push(@getterImplementation, " if (!resultImpl)\n"); + push(@getterImplementation, " return E_POINTER;\n\n"); + push(@getterImplementation, " *result = to${attributeTypeCOMInterfaceName}(resultImpl);\n"); + } + + # FIXME: CHECK EXCEPTION AND DO SOMETHING WITH IT + + push(@getterImplementation, " return S_OK;\n"); + push(@getterImplementation, "}\n\n"); + + $attrbutesToReturn{"Getter"} = join("", @getterImplementation); + + return %attrbutesToReturn; +} + +sub GenerateCPPFunctionSignature +{ + my ($function, $className, $options) = @_; + + my $functionName = $function->signature->name; + my $returnIDLType = $function->signature->type; + my $returnType = GetCOMTypeOut($returnIDLType); + my $noReturn = ($returnType eq "void"); + + my $newline = $$options{"NewLines"} ? "\n" : ""; + my $indent = $$options{"Indent"} ? " " x $$options{"Indent"} : ""; + my $semicolon = $$options{"IncludeSemiColon"} ? ";" : ""; + my $virtual = $$options{"AddVirtualKeyword"} ? "virtual " : ""; + my $class = $$options{"UseClassName"} ? "${className}::" : ""; + my $forwarder = $$options{"Forwarder"} ? 1 : 0; + my $joiner = ($$options{"NewLines"} ? "\n" . $indent . " " : " "); + + my @paramArgList = (); + foreach my $param (@{$function->parameters}) { + my $paramName = $param->name; + my $paramType = GetCOMTypeIn($param->type); + my $parameter = "/* [in] */ ${paramType} ${paramName}"; + push(@paramArgList, $parameter); + } + + unless ($noReturn) { + my $resultParameter .= "/* [out, retval] */ ${returnType}* result"; + push(@paramArgList, $resultParameter); + } + + my $functionSig = $indent . $virtual . "HRESULT STDMETHODCALLTYPE " . $class . $functionName . "("; + $functionSig .= $joiner . join("," . $joiner, @paramArgList) if @paramArgList > 0; + $functionSig .= ")" . $semicolon . $newline; + if ($forwarder) { + my @paramNameList = (); + push(@paramNameList, $_->name) foreach (@{$function->parameters}); + push(@paramNameList, "result") unless $noReturn; + $functionSig .= " { return " . $$options{"Forwarder"} . "::" . $functionName . "(" . join(", ", @paramNameList) . "); }\n"; + } + + return $functionSig +} + +sub GenerateCPPFunction +{ + my ($function, $className, $implementationClass) = @_; + + my @functionImplementation = (); + + my $signature = GenerateCPPFunctionSignature($function, $className, { "NewLines" => 1, + "Indent" => 0, + "IncludeSemiColon" => 0, + "UseClassName" => 1, + "AddVirtualKeyword" => 0 }); + + my $implementationClassWithoutNamespace = StripNamespace($implementationClass); + + my $functionName = $function->signature->name; + my $returnIDLType = $function->signature->type; + my $noReturn = ($returnIDLType eq "void"); + my $requiresEventTargetNodeCast = $function->signature->extendedAttributes->{"EventTargetNodeCast"}; + my $raisesExceptions = @{$function->raisesExceptions}; + + AddIncludesForTypeInCPPImplementation($returnIDLType); + $CPPImplementationWebCoreIncludes{"ExceptionCode.h"} = 1 if $raisesExceptions; + + my %needsCustom = (); + my @parameterInitialization = (); + my @parameterList = (); + foreach my $param (@{$function->parameters}) { + my $paramName = $param->name; + my $paramIDLType = $param->type; + + my $paramTypeIsPrimitive = $codeGenerator->IsPrimitiveType($paramIDLType); + my $paramTypeIsString = $codeGenerator->IsStringType($paramIDLType); + + $needsCustom{"NodeToReturn"} = $paramName if $param->extendedAttributes->{"Return"}; + + AddIncludesForTypeInCPPImplementation($paramIDLType); + + # FIXME: We may need to null check the arguments as well + + if ($paramTypeIsString) { + push(@parameterList, $paramName); + } elsif ($paramTypeIsPrimitive) { + if ($paramIDLType eq "boolean") { + push(@parameterList, "!!${paramName}"); + } else { + my $primitiveImplementationType = IDLTypeToImplementationType($paramIDLType); + push(@parameterList, "static_cast<${primitiveImplementationType}>(${paramName})"); + } + } else { + $CPPImplementationWebCoreIncludes{"COMPtr.h"} = 1; + + $needsCustom{"CanReturnEarly"} = 1; + + my $paramTypeCOMClassName = GetClassName($paramIDLType); + my $paramTypeImplementationWithoutNamespace = StripNamespace(IDLTypeToImplementationType($paramIDLType)); + my $ptrName = "ptrFor" . $codeGenerator->WK_ucfirst($paramName); + my $paramInit = " COMPtr<${paramTypeCOMClassName}> ${ptrName}(Query, ${paramName});\n"; + $paramInit .= " if (!${ptrName})\n"; + $paramInit .= " return E_NOINTERFACE;"; + push(@parameterInitialization, $paramInit); + push(@parameterList, "${ptrName}->impl${paramTypeImplementationWithoutNamespace}()"); + } + } + + push(@parameterList, "ec") if $raisesExceptions; + + my $implementationGetter = "impl${implementationClassWithoutNamespace}()"; + if ($requiresEventTargetNodeCast) { + $implementationGetter = "WebCore::EventTargetNodeCast(${implementationGetter})"; + } + + my $callSigBegin = " "; + my $callSigMiddle = "${implementationGetter}->" . $codeGenerator->WK_lcfirst($functionName) . "(" . join(", ", @parameterList) . ")"; + my $callSigEnd = ";\n"; + + if (defined $needsCustom{"NodeToReturn"}) { + my $nodeToReturn = $needsCustom{"NodeToReturn"}; + $callSigBegin .= "if ("; + $callSigEnd = ")\n"; + $callSigEnd .= " *result = ${nodeToReturn};"; + } elsif (!$noReturn) { + my $returnTypeIsString = $codeGenerator->IsStringType($returnIDLType); + my $returnTypeIsPrimitive = $codeGenerator->IsPrimitiveType($returnIDLType); + + if ($returnTypeIsString) { + $callSigBegin .= "*result = WebCore::BString("; + $callSigEnd = ").release();\n"; + } elsif ($returnTypeIsPrimitive) { + my $primitiveCOMType = GetClassName($returnIDLType); + $callSigBegin .= "*result = static_cast<${primitiveCOMType}>("; + $callSigEnd = ");"; + } else { + $CPPImplementationIncludesAngle{"wtf/GetPtr.h"} = 1; + my $returnImplementationType = IDLTypeToImplementationType($returnIDLType); + my $returnTypeCOMInterfaceName = GetInterfaceName($returnIDLType); + $callSigBegin .= "${returnImplementationType}* resultImpl = WTF::getPtr("; + $callSigEnd = ");\n"; + $callSigEnd .= " if (!resultImpl)\n"; + $callSigEnd .= " return E_POINTER;\n\n"; + $callSigEnd .= " *result = to${returnTypeCOMInterfaceName}(resultImpl);"; + } + } + + push(@functionImplementation, $signature); + push(@functionImplementation, "{\n"); + unless ($noReturn) { + push(@functionImplementation, " if (!result)\n"); + push(@functionImplementation, " return E_POINTER;\n\n"); + push(@functionImplementation, " *result = 0;\n\n") if $needsCustom{"CanReturnEarly"}; + } + push(@functionImplementation, " WebCore::ExceptionCode ec = 0;\n") if $raisesExceptions; # FIXME: CHECK EXCEPTION AND DO SOMETHING WITH IT + push(@functionImplementation, join("\n", @parameterInitialization) . (@parameterInitialization > 0 ? "\n" : "")); + if ($requiresEventTargetNodeCast) { + push(@functionImplementation, " if (!impl${implementationClassWithoutNamespace}()->isEventTargetNode())\n"); + push(@functionImplementation, " return E_FAIL;\n"); + } + push(@functionImplementation, $callSigBegin . $callSigMiddle . $callSigEnd . "\n"); + push(@functionImplementation, " return S_OK;\n"); + push(@functionImplementation, "}\n\n"); + + return join("", @functionImplementation); +} + + +# ----------------------------------------------------------------------------- +# CPP Header +# ----------------------------------------------------------------------------- + +sub GenerateCPPHeader +{ + my ($object, $dataNode) = @_; + + my $IDLType = $dataNode->name; + my $implementationClass = IDLTypeToImplementationType($IDLType); + my $implementationClassWithoutNamespace = StripNamespace($implementationClass); + my $className = GetClassName($IDLType); + my $interfaceName = GetInterfaceName($IDLType); + + my $parentClassName = GetParentClass($dataNode); + my @otherInterfacesImplemented = GetAdditionalInterfaces($IDLType); + foreach my $otherInterface (@otherInterfacesImplemented) { + push(@additionalInterfaceDefinitions, $codeGenerator->ParseInterface($otherInterface)); + } + + # FIXME: strip whitespace from UUID + my $uuid = $dataNode->extendedAttributes->{"ImplementationUUID"} || die "All classes require an ImplementationUUID extended attribute."; + + my $numAttributes = @{$dataNode->attributes}; + my $numFunctions = @{$dataNode->functions}; + + # - Add default header template + @CPPHeaderHeader = @licenseTemplate; + push(@CPPHeaderHeader, "\n"); + + # - Header gaurds - + push(@CPPHeaderHeader, "#ifndef " . $className . "_h\n"); + push(@CPPHeaderHeader, "#define " . $className . "_h\n\n"); + + AddIncludesForTypeInCPPHeader($interfaceName); + AddIncludesForTypeInCPPHeader($parentClassName); + $CPPHeaderDontForwardDeclarations{$className} = 1; + $CPPHeaderDontForwardDeclarations{$interfaceName} = 1; + $CPPHeaderDontForwardDeclarations{$parentClassName} = 1; + + # -- Forward declare implementation type + push(@CPPHeaderContent, "namespace WebCore {\n"); + push(@CPPHeaderContent, " class ". StripNamespace($implementationClass) . ";\n"); + push(@CPPHeaderContent, "}\n\n"); + + # -- Start Class -- + my @parentsClasses = ($parentClassName, $interfaceName); + push(@parentsClasses, map { GetInterfaceName($_) } @otherInterfacesImplemented); + push(@CPPHeaderContent, "class __declspec(uuid(\"$uuid\")) ${className} : " . join(", ", map { "public $_" } @parentsClasses) . " {\n"); + + # Add includes for all additional interfaces to implement + map { AddIncludesForTypeInCPPHeader(GetInterfaceName($_)) } @otherInterfacesImplemented; + + # -- BASICS -- + # FIXME: The constructor and destructor should be protected, but the current design of + # createInstance requires them to be public. One solution is to friend the constructor + # of the top-level-class with every one of its child classes, but that requires information + # this script currently does not have, though possibly could determine. + push(@CPPHeaderContent, "public:\n"); + push(@CPPHeaderContent, " ${className}(${implementationClass}*);\n"); + push(@CPPHeaderContent, " virtual ~${className}();\n\n"); + + push(@CPPHeaderContent, "public:\n"); + push(@CPPHeaderContent, " static ${className}* createInstance(${implementationClass}*);\n\n"); + + push(@CPPHeaderContent, " // IUnknown\n"); + push(@CPPHeaderContent, " virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID, void** ppvObject);\n"); + push(@CPPHeaderContent, " virtual ULONG STDMETHODCALLTYPE AddRef() { return ${parentClassName}::AddRef(); }\n"); + push(@CPPHeaderContent, " virtual ULONG STDMETHODCALLTYPE Release() { return ${parentClassName}::Release(); }\n\n"); + + + # -- Parent Class Forwards -- + if (@{$dataNode->parents}) { + my %attributeNameSet = map {($_->signature->name, 1)} @{$dataNode->attributes}; + my %functionNameSet = map {($_->signature->name, 1)} @{$dataNode->functions}; + + my @parentLists = $codeGenerator->GetMethodsAndAttributesFromParentClasses($dataNode); + push(@CPPHeaderContent, "\n"); + foreach my $parentHash (@parentLists) { + + push(@CPPHeaderContent, " // " . GetInterfaceName($parentHash->{'name'}) . $DASHES . "\n"); + + my @attributeList = @{$parentHash->{'attributes'}}; + push(@CPPHeaderContent, " // Attributes\n"); + foreach my $attribute (@attributeList) { + # Don't forward an attribute that this class redefines. + next if $attributeNameSet{$attribute->signature->name}; + + AddForwardDeclarationsForTypeInCPPHeader($attribute->signature->type); + + my %attributes = GenerateCPPAttributeSignature($attribute, $className, { "NewLines" => 0, + "Indent" => 4, + "IncludeSemiColon" => 0, + "AddVirtualKeyword" => 1, + "UseClassName" => 0, + "Forwarder" => $parentClassName }); + push(@CPPHeaderContent, values(%attributes)); + } + + # Add attribute names to attribute names set in case other ancestors + # also define them. + $attributeNameSet{$_->signature->name} = 1 foreach @attributeList; + + push(@CPPHeaderContent, "\n"); + + my @functionList = @{$parentHash->{'functions'}}; + push(@CPPHeaderContent, " // Functions\n"); + foreach my $function (@functionList) { + # Don't forward a function that this class redefines. + next if $functionNameSet{$function->signature->name}; + + AddForwardDeclarationsForTypeInCPPHeader($function->signature->type); + AddForwardDeclarationsForTypeInCPPHeader($_->type) foreach (@{$function->parameters}); + + my $functionSig = GenerateCPPFunctionSignature($function, $className, { "NewLines" => 0, + "Indent" => 4, + "IncludeSemiColon" => 0, + "AddVirtualKeyword" => 1, + "UseClassName" => 0, + "Forwarder" => $parentClassName }); + + push(@CPPHeaderContent, $functionSig); + } + # Add functions names to functions names set in case other ancestors + # also define them. + $functionNameSet{$_->signature->name} = 1 foreach @functionList; + + push(@CPPHeaderContent, "\n"); + } + } + + # - Additional interfaces to implement - + foreach my $interfaceToImplement (@additionalInterfaceDefinitions) { + my $IDLTypeOfInterfaceToImplement = $interfaceToImplement->name; + my $nameOfInterfaceToImplement = GetInterfaceName($IDLTypeOfInterfaceToImplement); + my $numAttributesInInterface = @{$interfaceToImplement->attributes}; + my $numFunctionsInInterface = @{$interfaceToImplement->functions}; + + push(@CPPHeaderContent, " // ${nameOfInterfaceToImplement} ${DASHES}\n\n"); + + # - Add attribute getters/setters. + if ($numAttributesInInterface > 0) { + push(@CPPHeaderContent, " // Attributes\n\n"); + foreach my $attribute (@{$interfaceToImplement->attributes}) { + AddForwardDeclarationsForTypeInCPPHeader($attribute->signature->type); + + my %attributeSigs = GenerateCPPAttributeSignature($attribute, $className, { "NewLines" => 1, + "Indent" => 4, + "IncludeSemiColon" => 1, + "AddVirtualKeyword" => 1, + "UseClassName" => 0 }); + + push(@CPPHeaderContent, values(%attributeSigs)); + push(@CPPHeaderContent, "\n"); + } + } + + # - Add functions. + if ($numFunctionsInInterface > 0) { + push(@CPPHeaderContent, " // Functions\n\n"); + foreach my $function (@{$interfaceToImplement->functions}) { + AddForwardDeclarationsForTypeInCPPHeader($function->signature->type); + AddForwardDeclarationsForTypeInCPPHeader($_->type) foreach (@{$function->parameters}); + + my $functionSig = GenerateCPPFunctionSignature($function, $className, { "NewLines" => 1, + "Indent" => 4, + "IncludeSemiColon" => 1, + "AddVirtualKeyword" => 1, + "UseClassName" => 0 }); + + push(@CPPHeaderContent, $functionSig); + push(@CPPHeaderContent, "\n"); + } + } + } + + if ($numAttributes > 0 || $numFunctions > 0) { + push(@CPPHeaderContent, " // ${interfaceName} ${DASHES}\n\n"); + } + + # - Add constants COMING SOON + + # - Add attribute getters/setters. + if ($numAttributes > 0) { + push(@CPPHeaderContent, " // Attributes\n\n"); + foreach my $attribute (@{$dataNode->attributes}) { + AddForwardDeclarationsForTypeInCPPHeader($attribute->signature->type); + + my %attributeSigs = GenerateCPPAttributeSignature($attribute, $className, { "NewLines" => 1, + "Indent" => 4, + "IncludeSemiColon" => 1, + "AddVirtualKeyword" => 1, + "UseClassName" => 0 }); + + push(@CPPHeaderContent, values(%attributeSigs)); + push(@CPPHeaderContent, "\n"); + } + } + + # - Add functions. + if ($numFunctions > 0) { + push(@CPPHeaderContent, " // Functions\n\n"); + foreach my $function (@{$dataNode->functions}) { + AddForwardDeclarationsForTypeInCPPHeader($function->signature->type); + AddForwardDeclarationsForTypeInCPPHeader($_->type) foreach (@{$function->parameters}); + + my $functionSig = GenerateCPPFunctionSignature($function, $className, { "NewLines" => 1, + "Indent" => 4, + "IncludeSemiColon" => 1, + "AddVirtualKeyword" => 1, + "UseClassName" => 0 }); + + push(@CPPHeaderContent, $functionSig); + push(@CPPHeaderContent, "\n"); + } + } + + push(@CPPHeaderContent, " ${implementationClass}* impl${implementationClassWithoutNamespace}() const;\n"); + + if (@{$dataNode->parents} == 0) { + AddIncludesForTypeInCPPHeader("wtf/RefPtr", 1); + push(@CPPHeaderContent, "\n"); + push(@CPPHeaderContent, " ${implementationClass}* impl() const { return m_impl.get(); }\n\n"); + push(@CPPHeaderContent, "private:\n"); + push(@CPPHeaderContent, " RefPtr<${implementationClass}> m_impl;\n"); + } + + # -- End Class -- + push(@CPPHeaderContent, "};\n\n"); + + # -- Default Interface Creator -- + push(@CPPHeaderContent, "${interfaceName}* to${interfaceName}(${implementationClass}*);\n\n"); + + push(@CPPHeaderContent, "#endif // " . $className . "_h\n"); +} + + +# ----------------------------------------------------------------------------- +# CPP Implementation +# ----------------------------------------------------------------------------- + +sub GenerateCPPImplementation +{ + my ($object, $dataNode) = @_; + + my $IDLType = $dataNode->name; + my $implementationClass = IDLTypeToImplementationType($IDLType); + my $implementationClassWithoutNamespace = StripNamespace($implementationClass); + my $className = GetClassName($IDLType); + my $interfaceName = GetInterfaceName($IDLType); + + my $parentClassName = GetParentClass($dataNode); + my $isBaseClass = (@{$dataNode->parents} == 0); + + my $uuid = $dataNode->extendedAttributes->{"ImplementationUUID"} || die "All classes require an ImplementationUUID extended attribute."; + + my $numAttributes = @{$dataNode->attributes}; + my $numFunctions = @{$dataNode->functions}; + + # - Add default header template + @CPPImplementationHeader = @licenseTemplate; + push(@CPPImplementationHeader, "\n"); + + push(@CPPImplementationHeader, "#include \"config.h\"\n"); + push(@CPPImplementationHeader, "#include \"WebKitDLL.h\"\n"); + push(@CPPImplementationHeader, "#include " . ($className eq "GEN_DOMImplementation" ? "\"GEN_DOMDOMImplementation.h\"" : "\"${className}.h\"") . "\n"); + $CPPImplementationDontIncludes{"${className}.h"} = 1; + $CPPImplementationWebCoreIncludes{"${implementationClassWithoutNamespace}.h"} = 1; + + # -- Constructor -- + push(@CPPImplementationContent, "${className}::${className}(${implementationClass}* impl)\n"); + if ($isBaseClass) { + push(@CPPImplementationContent, " : m_impl(impl)\n"); + push(@CPPImplementationContent, "{\n"); + push(@CPPImplementationContent, " ASSERT_ARG(impl, impl);\n"); + push(@CPPImplementationContent, "}\n\n"); + } else { + push(@CPPImplementationContent, " : ${parentClassName}(impl)\n"); + push(@CPPImplementationContent, "{\n"); + push(@CPPImplementationContent, "}\n\n"); + } + + # -- Destructor -- + push(@CPPImplementationContent, "${className}::~${className}()\n"); + push(@CPPImplementationContent, "{\n"); + if ($isBaseClass) { + $CPPImplementationIncludes{"DOMCreateInstance.h"} = 1; + push(@CPPImplementationContent, " removeDOMWrapper(impl());\n"); + } + push(@CPPImplementationContent, "}\n\n"); + + push(@CPPImplementationContent, "${implementationClass}* ${className}::impl${implementationClassWithoutNamespace}() const\n"); + push(@CPPImplementationContent, "{\n"); + push(@CPPImplementationContent, " return static_cast<${implementationClass}*>(impl());\n"); + push(@CPPImplementationContent, "}\n\n"); + + # Base classes must implement the createInstance method externally. + if (@{$dataNode->parents} != 0) { + push(@CPPImplementationContent, "${className}* ${className}::createInstance(${implementationClass}* impl)\n"); + push(@CPPImplementationContent, "{\n"); + push(@CPPImplementationContent, " return static_cast<${className}*>(${parentClassName}::createInstance(impl));\n"); + push(@CPPImplementationContent, "}\n"); + } + + push(@CPPImplementationContent, "// IUnknown $DASHES\n\n"); + + # -- QueryInterface -- + push(@CPPImplementationContent, "HRESULT STDMETHODCALLTYPE ${className}::QueryInterface(REFIID riid, void** ppvObject)\n"); + push(@CPPImplementationContent, "{\n"); + push(@CPPImplementationContent, " *ppvObject = 0;\n"); + push(@CPPImplementationContent, " if (IsEqualGUID(riid, IID_${interfaceName}))\n"); + push(@CPPImplementationContent, " *ppvObject = reinterpret_cast<${interfaceName}*>(this);\n"); + push(@CPPImplementationContent, " else if (IsEqualGUID(riid, __uuidof(${className})))\n"); + push(@CPPImplementationContent, " *ppvObject = reinterpret_cast<${className}*>(this);\n"); + push(@CPPImplementationContent, " else\n"); + push(@CPPImplementationContent, " return ${parentClassName}::QueryInterface(riid, ppvObject);\n\n"); + push(@CPPImplementationContent, " AddRef();\n"); + push(@CPPImplementationContent, " return S_OK;\n"); + push(@CPPImplementationContent, "}\n\n"); + + # - Additional interfaces to implement - + foreach my $interfaceToImplement (@additionalInterfaceDefinitions) { + my $IDLTypeOfInterfaceToImplement = $interfaceToImplement->name; + my $nameOfInterfaceToImplement = GetInterfaceName($IDLTypeOfInterfaceToImplement); + my $numAttributesInInterface = @{$interfaceToImplement->attributes}; + my $numFunctionsInInterface = @{$interfaceToImplement->functions}; + + push(@CPPImplementationContent, " // ${nameOfInterfaceToImplement} ${DASHES}\n\n"); + + if ($numAttributesInInterface > 0) { + push(@CPPImplementationContent, "// Attributes\n\n"); + foreach my $attribute (@{$interfaceToImplement->attributes}) { + # FIXME: Do this in one step. + # FIXME: Implement exception handling. + + AddIncludesForTypeInCPPImplementation($attribute->signature->type); + + my %attributes = GenerateCPPAttribute($attribute, $className, $implementationClass); + push(@CPPImplementationContent, values(%attributes)); + } + } + + # - Add functions. + if ($numFunctionsInInterface > 0) { + push(@CPPImplementationContent, "// Functions\n\n"); + + foreach my $function (@{$interfaceToImplement->functions}) { + my $functionImplementation = GenerateCPPFunction($function, $className, $implementationClass); + push(@CPPImplementationContent, $functionImplementation); + } + } + } + + push(@CPPImplementationContent, "// ${interfaceName} $DASHES\n\n"); + + # - Add attribute getters/setters. + if ($numAttributes > 0) { + push(@CPPImplementationContent, "// Attributes\n\n"); + foreach my $attribute (@{$dataNode->attributes}) { + # FIXME: do this in one step + my $hasSetterException = @{$attribute->setterExceptions}; + my $hasGetterException = @{$attribute->getterExceptions}; + + AddIncludesForTypeInCPPImplementation($attribute->signature->type); + + my %attributes = GenerateCPPAttribute($attribute, $className, $implementationClass); + push(@CPPImplementationContent, values(%attributes)); + } + } + + # - Add functions. + if ($numFunctions > 0) { + push(@CPPImplementationContent, "// Functions\n\n"); + + foreach my $function (@{$dataNode->functions}) { + my $functionImplementation = GenerateCPPFunction($function, $className, $implementationClass); + push(@CPPImplementationContent, $functionImplementation); + } + } + + # - Default implementation for interface creator. + # FIXME: add extended attribute to add custom implementation if necessary. + push(@CPPImplementationContent, "${interfaceName}* to${interfaceName}(${implementationClass}* impl)\n"); + push(@CPPImplementationContent, "{\n"); + push(@CPPImplementationContent, " return ${className}::createInstance(impl);\n"); + push(@CPPImplementationContent, "}\n"); +} + +sub WriteData +{ + my ($object, $name, $pureInterface) = @_; + + # -- IDL -- + my $IDLFileName = "$outputDir/I" . $TEMP_PREFIX . "DOM" . $name . ".idl"; + unlink($IDLFileName); + + # Write to output IDL. + open(OUTPUTIDL, ">$IDLFileName") or die "Couldn't open file $IDLFileName"; + + # Add header + print OUTPUTIDL @IDLHeader; + + # Add forward declarations and imorts + delete $IDLForwardDeclarations{keys(%IDLDontForwardDeclare)}; + delete $IDLImports{keys(%IDLDontImport)}; + + print OUTPUTIDL map { "cpp_quote(\"interface $_;\")\n" } sort keys(%IDLForwardDeclarations); + print OUTPUTIDL "\n"; + + print OUTPUTIDL map { "interface $_;\n" } sort keys(%IDLForwardDeclarations); + print OUTPUTIDL "\n"; + print OUTPUTIDL "#ifndef DO_NO_IMPORTS\n"; + print OUTPUTIDL map { ($_ eq "IGEN_DOMImplementation") ? "import \"IGEN_DOMDOMImplementation.idl\";\n" : "import \"$_.idl\";\n" } sort keys(%IDLImports); + print OUTPUTIDL "#endif\n"; + print OUTPUTIDL "\n"; + + # Add content + print OUTPUTIDL @IDLContent; + + close(OUTPUTIDL); + + @IDLHeader = (); + @IDLContent = (); + + if ($pureInterface) { + my $CPPInterfaceHeaderFileName = "$outputDir/" . $TEMP_PREFIX . "DOM" . $name . ".h"; + unlink($CPPInterfaceHeaderFileName); + + open(OUTPUTCPPInterfaceHeader, ">$CPPInterfaceHeaderFileName") or die "Couldn't open file $CPPInterfaceHeaderFileName"; + + print OUTPUTCPPInterfaceHeader @CPPInterfaceHeader; + + close(OUTPUTCPPInterfaceHeader); + + @CPPInterfaceHeader = (); + } else { + my $CPPHeaderFileName = "$outputDir/" . $TEMP_PREFIX . "DOM" . $name . ".h"; + unlink($CPPHeaderFileName); + + # -- CPP Header -- + open(OUTPUTCPPHeader, ">$CPPHeaderFileName") or die "Couldn't open file $CPPHeaderFileName"; + + # Add header + print OUTPUTCPPHeader @CPPHeaderHeader; + + # Add includes + print OUTPUTCPPHeader map { ($_ eq "GEN_DOMImplementation.h") ? "#include \"GEN_DOMDOMImplementation.h\"\n" : "#include \"$_\"\n" } sort keys(%CPPHeaderIncludes); + print OUTPUTCPPHeader map { "#include <$_>\n" } sort keys(%CPPHeaderIncludesAngle); + + foreach my $dontDeclare (keys(%CPPHeaderDontForwardDeclarations)) { + delete $CPPHeaderForwardDeclarations{$dontDeclare} if ($CPPHeaderForwardDeclarations{$dontDeclare}); + } + print OUTPUTCPPHeader "\n"; + print OUTPUTCPPHeader map { "interface $_;\n" } sort keys(%CPPHeaderForwardDeclarations); + print OUTPUTCPPHeader "\n"; + + # Add content + print OUTPUTCPPHeader @CPPHeaderContent; + + close(OUTPUTCPPHeader); + + @CPPHeaderHeader = (); + @CPPHeaderContent = (); + + + # -- CPP Implementation -- + my $CPPImplementationFileName = "$outputDir/" . $TEMP_PREFIX . "DOM" . $name . ".cpp"; + unlink($CPPImplementationFileName); + + open(OUTPUTCPPImplementation, ">$CPPImplementationFileName") or die "Couldn't open file $CPPImplementationFileName"; + + # Add header + print OUTPUTCPPImplementation @CPPImplementationHeader; + print OUTPUTCPPImplementation "\n"; + + # Add includes + foreach my $dontInclude (keys(%CPPImplementationDontIncludes)) { + delete $CPPImplementationIncludes{$dontInclude} if ($CPPImplementationIncludes{$dontInclude}); + } + print OUTPUTCPPImplementation map { ($_ eq "GEN_DOMImplementation.h") ? "#include \"GEN_DOMDOMImplementation.h\"\n" : "#include \"$_\"\n" } sort keys(%CPPImplementationIncludes); + print OUTPUTCPPImplementation map { "#include <$_>\n" } sort keys(%CPPImplementationIncludesAngle); + print OUTPUTCPPImplementation "\n"; + + print OUTPUTCPPImplementation "#pragma warning(push, 0)\n"; + print OUTPUTCPPImplementation map { "#include <WebCore/$_>\n" } sort keys(%CPPImplementationWebCoreIncludes); + print OUTPUTCPPImplementation "#pragma warning(pop)\n"; + + # Add content + print OUTPUTCPPImplementation @CPPImplementationContent; + + close(OUTPUTCPPImplementation); + + @CPPImplementationHeader = (); + @CPPImplementationContent = (); + } +} + +1; |