summaryrefslogtreecommitdiffstats
path: root/webkit
diff options
context:
space:
mode:
authorjaphet@chromium.org <japhet@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-29 16:26:01 +0000
committerjaphet@chromium.org <japhet@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-29 16:26:01 +0000
commitf58705418e184e0c42ebb5a264ff25785950cc0a (patch)
tree70a48dd90aeca08579b846e40f2fd4ad02debf92 /webkit
parent25d238062198d6e683cf33ca1033dd4bf7e9c5e3 (diff)
downloadchromium_src-f58705418e184e0c42ebb5a264ff25785950cc0a.zip
chromium_src-f58705418e184e0c42ebb5a264ff25785950cc0a.tar.gz
chromium_src-f58705418e184e0c42ebb5a264ff25785950cc0a.tar.bz2
Reverting 19489,19488.
Review URL: http://codereview.chromium.org/150024 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@19490 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit')
-rw-r--r--webkit/api/src/WebKit.cpp4
-rw-r--r--webkit/glue/chrome_client_impl.cc4
-rw-r--r--webkit/glue/devtools/bound_object.cc6
-rw-r--r--webkit/glue/devtools/debugger_agent_impl.cc19
-rw-r--r--webkit/glue/devtools/debugger_agent_manager.cc6
-rw-r--r--webkit/glue/npruntime_util.cc8
-rw-r--r--webkit/glue/webdevtoolsagent_impl.cc6
-rw-r--r--webkit/glue/webdevtoolsclient_impl.cc14
-rw-r--r--webkit/glue/webframe_impl.cc2
-rw-r--r--webkit/port/bindings/scripts/CodeGeneratorV8.pm94
-rw-r--r--webkit/port/bindings/v8/NPV8Object.cpp16
-rw-r--r--webkit/port/bindings/v8/V8NPObject.cpp22
-rw-r--r--webkit/port/bindings/v8/V8NPUtils.cpp2
-rw-r--r--webkit/port/bindings/v8/V8SVGPODTypeWrapper.h4
-rw-r--r--webkit/port/bindings/v8/v8_proxy.cpp3569
-rw-r--r--webkit/port/bindings/v8/v8_proxy.h673
-rw-r--r--webkit/port/bindings/v8/v8_utility.h68
-rw-r--r--webkit/tools/test_shell/test_shell.cc4
-rw-r--r--webkit/webkit.gyp4
19 files changed, 4419 insertions, 106 deletions
diff --git a/webkit/api/src/WebKit.cpp b/webkit/api/src/WebKit.cpp
index b903aec..8ecc859 100644
--- a/webkit/api/src/WebKit.cpp
+++ b/webkit/api/src/WebKit.cpp
@@ -97,13 +97,13 @@ void registerURLSchemeAsNoAccess(const WebString& scheme)
void registerExtension(v8::Extension* extension)
{
- WebCore::V8Proxy::registerExtension(extension, WebString());
+ WebCore::V8Proxy::RegisterExtension(extension, WebString());
}
void registerExtension(v8::Extension* extension,
const WebString& schemeRestriction)
{
- WebCore::V8Proxy::registerExtension(extension, schemeRestriction);
+ WebCore::V8Proxy::RegisterExtension(extension, schemeRestriction);
}
void enableWebWorkers()
diff --git a/webkit/glue/chrome_client_impl.cc b/webkit/glue/chrome_client_impl.cc
index 6341f55..ff8aeb5 100644
--- a/webkit/glue/chrome_client_impl.cc
+++ b/webkit/glue/chrome_client_impl.cc
@@ -25,7 +25,7 @@ MSVC_PUSH_WARNING_LEVEL(0);
#include "ScriptController.h"
#include "WindowFeatures.h"
#if USE(V8)
-#include "V8Proxy.h"
+#include "v8_proxy.h"
#endif
MSVC_POP_WARNING();
@@ -361,7 +361,7 @@ void ChromeClientImpl::runJavaScriptAlert(WebCore::Frame* frame,
#if USE(V8)
// Before showing the JavaScript dialog, we give the proxy implementation
// a chance to process any pending console messages.
- WebCore::V8Proxy::processConsoleMessages();
+ WebCore::V8Proxy::ProcessConsoleMessages();
#endif
std::wstring wstr = webkit_glue::StringToStdWString(message);
diff --git a/webkit/glue/devtools/bound_object.cc b/webkit/glue/devtools/bound_object.cc
index bc8310c..c9993c4 100644
--- a/webkit/glue/devtools/bound_object.cc
+++ b/webkit/glue/devtools/bound_object.cc
@@ -6,7 +6,7 @@
#include <string>
-#include "V8Proxy.h"
+#include "v8_proxy.h"
#include "webkit/glue/devtools/bound_object.h"
using namespace WebCore;
@@ -22,7 +22,7 @@ BoundObject::BoundObject(
v8_this_ = v8::Persistent<v8::External>::New(v8::External::New(v8_this));
v8::Local<v8::FunctionTemplate> local_template =
- v8::FunctionTemplate::New(V8Proxy::checkNewLegal);
+ v8::FunctionTemplate::New(V8Proxy::CheckNewLegal);
host_template_ = v8::Persistent<v8::FunctionTemplate>::New(local_template);
host_template_->SetClassName(v8::String::New(object_name));
}
@@ -54,7 +54,7 @@ void BoundObject::Build() {
v8::Local<v8::Function> constructor = host_template_->GetFunction();
bound_object_ = v8::Persistent<v8::Object>::New(
- SafeAllocation::newInstance(constructor));
+ SafeAllocation::NewInstance(constructor));
v8::Handle<v8::Object> global = context_->Global();
global->Set(v8::String::New(object_name_), bound_object_);
diff --git a/webkit/glue/devtools/debugger_agent_impl.cc b/webkit/glue/devtools/debugger_agent_impl.cc
index dfbe7bc..4312cbe 100644
--- a/webkit/glue/devtools/debugger_agent_impl.cc
+++ b/webkit/glue/devtools/debugger_agent_impl.cc
@@ -10,14 +10,15 @@
#include "Document.h"
#include "Page.h"
-#include "V8Binding.h"
-#include "V8DOMWindow.h"
-#include "V8Index.h"
-#include "V8Proxy.h"
#undef LOG
#include "base/string_piece.h"
#include "grit/webkit_resources.h"
+#include "V8Binding.h"
+#include "V8DOMWindow.h"
+#include "V8Index.h"
+#include "v8_binding.h"
+#include "v8_proxy.h"
#include "webkit/glue/devtools/debugger_agent_impl.h"
#include "webkit/glue/devtools/debugger_agent_manager.h"
#include "webkit/glue/glue_util.h"
@@ -61,8 +62,8 @@ void DebuggerAgentImpl::GetContextId() {
void DebuggerAgentImpl::StartProfiling() {
v8::HandleScope scope;
WebCore::V8Proxy* proxy = V8Proxy::retrieve(GetPage()->mainFrame());
- DCHECK(proxy && proxy->isContextInitialized());
- v8::Context::Scope context_scope(proxy->context());
+ DCHECK(proxy && proxy->ContextInitialized());
+ v8::Context::Scope context_scope(proxy->GetContext());
v8::V8::ResumeProfiler();
}
@@ -104,12 +105,12 @@ void DebuggerAgentImpl::ResetUtilityContext(
// TODO(pfeldman): Validate against Soeren.
// Set up the DOM window as the prototype of the new global object.
v8::Handle<v8::Context> window_context =
- V8Proxy::context(document->frame());
+ V8Proxy::GetContext(document->frame());
v8::Handle<v8::Object> window_global = window_context->Global();
v8::Handle<v8::Value> window_wrapper =
- V8Proxy::lookupDOMWrapper(V8ClassIndex::DOMWINDOW, window_global);
+ V8Proxy::LookupDOMWrapper(V8ClassIndex::DOMWINDOW, window_global);
- ASSERT(V8Proxy::convertDOMWrapperToNative<DOMWindow>(window_wrapper) ==
+ ASSERT(V8Proxy::DOMWrapperToNative<DOMWindow>(window_wrapper) ==
document->frame()->domWindow());
// Create a new environment using an empty template for the shadow
diff --git a/webkit/glue/devtools/debugger_agent_manager.cc b/webkit/glue/devtools/debugger_agent_manager.cc
index d2f41d3..102224f 100644
--- a/webkit/glue/devtools/debugger_agent_manager.cc
+++ b/webkit/glue/devtools/debugger_agent_manager.cc
@@ -6,7 +6,7 @@
#include "Frame.h"
#include "PageGroupLoadDeferrer.h"
-#include "V8Proxy.h"
+#include "v8_proxy.h"
#include <wtf/HashSet.h>
#undef LOG
@@ -188,7 +188,7 @@ void DebuggerAgentManager::OnV8DebugMessage(const v8::Debug::Message& message) {
// If the context is from one of the inpected tabs or injected extension
// scripts it must have host_id in the data field.
- int host_id = WebCore::V8Proxy::contextDebugId(context);
+ int host_id = WebCore::V8Proxy::GetContextDebugId(context);
if (host_id != -1) {
DebuggerAgentImpl* agent = DebuggerAgentForHostId(host_id);
if (agent) {
@@ -222,7 +222,7 @@ void DebuggerAgentManager::SetHostId(WebFrameImpl* webframe, int host_id) {
DCHECK(host_id > 0);
WebCore::V8Proxy* proxy = WebCore::V8Proxy::retrieve(webframe->frame());
if (proxy) {
- proxy->setContextDebugId(host_id);
+ proxy->SetContextDebugId(host_id);
}
}
diff --git a/webkit/glue/npruntime_util.cc b/webkit/glue/npruntime_util.cc
index 687afb1..f1c23eb 100644
--- a/webkit/glue/npruntime_util.cc
+++ b/webkit/glue/npruntime_util.cc
@@ -13,7 +13,7 @@
#include "MouseEvent.h"
#include "NPV8Object.h" // for PrivateIdentifier
#include "V8Helpers.h"
-#include "V8Proxy.h"
+#include "v8_proxy.h"
#elif USE(JAVASCRIPTCORE_BINDINGS)
#include "bridge/c/c_utility.h"
#endif
@@ -102,20 +102,20 @@ static bool DragEventData(NPObject* npobj, int* event_id, WebDragData* data) {
// Get the current WebCore event.
v8::Handle<v8::Value> current_event(GetEvent(context));
- WebCore::Event* event = V8Proxy::convertToNativeEvent(current_event);
+ WebCore::Event* event = V8Proxy::ToNativeEvent(current_event);
if (event == NULL)
return false;
// Check that the given npobj is that event.
V8NPObject* object = reinterpret_cast<V8NPObject*>(npobj);
- WebCore::Event* given = V8Proxy::convertToNativeEvent(object->v8Object);
+ WebCore::Event* given = V8Proxy::ToNativeEvent(object->v8Object);
if (given != event)
return false;
// Check the execution frames are same origin.
V8Proxy* current = V8Proxy::retrieve(V8Proxy::retrieveFrame());
WebCore::Frame* frame = V8Proxy::retrieveFrame(context);
- if (!current || !current->canAccessFrame(frame, false))
+ if (!current || !current->CanAccessFrame(frame, false))
return false;
const WebCore::EventNames& event_names(WebCore::eventNames());
diff --git a/webkit/glue/webdevtoolsagent_impl.cc b/webkit/glue/webdevtoolsagent_impl.cc
index 7f62701..ac50d37 100644
--- a/webkit/glue/webdevtoolsagent_impl.cc
+++ b/webkit/glue/webdevtoolsagent_impl.cc
@@ -17,11 +17,11 @@
#include "ScriptObject.h"
#include "ScriptState.h"
#include "ScriptValue.h"
-#include "V8Binding.h"
-#include "V8Proxy.h"
+#include "v8_proxy.h"
#include <wtf/OwnPtr.h>
#undef LOG
+#include "V8Binding.h"
#include "base/values.h"
#include "webkit/api/public/WebDataSource.h"
#include "webkit/api/public/WebURL.h"
@@ -317,7 +317,7 @@ v8::Handle<v8::Value> WebDevToolsAgentImpl::JsGetNodeForId(
WebDevToolsAgentImpl* agent = static_cast<WebDevToolsAgentImpl*>(
v8::External::Cast(*args.Data())->Value());
Node* node = agent->dom_agent_impl_->GetNodeForId(node_id);
- return V8Proxy::convertToV8Object(V8ClassIndex::NODE, node);
+ return V8Proxy::ToV8Object(V8ClassIndex::NODE, node);
}
// static
diff --git a/webkit/glue/webdevtoolsclient_impl.cc b/webkit/glue/webdevtoolsclient_impl.cc
index 16d19c5..085a0b8 100644
--- a/webkit/glue/webdevtoolsclient_impl.cc
+++ b/webkit/glue/webdevtoolsclient_impl.cc
@@ -14,14 +14,14 @@
#include "Page.h"
#include "PlatformString.h"
#include "SecurityOrigin.h"
-#include "V8Binding.h"
-#include "V8CustomBinding.h"
-#include "V8Proxy.h"
-#include "V8Utilities.h"
#include <wtf/OwnPtr.h>
#include <wtf/Vector.h>
#undef LOG
+#include "V8Binding.h"
+#include "V8CustomBinding.h"
+#include "v8_proxy.h"
+#include "v8_utility.h"
#include "base/string_util.h"
#include "base/values.h"
#include "webkit/api/public/WebScriptSource.h"
@@ -149,7 +149,7 @@ WebDevToolsClientImpl::WebDevToolsClientImpl(
new JsToolsAgentBoundObj(this, frame, L"RemoteToolsAgent"));
v8::HandleScope scope;
- v8::Handle<v8::Context> frame_context = V8Proxy::context(frame->frame());
+ v8::Handle<v8::Context> frame_context = V8Proxy::GetContext(frame->frame());
dev_tools_host_.set(new BoundObject(frame_context, this, "DevToolsHost"));
dev_tools_host_->AddProtoFunction(
"reset",
@@ -253,7 +253,7 @@ v8::Handle<v8::Value> WebDevToolsClientImpl::JsAddSourceToFrame(
if (source_string.isEmpty() || exception_catcher.HasCaught()) {
return v8::Undefined();
}
- Node* node = V8Proxy::convertDOMWrapperToNode<Node>(args[2]);
+ Node* node = V8Proxy::DOMWrapperToNode<Node>(args[2]);
if (!node || !node->attached()) {
return v8::Undefined();
}
@@ -272,7 +272,7 @@ v8::Handle<v8::Value> WebDevToolsClientImpl::JsAddResourceSourceToFrame(
if (mime_type.isEmpty()) {
return v8::Undefined();
}
- Node* node = V8Proxy::convertDOMWrapperToNode<Node>(args[2]);
+ Node* node = V8Proxy::DOMWrapperToNode<Node>(args[2]);
WebDevToolsClientImpl* client = static_cast<WebDevToolsClientImpl*>(
v8::External::Cast(*args.Data())->Value());
client->AddResourceSourceToFrame(resource_id, mime_type, node);
diff --git a/webkit/glue/webframe_impl.cc b/webkit/glue/webframe_impl.cc
index 8c13cb3..a02e73a 100644
--- a/webkit/glue/webframe_impl.cc
+++ b/webkit/glue/webframe_impl.cc
@@ -826,7 +826,7 @@ v8::Local<v8::Context> WebFrameImpl::GetScriptContext() {
if (!frame_)
return v8::Local<v8::Context>();
- return frame_->script()->proxy()->context();
+ return frame_->script()->proxy()->GetContext();
}
#endif
diff --git a/webkit/port/bindings/scripts/CodeGeneratorV8.pm b/webkit/port/bindings/scripts/CodeGeneratorV8.pm
index 24f5f4b..69eb445 100644
--- a/webkit/port/bindings/scripts/CodeGeneratorV8.pm
+++ b/webkit/port/bindings/scripts/CodeGeneratorV8.pm
@@ -315,7 +315,7 @@ sub GenerateSetDOMException
my $result = "";
$result .= $indent . "if (ec) {\n";
- $result .= $indent . " V8Proxy::setDOMException(ec);\n";
+ $result .= $indent . " V8Proxy::SetDOMException(ec);\n";
$result .= $indent . " return v8::Handle<v8::Value>();\n";
$result .= $indent . "}\n";
@@ -341,12 +341,12 @@ sub HolderToNative
if (IsNodeSubType($dataNode)) {
push(@implContentDecls, <<END);
- $implClassName* imp = V8Proxy::convertDOMWrapperToNode<$implClassName>(holder);
+ $implClassName* imp = V8Proxy::DOMWrapperToNode<$implClassName>(holder);
END
} else {
push(@implContentDecls, <<END);
- $implClassName* imp = V8Proxy::convertToNativeObject<$implClassName>(V8ClassIndex::$classIndex, holder);
+ $implClassName* imp = V8Proxy::ToNativeObject<$implClassName>(V8ClassIndex::$classIndex, holder);
END
}
@@ -369,14 +369,14 @@ sub GenerateDomainSafeFunctionGetter
my $newTemplateString = GenerateNewFunctionTemplate($function, $dataNode, $signature);
- $implIncludes{"V8Proxy.h"} = 1;
+ $implIncludes{"v8_proxy.h"} = 1;
push(@implContentDecls, <<END);
static v8::Handle<v8::Value> ${funcName}AttrGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info) {
INC_STATS(\"DOM.$implClassName.$funcName._get\");
static v8::Persistent<v8::FunctionTemplate> private_template =
v8::Persistent<v8::FunctionTemplate>::New($newTemplateString);
- v8::Handle<v8::Object> holder = V8Proxy::lookupDOMWrapper(V8ClassIndex::$classIndex, info.This());
+ v8::Handle<v8::Object> holder = V8Proxy::LookupDOMWrapper(V8ClassIndex::$classIndex, info.This());
if (holder.IsEmpty()) {
// can only reach here by 'object.__proto__.func', and it should passed
// domain security check already
@@ -388,7 +388,7 @@ END
HolderToNative($dataNode, $implClassName, $classIndex);
push(@implContentDecls, <<END);
- if (!V8Proxy::canAccessFrame(imp->frame(), false)) {
+ if (!V8Proxy::CanAccessFrame(imp->frame(), false)) {
static v8::Persistent<v8::FunctionTemplate> shared_template =
v8::Persistent<v8::FunctionTemplate>::New($newTemplateString);
return shared_template->GetFunction();
@@ -416,13 +416,13 @@ END
if ($classIndex eq "DOMWINDOW") {
push(@implContentDecls, <<END);
- DOMWindow* window = V8Proxy::convertToNativeObject<DOMWindow>(V8ClassIndex::DOMWINDOW, info.Holder());
+ DOMWindow* window = V8Proxy::ToNativeObject<DOMWindow>(V8ClassIndex::DOMWINDOW, info.Holder());
Frame* frame = window->frame();
if (frame) {
// Get the proxy corresponding to the DOMWindow if possible to
// make sure that the constructor function is constructed in the
// context of the DOMWindow and not in the context of the caller.
- return V8Proxy::retrieve(frame)->getConstructor(type);
+ return V8Proxy::retrieve(frame)->GetConstructor(type);
}
END
}
@@ -453,7 +453,7 @@ sub GenerateNormalAttrGetter
my $attrExt = $attribute->signature->extendedAttributes;
my $attrName = $attribute->signature->name;
- $implIncludes{"V8Proxy.h"} = 1;
+ $implIncludes{"v8_proxy.h"} = 1;
my $attrType = $codeGenerator->StripModule($attribute->signature->type);
my $attrIsPodType = $codeGenerator->IsPodType($attrType);
@@ -494,7 +494,7 @@ END
if ($isPodType) {
push(@implContentDecls, <<END);
- V8SVGPODTypeWrapper<$implClassName>* imp_wrapper = V8Proxy::convertToNativeObject<V8SVGPODTypeWrapper<$implClassName> >(V8ClassIndex::$classIndex, info.Holder());
+ V8SVGPODTypeWrapper<$implClassName>* imp_wrapper = V8Proxy::ToNativeObject<V8SVGPODTypeWrapper<$implClassName> >(V8ClassIndex::$classIndex, info.Holder());
$implClassName imp_instance = *imp_wrapper;
END
if ($getterStringUsesImp) {
@@ -506,7 +506,7 @@ END
} elsif ($attrExt->{"v8OnProto"} || $attrExt->{"V8DisallowShadowing"}) {
# perform lookup first
push(@implContentDecls, <<END);
- v8::Handle<v8::Object> holder = V8Proxy::lookupDOMWrapper(V8ClassIndex::$classIndex, info.This());
+ v8::Handle<v8::Object> holder = V8Proxy::LookupDOMWrapper(V8ClassIndex::$classIndex, info.This());
if (holder.IsEmpty()) return v8::Undefined();
END
HolderToNative($dataNode, $implClassName, $classIndex);
@@ -519,9 +519,9 @@ END
# Generate security checks if necessary
if ($attribute->signature->extendedAttributes->{"CheckNodeSecurity"}) {
- push(@implContentDecls, " if (!V8Proxy::checkNodeSecurity(imp->$attrName())) return v8::Undefined();\n\n");
+ push(@implContentDecls, " if (!V8Proxy::CheckNodeSecurity(imp->$attrName())) return v8::Undefined();\n\n");
} elsif ($attribute->signature->extendedAttributes->{"CheckFrameSecurity"}) {
- push(@implContentDecls, " if (!V8Proxy::checkNodeSecurity(imp->contentDocument())) return v8::Undefined();\n\n");
+ push(@implContentDecls, " if (!V8Proxy::CheckNodeSecurity(imp->contentDocument())) return v8::Undefined();\n\n");
}
my $useExceptions = 1 if @{$attribute->getterExceptions} and !($isPodType);
@@ -618,7 +618,7 @@ END
if ($attrIsPodType) {
my $classIndex = uc($attrType);
- push(@implContentDecls, " return V8Proxy::convertToV8Object(V8ClassIndex::$classIndex, wrapper);\n");
+ push(@implContentDecls, " return V8Proxy::ToV8Object(V8ClassIndex::$classIndex, wrapper);\n");
} else {
push(@implContentDecls, " return " . NativeToJSValue($attribute->signature, $result). ";\n");
}
@@ -631,7 +631,7 @@ sub GenerateReplaceableAttrSetter
{
my $implClassName = shift;
- $implIncludes{"V8Proxy.h"} = 1;
+ $implIncludes{"v8_proxy.h"} = 1;
push(@implContentDecls,
" static void ${attrName}AttrSetter(v8::Local<v8::String> name," .
@@ -655,7 +655,7 @@ sub GenerateNormalAttrSetter
my $attrExt = $attribute->signature->extendedAttributes;
- $implIncludes{"V8Proxy.h"} = 1;
+ $implIncludes{"v8_proxy.h"} = 1;
push(@implContentDecls,
" static void ${attrName}AttrSetter(v8::Local<v8::String> name," .
@@ -668,14 +668,14 @@ sub GenerateNormalAttrSetter
if ($isPodType) {
$implClassName = GetNativeType($implClassName);
$implIncludes{"V8SVGPODTypeWrapper.h"} = 1;
- push(@implContentDecls, " V8SVGPODTypeWrapper<$implClassName>* wrapper = V8Proxy::convertToNativeObject<V8SVGPODTypeWrapper<$implClassName> >(V8ClassIndex::$classIndex, info.Holder());\n");
+ push(@implContentDecls, " V8SVGPODTypeWrapper<$implClassName>* wrapper = V8Proxy::ToNativeObject<V8SVGPODTypeWrapper<$implClassName> >(V8ClassIndex::$classIndex, info.Holder());\n");
push(@implContentDecls, " $implClassName imp_instance = *wrapper;\n");
push(@implContentDecls, " $implClassName* imp = &imp_instance;\n");
} elsif ($attrExt->{"v8OnProto"}) {
# perform lookup first
push(@implContentDecls, <<END);
- v8::Handle<v8::Object> holder = V8Proxy::lookupDOMWrapper(V8ClassIndex::$classIndex, info.This());
+ v8::Handle<v8::Object> holder = V8Proxy::LookupDOMWrapper(V8ClassIndex::$classIndex, info.This());
if (holder.IsEmpty()) return v8::Undefined();
END
HolderToNative($dataNode, $implClassName, $classIndex);
@@ -718,11 +718,11 @@ END
}
if ($useExceptions) {
- push(@implContentDecls, " V8Proxy::setDOMException(ec);\n");
+ push(@implContentDecls, " V8Proxy::SetDOMException(ec);\n");
}
if ($isPodType) {
- push(@implContentDecls, " wrapper->commitChange(*imp, V8Proxy::svgContext(wrapper));\n");
+ push(@implContentDecls, " wrapper->commitChange(*imp, V8Proxy::GetSVGContext(wrapper));\n");
} elsif (IsSVGTypeNeedingContextParameter($implClassName)) {
$implIncludes{"SVGElement.h"} = 1;
@@ -731,7 +731,7 @@ END
$currentObject = "wrapper";
}
- push(@implContentDecls, " if (SVGElement* context = V8Proxy::svgContext($currentObject)) {\n");
+ push(@implContentDecls, " if (SVGElement* context = V8Proxy::GetSVGContext($currentObject)) {\n");
push(@implContentDecls, " context->svgAttributeChanged(imp->associatedAttributeName());\n");
push(@implContentDecls, " }\n");
}
@@ -791,7 +791,7 @@ sub GenerateFunctionCallback
if ($codeGenerator->IsPodType($implClassName)) {
my $nativeClassName = GetNativeType($implClassName);
- push(@implContentDecls, " V8SVGPODTypeWrapper<$nativeClassName>* imp_wrapper = V8Proxy::convertToNativeObject<V8SVGPODTypeWrapper<$nativeClassName> >(V8ClassIndex::$classIndex, args.Holder());\n");
+ push(@implContentDecls, " V8SVGPODTypeWrapper<$nativeClassName>* imp_wrapper = V8Proxy::ToNativeObject<V8SVGPODTypeWrapper<$nativeClassName> >(V8ClassIndex::$classIndex, args.Holder());\n");
push(@implContentDecls, " $nativeClassName imp_instance = *imp_wrapper;\n");
push(@implContentDecls, " $nativeClassName* imp = &imp_instance;\n");
} else {
@@ -807,7 +807,7 @@ END
&& !$function->signature->extendedAttributes->{"DoNotCheckDomainSecurity"}) {
# We have not find real use cases yet.
push(@implContentDecls,
-" if (!V8Proxy::canAccessFrame(imp->frame(), true)) {\n".
+" if (!V8Proxy::CanAccessFrame(imp->frame(), true)) {\n".
" return v8::Undefined();\n" .
" }\n");
}
@@ -849,7 +849,7 @@ END
$implIncludes{"ExceptionCode.h"} = 1;
push(@implContentDecls,
" if (!$parameterName" . (BasicTypeCanFailConversion($parameter) ? "Ok" : "") . ") {\n" .
-" V8Proxy::setDOMException(TYPE_MISMATCH_ERR);\n" .
+" V8Proxy::SetDOMException(TYPE_MISMATCH_ERR);\n" .
" return v8::Handle<v8::Value>();\n" .
" }\n");
}
@@ -858,7 +858,7 @@ END
$implIncludes{"ExceptionCode.h"} = 1;
push(@implContentDecls,
" if ($parameterName < 0) {\n" .
-" V8Proxy::setDOMException(INDEX_SIZE_ERR);\n" .
+" V8Proxy::SetDOMException(INDEX_SIZE_ERR);\n" .
" return v8::Handle<v8::Value>();\n" .
" }\n");
}
@@ -1050,7 +1050,7 @@ sub GenerateImplementation
push(@implFixedHeader,
"#include \"config.h\"\n" .
- "#include \"V8Proxy.h\"\n" .
+ "#include \"v8_proxy.h\"\n" .
"#include \"v8_binding.h\"\n\n" .
"#undef LOG\n\n");
@@ -1067,7 +1067,7 @@ sub GenerateImplementation
$implIncludes{"${className}.h"} = 1;
AddIncludesForType($interfaceName);
- $implIncludes{"V8Proxy.h"} = 1;
+ $implIncludes{"v8_proxy.h"} = 1;
push(@implContentDecls, "namespace WebCore {\n");
push(@implContentDecls, "namespace ${interfaceName}Internal {\n\n");
@@ -1217,7 +1217,7 @@ END
if ($implClassName eq "DOMWindow") {
push(@implContent, <<END);
static v8::Persistent<v8::ObjectTemplate> ConfigureShadowObjectTemplate(v8::Persistent<v8::ObjectTemplate> templ) {
- batchConfigureAttributes(templ,
+ BatchConfigureAttributes(templ,
v8::Handle<v8::ObjectTemplate>(),
shadow_attrs,
sizeof(shadow_attrs)/sizeof(*shadow_attrs));
@@ -1240,7 +1240,7 @@ END
# Set up our attributes if we have them
if ($has_attributes) {
push(@implContent, <<END);
- batchConfigureAttributes(instance, proto, attrs, sizeof(attrs)/sizeof(*attrs));
+ BatchConfigureAttributes(instance, proto, attrs, sizeof(attrs)/sizeof(*attrs));
END
}
@@ -1325,7 +1325,7 @@ END
if ($parent eq "EventTarget") { next; }
$implIncludes{"V8${parent}.h"} = 1;
my $parentClassIndex = uc($codeGenerator->StripModule($parent));
- push(@implContent, " desc->Inherit(V8Proxy::getTemplate(V8ClassIndex::${parentClassIndex}));\n");
+ push(@implContent, " desc->Inherit(V8Proxy::GetTemplate(V8ClassIndex::${parentClassIndex}));\n");
last;
}
@@ -1334,7 +1334,7 @@ END
if ($has_constants) {
push(@implContent, <<END);
- batchConfigureConstants(desc, proto, consts, sizeof(consts)/sizeof(*consts));
+ BatchConfigureConstants(desc, proto, consts, sizeof(consts)/sizeof(*consts));
END
}
@@ -1346,7 +1346,7 @@ v8::Persistent<v8::FunctionTemplate> ${className}::GetRawTemplate() {
static v8::Persistent<v8::FunctionTemplate> ${className}_raw_cache_;
if (${className}_raw_cache_.IsEmpty()) {
v8::HandleScope scope;
- v8::Local<v8::FunctionTemplate> result = v8::FunctionTemplate::New(V8Proxy::checkNewLegal);
+ v8::Local<v8::FunctionTemplate> result = v8::FunctionTemplate::New(V8Proxy::CheckNewLegal);
${className}_raw_cache_ = v8::Persistent<v8::FunctionTemplate>::New(result);
}
return ${className}_raw_cache_;
@@ -1489,7 +1489,7 @@ sub GenerateFunctionCallString()
}
$result .= $indent . "if (success)\n";
$result .= $indent . " " .
- "return V8Proxy::convertNodeToV8Object($nodeToReturn);\n";
+ "return V8Proxy::NodeToV8Object($nodeToReturn);\n";
$result .= $indent . "return v8::Null();\n";
return $result;
} elsif ($returnType eq "void") {
@@ -1554,7 +1554,7 @@ sub GenerateFunctionCallString()
if ($returnsPodType) {
my $classIndex = uc($returnType);
- $result .= $indent . "return V8Proxy::convertToV8Object(V8ClassIndex::$classIndex, wrapper);\n";
+ $result .= $indent . "return V8Proxy::ToV8Object(V8ClassIndex::$classIndex, wrapper);\n";
} else {
$result .= $indent . "return " . NativeToJSValue($function->signature, $return) . ";\n";
}
@@ -1818,7 +1818,7 @@ sub JSValueToNative
}
if ($type eq "NodeFilter") {
- return "V8Proxy::wrapNativeNodeFilter($value)";
+ return "V8Proxy::ToNativeNodeFilter($value)";
}
if ($type eq "SVGRect") {
@@ -1830,12 +1830,12 @@ sub JSValueToNative
}
# Default, assume autogenerated type conversion routines
- $implIncludes{"V8Proxy.h"} = 1;
+ $implIncludes{"v8_proxy.h"} = 1;
if ($type eq "EventTarget") {
$implIncludes{"V8Node.h"} = 1;
# EventTarget is not in DOM hierarchy, but all Nodes are EventTarget.
- return "V8Node::HasInstance($value) ? V8Proxy::convertDOMWrapperToNode<Node>($value) : 0";
+ return "V8Node::HasInstance($value) ? V8Proxy::DOMWrapperToNode<Node>($value) : 0";
}
AddIncludesForType($type);
@@ -1846,7 +1846,7 @@ sub JSValueToNative
# Perform type checks on the parameter, if it is expected Node type,
# return NULL.
- return "V8${type}::HasInstance($value) ? V8Proxy::convertDOMWrapperToNode<${type}>($value) : 0";
+ return "V8${type}::HasInstance($value) ? V8Proxy::DOMWrapperToNode<${type}>($value) : 0";
} else {
# TODO: Temporary to avoid Window name conflict.
@@ -1866,7 +1866,7 @@ sub JSValueToNative
# Perform type checks on the parameter, if it is expected Node type,
# return NULL.
- return "V8${type}::HasInstance($value) ? V8Proxy::convertToNativeObject<${implClassName}>(V8ClassIndex::${classIndex}, $value) : 0";
+ return "V8${type}::HasInstance($value) ? V8Proxy::ToNativeObject<${implClassName}>(V8ClassIndex::${classIndex}, $value) : 0";
}
}
@@ -2020,23 +2020,23 @@ sub NativeToJSValue
# special case for non-DOM node interfaces
if (IsDOMNodeType($type)) {
- return "V8Proxy::convertNodeToV8Object($value)";
+ return "V8Proxy::NodeToV8Object($value)";
}
if ($type eq "EventTarget" or $type eq "SVGElementInstance") {
- return "V8Proxy::convertEventTargetToV8Object($value)";
+ return "V8Proxy::EventTargetToV8Object($value)";
}
if ($type eq "Event") {
- return "V8Proxy::convertEventToV8Object($value)";
+ return "V8Proxy::EventToV8Object($value)";
}
if ($type eq "EventListener") {
- return "V8Proxy::convertEventListenerToV8Object($value)";
+ return "V8Proxy::EventListenerToV8Object($value)";
}
if ($type eq "RGBColor") {
- return "V8Proxy::convertToV8Object(V8ClassIndex::RGBCOLOR, new RGBColor($value))";
+ return "V8Proxy::ToV8Object(V8ClassIndex::RGBCOLOR, new RGBColor($value))";
}
if ($type eq "WorkerContext" or $type eq "WorkerLocation" or $type eq "WorkerNavigator") {
@@ -2055,7 +2055,7 @@ sub NativeToJSValue
$value = GenerateSVGStaticPodTypeWrapper($type, $value);
}
- return "V8Proxy::convertToV8Object(V8ClassIndex::$classIndex, $value)";
+ return "V8Proxy::ToV8Object(V8ClassIndex::$classIndex, $value)";
}
}
@@ -2127,7 +2127,7 @@ sub GenerateSVGContextAssignment
my $indent = shift;
$result = GenerateSVGContextRetrieval($srcType, $indent);
- $result .= $indent . "V8Proxy::setSVGContext($value, context);\n";
+ $result .= $indent . "V8Proxy::SetSVGContext($value, context);\n";
return $result;
}
@@ -2147,7 +2147,7 @@ sub GenerateSVGContextRetrieval
my $contextDecl;
if (IsSVGTypeNeedingContextParameter($srcType)) {
- $contextDecl = "V8Proxy::svgContext($srcObject)";
+ $contextDecl = "V8Proxy::GetSVGContext($srcObject)";
} else {
$contextDecl = $srcObject;
}
diff --git a/webkit/port/bindings/v8/NPV8Object.cpp b/webkit/port/bindings/v8/NPV8Object.cpp
index 5238ceb..24381c8 100644
--- a/webkit/port/bindings/v8/NPV8Object.cpp
+++ b/webkit/port/bindings/v8/NPV8Object.cpp
@@ -41,7 +41,7 @@
#include "V8CustomBinding.h"
#include "V8Helpers.h"
#include "V8NPUtils.h"
-#include "V8Proxy.h"
+#include "v8_proxy.h"
#include "DOMWindow.h"
using WebCore::toV8Context;
@@ -60,7 +60,7 @@ static void FreeV8NPObject(NPObject* npobj)
{
V8NPObject *object = reinterpret_cast<V8NPObject*>(npobj);
#ifndef NDEBUG
- V8Proxy::unregisterGlobalHandle(object, object->v8Object);
+ V8Proxy::UnregisterGlobalHandle(object, object->v8Object);
#endif
object->v8Object.Dispose();
free(object);
@@ -105,7 +105,7 @@ NPObject* npCreateV8ScriptObject(NPP npp, v8::Handle<v8::Object> object, WebCore
object->GetInternalField(V8Custom::kDOMWrapperTypeIndex)->IsNumber() &&
object->GetInternalField(V8Custom::kDOMWrapperTypeIndex)->Uint32Value() == V8ClassIndex::NPOBJECT) {
- NPObject* rv = V8Proxy::convertToNativeObject<NPObject>(V8ClassIndex::NPOBJECT, object);
+ NPObject* rv = V8Proxy::ToNativeObject<NPObject>(V8ClassIndex::NPOBJECT, object);
NPN_RetainObject(rv);
return rv;
}
@@ -113,7 +113,7 @@ NPObject* npCreateV8ScriptObject(NPP npp, v8::Handle<v8::Object> object, WebCore
V8NPObject* obj = reinterpret_cast<V8NPObject*>(NPN_CreateObject(npp, &V8NPObjectClass));
obj->v8Object = v8::Persistent<v8::Object>::New(object);
#ifndef NDEBUG
- V8Proxy::registerGlobalHandle(WebCore::NPOBJECT, obj, obj->v8Object);
+ V8Proxy::RegisterGlobalHandle(WebCore::NPOBJECT, obj, obj->v8Object);
#endif
obj->rootObject = root;
return reinterpret_cast<NPObject*>(obj);
@@ -167,7 +167,7 @@ bool NPN_Invoke(NPP npp, NPObject *npobj, NPIdentifier methodName,
v8::Handle<v8::Function> func = v8::Handle<v8::Function>::Cast(funcObj);
// 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->v8Object, argCount, argv);
+ v8::Local<v8::Value> resultObj = proxy->CallFunction(func, object->v8Object, argCount, argv);
delete[] argv;
// If we had an error, return false. The spec is a little unclear here, but
@@ -221,7 +221,7 @@ bool NPN_InvokeDefault(NPP npp, NPObject *npobj, const NPVariant *args,
// Create list of args to pass to v8
v8::Handle<v8::Value>* argv = listFromVariantArgs(args, argCount, npobj);
- resultObj = proxy->callFunction(func, funcObj, argCount, argv);
+ resultObj = proxy->CallFunction(func, funcObj, argCount, argv);
delete[] argv;
}
@@ -420,7 +420,7 @@ void NPN_SetException(NPObject *npobj, const NPUTF8 *message)
return;
v8::Context::Scope scope(context);
- V8Proxy::throwError(V8Proxy::GeneralError, message);
+ V8Proxy::ThrowError(V8Proxy::GENERAL_ERROR, message);
}
bool NPN_Enumerate(NPP npp, NPObject *npobj, NPIdentifier **identifier, uint32_t *count)
@@ -507,7 +507,7 @@ bool NPN_Construct(NPP npp, NPObject* npobj, const NPVariant* args, uint32_t arg
// Create list of args to pass to v8.
v8::Handle<v8::Value>* argv = listFromVariantArgs(args, argCount, npobj);
- resultObj = proxy->newInstance(ctor, argCount, argv);
+ resultObj = proxy->NewInstance(ctor, argCount, argv);
delete[] argv;
}
diff --git a/webkit/port/bindings/v8/V8NPObject.cpp b/webkit/port/bindings/v8/V8NPObject.cpp
index 09a56d8..35be7e0 100644
--- a/webkit/port/bindings/v8/V8NPObject.cpp
+++ b/webkit/port/bindings/v8/V8NPObject.cpp
@@ -63,25 +63,25 @@ static v8::Handle<v8::Value> npObjectInvokeImpl(const v8::Arguments& args, Invok
if (V8HTMLAppletElement::HasInstance(args.Holder()) || V8HTMLEmbedElement::HasInstance(args.Holder())
|| V8HTMLObjectElement::HasInstance(args.Holder())) {
// The holder object is a subtype of HTMLPlugInElement.
- HTMLPlugInElement* element = V8Proxy::convertDOMWrapperToNode<HTMLPlugInElement>(args.Holder());
+ HTMLPlugInElement* element = V8Proxy::DOMWrapperToNode<HTMLPlugInElement>(args.Holder());
ScriptInstance scriptInstance = element->getInstance();
if (scriptInstance)
- npObject = V8Proxy::convertToNativeObject<NPObject>(V8ClassIndex::NPOBJECT, scriptInstance->instance());
+ npObject = V8Proxy::ToNativeObject<NPObject>(V8ClassIndex::NPOBJECT, scriptInstance->instance());
else
npObject = 0;
} else {
// The holder object is not a subtype of HTMLPlugInElement, it
// must be an NPObject which has three internal fields.
if (args.Holder()->InternalFieldCount() != V8Custom::kNPObjectInternalFieldCount)
- return throwError("NPMethod called on non-NPObject", V8Proxy::ReferenceError);
+ return throwError("NPMethod called on non-NPObject", V8Proxy::REFERENCE_ERROR);
- npObject = V8Proxy::convertToNativeObject<NPObject>(V8ClassIndex::NPOBJECT, args.Holder());
+ 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))
- return throwError("NPObject deleted", V8Proxy::ReferenceError);
+ return throwError("NPObject deleted", V8Proxy::REFERENCE_ERROR);
// Wrap up parameters.
int numArgs = args.Length();
@@ -158,12 +158,12 @@ static v8::Handle<v8::Value> npObjectGetProperty(v8::Local<v8::Object> self,
NPIdentifier identifier,
v8::Local<v8::Value> key)
{
- NPObject* npObject = V8Proxy::convertToNativeObject<NPObject>(V8ClassIndex::NPOBJECT, self);
+ 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))
- return throwError("NPObject deleted", V8Proxy::ReferenceError);
+ return throwError("NPObject deleted", V8Proxy::REFERENCE_ERROR);
if (npObject->_class->hasProperty && npObject->_class->hasProperty(npObject, identifier)
@@ -231,12 +231,12 @@ static v8::Handle<v8::Value> npObjectSetProperty(v8::Local<v8::Object> self,
NPIdentifier identifier,
v8::Local<v8::Value> value)
{
- NPObject* npObject = V8Proxy::convertToNativeObject<NPObject>(V8ClassIndex::NPOBJECT, self);
+ 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)) {
- throwError("NPObject deleted", V8Proxy::ReferenceError);
+ throwError("NPObject deleted", V8Proxy::REFERENCE_ERROR);
return value; // Intercepted, but an exception was thrown.
}
@@ -339,7 +339,7 @@ v8::Local<v8::Object> createV8ObjectForNPObject(NPObject* object, NPObject* root
}
v8::Handle<v8::Function> v8Function = npObjectDesc->GetFunction();
- v8::Local<v8::Object> value = SafeAllocation::newInstance(v8Function);
+ v8::Local<v8::Object> value = SafeAllocation::NewInstance(v8Function);
// If we were unable to allocate the instance, we avoid wrapping
// and registering the NP object.
@@ -365,7 +365,7 @@ void forgetV8ObjectForNPObject(NPObject* object)
if (staticNPObjectMap.contains(object)) {
v8::HandleScope scope;
v8::Persistent<v8::Object> handle(staticNPObjectMap.get(object));
- WebCore::V8Proxy::setDOMWrapper(handle, WebCore::V8ClassIndex::NPOBJECT, 0);
+ WebCore::V8Proxy::SetDOMWrapper(handle, WebCore::V8ClassIndex::NPOBJECT, 0);
staticNPObjectMap.forget(object);
NPN_ReleaseObject(object);
}
diff --git a/webkit/port/bindings/v8/V8NPUtils.cpp b/webkit/port/bindings/v8/V8NPUtils.cpp
index fa0d76f..3a68288 100644
--- a/webkit/port/bindings/v8/V8NPUtils.cpp
+++ b/webkit/port/bindings/v8/V8NPUtils.cpp
@@ -39,7 +39,7 @@
#include "npruntime_priv.h"
#include "NPV8Object.h"
#include "V8NPObject.h"
-#include "V8Proxy.h"
+#include "v8_proxy.h"
void convertV8ObjectToNPVariant(v8::Local<v8::Value> object, NPObject *owner, NPVariant* result)
{
diff --git a/webkit/port/bindings/v8/V8SVGPODTypeWrapper.h b/webkit/port/bindings/v8/V8SVGPODTypeWrapper.h
index 4373b8e..0fb1fb8 100644
--- a/webkit/port/bindings/v8/V8SVGPODTypeWrapper.h
+++ b/webkit/port/bindings/v8/V8SVGPODTypeWrapper.h
@@ -36,7 +36,7 @@
#include <wtf/Assertions.h>
#include <wtf/RefCounted.h>
#include <wtf/HashMap.h>
-#include "V8Proxy.h"
+#include "v8_proxy.h"
namespace WebCore {
@@ -370,7 +370,7 @@ template <class P>
P V8SVGPODTypeUtil::ToSVGPODType(V8ClassIndex::V8WrapperType type,
v8::Handle<v8::Value> object,
bool& ok) {
- void *wrapper = V8Proxy::convertToSVGPODTypeImpl(type, object);
+ void *wrapper = V8Proxy::ToSVGPODTypeImpl(type, object);
if (wrapper == NULL) {
ok = false;
return P();
diff --git a/webkit/port/bindings/v8/v8_proxy.cpp b/webkit/port/bindings/v8/v8_proxy.cpp
new file mode 100644
index 0000000..e1f23ef
--- /dev/null
+++ b/webkit/port/bindings/v8/v8_proxy.cpp
@@ -0,0 +1,3569 @@
+// 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 <algorithm>
+#include <utility>
+
+#include <v8.h>
+#include <v8-debug.h>
+
+#include "v8_proxy.h"
+#include "v8_binding.h"
+#include "V8Collection.h"
+#include "V8DOMWindow.h"
+#include "V8IsolatedWorld.h"
+
+#include "ChromiumBridge.h"
+#include "CSSMutableStyleDeclaration.h"
+#include "DOMObjectsInclude.h"
+#include "DocumentLoader.h"
+#include "FrameLoaderClient.h"
+#include "ScriptController.h"
+#include "V8CustomBinding.h"
+#include "V8DOMMap.h"
+#include "V8Index.h"
+#include "WorkerContextExecutionProxy.h"
+
+namespace WebCore {
+
+// Static utility context.
+v8::Persistent<v8::Context> V8Proxy::m_utilityContext;
+
+// Static list of registered extensions
+V8ExtensionList V8Proxy::m_extensions;
+
+// static
+const char* V8Proxy::kContextDebugDataType = "type";
+const char* V8Proxy::kContextDebugDataValue = "value";
+
+#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 USE_VAR(x) template is used to silence C++ compiler warnings
+// issued for unused variables (typically parameters or values that
+// we want to watch in the debugger).
+template <typename T>
+static inline void USE_VAR(T) { }
+
+// 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;
+ USE_VAR(info);
+ v8::Value* handle = it->first;
+ USE_VAR(handle);
+ }
+}
+
+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 // ifndef NDEBUG
+
+void BatchConfigureAttributes(v8::Handle<v8::ObjectTemplate> inst,
+ v8::Handle<v8::ObjectTemplate> proto,
+ const BatchedAttribute* attrs,
+ size_t num_attrs)
+{
+ for (size_t i = 0; i < num_attrs; ++i) {
+ const BatchedAttribute* a = &attrs[i];
+ (a->on_proto ? proto : inst)->SetAccessor(
+ v8::String::New(a->name),
+ a->getter,
+ a->setter,
+ a->data == V8ClassIndex::INVALID_CLASS_INDEX
+ ? v8::Handle<v8::Value>()
+ : v8::Integer::New(V8ClassIndex::ToInt(a->data)),
+ a->settings,
+ a->attribute);
+ }
+}
+
+void BatchConfigureConstants(v8::Handle<v8::FunctionTemplate> desc,
+ v8::Handle<v8::ObjectTemplate> proto,
+ const BatchedConstant* consts,
+ size_t num_consts)
+{
+ for (size_t i = 0; i < num_consts; ++i) {
+ const BatchedConstant* c = &consts[i];
+ desc->Set(v8::String::New(c->name),
+ v8::Integer::New(c->value),
+ v8::ReadOnly);
+ proto->Set(v8::String::New(c->name),
+ v8::Integer::New(c->value),
+ v8::ReadOnly);
+ }
+}
+
+typedef HashMap<Node*, v8::Object*> DOMNodeMap;
+typedef HashMap<void*, v8::Object*> DOMObjectMap;
+
+#ifndef NDEBUG
+
+static void EnumerateDOMObjectMap(DOMObjectMap& wrapper_map)
+{
+ for (DOMObjectMap::iterator it = wrapper_map.begin(), end = wrapper_map.end();
+ it != end; ++it) {
+ v8::Persistent<v8::Object> wrapper(it->second);
+ V8ClassIndex::V8WrapperType type = V8Proxy::GetDOMWrapperType(wrapper);
+ void* obj = it->first;
+ USE_VAR(type);
+ USE_VAR(obj);
+ }
+}
+
+class DOMObjectVisitor : public DOMWrapperMap<void>::Visitor {
+ public:
+ void visitDOMWrapper(void* object, v8::Persistent<v8::Object> wrapper) {
+ V8ClassIndex::V8WrapperType type = V8Proxy::GetDOMWrapperType(wrapper);
+ USE_VAR(type);
+ USE_VAR(object);
+ }
+};
+
+class EnsureWeakDOMNodeVisitor : public DOMWrapperMap<Node>::Visitor {
+ public:
+ void visitDOMWrapper(Node* object, v8::Persistent<v8::Object> wrapper) {
+ USE_VAR(object);
+ ASSERT(wrapper.IsWeak());
+ }
+};
+
+#endif // NDEBUG
+
+#if ENABLE(SVG)
+v8::Handle<v8::Value> V8Proxy::SVGElementInstanceToV8Object(
+ SVGElementInstance* instance)
+{
+ if (!instance)
+ return v8::Null();
+
+ v8::Handle<v8::Object> existing_instance = getDOMSVGElementInstanceMap().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,
+ V8ClassIndex::SVGELEMENTINSTANCE,
+ instance);
+ if (!result.IsEmpty()) {
+ // Only update the DOM SVG element map if the result is non-empty.
+ getDOMSVGElementInstanceMap().set(instance,
+ v8::Persistent<v8::Object>::New(result));
+ }
+ return result;
+}
+
+// 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::Value> V8Proxy::SVGObjectWithContextToV8Object(
+ V8ClassIndex::V8WrapperType type, void* object)
+{
+ if (!object)
+ return v8::Null();
+
+ v8::Persistent<v8::Object> result =
+ getDOMSVGObjectWithContextMap().get(object);
+ if (!result.IsEmpty()) return result;
+
+ // Special case: SVGPathSegs need to be downcast to their real type
+ if (type == V8ClassIndex::SVGPATHSEG)
+ type = V8Custom::DowncastSVGPathSeg(object);
+
+ v8::Local<v8::Object> v8obj = InstantiateV8Object(type, type, object);
+ if (!v8obj.IsEmpty()) {
+ result = v8::Persistent<v8::Object>::New(v8obj);
+ switch (type) {
+#define MAKE_CASE(TYPE, NAME) \
+ case V8ClassIndex::TYPE: static_cast<NAME*>(object)->ref(); break;
+SVG_OBJECT_TYPES(MAKE_CASE)
+#undef MAKE_CASE
+#define MAKE_CASE(TYPE, NAME) \
+ case V8ClassIndex::TYPE: \
+ static_cast<V8SVGPODTypeWrapper<NAME>*>(object)->ref(); break;
+SVG_POD_NATIVE_TYPES(MAKE_CASE)
+#undef MAKE_CASE
+ default:
+ ASSERT(false);
+ }
+ getDOMSVGObjectWithContextMap().set(object, result);
+ }
+
+ return result;
+}
+
+void V8Proxy::SetSVGContext(void* obj, SVGElement* context)
+{
+ if (obj == NULL)
+ return;
+
+ 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
+
+// A map from a DOM node to its JS wrapper, the wrapper
+// is kept as a strong reference to survive GCs.
+static DOMObjectMap& gc_protected_map() {
+ static DOMObjectMap static_gc_protected_map;
+ return static_gc_protected_map;
+}
+
+// static
+void V8Proxy::GCProtect(void* dom_object)
+{
+ if (!dom_object)
+ return;
+ if (gc_protected_map().contains(dom_object))
+ return;
+ if (!getDOMObjectMap().contains(dom_object))
+ return;
+
+ // Create a new (strong) persistent handle for the object.
+ v8::Persistent<v8::Object> wrapper = getDOMObjectMap().get(dom_object);
+ if (wrapper.IsEmpty()) return;
+
+ gc_protected_map().set(dom_object, *v8::Persistent<v8::Object>::New(wrapper));
+}
+
+
+// static
+void V8Proxy::GCUnprotect(void* 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();
+}
+
+class GCPrologueVisitor : public DOMWrapperMap<void>::Visitor {
+ public:
+ void visitDOMWrapper(void* object, v8::Persistent<v8::Object> wrapper) {
+ ASSERT(wrapper.IsWeak());
+ V8ClassIndex::V8WrapperType type = V8Proxy::GetDOMWrapperType(wrapper);
+ switch (type) {
+#define MAKE_CASE(TYPE, NAME) \
+ case V8ClassIndex::TYPE: { \
+ NAME* impl = static_cast<NAME*>(object); \
+ if (impl->hasPendingActivity()) \
+ wrapper.ClearWeak(); \
+ break; \
+ }
+ACTIVE_DOM_OBJECT_TYPES(MAKE_CASE)
+ default:
+ ASSERT(false);
+#undef MAKE_CASE
+ }
+
+ // Additional handling of message port ensuring that entangled ports also
+ // have their wrappers entangled. This should ideally be handled when the
+ // ports are actually entangled in MessagePort::entangle, but to avoid
+ // forking MessagePort.* this is postponed to GC time. Having this postponed
+ // has the drawback that the wrappers are "entangled/unentangled" for each
+ // GC even though their entanglement most likely is still the same.
+ if (type == V8ClassIndex::MESSAGEPORT) {
+ // Get the port and its entangled port.
+ MessagePort* port1 = static_cast<MessagePort*>(object);
+ MessagePort* port2 = port1->locallyEntangledPort();
+
+ // If we are remotely entangled, then mark this object as reachable
+ // (we can't determine reachability directly as the remote object is
+ // out-of-proc).
+ if (port1->isEntangled() && !port2)
+ wrapper.ClearWeak();
+
+ if (port2 != NULL) {
+ // As ports are always entangled in pairs only perform the entanglement
+ // once for each pair (see ASSERT in MessagePort::unentangle()).
+ if (port1 < port2) {
+ v8::Handle<v8::Value> port1_wrapper =
+ V8Proxy::ToV8Object(V8ClassIndex::MESSAGEPORT, port1);
+ v8::Handle<v8::Value> port2_wrapper =
+ V8Proxy::ToV8Object(V8ClassIndex::MESSAGEPORT, port2);
+ ASSERT(port1_wrapper->IsObject());
+ v8::Handle<v8::Object>::Cast(port1_wrapper)->SetInternalField(
+ V8Custom::kMessagePortEntangledPortIndex, port2_wrapper);
+ ASSERT(port2_wrapper->IsObject());
+ v8::Handle<v8::Object>::Cast(port2_wrapper)->SetInternalField(
+ V8Custom::kMessagePortEntangledPortIndex, port1_wrapper);
+ }
+ } else {
+ // Remove the wrapper entanglement when a port is not entangled.
+ if (V8Proxy::DOMObjectHasJSWrapper(port1)) {
+ v8::Handle<v8::Value> wrapper =
+ V8Proxy::ToV8Object(V8ClassIndex::MESSAGEPORT, port1);
+ ASSERT(wrapper->IsObject());
+ v8::Handle<v8::Object>::Cast(wrapper)->SetInternalField(
+ V8Custom::kMessagePortEntangledPortIndex, v8::Undefined());
+ }
+ }
+ }
+ }
+};
+
+class GrouperItem {
+ public:
+ GrouperItem(uintptr_t group_id, Node* node, v8::Persistent<v8::Object> wrapper)
+ : group_id_(group_id), node_(node), wrapper_(wrapper) { }
+
+ uintptr_t group_id() const { return group_id_; }
+ Node* node() const { return node_; }
+ v8::Persistent<v8::Object> wrapper() const { return wrapper_; }
+
+ private:
+ uintptr_t group_id_;
+ Node* node_;
+ v8::Persistent<v8::Object> wrapper_;
+};
+
+bool operator<(const GrouperItem& a, const GrouperItem& b) {
+ return a.group_id() < b.group_id();
+}
+
+typedef Vector<GrouperItem> GrouperList;
+
+class ObjectGrouperVisitor : public DOMWrapperMap<Node>::Visitor {
+ public:
+ ObjectGrouperVisitor() {
+ // TODO(abarth): grouper_.reserveCapacity(node_map.size()); ?
+ }
+
+ void visitDOMWrapper(Node* node, v8::Persistent<v8::Object> wrapper) {
+ // 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.
+ //
+ // Otherwise, the node is put in an object group identified by the root
+ // elment of the tree to which it belongs.
+ uintptr_t group_id;
+ if (node->inDocument() ||
+ (node->hasTagName(HTMLNames::imgTag) &&
+ !static_cast<HTMLImageElement*>(node)->haveFiredLoadEvent())) {
+ group_id = reinterpret_cast<uintptr_t>(node->document());
+ } else {
+ Node* root = node;
+ while (root->parent())
+ root = root->parent();
+
+ // If the node is alone in its DOM tree (doesn't have a parent or any
+ // children) then the group will be filtered out later anyway.
+ if (root == node && !node->hasChildNodes())
+ return;
+
+ group_id = reinterpret_cast<uintptr_t>(root);
+ }
+ grouper_.append(GrouperItem(group_id, node, wrapper));
+ }
+
+ void ApplyGrouping() {
+ // Group by sorting by the group id.
+ std::sort(grouper_.begin(), grouper_.end());
+
+ // TODO(deanm): Should probably work in iterators here, but indexes were
+ // easier for my simple mind.
+ for (size_t i = 0; i < grouper_.size(); ) {
+ // Seek to the next key (or the end of the list).
+ size_t next_key_index = grouper_.size();
+ for (size_t j = i; j < grouper_.size(); ++j) {
+ if (grouper_[i].group_id() != grouper_[j].group_id()) {
+ next_key_index = j;
+ break;
+ }
+ }
+
+ ASSERT(next_key_index > i);
+
+ // We only care about a group if it has more than one object. If it only
+ // has one object, it has nothing else that needs to be kept alive.
+ if (next_key_index - i <= 1) {
+ i = next_key_index;
+ continue;
+ }
+
+ Vector<v8::Persistent<v8::Value> > group;
+ group.reserveCapacity(next_key_index - i);
+ for (; i < next_key_index; ++i) {
+ Node* node = grouper_[i].node();
+ v8::Persistent<v8::Value> wrapper = grouper_[i].wrapper();
+ if (!wrapper.IsEmpty())
+ group.append(wrapper);
+ /* TODO(abarth): Re-enabled this code to avoid GCing these wrappers!
+ Currently this depends on looking up the wrapper
+ during a GC, but we don't know which isolated world
+ we're in, so it's unclear which map to look in...
+
+ // If the node is styled and there is a wrapper for the inline
+ // style declaration, we need to keep that style declaration
+ // wrapper alive as well, so we add it to the object group.
+ if (node->isStyledElement()) {
+ StyledElement* element = reinterpret_cast<StyledElement*>(node);
+ CSSStyleDeclaration* style = element->inlineStyleDecl();
+ if (style != NULL) {
+ wrapper = getDOMObjectMap().get(style);
+ if (!wrapper.IsEmpty())
+ group.append(wrapper);
+ }
+ }
+ */
+ }
+
+ if (group.size() > 1)
+ v8::V8::AddObjectGroup(&group[0], group.size());
+
+ ASSERT(i == next_key_index);
+ }
+ }
+
+ private:
+ GrouperList grouper_;
+};
+
+// Create object groups for DOM tree nodes.
+static void GCPrologue()
+{
+ v8::HandleScope scope;
+
+#ifndef NDEBUG
+ DOMObjectVisitor domObjectVisitor;
+ visitDOMObjectsInCurrentThread(&domObjectVisitor);
+#endif
+
+ // Run through all objects with possible pending activity making their
+ // wrappers non weak if there is pending activity.
+ GCPrologueVisitor prologueVisitor;
+ visitActiveDOMObjectsInCurrentThread(&prologueVisitor);
+
+ // Create object groups.
+ ObjectGrouperVisitor objectGrouperVisitor;
+ visitDOMNodesInCurrentThread(&objectGrouperVisitor);
+ objectGrouperVisitor.ApplyGrouping();
+}
+
+class GCEpilogueVisitor : public DOMWrapperMap<void>::Visitor {
+ public:
+ void visitDOMWrapper(void* object, v8::Persistent<v8::Object> wrapper)
+ {
+ V8ClassIndex::V8WrapperType type = V8Proxy::GetDOMWrapperType(wrapper);
+ switch (type) {
+#define MAKE_CASE(TYPE, NAME) \
+ case V8ClassIndex::TYPE: { \
+ NAME* impl = static_cast<NAME*>(object); \
+ if (impl->hasPendingActivity()) { \
+ ASSERT(!wrapper.IsWeak()); \
+ wrapper.MakeWeak(impl, &weakActiveDOMObjectCallback); \
+ } \
+ break; \
+ }
+ACTIVE_DOM_OBJECT_TYPES(MAKE_CASE)
+ default:
+ ASSERT(false);
+#undef MAKE_CASE
+ }
+ }
+};
+
+static void GCEpilogue()
+{
+ v8::HandleScope scope;
+
+ // Run through all objects with pending activity making their wrappers weak
+ // again.
+ GCEpilogueVisitor epilogueVisitor;
+ visitActiveDOMObjectsInCurrentThread(&epilogueVisitor);
+
+#ifndef NDEBUG
+ // Check all survivals are weak.
+ DOMObjectVisitor domObjectVisitor;
+ visitDOMObjectsInCurrentThread(&domObjectVisitor);
+
+ EnsureWeakDOMNodeVisitor weakDOMNodeVisitor;
+ visitDOMNodesInCurrentThread(&weakDOMNodeVisitor);
+
+ EnumerateDOMObjectMap(gc_protected_map());
+ EnumerateGlobalHandles();
+#undef USE_VAR
+#endif
+}
+
+
+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);
+ Console* console = page->mainFrame()->domWindow()->console();
+ console->addMessage(JSMessageSource, ErrorMessageLevel, m_string, m_lineNumber, m_sourceID);
+}
+
+// The ConsoleMessageManager handles all console messages that stem
+// from JavaScript. It keeps a list of messages that have been delayed but
+// it makes sure to add all messages to the console in the right order.
+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::retrieveFrameForEnteredContext();
+ 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::retrieveFrameForEnteredContext();
+ 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::Value> resourceName = message->GetScriptResourceName();
+ bool useURL = (resourceName.IsEmpty() || !resourceName->IsString());
+ String resourceNameString = (useURL)
+ ? frame->document()->url()
+ : ToWebCoreString(resourceName);
+ JavaScriptConsoleMessage consoleMessage(errorMessage,
+ resourceNameString,
+ 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::retrieveFrameForEnteredContext();
+ if (!source || !source->document())
+ return; // Ignore error if the source document is gone.
+
+ Document* sourceDocument = source->document();
+
+ // 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().string().utf8().data(),
+ sourceDocument->url().string().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)
+{
+ Frame* target = V8Custom::GetTargetFrame(host, data);
+ if (target)
+ ReportUnsafeAccessTo(target, REPORT_LATER);
+}
+
+static void HandleFatalErrorInV8()
+{
+ // TODO: We temporarily deal with V8 internal error situations
+ // such as out-of-memory by crashing the renderer.
+ CRASH();
+}
+
+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);
+ HandleFatalErrorInV8();
+}
+
+V8Proxy::~V8Proxy()
+{
+ clearForClose();
+ DestroyGlobal();
+}
+
+void V8Proxy::DestroyGlobal()
+{
+ if (!m_global.IsEmpty()) {
+#ifndef NDEBUG
+ UnregisterGlobalHandle(this, m_global);
+#endif
+ m_global.Dispose();
+ m_global.Clear();
+ }
+}
+
+
+bool V8Proxy::DOMObjectHasJSWrapper(void* obj) {
+ return getDOMObjectMap().contains(obj) ||
+ getActiveDOMObjectMap().contains(obj);
+}
+
+
+// The caller must have increased obj's ref count.
+void V8Proxy::SetJSWrapperForDOMObject(void* obj, v8::Persistent<v8::Object> wrapper)
+{
+ ASSERT(MaybeDOMWrapper(wrapper));
+#ifndef NDEBUG
+ V8ClassIndex::V8WrapperType type = V8Proxy::GetDOMWrapperType(wrapper);
+ switch (type) {
+#define MAKE_CASE(TYPE, NAME) case V8ClassIndex::TYPE:
+ACTIVE_DOM_OBJECT_TYPES(MAKE_CASE)
+ ASSERT(false);
+#undef MAKE_CASE
+ default: break;
+ }
+#endif
+ getDOMObjectMap().set(obj, wrapper);
+}
+
+// The caller must have increased obj's ref count.
+void V8Proxy::SetJSWrapperForActiveDOMObject(void* obj, v8::Persistent<v8::Object> wrapper)
+{
+ ASSERT(MaybeDOMWrapper(wrapper));
+#ifndef NDEBUG
+ V8ClassIndex::V8WrapperType type = V8Proxy::GetDOMWrapperType(wrapper);
+ switch (type) {
+#define MAKE_CASE(TYPE, NAME) case V8ClassIndex::TYPE: break;
+ACTIVE_DOM_OBJECT_TYPES(MAKE_CASE)
+ default: ASSERT(false);
+#undef MAKE_CASE
+ }
+#endif
+ getActiveDOMObjectMap().set(obj, wrapper);
+}
+
+// The caller must have increased node's ref count.
+void V8Proxy::SetJSWrapperForDOMNode(Node* node, v8::Persistent<v8::Object> wrapper)
+{
+ ASSERT(MaybeDOMWrapper(wrapper));
+ getDOMNodeMap().set(node, wrapper);
+}
+
+// Event listeners
+
+static V8EventListener* FindEventListenerInList(V8EventListenerList& list,
+ v8::Local<v8::Value> listener,
+ bool isInline)
+{
+ ASSERT(v8::Context::InContext());
+
+ if (!listener->IsObject())
+ return 0;
+
+ return list.find(listener->ToObject(), isInline);
+}
+
+// Find an existing wrapper for a JS event listener in the map.
+PassRefPtr<V8EventListener> V8Proxy::FindV8EventListener(v8::Local<v8::Value> listener,
+ bool isInline)
+{
+ return FindEventListenerInList(m_event_listeners, listener, isInline);
+}
+
+PassRefPtr<V8EventListener> V8Proxy::FindOrCreateV8EventListener(v8::Local<v8::Value> obj, bool isInline)
+{
+ ASSERT(v8::Context::InContext());
+
+ if (!obj->IsObject())
+ return 0;
+
+ V8EventListener* wrapper =
+ FindEventListenerInList(m_event_listeners, obj, isInline);
+ if (wrapper)
+ return wrapper;
+
+ // Create a new one, and add to cache.
+ RefPtr<V8EventListener> new_listener =
+ V8EventListener::create(m_frame, v8::Local<v8::Object>::Cast(obj), isInline);
+ m_event_listeners.add(new_listener.get());
+
+ return new_listener;
+}
+
+
+// Object event listeners (such as XmlHttpRequest and MessagePort) are
+// different from listeners on DOM nodes. An object event listener wrapper
+// only holds a weak reference to the JS function. A strong reference can
+// create a cycle.
+//
+// The lifetime of these objects is bounded by the life time of its JS
+// wrapper. So we can create a hidden reference from the JS wrapper to
+// to its JS function.
+//
+// (map)
+// XHR <---------- JS_wrapper
+// | (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 V8ObjectEventListener.
+
+PassRefPtr<V8EventListener> V8Proxy::FindObjectEventListener(
+ v8::Local<v8::Value> listener, bool isInline)
+{
+ return FindEventListenerInList(m_xhr_listeners, listener, isInline);
+}
+
+
+PassRefPtr<V8EventListener> V8Proxy::FindOrCreateObjectEventListener(
+ v8::Local<v8::Value> obj, bool isInline)
+{
+ ASSERT(v8::Context::InContext());
+
+ if (!obj->IsObject())
+ return 0;
+
+ V8EventListener* wrapper =
+ FindEventListenerInList(m_xhr_listeners, obj, isInline);
+ if (wrapper)
+ return wrapper;
+
+ // Create a new one, and add to cache.
+ RefPtr<V8EventListener> new_listener =
+ V8ObjectEventListener::create(m_frame, v8::Local<v8::Object>::Cast(obj), isInline);
+ m_xhr_listeners.add(new_listener.get());
+
+ return new_listener.release();
+}
+
+
+static void RemoveEventListenerFromList(V8EventListenerList& list,
+ V8EventListener* listener)
+{
+ list.remove(listener);
+}
+
+
+void V8Proxy::RemoveV8EventListener(V8EventListener* listener)
+{
+ RemoveEventListenerFromList(m_event_listeners, listener);
+}
+
+
+void V8Proxy::RemoveObjectEventListener(V8ObjectEventListener* 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);
+ if (proxy != NULL) {
+ // Clean m_context, and event handlers.
+ proxy->clearForClose();
+ // Destroy the global object.
+ proxy->DestroyGlobal();
+ }
+
+ ChromiumBridge::notifyJSOutOfMemory(frame);
+
+ // Disable JS.
+ Settings* settings = frame->settings();
+ ASSERT(settings);
+ settings->setJavaScriptEnabled(false);
+
+ return true;
+}
+
+void V8Proxy::evaluateInNewWorld(const Vector<ScriptSourceCode>& sources)
+{
+ InitContextIfNeeded();
+ V8IsolatedWorld::evaluate(sources, this);
+}
+
+void V8Proxy::evaluateInNewContext(const Vector<ScriptSourceCode>& sources)
+{
+ InitContextIfNeeded();
+
+ v8::HandleScope handleScope;
+
+ // Set up the DOM window as the prototype of the new global object.
+ v8::Handle<v8::Context> windowContext = m_context;
+ v8::Handle<v8::Object> windowGlobal = windowContext->Global();
+ v8::Handle<v8::Value> windowWrapper =
+ V8Proxy::LookupDOMWrapper(V8ClassIndex::DOMWINDOW, windowGlobal);
+
+ ASSERT(V8Proxy::DOMWrapperToNative<DOMWindow>(windowWrapper) ==
+ m_frame->domWindow());
+
+ v8::Persistent<v8::Context> context =
+ createNewContext(v8::Handle<v8::Object>());
+ v8::Context::Scope context_scope(context);
+
+ // Setup context id for JS debugger.
+ v8::Handle<v8::Object> context_data = v8::Object::New();
+ v8::Handle<v8::Value> window_context_data = windowContext->GetData();
+ if (window_context_data->IsObject()) {
+ v8::Handle<v8::String> property_name =
+ v8::String::New(kContextDebugDataValue);
+ context_data->Set(
+ property_name,
+ v8::Object::Cast(*window_context_data)->Get(property_name));
+ }
+ context_data->Set(v8::String::New(kContextDebugDataType),
+ v8::String::New("injected"));
+ context->SetData(context_data);
+
+ v8::Handle<v8::Object> global = context->Global();
+
+ v8::Handle<v8::String> implicitProtoString = v8::String::New("__proto__");
+ global->Set(implicitProtoString, windowWrapper);
+
+ // Give the code running in the new context a way to get access to the
+ // original context.
+ global->Set(v8::String::New("contentWindow"), windowGlobal);
+
+ // Run code in the new context.
+ for (size_t i = 0; i < sources.size(); ++i)
+ evaluate(sources[i], 0);
+
+ // Using the default security token means that the canAccess is always
+ // called, which is slow.
+ // TODO(aa): Use tokens where possible. This will mean keeping track of all
+ // created contexts so that they can all be updated when the document domain
+ // changes.
+ context->UseDefaultSecurityToken();
+ context.Dispose();
+}
+
+v8::Local<v8::Value> V8Proxy::evaluate(const ScriptSourceCode& source, Node* n)
+{
+ ASSERT(v8::Context::InContext());
+
+ // Compile the script.
+ v8::Local<v8::String> code = v8ExternalString(source.source());
+ ChromiumBridge::traceEventBegin("v8.compile", n, "");
+
+ // NOTE: For compatibility with WebCore, ScriptSourceCode's line starts at
+ // 1, whereas v8 starts at 0.
+ v8::Handle<v8::Script> script = CompileScript(code, source.url(),
+ source.startLine() - 1);
+ ChromiumBridge::traceEventEnd("v8.compile", n, "");
+
+ ChromiumBridge::traceEventBegin("v8.run", n, "");
+ v8::Local<v8::Value> result;
+ {
+ // Isolate exceptions that occur when executing the code. These
+ // exceptions should not interfere with javascript code we might
+ // evaluate from C++ when returning from here
+ v8::TryCatch try_catch;
+ try_catch.SetVerbose(true);
+
+ // Set inlineCode to true for <a href="javascript:doSomething()">
+ // and false for <script>doSomething</script>. We make a rough guess at
+ // this based on whether the script source has a URL.
+ result = RunScript(script, source.url().string().isNull());
+ }
+ ChromiumBridge::traceEventEnd("v8.run", n, "");
+ return result;
+}
+
+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 >= kMaxRecursionDepth) {
+ 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::Local<v8::Value> V8Proxy::NewInstance(v8::Handle<v8::Function> constructor,
+ int argc,
+ v8::Handle<v8::Value> args[])
+{
+ // No artificial limitations on the depth of recursion, see comment in
+ // V8Proxy::CallFunction.
+ v8::Local<v8::Value> result;
+ {
+ ConsoleMessageScope scope;
+
+ // See comment in V8Proxy::CallFunction.
+ m_frame->keepAlive();
+
+ result = constructor->NewInstance(argc, args);
+ }
+
+ if (v8::V8::IsDead())
+ HandleFatalErrorInV8();
+
+ return result;
+}
+
+
+v8::Local<v8::Function> V8Proxy::GetConstructor(V8ClassIndex::V8WrapperType t){
+ // A DOM constructor is a function instance created from a DOM constructor
+ // template. There is one instance per context. A DOM constructor is
+ // different from a normal function in two ways:
+ // 1) it cannot be called as constructor (aka, used to create a DOM object)
+ // 2) its __proto__ points to Object.prototype rather than
+ // Function.prototype.
+ // The reason for 2) is that, in Safari, a DOM constructor is a normal JS
+ // object, but not a function. Hotmail relies on the fact that, in Safari,
+ // HTMLElement.__proto__ == Object.prototype.
+ //
+ // m_object_prototype is a cache of the original Object.prototype.
+
+ ASSERT(ContextInitialized());
+ // Enter the context of the proxy to make sure that the
+ // function is constructed in the context corresponding to
+ // this proxy.
+ v8::Context::Scope scope(m_context);
+ v8::Handle<v8::FunctionTemplate> templ = GetTemplate(t);
+ // Getting the function might fail if we're running out of
+ // stack or memory.
+ v8::TryCatch try_catch;
+ v8::Local<v8::Function> value = templ->GetFunction();
+ if (value.IsEmpty())
+ return v8::Local<v8::Function>();
+ // Hotmail fix, see comments above.
+ value->Set(v8::String::New("__proto__"), m_object_prototype);
+ return value;
+}
+
+
+v8::Local<v8::Object> V8Proxy::CreateWrapperFromCache(V8ClassIndex::V8WrapperType type) {
+ int class_index = V8ClassIndex::ToInt(type);
+ v8::Local<v8::Value> cached_object =
+ m_wrapper_boilerplates->Get(v8::Integer::New(class_index));
+ if (cached_object->IsObject()) {
+ v8::Local<v8::Object> object = v8::Local<v8::Object>::Cast(cached_object);
+ return object->Clone();
+ }
+
+ // Not in cache.
+ InitContextIfNeeded();
+ v8::Context::Scope scope(m_context);
+ v8::Local<v8::Function> function = GetConstructor(type);
+ v8::Local<v8::Object> instance = SafeAllocation::NewInstance(function);
+ if (!instance.IsEmpty()) {
+ m_wrapper_boilerplates->Set(v8::Integer::New(class_index), instance);
+ return instance->Clone();
+ }
+ return v8::Local<v8::Object>();
+}
+
+
+// Get the string 'toString'.
+static v8::Persistent<v8::String> GetToStringName() {
+ static v8::Persistent<v8::String> value;
+ if (value.IsEmpty())
+ value = v8::Persistent<v8::String>::New(v8::String::New("toString"));
+ return value;
+}
+
+
+static v8::Handle<v8::Value> ConstructorToString(const v8::Arguments& args) {
+ // The DOM constructors' toString functions grab the current toString
+ // for Functions by taking the toString function of itself and then
+ // calling it with the constructor as its receiver. This means that
+ // changes to the Function prototype chain or toString function are
+ // reflected when printing DOM constructors. The only wart is that
+ // changes to a DOM constructor's toString's toString will cause the
+ // toString of the DOM constructor itself to change. This is extremely
+ // obscure and unlikely to be a problem.
+ v8::Handle<v8::Value> val = args.Callee()->Get(GetToStringName());
+ if (!val->IsFunction()) return v8::String::New("");
+ return v8::Handle<v8::Function>::Cast(val)->Call(args.This(), 0, NULL);
+}
+
+
+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();
+ // DOM constructors are functions and should print themselves as such.
+ // However, we will later replace their prototypes with Object
+ // prototypes so we need to explicitly override toString on the
+ // instance itself. If we later make DOM constructors full objects
+ // we can give them class names instead and Object.prototype.toString
+ // will work so we can remove this code.
+ static v8::Persistent<v8::FunctionTemplate> to_string_template;
+ if (to_string_template.IsEmpty()) {
+ to_string_template = v8::Persistent<v8::FunctionTemplate>::New(
+ v8::FunctionTemplate::New(ConstructorToString));
+ }
+ desc->Set(GetToStringName(), to_string_template);
+ 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, CSSRule>(desc,
+ V8ClassIndex::CSSRULE);
+ break;
+ case V8ClassIndex::CSSVALUELIST:
+ setCollectionIndexedGetter<CSSValueList, CSSValue>(
+ desc,
+ V8ClassIndex::CSSVALUE);
+ break;
+ case V8ClassIndex::CSSVARIABLESDECLARATION:
+ setCollectionStringOrNullIndexedGetter<CSSVariablesDeclaration>(desc);
+ break;
+ case V8ClassIndex::WEBKITCSSTRANSFORMVALUE:
+ setCollectionIndexedGetter<WebKitCSSTransformValue, CSSValue>(
+ 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, Node>(desc,
+ V8ClassIndex::NODE);
+ break;
+ case V8ClassIndex::HTMLOPTIONSCOLLECTION:
+ desc->InstanceTemplate()->SetNamedPropertyHandler(
+ USE_NAMED_PROPERTY_GETTER(HTMLCollection));
+ 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(
+ USE_NAMED_PROPERTY_GETTER(HTMLSelectElementCollection));
+ desc->InstanceTemplate()->SetIndexedPropertyHandler(
+ nodeCollectionIndexedPropertyGetter<HTMLSelectElement>,
+ USE_INDEXED_PROPERTY_SETTER(HTMLSelectElementCollection),
+ 0,
+ 0,
+ nodeCollectionIndexedPropertyEnumerator<HTMLSelectElement>,
+ v8::Integer::New(V8ClassIndex::NODE));
+ break;
+ case V8ClassIndex::HTMLDOCUMENT: {
+ desc->InstanceTemplate()->SetNamedPropertyHandler(
+ USE_NAMED_PROPERTY_GETTER(HTMLDocument),
+ 0,
+ 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;
+ }
+#if ENABLE(SVG)
+ case V8ClassIndex::SVGDOCUMENT: // fall through
+#endif
+ case V8ClassIndex::DOCUMENT: {
+ // 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::HTMLAPPLETELEMENT: // fall through
+ case V8ClassIndex::HTMLEMBEDELEMENT: // fall through
+ case V8ClassIndex::HTMLOBJECTELEMENT:
+ // HTMLAppletElement, 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,
+ nodeCollectionIndexedPropertyEnumerator<HTMLFormElement>,
+ v8::Integer::New(V8ClassIndex::NODE));
+ break;
+ case V8ClassIndex::CANVASPIXELARRAY:
+ desc->InstanceTemplate()->SetIndexedPropertyHandler(
+ USE_INDEXED_PROPERTY_GETTER(CanvasPixelArray),
+ USE_INDEXED_PROPERTY_SETTER(CanvasPixelArray));
+ break;
+ case V8ClassIndex::STYLESHEET: // fall through
+ case V8ClassIndex::CSSSTYLESHEET: {
+ // We add an extra internal field to hold a reference to
+ // the owner node.
+ v8::Local<v8::ObjectTemplate> instance_template =
+ desc->InstanceTemplate();
+ ASSERT(instance_template->InternalFieldCount() ==
+ V8Custom::kDefaultWrapperInternalFieldCount);
+ instance_template->SetInternalFieldCount(
+ V8Custom::kStyleSheetInternalFieldCount);
+ break;
+ }
+ case V8ClassIndex::MEDIALIST:
+ setCollectionStringOrNullIndexedGetter<MediaList>(desc);
+ break;
+ case V8ClassIndex::MIMETYPEARRAY:
+ setCollectionIndexedAndNamedGetters<MimeTypeArray, MimeType>(
+ 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::Integer::New(V8ClassIndex::NODE));
+ break;
+#if ENABLE(DOM_STORAGE)
+ case V8ClassIndex::STORAGE:
+ desc->InstanceTemplate()->SetNamedPropertyHandler(
+ USE_NAMED_PROPERTY_GETTER(Storage),
+ USE_NAMED_PROPERTY_SETTER(Storage),
+ 0,
+ USE_NAMED_PROPERTY_DELETER(Storage),
+ V8Custom::v8StorageNamedPropertyEnumerator);
+ desc->InstanceTemplate()->SetIndexedPropertyHandler(
+ USE_INDEXED_PROPERTY_GETTER(Storage),
+ USE_INDEXED_PROPERTY_SETTER(Storage),
+ 0,
+ USE_INDEXED_PROPERTY_DELETER(Storage));
+ break;
+#endif
+ case V8ClassIndex::NODELIST:
+ setCollectionIndexedGetter<NodeList, Node>(desc, V8ClassIndex::NODE);
+ desc->InstanceTemplate()->SetNamedPropertyHandler(
+ USE_NAMED_PROPERTY_GETTER(NodeList));
+ break;
+ case V8ClassIndex::PLUGIN:
+ setCollectionIndexedAndNamedGetters<Plugin, MimeType>(
+ desc,
+ V8ClassIndex::MIMETYPE);
+ break;
+ case V8ClassIndex::PLUGINARRAY:
+ setCollectionIndexedAndNamedGetters<PluginArray, Plugin>(
+ desc,
+ V8ClassIndex::PLUGIN);
+ break;
+ case V8ClassIndex::STYLESHEETLIST:
+ desc->InstanceTemplate()->SetNamedPropertyHandler(
+ USE_NAMED_PROPERTY_GETTER(StyleSheetList));
+ setCollectionIndexedGetter<StyleSheetList, StyleSheet>(
+ 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->SetHiddenPrototype(true);
+
+ // Reserve spaces for references to location, history and
+ // navigator objects.
+ v8::Local<v8::ObjectTemplate> instance_template =
+ desc->InstanceTemplate();
+ instance_template->SetInternalFieldCount(
+ V8Custom::kDOMWindowInternalFieldCount);
+
+ // Set access check callbacks, but turned off initially.
+ // When a context is detached from a frame, turn on the access check.
+ // Turning on checks also invalidates inline caches of the object.
+ instance_template->SetAccessCheckCallbacks(
+ V8Custom::v8DOMWindowNamedSecurityCheck,
+ V8Custom::v8DOMWindowIndexedSecurityCheck,
+ v8::Integer::New(V8ClassIndex::DOMWINDOW),
+ false);
+ break;
+ }
+ case V8ClassIndex::LOCATION: {
+ // For security reasons, these functions are on the instance
+ // instead of on the prototype object to insure that they cannot
+ // be overwritten.
+ v8::Local<v8::ObjectTemplate> instance = desc->InstanceTemplate();
+ instance->SetAccessor(
+ v8::String::New("reload"),
+ V8Custom::v8LocationReloadAccessorGetter,
+ 0,
+ v8::Handle<v8::Value>(),
+ v8::ALL_CAN_READ,
+ static_cast<v8::PropertyAttribute>(v8::DontDelete|v8::ReadOnly));
+
+ instance->SetAccessor(
+ v8::String::New("replace"),
+ V8Custom::v8LocationReplaceAccessorGetter,
+ 0,
+ v8::Handle<v8::Value>(),
+ v8::ALL_CAN_READ,
+ static_cast<v8::PropertyAttribute>(v8::DontDelete|v8::ReadOnly));
+
+ instance->SetAccessor(
+ v8::String::New("assign"),
+ V8Custom::v8LocationAssignAccessorGetter,
+ 0,
+ v8::Handle<v8::Value>(),
+ v8::ALL_CAN_READ,
+ static_cast<v8::PropertyAttribute>(v8::DontDelete|v8::ReadOnly));
+ break;
+ }
+ case V8ClassIndex::HISTORY: {
+ break;
+ }
+
+ case V8ClassIndex::MESSAGECHANNEL: {
+ // Reserve two more internal fields for referencing the port1
+ // and port2 wrappers. This ensures that the port wrappers are
+ // kept alive when the channel wrapper is.
+ desc->SetCallHandler(USE_CALLBACK(MessageChannelConstructor));
+ v8::Local<v8::ObjectTemplate> instance_template =
+ desc->InstanceTemplate();
+ instance_template->SetInternalFieldCount(
+ V8Custom::kMessageChannelInternalFieldCount);
+ break;
+ }
+
+ case V8ClassIndex::MESSAGEPORT: {
+ // Reserve one more internal field for keeping event listeners.
+ v8::Local<v8::ObjectTemplate> instance_template =
+ desc->InstanceTemplate();
+ instance_template->SetInternalFieldCount(
+ V8Custom::kMessagePortInternalFieldCount);
+ break;
+ }
+
+#if ENABLE(WORKERS)
+ case V8ClassIndex::WORKER: {
+ // Reserve one more internal field for keeping event listeners.
+ v8::Local<v8::ObjectTemplate> instance_template =
+ desc->InstanceTemplate();
+ instance_template->SetInternalFieldCount(
+ V8Custom::kWorkerInternalFieldCount);
+ desc->SetCallHandler(USE_CALLBACK(WorkerConstructor));
+ break;
+ }
+
+ case V8ClassIndex::WORKERCONTEXT: {
+ // Reserve one more internal field for keeping event listeners.
+ v8::Local<v8::ObjectTemplate> instance_template =
+ desc->InstanceTemplate();
+ instance_template->SetInternalFieldCount(
+ V8Custom::kWorkerContextInternalFieldCount);
+ break;
+ }
+#endif // WORKERS
+
+
+ // The following objects are created from JavaScript.
+ case V8ClassIndex::DOMPARSER:
+ desc->SetCallHandler(USE_CALLBACK(DOMParserConstructor));
+ break;
+#if ENABLE(VIDEO)
+ case V8ClassIndex::HTMLAUDIOELEMENT:
+ desc->SetCallHandler(USE_CALLBACK(HTMLAudioElementConstructor));
+ break;
+#endif
+ case V8ClassIndex::HTMLIMAGEELEMENT:
+ desc->SetCallHandler(USE_CALLBACK(HTMLImageElementConstructor));
+ break;
+ case V8ClassIndex::HTMLOPTIONELEMENT:
+ desc->SetCallHandler(USE_CALLBACK(HTMLOptionElementConstructor));
+ break;
+ case V8ClassIndex::WEBKITCSSMATRIX:
+ desc->SetCallHandler(USE_CALLBACK(WebKitCSSMatrixConstructor));
+ break;
+ case V8ClassIndex::WEBKITPOINT:
+ desc->SetCallHandler(USE_CALLBACK(WebKitPointConstructor));
+ 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();
+ instance_template->SetInternalFieldCount(
+ V8Custom::kXMLHttpRequestInternalFieldCount);
+ desc->SetCallHandler(USE_CALLBACK(XMLHttpRequestConstructor));
+ break;
+ }
+ case V8ClassIndex::XMLHTTPREQUESTUPLOAD: {
+ // Reserve one more internal field for keeping event listeners.
+ v8::Local<v8::ObjectTemplate> instance_template =
+ desc->InstanceTemplate();
+ instance_template->SetInternalFieldCount(
+ V8Custom::kXMLHttpRequestInternalFieldCount);
+ break;
+ }
+ case V8ClassIndex::XPATHEVALUATOR:
+ desc->SetCallHandler(USE_CALLBACK(XPathEvaluatorConstructor));
+ break;
+ case V8ClassIndex::XSLTPROCESSOR:
+ desc->SetCallHandler(USE_CALLBACK(XSLTProcessorConstructor));
+ break;
+ case V8ClassIndex::CLIENTRECTLIST:
+ desc->InstanceTemplate()->SetIndexedPropertyHandler(
+ USE_INDEXED_PROPERTY_GETTER(ClientRectList));
+ break;
+ default:
+ break;
+ }
+
+ *cache_cell = desc;
+ return desc;
+}
+
+
+bool V8Proxy::ContextInitialized()
+{
+ // m_context, m_global, m_object_prototype and m_wrapper_boilerplates should
+ // all be non-empty if if m_context is non-empty.
+ ASSERT(m_context.IsEmpty() || !m_global.IsEmpty());
+ ASSERT(m_context.IsEmpty() || !m_object_prototype.IsEmpty());
+ ASSERT(m_context.IsEmpty() || !m_wrapper_boilerplates.IsEmpty());
+ 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?
+ return retrieveWindow(v8::Context::GetCurrent());
+}
+
+
+DOMWindow* V8Proxy::retrieveWindow(v8::Handle<v8::Context> context)
+{
+ v8::Handle<v8::Object> global = context->Global();
+ ASSERT(!global.IsEmpty());
+ global = LookupDOMWrapper(V8ClassIndex::DOMWINDOW, global);
+ ASSERT(!global.IsEmpty());
+ return ToNativeObject<DOMWindow>(V8ClassIndex::DOMWINDOW, global);
+}
+
+
+Frame* V8Proxy::retrieveFrame(v8::Handle<v8::Context> context)
+{
+ return retrieveWindow(context)->frame();
+}
+
+
+Frame* V8Proxy::retrieveFrameForEnteredContext()
+{
+ v8::Handle<v8::Context> context = v8::Context::GetEntered();
+ if (context.IsEmpty())
+ return 0;
+ return retrieveFrame(context);
+}
+
+
+Frame* V8Proxy::retrieveFrameForCurrentContext()
+{
+ v8::Handle<v8::Context> context = v8::Context::GetCurrent();
+ if (context.IsEmpty())
+ return 0;
+ return retrieveFrame(context);
+}
+
+
+Frame* V8Proxy::retrieveFrameForCallingContext()
+{
+ v8::Handle<v8::Context> context = v8::Context::GetCalling();
+ 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;
+ return frame->script()->isEnabled() ? frame->script()->proxy() : 0;
+}
+
+
+V8Proxy* V8Proxy::retrieve(ScriptExecutionContext* context)
+{
+ if (!context->isDocument())
+ return 0;
+ return retrieve(static_cast<Document*>(context)->frame());
+}
+
+
+void V8Proxy::disconnectFrame()
+{
+ // disconnect all event listeners
+ DisconnectEventListeners();
+}
+
+
+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
+
+ // TODO(darin): the following are application decisions, and they should
+ // not be made at this layer. instead, we should bridge out to the
+ // embedder to allow them to override policy here.
+
+ if (origin->protocol() == ChromiumBridge::uiResourceProtocol())
+ 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" };
+ for (size_t i = 0; i < arraysize(kDirProtocols); ++i) {
+ if (origin->protocol() == kDirProtocols[i]) {
+ const KURL& url = document->url();
+ return url.pathAfterLastSlash() == url.pathEnd();
+ }
+ }
+
+ return false; // Other protocols fall through to here
+}
+
+
+void V8Proxy::UpdateDocumentWrapper(v8::Handle<v8::Value> wrapper) {
+ ClearDocumentWrapper();
+
+ ASSERT(m_document.IsEmpty());
+ m_document = v8::Persistent<v8::Value>::New(wrapper);
+#ifndef NDEBUG
+ RegisterGlobalHandle(PROXY, this, m_document);
+#endif
+}
+
+
+void V8Proxy::ClearDocumentWrapper()
+{
+ if (!m_document.IsEmpty()) {
+#ifndef NDEBUG
+ UnregisterGlobalHandle(this, m_document);
+#endif
+ m_document.Dispose();
+ m_document.Clear();
+ }
+}
+
+
+void V8Proxy::UpdateDocumentWrapperCache()
+{
+ v8::HandleScope handle_scope;
+ v8::Context::Scope context_scope(GetContext());
+
+ // If the document has no frame, NodeToV8Object might get the
+ // document wrapper for a document that is about to be deleted.
+ // If the ForceSet below causes a garbage collection, the document
+ // might get deleted and the global handle for the document
+ // wrapper cleared. Using the cleared global handle will lead to
+ // crashes. In this case we clear the cache and let the DOMWindow
+ // accessor handle access to the document.
+ if (!m_frame->document()->frame()) {
+ ClearDocumentWrapperCache();
+ return;
+ }
+
+ v8::Handle<v8::Value> document_wrapper = NodeToV8Object(m_frame->document());
+
+ // If instantiation of the document wrapper fails, clear the cache
+ // and let the DOMWindow accessor handle access to the document.
+ if (document_wrapper.IsEmpty()) {
+ ClearDocumentWrapperCache();
+ return;
+ }
+
+ m_context->Global()->ForceSet(v8::String::New("document"),
+ document_wrapper,
+ static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete));
+}
+
+
+void V8Proxy::ClearDocumentWrapperCache()
+{
+ ASSERT(!m_context.IsEmpty());
+ m_context->Global()->ForceDelete(v8::String::New("document"));
+}
+
+
+void V8Proxy::DisposeContextHandles() {
+ if (!m_context.IsEmpty()) {
+ m_frame->loader()->client()->didDestroyScriptContext();
+ m_context.Dispose();
+ m_context.Clear();
+ }
+
+ if (!m_wrapper_boilerplates.IsEmpty()) {
+#ifndef NDEBUG
+ UnregisterGlobalHandle(this, m_wrapper_boilerplates);
+#endif
+ m_wrapper_boilerplates.Dispose();
+ m_wrapper_boilerplates.Clear();
+ }
+
+ if (!m_object_prototype.IsEmpty()) {
+#ifndef NDEBUG
+ UnregisterGlobalHandle(this, m_object_prototype);
+#endif
+ m_object_prototype.Dispose();
+ m_object_prototype.Clear();
+ }
+}
+
+void V8Proxy::clearForClose()
+{
+ if (!m_context.IsEmpty()) {
+ v8::HandleScope handle_scope;
+
+ ClearDocumentWrapper();
+ DisposeContextHandles();
+ }
+}
+
+
+void V8Proxy::clearForNavigation()
+{
+ // disconnect all event listeners
+ DisconnectEventListeners();
+
+ if (!m_context.IsEmpty()) {
+ v8::HandleScope handle;
+ ClearDocumentWrapper();
+
+ v8::Context::Scope context_scope(m_context);
+
+ // Clear the document wrapper cache before turning on access checks on
+ // the old DOMWindow wrapper. This way, access to the document wrapper
+ // will be protected by the security checks on the DOMWindow wrapper.
+ ClearDocumentWrapperCache();
+
+ // Turn on access check on the old DOMWindow wrapper.
+ v8::Handle<v8::Object> wrapper =
+ LookupDOMWrapper(V8ClassIndex::DOMWINDOW, m_global);
+ ASSERT(!wrapper.IsEmpty());
+ wrapper->TurnOnAccessCheck();
+
+ // Separate the context from its global object.
+ m_context->DetachGlobal();
+
+ DisposeContextHandles();
+
+ // Reinitialize the context so the global object points to
+ // the new DOM window.
+ InitContextIfNeeded();
+ }
+}
+
+
+void V8Proxy::SetSecurityToken() {
+ Document* document = m_frame->document();
+ // Setup security origin and security token
+ if (!document) {
+ m_context->UseDefaultSecurityToken();
+ return;
+ }
+
+ // 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.
+ // Note: we can't use the HTTPOrigin if it was set from the DOM.
+ SecurityOrigin* origin = document->securityOrigin();
+ String token;
+ if (!origin->domainWasSetInDOM())
+ token = document->securityOrigin()->toString();
+
+ // An empty or "null" token means we always have to call
+ // canAccess. The toString method on securityOrigins returns the
+ // string "null" for empty security origins and for security
+ // origins that should only allow access to themselves. 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() || token == "null") {
+ m_context->UseDefaultSecurityToken();
+ return;
+ }
+
+ CString utf8_token = token.utf8();
+ // NOTE: V8 does identity comparison in fast path, must use a symbol
+ // as the security token.
+ m_context->SetSecurityToken(
+ v8::String::NewSymbol(utf8_token.data(), utf8_token.length()));
+}
+
+
+void V8Proxy::updateDocument()
+{
+ if (!m_frame->document())
+ return;
+
+ if (m_global.IsEmpty()) {
+ ASSERT(m_context.IsEmpty());
+ return;
+ }
+
+ // We have a new document and we need to update the cache.
+ UpdateDocumentWrapperCache();
+
+ updateSecurityOrigin();
+}
+
+void V8Proxy::updateSecurityOrigin()
+{
+ v8::HandleScope scope;
+ SetSecurityToken();
+}
+
+// Same origin policy implementation:
+//
+// Same origin policy prevents JS code from domain A access JS & DOM objects
+// in a different domain B. There are exceptions and several objects are
+// accessible by cross-domain code. For example, the window.frames object is
+// accessible by code from a different domain, but window.document is not.
+//
+// The binding code sets security check callbacks on a function template,
+// and accessing instances of the template calls the callback function.
+// The callback function checks same origin policy.
+//
+// Callback functions are expensive. V8 uses a security token string to do
+// fast access checks for the common case where source and target are in the
+// same domain. A security token is a string object that represents
+// the protocol/url/port of a domain.
+//
+// There are special cases where a security token matching is not enough.
+// For example, JavaScript can set its domain to a super domain by calling
+// document.setDomain(...). In these cases, the binding code can reset
+// a context's security token to its global object so that the fast access
+// check will always fail.
+
+// Check if the current execution context can access a target frame.
+// First it checks same domain policy using the lexical context
+//
+// This is equivalent to KJS::Window::allowsAccessFrom(ExecState*, String&).
+bool V8Proxy::CanAccessPrivate(DOMWindow* target_window)
+{
+ ASSERT(target_window);
+
+ String message;
+
+ DOMWindow* origin_window = retrieveWindow();
+ if (origin_window == target_window)
+ return true;
+
+ if (!origin_window)
+ return false;
+
+ const SecurityOrigin* active_security_origin = origin_window->securityOrigin();
+ const SecurityOrigin* target_security_origin = target_window->securityOrigin();
+
+ // We have seen crashes were the security origin of the target has not been
+ // initialized. Defend against that.
+ if (!target_security_origin)
+ return false;
+
+ if (active_security_origin->canAccess(target_security_origin))
+ return true;
+
+ // Allow access to a "about:blank" page if the dynamic context is a
+ // detached context of the same frame as the blank page.
+ if (target_security_origin->isEmpty() &&
+ origin_window->frame() == target_window->frame())
+ return true;
+
+ return false;
+}
+
+
+bool V8Proxy::CanAccessFrame(Frame* target, bool report_error)
+{
+ // The subject is detached from a frame, deny accesses.
+ if (!target)
+ return false;
+
+ if (!CanAccessPrivate(target->domWindow())) {
+ 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 CanAccessFrame(target, true);
+}
+
+v8::Persistent<v8::Context> V8Proxy::createNewContext(
+ v8::Handle<v8::Object> global)
+{
+ v8::Persistent<v8::Context> result;
+
+ // Create a new environment using an empty template for the shadow
+ // object. Reuse the global object if one has been created earlier.
+ v8::Persistent<v8::ObjectTemplate> globalTemplate =
+ V8DOMWindow::GetShadowObjectTemplate();
+ if (globalTemplate.IsEmpty())
+ return result;
+
+ // Install a security handler with V8.
+ globalTemplate->SetAccessCheckCallbacks(
+ V8Custom::v8DOMWindowNamedSecurityCheck,
+ V8Custom::v8DOMWindowIndexedSecurityCheck,
+ v8::Integer::New(V8ClassIndex::DOMWINDOW));
+
+ // Dynamically tell v8 about our extensions now.
+ const char** extensionNames = new const char*[m_extensions.size()];
+ int index = 0;
+ for (V8ExtensionList::iterator it = m_extensions.begin();
+ it != m_extensions.end(); ++it) {
+ // Note: we check the loader URL here instead of the document URL
+ // because we might be currently loading an URL into a blank page.
+ // See http://code.google.com/p/chromium/issues/detail?id=10924
+ if (it->scheme.length() > 0 &&
+ (it->scheme != m_frame->loader()->activeDocumentLoader()->url().protocol() ||
+ it->scheme != m_frame->page()->mainFrame()->loader()->activeDocumentLoader()->url().protocol()))
+ continue;
+
+ extensionNames[index++] = it->extension->name();
+ }
+ v8::ExtensionConfiguration extensions(index, extensionNames);
+ result = v8::Context::New(&extensions, globalTemplate, global);
+ delete [] extensionNames;
+ extensionNames = 0;
+
+ return result;
+}
+
+bool V8Proxy::installDOMWindow(v8::Handle<v8::Context> context,
+ DOMWindow* window)
+{
+ v8::Handle<v8::String> implicit_proto_string = v8::String::New("__proto__");
+ if (implicit_proto_string.IsEmpty())
+ return false;
+
+ // Create a new JS window object and use it as the prototype for the
+ // shadow global object.
+ v8::Handle<v8::Function> window_constructor =
+ GetConstructor(V8ClassIndex::DOMWINDOW);
+ v8::Local<v8::Object> js_window =
+ SafeAllocation::NewInstance(window_constructor);
+ // Bail out if allocation failed.
+ if (js_window.IsEmpty())
+ return false;
+
+ // Wrap the window.
+ SetDOMWrapper(js_window,
+ V8ClassIndex::ToInt(V8ClassIndex::DOMWINDOW),
+ window);
+
+ window->ref();
+ V8Proxy::SetJSWrapperForDOMObject(window,
+ v8::Persistent<v8::Object>::New(js_window));
+
+ // Insert the window instance as the prototype of the shadow object.
+ v8::Handle<v8::Object> v8_global = context->Global();
+ v8_global->Set(implicit_proto_string, js_window);
+ return 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.
+//
+// To implement split-window, see
+// 1) https://bugs.webkit.org/show_bug.cgi?id=17249
+// 2) https://wiki.mozilla.org/Gecko:SplitWindow
+// 3) https://bugzilla.mozilla.org/show_bug.cgi?id=296639
+// we need to split the shadow object further into two objects:
+// an outer window and an inner window. The inner window is the hidden
+// prototype of the outer window. The inner window is the default
+// global object of the context. A variable declared in the global
+// scope is a property of the inner window.
+//
+// The outer window sticks to a Frame, it is exposed to JavaScript
+// via window.window, window.self, window.parent, etc. The outer window
+// has a security token which is the domain. The outer window cannot
+// have its own properties. window.foo = 'x' is delegated to the
+// inner window.
+//
+// When a frame navigates to a new page, the inner window is cut off
+// the outer window, and the outer window identify is preserved for
+// the frame. However, a new inner window is created for the new page.
+// If there are JS code holds a closure to the old inner window,
+// it won't be able to reach the outer window via its global object.
+void V8Proxy::InitContextIfNeeded()
+{
+ // Bail out if the context has already been initialized.
+ if (!m_context.IsEmpty())
+ return;
+
+ // Create a handle scope for all local handles.
+ v8::HandleScope handle_scope;
+
+ // Setup the security handlers and message listener. This only has
+ // to be done once.
+ static bool v8_initialized = false;
+ if (!v8_initialized) {
+ // 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);
+
+ v8_initialized = true;
+ }
+
+ m_context = createNewContext(m_global);
+ if (m_context.IsEmpty())
+ return;
+
+ // Starting from now, use local context only.
+ v8::Local<v8::Context> context = GetContext();
+ v8::Context::Scope context_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());
+ // Bail out if allocation of the first global objects fails.
+ if (m_global.IsEmpty()) {
+ DisposeContextHandles();
+ return;
+ }
+#ifndef NDEBUG
+ RegisterGlobalHandle(PROXY, this, m_global);
+#endif
+ }
+
+ // Allocate strings used during initialization.
+ v8::Handle<v8::String> object_string = v8::String::New("Object");
+ v8::Handle<v8::String> prototype_string = v8::String::New("prototype");
+ // Bail out if allocation failed.
+ if (object_string.IsEmpty() ||
+ prototype_string.IsEmpty()) {
+ DisposeContextHandles();
+ return;
+ }
+
+ // Allocate clone cache and pre-allocated objects
+ v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(
+ m_global->Get(object_string));
+ m_object_prototype = v8::Persistent<v8::Value>::New(
+ object->Get(prototype_string));
+ m_wrapper_boilerplates = v8::Persistent<v8::Array>::New(
+ v8::Array::New(V8ClassIndex::WRAPPER_TYPE_COUNT));
+ // Bail out if allocation failed.
+ if (m_object_prototype.IsEmpty()) {
+ DisposeContextHandles();
+ return;
+ }
+#ifndef NDEBUG
+ RegisterGlobalHandle(PROXY, this, m_object_prototype);
+ RegisterGlobalHandle(PROXY, this, m_wrapper_boilerplates);
+#endif
+
+ if (!installDOMWindow(context, m_frame->domWindow()))
+ DisposeContextHandles();
+
+ updateDocument();
+
+ SetSecurityToken();
+
+ m_frame->loader()->client()->didCreateScriptContext();
+ m_frame->loader()->dispatchWindowObjectAvailable();
+}
+
+template <class T>
+void setDOMExceptionHelper(V8ClassIndex::V8WrapperType type, PassRefPtr<T> exception) {
+ v8::Handle<v8::Value> v8Exception;
+ if (WorkerContextExecutionProxy::retrieve())
+ v8Exception = WorkerContextExecutionProxy::ToV8Object(type, exception.get());
+ else
+ v8Exception = V8Proxy::ToV8Object(type, exception.get());
+
+ v8::ThrowException(v8Exception);
+}
+
+void V8Proxy::SetDOMException(int exception_code)
+{
+ if (exception_code <= 0)
+ return;
+
+ ExceptionCodeDescription description;
+ getExceptionCodeDescription(exception_code, description);
+
+ v8::Handle<v8::Value> exception;
+ switch (description.type) {
+ case DOMExceptionType:
+ setDOMExceptionHelper(V8ClassIndex::DOMCOREEXCEPTION,
+ DOMCoreException::create(description));
+ break;
+ case RangeExceptionType:
+ setDOMExceptionHelper(V8ClassIndex::RANGEEXCEPTION,
+ RangeException::create(description));
+ break;
+ case EventExceptionType:
+ setDOMExceptionHelper(V8ClassIndex::EVENTEXCEPTION,
+ EventException::create(description));
+ break;
+ case XMLHttpRequestExceptionType:
+ setDOMExceptionHelper(V8ClassIndex::XMLHTTPREQUESTEXCEPTION,
+ XMLHttpRequestException::create(description));
+ break;
+#if ENABLE(SVG)
+ case SVGExceptionType:
+ setDOMExceptionHelper(V8ClassIndex::SVGEXCEPTION,
+ SVGException::create(description));
+ break;
+#endif
+#if ENABLE(XPATH)
+ case XPathExceptionType:
+ setDOMExceptionHelper(V8ClassIndex::XPATHEXCEPTION,
+ XPathException::create(description));
+ break;
+#endif
+ default:
+ ASSERT(false);
+ break;
+ }
+}
+
+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);
+
+ bool is_active_dom_object = false;
+ switch (type) {
+#define MAKE_CASE(TYPE, NAME) case V8ClassIndex::TYPE:
+ DOM_NODE_TYPES(MAKE_CASE)
+#if ENABLE(SVG)
+ SVG_NODE_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)
+ SVG_NONNODE_TYPES(MAKE_CASE)
+ if (type == V8ClassIndex::SVGELEMENTINSTANCE)
+ return SVGElementInstanceToV8Object(static_cast<SVGElementInstance*>(imp));
+ return SVGObjectWithContextToV8Object(type, imp);
+#endif
+
+ ACTIVE_DOM_OBJECT_TYPES(MAKE_CASE)
+ is_active_dom_object = true;
+ break;
+ default:
+ break;
+ }
+
+#undef MAKE_CASE
+
+ if (!imp) return v8::Null();
+
+ // Non DOM node
+ v8::Persistent<v8::Object> result = is_active_dom_object ?
+ getActiveDOMObjectMap().get(imp) :
+ getDOMObjectMap().get(imp);
+ if (result.IsEmpty()) {
+ v8::Local<v8::Object> v8obj = InstantiateV8Object(type, type, imp);
+ if (!v8obj.IsEmpty()) {
+ // Go through big switch statement, it has some duplications
+ // that were handled by code above (such as CSSVALUE, CSSRULE, etc).
+ switch (type) {
+#define MAKE_CASE(TYPE, NAME) \
+ case V8ClassIndex::TYPE: static_cast<NAME*>(imp)->ref(); break;
+ DOM_OBJECT_TYPES(MAKE_CASE)
+#undef MAKE_CASE
+ default:
+ ASSERT(false);
+ }
+ result = v8::Persistent<v8::Object>::New(v8obj);
+ if (is_active_dom_object)
+ SetJSWrapperForActiveDOMObject(imp, result);
+ else
+ SetJSWrapperForDOMObject(imp, result);
+
+ // Special case for non-node objects associated with a
+ // DOMWindow. Both Safari and FF let the JS wrappers for these
+ // objects survive GC. To mimic their behavior, V8 creates
+ // hidden references from the DOMWindow to these wrapper
+ // objects. These references get cleared when the DOMWindow is
+ // reused by a new page.
+ switch (type) {
+ case V8ClassIndex::CONSOLE:
+ SetHiddenWindowReference(static_cast<Console*>(imp)->frame(),
+ V8Custom::kDOMWindowConsoleIndex, result);
+ break;
+ case V8ClassIndex::HISTORY:
+ SetHiddenWindowReference(static_cast<History*>(imp)->frame(),
+ V8Custom::kDOMWindowHistoryIndex, result);
+ break;
+ case V8ClassIndex::NAVIGATOR:
+ SetHiddenWindowReference(static_cast<Navigator*>(imp)->frame(),
+ V8Custom::kDOMWindowNavigatorIndex, result);
+ break;
+ case V8ClassIndex::SCREEN:
+ SetHiddenWindowReference(static_cast<Screen*>(imp)->frame(),
+ V8Custom::kDOMWindowScreenIndex, result);
+ break;
+ case V8ClassIndex::LOCATION:
+ SetHiddenWindowReference(static_cast<Location*>(imp)->frame(),
+ V8Custom::kDOMWindowLocationIndex, result);
+ break;
+ case V8ClassIndex::DOMSELECTION:
+ SetHiddenWindowReference(static_cast<DOMSelection*>(imp)->frame(),
+ V8Custom::kDOMWindowDOMSelectionIndex, result);
+ break;
+ case V8ClassIndex::BARINFO: {
+ BarInfo* barinfo = static_cast<BarInfo*>(imp);
+ Frame* frame = barinfo->frame();
+ switch (barinfo->type()) {
+ case BarInfo::Locationbar:
+ SetHiddenWindowReference(frame, V8Custom::kDOMWindowLocationbarIndex, result);
+ break;
+ case BarInfo::Menubar:
+ SetHiddenWindowReference(frame, V8Custom::kDOMWindowMenubarIndex, result);
+ break;
+ case BarInfo::Personalbar:
+ SetHiddenWindowReference(frame, V8Custom::kDOMWindowPersonalbarIndex, result);
+ break;
+ case BarInfo::Scrollbars:
+ SetHiddenWindowReference(frame, V8Custom::kDOMWindowScrollbarsIndex, result);
+ break;
+ case BarInfo::Statusbar:
+ SetHiddenWindowReference(frame, V8Custom::kDOMWindowStatusbarIndex, result);
+ break;
+ case BarInfo::Toolbar:
+ SetHiddenWindowReference(frame, V8Custom::kDOMWindowToolbarIndex, result);
+ break;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ }
+ return result;
+}
+
+
+void V8Proxy::SetHiddenWindowReference(Frame* frame,
+ const int internal_index,
+ v8::Handle<v8::Object> jsobj)
+{
+ // Get DOMWindow
+ if (!frame) return; // Object might be detached from window
+ v8::Handle<v8::Context> context = GetContext(frame);
+ if (context.IsEmpty()) return;
+
+ ASSERT(internal_index < V8Custom::kDOMWindowInternalFieldCount);
+
+ v8::Handle<v8::Object> global = context->Global();
+ // Look for real DOM wrapper.
+ global = LookupDOMWrapper(V8ClassIndex::DOMWINDOW, global);
+ ASSERT(!global.IsEmpty());
+ ASSERT(global->GetInternalField(internal_index)->IsUndefined());
+ global->SetInternalField(internal_index, jsobj);
+}
+
+
+V8ClassIndex::V8WrapperType V8Proxy::GetDOMWrapperType(v8::Handle<v8::Object> object)
+{
+ ASSERT(MaybeDOMWrapper(object));
+ v8::Handle<v8::Value> type =
+ object->GetInternalField(V8Custom::kDOMWrapperTypeIndex);
+ return V8ClassIndex::FromInt(type->Int32Value());
+}
+
+
+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);
+
+ ASSERT(MaybeDOMWrapper(object));
+
+ switch (type) {
+#define MAKE_CASE(TYPE, NAME) case V8ClassIndex::TYPE:
+ DOM_NODE_TYPES(MAKE_CASE)
+#if ENABLE(SVG)
+ SVG_NODE_TYPES(MAKE_CASE)
+#endif
+ ASSERT(false);
+ return NULL;
+ 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<void>(object);
+}
+
+
+void* V8Proxy::ToSVGPODTypeImpl(V8ClassIndex::V8WrapperType type,
+ v8::Handle<v8::Value> object) {
+ return IsWrapperOfType(object, type)
+ ? DOMWrapperToNative<void>(object)
+ : NULL;
+}
+
+
+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>();
+}
+
+
+// static
+void* V8Proxy::DOMWrapperToNodeHelper(v8::Handle<v8::Value> value) {
+ ASSERT(MaybeDOMWrapper(value));
+
+ v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(value);
+
+ ASSERT(GetDOMWrapperType(object) == V8ClassIndex::NODE);
+
+ v8::Handle<v8::Value> wrapper =
+ object->GetInternalField(V8Custom::kDOMWrapperObjectIndex);
+ return ExtractCPointer<Node>(wrapper);
+}
+
+
+PassRefPtr<NodeFilter> V8Proxy::ToNativeNodeFilter(v8::Handle<v8::Value> filter)
+{
+ // A NodeFilter is used when walking through a DOM tree or iterating tree
+ // nodes.
+ // TODO: we may want to cache NodeFilterCondition and NodeFilter
+ // object, but it is minor.
+ // NodeFilter is passed to NodeIterator that has a ref counted pointer
+ // to NodeFilter. NodeFilter has a ref counted pointer to NodeFilterCondition.
+ // In NodeFilterCondition, filter object is persisted in its constructor,
+ // and disposed in its destructor.
+ if (!filter->IsFunction())
+ return 0;
+
+ NodeFilterCondition* cond = new V8NodeFilterCondition(filter);
+ return NodeFilter::create(cond);
+}
+
+
+v8::Local<v8::Object> V8Proxy::InstantiateV8Object(
+ V8ClassIndex::V8WrapperType desc_type,
+ V8ClassIndex::V8WrapperType cptr_type,
+ void* imp)
+{
+ // Make a special case for document.all
+ if (desc_type == V8ClassIndex::HTMLCOLLECTION &&
+ static_cast<HTMLCollection*>(imp)->type() == DocAll) {
+ desc_type = V8ClassIndex::UNDETECTABLEHTMLCOLLECTION;
+ }
+
+ V8Proxy* proxy = V8Proxy::retrieve();
+ v8::Local<v8::Object> instance;
+ if (proxy) {
+ instance = proxy->CreateWrapperFromCache(desc_type);
+ } else {
+ v8::Local<v8::Function> function = GetTemplate(desc_type)->GetFunction();
+ instance = SafeAllocation::NewInstance(function);
+ }
+ if (!instance.IsEmpty()) {
+ // Avoid setting the DOM wrapper for failed allocations.
+ SetDOMWrapper(instance, V8ClassIndex::ToInt(cptr_type), imp);
+ }
+ return instance;
+}
+
+v8::Handle<v8::Value> V8Proxy::CheckNewLegal(const v8::Arguments& args)
+{
+ if (!AllowAllocation::m_current)
+ return ThrowError(TYPE_ERROR, "Illegal constructor");
+
+ return args.This();
+}
+
+void V8Proxy::SetDOMWrapper(v8::Handle<v8::Object> obj, int type, void* cptr)
+{
+ ASSERT(obj->InternalFieldCount() >= 2);
+ obj->SetInternalField(V8Custom::kDOMWrapperObjectIndex, WrapCPointer(cptr));
+ obj->SetInternalField(V8Custom::kDOMWrapperTypeIndex, v8::Integer::New(type));
+}
+
+
+#ifndef NDEBUG
+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() == 0) return false;
+
+ ASSERT(obj->InternalFieldCount() >=
+ V8Custom::kDefaultWrapperInternalFieldCount);
+
+ v8::Handle<v8::Value> type =
+ obj->GetInternalField(V8Custom::kDOMWrapperTypeIndex);
+ ASSERT(type->IsInt32());
+ ASSERT(V8ClassIndex::INVALID_CLASS_INDEX < type->Int32Value() &&
+ type->Int32Value() < V8ClassIndex::CLASSINDEX_END);
+
+ v8::Handle<v8::Value> wrapper =
+ obj->GetInternalField(V8Custom::kDOMWrapperObjectIndex);
+ ASSERT(wrapper->IsNumber() || wrapper->IsExternal());
+
+ return true;
+}
+#endif
+
+
+bool V8Proxy::IsDOMEventWrapper(v8::Handle<v8::Value> value)
+{
+ // All kinds of events use EVENT as dom type in JS wrappers.
+ // See EventToV8Object
+ return IsWrapperOfType(value, V8ClassIndex::EVENT);
+}
+
+bool V8Proxy::IsWrapperOfType(v8::Handle<v8::Value> value,
+ V8ClassIndex::V8WrapperType classType)
+{
+ if (value.IsEmpty() || !value->IsObject()) return false;
+
+ v8::Handle<v8::Object> obj = v8::Handle<v8::Object>::Cast(value);
+ if (obj->InternalFieldCount() == 0) return false;
+
+ ASSERT(obj->InternalFieldCount() >=
+ V8Custom::kDefaultWrapperInternalFieldCount);
+
+ v8::Handle<v8::Value> wrapper =
+ obj->GetInternalField(V8Custom::kDOMWrapperObjectIndex);
+ ASSERT(wrapper->IsNumber() || wrapper->IsExternal());
+
+ v8::Handle<v8::Value> type =
+ obj->GetInternalField(V8Custom::kDOMWrapperTypeIndex);
+ ASSERT(type->IsInt32());
+ ASSERT(V8ClassIndex::INVALID_CLASS_INDEX < type->Int32Value() &&
+ type->Int32Value() < V8ClassIndex::CLASSINDEX_END);
+
+ return V8ClassIndex::FromInt(type->Int32Value()) == classType;
+}
+
+#if ENABLE(VIDEO)
+#define FOR_EACH_VIDEO_TAG(macro) \
+ macro(audio, AUDIO) \
+ macro(source, SOURCE) \
+ macro(video, VIDEO)
+#else
+#define FOR_EACH_VIDEO_TAG(macro)
+#endif
+
+#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)
+#if ENABLE(VIDEO)
+ if (MediaPlayer::isAvailable()) {
+FOR_EACH_VIDEO_TAG(ADD_TO_HASH_MAP)
+ }
+#endif
+#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(altGlyph, ALTGLYPH) \
+ macro(circle, CIRCLE) \
+ macro(clipPath, CLIPPATH) \
+ macro(cursor, CURSOR) \
+ macro(defs, DEFS) \
+ macro(desc, DESC) \
+ macro(ellipse, ELLIPSE) \
+ macro(g, G) \
+ macro(glyph, GLYPH) \
+ 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> wrapper = getDOMObjectMap().get(event);
+ if (!wrapper.IsEmpty())
+ return wrapper;
+
+ V8ClassIndex::V8WrapperType type = V8ClassIndex::EVENT;
+
+ if (event->isUIEvent()) {
+ if (event->isKeyboardEvent())
+ type = V8ClassIndex::KEYBOARDEVENT;
+ else if (event->isTextEvent())
+ type = V8ClassIndex::TEXTEVENT;
+ else if (event->isMouseEvent())
+ type = V8ClassIndex::MOUSEEVENT;
+ else if (event->isWheelEvent())
+ type = V8ClassIndex::WHEELEVENT;
+#if ENABLE(SVG)
+ else if (event->isSVGZoomEvent())
+ type = V8ClassIndex::SVGZOOMEVENT;
+#endif
+ else
+ type = V8ClassIndex::UIEVENT;
+ } else if (event->isMutationEvent())
+ type = V8ClassIndex::MUTATIONEVENT;
+ else if (event->isOverflowEvent())
+ type = V8ClassIndex::OVERFLOWEVENT;
+ else if (event->isMessageEvent())
+ type = V8ClassIndex::MESSAGEEVENT;
+ else if (event->isProgressEvent()) {
+ if (event->isXMLHttpRequestProgressEvent())
+ type = V8ClassIndex::XMLHTTPREQUESTPROGRESSEVENT;
+ else
+ type = V8ClassIndex::PROGRESSEVENT;
+ } else if (event->isWebKitAnimationEvent())
+ type = V8ClassIndex::WEBKITANIMATIONEVENT;
+ else if (event->isWebKitTransitionEvent())
+ type = V8ClassIndex::WEBKITTRANSITIONEVENT;
+
+
+ v8::Handle<v8::Object> result =
+ InstantiateV8Object(type, V8ClassIndex::EVENT, 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();
+ }
+
+ event->ref(); // fast ref
+ SetJSWrapperForDOMObject(event, v8::Persistent<v8::Object>::New(result));
+
+ return result;
+}
+
+
+// Caller checks node is not null.
+v8::Handle<v8::Value> V8Proxy::NodeToV8Object(Node* node)
+{
+ if (!node) return v8::Null();
+
+ // Find the context to which the node belongs and create the wrapper
+ // in that context. If the node is not in a document, the current
+ // context is used.
+ //
+ // Getting the context might initialize the context which can instantiate
+ // a document wrapper. Therefore, we get the context before checking if
+ // the node already has a wrapper.
+ v8::Local<v8::Context> context;
+ Document* doc = node->document();
+ if (doc) {
+ context = V8Proxy::GetContext(doc->frame());
+ }
+
+ v8::Handle<v8::Object> wrapper = getDOMNodeMap().get(node);
+ if (!wrapper.IsEmpty())
+ return wrapper;
+
+ 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;
+ }
+
+ // Enter the node's context and create the wrapper in that context.
+ if (!context.IsEmpty()) {
+ context->Enter();
+ }
+
+ v8::Local<v8::Object> result =
+ InstantiateV8Object(type, V8ClassIndex::NODE, node);
+
+ // Exit the node's context if it was entered.
+ if (!context.IsEmpty()) {
+ context->Exit();
+ }
+
+ 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;
+ }
+
+ node->ref();
+ SetJSWrapperForDOMNode(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->UpdateDocumentWrapper(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;
+}
+
+
+// A JS object of type EventTarget can only be the following possible types:
+// 1) EventTargetNode; 2) DOMWindow 3) XMLHttpRequest; 4) MessagePort;
+// 5) XMLHttpRequestUpload
+// check EventTarget.h for new type conversion methods
+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
+
+#if ENABLE(WORKERS)
+ Worker* worker = target->toWorker();
+ if (worker)
+ return ToV8Object(V8ClassIndex::WORKER, worker);
+#endif // WORKERS
+
+ Node* node = target->toNode();
+ if (node)
+ return NodeToV8Object(node);
+
+ if (DOMWindow* domWindow = target->toDOMWindow())
+ return ToV8Object(V8ClassIndex::DOMWINDOW, domWindow);
+
+ // XMLHttpRequest is created within its JS counterpart.
+ XMLHttpRequest* xhr = target->toXMLHttpRequest();
+ if (xhr) {
+ v8::Handle<v8::Object> wrapper = getActiveDOMObjectMap().get(xhr);
+ ASSERT(!wrapper.IsEmpty());
+ return wrapper;
+ }
+
+ // MessagePort is created within its JS counterpart
+ MessagePort* port = target->toMessagePort();
+ if (port) {
+ v8::Handle<v8::Object> wrapper = getActiveDOMObjectMap().get(port);
+ ASSERT(!wrapper.IsEmpty());
+ return wrapper;
+ }
+
+ XMLHttpRequestUpload* upload = target->toXMLHttpRequestUpload();
+ if (upload) {
+ v8::Handle<v8::Object> wrapper = getDOMObjectMap().get(upload);
+ ASSERT(!wrapper.IsEmpty());
+ return wrapper;
+ }
+
+ 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,
+ 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::Value> V8Proxy::StyleSheetToV8Object(StyleSheet* sheet)
+{
+ if (!sheet) return v8::Null();
+
+ v8::Handle<v8::Object> wrapper = getDOMObjectMap().get(sheet);
+ if (!wrapper.IsEmpty())
+ return wrapper;
+
+ V8ClassIndex::V8WrapperType type = V8ClassIndex::STYLESHEET;
+ if (sheet->isCSSStyleSheet())
+ type = V8ClassIndex::CSSSTYLESHEET;
+
+ v8::Handle<v8::Object> result =
+ InstantiateV8Object(type, V8ClassIndex::STYLESHEET, sheet);
+ if (!result.IsEmpty()) {
+ // Only update the DOM object map if the result is non-empty.
+ sheet->ref();
+ SetJSWrapperForDOMObject(sheet, v8::Persistent<v8::Object>::New(result));
+ }
+
+ // Add a hidden reference from stylesheet object to its owner node.
+ Node* owner_node = sheet->ownerNode();
+ if (owner_node) {
+ v8::Handle<v8::Object> owner =
+ v8::Handle<v8::Object>::Cast(NodeToV8Object(owner_node));
+ result->SetInternalField(V8Custom::kStyleSheetOwnerNodeIndex, owner);
+ }
+
+ return result;
+}
+
+
+v8::Handle<v8::Value> V8Proxy::CSSValueToV8Object(CSSValue* value)
+{
+ if (!value) return v8::Null();
+
+ v8::Handle<v8::Object> wrapper = getDOMObjectMap().get(value);
+ if (!wrapper.IsEmpty())
+ return wrapper;
+
+ V8ClassIndex::V8WrapperType type;
+
+ if (value->isWebKitCSSTransformValue())
+ type = V8ClassIndex::WEBKITCSSTRANSFORMVALUE;
+ else 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, V8ClassIndex::CSSVALUE, value);
+ if (!result.IsEmpty()) {
+ // Only update the DOM object map if the result is non-empty.
+ value->ref();
+ SetJSWrapperForDOMObject(value, v8::Persistent<v8::Object>::New(result));
+ }
+
+ return result;
+}
+
+
+v8::Handle<v8::Value> V8Proxy::CSSRuleToV8Object(CSSRule* rule)
+{
+ if (!rule) return v8::Null();
+
+ v8::Handle<v8::Object> wrapper = getDOMObjectMap().get(rule);
+ if (!wrapper.IsEmpty())
+ return wrapper;
+
+ 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;
+ case CSSRule::VARIABLES_RULE:
+ type = V8ClassIndex::CSSVARIABLESRULE;
+ break;
+ case CSSRule::WEBKIT_KEYFRAME_RULE:
+ type = V8ClassIndex::WEBKITCSSKEYFRAMERULE;
+ break;
+ case CSSRule::WEBKIT_KEYFRAMES_RULE:
+ type = V8ClassIndex::WEBKITCSSKEYFRAMESRULE;
+ break;
+ default: // CSSRule::UNKNOWN_RULE
+ type = V8ClassIndex::CSSRULE;
+ break;
+ }
+
+ v8::Handle<v8::Object> result =
+ InstantiateV8Object(type, V8ClassIndex::CSSRULE, rule);
+ if (!result.IsEmpty()) {
+ // Only update the DOM object map if the result is non-empty.
+ rule->ref();
+ SetJSWrapperForDOMObject(rule, v8::Persistent<v8::Object>::New(result));
+ }
+ return result;
+}
+
+v8::Handle<v8::Value> V8Proxy::WindowToV8Object(DOMWindow* window)
+{
+ if (!window) return v8::Null();
+ // Initializes environment of a frame, and return the global object
+ // of the frame.
+ Frame* frame = window->frame();
+ if (!frame)
+ return v8::Handle<v8::Object>();
+
+ // Special case: Because of evaluateInNewContext() one DOMWindow can have
+ // multiple contexts and multiple global objects associated with it. When
+ // code running in one of those contexts accesses the window object, we
+ // want to return the global object associated with that context, not
+ // necessarily the first global object associated with that DOMWindow.
+ v8::Handle<v8::Context> current_context = v8::Context::GetCurrent();
+ v8::Handle<v8::Object> current_global = current_context->Global();
+ v8::Handle<v8::Object> windowWrapper =
+ LookupDOMWrapper(V8ClassIndex::DOMWINDOW, current_global);
+ if (!windowWrapper.IsEmpty())
+ if (DOMWrapperToNative<DOMWindow>(windowWrapper) == window)
+ return current_global;
+
+ // Otherwise, return the global object associated with this frame.
+ 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();
+}
+
+
+// Create the utility context for holding JavaScript functions used internally
+// which are not visible to JavaScript executing on the page.
+void V8Proxy::CreateUtilityContext() {
+ ASSERT(m_utilityContext.IsEmpty());
+
+ v8::HandleScope scope;
+ v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
+ m_utilityContext = v8::Context::New(NULL, global_template);
+ v8::Context::Scope context_scope(m_utilityContext);
+
+ // Compile JavaScript function for retrieving the source line of the top
+ // JavaScript stack frame.
+ static const char* frame_source_line_source =
+ "function frame_source_line(exec_state) {"
+ " return exec_state.frame(0).sourceLine();"
+ "}";
+ v8::Script::Compile(v8::String::New(frame_source_line_source))->Run();
+
+ // Compile JavaScript function for retrieving the source name of the top
+ // JavaScript stack frame.
+ static const char* frame_source_name_source =
+ "function frame_source_name(exec_state) {"
+ " var frame = exec_state.frame(0);"
+ " if (frame.func().resolved() && "
+ " frame.func().script() && "
+ " frame.func().script().name()) {"
+ " return frame.func().script().name();"
+ " }"
+ "}";
+ v8::Script::Compile(v8::String::New(frame_source_name_source))->Run();
+}
+
+
+int V8Proxy::GetSourceLineNumber() {
+ v8::HandleScope scope;
+ v8::Handle<v8::Context> utility_context = V8Proxy::GetUtilityContext();
+ if (utility_context.IsEmpty()) {
+ return 0;
+ }
+ v8::Context::Scope context_scope(utility_context);
+ v8::Handle<v8::Function> frame_source_line;
+ frame_source_line = v8::Local<v8::Function>::Cast(
+ utility_context->Global()->Get(v8::String::New("frame_source_line")));
+ if (frame_source_line.IsEmpty()) {
+ return 0;
+ }
+ v8::Handle<v8::Value> result = v8::Debug::Call(frame_source_line);
+ if (result.IsEmpty()) {
+ return 0;
+ }
+ return result->Int32Value();
+}
+
+
+String V8Proxy::GetSourceName() {
+ v8::HandleScope scope;
+ v8::Handle<v8::Context> utility_context = GetUtilityContext();
+ if (utility_context.IsEmpty()) {
+ return String();
+ }
+ v8::Context::Scope context_scope(utility_context);
+ v8::Handle<v8::Function> frame_source_name;
+ frame_source_name = v8::Local<v8::Function>::Cast(
+ utility_context->Global()->Get(v8::String::New("frame_source_name")));
+ if (frame_source_name.IsEmpty()) {
+ return String();
+ }
+ return ToWebCoreString(v8::Debug::Call(frame_source_name));
+}
+
+void V8Proxy::RegisterExtension(v8::Extension* extension,
+ const String& schemeRestriction) {
+ v8::RegisterExtension(extension);
+ V8ExtensionInfo info = {schemeRestriction, extension};
+ m_extensions.push_back(info);
+}
+
+bool V8Proxy::SetContextDebugId(int debug_id) {
+ ASSERT(debug_id > 0);
+ if (m_context.IsEmpty()) {
+ return false;
+ }
+ v8::HandleScope scope;
+ if (!m_context->GetData()->IsUndefined()) {
+ return false;
+ }
+
+ v8::Handle<v8::Object> context_data = v8::Object::New();
+ context_data->Set(v8::String::New(kContextDebugDataType),
+ v8::String::New("page"));
+ context_data->Set(v8::String::New(kContextDebugDataValue),
+ v8::Integer::New(debug_id));
+ m_context->SetData(context_data);
+ return true;
+}
+
+// static
+int V8Proxy::GetContextDebugId(v8::Handle<v8::Context> context) {
+ v8::HandleScope scope;
+ if (!context->GetData()->IsObject()) {
+ return -1;
+ }
+ v8::Handle<v8::Value> data = context->GetData()->ToObject()->Get(
+ v8::String::New(kContextDebugDataValue));
+ return data->IsInt32() ? data->Int32Value() : -1;
+}
+
+} // 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..fbb74f3
--- /dev/null
+++ b/webkit/port/bindings/v8/v8_proxy.h
@@ -0,0 +1,673 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_PROXY_H__
+#define V8_PROXY_H__
+
+#include <v8.h>
+#include "v8_utility.h"
+#include "ChromiumBridge.h"
+#include "Node.h"
+#include "NodeFilter.h"
+#include "PlatformString.h" // for WebCore::String
+#include "ScriptSourceCode.h" // for WebCore::ScriptSourceCode
+#include "SecurityOrigin.h" // for WebCore::SecurityOrigin
+#include "V8CustomBinding.h"
+#include "V8DOMMap.h"
+#include "V8EventListenerList.h"
+#include "V8Index.h"
+#include <wtf/Assertions.h>
+#include <wtf/PassRefPtr.h> // so generated bindings don't have to
+#include <wtf/Vector.h>
+
+#include <iterator>
+#include <list>
+
+#ifdef ENABLE_DOM_STATS_COUNTERS
+#define INC_STATS(name) ChromiumBridge::incrementStatsCounter(name)
+#else
+#define INC_STATS(name)
+#endif
+
+// FIXME: Remove the following hack when we replace all references to GetDOMObjectMap.
+#define GetDOMObjectMap getDOMObjectMap
+
+namespace WebCore {
+
+class CSSStyleDeclaration;
+class ClientRectList;
+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 StyleSheetList;
+class CSSValue;
+class CSSRule;
+class CSSRuleList;
+class CSSValueList;
+class NodeFilter;
+class ScriptExecutionContext;
+
+#if ENABLE(DOM_STORAGE)
+class Storage;
+class StorageEvent;
+#endif
+
+#if ENABLE(SVG)
+class SVGElementInstance;
+#endif
+
+class V8EventListener;
+class V8ObjectEventListener;
+
+
+// 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(SCRIPTINSTANCE) \
+ V(SCRIPTVALUE)
+
+
+// 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
+
+// The following Batch structs and methods are used for setting multiple
+// properties on an ObjectTemplate, used from the generated bindings
+// initialization (ConfigureXXXTemplate). This greatly reduces the binary
+// size by moving from code driven setup to data table driven setup.
+
+// BatchedAttribute translates into calls to SetAccessor() on either the
+// instance or the prototype ObjectTemplate, based on |on_proto|.
+struct BatchedAttribute {
+ const char* const name;
+ v8::AccessorGetter getter;
+ v8::AccessorSetter setter;
+ V8ClassIndex::V8WrapperType data;
+ v8::AccessControl settings;
+ v8::PropertyAttribute attribute;
+ bool on_proto;
+};
+
+void BatchConfigureAttributes(v8::Handle<v8::ObjectTemplate> inst,
+ v8::Handle<v8::ObjectTemplate> proto,
+ const BatchedAttribute* attrs,
+ size_t num_attrs);
+
+// BatchedConstant translates into calls to Set() for setting up an object's
+// constants. It sets the constant on both the FunctionTemplate |desc| and the
+// ObjectTemplate |proto|. PropertyAttributes is always ReadOnly.
+struct BatchedConstant {
+ const char* const name;
+ int value;
+};
+
+void BatchConfigureConstants(v8::Handle<v8::FunctionTemplate> desc,
+ v8::Handle<v8::ObjectTemplate> proto,
+ const BatchedConstant* consts,
+ size_t num_consts);
+
+const int kMaxRecursionDepth = 20;
+
+// Information about an extension that is registered for use with V8. If scheme
+// is non-empty, it contains the URL scheme the extension should be used with.
+// Otherwise, the extension is used with all schemes.
+struct V8ExtensionInfo {
+ String scheme;
+ v8::Extension* extension;
+};
+typedef std::list<V8ExtensionInfo> V8ExtensionList;
+
+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();
+
+ Frame* frame() { return m_frame; }
+
+ // Clear page-specific data, but keep the global object identify.
+ void clearForNavigation();
+
+ // Clear page-specific data before shutting down the proxy object.
+ void clearForClose();
+
+ // Update document object of the frame.
+ void updateDocument();
+
+ // Update the security origin of a document
+ // (e.g., after setting docoument.domain).
+ void updateSecurityOrigin();
+
+ // Destroy the global object.
+ void DestroyGlobal();
+
+ // 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();
+
+ // Find/Create/Remove event listener wrappers.
+ PassRefPtr<V8EventListener> FindV8EventListener(v8::Local<v8::Value> listener,
+ bool html);
+ PassRefPtr<V8EventListener> FindOrCreateV8EventListener(v8::Local<v8::Value> listener,
+ bool html);
+
+ PassRefPtr<V8EventListener> FindObjectEventListener(v8::Local<v8::Value> listener,
+ bool html);
+ PassRefPtr<V8EventListener> FindOrCreateObjectEventListener(v8::Local<v8::Value> listener,
+ bool html);
+
+ void RemoveV8EventListener(V8EventListener* listener);
+ void RemoveObjectEventListener(V8ObjectEventListener* listener);
+
+ // Protect/Unprotect JS wrappers of a DOM object.
+ static void GCProtect(void* dom_object);
+ static void GCUnprotect(void* dom_object);
+
+#if ENABLE(SVG)
+ 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 JavaScript in a new isolated world. The script gets its own
+ // global scope, its own prototypes for intrinsic JavaScript objects (String,
+ // Array, and so-on), and its own wrappers for all DOM nodes and DOM
+ // constructors.
+ void evaluateInNewWorld(const Vector<ScriptSourceCode>& sources);
+
+ // Evaluate JavaScript in a new context. The script gets its own global scope
+ // and its own prototypes for intrinsic JavaScript objects (String, Array,
+ // and so-on). It shares the wrappers for all DOM nodes and DOM constructors.
+ void evaluateInNewContext(const Vector<ScriptSourceCode>& sources);
+
+ // 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 ScriptSourceCode& source,
+ 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[]);
+
+ // Call the function as constructor with the given arguments.
+ v8::Local<v8::Value> NewInstance(v8::Handle<v8::Function> constructor,
+ int argc,
+ v8::Handle<v8::Value> argv[]);
+
+ // Returns the dom constructor function for the given node type.
+ v8::Local<v8::Function> GetConstructor(V8ClassIndex::V8WrapperType type);
+
+ // To create JS Wrapper objects, we create a cache of a 'boiler plate'
+ // object, and then simply Clone that object each time we need a new one.
+ // This is faster than going through the full object creation process.
+ v8::Local<v8::Object> CreateWrapperFromCache(V8ClassIndex::V8WrapperType type);
+
+ // Returns the window object of the currently executing context.
+ static DOMWindow* retrieveWindow();
+ // Returns the window object associated with a context.
+ static DOMWindow* retrieveWindow(v8::Handle<v8::Context> context);
+ // Returns V8Proxy object of the currently executing context.
+ static V8Proxy* retrieve();
+ // Returns V8Proxy object associated with a frame.
+ static V8Proxy* retrieve(Frame* frame);
+ // Returns V8Proxy object associated with a script execution context.
+ static V8Proxy* retrieve(ScriptExecutionContext* context);
+
+ // 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
+ // a context.
+ static Frame* retrieveFrame(v8::Handle<v8::Context> context);
+
+
+ // The three functions below retrieve WebFrame instances relating the
+ // currently executing JavaScript. Since JavaScript can make function calls
+ // across frames, though, we need to be more precise.
+ //
+ // For example, imagine that a JS function in frame A calls a function in
+ // frame B, which calls native code, which wants to know what the 'active'
+ // frame is.
+ //
+ // The 'entered context' is the context where execution first entered the
+ // script engine; the context that is at the bottom of the JS function stack.
+ // RetrieveFrameForEnteredContext() would return Frame A in our example.
+ // This frame is often referred to as the "dynamic global object."
+ //
+ // The 'current context' is the context the JS engine is currently inside of;
+ // the context that is at the top of the JS function stack.
+ // RetrieveFrameForCurrentContext() would return Frame B in our example.
+ // This frame is often referred to as the "lexical global object."
+ //
+ // Finally, the 'calling context' is the context one below the current
+ // context on the JS function stack. For example, if function f calls
+ // function g, then the calling context will be the context associated with
+ // f. This context is commonly used by DOM security checks because they want
+ // to know who called them.
+ //
+ // If you are unsure which of these functions to use, ask abarth.
+ //
+ // NOTE: These cannot be declared as inline function, because VS complains at
+ // linking time.
+ static Frame* retrieveFrameForEnteredContext();
+ static Frame* retrieveFrameForCurrentContext();
+ static Frame* retrieveFrameForCallingContext();
+
+ // 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();
+
+ // Check if the active execution context can access the target frame.
+ static bool CanAccessFrame(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);
+
+ static v8::Handle<v8::Value> CheckNewLegal(const v8::Arguments& args);
+
+ // Create a V8 wrapper for a C pointer
+ static v8::Handle<v8::Value> WrapCPointer(void* cptr) {
+ // Represent void* as int
+ int addr = reinterpret_cast<int>(cptr);
+ ASSERT((addr & 0x01) == 0); // the address must be aligned.
+ return v8::Integer::New(addr >> 1);
+ }
+
+ // 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);
+
+#ifndef NDEBUG
+ // Checks if a v8 value can be a DOM wrapper
+ static bool MaybeDOMWrapper(v8::Handle<v8::Value> value);
+#endif
+
+ // Sets contents of a DOM wrapper.
+ static void 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) {
+ ASSERT(MaybeDOMWrapper(object));
+ v8::Handle<v8::Value> ptr =
+ v8::Handle<v8::Object>::Cast(object)->GetInternalField(
+ V8Custom::kDOMWrapperObjectIndex);
+ return ExtractCPointer<C>(ptr);
+ }
+
+ // A help function extract a node type pointer from a DOM wrapper.
+ // Wrapped pointer must be cast to Node* first.
+ static void* DOMWrapperToNodeHelper(v8::Handle<v8::Value> value);
+
+ template <class C>
+ static C* DOMWrapperToNode(v8::Handle<v8::Value> value) {
+ return static_cast<C*>(DOMWrapperToNodeHelper(value));
+ }
+
+ template<typename T>
+ static v8::Handle<v8::Value> ToV8Object(V8ClassIndex::V8WrapperType type, PassRefPtr<T> imp)
+ {
+ return ToV8Object(type, imp.get());
+ }
+ static v8::Handle<v8::Value> ToV8Object(V8ClassIndex::V8WrapperType type,
+ void* imp);
+ // Fast-path for Node objects.
+ static v8::Handle<v8::Value> NodeToV8Object(Node* node);
+
+ 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 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) {
+ if (!IsDOMEventWrapper(jsevent)) return 0;
+ 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.
+ static v8::Handle<v8::Value> DOMImplementationToV8Object(
+ DOMImplementation* impl);
+
+ // Wrap JS node filter in C++
+ static PassRefPtr<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);
+
+ // Checks whether a DOM object has a JS wrapper.
+ static bool DOMObjectHasJSWrapper(void* obj);
+ // Set JS wrapper of a DOM object, the caller in charge of increase ref.
+ static void SetJSWrapperForDOMObject(void* obj,
+ v8::Persistent<v8::Object> wrapper);
+ static void SetJSWrapperForActiveDOMObject(void* obj,
+ v8::Persistent<v8::Object> wrapper);
+ static void SetJSWrapperForDOMNode(Node* node,
+ v8::Persistent<v8::Object> wrapper);
+
+ // 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
+
+ // Check whether a V8 value is a wrapper of type |classType|.
+ static bool IsWrapperOfType(v8::Handle<v8::Value> obj,
+ V8ClassIndex::V8WrapperType classType);
+
+ // Function for retrieving the line number and source name for the top
+ // JavaScript stack frame.
+ static int GetSourceLineNumber();
+ static String GetSourceName();
+
+
+ // Returns a local handle of the context.
+ v8::Local<v8::Context> GetContext() {
+ return v8::Local<v8::Context>::New(m_context);
+ }
+
+ bool SetContextDebugId(int id);
+ static int GetContextDebugId(v8::Handle<v8::Context> context);
+
+ // Registers an extension to be available on webpages with a particular scheme
+ // If the scheme argument is empty, the extension is available on all pages.
+ // Will only affect v8 contexts initialized after this call. Takes ownership
+ // of the v8::Extension object passed.
+ static void RegisterExtension(v8::Extension* extension,
+ const String& schemeRestriction);
+
+ static void* ToSVGPODTypeImpl(V8ClassIndex::V8WrapperType type,
+ v8::Handle<v8::Value> object);
+
+ // TODO(abarth): Separate these concerns from V8Proxy?
+ v8::Persistent<v8::Context> createNewContext(v8::Handle<v8::Object> global);
+ bool installDOMWindow(v8::Handle<v8::Context> context, DOMWindow* window);
+
+ private:
+ static const char* kContextDebugDataType;
+ static const char* kContextDebugDataValue;
+
+ void InitContextIfNeeded();
+ void DisconnectEventListeners();
+ void SetSecurityToken();
+ void ClearDocumentWrapper();
+ void UpdateDocumentWrapper(v8::Handle<v8::Value> wrapper);
+
+ // The JavaScript wrapper for the document object is cached on the global
+ // object for fast access. UpdateDocumentWrapperCache sets the wrapper
+ // for the current document on the global object. ClearDocumentWrapperCache
+ // deletes the document wrapper from the global object.
+ void UpdateDocumentWrapperCache();
+ void ClearDocumentWrapperCache();
+
+ // Dispose global handles of m_contexts and friends.
+ void DisposeContextHandles();
+
+ static bool CanAccessPrivate(DOMWindow* target);
+
+ // Check whether a V8 value is a DOM Event wrapper
+ static bool IsDOMEventWrapper(v8::Handle<v8::Value> obj);
+
+ static void* ToNativeObjectImpl(V8ClassIndex::V8WrapperType type,
+ v8::Handle<v8::Value> object);
+
+ // Take C pointer out of a v8 wrapper
+ static void* ExtractCPointerImpl(v8::Handle<v8::Value> obj) {
+ ASSERT(obj->IsNumber());
+ int addr = obj->Int32Value();
+ return reinterpret_cast<void*>(addr << 1);
+ }
+
+
+ static v8::Handle<v8::Value> StyleSheetToV8Object(StyleSheet* sheet);
+ static v8::Handle<v8::Value> CSSValueToV8Object(CSSValue* value);
+ static v8::Handle<v8::Value> CSSRuleToV8Object(CSSRule* rule);
+ // Returns the JS wrapper of a window object, initializes the environment
+ // of the window frame if needed.
+ static v8::Handle<v8::Value> WindowToV8Object(DOMWindow* window);
+
+#if ENABLE(SVG)
+ static v8::Handle<v8::Value> SVGElementInstanceToV8Object(
+ SVGElementInstance* instance);
+ static v8::Handle<v8::Value> SVGObjectWithContextToV8Object(
+ V8ClassIndex::V8WrapperType type, void* object);
+#endif
+
+ // Set hidden references in a DOMWindow object of a frame.
+ static void SetHiddenWindowReference(Frame* frame,
+ const int internal_index,
+ v8::Handle<v8::Object> jsobj);
+
+ static V8ClassIndex::V8WrapperType GetHTMLElementType(HTMLElement* elm);
+
+ // The first parameter, desc_type, specifies the function descriptor
+ // used to create JS object. The second parameter, cptr_type, specifies
+ // the type of third parameter, impl, for type casting.
+ // For example, a HTML element has HTMLELEMENT desc_type, but always
+ // use NODE as cptr_type. JS wrapper stores cptr_type and impl as
+ // internal fields.
+ static v8::Local<v8::Object> InstantiateV8Object(
+ V8ClassIndex::V8WrapperType desc_type,
+ V8ClassIndex::V8WrapperType cptr_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
+
+ // Create and populate the utility context.
+ static void CreateUtilityContext();
+
+ // Returns a local handle of the utility context.
+ static v8::Local<v8::Context> GetUtilityContext() {
+ if (m_utilityContext.IsEmpty()) {
+ CreateUtilityContext();
+ }
+ return v8::Local<v8::Context>::New(m_utilityContext);
+ }
+
+ Frame* m_frame;
+
+ v8::Persistent<v8::Context> m_context;
+ // For each possible type of wrapper, we keep a boilerplate object.
+ // The boilerplate is used to create additional wrappers of the same type.
+ // We keep a single persistent handle to an array of the activated
+ // boilerplates.
+ v8::Persistent<v8::Array> m_wrapper_boilerplates;
+ v8::Persistent<v8::Value> m_object_prototype;
+
+ v8::Persistent<v8::Object> m_global;
+ v8::Persistent<v8::Value> m_document;
+
+ // Utility context holding JavaScript functions used internally.
+ static v8::Persistent<v8::Context> m_utilityContext;
+
+ 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;
+
+ // List of extensions registered with the context.
+ static V8ExtensionList m_extensions;
+};
+
+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();
+ }
+
+
+ // Note: it's OK to let this RefPtr go out of scope because we also call
+ // SetDOMWrapper(), which effectively holds a reference to obj.
+ RefPtr<T> obj = T::create();
+ V8Proxy::SetDOMWrapper(args.Holder(), tag, obj.get());
+ obj->ref();
+ V8Proxy::SetJSWrapperForDOMObject(
+ obj.get(), v8::Persistent<v8::Object>::New(args.Holder()));
+ return args.Holder();
+}
+
+} // 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..a7c3325
--- /dev/null
+++ b/webkit/port/bindings/v8/v8_utility.h
@@ -0,0 +1,68 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_UTILITY_H__
+#define V8_UTILITY_H__
+
+#include "V8Utilities.h"
+
+// To break a cycle dependency during upstreaming this block of code,
+// ifdefing it out based on this #define.
+//
+// TODO(ajwong): After https://bugs.webkit.org/show_bug.cgi?id=25595
+// lands and is rolled down into chromium, migrate all headaers to use
+// the code in V8Utilities.h directly, and then, remove this code.
+#ifndef V8UTILITIES_DEFINED
+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 // V8UTILITIES_DEFINED
+
+#endif // V8_UTILITY_H__
diff --git a/webkit/tools/test_shell/test_shell.cc b/webkit/tools/test_shell/test_shell.cc
index 13a5e89..caa450d 100644
--- a/webkit/tools/test_shell/test_shell.cc
+++ b/webkit/tools/test_shell/test_shell.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "V8Proxy.h"
+#include "v8_proxy.h"
#undef LOG
#include "webkit/tools/test_shell/test_shell.h"
@@ -183,7 +183,7 @@ void TestShell::Dump(TestShell* shell) {
if ((shell == NULL) || ((params = shell->test_params()) == NULL))
return;
- WebCore::V8Proxy::processConsoleMessages();
+ WebCore::V8Proxy::ProcessConsoleMessages();
// Echo the url in the output so we know we're not getting out of sync.
printf("#URL:%s\n", params->test_url.c_str());
diff --git a/webkit/webkit.gyp b/webkit/webkit.gyp
index ea3b0b8..598ebb3 100644
--- a/webkit/webkit.gyp
+++ b/webkit/webkit.gyp
@@ -1130,7 +1130,6 @@
'../third_party/WebKit/WebCore/bindings/v8/V8NodeFilterCondition.h',
'../third_party/WebKit/WebCore/bindings/v8/V8ObjectEventListener.cpp',
'../third_party/WebKit/WebCore/bindings/v8/V8ObjectEventListener.h',
- '../third_party/WebKit/WebCore/bindings/v8/V8Proxy.cpp',
'../third_party/WebKit/WebCore/bindings/v8/V8Proxy.h',
'../third_party/WebKit/WebCore/bindings/v8/V8Utilities.cpp',
'../third_party/WebKit/WebCore/bindings/v8/V8Utilities.h',
@@ -1170,6 +1169,9 @@
'port/bindings/v8/V8NPUtils.h',
'port/bindings/v8/V8NPObject.cpp',
'port/bindings/v8/V8NPObject.h',
+ 'port/bindings/v8/v8_proxy.cpp',
+ 'port/bindings/v8/v8_proxy.h',
+ 'port/bindings/v8/v8_utility.h',
# This list contains every .cpp, .h, .m, and .mm file in the
# subdirectories of ../third_party/WebKit/WebCore, excluding the