2009-07-07 Nate Chapin <japhet@chromium.org>
[WebKit-https.git] / WebCore / bindings / scripts / CodeGeneratorV8.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 Samuel Weinig <sam.weinig@gmail.com>
5 # Copyright (C) 2006 Alexey Proskuryakov <ap@webkit.org>
6 # Copyright (C) 2006 Apple Computer, Inc.
7 # Copyright (C) 2007, 2008, 2009 Google Inc.
8 #
9 # This file is part of the KDE project
10 #
11 # This library is free software; you can redistribute it and/or
12 # modify it under the terms of the GNU Library General Public
13 # License as published by the Free Software Foundation; either
14 # version 2 of the License, or (at your option) any later version.
15 #
16 # This library is distributed in the hope that it will be useful,
17 # but WITHOUT ANY WARRANTY; without even the implied warranty of
18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19 # Library General Public License for more details.
20 #
21 # You should have received a copy of the GNU Library General Public License
22 # aint with this library; see the file COPYING.LIB.  If not, write to
23 # the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
24 # Boston, MA 02111-1307, USA.
25 #
26
27 package CodeGeneratorV8;
28
29 use File::stat;
30
31 my $module = "";
32 my $outputDir = "";
33
34 my @headerContent = ();
35 my @implContentHeader = ();
36 my @implFixedHeader = ();
37 my @implContent = ();
38 my @implContentDecls = ();
39 my %implIncludes = ();
40
41 my @allParents = ();
42
43 # Default .h template
44 my $headerTemplate = << "EOF";
45 /*
46     This file is part of the WebKit open source project.
47     This file has been generated by generate-bindings.pl. DO NOT MODIFY!
48
49     This library is free software; you can redistribute it and/or
50     modify it under the terms of the GNU Library General Public
51     License as published by the Free Software Foundation; either
52     version 2 of the License, or (at your option) any later version.
53
54     This library is distributed in the hope that it will be useful,
55     but WITHOUT ANY WARRANTY; without even the implied warranty of
56     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
57     Library General Public License for more details.
58
59     You should have received a copy of the GNU Library General Public License
60     along with this library; see the file COPYING.LIB.  If not, write to
61     the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
62     Boston, MA 02111-1307, USA.
63 */
64 EOF
65
66 # Default constructor
67 sub new
68 {
69     my $object = shift;
70     my $reference = { };
71
72     $codeGenerator = shift;
73     $outputDir = shift;
74
75     bless($reference, $object);
76     return $reference;
77 }
78
79 sub finish
80 {
81     my $object = shift;
82
83     # Commit changes!
84     $object->WriteData();
85 }
86
87 sub leftShift($$) {
88     my ($value, $distance) = @_;
89     return (($value << $distance) & 0xFFFFFFFF);
90 }
91
92 # Uppercase the first letter, while respecting WebKit style guidelines.
93 # E.g., xmlEncoding becomes XMLEncoding, but xmlllang becomes Xmllang.
94 sub WK_ucfirst
95 {
96     my $param = shift;
97     my $ret = ucfirst($param);
98     $ret =~ s/Xml/XML/ if $ret =~ /^Xml[^a-z]/;
99     return $ret;
100 }
101
102 # Lowercase the first letter while respecting WebKit style guidelines.
103 # URL becomes url, but SetURL becomes setURL.
104 sub WK_lcfirst
105 {
106     my $param = shift;
107     my $ret = lcfirst($param);
108     $ret =~ s/uRL/url/;
109     return $ret;
110 }
111
112 # Workaround for V8 bindings difference where RGBColor is not a POD type.
113 sub IsPodType
114 {
115     my $type = shift;
116     return 0 if $type eq "RGBColor";
117     return $codeGenerator->IsPodType($type);
118 }
119
120 # Params: 'domClass' struct
121 sub GenerateInterface
122 {
123     my $object = shift;
124     my $dataNode = shift;
125     my $defines = shift;
126
127     # Start actual generation
128     $object->GenerateHeader($dataNode);
129     $object->GenerateImplementation($dataNode);
130
131     my $name = $dataNode->name;
132
133     # Open files for writing
134     my $headerFileName = "$outputDir/V8$name.h";
135     my $implFileName = "$outputDir/V8$name.cpp";
136
137     open($IMPL, ">$implFileName") || die "Couldn't open file $implFileName";
138     open($HEADER, ">$headerFileName") || die "Couldn't open file $headerFileName";
139 }
140
141 # Params: 'idlDocument' struct
142 sub GenerateModule
143 {
144     my $object = shift;
145     my $dataNode = shift;
146
147     $module = $dataNode->module;
148 }
149
150 sub GetLegacyHeaderIncludes
151 {
152     my $legacyParent = shift;
153
154     die "Don't know what headers to include for module $module";
155 }
156
157 sub AvoidInclusionOfType
158 {
159     my $type = shift;
160
161     # Special case: SVGRect.h / SVGPoint.h / SVGNumber.h / SVGMatrix.h do not exist.
162     return 1 if $type eq "SVGRect" or $type eq "SVGPoint" or $type eq "SVGNumber" or $type eq "SVGMatrix";
163     return 0;
164 }
165
166 sub UsesManualToJSImplementation
167 {
168     my $type = shift;
169
170     return 1 if $type eq "SVGPathSeg";
171     return 0;
172 }
173
174 sub AddIncludesForType
175 {
176     my $type = $codeGenerator->StripModule(shift);
177
178     # When we're finished with the one-file-per-class
179     # reorganization, we won't need these special cases.
180     if ($codeGenerator->IsPrimitiveType($type) or AvoidInclusionOfType($type)) {
181     } elsif ($type =~ /SVGPathSeg/) {
182         $joinedName = $type;
183         $joinedName =~ s/Abs|Rel//;
184         $implIncludes{"${joinedName}.h"} = 1;
185     } else {
186         # default, include the same named file
187         $implIncludes{GetImplementationFileName(${type})} = 1;
188     }
189
190     # additional includes (things needed to compile the bindings but not the header)
191
192     if ($type eq "CanvasRenderingContext2D") {
193         $implIncludes{"CanvasGradient.h"} = 1;
194         $implIncludes{"CanvasPattern.h"} = 1;
195         $implIncludes{"CanvasStyle.h"} = 1;
196     }
197
198     if ($type eq "CanvasGradient" or $type eq "XPathNSResolver") {
199         $implIncludes{"PlatformString.h"} = 1;
200     }
201
202     if ($type eq "CSSStyleDeclaration") {
203         $implIncludes{"CSSMutableStyleDeclaration.h"} = 1;
204     }
205
206     if ($type eq "Plugin" or $type eq "PluginArray" or $type eq "MimeTypeArray") {
207         # So we can get String -> AtomicString conversion for namedItem().
208         $implIncludes{"AtomicString.h"} = 1;
209     }
210 }
211
212 sub AddIncludesForSVGAnimatedType
213 {
214     my $type = shift;
215     $type =~ s/SVGAnimated//;
216
217     if ($type eq "Point" or $type eq "Rect") {
218         $implIncludes{"Float$type.h"} = 1;
219     } elsif ($type eq "String") {
220         $implIncludes{"PlatformString.h"} = 1;
221     }
222
223     $implIncludes{"SVGAnimatedTemplate.h"} = 1;
224 }
225
226 sub AddClassForwardIfNeeded
227 {
228     my $implClassName = shift;
229
230     # SVGAnimatedLength/Number/etc.. are typedefs to SVGAnimtatedTemplate, so don't use class forwards for them!
231     push(@headerContent, "class $implClassName;\n\n") unless $codeGenerator->IsSVGAnimatedType($implClassName);
232 }
233
234 sub GetImplementationFileName
235 {
236     my $iface = shift;
237     return "HTMLCollection.h" if $iface eq "UndetectableHTMLCollection";
238     return "Event.h" if $iface eq "DOMTimeStamp";
239     return "NamedAttrMap.h" if $iface eq "NamedNodeMap";
240     return "NameNodeList.h" if $iface eq "NodeList";
241     return "XMLHttpRequest.h" if $iface eq "XMLHttpRequest";
242
243     return "${iface}.h";
244 }
245
246 sub GenerateHeader
247 {
248     my $object = shift;
249     my $dataNode = shift;
250
251     my $interfaceName = $dataNode->name;
252     my $className = "V8$interfaceName";
253     my $implClassName = $interfaceName;
254
255     # Copy contents of parent classes except the first parent or if it is
256     # EventTarget.
257     $codeGenerator->AddMethodsConstantsAndAttributesFromParentClasses($dataNode);
258
259     my $hasLegacyParent = $dataNode->extendedAttributes->{"LegacyParent"};
260     my $conditional = $dataNode->extendedAttributes->{"Conditional"};
261
262     # - Add default header template
263     @headerContent = split("\r", $headerTemplate);
264
265     my $conditionalString;
266     if ($conditional) {
267         $conditionalString = "ENABLE(" . join(") && ENABLE(", split(/&/, $conditional)) . ")";
268         push(@headerContent, "\n#if ${conditionalString}\n\n");
269     }
270
271     push(@headerContent, "\n#ifndef $className" . "_H");
272     push(@headerContent, "\n#define $className" . "_H\n\n");
273
274     # Get correct pass/store types respecting PODType flag
275     my $podType = $dataNode->extendedAttributes->{"PODType"};
276     my $passType = $podType ? "JSSVGPODTypeWrapper<$podType>*" : "$implClassName*";
277
278     push(@headerContent, "#include \"$podType.h\"\n") if $podType and ($podType ne "double" and $podType ne "float" and $podType ne "RGBA32");
279
280     push(@headerContent, "#include <v8.h>\n");
281     push(@headerContent, "#include <wtf/HashMap.h>\n");
282     push(@headerContent, "#include \"StringHash.h\"\n");
283
284     push(@headerContent, "\nnamespace WebCore {\n\n");
285     push(@headerContent, "class V8ClassIndex;\n");
286     push(@headerContent, "\nclass $className {\n");
287     push(@headerContent, <<END);
288
289  public:
290   static bool HasInstance(v8::Handle<v8::Value> value);
291   static v8::Persistent<v8::FunctionTemplate> GetRawTemplate();
292 END
293
294     if ($implClassName eq "DOMWindow") {
295       push(@headerContent, <<END);
296   static v8::Persistent<v8::ObjectTemplate> GetShadowObjectTemplate();
297 END
298     }
299
300     push(@headerContent, <<END);
301
302  private:
303   static v8::Persistent<v8::FunctionTemplate> GetTemplate();
304
305   friend class V8ClassIndex;
306 };
307
308 END
309
310     push(@headerContent, "}\n\n");
311     push(@headerContent, "#endif // $className" . "_H\n");
312
313     push(@headerContent, "#endif // ${conditionalString}\n\n") if $conditional;
314 }
315
316
317 sub GenerateSetDOMException
318 {
319     my $indent = shift;
320     my $result = "";
321
322     $result .= $indent . "if (ec) {\n";
323     $result .= $indent . "    V8Proxy::setDOMException(ec);\n";
324     $result .= $indent . "    return v8::Handle<v8::Value>();\n";
325     $result .= $indent . "}\n";
326
327     return $result;
328 }
329
330 sub IsNodeSubType
331 {
332     my $dataNode = shift;
333     return 1 if ($dataNode->name eq "Node");
334     foreach (@allParents) {
335         my $parent = $codeGenerator->StripModule($_);
336         return 1 if $parent eq "Node";
337     }
338     return 0;
339 }
340
341 sub HolderToNative
342 {
343     my $dataNode = shift;
344     my $implClassName = shift;
345     my $classIndex = shift;
346
347     if (IsNodeSubType($dataNode)) {
348         push(@implContentDecls, <<END);
349     $implClassName* imp = V8Proxy::convertDOMWrapperToNode<$implClassName>(holder);
350 END
351
352     } else {
353         push(@implContentDecls, <<END);
354     $implClassName* imp = V8Proxy::convertToNativeObject<$implClassName>(V8ClassIndex::$classIndex, holder);
355 END
356
357   }
358 }
359
360 sub GenerateDomainSafeFunctionGetter
361 {
362     my $function = shift;
363     my $dataNode = shift;
364     my $classIndex = shift;
365     my $implClassName = shift;
366
367     my $className = "V8" . $dataNode->name;
368     my $funcName = $function->signature->name;
369
370     my $signature = "v8::Signature::New(" . $className . "::GetRawTemplate())";
371     if ($function->signature->extendedAttributes->{"V8DoNotCheckSignature"}) {
372         $signature = "v8::Local<v8::Signature>()";
373     }
374
375     my $newTemplateString = GenerateNewFunctionTemplate($function, $dataNode, $signature);
376
377     $implIncludes{"V8Proxy.h"} = 1;
378
379     push(@implContentDecls, <<END);
380   static v8::Handle<v8::Value> ${funcName}AttrGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info) {
381     INC_STATS(\"DOM.$implClassName.$funcName._get\");
382     static v8::Persistent<v8::FunctionTemplate> private_template =
383         v8::Persistent<v8::FunctionTemplate>::New($newTemplateString);
384     v8::Handle<v8::Object> holder = V8Proxy::lookupDOMWrapper(V8ClassIndex::$classIndex, info.This());
385     if (holder.IsEmpty()) {
386       // can only reach here by 'object.__proto__.func', and it should passed
387       // domain security check already
388
389       return private_template->GetFunction();
390     }
391 END
392
393   HolderToNative($dataNode, $implClassName, $classIndex);
394
395     push(@implContentDecls, <<END);
396     if (!V8Proxy::canAccessFrame(imp->frame(), false)) {
397       static v8::Persistent<v8::FunctionTemplate> shared_template =
398         v8::Persistent<v8::FunctionTemplate>::New($newTemplateString);
399       return shared_template->GetFunction();
400
401     } else {
402       return private_template->GetFunction();
403     }
404   }
405
406 END
407 }
408
409 sub GenerateConstructorGetter
410 {
411     my $implClassName = shift;
412     my $classIndex = shift;
413
414     push(@implContentDecls, <<END);
415   static v8::Handle<v8::Value> ${implClassName}ConstructorGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info) {
416     INC_STATS(\"DOM.$implClassName.constructors._get\");
417     v8::Handle<v8::Value> data = info.Data();
418     ASSERT(data->IsNumber());
419     V8ClassIndex::V8WrapperType type = V8ClassIndex::FromInt(data->Int32Value());
420 END
421
422     if ($classIndex eq "DOMWINDOW") {
423         push(@implContentDecls, <<END);
424     DOMWindow* window = V8Proxy::convertToNativeObject<DOMWindow>(V8ClassIndex::DOMWINDOW, info.Holder());
425     Frame* frame = window->frame();
426     if (frame) {
427       // Get the proxy corresponding to the DOMWindow if possible to
428       // make sure that the constructor function is constructed in the
429       // context of the DOMWindow and not in the context of the caller.
430       return V8Proxy::retrieve(frame)->getConstructor(type);
431     }
432 END
433   }
434
435     if ($classIndex eq "WORKERCONTEXT") {
436         $implIncludes{"WorkerContextExecutionProxy.h"} = 1;
437         push(@implContentDecls, <<END);
438     return WorkerContextExecutionProxy::retrieve()->GetConstructor(type);
439 END
440     } else {
441         push(@implContentDecls, "    return v8::Undefined();");
442     }
443
444     push(@implContentDecls, <<END);
445
446     }
447
448 END
449 }
450
451 sub GenerateNormalAttrGetter
452 {
453     my $attribute = shift;
454     my $dataNode = shift;
455     my $classIndex = shift;
456     my $implClassName = shift;
457
458     my $attrExt = $attribute->signature->extendedAttributes;
459
460     my $attrName = $attribute->signature->name;
461     $implIncludes{"V8Proxy.h"} = 1;
462
463     my $attrType = $codeGenerator->StripModule($attribute->signature->type);
464     my $attrIsPodType = IsPodType($attrType);
465
466     my $nativeType = GetNativeTypeFromSignature($attribute->signature, 0);
467     my $isPodType = IsPodType($implClassName);
468     my $skipContext = 0;
469
470
471     if ($isPodType) {
472         $implClassName = GetNativeType($implClassName);
473         $implIncludes{"V8SVGPODTypeWrapper.h"} = 1;
474     }
475
476     # Special case: SVGZoomEvent's attributes are all read-only
477     if ($implClassName eq "SVGZoomEvent") {
478         $attrIsPodType = 0;
479         $skipContext = 1;
480     }
481
482     # Special case: SVGSVGEelement::viewport is read-only
483     if (($implClassName eq "SVGSVGElement") and ($attrName eq "viewport")) {
484         $attrIsPodType = 0;
485         $skipContext = 1;
486     }
487
488     # Special case for SVGColor
489     if (($implClassName eq "SVGColor") and ($attrName eq "rgbColor")) {
490         $attrIsPodType = 0;
491     }
492
493     my $getterStringUsesImp = $implClassName ne "double";
494
495   # Getter
496     push(@implContentDecls, <<END);
497   static v8::Handle<v8::Value> ${attrName}AttrGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info) {
498     INC_STATS(\"DOM.$implClassName.$attrName._get\");
499 END
500
501     if ($isPodType) {
502         push(@implContentDecls, <<END);
503     V8SVGPODTypeWrapper<$implClassName>* imp_wrapper = V8Proxy::convertToNativeObject<V8SVGPODTypeWrapper<$implClassName> >(V8ClassIndex::$classIndex, info.Holder());
504     $implClassName imp_instance = *imp_wrapper;
505 END
506         if ($getterStringUsesImp) {
507             push(@implContentDecls, <<END);
508     $implClassName* imp = &imp_instance;
509 END
510         }
511
512     } elsif ($attrExt->{"v8OnProto"} || $attrExt->{"V8DisallowShadowing"}) {
513         # perform lookup first
514         push(@implContentDecls, <<END);
515     v8::Handle<v8::Object> holder = V8Proxy::lookupDOMWrapper(V8ClassIndex::$classIndex, info.This());
516     if (holder.IsEmpty()) return v8::Undefined();
517 END
518         HolderToNative($dataNode, $implClassName, $classIndex);
519     } else {
520         push(@implContentDecls, <<END);
521     v8::Handle<v8::Object> holder = info.Holder();
522 END
523         HolderToNative($dataNode, $implClassName, $classIndex);
524     }
525
526     # Generate security checks if necessary
527     if ($attribute->signature->extendedAttributes->{"CheckNodeSecurity"}) {
528         push(@implContentDecls, "    if (!V8Proxy::checkNodeSecurity(imp->$attrName())) return v8::Undefined();\n\n");
529     } elsif ($attribute->signature->extendedAttributes->{"CheckFrameSecurity"}) {
530         push(@implContentDecls, "    if (!V8Proxy::checkNodeSecurity(imp->contentDocument())) return v8::Undefined();\n\n");
531     }
532
533     my $useExceptions = 1 if @{$attribute->getterExceptions} and !($isPodType);
534     if ($useExceptions) {
535         $implIncludes{"ExceptionCode.h"} = 1;
536         push(@implContentDecls, "    ExceptionCode ec = 0;\n");
537     }
538
539     if ($attribute->signature->extendedAttributes->{"v8referenceattr"}) {
540         $attrName = $attribute->signature->extendedAttributes->{"v8referenceattr"};
541     }
542
543     my $getterFunc = WK_lcfirst($attrName);
544     $getterFunc .= "Animated" if $codeGenerator->IsSVGAnimatedType($attribute->signature->type);
545
546     my $returnType = $codeGenerator->StripModule($attribute->signature->type);
547
548     my $getterString;
549     if ($getterStringUsesImp) {
550         $getterString = "imp->$getterFunc(";
551         $getterString .= "ec" if $useExceptions;
552         $getterString .= ")";
553         if (IsRefPtrType($returnType)) {
554             $implIncludes{"wtf/GetPtr.h"} = 1;
555             $getterString = "WTF::getPtr(" . $getterString . ")";
556         }
557         if ($nativeType eq "int" and
558             $attribute->signature->extendedAttributes->{"ConvertFromString"}) {
559                 $getterString .= ".toInt()";
560             }
561         } else {
562             $getterString = "imp_instance";
563         }
564         if ($nativeType eq "String") {
565             $getterString = "toString($getterString)";
566         }
567
568         my $result;
569         my $wrapper;
570
571         if ($attrIsPodType) {
572             $implIncludes{"V8SVGPODTypeWrapper.h"} = 1;
573
574             my $getter = $getterString;
575             $getter =~ s/imp->//;
576             $getter =~ s/\(\)//;
577             my $setter = "set" . WK_ucfirst($getter);
578
579             my $implClassIsAnimatedType = $codeGenerator->IsSVGAnimatedType($implClassName);
580             if (not $implClassIsAnimatedType
581                 and $codeGenerator->IsPodTypeWithWriteableProperties($attrType)
582                 and not defined $attribute->signature->extendedAttributes->{"Immutable"}) {
583             if (IsPodType($implClassName)) {
584                 $wrapper = "new V8SVGStaticPODTypeWrapperWithPODTypeParent<$nativeType, $implClassName>($getterString, imp_wrapper)";
585             } else {
586                 $wrapper = "new V8SVGStaticPODTypeWrapperWithParent<$nativeType, $implClassName>(imp, &${implClassName}::$getter, &${implClassName}::$setter)";
587             }
588         } else {
589             if ($implClassIsAnimatedType) {
590                 $wrapper = "V8SVGDynamicPODTypeWrapperCache<$nativeType, $implClassName>::lookupOrCreateWrapper(imp, &${implClassName}::$getter, &${implClassName}::$setter)";
591             } else {
592                 $wrapper = GenerateSVGStaticPodTypeWrapper($returnType, $getterString);
593             }
594         }
595
596         push(@implContentDecls, "    void* wrapper = $wrapper;\n");
597     } elsif ($nativeType ne "RGBColor") {
598         push(@implContentDecls, "    $nativeType v = ");
599
600         push(@implContentDecls, "$getterString;\n");
601
602         if ($useExceptions) {
603             push(@implContentDecls, GenerateSetDOMException("    "));
604         }
605
606         $result = "v";
607         if (IsRefPtrType($returnType)) {
608             $result = "WTF::getPtr(" . $result . ")";
609         }
610     } else {
611         # Special case: RGBColor is noncopyable
612         $result = $getterString;
613     }
614
615
616     if (IsSVGTypeNeedingContextParameter($attrType) && !$skipContext) {
617         my $resultObject = $result;
618         if ($attrIsPodType) {
619             $resultObject = "wrapper";
620         }
621
622         push(@implContentDecls, GenerateSVGContextAssignment($implClassName, $resultObject, "    "));
623     }
624
625     if ($attrIsPodType) {
626         my $classIndex = uc($attrType);
627         push(@implContentDecls, "    return V8Proxy::convertToV8Object(V8ClassIndex::$classIndex, wrapper);\n");
628     } else {
629         push(@implContentDecls, "    return ".NativeToJSValue($attribute->signature, $result).";\n");
630     }
631
632     push(@implContentDecls, "  }\n\n");  # end of getter
633 }
634
635
636 sub GenerateReplaceableAttrSetter
637 {
638     my $implClassName = shift;
639
640     $implIncludes{"V8Proxy.h"} = 1;
641
642     push(@implContentDecls,
643        "  static void ${attrName}AttrSetter(v8::Local<v8::String> name," .
644        " v8::Local<v8::Value> value, const v8::AccessorInfo& info) {\n");
645
646     push(@implContentDecls, "    INC_STATS(\"DOM.$implClassName.$attrName._set\");\n");
647
648     push(@implContentDecls, "    v8::Local<v8::String> ${attrName}_string = v8::String::New(\"${attrName}\");\n");
649     push(@implContentDecls, "    info.Holder()->Delete(${attrName}_string);\n");
650     push(@implContentDecls, "    info.This()->Set(${attrName}_string, value);\n");
651     push(@implContentDecls, "  }\n\n");
652 }
653
654
655 sub GenerateNormalAttrSetter
656 {
657     my $attribute = shift;
658     my $dataNode = shift;
659     my $classIndex = shift;
660     my $implClassName = shift;
661
662     my $attrExt = $attribute->signature->extendedAttributes;
663
664     $implIncludes{"V8Proxy.h"} = 1;
665
666     push(@implContentDecls,
667        "  static void ${attrName}AttrSetter(v8::Local<v8::String> name," .
668        " v8::Local<v8::Value> value, const v8::AccessorInfo& info) {\n");
669
670     push(@implContentDecls, "    INC_STATS(\"DOM.$implClassName.$attrName._set\");\n");
671
672     my $isPodType = IsPodType($implClassName);
673
674     if ($isPodType) {
675         $implClassName = GetNativeType($implClassName);
676         $implIncludes{"V8SVGPODTypeWrapper.h"} = 1;
677         push(@implContentDecls, "    V8SVGPODTypeWrapper<$implClassName>* wrapper = V8Proxy::convertToNativeObject<V8SVGPODTypeWrapper<$implClassName> >(V8ClassIndex::$classIndex, info.Holder());\n");
678         push(@implContentDecls, "    $implClassName imp_instance = *wrapper;\n");
679         push(@implContentDecls, "    $implClassName* imp = &imp_instance;\n");
680
681     } elsif ($attrExt->{"v8OnProto"}) {
682         # perform lookup first
683         push(@implContentDecls, <<END);
684     v8::Handle<v8::Object> holder = V8Proxy::lookupDOMWrapper(V8ClassIndex::$classIndex, info.This());
685     if (holder.IsEmpty()) return v8::Undefined();
686 END
687         HolderToNative($dataNode, $implClassName, $classIndex);
688     } else {
689         push(@implContentDecls, <<END);
690     v8::Handle<v8::Object> holder = info.Holder();
691 END
692         HolderToNative($dataNode, $implClassName, $classIndex);
693     }
694
695     my $nativeType = GetNativeTypeFromSignature($attribute->signature, 0);
696     push(@implContentDecls, "    $nativeType v = " . JSValueToNative($attribute->signature, "value") . ";\n");
697
698     my $result = "";
699     if ($nativeType eq "int" and $attribute->signature->extendedAttributes->{"ConvertFromString"}) {
700         $result .= "WebCore::String::number(";
701     }
702     $result .= "v";
703     if ($nativeType eq "int" and $attribute->signature->extendedAttributes->{"ConvertFromString"}) {
704         $result .= ")";
705     }
706     my $returnType = $codeGenerator->StripModule($attribute->signature->type);
707     if (IsRefPtrType($returnType)) {
708         $result = "WTF::getPtr(" . $result . ")";
709     }
710
711     my $useExceptions = 1 if @{$attribute->setterExceptions} and !($isPodType);
712
713     if ($useExceptions) {
714         $implIncludes{"ExceptionCode.h"} = 1;
715         push(@implContentDecls, "    ExceptionCode ec = 0;\n");
716     }
717
718     if ($implClassName eq "double") {
719         push(@implContentDecls, "    *imp = $result;\n");
720     } else {
721         push(@implContentDecls, "    imp->set" . WK_ucfirst($attrName) . "(" . $result);
722         push(@implContentDecls, ", ec") if $useExceptions;
723         push(@implContentDecls, ");\n");
724     }
725
726     if ($useExceptions) {
727         push(@implContentDecls, "    V8Proxy::setDOMException(ec);\n");
728     }
729
730     if ($isPodType) {
731         push(@implContentDecls, "    wrapper->commitChange(*imp, V8Proxy::svgContext(wrapper));\n");
732     } elsif (IsSVGTypeNeedingContextParameter($implClassName)) {
733         $implIncludes{"SVGElement.h"} = 1;
734
735         my $currentObject = "imp";
736         if ($isPodType) {
737             $currentObject = "wrapper";
738         }
739
740         push(@implContentDecls, "    if (SVGElement* context = V8Proxy::svgContext($currentObject)) {\n");
741         push(@implContentDecls, "        context->svgAttributeChanged(imp->associatedAttributeName());\n");
742         push(@implContentDecls, "    }\n");
743     }
744
745     push(@implContentDecls, "    return;\n");
746     push(@implContentDecls, "  }\n\n");  # end of setter
747 }
748
749 sub GenerateNewFunctionTemplate
750 {
751     $function = shift;
752     $dataNode = shift;
753     $signature = shift;
754
755     my $interfaceName = $dataNode->name;
756     my $name = $function->signature->name;
757
758     if ($function->signature->extendedAttributes->{"Custom"} ||
759         $function->signature->extendedAttributes->{"V8Custom"}) {
760         if ($function->signature->extendedAttributes->{"Custom"} &&
761             $function->signature->extendedAttributes->{"V8Custom"}) {
762             die "Custom and V8Custom should be mutually exclusive!"
763         }
764         my $customFunc = $function->signature->extendedAttributes->{"Custom"} ||
765                          $function->signature->extendedAttributes->{"V8Custom"};
766         if ($customFunc eq 1) {
767             $customFunc = $interfaceName . WK_ucfirst($name);
768         }
769         return "v8::FunctionTemplate::New(V8Custom::v8${customFunc}Callback, v8::Handle<v8::Value>(), $signature)";
770     } else {
771         return "v8::FunctionTemplate::New(${interfaceName}Internal::${name}Callback, v8::Handle<v8::Value>(), $signature)";
772     }
773 }
774
775 sub GenerateFunctionCallback
776 {
777     my $function = shift;
778     my $dataNode = shift;
779     my $classIndex = shift;
780     my $implClassName = shift;
781
782     my $interfaceName = $dataNode->name;
783     my $name = $function->signature->name;
784
785     push(@implContentDecls,
786 "  static v8::Handle<v8::Value> ${name}Callback(const v8::Arguments& args) {\n" .
787 "    INC_STATS(\"DOM.$implClassName.$name\");\n");
788
789     my $numParameters = @{$function->parameters};
790
791     if ($function->signature->extendedAttributes->{"RequiresAllArguments"}) {
792         push(@implContentDecls,
793             "    if (args.Length() < $numParameters) return v8::Undefined();\n");
794     }
795
796     if (IsPodType($implClassName)) {
797         my $nativeClassName = GetNativeType($implClassName);
798         push(@implContentDecls, "    V8SVGPODTypeWrapper<$nativeClassName>* imp_wrapper = V8Proxy::convertToNativeObject<V8SVGPODTypeWrapper<$nativeClassName> >(V8ClassIndex::$classIndex, args.Holder());\n");
799         push(@implContentDecls, "    $nativeClassName imp_instance = *imp_wrapper;\n");
800         push(@implContentDecls, "    $nativeClassName* imp = &imp_instance;\n");
801     } else {
802         push(@implContentDecls, <<END);
803     v8::Handle<v8::Value> holder = args.Holder();
804 END
805         HolderToNative($dataNode, $implClassName, $classIndex);
806     }
807
808   # Check domain security if needed
809     if (($dataNode->extendedAttributes->{"CheckDomainSecurity"}
810        || $interfaceName eq "DOMWindow")
811        && !$function->signature->extendedAttributes->{"DoNotCheckDomainSecurity"}) {
812     # We have not find real use cases yet.
813     push(@implContentDecls,
814 "    if (!V8Proxy::canAccessFrame(imp->frame(), true)) {\n".
815 "      return v8::Undefined();\n" .
816 "    }\n");
817     }
818
819
820     if (@{$function->raisesExceptions}) {
821         $implIncludes{"ExceptionCode.h"} = 1;
822         push(@implContentDecls, "    ExceptionCode ec = 0;\n");
823     }
824
825     if ($function->signature->extendedAttributes->{"CustomArgumentHandling"}) {
826         push(@implContentDecls, "    ScriptCallStack callStack(args, $numParameters);\n");
827         $implIncludes{"ScriptCallStack.h"} = 1;
828     }
829
830     my $paramIndex = 0;
831     foreach my $parameter (@{$function->parameters}) {
832         TranslateParameter($parameter);
833
834         my $parameterName = $parameter->name;
835
836         if ($parameter->extendedAttributes->{"Optional"}) {
837             # Generate early call if there are not enough parameters.
838             push(@implContentDecls, "    if (args.Length() <= $paramIndex) {\n");
839             my $functionCall = GenerateFunctionCallString($function, $paramIndex, "    " x 2, $implClassName);
840             push(@implContentDecls, $functionCall);
841             push(@implContentDecls, "    }\n");
842         }
843
844         if (BasicTypeCanFailConversion($parameter)) {
845             push(@implContentDecls, "    bool ${parameterName}Ok;\n");
846         }
847
848         push(@implContentDecls, "    " . GetNativeTypeFromSignature($parameter, 1) . " $parameterName = ");
849         push(@implContentDecls, JSValueToNative($parameter, "args[$paramIndex]",
850            BasicTypeCanFailConversion($parameter) ?  "${parameterName}Ok" : undef) . ";\n");
851
852         if (TypeCanFailConversion($parameter)) {
853             $implIncludes{"ExceptionCode.h"} = 1;
854             push(@implContentDecls,
855 "    if (!$parameterName" . (BasicTypeCanFailConversion($parameter) ? "Ok" : "") . ") {\n" .
856 "      V8Proxy::setDOMException(TYPE_MISMATCH_ERR);\n" .
857 "      return v8::Handle<v8::Value>();\n" .
858 "    }\n");
859         }
860
861         if ($parameter->extendedAttributes->{"IsIndex"}) {
862             $implIncludes{"ExceptionCode.h"} = 1;
863             push(@implContentDecls,
864 "    if ($parameterName < 0) {\n" .
865 "      V8Proxy::setDOMException(INDEX_SIZE_ERR);\n" .
866 "      return v8::Handle<v8::Value>();\n" .
867 "    }\n");
868         }
869
870         $paramIndex++;
871     }
872
873     # Build the function call string.
874     my $callString = GenerateFunctionCallString($function, $paramIndex, "    ", $implClassName);
875     push(@implContentDecls, "$callString");
876     push(@implContentDecls, "  }\n\n");
877 }
878
879 sub GenerateBatchedAttributeData
880 {
881     my $interfaceName = shift;
882     my $attributes = shift;
883
884     foreach my $attribute (@$attributes) {
885         my $attrName = $attribute->signature->name;
886         my $attrExt = $attribute->signature->extendedAttributes;
887
888         my $accessControl = "v8::DEFAULT";
889         if ($attrExt->{"DoNotCheckDomainSecurityOnGet"}) {
890             $accessControl = "v8::ALL_CAN_READ";
891         } elsif ($attrExt->{"DoNotCheckDomainSecurityOnSet"}) {
892             $accessControl = "v8::ALL_CAN_WRITE";
893         } elsif ($attrExt->{"DoNotCheckDomainSecurity"}) {
894             $accessControl = "v8::ALL_CAN_READ";
895         if (!($attribute->type =~ /^readonly/) && !($attrExt->{"V8ReadOnly"})) {
896             $accessControl .= "|v8::ALL_CAN_WRITE";
897         }
898     }
899     if ($attrExt->{"V8DisallowShadowing"}) {
900         $accessControl .= "|v8::PROHIBITS_OVERWRITING";
901     }
902     $accessControl = "static_cast<v8::AccessControl>(" . $accessControl . ")";
903
904     my $customAccessor =
905         $attrExt->{"Custom"} ||
906         $attrExt->{"CustomSetter"} ||
907         $attrExt->{"CustomGetter"} ||
908         $attrExt->{"V8Custom"} ||
909         $attrExt->{"V8CustomSetter"} ||
910         $attrExt->{"V8CustomGetter"} ||
911         "";
912     if ($customAccessor eq 1) {
913         # use the naming convension, interface + (capitalize) attr name
914         $customAccessor = $interfaceName . WK_ucfirst($attrName);
915     }
916
917     my $getter;
918     my $setter;
919     my $propAttr = "v8::None";
920     my $hasCustomSetter = 0;
921
922     # Check attributes.
923     if ($attrExt->{"DontEnum"}) {
924         $propAttr .= "|v8::DontEnum";
925     }
926     if ($attrExt->{"V8DisallowShadowing"}) {
927         $propAttr .= "|v8::DontDelete";
928     }
929
930     my $on_proto = "0 /* on instance */";
931     my $data = "V8ClassIndex::INVALID_CLASS_INDEX /* no data */";
932
933     # Constructor
934     if ($attribute->signature->type =~ /Constructor$/) {
935         my $constructorType = $codeGenerator->StripModule($attribute->signature->type);
936         $constructorType =~ s/Constructor$//;
937         my $constructorIndex = uc($constructorType);
938         $data = "V8ClassIndex::${constructorIndex}";
939         $getter = "${interfaceName}Internal::${interfaceName}ConstructorGetter";
940         $setter = "0";
941         $propAttr = "v8::ReadOnly";
942
943     # EventListeners
944     } elsif ($attribute->signature->type eq "EventListener") {
945         if ($interfaceName eq "DOMWindow") {
946             $getter = "V8Custom::v8DOMWindowEventHandlerAccessorGetter";
947             $setter = "V8Custom::v8DOMWindowEventHandlerAccessorSetter";
948         } elsif ($interfaceName eq "Element" || $interfaceName eq "Document" || $interfaceName eq "HTMLBodyElement" || $interfaceName eq "SVGElementInstance" || $interfaceName eq "HTMLFrameSetElement") {
949             $getter = "V8Custom::v8ElementEventHandlerAccessorGetter";
950             $setter = "V8Custom::v8ElementEventHandlerAccessorSetter";
951         } else {
952             $getter = "V8Custom::v8${customAccessor}AccessorGetter";
953             if ($interfaceName eq "WorkerContext" and $attrName eq "self") {
954                 $setter = "0";
955                 $propAttr = "v8::ReadOnly";
956             } else {
957                 $setter = "V8Custom::v8${customAccessor}AccessorSetter";
958             }
959         }
960
961     # Custom Getter and Setter
962     } elsif ($attrExt->{"Custom"} || $attrExt->{"V8Custom"}) {
963         $getter = "V8Custom::v8${customAccessor}AccessorGetter";
964         if ($interfaceName eq "WorkerContext" and $attrName eq "self") {
965             $setter = "0";
966             $propAttr = "v8::ReadOnly";
967         } else {
968             $hasCustomSetter = 1;
969             $setter = "V8Custom::v8${customAccessor}AccessorSetter";
970         }
971
972     # Custom Setter
973     } elsif ($attrExt->{"CustomSetter"} || $attrExt->{"V8CustomSetter"}) {
974         $hasCustomSetter = 1;
975         $getter = "${interfaceName}Internal::${attrName}AttrGetter";
976         $setter = "V8Custom::v8${customAccessor}AccessorSetter";
977
978     # Custom Getter
979     } elsif ($attrExt->{"CustomGetter"}) {
980         $getter = "V8Custom::v8${customAccessor}AccessorGetter";
981         $setter = "${interfaceName}Internal::${attrName}AttrSetter";
982
983     # Replaceable
984     } elsif ($attrExt->{"Replaceable"}) {
985         # Replaceable accessor is put on instance template with ReadOnly attribute.
986         $getter = "${interfaceName}Internal::${attrName}AttrGetter";
987         $setter = "0";
988
989         # Mark to avoid duplicate v8::ReadOnly flags in output.
990         $hasCustomSetter = 1;
991
992         # Handle the special case of window.top being marked upstream as Replaceable.
993         # FIXME: Investigate why [Replaceable] is not marked as ReadOnly
994         # upstream and reach parity.
995         if (!($interfaceName eq "DOMWindow" and $attrName eq "top")) {
996             $propAttr .= "|v8::ReadOnly";
997         }
998
999     # Normal
1000     } else {
1001         $getter = "${interfaceName}Internal::${attrName}AttrGetter";
1002         $setter = "${interfaceName}Internal::${attrName}AttrSetter";
1003     }
1004
1005     if ($attrExt->{"Replaceable"} && !$hasCustomSetter) {
1006         $setter = "0";
1007         $propAttr .= "|v8::ReadOnly";
1008     }
1009
1010     # Read only attributes
1011     if ($attribute->type =~ /^readonly/ || $attrExt->{"V8ReadOnly"}) {
1012         $setter = "0";
1013     }
1014
1015     # An accessor can be installed on the proto
1016     if ($attrExt->{"v8OnProto"}) {
1017         $on_proto = "1 /* on proto */";
1018     }
1019
1020     my $commentInfo = "Attribute '$attrName' (Type: '" . $attribute->type .
1021                       "' ExtAttr: '" . join(' ', keys(%{$attrExt})) . "')";
1022     push(@implContent, <<END);
1023   // $commentInfo
1024   { "$attrName",
1025     $getter,
1026     $setter,
1027     $data,
1028     $accessControl,
1029     static_cast<v8::PropertyAttribute>($propAttr),
1030     $on_proto },
1031 END
1032     }
1033 }
1034
1035
1036 sub GenerateImplementation
1037 {
1038     my $object = shift;
1039     my $dataNode = shift;
1040     my $interfaceName = $dataNode->name;
1041     my $className = "V8$interfaceName";
1042     my $implClassName = $interfaceName;
1043     my $classIndex = uc($codeGenerator->StripModule($interfaceName));
1044
1045     my $hasLegacyParent = $dataNode->extendedAttributes->{"LegacyParent"};
1046     my $conditional = $dataNode->extendedAttributes->{"Conditional"};
1047
1048     @allParents = $codeGenerator->FindParentsRecursively($dataNode);
1049
1050     # - Add default header template
1051     @implContentHeader = split("\r", $headerTemplate);
1052
1053     push(@implFixedHeader,
1054          "#include \"config.h\"\n" .
1055          "#include \"V8Proxy.h\"\n" .
1056          "#include \"V8Binding.h\"\n\n" .
1057          "#undef LOG\n\n");
1058
1059     my $conditionalString;
1060     if ($conditional) {
1061         $conditionalString = "ENABLE(" . join(") && ENABLE(", split(/&/, $conditional)) . ")";
1062         push(@implFixedHeader, "\n#if ${conditionalString}\n\n");
1063     }
1064
1065     if ($className =~ /^V8SVGAnimated/) {
1066         AddIncludesForSVGAnimatedType($interfaceName);
1067     }
1068
1069     $implIncludes{"${className}.h"} = 1;
1070
1071     AddIncludesForType($interfaceName);
1072     $implIncludes{"V8Proxy.h"} = 1;
1073
1074     push(@implContentDecls, "namespace WebCore {\n");
1075     push(@implContentDecls, "namespace ${interfaceName}Internal {\n\n");
1076     push(@implContentDecls, "template <typename T> void V8_USE(T) { }\n\n");
1077
1078     my $hasConstructors = 0;
1079
1080     # Generate property accessors for attributes.
1081     for ($index = 0; $index < @{$dataNode->attributes}; $index++) {
1082         $attribute = @{$dataNode->attributes}[$index];
1083         $attrName = $attribute->signature->name;
1084         $attrType = $attribute->signature->type;
1085
1086         # Generate special code for the constructor attributes.
1087         if ($attrType =~ /Constructor$/) {
1088             $hasConstructors = 1;
1089             next;
1090         }
1091
1092         # Make EventListeners always custom.
1093         # FIXME: make the perl code capable of generating the
1094         #   event setters/getters.  For now, WebKit has started removing the
1095         #   [Custom] attribute, so just automatically insert it to avoid forking
1096         #   other files.  This should be okay because we can't generate stubs
1097         #   for any event getter/setters anyway.
1098         if ($attrType eq "EventListener") {
1099             $attribute->signature->extendedAttributes->{"Custom"} = 1;
1100             $implIncludes{"V8CustomBinding.h"} = 1;
1101             next;
1102         }
1103
1104         # Do not generate accessor if this is a custom attribute.  The
1105         # call will be forwarded to a hand-written accessor
1106         # implementation.
1107         if ($attribute->signature->extendedAttributes->{"Custom"} ||
1108             $attribute->signature->extendedAttributes->{"V8Custom"}) {
1109             $implIncludes{"V8CustomBinding.h"} = 1;
1110             next;
1111         }
1112
1113         # Generate the accessor.
1114         if ($attribute->signature->extendedAttributes->{"CustomGetter"}) {
1115             $implIncludes{"V8CustomBinding.h"} = 1;
1116         } else {
1117             GenerateNormalAttrGetter($attribute, $dataNode, $classIndex, $implClassName);
1118         }
1119         if ($attribute->signature->extendedAttributes->{"CustomSetter"} ||
1120             $attribute->signature->extendedAttributes->{"V8CustomSetter"}) {
1121             $implIncludes{"V8CustomBinding.h"} = 1;
1122         } elsif ($attribute->signature->extendedAttributes->{"Replaceable"}) {
1123             $dataNode->extendedAttributes->{"ExtendsDOMGlobalObject"} || die "Replaceable attribute can only be used in interface that defines ExtendsDOMGlobalObject attribute!";
1124             # GenerateReplaceableAttrSetter($implClassName);
1125         } elsif ($attribute->type !~ /^readonly/ && !$attribute->signature->extendedAttributes->{"V8ReadOnly"}) {
1126             GenerateNormalAttrSetter($attribute, $dataNode, $classIndex, $implClassName);
1127         }
1128     }
1129
1130     if ($hasConstructors) {
1131         GenerateConstructorGetter($implClassName, $classIndex);
1132     }
1133
1134     # Generate methods for functions.
1135     foreach my $function (@{$dataNode->functions}) {
1136         # hack for addEventListener/RemoveEventListener
1137         # FIXME: avoid naming conflict
1138         if ($function->signature->extendedAttributes->{"Custom"} || $function->signature->extendedAttributes->{"V8Custom"}) {
1139                 $implIncludes{"V8CustomBinding.h"} = 1;
1140         } else {
1141             GenerateFunctionCallback($function, $dataNode, $classIndex, $implClassName);
1142         }
1143
1144         # If the function does not need domain security check, we need to
1145         # generate an access getter that returns different function objects
1146         # for different calling context.
1147         if (($dataNode->extendedAttributes->{"CheckDomainSecurity"} || ($interfaceName eq "DOMWindow")) && $function->signature->extendedAttributes->{"DoNotCheckDomainSecurity"}) {
1148             GenerateDomainSafeFunctionGetter($function, $dataNode, $classIndex, $implClassName);
1149         }
1150     }
1151
1152     # Attributes
1153     my $attributes = $dataNode->attributes;
1154
1155     # For the DOMWindow interface we partition the attributes into the
1156     # ones that disallows shadowing and the rest.
1157     my @disallows_shadowing;
1158     my @normal;
1159     if ($interfaceName eq "DOMWindow") {
1160         foreach my $attribute (@$attributes) {
1161             if ($attribute->signature->extendedAttributes->{"V8DisallowShadowing"}) {
1162                 push(@disallows_shadowing, $attribute);
1163             } else {
1164                 push(@normal, $attribute);
1165             }
1166         }
1167         # Put the attributes that disallow shadowing on the shadow object.
1168         $attributes = \@normal;
1169         push(@implContent, "static const BatchedAttribute shadow_attrs[] = {\n");
1170         GenerateBatchedAttributeData($interfaceName, \@disallows_shadowing);
1171         push(@implContent, "};\n");
1172     }
1173
1174     my $has_attributes = 0;
1175     if (@$attributes) {
1176         $has_attributes = 1;
1177         push(@implContent, "static const BatchedAttribute attrs[] = {\n");
1178         GenerateBatchedAttributeData($interfaceName, $attributes);
1179         push(@implContent, "};\n");
1180     }
1181
1182     # Setup constants
1183     my $has_constants = 0;
1184     if (@{$dataNode->constants}) {
1185         $has_constants = 1;
1186         push(@implContent, "static const BatchedConstant consts[] = {\n");
1187     }
1188     foreach my $constant (@{$dataNode->constants}) {
1189         my $name = $constant->name;
1190         my $value = $constant->value;
1191         # FIXME: we need the static_cast here only because of one constant, NodeFilter.idl
1192         # defines "const unsigned long SHOW_ALL = 0xFFFFFFFF".  It would be better if we
1193         # handled this here, and converted it to a -1 constant in the c++ output.
1194         push(@implContent, <<END);
1195   { "${name}", static_cast<signed int>($value) },
1196 END
1197     }
1198     if ($has_constants) {
1199         push(@implContent, "};\n");
1200     }
1201
1202     push(@implContentDecls, "} // namespace ${interfaceName}Internal\n\n");
1203
1204     my $access_check = "/* no access check */";
1205     if ($dataNode->extendedAttributes->{"CheckDomainSecurity"} && !($interfaceName eq "DOMWindow")) {
1206         $access_check = "instance->SetAccessCheckCallbacks(V8Custom::v8${interfaceName}NamedSecurityCheck, V8Custom::v8${interfaceName}IndexedSecurityCheck, v8::Integer::New(V8ClassIndex::ToInt(V8ClassIndex::${classIndex})));";
1207     }
1208
1209     # For the DOMWindow interface, generate the shadow object template
1210     # configuration method.
1211     if ($implClassName eq "DOMWindow") {
1212         push(@implContent, <<END);
1213 static v8::Persistent<v8::ObjectTemplate> ConfigureShadowObjectTemplate(v8::Persistent<v8::ObjectTemplate> templ) {
1214   batchConfigureAttributes(templ,
1215                            v8::Handle<v8::ObjectTemplate>(),
1216                            shadow_attrs,
1217                            sizeof(shadow_attrs)/sizeof(*shadow_attrs));
1218   return templ;
1219 }
1220 END
1221     }
1222
1223     # Generate the template configuration method
1224     push(@implContent,  <<END);
1225 static v8::Persistent<v8::FunctionTemplate> Configure${className}Template(v8::Persistent<v8::FunctionTemplate> desc) {
1226   v8::Local<v8::ObjectTemplate> instance = desc->InstanceTemplate();
1227   instance->SetInternalFieldCount(2);
1228   v8::Local<v8::Signature> default_signature = v8::Signature::New(desc);
1229   v8::Local<v8::ObjectTemplate> proto = desc->PrototypeTemplate();
1230   $access_check
1231 END
1232
1233
1234     # Set up our attributes if we have them
1235     if ($has_attributes) {
1236         push(@implContent, <<END);
1237   batchConfigureAttributes(instance, proto, attrs, sizeof(attrs)/sizeof(*attrs));
1238 END
1239     }
1240
1241     # Define our functions with Set() or SetAccessor()
1242     foreach my $function (@{$dataNode->functions}) {
1243         my $attrExt = $function->signature->extendedAttributes;
1244         my $name = $function->signature->name;
1245
1246         my $property_attributes = "v8::DontDelete";
1247         if ($attrExt->{"DontEnum"}) {
1248             $property_attributes .= "|v8::DontEnum";
1249         }
1250         if ($attrExt->{"V8ReadOnly"}) {
1251             $property_attributes .= "|v8::ReadOnly";
1252         }
1253
1254         my $commentInfo = "Function '$name' (ExtAttr: '" . join(' ', keys(%{$attrExt})) . "')";
1255
1256         my $template = "proto";
1257         if ($attrExt->{"V8OnInstance"}) {
1258             $template = "instance";
1259         }
1260
1261         if ($attrExt->{"DoNotCheckDomainSecurity"} &&
1262             ($dataNode->extendedAttributes->{"CheckDomainSecurity"} || $interfaceName eq "DOMWindow")) {
1263             # Mark the accessor as ReadOnly and set it on the proto object so
1264             # it can be shadowed. This is really a hack to make it work.
1265             # There are several sceneria to call into the accessor:
1266             #   1) from the same domain: "window.open":
1267             #      the accessor finds the DOM wrapper in the proto chain;
1268             #   2) from the same domain: "window.__proto__.open":
1269             #      the accessor will NOT find a DOM wrapper in the prototype chain
1270             #   3) from another domain: "window.open":
1271             #      the access find the DOM wrapper in the prototype chain
1272             #   "window.__proto__.open" from another domain will fail when
1273             #   accessing '__proto__'
1274             #
1275             # The solution is very hacky and fragile, it really needs to be replaced
1276             # by a better solution.
1277             $property_attributes .= "|v8::ReadOnly";
1278             push(@implContent, <<END);
1279
1280   // $commentInfo
1281   $template->SetAccessor(
1282       v8::String::New("$name"),
1283       ${interfaceName}Internal::${name}AttrGetter,
1284       0,
1285       v8::Handle<v8::Value>(),
1286       v8::ALL_CAN_READ,
1287       static_cast<v8::PropertyAttribute>($property_attributes));
1288 END
1289           next;
1290       }
1291
1292       my $signature = "default_signature";
1293       if ($attrExt->{"V8DoNotCheckSignature"}){
1294           $signature = "v8::Local<v8::Signature>()";
1295       }
1296
1297       if (RequiresCustomSignature($function)) {
1298           $signature = "${name}_signature";
1299           push(@implContent, "\n  // Custom Signature '$name'\n", CreateCustomSignature($function));
1300       }
1301
1302       # Normal function call is a template
1303       my $templateFunction = GenerateNewFunctionTemplate($function, $dataNode, $signature);
1304
1305
1306       push(@implContent, <<END);
1307
1308   // $commentInfo
1309   ${template}->Set(
1310       v8::String::New("$name"),
1311       $templateFunction,
1312       static_cast<v8::PropertyAttribute>($property_attributes));
1313 END
1314     }
1315
1316     # set the super descriptor
1317     foreach (@{$dataNode->parents}) {
1318         my $parent = $codeGenerator->StripModule($_);
1319         if ($parent eq "EventTarget") { next; }
1320         $implIncludes{"V8${parent}.h"} = 1;
1321         my $parentClassIndex = uc($codeGenerator->StripModule($parent));
1322         push(@implContent, "  desc->Inherit(V8Proxy::getTemplate(V8ClassIndex::${parentClassIndex}));\n");
1323         last;
1324     }
1325
1326     # Set the class name.  This is used when printing objects.
1327     push(@implContent, "  desc->SetClassName(v8::String::New(\"" . GetClassName(${interfaceName}) . "\"));\n");
1328
1329     if ($has_constants) {
1330         push(@implContent, <<END);
1331   batchConfigureConstants(desc, proto, consts, sizeof(consts)/sizeof(*consts));
1332 END
1333     }
1334
1335     push(@implContent, <<END);
1336   return desc;
1337 }
1338
1339 v8::Persistent<v8::FunctionTemplate> ${className}::GetRawTemplate() {
1340   static v8::Persistent<v8::FunctionTemplate> ${className}_raw_cache_;
1341   if (${className}_raw_cache_.IsEmpty()) {
1342     v8::HandleScope scope;
1343     v8::Local<v8::FunctionTemplate> result = v8::FunctionTemplate::New(V8Proxy::checkNewLegal);
1344     ${className}_raw_cache_ = v8::Persistent<v8::FunctionTemplate>::New(result);
1345   }
1346   return ${className}_raw_cache_;
1347 }
1348
1349 v8::Persistent<v8::FunctionTemplate> ${className}::GetTemplate() {
1350   static v8::Persistent<v8::FunctionTemplate> ${className}_cache_;
1351   if (${className}_cache_.IsEmpty())
1352     ${className}_cache_ = Configure${className}Template(GetRawTemplate());
1353   return ${className}_cache_;
1354 }
1355
1356 bool ${className}::HasInstance(v8::Handle<v8::Value> value) {
1357   return GetRawTemplate()->HasInstance(value);
1358 }
1359
1360 END
1361
1362     if ($implClassName eq "DOMWindow") {
1363         push(@implContent, <<END);
1364 v8::Persistent<v8::ObjectTemplate> V8DOMWindow::GetShadowObjectTemplate() {
1365   static v8::Persistent<v8::ObjectTemplate> V8DOMWindowShadowObject_cache_;
1366   if (V8DOMWindowShadowObject_cache_.IsEmpty()) {
1367     V8DOMWindowShadowObject_cache_ = v8::Persistent<v8::ObjectTemplate>::New(v8::ObjectTemplate::New());
1368     ConfigureShadowObjectTemplate(V8DOMWindowShadowObject_cache_);
1369   }
1370   return V8DOMWindowShadowObject_cache_;
1371 }
1372 END
1373     }
1374
1375     push(@implContent, <<END);
1376 } // namespace WebCore
1377 END
1378
1379     push(@implContent, "\n#endif // ${conditionalString}\n") if $conditional;
1380 }
1381
1382
1383 sub GenerateFunctionCallString()
1384 {
1385     my $function = shift;
1386     my $numberOfParameters = shift;
1387     my $indent = shift;
1388     my $implClassName = shift;
1389
1390     my $name = $function->signature->name;
1391     my $isPodType = IsPodType($implClassName);
1392     my $returnType = $codeGenerator->StripModule($function->signature->type);
1393     my $returnsPodType = IsPodType($returnType);
1394     my $nativeReturnType = GetNativeType($returnType, 0);
1395     my $result = "";
1396
1397     # Special case: SVG matrix transform methods should not mutate
1398     # the matrix but return a copy
1399     my $copyFirst = 0;
1400     if ($implClassName eq "SVGMatrix" && $function->signature->type eq "SVGMatrix") {
1401         $copyFirst = 1;
1402     }
1403
1404     if ($function->signature->extendedAttributes->{"v8implname"}) {
1405         $name = $function->signature->extendedAttributes->{"v8implname"};
1406     }
1407
1408     if ($function->signature->extendedAttributes->{"ImplementationFunction"}) {
1409         $name = $function->signature->extendedAttributes->{"ImplementationFunction"};
1410     }
1411
1412     my $functionString = "imp->${name}(";
1413
1414     if ($copyFirst) {
1415         $functionString = "result.${name}(";
1416     }
1417
1418     my $returnsListItemPodType = 0;
1419     # SVG lists functions that return POD types require special handling
1420     if (IsSVGListTypeNeedingSpecialHandling($implClassName) && IsSVGListMethod($name) && $returnsPodType) {
1421         $returnsListItemPodType = 1;
1422         $result .= $indent . "SVGList<RefPtr<SVGPODListItem<$nativeReturnType> > >* listImp = imp;\n";
1423         $functionString = "listImp->${name}(";
1424     }
1425
1426     my $first = 1;
1427     my $index = 0;
1428     my $nodeToReturn = 0;
1429
1430     foreach my $parameter (@{$function->parameters}) {
1431         if ($index eq $numberOfParameters) {
1432             last;
1433         }
1434         if ($first) { $first = 0; }
1435         else { $functionString .= ", "; }
1436         my $paramName = $parameter->name;
1437         my $paramType = $parameter->type;
1438
1439         # This is a bit of a hack... we need to convert parameters to methods on SVG lists
1440         # of POD types which are items in the list to appropriate SVGList<> instances
1441         if ($returnsListItemPodType && $paramType . "List" eq $implClassName) {
1442             $paramName = "SVGPODListItem<" . GetNativeType($paramType, 1) . ">::copy($paramName)";
1443         }
1444
1445         if ($parameter->type eq "NodeFilter") {
1446             $functionString .= "$paramName.get()";
1447         } else {
1448             $functionString .= $paramName;
1449         }
1450
1451         if ($parameter->extendedAttributes->{"Return"}) {
1452             $nodeToReturn = $parameter->name;
1453         }
1454         $index++;
1455     }
1456
1457     if ($function->signature->extendedAttributes->{"CustomArgumentHandling"}) {
1458         $functionString .= ", " if not $first;
1459         $functionString .= "&callStack";
1460         if ($first) { $first = 0; }
1461     }
1462
1463     if (@{$function->raisesExceptions}) {
1464         $functionString .= ", " if not $first;
1465         $functionString .= "ec";
1466     }
1467     $functionString .= ")";
1468
1469     if ((IsRefPtrType($returnType) || $returnsListItemPodType) && !$nodeToReturn) {
1470         # We don't use getPtr when $nodeToReturn because that situation is
1471         # special-cased below to return a bool.
1472         $implIncludes{"wtf/GetPtr.h"} = 1;
1473         $functionString = "WTF::getPtr(" . $functionString . ")";
1474     }
1475
1476     if ($nodeToReturn) {
1477         # Special case for insertBefore, replaceChild, removeChild and
1478         # appendChild functions from Node.
1479         $result .= $indent . "bool success = $functionString;\n";
1480         if (@{$function->raisesExceptions}) {
1481             $result .= GenerateSetDOMException($indent);
1482         }
1483         $result .= $indent . "if (success)\n";
1484         $result .= $indent . "    " .
1485             "return V8Proxy::convertNodeToV8Object($nodeToReturn);\n";
1486         $result .= $indent . "return v8::Null();\n";
1487         return $result;
1488     } elsif ($returnType eq "void") {
1489         $result .= $indent . "$functionString;\n";
1490     } elsif ($copyFirst) {
1491         $result .=
1492             $indent . GetNativeType($returnType, 0) . " result = *imp;\n" .
1493             $indent . "$functionString;\n";
1494     } elsif ($returnsListItemPodType) {
1495         $result .= $indent . "RefPtr<SVGPODListItem<$nativeReturnType> > result = $functionString;\n";
1496     } else {
1497         $result .= $indent . $nativeReturnType . " result = $functionString;\n";
1498     }
1499
1500     if (@{$function->raisesExceptions}) {
1501         $result .= GenerateSetDOMException($indent);
1502     }
1503
1504     my $return = "result";
1505     if (IsRefPtrType($returnType) || $returnsListItemPodType) {
1506         $implIncludes{"wtf/GetPtr.h"} = 1;
1507         $return = "WTF::getPtr(" . $return . ")";
1508     }
1509
1510     # If the return type is a POD type, separate out the wrapper generation
1511     if ($returnsListItemPodType) {
1512         $result .= $indent . "V8SVGPODTypeWrapper<" . $nativeReturnType . ">* wrapper = new ";
1513         $result .= "V8SVGPODTypeWrapperCreatorForList<" . $nativeReturnType . ">($return, imp->associatedAttributeName());\n";
1514         $return = "wrapper";
1515     } elsif ($returnsPodType) {
1516         $result .= $indent . "V8SVGPODTypeWrapper<" . $nativeReturnType . ">* wrapper = ";
1517         $result .= GenerateSVGStaticPodTypeWrapper($returnType, $return) . ";\n";
1518         $return = "wrapper";
1519     }
1520
1521     my $generatedSVGContextRetrieval = 0;
1522     # If the return type needs an SVG context, output it
1523     if (IsSVGTypeNeedingContextParameter($returnType)) {
1524         $result .= GenerateSVGContextAssignment($implClassName, $return, $indent);
1525         $generatedSVGContextRetrieval = 1;
1526     }
1527
1528     if (IsSVGTypeNeedingContextParameter($implClassName) && $implClassName =~ /List$/ && IsSVGListMutator($name)) {
1529         if (!$generatedSVGContextRetrieval) {
1530             $result .= GenerateSVGContextRetrieval($implClassName, $indent);
1531             $generatedSVGContextRetrieval = 1;
1532         }
1533
1534         $result .= $indent . "context->svgAttributeChanged(imp->associatedAttributeName());\n";
1535         $implIncludes{"SVGElement.h"} = 1;
1536     }
1537
1538     # If the implementing class is a POD type, commit changes
1539     if ($isPodType) {
1540         if (!$generatedSVGContextRetrieval) {
1541             $result .= GenerateSVGContextRetrieval($implClassName, $indent);
1542             $generatedSVGContextRetrieval = 1;
1543         }
1544
1545         $result .= $indent . "imp_wrapper->commitChange(imp_instance, context);\n";
1546     }
1547
1548     if ($returnsPodType) {
1549         my $classIndex = uc($returnType);
1550         $result .= $indent . "return V8Proxy::convertToV8Object(V8ClassIndex::$classIndex, wrapper);\n";
1551     } else {
1552         $result .= $indent . "return " . NativeToJSValue($function->signature, $return) . ";\n";
1553     }
1554
1555     return $result;
1556 }
1557
1558
1559 # Get the class name used for printing javascript DOM-object wrappers.
1560 sub GetClassName
1561 {
1562     my $type = shift;
1563     return "HTMLCollection" if $type eq "UndetectableHTMLCollection";
1564     return $type;
1565 }
1566
1567
1568 sub GetNativeTypeFromSignature
1569 {
1570     my $signature = shift;
1571     my $isParameter = shift;
1572
1573     my $type = $codeGenerator->StripModule($signature->type);
1574
1575     return GetNativeType($type, $isParameter);
1576 }
1577
1578 sub IsRefPtrType
1579 {
1580     my $type = shift;
1581     return 1 if $type eq "Attr";
1582     return 1 if $type eq "CanvasGradient";
1583     return 1 if $type eq "ClientRect";
1584     return 1 if $type eq "ClientRectList";
1585     return 1 if $type eq "CDATASection";
1586     return 1 if $type eq "Comment";
1587     return 1 if $type eq "CSSRule";
1588     return 1 if $type eq "CSSStyleRule";
1589     return 1 if $type eq "CSSCharsetRule";
1590     return 1 if $type eq "CSSImportRule";
1591     return 1 if $type eq "CSSMediaRule";
1592     return 1 if $type eq "CSSFontFaceRule";
1593     return 1 if $type eq "CSSPageRule";
1594     return 1 if $type eq "CSSPrimitiveValue";
1595     return 1 if $type eq "CSSStyleSheet";
1596     return 1 if $type eq "CSSStyleDeclaration";
1597     return 1 if $type eq "CSSValue";
1598     return 1 if $type eq "CSSRuleList";
1599     return 1 if $type eq "Database";
1600     return 1 if $type eq "Document";
1601     return 1 if $type eq "DocumentFragment";
1602     return 1 if $type eq "DocumentType";
1603     return 1 if $type eq "Element";
1604     return 1 if $type eq "EntityReference";
1605     return 1 if $type eq "Event";
1606     return 1 if $type eq "FileList";
1607     return 1 if $type eq "HTMLCollection";
1608     return 1 if $type eq "HTMLDocument";
1609     return 1 if $type eq "HTMLElement";
1610     return 1 if $type eq "HTMLOptionsCollection";
1611     return 1 if $type eq "ImageData";
1612     return 1 if $type eq "MediaError";
1613     return 1 if $type eq "MimeType";
1614     return 1 if $type eq "Node";
1615     return 1 if $type eq "NodeList";
1616     return 1 if $type eq "NodeFilter";
1617     return 1 if $type eq "NodeIterator";
1618     return 1 if $type eq "NSResolver";
1619     return 1 if $type eq "Plugin";
1620     return 1 if $type eq "ProcessingInstruction";
1621     return 1 if $type eq "Range";
1622     return 1 if $type eq "Text";
1623     return 1 if $type eq "TextMetrics";
1624     return 1 if $type eq "TimeRanges";
1625     return 1 if $type eq "TreeWalker";
1626     return 1 if $type eq "WebKitCSSMatrix";
1627     return 1 if $type eq "WebKitPoint";
1628     return 1 if $type eq "XPathExpression";
1629     return 1 if $type eq "XPathNSResolver";
1630     return 1 if $type eq "XPathResult";
1631
1632     return 1 if $type eq "SVGAngle";
1633     return 1 if $type eq "SVGElementInstance";
1634     return 1 if $type eq "SVGElementInstanceList";
1635     return 1 if $type =~ /^SVGPathSeg/;
1636
1637     return 1 if $type =~ /^SVGAnimated/;
1638
1639     return 0;
1640 }
1641
1642 sub IsVideoClassName
1643 {
1644     my $class = shift;
1645     return 1 if $class eq "V8HTMLAudioElement";
1646     return 1 if $class eq "V8HTMLMediaElement";
1647     return 1 if $class eq "V8HTMLSourceElement";
1648     return 1 if $class eq "V8HTMLVideoElement";
1649     return 1 if $class eq "V8MediaError";
1650     return 1 if $class eq "V8TimeRanges";
1651
1652     return 0;
1653 }
1654
1655 sub IsWorkerClassName
1656 {
1657     my $class = shift;
1658     return 1 if $class eq "V8Worker";
1659     return 1 if $class eq "V8WorkerContext";
1660     return 1 if $class eq "V8WorkerLocation";
1661     return 1 if $class eq "V8WorkerNavigator";
1662
1663     return 0;
1664 }
1665
1666 sub GetNativeType
1667 {
1668     my $type = shift;
1669     my $isParameter = shift;
1670
1671     if ($type eq "float" or $type eq "AtomicString" or $type eq "double") {
1672         return $type;
1673     }
1674
1675     return "int" if $type eq "int";
1676     return "int" if $type eq "short" or $type eq "unsigned short";
1677     return "int" if $type eq "long" or $type eq "unsigned long";
1678     return "unsigned long long" if $type eq "unsigned long long";
1679     return "bool" if $type eq "boolean";
1680     return "String" if $type eq "DOMString";
1681     return "Range::CompareHow" if $type eq "CompareHow";
1682     return "FloatRect" if $type eq "SVGRect";
1683     return "FloatPoint" if $type eq "SVGPoint";
1684     return "TransformationMatrix" if $type eq "SVGMatrix";
1685     return "SVGTransform" if $type eq "SVGTransform";
1686     return "SVGLength" if $type eq "SVGLength";
1687     return "double" if $type eq "SVGNumber";
1688     return "SVGPaint::SVGPaintType" if $type eq "SVGPaintType";
1689     return "DOMTimeStamp" if $type eq "DOMTimeStamp";
1690     return "unsigned" if $type eq "unsigned int";
1691     return "unsigned" if $type eq "RGBColor";
1692     return "Node*" if $type eq "EventTarget" and $isParameter;
1693
1694     return "String" if $type eq "DOMUserData";  # FIXME: Temporary hack?
1695
1696     # temporary hack
1697     return "RefPtr<NodeFilter>" if $type eq "NodeFilter";
1698
1699     return "RefPtr<${type}>" if IsRefPtrType($type) and not $isParameter;
1700
1701     # Default, assume native type is a pointer with same type name as idl type
1702     return "${type}*";
1703 }
1704
1705
1706 my %typeCanFailConversion = (
1707     "AtomicString" => 0,
1708     "Attr" => 1,
1709     "CompareHow" => 0,
1710     "DataGridColumn" => 0,
1711     "DOMString" => 0,
1712     "DOMWindow" => 0,
1713     "DocumentType" => 0,
1714     "Element" => 0,
1715     "Event" => 0,
1716     "EventListener" => 0,
1717     "EventTarget" => 0,
1718     "HTMLElement" => 0,
1719     "HTMLOptionElement" => 0,
1720     "Node" => 0,
1721     "NodeFilter" => 0,
1722     "MessagePort" => 0,
1723     "NSResolver" => 0,
1724     "Range" => 0,
1725     "SQLResultSet" => 0,
1726     "Storage" => 0,
1727     "SVGAngle" => 0,
1728     "SVGElement" => 0,
1729     "SVGLength" => 1,
1730     "SVGMatrix" => 1,
1731     "SVGNumber" => 0,
1732     "SVGPaintType" => 0,
1733     "SVGPathSeg" => 0,
1734     "SVGPoint" => 1,
1735     "SVGRect" => 1,
1736     "SVGTransform" => 1,
1737     "VoidCallback" => 1,
1738     "WebKitCSSMatrix" => 0,
1739     "WebKitPoint" => 0,
1740     "XPathEvaluator" => 0,
1741     "XPathNSResolver" => 0,
1742     "XPathResult" => 0,
1743     "boolean" => 0,
1744     "double" => 0,
1745     "float" => 0,
1746     "long" => 0,
1747     "unsigned long" => 0,
1748     "unsigned short" => 0,
1749 );
1750
1751
1752 sub TranslateParameter
1753 {
1754     my $signature = shift;
1755
1756     # The IDL uses some pseudo-types which don't really exist.
1757     if ($signature->type eq "TimeoutHandler") {
1758       $signature->type("DOMString");
1759     }
1760 }
1761
1762 sub BasicTypeCanFailConversion
1763 {
1764     my $signature = shift;
1765     my $type = $codeGenerator->StripModule($signature->type);
1766
1767     return 1 if $type eq "SVGLength";
1768     return 1 if $type eq "SVGMatrix";
1769     return 1 if $type eq "SVGPoint";
1770     return 1 if $type eq "SVGRect";
1771     return 1 if $type eq "SVGTransform";
1772     return 0;
1773 }
1774
1775 sub TypeCanFailConversion
1776 {
1777     my $signature = shift;
1778
1779     my $type = $codeGenerator->StripModule($signature->type);
1780
1781     $implIncludes{"ExceptionCode.h"} = 1 if $type eq "Attr";
1782
1783     return $typeCanFailConversion{$type} if exists $typeCanFailConversion{$type};
1784
1785     die "Don't know whether a JS value can fail conversion to type $type.";
1786 }
1787
1788 sub JSValueToNative
1789 {
1790     my $signature = shift;
1791     my $value = shift;
1792     my $okParam = shift;
1793     my $maybeOkParam = $okParam ? ", ${okParam}" : "";
1794
1795     my $type = $codeGenerator->StripModule($signature->type);
1796
1797     return "$value" if $type eq "JSObject";
1798     return "$value->BooleanValue()" if $type eq "boolean";
1799     return "static_cast<$type>($value->NumberValue())" if $type eq "float" or $type eq "double";
1800     return "$value->NumberValue()" if $type eq "SVGNumber";
1801
1802     return "toInt32($value${maybeOkParam})" if $type eq "unsigned long" or $type eq "unsigned short" or $type eq "long";
1803     return "static_cast<Range::CompareHow>($value->Int32Value())" if $type eq "CompareHow";
1804     return "static_cast<SVGPaint::SVGPaintType>($value->ToInt32()->Int32Value())" if $type eq "SVGPaintType";
1805
1806     return "toWebCoreString($value)" if $type eq "AtomicString" or $type eq "DOMUserData";
1807     if ($type eq "DOMString") {
1808         return "toWebCoreStringWithNullCheck($value)" if $signature->extendedAttributes->{"ConvertNullToNullString"};
1809         return "toWebCoreStringWithNullOrUndefinedCheck($value)" if $signature->extendedAttributes->{"ConvertUndefinedOrNullToNullString"};
1810         return "toWebCoreString($value)";
1811     }
1812
1813     if ($type eq "NodeFilter") {
1814         return "V8Proxy::wrapNativeNodeFilter($value)";
1815     }
1816
1817     if ($type eq "SVGRect") {
1818         $implIncludes{"FloatRect.h"} = 1;
1819     }
1820
1821     if ($type eq "SVGPoint") {
1822         $implIncludes{"FloatPoint.h"} = 1;
1823     }
1824
1825     # Default, assume autogenerated type conversion routines
1826     $implIncludes{"V8Proxy.h"} = 1;
1827     if ($type eq "EventTarget") {
1828         $implIncludes{"V8Node.h"} = 1;
1829
1830         # EventTarget is not in DOM hierarchy, but all Nodes are EventTarget.
1831         return "V8Node::HasInstance($value) ? V8Proxy::convertDOMWrapperToNode<Node>($value) : 0";
1832     }
1833
1834     AddIncludesForType($type);
1835     # $implIncludes{"$type.h"} = 1 unless AvoidInclusionOfType($type);
1836
1837     if (IsDOMNodeType($type)) {
1838         $implIncludes{"V8${type}.h"} = 1;
1839
1840         # Perform type checks on the parameter, if it is expected Node type,
1841         # return NULL.
1842         return "V8${type}::HasInstance($value) ? V8Proxy::convertDOMWrapperToNode<${type}>($value) : 0";
1843     } else {
1844         # TODO: Temporary to avoid Window name conflict.
1845         my $classIndex = uc($type);
1846         my $implClassName = ${type};
1847
1848         $implIncludes{"V8$type.h"} = 1;
1849
1850         if (IsPodType($type)) {
1851             my $nativeType = GetNativeType($type);
1852             $implIncludes{"V8SVGPODTypeWrapper.h"} = 1;
1853
1854             return "V8SVGPODTypeUtil::toSVGPODType<${nativeType}>(V8ClassIndex::${classIndex}, $value${maybeOkParam})"
1855         }
1856
1857         $implIncludes{"V8${type}.h"} = 1;
1858
1859         # Perform type checks on the parameter, if it is expected Node type,
1860         # return NULL.
1861         return "V8${type}::HasInstance($value) ? V8Proxy::convertToNativeObject<${implClassName}>(V8ClassIndex::${classIndex}, $value) : 0";
1862     }
1863 }
1864
1865
1866 sub GetV8HeaderName
1867 {
1868     my $type = shift;
1869     return "V8" . GetImplementationFileName($type);
1870 }
1871
1872
1873 sub CreateCustomSignature
1874 {
1875     my $function = shift;
1876     my $count = @{$function->parameters};
1877     my $name = $function->signature->name;
1878     my $result = "  const int ${name}_argc = ${count};\n" .
1879       "  v8::Handle<v8::FunctionTemplate> ${name}_argv[${name}_argc] = { ";
1880     my $first = 1;
1881     foreach my $parameter (@{$function->parameters}) {
1882         if ($first) { $first = 0; }
1883         else { $result .= ", "; }
1884         if (IsWrapperType($parameter->type)) {
1885             my $type = $parameter->type;
1886             my $header = GetV8HeaderName($type);
1887             $implIncludes{$header} = 1;
1888             $result .= "V8${type}::GetRawTemplate()";
1889         } else {
1890             $result .= "v8::Handle<v8::FunctionTemplate>()";
1891         }
1892     }
1893     $result .= " };\n";
1894     $result .= "  v8::Handle<v8::Signature> ${name}_signature = v8::Signature::New(desc, ${name}_argc, ${name}_argv);\n";
1895     return $result;
1896 }
1897
1898
1899 sub RequiresCustomSignature
1900 {
1901     my $function = shift;
1902     # No signature needed for Custom function
1903     if ($function->signature->extendedAttributes->{"Custom"} ||
1904         $function->signature->extendedAttributes->{"V8Custom"}) {
1905         return 0;
1906     }
1907
1908     foreach my $parameter (@{$function->parameters}) {
1909       if (IsWrapperType($parameter->type)) {
1910           return 1;
1911       }
1912     }
1913     return 0;
1914 }
1915
1916
1917 my %non_wrapper_types = (
1918     'float' => 1,
1919     'AtomicString' => 1,
1920     'double' => 1,
1921     'short' => 1,
1922     'unsigned short' => 1,
1923     'long' => 1,
1924     'unsigned long' => 1,
1925     'boolean' => 1,
1926     'DOMString' => 1,
1927     'CompareHow' => 1,
1928     'SVGRect' => 1,
1929     'SVGPoint' => 1,
1930     'SVGMatrix' => 1,
1931     'SVGTransform' => 1,
1932     'SVGLength' => 1,
1933     'SVGNumber' => 1,
1934     'SVGPaintType' => 1,
1935     'DOMTimeStamp' => 1,
1936     'JSObject' => 1,
1937     'EventTarget' => 1,
1938     'NodeFilter' => 1,
1939     'EventListener' => 1
1940 );
1941
1942
1943 sub IsWrapperType
1944 {
1945     my $type = $codeGenerator->StripModule(shift);
1946     return !($non_wrapper_types{$type});
1947 }
1948
1949 sub IsDOMNodeType
1950 {
1951     my $type = shift;
1952
1953     return 1 if $type eq 'Attr';
1954     return 1 if $type eq 'CDATASection';
1955     return 1 if $type eq 'Comment';
1956     return 1 if $type eq 'Document';
1957     return 1 if $type eq 'DocumentFragment';
1958     return 1 if $type eq 'DocumentType';
1959     return 1 if $type eq 'Element';
1960     return 1 if $type eq 'EntityReference';
1961     return 1 if $type eq 'HTMLCanvasElement';
1962     return 1 if $type eq 'HTMLDocument';
1963     return 1 if $type eq 'HTMLElement';
1964     return 1 if $type eq 'HTMLFormElement';
1965     return 1 if $type eq 'HTMLTableCaptionElement';
1966     return 1 if $type eq 'HTMLTableSectionElement';
1967     return 1 if $type eq 'Node';
1968     return 1 if $type eq 'ProcessingInstruction';
1969     return 1 if $type eq 'SVGElement';
1970     return 1 if $type eq 'SVGDocument';
1971     return 1 if $type eq 'SVGSVGElement';
1972     return 1 if $type eq 'SVGUseElement';
1973     return 1 if $type eq 'Text';
1974
1975     return 0;
1976 }
1977
1978
1979 sub NativeToJSValue
1980 {
1981     my $signature = shift;
1982     my $value = shift;
1983     my $type = $codeGenerator->StripModule($signature->type);
1984     my $className= "V8$type";
1985
1986     return "v8::Date::New(static_cast<double>($value))" if $type eq "DOMTimeStamp";
1987     return "$value ? v8::True() : v8::False()" if $type eq "boolean";
1988     return "v8::Undefined()" if $type eq "void";
1989
1990     # For all the types where we use 'int' as the representation type,
1991     # we use Integer::New which has a fast Smi conversion check.
1992     return "v8::Integer::New($value)" if GetNativeType($type) eq "int";
1993
1994     return "v8::Number::New($value)" if $codeGenerator->IsPrimitiveType($type) or $type eq "SVGPaintType";
1995
1996     if ($codeGenerator->IsStringType($type)) {
1997         my $conv = $signature->extendedAttributes->{"ConvertNullStringTo"};
1998         if (defined $conv) {
1999             return "v8StringOrNull($value)" if $conv eq "Null";
2000             return "v8StringOrUndefined($value)" if $conv eq "Undefined";
2001             return "v8StringOrFalse($value)" if $conv eq "False";
2002
2003             die "Unknown value for ConvertNullStringTo extended attribute";
2004         }
2005         return "v8String($value)";
2006     }
2007
2008     # V8 specific.
2009     my $implClassName = $type;
2010     AddIncludesForType($type);
2011     # $implIncludes{GetImplementationFileName($type)} = 1 unless AvoidInclusionOfType($type);
2012
2013     # special case for non-DOM node interfaces
2014     if (IsDOMNodeType($type)) {
2015         return "V8Proxy::convertNodeToV8Object($value)";
2016     }
2017
2018     if ($type eq "EventTarget" or $type eq "SVGElementInstance") {
2019         return "V8Proxy::convertEventTargetToV8Object($value)";
2020     }
2021
2022     if ($type eq "Event") {
2023         return "V8Proxy::convertEventToV8Object($value)";
2024     }
2025
2026     if ($type eq "EventListener") {
2027         return "V8Proxy::convertEventListenerToV8Object($value)";
2028     }
2029
2030     if ($type eq "RGBColor") {
2031         return "V8Proxy::convertToV8Object(V8ClassIndex::RGBCOLOR, new RGBColor($value))";
2032     }
2033
2034     if ($type eq "WorkerContext" or $type eq "WorkerLocation" or $type eq "WorkerNavigator") {
2035         $implIncludes{"WorkerContextExecutionProxy.h"} = 1;
2036         my $classIndex = uc($type);
2037
2038         return "WorkerContextExecutionProxy::ToV8Object(V8ClassIndex::$classIndex, $value)";
2039     }
2040
2041     else {
2042         $implIncludes{"wtf/RefCounted.h"} = 1;
2043         $implIncludes{"wtf/RefPtr.h"} = 1;
2044         my $classIndex = uc($type);
2045
2046         if (IsPodType($type)) {
2047             $value = GenerateSVGStaticPodTypeWrapper($type, $value);
2048         }
2049
2050         return "V8Proxy::convertToV8Object(V8ClassIndex::$classIndex, $value)";
2051     }
2052 }
2053
2054 sub GenerateSVGStaticPodTypeWrapper {
2055     my $type = shift;
2056     my $value = shift;
2057
2058     $implIncludes{"V8$type.h"}=1;
2059     $implIncludes{"V8SVGPODTypeWrapper.h"} = 1;
2060
2061     my $nativeType = GetNativeType($type);
2062     return "new V8SVGStaticPODTypeWrapper<$nativeType>($value)";
2063 }
2064
2065 # Internal helper
2066 sub WriteData
2067 {
2068     if (defined($IMPL)) {
2069         # Write content to file.
2070         print $IMPL @implContentHeader;
2071
2072         print $IMPL @implFixedHeader;
2073
2074         foreach my $implInclude (sort keys(%implIncludes)) {
2075             my $checkType = $implInclude;
2076             $checkType =~ s/\.h//;
2077
2078             print $IMPL "#include \"$implInclude\"\n" unless $codeGenerator->IsSVGAnimatedType($checkType);
2079         }
2080
2081         print $IMPL "\n";
2082         print $IMPL @implContentDecls;
2083         print $IMPL @implContent;
2084         close($IMPL);
2085         undef($IMPL);
2086
2087         %implIncludes = ();
2088         @implFixedHeader = ();
2089         @implHeaderContent = ();
2090         @implContentDecls = ();
2091         @implContent = ();
2092     }
2093
2094     if (defined($HEADER)) {
2095         # Write content to file.
2096         print $HEADER @headerContent;
2097         close($HEADER);
2098         undef($HEADER);
2099
2100         @headerContent = ();
2101     }
2102 }
2103
2104 sub IsSVGTypeNeedingContextParameter
2105 {
2106     my $implClassName = shift;
2107
2108     if ($implClassName =~ /SVG/ and not $implClassName =~ /Element/) {
2109         return 1 unless $implClassName =~ /SVGPaint/ or $implClassName =~ /SVGColor/ or $implClassName =~ /SVGDocument/;
2110     }
2111
2112     return 0;
2113 }
2114
2115 sub GenerateSVGContextAssignment
2116 {
2117     my $srcType = shift;
2118     my $value = shift;
2119     my $indent = shift;
2120
2121     $result = GenerateSVGContextRetrieval($srcType, $indent);
2122     $result .=   $indent . "V8Proxy::setSVGContext($value, context);\n";
2123
2124     return $result;
2125 }
2126
2127 sub GenerateSVGContextRetrieval
2128 {
2129     my $srcType = shift;
2130     my $indent = shift;
2131
2132     my $srcIsPodType = IsPodType($srcType);
2133
2134     my $srcObject = "imp";
2135     if ($srcIsPodType) {
2136         $srcObject = "imp_wrapper";
2137     }
2138
2139     my $contextDecl;
2140
2141     if (IsSVGTypeNeedingContextParameter($srcType)) {
2142         $contextDecl = "V8Proxy::svgContext($srcObject)";
2143     } else {
2144         $contextDecl = $srcObject;
2145     }
2146
2147     return $indent . "SVGElement* context = $contextDecl;\n";
2148 }
2149
2150 sub IsSVGListMutator
2151 {
2152     my $functionName = shift;
2153
2154     return 1 if $functionName eq "clear";
2155     return 1 if $functionName eq "initialize";
2156     return 1 if $functionName eq "insertItemBefore";
2157     return 1 if $functionName eq "replaceItem";
2158     return 1 if $functionName eq "removeItem";
2159     return 1 if $functionName eq "appendItem";
2160
2161     return 0;
2162 }
2163
2164 sub IsSVGListMethod
2165 {
2166     my $functionName = shift;
2167
2168     return 1 if $functionName eq "getFirst";
2169     return 1 if $functionName eq "getLast";
2170     return 1 if $functionName eq "getItem";
2171
2172     return IsSVGListMutator($functionName);
2173 }
2174
2175 sub IsSVGListTypeNeedingSpecialHandling
2176 {
2177     my $className = shift;
2178
2179     return 1 if $className eq "SVGPointList";
2180     return 1 if $className eq "SVGTransformList";
2181
2182     return 0;
2183 }
2184
2185 sub DebugPrint
2186 {
2187     my $output = shift;
2188
2189     print $output;
2190     print "\n";
2191 }