# # Copyright (C) 2005, 2006 Nikolas Zimmermann # Copyright (C) 2006 Anders Carlsson # Copyright (C) 2006, 2007 Samuel Weinig # Copyright (C) 2006 Alexey Proskuryakov # 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 my $beginAppleCopyright = <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 ($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{"PlatformString.h"} = 1; $CPPImplementationWebCoreIncludes{"BString.h"} = 1; $CPPImplementationWebCoreIncludes{"AtomicString.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 if ($dataNode->extendedAttributes->{"AppleCopyright"}) { @IDLHeader = split("\r", $beginAppleCopyright); } else { @IDLHeader = @licenseTemplate; } push(@IDLHeader, "\n"); # - INCLUDES - push(@IDLHeader, "import \"oaidl.idl\";\n"); push(@IDLHeader, "import \"ocidl.idl\";\n\n"); unless ($pureInterface) { push(@IDLHeader, "import \"${parentInterfaceName}.idl\";\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) { my $inAppleCopyright = 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"; my $needsAppleCopyright = $function->signature->extendedAttributes->{"AppleCopyright"}; if ($needsAppleCopyright) { if (!$inAppleCopyright) { push(@IDLContent, $beginAppleCopyright); $inAppleCopyright = 1; } } elsif ($inAppleCopyright) { push(@IDLContent, $endAppleCopyright); $inAppleCopyright = 0; } push(@IDLContent, $functionSig); } push(@IDLContent, $endAppleCopyright) if $inAppleCopyright; } # - End push(@IDLContent, "}\n\n"); if ($dataNode->extendedAttributes->{"AppleCopyright"}) { push(@IDLContent, split("\r", $endAppleCopyright)); } } 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 if ($dataNode->extendedAttributes->{"AppleCopyright"}) { @CPPInterfaceHeader = split("\r", $beginAppleCopyright); } else { @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"); if ($dataNode->extendedAttributes->{"AppleCopyright"}) { push(@CPPInterfaceHeader, split("\r", $endAppleCopyright)); } } # ----------------------------------------------------------------------------- # 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 if ($dataNode->extendedAttributes->{"AppleCopyright"}) { @CPPHeaderHeader = split("\r", $beginAppleCopyright); } else { @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) { my $inAppleCopyright = 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 }); my $needsAppleCopyright = $function->signature->extendedAttributes->{"AppleCopyright"}; if ($needsAppleCopyright) { if (!$inAppleCopyright) { push(@CPPHeaderContent, $beginAppleCopyright); $inAppleCopyright = 1; } } elsif ($inAppleCopyright) { push(@CPPHeaderContent, $endAppleCopyright); $inAppleCopyright = 0; } push(@CPPHeaderContent, $functionSig); push(@CPPHeaderContent, "\n"); } push(@CPPHeaderContent, $endAppleCopyright) if $inAppleCopyright; } } 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) { my $inAppleCopyright = 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 }); my $needsAppleCopyright = $function->signature->extendedAttributes->{"AppleCopyright"}; if ($needsAppleCopyright) { if (!$inAppleCopyright) { push(@CPPHeaderContent, $beginAppleCopyright); $inAppleCopyright = 1; } } elsif ($inAppleCopyright) { push(@CPPHeaderContent, $endAppleCopyright); $inAppleCopyright = 0; } push(@CPPHeaderContent, $functionSig); push(@CPPHeaderContent, "\n"); } push(@CPPHeaderContent, $endAppleCopyright) if $inAppleCopyright; } 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"); if ($dataNode->extendedAttributes->{"AppleCopyright"}) { push(@CPPHeaderContent, split("\r", $endAppleCopyright)); } } # ----------------------------------------------------------------------------- # 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 if ($dataNode->extendedAttributes->{"AppleCopyright"}) { @CPPImplementationHeader = split("\r", $beginAppleCopyright); } else { @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) { my $inAppleCopyright = 0; push(@CPPImplementationContent, "// Functions\n\n"); foreach my $function (@{$interfaceToImplement->functions}) { my $needsAppleCopyright = $function->signature->extendedAttributes->{"AppleCopyright"}; if ($needsAppleCopyright) { if (!$inAppleCopyright) { push(@CPPImplementationContent, $beginAppleCopyright); $inAppleCopyright = 1; } } elsif ($inAppleCopyright) { push(@CPPImplementationContent, $endAppleCopyright); $inAppleCopyright = 0; } my $functionImplementation = GenerateCPPFunction($function, $className, $implementationClass); push(@CPPImplementationContent, $functionImplementation); } push(@CPPImplementationContent, $endAppleCopyright) if $inAppleCopyright; } } 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) { my $inAppleCopyright = 0; push(@CPPImplementationContent, "// Functions\n\n"); foreach my $function (@{$dataNode->functions}) { my $needsAppleCopyright = $function->signature->extendedAttributes->{"AppleCopyright"}; if ($needsAppleCopyright) { if (!$inAppleCopyright) { push(@CPPImplementationContent, $beginAppleCopyright); $inAppleCopyright = 1; } } elsif ($inAppleCopyright) { push(@CPPImplementationContent, $endAppleCopyright); $inAppleCopyright = 0; } my $functionImplementation = GenerateCPPFunction($function, $className, $implementationClass); push(@CPPImplementationContent, $functionImplementation); } push(@CPPImplementationContent, $endAppleCopyright) if $inAppleCopyright; } # - 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"); if ($dataNode->extendedAttributes->{"AppleCopyright"}) { push(@CPPImplementationContent, split("\r", $endAppleCopyright)); } } 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 map { ($_ eq "IGEN_DOMImplementation") ? "import \"IGEN_DOMDOMImplementation.idl\";\n" : "import \"$_.idl\";\n" } sort keys(%IDLImports); 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 \n" } sort keys(%CPPImplementationWebCoreIncludes); print OUTPUTCPPImplementation "#pragma warning(pop)\n"; # Add content print OUTPUTCPPImplementation @CPPImplementationContent; close(OUTPUTCPPImplementation); @CPPImplementationHeader = (); @CPPImplementationContent = (); } } 1;