
# Copyright (C) 2005, 2006 Nikolas Zimmermann <zimmermann@kde.org>
# Copyright (C) 2006 Anders Carlsson <andersca@mac.com>
# Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
# Copyright (C) 2006 Alexey Proskuryakov <ap@webkit.org>
# Copyright (C) 2006 Apple Computer, Inc.
# Copyright (C) 2007, 2008, 2009 Google Inc.
# Copyright (C) 2009 Cameron McCormack <cam@mcc.id.au>
#
# This file is part of the KDE project
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Library General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Library General Public License for more details.
#
# You should have received a copy of the GNU Library General Public License
# aint with this library; see the file COPYING.LIB.  If not, write to
# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA.
#

package CodeGeneratorV8;

use File::stat;
use Digest::MD5;

my $module = "";
my $outputDir = "";

my @headerContent = ();
my @implContentHeader = ();
my @implFixedHeader = ();
my @implContent = ();
my @implContentDecls = ();
my %implIncludes = ();

my @allParents = ();

# Default .h template
my $headerTemplate = << "EOF";
/*
    This file is part of the WebKit open source project.
    This file has been generated by generate-bindings.pl. DO NOT MODIFY!

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.
*/
EOF

# Default constructor
sub new
{
    my $object = shift;
    my $reference = { };

    $codeGenerator = shift;
    $outputDir = shift;

    bless($reference, $object);
    return $reference;
}

sub finish
{
    my $object = shift;

    # Commit changes!
    $object->WriteData();
}

sub leftShift($$) {
    my ($value, $distance) = @_;
    return (($value << $distance) & 0xFFFFFFFF);
}

# Workaround for V8 bindings difference where RGBColor is not a POD type.
sub IsPodType
{
    my $type = shift;
    return $codeGenerator->IsPodType($type);
}

# Params: 'domClass' struct
sub GenerateInterface
{
    my $object = shift;
    my $dataNode = shift;
    my $defines = shift;

    # Start actual generation
    $object->GenerateHeader($dataNode);
    $object->GenerateImplementation($dataNode);

    my $name = $dataNode->name;

    # Open files for writing
    my $headerFileName = "$outputDir/V8$name.h";
    my $implFileName = "$outputDir/V8$name.cpp";

    open($IMPL, ">$implFileName") || die "Couldn't open file $implFileName";
    open($HEADER, ">$headerFileName") || die "Couldn't open file $headerFileName";
}

# Params: 'idlDocument' struct
sub GenerateModule
{
    my $object = shift;
    my $dataNode = shift;

    $module = $dataNode->module;
}

sub GetLegacyHeaderIncludes
{
    my $legacyParent = shift;

    die "Don't know what headers to include for module $module";
}

sub AvoidInclusionOfType
{
    my $type = shift;

    # Special case: SVGRect.h / SVGPoint.h / SVGNumber.h / SVGMatrix.h do not exist.
    return 1 if $type eq "SVGRect" or $type eq "SVGPoint" or $type eq "SVGNumber" or $type eq "SVGMatrix";
    return 0;
}

sub UsesManualToJSImplementation
{
    my $type = shift;

    return 1 if $type eq "SVGPathSeg";
    return 0;
}

sub AddIncludesForType
{
    my $type = $codeGenerator->StripModule(shift);

    # When we're finished with the one-file-per-class
    # reorganization, we won't need these special cases.
    if ($codeGenerator->IsPrimitiveType($type) or AvoidInclusionOfType($type)) {
    } elsif ($type =~ /SVGPathSeg/) {
        $joinedName = $type;
        $joinedName =~ s/Abs|Rel//;
        $implIncludes{"${joinedName}.h"} = 1;
    } else {
        # default, include the same named file
        $implIncludes{GetImplementationFileName(${type})} = 1;
    }

    # additional includes (things needed to compile the bindings but not the header)

    if ($type eq "CanvasRenderingContext2D") {
        $implIncludes{"CanvasGradient.h"} = 1;
        $implIncludes{"CanvasPattern.h"} = 1;
        $implIncludes{"CanvasStyle.h"} = 1;
    }

    if ($type eq "CanvasGradient" or $type eq "XPathNSResolver") {
        $implIncludes{"PlatformString.h"} = 1;
    }

    if ($type eq "CSSStyleDeclaration") {
        $implIncludes{"CSSMutableStyleDeclaration.h"} = 1;
    }

    if ($type eq "Plugin" or $type eq "PluginArray" or $type eq "MimeTypeArray") {
        # So we can get String -> AtomicString conversion for namedItem().
        $implIncludes{"AtomicString.h"} = 1;
    }
}

sub AddIncludesForSVGAnimatedType
{
    my $type = shift;
    $type =~ s/SVGAnimated//;

    if ($type eq "Point" or $type eq "Rect") {
        $implIncludes{"Float$type.h"} = 1;
    } elsif ($type eq "String") {
        $implIncludes{"PlatformString.h"} = 1;
    }

    $implIncludes{"SVGAnimatedTemplate.h"} = 1;
}

sub AddClassForwardIfNeeded
{
    my $implClassName = shift;

    # SVGAnimatedLength/Number/etc.. are typedefs to SVGAnimtatedTemplate, so don't use class forwards for them!
    push(@headerContent, "class $implClassName;\n\n") unless $codeGenerator->IsSVGAnimatedType($implClassName);
}

sub GetImplementationFileName
{
    my $iface = shift;
    return "HTMLCollection.h" if $iface eq "HTMLAllCollection";
    return "Event.h" if $iface eq "DOMTimeStamp";
    return "NamedAttrMap.h" if $iface eq "NamedNodeMap";
    return "NameNodeList.h" if $iface eq "NodeList";
    return "XMLHttpRequest.h" if $iface eq "XMLHttpRequest";

    return "${iface}.h";
}

# If the node has a [Conditional=XXX] attribute, returns an "ENABLE(XXX)" string for use in an #if.
sub GenerateConditionalString
{
    my $node = shift;
    my $conditional = $node->extendedAttributes->{"Conditional"};
    if ($conditional) {
        return "ENABLE(" . join(") && ENABLE(", split(/&/, $conditional)) . ")";
    } else {
        return "";
    }
}

sub GenerateHeader
{
    my $object = shift;
    my $dataNode = shift;

    my $interfaceName = $dataNode->name;
    my $className = "V8$interfaceName";
    my $implClassName = $interfaceName;

    # Copy contents of parent classes except the first parent or if it is
    # EventTarget.
    $codeGenerator->AddMethodsConstantsAndAttributesFromParentClasses($dataNode, \@allParents, 1);

    my $hasLegacyParent = $dataNode->extendedAttributes->{"LegacyParent"};
    my $conditionalString = GenerateConditionalString($dataNode);

    # - Add default header template
    @headerContent = split("\r", $headerTemplate);

    push(@headerContent, "\n#if ${conditionalString}\n\n") if $conditionalString;
    push(@headerContent, "\n#ifndef $className" . "_H");
    push(@headerContent, "\n#define $className" . "_H\n\n");

    # Get correct pass/store types respecting PODType flag
    my $podType = $dataNode->extendedAttributes->{"PODType"};
    my $passType = $podType ? "JSSVGPODTypeWrapper<$podType>*" : "$implClassName*";

    push(@headerContent, "#include \"$podType.h\"\n") if $podType and ($podType ne "double" and $podType ne "float" and $podType ne "RGBA32");

    push(@headerContent, "#include <v8.h>\n");
    push(@headerContent, "#include <wtf/HashMap.h>\n");
    push(@headerContent, "#include \"StringHash.h\"\n");

    push(@headerContent, "\nnamespace WebCore {\n\n");
    push(@headerContent, "class V8ClassIndex;\n");
    push(@headerContent, "\nclass $className {\n");
    push(@headerContent, <<END);

 public:
  static bool HasInstance(v8::Handle<v8::Value> value);
  static v8::Persistent<v8::FunctionTemplate> GetRawTemplate();
END

    if ($implClassName eq "DOMWindow") {
      push(@headerContent, <<END);
  static v8::Persistent<v8::ObjectTemplate> GetShadowObjectTemplate();
END
    }

    push(@headerContent, <<END);

 private:
  static v8::Persistent<v8::FunctionTemplate> GetTemplate();

  friend class V8ClassIndex;
};

END

    push(@headerContent, "}\n\n");
    push(@headerContent, "#endif // $className" . "_H\n");

    push(@headerContent, "#endif // ${conditionalString}\n\n") if $conditionalString;
}


sub GenerateSetDOMException
{
    my $indent = shift;
    my $result = "";

    $result .= $indent . "if (ec) {\n";
    $result .= $indent . "    V8Proxy::setDOMException(ec);\n";
    $result .= $indent . "    return v8::Handle<v8::Value>();\n";
    $result .= $indent . "}\n";

    return $result;
}

sub IsNodeSubType
{
    my $dataNode = shift;
    return 1 if ($dataNode->name eq "Node");
    foreach (@allParents) {
        my $parent = $codeGenerator->StripModule($_);
        return 1 if $parent eq "Node";
    }
    return 0;
}

sub GetHiddenDependencyIndex
{
    my $dataNode = shift;
    my $attribute = shift;
    my $name = $dataNode->name;
    return "V8Custom::kNodeEventListenerCacheIndex" if IsNodeSubType($dataNode);
    return "V8Custom::kSVGElementInstanceEventListenerCacheIndex" if $name eq "SVGElementInstance";
    return "V8Custom::kAbstractWorkerRequestCacheIndex" if $name eq "AbstractWorker";
    return "V8Custom::kWorkerRequestCacheIndex" if $name eq "Worker";
    return "V8Custom::kDedicatedWorkerContextRequestCacheIndex" if $name eq "DedicatedWorkerContext";
    return "V8Custom::kWorkerContextRequestCacheIndex" if $name eq "WorkerContext";
    return "V8Custom::kWorkerContextRequestCacheIndex" if $name eq "SharedWorkerContext";
    return "V8Custom::kMessagePortRequestCacheIndex" if $name eq "MessagePort";
    return "V8Custom::kWebSocketCacheIndex" if $name eq "WebSocket";
    return "V8Custom::kXMLHttpRequestCacheIndex" if $name eq "XMLHttpRequest";
    return "V8Custom::kXMLHttpRequestCacheIndex" if $name eq "XMLHttpRequestUpload";
    return "V8Custom::kDOMApplicationCacheCacheIndex" if $name eq "DOMApplicationCache";
    return "V8Custom::kNotificationRequestCacheIndex" if $name eq "Notification";
    return "V8Custom::kDOMWindowEventListenerCacheIndex" if $name eq "DOMWindow";
    die "Unexpected name " . $name . " when generating " . $attribute;
}

sub HolderToNative
{
    my $dataNode = shift;
    my $implClassName = shift;
    my $classIndex = shift;

    if (IsNodeSubType($dataNode)) {
        push(@implContentDecls, <<END);
    $implClassName* imp = V8DOMWrapper::convertDOMWrapperToNode<$implClassName>(holder);
END

    } else {
        push(@implContentDecls, <<END);
    $implClassName* imp = V8DOMWrapper::convertToNativeObject<$implClassName>(V8ClassIndex::$classIndex, holder);
END

  }
}

sub GenerateDomainSafeFunctionGetter
{
    my $function = shift;
    my $dataNode = shift;
    my $classIndex = shift;
    my $implClassName = shift;

    my $className = "V8" . $dataNode->name;
    my $funcName = $function->signature->name;

    my $signature = "v8::Signature::New(" . $className . "::GetRawTemplate())";
    if ($function->signature->extendedAttributes->{"V8DoNotCheckSignature"}) {
        $signature = "v8::Local<v8::Signature>()";
    }

    my $newTemplateString = GenerateNewFunctionTemplate($function, $dataNode, $signature);

    $implIncludes{"V8Proxy.h"} = 1;

    push(@implContentDecls, <<END);
  static v8::Handle<v8::Value> ${funcName}AttrGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info) {
    INC_STATS(\"DOM.$implClassName.$funcName._get\");
    static v8::Persistent<v8::FunctionTemplate> private_template =
        v8::Persistent<v8::FunctionTemplate>::New($newTemplateString);
    v8::Handle<v8::Object> holder = V8DOMWrapper::lookupDOMWrapper(V8ClassIndex::$classIndex, info.This());
    if (holder.IsEmpty()) {
      // can only reach here by 'object.__proto__.func', and it should passed
      // domain security check already

      return private_template->GetFunction();
    }
END

  HolderToNative($dataNode, $implClassName, $classIndex);

    push(@implContentDecls, <<END);
    if (!V8Proxy::canAccessFrame(imp->frame(), false)) {
      static v8::Persistent<v8::FunctionTemplate> shared_template =
        v8::Persistent<v8::FunctionTemplate>::New($newTemplateString);
      return shared_template->GetFunction();

    } else {
      return private_template->GetFunction();
    }
  }

END
}

sub GenerateConstructorGetter
{
    my $implClassName = shift;
    my $classIndex = shift;

    push(@implContentDecls, <<END);
  static v8::Handle<v8::Value> ${implClassName}ConstructorGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info) {
    INC_STATS(\"DOM.$implClassName.constructors._get\");
    v8::Handle<v8::Value> data = info.Data();
    ASSERT(data->IsNumber());
    V8ClassIndex::V8WrapperType type = V8ClassIndex::FromInt(data->Int32Value());
END

    if ($classIndex eq "DOMWINDOW") {
        push(@implContentDecls, <<END);
    DOMWindow* window = V8DOMWrapper::convertToNativeObject<DOMWindow>(V8ClassIndex::DOMWINDOW, info.Holder());
    // Get the proxy corresponding to the DOMWindow if possible to
    // make sure that the constructor function is constructed in the
    // context of the DOMWindow and not in the context of the caller.
    return V8DOMWrapper::getConstructor(type, window);
END
    } elsif ($classIndex eq "DEDICATEDWORKERCONTEXT" or $classIndex eq "WORKERCONTEXT" or $classIndex eq "SHAREDWORKERCONTEXT") {
        $implIncludes{"WorkerContextExecutionProxy.h"} = 1;
        push(@implContentDecls, <<END);
    WorkerContext* workerContext = V8DOMWrapper::convertToNativeObject<WorkerContext>(V8ClassIndex::WORKERCONTEXT, info.Holder());
    return V8DOMWrapper::getConstructor(type, workerContext);
END
    } else {
        push(@implContentDecls, "    return v8::Undefined();");
    }

    push(@implContentDecls, <<END);

    }

END
}

sub GenerateNormalAttrGetter
{
    my $attribute = shift;
    my $dataNode = shift;
    my $classIndex = shift;
    my $implClassName = shift;
    my $interfaceName = shift;

    my $attrExt = $attribute->signature->extendedAttributes;

    my $attrName = $attribute->signature->name;
    $implIncludes{"V8Proxy.h"} = 1;

    my $attrType = GetTypeFromSignature($attribute->signature);
    my $attrIsPodType = IsPodType($attrType);

    my $nativeType = GetNativeTypeFromSignature($attribute->signature, 0);
    my $isPodType = IsPodType($implClassName);
    my $skipContext = 0;


    if ($isPodType) {
        $implClassName = GetNativeType($implClassName);
        $implIncludes{"V8SVGPODTypeWrapper.h"} = 1;
    }

    # Special case: SVGZoomEvent's attributes are all read-only
    if ($implClassName eq "SVGZoomEvent") {
        $attrIsPodType = 0;
        $skipContext = 1;
    }

    # Special case: SVGSVGEelement::viewport is read-only
    if (($implClassName eq "SVGSVGElement") and ($attrName eq "viewport")) {
        $attrIsPodType = 0;
        $skipContext = 1;
    }

    # Special case for SVGColor
    if (($implClassName eq "SVGColor") and ($attrName eq "rgbColor")) {
        $attrIsPodType = 0;
    }

    my $getterStringUsesImp = $implClassName ne "double";

  # Getter
    push(@implContentDecls, <<END);
  static v8::Handle<v8::Value> ${attrName}AttrGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info) {
    INC_STATS(\"DOM.$implClassName.$attrName._get\");
END

    if ($isPodType) {
        push(@implContentDecls, <<END);
    V8SVGPODTypeWrapper<$implClassName>* imp_wrapper = V8DOMWrapper::convertToNativeObject<V8SVGPODTypeWrapper<$implClassName> >(V8ClassIndex::$classIndex, info.Holder());
    $implClassName imp_instance = *imp_wrapper;
END
        if ($getterStringUsesImp) {
            push(@implContentDecls, <<END);
    $implClassName* imp = &imp_instance;
END
        }

    } elsif ($attrExt->{"v8OnProto"} || $attrExt->{"V8DisallowShadowing"}) {
      if ($classIndex eq "DOMWINDOW") {
        push(@implContentDecls, <<END);
    v8::Handle<v8::Object> holder = info.Holder();
END
      } else {
        # perform lookup first
        push(@implContentDecls, <<END);
    v8::Handle<v8::Object> holder = V8DOMWrapper::lookupDOMWrapper(V8ClassIndex::$classIndex, info.This());
    if (holder.IsEmpty()) return v8::Undefined();
END
      }
        HolderToNative($dataNode, $implClassName, $classIndex);
    } else {
        push(@implContentDecls, <<END);
    v8::Handle<v8::Object> holder = info.Holder();
END
        HolderToNative($dataNode, $implClassName, $classIndex);
    }

    # Generate security checks if necessary
    if ($attribute->signature->extendedAttributes->{"CheckNodeSecurity"}) {
        push(@implContentDecls, "    if (!V8Proxy::checkNodeSecurity(imp->$attrName())) return v8::Undefined();\n\n");
    } elsif ($attribute->signature->extendedAttributes->{"CheckFrameSecurity"}) {
        push(@implContentDecls, "    if (!V8Proxy::checkNodeSecurity(imp->contentDocument())) return v8::Undefined();\n\n");
    }

    my $useExceptions = 1 if @{$attribute->getterExceptions} and !($isPodType);
    if ($useExceptions) {
        $implIncludes{"ExceptionCode.h"} = 1;
        push(@implContentDecls, "    ExceptionCode ec = 0;\n");
    }

    if ($attribute->signature->extendedAttributes->{"v8referenceattr"}) {
        $attrName = $attribute->signature->extendedAttributes->{"v8referenceattr"};
    }

    my $getterFunc = $codeGenerator->WK_lcfirst($attrName);
    $getterFunc .= "Animated" if $codeGenerator->IsSVGAnimatedType($attribute->signature->type);

    my $returnType = GetTypeFromSignature($attribute->signature);

    my $getterString;
    if ($getterStringUsesImp) {
        my $reflect = $attribute->signature->extendedAttributes->{"Reflect"};
        my $reflectURL = $attribute->signature->extendedAttributes->{"ReflectURL"};
        if ($reflect || $reflectURL) {
            my $contentAttributeName = ($reflect || $reflectURL) eq "1" ? $attrName : ($reflect || $reflectURL);
            my $namespace = $codeGenerator->NamespaceForAttributeName($interfaceName, $contentAttributeName);
            $implIncludes{"${namespace}.h"} = 1;
            my $getAttributeFunctionName = $reflectURL ? "getURLAttribute" : "getAttribute";
            $getterString = "imp->$getAttributeFunctionName(${namespace}::${contentAttributeName}Attr";
        } else {
            $getterString = "imp->$getterFunc(";
        }
        $getterString .= "ec" if $useExceptions;
        $getterString .= ")";
        if ($nativeType eq "int" and $attribute->signature->extendedAttributes->{"ConvertFromString"}) {
            $getterString .= ".toInt()";
        }
    } else {
        $getterString = "imp_instance";
    }

    if ($nativeType eq "String") {
        $getterString = "toString($getterString)";
    }

    my $result;
    my $wrapper;

    if ($attrIsPodType) {
        $implIncludes{"V8SVGPODTypeWrapper.h"} = 1;

        my $getter = $getterString;
        $getter =~ s/imp->//;
        $getter =~ s/\(\)//;
        my $setter = "set" . $codeGenerator->WK_ucfirst($getter);

        my $implClassIsAnimatedType = $codeGenerator->IsSVGAnimatedType($implClassName);
        if (not $implClassIsAnimatedType and $codeGenerator->IsPodTypeWithWriteableProperties($attrType) and not defined $attribute->signature->extendedAttributes->{"Immutable"}) {
            if (IsPodType($implClassName)) {
                my $wrapper = "V8SVGStaticPODTypeWrapperWithPODTypeParent<$nativeType, $implClassName>::create($getterString, imp_wrapper)";
                push(@implContentDecls, "    RefPtr<V8SVGStaticPODTypeWrapperWithPODTypeParent<$nativeType, $implClassName> > wrapper = $wrapper;\n");
            } else {
                my $wrapper = "V8SVGStaticPODTypeWrapperWithParent<$nativeType, $implClassName>::create(imp, &${implClassName}::$getter, &${implClassName}::$setter)";
                push(@implContentDecls, "    RefPtr<V8SVGStaticPODTypeWrapperWithParent<$nativeType, $implClassName> > wrapper = $wrapper;\n");
            }
        } else {
            if ($implClassIsAnimatedType) {
                # We can't hash member function pointers, so instead generate
                # some hashing material based on the names of the methods.
                my $hashhex = substr(Digest::MD5::md5_hex("${implClassName}::$getter ${implClassName}::$setter)"), 0, 8);
                my $wrapper = "V8SVGDynamicPODTypeWrapperCache<$nativeType, $implClassName>::lookupOrCreateWrapper(imp, &${implClassName}::$getter, &${implClassName}::$setter, 0x$hashhex)";
                push(@implContentDecls, "    RefPtr<V8SVGPODTypeWrapper<" . $nativeType . "> > wrapper = $wrapper;\n");
            } else {
                my $wrapper = GenerateSVGStaticPodTypeWrapper($returnType, $getterString);
                push(@implContentDecls, "    RefPtr<V8SVGStaticPODTypeWrapper<" . $nativeType . "> > wrapper = $wrapper;\n");
            }
        }

    } else {
        if ($attribute->signature->type eq "EventListener" && $dataNode->name eq "DOMWindow") {
            push(@implContentDecls, "    if (!imp->document())\n");
            push(@implContentDecls, "      return v8::Undefined();\n");
        }
        push(@implContentDecls, "    $nativeType v = ");

        push(@implContentDecls, "$getterString;\n");

        if ($useExceptions) {
            push(@implContentDecls, GenerateSetDOMException("    "));
        }

        $result = "v";
    }

    if (IsSVGTypeNeedingContextParameter($attrType) && !$skipContext) {
        my $resultObject = $result;
        if ($attrIsPodType) {
            $resultObject = "wrapper";
        }
        $resultObject = "WTF::getPtr(" . $resultObject . ")";
        push(@implContentDecls, GenerateSVGContextAssignment($implClassName, $resultObject, "    "));
    }

    if ($attrIsPodType) {
        my $classIndex = uc($attrType);
        push(@implContentDecls, "    return V8DOMWrapper::convertToV8Object(V8ClassIndex::$classIndex, wrapper.release());\n");
    } else {
        $result .= ".release()" if (IsRefPtrType($attrType));
        push(@implContentDecls, "    " . ReturnNativeToJSValue($attribute->signature, $result, "    ").";\n");
    }

    push(@implContentDecls, "  }\n\n");  # end of getter
}


sub GenerateReplaceableAttrSetter
{
    my $implClassName = shift;

    $implIncludes{"V8Proxy.h"} = 1;

    push(@implContentDecls,
       "  static void ${attrName}AttrSetter(v8::Local<v8::String> name," .
       " v8::Local<v8::Value> value, const v8::AccessorInfo& info) {\n");

    push(@implContentDecls, "    INC_STATS(\"DOM.$implClassName.$attrName._set\");\n");

    push(@implContentDecls, "    v8::Local<v8::String> ${attrName}_string = v8::String::New(\"${attrName}\");\n");
    push(@implContentDecls, "    info.Holder()->Delete(${attrName}_string);\n");
    push(@implContentDecls, "    info.This()->Set(${attrName}_string, value);\n");
    push(@implContentDecls, "  }\n\n");
}


sub GenerateNormalAttrSetter
{
    my $attribute = shift;
    my $dataNode = shift;
    my $classIndex = shift;
    my $implClassName = shift;
    my $interfaceName = shift;

    my $attrExt = $attribute->signature->extendedAttributes;

    $implIncludes{"V8Proxy.h"} = 1;

    push(@implContentDecls,
       "  static void ${attrName}AttrSetter(v8::Local<v8::String> name," .
       " v8::Local<v8::Value> value, const v8::AccessorInfo& info) {\n");

    push(@implContentDecls, "    INC_STATS(\"DOM.$implClassName.$attrName._set\");\n");

    my $isPodType = IsPodType($implClassName);

    if ($isPodType) {
        $implClassName = GetNativeType($implClassName);
        $implIncludes{"V8SVGPODTypeWrapper.h"} = 1;
        push(@implContentDecls, "    V8SVGPODTypeWrapper<$implClassName>* wrapper = V8DOMWrapper::convertToNativeObject<V8SVGPODTypeWrapper<$implClassName> >(V8ClassIndex::$classIndex, info.Holder());\n");
        push(@implContentDecls, "    $implClassName imp_instance = *wrapper;\n");
        push(@implContentDecls, "    $implClassName* imp = &imp_instance;\n");

    } elsif ($attrExt->{"v8OnProto"}) {
      if ($classIndex eq "DOMWINDOW") {
        push(@implContentDecls, <<END);
    v8::Handle<v8::Object> holder = info.Holder();
END
      } else {
        # perform lookup first
        push(@implContentDecls, <<END);
    v8::Handle<v8::Object> holder = V8DOMWrapper::lookupDOMWrapper(V8ClassIndex::$classIndex, info.This());
    if (holder.IsEmpty()) return;
END
      }
        HolderToNative($dataNode, $implClassName, $classIndex);
    } else {
        push(@implContentDecls, <<END);
    v8::Handle<v8::Object> holder = info.Holder();
END
        HolderToNative($dataNode, $implClassName, $classIndex);
    }

    my $nativeType = GetNativeTypeFromSignature($attribute->signature, 0);
    if ($attribute->signature->type eq "EventListener") {
        if ($dataNode->name eq "DOMWindow") {
            push(@implContentDecls, "    if (!imp->document())\n");
            push(@implContentDecls, "      return;\n");
        }
        push(@implContentDecls, "    $nativeType v = V8DOMWrapper::getEventListener(imp, value, true, ListenerFindOrCreate);\n");
    } else {
        push(@implContentDecls, "    $nativeType v = " . JSValueToNative($attribute->signature, "value") . ";\n");
    }

    my $result = "";
    if ($nativeType eq "int" and $attribute->signature->extendedAttributes->{"ConvertFromString"}) {
        $result .= "WebCore::String::number(";
    }
    $result .= "v";
    if ($nativeType eq "int" and $attribute->signature->extendedAttributes->{"ConvertFromString"}) {
        $result .= ")";
    }
    my $returnType = GetTypeFromSignature($attribute->signature);
    if (IsRefPtrType($returnType)) {
        $result = "WTF::getPtr(" . $result . ")";
    }

    my $useExceptions = 1 if @{$attribute->setterExceptions} and !($isPodType);

    if ($useExceptions) {
        $implIncludes{"ExceptionCode.h"} = 1;
        push(@implContentDecls, "    ExceptionCode ec = 0;\n");
    }

    if ($implClassName eq "double") {
        push(@implContentDecls, "    *imp = $result;\n");
    } else {
        my $implSetterFunctionName = $codeGenerator->WK_ucfirst($attrName);
        my $reflect = $attribute->signature->extendedAttributes->{"Reflect"};
        my $reflectURL = $attribute->signature->extendedAttributes->{"ReflectURL"};
        if ($reflect || $reflectURL) {
            my $contentAttributeName = ($reflect || $reflectURL) eq "1" ? $attrName : ($reflect || $reflectURL);
            my $namespace = $codeGenerator->NamespaceForAttributeName($interfaceName, $contentAttributeName);
            $implIncludes{"${namespace}.h"} = 1;
            push(@implContentDecls, "    imp->setAttribute(${namespace}::${contentAttributeName}Attr, $result");
        } elsif ($attribute->signature->type eq "EventListener") {
            $implIncludes{"V8AbstractEventListener.h"} = 1;
            $implIncludes{"V8CustomBinding.h"} = 1;
            $cacheIndex = GetHiddenDependencyIndex($dataNode, $attrName);
            push(@implContentDecls, "    $nativeType old = imp->$attrName();\n");
            push(@implContentDecls, "    V8AbstractEventListener* oldListener = old ? V8AbstractEventListener::cast(old.get()) : 0;\n");
            push(@implContentDecls, "    if (oldListener) {\n");
            push(@implContentDecls, "      v8::Local<v8::Object> oldListenerObject = oldListener->getExistingListenerObject();\n");
            push(@implContentDecls, "      if (!oldListenerObject.IsEmpty())\n");
            push(@implContentDecls, "        removeHiddenDependency(holder, oldListenerObject, $cacheIndex);\n");
            push(@implContentDecls, "    }\n");
            push(@implContentDecls, "    imp->set$implSetterFunctionName($result);\n");
            push(@implContentDecls, "    if ($result)\n");
            push(@implContentDecls, "      createHiddenDependency(holder, value, $cacheIndex");
        } else {
            push(@implContentDecls, "    imp->set$implSetterFunctionName(" . $result);
        }
        push(@implContentDecls, ", ec") if $useExceptions;
        push(@implContentDecls, ");\n");
    }

    if ($useExceptions) {
        push(@implContentDecls, "    V8Proxy::setDOMException(ec);\n");
    }

    if ($isPodType) {
        push(@implContentDecls, "    wrapper->commitChange(*imp, V8Proxy::svgContext(wrapper));\n");
    } elsif (IsSVGTypeNeedingContextParameter($implClassName)) {
        $implIncludes{"SVGElement.h"} = 1;

        my $currentObject = "imp";
        if ($isPodType) {
            $currentObject = "wrapper";
        }

        push(@implContentDecls, "    if (SVGElement* context = V8Proxy::svgContext($currentObject)) {\n");
        push(@implContentDecls, "        context->svgAttributeChanged(imp->associatedAttributeName());\n");
        push(@implContentDecls, "    }\n");
    }

    push(@implContentDecls, "    return;\n");
    push(@implContentDecls, "  }\n\n");  # end of setter
}

sub GenerateNewFunctionTemplate
{
    $function = shift;
    $dataNode = shift;
    $signature = shift;

    my $interfaceName = $dataNode->name;
    my $name = $function->signature->name;

    if ($function->signature->extendedAttributes->{"Custom"} ||
        $function->signature->extendedAttributes->{"V8Custom"}) {
        if ($function->signature->extendedAttributes->{"Custom"} &&
            $function->signature->extendedAttributes->{"V8Custom"}) {
            die "Custom and V8Custom should be mutually exclusive!"
        }
        my $customFunc = $function->signature->extendedAttributes->{"Custom"} ||
                         $function->signature->extendedAttributes->{"V8Custom"};
        if ($customFunc eq 1) {
            $customFunc = $interfaceName . $codeGenerator->WK_ucfirst($name);
        }
        return "v8::FunctionTemplate::New(V8Custom::v8${customFunc}Callback, v8::Handle<v8::Value>(), $signature)";
    } else {
        return "v8::FunctionTemplate::New(${interfaceName}Internal::${name}Callback, v8::Handle<v8::Value>(), $signature)";
    }
}

sub GenerateFunctionCallback
{
    my $function = shift;
    my $dataNode = shift;
    my $classIndex = shift;
    my $implClassName = shift;

    my $interfaceName = $dataNode->name;
    my $name = $function->signature->name;

    push(@implContentDecls,
"  static v8::Handle<v8::Value> ${name}Callback(const v8::Arguments& args) {\n" .
"    INC_STATS(\"DOM.$implClassName.$name\");\n");

    my $numParameters = @{$function->parameters};

    if ($function->signature->extendedAttributes->{"RequiresAllArguments"}) {
        push(@implContentDecls,
            "    if (args.Length() < $numParameters) return v8::Undefined();\n");
    }

    if (IsPodType($implClassName)) {
        my $nativeClassName = GetNativeType($implClassName);
        push(@implContentDecls, "    V8SVGPODTypeWrapper<$nativeClassName>* imp_wrapper = V8DOMWrapper::convertToNativeObject<V8SVGPODTypeWrapper<$nativeClassName> >(V8ClassIndex::$classIndex, args.Holder());\n");
        push(@implContentDecls, "    $nativeClassName imp_instance = *imp_wrapper;\n");
        push(@implContentDecls, "    $nativeClassName* imp = &imp_instance;\n");
    } else {
        push(@implContentDecls, <<END);
    v8::Handle<v8::Object> holder = args.Holder();
END
        HolderToNative($dataNode, $implClassName, $classIndex);
    }

  # Check domain security if needed
    if (($dataNode->extendedAttributes->{"CheckDomainSecurity"}
       || $interfaceName eq "DOMWindow")
       && !$function->signature->extendedAttributes->{"DoNotCheckDomainSecurity"}) {
    # We have not find real use cases yet.
    push(@implContentDecls,
"    if (!V8Proxy::canAccessFrame(imp->frame(), true)) {\n".
"      return v8::Undefined();\n" .
"    }\n");
    }


    if (@{$function->raisesExceptions}) {
        $implIncludes{"ExceptionCode.h"} = 1;
        push(@implContentDecls, "    ExceptionCode ec = 0;\n");
    }

    if ($function->signature->extendedAttributes->{"CustomArgumentHandling"}) {
        push(@implContentDecls, "    ScriptCallStack callStack(args, $numParameters);\n");
        $implIncludes{"ScriptCallStack.h"} = 1;
    }
    if ($function->signature->extendedAttributes->{"SVGCheckSecurityDocument"}) {
        push(@implContentDecls,
"    if (!V8Proxy::checkNodeSecurity(imp->getSVGDocument(ec)))\n" .
"      return v8::Undefined();\n");
    }

    my $paramIndex = 0;
    foreach my $parameter (@{$function->parameters}) {
        TranslateParameter($parameter);

        my $parameterName = $parameter->name;

        if ($parameter->extendedAttributes->{"Optional"}) {
            # Generate early call if there are not enough parameters.
            push(@implContentDecls, "    if (args.Length() <= $paramIndex) {\n");
            my $functionCall = GenerateFunctionCallString($function, $paramIndex, "    " x 2, $implClassName);
            push(@implContentDecls, $functionCall);
            push(@implContentDecls, "    }\n");
        }

        if (BasicTypeCanFailConversion($parameter)) {
            push(@implContentDecls, "    bool ${parameterName}Ok;\n");
        }

        push(@implContentDecls, "    " . GetNativeTypeFromSignature($parameter, 1) . " $parameterName = ");
        push(@implContentDecls, JSValueToNative($parameter, "args[$paramIndex]",
           BasicTypeCanFailConversion($parameter) ?  "${parameterName}Ok" : undef) . ";\n");

        if (TypeCanFailConversion($parameter)) {
            $implIncludes{"ExceptionCode.h"} = 1;
            push(@implContentDecls,
"    if (!$parameterName" . (BasicTypeCanFailConversion($parameter) ? "Ok" : "") . ") {\n" .
"      V8Proxy::setDOMException(TYPE_MISMATCH_ERR);\n" .
"      return v8::Handle<v8::Value>();\n" .
"    }\n");
        }

        if ($parameter->extendedAttributes->{"IsIndex"}) {
            $implIncludes{"ExceptionCode.h"} = 1;
            push(@implContentDecls,
"    if ($parameterName < 0) {\n" .
"      V8Proxy::setDOMException(INDEX_SIZE_ERR);\n" .
"      return v8::Handle<v8::Value>();\n" .
"    }\n");
        }

        $paramIndex++;
    }

    # Build the function call string.
    my $callString = GenerateFunctionCallString($function, $paramIndex, "    ", $implClassName);
    push(@implContentDecls, "$callString");
    push(@implContentDecls, "  }\n\n");
}

sub GenerateBatchedAttributeData
{
    my $dataNode = shift;
    my $interfaceName = $dataNode->name;
    my $attributes = shift;

    foreach my $attribute (@$attributes) {
        my $conditionalString = GenerateConditionalString($attribute->signature);
        push(@implContent, "\n#if ${conditionalString}\n") if $conditionalString;
        GenerateSingleBatchedAttribute($interfaceName, $attribute, ",", "");
        push(@implContent, "\n#endif // ${conditionalString}\n") if $conditionalString;
    }
}

sub GenerateSingleBatchedAttribute
{
    my $interfaceName = shift;
    my $attribute = shift;
    my $delimiter = shift;
    my $indent = shift;
    my $attrName = $attribute->signature->name;
    my $attrExt = $attribute->signature->extendedAttributes;

    my $accessControl = "v8::DEFAULT";
    if ($attrExt->{"DoNotCheckDomainSecurityOnGet"}) {
        $accessControl = "v8::ALL_CAN_READ";
    } elsif ($attrExt->{"DoNotCheckDomainSecurityOnSet"}) {
        $accessControl = "v8::ALL_CAN_WRITE";
    } elsif ($attrExt->{"DoNotCheckDomainSecurity"}) {
        $accessControl = "v8::ALL_CAN_READ";
        if (!($attribute->type =~ /^readonly/) && !($attrExt->{"V8ReadOnly"})) {
            $accessControl .= "|v8::ALL_CAN_WRITE";
        }
    }
    if ($attrExt->{"V8DisallowShadowing"}) {
        $accessControl .= "|v8::PROHIBITS_OVERWRITING";
    }
    $accessControl = "static_cast<v8::AccessControl>(" . $accessControl . ")";

    my $customAccessor =
        $attrExt->{"Custom"} ||
        $attrExt->{"CustomSetter"} ||
        $attrExt->{"CustomGetter"} ||
        $attrExt->{"V8Custom"} ||
        $attrExt->{"V8CustomSetter"} ||
        $attrExt->{"V8CustomGetter"} ||
        "";
    if ($customAccessor eq 1) {
        # use the naming convension, interface + (capitalize) attr name
        $customAccessor = $interfaceName . $codeGenerator->WK_ucfirst($attrName);
    }

    my $getter;
    my $setter;
    my $propAttr = "v8::None";
    my $hasCustomSetter = 0;

    # Check attributes.
    if ($attrExt->{"DontEnum"}) {
        $propAttr .= "|v8::DontEnum";
    }
    if ($attrExt->{"V8DisallowShadowing"}) {
        $propAttr .= "|v8::DontDelete";
    }

    my $on_proto = "0 /* on instance */";
    my $data = "V8ClassIndex::INVALID_CLASS_INDEX /* no data */";

    # Constructor
    if ($attribute->signature->type =~ /Constructor$/) {
        my $constructorType = $codeGenerator->StripModule($attribute->signature->type);
        $constructorType =~ s/Constructor$//;
        my $constructorIndex = uc($constructorType);
        if ($customAccessor) {
            $getter = "V8Custom::v8${customAccessor}AccessorGetter";
        } else {
            $data = "V8ClassIndex::${constructorIndex}";
            $getter = "${interfaceName}Internal::${interfaceName}ConstructorGetter";
        }
        $setter = "0";
        $propAttr = "v8::ReadOnly";

    } else {
        # Default Getter and Setter
        $getter = "${interfaceName}Internal::${attrName}AttrGetter";
        $setter = "${interfaceName}Internal::${attrName}AttrSetter";

        # Custom Setter
        if ($attrExt->{"CustomSetter"} || $attrExt->{"V8CustomSetter"} || $attrExt->{"Custom"} || $attrExt->{"V8Custom"}) {
            $hasCustomSetter = 1;
            $setter = "V8Custom::v8${customAccessor}AccessorSetter";
        }

        # Custom Getter
        if ($attrExt->{"CustomGetter"} || $attrExt->{"Custom"} || $attrExt->{"V8Custom"}) {
            $getter = "V8Custom::v8${customAccessor}AccessorGetter";
        }
    }

    # Replaceable
    if ($attrExt->{"Replaceable"} && !$hasCustomSetter) {
        $setter = "0";
        # Handle the special case of window.top being marked as Replaceable.
        # FIXME: Investigate whether we could treat window.top as replaceable
        # and allow shadowing without it being a security hole.
        if (!($interfaceName eq "DOMWindow" and $attrName eq "top")) {
            $propAttr .= "|v8::ReadOnly";
        }
    }

    # Read only attributes
    if ($attribute->type =~ /^readonly/ || $attrExt->{"V8ReadOnly"}) {
        $setter = "0";
    }

    # An accessor can be installed on the proto
    if ($attrExt->{"v8OnProto"}) {
        $on_proto = "1 /* on proto */";
    }

    my $commentInfo = "Attribute '$attrName' (Type: '" . $attribute->type .
                      "' ExtAttr: '" . join(' ', keys(%{$attrExt})) . "')";

    push(@implContent, $indent . "    {\n");
    push(@implContent, $indent . "        \/\/ $commentInfo\n");
    push(@implContent, $indent . "        \"$attrName\",\n");
    push(@implContent, $indent . "        $getter,\n");
    push(@implContent, $indent . "        $setter,\n");
    push(@implContent, $indent . "        $data,\n");
    push(@implContent, $indent . "        $accessControl,\n");
    push(@implContent, $indent . "        static_cast<v8::PropertyAttribute>($propAttr),\n");
    push(@implContent, $indent . "        $on_proto\n");
    push(@implContent, $indent . "    }" . $delimiter . "\n");
END
}

sub GenerateImplementation
{
    my $object = shift;
    my $dataNode = shift;
    my $interfaceName = $dataNode->name;
    my $className = "V8$interfaceName";
    my $implClassName = $interfaceName;
    my $classIndex = uc($codeGenerator->StripModule($interfaceName));

    my $hasLegacyParent = $dataNode->extendedAttributes->{"LegacyParent"};
    my $conditionalString = GenerateConditionalString($dataNode);

    # - Add default header template
    @implContentHeader = split("\r", $headerTemplate);

    push(@implFixedHeader,
         "#include \"config.h\"\n" .
         "#include \"V8Proxy.h\"\n" .
         "#include \"V8Binding.h\"\n\n" .
         "#undef LOG\n\n");

    push(@implFixedHeader, "\n#if ${conditionalString}\n\n") if $conditionalString;

    if ($className =~ /^V8SVGAnimated/) {
        AddIncludesForSVGAnimatedType($interfaceName);
    }

    $implIncludes{"${className}.h"} = 1;

    AddIncludesForType($interfaceName);
    $implIncludes{"V8Proxy.h"} = 1;

    push(@implContentDecls, "namespace WebCore {\n");
    push(@implContentDecls, "namespace ${interfaceName}Internal {\n\n");
    push(@implContentDecls, "template <typename T> void V8_USE(T) { }\n\n");

    my $hasConstructors = 0;

    # Generate property accessors for attributes.
    for ($index = 0; $index < @{$dataNode->attributes}; $index++) {
        $attribute = @{$dataNode->attributes}[$index];
        $attrName = $attribute->signature->name;
        $attrType = $attribute->signature->type;

        # Generate special code for the constructor attributes.
        if ($attrType =~ /Constructor$/) {
            if ($attribute->signature->extendedAttributes->{"CustomGetter"}) {
                $implIncludes{"V8CustomBinding.h"} = 1;
            } else {
                $hasConstructors = 1;
            }
            next;
        }

        if ($attrType eq "EventListener" && $interfaceName eq "DOMWindow") {
            $attribute->signature->extendedAttributes->{"v8OnProto"} = 1;
        }

        # Do not generate accessor if this is a custom attribute.  The
        # call will be forwarded to a hand-written accessor
        # implementation.
        if ($attribute->signature->extendedAttributes->{"Custom"} ||
            $attribute->signature->extendedAttributes->{"V8Custom"}) {
            $implIncludes{"V8CustomBinding.h"} = 1;
            next;
        }

        # Generate the accessor.
        if ($attribute->signature->extendedAttributes->{"CustomGetter"}) {
            $implIncludes{"V8CustomBinding.h"} = 1;
        } else {
            GenerateNormalAttrGetter($attribute, $dataNode, $classIndex, $implClassName, $interfaceName);
        }
        if ($attribute->signature->extendedAttributes->{"CustomSetter"} ||
            $attribute->signature->extendedAttributes->{"V8CustomSetter"}) {
            $implIncludes{"V8CustomBinding.h"} = 1;
        } elsif ($attribute->signature->extendedAttributes->{"Replaceable"}) {
            $dataNode->extendedAttributes->{"ExtendsDOMGlobalObject"} || die "Replaceable attribute can only be used in interface that defines ExtendsDOMGlobalObject attribute!";
            # GenerateReplaceableAttrSetter($implClassName);
        } elsif ($attribute->type !~ /^readonly/ && !$attribute->signature->extendedAttributes->{"V8ReadOnly"}) {
            GenerateNormalAttrSetter($attribute, $dataNode, $classIndex, $implClassName, $interfaceName);
        }
    }

    if ($hasConstructors) {
        GenerateConstructorGetter($implClassName, $classIndex);
    }

    # Generate methods for functions.
    foreach my $function (@{$dataNode->functions}) {
        # hack for addEventListener/RemoveEventListener
        # FIXME: avoid naming conflict
        if ($function->signature->extendedAttributes->{"Custom"} || $function->signature->extendedAttributes->{"V8Custom"}) {
                $implIncludes{"V8CustomBinding.h"} = 1;
        } else {
            GenerateFunctionCallback($function, $dataNode, $classIndex, $implClassName);
        }

        # If the function does not need domain security check, we need to
        # generate an access getter that returns different function objects
        # for different calling context.
        if (($dataNode->extendedAttributes->{"CheckDomainSecurity"} || ($interfaceName eq "DOMWindow")) && $function->signature->extendedAttributes->{"DoNotCheckDomainSecurity"}) {
            GenerateDomainSafeFunctionGetter($function, $dataNode, $classIndex, $implClassName);
        }
    }

    # Attributes
    my $attributes = $dataNode->attributes;

    # For the DOMWindow interface we partition the attributes into the
    # ones that disallows shadowing and the rest.
    my @disallowsShadowing;
    # Also separate out attributes that are enabled at runtime so we can process them specially.
    my @enabledAtRuntime;
    my @normal;
    foreach my $attribute (@$attributes) {
        if ($interfaceName eq "DOMWindow" && $attribute->signature->extendedAttributes->{"V8DisallowShadowing"}) {
            push(@disallowsShadowing, $attribute);
        } elsif ($attribute->signature->extendedAttributes->{"EnabledAtRuntime"}) {
            push(@enabledAtRuntime, $attribute);
        } else {
            push(@normal, $attribute);
        }
    }
    $attributes = \@normal;
    # Put the attributes that disallow shadowing on the shadow object.
    if (@disallowsShadowing) {
        push(@implContent, "static const BatchedAttribute shadow_attrs[] = {\n");
        GenerateBatchedAttributeData($dataNode, \@disallowsShadowing);
        push(@implContent, "};\n");
    }

    my $has_attributes = 0;
    if (@$attributes) {
        $has_attributes = 1;
        push(@implContent, "static const BatchedAttribute ${interfaceName}_attrs[] = {\n");
        GenerateBatchedAttributeData($dataNode, $attributes);
        push(@implContent, "};\n");
    }

    # Setup constants
    my $has_constants = 0;
    if (@{$dataNode->constants}) {
        $has_constants = 1;
        push(@implContent, "static const BatchedConstant ${interfaceName}_consts[] = {\n");
    }
    foreach my $constant (@{$dataNode->constants}) {
        my $name = $constant->name;
        my $value = $constant->value;
        # FIXME: we need the static_cast here only because of one constant, NodeFilter.idl
        # defines "const unsigned long SHOW_ALL = 0xFFFFFFFF".  It would be better if we
        # handled this here, and converted it to a -1 constant in the c++ output.
        push(@implContent, <<END);
  { "${name}", static_cast<signed int>($value) },
END
    }
    if ($has_constants) {
        push(@implContent, "};\n");
    }

    push(@implContentDecls, "} // namespace ${interfaceName}Internal\n\n");

    my $access_check = "/* no access check */";
    if ($dataNode->extendedAttributes->{"CheckDomainSecurity"} && !($interfaceName eq "DOMWindow")) {
        $access_check = "instance->SetAccessCheckCallbacks(V8Custom::v8${interfaceName}NamedSecurityCheck, V8Custom::v8${interfaceName}IndexedSecurityCheck, v8::Integer::New(V8ClassIndex::ToInt(V8ClassIndex::${classIndex})));";
    }

    # For the DOMWindow interface, generate the shadow object template
    # configuration method.
    if ($implClassName eq "DOMWindow") {
        push(@implContent, <<END);
static v8::Persistent<v8::ObjectTemplate> ConfigureShadowObjectTemplate(v8::Persistent<v8::ObjectTemplate> templ) {
  batchConfigureAttributes(templ,
                           v8::Handle<v8::ObjectTemplate>(),
                           shadow_attrs,
                           sizeof(shadow_attrs)/sizeof(*shadow_attrs));
  return templ;
}
END
    }

    # Generate the template configuration method
    push(@implContent,  <<END);
static v8::Persistent<v8::FunctionTemplate> Configure${className}Template(v8::Persistent<v8::FunctionTemplate> desc) {
  v8::Local<v8::ObjectTemplate> instance = desc->InstanceTemplate();
END
    if (IsNodeSubType($dataNode)) {
        push(@implContent, <<END);
  instance->SetInternalFieldCount(V8Custom::kNodeMinimumInternalFieldCount);
END
    } else {
        push(@implContent, <<END);
  instance->SetInternalFieldCount(V8Custom::kDefaultWrapperInternalFieldCount);
END
    }

    push(@implContent,  <<END);
  v8::Local<v8::Signature> default_signature = v8::Signature::New(desc);
  v8::Local<v8::ObjectTemplate> proto = desc->PrototypeTemplate();
  $access_check
END


    # Set up our attributes if we have them
    if ($has_attributes) {
        push(@implContent, <<END);
  batchConfigureAttributes(instance, proto, ${interfaceName}_attrs, sizeof(${interfaceName}_attrs)/sizeof(*${interfaceName}_attrs));
END
    }

    # Setup the enable-at-runtime attrs if we have them
    foreach my $runtime_attr (@enabledAtRuntime) {
        $enable_function = $interfaceName . $codeGenerator->WK_ucfirst($runtime_attr->signature->name);
        my $conditionalString = GenerateConditionalString($runtime_attr->signature);
        push(@implContent, "\n#if ${conditionalString}\n") if $conditionalString;
        push(@implContent, "    if (V8Custom::v8${enable_function}Enabled()) {\n");
        push(@implContent, "        static const BatchedAttribute attrData =\\\n");
        GenerateSingleBatchedAttribute($interfaceName, $runtime_attr, ";", "    ");
        push(@implContent, <<END);
        configureAttribute(instance, proto, attrData);
    }
END
        push(@implContent, "\n#endif // ${conditionalString}\n") if $conditionalString;
    }

    # Define our functions with Set() or SetAccessor()
    foreach my $function (@{$dataNode->functions}) {
        my $attrExt = $function->signature->extendedAttributes;
        my $name = $function->signature->name;

        my $property_attributes = "v8::DontDelete";
        if ($attrExt->{"DontEnum"}) {
            $property_attributes .= "|v8::DontEnum";
        }
        if ($attrExt->{"V8ReadOnly"}) {
            $property_attributes .= "|v8::ReadOnly";
        }

        my $commentInfo = "Function '$name' (ExtAttr: '" . join(' ', keys(%{$attrExt})) . "')";

        my $template = "proto";
        if ($attrExt->{"V8OnInstance"}) {
            $template = "instance";
        }

        if ($attrExt->{"DoNotCheckDomainSecurity"} &&
            ($dataNode->extendedAttributes->{"CheckDomainSecurity"} || $interfaceName eq "DOMWindow")) {
            # Mark the accessor as ReadOnly and set it on the proto object so
            # it can be shadowed. This is really a hack to make it work.
            # There are several sceneria to call into the accessor:
            #   1) from the same domain: "window.open":
            #      the accessor finds the DOM wrapper in the proto chain;
            #   2) from the same domain: "window.__proto__.open":
            #      the accessor will NOT find a DOM wrapper in the prototype chain
            #   3) from another domain: "window.open":
            #      the access find the DOM wrapper in the prototype chain
            #   "window.__proto__.open" from another domain will fail when
            #   accessing '__proto__'
            #
            # The solution is very hacky and fragile, it really needs to be replaced
            # by a better solution.
            $property_attributes .= "|v8::ReadOnly";
            push(@implContent, <<END);

  // $commentInfo
  $template->SetAccessor(
      v8::String::New("$name"),
      ${interfaceName}Internal::${name}AttrGetter,
      0,
      v8::Handle<v8::Value>(),
      v8::ALL_CAN_READ,
      static_cast<v8::PropertyAttribute>($property_attributes));
END
          next;
      }

      my $signature = "default_signature";
      if ($attrExt->{"V8DoNotCheckSignature"}){
          $signature = "v8::Local<v8::Signature>()";
      }

      if (RequiresCustomSignature($function)) {
          $signature = "${name}_signature";
          push(@implContent, "\n  // Custom Signature '$name'\n", CreateCustomSignature($function));
      }

      # Normal function call is a template
      my $templateFunction = GenerateNewFunctionTemplate($function, $dataNode, $signature);


      push(@implContent, <<END);

  // $commentInfo
  ${template}->Set(
      v8::String::New("$name"),
      $templateFunction,
      static_cast<v8::PropertyAttribute>($property_attributes));
END
    }

    # set the super descriptor
    foreach (@{$dataNode->parents}) {
        my $parent = $codeGenerator->StripModule($_);
        if ($parent eq "EventTarget") { next; }
        $implIncludes{"V8${parent}.h"} = 1;
        my $parentClassIndex = uc($codeGenerator->StripModule($parent));
        push(@implContent, "  desc->Inherit(V8DOMWrapper::getTemplate(V8ClassIndex::${parentClassIndex}));\n");
        last;
    }

    # Set the class name.  This is used when printing objects.
    push(@implContent, "  desc->SetClassName(v8::String::New(\"" . GetClassName(${interfaceName}) . "\"));\n");

    if ($has_constants) {
        push(@implContent, <<END);
  batchConfigureConstants(desc, proto, ${interfaceName}_consts, sizeof(${interfaceName}_consts)/sizeof(*${interfaceName}_consts));
END
    }

    push(@implContent, <<END);
  return desc;
}

v8::Persistent<v8::FunctionTemplate> ${className}::GetRawTemplate() {
  static v8::Persistent<v8::FunctionTemplate> ${className}_raw_cache_;
  if (${className}_raw_cache_.IsEmpty()) {
    v8::HandleScope scope;
    v8::Local<v8::FunctionTemplate> result = v8::FunctionTemplate::New(V8Proxy::checkNewLegal);
    ${className}_raw_cache_ = v8::Persistent<v8::FunctionTemplate>::New(result);
  }
  return ${className}_raw_cache_;
}

v8::Persistent<v8::FunctionTemplate> ${className}::GetTemplate() {
  static v8::Persistent<v8::FunctionTemplate> ${className}_cache_;
  if (${className}_cache_.IsEmpty())
    ${className}_cache_ = Configure${className}Template(GetRawTemplate());
  return ${className}_cache_;
}

bool ${className}::HasInstance(v8::Handle<v8::Value> value) {
  return GetRawTemplate()->HasInstance(value);
}

END

    if ($implClassName eq "DOMWindow") {
        push(@implContent, <<END);
v8::Persistent<v8::ObjectTemplate> V8DOMWindow::GetShadowObjectTemplate() {
  static v8::Persistent<v8::ObjectTemplate> V8DOMWindowShadowObject_cache_;
  if (V8DOMWindowShadowObject_cache_.IsEmpty()) {
    V8DOMWindowShadowObject_cache_ = v8::Persistent<v8::ObjectTemplate>::New(v8::ObjectTemplate::New());
    ConfigureShadowObjectTemplate(V8DOMWindowShadowObject_cache_);
  }
  return V8DOMWindowShadowObject_cache_;
}
END
    }

    push(@implContent, <<END);
} // namespace WebCore
END

    push(@implContent, "\n#endif // ${conditionalString}\n") if $conditionalString;
}


sub GenerateFunctionCallString()
{
    my $function = shift;
    my $numberOfParameters = shift;
    my $indent = shift;
    my $implClassName = shift;

    my $name = $function->signature->name;
    my $isPodType = IsPodType($implClassName);
    my $returnType = GetTypeFromSignature($function->signature);
    my $returnsPodType = IsPodType($returnType);
    my $nativeReturnType = GetNativeType($returnType, 0);
    my $result = "";

    # Special case: SVG matrix transform methods should not mutate
    # the matrix but return a copy
    my $copyFirst = 0;
    if ($implClassName eq "SVGMatrix" && $function->signature->type eq "SVGMatrix") {
        $copyFirst = 1;
    }

    if ($function->signature->extendedAttributes->{"v8implname"}) {
        $name = $function->signature->extendedAttributes->{"v8implname"};
    }

    if ($function->signature->extendedAttributes->{"ImplementationFunction"}) {
        $name = $function->signature->extendedAttributes->{"ImplementationFunction"};
    }

    my $functionString = "imp->${name}(";

    if ($copyFirst) {
        $functionString = "result.${name}(";
    }

    my $returnsListItemPodType = 0;
    # SVG lists functions that return POD types require special handling
    if (IsSVGListTypeNeedingSpecialHandling($implClassName) && IsSVGListMethod($name) && $returnsPodType) {
        $returnsListItemPodType = 1;
        $result .= $indent . "SVGList<RefPtr<SVGPODListItem<$nativeReturnType> > >* listImp = imp;\n";
        $functionString = "listImp->${name}(";
    }

    my $first = 1;
    my $index = 0;
    my $nodeToReturn = 0;

    foreach my $parameter (@{$function->parameters}) {
        if ($index eq $numberOfParameters) {
            last;
        }
        if ($first) { $first = 0; }
        else { $functionString .= ", "; }
        my $paramName = $parameter->name;
        my $paramType = $parameter->type;

        # This is a bit of a hack... we need to convert parameters to methods on SVG lists
        # of POD types which are items in the list to appropriate SVGList<> instances
        if ($returnsListItemPodType && $paramType . "List" eq $implClassName) {
            $paramName = "SVGPODListItem<" . GetNativeType($paramType, 1) . ">::copy($paramName)";
        }

        if ($parameter->type eq "NodeFilter" || $parameter->type eq "XPathNSResolver") {
            $functionString .= "$paramName.get()";
        } else {
            $functionString .= $paramName;
        }

        if ($parameter->extendedAttributes->{"Return"}) {
            $nodeToReturn = $parameter->name;
        }
        $index++;
    }

    if ($function->signature->extendedAttributes->{"CustomArgumentHandling"}) {
        $functionString .= ", " if not $first;
        $functionString .= "&callStack";
        if ($first) { $first = 0; }
    }

    if (@{$function->raisesExceptions}) {
        $functionString .= ", " if not $first;
        $functionString .= "ec";
    }
    $functionString .= ")";

    if ($nodeToReturn) {
        # Special case for insertBefore, replaceChild, removeChild and
        # appendChild functions from Node.
        $result .= $indent . "bool success = $functionString;\n";
        if (@{$function->raisesExceptions}) {
            $result .= GenerateSetDOMException($indent);
        }
        $result .= $indent . "if (success)\n";
        $result .= $indent . "    " .
            "return V8DOMWrapper::convertNodeToV8Object($nodeToReturn);\n";
        $result .= $indent . "return v8::Null();\n";
        return $result;
    } elsif ($returnType eq "void") {
        $result .= $indent . "$functionString;\n";
    } elsif ($copyFirst) {
        $result .=
            $indent . GetNativeType($returnType, 0) . " result = *imp;\n" .
            $indent . "$functionString;\n";
    } elsif ($returnsListItemPodType) {
        $result .= $indent . "RefPtr<SVGPODListItem<$nativeReturnType> > result = $functionString;\n";
    } else {
        $result .= $indent . $nativeReturnType . " result = $functionString;\n";
    }

    if (@{$function->raisesExceptions}) {
        $result .= GenerateSetDOMException($indent);
    }

    my $return = "result";

    # If the return type is a POD type, separate out the wrapper generation
    if ($returnsListItemPodType) {
        $result .= $indent . "RefPtr<V8SVGPODTypeWrapper<" . $nativeReturnType . "> > wrapper = ";
        $result .= "V8SVGPODTypeWrapperCreatorForList<" . $nativeReturnType . ">::create($return, imp->associatedAttributeName());\n";
        $return = "wrapper";
    } elsif ($returnsPodType) {
        $result .= $indent . "RefPtr<V8SVGPODTypeWrapper<" . $nativeReturnType . "> > wrapper = ";
        $result .= GenerateSVGStaticPodTypeWrapper($returnType, $return) . ";\n";
        $return = "wrapper";
    }

    my $generatedSVGContextRetrieval = 0;
    # If the return type needs an SVG context, output it
    if (IsSVGTypeNeedingContextParameter($returnType)) {
        $result .= GenerateSVGContextAssignment($implClassName, $return . ".get()", $indent);
        $generatedSVGContextRetrieval = 1;
    }

    if (IsSVGTypeNeedingContextParameter($implClassName) && $implClassName =~ /List$/ && IsSVGListMutator($name)) {
        if (!$generatedSVGContextRetrieval) {
            $result .= GenerateSVGContextRetrieval($implClassName, $indent);
            $generatedSVGContextRetrieval = 1;
        }

        $result .= $indent . "context->svgAttributeChanged(imp->associatedAttributeName());\n";
        $implIncludes{"SVGElement.h"} = 1;
    }

    # If the implementing class is a POD type, commit changes
    if ($isPodType) {
        if (!$generatedSVGContextRetrieval) {
            $result .= GenerateSVGContextRetrieval($implClassName, $indent);
            $generatedSVGContextRetrieval = 1;
        }

        $result .= $indent . "imp_wrapper->commitChange(imp_instance, context);\n";
    }

    if ($returnsPodType) {
        my $classIndex = uc($returnType);
        $result .= $indent . "return V8DOMWrapper::convertToV8Object(V8ClassIndex::$classIndex, wrapper.release());\n";
    } else {
        $return .= ".release()" if (IsRefPtrType($returnType));
        $result .= $indent . ReturnNativeToJSValue($function->signature, $return, $indent) . ";\n";
    }

    return $result;
}


# Get the class name used for printing javascript DOM-object wrappers.
sub GetClassName
{
    my $type = shift;
    return "HTMLCollection" if $type eq "HTMLAllCollection";
    return $type;
}


sub GetTypeFromSignature
{
    my $signature = shift;

    my $type = $codeGenerator->StripModule($signature->type);
    if (($type eq "DOMString") && $signature->extendedAttributes->{"HintAtomic"}) {
        $type = "AtomicString";
    }

    return $type;
}


sub GetNativeTypeFromSignature
{
    my $signature = shift;
    my $isParameter = shift;

    my $type = GetTypeFromSignature($signature);

    if ($type eq "unsigned long" and $signature->extendedAttributes->{"IsIndex"}) {
        # Special-case index arguments because we need to check that they aren't < 0.
        return "int";
    }

    return GetNativeType($type, $isParameter);
}

sub IsRefPtrType
{
    my $type = shift;
    return 1 if $type eq "Attr";
    return 1 if $type eq "CanvasActiveInfo";
    return 1 if $type eq "CanvasArray";
    return 1 if $type eq "CanvasArrayBuffer";
    return 1 if $type eq "CanvasBooleanArray";
    return 1 if $type eq "CanvasByteArray";
    return 1 if $type eq "CanvasBuffer";
    return 1 if $type eq "CanvasFloatArray";
    return 1 if $type eq "CanvasFramebuffer";
    return 1 if $type eq "CanvasGradient";
    return 1 if $type eq "CanvasIntArray";
    return 1 if $type eq "CanvasObject";
    return 1 if $type eq "CanvasProgram";
    return 1 if $type eq "CanvasRenderbuffer";
    return 1 if $type eq "CanvasShader";
    return 1 if $type eq "CanvasShortArray";
    return 1 if $type eq "CanvasTexture";
    return 1 if $type eq "CanvasUnsignedByteArray";
    return 1 if $type eq "CanvasUnsignedIntArray";
    return 1 if $type eq "CanvasUnsignedShortArray";
    return 1 if $type eq "ClientRect";
    return 1 if $type eq "ClientRectList";
    return 1 if $type eq "CDATASection";
    return 1 if $type eq "Comment";
    return 1 if $type eq "CSSRule";
    return 1 if $type eq "CSSStyleRule";
    return 1 if $type eq "CSSCharsetRule";
    return 1 if $type eq "CSSImportRule";
    return 1 if $type eq "CSSMediaRule";
    return 1 if $type eq "CSSFontFaceRule";
    return 1 if $type eq "CSSPageRule";
    return 1 if $type eq "CSSPrimitiveValue";
    return 1 if $type eq "CSSStyleSheet";
    return 1 if $type eq "CSSStyleDeclaration";
    return 1 if $type eq "CSSValue";
    return 1 if $type eq "CSSRuleList";
    return 1 if $type eq "Database";
    return 1 if $type eq "Document";
    return 1 if $type eq "DocumentFragment";
    return 1 if $type eq "DocumentType";
    return 1 if $type eq "Element";
    return 1 if $type eq "EntityReference";
    return 1 if $type eq "Event";
    return 1 if $type eq "EventListener";
    return 1 if $type eq "FileList";
    return 1 if $type eq "HTMLCollection";
    return 1 if $type eq "HTMLDocument";
    return 1 if $type eq "HTMLElement";
    return 1 if $type eq "HTMLOptionsCollection";
    return 1 if $type eq "ImageData";
    return 1 if $type eq "Media";
    return 1 if $type eq "MediaError";
    return 1 if $type eq "MimeType";
    return 1 if $type eq "Node";
    return 1 if $type eq "NodeList";
    return 1 if $type eq "NodeFilter";
    return 1 if $type eq "NodeIterator";
    return 1 if $type eq "NSResolver";
    return 1 if $type eq "Plugin";
    return 1 if $type eq "ProcessingInstruction";
    return 1 if $type eq "Range";
    return 1 if $type eq "RGBColor";
    return 1 if $type eq "Text";
    return 1 if $type eq "TextMetrics";
    return 1 if $type eq "TimeRanges";
    return 1 if $type eq "TreeWalker";
    return 1 if $type eq "WebKitCSSMatrix";
    return 1 if $type eq "WebKitPoint";
    return 1 if $type eq "XPathExpression";
    return 1 if $type eq "XPathNSResolver";
    return 1 if $type eq "XPathResult";

    return 1 if $type eq "SVGAngle";
    return 1 if $type eq "SVGElementInstance";
    return 1 if $type eq "SVGElementInstanceList";
    return 1 if $type =~ /^SVGPathSeg/;

    return 1 if $type =~ /^SVGAnimated/;

    return 0;
}

sub IsVideoClassName
{
    my $class = shift;
    return 1 if $class eq "V8HTMLAudioElement";
    return 1 if $class eq "V8HTMLMediaElement";
    return 1 if $class eq "V8HTMLSourceElement";
    return 1 if $class eq "V8HTMLVideoElement";
    return 1 if $class eq "V8MediaError";
    return 1 if $class eq "V8TimeRanges";

    return 0;
}

sub IsWorkerClassName
{
    my $class = shift;
    return 1 if $class eq "V8Worker";
    return 1 if $class eq "V8WorkerContext";
    return 1 if $class eq "V8WorkerLocation";
    return 1 if $class eq "V8WorkerNavigator";

    return 0;
}

sub GetNativeType
{
    my $type = shift;
    my $isParameter = shift;

    if ($type eq "float" or $type eq "AtomicString" or $type eq "double") {
        return $type;
    }

    return "int" if $type eq "int";
    return "int" if $type eq "short" or $type eq "unsigned short";
    return "unsigned" if $type eq "unsigned long";
    return "int" if $type eq "long";
    return "unsigned long long" if $type eq "unsigned long long";
    return "bool" if $type eq "boolean";
    return "String" if $type eq "DOMString";
    return "Range::CompareHow" if $type eq "CompareHow";
    return "FloatRect" if $type eq "SVGRect";
    return "FloatPoint" if $type eq "SVGPoint";
    return "TransformationMatrix" if $type eq "SVGMatrix";
    return "SVGTransform" if $type eq "SVGTransform";
    return "SVGLength" if $type eq "SVGLength";
    return "double" if $type eq "SVGNumber";
    return "SVGPaint::SVGPaintType" if $type eq "SVGPaintType";
    return "DOMTimeStamp" if $type eq "DOMTimeStamp";
    return "unsigned" if $type eq "unsigned int";
    return "Node*" if $type eq "EventTarget" and $isParameter;

    return "String" if $type eq "DOMUserData";  # FIXME: Temporary hack?

    # temporary hack
    return "RefPtr<NodeFilter>" if $type eq "NodeFilter";

    # necessary as resolvers could be constructed on fly.
    return "RefPtr<XPathNSResolver>" if $type eq "XPathNSResolver";

    return "RefPtr<${type}>" if IsRefPtrType($type) and not $isParameter;

    # Default, assume native type is a pointer with same type name as idl type
    return "${type}*";
}


my %typeCanFailConversion = (
    "AtomicString" => 0,
    "Attr" => 1,
    "CanvasArray" => 0,
    "CanvasBuffer" => 0,
    "CanvasByteArray" => 0,
    "CanvasFloatArray" => 0,
    "CanvasFramebuffer" => 0,
    "CanvasGradient" => 0,
    "CanvasIntArray" => 0,
    "CanvasPixelArray" => 0,
    "CanvasProgram" => 0,
    "CanvasRenderbuffer" => 0,
    "CanvasShader" => 0,
    "CanvasShortArray" => 0,
    "CanvasTexture" => 0,
    "CompareHow" => 0,
    "DataGridColumn" => 0,
    "DOMString" => 0,
    "DOMWindow" => 0,
    "DocumentType" => 0,
    "Element" => 0,
    "Event" => 0,
    "EventListener" => 0,
    "EventTarget" => 0,
    "HTMLCanvasElement" => 0,
    "HTMLElement" => 0,
    "HTMLImageElement" => 0,
    "HTMLOptionElement" => 0,
    "HTMLVideoElement" => 0,
    "Node" => 0,
    "NodeFilter" => 0,
    "MessagePort" => 0,
    "NSResolver" => 0,
    "Range" => 0,
    "SQLResultSet" => 0,
    "Storage" => 0,
    "SVGAngle" => 0,
    "SVGElement" => 0,
    "SVGLength" => 1,
    "SVGMatrix" => 1,
    "SVGNumber" => 0,
    "SVGPaintType" => 0,
    "SVGPathSeg" => 0,
    "SVGPoint" => 1,
    "SVGRect" => 1,
    "SVGTransform" => 1,
    "VoidCallback" => 1,
    "WebKitCSSMatrix" => 0,
    "WebKitPoint" => 0,
    "XPathEvaluator" => 0,
    "XPathNSResolver" => 0,
    "XPathResult" => 0,
    "boolean" => 0,
    "double" => 0,
    "float" => 0,
    "long" => 0,
    "unsigned long" => 0,
    "unsigned short" => 0,
);


sub TranslateParameter
{
    my $signature = shift;

    # The IDL uses some pseudo-types which don't really exist.
    if ($signature->type eq "TimeoutHandler") {
      $signature->type("DOMString");
    }
}

sub BasicTypeCanFailConversion
{
    my $signature = shift;
    my $type = GetTypeFromSignature($signature);

    return 1 if $type eq "SVGLength";
    return 1 if $type eq "SVGMatrix";
    return 1 if $type eq "SVGPoint";
    return 1 if $type eq "SVGRect";
    return 1 if $type eq "SVGTransform";
    return 0;
}

sub TypeCanFailConversion
{
    my $signature = shift;

    my $type = GetTypeFromSignature($signature);

    $implIncludes{"ExceptionCode.h"} = 1 if $type eq "Attr";

    return $typeCanFailConversion{$type} if exists $typeCanFailConversion{$type};

    die "Don't know whether a JS value can fail conversion to type $type.";
}

sub JSValueToNative
{
    my $signature = shift;
    my $value = shift;
    my $okParam = shift;
    my $maybeOkParam = $okParam ? ", ${okParam}" : "";

    my $type = GetTypeFromSignature($signature);

    return "$value" if $type eq "JSObject";
    return "$value->BooleanValue()" if $type eq "boolean";
    return "static_cast<$type>($value->NumberValue())" if $type eq "float" or $type eq "double";
    return "$value->NumberValue()" if $type eq "SVGNumber";

    return "toInt32($value${maybeOkParam})" if $type eq "unsigned long" or $type eq "unsigned short" or $type eq "long";
    return "static_cast<Range::CompareHow>($value->Int32Value())" if $type eq "CompareHow";
    return "static_cast<SVGPaint::SVGPaintType>($value->ToInt32()->Int32Value())" if $type eq "SVGPaintType";

    if ($type eq "AtomicString") {
        return "v8ValueToAtomicWebCoreStringWithNullCheck($value)" if $signature->extendedAttributes->{"ConvertNullToNullString"};
        return "v8ValueToAtomicWebCoreString($value)";
    }

    return "toWebCoreString($value)" if $type eq "DOMUserData";
    if ($type eq "DOMString") {
        return "toWebCoreStringWithNullCheck($value)" if $signature->extendedAttributes->{"ConvertNullToNullString"};
        return "toWebCoreStringWithNullOrUndefinedCheck($value)" if $signature->extendedAttributes->{"ConvertUndefinedOrNullToNullString"};
        return "toWebCoreString($value)";
    }

    if ($type eq "SerializedScriptValue") {
        $implIncludes{"SerializedScriptValue.h"} = 1;
        return "SerializedScriptValue::create($value)";
    }

    if ($type eq "NodeFilter") {
        return "V8DOMWrapper::wrapNativeNodeFilter($value)";
    }

    if ($type eq "SVGRect") {
        $implIncludes{"FloatRect.h"} = 1;
    }

    if ($type eq "SVGPoint") {
        $implIncludes{"FloatPoint.h"} = 1;
    }

    # Default, assume autogenerated type conversion routines
    $implIncludes{"V8Proxy.h"} = 1;
    if ($type eq "EventTarget") {
        $implIncludes{"V8Node.h"} = 1;

        # EventTarget is not in DOM hierarchy, but all Nodes are EventTarget.
        return "V8Node::HasInstance($value) ? V8DOMWrapper::convertDOMWrapperToNode<Node>(v8::Handle<v8::Object>::Cast($value)) : 0";
    }

    if ($type eq "XPathNSResolver") {
        return "V8DOMWrapper::getXPathNSResolver($value)";
    }

    AddIncludesForType($type);
    # $implIncludes{"$type.h"} = 1 unless AvoidInclusionOfType($type);

    if (IsDOMNodeType($type)) {
        $implIncludes{"V8${type}.h"} = 1;

        # Perform type checks on the parameter, if it is expected Node type,
        # return NULL.
        return "V8${type}::HasInstance($value) ? V8DOMWrapper::convertDOMWrapperToNode<${type}>(v8::Handle<v8::Object>::Cast($value)) : 0";
    } else {
        # TODO: Temporary to avoid Window name conflict.
        my $classIndex = uc($type);
        my $implClassName = ${type};

        $implIncludes{"V8$type.h"} = 1;

        if (IsPodType($type)) {
            my $nativeType = GetNativeType($type);
            $implIncludes{"V8SVGPODTypeWrapper.h"} = 1;

            return "V8SVGPODTypeUtil::toSVGPODType<${nativeType}>(V8ClassIndex::${classIndex}, $value${maybeOkParam})"
        }

        $implIncludes{"V8${type}.h"} = 1;

        # Perform type checks on the parameter, if it is expected Node type,
        # return NULL.
        return "V8${type}::HasInstance($value) ? V8DOMWrapper::convertToNativeObject<${implClassName}>(V8ClassIndex::${classIndex}, v8::Handle<v8::Object>::Cast($value)) : 0";
    }
}


sub GetV8HeaderName
{
    my $type = shift;
    return "V8" . GetImplementationFileName($type);
}


sub CreateCustomSignature
{
    my $function = shift;
    my $count = @{$function->parameters};
    my $name = $function->signature->name;
    my $result = "  const int ${name}_argc = ${count};\n" .
      "  v8::Handle<v8::FunctionTemplate> ${name}_argv[${name}_argc] = { ";
    my $first = 1;
    foreach my $parameter (@{$function->parameters}) {
        if ($first) { $first = 0; }
        else { $result .= ", "; }
        if (IsWrapperType($parameter->type)) {
            if ($parameter->type eq "XPathNSResolver") {
                # Special case for XPathNSResolver.  All other browsers accepts a callable,
                # so, even though it's against IDL, accept objects here.
                $result .= "v8::Handle<v8::FunctionTemplate>()";
            } else {
                my $type = $parameter->type;
                my $header = GetV8HeaderName($type);
                $implIncludes{$header} = 1;
                $result .= "V8${type}::GetRawTemplate()";
            }
        } else {
            $result .= "v8::Handle<v8::FunctionTemplate>()";
        }
    }
    $result .= " };\n";
    $result .= "  v8::Handle<v8::Signature> ${name}_signature = v8::Signature::New(desc, ${name}_argc, ${name}_argv);\n";
    return $result;
}


sub RequiresCustomSignature
{
    my $function = shift;
    # No signature needed for Custom function
    if ($function->signature->extendedAttributes->{"Custom"} ||
        $function->signature->extendedAttributes->{"V8Custom"}) {
        return 0;
    }

    foreach my $parameter (@{$function->parameters}) {
      if (IsWrapperType($parameter->type)) {
          return 1;
      }
    }
    return 0;
}


my %non_wrapper_types = (
    'float' => 1,
    'AtomicString' => 1,
    'double' => 1,
    'short' => 1,
    'unsigned short' => 1,
    'long' => 1,
    'unsigned long' => 1,
    'boolean' => 1,
    'DOMString' => 1,
    'CompareHow' => 1,
    'SVGRect' => 1,
    'SVGPoint' => 1,
    'SVGMatrix' => 1,
    'SVGTransform' => 1,
    'SVGLength' => 1,
    'SVGNumber' => 1,
    'SVGPaintType' => 1,
    'DOMTimeStamp' => 1,
    'JSObject' => 1,
    'EventTarget' => 1,
    'NodeFilter' => 1,
    'EventListener' => 1
);


sub IsWrapperType
{
    my $type = $codeGenerator->StripModule(shift);
    return !($non_wrapper_types{$type});
}

sub IsDOMNodeType
{
    my $type = shift;

    return 1 if $type eq 'Attr';
    return 1 if $type eq 'CDATASection';
    return 1 if $type eq 'Comment';
    return 1 if $type eq 'Document';
    return 1 if $type eq 'DocumentFragment';
    return 1 if $type eq 'DocumentType';
    return 1 if $type eq 'Element';
    return 1 if $type eq 'EntityReference';
    return 1 if $type eq 'HTMLCanvasElement';
    return 1 if $type eq 'HTMLDocument';
    return 1 if $type eq 'HTMLElement';
    return 1 if $type eq 'HTMLFormElement';
    return 1 if $type eq 'HTMLTableCaptionElement';
    return 1 if $type eq 'HTMLTableSectionElement';
    return 1 if $type eq 'Node';
    return 1 if $type eq 'ProcessingInstruction';
    return 1 if $type eq 'SVGElement';
    return 1 if $type eq 'SVGDocument';
    return 1 if $type eq 'SVGSVGElement';
    return 1 if $type eq 'SVGUseElement';
    return 1 if $type eq 'Text';

    return 0;
}


sub ReturnNativeToJSValue
{
    my $signature = shift;
    my $value = shift;
    my $indent = shift;
    my $type = GetTypeFromSignature($signature);
    my $className= "V8$type";

    return "return v8::Date::New(static_cast<double>($value))" if $type eq "DOMTimeStamp";
    return "return $value ? v8::True() : v8::False()" if $type eq "boolean";
    return "return v8::Undefined()" if $type eq "void";

    # For all the types where we use 'int' as the representation type,
    # we use Integer::New which has a fast Smi conversion check.
    my $nativeType = GetNativeType($type);
    return "return v8::Integer::New($value)" if $nativeType eq "int";
    return "return v8::Integer::NewFromUnsigned($value)" if $nativeType eq "unsigned";

    return "return v8::Number::New($value)" if $codeGenerator->IsPrimitiveType($type) or $type eq "SVGPaintType";

    if ($codeGenerator->IsStringType($type)) {
        my $conv = $signature->extendedAttributes->{"ConvertNullStringTo"};
        if (defined $conv) {
            return "return v8StringOrNull($value)" if $conv eq "Null";
            return "return v8StringOrUndefined($value)" if $conv eq "Undefined";
            return "return v8StringOrFalse($value)" if $conv eq "False";

            die "Unknown value for ConvertNullStringTo extended attribute";
        }
        return "return v8String($value)";
    }

    # V8 specific.
    my $implClassName = $type;
    AddIncludesForType($type);
    # $implIncludes{GetImplementationFileName($type)} = 1 unless AvoidInclusionOfType($type);

    # special case for non-DOM node interfaces
    if (IsDOMNodeType($type)) {
        return "return V8DOMWrapper::convertNodeToV8Object($value)";
    }

    if ($type eq "EventTarget" or $type eq "SVGElementInstance") {
        return "return V8DOMWrapper::convertEventTargetToV8Object($value)";
    }

    if ($type eq "Event") {
        return "return V8DOMWrapper::convertEventToV8Object($value)";
    }

    if ($type eq "EventListener") {
        return "return V8DOMWrapper::convertEventListenerToV8Object($value)";
    }

    if ($type eq "SerializedScriptValue") {
        $implIncludes{"$type.h"} = 1;
        return "return v8String($value->toString())";
    }

    if ($type eq "DedicatedWorkerContext" or $type eq "WorkerContext" or $type eq "SharedWorkerContext") {
        $implIncludes{"WorkerContextExecutionProxy.h"} = 1;
        return "return WorkerContextExecutionProxy::convertWorkerContextToV8Object($value)";
    }

    if ($type eq "WorkerLocation" or $type eq "WorkerNavigator" or $type eq "NotificationCenter") {
        $implIncludes{"WorkerContextExecutionProxy.h"} = 1;
        my $classIndex = uc($type);

        return "return WorkerContextExecutionProxy::convertToV8Object(V8ClassIndex::$classIndex, $value)";
    }

    else {
        $implIncludes{"wtf/RefCounted.h"} = 1;
        $implIncludes{"wtf/RefPtr.h"} = 1;
        $implIncludes{"wtf/GetPtr.h"} = 1;
        my $classIndex = uc($type);

        if (IsPodType($type)) {
            $value = GenerateSVGStaticPodTypeWrapper($type, $value);
        }

        return "return V8DOMWrapper::convertToV8Object(V8ClassIndex::$classIndex, $value)";
    }
}

sub GenerateSVGStaticPodTypeWrapper {
    my $type = shift;
    my $value = shift;

    $implIncludes{"V8$type.h"}=1;
    $implIncludes{"V8SVGPODTypeWrapper.h"} = 1;

    my $nativeType = GetNativeType($type);
    return "V8SVGStaticPODTypeWrapper<$nativeType>::create($value)";
}

# Internal helper
sub WriteData
{
    if (defined($IMPL)) {
        # Write content to file.
        print $IMPL @implContentHeader;

        print $IMPL @implFixedHeader;

        foreach my $implInclude (sort keys(%implIncludes)) {
            my $checkType = $implInclude;
            $checkType =~ s/\.h//;

            print $IMPL "#include \"$implInclude\"\n" unless $codeGenerator->IsSVGAnimatedType($checkType);
        }

        print $IMPL "\n";
        print $IMPL @implContentDecls;
        print $IMPL @implContent;
        close($IMPL);
        undef($IMPL);

        %implIncludes = ();
        @implFixedHeader = ();
        @implHeaderContent = ();
        @implContentDecls = ();
        @implContent = ();
    }

    if (defined($HEADER)) {
        # Write content to file.
        print $HEADER @headerContent;
        close($HEADER);
        undef($HEADER);

        @headerContent = ();
    }
}

sub IsSVGTypeNeedingContextParameter
{
    my $implClassName = shift;

    if ($implClassName =~ /SVG/ and not $implClassName =~ /Element/) {
        return 1 unless $implClassName =~ /SVGPaint/ or $implClassName =~ /SVGColor/ or $implClassName =~ /SVGDocument/;
    }

    return 0;
}

sub GenerateSVGContextAssignment
{
    my $srcType = shift;
    my $value = shift;
    my $indent = shift;

    $result = GenerateSVGContextRetrieval($srcType, $indent);
    $result .= $indent . "V8Proxy::setSVGContext($value, context);\n";

    return $result;
}

sub GenerateSVGContextRetrieval
{
    my $srcType = shift;
    my $indent = shift;

    my $srcIsPodType = IsPodType($srcType);

    my $srcObject = "imp";
    if ($srcIsPodType) {
        $srcObject = "imp_wrapper";
    }

    my $contextDecl;

    if (IsSVGTypeNeedingContextParameter($srcType)) {
        $contextDecl = "V8Proxy::svgContext($srcObject)";
    } else {
        $contextDecl = $srcObject;
    }

    return $indent . "SVGElement* context = $contextDecl;\n";
}

sub IsSVGListMutator
{
    my $functionName = shift;

    return 1 if $functionName eq "clear";
    return 1 if $functionName eq "initialize";
    return 1 if $functionName eq "insertItemBefore";
    return 1 if $functionName eq "replaceItem";
    return 1 if $functionName eq "removeItem";
    return 1 if $functionName eq "appendItem";

    return 0;
}

sub IsSVGListMethod
{
    my $functionName = shift;

    return 1 if $functionName eq "getFirst";
    return 1 if $functionName eq "getLast";
    return 1 if $functionName eq "getItem";

    return IsSVGListMutator($functionName);
}

sub IsSVGListTypeNeedingSpecialHandling
{
    my $className = shift;

    return 1 if $className eq "SVGPointList";
    return 1 if $className eq "SVGTransformList";

    return 0;
}

sub DebugPrint
{
    my $output = shift;

    print $output;
    print "\n";
}
