Add an 'isReadOnly' member to IDL parse tree structure
[WebKit-https.git] / Source / WebCore / bindings / scripts / CodeGeneratorCPP.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, 2009 Apple Inc. All rights reserved.
7 # Copyright (C) 2009 Cameron McCormack <cam@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 use constant FileNamePrefix => "WebDOM";
29
30 # Global Variables
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     shift; # $useLayerOnTop
99     shift; # $preprocessor
100     shift; # $writeDependencies
101
102     bless($reference, $object);
103     return $reference;
104 }
105
106 sub GenerateInterface
107 {
108     my $object = shift;
109     my $interface = shift;
110     my $defines = shift;
111
112     my $name = $interface->name;
113     my $className = GetClassName($name);
114     my $parentClassName = "WebDOM" . GetParentImplClassName($interface);
115
116     $object->GenerateHeader($interface);
117     $object->GenerateImplementation($interface);
118 }
119
120 sub GetClassName
121 {
122     my $name = shift;
123
124     # special cases
125     return "WebDOMString" if $codeGenerator->IsStringType($name) or $name eq "SerializedScriptValue";
126     return "WebDOMObject" if $name eq "any";
127     return "bool" if $name eq "boolean";
128     return $name if $codeGenerator->IsPrimitiveType($name);
129
130     return "WebDOM$name";
131 }
132
133 sub GetImplClassName
134 {
135     return shift;
136 }
137
138 sub GetParentImplClassName
139 {
140     my $interface = shift;
141
142     if (@{$interface->parents} eq 0) {
143         return "EventTarget" if $interface->extendedAttributes->{"EventTarget"};
144         return "Object";
145     }
146
147     return $interface->parents(0);
148 }
149
150 sub GetParent
151 {
152     my $interface = shift;
153     my $numParents = @{$interface->parents};
154
155     my $parent = "";
156     if ($numParents eq 0) {
157         $parent = "WebDOMObject";
158         $parent = "WebDOMEventTarget" if $interface->extendedAttributes->{"EventTarget"};
159     } elsif ($numParents eq 1) {
160         my $parentName = $interface->parents(0);
161         $parent = "WebDOM" . $parentName;
162     } else {
163         my @parents = @{$interface->parents};
164         my $firstParent = shift(@parents);
165         $parent = "WebDOM" . $firstParent;
166     }
167
168     return $parent;
169 }
170
171 sub SkipFunction
172 {
173     my $function = shift;
174
175     return 1 if $function->signature->extendedAttributes->{"Custom"};
176
177     # FIXME: We don't generate bindings for SVG related interfaces yet
178     return 1 if $function->signature->name =~ /getSVGDocument/;
179
180     if ($codeGenerator->GetArrayType($function->signature->type)) {
181         return 1;
182     }
183
184     if ($codeGenerator->GetSequenceType($function->signature->type)) {
185         return 1;
186     }
187
188     foreach my $param (@{$function->parameters}) {
189         return 1 if $codeGenerator->GetSequenceType($param->type);
190         return 1 if $param->extendedAttributes->{"Clamp"};
191     }
192
193     # FIXME: This is typically used to add script execution state arguments to the method.
194     # These functions will not compile with the C++ bindings as is, so disable them
195     # to restore compilation until a proper implementation can be developed.
196     return 1 if $function->signature->extendedAttributes->{"CallWith"};
197 }
198
199 sub SkipAttribute
200 {
201     my $attribute = shift;
202     my $type = $attribute->signature->type;
203
204     return 1 if $attribute->signature->extendedAttributes->{"Custom"}
205                 or $attribute->signature->extendedAttributes->{"CustomGetter"};
206
207     return 1 if $type =~ /Constructor$/;
208     return 1 if $attribute->isStatic;
209     return 1 if $codeGenerator->IsTypedArrayType($type);
210
211     if ($codeGenerator->GetArrayType($type)) {
212         return 1;
213     }
214
215     if ($codeGenerator->GetSequenceType($type)) {
216         return 1;
217     }
218
219     if ($codeGenerator->IsEnumType($type)) {
220         return 1;
221     }
222
223     $codeGenerator->AssertNotSequenceType($type);
224
225     # FIXME: This is typically used to add script execution state arguments to the method.
226     # These functions will not compile with the C++ bindings as is, so disable them
227     # to restore compilation until a proper implementation can be developed.
228     return 1 if $attribute->signature->extendedAttributes->{"CallWith"};
229
230     return 0;
231 }
232
233 sub GetCPPType
234 {
235     my $type = shift;
236     my $useConstReference = shift;
237     my $name = GetClassName($type);
238
239     return "int" if $type eq "long";
240     return "unsigned" if $name eq "unsigned long";
241     return "unsigned short" if $type eq "CompareHow";
242     return "double" if $name eq "Date";
243
244     if ($codeGenerator->IsStringType($type)) {
245         if ($useConstReference) {
246             return "const $name&";
247         }
248
249         return $name;
250     }
251
252     return $name if $codeGenerator->IsPrimitiveType($type) or $type eq "DOMTimeStamp";
253     return "const $name&" if $useConstReference;
254     return $name;
255 }
256
257 sub ConversionNeeded
258 {
259     my $type = shift;
260     return !$codeGenerator->IsNonPointerType($type) && !$codeGenerator->IsStringType($type);
261 }
262
263 sub GetCPPTypeGetter
264 {
265     my $argName = shift;
266     my $type = shift;
267
268     return $argName if $codeGenerator->IsPrimitiveType($type) or $codeGenerator->IsStringType($type);
269     return "static_cast<WebCore::Range::CompareHow>($argName)" if $type eq "CompareHow";
270     return "WebCore::SerializedScriptValue::create(WTF::String($argName))" if $type eq "SerializedScriptValue";
271     return "to" . GetNamespaceForClass($argName) . "($argName)";
272 }
273
274 sub AddForwardDeclarationsForType
275 {
276     my $type = shift;
277     my $public = shift;
278
279     return if $codeGenerator->IsNonPointerType($type) or $codeGenerator->IsStringType($type);
280
281     my $class = GetClassName($type);
282     $headerForwardDeclarations{$class} = 1 if $public;
283 }
284
285 sub AddIncludesForType
286 {
287     my $type = shift;
288
289     return if $codeGenerator->GetSequenceType($type);
290     return if $codeGenerator->GetArrayType($type);
291     return if $codeGenerator->IsNonPointerType($type);
292     return if $type =~ /Constructor/;
293
294     if ($codeGenerator->IsStringType($type)) {
295         $implIncludes{"wtf/text/AtomicString.h"} = 1;
296         $implIncludes{"KURL.h"} = 1;
297         $implIncludes{"WebDOMString.h"} = 1;
298         return;
299     }
300
301     if ($type eq "any") {
302         $implIncludes{"WebDOMObject.h"} = 1;
303         return;
304     }
305
306     if ($type eq "EventListener") {
307         $implIncludes{"WebNativeEventListener.h"} = 1;
308         return;
309     }
310
311     if ($type eq "SerializedScriptValue") {
312         $implIncludes{"SerializedScriptValue.h"} = 1;
313         return;
314     }
315
316     # Also include CSSImportRule so that the toWebKit methods for subclasses are found
317     if ($type eq "CSSRule") {
318         $implIncludes{"WebDOMCSSImportRule.h"} = 1;
319     }
320
321     $implIncludes{"Node.h"} = 1 if $type eq "NodeList";
322     $implIncludes{"StylePropertySet.h"} = 1 if $type eq "CSSStyleDeclaration";
323
324     # Default, include the same named file (the implementation) and the same name prefixed with "WebDOM". 
325     $implIncludes{"$type.h"} = 1 unless $type eq "any";
326     $implIncludes{"WebDOM$type.h"} = 1;
327 }
328
329 sub GetNamespaceForClass
330 {
331     my $type = shift;
332     return "WTF" if (($type eq "ArrayBuffer") or ($type eq "ArrayBufferView")); 
333     return "WTF" if (($type eq "Uint8Array") or ($type eq "Uint8ClampedArray") or ($type eq "Uint16Array") or ($type eq "Uint32Array")); 
334     return "WTF" if (($type eq "Int8Array") or ($type eq "Int16Array") or ($type eq "Int32Array")); 
335     return "WTF" if (($type eq "Float32Array") or ($type eq "Float64Array"));    
336     return "WebCore";
337 }
338
339 sub GenerateHeader
340 {
341     my $object = shift;
342     my $interface = shift;
343
344     my $interfaceName = $interface->name;
345     my $className = GetClassName($interfaceName);
346     my $implClassName = GetImplClassName($interfaceName);
347     
348     my $implClassNameWithNamespace = GetNamespaceForClass($implClassName) . "::" . $implClassName;
349
350     my $parentName = "";
351     $parentName = GetParent($interface);
352
353     my $numConstants = @{$interface->constants};
354     my $numAttributes = @{$interface->attributes};
355     my $numFunctions = @{$interface->functions};
356
357     # - Add default header template
358     @headerContentHeader = split("\r", $headerLicenseTemplate);
359     push(@headerContentHeader, "\n#ifndef $className" . "_h");
360     push(@headerContentHeader, "\n#define $className" . "_h\n\n");
361
362     my $conditionalString = $codeGenerator->GenerateConditionalString($interface);
363     push(@headerContentHeader, "#if ${conditionalString}\n\n") if $conditionalString;
364
365     # - INCLUDES -
366
367     my %headerIncludes = ();
368     $headerIncludes{"WebDOMString.h"} = 1;
369     $headerIncludes{"$parentName.h"} = 1;
370     foreach my $include (sort keys(%headerIncludes)) {
371         push(@headerContentHeader, "#include <$include>\n");
372     }
373
374     push(@headerContent, "class $className");
375     push(@headerContent, " : public $parentName") if $parentName;
376     push(@headerContent, " {\n");
377     push(@headerContent, "public:\n");
378
379     # Constructor
380     push(@headerContent, "    $className();\n");
381     push(@headerContent, "    explicit $className($implClassNameWithNamespace*);\n");
382
383     # Copy constructor and assignment operator on classes which have the d-ptr
384     if ($parentName eq "WebDOMObject") {
385         push(@headerContent, "    $className(const $className&);\n");
386         push(@headerContent, "    ${className}& operator=(const $className&);\n");
387     }
388
389     # Destructor
390     if ($parentName eq "WebDOMObject") {
391         push(@headerContent, "    virtual ~$className();\n");
392     } else {
393         push(@headerContent, "    virtual ~$className() { }\n");
394     }
395
396     push(@headerContent, "\n");
397     $headerForwardDeclarations{$implClassNameWithNamespace} = 1;
398
399     # - Add constants.
400     if ($numConstants > 0) {
401         my @headerConstants = ();
402         my @constants = @{$interface->constants};
403         my $combinedConstants = "";
404
405         # FIXME: we need a way to include multiple enums.
406         foreach my $constant (@constants) {
407             my $constantName = $constant->name;
408             my $constantValue = $constant->value;
409             my $conditional = $constant->extendedAttributes->{"Conditional"};
410             my $notLast = $constant ne $constants[-1];
411
412             if ($conditional) {
413                 my $conditionalString = $codeGenerator->GenerateConditionalStringFromAttributeValue($conditional);
414                 $combinedConstants .= "#if ${conditionalString}\n";
415             }
416             $combinedConstants .= "        WEBDOM_$constantName = $constantValue";
417             $combinedConstants .= "," if $notLast;
418             if ($conditional) {
419                 $combinedConstants .= "\n#endif\n";
420             } elsif ($notLast) {
421                 $combinedConstants .= "\n";
422             }
423         }
424
425         push(@headerContent, "    ");
426         push(@headerContent, "enum {\n");
427         push(@headerContent, $combinedConstants);
428         push(@headerContent, "\n    ");
429         push(@headerContent, "};\n\n");
430     }
431
432     my @headerAttributes = ();
433
434     # - Add attribute getters/setters.
435     if ($numAttributes > 0) {
436         foreach my $attribute (@{$interface->attributes}) {
437             next if SkipAttribute($attribute);
438
439             my $attributeConditionalString = $codeGenerator->GenerateConditionalString($attribute->signature);
440             my $attributeName = $attribute->signature->name;
441             my $attributeType = GetCPPType($attribute->signature->type, 0);
442             my $property = "";
443             
444             $property .= "#if ${attributeConditionalString}\n" if $attributeConditionalString;
445             $property .= "    " . $attributeType . ($attributeType =~ /\*$/ ? "" : " ") . $attributeName . "() const";
446
447             my $availabilityMacro = "";
448             my $declarationSuffix = ";\n";
449
450             AddForwardDeclarationsForType($attribute->signature->type, 1);
451
452             $attributeType = GetCPPType($attribute->signature->type, 1);
453             my $setterName = "set" . ucfirst($attributeName);
454
455             $property .= $declarationSuffix;
456             push(@headerAttributes, $property);
457             if (!$attribute->isReadOnly and !$attribute->signature->extendedAttributes->{"Replaceable"}) {
458                 $property = "    void $setterName($attributeType)";
459                 $property .= $declarationSuffix;
460                 push(@headerAttributes, $property); 
461             }
462
463             push(@headerAttributes, "#endif\n") if $attributeConditionalString;
464         }
465         push(@headerContent, @headerAttributes) if @headerAttributes > 0;
466     }
467
468     my @headerFunctions = ();
469     my @deprecatedHeaderFunctions = ();
470     my @interfaceFunctions = ();
471
472     # - Add functions.
473     if ($numFunctions > 0) {
474         foreach my $function (@{$interface->functions}) {
475             next if SkipFunction($function);
476             next if ($function->signature->name eq "set" and $interface->extendedAttributes->{"TypedArray"});
477             my $functionName = $function->signature->extendedAttributes->{"ImplementedAs"} || $function->signature->name;
478
479             my $returnType = GetCPPType($function->signature->type, 0);
480             my $numberOfParameters = @{$function->parameters};
481             my %typesToForwardDeclare = ($function->signature->type => 1);
482
483             my $parameterIndex = 0;
484             my $functionSig = "$returnType $functionName(";
485             my $methodName = $functionName;
486             foreach my $param (@{$function->parameters}) {
487                 my $paramName = $param->name;
488                 my $paramType = GetCPPType($param->type, 1);
489                 $typesToForwardDeclare{$param->type} = 1;
490
491                 $functionSig .= ", " if $parameterIndex >= 1;
492                 $functionSig .= "$paramType $paramName";
493                 $parameterIndex++;
494             }
495             $functionSig .= ")";
496             if ($interface->extendedAttributes->{"CPPPureInterface"}) {
497                 push(@interfaceFunctions, "    virtual " . $functionSig . " = 0;\n");
498             }
499             my $functionDeclaration = $functionSig;
500             $functionDeclaration .= ";\n";
501
502             foreach my $type (keys %typesToForwardDeclare) {
503                 # add any forward declarations to the public header if a deprecated version will be generated
504                 AddForwardDeclarationsForType($type, 1);
505             }
506
507             my $conditionalString = $codeGenerator->GenerateConditionalString($function->signature);
508             push(@headerFunctions, "#if ${conditionalString}\n") if $conditionalString;
509             push(@headerFunctions, "    ");
510             push(@headerFunctions, $functionDeclaration);
511             push(@headerFunctions, "#endif\n") if $conditionalString;
512         }
513
514         if (@headerFunctions > 0) {
515             push(@headerContent, "\n") if @headerAttributes > 0;
516             push(@headerContent, @headerFunctions);
517         }
518     }
519
520     push(@headerContent, "\n");
521     push(@headerContent, "    $implClassNameWithNamespace* impl() const;\n");
522
523     if ($parentName eq "WebDOMObject") {
524         push(@headerContent, "\nprotected:\n");
525         push(@headerContent, "    struct ${className}Private;\n");
526         push(@headerContent, "    ${className}Private* m_impl;\n");
527     }
528
529     push(@headerContent, "};\n\n");
530
531     # for CPPPureInterface classes also add the interface that the client code needs to
532     # implement
533     if ($interface->extendedAttributes->{"CPPPureInterface"}) {
534         push(@headerContent, "class WebUser$interfaceName {\n");
535         push(@headerContent, "public:\n");
536         push(@headerContent, "    virtual void ref() = 0;\n");
537         push(@headerContent, "    virtual void deref() = 0;\n\n");
538         push(@headerContent, @interfaceFunctions);
539         push(@headerContent, "\nprotected:\n");
540         push(@headerContent, "    virtual ~WebUser$interfaceName() {}\n");
541         push(@headerContent, "};\n\n");
542     }
543
544     my $namespace = GetNamespaceForClass($implClassName);
545     push(@headerContent, "$namespace" . "::$implClassName* toWebCore(const $className&);\n");
546     push(@headerContent, "$className toWebKit($namespace" . "::$implClassName*);\n");
547     if ($interface->extendedAttributes->{"CPPPureInterface"}) {
548         push(@headerContent, "$className toWebKit(WebUser$interfaceName*);\n");
549     }
550     push(@headerContent, "\n#endif\n");
551     push(@headerContent, "#endif // ${conditionalString}\n\n") if $conditionalString;
552 }
553
554 sub AddEarlyReturnStatement
555 {
556     my $returnType = shift;
557
558     if (!defined($returnType) or $returnType eq "void") {
559         $returnType = "";
560     } elsif ($codeGenerator->IsPrimitiveType($returnType)) {
561         $returnType = " 0";
562     } elsif ($returnType eq "bool") {
563         $returnType = " false";
564     } else {
565         $returnType = " $returnType()";
566     }
567
568     # TODO: We could set exceptions here, if we want that
569     my $statement = "    if (!impl())\n";
570     $statement .=   "        return$returnType;\n\n";
571     return $statement;
572 }
573
574 sub AddReturnStatement
575 {
576     my $typeInfo = shift;
577     my $returnValue = shift;
578
579     # Used to invoke KURLs "const String&" operator
580     if ($codeGenerator->IsStringType($typeInfo->signature->type)) {
581         return "    return static_cast<const WTF::String&>($returnValue);\n";
582     }
583
584     return "    return $returnValue;\n";
585 }
586
587 sub GenerateImplementation
588 {
589     my $object = shift;
590     my $interface = shift;
591
592     my @ancestorInterfaceNames = ();
593
594     if (@{$interface->parents} > 1) {
595         $codeGenerator->AddMethodsConstantsAndAttributesFromParentInterfaces($interface, \@ancestorInterfaceNames);
596     }
597
598     my $interfaceName = $interface->name;
599     my $className = GetClassName($interfaceName);
600     my $implClassName = GetImplClassName($interfaceName);
601     my $parentImplClassName = GetParentImplClassName($interface);
602     my $implClassNameWithNamespace = GetNamespaceForClass($implClassName) . "::" . $implClassName;
603     my $baseClass = "WebDOM$parentImplClassName";
604     my $conditional = $interface->extendedAttributes->{"Conditional"};
605
606     my $numAttributes = @{$interface->attributes};
607     my $numFunctions = @{$interface->functions};
608
609     # - Add default header template.
610     @implContentHeader = split("\r", $implementationLicenseTemplate);
611
612     # - INCLUDES -
613     push(@implContentHeader, "\n#include \"config.h\"\n");
614     my $conditionalString = $codeGenerator->GenerateConditionalString($interface);
615     push(@implContentHeader, "\n#if ${conditionalString}\n\n") if $conditionalString;
616     push(@implContentHeader, "#include \"$className.h\"\n\n");
617
618     $implIncludes{"WebExceptionHandler.h"} = 1;
619     $implIncludes{"$implClassName.h"} = 1;
620     @implContent = ();
621
622     push(@implContent, "#include <wtf/GetPtr.h>\n");
623     push(@implContent, "#include <wtf/RefPtr.h>\n\n");
624
625     # Private datastructure, encapsulating WebCore types
626     if ($baseClass eq "WebDOMObject") {
627         push(@implContent, "struct ${className}::${className}Private {\n");
628         push(@implContent, "    ${className}Private($implClassNameWithNamespace* object = 0)\n");
629         push(@implContent, "        : impl(object)\n");
630         push(@implContent, "    {\n");
631         push(@implContent, "    }\n\n");
632         push(@implContent, "    RefPtr<$implClassNameWithNamespace> impl;\n");
633         push(@implContent, "};\n\n");
634     }
635
636     # Constructor
637     push(@implContent, "${className}::$className()\n");
638     push(@implContent, "    : ${baseClass}()\n");
639     push(@implContent, "    , m_impl(0)\n") if ($baseClass eq "WebDOMObject");
640     push(@implContent, "{\n");
641     push(@implContent, "}\n\n");
642
643     push(@implContent, "${className}::$className($implClassNameWithNamespace* impl)\n");
644     if ($baseClass eq "WebDOMObject") {
645         push(@implContent, "    : ${baseClass}()\n");
646         push(@implContent, "    , m_impl(new ${className}Private(impl))\n");
647         push(@implContent, "{\n");
648         push(@implContent, "}\n\n");
649
650         push(@implContent, "${className}::${className}(const ${className}& copy)\n");
651         push(@implContent, "    : ${baseClass}()\n");
652         push(@implContent, "{\n");
653         push(@implContent, "    m_impl = copy.impl() ? new ${className}Private(copy.impl()) : 0;\n");
654         push(@implContent, "}\n\n");
655
656         push(@implContent, "${className}& ${className}::operator\=(const ${className}& copy)\n");
657         push(@implContent, "{\n");
658         push(@implContent, "    delete m_impl;\n");
659         push(@implContent, "    m_impl = copy.impl() ? new ${className}Private(copy.impl()) : 0;\n");
660         push(@implContent, "    return *this;\n");
661         push(@implContent, "}\n\n");
662
663         push(@implContent, "$implClassNameWithNamespace* ${className}::impl() const\n");
664         push(@implContent, "{\n");
665         push(@implContent, "    return m_impl ? WTF::getPtr(m_impl->impl) : 0;\n");
666         push(@implContent, "}\n\n");
667
668         # Destructor
669         push(@implContent, "${className}::~$className()\n");
670         push(@implContent, "{\n");
671         push(@implContent, "    delete m_impl;\n");
672         push(@implContent, "    m_impl = 0;\n");
673         push(@implContent, "}\n\n");
674     } else {
675         push(@implContent, "    : ${baseClass}(impl)\n");
676         push(@implContent, "{\n");
677         push(@implContent, "}\n\n");
678
679         push(@implContent, "$implClassNameWithNamespace* ${className}::impl() const\n");
680         push(@implContent, "{\n");
681         push(@implContent, "    return static_cast<$implClassNameWithNamespace*>(${baseClass}::impl());\n");
682         push(@implContent, "}\n\n");
683     }
684
685     # START implementation
686     %attributeNames = ();
687
688     # - Attributes
689     if ($numAttributes > 0) {
690         foreach my $attribute (@{$interface->attributes}) {
691             next if SkipAttribute($attribute);
692             AddIncludesForType($attribute->signature->type);
693
694             my $idlType = $attribute->signature->type;
695
696             my $attributeName = $attribute->signature->name;
697             my $attributeType = GetCPPType($attribute->signature->type, 0);
698             my $attributeIsNullable = $attribute->signature->isNullable;
699
700             $attributeNames{$attributeName} = 1;
701
702             # - GETTER
703             my $getterSig = "$attributeType $className\:\:$attributeName() const\n";
704             my $hasGetterException = @{$attribute->getterExceptions};
705             my ($functionName, @arguments) = $codeGenerator->GetterExpression(\%implIncludes, $interfaceName, $attribute);
706             push(@arguments, "isNull") if $attributeIsNullable;
707             push(@arguments, "ec") if $hasGetterException;
708             if ($attribute->signature->extendedAttributes->{"ImplementedBy"}) {
709                 my $implementedBy = $attribute->signature->extendedAttributes->{"ImplementedBy"};
710                 $implIncludes{"${implementedBy}.h"} = 1;
711                 unshift(@arguments, "impl()");
712                 $functionName = "${implementedBy}::${functionName}";
713             } else {
714                 $functionName = "impl()->${functionName}";
715             }
716
717             # Special cases
718             my $getterContentHead = "";
719             my $getterContentTail = "";
720             my @customGetterContent = (); 
721             if ($attribute->signature->extendedAttributes->{"ConvertToString"}) {
722                 $getterContentHead = "WTF::String::number(";
723                 $getterContentTail = ")";
724             } elsif ($attribute->signature->type eq "SerializedScriptValue") {
725                 $getterContentTail = "->toString()";
726             } elsif (ConversionNeeded($attribute->signature->type)) {
727                 $getterContentHead = "toWebKit(WTF::getPtr(";
728                 $getterContentTail = "))";
729             }
730
731             my $getterContent = "${getterContentHead}${functionName}(" . join(", ", @arguments) . ")${getterContentTail}";
732             my $attributeConditionalString = $codeGenerator->GenerateConditionalString($attribute->signature);
733             push(@implContent, "#if ${attributeConditionalString}\n") if $attributeConditionalString;
734
735             push(@implContent, $getterSig);
736             push(@implContent, "{\n");
737             push(@implContent, AddEarlyReturnStatement($attributeType));
738             push(@implContent, @customGetterContent);
739
740             # FIXME: Should we return a default value when isNull == true?
741             if ($attributeIsNullable) {
742                 push(@implContent, "    bool isNull = false;\n");
743             }
744
745             if ($hasGetterException) {
746                 # Differentiated between when the return type is a pointer and
747                 # not for white space issue (ie. Foo *result vs. int result).
748                 if ($attributeType =~ /\*$/) {
749                     $getterContent = $attributeType . "result = " . $getterContent;
750                 } else {
751                     $getterContent = $attributeType . " result = " . $getterContent;
752                 }
753
754                 push(@implContent, "    $exceptionInit\n");
755                 push(@implContent, "    $getterContent;\n");
756                 push(@implContent, "    $exceptionRaiseOnError\n");
757                 push(@implContent, AddReturnStatement($attribute, "result"));
758             } else {
759                 push(@implContent, AddReturnStatement($attribute, $getterContent));
760             }
761             push(@implContent, "}\n\n");
762
763             # - SETTER
764             if (!$attribute->isReadOnly and !$attribute->signature->extendedAttributes->{"Replaceable"}) {
765                 # Exception handling
766                 my $hasSetterException = @{$attribute->setterExceptions};
767
768                 my $coreSetterName = "set" . $codeGenerator->WK_ucfirst($attributeName);
769                 my $setterName = "set" . ucfirst($attributeName);
770                 my $argName = "new" . ucfirst($attributeName);
771                 my $arg = GetCPPTypeGetter($argName, $idlType);
772
773                 my $attributeType = GetCPPType($attribute->signature->type, 1);
774                 push(@implContent, "void $className\:\:$setterName($attributeType $argName)\n");
775                 push(@implContent, "{\n");
776                 push(@implContent, AddEarlyReturnStatement());
777
778                 push(@implContent, "    $exceptionInit\n") if $hasSetterException;
779
780                 my ($functionName, @arguments) = $codeGenerator->SetterExpression(\%implIncludes, $interfaceName, $attribute);
781                 push(@arguments, $arg);
782                 push(@arguments, "ec") if $hasSetterException;
783                 if ($attribute->signature->extendedAttributes->{"ImplementedBy"}) {
784                     my $implementedBy = $attribute->signature->extendedAttributes->{"ImplementedBy"};
785                     $implIncludes{"${implementedBy}.h"} = 1;
786                     unshift(@arguments, "impl()");
787                     $functionName = "${implementedBy}::${functionName}";
788                 } else {
789                     $functionName = "impl()->${functionName}";
790                 }
791                 push(@implContent, "    ${functionName}(" . join(", ", @arguments) . ");\n");
792                 push(@implContent, "    $exceptionRaiseOnError\n") if $hasSetterException;
793                 push(@implContent, "}\n\n");
794             }
795
796             push(@implContent, "#endif\n") if $attributeConditionalString;
797         }
798     }
799
800     # - Functions
801     if ($numFunctions > 0) {
802         foreach my $function (@{$interface->functions}) {
803             # Treat CPPPureInterface as Custom as well, since the WebCore versions will take a script context as well
804             next if SkipFunction($function) || $interface->extendedAttributes->{"CPPPureInterface"};
805             next if ($function->signature->name eq "set" and $interface->extendedAttributes->{"TypedArray"});
806             AddIncludesForType($function->signature->type);
807
808             my $functionName = $function->signature->name;
809             my $returnType = GetCPPType($function->signature->type, 0);
810             my $hasParameters = @{$function->parameters};
811             my $raisesExceptions = @{$function->raisesExceptions};
812
813             my @parameterNames = ();
814             my @needsAssert = ();
815             my %needsCustom = ();
816
817             my $parameterIndex = 0;
818
819             my $functionSig = "$returnType $className\:\:$functionName(";
820             foreach my $param (@{$function->parameters}) {
821                 my $paramName = $param->name;
822                 my $paramType = GetCPPType($param->type, 1);
823
824                 # make a new parameter name if the original conflicts with a property name
825                 $paramName = "in" . ucfirst($paramName) if $attributeNames{$paramName};
826
827                 AddIncludesForType($param->type);
828
829                 my $idlType = $param->type;
830                 my $implGetter = GetCPPTypeGetter($paramName, $idlType);
831
832                 push(@parameterNames, $implGetter);
833                 $needsCustom{"NodeToReturn"} = $paramName if $param->extendedAttributes->{"CustomReturn"};
834
835                 unless ($codeGenerator->IsPrimitiveType($idlType) or $codeGenerator->IsStringType($idlType)) {
836                     push(@needsAssert, "    ASSERT($paramName);\n");
837                 }
838
839                 $functionSig .= ", " if $parameterIndex >= 1;
840                 $functionSig .= "$paramType $paramName";
841                 $parameterIndex++;
842             }
843
844             $functionSig .= ")";
845
846             my @functionContent = ();
847             push(@parameterNames, "ec") if $raisesExceptions;
848
849             my $content;
850             if ($function->signature->extendedAttributes->{"ImplementedBy"}) {
851                 my $implementedBy = $function->signature->extendedAttributes->{"ImplementedBy"};
852                 $implIncludes{"${implementedBy}.h"} = 1;
853                 unshift(@parameterNames, "impl()");
854                 $content = "WebCore::${implementedBy}::" . $codeGenerator->WK_lcfirst($functionName) . "(" . join(", ", @parameterNames) . ")";
855             } else {
856                 $content = "impl()->" . $codeGenerator->WK_lcfirst($functionName) . "(" . join(", ", @parameterNames) . ")";
857             }
858
859             if ($returnType eq "void") {
860                 # Special case 'void' return type.
861                 if ($raisesExceptions) {
862                     push(@functionContent, "    $exceptionInit\n");
863                     push(@functionContent, "    $content;\n");
864                     push(@functionContent, "    $exceptionRaiseOnError\n");
865                 } else {
866                     push(@functionContent, "    $content;\n");
867                 }
868             } elsif (defined $needsCustom{"NodeToReturn"}) {
869                 # TODO: This is important to enable, once we care about custom code!
870
871                 # Special case the insertBefore, replaceChild, removeChild 
872                 # and appendChild functions from DOMNode 
873                 my $toReturn = $needsCustom{"NodeToReturn"};
874                 if ($raisesExceptions) {
875                     push(@functionContent, "    $exceptionInit\n");
876                     push(@functionContent, "    if ($content)\n");
877                     push(@functionContent, "        return $toReturn;\n");
878                     push(@functionContent, "    $exceptionRaiseOnError\n");
879                     push(@functionContent, "    return $className();\n");
880                 } else {
881                     push(@functionContent, "    if ($content)\n");
882                     push(@functionContent, "        return $toReturn;\n");
883                     push(@functionContent, "    return NULL;\n");
884                 }
885             } else {
886                 if (ConversionNeeded($function->signature->type)) {
887                     $content = "toWebKit(WTF::getPtr($content))";
888                 }
889
890                 if ($raisesExceptions) {
891                     # Differentiated between when the return type is a pointer and
892                     # not for white space issue (ie. Foo *result vs. int result).
893                     if ($returnType =~ /\*$/) {
894                         $content = $returnType . "result = " . $content;
895                     } else {
896                         $content = $returnType . " result = " . $content;
897                     }
898
899                     push(@functionContent, "    $exceptionInit\n");
900                     push(@functionContent, "    $content;\n");
901                     push(@functionContent, "    $exceptionRaiseOnError\n");
902                     push(@functionContent, "    return result;\n");
903                 } else {
904                     push(@functionContent, "    return $content;\n");
905                 }
906             }
907
908             my $conditionalString = $codeGenerator->GenerateConditionalString($function->signature);
909             push(@implContent, "\n#if ${conditionalString}\n") if $conditionalString;
910
911             push(@implContent, "$functionSig\n");
912             push(@implContent, "{\n");
913             push(@implContent, AddEarlyReturnStatement($returnType));
914             push(@implContent, @functionContent);
915             push(@implContent, "}\n\n");
916
917             push(@implContent, "#endif\n\n") if $conditionalString;
918
919             # Clear the hash
920             %needsCustom = ();
921         }
922     }
923
924     # END implementation
925
926     # Generate internal interfaces
927     my $namespace = GetNamespaceForClass($implClassName);
928     push(@implContent, "$namespace" . "::$implClassName* toWebCore(const $className& wrapper)\n");
929     push(@implContent, "{\n");
930     push(@implContent, "    return wrapper.impl();\n");
931     push(@implContent, "}\n\n");
932
933     push(@implContent, "$className toWebKit($namespace" . "::$implClassName* value)\n");
934     push(@implContent, "{\n");
935     push(@implContent, "    return $className(value);\n");
936     push(@implContent, "}\n");
937
938     # - End the ifdef conditional if necessary
939     push(@implContent, "\n#endif // ${conditionalString}\n") if $conditionalString;
940 }
941
942 sub WriteData
943 {
944     my $object = shift;
945     my $dataNode = shift;
946     my $outputDir = shift;
947
948     # Open files for writing...
949     my $name = $dataNode->name;
950     my $prefix = FileNamePrefix;
951     my $headerFileName = "$outputDir/$prefix$name.h";
952     my $implFileName = "$outputDir/$prefix$name.cpp";
953
954     # Update a .h file if the contents are changed.
955     my $contents = join "", @headerContentHeader;
956     $contents .= "\n";
957     foreach my $class (sort keys(%headerForwardDeclarations)) {
958         if ($class =~ /::/) {
959             my $namespacePart = $class;
960             $namespacePart =~ s/::.*//;
961
962             my $classPart = $class;
963             $classPart =~ s/${namespacePart}:://;
964
965             $contents .= "namespace $namespacePart {\nclass $classPart;\n};\n\n";
966         } else {
967             $contents .= "class $class;\n"
968         }
969     }
970
971     my $hasForwardDeclarations = keys(%headerForwardDeclarations);
972     $contents .= "\n" if $hasForwardDeclarations;
973     $contents .= join "", @headerContent;
974     $codeGenerator->UpdateFile($headerFileName, $contents);
975
976     @headerContentHeader = ();
977     @headerContent = ();
978     %headerForwardDeclarations = ();
979
980     # Update a .cpp file if the contents are changed.
981     $contents = join "", @implContentHeader;
982
983     foreach my $include (sort keys(%implIncludes)) {
984         # "className.h" is already included right after config.h, silence check-webkit-style
985         next if $include eq "$name.h";
986         $contents .= "#include \"$include\"\n";
987     }
988
989     $contents .= join "", @implContent;
990     $codeGenerator->UpdateFile($implFileName, $contents);
991
992     @implContentHeader = ();
993     @implContent = ();
994     %implIncludes = ();
995 }
996
997 1;