Home | History | Annotate | Download | only in scripts
      1 
      2 # Copyright (C) 2005, 2006 Nikolas Zimmermann <zimmermann (at] kde.org>
      3 # Copyright (C) 2006 Anders Carlsson <andersca (at] mac.com> 
      4 # Copyright (C) 2006, 2007 Samuel Weinig <sam (at] webkit.org>
      5 # Copyright (C) 2006 Alexey Proskuryakov <ap (at] webkit.org>
      6 # Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
      7 # Copyright (C) 2009 Cameron McCormack <cam (at] mcc.id.au>
      8 # Copyright (C) Research In Motion Limited 2010. All rights reserved.
      9 #
     10 # This library is free software; you can redistribute it and/or
     11 # modify it under the terms of the GNU Library General Public
     12 # License as published by the Free Software Foundation; either
     13 # version 2 of the License, or (at your option) any later version.
     14 # 
     15 # This library is distributed in the hope that it will be useful,
     16 # but WITHOUT ANY WARRANTY; without even the implied warranty of
     17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     18 # Library General Public License for more details.
     19 # 
     20 # You should have received a copy of the GNU Library General Public License
     21 # aint with this library; see the file COPYING.LIB.  If not, write to
     22 # the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     23 # Boston, MA 02110-1301, USA.
     24 #
     25 
     26 package CodeGeneratorCPP;
     27 
     28 # Global Variables
     29 my $module = "";
     30 my $outputDir = "";
     31 
     32 my @headerContentHeader = ();
     33 my @headerContent = ();
     34 my %headerForwardDeclarations = ();
     35 
     36 my @implContentHeader = ();
     37 my @implContent = ();
     38 my %implIncludes = ();
     39 
     40 # Constants
     41 my $exceptionInit = "WebCore::ExceptionCode ec = 0;";
     42 my $exceptionRaiseOnError = "webDOMRaiseError(static_cast<WebDOMExceptionCode>(ec));";
     43 
     44 # Default License Templates
     45 my $headerLicenseTemplate = << "EOF";
     46 /*
     47  * Copyright (C) Research In Motion Limited 2010. All rights reserved.
     48  * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
     49  * Copyright (C) 2006 Samuel Weinig <sam.weinig\@gmail.com>
     50  * Copyright (C) Research In Motion Limited 2010. All rights reserved.
     51  *
     52  * This library is free software; you can redistribute it and/or
     53  * modify it under the terms of the GNU Library General Public
     54  * License as published by the Free Software Foundation; either
     55  * version 2 of the License, or (at your option) any later version.
     56  *
     57  * This library is distributed in the hope that it will be useful,
     58  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     59  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     60  * Library General Public License for more details.
     61  *
     62  * You should have received a copy of the GNU Library General Public License
     63  * along with this library; see the file COPYING.LIB.  If not, write to
     64  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     65  * Boston, MA 02110-1301, USA.
     66  */
     67 EOF
     68 
     69 my $implementationLicenseTemplate = << "EOF";
     70 /*
     71  * This file is part of the WebKit open source project.
     72  * This file has been generated by generate-bindings.pl. DO NOT MODIFY!
     73  *
     74  * This library is free software; you can redistribute it and/or
     75  * modify it under the terms of the GNU Library General Public
     76  * License as published by the Free Software Foundation; either
     77  * version 2 of the License, or (at your option) any later version.
     78  *
     79  * This library is distributed in the hope that it will be useful,
     80  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     81  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     82  * Library General Public License for more details.
     83  *
     84  * You should have received a copy of the GNU Library General Public License
     85  * along with this library; see the file COPYING.LIB.  If not, write to
     86  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     87  * Boston, MA 02110-1301, USA.
     88  */
     89 EOF
     90 
     91 # Default constructor
     92 sub new
     93 {
     94     my $object = shift;
     95     my $reference = { };
     96 
     97     $codeGenerator = shift;
     98     $outputDir = shift;
     99     shift; # $outputHeadersDir
    100     shift; # $useLayerOnTop
    101     shift; # $preprocessor
    102     shift; # $writeDependencies
    103 
    104     bless($reference, $object);
    105     return $reference;
    106 }
    107 
    108 sub finish
    109 {
    110     my $object = shift;
    111 }
    112 
    113 # Params: 'domClass' struct
    114 sub GenerateInterface
    115 {
    116     my $object = shift;
    117     my $dataNode = shift;
    118     my $defines = shift;
    119 
    120     my $name = $dataNode->name;
    121     my $className = GetClassName($name);
    122     my $parentClassName = "WebDOM" . GetParentImplClassName($dataNode);
    123 
    124     # Start actual generation.
    125     $object->GenerateHeader($dataNode);
    126     $object->GenerateImplementation($dataNode);
    127 
    128     # Write changes.
    129     $object->WriteData("WebDOM" . $name);
    130 }
    131 
    132 # Params: 'idlDocument' struct
    133 sub GenerateModule
    134 {
    135     my $object = shift;
    136     my $dataNode = shift;
    137 
    138     $module = $dataNode->module;
    139 }
    140 
    141 sub GetClassName
    142 {
    143     my $name = $codeGenerator->StripModule(shift);
    144 
    145     # special cases
    146     return "WebDOMString" if $codeGenerator->IsStringType($name) or $name eq "SerializedScriptValue";
    147     return "WebDOMObject" if $name eq "DOMObject";
    148     return "bool" if $name eq "boolean";
    149     return $name if $codeGenerator->IsPrimitiveType($name);
    150     return "WebDOMCustomVoidCallback" if $name eq "VoidCallback";
    151 
    152     return "WebDOM$name";
    153 }
    154 
    155 sub GetImplClassName
    156 {
    157     return $codeGenerator->StripModule(shift);
    158 }
    159 
    160 sub GetParentImplClassName
    161 {
    162     my $dataNode = shift;
    163 
    164     if (@{$dataNode->parents} eq 0) {
    165         return "EventTarget" if $dataNode->extendedAttributes->{"EventTarget"};
    166         return "Object";
    167     }
    168 
    169     return $codeGenerator->StripModule($dataNode->parents(0));
    170 }
    171 
    172 sub GetParent
    173 {
    174     my $dataNode = shift;
    175     my $numParents = @{$dataNode->parents};
    176 
    177     my $parent = "";
    178     if ($numParents eq 0) {
    179         $parent = "WebDOMObject";
    180         $parent = "WebDOMEventTarget" if $dataNode->extendedAttributes->{"EventTarget"};
    181     } elsif ($numParents eq 1) {
    182         my $parentName = $codeGenerator->StripModule($dataNode->parents(0));
    183         $parent = "WebDOM" . $parentName;
    184     } else {
    185         my @parents = @{$dataNode->parents};
    186         my $firstParent = $codeGenerator->StripModule(shift(@parents));
    187         $parent = "WebDOM" . $firstParent;
    188     }
    189 
    190     return $parent;
    191 }
    192 
    193 sub ShouldSkipTypeInImplementation
    194 {
    195     my $typeInfo = shift;
    196 
    197     return 1 if $typeInfo->signature->extendedAttributes->{"Custom"}
    198              and !$typeInfo->signature->extendedAttributes->{"NoCPPCustom"};
    199 
    200     return 1 if $typeInfo->signature->extendedAttributes->{"CustomArgumentHandling"}
    201              or $typeInfo->signature->extendedAttributes->{"CustomGetter"}
    202              or $typeInfo->signature->extendedAttributes->{"NeedsUserGestureCheck"}
    203              or $typeInfo->signature->extendedAttributes->{"CPPCustom"};
    204 
    205     # FIXME: We don't generate bindings for SVG related interfaces yet
    206     return 1 if $typeInfo->signature->name =~ /getSVGDocument/;
    207 
    208     return 1 if $typeInfo->signature->name =~ /Constructor/;
    209     return 0;
    210 }
    211 
    212 sub ShouldSkipTypeInHeader
    213 {
    214     my $typeInfo = shift;
    215 
    216     # FIXME: We currently ignore any attribute/function needing custom code
    217     return 1 if $typeInfo->signature->extendedAttributes->{"CustomArgumentHandling"}
    218              or $typeInfo->signature->extendedAttributes->{"CustomGetter"};
    219 
    220     # FIXME: We don't generate bindings for SVG related interfaces yet
    221     return 1 if $typeInfo->signature->name =~ /getSVGDocument/;
    222 
    223     return 1 if $typeInfo->signature->name =~ /Constructor/;
    224     return 0;
    225 }
    226 
    227 sub GetCPPType
    228 {
    229     my $type = shift;
    230     my $useConstReference = shift;
    231     my $name = GetClassName($type);
    232 
    233     return "int" if $type eq "long";
    234     return "unsigned" if $name eq "unsigned long";
    235     return "unsigned short" if $type eq "CompareHow";
    236     return "double" if $name eq "Date";
    237 
    238     if ($codeGenerator->IsStringType($type)) {
    239         if ($useConstReference) {
    240             return "const $name&";
    241         }
    242 
    243         return $name;
    244     }
    245 
    246     return $name if $codeGenerator->IsPrimitiveType($type) or $type eq "DOMTimeStamp";
    247     return "const $name&" if $useConstReference;
    248     return $name;
    249 }
    250 
    251 sub ConversionNeeded
    252 {
    253     my $type = $codeGenerator->StripModule(shift);
    254     return !$codeGenerator->IsNonPointerType($type) && !$codeGenerator->IsStringType($type);
    255 }
    256 
    257 sub GetCPPTypeGetter
    258 {
    259     my $argName = shift;
    260     my $type = $codeGenerator->StripModule(shift);
    261 
    262     return $argName if $codeGenerator->IsPrimitiveType($type) or $codeGenerator->IsStringType($type);
    263     return "static_cast<WebCore::Range::CompareHow>($argName)" if $type eq "CompareHow";
    264     return "WebCore::SerializedScriptValue::create(WTF::String($argName))" if $type eq "SerializedScriptValue";
    265     return "toWebCore($argName)";
    266 }
    267 
    268 sub AddForwardDeclarationsForType
    269 {
    270     my $type = $codeGenerator->StripModule(shift);
    271     my $public = shift;
    272 
    273     return if $codeGenerator->IsNonPointerType($type) or $codeGenerator->IsStringType($type);
    274 
    275     my $class = GetClassName($type);
    276     $headerForwardDeclarations{$class} = 1 if $public;
    277 }
    278 
    279 sub AddIncludesForType
    280 {
    281     my $type = $codeGenerator->StripModule(shift);
    282 
    283     return if $codeGenerator->IsNonPointerType($type);
    284     return if $type =~ /Constructor/;
    285 
    286     if ($codeGenerator->IsStringType($type)) {
    287         $implIncludes{"wtf/text/AtomicString.h"} = 1;
    288         $implIncludes{"KURL.h"} = 1;
    289         $implIncludes{"WebDOMString.h"} = 1;
    290         return;
    291     }
    292 
    293     if ($type eq "DOMObject") {
    294         $implIncludes{"WebDOMObject.h"} = 1;
    295         return;
    296     }
    297 
    298     if ($type eq "EventListener") {
    299         $implIncludes{"WebNativeEventListener.h"} = 1;
    300         return;
    301     }
    302 
    303     if ($type eq "SerializedScriptValue") {
    304         $implIncludes{"SerializedScriptValue.h"} = 1;
    305         return;
    306     }
    307     
    308     if ($type eq "VoidCallback") {
    309         $implIncludes{"WebDOMCustomVoidCallback.h"} = 1;
    310         return;
    311     }
    312 
    313     $implIncludes{"Node.h"} = 1 if $type eq "NodeList";
    314     $implIncludes{"CSSMutableStyleDeclaration.h"} = 1 if $type eq "CSSStyleDeclaration";
    315 
    316     # Default, include the same named file (the implementation) and the same name prefixed with "WebDOM". 
    317     $implIncludes{"$type.h"} = 1 unless $type eq "DOMObject";
    318     $implIncludes{"WebDOM$type.h"} = 1;
    319 }
    320 
    321 sub GenerateConditionalStringFromAttributeValue
    322 {
    323     my $conditional = shift;
    324     if ($conditional =~ /&/) {
    325         return "ENABLE(" . join(") && ENABLE(", split(/&/, $conditional)) . ")";
    326     } elsif ($conditional =~ /\|/) {
    327         return "ENABLE(" . join(") || ENABLE(", split(/\|/, $conditional)) . ")";
    328     } else {
    329         return "ENABLE(" . $conditional . ")";
    330     }
    331 }
    332 
    333 sub GenerateConditionalString
    334 {
    335     my $node = shift;
    336     my $conditional = $node->extendedAttributes->{"Conditional"};
    337     if ($conditional) {
    338         return GenerateConditionalStringFromAttributeValue($conditional);
    339     } else {
    340         return "";
    341     }
    342 }
    343 
    344 sub GenerateHeader
    345 {
    346     my $object = shift;
    347     my $dataNode = shift;
    348 
    349     my $interfaceName = $dataNode->name;
    350     my $className = GetClassName($interfaceName);
    351     my $implClassName = GetImplClassName($interfaceName);
    352     my $implClassNameWithNamespace = "WebCore::" . $implClassName;
    353 
    354     my $parentName = "";
    355     $parentName = GetParent($dataNode);
    356 
    357     my $numConstants = @{$dataNode->constants};
    358     my $numAttributes = @{$dataNode->attributes};
    359     my $numFunctions = @{$dataNode->functions};
    360 
    361     # - Add default header template
    362     @headerContentHeader = split("\r", $headerLicenseTemplate);
    363     push(@headerContentHeader, "\n#ifndef $className" . "_h");
    364     push(@headerContentHeader, "\n#define $className" . "_h\n\n");
    365 
    366     my $conditionalString = GenerateConditionalString($dataNode);
    367     push(@headerContentHeader, "#if ${conditionalString}\n\n") if $conditionalString;
    368 
    369     # - INCLUDES -
    370 
    371     my %headerIncludes = ();
    372     $headerIncludes{"WebDOMString.h"} = 1;
    373     $headerIncludes{"$parentName.h"} = 1;
    374     foreach my $include (sort keys(%headerIncludes)) {
    375         push(@headerContentHeader, "#include <$include>\n");
    376     }
    377 
    378     push(@headerContent, "class $className");
    379     push(@headerContent, " : public $parentName") if $parentName;
    380     push(@headerContent, " {\n");
    381     push(@headerContent, "public:\n");
    382 
    383     # Constructor
    384     push(@headerContent, "    $className();\n");
    385     push(@headerContent, "    explicit $className($implClassNameWithNamespace*);\n");
    386 
    387     # Copy constructor and assignment operator on classes which have the d-ptr
    388     if ($parentName eq "WebDOMObject") {
    389         push(@headerContent, "    $className(const $className&);\n");
    390         push(@headerContent, "    ${className}& operator=(const $className&);\n");
    391     }
    392 
    393     # Destructor
    394     if ($parentName eq "WebDOMObject") {
    395         push(@headerContent, "    virtual ~$className();\n");
    396     } else {
    397         push(@headerContent, "    virtual ~$className() { }\n");
    398     }
    399 
    400     push(@headerContent, "\n");
    401     $headerForwardDeclarations{$implClassNameWithNamespace} = 1;
    402 
    403     # - Add constants.
    404     if ($numConstants > 0) {
    405         my @headerConstants = ();
    406 
    407         # FIXME: we need a way to include multiple enums.
    408         foreach my $constant (@{$dataNode->constants}) {
    409             my $constantName = $constant->name;
    410             my $constantValue = $constant->value;
    411 
    412             my $output = "WEBDOM_" . $constantName . " = " . $constantValue;
    413             push(@headerConstants, "        " . $output);
    414         }
    415 
    416         my $combinedConstants = join(",\n", @headerConstants);
    417 
    418         push(@headerContent, "    ");
    419         push(@headerContent, "enum {\n");
    420         push(@headerContent, $combinedConstants);
    421         push(@headerContent, "\n    ");
    422         push(@headerContent, "};\n\n");
    423     }
    424 
    425     my @headerAttributes = ();
    426 
    427     # - Add attribute getters/setters.
    428     if ($numAttributes > 0) {
    429         foreach my $attribute (@{$dataNode->attributes}) {
    430             next if ShouldSkipTypeInHeader($attribute);
    431 
    432             my $attributeConditionalString = GenerateConditionalString($attribute->signature);
    433             my $attributeName = $attribute->signature->name;
    434             my $attributeType = GetCPPType($attribute->signature->type, 0);
    435             my $attributeIsReadonly = ($attribute->type =~ /^readonly/);
    436             my $property = "";
    437             
    438             $property .= "#if ${attributeConditionalString}\n" if $attributeConditionalString;
    439             $property .= "    " . $attributeType . ($attributeType =~ /\*$/ ? "" : " ") . $attributeName . "() const";
    440 
    441             my $availabilityMacro = "";
    442             my $declarationSuffix = ";\n";
    443 
    444             AddForwardDeclarationsForType($attribute->signature->type, 1);
    445 
    446             $attributeType = GetCPPType($attribute->signature->type, 1);
    447             my $setterName = "set" . ucfirst($attributeName);
    448 
    449             $property .= $declarationSuffix;
    450             push(@headerAttributes, $property);
    451             if (!$attributeIsReadonly and !$attribute->signature->extendedAttributes->{"Replaceable"}) {
    452                 $property = "    void $setterName($attributeType)";
    453                 $property .= $declarationSuffix;
    454                 push(@headerAttributes, $property); 
    455             }
    456 
    457             push(@headerAttributes, "#endif\n") if $attributeConditionalString;
    458         }
    459         push(@headerContent, @headerAttributes) if @headerAttributes > 0;
    460     }
    461 
    462     my @headerFunctions = ();
    463     my @deprecatedHeaderFunctions = ();
    464     my @interfaceFunctions = ();
    465 
    466     # - Add functions.
    467     if ($numFunctions > 0) {
    468         foreach my $function (@{$dataNode->functions}) {
    469             next if ShouldSkipTypeInHeader($function);
    470             my $functionName = $function->signature->name;
    471 
    472             my $returnType = GetCPPType($function->signature->type, 0);
    473             my $numberOfParameters = @{$function->parameters};
    474             my %typesToForwardDeclare = ($function->signature->type => 1);
    475 
    476             my $parameterIndex = 0;
    477             my $functionSig = "$returnType $functionName(";
    478             my $methodName = $functionName;
    479             foreach my $param (@{$function->parameters}) {
    480                 my $paramName = $param->name;
    481                 my $paramType = GetCPPType($param->type, 1);
    482                 $typesToForwardDeclare{$param->type} = 1;
    483 
    484                 $functionSig .= ", " if $parameterIndex >= 1;
    485                 $functionSig .= "$paramType $paramName";
    486                 $parameterIndex++;
    487             }
    488             $functionSig .= ")";
    489             if ($dataNode->extendedAttributes->{"PureInterface"}) {
    490                 push(@interfaceFunctions, "    virtual " . $functionSig . " = 0;\n");
    491             }
    492             my $functionDeclaration = $functionSig;
    493             $functionDeclaration .= ";\n";
    494 
    495             foreach my $type (keys %typesToForwardDeclare) {
    496                 # add any forward declarations to the public header if a deprecated version will be generated
    497                 AddForwardDeclarationsForType($type, 1);
    498             }
    499 
    500             push(@headerFunctions, "    ");
    501             push(@headerFunctions, $functionDeclaration);
    502         }
    503 
    504         if (@headerFunctions > 0) {
    505             push(@headerContent, "\n") if @headerAttributes > 0;
    506             push(@headerContent, @headerFunctions);
    507         }
    508     }
    509 
    510     push(@headerContent, "\n");
    511     push(@headerContent, "    $implClassNameWithNamespace* impl() const;\n");
    512 
    513     if ($parentName eq "WebDOMObject") {
    514         push(@headerContent, "\nprotected:\n");
    515         push(@headerContent, "    struct ${className}Private;\n");
    516         push(@headerContent, "    ${className}Private* m_impl;\n");
    517     }
    518 
    519     push(@headerContent, "};\n\n");
    520 
    521     # for PureInterface classes also add the interface that the client code needs to
    522     # implement
    523     if ($dataNode->extendedAttributes->{"PureInterface"}) {
    524         push(@headerContent, "class WebUser$interfaceName {\n");
    525         push(@headerContent, "public:\n");
    526         push(@headerContent, "    virtual void ref() = 0;\n");
    527         push(@headerContent, "    virtual void deref() = 0;\n\n");
    528         push(@headerContent, @interfaceFunctions);
    529         push(@headerContent, "\nprotected:\n");
    530         push(@headerContent, "    virtual ~WebUser$interfaceName() {}\n");
    531         push(@headerContent, "};\n\n");
    532     }
    533 
    534     push(@headerContent, "WebCore::$implClassName* toWebCore(const $className&);\n");
    535     push(@headerContent, "$className toWebKit(WebCore::$implClassName*);\n");
    536     if ($dataNode->extendedAttributes->{"PureInterface"}) {
    537         push(@headerContent, "$className toWebKit(WebUser$interfaceName*);\n");
    538     }
    539     push(@headerContent, "\n#endif\n");
    540     push(@headerContent, "#endif // ${conditionalString}\n\n") if $conditionalString;
    541 }
    542 
    543 sub AddEarlyReturnStatement
    544 {
    545     my $returnType = shift;
    546 
    547     if (!defined($returnType) or $returnType eq "void") {
    548         $returnType = "";
    549     } elsif ($codeGenerator->IsPrimitiveType($returnType)) {
    550         $returnType = " 0";
    551     } elsif ($returnType eq "bool") {
    552         $returnType = " false";
    553     } else {
    554         $returnType = " $returnType()";
    555     }
    556 
    557     # TODO: We could set exceptions here, if we want that
    558     my $statement = "    if (!impl())\n";
    559     $statement .=   "        return$returnType;\n\n";
    560     return $statement;
    561 }
    562 
    563 sub AddReturnStatement
    564 {
    565     my $typeInfo = shift;
    566     my $returnValue = shift;
    567 
    568     # Used to invoke KURLs "const String&" operator
    569     if ($codeGenerator->IsStringType($typeInfo->signature->type)) {
    570         return "    return static_cast<const WTF::String&>($returnValue);\n";
    571     }
    572 
    573     return "    return $returnValue;\n";
    574 }
    575 
    576 sub GenerateImplementation
    577 {
    578     my $object = shift;
    579     my $dataNode = shift;
    580 
    581     my @ancestorInterfaceNames = ();
    582 
    583     if (@{$dataNode->parents} > 1) {
    584         $codeGenerator->AddMethodsConstantsAndAttributesFromParentClasses($dataNode, \@ancestorInterfaceNames);
    585     }
    586 
    587     my $interfaceName = $dataNode->name;
    588     my $className = GetClassName($interfaceName);
    589     my $implClassName = GetImplClassName($interfaceName);
    590     my $parentImplClassName = GetParentImplClassName($dataNode);
    591     my $implClassNameWithNamespace = "WebCore::" . $implClassName;
    592     my $baseClass = "WebDOM$parentImplClassName";
    593     my $conditional = $dataNode->extendedAttributes->{"Conditional"};
    594 
    595     my $numAttributes = @{$dataNode->attributes};
    596     my $numFunctions = @{$dataNode->functions};
    597 
    598     # - Add default header template.
    599     @implContentHeader = split("\r", $implementationLicenseTemplate);
    600 
    601     # - INCLUDES -
    602     push(@implContentHeader, "\n#include \"config.h\"\n");
    603     my $conditionalString = GenerateConditionalString($dataNode);
    604     push(@implContentHeader, "\n#if ${conditionalString}\n\n") if $conditionalString;
    605     push(@implContentHeader, "#include \"$className.h\"\n\n");
    606 
    607     $implIncludes{"WebExceptionHandler.h"} = 1;
    608     $implIncludes{"$implClassName.h"} = 1;
    609     @implContent = ();
    610 
    611     push(@implContent, "#include <wtf/GetPtr.h>\n");
    612     push(@implContent, "#include <wtf/RefPtr.h>\n\n");
    613 
    614     # Private datastructure, encapsulating WebCore types
    615     if ($baseClass eq "WebDOMObject") {
    616         push(@implContent, "struct ${className}::${className}Private {\n");
    617         push(@implContent, "    ${className}Private($implClassNameWithNamespace* object = 0)\n");
    618         push(@implContent, "        : impl(object)\n");
    619         push(@implContent, "    {\n");
    620         push(@implContent, "    }\n\n");
    621         push(@implContent, "    RefPtr<$implClassNameWithNamespace> impl;\n");
    622         push(@implContent, "};\n\n");
    623     }
    624 
    625     # Constructor
    626     push(@implContent, "${className}::$className()\n");
    627     push(@implContent, "    : ${baseClass}()\n");
    628     push(@implContent, "    , m_impl(0)\n") if ($baseClass eq "WebDOMObject");
    629     push(@implContent, "{\n");
    630     push(@implContent, "}\n\n");
    631 
    632     push(@implContent, "${className}::$className($implClassNameWithNamespace* impl)\n");
    633     if ($baseClass eq "WebDOMObject") {
    634         push(@implContent, "    : ${baseClass}()\n");
    635         push(@implContent, "    , m_impl(new ${className}Private(impl))\n");
    636         push(@implContent, "{\n");
    637         push(@implContent, "}\n\n");
    638 
    639         push(@implContent, "${className}::${className}(const ${className}& copy)\n");
    640         push(@implContent, "    : ${baseClass}()\n");
    641         push(@implContent, "{\n");
    642         push(@implContent, "    m_impl = copy.impl() ? new ${className}Private(copy.impl()) : 0;\n");
    643         push(@implContent, "}\n\n");
    644 
    645         push(@implContent, "${className}& ${className}::operator\=(const ${className}& copy)\n");
    646         push(@implContent, "{\n");
    647         push(@implContent, "    delete m_impl;\n");
    648         push(@implContent, "    m_impl = copy.impl() ? new ${className}Private(copy.impl()) : 0;\n");
    649         push(@implContent, "    return *this;\n");
    650         push(@implContent, "}\n\n");
    651 
    652         push(@implContent, "$implClassNameWithNamespace* ${className}::impl() const\n");
    653         push(@implContent, "{\n");
    654         push(@implContent, "    return m_impl ? m_impl->impl.get() : 0;\n");
    655         push(@implContent, "}\n\n");
    656 
    657         # Destructor
    658         push(@implContent, "${className}::~$className()\n");
    659         push(@implContent, "{\n");
    660         push(@implContent, "    delete m_impl;\n");
    661         push(@implContent, "    m_impl = 0;\n");
    662         push(@implContent, "}\n\n");
    663     } else {
    664         push(@implContent, "    : ${baseClass}(impl)\n");
    665         push(@implContent, "{\n");
    666         push(@implContent, "}\n\n");
    667 
    668         push(@implContent, "$implClassNameWithNamespace* ${className}::impl() const\n");
    669         push(@implContent, "{\n");
    670         push(@implContent, "    return static_cast<$implClassNameWithNamespace*>(${baseClass}::impl());\n");
    671         push(@implContent, "}\n\n");
    672     }
    673 
    674     # START implementation
    675     %attributeNames = ();
    676 
    677     # - Attributes
    678     if ($numAttributes > 0) {
    679         foreach my $attribute (@{$dataNode->attributes}) {
    680             next if ShouldSkipTypeInImplementation($attribute);
    681             AddIncludesForType($attribute->signature->type);
    682 
    683             my $idlType = $codeGenerator->StripModule($attribute->signature->type);
    684 
    685             my $attributeName = $attribute->signature->name;
    686             my $attributeType = GetCPPType($attribute->signature->type, 0);
    687             my $attributeIsReadonly = ($attribute->type =~ /^readonly/);
    688 
    689             $attributeNames{$attributeName} = 1;
    690 
    691             # - GETTER
    692             my $getterSig = "$attributeType $className\:\:$attributeName() const\n";
    693             my $hasGetterException = @{$attribute->getterExceptions};
    694             my $getterContentHead = "impl()->" . $codeGenerator->GetterExpressionPrefix(\%implIncludes, $interfaceName, $attribute);
    695             my $getterContentTail = ")";
    696 
    697             # Special cases
    698             my @customGetterContent = (); 
    699             if ($attribute->signature->extendedAttributes->{"ConvertToString"}) {
    700                 $getterContentHead = "WTF::String::number(" . $getterContentHead;
    701                 $getterContentTail .= ")";
    702             } elsif ($attribute->signature->type eq "SerializedScriptValue") {
    703                 $getterContentHead = "$getterContentHead";
    704                 $getterContentTail .= "->toString()";                
    705             } elsif (ConversionNeeded($attribute->signature->type)) {
    706                 $getterContentHead = "toWebKit(WTF::getPtr($getterContentHead";
    707                 $getterContentTail .= "))";
    708             }
    709 
    710             my $getterContent;
    711             if ($hasGetterException) {
    712                 $getterContent = $getterContentHead . "ec" . $getterContentTail;
    713             } else {
    714                 $getterContent = $getterContentHead . $getterContentTail;
    715             }
    716 
    717             my $attributeConditionalString = GenerateConditionalString($attribute->signature);
    718             push(@implContent, "#if ${attributeConditionalString}\n") if $attributeConditionalString;
    719 
    720             push(@implContent, $getterSig);
    721             push(@implContent, "{\n");
    722             push(@implContent, AddEarlyReturnStatement($attributeType));
    723             push(@implContent, @customGetterContent);
    724             if ($hasGetterException) {
    725                 # Differentiated between when the return type is a pointer and
    726                 # not for white space issue (ie. Foo *result vs. int result).
    727                 if ($attributeType =~ /\*$/) {
    728                     $getterContent = $attributeType . "result = " . $getterContent;
    729                 } else {
    730                     $getterContent = $attributeType . " result = " . $getterContent;
    731                 }
    732 
    733                 push(@implContent, "    $exceptionInit\n");
    734                 push(@implContent, "    $getterContent;\n");
    735                 push(@implContent, "    $exceptionRaiseOnError\n");
    736                 push(@implContent, AddReturnStatement($attribute, "result"));
    737             } else {
    738                 push(@implContent, AddReturnStatement($attribute, $getterContent));
    739             }
    740             push(@implContent, "}\n\n");
    741 
    742             # - SETTER
    743             if (!$attributeIsReadonly and !$attribute->signature->extendedAttributes->{"Replaceable"}) {
    744                 # Exception handling
    745                 my $hasSetterException = @{$attribute->setterExceptions};
    746 
    747                 my $coreSetterName = "set" . $codeGenerator->WK_ucfirst($attributeName);
    748                 my $setterName = "set" . ucfirst($attributeName);
    749                 my $argName = "new" . ucfirst($attributeName);
    750                 my $arg = GetCPPTypeGetter($argName, $idlType);
    751 
    752                 # The definition of ConvertToString is flipped for the setter
    753                 if ($attribute->signature->extendedAttributes->{"ConvertToString"}) {
    754                     $arg = "WTF::String($arg).toInt()";
    755                 }
    756 
    757                 my $attributeType = GetCPPType($attribute->signature->type, 1);
    758                 push(@implContent, "void $className\:\:$setterName($attributeType $argName)\n");
    759                 push(@implContent, "{\n");
    760                 push(@implContent, AddEarlyReturnStatement());
    761 
    762                 push(@implContent, "    $exceptionInit\n") if $hasSetterException;
    763                 my $ec = $hasSetterException ? ", ec" : "";
    764                 my $setterExpressionPrefix = $codeGenerator->SetterExpressionPrefix(\%implIncludes, $interfaceName, $attribute);
    765                 push(@implContent, "    impl()->$setterExpressionPrefix$arg$ec);\n");
    766                 push(@implContent, "    $exceptionRaiseOnError\n") if $hasSetterException;
    767                 push(@implContent, "}\n\n");
    768             }
    769 
    770             push(@implContent, "#endif\n") if $attributeConditionalString;
    771         }
    772     }
    773 
    774     # - Functions
    775     if ($numFunctions > 0) {
    776         foreach my $function (@{$dataNode->functions}) {
    777             # Treat PureInterface as Custom as well, since the WebCore versions will take a script context as well
    778             next if ShouldSkipTypeInImplementation($function) || $dataNode->extendedAttributes->{"PureInterface"};
    779             AddIncludesForType($function->signature->type);
    780 
    781             my $functionName = $function->signature->name;
    782             my $returnType = GetCPPType($function->signature->type, 0);
    783             my $hasParameters = @{$function->parameters};
    784             my $raisesExceptions = @{$function->raisesExceptions};
    785 
    786             my @parameterNames = ();
    787             my @needsAssert = ();
    788             my %needsCustom = ();
    789 
    790             my $parameterIndex = 0;
    791 
    792             my $functionSig = "$returnType $className\:\:$functionName(";
    793             foreach my $param (@{$function->parameters}) {
    794                 my $paramName = $param->name;
    795                 my $paramType = GetCPPType($param->type, 1);
    796 
    797                 # make a new parameter name if the original conflicts with a property name
    798                 $paramName = "in" . ucfirst($paramName) if $attributeNames{$paramName};
    799 
    800                 AddIncludesForType($param->type);
    801 
    802                 my $idlType = $codeGenerator->StripModule($param->type);
    803                 my $implGetter = GetCPPTypeGetter($paramName, $idlType);
    804 
    805                 push(@parameterNames, $implGetter);
    806                 $needsCustom{"NodeToReturn"} = $paramName if $param->extendedAttributes->{"Return"};
    807 
    808                 unless ($codeGenerator->IsPrimitiveType($idlType) or $codeGenerator->IsStringType($idlType)) {
    809                     push(@needsAssert, "    ASSERT($paramName);\n");
    810                 }
    811 
    812                 $functionSig .= ", " if $parameterIndex >= 1;
    813                 $functionSig .= "$paramType $paramName";
    814                 $parameterIndex++;
    815             }
    816 
    817             $functionSig .= ")";
    818 
    819             my @functionContent = ();
    820             push(@parameterNames, "ec") if $raisesExceptions;
    821             my $content = "impl()->" . $codeGenerator->WK_lcfirst($functionName) . "(" . join(", ", @parameterNames) . ")"; 
    822 
    823             if ($returnType eq "void") {
    824                 # Special case 'void' return type.
    825                 if ($raisesExceptions) {
    826                     push(@functionContent, "    $exceptionInit\n");
    827                     push(@functionContent, "    $content;\n");
    828                     push(@functionContent, "    $exceptionRaiseOnError\n");
    829                 } else {
    830                     push(@functionContent, "    $content;\n");
    831                 }
    832             } elsif (defined $needsCustom{"NodeToReturn"}) {
    833                 # TODO: This is important to enable, once we care about custom code!
    834 
    835                 # Special case the insertBefore, replaceChild, removeChild 
    836                 # and appendChild functions from DOMNode 
    837                 my $toReturn = $needsCustom{"NodeToReturn"};
    838                 if ($raisesExceptions) {
    839                     push(@functionContent, "    $exceptionInit\n");
    840                     push(@functionContent, "    if ($content)\n");
    841                     push(@functionContent, "        return $toReturn;\n");
    842                     push(@functionContent, "    $exceptionRaiseOnError\n");
    843                     push(@functionContent, "    return $className();\n");
    844                 } else {
    845                     push(@functionContent, "    if ($content)\n");
    846                     push(@functionContent, "        return $toReturn;\n");
    847                     push(@functionContent, "    return NULL;\n");
    848                 }
    849             } else {
    850                 if (ConversionNeeded($function->signature->type)) {
    851                     $content = "toWebKit(WTF::getPtr($content))";
    852                 }
    853 
    854                 if ($raisesExceptions) {
    855                     # Differentiated between when the return type is a pointer and
    856                     # not for white space issue (ie. Foo *result vs. int result).
    857                     if ($returnType =~ /\*$/) {
    858                         $content = $returnType . "result = " . $content;
    859                     } else {
    860                         $content = $returnType . " result = " . $content;
    861                     }
    862 
    863                     push(@functionContent, "    $exceptionInit\n");
    864                     push(@functionContent, "    $content;\n");
    865                     push(@functionContent, "    $exceptionRaiseOnError\n");
    866                     push(@functionContent, "    return result;\n");
    867                 } else {
    868                     push(@functionContent, "    return $content;\n");
    869                 }
    870             }
    871 
    872             push(@implContent, "$functionSig\n");
    873             push(@implContent, "{\n");
    874             push(@implContent, AddEarlyReturnStatement($returnType));
    875             push(@implContent, @functionContent);
    876             push(@implContent, "}\n\n");
    877 
    878             # Clear the hash
    879             %needsCustom = ();
    880         }
    881     }
    882 
    883     # END implementation
    884 
    885     # Generate internal interfaces
    886     push(@implContent, "WebCore::$implClassName* toWebCore(const $className& wrapper)\n");
    887     push(@implContent, "{\n");
    888     push(@implContent, "    return wrapper.impl();\n");
    889     push(@implContent, "}\n\n");
    890 
    891     push(@implContent, "$className toWebKit(WebCore::$implClassName* value)\n");
    892     push(@implContent, "{\n");
    893     push(@implContent, "    return $className(value);\n");
    894     push(@implContent, "}\n");
    895 
    896     # - End the ifdef conditional if necessary
    897     push(@implContent, "\n#endif // ${conditionalString}\n") if $conditionalString;
    898 }
    899 
    900 # Internal helper
    901 sub WriteData
    902 {
    903     my $object = shift;
    904     my $name = shift;
    905 
    906     # Open files for writing...
    907     my $headerFileName = "$outputDir/" . $name . ".h";
    908     my $implFileName = "$outputDir/" . $name . ".cpp";
    909 
    910     # Remove old files.
    911     unlink($headerFileName);
    912     unlink($implFileName);
    913 
    914     # Write public header.
    915     open(HEADER, ">$headerFileName") or die "Couldn't open file $headerFileName";
    916     
    917     print HEADER @headerContentHeader;
    918     print HEADER "\n";
    919     foreach my $class (sort keys(%headerForwardDeclarations)) {
    920         if ($class =~ /::/) {
    921             my $namespacePart = $class;
    922             $namespacePart =~ s/::.*//;
    923 
    924             my $classPart = $class;
    925             $classPart =~ s/${namespacePart}:://;
    926 
    927             print HEADER "namespace $namespacePart {\nclass $classPart;\n};\n\n";
    928         } else {
    929             print HEADER "class $class;\n"
    930         }
    931     }
    932 
    933     my $hasForwardDeclarations = keys(%headerForwardDeclarations);
    934     print HEADER "\n" if $hasForwardDeclarations;
    935     print HEADER @headerContent;
    936     close(HEADER);
    937 
    938     @headerContentHeader = ();
    939     @headerContent = ();
    940     %headerForwardDeclarations = ();
    941 
    942     # Write implementation file.
    943     open(IMPL, ">$implFileName") or die "Couldn't open file $implFileName";
    944 
    945     print IMPL @implContentHeader;
    946 
    947     foreach my $include (sort keys(%implIncludes)) {
    948         # "className.h" is already included right after config.h, silence check-webkit-style
    949         next if $include eq "$name.h";
    950         print IMPL "#include \"$include\"\n";
    951     }
    952 
    953     print IMPL @implContent;
    954     close(IMPL);
    955 
    956     @implContentHeader = ();
    957     @implContent = ();
    958     %implIncludes = ();
    959 }
    960 
    961 1;
    962