| # |
| # 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 ($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 |
| @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) { |
| 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 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 <WebCore/$_>\n" } sort keys(%CPPImplementationWebCoreIncludes); |
| print OUTPUTCPPImplementation "#pragma warning(pop)\n"; |
| |
| # Add content |
| print OUTPUTCPPImplementation @CPPImplementationContent; |
| |
| close(OUTPUTCPPImplementation); |
| |
| @CPPImplementationHeader = (); |
| @CPPImplementationContent = (); |
| } |
| } |
| |
| 1; |