Windows build fixes
[WebKit-https.git] / WebCore / bindings / scripts / CodeGeneratorCOM.pm
1 #
2 # Copyright (C) 2005, 2006 Nikolas Zimmermann <zimmermann@kde.org>
3 # Copyright (C) 2006 Anders Carlsson <andersca@mac.com>
4 # Copyright (C) 2006, 2007 Samuel Weinig <sam@webkit.org>
5 # Copyright (C) 2006 Alexey Proskuryakov <ap@webkit.org>
6 # Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
7 #
8 # This library is free software; you can redistribute it and/or
9 # modify it under the terms of the GNU Library General Public
10 # License as published by the Free Software Foundation; either
11 # version 2 of the License, or (at your option) any later version.
12 #
13 # This library is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 # Library General Public License for more details.
17 #
18 # You should have received a copy of the GNU Library General Public License
19 # aint with this library; see the file COPYING.LIB.  If not, write to
20 # the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 # Boston, MA 02111-1307, USA.
22
23 package CodeGeneratorCOM;
24
25 use File::stat;
26
27 # Global Variables
28 my $module = "";
29 my $outputDir = "";
30
31 my @IDLHeader = ();
32 my @IDLContent = ();
33 my %IDLIncludes = ();
34 my %IDLForwardDeclarations = ();
35 my %IDLDontForwardDeclare = ();
36 my %IDLImports = ();
37 my %IDLDontImport = ();
38
39 my @CPPInterfaceHeader = ();
40
41 my @CPPHeaderHeader = ();
42 my @CPPHeaderContent = ();
43 my %CPPHeaderIncludes = ();
44 my %CPPHeaderIncludesAngle = ();
45 my %CPPHeaderForwardDeclarations = ();
46 my %CPPHeaderDontForwardDeclarations = ();
47
48 my @CPPImplementationHeader = ();
49 my @CPPImplementationContent = ();
50 my %CPPImplementationIncludes = ();
51 my %CPPImplementationWebCoreIncludes = ();
52 my %CPPImplementationIncludesAngle = ();
53 my %CPPImplementationDontIncludes = ();
54
55 my @additionalInterfaceDefinitions = ();
56
57 my $DASHES = "----------------------------------------";
58 my $TEMP_PREFIX = "GEN_";
59
60 # Hashes
61
62 my %includeCorrector = map {($_, 1)} qw{UIEvent KeyboardEvent MouseEvent
63                                         MutationEvent OverflowEvent WheelEvent};
64
65 my %conflictMethod = (
66     # FIXME: Add C language keywords?
67 );
68
69 # Default License Templates
70 my @licenseTemplate = split(/\r/, << "EOF");
71 /*
72  * Copyright (C) 2007 Apple Inc.  All rights reserved.
73  *
74  * Redistribution and use in source and binary forms, with or without
75  * modification, are permitted provided that the following conditions
76  * are met:
77  *
78  * 1.  Redistributions of source code must retain the above copyright
79  *     notice, this list of conditions and the following disclaimer.
80  * 2.  Redistributions in binary form must reproduce the above copyright
81  *     notice, this list of conditions and the following disclaimer in the
82  *     documentation and/or other materials provided with the distribution.
83  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
84  *     its contributors may be used to endorse or promote products derived
85  *     from this software without specific prior written permission.
86  *
87  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
88  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
89  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
90  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
91  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
92  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
93  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
94  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
95  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
96  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
97  */
98 EOF
99
100 # Default constructor
101 sub new
102 {
103     my $object = shift;
104     my $reference = { };
105
106     $codeGenerator = shift;
107     $outputDir = shift;
108
109     bless($reference, $object);
110     return $reference;
111 }
112
113 sub finish
114 {
115     my $object = shift;
116 }
117
118 # Params: 'domClass' struct
119 sub GenerateInterface
120 {
121     my $object = shift;
122     my $dataNode = shift;
123     my $defines = shift;
124
125     my $name = $dataNode->name;
126
127     my $pureInterface = $dataNode->extendedAttributes->{"PureInterface"};
128
129     # Start actual generation..
130     $object->GenerateIDL($dataNode, $pureInterface);
131     if ($pureInterface) {
132         $object->GenerateInterfaceHeader($dataNode);
133     } else {
134         $object->GenerateCPPHeader($dataNode);
135         $object->GenerateCPPImplementation($dataNode);
136     }
137
138     # Write changes.
139     $object->WriteData($name, $pureInterface);
140 }
141
142 # Params: 'idlDocument' struct
143 sub GenerateModule
144 {
145     my $object = shift;
146     my $dataNode = shift;
147
148     $module = $dataNode->module;
149 }
150
151 sub GetInterfaceName
152 {
153     my $name = $codeGenerator->StripModule(shift);
154
155     die "GetInterfaceName should only be used on interfaces." if ($codeGenerator->IsStringType($name) or $codeGenerator->IsPrimitiveType($name));
156
157     # special cases
158     return "I" . $TEMP_PREFIX . "DOMAbstractView" if $name eq "DOMWindow";
159     return "I" . $TEMP_PREFIX . $name if $name eq "DOMImplementation" or $name eq "DOMTimeStamp";
160
161     # Default, assume COM type has the same type name as
162     # idl type prefixed with "IDOM".
163     return "I" . $TEMP_PREFIX . "DOM" . $name;
164 }
165
166 sub GetClassName
167 {
168     my $name = $codeGenerator->StripModule(shift);
169
170     # special cases
171     return "BSTR" if $codeGenerator->IsStringType($name);
172     return "BOOL" if $name eq "boolean";
173     return "unsigned" if $name eq "unsigned long";
174     return "int" if $name eq "long";
175     return $name if $codeGenerator->IsPrimitiveType($name);
176     return $TEMP_PREFIX . "DOMAbstractView" if $name eq "DOMWindow";
177     return $TEMP_PREFIX . $name if $name eq "DOMImplementation" or $name eq "DOMTimeStamp";
178
179     # Default, assume COM type has the same type name as
180     # idl type prefixed with "DOM".
181     return $TEMP_PREFIX . "DOM" . $name;
182 }
183
184 sub GetCOMType
185 {
186     my ($type) = @_;
187
188     die "Don't use GetCOMType for string types, use one of In/Out variants instead." if $codeGenerator->IsStringType($type);
189
190     return "BOOL" if $type eq "boolean";
191     return "UINT" if $type eq "unsigned long";
192     return "INT" if $type eq "long";
193     return $type if $codeGenerator->IsPrimitiveType($type) or $type eq "DOMTimeStamp";
194     # return "unsigned short" if $type eq "CompareHow" or $type eq "SVGPaintType";
195
196     return GetInterfaceName($type) . "*";
197 }
198
199 sub GetCOMTypeIn
200 {
201     my ($type) = @_;
202     return "LPCTSTR" if $codeGenerator->IsStringType($type);
203     return GetCOMType($type);
204 }
205
206 sub GetCOMTypeOut
207 {
208     my ($type) = @_;
209     return "BSTR" if $codeGenerator->IsStringType($type);
210     return GetCOMType($type);
211 }
212
213 sub IDLTypeToImplementationType
214 {
215     my $type = $codeGenerator->StripModule(shift);
216
217     return "bool" if $type eq "boolean";
218     return "unsigned" if $type eq "unsigned long";
219     return "int" if $type eq "long";
220     return $type if $codeGenerator->IsPrimitiveType($type);
221
222     return "WebCore::String" if $codeGenerator->IsStringType($type);
223     return "WebCore::${type}";
224 }
225
226 sub StripNamespace
227 {
228     my ($type) = @_;
229
230     $type =~ s/^WebCore:://;
231
232     return $type;
233 }
234
235 sub GetParentInterface
236 {
237     my ($dataNode) = @_;
238     return "I" . $TEMP_PREFIX . "DOMObject" if (@{$dataNode->parents} == 0);
239     return "I" . $TEMP_PREFIX . "DOMNode" if $codeGenerator->StripModule($dataNode->parents(0)) eq "EventTargetNode";
240     return GetInterfaceName($codeGenerator->StripModule($dataNode->parents(0)));
241 }
242
243 sub GetParentClass
244 {
245     my ($dataNode) = @_;
246     return $TEMP_PREFIX . "DOMObject" if (@{$dataNode->parents} == 0);
247     return $TEMP_PREFIX . "DOMNode" if $codeGenerator->StripModule($dataNode->parents(0)) eq "EventTargetNode";
248     return GetClassName($codeGenerator->StripModule($dataNode->parents(0)));
249 }
250
251 sub AddForwardDeclarationsForTypeInIDL
252 {
253     my $type = $codeGenerator->StripModule(shift);
254
255     return if $codeGenerator->IsNonPointerType($type) or $codeGenerator->IsStringType($type);
256
257     my $interface = GetInterfaceName($type);
258     $IDLForwardDeclarations{$interface} = 1;
259     $IDLImports{$interface} = 1;
260 }
261
262 sub AddIncludesForTypeInCPPHeader
263 {
264     my $type = $codeGenerator->StripModule(shift);
265     my $useAngleBrackets = shift;
266
267     return if $codeGenerator->IsNonPointerType($type);
268
269     # Add special Cases HERE
270
271     if ($type =~ m/^I/) {
272         $type = "WebKit";
273     }
274
275     if ($useAngleBrackets) {
276         $CPPHeaderIncludesAngle{"$type.h"} = 1;
277         return;
278     }
279
280     if ($type eq "GEN_DOMImplementation") {
281         $CPPHeaderIncludes{"GEN_DOMDOMImplementation.h"} = 1;
282         return;
283     }
284
285     if ($type eq "IGEN_DOMImplementation") {
286         $CPPHeaderIncludes{"IGEN_DOMDOMImplementation.h"} = 1;
287         return;
288     }
289
290     $CPPHeaderIncludes{"$type.h"} = 1;
291 }
292
293 sub AddForwardDeclarationsForTypeInCPPHeader
294 {
295     my $type = $codeGenerator->StripModule(shift);
296
297     return if $codeGenerator->IsNonPointerType($type) or $codeGenerator->IsStringType($type);
298
299     my $interface = GetInterfaceName($type);
300     $CPPHeaderForwardDeclarations{$interface} = 1;
301 }
302
303 sub AddIncludesForTypeInCPPImplementation
304 {
305     my $type = $codeGenerator->StripModule(shift);
306
307     die "Include type not supported!" if $includeCorrector{$type};
308
309     return if $codeGenerator->IsNonPointerType($type);
310
311     if ($codeGenerator->IsStringType($type)) {
312         $CPPImplementationWebCoreIncludes{"AtomicString.h"} = 1;
313         $CPPImplementationWebCoreIncludes{"BString.h"} = 1;
314         $CPPImplementationWebCoreIncludes{"KURL.h"} = 1;
315         return;
316     }
317
318     # Special casing
319     $CPPImplementationWebCoreIncludes{"EventTargetNode.h"} = 1 if $type eq "Node";
320     $CPPImplementationWebCoreIncludes{"NameNodeList.h"} = 1 if $type eq "NodeList";
321     $CPPImplementationWebCoreIncludes{"CSSMutableStyleDeclaration.h"} = 1 if $type eq "CSSStyleDeclaration";
322
323     # Add implementation type
324     $CPPImplementationWebCoreIncludes{StripNamespace(IDLTypeToImplementationType($type)) . ".h"} = 1;
325
326     my $COMClassName = GetClassName($type);
327     $CPPImplementationIncludes{"${COMClassName}.h"} = 1;
328 }
329
330 sub GetAdditionalInterfaces
331 {
332     my $type = $codeGenerator->StripModule(shift);
333
334     return ("EventTarget") if $type eq "Node";
335     return ();
336 }
337
338 sub GenerateIDL
339 {
340     my ($object, $dataNode, $pureInterface) = @_;
341
342     my $inInterfaceName = $dataNode->name;
343     my $outInterfaceName = GetInterfaceName($inInterfaceName);
344     my $uuid = $dataNode->extendedAttributes->{"InterfaceUUID"} || die "All classes require an InterfaceUUID extended attribute.";
345
346     my $parentInterfaceName = ($pureInterface) ? "IUnknown" : GetParentInterface($dataNode);
347
348     my $numConstants = @{$dataNode->constants};
349     my $numAttributes = @{$dataNode->attributes};
350     my $numFunctions = @{$dataNode->functions};
351
352     # - Add default header template
353     @IDLHeader = @licenseTemplate;
354     push(@IDLHeader, "\n");
355
356     # - INCLUDES -
357     push(@IDLHeader, "#ifndef DO_NO_IMPORTS\n");
358     push(@IDLHeader, "import \"oaidl.idl\";\n");
359     push(@IDLHeader, "import \"ocidl.idl\";\n");
360     push(@IDLHeader, "#endif\n\n");
361
362     unless ($pureInterface) {
363         push(@IDLHeader, "#ifndef DO_NO_IMPORTS\n");
364         push(@IDLHeader, "import \"${parentInterfaceName}.idl\";\n");
365         push(@IDLHeader, "#endif\n\n");
366
367         $IDLDontForwardDeclare{$outInterfaceName} = 1;
368         $IDLDontImport{$outInterfaceName} = 1;
369         $IDLDontForwardDeclare{$parentInterfaceName} = 1;
370         $IDLDontImport{$parentInterfaceName} = 1;
371     }
372
373     # - Begin
374     # -- Attributes
375     push(@IDLContent, "[\n");
376     push(@IDLContent, "    object,\n");
377     push(@IDLContent, "    oleautomation,\n");
378     push(@IDLContent, "    uuid(" . $uuid . "),\n");
379     push(@IDLContent, "    pointer_default(unique)\n");
380     push(@IDLContent, "]\n");
381
382     # -- Interface
383     push(@IDLContent, "interface " . $outInterfaceName . " : " . $parentInterfaceName . "\n");
384     push(@IDLContent, "{\n");
385
386
387     # - FIXME: Add constants.
388
389
390     # - Add attribute getters/setters.
391     if ($numAttributes > 0) {
392         foreach my $attribute (@{$dataNode->attributes}) {
393             my $attributeName = $attribute->signature->name;
394             my $attributeIDLType = $attribute->signature->type;
395             my $attributeTypeIn = GetCOMTypeIn($attributeIDLType);
396             my $attributeTypeOut = GetCOMTypeOut($attributeIDLType);
397             my $attributeIsReadonly = ($attribute->type =~ /^readonly/);
398
399             AddForwardDeclarationsForTypeInIDL($attributeIDLType);
400
401             unless ($attributeIsReadonly) {
402                 # Setter
403                 my $setterName = "set" . $codeGenerator->WK_ucfirst($attributeName);
404                 my $setter = "    HRESULT " . $setterName . "([in] " . $attributeTypeIn . ");\n";
405                 push(@IDLContent, $setter);
406             }
407
408             # Getter
409             my $getter = "    HRESULT " . $attributeName . "([out, retval] " . $attributeTypeOut . "*);\n\n";
410             push(@IDLContent, $getter);
411         }
412     }
413
414     # - Add functions.
415     if ($numFunctions > 0) {
416         foreach my $function (@{$dataNode->functions}) {
417             my $functionName = $function->signature->name;
418             my $returnIDLType = $function->signature->type;
419             my $returnType = GetCOMTypeOut($returnIDLType);
420             my $noReturn = ($returnType eq "void");
421
422             AddForwardDeclarationsForTypeInIDL($returnIDLType);
423
424             my @paramArgList = ();
425             foreach my $param (@{$function->parameters}) {
426                 my $paramName = $param->name;
427                 my $paramIDLType = $param->type;
428                 my $paramType = GetCOMTypeIn($param->type);
429
430                 AddForwardDeclarationsForTypeInIDL($paramIDLType);
431
432                 # Form parameter
433                 my $parameter = "[in] ${paramType} ${paramName}";
434
435                 # Add parameter to function signature
436                 push(@paramArgList, $parameter);
437             }
438
439             unless ($noReturn) {
440                 my $resultParameter = "[out, retval] " . $returnType . "* result";
441                 push(@paramArgList, $resultParameter);
442             }
443
444             my $functionSig = "    HRESULT " . $functionName . "(";
445             $functionSig .= join(", ", @paramArgList);
446             $functionSig .= ");\n\n";
447             push(@IDLContent, $functionSig);
448         }
449     }
450
451     # - End
452     push(@IDLContent, "}\n\n");
453 }
454
455 sub GenerateInterfaceHeader
456 {
457     my ($object, $dataNode) = @_;
458
459     my $IDLType = $dataNode->name;
460     my $implementationClass = IDLTypeToImplementationType($IDLType);
461     my $implementationClassWithoutNamespace = StripNamespace($implementationClass);
462     my $className = GetClassName($IDLType);
463     my $interfaceName = GetInterfaceName($IDLType);
464
465     # - Add default header template
466     @CPPInterfaceHeader = @licenseTemplate;
467     push(@CPPInterfaceHeader, "\n");
468
469     # - Header guards -
470     push(@CPPInterfaceHeader, "#ifndef " . $className . "_h\n");
471     push(@CPPInterfaceHeader, "#define " . $className . "_h\n\n");
472
473     # - Forward Declarations -
474     push(@CPPInterfaceHeader, "interface ${interfaceName};\n\n");
475     push(@CPPInterfaceHeader, "namespace WebCore {\n");
476     push(@CPPInterfaceHeader, "    class ${implementationClassWithoutNamespace};\n");
477     push(@CPPInterfaceHeader, "}\n\n");
478
479     # - Default Interface Creator -
480     push(@CPPInterfaceHeader, "${interfaceName}* to${interfaceName}(${implementationClass}*) { return 0; }\n\n");
481
482     push(@CPPInterfaceHeader, "#endif // " . $className . "_h\n");
483 }
484
485 # -----------------------------------------------------------------------------
486 #    CPP Helper Functions
487 # -----------------------------------------------------------------------------
488
489 sub GenerateCPPAttributeSignature
490 {
491     my ($attribute, $className, $options) = @_;
492
493     my $attributeName = $attribute->signature->name;
494     my $isReadonly = ($attribute->type =~ /^readonly/);
495
496     my $newline = $$options{"NewLines"} ? "\n" : "";
497     my $indent = $$options{"Indent"} ? " " x $$options{"Indent"} : "";
498     my $semicolon = $$options{"IncludeSemiColon"} ? ";" : "";
499     my $virtual = $$options{"AddVirtualKeyword"} ? "virtual " : "";
500     my $class = $$options{"UseClassName"} ? "${className}::" : "";
501     my $forwarder = $$options{"Forwarder"} ? 1 : 0;
502     my $joiner =  ($$options{"NewLines"} ? "\n" . $indent . "    " : "");
503
504     my %attributeSignatures = ();
505
506     unless ($isReadonly) {
507         my $attributeTypeIn = GetCOMTypeIn($attribute->signature->type);
508         my $setterName = "set" . $codeGenerator->WK_ucfirst($attributeName);
509         my $setter = $indent . $virtual . "HRESULT STDMETHODCALLTYPE ". $class . $setterName . "(";
510         $setter .= $joiner . "/* [in] */ ${attributeTypeIn} ${attributeName})" . $semicolon . $newline;
511         if ($forwarder) {
512             $setter .= " { return " . $$options{"Forwarder"} . "::" . $setterName . "(${attributeName}); }\n";
513         }
514         $attributeSignatures{"Setter"} = $setter;
515     }
516
517     my $attributeTypeOut = GetCOMTypeOut($attribute->signature->type);
518     my $getter = $indent . $virtual . "HRESULT STDMETHODCALLTYPE " . $class . $attributeName . "(";
519     $getter .= $joiner . "/* [retval][out] */ ${attributeTypeOut}* result)" . $semicolon . $newline;
520     if ($forwarder) {
521         $getter .= " { return " . $$options{"Forwarder"} . "::" . $attributeName . "(result); }\n";
522     }
523     $attributeSignatures{"Getter"} = $getter;
524
525     return %attributeSignatures;
526 }
527
528
529 sub GenerateCPPAttribute
530 {
531     my ($attribute, $className, $implementationClass) = @_;
532
533     my $implementationClassWithoutNamespace = StripNamespace($implementationClass);
534
535     my $attributeName = $attribute->signature->name;
536     my $attributeIDLType = $attribute->signature->type;
537     my $hasSetterException = @{$attribute->setterExceptions};
538     my $hasGetterException = @{$attribute->getterExceptions};
539     my $isReadonly = ($attribute->type =~ /^readonly/);
540     my $attributeTypeIsPrimitive = $codeGenerator->IsPrimitiveType($attributeIDLType);
541     my $attributeTypeIsString = $codeGenerator->IsStringType($attributeIDLType);
542     my $attributeImplementationType = IDLTypeToImplementationType($attributeIDLType);
543     my $attributeImplementationTypeWithoutNamespace = StripNamespace($attributeImplementationType);
544     my $attributeTypeCOMClassName = GetClassName($attributeIDLType);
545
546     $CPPImplementationWebCoreIncludes{"ExceptionCode.h"} = 1 if $hasSetterException or $hasGetterException;
547
548     my %signatures = GenerateCPPAttributeSignature($attribute, $className, { "NewLines" => 1,
549                                                                              "Indent" => 0,
550                                                                              "IncludeSemiColon" => 0,
551                                                                              "UseClassName" => 1,
552                                                                              "AddVirtualKeyword" => 0 });
553
554     my %attrbutesToReturn = ();
555
556     unless ($isReadonly) {
557         my @setterImplementation = ();
558         push(@setterImplementation, $signatures{"Setter"});
559         push(@setterImplementation, "{\n");
560
561         my $setterName = "set" . $codeGenerator->WK_ucfirst($attributeName);
562
563         my @setterParams = ();
564         if ($attributeTypeIsString) {
565             push(@setterParams, $attributeName);
566             if ($hasSetterException) {
567                 push(@setterImplementation, "    WebCore::ExceptionCode ec = 0;\n");
568                 push(@setterParams, "ec");
569             }
570         } elsif ($attributeTypeIsPrimitive) {
571             if ($attribute->signature->extendedAttributes->{"ConvertFromString"}) {
572                 push(@setterParams, "WebCore::String::number(${attributeName})");
573             } elsif ($attributeIDLType eq "boolean") {
574                 push(@setterParams, "!!${attributeName}");
575             } else {
576                 my $primitiveImplementationType = IDLTypeToImplementationType($attributeIDLType);
577                 push(@setterParams, "static_cast<${primitiveImplementationType}>(${attributeName})");
578             }
579
580             if ($hasSetterException) {
581                 push(@setterImplementation, "    WebCore::ExceptionCode ec = 0;\n");
582                 push(@setterParams, "ec");
583             }
584         } else {
585             $CPPImplementationWebCoreIncludes{"COMPtr.h"} = 1;
586
587             push(@setterImplementation, "    if (!${attributeName})\n");
588             push(@setterImplementation, "        return E_POINTER;\n\n");
589             push(@setterImplementation, "    COMPtr<${attributeTypeCOMClassName}> ptr(Query, ${attributeName});\n");
590             push(@setterImplementation, "    if (!ptr)\n");
591             push(@setterImplementation, "        return E_NOINTERFACE;\n");
592
593             push(@setterParams, "ptr->impl${attributeImplementationTypeWithoutNamespace}()");
594             if ($hasSetterException) {
595                 push(@setterImplementation, "    WebCore::ExceptionCode ec = 0;\n");
596                 push(@setterParams, "ec");
597             }
598         }
599
600         # FIXME: CHECK EXCEPTION AND DO SOMETHING WITH IT
601
602         my $setterCall = "    impl${implementationClassWithoutNamespace}()->${setterName}(" . join(", ", @setterParams) . ");\n";
603
604         push(@setterImplementation, $setterCall);
605         push(@setterImplementation, "    return S_OK;\n");
606         push(@setterImplementation, "}\n\n");
607
608         $attrbutesToReturn{"Setter"} = join("", @setterImplementation);
609     }
610
611     my @getterImplementation = ();
612     push(@getterImplementation, $signatures{"Getter"});
613     push(@getterImplementation, "{\n");
614     push(@getterImplementation, "    if (!result)\n");
615     push(@getterImplementation, "        return E_POINTER;\n\n");
616
617     my $implementationGetter = "impl${implementationClassWithoutNamespace}()->" . $codeGenerator->WK_lcfirst($attributeName) . "(" . ($hasGetterException ? "ec" : ""). ")";
618
619     push(@getterImplementation, "    WebCore::ExceptionCode ec = 0;\n") if $hasGetterException;
620
621     if ($attributeTypeIsString) {
622         push(@getterImplementation, "    *result = WebCore::BString(${implementationGetter}).release();\n");
623     } elsif ($attributeTypeIsPrimitive) {
624         if ($attribute->signature->extendedAttributes->{"ConvertFromString"}) {
625             push(@getterImplementation, "    *result = static_cast<${attributeTypeCOMClassName}>(${implementationGetter}.toInt());\n");
626         } else {
627             push(@getterImplementation, "    *result = static_cast<${attributeTypeCOMClassName}>(${implementationGetter});\n");
628         }
629     } else {
630         $CPPImplementationIncludesAngle{"wtf/GetPtr.h"} = 1;
631         my $attributeTypeCOMInterfaceName = GetInterfaceName($attributeIDLType);
632         push(@getterImplementation, "    *result = 0;\n");
633         push(@getterImplementation, "    ${attributeImplementationType}* resultImpl = WTF::getPtr(${implementationGetter});\n");
634         push(@getterImplementation, "    if (!resultImpl)\n");
635         push(@getterImplementation, "        return E_POINTER;\n\n");
636         push(@getterImplementation, "    *result = to${attributeTypeCOMInterfaceName}(resultImpl);\n");
637     }
638
639     # FIXME: CHECK EXCEPTION AND DO SOMETHING WITH IT
640
641     push(@getterImplementation, "    return S_OK;\n");
642     push(@getterImplementation, "}\n\n");
643
644     $attrbutesToReturn{"Getter"} = join("", @getterImplementation);
645
646     return %attrbutesToReturn;
647 }
648
649 sub GenerateCPPFunctionSignature
650 {
651     my ($function, $className, $options) = @_;
652
653     my $functionName = $function->signature->name;
654     my $returnIDLType = $function->signature->type;
655     my $returnType = GetCOMTypeOut($returnIDLType);
656     my $noReturn = ($returnType eq "void");
657
658     my $newline = $$options{"NewLines"} ? "\n" : "";
659     my $indent = $$options{"Indent"} ? " " x $$options{"Indent"} : "";
660     my $semicolon = $$options{"IncludeSemiColon"} ? ";" : "";
661     my $virtual = $$options{"AddVirtualKeyword"} ? "virtual " : "";
662     my $class = $$options{"UseClassName"} ? "${className}::" : "";
663     my $forwarder = $$options{"Forwarder"} ? 1 : 0;
664     my $joiner = ($$options{"NewLines"} ? "\n" . $indent . "    " : " ");
665
666     my @paramArgList = ();
667     foreach my $param (@{$function->parameters}) {
668         my $paramName = $param->name;
669         my $paramType = GetCOMTypeIn($param->type);
670         my $parameter = "/* [in] */ ${paramType} ${paramName}";
671         push(@paramArgList, $parameter);
672     }
673
674     unless ($noReturn) {
675         my $resultParameter .= "/* [out, retval] */ ${returnType}* result";
676         push(@paramArgList, $resultParameter);
677     }
678
679     my $functionSig = $indent . $virtual . "HRESULT STDMETHODCALLTYPE " . $class . $functionName . "(";
680     $functionSig .= $joiner . join("," . $joiner, @paramArgList) if @paramArgList > 0;
681     $functionSig .= ")" . $semicolon . $newline;
682     if ($forwarder) {
683         my @paramNameList = ();
684         push(@paramNameList, $_->name) foreach (@{$function->parameters});
685         push(@paramNameList, "result") unless $noReturn;
686         $functionSig .= " { return " . $$options{"Forwarder"} . "::" . $functionName . "(" . join(", ", @paramNameList) . "); }\n";
687     }
688
689     return $functionSig
690 }
691
692 sub GenerateCPPFunction
693 {
694     my ($function, $className, $implementationClass) = @_;
695
696     my @functionImplementation = ();
697
698     my $signature = GenerateCPPFunctionSignature($function, $className, { "NewLines" => 1,
699                                                                           "Indent" => 0,
700                                                                           "IncludeSemiColon" => 0,
701                                                                           "UseClassName" => 1,
702                                                                           "AddVirtualKeyword" => 0 });
703
704     my $implementationClassWithoutNamespace = StripNamespace($implementationClass);
705
706     my $functionName = $function->signature->name;
707     my $returnIDLType = $function->signature->type;
708     my $noReturn = ($returnIDLType eq "void");
709     my $requiresEventTargetNodeCast = $function->signature->extendedAttributes->{"EventTargetNodeCast"};
710     my $raisesExceptions = @{$function->raisesExceptions};
711
712     AddIncludesForTypeInCPPImplementation($returnIDLType);
713     $CPPImplementationWebCoreIncludes{"ExceptionCode.h"} = 1 if $raisesExceptions;
714
715     my %needsCustom = ();
716     my @parameterInitialization = ();
717     my @parameterList = ();
718     foreach my $param (@{$function->parameters}) {
719         my $paramName = $param->name;
720         my $paramIDLType = $param->type;
721
722         my $paramTypeIsPrimitive = $codeGenerator->IsPrimitiveType($paramIDLType);
723         my $paramTypeIsString = $codeGenerator->IsStringType($paramIDLType);
724
725         $needsCustom{"NodeToReturn"} = $paramName if $param->extendedAttributes->{"Return"};
726
727         AddIncludesForTypeInCPPImplementation($paramIDLType);
728
729         # FIXME: We may need to null check the arguments as well
730
731         if ($paramTypeIsString) {
732             push(@parameterList, $paramName);
733         } elsif ($paramTypeIsPrimitive) {
734             if ($paramIDLType eq "boolean") {
735                 push(@parameterList, "!!${paramName}");
736             } else {
737                 my $primitiveImplementationType = IDLTypeToImplementationType($paramIDLType);
738                 push(@parameterList, "static_cast<${primitiveImplementationType}>(${paramName})");
739             }
740         } else {
741             $CPPImplementationWebCoreIncludes{"COMPtr.h"} = 1;
742
743             $needsCustom{"CanReturnEarly"} = 1;
744
745             my $paramTypeCOMClassName = GetClassName($paramIDLType);
746             my $paramTypeImplementationWithoutNamespace = StripNamespace(IDLTypeToImplementationType($paramIDLType));
747             my $ptrName = "ptrFor" . $codeGenerator->WK_ucfirst($paramName);
748             my $paramInit = "    COMPtr<${paramTypeCOMClassName}> ${ptrName}(Query, ${paramName});\n";
749             $paramInit .= "    if (!${ptrName})\n";
750             $paramInit .= "        return E_NOINTERFACE;";
751             push(@parameterInitialization, $paramInit);
752             push(@parameterList, "${ptrName}->impl${paramTypeImplementationWithoutNamespace}()");
753         }
754     }
755
756     push(@parameterList, "ec") if $raisesExceptions;
757
758     my $implementationGetter = "impl${implementationClassWithoutNamespace}()";
759     if ($requiresEventTargetNodeCast) {
760         $implementationGetter = "WebCore::EventTargetNodeCast(${implementationGetter})";
761     }
762
763     my $callSigBegin = "    ";
764     my $callSigMiddle = "${implementationGetter}->" . $codeGenerator->WK_lcfirst($functionName) . "(" . join(", ", @parameterList) . ")";
765     my $callSigEnd = ";\n";
766
767     if (defined $needsCustom{"NodeToReturn"}) {
768         my $nodeToReturn = $needsCustom{"NodeToReturn"};
769         $callSigBegin .= "if (";
770         $callSigEnd = ")\n";
771         $callSigEnd .= "        *result = ${nodeToReturn};";
772     } elsif (!$noReturn) {
773         my $returnTypeIsString =  $codeGenerator->IsStringType($returnIDLType);
774         my $returnTypeIsPrimitive = $codeGenerator->IsPrimitiveType($returnIDLType);
775
776         if ($returnTypeIsString) {
777             $callSigBegin .= "*result = WebCore::BString(";
778             $callSigEnd = ").release();\n";
779         } elsif ($returnTypeIsPrimitive) {
780             my $primitiveCOMType = GetClassName($returnIDLType);
781             $callSigBegin .= "*result = static_cast<${primitiveCOMType}>(";
782             $callSigEnd = ");";
783         } else {
784             $CPPImplementationIncludesAngle{"wtf/GetPtr.h"} = 1;
785             my $returnImplementationType = IDLTypeToImplementationType($returnIDLType);
786             my $returnTypeCOMInterfaceName = GetInterfaceName($returnIDLType);
787             $callSigBegin .= "${returnImplementationType}* resultImpl = WTF::getPtr(";
788             $callSigEnd = ");\n";
789             $callSigEnd .= "    if (!resultImpl)\n";
790             $callSigEnd .= "        return E_POINTER;\n\n";
791             $callSigEnd .= "    *result = to${returnTypeCOMInterfaceName}(resultImpl);";
792         }
793     }
794
795     push(@functionImplementation, $signature);
796     push(@functionImplementation, "{\n");
797     unless ($noReturn) {
798         push(@functionImplementation, "    if (!result)\n");
799         push(@functionImplementation, "        return E_POINTER;\n\n");
800         push(@functionImplementation, "    *result = 0;\n\n") if $needsCustom{"CanReturnEarly"};
801     }
802     push(@functionImplementation, "    WebCore::ExceptionCode ec = 0;\n") if $raisesExceptions; # FIXME: CHECK EXCEPTION AND DO SOMETHING WITH IT
803     push(@functionImplementation, join("\n", @parameterInitialization) . (@parameterInitialization > 0 ? "\n" : ""));
804     if ($requiresEventTargetNodeCast) {
805         push(@functionImplementation, "    if (!impl${implementationClassWithoutNamespace}()->isEventTargetNode())\n");
806         push(@functionImplementation, "        return E_FAIL;\n");
807     }
808     push(@functionImplementation, $callSigBegin . $callSigMiddle . $callSigEnd . "\n");
809     push(@functionImplementation, "    return S_OK;\n");
810     push(@functionImplementation, "}\n\n");
811
812     return join("", @functionImplementation);
813 }
814
815
816 # -----------------------------------------------------------------------------
817 #    CPP Header
818 # -----------------------------------------------------------------------------
819
820 sub GenerateCPPHeader
821 {
822     my ($object, $dataNode) = @_;
823
824     my $IDLType = $dataNode->name;
825     my $implementationClass = IDLTypeToImplementationType($IDLType);
826     my $implementationClassWithoutNamespace = StripNamespace($implementationClass);
827     my $className = GetClassName($IDLType);
828     my $interfaceName = GetInterfaceName($IDLType);
829
830     my $parentClassName = GetParentClass($dataNode);
831     my @otherInterfacesImplemented = GetAdditionalInterfaces($IDLType);
832     foreach my $otherInterface (@otherInterfacesImplemented) {
833         push(@additionalInterfaceDefinitions, $codeGenerator->ParseInterface($otherInterface));
834     }
835
836     # FIXME: strip whitespace from UUID
837     my $uuid = $dataNode->extendedAttributes->{"ImplementationUUID"} || die "All classes require an ImplementationUUID extended attribute.";
838
839     my $numAttributes = @{$dataNode->attributes};
840     my $numFunctions = @{$dataNode->functions};
841
842     # - Add default header template
843     @CPPHeaderHeader = @licenseTemplate;
844     push(@CPPHeaderHeader, "\n");
845
846     # - Header guards -
847     push(@CPPHeaderHeader, "#ifndef " . $className . "_h\n");
848     push(@CPPHeaderHeader, "#define " . $className . "_h\n\n");
849
850     AddIncludesForTypeInCPPHeader($interfaceName);
851     AddIncludesForTypeInCPPHeader($parentClassName);
852     $CPPHeaderDontForwardDeclarations{$className} = 1;
853     $CPPHeaderDontForwardDeclarations{$interfaceName} = 1;
854     $CPPHeaderDontForwardDeclarations{$parentClassName} = 1;
855
856     # -- Forward declare implementation type
857     push(@CPPHeaderContent, "namespace WebCore {\n");
858     push(@CPPHeaderContent, "    class ". StripNamespace($implementationClass) . ";\n");
859     push(@CPPHeaderContent, "}\n\n");
860
861     # -- Start Class --
862     my @parentsClasses = ($parentClassName, $interfaceName);
863     push(@parentsClasses, map { GetInterfaceName($_) } @otherInterfacesImplemented);
864     push(@CPPHeaderContent, "class __declspec(uuid(\"$uuid\")) ${className} : " . join(", ", map { "public $_" } @parentsClasses) . " {\n");
865
866     # Add includes for all additional interfaces to implement
867     map { AddIncludesForTypeInCPPHeader(GetInterfaceName($_)) } @otherInterfacesImplemented;
868
869     # -- BASICS --
870     # FIXME: The constructor and destructor should be protected, but the current design of
871     # createInstance requires them to be public.  One solution is to friend the constructor
872     # of the top-level-class with every one of its child classes, but that requires information
873     # this script currently does not have, though possibly could determine.
874     push(@CPPHeaderContent, "public:\n");
875     push(@CPPHeaderContent, "   ${className}(${implementationClass}*);\n");
876     push(@CPPHeaderContent, "   virtual ~${className}();\n\n");
877
878     push(@CPPHeaderContent, "public:\n");
879     push(@CPPHeaderContent, "    static ${className}* createInstance(${implementationClass}*);\n\n");
880
881     push(@CPPHeaderContent, "    // IUnknown\n");
882     push(@CPPHeaderContent, "    virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID, void** ppvObject);\n");
883     push(@CPPHeaderContent, "    virtual ULONG STDMETHODCALLTYPE AddRef() { return ${parentClassName}::AddRef(); }\n");
884     push(@CPPHeaderContent, "    virtual ULONG STDMETHODCALLTYPE Release() { return ${parentClassName}::Release(); }\n\n");
885
886
887     # -- Parent Class Forwards --
888     if (@{$dataNode->parents}) {
889         my %attributeNameSet = map {($_->signature->name, 1)} @{$dataNode->attributes};
890         my %functionNameSet = map {($_->signature->name, 1)} @{$dataNode->functions};
891
892         my @parentLists = $codeGenerator->GetMethodsAndAttributesFromParentClasses($dataNode);
893         push(@CPPHeaderContent, "\n");
894         foreach my $parentHash (@parentLists) {
895
896             push(@CPPHeaderContent, "    // " . GetInterfaceName($parentHash->{'name'}) . $DASHES . "\n");
897
898             my @attributeList = @{$parentHash->{'attributes'}};
899             push(@CPPHeaderContent, "    // Attributes\n");
900             foreach my $attribute (@attributeList) {
901                 # Don't forward an attribute that this class redefines.
902                 next if $attributeNameSet{$attribute->signature->name};
903
904                 AddForwardDeclarationsForTypeInCPPHeader($attribute->signature->type);
905
906                 my %attributes = GenerateCPPAttributeSignature($attribute, $className, { "NewLines" => 0,
907                                                                                          "Indent" => 4,
908                                                                                          "IncludeSemiColon" => 0,
909                                                                                          "AddVirtualKeyword" => 1,
910                                                                                          "UseClassName" => 0,
911                                                                                          "Forwarder" => $parentClassName });
912                 push(@CPPHeaderContent, values(%attributes));
913             }
914             
915             # Add attribute names to attribute names set in case other ancestors 
916             # also define them.
917             $attributeNameSet{$_->signature->name} = 1 foreach @attributeList;
918
919             push(@CPPHeaderContent, "\n");
920
921             my @functionList = @{$parentHash->{'functions'}};
922             push(@CPPHeaderContent, "    // Functions\n");
923             foreach my $function (@functionList) {
924                 # Don't forward a function that this class redefines.
925                 next if $functionNameSet{$function->signature->name};
926
927                 AddForwardDeclarationsForTypeInCPPHeader($function->signature->type);
928                 AddForwardDeclarationsForTypeInCPPHeader($_->type) foreach (@{$function->parameters});
929
930                 my $functionSig = GenerateCPPFunctionSignature($function, $className, { "NewLines" => 0,
931                                                                                         "Indent" => 4,
932                                                                                         "IncludeSemiColon" => 0,
933                                                                                         "AddVirtualKeyword" => 1,
934                                                                                         "UseClassName" => 0,
935                                                                                         "Forwarder" => $parentClassName });
936
937                 push(@CPPHeaderContent, $functionSig);
938             }
939             # Add functions names to functions names set in case other ancestors 
940             # also define them.
941             $functionNameSet{$_->signature->name} = 1 foreach @functionList;
942
943             push(@CPPHeaderContent, "\n");
944         }
945     }
946
947     # - Additional interfaces to implement -
948     foreach my $interfaceToImplement (@additionalInterfaceDefinitions) {
949         my $IDLTypeOfInterfaceToImplement = $interfaceToImplement->name;
950         my $nameOfInterfaceToImplement = GetInterfaceName($IDLTypeOfInterfaceToImplement);
951         my $numAttributesInInterface = @{$interfaceToImplement->attributes};
952         my $numFunctionsInInterface = @{$interfaceToImplement->functions};
953
954         push(@CPPHeaderContent, "    // ${nameOfInterfaceToImplement} ${DASHES}\n\n");
955
956         # - Add attribute getters/setters.
957         if ($numAttributesInInterface > 0) {
958             push(@CPPHeaderContent, "    // Attributes\n\n");
959             foreach my $attribute (@{$interfaceToImplement->attributes}) {
960                 AddForwardDeclarationsForTypeInCPPHeader($attribute->signature->type);
961
962                 my %attributeSigs = GenerateCPPAttributeSignature($attribute, $className, { "NewLines" => 1,
963                                                                                             "Indent" => 4,
964                                                                                             "IncludeSemiColon" => 1,
965                                                                                             "AddVirtualKeyword" => 1,
966                                                                                             "UseClassName" => 0 });
967
968                 push(@CPPHeaderContent, values(%attributeSigs));
969                 push(@CPPHeaderContent, "\n");
970             }
971         }
972
973         # - Add functions.
974         if ($numFunctionsInInterface > 0) {
975             push(@CPPHeaderContent, "    // Functions\n\n");
976             foreach my $function (@{$interfaceToImplement->functions}) {
977                 AddForwardDeclarationsForTypeInCPPHeader($function->signature->type);
978                 AddForwardDeclarationsForTypeInCPPHeader($_->type) foreach (@{$function->parameters});
979
980                 my $functionSig = GenerateCPPFunctionSignature($function, $className, { "NewLines" => 1,
981                                                                                         "Indent" => 4,
982                                                                                         "IncludeSemiColon" => 1,
983                                                                                         "AddVirtualKeyword" => 1,
984                                                                                         "UseClassName" => 0 });
985
986                 push(@CPPHeaderContent, $functionSig);
987                 push(@CPPHeaderContent, "\n");
988             }
989         }
990     }
991
992     if ($numAttributes > 0 || $numFunctions > 0) {
993         push(@CPPHeaderContent, "    // ${interfaceName} ${DASHES}\n\n");
994     }
995
996     # - Add constants COMING SOON
997
998     # - Add attribute getters/setters.
999     if ($numAttributes > 0) {
1000         push(@CPPHeaderContent, "    // Attributes\n\n");
1001         foreach my $attribute (@{$dataNode->attributes}) {
1002             AddForwardDeclarationsForTypeInCPPHeader($attribute->signature->type);
1003
1004             my %attributeSigs = GenerateCPPAttributeSignature($attribute, $className, { "NewLines" => 1,
1005                                                                                         "Indent" => 4,
1006                                                                                         "IncludeSemiColon" => 1,
1007                                                                                         "AddVirtualKeyword" => 1,
1008                                                                                         "UseClassName" => 0 });
1009
1010             push(@CPPHeaderContent, values(%attributeSigs));
1011             push(@CPPHeaderContent, "\n");
1012         }
1013     }
1014
1015     # - Add functions.
1016     if ($numFunctions > 0) {
1017         push(@CPPHeaderContent, "    // Functions\n\n");
1018         foreach my $function (@{$dataNode->functions}) {
1019             AddForwardDeclarationsForTypeInCPPHeader($function->signature->type);
1020             AddForwardDeclarationsForTypeInCPPHeader($_->type) foreach (@{$function->parameters});
1021
1022             my $functionSig = GenerateCPPFunctionSignature($function, $className, { "NewLines" => 1,
1023                                                                                     "Indent" => 4,
1024                                                                                     "IncludeSemiColon" => 1,
1025                                                                                     "AddVirtualKeyword" => 1,
1026                                                                                     "UseClassName" => 0 });
1027
1028             push(@CPPHeaderContent, $functionSig);
1029             push(@CPPHeaderContent, "\n");
1030         }
1031     }
1032
1033     push(@CPPHeaderContent, "    ${implementationClass}* impl${implementationClassWithoutNamespace}() const;\n");
1034
1035     if (@{$dataNode->parents} == 0) {
1036         AddIncludesForTypeInCPPHeader("wtf/RefPtr", 1);
1037         push(@CPPHeaderContent, "\n");
1038         push(@CPPHeaderContent, "    ${implementationClass}* impl() const { return m_impl.get(); }\n\n");
1039         push(@CPPHeaderContent, "private:\n");
1040         push(@CPPHeaderContent, "    RefPtr<${implementationClass}> m_impl;\n");
1041     }
1042
1043     # -- End Class --
1044     push(@CPPHeaderContent, "};\n\n");
1045
1046     # -- Default Interface Creator --
1047     push(@CPPHeaderContent, "${interfaceName}* to${interfaceName}(${implementationClass}*);\n\n");
1048
1049     push(@CPPHeaderContent, "#endif // " . $className . "_h\n");
1050 }
1051
1052
1053 # -----------------------------------------------------------------------------
1054 #    CPP Implementation
1055 # -----------------------------------------------------------------------------
1056
1057 sub GenerateCPPImplementation
1058 {
1059     my ($object, $dataNode) = @_;
1060
1061     my $IDLType = $dataNode->name;
1062     my $implementationClass = IDLTypeToImplementationType($IDLType);
1063     my $implementationClassWithoutNamespace = StripNamespace($implementationClass);
1064     my $className = GetClassName($IDLType);
1065     my $interfaceName = GetInterfaceName($IDLType);
1066
1067     my $parentClassName = GetParentClass($dataNode);
1068     my $isBaseClass = (@{$dataNode->parents} == 0);
1069
1070     my $uuid = $dataNode->extendedAttributes->{"ImplementationUUID"} || die "All classes require an ImplementationUUID extended attribute.";
1071
1072     my $numAttributes = @{$dataNode->attributes};
1073     my $numFunctions = @{$dataNode->functions};
1074
1075     # - Add default header template
1076     @CPPImplementationHeader = @licenseTemplate;
1077     push(@CPPImplementationHeader, "\n");
1078
1079     push(@CPPImplementationHeader, "#include \"config.h\"\n");
1080     push(@CPPImplementationHeader, "#include \"WebKitDLL.h\"\n");
1081     push(@CPPImplementationHeader, "#include " . ($className eq "GEN_DOMImplementation" ? "\"GEN_DOMDOMImplementation.h\"" : "\"${className}.h\"") . "\n");
1082     $CPPImplementationDontIncludes{"${className}.h"} = 1;
1083     $CPPImplementationWebCoreIncludes{"${implementationClassWithoutNamespace}.h"} = 1;
1084
1085     # -- Constructor --
1086     push(@CPPImplementationContent, "${className}::${className}(${implementationClass}* impl)\n");
1087     if ($isBaseClass) {
1088         push(@CPPImplementationContent, "    : m_impl(impl)\n");
1089         push(@CPPImplementationContent, "{\n");
1090         push(@CPPImplementationContent, "    ASSERT_ARG(impl, impl);\n");
1091         push(@CPPImplementationContent, "}\n\n");
1092     } else {
1093         push(@CPPImplementationContent, "    : ${parentClassName}(impl)\n");
1094         push(@CPPImplementationContent, "{\n");
1095         push(@CPPImplementationContent, "}\n\n");
1096     }
1097
1098     # -- Destructor --
1099     push(@CPPImplementationContent, "${className}::~${className}()\n");
1100     push(@CPPImplementationContent, "{\n");
1101     if ($isBaseClass) {
1102         $CPPImplementationIncludes{"DOMCreateInstance.h"} = 1;
1103         push(@CPPImplementationContent, "    removeDOMWrapper(impl());\n");
1104     }
1105     push(@CPPImplementationContent, "}\n\n");
1106
1107     push(@CPPImplementationContent, "${implementationClass}* ${className}::impl${implementationClassWithoutNamespace}() const\n");
1108     push(@CPPImplementationContent, "{\n");
1109     push(@CPPImplementationContent, "    return static_cast<${implementationClass}*>(impl());\n");
1110     push(@CPPImplementationContent, "}\n\n");
1111
1112     # Base classes must implement the createInstance method externally.
1113     if (@{$dataNode->parents} != 0) {
1114         push(@CPPImplementationContent, "${className}* ${className}::createInstance(${implementationClass}* impl)\n");
1115         push(@CPPImplementationContent, "{\n");
1116         push(@CPPImplementationContent, "    return static_cast<${className}*>(${parentClassName}::createInstance(impl));\n");
1117         push(@CPPImplementationContent, "}\n");
1118     }
1119
1120     push(@CPPImplementationContent, "// IUnknown $DASHES\n\n");
1121
1122     # -- QueryInterface --
1123     push(@CPPImplementationContent, "HRESULT STDMETHODCALLTYPE ${className}::QueryInterface(REFIID riid, void** ppvObject)\n");
1124     push(@CPPImplementationContent, "{\n");
1125     push(@CPPImplementationContent, "    *ppvObject = 0;\n");
1126     push(@CPPImplementationContent, "    if (IsEqualGUID(riid, IID_${interfaceName}))\n");
1127     push(@CPPImplementationContent, "        *ppvObject = reinterpret_cast<${interfaceName}*>(this);\n");
1128     push(@CPPImplementationContent, "    else if (IsEqualGUID(riid, __uuidof(${className})))\n");
1129     push(@CPPImplementationContent, "        *ppvObject = reinterpret_cast<${className}*>(this);\n");
1130     push(@CPPImplementationContent, "    else\n");
1131     push(@CPPImplementationContent, "        return ${parentClassName}::QueryInterface(riid, ppvObject);\n\n");
1132     push(@CPPImplementationContent, "    AddRef();\n");
1133     push(@CPPImplementationContent, "    return S_OK;\n");
1134     push(@CPPImplementationContent, "}\n\n");
1135
1136     # - Additional interfaces to implement -
1137     foreach my $interfaceToImplement (@additionalInterfaceDefinitions) {
1138         my $IDLTypeOfInterfaceToImplement = $interfaceToImplement->name;
1139         my $nameOfInterfaceToImplement = GetInterfaceName($IDLTypeOfInterfaceToImplement);
1140         my $numAttributesInInterface = @{$interfaceToImplement->attributes};
1141         my $numFunctionsInInterface = @{$interfaceToImplement->functions};
1142
1143         push(@CPPImplementationContent, "    // ${nameOfInterfaceToImplement} ${DASHES}\n\n");
1144
1145         if ($numAttributesInInterface > 0) {
1146             push(@CPPImplementationContent, "// Attributes\n\n");
1147             foreach my $attribute (@{$interfaceToImplement->attributes}) {
1148                 # FIXME: Do this in one step.
1149                 # FIXME: Implement exception handling.
1150
1151                 AddIncludesForTypeInCPPImplementation($attribute->signature->type);
1152
1153                 my %attributes = GenerateCPPAttribute($attribute, $className, $implementationClass);
1154                 push(@CPPImplementationContent, values(%attributes));
1155             }
1156         }
1157
1158         # - Add functions.
1159         if ($numFunctionsInInterface > 0) {
1160             push(@CPPImplementationContent, "// Functions\n\n");
1161
1162             foreach my $function (@{$interfaceToImplement->functions}) {
1163                 my $functionImplementation = GenerateCPPFunction($function, $className, $implementationClass);
1164                 push(@CPPImplementationContent, $functionImplementation);
1165             }
1166         }
1167     }
1168
1169     push(@CPPImplementationContent, "// ${interfaceName} $DASHES\n\n");
1170
1171     # - Add attribute getters/setters.
1172     if ($numAttributes > 0) {
1173         push(@CPPImplementationContent, "// Attributes\n\n");
1174         foreach my $attribute (@{$dataNode->attributes}) {
1175             # FIXME: do this in one step
1176             my $hasSetterException = @{$attribute->setterExceptions};
1177             my $hasGetterException = @{$attribute->getterExceptions};
1178
1179             AddIncludesForTypeInCPPImplementation($attribute->signature->type);
1180
1181             my %attributes = GenerateCPPAttribute($attribute, $className, $implementationClass);
1182             push(@CPPImplementationContent, values(%attributes));
1183         }
1184     }
1185
1186     # - Add functions.
1187     if ($numFunctions > 0) {
1188         push(@CPPImplementationContent, "// Functions\n\n");
1189
1190         foreach my $function (@{$dataNode->functions}) {
1191             my $functionImplementation = GenerateCPPFunction($function, $className, $implementationClass);
1192             push(@CPPImplementationContent, $functionImplementation);
1193         }
1194     }
1195
1196     # - Default implementation for interface creator.
1197     # FIXME: add extended attribute to add custom implementation if necessary.
1198     push(@CPPImplementationContent, "${interfaceName}* to${interfaceName}(${implementationClass}* impl)\n");
1199     push(@CPPImplementationContent, "{\n");
1200     push(@CPPImplementationContent, "    return ${className}::createInstance(impl);\n");
1201     push(@CPPImplementationContent, "}\n");
1202 }
1203
1204 sub WriteData
1205 {
1206     my ($object, $name, $pureInterface) = @_;
1207
1208     # -- IDL --
1209     my $IDLFileName = "$outputDir/I" . $TEMP_PREFIX . "DOM" . $name . ".idl";
1210     unlink($IDLFileName);
1211
1212     # Write to output IDL.
1213     open(OUTPUTIDL, ">$IDLFileName") or die "Couldn't open file $IDLFileName";
1214
1215     # Add header
1216     print OUTPUTIDL @IDLHeader;
1217
1218     # Add forward declarations and imorts
1219     delete $IDLForwardDeclarations{keys(%IDLDontForwardDeclare)};
1220     delete $IDLImports{keys(%IDLDontImport)};
1221
1222     print OUTPUTIDL map { "cpp_quote(\"interface $_;\")\n" } sort keys(%IDLForwardDeclarations);
1223     print OUTPUTIDL "\n";
1224
1225     print OUTPUTIDL map { "interface $_;\n" } sort keys(%IDLForwardDeclarations);
1226     print OUTPUTIDL "\n";
1227     print OUTPUTIDL "#ifndef DO_NO_IMPORTS\n";
1228     print OUTPUTIDL map { ($_ eq "IGEN_DOMImplementation") ? "import \"IGEN_DOMDOMImplementation.idl\";\n" : "import \"$_.idl\";\n" } sort keys(%IDLImports);
1229     print OUTPUTIDL "#endif\n";
1230     print OUTPUTIDL "\n";
1231
1232     # Add content
1233     print OUTPUTIDL @IDLContent;
1234
1235     close(OUTPUTIDL);
1236
1237     @IDLHeader = ();
1238     @IDLContent = ();
1239
1240     if ($pureInterface) {
1241         my $CPPInterfaceHeaderFileName = "$outputDir/" . $TEMP_PREFIX . "DOM" . $name . ".h";
1242         unlink($CPPInterfaceHeaderFileName);
1243
1244         open(OUTPUTCPPInterfaceHeader, ">$CPPInterfaceHeaderFileName") or die "Couldn't open file $CPPInterfaceHeaderFileName";
1245
1246         print OUTPUTCPPInterfaceHeader @CPPInterfaceHeader;
1247
1248         close(OUTPUTCPPInterfaceHeader);
1249
1250         @CPPInterfaceHeader = ();
1251     } else {
1252         my $CPPHeaderFileName = "$outputDir/" . $TEMP_PREFIX . "DOM" . $name . ".h";
1253         unlink($CPPHeaderFileName);
1254
1255         # -- CPP Header --
1256         open(OUTPUTCPPHeader, ">$CPPHeaderFileName") or die "Couldn't open file $CPPHeaderFileName";
1257
1258         # Add header
1259         print OUTPUTCPPHeader @CPPHeaderHeader;
1260
1261         # Add includes
1262         print OUTPUTCPPHeader map { ($_ eq "GEN_DOMImplementation.h") ? "#include \"GEN_DOMDOMImplementation.h\"\n" : "#include \"$_\"\n" } sort keys(%CPPHeaderIncludes);
1263         print OUTPUTCPPHeader map { "#include <$_>\n" } sort keys(%CPPHeaderIncludesAngle);
1264
1265         foreach my $dontDeclare (keys(%CPPHeaderDontForwardDeclarations)) {
1266             delete $CPPHeaderForwardDeclarations{$dontDeclare} if ($CPPHeaderForwardDeclarations{$dontDeclare});
1267         }
1268         print OUTPUTCPPHeader "\n";
1269         print OUTPUTCPPHeader map { "interface $_;\n" } sort keys(%CPPHeaderForwardDeclarations);
1270         print OUTPUTCPPHeader "\n";
1271
1272         # Add content
1273         print OUTPUTCPPHeader @CPPHeaderContent;
1274
1275         close(OUTPUTCPPHeader);
1276
1277         @CPPHeaderHeader = ();
1278         @CPPHeaderContent = ();
1279
1280
1281         # -- CPP Implementation --
1282         my $CPPImplementationFileName = "$outputDir/" . $TEMP_PREFIX . "DOM" . $name . ".cpp";
1283         unlink($CPPImplementationFileName);
1284
1285         open(OUTPUTCPPImplementation, ">$CPPImplementationFileName") or die "Couldn't open file $CPPImplementationFileName";
1286
1287         # Add header
1288         print OUTPUTCPPImplementation @CPPImplementationHeader;
1289         print OUTPUTCPPImplementation "\n";
1290
1291         # Add includes
1292         foreach my $dontInclude (keys(%CPPImplementationDontIncludes)) {
1293             delete $CPPImplementationIncludes{$dontInclude} if ($CPPImplementationIncludes{$dontInclude});
1294         }
1295         print OUTPUTCPPImplementation map { ($_ eq "GEN_DOMImplementation.h") ? "#include \"GEN_DOMDOMImplementation.h\"\n" : "#include \"$_\"\n" } sort keys(%CPPImplementationIncludes);
1296         print OUTPUTCPPImplementation map { "#include <$_>\n" } sort keys(%CPPImplementationIncludesAngle);
1297         print OUTPUTCPPImplementation "\n";
1298
1299         print OUTPUTCPPImplementation "#pragma warning(push, 0)\n";
1300         print OUTPUTCPPImplementation map { "#include <WebCore/$_>\n" } sort keys(%CPPImplementationWebCoreIncludes);
1301         print OUTPUTCPPImplementation "#pragma warning(pop)\n";
1302
1303         # Add content
1304         print OUTPUTCPPImplementation @CPPImplementationContent;
1305
1306         close(OUTPUTCPPImplementation);
1307
1308         @CPPImplementationHeader = ();
1309         @CPPImplementationContent = ();
1310     }
1311 }
1312
1313 1;