1# Copyright (C) 2005, 2006 Nikolas Zimmermann <zimmermann@kde.org>
2# Copyright (C) 2006 Anders Carlsson <andersca@mac.com>
3# Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
4# Copyright (C) 2006 Alexey Proskuryakov <ap@webkit.org>
5# Copyright (C) 2006 Apple Computer, Inc.
6# Copyright (C) 2007, 2008, 2009 Google Inc.
7# Copyright (C) 2009 Cameron McCormack <cam@mcc.id.au>
8# Copyright (C) Research In Motion Limited 2010. All rights reserved.
9# Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
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# along 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
27package CodeGeneratorV8;
28
29use Digest::MD5;
30
31my $module = "";
32my $outputDir = "";
33my $outputHeadersDir = "";
34
35my @headerContent = ();
36my @implContentHeader = ();
37my @implFixedHeader = ();
38my @implContent = ();
39my @implContentDecls = ();
40my %implIncludes = ();
41my %headerIncludes = ();
42
43my @allParents = ();
44
45# Default .h template
46my $headerTemplate = << "EOF";
47/*
48    This file is part of the WebKit open source project.
49    This file has been generated by generate-bindings.pl. DO NOT MODIFY!
50
51    This library is free software; you can redistribute it and/or
52    modify it under the terms of the GNU Library General Public
53    License as published by the Free Software Foundation; either
54    version 2 of the License, or (at your option) any later version.
55
56    This library is distributed in the hope that it will be useful,
57    but WITHOUT ANY WARRANTY; without even the implied warranty of
58    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
59    Library General Public License for more details.
60
61    You should have received a copy of the GNU Library General Public License
62    along with this library; see the file COPYING.LIB.  If not, write to
63    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
64    Boston, MA 02111-1307, USA.
65*/
66EOF
67
68# Default constructor
69sub new
70{
71    my $object = shift;
72    my $reference = { };
73
74    $codeGenerator = shift;
75    $outputDir = shift;
76    $outputHeadersDir = shift;
77
78    bless($reference, $object);
79    return $reference;
80}
81
82sub finish
83{
84    my $object = shift;
85
86    # Commit changes!
87    $object->WriteData();
88}
89
90# Params: 'domClass' struct
91sub GenerateInterface
92{
93    my $object = shift;
94    my $dataNode = shift;
95    my $defines = shift;
96
97    # Start actual generation
98    if ($dataNode->extendedAttributes->{"Callback"}) {
99        $object->GenerateCallbackHeader($dataNode);
100        $object->GenerateCallbackImplementation($dataNode);
101    } else {
102        $object->GenerateHeader($dataNode);
103        $object->GenerateImplementation($dataNode);
104    }
105
106    my $name = $dataNode->name;
107
108    # Open files for writing
109    my $headerFileName = "$outputHeadersDir/V8$name.h";
110    my $implFileName = "$outputDir/V8$name.cpp";
111
112    open($IMPL, ">$implFileName") || die "Couldn't open file $implFileName";
113    open($HEADER, ">$headerFileName") || die "Couldn't open file $headerFileName";
114}
115
116# Params: 'idlDocument' struct
117sub GenerateModule
118{
119    my $object = shift;
120    my $dataNode = shift;
121
122    $module = $dataNode->module;
123}
124
125sub AddIncludesForType
126{
127    my $type = $codeGenerator->StripModule(shift);
128
129    # When we're finished with the one-file-per-class
130    # reorganization, we won't need these special cases.
131    if (!$codeGenerator->IsPrimitiveType($type) and !$codeGenerator->IsStringType($type) and !$codeGenerator->AvoidInclusionOfType($type) and $type ne "Date") {
132        # default, include the same named file
133        $implIncludes{GetV8HeaderName(${type})} = 1;
134
135        if ($type =~ /SVGPathSeg/) {
136            $joinedName = $type;
137            $joinedName =~ s/Abs|Rel//;
138            $implIncludes{"${joinedName}.h"} = 1;
139        }
140    }
141
142    # additional includes (things needed to compile the bindings but not the header)
143
144    if ($type eq "CanvasRenderingContext2D") {
145        $implIncludes{"CanvasGradient.h"} = 1;
146        $implIncludes{"CanvasPattern.h"} = 1;
147        $implIncludes{"CanvasStyle.h"} = 1;
148    }
149
150    if ($type eq "CanvasGradient" or $type eq "XPathNSResolver") {
151        $implIncludes{"PlatformString.h"} = 1;
152    }
153
154    if ($type eq "CSSStyleDeclaration") {
155        $implIncludes{"CSSMutableStyleDeclaration.h"} = 1;
156    }
157
158    if ($type eq "Plugin" or $type eq "PluginArray" or $type eq "MimeTypeArray") {
159        # So we can get String -> AtomicString conversion for namedItem().
160        $implIncludes{"wtf/text/AtomicString.h"} = 1;
161    }
162}
163
164# If the node has a [Conditional=XXX] attribute, returns an "ENABLE(XXX)" string for use in an #if.
165sub GenerateConditionalString
166{
167    my $node = shift;
168    my $conditional = $node->extendedAttributes->{"Conditional"};
169    if ($conditional) {
170        if ($conditional =~ /&/) {
171            return "ENABLE(" . join(") && ENABLE(", split(/&/, $conditional)) . ")";
172        } elsif ($conditional =~ /\|/) {
173            return "ENABLE(" . join(") || ENABLE(", split(/\|/, $conditional)) . ")";
174        } else {
175            return "ENABLE(" . $conditional . ")";
176        }
177    } else {
178        return "";
179    }
180}
181
182sub GetSVGPropertyTypes
183{
184    my $implType = shift;
185
186    my $svgPropertyType;
187    my $svgListPropertyType;
188    my $svgNativeType;
189
190    return ($svgPropertyType, $svgListPropertyType, $svgNativeType) if not $implType =~ /SVG/;
191
192    $svgNativeType = $codeGenerator->GetSVGTypeNeedingTearOff($implType);
193    return ($svgPropertyType, $svgListPropertyType, $svgNativeType) if not $svgNativeType;
194
195    # Append space to avoid compilation errors when using  PassRefPtr<$svgNativeType>
196    $svgNativeType = "$svgNativeType ";
197
198    my $svgWrappedNativeType = $codeGenerator->GetSVGWrappedTypeNeedingTearOff($implType);
199    if ($svgNativeType =~ /SVGPropertyTearOff/) {
200        $svgPropertyType = $svgWrappedNativeType;
201        $implIncludes{"SVGAnimatedPropertyTearOff.h"} = 1;
202    } elsif ($svgNativeType =~ /SVGListPropertyTearOff/ or $svgNativeType =~ /SVGStaticListPropertyTearOff/) {
203        $svgListPropertyType = $svgWrappedNativeType;
204        $headerIncludes{"SVGAnimatedListPropertyTearOff.h"} = 1;
205        $headerIncludes{"SVGStaticListPropertyTearOff.h"} = 1;
206    } elsif ($svgNativeType =~ /SVGTransformListPropertyTearOff/) {
207        $svgListPropertyType = $svgWrappedNativeType;
208        $headerIncludes{"SVGAnimatedListPropertyTearOff.h"} = 1;
209        $headerIncludes{"SVGTransformListPropertyTearOff.h"} = 1;
210    } elsif ($svgNativeType =~ /SVGPathSegListPropertyTearOff/) {
211        $svgListPropertyType = $svgWrappedNativeType;
212        $headerIncludes{"SVGPathSegListPropertyTearOff.h"} = 1;
213    }
214
215    if ($svgPropertyType) {
216        $svgPropertyType = "SVGPoint" if $svgPropertyType eq "FloatPoint";
217    }
218
219    return ($svgPropertyType, $svgListPropertyType, $svgNativeType);
220}
221
222sub GenerateHeader
223{
224    my $object = shift;
225    my $dataNode = shift;
226
227    my $interfaceName = $dataNode->name;
228    my $className = "V8$interfaceName";
229    my $implClassName = $interfaceName;
230
231    # Copy contents of parent classes except the first parent or if it is
232    # EventTarget.
233    $codeGenerator->AddMethodsConstantsAndAttributesFromParentClasses($dataNode, \@allParents, 1);
234
235    my $hasLegacyParent = $dataNode->extendedAttributes->{"LegacyParent"};
236
237    # - Add default header template
238    push(@headerContent, GenerateHeaderContentHeader($dataNode));
239
240    $headerIncludes{"wtf/text/StringHash.h"} = 1;
241    $headerIncludes{"WrapperTypeInfo.h"} = 1;
242    $headerIncludes{"V8DOMWrapper.h"} = 1;
243
244    my $headerClassInclude = GetHeaderClassInclude($implClassName);
245    $headerIncludes{$headerClassInclude} = 1 if $headerClassInclude ne "";
246
247    my ($svgPropertyType, $svgListPropertyType, $svgNativeType) = GetSVGPropertyTypes($implClassName);
248
249    foreach my $headerInclude (sort keys(%headerIncludes)) {
250        if ($headerInclude =~ /wtf/) {
251            push(@headerContent, "#include \<${headerInclude}\>\n");
252        } else {
253            push(@headerContent, "#include \"${headerInclude}\"\n");
254        }
255    }
256
257    push(@headerContent, "#include <v8.h>\n");
258    push(@headerContent, "#include <wtf/HashMap.h>\n");
259
260    push(@headerContent, "\nnamespace WebCore {\n");
261    push(@headerContent, "\ntemplate<typename PropertyType> class SVGPropertyTearOff;\n") if $svgPropertyType;
262    if ($svgNativeType) {
263        if ($svgNativeType =~ /SVGStaticListPropertyTearOff/) {
264            push(@headerContent, "\ntemplate<typename PropertyType> class SVGStaticListPropertyTearOff;\n");
265        } else {
266            push(@headerContent, "\ntemplate<typename PropertyType> class SVGListPropertyTearOff;\n");
267        }
268    }
269    push(@headerContent, "\nclass FloatRect;\n") if $svgPropertyType && $svgPropertyType eq "FloatRect";
270    push(@headerContent, "\nclass $className {\n");
271
272    my $nativeType = GetNativeTypeForConversions($dataNode, $interfaceName);
273    my $domMapFunction = GetDomMapFunction($dataNode, $interfaceName);
274    my $forceNewObjectParameter = IsDOMNodeType($interfaceName) ? ", bool forceNewObject = false" : "";
275    my $forceNewObjectInput = IsDOMNodeType($interfaceName) ? ", bool forceNewObject" : "";
276    my $forceNewObjectCall = IsDOMNodeType($interfaceName) ? ", forceNewObject" : "";
277
278    push(@headerContent, <<END);
279
280public:
281    static bool HasInstance(v8::Handle<v8::Value> value);
282    static v8::Persistent<v8::FunctionTemplate> GetRawTemplate();
283    static v8::Persistent<v8::FunctionTemplate> GetTemplate();
284    static ${nativeType}* toNative(v8::Handle<v8::Object> object)
285    {
286        return reinterpret_cast<${nativeType}*>(object->GetPointerFromInternalField(v8DOMWrapperObjectIndex));
287    }
288    inline static v8::Handle<v8::Object> wrap(${nativeType}*${forceNewObjectParameter});
289    static void derefObject(void*);
290    static WrapperTypeInfo info;
291END
292    if (IsActiveDomType($implClassName)) {
293        push(@headerContent, "    static ActiveDOMObject* toActiveDOMObject(v8::Handle<v8::Object>);\n");
294    }
295
296    if ($implClassName eq "DOMWindow") {
297        push(@headerContent, <<END);
298    static v8::Persistent<v8::ObjectTemplate> GetShadowObjectTemplate();
299END
300    }
301
302    if ($implClassName eq "HTMLDocument") {
303      push(@headerContent, <<END);
304  static v8::Local<v8::Object> WrapInShadowObject(v8::Local<v8::Object> wrapper, Node* impl);
305  static v8::Handle<v8::Value> GetNamedProperty(HTMLDocument* htmlDocument, const AtomicString& key);
306END
307    }
308
309    my @enabledAtRuntime;
310    foreach my $function (@{$dataNode->functions}) {
311        my $name = $function->signature->name;
312        my $attrExt = $function->signature->extendedAttributes;
313
314        if ($attrExt->{"Custom"} || $attrExt->{"V8Custom"}) {
315            push(@headerContent, <<END);
316    static v8::Handle<v8::Value> ${name}Callback(const v8::Arguments&);
317END
318        }
319
320        if ($attrExt->{"EnabledAtRuntime"}) {
321            push(@enabledAtRuntime, $function);
322        }
323    }
324
325    if ($dataNode->extendedAttributes->{"CustomConstructor"} || $dataNode->extendedAttributes->{"V8CustomConstructor"} || $dataNode->extendedAttributes->{"CanBeConstructed"}) {
326        push(@headerContent, <<END);
327    static v8::Handle<v8::Value> constructorCallback(const v8::Arguments& args);
328END
329    }
330
331    foreach my $attribute (@{$dataNode->attributes}) {
332        my $name = $attribute->signature->name;
333        my $attrExt = $attribute->signature->extendedAttributes;
334        if ($attrExt->{"V8CustomGetter"} || $attrExt->{"CustomGetter"}
335            || $attrExt->{"V8Custom"} || $attrExt->{"Custom"}) {
336            push(@headerContent, <<END);
337    static v8::Handle<v8::Value> ${name}AccessorGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info);
338END
339        }
340        if ($attrExt->{"V8CustomSetter"} || $attrExt->{"CustomSetter"}
341            || $attrExt->{"V8Custom"} || $attrExt->{"Custom"}) {
342            push(@headerContent, <<END);
343    static void ${name}AccessorSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info);
344END
345        }
346        if ($attrExt->{"EnabledAtRuntime"}) {
347            push(@enabledAtRuntime, $attribute);
348        }
349    }
350
351    GenerateHeaderNamedAndIndexedPropertyAccessors($dataNode);
352    GenerateHeaderCustomCall($dataNode);
353    GenerateHeaderCustomInternalFieldIndices($dataNode);
354
355    if ($dataNode->extendedAttributes->{"CheckDomainSecurity"}) {
356        push(@headerContent, <<END);
357    static bool namedSecurityCheck(v8::Local<v8::Object> host, v8::Local<v8::Value> key, v8::AccessType, v8::Local<v8::Value> data);
358    static bool indexedSecurityCheck(v8::Local<v8::Object> host, uint32_t index, v8::AccessType, v8::Local<v8::Value> data);
359END
360    }
361
362    push(@headerContent, <<END);
363private:
364    static v8::Handle<v8::Object> wrapSlow(${nativeType}*);
365};
366
367END
368
369    push(@headerContent, <<END);
370
371v8::Handle<v8::Object> ${className}::wrap(${nativeType}* impl${forceNewObjectInput})
372{
373END
374    push(@headerContent, "    if (!forceNewObject) {\n") if IsDOMNodeType($interfaceName);
375    my $getWrapper = IsNodeSubType($dataNode) ? "V8DOMWrapper::getWrapper(impl)" : "${domMapFunction}.get(impl)";
376    push(@headerContent, <<END);
377        v8::Handle<v8::Object> wrapper = ${getWrapper};
378        if (!wrapper.IsEmpty())
379            return wrapper;
380END
381    push(@headerContent, "    }\n") if IsDOMNodeType($interfaceName);
382    push(@headerContent, <<END);
383    return ${className}::wrapSlow(impl);
384}
385END
386
387    if (!HasCustomToV8Implementation($dataNode, $interfaceName)) {
388        push(@headerContent, <<END);
389
390inline v8::Handle<v8::Value> toV8(${nativeType}* impl${forceNewObjectParameter})
391{
392    if (!impl)
393        return v8::Null();
394    return ${className}::wrap(impl${forceNewObjectCall});
395}
396END
397    } elsif ($interfaceName ne 'Node') {
398        push(@headerContent, <<END);
399
400v8::Handle<v8::Value> toV8(${nativeType}*${forceNewObjectParameter});
401END
402    } else {
403        push(@headerContent, <<END);
404
405v8::Handle<v8::Value> toV8Slow(Node*, bool);
406
407inline v8::Handle<v8::Value> toV8(Node* impl, bool forceNewObject = false)
408{
409    if (!impl)
410        return v8::Null();
411    if (!forceNewObject) {
412        v8::Handle<v8::Value> wrapper = V8DOMWrapper::getWrapper(impl);
413        if (!wrapper.IsEmpty())
414            return wrapper;
415    }
416    return toV8Slow(impl, forceNewObject);
417}
418END
419    }
420
421    if (IsRefPtrType($implClassName)) {
422        push(@headerContent, <<END);
423inline v8::Handle<v8::Value> toV8(PassRefPtr< ${nativeType} > impl${forceNewObjectParameter})
424{
425    return toV8(impl.get()${forceNewObjectCall});
426}
427END
428    }
429
430    push(@headerContent, "}\n\n");
431    push(@headerContent, "#endif // $className" . "_h\n");
432
433    my $conditionalString = GenerateConditionalString($dataNode);
434    push(@headerContent, "#endif // ${conditionalString}\n\n") if $conditionalString;
435}
436
437sub GetInternalFields
438{
439    my $dataNode = shift;
440    my $name = $dataNode->name;
441
442    my @customInternalFields = ();
443
444    # We can't ask whether a parent type has a given extendedAttribute, so special-case AbstractWorker and WorkerContext to include all sub-types.
445    # Event listeners on DOM nodes are explicitly supported in the GC controller.
446    # FIXME: SVGElementInstance should probably have the EventTarget extended attribute, but doesn't.
447    if (!IsNodeSubType($dataNode) &&
448        ($dataNode->extendedAttributes->{"EventTarget"} ||
449         IsSubType($dataNode, "AbstractWorker") ||
450         IsSubType($dataNode, "WorkerContext") ||
451         $name eq "SVGElementInstance")) {
452        push(@customInternalFields, "eventListenerCacheIndex");
453    }
454
455    if ($name eq "DOMWindow") {
456        push(@customInternalFields, "enteredIsolatedWorldIndex");
457    }
458    return @customInternalFields;
459}
460
461sub GetHeaderClassInclude
462{
463    my $className = shift;
464    if ($className =~ /SVGPathSeg/) {
465        $className =~ s/Abs|Rel//;
466    }
467    return "" if ($codeGenerator->AvoidInclusionOfType($className));
468    return "${className}.h";
469}
470
471sub GenerateHeaderCustomInternalFieldIndices
472{
473    my $dataNode = shift;
474    my @customInternalFields = GetInternalFields($dataNode);
475    my $customFieldCounter = 0;
476    foreach my $customInternalField (@customInternalFields) {
477        push(@headerContent, <<END);
478    static const int ${customInternalField} = v8DefaultWrapperInternalFieldCount + ${customFieldCounter};
479END
480        $customFieldCounter++;
481    }
482    push(@headerContent, <<END);
483    static const int internalFieldCount = v8DefaultWrapperInternalFieldCount + ${customFieldCounter};
484END
485}
486
487my %indexerSpecialCases = (
488    "Storage" => 1,
489    "HTMLAppletElement" => 1,
490    "HTMLEmbedElement" => 1,
491    "HTMLObjectElement" => 1
492);
493
494sub GenerateHeaderNamedAndIndexedPropertyAccessors
495{
496    my $dataNode = shift;
497    my $interfaceName = $dataNode->name;
498    my $hasCustomIndexedGetter = $dataNode->extendedAttributes->{"HasIndexGetter"} || $dataNode->extendedAttributes->{"CustomGetOwnPropertySlot"};
499    my $hasCustomIndexedSetter = $dataNode->extendedAttributes->{"HasCustomIndexSetter"} && !$dataNode->extendedAttributes->{"HasNumericIndexGetter"};
500    my $hasCustomNamedGetter = $dataNode->extendedAttributes->{"HasNameGetter"} || $dataNode->extendedAttributes->{"HasOverridingNameGetter"} || $dataNode->extendedAttributes->{"CustomGetOwnPropertySlot"};
501    my $hasCustomNamedSetter = $dataNode->extendedAttributes->{"DelegatingPutFunction"};
502    my $hasCustomDeleters = $dataNode->extendedAttributes->{"CustomDeleteProperty"};
503    my $hasCustomEnumerator = $dataNode->extendedAttributes->{"CustomGetPropertyNames"};
504    if ($interfaceName eq "HTMLOptionsCollection") {
505        $interfaceName = "HTMLCollection";
506        $hasCustomIndexedGetter = 1;
507        $hasCustomNamedGetter = 1;
508    }
509    if ($interfaceName eq "DOMWindow") {
510        $hasCustomDeleterr = 0;
511        $hasEnumerator = 0;
512    }
513    if ($interfaceName eq "HTMLAppletElement" || $interfaceName eq "HTMLEmbedElement" || $interfaceName eq "HTMLObjectElement") {
514        $hasCustomNamedGetter = 1;
515    }
516    if ($interfaceName eq "HTMLDocument") {
517        $hasCustomNamedGetter = 0;
518        $hasCustomIndexedGetter = 0;
519    }
520    my $isIndexerSpecialCase = exists $indexerSpecialCases{$interfaceName};
521
522    if ($hasCustomIndexedGetter || $isIndexerSpecialCase) {
523        push(@headerContent, <<END);
524    static v8::Handle<v8::Value> indexedPropertyGetter(uint32_t, const v8::AccessorInfo&);
525END
526    }
527
528    if ($isIndexerSpecialCase || $hasCustomIndexedSetter) {
529        push(@headerContent, <<END);
530    static v8::Handle<v8::Value> indexedPropertySetter(uint32_t, v8::Local<v8::Value>, const v8::AccessorInfo&);
531END
532    }
533    if ($hasCustomDeleters) {
534        push(@headerContent, <<END);
535    static v8::Handle<v8::Boolean> indexedPropertyDeleter(uint32_t, const v8::AccessorInfo&);
536END
537    }
538    if ($hasCustomNamedGetter) {
539        push(@headerContent, <<END);
540    static v8::Handle<v8::Value> namedPropertyGetter(v8::Local<v8::String>, const v8::AccessorInfo&);
541END
542    }
543    if ($hasCustomNamedSetter) {
544        push(@headerContent, <<END);
545    static v8::Handle<v8::Value> namedPropertySetter(v8::Local<v8::String>, v8::Local<v8::Value>, const v8::AccessorInfo&);
546END
547    }
548    if ($hasCustomDeleters) {
549        push(@headerContent, <<END);
550    static v8::Handle<v8::Boolean> namedPropertyDeleter(v8::Local<v8::String>, const v8::AccessorInfo&);
551END
552    }
553    if ($hasCustomEnumerator) {
554        push(@headerContent, <<END);
555    static v8::Handle<v8::Array> namedPropertyEnumerator(const v8::AccessorInfo&);
556    static v8::Handle<v8::Integer> namedPropertyQuery(v8::Local<v8::String>, const v8::AccessorInfo&);
557END
558    }
559}
560
561sub GenerateHeaderCustomCall
562{
563    my $dataNode = shift;
564
565    if ($dataNode->extendedAttributes->{"CustomCall"}) {
566        push(@headerContent, "    static v8::Handle<v8::Value> callAsFunctionCallback(const v8::Arguments&);\n");
567    }
568    if ($dataNode->name eq "Event") {
569        push(@headerContent, "    static v8::Handle<v8::Value> dataTransferAccessorGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info);\n");
570        push(@headerContent, "    static void valueAccessorSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info);\n");
571    }
572    if ($dataNode->name eq "Location") {
573        push(@headerContent, "    static v8::Handle<v8::Value> assignAccessorGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info);\n");
574        push(@headerContent, "    static v8::Handle<v8::Value> reloadAccessorGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info);\n");
575        push(@headerContent, "    static v8::Handle<v8::Value> replaceAccessorGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info);\n");
576    }
577}
578
579sub GenerateSetDOMException
580{
581    my $indent = shift;
582    my $result = "";
583
584    $result .= $indent . "if (UNLIKELY(ec)) {\n";
585    $result .= $indent . "    V8Proxy::setDOMException(ec);\n";
586    $result .= $indent . "    return v8::Handle<v8::Value>();\n";
587    $result .= $indent . "}\n";
588
589    return $result;
590}
591
592sub IsSubType
593{
594    my $dataNode = shift;
595    my $parentType = shift;
596    return 1 if ($dataNode->name eq $parentType);
597    foreach (@allParents) {
598        my $parent = $codeGenerator->StripModule($_);
599        return 1 if $parent eq $parentType;
600    }
601    return 0;
602}
603
604sub IsNodeSubType
605{
606    my $dataNode = shift;
607    return IsSubType($dataNode, "Node");
608}
609
610sub GenerateDomainSafeFunctionGetter
611{
612    my $function = shift;
613    my $implClassName = shift;
614
615    my $className = "V8" . $implClassName;
616    my $funcName = $function->signature->name;
617
618    my $signature = "v8::Signature::New(" . $className . "::GetRawTemplate())";
619    if ($function->signature->extendedAttributes->{"V8DoNotCheckSignature"}) {
620        $signature = "v8::Local<v8::Signature>()";
621    }
622
623    my $newTemplateString = GenerateNewFunctionTemplate($function, $implClassName, $signature);
624
625    push(@implContentDecls, <<END);
626static v8::Handle<v8::Value> ${funcName}AttrGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info)
627{
628    INC_STATS(\"DOM.$implClassName.$funcName._get\");
629    static v8::Persistent<v8::FunctionTemplate> privateTemplate = v8::Persistent<v8::FunctionTemplate>::New($newTemplateString);
630    v8::Handle<v8::Object> holder = V8DOMWrapper::lookupDOMWrapper(${className}::GetTemplate(), info.This());
631    if (holder.IsEmpty()) {
632        // can only reach here by 'object.__proto__.func', and it should passed
633        // domain security check already
634        return privateTemplate->GetFunction();
635    }
636    ${implClassName}* imp = ${className}::toNative(holder);
637    if (!V8BindingSecurity::canAccessFrame(V8BindingState::Only(), imp->frame(), false)) {
638        static v8::Persistent<v8::FunctionTemplate> sharedTemplate = v8::Persistent<v8::FunctionTemplate>::New($newTemplateString);
639        return sharedTemplate->GetFunction();
640    }
641    return privateTemplate->GetFunction();
642}
643
644END
645}
646
647sub GenerateConstructorGetter
648{
649    my $implClassName = shift;
650
651    push(@implContentDecls, <<END);
652static v8::Handle<v8::Value> ${implClassName}ConstructorGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info)
653{
654    INC_STATS(\"DOM.$implClassName.constructors._get\");
655    v8::Handle<v8::Value> data = info.Data();
656    ASSERT(data->IsExternal() || data->IsNumber());
657    WrapperTypeInfo* type = WrapperTypeInfo::unwrap(data);
658END
659
660    if ($implClassName eq "DOMWindow") {
661        push(@implContentDecls, <<END);
662    // Get the proxy corresponding to the DOMWindow if possible to
663    // make sure that the constructor function is constructed in the
664    // context of the DOMWindow and not in the context of the caller.
665    return V8DOMWrapper::getConstructor(type, V8DOMWindow::toNative(info.Holder()));
666END
667    } elsif ($implClassName eq "DedicatedWorkerContext" or $implClassName eq "WorkerContext" or $implClassName eq "SharedWorkerContext") {
668        push(@implContentDecls, <<END);
669    return V8DOMWrapper::getConstructor(type, V8WorkerContext::toNative(info.Holder()));
670END
671    } else {
672        push(@implContentDecls, "    return v8::Handle<v8::Value>();");
673    }
674
675    push(@implContentDecls, <<END);
676}
677
678END
679}
680
681sub GenerateNormalAttrGetter
682{
683    my $attribute = shift;
684    my $dataNode = shift;
685    my $implClassName = shift;
686    my $interfaceName = shift;
687
688    my $attrExt = $attribute->signature->extendedAttributes;
689    my $attrName = $attribute->signature->name;
690    my $attrType = GetTypeFromSignature($attribute->signature);
691    my $nativeType = GetNativeTypeFromSignature($attribute->signature, -1);
692
693    my $getterStringUsesImp = $implClassName ne "SVGNumber";
694    my $svgNativeType = $codeGenerator->GetSVGTypeNeedingTearOff($implClassName);
695
696    # Getter
697    my $conditionalString = GenerateConditionalString($attribute->signature);
698    push(@implContentDecls, "#if ${conditionalString}\n\n") if $conditionalString;
699
700    push(@implContentDecls, <<END);
701static v8::Handle<v8::Value> ${attrName}AttrGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info)
702{
703    INC_STATS(\"DOM.$implClassName.$attrName._get\");
704END
705
706    if ($svgNativeType) {
707        my $svgWrappedNativeType = $codeGenerator->GetSVGWrappedTypeNeedingTearOff($implClassName);
708        if ($svgWrappedNativeType =~ /List/) {
709            push(@implContentDecls, <<END);
710    $svgNativeType* imp = V8${implClassName}::toNative(info.Holder());
711END
712        } else {
713            push(@implContentDecls, <<END);
714    $svgNativeType* wrapper = V8${implClassName}::toNative(info.Holder());
715    $svgWrappedNativeType& impInstance = wrapper->propertyReference();
716END
717            if ($getterStringUsesImp) {
718                push(@implContentDecls, <<END);
719    $svgWrappedNativeType* imp = &impInstance;
720END
721            }
722        }
723    } elsif ($attrExt->{"v8OnProto"} || $attrExt->{"V8DisallowShadowing"}) {
724        if ($interfaceName eq "DOMWindow") {
725            push(@implContentDecls, <<END);
726    v8::Handle<v8::Object> holder = info.Holder();
727END
728        } else {
729            # perform lookup first
730            push(@implContentDecls, <<END);
731    v8::Handle<v8::Object> holder = V8DOMWrapper::lookupDOMWrapper(V8${interfaceName}::GetTemplate(), info.This());
732    if (holder.IsEmpty())
733        return v8::Handle<v8::Value>();
734END
735        }
736        push(@implContentDecls, <<END);
737    ${implClassName}* imp = V8${implClassName}::toNative(holder);
738END
739    } else {
740        my $reflect = $attribute->signature->extendedAttributes->{"Reflect"};
741        my $url = $attribute->signature->extendedAttributes->{"URL"};
742        if ($getterStringUsesImp && $reflect && !$url && IsNodeSubType($dataNode) && $codeGenerator->IsStringType($attrType)) {
743            # Generate super-compact call for regular attribute getter:
744            my $contentAttributeName = $reflect eq "1" ? lc $attrName : $reflect;
745            my $namespace = $codeGenerator->NamespaceForAttributeName($interfaceName, $contentAttributeName);
746            $implIncludes{"${namespace}.h"} = 1;
747            push(@implContentDecls, "    return getElementStringAttr(info, ${namespace}::${contentAttributeName}Attr);\n");
748            push(@implContentDecls, "}\n\n");
749            push(@implContentDecls, "#endif // ${conditionalString}\n\n") if $conditionalString;
750            return;
751            # Skip the rest of the function!
752        }
753        push(@implContentDecls, <<END);
754    ${implClassName}* imp = V8${implClassName}::toNative(info.Holder());
755END
756    }
757
758    # Generate security checks if necessary
759    if ($attribute->signature->extendedAttributes->{"CheckNodeSecurity"}) {
760        push(@implContentDecls, "    if (!V8BindingSecurity::checkNodeSecurity(V8BindingState::Only(), imp->$attrName()))\n    return v8::Handle<v8::Value>();\n\n");
761    } elsif ($attribute->signature->extendedAttributes->{"CheckFrameSecurity"}) {
762        push(@implContentDecls, "    if (!V8BindingSecurity::checkNodeSecurity(V8BindingState::Only(), imp->contentDocument()))\n    return v8::Handle<v8::Value>();\n\n");
763    }
764
765    my $useExceptions = 1 if @{$attribute->getterExceptions};
766    if ($useExceptions) {
767        $implIncludes{"ExceptionCode.h"} = 1;
768        push(@implContentDecls, "    ExceptionCode ec = 0;\n");
769    }
770
771    if ($attribute->signature->extendedAttributes->{"v8referenceattr"}) {
772        $attrName = $attribute->signature->extendedAttributes->{"v8referenceattr"};
773    }
774
775    my $returnType = GetTypeFromSignature($attribute->signature);
776
777    my $getterString;
778    if ($getterStringUsesImp) {
779        $getterString = "imp->" . $codeGenerator->GetterExpressionPrefix(\%implIncludes, $interfaceName, $attribute);
780        $getterString .= "ec" if $useExceptions;
781        $getterString .= ")";
782    } else {
783        $getterString = "impInstance";
784    }
785
786    my $result;
787    my $wrapper;
788
789        if ($attribute->signature->type eq "EventListener" && $dataNode->name eq "DOMWindow") {
790        push(@implContentDecls, "    if (!imp->document())\n");
791        push(@implContentDecls, "        return v8::Handle<v8::Value>();\n");
792    }
793
794    if ($useExceptions) {
795        if ($nativeType =~ /^V8Parameter/) {
796          push(@implContentDecls, "    " . ConvertToV8Parameter($attribute->signature, $nativeType, "v", $getterString) . ";\n");
797        } else {
798          push(@implContentDecls, "    $nativeType v = $getterString;\n");
799        }
800        push(@implContentDecls, GenerateSetDOMException("    "));
801        $result = "v";
802        $result .= ".release()" if (IsRefPtrType($returnType));
803    } else {
804        # Can inline the function call into the return statement to avoid overhead of using a Ref<> temporary
805        $result = $getterString;
806    }
807
808    # Special case for readonly or Replaceable attributes (with a few exceptions). This attempts to ensure that JS wrappers don't get
809    # garbage-collected prematurely when their lifetime is strongly tied to their owner. We accomplish this by inserting a reference to
810    # the newly created wrapper into an internal field of the holder object.
811    if (!IsNodeSubType($dataNode) && $attrName ne "self" && (IsWrapperType($returnType) && ($attribute->type =~ /^readonly/ || $attribute->signature->extendedAttributes->{"Replaceable"})
812        && $returnType ne "EventTarget" && $returnType ne "SerializedScriptValue" && $returnType ne "DOMWindow"
813        && $returnType !~ /SVG/ && $returnType !~ /HTML/ && !IsDOMNodeType($returnType))) {
814        AddIncludesForType($returnType);
815        my $domMapFunction = GetDomMapFunction(0, $returnType);
816        # Check for a wrapper in the wrapper cache. If there is one, we know that a hidden reference has already
817        # been created. If we don't find a wrapper, we create both a wrapper and a hidden reference.
818        push(@implContentDecls, "    RefPtr<$returnType> result = ${getterString};\n");
819        push(@implContentDecls, "    v8::Handle<v8::Value> wrapper = result.get() ? ${domMapFunction}.get(result.get()) : v8::Handle<v8::Value>();\n");
820        push(@implContentDecls, "    if (wrapper.IsEmpty()) {\n");
821        push(@implContentDecls, "        wrapper = toV8(result.get());\n");
822        push(@implContentDecls, "        if (!wrapper.IsEmpty())\n");
823        if ($dataNode->name eq "DOMWindow") {
824            push(@implContentDecls, "            V8DOMWrapper::setHiddenWindowReference(imp->frame(), wrapper);\n");
825        } else {
826            push(@implContentDecls, "            V8DOMWrapper::setHiddenReference(info.Holder(), wrapper);\n");
827        }
828        push(@implContentDecls, "    }\n");
829        push(@implContentDecls, "    return wrapper;\n");
830        push(@implContentDecls, "}\n\n");
831        push(@implContentDecls, "#endif // ${conditionalString}\n\n") if $conditionalString;
832        return;
833    }
834
835    if ($codeGenerator->IsSVGAnimatedType($implClassName) and $codeGenerator->IsSVGTypeNeedingTearOff($attrType)) {
836        $implIncludes{"V8$attrType.h"} = 1;
837        my $svgNativeType = $codeGenerator->GetSVGTypeNeedingTearOff($attrType);
838        # Convert from abstract SVGProperty to real type, so the right toJS() method can be invoked.
839        push(@implContentDecls, "    return toV8(static_cast<$svgNativeType*>($result));\n");
840    } elsif ($codeGenerator->IsSVGTypeNeedingTearOff($attrType) and not $implClassName =~ /List$/) {
841        $implIncludes{"V8$attrType.h"} = 1;
842        $implIncludes{"SVGPropertyTearOff.h"} = 1;
843        my $tearOffType = $codeGenerator->GetSVGTypeNeedingTearOff($attrType);
844        if ($codeGenerator->IsSVGTypeWithWritablePropertiesNeedingTearOff($attrType) and not defined $attribute->signature->extendedAttributes->{"Immutable"}) {
845            my $getter = $result;
846            $getter =~ s/imp->//;
847            $getter =~ s/\(\)//;
848
849            my $updateMethod = "&${implClassName}::update" . $codeGenerator->WK_ucfirst($getter);
850
851            my $selfIsTearOffType = $codeGenerator->IsSVGTypeNeedingTearOff($implClassName);
852            if ($selfIsTearOffType) {
853                $implIncludes{"SVGStaticPropertyWithParentTearOff.h"} = 1;
854                $tearOffType =~ s/SVGPropertyTearOff</SVGStaticPropertyWithParentTearOff<$implClassName, /;
855
856                if ($result =~ /matrix/ and $implClassName eq "SVGTransform") {
857                    # SVGTransform offers a matrix() method for internal usage that returns an AffineTransform
858                    # and a svgMatrix() method returning a SVGMatrix, used for the bindings.
859                    $result =~ s/matrix/svgMatrix/;
860                }
861
862                push(@implContentDecls, "    return toV8(WTF::getPtr(${tearOffType}::create(wrapper, $result, $updateMethod)));\n");
863            } else {
864                $implIncludes{"SVGStaticPropertyTearOff.h"} = 1;
865                $tearOffType =~ s/SVGPropertyTearOff</SVGStaticPropertyTearOff<$implClassName, /;
866
867                push(@implContentDecls, "    return toV8(WTF::getPtr(${tearOffType}::create(imp, $result, $updateMethod)));\n");
868            }
869        } elsif ($tearOffType =~ /SVGStaticListPropertyTearOff/) {
870            my $extraImp = "GetOwnerElementForType<$implClassName, IsDerivedFromSVGElement<$implClassName>::value>::ownerElement(imp), ";
871            push(@implContentDecls, "    return toV8(WTF::getPtr(${tearOffType}::create($extraImp$result)));\n");
872        } elsif ($tearOffType =~ /SVG(Point|PathSeg)List/) {
873            push(@implContentDecls, "    return toV8(WTF::getPtr($result));\n");
874        } else {
875            push(@implContentDecls, "    return toV8(WTF::getPtr(${tearOffType}::create($result)));\n");
876        }
877    } else {
878        push(@implContentDecls, "    " . ReturnNativeToJSValue($attribute->signature, $result, "    ").";\n");
879    }
880
881    push(@implContentDecls, "}\n\n");  # end of getter
882    push(@implContentDecls, "#endif // ${conditionalString}\n\n") if $conditionalString;
883}
884
885sub GenerateNormalAttrSetter
886{
887    my $attribute = shift;
888    my $dataNode = shift;
889    my $implClassName = shift;
890    my $interfaceName = shift;
891
892    $implIncludes{"V8BindingMacros.h"} = 1;
893
894    my $attrExt = $attribute->signature->extendedAttributes;
895
896    my $conditionalString = GenerateConditionalString($attribute->signature);
897    push(@implContentDecls, "#if ${conditionalString}\n\n") if $conditionalString;
898
899    push(@implContentDecls, "static void ${attrName}AttrSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info)\n{\n");
900    push(@implContentDecls, "    INC_STATS(\"DOM.$implClassName.$attrName._set\");\n");
901
902    # If the "StrictTypeChecking" extended attribute is present, and the attribute's type is an
903    # interface type, then if the incoming value does not implement that interface, a TypeError is
904    # thrown rather than silently passing NULL to the C++ code.
905    # Per the Web IDL and ECMAScript specifications, incoming values can always be converted to both
906    # strings and numbers, so do not throw TypeError if the attribute is of these types.
907    if ($attribute->signature->extendedAttributes->{"StrictTypeChecking"}) {
908        my $argType = GetTypeFromSignature($attribute->signature);
909        if (IsWrapperType($argType)) {
910            push(@implContentDecls, "    if (!isUndefinedOrNull(value) && !V8${argType}::HasInstance(value)) {\n");
911            push(@implContentDecls, "        V8Proxy::throwTypeError();\n");
912            push(@implContentDecls, "        return;\n");
913            push(@implContentDecls, "    }\n");
914        }
915    }
916
917    my $svgNativeType = $codeGenerator->GetSVGTypeNeedingTearOff($implClassName);
918    if ($svgNativeType) {
919        my $svgWrappedNativeType = $codeGenerator->GetSVGWrappedTypeNeedingTearOff($implClassName);
920        if ($svgWrappedNativeType =~ /List$/) {
921            push(@implContentDecls, <<END);
922    $svgNativeType* imp = V8${implClassName}::toNative(info.Holder());
923END
924        } else {
925            push(@implContentDecls, "    $svgNativeType* wrapper = V8${implClassName}::toNative(info.Holder());\n");
926            push(@implContentDecls, "    if (wrapper->role() == AnimValRole) {\n");
927            push(@implContentDecls, "        V8Proxy::setDOMException(NO_MODIFICATION_ALLOWED_ERR);\n");
928            push(@implContentDecls, "        return;\n");
929            push(@implContentDecls, "    }\n");
930            push(@implContentDecls, "    $svgWrappedNativeType& impInstance = wrapper->propertyReference();\n");
931            push(@implContentDecls, "    $svgWrappedNativeType* imp = &impInstance;\n");
932        }
933    } elsif ($attrExt->{"v8OnProto"}) {
934      if ($interfaceName eq "DOMWindow") {
935        push(@implContentDecls, <<END);
936    v8::Handle<v8::Object> holder = info.Holder();
937END
938      } else {
939        # perform lookup first
940        push(@implContentDecls, <<END);
941    v8::Handle<v8::Object> holder = V8DOMWrapper::lookupDOMWrapper(V8${interfaceName}::GetTemplate(), info.This());
942    if (holder.IsEmpty())
943        return;
944END
945      }
946    push(@implContentDecls, <<END);
947    ${implClassName}* imp = V8${implClassName}::toNative(holder);
948END
949    } else {
950        my $attrType = GetTypeFromSignature($attribute->signature);
951        my $reflect = $attribute->signature->extendedAttributes->{"Reflect"};
952        if ($reflect && IsNodeSubType($dataNode) && $codeGenerator->IsStringType($attrType)) {
953            # Generate super-compact call for regular attribute setter:
954            my $contentAttributeName = $reflect eq "1" ? lc $attrName : $reflect;
955            my $namespace = $codeGenerator->NamespaceForAttributeName($interfaceName, $contentAttributeName);
956            $implIncludes{"${namespace}.h"} = 1;
957            push(@implContentDecls, "    setElementStringAttr(info, ${namespace}::${contentAttributeName}Attr, value);\n");
958            push(@implContentDecls, "}\n\n");
959            push(@implContentDecls, "#endif // ${conditionalString}\n\n") if $conditionalString;
960            return;
961            # Skip the rest of the function!
962        }
963
964        push(@implContentDecls, <<END);
965    ${implClassName}* imp = V8${implClassName}::toNative(info.Holder());
966END
967    }
968
969    my $nativeType = GetNativeTypeFromSignature($attribute->signature, 0);
970    if ($attribute->signature->type eq "EventListener") {
971        if ($dataNode->name eq "DOMWindow") {
972            push(@implContentDecls, "    if (!imp->document())\n");
973            push(@implContentDecls, "        return;\n");
974        }
975    } else {
976        my $value = JSValueToNative($attribute->signature, "value");
977        if ($nativeType =~ /^V8Parameter/) {
978          push(@implContentDecls, "    " . ConvertToV8Parameter($attribute->signature, $nativeType, "v", $value, "VOID") . "\n");
979        } else {
980          push(@implContentDecls, "    $nativeType v = $value;\n");
981        }
982    }
983
984    my $result = "v";
985    my $returnType = GetTypeFromSignature($attribute->signature);
986    if (IsRefPtrType($returnType)) {
987        $result = "WTF::getPtr(" . $result . ")";
988    }
989
990    my $useExceptions = 1 if @{$attribute->setterExceptions};
991
992    if ($useExceptions) {
993        $implIncludes{"ExceptionCode.h"} = 1;
994        push(@implContentDecls, "    ExceptionCode ec = 0;\n");
995    }
996
997    if ($implClassName eq "SVGNumber") {
998        push(@implContentDecls, "    *imp = $result;\n");
999    } else {
1000        if ($attribute->signature->type eq "EventListener") {
1001            my $implSetterFunctionName = $codeGenerator->WK_ucfirst($attrName);
1002            $implIncludes{"V8AbstractEventListener.h"} = 1;
1003            if (!IsNodeSubType($dataNode)) {
1004                push(@implContentDecls, "    transferHiddenDependency(info.Holder(), imp->$attrName(), value, V8${interfaceName}::eventListenerCacheIndex);\n");
1005            }
1006            if ($interfaceName eq "WorkerContext" and $attribute->signature->name eq "onerror") {
1007                $implIncludes{"V8EventListenerList.h"} = 1;
1008                $implIncludes{"V8WorkerContextErrorHandler.h"} = 1;
1009                push(@implContentDecls, "    imp->set$implSetterFunctionName(V8EventListenerList::findOrCreateWrapper<V8WorkerContextErrorHandler>(value, true)");
1010            } elsif ($interfaceName eq "DOMWindow" and $attribute->signature->name eq "onerror") {
1011                $implIncludes{"V8EventListenerList.h"} = 1;
1012                $implIncludes{"V8WindowErrorHandler.h"} = 1;
1013                push(@implContentDecls, "    imp->set$implSetterFunctionName(V8EventListenerList::findOrCreateWrapper<V8WindowErrorHandler>(value, true)");
1014            } else {
1015                push(@implContentDecls, "    imp->set$implSetterFunctionName(V8DOMWrapper::getEventListener(value, true, ListenerFindOrCreate)");
1016            }
1017        } else {
1018            my $setterExpressionPrefix = $codeGenerator->SetterExpressionPrefix(\%implIncludes, $interfaceName, $attribute);
1019            push(@implContentDecls, "    imp->$setterExpressionPrefix$result");
1020        }
1021        push(@implContentDecls, ", ec") if $useExceptions;
1022        push(@implContentDecls, ");\n");
1023    }
1024
1025    if ($useExceptions) {
1026        push(@implContentDecls, "    if (UNLIKELY(ec))\n");
1027        push(@implContentDecls, "        V8Proxy::setDOMException(ec);\n");
1028    }
1029
1030    if ($svgNativeType) {
1031        if ($useExceptions) {
1032            push(@implContentDecls, "    if (!ec)\n");
1033            push(@implContentDecls, "        wrapper->commitChange();\n");
1034        } else {
1035            push(@implContentDecls, "    wrapper->commitChange();\n");
1036        }
1037    }
1038
1039    push(@implContentDecls, "    return;\n");
1040    push(@implContentDecls, "}\n\n");  # end of setter
1041    push(@implContentDecls, "#endif // ${conditionalString}\n\n") if $conditionalString;
1042}
1043
1044sub GetFunctionTemplateCallbackName
1045{
1046    $function = shift;
1047    $interfaceName = shift;
1048
1049    my $name = $function->signature->name;
1050
1051    if ($function->signature->extendedAttributes->{"Custom"} ||
1052        $function->signature->extendedAttributes->{"V8Custom"}) {
1053        if ($function->signature->extendedAttributes->{"Custom"} &&
1054            $function->signature->extendedAttributes->{"V8Custom"}) {
1055            die "Custom and V8Custom should be mutually exclusive!"
1056        }
1057        return "V8${interfaceName}::${name}Callback";
1058    } else {
1059        return "${interfaceName}Internal::${name}Callback";
1060    }
1061}
1062
1063sub GenerateNewFunctionTemplate
1064{
1065    $function = shift;
1066    $interfaceName = shift;
1067    $signature = shift;
1068
1069    my $callback = GetFunctionTemplateCallbackName($function, $interfaceName);
1070    return "v8::FunctionTemplate::New($callback, v8::Handle<v8::Value>(), $signature)";
1071}
1072
1073sub GenerateEventListenerCallback
1074{
1075    my $implClassName = shift;
1076    my $requiresHiddenDependency = shift;
1077    my $functionName = shift;
1078    my $lookupType = ($functionName eq "add") ? "OrCreate" : "Only";
1079    my $passRefPtrHandling = ($functionName eq "add") ? "" : ".get()";
1080    my $hiddenDependencyAction = ($functionName eq "add") ? "create" : "remove";
1081
1082    push(@implContentDecls, <<END);
1083static v8::Handle<v8::Value> ${functionName}EventListenerCallback(const v8::Arguments& args)
1084{
1085    INC_STATS("DOM.${implClassName}.${functionName}EventListener()");
1086    RefPtr<EventListener> listener = V8DOMWrapper::getEventListener(args[1], false, ListenerFind${lookupType});
1087    if (listener) {
1088        V8${implClassName}::toNative(args.Holder())->${functionName}EventListener(v8ValueToAtomicWebCoreString(args[0]), listener${passRefPtrHandling}, args[2]->BooleanValue());
1089END
1090    if ($requiresHiddenDependency) {
1091        push(@implContentDecls, <<END);
1092        ${hiddenDependencyAction}HiddenDependency(args.Holder(), args[1], V8${implClassName}::eventListenerCacheIndex);
1093END
1094    }
1095    push(@implContentDecls, <<END);
1096    }
1097    return v8::Undefined();
1098}
1099
1100END
1101}
1102
1103sub GenerateParametersCheckExpression
1104{
1105    my $numParameters = shift;
1106    my $function = shift;
1107
1108    my @andExpression = ();
1109    push(@andExpression, "args.Length() == $numParameters");
1110    my $parameterIndex = 0;
1111    foreach $parameter (@{$function->parameters}) {
1112        last if $parameterIndex >= $numParameters;
1113        my $value = "args[$parameterIndex]";
1114        my $type = GetTypeFromSignature($parameter);
1115
1116        # Only DOMString or wrapper types are checked.
1117        # For DOMString, Null, Undefined and any Object are accepted too, as
1118        # these are acceptable values for a DOMString argument (any Object can
1119        # be converted to a string via .toString).
1120        if ($codeGenerator->IsStringType($type)) {
1121            push(@andExpression, "(${value}->IsNull() || ${value}->IsUndefined() || ${value}->IsString() || ${value}->IsObject())");
1122        } elsif ($parameter->extendedAttributes->{"Callback"}) {
1123            # For Callbacks only checks if the value is null or object.
1124            push(@andExpression, "(${value}->IsNull() || ${value}->IsObject())");
1125        } elsif (IsWrapperType($type)) {
1126            push(@andExpression, "(${value}->IsNull() || V8${type}::HasInstance($value))");
1127        }
1128
1129        $parameterIndex++;
1130    }
1131    my $res = join(" && ", @andExpression);
1132    $res = "($res)" if @andExpression > 1;
1133    return $res;
1134}
1135
1136sub GenerateFunctionParametersCheck
1137{
1138    my $function = shift;
1139
1140    my @orExpression = ();
1141    my $numParameters = 0;
1142    foreach $parameter (@{$function->parameters}) {
1143        if ($parameter->extendedAttributes->{"Optional"}) {
1144            push(@orExpression, GenerateParametersCheckExpression($numParameters, $function));
1145        }
1146        $numParameters++;
1147    }
1148    push(@orExpression, GenerateParametersCheckExpression($numParameters, $function));
1149    return join(" || ", @orExpression);
1150}
1151
1152sub GenerateOverloadedFunctionCallback
1153{
1154    my $function = shift;
1155    my $dataNode = shift;
1156    my $implClassName = shift;
1157
1158    # Generate code for choosing the correct overload to call. Overloads are
1159    # chosen based on the total number of arguments passed and the type of
1160    # values passed in non-primitive argument slots. When more than a single
1161    # overload is applicable, precedence is given according to the order of
1162    # declaration in the IDL.
1163
1164    my $name = $function->signature->name;
1165    push(@implContentDecls, <<END);
1166static v8::Handle<v8::Value> ${name}Callback(const v8::Arguments& args)
1167{
1168    INC_STATS(\"DOM.$implClassName.$name\");
1169END
1170
1171    foreach my $overload (@{$function->{overloads}}) {
1172        my $parametersCheck = GenerateFunctionParametersCheck($overload);
1173        push(@implContentDecls, "    if ($parametersCheck)\n");
1174        push(@implContentDecls, "        return ${name}$overload->{overloadIndex}Callback(args);\n");
1175    }
1176    push(@implContentDecls, <<END);
1177    V8Proxy::throwTypeError();
1178    return notHandledByInterceptor();
1179END
1180    push(@implContentDecls, "}\n\n");
1181}
1182
1183sub GenerateFunctionCallback
1184{
1185    my $function = shift;
1186    my $dataNode = shift;
1187    my $implClassName = shift;
1188
1189    my $interfaceName = $dataNode->name;
1190    my $name = $function->signature->name;
1191
1192    if (@{$function->{overloads}} > 1) {
1193        # Append a number to an overloaded method's name to make it unique:
1194        $name = $name . $function->{overloadIndex};
1195    }
1196
1197    # Adding and removing event listeners are not standard callback behavior,
1198    # but they are extremely consistent across the various classes that take event listeners,
1199    # so we can generate them as a "special case".
1200    if ($name eq "addEventListener") {
1201        GenerateEventListenerCallback($implClassName, !IsNodeSubType($dataNode), "add");
1202        return;
1203    } elsif ($name eq "removeEventListener") {
1204        GenerateEventListenerCallback($implClassName, !IsNodeSubType($dataNode), "remove");
1205        return;
1206    }
1207
1208    push(@implContentDecls, <<END);
1209static v8::Handle<v8::Value> ${name}Callback(const v8::Arguments& args)
1210{
1211    INC_STATS(\"DOM.$implClassName.$name\");
1212END
1213
1214    my $numParameters = @{$function->parameters};
1215
1216    my $requiresAllArguments = $function->signature->extendedAttributes->{"RequiresAllArguments"};
1217    if ($requiresAllArguments) {
1218        my $numMandatoryParams = @{$function->parameters};
1219        foreach my $param (reverse(@{$function->parameters})) {
1220            if ($param->extendedAttributes->{"Optional"}) {
1221                $numMandatoryParams--;
1222            } else {
1223                last;
1224            }
1225        }
1226        push(@implContentDecls, "    if (args.Length() < $numMandatoryParams)\n");
1227        if ($requiresAllArguments eq "Raise") {
1228            push(@implContentDecls, "        return throwError(\"Not enough arguments\", V8Proxy::SyntaxError);\n");
1229        } else {
1230            push(@implContentDecls, "        return v8::Handle<v8::Value>();\n");
1231        }
1232    }
1233
1234    my ($svgPropertyType, $svgListPropertyType, $svgNativeType) = GetSVGPropertyTypes($implClassName);
1235
1236    if ($svgNativeType) {
1237        my $nativeClassName = GetNativeType($implClassName);
1238        if ($implClassName =~ /List$/) {
1239            push(@implContentDecls, "    $nativeClassName imp = V8${implClassName}::toNative(args.Holder());\n");
1240        } else {
1241            push(@implContentDecls, "    $nativeClassName wrapper = V8${implClassName}::toNative(args.Holder());\n");
1242            push(@implContentDecls, "    if (wrapper->role() == AnimValRole) {\n");
1243            push(@implContentDecls, "        V8Proxy::setDOMException(NO_MODIFICATION_ALLOWED_ERR);\n");
1244            push(@implContentDecls, "        return v8::Handle<v8::Value>();\n");
1245            push(@implContentDecls, "    }\n");
1246            my $svgWrappedNativeType = $codeGenerator->GetSVGWrappedTypeNeedingTearOff($implClassName);
1247            push(@implContentDecls, "    $svgWrappedNativeType& impInstance = wrapper->propertyReference();\n");
1248            push(@implContentDecls, "    $svgWrappedNativeType* imp = &impInstance;\n");
1249        }
1250    } elsif (!$function->signature->extendedAttributes->{"ClassMethod"}) {
1251        push(@implContentDecls, <<END);
1252    ${implClassName}* imp = V8${implClassName}::toNative(args.Holder());
1253END
1254    }
1255
1256    # Check domain security if needed
1257    if (($dataNode->extendedAttributes->{"CheckDomainSecurity"}
1258       || $interfaceName eq "DOMWindow")
1259       && !$function->signature->extendedAttributes->{"DoNotCheckDomainSecurity"}) {
1260    # We have not find real use cases yet.
1261    push(@implContentDecls, <<END);
1262    if (!V8BindingSecurity::canAccessFrame(V8BindingState::Only(), imp->frame(), true))
1263        return v8::Handle<v8::Value>();
1264END
1265    }
1266
1267    my $raisesExceptions = @{$function->raisesExceptions};
1268    if (!$raisesExceptions) {
1269        foreach my $parameter (@{$function->parameters}) {
1270            if ((!$parameter->extendedAttributes->{"Callback"} and TypeCanFailConversion($parameter)) or $parameter->extendedAttributes->{"IsIndex"}) {
1271                $raisesExceptions = 1;
1272            }
1273        }
1274    }
1275
1276    if ($raisesExceptions) {
1277        $implIncludes{"ExceptionCode.h"} = 1;
1278        push(@implContentDecls, "    ExceptionCode ec = 0;\n");
1279        push(@implContentDecls, "    {\n");
1280        # The brace here is needed to prevent the ensuing 'goto fail's from jumping past constructors
1281        # of objects (like Strings) declared later, causing compile errors. The block scope ends
1282        # right before the label 'fail:'.
1283    }
1284
1285    if ($function->signature->extendedAttributes->{"CustomArgumentHandling"}) {
1286        push(@implContentDecls, <<END);
1287    RefPtr<ScriptArguments> scriptArguments(createScriptArguments(args, $numParameters));
1288    size_t maxStackSize = imp->shouldCaptureFullStackTrace() ? ScriptCallStack::maxCallStackSizeToCapture : 1;
1289    RefPtr<ScriptCallStack> callStack(createScriptCallStack(maxStackSize));
1290    if (!callStack)
1291        return v8::Undefined();
1292END
1293        $implIncludes{"ScriptArguments.h"} = 1;
1294        $implIncludes{"ScriptCallStack.h"} = 1;
1295        $implIncludes{"ScriptCallStackFactory.h"} = 1;
1296    }
1297    if ($function->signature->extendedAttributes->{"SVGCheckSecurityDocument"}) {
1298        push(@implContentDecls, <<END);
1299    if (!V8BindingSecurity::checkNodeSecurity(V8BindingState::Only(), imp->getSVGDocument(ec)))
1300        return v8::Handle<v8::Value>();
1301END
1302    }
1303
1304    my $paramIndex = 0;
1305    foreach my $parameter (@{$function->parameters}) {
1306        TranslateParameter($parameter);
1307
1308        my $parameterName = $parameter->name;
1309
1310        # Optional callbacks should be treated differently, because they always have a default value (0),
1311        # and we can reduce the number of overloaded functions that take a different number of parameters.
1312        if ($parameter->extendedAttributes->{"Optional"} && !$parameter->extendedAttributes->{"Callback"}) {
1313            # Generate early call if there are not enough parameters.
1314            push(@implContentDecls, "    if (args.Length() <= $paramIndex) {\n");
1315            my $functionCall = GenerateFunctionCallString($function, $paramIndex, "    " x 2, $implClassName);
1316            push(@implContentDecls, $functionCall);
1317            push(@implContentDecls, "    }\n");
1318        }
1319
1320        $implIncludes{"ExceptionCode.h"} = 1;
1321        my $nativeType = GetNativeTypeFromSignature($parameter, $paramIndex);
1322        if ($parameter->extendedAttributes->{"Callback"}) {
1323            my $className = GetCallbackClassName($parameter->type);
1324            $implIncludes{"$className.h"} = 1;
1325            if ($parameter->extendedAttributes->{"Optional"}) {
1326                push(@implContentDecls, "    RefPtr<" . $parameter->type . "> $parameterName;\n");
1327                push(@implContentDecls, "    if (args.Length() > $paramIndex && !args[$paramIndex]->IsNull() && !args[$paramIndex]->IsUndefined()) {\n");
1328                push(@implContentDecls, "        if (!args[$paramIndex]->IsObject())\n");
1329                push(@implContentDecls, "            return throwError(TYPE_MISMATCH_ERR);\n");
1330                push(@implContentDecls, "        $parameterName = ${className}::create(args[$paramIndex], getScriptExecutionContext());\n");
1331                push(@implContentDecls, "    }\n");
1332            } else {
1333                push(@implContentDecls, "    if (args.Length() <= $paramIndex || !args[$paramIndex]->IsObject())\n");
1334                push(@implContentDecls, "        return throwError(TYPE_MISMATCH_ERR);\n");
1335                push(@implContentDecls, "    RefPtr<" . $parameter->type . "> $parameterName = ${className}::create(args[$paramIndex], getScriptExecutionContext());\n");
1336            }
1337        } elsif ($parameter->type eq "SerializedScriptValue") {
1338            $implIncludes{"SerializedScriptValue.h"} = 1;
1339            push(@implContentDecls, "    bool ${parameterName}DidThrow = false;\n");
1340            push(@implContentDecls, "    $nativeType $parameterName = SerializedScriptValue::create(args[$paramIndex], ${parameterName}DidThrow);\n");
1341            push(@implContentDecls, "    if (${parameterName}DidThrow)\n");
1342            push(@implContentDecls, "        return v8::Undefined();\n");
1343        } elsif (TypeCanFailConversion($parameter)) {
1344            push(@implContentDecls, "    $nativeType $parameterName = " .
1345                 JSValueToNative($parameter, "args[$paramIndex]") . ";\n");
1346            push(@implContentDecls, "    if (UNLIKELY(!$parameterName)) {\n");
1347            push(@implContentDecls, "        ec = TYPE_MISMATCH_ERR;\n");
1348            push(@implContentDecls, "        goto fail;\n");
1349            push(@implContentDecls, "    }\n");
1350        } elsif ($nativeType =~ /^V8Parameter/) {
1351            my $value = JSValueToNative($parameter, "args[$paramIndex]");
1352            push(@implContentDecls, "    " . ConvertToV8Parameter($parameter, $nativeType, $parameterName, $value) . "\n");
1353        } else {
1354            $implIncludes{"V8BindingMacros.h"} = 1;
1355            # If the "StrictTypeChecking" extended attribute is present, and the argument's type is an
1356            # interface type, then if the incoming value does not implement that interface, a TypeError
1357            # is thrown rather than silently passing NULL to the C++ code.
1358            # Per the Web IDL and ECMAScript specifications, incoming values can always be converted
1359            # to both strings and numbers, so do not throw TypeError if the argument is of these
1360            # types.
1361            if ($function->signature->extendedAttributes->{"StrictTypeChecking"}) {
1362                my $argValue = "args[$paramIndex]";
1363                my $argType = GetTypeFromSignature($parameter);
1364                if (IsWrapperType($argType)) {
1365                    push(@implContentDecls, "    if (args.Length() > $paramIndex && !isUndefinedOrNull($argValue) && !V8${argType}::HasInstance($argValue)) {\n");
1366                    push(@implContentDecls, "        V8Proxy::throwTypeError();\n");
1367                    push(@implContentDecls, "        return notHandledByInterceptor();\n");
1368                    push(@implContentDecls, "    }\n");
1369                }
1370            }
1371            push(@implContentDecls, "    EXCEPTION_BLOCK($nativeType, $parameterName, " .
1372                 JSValueToNative($parameter, "args[$paramIndex]") . ");\n");
1373        }
1374
1375        if ($parameter->extendedAttributes->{"IsIndex"}) {
1376            push(@implContentDecls, "    if (UNLIKELY($parameterName < 0)) {\n");
1377            push(@implContentDecls, "        ec = INDEX_SIZE_ERR;\n");
1378            push(@implContentDecls, "        goto fail;\n");
1379            push(@implContentDecls, "    }\n");
1380        }
1381
1382        $paramIndex++;
1383    }
1384
1385    # Build the function call string.
1386    my $callString = GenerateFunctionCallString($function, $paramIndex, "    ", $implClassName);
1387    push(@implContentDecls, "$callString");
1388
1389    if ($raisesExceptions) {
1390        push(@implContentDecls, "    }\n");
1391        push(@implContentDecls, "    fail:\n");
1392        push(@implContentDecls, "    V8Proxy::setDOMException(ec);\n");
1393        push(@implContentDecls, "    return v8::Handle<v8::Value>();\n");
1394    }
1395
1396    push(@implContentDecls, "}\n\n");
1397}
1398
1399sub GenerateBatchedAttributeData
1400{
1401    my $dataNode = shift;
1402    my $interfaceName = $dataNode->name;
1403    my $attributes = shift;
1404
1405    foreach my $attribute (@$attributes) {
1406        my $conditionalString = GenerateConditionalString($attribute->signature);
1407        push(@implContent, "#if ${conditionalString}\n") if $conditionalString;
1408        GenerateSingleBatchedAttribute($interfaceName, $attribute, ",", "");
1409        push(@implContent, "#endif // ${conditionalString}\n") if $conditionalString;
1410    }
1411}
1412
1413sub GenerateSingleBatchedAttribute
1414{
1415    my $interfaceName = shift;
1416    my $attribute = shift;
1417    my $delimiter = shift;
1418    my $indent = shift;
1419    my $attrName = $attribute->signature->name;
1420    my $attrExt = $attribute->signature->extendedAttributes;
1421
1422    # Attributes of type SerializedScriptValue are set in the
1423    # constructor and don't require callbacks.
1424    return if ($attribute->signature->type eq "SerializedScriptValue");
1425
1426    my $accessControl = "v8::DEFAULT";
1427    if ($attrExt->{"DoNotCheckDomainSecurityOnGet"}) {
1428        $accessControl = "v8::ALL_CAN_READ";
1429    } elsif ($attrExt->{"DoNotCheckDomainSecurityOnSet"}) {
1430        $accessControl = "v8::ALL_CAN_WRITE";
1431    } elsif ($attrExt->{"DoNotCheckDomainSecurity"}) {
1432        $accessControl = "v8::ALL_CAN_READ";
1433        if (!($attribute->type =~ /^readonly/) && !($attrExt->{"V8ReadOnly"})) {
1434            $accessControl .= " | v8::ALL_CAN_WRITE";
1435        }
1436    }
1437    if ($attrExt->{"V8DisallowShadowing"}) {
1438        $accessControl .= " | v8::PROHIBITS_OVERWRITING";
1439    }
1440    $accessControl = "static_cast<v8::AccessControl>(" . $accessControl . ")";
1441
1442    my $customAccessor =
1443        $attrExt->{"Custom"} ||
1444        $attrExt->{"CustomSetter"} ||
1445        $attrExt->{"CustomGetter"} ||
1446        $attrExt->{"V8Custom"} ||
1447        $attrExt->{"V8CustomSetter"} ||
1448        $attrExt->{"V8CustomGetter"} ||
1449        "";
1450    if ($customAccessor eq 1) {
1451        # use the naming convension, interface + (capitalize) attr name
1452        $customAccessor = $interfaceName . "::" . $attrName;
1453    }
1454
1455    my $getter;
1456    my $setter;
1457    my $propAttr = "v8::None";
1458    my $hasCustomSetter = 0;
1459
1460    # Check attributes.
1461    if ($attrExt->{"DontEnum"}) {
1462        $propAttr .= " | v8::DontEnum";
1463    }
1464    if ($attrExt->{"V8DisallowShadowing"}) {
1465        $propAttr .= " | v8::DontDelete";
1466    }
1467
1468    my $on_proto = "0 /* on instance */";
1469    my $data = "0 /* no data */";
1470
1471    # Constructor
1472    if ($attribute->signature->type =~ /Constructor$/) {
1473        my $constructorType = $codeGenerator->StripModule($attribute->signature->type);
1474        $constructorType =~ s/Constructor$//;
1475        $implIncludes{"V8${constructorType}.h"} = 1;
1476        if ($customAccessor) {
1477            $getter = "V8${customAccessor}AccessorGetter";
1478        } else {
1479            $data = "&V8${constructorType}::info";
1480            $getter = "${interfaceName}Internal::${interfaceName}ConstructorGetter";
1481        }
1482        $setter = "0";
1483        $propAttr = "v8::ReadOnly";
1484
1485    } else {
1486        # Default Getter and Setter
1487        $getter = "${interfaceName}Internal::${attrName}AttrGetter";
1488        $setter = "${interfaceName}Internal::${attrName}AttrSetter";
1489
1490        # Custom Setter
1491        if ($attrExt->{"CustomSetter"} || $attrExt->{"V8CustomSetter"} || $attrExt->{"Custom"} || $attrExt->{"V8Custom"}) {
1492            $hasCustomSetter = 1;
1493            $setter = "V8${customAccessor}AccessorSetter";
1494        }
1495
1496        # Custom Getter
1497        if ($attrExt->{"CustomGetter"} || $attrExt->{"V8CustomGetter"} || $attrExt->{"Custom"} || $attrExt->{"V8Custom"}) {
1498            $getter = "V8${customAccessor}AccessorGetter";
1499        }
1500    }
1501
1502    # Replaceable
1503    if ($attrExt->{"Replaceable"} && !$hasCustomSetter) {
1504        $setter = "0";
1505        # Handle the special case of window.top being marked as Replaceable.
1506        # FIXME: Investigate whether we could treat window.top as replaceable
1507        # and allow shadowing without it being a security hole.
1508        if (!($interfaceName eq "DOMWindow" and $attrName eq "top")) {
1509            $propAttr .= " | v8::ReadOnly";
1510        }
1511    }
1512
1513    # Read only attributes
1514    if ($attribute->type =~ /^readonly/ || $attrExt->{"V8ReadOnly"}) {
1515        $setter = "0";
1516    }
1517
1518    # An accessor can be installed on the proto
1519    if ($attrExt->{"v8OnProto"}) {
1520        $on_proto = "1 /* on proto */";
1521    }
1522
1523    my $commentInfo = "Attribute '$attrName' (Type: '" . $attribute->type .
1524                      "' ExtAttr: '" . join(' ', keys(%{$attrExt})) . "')";
1525
1526    push(@implContent, $indent . "    \/\/ $commentInfo\n");
1527    push(@implContent, $indent . "    {\"$attrName\", $getter, $setter, $data, $accessControl, static_cast<v8::PropertyAttribute>($propAttr), $on_proto}" . $delimiter . "\n");
1528}
1529
1530sub GenerateImplementationIndexer
1531{
1532    my $dataNode = shift;
1533    my $indexer = shift;
1534    my $interfaceName = $dataNode->name;
1535
1536    # FIXME: Figure out what HasNumericIndexGetter is really supposed to do. Right now, it's only set on WebGL-related files.
1537    my $hasCustomSetter = $dataNode->extendedAttributes->{"HasCustomIndexSetter"} && !$dataNode->extendedAttributes->{"HasNumericIndexGetter"};
1538    my $hasGetter = $dataNode->extendedAttributes->{"HasIndexGetter"} || $dataNode->extendedAttributes->{"CustomGetOwnPropertySlot"};
1539
1540    # FIXME: Find a way to not have to special-case HTMLOptionsCollection.
1541    if ($interfaceName eq "HTMLOptionsCollection") {
1542        $hasGetter = 1;
1543    }
1544
1545    # FIXME: Investigate and remove this nastinesss. In V8, named property handling and indexer handling are apparently decoupled,
1546    # which means that object[X] where X is a number doesn't reach named property indexer. So we need to provide
1547    # simplistic, mirrored indexer handling in addition to named property handling.
1548    my $isSpecialCase = exists $indexerSpecialCases{$interfaceName};
1549    if ($isSpecialCase) {
1550        $hasGetter = 1;
1551        if ($dataNode->extendedAttributes->{"DelegatingPutFunction"}) {
1552            $hasCustomSetter = 1;
1553        }
1554    }
1555
1556    if (!$hasGetter) {
1557        return;
1558    }
1559
1560    $implIncludes{"V8Collection.h"} = 1;
1561
1562    my $indexerType = $indexer ? $indexer->type : 0;
1563
1564    # FIXME: Remove this once toV8 helper methods are implemented (see https://bugs.webkit.org/show_bug.cgi?id=32563).
1565    if ($interfaceName eq "WebKitCSSKeyframesRule") {
1566        $indexerType = "WebKitCSSKeyframeRule";
1567    }
1568
1569    # FIXME: The item() getter is not inherited from CSSValueList, seemingly due to the way
1570    # the CodeGenerator->AddMethodsConstantsAndAttributesFromParentClasses() method works,
1571    # so we need to set the indexerType manually in this case.
1572    if ($interfaceName eq "WebKitCSSTransformValue") {
1573        $indexerType = "CSSValue";
1574    }
1575
1576    if ($indexerType && !$hasCustomSetter) {
1577        if ($indexerType eq "DOMString") {
1578            my $conversion = $indexer->extendedAttributes->{"ConvertNullStringTo"};
1579            if ($conversion && $conversion eq "Null") {
1580                push(@implContent, <<END);
1581    setCollectionStringOrNullIndexedGetter<${interfaceName}>(desc);
1582END
1583            } else {
1584                push(@implContent, <<END);
1585    setCollectionStringIndexedGetter<${interfaceName}>(desc);
1586END
1587            }
1588        } else {
1589            push(@implContent, <<END);
1590    setCollectionIndexedGetter<${interfaceName}, ${indexerType}>(desc);
1591END
1592            # Include the header for this indexer type, because setCollectionIndexedGetter() requires toV8() for this type.
1593            $implIncludes{"V8${indexerType}.h"} = 1;
1594        }
1595
1596        return;
1597    }
1598
1599    my $hasDeleter = $dataNode->extendedAttributes->{"CustomDeleteProperty"};
1600    my $hasEnumerator = !$isSpecialCase && IsNodeSubType($dataNode);
1601    my $setOn = "Instance";
1602
1603    # V8 has access-check callback API (see ObjectTemplate::SetAccessCheckCallbacks) and it's used on DOMWindow
1604    # instead of deleters or enumerators. In addition, the getter should be set on prototype template, to
1605    # get implementation straight out of the DOMWindow prototype regardless of what prototype is actually set
1606    # on the object.
1607    if ($interfaceName eq "DOMWindow") {
1608        $setOn = "Prototype";
1609        $hasDeleter = 0;
1610    }
1611
1612    push(@implContent, "    desc->${setOn}Template()->SetIndexedPropertyHandler(V8${interfaceName}::indexedPropertyGetter");
1613    push(@implContent, $hasCustomSetter ? ", V8${interfaceName}::indexedPropertySetter" : ", 0");
1614    push(@implContent, ", 0"); # IndexedPropertyQuery -- not being used at the moment.
1615    push(@implContent, $hasDeleter ? ", V8${interfaceName}::indexedPropertyDeleter" : ", 0");
1616    push(@implContent, ", nodeCollectionIndexedPropertyEnumerator<${interfaceName}>") if $hasEnumerator;
1617    push(@implContent, ");\n");
1618}
1619
1620sub GenerateImplementationNamedPropertyGetter
1621{
1622    my $dataNode = shift;
1623    my $namedPropertyGetter = shift;
1624    my $interfaceName = $dataNode->name;
1625    my $hasCustomGetter = $dataNode->extendedAttributes->{"HasOverridingNameGetter"} || $dataNode->extendedAttributes->{"CustomGetOwnPropertySlot"};
1626
1627    # FIXME: Remove hard-coded HTMLOptionsCollection reference by changing HTMLOptionsCollection to not inherit
1628    # from HTMLCollection per W3C spec (http://www.w3.org/TR/2003/REC-DOM-Level-2-HTML-20030109/html.html#HTMLOptionsCollection).
1629    if ($interfaceName eq "HTMLOptionsCollection") {
1630        $interfaceName = "HTMLCollection";
1631        $hasCustomGetter = 1;
1632    }
1633
1634    if ($interfaceName eq "HTMLAppletElement" || $interfaceName eq "HTMLEmbedElement" || $interfaceName eq "HTMLObjectElement") {
1635        $hasCustomGetter = 1;
1636    }
1637
1638    if ($interfaceName eq "HTMLDocument") {
1639        $hasCustomGetter = 0;
1640    }
1641
1642    my $hasGetter = $dataNode->extendedAttributes->{"HasNameGetter"} || $hasCustomGetter;
1643    if (!$hasGetter) {
1644        return;
1645    }
1646
1647    if ($namedPropertyGetter && $namedPropertyGetter->type ne "Node" && !$namedPropertyGetter->extendedAttributes->{"Custom"} && !$hasCustomGetter) {
1648        $implIncludes{"V8Collection.h"} = 1;
1649        my $type = $namedPropertyGetter->type;
1650        push(@implContent, <<END);
1651    setCollectionNamedGetter<${interfaceName}, ${type}>(desc);
1652END
1653        return;
1654    }
1655
1656    my $hasSetter = $dataNode->extendedAttributes->{"DelegatingPutFunction"};
1657    my $hasDeleter = $dataNode->extendedAttributes->{"CustomDeleteProperty"};
1658    my $hasEnumerator = $dataNode->extendedAttributes->{"CustomGetPropertyNames"};
1659    my $setOn = "Instance";
1660
1661    # V8 has access-check callback API (see ObjectTemplate::SetAccessCheckCallbacks) and it's used on DOMWindow
1662    # instead of deleters or enumerators. In addition, the getter should be set on prototype template, to
1663    # get implementation straight out of the DOMWindow prototype regardless of what prototype is actually set
1664    # on the object.
1665    if ($interfaceName eq "DOMWindow") {
1666        $setOn = "Prototype";
1667        $hasDeleter = 0;
1668        $hasEnumerator = 0;
1669    }
1670
1671    push(@implContent, "    desc->${setOn}Template()->SetNamedPropertyHandler(V8${interfaceName}::namedPropertyGetter, ");
1672    push(@implContent, $hasSetter ? "V8${interfaceName}::namedPropertySetter, " : "0, ");
1673    # If there is a custom enumerator, there MUST be custom query to properly communicate property attributes.
1674    push(@implContent, $hasEnumerator ? "V8${interfaceName}::namedPropertyQuery, " : "0, ");
1675    push(@implContent, $hasDeleter ? "V8${interfaceName}::namedPropertyDeleter, " : "0, ");
1676    push(@implContent, $hasEnumerator ? "V8${interfaceName}::namedPropertyEnumerator" : "0");
1677    push(@implContent, ");\n");
1678}
1679
1680sub GenerateImplementationCustomCall
1681{
1682    my $dataNode = shift;
1683    my $interfaceName = $dataNode->name;
1684    my $hasCustomCall = $dataNode->extendedAttributes->{"CustomCall"};
1685
1686    # FIXME: Remove hard-coded HTMLOptionsCollection reference.
1687    if ($interfaceName eq "HTMLOptionsCollection") {
1688        $interfaceName = "HTMLCollection";
1689        $hasCustomCall = 1;
1690    }
1691
1692    if ($hasCustomCall) {
1693        push(@implContent, "    desc->InstanceTemplate()->SetCallAsFunctionHandler(V8${interfaceName}::callAsFunctionCallback);\n");
1694    }
1695}
1696
1697sub GenerateImplementationMasqueradesAsUndefined
1698{
1699    my $dataNode = shift;
1700    if ($dataNode->extendedAttributes->{"MasqueradesAsUndefined"})
1701    {
1702        push(@implContent, "    desc->InstanceTemplate()->MarkAsUndetectable();\n");
1703    }
1704}
1705
1706sub GenerateImplementation
1707{
1708    my $object = shift;
1709    my $dataNode = shift;
1710    my $interfaceName = $dataNode->name;
1711    my $visibleInterfaceName = GetVisibleInterfaceName($interfaceName);
1712    my $className = "V8$interfaceName";
1713    my $implClassName = $interfaceName;
1714    my $hasLegacyParent = $dataNode->extendedAttributes->{"LegacyParent"};
1715
1716    # - Add default header template
1717    push(@implFixedHeader, GenerateImplementationContentHeader($dataNode));
1718
1719    $implIncludes{"RuntimeEnabledFeatures.h"} = 1;
1720    $implIncludes{"V8Proxy.h"} = 1;
1721    $implIncludes{"V8Binding.h"} = 1;
1722    $implIncludes{"V8BindingState.h"} = 1;
1723    $implIncludes{"V8DOMWrapper.h"} = 1;
1724    $implIncludes{"V8IsolatedContext.h"} = 1;
1725
1726    AddIncludesForType($interfaceName);
1727
1728    my $toActive = IsActiveDomType($interfaceName) ? "${className}::toActiveDOMObject" : "0";
1729
1730    # Find the super descriptor.
1731    my $parentClass = "";
1732    my $parentClassTemplate = "";
1733    foreach (@{$dataNode->parents}) {
1734        my $parent = $codeGenerator->StripModule($_);
1735        if ($parent eq "EventTarget") {
1736            next;
1737        }
1738        $implIncludes{"V8${parent}.h"} = 1;
1739        $parentClass = "V8" . $parent;
1740        $parentClassTemplate = $parentClass . "::GetTemplate()";
1741        last;
1742    }
1743    push(@implContentDecls, "namespace WebCore {\n\n");
1744    my $parentClassInfo = $parentClass ? "&${parentClass}::info" : "0";
1745    push(@implContentDecls, "WrapperTypeInfo ${className}::info = { ${className}::GetTemplate, ${className}::derefObject, ${toActive}, ${parentClassInfo} };\n\n");
1746    push(@implContentDecls, "namespace ${interfaceName}Internal {\n\n");
1747    push(@implContentDecls, "template <typename T> void V8_USE(T) { }\n\n");
1748
1749    my $hasConstructors = 0;
1750    my $serializedAttribute;
1751    # Generate property accessors for attributes.
1752    for ($index = 0; $index < @{$dataNode->attributes}; $index++) {
1753        $attribute = @{$dataNode->attributes}[$index];
1754        $attrName = $attribute->signature->name;
1755        $attrType = $attribute->signature->type;
1756
1757        # Generate special code for the constructor attributes.
1758        if ($attrType =~ /Constructor$/) {
1759            if (!($attribute->signature->extendedAttributes->{"CustomGetter"} ||
1760                $attribute->signature->extendedAttributes->{"V8CustomGetter"})) {
1761                $hasConstructors = 1;
1762            }
1763            next;
1764        }
1765
1766        if ($attrType eq "EventListener" && $interfaceName eq "DOMWindow") {
1767            $attribute->signature->extendedAttributes->{"v8OnProto"} = 1;
1768        }
1769
1770        # Attributes of type SerializedScriptValue are set in the
1771        # constructor and don't require callbacks.
1772        if ($attrType eq "SerializedScriptValue") {
1773            die "Only one attribute of type SerializedScriptValue supported" if $serializedAttribute;
1774            $implIncludes{"SerializedScriptValue.h"} = 1;
1775            $serializedAttribute = $attribute;
1776            next;
1777        }
1778
1779        # Do not generate accessor if this is a custom attribute.  The
1780        # call will be forwarded to a hand-written accessor
1781        # implementation.
1782        if ($attribute->signature->extendedAttributes->{"Custom"} ||
1783            $attribute->signature->extendedAttributes->{"V8Custom"}) {
1784            next;
1785        }
1786
1787        # Generate the accessor.
1788        if (!($attribute->signature->extendedAttributes->{"CustomGetter"} ||
1789            $attribute->signature->extendedAttributes->{"V8CustomGetter"})) {
1790            GenerateNormalAttrGetter($attribute, $dataNode, $implClassName, $interfaceName);
1791        }
1792        if (!$attribute->signature->extendedAttributes->{"CustomSetter"} &&
1793            !$attribute->signature->extendedAttributes->{"V8CustomSetter"} &&
1794            !$attribute->signature->extendedAttributes->{"Replaceable"} &&
1795            $attribute->type !~ /^readonly/ &&
1796            !$attribute->signature->extendedAttributes->{"V8ReadOnly"}) {
1797            GenerateNormalAttrSetter($attribute, $dataNode, $implClassName, $interfaceName);
1798        }
1799    }
1800
1801    if ($hasConstructors) {
1802        GenerateConstructorGetter($implClassName);
1803    }
1804
1805    $codeGenerator->LinkOverloadedFunctions($dataNode);
1806
1807    my $indexer;
1808    my $namedPropertyGetter;
1809    # Generate methods for functions.
1810    foreach my $function (@{$dataNode->functions}) {
1811        if (!($function->signature->extendedAttributes->{"Custom"} || $function->signature->extendedAttributes->{"V8Custom"})) {
1812            GenerateFunctionCallback($function, $dataNode, $implClassName);
1813            if ($function->{overloadIndex} > 1 && $function->{overloadIndex} == @{$function->{overloads}}) {
1814                GenerateOverloadedFunctionCallback($function, $dataNode, $implClassName);
1815            }
1816        }
1817
1818        if ($function->signature->name eq "item") {
1819            $indexer = $function->signature;
1820        }
1821
1822        if ($function->signature->name eq "namedItem") {
1823            $namedPropertyGetter = $function->signature;
1824        }
1825
1826        # If the function does not need domain security check, we need to
1827        # generate an access getter that returns different function objects
1828        # for different calling context.
1829        if (($dataNode->extendedAttributes->{"CheckDomainSecurity"} || ($interfaceName eq "DOMWindow")) && $function->signature->extendedAttributes->{"DoNotCheckDomainSecurity"}) {
1830            GenerateDomainSafeFunctionGetter($function, $implClassName);
1831        }
1832    }
1833
1834    # Attributes
1835    my $attributes = $dataNode->attributes;
1836
1837    # For the DOMWindow interface we partition the attributes into the
1838    # ones that disallows shadowing and the rest.
1839    my @disallowsShadowing;
1840    # Also separate out attributes that are enabled at runtime so we can process them specially.
1841    my @enabledAtRuntime;
1842    my @normal;
1843    foreach my $attribute (@$attributes) {
1844
1845        if ($interfaceName eq "DOMWindow" && $attribute->signature->extendedAttributes->{"V8DisallowShadowing"}) {
1846            push(@disallowsShadowing, $attribute);
1847        } elsif ($attribute->signature->extendedAttributes->{"EnabledAtRuntime"}) {
1848            push(@enabledAtRuntime, $attribute);
1849        } else {
1850            push(@normal, $attribute);
1851        }
1852    }
1853    $attributes = \@normal;
1854    # Put the attributes that disallow shadowing on the shadow object.
1855    if (@disallowsShadowing) {
1856        push(@implContent, "static const BatchedAttribute shadowAttrs[] = {\n");
1857        GenerateBatchedAttributeData($dataNode, \@disallowsShadowing);
1858        push(@implContent, "};\n");
1859    }
1860
1861    my $has_attributes = 0;
1862    if (@$attributes && (@$attributes > 1 || $$attributes[0]->signature->type ne "SerializedScriptValue")) {
1863        $has_attributes = 1;
1864        push(@implContent, "static const BatchedAttribute ${interfaceName}Attrs[] = {\n");
1865        GenerateBatchedAttributeData($dataNode, $attributes);
1866        push(@implContent, "};\n");
1867    }
1868
1869    # Setup table of standard callback functions
1870    $num_callbacks = 0;
1871    $has_callbacks = 0;
1872    foreach my $function (@{$dataNode->functions}) {
1873        # Only one table entry is needed for overloaded methods:
1874        next if $function->{overloadIndex} > 1;
1875
1876        my $attrExt = $function->signature->extendedAttributes;
1877        # Don't put any nonstandard functions into this table:
1878        if ($attrExt->{"V8OnInstance"}) {
1879            next;
1880        }
1881        if ($attrExt->{"ClassMethod"}) {
1882            next;
1883        }
1884        if ($attrExt->{"EnabledAtRuntime"} || RequiresCustomSignature($function) || $attrExt->{"V8DoNotCheckSignature"}) {
1885            next;
1886        }
1887        if ($attrExt->{"DoNotCheckDomainSecurity"} &&
1888            ($dataNode->extendedAttributes->{"CheckDomainSecurity"} || $interfaceName eq "DOMWindow")) {
1889            next;
1890        }
1891        if ($attrExt->{"DontEnum"} || $attrExt->{"V8ReadOnly"}) {
1892            next;
1893        }
1894        if (!$has_callbacks) {
1895            $has_callbacks = 1;
1896            push(@implContent, "static const BatchedCallback ${interfaceName}Callbacks[] = {\n");
1897        }
1898        my $name = $function->signature->name;
1899        my $callback = GetFunctionTemplateCallbackName($function, $interfaceName);
1900        push(@implContent, <<END);
1901    {"$name", $callback},
1902END
1903        $num_callbacks++;
1904    }
1905    push(@implContent, "};\n")  if $has_callbacks;
1906
1907    # Setup constants
1908    my $has_constants = 0;
1909    if (@{$dataNode->constants}) {
1910        $has_constants = 1;
1911        push(@implContent, "static const BatchedConstant ${interfaceName}Consts[] = {\n");
1912    }
1913    foreach my $constant (@{$dataNode->constants}) {
1914        my $name = $constant->name;
1915        my $value = $constant->value;
1916        # FIXME: we need the static_cast here only because of one constant, NodeFilter.idl
1917        # defines "const unsigned long SHOW_ALL = 0xFFFFFFFF".  It would be better if we
1918        # handled this here, and converted it to a -1 constant in the c++ output.
1919        push(@implContent, <<END);
1920    {"${name}", static_cast<signed int>($value)},
1921END
1922    }
1923    if ($has_constants) {
1924        push(@implContent, "};\n");
1925        push(@implContent, $codeGenerator->GenerateCompileTimeCheckForEnumsIfNeeded($dataNode));
1926    }
1927
1928    push(@implContentDecls, "} // namespace ${interfaceName}Internal\n\n");
1929
1930    # In namespace WebCore, add generated implementation for 'CanBeConstructed'.
1931    if ($dataNode->extendedAttributes->{"CanBeConstructed"} && !$dataNode->extendedAttributes->{"CustomConstructor"} && !$dataNode->extendedAttributes->{"V8CustomConstructor"}) {
1932        my $v8ConstructFunction;
1933        my $callWith = $dataNode->extendedAttributes->{"CallWith"};
1934        if ($callWith and $callWith eq "ScriptExecutionContext") {
1935            $v8ConstructFunction = "constructDOMObjectWithScriptExecutionContext";
1936        } else {
1937            $v8ConstructFunction = "constructDOMObject";
1938        }
1939        push(@implContent, <<END);
1940v8::Handle<v8::Value> ${className}::constructorCallback(const v8::Arguments& args)
1941{
1942    INC_STATS("DOM.${interfaceName}.Contructor");
1943    return V8Proxy::${v8ConstructFunction}<$interfaceName>(args, &info);
1944}
1945END
1946   }
1947
1948    my $access_check = "";
1949    if ($dataNode->extendedAttributes->{"CheckDomainSecurity"} && !($interfaceName eq "DOMWindow")) {
1950        $access_check = "instance->SetAccessCheckCallbacks(V8${interfaceName}::namedSecurityCheck, V8${interfaceName}::indexedSecurityCheck, v8::External::Wrap(&V8${interfaceName}::info));";
1951    }
1952
1953    # For the DOMWindow interface, generate the shadow object template
1954    # configuration method.
1955    if ($implClassName eq "DOMWindow") {
1956        push(@implContent, <<END);
1957static v8::Persistent<v8::ObjectTemplate> ConfigureShadowObjectTemplate(v8::Persistent<v8::ObjectTemplate> templ)
1958{
1959    batchConfigureAttributes(templ, v8::Handle<v8::ObjectTemplate>(), shadowAttrs, WTF_ARRAY_LENGTH(shadowAttrs));
1960
1961    // Install a security handler with V8.
1962    templ->SetAccessCheckCallbacks(V8DOMWindow::namedSecurityCheck, V8DOMWindow::indexedSecurityCheck, v8::External::Wrap(&V8DOMWindow::info));
1963    templ->SetInternalFieldCount(V8DOMWindow::internalFieldCount);
1964    return templ;
1965}
1966END
1967    }
1968
1969    if (!$parentClassTemplate) {
1970        $parentClassTemplate = "v8::Persistent<v8::FunctionTemplate>()";
1971    }
1972
1973    # Generate the template configuration method
1974    push(@implContent,  <<END);
1975static v8::Persistent<v8::FunctionTemplate> Configure${className}Template(v8::Persistent<v8::FunctionTemplate> desc)
1976{
1977    v8::Local<v8::Signature> defaultSignature = configureTemplate(desc, \"${visibleInterfaceName}\", $parentClassTemplate, V8${interfaceName}::internalFieldCount,
1978END
1979    # Set up our attributes if we have them
1980    if ($has_attributes) {
1981        push(@implContent, <<END);
1982        ${interfaceName}Attrs, WTF_ARRAY_LENGTH(${interfaceName}Attrs),
1983END
1984    } else {
1985        push(@implContent, <<END);
1986        0, 0,
1987END
1988    }
1989
1990    if ($has_callbacks) {
1991        push(@implContent, <<END);
1992        ${interfaceName}Callbacks, WTF_ARRAY_LENGTH(${interfaceName}Callbacks));
1993END
1994    } else {
1995        push(@implContent, <<END);
1996        0, 0);
1997    UNUSED_PARAM(defaultSignature); // In some cases, it will not be used.
1998END
1999        $implIncludes{"wtf/UnusedParam.h"} = 1;
2000    }
2001
2002    if ($dataNode->extendedAttributes->{"CustomConstructor"} || $dataNode->extendedAttributes->{"V8CustomConstructor"} || $dataNode->extendedAttributes->{"CanBeConstructed"}) {
2003        push(@implContent, <<END);
2004        desc->SetCallHandler(V8${interfaceName}::constructorCallback);
2005END
2006    }
2007
2008    if ($access_check or @enabledAtRuntime or @{$dataNode->functions} or $has_constants) {
2009        push(@implContent,  <<END);
2010    v8::Local<v8::ObjectTemplate> instance = desc->InstanceTemplate();
2011    v8::Local<v8::ObjectTemplate> proto = desc->PrototypeTemplate();
2012END
2013    }
2014
2015    push(@implContent,  "    $access_check\n");
2016
2017    # Setup the enable-at-runtime attrs if we have them
2018    foreach my $runtime_attr (@enabledAtRuntime) {
2019        my $enable_function = GetRuntimeEnableFunctionName($runtime_attr->signature);
2020        my $conditionalString = GenerateConditionalString($runtime_attr->signature);
2021        push(@implContent, "\n#if ${conditionalString}\n") if $conditionalString;
2022        push(@implContent, "    if (${enable_function}()) {\n");
2023        push(@implContent, "        static const BatchedAttribute attrData =\\\n");
2024        GenerateSingleBatchedAttribute($interfaceName, $runtime_attr, ";", "    ");
2025        push(@implContent, <<END);
2026        configureAttribute(instance, proto, attrData);
2027    }
2028END
2029        push(@implContent, "\n#endif // ${conditionalString}\n") if $conditionalString;
2030    }
2031
2032    GenerateImplementationIndexer($dataNode, $indexer);
2033    GenerateImplementationNamedPropertyGetter($dataNode, $namedPropertyGetter);
2034    GenerateImplementationCustomCall($dataNode);
2035    GenerateImplementationMasqueradesAsUndefined($dataNode);
2036
2037    # Define our functions with Set() or SetAccessor()
2038    $total_functions = 0;
2039    foreach my $function (@{$dataNode->functions}) {
2040        # Only one accessor is needed for overloaded methods:
2041        next if $function->{overloadIndex} > 1;
2042
2043        $total_functions++;
2044        my $attrExt = $function->signature->extendedAttributes;
2045        my $name = $function->signature->name;
2046
2047        my $property_attributes = "v8::DontDelete";
2048        if ($attrExt->{"DontEnum"}) {
2049            $property_attributes .= " | v8::DontEnum";
2050        }
2051        if ($attrExt->{"V8ReadOnly"}) {
2052            $property_attributes .= " | v8::ReadOnly";
2053        }
2054
2055        my $commentInfo = "Function '$name' (ExtAttr: '" . join(' ', keys(%{$attrExt})) . "')";
2056
2057        my $template = "proto";
2058        if ($attrExt->{"V8OnInstance"}) {
2059            $template = "instance";
2060        }
2061        if ($attrExt->{"ClassMethod"}) {
2062            $template = "desc";
2063        }
2064
2065        my $conditional = "";
2066        if ($attrExt->{"EnabledAtRuntime"}) {
2067            # Only call Set()/SetAccessor() if this method should be enabled
2068            $enable_function = GetRuntimeEnableFunctionName($function->signature);
2069            $conditional = "if (${enable_function}())\n        ";
2070        }
2071
2072        if ($attrExt->{"DoNotCheckDomainSecurity"} &&
2073            ($dataNode->extendedAttributes->{"CheckDomainSecurity"} || $interfaceName eq "DOMWindow")) {
2074            # Mark the accessor as ReadOnly and set it on the proto object so
2075            # it can be shadowed. This is really a hack to make it work.
2076            # There are several sceneria to call into the accessor:
2077            #   1) from the same domain: "window.open":
2078            #      the accessor finds the DOM wrapper in the proto chain;
2079            #   2) from the same domain: "window.__proto__.open":
2080            #      the accessor will NOT find a DOM wrapper in the prototype chain
2081            #   3) from another domain: "window.open":
2082            #      the access find the DOM wrapper in the prototype chain
2083            #   "window.__proto__.open" from another domain will fail when
2084            #   accessing '__proto__'
2085            #
2086            # The solution is very hacky and fragile, it really needs to be replaced
2087            # by a better solution.
2088            $property_attributes .= " | v8::ReadOnly";
2089            push(@implContent, <<END);
2090
2091    // $commentInfo
2092    ${conditional}$template->SetAccessor(v8::String::New("$name"), ${interfaceName}Internal::${name}AttrGetter, 0, v8::Handle<v8::Value>(), v8::ALL_CAN_READ, static_cast<v8::PropertyAttribute>($property_attributes));
2093END
2094          $num_callbacks++;
2095          next;
2096      }
2097
2098      my $signature = "defaultSignature";
2099      if ($attrExt->{"V8DoNotCheckSignature"} || $attrExt->{"ClassMethod"}) {
2100          $signature = "v8::Local<v8::Signature>()";
2101      }
2102
2103      if (RequiresCustomSignature($function)) {
2104          $signature = "${name}Signature";
2105          push(@implContent, "\n    // Custom Signature '$name'\n", CreateCustomSignature($function));
2106      }
2107
2108      # Normal function call is a template
2109      my $callback = GetFunctionTemplateCallbackName($function, $interfaceName);
2110
2111      if ($property_attributes eq "v8::DontDelete") {
2112          $property_attributes = "";
2113      } else {
2114          $property_attributes = ", static_cast<v8::PropertyAttribute>($property_attributes)";
2115      }
2116
2117      if ($template eq "proto" && $conditional eq "" && $signature eq "defaultSignature" && $property_attributes eq "") {
2118          # Standard type of callback, already created in the batch, so skip it here.
2119          next;
2120      }
2121
2122      push(@implContent, <<END);
2123    ${conditional}$template->Set(v8::String::New("$name"), v8::FunctionTemplate::New($callback, v8::Handle<v8::Value>(), ${signature})$property_attributes);
2124END
2125      $num_callbacks++;
2126    }
2127
2128    die "Wrong number of callbacks generated for $interfaceName ($num_callbacks, should be $total_functions)" if $num_callbacks != $total_functions;
2129
2130    if ($has_constants) {
2131        push(@implContent, <<END);
2132    batchConfigureConstants(desc, proto, ${interfaceName}Consts, WTF_ARRAY_LENGTH(${interfaceName}Consts));
2133END
2134    }
2135
2136    # Special cases
2137    if ($interfaceName eq "DOMWindow") {
2138        push(@implContent, <<END);
2139
2140    proto->SetInternalFieldCount(V8DOMWindow::internalFieldCount);
2141    desc->SetHiddenPrototype(true);
2142    instance->SetInternalFieldCount(V8DOMWindow::internalFieldCount);
2143    // Set access check callbacks, but turned off initially.
2144    // When a context is detached from a frame, turn on the access check.
2145    // Turning on checks also invalidates inline caches of the object.
2146    instance->SetAccessCheckCallbacks(V8DOMWindow::namedSecurityCheck, V8DOMWindow::indexedSecurityCheck, v8::External::Wrap(&V8DOMWindow::info), false);
2147END
2148    }
2149    if ($interfaceName eq "HTMLDocument") {
2150        push(@implContent, <<END);
2151    desc->SetHiddenPrototype(true);
2152END
2153    }
2154    if ($interfaceName eq "Location") {
2155        push(@implContent, <<END);
2156
2157    // For security reasons, these functions are on the instance instead
2158    // of on the prototype object to ensure that they cannot be overwritten.
2159    instance->SetAccessor(v8::String::New("reload"), V8Location::reloadAccessorGetter, 0, v8::Handle<v8::Value>(), v8::ALL_CAN_READ, static_cast<v8::PropertyAttribute>(v8::DontDelete | v8::ReadOnly));
2160    instance->SetAccessor(v8::String::New("replace"), V8Location::replaceAccessorGetter, 0, v8::Handle<v8::Value>(), v8::ALL_CAN_READ, static_cast<v8::PropertyAttribute>(v8::DontDelete | v8::ReadOnly));
2161    instance->SetAccessor(v8::String::New("assign"), V8Location::assignAccessorGetter, 0, v8::Handle<v8::Value>(), v8::ALL_CAN_READ, static_cast<v8::PropertyAttribute>(v8::DontDelete | v8::ReadOnly));
2162END
2163    }
2164
2165    my $nativeType = GetNativeTypeForConversions($dataNode, $interfaceName);
2166    push(@implContent, <<END);
2167
2168    // Custom toString template
2169    desc->Set(getToStringName(), getToStringTemplate());
2170    return desc;
2171}
2172
2173v8::Persistent<v8::FunctionTemplate> ${className}::GetRawTemplate()
2174{
2175    static v8::Persistent<v8::FunctionTemplate> ${className}RawCache = createRawTemplate();
2176    return ${className}RawCache;
2177}
2178
2179v8::Persistent<v8::FunctionTemplate> ${className}::GetTemplate()\
2180{
2181    static v8::Persistent<v8::FunctionTemplate> ${className}Cache = Configure${className}Template(GetRawTemplate());
2182    return ${className}Cache;
2183}
2184
2185bool ${className}::HasInstance(v8::Handle<v8::Value> value)
2186{
2187    return GetRawTemplate()->HasInstance(value);
2188}
2189
2190END
2191
2192    if (IsActiveDomType($interfaceName)) {
2193        # MessagePort is handled like an active dom object even though it doesn't inherit
2194        # from ActiveDOMObject, so don't try to cast it to ActiveDOMObject.
2195        my $returnValue = $interfaceName eq "MessagePort" ? "0" : "toNative(object)";
2196        push(@implContent, <<END);
2197ActiveDOMObject* ${className}::toActiveDOMObject(v8::Handle<v8::Object> object)
2198{
2199    return ${returnValue};
2200}
2201END
2202    }
2203
2204    if ($implClassName eq "DOMWindow") {
2205        push(@implContent, <<END);
2206v8::Persistent<v8::ObjectTemplate> V8DOMWindow::GetShadowObjectTemplate()
2207{
2208    static v8::Persistent<v8::ObjectTemplate> V8DOMWindowShadowObjectCache;
2209    if (V8DOMWindowShadowObjectCache.IsEmpty()) {
2210        V8DOMWindowShadowObjectCache = v8::Persistent<v8::ObjectTemplate>::New(v8::ObjectTemplate::New());
2211        ConfigureShadowObjectTemplate(V8DOMWindowShadowObjectCache);
2212    }
2213    return V8DOMWindowShadowObjectCache;
2214}
2215END
2216    }
2217
2218    GenerateToV8Converters($dataNode, $interfaceName, $className, $nativeType, $serializedAttribute);
2219
2220    push(@implContent, <<END);
2221
2222void ${className}::derefObject(void* object)
2223{
2224END
2225
2226    if (IsRefPtrType($interfaceName)) {
2227        push(@implContent, <<END);
2228    static_cast<${nativeType}*>(object)->deref();
2229END
2230    }
2231
2232    push(@implContent, <<END);
2233}
2234
2235} // namespace WebCore
2236END
2237
2238    my $conditionalString = GenerateConditionalString($dataNode);
2239    push(@implContent, "\n#endif // ${conditionalString}\n") if $conditionalString;
2240
2241    # We've already added the header for this file in implFixedHeader, so remove
2242    # it from implIncludes to ensure we don't #include it twice.
2243    delete $implIncludes{"${className}.h"};
2244}
2245
2246sub GenerateHeaderContentHeader
2247{
2248    my $dataNode = shift;
2249    my $className = "V8" . $dataNode->name;
2250    my $conditionalString = GenerateConditionalString($dataNode);
2251
2252    my @headerContentHeader = split("\r", $headerTemplate);
2253
2254    push(@headerContentHeader, "\n#if ${conditionalString}\n") if $conditionalString;
2255    push(@headerContentHeader, "\n#ifndef ${className}" . "_h");
2256    push(@headerContentHeader, "\n#define ${className}" . "_h\n\n");
2257    return @headerContentHeader;
2258}
2259
2260sub GenerateImplementationContentHeader
2261{
2262    my $dataNode = shift;
2263    my $className = "V8" . $dataNode->name;
2264    my $conditionalString = GenerateConditionalString($dataNode);
2265
2266    my @implContentHeader = split("\r", $headerTemplate);
2267
2268    push(@implContentHeader, "\n#include \"config.h\"\n");
2269    push(@implContentHeader, "#include \"${className}.h\"\n\n");
2270    push(@implContentHeader, "#if ${conditionalString}\n\n") if $conditionalString;
2271    return @implContentHeader;
2272}
2273
2274sub GenerateCallbackHeader
2275{
2276    my $object = shift;
2277    my $dataNode = shift;
2278
2279    my $interfaceName = $dataNode->name;
2280    my $className = "V8$interfaceName";
2281
2282
2283    # - Add default header template
2284    push(@headerContent, GenerateHeaderContentHeader($dataNode));
2285
2286    my @unsortedIncludes = ();
2287    push(@unsortedIncludes, "#include \"ActiveDOMCallback.h\"");
2288    push(@unsortedIncludes, "#include \"$interfaceName.h\"");
2289    push(@unsortedIncludes, "#include \"WorldContextHandle.h\"");
2290    push(@unsortedIncludes, "#include <v8.h>");
2291    push(@unsortedIncludes, "#include <wtf/Forward.h>");
2292    push(@headerContent, join("\n", sort @unsortedIncludes));
2293
2294    push(@headerContent, "\n\nnamespace WebCore {\n\n");
2295    push(@headerContent, "class ScriptExecutionContext;\n\n");
2296    push(@headerContent, "class $className : public $interfaceName, public ActiveDOMCallback {\n");
2297
2298    push(@headerContent, <<END);
2299public:
2300    static PassRefPtr<${className}> create(v8::Local<v8::Value> value, ScriptExecutionContext* context)
2301    {
2302        ASSERT(value->IsObject());
2303        ASSERT(context);
2304        return adoptRef(new ${className}(value->ToObject(), context));
2305    }
2306
2307    virtual ~${className}();
2308
2309END
2310
2311    # Functions
2312    my $numFunctions = @{$dataNode->functions};
2313    if ($numFunctions > 0) {
2314        push(@headerContent, "    // Functions\n");
2315        foreach my $function (@{$dataNode->functions}) {
2316            my @params = @{$function->parameters};
2317            if (!$function->signature->extendedAttributes->{"Custom"} &&
2318                !(GetNativeType($function->signature->type) eq "bool")) {
2319                    push(@headerContent, "    COMPILE_ASSERT(false)");
2320            }
2321
2322            push(@headerContent, "    virtual " . GetNativeTypeForCallbacks($function->signature->type) . " " . $function->signature->name . "(");
2323
2324            my @args = ();
2325            foreach my $param (@params) {
2326                push(@args, GetNativeTypeForCallbacks($param->type) . " " . $param->name);
2327            }
2328            push(@headerContent, join(", ", @args));
2329            push(@headerContent, ");\n");
2330        }
2331    }
2332
2333    push(@headerContent, <<END);
2334
2335private:
2336    ${className}(v8::Local<v8::Object>, ScriptExecutionContext*);
2337
2338    v8::Persistent<v8::Object> m_callback;
2339    WorldContextHandle m_worldContext;
2340};
2341
2342END
2343
2344    push(@headerContent, "}\n\n");
2345    push(@headerContent, "#endif // $className" . "_h\n\n");
2346
2347    my $conditionalString = GenerateConditionalString($dataNode);
2348    push(@headerContent, "#endif // ${conditionalString}\n") if $conditionalString;
2349}
2350
2351sub GenerateCallbackImplementation
2352{
2353    my $object = shift;
2354    my $dataNode = shift;
2355    my $interfaceName = $dataNode->name;
2356    my $className = "V8$interfaceName";
2357
2358    # - Add default header template
2359    push(@implFixedHeader, GenerateImplementationContentHeader($dataNode));
2360
2361    $implIncludes{"ScriptExecutionContext.h"} = 1;
2362    $implIncludes{"V8Binding.h"} = 1;
2363    $implIncludes{"V8CustomVoidCallback.h"} = 1;
2364    $implIncludes{"V8Proxy.h"} = 1;
2365
2366    push(@implContent, "#include <wtf/Assertions.h>\n\n");
2367    push(@implContent, "namespace WebCore {\n\n");
2368    push(@implContent, <<END);
2369${className}::${className}(v8::Local<v8::Object> callback, ScriptExecutionContext* context)
2370    : ActiveDOMCallback(context)
2371    , m_callback(v8::Persistent<v8::Object>::New(callback))
2372    , m_worldContext(UseCurrentWorld)
2373{
2374}
2375
2376${className}::~${className}()
2377{
2378    m_callback.Dispose();
2379}
2380
2381END
2382
2383    # Functions
2384    my $numFunctions = @{$dataNode->functions};
2385    if ($numFunctions > 0) {
2386        push(@implContent, "// Functions\n");
2387        foreach my $function (@{$dataNode->functions}) {
2388            my @params = @{$function->parameters};
2389            if ($function->signature->extendedAttributes->{"Custom"} ||
2390                !(GetNativeTypeForCallbacks($function->signature->type) eq "bool")) {
2391                next;
2392            }
2393
2394            AddIncludesForType($function->signature->type);
2395            push(@implContent, "\n" . GetNativeTypeForCallbacks($function->signature->type) . " ${className}::" . $function->signature->name . "(");
2396
2397            my @args = ();
2398            foreach my $param (@params) {
2399                AddIncludesForType($param->type);
2400                push(@args, GetNativeTypeForCallbacks($param->type) . " " . $param->name);
2401            }
2402            push(@implContent, join(", ", @args));
2403
2404            push(@implContent, ")\n");
2405            push(@implContent, "{\n");
2406            push(@implContent, "    if (!canInvokeCallback())\n");
2407            push(@implContent, "        return true;\n\n");
2408            push(@implContent, "    v8::HandleScope handleScope;\n\n");
2409            push(@implContent, "    v8::Handle<v8::Context> v8Context = toV8Context(scriptExecutionContext(), m_worldContext);\n");
2410            push(@implContent, "    if (v8Context.IsEmpty())\n");
2411            push(@implContent, "        return true;\n\n");
2412            push(@implContent, "    v8::Context::Scope scope(v8Context);\n\n");
2413
2414            @args = ();
2415            foreach my $param (@params) {
2416                my $paramName = $param->name;
2417                push(@implContent, "    v8::Handle<v8::Value> ${paramName}Handle = " . NativeToJSValue($param, $paramName) . ";\n");
2418                push(@implContent, "    if (${paramName}Handle.IsEmpty()) {\n");
2419                push(@implContent, "        CRASH();\n");
2420                push(@implContent, "        return true;\n");
2421                push(@implContent, "    }\n");
2422                push(@args, "        ${paramName}Handle");
2423            }
2424
2425            if (scalar(@args) > 0) {
2426                push(@implContent, "\n    v8::Handle<v8::Value> argv[] = {\n");
2427                push(@implContent, join(",\n", @args));
2428                push(@implContent, "\n    };\n\n");
2429            } else {
2430                push(@implContent, "\n    v8::Handle<v8::Value> *argv = 0;\n\n");
2431            }
2432            push(@implContent, "    bool callbackReturnValue = false;\n");
2433            push(@implContent, "    return !invokeCallback(m_callback, " . scalar(@params) . ", argv, callbackReturnValue, scriptExecutionContext());\n");
2434            push(@implContent, "}\n");
2435        }
2436    }
2437
2438    push(@implContent, "\n} // namespace WebCore\n\n");
2439
2440    my $conditionalString = GenerateConditionalString($dataNode);
2441    push(@implContent, "#endif // ${conditionalString}\n") if $conditionalString;
2442}
2443
2444sub GenerateToV8Converters
2445{
2446    my $dataNode = shift;
2447    my $interfaceName = shift;
2448    my $className = shift;
2449    my $nativeType = shift;
2450    my $serializedAttribute = shift;
2451
2452    my $domMapFunction = GetDomMapFunction($dataNode, $interfaceName);
2453    my $forceNewObjectInput = IsDOMNodeType($interfaceName) ? ", bool forceNewObject" : "";
2454    my $forceNewObjectCall = IsDOMNodeType($interfaceName) ? ", forceNewObject" : "";
2455
2456    push(@implContent, <<END);
2457
2458v8::Handle<v8::Object> ${className}::wrapSlow(${nativeType}* impl)
2459{
2460    v8::Handle<v8::Object> wrapper;
2461    V8Proxy* proxy = 0;
2462END
2463
2464    if (IsNodeSubType($dataNode)) {
2465        push(@implContent, <<END);
2466    if (impl->document()) {
2467        proxy = V8Proxy::retrieve(impl->document()->frame());
2468        if (proxy && static_cast<Node*>(impl->document()) == static_cast<Node*>(impl)) {
2469            if (proxy->windowShell()->initContextIfNeeded()) {
2470                // initContextIfNeeded may have created a wrapper for the object, retry from the start.
2471                return ${className}::wrap(impl);
2472            }
2473        }
2474    }
2475
2476END
2477    }
2478
2479    if (IsNodeSubType($dataNode)) {
2480        push(@implContent, <<END);
2481
2482    v8::Handle<v8::Context> context;
2483    if (proxy)
2484        context = proxy->context();
2485
2486    // Enter the node's context and create the wrapper in that context.
2487    if (!context.IsEmpty())
2488        context->Enter();
2489END
2490    }
2491
2492    push(@implContent, <<END);
2493    wrapper = V8DOMWrapper::instantiateV8Object(proxy, &info, impl);
2494END
2495    if (IsNodeSubType($dataNode)) {
2496        push(@implContent, <<END);
2497    // Exit the node's context if it was entered.
2498    if (!context.IsEmpty())
2499        context->Exit();
2500END
2501    }
2502
2503    push(@implContent, <<END);
2504    if (wrapper.IsEmpty())
2505        return wrapper;
2506END
2507    push(@implContent, "\n    impl->ref();\n") if IsRefPtrType($interfaceName);
2508
2509    # Eagerly deserialize attributes of type SerializedScriptValue
2510    # while we're in the right context.
2511    if ($serializedAttribute) {
2512        die "Attribute of type SerializedScriptValue expected" if $serializedAttribute->signature->type ne "SerializedScriptValue";
2513        my $attrName = $serializedAttribute->signature->name;
2514        my $attrAttr = "v8::DontDelete";
2515        if ($serializedAttribute->type =~ /^readonly/) {
2516            $attrAttr .= " | v8::ReadOnly";
2517        }
2518        $attrAttr = "static_cast<v8::PropertyAttribute>($attrAttr)";
2519        my $getterFunc = $codeGenerator->WK_lcfirst($attrName);
2520        push(@implContent, <<END);
2521    SerializedScriptValue::deserializeAndSetProperty(wrapper, "${attrName}", ${attrAttr}, impl->${getterFunc}());
2522END
2523    }
2524
2525    push(@implContent, <<END);
2526    v8::Persistent<v8::Object> wrapperHandle = v8::Persistent<v8::Object>::New(wrapper);
2527END
2528    if (IsNodeSubType($dataNode)) {
2529        push(@implContent, <<END);
2530    wrapperHandle.SetWrapperClassId(v8DOMSubtreeClassId);
2531END
2532    }
2533    push(@implContent, <<END);
2534    ${domMapFunction}.set(impl, wrapperHandle);
2535END
2536
2537    push(@implContent, <<END);
2538    return wrapper;
2539}
2540END
2541}
2542
2543sub HasCustomToV8Implementation {
2544    # FIXME: This subroutine is lame. Probably should be an .idl attribute (CustomToV8)?
2545    $dataNode = shift;
2546    $interfaceName = shift;
2547
2548    # We generate a custom converter (but JSC doesn't) for the following:
2549    return 1 if $interfaceName eq "CSSStyleSheet";
2550    return 1 if $interfaceName eq "CanvasPixelArray";
2551    return 1 if $interfaceName eq "DOMStringMap";
2552    return 1 if $interfaceName eq "DOMWindow";
2553    return 1 if $interfaceName eq "DOMTokenList";
2554    return 1 if $interfaceName eq "Element";
2555    return 1 if $interfaceName eq "HTMLDocument";
2556    return 1 if $interfaceName eq "HTMLElement";
2557    return 1 if $interfaceName eq "Location";
2558    return 1 if $interfaceName eq "NamedNodeMap";
2559    return 1 if $interfaceName eq "SVGDocument";
2560    return 1 if $interfaceName eq "SVGElement";
2561    return 1 if $interfaceName eq "ScriptProfile";
2562    return 1 if $interfaceName eq "ScriptProfileNode";
2563    return 1 if $interfaceName eq "WorkerContext";
2564    # We don't generate a custom converter (but JSC does) for the following:
2565    return 0 if $interfaceName eq "AbstractWorker";
2566    return 0 if $interfaceName eq "CanvasRenderingContext";
2567    return 0 if $interfaceName eq "SVGElementInstance";
2568    return 0 if $interfaceName eq "NodeList";
2569    return 0 if $interfaceName eq "CSSRuleList";
2570    return 0 if $interfaceName eq "CSSStyleDeclaration";
2571    return 0 if $interfaceName eq "MediaList";
2572    return 0 if $interfaceName eq "StyleSheetList";
2573    return 0 if $interfaceName eq "DOMImplementation";
2574    return 0 if $interfaceName eq "DOMStringMap";
2575    return 0 if $interfaceName eq "DOMTokenList";
2576
2577    # For everything else, do what JSC does.
2578    return $dataNode->extendedAttributes->{"CustomToJS"};
2579}
2580
2581sub GetDomMapFunction
2582{
2583    my $dataNode = shift;
2584    my $type = shift;
2585    return "getDOMSVGElementInstanceMap()" if $type eq "SVGElementInstance";
2586    return "getDOMNodeMap()" if ($dataNode && IsNodeSubType($dataNode));
2587    return "getActiveDOMObjectMap()" if IsActiveDomType($type);
2588    return "getDOMObjectMap()";
2589}
2590
2591sub IsActiveDomType
2592{
2593    # FIXME: Consider making this an .idl attribute.
2594    my $type = shift;
2595    return 1 if $type eq "EventSource";
2596    return 1 if $type eq "MessagePort";
2597    return 1 if $type eq "XMLHttpRequest";
2598    return 1 if $type eq "WebSocket";
2599    return 1 if $type eq "Worker";
2600    return 1 if $type eq "SharedWorker";
2601    return 1 if $type eq "IDBRequest";
2602    return 1 if $type eq "IDBTransaction";
2603    return 1 if $type eq "FileReader";
2604    return 1 if $type eq "FileWriter";
2605    return 0;
2606}
2607
2608sub GetNativeTypeForConversions
2609{
2610    my $dataNode = shift;
2611    my $type = shift;
2612
2613    $type = $codeGenerator->GetSVGTypeNeedingTearOff($type) if $codeGenerator->IsSVGTypeNeedingTearOff($type);
2614    return $type;
2615}
2616
2617sub GenerateFunctionCallString()
2618{
2619    my $function = shift;
2620    my $numberOfParameters = shift;
2621    my $indent = shift;
2622    my $implClassName = shift;
2623
2624    my $name = $function->signature->name;
2625    my $returnType = GetTypeFromSignature($function->signature);
2626    my $nativeReturnType = GetNativeType($returnType, 0);
2627    my $result = "";
2628
2629    my $isSVGTearOffType = ($codeGenerator->IsSVGTypeNeedingTearOff($returnType) and not $implClassName =~ /List$/);
2630    $nativeReturnType = $codeGenerator->GetSVGWrappedTypeNeedingTearOff($returnType) if $isSVGTearOffType;
2631
2632    if ($function->signature->extendedAttributes->{"v8implname"}) {
2633        $name = $function->signature->extendedAttributes->{"v8implname"};
2634    }
2635
2636    if ($function->signature->extendedAttributes->{"ImplementationFunction"}) {
2637        $name = $function->signature->extendedAttributes->{"ImplementationFunction"};
2638    }
2639
2640    my $functionString = "imp->${name}(";
2641    if ($function->signature->extendedAttributes->{"ClassMethod"}) {
2642        $functionString = "${implClassName}::${name}(";
2643    }
2644
2645    my $index = 0;
2646    my $hasScriptState = 0;
2647
2648    my $callWith = $function->signature->extendedAttributes->{"CallWith"};
2649    if ($callWith) {
2650        my $callWithArg = "COMPILE_ASSERT(false)";
2651        if ($callWith eq "DynamicFrame") {
2652            $result .= $indent . "Frame* enteredFrame = V8Proxy::retrieveFrameForEnteredContext();\n";
2653            $result .= $indent . "if (!enteredFrame)\n";
2654            $result .= $indent . "    return v8::Undefined();\n";
2655            $callWithArg = "enteredFrame";
2656        } elsif ($callWith eq "ScriptState") {
2657            $result .= $indent . "EmptyScriptState state;\n";
2658            $callWithArg = "&state";
2659            $hasScriptState = 1;
2660        } elsif ($callWith eq "ScriptExecutionContext") {
2661            $result .= $indent . "ScriptExecutionContext* scriptContext = getScriptExecutionContext();\n";
2662            $result .= $indent . "if (!scriptContext)\n";
2663            $result .= $indent . "    return v8::Undefined();\n";
2664            $callWithArg = "scriptContext";
2665        }
2666        $functionString .= ", " if $index;
2667        $functionString .= $callWithArg;
2668        $index++;
2669        $numberOfParameters++
2670    }
2671
2672    foreach my $parameter (@{$function->parameters}) {
2673        if ($index eq $numberOfParameters) {
2674            last;
2675        }
2676        $functionString .= ", " if $index;
2677        my $paramName = $parameter->name;
2678        my $paramType = $parameter->type;
2679
2680        if ($parameter->type eq "NodeFilter" || $parameter->type eq "XPathNSResolver") {
2681            $functionString .= "$paramName.get()";
2682        } elsif ($codeGenerator->IsSVGTypeNeedingTearOff($parameter->type) and not $implClassName =~ /List$/) {
2683            $functionString .= "$paramName->propertyReference()";
2684            $result .= $indent . "if (!$paramName) {\n";
2685            $result .= $indent . "    V8Proxy::setDOMException(WebCore::TYPE_MISMATCH_ERR);\n";
2686            $result .= $indent . "    return v8::Handle<v8::Value>();\n";
2687            $result .= $indent . "}\n";
2688        } elsif ($parameter->type eq "SVGMatrix" and $implClassName eq "SVGTransformList") {
2689            $functionString .= "$paramName.get()";
2690        } else {
2691            $functionString .= $paramName;
2692        }
2693        $index++;
2694    }
2695
2696    if ($function->signature->extendedAttributes->{"CustomArgumentHandling"}) {
2697        $functionString .= ", " if $index;
2698        $functionString .= "scriptArguments, callStack";
2699        $index += 2;
2700    }
2701
2702    if ($function->signature->extendedAttributes->{"NeedsUserGestureCheck"}) {
2703        $functionString .= ", " if $index;
2704        # FIXME: We need to pass DOMWrapperWorld as a parameter.
2705        # See http://trac.webkit.org/changeset/54182
2706        $functionString .= "processingUserGesture()";
2707        $index++;
2708    }
2709
2710    if (@{$function->raisesExceptions}) {
2711        $functionString .= ", " if $index;
2712        $functionString .= "ec";
2713        $index++;
2714    }
2715    $functionString .= ")";
2716
2717    my $return = "result";
2718    my $returnIsRef = IsRefPtrType($returnType);
2719
2720    if ($returnType eq "void") {
2721        $result .= $indent . "$functionString;\n";
2722    } elsif ($hasScriptState or @{$function->raisesExceptions}) {
2723        $result .= $indent . $nativeReturnType . " result = $functionString;\n";
2724    } else {
2725        # Can inline the function call into the return statement to avoid overhead of using a Ref<> temporary
2726        $return = $functionString;
2727        $returnIsRef = 0;
2728
2729        if ($implClassName eq "SVGTransformList" and IsRefPtrType($returnType)) {
2730            $return = "WTF::getPtr(" . $return . ")";
2731        }
2732    }
2733
2734    if (@{$function->raisesExceptions}) {
2735        $result .= $indent . "if (UNLIKELY(ec))\n";
2736        $result .= $indent . "    goto fail;\n";
2737    }
2738
2739    if ($hasScriptState) {
2740        $result .= $indent . "if (state.hadException())\n";
2741        $result .= $indent . "    return throwError(state.exception());\n"
2742    }
2743
2744    if ($isSVGTearOffType) {
2745        $implIncludes{"V8$returnType.h"} = 1;
2746        $implIncludes{"SVGPropertyTearOff.h"} = 1;
2747        my $svgNativeType = $codeGenerator->GetSVGTypeNeedingTearOff($returnType);
2748        $result .= $indent . "return toV8(WTF::getPtr(${svgNativeType}::create($return)));\n";
2749        return $result;
2750    }
2751
2752    # If the implementing class is a POD type, commit changes
2753    if ($codeGenerator->IsSVGTypeNeedingTearOff($implClassName) and not $implClassName =~ /List$/) {
2754        $result .= $indent . "wrapper->commitChange();\n";
2755    }
2756
2757    $return .= ".release()" if ($returnIsRef);
2758    $result .= $indent . ReturnNativeToJSValue($function->signature, $return, $indent) . ";\n";
2759
2760    return $result;
2761}
2762
2763
2764sub GetTypeFromSignature
2765{
2766    my $signature = shift;
2767
2768    return $codeGenerator->StripModule($signature->type);
2769}
2770
2771
2772sub GetNativeTypeFromSignature
2773{
2774    my $signature = shift;
2775    my $parameterIndex = shift;
2776
2777    my $type = GetTypeFromSignature($signature);
2778
2779    if ($type eq "unsigned long" and $signature->extendedAttributes->{"IsIndex"}) {
2780        # Special-case index arguments because we need to check that they aren't < 0.
2781        return "int";
2782    }
2783
2784    $type = GetNativeType($type, $parameterIndex >= 0 ? 1 : 0);
2785
2786    if ($parameterIndex >= 0 && $type eq "V8Parameter") {
2787        my $mode = "";
2788        if ($signature->extendedAttributes->{"ConvertUndefinedOrNullToNullString"}) {
2789            $mode = "WithUndefinedOrNullCheck";
2790        } elsif ($signature->extendedAttributes->{"ConvertNullToNullString"} || $signature->extendedAttributes->{"Reflect"}) {
2791            $mode = "WithNullCheck";
2792        }
2793        $type .= "<$mode>";
2794    }
2795
2796    return $type;
2797}
2798
2799sub IsRefPtrType
2800{
2801    my $type = shift;
2802
2803    return 0 if $type eq "boolean";
2804    return 0 if $type eq "float";
2805    return 0 if $type eq "int";
2806    return 0 if $type eq "Date";
2807    return 0 if $type eq "DOMString";
2808    return 0 if $type eq "double";
2809    return 0 if $type eq "short";
2810    return 0 if $type eq "long";
2811    return 0 if $type eq "unsigned";
2812    return 0 if $type eq "unsigned long";
2813    return 0 if $type eq "unsigned short";
2814
2815    return 1;
2816}
2817
2818sub GetNativeType
2819{
2820    my $type = shift;
2821    my $isParameter = shift;
2822
2823    my $svgNativeType = $codeGenerator->GetSVGTypeNeedingTearOff($type);
2824    if ($svgNativeType) {
2825        if ($svgNativeType =~ /List$/) {
2826            return "${svgNativeType}*";
2827        } else {
2828            return "RefPtr<${svgNativeType} >";
2829        }
2830    }
2831
2832    if ($type eq "float" or $type eq "double") {
2833        return $type;
2834    }
2835
2836    return "V8Parameter" if ($type eq "DOMString" or $type eq "DOMUserData") and $isParameter;
2837    return "int" if $type eq "int";
2838    return "int" if $type eq "short" or $type eq "unsigned short";
2839    return "unsigned" if $type eq "unsigned long";
2840    return "int" if $type eq "long";
2841    return "long long" if $type eq "long long";
2842    return "unsigned long long" if $type eq "unsigned long long";
2843    return "bool" if $type eq "boolean";
2844    return "String" if $type eq "DOMString";
2845    return "Range::CompareHow" if $type eq "CompareHow";
2846    return "DOMTimeStamp" if $type eq "DOMTimeStamp";
2847    return "unsigned" if $type eq "unsigned int";
2848    return "Node*" if $type eq "EventTarget" and $isParameter;
2849    return "double" if $type eq "Date";
2850    return "ScriptValue" if $type eq "DOMObject";
2851    return "OptionsObject" if $type eq "OptionsObject";
2852
2853    return "String" if $type eq "DOMUserData";  # FIXME: Temporary hack?
2854
2855    # temporary hack
2856    return "RefPtr<NodeFilter>" if $type eq "NodeFilter";
2857
2858    return "RefPtr<SerializedScriptValue>" if $type eq "SerializedScriptValue";
2859
2860    return "RefPtr<IDBKey>" if $type eq "IDBKey";
2861
2862    # necessary as resolvers could be constructed on fly.
2863    return "RefPtr<XPathNSResolver>" if $type eq "XPathNSResolver";
2864
2865    return "RefPtr<${type}>" if IsRefPtrType($type) and not $isParameter;
2866
2867    return "RefPtr<MediaQueryListListener>" if $type eq "MediaQueryListListener";
2868
2869    return "PassRefPtr<DOMStringList>" if $type eq "DOMStringList" and $isParameter;
2870    return "RefPtr<DOMStringList>" if $type eq "DOMStringList";
2871
2872    # Default, assume native type is a pointer with same type name as idl type
2873    return "${type}*";
2874}
2875
2876sub GetNativeTypeForCallbacks
2877{
2878    my $type = shift;
2879    return "const String&" if $type eq "DOMString";
2880
2881    # Callbacks use raw pointers, so pass isParameter = 1
2882    return GetNativeType($type, 1);
2883}
2884
2885sub TranslateParameter
2886{
2887    my $signature = shift;
2888
2889    # The IDL uses some pseudo-types which don't really exist.
2890    if ($signature->type eq "TimeoutHandler") {
2891      $signature->type("DOMString");
2892    }
2893}
2894
2895sub TypeCanFailConversion
2896{
2897    my $signature = shift;
2898
2899    my $type = GetTypeFromSignature($signature);
2900
2901    $implIncludes{"ExceptionCode.h"} = 1 if $type eq "Attr";
2902    return 1 if $type eq "Attr";
2903    return 1 if $type eq "VoidCallback";
2904    return 1 if $type eq "IDBKey";
2905    return 0;
2906}
2907
2908sub JSValueToNative
2909{
2910    my $signature = shift;
2911    my $value = shift;
2912
2913    my $type = GetTypeFromSignature($signature);
2914
2915    return "$value" if $type eq "JSObject";
2916    return "$value->BooleanValue()" if $type eq "boolean";
2917    return "static_cast<$type>($value->NumberValue())" if $type eq "float" or $type eq "double";
2918
2919    return "toInt32($value)" if $type eq "long" or $type eq "short";
2920    return "toUInt32($value)" if $type eq "unsigned long" or $type eq "unsigned short";
2921    return "toInt64($value)" if $type eq "unsigned long long" or $type eq "long long";
2922    return "static_cast<Range::CompareHow>($value->Int32Value())" if $type eq "CompareHow";
2923    return "toWebCoreDate($value)" if $type eq "Date";
2924    return "v8ValueToWebCoreDOMStringList($value)" if $type eq "DOMStringList";
2925
2926    if ($type eq "DOMString" or $type eq "DOMUserData") {
2927        return $value;
2928    }
2929
2930    die "Unexpected SerializedScriptValue" if $type eq "SerializedScriptValue";
2931
2932    if ($type eq "IDBKey") {
2933        $implIncludes{"IDBBindingUtilities.h"} = 1;
2934        $implIncludes{"IDBKey.h"} = 1;
2935        return "createIDBKeyFromValue($value)";
2936    }
2937
2938    if ($type eq "OptionsObject") {
2939        $implIncludes{"OptionsObject.h"} = 1;
2940        return $value;
2941    }
2942
2943    if ($type eq "DOMObject") {
2944        $implIncludes{"ScriptValue.h"} = 1;
2945        return "ScriptValue($value)";
2946    }
2947
2948    if ($type eq "NodeFilter") {
2949        return "V8DOMWrapper::wrapNativeNodeFilter($value)";
2950    }
2951
2952    if ($type eq "MediaQueryListListener") {
2953        $implIncludes{"MediaQueryListListener.h"} = 1;
2954        return "MediaQueryListListener::create(" . $value . ")";
2955    }
2956
2957    # Default, assume autogenerated type conversion routines
2958    if ($type eq "EventTarget") {
2959        $implIncludes{"V8Node.h"} = 1;
2960
2961        # EventTarget is not in DOM hierarchy, but all Nodes are EventTarget.
2962        return "V8Node::HasInstance($value) ? V8Node::toNative(v8::Handle<v8::Object>::Cast($value)) : 0";
2963    }
2964
2965    if ($type eq "XPathNSResolver") {
2966        return "V8DOMWrapper::getXPathNSResolver($value)";
2967    }
2968
2969    AddIncludesForType($type);
2970
2971    if (IsDOMNodeType($type)) {
2972        $implIncludes{"V8${type}.h"} = 1;
2973
2974        # Perform type checks on the parameter, if it is expected Node type,
2975        # return NULL.
2976        return "V8${type}::HasInstance($value) ? V8${type}::toNative(v8::Handle<v8::Object>::Cast($value)) : 0";
2977    } else {
2978        $implIncludes{"V8$type.h"} = 1;
2979
2980        # Perform type checks on the parameter, if it is expected Node type,
2981        # return NULL.
2982        return "V8${type}::HasInstance($value) ? V8${type}::toNative(v8::Handle<v8::Object>::Cast($value)) : 0";
2983    }
2984}
2985
2986sub GetV8HeaderName
2987{
2988    my $type = shift;
2989    return "V8Event.h" if $type eq "DOMTimeStamp";
2990    return "EventListener.h" if $type eq "EventListener";
2991    return "EventTarget.h" if $type eq "EventTarget";
2992    return "SerializedScriptValue.h" if $type eq "SerializedScriptValue";
2993    return "ScriptValue.h" if $type eq "DOMObject";
2994    return "V8${type}.h";
2995}
2996
2997sub CreateCustomSignature
2998{
2999    my $function = shift;
3000    my $count = @{$function->parameters};
3001    my $name = $function->signature->name;
3002    my $result = "    const int ${name}Argc = ${count};\n" .
3003      "    v8::Handle<v8::FunctionTemplate> ${name}Argv[${name}Argc] = { ";
3004    my $first = 1;
3005    foreach my $parameter (@{$function->parameters}) {
3006        if ($first) { $first = 0; }
3007        else { $result .= ", "; }
3008        if (IsWrapperType($parameter->type)) {
3009            if ($parameter->type eq "XPathNSResolver") {
3010                # Special case for XPathNSResolver.  All other browsers accepts a callable,
3011                # so, even though it's against IDL, accept objects here.
3012                $result .= "v8::Handle<v8::FunctionTemplate>()";
3013            } else {
3014                my $type = $parameter->type;
3015                my $header = GetV8HeaderName($type);
3016                $implIncludes{$header} = 1;
3017                $result .= "V8${type}::GetRawTemplate()";
3018            }
3019        } else {
3020            $result .= "v8::Handle<v8::FunctionTemplate>()";
3021        }
3022    }
3023    $result .= " };\n";
3024    $result .= "    v8::Handle<v8::Signature> ${name}Signature = v8::Signature::New(desc, ${name}Argc, ${name}Argv);\n";
3025    return $result;
3026}
3027
3028
3029sub RequiresCustomSignature
3030{
3031    my $function = shift;
3032    # No signature needed for Custom function
3033    if ($function->signature->extendedAttributes->{"Custom"} ||
3034        $function->signature->extendedAttributes->{"V8Custom"}) {
3035        return 0;
3036    }
3037    # No signature needed for overloaded function
3038    if (@{$function->{overloads}} > 1) {
3039        return 0;
3040    }
3041    # Type checking is performed in the generated code
3042    if ($function->signature->extendedAttributes->{"StrictTypeChecking"}) {
3043      return 0;
3044    }
3045    foreach my $parameter (@{$function->parameters}) {
3046        if ($parameter->extendedAttributes->{"Optional"} || $parameter->extendedAttributes->{"Callback"}) {
3047            return 0;
3048        }
3049    }
3050
3051    foreach my $parameter (@{$function->parameters}) {
3052        if (IsWrapperType($parameter->type)) {
3053            return 1;
3054        }
3055    }
3056    return 0;
3057}
3058
3059
3060# FIXME: Sort this array.
3061my %non_wrapper_types = (
3062    'float' => 1,
3063    'double' => 1,
3064    'int' => 1,
3065    'unsigned int' => 1,
3066    'short' => 1,
3067    'unsigned short' => 1,
3068    'long' => 1,
3069    'unsigned long' => 1,
3070    'boolean' => 1,
3071    'long long' => 1,
3072    'unsigned long long' => 1,
3073    'DOMString' => 1,
3074    'CompareHow' => 1,
3075    'SerializedScriptValue' => 1,
3076    'DOMTimeStamp' => 1,
3077    'JSObject' => 1,
3078    'DOMObject' => 1,
3079    'EventTarget' => 1,
3080    'NodeFilter' => 1,
3081    'EventListener' => 1,
3082    'IDBKey' => 1,
3083    'OptionsObject' => 1,
3084    'Date' => 1,
3085    'MediaQueryListListener' => 1
3086);
3087
3088
3089sub IsWrapperType
3090{
3091    my $type = $codeGenerator->StripModule(shift);
3092    return !($non_wrapper_types{$type});
3093}
3094
3095sub IsDOMNodeType
3096{
3097    my $type = shift;
3098
3099    return 1 if $type eq 'Attr';
3100    return 1 if $type eq 'CDATASection';
3101    return 1 if $type eq 'Comment';
3102    return 1 if $type eq 'Document';
3103    return 1 if $type eq 'DocumentFragment';
3104    return 1 if $type eq 'DocumentType';
3105    return 1 if $type eq 'Element';
3106    return 1 if $type eq 'EntityReference';
3107    return 1 if $type eq 'HTMLCanvasElement';
3108    return 1 if $type eq 'HTMLDocument';
3109    return 1 if $type eq 'HTMLElement';
3110    return 1 if $type eq 'HTMLFormElement';
3111    return 1 if $type eq 'HTMLTableCaptionElement';
3112    return 1 if $type eq 'HTMLTableSectionElement';
3113    return 1 if $type eq 'Node';
3114    return 1 if $type eq 'ProcessingInstruction';
3115    return 1 if $type eq 'SVGElement';
3116    return 1 if $type eq 'SVGDocument';
3117    return 1 if $type eq 'SVGSVGElement';
3118    return 1 if $type eq 'SVGUseElement';
3119    return 1 if $type eq 'Text';
3120
3121    return 0;
3122}
3123
3124
3125sub NativeToJSValue
3126{
3127    my $signature = shift;
3128    my $value = shift;
3129    my $indent = shift;
3130    my $type = GetTypeFromSignature($signature);
3131
3132    return "v8Boolean($value)" if $type eq "boolean";
3133    return "v8::Handle<v8::Value>()" if $type eq "void";     # equivalent to v8::Undefined()
3134
3135    # HTML5 says that unsigned reflected attributes should be in the range
3136    # [0, 2^31). When a value isn't in this range, a default value (or 0)
3137    # should be returned instead.
3138    if ($signature->extendedAttributes->{"Reflect"} and ($type eq "unsigned long" or $type eq "unsigned short")) {
3139        $value =~ s/getUnsignedIntegralAttribute/getIntegralAttribute/g;
3140        return "v8::Integer::NewFromUnsigned(std::max(0, " . $value . "))";
3141    }
3142
3143    # For all the types where we use 'int' as the representation type,
3144    # we use Integer::New which has a fast Smi conversion check.
3145    my $nativeType = GetNativeType($type);
3146    return "v8::Integer::New($value)" if $nativeType eq "int";
3147    return "v8::Integer::NewFromUnsigned($value)" if $nativeType eq "unsigned";
3148
3149    return "v8DateOrNull($value)" if $type eq "Date";
3150    # long long and unsigned long long are not representable in ECMAScript.
3151    return "v8::Number::New(static_cast<double>($value))" if $type eq "long long" or $type eq "unsigned long long" or $type eq "DOMTimeStamp";
3152    return "v8::Number::New($value)" if $codeGenerator->IsPrimitiveType($type);
3153    return "$value.v8Value()" if $nativeType eq "ScriptValue";
3154
3155    if ($codeGenerator->IsStringType($type)) {
3156        my $conv = $signature->extendedAttributes->{"ConvertNullStringTo"};
3157        if (defined $conv) {
3158            return "v8StringOrNull($value)" if $conv eq "Null";
3159            return "v8StringOrUndefined($value)" if $conv eq "Undefined";
3160            return "v8StringOrFalse($value)" if $conv eq "False";
3161
3162            die "Unknown value for ConvertNullStringTo extended attribute";
3163        }
3164        $conv = $signature->extendedAttributes->{"ConvertScriptString"};
3165        return "v8StringOrNull($value)" if $conv;
3166        return "v8String($value)";
3167    }
3168
3169    AddIncludesForType($type);
3170
3171    # special case for non-DOM node interfaces
3172    if (IsDOMNodeType($type)) {
3173        return "toV8(${value}" . ($signature->extendedAttributes->{"ReturnsNew"} ? ", true)" : ")");
3174    }
3175
3176    if ($type eq "EventTarget") {
3177        return "V8DOMWrapper::convertEventTargetToV8Object($value)";
3178    }
3179
3180    if ($type eq "EventListener") {
3181        $implIncludes{"V8AbstractEventListener.h"} = 1;
3182        return "${value} ? v8::Handle<v8::Value>(static_cast<V8AbstractEventListener*>(${value})->getListenerObject(imp->scriptExecutionContext())) : v8::Handle<v8::Value>(v8::Null())";
3183    }
3184
3185    if ($type eq "SerializedScriptValue") {
3186        $implIncludes{"$type.h"} = 1;
3187        return "$value->deserialize()";
3188    }
3189
3190    $implIncludes{"wtf/RefCounted.h"} = 1;
3191    $implIncludes{"wtf/RefPtr.h"} = 1;
3192    $implIncludes{"wtf/GetPtr.h"} = 1;
3193
3194    return "toV8($value)";
3195}
3196
3197sub ReturnNativeToJSValue
3198{
3199    return "return " . NativeToJSValue(@_);
3200}
3201
3202# Internal helper
3203sub WriteData
3204{
3205    if (defined($IMPL)) {
3206        # Write content to file.
3207        print $IMPL @implContentHeader;
3208
3209        print $IMPL @implFixedHeader;
3210
3211        foreach my $implInclude (sort keys(%implIncludes)) {
3212            my $checkType = $implInclude;
3213            $checkType =~ s/\.h//;
3214
3215            if ($implInclude =~ /wtf/) {
3216                print $IMPL "#include \<$implInclude\>\n";
3217            } else {
3218                print $IMPL "#include \"$implInclude\"\n" unless $codeGenerator->IsSVGAnimatedType($checkType);
3219            }
3220        }
3221
3222        print $IMPL "\n";
3223        print $IMPL @implContentDecls;
3224        print $IMPL @implContent;
3225        close($IMPL);
3226        undef($IMPL);
3227
3228        %implIncludes = ();
3229        @implFixedHeader = ();
3230        @implHeaderContent = ();
3231        @implContentDecls = ();
3232        @implContent = ();
3233    }
3234
3235    if (defined($HEADER)) {
3236        # Write content to file.
3237        print $HEADER @headerContent;
3238        close($HEADER);
3239        undef($HEADER);
3240
3241        @headerContent = ();
3242    }
3243}
3244
3245sub GetVisibleInterfaceName
3246{
3247    my $interfaceName = shift;
3248
3249    return "DOMException" if $interfaceName eq "DOMCoreException";
3250    return "FormData" if $interfaceName eq "DOMFormData";
3251    return $interfaceName;
3252}
3253
3254sub GetCallbackClassName
3255{
3256    my $interfaceName = shift;
3257
3258    return "V8CustomVoidCallback" if $interfaceName eq "VoidCallback";
3259    return "V8$interfaceName";
3260}
3261
3262sub ConvertToV8Parameter
3263{
3264    my $signature = shift;
3265    my $nativeType = shift;
3266    my $variableName = shift;
3267    my $value = shift;
3268    my $suffix = shift;
3269
3270    die "Wrong native type passed: $nativeType" unless $nativeType =~ /^V8Parameter/;
3271    if ($signature->type eq "DOMString") {
3272        $implIncludes{"V8BindingMacros.h"} = 1;
3273        my $macro = "STRING_TO_V8PARAMETER_EXCEPTION_BLOCK";
3274        $macro .= "_$suffix" if $suffix;
3275        return "$macro($nativeType, $variableName, $value);"
3276    } else {
3277        # Don't know how to properly check for conversion exceptions when $parameter->type is "DOMUserData"
3278        return "$nativeType $variableName($value, true);";
3279    }
3280}
3281
3282# Returns the RuntimeEnabledFeatures function name that is hooked up to check if a method/attribute is enabled.
3283sub GetRuntimeEnableFunctionName
3284{
3285    my $signature = shift;
3286
3287    # If a parameter is given (e.g. "EnabledAtRuntime=FeatureName") return the RuntimeEnabledFeatures::{FeatureName}Enabled() method.
3288    return "RuntimeEnabledFeatures::" . $codeGenerator->WK_lcfirst($signature->extendedAttributes->{"EnabledAtRuntime"}) . "Enabled" if ($signature->extendedAttributes->{"EnabledAtRuntime"} && $signature->extendedAttributes->{"EnabledAtRuntime"} ne "1");
3289
3290    # Otherwise return a function named RuntimeEnabledFeatures::{methodName}Enabled().
3291    return "RuntimeEnabledFeatures::" . $codeGenerator->WK_lcfirst($signature->name) . "Enabled";
3292}
3293
3294sub DebugPrint
3295{
3296    my $output = shift;
3297
3298    print $output;
3299    print "\n";
3300}
3301