diff options
author | tc@google.com <tc@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-10-01 22:31:35 +0000 |
---|---|---|
committer | tc@google.com <tc@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-10-01 22:31:35 +0000 |
commit | de56f378336660dcc848763c80267a5e063ae47d (patch) | |
tree | 7f551b88923b35bc4022ce6ab3a3f602fb60d91c /webkit/port/bindings | |
parent | dc4f63c80cb90efe594131030aad6776e5945fcc (diff) | |
download | chromium_src-de56f378336660dcc848763c80267a5e063ae47d.zip chromium_src-de56f378336660dcc848763c80267a5e063ae47d.tar.gz chromium_src-de56f378336660dcc848763c80267a5e063ae47d.tar.bz2 |
Merge the chrome_webkit_merge_branch back on to trunk. This brings us
up to webkit@36102.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@2778 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/port/bindings')
-rw-r--r-- | webkit/port/bindings/scripts/CodeGenerator.pm | 1 | ||||
-rw-r--r-- | webkit/port/bindings/scripts/CodeGeneratorV8.pm | 57 | ||||
-rw-r--r-- | webkit/port/bindings/v8/JSNSResolver.cpp | 99 | ||||
-rw-r--r-- | webkit/port/bindings/v8/JSNSResolver.h | 58 | ||||
-rw-r--r-- | webkit/port/bindings/v8/V8SVGPODTypeWrapper.h | 29 | ||||
-rw-r--r-- | webkit/port/bindings/v8/V8XMLHttpRequestCustom.cpp | 792 | ||||
-rw-r--r-- | webkit/port/bindings/v8/np_v8object.cpp | 4 | ||||
-rw-r--r-- | webkit/port/bindings/v8/npruntime_internal.h | 2 | ||||
-rw-r--r-- | webkit/port/bindings/v8/v8_binding.h | 9 | ||||
-rw-r--r-- | webkit/port/bindings/v8/v8_custom.cpp | 1096 | ||||
-rw-r--r-- | webkit/port/bindings/v8/v8_custom.h | 60 | ||||
-rw-r--r-- | webkit/port/bindings/v8/v8_events.cpp | 5 | ||||
-rw-r--r-- | webkit/port/bindings/v8/v8_index.cpp | 7 | ||||
-rw-r--r-- | webkit/port/bindings/v8/v8_index.h | 7 | ||||
-rw-r--r-- | webkit/port/bindings/v8/v8_nodefilter.cpp | 13 | ||||
-rw-r--r-- | webkit/port/bindings/v8/v8_nodefilter.h | 3 | ||||
-rw-r--r-- | webkit/port/bindings/v8/v8_proxy.cpp | 1091 | ||||
-rw-r--r-- | webkit/port/bindings/v8/v8_proxy.h | 18 |
18 files changed, 2271 insertions, 1080 deletions
diff --git a/webkit/port/bindings/scripts/CodeGenerator.pm b/webkit/port/bindings/scripts/CodeGenerator.pm index 7d7fe50..d6900ee 100644 --- a/webkit/port/bindings/scripts/CodeGenerator.pm +++ b/webkit/port/bindings/scripts/CodeGenerator.pm @@ -38,6 +38,7 @@ my $verbose = 0; my %primitiveTypeHash = ("int" => 1, "short" => 1, "long" => 1, "unsigned int" => 1, "unsigned short" => 1, "unsigned long" => 1, "float" => 1, + "unsigned long long" => 1, "double" => 1, "boolean" => 1, "void" => 1); my %podTypeHash = ("SVGLength" => 1, "SVGPoint" => 1, "SVGRect" => 1, "SVGNumber" => 1, "SVGMatrix" => 1, "SVGTransform" => 1); diff --git a/webkit/port/bindings/scripts/CodeGeneratorV8.pm b/webkit/port/bindings/scripts/CodeGeneratorV8.pm index f1c235f..7186575 100644 --- a/webkit/port/bindings/scripts/CodeGeneratorV8.pm +++ b/webkit/port/bindings/scripts/CodeGeneratorV8.pm @@ -268,7 +268,7 @@ sub GenerateHeader my $podType = $dataNode->extendedAttributes->{"PODType"}; my $passType = $podType ? "JSSVGPODTypeWrapper<$podType>*" : "$implClassName*"; - push(@headerContent, "#include \"$podType.h\"\n") if $podType and $podType ne "double"; + 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"); @@ -304,7 +304,7 @@ sub GenerateSetDOMException my $indent = shift; my $result = ""; - $result .= $indent . "if (ec != 0) {\n"; + $result .= $indent . "if (ec) {\n"; $result .= $indent . " V8Proxy::SetDOMException(ec);\n"; $result .= $indent . " return v8::Handle<v8::Value>();\n"; $result .= $indent . "}\n"; @@ -530,6 +530,9 @@ END } else { $getterString = "imp_instance"; } + if ($nativeType eq "String") { + $getterString = "ToString($getterString)"; + } my $result; my $wrapper; @@ -584,7 +587,7 @@ sub GenerateReplaceableAttrSetter push(@implContentDecls, " static void ${attrName}AttrSetter(v8::Local<v8::String> name," . - " v8::Local<v8::Value> value, const v8::AccessorInfo& info) {\n"); + " v8::Local<v8::Value> value, const v8::AccessorInfo& info)\n{\n"); push(@implContentDecls, " INC_STATS(L\"DOM.$implClassName.$attrName._set\");\n"); @@ -608,7 +611,7 @@ sub GenerateNormalAttrSetter push(@implContentDecls, " static void ${attrName}AttrSetter(v8::Local<v8::String> name," . - " v8::Local<v8::Value> value, const v8::AccessorInfo& info) {\n"); + " v8::Local<v8::Value> value, const v8::AccessorInfo& info)\n{\n"); push(@implContentDecls, " INC_STATS(L\"DOM.$implClassName.$attrName._set\");\n"); @@ -722,7 +725,7 @@ sub GenerateFunctionCallback my $name = $function->signature->name; push(@implContentDecls, -" static v8::Handle<v8::Value> ${name}Callback(const v8::Arguments& args) {\n" . +" static v8::Handle<v8::Value> ${name}Callback(const v8::Arguments& args)\n{\n" . " INC_STATS(L\"DOM.$implClassName.$name\");\n"); my $numParameters = @{$function->parameters}; @@ -871,7 +874,11 @@ sub GenerateImplementation } # Generate the accessor. - GenerateNormalAttrGetter($attribute, $dataNode, $classIndex, $implClassName); + if ($attribute->signature->extendedAttributes->{"CustomGetter"}) { + $implIncludes{"v8_custom.h"} = 1; + } else { + GenerateNormalAttrGetter($attribute, $dataNode, $classIndex, $implClassName); + } if ($attribute->signature->extendedAttributes->{"CustomSetter"}) { $implIncludes{"v8_custom.h"} = 1; } elsif ($attribute->signature->extendedAttributes->{"Replaceable"}) { @@ -930,7 +937,7 @@ sub GenerateImplementation } } - my $customAccessor = $attrExt->{"Custom"} || $attrExt->{"CustomSetter"} || ""; + my $customAccessor = $attrExt->{"Custom"} || $attrExt->{"CustomSetter"} || $attrExt->{"CustomGetter"} || ""; if ($customAccessor eq 1) { # use the naming convension, interface + (capitalize) attr name $customAccessor = $interfaceName . WK_ucfirst($attrName); @@ -967,7 +974,12 @@ sub GenerateImplementation } elsif ($attrExt->{"CustomSetter"}) { $getter = "${interfaceName}Internal::${attrName}AttrGetter"; $setter = "V8Custom::v8${customAccessor}AccessorSetter"; - + + # Custom Getter + } elsif ($attrExt->{"CustomGetter"}) { + $getter = "V8Custom::v8${customAccessor}AccessorGetter"; + $setter = "${interfaceName}Internal::${attrName}AttrSetter"; + # Replaceable } elsif ($attrExt->{"Replaceable"}) { # Replaceable accessor is put on instance template with ReadOnly attribute. @@ -1233,9 +1245,15 @@ sub GenerateFunctionCallString() # 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 = "new SVGPODListItem<" . GetNativeType($paramType, 1) . ">($paramName)"; + $paramName = "SVGPODListItem<" . GetNativeType($paramType, 1) . ">::copy($paramName)"; + } + + if ($parameter->type eq "NodeFilter") { + $functionString .= "$paramName.get()"; + } else { + $functionString .= $paramName; } - $functionString .= $paramName; + if ($parameter->extendedAttributes->{"Return"}) { $nodeToReturn = $parameter->name; } @@ -1383,6 +1401,7 @@ sub IsRefPtrType 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"; @@ -1397,21 +1416,25 @@ sub IsRefPtrType 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 "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 "ProcessingInstruction"; return 1 if $type eq "Range"; return 1 if $type eq "Text"; + return 1 if $type eq "TextMetrics"; return 1 if $type eq "TreeWalker"; 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 eq "SVGPathSeg"; + return 1 if $type =~ /^SVGPathSeg/; return 1 if $type =~ /^SVGAnimated/; @@ -1429,6 +1452,7 @@ sub GetNativeType return "int" if $type eq "short" or $type eq "unsigned short"; return "int" if $type eq "long" or $type eq "unsigned 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"; @@ -1441,12 +1465,16 @@ sub GetNativeType return "SVGPaint::SVGPaintType" if $type eq "SVGPaintType"; return "DOMTimeStamp" if $type eq "DOMTimeStamp"; return "RGBColor" if $type eq "RGBColor"; + return "EventTargetNode*" if $type eq "EventTarget" and $isParameter; return "String" if $type eq "DOMUserData"; # temporary hack, TODO # temporary hack $type = GetImplementationClassName($type); + # temporary hack + return "RefPtr<NodeFilter>" if $type eq "NodeFilter"; + return "RefPtr<${type}>" if IsRefPtrType($type) and not $isParameter; # Default, assume native type is a pointer with same type name as idl type @@ -1469,6 +1497,7 @@ my %typeCanFailConversion = ( "HTMLOptionElement" => 0, "Node" => 0, "NodeFilter" => 0, + "NSResolver" => 0, "Range" => 0, "SQLResultSet" => 0, "SVGAngle" => 0, @@ -1740,6 +1769,10 @@ sub NativeToJSValue AddIncludesForType($type); # $implIncludes{GetImplementationFileName($type)} = 1 unless AvoidInclusionOfType($type); + if ($type eq "CSSStyleDeclaration") { + $implIncludes{"CSSMutableStyleDeclaration.h"} = 1; + } + # special case for non-DOM node interfaces if (IsDOMNodeType($type)) { return "V8Proxy::NodeToV8Object($value)"; @@ -1770,7 +1803,7 @@ sub NativeToJSValue $value = GenerateReadOnlyPodTypeWrapper($type, $value); } - return "V8Proxy::ToV8Object(V8ClassIndex::$classIndex, static_cast<Peerable*>($value))"; + return "V8Proxy::ToV8Object(V8ClassIndex::$classIndex, $value)"; } } diff --git a/webkit/port/bindings/v8/JSNSResolver.cpp b/webkit/port/bindings/v8/JSNSResolver.cpp new file mode 100644 index 0000000..5251a35 --- /dev/null +++ b/webkit/port/bindings/v8/JSNSResolver.cpp @@ -0,0 +1,99 @@ +// Copyright (c) 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "config.h" +#include "JSNSResolver.h" + +#include "v8_proxy.h" +#include "v8_binding.h" +#include "ExceptionContext.h" +#include "PlatformString.h" + +namespace WebCore { + +JSNSResolver::JSNSResolver(v8::Handle<v8::Object> resolver) + : m_resolver(resolver) +{ +} + +JSNSResolver::~JSNSResolver() +{ +} + +String JSNSResolver::lookupNamespaceURI(ExceptionContext* exceptionContext, + const String& prefix) +{ + v8::Handle<v8::Function> lookupNamespaceURIFunc; + v8::Handle<v8::String> lookupNamespaceURIName = + v8::String::New("lookupNamespaceURI"); + + // Check if the resolver has a function property named lookupNamespaceURI. + if (m_resolver->Has(lookupNamespaceURIName)) { + // In case the property is a getter that throws an error, + // see LayoutTests/fast/dom/SelectorAPI/NSResolver-exceptions.xhtml + ExceptionCatcher exceptionCatcher(exceptionContext); + v8::Handle<v8::Value> lookupNamespaceURI = m_resolver->Get( + lookupNamespaceURIName); + if (exceptionContext->hadException()) + return String(); + if (lookupNamespaceURI->IsFunction()) { + lookupNamespaceURIFunc = v8::Handle<v8::Function>::Cast( + lookupNamespaceURI); + } + } + + if (lookupNamespaceURIFunc.IsEmpty() && !m_resolver->IsFunction()) { + Frame* frame = ScriptController::retrieveActiveFrame(); + log_info(frame, "NSResolver does not have a lookupNamespaceURI method.", + String()); + return String(); + } + + // Catch exceptions from calling the namespace resolver. + ExceptionCatcher exceptionCatcher(exceptionContext); + + const int argc = 1; + v8::Handle<v8::Value> argv[argc] = { v8String(prefix) }; + v8::Handle<v8::Function> function = lookupNamespaceURIFunc.IsEmpty() + ? v8::Handle<v8::Function>::Cast(m_resolver) + : lookupNamespaceURIFunc; + + V8Proxy* proxy = V8Proxy::retrieve(); + v8::Handle<v8::Value> retval = proxy->CallFunction(function, m_resolver, + argc, argv); + + // Eat exceptions from namespace resolver and return an empty string. This + // will cause NAMESPACE_ERR. + if (exceptionContext->hadException()) + return String(); + + return valueToStringWithNullOrUndefinedCheck(retval); +} + +} diff --git a/webkit/port/bindings/v8/JSNSResolver.h b/webkit/port/bindings/v8/JSNSResolver.h new file mode 100644 index 0000000..84bd072 --- /dev/null +++ b/webkit/port/bindings/v8/JSNSResolver.h @@ -0,0 +1,58 @@ +// Copyright (c) 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +// The wrapper for a JS object that implements NSResolver interface. + +#ifndef JSNSResolver_h +#define JSNSResolver_h + +#include <v8.h> +#include <wtf/RefCounted.h> +#include "NSResolver.h" + +namespace WebCore { + +class ExceptionContext; +class String; + +class JSNSResolver : public NSResolver { +public: + JSNSResolver(v8::Handle<v8::Object>); + virtual ~JSNSResolver(); + + virtual String lookupNamespaceURI(ExceptionContext*, const String&); + +private: + v8::Handle<v8::Object> m_resolver; // Handle to resolver object. +}; + +} + +#endif // !defined(JSNSResolver_h) diff --git a/webkit/port/bindings/v8/V8SVGPODTypeWrapper.h b/webkit/port/bindings/v8/V8SVGPODTypeWrapper.h index 488ab2b..94ddf5d 100644 --- a/webkit/port/bindings/v8/V8SVGPODTypeWrapper.h +++ b/webkit/port/bindings/v8/V8SVGPODTypeWrapper.h @@ -160,11 +160,14 @@ struct PODTypeReadWriteHashInfo { { } // Deleted value - explicit PODTypeReadWriteHashInfo(bool) + explicit PODTypeReadWriteHashInfo(WTF::HashTableDeletedValueType) : creator(reinterpret_cast<PODTypeCreator*>(-1)) - , getter(0) - , setter(0) - { } + { + } + bool isHashTableDeletedValue() const + { + return creator == reinterpret_cast<PODTypeCreator*>(-1); + } PODTypeReadWriteHashInfo(PODTypeCreator* _creator, GetterMethod _getter, SetterMethod _setter) : creator(_creator) @@ -202,19 +205,25 @@ struct PODTypeReadWriteHashInfoHash { template<typename PODType, typename PODTypeCreator> struct PODTypeReadWriteHashInfoTraits : WTF::GenericHashTraits<PODTypeReadWriteHashInfo<PODType, PODTypeCreator> > { + typedef PODTypeReadWriteHashInfo<PODType, PODTypeCreator> CacheInfo; + static const bool emptyValueIsZero = true; static const bool needsDestruction = false; - static const PODTypeReadWriteHashInfo<PODType, PODTypeCreator>& deletedValue() + static const CacheInfo& emptyValue() { - static PODTypeReadWriteHashInfo<PODType, PODTypeCreator> key(true); + static CacheInfo key; return key; } - static const PODTypeReadWriteHashInfo<PODType, PODTypeCreator>& emptyValue() + static void constructDeletedValue(CacheInfo& slot) { - static PODTypeReadWriteHashInfo<PODType, PODTypeCreator> key; - return key; + new (&slot) CacheInfo(WTF::HashTableDeletedValue); + } + + static bool isDeletedValue(const CacheInfo& value) + { + return value.isHashTableDeletedValue(); } }; @@ -260,7 +269,7 @@ public: if (it->second != wrapper) continue; - // It's guaruanteed that there's just one object we need to take care of. + // It's guaranteed that there's just one object we need to take care of. map.remove(it->first); break; } diff --git a/webkit/port/bindings/v8/V8XMLHttpRequestCustom.cpp b/webkit/port/bindings/v8/V8XMLHttpRequestCustom.cpp new file mode 100644 index 0000000..0c2cda0 --- /dev/null +++ b/webkit/port/bindings/v8/V8XMLHttpRequestCustom.cpp @@ -0,0 +1,792 @@ +// Copyright (c) 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "config.h" + +#include "v8_binding.h" +#include "v8_custom.h" +#include "v8_events.h" +#include "v8_proxy.h" + +#include "V8Document.h" +#include "V8HTMLDocument.h" + +#include "ExceptionCode.h" +#include "Frame.h" +#include "XMLHttpRequest.h" +#include "XMLHttpRequestUpload.h" + +namespace WebCore { + +CALLBACK_FUNC_DECL(XMLHttpRequestConstructor) { + INC_STATS(L"DOM.XMLHttpRequest.Constructor"); + + if (!args.IsConstructCall()) { + V8Proxy::ThrowError(V8Proxy::TYPE_ERROR, + "DOM object constructor cannot be called as a function."); + return v8::Undefined(); + } + // Expect no parameters. + // Allocate a XMLHttpRequest object as its internal field. + Document* doc = V8Proxy::retrieveFrame()->document(); + RefPtr<XMLHttpRequest> xhr = XMLHttpRequest::create(doc); + V8Proxy::SetDOMWrapper(args.Holder(), + V8ClassIndex::ToInt(V8ClassIndex::XMLHTTPREQUEST), xhr.get()); + // Set object as the peer. + V8Proxy::SetJSWrapperForDOMObject(xhr.get(), + v8::Persistent<v8::Object>::New(args.Holder())); + return args.Holder(); +} + +// XMLHttpRequest -------------------------------------------------------------- + +// Use an array to hold dependents. It works like a ref-counted scheme. +// A value can be added more than once to the xhr object. +static void CreateHiddenXHRDependency(v8::Local<v8::Object> xhr, + v8::Local<v8::Value> value) { + ASSERT(V8Proxy::GetDOMWrapperType(xhr) == V8ClassIndex::XMLHTTPREQUEST || + V8Proxy::GetDOMWrapperType(xhr) == V8ClassIndex::XMLHTTPREQUESTUPLOAD); + v8::Local<v8::Value> cache = + xhr->GetInternalField(V8Custom::kXMLHttpRequestCacheIndex); + if (cache->IsNull() || cache->IsUndefined()) { + cache = v8::Array::New(); + xhr->SetInternalField(V8Custom::kXMLHttpRequestCacheIndex, cache); + } + + v8::Local<v8::Array> cache_array = v8::Local<v8::Array>::Cast(cache); + cache_array->Set(v8::Integer::New(cache_array->Length()), value); +} + +static void RemoveHiddenXHRDependency(v8::Local<v8::Object> xhr, + v8::Local<v8::Value> value) { + ASSERT(V8Proxy::GetDOMWrapperType(xhr) == V8ClassIndex::XMLHTTPREQUEST || + V8Proxy::GetDOMWrapperType(xhr) == V8ClassIndex::XMLHTTPREQUESTUPLOAD); + v8::Local<v8::Value> cache = + xhr->GetInternalField(V8Custom::kXMLHttpRequestCacheIndex); + ASSERT(cache->IsArray()); + v8::Local<v8::Array> cache_array = v8::Local<v8::Array>::Cast(cache); + for (int i = cache_array->Length() - 1; i >= 0; i--) { + v8::Local<v8::Value> cached = cache_array->Get(v8::Integer::New(i)); + if (cached->StrictEquals(value)) { + cache_array->Delete(i); + return; + } + } + + // We should only get here if we try to remove an event listener that was + // never added. +} + +ACCESSOR_GETTER(XMLHttpRequestOnabort) { + INC_STATS(L"DOM.XMLHttpRequest.onabort._get"); + XMLHttpRequest* imp = V8Proxy::ToNativeObject<XMLHttpRequest>( + V8ClassIndex::XMLHTTPREQUEST, info.Holder()); + if (imp->onAbortListener()) { + V8XHREventListener* listener = + static_cast<V8XHREventListener*>(imp->onAbortListener()); + v8::Local<v8::Object> v8_listener = listener->GetListenerObject(); + return v8_listener; + } + return v8::Undefined(); +} + +ACCESSOR_SETTER(XMLHttpRequestOnabort) { + INC_STATS(L"DOM.XMLHttpRequest.onabort._set"); + XMLHttpRequest* imp = V8Proxy::ToNativeObject<XMLHttpRequest>( + V8ClassIndex::XMLHTTPREQUEST, info.Holder()); + if (value->IsNull()) { + if (imp->onAbortListener()) { + V8XHREventListener* listener = + static_cast<V8XHREventListener*>(imp->onAbortListener()); + v8::Local<v8::Object> v8_listener = listener->GetListenerObject(); + RemoveHiddenXHRDependency(info.Holder(), v8_listener); + } + + // Clear the listener + imp->setOnAbortListener(0); + } else { + V8Proxy* proxy = V8Proxy::retrieve(imp->document()->frame()); + if (!proxy) + return; + + EventListener* listener = proxy->FindOrCreateXHREventListener(value, false); + if (listener) { + imp->setOnAbortListener(listener); + CreateHiddenXHRDependency(info.Holder(), value); + } + } +} + +ACCESSOR_GETTER(XMLHttpRequestOnerror) { + INC_STATS(L"DOM.XMLHttpRequest.onerror._get"); + XMLHttpRequest* imp = V8Proxy::ToNativeObject<XMLHttpRequest>( + V8ClassIndex::XMLHTTPREQUEST, info.Holder()); + if (imp->onErrorListener()) { + V8XHREventListener* listener = + static_cast<V8XHREventListener*>(imp->onErrorListener()); + v8::Local<v8::Object> v8_listener = listener->GetListenerObject(); + return v8_listener; + } + return v8::Undefined(); +} + +ACCESSOR_SETTER(XMLHttpRequestOnerror) { + INC_STATS(L"DOM.XMLHttpRequest.onerror._set"); + XMLHttpRequest* imp = V8Proxy::ToNativeObject<XMLHttpRequest>( + V8ClassIndex::XMLHTTPREQUEST, info.Holder()); + if (value->IsNull()) { + if (imp->onErrorListener()) { + V8XHREventListener* listener = + static_cast<V8XHREventListener*>(imp->onErrorListener()); + v8::Local<v8::Object> v8_listener = listener->GetListenerObject(); + RemoveHiddenXHRDependency(info.Holder(), v8_listener); + } + + // Clear the listener + imp->setOnErrorListener(0); + } else { + V8Proxy* proxy = V8Proxy::retrieve(imp->document()->frame()); + if (!proxy) + return; + + EventListener* listener = proxy->FindOrCreateXHREventListener(value, false); + if (listener) { + imp->setOnErrorListener(listener); + CreateHiddenXHRDependency(info.Holder(), value); + } + } +} + +ACCESSOR_GETTER(XMLHttpRequestOnload) { + INC_STATS(L"DOM.XMLHttpRequest.onload._get"); + XMLHttpRequest* imp = V8Proxy::ToNativeObject<XMLHttpRequest>( + V8ClassIndex::XMLHTTPREQUEST, info.Holder()); + if (imp->onLoadListener()) { + V8XHREventListener* listener = + static_cast<V8XHREventListener*>(imp->onLoadListener()); + v8::Local<v8::Object> v8_listener = listener->GetListenerObject(); + return v8_listener; + } + return v8::Undefined(); +} + +ACCESSOR_SETTER(XMLHttpRequestOnload) +{ + INC_STATS(L"DOM.XMLHttpRequest.onload._set"); + XMLHttpRequest* imp = V8Proxy::ToNativeObject<XMLHttpRequest>( + V8ClassIndex::XMLHTTPREQUEST, info.Holder()); + if (value->IsNull()) { + if (imp->onload()) { + V8XHREventListener* listener = static_cast<V8XHREventListener*>(imp->onload()); + v8::Local<v8::Object> v8_listener = listener->GetListenerObject(); + RemoveHiddenXHRDependency(info.Holder(), v8_listener); + } + + imp->setOnload(0); + + } else { + V8Proxy* proxy = V8Proxy::retrieve(imp->document()->frame()); + if (!proxy) + return; + + EventListener* listener = proxy->FindOrCreateXHREventListener(value, false); + if (listener) { + imp->setOnload(listener); + CreateHiddenXHRDependency(info.Holder(), value); + } + } +} + +ACCESSOR_GETTER(XMLHttpRequestOnloadstart) { + INC_STATS(L"DOM.XMLHttpRequest.onloadstart._get"); + XMLHttpRequest* imp = V8Proxy::ToNativeObject<XMLHttpRequest>( + V8ClassIndex::XMLHTTPREQUEST, info.Holder()); + if (imp->onLoadStartListener()) { + V8XHREventListener* listener = + static_cast<V8XHREventListener*>(imp->onLoadStartListener()); + v8::Local<v8::Object> v8_listener = listener->GetListenerObject(); + return v8_listener; + } + return v8::Undefined(); +} + +ACCESSOR_SETTER(XMLHttpRequestOnloadstart) { + INC_STATS(L"DOM.XMLHttpRequest.onloadstart._set"); + XMLHttpRequest* imp = V8Proxy::ToNativeObject<XMLHttpRequest>( + V8ClassIndex::XMLHTTPREQUEST, info.Holder()); + if (value->IsNull()) { + if (imp->onLoadStartListener()) { + V8XHREventListener* listener = + static_cast<V8XHREventListener*>(imp->onLoadStartListener()); + v8::Local<v8::Object> v8_listener = listener->GetListenerObject(); + RemoveHiddenXHRDependency(info.Holder(), v8_listener); + } + + // Clear the listener + imp->setOnLoadStartListener(0); + } else { + V8Proxy* proxy = V8Proxy::retrieve(imp->document()->frame()); + if (!proxy) + return; + + EventListener* listener = proxy->FindOrCreateXHREventListener(value, false); + if (listener) { + imp->setOnLoadStartListener(listener); + CreateHiddenXHRDependency(info.Holder(), value); + } + } +} + +ACCESSOR_GETTER(XMLHttpRequestOnprogress) { + INC_STATS(L"DOM.XMLHttpRequest.onprogress._get"); + XMLHttpRequest* imp = V8Proxy::ToNativeObject<XMLHttpRequest>( + V8ClassIndex::XMLHTTPREQUEST, info.Holder()); + if (imp->onProgressListener()) { + V8XHREventListener* listener = + static_cast<V8XHREventListener*>(imp->onProgressListener()); + v8::Local<v8::Object> v8_listener = listener->GetListenerObject(); + return v8_listener; + } + return v8::Undefined(); +} + +ACCESSOR_SETTER(XMLHttpRequestOnprogress) { + INC_STATS(L"DOM.XMLHttpRequest.onprogress._set"); + XMLHttpRequest* imp = V8Proxy::ToNativeObject<XMLHttpRequest>( + V8ClassIndex::XMLHTTPREQUEST, info.Holder()); + if (value->IsNull()) { + if (imp->onProgressListener()) { + V8XHREventListener* listener = + static_cast<V8XHREventListener*>(imp->onProgressListener()); + v8::Local<v8::Object> v8_listener = listener->GetListenerObject(); + RemoveHiddenXHRDependency(info.Holder(), v8_listener); + } + + // Clear the listener + imp->setOnProgressListener(0); + } else { + V8Proxy* proxy = V8Proxy::retrieve(imp->document()->frame()); + if (!proxy) + return; + + EventListener* listener = proxy->FindOrCreateXHREventListener(value, false); + if (listener) { + imp->setOnProgressListener(listener); + CreateHiddenXHRDependency(info.Holder(), value); + } + } +} + +ACCESSOR_GETTER(XMLHttpRequestOnreadystatechange) { + INC_STATS(L"DOM.XMLHttpRequest.onreadystatechange._get"); + XMLHttpRequest* imp = V8Proxy::ToNativeObject<XMLHttpRequest>( + V8ClassIndex::XMLHTTPREQUEST, info.Holder()); + if (imp->onReadyStateChangeListener()) { + V8XHREventListener* listener = + static_cast<V8XHREventListener*>(imp->onReadyStateChangeListener()); + v8::Local<v8::Object> v8_listener = listener->GetListenerObject(); + return v8_listener; + } + return v8::Undefined(); +} + +ACCESSOR_SETTER(XMLHttpRequestOnreadystatechange) +{ + INC_STATS(L"DOM.XMLHttpRequest.onreadystatechange._set"); + XMLHttpRequest* imp = V8Proxy::ToNativeObject<XMLHttpRequest>( + V8ClassIndex::XMLHTTPREQUEST, info.Holder()); + if (value->IsNull()) { + if (imp->onreadystatechange()) { + V8XHREventListener* listener = + static_cast<V8XHREventListener*>(imp->onreadystatechange()); + v8::Local<v8::Object> v8_listener = listener->GetListenerObject(); + RemoveHiddenXHRDependency(info.Holder(), v8_listener); + } + + // Clear the listener + imp->setOnreadystatechange(0); + } else { + V8Proxy* proxy = V8Proxy::retrieve(imp->document()->frame()); + if (!proxy) + return; + + EventListener* listener = proxy->FindOrCreateXHREventListener(value, false); + if (listener) { + imp->setOnreadystatechange(listener); + CreateHiddenXHRDependency(info.Holder(), value); + } + } +} + +CALLBACK_FUNC_DECL(XMLHttpRequestAddEventListener) +{ + INC_STATS(L"DOM.XMLHttpRequest.addEventListener()"); + XMLHttpRequest* imp = V8Proxy::ToNativeObject<XMLHttpRequest>( + V8ClassIndex::XMLHTTPREQUEST, args.Holder()); + + V8Proxy* proxy = V8Proxy::retrieve(imp->document()->frame()); + if (!proxy) + return v8::Undefined(); + + EventListener* listener = proxy->FindOrCreateXHREventListener(args[1], false); + if (listener) { + String type = ToWebCoreString(args[0]); + bool useCapture = args[2]->BooleanValue(); + imp->addEventListener(type, listener, useCapture); + + CreateHiddenXHRDependency(args.Holder(), args[1]); + } + return v8::Undefined(); +} + +CALLBACK_FUNC_DECL(XMLHttpRequestRemoveEventListener) { + INC_STATS(L"DOM.XMLHttpRequest.removeEventListener()"); + XMLHttpRequest* imp = V8Proxy::ToNativeObject<XMLHttpRequest>( + V8ClassIndex::XMLHTTPREQUEST, args.Holder()); + + V8Proxy* proxy = V8Proxy::retrieve(imp->document()->frame()); + if (!proxy) + return v8::Undefined(); // probably leaked + + EventListener* listener = + proxy->FindXHREventListener(args[1], false); + + if (listener) { + String type = ToWebCoreString(args[0]); + bool useCapture = args[2]->BooleanValue(); + imp->removeEventListener(type, listener, useCapture); + + RemoveHiddenXHRDependency(args.Holder(), args[1]); + } + + return v8::Undefined(); +} + +CALLBACK_FUNC_DECL(XMLHttpRequestOpen) +{ + INC_STATS(L"DOM.XMLHttpRequest.open()"); + // Four cases: + // open(method, url) + // open(method, url, async) + // open(method, url, async, user) + // open(method, url, async, user, passwd) + + if (args.Length() < 2) { + V8Proxy::ThrowError(V8Proxy::SYNTAX_ERROR, "Not enough arguments"); + return v8::Undefined(); + } + + // get the implementation + XMLHttpRequest* xhr = V8Proxy::ToNativeObject<XMLHttpRequest>( + V8ClassIndex::XMLHTTPREQUEST, args.Holder()); + + // retrieve parameters + String method = ToWebCoreString(args[0]); + String urlstring = ToWebCoreString(args[1]); + V8Proxy* proxy = V8Proxy::retrieve(); + KURL url = proxy->frame()->document()->completeURL(urlstring); + + bool async = (args.Length() < 3) ? true : args[2]->BooleanValue(); + + ExceptionCode ec = 0; + String user, passwd; + if (args.Length() >= 4 && !args[3]->IsUndefined()) { + user = valueToStringWithNullCheck(args[3]); + + if (args.Length() >= 5 && !args[4]->IsUndefined()) { + passwd = valueToStringWithNullCheck(args[4]); + xhr->open(method, url, async, user, passwd, ec); + } else + xhr->open(method, url, async, user, ec); + } else + xhr->open(method, url, async, ec); + + if (ec != 0) { + V8Proxy::SetDOMException(ec); + return v8::Handle<v8::Value>(); + } + + return v8::Undefined(); +} + +static bool IsDocumentType(v8::Handle<v8::Value> value) +{ + // TODO(fqian): add other document types. + return V8Document::HasInstance(value) || V8HTMLDocument::HasInstance(value); +} + +CALLBACK_FUNC_DECL(XMLHttpRequestSend) +{ + INC_STATS(L"DOM.XMLHttpRequest.send()"); + XMLHttpRequest* xhr = V8Proxy::ToNativeObject<XMLHttpRequest>( + V8ClassIndex::XMLHTTPREQUEST, args.Holder()); + + ExceptionCode ec = 0; + if (args.Length() < 1) + xhr->send(ec); + else { + v8::Handle<v8::Value> arg = args[0]; + // TODO(eseidel): upstream handles "File" objects too + if (IsDocumentType(arg)) { + v8::Handle<v8::Object> obj = v8::Handle<v8::Object>::Cast(arg); + Document* doc = V8Proxy::DOMWrapperToNode<Document>(obj); + ASSERT(doc); + xhr->send(doc, ec); + } else + xhr->send(valueToStringWithNullCheck(arg), ec); + } + + if (ec) { + V8Proxy::SetDOMException(ec); + return v8::Handle<v8::Value>(); + } + + return v8::Undefined(); +} + +CALLBACK_FUNC_DECL(XMLHttpRequestSetRequestHeader) { + INC_STATS(L"DOM.XMLHttpRequest.setRequestHeader()"); + if (args.Length() < 2) { + V8Proxy::ThrowError(V8Proxy::SYNTAX_ERROR, "Not enough arguments"); + return v8::Undefined(); + } + + XMLHttpRequest* imp = V8Proxy::ToNativeObject<XMLHttpRequest>( + V8ClassIndex::XMLHTTPREQUEST, args.Holder()); + ExceptionCode ec = 0; + String header = ToWebCoreString(args[0]); + String value = ToWebCoreString(args[1]); + imp->setRequestHeader(header, value, ec); + if (ec != 0) { + V8Proxy::SetDOMException(ec); + return v8::Handle<v8::Value>(); + } + return v8::Undefined(); +} + +CALLBACK_FUNC_DECL(XMLHttpRequestGetResponseHeader) { + INC_STATS(L"DOM.XMLHttpRequest.getResponseHeader()"); + if (args.Length() < 1) { + V8Proxy::ThrowError(V8Proxy::SYNTAX_ERROR, "Not enough arguments"); + return v8::Undefined(); + } + + XMLHttpRequest* imp = V8Proxy::ToNativeObject<XMLHttpRequest>( + V8ClassIndex::XMLHTTPREQUEST, args.Holder()); + ExceptionCode ec = 0; + String header = ToWebCoreString(args[0]); + String result = imp->getResponseHeader(header, ec); + if (ec != 0) { + V8Proxy::SetDOMException(ec); + return v8::Handle<v8::Value>(); + } + return v8StringOrNull(result); +} + +CALLBACK_FUNC_DECL(XMLHttpRequestOverrideMimeType) +{ + INC_STATS(L"DOM.XMLHttpRequest.overrideMimeType()"); + if (args.Length() < 1) { + V8Proxy::ThrowError(V8Proxy::SYNTAX_ERROR, "Not enough arguments"); + return v8::Undefined(); + } + + XMLHttpRequest* imp = V8Proxy::ToNativeObject<XMLHttpRequest>( + V8ClassIndex::XMLHTTPREQUEST, args.Holder()); + String value = ToWebCoreString(args[0]); + imp->overrideMimeType(value); + return v8::Undefined(); +} + +CALLBACK_FUNC_DECL(XMLHttpRequestDispatchEvent) +{ + INC_STATS(L"DOM.XMLHttpRequest.dispatchEvent()"); + return v8::Undefined(); +} + + +// XMLHttpRequestUpload -------------------------------------------------------- + +ACCESSOR_GETTER(XMLHttpRequestUploadOnabort) { + INC_STATS(L"DOM.XMLHttpRequestUpload.onabort._get"); + XMLHttpRequestUpload* imp = V8Proxy::ToNativeObject<XMLHttpRequestUpload>( + V8ClassIndex::XMLHTTPREQUESTUPLOAD, info.Holder()); + if (imp->onAbortListener()) { + V8XHREventListener* listener = + static_cast<V8XHREventListener*>(imp->onAbortListener()); + v8::Local<v8::Object> v8_listener = listener->GetListenerObject(); + return v8_listener; + } + return v8::Undefined(); +} + +ACCESSOR_SETTER(XMLHttpRequestUploadOnabort) { + INC_STATS(L"DOM.XMLHttpRequestUpload.onabort._set"); + XMLHttpRequestUpload* imp = V8Proxy::ToNativeObject<XMLHttpRequestUpload>( + V8ClassIndex::XMLHTTPREQUESTUPLOAD, info.Holder()); + if (value->IsNull()) { + if (imp->onAbortListener()) { + V8XHREventListener* listener = + static_cast<V8XHREventListener*>(imp->onAbortListener()); + v8::Local<v8::Object> v8_listener = listener->GetListenerObject(); + RemoveHiddenXHRDependency(info.Holder(), v8_listener); + } + + // Clear the listener + imp->setOnAbortListener(0); + } else { + XMLHttpRequest* xmlhttprequest = imp->associatedXMLHttpRequest(); + V8Proxy* proxy = V8Proxy::retrieve(xmlhttprequest->document()->frame()); + if (!proxy) + return; + + EventListener* listener = proxy->FindOrCreateXHREventListener(value, false); + if (listener) { + imp->setOnAbortListener(listener); + CreateHiddenXHRDependency(info.Holder(), value); + } + } +} + +ACCESSOR_GETTER(XMLHttpRequestUploadOnerror) { + INC_STATS(L"DOM.XMLHttpRequestUpload.onerror._get"); + XMLHttpRequestUpload* imp = V8Proxy::ToNativeObject<XMLHttpRequestUpload>( + V8ClassIndex::XMLHTTPREQUESTUPLOAD, info.Holder()); + if (imp->onErrorListener()) { + V8XHREventListener* listener = + static_cast<V8XHREventListener*>(imp->onErrorListener()); + v8::Local<v8::Object> v8_listener = listener->GetListenerObject(); + return v8_listener; + } + return v8::Undefined(); +} + +ACCESSOR_SETTER(XMLHttpRequestUploadOnerror) { + INC_STATS(L"DOM.XMLHttpRequestUpload.onerror._set"); + XMLHttpRequestUpload* imp = V8Proxy::ToNativeObject<XMLHttpRequestUpload>( + V8ClassIndex::XMLHTTPREQUESTUPLOAD, info.Holder()); + if (value->IsNull()) { + if (imp->onErrorListener()) { + V8XHREventListener* listener = + static_cast<V8XHREventListener*>(imp->onErrorListener()); + v8::Local<v8::Object> v8_listener = listener->GetListenerObject(); + RemoveHiddenXHRDependency(info.Holder(), v8_listener); + } + + // Clear the listener + imp->setOnErrorListener(0); + } else { + XMLHttpRequest* xmlhttprequest = imp->associatedXMLHttpRequest(); + V8Proxy* proxy = V8Proxy::retrieve(xmlhttprequest->document()->frame()); + if (!proxy) + return; + + EventListener* listener = proxy->FindOrCreateXHREventListener(value, false); + if (listener) { + imp->setOnErrorListener(listener); + CreateHiddenXHRDependency(info.Holder(), value); + } + } +} + +ACCESSOR_GETTER(XMLHttpRequestUploadOnload) { + INC_STATS(L"DOM.XMLHttpRequestUpload.onload._get"); + XMLHttpRequestUpload* imp = V8Proxy::ToNativeObject<XMLHttpRequestUpload>( + V8ClassIndex::XMLHTTPREQUESTUPLOAD, info.Holder()); + if (imp->onLoadListener()) { + V8XHREventListener* listener = + static_cast<V8XHREventListener*>(imp->onLoadListener()); + v8::Local<v8::Object> v8_listener = listener->GetListenerObject(); + return v8_listener; + } + return v8::Undefined(); +} + +ACCESSOR_SETTER(XMLHttpRequestUploadOnload) { + INC_STATS(L"DOM.XMLHttpRequestUpload.onload._set"); + XMLHttpRequestUpload* imp = V8Proxy::ToNativeObject<XMLHttpRequestUpload>( + V8ClassIndex::XMLHTTPREQUESTUPLOAD, info.Holder()); + if (value->IsNull()) { + if (imp->onLoadListener()) { + V8XHREventListener* listener = + static_cast<V8XHREventListener*>(imp->onLoadListener()); + v8::Local<v8::Object> v8_listener = listener->GetListenerObject(); + RemoveHiddenXHRDependency(info.Holder(), v8_listener); + } + + // Clear the listener + imp->setOnLoadListener(0); + } else { + XMLHttpRequest* xmlhttprequest = imp->associatedXMLHttpRequest(); + V8Proxy* proxy = V8Proxy::retrieve(xmlhttprequest->document()->frame()); + if (!proxy) + return; + + EventListener* listener = proxy->FindOrCreateXHREventListener(value, false); + if (listener) { + imp->setOnLoadListener(listener); + CreateHiddenXHRDependency(info.Holder(), value); + } + } +} + +ACCESSOR_GETTER(XMLHttpRequestUploadOnloadstart) { + INC_STATS(L"DOM.XMLHttpRequestUpload.onloadstart._get"); + XMLHttpRequestUpload* imp = V8Proxy::ToNativeObject<XMLHttpRequestUpload>( + V8ClassIndex::XMLHTTPREQUESTUPLOAD, info.Holder()); + if (imp->onLoadStartListener()) { + V8XHREventListener* listener = + static_cast<V8XHREventListener*>(imp->onLoadStartListener()); + v8::Local<v8::Object> v8_listener = listener->GetListenerObject(); + return v8_listener; + } + return v8::Undefined(); +} + +ACCESSOR_SETTER(XMLHttpRequestUploadOnloadstart) { + INC_STATS(L"DOM.XMLHttpRequestUpload.onloadstart._set"); + XMLHttpRequestUpload* imp = V8Proxy::ToNativeObject<XMLHttpRequestUpload>( + V8ClassIndex::XMLHTTPREQUESTUPLOAD, info.Holder()); + if (value->IsNull()) { + if (imp->onLoadStartListener()) { + V8XHREventListener* listener = + static_cast<V8XHREventListener*>(imp->onLoadStartListener()); + v8::Local<v8::Object> v8_listener = listener->GetListenerObject(); + RemoveHiddenXHRDependency(info.Holder(), v8_listener); + } + + // Clear the listener + imp->setOnLoadStartListener(0); + } else { + XMLHttpRequest* xmlhttprequest = imp->associatedXMLHttpRequest(); + V8Proxy* proxy = V8Proxy::retrieve(xmlhttprequest->document()->frame()); + if (!proxy) + return; + + EventListener* listener = proxy->FindOrCreateXHREventListener(value, false); + if (listener) { + imp->setOnLoadStartListener(listener); + CreateHiddenXHRDependency(info.Holder(), value); + } + } +} + +ACCESSOR_GETTER(XMLHttpRequestUploadOnprogress) { + INC_STATS(L"DOM.XMLHttpRequestUpload.onprogress._get"); + XMLHttpRequestUpload* imp = V8Proxy::ToNativeObject<XMLHttpRequestUpload>( + V8ClassIndex::XMLHTTPREQUESTUPLOAD, info.Holder()); + if (imp->onProgressListener()) { + V8XHREventListener* listener = + static_cast<V8XHREventListener*>(imp->onProgressListener()); + v8::Local<v8::Object> v8_listener = listener->GetListenerObject(); + return v8_listener; + } + return v8::Undefined(); +} + +ACCESSOR_SETTER(XMLHttpRequestUploadOnprogress) { + INC_STATS(L"DOM.XMLHttpRequestUpload.onprogress._set"); + XMLHttpRequestUpload* imp = V8Proxy::ToNativeObject<XMLHttpRequestUpload>( + V8ClassIndex::XMLHTTPREQUESTUPLOAD, info.Holder()); + if (value->IsNull()) { + if (imp->onProgressListener()) { + V8XHREventListener* listener = + static_cast<V8XHREventListener*>(imp->onProgressListener()); + v8::Local<v8::Object> v8_listener = listener->GetListenerObject(); + RemoveHiddenXHRDependency(info.Holder(), v8_listener); + } + + // Clear the listener + imp->setOnProgressListener(0); + } else { + XMLHttpRequest* xmlhttprequest = imp->associatedXMLHttpRequest(); + V8Proxy* proxy = V8Proxy::retrieve(xmlhttprequest->document()->frame()); + if (!proxy) + return; + + EventListener* listener = proxy->FindOrCreateXHREventListener(value, false); + if (listener) { + imp->setOnProgressListener(listener); + CreateHiddenXHRDependency(info.Holder(), value); + } + } +} + +CALLBACK_FUNC_DECL(XMLHttpRequestUploadAddEventListener) { + INC_STATS(L"DOM.XMLHttpRequestUpload.addEventListener()"); + XMLHttpRequestUpload* imp = V8Proxy::ToNativeObject<XMLHttpRequestUpload>( + V8ClassIndex::XMLHTTPREQUESTUPLOAD, args.Holder()); + + XMLHttpRequest* xmlhttprequest = imp->associatedXMLHttpRequest(); + V8Proxy* proxy = V8Proxy::retrieve(xmlhttprequest->document()->frame()); + if (!proxy) + return v8::Undefined(); + + EventListener* listener = proxy->FindOrCreateXHREventListener(args[1], false); + if (listener) { + String type = ToWebCoreString(args[0]); + bool useCapture = args[2]->BooleanValue(); + imp->addEventListener(type, listener, useCapture); + + CreateHiddenXHRDependency(args.Holder(), args[1]); + } + return v8::Undefined(); +} + +CALLBACK_FUNC_DECL(XMLHttpRequestUploadRemoveEventListener) { + INC_STATS(L"DOM.XMLHttpRequestUpload.removeEventListener()"); + XMLHttpRequestUpload* imp = V8Proxy::ToNativeObject<XMLHttpRequestUpload>( + V8ClassIndex::XMLHTTPREQUESTUPLOAD, args.Holder()); + + XMLHttpRequest* xmlhttprequest = imp->associatedXMLHttpRequest(); + V8Proxy* proxy = V8Proxy::retrieve(xmlhttprequest->document()->frame()); + if (!proxy) + return v8::Undefined(); // probably leaked + + EventListener* listener = + proxy->FindXHREventListener(args[1], false); + + if (listener) { + String type = ToWebCoreString(args[0]); + bool useCapture = args[2]->BooleanValue(); + imp->removeEventListener(type, listener, useCapture); + + RemoveHiddenXHRDependency(args.Holder(), args[1]); + } + + return v8::Undefined(); +} + +CALLBACK_FUNC_DECL(XMLHttpRequestUploadDispatchEvent) { + INC_STATS(L"DOM.XMLHttpRequestUpload.dispatchEvent()"); + V8Proxy::SetDOMException(NOT_SUPPORTED_ERR); + return v8::Undefined(); +} + +} // namespace WebCore diff --git a/webkit/port/bindings/v8/np_v8object.cpp b/webkit/port/bindings/v8/np_v8object.cpp index 3b3be3a..4387180 100644 --- a/webkit/port/bindings/v8/np_v8object.cpp +++ b/webkit/port/bindings/v8/np_v8object.cpp @@ -36,10 +36,10 @@ #include "bindings/npruntime.h" #include "npruntime_priv.h" #include "PlatformString.h" +#include "ScriptController.h" #include "v8_helpers.h" #include "v8_np_utils.h" #include "v8_proxy.h" -#include "V8Bridge.h" #include "DOMWindow.h" using WebCore::V8ClassIndex; @@ -326,7 +326,7 @@ bool NPN_SetProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName, NPIdentifierToV8Identifier(propertyName, identifier); obj->Set(v8::String::New(identifier.c_str()), ConvertNPVariantToV8Object(value, - object->root_object->frame()->windowScriptNPObject())); + object->root_object->frame()->script()->windowScriptNPObject())); return true; } diff --git a/webkit/port/bindings/v8/npruntime_internal.h b/webkit/port/bindings/v8/npruntime_internal.h index f5357cd..75bf2b0 100644 --- a/webkit/port/bindings/v8/npruntime_internal.h +++ b/webkit/port/bindings/v8/npruntime_internal.h @@ -25,7 +25,9 @@ * include this file instead of the actual npapi.h or npruntime.h */ +#include "npapi.h" #include "npruntime.h" +#include "npfunctions.h" #ifdef XP_UNIX #include <X11/Xresource.h> diff --git a/webkit/port/bindings/v8/v8_binding.h b/webkit/port/bindings/v8/v8_binding.h index 81d7dde..1239791 100644 --- a/webkit/port/bindings/v8/v8_binding.h +++ b/webkit/port/bindings/v8/v8_binding.h @@ -9,6 +9,7 @@ #include "build/build_config.h" #include <v8.h> +#include "KURL.h" #include "PlatformString.h" #include "MathExtras.h" #include "StringBuffer.h" @@ -131,6 +132,14 @@ inline int ToInt32(v8::Handle<v8::Value> value) { return ToInt32(value, ok); } +inline String ToString(const String& string) { + return string; +} + +inline String ToString(const KURL& url) { + return url.string(); +} + // If a WebCore string length is greater than the threshold, // v8String creates an external string to avoid allocating // the string in the large object space (which has a high memory overhead). diff --git a/webkit/port/bindings/v8/v8_custom.cpp b/webkit/port/bindings/v8/v8_custom.cpp index 604ab14..78a0160 100644 --- a/webkit/port/bindings/v8/v8_custom.cpp +++ b/webkit/port/bindings/v8/v8_custom.cpp @@ -1,11 +1,10 @@ /* - * This file is part of the KDE libraries * Copyright (C) 2000 Harri Porten (porten@kde.org) * Copyright (C) 2001 Peter Kelly (pmk@post.com) * Copyright (C) 2004-2006 Apple Computer, Inc. * Copyright (C) 2006 James G. Speth (speth@end.com) * Copyright (C) 2006 Samuel Weinig (sam@webkit.org) - * Copyright 2007 Google Inc. All Rights Reserved. + * Copyright 2007, 2008 Google Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -25,6 +24,7 @@ #include "config.h" #include <Assertions.h> +#include <wtf/ASCIICType.h> #include "v8_proxy.h" #include "v8_events.h" @@ -43,6 +43,7 @@ #include "V8HTMLImageElement.h" #include "V8HTMLOptionElement.h" #include "V8Node.h" +#include "V8NSResolver.h" #include "V8XPathNSResolver.h" #include "V8XPathResult.h" @@ -50,11 +51,12 @@ #include "CanvasPattern.h" #include "CanvasStyle.h" #include "CanvasRenderingContext2D.h" - #include "Clipboard.h" #include "ClipboardEvent.h" +// TODO(tc): Sort these after the merge lands on trunk. #include "Base64.h" +#include "Console.h" #include "FloatRect.h" #include "Frame.h" #include "FrameTree.h" @@ -72,10 +74,8 @@ #include "EventTargetNode.h" #include "EventTarget.h" #include "ExceptionCode.h" -#include "XMLHttpRequest.h" #include "XMLSerializer.h" #include "KURL.h" -#include "DeprecatedString.h" #include "HTMLDocument.h" #include "HTMLNames.h" #include "HTMLBodyElement.h" @@ -101,12 +101,12 @@ #include "Settings.h" #include "StyleSheetList.h" #include "TreeWalker.h" +#include "JSNSResolver.h" #include "WindowFeatures.h" #include "XPathEvaluator.h" #include "JSXPathNSResolver.h" #include "XPathResult.h" #include "XSLTProcessor.h" -#include "V8Bridge.h" #if ENABLE(SVG) #include "V8SVGPODTypeWrapper.h" @@ -124,18 +124,6 @@ static const int kPopupTilePixels = 10; namespace WebCore { -#define CALLBACK_FUNC_DECL(NAME) \ -v8::Handle<v8::Value> V8Custom::v8##NAME##Callback(const v8::Arguments& args) - -#define ACCESSOR_GETTER(NAME) \ -v8::Handle<v8::Value> V8Custom::v8##NAME##AccessorGetter(\ - v8::Local<v8::String> name, const v8::AccessorInfo& info) - -#define ACCESSOR_SETTER(NAME) \ -void V8Custom::v8##NAME##AccessorSetter(v8::Local<v8::String> name, \ - v8::Local<v8::Value> value, \ - const v8::AccessorInfo& info) - #define NAMED_PROPERTY_GETTER(NAME) \ v8::Handle<v8::Value> V8Custom::v8##NAME##NamedPropertyGetter(\ v8::Local<v8::String> name, const v8::AccessorInfo& info) @@ -264,27 +252,6 @@ void V8ScheduledAction::execute(DOMWindow* window) { } -CALLBACK_FUNC_DECL(XMLHttpRequestConstructor) { - INC_STATS(L"DOM.XMLHttpRequest.Constructor"); - - if (!args.IsConstructCall()) { - V8Proxy::ThrowError(V8Proxy::TYPE_ERROR, - "DOM object constructor cannot be called as a function."); - return v8::Undefined(); - } - // Expect no parameters. - // Allocate a XMLHttpRequest object as its internal field. - Document* doc = V8Proxy::retrieveFrame()->document(); - XMLHttpRequest* xhr = new XMLHttpRequest(doc); - V8Proxy::SetDOMWrapper(args.Holder(), - V8ClassIndex::ToInt(V8ClassIndex::XMLHTTPREQUEST), xhr); - // Set object as the peer. - V8Proxy::SetJSWrapperForDOMObject(xhr, - v8::Persistent<v8::Object>::New(args.Holder())); - return args.Holder(); -} - - CALLBACK_FUNC_DECL(DOMParserConstructor) { INC_STATS(L"DOM.DOMParser.Contructor"); return V8Proxy::ConstructDOMObject<V8ClassIndex::DOMPARSER, @@ -355,10 +322,12 @@ CALLBACK_FUNC_DECL(XSLTProcessorTransformToDocument) { V8ClassIndex::XSLTPROCESSOR, args.Holder()); Node* source = V8Proxy::DOMWrapperToNode<Node>(args[0]); - if (!source) return v8::Undefined(); + if (!source) + return v8::Undefined(); RefPtr<Document> result = imp->transformToDocument(source); // Return undefined if no result was found. - if (!result) return v8::Undefined(); + if (!result) + return v8::Undefined(); return V8Proxy::NodeToV8Object(result.get()); } @@ -404,9 +373,8 @@ CALLBACK_FUNC_DECL(XSLTProcessorGetParameter) { CALLBACK_FUNC_DECL(XSLTProcessorRemoveParameter) { INC_STATS(L"DOM.XSLTProcessor.removeParameter"); // Bail out if localName is null or undefined. - if (args[1]->IsNull() || args[1]->IsUndefined()) { + if (args[1]->IsNull() || args[1]->IsUndefined()) return v8::Undefined(); - } XSLTProcessor* imp = V8Proxy::ToNativeObject<XSLTProcessor>( V8ClassIndex::XSLTPROCESSOR, args.Holder()); @@ -419,33 +387,30 @@ CALLBACK_FUNC_DECL(XSLTProcessorRemoveParameter) { // ---- Canvas support ---- -static v8::Handle<v8::Value> CanvasStyleToV8Object(CanvasStyle* style) { - if (style->gradient()) { - return V8Proxy::ToV8Object(V8ClassIndex::CANVASGRADIENT, - static_cast<Peerable*>(style->gradient())); - } - if (style->pattern()) { - return V8Proxy::ToV8Object(V8ClassIndex::CANVASPATTERN, - static_cast<Peerable*>(style->pattern())); - } - return v8String(style->color()); +static v8::Handle<v8::Value> CanvasStyleToV8Object(CanvasStyle* style) +{ + if (style->canvasGradient()) + return V8Proxy::ToV8Object(V8ClassIndex::CANVASGRADIENT, static_cast<Peerable*>(style->canvasGradient())); + if (style->canvasPattern()) + return V8Proxy::ToV8Object(V8ClassIndex::CANVASPATTERN, static_cast<Peerable*>(style->canvasPattern())); + return v8String(style->color()); } - -static PassRefPtr<CanvasStyle> V8ObjectToCanvasStyle( - v8::Handle<v8::Value> value) { - if (value->IsString()) return new CanvasStyle(ToWebCoreString(value)); +static PassRefPtr<CanvasStyle> V8ObjectToCanvasStyle(v8::Handle<v8::Value> value) +{ + if (value->IsString()) + return CanvasStyle::create(ToWebCoreString(value)); if (V8CanvasGradient::HasInstance(value)) { CanvasGradient* gradient = V8Proxy::DOMWrapperToNative<CanvasGradient>(value); - return new CanvasStyle(gradient); + return CanvasStyle::create(gradient); } if (V8CanvasPattern::HasInstance(value)) { CanvasPattern* pattern = V8Proxy::DOMWrapperToNative<CanvasPattern>(value); - return new CanvasStyle(pattern); + return CanvasStyle::create(pattern); } return 0; @@ -866,16 +831,19 @@ CALLBACK_FUNC_DECL(DOMWindowPostMessage) { DOMWindow* source = V8Proxy::retrieveActiveFrame()->domWindow(); ASSERT(source->frame()); - String domain = source->frame()->loader()->url().host(); String uri = source->frame()->loader()->url().string(); v8::TryCatch try_catch; String message = ToWebCoreString(args[0]); + String domain = ToWebCoreString(args[1]); if (try_catch.HasCaught()) return v8::Undefined(); - window->postMessage(message, domain, uri, source); + ExceptionCode ec; + window->postMessage(message, domain, source, ec); + if (ec) + V8Proxy::SetDOMException(ec); return v8::Undefined(); } @@ -892,7 +860,7 @@ static bool allowPopUp() { Frame* frame = V8Proxy::retrieveActiveFrame(); ASSERT(frame); - if (frame->scriptBridge()->wasRunByUserGesture()) return true; + if (frame->script()->processingUserGesture()) return true; Settings* settings = frame->settings(); return settings && settings->JavaScriptCanOpenWindowsAutomatically(); } @@ -901,7 +869,8 @@ static HashMap<String, String> parseModalDialogFeatures( const String& features_arg) { HashMap<String, String> map; - Vector<String> features = features_arg.split(';'); + Vector<String> features; + features_arg.split(';', features); Vector<String>::const_iterator end = features.end(); for (Vector<String>::const_iterator it = features.begin(); it != end; ++it) { String s = *it; @@ -956,9 +925,8 @@ static Frame* createWindow(Frame* opener_frame, // "_self" or "_parent". Frame* new_frame = active_frame->loader()->createWindow( opener_frame->loader(), frame_request, window_features, created); - if (!new_frame) { + if (!new_frame) return 0; - } new_frame->loader()->setOpener(opener_frame); new_frame->loader()->setOpenedByDOM(); @@ -973,23 +941,20 @@ static Frame* createWindow(Frame* opener_frame, } if (!parseURL(url).startsWith("javascript:", false) || - JSBridge::isSafeScript(new_frame)) { - String completed_url = - url.isEmpty() ? url : active_frame->document()->completeURL(url); - bool user_gesture = active_frame->scriptBridge()->wasRunByUserGesture(); + ScriptController::isSafeScript(new_frame)) { + KURL completed_url = + url.isEmpty() ? KURL("") : active_frame->document()->completeURL(url); + bool user_gesture = active_frame->script()->processingUserGesture(); if (created) { new_frame->loader()->changeLocation( - KURL(completed_url.deprecatedString()), + completed_url, active_frame->loader()->outgoingReferrer(), false, user_gesture); - if (Document* old_doc = opener_frame->document()) { - new_frame->document()->setBaseURL(old_doc->baseURL()); - } } else if (!url.isEmpty()) { new_frame->loader()->scheduleLocationChange( - completed_url, + completed_url.string(), active_frame->loader()->outgoingReferrer(), false, user_gesture); @@ -1149,8 +1114,8 @@ CALLBACK_FUNC_DECL(DOMWindowOpen) { if (!completed_url.isEmpty() && (!parseURL(url_string).startsWith("javascript:", false) || - JSBridge::isSafeScript(frame))) { - bool user_gesture = active_frame->scriptBridge()->wasRunByUserGesture(); + ScriptController::isSafeScript(frame))) { + bool user_gesture = active_frame->script()->processingUserGesture(); frame->loader()->scheduleLocationChange( completed_url, active_frame->loader()->outgoingReferrer(), @@ -1373,7 +1338,8 @@ NAMED_PROPERTY_DELETER(HTMLDocument) { } -NAMED_PROPERTY_SETTER(HTMLDocument) { +NAMED_PROPERTY_SETTER(HTMLDocument) +{ INC_STATS(L"DOM.HTMLDocument.NamedPropertySetter"); // Only handle document.all. We insert the value into the shadow // internal field from which the getter will retrieve it. @@ -1387,50 +1353,45 @@ NAMED_PROPERTY_SETTER(HTMLDocument) { } -NAMED_PROPERTY_GETTER(HTMLDocument) { - INC_STATS(L"DOM.HTMLDocument.NamedPropertyGetter"); - String key = ToWebCoreString(name); +NAMED_PROPERTY_GETTER(HTMLDocument) +{ + INC_STATS(L"DOM.HTMLDocument.NamedPropertyGetter"); + AtomicString key = ToWebCoreString(name); - // Special case for document.all. If the value in the shadow - // internal field is not the marker object, then document.all has - // been temporarily shadowed and we return the value. - if (key == "all") { - ASSERT(info.Holder()->InternalFieldCount() == - kHTMLDocumentInternalFieldCount); - v8::Local<v8::Value> marker = - info.Holder()->GetInternalField(kHTMLDocumentMarkerIndex); - v8::Local<v8::Value> value = - info.Holder()->GetInternalField(kHTMLDocumentShadowIndex); - if (marker != value) { - return value; + // Special case for document.all. If the value in the shadow + // internal field is not the marker object, then document.all has + // been temporarily shadowed and we return the value. + if (key == "all") { + ASSERT(info.Holder()->InternalFieldCount() == kHTMLDocumentInternalFieldCount); + v8::Local<v8::Value> marker = info.Holder()->GetInternalField(kHTMLDocumentMarkerIndex); + v8::Local<v8::Value> value = info.Holder()->GetInternalField(kHTMLDocumentShadowIndex); + if (marker != value) + return value; } - } HTMLDocument* imp = V8Proxy::DOMWrapperToNode<HTMLDocument>(info.Holder()); - // Fast case for named elements that are not there. - if (!imp->hasNamedItem(key) && !imp->hasDocExtraNamedItem(key)) { - return v8::Handle<v8::Value>(); - } - + // Fast case for named elements that are not there. + if (!imp->hasNamedItem(key.impl()) && !imp->hasExtraNamedItem(key.impl())) + return v8::Handle<v8::Value>(); - RefPtr<HTMLCollection> items = imp->documentNamedItems(key); - if (items->length() == 0) return v8::Handle<v8::Value>(); - if (items->length() == 1) { - Node* node = items->firstItem(); - Frame* frame = 0; - if (node->hasTagName(HTMLNames::iframeTag) && - (frame = static_cast<HTMLIFrameElement*>(node)->contentFrame())) { - return V8Proxy::ToV8Object(V8ClassIndex::DOMWINDOW, frame->domWindow()); - } + RefPtr<HTMLCollection> items = imp->documentNamedItems(key); + if (items->length() == 0) + return v8::Handle<v8::Value>(); + if (items->length() == 1) { + Node* node = items->firstItem(); + Frame* frame = 0; + if (node->hasTagName(HTMLNames::iframeTag) && (frame = static_cast<HTMLIFrameElement*>(node)->contentFrame())) + return V8Proxy::ToV8Object(V8ClassIndex::DOMWINDOW, frame->domWindow()); return V8Proxy::NodeToV8Object(node); - } - return V8Proxy::ToV8Object(V8ClassIndex::HTMLCOLLECTION, + } + return V8Proxy::ToV8Object(V8ClassIndex::HTMLCOLLECTION, static_cast<Peerable*>(items.get())); } -NAMED_PROPERTY_GETTER(HTMLFrameSetElement) { +NAMED_PROPERTY_GETTER(HTMLFrameSetElement) +{ INC_STATS(L"DOM.HTMLFrameSetElement.NamedPropertyGetter"); HTMLFrameSetElement* imp = V8Proxy::DOMWrapperToNode<HTMLFrameSetElement>(info.Holder()); @@ -1440,10 +1401,8 @@ NAMED_PROPERTY_GETTER(HTMLFrameSetElement) { Document* doc = static_cast<HTMLFrameElement*>(frame)->contentDocument(); if (doc) { Frame* content_frame = doc->frame(); - if (content_frame) { - return V8Proxy::ToV8Object(V8ClassIndex::DOMWINDOW, - content_frame->domWindow()); - } + if (content_frame) + return V8Proxy::ToV8Object(V8ClassIndex::DOMWINDOW, content_frame->domWindow()); } return v8::Undefined(); } @@ -1598,6 +1557,32 @@ INDEXED_PROPERTY_SETTER(HTMLSelectElementCollection) { return OptionsCollectionSetter(index, value, select); } +// Check for a CSS prefix. +// Passed prefix is all lowercase. +// First character of the prefix within the property name may be upper or lowercase. +// Other characters in the prefix within the property name must be lowercase. +// The prefix within the property name must be followed by a capital letter. +static bool hasCSSPropertyNamePrefix(const String& propertyName, const char* prefix) +{ +#ifndef NDEBUG + ASSERT(*prefix); + for (const char* p = prefix; *p; ++p) + ASSERT(WTF::isASCIILower(*p)); + ASSERT(propertyName.length()); +#endif + + if (WTF::toASCIILower(propertyName[0]) != prefix[0]) + return false; + + unsigned length = propertyName.length(); + for (unsigned i = 1; i < length; ++i) { + if (!prefix[i]) + return WTF::isASCIIUpper(propertyName[i]); + if (propertyName[i] != prefix[i]) + return false; + } + return false; +} // When getting properties on CSSStyleDeclarations, the name used from // Javascript and the actual name of the property are not the same, so @@ -1610,48 +1595,60 @@ INDEXED_PROPERTY_SETTER(HTMLSelectElementCollection) { // Also, certain prefixes such as 'pos', 'css-' and 'pixel-' are stripped // and the pixel_or_pos_prefix out parameter is used to indicate whether or // not the property name was prefixed with 'pos-' or 'pixel-'. -static String CSSPropertyName(const String &p, bool *pixel_or_pos_prefix = 0) { - DeprecatedString prop = p.deprecatedString(); - - int i = prop.length(); - while (--i > 0) { - ::UChar c = prop[i].unicode(); - if (c >= 'A' && c <= 'Z') - prop.insert(i, '-'); - } - - prop = prop.lower(); +static String cssPropertyName(const String& propertyName, bool* hadPixelOrPosPrefix = 0) +{ + if (hadPixelOrPosPrefix) + *hadPixelOrPosPrefix = false; + + unsigned length = propertyName.length(); + if (!length) + return String(); + + Vector<UChar> name; + name.reserveCapacity(length); + + unsigned i = 0; + + if (hasCSSPropertyNamePrefix(propertyName, "css")) + i += 3; + else if (hasCSSPropertyNamePrefix(propertyName, "pixel")) { + i += 5; + if (hadPixelOrPosPrefix) + *hadPixelOrPosPrefix = true; + } else if (hasCSSPropertyNamePrefix(propertyName, "pos")) { + i += 3; + if (hadPixelOrPosPrefix) + *hadPixelOrPosPrefix = true; + } else if (hasCSSPropertyNamePrefix(propertyName, "webkit") + || hasCSSPropertyNamePrefix(propertyName, "khtml") + || hasCSSPropertyNamePrefix(propertyName, "apple")) + name.append('-'); + else { + if (WTF::isASCIIUpper(propertyName[0])) + return String(); + } - if (pixel_or_pos_prefix) - *pixel_or_pos_prefix = false; + name.append(WTF::toASCIILower(propertyName[i++])); - if (prop.startsWith("css-")) { - prop = prop.mid(4); - } else if (prop.startsWith("pixel-")) { - prop = prop.mid(6); - if (pixel_or_pos_prefix) - *pixel_or_pos_prefix = true; - } else if (prop.startsWith("pos-")) { - prop = prop.mid(4); - if (pixel_or_pos_prefix) - *pixel_or_pos_prefix = true; - } else if (prop.startsWith("khtml-") || - prop.startsWith("apple-") || - prop.startsWith("webkit-")) { - prop.insert(0, '-'); - } + for (; i < length; ++i) { + UChar c = propertyName[i]; + if (!WTF::isASCIIUpper(c)) + name.append(c); + else { + name.append('-'); + name.append(WTF::toASCIILower(c)); + } + } - return prop; + return String::adopt(name); } - NAMED_PROPERTY_GETTER(CSSStyleDeclaration) { INC_STATS(L"DOM.CSSStyleDeclaration.NamedPropertyGetter"); // First look for API defined attributes on the style declaration // object. - if (info.Holder()->HasRealNamedCallbackProperty(name)) { + if (info.Holder()->HasRealNamedCallbackProperty(name)) return v8::Handle<v8::Value>(); - } // Search the style declaration. CSSStyleDeclaration* imp = V8Proxy::ToNativeObject<CSSStyleDeclaration>( @@ -1659,7 +1656,7 @@ NAMED_PROPERTY_GETTER(CSSStyleDeclaration) { bool pixel_or_pos; String p = ToWebCoreString(name); - String prop = CSSPropertyName(p, &pixel_or_pos); + String prop = cssPropertyName(p, &pixel_or_pos); // Do not handle non-property names. if (!CSSStyleDeclaration::isPropertyName(prop)) { @@ -1698,7 +1695,7 @@ NAMED_PROPERTY_SETTER(CSSStyleDeclaration) { int ec = 0; bool pixel_or_pos; - String prop = CSSPropertyName(property_name, &pixel_or_pos); + String prop = cssPropertyName(property_name, &pixel_or_pos); if (!CSSStyleDeclaration::isPropertyName(prop)) { return v8::Handle<v8::Value>(); // do not block the call } @@ -1800,6 +1797,9 @@ CALLBACK_FUNC_DECL(CSSPrimitiveValueGetRGBColorValue) { static_cast<Peerable*>(new RGBColor(rgbcolor))); } + +// CanvasRenderingContext2D ---------------------------------------------------- + // Helper macro for converting v8 values into floats (expected by many of the // canvas functions). #define TO_FLOAT(a) static_cast<float>((a)->NumberValue()) @@ -1849,7 +1849,6 @@ CALLBACK_FUNC_DECL(CanvasRenderingContext2DSetStrokeColor) { return v8::Undefined(); } - CALLBACK_FUNC_DECL(CanvasRenderingContext2DSetFillColor) { INC_STATS(L"DOM.CanvasRenderingContext2D.steFillColor()"); CanvasRenderingContext2D* context = @@ -1891,39 +1890,31 @@ CALLBACK_FUNC_DECL(CanvasRenderingContext2DSetFillColor) { return v8::Undefined(); } - CALLBACK_FUNC_DECL(CanvasRenderingContext2DStrokeRect) { INC_STATS(L"DOM.CanvasRenderingContext2D.strokeRect()"); CanvasRenderingContext2D* context = V8Proxy::ToNativeObject<CanvasRenderingContext2D>( V8ClassIndex::CANVASRENDERINGCONTEXT2D, args.Holder()); - ExceptionCode ec = 0; double x = 0, y = 0, width = 0, height = 0, line_width = 0; if (args.Length() == 5) { context->strokeRect(TO_FLOAT(args[0]), TO_FLOAT(args[1]), TO_FLOAT(args[2]), TO_FLOAT(args[3]), - TO_FLOAT(args[4]), - ec); + TO_FLOAT(args[4])); } else if (args.Length() == 4) { context->strokeRect(TO_FLOAT(args[0]), TO_FLOAT(args[1]), TO_FLOAT(args[2]), - TO_FLOAT(args[3]), - ec); + TO_FLOAT(args[3])); } else { - // Should throw index error - ec = INDEX_SIZE_ERR; - } - if (ec != 0) { - V8Proxy::SetDOMException(ec); + V8Proxy::SetDOMException(INDEX_SIZE_ERR); return v8::Handle<v8::Value>(); } + return v8::Undefined(); } - CALLBACK_FUNC_DECL(CanvasRenderingContext2DSetShadow) { INC_STATS(L"DOM.CanvasRenderingContext2D.setShadow()"); CanvasRenderingContext2D* context = @@ -1974,7 +1965,6 @@ CALLBACK_FUNC_DECL(CanvasRenderingContext2DSetShadow) { return v8::Undefined(); } - CALLBACK_FUNC_DECL(CanvasRenderingContext2DDrawImage) { INC_STATS(L"DOM.CanvasRenderingContext2D.drawImage()"); CanvasRenderingContext2D* context = @@ -2060,7 +2050,6 @@ CALLBACK_FUNC_DECL(CanvasRenderingContext2DDrawImage) { return v8::Handle<v8::Value>(); } - CALLBACK_FUNC_DECL(CanvasRenderingContext2DDrawImageFromRect) { INC_STATS(L"DOM.CanvasRenderingContext2D.drawImageFromRect()"); CanvasRenderingContext2D* context = @@ -2129,6 +2118,113 @@ CALLBACK_FUNC_DECL(CanvasRenderingContext2DCreatePattern) { return v8::Handle<v8::Value>(); } +CALLBACK_FUNC_DECL(CanvasRenderingContext2DFillText) { + INC_STATS(L"DOM.CanvasRenderingContext2D.fillText()"); + V8Proxy::SetDOMException(NOT_SUPPORTED_ERR); + return v8::Undefined(); +} + +CALLBACK_FUNC_DECL(CanvasRenderingContext2DStrokeText) { + INC_STATS(L"DOM.CanvasRenderingContext2D.strokeText()"); + V8Proxy::SetDOMException(NOT_SUPPORTED_ERR); + return v8::Undefined(); +} + +CALLBACK_FUNC_DECL(CanvasRenderingContext2DPutImageData) { + INC_STATS(L"DOM.CanvasRenderingContext2D.putImageData()"); + V8Proxy::SetDOMException(NOT_SUPPORTED_ERR); + return v8::Undefined(); +} + + +// Console --------------------------------------------------------------------- + +CALLBACK_FUNC_DECL(ConsoleAssert) { + INC_STATS(L"DOM.Console.assert()"); + V8Proxy::SetDOMException(NOT_SUPPORTED_ERR); + return v8::Undefined(); +} + +CALLBACK_FUNC_DECL(ConsoleCount) { + INC_STATS(L"DOM.Console.count()"); + V8Proxy::SetDOMException(NOT_SUPPORTED_ERR); + return v8::Undefined(); +} + +CALLBACK_FUNC_DECL(ConsoleDebug) { + INC_STATS(L"DOM.Console.debug()"); + V8Proxy::SetDOMException(NOT_SUPPORTED_ERR); + return v8::Undefined(); +} + +CALLBACK_FUNC_DECL(ConsoleDir) { + INC_STATS(L"DOM.Console.dir()"); + V8Proxy::SetDOMException(NOT_SUPPORTED_ERR); + return v8::Undefined(); +} + +CALLBACK_FUNC_DECL(ConsoleError) { + INC_STATS(L"DOM.Console.error()"); + v8::Handle<v8::Value> holder = args.Holder(); + Console* imp = V8Proxy::ToNativeObject<Console>(V8ClassIndex::CONSOLE, holder); + String message = ToWebCoreString(args[0]); + imp->error(message); + return v8::Undefined(); +} + +CALLBACK_FUNC_DECL(ConsoleGroup) { + INC_STATS(L"DOM.Console.group()"); + V8Proxy::SetDOMException(NOT_SUPPORTED_ERR); + return v8::Undefined(); +} + +CALLBACK_FUNC_DECL(ConsoleInfo) { + INC_STATS(L"DOM.Console.info()"); + v8::Handle<v8::Value> holder = args.Holder(); + Console* imp = V8Proxy::ToNativeObject<Console>(V8ClassIndex::CONSOLE, holder); + String message = ToWebCoreString(args[0]); + imp->info(message); + return v8::Undefined(); +} + +CALLBACK_FUNC_DECL(ConsoleLog) { + INC_STATS(L"DOM.Console.log()"); + v8::Handle<v8::Value> holder = args.Holder(); + Console* imp = V8Proxy::ToNativeObject<Console>(V8ClassIndex::CONSOLE, holder); + String message = ToWebCoreString(args[0]); + imp->log(message); + return v8::Undefined(); +} + +CALLBACK_FUNC_DECL(ConsoleProfile) { + INC_STATS(L"DOM.Console.profile()"); + V8Proxy::SetDOMException(NOT_SUPPORTED_ERR); + return v8::Undefined(); +} + +CALLBACK_FUNC_DECL(ConsoleProfileEnd) { + INC_STATS(L"DOM.Console.profileEnd()"); + V8Proxy::SetDOMException(NOT_SUPPORTED_ERR); + return v8::Undefined(); +} + +CALLBACK_FUNC_DECL(ConsoleTimeEnd) { + INC_STATS(L"DOM.Console.timeEnd()"); + V8Proxy::SetDOMException(NOT_SUPPORTED_ERR); + return v8::Undefined(); +} + +CALLBACK_FUNC_DECL(ConsoleWarn) { + INC_STATS(L"DOM.Console.warn()"); + v8::Handle<v8::Value> holder = args.Holder(); + Console* imp = V8Proxy::ToNativeObject<Console>(V8ClassIndex::CONSOLE, holder); + String message = ToWebCoreString(args[0]); + imp->warn(message); + return v8::Undefined(); +} + + +// Clipboard ------------------------------------------------------------------- CALLBACK_FUNC_DECL(ClipboardClearData) { INC_STATS(L"DOM.Clipboard.clearData()"); @@ -2215,6 +2311,71 @@ static bool AllowSettingFrameSrcToJavascriptUrl(HTMLFrameElementBase* frame, } +// Element --------------------------------------------------------------------- + +CALLBACK_FUNC_DECL(ElementQuerySelector) { + INC_STATS(L"DOM.Element.querySelector()"); + Element* element = V8Proxy::DOMWrapperToNode<Element>(args.Holder()); + + ExceptionCode ec = 0; + + String selectors = valueToStringWithNullOrUndefinedCheck(args[0]); + + NSResolver* resolver = 0; + if (V8NSResolver::HasInstance(args[1])) { + resolver = V8Proxy::ToNativeObject<NSResolver>( + V8ClassIndex::NSRESOLVER, args[1]); + } else if (args[1]->IsObject()) { + resolver = new JSNSResolver(args[1]->ToObject()); + } else if (!args[1]->IsNull() && !args[1]->IsUndefined()) { + V8Proxy::SetDOMException(TYPE_MISMATCH_ERR); + return v8::Handle<v8::Value>(); + } + OwnPtr<ExceptionContext> context(new ExceptionContext()); + RefPtr<Element> result = WTF::getPtr( + element->querySelector(selectors, resolver, ec, context.get())); + if (ec != 0) { + V8Proxy::SetDOMException(ec); + return v8::Handle<v8::Value>(); + } + if (context->hadException()) { + v8::ThrowException(context->exception()); + return v8::Undefined(); + } + return V8Proxy::ToV8Object(V8ClassIndex::NODE, WTF::getPtr(result)); +} + +CALLBACK_FUNC_DECL(ElementQuerySelectorAll) { + INC_STATS(L"DOM.Element.querySelectorAll()"); + Element* element = V8Proxy::DOMWrapperToNode<Element>(args.Holder()); + ExceptionCode ec = 0; + + String selectors = valueToStringWithNullOrUndefinedCheck(args[0]); + + NSResolver* resolver = 0; + if (V8NSResolver::HasInstance(args[1])) { + resolver = V8Proxy::ToNativeObject<NSResolver>( + V8ClassIndex::NSRESOLVER, args[1]); + } else if (args[1]->IsObject()) { + resolver = new JSNSResolver(args[1]->ToObject()); + } else if (!args[1]->IsNull() && !args[1]->IsUndefined()) { + V8Proxy::SetDOMException(TYPE_MISMATCH_ERR); + return v8::Handle<v8::Value>(); + } + OwnPtr<ExceptionContext> context(new ExceptionContext()); + RefPtr<NodeList> result = WTF::getPtr( + element->querySelectorAll(selectors, resolver, ec, context.get())); + if (ec != 0) { + V8Proxy::SetDOMException(ec); + return v8::Handle<v8::Value>(); + } + if (context->hadException()) { + v8::ThrowException(context->exception()); + return v8::Undefined(); + } + return V8Proxy::ToV8Object(V8ClassIndex::NODELIST, WTF::getPtr(result)); +} + CALLBACK_FUNC_DECL(ElementSetAttribute) { INC_STATS(L"DOM.Element.setAttribute()"); Element* imp = V8Proxy::DOMWrapperToNode<Element>(args.Holder()); @@ -2234,7 +2395,6 @@ CALLBACK_FUNC_DECL(ElementSetAttribute) { return v8::Undefined(); } - CALLBACK_FUNC_DECL(ElementSetAttributeNode) { INC_STATS(L"DOM.Element.setAttributeNode()"); if (!V8Attr::HasInstance(args[0])) { @@ -2258,7 +2418,6 @@ CALLBACK_FUNC_DECL(ElementSetAttributeNode) { return V8Proxy::NodeToV8Object(result.get()); } - CALLBACK_FUNC_DECL(ElementSetAttributeNS) { INC_STATS(L"DOM.Element.setAttributeNS()"); Element* imp = V8Proxy::DOMWrapperToNode<Element>(args.Holder()); @@ -2279,7 +2438,6 @@ CALLBACK_FUNC_DECL(ElementSetAttributeNS) { return v8::Undefined(); } - CALLBACK_FUNC_DECL(ElementSetAttributeNodeNS) { INC_STATS(L"DOM.Element.setAttributeNodeNS()"); if (!V8Attr::HasInstance(args[0])) { @@ -2304,6 +2462,8 @@ CALLBACK_FUNC_DECL(ElementSetAttributeNodeNS) { } +// Attr ------------------------------------------------------------------------ + ACCESSOR_SETTER(AttrValue) { Attr* imp = V8Proxy::DOMWrapperToNode<Attr>(info.Holder()); @@ -2320,6 +2480,8 @@ ACCESSOR_SETTER(AttrValue) { } +// HTMLFrameElement ------------------------------------------------------------ + ACCESSOR_SETTER(HTMLFrameElementSrc) { HTMLFrameElement* imp = V8Proxy::DOMWrapperToNode<HTMLFrameElement>(info.Holder()); @@ -2330,7 +2492,6 @@ ACCESSOR_SETTER(HTMLFrameElementSrc) { imp->setSrc(v); } - ACCESSOR_SETTER(HTMLFrameElementLocation) { HTMLFrameElement* imp = V8Proxy::DOMWrapperToNode<HTMLFrameElement>(info.Holder()); @@ -2342,6 +2503,8 @@ ACCESSOR_SETTER(HTMLFrameElementLocation) { } +// HTMLIFrameElement ----------------------------------------------------------- + ACCESSOR_SETTER(HTMLIFrameElementSrc) { HTMLIFrameElement* imp = V8Proxy::DOMWrapperToNode<HTMLIFrameElement>(info.Holder()); @@ -2419,6 +2582,9 @@ CALLBACK_FUNC_DECL(DOMWindowSetInterval) { return WindowSetTimeoutImpl(args, false); } + +// HTMLDocument ---------------------------------------------------------------- + // Concatenates "args" to a string. If args is empty, returns empty string. // Firefox/Safari/IE support non-standard arguments to document.write, ex: // document.write("a", "b", "c") --> document.write("abc") @@ -2431,23 +2597,22 @@ static String WriteHelper_GetString(const v8::Arguments& args) { return str; } - CALLBACK_FUNC_DECL(HTMLDocumentWrite) { INC_STATS(L"DOM.HTMLDocument.write()"); HTMLDocument* imp = V8Proxy::DOMWrapperToNode<HTMLDocument>(args.Holder()); - imp->write(WriteHelper_GetString(args)); + imp->write(WriteHelper_GetString(args), + V8Proxy::retrieveWindow()->document()); return v8::Undefined(); } - CALLBACK_FUNC_DECL(HTMLDocumentWriteln) { INC_STATS(L"DOM.HTMLDocument.writeln()"); HTMLDocument* imp = V8Proxy::DOMWrapperToNode<HTMLDocument>(args.Holder()); - imp->writeln(WriteHelper_GetString(args)); + imp->writeln(WriteHelper_GetString(args), + V8Proxy::retrieveWindow()->document()); return v8::Undefined(); } - CALLBACK_FUNC_DECL(HTMLDocumentOpen) { INC_STATS(L"DOM.HTMLDocument.open()"); HTMLDocument* imp = V8Proxy::DOMWrapperToNode<HTMLDocument>(args.Holder()); @@ -2487,7 +2652,6 @@ CALLBACK_FUNC_DECL(HTMLDocumentOpen) { return v8::Undefined(); } - CALLBACK_FUNC_DECL(HTMLDocumentClear) { INC_STATS(L"DOM.HTMLDocument.clear()"); // Do nothing (unimplemented) @@ -2500,6 +2664,8 @@ CALLBACK_FUNC_DECL(HTMLDocumentClear) { } +// Document -------------------------------------------------------------------- + CALLBACK_FUNC_DECL(DocumentEvaluate) { INC_STATS(L"DOM.Document.evaluate()"); @@ -2538,6 +2704,133 @@ CALLBACK_FUNC_DECL(DocumentEvaluate) { static_cast<Peerable*>(result.get())); } +CALLBACK_FUNC_DECL(DocumentQuerySelector) { + INC_STATS(L"DOM.Document.querySelector()"); + Document* document = V8Proxy::DOMWrapperToNode<Document>(args.Holder()); + ExceptionCode ec = 0; + + String selectors = valueToStringWithNullOrUndefinedCheck(args[0]); + + NSResolver* resolver = 0; + if (V8NSResolver::HasInstance(args[1])) { + resolver = V8Proxy::ToNativeObject<NSResolver>( + V8ClassIndex::NSRESOLVER, args[1]); + } else if (args[1]->IsObject()) { + resolver = new JSNSResolver(args[1]->ToObject()); + } else if (!args[1]->IsNull() && !args[1]->IsUndefined()) { + V8Proxy::SetDOMException(TYPE_MISMATCH_ERR); + return v8::Handle<v8::Value>(); + } + OwnPtr<ExceptionContext> context(new ExceptionContext()); + RefPtr<Element> result = WTF::getPtr( + document->querySelector(selectors, resolver, ec, context.get())); + if (ec != 0) { + V8Proxy::SetDOMException(ec); + return v8::Handle<v8::Value>(); + } + if (context->hadException()) { + v8::ThrowException(context->exception()); + return v8::Undefined(); + } + return V8Proxy::ToV8Object(V8ClassIndex::NODE, WTF::getPtr(result)); +} + +CALLBACK_FUNC_DECL(DocumentQuerySelectorAll) { + INC_STATS(L"DOM.Document.querySelectorAll()"); + Document* document = V8Proxy::DOMWrapperToNode<Document>(args.Holder()); + ExceptionCode ec = 0; + + String selectors = valueToStringWithNullOrUndefinedCheck(args[0]); + + NSResolver* resolver = 0; + if (V8NSResolver::HasInstance(args[1])) { + resolver = V8Proxy::ToNativeObject<NSResolver>( + V8ClassIndex::NSRESOLVER, args[1]); + } else if (args[1]->IsObject()) { + resolver = new JSNSResolver(args[1]->ToObject()); + } else if (!args[1]->IsNull() && !args[1]->IsUndefined()) { + V8Proxy::SetDOMException(TYPE_MISMATCH_ERR); + return v8::Handle<v8::Value>(); + } + OwnPtr<ExceptionContext> context(new ExceptionContext()); + RefPtr<NodeList> result = WTF::getPtr( + document->querySelectorAll(selectors, resolver, ec, context.get())); + if (ec != 0) { + V8Proxy::SetDOMException(ec); + return v8::Handle<v8::Value>(); + } + if (context->hadException()) { + v8::ThrowException(context->exception()); + return v8::Undefined(); + } + return V8Proxy::ToV8Object(V8ClassIndex::NODELIST, WTF::getPtr(result)); +} + +CALLBACK_FUNC_DECL(DocumentFragmentQuerySelector) { + INC_STATS(L"DOM.DocumentFragment.querySelector()"); + DocumentFragment* fragment = + V8Proxy::DOMWrapperToNode<DocumentFragment>(args.Holder()); + ExceptionCode ec = 0; + + String selectors = valueToStringWithNullOrUndefinedCheck(args[0]); + + NSResolver* resolver = 0; + if (V8NSResolver::HasInstance(args[1])) { + resolver = V8Proxy::ToNativeObject<NSResolver>( + V8ClassIndex::NSRESOLVER, args[1]); + } else if (args[1]->IsObject()) { + resolver = new JSNSResolver(args[1]->ToObject()); + } else if (!args[1]->IsNull() && !args[1]->IsUndefined()) { + V8Proxy::SetDOMException(TYPE_MISMATCH_ERR); + return v8::Handle<v8::Value>(); + } + OwnPtr<ExceptionContext> context(new ExceptionContext()); + RefPtr<Element> result = WTF::getPtr( + fragment->querySelector(selectors, resolver, ec, context.get())); + if (ec != 0) { + V8Proxy::SetDOMException(ec); + return v8::Handle<v8::Value>(); + } + if (context->hadException()) { + v8::ThrowException(context->exception()); + return v8::Undefined(); + } + return V8Proxy::ToV8Object(V8ClassIndex::NODE, WTF::getPtr(result)); +} + +CALLBACK_FUNC_DECL(DocumentFragmentQuerySelectorAll) { + INC_STATS(L"DOM.DocumentFragment.querySelectorAll()"); + DocumentFragment* fragment = + V8Proxy::DOMWrapperToNode<DocumentFragment>(args.Holder()); + ExceptionCode ec = 0; + + String selectors = valueToStringWithNullOrUndefinedCheck(args[0]); + + NSResolver* resolver = 0; + if (V8NSResolver::HasInstance(args[1])) { + resolver = V8Proxy::ToNativeObject<NSResolver>( + V8ClassIndex::NSRESOLVER, args[1]); + } else if (args[1]->IsObject()) { + resolver = new JSNSResolver(args[1]->ToObject()); + } else if (!args[1]->IsNull() && !args[1]->IsUndefined()) { + V8Proxy::SetDOMException(TYPE_MISMATCH_ERR); + return v8::Handle<v8::Value>(); + } + OwnPtr<ExceptionContext> context(new ExceptionContext()); + RefPtr<NodeList> result = WTF::getPtr( + fragment->querySelectorAll(selectors, resolver, ec, context.get())); + if (ec != 0) { + V8Proxy::SetDOMException(ec); + return v8::Handle<v8::Value>(); + } + if (context->hadException()) { + v8::ThrowException(context->exception()); + return v8::Undefined(); + } + return V8Proxy::ToV8Object(V8ClassIndex::NODELIST, WTF::getPtr(result)); +} + +// DOMWindow ------------------------------------------------------------------- static bool IsAscii(const String& str) { for (size_t i = 0; i < str.length(); i++) { @@ -2547,7 +2840,6 @@ static bool IsAscii(const String& str) { return true; } - static v8::Handle<v8::Value> Base64Convert(const String& str, bool encode) { if (!IsAscii(str)) { V8Proxy::SetDOMException(INVALID_CHARACTER_ERR); @@ -2572,7 +2864,6 @@ static v8::Handle<v8::Value> Base64Convert(const String& str, bool encode) { return v8String(String(out.data(), out.size())); } - CALLBACK_FUNC_DECL(DOMWindowAtob) { INC_STATS(L"DOM.DOMWindow.atob()"); DOMWindow* imp = V8Proxy::ToNativeObject<DOMWindow>( @@ -2595,7 +2886,6 @@ CALLBACK_FUNC_DECL(DOMWindowAtob) { return Base64Convert(str, false); } - CALLBACK_FUNC_DECL(DOMWindowBtoa) { INC_STATS(L"DOM.DOMWindow.btoa()"); DOMWindow* imp = V8Proxy::ToNativeObject<DOMWindow>( @@ -2618,23 +2908,25 @@ CALLBACK_FUNC_DECL(DOMWindowBtoa) { return Base64Convert(str, true); } - // TODO(fqian): returning string is cheating, and we should // fix this by calling toString function on the receiver. // However, V8 implements toString in JavaScript, which requires // switching context of receiver. I consider it is dangerous. -CALLBACK_FUNC_DECL(DOMWindowToString) { - INC_STATS(L"DOM.DOMWindow.toString()"); - return args.This()->ObjectProtoToString(); +CALLBACK_FUNC_DECL(DOMWindowToString) +{ + INC_STATS(L"DOM.DOMWindow.toString()"); + return args.This()->ObjectProtoToString(); } - -CALLBACK_FUNC_DECL(DOMWindowNOP) { - INC_STATS(L"DOM.DOMWindow.nop()"); - return v8::Undefined(); +CALLBACK_FUNC_DECL(DOMWindowNOP) +{ + INC_STATS(L"DOM.DOMWindow.nop()"); + return v8::Undefined(); } +// EventTargetNode ------------------------------------------------------------- + CALLBACK_FUNC_DECL(EventTargetNodeAddEventListener) { INC_STATS(L"DOM.EventTargetNode.addEventListener()"); EventTargetNode* node = @@ -2654,7 +2946,6 @@ CALLBACK_FUNC_DECL(EventTargetNodeAddEventListener) { return v8::Undefined(); } - CALLBACK_FUNC_DECL(EventTargetNodeRemoveEventListener) { INC_STATS(L"DOM.EventTargetNode.removeEventListener()"); EventTargetNode* node = @@ -2679,365 +2970,164 @@ CALLBACK_FUNC_DECL(EventTargetNodeRemoveEventListener) { } -// ------------------------------------------------------------------ -// Customized XMLHttpRequest binding implementation - -// Use an array to hold dependents. It works like a ref-counted scheme. -// A value can be added more than once to the xhr object. -static void CreateHiddenXHRDependency(v8::Local<v8::Object> xhr, - v8::Local<v8::Value> value) { - ASSERT(V8Proxy::GetDOMWrapperType(xhr) == V8ClassIndex::XMLHTTPREQUEST); - v8::Local<v8::Value> cache = - xhr->GetInternalField(V8Custom::kXMLHttpRequestCacheIndex); - if (cache->IsNull() || cache->IsUndefined()) { - cache = v8::Array::New(); - xhr->SetInternalField(V8Custom::kXMLHttpRequestCacheIndex, cache); - } - - v8::Local<v8::Array> cache_array = v8::Local<v8::Array>::Cast(cache); - cache_array->Set(v8::Integer::New(cache_array->Length()), value); -} - - -static void RemoveHiddenXHRDependency(v8::Local<v8::Object> xhr, - v8::Local<v8::Value> value) { - ASSERT(V8Proxy::GetDOMWrapperType(xhr) == V8ClassIndex::XMLHTTPREQUEST); - v8::Local<v8::Value> cache = - xhr->GetInternalField(V8Custom::kXMLHttpRequestCacheIndex); - ASSERT(cache->IsArray()); - v8::Local<v8::Array> cache_array = v8::Local<v8::Array>::Cast(cache); - for (int i = cache_array->Length() - 1; i >= 0; i--) { - v8::Local<v8::Value> cached = cache_array->Get(v8::Integer::New(i)); - if (cached->StrictEquals(value)) { - cache_array->Delete(i); - return; - } - } - - // Should not reach here. - ASSERT(false); -} - - -ACCESSOR_SETTER(XMLHttpRequestOnreadystatechange) { - XMLHttpRequest* imp = V8Proxy::ToNativeObject<XMLHttpRequest>( - V8ClassIndex::XMLHTTPREQUEST, info.Holder()); - if (value->IsNull()) { - if (imp->onreadystatechange()) { - V8XHREventListener* listener = - static_cast<V8XHREventListener*>(imp->onreadystatechange()); - v8::Local<v8::Object> v8_listener = listener->GetListenerObject(); - RemoveHiddenXHRDependency(info.Holder(), v8_listener); - } - - // Clear the listener - imp->setOnreadystatechange(0); - - } else { - V8Proxy* proxy = V8Proxy::retrieve(imp->document()->frame()); - if (!proxy) - return; - - EventListener* listener = - proxy->FindOrCreateXHREventListener(value, false); - if (listener) { - imp->setOnreadystatechange(listener); - CreateHiddenXHRDependency(info.Holder(), value); - } - } -} - - -ACCESSOR_SETTER(XMLHttpRequestOnload) { - XMLHttpRequest* imp = V8Proxy::ToNativeObject<XMLHttpRequest>( - V8ClassIndex::XMLHTTPREQUEST, info.Holder()); - if (value->IsNull()) { - if (imp->onload()) { - V8XHREventListener* listener = - static_cast<V8XHREventListener*>(imp->onload()); - v8::Local<v8::Object> v8_listener = listener->GetListenerObject(); - RemoveHiddenXHRDependency(info.Holder(), v8_listener); - } - - imp->setOnload(0); - - } else { - V8Proxy* proxy = V8Proxy::retrieve(imp->document()->frame()); - if (!proxy) - return; - - EventListener* listener = - proxy->FindOrCreateXHREventListener(value, false); - if (listener) { - imp->setOnload(listener); - CreateHiddenXHRDependency(info.Holder(), value); - } - } -} - - -CALLBACK_FUNC_DECL(XMLHttpRequestAddEventListener) { - INC_STATS(L"DOM.XMLHttpRequest.addEventListener()"); - XMLHttpRequest* imp = V8Proxy::ToNativeObject<XMLHttpRequest>( - V8ClassIndex::XMLHTTPREQUEST, args.Holder()); - - V8Proxy* proxy = V8Proxy::retrieve(imp->document()->frame()); - if (!proxy) - return v8::Undefined(); - - EventListener* listener = - proxy->FindOrCreateXHREventListener(args[1], false); - if (listener) { - String type = ToWebCoreString(args[0]); - bool useCapture = args[2]->BooleanValue(); - imp->addEventListener(type, listener, useCapture); - - CreateHiddenXHRDependency(args.Holder(), args[1]); - } - return v8::Undefined(); -} - - -CALLBACK_FUNC_DECL(XMLHttpRequestRemoveEventListener) { - INC_STATS(L"DOM.XMLHttpRequest.removeEventListener()"); - XMLHttpRequest* imp = V8Proxy::ToNativeObject<XMLHttpRequest>( - V8ClassIndex::XMLHTTPREQUEST, args.Holder()); - - V8Proxy* proxy = V8Proxy::retrieve(imp->document()->frame()); - if (!proxy) - return v8::Undefined(); // probably leaked - - EventListener* listener = - proxy->FindXHREventListener(args[1], false); - - if (listener) { - String type = ToWebCoreString(args[0]); - bool useCapture = args[2]->BooleanValue(); - imp->removeEventListener(type, listener, useCapture); - - RemoveHiddenXHRDependency(args.Holder(), args[1]); - } - - return v8::Undefined(); -} - - -CALLBACK_FUNC_DECL(XMLHttpRequestOpen) { - INC_STATS(L"DOM.XMLHttpRequest.open()"); - // Four cases: - // open(method, url) - // open(method, url, async) - // open(method, url, async, user) - // open(method, url, async, user, passwd) - - if (args.Length() < 2) { - V8Proxy::ThrowError(V8Proxy::SYNTAX_ERROR, "Not enough arguments"); - return v8::Undefined(); - } - - // get the implementation - XMLHttpRequest* xhr = V8Proxy::ToNativeObject<XMLHttpRequest>( - V8ClassIndex::XMLHTTPREQUEST, args.Holder()); - - // retrieve parameters - String method = ToWebCoreString(args[0]); - String urlstring = ToWebCoreString(args[1]); - V8Proxy* proxy = V8Proxy::retrieve(); - KURL url = - proxy->frame()->document()->completeURL(urlstring).deprecatedString(); - - bool async = (args.Length() < 3) ? true : args[2]->BooleanValue(); - - ExceptionCode ec = 0; - String user, passwd; - if (args.Length() >= 4 && !args[3]->IsUndefined()) { - user = valueToStringWithNullCheck(args[3]); - - if (args.Length() >= 5 && !args[4]->IsUndefined()) { - passwd = valueToStringWithNullCheck(args[4]); - xhr->open(method, url, async, user, passwd, ec); - } else { - xhr->open(method, url, async, user, ec); - } - } else { - xhr->open(method, url, async, ec); - } - - if (ec != 0) { - V8Proxy::SetDOMException(ec); - return v8::Handle<v8::Value>(); - } - - return v8::Undefined(); -} - - -static bool IsDocumentType(v8::Handle<v8::Value> value) { - // TODO(fqian): add other document types. - return V8Document::HasInstance(value) || V8HTMLDocument::HasInstance(value); -} - - -CALLBACK_FUNC_DECL(XMLHttpRequestSend) { - INC_STATS(L"DOM.XMLHttpRequest.send()"); - // Two cases: - // send(document) - // send(string) - - // get implementation - XMLHttpRequest* xhr = V8Proxy::ToNativeObject<XMLHttpRequest>( - V8ClassIndex::XMLHTTPREQUEST, args.Holder()); - - String body; - if (args.Length() >= 1) { - v8::Handle<v8::Value> arg = args[0]; - if (IsDocumentType(arg)) { - v8::Handle<v8::Object> obj = v8::Handle<v8::Object>::Cast(arg); - Document* doc = V8Proxy::DOMWrapperToNode<Document>(obj); - ASSERT(doc); - body = doc->toString(); - } else { - body = valueToStringWithNullCheck(arg); - } - } - - ExceptionCode ec = 0; - xhr->send(body, ec); - if (ec != 0) { - V8Proxy::SetDOMException(ec); - return v8::Handle<v8::Value>(); - } - - return v8::Undefined(); -} - - -CALLBACK_FUNC_DECL(XMLHttpRequestSetRequestHeader) { - INC_STATS(L"DOM.XMLHttpRequest.setRequestHeader()"); - if (args.Length() < 2) { - V8Proxy::ThrowError(V8Proxy::SYNTAX_ERROR, "Not enough arguments"); - return v8::Undefined(); - } - - XMLHttpRequest* imp = V8Proxy::ToNativeObject<XMLHttpRequest>( - V8ClassIndex::XMLHTTPREQUEST, args.Holder()); - ExceptionCode ec = 0; - String header = ToWebCoreString(args[0]); - String value = ToWebCoreString(args[1]); - imp->setRequestHeader(header, value, ec); - if (ec != 0) { - V8Proxy::SetDOMException(ec); - return v8::Handle<v8::Value>(); - } - return v8::Undefined(); -} - - -CALLBACK_FUNC_DECL(XMLHttpRequestGetResponseHeader) { - INC_STATS(L"DOM.XMLHttpRequest.getResponseHeader()"); - if (args.Length() < 1) { - V8Proxy::ThrowError(V8Proxy::SYNTAX_ERROR, "Not enough arguments"); - return v8::Undefined(); - } - - XMLHttpRequest* imp = V8Proxy::ToNativeObject<XMLHttpRequest>( - V8ClassIndex::XMLHTTPREQUEST, args.Holder()); - ExceptionCode ec = 0; - String header = ToWebCoreString(args[0]); - String result = imp->getResponseHeader(header, ec); - if (ec != 0) { - V8Proxy::SetDOMException(ec); - return v8::Handle<v8::Value>(); - } - return v8StringOrNull(result); -} - - -CALLBACK_FUNC_DECL(XMLHttpRequestOverrideMimeType) { - INC_STATS(L"DOM.XMLHttpRequest.overrideMimeType()"); - if (args.Length() < 1) { - V8Proxy::ThrowError(V8Proxy::SYNTAX_ERROR, "Not enough arguments"); - return v8::Undefined(); - } - - XMLHttpRequest* imp = V8Proxy::ToNativeObject<XMLHttpRequest>( - V8ClassIndex::XMLHTTPREQUEST, args.Holder()); - String value = ToWebCoreString(args[0]); - imp->overrideMIMEType(value); - return v8::Undefined(); -} +// TreeWalker ------------------------------------------------------------------ CALLBACK_FUNC_DECL(TreeWalkerParentNode) { INC_STATS(L"DOM.TreeWalker.parentNode()"); - TreeWalker* imp = V8Proxy::ToNativeObject<TreeWalker>( + TreeWalker* treeWalker = V8Proxy::ToNativeObject<TreeWalker>( V8ClassIndex::TREEWALKER, args.Holder()); - return V8Proxy::NodeToV8Object(imp->parentNode()); + + OwnPtr<ExceptionContext> context(new ExceptionContext()); + RefPtr<Node> result = treeWalker->parentNode(context.get()); + if (context->hadException()) { + v8::ThrowException(context->exception()); + return v8::Undefined(); + } + if (!result) return v8::Null(); + return V8Proxy::NodeToV8Object(result.get()); } CALLBACK_FUNC_DECL(TreeWalkerFirstChild) { INC_STATS(L"DOM.TreeWalker.firstChild()"); - TreeWalker* imp = V8Proxy::ToNativeObject<TreeWalker>( + TreeWalker* treeWalker = V8Proxy::ToNativeObject<TreeWalker>( V8ClassIndex::TREEWALKER, args.Holder()); - return V8Proxy::NodeToV8Object(imp->firstChild()); + + OwnPtr<ExceptionContext> context(new ExceptionContext()); + RefPtr<Node> result = treeWalker->firstChild(context.get()); + if (context->hadException()) { + v8::ThrowException(context->exception()); + return v8::Undefined(); + } + if (!result) return v8::Null(); + return V8Proxy::NodeToV8Object(result.get()); } CALLBACK_FUNC_DECL(TreeWalkerLastChild) { INC_STATS(L"DOM.TreeWalker.lastChild()"); - TreeWalker* imp = V8Proxy::ToNativeObject<TreeWalker>( + TreeWalker* treeWalker = V8Proxy::ToNativeObject<TreeWalker>( V8ClassIndex::TREEWALKER, args.Holder()); - return V8Proxy::NodeToV8Object(imp->lastChild()); + + OwnPtr<ExceptionContext> context(new ExceptionContext()); + RefPtr<Node> result = treeWalker->lastChild(context.get()); + if (context->hadException()) { + v8::ThrowException(context->exception()); + return v8::Undefined(); + } + if (!result) return v8::Null(); + return V8Proxy::NodeToV8Object(result.get()); } CALLBACK_FUNC_DECL(TreeWalkerNextNode) { INC_STATS(L"DOM.TreeWalker.nextNode()"); - TreeWalker* imp = V8Proxy::ToNativeObject<TreeWalker>( + TreeWalker* treeWalker = V8Proxy::ToNativeObject<TreeWalker>( V8ClassIndex::TREEWALKER, args.Holder()); - return V8Proxy::NodeToV8Object(imp->nextNode()); + + OwnPtr<ExceptionContext> context(new ExceptionContext()); + RefPtr<Node> result = treeWalker->nextNode(context.get()); + if (context->hadException()) { + v8::ThrowException(context->exception()); + return v8::Undefined(); + } + if (!result) return v8::Null(); + return V8Proxy::NodeToV8Object(result.get()); } CALLBACK_FUNC_DECL(TreeWalkerPreviousNode) { INC_STATS(L"DOM.TreeWalker.previousNode()"); - TreeWalker* imp = V8Proxy::ToNativeObject<TreeWalker>( + TreeWalker* treeWalker = V8Proxy::ToNativeObject<TreeWalker>( V8ClassIndex::TREEWALKER, args.Holder()); - return V8Proxy::NodeToV8Object(imp->previousNode()); + + OwnPtr<ExceptionContext> context(new ExceptionContext()); + RefPtr<Node> result = treeWalker->previousNode(context.get()); + if (context->hadException()) { + v8::ThrowException(context->exception()); + return v8::Undefined(); + } + if (!result) return v8::Null(); + return V8Proxy::NodeToV8Object(result.get()); } CALLBACK_FUNC_DECL(TreeWalkerNextSibling) { INC_STATS(L"DOM.TreeWalker.nextSibling()"); - TreeWalker* imp = V8Proxy::ToNativeObject<TreeWalker>( + TreeWalker* treeWalker = V8Proxy::ToNativeObject<TreeWalker>( V8ClassIndex::TREEWALKER, args.Holder()); - return V8Proxy::NodeToV8Object(imp->nextSibling()); + + OwnPtr<ExceptionContext> context(new ExceptionContext()); + RefPtr<Node> result = treeWalker->nextSibling(context.get()); + if (context->hadException()) { + v8::ThrowException(context->exception()); + return v8::Undefined(); + } + if (!result) return v8::Null(); + return V8Proxy::NodeToV8Object(result.get()); } CALLBACK_FUNC_DECL(TreeWalkerPreviousSibling) { INC_STATS(L"DOM.TreeWalker.previousSibling()"); - TreeWalker* imp = V8Proxy::ToNativeObject<TreeWalker>( + TreeWalker* treeWalker = V8Proxy::ToNativeObject<TreeWalker>( V8ClassIndex::TREEWALKER, args.Holder()); - return V8Proxy::NodeToV8Object(imp->previousSibling()); + + OwnPtr<ExceptionContext> context(new ExceptionContext()); + RefPtr<Node> result = treeWalker->previousSibling(context.get()); + if (context->hadException()) { + v8::ThrowException(context->exception()); + return v8::Undefined(); + } + if (!result) return v8::Null(); + return V8Proxy::NodeToV8Object(result.get()); } CALLBACK_FUNC_DECL(NodeIteratorNextNode) { INC_STATS(L"DOM.NodeIterator.nextNode()"); - NodeIterator* imp = V8Proxy::ToNativeObject<NodeIterator>( + NodeIterator* nodeIterator = V8Proxy::ToNativeObject<NodeIterator>( V8ClassIndex::NODEITERATOR, args.Holder()); + ExceptionCode ec = 0; - return V8Proxy::NodeToV8Object(imp->nextNode(ec)); + OwnPtr<ExceptionContext> context(new ExceptionContext()); + RefPtr<Node> result = nodeIterator->nextNode(context.get(), ec); + if (ec != 0) { + V8Proxy::SetDOMException(ec); + return v8::Null(); + } + if (context->hadException()) { + v8::ThrowException(context->exception()); + return v8::Undefined(); + } + if (!result) return v8::Null(); + return V8Proxy::NodeToV8Object(result.get()); } CALLBACK_FUNC_DECL(NodeIteratorPreviousNode) { INC_STATS(L"DOM.NodeIterator.previousNode()"); - NodeIterator* imp = V8Proxy::ToNativeObject<NodeIterator>( + NodeIterator* nodeIterator = V8Proxy::ToNativeObject<NodeIterator>( V8ClassIndex::NODEITERATOR, args.Holder()); + ExceptionCode ec = 0; - return V8Proxy::NodeToV8Object(imp->previousNode(ec)); + OwnPtr<ExceptionContext> context(new ExceptionContext()); + RefPtr<Node> result = nodeIterator->previousNode(context.get(), ec); + if (ec != 0) { + V8Proxy::SetDOMException(ec); + return v8::Null(); + } + if (context->hadException()) { + v8::ThrowException(context->exception()); + return v8::Undefined(); + } + if (!result) return v8::Null(); + return V8Proxy::NodeToV8Object(result.get()); } CALLBACK_FUNC_DECL(NodeFilterAcceptNode) { INC_STATS(L"DOM.NodeFilter.acceptNode()"); - NodeFilter* imp = V8Proxy::ToNativeObject<NodeFilter>( - V8ClassIndex::NODEFILTER, args.Holder()); - Node* node = V8Proxy::DOMWrapperToNode<Node>(args[0]); - return v8::Local<v8::Integer>(v8::Integer::New(imp->acceptNode(node))); + V8Proxy::SetDOMException(NOT_SUPPORTED_ERR); + return v8::Undefined(); +} + +// NSResolver +CALLBACK_FUNC_DECL(NSResolverLookupNamespaceURI) { + INC_STATS(L"DOM.NSResolver.lookupNamespaceURI()"); + V8Proxy::SetDOMException(NOT_SUPPORTED_ERR); + return v8::Undefined(); } ACCESSOR_SETTER(DOMWindowEventHandler) { @@ -3168,6 +3258,21 @@ ACCESSOR_SETTER(HTMLOptionsCollectionLength) { } #if ENABLE(SVG) + +ACCESSOR_GETTER(SVGLengthValue) { + INC_STATS(L"DOM.SVGLength.value"); + V8SVGPODTypeWrapper<SVGLength>* wrapper = V8Proxy::ToNativeObject<V8SVGPODTypeWrapper<SVGLength> >(V8ClassIndex::SVGLENGTH, info.Holder()); + SVGLength imp_instance = *wrapper; + SVGLength* imp = &imp_instance; + return v8::Number::New(imp->value(V8Proxy::GetSVGContext(wrapper))); +} + +CALLBACK_FUNC_DECL(SVGLengthConvertToSpecifiedUnits) { + INC_STATS(L"DOM.SVGLength.convertToSpecifiedUnits"); + V8Proxy::SetDOMException(NOT_SUPPORTED_ERR); + return v8::Undefined(); +} + CALLBACK_FUNC_DECL(SVGMatrixInverse) { INC_STATS(L"DOM.SVGMatrix.inverse()"); AffineTransform imp = @@ -3300,9 +3405,6 @@ NAMED_ACCESS_CHECK(Location) { #undef INDEXED_ACCESS_CHECK #undef NAMED_ACCESS_CHECK -#undef ACCESSOR_GETTER -#undef ACCESSOR_SETTER -#undef CALLBACK_FUNC_DECL #undef NAMED_PROPERTY_GETTER #undef NAMED_PROPERTY_SETTER #undef INDEXED_PROPERTY_GETTER diff --git a/webkit/port/bindings/v8/v8_custom.h b/webkit/port/bindings/v8/v8_custom.h index dae13ab..6c60e33 100644 --- a/webkit/port/bindings/v8/v8_custom.h +++ b/webkit/port/bindings/v8/v8_custom.h @@ -6,9 +6,22 @@ #define V8_CUSTOM_H__ #include <v8.h> +#include "v8_index.h" struct NPObject; +#define CALLBACK_FUNC_DECL(NAME) \ +v8::Handle<v8::Value> V8Custom::v8##NAME##Callback(const v8::Arguments& args) + +#define ACCESSOR_GETTER(NAME) \ +v8::Handle<v8::Value> V8Custom::v8##NAME##AccessorGetter(\ + v8::Local<v8::String> name, const v8::AccessorInfo& info) + +#define ACCESSOR_SETTER(NAME) \ +void V8Custom::v8##NAME##AccessorSetter(v8::Local<v8::String> name, \ + v8::Local<v8::Value> value, \ + const v8::AccessorInfo& info) + namespace WebCore { class Frame; @@ -186,6 +199,10 @@ DECLARE_CALLBACK(HTMLDocumentClear) // Document customized functions DECLARE_CALLBACK(DocumentEvaluate) +DECLARE_CALLBACK(DocumentQuerySelector) +DECLARE_CALLBACK(DocumentQuerySelectorAll) +DECLARE_CALLBACK(DocumentFragmentQuerySelector) +DECLARE_CALLBACK(DocumentFragmentQuerySelectorAll) // Window customized functions DECLARE_CALLBACK(DOMWindowAddEventListener) @@ -225,6 +242,23 @@ DECLARE_CALLBACK(CanvasRenderingContext2DSetShadow) DECLARE_CALLBACK(CanvasRenderingContext2DDrawImage) DECLARE_CALLBACK(CanvasRenderingContext2DDrawImageFromRect) DECLARE_CALLBACK(CanvasRenderingContext2DCreatePattern) +DECLARE_CALLBACK(CanvasRenderingContext2DFillText) +DECLARE_CALLBACK(CanvasRenderingContext2DStrokeText) +DECLARE_CALLBACK(CanvasRenderingContext2DPutImageData) + +// Console customized functions +DECLARE_CALLBACK(ConsoleAssert) +DECLARE_CALLBACK(ConsoleCount) +DECLARE_CALLBACK(ConsoleDebug) +DECLARE_CALLBACK(ConsoleDir) +DECLARE_CALLBACK(ConsoleError) +DECLARE_CALLBACK(ConsoleGroup) +DECLARE_CALLBACK(ConsoleInfo) +DECLARE_CALLBACK(ConsoleLog) +DECLARE_CALLBACK(ConsoleProfile) +DECLARE_CALLBACK(ConsoleProfileEnd) +DECLARE_CALLBACK(ConsoleTimeEnd) +DECLARE_CALLBACK(ConsoleWarn) // Implementation of Clipboard methods. DECLARE_CALLBACK(ClipboardClearData) @@ -232,6 +266,8 @@ DECLARE_CALLBACK(ClipboardGetData) DECLARE_CALLBACK(ClipboardSetData) // Implementation of Element methods. +DECLARE_CALLBACK(ElementQuerySelector) +DECLARE_CALLBACK(ElementQuerySelectorAll) DECLARE_CALLBACK(ElementSetAttribute) DECLARE_CALLBACK(ElementSetAttributeNode) DECLARE_CALLBACK(ElementSetAttributeNS) @@ -243,8 +279,12 @@ DECLARE_CALLBACK(EventTargetNodeAddEventListener) DECLARE_CALLBACK(EventTargetNodeRemoveEventListener) // Custom implementation of XMLHttpRequest properties -DECLARE_PROPERTY_ACCESSOR_SETTER(XMLHttpRequestOnreadystatechange) -DECLARE_PROPERTY_ACCESSOR_SETTER(XMLHttpRequestOnload) +DECLARE_PROPERTY_ACCESSOR(XMLHttpRequestOnabort) +DECLARE_PROPERTY_ACCESSOR(XMLHttpRequestOnerror) +DECLARE_PROPERTY_ACCESSOR(XMLHttpRequestOnload) +DECLARE_PROPERTY_ACCESSOR(XMLHttpRequestOnloadstart) +DECLARE_PROPERTY_ACCESSOR(XMLHttpRequestOnprogress) +DECLARE_PROPERTY_ACCESSOR(XMLHttpRequestOnreadystatechange) DECLARE_CALLBACK(XMLHttpRequestAddEventListener) DECLARE_CALLBACK(XMLHttpRequestRemoveEventListener) DECLARE_CALLBACK(XMLHttpRequestOpen) @@ -252,6 +292,17 @@ DECLARE_CALLBACK(XMLHttpRequestSend) DECLARE_CALLBACK(XMLHttpRequestSetRequestHeader) DECLARE_CALLBACK(XMLHttpRequestGetResponseHeader) DECLARE_CALLBACK(XMLHttpRequestOverrideMimeType) +DECLARE_CALLBACK(XMLHttpRequestDispatchEvent) + +// Custom implementation of XMLHttpRequestUpload properties +DECLARE_PROPERTY_ACCESSOR(XMLHttpRequestUploadOnabort) +DECLARE_PROPERTY_ACCESSOR(XMLHttpRequestUploadOnerror) +DECLARE_PROPERTY_ACCESSOR(XMLHttpRequestUploadOnload) +DECLARE_PROPERTY_ACCESSOR(XMLHttpRequestUploadOnloadstart) +DECLARE_PROPERTY_ACCESSOR(XMLHttpRequestUploadOnprogress) +DECLARE_CALLBACK(XMLHttpRequestUploadAddEventListener) +DECLARE_CALLBACK(XMLHttpRequestUploadRemoveEventListener) +DECLARE_CALLBACK(XMLHttpRequestUploadDispatchEvent) // Custom implementation of TreeWalker functions DECLARE_CALLBACK(TreeWalkerParentNode) @@ -299,8 +350,13 @@ DECLARE_INDEXED_PROPERTY_SETTER(HTMLOptionsCollection) DECLARE_INDEXED_PROPERTY_SETTER(HTMLSelectElementCollection) DECLARE_NAMED_PROPERTY_GETTER(HTMLCollection) +// NSResolver +DECLARE_CALLBACK(NSResolverLookupNamespaceURI) + // SVG custom properties and callbacks #if ENABLE(SVG) +DECLARE_PROPERTY_ACCESSOR_GETTER(SVGLengthValue) +DECLARE_CALLBACK(SVGLengthConvertToSpecifiedUnits) DECLARE_CALLBACK(SVGMatrixInverse) DECLARE_CALLBACK(SVGMatrixRotateFromVector) #endif diff --git a/webkit/port/bindings/v8/v8_events.cpp b/webkit/port/bindings/v8/v8_events.cpp index feb13f53..33bb48f 100644 --- a/webkit/port/bindings/v8/v8_events.cpp +++ b/webkit/port/bindings/v8/v8_events.cpp @@ -223,6 +223,11 @@ v8::Local<v8::Object> V8EventListener::GetThisObject(Event* event, V8ClassIndex::XMLHTTPREQUEST, target->toXMLHttpRequest()); return v8::Local<v8::Object>::New(v8::Handle<v8::Object>::Cast(value)); + } else if (target->toXMLHttpRequestUpload()) { + v8::Handle<v8::Value> value = V8Proxy::ToV8Object( + V8ClassIndex::XMLHTTPREQUESTUPLOAD, target->toXMLHttpRequestUpload()); + return v8::Local<v8::Object>::New(v8::Handle<v8::Object>::Cast(value)); + } else { ASSERT(false); return v8::Local<v8::Object>(); diff --git a/webkit/port/bindings/v8/v8_index.cpp b/webkit/port/bindings/v8/v8_index.cpp index 4cbe7d9..e731b05 100644 --- a/webkit/port/bindings/v8/v8_index.cpp +++ b/webkit/port/bindings/v8/v8_index.cpp @@ -38,6 +38,7 @@ #include "V8CanvasRenderingContext2D.h" #include "V8CanvasGradient.h" #include "V8CanvasPattern.h" +#include "V8CanvasPixelArray.h" #include "V8CDATASection.h" #include "V8CharacterData.h" #include "V8Clipboard.h" @@ -63,6 +64,8 @@ #include "V8Element.h" #include "V8Entity.h" #include "V8EntityReference.h" +#include "V8File.h" +#include "V8FileList.h" #include "V8History.h" #include "V8HTMLCanvasElement.h" #include "V8UndetectableHTMLCollection.h" @@ -127,6 +130,7 @@ #include "V8HTMLTextAreaElement.h" #include "V8HTMLTitleElement.h" #include "V8HTMLUListElement.h" +#include "V8ImageData.h" #include "V8InspectorController.h" #include "V8MediaList.h" #include "V8MessageEvent.h" @@ -135,6 +139,7 @@ #include "V8NodeList.h" #include "V8NodeFilter.h" #include "V8Notation.h" +#include "V8NSResolver.h" #include "V8ProcessingInstruction.h" #include "V8ProgressEvent.h" #include "V8StyleSheet.h" @@ -164,6 +169,7 @@ #include "V8RangeException.h" #include "V8Rect.h" #include "V8NodeIterator.h" +#include "V8TextMetrics.h" #include "V8TreeWalker.h" #include "V8StyleSheetList.h" #include "V8DOMImplementation.h" @@ -172,6 +178,7 @@ #include "V8XPathExpression.h" #include "V8XPathNSResolver.h" #include "V8XMLHttpRequest.h" +#include "V8XMLHttpRequestUpload.h" #include "V8XMLHttpRequestException.h" #include "V8XMLSerializer.h" #include "V8XPathEvaluator.h" diff --git a/webkit/port/bindings/v8/v8_index.h b/webkit/port/bindings/v8/v8_index.h index 8ff9d35..0df22e9 100644 --- a/webkit/port/bindings/v8/v8_index.h +++ b/webkit/port/bindings/v8/v8_index.h @@ -211,6 +211,7 @@ typedef v8::Persistent<v8::FunctionTemplate> (*FunctionTemplateFactory)(); V(BARINFO, BarInfo) \ V(CANVASGRADIENT, CanvasGradient) \ V(CANVASPATTERN, CanvasPattern) \ + V(CANVASPIXELARRAY, CanvasPixelArray) \ V(CANVASRENDERINGCONTEXT2D, CanvasRenderingContext2D) \ V(CLIPBOARD, Clipboard) \ V(CONSOLE, Console) \ @@ -235,10 +236,13 @@ typedef v8::Persistent<v8::FunctionTemplate> (*FunctionTemplateFactory)(); V(DOMWINDOW, DOMWindow) \ V(EVENT, Event) \ V(EVENTEXCEPTION, EventException) \ + V(FILE, File) \ + V(FILELIST, FileList) \ V(HISTORY, History) \ V(UNDETECTABLEHTMLCOLLECTION, UndetectableHTMLCollection) \ V(HTMLCOLLECTION, HTMLCollection) \ V(HTMLOPTIONSCOLLECTION, HTMLOptionsCollection) \ + V(IMAGEDATA, ImageData) \ V(INSPECTORCONTROLLER, InspectorController) \ V(KEYBOARDEVENT, KeyboardEvent) \ V(LOCATION, Location) \ @@ -253,6 +257,7 @@ typedef v8::Persistent<v8::FunctionTemplate> (*FunctionTemplateFactory)(); V(NODEFILTER, NodeFilter) \ V(NODEITERATOR, NodeIterator) \ V(NODELIST, NodeList) \ + V(NSRESOLVER, NSResolver) \ V(OVERFLOWEVENT, OverflowEvent) \ V(PLUGIN, Plugin) \ V(PLUGINARRAY, PluginArray) \ @@ -265,10 +270,12 @@ typedef v8::Persistent<v8::FunctionTemplate> (*FunctionTemplateFactory)(); V(STYLESHEET, StyleSheet) \ V(STYLESHEETLIST, StyleSheetList) \ V(TEXTEVENT, TextEvent) \ + V(TEXTMETRICS, TextMetrics) \ V(TREEWALKER, TreeWalker) \ V(UIEVENT, UIEvent) \ V(WHEELEVENT, WheelEvent) \ V(XMLHTTPREQUEST, XMLHttpRequest) \ + V(XMLHTTPREQUESTUPLOAD, XMLHttpRequestUpload) \ V(XMLHTTPREQUESTEXCEPTION, XMLHttpRequestException) \ V(XMLSERIALIZER, XMLSerializer) \ V(XPATHEVALUATOR, XPathEvaluator) \ diff --git a/webkit/port/bindings/v8/v8_nodefilter.cpp b/webkit/port/bindings/v8/v8_nodefilter.cpp index c8846ab..3f958e5 100644 --- a/webkit/port/bindings/v8/v8_nodefilter.cpp +++ b/webkit/port/bindings/v8/v8_nodefilter.cpp @@ -31,6 +31,7 @@ #include "v8_nodefilter.h" #include "v8_proxy.h" +#include "ExceptionContext.h" #include "NodeFilter.h" #include "Node.h" @@ -51,15 +52,17 @@ V8NodeFilterCondition::~V8NodeFilterCondition() { m_filter.Clear(); } -short V8NodeFilterCondition::acceptNode(Node* node) const { +short V8NodeFilterCondition::acceptNode(ExceptionContext* exception_context, + Node* node) const { ASSERT(v8::Context::InContext()); if (!m_filter->IsFunction()) return NodeFilter::FILTER_ACCEPT; - v8::TryCatch exception_catcher; + ExceptionCatcher exception_catcher(exception_context); v8::Handle<v8::Object> this_obj = v8::Context::GetCurrent()->Global(); - v8::Handle<v8::Function> callback = v8::Handle<v8::Function>::Cast(m_filter); + v8::Handle<v8::Function> callback = + v8::Handle<v8::Function>::Cast(m_filter); v8::Handle<v8::Value>* args = new v8::Handle<v8::Value>[1]; args[0] = V8Proxy::ToV8Object(V8ClassIndex::NODE, node); @@ -70,9 +73,7 @@ short V8NodeFilterCondition::acceptNode(Node* node) const { proxy->CallFunction(callback, this_obj, 1, args); delete[] args; - // TODO(fqian): this code can be removed when issue 1042294 is fixed. - // See also 1068243. - if (exception_catcher.HasCaught()) { + if (exception_context->hadException()) { return NodeFilter::FILTER_REJECT; } diff --git a/webkit/port/bindings/v8/v8_nodefilter.h b/webkit/port/bindings/v8/v8_nodefilter.h index cf203eff..ef7906d 100644 --- a/webkit/port/bindings/v8/v8_nodefilter.h +++ b/webkit/port/bindings/v8/v8_nodefilter.h @@ -19,7 +19,8 @@ class V8NodeFilterCondition : public NodeFilterCondition { explicit V8NodeFilterCondition(v8::Handle<v8::Value> filter); virtual ~V8NodeFilterCondition(); - virtual short acceptNode(Node* node) const; + virtual short acceptNode(ExceptionContext* exception_context, + Node* node) const; private: mutable v8::Persistent<v8::Value> m_filter; diff --git a/webkit/port/bindings/v8/v8_proxy.cpp b/webkit/port/bindings/v8/v8_proxy.cpp index 60f0488..ae96b63 100644 --- a/webkit/port/bindings/v8/v8_proxy.cpp +++ b/webkit/port/bindings/v8/v8_proxy.cpp @@ -39,7 +39,6 @@ #include "v8_custom.h" #include "v8_collection.h" #include "v8_nodefilter.h" -#include "V8Bridge.h" #include "RefCounted.h" // for Peerable @@ -65,6 +64,7 @@ #include "Notation.h" #include "Text.h" #include "ProcessingInstruction.h" +#include "Console.h" #include "CharacterData.h" #include "DocumentType.h" #include "DocumentFragment.h" @@ -82,6 +82,7 @@ #include "FrameLoader.h" #include "FrameTree.h" #include "RangeException.h" +#include "ScriptController.h" #include "NodeFilter.h" #include "SecurityOrigin.h" #include "XMLHttpRequestException.h" @@ -97,8 +98,10 @@ #include "XPathEvaluator.h" #endif +#undef LOG #include "base/stats_table.h" #include "base/trace_event.h" +#include "webkit/glue/webkit_glue.h" #include "webkit/glue/glue_util.h" #include "webkit/glue/webkit_glue.h" @@ -154,9 +157,10 @@ namespace WebCore { // typedef HashMap<v8::Value*, GlobalHandleInfo*> GlobalHandleMap; -static GlobalHandleMap& global_handle_map() { - static GlobalHandleMap static_global_handle_map; - return static_global_handle_map; +static GlobalHandleMap& global_handle_map() +{ + static GlobalHandleMap static_global_handle_map; + return static_global_handle_map; } @@ -178,12 +182,12 @@ void V8Proxy::RegisterGlobalHandle(GlobalHandleType type, void* host, } -void V8Proxy::UnregisterGlobalHandle(void* host, - v8::Persistent<v8::Value> handle) { - ASSERT(global_handle_map().contains(*handle)); - GlobalHandleInfo* info = global_handle_map().take(*handle); - ASSERT(info->host_ == host); - delete info; +void V8Proxy::UnregisterGlobalHandle(void* host, v8::Persistent<v8::Value> handle) +{ + ASSERT(global_handle_map().contains(*handle)); + GlobalHandleInfo* info = global_handle_map().take(*handle); + ASSERT(info->host_ == host); + delete info; } #endif // ifndef NDEBUG @@ -293,13 +297,12 @@ static void WeakSVGElementInstanceCallback(v8::Persistent<v8::Object> obj, v8::Handle<v8::Value> V8Proxy::SVGElementInstanceToV8Object( SVGElementInstance* instance) { - if (!instance) return v8::Null(); + if (!instance) + return v8::Null(); - v8::Handle<v8::Object> existing_instance = - dom_svg_element_instance_map().get(instance); - if (!existing_instance.IsEmpty()) { + v8::Handle<v8::Object> existing_instance = dom_svg_element_instance_map().get(instance); + if (!existing_instance.IsEmpty()) return existing_instance; - } instance->ref(); @@ -317,31 +320,34 @@ v8::Handle<v8::Value> V8Proxy::SVGElementInstanceToV8Object( } // SVG non-node elements may have a reference to a context node which -// should be notified when the element is changed +// should be notified when the element is change static void WeakSVGObjectWithContext(v8::Persistent<v8::Object> obj, void* param); // Map of SVG objects with contexts to V8 objects -static DOMWrapperMap<Peerable>& dom_svg_object_with_context_map() { - static DOMPeerableWrapperMap<Peerable> - static_dom_svg_object_with_context_map(&WeakSVGObjectWithContext); - return static_dom_svg_object_with_context_map; +static DOMWrapperMap<Peerable>& dom_svg_object_with_context_map() +{ + static DOMPeerableWrapperMap<Peerable> + static_dom_svg_object_with_context_map(&WeakSVGObjectWithContext); + return static_dom_svg_object_with_context_map; } // Map of SVG objects with contexts to their contexts -static HashMap<void*, SVGElement*>& svg_object_to_context_map() { - static HashMap<void*, SVGElement*> static_svg_object_to_context_map; - return static_svg_object_to_context_map; +static HashMap<void*, SVGElement*>& svg_object_to_context_map() +{ + static HashMap<void*, SVGElement*> static_svg_object_to_context_map; + return static_svg_object_to_context_map; } v8::Handle<v8::Value> V8Proxy::SVGObjectWithContextToV8Object( - Peerable* object, V8ClassIndex::V8WrapperType type) { - if (!object) return v8::Null(); + Peerable* object, V8ClassIndex::V8WrapperType type) +{ + if (!object) + return v8::Null(); // Special case: SVGPathSegs need to be downcast to their real type - if (type == V8ClassIndex::SVGPATHSEG) { + if (type == V8ClassIndex::SVGPATHSEG) type = V8Custom::DowncastSVGPathSeg(object); - } v8::Persistent<v8::Object> result = dom_svg_object_with_context_map().get(object); @@ -372,26 +378,25 @@ static void WeakSVGObjectWithContext(v8::Persistent<v8::Object> obj, dom_svg_object_with_context_map().forget(dom_obj); } -void V8Proxy::SetSVGContext(void* obj, SVGElement* context) { +void V8Proxy::SetSVGContext(void* obj, SVGElement* context) +{ SVGElement* old_context = svg_object_to_context_map().get(obj); - if (old_context == context) { + if (old_context == context) return; - } - if (old_context) { + if (old_context) old_context->deref(); - } - if (context) { + if (context) context->ref(); - } svg_object_to_context_map().set(obj, context); } -SVGElement* V8Proxy::GetSVGContext(void* obj) { - return svg_object_to_context_map().get(obj); +SVGElement* V8Proxy::GetSVGContext(void* obj) +{ + return svg_object_to_context_map().get(obj); } #endif @@ -409,17 +414,17 @@ static void WeakPeerableCallback(v8::Persistent<v8::Object> obj, void* para) { dom_object_map().forget(dom_obj); } - -static void WeakNodeCallback(v8::Persistent<v8::Object> obj, void* param) { +static void WeakNodeCallback(v8::Persistent<v8::Object> obj, void* param) +{ Node* node = static_cast<Node*>(param); ASSERT(dom_node_map().contains(node)); dom_node_map().forget(node); } - // Create object groups for DOM tree nodes. -static void GCPrologue() { +static void GCPrologue() +{ #ifndef NDEBUG // Check that all references in the map are weak. PeerableMap peer_map = dom_object_map().impl(); @@ -448,9 +453,8 @@ static void GCPrologue() { !static_cast<HTMLImageElement*>(node)->haveFiredLoadEvent()) ) { Document* doc = node->document(); v8::Persistent<v8::Object> wrapper = dom_node_map().get(node); - if (!wrapper.IsEmpty()) { + if (!wrapper.IsEmpty()) v8::V8::AddObjectToGroup(doc, wrapper); - } } } } @@ -477,20 +481,23 @@ static void GCEpilogue() { #endif } - // A map from a peerable node to its JS wrapper, the wrapper // is kept as a strong reference to survive GCs. -static PeerableMap& gc_protected_map() { - static PeerableMap static_gc_protected_map; - return static_gc_protected_map; +static PeerableMap& gc_protected_map() +{ + static PeerableMap static_gc_protected_map; + return static_gc_protected_map; } - // static -void V8Proxy::GCProtect(Peerable* dom_object) { - if (!dom_object) return; - if (gc_protected_map().contains(dom_object)) return; - if (!dom_object->peer()) return; +void V8Proxy::GCProtect(Peerable* dom_object) +{ + if (!dom_object) + return; + if (gc_protected_map().contains(dom_object)) + return; + if (!dom_object->peer()) + return; // Create a new (strong) persistent handle for the peer. v8::Persistent<v8::Object> @@ -502,8 +509,10 @@ void V8Proxy::GCProtect(Peerable* dom_object) { // static void V8Proxy::GCUnprotect(Peerable* dom_object) { - if (!dom_object) return; - if (!gc_protected_map().contains(dom_object)) return; + if (!dom_object) + return; + if (!gc_protected_map().contains(dom_object)) + return; // Dispose the strong reference. v8::Persistent<v8::Object> wrapper(gc_protected_map().take(dom_object)); @@ -535,17 +544,13 @@ class JavaScriptConsoleMessage { const unsigned m_lineNumber; }; - -void JavaScriptConsoleMessage::AddToPage(Page* page) const { - ASSERT(page); - Chrome* chrome = page->chrome(); - // Only messages with ErrorMessageLevel are logged when - // calling Chrome::addMessageToConsole(). - chrome->addMessageToConsole(JSMessageSource, ErrorMessageLevel, - m_string, m_lineNumber, m_sourceID); +void JavaScriptConsoleMessage::AddToPage(Page* page) const +{ + ASSERT(page); + Console* console = page->mainFrame()->domWindow()->console(); + console->addMessage(JSMessageSource, ErrorMessageLevel, m_string, m_lineNumber, m_sourceID); } - // The ConsoleMessageManager handles all console messages that stem // from JavaScript. It keeps a list of messages that have been delayed but // it makes sure to add all messages to the console in the right order. @@ -590,21 +595,22 @@ void ConsoleMessageManager::AddMessage( } -void ConsoleMessageManager::AddDelayedMessage( - const JavaScriptConsoleMessage& message) { - if (!m_delayed) { - // Allocate a vector for the delayed messages. Will be - // deallocated when the delayed messages are processed - // in ProcessDelayedMessages(). - m_delayed = new Vector<JavaScriptConsoleMessage>(); - } - m_delayed->append(message); +void ConsoleMessageManager::AddDelayedMessage(const JavaScriptConsoleMessage& message) +{ + if (!m_delayed) + // Allocate a vector for the delayed messages. Will be + // deallocated when the delayed messages are processed + // in ProcessDelayedMessages(). + m_delayed = new Vector<JavaScriptConsoleMessage>(); + m_delayed->append(message); } -void ConsoleMessageManager::ProcessDelayedMessages() { +void ConsoleMessageManager::ProcessDelayedMessages() +{ // If we have a delayed vector it cannot be empty. - if (!m_delayed) return; + if (!m_delayed) + return; ASSERT(!m_delayed->isEmpty()); // Add the delayed messages to the page of the active @@ -613,8 +619,10 @@ void ConsoleMessageManager::ProcessDelayedMessages() { // posting messages. We still deallocate the vector. Frame* frame = V8Proxy::retrieveActiveFrame(); Page* page = NULL; - if (frame) page = frame->page(); - if (!page) m_delayed->clear(); + if (frame) + page = frame->page(); + if (!page) + m_delayed->clear(); // Iterate through all the delayed messages and add them // to the console. @@ -637,23 +645,25 @@ class ConsoleMessageScope { ~ConsoleMessageScope() { ConsoleMessageManager::ProcessDelayedMessages(); } }; - -void log_info(Frame* frame, const String& msg, const String& url) { - Page* page = frame->page(); - if (!page) return; - JavaScriptConsoleMessage message(msg, url, 0); - ConsoleMessageManager::AddMessage(page, message); +void log_info(Frame* frame, const String& msg, const String& url) +{ + Page* page = frame->page(); + if (!page) + return; + JavaScriptConsoleMessage message(msg, url, 0); + ConsoleMessageManager::AddMessage(page, message); } - static void HandleConsoleMessage(v8::Handle<v8::Message> message, v8::Handle<v8::Value> data) { // Use the frame where JavaScript is called from. Frame* frame = V8Proxy::retrieveActiveFrame(); - if (!frame) return; + if (!frame) + return; Page* page = frame->page(); - if (!page) return; + if (!page) + return; v8::Handle<v8::String> errorMessageString = message->Get(); ASSERT(!errorMessageString.IsEmpty()); @@ -679,7 +689,8 @@ enum DelayReporting { static void ReportUnsafeAccessTo(Frame* target, DelayReporting delay) { ASSERT(target); Document* targetDocument = target->document(); - if (!targetDocument) return; + if (!targetDocument) + return; Frame* source = V8Proxy::retrieveActiveFrame(); Document* sourceDocument = source->document(); @@ -690,8 +701,8 @@ static void ReportUnsafeAccessTo(Frame* target, DelayReporting delay) { String str = String::format("Unsafe JavaScript attempt to access frame " "with URL %s from frame with URL %s. Domains, protocols and ports must " "match.\n", - targetDocument->url().utf8().data(), - sourceDocument->url().utf8().data()); + targetDocument->url().string().utf8().data(), + sourceDocument->url().string().utf8().data()); // Build a console message with fake source ID and line number. const String kSourceID = ""; @@ -713,72 +724,72 @@ static void ReportUnsafeAccessTo(Frame* target, DelayReporting delay) { } } - static void ReportUnsafeJavaScriptAccess(v8::Local<v8::Object> host, v8::AccessType type, v8::Local<v8::Value> data) { - // Do not report error if the access type is HAS. - if (type == v8::ACCESS_HAS) return; + // Do not report error if the access type is HAS. + if (type == v8::ACCESS_HAS) + return; - Frame* target = V8Custom::GetTargetFrame(host, data); - if (target) - ReportUnsafeAccessTo(target, REPORT_LATER); + Frame* target = V8Custom::GetTargetFrame(host, data); + if (target) + ReportUnsafeAccessTo(target, REPORT_LATER); } - -static void ReportFatalErrorInV8(const char* location, const char* message) { - // V8 is shutdown, we cannot use V8 api. - // The only thing we can do is to disable JavaScript. - // TODO: clean up V8Proxy and disable JavaScript. - printf("V8 error: %s (%s)\n", message, location); +static void ReportFatalErrorInV8(const char* location, const char* message) +{ + // V8 is shutdown, we cannot use V8 api. + // The only thing we can do is to disable JavaScript. + // TODO: clean up V8Proxy and disable JavaScript. + printf("V8 error: %s (%s)\n", message, location); } - -static void HandleFatalErrorInV8() { - // TODO: We temporarily deal with V8 internal error situations - // such as out-of-memory by crashing the renderer. - CRASH(); +static void HandleFatalErrorInV8() +{ + // TODO: We temporarily deal with V8 internal error situations + // such as out-of-memory by crashing the renderer. + CRASH(); } -V8Proxy::~V8Proxy() { - clear(); - DestroyGlobal(); +V8Proxy::~V8Proxy() +{ + clear(); + DestroyGlobal(); } - -void V8Proxy::DestroyGlobal() { - if (!m_global.IsEmpty()) { +void V8Proxy::DestroyGlobal() +{ + if (!m_global.IsEmpty()) { #ifndef NDEBUG - UnregisterGlobalHandle(this, m_global); + UnregisterGlobalHandle(this, m_global); #endif - m_global.Dispose(); - m_global.Clear(); - } + m_global.Dispose(); + m_global.Clear(); + } } - -void V8Proxy::SetJSWrapperForDOMObject(Peerable* obj, - v8::Persistent<v8::Object> wrapper) { - dom_object_map().set(obj, wrapper); +void V8Proxy::SetJSWrapperForDOMObject(Peerable* obj, v8::Persistent<v8::Object> wrapper) +{ + dom_object_map().set(obj, wrapper); } - -void V8Proxy::SetJSWrapperForDOMNode(Node* node, - v8::Persistent<v8::Object> wrapper) { - dom_node_map().set(node, wrapper); +void V8Proxy::SetJSWrapperForDOMNode(Node* node, v8::Persistent<v8::Object> wrapper) +{ + dom_node_map().set(node, wrapper); } - EventListener* V8Proxy::createHTMLEventHandler(const String& functionName, - const String& code, Node* node) { - return new V8LazyEventListener(m_frame, code, functionName); + const String& code, Node* node) +{ + return new V8LazyEventListener(m_frame, code, functionName); } #if ENABLE(SVG) EventListener* V8Proxy::createSVGEventHandler(const String& functionName, - const String& code, Node* node) { - return new V8LazyEventListener(m_frame, code, functionName); + const String& code, Node* node) +{ + return new V8LazyEventListener(m_frame, code, functionName); } #endif @@ -790,7 +801,8 @@ static V8EventListener* FindEventListenerInList(V8EventListenerList& list, bool html) { ASSERT(v8::Context::InContext()); - if (!listener->IsObject()) return 0; + if (!listener->IsObject()) + return 0; V8EventListenerList::iterator p = list.begin(); while (p != list.end()) { @@ -802,31 +814,31 @@ static V8EventListener* FindEventListenerInList(V8EventListenerList& list, // check using the == operator on the handles. This is much, // much faster than calling StrictEquals through the API in // the negative case. - if (el->isHTMLEventListener() == html && listener == wrapper) { - return el; - } + if (el->isHTMLEventListener() == html && listener == wrapper) + return el; ++p; } return 0; } - // Find an existing wrapper for a JS event listener in the map. V8EventListener* V8Proxy::FindV8EventListener(v8::Local<v8::Value> listener, - bool html) { - return FindEventListenerInList(m_event_listeners, listener, html); + bool html) +{ + return FindEventListenerInList(m_event_listeners, listener, html); } - -V8EventListener* V8Proxy::FindOrCreateV8EventListener(v8::Local<v8::Value> obj, - bool html) { +V8EventListener* V8Proxy::FindOrCreateV8EventListener(v8::Local<v8::Value> obj, bool html) +{ ASSERT(v8::Context::InContext()); - if (!obj->IsObject()) return 0; + if (!obj->IsObject()) + return 0; V8EventListener* wrapper = FindEventListenerInList(m_event_listeners, obj, html); - if (wrapper) return wrapper; + if (wrapper) + return wrapper; // Create a new one, and add to cache. V8EventListener* new_listener = @@ -921,63 +933,63 @@ void V8Proxy::DisconnectEventListeners() { v8::Handle<v8::Script> V8Proxy::CompileScript(v8::Handle<v8::String> code, const String& fileName, - int baseLine) { - const uint16_t* fileNameString = FromWebCoreString(fileName); - v8::Handle<v8::String> name = + int baseLine) +{ + const uint16_t* fileNameString = FromWebCoreString(fileName); + v8::Handle<v8::String> name = v8::String::New(fileNameString, fileName.length()); - v8::Handle<v8::Integer> line = v8::Integer::New(baseLine); - v8::ScriptOrigin origin(name, line); - v8::Handle<v8::Script> script = v8::Script::Compile(code, &origin); - return script; + v8::Handle<v8::Integer> line = v8::Integer::New(baseLine); + v8::ScriptOrigin origin(name, line); + v8::Handle<v8::Script> script = v8::Script::Compile(code, &origin); + return script; } +bool V8Proxy::HandleOutOfMemory() +{ + v8::Local<v8::Context> context = v8::Context::GetCurrent(); -bool V8Proxy::HandleOutOfMemory() { - v8::Local<v8::Context> context = v8::Context::GetCurrent(); - - if (!context->HasOutOfMemoryException()) - return false; + if (!context->HasOutOfMemoryException()) + return false; - // Warning, error, disable JS for this frame? - Frame* frame = V8Proxy::retrieveFrame(context); + // Warning, error, disable JS for this frame? + Frame* frame = V8Proxy::retrieveFrame(context); - V8Proxy* proxy = V8Proxy::retrieve(frame); - // Clean m_context, m_document, and event handlers. - proxy->clear(); - // Destroy the global object. - proxy->DestroyGlobal(); + V8Proxy* proxy = V8Proxy::retrieve(frame); + // Clean m_context, m_document, and event handlers. + proxy->clear(); + // Destroy the global object. + proxy->DestroyGlobal(); - webkit_glue::NotifyJSOutOfMemory(frame); + webkit_glue::NotifyJSOutOfMemory(frame); - // Disable JS. - Settings* settings = frame->settings(); - ASSERT(settings); - settings->setJavaScriptEnabled(false); + // Disable JS. + Settings* settings = frame->settings(); + ASSERT(settings); + settings->setJavaScriptEnabled(false); - return true; + return true; } - v8::Local<v8::Value> V8Proxy::Evaluate(const String& fileName, int baseLine, - const String& str, Node* n) { - ASSERT(v8::Context::InContext()); - - // Compile the script. - v8::Local<v8::String> code = v8ExternalString(str); - TRACE_EVENT_BEGIN("v8.compile", n, ""); - v8::Handle<v8::Script> script = CompileScript(code, fileName, baseLine); - TRACE_EVENT_END("v8.compile", n, ""); - - // Set inlineCode to true for <a href="javascript:doSomething()"> - // and false for <script>doSomething</script>. For some reason, fileName - // gives us this information. - TRACE_EVENT_BEGIN("v8.run", n, ""); - v8::Local<v8::Value> result = RunScript(script, fileName.isNull()); - TRACE_EVENT_END("v8.run", n, ""); - return result; + const String& str, Node* n) +{ + ASSERT(v8::Context::InContext()); + + // Compile the script. + v8::Local<v8::String> code = v8ExternalString(str); + TRACE_EVENT_BEGIN("v8.compile", n, ""); + v8::Handle<v8::Script> script = CompileScript(code, fileName, baseLine); + TRACE_EVENT_END("v8.compile", n, ""); + + // Set inlineCode to true for <a href="javascript:doSomething()"> + // and false for <script>doSomething</script>. For some reason, fileName + // gives us this information. + TRACE_EVENT_BEGIN("v8.run", n, ""); + v8::Local<v8::Value> result = RunScript(script, fileName.isNull()); + TRACE_EVENT_END("v8.run", n, ""); + return result; } - v8::Local<v8::Value> V8Proxy::RunScript(v8::Handle<v8::Script> script, bool inline_code) { if (script.IsEmpty()) @@ -1293,6 +1305,14 @@ v8::Persistent<v8::FunctionTemplate> V8Proxy::GetTemplate( desc->SetCallHandler(USE_CALLBACK(XMLHttpRequestConstructor)); break; } + case V8ClassIndex::XMLHTTPREQUESTUPLOAD: { + // Reserve one more internal field for keeping event listeners. + v8::Local<v8::ObjectTemplate> instance_template = + desc->InstanceTemplate(); + instance_template->SetInternalFieldCount( + V8Custom::kXMLHttpRequestInternalFieldCount); + break; + } case V8ClassIndex::XPATHEVALUATOR: desc->SetCallHandler(USE_CALLBACK(XPathEvaluatorConstructor)); break; @@ -1307,141 +1327,144 @@ v8::Persistent<v8::FunctionTemplate> V8Proxy::GetTemplate( return desc; } - -bool V8Proxy::ContextInitialized() { - return !m_context.IsEmpty(); +bool V8Proxy::ContextInitialized() +{ + return !m_context.IsEmpty(); } - -DOMWindow* V8Proxy::retrieveWindow() { - // TODO: This seems very fragile. How do we know that the global object - // from the current context is something sensible? Do we need to use the - // last entered here? Who calls this? - v8::Handle<v8::Object> global = v8::Context::GetCurrent()->Global(); - if (global.IsEmpty()) return 0; - v8::Handle<v8::Value> window = global->GetPrototype(); - return ToNativeObject<DOMWindow>(V8ClassIndex::DOMWINDOW, window); +DOMWindow* V8Proxy::retrieveWindow() +{ + // TODO: This seems very fragile. How do we know that the global object + // from the current context is something sensible? Do we need to use the + // last entered here? Who calls this? + v8::Handle<v8::Object> global = v8::Context::GetCurrent()->Global(); + if (global.IsEmpty()) + return 0; + v8::Handle<v8::Value> window = global->GetPrototype(); + return ToNativeObject<DOMWindow>(V8ClassIndex::DOMWINDOW, window); } - -Frame* V8Proxy::retrieveFrame(v8::Handle<v8::Context> context) { - v8::Handle<v8::Object> global = context->Global(); - v8::Handle<v8::Value> window_peer = global->GetPrototype(); - DOMWindow* window = - ToNativeObject<DOMWindow>(V8ClassIndex::DOMWINDOW, window_peer); - return window->frame(); +Frame* V8Proxy::retrieveFrame(v8::Handle<v8::Context> context) +{ + v8::Handle<v8::Object> global = context->Global(); + v8::Handle<v8::Value> window_peer = global->GetPrototype(); + DOMWindow* window = ToNativeObject<DOMWindow>(V8ClassIndex::DOMWINDOW, window_peer); + return window->frame(); } - -Frame* V8Proxy::retrieveActiveFrame() { - v8::Handle<v8::Context> context = v8::Context::GetEntered(); - if (context.IsEmpty()) - return 0; - return retrieveFrame(context); +Frame* V8Proxy::retrieveActiveFrame() +{ + v8::Handle<v8::Context> context = v8::Context::GetEntered(); + if (context.IsEmpty()) + return 0; + return retrieveFrame(context); } - -Frame* V8Proxy::retrieveFrame() { - DOMWindow* window = retrieveWindow(); - return window ? window->frame() : 0; +Frame* V8Proxy::retrieveFrame() +{ + DOMWindow* window = retrieveWindow(); + return window ? window->frame() : 0; } - -V8Proxy* V8Proxy::retrieve() { - DOMWindow* window = retrieveWindow(); - ASSERT(window); - return retrieve(window->frame()); +V8Proxy* V8Proxy::retrieve() +{ + DOMWindow* window = retrieveWindow(); + ASSERT(window); + return retrieve(window->frame()); } - -V8Proxy* V8Proxy::retrieve(Frame* frame) { - if (!frame) return 0; - V8Bridge* bridge = static_cast<V8Bridge*>(frame->scriptBridge()); - return bridge->isEnabled() ? bridge->proxy() : 0; +V8Proxy* V8Proxy::retrieve(Frame* frame) +{ + if (!frame) + return 0; + return frame->script()->isEnabled() ? frame->script()->proxy() : 0; } +void V8Proxy::disconnectFrame() +{ + // disconnect all event listeners + DisconnectEventListeners(); -void V8Proxy::disconnectFrame() { - // disconnect all event listeners - DisconnectEventListeners(); - - // clear all timeouts. - if (m_frame->domWindow()) - m_frame->domWindow()->clearAllTimeouts(); -} - -bool V8Proxy::isEnabled() { - Settings* settings = m_frame->settings(); - if (!settings) - return false; - - // In the common case, JavaScript is enabled and we're done. - if (settings->isJavaScriptEnabled()) - return true; - - // If JavaScript has been disabled, we need to look at the frame to tell - // whether this script came from the web or the embedder. Scripts from the - // embedder are safe to run, but scripts from the other sources are - // disallowed. - Document* document = m_frame->document(); - if (!document) - return false; - - SecurityOrigin* origin = document->securityOrigin(); - if (origin->protocol().isEmpty()) - return false; // Uninitialized document - - if (origin->protocol() == "http" || origin->protocol() == "https") - return false; // Web site - - if (origin->protocol() == - webkit_glue::StdStringToString(webkit_glue::GetUIResourceProtocol())) - return true; // Embedder's scripts are ok to run - - // If the scheme is ftp: or file:, an empty file name indicates a directory - // listing, which requires JavaScript to function properly. - const char* kDirProtocols[] = { "ftp", "file" }; - GURL url(document->url().utf8().data()); - for (size_t i = 0; i < arraysize(kDirProtocols); ++i) { - if (origin->protocol() == kDirProtocols[i]) { - ASSERT(url.SchemeIs(kDirProtocols[i])); - return url.ExtractFileName().empty(); + // clear all timeouts. + if (m_frame->domWindow()) + m_frame->domWindow()->clearAllTimeouts(); +} + +bool V8Proxy::isEnabled() +{ + Settings* settings = m_frame->settings(); + if (!settings) + return false; + + // In the common case, JavaScript is enabled and we're done. + if (settings->isJavaScriptEnabled()) + return true; + + // If JavaScript has been disabled, we need to look at the frame to tell + // whether this script came from the web or the embedder. Scripts from the + // embedder are safe to run, but scripts from the other sources are + // disallowed. + Document* document = m_frame->document(); + if (!document) + return false; + + SecurityOrigin* origin = document->securityOrigin(); + if (origin->protocol().isEmpty()) + return false; // Uninitialized document + + if (origin->protocol() == "http" || origin->protocol() == "https") + return false; // Web site + + if (origin->protocol() == webkit_glue::StdStringToString(webkit_glue::GetUIResourceProtocol())) + return true; // Embedder's scripts are ok to run + + // If the scheme is ftp: or file:, an empty file name indicates a directory + // listing, which requires JavaScript to function properly. + const char* kDirProtocols[] = { "ftp", "file" }; + GURL url = webkit_glue::KURLToGURL(document->url()); + for (size_t i = 0; i < arraysize(kDirProtocols); ++i) { + if (origin->protocol() == kDirProtocols[i]) { + ASSERT(url.SchemeIs(kDirProtocols[i])); + return url.ExtractFileName().empty(); + } } - } - return false; // Other protocols fall through to here + return false; // Other protocols fall through to here } +void V8Proxy::clearDocumentWrapper() +{ + v8::HandleScope handle_scope; + v8::Local<v8::Context> context = GetContext(); + if (context.IsEmpty()) + return; // not initialize yet -void V8Proxy::clearDocumentWrapper() { - v8::HandleScope handle_scope; - v8::Local<v8::Context> context = GetContext(); - if (context.IsEmpty()) return; // not initialize yet - - if (!m_document.IsEmpty()) { + if (!m_document.IsEmpty()) { #ifndef NDEBUG - UnregisterGlobalHandle(this, m_document); + UnregisterGlobalHandle(this, m_document); #endif - m_document.Dispose(); - m_document.Clear(); - } + m_document.Dispose(); + m_document.Clear(); + } } - // static -void V8Proxy::DomainChanged(Frame* frame) { - V8Proxy* proxy = retrieve(frame); - proxy->ClearSecurityToken(); +void V8Proxy::DomainChanged(Frame* frame) +{ + V8Proxy* proxy = retrieve(frame); + proxy->ClearSecurityToken(); } - -void V8Proxy::ClearSecurityToken() { - m_context->SetSecurityToken(m_global); +void V8Proxy::ClearSecurityToken() +{ + m_context->SetSecurityToken(m_global); } +void V8Proxy::clear() +{ + if (m_context.IsEmpty()) + return; -void V8Proxy::clear() { - if (!m_context.IsEmpty()) { ClearSecurityToken(); if (m_frame->domWindow()) @@ -1452,68 +1475,55 @@ void V8Proxy::clear() { // Corresponds to the context creation in initContextIfNeeded(). m_context.Dispose(); m_context.Clear(); - } } - // Check if two frames are from the same origin. // This function is equivalent to // KJS::Window::allowsAccessFrom(const JSGlobalObject*, // SecurityOrigin::Reason&, String& message) const. -static bool SameOrigin(Frame* source, Frame* target, - SecurityOrigin::Reason& reason, String& message) { - if (!source) { - reason = SecurityOrigin::GenericMismatch; - return false; - } +static bool SameOrigin(Frame* source, Frame* target, String& message) +{ + if (!source || !target) + return false; - if (!target) { - reason = SecurityOrigin::GenericMismatch; - return false; - } - - // Allow access if the frames the windows represent are the same. - if (source == target) - return true; + // Allow access if the frames the windows represent are the same. + if (source == target) + return true; - Document* target_document = target->document(); + Document* target_document = target->document(); - // JS may be attempting to access the "window" object, which should be valid, - // even if the document hasn't been constructed yet. If the document doesn't - // exist yet allow JS to access the window object. - if (!target_document) - return true; + // JS may be attempting to access the "window" object, which should be valid, + // even if the document hasn't been constructed yet. If the document doesn't + // exist yet allow JS to access the window object. + if (!target_document) + return true; - Document* act_document = source->document(); + Document* act_document = source->document(); - const SecurityOrigin* active_security_origin = act_document->securityOrigin(); - const SecurityOrigin* target_security_origin = - target_document->securityOrigin(); + const SecurityOrigin* active_security_origin = act_document->securityOrigin(); + const SecurityOrigin* target_security_origin = target_document->securityOrigin(); - String ui_resource_protocol = - webkit_glue::StdStringToString(webkit_glue::GetUIResourceProtocol()); - if (active_security_origin->protocol() == ui_resource_protocol) { - KURL inspector_url = - webkit_glue::GURLToKURL(webkit_glue::GetInspectorURL()); - ASSERT(inspector_url.protocol() == ui_resource_protocol); - ASSERT(inspector_url.protocol().endsWith("-resource")); + String ui_resource_protocol = webkit_glue::StdStringToString(webkit_glue::GetUIResourceProtocol()); + if (active_security_origin->protocol() == ui_resource_protocol) { + KURL inspector_url = webkit_glue::GURLToKURL(webkit_glue::GetInspectorURL()); + ASSERT(inspector_url.protocol() == ui_resource_protocol); + ASSERT(inspector_url.protocol().endsWith("-resource")); - // The Inspector can access anything. - if (active_security_origin->host() == inspector_url.host()) - return true; + // The Inspector can access anything. + if (active_security_origin->host() == inspector_url.host()) + return true; - // To mitigate XSS vulnerabilities on the browser itself, UI resources - // besides the Inspector can't access other documents. - return false; - } + // To mitigate XSS vulnerabilities on the browser itself, UI resources + // besides the Inspector can't access other documents. + return false; + } - if (active_security_origin->canAccess(target_security_origin, reason)) - return true; + if (active_security_origin->canAccess(target_security_origin)) + return true; - return false; + return false; } - // Check if the current execution context can access a target frame. // First it checks same domain policy using the security context // (where the script is invoked), if domain check failed due to @@ -1521,54 +1531,49 @@ static bool SameOrigin(Frame* source, Frame* target, // to check domain policy. // // This is equivalent to KJS::Window::allowsAccessFrom(ExecState*, String&). -bool V8Proxy::CanAccess(Frame* target) { - SecurityOrigin::Reason reason; - String message; - - // Check dynamic (security) context first. - Frame* source = - V8Proxy::retrieveFrame(v8::Context::GetCurrentSecurityContext()); - if (SameOrigin(source, target, reason, message)) { - return true; - } +bool V8Proxy::CanAccess(Frame* target) +{ + String message; + + // Check dynamic (security) context first. + Frame* source = V8Proxy::retrieveFrame(v8::Context::GetCurrentSecurityContext()); + if (SameOrigin(source, target, message)) + return true; - // Check lexical orgin if the reason is DomainSetInDOM mismatch. - if (reason == SecurityOrigin::DomainSetInDOMMismatch) { source = V8Proxy::retrieveFrame(v8::Context::GetCurrent()); - if (SameOrigin(source, target, reason, message)) { - return true; - } - } + if (SameOrigin(source, target, message)) + return true; - return false; + return false; } +bool V8Proxy::IsFromSameOrigin(Frame* target, bool report_error) +{ + // The subject is detached from a frame, deny accesses. + if (!target) + return false; -bool V8Proxy::IsFromSameOrigin(Frame* target, bool report_error) { - // The subject is detached from a frame, deny accesses. - if (!target) return false; - - if (!CanAccess(target)) { - if (report_error) ReportUnsafeAccessTo(target, REPORT_NOW); - return false; - } - return true; + if (!CanAccess(target)) { + if (report_error) + ReportUnsafeAccessTo(target, REPORT_NOW); + return false; + } + return true; } +bool V8Proxy::CheckNodeSecurity(Node* node) +{ + if (!node) + return false; -bool V8Proxy::CheckNodeSecurity(Node* node) { - if (!node) - return false; + Frame* target = node->document()->frame(); - Frame* target = node->document()->frame(); + if (!target) + return false; - if (!target) - return false; - - return IsFromSameOrigin(target, true); + return IsFromSameOrigin(target, true); } - // Create a new environment and setup the global object. // // The global object corresponds to a DOMWindow instance. However, to @@ -1582,9 +1587,11 @@ bool V8Proxy::CheckNodeSecurity(Node* node) { // from javascript. The javascript object that corresponds to a // DOMWindow instance is the shadow object. When mapping a DOMWindow // instance to a V8 object, we return the shadow object. -void V8Proxy::initContextIfNeeded() { +void V8Proxy::initContextIfNeeded() +{ // Bail out if the context has already been initialized. - if (!m_context.IsEmpty()) return; + if (!m_context.IsEmpty()) + return; // Install counters handler with V8. static bool v8_counters_initialized = false; @@ -1619,7 +1626,8 @@ void V8Proxy::initContextIfNeeded() { return; // Install a security handler with V8. - { v8::Local<v8::External> external = + { + v8::Local<v8::External> external = v8::External::New(reinterpret_cast<void*>(V8ClassIndex::DOMWINDOW)); if (external.IsEmpty()) return; @@ -1674,7 +1682,7 @@ void V8Proxy::initContextIfNeeded() { V8Proxy::retrieveFrame(context)->loader()->dispatchWindowObjectAvailable(); - if (JSBridge::RecordPlaybackMode()) { + if (ScriptController::RecordPlaybackMode()) { // Inject code which overrides a few common JS functions for implementing // randomness. In order to implement effective record & playback of // websites, it is important that the URLs not change. Many popular web @@ -1721,13 +1729,10 @@ v8::Handle<v8::Value> V8Proxy::GenerateSecurityToken( } -void V8Proxy::SetDOMException(int exception_code) { - if (exception_code <= 0) return; - - if (exception_code == XMLHttpRequestException::PERMISSION_DENIED) { - ThrowError(GENERAL_ERROR, "Permission denied"); - return; - } +void V8Proxy::SetDOMException(int exception_code) +{ + if (exception_code <= 0) + return; ExceptionCodeDescription description; getExceptionCodeDescription(exception_code, description); @@ -1736,30 +1741,30 @@ void V8Proxy::SetDOMException(int exception_code) { switch (description.type) { case DOMExceptionType: exception = ToV8Object(V8ClassIndex::DOMCOREEXCEPTION, - new DOMCoreException(description)); + DOMCoreException::create(description)); break; case RangeExceptionType: exception = ToV8Object(V8ClassIndex::RANGEEXCEPTION, - new RangeException(description)); + RangeException::create(description)); break; case EventExceptionType: exception = ToV8Object(V8ClassIndex::EVENTEXCEPTION, - new EventException(description)); + EventException::create(description)); break; case XMLHttpRequestExceptionType: exception = ToV8Object(V8ClassIndex::XMLHTTPREQUESTEXCEPTION, - new XMLHttpRequestException(description)); + XMLHttpRequestException::create(description)); break; #if ENABLE(SVG) case SVGExceptionType: exception = ToV8Object(V8ClassIndex::SVGEXCEPTION, - new SVGException(description)); + SVGException::create(description)); break; #endif #if ENABLE(XPATH) case XPathExceptionType: exception = ToV8Object(V8ClassIndex::XPATHEXCEPTION, - new XPathException(description)); + XPathException::create(description)); break; #endif } @@ -1768,8 +1773,8 @@ void V8Proxy::SetDOMException(int exception_code) { v8::ThrowException(exception); } - -v8::Handle<v8::Value> V8Proxy::ThrowError(ErrorType type, const char* message) { +v8::Handle<v8::Value> V8Proxy::ThrowError(ErrorType type, const char* message) +{ switch (type) { case RANGE_ERROR: return v8::ThrowException(v8::Exception::RangeError(v8String(message))); @@ -1788,24 +1793,23 @@ v8::Handle<v8::Value> V8Proxy::ThrowError(ErrorType type, const char* message) { } } +v8::Local<v8::Context> V8Proxy::GetContext(Frame* frame) +{ + V8Proxy* proxy = retrieve(frame); + if (!proxy) + return v8::Local<v8::Context>(); -v8::Local<v8::Context> V8Proxy::GetContext(Frame* frame) { - V8Proxy* proxy = retrieve(frame); - if (!proxy) - return v8::Local<v8::Context>(); - - proxy->initContextIfNeeded(); - return proxy->GetContext(); + proxy->initContextIfNeeded(); + return proxy->GetContext(); } - -v8::Local<v8::Context> V8Proxy::GetCurrentContext() { - return v8::Context::GetCurrent(); +v8::Local<v8::Context> V8Proxy::GetCurrentContext() +{ + return v8::Context::GetCurrent(); } - -v8::Handle<v8::Value> V8Proxy::ToV8Object(V8ClassIndex::V8WrapperType type, - void* imp) { +v8::Handle<v8::Value> V8Proxy::ToV8Object(V8ClassIndex::V8WrapperType type, void* imp) +{ ASSERT(type != V8ClassIndex::EVENTLISTENER); ASSERT(type != V8ClassIndex::EVENTTARGET); ASSERT(type != V8ClassIndex::EVENT); @@ -1830,13 +1834,9 @@ v8::Handle<v8::Value> V8Proxy::ToV8Object(V8ClassIndex::V8WrapperType type, return WindowToV8Object(static_cast<DOMWindow*>(imp)); #if ENABLE(SVG) SVGNONNODE_WRAPPER_TYPES(MAKE_CASE) - if (type == V8ClassIndex::SVGELEMENTINSTANCE) { - return SVGElementInstanceToV8Object( - static_cast<SVGElementInstance*>(imp)); - } else { - return SVGObjectWithContextToV8Object(static_cast<Peerable*>(imp), - type); - } + if (type == V8ClassIndex::SVGELEMENTINSTANCE) + return SVGElementInstanceToV8Object(static_cast<SVGElementInstance*>(imp)); + return SVGObjectWithContextToV8Object(static_cast<Peerable*>(imp), type); #endif default: break; @@ -1876,29 +1876,28 @@ v8::Handle<v8::Value> V8Proxy::ToV8Object(V8ClassIndex::V8WrapperType type, void V8Proxy::SetHiddenWindowReference(Frame* frame, const int internal_index, v8::Handle<v8::Object> jsobj) { - // Get DOMWindow - if (!frame) return; // Object might be detached from window - v8::Handle<v8::Context> context = GetContext(frame); - if (context.IsEmpty()) return; + // Get DOMWindow + if (!frame) return; // Object might be detached from window + v8::Handle<v8::Context> context = GetContext(frame); + if (context.IsEmpty()) return; - ASSERT(internal_index < V8Custom::kDOMWindowInternalFieldCount); + ASSERT(internal_index < V8Custom::kDOMWindowInternalFieldCount); - v8::Handle<v8::Object> global = context->Global(); - ASSERT(!global.IsEmpty()); - // Look for real DOM wrapper. - global = LookupDOMWrapper(V8ClassIndex::DOMWINDOW, global); - ASSERT(global->GetInternalField(internal_index)->IsUndefined()); - global->SetInternalField(internal_index, jsobj); + v8::Handle<v8::Object> global = context->Global(); + ASSERT(!global.IsEmpty()); + // Look for real DOM wrapper. + global = LookupDOMWrapper(V8ClassIndex::DOMWINDOW, global); + ASSERT(global->GetInternalField(internal_index)->IsUndefined()); + global->SetInternalField(internal_index, jsobj); } -V8ClassIndex::V8WrapperType V8Proxy::GetDOMWrapperType( - v8::Handle<v8::Object> object) { +V8ClassIndex::V8WrapperType V8Proxy::GetDOMWrapperType(v8::Handle<v8::Object> object) +{ ASSERT(MaybeDOMWrapper(object)); - v8::Handle<v8::Value> type = object->GetInternalField(V8Custom::kDOMWrapperTypeIndex); - return V8ClassIndex::FromInt(type->Int32Value()); + return V8ClassIndex::FromInt(type->Int32Value()); } @@ -1935,36 +1934,39 @@ void* V8Proxy::ToNativeObjectImpl(V8ClassIndex::V8WrapperType type, return DOMWrapperToNative<Peerable>(object); } - v8::Handle<v8::Object> V8Proxy::LookupDOMWrapper( - V8ClassIndex::V8WrapperType type, v8::Handle<v8::Value> value) { - if (value.IsEmpty()) return v8::Handle<v8::Object>(); - - v8::Handle<v8::FunctionTemplate> desc = V8Proxy::GetTemplate(type); - while (value->IsObject()) { - v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(value); - if (desc->HasInstance(object)) - return object; - - value = object->GetPrototype(); - } - return v8::Handle<v8::Object>(); + V8ClassIndex::V8WrapperType type, v8::Handle<v8::Value> value) +{ + if (value.IsEmpty()) + return v8::Handle<v8::Object>(); + + v8::Handle<v8::FunctionTemplate> desc = V8Proxy::GetTemplate(type); + while (value->IsObject()) { + v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(value); + if (desc->HasInstance(object)) + return object; + + value = object->GetPrototype(); + } + return v8::Handle<v8::Object>(); } -NodeFilter* V8Proxy::ToNativeNodeFilter(v8::Handle<v8::Value> filter) { - // A NodeFilter is used when walking through a DOM tree or iterating tree - // nodes. - // TODO: we may want to cache NodeFilterCondition and NodeFilter - // object, but it is minor. - // NodeFilter is passed to NodeIterator that has a ref counted pointer - // to NodeFilter. NodeFilter has a ref counted pointer to NodeFilterCondition. - // In NodeFilterCondition, filter object is persisted in its constructor, - // and disposed in its destructor. No need to use peer field in this case. - if (!filter->IsFunction()) return 0; +PassRefPtr<NodeFilter> V8Proxy::ToNativeNodeFilter(v8::Handle<v8::Value> filter) +{ + // A NodeFilter is used when walking through a DOM tree or iterating tree + // nodes. + // TODO: we may want to cache NodeFilterCondition and NodeFilter + // object, but it is minor. + // NodeFilter is passed to NodeIterator that has a ref counted pointer + // to NodeFilter. NodeFilter has a ref counted pointer to NodeFilterCondition. + // In NodeFilterCondition, filter object is persisted in its constructor, + // and disposed in its destructor. No need to use peer field in this case. + if (!filter->IsFunction()) + return 0; - NodeFilterCondition* cond = new V8NodeFilterCondition(filter); - return new NodeFilter(cond); + NodeFilterCondition* cond = new V8NodeFilterCondition(filter); + return NodeFilter::create(cond); } @@ -1981,9 +1983,8 @@ v8::Local<v8::Object> V8Proxy::InstantiateV8Object( // Special case for HTMLInputElements that support selection. if (desc_type == V8ClassIndex::HTMLINPUTELEMENT) { HTMLInputElement* element = static_cast<HTMLInputElement*>(imp); - if (element->canHaveSelection()) { + if (element->canHaveSelection()) desc_type = V8ClassIndex::HTMLSELECTIONINPUTELEMENT; - } } v8::Persistent<v8::FunctionTemplate> desc = GetTemplate(desc_type); @@ -1996,15 +1997,14 @@ v8::Local<v8::Object> V8Proxy::InstantiateV8Object( return instance; } -v8::Handle<v8::Value> V8Proxy::CheckNewLegal(const v8::Arguments& args) { - if (!AllowAllocation::m_current) { - return ThrowError(TYPE_ERROR, "Illegal constructor"); - } else { +v8::Handle<v8::Value> V8Proxy::CheckNewLegal(const v8::Arguments& args) +{ + if (!AllowAllocation::m_current) + return ThrowError(TYPE_ERROR, "Illegal constructor"); + return args.This(); - } } - void V8Proxy::SetDOMWrapper(v8::Handle<v8::Object> obj, int type, void* cptr) { ASSERT(obj->InternalFieldCount() >= 2); obj->SetInternalField(V8Custom::kDOMWrapperObjectIndex, WrapCPointer(cptr)); @@ -2144,7 +2144,8 @@ FOR_EACH_TAG(ADD_TO_HASH_MAP) } V8ClassIndex::V8WrapperType t = map.get(element->localName().impl()); - if (t == 0) return V8ClassIndex::HTMLELEMENT; + if (t == 0) + return V8ClassIndex::HTMLELEMENT; return t; } #undef FOR_EACH_TAG @@ -2274,13 +2275,14 @@ FOR_EACH_TAG(ADD_TO_HASH_MAP) #endif // ENABLE(SVG) -v8::Handle<v8::Value> V8Proxy::EventToV8Object(Event* event) { - if (!event) return v8::Null(); +v8::Handle<v8::Value> V8Proxy::EventToV8Object(Event* event) +{ + if (!event) + return v8::Null(); v8::Handle<v8::Object> peer = dom_object_map().get(event); - if (!peer.IsEmpty()) { + if (!peer.IsEmpty()) return peer; - } V8ClassIndex::V8WrapperType type = V8ClassIndex::EVENT; @@ -2324,24 +2326,22 @@ v8::Handle<v8::Value> V8Proxy::NodeToV8Object(Node* node) { if (!node) return v8::Null(); v8::Handle<v8::Object> peer = dom_node_map().get(node); - if (!peer.IsEmpty()) { + if (!peer.IsEmpty()) return peer; - } bool is_document = false; // document type node has special handling V8ClassIndex::V8WrapperType type; switch (node->nodeType()) { case Node::ELEMENT_NODE: - if (node->isHTMLElement()) { + if (node->isHTMLElement()) type = GetHTMLElementType(static_cast<HTMLElement*>(node)); #if ENABLE(SVG) - } else if (node->isSVGElement()) { + else if (node->isSVGElement()) type = GetSVGElementType(static_cast<SVGElement*>(node)); #endif - } else { + else type = V8ClassIndex::ELEMENT; - } break; case Node::ATTRIBUTE_NODE: type = V8ClassIndex::ATTR; @@ -2364,15 +2364,14 @@ v8::Handle<v8::Value> V8Proxy::NodeToV8Object(Node* node) { case Node::DOCUMENT_NODE: { is_document = true; Document* doc = static_cast<Document*>(node); - if (doc->isHTMLDocument()) { + if (doc->isHTMLDocument()) type = V8ClassIndex::HTMLDOCUMENT; #if ENABLE(SVG) - } else if (doc->isSVGDocument()) { + else if (doc->isSVGDocument()) type = V8ClassIndex::SVGDOCUMENT; #endif - } else { + else type = V8ClassIndex::DOCUMENT; - } break; } case Node::DOCUMENT_TYPE_NODE: @@ -2408,9 +2407,8 @@ v8::Handle<v8::Value> V8Proxy::NodeToV8Object(Node* node) { if (is_document) { Document* doc = static_cast<Document*>(node); V8Proxy* proxy = V8Proxy::retrieve(doc->frame()); - if (proxy) { + if (proxy) proxy->UpdateDocumentHandle(result); - } if (type == V8ClassIndex::HTMLDOCUMENT) { // Create marker object and insert it in two internal fields. @@ -2447,16 +2445,20 @@ void V8Proxy::UpdateDocumentHandle(v8::Local<v8::Object> handle) { // A JS object of type EventTarget can only be two possible types: // 1) EventTargetNode; 2) XMLHttpRequest; -v8::Handle<v8::Value> V8Proxy::EventTargetToV8Object(EventTarget* target) { - if (!target) return v8::Null(); +v8::Handle<v8::Value> V8Proxy::EventTargetToV8Object(EventTarget* target) +{ + if (!target) + return v8::Null(); #if ENABLE(SVG) SVGElementInstance* instance = target->toSVGElementInstance(); - if (instance) return ToV8Object(V8ClassIndex::SVGELEMENTINSTANCE, instance); + if (instance) + return ToV8Object(V8ClassIndex::SVGELEMENTINSTANCE, instance); #endif Node* node = target->toNode(); - if (node) return NodeToV8Object(node); + if (node) + return NodeToV8Object(node); // XMLHttpRequest is created within its JS counterpart. XMLHttpRequest* xhr = target->toXMLHttpRequest(); @@ -2501,12 +2503,12 @@ v8::Handle<v8::Value> V8Proxy::StyleSheetToV8Object(StyleSheet* sheet) { if (!sheet) return v8::Null(); v8::Handle<v8::Object> peer = dom_object_map().get(sheet); - if (!peer.IsEmpty()) { + if (!peer.IsEmpty()) return peer; - } V8ClassIndex::V8WrapperType type = V8ClassIndex::STYLESHEET; - if (sheet->isCSSStyleSheet()) type = V8ClassIndex::CSSSTYLESHEET; + if (sheet->isCSSStyleSheet()) + type = V8ClassIndex::CSSSTYLESHEET; v8::Handle<v8::Object> result = InstantiateV8Object(type, V8ClassIndex::STYLESHEET, sheet); @@ -2519,7 +2521,7 @@ v8::Handle<v8::Value> V8Proxy::StyleSheetToV8Object(StyleSheet* sheet) { Node* owner_node = sheet->ownerNode(); if (owner_node) { v8::Handle<v8::Object> owner = - v8::Handle<v8::Object>::Cast(NodeToV8Object(owner_node)); + v8::Handle<v8::Object>::Cast(NodeToV8Object(owner_node)); result->SetInternalField(V8Custom::kStyleSheetOwnerNodeIndex, owner); } @@ -2531,9 +2533,8 @@ v8::Handle<v8::Value> V8Proxy::CSSValueToV8Object(CSSValue* value) { if (!value) return v8::Null(); v8::Handle<v8::Object> peer = dom_object_map().get(value); - if (!peer.IsEmpty()) { + if (!peer.IsEmpty()) return peer; - } V8ClassIndex::V8WrapperType type; @@ -2552,95 +2553,93 @@ v8::Handle<v8::Value> V8Proxy::CSSValueToV8Object(CSSValue* value) { v8::Handle<v8::Object> result = InstantiateV8Object(type, V8ClassIndex::CSSVALUE, value); - if (!result.IsEmpty()) { + if (!result.IsEmpty()) // Only update the DOM object map if the result is non-empty. dom_object_map().set(value, v8::Persistent<v8::Object>::New(result)); - } return result; } v8::Handle<v8::Value> V8Proxy::CSSRuleToV8Object(CSSRule* rule) { - if (!rule) return v8::Null(); - - v8::Handle<v8::Object> peer = dom_object_map().get(rule); - if (!peer.IsEmpty()) { - return peer; - } - - V8ClassIndex::V8WrapperType type; - - switch (rule->type()) { - case CSSRule::STYLE_RULE: - type = V8ClassIndex::CSSSTYLERULE; - break; - case CSSRule::CHARSET_RULE: - type = V8ClassIndex::CSSCHARSETRULE; - break; - case CSSRule::IMPORT_RULE: - type = V8ClassIndex::CSSIMPORTRULE; - break; - case CSSRule::MEDIA_RULE: - type = V8ClassIndex::CSSMEDIARULE; - break; - case CSSRule::FONT_FACE_RULE: - type = V8ClassIndex::CSSFONTFACERULE; - break; - case CSSRule::PAGE_RULE: - type = V8ClassIndex::CSSPAGERULE; - break; - default: // CSSRule::UNKNOWN_RULE - type = V8ClassIndex::CSSRULE; - } + if (!rule) return v8::Null(); + + v8::Handle<v8::Object> peer = dom_object_map().get(rule); + if (!peer.IsEmpty()) + return peer; + + V8ClassIndex::V8WrapperType type; + + switch (rule->type()) { + case CSSRule::STYLE_RULE: + type = V8ClassIndex::CSSSTYLERULE; + break; + case CSSRule::CHARSET_RULE: + type = V8ClassIndex::CSSCHARSETRULE; + break; + case CSSRule::IMPORT_RULE: + type = V8ClassIndex::CSSIMPORTRULE; + break; + case CSSRule::MEDIA_RULE: + type = V8ClassIndex::CSSMEDIARULE; + break; + case CSSRule::FONT_FACE_RULE: + type = V8ClassIndex::CSSFONTFACERULE; + break; + case CSSRule::PAGE_RULE: + type = V8ClassIndex::CSSPAGERULE; + break; + default: // CSSRule::UNKNOWN_RULE + type = V8ClassIndex::CSSRULE; + } - // Set the peer object for future access. - v8::Handle<v8::Object> result = - InstantiateV8Object(type, V8ClassIndex::CSSRULE, rule); - if (!result.IsEmpty()) { - // Only update the DOM object map if the result is non-empty. - dom_object_map().set(rule, v8::Persistent<v8::Object>::New(result)); - } - return result; + // Set the peer object for future access. + v8::Handle<v8::Object> result = + InstantiateV8Object(type, V8ClassIndex::CSSRULE, rule); + if (!result.IsEmpty()) + // Only update the DOM object map if the result is non-empty. + dom_object_map().set(rule, v8::Persistent<v8::Object>::New(result)); + return result; } v8::Handle<v8::Value> V8Proxy::WindowToV8Object(DOMWindow* window) { - if (!window) return v8::Null(); + if (!window) return v8::Null(); + // Initializes environment of a frame, and return the global object + // of the frame. + Frame* frame = window->frame(); + if (!frame) + return v8::Handle<v8::Object>(); - // Initializes environment of a frame, and return the global object - // of the frame. - Frame* frame = window->frame(); - if (!frame) return v8::Handle<v8::Object>(); + v8::Handle<v8::Context> context = GetContext(frame); + if (context.IsEmpty()) + return v8::Handle<v8::Object>(); - v8::Handle<v8::Context> context = GetContext(frame); - if (context.IsEmpty()) return v8::Handle<v8::Object>(); - - v8::Handle<v8::Object> global = context->Global(); - ASSERT(!global.IsEmpty()); - return global; + v8::Handle<v8::Object> global = context->Global(); + ASSERT(!global.IsEmpty()); + return global; } - void V8Proxy::BindJSObjectToWindow(Frame* frame, const char* name, int type, v8::Handle<v8::FunctionTemplate> desc, - void* imp) { - // Get environment. - v8::Handle<v8::Context> context = V8Proxy::GetContext(frame); - if (context.IsEmpty()) return; // JS not enabled. + void* imp) +{ + // Get environment. + v8::Handle<v8::Context> context = V8Proxy::GetContext(frame); + if (context.IsEmpty()) + return; // JS not enabled. - v8::Context::Scope scope(context); - v8::Handle<v8::Object> instance = desc->GetFunction(); - SetDOMWrapper(instance, type, imp); + v8::Context::Scope scope(context); + v8::Handle<v8::Object> instance = desc->GetFunction(); + SetDOMWrapper(instance, type, imp); - v8::Handle<v8::Object> global = context->Global(); - global->Set(v8::String::New(name), instance); + v8::Handle<v8::Object> global = context->Global(); + global->Set(v8::String::New(name), instance); } - -void V8Proxy::ProcessConsoleMessages() { - ConsoleMessageManager::ProcessDelayedMessages(); +void V8Proxy::ProcessConsoleMessages() +{ + ConsoleMessageManager::ProcessDelayedMessages(); } - } // namespace WebCore diff --git a/webkit/port/bindings/v8/v8_proxy.h b/webkit/port/bindings/v8/v8_proxy.h index 94f0450..784d763 100644 --- a/webkit/port/bindings/v8/v8_proxy.h +++ b/webkit/port/bindings/v8/v8_proxy.h @@ -13,6 +13,7 @@ #include "NodeFilter.h" #include "PlatformString.h" // for WebCore::String #include <wtf/HashMap.h> // for HashMap +#include <wtf/PassRefPtr.h> // so generated bindings don't have to #include <wtf/Assertions.h> #include <iterator> @@ -331,6 +332,11 @@ class V8Proxy { return static_cast<C*>(ExtractCPointer<Node>(wrapper)); } + template<typename T> + static v8::Handle<v8::Value> ToV8Object(V8ClassIndex::V8WrapperType type, PassRefPtr<T> imp) + { + return ToV8Object(type, imp.get()); + } static v8::Handle<v8::Value> ToV8Object(V8ClassIndex::V8WrapperType type, void* imp); // Fast-path for Node objects. @@ -378,7 +384,7 @@ class V8Proxy { DOMImplementation* impl); // Wrap JS node filter in C++ - static NodeFilter* ToNativeNodeFilter(v8::Handle<v8::Value> filter); + static PassRefPtr<NodeFilter> ToNativeNodeFilter(v8::Handle<v8::Value> filter); static v8::Persistent<v8::FunctionTemplate> GetTemplate( V8ClassIndex::V8WrapperType type); @@ -518,10 +524,14 @@ v8::Handle<v8::Value> V8Proxy::ConstructDOMObject(const v8::Arguments& args) { "DOM object constructor cannot be called as a function."); return v8::Undefined(); } - T* obj = new T(); - V8Proxy::SetDOMWrapper(args.Holder(), tag, obj); + + + // Note: it's OK to let this RefPtr go out of scope because we also call + // SetDOMWrapper(), which effectively holds a reference to obj. + RefPtr<T> obj = T::create(); + V8Proxy::SetDOMWrapper(args.Holder(), tag, obj.get()); V8Proxy::SetJSWrapperForDOMObject( - obj, v8::Persistent<v8::Object>::New(args.Holder())); + obj.get(), v8::Persistent<v8::Object>::New(args.Holder())); return args.Holder(); } |