• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#
2# Copyright (C) 2005, 2006, 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org>
3# Copyright (C) 2006 Anders Carlsson <andersca@mac.com>
4# Copyright (C) 2006, 2007 Samuel Weinig <sam@webkit.org>
5# Copyright (C) 2006 Alexey Proskuryakov <ap@webkit.org>
6# Copyright (C) 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
7# Copyright (C) 2009 Cameron McCormack <cam@mcc.id.au>
8# Copyright (C) Research In Motion Limited 2010. All rights reserved.
9# 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., 51 Franklin Street, Fifth Floor,
24# Boston, MA 02110-1301, USA.
25
26package CodeGeneratorJS;
27
28my $module = "";
29my $outputDir = "";
30my $writeDependencies = 0;
31
32my @headerContentHeader = ();
33my @headerContent = ();
34my %headerIncludes = ();
35my %headerTrailingIncludes = ();
36
37my @implContentHeader = ();
38my @implContent = ();
39my %implIncludes = ();
40my @depsContent = ();
41my $numCachedAttributes = 0;
42my $currentCachedAttribute = 0;
43
44# Default .h template
45my $headerTemplate = << "EOF";
46/*
47    This file is part of the WebKit open source project.
48    This file has been generated by generate-bindings.pl. DO NOT MODIFY!
49
50    This library is free software; you can redistribute it and/or
51    modify it under the terms of the GNU Library General Public
52    License as published by the Free Software Foundation; either
53    version 2 of the License, or (at your option) any later version.
54
55    This library is distributed in the hope that it will be useful,
56    but WITHOUT ANY WARRANTY; without even the implied warranty of
57    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
58    Library General Public License for more details.
59
60    You should have received a copy of the GNU Library General Public License
61    along with this library; see the file COPYING.LIB.  If not, write to
62    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
63    Boston, MA 02110-1301, USA.
64*/
65EOF
66
67# Default constructor
68sub new
69{
70    my $object = shift;
71    my $reference = { };
72
73    $codeGenerator = shift;
74    $outputDir = shift;
75    shift; # $outputHeadersDir
76    shift; # $useLayerOnTop
77    shift; # $preprocessor
78    $writeDependencies = shift;
79
80    bless($reference, $object);
81    return $reference;
82}
83
84sub finish
85{
86    my $object = shift;
87
88    # Commit changes!
89    $object->WriteData();
90}
91
92sub leftShift($$) {
93    my ($value, $distance) = @_;
94    return (($value << $distance) & 0xFFFFFFFF);
95}
96
97# Params: 'domClass' struct
98sub GenerateInterface
99{
100    my $object = shift;
101    my $dataNode = shift;
102    my $defines = shift;
103
104    $codeGenerator->LinkOverloadedFunctions($dataNode);
105
106    # Start actual generation
107    if ($dataNode->extendedAttributes->{"Callback"}) {
108        $object->GenerateCallbackHeader($dataNode);
109        $object->GenerateCallbackImplementation($dataNode);
110    } else {
111        $object->GenerateHeader($dataNode);
112        $object->GenerateImplementation($dataNode);
113    }
114
115    my $name = $dataNode->name;
116
117    # Open files for writing
118    my $headerFileName = "$outputDir/JS$name.h";
119    my $implFileName = "$outputDir/JS$name.cpp";
120    my $depsFileName = "$outputDir/JS$name.dep";
121
122    # Remove old dependency file.
123    unlink($depsFileName);
124
125    open($IMPL, ">$implFileName") || die "Couldn't open file $implFileName";
126    open($HEADER, ">$headerFileName") || die "Couldn't open file $headerFileName";
127    if (@depsContent) {
128        open($DEPS, ">$depsFileName") || die "Couldn't open file $depsFileName";
129    }
130}
131
132sub GenerateAttributeEventListenerCall
133{
134    my $className = shift;
135    my $implSetterFunctionName = shift;
136    my $windowEventListener = shift;
137
138    my $wrapperObject = $windowEventListener ? "globalObject" : "thisObject";
139    my @GenerateEventListenerImpl = ();
140
141    if ($className eq "JSSVGElementInstance") {
142        # SVGElementInstances have to create JSEventListeners with the wrapper equal to the correspondingElement
143        $wrapperObject = "asObject(correspondingElementWrapper)";
144
145        push(@GenerateEventListenerImpl, <<END);
146    JSValue correspondingElementWrapper = toJS(exec, imp->correspondingElement());
147    if (correspondingElementWrapper.isObject())
148END
149
150        # Add leading whitespace to format the imp->set... line correctly
151        push(@GenerateEventListenerImpl, "    ");
152    }
153
154    push(@GenerateEventListenerImpl, "    imp->set$implSetterFunctionName(createJSAttributeEventListener(exec, value, $wrapperObject));\n");
155    return @GenerateEventListenerImpl;
156}
157
158sub GenerateEventListenerCall
159{
160    my $className = shift;
161    my $functionName = shift;
162    my $passRefPtrHandling = ($functionName eq "add") ? "" : ".get()";
163
164    $implIncludes{"JSEventListener.h"} = 1;
165
166    my @GenerateEventListenerImpl = ();
167    my $wrapperObject = "castedThis";
168    if ($className eq "JSSVGElementInstance") {
169        # SVGElementInstances have to create JSEventListeners with the wrapper equal to the correspondingElement
170        $wrapperObject = "asObject(correspondingElementWrapper)";
171
172        push(@GenerateEventListenerImpl, <<END);
173    JSValue correspondingElementWrapper = toJS(exec, imp->correspondingElement());
174    if (!correspondingElementWrapper.isObject())
175        return JSValue::encode(jsUndefined());
176END
177    }
178
179    push(@GenerateEventListenerImpl, <<END);
180    JSValue listener = exec->argument(1);
181    if (!listener.isObject())
182        return JSValue::encode(jsUndefined());
183    imp->${functionName}EventListener(ustringToAtomicString(exec->argument(0).toString(exec)), JSEventListener::create(asObject(listener), $wrapperObject, false, currentWorld(exec))$passRefPtrHandling, exec->argument(2).toBoolean(exec));
184    return JSValue::encode(jsUndefined());
185END
186    return @GenerateEventListenerImpl;
187}
188
189# Params: 'idlDocument' struct
190sub GenerateModule
191{
192    my $object = shift;
193    my $dataNode = shift;
194
195    $module = $dataNode->module;
196}
197
198sub GetParentClassName
199{
200    my $dataNode = shift;
201
202    return $dataNode->extendedAttributes->{"LegacyParent"} if $dataNode->extendedAttributes->{"LegacyParent"};
203    return "JSDOMWrapperWithGlobalPointer" if (@{$dataNode->parents} eq 0);
204    return "JS" . $codeGenerator->StripModule($dataNode->parents(0));
205}
206
207sub GetVisibleClassName
208{
209    my $className = shift;
210
211    return "DOMException" if $className eq "DOMCoreException";
212    return "FormData" if $className eq "DOMFormData";
213    return "MimeType" if $className eq "DOMMimeType";
214    return "MimeTypeArray" if $className eq "DOMMimeTypeArray";
215    return "Plugin" if $className eq "DOMPlugin";
216    return "PluginArray" if $className eq "DOMPluginArray";
217
218    return $className;
219}
220
221sub GetCallbackClassName
222{
223    my $className = shift;
224
225    return "JSCustomVoidCallback" if $className eq "VoidCallback";
226    return "JS$className";
227}
228
229sub IndexGetterReturnsStrings
230{
231    my $type = shift;
232
233    return 1 if $type eq "CSSStyleDeclaration" or $type eq "MediaList" or $type eq "DOMStringList" or $type eq "DOMTokenList" or $type eq "DOMSettableTokenList";
234    return 0;
235}
236
237sub AddIncludesForType
238{
239    my $type = $codeGenerator->StripModule(shift);
240    my $isCallback = @_ ? shift : 0;
241
242    # When we're finished with the one-file-per-class
243    # reorganization, we won't need these special cases.
244    if ($codeGenerator->IsPrimitiveType($type) or $codeGenerator->AvoidInclusionOfType($type)
245        or $type eq "DOMString" or $type eq "DOMObject" or $type eq "Array") {
246    } elsif ($type =~ /SVGPathSeg/) {
247        $joinedName = $type;
248        $joinedName =~ s/Abs|Rel//;
249        $implIncludes{"${joinedName}.h"} = 1;
250    } elsif ($type eq "XPathNSResolver") {
251        $implIncludes{"JSXPathNSResolver.h"} = 1;
252        $implIncludes{"JSCustomXPathNSResolver.h"} = 1;
253    } elsif ($isCallback) {
254        $implIncludes{"JS${type}.h"} = 1;
255    } else {
256        # default, include the same named file
257        $implIncludes{"${type}.h"} = 1;
258    }
259
260    # additional includes (things needed to compile the bindings but not the header)
261
262    if ($type eq "CanvasRenderingContext2D") {
263        $implIncludes{"CanvasGradient.h"} = 1;
264        $implIncludes{"CanvasPattern.h"} = 1;
265        $implIncludes{"CanvasStyle.h"} = 1;
266    }
267
268    if ($type eq "CanvasGradient" or $type eq "XPathNSResolver" or $type eq "MessagePort") {
269        $implIncludes{"PlatformString.h"} = 1;
270    }
271
272    if ($type eq "Document") {
273        $implIncludes{"NodeFilter.h"} = 1;
274    }
275
276    if ($type eq "MediaQueryListListener") {
277        $implIncludes{"MediaQueryListListener.h"} = 1;
278    }
279}
280
281# FIXME: This method will go away once all SVG animated properties are converted to the new scheme.
282sub AddIncludesForSVGAnimatedType
283{
284    my $type = shift;
285    $type =~ s/SVGAnimated//;
286
287    if ($type eq "Point" or $type eq "Rect") {
288        $implIncludes{"Float$type.h"} = 1;
289    } elsif ($type eq "String") {
290        $implIncludes{"PlatformString.h"} = 1;
291    }
292}
293
294sub IsScriptProfileType
295{
296    my $type = shift;
297    return 1 if ($type eq "ScriptProfileNode");
298    return 0;
299}
300
301sub AddTypedefForScriptProfileType
302{
303    my $type = shift;
304    (my $jscType = $type) =~ s/Script//;
305
306    push(@headerContent, "typedef JSC::$jscType $type;\n\n");
307}
308
309sub AddClassForwardIfNeeded
310{
311    my $implClassName = shift;
312
313    # SVGAnimatedLength/Number/etc. are typedefs to SVGAnimatedTemplate, so don't use class forwards for them!
314    unless ($codeGenerator->IsSVGAnimatedType($implClassName) or IsScriptProfileType($implClassName)) {
315        push(@headerContent, "class $implClassName;\n\n");
316    # ScriptProfile and ScriptProfileNode are typedefs to JSC::Profile and JSC::ProfileNode.
317    } elsif (IsScriptProfileType($implClassName)) {
318        AddTypedefForScriptProfileType($implClassName);
319    }
320}
321
322sub HashValueForClassAndName
323{
324    my $class = shift;
325    my $name = shift;
326
327    # SVG Filter enums live in WebCore namespace (platform/graphics/)
328    if ($class =~ /^SVGFE*/ or $class =~ /^SVGComponentTransferFunctionElement$/) {
329        return "WebCore::$name";
330    }
331
332    return "${class}::$name";
333}
334
335sub hashTableAccessor
336{
337    my $noStaticTables = shift;
338    my $className = shift;
339    if ($noStaticTables) {
340        return "get${className}Table(exec)";
341    } else {
342        return "&${className}Table";
343    }
344}
345
346sub prototypeHashTableAccessor
347{
348    my $noStaticTables = shift;
349    my $className = shift;
350    if ($noStaticTables) {
351        return "get${className}PrototypeTable(exec)";
352    } else {
353        return "&${className}PrototypeTable";
354    }
355}
356
357sub GenerateConditionalStringFromAttributeValue
358{
359    my $conditional = shift;
360    if ($conditional =~ /&/) {
361        return "ENABLE(" . join(") && ENABLE(", split(/&/, $conditional)) . ")";
362    } elsif ($conditional =~ /\|/) {
363        return "ENABLE(" . join(") || ENABLE(", split(/\|/, $conditional)) . ")";
364    } else {
365        return "ENABLE(" . $conditional . ")";
366    }
367}
368
369sub GenerateConditionalString
370{
371    my $node = shift;
372    my $conditional = $node->extendedAttributes->{"Conditional"};
373    if ($conditional) {
374        return GenerateConditionalStringFromAttributeValue($conditional);
375    } else {
376        return "";
377    }
378}
379
380sub GenerateGetOwnPropertySlotBody
381{
382    my ($dataNode, $interfaceName, $className, $implClassName, $hasAttributes, $inlined) = @_;
383
384    my $namespaceMaybe = ($inlined ? "JSC::" : "");
385
386    my @getOwnPropertySlotImpl = ();
387
388    if ($interfaceName eq "NamedNodeMap" or $interfaceName eq "HTMLCollection" or $interfaceName eq "HTMLAllCollection") {
389        push(@getOwnPropertySlotImpl, "    ${namespaceMaybe}JSValue proto = prototype();\n");
390        push(@getOwnPropertySlotImpl, "    if (proto.isObject() && static_cast<${namespaceMaybe}JSObject*>(asObject(proto))->hasProperty(exec, propertyName))\n");
391        push(@getOwnPropertySlotImpl, "        return false;\n\n");
392    }
393
394    my $manualLookupGetterGeneration = sub {
395        my $requiresManualLookup = $dataNode->extendedAttributes->{"HasIndexGetter"} || $dataNode->extendedAttributes->{"HasNameGetter"};
396        if ($requiresManualLookup) {
397            push(@getOwnPropertySlotImpl, "    const ${namespaceMaybe}HashEntry* entry = ${className}Table.entry(exec, propertyName);\n");
398            push(@getOwnPropertySlotImpl, "    if (entry) {\n");
399            push(@getOwnPropertySlotImpl, "        slot.setCustom(this, entry->propertyGetter());\n");
400            push(@getOwnPropertySlotImpl, "        return true;\n");
401            push(@getOwnPropertySlotImpl, "    }\n");
402        }
403    };
404
405    if (!$dataNode->extendedAttributes->{"HasOverridingNameGetter"}) {
406        &$manualLookupGetterGeneration();
407    }
408
409    if ($dataNode->extendedAttributes->{"HasIndexGetter"} || $dataNode->extendedAttributes->{"HasCustomIndexGetter"} || $dataNode->extendedAttributes->{"HasNumericIndexGetter"}) {
410        push(@getOwnPropertySlotImpl, "    bool ok;\n");
411        push(@getOwnPropertySlotImpl, "    unsigned index = propertyName.toUInt32(ok);\n");
412
413        # If the item function returns a string then we let the ConvertNullStringTo handle the cases
414        # where the index is out of range.
415        if (IndexGetterReturnsStrings($implClassName)) {
416            push(@getOwnPropertySlotImpl, "    if (ok) {\n");
417        } else {
418            push(@getOwnPropertySlotImpl, "    if (ok && index < static_cast<$implClassName*>(impl())->length()) {\n");
419        }
420        if ($dataNode->extendedAttributes->{"HasCustomIndexGetter"} || $dataNode->extendedAttributes->{"HasNumericIndexGetter"}) {
421            push(@getOwnPropertySlotImpl, "        slot.setValue(getByIndex(exec, index));\n");
422        } else {
423            push(@getOwnPropertySlotImpl, "        slot.setCustomIndex(this, index, indexGetter);\n");
424        }
425        push(@getOwnPropertySlotImpl, "        return true;\n");
426        push(@getOwnPropertySlotImpl, "    }\n");
427    }
428
429    if ($dataNode->extendedAttributes->{"HasNameGetter"} || $dataNode->extendedAttributes->{"HasOverridingNameGetter"}) {
430        push(@getOwnPropertySlotImpl, "    if (canGetItemsForName(exec, static_cast<$implClassName*>(impl()), propertyName)) {\n");
431        push(@getOwnPropertySlotImpl, "        slot.setCustom(this, nameGetter);\n");
432        push(@getOwnPropertySlotImpl, "        return true;\n");
433        push(@getOwnPropertySlotImpl, "    }\n");
434        if ($inlined) {
435            $headerIncludes{"wtf/text/AtomicString.h"} = 1;
436        } else {
437            $implIncludes{"wtf/text/AtomicString.h"} = 1;
438        }
439    }
440
441    if ($dataNode->extendedAttributes->{"HasOverridingNameGetter"}) {
442        &$manualLookupGetterGeneration();
443    }
444
445    if ($dataNode->extendedAttributes->{"DelegatingGetOwnPropertySlot"}) {
446        push(@getOwnPropertySlotImpl, "    if (getOwnPropertySlotDelegate(exec, propertyName, slot))\n");
447        push(@getOwnPropertySlotImpl, "        return true;\n");
448    }
449
450    if ($hasAttributes) {
451        if ($inlined) {
452            die "Cannot inline if NoStaticTables is set." if ($dataNode->extendedAttributes->{"NoStaticTables"});
453            push(@getOwnPropertySlotImpl, "    return ${namespaceMaybe}getStaticValueSlot<$className, Base>(exec, s_info.staticPropHashTable, this, propertyName, slot);\n");
454        } else {
455            push(@getOwnPropertySlotImpl, "    return ${namespaceMaybe}getStaticValueSlot<$className, Base>(exec, " . hashTableAccessor($dataNode->extendedAttributes->{"NoStaticTables"}, $className) . ", this, propertyName, slot);\n");
456        }
457    } else {
458        push(@getOwnPropertySlotImpl, "    return Base::getOwnPropertySlot(exec, propertyName, slot);\n");
459    }
460
461    return @getOwnPropertySlotImpl;
462}
463
464sub GenerateGetOwnPropertyDescriptorBody
465{
466    my ($dataNode, $interfaceName, $className, $implClassName, $hasAttributes, $inlined) = @_;
467
468    my $namespaceMaybe = ($inlined ? "JSC::" : "");
469
470    my @getOwnPropertyDescriptorImpl = ();
471    if ($dataNode->extendedAttributes->{"CheckDomainSecurity"}) {
472        if ($interfaceName eq "DOMWindow") {
473            push(@implContent, "    if (!static_cast<$className*>(thisObject)->allowsAccessFrom(exec))\n");
474        } else {
475            push(@implContent, "    if (!allowsAccessFromFrame(exec, static_cast<$className*>(thisObject)->impl()->frame()))\n");
476        }
477        push(@implContent, "        return false;\n");
478    }
479
480    if ($interfaceName eq "NamedNodeMap" or $interfaceName eq "HTMLCollection" or $interfaceName eq "HTMLAllCollection") {
481        push(@getOwnPropertyDescriptorImpl, "    ${namespaceMaybe}JSValue proto = prototype();\n");
482        push(@getOwnPropertyDescriptorImpl, "    if (proto.isObject() && static_cast<${namespaceMaybe}JSObject*>(asObject(proto))->hasProperty(exec, propertyName))\n");
483        push(@getOwnPropertyDescriptorImpl, "        return false;\n\n");
484    }
485
486    my $manualLookupGetterGeneration = sub {
487        my $requiresManualLookup = $dataNode->extendedAttributes->{"HasIndexGetter"} || $dataNode->extendedAttributes->{"HasNameGetter"};
488        if ($requiresManualLookup) {
489            push(@getOwnPropertyDescriptorImpl, "    const ${namespaceMaybe}HashEntry* entry = ${className}Table.entry(exec, propertyName);\n");
490            push(@getOwnPropertyDescriptorImpl, "    if (entry) {\n");
491            push(@getOwnPropertyDescriptorImpl, "        PropertySlot slot;\n");
492            push(@getOwnPropertyDescriptorImpl, "        slot.setCustom(this, entry->propertyGetter());\n");
493            push(@getOwnPropertyDescriptorImpl, "        descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());\n");
494            push(@getOwnPropertyDescriptorImpl, "        return true;\n");
495            push(@getOwnPropertyDescriptorImpl, "    }\n");
496        }
497    };
498
499    if (!$dataNode->extendedAttributes->{"HasOverridingNameGetter"}) {
500        &$manualLookupGetterGeneration();
501    }
502
503    if ($dataNode->extendedAttributes->{"HasIndexGetter"} || $dataNode->extendedAttributes->{"HasCustomIndexGetter"} || $dataNode->extendedAttributes->{"HasNumericIndexGetter"}) {
504        push(@getOwnPropertyDescriptorImpl, "    bool ok;\n");
505        push(@getOwnPropertyDescriptorImpl, "    unsigned index = propertyName.toUInt32(ok);\n");
506        push(@getOwnPropertyDescriptorImpl, "    if (ok && index < static_cast<$implClassName*>(impl())->length()) {\n");
507        if ($dataNode->extendedAttributes->{"HasCustomIndexGetter"} || $dataNode->extendedAttributes->{"HasNumericIndexGetter"}) {
508            # Assume that if there's a setter, the index will be writable
509            if ($dataNode->extendedAttributes->{"HasIndexSetter"} || $dataNode->extendedAttributes->{"HasCustomIndexSetter"}) {
510                push(@getOwnPropertyDescriptorImpl, "        descriptor.setDescriptor(getByIndex(exec, index), ${namespaceMaybe}DontDelete);\n");
511            } else {
512                push(@getOwnPropertyDescriptorImpl, "        descriptor.setDescriptor(getByIndex(exec, index), ${namespaceMaybe}DontDelete | ${namespaceMaybe}ReadOnly);\n");
513            }
514        } else {
515            push(@getOwnPropertyDescriptorImpl, "        ${namespaceMaybe}PropertySlot slot;\n");
516            push(@getOwnPropertyDescriptorImpl, "        slot.setCustomIndex(this, index, indexGetter);\n");
517            # Assume that if there's a setter, the index will be writable
518            if ($dataNode->extendedAttributes->{"HasIndexSetter"} || $dataNode->extendedAttributes->{"HasCustomIndexSetter"}) {
519                push(@getOwnPropertyDescriptorImpl, "        descriptor.setDescriptor(slot.getValue(exec, propertyName), ${namespaceMaybe}DontDelete);\n");
520            } else {
521                push(@getOwnPropertyDescriptorImpl, "        descriptor.setDescriptor(slot.getValue(exec, propertyName), ${namespaceMaybe}DontDelete | ${namespaceMaybe}ReadOnly);\n");
522            }
523        }
524        push(@getOwnPropertyDescriptorImpl, "        return true;\n");
525        push(@getOwnPropertyDescriptorImpl, "    }\n");
526    }
527
528    if ($dataNode->extendedAttributes->{"HasNameGetter"} || $dataNode->extendedAttributes->{"HasOverridingNameGetter"}) {
529        push(@getOwnPropertyDescriptorImpl, "    if (canGetItemsForName(exec, static_cast<$implClassName*>(impl()), propertyName)) {\n");
530        push(@getOwnPropertyDescriptorImpl, "        ${namespaceMaybe}PropertySlot slot;\n");
531        push(@getOwnPropertyDescriptorImpl, "        slot.setCustom(this, nameGetter);\n");
532        push(@getOwnPropertyDescriptorImpl, "        descriptor.setDescriptor(slot.getValue(exec, propertyName), ReadOnly | DontDelete | DontEnum);\n");
533        push(@getOwnPropertyDescriptorImpl, "        return true;\n");
534        push(@getOwnPropertyDescriptorImpl, "    }\n");
535        if ($inlined) {
536            $headerIncludes{"wtf/text/AtomicString.h"} = 1;
537        } else {
538            $implIncludes{"wtf/text/AtomicString.h"} = 1;
539        }
540    }
541
542    if ($dataNode->extendedAttributes->{"HasOverridingNameGetter"}) {
543        &$manualLookupGetterGeneration();
544    }
545
546    if ($dataNode->extendedAttributes->{"DelegatingGetOwnPropertySlot"}) {
547        push(@getOwnPropertyDescriptorImpl, "    if (getOwnPropertyDescriptorDelegate(exec, propertyName, descriptor))\n");
548        push(@getOwnPropertyDescriptorImpl, "        return true;\n");
549    }
550
551    if ($hasAttributes) {
552        if ($inlined) {
553            die "Cannot inline if NoStaticTables is set." if ($dataNode->extendedAttributes->{"NoStaticTables"});
554            push(@getOwnPropertyDescriptorImpl, "    return ${namespaceMaybe}getStaticValueDescriptor<$className, Base>(exec, s_info.staticPropHashTable, this, propertyName, descriptor);\n");
555        } else {
556            push(@getOwnPropertyDescriptorImpl, "    return ${namespaceMaybe}getStaticValueDescriptor<$className, Base>(exec, " . hashTableAccessor($dataNode->extendedAttributes->{"NoStaticTables"}, $className) . ", this, propertyName, descriptor);\n");
557        }
558    } else {
559        push(@getOwnPropertyDescriptorImpl, "    return Base::getOwnPropertyDescriptor(exec, propertyName, descriptor);\n");
560    }
561
562    return @getOwnPropertyDescriptorImpl;
563}
564
565sub GenerateHeaderContentHeader
566{
567    my $dataNode = shift;
568    my $className = "JS" . $dataNode->name;
569
570    my @headerContentHeader = split("\r", $headerTemplate);
571
572    # - Add header protection
573    push(@headerContentHeader, "\n#ifndef $className" . "_h");
574    push(@headerContentHeader, "\n#define $className" . "_h\n\n");
575
576    my $conditionalString = GenerateConditionalString($dataNode);
577    push(@headerContentHeader, "#if ${conditionalString}\n\n") if $conditionalString;
578    return @headerContentHeader;
579}
580
581sub GenerateImplementationContentHeader
582{
583    my $dataNode = shift;
584    my $className = "JS" . $dataNode->name;
585
586    my @implContentHeader = split("\r", $headerTemplate);
587
588    push(@implContentHeader, "\n#include \"config.h\"\n");
589    my $conditionalString = GenerateConditionalString($dataNode);
590    push(@implContentHeader, "\n#if ${conditionalString}\n\n") if $conditionalString;
591    push(@implContentHeader, "#include \"$className.h\"\n\n");
592    return @implContentHeader;
593}
594
595my %usesToJSNewlyCreated = (
596    "CDATASection" => 1,
597    "Element" => 1,
598    "Node" => 1,
599    "Text" => 1,
600    "Touch" => 1,
601    "TouchList" => 1
602);
603
604sub GenerateHeader
605{
606    my $object = shift;
607    my $dataNode = shift;
608
609    my $interfaceName = $dataNode->name;
610    my $className = "JS$interfaceName";
611    my $implClassName = $interfaceName;
612    my @ancestorInterfaceNames = ();
613    my %structureFlags = ();
614
615    # We only support multiple parents with SVG (for now).
616    if (@{$dataNode->parents} > 1) {
617        die "A class can't have more than one parent" unless $interfaceName =~ /SVG/;
618        $codeGenerator->AddMethodsConstantsAndAttributesFromParentClasses($dataNode, \@ancestorInterfaceNames);
619    }
620
621    my $hasLegacyParent = $dataNode->extendedAttributes->{"LegacyParent"};
622    my $hasRealParent = @{$dataNode->parents} > 0;
623    my $hasParent = $hasLegacyParent || $hasRealParent;
624    my $parentClassName = GetParentClassName($dataNode);
625    my $eventTarget = $dataNode->extendedAttributes->{"EventTarget"};
626    my $needsMarkChildren = $dataNode->extendedAttributes->{"CustomMarkFunction"} || $dataNode->extendedAttributes->{"EventTarget"};
627
628    # - Add default header template and header protection
629    push(@headerContentHeader, GenerateHeaderContentHeader($dataNode));
630
631    if ($hasParent) {
632        $headerIncludes{"$parentClassName.h"} = 1;
633    } else {
634        $headerIncludes{"JSDOMBinding.h"} = 1;
635        $headerIncludes{"<runtime/JSGlobalObject.h>"} = 1;
636        $headerIncludes{"<runtime/ObjectPrototype.h>"} = 1;
637    }
638
639    if ($dataNode->extendedAttributes->{"CustomCall"}) {
640        $headerIncludes{"<runtime/CallData.h>"} = 1;
641    }
642
643    if ($dataNode->extendedAttributes->{"InlineGetOwnPropertySlot"}) {
644        $headerIncludes{"<runtime/Lookup.h>"} = 1;
645        $headerIncludes{"<wtf/AlwaysInline.h>"} = 1;
646    }
647
648    if ($hasParent && $dataNode->extendedAttributes->{"GenerateNativeConverter"}) {
649        $headerIncludes{"$implClassName.h"} = 1;
650    }
651
652    $headerIncludes{"<runtime/JSObjectWithGlobalObject.h>"} = 1;
653    $headerIncludes{"SVGElement.h"} = 1 if $className =~ /^JSSVG/;
654
655    my $implType = $implClassName;
656    my ($svgPropertyType, $svgListPropertyType, $svgNativeType) = GetSVGPropertyTypes($implType);
657    $implType = $svgNativeType if $svgNativeType;
658
659    my $svgPropertyOrListPropertyType;
660    $svgPropertyOrListPropertyType = $svgPropertyType if $svgPropertyType;
661    $svgPropertyOrListPropertyType = $svgListPropertyType if $svgListPropertyType;
662
663    my $numConstants = @{$dataNode->constants};
664    my $numAttributes = @{$dataNode->attributes};
665    my $numFunctions = @{$dataNode->functions};
666
667    push(@headerContent, "\nnamespace WebCore {\n\n");
668
669    if ($codeGenerator->IsSVGAnimatedType($implClassName)) {
670        $headerIncludes{"$implClassName.h"} = 1;
671    } else {
672        # Implementation class forward declaration
673        AddClassForwardIfNeeded($implClassName) unless $svgPropertyOrListPropertyType;
674    }
675
676    AddClassForwardIfNeeded("JSDOMWindowShell") if $interfaceName eq "DOMWindow";
677
678    # Class declaration
679    push(@headerContent, "class $className : public $parentClassName {\n");
680    push(@headerContent, "    typedef $parentClassName Base;\n");
681    push(@headerContent, "public:\n");
682
683    # Constructor
684    if ($interfaceName eq "DOMWindow") {
685        push(@headerContent, "    $className(JSC::JSGlobalData&, JSC::Structure*, PassRefPtr<$implType>, JSDOMWindowShell*);\n");
686    } elsif ($dataNode->extendedAttributes->{"IsWorkerContext"}) {
687        push(@headerContent, "    $className(JSC::JSGlobalData&, JSC::Structure*, PassRefPtr<$implType>);\n");
688    } else {
689        push(@headerContent, "    $className(JSC::Structure*, JSDOMGlobalObject*, PassRefPtr<$implType>);\n");
690    }
691
692    # Prototype
693    push(@headerContent, "    static JSC::JSObject* createPrototype(JSC::ExecState*, JSC::JSGlobalObject*);\n") unless ($dataNode->extendedAttributes->{"ExtendsDOMGlobalObject"});
694
695    $headerTrailingIncludes{"${className}Custom.h"} = 1 if $dataNode->extendedAttributes->{"CustomHeader"};
696
697    $implIncludes{"${className}Custom.h"} = 1 if !$dataNode->extendedAttributes->{"CustomHeader"} && ($dataNode->extendedAttributes->{"CustomPutFunction"} || $dataNode->extendedAttributes->{"DelegatingPutFunction"});
698
699    my $hasGetter = $numAttributes > 0
700                 || !($dataNode->extendedAttributes->{"OmitConstructor"}
701                 || $dataNode->extendedAttributes->{"CustomConstructor"})
702                 || $dataNode->extendedAttributes->{"HasIndexGetter"}
703                 || $dataNode->extendedAttributes->{"HasCustomIndexGetter"}
704                 || $dataNode->extendedAttributes->{"HasNumericIndexGetter"}
705                 || $dataNode->extendedAttributes->{"CustomGetOwnPropertySlot"}
706                 || $dataNode->extendedAttributes->{"DelegatingGetOwnPropertySlot"}
707                 || $dataNode->extendedAttributes->{"HasNameGetter"}
708                 || $dataNode->extendedAttributes->{"HasOverridingNameGetter"};
709
710    # Getters
711    if ($hasGetter) {
712        push(@headerContent, "    virtual bool getOwnPropertySlot(JSC::ExecState*, const JSC::Identifier& propertyName, JSC::PropertySlot&);\n");
713        push(@headerContent, "    virtual bool getOwnPropertyDescriptor(JSC::ExecState*, const JSC::Identifier& propertyName, JSC::PropertyDescriptor&);\n");
714        push(@headerContent, "    virtual bool getOwnPropertySlot(JSC::ExecState*, unsigned propertyName, JSC::PropertySlot&);\n") if ($dataNode->extendedAttributes->{"HasIndexGetter"} || $dataNode->extendedAttributes->{"HasCustomIndexGetter"} || $dataNode->extendedAttributes->{"HasNumericIndexGetter"}) && !$dataNode->extendedAttributes->{"HasOverridingNameGetter"};
715        push(@headerContent, "    bool getOwnPropertySlotDelegate(JSC::ExecState*, const JSC::Identifier&, JSC::PropertySlot&);\n") if $dataNode->extendedAttributes->{"DelegatingGetOwnPropertySlot"};
716        push(@headerContent, "    bool getOwnPropertyDescriptorDelegate(JSC::ExecState*, const JSC::Identifier&, JSC::PropertyDescriptor&);\n") if $dataNode->extendedAttributes->{"DelegatingGetOwnPropertySlot"};
717        $structureFlags{"JSC::OverridesGetOwnPropertySlot"} = 1;
718    }
719
720    # Check if we have any writable properties
721    my $hasReadWriteProperties = 0;
722    foreach (@{$dataNode->attributes}) {
723        if ($_->type !~ /^readonly\ attribute$/) {
724            $hasReadWriteProperties = 1;
725        }
726    }
727
728    my $hasSetter = $hasReadWriteProperties
729                 || $dataNode->extendedAttributes->{"CustomPutFunction"}
730                 || $dataNode->extendedAttributes->{"DelegatingPutFunction"}
731                 || $dataNode->extendedAttributes->{"HasCustomIndexSetter"};
732
733    # Getters
734    if ($hasSetter) {
735        push(@headerContent, "    virtual void put(JSC::ExecState*, const JSC::Identifier& propertyName, JSC::JSValue, JSC::PutPropertySlot&);\n");
736        push(@headerContent, "    virtual void put(JSC::ExecState*, unsigned propertyName, JSC::JSValue);\n") if $dataNode->extendedAttributes->{"HasCustomIndexSetter"};
737        push(@headerContent, "    bool putDelegate(JSC::ExecState*, const JSC::Identifier&, JSC::JSValue, JSC::PutPropertySlot&);\n") if $dataNode->extendedAttributes->{"DelegatingPutFunction"};
738    }
739
740    # Class info
741    push(@headerContent, "    static const JSC::ClassInfo s_info;\n\n");
742
743    # Structure ID
744    if ($interfaceName eq "DOMWindow") {
745        $structureFlags{"JSC::ImplementsHasInstance"} = 1;
746        $structureFlags{"JSC::NeedsThisConversion"} = 1;
747    }
748    push(@headerContent,
749        "    static JSC::Structure* createStructure(JSC::JSGlobalData& globalData, JSC::JSValue prototype)\n" .
750        "    {\n" .
751        "        return JSC::Structure::create(globalData, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), AnonymousSlotCount, &s_info);\n" .
752        "    }\n\n");
753
754    # markChildren function
755    if ($needsMarkChildren) {
756        push(@headerContent, "    virtual void markChildren(JSC::MarkStack&);\n\n");
757        $structureFlags{"JSC::OverridesMarkChildren"} = 1;
758    }
759
760    # Custom pushEventHandlerScope function
761    push(@headerContent, "    virtual JSC::ScopeChainNode* pushEventHandlerScope(JSC::ExecState*, JSC::ScopeChainNode*) const;\n\n") if $dataNode->extendedAttributes->{"CustomPushEventHandlerScope"};
762
763    # Custom call functions
764    push(@headerContent, "    virtual JSC::CallType getCallData(JSC::CallData&);\n\n") if $dataNode->extendedAttributes->{"CustomCall"};
765
766    # Custom deleteProperty function
767    push(@headerContent, "    virtual bool deleteProperty(JSC::ExecState*, const JSC::Identifier&);\n") if $dataNode->extendedAttributes->{"CustomDeleteProperty"};
768
769    # Custom getPropertyNames function exists on DOMWindow
770    if ($interfaceName eq "DOMWindow") {
771        push(@headerContent, "    virtual void getPropertyNames(JSC::ExecState*, JSC::PropertyNameArray&, JSC::EnumerationMode mode = JSC::ExcludeDontEnumProperties);\n");
772        $structureFlags{"JSC::OverridesGetPropertyNames"} = 1;
773    }
774
775    # Custom defineProperty function exists on DOMWindow
776    push(@headerContent, "    virtual bool defineOwnProperty(JSC::ExecState*, const JSC::Identifier& propertyName, JSC::PropertyDescriptor&, bool shouldThrow);\n") if $interfaceName eq "DOMWindow";
777
778    # Custom getOwnPropertyNames function
779    if ($dataNode->extendedAttributes->{"CustomGetPropertyNames"} || $dataNode->extendedAttributes->{"HasIndexGetter"} || $dataNode->extendedAttributes->{"HasCustomIndexGetter"} || $dataNode->extendedAttributes->{"HasNumericIndexGetter"}) {
780        push(@headerContent, "    virtual void getOwnPropertyNames(JSC::ExecState*, JSC::PropertyNameArray&, JSC::EnumerationMode mode = JSC::ExcludeDontEnumProperties);\n");
781        $structureFlags{"JSC::OverridesGetPropertyNames"} = 1;
782    }
783
784    # Custom defineGetter function
785    push(@headerContent, "    virtual void defineGetter(JSC::ExecState*, const JSC::Identifier& propertyName, JSC::JSObject* getterFunction, unsigned attributes);\n") if $dataNode->extendedAttributes->{"CustomDefineGetter"};
786
787    # Custom defineSetter function
788    push(@headerContent, "    virtual void defineSetter(JSC::ExecState*, const JSC::Identifier& propertyName, JSC::JSObject* setterFunction, unsigned attributes);\n") if $dataNode->extendedAttributes->{"CustomDefineSetter"};
789
790    # Custom lookupGetter function
791    push(@headerContent, "    virtual JSC::JSValue lookupGetter(JSC::ExecState*, const JSC::Identifier& propertyName);\n") if $dataNode->extendedAttributes->{"CustomLookupGetter"};
792
793    # Custom lookupSetter function
794    push(@headerContent, "    virtual JSC::JSValue lookupSetter(JSC::ExecState*, const JSC::Identifier& propertyName);\n") if $dataNode->extendedAttributes->{"CustomLookupSetter"};
795
796    # Override toBoolean to return false for objects that want to 'MasqueradesAsUndefined'.
797    if ($dataNode->extendedAttributes->{"MasqueradesAsUndefined"}) {
798        push(@headerContent, "    virtual bool toBoolean(JSC::ExecState*) const { return false; };\n");
799        $structureFlags{"JSC::MasqueradesAsUndefined"} = 1;
800    }
801
802    # Constructor object getter
803    push(@headerContent, "    static JSC::JSValue getConstructor(JSC::ExecState*, JSC::JSGlobalObject*);\n") if (!($dataNode->extendedAttributes->{"OmitConstructor"} || $dataNode->extendedAttributes->{"CustomConstructor"}));
804
805    my $numCustomFunctions = 0;
806    my $numCustomAttributes = 0;
807
808    # Attribute and function enums
809    if ($numAttributes > 0) {
810        foreach (@{$dataNode->attributes}) {
811            my $attribute = $_;
812            $numCustomAttributes++ if $attribute->signature->extendedAttributes->{"Custom"} || $attribute->signature->extendedAttributes->{"JSCCustom"};
813            $numCustomAttributes++ if $attribute->signature->extendedAttributes->{"CustomGetter"} || $attribute->signature->extendedAttributes->{"JSCCustomGetter"};
814            $numCustomAttributes++ if $attribute->signature->extendedAttributes->{"CustomSetter"} || $attribute->signature->extendedAttributes->{"JSCCustomSetter"};
815            if ($attribute->signature->extendedAttributes->{"CachedAttribute"}) {
816                push(@headerContent, "    static const unsigned " . $attribute->signature->name . "Slot = $numCachedAttributes + Base::AnonymousSlotCount;\n");
817                $numCachedAttributes++;
818            }
819        }
820    }
821
822    if ($numCachedAttributes > 0) {
823        push(@headerContent, "    using $parentClassName" . "::putAnonymousValue;\n");
824        push(@headerContent, "    using $parentClassName" . "::getAnonymousValue;\n");
825    }
826    if ($numCustomAttributes > 0) {
827        push(@headerContent, "\n    // Custom attributes\n");
828
829        foreach my $attribute (@{$dataNode->attributes}) {
830            if ($attribute->signature->extendedAttributes->{"Custom"} || $attribute->signature->extendedAttributes->{"JSCCustom"}) {
831                push(@headerContent, "    JSC::JSValue " . $codeGenerator->WK_lcfirst($attribute->signature->name) . "(JSC::ExecState*) const;\n");
832                if ($attribute->type !~ /^readonly/) {
833                    push(@headerContent, "    void set" . $codeGenerator->WK_ucfirst($attribute->signature->name) . "(JSC::ExecState*, JSC::JSValue);\n");
834                }
835            } elsif ($attribute->signature->extendedAttributes->{"CustomGetter"} || $attribute->signature->extendedAttributes->{"JSCCustomGetter"}) {
836                push(@headerContent, "    JSC::JSValue " . $codeGenerator->WK_lcfirst($attribute->signature->name) . "(JSC::ExecState*) const;\n");
837            } elsif ($attribute->signature->extendedAttributes->{"CustomSetter"} || $attribute->signature->extendedAttributes->{"JSCCustomSetter"}) {
838                if ($attribute->type !~ /^readonly/) {
839                    push(@headerContent, "    void set" . $codeGenerator->WK_ucfirst($attribute->signature->name) . "(JSC::ExecState*, JSC::JSValue);\n");
840                }
841            }
842        }
843    }
844
845    foreach my $function (@{$dataNode->functions}) {
846        $numCustomFunctions++ if $function->signature->extendedAttributes->{"Custom"} || $function->signature->extendedAttributes->{"JSCCustom"};
847    }
848
849    if ($numCustomFunctions > 0) {
850        push(@headerContent, "\n    // Custom functions\n");
851        foreach my $function (@{$dataNode->functions}) {
852            if ($function->signature->extendedAttributes->{"Custom"} || $function->signature->extendedAttributes->{"JSCCustom"}) {
853                my $functionImplementationName = $function->signature->extendedAttributes->{"ImplementationFunction"} || $codeGenerator->WK_lcfirst($function->signature->name);
854                push(@headerContent, "    JSC::JSValue " . $functionImplementationName . "(JSC::ExecState*);\n");
855            }
856        }
857    }
858
859    if (!$hasParent) {
860        push(@headerContent, "    $implType* impl() const { return m_impl.get(); }\n\n");
861        push(@headerContent, "private:\n");
862        push(@headerContent, "    RefPtr<$implType> m_impl;\n");
863    } elsif ($dataNode->extendedAttributes->{"GenerateNativeConverter"}) {
864        push(@headerContent, "    $implClassName* impl() const\n");
865        push(@headerContent, "    {\n");
866        push(@headerContent, "        return static_cast<$implClassName*>(Base::impl());\n");
867        push(@headerContent, "    }\n");
868    }
869
870    # anonymous slots
871    if ($numCachedAttributes) {
872        push(@headerContent, "public:\n");
873        push(@headerContent, "    static const unsigned AnonymousSlotCount = $numCachedAttributes + Base::AnonymousSlotCount;\n");
874    }
875
876    # structure flags
877    push(@headerContent, "protected:\n");
878    push(@headerContent, "    static const unsigned StructureFlags = ");
879    foreach my $structureFlag (keys %structureFlags) {
880        push(@headerContent, $structureFlag . " | ");
881    }
882    push(@headerContent, "Base::StructureFlags;\n");
883
884    # Index getter
885    if ($dataNode->extendedAttributes->{"HasIndexGetter"}) {
886        push(@headerContent, "    static JSC::JSValue indexGetter(JSC::ExecState*, JSC::JSValue, unsigned);\n");
887    }
888    if ($dataNode->extendedAttributes->{"HasCustomIndexGetter"} || $dataNode->extendedAttributes->{"HasNumericIndexGetter"}) {
889        push(@headerContent, "    JSC::JSValue getByIndex(JSC::ExecState*, unsigned index);\n");
890
891    }
892
893    # Index setter
894    if ($dataNode->extendedAttributes->{"HasCustomIndexSetter"}) {
895        push(@headerContent, "    void indexSetter(JSC::ExecState*, unsigned index, JSC::JSValue);\n");
896    }
897    # Name getter
898    if ($dataNode->extendedAttributes->{"HasNameGetter"} || $dataNode->extendedAttributes->{"HasOverridingNameGetter"}) {
899        push(@headerContent, "private:\n");
900        push(@headerContent, "    static bool canGetItemsForName(JSC::ExecState*, $implClassName*, const JSC::Identifier&);\n");
901        push(@headerContent, "    static JSC::JSValue nameGetter(JSC::ExecState*, JSC::JSValue, const JSC::Identifier&);\n");
902    }
903
904    push(@headerContent, "};\n\n");
905
906    if ($dataNode->extendedAttributes->{"InlineGetOwnPropertySlot"} && !$dataNode->extendedAttributes->{"CustomGetOwnPropertySlot"}) {
907        push(@headerContent, "ALWAYS_INLINE bool ${className}::getOwnPropertySlot(JSC::ExecState* exec, const JSC::Identifier& propertyName, JSC::PropertySlot& slot)\n");
908        push(@headerContent, "{\n");
909        push(@headerContent, GenerateGetOwnPropertySlotBody($dataNode, $interfaceName, $className, $implClassName, $numAttributes > 0, 1));
910        push(@headerContent, "}\n\n");
911        push(@headerContent, "ALWAYS_INLINE bool ${className}::getOwnPropertyDescriptor(JSC::ExecState* exec, const JSC::Identifier& propertyName, JSC::PropertyDescriptor& descriptor)\n");
912        push(@headerContent, "{\n");
913        push(@headerContent, GenerateGetOwnPropertyDescriptorBody($dataNode, $interfaceName, $className, $implClassName, $numAttributes > 0, 1));
914        push(@headerContent, "}\n\n");
915    }
916
917    if (!$hasParent || $dataNode->extendedAttributes->{"GenerateToJS"} || $dataNode->extendedAttributes->{"CustomToJS"}) {
918        if ($svgPropertyType) {
919            push(@headerContent, "JSC::JSValue toJS(JSC::ExecState*, JSDOMGlobalObject*, $implType*);\n");
920        } else {
921            push(@headerContent, "JSC::JSValue toJS(JSC::ExecState*, JSDOMGlobalObject*, $implType*);\n");
922        }
923    }
924    if (!$hasParent || $dataNode->extendedAttributes->{"GenerateNativeConverter"}) {
925        if ($interfaceName eq "NodeFilter") {
926            push(@headerContent, "PassRefPtr<NodeFilter> toNodeFilter(JSC::JSGlobalData&, JSC::JSValue);\n");
927        } else {
928            push(@headerContent, "$implType* to${interfaceName}(JSC::JSValue);\n");
929        }
930    }
931    if ($usesToJSNewlyCreated{$interfaceName}) {
932        push(@headerContent, "JSC::JSValue toJSNewlyCreated(JSC::ExecState*, JSDOMGlobalObject*, $interfaceName*);\n");
933    }
934
935    push(@headerContent, "\n");
936
937    # Add prototype declaration.
938    %structureFlags = ();
939    push(@headerContent, "class ${className}Prototype : public JSC::JSObjectWithGlobalObject {\n");
940    push(@headerContent, "    typedef JSC::JSObjectWithGlobalObject Base;\n");
941    push(@headerContent, "public:\n");
942    if ($interfaceName eq "DOMWindow") {
943        push(@headerContent, "    void* operator new(size_t);\n");
944    } elsif ($dataNode->extendedAttributes->{"IsWorkerContext"}) {
945        push(@headerContent, "    void* operator new(size_t, JSC::JSGlobalData*);\n");
946    } else {
947        push(@headerContent, "    static JSC::JSObject* self(JSC::ExecState*, JSC::JSGlobalObject*);\n");
948    }
949    push(@headerContent, "    static const JSC::ClassInfo s_info;\n");
950    if ($numFunctions > 0 || $numConstants > 0 || $dataNode->extendedAttributes->{"DelegatingPrototypeGetOwnPropertySlot"}) {
951        push(@headerContent, "    virtual bool getOwnPropertySlot(JSC::ExecState*, const JSC::Identifier&, JSC::PropertySlot&);\n");
952        push(@headerContent, "    virtual bool getOwnPropertyDescriptor(JSC::ExecState*, const JSC::Identifier&, JSC::PropertyDescriptor&);\n");
953        push(@headerContent, "    bool getOwnPropertySlotDelegate(JSC::ExecState*, const JSC::Identifier&, JSC::PropertySlot&);\n") if $dataNode->extendedAttributes->{"DelegatingPrototypeGetOwnPropertySlot"};
954        push(@headerContent, "    bool getOwnPropertyDescriptorDelegate(JSC::ExecState*, const JSC::Identifier&, JSC::PropertyDescriptor&);\n") if $dataNode->extendedAttributes->{"DelegatingPrototypeGetOwnPropertySlot"};
955        $structureFlags{"JSC::OverridesGetOwnPropertySlot"} = 1;
956    }
957    if ($dataNode->extendedAttributes->{"CustomMarkFunction"} or $needsMarkChildren) {
958        $structureFlags{"JSC::OverridesMarkChildren"} = 1;
959    }
960    push(@headerContent,
961        "    static JSC::Structure* createStructure(JSC::JSGlobalData& globalData, JSC::JSValue prototype)\n" .
962        "    {\n" .
963        "        return JSC::Structure::create(globalData, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), AnonymousSlotCount, &s_info);\n" .
964        "    }\n");
965    if ($dataNode->extendedAttributes->{"DelegatingPrototypePutFunction"}) {
966        push(@headerContent, "    virtual void put(JSC::ExecState*, const JSC::Identifier& propertyName, JSC::JSValue, JSC::PutPropertySlot&);\n");
967        push(@headerContent, "    bool putDelegate(JSC::ExecState*, const JSC::Identifier&, JSC::JSValue, JSC::PutPropertySlot&);\n");
968    }
969
970    # Custom defineGetter function
971    push(@headerContent, "    virtual void defineGetter(JSC::ExecState*, const JSC::Identifier& propertyName, JSC::JSObject* getterFunction, unsigned attributes);\n") if $dataNode->extendedAttributes->{"CustomPrototypeDefineGetter"};
972
973    push(@headerContent, "    ${className}Prototype(JSC::JSGlobalData& globalData, JSC::JSGlobalObject* globalObject, JSC::Structure* structure) : JSC::JSObjectWithGlobalObject(globalData, globalObject, structure) { }\n");
974
975    # structure flags
976    push(@headerContent, "protected:\n");
977    push(@headerContent, "    static const unsigned StructureFlags = ");
978    foreach my $structureFlag (keys %structureFlags) {
979        push(@headerContent, $structureFlag . " | ");
980    }
981    push(@headerContent, "Base::StructureFlags;\n");
982
983    push(@headerContent, "};\n\n");
984
985    # Conditionally emit the constructor object's declaration
986    if ($dataNode->extendedAttributes->{"CustomConstructFunction"}) {
987        GenerateConstructorDeclaration(\@headerContent, $className, $dataNode);
988    }
989
990
991    if ($numFunctions > 0) {
992        push(@headerContent,"// Functions\n\n");
993        foreach my $function (@{$dataNode->functions}) {
994            next if $function->{overloadIndex} && $function->{overloadIndex} > 1;
995            my $functionName = $codeGenerator->WK_lcfirst($className) . "PrototypeFunction" . $codeGenerator->WK_ucfirst($function->signature->name);
996            push(@headerContent, "JSC::EncodedJSValue JSC_HOST_CALL ${functionName}(JSC::ExecState*);\n");
997        }
998    }
999
1000    if ($numAttributes > 0 || !($dataNode->extendedAttributes->{"OmitConstructor"} || $dataNode->extendedAttributes->{"CustomConstructor"})) {
1001        push(@headerContent,"// Attributes\n\n");
1002        foreach my $attribute (@{$dataNode->attributes}) {
1003            my $getter = "js" . $interfaceName . $codeGenerator->WK_ucfirst($attribute->signature->name) . ($attribute->signature->type =~ /Constructor$/ ? "Constructor" : "");
1004            push(@headerContent, "JSC::JSValue ${getter}(JSC::ExecState*, JSC::JSValue, const JSC::Identifier&);\n");
1005            unless ($attribute->type =~ /readonly/) {
1006                my $setter = "setJS" . $interfaceName . $codeGenerator->WK_ucfirst($attribute->signature->name) . ($attribute->signature->type =~ /Constructor$/ ? "Constructor" : "");
1007                push(@headerContent, "void ${setter}(JSC::ExecState*, JSC::JSObject*, JSC::JSValue);\n");
1008            }
1009        }
1010
1011        if (!($dataNode->extendedAttributes->{"OmitConstructor"} || $dataNode->extendedAttributes->{"CustomConstructor"})) {
1012            my $getter = "js" . $interfaceName . "Constructor";
1013            push(@headerContent, "JSC::JSValue ${getter}(JSC::ExecState*, JSC::JSValue, const JSC::Identifier&);\n");
1014        }
1015
1016        if ($dataNode->extendedAttributes->{"ReplaceableConstructor"}) {
1017            my $constructorFunctionName = "setJS" . $interfaceName . "Constructor";
1018            push(@headerContent, "void ${constructorFunctionName}(JSC::ExecState*, JSC::JSObject*, JSC::JSValue);\n");
1019        }
1020    }
1021
1022    if ($numConstants > 0) {
1023        push(@headerContent,"// Constants\n\n");
1024        foreach my $constant (@{$dataNode->constants}) {
1025            my $getter = "js" . $interfaceName . $codeGenerator->WK_ucfirst($constant->name);
1026            push(@headerContent, "JSC::JSValue ${getter}(JSC::ExecState*, JSC::JSValue, const JSC::Identifier&);\n");
1027        }
1028    }
1029
1030    my $conditionalString = GenerateConditionalString($dataNode);
1031    push(@headerContent, "\n} // namespace WebCore\n\n");
1032    push(@headerContent, "#endif // ${conditionalString}\n\n") if $conditionalString;
1033    push(@headerContent, "#endif\n");
1034
1035    # - Generate dependencies.
1036    if ($writeDependencies && @ancestorInterfaceNames) {
1037        push(@depsContent, "$className.h : ", join(" ", map { "$_.idl" } @ancestorInterfaceNames), "\n");
1038        push(@depsContent, map { "$_.idl :\n" } @ancestorInterfaceNames);
1039    }
1040}
1041
1042sub GenerateAttributesHashTable($$)
1043{
1044    my ($object, $dataNode) = @_;
1045
1046    # FIXME: These should be functions on $dataNode.
1047    my $interfaceName = $dataNode->name;
1048    my $className = "JS$interfaceName";
1049
1050    # - Add all attributes in a hashtable definition
1051    my $numAttributes = @{$dataNode->attributes};
1052    $numAttributes++ if (!($dataNode->extendedAttributes->{"OmitConstructor"} || $dataNode->extendedAttributes->{"CustomConstructor"}));
1053
1054    return 0  if !$numAttributes;
1055
1056    my $hashSize = $numAttributes;
1057    my $hashName = $className . "Table";
1058
1059    my @hashKeys = ();
1060    my @hashSpecials = ();
1061    my @hashValue1 = ();
1062    my @hashValue2 = ();
1063    my %conditionals = ();
1064
1065    my @entries = ();
1066
1067    foreach my $attribute (@{$dataNode->attributes}) {
1068        my $name = $attribute->signature->name;
1069        push(@hashKeys, $name);
1070
1071        my @specials = ();
1072        push(@specials, "DontDelete") unless $attribute->signature->extendedAttributes->{"Deletable"};
1073        push(@specials, "DontEnum") if $attribute->signature->extendedAttributes->{"DontEnum"};
1074        push(@specials, "ReadOnly") if $attribute->type =~ /readonly/;
1075        my $special = (@specials > 0) ? join(" | ", @specials) : "0";
1076        push(@hashSpecials, $special);
1077
1078        my $getter = "js" . $interfaceName . $codeGenerator->WK_ucfirst($attribute->signature->name) . ($attribute->signature->type =~ /Constructor$/ ? "Constructor" : "");
1079        push(@hashValue1, $getter);
1080
1081        if ($attribute->type =~ /readonly/) {
1082            push(@hashValue2, "0");
1083        } else {
1084            my $setter = "setJS" . $interfaceName . $codeGenerator->WK_ucfirst($attribute->signature->name) . ($attribute->signature->type =~ /Constructor$/ ? "Constructor" : "");
1085            push(@hashValue2, $setter);
1086        }
1087
1088        my $conditional = $attribute->signature->extendedAttributes->{"Conditional"};
1089        if ($conditional) {
1090            $conditionals{$name} = $conditional;
1091        }
1092    }
1093
1094    if (!($dataNode->extendedAttributes->{"OmitConstructor"} || $dataNode->extendedAttributes->{"CustomConstructor"})) {
1095        push(@hashKeys, "constructor");
1096        my $getter = "js" . $interfaceName . "Constructor";
1097        push(@hashValue1, $getter);
1098        if ($dataNode->extendedAttributes->{"ReplaceableConstructor"}) {
1099            my $setter = "setJS" . $interfaceName . "Constructor";
1100            push(@hashValue2, $setter);
1101            push(@hashSpecials, "DontEnum | DontDelete");
1102        } else {
1103            push(@hashValue2, "0");
1104            push(@hashSpecials, "DontEnum | ReadOnly");
1105        }
1106    }
1107
1108    $object->GenerateHashTable($hashName, $hashSize,
1109                               \@hashKeys, \@hashSpecials,
1110                               \@hashValue1, \@hashValue2,
1111                               \%conditionals);
1112    return $numAttributes;
1113}
1114
1115sub GenerateParametersCheckExpression
1116{
1117    my $numParameters = shift;
1118    my $function = shift;
1119
1120    my @andExpression = ();
1121    push(@andExpression, "exec->argumentCount() == $numParameters");
1122    my $parameterIndex = 0;
1123    foreach $parameter (@{$function->parameters}) {
1124        last if $parameterIndex >= $numParameters;
1125        my $value = "exec->argument($parameterIndex)";
1126        my $type = $codeGenerator->StripModule($parameter->type);
1127
1128        # Only DOMString or wrapper types are checked.
1129        # For DOMString, Null, Undefined and any Object are accepted too, as
1130        # these are acceptable values for a DOMString argument (any Object can
1131        # be converted to a string via .toString).
1132        if ($codeGenerator->IsStringType($type)) {
1133            push(@andExpression, "(${value}.isNull() || ${value}.isUndefined() || ${value}.isString() || ${value}.isObject())");
1134        } elsif ($parameter->extendedAttributes->{"Callback"}) {
1135            # For Callbacks only checks if the value is null or object.
1136            push(@andExpression, "(${value}.isNull() || ${value}.isObject())");
1137        } elsif (!IsNativeType($type)) {
1138            push(@andExpression, "(${value}.isNull() || (${value}.isObject() && asObject(${value})->inherits(&JS${type}::s_info)))");
1139        }
1140        $parameterIndex++;
1141    }
1142    my $res = join(" && ", @andExpression);
1143    $res = "($res)" if @andExpression > 1;
1144    return $res;
1145}
1146
1147sub GenerateFunctionParametersCheck
1148{
1149    my $function = shift;
1150
1151    my @orExpression = ();
1152    my $numParameters = 0;
1153    foreach $parameter (@{$function->parameters}) {
1154        if ($parameter->extendedAttributes->{"Optional"}) {
1155            push(@orExpression, GenerateParametersCheckExpression($numParameters, $function));
1156        }
1157        $numParameters++;
1158    }
1159    push(@orExpression, GenerateParametersCheckExpression($numParameters, $function));
1160    return join(" || ", @orExpression);
1161}
1162
1163sub GenerateOverloadedPrototypeFunction
1164{
1165    my $function = shift;
1166    my $dataNode = shift;
1167    my $implClassName = shift;
1168
1169    # Generate code for choosing the correct overload to call. Overloads are
1170    # chosen based on the total number of arguments passed and the type of
1171    # values passed in non-primitive argument slots. When more than a single
1172    # overload is applicable, precedence is given according to the order of
1173    # declaration in the IDL.
1174
1175    my $functionName = "js${implClassName}PrototypeFunction" . $codeGenerator->WK_ucfirst($function->signature->name);
1176
1177    push(@implContent, "EncodedJSValue JSC_HOST_CALL ${functionName}(ExecState* exec)\n");
1178    push(@implContent, <<END);
1179{
1180END
1181    foreach my $overload (@{$function->{overloads}}) {
1182        my $parametersCheck = GenerateFunctionParametersCheck($overload);
1183        push(@implContent, "    if ($parametersCheck)\n");
1184        push(@implContent, "        return ${functionName}$overload->{overloadIndex}(exec);\n");
1185    }
1186    push(@implContent, <<END);
1187    return throwVMTypeError(exec);
1188}
1189
1190END
1191}
1192
1193sub GenerateImplementation
1194{
1195    my ($object, $dataNode) = @_;
1196
1197    my $interfaceName = $dataNode->name;
1198    my $className = "JS$interfaceName";
1199    my $implClassName = $interfaceName;
1200
1201    my $hasLegacyParent = $dataNode->extendedAttributes->{"LegacyParent"};
1202    my $hasRealParent = @{$dataNode->parents} > 0;
1203    my $hasParent = $hasLegacyParent || $hasRealParent;
1204    my $parentClassName = GetParentClassName($dataNode);
1205    my $visibleClassName = GetVisibleClassName($interfaceName);
1206    my $eventTarget = $dataNode->extendedAttributes->{"EventTarget"};
1207    my $needsMarkChildren = $dataNode->extendedAttributes->{"CustomMarkFunction"} || $dataNode->extendedAttributes->{"EventTarget"};
1208
1209    # - Add default header template
1210    push(@implContentHeader, GenerateImplementationContentHeader($dataNode));
1211
1212    AddIncludesForSVGAnimatedType($interfaceName) if $className =~ /^JSSVGAnimated/;
1213
1214    $implIncludes{"<wtf/GetPtr.h>"} = 1;
1215    $implIncludes{"<runtime/PropertyNameArray.h>"} = 1 if $dataNode->extendedAttributes->{"HasIndexGetter"} || $dataNode->extendedAttributes->{"HasCustomIndexGetter"} || $dataNode->extendedAttributes->{"HasNumericIndexGetter"};
1216
1217    AddIncludesForType($interfaceName);
1218
1219    @implContent = ();
1220
1221    push(@implContent, "\nusing namespace JSC;\n\n");
1222    push(@implContent, "namespace WebCore {\n\n");
1223
1224    push(@implContent, "ASSERT_CLASS_FITS_IN_CELL($className);\n\n");
1225
1226    my $numAttributes = GenerateAttributesHashTable($object, $dataNode);
1227
1228    my $numConstants = @{$dataNode->constants};
1229    my $numFunctions = @{$dataNode->functions};
1230
1231    # - Add all constants
1232    if (!($dataNode->extendedAttributes->{"OmitConstructor"} || $dataNode->extendedAttributes->{"CustomConstructor"})) {
1233        $hashSize = $numConstants;
1234        $hashName = $className . "ConstructorTable";
1235
1236        @hashKeys = ();
1237        @hashValue1 = ();
1238        @hashValue2 = ();
1239        @hashSpecials = ();
1240
1241        # FIXME: we should not need a function for every constant.
1242        foreach my $constant (@{$dataNode->constants}) {
1243            push(@hashKeys, $constant->name);
1244            my $getter = "js" . $interfaceName . $codeGenerator->WK_ucfirst($constant->name);
1245            push(@hashValue1, $getter);
1246            push(@hashValue2, "0");
1247            push(@hashSpecials, "DontDelete | ReadOnly");
1248        }
1249
1250        $object->GenerateHashTable($hashName, $hashSize,
1251                                   \@hashKeys, \@hashSpecials,
1252                                   \@hashValue1, \@hashValue2);
1253
1254        push(@implContent, $codeGenerator->GenerateCompileTimeCheckForEnumsIfNeeded($dataNode));
1255
1256        my $protoClassName = "${className}Prototype";
1257
1258        GenerateConstructorDeclaration(\@implContent, $className, $dataNode) unless $dataNode->extendedAttributes->{"CustomConstructFunction"};
1259        GenerateConstructorDefinition(\@implContent, $className, $protoClassName, $interfaceName, $visibleClassName, $dataNode);
1260    }
1261
1262    # - Add functions and constants to a hashtable definition
1263    $hashSize = $numFunctions + $numConstants;
1264    $hashName = $className . "PrototypeTable";
1265
1266    @hashKeys = ();
1267    @hashValue1 = ();
1268    @hashValue2 = ();
1269    @hashSpecials = ();
1270
1271    # FIXME: we should not need a function for every constant.
1272    foreach my $constant (@{$dataNode->constants}) {
1273        push(@hashKeys, $constant->name);
1274        my $getter = "js" . $interfaceName . $codeGenerator->WK_ucfirst($constant->name);
1275        push(@hashValue1, $getter);
1276        push(@hashValue2, "0");
1277        push(@hashSpecials, "DontDelete | ReadOnly");
1278    }
1279
1280    foreach my $function (@{$dataNode->functions}) {
1281        next if $function->{overloadIndex} && $function->{overloadIndex} > 1;
1282        my $name = $function->signature->name;
1283        push(@hashKeys, $name);
1284
1285        my $value = $codeGenerator->WK_lcfirst($className) . "PrototypeFunction" . $codeGenerator->WK_ucfirst($name);
1286        push(@hashValue1, $value);
1287
1288        my $numParameters = @{$function->parameters};
1289        push(@hashValue2, $numParameters);
1290
1291        my @specials = ();
1292        push(@specials, "DontDelete") unless $function->signature->extendedAttributes->{"Deletable"};
1293        push(@specials, "DontEnum") if $function->signature->extendedAttributes->{"DontEnum"};
1294        push(@specials, "Function");
1295        my $special = (@specials > 0) ? join(" | ", @specials) : "0";
1296        push(@hashSpecials, $special);
1297    }
1298
1299    $object->GenerateHashTable($hashName, $hashSize,
1300                               \@hashKeys, \@hashSpecials,
1301                               \@hashValue1, \@hashValue2);
1302
1303    if ($dataNode->extendedAttributes->{"NoStaticTables"}) {
1304        push(@implContent, "static const HashTable* get${className}PrototypeTable(ExecState* exec)\n");
1305        push(@implContent, "{\n");
1306        push(@implContent, "    return getHashTableForGlobalData(exec->globalData(), &${className}PrototypeTable);\n");
1307        push(@implContent, "}\n\n");
1308        push(@implContent, "const ClassInfo ${className}Prototype::s_info = { \"${visibleClassName}Prototype\", &JSC::JSObjectWithGlobalObject::s_info, 0, get${className}PrototypeTable };\n\n");
1309    } else {
1310        push(@implContent, "const ClassInfo ${className}Prototype::s_info = { \"${visibleClassName}Prototype\", &JSC::JSObjectWithGlobalObject::s_info, &${className}PrototypeTable, 0 };\n\n");
1311    }
1312    if ($interfaceName eq "DOMWindow") {
1313        push(@implContent, "void* ${className}Prototype::operator new(size_t size)\n");
1314        push(@implContent, "{\n");
1315        push(@implContent, "    return JSDOMWindow::commonJSGlobalData()->heap.allocate(size);\n");
1316        push(@implContent, "}\n\n");
1317    } elsif ($dataNode->extendedAttributes->{"IsWorkerContext"}) {
1318        push(@implContent, "void* ${className}Prototype::operator new(size_t size, JSGlobalData* globalData)\n");
1319        push(@implContent, "{\n");
1320        push(@implContent, "    return globalData->heap.allocate(size);\n");
1321        push(@implContent, "}\n\n");
1322    } else {
1323        push(@implContent, "JSObject* ${className}Prototype::self(ExecState* exec, JSGlobalObject* globalObject)\n");
1324        push(@implContent, "{\n");
1325        push(@implContent, "    return getDOMPrototype<${className}>(exec, globalObject);\n");
1326        push(@implContent, "}\n\n");
1327    }
1328    if ($numConstants > 0 || $numFunctions > 0 || $dataNode->extendedAttributes->{"DelegatingPrototypeGetOwnPropertySlot"}) {
1329        push(@implContent, "bool ${className}Prototype::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)\n");
1330        push(@implContent, "{\n");
1331
1332        if ($dataNode->extendedAttributes->{"DelegatingPrototypeGetOwnPropertySlot"}) {
1333            push(@implContent, "    if (getOwnPropertySlotDelegate(exec, propertyName, slot))\n");
1334            push(@implContent, "        return true;\n");
1335        }
1336
1337        if ($numConstants eq 0 && $numFunctions eq 0) {
1338            push(@implContent, "    return Base::getOwnPropertySlot(exec, propertyName, slot);\n");
1339        } elsif ($numConstants eq 0) {
1340            push(@implContent, "    return getStaticFunctionSlot<JSObject>(exec, " . prototypeHashTableAccessor($dataNode->extendedAttributes->{"NoStaticTables"}, $className) . ", this, propertyName, slot);\n");
1341        } elsif ($numFunctions eq 0) {
1342            push(@implContent, "    return getStaticValueSlot<${className}Prototype, JSObject>(exec, " . prototypeHashTableAccessor($dataNode->extendedAttributes->{"NoStaticTables"}, $className) . ", this, propertyName, slot);\n");
1343        } else {
1344            push(@implContent, "    return getStaticPropertySlot<${className}Prototype, JSObject>(exec, " . prototypeHashTableAccessor($dataNode->extendedAttributes->{"NoStaticTables"}, $className) . ", this, propertyName, slot);\n");
1345        }
1346        push(@implContent, "}\n\n");
1347
1348        push(@implContent, "bool ${className}Prototype::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)\n");
1349        push(@implContent, "{\n");
1350
1351        if ($dataNode->extendedAttributes->{"DelegatingPrototypeGetOwnPropertySlot"}) {
1352            push(@implContent, "    if (getOwnPropertyDescriptorDelegate(exec, propertyName, descriptor))\n");
1353            push(@implContent, "        return true;\n");
1354        }
1355
1356        if ($numConstants eq 0 && $numFunctions eq 0) {
1357            push(@implContent, "    return Base::getOwnPropertyDescriptor(exec, propertyName, descriptor);\n");
1358        } elsif ($numConstants eq 0) {
1359            push(@implContent, "    return getStaticFunctionDescriptor<JSObject>(exec, " . prototypeHashTableAccessor($dataNode->extendedAttributes->{"NoStaticTables"}, $className) . ", this, propertyName, descriptor);\n");
1360        } elsif ($numFunctions eq 0) {
1361            push(@implContent, "    return getStaticValueDescriptor<${className}Prototype, JSObject>(exec, " . prototypeHashTableAccessor($dataNode->extendedAttributes->{"NoStaticTables"}, $className) . ", this, propertyName, descriptor);\n");
1362        } else {
1363            push(@implContent, "    return getStaticPropertyDescriptor<${className}Prototype, JSObject>(exec, " . prototypeHashTableAccessor($dataNode->extendedAttributes->{"NoStaticTables"}, $className) . ", this, propertyName, descriptor);\n");
1364        }
1365        push(@implContent, "}\n\n");
1366    }
1367
1368    if ($dataNode->extendedAttributes->{"DelegatingPrototypePutFunction"}) {
1369        push(@implContent, "void ${className}Prototype::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)\n");
1370        push(@implContent, "{\n");
1371        push(@implContent, "    if (putDelegate(exec, propertyName, value, slot))\n");
1372        push(@implContent, "        return;\n");
1373        push(@implContent, "    Base::put(exec, propertyName, value, slot);\n");
1374        push(@implContent, "}\n\n");
1375    }
1376
1377    # - Initialize static ClassInfo object
1378    if ($numAttributes > 0 && $dataNode->extendedAttributes->{"NoStaticTables"}) {
1379        push(@implContent, "static const HashTable* get${className}Table(ExecState* exec)\n");
1380        push(@implContent, "{\n");
1381        push(@implContent, "    return getHashTableForGlobalData(exec->globalData(), &${className}Table);\n");
1382        push(@implContent, "}\n\n");
1383    }
1384
1385    push(@implContent, "const ClassInfo $className" . "::s_info = { \"${visibleClassName}\", &" . $parentClassName . "::s_info, ");
1386
1387    if ($numAttributes > 0 && !$dataNode->extendedAttributes->{"NoStaticTables"}) {
1388        push(@implContent, "&${className}Table");
1389    } else {
1390        push(@implContent, "0");
1391    }
1392    if ($numAttributes > 0 && $dataNode->extendedAttributes->{"NoStaticTables"}) {
1393        push(@implContent, ", get${className}Table ");
1394    } else {
1395        push(@implContent, ", 0 ");
1396    }
1397    push(@implContent, "};\n\n");
1398
1399    my $implType = $implClassName;
1400    my ($svgPropertyType, $svgListPropertyType, $svgNativeType) = GetSVGPropertyTypes($implType);
1401    $implType = $svgNativeType if $svgNativeType;
1402
1403    my $svgPropertyOrListPropertyType;
1404    $svgPropertyOrListPropertyType = $svgPropertyType if $svgPropertyType;
1405    $svgPropertyOrListPropertyType = $svgListPropertyType if $svgListPropertyType;
1406
1407    # Constructor
1408    if ($interfaceName eq "DOMWindow") {
1409        AddIncludesForType("JSDOMWindowShell");
1410        push(@implContent, "${className}::$className(JSGlobalData& globalData, Structure* structure, PassRefPtr<$implType> impl, JSDOMWindowShell* shell)\n");
1411        push(@implContent, "    : $parentClassName(globalData, structure, impl, shell)\n");
1412    } elsif ($dataNode->extendedAttributes->{"IsWorkerContext"}) {
1413        AddIncludesForType($interfaceName);
1414        push(@implContent, "${className}::$className(JSGlobalData& globalData, Structure* structure, PassRefPtr<$implType> impl)\n");
1415        push(@implContent, "    : $parentClassName(globalData, structure, impl)\n");
1416    } else {
1417        push(@implContent, "${className}::$className(Structure* structure, JSDOMGlobalObject* globalObject, PassRefPtr<$implType> impl)\n");
1418        if ($hasParent) {
1419            push(@implContent, "    : $parentClassName(structure, globalObject, impl)\n");
1420        } else {
1421            push(@implContent, "    : $parentClassName(structure, globalObject)\n");
1422            push(@implContent, "    , m_impl(impl)\n");
1423        }
1424    }
1425    push(@implContent, "{\n");
1426    push(@implContent, "    ASSERT(inherits(&s_info));\n");
1427    if ($numCachedAttributes > 0) {
1428        push(@implContent, "    for (unsigned i = Base::AnonymousSlotCount; i < AnonymousSlotCount; i++)\n");
1429        push(@implContent, "        putAnonymousValue(globalObject->globalData(), i, JSValue());\n");
1430    }
1431    push(@implContent, "}\n\n");
1432
1433    if ($needsMarkChildren && !$dataNode->extendedAttributes->{"CustomMarkFunction"}) {
1434        push(@implContent, "void ${className}::markChildren(MarkStack& markStack)\n");
1435        push(@implContent, "{\n");
1436        push(@implContent, "    Base::markChildren(markStack);\n");
1437        push(@implContent, "    impl()->markJSEventListeners(markStack);\n");
1438        push(@implContent, "}\n\n");
1439    }
1440
1441    if (!$dataNode->extendedAttributes->{"ExtendsDOMGlobalObject"}) {
1442        push(@implContent, "JSObject* ${className}::createPrototype(ExecState* exec, JSGlobalObject* globalObject)\n");
1443        push(@implContent, "{\n");
1444        if ($hasParent && $parentClassName ne "JSC::DOMNodeFilter") {
1445            push(@implContent, "    return new (exec) ${className}Prototype(exec->globalData(), globalObject, ${className}Prototype::createStructure(exec->globalData(), ${parentClassName}Prototype::self(exec, globalObject)));\n");
1446        } else {
1447            push(@implContent, "    return new (exec) ${className}Prototype(exec->globalData(), globalObject, ${className}Prototype::createStructure(globalObject->globalData(), globalObject->objectPrototype()));\n");
1448        }
1449        push(@implContent, "}\n\n");
1450    }
1451
1452    my $hasGetter = $numAttributes > 0
1453                 || !($dataNode->extendedAttributes->{"OmitConstructor"}
1454                 || $dataNode->extendedAttributes->{"CustomConstructor"})
1455                 || $dataNode->extendedAttributes->{"HasIndexGetter"}
1456                 || $dataNode->extendedAttributes->{"HasCustomIndexGetter"}
1457                 || $dataNode->extendedAttributes->{"HasNumericIndexGetter"}
1458                 || $dataNode->extendedAttributes->{"DelegatingGetOwnPropertySlot"}
1459                 || $dataNode->extendedAttributes->{"CustomGetOwnPropertySlot"}
1460                 || $dataNode->extendedAttributes->{"HasNameGetter"}
1461                 || $dataNode->extendedAttributes->{"HasOverridingNameGetter"};
1462
1463    # Attributes
1464    if ($hasGetter) {
1465        if (!$dataNode->extendedAttributes->{"InlineGetOwnPropertySlot"} && !$dataNode->extendedAttributes->{"CustomGetOwnPropertySlot"}) {
1466            push(@implContent, "bool ${className}::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)\n");
1467            push(@implContent, "{\n");
1468            push(@implContent, GenerateGetOwnPropertySlotBody($dataNode, $interfaceName, $className, $implClassName, $numAttributes > 0, 0));
1469            push(@implContent, "}\n\n");
1470            push(@implContent, "bool ${className}::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)\n");
1471            push(@implContent, "{\n");
1472            push(@implContent, GenerateGetOwnPropertyDescriptorBody($dataNode, $interfaceName, $className, $implClassName, $numAttributes > 0, 0));
1473            push(@implContent, "}\n\n");
1474        }
1475
1476        if (($dataNode->extendedAttributes->{"HasIndexGetter"} || $dataNode->extendedAttributes->{"HasCustomIndexGetter"} || $dataNode->extendedAttributes->{"HasNumericIndexGetter"})
1477                && !$dataNode->extendedAttributes->{"HasOverridingNameGetter"}) {
1478            push(@implContent, "bool ${className}::getOwnPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot)\n");
1479            push(@implContent, "{\n");
1480            push(@implContent, "    if (propertyName < static_cast<$implClassName*>(impl())->length()) {\n");
1481            if ($dataNode->extendedAttributes->{"HasCustomIndexGetter"} || $dataNode->extendedAttributes->{"HasNumericIndexGetter"}) {
1482                push(@implContent, "        slot.setValue(getByIndex(exec, propertyName));\n");
1483            } else {
1484                push(@implContent, "        slot.setCustomIndex(this, propertyName, indexGetter);\n");
1485            }
1486            push(@implContent, "        return true;\n");
1487            push(@implContent, "    }\n");
1488            push(@implContent, "    return getOwnPropertySlot(exec, Identifier::from(exec, propertyName), slot);\n");
1489            push(@implContent, "}\n\n");
1490        }
1491
1492        if ($numAttributes > 0) {
1493            foreach my $attribute (@{$dataNode->attributes}) {
1494                my $name = $attribute->signature->name;
1495                my $type = $codeGenerator->StripModule($attribute->signature->type);
1496                my $getFunctionName = "js" . $interfaceName .  $codeGenerator->WK_ucfirst($attribute->signature->name) . ($attribute->signature->type =~ /Constructor$/ ? "Constructor" : "");
1497                my $implGetterFunctionName = $codeGenerator->WK_lcfirst($name);
1498
1499                my $attributeConditionalString = GenerateConditionalString($attribute->signature);
1500                push(@implContent, "#if ${attributeConditionalString}\n") if $attributeConditionalString;
1501
1502                push(@implContent, "JSValue ${getFunctionName}(ExecState* exec, JSValue slotBase, const Identifier&)\n");
1503                push(@implContent, "{\n");
1504                push(@implContent, "    ${className}* castedThis = static_cast<$className*>(asObject(slotBase));\n");
1505
1506                if ($dataNode->extendedAttributes->{"CheckDomainSecurity"} &&
1507                        !$attribute->signature->extendedAttributes->{"DoNotCheckDomainSecurity"} &&
1508                        !$attribute->signature->extendedAttributes->{"DoNotCheckDomainSecurityOnGet"}) {
1509                    push(@implContent, "    if (!castedThis->allowsAccessFrom(exec))\n");
1510                    push(@implContent, "        return jsUndefined();\n");
1511                }
1512
1513                if ($attribute->signature->extendedAttributes->{"Custom"} || $attribute->signature->extendedAttributes->{"JSCCustom"} || $attribute->signature->extendedAttributes->{"CustomGetter"} || $attribute->signature->extendedAttributes->{"JSCCustomGetter"}) {
1514                    push(@implContent, "    return castedThis->$implGetterFunctionName(exec);\n");
1515                } elsif ($attribute->signature->extendedAttributes->{"CheckNodeSecurity"}) {
1516                    $implIncludes{"JSDOMBinding.h"} = 1;
1517                    push(@implContent, "    $implClassName* imp = static_cast<$implClassName*>(castedThis->impl());\n");
1518                    push(@implContent, "    return checkNodeSecurity(exec, imp->$implGetterFunctionName()) ? " . NativeToJSValue($attribute->signature, 0, $implClassName, "imp->$implGetterFunctionName()", "castedThis") . " : jsUndefined();\n");
1519                } elsif ($attribute->signature->extendedAttributes->{"CheckFrameSecurity"}) {
1520                    $implIncludes{"Document.h"} = 1;
1521                    $implIncludes{"JSDOMBinding.h"} = 1;
1522                    push(@implContent, "    $implClassName* imp = static_cast<$implClassName*>(castedThis->impl());\n");
1523                    push(@implContent, "    return checkNodeSecurity(exec, imp->contentDocument()) ? " . NativeToJSValue($attribute->signature, 0, $implClassName, "imp->$implGetterFunctionName()", "castedThis") . " : jsUndefined();\n");
1524                } elsif ($type eq "EventListener") {
1525                    $implIncludes{"EventListener.h"} = 1;
1526                    push(@implContent, "    UNUSED_PARAM(exec);\n");
1527                    push(@implContent, "    $implClassName* imp = static_cast<$implClassName*>(castedThis->impl());\n");
1528                    push(@implContent, "    if (EventListener* listener = imp->$implGetterFunctionName()) {\n");
1529                    push(@implContent, "        if (const JSEventListener* jsListener = JSEventListener::cast(listener)) {\n");
1530                    if ($implClassName eq "Document" || $implClassName eq "WorkerContext" || $implClassName eq "SharedWorkerContext" || $implClassName eq "DedicatedWorkerContext") {
1531                        push(@implContent, "            if (JSObject* jsFunction = jsListener->jsFunction(imp))\n");
1532                    } else {
1533                        push(@implContent, "            if (JSObject* jsFunction = jsListener->jsFunction(imp->scriptExecutionContext()))\n");
1534                    }
1535                    push(@implContent, "                return jsFunction;\n");
1536                    push(@implContent, "        }\n");
1537                    push(@implContent, "    }\n");
1538                    push(@implContent, "    return jsNull();\n");
1539                } elsif ($attribute->signature->type =~ /Constructor$/) {
1540                    my $constructorType = $codeGenerator->StripModule($attribute->signature->type);
1541                    $constructorType =~ s/Constructor$//;
1542                    # Constructor attribute is only used by DOMWindow.idl, so it's correct to pass castedThis as the global object
1543                    # Once JSDOMWrappers have a back-pointer to the globalObject we can pass castedThis->globalObject()
1544                    push(@implContent, "    return JS" . $constructorType . "::getConstructor(exec, castedThis);\n");
1545                } elsif (!@{$attribute->getterExceptions}) {
1546                    push(@implContent, "    UNUSED_PARAM(exec);\n");
1547                    my $cacheIndex = 0;
1548                    if ($attribute->signature->extendedAttributes->{"CachedAttribute"}) {
1549                        $cacheIndex = $currentCachedAttribute;
1550                        $currentCachedAttribute++;
1551                        push(@implContent, "    if (JSValue cachedValue = castedThis->getAnonymousValue(" . $className . "::" . $attribute->signature->name . "Slot))\n");
1552                        push(@implContent, "        return cachedValue;\n");
1553                    }
1554
1555                    if ($svgListPropertyType) {
1556                        push(@implContent, "    JSValue result =  " . NativeToJSValue($attribute->signature, 0, $implClassName, "castedThis->impl()->$implGetterFunctionName()", "castedThis") . ";\n");
1557                    } elsif ($svgPropertyOrListPropertyType) {
1558                        push(@implContent, "    $svgPropertyOrListPropertyType& imp = castedThis->impl()->propertyReference();\n");
1559                        if ($svgPropertyOrListPropertyType eq "float") { # Special case for JSSVGNumber
1560                            push(@implContent, "    JSValue result =  " . NativeToJSValue($attribute->signature, 0, $implClassName, "imp", "castedThis") . ";\n");
1561                        } else {
1562                            push(@implContent, "    JSValue result =  " . NativeToJSValue($attribute->signature, 0, $implClassName, "imp.$implGetterFunctionName()", "castedThis") . ";\n");
1563                        }
1564                    } else {
1565                        my $getterExpression = "imp->" . $codeGenerator->GetterExpressionPrefix(\%implIncludes, $interfaceName, $attribute) . ")";
1566                        my $jsType = NativeToJSValue($attribute->signature, 0, $implClassName, $getterExpression, "castedThis");
1567                        push(@implContent, "    $implClassName* imp = static_cast<$implClassName*>(castedThis->impl());\n");
1568                        if ($codeGenerator->IsSVGAnimatedType($type)) {
1569                            push(@implContent, "    RefPtr<$type> obj = $jsType;\n");
1570                            push(@implContent, "    JSValue result =  toJS(exec, castedThis->globalObject(), obj.get());\n");
1571                        } else {
1572                            push(@implContent, "    JSValue result = $jsType;\n");
1573                        }
1574                    }
1575
1576                    push(@implContent, "    castedThis->putAnonymousValue(exec->globalData(), " . $className . "::" . $attribute->signature->name . "Slot, result);\n") if ($attribute->signature->extendedAttributes->{"CachedAttribute"});
1577                    push(@implContent, "    return result;\n");
1578
1579                } else {
1580                    push(@implContent, "    ExceptionCode ec = 0;\n");
1581                    if ($svgPropertyOrListPropertyType) {
1582                        push(@implContent, "    $svgPropertyOrListPropertyType imp(*castedThis->impl());\n");
1583                        push(@implContent, "    JSC::JSValue result = " . NativeToJSValue($attribute->signature, 0, $implClassName, "imp.$implGetterFunctionName(ec)", "castedThis") . ";\n");
1584                    } else {
1585                        push(@implContent, "    $implClassName* imp = static_cast<$implClassName*>(castedThis->impl());\n");
1586                        push(@implContent, "    JSC::JSValue result = " . NativeToJSValue($attribute->signature, 0, $implClassName, "imp->$implGetterFunctionName(ec)", "castedThis") . ";\n");
1587                    }
1588
1589                    push(@implContent, "    setDOMException(exec, ec);\n");
1590                    push(@implContent, "    return result;\n");
1591                }
1592
1593                push(@implContent, "}\n\n");
1594
1595                push(@implContent, "#endif\n") if $attributeConditionalString;
1596
1597                push(@implContent, "\n");
1598            }
1599
1600            if (!($dataNode->extendedAttributes->{"OmitConstructor"} || $dataNode->extendedAttributes->{"CustomConstructor"})) {
1601                my $constructorFunctionName = "js" . $interfaceName . "Constructor";
1602
1603                push(@implContent, "JSValue ${constructorFunctionName}(ExecState* exec, JSValue slotBase, const Identifier&)\n");
1604                push(@implContent, "{\n");
1605                push(@implContent, "    ${className}* domObject = static_cast<$className*>(asObject(slotBase));\n");
1606
1607                if ($dataNode->extendedAttributes->{"CheckDomainSecurity"}) {
1608                    push(@implContent, "    if (!domObject->allowsAccessFrom(exec))\n");
1609                    push(@implContent, "        return jsUndefined();\n");
1610                }
1611
1612                push(@implContent, "    return ${className}::getConstructor(exec, domObject->globalObject());\n");
1613                push(@implContent, "}\n\n");
1614            }
1615        }
1616
1617        # Check if we have any writable attributes
1618        my $hasReadWriteProperties = 0;
1619        foreach my $attribute (@{$dataNode->attributes}) {
1620            $hasReadWriteProperties = 1 if $attribute->type !~ /^readonly/;
1621        }
1622
1623        my $hasSetter = $hasReadWriteProperties
1624                     || $dataNode->extendedAttributes->{"DelegatingPutFunction"}
1625                     || $dataNode->extendedAttributes->{"HasCustomIndexSetter"};
1626
1627        if ($hasSetter) {
1628            if (!$dataNode->extendedAttributes->{"CustomPutFunction"}) {
1629                push(@implContent, "void ${className}::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)\n");
1630                push(@implContent, "{\n");
1631                if ($dataNode->extendedAttributes->{"HasCustomIndexSetter"}) {
1632                    push(@implContent, "    bool ok;\n");
1633                    push(@implContent, "    unsigned index = propertyName.toUInt32(ok);\n");
1634                    push(@implContent, "    if (ok) {\n");
1635                    push(@implContent, "        indexSetter(exec, index, value);\n");
1636                    push(@implContent, "        return;\n");
1637                    push(@implContent, "    }\n");
1638                }
1639                if ($dataNode->extendedAttributes->{"DelegatingPutFunction"}) {
1640                    push(@implContent, "    if (putDelegate(exec, propertyName, value, slot))\n");
1641                    push(@implContent, "        return;\n");
1642                }
1643
1644                if ($hasReadWriteProperties) {
1645                    push(@implContent, "    lookupPut<$className, Base>(exec, propertyName, value, " . hashTableAccessor($dataNode->extendedAttributes->{"NoStaticTables"}, $className) . ", this, slot);\n");
1646                } else {
1647                    push(@implContent, "    Base::put(exec, propertyName, value, slot);\n");
1648                }
1649                push(@implContent, "}\n\n");
1650            }
1651
1652            if ($dataNode->extendedAttributes->{"HasCustomIndexSetter"}) {
1653                push(@implContent, "void ${className}::put(ExecState* exec, unsigned propertyName, JSValue value)\n");
1654                push(@implContent, "{\n");
1655                push(@implContent, "    indexSetter(exec, propertyName, value);\n");
1656                push(@implContent, "    return;\n");
1657                push(@implContent, "}\n\n");
1658            }
1659
1660            if ($hasReadWriteProperties) {
1661                foreach my $attribute (@{$dataNode->attributes}) {
1662                    if ($attribute->type !~ /^readonly/) {
1663                        my $name = $attribute->signature->name;
1664                        my $type = $codeGenerator->StripModule($attribute->signature->type);
1665                        my $putFunctionName = "setJS" . $interfaceName .  $codeGenerator->WK_ucfirst($name) . ($attribute->signature->type =~ /Constructor$/ ? "Constructor" : "");
1666                        my $implSetterFunctionName = $codeGenerator->WK_ucfirst($name);
1667
1668                        my $attributeConditionalString = GenerateConditionalString($attribute->signature);
1669                        push(@implContent, "#if ${attributeConditionalString}\n") if $attributeConditionalString;
1670
1671                        push(@implContent, "void ${putFunctionName}(ExecState* exec, JSObject* thisObject, JSValue value)\n");
1672                        push(@implContent, "{\n");
1673
1674                        if ($dataNode->extendedAttributes->{"CheckDomainSecurity"} && !$attribute->signature->extendedAttributes->{"DoNotCheckDomainSecurity"}) {
1675                            if ($interfaceName eq "DOMWindow") {
1676                                push(@implContent, "    if (!static_cast<$className*>(thisObject)->allowsAccessFrom(exec))\n");
1677                            } else {
1678                                push(@implContent, "    if (!allowsAccessFromFrame(exec, static_cast<$className*>(thisObject)->impl()->frame()))\n");
1679                            }
1680                            push(@implContent, "        return;\n");
1681                        }
1682
1683                        if ($attribute->signature->extendedAttributes->{"Custom"} || $attribute->signature->extendedAttributes->{"JSCCustom"} || $attribute->signature->extendedAttributes->{"CustomSetter"} || $attribute->signature->extendedAttributes->{"JSCCustomSetter"}) {
1684                            push(@implContent, "    static_cast<$className*>(thisObject)->set$implSetterFunctionName(exec, value);\n");
1685                        } elsif ($type eq "EventListener") {
1686                            $implIncludes{"JSEventListener.h"} = 1;
1687                            push(@implContent, "    UNUSED_PARAM(exec);\n");
1688                            my $windowEventListener = $attribute->signature->extendedAttributes->{"WindowEventListener"};
1689                            if ($windowEventListener) {
1690                                push(@implContent, "    ${className}* castedThis = static_cast<${className}*>(thisObject);\n");
1691                                push(@implContent, "    JSDOMGlobalObject* globalObject = castedThis->globalObject();\n");
1692                            }
1693                            push(@implContent, "    $implClassName* imp = static_cast<$implClassName*>(static_cast<$className*>(thisObject)->impl());\n");
1694                            if ((($interfaceName eq "DOMWindow") or ($interfaceName eq "WorkerContext")) and $name eq "onerror") {
1695                                $implIncludes{"JSErrorHandler.h"} = 1;
1696                                push(@implContent, "    imp->set$implSetterFunctionName(createJSErrorHandler(exec, value, thisObject));\n");
1697                            } else {
1698                                push(@implContent, GenerateAttributeEventListenerCall($className, $implSetterFunctionName, $windowEventListener));
1699                            }
1700                        } elsif ($attribute->signature->type =~ /Constructor$/) {
1701                            my $constructorType = $attribute->signature->type;
1702                            $constructorType =~ s/Constructor$//;
1703                            if ($constructorType ne "DOMObject") {
1704                                $implIncludes{"JS" . $constructorType . ".h"} = 1;
1705                            }
1706                            push(@implContent, "    // Shadowing a built-in constructor\n");
1707                            if ($interfaceName eq "DOMWindow" && $className eq "JSblah") {
1708                                push(@implContent, "    static_cast<$className*>(thisObject)->putDirect(exec->globalData(), exec->propertyNames().constructor, value);\n");
1709                            } else {
1710                                push(@implContent, "    static_cast<$className*>(thisObject)->putDirect(exec->globalData(), Identifier(exec, \"$name\"), value);\n");
1711                            }
1712                        } elsif ($attribute->signature->extendedAttributes->{"Replaceable"}) {
1713                            push(@implContent, "    // Shadowing a built-in object\n");
1714                            push(@implContent, "    static_cast<$className*>(thisObject)->putDirect(exec->globalData(), Identifier(exec, \"$name\"), value);\n");
1715                        } else {
1716                            push(@implContent, "    $className* castedThis = static_cast<$className*>(thisObject);\n");
1717                            push(@implContent, "    $implType* imp = static_cast<$implType*>(castedThis->impl());\n");
1718                            push(@implContent, "    ExceptionCode ec = 0;\n") if @{$attribute->setterExceptions};
1719
1720                            # If the "StrictTypeChecking" extended attribute is present, and the attribute's type is an
1721                            # interface type, then if the incoming value does not implement that interface, a TypeError
1722                            # is thrown rather than silently passing NULL to the C++ code.
1723                            # Per the Web IDL and ECMAScript specifications, incoming values can always be converted to
1724                            # both strings and numbers, so do not throw TypeError if the attribute is of these types.
1725                            if ($attribute->signature->extendedAttributes->{"StrictTypeChecking"}) {
1726                                $implIncludes{"<runtime/Error.h>"} = 1;
1727
1728                                my $argType = $attribute->signature->type;
1729                                if (!IsNativeType($argType)) {
1730                                    push(@implContent, "    if (!value.isUndefinedOrNull() && !value.inherits(&JS${argType}::s_info)) {\n");
1731                                    push(@implContent, "        throwVMTypeError(exec);\n");
1732                                    push(@implContent, "        return;\n");
1733                                    push(@implContent, "    };\n");
1734                                }
1735                            }
1736
1737                            my $nativeValue = JSValueToNative($attribute->signature, "value");
1738                            if ($svgPropertyOrListPropertyType) {
1739                                if ($svgPropertyType) {
1740                                    push(@implContent, "    if (imp->role() == AnimValRole) {\n");
1741                                    push(@implContent, "        setDOMException(exec, NO_MODIFICATION_ALLOWED_ERR);\n");
1742                                    push(@implContent, "        return;\n");
1743                                    push(@implContent, "    }\n");
1744                                }
1745                                push(@implContent, "    $svgPropertyOrListPropertyType& podImp = imp->propertyReference();\n");
1746                                if ($svgPropertyOrListPropertyType eq "float") { # Special case for JSSVGNumber
1747                                    push(@implContent, "    podImp = $nativeValue;\n");
1748                                } else {
1749                                    push(@implContent, "    podImp.set$implSetterFunctionName($nativeValue");
1750                                    push(@implContent, ", ec") if @{$attribute->setterExceptions};
1751                                    push(@implContent, ");\n");
1752                                    push(@implContent, "    setDOMException(exec, ec);\n") if @{$attribute->setterExceptions};
1753                                }
1754                                if ($svgPropertyType) {
1755                                    if (@{$attribute->setterExceptions}) {
1756                                        push(@implContent, "    if (!ec)\n");
1757                                        push(@implContent, "        imp->commitChange();\n");
1758                                    } else {
1759                                        push(@implContent, "    imp->commitChange();\n");
1760                                    }
1761                                }
1762                            } else {
1763                                my $setterExpressionPrefix = $codeGenerator->SetterExpressionPrefix(\%implIncludes, $interfaceName, $attribute);
1764                                push(@implContent, "    imp->$setterExpressionPrefix$nativeValue");
1765                                push(@implContent, ", ec") if @{$attribute->setterExceptions};
1766                                push(@implContent, ");\n");
1767                                push(@implContent, "    setDOMException(exec, ec);\n") if @{$attribute->setterExceptions};
1768                            }
1769                        }
1770
1771                        push(@implContent, "}\n\n");
1772
1773                        push(@implContent, "#endif\n") if $attributeConditionalString;
1774
1775                        push(@implContent, "\n");
1776                    }
1777                }
1778            }
1779
1780            if ($dataNode->extendedAttributes->{"ReplaceableConstructor"}) {
1781                my $constructorFunctionName = "setJS" . $interfaceName . "Constructor";
1782
1783                push(@implContent, "void ${constructorFunctionName}(ExecState* exec, JSObject* thisObject, JSValue value)\n");
1784                push(@implContent, "{\n");
1785                if ($dataNode->extendedAttributes->{"CheckDomainSecurity"}) {
1786                    if ($interfaceName eq "DOMWindow") {
1787                        push(@implContent, "    if (!static_cast<$className*>(thisObject)->allowsAccessFrom(exec))\n");
1788                    } else {
1789                        push(@implContent, "    if (!allowsAccessFromFrame(exec, static_cast<$className*>(thisObject)->impl()->frame()))\n");
1790                    }
1791                    push(@implContent, "        return;\n");
1792                }
1793
1794                push(@implContent, "    // Shadowing a built-in constructor\n");
1795
1796                if ($interfaceName eq "DOMWindow") {
1797                    push(@implContent, "    static_cast<$className*>(thisObject)->putDirect(exec->globalData(), exec->propertyNames().constructor, value);\n");
1798                } else {
1799                    push(@implContent, "    static_cast<$className*>(thisObject)->putDirect(exec->globalData(), Identifier(exec, \"$name\"), value);\n");
1800                }
1801                push(@implContent, "}\n\n");
1802            }
1803        }
1804    }
1805
1806    if (($dataNode->extendedAttributes->{"HasIndexGetter"} || $dataNode->extendedAttributes->{"HasCustomIndexGetter"} || $dataNode->extendedAttributes->{"HasNumericIndexGetter"}) && !$dataNode->extendedAttributes->{"CustomGetPropertyNames"}) {
1807        push(@implContent, "void ${className}::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)\n");
1808        push(@implContent, "{\n");
1809        if ($dataNode->extendedAttributes->{"HasIndexGetter"} || $dataNode->extendedAttributes->{"HasCustomIndexGetter"} || $dataNode->extendedAttributes->{"HasNumericIndexGetter"}) {
1810            push(@implContent, "    for (unsigned i = 0; i < static_cast<${implClassName}*>(impl())->length(); ++i)\n");
1811            push(@implContent, "        propertyNames.add(Identifier::from(exec, i));\n");
1812        }
1813        push(@implContent, "     Base::getOwnPropertyNames(exec, propertyNames, mode);\n");
1814        push(@implContent, "}\n\n");
1815    }
1816
1817    if (!($dataNode->extendedAttributes->{"OmitConstructor"} || $dataNode->extendedAttributes->{"CustomConstructor"})) {
1818        push(@implContent, "JSValue ${className}::getConstructor(ExecState* exec, JSGlobalObject* globalObject)\n{\n");
1819        push(@implContent, "    return getDOMConstructor<${className}Constructor>(exec, static_cast<JSDOMGlobalObject*>(globalObject));\n");
1820        push(@implContent, "}\n\n");
1821    }
1822
1823    # Functions
1824    if ($numFunctions > 0) {
1825        foreach my $function (@{$dataNode->functions}) {
1826            AddIncludesForType($function->signature->type);
1827
1828            my $functionName = $codeGenerator->WK_lcfirst($className) . "PrototypeFunction" . $codeGenerator->WK_ucfirst($function->signature->name);
1829
1830            if ($function->{overloads} && @{$function->{overloads}} > 1) {
1831                # Append a number to an overloaded method's name to make it unique:
1832                $functionName = $functionName . $function->{overloadIndex};
1833                # Make this function static to avoid compiler warnings, since we
1834                # don't generate a prototype for it in the header.
1835                push(@implContent, "static ");
1836            }
1837
1838            my $functionImplementationName = $function->signature->extendedAttributes->{"ImplementationFunction"} || $codeGenerator->WK_lcfirst($function->signature->name);
1839
1840            push(@implContent, "EncodedJSValue JSC_HOST_CALL ${functionName}(ExecState* exec)\n");
1841            push(@implContent, "{\n");
1842
1843            $implIncludes{"<runtime/Error.h>"} = 1;
1844
1845            if ($interfaceName eq "DOMWindow") {
1846                push(@implContent, "    $className* castedThis = toJSDOMWindow(exec->hostThisValue().toThisObject(exec));\n");
1847                push(@implContent, "    if (!castedThis)\n");
1848                push(@implContent, "        return throwVMTypeError(exec);\n");
1849            } elsif ($dataNode->extendedAttributes->{"IsWorkerContext"}) {
1850                push(@implContent, "    $className* castedThis = to${className}(exec->hostThisValue().toThisObject(exec));\n");
1851                push(@implContent, "    if (!castedThis)\n");
1852                push(@implContent, "        return throwVMTypeError(exec);\n");
1853            } else {
1854                push(@implContent, "    JSValue thisValue = exec->hostThisValue();\n");
1855                push(@implContent, "    if (!thisValue.inherits(&${className}::s_info))\n");
1856                push(@implContent, "        return throwVMTypeError(exec);\n");
1857                push(@implContent, "    $className* castedThis = static_cast<$className*>(asObject(thisValue));\n");
1858            }
1859
1860            if ($dataNode->extendedAttributes->{"CheckDomainSecurity"} &&
1861                !$function->signature->extendedAttributes->{"DoNotCheckDomainSecurity"}) {
1862                push(@implContent, "    if (!castedThis->allowsAccessFrom(exec))\n");
1863                push(@implContent, "        return JSValue::encode(jsUndefined());\n");
1864            }
1865
1866            if ($function->signature->extendedAttributes->{"Custom"} || $function->signature->extendedAttributes->{"JSCCustom"}) {
1867                push(@implContent, "    return JSValue::encode(castedThis->" . $functionImplementationName . "(exec));\n");
1868            } else {
1869                push(@implContent, "    $implType* imp = static_cast<$implType*>(castedThis->impl());\n");
1870                if ($svgPropertyType) {
1871                    push(@implContent, "    if (imp->role() == AnimValRole) {\n");
1872                    push(@implContent, "        setDOMException(exec, NO_MODIFICATION_ALLOWED_ERR);\n");
1873                    push(@implContent, "        return JSValue::encode(jsUndefined());\n");
1874                    push(@implContent, "    }\n");
1875                    push(@implContent, "    $svgPropertyType& podImp = imp->propertyReference();\n");
1876                }
1877
1878                my $numParameters = @{$function->parameters};
1879
1880                my $requiresAllArguments = $function->signature->extendedAttributes->{"RequiresAllArguments"};
1881                if ($requiresAllArguments) {
1882                    my $numMandatoryParams = @{$function->parameters};
1883                    foreach my $param (reverse(@{$function->parameters})) {
1884                        if ($param->extendedAttributes->{"Optional"}) {
1885                            $numMandatoryParams--;
1886                        } else {
1887                            last;
1888                        }
1889                    }
1890                    push(@implContent, "    if (exec->argumentCount() < $numMandatoryParams)\n");
1891                    if ($requiresAllArguments eq "Raise") {
1892                        push(@implContent, "        return throwVMError(exec, createSyntaxError(exec, \"Not enough arguments\"));\n");
1893                    } else {
1894                        push(@implContent, "        return JSValue::encode(jsUndefined());\n");
1895                    }
1896                }
1897
1898                if (@{$function->raisesExceptions}) {
1899                    push(@implContent, "    ExceptionCode ec = 0;\n");
1900                }
1901
1902                if ($function->signature->extendedAttributes->{"SVGCheckSecurityDocument"}) {
1903                    push(@implContent, "    if (!checkNodeSecurity(exec, imp->getSVGDocument(" . (@{$function->raisesExceptions} ? "ec" : "") .")))\n");
1904                    push(@implContent, "        return JSValue::encode(jsUndefined());\n");
1905                    $implIncludes{"JSDOMBinding.h"} = 1;
1906                }
1907
1908                if ($function->signature->name eq "addEventListener") {
1909                    push(@implContent, GenerateEventListenerCall($className, "add"));
1910                } elsif ($function->signature->name eq "removeEventListener") {
1911                    push(@implContent, GenerateEventListenerCall($className, "remove"));
1912                } else {
1913                    my $argsIndex = 0;
1914                    my $paramIndex = 0;
1915                    my $functionString = (($svgPropertyOrListPropertyType and !$svgListPropertyType) ? "podImp." : "imp->") . $functionImplementationName . "(";
1916                    my $hasOptionalArguments = 0;
1917
1918                    if ($function->signature->extendedAttributes->{"CustomArgumentHandling"}) {
1919                        push(@implContent, "    RefPtr<ScriptArguments> scriptArguments(createScriptArguments(exec, $numParameters));\n");
1920                        push(@implContent, "    size_t maxStackSize = imp->shouldCaptureFullStackTrace() ? ScriptCallStack::maxCallStackSizeToCapture : 1;\n");
1921                        push(@implContent, "    RefPtr<ScriptCallStack> callStack(createScriptCallStack(exec, maxStackSize));\n");
1922                        $implIncludes{"ScriptArguments.h"} = 1;
1923                        $implIncludes{"ScriptCallStack.h"} = 1;
1924                        $implIncludes{"ScriptCallStackFactory.h"} = 1;
1925                    }
1926
1927                    my $callWith = $function->signature->extendedAttributes->{"CallWith"};
1928                    if ($callWith) {
1929                        my $callWithArg = "COMPILE_ASSERT(false)";
1930                        if ($callWith eq "DynamicFrame") {
1931                            push(@implContent, "    Frame* dynamicFrame = toDynamicFrame(exec);\n");
1932                            push(@implContent, "    if (!dynamicFrame)\n");
1933                            push(@implContent, "        return JSValue::encode(jsUndefined());\n");
1934                            $callWithArg = "dynamicFrame";
1935                        } elsif ($callWith eq "ScriptState") {
1936                            $callWithArg = "exec";
1937                        } elsif ($callWith eq "ScriptExecutionContext") {
1938                            push(@implContent, "    ScriptExecutionContext* scriptContext = static_cast<JSDOMGlobalObject*>(exec->lexicalGlobalObject())->scriptExecutionContext();\n");
1939                            push(@implContent, "    if (!scriptContext)\n");
1940                            push(@implContent, "        return JSValue::encode(jsUndefined());\n");
1941                            $callWithArg = "scriptContext";
1942                        }
1943                        $functionString .= ", " if $paramIndex;
1944                        $functionString .= $callWithArg;
1945                        $paramIndex++;
1946                    }
1947
1948                    $implIncludes{"ExceptionCode.h"} = 1;
1949                    $implIncludes{"JSDOMBinding.h"} = 1;
1950                    foreach my $parameter (@{$function->parameters}) {
1951                        # Optional callbacks should be treated differently, because they always have a default value (0),
1952                        # and we can reduce the number of overloaded functions that take a different number of parameters.
1953                        if ($parameter->extendedAttributes->{"Optional"} && !$parameter->extendedAttributes->{"Callback"}) {
1954                            # Generate early call if there are enough parameters.
1955                            if (!$hasOptionalArguments) {
1956                                push(@implContent, "\n    int argsCount = exec->argumentCount();\n");
1957                                $hasOptionalArguments = 1;
1958                            }
1959                            push(@implContent, "    if (argsCount <= $argsIndex) {\n");
1960                            GenerateImplementationFunctionCall($function, $functionString, $paramIndex, "    " x 2, $svgPropertyType, $implClassName);
1961                            push(@implContent, "    }\n\n");
1962                        }
1963
1964                        my $name = $parameter->name;
1965                        my $argType = $codeGenerator->StripModule($parameter->type);
1966
1967                        if ($argType eq "XPathNSResolver") {
1968                            push(@implContent, "    RefPtr<XPathNSResolver> customResolver;\n");
1969                            push(@implContent, "    XPathNSResolver* resolver = toXPathNSResolver(exec->argument($argsIndex));\n");
1970                            push(@implContent, "    if (!resolver) {\n");
1971                            push(@implContent, "        customResolver = JSCustomXPathNSResolver::create(exec, exec->argument($argsIndex));\n");
1972                            push(@implContent, "        if (exec->hadException())\n");
1973                            push(@implContent, "            return JSValue::encode(jsUndefined());\n");
1974                            push(@implContent, "        resolver = customResolver.get();\n");
1975                            push(@implContent, "    }\n");
1976                        } elsif ($parameter->extendedAttributes->{"Callback"}) {
1977                            my $callbackClassName = GetCallbackClassName($argType);
1978                            $implIncludes{"$callbackClassName.h"} = 1;
1979                            if ($parameter->extendedAttributes->{"Optional"}) {
1980                                push(@implContent, "    RefPtr<$argType> $name;\n");
1981                                push(@implContent, "    if (exec->argumentCount() > $argsIndex && !exec->argument($argsIndex).isNull() && !exec->argument($argsIndex).isUndefined()) {\n");
1982                                push(@implContent, "        if (!exec->argument($argsIndex).isObject()) {\n");
1983                                push(@implContent, "            setDOMException(exec, TYPE_MISMATCH_ERR);\n");
1984                                push(@implContent, "            return JSValue::encode(jsUndefined());\n");
1985                                push(@implContent, "        }\n");
1986                                push(@implContent, "        $name = ${callbackClassName}::create(asObject(exec->argument($argsIndex)), castedThis->globalObject());\n");
1987                                push(@implContent, "    }\n");
1988                            } else {
1989                                push(@implContent, "    if (exec->argumentCount() <= $argsIndex || !exec->argument($argsIndex).isObject()) {\n");
1990                                push(@implContent, "        setDOMException(exec, TYPE_MISMATCH_ERR);\n");
1991                                push(@implContent, "        return JSValue::encode(jsUndefined());\n");
1992                                push(@implContent, "    }\n");
1993                                push(@implContent, "    RefPtr<$argType> $name = ${callbackClassName}::create(asObject(exec->argument($argsIndex)), castedThis->globalObject());\n");
1994                            }
1995                        } else {
1996                            # If the "StrictTypeChecking" extended attribute is present, and the argument's type is an
1997                            # interface type, then if the incoming value does not implement that interface, a TypeError
1998                            # is thrown rather than silently passing NULL to the C++ code.
1999                            # Per the Web IDL and ECMAScript semantics, incoming values can always be converted to both
2000                            # strings and numbers, so do not throw TypeError if the argument is of these types.
2001                            if ($function->signature->extendedAttributes->{"StrictTypeChecking"}) {
2002                                $implIncludes{"<runtime/Error.h>"} = 1;
2003
2004                                my $argValue = "exec->argument($argsIndex)";
2005                                if (!IsNativeType($argType)) {
2006                                    push(@implContent, "    if (exec->argumentCount() > $argsIndex && !${argValue}.isUndefinedOrNull() && !${argValue}.inherits(&JS${argType}::s_info))\n");
2007                                    push(@implContent, "        return throwVMTypeError(exec);\n");
2008                                }
2009                            }
2010
2011                            push(@implContent, "    " . GetNativeTypeFromSignature($parameter) . " $name(" . JSValueToNative($parameter, "exec->argument($argsIndex)") . ");\n");
2012
2013                            # If a parameter is "an index" and it's negative it should throw an INDEX_SIZE_ERR exception.
2014                            # But this needs to be done in the bindings, because the type is unsigned and the fact that it
2015                            # was negative will be lost by the time we're inside the DOM.
2016                            if ($parameter->extendedAttributes->{"IsIndex"}) {
2017                                push(@implContent, "    if ($name < 0) {\n");
2018                                push(@implContent, "        setDOMException(exec, INDEX_SIZE_ERR);\n");
2019                                push(@implContent, "        return JSValue::encode(jsUndefined());\n");
2020                                push(@implContent, "    }\n");
2021                            }
2022
2023                            # Check if the type conversion succeeded.
2024                            push(@implContent, "    if (exec->hadException())\n");
2025                            push(@implContent, "        return JSValue::encode(jsUndefined());\n");
2026
2027                            if ($codeGenerator->IsSVGTypeNeedingTearOff($argType) and not $implClassName =~ /List$/) {
2028                                push(@implContent, "    if (!$name) {\n");
2029                                push(@implContent, "        setDOMException(exec, TYPE_MISMATCH_ERR);\n");
2030                                push(@implContent, "        return JSValue::encode(jsUndefined());\n");
2031                                push(@implContent, "    }\n");
2032                            }
2033                        }
2034
2035                        $functionString .= ", " if $paramIndex;
2036
2037                        if ($argType eq "NodeFilter") {
2038                            $functionString .= "$name.get()";
2039                        } elsif ($codeGenerator->IsSVGTypeNeedingTearOff($argType) and not $implClassName =~ /List$/) {
2040                            $functionString .= "$name->propertyReference()";
2041                        } else {
2042                            $functionString .= $name;
2043                        }
2044                        $argsIndex++;
2045                        $paramIndex++;
2046                    }
2047
2048                    if ($function->signature->extendedAttributes->{"NeedsUserGestureCheck"}) {
2049                        $functionString .= ", " if $paramIndex;
2050                        $functionString .= "processingUserGesture()";
2051                        $paramIndex++;
2052                    }
2053
2054                    push(@implContent, "\n");
2055                    GenerateImplementationFunctionCall($function, $functionString, $paramIndex, "    ", $svgPropertyType, $implClassName);
2056                }
2057            }
2058            push(@implContent, "}\n\n");
2059
2060            if ($function->{overloads} && @{$function->{overloads}} > 1 && $function->{overloadIndex} == @{$function->{overloads}}) {
2061                # Generate a function dispatching call to the rest of the overloads.
2062                GenerateOverloadedPrototypeFunction($function, $dataNode, $implClassName);
2063            }
2064        }
2065    }
2066
2067    if ($numConstants > 0) {
2068        push(@implContent, "// Constant getters\n\n");
2069
2070        foreach my $constant (@{$dataNode->constants}) {
2071            my $getter = "js" . $interfaceName . $codeGenerator->WK_ucfirst($constant->name);
2072
2073            # FIXME: this casts into int to match our previous behavior which turned 0xFFFFFFFF in -1 for NodeFilter.SHOW_ALL
2074            push(@implContent, "JSValue ${getter}(ExecState* exec, JSValue, const Identifier&)\n");
2075            push(@implContent, "{\n");
2076            if ($constant->type eq "DOMString") {
2077                push(@implContent, "    return jsStringOrNull(exec, String(" . $constant->value . "));\n");
2078            } else {
2079                push(@implContent, "    UNUSED_PARAM(exec);\n");
2080                push(@implContent, "    return jsNumber(static_cast<int>(" . $constant->value . "));\n");
2081            }
2082            push(@implContent, "}\n\n");
2083        }
2084    }
2085
2086    if ($dataNode->extendedAttributes->{"HasIndexGetter"}) {
2087        push(@implContent, "\nJSValue ${className}::indexGetter(ExecState* exec, JSValue slotBase, unsigned index)\n");
2088        push(@implContent, "{\n");
2089        push(@implContent, "    ${className}* thisObj = static_cast<$className*>(asObject(slotBase));\n");
2090        if (IndexGetterReturnsStrings($implClassName)) {
2091            $implIncludes{"KURL.h"} = 1;
2092            push(@implContent, "    return jsStringOrNull(exec, thisObj->impl()->item(index));\n");
2093        } else {
2094            push(@implContent, "    return toJS(exec, thisObj->globalObject(), static_cast<$implClassName*>(thisObj->impl())->item(index));\n");
2095        }
2096        push(@implContent, "}\n\n");
2097        if ($interfaceName eq "HTMLCollection" or $interfaceName eq "HTMLAllCollection") {
2098            $implIncludes{"JSNode.h"} = 1;
2099            $implIncludes{"Node.h"} = 1;
2100        }
2101    }
2102
2103    if ($dataNode->extendedAttributes->{"HasNumericIndexGetter"}) {
2104        push(@implContent, "\nJSValue ${className}::getByIndex(ExecState*, unsigned index)\n");
2105        push(@implContent, "{\n");
2106        push(@implContent, "    return jsNumber(static_cast<$implClassName*>(impl())->item(index));\n");
2107        push(@implContent, "}\n\n");
2108        if ($interfaceName eq "HTMLCollection" or $interfaceName eq "HTMLAllCollection") {
2109            $implIncludes{"JSNode.h"} = 1;
2110            $implIncludes{"Node.h"} = 1;
2111        }
2112    }
2113
2114    if ((!$hasParent or $dataNode->extendedAttributes->{"GenerateToJS"}) and !$dataNode->extendedAttributes->{"CustomToJS"}) {
2115        if ($svgPropertyType) {
2116            push(@implContent, "JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, $implType* impl)\n");
2117        } else {
2118            push(@implContent, "JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, $implType* impl)\n");
2119        }
2120        push(@implContent, "{\n");
2121        if ($svgPropertyType) {
2122            push(@implContent, "    return wrap<$className, $implType>(exec, globalObject, impl);\n");
2123        } else {
2124            push(@implContent, "    return wrap<$className>(exec, globalObject, impl);\n");
2125        }
2126        push(@implContent, "}\n\n");
2127    }
2128
2129    if ((!$hasParent or $dataNode->extendedAttributes->{"GenerateNativeConverter"}) and !$dataNode->extendedAttributes->{"CustomNativeConverter"}) {
2130        push(@implContent, "$implType* to${interfaceName}(JSC::JSValue value)\n");
2131        push(@implContent, "{\n");
2132        push(@implContent, "    return value.inherits(&${className}::s_info) ? static_cast<$className*>(asObject(value))->impl() : 0");
2133        push(@implContent, ";\n}\n");
2134    }
2135
2136    push(@implContent, "\n}\n");
2137
2138    my $conditionalString = GenerateConditionalString($dataNode);
2139    push(@implContent, "\n#endif // ${conditionalString}\n") if $conditionalString;
2140}
2141
2142sub GenerateCallbackHeader
2143{
2144    my $object = shift;
2145    my $dataNode = shift;
2146
2147    my $interfaceName = $dataNode->name;
2148    my $className = "JS$interfaceName";
2149
2150    # - Add default header template and header protection
2151    push(@headerContentHeader, GenerateHeaderContentHeader($dataNode));
2152
2153    $headerIncludes{"ActiveDOMCallback.h"} = 1;
2154    $headerIncludes{"$interfaceName.h"} = 1;
2155    $headerIncludes{"JSCallbackData.h"} = 1;
2156    $headerIncludes{"<wtf/Forward.h>"} = 1;
2157
2158    push(@headerContent, "\nnamespace WebCore {\n\n");
2159    push(@headerContent, "class $className : public $interfaceName, public ActiveDOMCallback {\n");
2160    push(@headerContent, "public:\n");
2161
2162    # The static create() method.
2163    push(@headerContent, "    static PassRefPtr<$className> create(JSC::JSObject* callback, JSDOMGlobalObject* globalObject)\n");
2164    push(@headerContent, "    {\n");
2165    push(@headerContent, "        return adoptRef(new $className(callback, globalObject));\n");
2166    push(@headerContent, "    }\n\n");
2167
2168    # Destructor
2169    push(@headerContent, "    virtual ~$className();\n");
2170
2171    # Functions
2172    my $numFunctions = @{$dataNode->functions};
2173    if ($numFunctions > 0) {
2174        push(@headerContent, "\n    // Functions\n");
2175        foreach my $function (@{$dataNode->functions}) {
2176            my @params = @{$function->parameters};
2177            if (!$function->signature->extendedAttributes->{"Custom"} &&
2178                !(GetNativeType($function->signature->type) eq "bool")) {
2179                push(@headerContent, "    COMPILE_ASSERT(false)");
2180            }
2181
2182            push(@headerContent, "    virtual " . GetNativeType($function->signature->type) . " " . $function->signature->name . "(");
2183
2184            my @args = ();
2185            foreach my $param (@params) {
2186                push(@args, GetNativeType($param->type) . " " . $param->name);
2187            }
2188            push(@headerContent, join(", ", @args));
2189
2190            push(@headerContent, ");\n");
2191        }
2192    }
2193
2194    push(@headerContent, "\nprivate:\n");
2195
2196    # Constructor
2197    push(@headerContent, "    $className(JSC::JSObject* callback, JSDOMGlobalObject*);\n\n");
2198
2199    # Private members
2200    push(@headerContent, "    JSCallbackData* m_data;\n");
2201    push(@headerContent, "};\n\n");
2202
2203    push(@headerContent, "} // namespace WebCore\n\n");
2204    my $conditionalString = GenerateConditionalString($dataNode);
2205    push(@headerContent, "#endif // ${conditionalString}\n\n") if $conditionalString;
2206    push(@headerContent, "#endif\n");
2207}
2208
2209sub GenerateCallbackImplementation
2210{
2211    my ($object, $dataNode) = @_;
2212
2213    my $interfaceName = $dataNode->name;
2214    my $className = "JS$interfaceName";
2215
2216    # - Add default header template
2217    push(@implContentHeader, GenerateImplementationContentHeader($dataNode));
2218
2219    $implIncludes{"ScriptExecutionContext.h"} = 1;
2220    $implIncludes{"<runtime/JSLock.h>"} = 1;
2221    $implIncludes{"<wtf/MainThread.h>"} = 1;
2222
2223    @implContent = ();
2224
2225    push(@implContent, "\nusing namespace JSC;\n\n");
2226    push(@implContent, "namespace WebCore {\n\n");
2227
2228    # Constructor
2229    push(@implContent, "${className}::${className}(JSObject* callback, JSDOMGlobalObject* globalObject)\n");
2230    push(@implContent, "    : ActiveDOMCallback(globalObject->scriptExecutionContext())\n");
2231    push(@implContent, "    , m_data(new JSCallbackData(callback, globalObject))\n");
2232    push(@implContent, "{\n");
2233    push(@implContent, "}\n\n");
2234
2235    # Destructor
2236    push(@implContent, "${className}::~${className}()\n");
2237    push(@implContent, "{\n");
2238    push(@implContent, "    ScriptExecutionContext* context = scriptExecutionContext();\n");
2239    push(@implContent, "    // When the context is destroyed, all tasks with a reference to a callback\n");
2240    push(@implContent, "    // should be deleted. So if the context is 0, we are on the context thread.\n");
2241    push(@implContent, "    if (!context || context->isContextThread())\n");
2242    push(@implContent, "        delete m_data;\n");
2243    push(@implContent, "    else\n");
2244    push(@implContent, "        context->postTask(DeleteCallbackDataTask::create(m_data));\n");
2245    push(@implContent, "#ifndef NDEBUG\n");
2246    push(@implContent, "    m_data = 0;\n");
2247    push(@implContent, "#endif\n");
2248    push(@implContent, "}\n");
2249
2250    # Functions
2251    my $numFunctions = @{$dataNode->functions};
2252    if ($numFunctions > 0) {
2253        push(@implContent, "\n// Functions\n");
2254        foreach my $function (@{$dataNode->functions}) {
2255            my @params = @{$function->parameters};
2256            if ($function->signature->extendedAttributes->{"Custom"} ||
2257                !(GetNativeType($function->signature->type) eq "bool")) {
2258                next;
2259            }
2260
2261            AddIncludesForType($function->signature->type);
2262            push(@implContent, "\n" . GetNativeType($function->signature->type) . " ${className}::" . $function->signature->name . "(");
2263
2264            my @args = ();
2265            foreach my $param (@params) {
2266                AddIncludesForType($param->type, 1);
2267                push(@args, GetNativeType($param->type) . " " . $param->name);
2268            }
2269            push(@implContent, join(", ", @args));
2270            push(@implContent, ")\n");
2271
2272            push(@implContent, "{\n");
2273            push(@implContent, "    if (!canInvokeCallback())\n");
2274            push(@implContent, "        return true;\n\n");
2275            push(@implContent, "    RefPtr<$className> protect(this);\n\n");
2276            push(@implContent, "    JSLock lock(SilenceAssertionsOnly);\n\n");
2277            push(@implContent, "    ExecState* exec = m_data->globalObject()->globalExec();\n");
2278            push(@implContent, "    MarkedArgumentBuffer args;\n");
2279
2280            foreach my $param (@params) {
2281                my $paramName = $param->name;
2282                if ($param->type eq "DOMString") {
2283                    push(@implContent, "    args.append(jsString(exec, ${paramName}));\n");
2284                } else {
2285                    push(@implContent, "    args.append(toJS(exec, ${paramName}));\n");
2286                }
2287            }
2288
2289            push(@implContent, "\n    bool raisedException = false;\n");
2290            push(@implContent, "    m_data->invokeCallback(args, &raisedException);\n");
2291            push(@implContent, "    return !raisedException;\n");
2292            push(@implContent, "}\n");
2293        }
2294    }
2295
2296    push(@implContent, "\n}\n");
2297    my $conditionalString = GenerateConditionalString($dataNode);
2298    push(@implContent, "\n#endif // ${conditionalString}\n") if $conditionalString;
2299}
2300
2301sub GenerateImplementationFunctionCall()
2302{
2303    my $function = shift;
2304    my $functionString = shift;
2305    my $paramIndex = shift;
2306    my $indent = shift;
2307    my $svgPropertyType = shift;
2308    my $implClassName = shift;
2309
2310    if ($function->signature->extendedAttributes->{"CustomArgumentHandling"}) {
2311        $functionString .= ", " if $paramIndex;
2312        $paramIndex += 2;
2313        $functionString .= "scriptArguments, callStack";
2314    }
2315
2316    if (@{$function->raisesExceptions}) {
2317        $functionString .= ", " if $paramIndex;
2318        $functionString .= "ec";
2319    }
2320    $functionString .= ")";
2321
2322    if ($function->signature->type eq "void") {
2323        push(@implContent, $indent . "$functionString;\n");
2324        push(@implContent, $indent . "setDOMException(exec, ec);\n") if @{$function->raisesExceptions};
2325
2326        if ($svgPropertyType) {
2327            if (@{$function->raisesExceptions}) {
2328                push(@implContent, $indent . "if (!ec)\n");
2329                push(@implContent, $indent . "    imp->commitChange();\n");
2330            } else {
2331                push(@implContent, $indent . "imp->commitChange();\n");
2332            }
2333        }
2334
2335        push(@implContent, $indent . "return JSValue::encode(jsUndefined());\n");
2336    } else {
2337        push(@implContent, "\n" . $indent . "JSC::JSValue result = " . NativeToJSValue($function->signature, 1, $implClassName, $functionString, "castedThis") . ";\n");
2338        push(@implContent, $indent . "setDOMException(exec, ec);\n") if @{$function->raisesExceptions};
2339
2340        $callWith = $function->signature->extendedAttributes->{"CallWith"};
2341        if ($callWith and $callWith eq "ScriptState") {
2342            push(@implContent, $indent . "if (exec->hadException())\n");
2343            push(@implContent, $indent . "    return JSValue::encode(jsUndefined());\n");
2344        }
2345
2346        push(@implContent, $indent . "return JSValue::encode(result);\n");
2347    }
2348}
2349
2350sub GetNativeTypeFromSignature
2351{
2352    my $signature = shift;
2353    my $type = $codeGenerator->StripModule($signature->type);
2354
2355    if ($type eq "unsigned long" and $signature->extendedAttributes->{"IsIndex"}) {
2356        # Special-case index arguments because we need to check that they aren't < 0.
2357        return "int";
2358    }
2359
2360    return GetNativeType($type);
2361}
2362
2363my %nativeType = (
2364    "CompareHow" => "Range::CompareHow",
2365    "DOMString" => "const String&",
2366    "DOMObject" => "ScriptValue",
2367    "NodeFilter" => "RefPtr<NodeFilter>",
2368    "SerializedScriptValue" => "RefPtr<SerializedScriptValue>",
2369    "IDBKey" => "RefPtr<IDBKey>",
2370    "boolean" => "bool",
2371    "double" => "double",
2372    "float" => "float",
2373    "short" => "short",
2374    "long" => "int",
2375    "unsigned long" => "unsigned",
2376    "unsigned short" => "unsigned short",
2377    "long long" => "long long",
2378    "unsigned long long" => "unsigned long long",
2379    "MediaQueryListListener" => "RefPtr<MediaQueryListListener>"
2380);
2381
2382sub GetNativeType
2383{
2384    my $type = shift;
2385
2386    my $svgNativeType = $codeGenerator->GetSVGTypeNeedingTearOff($type);
2387    return "${svgNativeType}*" if $svgNativeType;
2388    return $nativeType{$type} if exists $nativeType{$type};
2389
2390    # For all other types, the native type is a pointer with same type name as the IDL type.
2391    return "${type}*";
2392}
2393
2394sub GetSVGPropertyTypes
2395{
2396    my $implType = shift;
2397
2398    my $svgPropertyType;
2399    my $svgListPropertyType;
2400    my $svgNativeType;
2401
2402    return ($svgPropertyType, $svgListPropertyType, $svgNativeType) if not $implType =~ /SVG/;
2403
2404    $svgNativeType = $codeGenerator->GetSVGTypeNeedingTearOff($implType);
2405    return ($svgPropertyType, $svgListPropertyType, $svgNativeType) if not $svgNativeType;
2406
2407    # Append space to avoid compilation errors when using  PassRefPtr<$svgNativeType>
2408    $svgNativeType = "$svgNativeType ";
2409
2410    my $svgWrappedNativeType = $codeGenerator->GetSVGWrappedTypeNeedingTearOff($implType);
2411    if ($svgNativeType =~ /SVGPropertyTearOff/) {
2412        $svgPropertyType = $svgWrappedNativeType;
2413        $headerIncludes{"$svgWrappedNativeType.h"} = 1;
2414        $headerIncludes{"SVGAnimatedPropertyTearOff.h"} = 1;
2415    } elsif ($svgNativeType =~ /SVGListPropertyTearOff/ or $svgNativeType =~ /SVGStaticListPropertyTearOff/) {
2416        $svgListPropertyType = $svgWrappedNativeType;
2417        $headerIncludes{"$svgWrappedNativeType.h"} = 1;
2418        $headerIncludes{"SVGAnimatedListPropertyTearOff.h"} = 1;
2419    } elsif ($svgNativeType =~ /SVGTransformListPropertyTearOff/) {
2420        $svgListPropertyType = $svgWrappedNativeType;
2421        $headerIncludes{"$svgWrappedNativeType.h"} = 1;
2422        $headerIncludes{"SVGAnimatedListPropertyTearOff.h"} = 1;
2423        $headerIncludes{"SVGTransformListPropertyTearOff.h"} = 1;
2424    } elsif ($svgNativeType =~ /SVGPathSegListPropertyTearOff/) {
2425        $svgListPropertyType = $svgWrappedNativeType;
2426        $headerIncludes{"$svgWrappedNativeType.h"} = 1;
2427        $headerIncludes{"SVGAnimatedListPropertyTearOff.h"} = 1;
2428        $headerIncludes{"SVGPathSegListPropertyTearOff.h"} = 1;
2429    }
2430
2431    return ($svgPropertyType, $svgListPropertyType, $svgNativeType);
2432}
2433
2434sub IsNativeType
2435{
2436    my $type = shift;
2437    return exists $nativeType{$type};
2438}
2439
2440sub JSValueToNative
2441{
2442    my $signature = shift;
2443    my $value = shift;
2444
2445    my $type = $codeGenerator->StripModule($signature->type);
2446
2447    return "$value.toBoolean(exec)" if $type eq "boolean";
2448    return "$value.toNumber(exec)" if $type eq "double";
2449    return "$value.toFloat(exec)" if $type eq "float";
2450    return "$value.toInt32(exec)" if $type eq "long" or $type eq "short";
2451    return "$value.toUInt32(exec)" if $type eq "unsigned long" or $type eq "unsigned short";
2452    return "static_cast<$type>($value.toInteger(exec))" if $type eq "long long" or $type eq "unsigned long long";
2453
2454    return "valueToDate(exec, $value)" if $type eq "Date";
2455    return "static_cast<Range::CompareHow>($value.toInt32(exec))" if $type eq "CompareHow";
2456
2457    if ($type eq "DOMString") {
2458        return "valueToStringWithNullCheck(exec, $value)" if $signature->extendedAttributes->{"ConvertNullToNullString"} || $signature->extendedAttributes->{"Reflect"};
2459        return "valueToStringWithUndefinedOrNullCheck(exec, $value)" if $signature->extendedAttributes->{"ConvertUndefinedOrNullToNullString"};
2460        return "ustringToString($value.toString(exec))";
2461    }
2462
2463    if ($type eq "DOMObject") {
2464        return "exec->globalData(), $value";
2465    }
2466
2467    if ($type eq "NodeFilter") {
2468        $implIncludes{"JS$type.h"} = 1;
2469        return "to$type(exec->globalData(), $value)";
2470    }
2471
2472    if ($type eq "MediaQueryListListener") {
2473        $implIncludes{"MediaQueryListListener.h"} = 1;
2474        return "MediaQueryListListener::create(ScriptValue(exec->globalData(), " . $value ."))";
2475    }
2476
2477    if ($type eq "SerializedScriptValue" or $type eq "any") {
2478        $implIncludes{"SerializedScriptValue.h"} = 1;
2479        return "SerializedScriptValue::create(exec, $value)";
2480    }
2481
2482    if ($type eq "IDBKey") {
2483        $implIncludes{"IDBBindingUtilities.h"} = 1;
2484        $implIncludes{"IDBKey.h"} = 1;
2485        return "createIDBKeyFromValue(exec, $value)";
2486    }
2487
2488    $implIncludes{"HTMLOptionElement.h"} = 1 if $type eq "HTMLOptionElement";
2489    $implIncludes{"JSCustomVoidCallback.h"} = 1 if $type eq "VoidCallback";
2490    $implIncludes{"Event.h"} = 1 if $type eq "Event";
2491
2492    # Default, assume autogenerated type conversion routines
2493    $implIncludes{"JS$type.h"} = 1;
2494    return "to$type($value)";
2495}
2496
2497sub NativeToJSValue
2498{
2499    my $signature = shift;
2500    my $inFunctionCall = shift;
2501    my $implClassName = shift;
2502    my $value = shift;
2503    my $thisValue = shift;
2504
2505    my $type = $codeGenerator->StripModule($signature->type);
2506
2507    return "jsBoolean($value)" if $type eq "boolean";
2508
2509    # Need to check Date type before IsPrimitiveType().
2510    if ($type eq "Date") {
2511        return "jsDateOrNull(exec, $value)";
2512    }
2513
2514    if ($signature->extendedAttributes->{"Reflect"} and ($type eq "unsigned long" or $type eq "unsigned short")) {
2515        $value =~ s/getUnsignedIntegralAttribute/getIntegralAttribute/g;
2516        return "jsNumber(std::max(0, " . $value . "))";
2517    }
2518
2519    if ($codeGenerator->IsPrimitiveType($type) or $type eq "DOMTimeStamp") {
2520        return "jsNumber($value)";
2521    }
2522
2523    if ($codeGenerator->IsStringType($type)) {
2524        $implIncludes{"KURL.h"} = 1;
2525        my $conv = $signature->extendedAttributes->{"ConvertNullStringTo"};
2526        if (defined $conv) {
2527            return "jsStringOrNull(exec, $value)" if $conv eq "Null";
2528            return "jsStringOrUndefined(exec, $value)" if $conv eq "Undefined";
2529            return "jsStringOrFalse(exec, $value)" if $conv eq "False";
2530
2531            die "Unknown value for ConvertNullStringTo extended attribute";
2532        }
2533        $conv = $signature->extendedAttributes->{"ConvertScriptString"};
2534        return "jsOwnedStringOrNull(exec, $value)" if $conv;
2535        $implIncludes{"<runtime/JSString.h>"} = 1;
2536        return "jsString(exec, $value)";
2537    }
2538
2539    my $globalObject = "$thisValue->globalObject()";
2540
2541    if ($type eq "CSSStyleDeclaration") {
2542        $implIncludes{"CSSMutableStyleDeclaration.h"} = 1;
2543    }
2544
2545    if ($type eq "NodeList") {
2546        $implIncludes{"NameNodeList.h"} = 1;
2547    }
2548
2549    if ($type eq "DOMObject") {
2550        if ($implClassName eq "Document") {
2551            $implIncludes{"JSCanvasRenderingContext2D.h"} = 1;
2552        } else {
2553            return "$value.jsValue();";
2554        }
2555    } elsif ($type =~ /SVGPathSeg/) {
2556        $implIncludes{"JS$type.h"} = 1;
2557        $joinedName = $type;
2558        $joinedName =~ s/Abs|Rel//;
2559        $implIncludes{"$joinedName.h"} = 1;
2560    } elsif ($type eq "SerializedScriptValue" or $type eq "any") {
2561        $implIncludes{"SerializedScriptValue.h"} = 1;
2562        return "$value ? $value->deserialize(exec, castedThis->globalObject()) : jsNull()";
2563    } else {
2564        # Default, include header with same name.
2565        $implIncludes{"JS$type.h"} = 1;
2566        $implIncludes{"$type.h"} = 1 if not $codeGenerator->AvoidInclusionOfType($type);
2567    }
2568
2569    return $value if $codeGenerator->IsSVGAnimatedType($type);
2570
2571    if ($signature->extendedAttributes->{"ReturnsNew"}) {
2572        return "toJSNewlyCreated(exec, $globalObject, WTF::getPtr($value))";
2573    }
2574
2575    if ($codeGenerator->IsSVGAnimatedType($implClassName)) {
2576        # Convert from abstract SVGProperty to real type, so the right toJS() method can be invoked.
2577        $value = "static_cast<" . GetNativeType($type) . ">($value)";
2578    } elsif ($codeGenerator->IsSVGTypeNeedingTearOff($type) and not $implClassName =~ /List$/) {
2579        my $tearOffType = $codeGenerator->GetSVGTypeNeedingTearOff($type);
2580        if ($codeGenerator->IsSVGTypeWithWritablePropertiesNeedingTearOff($type) and $inFunctionCall eq 0 and not defined $signature->extendedAttributes->{"Immutable"}) {
2581            my $getter = $value;
2582            $getter =~ s/imp\.//;
2583            $getter =~ s/imp->//;
2584            $getter =~ s/\(\)//;
2585            my $updateMethod = "&${implClassName}::update" . $codeGenerator->WK_ucfirst($getter);
2586
2587            my $selfIsTearOffType = $codeGenerator->IsSVGTypeNeedingTearOff($implClassName);
2588            if ($selfIsTearOffType) {
2589                $implIncludes{"SVGStaticPropertyWithParentTearOff.h"} = 1;
2590                $tearOffType =~ s/SVGPropertyTearOff</SVGStaticPropertyWithParentTearOff<$implClassName, /;
2591
2592                if ($value =~ /matrix/ and $implClassName eq "SVGTransform") {
2593                    # SVGTransform offers a matrix() method for internal usage that returns an AffineTransform
2594                    # and a svgMatrix() method returning a SVGMatrix, used for the bindings.
2595                    $value =~ s/matrix/svgMatrix/;
2596                }
2597
2598                $value = "${tearOffType}::create(castedThis->impl(), $value, $updateMethod)";
2599            } else {
2600                $implIncludes{"SVGStaticPropertyTearOff.h"} = 1;
2601                $tearOffType =~ s/SVGPropertyTearOff</SVGStaticPropertyTearOff<$implClassName, /;
2602                $value = "${tearOffType}::create(imp, $value, $updateMethod)";
2603            }
2604        } elsif ($tearOffType =~ /SVGStaticListPropertyTearOff/) {
2605            my $extraImp = "GetOwnerElementForType<$implClassName, IsDerivedFromSVGElement<$implClassName>::value>::ownerElement(imp), ";
2606            $value = "${tearOffType}::create($extraImp$value)";
2607        } elsif (not $tearOffType =~ /SVG(Point|PathSeg)List/) {
2608            $value = "${tearOffType}::create($value)";
2609        }
2610    }
2611
2612    return "toJS(exec, $globalObject, WTF::getPtr($value))";
2613}
2614
2615sub ceilingToPowerOf2
2616{
2617    my ($size) = @_;
2618
2619    my $powerOf2 = 1;
2620    while ($size > $powerOf2) {
2621        $powerOf2 <<= 1;
2622    }
2623
2624    return $powerOf2;
2625}
2626
2627# Internal Helper
2628sub GenerateHashTable
2629{
2630    my $object = shift;
2631
2632    my $name = shift;
2633    my $size = shift;
2634    my $keys = shift;
2635    my $specials = shift;
2636    my $value1 = shift;
2637    my $value2 = shift;
2638    my $conditionals = shift;
2639
2640    # Generate size data for compact' size hash table
2641
2642    my @table = ();
2643    my @links = ();
2644
2645    my $compactSize = ceilingToPowerOf2($size * 2);
2646
2647    my $maxDepth = 0;
2648    my $collisions = 0;
2649    my $numEntries = $compactSize;
2650
2651    my $i = 0;
2652    foreach (@{$keys}) {
2653        my $depth = 0;
2654        my $h = $object->GenerateHashValue($_) % $numEntries;
2655
2656        while (defined($table[$h])) {
2657            if (defined($links[$h])) {
2658                $h = $links[$h];
2659                $depth++;
2660            } else {
2661                $collisions++;
2662                $links[$h] = $compactSize;
2663                $h = $compactSize;
2664                $compactSize++;
2665            }
2666        }
2667
2668        $table[$h] = $i;
2669
2670        $i++;
2671        $maxDepth = $depth if ($depth > $maxDepth);
2672    }
2673
2674    # Start outputing the hashtables
2675    my $nameEntries = "${name}Values";
2676    $nameEntries =~ s/:/_/g;
2677
2678    if (($name =~ /Prototype/) or ($name =~ /Constructor/)) {
2679        my $type = $name;
2680        my $implClass;
2681
2682        if ($name =~ /Prototype/) {
2683            $type =~ s/Prototype.*//;
2684            $implClass = $type; $implClass =~ s/Wrapper$//;
2685            push(@implContent, "/* Hash table for prototype */\n");
2686        } else {
2687            $type =~ s/Constructor.*//;
2688            $implClass = $type; $implClass =~ s/Constructor$//;
2689            push(@implContent, "/* Hash table for constructor */\n");
2690        }
2691    } else {
2692        push(@implContent, "/* Hash table */\n");
2693    }
2694
2695    # Dump the hash table
2696    my $count = scalar @{$keys} + 1;
2697    push(@implContent, "#if ENABLE(JIT)\n");
2698    push(@implContent, "#define THUNK_GENERATOR(generator) , generator\n");
2699    push(@implContent, "#else\n");
2700    push(@implContent, "#define THUNK_GENERATOR(generator)\n");
2701    push(@implContent, "#endif\n");
2702    push(@implContent, "\nstatic const HashTableValue $nameEntries\[$count\] =\n\{\n");
2703    $i = 0;
2704    foreach my $key (@{$keys}) {
2705        my $conditional;
2706        my $targetType;
2707
2708        if ($conditionals) {
2709            $conditional = $conditionals->{$key};
2710        }
2711        if ($conditional) {
2712            my $conditionalString = GenerateConditionalStringFromAttributeValue($conditional);
2713            push(@implContent, "#if ${conditionalString}\n");
2714        }
2715
2716        if ("@$specials[$i]" =~ m/Function/) {
2717            $targetType = "static_cast<NativeFunction>";
2718        } else {
2719            $targetType = "static_cast<PropertySlot::GetValueFunc>";
2720        }
2721        push(@implContent, "    { \"$key\", @$specials[$i], (intptr_t)" . $targetType . "(@$value1[$i]), (intptr_t)@$value2[$i] THUNK_GENERATOR(0) },\n");
2722        if ($conditional) {
2723            push(@implContent, "#endif\n");
2724        }
2725        ++$i;
2726    }
2727    push(@implContent, "    { 0, 0, 0, 0 THUNK_GENERATOR(0) }\n");
2728    push(@implContent, "};\n\n");
2729    push(@implContent, "#undef THUNK_GENERATOR\n");
2730    my $compactSizeMask = $numEntries - 1;
2731    push(@implContent, "static JSC_CONST_HASHTABLE HashTable $name = { $compactSize, $compactSizeMask, $nameEntries, 0 };\n");
2732}
2733
2734# Internal helper
2735sub GenerateHashValue
2736{
2737    my $object = shift;
2738
2739    @chars = split(/ */, $_[0]);
2740
2741    # This hash is designed to work on 16-bit chunks at a time. But since the normal case
2742    # (above) is to hash UTF-16 characters, we just treat the 8-bit chars as if they
2743    # were 16-bit chunks, which should give matching results
2744
2745    my $EXP2_32 = 4294967296;
2746
2747    my $hash = 0x9e3779b9;
2748    my $l    = scalar @chars; #I wish this was in Ruby --- Maks
2749    my $rem  = $l & 1;
2750    $l = $l >> 1;
2751
2752    my $s = 0;
2753
2754    # Main loop
2755    for (; $l > 0; $l--) {
2756        $hash   += ord($chars[$s]);
2757        my $tmp = leftShift(ord($chars[$s+1]), 11) ^ $hash;
2758        $hash   = (leftShift($hash, 16)% $EXP2_32) ^ $tmp;
2759        $s += 2;
2760        $hash += $hash >> 11;
2761        $hash %= $EXP2_32;
2762    }
2763
2764    # Handle end case
2765    if ($rem != 0) {
2766        $hash += ord($chars[$s]);
2767        $hash ^= (leftShift($hash, 11)% $EXP2_32);
2768        $hash += $hash >> 17;
2769    }
2770
2771    # Force "avalanching" of final 127 bits
2772    $hash ^= leftShift($hash, 3);
2773    $hash += ($hash >> 5);
2774    $hash = ($hash% $EXP2_32);
2775    $hash ^= (leftShift($hash, 2)% $EXP2_32);
2776    $hash += ($hash >> 15);
2777    $hash = $hash% $EXP2_32;
2778    $hash ^= (leftShift($hash, 10)% $EXP2_32);
2779
2780    # this avoids ever returning a hash code of 0, since that is used to
2781    # signal "hash not computed yet", using a value that is likely to be
2782    # effectively the same as 0 when the low bits are masked
2783    $hash = 0x80000000 if ($hash == 0);
2784
2785    return $hash;
2786}
2787
2788# Internal helper
2789sub WriteData
2790{
2791    if (defined($IMPL)) {
2792        # Write content to file.
2793        print $IMPL @implContentHeader;
2794
2795        my @includes = ();
2796        foreach my $include (keys %implIncludes) {
2797            my $checkType = $include;
2798            $checkType =~ s/\.h//;
2799            next if $codeGenerator->IsSVGAnimatedType($checkType);
2800
2801            $include = "\"$include\"" unless $include =~ /^["<]/; # "
2802            push @includes, $include;
2803        }
2804        foreach my $include (sort @includes) {
2805            print $IMPL "#include $include\n";
2806        }
2807
2808        print $IMPL @implContent;
2809        close($IMPL);
2810        undef($IMPL);
2811
2812        @implContentHeader = ();
2813        @implContent = ();
2814        %implIncludes = ();
2815    }
2816
2817    if (defined($HEADER)) {
2818        # Write content to file.
2819        print $HEADER @headerContentHeader;
2820
2821        my @includes = ();
2822        foreach my $include (keys %headerIncludes) {
2823            $include = "\"$include\"" unless $include =~ /^["<]/; # "
2824            push @includes, $include;
2825        }
2826        foreach my $include (sort @includes) {
2827            print $HEADER "#include $include\n";
2828        }
2829
2830        print $HEADER @headerContent;
2831
2832        @includes = ();
2833        foreach my $include (keys %headerTrailingIncludes) {
2834            $include = "\"$include\"" unless $include =~ /^["<]/; # "
2835            push @includes, $include;
2836        }
2837        foreach my $include (sort @includes) {
2838            print $HEADER "#include $include\n";
2839        }
2840
2841        close($HEADER);
2842        undef($HEADER);
2843
2844        @headerContentHeader = ();
2845        @headerContent = ();
2846        %headerIncludes = ();
2847        %headerTrailingIncludes = ();
2848    }
2849
2850    if (defined($DEPS)) {
2851        # Write dependency file.
2852        print $DEPS @depsContent;
2853        close($DEPS);
2854        undef($DEPS);
2855
2856        @depsContent = ();
2857    }
2858}
2859
2860sub GenerateConstructorDeclaration
2861{
2862    my $outputArray = shift;
2863    my $className = shift;
2864    my $dataNode = shift;
2865
2866    my $constructorClassName = "${className}Constructor";
2867    my $canConstruct = $dataNode->extendedAttributes->{"CanBeConstructed"};
2868    my $callWith = $dataNode->extendedAttributes->{"CallWith"};
2869
2870    push(@$outputArray, "class ${constructorClassName} : public DOMConstructorObject {\n");
2871    push(@$outputArray, "public:\n");
2872    push(@$outputArray, "    ${constructorClassName}(JSC::ExecState*, JSDOMGlobalObject*);\n\n");
2873
2874    push(@$outputArray, "    virtual bool getOwnPropertySlot(JSC::ExecState*, const JSC::Identifier&, JSC::PropertySlot&);\n");
2875    push(@$outputArray, "    virtual bool getOwnPropertyDescriptor(JSC::ExecState*, const JSC::Identifier&, JSC::PropertyDescriptor&);\n");
2876    push(@$outputArray, "    static const JSC::ClassInfo s_info;\n");
2877
2878    push(@$outputArray, "    static JSC::Structure* createStructure(JSC::JSGlobalData& globalData, JSC::JSValue prototype)\n");
2879    push(@$outputArray, "    {\n");
2880    push(@$outputArray, "        return JSC::Structure::create(globalData, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), AnonymousSlotCount, &s_info);\n");
2881    push(@$outputArray, "    }\n");
2882
2883    push(@$outputArray, "protected:\n");
2884    push(@$outputArray, "    static const unsigned StructureFlags = JSC::OverridesGetOwnPropertySlot | JSC::ImplementsHasInstance | DOMConstructorObject::StructureFlags;\n");
2885
2886    if ($canConstruct) {
2887        push(@$outputArray, "    static JSC::EncodedJSValue JSC_HOST_CALL construct${className}(JSC::ExecState*);\n");
2888        push(@$outputArray, "    virtual JSC::ConstructType getConstructData(JSC::ConstructData&);\n");
2889    }
2890    push(@$outputArray, "};\n\n");
2891}
2892
2893sub GenerateConstructorDefinition
2894{
2895    my $outputArray = shift;
2896
2897    my $className = shift;
2898    my $protoClassName = shift;
2899    my $interfaceName = shift;
2900    my $visibleClassName = shift;
2901    my $dataNode = shift;
2902
2903    my $constructorClassName = "${className}Constructor";
2904    my $canConstruct = $dataNode->extendedAttributes->{"CanBeConstructed"};
2905    my $customConstructFunction = $dataNode->extendedAttributes->{"CustomConstructFunction"};
2906    my $callWith = $dataNode->extendedAttributes->{"CallWith"};
2907    my $numberOfconstructParameters = $dataNode->extendedAttributes->{"ConstructorParameters"};
2908
2909    push(@$outputArray, "const ClassInfo ${constructorClassName}::s_info = { \"${visibleClassName}Constructor\", &DOMConstructorObject::s_info, &${constructorClassName}Table, 0 };\n\n");
2910
2911    push(@$outputArray, "${constructorClassName}::${constructorClassName}(ExecState* exec, JSDOMGlobalObject* globalObject)\n");
2912    push(@$outputArray, "    : DOMConstructorObject(${constructorClassName}::createStructure(globalObject->globalData(), globalObject->objectPrototype()), globalObject)\n");
2913    push(@$outputArray, "{\n");
2914    push(@$outputArray, "    ASSERT(inherits(&s_info));\n");
2915    if ($interfaceName eq "DOMWindow") {
2916        push(@$outputArray, "    putDirect(exec->globalData(), exec->propertyNames().prototype, globalObject->prototype(), DontDelete | ReadOnly);\n");
2917    } else {
2918        push(@$outputArray, "    putDirect(exec->globalData(), exec->propertyNames().prototype, ${protoClassName}::self(exec, globalObject), DontDelete | ReadOnly);\n");
2919    }
2920    push(@$outputArray, "    putDirect(exec->globalData(), exec->propertyNames().length, jsNumber(${numberOfconstructParameters}), ReadOnly | DontDelete | DontEnum);\n") if $numberOfconstructParameters;
2921    push(@$outputArray, "}\n\n");
2922
2923    push(@$outputArray, "bool ${constructorClassName}::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)\n");
2924    push(@$outputArray, "{\n");
2925    push(@$outputArray, "    return getStaticValueSlot<${constructorClassName}, JSDOMWrapper>(exec, &${constructorClassName}Table, this, propertyName, slot);\n");
2926    push(@$outputArray, "}\n\n");
2927
2928    push(@$outputArray, "bool ${constructorClassName}::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)\n");
2929    push(@$outputArray, "{\n");
2930    push(@$outputArray, "    return getStaticValueDescriptor<${constructorClassName}, JSDOMWrapper>(exec, &${constructorClassName}Table, this, propertyName, descriptor);\n");
2931    push(@$outputArray, "}\n\n");
2932
2933    if ($canConstruct) {
2934        if (!$customConstructFunction) {
2935            push(@$outputArray, "EncodedJSValue JSC_HOST_CALL ${constructorClassName}::construct${className}(ExecState* exec)\n");
2936            push(@$outputArray, "{\n");
2937            my $constructorArg = "";
2938            if ($callWith and $callWith eq "ScriptExecutionContext") {
2939                $constructorArg = "context";
2940                push(@$outputArray, "    ScriptExecutionContext* context = static_cast<${constructorClassName}*>(exec->callee())->scriptExecutionContext();\n");
2941                push(@$outputArray, "    if (!context)\n");
2942                push(@$outputArray, "        return throwVMError(exec, createReferenceError(exec, \"Reference error\"));\n");
2943            }
2944            push(@$outputArray, "    return JSValue::encode(asObject(toJS(exec, static_cast<${constructorClassName}*>(exec->callee())->globalObject(), ${interfaceName}::create(${constructorArg}))));\n");
2945            push(@$outputArray, "}\n\n");
2946        }
2947
2948        push(@$outputArray, "ConstructType ${constructorClassName}::getConstructData(ConstructData& constructData)\n");
2949        push(@$outputArray, "{\n");
2950        push(@$outputArray, "    constructData.native.function = construct${className};\n");
2951        push(@$outputArray, "    return ConstructTypeHost;\n");
2952        push(@$outputArray, "}\n\n");
2953    }
2954}
2955
29561;
2957