summaryrefslogtreecommitdiffstats
path: root/webkit/port/bindings/v8
diff options
context:
space:
mode:
authorinitial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-27 00:20:51 +0000
committerinitial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-27 00:20:51 +0000
commitf5b16fed647e941aa66933178da85db2860d639b (patch)
treef00e9856c04aad3b558a140955e7674add33f051 /webkit/port/bindings/v8
parent920c091ac3ee15079194c82ae8a7a18215f3f23c (diff)
downloadchromium_src-f5b16fed647e941aa66933178da85db2860d639b.zip
chromium_src-f5b16fed647e941aa66933178da85db2860d639b.tar.gz
chromium_src-f5b16fed647e941aa66933178da85db2860d639b.tar.bz2
Add webkit to the repository.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@18 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/port/bindings/v8')
-rw-r--r--webkit/port/bindings/v8/JSXPathNSResolver.cpp90
-rw-r--r--webkit/port/bindings/v8/JSXPathNSResolver.h58
-rw-r--r--webkit/port/bindings/v8/V8SVGPODTypeWrapper.h299
-rw-r--r--webkit/port/bindings/v8/dom_wrapper_map.h96
-rw-r--r--webkit/port/bindings/v8/np_v8object.cpp482
-rw-r--r--webkit/port/bindings/v8/np_v8object.h63
-rw-r--r--webkit/port/bindings/v8/npruntime.cpp346
-rw-r--r--webkit/port/bindings/v8/npruntime_impl.h61
-rw-r--r--webkit/port/bindings/v8/npruntime_internal.h39
-rw-r--r--webkit/port/bindings/v8/npruntime_priv.h92
-rw-r--r--webkit/port/bindings/v8/v8_binding.h195
-rw-r--r--webkit/port/bindings/v8/v8_custom.cpp3414
-rw-r--r--webkit/port/bindings/v8/v8_custom.h459
-rw-r--r--webkit/port/bindings/v8/v8_events.cpp472
-rw-r--r--webkit/port/bindings/v8/v8_events.h171
-rw-r--r--webkit/port/bindings/v8/v8_helpers.cpp59
-rw-r--r--webkit/port/bindings/v8/v8_helpers.h49
-rw-r--r--webkit/port/bindings/v8/v8_index.cpp361
-rw-r--r--webkit/port/bindings/v8/v8_index.h422
-rw-r--r--webkit/port/bindings/v8/v8_nodefilter.cpp84
-rw-r--r--webkit/port/bindings/v8/v8_nodefilter.h54
-rw-r--r--webkit/port/bindings/v8/v8_np_utils.cpp126
-rw-r--r--webkit/port/bindings/v8/v8_np_utils.h54
-rw-r--r--webkit/port/bindings/v8/v8_npobject.cpp364
-rw-r--r--webkit/port/bindings/v8/v8_npobject.h79
-rw-r--r--webkit/port/bindings/v8/v8_proxy.cpp2557
-rw-r--r--webkit/port/bindings/v8/v8_proxy.h571
-rw-r--r--webkit/port/bindings/v8/v8_utility.h82
-rw-r--r--webkit/port/bindings/v8/v8_vectornodelist.cpp57
-rw-r--r--webkit/port/bindings/v8/v8_vectornodelist.h58
30 files changed, 11314 insertions, 0 deletions
diff --git a/webkit/port/bindings/v8/JSXPathNSResolver.cpp b/webkit/port/bindings/v8/JSXPathNSResolver.cpp
new file mode 100644
index 0000000..ed6ed3c
--- /dev/null
+++ b/webkit/port/bindings/v8/JSXPathNSResolver.cpp
@@ -0,0 +1,90 @@
+// 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 "JSXPathNSResolver.h"
+
+#if ENABLE(XPATH)
+
+#include "v8_proxy.h"
+#include "v8_binding.h"
+#include "PlatformString.h"
+
+namespace WebCore {
+
+JSXPathNSResolver::JSXPathNSResolver(v8::Handle<v8::Object> resolver)
+: m_resolver(resolver) {
+}
+
+JSXPathNSResolver::~JSXPathNSResolver() {
+}
+
+String JSXPathNSResolver::lookupNamespaceURI(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)) {
+ v8::Handle<v8::Value> lookupNamespaceURI = m_resolver->Get(lookupNamespaceURIName);
+ if (lookupNamespaceURI->IsFunction()) {
+ lookupNamespaceURIFunc = v8::Handle<v8::Function>::Cast(lookupNamespaceURI);
+ }
+ }
+
+ if (lookupNamespaceURIFunc.IsEmpty() && !m_resolver->IsFunction()) {
+ Frame* frame = V8Proxy::retrieveActiveFrame();
+ log_info(frame, "XPathNSResolver does not have a lookupNamespaceURI method.", String());
+ return String();
+ }
+
+ // Catch exceptions from calling the namespace resolver.
+ v8::TryCatch try_catch;
+ try_catch.SetVerbose(true); // Print exceptions to console.
+
+ 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 most likely cause NAMESPACE_ERR.
+ if (try_catch.HasCaught()) {
+ return String();
+ }
+
+ return ToWebCoreString(retval);
+}
+
+}
+
+#endif // ENABLE(XPATH)
diff --git a/webkit/port/bindings/v8/JSXPathNSResolver.h b/webkit/port/bindings/v8/JSXPathNSResolver.h
new file mode 100644
index 0000000..b584ace
--- /dev/null
+++ b/webkit/port/bindings/v8/JSXPathNSResolver.h
@@ -0,0 +1,58 @@
+// Copyright 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.
+
+#ifndef JSXPATHNSRESOLVER_H__
+#define JSXPATHNSRESOLVER_H__
+
+#if ENABLE(XPATH)
+
+#include <v8.h>
+#include <wtf/RefCounted.h>
+#include "XPathNSResolver.h"
+
+namespace WebCore {
+
+ class String;
+
+ class JSXPathNSResolver : public XPathNSResolver {
+ public:
+
+ JSXPathNSResolver(v8::Handle<v8::Object> resolver);
+ virtual ~JSXPathNSResolver();
+
+ virtual String lookupNamespaceURI(const String& prefix);
+
+ private:
+ v8::Handle<v8::Object> m_resolver; // Handle to resolver object.
+ };
+}
+
+#endif // ENABLE(XPATH)
+
+#endif // JSXPATHNSRESOLVER_H__
diff --git a/webkit/port/bindings/v8/V8SVGPODTypeWrapper.h b/webkit/port/bindings/v8/V8SVGPODTypeWrapper.h
new file mode 100644
index 0000000..190b982
--- /dev/null
+++ b/webkit/port/bindings/v8/V8SVGPODTypeWrapper.h
@@ -0,0 +1,299 @@
+// Copyright 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.
+
+#ifndef V8SVGPODTypeWrapper_h
+#define V8SVGPODTypeWrapper_h
+
+#if ENABLE(SVG)
+
+#include "config.h"
+#include "SVGElement.h"
+#include "SVGList.h"
+#include <wtf/Assertions.h>
+#include <wtf/RefCounted.h>
+#include <wtf/HashMap.h>
+
+namespace WebCore {
+
+template<typename PODType>
+class V8SVGPODTypeWrapper : public RefCounted<V8SVGPODTypeWrapper<PODType> > {
+public:
+ V8SVGPODTypeWrapper() : RefCounted<V8SVGPODTypeWrapper<PODType> >(0) {
+ }
+ virtual ~V8SVGPODTypeWrapper() {
+ }
+
+ // Getter wrapper
+ virtual operator PODType() = 0;
+
+ // Setter wrapper
+ virtual void commitChange(PODType, SVGElement*) = 0;
+};
+
+template<typename PODType>
+class V8SVGPODTypeWrapperCreatorForList : public V8SVGPODTypeWrapper<PODType>
+{
+public:
+ typedef PODType (SVGPODListItem<PODType>::*GetterMethod)() const;
+ typedef void (SVGPODListItem<PODType>::*SetterMethod)(PODType);
+
+ V8SVGPODTypeWrapperCreatorForList(SVGPODListItem<PODType>* creator, const QualifiedName& attributeName)
+ : m_creator(creator)
+ , m_getter(&SVGPODListItem<PODType>::value)
+ , m_setter(&SVGPODListItem<PODType>::setValue)
+ , m_associatedAttributeName(attributeName)
+ {
+ ASSERT(m_creator);
+ ASSERT(m_getter);
+ ASSERT(m_setter);
+ }
+
+ virtual ~V8SVGPODTypeWrapperCreatorForList() { }
+
+ // Getter wrapper
+ virtual operator PODType() { return (m_creator.get()->*m_getter)(); }
+
+ // Setter wrapper
+ virtual void commitChange(PODType type, SVGElement* context)
+ {
+ if (!m_setter)
+ return;
+
+ (m_creator.get()->*m_setter)(type);
+
+ if (context)
+ context->svgAttributeChanged(m_associatedAttributeName);
+ }
+
+private:
+ // Update callbacks
+ RefPtr<SVGPODListItem<PODType> > m_creator;
+ GetterMethod m_getter;
+ SetterMethod m_setter;
+ const QualifiedName& m_associatedAttributeName;
+};
+
+template<typename PODType>
+class V8SVGPODTypeWrapperCreatorReadOnly : public V8SVGPODTypeWrapper<PODType>
+{
+public:
+ V8SVGPODTypeWrapperCreatorReadOnly(PODType type)
+ : m_podType(type)
+ { }
+
+ virtual ~V8SVGPODTypeWrapperCreatorReadOnly() { }
+
+ // Getter wrapper
+ virtual operator PODType() { return m_podType; }
+
+ // Setter wrapper
+ virtual void commitChange(PODType type, SVGElement*)
+ {
+ m_podType = type;
+ }
+
+private:
+ PODType m_podType;
+};
+
+template<typename PODType, typename PODTypeCreator>
+class V8SVGPODTypeWrapperCreatorReadWrite : public V8SVGPODTypeWrapper<PODType>
+{
+public:
+ typedef PODType (PODTypeCreator::*GetterMethod)() const;
+ typedef void (PODTypeCreator::*SetterMethod)(PODType);
+ typedef void (*CacheRemovalCallback)(V8SVGPODTypeWrapper<PODType>*);
+
+ V8SVGPODTypeWrapperCreatorReadWrite(PODTypeCreator* creator, GetterMethod getter, SetterMethod setter, CacheRemovalCallback cacheRemovalCallback)
+ : m_creator(creator)
+ , m_getter(getter)
+ , m_setter(setter)
+ , m_cacheRemovalCallback(cacheRemovalCallback)
+ {
+ ASSERT(creator);
+ ASSERT(getter);
+ ASSERT(setter);
+ ASSERT(cacheRemovalCallback);
+ }
+
+ virtual ~V8SVGPODTypeWrapperCreatorReadWrite() {
+ ASSERT(m_cacheRemovalCallback);
+
+ (*m_cacheRemovalCallback)(this);
+ }
+
+ // Getter wrapper
+ virtual operator PODType() { return (m_creator.get()->*m_getter)(); }
+
+ // Setter wrapper
+ virtual void commitChange(PODType type, SVGElement* context)
+ {
+ if (!m_setter)
+ return;
+
+ (m_creator.get()->*m_setter)(type);
+
+ if (context)
+ context->svgAttributeChanged(m_creator->associatedAttributeName());
+ }
+
+private:
+ // Update callbacks
+ RefPtr<PODTypeCreator> m_creator;
+ GetterMethod m_getter;
+ SetterMethod m_setter;
+ CacheRemovalCallback m_cacheRemovalCallback;
+};
+
+// Caching facilities
+template<typename PODType, typename PODTypeCreator>
+struct PODTypeReadWriteHashInfo {
+ typedef PODType (PODTypeCreator::*GetterMethod)() const;
+ typedef void (PODTypeCreator::*SetterMethod)(PODType);
+
+ // Empty value
+ PODTypeReadWriteHashInfo()
+ : creator(0)
+ , getter(0)
+ , setter(0)
+ { }
+
+ // Deleted value
+ explicit PODTypeReadWriteHashInfo(bool)
+ : creator(reinterpret_cast<PODTypeCreator*>(-1))
+ , getter(0)
+ , setter(0)
+ { }
+
+ PODTypeReadWriteHashInfo(PODTypeCreator* _creator, GetterMethod _getter, SetterMethod _setter)
+ : creator(_creator)
+ , getter(_getter)
+ , setter(_setter)
+ {
+ ASSERT(creator);
+ ASSERT(getter);
+ }
+
+ bool operator==(const PODTypeReadWriteHashInfo& other) const
+ {
+ return creator == other.creator && getter == other.getter && setter == other.setter;
+ }
+
+ PODTypeCreator* creator;
+ GetterMethod getter;
+ SetterMethod setter;
+};
+
+template<typename PODType, typename PODTypeCreator>
+struct PODTypeReadWriteHashInfoHash {
+ static unsigned hash(const PODTypeReadWriteHashInfo<PODType, PODTypeCreator>& info)
+ {
+ return StringImpl::computeHash((::UChar*) &info, sizeof(PODTypeReadWriteHashInfo<PODType, PODTypeCreator>) / sizeof(::UChar));
+ }
+
+ static bool equal(const PODTypeReadWriteHashInfo<PODType, PODTypeCreator>& a, const PODTypeReadWriteHashInfo<PODType, PODTypeCreator>& b)
+ {
+ return a == b;
+ }
+
+ static const bool safeToCompareToEmptyOrDeleted = true;
+};
+
+template<typename PODType, typename PODTypeCreator>
+struct PODTypeReadWriteHashInfoTraits : WTF::GenericHashTraits<PODTypeReadWriteHashInfo<PODType, PODTypeCreator> > {
+ static const bool emptyValueIsZero = true;
+ static const bool needsDestruction = false;
+
+ static const PODTypeReadWriteHashInfo<PODType, PODTypeCreator>& deletedValue()
+ {
+ static PODTypeReadWriteHashInfo<PODType, PODTypeCreator> key(true);
+ return key;
+ }
+
+ static const PODTypeReadWriteHashInfo<PODType, PODTypeCreator>& emptyValue()
+ {
+ static PODTypeReadWriteHashInfo<PODType, PODTypeCreator> key;
+ return key;
+ }
+};
+
+template<typename PODType, typename PODTypeCreator>
+class V8SVGPODTypeWrapperCache
+{
+public:
+ typedef PODType (PODTypeCreator::*GetterMethod)() const;
+ typedef void (PODTypeCreator::*SetterMethod)(PODType);
+
+ typedef HashMap<PODTypeReadWriteHashInfo<PODType, PODTypeCreator>, V8SVGPODTypeWrapperCreatorReadWrite<PODType, PODTypeCreator>*, PODTypeReadWriteHashInfoHash<PODType, PODTypeCreator>, PODTypeReadWriteHashInfoTraits<PODType, PODTypeCreator> > ReadWriteHashMap;
+ typedef typename ReadWriteHashMap::const_iterator ReadWriteHashMapIterator;
+
+ static ReadWriteHashMap& readWriteHashMap()
+ {
+ static ReadWriteHashMap _readWriteHashMap;
+ return _readWriteHashMap;
+ }
+
+ // Used for readwrite attributes only
+ static V8SVGPODTypeWrapper<PODType>* lookupOrCreateWrapper(PODTypeCreator* creator, GetterMethod getter, SetterMethod setter)
+ {
+ ReadWriteHashMap& map(readWriteHashMap());
+ PODTypeReadWriteHashInfo<PODType, PODTypeCreator> info(creator, getter, setter);
+
+ if (map.contains(info))
+ return map.get(info);
+
+ V8SVGPODTypeWrapperCreatorReadWrite<PODType, PODTypeCreator>* wrapper = new V8SVGPODTypeWrapperCreatorReadWrite<PODType, PODTypeCreator>(
+ creator, getter, setter, forgetWrapper);
+ map.set(info, wrapper);
+ return wrapper;
+ }
+
+ static void forgetWrapper(V8SVGPODTypeWrapper<PODType>* wrapper)
+ {
+ ReadWriteHashMap& map(readWriteHashMap());
+
+ ReadWriteHashMapIterator it = map.begin();
+ ReadWriteHashMapIterator end = map.end();
+
+ for (; it != end; ++it) {
+ if (it->second != wrapper)
+ continue;
+
+ // It's guaruanteed that there's just one object we need to take care of.
+ map.remove(it->first);
+ break;
+ }
+ }
+};
+
+
+} // namespace WebCore
+
+#endif // ENABLE(SVG)
+#endif // V8SVGPODTypeWrapper_h
diff --git a/webkit/port/bindings/v8/dom_wrapper_map.h b/webkit/port/bindings/v8/dom_wrapper_map.h
new file mode 100644
index 0000000..d5f88b3
--- /dev/null
+++ b/webkit/port/bindings/v8/dom_wrapper_map.h
@@ -0,0 +1,96 @@
+// Copyright 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.
+
+#ifndef BINDINGS_V8_DOM_WRAPPER_MAP
+#define BINDINGS_V8_DOM_WRAPPER_MAP
+
+#include <wtf/HashMap.h>
+
+// A table of wrappers with weak pointers.
+// This table allows us to avoid track wrapped objects for debugging
+// and for ensuring that we don't double wrap the same object.
+template<class KeyType, class ValueType>
+class WeakReferenceMap {
+ public:
+ WeakReferenceMap(v8::WeakReferenceCallback callback) :
+ weak_reference_callback_(callback) { }
+#ifndef NDEBUG
+ virtual ~WeakReferenceMap() {
+ if (map_.size() > 0) {
+ fprintf(stderr, "Leak %d JS wrappers.\n", map_.size());
+ // Print out details.
+ }
+ }
+#endif
+
+ // Get the JS wrapper object of an object.
+ virtual v8::Persistent<ValueType> get(KeyType* obj) {
+ ValueType* wrapper = map_.get(obj);
+ return wrapper ? v8::Persistent<ValueType>(wrapper)
+ : v8::Persistent<ValueType>();
+ }
+
+ virtual void set(KeyType* obj, v8::Persistent<ValueType> wrapper) {
+ ASSERT(!map_.contains(obj));
+ wrapper.MakeWeak(obj, weak_reference_callback_);
+ map_.set(obj, *wrapper);
+ }
+
+ virtual void forget(KeyType* obj) {
+ ASSERT(obj);
+ ValueType* wrapper = map_.take(obj);
+ if (wrapper) {
+ v8::Persistent<ValueType> handle(wrapper);
+ handle.Dispose();
+ handle.Clear();
+ }
+ }
+
+ bool contains(KeyType* obj) {
+ return map_.contains(obj);
+ }
+
+ HashMap<KeyType*, ValueType*>& impl() {
+ return map_;
+ }
+
+ protected:
+ HashMap<KeyType*, ValueType*> map_;
+ v8::WeakReferenceCallback weak_reference_callback_;
+};
+
+
+template <class KeyType>
+class DOMWrapperMap : public WeakReferenceMap<KeyType, v8::Object> {
+ public:
+ DOMWrapperMap(v8::WeakReferenceCallback callback) :
+ WeakReferenceMap(callback) { }
+};
+
+#endif // BINDINGS_V8_DOM_WRAPPER_MAP
diff --git a/webkit/port/bindings/v8/np_v8object.cpp b/webkit/port/bindings/v8/np_v8object.cpp
new file mode 100644
index 0000000..df04aca
--- /dev/null
+++ b/webkit/port/bindings/v8/np_v8object.cpp
@@ -0,0 +1,482 @@
+/*
+ * Copyright (C) 2004, 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2007 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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"
+
+#define max max
+#define min min
+#include <string>
+#include <sstream>
+#include <v8.h>
+#include "np_v8object.h"
+#include "Frame.h"
+#include "bindings/npruntime.h"
+#include "npruntime_priv.h"
+#include "PlatformString.h"
+#include "v8_helpers.h"
+#include "v8_np_utils.h"
+#include "v8_proxy.h"
+#include "V8Bridge.h"
+#include "DOMWindow.h"
+
+using WebCore::V8ClassIndex;
+using WebCore::V8Proxy;
+
+namespace {
+
+// TODO(mbelshe): comments on why use malloc and free.
+static NPObject* AllocV8NPObject(NPP, NPClass*) {
+ return static_cast<NPObject*>(malloc(sizeof(V8NPObject)));
+}
+
+static void FreeV8NPObject(NPObject* npobj) {
+ V8NPObject *object = reinterpret_cast<V8NPObject*>(npobj);
+#ifndef NDEBUG
+ V8Proxy::UnregisterGlobalHandle(object, object->v8_object);
+#endif
+ object->v8_object.Dispose();
+ free(object);
+}
+
+static v8::Handle<v8::Value>* listFromVariantArgs(const NPVariant* args,
+ uint32_t argCount,
+ NPObject *owner) {
+ v8::Handle<v8::Value>* argv = new v8::Handle<v8::Value>[argCount];
+ for (uint32_t index = 0; index < argCount; index++) {
+ const NPVariant *arg = &args[index];
+ argv[index] = ConvertNPVariantToV8Object(arg, owner);
+ }
+ return argv;
+}
+
+// Create an identifier (null terminated utf8 char*) from the NPIdentifier.
+static void NPIdentifierToV8Identifier(NPIdentifier name, std::string &string) {
+ PrivateIdentifier* identifier = static_cast<PrivateIdentifier*>(name);
+ if (identifier->isString) {
+ string = static_cast<const char *>(identifier->value.string);
+ } else {
+ std::ostringstream o;
+ o << identifier->value.number;
+ string = o.str();
+ }
+}
+
+static NPClass V8NPObjectClass = { NP_CLASS_STRUCT_VERSION,
+ AllocV8NPObject,
+ FreeV8NPObject,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+} // namespace
+
+//
+// NPAPI's npruntime functions
+//
+NPClass* NPScriptObjectClass = &V8NPObjectClass;
+
+NPObject* NPN_CreateScriptObject(NPP npp, v8::Handle<v8::Object> object,
+ WebCore::DOMWindow* root) {
+ // Check to see if this object is already wrapped.
+ if (object->InternalFieldCount() == 3 &&
+ object->GetInternalField(1)->IsNumber() &&
+ object->GetInternalField(1)->Uint32Value() == V8ClassIndex::NPOBJECT) {
+ NPObject* rv = V8Proxy::ToNativeObject<NPObject>(V8ClassIndex::NPOBJECT,
+ object);
+ NPN_RetainObject(rv);
+ return rv;
+ }
+
+ V8NPObject* obj =
+ reinterpret_cast<V8NPObject*>(NPN_CreateObject(npp, &V8NPObjectClass));
+ obj->v8_object = v8::Persistent<v8::Object>::New(object);
+#ifndef NDEBUG
+ V8Proxy::RegisterGlobalHandle(WebCore::NPOBJECT, obj, obj->v8_object);
+#endif
+ obj->root_object = root;
+ return reinterpret_cast<NPObject*>(obj);
+}
+
+bool NPN_Invoke(NPP npp, NPObject *npobj, NPIdentifier methodName,
+ const NPVariant *args, uint32_t argCount, NPVariant *result) {
+ if (npobj == NULL)
+ return false;
+
+ if (npobj->_class == NPScriptObjectClass) {
+ V8NPObject *object = reinterpret_cast<V8NPObject*>(npobj);
+
+ PrivateIdentifier *identifier = static_cast<PrivateIdentifier*>(methodName);
+ if (!identifier->isString)
+ return false;
+
+ v8::HandleScope handle_scope;
+ // TODO: should use the plugin's owner frame as the security context
+ v8::Handle<v8::Context> context = GetV8Context(npp, npobj);
+ if (context.IsEmpty()) return false;
+
+ v8::Context::Scope scope(context);
+
+ // Special case the "eval" method.
+ if (methodName == NPN_GetStringIdentifier("eval")) {
+ if (argCount != 1)
+ return false;
+ if (args[0].type != NPVariantType_String)
+ return false;
+ return NPN_Evaluate(npp, npobj,
+ const_cast<NPString*>(&args[0].value.stringValue), result);
+ }
+
+ v8::Handle<v8::Value> func_obj =
+ object->v8_object->Get(v8::String::New(identifier->value.string));
+ if (func_obj.IsEmpty() || func_obj->IsNull()) {
+ NULL_TO_NPVARIANT(*result);
+ return false;
+ }
+ if (func_obj->IsUndefined()) {
+ VOID_TO_NPVARIANT(*result);
+ return false;
+ }
+
+ WebCore::V8Proxy* proxy = GetV8Proxy(npobj);
+ ASSERT(proxy); // must not be null
+
+ // TODO: fix variable naming
+ // Call the function object
+ v8::Handle<v8::Function> func = v8::Handle<v8::Function>::Cast(func_obj);
+ // Create list of args to pass to v8
+ v8::Handle<v8::Value>* argv = listFromVariantArgs(args, argCount, npobj);
+ v8::Local<v8::Value> resultObj =
+ proxy->CallFunction(func, object->v8_object, argCount, argv);
+ delete[] argv;
+
+ // If we had an error, return false. The spec is a little unclear here, but
+ // says "Returns true if the method was successfully invoked". If we get an
+ // error return value, was that successfully invoked?
+ if (resultObj.IsEmpty()) return false;
+
+ // Convert the result back to an NPVariant
+ ConvertV8ObjectToNPVariant(resultObj, npobj, result);
+ return true;
+ }
+
+ if (npobj->_class->invoke)
+ return npobj->_class->invoke(npobj, methodName, args, argCount, result);
+
+ VOID_TO_NPVARIANT(*result);
+ return true;
+}
+
+
+// TODO: Fix it same as NPN_Invoke (HandleScope and such)
+bool NPN_InvokeDefault(NPP npp, NPObject *npobj, const NPVariant *args,
+ uint32_t argCount, NPVariant *result) {
+ if (npobj == NULL)
+ return false;
+
+ if (npobj->_class == NPScriptObjectClass) {
+ V8NPObject *object = reinterpret_cast<V8NPObject*>(npobj);
+
+ VOID_TO_NPVARIANT(*result);
+
+ v8::HandleScope handle_scope;
+ v8::Handle<v8::Context> context = GetV8Context(npp, npobj);
+ if (context.IsEmpty()) return false;
+
+ v8::Context::Scope scope(context);
+
+ // Lookup the function object
+ v8::Handle<v8::Object> funcObj(object->v8_object);
+ if (!funcObj->IsFunction())
+ return false;
+
+ // Call the function object
+ v8::Local<v8::Value> resultObj;
+ v8::Handle<v8::Function> func(v8::Function::Cast(*funcObj));
+ if (!func->IsNull()) {
+ WebCore::V8Proxy* proxy = GetV8Proxy(npobj);
+ ASSERT(proxy);
+
+ // Create list of args to pass to v8
+ v8::Handle<v8::Value>* argv = listFromVariantArgs(args, argCount, npobj);
+ resultObj = proxy->CallFunction(func, funcObj, argCount, argv);
+ delete[] argv;
+ }
+
+ // If we had an error, return false. The spec is a little unclear here, but
+ // says "Returns true if the method was successfully invoked". If we get an
+ // error return value, was that successfully invoked?
+ if (resultObj.IsEmpty()) return false;
+
+ // Convert the result back to an NPVariant
+ ConvertV8ObjectToNPVariant(resultObj, npobj, result);
+ return true;
+ }
+
+ if (npobj->_class->invokeDefault)
+ return npobj->_class->invokeDefault(npobj, args, argCount, result);
+
+ VOID_TO_NPVARIANT(*result);
+ return true;
+}
+
+bool NPN_Evaluate(NPP npp, NPObject *npobj, NPString *npscript,
+ NPVariant *result) {
+ VOID_TO_NPVARIANT(*result);
+ if (npobj == NULL)
+ return false;
+
+ if (npobj->_class == NPScriptObjectClass) {
+ v8::HandleScope handle_scope;
+ v8::Handle<v8::Context> context = GetV8Context(npp, npobj);
+ if (context.IsEmpty())
+ return false;
+
+ WebCore::V8Proxy* proxy = GetV8Proxy(npobj);
+ ASSERT(proxy);
+
+ v8::Context::Scope scope(context);
+
+ WebCore::String filename(L"npscript");
+ // Convert UTF-8 stream to WebCore::String.
+ WebCore::String script = WebCore::String::fromUTF8(
+ npscript->UTF8Characters, npscript->UTF8Length);
+ v8::Local<v8::Value> v8result =
+ proxy->Evaluate(filename, 0, script, NULL);
+
+ // If we had an error, return false.
+ if (v8result.IsEmpty()) return false;
+
+ ConvertV8ObjectToNPVariant(v8result, npobj, result);
+ return true;
+ }
+
+ return false;
+}
+
+bool NPN_GetProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName,
+ NPVariant *result) {
+ if (npobj == NULL)
+ return false;
+
+ if (npobj->_class == NPScriptObjectClass) {
+ V8NPObject *object = reinterpret_cast<V8NPObject*>(npobj);
+
+ v8::HandleScope handle_scope;
+ v8::Handle<v8::Context> context = GetV8Context(npp, npobj);
+ if (context.IsEmpty()) return false;
+
+ v8::Context::Scope scope(context);
+
+ v8::Handle<v8::Object> obj(object->v8_object);
+
+ std::string identifier;
+ NPIdentifierToV8Identifier(propertyName, identifier);
+ v8::Local<v8::Value> v8result =
+ obj->Get(v8::String::New(identifier.c_str()));
+
+ ConvertV8ObjectToNPVariant(v8result, npobj, result);
+ return true;
+ }
+
+ if (npobj->_class->hasProperty && npobj->_class->getProperty)
+ if (npobj->_class->hasProperty(npobj, propertyName))
+ return npobj->_class->getProperty(npobj, propertyName, result);
+
+ VOID_TO_NPVARIANT(*result);
+ return false;
+}
+
+bool NPN_SetProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName,
+ const NPVariant *value) {
+ if (npobj == NULL)
+ return false;
+
+ if (npobj->_class == NPScriptObjectClass) {
+ V8NPObject *object = reinterpret_cast<V8NPObject*>(npobj);
+
+ v8::HandleScope handle_scope;
+ v8::Handle<v8::Context> context = GetV8Context(npp, npobj);
+ if (context.IsEmpty()) return false;
+
+ v8::Context::Scope scope(context);
+
+ v8::Handle<v8::Object> obj(object->v8_object);
+ std::string identifier;
+ NPIdentifierToV8Identifier(propertyName, identifier);
+ obj->Set(v8::String::New(identifier.c_str()),
+ ConvertNPVariantToV8Object(value,
+ object->root_object->frame()->windowScriptNPObject()));
+ return true;
+ }
+
+ if (npobj->_class->setProperty)
+ return npobj->_class->setProperty(npobj, propertyName, value);
+
+ return false;
+}
+
+bool NPN_RemoveProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName) {
+ if (npobj == NULL)
+ return false;
+
+ if (npobj->_class == NPScriptObjectClass) {
+ V8NPObject *object = reinterpret_cast<V8NPObject*>(npobj);
+
+ v8::HandleScope handle_scope;
+ v8::Handle<v8::Context> context = GetV8Context(npp, npobj);
+ if (context.IsEmpty()) return false;
+ v8::Context::Scope scope(context);
+
+ v8::Handle<v8::Object> obj(object->v8_object);
+ std::string identifier;
+ NPIdentifierToV8Identifier(propertyName, identifier);
+ // TODO(mbelshe) - verify that setting to undefined is right.
+ obj->Set(v8::String::New(identifier.c_str()), v8::Undefined());
+ return true;
+ }
+
+ return false;
+}
+
+bool NPN_HasProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName) {
+ if (npobj == NULL)
+ return false;
+
+ if (npobj->_class == NPScriptObjectClass) {
+ V8NPObject *object = reinterpret_cast<V8NPObject*>(npobj);
+
+ v8::HandleScope handle_scope;
+ v8::Handle<v8::Context> context = GetV8Context(npp, npobj);
+ if (context.IsEmpty()) return false;
+ v8::Context::Scope scope(context);
+
+ v8::Handle<v8::Object> obj(object->v8_object);
+ std::string identifier;
+ NPIdentifierToV8Identifier(propertyName, identifier);
+ return obj->Has(v8::String::New(identifier.c_str()));
+ }
+
+ if (npobj->_class->hasProperty)
+ return npobj->_class->hasProperty(npobj, propertyName);
+
+ return false;
+}
+
+bool NPN_HasMethod(NPP npp, NPObject *npobj, NPIdentifier methodName) {
+ if (npobj == NULL) return false;
+
+ if (npobj->_class == NPScriptObjectClass) {
+ V8NPObject *object = reinterpret_cast<V8NPObject*>(npobj);
+
+ v8::HandleScope handle_scope;
+ v8::Handle<v8::Context> context = GetV8Context(npp, npobj);
+ if (context.IsEmpty()) return false;
+ v8::Context::Scope scope(context);
+
+ v8::Handle<v8::Object> obj(object->v8_object);
+ std::string identifier;
+ NPIdentifierToV8Identifier(methodName, identifier);
+ v8::Handle<v8::Value> prop = obj->Get(v8::String::New(identifier.c_str()));
+ return prop->IsFunction();
+ }
+
+ if (npobj->_class->hasMethod)
+ return npobj->_class->hasMethod(npobj, methodName);
+
+ return false;
+}
+
+void NPN_SetException(NPObject *npobj, const NPUTF8 *message) {
+ if (npobj->_class == NPScriptObjectClass) {
+ V8NPObject *object = reinterpret_cast<V8NPObject*>(npobj);
+
+ v8::HandleScope handle_scope;
+ v8::Handle<v8::Context> context = GetV8Context(NULL, npobj);
+ if (context.IsEmpty()) return;
+
+ v8::Context::Scope scope(context);
+
+ V8Proxy::ThrowError(V8Proxy::GENERAL_ERROR, message);
+ }
+}
+
+bool NPN_Enumerate(NPP npp, NPObject *npobj, NPIdentifier **identifier,
+ uint32_t *count) {
+ if (npobj == NULL) return false;
+
+ if (npobj->_class == NPScriptObjectClass) {
+ V8NPObject *object = reinterpret_cast<V8NPObject*>(npobj);
+
+ v8::HandleScope handle_scope;
+ v8::Handle<v8::Context> context = GetV8Context(npp, npobj);
+ if (context.IsEmpty()) return false;
+ v8::Context::Scope scope(context);
+
+ v8::Handle<v8::Object> obj(object->v8_object);
+
+ // TODO(fqian): http://b/issue?id=1210340: Use a v8::Object::Keys() method
+ // when it exists, instead of evaluating javascript.
+
+ // TODO(mpcomplete): figure out how to cache this helper function.
+ // Run a helper function that collects the properties on the object into
+ // an array.
+ const char kEnumeratorCode[] =
+ "(function (obj) {"
+ " var props = [];"
+ " for (var prop in obj) {"
+ " props[props.length] = prop;"
+ " }"
+ " return props;"
+ "});";
+ v8::Handle<v8::String> source = v8::String::New(kEnumeratorCode);
+ v8::Handle<v8::Script> script = v8::Script::Compile(source, NULL);
+ v8::Handle<v8::Value> enumerator_obj = script->Run();
+ v8::Handle<v8::Function> enumerator =
+ v8::Handle<v8::Function>::Cast(enumerator_obj);
+ v8::Handle<v8::Value> argv[] = { obj };
+ v8::Local<v8::Value> props_obj =
+ enumerator->Call(v8::Handle<v8::Object>::Cast(enumerator_obj),
+ arraysize(argv), argv);
+ if (props_obj.IsEmpty())
+ return false;
+
+ // Convert the results into an array of NPIdentifiers.
+ v8::Handle<v8::Array> props = v8::Handle<v8::Array>::Cast(props_obj);
+ *count = props->Length();
+ *identifier =
+ static_cast<NPIdentifier*>(malloc(sizeof(NPIdentifier*) * *count));
+ for (uint32_t i = 0; i < *count; ++i) {
+ v8::Local<v8::Value> name = props->Get(v8::Integer::New(i));
+ (*identifier)[i] = GetStringIdentifier(v8::Local<v8::String>::Cast(name));
+ }
+ return true;
+ }
+
+ if (NP_CLASS_STRUCT_VERSION_HAS_ENUM(npobj->_class) &&
+ npobj->_class->enumerate) {
+ return npobj->_class->enumerate(npobj, identifier, count);
+ }
+
+ return false;
+}
diff --git a/webkit/port/bindings/v8/np_v8object.h b/webkit/port/bindings/v8/np_v8object.h
new file mode 100644
index 0000000..cc25057
--- /dev/null
+++ b/webkit/port/bindings/v8/np_v8object.h
@@ -0,0 +1,63 @@
+// Copyright 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.
+
+#ifndef NP_V8OBJECT_H__
+#define NP_V8OBJECT_H__
+
+#include "bindings/npruntime.h"
+#include <v8.h>
+
+namespace WebCore {
+ class DOMWindow;
+}
+
+extern NPClass* NPScriptObjectClass;
+
+// A V8NPObject is a NPObject which carries additional V8-specific
+// information. It is allocated and deallocated by AllocV8NPObject()
+// and FreeV8NPObject() methods.
+struct V8NPObject {
+ NPObject object;
+ v8::Persistent<v8::Object> v8_object;
+ WebCore::DOMWindow* root_object;
+};
+
+struct PrivateIdentifier {
+ union {
+ const NPUTF8* string;
+ int32_t number;
+ } value;
+ bool isString;
+};
+
+NPObject* NPN_CreateScriptObject(NPP npp, v8::Handle<v8::Object>,
+ WebCore::DOMWindow*);
+NPObject* NPN_CreateNoScriptObject(void);
+
+#endif // NP_V8OBJECT_H__
diff --git a/webkit/port/bindings/v8/npruntime.cpp b/webkit/port/bindings/v8/npruntime.cpp
new file mode 100644
index 0000000..074fa46
--- /dev/null
+++ b/webkit/port/bindings/v8/npruntime.cpp
@@ -0,0 +1,346 @@
+/*
+ * Copyright (C) 2004, 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2007 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 <map>
+#include <set>
+#include <string>
+#include <v8.h>
+#include "base/stats_counters.h"
+#include "bindings/npruntime.h"
+#include "np_v8object.h"
+#include "npruntime_priv.h"
+#include "v8_npobject.h"
+
+#include <wtf/Assertions.h>
+
+using namespace v8;
+
+
+// TODO: Consider removing locks if we're singlethreaded already.
+// The static initializer here should work okay, but we want to avoid
+// static initialization in general.
+//
+// Commenting out the locks to avoid dependencies on chrome for now.
+// Need a platform abstraction which we can use.
+// static Lock StringIdentifierMapLock;
+
+typedef std::map<std::string, PrivateIdentifier*> StringIdentifierMap;
+
+static StringIdentifierMap* getStringIdentifierMap() {
+ static StringIdentifierMap* stringIdentifierMap = 0;
+ if (!stringIdentifierMap)
+ stringIdentifierMap = new StringIdentifierMap();
+ return stringIdentifierMap;
+}
+
+// TODO: Consider removing locks if we're singlethreaded already.
+// static Lock IntIdentifierMapLock;
+
+typedef std::map<int, PrivateIdentifier*> IntIdentifierMap;
+
+static IntIdentifierMap* getIntIdentifierMap() {
+ static IntIdentifierMap* intIdentifierMap = 0;
+ if (!intIdentifierMap)
+ intIdentifierMap = new IntIdentifierMap;
+ return intIdentifierMap;
+}
+
+extern "C" {
+
+NPIdentifier NPN_GetStringIdentifier(const NPUTF8* name) {
+ ASSERT(name);
+
+ if (name) {
+ // AutoLock safeLock(StringIdentifierMapLock);
+
+ StringIdentifierMap::iterator iter =
+ getStringIdentifierMap()->find(std::string(name));
+ if (iter != getStringIdentifierMap()->end())
+ return static_cast<NPIdentifier>(iter->second);
+
+ PrivateIdentifier* identifier = reinterpret_cast<PrivateIdentifier*>(
+ malloc(sizeof(PrivateIdentifier)));
+ // We never release identifier names, so this dictionary will grow,
+ // as will the memory for the identifier name strings.
+ identifier->isString = true;
+ identifier->value.string = strdup(name);
+ (*getStringIdentifierMap())[std::string(name)] = identifier;
+ return (NPIdentifier)identifier;
+ }
+
+ return 0;
+}
+
+void NPN_GetStringIdentifiers(const NPUTF8** names, int32_t nameCount,
+ NPIdentifier* identifiers) {
+ ASSERT(names);
+ ASSERT(identifiers);
+
+ if (names && identifiers)
+ for (int i = 0; i < nameCount; i++)
+ identifiers[i] = NPN_GetStringIdentifier(names[i]);
+}
+
+NPIdentifier NPN_GetIntIdentifier(int32_t intid) {
+ // AutoLock safeLock(IntIdentifierMapLock);
+
+ IntIdentifierMap::iterator iter = getIntIdentifierMap()->find(intid);
+ if (iter != getIntIdentifierMap()->end())
+ return static_cast<NPIdentifier>(iter->second);
+
+ PrivateIdentifier* identifier = reinterpret_cast<PrivateIdentifier*>(
+ malloc(sizeof(PrivateIdentifier)));
+ // We never release identifier names, so this dictionary will grow.
+ identifier->isString = false;
+ identifier->value.number = intid;
+ (*getIntIdentifierMap())[intid] = identifier;
+ return (NPIdentifier)identifier;
+}
+
+bool NPN_IdentifierIsString(NPIdentifier identifier) {
+ PrivateIdentifier* i = reinterpret_cast<PrivateIdentifier*>(identifier);
+ return i->isString;
+}
+
+NPUTF8 *NPN_UTF8FromIdentifier(NPIdentifier identifier) {
+ PrivateIdentifier* i = reinterpret_cast<PrivateIdentifier*>(identifier);
+ if (!i->isString || !i->value.string)
+ return NULL;
+
+ return (NPUTF8 *)strdup(i->value.string);
+}
+
+int32_t NPN_IntFromIdentifier(NPIdentifier identifier) {
+ PrivateIdentifier* i = reinterpret_cast<PrivateIdentifier*>(identifier);
+ if (i->isString)
+ return 0;
+ return i->value.number;
+}
+
+void NPN_ReleaseVariantValue(NPVariant* variant) {
+ ASSERT(variant);
+
+ if (variant->type == NPVariantType_Object) {
+ NPN_ReleaseObject(variant->value.objectValue);
+ variant->value.objectValue = 0;
+ } else if (variant->type == NPVariantType_String) {
+ free((void*)variant->value.stringValue.UTF8Characters);
+ variant->value.stringValue.UTF8Characters = 0;
+ variant->value.stringValue.UTF8Length = 0;
+ }
+
+ variant->type = NPVariantType_Void;
+}
+
+static StatsCounter global_npobjects(L"NPObjects");
+
+NPObject *NPN_CreateObject(NPP npp, NPClass* aClass) {
+ ASSERT(aClass);
+
+ if (aClass) {
+ NPObject* obj;
+ if (aClass->allocate != NULL)
+ obj = aClass->allocate(npp, aClass);
+ else
+ obj = reinterpret_cast<NPObject*>(malloc(sizeof(NPObject)));
+
+ obj->_class = aClass;
+ obj->referenceCount = 1;
+
+ global_npobjects.Increment();
+ return obj;
+ }
+
+ return 0;
+}
+
+NPObject* NPN_RetainObject(NPObject* obj) {
+ ASSERT(obj);
+ ASSERT(obj->referenceCount > 0);
+
+ if (obj)
+ obj->referenceCount++;
+
+ return obj;
+}
+
+// _NPN_DeallocateObject actually deletes the object. Technically,
+// callers should use NPN_ReleaseObject. Webkit exposes this function
+// to kill objects which plugins may not have properly released.
+void _NPN_DeallocateObject(NPObject *obj) {
+ ASSERT(obj);
+ ASSERT(obj->referenceCount >= 0);
+
+ if (obj) {
+ global_npobjects.Decrement();
+
+ // NPObjects that remain in pure C++ may never have wrappers.
+ // Hence, if it's not already alive, don't unregister it.
+ // If it is alive, unregister it as the *last* thing we do
+ // so that it can do as much cleanup as possible on its own.
+ if (_NPN_IsAlive(obj))
+ _NPN_UnregisterObject(obj);
+
+ obj->referenceCount = -1;
+ if (obj->_class->deallocate)
+ obj->_class->deallocate(obj);
+ else
+ free(obj);
+ }
+}
+
+void NPN_ReleaseObject(NPObject* obj) {
+ ASSERT(obj);
+ ASSERT(obj->referenceCount >= 1);
+
+ if (obj && obj->referenceCount >= 1) {
+ if (--obj->referenceCount == 0)
+ _NPN_DeallocateObject(obj);
+ }
+}
+
+void _NPN_InitializeVariantWithStringCopy(NPVariant* variant,
+ const NPString* value) {
+ variant->type = NPVariantType_String;
+ variant->value.stringValue.UTF8Length = value->UTF8Length;
+ variant->value.stringValue.UTF8Characters =
+ reinterpret_cast<NPUTF8*>(malloc(sizeof(NPUTF8) * value->UTF8Length));
+ memcpy((void*)variant->value.stringValue.UTF8Characters,
+ value->UTF8Characters,
+ sizeof(NPUTF8) * value->UTF8Length);
+}
+
+
+// NPN_Registry
+//
+// The registry is designed for quick lookup of NPObjects.
+// JS needs to be able to quickly lookup a given NPObject to determine
+// if it is alive or not.
+// The browser needs to be able to quickly lookup all NPObjects which are
+// "owned" by an object.
+//
+// The g_live_objects is a hash table of all live objects to their owner
+// objects. Presence in this table is used primarily to determine if
+// objects are live or not.
+//
+// The g_root_objects is a hash table of root objects to a set of
+// objects that should be deactivated in sync with the root. A
+// root is defined as a top-level owner object. This is used on
+// Frame teardown to deactivate all objects associated
+// with a particular plugin.
+
+typedef std::set<NPObject*> NPObjectSet;
+typedef std::map<NPObject*, NPObject*> NPObjectMap;
+typedef std::map<NPObject*, NPObjectSet*> NPRootObjectMap;
+
+// A map of live NPObjects with pointers to their Roots.
+NPObjectMap g_live_objects;
+
+// A map of the root objects and the list of NPObjects
+// associated with that object.
+NPRootObjectMap g_root_objects;
+
+void _NPN_RegisterObject(NPObject* obj, NPObject* owner) {
+ ASSERT(obj);
+
+ // Check if already registered.
+ if (g_live_objects.find(obj) != g_live_objects.end()) {
+ return;
+ }
+
+ if (!owner) {
+ // Registering a new owner object.
+ ASSERT(g_root_objects.find(obj) == g_root_objects.end());
+ g_root_objects[obj] = new NPObjectSet();
+ } else {
+ // Always associate this object with it's top-most parent.
+ // Since we always flatten, we only have to look up one level.
+ NPObjectMap::iterator owner_entry = g_live_objects.find(owner);
+ NPObject* parent = NULL;
+ if (g_live_objects.end() != owner_entry)
+ parent = owner_entry->second;
+
+ if (parent) {
+ owner = parent;
+ }
+ ASSERT(g_root_objects.find(obj) == g_root_objects.end());
+ if (g_root_objects.find(owner) != g_root_objects.end())
+ (g_root_objects[owner])->insert(obj);
+ }
+
+ ASSERT(g_live_objects.find(obj) == g_live_objects.end());
+ g_live_objects[obj] = owner;
+}
+
+void _NPN_UnregisterObject(NPObject* obj) {
+ ASSERT(obj);
+ ASSERT(g_live_objects.find(obj) != g_live_objects.end());
+
+ NPObject* owner = NULL;
+ if (g_live_objects.find(obj) != g_live_objects.end())
+ owner = g_live_objects.find(obj)->second;
+
+ if (owner == NULL) {
+ // Unregistering a owner object; also unregister it's descendants.
+ ASSERT(g_root_objects.find(obj) != g_root_objects.end());
+ NPObjectSet* set = g_root_objects[obj];
+ while (set->size() > 0) {
+ size_t size = set->size();
+ NPObject* sub_object = *(set->begin());
+ // The sub-object should not be a owner!
+ ASSERT(g_root_objects.find(sub_object) == g_root_objects.end());
+
+ // First, unregister the object.
+ set->erase(sub_object);
+ g_live_objects.erase(sub_object);
+
+ // Remove the JS references to the object.
+ ForgetV8ObjectForNPObject(sub_object);
+
+ ASSERT(set->size() < size);
+ }
+ delete set;
+ g_root_objects.erase(obj);
+ } else {
+ NPRootObjectMap::iterator owner_entry = g_root_objects.find(owner);
+ if (owner_entry != g_root_objects.end()) {
+ NPObjectSet* list = owner_entry->second;
+ ASSERT(list->find(obj) != list->end());
+ list->erase(obj);
+ }
+ }
+ ForgetV8ObjectForNPObject(obj);
+
+ g_live_objects.erase(obj);
+}
+
+bool _NPN_IsAlive(NPObject* obj) {
+ return g_live_objects.find(obj) != g_live_objects.end();
+}
+
+} // extern "C"
diff --git a/webkit/port/bindings/v8/npruntime_impl.h b/webkit/port/bindings/v8/npruntime_impl.h
new file mode 100644
index 0000000..7dae168
--- /dev/null
+++ b/webkit/port/bindings/v8/npruntime_impl.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2004 Apple Computer, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#ifndef _NP_RUNTIME_IMPL_H_
+#define _NP_RUNTIME_IMPL_H_
+
+#include "bindings/npruntime.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void _NPN_ReleaseVariantValue(NPVariant *variant);
+extern NPIdentifier _NPN_GetStringIdentifier(const NPUTF8 *name);
+extern void _NPN_GetStringIdentifiers(const NPUTF8 **names, int32_t nameCount, NPIdentifier *identifiers);
+extern NPIdentifier _NPN_GetIntIdentifier(int32_t intid);
+extern bool _NPN_IdentifierIsString(NPIdentifier identifier);
+extern NPUTF8 *_NPN_UTF8FromIdentifier(NPIdentifier identifier);
+extern int32_t _NPN_IntFromIdentifier(NPIdentifier identifier);
+extern NPObject *_NPN_CreateObject(NPP npp, NPClass *aClass);
+extern NPObject *_NPN_RetainObject(NPObject *obj);
+extern void _NPN_ReleaseObject(NPObject *obj);
+extern void _NPN_DeallocateObject(NPObject *obj);
+extern bool _NPN_Invoke(NPP npp, NPObject *npobj, NPIdentifier methodName, const NPVariant *args, uint32_t argCount, NPVariant *result);
+extern bool _NPN_InvokeDefault(NPP npp, NPObject *npobj, const NPVariant *args, uint32_t argCount, NPVariant *result);
+extern bool _NPN_Evaluate(NPP npp, NPObject *npobj, NPString *script, NPVariant *result);
+extern bool _NPN_GetProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName, NPVariant *result);
+extern bool _NPN_SetProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName, const NPVariant *value);
+extern bool _NPN_RemoveProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName);
+extern bool _NPN_HasProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName);
+extern bool _NPN_HasMethod(NPP npp, NPObject *npobj, NPIdentifier methodName);
+extern void _NPN_SetException(NPObject *obj, const NPUTF8 *message);
+extern bool _NPN_Enumerate(NPP npp, NPObject *npobj, NPIdentifier **identifier, uint32_t *count);
+
+#ifdef __cplusplus
+} /* end extern "C" */
+#endif
+
+#endif
diff --git a/webkit/port/bindings/v8/npruntime_internal.h b/webkit/port/bindings/v8/npruntime_internal.h
new file mode 100644
index 0000000..f5357cd
--- /dev/null
+++ b/webkit/port/bindings/v8/npruntime_internal.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2007 Collabora, Ltd. 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
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * This is a internal include header for npapi.h
+ *
+ * Some of the #defines which are in X11 headers conflict with type and enum
+ * names in JavaScriptCore and WebCore
+ * This header #undefs those defines to fix the conflicts
+ * If you need to include npapi.h or npruntime.h when building on X11,
+ * include this file instead of the actual npapi.h or npruntime.h
+ */
+
+#include "npruntime.h"
+
+#ifdef XP_UNIX
+ #include <X11/Xresource.h>
+
+ #undef None
+ #undef Above
+ #undef Below
+ #undef Auto
+ #undef Complex
+ #undef Status
+#endif
diff --git a/webkit/port/bindings/v8/npruntime_priv.h b/webkit/port/bindings/v8/npruntime_priv.h
new file mode 100644
index 0000000..543c7d1
--- /dev/null
+++ b/webkit/port/bindings/v8/npruntime_priv.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2003, 2006 Apple Computer, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#ifndef NP_RUNTIME_PRIV_H_
+#define NP_RUNTIME_PRIV_H_
+
+
+#include "bindings/npruntime.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ _NPN_InitializeVariantWithStringCopy() will copy string data. The string data
+ will be deallocated by calls to NPReleaseVariantValue().
+*/
+void _NPN_InitializeVariantWithStringCopy(NPVariant*, const NPString*);
+void _NPN_DeallocateObject(NPObject *obj);
+
+// The following routines allow the browser to aggressively cleanup NPObjects
+// on a per plugin basis. All NPObjects used through the NPRuntime API should
+// be "registered" while they are alive. After an object has been
+// deleted, it is possible for Javascript to have a reference to that object
+// which has not yet been garbage collected. Javascript access to NPObjects
+// will reference this registry to determine if the object is accessible or
+// not.
+
+// Windows introduces an additional complication for objects created by the
+// plugin. Plugins load inside of a DLL. Each DLL has it's own heap. If
+// the browser unloads the plugin DLL, all objects created within the DLL's
+// heap instantly become invalid. Normally, when WebKit drops the reference
+// on the top-level plugin object, it tells the plugin manager that the
+// plugin can be destroyed, which can unload the DLL. So, we must eliminate
+// all pointers to any object ever created by the plugin.
+
+// We generally associate NPObjects with an owner. The owner of an NPObject
+// is an NPObject which, when destroyed, also destroys all objects it owns.
+// For example, if an NPAPI plugin creates 10 sub-NPObjects, all 11 objects
+// (the NPAPI plugin + its 10 sub-objects) should become inaccessible
+// simultaneously.
+
+// The ownership hierarchy is flat, and not a tree. Imagine the following
+// object creation:
+// PluginObject
+// |
+// +-- Creates -----> Object1
+// |
+// +-- Creates -----> Object2
+//
+// PluginObject will be the "owner" for both Object1 and Object2.
+
+// Register an NPObject with the runtime. If the owner is NULL, the
+// object is treated as an owning object. If owner is not NULL,
+// this object will be registered as owned by owner's top-level owner.
+void _NPN_RegisterObject(NPObject* obj, NPObject* owner);
+
+// Unregister an NPObject with the runtime. If obj is an owning
+// object, this call will also unregister all of the owned objects.
+void _NPN_UnregisterObject(NPObject* obj);
+
+// Check to see if an object is registered with the runtime.
+// Return true if registered, false otherwise.
+bool _NPN_IsAlive(NPObject* obj);
+
+#ifdef __cplusplus
+} /* end extern "C" */
+#endif
+
+#endif
diff --git a/webkit/port/bindings/v8/v8_binding.h b/webkit/port/bindings/v8/v8_binding.h
new file mode 100644
index 0000000..66237e8
--- /dev/null
+++ b/webkit/port/bindings/v8/v8_binding.h
@@ -0,0 +1,195 @@
+// Copyright 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.
+
+#ifndef V8_BINDING_H__
+#define V8_BINDING_H__
+
+#include <v8.h>
+#include "PlatformString.h"
+#include "MathExtras.h"
+#include "StringBuffer.h"
+
+// Suppress warnings in CString of converting size_t to unsigned int.
+// TODO(fqian): fix CString.h.
+#pragma warning(push, 0)
+#include "CString.h"
+#pragma warning(pop)
+#include "windows.h"
+
+#include "platform.h"
+
+namespace WebCore {
+
+// The string returned by this function is still owned by the argument
+// and will be deallocated when the argument is deallocated.
+inline const uint16_t* FromWebCoreString(const String& str) {
+ return reinterpret_cast<const uint16_t*>(str.characters());
+}
+
+// WebCoreStringResource is a helper class for v8ExternalString. It is used
+// to manage the life-cycle of the underlying buffer of the external string.
+class WebCoreStringResource: public v8::String::ExternalStringResource {
+ public:
+ explicit WebCoreStringResource(const String& str)
+ : external_string_(str) {
+ }
+
+ ~WebCoreStringResource() {}
+
+ const uint16_t* data() const { return FromWebCoreString(external_string_); }
+
+ size_t length() const { return external_string_.length(); }
+
+ String webcore_string() { return external_string_; }
+
+ private:
+ // A shallow copy of the string.
+ // Keeps the string buffer alive until the V8 engine garbage collects it.
+ String external_string_;
+};
+
+// TODO: converting between WebCore::String and V8 string is expensive.
+// Optimize it !!!
+inline String ToWebCoreString(v8::Handle<v8::Value> obj) {
+ v8::TryCatch block;
+ v8::Local<v8::String> v8_str = obj->ToString();
+ if (v8_str.IsEmpty())
+ return "";
+
+ if (v8_str->IsExternal()) {
+ WebCoreStringResource* str_resource = static_cast<WebCoreStringResource*>(
+ v8_str->GetExternalStringResource());
+ return str_resource->webcore_string();
+ }
+
+ int length = v8_str->Length();
+ StringBuffer buf(length);
+ v8_str->Write(reinterpret_cast<uint16_t*>(buf.characters()), 0, length);
+ return String::adopt(buf);
+}
+
+inline String valueToStringWithNullCheck(v8::Handle<v8::Value> value) {
+ if (value->IsNull()) return String();
+ return ToWebCoreString(value);
+}
+
+inline String valueToStringWithNullOrUndefinedCheck(
+ v8::Handle<v8::Value> value) {
+ if (value->IsNull() || value->IsUndefined()) return String();
+ return ToWebCoreString(value);
+}
+
+// Convert a value to a 32-bit integer. The conversion fails if the
+// value cannot be converted to an integer or converts to nan or to an
+// infinity.
+inline int ToInt32(v8::Handle<v8::Value> value, bool& ok) {
+ ok = true;
+
+ // Fast case. The value is already a 32-bit integer.
+ if (value->IsInt32()) {
+ return value->Int32Value();
+ }
+
+ // Can the value be converted to a number?
+ v8::Local<v8::Number> number_object = value->ToNumber();
+ if (number_object.IsEmpty()) {
+ ok = false;
+ return 0;
+ }
+
+ // Does the value convert to nan or to an infinity?
+ double number_value = number_object->Value();
+ if (isnan(number_value) || isinf(number_value)) {
+ ok = false;
+ return 0;
+ }
+
+ // Can the value be converted to a 32-bit integer?
+ v8::Local<v8::Int32> int_value = value->ToInt32();
+ if (int_value.IsEmpty()) {
+ ok = false;
+ return 0;
+ }
+
+ // Return the result of the int32 conversion.
+ return int_value->Value();
+}
+
+// Convert a value to a 32-bit integer assuming the conversion cannot fail.
+inline int ToInt32(v8::Handle<v8::Value> value) {
+ bool ok;
+ return ToInt32(value, ok);
+}
+
+// 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).
+static const int kV8ExternalStringThreshold = 2048;
+
+// Convert a string to a V8 string.
+inline v8::Handle<v8::String> v8String(const String& str) {
+ if (str.length() <= kV8ExternalStringThreshold) {
+ return v8::String::New(FromWebCoreString(str), str.length());
+ } else {
+ return v8::String::NewExternal(new WebCoreStringResource(str));
+ }
+}
+
+inline v8::Handle<v8::String> v8UndetectableString(const String& str) {
+ return v8::String::NewUndetectable(FromWebCoreString(str), str.length());
+}
+
+// Return a V8 external string that shares the underlying buffer with the given
+// WebCore string. The reference counting mechanism is used to keep the
+// underlying buffer alive while the string is still live in the V8 engine.
+inline v8::Local<v8::String> v8ExternalString(const String& str) {
+ return v8::String::NewExternal(new WebCoreStringResource(str));
+}
+
+inline v8::Handle<v8::Value> v8StringOrNull(const String& str) {
+ return str.isNull()
+ ? v8::Handle<v8::Value>(v8::Null())
+ : v8::Handle<v8::Value>(v8String(str));
+}
+
+inline v8::Handle<v8::Value> v8StringOrUndefined(const String& str) {
+ return str.isNull()
+ ? v8::Handle<v8::Value>(v8::Undefined())
+ : v8::Handle<v8::Value>(v8String(str));
+}
+
+inline v8::Handle<v8::Value> v8StringOrFalse(const String& str) {
+ return str.isNull()
+ ? v8::Handle<v8::Value>(v8::False())
+ : v8::Handle<v8::Value>(v8String(str));
+}
+
+} // namespace WebCore
+
+#endif // V8_BINDING_H__
diff --git a/webkit/port/bindings/v8/v8_custom.cpp b/webkit/port/bindings/v8/v8_custom.cpp
new file mode 100644
index 0000000..63b9d24
--- /dev/null
+++ b/webkit/port/bindings/v8/v8_custom.cpp
@@ -0,0 +1,3414 @@
+/*
+ * 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.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "config.h"
+
+#include <Assertions.h>
+
+#include "v8_proxy.h"
+#include "v8_events.h"
+#include "v8_binding.h"
+#include "v8_npobject.h"
+#include "v8_vectornodelist.h"
+#include "v8_custom.h"
+
+#include "V8Attr.h"
+#include "V8CanvasGradient.h"
+#include "V8CanvasPattern.h"
+#include "V8Document.h"
+#include "V8DOMWindow.h"
+#include "V8HTMLCanvasElement.h"
+#include "V8HTMLDocument.h"
+#include "V8HTMLImageElement.h"
+#include "V8HTMLOptionElement.h"
+#include "V8Node.h"
+#include "V8XPathNSResolver.h"
+#include "V8XPathResult.h"
+
+#include "CanvasGradient.h"
+#include "CanvasPattern.h"
+#include "CanvasStyle.h"
+#include "CanvasRenderingContext2D.h"
+
+#include "Clipboard.h"
+#include "ClipboardEvent.h"
+
+#include "Base64.h"
+#include "FloatRect.h"
+#include "Frame.h"
+#include "FrameTree.h"
+#include "FrameLoader.h"
+#include "FrameView.h"
+#include "Document.h"
+#include "DocumentFragment.h"
+#include "DOMParser.h"
+#include "DOMWindow.h"
+#include "Location.h"
+#include "History.h"
+#include "ScheduledAction.h"
+#include "Event.h"
+#include "EventListener.h"
+#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"
+#include "HTMLEmbedElement.h"
+#include "HTMLIFrameElement.h"
+#include "HTMLFrameElement.h"
+#include "HTMLFrameElementBase.h"
+#include "HTMLFrameSetElement.h"
+#include "HTMLImageElement.h"
+#include "HTMLCanvasElement.h"
+#include "HTMLFormElement.h"
+#include "HTMLOptionElement.h"
+#include "HTMLOptionsCollection.h"
+#include "HTMLSelectElement.h"
+#include "MouseEvent.h"
+#include "NodeIterator.h"
+#include "Page.h"
+#include "PlatformScreen.h"
+#include "RenderWidget.h"
+#include "RenderPartObject.h"
+#include "RGBColor.h"
+#include "SecurityOrigin.h"
+#include "Settings.h"
+#include "StyleSheetList.h"
+#include "TreeWalker.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"
+#include "SVGException.h"
+#include "SVGPathSeg.h"
+#endif
+
+#undef LOG
+
+#include "webkit/glue/webplugin_impl.h"
+
+// Horizontal and vertical offset, from the parent content area, around newly
+// opened popups that don't specify a location.
+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)
+
+#define NAMED_PROPERTY_SETTER(NAME) \
+v8::Handle<v8::Value> V8Custom::v8##NAME##NamedPropertySetter(\
+ v8::Local<v8::String> name, v8::Local<v8::Value> value, \
+ const v8::AccessorInfo& info)
+
+#define NAMED_PROPERTY_DELETER(NAME) \
+v8::Handle<v8::Boolean> V8Custom::v8##NAME##NamedPropertyDeleter(\
+ v8::Local<v8::String> name, const v8::AccessorInfo& info)
+
+#define INDEXED_PROPERTY_GETTER(NAME) \
+v8::Handle<v8::Value> V8Custom::v8##NAME##IndexedPropertyGetter(\
+ uint32_t index, const v8::AccessorInfo& info)
+
+#define INDEXED_PROPERTY_SETTER(NAME) \
+v8::Handle<v8::Value> V8Custom::v8##NAME##IndexedPropertySetter(\
+ uint32_t index, v8::Local<v8::Value> value, const v8::AccessorInfo& info)
+
+#define INDEXED_PROPERTY_DELETER(NAME) \
+v8::Handle<v8::Boolean> V8Custom::v8##NAME##IndexedPropertyDeleter(\
+ uint32_t index, const v8::AccessorInfo& info)
+
+#define NAMED_ACCESS_CHECK(NAME) \
+bool V8Custom::v8##NAME##NamedSecurityCheck(v8::Local<v8::Object> host, \
+ v8::Local<v8::Value> key, \
+ v8::AccessType type, \
+ v8::Local<v8::Value> data)
+
+#define INDEXED_ACCESS_CHECK(NAME) \
+bool V8Custom::v8##NAME##IndexedSecurityCheck(v8::Local<v8::Object> host, \
+ uint32_t index, \
+ v8::AccessType type, \
+ v8::Local<v8::Value> data)
+
+class V8ScheduledAction : public ScheduledAction {
+ public:
+ V8ScheduledAction(v8::Handle<v8::Function> func, int argc,
+ v8::Handle<v8::Value> argv[]);
+ explicit V8ScheduledAction(const WebCore::String& code) : m_code(code),
+ m_argc(0), m_argv(NULL) { }
+ virtual ~V8ScheduledAction();
+ virtual void execute(DOMWindow* window);
+
+ private:
+ v8::Persistent<v8::Function> m_func;
+ int m_argc;
+ v8::Persistent<v8::Value>* m_argv;
+
+ String m_code;
+};
+
+V8ScheduledAction::V8ScheduledAction(v8::Handle<v8::Function> func, int argc,
+ v8::Handle<v8::Value> argv[]) {
+ m_func = v8::Persistent<v8::Function>::New(func);
+
+#ifndef NDEBUG
+ V8Proxy::RegisterGlobalHandle(SCHEDULED_ACTION, this, m_func);
+#endif
+
+ m_argc = argc;
+ if (argc > 0) {
+ m_argv = new v8::Persistent<v8::Value>[argc];
+ for (int i = 0; i < argc; i++) {
+ m_argv[i] = v8::Persistent<v8::Value>::New(argv[i]);
+
+#ifndef NDEBUG
+ V8Proxy::RegisterGlobalHandle(SCHEDULED_ACTION, this, m_argv[i]);
+#endif
+ }
+ } else {
+ m_argv = NULL;
+ }
+}
+
+
+V8ScheduledAction::~V8ScheduledAction() {
+ if (!m_func.IsEmpty()) {
+#ifndef NDEBUG
+ V8Proxy::UnregisterGlobalHandle(this, m_func);
+#endif
+ m_func.Dispose();
+
+ for (int i = 0; i < m_argc; i++) {
+#ifndef NDEBUG
+ V8Proxy::UnregisterGlobalHandle(this, m_argv[i]);
+#endif
+ m_argv[i].Dispose();
+ }
+ if (m_argc > 0) {
+ delete[] m_argv;
+ }
+ }
+}
+
+
+void V8ScheduledAction::execute(DOMWindow* window) {
+ // TODO(ager): Timeouts for running the javascript code are not set.
+ Frame* frame = window->frame();
+ if (!frame) return;
+
+ v8::HandleScope handle_scope;
+ v8::Local<v8::Context> context = V8Proxy::GetContext(frame);
+ if (context.IsEmpty()) return; // JS may not be enabled.
+
+ v8::Context::Scope scope(context);
+
+ V8Proxy* proxy = V8Proxy::retrieve(frame);
+ proxy->setTimerCallback(true);
+
+ if (!m_func.IsEmpty() && m_func->IsFunction()) {
+ proxy->CallFunction(v8::Persistent<v8::Function>::Cast(m_func),
+ context->Global(), m_argc, m_argv);
+ } else {
+ // TODO: why cannot just compile and run m_code?
+ // check what's in V8Proxy::Evaluate
+ frame->loader()->executeScript(m_code);
+ }
+
+ if (Document* doc = frame->document())
+ doc->updateRendering();
+
+ proxy->setTimerCallback(false);
+}
+
+
+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,
+ DOMParser>(args);
+}
+
+
+CALLBACK_FUNC_DECL(XMLSerializerConstructor) {
+ INC_STATS(L"DOM.XMLSerializer.Constructor");
+ return V8Proxy::ConstructDOMObject<V8ClassIndex::XMLSERIALIZER,
+ XMLSerializer>(args);
+}
+
+
+CALLBACK_FUNC_DECL(XPathEvaluatorConstructor) {
+ INC_STATS(L"DOM.XPathEvaluator.Constructor");
+ return V8Proxy::ConstructDOMObject<V8ClassIndex::XPATHEVALUATOR,
+ XPathEvaluator>(args);
+}
+
+
+CALLBACK_FUNC_DECL(XSLTProcessorConstructor) {
+ INC_STATS(L"DOM.XSLTProcessor.Constructor");
+ return V8Proxy::ConstructDOMObject<V8ClassIndex::XSLTPROCESSOR,
+ XSLTProcessor>(args);
+}
+
+
+CALLBACK_FUNC_DECL(XSLTProcessorImportStylesheet) {
+ INC_STATS(L"DOM.XSLTProcessor.importStylesheet");
+ // Return undefined if argument does not have the correct type.
+ if (!V8Node::HasInstance(args[0]))
+ return v8::Undefined();
+
+ XSLTProcessor* imp = V8Proxy::FastToNativeObject<XSLTProcessor>(
+ V8ClassIndex::XSLTPROCESSOR, args.Holder());
+
+ Node* node = V8Proxy::FastToNativeObject<Node>(V8ClassIndex::NODE, args[0]);
+ imp->importStylesheet(node);
+ return v8::Undefined();
+}
+
+
+CALLBACK_FUNC_DECL(XSLTProcessorTransformToFragment) {
+ INC_STATS(L"DOM.XSLTProcessor.transformToFragment");
+ // Return undefined if arguments do not have correct types.
+ if (!V8Node::HasInstance(args[0]) || !V8Document::HasInstance(args[1]))
+ return v8::Undefined();
+
+ XSLTProcessor* imp = V8Proxy::FastToNativeObject<XSLTProcessor>(
+ V8ClassIndex::XSLTPROCESSOR, args.Holder());
+
+ Node* source = V8Proxy::FastToNativeObject<Node>(V8ClassIndex::NODE, args[0]);
+ Document* owner =
+ V8Proxy::FastToNativeObject<Document>(V8ClassIndex::NODE, args[1]);
+ RefPtr<DocumentFragment> result = imp->transformToFragment(source, owner);
+ return V8Proxy::ToV8Object(V8ClassIndex::NODE, result.get());
+}
+
+
+CALLBACK_FUNC_DECL(XSLTProcessorTransformToDocument) {
+ INC_STATS(L"DOM.XSLTProcessor.transformToDocument");
+ // Return undefined if argument does not have the correct type.
+ if (!V8Node::HasInstance(args[0]))
+ return v8::Undefined();
+
+ XSLTProcessor* imp = V8Proxy::FastToNativeObject<XSLTProcessor>(
+ V8ClassIndex::XSLTPROCESSOR, args.Holder());
+
+ Node* source = V8Proxy::FastToNativeObject<Node>(V8ClassIndex::NODE, args[0]);
+ if (!source) return v8::Undefined();
+ RefPtr<Document> result = imp->transformToDocument(source);
+ // Return undefined if no result was found.
+ if (!result) return v8::Undefined();
+ return V8Proxy::ToV8Object(V8ClassIndex::NODE, result.get());
+}
+
+
+CALLBACK_FUNC_DECL(XSLTProcessorSetParameter) {
+ INC_STATS(L"DOM.XSLTProcessor.setParameter");
+ // Bail out if localName or value is null or undefined.
+ if (args[1]->IsNull() || args[1]->IsUndefined() ||
+ args[2]->IsNull() || args[2]->IsUndefined()) {
+ return v8::Undefined();
+ }
+
+ XSLTProcessor* imp = V8Proxy::FastToNativeObject<XSLTProcessor>(
+ V8ClassIndex::XSLTPROCESSOR, args.Holder());
+
+ String namespaceURI = ToWebCoreString(args[0]);
+ String localName = ToWebCoreString(args[1]);
+ String value = ToWebCoreString(args[2]);
+ imp->setParameter(namespaceURI, localName, value);
+ return v8::Undefined();
+}
+
+
+CALLBACK_FUNC_DECL(XSLTProcessorGetParameter) {
+ INC_STATS(L"DOM.XSLTProcessor.getParameter");
+ // Bail out if localName is null or undefined.
+ if (args[1]->IsNull() || args[1]->IsUndefined()) {
+ return v8::Undefined();
+ }
+
+ XSLTProcessor* imp = V8Proxy::FastToNativeObject<XSLTProcessor>(
+ V8ClassIndex::XSLTPROCESSOR, args.Holder());
+
+ String namespaceURI = ToWebCoreString(args[0]);
+ String localName = ToWebCoreString(args[1]);
+ String result = imp->getParameter(namespaceURI, localName);
+ // Return undefined if the string is null.
+ if (result.isNull()) return v8::Undefined();
+ return v8String(result);
+}
+
+
+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()) {
+ return v8::Undefined();
+ }
+
+ XSLTProcessor* imp = V8Proxy::FastToNativeObject<XSLTProcessor>(
+ V8ClassIndex::XSLTPROCESSOR, args.Holder());
+
+ String namespaceURI = ToWebCoreString(args[0]);
+ String localName = ToWebCoreString(args[1]);
+ imp->removeParameter(namespaceURI, localName);
+ return v8::Undefined();
+}
+
+
+// ---- 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 PassRefPtr<CanvasStyle> V8ObjectToCanvasStyle(
+ v8::Handle<v8::Value> value) {
+ if (value->IsString()) return new CanvasStyle(ToWebCoreString(value));
+
+ if (V8CanvasGradient::HasInstance(value)) {
+ CanvasGradient* gradient =
+ V8Proxy::FastDOMWrapperToNative<CanvasGradient>(value);
+ return new CanvasStyle(gradient);
+ }
+
+ if (V8CanvasPattern::HasInstance(value)) {
+ CanvasPattern* pattern =
+ V8Proxy::FastDOMWrapperToNative<CanvasPattern>(value);
+ return new CanvasStyle(pattern);
+ }
+
+ return 0;
+}
+
+
+ACCESSOR_GETTER(CanvasRenderingContext2DStrokeStyle) {
+ CanvasRenderingContext2D* impl =
+ V8Proxy::FastDOMWrapperToNative<CanvasRenderingContext2D>(info.Holder());
+ CanvasStyle* strokeStyle = impl->strokeStyle();
+ return CanvasStyleToV8Object(strokeStyle);
+}
+
+
+ACCESSOR_SETTER(CanvasRenderingContext2DStrokeStyle) {
+ CanvasRenderingContext2D* impl =
+ V8Proxy::FastDOMWrapperToNative<CanvasRenderingContext2D>(info.Holder());
+ impl->setStrokeStyle(V8ObjectToCanvasStyle(value));
+}
+
+ACCESSOR_GETTER(CanvasRenderingContext2DFillStyle) {
+ CanvasRenderingContext2D* impl =
+ V8Proxy::FastDOMWrapperToNative<CanvasRenderingContext2D>(info.Holder());
+ CanvasStyle* fillStyle = impl->fillStyle();
+ return CanvasStyleToV8Object(fillStyle);
+}
+
+
+ACCESSOR_SETTER(CanvasRenderingContext2DFillStyle) {
+ CanvasRenderingContext2D* impl =
+ V8Proxy::FastDOMWrapperToNative<CanvasRenderingContext2D>(info.Holder());
+ impl->setFillStyle(V8ObjectToCanvasStyle(value));
+}
+
+
+// DOMImplementation is a singleton in WebCore. If we use our normal
+// mapping from DOM objects to V8 wrappers, the same wrapper will be
+// shared for all frames in the same process. This is a major
+// security problem. Therefore, we generate a DOMImplementation
+// wrapper per document and store it in an internal field of the
+// document. Since the DOMImplementation object is a singleton, we do
+// not have to do anything to keep the DOMImplementation object alive
+// for the lifetime of the wrapper.
+ACCESSOR_GETTER(DocumentImplementation) {
+ ASSERT(info.Holder()->InternalFieldCount() >=
+ kDocumentMinimumInternalFieldCount);
+ // Check if the internal field already contains a wrapper.
+ v8::Local<v8::Value> implementation =
+ info.Holder()->GetInternalField(kDocumentImplementationIndex);
+ if (!implementation->IsUndefined()) {
+ return implementation;
+ }
+ // Generate a wrapper.
+ Document* doc = V8Proxy::FastDOMWrapperToNative<Document>(info.Holder());
+ v8::Handle<v8::Value> wrapper =
+ V8Proxy::DOMImplementationToV8Object(doc->implementation());
+ // Store the wrapper in the internal field.
+ info.Holder()->SetInternalField(kDocumentImplementationIndex, wrapper);
+
+ return wrapper;
+}
+
+
+ACCESSOR_GETTER(DocumentLocation) {
+ Document* imp = V8Proxy::FastDOMWrapperToNative<Document>(info.Holder());
+ if (!imp->frame())
+ return v8::Null();
+
+ DOMWindow* window = imp->frame()->domWindow();
+ return V8Proxy::ToV8Object(V8ClassIndex::LOCATION,
+ static_cast<Peerable*>(window->location()));
+}
+
+
+ACCESSOR_SETTER(DocumentLocation) {
+ Document* imp = V8Proxy::FastDOMWrapperToNative<Document>(info.Holder());
+ if (!imp->frame())
+ return;
+
+ DOMWindow* window = imp->frame()->domWindow();
+ // DOMWindow::setLocation does security checks.
+ window->setLocation(ToWebCoreString(value));
+}
+
+
+ACCESSOR_GETTER(DOMWindowLocation) {
+ v8::Handle<v8::Object> holder = V8Proxy::LookupDOMWrapper(
+ V8ClassIndex::DOMWINDOW, info.This());
+ if (holder.IsEmpty())
+ return v8::Undefined();
+
+ DOMWindow* imp = V8Proxy::FastToNativeObject<DOMWindow>(
+ V8ClassIndex::DOMWINDOW, holder);
+
+ // Give subframes precedence.
+ if (imp->frame()) {
+ Frame* child = imp->frame()->tree()->child("location");
+ if (child)
+ return V8Proxy::ToV8Object(V8ClassIndex::DOMWINDOW, child->domWindow());
+ }
+
+ // Normal getter or real 'location' property.
+ Location* v = imp->location();
+ return V8Proxy::ToV8Object(V8ClassIndex::LOCATION, static_cast<Peerable*>(v));
+}
+
+
+ACCESSOR_SETTER(DOMWindowLocation) {
+ v8::Handle<v8::Object> holder = V8Proxy::LookupDOMWrapper(
+ V8ClassIndex::DOMWINDOW, info.This());
+ if (holder.IsEmpty())
+ return;
+
+ DOMWindow* imp = V8Proxy::FastToNativeObject<DOMWindow>(
+ V8ClassIndex::DOMWINDOW, holder);
+ imp->setLocation(ToWebCoreString(value));
+}
+
+
+ACCESSOR_SETTER(DOMWindowOpener) {
+ DOMWindow* imp = V8Proxy::FastToNativeObject<DOMWindow>(
+ V8ClassIndex::DOMWINDOW, info.Holder());
+
+ if (!V8Proxy::IsFromSameOrigin(imp->frame(), true))
+ return;
+
+ // Opener can be shadowed if it is in the same domain.
+ // Have a special handling of null value to behave
+ // like Firefox. See bug 1224887 & 791706.
+ if (value->IsNull()) {
+ // imp->frame() cannot be null,
+ // otherwise, SameOrigin check would have failed.
+ ASSERT(imp->frame());
+ imp->frame()->loader()->setOpener(0);
+ }
+
+ // Delete the accessor from this object.
+ info.Holder()->Delete(name);
+
+ // Put property on the front (this) object.
+ info.This()->Set(name, value);
+}
+
+
+ACCESSOR_GETTER(EventSrcElement) {
+ Event* event = V8Proxy::FastDOMWrapperToNative<Event>(info.Holder());
+ EventTarget* target = event->target();
+ return V8Proxy::EventTargetToV8Object(target);
+}
+
+
+ACCESSOR_GETTER(EventReturnValue) {
+ Event* event = V8Proxy::FastDOMWrapperToNative<Event>(info.Holder());
+ return event->defaultPrevented() ? v8::False() : v8::True();
+}
+
+
+ACCESSOR_SETTER(EventReturnValue) {
+ Event* event = V8Proxy::FastDOMWrapperToNative<Event>(info.Holder());
+ bool v = value->BooleanValue();
+ event->setDefaultPrevented(!v);
+}
+
+
+ACCESSOR_GETTER(EventDataTransfer) {
+ Event* event = V8Proxy::FastDOMWrapperToNative<Event>(info.Holder());
+
+ if (event->isDragEvent()) {
+ MouseEvent* impl = static_cast<MouseEvent*>(event);
+ Clipboard* clipboard = impl->clipboard();
+ return V8Proxy::ToV8Object(V8ClassIndex::CLIPBOARD, clipboard);
+ }
+
+ return v8::Undefined();
+}
+
+
+ACCESSOR_GETTER(EventClipboardData) {
+ Event* event = V8Proxy::FastDOMWrapperToNative<Event>(info.Holder());
+
+ if (event->isClipboardEvent()) {
+ ClipboardEvent* impl = static_cast<ClipboardEvent*>(event);
+ Clipboard* clipboard = impl->clipboard();
+ return V8Proxy::ToV8Object(V8ClassIndex::CLIPBOARD, clipboard);
+ }
+
+ return v8::Undefined();
+}
+
+
+static v8::Handle<v8::Value> HTMLCollectionGetNamedItems(
+ HTMLCollection* collection, String name) {
+ Vector<RefPtr<Node> > namedItems;
+ collection->namedItems(name, namedItems);
+ switch (namedItems.size()) {
+ case 0:
+ return v8::Handle<v8::Value>();
+ case 1:
+ return V8Proxy::ToV8Object(V8ClassIndex::NODE, namedItems.at(0).get());
+ default:
+ NodeList* list = new V8VectorNodeList(namedItems);
+ return V8Proxy::ToV8Object(V8ClassIndex::NODELIST,
+ static_cast<Peerable*>(list));
+ }
+}
+
+
+static v8::Handle<v8::Value> HTMLCollectionGetItem(
+ HTMLCollection* collection, v8::Handle<v8::Value> argument) {
+ v8::Local<v8::Uint32> index = argument->ToArrayIndex();
+ if (index.IsEmpty()) {
+ v8::Handle<v8::String> str = argument->ToString();
+ v8::Handle<v8::Value> result =
+ HTMLCollectionGetNamedItems(collection, ToWebCoreString(str));
+ if (result.IsEmpty())
+ return v8::Undefined();
+ else
+ return result;
+ }
+ unsigned i = index->Uint32Value();
+ RefPtr<Node> result = collection->item(i);
+ return V8Proxy::ToV8Object(V8ClassIndex::NODE, result.get());
+}
+
+
+NAMED_PROPERTY_GETTER(HTMLCollection) {
+ INC_STATS(L"DOM.HTMLCollection.NamedPropertyGetter");
+ // Search the prototype chain first.
+ v8::Handle<v8::Value> value =
+ info.Holder()->GetRealNamedPropertyInPrototypeChain(name);
+
+ if (!value.IsEmpty()) {
+ return value;
+ }
+
+ // Search local callback properties next to find IDL defined
+ // properties.
+ if (info.Holder()->HasRealNamedCallbackProperty(name)) {
+ return v8::Handle<v8::Value>();
+ }
+
+ // Finally, search the DOM structure.
+ HTMLCollection* imp = V8Proxy::FastToNativeObject<HTMLCollection>(
+ V8ClassIndex::HTMLCOLLECTION, info.Holder());
+ String key = ToWebCoreString(name);
+ return HTMLCollectionGetNamedItems(imp, key);
+}
+
+
+CALLBACK_FUNC_DECL(HTMLCollectionItem) {
+ INC_STATS(L"DOM.HTMLCollection.item()");
+ HTMLCollection* imp = V8Proxy::FastToNativeObject<HTMLCollection>(
+ V8ClassIndex::HTMLCOLLECTION, args.Holder());
+ return HTMLCollectionGetItem(imp, args[0]);
+}
+
+
+CALLBACK_FUNC_DECL(HTMLCollectionNamedItem) {
+ INC_STATS(L"DOM.HTMLCollection.namedItem()");
+ HTMLCollection* imp = V8Proxy::FastToNativeObject<HTMLCollection>(
+ V8ClassIndex::HTMLCOLLECTION, args.Holder());
+ String name = ToWebCoreString(args[0]);
+ v8::Handle<v8::Value> result =
+ HTMLCollectionGetNamedItems(imp, name);
+ if (result.IsEmpty())
+ return v8::Undefined();
+ else
+ return result;
+}
+
+
+CALLBACK_FUNC_DECL(HTMLCollectionCallAsFunction) {
+ INC_STATS(L"DOM.HTMLCollection.callAsFunction()");
+ if (args.Length() < 1) return v8::Undefined();
+
+ HTMLCollection* imp = V8Proxy::FastToNativeObject<HTMLCollection>(
+ V8ClassIndex::HTMLCOLLECTION, args.Holder());
+
+ if (args.Length() == 1) {
+ return HTMLCollectionGetItem(imp, args[0]);
+ }
+
+ // If there is a second argument it is the index of the item we
+ // want.
+ String name = ToWebCoreString(args[0]);
+ v8::Local<v8::Uint32> index = args[1]->ToArrayIndex();
+ if (index.IsEmpty()) return v8::Undefined();
+ unsigned i = index->Uint32Value();
+ Node* node = imp->namedItem(name);
+ while (node) {
+ if (i == 0) return V8Proxy::ToV8Object(V8ClassIndex::NODE, node);
+ node = imp->nextNamedItem(name);
+ i--;
+ }
+
+ return v8::Undefined();
+}
+
+
+static v8::Handle<v8::Value> V8HTMLSelectElementRemoveHelper(
+ HTMLSelectElement* imp, const v8::Arguments& args) {
+ if (V8HTMLOptionElement::HasInstance(args[0])) {
+ HTMLOptionElement* element = V8Proxy::ToNativeObject<HTMLOptionElement>(
+ V8ClassIndex::HTMLOPTIONELEMENT, args[0]);
+ imp->remove(element->index());
+ return v8::Undefined();
+ }
+
+ imp->remove(ToInt32(args[0]));
+ return v8::Undefined();
+}
+
+CALLBACK_FUNC_DECL(HTMLSelectElementRemove) {
+ INC_STATS(L"DOM.HTMLSelectElement.remove");
+ HTMLSelectElement* imp = V8Proxy::FastToNativeObject<HTMLSelectElement>(
+ V8ClassIndex::HTMLSELECTELEMENT, args.Holder());
+ return V8HTMLSelectElementRemoveHelper(imp, args);
+}
+
+CALLBACK_FUNC_DECL(HTMLOptionsCollectionRemove) {
+ INC_STATS(L"DOM.HTMLOptionsCollection.remove()");
+ HTMLOptionsCollection* imp =
+ V8Proxy::FastToNativeObject<HTMLOptionsCollection>(
+ V8ClassIndex::HTMLOPTIONSCOLLECTION, args.Holder());
+ HTMLSelectElement* base = static_cast<HTMLSelectElement*>(imp->base());
+ return V8HTMLSelectElementRemoveHelper(base, args);
+}
+
+
+CALLBACK_FUNC_DECL(HTMLOptionsCollectionAdd) {
+ INC_STATS(L"DOM.HTMLOptionsCollection.add()");
+ if (!V8HTMLOptionElement::HasInstance(args[0])) {
+ V8Proxy::SetDOMException(TYPE_MISMATCH_ERR);
+ return v8::Undefined();
+ }
+ HTMLOptionsCollection* imp =
+ V8Proxy::FastToNativeObject<HTMLOptionsCollection>(
+ V8ClassIndex::HTMLOPTIONSCOLLECTION, args.Holder());
+ HTMLOptionElement* option = V8Proxy::ToNativeObject<HTMLOptionElement>(
+ V8ClassIndex::NODE, args[0]);
+
+ ExceptionCode ec = 0;
+ if (args.Length() < 2) {
+ imp->add(option, ec);
+ } else {
+ bool ok;
+ v8::TryCatch try_catch;
+ int index = ToInt32(args[1], ok);
+ if (try_catch.HasCaught()) {
+ return v8::Undefined();
+ }
+ if (!ok) {
+ ec = TYPE_MISMATCH_ERR;
+ } else {
+ imp->add(option, index, ec);
+ }
+ }
+ if (ec != 0) {
+ V8Proxy::SetDOMException(ec);
+ }
+ return v8::Undefined();
+}
+
+
+CALLBACK_FUNC_DECL(DOMWindowAddEventListener) {
+ INC_STATS(L"DOM.DOMWindow.addEventListener()");
+ DOMWindow* imp = V8Proxy::FastToNativeObject<DOMWindow>(
+ V8ClassIndex::DOMWINDOW, args.Holder());
+
+ // Fast check This argument with the global object of security context.
+ if ((args.This() != v8::Context::GetCurrentSecurityContext()->Global()) &&
+ !V8Proxy::IsFromSameOrigin(imp->frame(), true)) {
+ return v8::Undefined();
+ }
+
+ if (!imp->frame())
+ return v8::Undefined(); // DOMWindow could be disconnected from the frame
+
+ Document* doc = imp->frame()->document();
+ if (!doc)
+ return v8::Undefined();
+
+ // TODO: Check if there is not enough arguments
+ V8Proxy* proxy = V8Proxy::retrieve(imp->frame());
+ if (!proxy)
+ return v8::Undefined();
+
+ EventListener* listener =
+ proxy->FindOrCreateV8EventListener(args[1], false);
+
+ if (listener) {
+ String event_type = ToWebCoreString(args[0]);
+ bool useCapture = args[2]->BooleanValue();
+ doc->addWindowEventListener(event_type, listener, useCapture);
+ }
+
+ return v8::Undefined();
+}
+
+
+CALLBACK_FUNC_DECL(DOMWindowRemoveEventListener) {
+ INC_STATS(L"DOM.DOMWindow.removeEventListener()");
+ DOMWindow* imp = V8Proxy::FastToNativeObject<DOMWindow>(
+ V8ClassIndex::DOMWINDOW, args.Holder());
+
+ // Fast check This argument with the global object of security context.
+ if ((args.This() != v8::Context::GetCurrentSecurityContext()->Global()) &&
+ !V8Proxy::IsFromSameOrigin(imp->frame(), true)) {
+ return v8::Undefined();
+ }
+
+ if (!imp->frame())
+ return v8::Undefined();
+
+ Document* doc = imp->frame()->document();
+ if (!doc)
+ return v8::Undefined();
+
+ V8Proxy* proxy = V8Proxy::retrieve(imp->frame());
+ if (!proxy)
+ return v8::Undefined();
+
+ EventListener* listener =
+ proxy->FindV8EventListener(args[1], false);
+
+ if (listener) {
+ String event_type = ToWebCoreString(args[0]);
+ bool useCapture = args[2]->BooleanValue();
+ doc->removeWindowEventListener(event_type, listener, useCapture);
+ }
+
+ return v8::Undefined();
+}
+
+CALLBACK_FUNC_DECL(DOMWindowPostMessage) {
+ INC_STATS(L"DOM.DOMWindow.postMessage()");
+ DOMWindow* window = V8Proxy::FastToNativeObject<DOMWindow>(
+ V8ClassIndex::DOMWINDOW, args.Holder());
+
+ 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]);
+
+ if (try_catch.HasCaught()) return v8::Undefined();
+
+ window->postMessage(message, domain, uri, source);
+
+ return v8::Undefined();
+}
+
+
+static bool canShowModalDialogNow(const Frame* frame) {
+ // A frame can out live its page. See bug 1219613.
+ if (!frame || !frame->page())
+ return false;
+ return frame->page()->chrome()->canRunModalNow();
+}
+
+static bool allowPopUp() {
+ Frame* frame = V8Proxy::retrieveActiveFrame();
+
+ ASSERT(frame);
+ if (frame->scriptBridge()->wasRunByUserGesture()) return true;
+ Settings* settings = frame->settings();
+ return settings && settings->JavaScriptCanOpenWindowsAutomatically();
+}
+
+static HashMap<String, String> parseModalDialogFeatures(
+ const String& features_arg) {
+ HashMap<String, String> map;
+
+ Vector<String> features = features_arg.split(';');
+ Vector<String>::const_iterator end = features.end();
+ for (Vector<String>::const_iterator it = features.begin(); it != end; ++it) {
+ String s = *it;
+ int pos = s.find('=');
+ int colonPos = s.find(':');
+ if (pos >= 0 && colonPos >= 0)
+ continue; // ignore any strings that have both = and :
+ if (pos < 0)
+ pos = colonPos;
+ if (pos < 0) {
+ // null string for value means key without value
+ map.set(s.stripWhiteSpace().lower(), String());
+ } else {
+ String key = s.left(pos).stripWhiteSpace().lower();
+ String val = s.substring(pos + 1).stripWhiteSpace().lower();
+ int spacePos = val.find(' ');
+ if (spacePos != -1)
+ val = val.left(spacePos);
+ map.set(key, val);
+ }
+ }
+
+ return map;
+}
+
+
+static Frame* createWindow(Frame* opener_frame,
+ const String& url,
+ const String& frame_name,
+ const WindowFeatures& window_features,
+ v8::Local<v8::Value> dialog_args) {
+ Frame* active_frame = V8Proxy::retrieveActiveFrame();
+
+ ResourceRequest request;
+ if (active_frame)
+ request.setHTTPReferrer(active_frame->loader()->outgoingReferrer());
+ FrameLoadRequest frame_request(request, frame_name);
+
+ // FIXME: It's much better for client API if a new window starts with a URL,
+ // here where we know what URL we are going to open. Unfortunately, this code
+ // passes the empty string for the URL, but there's a reason for that.
+ // Before loading we have to set up the opener, openedByDOM,
+ // and dialogArguments values. Also, to decide whether to use the URL
+ // we currently do an allowsAccessFrom call using the window we create,
+ // which can't be done before creating it. We'd have to resolve all those
+ // issues to pass the URL instead of "".
+
+ bool created;
+ // We pass in the opener frame here so it can be used for looking up the frame
+ // name, in case the active frame is different from the opener frame, and
+ // the name references a frame relative to the opener frame, for example
+ // "_self" or "_parent".
+ Frame* new_frame = active_frame->loader()->createWindow(
+ opener_frame->loader(), frame_request, window_features, created);
+ if (!new_frame) {
+ return 0;
+ }
+
+ new_frame->loader()->setOpener(opener_frame);
+ new_frame->loader()->setOpenedByDOM();
+
+ // Set dialog arguments on the global object of the new frame.
+ if (!dialog_args.IsEmpty()) {
+ v8::Local<v8::Context> context = V8Proxy::GetContext(new_frame);
+ if (!context.IsEmpty()) {
+ v8::Context::Scope scope(context);
+ context->Global()->Set(v8::String::New("dialogArguments"), dialog_args);
+ }
+ }
+
+ 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();
+
+ if (created) {
+ new_frame->loader()->changeLocation(
+ KURL(completed_url.deprecatedString()),
+ 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,
+ active_frame->loader()->outgoingReferrer(),
+ false,
+ user_gesture);
+ }
+ }
+
+ return new_frame;
+}
+
+
+CALLBACK_FUNC_DECL(DOMWindowShowModalDialog) {
+ INC_STATS(L"DOM.DOMWindow.showModalDialog()");
+ DOMWindow* window = V8Proxy::FastToNativeObject<DOMWindow>(
+ V8ClassIndex::DOMWINDOW, args.Holder());
+ Frame* frame = window->frame();
+
+ if (!frame)
+ return v8::Undefined();
+
+ if (!canShowModalDialogNow(frame) || !allowPopUp())
+ return v8::Undefined();
+
+ String url = valueToStringWithNullOrUndefinedCheck(args[0]);
+ v8::Local<v8::Value> dialog_args = args[1];
+ String feature_args = valueToStringWithNullOrUndefinedCheck(args[2]);
+
+ const HashMap<String, String> features =
+ parseModalDialogFeatures(feature_args);
+
+ const bool trusted = false;
+
+ FloatRect screenRect = screenAvailableRect(frame->view());
+
+ WindowFeatures wargs;
+ // default here came from frame size of dialog in MacIE.
+ wargs.width = WindowFeatures::floatFeature(features, "dialogwidth", 100,
+ screenRect.width(), 620);
+ wargs.widthSet = true;
+ // default here came from frame size of dialog in MacIE.
+ wargs.height = WindowFeatures::floatFeature(features, "dialogheight", 100,
+ screenRect.height(), 450);
+ wargs.heightSet = true;
+
+ wargs.x = WindowFeatures::floatFeature(features, "dialogleft", screenRect.x(),
+ screenRect.right() - wargs.width,
+ -1);
+ wargs.xSet = wargs.x > 0;
+ wargs.y = WindowFeatures::floatFeature(features, "dialogtop", screenRect.y(),
+ screenRect.bottom() - wargs.height,
+ -1);
+ wargs.ySet = wargs.y > 0;
+
+ if (WindowFeatures::boolFeature(features, "center", true)) {
+ if (!wargs.xSet) {
+ wargs.x = screenRect.x() + (screenRect.width() - wargs.width) / 2;
+ wargs.xSet = true;
+ }
+ if (!wargs.ySet) {
+ wargs.y = screenRect.y() + (screenRect.height() - wargs.height) / 2;
+ wargs.ySet = true;
+ }
+ }
+
+ wargs.dialog = true;
+ wargs.resizable = WindowFeatures::boolFeature(features, "resizable");
+ wargs.scrollbarsVisible =
+ WindowFeatures::boolFeature(features, "scroll", true);
+ wargs.statusBarVisible =
+ WindowFeatures::boolFeature(features, "status", !trusted);
+ wargs.menuBarVisible = false;
+ wargs.toolBarVisible = false;
+ wargs.locationBarVisible = false;
+ wargs.fullscreen = false;
+
+ Frame* dialog_frame = createWindow(frame, url, "", wargs, dialog_args);
+ if (!dialog_frame)
+ return v8::Undefined();
+
+ // Hold on to the context of the dialog window long enough to retrieve the
+ // value of the return value property.
+ v8::Local<v8::Context> context = V8Proxy::GetContext(dialog_frame);
+
+ // Run the dialog.
+ dialog_frame->page()->chrome()->runModal();
+
+ // Extract the return value property from the dialog window.
+ v8::Local<v8::Value> return_value;
+ if (!context.IsEmpty()) {
+ v8::Context::Scope scope(context);
+ return_value = context->Global()->Get(v8::String::New("returnValue"));
+ }
+
+ if (!return_value.IsEmpty()) {
+ return return_value;
+ }
+
+ return v8::Undefined();
+}
+
+
+CALLBACK_FUNC_DECL(DOMWindowOpen) {
+ INC_STATS(L"DOM.DOMWindow.open()");
+ DOMWindow* parent = V8Proxy::FastToNativeObject<DOMWindow>(
+ V8ClassIndex::DOMWINDOW, args.Holder());
+ Frame* frame = parent->frame();
+ if (!frame)
+ return v8::Undefined();
+
+ // Fast check This argument with the global object of security context.
+ if ((args.This() != v8::Context::GetCurrentSecurityContext()->Global()) &&
+ !V8Proxy::IsFromSameOrigin(frame, true)) {
+ return v8::Undefined();
+ }
+
+ Frame* active_frame = V8Proxy::retrieveActiveFrame();
+ if (!active_frame)
+ return v8::Undefined();
+
+ Page* page = frame->page();
+ if (!page)
+ return v8::Undefined();
+
+ String url_string = valueToStringWithNullOrUndefinedCheck(args[0]);
+ AtomicString frame_name = (args[1]->IsUndefined() || args[1]->IsNull()) ?
+ "_blank" : AtomicString(ToWebCoreString(args[1]));
+
+ // Because FrameTree::find() returns true for empty strings, we must check
+ // for empty framenames. Otherwise, illegitimate window.open() calls with
+ // no name will pass right through the popup blocker.
+ if (!allowPopUp() &&
+ (frame_name.isEmpty() ||
+ !frame->tree()->find(frame_name))) {
+ return v8::Undefined();
+ }
+
+ // Get the target frame for the special cases of _top and _parent. In those
+ // cases, we can schedule a location change right now and return early.
+ bool top_or_parent = false;
+ if (frame_name == "_top") {
+ frame = frame->tree()->top();
+ top_or_parent = true;
+ } else if (frame_name == "_parent") {
+ if (Frame* parent = frame->tree()->parent()) {
+ frame = parent;
+ }
+ top_or_parent = true;
+ }
+ if (top_or_parent) {
+ if (!active_frame->loader()->shouldAllowNavigation(frame)) {
+ return v8::Undefined();
+ }
+
+ String completed_url;
+ if (!url_string.isEmpty()) {
+ completed_url = active_frame->document()->completeURL(url_string);
+ }
+
+ if (!completed_url.isEmpty() &&
+ (!parseURL(url_string).startsWith("javascript:", false) ||
+ JSBridge::isSafeScript(frame))) {
+ bool user_gesture = active_frame->scriptBridge()->wasRunByUserGesture();
+ frame->loader()->scheduleLocationChange(
+ completed_url,
+ active_frame->loader()->outgoingReferrer(),
+ false,
+ user_gesture);
+ }
+ return V8Proxy::ToV8Object(V8ClassIndex::DOMWINDOW, frame->domWindow());
+ }
+
+ // In the case of a named frame or a new window, we'll use the createWindow()
+ // helper.
+ WindowFeatures window_features(
+ valueToStringWithNullOrUndefinedCheck(args[2]));
+ FloatRect screen_rect = screenAvailableRect(page->mainFrame()->view());
+
+ // Set default size and location near parent window if none were specified.
+ // These may be further modified by adjustWindowRect, below.
+ if (!window_features.xSet) {
+ window_features.x = parent->screenX() - screen_rect.x() + kPopupTilePixels;
+ window_features.xSet = true;
+ }
+ if (!window_features.ySet) {
+ window_features.y = parent->screenY() - screen_rect.y() + kPopupTilePixels;
+ window_features.ySet = true;
+ }
+ if (!window_features.widthSet) {
+ window_features.width = parent->innerWidth();
+ window_features.widthSet = true;
+ }
+ if (!window_features.heightSet) {
+ window_features.height = parent->innerHeight();
+ window_features.heightSet = true;
+ }
+
+ FloatRect window_rect(window_features.x, window_features.y,
+ window_features.width, window_features.height);
+
+ // The new window's location is relative to its current screen, so shift
+ // it in case it's on a secondary monitor. See http://b/viewIssue?id=967905.
+ window_rect.move(screen_rect.x(), screen_rect.y());
+ WebCore::DOMWindow::adjustWindowRect(screen_rect, window_rect, window_rect);
+
+ // createWindow expects the location to be specified relative to the parent.
+ window_features.x = window_rect.x() - parent->screenX();
+ window_features.y = window_rect.y() - parent->screenY();
+ window_features.height = window_rect.height();
+ window_features.width = window_rect.width();
+
+ frame = createWindow(frame, url_string, frame_name,
+ window_features, v8::Local<v8::Value>());
+
+ if (!frame) return v8::Undefined();
+
+ return V8Proxy::ToV8Object(V8ClassIndex::DOMWINDOW, frame->domWindow());
+}
+
+
+INDEXED_PROPERTY_GETTER(DOMWindow) {
+ INC_STATS(L"DOM.DOMWindow.IndexedPropertyGetter");
+ v8::Handle<v8::Object> holder = V8Proxy::LookupDOMWrapper(
+ V8ClassIndex::DOMWINDOW, info.This());
+ if (holder.IsEmpty())
+ return v8::Handle<v8::Value>();
+
+ DOMWindow* window = V8Proxy::ToNativeObject<DOMWindow>(
+ V8ClassIndex::DOMWINDOW, holder);
+ if (!window)
+ return v8::Handle<v8::Value>();
+
+ Frame* frame = window->frame();
+ if (!frame)
+ return v8::Handle<v8::Value>();
+
+ Frame* child = frame->tree()->child(index);
+ if (child) {
+ return V8Proxy::ToV8Object(V8ClassIndex::DOMWINDOW, child->domWindow());
+ }
+
+ return v8::Handle<v8::Value>();
+}
+
+
+NAMED_PROPERTY_GETTER(DOMWindow) {
+ INC_STATS(L"DOM.DOMWindow.NamedPropertyGetter");
+ // The key must be a string.
+ if (!name->IsString())
+ return v8::Handle<v8::Value>();
+
+ v8::Handle<v8::Object> holder = V8Proxy::LookupDOMWrapper(
+ V8ClassIndex::DOMWINDOW, info.This());
+ if (holder.IsEmpty())
+ return v8::Handle<v8::Value>();
+
+ DOMWindow* window = V8Proxy::ToNativeObject<DOMWindow>(
+ V8ClassIndex::DOMWINDOW, holder);
+ if (!window)
+ return v8::Handle<v8::Value>();
+
+ String prop_name = ToWebCoreString(name);
+
+ Frame* frame = window->frame();
+ // window is detached from a frame.
+ if (!frame)
+ return v8::Handle<v8::Value>();
+
+ // Search sub-frames.
+ Frame* child = frame->tree()->child(prop_name);
+ if (child)
+ return V8Proxy::ToV8Object(V8ClassIndex::DOMWINDOW, child->domWindow());
+
+ // Search IDL functions defined in the prototype
+ v8::Handle<v8::Value> result =
+ holder->GetRealNamedPropertyInPrototypeChain(name);
+ if (!result.IsEmpty())
+ return result;
+
+ // Search named items in the document.
+ Document* doc = frame->document();
+ if (doc) {
+ RefPtr<HTMLCollection> items = doc->windowNamedItems(prop_name);
+ if (items->length() >= 1) {
+ if (items->length() == 1) {
+ return V8Proxy::ToV8Object(V8ClassIndex::NODE, items->firstItem());
+ } else {
+ return V8Proxy::ToV8Object(V8ClassIndex::HTMLCOLLECTION,
+ static_cast<Peerable*>(items.get()));
+ }
+ }
+ }
+
+ // Lazy initialization map keeps global properties that can be lazily
+ // initialized. The value is the code to instantiate the property.
+ // It must return the value of property after initialization.
+ static HashMap<String, String> kLazyInitMap;
+ if (kLazyInitMap.isEmpty()) {
+ kLazyInitMap.set("Image",
+ "function Image() { \
+ return document.createElement('image'); \
+ }; \
+ Image");
+ kLazyInitMap.set("Option",
+ "function Option(text, value, defaultSelected, selected) { \
+ var option = document.createElement('option'); \
+ if (text == null) return option; \
+ option.text = text; \
+ if (value == null) return option; \
+ option.value = value; \
+ if (defaultSelected == null) return option; \
+ option.defaultSelected = defaultSelected; \
+ if (selected == null) return option; \
+ option.selected = selected; \
+ return option; \
+ }; \
+ Option");
+ }
+
+ String code = kLazyInitMap.get(prop_name);
+ if (!code.isEmpty()) {
+ v8::Local<v8::Context> context = V8Proxy::GetContext(window->frame());
+ // Bail out if we cannot get the context for the frame.
+ if (context.IsEmpty()) return v8::Handle<v8::Value>();
+
+ // switch to the target object's environment.
+ v8::Context::Scope scope(context);
+
+ // Set the property name to undefined to make sure that the
+ // property exists. This is necessary because this getter
+ // might be called when evaluating 'var RangeException = value'
+ // to figure out if we have a property named 'RangeException' before
+ // we set RangeException to the new value. In that case, we will
+ // evaluate 'var RangeException = {}' and enter an infinite loop.
+ // Setting the property name to undefined on the global object
+ // ensures that we do not have to ask this getter to figure out
+ // that we have the property.
+ //
+ // TODO(ager): We probably should implement the Has method
+ // for the interceptor instead of using the default Has method
+ // that calls Get.
+ context->Global()->Set(v8String(prop_name), v8::Undefined());
+ V8Proxy* proxy = V8Proxy::retrieve(window->frame());
+ ASSERT(proxy);
+
+ v8::Local<v8::Value> result = proxy->Evaluate(prop_name, 0, code, 0);
+ if (result.IsEmpty()) return result;
+
+ return result;
+ }
+
+ return v8::Handle<v8::Value>();
+}
+
+
+NAMED_PROPERTY_DELETER(HTMLDocument) {
+ // Only handle document.all. Insert the marker object into the
+ // shadow internal field to signal that document.all is no longer
+ // shadowed.
+ String key = ToWebCoreString(name);
+ if (key == "all") {
+ ASSERT(info.Holder()->InternalFieldCount() ==
+ kHTMLDocumentInternalFieldCount);
+ v8::Local<v8::Value> marker =
+ info.Holder()->GetInternalField(kHTMLDocumentMarkerIndex);
+ info.Holder()->SetInternalField(kHTMLDocumentShadowIndex, marker);
+ return v8::True();
+ }
+ return v8::Handle<v8::Boolean>();
+}
+
+
+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.
+ String key = ToWebCoreString(name);
+ if (key == "all") {
+ ASSERT(info.Holder()->InternalFieldCount() ==
+ kHTMLDocumentInternalFieldCount);
+ info.Holder()->SetInternalField(kHTMLDocumentShadowIndex, value);
+ }
+ return v8::Handle<v8::Value>();
+}
+
+
+NAMED_PROPERTY_GETTER(HTMLDocument) {
+ INC_STATS(L"DOM.HTMLDocument.NamedPropertyGetter");
+ String 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;
+ }
+ }
+
+ HTMLDocument* imp = V8Proxy::FastToNativeObject<HTMLDocument>(
+ V8ClassIndex::HTMLDOCUMENT, info.Holder());
+
+ // Fast case for named elements that are not there.
+ if (!imp->hasNamedItem(key) && !imp->hasDocExtraNamedItem(key)) {
+ 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());
+ }
+ return V8Proxy::ToV8Object(V8ClassIndex::NODE, node);
+ }
+ return V8Proxy::ToV8Object(V8ClassIndex::HTMLCOLLECTION,
+ static_cast<Peerable*>(items.get()));
+}
+
+
+NAMED_PROPERTY_GETTER(HTMLFrameSetElement) {
+ INC_STATS(L"DOM.HTMLFrameSetElement.NamedPropertyGetter");
+ HTMLFrameSetElement* imp = V8Proxy::FastToNativeObject<HTMLFrameSetElement>(
+ V8ClassIndex::HTMLFRAMESETELEMENT, info.Holder());
+ String key = ToWebCoreString(name);
+ Node* frame = imp->children()->namedItem(key);
+ if (frame && frame->hasTagName(HTMLNames::frameTag)) {
+ 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());
+ }
+ }
+ return v8::Undefined();
+ }
+ return v8::Handle<v8::Value>();
+}
+
+
+NAMED_PROPERTY_GETTER(HTMLFormElement) {
+ INC_STATS(L"DOM.HTMLFormElement.NamedPropertyGetter");
+ HTMLFormElement* imp = V8Proxy::FastToNativeObject<HTMLFormElement>(
+ V8ClassIndex::HTMLFORMELEMENT, info.Holder());
+ String v = ToWebCoreString(name);
+
+ // Call getNamedElements twice, first time check if it has a value
+ // and let HTMLFormElement update its cache.
+ // See issue: 867404
+ {
+ Vector<RefPtr<Node> > elements;
+ imp->getNamedElements(v, elements);
+ if (elements.size() == 0)
+ return v8::Handle<v8::Value>();
+ }
+ // Second call may return different results from the first call,
+ // but if the first the size cannot be zero.
+ Vector<RefPtr<Node>> elements;
+ imp->getNamedElements(v, elements);
+ ASSERT(elements.size() != 0);
+ if (elements.size() == 1) {
+ return V8Proxy::ToV8Object(V8ClassIndex::NODE, elements.at(0).get());
+ } else {
+ NodeList* collection = new V8VectorNodeList(elements);
+ return V8Proxy::ToV8Object(V8ClassIndex::NODELIST,
+ static_cast<Peerable*>(collection));
+ }
+}
+
+
+INDEXED_PROPERTY_GETTER(NamedNodeMap) {
+ INC_STATS(L"DOM.NamedNodeMap.IndexedPropertyGetter");
+ NamedNodeMap* imp = V8Proxy::FastToNativeObject<NamedNodeMap>(
+ V8ClassIndex::NAMEDNODEMAP, info.Holder());
+ RefPtr<Node> result = imp->item(index);
+ if (!result) return v8::Handle<v8::Value>();
+
+ return V8Proxy::ToV8Object(V8ClassIndex::NODE, result.get());
+}
+
+NAMED_PROPERTY_GETTER(NamedNodeMap) {
+ INC_STATS(L"DOM.NamedNodeMap.NamedPropertyGetter");
+ // Search the prototype chain first.
+ v8::Handle<v8::Value> value =
+ info.Holder()->GetRealNamedPropertyInPrototypeChain(name);
+ if (!value.IsEmpty())
+ return value;
+
+ // Then look for IDL defined properties on the object itself.
+ if (info.Holder()->HasRealNamedCallbackProperty(name))
+ return v8::Handle<v8::Value>();
+
+ // Finally, search the DOM.
+ NamedNodeMap* imp = V8Proxy::FastToNativeObject<NamedNodeMap>(
+ V8ClassIndex::NAMEDNODEMAP, info.Holder());
+ String prop_name = ToWebCoreString(name);
+ RefPtr<Node> result = imp->getNamedItem(prop_name);
+ if (!result) return v8::Handle<v8::Value>();
+
+ return V8Proxy::ToV8Object(V8ClassIndex::NODE, result.get());
+}
+
+
+NAMED_PROPERTY_GETTER(NodeList) {
+ INC_STATS(L"DOM.NodeList.NamedPropertyGetter");
+ NodeList* list = V8Proxy::FastToNativeObject<NodeList>(
+ V8ClassIndex::NODELIST, info.Holder());
+ String prop_name = ToWebCoreString(name);
+
+ // Length property cannot be overridden.
+ if (prop_name == "length")
+ return v8::Number::New(list->length());
+
+ RefPtr<Node> result = list->itemWithName(prop_name);
+ if (result)
+ return V8Proxy::ToV8Object(V8ClassIndex::NODE, result.get());
+
+ return v8::Handle<v8::Value>();
+}
+
+
+INDEXED_PROPERTY_GETTER(HTMLFormElement) {
+ INC_STATS(L"DOM.HTMLFormElement.IndexedPropertyGetter");
+ HTMLFormElement* form = V8Proxy::FastToNativeObject<HTMLFormElement>(
+ V8ClassIndex::HTMLFORMELEMENT, info.Holder());
+
+ RefPtr<Node> result = form->elements()->item(index);
+ if (!result) return v8::Handle<v8::Value>();
+ return V8Proxy::ToV8Object(V8ClassIndex::NODE, result.get());
+}
+
+
+INDEXED_PROPERTY_GETTER(HTMLOptionsCollection) {
+ INC_STATS(L"DOM.HTMLOptionsCollection.IndexedPropertyGetter");
+ HTMLOptionsCollection* collection =
+ V8Proxy::FastToNativeObject<HTMLOptionsCollection>(
+ V8ClassIndex::HTMLOPTIONSCOLLECTION, info.Holder());
+
+ RefPtr<Node> result = collection->item(index);
+ if (!result) return v8::Handle<v8::Value>();
+
+ return V8Proxy::ToV8Object(V8ClassIndex::NODE, result.get());
+}
+
+static v8::Handle<v8::Value> OptionsCollectionSetter(uint32_t index,
+ v8::Handle<v8::Value> value, HTMLSelectElement* base) {
+ if (value->IsNull() || value->IsUndefined()) {
+ base->remove(index);
+ return value;
+ }
+
+ ExceptionCode ec = 0;
+
+ // Check that the value is an HTMLOptionElement. If not, throw a
+ // TYPE_MISMATCH_ERR DOMException.
+ if (!V8HTMLOptionElement::HasInstance(value)) {
+ V8Proxy::SetDOMException(TYPE_MISMATCH_ERR);
+ return value;
+ }
+
+ HTMLOptionElement* element = V8Proxy::FastToNativeObject<HTMLOptionElement>(
+ V8ClassIndex::HTMLOPTIONELEMENT, v8::Handle<v8::Object>::Cast(value));
+ base->setOption(index, element, ec);
+
+ V8Proxy::SetDOMException(ec);
+ return value;
+}
+
+
+INDEXED_PROPERTY_SETTER(HTMLOptionsCollection) {
+ INC_STATS(L"DOM.HTMLOptionsCollection.IndexedPropertySetter");
+ HTMLOptionsCollection* collection =
+ V8Proxy::FastToNativeObject<HTMLOptionsCollection>(
+ V8ClassIndex::HTMLOPTIONSCOLLECTION, info.Holder());
+ HTMLSelectElement* base = static_cast<HTMLSelectElement*>(collection->base());
+ return OptionsCollectionSetter(index, value, base);
+}
+
+
+INDEXED_PROPERTY_SETTER(HTMLSelectElementCollection) {
+ INC_STATS(L"DOM.HTMLSelectElementCollection.IndexedPropertySetter");
+ HTMLSelectElement* select =
+ V8Proxy::FastToNativeObject<HTMLSelectElement>(
+ V8ClassIndex::HTMLSELECTELEMENT, info.Holder());
+ return OptionsCollectionSetter(index, value, select);
+}
+
+
+// When getting properties on CSSStyleDeclarations, the name used from
+// Javascript and the actual name of the property are not the same, so
+// we have to do the following translation. The translation turns upper
+// case characters into lower case characters and inserts dashes to
+// separate words.
+//
+// Example: 'backgroundPositionY' -> 'background-position-y'
+//
+// 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();
+
+ if (pixel_or_pos_prefix)
+ *pixel_or_pos_prefix = false;
+
+ 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, '-');
+ }
+
+ return prop;
+}
+
+
+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)) {
+ return v8::Handle<v8::Value>();
+ }
+
+ // Search the style declaration.
+ CSSStyleDeclaration* imp = V8Proxy::FastToNativeObject<CSSStyleDeclaration>(
+ V8ClassIndex::CSSSTYLEDECLARATION, info.Holder());
+
+ bool pixel_or_pos;
+ String p = ToWebCoreString(name);
+ String prop = CSSPropertyName(p, &pixel_or_pos);
+
+ // Do not handle non-property names.
+ if (!CSSStyleDeclaration::isPropertyName(prop)) {
+ return v8::Handle<v8::Value>();
+ }
+
+ RefPtr<CSSValue> v = imp->getPropertyCSSValue(prop);
+ if (v) {
+ if (pixel_or_pos && v->cssValueType() == CSSValue::CSS_PRIMITIVE_VALUE) {
+ RefPtr<CSSPrimitiveValue> primitive_value =
+ static_pointer_cast<CSSPrimitiveValue>(v);
+ return v8::Number::New(
+ primitive_value->getFloatValue(CSSPrimitiveValue::CSS_PX));
+ }
+ return v8StringOrNull(v->cssText());
+ }
+
+ String result = imp->getPropertyValue(prop);
+ if (result.isNull())
+ result = ""; // convert null to empty string.
+
+ // The 'filter' attribute is made undetectable in KJS/WebKit
+ // to avoid confusion with IE's filter extension.
+ if (prop == "filter") {
+ return v8UndetectableString(result);
+ }
+ return v8String(result);
+}
+
+
+NAMED_PROPERTY_SETTER(CSSStyleDeclaration) {
+ INC_STATS(L"DOM.CSSStyleDeclaration.NamedPropertySetter");
+ CSSStyleDeclaration* imp = V8Proxy::FastToNativeObject<CSSStyleDeclaration>(
+ V8ClassIndex::CSSSTYLEDECLARATION, info.Holder());
+ String property_name = ToWebCoreString(name);
+ int ec = 0;
+
+ bool 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
+ }
+
+ String prop_value = valueToStringWithNullCheck(value);
+ if (pixel_or_pos) prop_value += "px";
+ imp->setProperty(prop, prop_value, ec);
+
+ V8Proxy::SetDOMException(ec);
+ return value;
+}
+
+
+NAMED_PROPERTY_GETTER(HTMLPlugInElement) {
+ INC_STATS(L"DOM.HTMLPlugInElement.NamedPropertyGetter");
+ HTMLPlugInElement* imp = V8Proxy::FastToNativeObject<HTMLPlugInElement>(
+ V8ClassIndex::NODE, info.Holder());
+ v8::Local<v8::Object> instance =
+ v8::Local<v8::Object>::New(imp->getInstance());
+ if (instance.IsEmpty()) return v8::Handle<v8::Object>();
+ return NPObjectGetNamedProperty(instance, name);
+}
+
+
+NAMED_PROPERTY_SETTER(HTMLPlugInElement) {
+ INC_STATS(L"DOM.HTMLPlugInElement.NamedPropertySetter");
+ HTMLPlugInElement* imp = V8Proxy::FastToNativeObject<HTMLPlugInElement>(
+ V8ClassIndex::NODE, info.Holder());
+ v8::Local<v8::Object> instance =
+ v8::Local<v8::Object>::New(imp->getInstance());
+ if (instance.IsEmpty()) {
+ return v8::Handle<v8::Value>(); // do not block the call
+ }
+
+ return NPObjectSetNamedProperty(instance, name, value);
+}
+
+
+CALLBACK_FUNC_DECL(HTMLPlugInElement) {
+ INC_STATS(L"DOM.HTMLPluginElement()");
+ return NPObjectInvokeDefaultHandler(args);
+}
+
+
+INDEXED_PROPERTY_GETTER(HTMLPlugInElement) {
+ INC_STATS(L"DOM.HTMLPlugInElement.IndexedPropertyGetter");
+ HTMLPlugInElement* imp = V8Proxy::FastToNativeObject<HTMLPlugInElement>(
+ V8ClassIndex::NODE, info.Holder());
+ v8::Local<v8::Object> instance =
+ v8::Local<v8::Object>::New(imp->getInstance());
+ if (instance.IsEmpty()) return v8::Handle<v8::Object>();
+ return NPObjectGetIndexedProperty(instance, index);
+}
+
+
+INDEXED_PROPERTY_SETTER(HTMLPlugInElement) {
+ INC_STATS(L"DOM.HTMLPlugInElement.IndexedPropertySetter");
+ HTMLPlugInElement* imp = V8Proxy::FastToNativeObject<HTMLPlugInElement>(
+ V8ClassIndex::NODE, info.Holder());
+ v8::Local<v8::Object> instance =
+ v8::Local<v8::Object>::New(imp->getInstance());
+ if (instance.IsEmpty()) {
+ return v8::Handle<v8::Value>(); // do not block the call
+ }
+
+ return NPObjectSetIndexedProperty(instance, index, value);
+}
+
+NAMED_PROPERTY_GETTER(StyleSheetList) {
+ INC_STATS(L"DOM.StyleSheetList.NamedPropertyGetter");
+ // Look for local properties first.
+ if (info.Holder()->HasRealNamedProperty(name)) {
+ return v8::Handle<v8::Value>();
+ }
+
+ // Search style sheet.
+ StyleSheetList* imp = V8Proxy::FastToNativeObject<StyleSheetList>(
+ V8ClassIndex::STYLESHEETLIST, info.Holder());
+ String key = ToWebCoreString(name);
+ HTMLStyleElement* item = imp->getNamedItem(key);
+ if (item) {
+ return V8Proxy::ToV8Object(V8ClassIndex::HTMLSTYLEELEMENT, item);
+ }
+ return v8::Handle<v8::Value>();
+}
+
+
+CALLBACK_FUNC_DECL(CSSPrimitiveValueGetRGBColorValue) {
+ INC_STATS(L"DOM.CSSPrimitiveValue.getRGBColorValue()");
+ CSSPrimitiveValue* value = V8Proxy::FastToNativeObject<CSSPrimitiveValue>(
+ V8ClassIndex::CSSPRIMITIVEVALUE, args.Holder());
+ ExceptionCode ec = 0;
+ unsigned int rgbcolor = value->getRGBColorValue(ec);
+ if (ec != 0) {
+ V8Proxy::SetDOMException(ec);
+ return v8::Handle<v8::Value>();
+ }
+ return V8Proxy::ToV8Object(V8ClassIndex::RGBCOLOR,
+ static_cast<Peerable*>(new RGBColor(rgbcolor)));
+}
+
+// Helper macro for converting v8 values into floats (expected by many of the
+// canvas functions).
+#define TO_FLOAT(a) static_cast<float>((a)->NumberValue())
+
+// TODO: SetStrokeColor and SetFillColor are similar except function names,
+// consolidate them into one.
+CALLBACK_FUNC_DECL(CanvasRenderingContext2DSetStrokeColor) {
+ INC_STATS(L"DOM.CanvasRenderingContext2D.setStrokeColor()");
+ CanvasRenderingContext2D* context =
+ V8Proxy::FastToNativeObject<CanvasRenderingContext2D>(
+ V8ClassIndex::CANVASRENDERINGCONTEXT2D, args.Holder());
+ switch (args.Length()) {
+ case 1:
+ if (args[0]->IsString()) {
+ context->setStrokeColor(ToWebCoreString(args[0]));
+ } else {
+ context->setStrokeColor(TO_FLOAT(args[0]));
+ }
+ break;
+ case 2:
+ if (args[0]->IsString()) {
+ context->setStrokeColor(ToWebCoreString(args[0]),
+ TO_FLOAT(args[1]));
+ } else {
+ context->setStrokeColor(TO_FLOAT(args[0]),
+ TO_FLOAT(args[1]));
+ }
+ break;
+ case 4:
+ context->setStrokeColor(TO_FLOAT(args[0]),
+ TO_FLOAT(args[1]),
+ TO_FLOAT(args[2]),
+ TO_FLOAT(args[3]));
+ break;
+ case 5:
+ context->setStrokeColor(TO_FLOAT(args[0]),
+ TO_FLOAT(args[1]),
+ TO_FLOAT(args[2]),
+ TO_FLOAT(args[3]),
+ TO_FLOAT(args[4]));
+ break;
+ default:
+ V8Proxy::ThrowError(V8Proxy::SYNTAX_ERROR,
+ "setStrokeColor: Invalid number of arguments");
+ break;
+ }
+ return v8::Undefined();
+}
+
+
+CALLBACK_FUNC_DECL(CanvasRenderingContext2DSetFillColor) {
+ INC_STATS(L"DOM.CanvasRenderingContext2D.steFillColor()");
+ CanvasRenderingContext2D* context =
+ V8Proxy::FastToNativeObject<CanvasRenderingContext2D>(
+ V8ClassIndex::CANVASRENDERINGCONTEXT2D, args.Holder());
+ switch (args.Length()) {
+ case 1:
+ if (args[0]->IsString()) {
+ context->setFillColor(ToWebCoreString(args[0]));
+ } else {
+ context->setFillColor(TO_FLOAT(args[0]));
+ }
+ break;
+ case 2:
+ if (args[0]->IsString()) {
+ context->setFillColor(ToWebCoreString(args[0]), TO_FLOAT(args[1]));
+ } else {
+ context->setFillColor(TO_FLOAT(args[0]), TO_FLOAT(args[1]));
+ }
+ break;
+ case 4:
+ context->setFillColor(TO_FLOAT(args[0]),
+ TO_FLOAT(args[1]),
+ TO_FLOAT(args[2]),
+ TO_FLOAT(args[3]));
+ break;
+ case 5:
+ context->setFillColor(TO_FLOAT(args[0]),
+ TO_FLOAT(args[1]),
+ TO_FLOAT(args[2]),
+ TO_FLOAT(args[3]),
+ TO_FLOAT(args[4]));
+ break;
+ default:
+ V8Proxy::ThrowError(V8Proxy::SYNTAX_ERROR,
+ "setFillColor: Invalid number of arguments");
+ break;
+ }
+ return v8::Undefined();
+}
+
+
+CALLBACK_FUNC_DECL(CanvasRenderingContext2DStrokeRect) {
+ INC_STATS(L"DOM.CanvasRenderingContext2D.strokeRect()");
+ CanvasRenderingContext2D* context =
+ V8Proxy::FastToNativeObject<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);
+ } else if (args.Length() == 4) {
+ context->strokeRect(TO_FLOAT(args[0]),
+ TO_FLOAT(args[1]),
+ TO_FLOAT(args[2]),
+ TO_FLOAT(args[3]),
+ ec);
+ } else {
+ // Should throw index error
+ ec = INDEX_SIZE_ERR;
+ }
+ if (ec != 0) {
+ V8Proxy::SetDOMException(ec);
+ return v8::Handle<v8::Value>();
+ }
+ return v8::Undefined();
+}
+
+
+CALLBACK_FUNC_DECL(CanvasRenderingContext2DSetShadow) {
+ INC_STATS(L"DOM.CanvasRenderingContext2D.setShadow()");
+ CanvasRenderingContext2D* context =
+ V8Proxy::FastToNativeObject<CanvasRenderingContext2D>(
+ V8ClassIndex::CANVASRENDERINGCONTEXT2D, args.Holder());
+
+ switch (args.Length()) {
+ case 3:
+ context->setShadow(TO_FLOAT(args[0]), TO_FLOAT(args[1]),
+ TO_FLOAT(args[2]));
+ break;
+ case 4:
+ if (args[3]->IsString())
+ context->setShadow(TO_FLOAT(args[0]), TO_FLOAT(args[1]),
+ TO_FLOAT(args[2]), ToWebCoreString(args[3]));
+ else
+ context->setShadow(TO_FLOAT(args[0]), TO_FLOAT(args[1]),
+ TO_FLOAT(args[2]), TO_FLOAT(args[3]));
+ break;
+ case 5:
+ if (args[3]->IsString())
+ context->setShadow(TO_FLOAT(args[0]), TO_FLOAT(args[1]),
+ TO_FLOAT(args[2]), ToWebCoreString(args[3]),
+ TO_FLOAT(args[4]));
+ else
+ context->setShadow(TO_FLOAT(args[0]), TO_FLOAT(args[1]),
+ TO_FLOAT(args[2]), TO_FLOAT(args[3]),
+ TO_FLOAT(args[4]));
+ break;
+ case 7:
+ context->setShadow(TO_FLOAT(args[0]), TO_FLOAT(args[1]),
+ TO_FLOAT(args[2]), TO_FLOAT(args[3]),
+ TO_FLOAT(args[4]), TO_FLOAT(args[5]),
+ TO_FLOAT(args[6]));
+ break;
+ case 8:
+ context->setShadow(TO_FLOAT(args[0]), TO_FLOAT(args[1]),
+ TO_FLOAT(args[2]), TO_FLOAT(args[3]),
+ TO_FLOAT(args[4]), TO_FLOAT(args[5]),
+ TO_FLOAT(args[6]), TO_FLOAT(args[7]));
+ break;
+ default:
+ V8Proxy::ThrowError(V8Proxy::SYNTAX_ERROR,
+ "setShadow: Invalid number of arguments");
+ break;
+ }
+
+ return v8::Undefined();
+}
+
+
+CALLBACK_FUNC_DECL(CanvasRenderingContext2DDrawImage) {
+ INC_STATS(L"DOM.CanvasRenderingContext2D.drawImage()");
+ CanvasRenderingContext2D* context =
+ V8Proxy::FastToNativeObject<CanvasRenderingContext2D>(
+ V8ClassIndex::CANVASRENDERINGCONTEXT2D, args.Holder());
+
+ v8::Handle<v8::Value> arg = args[0];
+
+ if (V8HTMLImageElement::HasInstance(arg)) {
+ ExceptionCode ec = 0;
+ HTMLImageElement* image_element =
+ V8Proxy::FastToNativeObject<HTMLImageElement>(
+ V8ClassIndex::HTMLIMAGEELEMENT, arg);
+ switch (args.Length()) {
+ case 3:
+ context->drawImage(image_element, TO_FLOAT(args[1]), TO_FLOAT(args[2]));
+ break;
+ case 5:
+ context->drawImage(image_element, TO_FLOAT(args[1]), TO_FLOAT(args[2]),
+ TO_FLOAT(args[3]), TO_FLOAT(args[4]), ec);
+ if (ec != 0) {
+ V8Proxy::SetDOMException(ec);
+ return v8::Handle<v8::Value>();
+ }
+ break;
+ case 9:
+ context->drawImage(image_element,
+ FloatRect(TO_FLOAT(args[1]), TO_FLOAT(args[2]),
+ TO_FLOAT(args[3]), TO_FLOAT(args[4])),
+ FloatRect(TO_FLOAT(args[5]), TO_FLOAT(args[6]),
+ TO_FLOAT(args[7]), TO_FLOAT(args[8])),
+ ec);
+ if (ec != 0) {
+ V8Proxy::SetDOMException(ec);
+ return v8::Handle<v8::Value>();
+ }
+ break;
+ default:
+ V8Proxy::ThrowError(V8Proxy::SYNTAX_ERROR,
+ "drawImage: Invalid number of arguments");
+ return v8::Undefined();
+ }
+ return v8::Undefined();
+ }
+
+ // HTMLCanvasElement
+ if (V8HTMLCanvasElement::HasInstance(arg)) {
+ ExceptionCode ec = 0;
+ HTMLCanvasElement* canvas_element =
+ V8Proxy::FastToNativeObject<HTMLCanvasElement>(
+ V8ClassIndex::HTMLCANVASELEMENT, arg);
+ switch (args.Length()) {
+ case 3:
+ context->drawImage(canvas_element, TO_FLOAT(args[1]), TO_FLOAT(args[2]));
+ break;
+ case 5:
+ context->drawImage(canvas_element, TO_FLOAT(args[1]), TO_FLOAT(args[2]),
+ TO_FLOAT(args[3]), TO_FLOAT(args[4]), ec);
+ if (ec != 0) {
+ V8Proxy::SetDOMException(ec);
+ return v8::Handle<v8::Value>();
+ }
+ break;
+ case 9:
+ context->drawImage(canvas_element,
+ FloatRect(TO_FLOAT(args[1]), TO_FLOAT(args[2]),
+ TO_FLOAT(args[3]), TO_FLOAT(args[4])),
+ FloatRect(TO_FLOAT(args[5]), TO_FLOAT(args[6]),
+ TO_FLOAT(args[7]), TO_FLOAT(args[8])),
+ ec);
+ if (ec != 0) {
+ V8Proxy::SetDOMException(ec);
+ return v8::Handle<v8::Value>();
+ }
+ break;
+ default:
+ V8Proxy::ThrowError(V8Proxy::SYNTAX_ERROR,
+ "drawImage: Invalid number of arguments");
+ return v8::Undefined();
+ }
+ return v8::Undefined();
+ }
+
+ V8Proxy::SetDOMException(TYPE_MISMATCH_ERR);
+ return v8::Handle<v8::Value>();
+}
+
+
+CALLBACK_FUNC_DECL(CanvasRenderingContext2DDrawImageFromRect) {
+ INC_STATS(L"DOM.CanvasRenderingContext2D.drawImageFromRect()");
+ CanvasRenderingContext2D* context =
+ V8Proxy::FastToNativeObject<CanvasRenderingContext2D>(
+ V8ClassIndex::CANVASRENDERINGCONTEXT2D, args.Holder());
+
+ v8::Handle<v8::Value> arg = args[0];
+
+ if (!V8Proxy::MaybeDOMWrapper(arg)) {
+ V8Proxy::ThrowError(V8Proxy::TYPE_ERROR,
+ "drawImageFromRect: Invalid type of arguments");
+ return v8::Undefined();
+ }
+
+ if (V8HTMLImageElement::HasInstance(arg)) {
+ HTMLImageElement* image_element =
+ V8Proxy::FastToNativeObject<HTMLImageElement>(
+ V8ClassIndex::HTMLIMAGEELEMENT, arg);
+ context->drawImageFromRect(image_element,
+ TO_FLOAT(args[1]), TO_FLOAT(args[2]),
+ TO_FLOAT(args[3]), TO_FLOAT(args[4]),
+ TO_FLOAT(args[5]), TO_FLOAT(args[6]),
+ TO_FLOAT(args[7]), TO_FLOAT(args[8]),
+ ToWebCoreString(args[9]));
+ } else {
+ V8Proxy::ThrowError(V8Proxy::TYPE_ERROR,
+ "drawImageFromRect: Invalid type of arguments");
+ }
+
+ return v8::Undefined();
+}
+
+// Remove the macro since we don't need it anymore.
+#undef TO_FLOAT
+
+CALLBACK_FUNC_DECL(CanvasRenderingContext2DCreatePattern) {
+ INC_STATS(L"DOM.CanvasRenderingContext2D.createPattern()");
+ CanvasRenderingContext2D* context =
+ V8Proxy::FastToNativeObject<CanvasRenderingContext2D>(
+ V8ClassIndex::CANVASRENDERINGCONTEXT2D, args.Holder());
+
+ v8::Handle<v8::Value> arg = args[0];
+
+ if (V8HTMLImageElement::HasInstance(arg)) {
+ HTMLImageElement* image_element =
+ V8Proxy::FastToNativeObject<HTMLImageElement>(
+ V8ClassIndex::HTMLIMAGEELEMENT, arg);
+ ExceptionCode ec = 0;
+ RefPtr<CanvasPattern> pattern =
+ context->createPattern(image_element, ToWebCoreString(args[1]), ec);
+ if (ec != 0) {
+ V8Proxy::SetDOMException(ec);
+ return v8::Handle<v8::Value>();
+ }
+ return V8Proxy::ToV8Object(V8ClassIndex::CANVASPATTERN,
+ static_cast<Peerable*>(pattern.get()));
+ }
+
+ if (V8HTMLCanvasElement::HasInstance(arg)) {
+ HTMLCanvasElement* canvas_element =
+ V8Proxy::FastToNativeObject<HTMLCanvasElement>(
+ V8ClassIndex::HTMLCANVASELEMENT, arg);
+ ExceptionCode ec = 0;
+ RefPtr<CanvasPattern> pattern =
+ context->createPattern(canvas_element, ToWebCoreString(args[1]), ec);
+ if (ec != 0) {
+ V8Proxy::SetDOMException(ec);
+ return v8::Handle<v8::Value>();
+ }
+ return V8Proxy::ToV8Object(V8ClassIndex::CANVASPATTERN,
+ static_cast<Peerable*>(pattern.get()));
+ }
+
+ V8Proxy::SetDOMException(TYPE_MISMATCH_ERR);
+ return v8::Handle<v8::Value>();
+}
+
+
+CALLBACK_FUNC_DECL(ClipboardClearData) {
+ INC_STATS(L"DOM.Clipboard.clearData()");
+ Clipboard* imp = V8Proxy::FastToNativeObject<Clipboard>(
+ V8ClassIndex::CLIPBOARD, args.Holder());
+ if (args.Length() == 0) {
+ imp->clearAllData();
+ } else {
+ String v = ToWebCoreString(args[0]);
+ imp->clearData(v);
+ }
+ return v8::Undefined();
+}
+
+
+CALLBACK_FUNC_DECL(ClipboardGetData) {
+ INC_STATS(L"DOM.Clipboard.getData()");
+ Clipboard* imp = V8Proxy::FastToNativeObject<Clipboard>(
+ V8ClassIndex::CLIPBOARD, args.Holder());
+ if (args.Length() == 1) {
+ bool success;
+ String v = ToWebCoreString(args[0]);
+ String result = imp->getData(v, success);
+ if (success) return v8String(result);
+ return v8::Undefined();
+ }
+
+ V8Proxy::ThrowError(V8Proxy::SYNTAX_ERROR,
+ "getData: Invalid number of arguments");
+
+ return v8::Undefined();
+}
+
+CALLBACK_FUNC_DECL(ClipboardSetData) {
+ INC_STATS(L"DOM.Clipboard.setData()");
+ Clipboard* imp = V8Proxy::FastToNativeObject<Clipboard>(
+ V8ClassIndex::CLIPBOARD, args.Holder());
+ if (args.Length() == 2) {
+ String type = ToWebCoreString(args[0]);
+ String data = ToWebCoreString(args[1]);
+ bool result = imp->setData(type, data);
+ return result?v8::True():v8::False();
+ }
+
+ V8Proxy::ThrowError(V8Proxy::SYNTAX_ERROR,
+ "setData: Invalid number of arguments");
+
+ return v8::Undefined();
+}
+
+
+static bool AllowSettingSrcToJavascriptURL(Element* element, String name,
+ String value) {
+ // Need to parse value as URL first in order to check its protocol.
+ // " javascript:", "java\0script:", "javascript\t:", "javascript\1:"
+ // are all parsed as "javascript:" url.
+ // When changing location in HTMLFrameElement, value is parsed as url.
+ // We must match the behavior there.
+ // See issue 804099.
+ //
+ // parseURL is defined in CSSHelper.cpp.
+ if ((element->hasTagName(HTMLNames::iframeTag) ||
+ element->hasTagName(HTMLNames::frameTag)) &&
+ equalIgnoringCase(name, "src") &&
+ parseURL(value).startsWith("javascript:", false)) {
+ HTMLFrameElementBase* frame = static_cast<HTMLFrameElementBase*>(element);
+ Node* contentDoc = frame->contentDocument();
+ if (contentDoc && !V8Proxy::CheckNodeSecurity(contentDoc))
+ return false;
+ }
+ return true;
+}
+
+
+static bool AllowSettingFrameSrcToJavascriptUrl(HTMLFrameElementBase* frame,
+ String value) {
+ // See same issue in AllowSettingSrcToJavascriptURL.
+ if (parseURL(value).startsWith("javascript:", false)) {
+ Node* contentDoc = frame->contentDocument();
+ if (contentDoc && !V8Proxy::CheckNodeSecurity(contentDoc))
+ return false;
+ }
+ return true;
+}
+
+
+CALLBACK_FUNC_DECL(ElementSetAttribute) {
+ INC_STATS(L"DOM.Element.setAttribute()");
+ Element* imp = V8Proxy::FastToNativeObject<Element>(
+ V8ClassIndex::ELEMENT, args.Holder());
+ ExceptionCode ec = 0;
+ String name = ToWebCoreString(args[0]);
+ String value = ToWebCoreString(args[1]);
+
+ if (!AllowSettingSrcToJavascriptURL(imp, name, value)) {
+ return v8::Undefined();
+ }
+
+ imp->setAttribute(name, value, ec);
+ if (ec != 0) {
+ V8Proxy::SetDOMException(ec);
+ return v8::Handle<v8::Value>();
+ }
+ return v8::Undefined();
+}
+
+
+CALLBACK_FUNC_DECL(ElementSetAttributeNode) {
+ INC_STATS(L"DOM.Element.setAttributeNode()");
+ if (!V8Attr::HasInstance(args[0])) {
+ V8Proxy::SetDOMException(TYPE_MISMATCH_ERR);
+ return v8::Handle<v8::Value>();
+ }
+
+ Attr* newAttr =
+ V8Proxy::FastToNativeObject<Attr>(V8ClassIndex::ATTR, args[0]);
+
+ ExceptionCode ec = 0;
+ Element* imp = V8Proxy::FastToNativeObject<Element>(
+ V8ClassIndex::ELEMENT, args.Holder());
+
+ if (!AllowSettingSrcToJavascriptURL(imp, newAttr->name(), newAttr->value())) {
+ return v8::Undefined();
+ }
+
+ RefPtr<Attr> result = imp->setAttributeNode(newAttr, ec);
+ if (ec != 0) {
+ V8Proxy::SetDOMException(ec);
+ return v8::Handle<v8::Value>();
+ }
+ return V8Proxy::ToV8Object(V8ClassIndex::NODE, result.get());
+}
+
+
+CALLBACK_FUNC_DECL(ElementSetAttributeNS) {
+ INC_STATS(L"DOM.Element.setAttributeNS()");
+ Element* imp = V8Proxy::FastToNativeObject<Element>(
+ V8ClassIndex::ELEMENT, args.Holder());
+ ExceptionCode ec = 0;
+ String namespaceURI = valueToStringWithNullCheck(args[0]);
+ String qualifiedName = ToWebCoreString(args[1]);
+ String value = ToWebCoreString(args[2]);
+
+ if (!AllowSettingSrcToJavascriptURL(imp, qualifiedName, value)) {
+ return v8::Undefined();
+ }
+
+ imp->setAttributeNS(namespaceURI, qualifiedName, value, ec);
+ if (ec != 0) {
+ V8Proxy::SetDOMException(ec);
+ return v8::Handle<v8::Value>();
+ }
+ return v8::Undefined();
+}
+
+
+CALLBACK_FUNC_DECL(ElementSetAttributeNodeNS) {
+ INC_STATS(L"DOM.Element.setAttributeNodeNS()");
+ if (!V8Attr::HasInstance(args[0])) {
+ V8Proxy::SetDOMException(TYPE_MISMATCH_ERR);
+ return v8::Handle<v8::Value>();
+ }
+
+ Attr* newAttr =
+ V8Proxy::FastToNativeObject<Attr>(V8ClassIndex::ATTR, args[0]);
+
+ Element* imp = V8Proxy::FastToNativeObject<Element>(
+ V8ClassIndex::ELEMENT, args.Holder());
+ ExceptionCode ec = 0;
+
+ if (!AllowSettingSrcToJavascriptURL(imp, newAttr->name(), newAttr->value())) {
+ return v8::Undefined();
+ }
+
+ RefPtr<Attr> result = imp->setAttributeNodeNS(newAttr, ec);
+ if (ec != 0) {
+ V8Proxy::SetDOMException(ec);
+ return v8::Handle<v8::Value>();
+ }
+ return V8Proxy::ToV8Object(V8ClassIndex::NODE, result.get());
+}
+
+
+ACCESSOR_SETTER(AttrValue) {
+ Attr* imp =
+ V8Proxy::FastToNativeObject<Attr>(V8ClassIndex::ATTR, info.Holder());
+ String v = valueToStringWithNullCheck(value);
+ Element* ownerElement = imp->ownerElement();
+
+ if (ownerElement &&
+ !AllowSettingSrcToJavascriptURL(ownerElement, imp->name(), v))
+ return;
+
+ ExceptionCode ec = 0;
+ imp->setValue(v, ec);
+ V8Proxy::SetDOMException(ec);
+}
+
+
+ACCESSOR_SETTER(HTMLFrameElementSrc) {
+ HTMLFrameElement* imp = V8Proxy::FastToNativeObject<HTMLFrameElement>(
+ V8ClassIndex::HTMLFRAMEELEMENT, info.Holder());
+ String v = valueToStringWithNullCheck(value);
+
+ if (!AllowSettingFrameSrcToJavascriptUrl(imp, v)) return;
+
+ imp->setSrc(v);
+}
+
+
+ACCESSOR_SETTER(HTMLFrameElementLocation) {
+ HTMLFrameElement* imp = V8Proxy::FastToNativeObject<HTMLFrameElement>(
+ V8ClassIndex::HTMLFRAMEELEMENT, info.Holder());
+ String v = valueToStringWithNullCheck(value);
+
+ if (!AllowSettingFrameSrcToJavascriptUrl(imp, v)) return;
+
+ imp->setLocation(v);
+}
+
+
+ACCESSOR_SETTER(HTMLIFrameElementSrc) {
+ HTMLIFrameElement* imp = V8Proxy::FastToNativeObject<HTMLIFrameElement>(
+ V8ClassIndex::HTMLIFRAMEELEMENT, info.Holder());
+ String v = valueToStringWithNullCheck(value);
+
+ if (!AllowSettingFrameSrcToJavascriptUrl(imp, v)) return;
+
+ imp->setSrc(v);
+}
+
+
+v8::Handle<v8::Value> V8Custom::WindowSetTimeoutImpl(const v8::Arguments& args,
+ bool single_shot) {
+ int num_arguments = args.Length();
+
+ if (num_arguments < 1) return v8::Undefined();
+
+ DOMWindow* imp = V8Proxy::FastToNativeObject<DOMWindow>(
+ V8ClassIndex::DOMWINDOW, args.Holder());
+
+ // Fast check This argument with the global object of security context.
+ if ((args.This() != v8::Context::GetCurrentSecurityContext()->Global()) &&
+ !V8Proxy::IsFromSameOrigin(imp->frame(), true)) {
+ return v8::Undefined();
+ }
+
+ v8::Handle<v8::Value> function = args[0];
+
+ int32_t timeout = 0;
+ if (num_arguments >= 2) timeout = args[1]->Int32Value();
+
+ int id;
+ if (function->IsString()) {
+ // Don't allow setting timeouts to run empty functions!
+ // (Bug 1009597)
+ WebCore::String string_function = ToWebCoreString(function);
+ if (string_function.length() == 0)
+ return v8::Undefined();
+
+ id = imp->installTimeout(new V8ScheduledAction(string_function),
+ timeout, single_shot);
+ } else if (function->IsFunction()) {
+ int param_count = num_arguments >= 2 ? num_arguments - 2 : 0;
+ v8::Local<v8::Value>* params = 0;
+ if (param_count > 0) {
+ params = new v8::Local<v8::Value>[param_count];
+ for (int i = 0; i < param_count; i++)
+ // parameters must be globalized
+ params[i] = args[i+2];
+ }
+
+ // params is passed to action, and released in action's destructor
+ ScheduledAction* action = new V8ScheduledAction(
+ v8::Handle<v8::Function>::Cast(function), param_count, params);
+
+ delete[] params;
+
+ id = imp->installTimeout(action, timeout, single_shot);
+ } else {
+ // TODO(fqian): what's the right return value if failed.
+ return v8::Undefined();
+ }
+ return v8::Integer::New(id);
+}
+
+
+CALLBACK_FUNC_DECL(DOMWindowSetTimeout) {
+ INC_STATS(L"DOM.DOMWindow.setTimeout()");
+ return WindowSetTimeoutImpl(args, true);
+}
+
+
+CALLBACK_FUNC_DECL(DOMWindowSetInterval) {
+ INC_STATS(L"DOM.DOMWindow.setInterval()");
+ return WindowSetTimeoutImpl(args, false);
+}
+
+// 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")
+// document.write() --> document.write("")
+static String WriteHelper_GetString(const v8::Arguments& args) {
+ String str = "";
+ for (int i = 0; i < args.Length(); ++i) {
+ str += ToWebCoreString(args[i]);
+ }
+ return str;
+}
+
+
+CALLBACK_FUNC_DECL(HTMLDocumentWrite) {
+ INC_STATS(L"DOM.HTMLDocument.write()");
+ HTMLDocument* imp = V8Proxy::FastToNativeObject<HTMLDocument>(
+ V8ClassIndex::HTMLDOCUMENT, args.Holder());
+ imp->write(WriteHelper_GetString(args));
+ return v8::Undefined();
+}
+
+
+CALLBACK_FUNC_DECL(HTMLDocumentWriteln) {
+ INC_STATS(L"DOM.HTMLDocument.writeln()");
+ HTMLDocument* imp = V8Proxy::FastToNativeObject<HTMLDocument>(
+ V8ClassIndex::HTMLDOCUMENT, args.Holder());
+ imp->writeln(WriteHelper_GetString(args));
+ return v8::Undefined();
+}
+
+
+CALLBACK_FUNC_DECL(HTMLDocumentOpen) {
+ INC_STATS(L"DOM.HTMLDocument.open()");
+ HTMLDocument* imp = V8Proxy::FastToNativeObject<HTMLDocument>(
+ V8ClassIndex::HTMLDOCUMENT, args.Holder());
+
+ if (args.Length() > 2) {
+ if (Frame* frame = imp->frame()) {
+ // Fetch the global object for the frame.
+ v8::Local<v8::Context> context = V8Proxy::GetContext(frame);
+ // Bail out if we cannot get the context.
+ if (context.IsEmpty()) return v8::Undefined();
+ v8::Local<v8::Object> global = context->Global();
+ // Get the open property of the global object.
+ v8::Local<v8::Value> function = global->Get(v8::String::New("open"));
+ // If the open property is not a function throw a type error.
+ if (!function->IsFunction()) {
+ V8Proxy::ThrowError(V8Proxy::TYPE_ERROR, "open is not a function");
+ return v8::Undefined();
+ }
+ // Wrap up the arguments and call the function.
+ v8::Local<v8::Value>* params = new v8::Local<v8::Value>[args.Length()];
+ for (int i = 0; i < args.Length(); i++) {
+ params[i] = args[i];
+ }
+
+ V8Proxy* proxy = V8Proxy::retrieve(frame);
+ ASSERT(proxy);
+
+ v8::Local<v8::Value> result =
+ proxy->CallFunction(v8::Local<v8::Function>::Cast(function),
+ global, args.Length(), params);
+ delete[] params;
+ return result;
+ }
+ }
+
+ imp->open();
+ return v8::Undefined();
+}
+
+
+CALLBACK_FUNC_DECL(HTMLDocumentClear) {
+ INC_STATS(L"DOM.HTMLDocument.clear()");
+ // Do nothing (unimplemented)
+
+ // KJS's bindings do do the same thing in JSHTMLDocument::clear().
+ // Invoking HTMLDocument::clear() can cause a crash, since it
+ // deletes the document's tokenizer while it may still be in use.
+ // See b:1055485 for details.
+ return v8::Undefined();
+}
+
+
+CALLBACK_FUNC_DECL(DocumentEvaluate) {
+ INC_STATS(L"DOM.Document.evaluate()");
+
+ Document* imp = V8Proxy::FastToNativeObject<Document>(
+ V8ClassIndex::DOCUMENT, args.Holder());
+ ExceptionCode ec = 0;
+ String expression = ToWebCoreString(args[0]);
+ Node* contextNode = NULL;
+ if (V8Node::HasInstance(args[1])) {
+ contextNode =
+ V8Proxy::FastToNativeObject<Node>(V8ClassIndex::NODE, args[1]);
+ }
+ // Find the XPath
+ XPathNSResolver* resolver = NULL;
+ if (V8XPathNSResolver::HasInstance(args[2])) {
+ resolver = V8Proxy::FastToNativeObject<XPathNSResolver>(
+ V8ClassIndex::XPATHNSRESOLVER, args[2]);
+ } else if (args[2]->IsObject()) {
+ v8::Handle<v8::Object> obj = args[2]->ToObject();
+ resolver = new JSXPathNSResolver(obj);
+ } else if (!args[2]->IsNull() && !args[2]->IsUndefined()) {
+ V8Proxy::SetDOMException(TYPE_MISMATCH_ERR);
+ return v8::Handle<v8::Value>();
+ }
+ int type = ToInt32(args[3]);
+ XPathResult* inResult = NULL;
+ if (V8XPathResult::HasInstance(args[4])) {
+ inResult = V8Proxy::FastToNativeObject<XPathResult>(
+ V8ClassIndex::XPATHRESULT, args[4]);
+ }
+ RefPtr<XPathResult> result =
+ imp->evaluate(expression, contextNode, resolver, type, inResult, ec);
+ if (ec != 0) {
+ V8Proxy::SetDOMException(ec);
+ return v8::Handle<v8::Value>();
+ }
+ return V8Proxy::ToV8Object(V8ClassIndex::XPATHRESULT,
+ static_cast<Peerable*>(result.get()));
+}
+
+
+static bool IsAscii(const String& str) {
+ for (size_t i = 0; i < str.length(); i++) {
+ if (str[i] > 0xFF)
+ return false;
+ }
+ return true;
+}
+
+
+static v8::Handle<v8::Value> Base64Convert(const String& str, bool encode) {
+ if (!IsAscii(str)) {
+ V8Proxy::SetDOMException(INVALID_CHARACTER_ERR);
+ return v8::Handle<v8::Value>();
+ }
+
+ Vector<char> in(str.length());
+ for (size_t i = 0; i < str.length(); i++) {
+ in[i] = static_cast<char>(str[i]);
+ }
+ Vector<char> out;
+
+ if (encode) {
+ base64Encode(in, out);
+ } else {
+ if (!base64Decode(in, out)) {
+ V8Proxy::ThrowError(V8Proxy::GENERAL_ERROR, "Cannot decode base64");
+ return v8::Undefined();
+ }
+ }
+
+ return v8String(String(out.data(), out.size()));
+}
+
+
+CALLBACK_FUNC_DECL(DOMWindowAtob) {
+ INC_STATS(L"DOM.DOMWindow.atob()");
+ DOMWindow* imp = V8Proxy::FastToNativeObject<DOMWindow>(
+ V8ClassIndex::DOMWINDOW, args.Holder());
+
+ // Fast check This argument with the global object of security context.
+ if ((args.This() != v8::Context::GetCurrentSecurityContext()->Global()) &&
+ !V8Proxy::IsFromSameOrigin(imp->frame(), true)) {
+ return v8::Undefined();
+ }
+
+ if (args.Length() < 1) {
+ V8Proxy::ThrowError(V8Proxy::SYNTAX_ERROR, "Not enough arguments");
+ return v8::Undefined();
+ }
+
+ if (args[0]->IsNull()) return v8String("");
+
+ String str = ToWebCoreString(args[0]);
+ return Base64Convert(str, false);
+}
+
+
+CALLBACK_FUNC_DECL(DOMWindowBtoa) {
+ INC_STATS(L"DOM.DOMWindow.btoa()");
+ DOMWindow* imp = V8Proxy::FastToNativeObject<DOMWindow>(
+ V8ClassIndex::DOMWINDOW, args.Holder());
+
+ // Fast check This argument with the global object of security context.
+ if ((args.This() != v8::Context::GetCurrentSecurityContext()->Global()) &&
+ !V8Proxy::IsFromSameOrigin(imp->frame(), true)) {
+ return v8::Undefined();
+ }
+
+ if (args.Length() < 1) {
+ V8Proxy::ThrowError(V8Proxy::SYNTAX_ERROR, "Not enough arguments");
+ return v8::Undefined();
+ }
+
+ if (args[0]->IsNull()) return v8String("");
+
+ String str = ToWebCoreString(args[0]);
+ 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(DOMWindowNOP) {
+ INC_STATS(L"DOM.DOMWindow.nop()");
+ return v8::Undefined();
+}
+
+
+CALLBACK_FUNC_DECL(EventTargetNodeAddEventListener) {
+ INC_STATS(L"DOM.EventTargetNode.addEventListener()");
+ EventTargetNode* node = V8Proxy::FastToNativeObject<EventTargetNode>(
+ V8ClassIndex::EVENTTARGETNODE, args.Holder());
+
+ V8Proxy* proxy = V8Proxy::retrieve(node->document()->frame());
+ if (!proxy)
+ return v8::Undefined();
+
+ EventListener* listener =
+ proxy->FindOrCreateV8EventListener(args[1], false);
+ if (listener) {
+ String type = ToWebCoreString(args[0]);
+ bool useCapture = args[2]->BooleanValue();
+ node->addEventListener(type, listener, useCapture);
+ }
+ return v8::Undefined();
+}
+
+
+CALLBACK_FUNC_DECL(EventTargetNodeRemoveEventListener) {
+ INC_STATS(L"DOM.EventTargetNode.removeEventListener()");
+ EventTargetNode* node = V8Proxy::FastToNativeObject<EventTargetNode>(
+ V8ClassIndex::EVENTTARGETNODE, args.Holder());
+
+ V8Proxy* proxy = V8Proxy::retrieve(node->document()->frame());
+ // It is possbile that the owner document of the node is detached
+ // from the frame, return immediately in this case.
+ // See issue 878909
+ if (!proxy)
+ return v8::Undefined();
+
+ EventListener* listener =
+ proxy->FindV8EventListener(args[1], false);
+ if (listener) {
+ String type = ToWebCoreString(args[0]);
+ bool useCapture = args[2]->BooleanValue();
+ node->removeEventListener(type, listener, useCapture);
+ }
+
+ return v8::Undefined();
+}
+
+
+// ------------------------------------------------------------------
+// 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);
+ int last_internal_field_index = xhr->InternalFieldCount() - 1;
+ v8::Local<v8::Value> cache = xhr->GetInternalField(last_internal_field_index);
+ if (cache->IsNull() || cache->IsUndefined()) {
+ cache = v8::Array::New();
+ xhr->SetInternalField(last_internal_field_index, 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);
+ int last_internal_field_index = xhr->InternalFieldCount() - 1;
+ v8::Local<v8::Value> cache = xhr->GetInternalField(last_internal_field_index);
+ 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::FastToNativeObject<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::FastToNativeObject<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::FastToNativeObject<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::FastToNativeObject<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::FastToNativeObject<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::FastToNativeObject<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::ToNativeObject<Document>(V8ClassIndex::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::FastToNativeObject<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::FastToNativeObject<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::FastToNativeObject<XMLHttpRequest>(
+ V8ClassIndex::XMLHTTPREQUEST, args.Holder());
+ String value = ToWebCoreString(args[0]);
+ imp->overrideMIMEType(value);
+ return v8::Undefined();
+}
+
+CALLBACK_FUNC_DECL(TreeWalkerParentNode) {
+ INC_STATS(L"DOM.TreeWalker.parentNode()");
+ TreeWalker* imp = V8Proxy::FastToNativeObject<TreeWalker>(
+ V8ClassIndex::TREEWALKER, args.Holder());
+ return V8Proxy::ToV8Object(V8ClassIndex::NODE, imp->parentNode());
+}
+
+CALLBACK_FUNC_DECL(TreeWalkerFirstChild) {
+ INC_STATS(L"DOM.TreeWalker.firstChild()");
+ TreeWalker* imp = V8Proxy::FastToNativeObject<TreeWalker>(
+ V8ClassIndex::TREEWALKER, args.Holder());
+ return V8Proxy::ToV8Object(V8ClassIndex::NODE, imp->firstChild());
+}
+
+CALLBACK_FUNC_DECL(TreeWalkerLastChild) {
+ INC_STATS(L"DOM.TreeWalker.lastChild()");
+ TreeWalker* imp = V8Proxy::FastToNativeObject<TreeWalker>(
+ V8ClassIndex::TREEWALKER, args.Holder());
+ return V8Proxy::ToV8Object(V8ClassIndex::NODE, imp->lastChild());
+}
+
+CALLBACK_FUNC_DECL(TreeWalkerNextNode) {
+ INC_STATS(L"DOM.TreeWalker.nextNode()");
+ TreeWalker* imp = V8Proxy::FastToNativeObject<TreeWalker>(
+ V8ClassIndex::TREEWALKER, args.Holder());
+ return V8Proxy::ToV8Object(V8ClassIndex::NODE, imp->nextNode());
+}
+
+CALLBACK_FUNC_DECL(TreeWalkerPreviousNode) {
+ INC_STATS(L"DOM.TreeWalker.previousNode()");
+ TreeWalker* imp = V8Proxy::FastToNativeObject<TreeWalker>(
+ V8ClassIndex::TREEWALKER, args.Holder());
+ return V8Proxy::ToV8Object(V8ClassIndex::NODE, imp->previousNode());
+}
+
+CALLBACK_FUNC_DECL(TreeWalkerNextSibling) {
+ INC_STATS(L"DOM.TreeWalker.nextSibling()");
+ TreeWalker* imp = V8Proxy::FastToNativeObject<TreeWalker>(
+ V8ClassIndex::TREEWALKER, args.Holder());
+ return V8Proxy::ToV8Object(V8ClassIndex::NODE, imp->nextSibling());
+}
+
+CALLBACK_FUNC_DECL(TreeWalkerPreviousSibling) {
+ INC_STATS(L"DOM.TreeWalker.previousSibling()");
+ TreeWalker* imp = V8Proxy::FastToNativeObject<TreeWalker>(
+ V8ClassIndex::TREEWALKER, args.Holder());
+ return V8Proxy::ToV8Object(V8ClassIndex::NODE, imp->previousSibling());
+}
+
+CALLBACK_FUNC_DECL(NodeIteratorNextNode) {
+ INC_STATS(L"DOM.NodeIterator.nextNode()");
+ NodeIterator* imp = V8Proxy::FastToNativeObject<NodeIterator>(
+ V8ClassIndex::NODEITERATOR, args.Holder());
+ ExceptionCode ec = 0;
+ return V8Proxy::ToV8Object(V8ClassIndex::NODE, imp->nextNode(ec));
+}
+
+CALLBACK_FUNC_DECL(NodeIteratorPreviousNode) {
+ INC_STATS(L"DOM.NodeIterator.previousNode()");
+ NodeIterator* imp = V8Proxy::FastToNativeObject<NodeIterator>(
+ V8ClassIndex::NODEITERATOR, args.Holder());
+ ExceptionCode ec = 0;
+ return V8Proxy::ToV8Object(V8ClassIndex::NODE, imp->previousNode(ec));
+}
+
+CALLBACK_FUNC_DECL(NodeFilterAcceptNode) {
+ INC_STATS(L"DOM.NodeFilter.acceptNode()");
+ NodeFilter* imp = V8Proxy::FastToNativeObject<NodeFilter>(
+ V8ClassIndex::NODEFILTER, args.Holder());
+ Node* node = V8Proxy::FastToNativeObject<Node>(V8ClassIndex::NODE, args[0]);
+ return v8::Local<v8::Integer>(v8::Integer::New(imp->acceptNode(node)));
+}
+
+ACCESSOR_SETTER(DOMWindowEventHandler) {
+ v8::Handle<v8::Object> holder = V8Proxy::LookupDOMWrapper(
+ V8ClassIndex::DOMWINDOW, info.This());
+ if (holder.IsEmpty())
+ return;
+
+ DOMWindow* imp = V8Proxy::FastToNativeObject<DOMWindow>(
+ V8ClassIndex::DOMWINDOW, holder);
+ if (!imp->frame())
+ return;
+
+ Document* doc = imp->frame()->document();
+ if (!doc)
+ return;
+
+ // Name starts with 'on', remove them.
+ String key = ToWebCoreString(name);
+ ASSERT(key.startsWith("on"));
+ String event_type = key.substring(2);
+
+ if (value->IsNull()) {
+ // Clear the event listener
+ doc->removeHTMLWindowEventListener(event_type);
+ } else {
+ V8Proxy* proxy = V8Proxy::retrieve(imp->frame());
+ if (!proxy)
+ return;
+
+ EventListener* listener =
+ proxy->FindOrCreateV8EventListener(value, true);
+ if (listener) {
+ doc->setHTMLWindowEventListener(event_type, listener);
+ }
+ }
+}
+
+
+ACCESSOR_GETTER(DOMWindowEventHandler) {
+ v8::Handle<v8::Object> holder = V8Proxy::LookupDOMWrapper(
+ V8ClassIndex::DOMWINDOW, info.This());
+ if (holder.IsEmpty())
+ return v8::Undefined();
+
+ DOMWindow* imp = V8Proxy::FastToNativeObject<DOMWindow>(
+ V8ClassIndex::DOMWINDOW, holder);
+ if (!imp->frame())
+ return v8::Undefined();
+
+ Document* doc = imp->frame()->document();
+ if (!doc)
+ return v8::Undefined();
+
+ // Name starts with 'on', remove them.
+ String key = ToWebCoreString(name);
+ ASSERT(key.startsWith("on"));
+ String event_type = key.substring(2);
+
+ EventListener* listener = doc->getHTMLWindowEventListener(event_type);
+ return V8Proxy::EventListenerToV8Object(listener);
+}
+
+
+ACCESSOR_SETTER(ElementEventHandler) {
+ EventTargetNode* node = V8Proxy::FastToNativeObject<EventTargetNode>(
+ V8ClassIndex::EVENTTARGETNODE, info.Holder());
+
+ // Name starts with 'on', remove them.
+ String key = ToWebCoreString(name);
+ ASSERT(key.startsWith("on"));
+ String event_type = key.substring(2);
+
+ // Set handler if the value is a function. Otherwise, clear the
+ // event handler.
+ if (value->IsFunction()) {
+ V8Proxy* proxy = V8Proxy::retrieve(node->document()->frame());
+ // the document might be created using createDocument,
+ // which does not have a frame, use the active frame
+ if (!proxy)
+ proxy = V8Proxy::retrieve(V8Proxy::retrieveActiveFrame());
+ if (!proxy)
+ return;
+
+ EventListener* listener =
+ proxy->FindOrCreateV8EventListener(value, true);
+ if (listener) {
+ node->setHTMLEventListener(event_type, listener);
+ }
+ } else {
+ node->removeHTMLEventListener(event_type);
+ }
+}
+
+
+ACCESSOR_GETTER(ElementEventHandler) {
+ EventTargetNode* node = V8Proxy::FastToNativeObject<EventTargetNode>(
+ V8ClassIndex::EVENTTARGETNODE, info.Holder());
+
+ // Name starts with 'on', remove them.
+ String key = ToWebCoreString(name);
+ ASSERT(key.startsWith("on"));
+ String event_type = key.substring(2);
+
+ EventListener* listener = node->getHTMLEventListener(event_type);
+ return V8Proxy::EventListenerToV8Object(listener);
+}
+
+
+ACCESSOR_SETTER(HTMLOptionsCollectionLength) {
+ HTMLOptionsCollection* imp =
+ V8Proxy::FastToNativeObject<HTMLOptionsCollection>(
+ V8ClassIndex::HTMLOPTIONSCOLLECTION, info.Holder());
+ double v = value->NumberValue();
+ unsigned newLength = 0;
+ ExceptionCode ec = 0;
+ if (!isnan(v) && !isinf(v)) {
+ if (v < 0.0) {
+ ec = INDEX_SIZE_ERR;
+ } else if (v > static_cast<double>(UINT_MAX)) {
+ newLength = UINT_MAX;
+ } else {
+ newLength = static_cast<unsigned>(v);
+ }
+ }
+ if (!ec) imp->setLength(value->Uint32Value(), ec);
+ V8Proxy::SetDOMException(ec);
+}
+
+#if ENABLE(SVG)
+CALLBACK_FUNC_DECL(SVGMatrixInverse) {
+ INC_STATS(L"DOM.SVGMatrix.inverse()");
+ AffineTransform imp =
+ *V8Proxy::FastToNativeObject<V8SVGPODTypeWrapper<AffineTransform> >(
+ V8ClassIndex::SVGMATRIX, args.Holder());
+ ExceptionCode ec = 0;
+ AffineTransform result = imp.inverse();
+ if (!imp.isInvertible()) {
+ ec = SVGException::SVG_MATRIX_NOT_INVERTABLE;
+ }
+ if (ec != 0) {
+ V8Proxy::SetDOMException(ec);
+ return v8::Handle<v8::Value>();
+ }
+
+ Peerable* peer = static_cast<Peerable*>(
+ new V8SVGPODTypeWrapperCreatorReadOnly<AffineTransform>(result));
+ return V8Proxy::ToV8Object(V8ClassIndex::SVGMATRIX, peer);
+}
+
+CALLBACK_FUNC_DECL(SVGMatrixRotateFromVector) {
+ INC_STATS(L"DOM.SVGMatrix.rotateFromVector()");
+ AffineTransform imp =
+ *V8Proxy::FastToNativeObject<V8SVGPODTypeWrapper<AffineTransform> >(
+ V8ClassIndex::SVGMATRIX, args.Holder());
+ ExceptionCode ec = 0;
+ float x = static_cast<float>(args[0]->NumberValue());
+ float y = static_cast<float>(args[1]->NumberValue());
+ AffineTransform result = imp;
+ result.rotateFromVector(x, y);
+ if (x == 0.0 || y == 0.0) {
+ ec = SVGException::SVG_INVALID_VALUE_ERR;
+ }
+ if (ec != 0) {
+ V8Proxy::SetDOMException(ec);
+ return v8::Handle<v8::Value>();
+ }
+
+ Peerable* peer = static_cast<Peerable*>(
+ new V8SVGPODTypeWrapperCreatorReadOnly<AffineTransform>(result));
+ return V8Proxy::ToV8Object(V8ClassIndex::SVGMATRIX, peer);
+}
+
+#endif // ENABLE(SVG)
+
+// --------------- Security Checks -------------------------
+NAMED_ACCESS_CHECK(DOMWindow) {
+ ASSERT(V8ClassIndex::ToWrapperType(data) == V8ClassIndex::DOMWINDOW);
+ v8::Handle<v8::Value> window = host->GetPrototype();
+ DOMWindow* target_win =
+ V8Proxy::ToNativeObject<DOMWindow>(V8ClassIndex::DOMWINDOW, window);
+
+ ASSERT(target_win);
+
+ Frame* target = target_win->frame();
+ if (!target)
+ return false;
+
+ if (key->IsString()) {
+ String name = ToWebCoreString(key);
+
+ // Allow access of GET and HAS if index is a subframe.
+ if ((type == v8::ACCESS_GET || type == v8::ACCESS_HAS) &&
+ target->tree()->child(name)) {
+ return true;
+ }
+ }
+
+ return V8Proxy::CanAccess(target);
+}
+
+
+INDEXED_ACCESS_CHECK(DOMWindow) {
+ ASSERT(V8ClassIndex::ToWrapperType(data) == V8ClassIndex::DOMWINDOW);
+ v8::Handle<v8::Value> window = host->GetPrototype();
+ DOMWindow* target_win =
+ V8Proxy::ToNativeObject<DOMWindow>(V8ClassIndex::DOMWINDOW, window);
+
+ ASSERT(target_win);
+
+ Frame* target = target_win->frame();
+ if (!target)
+ return false;
+
+ // Allow access of GET and HAS if index is a subframe.
+ if ((type == v8::ACCESS_GET || type == v8::ACCESS_HAS) &&
+ target->tree()->child(index)) {
+ return true;
+ }
+
+ return V8Proxy::CanAccess(target);
+}
+
+
+INDEXED_ACCESS_CHECK(History) {
+ ASSERT(V8ClassIndex::ToWrapperType(data) == V8ClassIndex::HISTORY);
+ // Only allow same origin access
+ History* imp =
+ V8Proxy::FastToNativeObject<History>(V8ClassIndex::HISTORY, host);
+ return V8Proxy::IsFromSameOrigin(imp->frame(), false);
+}
+
+
+NAMED_ACCESS_CHECK(History) {
+ ASSERT(V8ClassIndex::ToWrapperType(data) == V8ClassIndex::HISTORY);
+ // Only allow same origin access
+ History* imp =
+ V8Proxy::FastToNativeObject<History>(V8ClassIndex::HISTORY, host);
+ return V8Proxy::IsFromSameOrigin(imp->frame(), false);
+}
+
+
+INDEXED_ACCESS_CHECK(Location) {
+ ASSERT(V8ClassIndex::ToWrapperType(data) == V8ClassIndex::LOCATION);
+ // Only allow same origin access
+ Location* imp =
+ V8Proxy::FastToNativeObject<Location>(V8ClassIndex::LOCATION, host);
+ return V8Proxy::IsFromSameOrigin(imp->frame(), false);
+}
+
+
+NAMED_ACCESS_CHECK(Location) {
+ ASSERT(V8ClassIndex::ToWrapperType(data) == V8ClassIndex::LOCATION);
+ // Only allow same origin access
+ Location* imp =
+ V8Proxy::FastToNativeObject<Location>(V8ClassIndex::LOCATION, host);
+ return V8Proxy::IsFromSameOrigin(imp->frame(), false);
+}
+
+
+#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
+#undef INDEXED_PROPERTY_SETTER
+
+
+// static
+Frame* V8Custom::GetTargetFrame(v8::Local<v8::Object> host,
+ v8::Local<v8::Value> data) {
+ Frame* target = 0;
+ switch (V8ClassIndex::ToWrapperType(data)) {
+ case V8ClassIndex::DOMWINDOW: {
+ v8::Handle<v8::Value> window = host->GetPrototype();
+ DOMWindow* target_win =
+ V8Proxy::ToNativeObject<DOMWindow>(V8ClassIndex::DOMWINDOW, window);
+ target = target_win->frame();
+ break;
+ }
+ case V8ClassIndex::LOCATION: {
+ History* imp =
+ V8Proxy::FastToNativeObject<History>(V8ClassIndex::HISTORY, host);
+ target = imp->frame();
+ break;
+ }
+ case V8ClassIndex::HISTORY: {
+ Location* imp =
+ V8Proxy::FastToNativeObject<Location>(V8ClassIndex::LOCATION, host);
+ target = imp->frame();
+ break;
+ }
+ }
+ return target;
+}
+
+#if ENABLE(SVG)
+V8ClassIndex::V8WrapperType V8Custom::DowncastSVGPathSeg(void* path_seg) {
+ WebCore::SVGPathSeg *real_path_seg =
+ reinterpret_cast<WebCore::SVGPathSeg*>(path_seg);
+
+ switch (real_path_seg->pathSegType()) {
+#define MAKE_CASE(svg_val, v8_val) \
+ case WebCore::SVGPathSeg::svg_val: \
+ return V8ClassIndex::v8_val;
+
+MAKE_CASE(PATHSEG_CLOSEPATH, SVGPATHSEGCLOSEPATH)
+MAKE_CASE(PATHSEG_MOVETO_ABS, SVGPATHSEGMOVETOABS)
+MAKE_CASE(PATHSEG_MOVETO_REL, SVGPATHSEGMOVETOREL)
+MAKE_CASE(PATHSEG_LINETO_ABS, SVGPATHSEGLINETOABS)
+MAKE_CASE(PATHSEG_LINETO_REL, SVGPATHSEGLINETOREL)
+MAKE_CASE(PATHSEG_CURVETO_CUBIC_ABS, SVGPATHSEGCURVETOCUBICABS)
+MAKE_CASE(PATHSEG_CURVETO_CUBIC_REL, SVGPATHSEGCURVETOCUBICREL)
+MAKE_CASE(PATHSEG_CURVETO_QUADRATIC_ABS, SVGPATHSEGCURVETOQUADRATICABS)
+MAKE_CASE(PATHSEG_CURVETO_QUADRATIC_REL, SVGPATHSEGCURVETOQUADRATICREL)
+MAKE_CASE(PATHSEG_ARC_ABS, SVGPATHSEGARCABS)
+MAKE_CASE(PATHSEG_ARC_REL, SVGPATHSEGARCREL)
+MAKE_CASE(PATHSEG_LINETO_HORIZONTAL_ABS, SVGPATHSEGLINETOHORIZONTALABS)
+MAKE_CASE(PATHSEG_LINETO_HORIZONTAL_REL, SVGPATHSEGLINETOHORIZONTALREL)
+MAKE_CASE(PATHSEG_LINETO_VERTICAL_ABS, SVGPATHSEGLINETOVERTICALABS)
+MAKE_CASE(PATHSEG_LINETO_VERTICAL_REL, SVGPATHSEGLINETOVERTICALREL)
+MAKE_CASE(PATHSEG_CURVETO_CUBIC_SMOOTH_ABS, SVGPATHSEGCURVETOCUBICSMOOTHABS)
+MAKE_CASE(PATHSEG_CURVETO_CUBIC_SMOOTH_REL, SVGPATHSEGCURVETOCUBICSMOOTHREL)
+MAKE_CASE(PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS, \
+ SVGPATHSEGCURVETOQUADRATICSMOOTHABS)
+MAKE_CASE(PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL, \
+ SVGPATHSEGCURVETOQUADRATICSMOOTHREL)
+
+#undef MAKE_CASE
+
+ default:
+ return V8ClassIndex::INVALID_CLASS_INDEX;
+ }
+}
+
+#endif // ENABLE(SVG)
+
+} // namespace WebCore
diff --git a/webkit/port/bindings/v8/v8_custom.h b/webkit/port/bindings/v8/v8_custom.h
new file mode 100644
index 0000000..6b94f81
--- /dev/null
+++ b/webkit/port/bindings/v8/v8_custom.h
@@ -0,0 +1,459 @@
+// Copyright 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.
+
+#ifndef V8_CUSTOM_H__
+#define V8_CUSTOM_H__
+
+#include <v8.h>
+
+struct NPObject;
+
+namespace WebCore {
+
+class Frame;
+class V8Proxy;
+class String;
+class HTMLCollection;
+
+class V8Custom {
+ public:
+
+ // Constants.
+ static const int kDefaultWrapperInternalFieldCount = 2;
+ static const int kDocumentMinimumInternalFieldCount = 3;
+ static const int kDocumentImplementationIndex = 2;
+ static const int kHTMLDocumentInternalFieldCount = 5;
+ static const int kHTMLDocumentMarkerIndex = 3;
+ static const int kHTMLDocumentShadowIndex = 4;
+
+#define DECLARE_PROPERTY_ACCESSOR_GETTER(NAME) \
+static v8::Handle<v8::Value> v8##NAME##AccessorGetter(\
+ v8::Local<v8::String> name, const v8::AccessorInfo& info);
+
+#define DECLARE_PROPERTY_ACCESSOR_SETTER(NAME) \
+static void v8##NAME##AccessorSetter(v8::Local<v8::String> name, \
+ v8::Local<v8::Value> value, \
+ const v8::AccessorInfo& info);
+
+#define DECLARE_PROPERTY_ACCESSOR(NAME) \
+ DECLARE_PROPERTY_ACCESSOR_GETTER(NAME) \
+ DECLARE_PROPERTY_ACCESSOR_SETTER(NAME)
+
+
+#define DECLARE_NAMED_PROPERTY_GETTER(NAME) \
+static v8::Handle<v8::Value> v8##NAME##NamedPropertyGetter(\
+ v8::Local<v8::String> name, const v8::AccessorInfo& info);
+
+#define DECLARE_NAMED_PROPERTY_SETTER(NAME) \
+static v8::Handle<v8::Value> v8##NAME##NamedPropertySetter(\
+ v8::Local<v8::String> name, \
+ v8::Local<v8::Value> value, \
+ const v8::AccessorInfo& info);
+
+#define DECLARE_NAMED_PROPERTY_DELETER(NAME) \
+static v8::Handle<v8::Boolean> v8##NAME##NamedPropertyDeleter(\
+ v8::Local<v8::String> name, const v8::AccessorInfo& info);
+
+#define USE_NAMED_PROPERTY_GETTER(NAME) \
+ V8Custom::v8##NAME##NamedPropertyGetter
+
+#define USE_NAMED_PROPERTY_SETTER(NAME) \
+ V8Custom::v8##NAME##NamedPropertySetter
+
+#define USE_NAMED_PROPERTY_DELETER(NAME) \
+ V8Custom::v8##NAME##NamedPropertyDeleter
+
+#define DECLARE_INDEXED_PROPERTY_GETTER(NAME) \
+static v8::Handle<v8::Value> v8##NAME##IndexedPropertyGetter(\
+ uint32_t index, const v8::AccessorInfo& info);
+
+#define DECLARE_INDEXED_PROPERTY_SETTER(NAME) \
+static v8::Handle<v8::Value> v8##NAME##IndexedPropertySetter(\
+ uint32_t index, v8::Local<v8::Value> value, const v8::AccessorInfo& info);
+
+#define DECLARE_INDEXED_PROPERTY_DELETER(NAME) \
+static v8::Handle<v8::Boolean> v8##NAME##IndexedPropertyDeleter(\
+ uint32_t index, const v8::AccessorInfo& info);
+
+#define USE_INDEXED_PROPERTY_GETTER(NAME) \
+ V8Custom::v8##NAME##IndexedPropertyGetter
+
+#define USE_INDEXED_PROPERTY_SETTER(NAME) \
+ V8Custom::v8##NAME##IndexedPropertySetter
+
+#define USE_INDEXED_PROPERTY_DELETER(NAME) \
+ V8Custom::v8##NAME##IndexedPropertyDeleter
+
+#define DECLARE_CALLBACK(NAME) \
+static v8::Handle<v8::Value> v8##NAME##Callback(const v8::Arguments& args);
+
+#define USE_CALLBACK(NAME) \
+ V8Custom::v8##NAME##Callback
+
+#define DECLARE_NAMED_ACCESS_CHECK(NAME) \
+static bool v8##NAME##NamedSecurityCheck(v8::Local<v8::Object> host, \
+ v8::Local<v8::Value> key, \
+ v8::AccessType type, \
+ v8::Local<v8::Value> data);
+
+#define DECLARE_INDEXED_ACCESS_CHECK(NAME) \
+static bool v8##NAME##IndexedSecurityCheck(v8::Local<v8::Object> host, \
+ uint32_t index, \
+ v8::AccessType type, \
+ v8::Local<v8::Value> data);
+
+DECLARE_PROPERTY_ACCESSOR(CanvasRenderingContext2DStrokeStyle)
+DECLARE_PROPERTY_ACCESSOR(CanvasRenderingContext2DFillStyle)
+// Customized getter&setter of DOMWindow.location
+DECLARE_PROPERTY_ACCESSOR(DOMWindowLocation)
+// Customized setter of DOMWindow.opener
+DECLARE_PROPERTY_ACCESSOR_SETTER(DOMWindowOpener)
+
+DECLARE_PROPERTY_ACCESSOR(DocumentLocation)
+DECLARE_PROPERTY_ACCESSOR(DocumentImplementation)
+DECLARE_PROPERTY_ACCESSOR_GETTER(EventSrcElement)
+DECLARE_PROPERTY_ACCESSOR(EventReturnValue)
+DECLARE_PROPERTY_ACCESSOR_GETTER(EventDataTransfer)
+DECLARE_PROPERTY_ACCESSOR_GETTER(EventClipboardData)
+
+// Getter/Setter for window event handlers
+DECLARE_PROPERTY_ACCESSOR(DOMWindowEventHandler)
+// Getter/Setter for Element event handlers
+DECLARE_PROPERTY_ACCESSOR(ElementEventHandler)
+
+// Customized setter of src and location on HTMLFrameElement
+DECLARE_PROPERTY_ACCESSOR_SETTER(HTMLFrameElementSrc)
+DECLARE_PROPERTY_ACCESSOR_SETTER(HTMLFrameElementLocation)
+// Customized setter of src on HTMLIFrameElement
+DECLARE_PROPERTY_ACCESSOR_SETTER(HTMLIFrameElementSrc)
+// Customized setter of Attr.value
+DECLARE_PROPERTY_ACCESSOR_SETTER(AttrValue)
+
+// Customized setter of HTMLOptionsCollection length
+DECLARE_PROPERTY_ACCESSOR_SETTER(HTMLOptionsCollectionLength)
+
+DECLARE_NAMED_ACCESS_CHECK(Location)
+DECLARE_INDEXED_ACCESS_CHECK(History)
+
+DECLARE_NAMED_ACCESS_CHECK(History)
+DECLARE_INDEXED_ACCESS_CHECK(Location)
+
+// HTMLCollection customized functions.
+DECLARE_CALLBACK(HTMLCollectionItem)
+DECLARE_CALLBACK(HTMLCollectionNamedItem)
+// HTMLCollections are callable as functions.
+DECLARE_CALLBACK(HTMLCollectionCallAsFunction)
+
+// HTMLSelectElement customized functions.
+DECLARE_CALLBACK(HTMLSelectElementRemove)
+
+// HTMLOptionsCollection customized functions.
+DECLARE_CALLBACK(HTMLOptionsCollectionRemove)
+DECLARE_CALLBACK(HTMLOptionsCollectionAdd)
+
+// HTMLDocument customized functions
+DECLARE_CALLBACK(HTMLDocumentWrite)
+DECLARE_CALLBACK(HTMLDocumentWriteln)
+DECLARE_CALLBACK(HTMLDocumentOpen)
+DECLARE_CALLBACK(HTMLDocumentClear)
+
+// Document customized functions
+DECLARE_CALLBACK(DocumentEvaluate)
+
+// Window customized functions
+DECLARE_CALLBACK(DOMWindowAddEventListener)
+DECLARE_CALLBACK(DOMWindowRemoveEventListener)
+DECLARE_CALLBACK(DOMWindowPostMessage)
+DECLARE_CALLBACK(DOMWindowSetTimeout)
+DECLARE_CALLBACK(DOMWindowSetInterval)
+DECLARE_CALLBACK(DOMWindowAtob)
+DECLARE_CALLBACK(DOMWindowBtoa)
+DECLARE_CALLBACK(DOMWindowNOP)
+DECLARE_CALLBACK(DOMWindowToString)
+DECLARE_CALLBACK(DOMWindowShowModalDialog)
+DECLARE_CALLBACK(DOMWindowOpen)
+
+DECLARE_CALLBACK(DOMParserConstructor)
+DECLARE_CALLBACK(XMLHttpRequestConstructor)
+DECLARE_CALLBACK(XMLSerializerConstructor)
+DECLARE_CALLBACK(XPathEvaluatorConstructor)
+DECLARE_CALLBACK(XSLTProcessorConstructor)
+
+// Implementation of custom XSLTProcessor methods.
+DECLARE_CALLBACK(XSLTProcessorImportStylesheet)
+DECLARE_CALLBACK(XSLTProcessorTransformToFragment)
+DECLARE_CALLBACK(XSLTProcessorTransformToDocument)
+DECLARE_CALLBACK(XSLTProcessorSetParameter)
+DECLARE_CALLBACK(XSLTProcessorGetParameter)
+DECLARE_CALLBACK(XSLTProcessorRemoveParameter)
+
+// CSSPrimitiveValue customized functions
+DECLARE_CALLBACK(CSSPrimitiveValueGetRGBColorValue)
+
+// Canvas 2D customized functions
+DECLARE_CALLBACK(CanvasRenderingContext2DSetStrokeColor)
+DECLARE_CALLBACK(CanvasRenderingContext2DSetFillColor)
+DECLARE_CALLBACK(CanvasRenderingContext2DStrokeRect)
+DECLARE_CALLBACK(CanvasRenderingContext2DSetShadow)
+DECLARE_CALLBACK(CanvasRenderingContext2DDrawImage)
+DECLARE_CALLBACK(CanvasRenderingContext2DDrawImageFromRect)
+DECLARE_CALLBACK(CanvasRenderingContext2DCreatePattern)
+
+// Implementation of Clipboard methods.
+DECLARE_CALLBACK(ClipboardClearData)
+DECLARE_CALLBACK(ClipboardGetData)
+DECLARE_CALLBACK(ClipboardSetData)
+
+// Implementation of Element methods.
+DECLARE_CALLBACK(ElementSetAttribute)
+DECLARE_CALLBACK(ElementSetAttributeNode)
+DECLARE_CALLBACK(ElementSetAttributeNS)
+DECLARE_CALLBACK(ElementSetAttributeNodeNS)
+
+// Implementation of EventTarget::addEventListener
+// and EventTarget::removeEventListener
+DECLARE_CALLBACK(EventTargetNodeAddEventListener)
+DECLARE_CALLBACK(EventTargetNodeRemoveEventListener)
+
+// Custom implementation of XMLHttpRequest properties
+DECLARE_PROPERTY_ACCESSOR_SETTER(XMLHttpRequestOnreadystatechange)
+DECLARE_PROPERTY_ACCESSOR_SETTER(XMLHttpRequestOnload)
+DECLARE_CALLBACK(XMLHttpRequestAddEventListener)
+DECLARE_CALLBACK(XMLHttpRequestRemoveEventListener)
+DECLARE_CALLBACK(XMLHttpRequestOpen)
+DECLARE_CALLBACK(XMLHttpRequestSend)
+DECLARE_CALLBACK(XMLHttpRequestSetRequestHeader)
+DECLARE_CALLBACK(XMLHttpRequestGetResponseHeader)
+DECLARE_CALLBACK(XMLHttpRequestOverrideMimeType)
+
+// Custom implementation of TreeWalker functions
+DECLARE_CALLBACK(TreeWalkerParentNode)
+DECLARE_CALLBACK(TreeWalkerFirstChild)
+DECLARE_CALLBACK(TreeWalkerLastChild)
+DECLARE_CALLBACK(TreeWalkerNextNode)
+DECLARE_CALLBACK(TreeWalkerPreviousNode)
+DECLARE_CALLBACK(TreeWalkerNextSibling)
+DECLARE_CALLBACK(TreeWalkerPreviousSibling)
+
+// Custom implementation of NodeIterator functions
+DECLARE_CALLBACK(NodeIteratorNextNode)
+DECLARE_CALLBACK(NodeIteratorPreviousNode)
+
+// Custom implementation of NodeFilter function
+DECLARE_CALLBACK(NodeFilterAcceptNode)
+
+DECLARE_NAMED_PROPERTY_GETTER(DOMWindow)
+DECLARE_INDEXED_PROPERTY_GETTER(DOMWindow)
+DECLARE_NAMED_ACCESS_CHECK(DOMWindow)
+DECLARE_INDEXED_ACCESS_CHECK(DOMWindow)
+
+DECLARE_NAMED_PROPERTY_GETTER(HTMLFrameSetElement)
+DECLARE_NAMED_PROPERTY_GETTER(HTMLFormElement)
+DECLARE_NAMED_PROPERTY_GETTER(HTMLDocument)
+DECLARE_NAMED_PROPERTY_SETTER(HTMLDocument)
+DECLARE_NAMED_PROPERTY_DELETER(HTMLDocument)
+DECLARE_NAMED_PROPERTY_GETTER(NodeList)
+DECLARE_NAMED_PROPERTY_GETTER(NamedNodeMap)
+DECLARE_NAMED_PROPERTY_GETTER(CSSStyleDeclaration)
+DECLARE_NAMED_PROPERTY_SETTER(CSSStyleDeclaration)
+DECLARE_NAMED_PROPERTY_GETTER(HTMLPlugInElement)
+DECLARE_NAMED_PROPERTY_SETTER(HTMLPlugInElement)
+DECLARE_INDEXED_PROPERTY_GETTER(HTMLPlugInElement)
+DECLARE_INDEXED_PROPERTY_SETTER(HTMLPlugInElement)
+
+// Plugin object can be called as function.
+DECLARE_CALLBACK(HTMLPlugInElement)
+
+DECLARE_NAMED_PROPERTY_GETTER(StyleSheetList)
+DECLARE_INDEXED_PROPERTY_GETTER(NamedNodeMap)
+DECLARE_INDEXED_PROPERTY_GETTER(HTMLFormElement)
+DECLARE_INDEXED_PROPERTY_GETTER(HTMLOptionsCollection)
+DECLARE_INDEXED_PROPERTY_SETTER(HTMLOptionsCollection)
+DECLARE_INDEXED_PROPERTY_SETTER(HTMLSelectElementCollection)
+DECLARE_NAMED_PROPERTY_GETTER(HTMLCollection)
+
+// SVG custom properties and callbacks
+#if ENABLE(SVG)
+DECLARE_CALLBACK(SVGMatrixInverse)
+DECLARE_CALLBACK(SVGMatrixRotateFromVector)
+#endif
+
+#undef DECLARE_INDEXED_ACCESS_CHECK
+#undef DECLARE_NAMED_ACCESS_CHECK
+
+#undef DECLARE_PROPERTY_ACCESSOR_SETTER
+#undef DECLARE_PROPERTY_ACCESSOR_GETTER
+#undef DECLARE_PROPERTY_ACCESSOR
+
+#undef DECLARE_NAMED_PROPERTY_GETTER
+#undef DECLARE_NAMED_PROPERTY_SETTER
+#undef DECLARE_NAMED_PROPERTY_DELETER
+
+#undef DECLARE_INDEXED_PROPERTY_GETTER
+#undef DECLARE_INDEXED_PROPERTY_SETTER
+#undef DECLARE_INDEXED_PROPERTY_DELETER
+
+#undef DECLARE_CALLBACK
+
+ // Returns the NPObject corresponding to an HTMLElement object.
+ static NPObject* GetHTMLPlugInElementNPObject(v8::Handle<v8::Object> object);
+
+ // Returns the owner frame pointer of a DOM wrapper object. It only works for
+ // these DOM objects requiring cross-domain access check.
+ static Frame* GetTargetFrame(v8::Local<v8::Object> host,
+ v8::Local<v8::Value> data);
+
+ // Special case for downcasting SVG path segments
+#if ENABLE(SVG)
+ static V8ClassIndex::V8WrapperType DowncastSVGPathSeg(void* path_seg);
+#endif
+
+ private:
+ static v8::Handle<v8::Value> WindowSetTimeoutImpl(const v8::Arguments& args,
+ bool single_shot);
+};
+
+
+// A template of named property accessor of collections.
+template <class C>
+static v8::Handle<v8::Value> CollectionNamedPropertyGetter(
+ v8::Local<v8::String> name, const v8::AccessorInfo& info) {
+ return GetNamedPropertyOfCollection<C>(name, info.Holder(), info.Data());
+}
+
+
+// Returns named property of a collection.
+template <class C>
+static v8::Handle<v8::Value> GetNamedPropertyOfCollection(
+ v8::Local<v8::String> name,
+ v8::Local<v8::Object> object,
+ v8::Local<v8::Value> data) {
+ // TODO: assert object is a collection type
+ ASSERT(V8Proxy::MaybeDOMWrapper(object));
+
+ V8ClassIndex::V8WrapperType t = V8Proxy::GetDOMWrapperType(object);
+ C* collection = V8Proxy::FastToNativeObject<C>(t, object);
+ String prop_name = ToWebCoreString(name);
+ void* result = collection->namedItem(prop_name);
+ if (!result) return v8::Handle<v8::Value>();
+ V8ClassIndex::V8WrapperType type = V8ClassIndex::ToWrapperType(data);
+ return V8Proxy::ToV8Object(type, result);
+}
+
+
+// A template returns whether a collection has a named property.
+// This function does not cause JS heap allocation.
+template <class C>
+static bool HasNamedPropertyOfCollection(v8::Local<v8::String> name,
+ v8::Local<v8::Object> object,
+ v8::Local<v8::Value> data) {
+ // TODO: assert object is a collection type
+ ASSERT(V8Proxy::MaybeDOMWrapper(object));
+
+ V8ClassIndex::V8WrapperType t = V8Proxy::GetDOMWrapperType(object);
+ C* collection = V8Proxy::FastToNativeObject<C>(t, object);
+ String prop_name = ToWebCoreString(name);
+ void* result = collection->namedItem(prop_name);
+ return result != NULL;
+}
+
+
+// A template of index interceptor of collections.
+template <class C>
+static v8::Handle<v8::Value> CollectionIndexedPropertyGetter(
+ uint32_t index, const v8::AccessorInfo& info) {
+ return GetIndexedPropertyOfCollection<C>(index, info.Holder(), info.Data());
+}
+
+
+// Returns the property at the index of a collection.
+template <class C>
+static v8::Handle<v8::Value> GetIndexedPropertyOfCollection(
+ uint32_t index, v8::Local<v8::Object> object, v8::Local<v8::Value> data) {
+ // TODO, assert that object must be a collection type
+ ASSERT(V8Proxy::MaybeDOMWrapper(object));
+ V8ClassIndex::V8WrapperType t = V8Proxy::GetDOMWrapperType(object);
+ C* collection = V8Proxy::FastToNativeObject<C>(t, object);
+ void* result = collection->item(index);
+ if (!result) return v8::Handle<v8::Value>();
+ V8ClassIndex::V8WrapperType type = V8ClassIndex::ToWrapperType(data);
+ return V8Proxy::ToV8Object(type, result);
+}
+
+
+// Get an array containing the names of indexed properties in a collection.
+template <class C>
+static v8::Handle<v8::Array> CollectionIndexedPropertyEnumerator(
+ const v8::AccessorInfo& info) {
+ ASSERT(V8Proxy::MaybeDOMWrapper(info.Holder()));
+ V8ClassIndex::V8WrapperType t = V8Proxy::GetDOMWrapperType(info.Holder());
+ C* collection = V8Proxy::FastToNativeObject<C>(t, info.Holder());
+ int length = collection->length();
+ v8::Handle<v8::Array> properties = v8::Array::New(length);
+ for (int i = 0; i < length; i++) {
+ // TODO(ager): Do we need to check that the item function returns
+ // a non-null value for this index?
+ v8::Handle<v8::Integer> integer = v8::Integer::New(i);
+ properties->Set(integer, integer);
+ }
+ return properties;
+}
+
+
+// Returns whether a collection has a property at a given index.
+// This function does not cause JS heap allocation.
+template <class C>
+static bool HasIndexedPropertyOfCollection(uint32_t index,
+ v8::Local<v8::Object> object,
+ v8::Local<v8::Value> data) {
+ // TODO, assert that object must be a collection type
+ ASSERT(V8Proxy::MaybeDOMWrapper(object));
+ V8ClassIndex::V8WrapperType t = V8Proxy::GetDOMWrapperType(object);
+ C* collection = V8Proxy::FastToNativeObject<C>(t, object);
+ void* result = collection->item(index);
+ return result != NULL;
+}
+
+
+// A template for indexed getters on collections of strings that should return
+// null if the resulting string is a null string.
+template <class C>
+static v8::Handle<v8::Value> CollectionStringOrNullIndexedPropertyGetter(
+ uint32_t index, const v8::AccessorInfo& info) {
+ // TODO, assert that object must be a collection type
+ ASSERT(V8Proxy::MaybeDOMWrapper(info.Holder()));
+ V8ClassIndex::V8WrapperType t = V8Proxy::GetDOMWrapperType(info.Holder());
+ C* collection = V8Proxy::FastToNativeObject<C>(t, info.Holder());
+ String result = collection->item(index);
+ return v8StringOrNull(result);
+}
+
+} // namespace WebCore
+
+#endif // V8_CUSTOM_H__
diff --git a/webkit/port/bindings/v8/v8_events.cpp b/webkit/port/bindings/v8/v8_events.cpp
new file mode 100644
index 0000000..38e3802
--- /dev/null
+++ b/webkit/port/bindings/v8/v8_events.cpp
@@ -0,0 +1,472 @@
+// 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_events.h"
+#include "v8_proxy.h"
+#include "v8_binding.h"
+#include "Frame.h"
+#include "DOMWindow.h"
+#include "V8Event.h"
+#include "Event.h"
+#include "Document.h"
+#include "Tokenizer.h"
+#include "Node.h"
+#include "XMLHttpRequest.h"
+#include "CString.h"
+
+namespace WebCore {
+
+
+V8AbstractEventListener::V8AbstractEventListener(Frame* frame, bool html)
+ : m_frame(frame), m_html(html) {
+ ASSERT(m_frame);
+ if (!m_frame) return;
+
+ // Get the position in the source if any.
+ m_lineNumber = 0;
+ m_columnNumber = 0;
+ if (m_html && m_frame->document()->tokenizer()) {
+ m_lineNumber = m_frame->document()->tokenizer()->lineNumber();
+ m_columnNumber = m_frame->document()->tokenizer()->columnNumber();
+ }
+}
+
+void V8AbstractEventListener::handleEvent(Event* event, bool isWindowEvent) {
+ // EventListener could be disconnected from the frame.
+ ASSERT(m_frame);
+ if (!m_frame) return;
+
+ // The callback function on XMLHttpRequest can clear the event listener
+ // and destroys 'this' object. Keep a local reference of it.
+ // See issue 889829
+ RefPtr<V8AbstractEventListener> self(this);
+
+ v8::HandleScope handle_scope;
+
+ v8::Handle<v8::Context> context = V8Proxy::GetContext(m_frame);
+ if (context.IsEmpty()) return;
+ v8::Context::Scope scope(context);
+
+ // m_frame can removed by the callback function,
+ // protect it until the callback function returns.
+ RefPtr<Frame> protector(m_frame);
+
+ IF_DEVEL(log_info(frame, "Handling DOM event", m_frame->document()->URL()));
+
+ v8::Handle<v8::Value> jsevent = V8Proxy::EventToV8Object(event);
+
+ v8::Local<v8::String> event_symbol = v8::String::NewSymbol("event");
+
+ // Save the old 'event' property.
+ v8::Local<v8::Value> saved_evt = context->Global()->Get(event_symbol);
+
+ // Make the event available in the window object.
+ //
+ // TODO: This does not work as in safari if the window.event
+ // property is already set. We need to make sure that property
+ // access is intercepted correctly.
+ context->Global()->Set(event_symbol, jsevent);
+
+ v8::Local<v8::Value> ret;
+ {
+ // Catch exceptions thrown in the event handler so they do not
+ // propagate to javascript code that caused the event to fire.
+ v8::TryCatch try_catch;
+ try_catch.SetVerbose(true);
+
+ // Call the event handler.
+ ret = CallListenerFunction(jsevent, event, isWindowEvent);
+ }
+
+ if (V8Proxy::HandleOutOfMemory())
+ ASSERT(ret.IsEmpty());
+
+ if (ret.IsEmpty()) {
+ return;
+ }
+
+ if (!ret.IsEmpty()) {
+ if (!ret->IsNull() && !ret->IsUndefined() &&
+ event->storesResultAsString()) {
+ event->storeResult(ToWebCoreString(ret));
+ }
+ // Prevent default action if the return value is false;
+ // TODO(fqian): example, and reference to buganizer entry
+ if (m_html) {
+ if (ret->IsBoolean() && !ret->BooleanValue()) {
+ event->preventDefault();
+ }
+ }
+ }
+
+ // Restore the old event.
+ context->Global()->Set(event_symbol, saved_evt);
+
+ Document::updateDocumentsRendering();
+}
+
+
+void V8AbstractEventListener::DisposeListenerObject() {
+ if (!m_listener.IsEmpty()) {
+#ifndef NDEBUG
+ V8Proxy::UnregisterGlobalHandle(this, m_listener);
+#endif
+ m_listener.Dispose();
+ m_listener.Clear();
+ }
+}
+
+
+V8EventListener::V8EventListener(Frame* frame, v8::Local<v8::Object> listener,
+ bool html)
+ : V8AbstractEventListener(frame, html) {
+ m_listener = v8::Persistent<v8::Object>::New(listener);
+#ifndef NDEBUG
+ V8Proxy::RegisterGlobalHandle(EVENT_LISTENER, this, m_listener);
+#endif
+}
+
+
+V8EventListener::~V8EventListener() {
+ if (m_frame) {
+ V8Proxy* proxy = V8Proxy::retrieve(m_frame);
+ if (proxy)
+ proxy->RemoveV8EventListener(this);
+ }
+
+ DisposeListenerObject();
+}
+
+
+v8::Local<v8::Function> V8EventListener::GetListenerFunction() {
+ // It could be disposed already.
+ if (m_listener.IsEmpty()) return v8::Local<v8::Function>();
+
+ if (m_listener->IsFunction()) {
+ return v8::Local<v8::Function>::New(
+ v8::Persistent<v8::Function>::Cast(m_listener));
+
+ } else if (m_listener->IsObject()) {
+ v8::Local<v8::Value> prop =
+ m_listener->Get(v8::String::NewSymbol("handleEvent"));
+ if (prop->IsFunction()) {
+ return v8::Local<v8::Function>::Cast(prop);
+ }
+ }
+
+ return v8::Local<v8::Function>();
+}
+
+
+v8::Local<v8::Value>
+V8EventListener::CallListenerFunction(v8::Handle<v8::Value> jsevent,
+ Event* event, bool isWindowEvent) {
+ v8::Local<v8::Function> handler_func = GetListenerFunction();
+ if (handler_func.IsEmpty()) return v8::Local<v8::Value>();
+
+ v8::Local<v8::Object> this_obj = GetThisObject(event, isWindowEvent);
+ v8::Handle<v8::Value> parameters[1] = {jsevent};
+
+ V8Proxy* proxy = V8Proxy::retrieve(m_frame);
+ ASSERT(proxy);
+
+ return proxy->CallFunction(handler_func, this_obj, 1, parameters);
+}
+
+
+v8::Local<v8::Object> V8EventListener::GetThisObject(Event* event,
+ bool isWindowEvent) {
+ if (!m_listener.IsEmpty() && !m_listener->IsFunction()) {
+ return v8::Local<v8::Object>::New(m_listener);
+ }
+
+ if (isWindowEvent) {
+ return v8::Context::GetCurrent()->Global();
+ }
+
+ EventTarget* target = event->currentTarget();
+ if (target->toNode()) {
+ v8::Handle<v8::Value> value =
+ V8Proxy::ToV8Object(V8ClassIndex::NODE, target->toNode());
+ return v8::Local<v8::Object>::New(v8::Handle<v8::Object>::Cast(value));
+
+ } else if (target->toXMLHttpRequest()) {
+ v8::Handle<v8::Value> value = V8Proxy::ToV8Object(
+ V8ClassIndex::XMLHTTPREQUEST, target->toXMLHttpRequest());
+ return v8::Local<v8::Object>::New(v8::Handle<v8::Object>::Cast(value));
+
+ } else {
+ ASSERT(false);
+ return v8::Local<v8::Object>();
+ }
+}
+
+
+// ------- V 8 X H R E v e n t L i s t e n e r -----------------
+
+static void WeakXHRListenerCallback(v8::Persistent<v8::Object> obj,
+ void* para) {
+ V8XHREventListener* listener = static_cast<V8XHREventListener*>(para);
+
+ // Remove the wrapper
+ Frame* frame = listener->frame();
+ if (frame) {
+ V8Proxy* proxy = V8Proxy::retrieve(frame);
+ if (proxy)
+ proxy->RemoveXHREventListener(listener);
+
+ // Because the listener is no longer in the list, it must
+ // be disconnected from the frame to avoid dangling frame pointer
+ // in the destructor.
+ listener->disconnectFrame();
+ }
+
+ // Dispose the listener object.
+ listener->DisposeListenerObject();
+}
+
+
+V8XHREventListener::V8XHREventListener(Frame* frame,
+ v8::Local<v8::Object> listener,
+ bool html)
+ : V8EventListener(frame, listener, html) {
+ // make m_listener weak.
+ m_listener.MakeWeak(this, WeakXHRListenerCallback);
+}
+
+
+V8XHREventListener::~V8XHREventListener() {
+ if (m_frame) {
+ ASSERT(!m_listener.IsEmpty());
+ V8Proxy* proxy = V8Proxy::retrieve(m_frame);
+ if (proxy)
+ proxy->RemoveXHREventListener(this);
+ }
+
+ DisposeListenerObject();
+}
+
+
+// ------- L a z y E v e n t L i s t e n e r ---------------
+
+V8LazyEventListener::V8LazyEventListener(Frame *frame, const String& code,
+ const String& func_name)
+ : V8AbstractEventListener(frame, true), m_code(code),
+ m_func_name(func_name), m_compiled(false),
+ m_wrapped_function_compiled(false) {
+}
+
+
+V8LazyEventListener::~V8LazyEventListener() {
+ DisposeListenerObject();
+
+ // Dispose wrapped function
+ if (!m_wrapped_function.IsEmpty()) {
+#ifndef NDEBUG
+ V8Proxy::UnregisterGlobalHandle(this, m_wrapped_function);
+#endif
+ m_wrapped_function.Dispose();
+ m_wrapped_function.Clear();
+ }
+}
+
+
+v8::Local<v8::Object> V8LazyEventListener::GetThisObject(Event* event,
+ bool isWindowEvent) {
+ if (isWindowEvent) {
+ return v8::Context::GetCurrent()->Global();
+ }
+
+ v8::Handle<v8::Value> value =
+ V8Proxy::ToV8Object(V8ClassIndex::NODE, event->currentTarget()->toNode());
+ ASSERT(!value.IsEmpty());
+
+ return v8::Local<v8::Object>::New(v8::Handle<v8::Object>::Cast(value));
+}
+
+
+v8::Local<v8::Function> V8LazyEventListener::GetListenerFunction() {
+ if (m_compiled) {
+ ASSERT(m_listener.IsEmpty() || m_listener->IsFunction());
+ return m_listener.IsEmpty() ?
+ v8::Local<v8::Function>() :
+ v8::Local<v8::Function>::New(
+ v8::Persistent<v8::Function>::Cast(m_listener));
+ }
+
+ m_compiled = true;
+
+ ASSERT(m_frame);
+
+ {
+ // Switch to the contex of m_frame
+ v8::HandleScope handle_scope;
+
+ // Use the outer scope to hold context.
+ v8::Handle<v8::Context> context = V8Proxy::GetContext(m_frame);
+ // Bail out if we could not get the context.
+ if (context.IsEmpty()) return v8::Local<v8::Function>();
+
+ v8::Context::Scope scope(context);
+
+ // Wrap function around the event code. The parenthesis around
+ // the function are needed so that evaluating the code yields
+ // the function value. Without the parenthesis the function
+ // value is thrown away.
+
+ // Make it an anonymous function to avoid name conflict for cases like
+ // <body onload='onload()'>
+ // <script> function onload() { alert('hi'); } </script>.
+ // Set function name to function object instead.
+ // See issue 944690.
+ //
+ // The ECMAScript spec says (very obliquely) that the parameter to
+ // an event handler is named "evt".
+ String code = "(function (evt) {\n";
+ code.append(m_code);
+ code.append("})");
+
+ IF_DEVEL(log_info(frame, code, "<getListener>"));
+
+ v8::Handle<v8::String> codeExternalString = v8ExternalString(code);
+ v8::Handle<v8::Script> script = V8Proxy::CompileScript(codeExternalString,
+ m_frame->document()->url(), m_lineNumber - 1);
+ if (!script.IsEmpty()) {
+ V8Proxy* proxy = V8Proxy::retrieve(m_frame);
+ ASSERT(proxy); // must be valid at this point
+ v8::Local<v8::Value> value = proxy->RunScript(script, false);
+ if (!value.IsEmpty()) {
+ ASSERT(value->IsFunction());
+ v8::Local<v8::Function> listener_func =
+ v8::Local<v8::Function>::Cast(value);
+ // Set the function name.
+ listener_func->SetName(v8::String::New(FromWebCoreString(m_func_name),
+ m_func_name.length()));
+
+ m_listener = v8::Persistent<v8::Function>::New(listener_func);
+#ifndef NDEBUG
+ V8Proxy::RegisterGlobalHandle(EVENT_LISTENER, this, m_listener);
+#endif
+ }
+ }
+ } // end of HandleScope
+
+ ASSERT(m_listener.IsEmpty() || m_listener->IsFunction());
+ return m_listener.IsEmpty() ?
+ v8::Local<v8::Function>() :
+ v8::Local<v8::Function>::New(
+ v8::Persistent<v8::Function>::Cast(m_listener));
+}
+
+
+v8::Local<v8::Value>
+V8LazyEventListener::CallListenerFunction(v8::Handle<v8::Value> jsevent,
+ Event* event, bool isWindowEvent) {
+ v8::Local<v8::Object> this_obj = GetThisObject(event, isWindowEvent);
+ v8::Local<v8::Function> handler_func = GetWrappedListenerFunction();
+ if (handler_func.IsEmpty()) return v8::Local<v8::Value>();
+
+ v8::Handle<v8::Value> parameters[1] = {jsevent};
+
+ V8Proxy* proxy = V8Proxy::retrieve(m_frame);
+ return proxy->CallFunction(handler_func, this_obj, 1, parameters);
+}
+
+
+v8::Local<v8::Function> V8LazyEventListener::GetWrappedListenerFunction() {
+ if (m_wrapped_function_compiled) {
+ ASSERT(m_wrapped_function.IsEmpty() || m_wrapped_function->IsFunction());
+ return m_wrapped_function.IsEmpty() ? v8::Local<v8::Function>() :
+ v8::Local<v8::Function>::New(m_wrapped_function);
+ }
+
+ m_wrapped_function_compiled = true;
+
+ {
+ // Switch to the contex of m_frame
+ v8::HandleScope handle_scope;
+
+ // Use the outer scope to hold context.
+ v8::Handle<v8::Context> context = V8Proxy::GetContext(m_frame);
+ // Bail out if we cannot get the context.
+ if (context.IsEmpty()) return v8::Local<v8::Function>();
+
+ v8::Context::Scope scope(context);
+
+ // TODO(fqian): cache the wrapper function.
+ String code = "(function (evt) {\n";
+
+ // This variable records how many lines the code has been offset within the
+ // source code to be evaluated
+ int codeOffset = 2;
+
+ // Nodes other than the document object, when executing inline event
+ // handlers push document, form, and the target node on the scope chain.
+ // We do this by using 'with' statement.
+ // See chrome/fast/forms/form-action.html
+ // chrome/fast/forms/selected-index-value.html
+ // base/fast/overflow/onscroll-layer-self-destruct.html
+ code.append(" with (this.ownerDocument ? this.ownerDocument : {}) {\n");
+ code.append(" with (this.form ? this.form : {}) {\n");
+ code.append(" with (this) {\n");
+ code.append(" ");
+ code.append(m_code);
+ code.append("\n");
+ code.append(" }\n");
+ code.append(" }\n");
+ code.append(" }\n");
+ code.append("})");
+ v8::Handle<v8::String> codeExternalString = v8ExternalString(code);
+ v8::Handle<v8::Script> script = V8Proxy::CompileScript(codeExternalString,
+ m_frame->document()->url(), m_lineNumber - 4);
+ if (!script.IsEmpty()) {
+ V8Proxy* proxy = V8Proxy::retrieve(m_frame);
+ ASSERT(proxy);
+ v8::Local<v8::Value> value = proxy->RunScript(script, false);
+ if (!value.IsEmpty()) {
+ ASSERT(value->IsFunction());
+
+ m_wrapped_function = v8::Persistent<v8::Function>::New(
+ v8::Local<v8::Function>::Cast(value));
+#ifndef NDEBUG
+ V8Proxy::RegisterGlobalHandle(EVENT_LISTENER, this, m_wrapped_function);
+#endif
+ // Set the function name.
+ m_wrapped_function->SetName(v8::String::New(
+ FromWebCoreString(m_func_name), m_func_name.length()));
+ }
+ }
+ } // end of local scope
+
+ return v8::Local<v8::Function>::New(m_wrapped_function);
+}
+
+} // namespace WebCore
diff --git a/webkit/port/bindings/v8/v8_events.h b/webkit/port/bindings/v8/v8_events.h
new file mode 100644
index 0000000..e2dc524
--- /dev/null
+++ b/webkit/port/bindings/v8/v8_events.h
@@ -0,0 +1,171 @@
+// Copyright 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.
+
+#ifndef V8_EVENTS_H__
+#define V8_EVENTS_H__
+
+#include "config.h"
+#include <v8.h>
+#include "Frame.h"
+#include "Event.h"
+#include "EventListener.h"
+#include "PlatformString.h"
+
+// #define IF_DEVEL(stmt) stmt
+#define IF_DEVEL(stmt) ((void) 0)
+
+namespace WebCore {
+
+// There are two kinds of event listeners: HTML or non-HMTL.
+// onload, onfocus, etc (attributes) are always HTML event handler type;
+// Event listeners added by Window.addEventListener
+// or EventTargetNode::addEventListener are non-HTML type.
+//
+// Why does this matter?
+// WebKit does not allow duplicated HTML event handlers of the same type,
+// but ALLOWs duplicated non-HTML event handlers.
+
+class V8AbstractEventListener : public EventListener {
+ public:
+ virtual ~V8AbstractEventListener() { }
+
+ // Returns the owner frame of the listener.
+ Frame* frame() { return m_frame; }
+
+ // Handle event.
+ void handleEvent(Event*, bool isWindowEvent);
+
+ // Returns the listener object, either a function or an object.
+ virtual v8::Local<v8::Object> GetListenerObject() {
+ return v8::Local<v8::Object>::New(m_listener);
+ }
+
+ // Dispose listener object and clear the handle
+ void DisposeListenerObject();
+
+ private:
+ V8AbstractEventListener(Frame* frame, bool html);
+
+
+ // Call listener function.
+ virtual v8::Local<v8::Value>
+ CallListenerFunction(v8::Handle<v8::Value> jsevent,
+ Event* event, bool isWindowEvent) = 0;
+
+ // Frame to which the event listener is attached to.
+ // An event listener must be destroyed before its owner
+ // frame is deleted.
+ // See fast/dom/replaceChild.html
+ // TODO(fqian): this could hold m_frame live until
+ // the event listener is deleted. Fix this!
+ Frame* m_frame;
+
+ // Listener object, avoid using peer because it can keep this object alive.
+ v8::Persistent<v8::Object> m_listener;
+
+ // Flags this is a HTML type listener.
+ bool m_html;
+
+ // Position in the HTML source for HTML event listeners.
+ int m_lineNumber;
+ int m_columnNumber;
+
+ friend class V8EventListener;
+ friend class V8XHREventListener;
+ friend class V8LazyEventListener;
+};
+
+// V8EventListener is a wrapper of a JS object implements EventListener
+// interface (has handleEvent(event) method), or a JS function
+// that can handle the event.
+class V8EventListener : public V8AbstractEventListener {
+ public:
+ V8EventListener(Frame* frame, v8::Local<v8::Object> listener, bool html);
+ virtual ~V8EventListener();
+ virtual bool isHTMLEventListener() const { return m_html; }
+
+ // Detach the listener from its owner frame.
+ void disconnectFrame() { m_frame = 0; }
+
+ private:
+ // Call listener function.
+ virtual v8::Local<v8::Value> CallListenerFunction(
+ v8::Handle<v8::Value> jsevent, Event* event, bool isWindowEvent);
+ v8::Local<v8::Object> GetThisObject(Event* event, bool isWindowEvent);
+ v8::Local<v8::Function> GetListenerFunction();
+};
+
+
+// V8XHREventListener is a special listener wrapper for XMLHttpRequest object.
+// It keeps JS listener week.
+class V8XHREventListener : public V8EventListener {
+ public:
+ V8XHREventListener(Frame* frame, v8::Local<v8::Object> listener, bool html);
+ virtual ~V8XHREventListener();
+};
+
+
+// V8LazyEventListener is a wrapper for a JavaScript code string that is
+// compiled and evaluated when an event is fired.
+// A V8LazyEventListener is always a HTML event handler.
+class V8LazyEventListener : public V8AbstractEventListener {
+ public:
+ V8LazyEventListener(Frame *frame, const String& code,
+ const String& func_name);
+ virtual ~V8LazyEventListener();
+ virtual bool isHTMLEventListener() const { return true; }
+
+ // For lazy event listener, the listener object is the same as its listener
+ // function without additional scope chains.
+ virtual v8::Local<v8::Object> GetListenerObject() {
+ return GetWrappedListenerFunction();
+ }
+
+ private:
+ String m_code;
+ String m_func_name; // function name
+ bool m_compiled;
+
+ // If the event listener is on a non-document dom node,
+ // we compile the function with some implicit scope chains before it.
+ bool m_wrapped_function_compiled;
+ v8::Persistent<v8::Function> m_wrapped_function;
+
+ v8::Local<v8::Function> GetWrappedListenerFunction();
+
+ virtual v8::Local<v8::Value> CallListenerFunction(
+ v8::Handle<v8::Value> jsevent, Event* event, bool isWindowEvent);
+
+ v8::Local<v8::Object> GetThisObject(Event* event, bool isWindowEvent);
+ v8::Local<v8::Function> GetListenerFunction();
+};
+
+} // namespace WebCore
+
+#endif // V8_EVENTS_H__
diff --git a/webkit/port/bindings/v8/v8_helpers.cpp b/webkit/port/bindings/v8/v8_helpers.cpp
new file mode 100644
index 0000000..466f810
--- /dev/null
+++ b/webkit/port/bindings/v8/v8_helpers.cpp
@@ -0,0 +1,59 @@
+// 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"
+
+#define max max
+#define min min
+#include "v8_helpers.h"
+#include "v8_proxy.h"
+#include "v8_index.h"
+#include "np_v8object.h"
+
+#include "DOMWindow.h"
+
+void WrapNPObject(v8::Handle<v8::Object> obj, NPObject* npobj) {
+ ASSERT(obj->InternalFieldCount() >= 3);
+
+ WebCore::V8Proxy::SetDOMWrapper(obj, WebCore::V8ClassIndex::NPOBJECT, npobj);
+
+ // Create a JS object as a hash map for functions
+ obj->SetInternalField(2, v8::Object::New());
+}
+
+v8::Local<v8::Context> GetV8Context(NPP npp, NPObject* npobj) {
+ V8NPObject* object = reinterpret_cast<V8NPObject*>(npobj);
+ return WebCore::V8Proxy::GetContext(object->root_object->frame());
+}
+
+WebCore::V8Proxy* GetV8Proxy(NPObject* npobj) {
+ V8NPObject* object = reinterpret_cast<V8NPObject*>(npobj);
+ WebCore::Frame* frame = object->root_object->frame();
+ return WebCore::V8Proxy::retrieve(frame);
+}
diff --git a/webkit/port/bindings/v8/v8_helpers.h b/webkit/port/bindings/v8/v8_helpers.h
new file mode 100644
index 0000000..39b53f3
--- /dev/null
+++ b/webkit/port/bindings/v8/v8_helpers.h
@@ -0,0 +1,49 @@
+// Copyright 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.
+
+#ifndef V8_HELPERS_H__
+#define V8_HELPERS_H__
+
+#include "bindings/npruntime.h"
+#include <v8.h>
+
+namespace WebCore {
+ class V8Proxy;
+}
+
+// Associates an NPObject with a V8 object.
+void WrapNPObject(v8::Handle<v8::Object> obj, NPObject *npobj);
+
+// Retrieves the V8 Context from the NP context pr obj (at most 1 may be NULL).
+v8::Local<v8::Context> GetV8Context(NPP npp, NPObject* npobj);
+
+// Get V8Proxy object from an NPObject.
+WebCore::V8Proxy* GetV8Proxy(NPObject* npobj);
+
+#endif // V8_HELPERS_H__
diff --git a/webkit/port/bindings/v8/v8_index.cpp b/webkit/port/bindings/v8/v8_index.cpp
new file mode 100644
index 0000000..4cbe7d9
--- /dev/null
+++ b/webkit/port/bindings/v8/v8_index.cpp
@@ -0,0 +1,361 @@
+// 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_index.h"
+
+// TODO: Can we use a macro to include necessary headers by using
+// WRAPPER_TYPES?
+#include "V8Attr.h"
+#include "V8BarInfo.h"
+#include "V8CanvasRenderingContext2D.h"
+#include "V8CanvasGradient.h"
+#include "V8CanvasPattern.h"
+#include "V8CDATASection.h"
+#include "V8CharacterData.h"
+#include "V8Clipboard.h"
+#include "V8Comment.h"
+#include "V8Console.h"
+#include "V8Counter.h"
+#include "V8CSSSTyleDeclaration.h"
+#include "V8CSSRule.h"
+#include "V8CSSStyleRule.h"
+#include "V8CSSCharsetRule.h"
+#include "V8CSSImportRule.h"
+#include "V8CSSMediaRule.h"
+#include "V8CSSFontFaceRule.h"
+#include "V8CSSPageRule.h"
+#include "V8CSSRuleList.h"
+#include "V8CSSPrimitiveValue.h"
+#include "V8CSSValue.h"
+#include "V8CSSValueList.h"
+#include "V8CSSStyleSheet.h"
+#include "V8Document.h"
+#include "V8DocumentFragment.h"
+#include "V8DocumentType.h"
+#include "V8Element.h"
+#include "V8Entity.h"
+#include "V8EntityReference.h"
+#include "V8History.h"
+#include "V8HTMLCanvasElement.h"
+#include "V8UndetectableHTMLCollection.h"
+#include "V8HTMLCollection.h"
+#include "V8HTMLDocument.h"
+#include "V8HTMLElement.h"
+#include "V8HTMLOptionsCollection.h"
+#include "V8HTMLAnchorElement.h"
+#include "V8HTMLAppletElement.h"
+#include "V8HTMLAreaElement.h"
+#include "V8HTMLBaseElement.h"
+#include "V8HTMLBaseFontElement.h"
+#include "V8HTMLBlockquoteElement.h"
+#include "V8HTMLBodyElement.h"
+#include "V8HTMLBRElement.h"
+#include "V8HTMLButtonElement.h"
+#include "V8HTMLCanvasElement.h"
+#include "V8HTMLModElement.h"
+#include "V8HTMLDirectoryElement.h"
+#include "V8HTMLDivElement.h"
+#include "V8HTMLDListElement.h"
+#include "V8HTMLEmbedElement.h"
+#include "V8HTMLFieldSetElement.h"
+#include "V8HTMLFormElement.h"
+#include "V8HTMLFontElement.h"
+#include "V8HTMLFrameElement.h"
+#include "V8HTMLFrameSetElement.h"
+#include "V8HTMLHeadingElement.h"
+#include "V8HTMLHeadElement.h"
+#include "V8HTMLHRElement.h"
+#include "V8HTMLHtmlElement.h"
+#include "V8HTMLIFrameElement.h"
+#include "V8HTMLImageElement.h"
+#include "V8HTMLInputElement.h"
+#include "V8HTMLSelectionInputElement.h"
+#include "V8HTMLIsIndexElement.h"
+#include "V8HTMLLabelElement.h"
+#include "V8HTMLLegendElement.h"
+#include "V8HTMLLIElement.h"
+#include "V8HTMLLinkElement.h"
+#include "V8HTMLMapElement.h"
+#include "V8HTMLMarqueeElement.h"
+#include "V8HTMLMenuElement.h"
+#include "V8HTMLMetaElement.h"
+#include "V8HTMLObjectElement.h"
+#include "V8HTMLOListElement.h"
+#include "V8HTMLOptGroupElement.h"
+#include "V8HTMLOptionElement.h"
+#include "V8HTMLParagraphElement.h"
+#include "V8HTMLParamElement.h"
+#include "V8HTMLPreElement.h"
+#include "V8HTMLQuoteElement.h"
+#include "V8HTMLScriptElement.h"
+#include "V8HTMLSelectElement.h"
+#include "V8HTMLStyleElement.h"
+#include "V8HTMLTableCaptionElement.h"
+#include "V8HTMLTableColElement.h"
+#include "V8HTMLTableElement.h"
+#include "V8HTMLTableSectionElement.h"
+#include "V8HTMLTableCellElement.h"
+#include "V8HTMLTableRowElement.h"
+#include "V8HTMLTextAreaElement.h"
+#include "V8HTMLTitleElement.h"
+#include "V8HTMLUListElement.h"
+#include "V8InspectorController.h"
+#include "V8MediaList.h"
+#include "V8MessageEvent.h"
+#include "V8NamedNodeMap.h"
+#include "V8Node.h"
+#include "V8NodeList.h"
+#include "V8NodeFilter.h"
+#include "V8Notation.h"
+#include "V8ProcessingInstruction.h"
+#include "V8ProgressEvent.h"
+#include "V8StyleSheet.h"
+#include "V8Text.h"
+#include "V8TextEvent.h"
+#include "V8DOMCoreException.h"
+#include "V8DOMParser.h"
+#include "V8DOMWindow.h"
+#include "V8Event.h"
+#include "V8EventException.h"
+#include "V8EventTargetNode.h"
+#include "V8KeyboardEvent.h"
+#include "V8MouseEvent.h"
+#include "V8WheelEvent.h"
+#include "V8UIEvent.h"
+#include "V8MutationEvent.h"
+#include "V8OverflowEvent.h"
+#include "V8Location.h"
+#include "V8Screen.h"
+#include "V8DOMSelection.h"
+#include "V8Navigator.h"
+#include "V8MimeType.h"
+#include "V8MimeTypeArray.h"
+#include "V8Plugin.h"
+#include "V8PluginArray.h"
+#include "V8Range.h"
+#include "V8RangeException.h"
+#include "V8Rect.h"
+#include "V8NodeIterator.h"
+#include "V8TreeWalker.h"
+#include "V8StyleSheetList.h"
+#include "V8DOMImplementation.h"
+#include "V8XPathResult.h"
+#include "V8XPathException.h"
+#include "V8XPathExpression.h"
+#include "V8XPathNSResolver.h"
+#include "V8XMLHttpRequest.h"
+#include "V8XMLHttpRequestException.h"
+#include "V8XMLSerializer.h"
+#include "V8XPathEvaluator.h"
+#include "V8XSLTProcessor.h"
+#include "V8RGBColor.h"
+
+#if ENABLE(SVG_ANIMATION)
+#include "V8SVGAnimateColorElement.h"
+#include "V8SVGAnimateElement.h"
+#include "V8SVGAnimateTransformElement.h"
+#include "V8SVGAnimationElement.h"
+#include "V8SVGSetElement.h"
+#endif
+
+#if ENABLE(SVG_FILTERS)
+#include "V8SVGComponentTransferFunctionElement.h"
+#include "V8SVGFEBlendElement.h"
+#include "V8SVGFEColorMatrixElement.h"
+#include "V8SVGFEComponentTransferElement.h"
+#include "V8SVGFECompositeElement.h"
+#include "V8SVGFEDiffuseLightingElement.h"
+#include "V8SVGFEDisplacementMapElement.h"
+#include "V8SVGFEDistantLightElement.h"
+#include "V8SVGFEFloodElement.h"
+#include "V8SVGFEFuncAElement.h"
+#include "V8SVGFEFuncBElement.h"
+#include "V8SVGFEFuncGElement.h"
+#include "V8SVGFEFuncRElement.h"
+#include "V8SVGFEGaussianBlurElement.h"
+#include "V8SVGFEImageElement.h"
+#include "V8SVGFEMergeElement.h"
+#include "V8SVGFEMergeNodeElement.h"
+#include "V8SVGFEOffsetElement.h"
+#include "V8SVGFEPointLightElement.h"
+#include "V8SVGFESpecularLightingElement.h"
+#include "V8SVGFESpotLightElement.h"
+#include "V8SVGFETileElement.h"
+#include "V8SVGFETurbulenceElement.h"
+#include "V8SVGFilterElement.h"
+#endif
+
+#if ENABLE(SVG_FONTS)
+#include "V8SVGDefinitionSrcElement.h"
+#include "V8SVGFontFaceElement.h"
+#include "V8SVGFontFaceFormatElement.h"
+#include "V8SVGFontFaceNameElement.h"
+#include "V8SVGFontFaceSrcElement.h"
+#include "V8SVGFontFaceUriElement.h"
+#endif
+
+#if ENABLE(SVG_FOREIGN_OBJECT)
+#include "V8SVGForeignObjectElement.h"
+#endif
+
+#if ENABLE(SVG_USE)
+#include "V8SVGUseElement.h"
+#endif
+
+#if ENABLE(SVG)
+#include "V8SVGAElement.h"
+#include "V8SVGCircleElement.h"
+#include "V8SVGClipPathElement.h"
+#include "V8SVGCursorElement.h"
+#include "V8SVGDefsElement.h"
+#include "V8SVGDescElement.h"
+#include "V8SVGElement.h"
+#include "V8SVGEllipseElement.h"
+#include "V8SVGException.h"
+#include "V8SVGGElement.h"
+#include "V8SVGGradientElement.h"
+#include "V8SVGImageElement.h"
+#include "V8SVGLinearGradientElement.h"
+#include "V8SVGLineElement.h"
+#include "V8SVGMarkerElement.h"
+#include "V8SVGMaskElement.h"
+#include "V8SVGMetadataElement.h"
+#include "V8SVGPathElement.h"
+#include "V8SVGPatternElement.h"
+#include "V8SVGPolygonElement.h"
+#include "V8SVGPolylineElement.h"
+#include "V8SVGRadialGradientElement.h"
+#include "V8SVGRectElement.h"
+#include "V8SVGScriptElement.h"
+#include "V8SVGStopElement.h"
+#include "V8SVGStyleElement.h"
+#include "V8SVGSVGElement.h"
+#include "V8SVGSwitchElement.h"
+#include "V8SVGSymbolElement.h"
+#include "V8SVGTextContentElement.h"
+#include "V8SVGTextElement.h"
+#include "V8SVGTextPathElement.h"
+#include "V8SVGTextPositioningElement.h"
+#include "V8SVGTitleElement.h"
+#include "V8SVGTRefElement.h"
+#include "V8SVGTSpanElement.h"
+#include "V8SVGViewElement.h"
+#include "V8SVGAngle.h"
+#include "V8SVGAnimatedAngle.h"
+#include "V8SVGAnimatedBoolean.h"
+#include "V8SVGAnimatedEnumeration.h"
+#include "V8SVGAnimatedInteger.h"
+#include "V8SVGAnimatedLength.h"
+#include "V8SVGAnimatedLengthList.h"
+#include "V8SVGAnimatedNumber.h"
+#include "V8SVGAnimatedNumberList.h"
+#include "V8SVGAnimatedPoints.h"
+#include "V8SVGAnimatedPreserveAspectRatio.h"
+#include "V8SVGAnimatedRect.h"
+#include "V8SVGAnimatedString.h"
+#include "V8SVGAnimatedTransformList.h"
+#include "V8SVGColor.h"
+#include "V8SVGDocument.h"
+#include "V8SVGElementInstance.h"
+#include "V8SVGElementInstanceList.h"
+#include "V8SVGLength.h"
+#include "V8SVGLengthList.h"
+#include "V8SVGMatrix.h"
+#include "V8SVGNumber.h"
+#include "V8SVGNumberList.h"
+#include "V8SVGPaint.h"
+#include "V8SVGPathSeg.h"
+#include "V8SVGPathSegArcAbs.h"
+#include "V8SVGPathSegArcRel.h"
+#include "V8SVGPathSegClosePath.h"
+#include "V8SVGPathSegCurvetoCubicAbs.h"
+#include "V8SVGPathSegCurvetoCubicRel.h"
+#include "V8SVGPathSegCurvetoCubicSmoothAbs.h"
+#include "V8SVGPathSegCurvetoCubicSmoothRel.h"
+#include "V8SVGPathSegCurvetoQuadraticAbs.h"
+#include "V8SVGPathSegCurvetoQuadraticRel.h"
+#include "V8SVGPathSegCurvetoQuadraticSmoothAbs.h"
+#include "V8SVGPathSegCurvetoQuadraticSmoothRel.h"
+#include "V8SVGPathSegLinetoAbs.h"
+#include "V8SVGPathSegLinetoHorizontalAbs.h"
+#include "V8SVGPathSegLinetoHorizontalRel.h"
+#include "V8SVGPathSegLinetoRel.h"
+#include "V8SVGPathSegLinetoVerticalAbs.h"
+#include "V8SVGPathSegLinetoVerticalRel.h"
+#include "V8SVGPathSegList.h"
+#include "V8SVGPathSegMovetoAbs.h"
+#include "V8SVGPathSegMovetoRel.h"
+#include "V8SVGPoint.h"
+#include "V8SVGPointList.h"
+#include "V8SVGPreserveAspectRatio.h"
+#include "V8SVGRect.h"
+#include "V8SVGRenderingIntent.h"
+#include "V8SVGStringList.h"
+#include "V8SVGTransform.h"
+#include "V8SVGTransformList.h"
+#include "V8SVGUnitTypes.h"
+#include "V8SVGURIReference.h"
+#include "V8SVGZoomEvent.h"
+#endif
+
+namespace WebCore {
+
+FunctionTemplateFactory V8ClassIndex::GetFactory(V8WrapperType type) {
+ switch (type) {
+#define MAKE_CASE(type, name)\
+ case V8ClassIndex::type: return V8##name::GetTemplate;
+ WRAPPER_TYPES(MAKE_CASE)
+#undef MAKE_CASE
+ default: return NULL;
+ }
+}
+
+
+#define MAKE_CACHE(type, name)\
+ static v8::Persistent<v8::FunctionTemplate> name##_cache_;
+ ALL_WRAPPER_TYPES(MAKE_CACHE)
+#undef MAKE_CACHE
+
+
+v8::Persistent<v8::FunctionTemplate>* V8ClassIndex::GetCache(
+ V8WrapperType type) {
+ switch (type) {
+#define MAKE_CASE(type, name)\
+ case V8ClassIndex::type: return &name##_cache_;
+ ALL_WRAPPER_TYPES(MAKE_CASE)
+#undef MAKE_CASE
+ default:
+ ASSERT(false);
+ return NULL;
+ }
+}
+
+} // namespace WebCore
diff --git a/webkit/port/bindings/v8/v8_index.h b/webkit/port/bindings/v8/v8_index.h
new file mode 100644
index 0000000..7fc6041
--- /dev/null
+++ b/webkit/port/bindings/v8/v8_index.h
@@ -0,0 +1,422 @@
+// Copyright 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.
+
+#ifndef V8_INDEX_H__
+#define V8_INDEX_H__
+
+#include <v8.h>
+#include "PlatformString.h" // for WebCore::String
+
+namespace WebCore {
+
+class Node;
+class XMLHttpRequest;
+
+typedef v8::Persistent<v8::FunctionTemplate> (*FunctionTemplateFactory)();
+
+
+#define NODE_WRAPPER_TYPES(V) \
+ V(ATTR, Attr) \
+ V(CHARACTERDATA, CharacterData) \
+ V(CDATASECTION, CDATASection) \
+ V(COMMENT, Comment) \
+ V(DOCUMENT, Document) \
+ V(DOCUMENTFRAGMENT, DocumentFragment) \
+ V(DOCUMENTTYPE, DocumentType) \
+ V(ELEMENT, Element) \
+ V(ENTITY, Entity) \
+ V(ENTITYREFERENCE, EntityReference) \
+ V(EVENTTARGETNODE, EventTargetNode) \
+ V(HTMLDOCUMENT, HTMLDocument) \
+ V(NODE, Node) \
+ V(NOTATION, Notation) \
+ V(PROCESSINGINSTRUCTION, ProcessingInstruction) \
+ V(TEXT, Text)
+
+#define HTMLELEMENT_TYPES(V) \
+ V(HTMLANCHORELEMENT, HTMLAnchorElement) \
+ V(HTMLAPPLETELEMENT, HTMLAppletElement) \
+ V(HTMLAREAELEMENT, HTMLAreaElement) \
+ V(HTMLBASEELEMENT, HTMLBaseElement) \
+ V(HTMLBASEFONTELEMENT, HTMLBaseFontElement) \
+ V(HTMLBLOCKQUOTEELEMENT, HTMLBlockquoteElement) \
+ V(HTMLBODYELEMENT, HTMLBodyElement) \
+ V(HTMLBRELEMENT, HTMLBRElement) \
+ V(HTMLBUTTONELEMENT, HTMLButtonElement) \
+ V(HTMLCANVASELEMENT, HTMLCanvasElement) \
+ V(HTMLDIRECTORYELEMENT, HTMLDirectoryElement) \
+ V(HTMLDIVELEMENT, HTMLDivElement) \
+ V(HTMLDLISTELEMENT, HTMLDListElement) \
+ V(HTMLEMBEDELEMENT, HTMLEmbedElement) \
+ V(HTMLFIELDSETELEMENT, HTMLFieldSetElement) \
+ V(HTMLFONTELEMENT, HTMLFontElement) \
+ V(HTMLFORMELEMENT, HTMLFormElement) \
+ V(HTMLFRAMEELEMENT, HTMLFrameElement) \
+ V(HTMLFRAMESETELEMENT, HTMLFrameSetElement) \
+ V(HTMLHEADINGELEMENT, HTMLHeadingElement) \
+ V(HTMLHEADELEMENT, HTMLHeadElement) \
+ V(HTMLHRELEMENT, HTMLHRElement) \
+ V(HTMLHTMLELEMENT, HTMLHtmlElement) \
+ V(HTMLIFRAMEELEMENT, HTMLIFrameElement) \
+ V(HTMLIMAGEELEMENT, HTMLImageElement) \
+ V(HTMLINPUTELEMENT, HTMLInputElement) \
+ V(HTMLSELECTIONINPUTELEMENT, HTMLSelectionInputElement) \
+ V(HTMLISINDEXELEMENT, HTMLIsIndexElement) \
+ V(HTMLLABELELEMENT, HTMLLabelElement) \
+ V(HTMLLEGENDELEMENT, HTMLLegendElement) \
+ V(HTMLLIELEMENT, HTMLLIElement) \
+ V(HTMLLINKELEMENT, HTMLLinkElement) \
+ V(HTMLMAPELEMENT, HTMLMapElement) \
+ V(HTMLMARQUEEELEMENT, HTMLMarqueeElement) \
+ V(HTMLMENUELEMENT, HTMLMenuElement) \
+ V(HTMLMETAELEMENT, HTMLMetaElement) \
+ V(HTMLMODELEMENT, HTMLModElement) \
+ V(HTMLOBJECTELEMENT, HTMLObjectElement) \
+ V(HTMLOLISTELEMENT, HTMLOListElement) \
+ V(HTMLOPTGROUPELEMENT, HTMLOptGroupElement) \
+ V(HTMLOPTIONELEMENT, HTMLOptionElement) \
+ V(HTMLPARAGRAPHELEMENT, HTMLParagraphElement) \
+ V(HTMLPARAMELEMENT, HTMLParamElement) \
+ V(HTMLPREELEMENT, HTMLPreElement) \
+ V(HTMLQUOTEELEMENT, HTMLQuoteElement) \
+ V(HTMLSCRIPTELEMENT, HTMLScriptElement) \
+ V(HTMLSELECTELEMENT, HTMLSelectElement) \
+ V(HTMLSTYLEELEMENT, HTMLStyleElement) \
+ V(HTMLTABLECAPTIONELEMENT, HTMLTableCaptionElement) \
+ V(HTMLTABLECOLELEMENT, HTMLTableColElement) \
+ V(HTMLTABLEELEMENT, HTMLTableElement) \
+ V(HTMLTABLESECTIONELEMENT, HTMLTableSectionElement) \
+ V(HTMLTABLECELLELEMENT, HTMLTableCellElement) \
+ V(HTMLTABLEROWELEMENT, HTMLTableRowElement) \
+ V(HTMLTEXTAREAELEMENT, HTMLTextAreaElement) \
+ V(HTMLTITLEELEMENT, HTMLTitleElement) \
+ V(HTMLULISTELEMENT, HTMLUListElement) \
+ V(HTMLELEMENT, HTMLElement)
+
+#if ENABLE(SVG_ANIMATION)
+#define SVG_ANIMATION_ELEMENT_TYPES(V) \
+ V(SVGANIMATECOLORELEMENT, SVGAnimateColorElement) \
+ V(SVGANIMATEELEMENT, SVGAnimateElement) \
+ V(SVGANIMATETRANSFORMELEMENT, SVGAnimateTransformElement) \
+ V(SVGANIMATIONELEMENT, SVGAnimationElement) \
+ V(SVGSETELEMENT, SVGSetElement)
+#else
+#define SVG_ANIMATION_ELEMENT_TYPES(V)
+#endif
+
+#if ENABLE(SVG_FILTERS)
+#define SVG_FILTERS_ELEMENT_TYPES(V) \
+ V(SVGCOMPONENTTRANSFERFUNCTIONELEMENT, SVGComponentTransferFunctionElement)\
+ V(SVGFEBLENDELEMENT, SVGFEBlendElement) \
+ V(SVGFECOLORMATRIXELEMENT, SVGFEColorMatrixElement) \
+ V(SVGFECOMPONENTTRANSFERELEMENT, SVGFEComponentTransferElement) \
+ V(SVGFECOMPOSITEELEMENT, SVGFECompositeElement) \
+ V(SVGFEDIFFUSELIGHTINGELEMENT, SVGFEDiffuseLightingElement) \
+ V(SVGFEDISPLACEMENTMAPELEMENT, SVGFEDisplacementMapElement) \
+ V(SVGFEDISTANTLIGHTELEMENT, SVGFEDistantLightElement) \
+ V(SVGFEFLOODELEMENT, SVGFEFloodElement) \
+ V(SVGFEFUNCAELEMENT, SVGFEFuncAElement) \
+ V(SVGFEFUNCBELEMENT, SVGFEFuncBElement) \
+ V(SVGFEFUNCGELEMENT, SVGFEFuncGElement) \
+ V(SVGFEFUNCRELEMENT, SVGFEFuncRElement) \
+ V(SVGFEGAUSSIANBLURELEMENT, SVGFEGaussianBlurElement) \
+ V(SVGFEIMAGEELEMENT, SVGFEImageElement) \
+ V(SVGFEMERGEELEMENT, SVGFEMergeElement) \
+ V(SVGFEMERGENODEELEMENT, SVGFEMergeNodeElement) \
+ V(SVGFEOFFSETELEMENT, SVGFEOffsetElement) \
+ V(SVGFEPOINTLIGHTELEMENT, SVGFEPointLightElement) \
+ V(SVGFESPECULARLIGHTINGELEMENT, SVGFESpecularLightingElement) \
+ V(SVGFESPOTLIGHTELEMENT, SVGFESpotLightElement) \
+ V(SVGFETILEELEMENT, SVGFETileElement) \
+ V(SVGFETURBULENCEELEMENT, SVGFETurbulenceElement) \
+ V(SVGFILTERELEMENT, SVGFilterElement)
+#else
+#define SVG_FILTERS_ELEMENT_TYPES(V)
+#endif
+
+#if ENABLE(SVG_FONTS)
+#define SVG_FONTS_ELEMENT_TYPES(V) \
+ V(SVGDEFINITIONSRCELEMENT, SVGDefinitionSrcElement) \
+ V(SVGFONTFACEELEMENT, SVGFontFaceElement) \
+ V(SVGFONTFACEFORMATELEMENT, SVGFontFaceFormatElement) \
+ V(SVGFONTFACENAMEELEMENT, SVGFontFaceNameElement) \
+ V(SVGFONTFACESRCELEMENT, SVGFontFaceSrcElement) \
+ V(SVGFONTFACEURIELEMENT, SVGFontFaceUriElement)
+#else
+#define SVG_FONTS_ELEMENT_TYPES(V)
+#endif
+
+#if ENABLE(SVG_FOREIGN_OBJECT)
+#define SVG_FOREIGN_OBJECT_ELEMENT_TYPES(V) \
+ V(SVGFOREIGNOBJECTELEMENT, SVGForeignObjectElement)
+#else
+#define SVG_FOREIGN_OBJECT_ELEMENT_TYPES(V)
+#endif
+
+#if ENABLE(SVG_USE)
+#define SVG_USE_ELEMENT_TYPES(V) \
+ V(SVGUSEELEMENT, SVGUseElement)
+#else
+#define SVG_USE_ELEMENT_TYPES(V)
+#endif
+
+#if ENABLE(SVG)
+#define SVGELEMENT_TYPES(V) \
+ SVG_ANIMATION_ELEMENT_TYPES(V) \
+ SVG_FILTERS_ELEMENT_TYPES(V) \
+ SVG_FONTS_ELEMENT_TYPES(V) \
+ SVG_FOREIGN_OBJECT_ELEMENT_TYPES(V) \
+ SVG_USE_ELEMENT_TYPES(V) \
+ V(SVGAELEMENT, SVGAElement) \
+ V(SVGCIRCLEELEMENT, SVGCircleElement) \
+ V(SVGCLIPPATHELEMENT, SVGClipPathElement) \
+ V(SVGCURSORELEMENT, SVGCursorElement) \
+ V(SVGDEFSELEMENT, SVGDefsElement) \
+ V(SVGDESCELEMENT, SVGDescElement) \
+ V(SVGELLIPSEELEMENT, SVGEllipseElement) \
+ V(SVGGELEMENT, SVGGElement) \
+ V(SVGGRADIENTELEMENT, SVGGradientElement) \
+ V(SVGIMAGEELEMENT, SVGImageElement) \
+ V(SVGLINEARGRADIENTELEMENT, SVGLinearGradientElement) \
+ V(SVGLINEELEMENT, SVGLineElement) \
+ V(SVGMARKERELEMENT, SVGMarkerElement) \
+ V(SVGMASKELEMENT, SVGMaskElement) \
+ V(SVGMETADATAELEMENT, SVGMetadataElement) \
+ V(SVGPATHELEMENT, SVGPathElement) \
+ V(SVGPATTERNELEMENT, SVGPatternElement) \
+ V(SVGPOLYGONELEMENT, SVGPolygonElement) \
+ V(SVGPOLYLINEELEMENT, SVGPolylineElement) \
+ V(SVGRADIALGRADIENTELEMENT, SVGRadialGradientElement) \
+ V(SVGRECTELEMENT, SVGRectElement) \
+ V(SVGSCRIPTELEMENT, SVGScriptElement) \
+ V(SVGSTOPELEMENT, SVGStopElement) \
+ V(SVGSTYLEELEMENT, SVGStyleElement) \
+ V(SVGSVGELEMENT, SVGSVGElement) \
+ V(SVGSWITCHELEMENT, SVGSwitchElement) \
+ V(SVGSYMBOLELEMENT, SVGSymbolElement) \
+ V(SVGTEXTCONTENTELEMENT, SVGTextContentElement) \
+ V(SVGTEXTELEMENT, SVGTextElement) \
+ V(SVGTEXTPATHELEMENT, SVGTextPathElement) \
+ V(SVGTEXTPOSITIONINGELEMENT, SVGTextPositioningElement) \
+ V(SVGTITLEELEMENT, SVGTitleElement) \
+ V(SVGTREFELEMENT, SVGTRefElement) \
+ V(SVGTSPANELEMENT, SVGTSpanElement) \
+ V(SVGVIEWELEMENT, SVGViewElement) \
+ V(SVGELEMENT, SVGElement)
+#endif
+
+
+#define NONNODE_WRAPPER_TYPES(V) \
+ V(BARINFO, BarInfo) \
+ V(CANVASGRADIENT, CanvasGradient) \
+ V(CANVASPATTERN, CanvasPattern) \
+ V(CANVASRENDERINGCONTEXT2D, CanvasRenderingContext2D) \
+ V(CLIPBOARD, Clipboard) \
+ V(CONSOLE, Console) \
+ V(COUNTER, Counter) \
+ V(CSSCHARSETRULE, CSSCharsetRule) \
+ V(CSSFONTFACERULE, CSSFontFaceRule) \
+ V(CSSIMPORTRULE, CSSImportRule) \
+ V(CSSMEDIARULE, CSSMediaRule) \
+ V(CSSPAGERULE, CSSPageRule) \
+ V(CSSPRIMITIVEVALUE, CSSPrimitiveValue) \
+ V(CSSRULE, CSSRule) \
+ V(CSSRULELIST, CSSRuleList) \
+ V(CSSSTYLEDECLARATION, CSSStyleDeclaration) \
+ V(CSSSTYLERULE, CSSStyleRule) \
+ V(CSSSTYLESHEET, CSSStyleSheet) \
+ V(CSSVALUE, CSSValue) \
+ V(CSSVALUELIST, CSSValueList) \
+ V(DOMCOREEXCEPTION, DOMCoreException) \
+ V(DOMIMPLEMENTATION, DOMImplementation) \
+ V(DOMPARSER, DOMParser) \
+ V(DOMSELECTION, DOMSelection) \
+ V(DOMWINDOW, DOMWindow) \
+ V(EVENT, Event) \
+ V(EVENTEXCEPTION, EventException) \
+ V(HISTORY, History) \
+ V(UNDETECTABLEHTMLCOLLECTION, UndetectableHTMLCollection) \
+ V(HTMLCOLLECTION, HTMLCollection) \
+ V(HTMLOPTIONSCOLLECTION, HTMLOptionsCollection) \
+ V(INSPECTORCONTROLLER, InspectorController) \
+ V(KEYBOARDEVENT, KeyboardEvent) \
+ V(LOCATION, Location) \
+ V(MEDIALIST, MediaList) \
+ V(MESSAGEEVENT, MessageEvent) \
+ V(MIMETYPE, MimeType) \
+ V(MIMETYPEARRAY, MimeTypeArray) \
+ V(MOUSEEVENT, MouseEvent) \
+ V(MUTATIONEVENT, MutationEvent) \
+ V(NAMEDNODEMAP, NamedNodeMap) \
+ V(NAVIGATOR, Navigator) \
+ V(NODEFILTER, NodeFilter) \
+ V(NODEITERATOR, NodeIterator) \
+ V(NODELIST, NodeList) \
+ V(OVERFLOWEVENT, OverflowEvent) \
+ V(PLUGIN, Plugin) \
+ V(PLUGINARRAY, PluginArray) \
+ V(PROGRESSEVENT, ProgressEvent) \
+ V(RANGE, Range) \
+ V(RANGEEXCEPTION, RangeException) \
+ V(RECT, Rect) \
+ V(RGBCOLOR, RGBColor) \
+ V(SCREEN, Screen) \
+ V(STYLESHEET, StyleSheet) \
+ V(STYLESHEETLIST, StyleSheetList) \
+ V(TEXTEVENT, TextEvent) \
+ V(TREEWALKER, TreeWalker) \
+ V(UIEVENT, UIEvent) \
+ V(WHEELEVENT, WheelEvent) \
+ V(XMLHTTPREQUEST, XMLHttpRequest) \
+ V(XMLHTTPREQUESTEXCEPTION, XMLHttpRequestException) \
+ V(XMLSERIALIZER, XMLSerializer) \
+ V(XPATHEVALUATOR, XPathEvaluator) \
+ V(XPATHEXCEPTION, XPathException) \
+ V(XPATHEXPRESSION, XPathExpression) \
+ V(XPATHNSRESOLVER, XPathNSResolver) \
+ V(XPATHRESULT, XPathResult) \
+ V(XSLTPROCESSOR, XSLTProcessor)
+
+#if ENABLE(SVG)
+#define SVGNODE_WRAPPER_TYPES(V) \
+ V(SVGDOCUMENT, SVGDocument)
+
+#define SVGNONNODE_WRAPPER_TYPES(V) \
+ V(SVGANGLE, SVGAngle) \
+ V(SVGANIMATEDANGLE, SVGAnimatedAngle) \
+ V(SVGANIMATEDBOOLEAN, SVGAnimatedBoolean) \
+ V(SVGANIMATEDENUMERATION, SVGAnimatedEnumeration) \
+ V(SVGANIMATEDINTEGER, SVGAnimatedInteger) \
+ V(SVGANIMATEDLENGTH, SVGAnimatedLength) \
+ V(SVGANIMATEDLENGTHLIST, SVGAnimatedLengthList) \
+ V(SVGANIMATEDNUMBER, SVGAnimatedNumber) \
+ V(SVGANIMATEDNUMBERLIST, SVGAnimatedNumberList) \
+ V(SVGANIMATEDPOINTS, SVGAnimatedPoints) \
+ V(SVGANIMATEDPRESERVEASPECTRATIO, SVGAnimatedPreserveAspectRatio) \
+ V(SVGANIMATEDRECT, SVGAnimatedRect) \
+ V(SVGANIMATEDSTRING, SVGAnimatedString) \
+ V(SVGANIMATEDTRANSFORMLIST, SVGAnimatedTransformList) \
+ V(SVGCOLOR, SVGColor) \
+ V(SVGELEMENTINSTANCE, SVGElementInstance) \
+ V(SVGELEMENTINSTANCELIST, SVGElementInstanceList) \
+ V(SVGEXCEPTION, SVGException) \
+ V(SVGLENGTH, SVGLength) \
+ V(SVGLENGTHLIST, SVGLengthList) \
+ V(SVGMATRIX, SVGMatrix) \
+ V(SVGNUMBER, SVGNumber) \
+ V(SVGNUMBERLIST, SVGNumberList) \
+ V(SVGPAINT, SVGPaint) \
+ V(SVGPATHSEG, SVGPathSeg) \
+ V(SVGPATHSEGARCABS, SVGPathSegArcAbs) \
+ V(SVGPATHSEGARCREL, SVGPathSegArcRel) \
+ V(SVGPATHSEGCLOSEPATH, SVGPathSegClosePath) \
+ V(SVGPATHSEGCURVETOCUBICABS, SVGPathSegCurvetoCubicAbs) \
+ V(SVGPATHSEGCURVETOCUBICREL, SVGPathSegCurvetoCubicRel) \
+ V(SVGPATHSEGCURVETOCUBICSMOOTHABS, SVGPathSegCurvetoCubicSmoothAbs) \
+ V(SVGPATHSEGCURVETOCUBICSMOOTHREL, SVGPathSegCurvetoCubicSmoothRel) \
+ V(SVGPATHSEGCURVETOQUADRATICABS, SVGPathSegCurvetoQuadraticAbs) \
+ V(SVGPATHSEGCURVETOQUADRATICREL, SVGPathSegCurvetoQuadraticRel) \
+ V(SVGPATHSEGCURVETOQUADRATICSMOOTHABS, SVGPathSegCurvetoQuadraticSmoothAbs)\
+ V(SVGPATHSEGCURVETOQUADRATICSMOOTHREL, SVGPathSegCurvetoQuadraticSmoothRel)\
+ V(SVGPATHSEGLINETOABS, SVGPathSegLinetoAbs) \
+ V(SVGPATHSEGLINETOHORIZONTALABS, SVGPathSegLinetoHorizontalAbs) \
+ V(SVGPATHSEGLINETOHORIZONTALREL, SVGPathSegLinetoHorizontalRel) \
+ V(SVGPATHSEGLINETOREL, SVGPathSegLinetoRel) \
+ V(SVGPATHSEGLINETOVERTICALABS, SVGPathSegLinetoVerticalAbs) \
+ V(SVGPATHSEGLINETOVERTICALREL, SVGPathSegLinetoVerticalRel) \
+ V(SVGPATHSEGLIST, SVGPathSegList) \
+ V(SVGPATHSEGMOVETOABS, SVGPathSegMovetoAbs) \
+ V(SVGPATHSEGMOVETOREL, SVGPathSegMovetoRel) \
+ V(SVGPOINT, SVGPoint) \
+ V(SVGPOINTLIST, SVGPointList) \
+ V(SVGPRESERVEASPECTRATIO, SVGPreserveAspectRatio) \
+ V(SVGRECT, SVGRect) \
+ V(SVGRENDERINGINTENT, SVGRenderingIntent) \
+ V(SVGSTRINGLIST, SVGStringList) \
+ V(SVGTRANSFORM, SVGTransform) \
+ V(SVGTRANSFORMLIST, SVGTransformList) \
+ V(SVGUNITTYPES, SVGUnitTypes) \
+ V(SVGURIREFERENCE, SVGURIReference) \
+ V(SVGZOOMEVENT, SVGZoomEvent)
+#endif
+
+// EVENTTARGET, EVENTLISTENER, and NPOBJECT do not have V8 wrappers.
+#define NO_WRAPPER_TYPES(V) \
+ V(EVENTTARGET, EventTarget) \
+ V(EVENTLISTENER, EventListener) \
+ V(NPOBJECT, NPObject)
+
+#if ENABLE(SVG)
+#define WRAPPER_TYPES(V) \
+ NODE_WRAPPER_TYPES(V) \
+ HTMLELEMENT_TYPES(V) \
+ NONNODE_WRAPPER_TYPES(V) \
+ SVGNODE_WRAPPER_TYPES(V) \
+ SVGELEMENT_TYPES(V) \
+ SVGNONNODE_WRAPPER_TYPES(V)
+#else
+#define WRAPPER_TYPES(V) \
+ NODE_WRAPPER_TYPES(V) \
+ HTMLELEMENT_TYPES(V) \
+ NONNODE_WRAPPER_TYPES(V)
+#endif
+
+#define ALL_WRAPPER_TYPES(V) \
+ WRAPPER_TYPES(V) \
+ NO_WRAPPER_TYPES(V)
+
+class V8ClassIndex {
+ public:
+ // Type must start at non-negative numbers. See ToInt, FromInt.
+ enum V8WrapperType {
+ INVALID_CLASS_INDEX = 0,
+#define DEFINE_ENUM(name, type) name,
+ALL_WRAPPER_TYPES(DEFINE_ENUM)
+#undef DEFINE_ENUM
+ CLASSINDEX_END,
+ };
+ static inline V8WrapperType ToWrapperType(v8::Handle<v8::Value> obj) {
+ return static_cast<V8WrapperType>(
+ reinterpret_cast<int>(v8::Handle<v8::External>::Cast(obj)->Value()));
+ }
+
+ static int ToInt(V8WrapperType type) { return static_cast<int>(type); }
+
+ static V8WrapperType FromInt(int v) {
+ ASSERT(INVALID_CLASS_INDEX <= v && v < CLASSINDEX_END);
+ return static_cast<V8WrapperType>(v);
+ }
+
+ static FunctionTemplateFactory GetFactory(V8WrapperType type);
+ // Returns a field to be used as cache for the template for the given type
+ static v8::Persistent<v8::FunctionTemplate>* GetCache(V8WrapperType type);
+};
+}
+
+#endif // V8_INDEX_H__
diff --git a/webkit/port/bindings/v8/v8_nodefilter.cpp b/webkit/port/bindings/v8/v8_nodefilter.cpp
new file mode 100644
index 0000000..c8846ab
--- /dev/null
+++ b/webkit/port/bindings/v8/v8_nodefilter.cpp
@@ -0,0 +1,84 @@
+// 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_nodefilter.h"
+#include "v8_proxy.h"
+#include "NodeFilter.h"
+#include "Node.h"
+
+namespace WebCore {
+
+V8NodeFilterCondition::V8NodeFilterCondition(v8::Handle<v8::Value> filter) {
+ m_filter = v8::Persistent<v8::Value>::New(filter);
+#ifndef NDEBUG
+ V8Proxy::RegisterGlobalHandle(NODE_FILTER, this, m_filter);
+#endif
+}
+
+V8NodeFilterCondition::~V8NodeFilterCondition() {
+#ifndef NDEBUG
+ V8Proxy::UnregisterGlobalHandle(this, m_filter);
+#endif
+ m_filter.Dispose();
+ m_filter.Clear();
+}
+
+short V8NodeFilterCondition::acceptNode(Node* node) const {
+ ASSERT(v8::Context::InContext());
+
+ if (!m_filter->IsFunction()) return NodeFilter::FILTER_ACCEPT;
+
+ v8::TryCatch exception_catcher;
+
+ 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::Value>* args = new v8::Handle<v8::Value>[1];
+ args[0] = V8Proxy::ToV8Object(V8ClassIndex::NODE, node);
+
+ V8Proxy* proxy = V8Proxy::retrieve();
+ ASSERT(proxy);
+
+ v8::Handle<v8::Value> result =
+ 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()) {
+ return NodeFilter::FILTER_REJECT;
+ }
+
+ ASSERT(!result.IsEmpty());
+
+ return result->Int32Value();
+}
+
+} // namespace WebCore
diff --git a/webkit/port/bindings/v8/v8_nodefilter.h b/webkit/port/bindings/v8/v8_nodefilter.h
new file mode 100644
index 0000000..01f2023
--- /dev/null
+++ b/webkit/port/bindings/v8/v8_nodefilter.h
@@ -0,0 +1,54 @@
+// Copyright 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.
+
+#ifndef V8_NODEFILTER_H__
+#define V8_NODEFILTER_H__
+
+#include <v8.h>
+#include "NodeFilterCondition.h"
+
+// NodeFilter is a JavaScript function that takes a Node as parameter
+// and returns a short (ACCEPT, SKIP, REJECT) as the result.
+namespace WebCore {
+class Node;
+
+// NodeFilterCondition is a wrapper around a NodeFilter JS function.
+class V8NodeFilterCondition : public NodeFilterCondition {
+ public:
+ explicit V8NodeFilterCondition(v8::Handle<v8::Value> filter);
+ virtual ~V8NodeFilterCondition();
+
+ virtual short acceptNode(Node* node) const;
+
+ private:
+ mutable v8::Persistent<v8::Value> m_filter;
+};
+
+} // namesapce WebCore
+#endif // V8_NODEFILTER_H__
diff --git a/webkit/port/bindings/v8/v8_np_utils.cpp b/webkit/port/bindings/v8/v8_np_utils.cpp
new file mode 100644
index 0000000..06e02b8
--- /dev/null
+++ b/webkit/port/bindings/v8/v8_np_utils.cpp
@@ -0,0 +1,126 @@
+// 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_np_utils.h"
+
+#include "base/string_util.h"
+#include "DOMWindow.h"
+#include "Frame.h"
+#include "npruntime_priv.h"
+#include "np_v8object.h"
+#include "v8_npobject.h"
+#include "v8_proxy.h"
+
+void ConvertV8ObjectToNPVariant(v8::Local<v8::Value> object, NPObject *owner,
+ NPVariant* result) {
+ VOID_TO_NPVARIANT(*result);
+
+ // It is really the caller's responsibility to deal with the empty handle
+ // case because there could be different actions to take in different
+ // contexts.
+ ASSERT(!object.IsEmpty());
+
+ if (object.IsEmpty()) return;
+
+ if (object->IsNumber()) {
+ DOUBLE_TO_NPVARIANT(object->NumberValue(), *result);
+
+ } else if (object->IsBoolean()) {
+ BOOLEAN_TO_NPVARIANT(object->BooleanValue(), *result);
+
+ } else if (object->IsNull()) {
+ NULL_TO_NPVARIANT(*result);
+
+ } else if (object->IsUndefined()) {
+ VOID_TO_NPVARIANT(*result);
+
+ } else if (object->IsString()) {
+ v8::Handle<v8::String> str = object->ToString();
+ uint16_t *buf = new uint16_t[str->Length()+1];
+ str->Write(buf);
+ std::string utf8 = WideToUTF8(reinterpret_cast<wchar_t*>(buf));
+ char* utf8_chars = strdup(utf8.c_str());
+ STRINGN_TO_NPVARIANT(utf8_chars, utf8.length(), *result);
+ delete[] buf;
+
+ } else if (object->IsObject()) {
+ WebCore::DOMWindow* window = WebCore::V8Proxy::retrieveWindow();
+ NPObject* npobject = NPN_CreateScriptObject(
+ 0, v8::Handle<v8::Object>::Cast(object), window);
+ if (npobject) {
+ _NPN_RegisterObject(npobject, owner);
+ }
+ OBJECT_TO_NPVARIANT(npobject, *result);
+ }
+}
+
+
+v8::Handle<v8::Value> ConvertNPVariantToV8Object(const NPVariant* variant,
+ NPObject* npobject) {
+ NPVariantType type = variant->type;
+
+ if (type == NPVariantType_Int32) {
+ return v8::Integer::New(NPVARIANT_TO_INT32(*variant));
+ }
+ if (type == NPVariantType_Double) {
+ return v8::Number::New(NPVARIANT_TO_DOUBLE(*variant));
+ }
+ if (type == NPVariantType_Bool) {
+ return NPVARIANT_TO_BOOLEAN(*variant) ? v8::True() : v8::False();
+ }
+ if (type == NPVariantType_Null) {
+ return v8::Null();
+ }
+ if (type == NPVariantType_Void) {
+ return v8::Undefined();
+ }
+ if (type == NPVariantType_String) {
+ NPString src = NPVARIANT_TO_STRING(*variant);
+ return v8::String::New(src.UTF8Characters, src.UTF8Length);
+ }
+ if (type == NPVariantType_Object) {
+ NPObject* obj = NPVARIANT_TO_OBJECT(*variant);
+ if (obj->_class == NPScriptObjectClass) {
+ return reinterpret_cast<V8NPObject*>(obj)->v8_object;
+ }
+ return CreateV8ObjectForNPObject(obj, npobject);
+ }
+ return v8::Undefined();
+}
+
+// Helper function to create an NPN String Identifier from a v8 string.
+NPIdentifier GetStringIdentifier(v8::Handle<v8::String> str) {
+ char *buf = new char[str->Length() + 1];
+ str->WriteAscii(buf);
+ NPIdentifier ident = NPN_GetStringIdentifier(buf);
+ delete[] buf;
+ return ident;
+}
diff --git a/webkit/port/bindings/v8/v8_np_utils.h b/webkit/port/bindings/v8/v8_np_utils.h
new file mode 100644
index 0000000..5124571
--- /dev/null
+++ b/webkit/port/bindings/v8/v8_np_utils.h
@@ -0,0 +1,54 @@
+// Copyright 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.
+
+#ifndef V8_NP_UTILS_H__
+#define V8_NP_UTILS_H__
+
+#include <v8.h>
+#include "bindings/npruntime.h"
+
+namespace WebCore {
+ class Frame;
+}
+
+// Convert a V8 Value of any type (string, bool, object, etc) to a NPVariant.
+void ConvertV8ObjectToNPVariant(v8::Local<v8::Value> object, NPObject *owner,
+ NPVariant* result);
+
+// Convert a NPVariant (string, bool, object, etc) back to a V8 Value.
+// The owner object is the NPObject which relates to the object, if the object
+// is an Object. The created NPObject will be tied to the lifetime of the
+// owner.
+v8::Handle<v8::Value> ConvertNPVariantToV8Object(const NPVariant* value,
+ NPObject* owner);
+
+// Helper function to create an NPN String Identifier from a v8 string.
+NPIdentifier GetStringIdentifier(v8::Handle<v8::String> str);
+
+#endif // V8_NP_UTILS_H__
diff --git a/webkit/port/bindings/v8/v8_npobject.cpp b/webkit/port/bindings/v8/v8_npobject.cpp
new file mode 100644
index 0000000..eecc753
--- /dev/null
+++ b/webkit/port/bindings/v8/v8_npobject.cpp
@@ -0,0 +1,364 @@
+// 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_helpers.h"
+#include "v8_npobject.h"
+#include "v8_np_utils.h"
+#include "np_v8object.h"
+#include "npruntime_priv.h"
+#include "v8_proxy.h"
+#include "dom_wrapper_map.h"
+#include "HTMLPlugInElement.h"
+#include "V8HTMLAppletElement.h"
+#include "V8HTMLEmbedElement.h"
+#include "V8HTMLObjectElement.h"
+
+using namespace WebCore;
+
+enum InvokeFunctionType {
+ INVOKE_METHOD = 1,
+ INVOKE_DEFAULT = 2
+};
+
+// TODO(mbelshe): need comments.
+// Params: holder could be HTMLEmbedElement or NPObject
+static v8::Handle<v8::Value> NPObjectInvokeImpl(
+ const v8::Arguments& args, InvokeFunctionType func_id) {
+ NPObject* npobject;
+
+ // These three types are subtypes of HTMLPlugInElement.
+ if (V8HTMLAppletElement::HasInstance(args.Holder()) ||
+ V8HTMLEmbedElement::HasInstance(args.Holder()) ||
+ V8HTMLObjectElement::HasInstance(args.Holder())) {
+ // The holder object is a subtype of HTMLPlugInElement.
+ HTMLPlugInElement* imp = V8Proxy::FastToNativeObject<HTMLPlugInElement>(
+ V8ClassIndex::NODE, args.Holder());
+ v8::Handle<v8::Object> instance = imp->getInstance();
+ npobject = V8Proxy::ToNativeObject<NPObject>(
+ V8ClassIndex::NPOBJECT, instance);
+
+ } else {
+ // The holder object is not a subtype of HTMLPlugInElement, it
+ // must be an NPObject which has three internal fields.
+ ASSERT(args.Holder()->InternalFieldCount() == 3);
+ npobject = V8Proxy::ToNativeObject<NPObject>(
+ V8ClassIndex::NPOBJECT, args.Holder());
+ }
+
+ // Verify that our wrapper wasn't using a NPObject which
+ // has already been deleted.
+ if (!npobject || !_NPN_IsAlive(npobject)) {
+ V8Proxy::ThrowError(V8Proxy::REFERENCE_ERROR, "NPObject deleted");
+ return v8::Undefined();
+ }
+
+ // wrap up parameters
+ int argc = args.Length();
+ NPVariant* np_args = new NPVariant[argc];
+
+ for (int i = 0; i < argc; i++) {
+ ConvertV8ObjectToNPVariant(args[i], npobject, &np_args[i]);
+ }
+
+ NPVariant result;
+ VOID_TO_NPVARIANT(result);
+
+ switch (func_id) {
+ case INVOKE_METHOD:
+ if (npobject->_class->invoke) {
+ v8::Handle<v8::String> function_name(v8::String::Cast(*args.Data()));
+ NPIdentifier ident = GetStringIdentifier(function_name);
+ npobject->_class->invoke(npobject, ident, np_args, argc, &result);
+ }
+ break;
+ case INVOKE_DEFAULT:
+ if (npobject->_class->invokeDefault) {
+ npobject->_class->invokeDefault(npobject, np_args, argc, &result);
+ }
+ break;
+ default:
+ break;
+ }
+
+ for (int i=0; i < argc; i++) {
+ NPN_ReleaseVariantValue(&np_args[i]);
+ }
+ delete[] np_args;
+
+ // unwrap return values
+ v8::Handle<v8::Value> rv = ConvertNPVariantToV8Object(&result, npobject);
+ NPN_ReleaseVariantValue(&result);
+
+ return rv;
+}
+
+
+v8::Handle<v8::Value> NPObjectMethodHandler(const v8::Arguments& args) {
+ return NPObjectInvokeImpl(args, INVOKE_METHOD);
+}
+
+
+v8::Handle<v8::Value> NPObjectInvokeDefaultHandler(const v8::Arguments& args) {
+ return NPObjectInvokeImpl(args, INVOKE_DEFAULT);
+}
+
+
+static void WeakTemplateCallback(v8::Persistent<v8::Object> obj, void* param);
+
+// NPIdentifier is PrivateIdentifier*.
+static WeakReferenceMap<PrivateIdentifier, v8::FunctionTemplate> \
+ static_template_map(&WeakTemplateCallback);
+
+static void WeakTemplateCallback(v8::Persistent<v8::Object> obj,
+ void* param) {
+ PrivateIdentifier* iden = static_cast<PrivateIdentifier*>(param);
+ ASSERT(iden != NULL);
+ ASSERT(static_template_map.contains(iden));
+
+ static_template_map.forget(iden);
+}
+
+
+static v8::Handle<v8::Value> NPObjectGetProperty(v8::Local<v8::Object> self,
+ NPIdentifier ident,
+ v8::Local<v8::Value> key) {
+ NPObject* npobject = V8Proxy::ToNativeObject<NPObject>(V8ClassIndex::NPOBJECT,
+ self);
+
+ // Verify that our wrapper wasn't using a NPObject which
+ // has already been deleted.
+ if (!npobject || !_NPN_IsAlive(npobject)) {
+ V8Proxy::ThrowError(V8Proxy::REFERENCE_ERROR, "NPObject deleted");
+ return v8::Handle<v8::Value>();
+ }
+
+ if (npobject->_class->hasProperty &&
+ npobject->_class->hasProperty(npobject, ident) &&
+ npobject->_class->getProperty) {
+ NPVariant result;
+ VOID_TO_NPVARIANT(result);
+ if (!npobject->_class->getProperty(npobject, ident, &result)) {
+ return v8::Handle<v8::Value>();
+ }
+
+ v8::Handle<v8::Value> rv = ConvertNPVariantToV8Object(&result, npobject);
+ NPN_ReleaseVariantValue(&result);
+ return rv;
+
+ } else if (key->IsString() &&
+ npobject->_class->hasMethod &&
+ npobject->_class->hasMethod(npobject, ident)) {
+ PrivateIdentifier* id = static_cast<PrivateIdentifier*>(ident);
+ v8::Persistent<v8::FunctionTemplate> desc = static_template_map.get(id);
+ // Cache templates using identifier as the key.
+ if (desc.IsEmpty()) {
+ // Create a new template
+ v8::Local<v8::FunctionTemplate> temp = v8::FunctionTemplate::New();
+ temp->SetCallHandler(NPObjectMethodHandler, key);
+ desc = v8::Persistent<v8::FunctionTemplate>::New(temp);
+ static_template_map.set(id, desc);
+ }
+
+ // FunctionTemplate caches function for each context.
+ v8::Local<v8::Function> func = desc->GetFunction();
+ func->SetName(v8::Handle<v8::String>::Cast(key));
+ return func;
+ }
+
+ return v8::Handle<v8::Value>();
+}
+
+v8::Handle<v8::Value> NPObjectNamedPropertyGetter(v8::Local<v8::String> name,
+ const v8::AccessorInfo& info) {
+ NPIdentifier ident = GetStringIdentifier(name);
+ return NPObjectGetProperty(info.Holder(), ident, name);
+}
+
+v8::Handle<v8::Value> NPObjectIndexedPropertyGetter(uint32_t index,
+ const v8::AccessorInfo& info) {
+ NPIdentifier ident = NPN_GetIntIdentifier(index);
+ return NPObjectGetProperty(info.Holder(), ident, v8::Number::New(index));
+}
+
+v8::Handle<v8::Value> NPObjectGetNamedProperty(v8::Local<v8::Object> self,
+ v8::Local<v8::String> name) {
+ NPIdentifier ident = GetStringIdentifier(name);
+ return NPObjectGetProperty(self, ident, name);
+}
+
+v8::Handle<v8::Value> NPObjectGetIndexedProperty(v8::Local<v8::Object> self,
+ uint32_t index) {
+ NPIdentifier ident = NPN_GetIntIdentifier(index);
+ return NPObjectGetProperty(self, ident, v8::Number::New(index));
+}
+
+static v8::Handle<v8::Value> NPObjectSetProperty(v8::Local<v8::Object> self,
+ NPIdentifier ident,
+ v8::Local<v8::Value> value) {
+ NPObject* npobject = V8Proxy::ToNativeObject<NPObject>(V8ClassIndex::NPOBJECT,
+ self);
+
+ // Verify that our wrapper wasn't using a NPObject which
+ // has already been deleted.
+ if (!npobject || !_NPN_IsAlive(npobject)) {
+ V8Proxy::ThrowError(V8Proxy::REFERENCE_ERROR, "NPObject deleted");
+ return value; // intercepted, but an exception was thrown
+ }
+
+ if (npobject->_class->hasProperty &&
+ npobject->_class->hasProperty(npobject, ident) &&
+ npobject->_class->setProperty) {
+ NPVariant npvalue;
+ VOID_TO_NPVARIANT(npvalue);
+ ConvertV8ObjectToNPVariant(value, npobject, &npvalue);
+ bool succ = npobject->_class->setProperty(npobject, ident, &npvalue);
+ NPN_ReleaseVariantValue(&npvalue);
+ if (succ) return value; // intercept the call
+ }
+ return v8::Local<v8::Value>(); // do not intercept the call
+}
+
+
+v8::Handle<v8::Value> NPObjectNamedPropertySetter(v8::Local<v8::String> name,
+ v8::Local<v8::Value> value,
+ const v8::AccessorInfo& info) {
+ NPIdentifier ident = GetStringIdentifier(name);
+ return NPObjectSetProperty(info.Holder(), ident, value);
+}
+
+
+v8::Handle<v8::Value> NPObjectIndexedPropertySetter(uint32_t index,
+ v8::Local<v8::Value> value,
+ const v8::AccessorInfo& info) {
+ NPIdentifier ident = NPN_GetIntIdentifier(index);
+ return NPObjectSetProperty(info.Holder(), ident, value);
+}
+
+v8::Handle<v8::Value> NPObjectSetNamedProperty(v8::Local<v8::Object> self,
+ v8::Local<v8::String> name,
+ v8::Local<v8::Value> value) {
+ NPIdentifier ident = GetStringIdentifier(name);
+ return NPObjectSetProperty(self, ident, value);
+}
+
+v8::Handle<v8::Value> NPObjectSetIndexedProperty(v8::Local<v8::Object> self,
+ uint32_t index,
+ v8::Local<v8::Value> value) {
+ NPIdentifier ident = NPN_GetIntIdentifier(index);
+ return NPObjectSetProperty(self, ident, value);
+}
+
+
+static void WeakNPObjectCallback(v8::Persistent<v8::Object> obj, void* param);
+
+static DOMWrapperMap<NPObject> static_npobject_map(&WeakNPObjectCallback);
+
+static void WeakNPObjectCallback(v8::Persistent<v8::Object> obj,
+ void* param) {
+ NPObject* npobject = static_cast<NPObject*>(param);
+ ASSERT(static_npobject_map.contains(npobject));
+ ASSERT(npobject != NULL);
+
+ // Must remove from our map before calling NPN_ReleaseObject().
+ // NPN_ReleaseObject can call ForgetV8ObjectForNPObject, which
+ // uses the table as well.
+ static_npobject_map.forget(npobject);
+
+ if (_NPN_IsAlive(npobject))
+ NPN_ReleaseObject(npobject);
+}
+
+
+v8::Local<v8::Object> CreateV8ObjectForNPObject(NPObject* object,
+ NPObject* root) {
+ static v8::Persistent<v8::FunctionTemplate> np_object_desc;
+
+ ASSERT(v8::Context::InContext());
+
+ // If this is a v8 object, just return it.
+ if (object->_class == NPScriptObjectClass) {
+ V8NPObject* v8npobject = reinterpret_cast<V8NPObject*>(object);
+ return v8::Local<v8::Object>::New(v8npobject->v8_object);
+ }
+
+ // If we've already wrapped this object, just return it.
+ if (static_npobject_map.contains(object))
+ return v8::Local<v8::Object>::New(static_npobject_map.get(object));
+
+ // TODO: we should create a Wrapper type as a subclass of JSObject.
+ // It has two internal fields, field 0 is the wrapped pointer,
+ // and field 1 is the type. There should be an api function that
+ // returns unused type id.
+ // The same Wrapper type can be used by DOM bindings.
+ if (np_object_desc.IsEmpty()) {
+ np_object_desc =
+ v8::Persistent<v8::FunctionTemplate>::New(v8::FunctionTemplate::New());
+ np_object_desc->InstanceTemplate()->SetInternalFieldCount(3);
+ np_object_desc->InstanceTemplate()->SetNamedPropertyHandler(
+ NPObjectNamedPropertyGetter, NPObjectNamedPropertySetter);
+ np_object_desc->InstanceTemplate()->SetIndexedPropertyHandler(
+ NPObjectIndexedPropertyGetter, NPObjectIndexedPropertySetter);
+ np_object_desc->InstanceTemplate()->SetCallAsFunctionHandler(
+ NPObjectInvokeDefaultHandler);
+ }
+
+ v8::Handle<v8::Function> func = np_object_desc->GetFunction();
+ v8::Local<v8::Object> value = SafeAllocation::NewInstance(func);
+
+ // If we were unable to allocate the instance we avoid wrapping
+ // and registering the NP object.
+ if (value.IsEmpty())
+ return value;
+
+ WrapNPObject(value, object);
+
+ // KJS retains the object as part of its wrapper (see Bindings::CInstance)
+ NPN_RetainObject(object);
+
+ _NPN_RegisterObject(object, root);
+
+ // Maintain a weak pointer for v8 so we can cleanup the object.
+ v8::Persistent<v8::Object> weak_ref = v8::Persistent<v8::Object>::New(value);
+ static_npobject_map.set(object, weak_ref);
+
+ return value;
+}
+
+void ForgetV8ObjectForNPObject(NPObject* object) {
+ if (static_npobject_map.contains(object)) {
+ v8::HandleScope scope;
+ v8::Persistent<v8::Object> handle(static_npobject_map.get(object));
+ WebCore::V8Proxy::SetDOMWrapper(handle,
+ WebCore::V8ClassIndex::NPOBJECT, NULL);
+ static_npobject_map.forget(object);
+ NPN_ReleaseObject(object);
+ }
+}
diff --git a/webkit/port/bindings/v8/v8_npobject.h b/webkit/port/bindings/v8/v8_npobject.h
new file mode 100644
index 0000000..3ff7d31
--- /dev/null
+++ b/webkit/port/bindings/v8/v8_npobject.h
@@ -0,0 +1,79 @@
+// Copyright 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.
+
+#ifndef V8_NPOBJECT_H__
+#define V8_NPOBJECT_H__
+
+#include <v8.h>
+#include "bindings/npruntime.h"
+
+// These functions can be replaced by normal JS operation.
+// Getters
+v8::Handle<v8::Value> NPObjectNamedPropertyGetter(v8::Local<v8::String> name,
+ const v8::AccessorInfo& info);
+v8::Handle<v8::Value> NPObjectIndexedPropertyGetter(uint32_t index,
+ const v8::AccessorInfo& info);
+v8::Handle<v8::Value> NPObjectGetNamedProperty(v8::Local<v8::Object> self,
+ v8::Local<v8::String> name);
+v8::Handle<v8::Value> NPObjectGetIndexedProperty(v8::Local<v8::Object> self,
+ uint32_t index);
+
+// Setters
+v8::Handle<v8::Value> NPObjectNamedPropertySetter(v8::Local<v8::String> name,
+ v8::Local<v8::Value> value,
+ const v8::AccessorInfo& info);
+v8::Handle<v8::Value> NPObjectIndexedPropertySetter(uint32_t index,
+ const v8::AccessorInfo& info);
+v8::Handle<v8::Value> NPObjectSetNamedProperty(v8::Local<v8::Object> self,
+ v8::Local<v8::String> name,
+ v8::Local<v8::Value> value);
+v8::Handle<v8::Value> NPObjectSetIndexedProperty(v8::Local<v8::Object> self,
+ uint32_t index,
+ v8::Local<v8::Value> value);
+
+v8::Handle<v8::Value> NPObjectInvokeDefaultHandler(const v8::Arguments& args);
+
+// Get a wrapper for a NPObject.
+// If the object is already wrapped, the pre-existing wrapper
+// will be returned.
+// If the object is not wrapped, wrap it, and give V8 a weak
+// reference to the wrapper which will cleanup when there are
+// no more JS references to the object.
+v8::Local<v8::Object> CreateV8ObjectForNPObject(NPObject* object,
+ NPObject *root);
+
+// Tell V8 to forcibly remove an object.
+// This is used at plugin teardown so that the caller can
+// aggressively unload the plugin library. After calling this
+// function, the persistent handle to the wrapper will be
+// gone, and the wrapped NPObject will be removed so that
+// it cannot be referred to.
+void ForgetV8ObjectForNPObject(NPObject*object);
+
+#endif // V8_NPOBJECT_H__
diff --git a/webkit/port/bindings/v8/v8_proxy.cpp b/webkit/port/bindings/v8/v8_proxy.cpp
new file mode 100644
index 0000000..be8c7ff
--- /dev/null
+++ b/webkit/port/bindings/v8/v8_proxy.cpp
@@ -0,0 +1,2557 @@
+// 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.h>
+
+#include "v8_proxy.h"
+#include "dom_wrapper_map.h"
+#include "v8_index.h"
+#include "v8_events.h"
+#include "v8_binding.h"
+#include "v8_custom.h"
+#include "v8_nodefilter.h"
+#include "V8Bridge.h"
+
+#include "RefCounted.h" // for Peerable
+
+#include "DOMCoreException.h"
+#include "EventException.h"
+#include "ExceptionCode.h"
+#include "Frame.h"
+#include "HTMLNames.h"
+#include "HTMLDocument.h"
+#include "HTMLElement.h"
+#include "HTMLImageElement.h"
+#include "HTMLSelectElement.h"
+#include "HTMLOptionsCollection.h"
+#include "Page.h"
+#include "DOMWindow.h"
+#include "Navigator.h" // for MimeTypeArray
+#include "V8DOMWindow.h"
+#include "V8HTMLElement.h"
+#include "Entity.h"
+#include "MediaList.h"
+#include "NodeList.h"
+#include "Notation.h"
+#include "Text.h"
+#include "ProcessingInstruction.h"
+#include "CharacterData.h"
+#include "DocumentType.h"
+#include "DocumentFragment.h"
+#include "EventListener.h"
+#include "EventTargetNode.h"
+#include "EventTarget.h"
+#include "Event.h"
+#include "HTMLInputElement.h"
+#include "xmlhttprequest.h"
+#include "StyleSheet.h"
+#include "StyleSheetList.h"
+#include "CSSRule.h"
+#include "CSSRuleList.h"
+#include "CSSValueList.h"
+#include "FrameLoader.h"
+#include "FrameTree.h"
+#include "RangeException.h"
+#include "NodeFilter.h"
+#include "SecurityOrigin.h"
+#include "XMLHttpRequestException.h"
+#include "XPathException.h"
+
+#if ENABLE(SVG)
+#include "SVGElement.h"
+#include "SVGElementInstance.h"
+#include "SVGException.h"
+#endif
+
+#if ENABLE(XPATH)
+#include "XPathEvaluator.h"
+#endif
+
+#include "base/stats_table.h"
+#include "webkit/glue/glue_util.h"
+
+namespace WebCore {
+
+// DOM binding algorithm:
+//
+// There are two kinds of DOM objects:
+// 1. DOM tree nodes, such as Document, HTMLElement, ...
+// there classes implements TreeShared<T> interface;
+// 2. Non-node DOM objects, such as CSSRule, Location, etc.
+// these classes implements RefCounted<T> interface.
+//
+// A DOM object may have a JS wrapper object. If a tree node
+// is alive, its JS wrapper must be kept alive even it is not
+// reachable from JS roots.
+// However, JS wrappers of non-node objects can go away if
+// not reachable from other JS objects. It works like a cache.
+//
+// DOM objects are ref-counted, and JS objects are traced from
+// a set of root objects. They can create a cycle. To break
+// cycles, we do following:
+// Peer from DOM objects to JS wrappers are always weak,
+// so JS wrappers of non-node object cannot create a cycle.
+// Before starting a global GC, we create a virtual connection
+// between nodes in the same tree in the JS heap. If the wrapper
+// of one node in a tree is alive, wrappers of all nodes in
+// the same tree are considered alive. This is done by creating
+// object groups in GC prologue callbacks. The mark-compact
+// collector will remove these groups after each GC.
+
+
+#ifndef NDEBUG
+// Keeps track of global handles created (not JS wrappers
+// of DOM objects). Often these global handles are source
+// of leaks.
+//
+// If you want to let a C++ object hold a persistent handle
+// to a JS object, you should register the handle here to
+// keep track of leaks.
+//
+// When creating a persistent handle, call:
+//
+// #ifndef NDEBUG
+// V8Proxy::RegisterGlobalHandle(type, host, handle);
+// #endif
+//
+// When releasing the handle, call:
+//
+// #ifndef NDEBUG
+// V8Proxy::UnregisterGlobalHandle(type, host, handle);
+// #endif
+//
+typedef HashMap<v8::Value*, GlobalHandleInfo*> GlobalHandleMap;
+
+static GlobalHandleMap& global_handle_map() {
+ static GlobalHandleMap static_global_handle_map;
+ return static_global_handle_map;
+}
+
+
+// The function is the place to set the break point to inspect
+// live global handles. Leaks are often come from leaked global handles.
+static void EnumerateGlobalHandles() {
+ for (GlobalHandleMap::iterator it = global_handle_map().begin(),
+ end = global_handle_map().end(); it != end; ++it) {
+ GlobalHandleInfo* info = it->second;
+ v8::Value* handle = it->first;
+ }
+}
+
+
+void V8Proxy::RegisterGlobalHandle(GlobalHandleType type, void* host,
+ v8::Persistent<v8::Value> handle) {
+ ASSERT(!global_handle_map().contains(*handle));
+ global_handle_map().set(*handle, new GlobalHandleInfo(host, type));
+}
+
+
+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
+
+
+typedef HashMap<Node*, v8::Object*> NodeMap;
+typedef HashMap<Peerable*, v8::Object*> PeerableMap;
+
+// Type T must implement Peerable interface.
+template<class T>
+class DOMPeerableWrapperMap : public DOMWrapperMap<T> {
+ public:
+ explicit DOMPeerableWrapperMap(v8::WeakReferenceCallback callback) :
+ DOMWrapperMap(callback) { }
+
+ // Get the JS wrapper object of an object.
+ v8::Persistent<v8::Object> get(T* obj) {
+ v8::Object* peer = static_cast<v8::Object*>(obj->peer());
+ ASSERT(peer == map_.get(obj));
+ return peer ? v8::Persistent<v8::Object>(peer)
+ : v8::Persistent<v8::Object>();
+ }
+
+ void set(T* obj, v8::Persistent<v8::Object> peer_handle) {
+ ASSERT(obj->peer() == 0);
+ obj->setPeer(*peer_handle);
+ DOMWrapperMap<T>::set(obj, peer_handle);
+ }
+
+ void forget(T* obj) {
+ v8::Object* peer = static_cast<v8::Object*>(obj->peer());
+ ASSERT(peer == map_.get(obj));
+ if (peer)
+ obj->setPeer(0);
+ DOMWrapperMap<T>::forget(obj);
+ }
+};
+
+
+static void WeakPeerableCallback(v8::Persistent<v8::Object> obj, void* para);
+static void WeakNodeCallback(v8::Persistent<v8::Object> obj, void* para);
+// A map from DOM node to its JS wrapper.
+static DOMWrapperMap<Node>& dom_node_map() {
+ static DOMPeerableWrapperMap<Node> static_dom_node_map(&WeakNodeCallback);
+ return static_dom_node_map;
+}
+
+
+// A map from a non-DOM node (peerable) to its JS wrapper.
+static DOMWrapperMap<Peerable>& dom_object_map() {
+ static DOMPeerableWrapperMap<Peerable>
+ static_dom_object_map(&WeakPeerableCallback);
+ return static_dom_object_map;
+}
+
+#if ENABLE(SVG)
+static void WeakSVGElementInstanceCallback(v8::Persistent<v8::Object> obj,
+ void* param);
+
+// A map for SVGElementInstances, which are not peerable
+static DOMWrapperMap<SVGElementInstance>& dom_svg_element_instance_map() {
+ static DOMWrapperMap<SVGElementInstance>
+ static_dom_svg_element_instance_map(&WeakSVGElementInstanceCallback);
+ return static_dom_svg_element_instance_map;
+}
+
+static void WeakSVGElementInstanceCallback(v8::Persistent<v8::Object> obj,
+ void* param) {
+ SVGElementInstance* instance = static_cast<SVGElementInstance*>(param);
+ ASSERT(dom_svg_element_instance_map().contains(instance));
+
+ instance->deref();
+ dom_svg_element_instance_map().forget(instance);
+}
+
+v8::Handle<v8::Object> V8Proxy::SVGElementInstanceToV8Object(
+ SVGElementInstance* instance) {
+ if (!instance) return v8::Handle<v8::Object>();
+
+ v8::Handle<v8::Object> existing_instance =
+ dom_svg_element_instance_map().get(instance);
+ if (!existing_instance.IsEmpty()) {
+ return existing_instance;
+ }
+
+ instance->ref();
+
+ // Instantiate the V8 object and remember it
+ v8::Handle<v8::Object> result =
+ InstantiateV8Object(V8ClassIndex::SVGELEMENTINSTANCE, instance);
+ if (!result.IsEmpty()) {
+ // Only update the DOM SVG element map if the result is non-empty.
+ dom_svg_element_instance_map().set(instance,
+ v8::Persistent<v8::Object>::New(result));
+ }
+ return result;
+}
+
+// SVG non-node elements may have a reference to a context node which
+// should be notified when the element is changed
+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;
+}
+
+// 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;
+}
+
+v8::Handle<v8::Object> V8Proxy::SVGObjectWithContextToV8Object(
+ Peerable* object, V8ClassIndex::V8WrapperType type) {
+ if (!object) return v8::Handle<v8::Object>();
+
+ // Special case: SVGPathSegs need to be downcast to their real type
+ if (type == V8ClassIndex::SVGPATHSEG) {
+ type = V8Custom::DowncastSVGPathSeg(object);
+ }
+
+ v8::Persistent<v8::Object> result =
+ dom_svg_object_with_context_map().get(object);
+ if (result.IsEmpty()) {
+ v8::Local<v8::Object> v8obj = InstantiateV8Object(type, object);
+ if (!v8obj.IsEmpty()) {
+ result = v8::Persistent<v8::Object>::New(v8obj);
+ dom_svg_object_with_context_map().set(object, result);
+ }
+ }
+
+ return result;
+}
+
+static void WeakSVGObjectWithContext(v8::Persistent<v8::Object> obj,
+ void* param) {
+ Peerable* dom_obj = static_cast<Peerable*>(param);
+ ASSERT(dom_svg_object_with_context_map().contains(dom_obj));
+
+ // Release the reference to the context if it exists
+ if (svg_object_to_context_map().contains(dom_obj)) {
+ svg_object_to_context_map().get(dom_obj)->deref();
+ svg_object_to_context_map().remove(dom_obj);
+ }
+
+ // forget function removes object from the map,
+ // disposes the wrapper and clears the peer.
+ dom_svg_object_with_context_map().forget(dom_obj);
+}
+
+void V8Proxy::SetSVGContext(void* obj, SVGElement* context) {
+ SVGElement* old_context = svg_object_to_context_map().get(obj);
+
+ if (old_context == context) {
+ return;
+ }
+
+ if (old_context) {
+ old_context->deref();
+ }
+
+ 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);
+}
+
+#endif
+
+
+// Called when obj is near death (not reachable from JS roots)
+// It is time to remove the entry from the table and dispose
+// the handle.
+static void WeakPeerableCallback(v8::Persistent<v8::Object> obj, void* para) {
+ Peerable* dom_obj = static_cast<Peerable*>(para);
+ ASSERT(dom_object_map().contains(dom_obj));
+
+ // forget function removes object from the map,
+ // disposes the wrapper and clears the peer.
+ dom_object_map().forget(dom_obj);
+}
+
+
+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() {
+#ifndef NDEBUG
+ // Check that all references in the map are weak.
+ PeerableMap peer_map = dom_object_map().impl();
+ for (PeerableMap::iterator it = peer_map.begin(), end = peer_map.end();
+ it != end; ++it) {
+ Peerable* obj = it->first;
+ ASSERT(v8::Persistent<v8::Object>(it->second).IsWeak());
+ }
+#endif
+
+ // Create object groups.
+ NodeMap node_map = dom_node_map().impl();
+ for (NodeMap::iterator it = node_map.begin(), end = node_map.end();
+ it != end; ++it) {
+ Node* node = it->first;
+
+ // If the node is in document, put it in the ownerDocument's
+ // object group.
+ //
+ // If an image element was created by JavaScript "new Image",
+ // it is not in a document. However, if the load event has not
+ // been fired (still onloading), it is treated as in the document.
+ //
+ if (node->inDocument() ||
+ (node->hasTagName(HTMLNames::imgTag) &&
+ !static_cast<HTMLImageElement*>(node)->haveFiredLoadEvent()) ) {
+ Document* doc = node->document();
+ v8::Persistent<v8::Object> wrapper = dom_node_map().get(node);
+ if (!wrapper.IsEmpty()) {
+ v8::V8::AddObjectToGroup(doc, wrapper);
+ }
+ }
+ }
+}
+
+
+static void GCEpilogue() {
+#ifndef NDEBUG
+ // Check all survivals are weak.
+ PeerableMap peer_map = dom_object_map().impl();
+ for (PeerableMap::iterator it = peer_map.begin(), end = peer_map.end();
+ it != end; ++it) {
+ Peerable* obj = it->first;
+ ASSERT(v8::Persistent<v8::Object>(it->second).IsWeak());
+ }
+
+ NodeMap node_map = dom_node_map().impl();
+ for (NodeMap::iterator it = node_map.begin(), end = node_map.end();
+ it != end; ++it) {
+ Node* node = it->first;
+ ASSERT(v8::Persistent<v8::Object>(it->second).IsWeak());
+ }
+
+ EnumerateGlobalHandles();
+#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
+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>
+ wrapper(static_cast<v8::Object*>(dom_object->peer()));
+
+ gc_protected_map().set(dom_object, *v8::Persistent<v8::Object>::New(wrapper));
+}
+
+
+// static
+void V8Proxy::GCUnprotect(Peerable* dom_object) {
+ 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));
+ wrapper.Dispose();
+}
+
+
+typedef HashMap<int, v8::FunctionTemplate*> FunctionTemplateMap;
+
+bool AllowAllocation::m_current = false;
+
+
+// JavaScriptConsoleMessages encapsulate everything needed to
+// log messages originating from JavaScript to the Chrome console.
+class JavaScriptConsoleMessage {
+ public:
+ JavaScriptConsoleMessage(const String& str,
+ const String& sourceID,
+ unsigned lineNumber)
+ : m_string(str)
+ , m_sourceID(sourceID)
+ , m_lineNumber(lineNumber) { }
+
+ void AddToPage(Page* page) const;
+
+ private:
+ const String m_string;
+ const String m_sourceID;
+ 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);
+}
+
+
+// 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.
+class ConsoleMessageManager {
+ public:
+ // Add a message to the console. May end up calling JavaScript code
+ // indirectly through the inspector so only call this function when
+ // it is safe to do allocations.
+ static void AddMessage(Page* page, const JavaScriptConsoleMessage& message);
+
+ // Add a message to the console but delay the reporting until it
+ // is safe to do so: Either when we leave JavaScript execution or
+ // when adding other console messages. The primary purpose of this
+ // method is to avoid calling into V8 to handle console messages
+ // when the VM is in a state that does not support GCs or allocations.
+ // Delayed messages are always reported in the page corresponding
+ // to the active context.
+ static void AddDelayedMessage(const JavaScriptConsoleMessage& message);
+
+ // Process any delayed messages. May end up calling JavaScript code
+ // indirectly through the inspector so only call this function when
+ // it is safe to do allocations.
+ static void ProcessDelayedMessages();
+
+ private:
+ // All delayed messages are stored in this vector. If the vector
+ // is NULL, there are no delayed messages.
+ static Vector<JavaScriptConsoleMessage>* m_delayed;
+};
+
+
+Vector<JavaScriptConsoleMessage>* ConsoleMessageManager::m_delayed = NULL;
+
+
+void ConsoleMessageManager::AddMessage(
+ Page* page,
+ const JavaScriptConsoleMessage& message) {
+ // Process any delayed messages to make sure that messages
+ // appear in the right order in the console.
+ ProcessDelayedMessages();
+ message.AddToPage(page);
+}
+
+
+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() {
+ // If we have a delayed vector it cannot be empty.
+ if (!m_delayed) return;
+ ASSERT(!m_delayed->isEmpty());
+
+ // Add the delayed messages to the page of the active
+ // context. If that for some bizarre reason does not
+ // exist, we clear the list of delayed messages to avoid
+ // posting messages. We still deallocate the vector.
+ Frame* frame = V8Proxy::retrieveActiveFrame();
+ Page* page = NULL;
+ if (frame) page = frame->page();
+ if (!page) m_delayed->clear();
+
+ // Iterate through all the delayed messages and add them
+ // to the console.
+ const int size = m_delayed->size();
+ for (int i = 0; i < size; i++) {
+ m_delayed->at(i).AddToPage(page);
+ }
+
+ // Deallocate the delayed vector.
+ delete m_delayed;
+ m_delayed = NULL;
+}
+
+
+// Convenience class for ensuring that delayed messages in the
+// ConsoleMessageManager are processed quickly.
+class ConsoleMessageScope {
+ public:
+ ConsoleMessageScope() { ConsoleMessageManager::ProcessDelayedMessages(); }
+ ~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);
+}
+
+
+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;
+
+ Page* page = frame->page();
+ if (!page) return;
+
+ v8::Handle<v8::String> errorMessageString = message->Get();
+ ASSERT(!errorMessageString.IsEmpty());
+ String errorMessage = ToWebCoreString(errorMessageString);
+
+ v8::Handle<v8::String> resourceNameString = message->GetScriptResourceName();
+ String resourceName = (resourceNameString.IsEmpty())
+ ? frame->document()->url()
+ : ToWebCoreString(resourceNameString);
+ JavaScriptConsoleMessage consoleMessage(errorMessage,
+ resourceName,
+ message->GetLineNumber());
+ ConsoleMessageManager::AddMessage(page, consoleMessage);
+}
+
+
+enum DelayReporting {
+ REPORT_LATER,
+ REPORT_NOW
+};
+
+
+static void ReportUnsafeAccessTo(Frame* target, DelayReporting delay) {
+ ASSERT(target);
+ Document* targetDocument = target->document();
+ if (!targetDocument) return;
+
+ Frame* source = V8Proxy::retrieveActiveFrame();
+ Document* sourceDocument = source->document();
+ ASSERT(sourceDocument);
+
+ // FIXME: This error message should contain more specifics of why the same
+ // origin check has failed.
+ 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());
+
+ // Build a console message with fake source ID and line number.
+ const String kSourceID = "";
+ const int kLineNumber = 1;
+ JavaScriptConsoleMessage message(str, kSourceID, kLineNumber);
+
+ if (delay == REPORT_NOW) {
+ // NOTE(tc): Apple prints the message in the target page, but it seems like
+ // it should be in the source page. Even for delayed messages, we put it in
+ // the source page; see ConsoleMessageManager::ProcessDelayedMessages().
+ ConsoleMessageManager::AddMessage(source->page(), message);
+
+ } else {
+ ASSERT(delay == REPORT_LATER);
+ // We cannot safely report the message eagerly, because this may cause
+ // allocations and GCs internally in V8 and we cannot handle that at this
+ // point. Therefore we delay the reporting.
+ ConsoleMessageManager::AddDelayedMessage(message);
+ }
+}
+
+
+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;
+
+ 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 HandleFatalErrorInV8() {
+ // TODO: We temporarily deal with V8 internal error situations
+ // such as out-of-memory by crashing the renderer.
+ CRASH();
+}
+
+
+V8Proxy::~V8Proxy() {
+ clear();
+ DestroyGlobal();
+}
+
+
+void V8Proxy::DestroyGlobal() {
+ if (!m_global.IsEmpty()) {
+#ifndef NDEBUG
+ UnregisterGlobalHandle(this, m_global);
+#endif
+ m_global.Dispose();
+ m_global.Clear();
+ }
+}
+
+
+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);
+}
+
+
+EventListener* V8Proxy::createHTMLEventHandler(const String& 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);
+}
+#endif
+
+
+// Event listeners
+
+static V8EventListener* FindEventListenerInList(V8EventListenerList& list,
+ v8::Local<v8::Value> listener,
+ bool html) {
+ ASSERT(v8::Context::InContext());
+
+ if (!listener->IsObject()) return 0;
+
+ V8EventListenerList::iterator p = list.begin();
+ while (p != list.end()) {
+ V8EventListener* el = *p;
+ v8::Local<v8::Object> wrapper = el->GetListenerObject();
+ ASSERT(!wrapper.IsEmpty());
+ // Since the listener is an object, it is safe to compare for
+ // strict equality (in the JS sense) by doing a simple equality
+ // 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;
+ }
+ ++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);
+}
+
+
+V8EventListener* V8Proxy::FindOrCreateV8EventListener(v8::Local<v8::Value> obj,
+ bool html) {
+ ASSERT(v8::Context::InContext());
+
+ if (!obj->IsObject()) return 0;
+
+ V8EventListener* wrapper =
+ FindEventListenerInList(m_event_listeners, obj, html);
+ if (wrapper) return wrapper;
+
+ // Create a new one, and add to cache.
+ V8EventListener* new_listener =
+ new V8EventListener(m_frame, v8::Local<v8::Object>::Cast(obj), html);
+ m_event_listeners.push_back(new_listener);
+
+ return new_listener;
+}
+
+
+// XMLHttpRequest(XHR) event listeners are different from listeners
+// on DOM nodes. A XHR event listener wrapper only hold a weak reference
+// to the JS function. A strong reference can create a cycle.
+//
+// The lifetime of a XHR object is bounded by the life time of its JS_XHR
+// object. So we can create a hidden reference from JS_XHR to JS function.
+//
+// (peer)
+// XHR <---------- JS_XHR
+// | (hidden) : ^
+// V V : (may reachable by closure)
+// V8_listener --------> JS_function
+// (weak) <-- may create a cycle if it is strong
+//
+// The persistent reference is made weak in the constructor
+// of V8XHREventListener.
+
+V8EventListener* V8Proxy::FindXHREventListener(v8::Local<v8::Value> listener,
+ bool html) {
+ return FindEventListenerInList(m_xhr_listeners, listener, html);
+}
+
+
+V8EventListener*
+V8Proxy::FindOrCreateXHREventListener(v8::Local<v8::Value> obj,
+ bool html) {
+ ASSERT(v8::Context::InContext());
+
+ if (!obj->IsObject()) return 0;
+
+ V8EventListener* wrapper =
+ FindEventListenerInList(m_xhr_listeners, obj, html);
+ if (wrapper) return wrapper;
+
+ // Create a new one, and add to cache.
+ V8EventListener* new_listener =
+ new V8XHREventListener(m_frame, v8::Local<v8::Object>::Cast(obj), html);
+ m_xhr_listeners.push_back(new_listener);
+
+ return new_listener;
+}
+
+
+static void RemoveEventListenerFromList(V8EventListenerList& list,
+ V8EventListener* listener) {
+ V8EventListenerList::iterator p = list.begin();
+ while (p != list.end()) {
+ if (*p == listener) {
+ list.erase(p);
+ return;
+ }
+ ++p;
+ }
+}
+
+
+void V8Proxy::RemoveV8EventListener(V8EventListener* listener) {
+ RemoveEventListenerFromList(m_event_listeners, listener);
+}
+
+
+void V8Proxy::RemoveXHREventListener(V8XHREventListener* listener) {
+ RemoveEventListenerFromList(m_xhr_listeners, listener);
+}
+
+
+static void DisconnectEventListenersInList(V8EventListenerList& list) {
+ V8EventListenerList::iterator p = list.begin();
+ while (p != list.end()) {
+ (*p)->disconnectFrame();
+ ++p;
+ }
+ list.clear();
+}
+
+
+void V8Proxy::DisconnectEventListeners() {
+ DisconnectEventListenersInList(m_event_listeners);
+ DisconnectEventListenersInList(m_xhr_listeners);
+}
+
+
+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 =
+ 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;
+}
+
+
+bool V8Proxy::HandleOutOfMemory() {
+ v8::Local<v8::Context> context = v8::Context::GetCurrent();
+
+ if (!context->HasOutOfMemoryException())
+ return false;
+
+ // 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();
+
+ webkit_glue::NotifyJSOutOfMemory(frame);
+
+ // Disable JS.
+ Settings* settings = frame->settings();
+ ASSERT(settings);
+ settings->setJavaScriptEnabled(false);
+
+ 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);
+ v8::Handle<v8::Script> script = CompileScript(code, fileName, baseLine);
+
+ // Set inlineCode to true for <a href="javascript:doSomething()">
+ // and false for <script>doSomething</script>. For some reason, fileName
+ // gives us this information.
+ return RunScript(script, fileName.isNull());
+}
+
+
+v8::Local<v8::Value> V8Proxy::RunScript(v8::Handle<v8::Script> script,
+ bool inline_code) {
+ if (script.IsEmpty())
+ return v8::Local<v8::Value>();
+
+ // Compute the source string and prevent against infinite recursion.
+ if (m_recursion >= 20) {
+ v8::Local<v8::String> code =
+ v8ExternalString("throw RangeError('Recursion too deep')");
+ // TODO(kasperl): Ideally, we should be able to re-use the origin of the
+ // script passed to us as the argument instead of using an empty string
+ // and 0 baseLine.
+ script = CompileScript(code, "", 0);
+ }
+
+ if (HandleOutOfMemory())
+ ASSERT(script.IsEmpty());
+
+ if (script.IsEmpty())
+ return v8::Local<v8::Value>();
+
+ // Save the previous value of the inlineCode flag and update the flag for
+ // the duration of the script invocation.
+ bool previous_inline_code = inlineCode();
+ setInlineCode(inline_code);
+
+ // Run the script and keep track of the current recursion depth.
+ v8::Local<v8::Value> result;
+ { ConsoleMessageScope scope;
+ m_recursion++;
+
+ // Evaluating the JavaScript could cause the frame to be deallocated,
+ // so we start the keep alive timer here.
+ // Frame::keepAlive method adds the ref count of the frame and sets a
+ // timer to decrease the ref count. It assumes that the current JavaScript
+ // execution finishs before firing the timer.
+ // See issue 1218756 and 914430.
+ m_frame->keepAlive();
+
+ result = script->Run();
+ m_recursion--;
+ }
+
+ if (HandleOutOfMemory())
+ ASSERT(result.IsEmpty());
+
+ // Handle V8 internal error situation (Out-of-memory).
+ if (result.IsEmpty())
+ return v8::Local<v8::Value>();
+
+ // Restore inlineCode flag.
+ setInlineCode(previous_inline_code);
+
+ if (v8::V8::IsDead())
+ HandleFatalErrorInV8();
+
+ return result;
+}
+
+
+v8::Local<v8::Value> V8Proxy::CallFunction(v8::Handle<v8::Function> function,
+ v8::Handle<v8::Object> receiver,
+ int argc,
+ v8::Handle<v8::Value> args[]) {
+ // For now, we don't put any artificial limitations on the depth
+ // of recursion that stems from calling functions. This is in
+ // contrast to the script evaluations.
+ v8::Local<v8::Value> result;
+ { ConsoleMessageScope scope;
+
+ // Evaluating the JavaScript could cause the frame to be deallocated,
+ // so we start the keep alive timer here.
+ // Frame::keepAlive method adds the ref count of the frame and sets a
+ // timer to decrease the ref count. It assumes that the current JavaScript
+ // execution finishs before firing the timer.
+ // See issue 1218756 and 914430.
+ m_frame->keepAlive();
+
+ result = function->Call(receiver, argc, args);
+ }
+
+ if (v8::V8::IsDead())
+ HandleFatalErrorInV8();
+
+ return result;
+}
+
+
+v8::Persistent<v8::FunctionTemplate> V8Proxy::GetTemplate(
+ V8ClassIndex::V8WrapperType type) {
+ v8::Persistent<v8::FunctionTemplate>* cache_cell =
+ V8ClassIndex::GetCache(type);
+ if (!(*cache_cell).IsEmpty()) return *cache_cell;
+
+ // not found
+ FunctionTemplateFactory factory = V8ClassIndex::GetFactory(type);
+ v8::Persistent<v8::FunctionTemplate> desc = factory();
+ switch (type) {
+ case V8ClassIndex::CSSSTYLEDECLARATION:
+ // The named property handler for style declarations has a
+ // setter. Therefore, the interceptor has to be on the object
+ // itself and not on the prototype object.
+ desc->InstanceTemplate()->SetNamedPropertyHandler(
+ USE_NAMED_PROPERTY_GETTER(CSSStyleDeclaration),
+ USE_NAMED_PROPERTY_SETTER(CSSStyleDeclaration));
+ SetCollectionStringOrNullIndexedGetter<CSSStyleDeclaration>(desc);
+ break;
+ case V8ClassIndex::CSSRULELIST:
+ SetCollectionIndexedGetter<CSSRuleList>(desc, V8ClassIndex::CSSRULE);
+ break;
+ case V8ClassIndex::CSSVALUELIST:
+ SetCollectionIndexedGetter<CSSValueList>(desc, V8ClassIndex::CSSVALUE);
+ break;
+ case V8ClassIndex::UNDETECTABLEHTMLCOLLECTION:
+ desc->InstanceTemplate()->MarkAsUndetectable(); // fall through
+ case V8ClassIndex::HTMLCOLLECTION:
+ desc->InstanceTemplate()->SetNamedPropertyHandler(
+ USE_NAMED_PROPERTY_GETTER(HTMLCollection));
+ desc->InstanceTemplate()->SetCallAsFunctionHandler(
+ USE_CALLBACK(HTMLCollectionCallAsFunction));
+ SetCollectionIndexedGetter<HTMLCollection>(desc, V8ClassIndex::NODE);
+ break;
+ case V8ClassIndex::HTMLOPTIONSCOLLECTION:
+ SetCollectionNamedGetter<HTMLOptionsCollection>(desc, V8ClassIndex::NODE);
+ desc->InstanceTemplate()->SetIndexedPropertyHandler(
+ USE_INDEXED_PROPERTY_GETTER(HTMLOptionsCollection),
+ USE_INDEXED_PROPERTY_SETTER(HTMLOptionsCollection));
+ desc->InstanceTemplate()->SetCallAsFunctionHandler(
+ USE_CALLBACK(HTMLCollectionCallAsFunction));
+ break;
+ case V8ClassIndex::HTMLSELECTELEMENT:
+ desc->InstanceTemplate()->SetNamedPropertyHandler(
+ CollectionNamedPropertyGetter<HTMLSelectElement>,
+ 0,
+ 0,
+ 0,
+ 0,
+ v8::External::New(reinterpret_cast<void*>(V8ClassIndex::NODE)));
+ desc->InstanceTemplate()->SetIndexedPropertyHandler(
+ CollectionIndexedPropertyGetter<HTMLSelectElement>,
+ USE_INDEXED_PROPERTY_SETTER(HTMLSelectElementCollection),
+ 0,
+ 0,
+ CollectionIndexedPropertyEnumerator<HTMLSelectElement>,
+ v8::External::New(reinterpret_cast<void*>(V8ClassIndex::NODE)));
+ break;
+ case V8ClassIndex::HTMLDOCUMENT: {
+ desc->InstanceTemplate()->SetNamedPropertyHandler(
+ USE_NAMED_PROPERTY_GETTER(HTMLDocument),
+ USE_NAMED_PROPERTY_SETTER(HTMLDocument),
+ 0,
+ USE_NAMED_PROPERTY_DELETER(HTMLDocument));
+
+ // We add an extra internal field to all Document wrappers for
+ // storing a per document DOMImplementation wrapper.
+ //
+ // Additionally, we add two extra internal fields for
+ // HTMLDocuments to implement temporary shadowing of
+ // document.all. One field holds an object that is used as a
+ // marker. The other field holds the marker object if
+ // document.all is not shadowed and some other value if
+ // document.all is shadowed.
+ v8::Local<v8::ObjectTemplate> instance_template =
+ desc->InstanceTemplate();
+ ASSERT(instance_template->InternalFieldCount() ==
+ V8Custom::kDefaultWrapperInternalFieldCount);
+ instance_template->SetInternalFieldCount(
+ V8Custom::kHTMLDocumentInternalFieldCount);
+ break;
+ }
+ case V8ClassIndex::DOCUMENT:
+ case V8ClassIndex::SVGDOCUMENT: {
+ // We add an extra internal field to all Document wrappers for
+ // storing a per document DOMImplementation wrapper.
+ v8::Local<v8::ObjectTemplate> instance_template =
+ desc->InstanceTemplate();
+ ASSERT(instance_template->InternalFieldCount() ==
+ V8Custom::kDefaultWrapperInternalFieldCount);
+ instance_template->SetInternalFieldCount(
+ V8Custom::kDocumentMinimumInternalFieldCount);
+ break;
+ }
+ case V8ClassIndex::HTMLEMBEDELEMENT:
+ // fall through
+ case V8ClassIndex::HTMLOBJECTELEMENT:
+ // Follow through. Both HTMLEmbedElement and HTMLObjectElement are
+ // inherited from HTMLPlugInElement, and they share the same property
+ // handling code.
+ desc->InstanceTemplate()->SetNamedPropertyHandler(
+ USE_NAMED_PROPERTY_GETTER(HTMLPlugInElement),
+ USE_NAMED_PROPERTY_SETTER(HTMLPlugInElement));
+ desc->InstanceTemplate()->SetIndexedPropertyHandler(
+ USE_INDEXED_PROPERTY_GETTER(HTMLPlugInElement),
+ USE_INDEXED_PROPERTY_SETTER(HTMLPlugInElement));
+ desc->InstanceTemplate()->SetCallAsFunctionHandler(
+ USE_CALLBACK(HTMLPlugInElement));
+ break;
+ case V8ClassIndex::HTMLFRAMESETELEMENT:
+ desc->InstanceTemplate()->SetNamedPropertyHandler(
+ USE_NAMED_PROPERTY_GETTER(HTMLFrameSetElement));
+ break;
+ case V8ClassIndex::HTMLFORMELEMENT:
+ desc->InstanceTemplate()->SetNamedPropertyHandler(
+ USE_NAMED_PROPERTY_GETTER(HTMLFormElement));
+ desc->InstanceTemplate()->SetIndexedPropertyHandler(
+ USE_INDEXED_PROPERTY_GETTER(HTMLFormElement),
+ 0,
+ 0,
+ 0,
+ CollectionIndexedPropertyEnumerator<HTMLFormElement>,
+ v8::External::New(reinterpret_cast<void*>(V8ClassIndex::NODE)));
+ break;
+ case V8ClassIndex::MEDIALIST:
+ SetCollectionStringOrNullIndexedGetter<MediaList>(desc);
+ break;
+ case V8ClassIndex::MIMETYPEARRAY:
+ SetCollectionIndexedAndNamedGetters<MimeTypeArray>(
+ desc,
+ V8ClassIndex::MIMETYPE);
+ break;
+ case V8ClassIndex::NAMEDNODEMAP:
+ desc->InstanceTemplate()->SetNamedPropertyHandler(
+ USE_NAMED_PROPERTY_GETTER(NamedNodeMap));
+ desc->InstanceTemplate()->SetIndexedPropertyHandler(
+ USE_INDEXED_PROPERTY_GETTER(NamedNodeMap),
+ 0,
+ 0,
+ 0,
+ CollectionIndexedPropertyEnumerator<NamedNodeMap>,
+ v8::External::New(reinterpret_cast<void*>(V8ClassIndex::NODE)));
+ break;
+ case V8ClassIndex::NODELIST:
+ SetCollectionIndexedGetter<NodeList>(desc, V8ClassIndex::NODE);
+ desc->InstanceTemplate()->SetNamedPropertyHandler(
+ USE_NAMED_PROPERTY_GETTER(NodeList));
+ break;
+ case V8ClassIndex::PLUGIN:
+ SetCollectionIndexedAndNamedGetters<Plugin>(desc, V8ClassIndex::MIMETYPE);
+ break;
+ case V8ClassIndex::PLUGINARRAY:
+ SetCollectionIndexedAndNamedGetters<PluginArray>(desc,
+ V8ClassIndex::PLUGIN);
+ break;
+ case V8ClassIndex::STYLESHEETLIST:
+ desc->InstanceTemplate()->SetNamedPropertyHandler(
+ USE_NAMED_PROPERTY_GETTER(StyleSheetList));
+ SetCollectionIndexedGetter<StyleSheetList>(desc,
+ V8ClassIndex::STYLESHEET);
+ break;
+ case V8ClassIndex::DOMWINDOW: {
+ v8::Local<v8::Signature> default_signature = v8::Signature::New(desc);
+
+ desc->PrototypeTemplate()->SetNamedPropertyHandler(
+ USE_NAMED_PROPERTY_GETTER(DOMWindow));
+ desc->PrototypeTemplate()->SetIndexedPropertyHandler(
+ USE_INDEXED_PROPERTY_GETTER(DOMWindow));
+
+ desc->PrototypeTemplate()->Set(
+ v8::String::New("addEventListener"),
+ v8::FunctionTemplate::New(USE_CALLBACK(DOMWindowAddEventListener),
+ v8::Handle<v8::Value>(),
+ default_signature),
+ v8::None);
+ desc->PrototypeTemplate()->Set(
+ v8::String::New("removeEventListener"),
+ v8::FunctionTemplate::New(USE_CALLBACK(DOMWindowRemoveEventListener),
+ v8::Handle<v8::Value>(),
+ default_signature),
+ v8::None);
+ desc->SetHiddenPrototype(true);
+ break;
+ }
+ case V8ClassIndex::LOCATION: {
+ break;
+ }
+ case V8ClassIndex::HISTORY: {
+ break;
+ }
+
+ // DOMParser, XMLSerializer, and XMLHttpRequest objects are created from
+ // JS world, but we setup the constructor function lazily in
+ // WindowNamedPropertyHandler::get.
+ case V8ClassIndex::DOMPARSER:
+ desc->SetCallHandler(USE_CALLBACK(DOMParserConstructor));
+ break;
+ case V8ClassIndex::XMLSERIALIZER:
+ desc->SetCallHandler(USE_CALLBACK(XMLSerializerConstructor));
+ break;
+ case V8ClassIndex::XMLHTTPREQUEST: {
+ // Reserve one more internal field for keeping event listeners.
+ v8::Local<v8::ObjectTemplate> instance_template =
+ desc->InstanceTemplate();
+ int internal_field_count = instance_template->InternalFieldCount() + 1;
+ instance_template->SetInternalFieldCount(internal_field_count);
+ desc->SetCallHandler(USE_CALLBACK(XMLHttpRequestConstructor));
+ break;
+ }
+ case V8ClassIndex::XPATHEVALUATOR:
+ desc->SetCallHandler(USE_CALLBACK(XPathEvaluatorConstructor));
+ break;
+ case V8ClassIndex::XSLTPROCESSOR:
+ desc->SetCallHandler(USE_CALLBACK(XSLTProcessorConstructor));
+ break;
+ default:
+ break;
+ }
+
+ *cache_cell = desc;
+ return desc;
+}
+
+
+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);
+}
+
+
+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::retrieveFrame() {
+ DOMWindow* window = retrieveWindow();
+ return window ? window->frame() : 0;
+}
+
+
+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;
+}
+
+
+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();
+ }
+ }
+
+ 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
+
+ if (!m_document.IsEmpty()) {
+#ifndef NDEBUG
+ UnregisterGlobalHandle(this, m_document);
+#endif
+ m_document.Dispose();
+ m_document.Clear();
+ }
+}
+
+
+// static
+void V8Proxy::DomainChanged(Frame* frame) {
+ V8Proxy* proxy = retrieve(frame);
+ proxy->ClearSecurityToken();
+}
+
+
+void V8Proxy::ClearSecurityToken() {
+ m_context->SetSecurityToken(m_global);
+}
+
+
+void V8Proxy::clear() {
+ if (!m_context.IsEmpty()) {
+ ClearSecurityToken();
+
+ if (m_frame->domWindow())
+ m_frame->domWindow()->clearAllTimeouts();
+
+ clearDocumentWrapper();
+
+ // 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;
+ }
+
+ if (!target) {
+ reason = SecurityOrigin::GenericMismatch;
+ return false;
+ }
+
+ // Allow access if the frames the windows represent are the same.
+ if (source == target)
+ return true;
+
+ 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;
+
+ Document* act_document = source->document();
+
+ 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"));
+
+ // 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;
+ }
+
+ if (active_security_origin->canAccess(target_security_origin, reason))
+ return true;
+
+ 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
+// setting document.domain, using the lexical context of the function
+// 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;
+ }
+
+ // 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;
+ }
+ }
+
+ 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;
+}
+
+
+bool V8Proxy::CheckNodeSecurity(Node* node) {
+ if (!node)
+ return false;
+
+ Frame* target = node->document()->frame();
+
+ if (!target)
+ return false;
+
+ return IsFromSameOrigin(target, true);
+}
+
+
+// Create a new environment and setup the global object.
+//
+// The global object corresponds to a DOMWindow instance. However, to
+// allow properties of the JS DOMWindow instance to be shadowed, we
+// use a shadow object as the global object and use the JS DOMWindow
+// instance as the prototype for that shadow object. The JS DOMWindow
+// instance is undetectable from javascript code because the __proto__
+// accessors skip that object.
+//
+// The shadow object and the DOMWindow instance are seen as one object
+// 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() {
+ // Bail out if the context has already been initialized.
+ if (!m_context.IsEmpty()) return;
+
+ // Install counters handler with V8.
+ static bool v8_counters_initialized = false;
+ if (!v8_counters_initialized) {
+ v8::V8::SetCounterFunction(StatsTable::FindLocation);
+ v8_counters_initialized = true;
+ }
+
+ // Setup the security handlers and message listener. This only has
+ // to be done once.
+ static bool v8_initialized = false;
+ if (!v8_initialized) {
+ v8_initialized = true;
+
+ // Tells V8 not to call the default OOM handler, binding code
+ // will handle it.
+ v8::V8::IgnoreOutOfMemoryException();
+ v8::V8::SetFatalErrorHandler(ReportFatalErrorInV8);
+
+ v8::V8::SetGlobalGCPrologueCallback(&GCPrologue);
+ v8::V8::SetGlobalGCEpilogueCallback(&GCEpilogue);
+
+ v8::V8::AddMessageListener(HandleConsoleMessage);
+
+ v8::V8::SetFailedAccessCheckCallbackFunction(ReportUnsafeJavaScriptAccess);
+ }
+
+ // Create a new environment using an empty template for the shadow
+ // object. Reuse the global object if one has been created earlier.
+ v8::Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
+ if (global_template.IsEmpty())
+ return;
+
+ // Install a security handler with V8.
+ { v8::Local<v8::External> external =
+ v8::External::New(reinterpret_cast<void*>(V8ClassIndex::DOMWINDOW));
+ if (external.IsEmpty())
+ return;
+
+ global_template->SetAccessCheckCallbacks(
+ V8Custom::v8DOMWindowNamedSecurityCheck,
+ V8Custom::v8DOMWindowIndexedSecurityCheck,
+ external);
+ }
+
+ m_context = v8::Context::New(NULL, global_template, m_global);
+ if (m_context.IsEmpty())
+ return;
+
+ // Starting from now, use local context only.
+ v8::Local<v8::Context> context = GetContext();
+ v8::Context::Scope scope(context);
+
+ // Store the first global object created so we can reuse it.
+ if (m_global.IsEmpty()) {
+ m_global = v8::Persistent<v8::Object>::New(context->Global());
+#ifndef NDEBUG
+ RegisterGlobalHandle(PROXY, this, m_global);
+#endif
+ }
+
+ // Create a new JS window object and use it as the prototype for the
+ // shadow global object.
+ v8::Persistent<v8::FunctionTemplate> window_descriptor =
+ GetTemplate(V8ClassIndex::DOMWINDOW);
+ v8::Local<v8::Object> window_peer =
+ SafeAllocation::NewInstance(window_descriptor->GetFunction());
+ if (window_peer.IsEmpty())
+ return;
+
+ DOMWindow* window = m_frame->domWindow();
+
+ // Get rid of the old window peer object if one exists.
+ dom_object_map().forget(window);
+
+ // Setup the peer object for the DOM window.
+ dom_object_map().set(window, v8::Persistent<v8::Object>::New(window_peer));
+ // Wrap the window.
+ SetDOMWrapper(window_peer,
+ V8ClassIndex::ToInt(V8ClassIndex::DOMWINDOW),
+ window);
+ // Insert the window instance as the prototype of the shadow object.
+ v8::Handle<v8::Object> v8_global = context->Global();
+ v8_global->Set(v8::String::New("__proto__"), window_peer);
+
+ context->SetSecurityToken(GenerateSecurityToken(context));
+
+ V8Proxy::retrieveFrame(context)->loader()->dispatchWindowObjectAvailable();
+
+ if (JSBridge::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
+ // based apps use randomness in URLs to unique-ify urls for proxies.
+ // Unfortunately, this breaks playback.
+ // To work around this, we take the two most common client-side randomness
+ // generators and make them constant. They really need to be constant
+ // (rather than a constant seed followed by constant change)
+ // because the playback mode wants flexibility in how it plays them back
+ // and cannot always guarantee that requests for randomness are played back
+ // in exactly the same order in which they were recorded.
+ String script(
+ "Math.random = function() { return 0.5; };"
+ "__ORIGDATE__ = Date;"
+ "Date.__proto__.now = function() { "
+ " return new __ORIGDATE__(1204251968254); };"
+ "Date = function() { return Date.now(); };");
+ this->Evaluate(String(), 0, script, 0);
+ }
+}
+
+
+v8::Handle<v8::Value> V8Proxy::GenerateSecurityToken(
+ v8::Local<v8::Context> context) {
+ Document* document = V8Proxy::retrieveFrame(context)->document();
+ if (!document)
+ return context->Global();
+
+ // Ask the document's SecurityOrigin to generate a security token.
+ // If two tokens are equal, then the SecurityOrigins canAccess each other.
+ // If two tokens are not equal, then we have to call canAccess.
+ String token = document->securityOrigin()->securityToken();
+
+ // An empty token means we always have to call canAccess. In this case, we
+ // use the global object as the security token to avoid calling canAccess
+ // when a script accesses its own objects.
+ if (token.isEmpty())
+ return context->Global();
+
+ CString utf8_token = token.utf8();
+ // NOTE: V8 does identity comparison in fast path, must use a symbol
+ // as the security token.
+ return v8::String::NewSymbol(utf8_token.data(), utf8_token.length());
+}
+
+
+void V8Proxy::SetDOMException(int exception_code) {
+ if (exception_code <= 0) return;
+
+ if (exception_code == XMLHttpRequestException::PERMISSION_DENIED) {
+ ThrowError(GENERAL_ERROR, "Permission denied");
+ return;
+ }
+
+ ExceptionCodeDescription description;
+ getExceptionCodeDescription(exception_code, description);
+
+ v8::Handle<v8::Value> exception;
+ switch (description.type) {
+ case DOMExceptionType:
+ exception = ToV8Object(V8ClassIndex::DOMCOREEXCEPTION,
+ new DOMCoreException(description));
+ break;
+ case RangeExceptionType:
+ exception = ToV8Object(V8ClassIndex::RANGEEXCEPTION,
+ new RangeException(description));
+ break;
+ case EventExceptionType:
+ exception = ToV8Object(V8ClassIndex::EVENTEXCEPTION,
+ new EventException(description));
+ break;
+ case XMLHttpRequestExceptionType:
+ exception = ToV8Object(V8ClassIndex::XMLHTTPREQUESTEXCEPTION,
+ new XMLHttpRequestException(description));
+ break;
+#if ENABLE(SVG)
+ case SVGExceptionType:
+ exception = ToV8Object(V8ClassIndex::SVGEXCEPTION,
+ new SVGException(description));
+ break;
+#endif
+#if ENABLE(XPATH)
+ case XPathExceptionType:
+ exception = ToV8Object(V8ClassIndex::XPATHEXCEPTION,
+ new XPathException(description));
+ break;
+#endif
+ }
+
+ ASSERT(!exception.IsEmpty());
+ v8::ThrowException(exception);
+}
+
+
+v8::Handle<v8::Value> V8Proxy::ThrowError(ErrorType type, const char* message) {
+ switch (type) {
+ case RANGE_ERROR:
+ return v8::ThrowException(v8::Exception::RangeError(v8String(message)));
+ case REFERENCE_ERROR:
+ return v8::ThrowException(
+ v8::Exception::ReferenceError(v8String(message)));
+ case SYNTAX_ERROR:
+ return v8::ThrowException(v8::Exception::SyntaxError(v8String(message)));
+ case TYPE_ERROR:
+ return v8::ThrowException(v8::Exception::TypeError(v8String(message)));
+ case GENERAL_ERROR:
+ return v8::ThrowException(v8::Exception::Error(v8String(message)));
+ default:
+ ASSERT(false);
+ return v8::Handle<v8::Value>();
+ }
+}
+
+
+v8::Local<v8::Context> V8Proxy::GetContext(Frame* frame) {
+ V8Proxy* proxy = retrieve(frame);
+ if (!proxy)
+ return v8::Local<v8::Context>();
+
+ proxy->initContextIfNeeded();
+ return proxy->GetContext();
+}
+
+
+v8::Local<v8::Context> V8Proxy::GetCurrentContext() {
+ return v8::Context::GetCurrent();
+}
+
+
+v8::Handle<v8::Value> V8Proxy::ToV8Object(V8ClassIndex::V8WrapperType type,
+ void* imp) {
+ ASSERT(type != V8ClassIndex::EVENTLISTENER);
+ ASSERT(type != V8ClassIndex::EVENTTARGET);
+ ASSERT(type != V8ClassIndex::EVENT);
+
+ if (!imp) return v8::Null();
+
+#define MAKE_CASE(TYPE, NAME) case V8ClassIndex::TYPE:
+
+ switch (type) {
+ NODE_WRAPPER_TYPES(MAKE_CASE)
+ HTMLELEMENT_TYPES(MAKE_CASE)
+#if ENABLE(SVG)
+ SVGNODE_WRAPPER_TYPES(MAKE_CASE)
+ SVGELEMENT_TYPES(MAKE_CASE)
+#endif
+ return NodeToV8Object(static_cast<Node*>(imp));
+ case V8ClassIndex::CSSVALUE:
+ return CSSValueToV8Object(static_cast<CSSValue*>(imp));
+ case V8ClassIndex::CSSRULE:
+ return CSSRuleToV8Object(static_cast<CSSRule*>(imp));
+ case V8ClassIndex::STYLESHEET:
+ return StyleSheetToV8Object(static_cast<StyleSheet*>(imp));
+ case V8ClassIndex::DOMWINDOW:
+ 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);
+ }
+#endif
+ default:
+ break;
+ }
+
+#undef MAKE_CASE
+
+ // Non DOM node
+ Peerable* obj = static_cast<Peerable*>(imp);
+ v8::Persistent<v8::Object> result = dom_object_map().get(obj);
+ if (result.IsEmpty()) {
+ v8::Local<v8::Object> v8obj = InstantiateV8Object(type, imp);
+ if (!v8obj.IsEmpty()) {
+ result = v8::Persistent<v8::Object>::New(v8obj);
+ dom_object_map().set(obj, result);
+ }
+ }
+ return result;
+}
+
+
+V8ClassIndex::V8WrapperType V8Proxy::GetDOMWrapperType(
+ v8::Handle<v8::Object> object) {
+ if (!MaybeDOMWrapper(object)) {
+ return V8ClassIndex::INVALID_CLASS_INDEX;
+ }
+
+ v8::Handle<v8::Value> type = object->GetInternalField(1);
+ return V8ClassIndex::FromInt(type->Int32Value());
+}
+
+
+void* V8Proxy::FastToNativeObjectImpl(V8ClassIndex::V8WrapperType type,
+ v8::Handle<v8::Value> object) {
+ // Native event listener is per frame, it cannot be handled
+ // by this generic function.
+ ASSERT(type != V8ClassIndex::EVENTLISTENER);
+ ASSERT(type != V8ClassIndex::EVENTTARGET);
+
+ ASSERT(MaybeDOMWrapper(object));
+
+#define MAKE_CASE(TYPE, NAME) case V8ClassIndex::TYPE:
+ switch (type) {
+ NODE_WRAPPER_TYPES(MAKE_CASE)
+ HTMLELEMENT_TYPES(MAKE_CASE)
+#if ENABLE(SVG)
+ SVGNODE_WRAPPER_TYPES(MAKE_CASE)
+ SVGELEMENT_TYPES(MAKE_CASE)
+#endif
+ return FastDOMWrapperToNative<Node>(object);
+ case V8ClassIndex::XMLHTTPREQUEST:
+ return FastDOMWrapperToNative<XMLHttpRequest>(object);
+ case V8ClassIndex::EVENT:
+ return FastDOMWrapperToNative<Event>(object);
+ case V8ClassIndex::CSSRULE:
+ return FastDOMWrapperToNative<CSSRule>(object);
+ default:
+ break;
+ }
+#undef MAKE_CASE
+
+ return FastDOMWrapperToNative<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>();
+}
+
+
+void* V8Proxy::ToNativeObjectImpl(V8ClassIndex::V8WrapperType type,
+ v8::Handle<v8::Value> object) {
+ // Native event listener is per frame, it cannot be handled
+ // by this generic function.
+ ASSERT(type != V8ClassIndex::EVENTLISTENER);
+ ASSERT(type != V8ClassIndex::EVENTTARGET);
+
+ // It could be null, undefined, etc.
+ if (!MaybeDOMWrapper(object))
+ return 0;
+
+#define MAKE_CASE(TYPE, NAME) case V8ClassIndex::TYPE:
+ switch (type) {
+ NODE_WRAPPER_TYPES(MAKE_CASE)
+ HTMLELEMENT_TYPES(MAKE_CASE)
+#if ENABLE(SVG)
+ SVGNODE_WRAPPER_TYPES(MAKE_CASE)
+ SVGELEMENT_TYPES(MAKE_CASE)
+#endif
+ return DOMWrapperToNative<Node>(object);
+ case V8ClassIndex::XMLHTTPREQUEST:
+ return DOMWrapperToNative<XMLHttpRequest>(object);
+ case V8ClassIndex::EVENT:
+ return DOMWrapperToNative<Event>(object);
+ case V8ClassIndex::CSSRULE:
+ return DOMWrapperToNative<CSSRule>(object);
+ default:
+ break;
+ }
+#undef MAKE_CASE
+
+ return DOMWrapperToNative<Peerable>(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;
+
+ NodeFilterCondition* cond = new V8NodeFilterCondition(filter);
+ return new NodeFilter(cond);
+}
+
+
+v8::Local<v8::Object> V8Proxy::InstantiateV8Object(
+ V8ClassIndex::V8WrapperType type, void* imp) {
+ V8ClassIndex::V8WrapperType wrapper_type = type;
+ // Make a special case for document.all
+ if (type == V8ClassIndex::HTMLCOLLECTION &&
+ static_cast<HTMLCollection*>(imp)->type() == HTMLCollection::DocAll) {
+ wrapper_type = V8ClassIndex::UNDETECTABLEHTMLCOLLECTION;
+ }
+
+ // Special case for HTMLInputElements that support selection.
+ if (type == V8ClassIndex::HTMLINPUTELEMENT) {
+ HTMLInputElement* element = static_cast<HTMLInputElement*>(imp);
+ if (element->canHaveSelection()) {
+ wrapper_type = V8ClassIndex::HTMLSELECTIONINPUTELEMENT;
+ }
+ }
+
+ v8::Persistent<v8::FunctionTemplate> desc = GetTemplate(wrapper_type);
+ v8::Local<v8::Function> function = desc->GetFunction();
+ v8::Local<v8::Object> instance = SafeAllocation::NewInstance(function);
+ if (!instance.IsEmpty()) {
+ // Avoid setting the DOM wrapper for failed allocations.
+ SetDOMWrapper(instance, V8ClassIndex::ToInt(type), imp);
+ }
+ return instance;
+}
+
+v8::Handle<v8::Value> V8Proxy::CheckNewLegal(const v8::Arguments& args) {
+ if (!AllowAllocation::m_current) {
+ return ThrowError(TYPE_ERROR, "Illegal constructor");
+ } else {
+ return args.This();
+ }
+}
+
+
+v8::Handle<v8::Value> V8Proxy::WrapCPointer(void* cptr) {
+ // Represent void* as int
+ int addr = reinterpret_cast<int>(cptr);
+ if ((addr & 0x01) == 0) {
+ return v8::Number::New(addr >> 1);
+ } else {
+ return v8::External::New(cptr);
+ }
+}
+
+
+void* V8Proxy::ExtractCPointerImpl(v8::Handle<v8::Value> obj) {
+ if (obj->IsNumber()) {
+ int addr = obj->Int32Value();
+ return reinterpret_cast<void*>(addr << 1);
+ } else if (obj->IsExternal()) {
+ return v8::Handle<v8::External>::Cast(obj)->Value();
+ }
+ ASSERT(false);
+ return 0;
+}
+
+
+bool V8Proxy::SetDOMWrapper(v8::Handle<v8::Object> obj, int type, void* cptr) {
+ ASSERT(obj->InternalFieldCount() >= 2);
+ obj->SetInternalField(0, WrapCPointer(cptr));
+ obj->SetInternalField(1, v8::Integer::New(type));
+ return true;
+}
+
+
+bool V8Proxy::MaybeDOMWrapper(v8::Handle<v8::Value> value) {
+ if (value.IsEmpty() || !value->IsObject()) return false;
+
+ v8::Handle<v8::Object> obj = v8::Handle<v8::Object>::Cast(value);
+ if (obj->InternalFieldCount() < 2) return false;
+
+ v8::Handle<v8::Value> wrapper = obj->GetInternalField(0);
+ if (!wrapper->IsNumber() && !wrapper->IsExternal()) return false;
+
+ v8::Handle<v8::Value> type = obj->GetInternalField(1);
+ if (!type->IsNumber()) return false;
+
+ return true;
+}
+
+
+#define FOR_EACH_TAG(macro) \
+ macro(a, ANCHOR) \
+ macro(applet, APPLET) \
+ macro(area, AREA) \
+ macro(base, BASE) \
+ macro(basefont, BASEFONT) \
+ macro(blockquote, BLOCKQUOTE) \
+ macro(body, BODY) \
+ macro(br, BR) \
+ macro(button, BUTTON) \
+ macro(caption, TABLECAPTION) \
+ macro(col, TABLECOL) \
+ macro(colgroup, TABLECOL) \
+ macro(del, MOD) \
+ macro(canvas, CANVAS) \
+ macro(dir, DIRECTORY) \
+ macro(div, DIV) \
+ macro(dl, DLIST) \
+ macro(embed, EMBED) \
+ macro(fieldset, FIELDSET) \
+ macro(font, FONT) \
+ macro(form, FORM) \
+ macro(frame, FRAME) \
+ macro(frameset, FRAMESET) \
+ macro(h1, HEADING) \
+ macro(h2, HEADING) \
+ macro(h3, HEADING) \
+ macro(h4, HEADING) \
+ macro(h5, HEADING) \
+ macro(h6, HEADING) \
+ macro(head, HEAD) \
+ macro(hr, HR) \
+ macro(html, HTML) \
+ macro(img, IMAGE) \
+ macro(iframe, IFRAME) \
+ macro(image, IMAGE) \
+ macro(input, INPUT) \
+ macro(ins, MOD) \
+ macro(isindex, ISINDEX) \
+ macro(keygen, SELECT) \
+ macro(label, LABEL) \
+ macro(legend, LEGEND) \
+ macro(li, LI) \
+ macro(link, LINK) \
+ macro(listing, PRE) \
+ macro(map, MAP) \
+ macro(marquee, MARQUEE) \
+ macro(menu, MENU) \
+ macro(meta, META) \
+ macro(object, OBJECT) \
+ macro(ol, OLIST) \
+ macro(optgroup, OPTGROUP) \
+ macro(option, OPTION) \
+ macro(p, PARAGRAPH) \
+ macro(param, PARAM) \
+ macro(pre, PRE) \
+ macro(q, QUOTE) \
+ macro(script, SCRIPT) \
+ macro(select, SELECT) \
+ macro(style, STYLE) \
+ macro(table, TABLE) \
+ macro(thead, TABLESECTION) \
+ macro(tbody, TABLESECTION) \
+ macro(tfoot, TABLESECTION) \
+ macro(td, TABLECELL) \
+ macro(th, TABLECELL) \
+ macro(tr, TABLEROW) \
+ macro(textarea, TEXTAREA) \
+ macro(title, TITLE) \
+ macro(ul, ULIST) \
+ macro(xmp, PRE)
+
+V8ClassIndex::V8WrapperType V8Proxy::GetHTMLElementType(HTMLElement* element) {
+ static HashMap<String, V8ClassIndex::V8WrapperType> map;
+ if (map.isEmpty()) {
+#define ADD_TO_HASH_MAP(tag, name) \
+ map.set(#tag, V8ClassIndex::HTML##name##ELEMENT);
+FOR_EACH_TAG(ADD_TO_HASH_MAP)
+#undef ADD_TO_HASH_MAP
+ }
+
+ V8ClassIndex::V8WrapperType t = map.get(element->localName().impl());
+ if (t == 0) return V8ClassIndex::HTMLELEMENT;
+ return t;
+}
+#undef FOR_EACH_TAG
+
+#if ENABLE(SVG)
+
+#if ENABLE(SVG_ANIMATION)
+#define FOR_EACH_ANIMATION_TAG(macro) \
+ macro(animateColor, ANIMATECOLOR) \
+ macro(animate, ANIMATE) \
+ macro(animateTransform, ANIMATETRANSFORM) \
+ macro(set, SET)
+#else
+#define FOR_EACH_ANIMATION_TAG(macro)
+#endif
+
+#if ENABLE(SVG_FILTERS)
+#define FOR_EACH_FILTERS_TAG(macro) \
+ macro(feBlend, FEBLEND) \
+ macro(feColorMatrix, FECOLORMATRIX) \
+ macro(feComponentTransfer, FECOMPONENTTRANSFER) \
+ macro(feComposite, FECOMPOSITE) \
+ macro(feDiffuseLighting, FEDIFFUSELIGHTING) \
+ macro(feDisplacementMap, FEDISPLACEMENTMAP) \
+ macro(feDistantLight, FEDISTANTLIGHT) \
+ macro(feFlood, FEFLOOD) \
+ macro(feFuncA, FEFUNCA) \
+ macro(feFuncB, FEFUNCB) \
+ macro(feFuncG, FEFUNCG) \
+ macro(feFuncR, FEFUNCR) \
+ macro(feGaussianBlur, FEGAUSSIANBLUR) \
+ macro(feImage, FEIMAGE) \
+ macro(feMerge, FEMERGE) \
+ macro(feMergeNode, FEMERGENODE) \
+ macro(feOffset, FEOFFSET) \
+ macro(fePointLight, FEPOINTLIGHT) \
+ macro(feSpecularLighting, FESPECULARLIGHTING) \
+ macro(feSpotLight, FESPOTLIGHT) \
+ macro(feTile, FETILE) \
+ macro(feTurbulence, FETURBULENCE) \
+ macro(filter, FILTER)
+#else
+#define FOR_EACH_FILTERS_TAG(macro)
+#endif
+
+#if ENABLE(SVG_FONTS)
+#define FOR_EACH_FONTS_TAG(macro) \
+ macro(definition-src, DEFINITIONSRC) \
+ macro(font-face, FONTFACE) \
+ macro(font-face-format, FONTFACEFORMAT) \
+ macro(font-face-name, FONTFACENAME) \
+ macro(font-face-src, FONTFACESRC) \
+ macro(font-face-uri, FONTFACEURI)
+#else
+#define FOR_EACH_FONTS_TAG(marco)
+#endif
+
+#if ENABLE(SVG_FOREIGN_OBJECT)
+#define FOR_EACH_FOREIGN_OBJECT_TAG(macro) \
+ macro(foreignObject, FOREIGNOBJECT)
+#else
+#define FOR_EACH_FOREIGN_OBJECT_TAG(macro)
+#endif
+
+#if ENABLE(SVG_USE)
+#define FOR_EACH_USE_TAG(macro) \
+ macro(use, USE)
+#else
+#define FOR_EACH_USE_TAG(macro)
+#endif
+
+#define FOR_EACH_TAG(macro) \
+ FOR_EACH_ANIMATION_TAG(macro) \
+ FOR_EACH_FILTERS_TAG(macro) \
+ FOR_EACH_FONTS_TAG(macro) \
+ FOR_EACH_FOREIGN_OBJECT_TAG(macro) \
+ FOR_EACH_USE_TAG(macro) \
+ macro(a, A) \
+ macro(circle, CIRCLE) \
+ macro(clipPath, CLIPPATH) \
+ macro(cursor, CURSOR) \
+ macro(defs, DEFS) \
+ macro(desc, DESC) \
+ macro(ellipse, ELLIPSE) \
+ macro(g, G) \
+ macro(image, IMAGE) \
+ macro(linearGradient, LINEARGRADIENT) \
+ macro(line, LINE) \
+ macro(marker, MARKER) \
+ macro(mask, MASK) \
+ macro(metadata, METADATA) \
+ macro(path, PATH) \
+ macro(pattern, PATTERN) \
+ macro(polyline, POLYLINE) \
+ macro(polygon, POLYGON) \
+ macro(radialGradient, RADIALGRADIENT) \
+ macro(rect, RECT) \
+ macro(script, SCRIPT) \
+ macro(stop, STOP) \
+ macro(style, STYLE) \
+ macro(svg, SVG) \
+ macro(switch, SWITCH) \
+ macro(symbol, SYMBOL) \
+ macro(text, TEXT) \
+ macro(textPath, TEXTPATH) \
+ macro(title, TITLE) \
+ macro(tref, TREF) \
+ macro(tspan, TSPAN) \
+ macro(view, VIEW) \
+ // end of macro
+
+V8ClassIndex::V8WrapperType V8Proxy::GetSVGElementType(SVGElement* element) {
+ static HashMap<String, V8ClassIndex::V8WrapperType> map;
+ if (map.isEmpty()) {
+#define ADD_TO_HASH_MAP(tag, name) \
+ map.set(#tag, V8ClassIndex::SVG##name##ELEMENT);
+FOR_EACH_TAG(ADD_TO_HASH_MAP)
+#undef ADD_TO_HASH_MAP
+ }
+
+ V8ClassIndex::V8WrapperType t = map.get(element->localName().impl());
+ if (t == 0) return V8ClassIndex::SVGELEMENT;
+ return t;
+}
+#undef FOR_EACH_TAG
+
+#endif // ENABLE(SVG)
+
+
+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()) {
+ return peer;
+ }
+
+ V8ClassIndex::V8WrapperType type = V8ClassIndex::EVENT;
+
+ if (event->isKeyboardEvent())
+ type = V8ClassIndex::KEYBOARDEVENT;
+ else if (event->isMouseEvent())
+ type = V8ClassIndex::MOUSEEVENT;
+ else if (event->isMessageEvent())
+ type = V8ClassIndex::MESSAGEEVENT;
+ else if (event->isWheelEvent())
+ type = V8ClassIndex::WHEELEVENT;
+ else if (event->isTextEvent())
+ type = V8ClassIndex::TEXTEVENT;
+ else if (event->isUIEvent())
+ type = V8ClassIndex::UIEVENT;
+ else if (event->isMutationEvent())
+ type = V8ClassIndex::MUTATIONEVENT;
+ else if (event->isOverflowEvent())
+ type = V8ClassIndex::OVERFLOWEVENT;
+ else if (event->isProgressEvent())
+ type = V8ClassIndex::PROGRESSEVENT;
+
+ // Set the peer object for future access.
+ v8::Handle<v8::Object> result = InstantiateV8Object(type, event);
+ if (result.IsEmpty()) {
+ // Instantiation failed. Avoid updating the DOM object map and
+ // return null which is already handled by callers of this function
+ // in case the event is NULL.
+ return v8::Null();
+ }
+
+ dom_object_map().set(event, v8::Persistent<v8::Object>::New(result));
+
+ return result;
+}
+
+
+v8::Handle<v8::Object> V8Proxy::NodeToV8Object(Node* node) {
+ if (!node) return v8::Handle<v8::Object>();
+
+ v8::Handle<v8::Object> peer = dom_node_map().get(node);
+ 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()) {
+ type = GetHTMLElementType(static_cast<HTMLElement*>(node));
+#if ENABLE(SVG)
+ } else if (node->isSVGElement()) {
+ type = GetSVGElementType(static_cast<SVGElement*>(node));
+#endif
+ } else {
+ type = V8ClassIndex::ELEMENT;
+ }
+ break;
+ case Node::ATTRIBUTE_NODE:
+ type = V8ClassIndex::ATTR;
+ break;
+ case Node::TEXT_NODE:
+ type = V8ClassIndex::TEXT;
+ break;
+ case Node::CDATA_SECTION_NODE:
+ type = V8ClassIndex::CDATASECTION;
+ break;
+ case Node::ENTITY_NODE:
+ type = V8ClassIndex::ENTITY;
+ break;
+ case Node::PROCESSING_INSTRUCTION_NODE:
+ type = V8ClassIndex::PROCESSINGINSTRUCTION;
+ break;
+ case Node::COMMENT_NODE:
+ type = V8ClassIndex::COMMENT;
+ break;
+ case Node::DOCUMENT_NODE: {
+ is_document = true;
+ Document* doc = static_cast<Document*>(node);
+ if (doc->isHTMLDocument()) {
+ type = V8ClassIndex::HTMLDOCUMENT;
+#if ENABLE(SVG)
+ } else if (doc->isSVGDocument()) {
+ type = V8ClassIndex::SVGDOCUMENT;
+#endif
+ } else {
+ type = V8ClassIndex::DOCUMENT;
+ }
+ break;
+ }
+ case Node::DOCUMENT_TYPE_NODE:
+ type = V8ClassIndex::DOCUMENTTYPE;
+ break;
+ case Node::NOTATION_NODE:
+ type = V8ClassIndex::NOTATION;
+ break;
+ case Node::DOCUMENT_FRAGMENT_NODE:
+ type = V8ClassIndex::DOCUMENTFRAGMENT;
+ break;
+ case Node::ENTITY_REFERENCE_NODE:
+ type = V8ClassIndex::ENTITYREFERENCE;
+ break;
+ default:
+ type = V8ClassIndex::NODE;
+ }
+
+ // Set the peer object for future access.
+ // InstantiateV8Object automatically casts node to Peerable*.
+ v8::Local<v8::Object> result = InstantiateV8Object(type, node);
+ if (result.IsEmpty()) {
+ // If instantiation failed it's important not to add the result
+ // to the DOM node map. Instead we return an empty handle, which
+ // should already be handled by callers of this function in case
+ // the node is NULL.
+ return result;
+ }
+
+ dom_node_map().set(node, v8::Persistent<v8::Object>::New(result));
+
+ if (is_document) {
+ Document* doc = static_cast<Document*>(node);
+ V8Proxy* proxy = V8Proxy::retrieve(doc->frame());
+ if (proxy) {
+ proxy->UpdateDocumentHandle(result);
+ }
+
+ if (type == V8ClassIndex::HTMLDOCUMENT) {
+ // Create marker object and insert it in two internal fields.
+ // This is used to implement temporary shadowing of
+ // document.all.
+ ASSERT(result->InternalFieldCount() ==
+ V8Custom::kHTMLDocumentInternalFieldCount);
+ v8::Local<v8::Object> marker = v8::Object::New();
+ result->SetInternalField(V8Custom::kHTMLDocumentMarkerIndex, marker);
+ result->SetInternalField(V8Custom::kHTMLDocumentShadowIndex, marker);
+ }
+ }
+
+ return result;
+}
+
+
+void V8Proxy::UpdateDocumentHandle(v8::Local<v8::Object> handle) {
+ // If the old handle is not empty, release it.
+ if (!m_document.IsEmpty()) {
+#ifndef NDEBUG
+ UnregisterGlobalHandle(this, m_document);
+#endif
+ m_document.Dispose();
+ m_document.Clear();
+ }
+
+ m_document = v8::Persistent<v8::Object>::New(handle);
+#ifndef NDEBUG
+ RegisterGlobalHandle(PROXY, this, m_document);
+#endif
+}
+
+
+// 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();
+
+#if ENABLE(SVG)
+ SVGElementInstance* instance = target->toSVGElementInstance();
+ if (instance) return ToV8Object(V8ClassIndex::SVGELEMENTINSTANCE, instance);
+#endif
+
+ Node* node = target->toNode();
+ if (node) return NodeToV8Object(node);
+
+ // XMLHttpRequest is created within its JS counterpart.
+ XMLHttpRequest* xhr = target->toXMLHttpRequest();
+ if (xhr) {
+ v8::Handle<v8::Object> peer = dom_object_map().get(xhr);
+ ASSERT(!peer.IsEmpty());
+ return peer;
+ }
+
+ ASSERT(0);
+ return v8::Handle<v8::Value>();
+}
+
+
+v8::Handle<v8::Value> V8Proxy::EventListenerToV8Object(
+ EventListener* listener) {
+ if (listener == 0) return v8::Null();
+
+ // TODO(fqian): can a user take a lazy event listener and set to other places?
+ V8AbstractEventListener* v8listener =
+ static_cast<V8AbstractEventListener*>(listener);
+ return v8listener->GetListenerObject();
+}
+
+
+v8::Handle<v8::Value> V8Proxy::DOMImplementationToV8Object(
+ DOMImplementation* impl) {
+ v8::Handle<v8::Object> result =
+ InstantiateV8Object(V8ClassIndex::DOMIMPLEMENTATION, impl);
+ if (result.IsEmpty()) {
+ // If the instantiation failed, we ignore it and return null instead
+ // of returning an empty handle.
+ return v8::Null();
+ }
+ return result;
+}
+
+
+v8::Handle<v8::Object> V8Proxy::StyleSheetToV8Object(StyleSheet* sheet) {
+ if (!sheet) return v8::Handle<v8::Object>();
+
+ v8::Handle<v8::Object> peer = dom_object_map().get(sheet);
+ if (!peer.IsEmpty()) {
+ return peer;
+ }
+
+ V8ClassIndex::V8WrapperType type = V8ClassIndex::STYLESHEET;
+ if (sheet->isCSSStyleSheet()) type = V8ClassIndex::CSSSTYLESHEET;
+
+ v8::Handle<v8::Object> result = InstantiateV8Object(type, sheet);
+ if (!result.IsEmpty()) {
+ // Only update the DOM object map if the result is non-empty.
+ dom_object_map().set(sheet, v8::Persistent<v8::Object>::New(result));
+ }
+ return result;
+}
+
+
+v8::Handle<v8::Object> V8Proxy::CSSValueToV8Object(CSSValue* value) {
+ if (!value) return v8::Handle<v8::Object>();
+
+ v8::Handle<v8::Object> peer = dom_object_map().get(value);
+ if (!peer.IsEmpty()) {
+ return peer;
+ }
+
+ V8ClassIndex::V8WrapperType type;
+
+ if (value->isValueList())
+ type = V8ClassIndex::CSSVALUELIST;
+ else if (value->isPrimitiveValue())
+ type = V8ClassIndex::CSSPRIMITIVEVALUE;
+#if ENABLE(SVG)
+ else if (value->isSVGPaint())
+ type = V8ClassIndex::SVGPAINT;
+ else if (value->isSVGColor())
+ type = V8ClassIndex::SVGCOLOR;
+#endif
+ else
+ type = V8ClassIndex::CSSVALUE;
+
+ v8::Handle<v8::Object> result = InstantiateV8Object(type, value);
+ 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::Object> V8Proxy::CSSRuleToV8Object(CSSRule* rule) {
+ if (!rule) return v8::Handle<v8::Object>();
+
+ 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, 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::Object> V8Proxy::WindowToV8Object(DOMWindow* window) {
+ // 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::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.
+
+ 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);
+}
+
+
+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
new file mode 100644
index 0000000..7bee90e
--- /dev/null
+++ b/webkit/port/bindings/v8/v8_proxy.h
@@ -0,0 +1,571 @@
+// Copyright 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.
+
+#ifndef V8_PROXY_H__
+#define V8_PROXY_H__
+
+#include <v8.h>
+#include "v8_index.h"
+#include "v8_custom.h"
+#include "v8_utility.h"
+#include "Node.h"
+#include "NodeFilter.h"
+#include "PlatformString.h" // for WebCore::String
+#include <wtf/HashMap.h> // for HashMap
+
+#include <iterator>
+#include <list>
+
+#ifdef ENABLE_DOM_STATS_COUNTERS
+#include "base/stats_counters.h"
+#define INC_STATS(name) StatsCounter(name).Increment()
+#else
+#define INC_STATS(name)
+#endif
+
+namespace WebCore {
+
+class CSSStyleDeclaration;
+class DOMImplementation;
+class Element;
+class Event;
+class EventListener;
+class Frame;
+class HTMLCollection;
+class HTMLOptionsCollection;
+class HTMLElement;
+class HTMLDocument;
+class MediaList;
+class NamedNodeMap;
+class Node;
+class NodeList;
+class Screen;
+class String;
+class StyleSheet;
+class SVGElement;
+class DOMWindow;
+class Document;
+class EventTarget;
+class Event;
+class EventListener;
+class Navigator;
+class MimeType;
+class MimeTypeArray;
+class Plugin;
+class PluginArray;
+class EventTargetNode;
+class StyleSheetList;
+class CSSValue;
+class CSSRule;
+class CSSRuleList;
+class CSSValueList;
+class NodeFilter;
+
+#if ENABLE(SVG)
+class SVGElementInstance;
+#endif
+
+class V8EventListener;
+class V8XHREventListener;
+typedef std::list<V8EventListener*> V8EventListenerList;
+
+// TODO(fqian): use standard logging facilities in WebCore.
+void log_info(Frame* frame, const String& msg, const String& url);
+
+
+#ifndef NDEBUG
+
+#define GlobalHandleTypeList(V) \
+ V(PROXY) \
+ V(NPOBJECT) \
+ V(SCHEDULED_ACTION) \
+ V(EVENT_LISTENER) \
+ V(NODE_FILTER) \
+ V(JSINSTANCE) \
+
+
+// Host information of persistent handles.
+enum GlobalHandleType {
+#define ENUM(name) name,
+ GlobalHandleTypeList(ENUM)
+#undef ENUM
+};
+
+
+class GlobalHandleInfo {
+ public:
+ GlobalHandleInfo(void* host, GlobalHandleType type)
+ : host_(host), type_(type) { }
+ void* host_;
+ GlobalHandleType type_;
+};
+
+#endif // NDEBUG
+
+class V8Proxy {
+ public:
+ // The types of javascript errors that can be thrown.
+ enum ErrorType {
+ RANGE_ERROR,
+ REFERENCE_ERROR,
+ SYNTAX_ERROR,
+ TYPE_ERROR,
+ GENERAL_ERROR
+ };
+
+ explicit V8Proxy(Frame* frame)
+ : m_frame(frame), m_inlineCode(false),
+ m_timerCallback(false), m_recursion(0) { }
+
+ ~V8Proxy();
+
+ // Clear security token by setting the security token
+ // for the context to the global object.
+ void ClearSecurityToken();
+
+ // Clear page-specific data, exception keep the global object identify.
+ void clear();
+
+ // Destroy the global object.
+ void DestroyGlobal();
+
+ Frame* frame() { return m_frame; }
+
+ // TODO(mpcomplete): Need comment. User Gesture related.
+ bool inlineCode() const { return m_inlineCode; }
+ void setInlineCode(bool value) { m_inlineCode = value; }
+
+ bool timerCallback() const { return m_timerCallback; }
+ void setTimerCallback(bool value) { m_timerCallback = value; }
+
+ // Has the context for this proxy been initialized?
+ bool ContextInitialized();
+
+ // Disconnects the proxy from its owner frame,
+ // and clears all timeouts on the DOM window.
+ void disconnectFrame();
+
+ bool isEnabled();
+
+ // Remove 'document' property from the global object.
+ void clearDocumentWrapper();
+
+ // Find/Create/Remove event listener wrappers.
+ V8EventListener* FindV8EventListener(v8::Local<v8::Value> listener,
+ bool html);
+ V8EventListener* FindOrCreateV8EventListener(v8::Local<v8::Value> listener,
+ bool html);
+
+ V8EventListener* FindXHREventListener(v8::Local<v8::Value> listener,
+ bool html);
+ V8EventListener* FindOrCreateXHREventListener(v8::Local<v8::Value> listener,
+ bool html);
+
+ void RemoveV8EventListener(V8EventListener* listener);
+ void RemoveXHREventListener(V8XHREventListener* listener);
+
+ // Protect/Unprotect JS wrappers of a DOM object.
+ static void GCProtect(Peerable* dom_object);
+ static void GCUnprotect(Peerable* dom_object);
+
+ // Create a lazy event listener.
+ EventListener* createHTMLEventHandler(const String& functionName,
+ const String& code, Node* node);
+#if ENABLE(SVG)
+ EventListener* createSVGEventHandler(const String& functionName,
+ const String& code, Node* node);
+
+ static void SetSVGContext(void* object, SVGElement* context);
+ static SVGElement* GetSVGContext(void* object);
+#endif
+
+ void setEventHandlerLineno(int lineno) { m_handlerLineno = lineno; }
+ void finishedWithEvent(Event* event) { }
+
+ // Evaluate a script file in the current execution environment.
+ // The caller must hold an execution context.
+ // If cannot evalute the script, it returns an error.
+ v8::Local<v8::Value> Evaluate(const String& filename, int baseLine,
+ const String& code, Node* node);
+
+ // Run an already compiled script.
+ v8::Local<v8::Value> RunScript(v8::Handle<v8::Script> script,
+ bool inline_code);
+
+ // Call the function with the given receiver and arguments.
+ v8::Local<v8::Value> CallFunction(v8::Handle<v8::Function> function,
+ v8::Handle<v8::Object> receiver,
+ int argc,
+ v8::Handle<v8::Value> argv[]);
+
+ // Returns the window object of the currently executing context.
+ static DOMWindow* retrieveWindow();
+ // Returns V8Proxy object of the currently executing context.
+ static V8Proxy* retrieve();
+ // Returns V8Proxy object associated with a frame.
+ static V8Proxy* retrieve(Frame* frame);
+ // Returns the frame object of the window object associated
+ // with the currently executing context.
+ static Frame* retrieveFrame();
+ // Returns the frame object of the window object associated with
+ // an context.
+ static Frame* retrieveFrame(v8::Handle<v8::Context> context);
+ // Returns the frame that started JS execution.
+ // NOTE: cannot declare retrieveActiveFrame as inline function,
+ // VS complains at linking time.
+ static Frame* retrieveActiveFrame();
+
+ // Returns V8 Context of a frame. If none exists, creates
+ // a new context. It is potentially slow and consumes memory.
+ static v8::Local<v8::Context> GetContext(Frame* frame);
+ static v8::Local<v8::Context> GetCurrentContext();
+
+ // If the current context causes out of memory, JavaScript setting
+ // is disabled and it returns true.
+ static bool HandleOutOfMemory();
+
+ // Generate the security token for a context.
+ static v8::Handle<v8::Value> GenerateSecurityToken(
+ v8::Local<v8::Context> context);
+
+ // Check if the active execution context is from the same origin
+ // as the target frame.
+ static bool IsFromSameOrigin(Frame* target, bool report_error);
+
+ // Check if it is safe to access the given node from the
+ // current security context.
+ static bool CheckNodeSecurity(Node* node);
+
+ // Return true if the current security context can access the target frame.
+ static bool CanAccess(Frame* target);
+
+ // Create a V8 wrapper for a C pointer
+ static v8::Handle<v8::Value> WrapCPointer(void* cptr);
+
+ static v8::Handle<v8::Value> CheckNewLegal(const v8::Arguments& args);
+
+ // Take C pointer out of a v8 wrapper
+ template <class C>
+ static C* ExtractCPointer(v8::Handle<v8::Value> obj) {
+ return static_cast<C*>(ExtractCPointerImpl(obj));
+ }
+
+
+ static v8::Handle<v8::Script> CompileScript(v8::Handle<v8::String> code,
+ const String& fileName,
+ int baseLine);
+
+ // Checks if a v8 value can be a DOM wrapper
+ static bool MaybeDOMWrapper(v8::Handle<v8::Value> obj);
+
+ // Sets contents of a DOM wrapper, returns false if
+ // obj is not a DOM wrapper type
+ static bool SetDOMWrapper(v8::Handle<v8::Object> obj, int type, void* ptr);
+
+ static v8::Handle<v8::Object> LookupDOMWrapper(
+ V8ClassIndex::V8WrapperType type, v8::Handle<v8::Value> value);
+
+ // A helper function extract native object pointer from a DOM wrapper
+ // and cast to the specified type.
+ template <class C>
+ static C* DOMWrapperToNative(v8::Handle<v8::Value> object) {
+ if (!MaybeDOMWrapper(object))
+ return 0;
+ return ExtractCPointer<C>(
+ v8::Handle<v8::Object>::Cast(object)->GetInternalField(0));
+ }
+
+ // A helper function extract native object pointer from a DOM wrapper
+ // and cast to the specified type.
+ template <class C>
+ static C* FastDOMWrapperToNative(v8::Handle<v8::Value> object) {
+ ASSERT(MaybeDOMWrapper(object));
+ return ExtractCPointer<C>(
+ v8::Handle<v8::Object>::Cast(object)->GetInternalField(0));
+ }
+
+ // A help function extract a node type pointer from a DOM wrapper.
+ // Wrapped pointer must be cast to Node* first.
+ template <class C>
+ static C* DOMWrapperToNode(v8::Handle<v8::Value> object) {
+ if (!MaybeDOMWrapper(object))
+ return 0;
+ v8::Handle<v8::Value> wrapper =
+ v8::Handle<v8::Object>::Cast(object)->GetInternalField(0);
+ return static_cast<C*>(ExtractCPointer<Node>(wrapper));
+ }
+
+ static v8::Handle<v8::Value> ToV8Object(V8ClassIndex::V8WrapperType type,
+ void* imp);
+
+ template <class C>
+ static C* FastToNativeObject(V8ClassIndex::V8WrapperType type,
+ v8::Handle<v8::Value> object) {
+ return static_cast<C*>(FastToNativeObjectImpl(type, object));
+ }
+
+ template <class C>
+ static C* ToNativeObject(V8ClassIndex::V8WrapperType type,
+ v8::Handle<v8::Value> object) {
+ return static_cast<C*>(ToNativeObjectImpl(type, object));
+ }
+
+ static V8ClassIndex::V8WrapperType GetDOMWrapperType(
+ v8::Handle<v8::Object> object);
+
+ // If the exception code is different from zero, a DOM exception is
+ // schedule to be thrown.
+ static void SetDOMException(int exception_code);
+
+ // Schedule an error object to be thrown.
+ static v8::Handle<v8::Value> ThrowError(ErrorType type, const char* message);
+
+ // Create an instance of a function descriptor and set to the global object
+ // as a named property. Used by v8_test_shell.
+ static void V8Proxy::BindJSObjectToWindow(Frame* frame,
+ const char* name,
+ int type,
+ v8::Handle<v8::FunctionTemplate> desc,
+ void* imp);
+
+ static v8::Handle<v8::Value> EventToV8Object(Event* event);
+ static Event* ToNativeEvent(v8::Handle<v8::Value> jsevent) {
+ return DOMWrapperToNative<Event>(jsevent);
+ }
+
+ static v8::Handle<v8::Value> EventTargetToV8Object(EventTarget* target);
+ // Wrap and unwrap JS event listeners
+ static v8::Handle<v8::Value> EventListenerToV8Object(EventListener* target);
+
+ // DOMImplementation is a singleton and it is handled in a special
+ // way. A wrapper is generated per document and stored in an
+ // internal field of the document. When wrapping the
+ // DOMImplementation object, the peer field is not set.
+ static v8::Handle<v8::Value> DOMImplementationToV8Object(
+ DOMImplementation* impl);
+
+ // Wrap JS node filter in C++
+ static NodeFilter* ToNativeNodeFilter(v8::Handle<v8::Value> filter);
+
+ static v8::Persistent<v8::FunctionTemplate> GetTemplate(
+ V8ClassIndex::V8WrapperType type);
+
+ template <int tag, typename T>
+ static v8::Handle<v8::Value> ConstructDOMObject(const v8::Arguments& args);
+
+ // Set JS wrapper of a DOM object
+ static void SetJSWrapperForDOMObject(Peerable* obj,
+ v8::Persistent<v8::Object> wrapper);
+ static void SetJSWrapperForDOMNode(Node* node,
+ v8::Persistent<v8::Object> wrapper);
+
+ // Domain of a frame is changed, invalidate its security token.
+ static void DomainChanged(Frame* frame);
+
+ // Process any pending JavaScript console messages.
+ static void ProcessConsoleMessages();
+
+#ifndef NDEBUG
+ // For debugging and leak detection purpose
+ static void RegisterGlobalHandle(GlobalHandleType type,
+ void* host,
+ v8::Persistent<v8::Value> handle);
+ static void UnregisterGlobalHandle(void* host,
+ v8::Persistent<v8::Value> handle);
+#endif
+
+ private:
+ void initContextIfNeeded();
+ void DisconnectEventListeners();
+
+ static void* ToNativeObjectImpl(V8ClassIndex::V8WrapperType type,
+ v8::Handle<v8::Value> object);
+ static void* FastToNativeObjectImpl(V8ClassIndex::V8WrapperType type,
+ v8::Handle<v8::Value> object);
+
+ // Take C pointer out of a v8 wrapper
+ static void* ExtractCPointerImpl(v8::Handle<v8::Value> obj);
+
+ static v8::Handle<v8::Object> NodeToV8Object(Node* node);
+ static v8::Handle<v8::Object> StyleSheetToV8Object(StyleSheet* sheet);
+ static v8::Handle<v8::Object> CSSValueToV8Object(CSSValue* value);
+ static v8::Handle<v8::Object> CSSRuleToV8Object(CSSRule* rule);
+ // Returns the JS wrapper of a window object, initializes the environment
+ // of the window frame if needed.
+ static v8::Handle<v8::Object> V8Proxy::WindowToV8Object(DOMWindow* window);
+
+#if ENABLE(SVG)
+ static v8::Handle<v8::Object> SVGElementInstanceToV8Object(
+ SVGElementInstance* instance);
+ static v8::Handle<v8::Object> SVGObjectWithContextToV8Object(
+ Peerable* object, V8ClassIndex::V8WrapperType type);
+#endif
+
+ static V8ClassIndex::V8WrapperType GetHTMLElementType(HTMLElement* elm);
+
+ static v8::Local<v8::Object> InstantiateV8Object(
+ V8ClassIndex::V8WrapperType type, void* impl);
+
+ static const char* GetRangeExceptionName(int exception_code);
+ static const char* GetEventExceptionName(int exception_code);
+ static const char* GetXMLHttpRequestExceptionName(int exception_code);
+ static const char* GetDOMExceptionName(int exception_code);
+
+#if ENABLE(XPATH)
+ static const char* GetXPathExceptionName(int exception_code);
+#endif
+
+#if ENABLE(SVG)
+ static V8ClassIndex::V8WrapperType GetSVGElementType(SVGElement* elm);
+ static const char* GetSVGExceptionName(int exception_code);
+#endif
+
+ // Update m_document field, dispose old one and create a string reference
+ // to the new one.
+ void UpdateDocumentHandle(v8::Local<v8::Object> handle);
+
+ // Returns a local handle of the context.
+ v8::Local<v8::Context> GetContext() {
+ return v8::Local<v8::Context>::New(m_context);
+ }
+
+ Frame* m_frame;
+ v8::Persistent<v8::Context> m_context;
+ v8::Persistent<v8::Object> m_global;
+
+ // Special handling of document wrapper;
+ v8::Persistent<v8::Object> m_document;
+
+ int m_handlerLineno;
+
+ // A list of event listeners created for this frame,
+ // the list gets cleared when removing all timeouts.
+ V8EventListenerList m_event_listeners;
+
+ // A list of event listeners create for XMLHttpRequest object for this frame,
+ // the list gets cleared when removing all timeouts.
+ V8EventListenerList m_xhr_listeners;
+
+ // True for <a href="javascript:foo()"> and false for <script>foo()</script>.
+ // Only valid during execution.
+ bool m_inlineCode;
+
+ // True when executing from within a timer callback. Only valid during
+ // execution.
+ bool m_timerCallback;
+
+ // Track the recursion depth to be able to avoid too deep recursion. The V8
+ // engine allows much more recursion than KJS does so we need to guard against
+ // excessive recursion in the binding layer.
+ int m_recursion;
+};
+
+
+// Add indexed getter to the function template for a collection.
+template <class T>
+static void SetCollectionIndexedGetter(v8::Handle<v8::FunctionTemplate> desc,
+ V8ClassIndex::V8WrapperType type) {
+ desc->InstanceTemplate()->SetIndexedPropertyHandler(
+ CollectionIndexedPropertyGetter<T>,
+ 0,
+ 0,
+ 0,
+ CollectionIndexedPropertyEnumerator<T>,
+ v8::External::New(reinterpret_cast<void*>(type)));
+}
+
+template <int tag, typename T>
+v8::Handle<v8::Value> V8Proxy::ConstructDOMObject(const v8::Arguments& args) {
+ if (!args.IsConstructCall()) {
+ V8Proxy::ThrowError(V8Proxy::TYPE_ERROR,
+ "DOM object constructor cannot be called as a function.");
+ return v8::Undefined();
+ }
+ T* obj = new T();
+ V8Proxy::SetDOMWrapper(args.Holder(), tag, obj);
+ V8Proxy::SetJSWrapperForDOMObject(
+ obj, v8::Persistent<v8::Object>::New(args.Holder()));
+ return args.Holder();
+}
+
+// Add named getter to the function template for a collection.
+template <class T>
+static void SetCollectionNamedGetter(v8::Handle<v8::FunctionTemplate> desc,
+ V8ClassIndex::V8WrapperType type) {
+ desc->InstanceTemplate()->SetNamedPropertyHandler(
+ CollectionNamedPropertyGetter<T>,
+ 0,
+ 0,
+ 0,
+ 0,
+ v8::External::New(reinterpret_cast<void*>(type)));
+}
+
+
+// Add named and indexed getters to the function template for a collection.
+template <class T>
+static void SetCollectionIndexedAndNamedGetters(
+ v8::Handle<v8::FunctionTemplate> desc, V8ClassIndex::V8WrapperType type) {
+ // If we interceptor before object, accessing 'length' can trigger
+ // a webkit assertion error.
+ // (see fast/dom/HTMLDocument/document-special-properties.html
+ desc->InstanceTemplate()->SetNamedPropertyHandler(
+ CollectionNamedPropertyGetter<T>,
+ 0,
+ 0,
+ 0,
+ 0,
+ v8::External::New(reinterpret_cast<void*>(type)));
+ desc->InstanceTemplate()->SetIndexedPropertyHandler(
+ CollectionIndexedPropertyGetter<T>,
+ 0,
+ 0,
+ 0,
+ CollectionIndexedPropertyEnumerator<T>,
+ v8::External::New(reinterpret_cast<void*>(type)));
+}
+
+
+// Add indexed getter returning a string or null to a function template
+// for a collection.
+template <class T>
+static void SetCollectionStringOrNullIndexedGetter(
+ v8::Handle<v8::FunctionTemplate> desc) {
+ desc->InstanceTemplate()->SetIndexedPropertyHandler(
+ CollectionStringOrNullIndexedPropertyGetter<T>,
+ 0,
+ 0,
+ 0,
+ CollectionIndexedPropertyEnumerator<T>);
+}
+
+
+} // namespace WebCore
+
+#endif // V8_PROXY_H__
diff --git a/webkit/port/bindings/v8/v8_utility.h b/webkit/port/bindings/v8/v8_utility.h
new file mode 100644
index 0000000..91322b5
--- /dev/null
+++ b/webkit/port/bindings/v8/v8_utility.h
@@ -0,0 +1,82 @@
+// Copyright 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.
+
+#ifndef V8_UTILITY_H__
+#define V8_UTILITY_H__
+
+namespace WebCore {
+
+class AllowAllocation {
+ public:
+ inline AllowAllocation() {
+ m_prev = m_current;
+ m_current = true;
+ }
+ inline ~AllowAllocation() {
+ m_current = m_prev;
+ }
+ static bool m_current;
+ private:
+ bool m_prev;
+};
+
+class SafeAllocation {
+ public:
+ static inline v8::Local<v8::Object> NewInstance(
+ v8::Handle<v8::Function> fun);
+ static inline v8::Local<v8::Object> NewInstance(
+ v8::Handle<v8::ObjectTemplate> templ);
+ static inline v8::Local<v8::Object> NewInstance(
+ v8::Handle<v8::Function> fun, int argc, v8::Handle<v8::Value> argv[]);
+};
+
+v8::Local<v8::Object> SafeAllocation::NewInstance(
+ v8::Handle<v8::Function> fun) {
+ if (fun.IsEmpty()) return v8::Local<v8::Object>();
+ AllowAllocation allow;
+ return fun->NewInstance();
+}
+
+v8::Local<v8::Object> SafeAllocation::NewInstance(
+ v8::Handle<v8::ObjectTemplate> templ) {
+ if (templ.IsEmpty()) return v8::Local<v8::Object>();
+ AllowAllocation allow;
+ return templ->NewInstance();
+}
+
+v8::Local<v8::Object> SafeAllocation::NewInstance(
+ v8::Handle<v8::Function> fun, int argc, v8::Handle<v8::Value> argv[]) {
+ if (fun.IsEmpty()) return v8::Local<v8::Object>();
+ AllowAllocation allow;
+ return fun->NewInstance(argc, argv);
+}
+
+} // namespace WebCore
+
+#endif // V8_UTILITY_H__
diff --git a/webkit/port/bindings/v8/v8_vectornodelist.cpp b/webkit/port/bindings/v8/v8_vectornodelist.cpp
new file mode 100644
index 0000000..7e19cf8
--- /dev/null
+++ b/webkit/port/bindings/v8/v8_vectornodelist.cpp
@@ -0,0 +1,57 @@
+// 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_vectornodelist.h"
+#include "NamedAttrMap.h" // Node::attributes
+
+namespace WebCore {
+
+unsigned V8VectorNodeList::length() const {
+ return m_nodes.size();
+}
+
+Node* V8VectorNodeList::item(unsigned index) const {
+ if (index < m_nodes.size())
+ return m_nodes[index].get();
+ return 0;
+}
+
+Node* V8VectorNodeList::itemWithName(const AtomicString& id) const {
+ for (unsigned i = 0; i < m_nodes.size(); i++) {
+ Node* node = m_nodes[i].get();
+ if (node->hasAttributes() && node->attributes()->id() == id) {
+ return node;
+ }
+ }
+ return 0;
+}
+
+} // namespace WebCore
diff --git a/webkit/port/bindings/v8/v8_vectornodelist.h b/webkit/port/bindings/v8/v8_vectornodelist.h
new file mode 100644
index 0000000..e4cd61c
--- /dev/null
+++ b/webkit/port/bindings/v8/v8_vectornodelist.h
@@ -0,0 +1,58 @@
+// Copyright 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.
+
+#ifndef V8_VECTORNODELIST_H__
+#define V8_VECTORNODELIST_H__
+
+#include "config.h"
+#include <v8.h>
+#include "Node.h"
+#include "NodeList.h"
+#include <wtf/RefPtr.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+// A NodeList backed by a Vector of Nodes.
+class V8VectorNodeList : public NodeList {
+ public:
+ explicit V8VectorNodeList(const Vector<RefPtr<Node> >& nodes)
+ : m_nodes(nodes) { }
+ virtual unsigned length() const;
+ virtual Node* item(unsigned index) const;
+ virtual Node* itemWithName(const AtomicString& name) const;
+
+ private:
+ Vector<RefPtr<Node> > m_nodes;
+};
+
+
+} // namespace WebCore
+
+#endif // V8_VECTORNODELIST_H__