summaryrefslogtreecommitdiffstats
path: root/webkit/port
diff options
context:
space:
mode:
authorjianli@chromium.org <jianli@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-02-09 19:16:29 +0000
committerjianli@chromium.org <jianli@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-02-09 19:16:29 +0000
commita6309f8198825442d77f0fc9aa70c82ae5dd6d04 (patch)
tree1ff2b6257184f746d15a1c4cdd91d41e038af3bc /webkit/port
parenteb6c8c24620c8f9f8afd3523cac74f03df0cfe52 (diff)
downloadchromium_src-a6309f8198825442d77f0fc9aa70c82ae5dd6d04.zip
chromium_src-a6309f8198825442d77f0fc9aa70c82ae5dd6d04.tar.gz
chromium_src-a6309f8198825442d77f0fc9aa70c82ae5dd6d04.tar.bz2
More v8 bindings work to support executing worker and handling events in its worker context.
For now, we still execute the worker script in the same renderer process with v8 locker. It will be rerouted once we have worker process ready. Review URL: http://codereview.chromium.org/18821 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@9399 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/port')
-rw-r--r--webkit/port/DerivedSources.make2
-rw-r--r--webkit/port/bindings/scripts/CodeGeneratorV8.pm39
-rw-r--r--webkit/port/bindings/v8/ScheduledAction.h1
-rw-r--r--webkit/port/bindings/v8/V8MessagePortCustom.cpp2
-rw-r--r--webkit/port/bindings/v8/V8WorkerContextCustom.cpp224
-rw-r--r--webkit/port/bindings/v8/WorkerContextExecutionProxy.cpp358
-rw-r--r--webkit/port/bindings/v8/WorkerContextExecutionProxy.h119
-rw-r--r--webkit/port/bindings/v8/WorkerScriptController.cpp62
-rw-r--r--webkit/port/bindings/v8/WorkerScriptController.h10
-rw-r--r--webkit/port/bindings/v8/v8_custom.h14
-rw-r--r--webkit/port/bindings/v8/v8_events.cpp134
-rw-r--r--webkit/port/bindings/v8/v8_events.h57
-rw-r--r--webkit/port/bindings/v8/v8_index.cpp2
-rw-r--r--webkit/port/bindings/v8/v8_index.h4
-rw-r--r--webkit/port/bindings/v8/v8_proxy.cpp92
-rw-r--r--webkit/port/bindings/v8/v8_proxy.h5
16 files changed, 1011 insertions, 114 deletions
diff --git a/webkit/port/DerivedSources.make b/webkit/port/DerivedSources.make
index 75d28ef..71e7eee 100644
--- a/webkit/port/DerivedSources.make
+++ b/webkit/port/DerivedSources.make
@@ -899,7 +899,9 @@ all : \
V8WebKitTransitionEvent.h \
V8WheelEvent.h \
V8Worker.h \
+ V8WorkerContext.h \
V8WorkerLocation.h \
+ V8WorkerNavigator.h \
V8XMLHttpRequest.h \
V8XMLHttpRequestException.h \
V8XMLHttpRequestProgressEvent.h \
diff --git a/webkit/port/bindings/scripts/CodeGeneratorV8.pm b/webkit/port/bindings/scripts/CodeGeneratorV8.pm
index dc37a04..e16851a 100644
--- a/webkit/port/bindings/scripts/CodeGeneratorV8.pm
+++ b/webkit/port/bindings/scripts/CodeGeneratorV8.pm
@@ -413,6 +413,7 @@ END
sub GenerateConstructorGetter
{
my $implClassName = shift;
+ my $classIndex = shift;
push(@implContentDecls, <<END);
static v8::Handle<v8::Value> ${implClassName}ConstructorGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info) {
@@ -420,6 +421,10 @@ sub GenerateConstructorGetter
v8::Handle<v8::Value> data = info.Data();
ASSERT(data->IsNumber());
V8ClassIndex::V8WrapperType type = V8ClassIndex::FromInt(data->Int32Value());
+END
+
+ if ($classIndex eq "DOMWINDOW") {
+ push(@implContentDecls, <<END);
DOMWindow* window = V8Proxy::ToNativeObject<DOMWindow>(V8ClassIndex::DOMWINDOW, info.Holder());
Frame* frame = window->frame();
if (frame) {
@@ -428,7 +433,19 @@ sub GenerateConstructorGetter
// context of the DOMWindow and not in the context of the caller.
return V8Proxy::retrieve(frame)->GetConstructor(type);
}
- return V8Proxy::retrieve()->GetConstructor(type);
+END
+ }
+
+ if ($classIndex eq "WORKERCONTEXT") {
+ $implIncludes{"WorkerContextExecutionProxy.h"} = 1;
+ push(@implContentDecls, <<END);
+ return WorkerContextExecutionProxy::retrieve()->GetConstructor(type);
+END
+ } else {
+ push(@implContentDecls, " return V8Proxy::retrieve()->GetConstructor(type);");
+ }
+
+ push(@implContentDecls, <<END);
}
END
@@ -932,7 +949,12 @@ sub GenerateBatchedAttributeData
# Custom Getter and Setter
} elsif ($attrExt->{"Custom"} || $attrExt->{"V8Custom"}) {
$getter = "V8Custom::v8${customAccessor}AccessorGetter";
- $setter = "V8Custom::v8${customAccessor}AccessorSetter";
+ if ($interfaceName eq "WorkerContext" and $attrName eq "self") {
+ $setter = "0";
+ $propAttr = "v8::ReadOnly";
+ } else {
+ $setter = "V8Custom::v8${customAccessor}AccessorSetter";
+ }
# Custom Setter
} elsif ($attrExt->{"CustomSetter"}) {
@@ -1071,7 +1093,7 @@ sub GenerateImplementation
if ($attribute->signature->extendedAttributes->{"CustomSetter"}) {
$implIncludes{"v8_custom.h"} = 1;
} elsif ($attribute->signature->extendedAttributes->{"Replaceable"}) {
- $interfaceName eq "DOMWindow" || die "Replaceable attribute can only be used in DOMWindow interface!";
+ $dataNode->extendedAttributes->{"ExtendsDOMGlobalObject"} || die "Replaceable attribute can only be used in interface that defines ExtendsDOMGlobalObject attribute!";
# GenerateReplaceableAttrSetter($implClassName);
} elsif ($attribute->type !~ /^readonly/) {
GenerateNormalAttrSetter($attribute, $dataNode, $classIndex, $implClassName);
@@ -1079,7 +1101,7 @@ sub GenerateImplementation
}
if ($hasConstructors) {
- GenerateConstructorGetter($implClassName);
+ GenerateConstructorGetter($implClassName, $classIndex);
}
# Generate methods for functions.
@@ -1615,7 +1637,9 @@ sub IsWorkerClassName
{
my $class = shift;
return 1 if $class eq "V8Worker";
+ return 1 if $class eq "V8WorkerContext";
return 1 if $class eq "V8WorkerLocation";
+ return 1 if $class eq "V8WorkerNavigator";
return 0;
}
@@ -1967,6 +1991,13 @@ sub NativeToJSValue
if ($type eq "RGBColor") {
return "V8Proxy::ToV8Object(V8ClassIndex::RGBCOLOR, new RGBColor($value))";
}
+
+ if ($type eq "WorkerLocation" or $type eq "WorkerNavigator") {
+ $implIncludes{"WorkerContextExecutionProxy.h"} = 1;
+ my $classIndex = uc($type);
+
+ return "WorkerContextExecutionProxy::ToV8Object(V8ClassIndex::$classIndex, $value)";
+ }
else {
$implIncludes{"wtf/RefCounted.h"} = 1;
diff --git a/webkit/port/bindings/v8/ScheduledAction.h b/webkit/port/bindings/v8/ScheduledAction.h
index ea4be9b..19b2ec0 100644
--- a/webkit/port/bindings/v8/ScheduledAction.h
+++ b/webkit/port/bindings/v8/ScheduledAction.h
@@ -13,6 +13,7 @@ class ScheduledAction {
public:
virtual ~ScheduledAction() { }
virtual void execute(DOMWindow* window) = 0;
+ virtual void execute(ScriptExecutionContext*) {}
};
}
diff --git a/webkit/port/bindings/v8/V8MessagePortCustom.cpp b/webkit/port/bindings/v8/V8MessagePortCustom.cpp
index 0025046..81948f8 100644
--- a/webkit/port/bindings/v8/V8MessagePortCustom.cpp
+++ b/webkit/port/bindings/v8/V8MessagePortCustom.cpp
@@ -54,7 +54,7 @@ static void CreateHiddenDependency(v8::Local<v8::Object> object,
v8::Local<v8::Value> cache = object->GetInternalField(V8Custom::kMessagePortRequestCacheIndex);
if (cache->IsNull() || cache->IsUndefined()) {
cache = v8::Array::New();
- object->SetInternalField(V8Custom::kXMLHttpRequestCacheIndex, cache);
+ object->SetInternalField(V8Custom::kMessagePortRequestCacheIndex, cache);
}
v8::Local<v8::Array> cacheArray = v8::Local<v8::Array>::Cast(cache);
diff --git a/webkit/port/bindings/v8/V8WorkerContextCustom.cpp b/webkit/port/bindings/v8/V8WorkerContextCustom.cpp
new file mode 100644
index 0000000..d3c1c3a
--- /dev/null
+++ b/webkit/port/bindings/v8/V8WorkerContextCustom.cpp
@@ -0,0 +1,224 @@
+// Copyright (c) 2009, 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"
+
+#if ENABLE(WORKERS)
+
+#include "v8_binding.h"
+#include "v8_custom.h"
+#include "v8_events.h"
+#include "v8_proxy.h"
+#include "WorkerContextExecutionProxy.h"
+
+#include "V8Document.h"
+#include "V8HTMLDocument.h"
+
+#include "ExceptionCode.h"
+#include "MessagePort.h"
+#include "WorkerContext.h"
+
+namespace WebCore {
+
+// TODO(mbelshe) - merge these with XHR's CreateHiddenXHRDependency
+
+// Use an array to hold dependents. It works like a ref-counted scheme.
+// A value can be added more than once to the xhr object.
+static void CreateHiddenDependency(v8::Local<v8::Object> object,
+ v8::Local<v8::Value> value) {
+ ASSERT(V8Proxy::GetDOMWrapperType(object) == V8ClassIndex::WORKERCONTEXT);
+ v8::Local<v8::Value> cache =
+ object->GetInternalField(V8Custom::kWorkerContextRequestCacheIndex);
+ if (cache->IsNull() || cache->IsUndefined()) {
+ cache = v8::Array::New();
+ object->SetInternalField(V8Custom::kWorkerContextRequestCacheIndex, cache);
+ }
+
+ v8::Local<v8::Array> cache_array = v8::Local<v8::Array>::Cast(cache);
+ cache_array->Set(v8::Integer::New(cache_array->Length()), value);
+}
+
+static void RemoveHiddenDependency(v8::Local<v8::Object> object,
+ v8::Local<v8::Value> value) {
+ ASSERT(V8Proxy::GetDOMWrapperType(object) == V8ClassIndex::WORKERCONTEXT);
+ v8::Local<v8::Value> cache =
+ object->GetInternalField(V8Custom::kWorkerContextRequestCacheIndex);
+ ASSERT(cache->IsArray());
+ v8::Local<v8::Array> cache_array = v8::Local<v8::Array>::Cast(cache);
+ for (int i = cache_array->Length() - 1; i >= 0; i--) {
+ v8::Local<v8::Value> cached = cache_array->Get(v8::Integer::New(i));
+ if (cached->StrictEquals(value)) {
+ cache_array->Delete(i);
+ return;
+ }
+ }
+
+ // We should only get here if we try to remove an event listener that was
+ // never added.
+}
+
+ACCESSOR_GETTER(WorkerContextSelf) {
+ INC_STATS(L"DOM.WorkerContext.self._get");
+ WorkerContext* imp = V8Proxy::ToNativeObject<WorkerContext>(
+ V8ClassIndex::WORKERCONTEXT, info.Holder());
+ return V8Proxy::ToV8Object(V8ClassIndex::WORKERCONTEXT, imp);
+}
+
+ACCESSOR_GETTER(WorkerContextOnmessage) {
+ INC_STATS(L"DOM.WorkerContext.onmessage._get");
+ WorkerContext* imp = V8Proxy::ToNativeObject<WorkerContext>(
+ V8ClassIndex::WORKERCONTEXT, info.Holder());
+ if (imp->onmessage()) {
+ V8WorkerContextEventListener* listener =
+ static_cast<V8WorkerContextEventListener*>(imp->onmessage());
+ v8::Local<v8::Object> v8_listener = listener->GetListenerObject();
+ return v8_listener;
+ }
+ return v8::Undefined();
+}
+
+ACCESSOR_SETTER(WorkerContextOnmessage) {
+ INC_STATS(L"DOM.WorkerContext.onmessage._set");
+ WorkerContext* imp = V8Proxy::ToNativeObject<WorkerContext>(
+ V8ClassIndex::WORKERCONTEXT, info.Holder());
+ V8WorkerContextEventListener* old_listener =
+ static_cast<V8WorkerContextEventListener*>(imp->onmessage());
+ if (value->IsNull()) {
+ if (imp->onmessage()) {
+ v8::Local<v8::Object> old_v8_listener = old_listener->GetListenerObject();
+ RemoveHiddenDependency(info.Holder(), old_v8_listener);
+ }
+
+ // Clear the listener
+ imp->setOnmessage(0);
+
+ } else {
+ RefPtr<V8EventListener> listener =
+ imp->script()->proxy()->FindOrCreateEventListener(
+ v8::Local<v8::Object>::Cast(value), false, false);
+ if (listener) {
+ if (old_listener) {
+ v8::Local<v8::Object> old_v8_listener =
+ old_listener->GetListenerObject();
+ RemoveHiddenDependency(info.Holder(), old_v8_listener);
+ }
+
+ imp->setOnmessage(listener);
+ CreateHiddenDependency(info.Holder(), value);
+ }
+ }
+}
+
+v8::Handle<v8::Value> SetTimeoutOrInterval(const v8::Arguments& args,
+ bool singleShot) {
+ WorkerContext* imp = V8Proxy::ToNativeObject<WorkerContext>(
+ V8ClassIndex::WORKERCONTEXT, args.Holder());
+
+ int delay = ToInt32(args[1]);
+
+ notImplemented();
+
+ return v8::Undefined();
+}
+
+v8::Handle<v8::Value> ClearTimeoutOrInterval(const v8::Arguments& args) {
+ WorkerContext* imp = V8Proxy::ToNativeObject<WorkerContext>(
+ V8ClassIndex::WORKERCONTEXT, args.Holder());
+
+ bool ok = false;
+ int tid = ToInt32(args[0], ok);
+ if (ok) {
+ imp->removeTimeout(tid);
+ }
+
+ return v8::Undefined();
+}
+
+CALLBACK_FUNC_DECL(WorkerContextSetTimeout) {
+ INC_STATS(L"DOM.WorkerContext.setTimeout()");
+ return SetTimeoutOrInterval(args, true);
+}
+
+CALLBACK_FUNC_DECL(WorkerContextClearTimeout) {
+ INC_STATS(L"DOM.WorkerContext.clearTimeout()");
+ return ClearTimeoutOrInterval(args);
+}
+
+CALLBACK_FUNC_DECL(WorkerContextSetInterval) {
+ INC_STATS(L"DOM.WorkerContext.setInterval()");
+ return SetTimeoutOrInterval(args, false);
+}
+
+CALLBACK_FUNC_DECL(WorkerContextClearInterval) {
+ INC_STATS(L"DOM.WorkerContext.clearInterval()");
+ return ClearTimeoutOrInterval(args);
+}
+
+CALLBACK_FUNC_DECL(WorkerContextAddEventListener) {
+ INC_STATS(L"DOM.WorkerContext.addEventListener()");
+ WorkerContext* imp = V8Proxy::ToNativeObject<WorkerContext>(
+ V8ClassIndex::WORKERCONTEXT, args.Holder());
+
+ RefPtr<V8EventListener> listener =
+ imp->script()->proxy()->FindOrCreateEventListener(
+ v8::Local<v8::Object>::Cast(args[1]), false, false);
+
+ if (listener) {
+ String type = ToWebCoreString(args[0]);
+ bool useCapture = args[2]->BooleanValue();
+ imp->addEventListener(type, listener, useCapture);
+
+ CreateHiddenDependency(args.Holder(), args[1]);
+ }
+ return v8::Undefined();
+}
+
+CALLBACK_FUNC_DECL(WorkerContextRemoveEventListener) {
+ INC_STATS(L"DOM.WorkerContext.removeEventListener()");
+ WorkerContext* imp = V8Proxy::ToNativeObject<WorkerContext>(
+ V8ClassIndex::WORKERCONTEXT, args.Holder());
+ WorkerContextExecutionProxy* proxy = imp->script()->proxy();
+
+ RefPtr<V8EventListener> listener = proxy->FindOrCreateEventListener(
+ v8::Local<v8::Object>::Cast(args[1]), false, true);
+
+ if (listener) {
+ String type = ToWebCoreString(args[0]);
+ bool useCapture = args[2]->BooleanValue();
+ imp->removeEventListener(type, listener.get(), useCapture);
+
+ RemoveHiddenDependency(args.Holder(), args[1]);
+ }
+
+ return v8::Undefined();
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WORKERS)
diff --git a/webkit/port/bindings/v8/WorkerContextExecutionProxy.cpp b/webkit/port/bindings/v8/WorkerContextExecutionProxy.cpp
new file mode 100644
index 0000000..496dce3
--- /dev/null
+++ b/webkit/port/bindings/v8/WorkerContextExecutionProxy.cpp
@@ -0,0 +1,358 @@
+// Copyright (c) 2009, 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"
+
+#if ENABLE(WORKERS)
+
+#include "WorkerContextExecutionProxy.h"
+
+#include "v8_binding.h"
+#include "v8_events.h"
+#include "v8_index.h"
+#include "v8_proxy.h"
+#include "WorkerContext.h"
+#include "WorkerLocation.h"
+#include "WorkerNavigator.h"
+#include "WorkerScriptController.h"
+
+namespace WebCore {
+
+WorkerContextExecutionProxy::WorkerContextExecutionProxy(
+ WorkerContext* workerContext)
+ : m_workerContext(workerContext),
+ m_recursion(0) {
+}
+
+WorkerContextExecutionProxy::~WorkerContextExecutionProxy() {
+ Dispose();
+}
+
+void WorkerContextExecutionProxy::Dispose() {
+ // Disconnect all event listeners.
+ for (EventListenerList::iterator iter = m_listeners.begin();
+ iter != m_listeners.end();
+ ++iter) {
+ static_cast<V8WorkerContextEventListener*>(*iter)->disconnect();
+ }
+ m_listeners.clear();
+
+ // Detach all events from their JS wrappers.
+ for (EventSet::iterator iter = m_events.begin();
+ iter != m_events.end();
+ ++iter) {
+ Event* event = *iter;
+ if (ForgetV8EventObject(event)) {
+ event->deref();
+ }
+ }
+ m_events.clear();
+
+ // Dispose the context.
+ if (!m_context.IsEmpty()) {
+ m_context.Dispose();
+ m_context.Clear();
+ }
+}
+
+WorkerContextExecutionProxy* WorkerContextExecutionProxy::retrieve() {
+ v8::Handle<v8::Context> context = v8::Context::GetCurrent();
+ v8::Handle<v8::Object> global = context->Global();
+ global = V8Proxy::LookupDOMWrapper(V8ClassIndex::WORKERCONTEXT, global);
+ ASSERT(!global.IsEmpty());
+ WorkerContext* worker_context =
+ V8Proxy::ToNativeObject<WorkerContext>(V8ClassIndex::WORKERCONTEXT,
+ global);
+ return worker_context->script()->proxy();
+}
+
+void WorkerContextExecutionProxy::InitContextIfNeeded() {
+ // Bail out if the context has already been initialized.
+ if (!m_context.IsEmpty()) {
+ return;
+ }
+
+ // Create a new environment
+ v8::Persistent<v8::ObjectTemplate> global_template;
+ m_context = v8::Context::New(NULL, global_template);
+
+ // Starting from now, use local context only.
+ v8::Local<v8::Context> context = v8::Local<v8::Context>::New(m_context);
+ v8::Context::Scope scope(context);
+
+ // Allocate strings used during initialization.
+ v8::Handle<v8::String> implicit_proto_string = v8::String::New("__proto__");
+
+ // Create a new JS object and use it as the prototype for the
+ // shadow global object.
+ v8::Handle<v8::Function> worker_context_constructor =
+ GetConstructor(V8ClassIndex::WORKERCONTEXT);
+ v8::Local<v8::Object> js_worker_context =
+ SafeAllocation::NewInstance(worker_context_constructor);
+ // Bail out if allocation failed.
+ if (js_worker_context.IsEmpty()) {
+ Dispose();
+ return;
+ }
+
+ // Wrap the object.
+ V8Proxy::SetDOMWrapper(js_worker_context,
+ V8ClassIndex::ToInt(V8ClassIndex::WORKERCONTEXT),
+ m_workerContext);
+
+ V8Proxy::SetJSWrapperForDOMObject(m_workerContext,
+ v8::Persistent<v8::Object>::New(js_worker_context));
+
+ // Insert the object instance as the prototype of the shadow object.
+ v8::Handle<v8::Object> v8_global = m_context->Global();
+ v8_global->Set(implicit_proto_string, js_worker_context);
+}
+
+v8::Local<v8::Function> WorkerContextExecutionProxy::GetConstructor(
+ V8ClassIndex::V8WrapperType t) {
+ // 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 = V8Proxy::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>();
+ }
+
+ return value;
+}
+
+v8::Handle<v8::Value> WorkerContextExecutionProxy::ToV8Object(
+ V8ClassIndex::V8WrapperType type, void* imp) {
+ if (!imp) return v8::Null();
+
+ // Non DOM node
+ v8::Persistent<v8::Object> result = 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) {
+ case V8ClassIndex::WORKERLOCATION:
+ static_cast<WorkerLocation*>(imp)->ref();
+ break;
+ case V8ClassIndex::WORKERNAVIGATOR:
+ static_cast<WorkerNavigator*>(imp)->ref();
+ break;
+ default:
+ ASSERT(false);
+ }
+ result = v8::Persistent<v8::Object>::New(v8obj);
+ V8Proxy::SetJSWrapperForDOMObject(imp, result);
+ }
+ }
+ return result;
+}
+
+v8::Handle<v8::Value> WorkerContextExecutionProxy::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->isMessageEvent())
+ type = V8ClassIndex::MESSAGEEVENT;
+
+ 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
+ V8Proxy::SetJSWrapperForDOMObject(
+ event, v8::Persistent<v8::Object>::New(result));
+
+ return result;
+}
+
+// A JS object of type EventTarget in the worker context can only be
+// WorkerContext.
+v8::Handle<v8::Value> WorkerContextExecutionProxy::EventTargetToV8Object(
+ EventTarget* target) {
+ if (!target)
+ return v8::Null();
+
+ WorkerContext* worker_context = target->toWorkerContext();
+ if (worker_context)
+ return WorkerContextToV8Object(worker_context);
+
+ ASSERT(0);
+ return v8::Handle<v8::Value>();
+}
+
+v8::Handle<v8::Value> WorkerContextExecutionProxy::WorkerContextToV8Object(
+ WorkerContext* worker_context) {
+ if (!worker_context) return v8::Null();
+
+ v8::Handle<v8::Context> context =
+ worker_context->script()->proxy()->GetContext();
+
+ v8::Handle<v8::Object> global = context->Global();
+ ASSERT(!global.IsEmpty());
+ return global;
+}
+
+v8::Local<v8::Object> WorkerContextExecutionProxy::InstantiateV8Object(
+ V8ClassIndex::V8WrapperType desc_type,
+ V8ClassIndex::V8WrapperType cptr_type,
+ void* imp) {
+ v8::Local<v8::Function> function;
+ WorkerContextExecutionProxy* proxy = retrieve();
+ if (proxy) {
+ function = proxy->GetConstructor(desc_type);
+ } else {
+ function = V8Proxy::GetTemplate(desc_type)->GetFunction();
+ }
+ v8::Local<v8::Object> instance = SafeAllocation::NewInstance(function);
+ if (!instance.IsEmpty()) {
+ // Avoid setting the DOM wrapper for failed allocations.
+ V8Proxy::SetDOMWrapper(instance, V8ClassIndex::ToInt(cptr_type), imp);
+ }
+ return instance;
+}
+
+bool WorkerContextExecutionProxy::ForgetV8EventObject(Event* event) {
+ if (GetDOMObjectMap().contains(event)) {
+ GetDOMObjectMap().forget(event);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+v8::Local<v8::Value> WorkerContextExecutionProxy::Evaluate(
+ const String& str, const String& file_name, int base_line) {
+ v8::HandleScope hs;
+
+ InitContextIfNeeded();
+ v8::Context::Scope scope(m_context);
+
+ v8::Local<v8::String> code = v8ExternalString(str);
+ v8::Handle<v8::Script> script = V8Proxy::CompileScript(code,
+ file_name,
+ base_line);
+ return RunScript(script);
+}
+
+v8::Local<v8::Value> WorkerContextExecutionProxy::RunScript(
+ v8::Handle<v8::Script> script) {
+ 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')");
+ script = V8Proxy::CompileScript(code, "", 0);
+ }
+
+ if (V8Proxy::HandleOutOfMemory())
+ ASSERT(script.IsEmpty());
+
+ if (script.IsEmpty())
+ return v8::Local<v8::Value>();
+
+ // Run the script and keep track of the current recursion depth.
+ v8::Local<v8::Value> result;
+ {
+ m_recursion++;
+ result = script->Run();
+ m_recursion--;
+ }
+
+ // Handle V8 internal error situation (Out-of-memory).
+ if (result.IsEmpty())
+ return v8::Local<v8::Value>();
+
+ return result;
+}
+
+PassRefPtr<V8EventListener>
+WorkerContextExecutionProxy::FindOrCreateEventListener(
+ v8::Local<v8::Value> obj, bool is_inline, bool find_only) {
+ if (!obj->IsObject())
+ return 0;
+
+ for (EventListenerList::iterator iter = m_listeners.begin();
+ iter != m_listeners.end();
+ ++iter) {
+ V8EventListener* el = *iter;
+ if (el->isInline() == is_inline && el->GetListenerObject() == obj)
+ return el;
+ }
+ if (find_only)
+ return NULL;
+
+ // Create a new one, and add to cache.
+ RefPtr<V8EventListener> listener = V8WorkerContextEventListener::create(
+ this, v8::Local<v8::Object>::Cast(obj), is_inline);
+ m_listeners.push_back(listener.get());
+
+ return listener.release();
+}
+
+void WorkerContextExecutionProxy::RemoveEventListener(
+ V8EventListener* listener) {
+ for (EventListenerList::iterator iter = m_listeners.begin();
+ iter != m_listeners.end();
+ ++iter) {
+ if (*iter == listener) {
+ m_listeners.erase(iter);
+ return;
+ }
+ }
+}
+
+void WorkerContextExecutionProxy::TrackEvent(Event* event) {
+ m_events.add(event);
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WORKERS)
diff --git a/webkit/port/bindings/v8/WorkerContextExecutionProxy.h b/webkit/port/bindings/v8/WorkerContextExecutionProxy.h
new file mode 100644
index 0000000..ac9fcfd
--- /dev/null
+++ b/webkit/port/bindings/v8/WorkerContextExecutionProxy.h
@@ -0,0 +1,119 @@
+// Copyright (c) 2009, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef WorkerContextExecutionProxy_h_
+#define WorkerContextExecutionProxy_h_
+
+#if ENABLE(WORKERS)
+
+#include <list>
+#include <wtf/HashSet.h>
+#include "v8.h"
+#include "v8_index.h"
+
+namespace WebCore {
+
+class Event;
+class V8EventListener;
+class WorkerContext;
+
+class WorkerContextExecutionProxy {
+ public:
+ WorkerContextExecutionProxy(WorkerContext*);
+ ~WorkerContextExecutionProxy();
+
+ // Returns a local handle of the context.
+ v8::Local<v8::Context> GetContext() {
+ return v8::Local<v8::Context>::New(m_context);
+ }
+
+ // Returns the dom constructor function for the given node type.
+ v8::Local<v8::Function> GetConstructor(V8ClassIndex::V8WrapperType t);
+
+ // Finds or creates an event listener;
+ PassRefPtr<V8EventListener> FindOrCreateEventListener(
+ v8::Local<v8::Value> listener, bool is_inline, bool find_only);
+
+ // Removes an event listener;
+ void RemoveEventListener(V8EventListener* listener);
+
+ // Track the event so that we can detach it from the JS wrapper when a worker
+ // terminates. This is needed because we need to be able to dispose these
+ // events and releases references to their event targets: WorkerContext.
+ void TrackEvent(Event* event);
+
+ // Evaluate a script file in the current execution environment.
+ v8::Local<v8::Value> Evaluate(const String& str,
+ const String& file_name,
+ int base_line);
+
+ // Returns WorkerContext object.
+ WorkerContext* worker_context() { return m_workerContext; }
+
+ // Returns WorkerContextExecutionProxy object of the currently executing
+ // context.
+ static WorkerContextExecutionProxy* retrieve();
+
+ // Returns the JS wrapper of object.
+ static v8::Handle<v8::Value> ToV8Object(V8ClassIndex::V8WrapperType type,
+ void* imp);
+ static v8::Handle<v8::Value> EventToV8Object(Event* event);
+ static v8::Handle<v8::Value> EventTargetToV8Object(EventTarget* target);
+ static v8::Handle<v8::Value> WorkerContextToV8Object(WorkerContext* wc);
+
+ private:
+ void InitContextIfNeeded();
+ void Dispose();
+
+ // Run an already compiled script.
+ v8::Local<v8::Value> RunScript(v8::Handle<v8::Script> script);
+
+ static v8::Local<v8::Object> InstantiateV8Object(
+ V8ClassIndex::V8WrapperType desc_type,
+ V8ClassIndex::V8WrapperType cptr_type,
+ void* impl);
+
+ static bool ForgetV8EventObject(Event* event);
+
+ WorkerContext* m_workerContext;
+ v8::Persistent<v8::Context> m_context;
+ int m_recursion;
+
+ typedef std::list<V8EventListener*> EventListenerList;
+ EventListenerList m_listeners;
+
+ typedef HashSet<Event*> EventSet;
+ EventSet m_events;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(WORKERS)
+
+#endif // WorkerContextExecutionProxy_h_
diff --git a/webkit/port/bindings/v8/WorkerScriptController.cpp b/webkit/port/bindings/v8/WorkerScriptController.cpp
index 967a2d2..a897bb2 100644
--- a/webkit/port/bindings/v8/WorkerScriptController.cpp
+++ b/webkit/port/bindings/v8/WorkerScriptController.cpp
@@ -35,52 +35,23 @@
#include "ScriptSourceCode.h"
#include "ScriptValue.h"
-#include "v8_proxy.h"
#include "DOMTimer.h"
#include "WorkerContext.h"
+#include "WorkerContextExecutionProxy.h"
#include "WorkerMessagingProxy.h"
#include "WorkerThread.h"
namespace WebCore {
-// TODO(dimich): Move these stubs once they're implemented.
-int DOMTimer::install(ScriptExecutionContext*, ScheduledAction*, int timeout,
- bool singleShot) {
- return 0;
-}
-void DOMTimer::removeById(ScriptExecutionContext*, int timeoutId) {
-}
-
WorkerScriptController::WorkerScriptController(WorkerContext* workerContext)
: m_workerContext(workerContext)
+ , m_proxy(new WorkerContextExecutionProxy(workerContext))
, m_executionForbidden(false)
{
}
WorkerScriptController::~WorkerScriptController()
{
- Dispose();
-}
-
-void WorkerScriptController::Dispose()
-{
- if (!m_context.IsEmpty()) {
- m_context.Dispose();
- m_context.Clear();
- }
-}
-
-void WorkerScriptController::InitContextIfNeeded()
-{
- // Bail out if the context has already been initialized.
- if (!m_context.IsEmpty())
- return;
-
- // Create a new environment
- v8::Persistent<v8::ObjectTemplate> global_template;
- m_context = v8::Context::New(NULL, global_template);
-
- // TODO (jianli): to initialize the context.
}
ScriptValue WorkerScriptController::evaluate(const ScriptSourceCode& sourceCode)
@@ -91,32 +62,15 @@ ScriptValue WorkerScriptController::evaluate(const ScriptSourceCode& sourceCode)
return ScriptValue();
}
- v8::Local<v8::Value> result;
- {
- v8::Locker locker;
- v8::HandleScope hs;
-
- InitContextIfNeeded();
- v8::Context::Scope scope(m_context);
-
- v8::Local<v8::String> code = v8ExternalString(sourceCode.source());
- v8::Handle<v8::Script> script =
- V8Proxy::CompileScript(code,
- sourceCode.url().string(),
- sourceCode.startLine() - 1);
-
- // TODO (jianli): handle infinite recursion.
-
- result = script->Run();
-
- if (V8Proxy::HandleOutOfMemory())
- return ScriptValue();
- }
+ v8::Local<v8::Value> result =
+ m_proxy->Evaluate(sourceCode.source(),
+ sourceCode.url().string(),
+ sourceCode.startLine() - 1);
m_workerContext->thread()->messagingProxy()->
reportWorkerThreadActivity(m_workerContext->hasPendingActivity());
- return ScriptValue(result);
+ return ScriptValue();
}
void WorkerScriptController::forbidExecution()
@@ -124,8 +78,6 @@ void WorkerScriptController::forbidExecution()
// This function is called from another thread.
MutexLocker lock(m_sharedDataMutex);
m_executionForbidden = true;
-
- Dispose();
}
} // namespace WebCore
diff --git a/webkit/port/bindings/v8/WorkerScriptController.h b/webkit/port/bindings/v8/WorkerScriptController.h
index a66e080..efc71d3 100644
--- a/webkit/port/bindings/v8/WorkerScriptController.h
+++ b/webkit/port/bindings/v8/WorkerScriptController.h
@@ -29,6 +29,8 @@
#if ENABLE(WORKERS)
+#include <wtf/OwnPtr.h>
+#include <wtf/Threading.h>
#include "v8.h"
namespace WebCore {
@@ -36,22 +38,22 @@ namespace WebCore {
class ScriptSourceCode;
class ScriptValue;
class WorkerContext;
+ class WorkerContextExecutionProxy;
class WorkerScriptController {
public:
WorkerScriptController(WorkerContext*);
~WorkerScriptController();
+ WorkerContextExecutionProxy* proxy() { return m_proxy.get(); }
+
ScriptValue evaluate(const ScriptSourceCode&);
void forbidExecution();
private:
- void InitContextIfNeeded();
- void Dispose();
-
WorkerContext* m_workerContext;
- v8::Persistent<v8::Context> m_context;
+ OwnPtr<WorkerContextExecutionProxy> m_proxy;
Mutex m_sharedDataMutex;
bool m_executionForbidden;
diff --git a/webkit/port/bindings/v8/v8_custom.h b/webkit/port/bindings/v8/v8_custom.h
index 72f9979..d27ed41 100644
--- a/webkit/port/bindings/v8/v8_custom.h
+++ b/webkit/port/bindings/v8/v8_custom.h
@@ -88,6 +88,11 @@ class V8Custom {
kDefaultWrapperInternalFieldCount + 0;
static const int kWorkerInternalFieldCount =
kDefaultWrapperInternalFieldCount + 1;
+
+ static const int kWorkerContextRequestCacheIndex =
+ kDefaultWrapperInternalFieldCount + 0;
+ static const int kWorkerContextInternalFieldCount =
+ kDefaultWrapperInternalFieldCount + 1;
#endif
static const int kDOMWindowLocationIndex =
@@ -425,6 +430,15 @@ DECLARE_PROPERTY_ACCESSOR(WorkerOnerror)
DECLARE_CALLBACK(WorkerConstructor)
DECLARE_CALLBACK(WorkerAddEventListener)
DECLARE_CALLBACK(WorkerRemoveEventListener)
+
+DECLARE_PROPERTY_ACCESSOR_GETTER(WorkerContextSelf)
+DECLARE_PROPERTY_ACCESSOR(WorkerContextOnmessage)
+DECLARE_CALLBACK(WorkerContextSetTimeout)
+DECLARE_CALLBACK(WorkerContextClearTimeout)
+DECLARE_CALLBACK(WorkerContextSetInterval)
+DECLARE_CALLBACK(WorkerContextClearInterval)
+DECLARE_CALLBACK(WorkerContextAddEventListener)
+DECLARE_CALLBACK(WorkerContextRemoveEventListener)
#endif
#undef DECLARE_INDEXED_ACCESS_CHECK
diff --git a/webkit/port/bindings/v8/v8_events.cpp b/webkit/port/bindings/v8/v8_events.cpp
index 7aecbb1..06de1c6 100644
--- a/webkit/port/bindings/v8/v8_events.cpp
+++ b/webkit/port/bindings/v8/v8_events.cpp
@@ -40,14 +40,14 @@
#include "Tokenizer.h"
#include "Node.h"
#include "XMLHttpRequest.h"
+#include "WorkerContextExecutionProxy.h"
#include "CString.h"
namespace WebCore {
V8AbstractEventListener::V8AbstractEventListener(Frame* frame, bool isInline)
- : m_frame(frame), m_isInline(isInline) {
- ASSERT(m_frame);
+ : m_isInline(isInline), m_frame(frame) {
if (!m_frame) return;
// Get the position in the source if any.
@@ -61,7 +61,7 @@ V8AbstractEventListener::V8AbstractEventListener(Frame* frame, bool isInline)
void V8AbstractEventListener::handleEvent(Event* event, bool isWindowEvent) {
// EventListener could be disconnected from the frame.
- if (!m_frame)
+ if (disconnected())
return;
// The callback function on XMLHttpRequest can clear the event listener
@@ -449,4 +449,132 @@ v8::Local<v8::Function> V8LazyEventListener::GetWrappedListenerFunction() {
return v8::Local<v8::Function>::New(m_wrapped_function);
}
+#if ENABLE(WORKERS)
+V8WorkerContextEventListener::V8WorkerContextEventListener(
+ WorkerContextExecutionProxy* proxy,
+ v8::Local<v8::Object> listener,
+ bool isInline)
+ : V8ObjectEventListener(NULL, listener, isInline)
+ , m_proxy(proxy) {
+}
+
+V8WorkerContextEventListener::~V8WorkerContextEventListener() {
+ if (m_proxy) {
+ m_proxy->RemoveEventListener(this);
+ }
+ DisposeListenerObject();
+}
+
+void V8WorkerContextEventListener::handleEvent(Event* event,
+ bool isWindowEvent) {
+ // EventListener could be disconnected from the frame.
+ if (disconnected())
+ return;
+
+ // The callback function on XMLHttpRequest can clear the event listener
+ // and destroys 'this' object. Keep a local reference of it.
+ // See issue 889829
+ RefPtr<V8AbstractEventListener> self(this);
+
+ v8::HandleScope handle_scope;
+
+ v8::Handle<v8::Context> context = m_proxy->GetContext();
+ if (context.IsEmpty())
+ return;
+ v8::Context::Scope scope(context);
+
+ v8::Handle<v8::Value> jsevent =
+ WorkerContextExecutionProxy::EventToV8Object(event);
+
+ // For compatibility, we store the event object as a property on the window
+ // called "event". Because this is the global namespace, we save away any
+ // existing "event" property, and then restore it after executing the
+ // javascript handler.
+ v8::Local<v8::String> event_symbol = v8::String::NewSymbol("event");
+
+ // Save the old 'event' property.
+ v8::Local<v8::Value> saved_evt = context->Global()->Get(event_symbol);
+
+ // Make the event available in the window object.
+ //
+ // TODO: This does not work as in safari if the window.event
+ // property is already set. We need to make sure that property
+ // access is intercepted correctly.
+ context->Global()->Set(event_symbol, jsevent);
+
+ v8::Local<v8::Value> ret;
+ {
+ // Catch exceptions thrown in the event handler so they do not
+ // propagate to javascript code that caused the event to fire.
+ v8::TryCatch try_catch;
+ try_catch.SetVerbose(true);
+
+ // Call the event handler.
+ ret = CallListenerFunction(jsevent, event, isWindowEvent);
+ }
+
+ // Restore the old event. This must be done for all exit paths through
+ // this method.
+ context->Global()->Set(event_symbol, saved_evt);
+
+ if (V8Proxy::HandleOutOfMemory())
+ ASSERT(ret.IsEmpty());
+
+ if (ret.IsEmpty()) {
+ return;
+ }
+
+ if (!ret.IsEmpty()) {
+ if (!ret->IsNull() && !ret->IsUndefined() &&
+ event->storesResultAsString()) {
+ event->storeResult(ToWebCoreString(ret));
+ }
+ // Prevent default action if the return value is false;
+ // TODO(fqian): example, and reference to buganizer entry
+ if (m_isInline) {
+ if (ret->IsBoolean() && !ret->BooleanValue()) {
+ event->preventDefault();
+ }
+ }
+ }
+}
+
+v8::Local<v8::Value> V8WorkerContextEventListener::CallListenerFunction(
+ v8::Handle<v8::Value> jsevent, Event* event, bool isWindowEvent) {
+ v8::Local<v8::Function> handler_func = GetListenerFunction();
+ if (handler_func.IsEmpty()) return v8::Local<v8::Value>();
+
+ v8::Local<v8::Object> receiver = GetReceiverObject(event, isWindowEvent);
+ v8::Handle<v8::Value> parameters[1] = {jsevent};
+
+ v8::Local<v8::Value> result;
+ {
+ //ConsoleMessageScope scope;
+
+ result = handler_func->Call(receiver, 1, parameters);
+ }
+
+ m_proxy->TrackEvent(event);
+
+ return result;
+}
+
+v8::Local<v8::Object> V8WorkerContextEventListener::GetReceiverObject(
+ Event* event, bool isWindowEvent) {
+ if (!m_listener.IsEmpty() && !m_listener->IsFunction()) {
+ return v8::Local<v8::Object>::New(m_listener);
+ }
+
+ if (isWindowEvent) {
+ return v8::Context::GetCurrent()->Global();
+ }
+
+ EventTarget* target = event->currentTarget();
+ v8::Handle<v8::Value> value =
+ WorkerContextExecutionProxy::EventTargetToV8Object(target);
+ if (value.IsEmpty()) return v8::Local<v8::Object>();
+ return v8::Local<v8::Object>::New(v8::Handle<v8::Object>::Cast(value));
+}
+#endif // WORKERS
+
} // namespace WebCore
diff --git a/webkit/port/bindings/v8/v8_events.h b/webkit/port/bindings/v8/v8_events.h
index 7306ab4..e01f972 100644
--- a/webkit/port/bindings/v8/v8_events.h
+++ b/webkit/port/bindings/v8/v8_events.h
@@ -17,6 +17,10 @@
namespace WebCore {
+#if ENABLE(WORKERS)
+class WorkerContextExecutionProxy;
+#endif // WORKERS
+
// There are two kinds of event listeners: HTML or non-HMTL.
// onload, onfocus, etc (attributes) are always HTML event handler type;
// Event listeners added by Window.addEventListener
@@ -34,7 +38,7 @@ class V8AbstractEventListener : public EventListener {
Frame* frame() { return m_frame; }
// Handle event.
- void handleEvent(Event*, bool isWindowEvent);
+ virtual void handleEvent(Event*, bool isWindowEvent);
// Returns the listener object, either a function or an object.
virtual v8::Local<v8::Object> GetListenerObject() {
@@ -44,10 +48,18 @@ class V8AbstractEventListener : public EventListener {
// Dispose listener object and clear the handle
void DisposeListenerObject();
+ virtual bool disconnected() const { return m_frame == NULL; }
+
+ protected:
+ // Listener object.
+ v8::Persistent<v8::Object> m_listener;
+
+ // Flags this is a HTML type listener.
+ bool m_isInline;
+
private:
V8AbstractEventListener(Frame* frame, bool isInline);
-
// Call listener function.
virtual v8::Local<v8::Value> CallListenerFunction(
v8::Handle<v8::Value> jsevent,
@@ -66,12 +78,6 @@ class V8AbstractEventListener : public EventListener {
// the event listener is deleted. Fix this!
Frame* m_frame;
- // Listener object.
- v8::Persistent<v8::Object> m_listener;
-
- // Flags this is a HTML type listener.
- bool m_isInline;
-
// Position in the HTML source for HTML event listeners.
int m_lineNumber;
int m_columnNumber;
@@ -98,11 +104,13 @@ class V8EventListener : public V8AbstractEventListener {
// Detach the listener from its owner frame.
void disconnectFrame() { m_frame = 0; }
+ protected:
+ v8::Local<v8::Function> GetListenerFunction();
+
private:
// Call listener function.
virtual v8::Local<v8::Value> CallListenerFunction(
v8::Handle<v8::Value> jsevent, Event* event, bool isWindowEvent);
- v8::Local<v8::Function> GetListenerFunction();
};
@@ -158,6 +166,37 @@ class V8LazyEventListener : public V8AbstractEventListener {
v8::Local<v8::Function> GetListenerFunction();
};
+#if ENABLE(WORKERS)
+class V8WorkerContextEventListener : public V8ObjectEventListener {
+ public:
+ static PassRefPtr<V8WorkerContextEventListener> create(
+ WorkerContextExecutionProxy* proxy,
+ v8::Local<v8::Object> listener,
+ bool isInline) {
+ return adoptRef(new V8WorkerContextEventListener(proxy,
+ listener,
+ isInline));
+ }
+ V8WorkerContextEventListener(WorkerContextExecutionProxy* proxy,
+ v8::Local<v8::Object> listener,
+ bool isInline);
+
+ virtual ~V8WorkerContextEventListener();
+ virtual void handleEvent(Event*, bool isWindowEvent);
+ virtual bool disconnected() const { return m_proxy == NULL; }
+
+ void disconnect() { m_proxy = NULL; }
+
+ private:
+ virtual v8::Local<v8::Value>
+ CallListenerFunction(v8::Handle<v8::Value> jsevent,
+ Event* event, bool isWindowEvent);
+ v8::Local<v8::Object> GetReceiverObject(Event* event,
+ bool isWindowEvent);
+ WorkerContextExecutionProxy* m_proxy;
+};
+#endif // WORKERS
+
} // namespace WebCore
#endif // V8_EVENTS_H__
diff --git a/webkit/port/bindings/v8/v8_index.cpp b/webkit/port/bindings/v8/v8_index.cpp
index 9f93a93..6be992c 100644
--- a/webkit/port/bindings/v8/v8_index.cpp
+++ b/webkit/port/bindings/v8/v8_index.cpp
@@ -355,7 +355,9 @@
#if ENABLE(WORKERS)
#include "V8Worker.h"
+#include "V8WorkerContext.h"
#include "V8WorkerLocation.h"
+#include "V8WorkerNavigator.h"
#endif
namespace WebCore {
diff --git a/webkit/port/bindings/v8/v8_index.h b/webkit/port/bindings/v8/v8_index.h
index d388116..f77557f 100644
--- a/webkit/port/bindings/v8/v8_index.h
+++ b/webkit/port/bindings/v8/v8_index.h
@@ -29,7 +29,9 @@ typedef v8::Persistent<v8::FunctionTemplate> (*FunctionTemplateFactory)();
#if ENABLE(WORKERS)
#define WORKER_NONNODE_WRAPPER_TYPES(V) \
V(WORKER, Worker) \
- V(WORKERLOCATION, WorkerLocation)
+ V(WORKERCONTEXT, WorkerContext) \
+ V(WORKERLOCATION, WorkerLocation) \
+ V(WORKERNAVIGATOR, WorkerNavigator)
#else
#define WORKER_NONNODE_WRAPPER_TYPES(V)
#endif
diff --git a/webkit/port/bindings/v8/v8_proxy.cpp b/webkit/port/bindings/v8/v8_proxy.cpp
index 4a76163..81c6e63 100644
--- a/webkit/port/bindings/v8/v8_proxy.cpp
+++ b/webkit/port/bindings/v8/v8_proxy.cpp
@@ -193,7 +193,9 @@
#if ENABLE(WORKERS)
#include "Worker.h"
+#include "WorkerContext.h"
#include "WorkerLocation.h"
+#include "WorkerNavigator.h"
#endif // WORKERS
#if ENABLE(XPATH)
@@ -380,7 +382,7 @@ static void WeakActiveDOMObjectCallback(v8::Persistent<v8::Value> obj,
void* para);
static void WeakNodeCallback(v8::Persistent<v8::Value> obj, void* para);
// A map from DOM node to its JS wrapper.
-static DOMWrapperMap<Node>& dom_node_map()
+static DOMWrapperMap<Node>& GetDOMNodeMap()
{
static DOMWrapperMap<Node> static_dom_node_map(&WeakNodeCallback);
return static_dom_node_map;
@@ -389,7 +391,7 @@ static DOMWrapperMap<Node>& dom_node_map()
// A map from a DOM object (non-node) to its JS wrapper. This map does not
// contain the DOM objects which can have pending activity (active dom objects).
-static DOMWrapperMap<void>& dom_object_map()
+DOMWrapperMap<void>& GetDOMObjectMap()
{
static DOMWrapperMap<void>
static_dom_object_map(&WeakDOMObjectCallback);
@@ -399,7 +401,7 @@ static DOMWrapperMap<void>& dom_object_map()
// A map from a DOM object to its JS wrapper for DOM objects which
// can have pending activity.
-static DOMWrapperMap<void>& active_dom_object_map()
+static DOMWrapperMap<void>& GetActiveDOMObjectMap()
{
static DOMWrapperMap<void>
static_active_dom_object_map(&WeakActiveDOMObjectCallback);
@@ -560,18 +562,17 @@ SVGElement* V8Proxy::GetSVGContext(void* obj)
#endif
-
// Called when obj is near death (not reachable from JS roots)
// It is time to remove the entry from the table and dispose
// the handle.
static void WeakDOMObjectCallback(v8::Persistent<v8::Value> obj,
void* dom_obj) {
v8::HandleScope scope;
- ASSERT(dom_object_map().contains(dom_obj));
+ ASSERT(GetDOMObjectMap().contains(dom_obj));
ASSERT(obj->IsObject());
// Forget function removes object from the map and dispose the wrapper.
- dom_object_map().forget(dom_obj);
+ GetDOMObjectMap().forget(dom_obj);
V8ClassIndex::V8WrapperType type =
V8Proxy::GetDOMWrapperType(v8::Handle<v8::Object>::Cast(obj));
@@ -590,11 +591,11 @@ static void WeakActiveDOMObjectCallback(v8::Persistent<v8::Value> obj,
void* dom_obj)
{
v8::HandleScope scope;
- ASSERT(active_dom_object_map().contains(dom_obj));
+ ASSERT(GetActiveDOMObjectMap().contains(dom_obj));
ASSERT(obj->IsObject());
// Forget function removes object from the map and dispose the wrapper.
- active_dom_object_map().forget(dom_obj);
+ GetActiveDOMObjectMap().forget(dom_obj);
V8ClassIndex::V8WrapperType type =
V8Proxy::GetDOMWrapperType(v8::Handle<v8::Object>::Cast(obj));
@@ -611,9 +612,9 @@ static void WeakActiveDOMObjectCallback(v8::Persistent<v8::Value> obj,
static void WeakNodeCallback(v8::Persistent<v8::Value> obj, void* param)
{
Node* node = static_cast<Node*>(param);
- ASSERT(dom_node_map().contains(node));
+ ASSERT(GetDOMNodeMap().contains(node));
- dom_node_map().forget(node);
+ GetDOMNodeMap().forget(node);
node->deref();
}
@@ -632,11 +633,11 @@ void V8Proxy::GCProtect(void* dom_object)
return;
if (gc_protected_map().contains(dom_object))
return;
- if (!dom_object_map().contains(dom_object))
+ if (!GetDOMObjectMap().contains(dom_object))
return;
// Create a new (strong) persistent handle for the object.
- v8::Persistent<v8::Object> wrapper = dom_object_map().get(dom_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));
@@ -663,12 +664,12 @@ static void GCPrologue()
v8::HandleScope scope;
#ifndef NDEBUG
- EnumerateDOMObjectMap(dom_object_map().impl());
+ EnumerateDOMObjectMap(GetDOMObjectMap().impl());
#endif
// Run through all objects with possible pending activity making their
// wrappers non weak if there is pending activity.
- DOMObjectMap active_map = active_dom_object_map().impl();
+ DOMObjectMap active_map = GetActiveDOMObjectMap().impl();
for (DOMObjectMap::iterator it = active_map.begin(), end = active_map.end();
it != end; ++it) {
void* obj = it->first;
@@ -731,7 +732,7 @@ ACTIVE_DOM_OBJECT_TYPES(MAKE_CASE)
typedef std::pair<uintptr_t, Node*> GrouperPair;
typedef Vector<GrouperPair> GrouperList;
- DOMNodeMap node_map = dom_node_map().impl();
+ DOMNodeMap node_map = GetDOMNodeMap().impl();
GrouperList grouper;
grouper.reserveCapacity(node_map.size());
@@ -797,7 +798,7 @@ ACTIVE_DOM_OBJECT_TYPES(MAKE_CASE)
group.reserveCapacity(next_key_index - i);
for (; i < next_key_index; ++i) {
v8::Persistent<v8::Value> wrapper =
- dom_node_map().get(grouper[i].second);
+ GetDOMNodeMap().get(grouper[i].second);
if (!wrapper.IsEmpty())
group.append(wrapper);
}
@@ -816,7 +817,7 @@ static void GCEpilogue()
// Run through all objects with pending activity making their wrappers weak
// again.
- DOMObjectMap active_map = active_dom_object_map().impl();
+ DOMObjectMap active_map = GetActiveDOMObjectMap().impl();
for (DOMObjectMap::iterator it = active_map.begin(), end = active_map.end();
it != end; ++it) {
void* obj = it->first;
@@ -841,8 +842,8 @@ ACTIVE_DOM_OBJECT_TYPES(MAKE_CASE)
#ifndef NDEBUG
// Check all survivals are weak.
- EnumerateDOMObjectMap(dom_object_map().impl());
- EnumerateDOMNodeMap(dom_node_map().impl());
+ EnumerateDOMObjectMap(GetDOMObjectMap().impl());
+ EnumerateDOMNodeMap(GetDOMNodeMap().impl());
EnumerateDOMObjectMap(gc_protected_map());
EnumerateGlobalHandles();
#undef USE_VAR
@@ -1104,8 +1105,8 @@ void V8Proxy::DestroyGlobal()
bool V8Proxy::DOMObjectHasJSWrapper(void* obj) {
- return dom_object_map().contains(obj) ||
- active_dom_object_map().contains(obj);
+ return GetDOMObjectMap().contains(obj) ||
+ GetActiveDOMObjectMap().contains(obj);
}
@@ -1123,7 +1124,7 @@ ACTIVE_DOM_OBJECT_TYPES(MAKE_CASE)
default: break;
}
#endif
- dom_object_map().set(obj, wrapper);
+ GetDOMObjectMap().set(obj, wrapper);
}
// The caller must have increased obj's ref count.
@@ -1139,14 +1140,14 @@ ACTIVE_DOM_OBJECT_TYPES(MAKE_CASE)
#undef MAKE_CASE
}
#endif
- active_dom_object_map().set(obj, wrapper);
+ 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));
- dom_node_map().set(node, wrapper);
+ GetDOMNodeMap().set(node, wrapper);
}
PassRefPtr<EventListener> V8Proxy::createInlineEventListener(
@@ -1379,7 +1380,7 @@ v8::Local<v8::Value> V8Proxy::RunScript(v8::Handle<v8::Script> script,
return v8::Local<v8::Value>();
// Compute the source string and prevent against infinite recursion.
- if (m_recursion >= 20) {
+ 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
@@ -1794,8 +1795,18 @@ v8::Persistent<v8::FunctionTemplate> V8Proxy::GetTemplate(
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));
@@ -2520,8 +2531,8 @@ v8::Handle<v8::Value> V8Proxy::ToV8Object(V8ClassIndex::V8WrapperType type, void
// Non DOM node
v8::Persistent<v8::Object> result = is_active_dom_object ?
- active_dom_object_map().get(imp) :
- dom_object_map().get(imp);
+ GetActiveDOMObjectMap().get(imp) :
+ GetDOMObjectMap().get(imp);
if (result.IsEmpty()) {
v8::Local<v8::Object> v8obj = InstantiateV8Object(type, type, imp);
if (!v8obj.IsEmpty()) {
@@ -2667,6 +2678,7 @@ v8::Local<v8::Object> V8Proxy::InstantiateV8Object(
desc_type = V8ClassIndex::UNDETECTABLEHTMLCOLLECTION;
}
+
v8::Local<v8::Function> function;
V8Proxy* proxy = V8Proxy::retrieve();
if (proxy) {
@@ -2994,7 +3006,7 @@ v8::Handle<v8::Value> V8Proxy::EventToV8Object(Event* event)
if (!event)
return v8::Null();
- v8::Handle<v8::Object> wrapper = dom_object_map().get(event);
+ v8::Handle<v8::Object> wrapper = GetDOMObjectMap().get(event);
if (!wrapper.IsEmpty())
return wrapper;
@@ -3053,7 +3065,7 @@ v8::Handle<v8::Value> V8Proxy::NodeToV8Object(Node* node)
{
if (!node) return v8::Null();
- v8::Handle<v8::Object> wrapper = dom_node_map().get(node);
+ v8::Handle<v8::Object> wrapper = GetDOMNodeMap().get(node);
if (!wrapper.IsEmpty())
return wrapper;
@@ -3171,9 +3183,9 @@ v8::Handle<v8::Value> V8Proxy::NodeToV8Object(Node* node)
}
-// A JS object of type EventTarget can only be five possible types:
+// A JS object of type EventTarget can only be the following possible types:
// 1) EventTargetNode; 2) XMLHttpRequest; 3) MessagePort; 4) SVGElementInstance;
-// 5) XMLHttpRequestUpload
+// 5) XMLHttpRequestUpload 6) Worker
// check EventTarget.h for new type conversion methods
v8::Handle<v8::Value> V8Proxy::EventTargetToV8Object(EventTarget* target)
{
@@ -3186,6 +3198,12 @@ v8::Handle<v8::Value> V8Proxy::EventTargetToV8Object(EventTarget* target)
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);
@@ -3193,7 +3211,7 @@ v8::Handle<v8::Value> V8Proxy::EventTargetToV8Object(EventTarget* target)
// XMLHttpRequest is created within its JS counterpart.
XMLHttpRequest* xhr = target->toXMLHttpRequest();
if (xhr) {
- v8::Handle<v8::Object> wrapper = active_dom_object_map().get(xhr);
+ v8::Handle<v8::Object> wrapper = GetActiveDOMObjectMap().get(xhr);
ASSERT(!wrapper.IsEmpty());
return wrapper;
}
@@ -3201,14 +3219,14 @@ v8::Handle<v8::Value> V8Proxy::EventTargetToV8Object(EventTarget* target)
// MessagePort is created within its JS counterpart
MessagePort* port = target->toMessagePort();
if (port) {
- v8::Handle<v8::Object> wrapper = active_dom_object_map().get(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 = dom_object_map().get(upload);
+ v8::Handle<v8::Object> wrapper = GetDOMObjectMap().get(upload);
ASSERT(!wrapper.IsEmpty());
return wrapper;
}
@@ -3250,7 +3268,7 @@ v8::Handle<v8::Value> V8Proxy::StyleSheetToV8Object(StyleSheet* sheet)
{
if (!sheet) return v8::Null();
- v8::Handle<v8::Object> wrapper = dom_object_map().get(sheet);
+ v8::Handle<v8::Object> wrapper = GetDOMObjectMap().get(sheet);
if (!wrapper.IsEmpty())
return wrapper;
@@ -3282,7 +3300,7 @@ v8::Handle<v8::Value> V8Proxy::CSSValueToV8Object(CSSValue* value)
{
if (!value) return v8::Null();
- v8::Handle<v8::Object> wrapper = dom_object_map().get(value);
+ v8::Handle<v8::Object> wrapper = GetDOMObjectMap().get(value);
if (!wrapper.IsEmpty())
return wrapper;
@@ -3319,7 +3337,7 @@ v8::Handle<v8::Value> V8Proxy::CSSRuleToV8Object(CSSRule* rule)
{
if (!rule) return v8::Null();
- v8::Handle<v8::Object> wrapper = dom_object_map().get(rule);
+ v8::Handle<v8::Object> wrapper = GetDOMObjectMap().get(rule);
if (!wrapper.IsEmpty())
return wrapper;
diff --git a/webkit/port/bindings/v8/v8_proxy.h b/webkit/port/bindings/v8/v8_proxy.h
index 772489f..2054035 100644
--- a/webkit/port/bindings/v8/v8_proxy.h
+++ b/webkit/port/bindings/v8/v8_proxy.h
@@ -6,6 +6,7 @@
#define V8_PROXY_H__
#include <v8.h>
+#include "dom_wrapper_map.h"
#include "v8_index.h"
#include "v8_custom.h"
#include "v8_utility.h"
@@ -142,6 +143,10 @@ void BatchConfigureConstants(v8::Handle<v8::FunctionTemplate> desc,
const BatchedConstant* consts,
size_t num_consts);
+DOMWrapperMap<void>& GetDOMObjectMap();
+
+const int kMaxRecursionDepth = 20;
+
class V8Proxy {
public:
// The types of javascript errors that can be thrown.