Bug 649537 - 'Workers: Make one OS thread and JS runtime per worker, and lose XPConnect'. r=sicking+mrbkap.

--HG--
rename : dom/src/threads/Makefile.in => dom/workers/Makefile.in
rename : dom/src/threads/test/Makefile.in => dom/workers/test/Makefile.in
rename : dom/src/threads/test/WorkerTest.jsm => dom/workers/test/WorkerTest.jsm
rename : dom/src/threads/test/WorkerTest_badworker.js => dom/workers/test/WorkerTest_badworker.js
rename : dom/src/threads/test/WorkerTest_subworker.js => dom/workers/test/WorkerTest_subworker.js
rename : dom/src/threads/test/WorkerTest_worker.js => dom/workers/test/WorkerTest_worker.js
rename : dom/src/threads/test/atob_worker.js => dom/workers/test/atob_worker.js
rename : dom/src/threads/test/chromeWorker_subworker.js => dom/workers/test/chromeWorker_subworker.js
rename : dom/src/threads/test/chromeWorker_worker.js => dom/workers/test/chromeWorker_worker.js
rename : dom/src/threads/test/closeOnGC_server.sjs => dom/workers/test/closeOnGC_server.sjs
rename : dom/src/threads/test/closeOnGC_worker.js => dom/workers/test/closeOnGC_worker.js
rename : dom/src/threads/test/close_worker.js => dom/workers/test/close_worker.js
rename : dom/src/threads/test/fibonacci_worker.js => dom/workers/test/fibonacci_worker.js
rename : dom/src/threads/test/importScripts_worker.js => dom/workers/test/importScripts_worker.js
rename : dom/src/threads/test/importScripts_worker_imported1.js => dom/workers/test/importScripts_worker_imported1.js
rename : dom/src/threads/test/importScripts_worker_imported2.js => dom/workers/test/importScripts_worker_imported2.js
rename : dom/src/threads/test/importScripts_worker_imported3.js => dom/workers/test/importScripts_worker_imported3.js
rename : dom/src/threads/test/importScripts_worker_imported4.js => dom/workers/test/importScripts_worker_imported4.js
rename : dom/src/threads/test/json_worker.js => dom/workers/test/json_worker.js
rename : dom/src/threads/test/location_worker.js => dom/workers/test/location_worker.js
rename : dom/src/threads/test/longThread_worker.js => dom/workers/test/longThread_worker.js
rename : dom/src/threads/test/navigator_worker.js => dom/workers/test/navigator_worker.js
rename : dom/src/threads/test/newError_worker.js => dom/workers/test/newError_worker.js
rename : dom/src/threads/test/recursion_worker.js => dom/workers/test/recursion_worker.js
rename : dom/src/threads/test/relativeLoad_import.js => dom/workers/test/relativeLoad_import.js
rename : dom/src/threads/test/relativeLoad_sub_import.js => dom/workers/test/relativeLoad_sub_import.js
rename : dom/src/threads/test/relativeLoad_sub_worker.js => dom/workers/test/relativeLoad_sub_worker.js
rename : dom/src/threads/test/relativeLoad_sub_worker2.js => dom/workers/test/relativeLoad_sub_worker2.js
rename : dom/src/threads/test/relativeLoad_worker.js => dom/workers/test/relativeLoad_worker.js
rename : dom/src/threads/test/relativeLoad_worker2.js => dom/workers/test/relativeLoad_worker2.js
rename : dom/src/threads/test/simpleThread_worker.js => dom/workers/test/simpleThread_worker.js
rename : dom/src/threads/test/suspend_iframe.html => dom/workers/test/suspend_iframe.html
rename : dom/src/threads/test/suspend_worker.js => dom/workers/test/suspend_worker.js
rename : dom/src/threads/test/terminate_worker.js => dom/workers/test/terminate_worker.js
rename : dom/src/threads/test/testXHR.txt => dom/workers/test/testXHR.txt
rename : dom/src/threads/test/test_404.html => dom/workers/test/test_404.html
rename : dom/src/threads/test/test_atob.html => dom/workers/test/test_atob.html
rename : dom/src/threads/test/test_chromeWorker.html => dom/workers/test/test_chromeWorker.html
rename : dom/src/threads/test/test_chromeWorker.xul => dom/workers/test/test_chromeWorker.xul
rename : dom/src/threads/test/test_chromeWorkerJSM.xul => dom/workers/test/test_chromeWorkerJSM.xul
rename : dom/src/threads/test/test_close.html => dom/workers/test/test_close.html
rename : dom/src/threads/test/test_closeOnGC.html => dom/workers/test/test_closeOnGC.html
rename : dom/src/threads/test/test_errorPropagation.html => dom/workers/test/test_errorPropagation.html
rename : dom/src/threads/test/test_fibonacci.html => dom/workers/test/test_fibonacci.html
rename : dom/src/threads/test/test_importScripts.html => dom/workers/test/test_importScripts.html
rename : dom/src/threads/test/test_json.html => dom/workers/test/test_json.html
rename : dom/src/threads/test/test_location.html => dom/workers/test/test_location.html
rename : dom/src/threads/test/test_longThread.html => dom/workers/test/test_longThread.html
rename : dom/src/threads/test/test_navigator.html => dom/workers/test/test_navigator.html
rename : dom/src/threads/test/test_newError.html => dom/workers/test/test_newError.html
rename : dom/src/threads/test/test_recursion.html => dom/workers/test/test_recursion.html
rename : dom/src/threads/test/test_relativeLoad.html => dom/workers/test/test_relativeLoad.html
rename : dom/src/threads/test/test_simpleThread.html => dom/workers/test/test_simpleThread.html
rename : dom/src/threads/test/test_suspend.html => dom/workers/test/test_suspend.html
rename : dom/src/threads/test/test_terminate.html => dom/workers/test/test_terminate.html
rename : dom/src/threads/test/test_threadErrors.html => dom/workers/test/test_threadErrors.html
rename : dom/src/threads/test/test_threadTimeouts.html => dom/workers/test/test_threadTimeouts.html
rename : dom/src/threads/test/test_throwingOnerror.html => dom/workers/test/test_throwingOnerror.html
rename : dom/src/threads/test/test_xhr.html => dom/workers/test/test_xhr.html
rename : dom/src/threads/test/test_xhrAbort.html => dom/workers/test/test_xhrAbort.html
rename : dom/src/threads/test/threadErrors_worker1.js => dom/workers/test/threadErrors_worker1.js
rename : dom/src/threads/test/threadErrors_worker2.js => dom/workers/test/threadErrors_worker2.js
rename : dom/src/threads/test/threadErrors_worker3.js => dom/workers/test/threadErrors_worker3.js
rename : dom/src/threads/test/threadErrors_worker4.js => dom/workers/test/threadErrors_worker4.js
rename : dom/src/threads/test/threadTimeouts_worker.js => dom/workers/test/threadTimeouts_worker.js
rename : dom/src/threads/test/throwingOnerror_worker.js => dom/workers/test/throwingOnerror_worker.js
rename : dom/src/threads/test/xhrAbort_worker.js => dom/workers/test/xhrAbort_worker.js
rename : dom/src/threads/test/xhr_worker.js => dom/workers/test/xhr_worker.js
This commit is contained in:
Ben Turner 2011-07-17 15:09:13 -04:00
Родитель d86d2598b0
Коммит 820e368a57
185 изменённых файлов: 15188 добавлений и 13391 удалений

Просмотреть файл

@ -62,7 +62,6 @@ DIRS = \
interfaces/json \
interfaces/offline \
interfaces/geolocation \
interfaces/threads \
interfaces/notification \
interfaces/svg \
$(NULL)
@ -81,6 +80,7 @@ DIRS += \
indexedDB \
system \
ipc \
workers \
$(NULL)
ifdef ENABLE_TESTS

Просмотреть файл

@ -460,7 +460,7 @@
#include "nsIDOMGeoPositionError.h"
// Workers
#include "nsDOMWorker.h"
#include "mozilla/dom/workers/Workers.h"
#include "nsDOMFile.h"
#include "nsDOMFileReader.h"
@ -599,9 +599,6 @@ DOMCI_DATA(ContentFrameMessageManager, void)
DOMCI_DATA(DOMPrototype, void)
DOMCI_DATA(DOMConstructor, void)
DOMCI_DATA(Worker, void)
DOMCI_DATA(ChromeWorker, void)
#define NS_DEFINE_CLASSINFO_DATA_WITH_NAME(_class, _name, _helper, \
_flags) \
{ #_name, \
@ -1431,11 +1428,6 @@ static nsDOMClassInfoData sClassInfoData[] = {
NS_DEFINE_CLASSINFO_DATA_WITH_NAME(MathMLElement, Element, nsElementSH,
ELEMENT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(Worker, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CHROME_ONLY_CLASSINFO_DATA(ChromeWorker, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(WebGLRenderingContext, nsWebGLViewportHandlerSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(WebGLBuffer, nsDOMGenericSH,
@ -1572,8 +1564,6 @@ struct nsConstructorFuncMapData
static const nsConstructorFuncMapData kConstructorFuncMap[] =
{
NS_DEFINE_CONSTRUCTOR_FUNC_DATA(Worker, nsDOMWorker::NewWorker)
NS_DEFINE_CONSTRUCTOR_FUNC_DATA(ChromeWorker, nsDOMWorker::NewChromeWorker)
NS_DEFINE_CONSTRUCTOR_FUNC_DATA(File, nsDOMFileFile::NewFile)
NS_DEFINE_CONSTRUCTOR_FUNC_DATA(MozBlobBuilder, NS_NewBlobBuilder)
};
@ -4144,18 +4134,6 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_MAP_ENTRY(nsIDOMNodeSelector)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(Worker, nsIWorker)
DOM_CLASSINFO_MAP_ENTRY(nsIWorker)
DOM_CLASSINFO_MAP_ENTRY(nsIAbstractWorker)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(ChromeWorker, nsIWorker)
DOM_CLASSINFO_MAP_ENTRY(nsIWorker)
DOM_CLASSINFO_MAP_ENTRY(nsIAbstractWorker)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(WebGLRenderingContext, nsIDOMWebGLRenderingContext)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMWebGLRenderingContext)
DOM_CLASSINFO_MAP_END
@ -6066,10 +6044,32 @@ nsDOMConstructor::HasInstance(nsIXPConnectWrappedNative *wrapper,
const nsGlobalNameStruct *name_struct;
rv = GetNameStruct(NS_ConvertASCIItoUTF16(dom_class->name), &name_struct);
if (!name_struct) {
if (NS_FAILED(rv)) {
return rv;
}
if (!name_struct) {
// This isn't a normal DOM object, see if this constructor lives on its
// prototype chain.
jsval val;
if (!JS_GetProperty(cx, obj, "prototype", &val)) {
return NS_ERROR_UNEXPECTED;
}
JS_ASSERT(!JSVAL_IS_PRIMITIVE(val));
JSObject *dot_prototype = JSVAL_TO_OBJECT(val);
JSObject *proto = JS_GetPrototype(cx, dom_obj);
for ( ; proto; proto = JS_GetPrototype(cx, proto)) {
if (proto == dot_prototype) {
*bp = PR_TRUE;
break;
}
}
return NS_OK;
}
if (name_struct->mType != nsGlobalNameStruct::eTypeClassConstructor &&
name_struct->mType != nsGlobalNameStruct::eTypeExternalClassInfo &&
name_struct->mType != nsGlobalNameStruct::eTypeExternalConstructorAlias) {
@ -6702,6 +6702,10 @@ ContentWindowGetter(JSContext *cx, uintN argc, jsval *vp)
return ::JS_GetProperty(cx, obj, "content", vp);
}
static JSNewResolveOp sOtherResolveFuncs[] = {
mozilla::dom::workers::ResolveWorkerClasses
};
NS_IMETHODIMP
nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, jsid id, PRUint32 flags,
@ -6928,6 +6932,16 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
if (!(flags & JSRESOLVE_ASSIGNING)) {
JSAutoRequest ar(cx);
// Resolve special classes.
for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(sOtherResolveFuncs); i++) {
if (!sOtherResolveFuncs[i](cx, obj, id, flags, objp)) {
return NS_ERROR_FAILURE;
}
if (*objp) {
return NS_OK;
}
}
// Call GlobalResolve() after we call FindChildWithName() so
// that named child frames will override external properties
// which have been registered with the script namespace manager.

Просмотреть файл

@ -462,9 +462,6 @@ DOMCI_CLASS(MozTouchEvent)
DOMCI_CLASS(MathMLElement)
DOMCI_CLASS(Worker)
DOMCI_CLASS(ChromeWorker)
// WebGL
DOMCI_CLASS(WebGLRenderingContext)
DOMCI_CLASS(WebGLBuffer)

Просмотреть файл

@ -91,9 +91,9 @@
#include "nsLayoutStatics.h"
#include "nsCycleCollector.h"
#include "nsCCUncollectableMarker.h"
#include "nsDOMThreadService.h"
#include "nsAutoJSValHolder.h"
#include "nsDOMMediaQueryList.h"
#include "mozilla/dom/workers/Workers.h"
// Interfaces Needed
#include "nsIFrame.h"
@ -1244,18 +1244,11 @@ nsGlobalWindow::FreeInnerObjects(PRBool aClearScope)
NS_ASSERTION(IsInnerWindow(), "Don't free inner objects on an outer window");
// Kill all of the workers for this window.
nsDOMThreadService* dts = nsDOMThreadService::get();
if (dts) {
nsIScriptContext *scx = GetContextInternal();
JSContext *cx = scx ? (JSContext *)scx->GetNativeContext() : nsnull;
// Have to suspend this request here because CancelWorkersForGlobal will
// lock until the worker has died and that could cause a deadlock.
JSAutoSuspendRequest asr(cx);
dts->CancelWorkersForGlobal(static_cast<nsIScriptGlobalObject*>(this));
}
nsIScriptContext *scx = GetContextInternal();
JSContext *cx = scx ?
static_cast<JSContext*>(scx->GetNativeContext()) :
nsnull;
mozilla::dom::workers::CancelWorkersForWindow(cx, this);
// Close all IndexedDB databases for this window.
indexedDB::IndexedDatabaseManager* idbManager =
@ -9928,11 +9921,13 @@ nsGlobalWindow::SuspendTimeouts(PRUint32 aIncrease,
if (!suspended) {
DisableDeviceMotionUpdates();
nsDOMThreadService* dts = nsDOMThreadService::get();
if (dts) {
dts->SuspendWorkersForGlobal(static_cast<nsIScriptGlobalObject*>(this));
}
// Suspend all of the workers for this window.
nsIScriptContext *scx = GetContextInternal();
JSContext *cx = scx ?
static_cast<JSContext*>(scx->GetNativeContext()) :
nsnull;
mozilla::dom::workers::SuspendWorkersForWindow(cx, this);
TimeStamp now = TimeStamp::Now();
for (nsTimeout *t = FirstTimeout(); IsTimeout(t); t = t->Next()) {
// Set mTimeRemaining to be the time remaining for this timer.
@ -10004,10 +9999,12 @@ nsGlobalWindow::ResumeTimeouts(PRBool aThawChildren)
if (shouldResume) {
EnableDeviceMotionUpdates();
nsDOMThreadService* dts = nsDOMThreadService::get();
if (dts) {
dts->ResumeWorkersForGlobal(static_cast<nsIScriptGlobalObject*>(this));
}
// Resume all of the workers for this window.
nsIScriptContext *scx = GetContextInternal();
JSContext *cx = scx ?
static_cast<JSContext*>(scx->GetNativeContext()) :
nsnull;
mozilla::dom::workers::ResumeWorkersForWindow(cx, this);
// Restore all of the timeouts, using the stored time remaining
// (stored in timeout->mTimeRemaining).

Просмотреть файл

@ -3690,32 +3690,32 @@ ObjectPrincipalFinder(JSContext *cx, JSObject *obj)
return jsPrincipals;
}
static JSObject*
DOMReadStructuredClone(JSContext* cx,
JSStructuredCloneReader* reader,
uint32 tag,
uint32 data,
void* closure)
JSObject*
NS_DOMReadStructuredClone(JSContext* cx,
JSStructuredCloneReader* reader,
uint32 tag,
uint32 data,
void* closure)
{
// We don't currently support any extensions to structured cloning.
nsDOMClassInfo::ThrowJSException(cx, NS_ERROR_DOM_DATA_CLONE_ERR);
return nsnull;
}
static JSBool
DOMWriteStructuredClone(JSContext* cx,
JSStructuredCloneWriter* writer,
JSObject* obj,
void *closure)
JSBool
NS_DOMWriteStructuredClone(JSContext* cx,
JSStructuredCloneWriter* writer,
JSObject* obj,
void *closure)
{
// We don't currently support any extensions to structured cloning.
nsDOMClassInfo::ThrowJSException(cx, NS_ERROR_DOM_DATA_CLONE_ERR);
return JS_FALSE;
}
static void
DOMStructuredCloneError(JSContext* cx,
uint32 errorid)
void
NS_DOMStructuredCloneError(JSContext* cx,
uint32 errorid)
{
// We don't currently support any extensions to structured cloning.
nsDOMClassInfo::ThrowJSException(cx, NS_ERROR_DOM_DATA_CLONE_ERR);
@ -3759,9 +3759,9 @@ nsJSRuntime::Init()
// Set up the structured clone callbacks.
static JSStructuredCloneCallbacks cloneCallbacks = {
DOMReadStructuredClone,
DOMWriteStructuredClone,
DOMStructuredCloneError
NS_DOMReadStructuredClone,
NS_DOMWriteStructuredClone,
NS_DOMStructuredCloneError
};
JS_SetStructuredCloneCallbacks(sRuntime, &cloneCallbacks);

Просмотреть файл

@ -363,4 +363,14 @@ nsresult NS_CreateJSRuntime(nsIScriptRuntime **aRuntime);
/* prototypes */
void NS_ScriptErrorReporter(JSContext *cx, const char *message, JSErrorReport *report);
JSObject* NS_DOMReadStructuredClone(JSContext* cx,
JSStructuredCloneReader* reader, uint32 tag,
uint32 data, void* closure);
JSBool NS_DOMWriteStructuredClone(JSContext* cx,
JSStructuredCloneWriter* writer,
JSObject* obj, void *closure);
void NS_DOMStructuredCloneError(JSContext* cx, uint32 errorid);
#endif /* nsJSEnvironment_h___ */

Просмотреть файл

@ -7,7 +7,7 @@ DOM_SRCDIRS = \
dom/src/offline \
dom/src/geolocation \
dom/src/notification \
dom/src/threads \
dom/workers \
content/xbl/src \
content/xul/document/src \
content/events/src \

Просмотреть файл

@ -1,156 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Web Workers.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
/**
* From http://www.whatwg.org/specs/web-workers/current-work
*/
#include "nsIDOMEvent.idl"
#include "nsIDOMEventTarget.idl"
interface nsIDOMEventListener;
[scriptable, uuid(ab3725b8-3fca-40cc-a42c-92fb154ef01d)]
interface nsIWorkerMessagePort : nsISupports
{
void postMessage(/* in JSObject aMessage */);
};
[scriptable, uuid(508f2d49-e9a0-4fe8-bd33-321820173b4a)]
interface nsIWorkerMessageEvent : nsIDOMEvent
{
readonly attribute DOMString data;
readonly attribute DOMString origin;
readonly attribute nsISupports source;
void initMessageEvent(in DOMString aTypeArg,
in boolean aCanBubbleArg,
in boolean aCancelableArg,
in DOMString aDataArg,
in DOMString aOriginArg,
in nsISupports aSourceArg);
};
[scriptable, uuid(73d82c1d-05de-49c9-a23b-7121ff09a67a)]
interface nsIWorkerErrorEvent : nsIDOMEvent
{
readonly attribute DOMString message;
readonly attribute DOMString filename;
readonly attribute unsigned long lineno;
void initErrorEvent(in DOMString aTypeArg,
in boolean aCanBubbleArg,
in boolean aCancelableArg,
in DOMString aMessageArg,
in DOMString aFilenameArg,
in unsigned long aLinenoArg);
};
[scriptable, uuid(17a005c3-4f2f-4bb6-b169-c181fa6873de)]
interface nsIWorkerLocation : nsISupports
{
readonly attribute AUTF8String href;
readonly attribute AUTF8String protocol;
readonly attribute AUTF8String host;
readonly attribute AUTF8String hostname;
readonly attribute AUTF8String port;
readonly attribute AUTF8String pathname;
readonly attribute AUTF8String search;
readonly attribute AUTF8String hash;
AUTF8String toString();
};
[scriptable, uuid(74fb665a-e477-4ce2-b3c6-c58b1b28b6c3)]
interface nsIWorkerNavigator : nsISupports
{
readonly attribute DOMString appName;
readonly attribute DOMString appVersion;
readonly attribute DOMString platform;
readonly attribute DOMString userAgent;
};
[scriptable, uuid(c111e7d3-8044-4458-aa7b-637696ffb841)]
interface nsIWorkerGlobalScope : nsISupports
{
readonly attribute nsIWorkerGlobalScope self;
readonly attribute nsIWorkerNavigator navigator;
readonly attribute nsIWorkerLocation location;
attribute nsIDOMEventListener onerror;
};
[scriptable, uuid(5c55ea4b-e4ac-4ceb-bfeb-46bd5e521b8a)]
interface nsIWorkerScope : nsIWorkerGlobalScope
{
void postMessage(/* in JSObject aMessage */);
void close();
attribute nsIDOMEventListener onmessage;
attribute nsIDOMEventListener onclose;
};
[scriptable, builtinclass, uuid(b90b7561-b5e2-4545-84b0-280dbaaa94ea)]
interface nsIAbstractWorker : nsIDOMEventTarget
{
attribute nsIDOMEventListener onerror;
};
[scriptable, builtinclass, uuid(daf945c3-8d29-4724-8939-dd383f7d27a7)]
interface nsIWorker : nsIAbstractWorker
{
void postMessage(/* in JSObject aMessage */);
attribute nsIDOMEventListener onmessage;
void terminate();
};
[scriptable, uuid(cfc4bb32-ca83-4d58-9b6f-66f8054a333a)]
interface nsIWorkerFactory : nsISupports
{
nsIWorker newChromeWorker(/* in DOMString aScriptURL */);
};
%{ C++
#define NS_WORKERFACTORY_CONTRACTID \
"@mozilla.org/threads/workerfactory;1"
%}

Просмотреть файл

@ -42,6 +42,6 @@ VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
DIRS = jsurl events storage offline json geolocation threads notification
DIRS = jsurl events storage offline json geolocation notification foo
include $(topsrcdir)/config/rules.mk

Просмотреть файл

@ -1,4 +1,3 @@
#
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
@ -12,10 +11,11 @@
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is mozilla.org code.
# The Original Code is worker threads.
#
# The Initial Developer of the Original Code is Mozilla Foundation.
# Portions created by the Initial Developer are Copyright (C) 2007
# The Initial Developer of the Original Code is
# Mozilla Corporation
# Portions created by the Initial Developer are Copyright (C) 2008
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
@ -23,8 +23,8 @@
# Ben Turner <bent.mozilla@gmail.com>
#
# Alternatively, the contents of this file may be used under the terms of
# either of the GNU General Public License Version 2 or later (the "GPL"),
# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
@ -36,17 +36,20 @@
#
# ***** END LICENSE BLOCK *****
DEPTH = ../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
DEPTH = ../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
relativesrcdir = dom/src/foo
include $(DEPTH)/config/autoconf.mk
MODULE = dom
XPIDL_MODULE = dom_threads
GRE_MODULE = 1
XPIDLSRCS = nsIDOMWorkers.idl
include $(topsrcdir)/config/rules.mk
_TEST_FILES = \
test_foo.html \
$(NULL)
libs:: $(_TEST_FILES)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)

Просмотреть файл

@ -1,15 +1,16 @@
<!DOCTYPE HTML>
<html>
<!--
Tests of DOM Worker Threads
Tests of DOM Worker Threads XHR(Bug 450452 )
-->
<head>
<title>Test for DOM Worker Threads Recursion</title>
<title>Test for DOM Worker Threads XHR (Bug 450452 )</title>
<script type="text/javascript" src="/MochiKit/packed.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=450452">DOM Worker Threads XHR (Bug 450452)</a>
<p id="display"></p>
<div id="content" style="display: none">
@ -17,20 +18,10 @@ Tests of DOM Worker Threads
<pre id="test">
<script class="testbody" type="text/javascript">
var worker = new Worker("functionHandlers_worker.js");
var message = "hello!";
worker.onmessage = function(event) {
is(event.data, "uncaught exception: " + message, "Bad message!");
SimpleTest.finish();
};
worker.postMessage(message);
SimpleTest.waitForExplicitFinish();
ok(true, "passed");
</script>
</pre>
</body>
</html>

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,212 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is worker threads.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Vladimir Vukicevic <vladimir@pobox.com> (Original Author)
* Ben Turner <bent.mozilla@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef __NSDOMTHREADSERVICE_H__
#define __NSDOMTHREADSERVICE_H__
// Interfaces
#include "nsIEventTarget.h"
#include "nsIObserver.h"
#include "nsIThreadPool.h"
// Other includes
#include "jsapi.h"
#include "mozilla/ReentrantMonitor.h"
#include "nsAutoPtr.h"
#include "nsCOMPtr.h"
#include "nsDataHashtable.h"
#include "nsRefPtrHashtable.h"
#include "nsStringGlue.h"
#include "nsTPtrArray.h"
#include "prlog.h"
#ifdef PR_LOGGING
extern PRLogModuleInfo* gDOMThreadsLog;
#endif
class nsDOMWorker;
class nsDOMWorkerPool;
class nsDOMWorkerRunnable;
class nsDOMWorkerTimeout;
class nsIJSRuntimeService;
class nsIScriptGlobalObject;
class nsIThreadJSContextStack;
class nsIXPConnect;
class nsIXPCSecurityManager;
enum ThreadsafeStatus
{
Threadsafe,
NotThreadsafe,
Unknown
};
class nsDOMThreadService : public nsIEventTarget,
public nsIObserver,
public nsIThreadPoolListener
{
friend class nsDOMWorker;
friend class nsDOMWorkerNavigator;
friend class nsDOMWorkerPool;
friend class nsDOMWorkerRunnable;
friend class nsDOMWorkerThread;
friend class nsDOMWorkerTimeout;
friend class nsDOMWorkerXHR;
friend class nsDOMWorkerXHRProxy;
friend class nsLayoutStatics;
friend class nsReportErrorRunnable;
friend void DOMWorkerErrorReporter(JSContext* aCx,
const char* aMessage,
JSErrorReport* aReport);
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIEVENTTARGET
NS_DECL_NSIOBSERVER
NS_DECL_NSITHREADPOOLLISTENER
// Any DOM consumers that need access to this service should use this method.
static already_AddRefed<nsDOMThreadService> GetOrInitService();
// Simple getter for this service. This does not create the service if it
// hasn't been created already, and it never AddRef's!
static nsDOMThreadService* get();
static JSContext* GetCurrentContext();
// Easy access to the services we care about.
static nsIJSRuntimeService* JSRuntimeService();
static nsIThreadJSContextStack* ThreadJSContextStack();
static nsIXPCSecurityManager* WorkerSecurityManager();
void CancelWorkersForGlobal(nsIScriptGlobalObject* aGlobalObject);
void SuspendWorkersForGlobal(nsIScriptGlobalObject* aGlobalObject);
void ResumeWorkersForGlobal(nsIScriptGlobalObject* aGlobalObject);
nsresult ChangeThreadPoolMaxThreads(PRInt16 aDelta);
void NoteThreadsafeContractId(const nsACString& aContractId,
PRBool aIsThreadsafe);
ThreadsafeStatus GetContractIdThreadsafeStatus(const nsACString& aContractId);
private:
nsDOMThreadService();
~nsDOMThreadService();
nsresult Init();
void Cleanup();
static void Shutdown();
nsresult Dispatch(nsDOMWorker* aWorker,
nsIRunnable* aRunnable,
PRIntervalTime aTimeoutInterval = 0,
PRBool aClearQueue = PR_FALSE);
void SetWorkerTimeout(nsDOMWorker* aWorker,
PRIntervalTime aTimeoutInterval);
void WorkerComplete(nsDOMWorkerRunnable* aRunnable);
static JSContext* CreateJSContext();
already_AddRefed<nsDOMWorkerPool>
GetPoolForGlobal(nsIScriptGlobalObject* aGlobalObject,
PRBool aRemove);
void TriggerOperationCallbackForPool(nsDOMWorkerPool* aPool);
void RescheduleSuspendedWorkerForPool(nsDOMWorkerPool* aPool);
void NoteEmptyPool(nsDOMWorkerPool* aPool);
void TimeoutReady(nsDOMWorkerTimeout* aTimeout);
nsresult RegisterWorker(nsDOMWorker* aWorker,
nsIScriptGlobalObject* aGlobalObject);
void GetAppName(nsAString& aAppName);
void GetAppVersion(nsAString& aAppVersion);
void GetPlatform(nsAString& aPlatform);
void GetUserAgent(nsAString& aUserAgent);
void RegisterPrefCallbacks();
void UnregisterPrefCallbacks();
static int PrefCallback(const char* aPrefName,
void* aClosure);
static PRUint32 GetWorkerCloseHandlerTimeoutMS();
PRBool QueueSuspendedWorker(nsDOMWorkerRunnable* aRunnable);
// Our internal thread pool.
nsCOMPtr<nsIThreadPool> mThreadPool;
// Maps nsIScriptGlobalObject* to nsDOMWorkerPool.
nsRefPtrHashtable<nsVoidPtrHashKey, nsDOMWorkerPool> mPools;
// mReentrantMonitor protects all access to mWorkersInProgress and
// mCreationsInProgress.
mozilla::ReentrantMonitor mReentrantMonitor;
// A map from nsDOMWorkerThread to nsDOMWorkerRunnable.
nsRefPtrHashtable<nsVoidPtrHashKey, nsDOMWorkerRunnable> mWorkersInProgress;
// A list of active JSContexts that we've created. Always protected with
// mReentrantMonitor.
nsTArray<JSContext*> mJSContexts;
// A list of worker runnables that were never started because the worker was
// suspended. Always protected with mReentrantMonitor.
nsTArray<nsDOMWorkerRunnable*> mSuspendedWorkers;
// Always protected with mReentrantMonitor.
nsDataHashtable<nsCStringHashKey, PRBool> mThreadsafeContractIDs;
nsString mAppName;
nsString mAppVersion;
nsString mPlatform;
nsString mUserAgent;
PRBool mNavigatorStringsLoaded;
};
#endif /* __NSDOMTHREADSERVICE_H__ */

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,471 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Web Workers.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef __NSDOMWORKER_H__
#define __NSDOMWORKER_H__
#include "nsIDOMEventTarget.h"
#include "nsIDOMWorkers.h"
#include "nsIJSNativeInitializer.h"
#include "nsIPrincipal.h"
#include "nsITimer.h"
#include "nsIURI.h"
#include "nsIXPCScriptable.h"
#include "jsapi.h"
#include "mozilla/Mutex.h"
#include "nsAutoPtr.h"
#include "nsCOMPtr.h"
#include "nsTPtrArray.h"
#include "nsDOMWorkerMessageHandler.h"
// {1295EFB5-8644-42B2-8B8E-80EEF56E4284}
#define NS_WORKERFACTORY_CID \
{0x1295efb5, 0x8644, 0x42b2, \
{0x8b, 0x8e, 0x80, 0xee, 0xf5, 0x6e, 0x42, 0x84} }
class nsDOMWorker;
class nsDOMWorkerFeature;
class nsDOMWorkerMessageHandler;
class nsDOMWorkerNavigator;
class nsDOMWorkerPool;
class nsDOMWorkerTimeout;
class nsICancelable;
class nsIDOMEventListener;
class nsIEventTarget;
class nsIRunnable;
class nsIScriptGlobalObject;
class nsIXPConnectWrappedNative;
class nsDOMWorkerScope : public nsDOMWorkerMessageHandler,
public nsIWorkerScope,
public nsIXPCScriptable
{
friend class nsDOMWorker;
public:
NS_DECL_ISUPPORTS_INHERITED
// nsIDOMEventHandler
NS_FORWARD_INTERNAL_NSIDOMEVENTTARGET(nsDOMWorkerMessageHandler::)
NS_IMETHOD AddEventListener(const nsAString& aType,
nsIDOMEventListener* aListener,
PRBool aUseCapture,
PRBool aWantsUntrusted,
PRUint8 optional_argc);
NS_IMETHOD RemoveEventListener(const nsAString& aType,
nsIDOMEventListener* aListener,
PRBool aUseCapture);
NS_IMETHOD DispatchEvent(nsIDOMEvent* aEvent,
PRBool* _retval);
NS_DECL_NSIWORKERGLOBALSCOPE
NS_DECL_NSIWORKERSCOPE
NS_DECL_NSIXPCSCRIPTABLE
NS_DECL_NSICLASSINFO
typedef NS_STDCALL_FUNCPROTO(nsresult, SetListenerFunc, nsDOMWorkerScope,
SetOnmessage, (nsIDOMEventListener*));
nsDOMWorkerScope(nsDOMWorker* aWorker);
protected:
already_AddRefed<nsIXPConnectWrappedNative> GetWrappedNative();
private:
nsDOMWorker* mWorker;
nsIXPConnectWrappedNative* mWrappedNative;
nsRefPtr<nsDOMWorkerNavigator> mNavigator;
PRPackedBool mHasOnerror;
};
class nsLazyAutoRequest
{
public:
nsLazyAutoRequest() : mCx(nsnull) {}
~nsLazyAutoRequest() {
if (mCx)
JS_EndRequest(mCx);
}
void enter(JSContext *aCx) {
JS_BeginRequest(aCx);
mCx = aCx;
}
bool entered() const { return mCx != nsnull; }
void swap(nsLazyAutoRequest &other) {
JSContext *tmp = mCx;
mCx = other.mCx;
other.mCx = tmp;
}
private:
JSContext *mCx;
};
class nsDOMWorker : public nsDOMWorkerMessageHandler,
public nsIWorker,
public nsITimerCallback,
public nsIJSNativeInitializer,
public nsIXPCScriptable
{
typedef mozilla::Mutex Mutex;
friend class nsDOMWorkerFeature;
friend class nsDOMWorkerFunctions;
friend class nsDOMWorkerScope;
friend class nsDOMWorkerScriptLoader;
friend class nsDOMWorkerTimeout;
friend class nsDOMWorkerXHR;
friend class nsDOMWorkerXHRProxy;
friend class nsReportErrorRunnable;
friend class nsDOMFireEventRunnable;
friend JSBool DOMWorkerOperationCallback(JSContext* aCx);
friend void DOMWorkerErrorReporter(JSContext* aCx,
const char* aMessage,
JSErrorReport* aReport);
public:
NS_DECL_ISUPPORTS_INHERITED
// nsIDOMEventHandler
NS_FORWARD_INTERNAL_NSIDOMEVENTTARGET(nsDOMWorkerMessageHandler::)
NS_IMETHOD AddEventListener(const nsAString& aType,
nsIDOMEventListener* aListener,
PRBool aUseCapture,
PRBool aWantsUntrusted,
PRUint8 optional_argc);
NS_IMETHOD RemoveEventListener(const nsAString& aType,
nsIDOMEventListener* aListener,
PRBool aUseCapture);
NS_IMETHOD DispatchEvent(nsIDOMEvent* aEvent,
PRBool* _retval);
NS_DECL_NSIABSTRACTWORKER
NS_DECL_NSIWORKER
NS_DECL_NSITIMERCALLBACK
NS_DECL_NSICLASSINFO
NS_DECL_NSIXPCSCRIPTABLE
static nsresult NewWorker(nsISupports** aNewObject);
static nsresult NewChromeWorker(nsISupports** aNewObject);
static nsresult NewChromeDOMWorker(nsDOMWorker** aNewObject);
enum WorkerPrivilegeModel { CONTENT, CHROME };
nsDOMWorker(nsDOMWorker* aParent,
nsIXPConnectWrappedNative* aParentWN,
WorkerPrivilegeModel aModel);
NS_IMETHOD Initialize(nsISupports* aOwner,
JSContext* aCx,
JSObject* aObj,
PRUint32 aArgc,
jsval* aArgv);
nsresult InitializeInternal(nsIScriptGlobalObject* aOwner,
JSContext* aCx,
JSObject* aObj,
PRUint32 aArgc,
jsval* aArgv);
void Cancel();
void Kill();
void Suspend();
void Resume();
// This just calls IsCanceledNoLock with an autolock around the call.
PRBool IsCanceled();
PRBool IsClosing();
PRBool IsSuspended();
PRBool SetGlobalForContext(JSContext* aCx, nsLazyAutoRequest *aRequest, JSAutoEnterCompartment *aComp);
void SetPool(nsDOMWorkerPool* aPool);
nsDOMWorkerPool* Pool() {
return mPool;
}
Mutex& GetLock() {
return mLock;
}
already_AddRefed<nsIXPConnectWrappedNative> GetWrappedNative();
already_AddRefed<nsDOMWorker> GetParent();
nsDOMWorkerScope* GetInnerScope() {
return mInnerScope;
}
void SetExpirationTime(PRIntervalTime aExpirationTime);
#ifdef DEBUG
PRIntervalTime GetExpirationTime();
#endif
PRBool IsPrivileged() {
return mPrivilegeModel == CHROME;
}
static JSObject* ReadStructuredClone(JSContext* aCx,
JSStructuredCloneReader* aReader,
uint32 aTag,
uint32 aData,
void* aClosure);
/**
* Use this chart to help figure out behavior during each of the closing
* statuses. Details below.
*
* +=============+=============+=================+=======================+
* | status | clear queue | abort execution | close handler timeout |
* +=============+=============+=================+=======================+
* | eClosed | yes | no | no |
* +-------------+-------------+-----------------+-----------------------+
* | eTerminated | yes | yes | no |
* +-------------+-------------+-----------------+-----------------------+
* | eCanceled | yes | yes | yes |
* +-------------+-------------+-----------------+-----------------------+
*
*/
enum DOMWorkerStatus {
// This status means that the close handler has not yet been scheduled.
eRunning = 0,
// Inner script called Close() on the worker global scope. Setting this
// status causes the worker to clear its queue of events but does not abort
// the currently running script. The close handler is also scheduled with
// no expiration time. This status may be superseded by 'eTerminated' in
// which case the currently running script will be aborted as detailed
// below. It may also be superseded by 'eCanceled' at which point the close
// handler will be assigned an expiration time. Once the close handler has
// completed or timed out the status will be changed to 'eKilled'.
eClosed,
// Outer script called Terminate() on the worker or the worker object was
// garbage collected in its outer script. Setting this status causes the
// worker to abort immediately, clear its queue of events, and schedules the
// close handler with no expiration time. This status may be superseded by
// 'eCanceled' at which point the close handler will have an expiration time
// assigned. Once the close handler has completed or timed out the status
// will be changed to 'eKilled'.
eTerminated,
// Either the user navigated away from the owning page, the owning page fell
// out of bfcache, or the user quit the application. Setting this status
// causes the worker to abort immediately and schedules the close handler
// with an expiration time. Since the page has gone away the worker may not
// post any messages. Once the close handler has completed or timed out the
// status will be changed to 'eKilled'.
eCanceled,
// The close handler has run and the worker is effectively dead.
eKilled
};
private:
~nsDOMWorker();
nsresult PostMessageInternal(PRBool aToInner);
PRBool CompileGlobalObject(JSContext* aCx, nsLazyAutoRequest *aRequest, JSAutoEnterCompartment *aComp);
PRUint32 NextTimeoutId() {
return ++mNextTimeoutId;
}
nsresult AddFeature(nsDOMWorkerFeature* aFeature,
JSContext* aCx);
void RemoveFeature(nsDOMWorkerFeature* aFeature,
JSContext* aCx);
void CancelTimeoutWithId(PRUint32 aId);
void SuspendFeatures();
void ResumeFeatures();
nsIPrincipal* GetPrincipal() {
return mPrincipal;
}
void SetPrincipal(nsIPrincipal* aPrincipal);
nsIURI* GetBaseURI() {
return mBaseURI;
}
nsresult SetBaseURI(nsIURI* aURI);
void ClearBaseURI();
nsresult FireCloseRunnable(PRIntervalTime aTimeoutInterval,
PRBool aClearQueue,
PRBool aFromFinalize);
nsresult Close();
nsresult TerminateInternal(PRBool aFromFinalize);
nsIWorkerLocation* GetLocation() {
return mLocation;
}
PRBool QueueSuspendedRunnable(nsIRunnable* aRunnable);
// Determines if the worker should be considered "canceled". See the large
// comment in the implementation for more details.
PRBool IsCanceledNoLock();
private:
// mParent will live as long as mParentWN but only mParentWN will keep the JS
// reflection alive, so we only hold one strong reference to mParentWN.
nsDOMWorker* mParent;
nsCOMPtr<nsIXPConnectWrappedNative> mParentWN;
// Whether or not this worker has chrome privileges. Never changed after the
// worker is created.
WorkerPrivilegeModel mPrivilegeModel;
Mutex mLock;
nsRefPtr<nsDOMWorkerPool> mPool;
nsDOMWorkerScope* mInnerScope;
nsCOMPtr<nsIXPConnectWrappedNative> mScopeWN;
JSObject* mGlobal;
PRUint32 mNextTimeoutId;
nsTArray<nsDOMWorkerFeature*> mFeatures;
PRUint32 mFeatureSuspendDepth;
nsString mScriptURL;
nsIXPConnectWrappedNative* mWrappedNative;
nsCOMPtr<nsIPrincipal> mPrincipal;
nsCOMPtr<nsIURI> mBaseURI;
PRInt32 mErrorHandlerRecursionCount;
// Always protected by mLock
DOMWorkerStatus mStatus;
// Always protected by mLock
PRIntervalTime mExpirationTime;
nsCOMPtr<nsITimer> mKillTimer;
nsCOMPtr<nsIWorkerLocation> mLocation;
nsTArray<nsCOMPtr<nsIRunnable> > mQueuedRunnables;
PRPackedBool mSuspended;
PRPackedBool mCompileAttempted;
};
/**
* A worker "feature" holds the worker alive yet can be canceled, paused, and
* resumed by the worker. It is up to each derived class to implement these
* methods. This class uses a custom implementation of Release in order to
* ensure no races between Cancel and object destruction can occur, so derived
* classes must use the ISUPPORTS_INHERITED macros.
*
* To use this class you should inherit it and use the ISUPPORTS_INHERITED
* macros. Then add or remove an instance to the worker using the
* AddFeature/RemoveFeature functions.
*/
class nsDOMWorkerFeature : public nsISupports
{
friend class nsDOMWorker;
public:
NS_DECL_ISUPPORTS
nsDOMWorkerFeature(nsDOMWorker* aWorker)
: mWorker(aWorker), mWorkerWN(aWorker->GetWrappedNative()), mId(0),
mHasId(PR_FALSE), mFreeToDie(PR_TRUE) { }
nsDOMWorkerFeature(nsDOMWorker* aWorker, PRUint32 aId)
: mWorker(aWorker), mWorkerWN(aWorker->GetWrappedNative()), mId(aId),
mHasId(PR_TRUE), mFreeToDie(PR_TRUE) { }
virtual void Cancel() = 0;
virtual void Suspend() { }
virtual void Resume() { }
PRUint32 GetId() {
return mId;
}
PRBool HasId() {
return mHasId;
}
protected:
virtual ~nsDOMWorkerFeature() { }
private:
void FreeToDie(PRBool aFreeToDie) {
mFreeToDie = aFreeToDie;
}
protected:
nsRefPtr<nsDOMWorker> mWorker;
nsCOMPtr<nsIXPConnectWrappedNative> mWorkerWN;
PRUint32 mId;
private:
PRPackedBool mHasId;
PRPackedBool mFreeToDie;
};
class nsWorkerFactory : public nsIWorkerFactory
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIWORKERFACTORY
};
#endif /* __NSDOMWORKER_H__ */

Просмотреть файл

@ -1,635 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Web Workers.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsDOMWorkerEvents.h"
#include "nsIXMLHttpRequest.h"
#include "nsIXPConnect.h"
#include "jsapi.h"
#include "nsAXPCNativeCallContext.h"
#include "nsContentUtils.h"
#include "nsThreadUtils.h"
#include "nsDOMWorkerMessageHandler.h"
#include "nsDOMThreadService.h"
#include "nsDOMWorkerXHR.h"
#include "nsDOMWorkerXHRProxy.h"
NS_DEFINE_STATIC_IID_ACCESSOR(nsIDOMWorkerPrivateEvent,
NS_IDOMWORKERPRIVATEEVENT_IID)
nsDOMWorkerPrivateEvent::nsDOMWorkerPrivateEvent(nsIDOMEvent* aEvent)
: mEvent(aEvent),
mProgressEvent(do_QueryInterface(aEvent)),
mMessageEvent(do_QueryInterface(aEvent)),
mErrorEvent(do_QueryInterface(aEvent)),
mPreventDefaultCalled(PR_FALSE)
{
NS_ASSERTION(aEvent, "Null pointer!");
}
NS_IMPL_THREADSAFE_ADDREF(nsDOMWorkerPrivateEvent)
NS_IMPL_THREADSAFE_RELEASE(nsDOMWorkerPrivateEvent)
NS_INTERFACE_MAP_BEGIN(nsDOMWorkerPrivateEvent)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMWorkerPrivateEvent)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsIDOMEvent, nsIDOMWorkerPrivateEvent)
NS_INTERFACE_MAP_ENTRY(nsIDOMWorkerPrivateEvent)
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIDOMProgressEvent, mProgressEvent)
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIWorkerMessageEvent, mMessageEvent)
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIWorkerErrorEvent, mErrorEvent)
NS_INTERFACE_MAP_ENTRY(nsIClassInfo)
NS_INTERFACE_MAP_END
NS_IMPL_CI_INTERFACE_GETTER1(nsDOMWorkerPrivateEvent, nsIDOMEvent)
NS_IMPL_THREADSAFE_DOM_CI_HELPER(nsDOMWorkerPrivateEvent)
NS_IMPL_THREADSAFE_DOM_CI_ALL_THE_REST(nsDOMWorkerPrivateEvent)
NS_IMETHODIMP
nsDOMWorkerPrivateEvent::GetInterfaces(PRUint32* aCount, nsIID*** aArray)
{
nsCOMPtr<nsIClassInfo> ci(do_QueryInterface(mEvent));
if (ci) {
return ci->GetInterfaces(aCount, aArray);
}
return NS_CI_INTERFACE_GETTER_NAME(nsDOMWorkerPrivateEvent)(aCount, aArray);
}
NS_IMETHODIMP
nsDOMWorkerPrivateEvent::PreventDefault()
{
PRBool cancelable = PR_FALSE;
mEvent->GetCancelable(&cancelable);
if (cancelable) {
mPreventDefaultCalled = PR_TRUE;
}
return mEvent->PreventDefault();
}
NS_IMETHODIMP
nsDOMWorkerPrivateEvent::GetDefaultPrevented(PRBool* aRetVal)
{
*aRetVal = mPreventDefaultCalled;
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerPrivateEvent::InitEvent(const nsAString& aEventType,
PRBool aCanBubble,
PRBool aCancelable)
{
mPreventDefaultCalled = PR_FALSE;
return mEvent->InitEvent(aEventType, aCanBubble, aCancelable);
}
NS_IMETHODIMP
nsDOMWorkerPrivateEvent::InitProgressEvent(const nsAString& aTypeArg,
PRBool aCanBubbleArg,
PRBool aCancelableArg,
PRBool aLengthComputableArg,
PRUint64 aLoadedArg,
PRUint64 aTotalArg)
{
NS_ASSERTION(mProgressEvent, "Impossible!");
mPreventDefaultCalled = PR_FALSE;
return mProgressEvent->InitProgressEvent(aTypeArg, aCanBubbleArg,
aCancelableArg, aLengthComputableArg,
aLoadedArg, aTotalArg);
}
NS_IMETHODIMP
nsDOMWorkerPrivateEvent::InitMessageEvent(const nsAString& aTypeArg,
PRBool aCanBubbleArg,
PRBool aCancelableArg,
const nsAString& aDataArg,
const nsAString& aOriginArg,
nsISupports* aSourceArg)
{
NS_ASSERTION(mMessageEvent, "Impossible!");
mPreventDefaultCalled = PR_FALSE;
return mMessageEvent->InitMessageEvent(aTypeArg, aCanBubbleArg,
aCancelableArg, aDataArg, aOriginArg,
aSourceArg);
}
NS_IMETHODIMP
nsDOMWorkerPrivateEvent::InitErrorEvent(const nsAString& aTypeArg,
PRBool aCanBubbleArg,
PRBool aCancelableArg,
const nsAString& aMessageArg,
const nsAString& aFilenameArg,
PRUint32 aLinenoArg)
{
NS_ASSERTION(mErrorEvent, "Impossible!");
mPreventDefaultCalled = PR_FALSE;
return mErrorEvent->InitErrorEvent(aTypeArg, aCanBubbleArg, aCancelableArg,
aMessageArg, aFilenameArg, aLinenoArg);
}
PRBool
nsDOMWorkerPrivateEvent::PreventDefaultCalled()
{
return mPreventDefaultCalled;
}
NS_IMPL_THREADSAFE_ISUPPORTS2(nsDOMWorkerEvent, nsIDOMEvent,
nsIClassInfo)
NS_IMPL_CI_INTERFACE_GETTER1(nsDOMWorkerEvent, nsIDOMEvent)
NS_IMPL_THREADSAFE_DOM_CI(nsDOMWorkerEvent)
NS_IMETHODIMP
nsDOMWorkerEvent::GetType(nsAString& aType)
{
aType.Assign(mType);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerEvent::GetTarget(nsIDOMEventTarget** aTarget)
{
NS_ENSURE_ARG_POINTER(aTarget);
NS_IF_ADDREF(*aTarget = mTarget);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerEvent::GetCurrentTarget(nsIDOMEventTarget** aCurrentTarget)
{
NS_ENSURE_ARG_POINTER(aCurrentTarget);
NS_IF_ADDREF(*aCurrentTarget = mTarget);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerEvent::GetEventPhase(PRUint16* aEventPhase)
{
NS_ENSURE_ARG_POINTER(aEventPhase);
*aEventPhase = mEventPhase;
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerEvent::GetBubbles(PRBool* aBubbles)
{
NS_ENSURE_ARG_POINTER(aBubbles);
*aBubbles = mBubbles;
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerEvent::GetCancelable(PRBool* aCancelable)
{
NS_ENSURE_ARG_POINTER(aCancelable);
*aCancelable = mCancelable;
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerEvent::GetTimeStamp(DOMTimeStamp* aTimeStamp)
{
NS_ENSURE_ARG_POINTER(aTimeStamp);
*aTimeStamp = mTimeStamp;
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerEvent::StopPropagation()
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsDOMWorkerEvent::PreventDefault()
{
mPreventDefaultCalled = PR_TRUE;
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerEvent::GetDefaultPrevented(PRBool* aRetVal)
{
*aRetVal = mPreventDefaultCalled;
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerEvent::InitEvent(const nsAString& aEventTypeArg,
PRBool aCanBubbleArg,
PRBool aCancelableArg)
{
NS_ENSURE_FALSE(aEventTypeArg.IsEmpty(), NS_ERROR_INVALID_ARG);
mType.Assign(aEventTypeArg);
mBubbles = aCanBubbleArg;
mCancelable = aCancelableArg;
mPreventDefaultCalled = PR_FALSE;
mTimeStamp = PR_Now();
return NS_OK;
}
nsDOMWorkerMessageEvent::~nsDOMWorkerMessageEvent()
{
if (mData) {
JSContext* cx = nsDOMThreadService::GetCurrentContext();
if (cx) {
JS_free(cx, mData);
}
else {
NS_WARNING("Failed to get safe JSContext, leaking event data!");
}
}
}
NS_IMPL_ISUPPORTS_INHERITED1(nsDOMWorkerMessageEvent, nsDOMWorkerEvent,
nsIWorkerMessageEvent)
NS_IMPL_CI_INTERFACE_GETTER2(nsDOMWorkerMessageEvent, nsIDOMEvent,
nsIWorkerMessageEvent)
NS_IMPL_THREADSAFE_DOM_CI_GETINTERFACES(nsDOMWorkerMessageEvent)
nsresult
nsDOMWorkerMessageEvent::SetJSData(
JSContext* aCx,
JSAutoStructuredCloneBuffer& aBuffer,
nsTArray<nsCOMPtr<nsISupports> >& aWrappedNatives)
{
NS_ASSERTION(aCx, "Null context!");
if (!mDataVal.Hold(aCx)) {
NS_WARNING("Failed to hold jsval!");
return NS_ERROR_FAILURE;
}
if (!mWrappedNatives.SwapElements(aWrappedNatives)) {
NS_ERROR("This should never fail!");
}
aBuffer.steal(&mData, &mDataLen);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerMessageEvent::GetData(nsAString& aData)
{
nsIXPConnect* xpc = nsContentUtils::XPConnect();
NS_ENSURE_TRUE(xpc, NS_ERROR_UNEXPECTED);
nsAXPCNativeCallContext* cc;
nsresult rv = xpc->GetCurrentNativeCallContext(&cc);
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(cc, NS_ERROR_UNEXPECTED);
if (mData) {
JSContext* cx;
rv = cc->GetJSContext(&cx);
NS_ENSURE_SUCCESS(rv, rv);
JSAutoRequest ar(cx);
JSAutoStructuredCloneBuffer buffer;
buffer.adopt(cx, mData, mDataLen);
mData = nsnull;
mDataLen = 0;
JSStructuredCloneCallbacks callbacks = {
nsDOMWorker::ReadStructuredClone, nsnull, nsnull
};
JSBool ok = buffer.read(mDataVal.ToJSValPtr(), cx, &callbacks);
// Release wrapped natives now, regardless of whether or not the deserialize
// succeeded.
mWrappedNatives.Clear();
if (!ok) {
NS_WARNING("Failed to deserialize!");
return NS_ERROR_FAILURE;
}
}
jsval* retval;
rv = cc->GetRetValPtr(&retval);
NS_ENSURE_SUCCESS(rv, rv);
cc->SetReturnValueWasSet(PR_TRUE);
*retval = mDataVal;
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerMessageEvent::GetOrigin(nsAString& aOrigin)
{
aOrigin.Assign(mOrigin);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerMessageEvent::GetSource(nsISupports** aSource)
{
NS_ENSURE_ARG_POINTER(aSource);
NS_IF_ADDREF(*aSource = mSource);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerMessageEvent::InitMessageEvent(const nsAString& aTypeArg,
PRBool aCanBubbleArg,
PRBool aCancelableArg,
const nsAString& aDataArg,
const nsAString& aOriginArg,
nsISupports* aSourceArg)
{
mOrigin.Assign(aOriginArg);
mSource = aSourceArg;
return nsDOMWorkerEvent::InitEvent(aTypeArg, aCanBubbleArg, aCancelableArg);
}
NS_IMPL_ISUPPORTS_INHERITED1(nsDOMWorkerProgressEvent, nsDOMWorkerEvent,
nsIDOMProgressEvent)
NS_IMPL_CI_INTERFACE_GETTER2(nsDOMWorkerProgressEvent, nsIDOMEvent,
nsIDOMProgressEvent)
NS_IMPL_THREADSAFE_DOM_CI_GETINTERFACES(nsDOMWorkerProgressEvent)
NS_IMETHODIMP
nsDOMWorkerProgressEvent::GetLengthComputable(PRBool* aLengthComputable)
{
NS_ENSURE_ARG_POINTER(aLengthComputable);
*aLengthComputable = mLengthComputable;
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerProgressEvent::GetLoaded(PRUint64* aLoaded)
{
NS_ENSURE_ARG_POINTER(aLoaded);
*aLoaded = mLoaded;
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerProgressEvent::GetTotal(PRUint64* aTotal)
{
NS_ENSURE_ARG_POINTER(aTotal);
*aTotal = mTotal;
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerProgressEvent::InitProgressEvent(const nsAString_internal& aTypeArg,
PRBool aCanBubbleArg,
PRBool aCancelableArg,
PRBool aLengthComputableArg,
PRUint64 aLoadedArg,
PRUint64 aTotalArg)
{
mLengthComputable = aLengthComputableArg;
mLoaded = aLoadedArg;
mTotal = aTotalArg;
return nsDOMWorkerEvent::InitEvent(aTypeArg, aCanBubbleArg, aCancelableArg);
}
NS_IMPL_THREADSAFE_ADDREF(nsDOMWorkerXHRState)
NS_IMPL_THREADSAFE_RELEASE(nsDOMWorkerXHRState)
nsDOMWorkerXHREvent::nsDOMWorkerXHREvent(nsDOMWorkerXHRProxy* aXHRProxy)
: mXHRProxy(aXHRProxy),
mXHREventType(PR_UINT32_MAX),
mChannelID(-1),
mUploadEvent(PR_FALSE),
mProgressEvent(PR_FALSE)
{
NS_ASSERTION(aXHRProxy, "Can't be null!");
}
NS_IMPL_ADDREF_INHERITED(nsDOMWorkerXHREvent, nsDOMWorkerProgressEvent)
NS_IMPL_RELEASE_INHERITED(nsDOMWorkerXHREvent, nsDOMWorkerProgressEvent)
NS_INTERFACE_MAP_BEGIN(nsDOMWorkerXHREvent)
NS_INTERFACE_MAP_ENTRY(nsIRunnable)
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIDOMProgressEvent, mProgressEvent)
NS_INTERFACE_MAP_END_INHERITING(nsDOMWorkerEvent)
NS_IMETHODIMP
nsDOMWorkerXHREvent::GetInterfaces(PRUint32* aCount,
nsIID*** aArray)
{
PRUint32 count = *aCount = mProgressEvent ? 2 : 1;
*aArray = (nsIID**)nsMemory::Alloc(sizeof(nsIID*) * count);
if (mProgressEvent) {
(*aArray)[--count] =
(nsIID*)nsMemory::Clone(&NS_GET_IID(nsIDOMProgressEvent), sizeof(nsIID));
}
(*aArray)[--count] =
(nsIID *)nsMemory::Clone(&NS_GET_IID(nsIDOMEvent), sizeof(nsIID));
NS_ASSERTION(!count, "Bad math!");
return NS_OK;
}
nsresult
nsDOMWorkerXHREvent::Init(PRUint32 aXHREventType,
const nsAString& aType,
nsIDOMEvent* aEvent,
SnapshotChoice aSnapshot)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(aEvent, "Don't pass null here!");
mXHREventType = aXHREventType;
// Only set a channel id if we're not going to be run immediately.
mChannelID = mXHRProxy->mSyncEventQueue ? -1 : mXHRProxy->ChannelID();
mTarget = static_cast<nsDOMWorkerMessageHandler*>(mXHRProxy->mWorkerXHR);
NS_ENSURE_TRUE(mTarget, NS_ERROR_UNEXPECTED);
mXHRWN = mXHRProxy->mWorkerXHR->GetWrappedNative();
NS_ENSURE_STATE(mXHRWN);
nsCOMPtr<nsIDOMEventTarget> mainThreadTarget;
nsresult rv = aEvent->GetTarget(getter_AddRefs(mainThreadTarget));
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_STATE(mainThreadTarget);
nsCOMPtr<nsIXMLHttpRequestUpload> upload(do_QueryInterface(mainThreadTarget));
if (upload) {
mUploadEvent = PR_TRUE;
mTarget =
static_cast<nsDOMWorkerMessageHandler*>(mXHRProxy->mWorkerXHR->mUpload);
}
else {
mUploadEvent = PR_FALSE;
mTarget = static_cast<nsDOMWorkerMessageHandler*>(mXHRProxy->mWorkerXHR);
}
NS_ASSERTION(mTarget, "Null target!");
PRBool bubbles;
rv = aEvent->GetBubbles(&bubbles);
NS_ENSURE_SUCCESS(rv, rv);
PRBool cancelable;
rv = aEvent->GetCancelable(&cancelable);
NS_ENSURE_SUCCESS(rv, rv);
rv = aEvent->GetTimeStamp(&mTimeStamp);
NS_ENSURE_SUCCESS(rv, rv);
rv = aEvent->GetEventPhase(&mEventPhase);
NS_ENSURE_SUCCESS(rv, rv);
NS_ASSERTION(mEventPhase == nsIDOMEvent::AT_TARGET, "Unsupported phase!");
nsCOMPtr<nsIDOMProgressEvent> progressEvent(do_QueryInterface(aEvent));
if (progressEvent) {
mProgressEvent = PR_TRUE;
PRBool lengthComputable;
rv = progressEvent->GetLengthComputable(&lengthComputable);
NS_ENSURE_SUCCESS(rv, rv);
PRUint64 loaded;
rv = progressEvent->GetLoaded(&loaded);
NS_ENSURE_SUCCESS(rv, rv);
PRUint64 total;
rv = progressEvent->GetTotal(&total);
NS_ENSURE_SUCCESS(rv, rv);
rv = InitProgressEvent(aType, bubbles, cancelable, lengthComputable, loaded,
total);
NS_ENSURE_SUCCESS(rv, rv);
}
else {
mProgressEvent = PR_FALSE;
rv = InitEvent(aType, bubbles, cancelable);
NS_ENSURE_SUCCESS(rv, rv);
}
mState = new nsDOMWorkerXHRState();
NS_ENSURE_TRUE(mState, NS_ERROR_OUT_OF_MEMORY);
if (aSnapshot == SNAPSHOT) {
SnapshotXHRState(mXHRProxy->mXHR, mState);
}
return NS_OK;
}
/* static */
void
nsDOMWorkerXHREvent::SnapshotXHRState(nsIXMLHttpRequest* aXHR,
nsDOMWorkerXHRState* aState)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(aXHR && aState, "Don't pass null here!");
aState->responseTextResult = aXHR->GetResponseText(aState->responseText);
aState->statusTextResult = aXHR->GetStatusText(aState->statusText);
aState->statusResult = aXHR->GetStatus(&aState->status);
aState->readyStateResult = aXHR->GetReadyState(&aState->readyState);
}
NS_IMETHODIMP
nsDOMWorkerXHREvent::Run()
{
nsresult rv = mXHRProxy->HandleWorkerEvent(this, mUploadEvent);
// Prevent reference cycles by releasing this here.
mXHRProxy = nsnull;
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMPL_ISUPPORTS_INHERITED1(nsDOMWorkerErrorEvent, nsDOMWorkerEvent,
nsIWorkerErrorEvent)
NS_IMPL_CI_INTERFACE_GETTER2(nsDOMWorkerErrorEvent, nsIDOMEvent,
nsIWorkerErrorEvent)
NS_IMPL_THREADSAFE_DOM_CI_GETINTERFACES(nsDOMWorkerErrorEvent)
nsresult
nsDOMWorkerErrorEvent::GetMessage(nsAString& aMessage)
{
aMessage.Assign(mMessage);
return NS_OK;
}
nsresult
nsDOMWorkerErrorEvent::GetFilename(nsAString& aFilename)
{
aFilename.Assign(mFilename);
return NS_OK;
}
nsresult
nsDOMWorkerErrorEvent::GetLineno(PRUint32* aLineno)
{
NS_ENSURE_ARG_POINTER(aLineno);
*aLineno = mLineno;
return NS_OK;
}
nsresult
nsDOMWorkerErrorEvent::InitErrorEvent(const nsAString& aTypeArg,
PRBool aCanBubbleArg,
PRBool aCancelableArg,
const nsAString& aMessageArg,
const nsAString& aFilenameArg,
PRUint32 aLinenoArg)
{
mMessage.Assign(aMessageArg);
mFilename.Assign(aFilenameArg);
mLineno = aLinenoArg;
return InitEvent(aTypeArg, aCanBubbleArg, aCancelableArg);
}

Просмотреть файл

@ -1,340 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Web Workers.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef __NSDOMWORKEREVENTS_H__
#define __NSDOMWORKEREVENTS_H__
#include "nsIClassInfo.h"
#include "nsIDOMEvent.h"
#include "nsIDOMEventTarget.h"
#include "nsIDOMProgressEvent.h"
#include "nsIDOMWorkers.h"
#include "nsIRunnable.h"
#include "jsapi.h"
#include "jsutil.h"
#include "nsAutoJSValHolder.h"
#include "nsAutoPtr.h"
#include "nsCOMPtr.h"
#include "nsStringGlue.h"
#include "nsDOMWorkerMacros.h"
class nsDOMWorkerXHRProxy;
class nsIXMLHttpRequest;
class nsIXPConnectWrappedNative;
/* 4d5794d6-98ab-4a6b-ad5a-8ed1fa1d4839 */
#define NS_IDOMWORKERPRIVATEEVENT_IID \
{ \
0x4d5794d6, \
0x98ab, \
0x4a6b, \
{ 0xad, 0x5a, 0x8e, 0xd1, 0xfa, 0x1d, 0x48, 0x39 } \
}
class nsIDOMWorkerPrivateEvent : public nsIDOMEvent
{
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IDOMWORKERPRIVATEEVENT_IID)
virtual PRBool PreventDefaultCalled() = 0;
};
#define NS_FORWARD_NSIDOMEVENT_SPECIAL \
NS_IMETHOD GetType(nsAString& aType) \
{ return mEvent->GetType(aType); } \
NS_IMETHOD GetTarget(nsIDOMEventTarget** aTarget) \
{ return mEvent->GetTarget(aTarget); } \
NS_IMETHOD GetCurrentTarget(nsIDOMEventTarget** aCurrentTarget) \
{ return mEvent->GetCurrentTarget(aCurrentTarget); } \
NS_IMETHOD GetEventPhase(PRUint16* aEventPhase) \
{ return mEvent->GetEventPhase(aEventPhase); } \
NS_IMETHOD GetBubbles(PRBool* aBubbles) \
{ return mEvent->GetBubbles(aBubbles); } \
NS_IMETHOD GetCancelable(PRBool* aCancelable) \
{ return mEvent->GetCancelable(aCancelable); } \
NS_IMETHOD GetTimeStamp(DOMTimeStamp* aTimeStamp) \
{ return mEvent->GetTimeStamp(aTimeStamp); } \
NS_IMETHOD StopPropagation() \
{ return mEvent->StopPropagation(); }
#define NS_FORWARD_NSIDOMPROGRESSEVENT_SPECIAL \
NS_IMETHOD GetLengthComputable(PRBool* aLengthComputable) \
{ return mProgressEvent->GetLengthComputable(aLengthComputable); } \
NS_IMETHOD GetLoaded(PRUint64* aLoaded) \
{ return mProgressEvent->GetLoaded(aLoaded); } \
NS_IMETHOD GetTotal(PRUint64* aTotal) \
{ return mProgressEvent->GetTotal(aTotal); }
#define NS_FORWARD_NSIWORKERMESSAGEEVENT_SPECIAL \
NS_IMETHOD GetData(nsAString& aData) \
{ return mMessageEvent->GetData(aData); } \
NS_IMETHOD GetOrigin(nsAString& aOrigin) \
{ return mMessageEvent->GetOrigin(aOrigin); } \
NS_IMETHOD GetSource(nsISupports** aSource) \
{ return mMessageEvent->GetSource(aSource); }
#define NS_FORWARD_NSIWORKERERROREVENT_SPECIAL \
NS_IMETHOD GetMessage(nsAString& aMessage) \
{ return mErrorEvent->GetMessage(aMessage); } \
NS_IMETHOD GetFilename(nsAString& aFilename) \
{ return mErrorEvent->GetFilename(aFilename); } \
NS_IMETHOD GetLineno(PRUint32* aLineno) \
{ return mErrorEvent->GetLineno(aLineno); }
class nsDOMWorkerPrivateEvent : public nsIDOMWorkerPrivateEvent,
public nsIDOMProgressEvent,
public nsIWorkerMessageEvent,
public nsIWorkerErrorEvent,
public nsIClassInfo
{
public:
NS_DECL_ISUPPORTS
NS_FORWARD_NSIDOMEVENT_SPECIAL
NS_FORWARD_NSIWORKERMESSAGEEVENT_SPECIAL
NS_FORWARD_NSIDOMPROGRESSEVENT_SPECIAL
NS_FORWARD_NSIWORKERERROREVENT_SPECIAL
NS_DECL_NSICLASSINFO
nsDOMWorkerPrivateEvent(nsIDOMEvent* aEvent);
NS_IMETHOD PreventDefault();
NS_IMETHOD InitEvent(const nsAString& aEventType,
PRBool aCanBubble,
PRBool aCancelable);
NS_IMETHOD InitProgressEvent(const nsAString& aTypeArg,
PRBool aCanBubbleArg,
PRBool aCancelableArg,
PRBool aLengthComputableArg,
PRUint64 aLoadedArg,
PRUint64 aTotalArg);
NS_IMETHOD InitMessageEvent(const nsAString& aTypeArg,
PRBool aCanBubbleArg,
PRBool aCancelableArg,
const nsAString& aDataArg,
const nsAString& aOriginArg,
nsISupports* aSourceArg);
NS_IMETHOD InitErrorEvent(const nsAString& aTypeArg,
PRBool aCanBubbleArg,
PRBool aCancelableArg,
const nsAString& aMessageArg,
const nsAString& aFilenameArg,
PRUint32 aLinenoArg);
NS_IMETHOD GetDefaultPrevented(PRBool* aRetVal);
virtual PRBool PreventDefaultCalled();
private:
nsCOMPtr<nsIDOMEvent> mEvent;
nsCOMPtr<nsIDOMProgressEvent> mProgressEvent;
nsCOMPtr<nsIWorkerMessageEvent> mMessageEvent;
nsCOMPtr<nsIWorkerErrorEvent> mErrorEvent;
PRBool mPreventDefaultCalled;
};
class nsDOMWorkerEvent : public nsIDOMEvent,
public nsIClassInfo
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIDOMEVENT
NS_DECL_NSICLASSINFO
nsDOMWorkerEvent()
: mEventPhase(nsIDOMEvent::AT_TARGET), mTimeStamp(0), mBubbles(PR_FALSE),
mCancelable(PR_FALSE), mPreventDefaultCalled(PR_FALSE) { }
void SetTarget(nsIDOMEventTarget* aTarget) {
mTarget = aTarget;
}
PRBool PreventDefaultCalled() {
return PRBool(mPreventDefaultCalled);
}
protected:
virtual ~nsDOMWorkerEvent() { }
nsString mType;
nsCOMPtr<nsIDOMEventTarget> mTarget;
PRUint16 mEventPhase;
DOMTimeStamp mTimeStamp;
PRPackedBool mBubbles;
PRPackedBool mCancelable;
PRPackedBool mPreventDefaultCalled;
};
class nsDOMWorkerMessageEvent : public nsDOMWorkerEvent,
public nsIWorkerMessageEvent
{
public:
NS_DECL_ISUPPORTS_INHERITED
NS_FORWARD_NSIDOMEVENT(nsDOMWorkerEvent::)
NS_DECL_NSIWORKERMESSAGEEVENT
NS_DECL_NSICLASSINFO_GETINTERFACES
nsDOMWorkerMessageEvent() : mData(nsnull) { }
~nsDOMWorkerMessageEvent();
nsresult SetJSData(JSContext* aCx,
JSAutoStructuredCloneBuffer& aBuffer,
nsTArray<nsCOMPtr<nsISupports> >& aWrappedNatives);
protected:
nsString mOrigin;
nsCOMPtr<nsISupports> mSource;
nsAutoJSValHolder mDataVal;
uint64* mData;
size_t mDataLen;
nsTArray<nsCOMPtr<nsISupports> > mWrappedNatives;
};
class nsDOMWorkerProgressEvent : public nsDOMWorkerEvent,
public nsIDOMProgressEvent
{
public:
NS_DECL_ISUPPORTS_INHERITED
NS_FORWARD_NSIDOMEVENT(nsDOMWorkerEvent::)
NS_DECL_NSIDOMPROGRESSEVENT
NS_DECL_NSICLASSINFO_GETINTERFACES
nsDOMWorkerProgressEvent()
: mLoaded(0), mTotal(0), mLengthComputable(PR_FALSE) { }
protected:
PRUint64 mLoaded;
PRUint64 mTotal;
PRBool mLengthComputable;
};
class nsDOMWorkerXHRState
{
public:
nsDOMWorkerXHRState()
: responseTextResult(NS_OK), statusTextResult(NS_OK), status(NS_OK),
statusResult(NS_OK), readyState(0), readyStateResult(NS_OK) { }
NS_IMETHOD_(nsrefcnt) AddRef();
NS_IMETHOD_(nsrefcnt) Release();
nsString responseText;
nsresult responseTextResult;
nsCString statusText;
nsresult statusTextResult;
nsresult status;
nsresult statusResult;
PRUint16 readyState;
nsresult readyStateResult;
protected:
virtual ~nsDOMWorkerXHRState() { }
nsAutoRefCnt mRefCnt;
};
class nsDOMWorkerXHREvent : public nsDOMWorkerProgressEvent,
public nsIRunnable
{
friend class nsDOMWorkerXHRProxy;
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIRUNNABLE
NS_DECL_NSICLASSINFO_GETINTERFACES
enum SnapshotChoice {
SNAPSHOT,
NO_SNAPSHOT
};
nsDOMWorkerXHREvent(nsDOMWorkerXHRProxy* aXHRProxy);
nsresult Init(PRUint32 aXHREventType,
const nsAString& aType,
nsIDOMEvent* aEvent,
SnapshotChoice = SNAPSHOT);
static void SnapshotXHRState(nsIXMLHttpRequest* aXHR,
nsDOMWorkerXHRState* aState);
already_AddRefed<nsDOMWorkerXHRState> ForgetState() {
return mState.forget();
}
protected:
nsDOMWorkerXHRState* GetState() {
return mState;
}
nsRefPtr<nsDOMWorkerXHRProxy> mXHRProxy;
nsCOMPtr<nsIXPConnectWrappedNative> mXHRWN;
nsRefPtr<nsDOMWorkerXHRState> mState;
PRUint32 mXHREventType;
PRInt32 mChannelID;
PRPackedBool mUploadEvent;
PRPackedBool mProgressEvent;
};
class nsDOMWorkerErrorEvent : public nsDOMWorkerEvent,
public nsIWorkerErrorEvent
{
public:
NS_DECL_ISUPPORTS_INHERITED
NS_FORWARD_NSIDOMEVENT(nsDOMWorkerEvent::)
NS_DECL_NSIWORKERERROREVENT
NS_DECL_NSICLASSINFO_GETINTERFACES
nsDOMWorkerErrorEvent()
: mLineno(0) { }
protected:
nsString mMessage;
nsString mFilename;
PRUint32 mLineno;
};
#endif /* __NSDOMWORKEREVENTS_H__ */

Просмотреть файл

@ -1,223 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is worker threads.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsDOMWorkerLocation.h"
#include "nsIClassInfoImpl.h"
#include "nsITextToSubURI.h"
#include "nsIURL.h"
#include "nsDOMWorkerMacros.h"
#include "nsAutoPtr.h"
#include "nsEscape.h"
#include "nsNetUtil.h"
#define XPC_MAP_CLASSNAME nsDOMWorkerLocation
#define XPC_MAP_QUOTED_CLASSNAME "WorkerLocation"
#define XPC_MAP_FLAGS \
nsIXPCScriptable::USE_JSSTUB_FOR_ADDPROPERTY | \
nsIXPCScriptable::USE_JSSTUB_FOR_DELPROPERTY | \
nsIXPCScriptable::USE_JSSTUB_FOR_SETPROPERTY | \
nsIXPCScriptable::DONT_ENUM_QUERY_INTERFACE | \
nsIXPCScriptable::CLASSINFO_INTERFACES_ONLY | \
nsIXPCScriptable::DONT_REFLECT_INTERFACE_NAMES
#include "xpc_map_end.h"
NS_IMPL_THREADSAFE_ISUPPORTS3(nsDOMWorkerLocation, nsIWorkerLocation,
nsIClassInfo,
nsIXPCScriptable)
NS_IMPL_CI_INTERFACE_GETTER1(nsDOMWorkerLocation, nsIWorkerLocation)
NS_IMPL_THREADSAFE_DOM_CI_GETINTERFACES(nsDOMWorkerLocation)
NS_IMPL_THREADSAFE_DOM_CI_ALL_THE_REST(nsDOMWorkerLocation)
NS_IMETHODIMP
nsDOMWorkerLocation::GetHelperForLanguage(PRUint32 aLanguage,
nsISupports** _retval)
{
if (aLanguage == nsIProgrammingLanguage::JAVASCRIPT) {
NS_ADDREF(*_retval = NS_ISUPPORTS_CAST(nsIWorkerLocation*, this));
}
else {
*_retval = nsnull;
}
return NS_OK;
}
// static
already_AddRefed<nsIWorkerLocation>
nsDOMWorkerLocation::NewLocation(nsIURL* aURL)
{
NS_ASSERTION(aURL, "Don't hand me a null pointer!");
nsAutoPtr<nsDOMWorkerLocation> location(new nsDOMWorkerLocation());
NS_ENSURE_TRUE(location, nsnull);
nsresult rv = aURL->GetSpec(location->mHref);
NS_ENSURE_SUCCESS(rv, nsnull);
rv = aURL->GetHost(location->mHostname);
NS_ENSURE_SUCCESS(rv, nsnull);
rv = aURL->GetPath(location->mPathname);
NS_ENSURE_SUCCESS(rv, nsnull);
nsCString temp;
rv = aURL->GetQuery(temp);
NS_ENSURE_SUCCESS(rv, nsnull);
if (!temp.IsEmpty()) {
location->mSearch.AssignLiteral("?");
location->mSearch.Append(temp);
}
rv = aURL->GetRef(temp);
NS_ENSURE_SUCCESS(rv, nsnull);
if (!temp.IsEmpty()) {
nsAutoString unicodeRef;
nsCOMPtr<nsITextToSubURI> converter =
do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv);
if (NS_SUCCEEDED(rv)) {
nsCString charset;
rv = aURL->GetOriginCharset(charset);
if (NS_SUCCEEDED(rv)) {
rv = converter->UnEscapeURIForUI(charset, temp, unicodeRef);
if (NS_SUCCEEDED(rv)) {
location->mHash.AssignLiteral("#");
location->mHash.Append(NS_ConvertUTF16toUTF8(unicodeRef));
}
}
}
if (NS_FAILED(rv)) {
location->mHash.AssignLiteral("#");
location->mHash.Append(temp);
}
}
rv = aURL->GetScheme(location->mProtocol);
NS_ENSURE_SUCCESS(rv, nsnull);
location->mProtocol.AppendLiteral(":");
PRInt32 port;
rv = aURL->GetPort(&port);
if (NS_SUCCEEDED(rv) && port != -1) {
location->mPort.AppendInt(port);
nsCAutoString host(location->mHostname);
host.AppendLiteral(":");
host.Append(location->mPort);
location->mHost.Assign(host);
}
else {
location->mHost.Assign(location->mHostname);
}
NS_ADDREF(location);
return location.forget();
}
NS_IMETHODIMP
nsDOMWorkerLocation::GetHref(nsACString& aHref)
{
aHref.Assign(mHref);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerLocation::GetProtocol(nsACString& aProtocol)
{
aProtocol.Assign(mProtocol);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerLocation::GetHost(nsACString& aHost)
{
aHost.Assign(mHost);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerLocation::GetHostname(nsACString& aHostname)
{
aHostname.Assign(mHostname);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerLocation::GetPort(nsACString& aPort)
{
aPort.Assign(mPort);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerLocation::GetPathname(nsACString& aPathname)
{
aPathname.Assign(mPathname);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerLocation::GetSearch(nsACString& aSearch)
{
aSearch.Assign(mSearch);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerLocation::GetHash(nsACString& aHash)
{
aHash.Assign(mHash);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerLocation::ToString(nsACString& _retval)
{
return GetHref(_retval);
}

Просмотреть файл

@ -1,135 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Web Workers.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef __NSDOMWORKERMACROS_H__
#define __NSDOMWORKERMACROS_H__
// Macro to generate nsIClassInfo methods for these threadsafe DOM classes
#define NS_IMPL_THREADSAFE_DOM_CI_GETINTERFACES(_class) \
NS_IMETHODIMP \
_class::GetInterfaces(PRUint32* _count, nsIID*** _array) \
{ \
return NS_CI_INTERFACE_GETTER_NAME(_class)(_count, _array); \
} \
#define NS_IMPL_THREADSAFE_DOM_CI_HELPER(_class) \
NS_IMETHODIMP \
_class::GetHelperForLanguage(PRUint32 _language, nsISupports** _retval) \
{ \
*_retval = nsnull; \
return NS_OK; \
}
#define NS_IMPL_THREADSAFE_DOM_CI_ALL_THE_REST(_class) \
NS_IMETHODIMP \
_class::GetContractID(char** _contractID) \
{ \
*_contractID = nsnull; \
return NS_OK; \
} \
\
NS_IMETHODIMP \
_class::GetClassDescription(char** _classDescription) \
{ \
*_classDescription = nsnull; \
return NS_OK; \
} \
\
NS_IMETHODIMP \
_class::GetClassID(nsCID** _classID) \
{ \
*_classID = nsnull; \
return NS_OK; \
} \
\
NS_IMETHODIMP \
_class::GetImplementationLanguage(PRUint32* _language) \
{ \
*_language = nsIProgrammingLanguage::CPLUSPLUS; \
return NS_OK; \
} \
\
NS_IMETHODIMP \
_class::GetFlags(PRUint32* _flags) \
{ \
*_flags = nsIClassInfo::THREADSAFE | nsIClassInfo::DOM_OBJECT; \
return NS_OK; \
} \
\
NS_IMETHODIMP \
_class::GetClassIDNoAlloc(nsCID* _classIDNoAlloc) \
{ \
return NS_ERROR_NOT_AVAILABLE; \
}
#define NS_IMPL_THREADSAFE_DOM_CI(_class) \
NS_IMPL_THREADSAFE_DOM_CI_GETINTERFACES(_class) \
NS_IMPL_THREADSAFE_DOM_CI_HELPER(_class) \
NS_IMPL_THREADSAFE_DOM_CI_ALL_THE_REST(_class)
#define NS_FORWARD_NSICLASSINFO_NOGETINTERFACES(_to) \
NS_IMETHOD GetHelperForLanguage(PRUint32 aLanguage, nsISupports** _retval) \
{ return _to GetHelperForLanguage(aLanguage, _retval); } \
NS_IMETHOD GetContractID(char** aContractID) \
{ return _to GetContractID(aContractID); } \
NS_IMETHOD GetClassDescription(char** aClassDescription) \
{ return _to GetClassDescription(aClassDescription); } \
NS_IMETHOD GetClassID(nsCID** aClassID) \
{ return _to GetClassID(aClassID); } \
NS_IMETHOD GetImplementationLanguage(PRUint32* aImplementationLanguage) \
{ return _to GetImplementationLanguage(aImplementationLanguage); } \
NS_IMETHOD GetFlags(PRUint32* aFlags) \
{ return _to GetFlags(aFlags); } \
NS_IMETHOD GetClassIDNoAlloc(nsCID* aClassIDNoAlloc) \
{ return _to GetClassIDNoAlloc(aClassIDNoAlloc); }
#define NS_DECL_NSICLASSINFO_GETINTERFACES \
NS_IMETHOD GetInterfaces(PRUint32* aCount, nsIID*** aArray);
// Don't know why nsISupports.idl defines this out...
#define NS_FORWARD_NSISUPPORTS(_to) \
NS_IMETHOD QueryInterface(const nsIID& uuid, void** result) { \
return _to QueryInterface(uuid, result); \
} \
NS_IMETHOD_(nsrefcnt) AddRef(void) { return _to AddRef(); } \
NS_IMETHOD_(nsrefcnt) Release(void) { return _to Release(); }
#define JSON_PRIMITIVE_PROPNAME \
"primitive"
#endif /* __NSDOMWORKERMACROS_H__ */

Просмотреть файл

@ -1,440 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Web Workers.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsDOMWorkerMessageHandler.h"
#include "nsIDOMEvent.h"
#include "nsIXPConnect.h"
#include "nsContentUtils.h"
#include "nsDOMThreadService.h"
#include "nsDOMWorkerEvents.h"
NS_IMPL_THREADSAFE_ADDREF(nsDOMWorkerEventListenerBase)
NS_IMPL_THREADSAFE_RELEASE(nsDOMWorkerEventListenerBase)
nsresult
nsDOMWorkerWeakEventListener::Init(nsIDOMEventListener* aListener)
{
NS_ENSURE_ARG_POINTER(aListener);
nsCOMPtr<nsIXPConnectWrappedJS> wrappedJS(do_QueryInterface(aListener));
NS_ENSURE_TRUE(wrappedJS, NS_NOINTERFACE);
JSObject* obj;
nsresult rv = wrappedJS->GetJSObject(&obj);
NS_ENSURE_SUCCESS(rv, rv);
mObj = obj;
return NS_OK;
}
already_AddRefed<nsIDOMEventListener>
nsDOMWorkerWeakEventListener::GetListener()
{
JSContext* cx = nsDOMThreadService::GetCurrentContext();
NS_ENSURE_TRUE(cx, nsnull);
nsIXPConnect* xpc = nsContentUtils::XPConnect();
nsCOMPtr<nsIDOMEventListener> listener;
nsresult rv = xpc->WrapJS(cx, mObj, NS_GET_IID(nsIDOMEventListener),
getter_AddRefs(listener));
NS_ENSURE_SUCCESS(rv, nsnull);
return listener.forget();
}
nsDOMWorkerWrappedWeakEventListener::
nsDOMWorkerWrappedWeakEventListener(nsDOMWorkerWeakEventListener* aInner)
: mInner(aInner)
{
NS_ASSERTION(aInner, "Null pointer!");
}
NS_IMPL_THREADSAFE_ISUPPORTS2(nsDOMWorkerMessageHandler,
nsIDOMEventTarget,
nsIClassInfo)
NS_IMPL_CI_INTERFACE_GETTER1(nsDOMWorkerMessageHandler,
nsIDOMEventTarget)
NS_IMPL_THREADSAFE_DOM_CI(nsDOMWorkerMessageHandler)
const nsDOMWorkerMessageHandler::ListenerCollection*
nsDOMWorkerMessageHandler::GetListenerCollection(const nsAString& aType) const
{
PRUint32 count = mCollections.Length();
for (PRUint32 index = 0; index < count; index++) {
const ListenerCollection& collection = mCollections[index];
if (collection.type.Equals(aType)) {
return &collection;
}
}
return nsnull;
}
void
nsDOMWorkerMessageHandler::GetListenersForType(const nsAString& aType,
ListenerArray& _retval) const
{
_retval.Clear();
const ListenerCollection* collection = GetListenerCollection(aType);
if (collection) {
PRUint32 count = collection->listeners.Length();
if (!_retval.SetLength(count)) {
NS_WARNING("Out of memory!");
return;
}
for (PRUint32 index = 0; index < count; index++) {
nsCOMPtr<nsIDOMEventListener> listener =
collection->listeners[index]->GetListener();
_retval[index].swap(listener);
}
}
}
nsresult
nsDOMWorkerMessageHandler::SetOnXListener(const nsAString& aType,
nsIDOMEventListener* aListener)
{
nsRefPtr<nsDOMWorkerWrappedWeakEventListener> wrappedListener;
ListenerCollection* collection =
const_cast<ListenerCollection*>(GetListenerCollection(aType));
#ifdef DEBUG
PRBool removed;
#endif
if (collection) {
wrappedListener.swap(collection->onXListener);
if (wrappedListener) {
#ifdef DEBUG
removed =
#endif
collection->listeners.RemoveElement(wrappedListener);
NS_ASSERTION(removed, "Element wasn't in the list!");
}
}
if (!aListener) {
if (collection && !collection->listeners.Length()) {
#ifdef DEBUG
removed =
#endif
mCollections.RemoveElement(*collection);
NS_ASSERTION(removed, "Element wasn't in the list!");
}
return NS_OK;
}
nsRefPtr<nsDOMWorkerWeakEventListener> weakListener =
new nsDOMWorkerWeakEventListener();
NS_ENSURE_TRUE(weakListener, NS_ERROR_OUT_OF_MEMORY);
nsresult rv = weakListener->Init(aListener);
NS_ENSURE_SUCCESS(rv, rv);
wrappedListener = new nsDOMWorkerWrappedWeakEventListener(weakListener);
NS_ENSURE_TRUE(wrappedListener, NS_ERROR_OUT_OF_MEMORY);
if (!collection) {
collection = mCollections.AppendElement(aType);
NS_ENSURE_TRUE(collection, NS_ERROR_OUT_OF_MEMORY);
}
WeakListener* newListener =
collection->listeners.AppendElement(wrappedListener);
NS_ENSURE_TRUE(newListener, NS_ERROR_OUT_OF_MEMORY);
wrappedListener.swap(collection->onXListener);
return NS_OK;
}
already_AddRefed<nsIDOMEventListener>
nsDOMWorkerMessageHandler::GetOnXListener(const nsAString& aType) const
{
const ListenerCollection* collection = GetListenerCollection(aType);
if (collection && collection->onXListener) {
return collection->onXListener->GetListener();
}
return nsnull;
}
void
nsDOMWorkerMessageHandler::ClearListeners(const nsAString& aType)
{
PRUint32 count = mCollections.Length();
for (PRUint32 index = 0; index < count; index++) {
if (mCollections[index].type.Equals(aType)) {
mCollections.RemoveElementAt(index);
return;
}
}
}
PRBool
nsDOMWorkerMessageHandler::HasListeners(const nsAString& aType)
{
const ListenerCollection* collection = GetListenerCollection(aType);
return collection && collection->listeners.Length();
}
void
nsDOMWorkerMessageHandler::ClearAllListeners()
{
mCollections.Clear();
}
void
nsDOMWorkerMessageHandler::Trace(JSTracer* aTracer)
{
PRUint32 cCount = mCollections.Length();
for (PRUint32 cIndex = 0; cIndex < cCount; cIndex++) {
const ListenerCollection& collection = mCollections[cIndex];
PRUint32 lCount = collection.listeners.Length();
for (PRUint32 lIndex = 0; lIndex < lCount; lIndex++) {
JSObject* obj = collection.listeners[lIndex]->GetJSObject();
NS_ASSERTION(obj, "Null object!");
JS_SET_TRACING_DETAILS(aTracer, nsnull, this, 0);
JS_CallTracer(aTracer, obj, JSTRACE_OBJECT);
}
}
}
/**
* See nsIDOMEventTarget
*/
NS_IMETHODIMP
nsDOMWorkerMessageHandler::RemoveEventListener(const nsAString& aType,
nsIDOMEventListener* aListener,
PRBool aUseCapture)
{
ListenerCollection* collection =
const_cast<ListenerCollection*>(GetListenerCollection(aType));
if (collection) {
PRUint32 count = collection->listeners.Length();
for (PRUint32 index = 0; index < count; index++) {
WeakListener& weakListener = collection->listeners[index];
if (weakListener == collection->onXListener) {
continue;
}
nsCOMPtr<nsIDOMEventListener> listener = weakListener->GetListener();
if (listener == aListener) {
collection->listeners.RemoveElementAt(index);
break;
}
}
if (!collection->listeners.Length()) {
#ifdef DEBUG
PRBool removed =
#endif
mCollections.RemoveElement(*collection);
NS_ASSERTION(removed, "Somehow this wasn't in the list!");
}
}
return NS_OK;
}
/**
* See nsIDOMEventTarget
*/
NS_IMETHODIMP
nsDOMWorkerMessageHandler::DispatchEvent(nsIDOMEvent* aEvent,
PRBool* _retval)
{
NS_ENSURE_ARG_POINTER(aEvent);
nsCOMPtr<nsIDOMWorkerPrivateEvent> event;
if (_retval) {
event = do_QueryInterface(aEvent);
if (!event) {
event = new nsDOMWorkerPrivateEvent(aEvent);
NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY);
}
aEvent = event;
}
nsAutoString type;
nsresult rv = aEvent->GetType(type);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoTArray<Listener, 10> listeners;
GetListenersForType(type, listeners);
PRUint32 count = listeners.Length();
for (PRUint32 index = 0; index < count; index++) {
const Listener& listener = listeners[index];
NS_ASSERTION(listener, "Null listener in array!");
listener->HandleEvent(aEvent);
}
if (_retval) {
*_retval = event->PreventDefaultCalled();
}
return NS_OK;
}
/**
* See nsIDOMEventTarget
*/
NS_IMETHODIMP
nsDOMWorkerMessageHandler::AddEventListener(const nsAString& aType,
nsIDOMEventListener* aListener,
PRBool aUseCapture,
PRBool aWantsUntrusted,
PRUint8 aOptionalArgc)
{
// We don't support aWantsUntrusted yet.
NS_ENSURE_TRUE(aOptionalArgc < 2, NS_ERROR_NOT_IMPLEMENTED);
ListenerCollection* collection =
const_cast<ListenerCollection*>(GetListenerCollection(aType));
if (!collection) {
collection = mCollections.AppendElement(aType);
NS_ENSURE_TRUE(collection, NS_ERROR_OUT_OF_MEMORY);
}
nsRefPtr<nsDOMWorkerWeakEventListener> weakListener =
new nsDOMWorkerWeakEventListener();
NS_ENSURE_TRUE(weakListener, NS_ERROR_OUT_OF_MEMORY);
nsresult rv = weakListener->Init(aListener);
NS_ENSURE_SUCCESS(rv, rv);
WeakListener* newListener = collection->listeners.AppendElement(weakListener);
NS_ENSURE_TRUE(newListener, NS_ERROR_OUT_OF_MEMORY);
return NS_OK;
}
nsIDOMEventTarget *
nsDOMWorkerMessageHandler::GetTargetForDOMEvent()
{
NS_ERROR("Should not be called");
return nsnull;
}
nsIDOMEventTarget *
nsDOMWorkerMessageHandler::GetTargetForEventTargetChain()
{
NS_ERROR("Should not be called");
return nsnull;
}
nsresult
nsDOMWorkerMessageHandler::PreHandleEvent(nsEventChainPreVisitor & aVisitor)
{
NS_ERROR("Should not be called");
return NS_ERROR_NOT_IMPLEMENTED;
}
nsresult
nsDOMWorkerMessageHandler::WillHandleEvent(nsEventChainPostVisitor & aVisitor)
{
NS_ERROR("Should not be called");
return NS_ERROR_NOT_IMPLEMENTED;
}
nsresult
nsDOMWorkerMessageHandler::PostHandleEvent(nsEventChainPostVisitor & aVisitor)
{
NS_ERROR("Should not be called");
return NS_ERROR_NOT_IMPLEMENTED;
}
nsresult
nsDOMWorkerMessageHandler::DispatchDOMEvent(nsEvent *aEvent, nsIDOMEvent *aDOMEvent,
nsPresContext *aPresContext,
nsEventStatus *aEventStatus)
{
NS_ERROR("Should not be called");
return NS_ERROR_NOT_IMPLEMENTED;
}
nsEventListenerManager*
nsDOMWorkerMessageHandler::GetListenerManager(PRBool aMayCreate)
{
NS_ERROR("Should not be called");
return nsnull;
}
nsresult
nsDOMWorkerMessageHandler::AddEventListenerByIID(nsIDOMEventListener *aListener,
const nsIID & aIID)
{
NS_ERROR("Should not be called");
return NS_ERROR_NOT_IMPLEMENTED;
}
nsresult
nsDOMWorkerMessageHandler::RemoveEventListenerByIID(nsIDOMEventListener *aListener,
const nsIID & aIID)
{
NS_ERROR("Should not be called");
return NS_ERROR_NOT_IMPLEMENTED;
}
nsIScriptContext*
nsDOMWorkerMessageHandler::GetContextForEventHandlers(nsresult *aRv)
{
NS_ERROR("Should not be called");
*aRv = NS_ERROR_NOT_IMPLEMENTED;
return nsnull;
}
JSContext*
nsDOMWorkerMessageHandler::GetJSContextForEventHandlers()
{
NS_ERROR("Should not be called");
return nsnull;
}

Просмотреть файл

@ -1,175 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Web Workers.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef __NSDOMWORKERMESSAGEHANDLER_H__
#define __NSDOMWORKERMESSAGEHANDLER_H__
#include "nsIClassInfo.h"
#include "nsIDOMEventListener.h"
#include "nsIDOMEventTarget.h"
#include "nsIDOMWorkers.h"
#include "nsIProgrammingLanguage.h"
#include "jsapi.h"
#include "nsAutoPtr.h"
#include "nsCOMPtr.h"
#include "nsIClassInfoImpl.h"
#include "nsStringGlue.h"
#include "nsTArray.h"
#include "nsIWeakReference.h"
class nsDOMWorkerEventListenerBase
{
public:
NS_IMETHOD_(nsrefcnt) AddRef();
NS_IMETHOD_(nsrefcnt) Release();
virtual already_AddRefed<nsIDOMEventListener> GetListener() = 0;
virtual JSObject* GetJSObject() = 0;
protected:
virtual ~nsDOMWorkerEventListenerBase() { }
nsAutoRefCnt mRefCnt;
};
class nsDOMWorkerWeakEventListener : public nsDOMWorkerEventListenerBase
{
public:
nsDOMWorkerWeakEventListener()
: mObj(NULL) { }
nsresult Init(nsIDOMEventListener* aListener);
already_AddRefed<nsIDOMEventListener> GetListener();
virtual JSObject* GetJSObject() {
return mObj;
}
private:
JSObject* mObj;
};
class nsDOMWorkerWrappedWeakEventListener : public nsDOMWorkerEventListenerBase
{
public:
nsDOMWorkerWrappedWeakEventListener(nsDOMWorkerWeakEventListener* aInner);
already_AddRefed<nsIDOMEventListener> GetListener() {
return mInner->GetListener();
}
virtual JSObject* GetJSObject() {
return mInner->GetJSObject();
}
private:
nsRefPtr<nsDOMWorkerWeakEventListener> mInner;
};
class nsDOMWorkerMessageHandler : public nsIDOMEventTarget,
public nsIClassInfo
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIDOMEVENTTARGET
NS_DECL_NSICLASSINFO
virtual nsresult SetOnXListener(const nsAString& aType,
nsIDOMEventListener* aListener);
already_AddRefed<nsIDOMEventListener>
GetOnXListener(const nsAString& aType) const;
void ClearListeners(const nsAString& aType);
PRBool HasListeners(const nsAString& aType);
void ClearAllListeners();
void Trace(JSTracer* aTracer);
protected:
virtual ~nsDOMWorkerMessageHandler() { }
private:
typedef nsCOMPtr<nsIDOMEventListener> Listener;
typedef nsTArray<Listener> ListenerArray;
typedef nsRefPtr<nsDOMWorkerEventListenerBase> WeakListener;
typedef nsTArray<WeakListener> WeakListenerArray;
struct ListenerCollection {
PRBool operator==(const ListenerCollection& aOther) const {
return this == &aOther;
}
ListenerCollection(const nsAString& aType)
: type(aType) { }
nsString type;
WeakListenerArray listeners;
nsRefPtr<nsDOMWorkerWrappedWeakEventListener> onXListener;
};
const ListenerCollection* GetListenerCollection(const nsAString& aType) const;
void GetListenersForType(const nsAString& aType,
ListenerArray& _retval) const;
nsTArray<ListenerCollection> mCollections;
};
#define NS_FORWARD_INTERNAL_NSIDOMEVENTTARGET(_to) \
virtual nsIDOMEventTarget * GetTargetForDOMEvent(void) { return _to GetTargetForDOMEvent(); } \
virtual nsIDOMEventTarget * GetTargetForEventTargetChain(void) { return _to GetTargetForEventTargetChain(); } \
virtual nsresult PreHandleEvent(nsEventChainPreVisitor & aVisitor) { return _to PreHandleEvent(aVisitor); } \
virtual nsresult WillHandleEvent(nsEventChainPostVisitor & aVisitor) { return _to WillHandleEvent(aVisitor); } \
virtual nsresult PostHandleEvent(nsEventChainPostVisitor & aVisitor) { return _to PostHandleEvent(aVisitor); } \
virtual nsresult DispatchDOMEvent(nsEvent *aEvent, nsIDOMEvent *aDOMEvent, nsPresContext *aPresContext, nsEventStatus *aEventStatus) { return _to DispatchDOMEvent(aEvent, aDOMEvent, aPresContext, aEventStatus); } \
virtual nsEventListenerManager * GetListenerManager(PRBool aMayCreate) { return _to GetListenerManager(aMayCreate); } \
virtual nsresult AddEventListenerByIID(nsIDOMEventListener *aListener, const nsIID & aIID) { return _to AddEventListenerByIID(aListener, aIID); } \
virtual nsresult RemoveEventListenerByIID(nsIDOMEventListener *aListener, const nsIID & aIID) { return _to RemoveEventListenerByIID(aListener, aIID); } \
virtual nsIScriptContext * GetContextForEventHandlers(nsresult *aRv NS_OUTPARAM) { return _to GetContextForEventHandlers(aRv); } \
virtual JSContext * GetJSContextForEventHandlers(void) { return _to GetJSContextForEventHandlers(); }
#endif /* __NSDOMWORKERMESSAGEHANDLER_H__ */

Просмотреть файл

@ -1,108 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is worker threads.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsDOMWorkerNavigator.h"
#include "nsIClassInfoImpl.h"
#include "nsStringGlue.h"
#include "nsDOMThreadService.h"
#include "nsDOMWorkerMacros.h"
#define XPC_MAP_CLASSNAME nsDOMWorkerNavigator
#define XPC_MAP_QUOTED_CLASSNAME "Navigator"
#define XPC_MAP_FLAGS \
nsIXPCScriptable::USE_JSSTUB_FOR_ADDPROPERTY | \
nsIXPCScriptable::USE_JSSTUB_FOR_DELPROPERTY | \
nsIXPCScriptable::USE_JSSTUB_FOR_SETPROPERTY | \
nsIXPCScriptable::DONT_ENUM_QUERY_INTERFACE | \
nsIXPCScriptable::CLASSINFO_INTERFACES_ONLY | \
nsIXPCScriptable::DONT_REFLECT_INTERFACE_NAMES
#include "xpc_map_end.h"
NS_IMPL_THREADSAFE_ISUPPORTS3(nsDOMWorkerNavigator, nsIWorkerNavigator,
nsIClassInfo,
nsIXPCScriptable)
NS_IMPL_CI_INTERFACE_GETTER1(nsDOMWorkerNavigator, nsIWorkerNavigator)
NS_IMPL_THREADSAFE_DOM_CI_GETINTERFACES(nsDOMWorkerNavigator)
NS_IMPL_THREADSAFE_DOM_CI_ALL_THE_REST(nsDOMWorkerNavigator)
NS_IMETHODIMP
nsDOMWorkerNavigator::GetHelperForLanguage(PRUint32 aLanguage,
nsISupports** _retval)
{
if (aLanguage == nsIProgrammingLanguage::JAVASCRIPT) {
NS_ADDREF(*_retval = NS_ISUPPORTS_CAST(nsIWorkerNavigator*, this));
}
else {
*_retval = nsnull;
}
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerNavigator::GetAppName(nsAString& aAppName)
{
nsDOMThreadService::get()->GetAppName(aAppName);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerNavigator::GetAppVersion(nsAString& aAppVersion)
{
nsDOMThreadService::get()->GetAppVersion(aAppVersion);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerNavigator::GetPlatform(nsAString& aPlatform)
{
nsDOMThreadService::get()->GetPlatform(aPlatform);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerNavigator::GetUserAgent(nsAString& aUserAgent)
{
nsDOMThreadService::get()->GetUserAgent(aUserAgent);
return NS_OK;
}

Просмотреть файл

@ -1,238 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is worker threads.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Vladimir Vukicevic <vladimir@pobox.com> (Original Author)
* Ben Turner <bent.mozilla@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsDOMWorkerPool.h"
// Interfaces
#include "nsIDocument.h"
#include "nsIDOMClassInfo.h"
#include "nsIJSContextStack.h"
#include "nsIScriptGlobalObject.h"
#include "nsIServiceManager.h"
#include "nsIThreadManager.h"
#include "nsIXPConnect.h"
#include "nsPIDOMWindow.h"
// Other includes
#include "nsContentUtils.h"
#include "nsDOMJSUtils.h"
#include "nsProxyRelease.h"
#include "nsThreadUtils.h"
// DOMWorker includes
#include "nsDOMThreadService.h"
#include "nsDOMWorker.h"
using namespace mozilla;
#define LOG(_args) PR_LOG(gDOMThreadsLog, PR_LOG_DEBUG, _args)
nsDOMWorkerPool::nsDOMWorkerPool(nsIScriptGlobalObject* aGlobalObject,
nsIDocument* aDocument)
: mParentGlobal(aGlobalObject),
mParentDocument(aDocument),
mReentrantMonitor("nsDOMWorkerPool.mReentrantMonitor"),
mCanceled(PR_FALSE),
mSuspended(PR_FALSE),
mWindowID(aDocument ? aDocument->OuterWindowID() : 0)
{
}
nsDOMWorkerPool::~nsDOMWorkerPool()
{
nsCOMPtr<nsIThread> mainThread;
NS_GetMainThread(getter_AddRefs(mainThread));
nsIScriptGlobalObject* global;
mParentGlobal.forget(&global);
if (global) {
NS_ProxyRelease(mainThread, global, PR_FALSE);
}
nsIDocument* document;
mParentDocument.forget(&document);
if (document) {
NS_ProxyRelease(mainThread, document, PR_FALSE);
}
}
NS_IMPL_THREADSAFE_ADDREF(nsDOMWorkerPool)
NS_IMPL_THREADSAFE_RELEASE(nsDOMWorkerPool)
nsresult
nsDOMWorkerPool::Init()
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
return NS_OK;
}
nsresult
nsDOMWorkerPool::NoteWorker(nsDOMWorker* aWorker)
{
NS_ASSERTION(aWorker, "Null pointer!");
PRBool suspendWorker;
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
if (mCanceled) {
return NS_ERROR_ABORT;
}
nsDOMWorker** newWorker = mWorkers.AppendElement(aWorker);
NS_ENSURE_TRUE(newWorker, NS_ERROR_OUT_OF_MEMORY);
suspendWorker = mSuspended;
}
if (suspendWorker) {
aWorker->Suspend();
}
return NS_OK;
}
void
nsDOMWorkerPool::NoteDyingWorker(nsDOMWorker* aWorker)
{
NS_ASSERTION(aWorker, "Null pointer!");
PRBool removeFromThreadService = PR_FALSE;
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
NS_ASSERTION(mWorkers.Contains(aWorker), "Worker from a different pool?!");
mWorkers.RemoveElement(aWorker);
if (!mCanceled && !mWorkers.Length()) {
removeFromThreadService = PR_TRUE;
}
}
if (removeFromThreadService) {
nsRefPtr<nsDOMWorkerPool> kungFuDeathGrip(this);
nsDOMThreadService::get()->NoteEmptyPool(this);
}
}
void
nsDOMWorkerPool::GetWorkers(nsTArray<nsDOMWorker*>& aArray)
{
mReentrantMonitor.AssertCurrentThreadIn();
NS_ASSERTION(!aArray.Length(), "Should be empty!");
#ifdef DEBUG
nsDOMWorker** newWorkers =
#endif
aArray.AppendElements(mWorkers);
NS_WARN_IF_FALSE(newWorkers, "Out of memory!");
}
void
nsDOMWorkerPool::Cancel()
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(!mCanceled, "Canceled more than once!");
nsAutoTArray<nsDOMWorker*, 10> workers;
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
mCanceled = PR_TRUE;
GetWorkers(workers);
}
PRUint32 count = workers.Length();
if (count) {
for (PRUint32 index = 0; index < count; index++) {
workers[index]->Cancel();
}
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
mon.NotifyAll();
}
}
void
nsDOMWorkerPool::Suspend()
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
nsAutoTArray<nsDOMWorker*, 10> workers;
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
NS_ASSERTION(!mSuspended, "Suspended more than once!");
mSuspended = PR_TRUE;
GetWorkers(workers);
}
PRUint32 count = workers.Length();
for (PRUint32 index = 0; index < count; index++) {
workers[index]->Suspend();
}
}
void
nsDOMWorkerPool::Resume()
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
nsAutoTArray<nsDOMWorker*, 10> workers;
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
NS_ASSERTION(mSuspended, "Not suspended!");
mSuspended = PR_FALSE;
GetWorkers(workers);
}
PRUint32 count = workers.Length();
if (count) {
for (PRUint32 index = 0; index < count; index++) {
workers[index]->Resume();
}
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
mon.NotifyAll();
}
}

Просмотреть файл

@ -1,118 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is worker threads.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Vladimir Vukicevic <vladimir@pobox.com> (Original Author)
* Ben Turner <bent.mozilla@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef __NSDOMWORKERPOOL_H__
#define __NSDOMWORKERPOOL_H__
// Other includes
#include "jsapi.h"
#include "mozilla/ReentrantMonitor.h"
#include "nsCOMPtr.h"
#include "nsStringGlue.h"
#include "nsTArray.h"
class nsDOMWorker;
class nsIDocument;
class nsIScriptContext;
class nsIScriptError;
class nsIScriptGlobalObject;
class nsDOMWorkerPool
{
typedef mozilla::ReentrantMonitor ReentrantMonitor;
public:
nsDOMWorkerPool(nsIScriptGlobalObject* aGlobalObject,
nsIDocument* aDocument);
NS_IMETHOD_(nsrefcnt) AddRef();
NS_IMETHOD_(nsrefcnt) Release();
nsIScriptGlobalObject* ScriptGlobalObject() {
return mParentGlobal;
}
nsIDocument* ParentDocument() {
return mParentDocument;
}
nsresult Init();
void Cancel();
void Suspend();
void Resume();
nsresult NoteWorker(nsDOMWorker* aWorker);
void NoteDyingWorker(nsDOMWorker* aWorker);
ReentrantMonitor& GetReentrantMonitor() {
return mReentrantMonitor;
}
const PRUint64 WindowID() const {
return mWindowID;
}
private:
virtual ~nsDOMWorkerPool();
void GetWorkers(nsTArray<nsDOMWorker*>& aArray);
nsAutoRefCnt mRefCnt;
// Reference to the window that created and owns this pool.
nsCOMPtr<nsIScriptGlobalObject> mParentGlobal;
// Reference to the document that created this pool.
nsCOMPtr<nsIDocument> mParentDocument;
// Weak array of workers. The idea is that workers can be garbage collected
// independently of the owning pool and other workers.
nsTArray<nsDOMWorker*> mWorkers;
// ReentrantMonitor for suspending and resuming workers.
ReentrantMonitor mReentrantMonitor;
PRPackedBool mCanceled;
PRPackedBool mSuspended;
const PRUint64 mWindowID;
};
#endif /* __NSDOMWORKERPOOL_H__ */

Просмотреть файл

@ -1,881 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is worker threads.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsDOMWorkerScriptLoader.h"
// Interfaces
#include "nsIChannel.h"
#include "nsIContentPolicy.h"
#include "nsIHttpChannel.h"
#include "nsIIOService.h"
#include "nsIProtocolHandler.h"
#include "nsIRequest.h"
#include "nsIScriptSecurityManager.h"
#include "nsIStreamLoader.h"
// Other includes
#include "nsContentErrors.h"
#include "nsContentPolicyUtils.h"
#include "nsContentUtils.h"
#include "nsISupportsPrimitives.h"
#include "nsNetError.h"
#include "nsNetUtil.h"
#include "nsScriptLoader.h"
#include "nsThreadUtils.h"
#include "pratom.h"
#include "nsDocShellCID.h"
#include "nsIChannelPolicy.h"
#include "nsChannelPolicy.h"
#include "nsIContentSecurityPolicy.h"
// DOMWorker includes
#include "nsDOMWorkerPool.h"
#include "nsDOMWorkerSecurityManager.h"
#include "nsDOMThreadService.h"
#include "nsDOMWorkerTimeout.h"
using namespace mozilla;
#define LOG(_args) PR_LOG(gDOMThreadsLog, PR_LOG_DEBUG, _args)
nsDOMWorkerScriptLoader::nsDOMWorkerScriptLoader(nsDOMWorker* aWorker)
: nsDOMWorkerFeature(aWorker),
mTarget(nsnull),
mScriptCount(0),
mCanceled(PR_FALSE),
mForWorker(PR_FALSE)
{
// Created on worker thread.
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(aWorker, "Null worker!");
}
NS_IMPL_ISUPPORTS_INHERITED2(nsDOMWorkerScriptLoader, nsDOMWorkerFeature,
nsIRunnable,
nsIStreamLoaderObserver)
nsresult
nsDOMWorkerScriptLoader::LoadScripts(JSContext* aCx,
const nsTArray<nsString>& aURLs,
PRBool aExecute)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(aCx, "Null context!");
mTarget = NS_GetCurrentThread();
NS_ASSERTION(mTarget, "This should never be null!");
if (mCanceled) {
return NS_ERROR_ABORT;
}
mScriptCount = aURLs.Length();
if (!mScriptCount) {
return NS_ERROR_INVALID_ARG;
}
// Do all the memory work for these arrays now rather than checking for
// failures all along the way.
PRBool success = mLoadInfos.SetCapacity(mScriptCount);
NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY);
// Need one runnable per script and then an extra for the finished
// notification.
success = mPendingRunnables.SetCapacity(mScriptCount + 1);
NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY);
for (PRUint32 index = 0; index < mScriptCount; index++) {
ScriptLoadInfo* newInfo = mLoadInfos.AppendElement();
NS_ASSERTION(newInfo, "Shouldn't fail if SetCapacity succeeded above!");
newInfo->url.Assign(aURLs[index]);
if (newInfo->url.IsEmpty()) {
return NS_ERROR_INVALID_ARG;
}
success = newInfo->scriptObj.Hold(aCx);
NS_ENSURE_TRUE(success, NS_ERROR_FAILURE);
}
// Don't want timeouts, etc., from queuing up while we're waiting on the
// network or compiling.
AutoSuspendWorkerEvents aswe(this);
nsresult rv = DoRunLoop(aCx);
if (NS_FAILED(rv)) {
return rv;
}
// Verify that all scripts downloaded and compiled.
rv = VerifyScripts(aCx);
if (NS_FAILED(rv)) {
return rv;
}
if (aExecute) {
rv = ExecuteScripts(aCx);
if (NS_FAILED(rv)) {
return rv;
}
}
return NS_OK;
}
nsresult
nsDOMWorkerScriptLoader::LoadWorkerScript(JSContext* aCx,
const nsString& aURL)
{
mForWorker = PR_TRUE;
nsAutoTArray<nsString, 1> url;
url.AppendElement(aURL);
return LoadScripts(aCx, url, PR_FALSE);
}
nsresult
nsDOMWorkerScriptLoader::DoRunLoop(JSContext* aCx)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
volatile PRBool done = PR_FALSE;
mDoneRunnable = new ScriptLoaderDone(this, &done);
NS_ENSURE_TRUE(mDoneRunnable, NS_ERROR_OUT_OF_MEMORY);
nsresult rv = NS_DispatchToMainThread(this);
NS_ENSURE_SUCCESS(rv, rv);
while (!(done || mCanceled)) {
JSAutoSuspendRequest asr(aCx);
NS_ProcessNextEvent(mTarget);
}
return mCanceled ? NS_ERROR_ABORT : NS_OK;
}
nsresult
nsDOMWorkerScriptLoader::VerifyScripts(JSContext* aCx)
{
NS_ASSERTION(aCx, "Shouldn't be null!");
nsresult rv = NS_OK;
for (PRUint32 index = 0; index < mScriptCount; index++) {
ScriptLoadInfo& loadInfo = mLoadInfos[index];
NS_ASSERTION(loadInfo.done, "Inconsistent state!");
if (NS_SUCCEEDED(loadInfo.result) && loadInfo.scriptObj.ToJSObject()) {
continue;
}
NS_ASSERTION(!loadInfo.scriptObj.ToJSObject(), "Inconsistent state!");
// Flag failure before worrying about whether or not to report an error.
rv = NS_FAILED(loadInfo.result) ? loadInfo.result : NS_ERROR_FAILURE;
// If loadInfo.result is a success code then the compiler probably reported
// an error already. Also we don't really care about NS_BINDING_ABORTED
// since that's the code we set when some other script had a problem and the
// rest were canceled.
if (NS_SUCCEEDED(loadInfo.result) || loadInfo.result == NS_BINDING_ABORTED) {
continue;
}
// Ok, this is the script that caused us to fail.
JSAutoRequest ar(aCx);
// Only throw an error if there is no other pending exception.
if (!JS_IsExceptionPending(aCx)) {
const char* message;
switch (loadInfo.result) {
case NS_ERROR_MALFORMED_URI:
message = "Malformed script URI: %s";
break;
case NS_ERROR_FILE_NOT_FOUND:
case NS_ERROR_NOT_AVAILABLE:
message = "Script file not found: %s";
break;
default:
message = "Failed to load script: %s (nsresult = 0x%x)";
break;
}
NS_ConvertUTF16toUTF8 url(loadInfo.url);
JS_ReportError(aCx, message, url.get(), loadInfo.result);
}
break;
}
return rv;
}
nsresult
nsDOMWorkerScriptLoader::ExecuteScripts(JSContext* aCx)
{
NS_ASSERTION(aCx, "Shouldn't be null!");
// Now execute all the scripts.
for (PRUint32 index = 0; index < mScriptCount; index++) {
ScriptLoadInfo& loadInfo = mLoadInfos[index];
JSAutoRequest ar(aCx);
JSObject* scriptObj = loadInfo.scriptObj.ToJSObject();
NS_ASSERTION(scriptObj, "This shouldn't ever be null!");
JSObject* global = mWorker->mGlobal ?
mWorker->mGlobal :
JS_GetGlobalObject(aCx);
NS_ENSURE_STATE(global);
// Because we may have nested calls to this function we don't want the
// execution to automatically report errors. We let them propagate instead.
uint32 oldOpts =
JS_SetOptions(aCx, JS_GetOptions(aCx) | JSOPTION_DONT_REPORT_UNCAUGHT);
PRBool success = JS_ExecuteScript(aCx, global, scriptObj, NULL);
JS_SetOptions(aCx, oldOpts);
if (!success) {
return NS_ERROR_FAILURE;
}
}
return NS_OK;
}
void
nsDOMWorkerScriptLoader::Cancel()
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(!mCanceled, "Cancel called more than once!");
mCanceled = PR_TRUE;
for (PRUint32 index = 0; index < mScriptCount; index++) {
ScriptLoadInfo& loadInfo = mLoadInfos[index];
nsIRequest* request =
static_cast<nsIRequest*>(loadInfo.channel.get());
if (request) {
#ifdef DEBUG
nsresult rv =
#endif
request->Cancel(NS_BINDING_ABORTED);
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Failed to cancel channel!");
}
}
nsAutoTArray<ScriptLoaderRunnable*, 10> runnables;
{
MutexAutoLock lock(mWorker->GetLock());
runnables.AppendElements(mPendingRunnables);
mPendingRunnables.Clear();
}
PRUint32 runnableCount = runnables.Length();
for (PRUint32 index = 0; index < runnableCount; index++) {
runnables[index]->Revoke();
}
// We're about to post a revoked event to the worker thread, which seems
// silly, but we have to do this because the worker thread may be sleeping
// waiting on its event queue.
NotifyDone();
}
NS_IMETHODIMP
nsDOMWorkerScriptLoader::Run()
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
// We may have been canceled already.
if (mCanceled) {
return NS_BINDING_ABORTED;
}
nsresult rv = RunInternal();
if (NS_SUCCEEDED(rv)) {
return rv;
}
// Ok, something failed beyond a normal cancel.
// If necko is holding a ref to us then we'll end up notifying in the
// OnStreamComplete method, not here.
PRBool needsNotify = PR_TRUE;
// Cancel any async channels that were already opened.
for (PRUint32 index = 0; index < mScriptCount; index++) {
ScriptLoadInfo& loadInfo = mLoadInfos[index];
nsIRequest* request = static_cast<nsIRequest*>(loadInfo.channel.get());
if (request) {
#ifdef DEBUG
nsresult rvInner =
#endif
request->Cancel(NS_BINDING_ABORTED);
NS_WARN_IF_FALSE(NS_SUCCEEDED(rvInner), "Failed to cancel channel!");
// Necko is holding a ref to us so make sure that the OnStreamComplete
// code sends the done event.
needsNotify = PR_FALSE;
}
else {
// Make sure to set this so that the OnStreamComplete code will dispatch
// the done event.
loadInfo.done = PR_TRUE;
}
}
if (needsNotify) {
NotifyDone();
}
return rv;
}
NS_IMETHODIMP
nsDOMWorkerScriptLoader::OnStreamComplete(nsIStreamLoader* aLoader,
nsISupports* aContext,
nsresult aStatus,
PRUint32 aStringLen,
const PRUint8* aString)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
// We may have been canceled already.
if (mCanceled) {
return NS_BINDING_ABORTED;
}
nsresult rv = OnStreamCompleteInternal(aLoader, aContext, aStatus, aStringLen,
aString);
// Dispatch the done event if we've received all the data.
for (PRUint32 index = 0; index < mScriptCount; index++) {
if (!mLoadInfos[index].done) {
// Some async load is still outstanding, don't notify yet.
break;
}
if (index == mScriptCount - 1) {
// All loads complete, signal the thread.
NotifyDone();
}
}
return rv;
}
nsresult
nsDOMWorkerScriptLoader::RunInternal()
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
if (mForWorker) {
NS_ASSERTION(mScriptCount == 1, "Bad state!");
}
nsRefPtr<nsDOMWorker> parentWorker = mWorker->GetParent();
// Figure out which principal to use.
nsIPrincipal* principal = mWorker->GetPrincipal();
if (!principal) {
if (!parentWorker) {
NS_ERROR("Must have a principal if this is not a subworker!");
}
principal = parentWorker->GetPrincipal();
}
NS_ASSERTION(principal, "This should never be null here!");
// Figure out our base URI.
nsCOMPtr<nsIURI> baseURI;
if (mForWorker) {
if (parentWorker) {
baseURI = parentWorker->GetBaseURI();
NS_ASSERTION(baseURI, "Should have been set already!");
}
else {
// May be null.
baseURI = mWorker->GetBaseURI();
// Don't leave a temporary URI hanging around.
mWorker->ClearBaseURI();
}
NS_ASSERTION(!mWorker->GetBaseURI(), "Should not be set here!");
}
else {
baseURI = mWorker->GetBaseURI();
NS_ASSERTION(baseURI, "Should have been set already!");
}
nsCOMPtr<nsIDocument> parentDoc = mWorker->Pool()->ParentDocument();
// All of these can potentially be null, but that should be ok. We'll either
// succeed without them or fail below.
nsCOMPtr<nsILoadGroup> loadGroup;
if (parentDoc) {
loadGroup = parentDoc->GetDocumentLoadGroup();
}
nsCOMPtr<nsIIOService> ios(do_GetIOService());
nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
NS_ASSERTION(secMan, "This should never be null!");
for (PRUint32 index = 0; index < mScriptCount; index++) {
ScriptLoadInfo& loadInfo = mLoadInfos[index];
nsresult& rv = loadInfo.result;
nsCOMPtr<nsIURI>& uri = loadInfo.finalURI;
rv = nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(uri),
loadInfo.url, parentDoc,
baseURI);
if (NS_FAILED(rv)) {
return rv;
}
// If we're part of a document then check the content load policy.
if (parentDoc) {
PRInt16 shouldLoad = nsIContentPolicy::ACCEPT;
rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_SCRIPT, uri,
principal, parentDoc,
NS_LITERAL_CSTRING("text/javascript"),
nsnull, &shouldLoad,
nsContentUtils::GetContentPolicy(),
secMan);
if (NS_FAILED(rv) || NS_CP_REJECTED(shouldLoad)) {
if (NS_FAILED(rv) || shouldLoad != nsIContentPolicy::REJECT_TYPE) {
return (rv = NS_ERROR_CONTENT_BLOCKED);
}
return (rv = NS_ERROR_CONTENT_BLOCKED_SHOW_ALT);
}
}
// If this script loader is being used to make a new worker then we need to
// do a same-origin check. Otherwise we need to clear the load with the
// security manager.
rv = mForWorker ?
principal->CheckMayLoad(uri, PR_FALSE):
secMan->CheckLoadURIWithPrincipal(principal, uri, 0);
NS_ENSURE_SUCCESS(rv, rv);
// We need to know which index we're on in OnStreamComplete so we know where
// to put the result.
nsCOMPtr<nsISupportsPRUint32> indexSupports =
do_CreateInstance(NS_SUPPORTS_PRUINT32_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = indexSupports->SetData(index);
NS_ENSURE_SUCCESS(rv, rv);
// We don't care about progress so just use the simple stream loader for
// OnStreamComplete notification only.
nsCOMPtr<nsIStreamLoader> loader;
rv = NS_NewStreamLoader(getter_AddRefs(loader), this);
NS_ENSURE_SUCCESS(rv, rv);
// Get Content Security Policy from parent document to pass into channel
nsCOMPtr<nsIContentSecurityPolicy> csp;
rv = principal->GetCsp(getter_AddRefs(csp));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIChannelPolicy> channelPolicy;
if (csp) {
channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1", &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = channelPolicy->SetContentSecurityPolicy(csp);
NS_ENSURE_SUCCESS(rv, rv);
rv = channelPolicy->SetLoadType(nsIContentPolicy::TYPE_SCRIPT);
NS_ENSURE_SUCCESS(rv, rv);
}
rv = NS_NewChannel(getter_AddRefs(loadInfo.channel),
uri, ios, loadGroup, nsnull,
nsIRequest::LOAD_NORMAL | nsIChannel::LOAD_CLASSIFY_URI,
channelPolicy);
NS_ENSURE_SUCCESS(rv, rv);
rv = loadInfo.channel->AsyncOpen(loader, indexSupports);
if (NS_FAILED(rv)) {
// Null this out so we don't try to cancel it later.
loadInfo.channel = nsnull;
return rv;
}
}
return NS_OK;
}
nsresult
nsDOMWorkerScriptLoader::OnStreamCompleteInternal(nsIStreamLoader* aLoader,
nsISupports* aContext,
nsresult aStatus,
PRUint32 aStringLen,
const PRUint8* aString)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
nsCOMPtr<nsISupportsPRUint32> indexSupports(do_QueryInterface(aContext));
NS_ENSURE_TRUE(indexSupports, NS_ERROR_NO_INTERFACE);
PRUint32 index = PR_UINT32_MAX;
indexSupports->GetData(&index);
if (index >= mScriptCount) {
NS_NOTREACHED("This really can't fail or we'll hang!");
return NS_ERROR_FAILURE;
}
ScriptLoadInfo& loadInfo = mLoadInfos[index];
NS_ASSERTION(!loadInfo.done, "Got complete on the same load twice!");
loadInfo.done = PR_TRUE;
// Use an alias to keep rv and loadInfo.result in sync.
nsresult& rv = loadInfo.result;
if (NS_FAILED(aStatus)) {
return rv = aStatus;
}
if (!(aStringLen && aString)) {
return rv = NS_ERROR_UNEXPECTED;
}
// Make sure we're not seeing the result of a 404 or something by checking the
// 'requestSucceeded' attribute on the http channel.
nsCOMPtr<nsIRequest> request;
rv = aLoader->GetRequest(getter_AddRefs(request));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(request);
if (httpChannel) {
PRBool requestSucceeded;
rv = httpChannel->GetRequestSucceeded(&requestSucceeded);
NS_ENSURE_SUCCESS(rv, rv);
if (!requestSucceeded) {
return rv = NS_ERROR_NOT_AVAILABLE;
}
}
// May be null.
nsIDocument* parentDoc = mWorker->Pool()->ParentDocument();
// Use the regular nsScriptLoader for this grunt work! Should be just fine
// because we're running on the main thread.
rv = nsScriptLoader::ConvertToUTF16(loadInfo.channel, aString, aStringLen,
EmptyString(), parentDoc,
loadInfo.scriptText);
if (NS_FAILED(rv)) {
return rv;
}
if (loadInfo.scriptText.IsEmpty()) {
return rv = NS_ERROR_FAILURE;
}
nsCString filename;
rv = loadInfo.finalURI->GetSpec(filename);
NS_ENSURE_SUCCESS(rv, rv);
if (filename.IsEmpty()) {
filename.Assign(NS_LossyConvertUTF16toASCII(loadInfo.url));
}
else {
// This will help callers figure out what their script url resolved to in
// case of errors.
loadInfo.url.Assign(NS_ConvertUTF8toUTF16(filename));
}
// Update the principal of the worker and its base URI if we just loaded the
// worker's primary script.
if (mForWorker) {
nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
NS_ASSERTION(channel, "This should never fail!");
// Take care of the base URI first.
nsCOMPtr<nsIURI> finalURI;
rv = NS_GetFinalChannelURI(channel, getter_AddRefs(finalURI));
NS_ENSURE_SUCCESS(rv, rv);
mWorker->SetBaseURI(finalURI);
// Now to figure out which principal to give this worker.
nsRefPtr<nsDOMWorker> parent = mWorker->GetParent();
NS_ASSERTION(mWorker->GetPrincipal() || parent, "Must have one of these!");
nsCOMPtr<nsIPrincipal> loadPrincipal = mWorker->GetPrincipal() ?
mWorker->GetPrincipal() :
parent->GetPrincipal();
nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
NS_ASSERTION(ssm, "Should never be null!");
nsCOMPtr<nsIPrincipal> channelPrincipal;
rv = ssm->GetChannelPrincipal(channel, getter_AddRefs(channelPrincipal));
NS_ENSURE_SUCCESS(rv, rv);
// See if this is a resource URI. Since JSMs usually come from resource://
// URIs we're currently considering all URIs with the URI_IS_UI_RESOURCE
// flag as valid for creating privileged workers.
if (!nsContentUtils::IsSystemPrincipal(channelPrincipal)) {
PRBool isResource;
rv = NS_URIChainHasFlags(finalURI,
nsIProtocolHandler::URI_IS_UI_RESOURCE,
&isResource);
NS_ENSURE_SUCCESS(rv, rv);
if (isResource) {
rv = ssm->GetSystemPrincipal(getter_AddRefs(channelPrincipal));
NS_ENSURE_SUCCESS(rv, rv);
}
}
// If the load principal is the system principal then the channel principal
// must also be the system principal (we do not allow chrome code to create
// workers with non-chrome scripts). Otherwise this channel principal must
// be same origin with the load principal (we check again here in case
// redirects changed the location of the script).
if (nsContentUtils::IsSystemPrincipal(loadPrincipal)) {
if (!nsContentUtils::IsSystemPrincipal(channelPrincipal)) {
return rv = NS_ERROR_DOM_BAD_URI;
}
}
else if (NS_FAILED(loadPrincipal->CheckMayLoad(finalURI, PR_FALSE))) {
return rv = NS_ERROR_DOM_BAD_URI;
}
mWorker->SetPrincipal(channelPrincipal);
}
nsRefPtr<ScriptCompiler> compiler =
new ScriptCompiler(this, loadInfo.scriptText, filename, loadInfo.scriptObj);
NS_ASSERTION(compiler, "Out of memory!");
if (!compiler) {
return rv = NS_ERROR_OUT_OF_MEMORY;
}
rv = mTarget->Dispatch(compiler, NS_DISPATCH_NORMAL);
NS_ENSURE_SUCCESS(rv, rv);
return rv;
}
void
nsDOMWorkerScriptLoader::NotifyDone()
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
if (!mDoneRunnable) {
// We've already completed, no need to cancel anything.
return;
}
for (PRUint32 index = 0; index < mScriptCount; index++) {
ScriptLoadInfo& loadInfo = mLoadInfos[index];
// Null both of these out because they aren't threadsafe and must be
// destroyed on this thread.
loadInfo.channel = nsnull;
loadInfo.finalURI = nsnull;
if (mCanceled) {
// Simulate a complete, yet failed, load.
loadInfo.done = PR_TRUE;
loadInfo.result = NS_BINDING_ABORTED;
}
}
#ifdef DEBUG
nsresult rv =
#endif
mTarget->Dispatch(mDoneRunnable, NS_DISPATCH_NORMAL);
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Couldn't dispatch done event!");
mDoneRunnable = nsnull;
}
void
nsDOMWorkerScriptLoader::SuspendWorkerEvents()
{
NS_ASSERTION(mWorker, "No worker yet!");
mWorker->SuspendFeatures();
}
void
nsDOMWorkerScriptLoader::ResumeWorkerEvents()
{
NS_ASSERTION(mWorker, "No worker yet!");
mWorker->ResumeFeatures();
}
nsDOMWorkerScriptLoader::
ScriptLoaderRunnable::ScriptLoaderRunnable(nsDOMWorkerScriptLoader* aLoader)
: mRevoked(PR_FALSE),
mLoader(aLoader)
{
MutexAutoLock lock(aLoader->GetLock());
#ifdef DEBUG
nsDOMWorkerScriptLoader::ScriptLoaderRunnable** added =
#endif
aLoader->mPendingRunnables.AppendElement(this);
NS_ASSERTION(added, "This shouldn't fail because we SetCapacity earlier!");
}
nsDOMWorkerScriptLoader::
ScriptLoaderRunnable::~ScriptLoaderRunnable()
{
if (!mRevoked) {
MutexAutoLock lock(mLoader->GetLock());
#ifdef DEBUG
PRBool removed =
#endif
mLoader->mPendingRunnables.RemoveElement(this);
NS_ASSERTION(removed, "Someone has changed the array!");
}
}
NS_IMPL_THREADSAFE_ISUPPORTS1(nsDOMWorkerScriptLoader::ScriptLoaderRunnable,
nsIRunnable)
void
nsDOMWorkerScriptLoader::ScriptLoaderRunnable::Revoke()
{
mRevoked = PR_TRUE;
}
nsDOMWorkerScriptLoader::
ScriptCompiler::ScriptCompiler(nsDOMWorkerScriptLoader* aLoader,
const nsString& aScriptText,
const nsCString& aFilename,
nsAutoJSValHolder& aScriptObj)
: ScriptLoaderRunnable(aLoader),
mScriptText(aScriptText),
mFilename(aFilename),
mScriptObj(aScriptObj)
{
NS_ASSERTION(!aScriptText.IsEmpty(), "No script to compile!");
NS_ASSERTION(aScriptObj.IsHeld(), "Should be held!");
}
NS_IMETHODIMP
nsDOMWorkerScriptLoader::ScriptCompiler::Run()
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (mRevoked) {
return NS_OK;
}
NS_ASSERTION(!mScriptObj.ToJSObject(), "Already have a script object?!");
NS_ASSERTION(mScriptObj.IsHeld(), "Not held?!");
NS_ASSERTION(!mScriptText.IsEmpty(), "Shouldn't have empty source here!");
JSContext* cx = nsDOMThreadService::GetCurrentContext();
NS_ENSURE_STATE(cx);
JSAutoRequest ar(cx);
JSObject* global = JS_GetGlobalObject(cx);
NS_ENSURE_STATE(global);
// Because we may have nested calls to this function we don't want the
// execution to automatically report errors. We let them propagate instead.
uint32 oldOpts =
JS_SetOptions(cx, JS_GetOptions(cx) | JSOPTION_DONT_REPORT_UNCAUGHT |
JSOPTION_NO_SCRIPT_RVAL);
JSPrincipals* principal = nsDOMWorkerSecurityManager::WorkerPrincipal();
JSObject* scriptObj =
JS_CompileUCScriptForPrincipals(cx, global, principal,
reinterpret_cast<const jschar*>
(mScriptText.BeginReading()),
mScriptText.Length(), mFilename.get(), 1);
JS_SetOptions(cx, oldOpts);
if (!scriptObj) {
return NS_ERROR_FAILURE;
}
mScriptObj = scriptObj;
return NS_OK;
}
nsDOMWorkerScriptLoader::
ScriptLoaderDone::ScriptLoaderDone(nsDOMWorkerScriptLoader* aLoader,
volatile PRBool* aDoneFlag)
: ScriptLoaderRunnable(aLoader),
mDoneFlag(aDoneFlag)
{
NS_ASSERTION(aDoneFlag && !*aDoneFlag, "Bad setup!");
}
NS_IMETHODIMP
nsDOMWorkerScriptLoader::ScriptLoaderDone::Run()
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (mRevoked) {
return NS_OK;
}
*mDoneFlag = PR_TRUE;
return NS_OK;
}
nsDOMWorkerScriptLoader::
AutoSuspendWorkerEvents::AutoSuspendWorkerEvents(nsDOMWorkerScriptLoader* aLoader)
: mLoader(aLoader)
{
NS_ASSERTION(aLoader, "Don't hand me null!");
aLoader->SuspendWorkerEvents();
}
nsDOMWorkerScriptLoader::
AutoSuspendWorkerEvents::~AutoSuspendWorkerEvents()
{
mLoader->ResumeWorkerEvents();
}

Просмотреть файл

@ -1,225 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is worker threads.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef __NSDOMWORKERSCRIPTLOADER_H__
#define __NSDOMWORKERSCRIPTLOADER_H__
// Bases
#include "nsIRunnable.h"
#include "nsIStreamLoader.h"
// Interfaces
#include "nsIChannel.h"
#include "nsIURI.h"
// Other includes
#include "jsapi.h"
#include "nsAutoPtr.h"
#include "nsAutoJSValHolder.h"
#include "nsCOMPtr.h"
#include "nsStringGlue.h"
#include "nsTArray.h"
#include "nsDOMWorker.h"
class nsIThread;
/**
* This class takes a list of script URLs, downloads the scripts, compiles the
* scripts, and then finally executes them. Due to platform limitations all
* network operations must happen on the main thread so this object sends events
* back and forth from the worker thread to the main thread. The flow goes like
* this:
*
* 1. (Worker thread) nsDOMWorkerScriptLoader created.
* 2. (Worker thread) LoadScript(s) called. Some simple argument validation is
* performed (currently limited to ensuring that all
* arguments are strings). nsDOMWorkerScriptLoader is then
* dispatched to the main thread.
* 3. (Main thread) Arguments validated as URIs, security checks performed,
* content policy consulted. Network loads begin.
* 4. (Necko thread) Necko stuff!
* 5. (Main thread) Completed downloads are packaged in a ScriptCompiler
* runnable and sent to the worker thread.
* 6. (Worker thread) ScriptCompiler runnables are processed (i.e. their
* scripts are compiled) in the order in which the necko
* downloads completed.
* 7. (Worker thread) After all loads complete and all compilation succeeds
* the scripts are executed in the order that the URLs were
* given to LoadScript(s).
*
* Currently if *anything* after 2 fails then we cancel any pending loads and
* bail out entirely.
*/
class nsDOMWorkerScriptLoader : public nsDOMWorkerFeature,
public nsIRunnable,
public nsIStreamLoaderObserver
{
typedef mozilla::Mutex Mutex;
friend class AutoSuspendWorkerEvents;
friend class ScriptLoaderRunnable;
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIRUNNABLE
NS_DECL_NSISTREAMLOADEROBSERVER
nsDOMWorkerScriptLoader(nsDOMWorker* aWorker);
nsresult LoadScripts(JSContext* aCx,
const nsTArray<nsString>& aURLs,
PRBool aExecute);
nsresult LoadWorkerScript(JSContext* aCx,
const nsString& aURL);
nsresult ExecuteScripts(JSContext* aCx);
virtual void Cancel();
private:
~nsDOMWorkerScriptLoader() { }
nsresult DoRunLoop(JSContext* aCx);
nsresult VerifyScripts(JSContext* aCx);
nsresult RunInternal();
nsresult OnStreamCompleteInternal(nsIStreamLoader* aLoader,
nsISupports* aContext,
nsresult aStatus,
PRUint32 aStringLen,
const PRUint8* aString);
void NotifyDone();
void SuspendWorkerEvents();
void ResumeWorkerEvents();
Mutex& GetLock() {
return mWorker->GetLock();
}
class ScriptLoaderRunnable : public nsIRunnable
{
public:
NS_DECL_ISUPPORTS
protected:
// Meant to be inherited.
ScriptLoaderRunnable(nsDOMWorkerScriptLoader* aLoader);
virtual ~ScriptLoaderRunnable();
public:
void Revoke();
protected:
PRBool mRevoked;
private:
nsDOMWorkerScriptLoader* mLoader;
};
class ScriptCompiler : public ScriptLoaderRunnable
{
public:
NS_DECL_NSIRUNNABLE
ScriptCompiler(nsDOMWorkerScriptLoader* aLoader,
const nsString& aScriptText,
const nsCString& aFilename,
nsAutoJSValHolder& aScriptObj);
private:
nsString mScriptText;
nsCString mFilename;
nsAutoJSValHolder& mScriptObj;
};
class ScriptLoaderDone : public ScriptLoaderRunnable
{
public:
NS_DECL_NSIRUNNABLE
ScriptLoaderDone(nsDOMWorkerScriptLoader* aLoader,
volatile PRBool* aDoneFlag);
private:
volatile PRBool* mDoneFlag;
};
class AutoSuspendWorkerEvents
{
public:
AutoSuspendWorkerEvents(nsDOMWorkerScriptLoader* aLoader);
~AutoSuspendWorkerEvents();
private:
nsDOMWorkerScriptLoader* mLoader;
};
struct ScriptLoadInfo
{
ScriptLoadInfo() : done(PR_FALSE), result(NS_ERROR_NOT_INITIALIZED) { }
nsString url;
nsString scriptText;
PRBool done;
nsresult result;
nsCOMPtr<nsIURI> finalURI;
nsCOMPtr<nsIChannel> channel;
nsAutoJSValHolder scriptObj;
};
nsIThread* mTarget;
nsRefPtr<ScriptLoaderDone> mDoneRunnable;
PRUint32 mScriptCount;
nsTArray<ScriptLoadInfo> mLoadInfos;
// Protected by mWorker's lock!
nsTArray<ScriptLoaderRunnable*> mPendingRunnables;
PRPackedBool mCanceled;
PRPackedBool mForWorker;
};
#endif /* __NSDOMWORKERSCRIPTLOADER_H__ */

Просмотреть файл

@ -1,148 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is worker threads.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsDOMWorkerSecurityManager.h"
// Interfaces
#include "nsIClassInfo.h"
// Other includes
#include "jsapi.h"
#include "nsDOMError.h"
#include "nsThreadUtils.h"
// DOMWorker includes
#include "nsDOMThreadService.h"
#include "nsDOMWorker.h"
#define LOG(_args) PR_LOG(gDOMThreadsLog, PR_LOG_DEBUG, _args)
class nsDOMWorkerPrincipal
{
public:
static void Destroy(JSContext*, JSPrincipals*) {
// nothing
}
static JSBool Subsume(JSPrincipals*, JSPrincipals*) {
return JS_TRUE;
}
};
static JSPrincipals gWorkerPrincipal =
{ "domworkerthread" /* codebase */,
NULL /* getPrincipalArray */,
NULL /* globalPrivilegesEnabled */,
1 /* refcount */,
nsDOMWorkerPrincipal::Destroy /* destroy */,
nsDOMWorkerPrincipal::Subsume /* subsume */ };
NS_IMPL_THREADSAFE_ISUPPORTS1(nsDOMWorkerSecurityManager,
nsIXPCSecurityManager)
NS_IMETHODIMP
nsDOMWorkerSecurityManager::CanCreateWrapper(JSContext* aCx,
const nsIID& aIID,
nsISupports* aObj,
nsIClassInfo* aClassInfo,
void** aPolicy)
{
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerSecurityManager::CanCreateInstance(JSContext* aCx,
const nsCID& aCID)
{
return CanGetService(aCx, aCID);
}
NS_IMETHODIMP
nsDOMWorkerSecurityManager::CanGetService(JSContext* aCx,
const nsCID& aCID)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
nsDOMWorker* worker = static_cast<nsDOMWorker*>(JS_GetContextPrivate(aCx));
NS_ASSERTION(worker, "This should be set by the DOM thread service!");
return worker->IsPrivileged() ? NS_OK : NS_ERROR_DOM_XPCONNECT_ACCESS_DENIED;
}
NS_IMETHODIMP
nsDOMWorkerSecurityManager::CanAccess(PRUint32 aAction,
nsAXPCNativeCallContext* aCallContext,
JSContext* aJSContext,
JSObject* aJSObject,
nsISupports* aObj,
nsIClassInfo* aClassInfo,
jsid aName,
void** aPolicy)
{
return NS_OK;
}
JSPrincipals*
nsDOMWorkerSecurityManager::WorkerPrincipal()
{
return &gWorkerPrincipal;
}
JSBool
nsDOMWorkerSecurityManager::JSCheckAccess(JSContext* aCx,
JSObject* aObj,
jsid aId,
JSAccessMode aMode,
jsval* aVp)
{
return JS_TRUE;
}
JSPrincipals*
nsDOMWorkerSecurityManager::JSFindPrincipal(JSContext* aCx, JSObject* aObj)
{
return WorkerPrincipal();
}
JSBool
nsDOMWorkerSecurityManager::JSTranscodePrincipals(JSXDRState* aXdr,
JSPrincipals** aJsprinp)
{
NS_NOTREACHED("Shouldn't ever call this!");
return JS_FALSE;
}

Просмотреть файл

@ -1,485 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is worker threads.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsDOMWorkerTimeout.h"
// Interfaces
#include "nsIJSContextStack.h"
#include "nsIJSRuntimeService.h"
#include "nsITimer.h"
#include "nsIXPConnect.h"
// Other includes
#include "nsContentUtils.h"
#include "nsJSUtils.h"
#include "nsThreadUtils.h"
#include "pratom.h"
#include "prtime.h"
// DOMWorker includes
#include "nsDOMThreadService.h"
#include "nsDOMWorkerSecurityManager.h"
#define LOG(_args) PR_LOG(gDOMThreadsLog, PR_LOG_DEBUG, _args)
#define CONSTRUCTOR_ENSURE_TRUE(_cond, _rv) \
PR_BEGIN_MACRO \
if (NS_UNLIKELY(!(_cond))) { \
NS_WARNING("CONSTRUCTOR_ENSURE_TRUE(" #_cond ") failed"); \
(_rv) = NS_ERROR_FAILURE; \
return; \
} \
PR_END_MACRO
#define SUSPEND_SPINLOCK_COUNT 5000
static const char* kSetIntervalStr = "setInterval";
static const char* kSetTimeoutStr = "setTimeout";
nsDOMWorkerTimeout::FunctionCallback::FunctionCallback(PRUint32 aArgc,
jsval* aArgv,
nsresult* aRv)
: mCallbackArgsLength(0)
{
MOZ_COUNT_CTOR(nsDOMWorkerTimeout::FunctionCallback);
JSRuntime* rt;
*aRv = nsDOMThreadService::JSRuntimeService()->GetRuntime(&rt);
if (NS_FAILED(*aRv))
return;
JSBool ok = mCallback.Hold(rt);
CONSTRUCTOR_ENSURE_TRUE(ok, *aRv);
mCallback = aArgv[0];
// We want enough space for an extra lateness arg.
mCallbackArgsLength = aArgc > 2 ? aArgc - 1 : 1;
PRBool success = mCallbackArgs.SetLength(mCallbackArgsLength);
CONSTRUCTOR_ENSURE_TRUE(success, *aRv);
PRUint32 index = 0;
for (; index < mCallbackArgsLength - 1; index++) {
ok = mCallbackArgs[index].Hold(rt);
CONSTRUCTOR_ENSURE_TRUE(ok, *aRv);
mCallbackArgs[index] = aArgv[index + 2];
}
// Take care of the last arg.
index = mCallbackArgsLength - 1;
ok = mCallbackArgs[index].Hold(rt);
CONSTRUCTOR_ENSURE_TRUE(ok, *aRv);
*aRv = NS_OK;
}
nsDOMWorkerTimeout::FunctionCallback::~FunctionCallback()
{
MOZ_COUNT_DTOR(nsDOMWorkerTimeout::FunctionCallback);
}
nsresult
nsDOMWorkerTimeout::FunctionCallback::Run(nsDOMWorkerTimeout* aTimeout,
JSContext* aCx)
{
PRInt32 lateness = NS_MAX(0, PRInt32(PR_Now() - aTimeout->mTargetTime)) /
(PRTime)PR_USEC_PER_MSEC;
mCallbackArgs[mCallbackArgsLength - 1] = INT_TO_JSVAL(lateness);
JSObject* global = JS_GetGlobalObject(aCx);
NS_ENSURE_TRUE(global, NS_ERROR_FAILURE);
nsTArray<jsval> argv;
PRBool success = argv.SetCapacity(mCallbackArgsLength);
NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY);
for (PRUint32 index = 0; index < mCallbackArgsLength; index++) {
argv.AppendElement(mCallbackArgs[index]);
}
jsval rval;
JSBool ok =
JS_CallFunctionValue(aCx, global, mCallback, mCallbackArgsLength,
argv.Elements(), &rval);
NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
return NS_OK;
}
nsDOMWorkerTimeout::ExpressionCallback::ExpressionCallback(PRUint32 aArgc,
jsval* aArgv,
JSContext* aCx,
nsresult* aRv)
: mLineNumber(0)
{
MOZ_COUNT_CTOR(nsDOMWorkerTimeout::ExpressionCallback);
JSString* expr = JS_ValueToString(aCx, aArgv[0]);
*aRv = expr ? NS_OK : NS_ERROR_FAILURE;
if (NS_FAILED(*aRv))
return;
JSRuntime* rt;
*aRv = nsDOMThreadService::JSRuntimeService()->GetRuntime(&rt);
if (NS_FAILED(*aRv))
return;
JSBool ok = mExpression.Hold(rt);
CONSTRUCTOR_ENSURE_TRUE(ok, *aRv);
mExpression = aArgv[0];
// Get the calling location.
const char* fileName;
PRUint32 lineNumber;
if (nsJSUtils::GetCallingLocation(aCx, &fileName, &lineNumber)) {
mFileName.Assign(fileName);
mLineNumber = lineNumber;
}
*aRv = NS_OK;
}
nsDOMWorkerTimeout::ExpressionCallback::~ExpressionCallback()
{
MOZ_COUNT_DTOR(nsDOMWorkerTimeout::ExpressionCallback);
}
nsresult
nsDOMWorkerTimeout::ExpressionCallback::Run(nsDOMWorkerTimeout* aTimeout,
JSContext* aCx)
{
JSObject* global = JS_GetGlobalObject(aCx);
NS_ENSURE_TRUE(global, NS_ERROR_FAILURE);
JSPrincipals* principal = nsDOMWorkerSecurityManager::WorkerPrincipal();
NS_ENSURE_TRUE(principal, NS_ERROR_FAILURE);
JSString* expression = JS_ValueToString(aCx, mExpression);
NS_ENSURE_TRUE(expression, NS_ERROR_FAILURE);
size_t stringLength;
const jschar* string = JS_GetStringCharsAndLength(aCx, expression, &stringLength);
NS_ENSURE_TRUE(string, NS_ERROR_FAILURE);
PRBool success = JS_EvaluateUCScriptForPrincipals(aCx, global, principal,
string, stringLength,
mFileName.get(),
mLineNumber, nsnull);
if (!success) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
nsDOMWorkerTimeout::nsDOMWorkerTimeout(nsDOMWorker* aWorker,
PRUint32 aId)
: nsDOMWorkerFeature(aWorker, aId),
mInterval(0),
mSuspendSpinlock(0),
mSuspendInterval(0),
mIsInterval(PR_FALSE),
mIsSuspended(PR_FALSE),
mSuspendedBeforeStart(PR_FALSE),
mStarted(PR_FALSE)
{
NS_ASSERTION(mWorker, "Need a worker here!");
}
NS_IMPL_ISUPPORTS_INHERITED1(nsDOMWorkerTimeout, nsDOMWorkerFeature,
nsITimerCallback)
nsresult
nsDOMWorkerTimeout::Init(JSContext* aCx, PRUint32 aArgc, jsval* aArgv,
PRBool aIsInterval)
{
NS_ASSERTION(aCx, "Null pointer!");
NS_ASSERTION(aArgv, "Null pointer!");
JSAutoRequest ar(aCx);
if (!aArgc) {
JS_ReportError(aCx, "Function %s requires at least 1 parameter",
aIsInterval ? kSetIntervalStr : kSetTimeoutStr);
return NS_ERROR_INVALID_ARG;
}
PRUint32 interval;
if (aArgc > 1) {
if (!JS_ValueToECMAUint32(aCx, aArgv[1], (uint32*)&interval)) {
JS_ReportError(aCx, "Second argument to %s must be a millisecond value",
aIsInterval ? kSetIntervalStr : kSetTimeoutStr);
return NS_ERROR_INVALID_ARG;
}
}
else {
// If no interval was specified, treat this like a timeout, to avoid
// setting an interval of 0 milliseconds.
interval = 0;
aIsInterval = PR_FALSE;
}
mInterval = interval;
mIsInterval = aIsInterval;
mTargetTime = PR_Now() + interval * (PRTime)PR_USEC_PER_MSEC;
nsresult rv;
switch (JS_TypeOfValue(aCx, aArgv[0])) {
case JSTYPE_FUNCTION:
mCallback = new FunctionCallback(aArgc, aArgv, &rv);
NS_ENSURE_TRUE(mCallback, NS_ERROR_OUT_OF_MEMORY);
NS_ENSURE_SUCCESS(rv, rv);
break;
case JSTYPE_STRING:
case JSTYPE_OBJECT:
mCallback = new ExpressionCallback(aArgc, aArgv, aCx, &rv);
NS_ENSURE_TRUE(mCallback, NS_ERROR_OUT_OF_MEMORY);
NS_ENSURE_SUCCESS(rv, rv);
break;
default:
JS_ReportError(aCx, "useless %s call (missing quotes around argument?)",
aIsInterval ? kSetIntervalStr : kSetTimeoutStr);
// Return an error that nsGlobalWindow can recognize and turn into NS_OK.
return NS_ERROR_INVALID_ARG;
}
nsCOMPtr<nsITimer> timer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsIEventTarget* target =
static_cast<nsIEventTarget*>(nsDOMThreadService::get());
rv = timer->SetTarget(target);
NS_ENSURE_SUCCESS(rv, rv);
mTimer.swap(timer);
return NS_OK;
}
nsresult
nsDOMWorkerTimeout::Start()
{
if (IsSuspended()) {
NS_ASSERTION(mSuspendedBeforeStart, "Bad state!");
return NS_OK;
}
nsresult rv = mTimer->InitWithCallback(this, mInterval,
nsITimer::TYPE_ONE_SHOT);
NS_ENSURE_SUCCESS(rv, rv);
mStarted = PR_TRUE;
return NS_OK;
}
nsresult
nsDOMWorkerTimeout::Run()
{
NS_ENSURE_TRUE(mCallback, NS_ERROR_NOT_INITIALIZED);
LOG(("Worker [0x%p] running timeout [0x%p] with id %u",
static_cast<void*>(mWorker.get()), static_cast<void*>(this), mId));
JSContext* cx;
nsresult rv =
nsDOMThreadService::ThreadJSContextStack()->GetSafeJSContext(&cx);
NS_ENSURE_SUCCESS(rv, rv);
JSAutoRequest ar(cx);
rv = mCallback->Run(this, cx);
// Make sure any pending exceptions are converted to errors for the pool.
JS_ReportPendingException(cx);
if (mIsInterval) {
mTargetTime = PR_Now() + mInterval * (PRTime)PR_USEC_PER_MSEC;
nsresult rv2 = mTimer->InitWithCallback(this, mInterval,
nsITimer::TYPE_ONE_SHOT);
NS_ENSURE_SUCCESS(rv2, rv2);
}
return rv;
}
void
nsDOMWorkerTimeout::Cancel()
{
NS_ASSERTION(mTimer, "Impossible to get here without a timer!");
LOG(("Worker [0x%p] canceling timeout [0x%p] with id %u",
static_cast<void*>(mWorker.get()), static_cast<void*>(this), mId));
{
AutoSpinlock lock(this);
if (IsSuspendedNoLock()) {
mIsSuspended = PR_FALSE;
// This should kill us when all is said and done.
mSuspendedRef = nsnull;
}
}
// This call to Cancel should kill us.
mTimer->Cancel();
}
void
nsDOMWorkerTimeout::Suspend()
{
AutoSpinlock lock(this);
NS_ASSERTION(!IsSuspendedNoLock(), "Bad state!");
mIsSuspended = PR_TRUE;
mSuspendedRef = this;
if (!mStarted) {
mSuspendedBeforeStart = PR_TRUE;
return;
}
mTimer->Cancel();
mSuspendInterval = NS_MAX(0, PRInt32(mTargetTime - PR_Now())) /
(PRTime)PR_USEC_PER_MSEC;
LOG(("Worker [0x%p] suspending timeout [0x%p] with id %u (interval = %u)",
static_cast<void*>(mWorker.get()), static_cast<void*>(this), mId,
mSuspendInterval));
}
void
nsDOMWorkerTimeout::Resume()
{
NS_ASSERTION(mTimer, "Impossible to get here without a timer!");
LOG(("Worker [0x%p] resuming timeout [0x%p] with id %u",
static_cast<void*>(mWorker.get()), static_cast<void*>(this), mId));
AutoSpinlock lock(this);
NS_ASSERTION(IsSuspendedNoLock(), "Should be suspended!");
if (mSuspendedBeforeStart) {
NS_ASSERTION(!mSuspendInterval, "Bad state!");
mSuspendedBeforeStart = PR_FALSE;
mSuspendInterval = mInterval;
mStarted = PR_TRUE;
}
mTargetTime = PR_Now() + mSuspendInterval * (PRTime)PR_USEC_PER_MSEC;
#ifdef DEBUG
nsresult rv =
#endif
mTimer->InitWithCallback(this, mSuspendInterval, nsITimer::TYPE_ONE_SHOT);
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Failed to init timer!");
}
void
nsDOMWorkerTimeout::AcquireSpinlock()
{
PRUint32 loopCount = 0;
while (PR_ATOMIC_SET(&mSuspendSpinlock, 1) == 1) {
if (++loopCount > SUSPEND_SPINLOCK_COUNT) {
LOG(("AcquireSpinlock taking too long (looped %u times), yielding.",
loopCount));
loopCount = 0;
PR_Sleep(PR_INTERVAL_NO_WAIT);
}
}
#ifdef PR_LOGGING
if (loopCount) {
LOG(("AcquireSpinlock needed %u loops", loopCount));
}
#endif
}
void
nsDOMWorkerTimeout::ReleaseSpinlock()
{
#ifdef DEBUG
PRInt32 suspended =
#endif
PR_ATOMIC_SET(&mSuspendSpinlock, 0);
NS_ASSERTION(suspended == 1, "Huh?!");
}
NS_IMETHODIMP
nsDOMWorkerTimeout::Notify(nsITimer* aTimer)
{
// Should be on the timer thread.
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(aTimer == mTimer, "Wrong timer?!");
PRUint32 type;
nsresult rv = aTimer->GetType(&type);
NS_ENSURE_SUCCESS(rv, rv);
// We only care about one-shot timers here because that may be the one that
// we set from Resume().
if (type == nsITimer::TYPE_ONE_SHOT) {
AutoSpinlock lock(this);
if (mIsSuspended) {
mIsSuspended = PR_FALSE;
mSuspendedRef = nsnull;
if (mIsInterval) {
// This is the first fire since we resumed. Set our interval back to the
// real interval.
mTargetTime = PR_Now() + mInterval * (PRTime)PR_USEC_PER_MSEC;
rv = aTimer->InitWithCallback(this, mInterval,
nsITimer::TYPE_REPEATING_SLACK);
NS_ENSURE_SUCCESS(rv, rv);
}
}
}
nsDOMThreadService::get()->TimeoutReady(this);
return NS_OK;
}

Просмотреть файл

@ -1,190 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is worker threads.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef __NSDOMWORKERTIMEOUT_H__
#define __NSDOMWORKERTIMEOUT_H__
// Interfaces
#include "nsITimer.h"
// Other includes
#include "jsapi.h"
#include "nsAutoJSValHolder.h"
#include "nsAutoPtr.h"
#include "nsCOMPtr.h"
#include "nsStringGlue.h"
#include "nsTArray.h"
// DOMWorker includes
#include "nsDOMWorker.h"
/**
* The nsDOMWorkerTimeout has a slightly complicated life cycle. It's created
* by an nsDOMWorker (or one of its JS context functions) and immediately takes
* a strong reference to the worker that created it. It does this so that the
* worker can't be collected while a timeout is outstanding. However, the worker
* needs a weak reference to the timeout so that it can be canceled if the
* worker is canceled (in the event that the page falls out of the fastback
* cache or the application is exiting, for instance). The only thing that holds
* the timeout alive is its mTimer via the nsITimerCallback interface. If the
* timer is single-shot and has run already or if the timer is canceled then
* this object should die.
*/
class nsDOMWorkerTimeout : public nsDOMWorkerFeature,
public nsITimerCallback
{
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSITIMERCALLBACK
nsDOMWorkerTimeout(nsDOMWorker* aWorker,
PRUint32 aId);
nsresult Init(JSContext* aCx,
PRUint32 aArgc,
jsval* aArgv,
PRBool aIsInterval);
nsresult Start();
nsresult Run();
virtual void Cancel();
virtual void Suspend();
virtual void Resume();
PRIntervalTime GetInterval() {
return mInterval;
}
nsDOMWorker* GetWorker() {
return mWorker;
}
PRBool IsSuspended() {
AutoSpinlock lock(this);
return IsSuspendedNoLock();
}
private:
~nsDOMWorkerTimeout() { }
void AcquireSpinlock();
void ReleaseSpinlock();
PRBool IsSuspendedNoLock() {
return mIsSuspended;
}
class AutoSpinlock
{
public:
AutoSpinlock(nsDOMWorkerTimeout* aTimeout)
: mTimeout(aTimeout) {
aTimeout->AcquireSpinlock();
}
~AutoSpinlock() {
mTimeout->ReleaseSpinlock();
}
private:
nsDOMWorkerTimeout* mTimeout;
};
// We support two types of callbacks (functions and expressions) just like the
// normal window timeouts. Each type has its own member and rooting needs so
// we split them into two classes with a common base.
class CallbackBase
{
public:
virtual ~CallbackBase() { }
virtual nsresult Run(nsDOMWorkerTimeout* aTimeout,
JSContext* aCx) = 0;
};
class FunctionCallback : public CallbackBase
{
public:
FunctionCallback(PRUint32 aArgc,
jsval* aArgv,
nsresult* aRv);
virtual ~FunctionCallback();
virtual nsresult Run(nsDOMWorkerTimeout* aTimeout,
JSContext* aCx);
protected:
nsAutoJSValHolder mCallback;
nsTArray<nsAutoJSValHolder> mCallbackArgs;
PRUint32 mCallbackArgsLength;
};
class ExpressionCallback : public CallbackBase
{
public:
ExpressionCallback(PRUint32 aArgc,
jsval* aArgv,
JSContext* aCx,
nsresult* aRv);
virtual ~ExpressionCallback();
virtual nsresult Run(nsDOMWorkerTimeout* aTimeout,
JSContext* aCx);
protected:
nsAutoJSValHolder mExpression;
nsCString mFileName;
PRUint32 mLineNumber;
};
// Hold this object alive!
nsCOMPtr<nsITimer> mTimer;
PRUint32 mInterval;
PRTime mTargetTime;
nsAutoPtr<CallbackBase> mCallback;
PRInt32 mSuspendSpinlock;
PRUint32 mSuspendInterval;
nsRefPtr<nsDOMWorkerTimeout> mSuspendedRef;
PRPackedBool mIsInterval;
PRPackedBool mIsSuspended;
PRPackedBool mSuspendedBeforeStart;
PRPackedBool mStarted;
};
#endif /* __NSDOMWORKERTIMEOUT_H__ */

Просмотреть файл

@ -1,910 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is worker threads.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsDOMWorkerXHR.h"
// Interfaces
#include "nsIDocument.h"
#include "nsIDOMEvent.h"
#include "nsIThread.h"
#include "nsIXPConnect.h"
// Other includes
#include "nsAXPCNativeCallContext.h"
#include "nsComponentManagerUtils.h"
#include "nsContentUtils.h"
#include "nsIClassInfoImpl.h"
#include "nsJSUtils.h"
#include "nsThreadUtils.h"
// DOMWorker includes
#include "nsDOMThreadService.h"
#include "nsDOMWorkerEvents.h"
#include "nsDOMWorkerPool.h"
#include "nsDOMWorkerXHRProxy.h"
using namespace mozilla;
// The list of event types that we support. This list and the defines based on
// it determine the sizes of the listener arrays in nsDOMWorkerXHRProxy. Make
// sure that any event types shared by both the XHR and Upload objects are
// together at the beginning of the list. Any changes made to this list may
// affect sMaxUploadEventTypes, so make sure that it is adjusted accordingly or
// things will break!
const char* const nsDOMWorkerXHREventTarget::sListenerTypes[] = {
// nsIXMLHttpRequestEventTarget listeners.
"abort", /* LISTENER_TYPE_ABORT */
"error", /* LISTENER_TYPE_ERROR */
"load", /* LISTENER_TYPE_LOAD */
"loadstart", /* LISTENER_TYPE_LOADSTART */
"progress", /* LISTENER_TYPE_PROGRESS */
// nsIXMLHttpRequest listeners.
"readystatechange", /* LISTENER_TYPE_READYSTATECHANGE */
"loadend"
};
// This should always be set to the length of sListenerTypes.
const PRUint32 nsDOMWorkerXHREventTarget::sMaxXHREventTypes =
NS_ARRAY_LENGTH(nsDOMWorkerXHREventTarget::sListenerTypes);
// This should be set to the index of the first event type that is *not*
// supported by the Upload object.
const PRUint32 nsDOMWorkerXHREventTarget::sMaxUploadEventTypes =
LISTENER_TYPE_READYSTATECHANGE;
// Enforce the invariant that the upload object supports no more event types
// than the xhr object.
PR_STATIC_ASSERT(nsDOMWorkerXHREventTarget::sMaxXHREventTypes >=
nsDOMWorkerXHREventTarget::sMaxUploadEventTypes);
NS_IMPL_ISUPPORTS_INHERITED1(nsDOMWorkerXHREventTarget,
nsDOMWorkerMessageHandler,
nsIXMLHttpRequestEventTarget)
PRUint32
nsDOMWorkerXHREventTarget::GetListenerTypeFromString(const nsAString& aString)
{
for (PRUint32 index = 0; index < sMaxXHREventTypes; index++) {
if (aString.EqualsASCII(sListenerTypes[index])) {
return index;
}
}
return PR_UINT32_MAX;
}
NS_IMETHODIMP
nsDOMWorkerXHREventTarget::GetOnabort(nsIDOMEventListener** aOnabort)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
NS_ENSURE_ARG_POINTER(aOnabort);
nsAutoString type;
type.AssignASCII(sListenerTypes[LISTENER_TYPE_ABORT]);
nsCOMPtr<nsIDOMEventListener> listener = GetOnXListener(type);
listener.forget(aOnabort);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHREventTarget::SetOnabort(nsIDOMEventListener* aOnabort)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
nsAutoString type;
type.AssignASCII(sListenerTypes[LISTENER_TYPE_ABORT]);
return SetOnXListener(type, aOnabort);
}
NS_IMETHODIMP
nsDOMWorkerXHREventTarget::GetOnerror(nsIDOMEventListener** aOnerror)
{
NS_ENSURE_ARG_POINTER(aOnerror);
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
nsAutoString type;
type.AssignASCII(sListenerTypes[LISTENER_TYPE_ERROR]);
nsCOMPtr<nsIDOMEventListener> listener = GetOnXListener(type);
listener.forget(aOnerror);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHREventTarget::SetOnerror(nsIDOMEventListener* aOnerror)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
nsAutoString type;
type.AssignASCII(sListenerTypes[LISTENER_TYPE_ERROR]);
return SetOnXListener(type, aOnerror);
}
NS_IMETHODIMP
nsDOMWorkerXHREventTarget::GetOnload(nsIDOMEventListener** aOnload)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
NS_ENSURE_ARG_POINTER(aOnload);
nsAutoString type;
type.AssignASCII(sListenerTypes[LISTENER_TYPE_LOAD]);
nsCOMPtr<nsIDOMEventListener> listener = GetOnXListener(type);
listener.forget(aOnload);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHREventTarget::SetOnload(nsIDOMEventListener* aOnload)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
nsAutoString type;
type.AssignASCII(sListenerTypes[LISTENER_TYPE_LOAD]);
return SetOnXListener(type, aOnload);
}
NS_IMETHODIMP
nsDOMWorkerXHREventTarget::GetOnloadstart(nsIDOMEventListener** aOnloadstart)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
NS_ENSURE_ARG_POINTER(aOnloadstart);
nsAutoString type;
type.AssignASCII(sListenerTypes[LISTENER_TYPE_LOADSTART]);
nsCOMPtr<nsIDOMEventListener> listener = GetOnXListener(type);
listener.forget(aOnloadstart);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHREventTarget::SetOnloadstart(nsIDOMEventListener* aOnloadstart)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
nsAutoString type;
type.AssignASCII(sListenerTypes[LISTENER_TYPE_LOADSTART]);
return SetOnXListener(type, aOnloadstart);
}
NS_IMETHODIMP
nsDOMWorkerXHREventTarget::GetOnprogress(nsIDOMEventListener** aOnprogress)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
NS_ENSURE_ARG_POINTER(aOnprogress);
nsAutoString type;
type.AssignASCII(sListenerTypes[LISTENER_TYPE_PROGRESS]);
nsCOMPtr<nsIDOMEventListener> listener = GetOnXListener(type);
listener.forget(aOnprogress);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHREventTarget::SetOnprogress(nsIDOMEventListener* aOnprogress)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
nsAutoString type;
type.AssignASCII(sListenerTypes[LISTENER_TYPE_PROGRESS]);
return SetOnXListener(type, aOnprogress);
}
NS_IMETHODIMP
nsDOMWorkerXHREventTarget::GetOnloadend(nsIDOMEventListener** aOnloadend)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
NS_ENSURE_ARG_POINTER(aOnloadend);
nsAutoString type;
type.AssignASCII(sListenerTypes[LISTENER_TYPE_LOADEND]);
nsCOMPtr<nsIDOMEventListener> listener = GetOnXListener(type);
listener.forget(aOnloadend);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHREventTarget::SetOnloadend(nsIDOMEventListener* aOnloadend)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
nsAutoString type;
type.AssignASCII(sListenerTypes[LISTENER_TYPE_LOADEND]);
return SetOnXListener(type, aOnloadend);
}
nsDOMWorkerXHRUpload::nsDOMWorkerXHRUpload(nsDOMWorkerXHR* aWorkerXHR)
: mWorkerXHR(aWorkerXHR)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(aWorkerXHR, "Null pointer!");
}
NS_IMPL_ISUPPORTS_INHERITED1(nsDOMWorkerXHRUpload, nsDOMWorkerXHREventTarget,
nsIXMLHttpRequestUpload)
NS_IMPL_CI_INTERFACE_GETTER3(nsDOMWorkerXHRUpload, nsIDOMEventTarget,
nsIXMLHttpRequestEventTarget,
nsIXMLHttpRequestUpload)
NS_IMPL_THREADSAFE_DOM_CI_GETINTERFACES(nsDOMWorkerXHRUpload)
NS_IMETHODIMP
nsDOMWorkerXHRUpload::RemoveEventListener(const nsAString& aType,
nsIDOMEventListener* aListener,
PRBool aUseCapture)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
NS_ENSURE_ARG_POINTER(aListener);
if (mWorkerXHR->mWorker->IsCanceled()) {
return NS_ERROR_ABORT;
}
return nsDOMWorkerXHREventTarget::RemoveEventListener(aType, aListener,
aUseCapture);
}
NS_IMETHODIMP
nsDOMWorkerXHRUpload::DispatchEvent(nsIDOMEvent* aEvent,
PRBool* _retval)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
NS_ENSURE_ARG_POINTER(aEvent);
if (mWorkerXHR->mWorker->IsCanceled()) {
return NS_ERROR_ABORT;
}
return nsDOMWorkerXHREventTarget::DispatchEvent(aEvent, _retval);
}
NS_IMETHODIMP
nsDOMWorkerXHRUpload::AddEventListener(const nsAString& aType,
nsIDOMEventListener* aListener,
PRBool aUseCapture,
PRBool aWantsUntrusted,
PRUint8 optional_argc)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
NS_ENSURE_ARG_POINTER(aListener);
if (mWorkerXHR->mWorker->IsCanceled()) {
return NS_ERROR_ABORT;
}
nsresult rv = nsDOMWorkerXHREventTarget::AddEventListener(aType, aListener,
aUseCapture,
aWantsUntrusted,
optional_argc);
NS_ENSURE_SUCCESS(rv, rv);
rv = mWorkerXHR->mXHRProxy->UploadEventListenerAdded();
if (NS_FAILED(rv)) {
NS_WARNING("UploadEventListenerAdded failed!");
RemoveEventListener(aType, aListener, aUseCapture);
return rv;
}
return NS_OK;
}
nsresult
nsDOMWorkerXHRUpload::SetOnXListener(const nsAString& aType,
nsIDOMEventListener* aListener)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (mWorkerXHR->mCanceled) {
return NS_ERROR_ABORT;
}
PRUint32 type = GetListenerTypeFromString(aType);
if (type > sMaxUploadEventTypes) {
// Silently ignore junk events.
return NS_OK;
}
return nsDOMWorkerXHREventTarget::SetOnXListener(aType, aListener);
}
nsDOMWorkerXHR::nsDOMWorkerXHR(nsDOMWorker* aWorker)
: nsDOMWorkerFeature(aWorker),
mWrappedNative(nsnull),
mCanceled(PR_FALSE)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(aWorker, "Must have a worker!");
}
nsDOMWorkerXHR::~nsDOMWorkerXHR()
{
if (mXHRProxy) {
if (!NS_IsMainThread()) {
nsCOMPtr<nsIRunnable> runnable =
NS_NewRunnableMethod(mXHRProxy, &nsDOMWorkerXHRProxy::Destroy);
if (runnable) {
mXHRProxy = nsnull;
NS_DispatchToMainThread(runnable, NS_DISPATCH_NORMAL);
}
}
else {
mXHRProxy->Destroy();
}
}
}
// Tricky! We use the AddRef/Release method of nsDOMWorkerFeature (to make sure
// we properly remove ourselves from the worker array) but inherit the QI of
// nsDOMWorkerXHREventTarget.
NS_IMPL_ADDREF_INHERITED(nsDOMWorkerXHR, nsDOMWorkerFeature)
NS_IMPL_RELEASE_INHERITED(nsDOMWorkerXHR, nsDOMWorkerFeature)
NS_IMPL_QUERY_INTERFACE_INHERITED2(nsDOMWorkerXHR, nsDOMWorkerXHREventTarget,
nsIXMLHttpRequest,
nsIXPCScriptable)
NS_IMPL_CI_INTERFACE_GETTER3(nsDOMWorkerXHR, nsIDOMEventTarget,
nsIXMLHttpRequestEventTarget,
nsIXMLHttpRequest)
NS_IMPL_THREADSAFE_DOM_CI_GETINTERFACES(nsDOMWorkerXHR)
#define XPC_MAP_CLASSNAME nsDOMWorkerXHR
#define XPC_MAP_QUOTED_CLASSNAME "XMLHttpRequest"
#define XPC_MAP_WANT_POSTCREATE
#define XPC_MAP_WANT_TRACE
#define XPC_MAP_WANT_FINALIZE
#define XPC_MAP_FLAGS \
nsIXPCScriptable::DONT_ENUM_QUERY_INTERFACE | \
nsIXPCScriptable::CLASSINFO_INTERFACES_ONLY | \
nsIXPCScriptable::DONT_REFLECT_INTERFACE_NAMES
#include "xpc_map_end.h"
NS_IMETHODIMP
nsDOMWorkerXHR::Trace(nsIXPConnectWrappedNative* /* aWrapper */,
JSTracer* aTracer,
JSObject* /*aObj */)
{
if (!mCanceled) {
nsDOMWorkerMessageHandler::Trace(aTracer);
if (mUpload) {
mUpload->Trace(aTracer);
}
}
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::Finalize(nsIXPConnectWrappedNative* /* aWrapper */,
JSContext* /* aCx */,
JSObject* /* aObj */)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
nsDOMWorkerMessageHandler::ClearAllListeners();
if (mUpload) {
mUpload->ClearAllListeners();
}
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::PostCreate(nsIXPConnectWrappedNative* aWrapper,
JSContext* /* aCx */,
JSObject* /* aObj */)
{
mWrappedNative = aWrapper;
return NS_OK;
}
nsresult
nsDOMWorkerXHR::Init()
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
nsRefPtr<nsDOMWorkerXHRProxy> proxy = new nsDOMWorkerXHRProxy(this);
NS_ENSURE_TRUE(proxy, NS_ERROR_OUT_OF_MEMORY);
nsresult rv = proxy->Init();
NS_ENSURE_SUCCESS(rv, rv);
proxy.swap(mXHRProxy);
return NS_OK;
}
void
nsDOMWorkerXHR::Cancel()
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
// Just in case mUpload holds the only ref to this object we make sure to stay
// alive through this call.
nsRefPtr<nsDOMWorkerXHR> kungFuDeathGrip(this);
{
// This lock is here to prevent a race between Cancel and GetUpload, not to
// protect mCanceled.
MutexAutoLock lock(mWorker->GetLock());
mCanceled = PR_TRUE;
mUpload = nsnull;
}
if (mXHRProxy) {
mXHRProxy->Destroy();
mXHRProxy = nsnull;
}
mWorker = nsnull;
}
nsresult
nsDOMWorkerXHR::SetOnXListener(const nsAString& aType,
nsIDOMEventListener* aListener)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (mCanceled) {
return NS_ERROR_ABORT;
}
PRUint32 type = GetListenerTypeFromString(aType);
if (type > sMaxXHREventTypes) {
// Silently ignore junk events.
return NS_OK;
}
return nsDOMWorkerXHREventTarget::SetOnXListener(aType, aListener);
}
NS_IMETHODIMP
nsDOMWorkerXHR::GetChannel(nsIChannel** aChannel)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
NS_ENSURE_ARG_POINTER(aChannel);
*aChannel = nsnull;
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::GetResponseXML(nsIDOMDocument** aResponseXML)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
NS_ENSURE_ARG_POINTER(aResponseXML);
*aResponseXML = nsnull;
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::GetResponseText(nsAString& aResponseText)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (mCanceled) {
return NS_ERROR_ABORT;
}
nsresult rv = mXHRProxy->GetResponseText(aResponseText);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::GetStatus(PRUint32* aStatus)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
NS_ENSURE_ARG_POINTER(aStatus);
if (mCanceled) {
return NS_ERROR_ABORT;
}
nsresult rv = mXHRProxy->GetStatus(aStatus);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::GetStatusText(nsACString& aStatusText)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (mCanceled) {
return NS_ERROR_ABORT;
}
nsresult rv = mXHRProxy->GetStatusText(aStatusText);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::Abort()
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (mCanceled) {
return NS_ERROR_ABORT;
}
nsresult rv = mXHRProxy->Abort();
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::GetAllResponseHeaders(char** _retval)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
NS_ENSURE_ARG_POINTER(_retval);
if (mCanceled) {
return NS_ERROR_ABORT;
}
nsresult rv = mXHRProxy->GetAllResponseHeaders(_retval);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::GetResponseHeader(const nsACString& aHeader,
nsACString& _retval)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (mCanceled) {
return NS_ERROR_ABORT;
}
nsresult rv = mXHRProxy->GetResponseHeader(aHeader, _retval);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::Open(const nsACString& aMethod, const nsACString& aUrl,
PRBool aAsync, const nsAString& aUser,
const nsAString& aPassword, PRUint8 optional_argc)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (mCanceled) {
return NS_ERROR_ABORT;
}
if (!optional_argc) {
aAsync = PR_TRUE;
}
nsresult rv = mXHRProxy->Open(aMethod, aUrl, aAsync, aUser, aPassword);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::Send(nsIVariant* aBody)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (mCanceled) {
return NS_ERROR_ABORT;
}
if (mWorker->IsClosing() && !mXHRProxy->mSyncRequest) {
// Cheat and don't start this request since we know we'll never be able to
// use the data.
return NS_OK;
}
nsresult rv = mXHRProxy->Send(aBody);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::SendAsBinary(const nsAString& aBody)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (mCanceled) {
return NS_ERROR_ABORT;
}
if (mWorker->IsClosing() && !mXHRProxy->mSyncRequest) {
// Cheat and don't start this request since we know we'll never be able to
// use the data.
return NS_OK;
}
nsresult rv = mXHRProxy->SendAsBinary(aBody);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::SetRequestHeader(const nsACString& aHeader,
const nsACString& aValue)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (mCanceled) {
return NS_ERROR_ABORT;
}
nsresult rv = mXHRProxy->SetRequestHeader(aHeader, aValue);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::GetReadyState(PRUint16* aReadyState)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (mCanceled) {
return NS_ERROR_ABORT;
}
NS_ENSURE_ARG_POINTER(aReadyState);
nsresult rv = mXHRProxy->GetReadyState(aReadyState);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::OverrideMimeType(const nsACString& aMimetype)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (mCanceled) {
return NS_ERROR_ABORT;
}
nsresult rv = mXHRProxy->OverrideMimeType(aMimetype);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::GetMultipart(PRBool* aMultipart)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (mCanceled) {
return NS_ERROR_ABORT;
}
NS_ENSURE_ARG_POINTER(aMultipart);
nsresult rv = mXHRProxy->GetMultipart(aMultipart);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::SetMultipart(PRBool aMultipart)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (mCanceled) {
return NS_ERROR_ABORT;
}
nsresult rv = mXHRProxy->SetMultipart(aMultipart);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::GetMozBackgroundRequest(PRBool* aMozBackgroundRequest)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (mCanceled) {
return NS_ERROR_ABORT;
}
NS_ENSURE_ARG_POINTER(aMozBackgroundRequest);
*aMozBackgroundRequest = PR_FALSE;
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::SetMozBackgroundRequest(PRBool aMozBackgroundRequest)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (aMozBackgroundRequest) {
return NS_ERROR_NOT_AVAILABLE;
}
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::Init(nsIPrincipal* aPrincipal,
nsIScriptContext* aScriptContext,
nsPIDOMWindow* aOwnerWindow,
nsIURI* aBaseURI)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
NS_NOTREACHED("No one should be calling this!");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsDOMWorkerXHR::GetUpload(nsIXMLHttpRequestUpload** aUpload)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
nsRefPtr<nsDOMWorker> worker = mWorker;
if (!worker) {
return NS_ERROR_ABORT;
}
MutexAutoLock lock(worker->GetLock());
if (mCanceled) {
return NS_ERROR_ABORT;
}
NS_ENSURE_ARG_POINTER(aUpload);
if (!mUpload) {
mUpload = new nsDOMWorkerXHRUpload(this);
NS_ENSURE_TRUE(mUpload, NS_ERROR_OUT_OF_MEMORY);
}
NS_ADDREF(*aUpload = mUpload);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::GetOnreadystatechange(nsIDOMEventListener** aOnreadystatechange)
{
NS_ENSURE_ARG_POINTER(aOnreadystatechange);
nsAutoString type;
type.AssignASCII(sListenerTypes[LISTENER_TYPE_READYSTATECHANGE]);
nsCOMPtr<nsIDOMEventListener> listener = GetOnXListener(type);
listener.forget(aOnreadystatechange);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::SetOnreadystatechange(nsIDOMEventListener* aOnreadystatechange)
{
nsAutoString type;
type.AssignASCII(sListenerTypes[LISTENER_TYPE_READYSTATECHANGE]);
return SetOnXListener(type, aOnreadystatechange);
}
NS_IMETHODIMP
nsDOMWorkerXHR::GetWithCredentials(PRBool* aWithCredentials)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (mCanceled) {
return NS_ERROR_ABORT;
}
NS_ENSURE_ARG_POINTER(aWithCredentials);
nsresult rv = mXHRProxy->GetWithCredentials(aWithCredentials);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::SetWithCredentials(PRBool aWithCredentials)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (mCanceled) {
return NS_ERROR_ABORT;
}
nsresult rv = mXHRProxy->SetWithCredentials(aWithCredentials);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::GetResponseType(nsAString& aResponseText)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsDOMWorkerXHR::SetResponseType(const nsAString& aResponseText)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* readonly attribute jsval response; */
NS_IMETHODIMP
nsDOMWorkerXHR::GetResponse(JSContext *aCx, jsval *aResult)
{
return NS_ERROR_NOT_IMPLEMENTED;
}

Просмотреть файл

@ -1,172 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is worker threads.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef __NSDOMWORKERXHR_H__
#define __NSDOMWORKERXHR_H__
// Bases
#include "nsIClassInfo.h"
#include "nsIXMLHttpRequest.h"
#include "nsIXPCScriptable.h"
// Other includes
#include "nsAutoPtr.h"
#include "nsCOMPtr.h"
#include "nsTArray.h"
// DOMWorker includes
#include "nsDOMWorker.h"
#include "nsDOMWorkerMacros.h"
#include "nsDOMWorkerXHRProxy.h"
// Convenience defines for event *indexes* in the sListenerTypes array.
#define LISTENER_TYPE_ABORT 0
#define LISTENER_TYPE_ERROR 1
#define LISTENER_TYPE_LOAD 2
#define LISTENER_TYPE_LOADSTART 3
#define LISTENER_TYPE_PROGRESS 4
#define LISTENER_TYPE_READYSTATECHANGE 5
#define LISTENER_TYPE_LOADEND 6
class nsIXPConnectWrappedNative;
class nsDOMWorkerXHREventTarget : public nsDOMWorkerMessageHandler,
public nsIXMLHttpRequestEventTarget
{
public:
NS_DECL_ISUPPORTS_INHERITED
NS_FORWARD_NSIDOMEVENTTARGET(nsDOMWorkerMessageHandler::)
NS_DECL_NSIXMLHTTPREQUESTEVENTTARGET
static const char* const sListenerTypes[];
static const PRUint32 sMaxXHREventTypes;
static const PRUint32 sMaxUploadEventTypes;
static PRUint32 GetListenerTypeFromString(const nsAString& aString);
protected:
virtual ~nsDOMWorkerXHREventTarget() { }
};
class nsDOMWorkerXHRUpload;
class nsDOMWorkerXHR : public nsDOMWorkerFeature,
public nsDOMWorkerXHREventTarget,
public nsIXMLHttpRequest,
public nsIXPCScriptable
{
typedef mozilla::Mutex Mutex;
friend class nsDOMWorkerXHREvent;
friend class nsDOMWorkerXHRLastProgressOrLoadEvent;
friend class nsDOMWorkerXHRProxy;
friend class nsDOMWorkerXHRUpload;
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIXMLHTTPREQUEST
NS_FORWARD_NSICLASSINFO_NOGETINTERFACES(nsDOMWorkerXHREventTarget::)
NS_DECL_NSICLASSINFO_GETINTERFACES
NS_DECL_NSIXPCSCRIPTABLE
nsDOMWorkerXHR(nsDOMWorker* aWorker);
nsresult Init();
virtual void Cancel();
virtual nsresult SetOnXListener(const nsAString& aType,
nsIDOMEventListener* aListener);
private:
virtual ~nsDOMWorkerXHR();
Mutex& GetLock() {
return mWorker->GetLock();
}
already_AddRefed<nsIXPConnectWrappedNative> GetWrappedNative() {
nsCOMPtr<nsIXPConnectWrappedNative> wrappedNative(mWrappedNative);
return wrappedNative.forget();
}
nsRefPtr<nsDOMWorkerXHRProxy> mXHRProxy;
nsRefPtr<nsDOMWorkerXHRUpload> mUpload;
nsIXPConnectWrappedNative* mWrappedNative;
volatile PRBool mCanceled;
};
class nsDOMWorkerXHRUpload : public nsDOMWorkerXHREventTarget,
public nsIXMLHttpRequestUpload
{
friend class nsDOMWorkerXHR;
public:
NS_DECL_ISUPPORTS_INHERITED
// nsIDOMEventHandler
NS_FORWARD_INTERNAL_NSIDOMEVENTTARGET(nsDOMWorkerMessageHandler::)
NS_IMETHOD AddEventListener(const nsAString& aType,
nsIDOMEventListener* aListener,
PRBool aUseCapture,
PRBool aWantsUntrusted,
PRUint8 optional_argc);
NS_IMETHOD RemoveEventListener(const nsAString& aType,
nsIDOMEventListener* aListener,
PRBool aUseCapture);
NS_IMETHOD DispatchEvent(nsIDOMEvent* aEvent,
PRBool* _retval);
NS_FORWARD_NSIXMLHTTPREQUESTEVENTTARGET(nsDOMWorkerXHREventTarget::)
NS_DECL_NSIXMLHTTPREQUESTUPLOAD
NS_FORWARD_NSICLASSINFO_NOGETINTERFACES(nsDOMWorkerXHREventTarget::)
NS_DECL_NSICLASSINFO_GETINTERFACES
nsDOMWorkerXHRUpload(nsDOMWorkerXHR* aWorkerXHR);
virtual nsresult SetOnXListener(const nsAString& aType,
nsIDOMEventListener* aListener);
protected:
virtual ~nsDOMWorkerXHRUpload() { }
nsRefPtr<nsDOMWorkerXHR> mWorkerXHR;
};
#endif /* __NSDOMWORKERXHR_H__ */

Просмотреть файл

@ -1,182 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is worker threads.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef __NSDOMWORKERXHRPROXIEDFUNCTIONS_H__
#define __NSDOMWORKERXHRPROXIEDFUNCTIONS_H__
#define MAKE_PROXIED_FUNCTION0(_name) \
class _name : public SyncEventCapturingRunnable \
{ \
public: \
virtual nsresult RunInternal() \
{ \
nsCOMPtr<nsIXMLHttpRequest> xhr = mXHR->GetXMLHttpRequest(); \
if (xhr) { \
return xhr-> _name (); \
} \
return NS_OK; \
} \
}
#define MAKE_PROXIED_FUNCTION1(_name, _arg1) \
class _name : public SyncEventCapturingRunnable \
{ \
public: \
_name (_arg1 aArg1) : mArg1(aArg1) { } \
\
virtual nsresult RunInternal() \
{ \
nsCOMPtr<nsIXMLHttpRequest> xhr = mXHR->GetXMLHttpRequest(); \
if (xhr) { \
return xhr-> _name (mArg1); \
} \
return NS_OK; \
} \
private: \
_arg1 mArg1; \
}
#define MAKE_PROXIED_FUNCTION2(_name, _arg1, _arg2) \
class _name : public SyncEventCapturingRunnable \
{ \
public: \
_name (_arg1 aArg1, _arg2 aArg2) : mArg1(aArg1), mArg2(aArg2) { } \
\
virtual nsresult RunInternal() \
{ \
nsCOMPtr<nsIXMLHttpRequest> xhr = mXHR->GetXMLHttpRequest(); \
if (xhr) { \
return xhr-> _name (mArg1, mArg2); \
} \
return NS_OK; \
} \
private: \
_arg1 mArg1; \
_arg2 mArg2; \
}
namespace nsDOMWorkerProxiedXHRFunctions
{
typedef nsDOMWorkerXHRProxy::SyncEventQueue SyncEventQueue;
class SyncEventCapturingRunnable : public nsRunnable
{
public:
SyncEventCapturingRunnable()
: mXHR(nsnull), mQueue(nsnull) { }
void Init(nsDOMWorkerXHRProxy* aXHR,
SyncEventQueue* aQueue) {
NS_ASSERTION(aXHR, "Null pointer!");
NS_ASSERTION(aQueue, "Null pointer!");
mXHR = aXHR;
mQueue = aQueue;
}
virtual nsresult RunInternal() = 0;
NS_IMETHOD Run() {
NS_ASSERTION(mXHR && mQueue, "Forgot to call Init!");
SyncEventQueue* oldQueue = mXHR->SetSyncEventQueue(mQueue);
nsresult rv = RunInternal();
mXHR->SetSyncEventQueue(oldQueue);
return rv;
}
protected:
nsRefPtr<nsDOMWorkerXHRProxy> mXHR;
SyncEventQueue* mQueue;
};
class Abort : public SyncEventCapturingRunnable
{
public:
virtual nsresult RunInternal() {
return mXHR->Abort();
}
};
class Open : public SyncEventCapturingRunnable
{
public:
Open(const nsACString& aMethod, const nsACString& aUrl,
PRBool aAsync, const nsAString& aUser,
const nsAString& aPassword)
: mMethod(aMethod), mUrl(aUrl), mAsync(aAsync), mUser(aUser),
mPassword(aPassword) { }
virtual nsresult RunInternal() {
return mXHR->Open(mMethod, mUrl, mAsync, mUser, mPassword);
}
private:
nsCString mMethod;
nsCString mUrl;
PRBool mAsync;
nsString mUser;
nsString mPassword;
};
MAKE_PROXIED_FUNCTION1(GetAllResponseHeaders, char**);
MAKE_PROXIED_FUNCTION2(GetResponseHeader, const nsACString&, nsACString&);
MAKE_PROXIED_FUNCTION1(Send, nsIVariant*);
MAKE_PROXIED_FUNCTION1(SendAsBinary, const nsAString&);
MAKE_PROXIED_FUNCTION2(SetRequestHeader, const nsACString&,
const nsACString&);
MAKE_PROXIED_FUNCTION1(OverrideMimeType, const nsACString&);
MAKE_PROXIED_FUNCTION1(SetMultipart, PRBool);
MAKE_PROXIED_FUNCTION1(GetMultipart, PRBool*);
MAKE_PROXIED_FUNCTION1(GetWithCredentials, PRBool*);
MAKE_PROXIED_FUNCTION1(SetWithCredentials, PRBool);
}
#endif /* __NSDOMWORKERXHRPROXIEDFUNCTIONS_H__ */

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,198 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is worker threads.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef __NSDOMWORKERXHRPROXY_H__
#define __NSDOMWORKERXHRPROXY_H__
// Bases
#include "nsThreadUtils.h"
#include "nsIDOMEventListener.h"
#include "nsIRequestObserver.h"
// Other includes
#include "nsIDOMEventTarget.h"
#include "nsAutoPtr.h"
#include "nsCOMPtr.h"
#include "nsStringGlue.h"
#include "nsTArray.h"
class nsIJSXMLHttpRequest;
class nsIThread;
class nsIVariant;
class nsIXMLHttpRequest;
class nsIXMLHttpRequestUpload;
class nsIXPConnectWrappedNative;
class nsDOMWorkerXHR;
class nsDOMWorkerXHREvent;
class nsDOMWorkerXHRFinishSyncXHRRunnable;
class nsDOMWorkerXHRState;
class nsDOMWorkerXHRWrappedListener;
class nsXMLHttpRequest;
class nsDOMWorkerXHRProxy : public nsIRunnable,
public nsIDOMEventListener,
public nsIRequestObserver
{
friend class nsDOMWorkerXHRAttachUploadListenersRunnable;
friend class nsDOMWorkerXHREvent;
friend class nsDOMWorkerXHRFinishSyncXHRRunnable;
friend class nsDOMWorkerXHRLastProgressOrLoadEvent;
friend class nsDOMWorkerXHR;
friend class nsDOMWorkerXHRUpload;
public:
typedef nsAutoTArray<nsCOMPtr<nsIRunnable>, 5> SyncEventQueue;
NS_DECL_ISUPPORTS
NS_DECL_NSIDOMEVENTLISTENER
NS_DECL_NSIRUNNABLE
NS_DECL_NSIREQUESTOBSERVER
nsDOMWorkerXHRProxy(nsDOMWorkerXHR* aWorkerXHR);
virtual ~nsDOMWorkerXHRProxy();
nsresult Init();
nsIXMLHttpRequest* GetXMLHttpRequest();
nsresult Open(const nsACString& aMethod,
const nsACString& aUrl,
PRBool aAsync,
const nsAString& aUser,
const nsAString& aPassword);
nsresult Abort();
SyncEventQueue* SetSyncEventQueue(SyncEventQueue* aQueue);
PRInt32 ChannelID() {
return mChannelID;
}
protected:
struct ProgressInfo {
ProgressInfo() : computable(PR_FALSE), loaded(0), total(0) { }
PRBool computable;
PRUint64 loaded;
PRUint64 total;
};
nsresult InitInternal();
void DestroyInternal();
nsresult Destroy();
void AddRemoveXHRListeners(PRBool aAdd);
void FlipOwnership();
nsresult UploadEventListenerAdded();
nsresult HandleWorkerEvent(nsDOMWorkerXHREvent* aEvent,
PRBool aUploadEvent);
nsresult HandleEventRunnable(nsIRunnable* aRunnable);
// Methods of nsIXMLHttpRequest that we implement
nsresult GetAllResponseHeaders(char** _retval);
nsresult GetResponseHeader(const nsACString& aHeader,
nsACString& _retval);
nsresult Send(nsIVariant* aBody);
nsresult SendAsBinary(const nsAString& aBody);
nsresult GetResponseText(nsAString& _retval);
nsresult GetStatusText(nsACString& _retval);
nsresult GetStatus(nsresult* _retval);
nsresult GetReadyState(PRUint16* _retval);
nsresult SetRequestHeader(const nsACString& aHeader,
const nsACString& aValue);
nsresult OverrideMimeType(const nsACString& aMimetype);
nsresult GetMultipart(PRBool* aMultipart);
nsresult SetMultipart(PRBool aMultipart);
nsresult GetWithCredentials(PRBool* aWithCredentials);
nsresult SetWithCredentials(PRBool aWithCredentials);
nsresult RunSyncEventLoop();
PRBool IsUploadEvent(nsIDOMEvent* aEvent);
nsresult DispatchPrematureAbortEvents(PRUint32 aType,
nsIDOMEventTarget* aTarget,
ProgressInfo* aProgressInfo);
nsresult MaybeDispatchPrematureAbortEvents(PRBool aFromOpenRequest);
// May be weak or strong, check mOwnedByXHR.
nsDOMWorkerXHR* mWorkerXHR;
nsCOMPtr<nsIXPConnectWrappedNative> mWorkerXHRWN;
// May be weak or strong, check mOwnedByXHR.
nsIXMLHttpRequest* mXHR;
// Always weak!
nsXMLHttpRequest* mConcreteXHR;
nsIXMLHttpRequestUpload* mUpload;
nsCOMPtr<nsIThread> mMainThread;
nsRefPtr<nsDOMWorkerXHRState> mLastXHRState;
nsRefPtr<nsDOMWorkerXHREvent> mLastProgressOrLoadEvent;
SyncEventQueue* mSyncEventQueue;
PRInt32 mChannelID;
// Only touched on the worker thread!
nsCOMPtr<nsIThread> mSyncXHRThread;
// Touched on more than one thread, protected by the worker's lock.
nsRefPtr<nsDOMWorkerXHRFinishSyncXHRRunnable> mSyncFinishedRunnable;
nsAutoPtr<ProgressInfo> mDownloadProgressInfo;
nsAutoPtr<ProgressInfo> mUploadProgressInfo;
// Whether or not this object is owned by the real XHR object.
PRPackedBool mOwnedByXHR;
PRPackedBool mWantUploadListeners;
PRPackedBool mCanceled;
PRPackedBool mSyncRequest;
};
#endif /* __NSDOMWORKERXHRPROXY_H__ */

Просмотреть файл

@ -1,76 +0,0 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is DOM Worker Tests.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
onmessage = function(event) {
let chromeURL = event.data.replace("test_chromeWorkerJSM.xul",
"WorkerTest_badworker.js");
let mochitestURL = event.data.replace("test_chromeWorkerJSM.xul",
"WorkerTest_badworker.js")
.replace("chrome://mochitests/content/chrome",
"http://mochi.test:8888/tests");
// We should be able to XHR to anything we want, including a chrome URL.
let xhr = new XMLHttpRequest();
xhr.open("GET", mochitestURL, false);
xhr.send();
if (!xhr.responseText) {
throw "Can't load script file via XHR!";
}
// We shouldn't be able to make a ChromeWorker to a non-chrome URL.
let worker = new ChromeWorker(mochitestURL);
worker.onmessage = function(event) {
throw event.data;
};
worker.onerror = function(event) {
event.preventDefault();
// And we shouldn't be able to make a regular Worker to a non-chrome URL.
worker = new Worker(mochitestURL);
worker.onmessage = function(event) {
throw event.data;
};
worker.onerror = function(event) {
event.preventDefault();
postMessage("Done");
};
worker.postMessage("Hi");
};
worker.postMessage("Hi");
};

Просмотреть файл

@ -1,5 +0,0 @@
onclose = function() {
postMessage("closed");
};
setTimeout(function() { close(); }, 1000);

Просмотреть файл

@ -1,26 +0,0 @@
var worker = new Worker("errorPropagation_worker2.js");
var errorCount = 0;
worker.onerror = function(event) {
switch (errorCount++) {
case 0:
case 1:
// Let it propagate.
break;
case 2:
// Stop and rethrow.
event.preventDefault();
throw event.message;
break;
case 3:
event.preventDefault();
postMessage(event.message);
worker.onerror = null;
break;
default:
}
};
onmessage = function(event) {
worker.postMessage(event.data);
};

Просмотреть файл

@ -1,3 +0,0 @@
onmessage = function(event) {
throw event.data;
};

Просмотреть файл

@ -1,28 +0,0 @@
var results = [];
function messageHandler(event) {
results.push(parseInt(event.data));
if (results.length == 2) {
postMessage(results[0] + results[1]);
}
}
function errorHandler(event) {
throw event.data;
}
onmessage = function(event) {
var n = parseInt(event.data);
if (n == 0 || n == 1) {
postMessage(n);
return;
}
for (var i = 1; i <= 2; i++) {
var worker = new Worker("fibonacci_worker.js");
worker.onmessage = messageHandler;
worker.onerror = errorHandler;
worker.postMessage(n - i);
}
}

Просмотреть файл

@ -1,8 +0,0 @@
function onmessage(event) {
throw event.data;
}
function onerror(event) {
postMessage(event.message);
event.preventDefault();
}

Просмотреть файл

@ -1,2 +0,0 @@
// Deliberate syntax error, should generate a worker exception!
for (var index = 0; index < 100) {}

Просмотреть файл

@ -1,2 +0,0 @@
// Deliberate throw, should generate a worker exception!
throw new Error("Bah!");

Просмотреть файл

@ -1,4 +0,0 @@
for (var string in self.location) {
postMessage({ "string": string, "value": self.location[string] });
}
postMessage({"string": "testfinished", "value": self.location.toString()});

Просмотреть файл

@ -1 +0,0 @@
throw new Error("foo!");

Просмотреть файл

@ -1,34 +0,0 @@
onerror = function(event) {
// Do nothing.
};
// Pure JS recursion
function recurse() {
recurse();
}
// JS -> C++ -> JS -> C++ recursion
function recurse2() {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
xhr.open("GET", "nonexistent.file");
}
xhr.open("GET", "nonexistent.file");
postMessage("Done");
}
var count = 0;
onmessage = function(event) {
switch (++count) {
case 1:
recurse();
break;
case 2:
recurse2();
// Have to return here because we don't propagate exceptions from event
// handlers!
return;
default:
}
throw "Never should have gotten here!";
}

Просмотреть файл

@ -1,26 +0,0 @@
var runCount = 0;
var timeout;
onmessage = function() {
run();
timeout = setTimeout(run, 0);
timeout = setTimeout(run, 5000);
};
function run() {
if (RegExp.$1) {
throw "RegExp.$1 already set!";
cancelTimeout(timeout);
}
var match = /a(sd)f/.exec("asdf");
if (!RegExp.$1) {
throw "RegExp.$1 didn't get set!";
cancelTimeout(timeout);
}
if (++runCount == 3) {
postMessage("done");
}
}

Просмотреть файл

@ -1 +0,0 @@
const workerURL = "relativeLoad_worker.js";

Просмотреть файл

@ -1 +0,0 @@
const workerSubURL = "subdir/relativeLoad_sub_worker.js";

Просмотреть файл

@ -1,5 +0,0 @@
const importSubURL = "relativeLoad_sub_import.js";
importScripts(importSubURL);
postMessage(workerSubURL);

Просмотреть файл

@ -1,5 +0,0 @@
const importURL = "relativeLoad_import.js";
importScripts(importURL);
postMessage(workerURL);

Просмотреть файл

@ -1,26 +0,0 @@
if (onerror !== undefined || typeof(onerror) != "undefined") {
throw "Undefined onerror has bad type!";
}
onerror = function(event) {
if (!event.cancelable) {
throw "Error event is not cancelable!";
}
if (event.target != this) {
throw "Error event is targeted at the wrong object!";
}
if (event.message == "uncaught exception: This error should not make it back out") {
event.preventDefault();
postMessage("Done");
}
}
if (onerror === undefined || typeof(onerror) == "undefined") {
throw "onerror has a bad type!";
}
onmessage = function(event) {
throw event.data;
}

Просмотреть файл

@ -1,5 +0,0 @@
var counter = 0;
setInterval(function() {
postMessage(++counter);
}, 100);

Просмотреть файл

@ -1,97 +0,0 @@
<?xml version="1.0"?>
<!-- ***** BEGIN LICENSE BLOCK *****
- Version: MPL 1.1/GPL 2.0/LGPL 2.1
-
- The contents of this file are subject to the Mozilla Public License Version
- 1.1 (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
- http://www.mozilla.org/MPL/
-
- Software distributed under the License is distributed on an "AS IS" basis,
- WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- for the specific language governing rights and limitations under the
- License.
-
- The Original Code is DOM Worker tests.
-
- The Initial Developer of the Original Code is
- The Mozilla Foundation.
- Portions created by the Initial Developer are Copyright (C) 2010
- the Initial Developer. All Rights Reserved.
-
- Contributor(s):
- Ben Turner <bent.mozilla@gmail.com>
-
- Alternatively, the contents of this file may be used under the terms of
- either the GNU General Public License Version 2 or later (the "GPL"), or
- the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- in which case the provisions of the GPL or the LGPL are applicable instead
- of those above. If you wish to allow use of your version of this file only
- under the terms of either the GPL or the LGPL, and not to allow others to
- use your version of this file under the terms of the MPL, indicate your
- decision by deleting the provisions above and replace them with the notice
- and other provisions required by the LGPL or the GPL. If you do not delete
- the provisions above, a recipient may use your version of this file under
- the terms of any one of the MPL, the GPL or the LGPL.
-
- ***** END LICENSE BLOCK ***** -->
<window title="DOM Worker Threads Test"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
onload="test();">
<script type="application/javascript"
src="chrome://mochikit/content/MochiKit/packed.js"/>
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
<script type="application/javascript">
<![CDATA[
function test()
{
SimpleTest.waitForExplicitFinish();
var worker = new ChromeWorker("chromeWorker_worker.js");
worker.onmessage = function(event) {
is(event.data, "Done!", "Wrong message!");
SimpleTest.finish();
}
worker.onerror = function(event) {
ok(false, "Worker had an error: " + event.message);
worker.terminate();
SimpleTest.finish();
}
// Test passing a non-threadsafe wrapped native to the worker.
var isupports =
Components.classes["@mozilla.org/supports-PRBool;1"]
.createInstance(Components.interfaces.nsISupportsPRBool);
try {
worker.postMessage(isupports);
ok(false, "Passing non-threadsafe thing should throw!");
}
catch (e) {
ok(true, "Passing non-threadsafe thing threw");
}
// Test passing a wrapped native to the worker.
var thread = Components.classes["@mozilla.org/thread-manager;1"]
.getService().newThread(0);
worker.postMessage(thread);
}
]]>
</script>
<body xmlns="http://www.w3.org/1999/xhtml">
<p id="display"></p>
<div id="content" style="display:none;"></div>
<pre id="test"></pre>
</body>
<label id="test-result"/>
</window>

Просмотреть файл

@ -1,88 +0,0 @@
<?xml version="1.0"?>
<!-- ***** BEGIN LICENSE BLOCK *****
- Version: MPL 1.1/GPL 2.0/LGPL 2.1
-
- The contents of this file are subject to the Mozilla Public License Version
- 1.1 (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
- http://www.mozilla.org/MPL/
-
- Software distributed under the License is distributed on an "AS IS" basis,
- WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- for the specific language governing rights and limitations under the
- License.
-
- The Original Code is DOM Worker tests.
-
- The Initial Developer of the Original Code is
- The Mozilla Foundation.
- Portions created by the Initial Developer are Copyright (C) 2010
- the Initial Developer. All Rights Reserved.
-
- Contributor(s):
- Ben Turner <bent.mozilla@gmail.com>
-
- Alternatively, the contents of this file may be used under the terms of
- either the GNU General Public License Version 2 or later (the "GPL"), or
- the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- in which case the provisions of the GPL or the LGPL are applicable instead
- of those above. If you wish to allow use of your version of this file only
- under the terms of either the GPL or the LGPL, and not to allow others to
- use your version of this file under the terms of the MPL, indicate your
- decision by deleting the provisions above and replace them with the notice
- and other provisions required by the LGPL or the GPL. If you do not delete
- the provisions above, a recipient may use your version of this file under
- the terms of any one of the MPL, the GPL or the LGPL.
-
- ***** END LICENSE BLOCK ***** -->
<window title="DOM Worker Threads Test"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
onload="test();">
<script type="application/javascript"
src="chrome://mochikit/content/MochiKit/packed.js"/>
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
<script type="application/javascript">
<![CDATA[
function test()
{
SimpleTest.waitForExplicitFinish();
const Cc = Components.classes;
const Ci = Components.interfaces;
var wf = Cc["@mozilla.org/threads/workerfactory;1"]
.createInstance(Ci.nsIWorkerFactory);
var worker = wf.newChromeWorker("chromeWorker_worker.js");
worker.onmessage = function(event) {
is(event.data, "Done!", "Wrong message!");
SimpleTest.finish();
}
worker.onerror = function(event) {
ok(false, "Worker had an error: " + event.message);
worker.terminate();
SimpleTest.finish();
}
// Test passing a wrapped native to the worker.
var thread = Components.classes["@mozilla.org/thread-manager;1"]
.getService().newThread(0);
worker.postMessage(thread);
}
]]>
</script>
<body xmlns="http://www.w3.org/1999/xhtml">
<p id="display"></p>
<div id="content" style="display:none;"></div>
<pre id="test"></pre>
</body>
<label id="test-result"/>
</window>

Просмотреть файл

@ -1,90 +0,0 @@
<?xml version="1.0"?>
<!-- ***** BEGIN LICENSE BLOCK *****
- Version: MPL 1.1/GPL 2.0/LGPL 2.1
-
- The contents of this file are subject to the Mozilla Public License Version
- 1.1 (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
- http://www.mozilla.org/MPL/
-
- Software distributed under the License is distributed on an "AS IS" basis,
- WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- for the specific language governing rights and limitations under the
- License.
-
- The Original Code is DOM Worker tests.
-
- The Initial Developer of the Original Code is
- The Mozilla Foundation.
- Portions created by the Initial Developer are Copyright (C) 2010
- the Initial Developer. All Rights Reserved.
-
- Contributor(s):
- Ben Turner <bent.mozilla@gmail.com>
-
- Alternatively, the contents of this file may be used under the terms of
- either the GNU General Public License Version 2 or later (the "GPL"), or
- the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- in which case the provisions of the GPL or the LGPL are applicable instead
- of those above. If you wish to allow use of your version of this file only
- under the terms of either the GPL or the LGPL, and not to allow others to
- use your version of this file under the terms of the MPL, indicate your
- decision by deleting the provisions above and replace them with the notice
- and other provisions required by the LGPL or the GPL. If you do not delete
- the provisions above, a recipient may use your version of this file under
- the terms of any one of the MPL, the GPL or the LGPL.
-
- ***** END LICENSE BLOCK ***** -->
<window title="DOM Worker Threads Test"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
onload="test();">
<script type="application/javascript"
src="chrome://mochikit/content/MochiKit/packed.js"/>
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
<script type="application/javascript">
<![CDATA[
function test()
{
SimpleTest.waitForExplicitFinish();
var worker;
function done()
{
worker = null;
SimpleTest.finish();
}
function messageCallback(event) {
is(event.data, "Done", "Correct message");
done();
}
function errorCallback(event) {
ok(false, "Worker had an error: " + event.message);
done();
}
Components.utils.import("chrome://mochitests/content/chrome/dom/src/threads/test/WorkerTest.jsm");
worker = WorkerTest.go(window.location.href, messageCallback,
errorCallback);
}
]]>
</script>
<body xmlns="http://www.w3.org/1999/xhtml">
<p id="display"></p>
<div id="content" style="display:none;"></div>
<pre id="test"></pre>
</body>
<label id="test-result"/>
</window>

Просмотреть файл

@ -1,107 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
Tests of DOM Worker Threads
-->
<head>
<title>Test for DOM Worker Threads</title>
<script type="text/javascript" src="/MochiKit/packed.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<pre id="test">
<script class="testbody" type="text/javascript">
var errors = [
"This exception should show up in the JS console",
"This exception should make it to onerror",
"This exception should too",
"This exception should should show up in onmessage"
];
var errorIndex = -1;
var worker = new Worker("errorPropagation_worker1.js");
worker.onmessage = function(event) {
is(event.target, worker);
isnot(-1, event.data.indexOf(errors[errorIndex]));
ok(errorIndex == errors.length - 1, "Wrong number of errors seen!");
SimpleTest.finish();
}
function nextError() {
worker.postMessage(errors[++errorIndex]);
}
function errorHandler(event) {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
is(event.target, worker);
isnot(-1, event.message.indexOf(errors[errorIndex]));
switch (errorIndex) {
case 1:
consoleService.unregisterListener(consoleListener);
consoleService.reset();
consoleListener = null;
nextError();
break;
case 2:
nextError();
break;
default:
ok(false, "Too many errors!");
}
}
var consoleListener = {
count: 0,
observe: function(message) {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
if (this.count++) {
ok(false, "Seen too many errors!");
SimpleTest.finish();
return;
}
is(message.message,
'[JavaScript Error: "uncaught exception: This exception should show ' +
'up in the JS console"]');
worker.onerror = errorHandler;
nextError();
},
QueryInterface: function(iid) {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
if (iid.equals(Ci.nsIConsoleListener) ||
iid.equals(Ci.nsISupports)) {
return this;
}
throw Cr.NS_NOINTERFACE;
}
};
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cr = Components.results;
var consoleService =
Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService);
consoleService.reset();
consoleService.registerListener(consoleListener);
nextError();
SimpleTest.waitForExplicitFinish();
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -1,47 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
Tests of DOM Worker Threads RegExp statics
-->
<head>
<title>Test for DOM Worker Threads RegExp statics</title>
<script type="text/javascript" src="/MochiKit/packed.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
const WORKER_COUNT = 25;
var doneWorkers = 0;
function onmessage(event) {
if (++doneWorkers == WORKER_COUNT) {
ok(true, "All messages received from workers");
SimpleTest.finish();
}
}
function onerror(event) {
ok(false, "Worker had an error: " + event.data);
SimpleTest.finish();
};
for (var i = 0; i < WORKER_COUNT; i++) {
var worker = new Worker("regExpStatics_worker.js");
worker.onmessage = onmessage;
worker.onerror = onerror;
worker.postMessage("start");
}
SimpleTest.waitForExplicitFinish();
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -1,44 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
Tests of DOM Worker Threads
-->
<head>
<title>Test for DOM Worker Threads</title>
<script type="text/javascript" src="/MochiKit/packed.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<pre id="test">
<script class="testbody" type="text/javascript">
var errors = [
"This exception should make it to onerror",
"This error should not make it back out"
];
var worker = new Worker("scopeOnerror_worker.js");
worker.onmessage = function(event) {
ok(event.data == "Done");
SimpleTest.finish();
}
worker.onerror = function(event) {
is(event.target, worker);
is(event.message, "uncaught exception: " + errors[0]);
event.preventDefault();
};
for (var index in errors) {
worker.postMessage(errors[index]);
}
SimpleTest.waitForExplicitFinish();
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -1,45 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test for DOM Worker Threads</title>
<script type="text/javascript" src="/MochiKit/packed.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<pre id="test">
<script class="testbody" type="text/javascript">
var worker = new Worker("xpcom_worker.js");
worker.onmessage = function(event) {
is(event.data, "Done", "Correct message");
SimpleTest.finish();
};
worker.onerror = function(event) {
ok(false, "Worker had an error: " + event.message);
SimpleTest.finish();
};
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
// Test passing a wrapped native to the worker.
var thread = Components.classes["@mozilla.org/thread-manager;1"]
.getService().newThread(0);
try {
worker.postMessage(thread);
ok(false, "postMessage with a wrapped native should fail!");
}
catch(e) {
ok(true, "postMessage with a wrapped native failed");
}
worker.postMessage("Hi");
SimpleTest.waitForExplicitFinish();
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -1,4 +0,0 @@
// Syntax error
onmessage = function(event) {
for (var i = 0; i < 10) { }
}

Просмотреть файл

@ -1,4 +0,0 @@
// Bad function error
onmessage = function(event) {
foopy();
}

Просмотреть файл

@ -1,5 +0,0 @@
// Unhandled exception in body
onmessage = function(event) {
};
throw new Error("Bah!");

Просмотреть файл

@ -1,4 +0,0 @@
// Throwing message listener
onmessage = function(event) {
throw new Error("Bah!");
};

Просмотреть файл

@ -1,52 +0,0 @@
var events = [];
function runTest() {
var xhr = new XMLHttpRequest();
function pushEvent(event) {
var str = event.type + "(" + xhr.readyState + ", '" + xhr.responseText +
"'";
if (typeof event.loaded != "undefined") {
str += ", progressEvent";
}
str += ")";
events.push(str);
}
xhr.onerror = function(event) {
dump("Error: " + xhr.statusText + "\n");
}
xhr.onload = function(event) {
pushEvent(event);
postMessage(events);
};
xhr.onabort = function(event) {
pushEvent(event);
postMessage(events);
};
var count = 0;
xhr.onreadystatechange = function(event) {
pushEvent(event);
if (++count == 3) {
xhr.abort();
}
};
xhr.open("GET", "testXHR.txt");
xhr.overrideMimeType("text/plain");
xhr.send(null);
}
function messageListener(event) {
switch (event.data) {
case "start":
runTest();
break;
default:
}
}
addEventListener("message", messageListener, false);

Просмотреть файл

@ -1,18 +0,0 @@
var exception;
try {
var xpcom = XPCOM;
}
catch(e) {
exception = e;
}
if (!exception) {
throw "Worker shouldn't be able to access the XPCOM object!";
}
onmessage = function(event) {
if (event.data != "Hi") {
throw "Bad message!";
}
postMessage("Done");
}

Просмотреть файл

@ -0,0 +1,102 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Web Workers.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "ChromeWorkerScope.h"
#include "jsapi.h"
#include "jscntxt.h"
#include "nsXPCOM.h"
#include "nsNativeCharsetUtils.h"
#include "nsStringGlue.h"
USING_WORKERS_NAMESPACE
namespace {
#ifdef BUILD_CTYPES
char*
UnicodeToNative(JSContext* aCx, const jschar* aSource, size_t aSourceLen)
{
nsDependentString unicode(aSource, aSourceLen);
nsCAutoString native;
if (NS_FAILED(NS_CopyUnicodeToNative(unicode, native))) {
JS_ReportError(aCx, "Could not convert string to native charset!");
return nsnull;
}
char* result = static_cast<char*>(JS_malloc(aCx, native.Length() + 1));
if (!result) {
return nsnull;
}
memcpy(result, native.get(), native.Length());
result[native.Length()] = 0;
return result;
}
JSCTypesCallbacks gCTypesCallbacks = {
UnicodeToNative
};
#endif
} // anonymous namespace
BEGIN_WORKERS_NAMESPACE
namespace chromeworker {
bool
DefineChromeWorkerFunctions(JSContext* aCx, JSObject* aGlobal)
{
#ifdef BUILD_CTYPES
jsval ctypes;
if (!JS_InitCTypesClass(aCx, aGlobal) ||
!JS_GetProperty(aCx, aGlobal, "ctypes", &ctypes) ||
!JS_SetCTypesCallbacks(aCx, JSVAL_TO_OBJECT(ctypes), &gCTypesCallbacks)) {
return false;
}
#endif
return true;
}
} // namespace chromeworker
END_WORKERS_NAMESPACE

Просмотреть файл

@ -0,0 +1,57 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Web Workers.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef mozilla_dom_workers_chromeworkerscope_h__
#define mozilla_dom_workers_chromeworkerscope_h__
#include "Workers.h"
#include "jspubtd.h"
BEGIN_WORKERS_NAMESPACE
namespace chromeworker {
bool
DefineChromeWorkerFunctions(JSContext* aCx, JSObject* aGlobal);
} // namespace chromeworker
END_WORKERS_NAMESPACE
#endif // mozilla_dom_workers_chromeworkerscope_h__

248
dom/workers/EventTarget.cpp Normal file
Просмотреть файл

@ -0,0 +1,248 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Web Workers.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "EventTarget.h"
#include "jsapi.h"
#include "jscntxt.h"
#include "nsTraceRefcnt.h"
#include "WorkerInlines.h"
USING_WORKERS_NAMESPACE
using mozilla::dom::workers::events::EventTarget;
namespace {
#define DECL_EVENTTARGET_CLASS(_varname, _name) \
JSClass _varname = { \
_name, 0, \
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, \
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub, \
JSCLASS_NO_OPTIONAL_MEMBERS \
};
DECL_EVENTTARGET_CLASS(gClass, "EventTarget")
DECL_EVENTTARGET_CLASS(gMainThreadClass, "WorkerEventTarget")
#undef DECL_EVENTTARGET_CLASS
inline
EventTarget*
GetPrivate(JSContext* aCx, JSObject* aObj)
{
return GetJSPrivateSafeish<EventTarget>(aCx, aObj);
}
JSBool
Construct(JSContext* aCx, uintN aArgc, jsval* aVp)
{
JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL, JSMSG_WRONG_CONSTRUCTOR,
gClass.name);
return false;
}
JSFunctionSpec gFunctions[] = {
JS_FN("addEventListener", EventTarget::AddEventListener, 3, JSPROP_ENUMERATE),
JS_FN("removeEventListener", EventTarget::RemoveEventListener, 3,
JSPROP_ENUMERATE),
JS_FN("dispatchEvent", EventTarget::DispatchEvent, 1, JSPROP_ENUMERATE),
JS_FS_END
};
} // anonymous namespace
EventTarget::EventTarget()
{
MOZ_COUNT_CTOR(mozilla::dom::workers::events::EventTarget);
}
EventTarget::~EventTarget()
{
MOZ_COUNT_DTOR(mozilla::dom::workers::events::EventTarget);
}
bool
EventTarget::GetEventListenerOnEventTarget(JSContext* aCx, const char* aType,
jsval* aVp)
{
JSString* type = JS_InternString(aCx, aType);
if (!type) {
return false;
}
return mListenerManager.GetEventListener(aCx, type, aVp);
}
bool
EventTarget::SetEventListenerOnEventTarget(JSContext* aCx, const char* aType,
jsval* aVp)
{
JSString* type = JS_InternString(aCx, aType);
if (!type) {
return false;
}
JSObject* listenerObj;
if (!JS_ValueToObject(aCx, *aVp, &listenerObj)) {
return false;
}
return mListenerManager.SetEventListener(aCx, type, *aVp);
}
// static
EventTarget*
EventTarget::FromJSObject(JSContext* aCx, JSObject* aObj)
{
return GetPrivate(aCx, aObj);
}
// static
JSBool
EventTarget::AddEventListener(JSContext* aCx, uintN aArgc, jsval* aVp)
{
JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
EventTarget* self = GetPrivate(aCx, obj);
JS_ASSERT(self);
JSString* type;
JSObject* listener;
JSBool capturing = false, wantsUntrusted = false;
if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "So/bb", &type,
&listener, &capturing, &wantsUntrusted)) {
return false;
}
if (!listener) {
return true;
}
return self->mListenerManager.AddEventListener(aCx, type,
JS_ARGV(aCx, aVp)[1],
capturing, wantsUntrusted);
}
// static
JSBool
EventTarget::RemoveEventListener(JSContext* aCx, uintN aArgc, jsval* aVp)
{
JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
EventTarget* self = GetPrivate(aCx, obj);
JS_ASSERT(self);
JSString* type;
JSObject* listener;
JSBool capturing = false;
if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "So/b", &type,
&listener, &capturing)) {
return false;
}
if (!listener) {
return true;
}
return self->mListenerManager.RemoveEventListener(aCx, type,
JS_ARGV(aCx, aVp)[1],
capturing);
}
// static
JSBool
EventTarget::DispatchEvent(JSContext* aCx, uintN aArgc, jsval* aVp)
{
JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
EventTarget* self = GetPrivate(aCx, obj);
JS_ASSERT(self);
JSObject* event;
if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "o", &event)) {
return false;
}
bool preventDefaultCalled;
if (!self->mListenerManager.DispatchEvent(aCx, obj, event,
&preventDefaultCalled)) {
return false;
}
JS_SET_RVAL(aCx, aVp, BOOLEAN_TO_JSVAL(preventDefaultCalled));
return true;
}
BEGIN_WORKERS_NAMESPACE
namespace events {
JSObject*
InitEventTargetClass(JSContext* aCx, JSObject* aObj, bool aMainRuntime)
{
if (aMainRuntime) {
// XXX Hack to prevent instanceof checks failing on the main thread.
jsval windowEventTarget;
if (!JS_GetProperty(aCx, aObj, gClass.name, &windowEventTarget)) {
return NULL;
}
if (!JSVAL_IS_PRIMITIVE(windowEventTarget)) {
jsval protoVal;
if (!JS_GetProperty(aCx, JSVAL_TO_OBJECT(windowEventTarget), "prototype",
&protoVal)) {
return NULL;
}
if (!JSVAL_IS_PRIMITIVE(protoVal)) {
return JS_InitClass(aCx, aObj, JSVAL_TO_OBJECT(protoVal),
&gMainThreadClass, Construct, 0, NULL, gFunctions,
NULL, NULL);
}
}
}
return JS_InitClass(aCx, aObj, NULL, &gClass, Construct, 0, NULL,
gFunctions, NULL, NULL);
}
} // namespace events
END_WORKERS_NAMESPACE

109
dom/workers/EventTarget.h Normal file
Просмотреть файл

@ -0,0 +1,109 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Web Workers.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef mozilla_dom_workers_eventtarget_h__
#define mozilla_dom_workers_eventtarget_h__
#include "jspubtd.h"
#include "ListenerManager.h"
BEGIN_WORKERS_NAMESPACE
namespace events {
class EventTarget : public PrivatizableBase
{
ListenerManager mListenerManager;
protected:
EventTarget();
~EventTarget();
void
TraceInstance(JSTracer* aTrc)
{
mListenerManager.Trace(aTrc);
}
void
FinalizeInstance(JSContext* aCx)
{
mListenerManager.Finalize(aCx);
}
bool
GetEventListenerOnEventTarget(JSContext* aCx, const char* aType, jsval* aVp);
bool
SetEventListenerOnEventTarget(JSContext* aCx, const char* aType, jsval* aVp);
public:
static EventTarget*
FromJSObject(JSContext* aCx, JSObject* aObj);
static JSBool
AddEventListener(JSContext* aCx, uintN aArgc, jsval* aVp);
static JSBool
RemoveEventListener(JSContext* aCx, uintN aArgc, jsval* aVp);
static JSBool
DispatchEvent(JSContext* aCx, uintN aArgc, jsval* aVp);
bool
HasListeners()
{
return mListenerManager.HasListeners();
}
bool
HasListenersForType(JSContext* aCx, JSString* aType)
{
return mListenerManager.HasListenersForType(aCx, aType);
}
};
JSObject*
InitEventTargetClass(JSContext* aCx, JSObject* aGlobal, bool aMainRuntime);
} // namespace events
END_WORKERS_NAMESPACE
#endif /* mozilla_dom_workers_eventtarget_h__ */

1124
dom/workers/Events.cpp Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

88
dom/workers/Events.h Normal file
Просмотреть файл

@ -0,0 +1,88 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Web Workers.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef mozilla_dom_workers_events_h__
#define mozilla_dom_workers_events_h__
#include "Workers.h"
#include "jspubtd.h"
class JSAutoStructuredCloneBuffer;
BEGIN_WORKERS_NAMESPACE
namespace events {
bool
InitClasses(JSContext* aCx, JSObject* aGlobal, bool aMainRuntime);
JSObject*
CreateGenericEvent(JSContext* aCx, JSString* aType, bool aBubbles,
bool aCancelable, bool aMainRuntime);
JSObject*
CreateMessageEvent(JSContext* aCx, JSAutoStructuredCloneBuffer& aData,
bool aMainRuntime);
JSObject*
CreateErrorEvent(JSContext* aCx, JSString* aMessage, JSString* aFilename,
uint32 aLineNumber, bool aMainRuntime);
JSObject*
CreateProgressEvent(JSContext* aCx, JSString* aType, bool aLengthComputable,
jsdouble aLoaded, jsdouble aTotal);
bool
IsSupportedEventClass(JSContext* aCx, JSObject* aEvent);
bool
SetEventTarget(JSContext* aCx, JSObject* aEvent, JSObject* aTarget);
bool
EventWasCanceled(JSContext* aCx, JSObject* aEvent);
bool
DispatchEventToTarget(JSContext* aCx, JSObject* aTarget, JSObject* aEvent,
bool* aPreventDefaultCalled);
} // namespace events
END_WORKERS_NAMESPACE
#endif /* mozilla_dom_workers_events_h__ */

303
dom/workers/Exceptions.cpp Normal file
Просмотреть файл

@ -0,0 +1,303 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Web Workers.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "Exceptions.h"
#include "jsapi.h"
#include "jscntxt.h"
#include "jsobj.h"
#include "jsprf.h"
#include "nsTraceRefcnt.h"
#include "WorkerInlines.h"
#define PROPERTY_FLAGS \
JSPROP_ENUMERATE | JSPROP_SHARED
#define CONSTANT_FLAGS \
JSPROP_ENUMERATE | JSPROP_SHARED | JSPROP_PERMANENT | JSPROP_READONLY
USING_WORKERS_NAMESPACE
namespace {
class DOMException : public PrivatizableBase
{
static JSClass sClass;
static JSPropertySpec sProperties[];
static JSFunctionSpec sFunctions[];
static JSPropertySpec sStaticProperties[];
enum SLOT {
SLOT_code = 0,
SLOT_name,
SLOT_COUNT
};
public:
static JSObject*
InitClass(JSContext* aCx, JSObject* aObj)
{
JSObject* proto = JS_InitClass(aCx, aObj, NULL, &sClass, Construct, 0,
sProperties, sFunctions, sStaticProperties,
NULL);
if (proto && !JS_DefineProperties(aCx, proto, sStaticProperties)) {
return NULL;
}
return proto;
}
static JSObject*
Create(JSContext* aCx, intN aCode);
private:
DOMException()
{
MOZ_COUNT_CTOR(mozilla::dom::workers::exceptions::DOMException);
}
~DOMException()
{
MOZ_COUNT_DTOR(mozilla::dom::workers::exceptions::DOMException);
}
static JSBool
Construct(JSContext* aCx, uintN aArgc, jsval* aVp)
{
JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL, JSMSG_WRONG_CONSTRUCTOR,
sClass.name);
return false;
}
static void
Finalize(JSContext* aCx, JSObject* aObj)
{
JS_ASSERT(JS_GET_CLASS(aCx, aObj) == &sClass);
delete GetJSPrivateSafeish<DOMException>(aCx, aObj);
}
static JSBool
ToString(JSContext* aCx, uintN aArgc, jsval* aVp)
{
JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
JSClass* classPtr;
if (!obj || ((classPtr = JS_GET_CLASS(aCx, obj)) != &sClass)) {
JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL,
JSMSG_INCOMPATIBLE_PROTO, sClass.name, "toString",
classPtr ? classPtr->name : "object");
return false;
}
char buf[100];
JS_snprintf(buf, sizeof(buf), "%s: ", sClass.name);
JSString* classString = JS_NewStringCopyZ(aCx, buf);
if (!classString) {
return false;
}
jsval name;
if (!JS_GetReservedSlot(aCx, obj, SLOT_name, &name)) {
return false;
}
JS_ASSERT(JSVAL_IS_STRING(name));
JSString* out = JS_ConcatStrings(aCx, classString, JSVAL_TO_STRING(name));
if (!out) {
return false;
}
JS_SET_RVAL(aCx, aVp, STRING_TO_JSVAL(out));
return true;
}
static JSBool
GetProperty(JSContext* aCx, JSObject* aObj, jsid aIdval, jsval* aVp)
{
JS_ASSERT(JSID_IS_INT(aIdval));
int32 slot = JSID_TO_INT(aIdval);
JSClass* classPtr = JS_GET_CLASS(aCx, aObj);
if (classPtr != &sClass ||
!GetJSPrivateSafeish<DOMException>(aCx, aObj)) {
JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL,
JSMSG_INCOMPATIBLE_PROTO, sClass.name,
sProperties[slot].name,
classPtr ? classPtr->name : "object");
return false;
}
return JS_GetReservedSlot(aCx, aObj, slot, aVp);
}
static JSBool
GetConstant(JSContext* aCx, JSObject* aObj, jsid idval, jsval* aVp)
{
JS_ASSERT(JSID_IS_INT(idval));
*aVp = INT_TO_JSVAL(JSID_TO_INT(idval));
return true;
}
};
JSClass DOMException::sClass = {
"DOMException",
JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(SLOT_COUNT),
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Finalize,
JSCLASS_NO_OPTIONAL_MEMBERS
};
JSPropertySpec DOMException::sProperties[] = {
{ "code", SLOT_code, PROPERTY_FLAGS, GetProperty, js_GetterOnlyPropertyStub },
{ "name", SLOT_name, PROPERTY_FLAGS, GetProperty, js_GetterOnlyPropertyStub },
{ 0, 0, 0, NULL, NULL }
};
JSFunctionSpec DOMException::sFunctions[] = {
JS_FN("toString", ToString, 0, 0),
JS_FS_END
};
JSPropertySpec DOMException::sStaticProperties[] = {
#define EXCEPTION_ENTRY(_name) \
{ #_name, _name, CONSTANT_FLAGS, GetConstant, NULL },
EXCEPTION_ENTRY(INDEX_SIZE_ERR)
EXCEPTION_ENTRY(DOMSTRING_SIZE_ERR)
EXCEPTION_ENTRY(HIERARCHY_REQUEST_ERR)
EXCEPTION_ENTRY(WRONG_DOCUMENT_ERR)
EXCEPTION_ENTRY(INVALID_CHARACTER_ERR)
EXCEPTION_ENTRY(NO_DATA_ALLOWED_ERR)
EXCEPTION_ENTRY(NO_MODIFICATION_ALLOWED_ERR)
EXCEPTION_ENTRY(NOT_FOUND_ERR)
EXCEPTION_ENTRY(NOT_SUPPORTED_ERR)
EXCEPTION_ENTRY(INUSE_ATTRIBUTE_ERR)
EXCEPTION_ENTRY(INVALID_STATE_ERR)
EXCEPTION_ENTRY(SYNTAX_ERR)
EXCEPTION_ENTRY(INVALID_MODIFICATION_ERR)
EXCEPTION_ENTRY(NAMESPACE_ERR)
EXCEPTION_ENTRY(INVALID_ACCESS_ERR)
EXCEPTION_ENTRY(VALIDATION_ERR)
EXCEPTION_ENTRY(TYPE_MISMATCH_ERR)
EXCEPTION_ENTRY(SECURITY_ERR)
EXCEPTION_ENTRY(NETWORK_ERR)
EXCEPTION_ENTRY(ABORT_ERR)
EXCEPTION_ENTRY(URL_MISMATCH_ERR)
EXCEPTION_ENTRY(QUOTA_EXCEEDED_ERR)
EXCEPTION_ENTRY(TIMEOUT_ERR)
EXCEPTION_ENTRY(INVALID_NODE_TYPE_ERR)
EXCEPTION_ENTRY(DATA_CLONE_ERR)
#undef EXCEPTION_ENTRY
{ 0, 0, 0, NULL, NULL }
};
// static
JSObject*
DOMException::Create(JSContext* aCx, intN aCode)
{
JSObject* obj = JS_NewObject(aCx, &sClass, NULL, NULL);
if (!obj) {
return NULL;
}
size_t foundIndex = size_t(-1);
for (size_t index = 0;
index < JS_ARRAY_LENGTH(sStaticProperties) - 1;
index++) {
if (sStaticProperties[index].tinyid == aCode) {
foundIndex = index;
break;
}
}
JS_ASSERT(foundIndex != size_t(-1));
JSString* name = JS_NewStringCopyZ(aCx, sStaticProperties[foundIndex].name);
if (!name) {
return NULL;
}
if (!JS_SetReservedSlot(aCx, obj, SLOT_code, INT_TO_JSVAL(aCode)) ||
!JS_SetReservedSlot(aCx, obj, SLOT_name, STRING_TO_JSVAL(name))) {
return NULL;
}
DOMException* priv = new DOMException();
if (!SetJSPrivateSafeish(aCx, obj, priv)) {
delete priv;
return NULL;
}
return obj;
}
} // anonymous namespace
BEGIN_WORKERS_NAMESPACE
namespace exceptions {
bool
InitClasses(JSContext* aCx, JSObject* aGlobal)
{
return !!DOMException::InitClass(aCx, aGlobal);
}
void
ThrowDOMExceptionForCode(JSContext* aCx, intN aCode)
{
JSObject* exception = DOMException::Create(aCx, aCode);
JS_ASSERT(exception);
JS_SetPendingException(aCx, OBJECT_TO_JSVAL(exception));
}
} // namespace exceptions
END_WORKERS_NAMESPACE

Просмотреть файл

@ -1,3 +1,4 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
@ -11,15 +12,15 @@
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is DOM Worker Tests.
* The Original Code is Web Workers.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2010
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com>
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -35,34 +36,51 @@
*
* ***** END LICENSE BLOCK ***** */
// Test XPCOM.getService()
let threadMan = XPCOM.getService("@mozilla.org/thread-manager;1");
let mainThread = threadMan.mainThread;
if (mainThread.isOnCurrentThread()) {
throw "Thread manager is lying to us!";
}
#ifndef mozilla_dom_workers_exceptions_h__
#define mozilla_dom_workers_exceptions_h__
// Test XPCOM.createInstance
let threadPool = XPCOM.createInstance("@mozilla.org/thread-pool;1");
threadPool.shutdown();
#include "Workers.h"
let notThreadsafe;
try {
notThreadsafe = XPCOM.createInstance("@mozilla.org/supports-PRBool;1");
}
catch(e) { }
#include "jspubtd.h"
if (notThreadsafe) {
throw "Shouldn't be able to create non-threadsafe component!";
}
#define INDEX_SIZE_ERR 1
#define DOMSTRING_SIZE_ERR 2
#define HIERARCHY_REQUEST_ERR 3
#define WRONG_DOCUMENT_ERR 4
#define INVALID_CHARACTER_ERR 5
#define NO_DATA_ALLOWED_ERR 6
#define NO_MODIFICATION_ALLOWED_ERR 7
#define NOT_FOUND_ERR 8
#define NOT_SUPPORTED_ERR 9
#define INUSE_ATTRIBUTE_ERR 10
#define INVALID_STATE_ERR 11
#define SYNTAX_ERR 12
#define INVALID_MODIFICATION_ERR 13
#define NAMESPACE_ERR 14
#define INVALID_ACCESS_ERR 15
#define VALIDATION_ERR 16
#define TYPE_MISMATCH_ERR 17
#define SECURITY_ERR 18
#define NETWORK_ERR 19
#define ABORT_ERR 20
#define URL_MISMATCH_ERR 21
#define QUOTA_EXCEEDED_ERR 22
#define TIMEOUT_ERR 23
#define INVALID_NODE_TYPE_ERR 24
#define DATA_CLONE_ERR 25
function onmessage(event) {
// Test passing wrapped natives from the main thread.
event.data.shutdown();
BEGIN_WORKERS_NAMESPACE
let worker = new ChromeWorker("chromeWorker_subworker.js");
worker.onmessage = function(event) {
postMessage(event.data);
}
worker.postMessage("Go");
}
namespace exceptions {
bool
InitClasses(JSContext* aCx, JSObject* aGlobal);
void
ThrowDOMExceptionForCode(JSContext* aCx, intN aCode);
} // namespace exceptions
END_WORKERS_NAMESPACE
#endif // mozilla_dom_workers_exceptions_h__

Просмотреть файл

@ -0,0 +1,458 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Web Workers.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "ListenerManager.h"
#include "jsapi.h"
#include "jscntxt.h"
#include "jsvector.h"
#include "Events.h"
using mozilla::dom::workers::events::ListenerManager;
namespace {
struct Listener;
struct ListenerCollection : PRCList
{
static ListenerCollection*
Add(JSContext* aCx, ListenerCollection* aCollectionHead, jsid aTypeId)
{
ListenerCollection* collection =
static_cast<ListenerCollection*>(JS_malloc(aCx,
sizeof(ListenerCollection)));
if (!collection) {
return NULL;
}
PR_APPEND_LINK(collection, aCollectionHead);
collection->mTypeId = aTypeId;
PR_INIT_CLIST(&collection->mListenerHead);
return collection;
}
static void
Remove(JSContext* aCx, ListenerCollection* aCollection)
{
PR_REMOVE_LINK(aCollection);
JS_free(aCx, aCollection);
}
jsid mTypeId;
PRCList mListenerHead;
};
struct Listener : PRCList
{
static Listener*
Add(JSContext* aCx, Listener* aListenerHead, jsval aListenerVal,
ListenerManager::Phase aPhase, bool aWantsUntrusted)
{
Listener* listener =
static_cast<Listener*>(JS_malloc(aCx, sizeof(Listener)));
if (!listener) {
return NULL;
}
PR_APPEND_LINK(listener, aListenerHead);
listener->mListenerVal = aListenerVal;
listener->mPhase = aPhase;
listener->mWantsUntrusted = aWantsUntrusted;
return listener;
}
static void
Remove(JSContext* aCx, Listener* aListener)
{
PR_REMOVE_LINK(aListener);
JS_free(aCx, aListener);
}
jsval mListenerVal;
ListenerManager::Phase mPhase;
bool mWantsUntrusted;
};
void
DestroyList(JSContext* aCx, PRCList* aListHead)
{
for (PRCList* elem = PR_NEXT_LINK(aListHead); elem != aListHead; ) {
PRCList* nextElem = PR_NEXT_LINK(elem);
JS_free(aCx, elem);
elem = nextElem;
}
}
ListenerCollection*
GetCollectionForType(PRCList* aHead, jsid aTypeId)
{
for (PRCList* elem = PR_NEXT_LINK(aHead);
elem != aHead;
elem = PR_NEXT_LINK(elem)) {
ListenerCollection* collection = static_cast<ListenerCollection*>(elem);
if (collection->mTypeId == aTypeId) {
return collection;
}
}
return NULL;
}
} // anonymous namespace
#ifdef DEBUG
ListenerManager::~ListenerManager()
{
JS_ASSERT(PR_CLIST_IS_EMPTY(&mCollectionHead));
}
#endif
void
ListenerManager::TraceInternal(JSTracer* aTrc)
{
JS_ASSERT(!PR_CLIST_IS_EMPTY(&mCollectionHead));
for (PRCList* collectionElem = PR_NEXT_LINK(&mCollectionHead);
collectionElem != &mCollectionHead;
collectionElem = PR_NEXT_LINK(collectionElem)) {
ListenerCollection* collection =
static_cast<ListenerCollection*>(collectionElem);
for (PRCList* listenerElem = PR_NEXT_LINK(&collection->mListenerHead);
listenerElem != &collection->mListenerHead;
listenerElem = PR_NEXT_LINK(listenerElem)) {
JS_CALL_VALUE_TRACER(aTrc,
static_cast<Listener*>(listenerElem)->mListenerVal,
"EventListenerManager listener value");
}
}
}
void
ListenerManager::FinalizeInternal(JSContext* aCx)
{
JS_ASSERT(!PR_CLIST_IS_EMPTY(&mCollectionHead));
for (PRCList* elem = PR_NEXT_LINK(&mCollectionHead);
elem != &mCollectionHead;
elem = PR_NEXT_LINK(elem)) {
DestroyList(aCx, &static_cast<ListenerCollection*>(elem)->mListenerHead);
}
DestroyList(aCx, &mCollectionHead);
#ifdef DEBUG
PR_INIT_CLIST(&mCollectionHead);
#endif
}
bool
ListenerManager::Add(JSContext* aCx, JSString* aType, jsval aListenerVal,
Phase aPhase, bool aWantsUntrusted)
{
aType = JS_InternJSString(aCx, aType);
if (!aType) {
return false;
}
if (JSVAL_IS_PRIMITIVE(aListenerVal)) {
JS_ReportError(aCx, "Bad listener!");
return false;
}
jsid typeId = INTERNED_STRING_TO_JSID(aCx, aType);
ListenerCollection* collection =
GetCollectionForType(&mCollectionHead, typeId);
if (!collection) {
ListenerCollection* head =
static_cast<ListenerCollection*>(&mCollectionHead);
collection = ListenerCollection::Add(aCx, head, typeId);
if (!collection) {
return false;
}
}
for (PRCList* elem = PR_NEXT_LINK(&collection->mListenerHead);
elem != &collection->mListenerHead;
elem = PR_NEXT_LINK(elem)) {
Listener* listener = static_cast<Listener*>(elem);
if (listener->mListenerVal == aListenerVal && listener->mPhase == aPhase) {
return true;
}
}
Listener* listener =
Listener::Add(aCx, static_cast<Listener*>(&collection->mListenerHead),
aListenerVal, aPhase, aWantsUntrusted);
if (!listener) {
return false;
}
return true;
}
bool
ListenerManager::Remove(JSContext* aCx, JSString* aType, jsval aListenerVal,
Phase aPhase, bool aClearEmpty)
{
aType = JS_InternJSString(aCx, aType);
if (!aType) {
return false;
}
ListenerCollection* collection =
GetCollectionForType(&mCollectionHead, INTERNED_STRING_TO_JSID(aCx, aType));
if (!collection) {
return true;
}
for (PRCList* elem = PR_NEXT_LINK(&collection->mListenerHead);
elem != &collection->mListenerHead;
elem = PR_NEXT_LINK(elem)) {
Listener* listener = static_cast<Listener*>(elem);
if (listener->mListenerVal == aListenerVal && listener->mPhase == aPhase) {
Listener::Remove(aCx, listener);
if (aClearEmpty && PR_CLIST_IS_EMPTY(&collection->mListenerHead)) {
ListenerCollection::Remove(aCx, collection);
}
break;
}
}
return true;
}
bool
ListenerManager::SetEventListener(JSContext* aCx, JSString* aType,
jsval aListener)
{
jsval existing;
if (!GetEventListener(aCx, aType, &existing)) {
return false;
}
if (!JSVAL_IS_VOID(existing) &&
!Remove(aCx, aType, existing, Onfoo, false)) {
return false;
}
return JSVAL_IS_VOID(aListener) || JSVAL_IS_NULL(aListener) ?
true :
Add(aCx, aType, aListener, Onfoo, false);
}
bool
ListenerManager::GetEventListener(JSContext* aCx, JSString* aType,
jsval* aListenerVal)
{
if (PR_CLIST_IS_EMPTY(&mCollectionHead)) {
*aListenerVal = JSVAL_VOID;
return true;
}
aType = JS_InternJSString(aCx, aType);
if (!aType) {
return false;
}
jsid typeId = INTERNED_STRING_TO_JSID(aCx, aType);
ListenerCollection* collection =
GetCollectionForType(&mCollectionHead, typeId);
if (collection) {
for (PRCList* elem = PR_PREV_LINK(&collection->mListenerHead);
elem != &collection->mListenerHead;
elem = PR_NEXT_LINK(elem)) {
Listener* listener = static_cast<Listener*>(elem);
if (listener->mPhase == Onfoo) {
*aListenerVal = listener->mListenerVal;
return true;
}
}
}
*aListenerVal = JSVAL_VOID;
return true;
}
bool
ListenerManager::DispatchEvent(JSContext* aCx, JSObject* aTarget,
JSObject* aEvent, bool* aPreventDefaultCalled)
{
if (!events::IsSupportedEventClass(aCx, aEvent)) {
JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL,
JSMSG_INCOMPATIBLE_METHOD,
"EventTarget", "dispatchEvent", "Event object");
return false;
}
jsval val;
if (!JS_GetProperty(aCx, aEvent, "target", &val)) {
return false;
}
if (!JSVAL_IS_NULL(val)) {
// Already has a target, must be recursively dispatched. Throw.
JS_ReportError(aCx, "Cannot recursively dispatch the same event!");
return false;
}
if (PR_CLIST_IS_EMPTY(&mCollectionHead)) {
*aPreventDefaultCalled = false;
return true;
}
JSString* eventType;
JSBool eventIsTrusted;
if (!JS_GetProperty(aCx, aEvent, "type", &val) ||
!(eventType = JS_ValueToString(aCx, val)) ||
!(eventType = JS_InternJSString(aCx, eventType))) {
return false;
}
// We have already ensure that the event is one of our types of events so
// there is no need to worry about this property being faked.
if (!JS_GetProperty(aCx, aEvent, "isTrusted", &val) ||
!JS_ValueToBoolean(aCx, val, &eventIsTrusted)) {
return false;
}
ListenerCollection* collection =
GetCollectionForType(&mCollectionHead,
INTERNED_STRING_TO_JSID(aCx, eventType));
if (!collection) {
*aPreventDefaultCalled = false;
return true;
}
js::ContextAllocPolicy ap(aCx);
js::Vector<jsval, 10, js::ContextAllocPolicy> listeners(ap);
for (PRCList* elem = PR_NEXT_LINK(&collection->mListenerHead);
elem != &collection->mListenerHead;
elem = PR_NEXT_LINK(elem)) {
Listener* listener = static_cast<Listener*>(elem);
// Listeners that don't want untrusted events will be skipped if this is an
// untrusted event.
if ((eventIsTrusted || listener->mWantsUntrusted) &&
!listeners.append(listener->mListenerVal)) {
return false;
}
}
if (listeners.empty()) {
return true;
}
if (!events::SetEventTarget(aCx, aEvent, aTarget)) {
return false;
}
for (size_t index = 0; index < listeners.length(); index++) {
// If anything fails in here we want to report the exception and continue on
// to the next listener rather than bailing out. If something fails and
// does not set an exception then we bail out entirely as we've either run
// out of memory or the operation callback has indicated that we should
// stop running.
jsval listenerVal = listeners[index];
JSObject* listenerObj;
if (!JS_ValueToObject(aCx, listenerVal, &listenerObj)) {
if (!JS_ReportPendingException(aCx)) {
return false;
}
continue;
}
static const char sHandleEventChars[] = "handleEvent";
JSBool hasHandleEvent;
if (!JS_HasProperty(aCx, listenerObj, sHandleEventChars, &hasHandleEvent)) {
if (!JS_ReportPendingException(aCx)) {
return false;
}
continue;
}
if (hasHandleEvent) {
if (!JS_GetProperty(aCx, listenerObj, sHandleEventChars, &listenerVal)) {
if (!JS_ReportPendingException(aCx)) {
return false;
}
continue;
}
}
jsval argv[] = { OBJECT_TO_JSVAL(aEvent) };
jsval rval = JSVAL_VOID;
if (!JS_CallFunctionValue(aCx, aTarget, listenerVal, JS_ARRAY_LENGTH(argv),
argv, &rval)) {
if (!JS_ReportPendingException(aCx)) {
return false;
}
continue;
}
}
if (!events::SetEventTarget(aCx, aEvent, NULL)) {
return false;
}
*aPreventDefaultCalled = events::EventWasCanceled(aCx, aEvent);
return true;
}
bool
ListenerManager::HasListenersForTypeInternal(JSContext* aCx, JSString* aType)
{
JS_ASSERT(!PR_CLIST_IS_EMPTY(&mCollectionHead));
aType = JS_InternJSString(aCx, aType);
if (!aType) {
return false;
}
jsid typeId = INTERNED_STRING_TO_JSID(aCx, aType);
return !!GetCollectionForType(&mCollectionHead, typeId);
}

Просмотреть файл

@ -0,0 +1,157 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Web Workers.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef mozilla_dom_workers_listenermanager_h__
#define mozilla_dom_workers_listenermanager_h__
#include "Workers.h"
#include "jspubtd.h"
#include "prclist.h"
BEGIN_WORKERS_NAMESPACE
namespace events {
// XXX Current impl doesn't divide into phases.
// XXX Current impl doesn't handle event target chains.
class ListenerManager
{
public:
enum Phase
{
All = 0,
Capturing,
Onfoo,
Bubbling
};
private:
PRCList mCollectionHead;
public:
ListenerManager()
{
PR_INIT_CLIST(&mCollectionHead);
}
#ifdef DEBUG
~ListenerManager();
#endif
void
Trace(JSTracer* aTrc)
{
if (!PR_CLIST_IS_EMPTY(&mCollectionHead)) {
TraceInternal(aTrc);
}
}
void
Finalize(JSContext* aCx)
{
if (!PR_CLIST_IS_EMPTY(&mCollectionHead)) {
FinalizeInternal(aCx);
}
}
bool
AddEventListener(JSContext* aCx, JSString* aType, jsval aListener,
bool aCapturing, bool aWantsUntrusted)
{
return Add(aCx, aType, aListener, aCapturing ? Capturing : Bubbling,
aWantsUntrusted);
}
bool
SetEventListener(JSContext* aCx, JSString* aType, jsval aListener);
bool
RemoveEventListener(JSContext* aCx, JSString* aType, jsval aListener,
bool aCapturing)
{
if (PR_CLIST_IS_EMPTY(&mCollectionHead)) {
return true;
}
return Remove(aCx, aType, aListener, aCapturing ? Capturing : Bubbling,
true);
}
bool
GetEventListener(JSContext* aCx, JSString* aType, jsval* aListener);
bool
DispatchEvent(JSContext* aCx, JSObject* aTarget, JSObject* aEvent,
bool* aPreventDefaultCalled);
bool
HasListeners()
{
return !PR_CLIST_IS_EMPTY(&mCollectionHead);
}
bool
HasListenersForType(JSContext* aCx, JSString* aType)
{
return HasListeners() && HasListenersForTypeInternal(aCx, aType);
}
bool
HasListenersForTypeInternal(JSContext* aCx, JSString* aType);
private:
void
TraceInternal(JSTracer* aTrc);
void
FinalizeInternal(JSContext* aCx);
bool
Add(JSContext* aCx, JSString* aType, jsval aListener, Phase aPhase,
bool aWantsUntrusted);
bool
Remove(JSContext* aCx, JSString* aType, jsval aListener, Phase aPhase,
bool aClearEmpty);
};
} // namespace events
END_WORKERS_NAMESPACE
#endif /* mozilla_dom_workers_listenermanager_h__ */

241
dom/workers/Location.cpp Normal file
Просмотреть файл

@ -0,0 +1,241 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Web Workers.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "Location.h"
#include "jsapi.h"
#include "jscntxt.h"
#include "jsobj.h"
#include "nsTraceRefcnt.h"
#define PROPERTY_FLAGS \
JSPROP_ENUMERATE | JSPROP_SHARED
USING_WORKERS_NAMESPACE
namespace {
class Location
{
static JSClass sClass;
static JSPropertySpec sProperties[];
static JSFunctionSpec sFunctions[];
enum SLOT {
SLOT_href = 0,
SLOT_protocol,
SLOT_host,
SLOT_hostname,
SLOT_port,
SLOT_pathname,
SLOT_search,
SLOT_hash,
SLOT_COUNT
};
public:
static JSObject*
InitClass(JSContext* aCx, JSObject* aObj)
{
return JS_InitClass(aCx, aObj, NULL, &sClass, Construct, 0, sProperties,
sFunctions, NULL, NULL);
}
static JSObject*
Create(JSContext* aCx, JSString* aHref, JSString* aProtocol, JSString* aHost,
JSString* aHostname, JSString* aPort, JSString* aPathname,
JSString* aSearch, JSString* aHash)
{
JSObject* obj = JS_NewObject(aCx, &sClass, NULL, NULL);
if (!obj) {
return NULL;
}
jsval empty = JS_GetEmptyStringValue(aCx);
if (!JS_SetReservedSlot(aCx, obj, SLOT_href,
aHref ? STRING_TO_JSVAL(aHref) : empty) ||
!JS_SetReservedSlot(aCx, obj, SLOT_protocol,
aProtocol ? STRING_TO_JSVAL(aProtocol) : empty) ||
!JS_SetReservedSlot(aCx, obj, SLOT_host,
aHost ? STRING_TO_JSVAL(aHost) : empty) ||
!JS_SetReservedSlot(aCx, obj, SLOT_hostname,
aHostname ? STRING_TO_JSVAL(aHostname) : empty) ||
!JS_SetReservedSlot(aCx, obj, SLOT_port,
aPort ? STRING_TO_JSVAL(aPort) : empty) ||
!JS_SetReservedSlot(aCx, obj, SLOT_pathname,
aPathname ? STRING_TO_JSVAL(aPathname) : empty) ||
!JS_SetReservedSlot(aCx, obj, SLOT_search,
aSearch ? STRING_TO_JSVAL(aSearch) : empty) ||
!JS_SetReservedSlot(aCx, obj, SLOT_hash,
aHash ? STRING_TO_JSVAL(aHash) : empty)) {
return NULL;
}
Location* priv = new Location();
if (!JS_SetPrivate(aCx, obj, priv)) {
delete priv;
return NULL;
}
return obj;
}
private:
Location()
{
MOZ_COUNT_CTOR(mozilla::dom::workers::Location);
}
~Location()
{
MOZ_COUNT_DTOR(mozilla::dom::workers::Location);
}
static JSBool
Construct(JSContext* aCx, uintN aArgc, jsval* aVp)
{
JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL, JSMSG_WRONG_CONSTRUCTOR,
sClass.name);
return false;
}
static void
Finalize(JSContext* aCx, JSObject* aObj)
{
JS_ASSERT(JS_GET_CLASS(aCx, aObj) == &sClass);
delete static_cast<Location*>(JS_GetPrivate(aCx, aObj));
}
static JSBool
ToString(JSContext* aCx, uintN aArgc, jsval* aVp)
{
JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
JSClass* classPtr;
if (!obj || ((classPtr = JS_GET_CLASS(aCx, obj)) != &sClass)) {
JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL,
JSMSG_INCOMPATIBLE_PROTO, sClass.name, "toString",
classPtr ? classPtr->name : "object");
return false;
}
jsval href;
if (!JS_GetReservedSlot(aCx, obj, SLOT_href, &href)) {
return false;
}
JS_SET_RVAL(aCx, aVp, href);
return true;
}
static JSBool
GetProperty(JSContext* aCx, JSObject* aObj, jsid aIdval, jsval* aVp)
{
JSClass* classPtr;
if (!aObj || ((classPtr = JS_GET_CLASS(aCx, aObj)) != &sClass)) {
JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL,
JSMSG_INCOMPATIBLE_PROTO, sClass.name, "GetProperty",
classPtr ? classPtr->name : "object");
return false;
}
JS_ASSERT(JSID_IS_INT(aIdval));
JS_ASSERT(JSID_TO_INT(aIdval) >= 0 && JSID_TO_INT(aIdval) < SLOT_COUNT);
return JS_GetReservedSlot(aCx, aObj, JSID_TO_INT(aIdval), aVp);
}
};
JSClass Location::sClass = {
"WorkerLocation",
JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(SLOT_COUNT),
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Finalize,
JSCLASS_NO_OPTIONAL_MEMBERS
};
JSPropertySpec Location::sProperties[] = {
{ "href", SLOT_href, PROPERTY_FLAGS, GetProperty, js_GetterOnlyPropertyStub },
{ "protocol", SLOT_protocol, PROPERTY_FLAGS, GetProperty,
js_GetterOnlyPropertyStub },
{ "host", SLOT_host, PROPERTY_FLAGS, GetProperty, js_GetterOnlyPropertyStub },
{ "hostname", SLOT_hostname, PROPERTY_FLAGS, GetProperty,
js_GetterOnlyPropertyStub },
{ "port", SLOT_port, PROPERTY_FLAGS, GetProperty, js_GetterOnlyPropertyStub },
{ "pathname", SLOT_pathname, PROPERTY_FLAGS, GetProperty,
js_GetterOnlyPropertyStub },
{ "search", SLOT_search, PROPERTY_FLAGS, GetProperty,
js_GetterOnlyPropertyStub },
{ "hash", SLOT_hash, PROPERTY_FLAGS, GetProperty, js_GetterOnlyPropertyStub },
{ 0, 0, 0, NULL, NULL }
};
JSFunctionSpec Location::sFunctions[] = {
JS_FN("toString", ToString, 0, 0),
JS_FS_END
};
} // anonymous namespace
BEGIN_WORKERS_NAMESPACE
namespace location {
bool
InitClass(JSContext* aCx, JSObject* aGlobal)
{
return !!Location::InitClass(aCx, aGlobal);
}
JSObject*
Create(JSContext* aCx, JSString* aHref, JSString* aProtocol, JSString* aHost,
JSString* aHostname, JSString* aPort, JSString* aPathname,
JSString* aSearch, JSString* aHash)
{
return Location::Create(aCx, aHref, aProtocol, aHost, aHostname, aPort,
aPathname, aSearch, aHash);
}
} // namespace location
END_WORKERS_NAMESPACE

Просмотреть файл

@ -1,3 +1,4 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
@ -11,15 +12,15 @@
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is DOM Worker Tests.
* The Original Code is Web Workers.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2010
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com>
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -35,23 +36,27 @@
*
* ***** END LICENSE BLOCK ***** */
let EXPORTED_SYMBOLS = [
"WorkerTest"
];
#ifndef mozilla_dom_workers_location_h__
#define mozilla_dom_workers_location_h__
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
#include "Workers.h"
// Define our lazy getters.
XPCOMUtils.defineLazyServiceGetter(this, "workerFactory",
"@mozilla.org/threads/workerfactory;1",
"nsIWorkerFactory");
#include "jspubtd.h"
const WorkerTest = {
go: function(message, messageCallback, errorCallback) {
let worker = workerFactory.newChromeWorker("WorkerTest_worker.js");
worker.onmessage = messageCallback;
worker.onerror = errorCallback;
worker.postMessage(message);
return worker;
}
};
BEGIN_WORKERS_NAMESPACE
namespace location {
bool
InitClass(JSContext* aCx, JSObject* aGlobal);
JSObject*
Create(JSContext* aCx, JSString* aHref, JSString* aProtocol, JSString* aHost,
JSString* aHostname, JSString* aPort, JSString* aPathname,
JSString* aSearch, JSString* aHash);
} // namespace location
END_WORKERS_NAMESPACE
#endif // mozilla_dom_workers_location_h__

Просмотреть файл

@ -36,7 +36,7 @@
#
# ***** END LICENSE BLOCK *****
DEPTH = ../../..
DEPTH = ../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
@ -44,31 +44,38 @@ VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
MODULE = dom
LIBRARY_NAME = domthreads_s
LIBRARY_NAME = domworkers_s
LIBXUL_LIBRARY = 1
FORCE_STATIC_LIB = 1
EXPORTS_NAMESPACES = mozilla/dom/workers
EXPORTS_mozilla/dom/workers = Workers.h
CPPSRCS = \
nsDOMThreadService.cpp \
nsDOMWorker.cpp \
nsDOMWorkerEvents.cpp \
nsDOMWorkerLocation.cpp \
nsDOMWorkerMessageHandler.cpp \
nsDOMWorkerNavigator.cpp \
nsDOMWorkerPool.cpp \
nsDOMWorkerScriptLoader.cpp \
nsDOMWorkerSecurityManager.cpp \
nsDOMWorkerTimeout.cpp \
nsDOMWorkerXHR.cpp \
nsDOMWorkerXHRProxy.cpp \
ChromeWorkerScope.cpp \
Events.cpp \
EventTarget.cpp \
Exceptions.cpp \
ListenerManager.cpp \
Location.cpp \
Navigator.cpp \
Principal.cpp \
RuntimeService.cpp \
ScriptLoader.cpp \
Worker.cpp \
WorkerPrivate.cpp \
WorkerScope.cpp \
XMLHttpRequest.cpp \
XMLHttpRequestPrivate.cpp \
$(NULL)
LOCAL_INCLUDES = \
-I$(topsrcdir)/content/base/src \
-I$(topsrcdir)/content/events/src \
-I$(topsrcdir)/dom/base \
-I$(topsrcdir)/dom/src/json \
-I$(topsrcdir)/js/src/xpconnect/src \
-I$(topsrcdir)/xpcom/build \
$(NULL)
ifdef ENABLE_TESTS

217
dom/workers/Navigator.cpp Normal file
Просмотреть файл

@ -0,0 +1,217 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Web Workers.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "Navigator.h"
#include "jsapi.h"
#include "jscntxt.h"
#include "jsobj.h"
#include "nsTraceRefcnt.h"
#include "RuntimeService.h"
#define PROPERTY_FLAGS \
JSPROP_ENUMERATE | JSPROP_SHARED
USING_WORKERS_NAMESPACE
namespace {
class Navigator
{
static JSClass sClass;
static JSPropertySpec sProperties[];
enum SLOT {
SLOT_appName = 0,
SLOT_appVersion,
SLOT_platform,
SLOT_userAgent,
SLOT_COUNT
};
public:
static JSObject*
InitClass(JSContext* aCx, JSObject* aObj)
{
return JS_InitClass(aCx, aObj, NULL, &sClass, Construct, 0, sProperties,
NULL, NULL, NULL);
}
static JSObject*
Create(JSContext* aCx)
{
RuntimeService* rts = RuntimeService::GetService();
JS_ASSERT(rts);
const RuntimeService::NavigatorStrings& strings =
rts->GetNavigatorStrings();
JSString* appName, *version, *platform, *userAgent;
#define COPY_STRING(_jsstr, _str) \
if (strings. _str .IsEmpty()) { \
_jsstr = NULL; \
} \
else if (!(_jsstr = JS_NewUCStringCopyN(aCx, strings. _str .get(), \
strings. _str .Length()))) { \
return NULL; \
}
COPY_STRING(appName, mAppName);
COPY_STRING(version, mAppVersion);
COPY_STRING(platform, mPlatform);
COPY_STRING(userAgent, mUserAgent);
#undef COPY_STRING
JSObject* obj = JS_NewObject(aCx, &sClass, NULL, NULL);
if (!obj) {
return NULL;
}
jsval empty = JS_GetEmptyStringValue(aCx);
if (!JS_SetReservedSlot(aCx, obj, SLOT_appName,
appName ? STRING_TO_JSVAL(appName) : empty) ||
!JS_SetReservedSlot(aCx, obj, SLOT_appVersion,
version ? STRING_TO_JSVAL(version) : empty) ||
!JS_SetReservedSlot(aCx, obj, SLOT_platform,
platform ? STRING_TO_JSVAL(platform) : empty) ||
!JS_SetReservedSlot(aCx, obj, SLOT_userAgent,
userAgent ? STRING_TO_JSVAL(userAgent) : empty)) {
return NULL;
}
Navigator* priv = new Navigator();
if (!JS_SetPrivate(aCx, obj, priv)) {
delete priv;
return NULL;
}
return obj;
}
private:
Navigator()
{
MOZ_COUNT_CTOR(mozilla::dom::workers::Navigator);
}
~Navigator()
{
MOZ_COUNT_DTOR(mozilla::dom::workers::Navigator);
}
static JSBool
Construct(JSContext* aCx, uintN aArgc, jsval* aVp)
{
JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL, JSMSG_WRONG_CONSTRUCTOR,
sClass.name);
return false;
}
static void
Finalize(JSContext* aCx, JSObject* aObj)
{
JS_ASSERT(JS_GET_CLASS(aCx, aObj) == &sClass);
delete static_cast<Navigator*>(JS_GetPrivate(aCx, aObj));
}
static JSBool
GetProperty(JSContext* aCx, JSObject* aObj, jsid aIdval, jsval* aVp)
{
JSClass* classPtr;
if (!aObj || ((classPtr = JS_GET_CLASS(aCx, aObj)) != &sClass)) {
JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL,
JSMSG_INCOMPATIBLE_PROTO, sClass.name, "GetProperty",
classPtr ? classPtr->name : "object");
return false;
}
JS_ASSERT(JSID_IS_INT(aIdval));
JS_ASSERT(JSID_TO_INT(aIdval) >= 0 && JSID_TO_INT(aIdval) < SLOT_COUNT);
return JS_GetReservedSlot(aCx, aObj, JSID_TO_INT(aIdval), aVp);
}
};
JSClass Navigator::sClass = {
"WorkerNavigator",
JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(SLOT_COUNT),
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Finalize,
JSCLASS_NO_OPTIONAL_MEMBERS
};
JSPropertySpec Navigator::sProperties[] = {
{ "appName", SLOT_appName, PROPERTY_FLAGS, GetProperty,
js_GetterOnlyPropertyStub },
{ "appVersion", SLOT_appVersion, PROPERTY_FLAGS, GetProperty,
js_GetterOnlyPropertyStub },
{ "platform", SLOT_platform, PROPERTY_FLAGS, GetProperty,
js_GetterOnlyPropertyStub },
{ "userAgent", SLOT_userAgent, PROPERTY_FLAGS, GetProperty,
js_GetterOnlyPropertyStub },
{ 0, 0, 0, NULL, NULL }
};
} // anonymous namespace
BEGIN_WORKERS_NAMESPACE
namespace navigator {
bool
InitClass(JSContext* aCx, JSObject* aGlobal)
{
return !!Navigator::InitClass(aCx, aGlobal);
}
JSObject*
Create(JSContext* aCx)
{
return Navigator::Create(aCx);
}
} // namespace navigator
END_WORKERS_NAMESPACE

Просмотреть файл

@ -1,3 +1,4 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
@ -11,15 +12,15 @@
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is DOM Worker Tests.
* The Original Code is Web Workers.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2010
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com>
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -35,10 +36,25 @@
*
* ***** END LICENSE BLOCK ***** */
onmessage = function(event) {
let worker = new ChromeWorker("WorkerTest_subworker.js");
worker.onmessage = function(event) {
postMessage(event.data);
}
worker.postMessage(event.data);
}
#ifndef mozilla_dom_workers_navigator_h__
#define mozilla_dom_workers_navigator_h__
#include "Workers.h"
#include "jspubtd.h"
BEGIN_WORKERS_NAMESPACE
namespace navigator {
bool
InitClass(JSContext* aCx, JSObject* aGlobal);
JSObject*
Create(JSContext* aCx);
} // namespace navigator
END_WORKERS_NAMESPACE
#endif // mozilla_dom_workers_navigator_h__

74
dom/workers/Principal.cpp Normal file
Просмотреть файл

@ -0,0 +1,74 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Web Workers.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "Principal.h"
#include "jsapi.h"
namespace {
void
PrincipalDestroy(JSContext*, JSPrincipals*)
{
// nothing
}
JSBool
PrincipalSubsume(JSPrincipals*, JSPrincipals*)
{
return JS_TRUE;
}
const char gPrincipalCodebase[] = "Web Worker";
JSPrincipals gPrincipal = {
const_cast<char*>(gPrincipalCodebase),
NULL, NULL, 1, PrincipalDestroy, PrincipalSubsume
};
} // anonymous namespace
BEGIN_WORKERS_NAMESPACE
JSPrincipals*
GetWorkerPrincipal()
{
return &gPrincipal;
}
END_WORKERS_NAMESPACE

Просмотреть файл

@ -1,3 +1,4 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
@ -11,15 +12,15 @@
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is DOM Worker Tests.
* The Original Code is Web Workers.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2010
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com>
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -35,6 +36,18 @@
*
* ***** END LICENSE BLOCK ***** */
onmessage = function(event) {
throw "Shouldn't be able to read this!";
}
#ifndef mozilla_dom_workers_principal_h__
#define mozilla_dom_workers_principal_h__
#include "Workers.h"
#include "jspubtd.h"
BEGIN_WORKERS_NAMESPACE
JSPrincipals*
GetWorkerPrincipal();
END_WORKERS_NAMESPACE
#endif /* mozilla_dom_workers_principal_h__ */

235
dom/workers/Queue.h Normal file
Просмотреть файл

@ -0,0 +1,235 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Web Workers.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef mozilla_dom_workers_queue_h__
#define mozilla_dom_workers_queue_h__
#include "Workers.h"
#include "mozilla/Mutex.h"
#include "nsTArray.h"
BEGIN_WORKERS_NAMESPACE
template <typename T, int TCount>
struct StorageWithTArray
{
typedef nsAutoTArray<T, TCount> StorageType;
static void Reverse(StorageType& aStorage)
{
PRUint32 length = aStorage.Length();
for (PRUint32 index = 0; index < length / 2; index++) {
PRUint32 reverseIndex = length - 1 - index;
T t1 = aStorage.ElementAt(index);
T t2 = aStorage.ElementAt(reverseIndex);
aStorage.ReplaceElementsAt(index, 1, t2);
aStorage.ReplaceElementsAt(reverseIndex, 1, t1);
}
}
static bool IsEmpty(const StorageType& aStorage)
{
return !!aStorage.IsEmpty();
}
static bool Push(StorageType& aStorage, const T& aEntry)
{
return !!aStorage.AppendElement(aEntry);
}
static bool Pop(StorageType& aStorage, T& aEntry)
{
if (IsEmpty(aStorage)) {
return false;
}
PRUint32 index = aStorage.Length() - 1;
aEntry = aStorage.ElementAt(index);
aStorage.RemoveElementAt(index);
return true;
}
static void Clear(StorageType& aStorage)
{
aStorage.Clear();
}
static void Compact(StorageType& aStorage)
{
aStorage.Compact();
}
};
class LockingWithMutex
{
mozilla::Mutex mMutex;
protected:
LockingWithMutex()
: mMutex("LockingWithMutex::mMutex")
{ }
void Lock()
{
mMutex.Lock();
}
void Unlock()
{
mMutex.Unlock();
}
class AutoLock
{
LockingWithMutex& mHost;
public:
AutoLock(LockingWithMutex& aHost)
: mHost(aHost)
{
mHost.Lock();
}
~AutoLock()
{
mHost.Unlock();
}
};
friend class AutoLock;
};
class NoLocking
{
protected:
void Lock()
{ }
void Unlock()
{ }
class AutoLock
{
public:
AutoLock(NoLocking& aHost)
{ }
~AutoLock()
{ }
};
};
template <typename T,
int TCount = 256,
class LockingPolicy = NoLocking,
class StoragePolicy = StorageWithTArray<T, TCount % 2 ?
TCount / 2 + 1 :
TCount / 2> >
class Queue : public LockingPolicy
{
typedef typename StoragePolicy::StorageType StorageType;
typedef typename LockingPolicy::AutoLock AutoLock;
StorageType mStorage1;
StorageType mStorage2;
StorageType* mFront;
StorageType* mBack;
public:
Queue()
: mFront(&mStorage1), mBack(&mStorage2)
{ }
bool IsEmpty()
{
AutoLock lock(*this);
return StoragePolicy::IsEmpty(*mFront) &&
StoragePolicy::IsEmpty(*mBack);
}
bool Push(const T& aEntry)
{
AutoLock lock(*this);
return StoragePolicy::Push(*mBack, aEntry);
}
bool Pop(T& aEntry)
{
AutoLock lock(*this);
if (StoragePolicy::IsEmpty(*mFront)) {
StoragePolicy::Compact(*mFront);
StoragePolicy::Reverse(*mBack);
StorageType* tmp = mFront;
mFront = mBack;
mBack = tmp;
}
return StoragePolicy::Pop(*mFront, aEntry);
}
void Clear()
{
AutoLock lock(*this);
StoragePolicy::Clear(*mFront);
StoragePolicy::Clear(*mBack);
}
// XXX Do we need this?
void Lock()
{
LockingPolicy::Lock();
}
// XXX Do we need this?
void Unlock()
{
LockingPolicy::Unlock();
}
private:
// Queue is not copyable.
Queue(const Queue&);
Queue & operator=(const Queue&);
};
END_WORKERS_NAMESPACE
#endif /* mozilla_dom_workers_queue_h__ */

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,224 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Web Workers.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef mozilla_dom_workers_runtimeservice_h__
#define mozilla_dom_workers_runtimeservice_h__
#include "Workers.h"
#include "nsIObserver.h"
#include "jsapi.h"
#include "mozilla/Mutex.h"
#include "nsAutoPtr.h"
#include "nsClassHashtable.h"
#include "nsCOMPtr.h"
#include "nsHashKeys.h"
#include "nsStringGlue.h"
#include "nsTArray.h"
class nsIThread;
class nsPIDOMWindow;
BEGIN_WORKERS_NAMESPACE
class WorkerPrivate;
class RuntimeService : public nsIObserver
{
struct WorkerDomainInfo
{
nsCString mDomain;
nsTArray<WorkerPrivate*> mActiveWorkers;
nsTArray<WorkerPrivate*> mQueuedWorkers;
PRUint32 mChildWorkerCount;
WorkerDomainInfo() : mActiveWorkers(1), mChildWorkerCount(0) { }
PRUint32
ActiveWorkerCount() const
{
return mActiveWorkers.Length() + mChildWorkerCount;
}
};
mozilla::Mutex mDomainMapMutex;
nsClassHashtable<nsCStringHashKey, WorkerDomainInfo> mDomainMap;
nsClassHashtable<nsVoidPtrHashKey, nsTArray<WorkerPrivate*> > mWindowMap;
static PRUint32 sDefaultJSContextOptions;
static PRInt32 sCloseHandlerTimeoutSeconds;
#ifdef JS_GC_ZEAL
static PRUint8 sDefaultGCZeal;
#endif
public:
struct NavigatorStrings
{
nsString mAppName;
nsString mAppVersion;
nsString mPlatform;
nsString mUserAgent;
};
private:
NavigatorStrings mNavigatorStrings;
// True when the observer service holds a reference to this object.
bool mObserved;
bool mShuttingDown;
bool mNavigatorStringsLoaded;
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
static RuntimeService*
GetOrCreateService();
static RuntimeService*
GetService();
bool
RegisterWorker(JSContext* aCx, WorkerPrivate* aWorkerPrivate);
void
UnregisterWorker(JSContext* aCx, WorkerPrivate* aWorkerPrivate);
void
CancelWorkersForWindow(JSContext* aCx, nsPIDOMWindow* aWindow);
void
SuspendWorkersForWindow(JSContext* aCx, nsPIDOMWindow* aWindow);
void
ResumeWorkersForWindow(JSContext* aCx, nsPIDOMWindow* aWindow);
const NavigatorStrings&
GetNavigatorStrings() const
{
return mNavigatorStrings;
}
static PRUint32
GetDefaultJSContextOptions()
{
AssertIsOnMainThread();
return sDefaultJSContextOptions;
}
static void
SetDefaultJSContextOptions(PRUint32 aOptions)
{
AssertIsOnMainThread();
sDefaultJSContextOptions = aOptions;
}
void
UpdateAllWorkerJSContextOptions();
static PRUint32
GetCloseHandlerTimeoutSeconds()
{
return sCloseHandlerTimeoutSeconds > 0 ? sCloseHandlerTimeoutSeconds : 0;
}
#ifdef JS_GC_ZEAL
static PRUint8
GetDefaultGCZeal()
{
AssertIsOnMainThread();
return sDefaultGCZeal;
}
static void
SetDefaultGCZeal(PRUint8 aGCZeal)
{
AssertIsOnMainThread();
sDefaultGCZeal = aGCZeal;
}
void
UpdateAllWorkerGCZeal();
#endif
class AutoSafeJSContext
{
JSContext* mContext;
public:
AutoSafeJSContext(JSContext* aCx = nsnull);
~AutoSafeJSContext();
operator JSContext*() const
{
return mContext;
}
static JSContext*
GetSafeContext();
};
private:
RuntimeService();
~RuntimeService();
nsresult
Init();
void
Cleanup();
static PLDHashOperator
AddAllTopLevelWorkersToArray(const nsACString& aKey,
WorkerDomainInfo* aData,
void* aUserArg);
void
GetWorkersForWindow(nsPIDOMWindow* aWindow,
nsTArray<WorkerPrivate*>& aWorkers);
bool
ScheduleWorker(JSContext* aCx, WorkerPrivate* aWorkerPrivate);
};
END_WORKERS_NAMESPACE
#endif /* mozilla_dom_workers_runtimeservice_h__ */

Просмотреть файл

@ -0,0 +1,755 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Web Workers.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "ScriptLoader.h"
#include "nsIChannel.h"
#include "nsIChannelPolicy.h"
#include "nsIContentPolicy.h"
#include "nsIContentSecurityPolicy.h"
#include "nsIHttpChannel.h"
#include "nsIIOService.h"
#include "nsIProtocolHandler.h"
#include "nsIScriptSecurityManager.h"
#include "nsIStreamLoader.h"
#include "nsIURI.h"
#include "jsapi.h"
#include "nsChannelPolicy.h"
#include "nsContentErrors.h"
#include "nsContentPolicyUtils.h"
#include "nsContentUtils.h"
#include "nsDocShellCID.h"
#include "nsISupportsPrimitives.h"
#include "nsNetError.h"
#include "nsNetUtil.h"
#include "nsScriptLoader.h"
#include "nsStringGlue.h"
#include "nsTArray.h"
#include "nsThreadUtils.h"
#include "nsXPCOM.h"
#include "Principal.h"
#include "WorkerFeature.h"
#include "WorkerPrivate.h"
#define MAX_CONCURRENT_SCRIPTS 1000
USING_WORKERS_NAMESPACE
namespace {
class ScriptLoaderRunnable;
struct ScriptLoadInfo
{
ScriptLoadInfo()
: mLoadResult(NS_ERROR_NOT_INITIALIZED), mExecutionScheduled(false),
mExecutionResult(false)
{ }
bool
ReadyToExecute()
{
return !mChannel && NS_SUCCEEDED(mLoadResult) && !mExecutionScheduled;
}
nsString mURL;
nsCOMPtr<nsIChannel> mChannel;
nsString mScriptText;
nsresult mLoadResult;
bool mExecutionScheduled;
bool mExecutionResult;
};
class ScriptExecutorRunnable : public WorkerSyncRunnable
{
ScriptLoaderRunnable& mScriptLoader;
PRUint32 mFirstIndex;
PRUint32 mLastIndex;
public:
ScriptExecutorRunnable(ScriptLoaderRunnable& aScriptLoader,
PRUint32 aSyncQueueKey, PRUint32 aFirstIndex,
PRUint32 aLastIndex);
bool
PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
{
AssertIsOnMainThread();
return true;
}
void
PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
bool aDispatchResult)
{
AssertIsOnMainThread();
}
bool
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate);
void
PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate, bool aRunResult);
};
class ScriptLoaderRunnable : public WorkerFeature,
public nsIRunnable,
public nsIStreamLoaderObserver
{
friend class ScriptExecutorRunnable;
WorkerPrivate* mWorkerPrivate;
PRUint32 mSyncQueueKey;
nsTArray<ScriptLoadInfo> mLoadInfos;
bool mIsWorkerScript;
bool mCanceled;
bool mCanceledMainThread;
public:
NS_DECL_ISUPPORTS
ScriptLoaderRunnable(WorkerPrivate* aWorkerPrivate,
PRUint32 aSyncQueueKey,
nsTArray<ScriptLoadInfo>& aLoadInfos,
bool aIsWorkerScript)
: mWorkerPrivate(aWorkerPrivate), mSyncQueueKey(aSyncQueueKey),
mIsWorkerScript(aIsWorkerScript), mCanceled(false),
mCanceledMainThread(false)
{
aWorkerPrivate->AssertIsOnWorkerThread();
NS_ASSERTION(!aIsWorkerScript || aLoadInfos.Length() == 1, "Bad args!");
if (!mLoadInfos.SwapElements(aLoadInfos)) {
NS_ERROR("This should never fail!");
}
}
NS_IMETHOD
Run()
{
AssertIsOnMainThread();
if (NS_FAILED(RunInternal())) {
CancelMainThread();
}
return NS_OK;
}
NS_IMETHOD
OnStreamComplete(nsIStreamLoader* aLoader, nsISupports* aContext,
nsresult aStatus, PRUint32 aStringLen,
const PRUint8* aString)
{
AssertIsOnMainThread();
nsCOMPtr<nsISupportsPRUint32> indexSupports(do_QueryInterface(aContext));
NS_ASSERTION(indexSupports, "This should never fail!");
PRUint32 index = PR_UINT32_MAX;
if (NS_FAILED(indexSupports->GetData(&index)) ||
index >= mLoadInfos.Length()) {
NS_ERROR("Bad index!");
}
ScriptLoadInfo& loadInfo = mLoadInfos[index];
loadInfo.mLoadResult = OnStreamCompleteInternal(aLoader, aContext, aStatus,
aStringLen, aString,
loadInfo);
ExecuteFinishedScripts();
return NS_OK;
}
bool
Notify(JSContext* aCx, Status aStatus)
{
mWorkerPrivate->AssertIsOnWorkerThread();
if (aStatus >= Terminating && !mCanceled) {
mCanceled = true;
nsCOMPtr<nsIRunnable> runnable =
NS_NewRunnableMethod(this, &ScriptLoaderRunnable::CancelMainThread);
NS_ASSERTION(runnable, "This should never fail!");
if (NS_FAILED(NS_DispatchToMainThread(runnable, NS_DISPATCH_NORMAL))) {
JS_ReportError(aCx, "Failed to cancel script loader!");
return false;
}
}
return true;
}
void
CancelMainThread()
{
AssertIsOnMainThread();
if (mCanceledMainThread) {
return;
}
mCanceledMainThread = true;
// Cancel all the channels that were already opened.
for (PRUint32 index = 0; index < mLoadInfos.Length(); index++) {
ScriptLoadInfo& loadInfo = mLoadInfos[index];
if (loadInfo.mChannel &&
NS_FAILED(loadInfo.mChannel->Cancel(NS_BINDING_ABORTED))) {
NS_WARNING("Failed to cancel channel!");
loadInfo.mChannel = nsnull;
loadInfo.mLoadResult = NS_BINDING_ABORTED;
}
}
ExecuteFinishedScripts();
}
nsresult
RunInternal()
{
AssertIsOnMainThread();
WorkerPrivate* parentWorker = mWorkerPrivate->GetParent();
// Figure out which principal to use.
nsIPrincipal* principal = mWorkerPrivate->GetPrincipal();
if (!principal) {
NS_ASSERTION(parentWorker, "Must have a principal!");
NS_ASSERTION(mIsWorkerScript, "Must have a principal for importScripts!");
principal = parentWorker->GetPrincipal();
}
NS_ASSERTION(principal, "This should never be null here!");
// Figure out our base URI.
nsCOMPtr<nsIURI> baseURI;
if (mIsWorkerScript) {
if (parentWorker) {
baseURI = parentWorker->GetBaseURI();
NS_ASSERTION(baseURI, "Should have been set already!");
}
else {
// May be null.
baseURI = mWorkerPrivate->GetBaseURI();
}
}
else {
baseURI = mWorkerPrivate->GetBaseURI();
NS_ASSERTION(baseURI, "Should have been set already!");
}
// May be null.
nsCOMPtr<nsIDocument> parentDoc = mWorkerPrivate->GetDocument();
// All of these can potentially be null, but that should be ok. We'll either
// succeed without them or fail below.
nsCOMPtr<nsILoadGroup> loadGroup;
if (parentDoc) {
loadGroup = parentDoc->GetDocumentLoadGroup();
}
nsCOMPtr<nsIIOService> ios(do_GetIOService());
nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
NS_ASSERTION(secMan, "This should never be null!");
for (PRUint32 index = 0; index < mLoadInfos.Length(); index++) {
ScriptLoadInfo& loadInfo = mLoadInfos[index];
nsresult& rv = loadInfo.mLoadResult;
nsCOMPtr<nsIURI> uri;
rv = nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(uri),
loadInfo.mURL, parentDoc,
baseURI);
if (NS_FAILED(rv)) {
return rv;
}
// If we're part of a document then check the content load policy.
if (parentDoc) {
PRInt16 shouldLoad = nsIContentPolicy::ACCEPT;
rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_SCRIPT, uri,
principal, parentDoc,
NS_LITERAL_CSTRING("text/javascript"),
nsnull, &shouldLoad,
nsContentUtils::GetContentPolicy(),
secMan);
if (NS_FAILED(rv) || NS_CP_REJECTED(shouldLoad)) {
if (NS_FAILED(rv) || shouldLoad != nsIContentPolicy::REJECT_TYPE) {
return rv = NS_ERROR_CONTENT_BLOCKED;
}
return rv = NS_ERROR_CONTENT_BLOCKED_SHOW_ALT;
}
}
// If this script loader is being used to make a new worker then we need
// to do a same-origin check. Otherwise we need to clear the load with the
// security manager.
rv = mIsWorkerScript ?
principal->CheckMayLoad(uri, PR_FALSE):
secMan->CheckLoadURIWithPrincipal(principal, uri, 0);
NS_ENSURE_SUCCESS(rv, rv);
// We need to know which index we're on in OnStreamComplete so we know
// where to put the result.
nsCOMPtr<nsISupportsPRUint32> indexSupports =
do_CreateInstance(NS_SUPPORTS_PRUINT32_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = indexSupports->SetData(index);
NS_ENSURE_SUCCESS(rv, rv);
// We don't care about progress so just use the simple stream loader for
// OnStreamComplete notification only.
nsCOMPtr<nsIStreamLoader> loader;
rv = NS_NewStreamLoader(getter_AddRefs(loader), this);
NS_ENSURE_SUCCESS(rv, rv);
// Get Content Security Policy from parent document to pass into channel.
nsCOMPtr<nsIContentSecurityPolicy> csp;
rv = principal->GetCsp(getter_AddRefs(csp));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIChannelPolicy> channelPolicy;
if (csp) {
channelPolicy = do_CreateInstance(NSCHANNELPOLICY_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = channelPolicy->SetContentSecurityPolicy(csp);
NS_ENSURE_SUCCESS(rv, rv);
rv = channelPolicy->SetLoadType(nsIContentPolicy::TYPE_SCRIPT);
NS_ENSURE_SUCCESS(rv, rv);
}
PRUint32 flags = nsIRequest::LOAD_NORMAL | nsIChannel::LOAD_CLASSIFY_URI;
nsCOMPtr<nsIChannel> channel;
rv = NS_NewChannel(getter_AddRefs(channel), uri, ios, loadGroup, nsnull,
flags, channelPolicy);
NS_ENSURE_SUCCESS(rv, rv);
rv = channel->AsyncOpen(loader, indexSupports);
NS_ENSURE_SUCCESS(rv, rv);
loadInfo.mChannel.swap(channel);
}
return NS_OK;
}
nsresult
OnStreamCompleteInternal(nsIStreamLoader* aLoader, nsISupports* aContext,
nsresult aStatus, PRUint32 aStringLen,
const PRUint8* aString, ScriptLoadInfo& aLoadInfo)
{
AssertIsOnMainThread();
if (!aLoadInfo.mChannel) {
return NS_BINDING_ABORTED;
}
aLoadInfo.mChannel = nsnull;
if (NS_FAILED(aStatus)) {
return aStatus;
}
if (!aStringLen) {
return NS_OK;
}
NS_ASSERTION(aString, "This should never be null!");
// Make sure we're not seeing the result of a 404 or something by checking
// the 'requestSucceeded' attribute on the http channel.
nsCOMPtr<nsIRequest> request;
nsresult rv = aLoader->GetRequest(getter_AddRefs(request));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(request);
if (httpChannel) {
PRBool requestSucceeded;
rv = httpChannel->GetRequestSucceeded(&requestSucceeded);
NS_ENSURE_SUCCESS(rv, rv);
if (!requestSucceeded) {
return NS_ERROR_NOT_AVAILABLE;
}
}
// May be null.
nsIDocument* parentDoc = mWorkerPrivate->GetDocument();
// Use the regular nsScriptLoader for this grunt work! Should be just fine
// because we're running on the main thread.
rv = nsScriptLoader::ConvertToUTF16(aLoadInfo.mChannel, aString, aStringLen,
EmptyString(), parentDoc,
aLoadInfo.mScriptText);
if (NS_FAILED(rv)) {
return rv;
}
if (aLoadInfo.mScriptText.IsEmpty()) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
NS_ASSERTION(channel, "This should never fail!");
// Figure out what we actually loaded.
nsCOMPtr<nsIURI> finalURI;
rv = NS_GetFinalChannelURI(channel, getter_AddRefs(finalURI));
NS_ENSURE_SUCCESS(rv, rv);
nsCString filename;
rv = finalURI->GetSpec(filename);
NS_ENSURE_SUCCESS(rv, rv);
if (!filename.IsEmpty()) {
// This will help callers figure out what their script url resolved to in
// case of errors.
aLoadInfo.mURL.Assign(NS_ConvertUTF8toUTF16(filename));
}
// Update the principal of the worker and its base URI if we just loaded the
// worker's primary script.
if (mIsWorkerScript) {
// Take care of the base URI first.
rv = mWorkerPrivate->SetBaseURI(finalURI);
NS_ENSURE_SUCCESS(rv, rv);
// Now to figure out which principal to give this worker.
WorkerPrivate* parent = mWorkerPrivate->GetParent();
NS_ASSERTION(mWorkerPrivate->GetPrincipal() || parent,
"Must have one of these!");
nsCOMPtr<nsIPrincipal> loadPrincipal = mWorkerPrivate->GetPrincipal() ?
mWorkerPrivate->GetPrincipal() :
parent->GetPrincipal();
nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
NS_ASSERTION(ssm, "Should never be null!");
nsCOMPtr<nsIPrincipal> channelPrincipal;
rv = ssm->GetChannelPrincipal(channel, getter_AddRefs(channelPrincipal));
NS_ENSURE_SUCCESS(rv, rv);
// See if this is a resource URI. Since JSMs usually come from resource://
// URIs we're currently considering all URIs with the URI_IS_UI_RESOURCE
// flag as valid for creating privileged workers.
if (!nsContentUtils::IsSystemPrincipal(channelPrincipal)) {
PRBool isResource;
rv = NS_URIChainHasFlags(finalURI,
nsIProtocolHandler::URI_IS_UI_RESOURCE,
&isResource);
NS_ENSURE_SUCCESS(rv, rv);
if (isResource) {
rv = ssm->GetSystemPrincipal(getter_AddRefs(channelPrincipal));
NS_ENSURE_SUCCESS(rv, rv);
}
}
// If the load principal is the system principal then the channel
// principal must also be the system principal (we do not allow chrome
// code to create workers with non-chrome scripts). Otherwise this channel
// principal must be same origin with the load principal (we check again
// here in case redirects changed the location of the script).
if (nsContentUtils::IsSystemPrincipal(loadPrincipal)) {
if (!nsContentUtils::IsSystemPrincipal(channelPrincipal)) {
return NS_ERROR_DOM_BAD_URI;
}
}
else if (NS_FAILED(loadPrincipal->CheckMayLoad(finalURI, PR_FALSE))) {
return NS_ERROR_DOM_BAD_URI;
}
mWorkerPrivate->SetPrincipal(channelPrincipal);
}
return NS_OK;
}
void
ExecuteFinishedScripts()
{
PRUint32 firstIndex = PR_UINT32_MAX;
PRUint32 lastIndex = PR_UINT32_MAX;
// Find firstIndex based on whether mExecutionScheduled is unset.
for (PRUint32 index = 0; index < mLoadInfos.Length(); index++) {
if (!mLoadInfos[index].mExecutionScheduled) {
firstIndex = index;
break;
}
}
// Find lastIndex based on whether mChannel is set, and update
// mExecutionScheduled on the ones we're about to schedule.
if (firstIndex != PR_UINT32_MAX) {
for (PRUint32 index = firstIndex; index < mLoadInfos.Length(); index++) {
ScriptLoadInfo& loadInfo = mLoadInfos[index];
// If we still have a channel then the load is not complete.
if (loadInfo.mChannel) {
break;
}
// We can execute this one.
loadInfo.mExecutionScheduled = true;
lastIndex = index;
}
}
if (firstIndex != PR_UINT32_MAX && lastIndex != PR_UINT32_MAX) {
nsRefPtr<ScriptExecutorRunnable> runnable =
new ScriptExecutorRunnable(*this, mSyncQueueKey, firstIndex, lastIndex);
if (!runnable->Dispatch(nsnull)) {
NS_ERROR("This should never fail!");
}
}
}
};
NS_IMPL_THREADSAFE_ISUPPORTS2(ScriptLoaderRunnable, nsIRunnable,
nsIStreamLoaderObserver)
ScriptExecutorRunnable::ScriptExecutorRunnable(
ScriptLoaderRunnable& aScriptLoader,
PRUint32 aSyncQueueKey,
PRUint32 aFirstIndex,
PRUint32 aLastIndex)
: WorkerSyncRunnable(aScriptLoader.mWorkerPrivate, aSyncQueueKey),
mScriptLoader(aScriptLoader), mFirstIndex(aFirstIndex), mLastIndex(aLastIndex)
{
NS_ASSERTION(aFirstIndex <= aLastIndex, "Bad first index!");
NS_ASSERTION(aLastIndex < aScriptLoader.mLoadInfos.Length(),
"Bad last index!");
}
bool
ScriptExecutorRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
{
nsTArray<ScriptLoadInfo>& loadInfos = mScriptLoader.mLoadInfos;
// Don't run if something else has already failed.
for (PRUint32 index = 0; index < mFirstIndex; index++) {
ScriptLoadInfo& loadInfo = loadInfos.ElementAt(index);
NS_ASSERTION(!loadInfo.mChannel, "Should no longer have a channel!");
NS_ASSERTION(loadInfo.mExecutionScheduled, "Should be scheduled!");
if (!loadInfo.mExecutionResult) {
return true;
}
}
JSObject* global = JS_GetGlobalObject(aCx);
NS_ASSERTION(global, "Must have a global by now!");
JSPrincipals* principal = GetWorkerPrincipal();
NS_ASSERTION(principal, "This should never be null!");
for (PRUint32 index = mFirstIndex; index <= mLastIndex; index++) {
ScriptLoadInfo& loadInfo = loadInfos.ElementAt(index);
NS_ASSERTION(!loadInfo.mChannel, "Should no longer have a channel!");
NS_ASSERTION(loadInfo.mExecutionScheduled, "Should be scheduled!");
NS_ASSERTION(!loadInfo.mExecutionResult, "Should not have executed yet!");
if (NS_FAILED(loadInfo.mLoadResult)) {
NS_ConvertUTF16toUTF8 url(loadInfo.mURL);
switch (loadInfo.mLoadResult) {
case NS_BINDING_ABORTED:
// Canceled, don't set an exception.
break;
case NS_ERROR_MALFORMED_URI:
JS_ReportError(aCx, "Malformed script URI: %s", url.get());
break;
case NS_ERROR_FILE_NOT_FOUND:
case NS_ERROR_NOT_AVAILABLE:
JS_ReportError(aCx, "Script file not found: %s", url.get());
break;
default:
JS_ReportError(aCx, "Failed to load script: %s (nsresult = 0x%x)",
url.get(), loadInfo.mLoadResult);
}
return true;
}
NS_ConvertUTF16toUTF8 filename(loadInfo.mURL);
if (!JS_EvaluateUCScriptForPrincipals(aCx, global, principal,
loadInfo.mScriptText.get(),
loadInfo.mScriptText.Length(),
filename.get(), 1, nsnull)) {
return true;
}
loadInfo.mExecutionResult = true;
}
return true;
}
void
ScriptExecutorRunnable::PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
bool aRunResult)
{
nsTArray<ScriptLoadInfo>& loadInfos = mScriptLoader.mLoadInfos;
if (mLastIndex == loadInfos.Length() - 1) {
// All done. If anything failed then return false.
bool result = true;
for (PRUint32 index = 0; index < loadInfos.Length(); index++) {
if (!loadInfos[index].mExecutionResult) {
result = false;
break;
}
}
aWorkerPrivate->RemoveFeature(aCx, &mScriptLoader);
aWorkerPrivate->StopSyncLoop(mSyncQueueKey, result);
}
}
bool
LoadAllScripts(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
nsTArray<ScriptLoadInfo>& aLoadInfos, bool aIsWorkerScript)
{
aWorkerPrivate->AssertIsOnWorkerThread();
NS_ASSERTION(!aLoadInfos.IsEmpty(), "Bad arguments!");
PRUint32 syncQueueKey = aWorkerPrivate->CreateNewSyncLoop();
nsRefPtr<ScriptLoaderRunnable> loader =
new ScriptLoaderRunnable(aWorkerPrivate, syncQueueKey, aLoadInfos,
aIsWorkerScript);
NS_ASSERTION(aLoadInfos.IsEmpty(), "Should have swapped!");
if (!aWorkerPrivate->AddFeature(aCx, loader)) {
return false;
}
if (NS_FAILED(NS_DispatchToMainThread(loader, NS_DISPATCH_NORMAL))) {
NS_ERROR("Failed to dispatch!");
aWorkerPrivate->RemoveFeature(aCx, loader);
return false;
}
return aWorkerPrivate->RunSyncLoop(aCx, syncQueueKey);
}
} /* anonymous namespace */
BEGIN_WORKERS_NAMESPACE
namespace scriptloader {
bool
LoadWorkerScript(JSContext* aCx)
{
WorkerPrivate* worker = GetWorkerPrivateFromContext(aCx);
NS_ASSERTION(worker, "This should never be null!");
nsTArray<ScriptLoadInfo> loadInfos;
ScriptLoadInfo* info = loadInfos.AppendElement();
info->mURL = worker->ScriptURL();
return LoadAllScripts(aCx, worker, loadInfos, true);
}
bool
Load(JSContext* aCx, uintN aURLCount, jsval* aURLs)
{
WorkerPrivate* worker = GetWorkerPrivateFromContext(aCx);
NS_ASSERTION(worker, "This should never be null!");
if (!aURLCount) {
return true;
}
if (aURLCount > MAX_CONCURRENT_SCRIPTS) {
JS_ReportError(aCx, "Cannot load more than %d scripts at one time!",
MAX_CONCURRENT_SCRIPTS);
return false;
}
nsTArray<ScriptLoadInfo> loadInfos;
loadInfos.SetLength(PRUint32(aURLCount));
for (uintN index = 0; index < aURLCount; index++) {
JSString* str = JS_ValueToString(aCx, aURLs[index]);
if (!str) {
return false;
}
size_t length;
const jschar* buffer = JS_GetStringCharsAndLength(aCx, str, &length);
if (!buffer) {
return false;
}
loadInfos[index].mURL.Assign(buffer, length);
}
return LoadAllScripts(aCx, worker, loadInfos, false);
}
} // namespace scriptloader
END_WORKERS_NAMESPACE

Просмотреть файл

@ -0,0 +1,58 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Web Workers.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef mozilla_dom_workers_scriptloader_h__
#define mozilla_dom_workers_scriptloader_h__
#include "Workers.h"
#include "jspubtd.h"
BEGIN_WORKERS_NAMESPACE
namespace scriptloader {
bool LoadWorkerScript(JSContext* aCx);
bool Load(JSContext* aCx, uintN aURLCount, jsval* aURLs);
} // namespace scriptloader
END_WORKERS_NAMESPACE
#endif /* mozilla_dom_workers_scriptloader_h__ */

441
dom/workers/Worker.cpp Normal file
Просмотреть файл

@ -0,0 +1,441 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Web Workers.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "Worker.h"
#include "jsapi.h"
#include "jscntxt.h"
#include "EventTarget.h"
#include "RuntimeService.h"
#include "WorkerPrivate.h"
#include "WorkerInlines.h"
#define PROPERTY_FLAGS \
JSPROP_ENUMERATE | JSPROP_SHARED
#define FUNCTION_FLAGS \
JSPROP_ENUMERATE
USING_WORKERS_NAMESPACE
namespace {
class Worker
{
static JSClass sClass;
static JSPropertySpec sProperties[];
static JSFunctionSpec sFunctions[];
enum
{
STRING_onerror = 0,
STRING_onmessage,
STRING_COUNT
};
static const char* const sEventStrings[STRING_COUNT];
protected:
enum {
// The constructor function holds a WorkerPrivate* in its first reserved
// slot.
CONSTRUCTOR_SLOT_PARENT = 0
};
public:
static JSClass*
Class()
{
return &sClass;
}
static JSObject*
InitClass(JSContext* aCx, JSObject* aObj, JSObject* aParentProto,
bool aMainRuntime)
{
JSObject* proto = JS_InitClass(aCx, aObj, aParentProto, &sClass, Construct,
0, sProperties, sFunctions, NULL, NULL);
if (!proto) {
return NULL;
}
if (!aMainRuntime) {
WorkerPrivate* parent = GetWorkerPrivateFromContext(aCx);
parent->AssertIsOnWorkerThread();
JSObject* constructor = JS_GetConstructor(aCx, proto);
if (!constructor ||
!JS_SetReservedSlot(aCx, constructor, CONSTRUCTOR_SLOT_PARENT,
PRIVATE_TO_JSVAL(parent))) {
return NULL;
}
}
return proto;
}
protected:
static WorkerPrivate*
GetInstancePrivate(JSContext* aCx, JSObject* aObj, const char* aFunctionName);
static JSBool
ConstructInternal(JSContext* aCx, uintN aArgc, jsval* aVp,
bool aIsChromeWorker)
{
if (!aArgc) {
JS_ReportError(aCx, "Constructor requires at least one argument!");
return false;
}
JSString* scriptURL = JS_ValueToString(aCx, JS_ARGV(aCx, aVp)[0]);
if (!scriptURL) {
return false;
}
jsval priv;
if (!JS_GetReservedSlot(aCx, JSVAL_TO_OBJECT(JS_CALLEE(aCx, aVp)),
CONSTRUCTOR_SLOT_PARENT, &priv)) {
return false;
}
RuntimeService* runtimeService;
WorkerPrivate* parent;
if (JSVAL_IS_VOID(priv)) {
runtimeService = RuntimeService::GetOrCreateService();
if (!runtimeService) {
JS_ReportError(aCx, "Failed to create runtime service!");
return false;
}
parent = NULL;
}
else {
runtimeService = RuntimeService::GetService();
parent = static_cast<WorkerPrivate*>(JSVAL_TO_PRIVATE(priv));
parent->AssertIsOnWorkerThread();
}
JSObject* obj = JS_NewObject(aCx, &sClass, nsnull, nsnull);
if (!obj) {
return false;
}
WorkerPrivate* worker = WorkerPrivate::Create(aCx, obj, parent, scriptURL,
aIsChromeWorker);
if (!worker) {
return false;
}
// Worker now owned by the JS object.
SetJSPrivateSafeish(aCx, obj, worker);
if (!runtimeService->RegisterWorker(aCx, worker)) {
return false;
}
JS_SET_RVAL(aCx, aVp, OBJECT_TO_JSVAL(obj));
return true;
}
private:
// No instance of this class should ever be created so these are explicitly
// left without an implementation to prevent linking in case someone tries to
// make one.
Worker();
~Worker();
static JSBool
GetEventListener(JSContext* aCx, JSObject* aObj, jsid aIdval, jsval* aVp)
{
JS_ASSERT(JSID_IS_INT(aIdval));
JS_ASSERT(JSID_TO_INT(aIdval) >= 0 && JSID_TO_INT(aIdval) < STRING_COUNT);
const char* name = sEventStrings[JSID_TO_INT(aIdval)];
WorkerPrivate* worker = GetInstancePrivate(aCx, aObj, name);
if (!worker) {
return false;
}
return worker->GetEventListenerOnEventTarget(aCx, name + 2, aVp);
}
static JSBool
SetEventListener(JSContext* aCx, JSObject* aObj, jsid aIdval, JSBool aStrict,
jsval* aVp)
{
JS_ASSERT(JSID_IS_INT(aIdval));
JS_ASSERT(JSID_TO_INT(aIdval) >= 0 && JSID_TO_INT(aIdval) < STRING_COUNT);
const char* name = sEventStrings[JSID_TO_INT(aIdval)];
WorkerPrivate* worker = GetInstancePrivate(aCx, aObj, name);
if (!worker) {
return false;
}
return worker->SetEventListenerOnEventTarget(aCx, name + 2, aVp);
}
static JSBool
Construct(JSContext* aCx, uintN aArgc, jsval* aVp)
{
return ConstructInternal(aCx, aArgc, aVp, false);
}
static void
Finalize(JSContext* aCx, JSObject* aObj)
{
JS_ASSERT(JS_GET_CLASS(aCx, aObj) == &sClass);
WorkerPrivate* worker = GetJSPrivateSafeish<WorkerPrivate>(aCx, aObj);
if (worker) {
worker->FinalizeInstance(aCx);
}
}
static void
Trace(JSTracer* aTrc, JSObject* aObj)
{
JS_ASSERT(JS_GET_CLASS(aTrc->context, aObj) == &sClass);
WorkerPrivate* worker =
GetJSPrivateSafeish<WorkerPrivate>(aTrc->context, aObj);
if (worker) {
worker->TraceInstance(aTrc);
}
}
static JSBool
Terminate(JSContext* aCx, uintN aArgc, jsval* aVp)
{
JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
const char*& name = sFunctions[0].name;
WorkerPrivate* worker = GetInstancePrivate(aCx, obj, name);
if (!worker) {
return false;
}
return worker->Terminate(aCx);
}
static JSBool
PostMessage(JSContext* aCx, uintN aArgc, jsval* aVp)
{
JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
const char*& name = sFunctions[1].name;
WorkerPrivate* worker = GetInstancePrivate(aCx, obj, name);
if (!worker) {
return false;
}
jsval message;
if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "v", &message)) {
return false;
}
return worker->PostMessage(aCx, message);
}
};
JSClass Worker::sClass = {
"Worker",
JSCLASS_HAS_PRIVATE,
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Finalize, NULL, NULL, NULL,
NULL, NULL, NULL, Trace, NULL
};
JSPropertySpec Worker::sProperties[] = {
{ sEventStrings[STRING_onerror], STRING_onerror, PROPERTY_FLAGS,
GetEventListener, SetEventListener },
{ sEventStrings[STRING_onmessage], STRING_onmessage, PROPERTY_FLAGS,
GetEventListener, SetEventListener },
{ 0, 0, 0, NULL, NULL }
};
JSFunctionSpec Worker::sFunctions[] = {
JS_FN("terminate", Terminate, 0, FUNCTION_FLAGS),
JS_FN("postMessage", PostMessage, 1, FUNCTION_FLAGS),
JS_FS_END
};
const char* const Worker::sEventStrings[STRING_COUNT] = {
"onerror",
"onmessage"
};
class ChromeWorker : public Worker
{
static JSClass sClass;
public:
static JSClass*
Class()
{
return &sClass;
}
static JSObject*
InitClass(JSContext* aCx, JSObject* aObj, JSObject* aParentProto,
bool aMainRuntime)
{
JSObject* proto = JS_InitClass(aCx, aObj, aParentProto, &sClass, Construct,
0, NULL, NULL, NULL, NULL);
if (!proto) {
return NULL;
}
if (!aMainRuntime) {
WorkerPrivate* parent = GetWorkerPrivateFromContext(aCx);
parent->AssertIsOnWorkerThread();
JSObject* constructor = JS_GetConstructor(aCx, proto);
if (!constructor ||
!JS_SetReservedSlot(aCx, constructor, CONSTRUCTOR_SLOT_PARENT,
PRIVATE_TO_JSVAL(parent))) {
return NULL;
}
}
return proto;
}
private:
// No instance of this class should ever be created so these are explicitly
// left without an implementation to prevent linking in case someone tries to
// make one.
ChromeWorker();
~ChromeWorker();
static WorkerPrivate*
GetInstancePrivate(JSContext* aCx, JSObject* aObj, const char* aFunctionName)
{
if (aObj) {
JSClass* classPtr = JS_GET_CLASS(aCx, aObj);
if (classPtr == &sClass) {
return GetJSPrivateSafeish<WorkerPrivate>(aCx, aObj);
}
}
return Worker::GetInstancePrivate(aCx, aObj, aFunctionName);
}
static JSBool
Construct(JSContext* aCx, uintN aArgc, jsval* aVp)
{
return ConstructInternal(aCx, aArgc, aVp, true);
}
static void
Finalize(JSContext* aCx, JSObject* aObj)
{
JS_ASSERT(JS_GET_CLASS(aCx, aObj) == &sClass);
WorkerPrivate* worker = GetJSPrivateSafeish<WorkerPrivate>(aCx, aObj);
if (worker) {
worker->FinalizeInstance(aCx);
}
}
static void
Trace(JSTracer* aTrc, JSObject* aObj)
{
JS_ASSERT(JS_GET_CLASS(aTrc->context, aObj) == &sClass);
WorkerPrivate* worker =
GetJSPrivateSafeish<WorkerPrivate>(aTrc->context, aObj);
if (worker) {
worker->TraceInstance(aTrc);
}
}
};
JSClass ChromeWorker::sClass = {
"ChromeWorker",
JSCLASS_HAS_PRIVATE,
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Finalize, NULL, NULL, NULL,
NULL, NULL, NULL, Trace, NULL
};
WorkerPrivate*
Worker::GetInstancePrivate(JSContext* aCx, JSObject* aObj,
const char* aFunctionName)
{
JSClass* classPtr = NULL;
if (aObj) {
classPtr = JS_GET_CLASS(aCx, aObj);
if (classPtr == &sClass || classPtr == ChromeWorker::Class()) {
return GetJSPrivateSafeish<WorkerPrivate>(aCx, aObj);
}
}
JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL, JSMSG_INCOMPATIBLE_PROTO,
sClass.name, aFunctionName,
classPtr ? classPtr->name : "object");
return NULL;
}
} // anonymous namespace
BEGIN_WORKERS_NAMESPACE
namespace worker {
JSObject*
InitClass(JSContext* aCx, JSObject* aGlobal, JSObject* aProto,
bool aMainRuntime)
{
return Worker::InitClass(aCx, aGlobal, aProto, aMainRuntime);
}
} // namespace worker
namespace chromeworker {
bool
InitClass(JSContext* aCx, JSObject* aGlobal, JSObject* aProto,
bool aMainRuntime)
{
return !!ChromeWorker::InitClass(aCx, aGlobal, aProto, aMainRuntime);
}
} // namespace chromeworker
END_WORKERS_NAMESPACE

66
dom/workers/Worker.h Normal file
Просмотреть файл

@ -0,0 +1,66 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Web Workers.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef mozilla_dom_workers_worker_h__
#define mozilla_dom_workers_worker_h__
#include "Workers.h"
#include "jspubtd.h"
BEGIN_WORKERS_NAMESPACE
namespace worker {
JSObject*
InitClass(JSContext* aCx, JSObject* aGlobal, JSObject* aProto,
bool aMainRuntime);
} // namespace worker
namespace chromeworker {
bool
InitClass(JSContext* aCx, JSObject* aGlobal, JSObject* aProto,
bool aMainRuntime);
} // namespace chromeworker
END_WORKERS_NAMESPACE
#endif /* mozilla_dom_workers_worker_h__ */

113
dom/workers/WorkerFeature.h Normal file
Просмотреть файл

@ -0,0 +1,113 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Web Workers.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef mozilla_dom_workers_workerfeature_h__
#define mozilla_dom_workers_workerfeature_h__
#include "Workers.h"
#include "jspubtd.h"
BEGIN_WORKERS_NAMESPACE
/**
* Use this chart to help figure out behavior during each of the closing
* statuses. Details below.
*
* +==============================================================+
* | Closing Statuses |
* +=============+=============+=================+================+
* | status | clear queue | abort execution | close handler |
* +=============+=============+=================+================+
* | Closing | yes | no | no timeout |
* +-------------+-------------+-----------------+----------------+
* | Terminating | yes | yes | no timeout |
* +-------------+-------------+-----------------+----------------+
* | Canceling | yes | yes | short duration |
* +-------------+-------------+-----------------+----------------+
* | Killing | yes | yes | doesn't run |
* +-------------+-------------+-----------------+----------------+
*/
enum Status
{
// Not yet scheduled.
Pending = 0,
// This status means that the close handler has not yet been scheduled.
Running,
// Inner script called close() on the worker global scope. Setting this
// status causes the worker to clear its queue of events but does not abort
// the currently running script. The close handler is also scheduled with
// no expiration time.
Closing,
// Outer script called terminate() on the worker or the worker object was
// garbage collected in its outer script. Setting this status causes the
// worker to abort immediately, clear its queue of events, and schedules the
// close handler with no expiration time.
Terminating,
// Either the user navigated away from the owning page or the owning page fell
// out of bfcache. Setting this status causes the worker to abort immediately
// and schedules the close handler with a short expiration time. Since the
// page has gone away the worker may not post any messages.
Canceling,
// The application is shutting down. Setting this status causes the worker to
// abort immediately and the close handler is never scheduled.
Killing,
// The close handler has run and the worker is effectively dead.
Dead
};
class WorkerFeature
{
public:
virtual ~WorkerFeature() { }
virtual bool Suspend(JSContext* aCx) { return true; }
virtual bool Resume(JSContext* aCx) { return true; }
virtual bool Notify(JSContext* aCx, Status aStatus) = 0;
};
END_WORKERS_NAMESPACE
#endif /* mozilla_dom_workers_workerfeature_h__ */

Просмотреть файл

@ -1,4 +1,4 @@
/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- */
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
@ -12,11 +12,11 @@
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is worker threads.
* The Original Code is Web Workers.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2008
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
@ -36,22 +36,22 @@
*
* ***** END LICENSE BLOCK ***** */
#ifndef __NSDOMWORKERNAVIGATOR_H__
#define __NSDOMWORKERNAVIGATOR_H__
BEGIN_WORKERS_NAMESPACE
#include "nsIClassInfo.h"
#include "nsIDOMWorkers.h"
#include "nsIXPCScriptable.h"
class nsDOMWorkerNavigator : public nsIWorkerNavigator,
public nsIClassInfo,
public nsIXPCScriptable
inline
JSBool
SetJSPrivateSafeish(JSContext* aCx, JSObject* aObj, PrivatizableBase* aBase)
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIWORKERNAVIGATOR
NS_DECL_NSICLASSINFO
NS_DECL_NSIXPCSCRIPTABLE
};
return JS_SetPrivate(aCx, aObj, aBase);
}
#endif /* __NSDOMWORKERNAVIGATOR_H__ */
template <class Derived>
inline
Derived*
GetJSPrivateSafeish(JSContext* aCx, JSObject* aObj)
{
return static_cast<Derived*>(
static_cast<PrivatizableBase*>(JS_GetPrivate(aCx, aObj)));
}
END_WORKERS_NAMESPACE

Разница между файлами не показана из-за своего большого размера Загрузить разницу

729
dom/workers/WorkerPrivate.h Normal file
Просмотреть файл

@ -0,0 +1,729 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Web Workers.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef mozilla_dom_workers_workerprivate_h__
#define mozilla_dom_workers_workerprivate_h__
#include "Workers.h"
#include "nsIRunnable.h"
#include "nsIThread.h"
#include "nsIThreadInternal.h"
#include "jsapi.h"
#include "mozilla/CondVar.h"
#include "mozilla/Mutex.h"
#include "mozilla/TimeStamp.h"
#include "nsAutoPtr.h"
#include "nsCOMPtr.h"
#include "nsEventQueue.h"
#include "nsStringGlue.h"
#include "nsTArray.h"
#include "nsTPriorityQueue.h"
#include "EventTarget.h"
#include "Queue.h"
#include "WorkerFeature.h"
class JSAutoStructuredCloneBuffer;
class nsIDocument;
class nsIPrincipal;
class nsIScriptContext;
class nsIURI;
class nsPIDOMWindow;
class nsITimer;
BEGIN_WORKERS_NAMESPACE
class WorkerPrivate;
class WorkerRunnable : public nsIRunnable
{
public:
enum Target { ParentThread, WorkerThread };
enum BusyBehavior { ModifyBusyCount, UnchangedBusyCount };
protected:
WorkerPrivate* mWorkerPrivate;
Target mTarget;
bool mBusyBehavior;
public:
NS_DECL_ISUPPORTS
bool
Dispatch(JSContext* aCx);
static bool
DispatchToMainThread(nsIRunnable*);
protected:
WorkerRunnable(WorkerPrivate* aWorkerPrivate, Target aTarget,
BusyBehavior aBusyBehavior)
#ifdef DEBUG
;
#else
: mWorkerPrivate(aWorkerPrivate), mTarget(aTarget),
mBusyBehavior(aBusyBehavior)
{ }
#endif
virtual ~WorkerRunnable()
{ }
virtual bool
PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate);
virtual void
PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
bool aDispatchResult);
virtual bool
DispatchInternal();
virtual bool
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) = 0;
virtual void
PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate, bool aRunResult);
private:
NS_DECL_NSIRUNNABLE
};
class WorkerSyncRunnable : public WorkerRunnable
{
protected:
PRUint32 mSyncQueueKey;
bool mBypassSyncQueue;
protected:
friend class WorkerPrivate;
WorkerSyncRunnable(WorkerPrivate* aWorkerPrivate, PRUint32 aSyncQueueKey,
bool aBypassSyncQueue = false)
: WorkerRunnable(aWorkerPrivate, WorkerThread, UnchangedBusyCount),
mSyncQueueKey(aSyncQueueKey), mBypassSyncQueue(aBypassSyncQueue)
{ }
virtual ~WorkerSyncRunnable()
{ }
virtual bool
DispatchInternal();
};
class WorkerControlRunnable : public WorkerRunnable
{
protected:
WorkerControlRunnable(WorkerPrivate* aWorkerPrivate, Target aTarget,
BusyBehavior aBusyBehavior)
: WorkerRunnable(aWorkerPrivate, aTarget, aBusyBehavior)
{ }
virtual ~WorkerControlRunnable()
{ }
virtual bool
DispatchInternal();
};
template <class Derived>
class WorkerPrivateParent : public events::EventTarget
{
public:
struct LocationInfo
{
nsCString mHref;
nsCString mProtocol;
nsCString mHost;
nsCString mHostname;
nsCString mPort;
nsCString mPathname;
nsCString mSearch;
nsCString mHash;
};
protected:
mozilla::Mutex mMutex;
mozilla::CondVar mCondVar;
private:
JSObject* mJSObject;
WorkerPrivate* mParent;
JSContext* mParentJSContext;
nsString mScriptURL;
nsCString mDomain;
LocationInfo mLocationInfo;
// Main-thread things.
nsCOMPtr<nsPIDOMWindow> mWindow;
nsCOMPtr<nsIScriptContext> mScriptContext;
nsCOMPtr<nsIURI> mBaseURI;
nsCOMPtr<nsIURI> mScriptURI;
nsCOMPtr<nsIPrincipal> mPrincipal;
nsCOMPtr<nsIDocument> mDocument;
// Only used for top level workers.
nsTArray<nsRefPtr<WorkerRunnable> > mQueuedRunnables;
PRUint64 mBusyCount;
Status mParentStatus;
PRUint32 mJSContextOptions;
PRUint8 mGCZeal;
bool mJSObjectRooted;
bool mParentSuspended;
bool mIsChromeWorker;
protected:
WorkerPrivateParent(JSContext* aCx, JSObject* aObject, WorkerPrivate* aParent,
JSContext* aParentJSContext, const nsAString& aScriptURL,
bool aIsChromeWorker, const nsACString& aDomain,
nsCOMPtr<nsPIDOMWindow>& aWindow,
nsCOMPtr<nsIScriptContext>& aScriptContext,
nsCOMPtr<nsIURI>& aBaseURI,
nsCOMPtr<nsIPrincipal>& aPrincipal,
nsCOMPtr<nsIDocument>& aDocument);
~WorkerPrivateParent();
private:
Derived*
ParentAsWorkerPrivate() const
{
return static_cast<Derived*>(const_cast<WorkerPrivateParent*>(this));
}
public:
// May be called on any thread...
bool
Start();
// Called on the parent thread.
bool
Notify(JSContext* aCx, Status aStatus);
bool
Cancel(JSContext* aCx)
{
return Notify(aCx, Canceling);
}
bool
Kill(JSContext* aCx)
{
return Notify(aCx, Killing);
}
bool
Suspend(JSContext* aCx);
bool
Resume(JSContext* aCx);
void
TraceInstance(JSTracer* aTrc)
{
AssertIsOnParentThread();
events::EventTarget::TraceInstance(aTrc);
}
void
FinalizeInstance(JSContext* aCx);
bool
Terminate(JSContext* aCx)
{
return Notify(aCx, Terminating);
}
bool
Close(JSContext* aCx);
bool
ModifyBusyCount(JSContext* aCx, bool aIncrease);
bool
RootJSObject(JSContext* aCx, bool aRoot);
void
ForgetMainThreadObjects(nsTArray<nsCOMPtr<nsISupports> >& aDoomed);
bool
PostMessage(JSContext* aCx, jsval aMessage);
PRUint64
GetOuterWindowId();
void
UpdateJSContextOptions(JSContext* aCx, PRUint32 aOptions);
#ifdef JS_GC_ZEAL
void
UpdateGCZeal(JSContext* aCx, PRUint8 aGCZeal);
#endif
using events::EventTarget::GetEventListenerOnEventTarget;
using events::EventTarget::SetEventListenerOnEventTarget;
void
QueueRunnable(WorkerRunnable* aRunnable)
{
AssertIsOnMainThread();
mQueuedRunnables.AppendElement(aRunnable);
}
WorkerPrivate*
GetParent() const
{
return mParent;
}
bool
IsSuspended() const
{
AssertIsOnParentThread();
return mParentSuspended;
}
Status
ParentStatus() const
{
mMutex.AssertCurrentThreadOwns();
return mParentStatus;
}
JSContext*
ParentJSContext() const;
nsIScriptContext*
GetScriptContext() const
{
AssertIsOnMainThread();
return mScriptContext;
}
JSObject*
GetJSObject() const
{
return mJSObject;
}
const nsString&
ScriptURL() const
{
return mScriptURL;
}
const nsCString&
Domain() const
{
return mDomain;
}
nsIURI*
GetBaseURI() const
{
AssertIsOnMainThread();
return mBaseURI;
}
nsresult
SetBaseURI(nsIURI* aBaseURI);
nsIURI*
GetScriptURI() const
{
AssertIsOnMainThread();
return mScriptURI;
}
void
SetScriptURI(nsIURI* aScriptURI)
{
AssertIsOnMainThread();
mScriptURI = aScriptURI;
}
nsIPrincipal*
GetPrincipal() const
{
AssertIsOnMainThread();
return mPrincipal;
}
void
SetPrincipal(nsIPrincipal* aPrincipal)
{
AssertIsOnMainThread();
mPrincipal = aPrincipal;
}
nsIDocument*
GetDocument() const
{
AssertIsOnMainThread();
return mDocument;
}
void
SetDocument(nsIDocument* aDocument)
{
AssertIsOnMainThread();
mDocument = aDocument;
}
nsPIDOMWindow*
GetWindow()
{
AssertIsOnMainThread();
return mWindow;
}
LocationInfo&
GetLocationInfo()
{
return mLocationInfo;
}
PRUint32
GetJSContextOptions() const
{
return mJSContextOptions;
}
#ifdef JS_GC_ZEAL
PRUint8
GetGCZeal() const
{
return mGCZeal;
}
#endif
bool
IsChromeWorker() const
{
return mIsChromeWorker;
}
#ifdef DEBUG
void
AssertIsOnParentThread() const;
void
AssertInnerWindowIsCorrect() const;
#else
void
AssertIsOnParentThread() const
{ }
void
AssertInnerWindowIsCorrect() const
{ }
#endif
};
class WorkerPrivate : public WorkerPrivateParent<WorkerPrivate>
{
friend class WorkerPrivateParent<WorkerPrivate>;
typedef WorkerPrivateParent<WorkerPrivate> ParentType;
struct TimeoutInfo;
typedef Queue<nsIRunnable*, 50> EventQueue;
EventQueue mQueue;
EventQueue mControlQueue;
struct SyncQueue
{
Queue<nsIRunnable*, 10> mQueue;
bool mComplete;
bool mResult;
SyncQueue()
: mComplete(false), mResult(false)
{ }
~SyncQueue()
{
nsIRunnable* event;
while (mQueue.Pop(event)) {
event->Release();
}
}
};
nsTArray<nsAutoPtr<SyncQueue> > mSyncQueues;
// Touched on multiple threads, protected with mMutex.
JSContext* mJSContext;
// Things touched on worker thread only.
nsTArray<ParentType*> mChildWorkers;
nsTArray<WorkerFeature*> mFeatures;
nsTArray<nsAutoPtr<TimeoutInfo> > mTimeouts;
nsCOMPtr<nsITimer> mTimer;
mozilla::TimeStamp mKillTime;
PRUint32 mErrorHandlerRecursionCount;
PRUint32 mNextTimeoutId;
Status mStatus;
bool mSuspended;
bool mTimerRunning;
bool mRunningExpiredTimeouts;
bool mCloseHandlerStarted;
bool mCloseHandlerFinished;
#ifdef DEBUG
nsCOMPtr<nsIThread> mThread;
#endif
public:
~WorkerPrivate();
static WorkerPrivate*
Create(JSContext* aCx, JSObject* aObj, WorkerPrivate* aParent,
JSString* aScriptURL, bool aIsChromeWorker);
void
DoRunLoop(JSContext* aCx);
bool
OperationCallback(JSContext* aCx);
bool
Dispatch(WorkerRunnable* aEvent)
{
return Dispatch(aEvent, &mQueue);
}
bool
Dispatch(WorkerSyncRunnable* aEvent)
{
if (aEvent->mBypassSyncQueue) {
return Dispatch(aEvent, &mQueue);
}
return DispatchToSyncQueue(aEvent);
}
bool
Dispatch(WorkerControlRunnable* aEvent)
{
return Dispatch(aEvent, &mControlQueue);
}
bool
CloseInternal(JSContext* aCx)
{
AssertIsOnWorkerThread();
return NotifyInternal(aCx, Closing);
}
bool
SuspendInternal(JSContext* aCx);
bool
ResumeInternal(JSContext* aCx);
void
TraceInternal(JSTracer* aTrc);
bool
ModifyBusyCountFromWorker(JSContext* aCx, bool aIncrease);
bool
AddChildWorker(JSContext* aCx, ParentType* aChildWorker);
void
RemoveChildWorker(JSContext* aCx, ParentType* aChildWorker);
bool
AddFeature(JSContext* aCx, WorkerFeature* aFeature);
void
RemoveFeature(JSContext* aCx, WorkerFeature* aFeature);
void
NotifyFeatures(JSContext* aCx, Status aStatus);
bool
HasActiveFeatures()
{
return !(mChildWorkers.IsEmpty() && mTimeouts.IsEmpty() &&
mFeatures.IsEmpty());
}
PRUint32
CreateNewSyncLoop();
bool
RunSyncLoop(JSContext* aCx, PRUint32 aSyncLoopKey);
void
StopSyncLoop(PRUint32 aSyncLoopKey, bool aSyncResult);
bool
PostMessageToParent(JSContext* aCx, jsval aMessage);
bool
NotifyInternal(JSContext* aCx, Status aStatus);
void
ReportError(JSContext* aCx, const char* aMessage, JSErrorReport* aReport);
bool
SetTimeout(JSContext* aCx, uintN aArgc, jsval* aVp, bool aIsInterval);
bool
ClearTimeout(JSContext* aCx, uint32 aId);
bool
RunExpiredTimeouts(JSContext* aCx);
bool
RescheduleTimeoutTimer(JSContext* aCx);
void
CloseHandlerStarted()
{
AssertIsOnWorkerThread();
mCloseHandlerStarted = true;
}
void
CloseHandlerFinished()
{
AssertIsOnWorkerThread();
mCloseHandlerFinished = true;
}
void
UpdateJSContextOptionsInternal(JSContext* aCx, PRUint32 aOptions);
void
ScheduleDeletion();
#ifdef JS_GC_ZEAL
void
UpdateGCZealInternal(JSContext* aCx, PRUint8 aGCZeal);
#endif
JSContext*
GetJSContext() const
{
AssertIsOnWorkerThread();
return mJSContext;
}
#ifdef DEBUG
void
AssertIsOnWorkerThread() const;
void
SetThread(nsIThread* aThread)
{
mThread = aThread;
}
#else
void
AssertIsOnWorkerThread() const
{ }
#endif
private:
WorkerPrivate(JSContext* aCx, JSObject* aObject, WorkerPrivate* aParent,
JSContext* aParentJSContext, const nsAString& aScriptURL,
bool aIsChromeWorker, const nsACString& aDomain,
nsCOMPtr<nsPIDOMWindow>& aWindow,
nsCOMPtr<nsIScriptContext>& aScriptContext,
nsCOMPtr<nsIURI>& aBaseURI, nsCOMPtr<nsIPrincipal>& aPrincipal,
nsCOMPtr<nsIDocument>& aDocument);
bool
Dispatch(WorkerRunnable* aEvent, EventQueue* aQueue);
bool
DispatchToSyncQueue(WorkerSyncRunnable* aEvent);
void
ClearQueue(EventQueue* aQueue);
bool
MayContinueRunning()
{
AssertIsOnWorkerThread();
Status status;
{
mozilla::MutexAutoLock lock(mMutex);
status = mStatus;
}
if (status >= Killing) {
return false;
}
if (status >= Running) {
return mKillTime.IsNull() || RemainingRunTimeMS() > 0;
}
return true;
}
PRUint32
RemainingRunTimeMS() const;
void
CancelAllTimeouts(JSContext* aCx);
bool
ScheduleKillCloseEventRunnable(JSContext* aCx);
};
WorkerPrivate*
GetWorkerPrivateFromContext(JSContext* aCx);
JSStructuredCloneCallbacks*
WorkerStructuredCloneCallbacks();
JSStructuredCloneCallbacks*
ChromeWorkerStructuredCloneCallbacks();
END_WORKERS_NAMESPACE
#endif /* mozilla_dom_workers_workerprivate_h__ */

892
dom/workers/WorkerScope.cpp Normal file
Просмотреть файл

@ -0,0 +1,892 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Web Workers.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "WorkerScope.h"
#include "jsapi.h"
#include "jscntxt.h"
#include "jsobj.h"
#include "nsTraceRefcnt.h"
#include "xpcprivate.h"
#include "ChromeWorkerScope.h"
#include "Events.h"
#include "EventTarget.h"
#include "Exceptions.h"
#include "ListenerManager.h"
#include "Location.h"
#include "Navigator.h"
#include "Principal.h"
#include "ScriptLoader.h"
#include "Worker.h"
#include "WorkerPrivate.h"
#include "XMLHttpRequest.h"
#include "WorkerInlines.h"
#define PROPERTY_FLAGS \
JSPROP_ENUMERATE | JSPROP_SHARED
#define FUNCTION_FLAGS \
JSPROP_ENUMERATE
USING_WORKERS_NAMESPACE
namespace {
class WorkerGlobalScope : public events::EventTarget
{
static JSClass sClass;
static JSPropertySpec sProperties[];
static JSFunctionSpec sFunctions[];
enum
{
SLOT_wrappedScope = 0,
SLOT_wrappedFunction
};
enum
{
SLOT_location = 0,
SLOT_navigator,
SLOT_COUNT
};
// Must be traced!
jsval mSlots[SLOT_COUNT];
enum
{
STRING_onerror = 0,
STRING_onclose,
STRING_COUNT
};
static const char* const sEventStrings[STRING_COUNT];
protected:
WorkerPrivate* mWorker;
public:
static JSClass*
Class()
{
return &sClass;
}
static JSObject*
InitClass(JSContext* aCx, JSObject* aObj, JSObject* aParentProto)
{
return JS_InitClass(aCx, aObj, aParentProto, &sClass, Construct, 0,
sProperties, sFunctions, NULL, NULL);
}
protected:
WorkerGlobalScope(WorkerPrivate* aWorker)
: mWorker(aWorker)
{
MOZ_COUNT_CTOR(mozilla::dom::workers::WorkerGlobalScope);
for (int32 i = 0; i < SLOT_COUNT; i++) {
mSlots[i] = JSVAL_VOID;
}
}
~WorkerGlobalScope()
{
MOZ_COUNT_DTOR(mozilla::dom::workers::WorkerGlobalScope);
}
void
TraceInstance(JSTracer* aTrc)
{
for (int32 i = 0; i < SLOT_COUNT; i++) {
JS_CALL_VALUE_TRACER(aTrc, mSlots[i], "WorkerGlobalScope instance slot");
}
mWorker->TraceInternal(aTrc);
events::EventTarget::TraceInstance(aTrc);
}
void
FinalizeInstance(JSContext* aCx)
{
events::EventTarget::FinalizeInstance(aCx);
}
private:
static JSBool
GetEventListener(JSContext* aCx, JSObject* aObj, jsid aIdval, jsval* aVp)
{
JS_ASSERT(JSID_IS_INT(aIdval));
JS_ASSERT(JSID_TO_INT(aIdval) >= 0 && JSID_TO_INT(aIdval) < STRING_COUNT);
const char* name = sEventStrings[JSID_TO_INT(aIdval)];
WorkerGlobalScope* scope = GetInstancePrivate(aCx, aObj, name);
if (!scope) {
return false;
}
return scope->GetEventListenerOnEventTarget(aCx, name + 2, aVp);
}
static JSBool
SetEventListener(JSContext* aCx, JSObject* aObj, jsid aIdval, JSBool aStrict,
jsval* aVp)
{
JS_ASSERT(JSID_IS_INT(aIdval));
JS_ASSERT(JSID_TO_INT(aIdval) >= 0 && JSID_TO_INT(aIdval) < STRING_COUNT);
const char* name = sEventStrings[JSID_TO_INT(aIdval)];
WorkerGlobalScope* scope = GetInstancePrivate(aCx, aObj, name);
if (!scope) {
return false;
}
return scope->SetEventListenerOnEventTarget(aCx, name + 2, aVp);
}
static WorkerGlobalScope*
GetInstancePrivate(JSContext* aCx, JSObject* aObj, const char* aFunctionName);
static JSBool
Construct(JSContext* aCx, uintN aArgc, jsval* aVp)
{
JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL, JSMSG_WRONG_CONSTRUCTOR,
sClass.name);
return false;
}
static JSBool
GetSelf(JSContext* aCx, JSObject* aObj, jsid aIdval, jsval* aVp)
{
if (!GetInstancePrivate(aCx, aObj, "self")) {
return false;
}
*aVp = OBJECT_TO_JSVAL(aObj);
return true;
}
static JSBool
GetLocation(JSContext* aCx, JSObject* aObj, jsid aIdval, jsval* aVp)
{
WorkerGlobalScope* scope =
GetInstancePrivate(aCx, aObj, sProperties[SLOT_location].name);
if (!scope) {
return false;
}
if (JSVAL_IS_VOID(scope->mSlots[SLOT_location])) {
JSString* href, *protocol, *host, *hostname;
JSString* port, *pathname, *search, *hash;
WorkerPrivate::LocationInfo& info = scope->mWorker->GetLocationInfo();
#define COPY_STRING(_jsstr, _cstr) \
if (info. _cstr .IsEmpty()) { \
_jsstr = NULL; \
} \
else { \
if (!(_jsstr = JS_NewStringCopyN(aCx, info. _cstr .get(), \
info. _cstr .Length()))) { \
return false; \
} \
info. _cstr .Truncate(); \
}
COPY_STRING(href, mHref);
COPY_STRING(protocol, mProtocol);
COPY_STRING(host, mHost);
COPY_STRING(hostname, mHostname);
COPY_STRING(port, mPort);
COPY_STRING(pathname, mPathname);
COPY_STRING(search, mSearch);
COPY_STRING(hash, mHash);
#undef COPY_STRING
JSObject* location = location::Create(aCx, href, protocol, host, hostname,
port, pathname, search, hash);
if (!location) {
return false;
}
scope->mSlots[SLOT_location] = OBJECT_TO_JSVAL(location);
}
*aVp = scope->mSlots[SLOT_location];
return true;
}
static JSBool
UnwrapErrorEvent(JSContext* aCx, uintN aArgc, jsval* aVp)
{
JS_ASSERT(JSVAL_IS_OBJECT(JS_CALLEE(aCx, aVp)));
JS_ASSERT(aArgc == 1);
JS_ASSERT(JSVAL_IS_OBJECT(JS_ARGV(aCx, aVp)[0]));
JSObject* wrapper = JSVAL_TO_OBJECT(JS_CALLEE(aCx, aVp));
JS_ASSERT(JS_ObjectIsFunction(aCx, wrapper));
jsval scope, listener;
if (!JS_GetReservedSlot(aCx, wrapper, SLOT_wrappedScope, &scope) ||
!JS_GetReservedSlot(aCx, wrapper, SLOT_wrappedFunction, &listener)) {
return false;
}
JS_ASSERT(JSVAL_IS_OBJECT(scope));
JSObject* event = JSVAL_TO_OBJECT(JS_ARGV(aCx, aVp)[0]);
jsval argv[3] = { JSVAL_VOID, JSVAL_VOID, JSVAL_VOID };
if (!JS_GetProperty(aCx, event, "message", &argv[0]) ||
!JS_GetProperty(aCx, event, "filename", &argv[1]) ||
!JS_GetProperty(aCx, event, "lineno", &argv[2])) {
return false;
}
jsval rval = JSVAL_VOID;
if (!JS_CallFunctionValue(aCx, JSVAL_TO_OBJECT(scope), listener,
JS_ARRAY_LENGTH(argv), argv, &rval)) {
JS_ReportPendingException(aCx);
return false;
}
if (JSVAL_IS_BOOLEAN(rval) && JSVAL_TO_BOOLEAN(rval) &&
!JS_CallFunctionName(aCx, event, "preventDefault", 0, NULL, &rval)) {
return false;
}
return true;
}
static JSBool
GetOnErrorListener(JSContext* aCx, JSObject* aObj, jsid aIdval, jsval* aVp)
{
const char* name = sEventStrings[STRING_onerror];
WorkerGlobalScope* scope = GetInstancePrivate(aCx, aObj, name);
if (!scope) {
return false;
}
jsval adaptor;
if (!scope->GetEventListenerOnEventTarget(aCx, name + 2, &adaptor)) {
return false;
}
JS_ASSERT(JSVAL_IS_OBJECT(adaptor));
jsval listener;
if (!JS_GetReservedSlot(aCx, JSVAL_TO_OBJECT(adaptor), SLOT_wrappedFunction,
&listener)) {
return false;
}
*aVp = listener;
return true;
}
static JSBool
SetOnErrorListener(JSContext* aCx, JSObject* aObj, jsid aIdval,
JSBool aStrict, jsval* aVp)
{
const char* name = sEventStrings[STRING_onerror];
WorkerGlobalScope* scope = GetInstancePrivate(aCx, aObj, name);
if (!scope) {
return false;
}
JSFunction* adaptor = JS_NewFunction(aCx, UnwrapErrorEvent, 1, 0,
JS_GetGlobalObject(aCx), "unwrap");
if (!adaptor) {
return false;
}
JSObject* listener = JS_GetFunctionObject(adaptor);
if (!listener) {
return false;
}
if (!JS_SetReservedSlot(aCx, listener, SLOT_wrappedScope,
OBJECT_TO_JSVAL(aObj)) ||
!JS_SetReservedSlot(aCx, listener, SLOT_wrappedFunction, *aVp)) {
return false;
}
jsval val = OBJECT_TO_JSVAL(listener);
return scope->SetEventListenerOnEventTarget(aCx, name + 2, &val);
}
static JSBool
GetNavigator(JSContext* aCx, JSObject* aObj, jsid aIdval, jsval* aVp)
{
WorkerGlobalScope* scope =
GetInstancePrivate(aCx, aObj, sProperties[SLOT_navigator].name);
if (!scope) {
return false;
}
if (JSVAL_IS_VOID(scope->mSlots[SLOT_navigator])) {
JSObject* navigator = navigator::Create(aCx);
if (!navigator) {
return false;
}
scope->mSlots[SLOT_navigator] = OBJECT_TO_JSVAL(navigator);
}
*aVp = scope->mSlots[SLOT_navigator];
return true;
}
static JSBool
Close(JSContext* aCx, uintN aArgc, jsval* aVp)
{
JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
WorkerGlobalScope* scope = GetInstancePrivate(aCx, obj, sFunctions[0].name);
if (!scope) {
return false;
}
return scope->mWorker->CloseInternal(aCx);
}
static JSBool
ImportScripts(JSContext* aCx, uintN aArgc, jsval* aVp)
{
JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
WorkerGlobalScope* scope = GetInstancePrivate(aCx, obj, sFunctions[1].name);
if (!scope) {
return false;
}
if (aArgc && !scriptloader::Load(aCx, aArgc, JS_ARGV(aCx, aVp))) {
return false;
}
return true;
}
static JSBool
SetTimeout(JSContext* aCx, uintN aArgc, jsval* aVp)
{
JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
WorkerGlobalScope* scope = GetInstancePrivate(aCx, obj, sFunctions[2].name);
if (!scope) {
return false;
}
jsval dummy;
if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "v", &dummy)) {
return false;
}
return scope->mWorker->SetTimeout(aCx, aArgc, aVp, false);
}
static JSBool
ClearTimeout(JSContext* aCx, uintN aArgc, jsval* aVp)
{
JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
WorkerGlobalScope* scope = GetInstancePrivate(aCx, obj, sFunctions[3].name);
if (!scope) {
return false;
}
uint32 id;
if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "u", &id)) {
return false;
}
return scope->mWorker->ClearTimeout(aCx, id);
}
static JSBool
SetInterval(JSContext* aCx, uintN aArgc, jsval* aVp)
{
JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
WorkerGlobalScope* scope = GetInstancePrivate(aCx, obj, sFunctions[4].name);
if (!scope) {
return false;
}
jsval dummy;
if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "v", &dummy)) {
return false;
}
return scope->mWorker->SetTimeout(aCx, aArgc, aVp, true);
}
static JSBool
ClearInterval(JSContext* aCx, uintN aArgc, jsval* aVp)
{
JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
WorkerGlobalScope* scope = GetInstancePrivate(aCx, obj, sFunctions[5].name);
if (!scope) {
return false;
}
uint32 id;
if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "u", &id)) {
return false;
}
return scope->mWorker->ClearTimeout(aCx, id);
}
static JSBool
Dump(JSContext* aCx, uintN aArgc, jsval* aVp)
{
if (!GetInstancePrivate(aCx, JS_THIS_OBJECT(aCx, aVp),
sFunctions[6].name)) {
return false;
}
if (aArgc) {
JSString* str = JS_ValueToString(aCx, JS_ARGV(aCx, aVp)[0]);
if (!str) {
return false;
}
JSAutoByteString buffer(aCx, str);
if (!buffer) {
return false;
}
fputs(buffer.ptr(), stderr);
fflush(stderr);
}
return true;
}
static JSBool
AtoB(JSContext* aCx, uintN aArgc, jsval* aVp)
{
if (!GetInstancePrivate(aCx, JS_THIS_OBJECT(aCx, aVp),
sFunctions[7].name)) {
return false;
}
jsval string;
if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "v", &string)) {
return false;
}
jsval result;
if (!nsXPConnect::Base64Decode(aCx, string, &result)) {
return false;
}
JS_SET_RVAL(aCx, aVp, result);
return true;
}
static JSBool
BtoA(JSContext* aCx, uintN aArgc, jsval* aVp)
{
if (!GetInstancePrivate(aCx, JS_THIS_OBJECT(aCx, aVp),
sFunctions[8].name)) {
return false;
}
jsval binary;
if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "v", &binary)) {
return false;
}
jsval result;
if (!nsXPConnect::Base64Encode(aCx, binary, &result)) {
return false;
}
JS_SET_RVAL(aCx, aVp, result);
return true;
}
};
JSClass WorkerGlobalScope::sClass = {
"WorkerGlobalScope",
0,
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
JSCLASS_NO_OPTIONAL_MEMBERS
};
JSPropertySpec WorkerGlobalScope::sProperties[] = {
{ "location", SLOT_location, PROPERTY_FLAGS, GetLocation,
js_GetterOnlyPropertyStub },
{ sEventStrings[STRING_onerror], STRING_onerror, PROPERTY_FLAGS,
GetOnErrorListener, SetOnErrorListener },
{ sEventStrings[STRING_onclose], STRING_onclose, PROPERTY_FLAGS,
GetEventListener, SetEventListener },
{ "navigator", SLOT_navigator, PROPERTY_FLAGS, GetNavigator,
js_GetterOnlyPropertyStub },
{ "self", 0, PROPERTY_FLAGS, GetSelf, js_GetterOnlyPropertyStub },
{ 0, 0, 0, NULL, NULL }
};
JSFunctionSpec WorkerGlobalScope::sFunctions[] = {
JS_FN("close", Close, 0, FUNCTION_FLAGS),
JS_FN("importScripts", ImportScripts, 1, FUNCTION_FLAGS),
JS_FN("setTimeout", SetTimeout, 1, FUNCTION_FLAGS),
JS_FN("clearTimeout", ClearTimeout, 1, FUNCTION_FLAGS),
JS_FN("setInterval", SetInterval, 1, FUNCTION_FLAGS),
JS_FN("clearInterval", ClearTimeout, 1, FUNCTION_FLAGS),
JS_FN("dump", Dump, 1, FUNCTION_FLAGS),
JS_FN("atob", AtoB, 1, FUNCTION_FLAGS),
JS_FN("btoa", BtoA, 1, FUNCTION_FLAGS),
JS_FS_END
};
const char* const WorkerGlobalScope::sEventStrings[STRING_COUNT] = {
"onerror",
"onclose"
};
class DedicatedWorkerGlobalScope : public WorkerGlobalScope
{
static JSClass sClass;
static JSPropertySpec sProperties[];
static JSFunctionSpec sFunctions[];
enum
{
STRING_onmessage = 0,
STRING_COUNT
};
static const char* const sEventStrings[STRING_COUNT];
public:
static JSClass*
Class()
{
return &sClass;
}
static JSObject*
InitClass(JSContext* aCx, JSObject* aObj, JSObject* aParentProto)
{
return JS_InitClass(aCx, aObj, aParentProto, &sClass, Construct, 0,
sProperties, sFunctions, NULL, NULL);
}
static JSBool
InitPrivate(JSContext* aCx, JSObject* aObj, WorkerPrivate* aWorkerPrivate)
{
JS_ASSERT(JS_GET_CLASS(aCx, aObj) == &sClass);
JS_ASSERT(!GetJSPrivateSafeish<DedicatedWorkerGlobalScope>(aCx, aObj));
DedicatedWorkerGlobalScope* priv =
new DedicatedWorkerGlobalScope(aWorkerPrivate);
if (!SetJSPrivateSafeish(aCx, aObj, priv)) {
delete priv;
return false;
}
return true;
}
protected:
DedicatedWorkerGlobalScope(WorkerPrivate* aWorker)
: WorkerGlobalScope(aWorker)
{
MOZ_COUNT_CTOR(mozilla::dom::workers::DedicatedWorkerGlobalScope);
}
~DedicatedWorkerGlobalScope()
{
MOZ_COUNT_DTOR(mozilla::dom::workers::DedicatedWorkerGlobalScope);
}
using WorkerGlobalScope::TraceInstance;
using WorkerGlobalScope::FinalizeInstance;
private:
static JSBool
GetEventListener(JSContext* aCx, JSObject* aObj, jsid aIdval, jsval* aVp)
{
JS_ASSERT(JSID_IS_INT(aIdval));
JS_ASSERT(JSID_TO_INT(aIdval) >= 0 && JSID_TO_INT(aIdval) < STRING_COUNT);
const char* name = sEventStrings[JSID_TO_INT(aIdval)];
DedicatedWorkerGlobalScope* scope = GetInstancePrivate(aCx, aObj, name);
if (!scope) {
return false;
}
return scope->GetEventListenerOnEventTarget(aCx, name + 2, aVp);
}
static JSBool
SetEventListener(JSContext* aCx, JSObject* aObj, jsid aIdval, JSBool aStrict,
jsval* aVp)
{
JS_ASSERT(JSID_IS_INT(aIdval));
JS_ASSERT(JSID_TO_INT(aIdval) >= 0 && JSID_TO_INT(aIdval) < STRING_COUNT);
const char* name = sEventStrings[JSID_TO_INT(aIdval)];
DedicatedWorkerGlobalScope* scope = GetInstancePrivate(aCx, aObj, name);
if (!scope) {
return false;
}
return scope->SetEventListenerOnEventTarget(aCx, name + 2, aVp);
}
static DedicatedWorkerGlobalScope*
GetInstancePrivate(JSContext* aCx, JSObject* aObj, const char* aFunctionName)
{
// JS_GetInstancePrivate is ok to be called with a null aObj, so this should
// be too.
JSClass* classPtr = NULL;
if (aObj) {
classPtr = JS_GET_CLASS(aCx, aObj);
if (classPtr == &sClass) {
return GetJSPrivateSafeish<DedicatedWorkerGlobalScope>(aCx, aObj);
}
}
JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL,
JSMSG_INCOMPATIBLE_PROTO, sClass.name, aFunctionName,
classPtr ? classPtr->name : "object");
return NULL;
}
static JSBool
Construct(JSContext* aCx, uintN aArgc, jsval* aVp)
{
JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL, JSMSG_WRONG_CONSTRUCTOR,
sClass.name);
return false;
}
static JSBool
Resolve(JSContext* aCx, JSObject* aObj, jsid aId, uintN aFlags,
JSObject** aObjp)
{
JSBool resolved;
if (!JS_ResolveStandardClass(aCx, aObj, aId, &resolved)) {
return false;
}
*aObjp = resolved ? aObj : NULL;
return true;
}
static void
Finalize(JSContext* aCx, JSObject* aObj)
{
JS_ASSERT(JS_GET_CLASS(aCx, aObj) == &sClass);
DedicatedWorkerGlobalScope* scope =
GetJSPrivateSafeish<DedicatedWorkerGlobalScope>(aCx, aObj);
if (scope) {
scope->FinalizeInstance(aCx);
delete scope;
}
}
static void
Trace(JSTracer* aTrc, JSObject* aObj)
{
JS_ASSERT(JS_GET_CLASS(aTrc->context, aObj) == &sClass);
DedicatedWorkerGlobalScope* scope =
GetJSPrivateSafeish<DedicatedWorkerGlobalScope>(aTrc->context, aObj);
if (scope) {
scope->TraceInstance(aTrc);
}
}
static JSBool
PostMessage(JSContext* aCx, uintN aArgc, jsval* aVp)
{
JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
const char*& name = sFunctions[0].name;
DedicatedWorkerGlobalScope* scope = GetInstancePrivate(aCx, obj, name);
if (!scope) {
return false;
}
jsval message;
if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "v", &message)) {
return false;
}
return scope->mWorker->PostMessageToParent(aCx, message);
}
};
JSClass DedicatedWorkerGlobalScope::sClass = {
"DedicatedWorkerGlobalScope",
JSCLASS_GLOBAL_FLAGS | JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE,
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
JS_EnumerateStub, reinterpret_cast<JSResolveOp>(Resolve), JS_ConvertStub,
Finalize, NULL, NULL, NULL, NULL, NULL, NULL, Trace, NULL
};
JSPropertySpec DedicatedWorkerGlobalScope::sProperties[] = {
{ sEventStrings[STRING_onmessage], STRING_onmessage, PROPERTY_FLAGS,
GetEventListener, SetEventListener },
{ 0, 0, 0, NULL, NULL }
};
JSFunctionSpec DedicatedWorkerGlobalScope::sFunctions[] = {
JS_FN("postMessage", PostMessage, 1, FUNCTION_FLAGS),
JS_FS_END
};
const char* const DedicatedWorkerGlobalScope::sEventStrings[STRING_COUNT] = {
"onmessage",
};
WorkerGlobalScope*
WorkerGlobalScope::GetInstancePrivate(JSContext* aCx, JSObject* aObj,
const char* aFunctionName)
{
// JS_GetInstancePrivate is ok to be called with a null aObj, so this should
// be too.
JSClass* classPtr = NULL;
if (aObj) {
classPtr = JS_GET_CLASS(aCx, aObj);
if (classPtr == &sClass ||
classPtr == DedicatedWorkerGlobalScope::Class()) {
return GetJSPrivateSafeish<WorkerGlobalScope>(aCx, aObj);
}
}
JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL, JSMSG_INCOMPATIBLE_PROTO,
sClass.name, aFunctionName,
classPtr ? classPtr->name : "object");
return NULL;
}
} /* anonymous namespace */
BEGIN_WORKERS_NAMESPACE
JSObject*
CreateDedicatedWorkerGlobalScope(JSContext* aCx)
{
WorkerPrivate* worker = GetWorkerPrivateFromContext(aCx);
JS_ASSERT(worker);
JSObject* global =
JS_NewCompartmentAndGlobalObject(aCx, DedicatedWorkerGlobalScope::Class(),
GetWorkerPrincipal());
if (!global) {
return NULL;
}
// Make the private slots now so that all our instance checks succeed.
if (!DedicatedWorkerGlobalScope::InitPrivate(aCx, global, worker)) {
return NULL;
}
// Proto chain should be:
// global -> DedicatedWorkerGlobalScope
// -> WorkerGlobalScope
// -> EventTarget
// -> Object
JSObject* eventTargetProto =
events::InitEventTargetClass(aCx, global, nsnull);
if (!eventTargetProto) {
return NULL;
}
JSObject* scopeProto =
WorkerGlobalScope::InitClass(aCx, global, eventTargetProto);
if (!scopeProto) {
return NULL;
}
JSObject* dedicatedScopeProto =
DedicatedWorkerGlobalScope::InitClass(aCx, global, scopeProto);
if (!dedicatedScopeProto) {
return NULL;
}
if (!JS_SetPrototype(aCx, global, dedicatedScopeProto)) {
return NULL;
}
JSObject* workerProto = worker::InitClass(aCx, global, eventTargetProto,
false);
if (!workerProto) {
return NULL;
}
if (worker->IsChromeWorker()) {
if (!chromeworker::InitClass(aCx, global, workerProto, false) ||
!chromeworker::DefineChromeWorkerFunctions(aCx, global)) {
return NULL;
}
}
// Init other classes we care about.
if (!events::InitClasses(aCx, global, false) ||
!exceptions::InitClasses(aCx, global) ||
!xhr::InitClasses(aCx, global, eventTargetProto) ||
!location::InitClass(aCx, global) ||
!navigator::InitClass(aCx, global)) {
return NULL;
}
if (!JS_DefineProfilingFunctions(aCx, global)) {
return NULL;
}
return global;
}
END_WORKERS_NAMESPACE

Просмотреть файл

@ -1,3 +1,4 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
@ -11,15 +12,15 @@
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is DOM Worker Tests.
* The Original Code is Web Workers.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2010
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com>
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -35,6 +36,18 @@
*
* ***** END LICENSE BLOCK ***** */
onmessage = function(event) {
postMessage("Done!");
};
#ifndef mozilla_dom_workers_workerscope_h__
#define mozilla_dom_workers_workerscope_h__
#include "Workers.h"
#include "jspubtd.h"
BEGIN_WORKERS_NAMESPACE
JSObject*
CreateDedicatedWorkerGlobalScope(JSContext* aCx);
END_WORKERS_NAMESPACE
#endif /* mozilla_dom_workers_workerscope_h__ */

Просмотреть файл

@ -1,4 +1,4 @@
/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- */
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
@ -12,11 +12,11 @@
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is worker threads.
* The Original Code is Web Workers.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2009
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
@ -36,42 +36,48 @@
*
* ***** END LICENSE BLOCK ***** */
#ifndef __NSDOMWORKERLOCATION_H__
#define __NSDOMWORKERLOCATION_H__
#ifndef mozilla_dom_workers_workers_h__
#define mozilla_dom_workers_workers_h__
#include "nsIClassInfo.h"
#include "nsIDOMWorkers.h"
#include "nsIXPCScriptable.h"
#include "jspubtd.h"
#include "nsCOMPtr.h"
#include "nsStringGlue.h"
#define BEGIN_WORKERS_NAMESPACE \
namespace mozilla { namespace dom { namespace workers {
#define END_WORKERS_NAMESPACE \
} /* namespace workers */ } /* namespace dom */ } /* namespace mozilla */
#define USING_WORKERS_NAMESPACE \
using namespace mozilla::dom::workers;
class nsIURL;
class nsPIDOMWindow;
class nsDOMWorkerLocation : public nsIWorkerLocation,
public nsIClassInfo,
public nsIXPCScriptable
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIWORKERLOCATION
NS_DECL_NSICLASSINFO
NS_DECL_NSIXPCSCRIPTABLE
BEGIN_WORKERS_NAMESPACE
static already_AddRefed<nsIWorkerLocation> NewLocation(nsIURL* aURL);
struct PrivatizableBase
{ };
protected:
nsDOMWorkerLocation() { }
#ifdef DEBUG
void
AssertIsOnMainThread();
#else
inline void
AssertIsOnMainThread()
{ }
#endif
private:
nsCString mHref;
nsCString mProtocol;
nsCString mHost;
nsCString mHostname;
nsCString mPort;
nsCString mPathname;
nsCString mSearch;
nsCString mHash;
};
// All of these are implemented in RuntimeService.cpp
JSBool
ResolveWorkerClasses(JSContext* aCx, JSObject* aObj, jsid aId, uintN aFlags,
JSObject** aObjp);
#endif /* __NSDOMWORKERLOCATION_H__ */
void
CancelWorkersForWindow(JSContext* aCx, nsPIDOMWindow* aWindow);
void
SuspendWorkersForWindow(JSContext* aCx, nsPIDOMWindow* aWindow);
void
ResumeWorkersForWindow(JSContext* aCx, nsPIDOMWindow* aWindow);
END_WORKERS_NAMESPACE
#endif /* mozilla_dom_workers_workers_h__ */

Просмотреть файл

@ -0,0 +1,836 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Web Workers.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "XMLHttpRequest.h"
#include "jsapi.h"
#include "jscntxt.h"
#include "jsobj.h"
#include "WorkerPrivate.h"
#include "XMLHttpRequestPrivate.h"
#include "WorkerInlines.h"
#define PROPERTY_FLAGS \
JSPROP_ENUMERATE | JSPROP_SHARED
#define FUNCTION_FLAGS \
JSPROP_ENUMERATE
#define CONSTANT_FLAGS \
JSPROP_ENUMERATE | JSPROP_SHARED | JSPROP_PERMANENT | JSPROP_READONLY
USING_WORKERS_NAMESPACE
using mozilla::dom::workers::xhr::XMLHttpRequestPrivate;
namespace {
class XMLHttpRequestUpload : public events::EventTarget
{
static JSClass sClass;
static JSPropertySpec sProperties[];
enum
{
STRING_onabort = 0,
STRING_onerror,
STRING_onload,
STRING_onloadstart,
STRING_onprogress,
STRING_onloadend,
STRING_COUNT
};
static const char* const sEventStrings[STRING_COUNT];
public:
static JSClass*
Class()
{
return &sClass;
}
static JSObject*
InitClass(JSContext* aCx, JSObject* aObj, JSObject* aParentProto)
{
return JS_InitClass(aCx, aObj, aParentProto, &sClass, Construct, 0,
sProperties, NULL, NULL, NULL);
}
static JSObject*
Create(JSContext* aCx)
{
JSObject* obj = JS_NewObject(aCx, &sClass, NULL, NULL);
if (obj) {
XMLHttpRequestUpload* priv = new XMLHttpRequestUpload();
if (!SetJSPrivateSafeish(aCx, obj, priv)) {
delete priv;
return NULL;
}
}
return obj;
}
private:
XMLHttpRequestUpload()
{
MOZ_COUNT_CTOR(mozilla::dom::workers::xhr::XMLHttpRequestUpload);
}
~XMLHttpRequestUpload()
{
MOZ_COUNT_DTOR(mozilla::dom::workers::xhr::XMLHttpRequestUpload);
}
static XMLHttpRequestUpload*
GetPrivate(JSContext* aCx, JSObject* aObj)
{
if (aObj) {
JSClass* classPtr = JS_GET_CLASS(aCx, aObj);
if (classPtr == &sClass) {
return GetJSPrivateSafeish<XMLHttpRequestUpload>(aCx, aObj);
}
}
return NULL;
}
static XMLHttpRequestUpload*
GetInstancePrivate(JSContext* aCx, JSObject* aObj, const char* aFunctionName)
{
JSClass* classPtr = NULL;
if (aObj) {
XMLHttpRequestUpload* priv = GetPrivate(aCx, aObj);
if (priv) {
return priv;
}
classPtr = JS_GET_CLASS(aCx, aObj);
}
JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL,
JSMSG_INCOMPATIBLE_PROTO, sClass.name, aFunctionName,
classPtr ? classPtr->name : "object");
return NULL;
}
static JSBool
Construct(JSContext* aCx, uintN aArgc, jsval* aVp)
{
JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL, JSMSG_WRONG_CONSTRUCTOR,
sClass.name);
return false;
}
static void
Finalize(JSContext* aCx, JSObject* aObj)
{
JS_ASSERT(JS_GET_CLASS(aCx, aObj) == &sClass);
XMLHttpRequestUpload* priv = GetPrivate(aCx, aObj);
if (priv) {
priv->FinalizeInstance(aCx);
delete priv;
}
}
static void
Trace(JSTracer* aTrc, JSObject* aObj)
{
JS_ASSERT(JS_GET_CLASS(aTrc->context, aObj) == &sClass);
XMLHttpRequestUpload* priv = GetPrivate(aTrc->context, aObj);
if (priv) {
priv->TraceInstance(aTrc);
}
}
static JSBool
GetEventListener(JSContext* aCx, JSObject* aObj, jsid aIdval, jsval* aVp)
{
JS_ASSERT(JSID_IS_INT(aIdval));
JS_ASSERT(JSID_TO_INT(aIdval) >= 0 && JSID_TO_INT(aIdval) < STRING_COUNT);
const char* name = sEventStrings[JSID_TO_INT(aIdval)];
XMLHttpRequestUpload* priv = GetInstancePrivate(aCx, aObj, name);
if (!priv) {
return false;
}
return priv->GetEventListenerOnEventTarget(aCx, name + 2, aVp);
}
static JSBool
SetEventListener(JSContext* aCx, JSObject* aObj, jsid aIdval, JSBool aStrict,
jsval* aVp)
{
JS_ASSERT(JSID_IS_INT(aIdval));
JS_ASSERT(JSID_TO_INT(aIdval) >= 0 && JSID_TO_INT(aIdval) < STRING_COUNT);
const char* name = sEventStrings[JSID_TO_INT(aIdval)];
XMLHttpRequestUpload* priv = GetInstancePrivate(aCx, aObj, name);
if (!priv) {
return false;
}
return priv->SetEventListenerOnEventTarget(aCx, name + 2, aVp);
}
};
JSClass XMLHttpRequestUpload::sClass = {
"XMLHttpRequestUpload",
JSCLASS_HAS_PRIVATE,
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Finalize,
NULL, NULL, NULL, NULL, NULL, NULL, Trace, NULL
};
JSPropertySpec XMLHttpRequestUpload::sProperties[] = {
{ sEventStrings[STRING_onabort], STRING_onabort, PROPERTY_FLAGS,
GetEventListener, SetEventListener },
{ sEventStrings[STRING_onerror], STRING_onerror, PROPERTY_FLAGS,
GetEventListener, SetEventListener },
{ sEventStrings[STRING_onload], STRING_onload, PROPERTY_FLAGS,
GetEventListener, SetEventListener },
{ sEventStrings[STRING_onloadstart], STRING_onloadstart, PROPERTY_FLAGS,
GetEventListener, SetEventListener },
{ sEventStrings[STRING_onprogress], STRING_onprogress, PROPERTY_FLAGS,
GetEventListener, SetEventListener },
{ sEventStrings[STRING_onloadend], STRING_onloadend, PROPERTY_FLAGS,
GetEventListener, SetEventListener },
{ 0, 0, 0, NULL, NULL }
};
const char* const XMLHttpRequestUpload::sEventStrings[STRING_COUNT] = {
"onabort",
"onerror",
"onload",
"onloadstart",
"onprogress",
"onloadend"
};
class XMLHttpRequest
{
static JSClass sClass;
static JSPropertySpec sProperties[];
static JSFunctionSpec sFunctions[];
static JSPropertySpec sStaticProperties[];
enum SLOT {
SLOT_channel = 0,
SLOT_responseXML,
SLOT_responseText,
SLOT_mozResponseArrayBuffer,
SLOT_status,
SLOT_statusText,
SLOT_readyState,
SLOT_multipart,
SLOT_mozBackgroundRequest,
SLOT_withCredentials,
SLOT_upload,
SLOT_COUNT
};
enum {
UNSENT = 0,
OPENED = 1,
HEADERS_RECEIVED = 2,
LOADING = 3,
DONE = 4
};
enum
{
STRING_onreadystatechange = 0,
STRING_onabort,
STRING_onerror,
STRING_onload,
STRING_onloadstart,
STRING_onprogress,
STRING_onloadend,
STRING_COUNT
};
static const char* const sEventStrings[STRING_COUNT];
public:
static JSClass*
Class()
{
return &sClass;
}
static JSObject*
InitClass(JSContext* aCx, JSObject* aObj, JSObject* aParentProto)
{
JSObject* proto = JS_InitClass(aCx, aObj, aParentProto, &sClass, Construct,
0, sProperties, sFunctions,
sStaticProperties, NULL);
if (proto && !JS_DefineProperties(aCx, proto, sStaticProperties)) {
return NULL;
}
return proto;
}
static bool
UpdateState(JSContext* aCx, JSObject* aObj, const xhr::StateData& aNewState)
{
JS_ASSERT(GetPrivate(aCx, aObj));
#define HANDLE_STATE_VALUE(_member, _slot) \
if (aNewState. _member##Exception || !JSVAL_IS_VOID(aNewState. _member)) { \
if (!JS_SetReservedSlot(aCx, aObj, _slot, aNewState. _member)) { \
return false; \
} \
}
HANDLE_STATE_VALUE(mResponseText, SLOT_responseText)
HANDLE_STATE_VALUE(mStatus, SLOT_status)
HANDLE_STATE_VALUE(mStatusText, SLOT_statusText)
HANDLE_STATE_VALUE(mReadyState, SLOT_readyState)
#undef HANDLE_STATE_VALUE
return true;
}
private:
// No instance of this class should ever be created so these are explicitly
// left without an implementation to prevent linking in case someone tries to
// make one.
XMLHttpRequest();
~XMLHttpRequest();
static XMLHttpRequestPrivate*
GetPrivate(JSContext* aCx, JSObject* aObj)
{
if (aObj) {
JSClass* classPtr = JS_GET_CLASS(aCx, aObj);
if (classPtr == &sClass) {
return GetJSPrivateSafeish<XMLHttpRequestPrivate>(aCx, aObj);
}
}
return NULL;
}
static XMLHttpRequestPrivate*
GetInstancePrivate(JSContext* aCx, JSObject* aObj, const char* aFunctionName)
{
JSClass* classPtr = NULL;
if (aObj) {
XMLHttpRequestPrivate* priv = GetPrivate(aCx, aObj);
if (priv) {
return priv;
}
classPtr = JS_GET_CLASS(aCx, aObj);
}
JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL,
JSMSG_INCOMPATIBLE_PROTO, sClass.name, aFunctionName,
classPtr ? classPtr->name : "object");
return NULL;
}
static JSBool
Construct(JSContext* aCx, uintN aArgc, jsval* aVp)
{
JSObject* obj = JS_NewObject(aCx, &sClass, NULL, NULL);
if (!obj) {
return false;
}
jsval emptyString = JS_GetEmptyStringValue(aCx);
jsval zero = INT_TO_JSVAL(0);
if (!JS_SetReservedSlot(aCx, obj, SLOT_channel, JSVAL_NULL) ||
!JS_SetReservedSlot(aCx, obj, SLOT_responseXML, JSVAL_NULL) ||
!JS_SetReservedSlot(aCx, obj, SLOT_responseText, emptyString) ||
!JS_SetReservedSlot(aCx, obj, SLOT_mozResponseArrayBuffer,
JSVAL_NULL) ||
!JS_SetReservedSlot(aCx, obj, SLOT_status, zero) ||
!JS_SetReservedSlot(aCx, obj, SLOT_statusText, emptyString) ||
!JS_SetReservedSlot(aCx, obj, SLOT_readyState, zero) ||
!JS_SetReservedSlot(aCx, obj, SLOT_multipart, JSVAL_FALSE) ||
!JS_SetReservedSlot(aCx, obj, SLOT_mozBackgroundRequest, JSVAL_FALSE) ||
!JS_SetReservedSlot(aCx, obj, SLOT_withCredentials, JSVAL_FALSE) ||
!JS_SetReservedSlot(aCx, obj, SLOT_upload, JSVAL_NULL)) {
return false;
}
WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
XMLHttpRequestPrivate* priv = new XMLHttpRequestPrivate(obj, workerPrivate);
if (!SetJSPrivateSafeish(aCx, obj, priv)) {
delete priv;
return false;
}
JS_SET_RVAL(aCx, aVp, OBJECT_TO_JSVAL(obj));
return true;
}
static void
Finalize(JSContext* aCx, JSObject* aObj)
{
JS_ASSERT(JS_GET_CLASS(aCx, aObj) == &sClass);
XMLHttpRequestPrivate* priv = GetPrivate(aCx, aObj);
if (priv) {
priv->FinalizeInstance(aCx);
delete priv;
}
}
static void
Trace(JSTracer* aTrc, JSObject* aObj)
{
JS_ASSERT(JS_GET_CLASS(aTrc->context, aObj) == &sClass);
XMLHttpRequestPrivate* priv = GetPrivate(aTrc->context, aObj);
if (priv) {
priv->TraceInstance(aTrc);
}
}
static JSBool
GetProperty(JSContext* aCx, JSObject* aObj, jsid aIdval, jsval* aVp)
{
JS_ASSERT(JSID_IS_INT(aIdval));
int32 slot = JSID_TO_INT(aIdval);
const char*& name = sProperties[slot].name;
if (!GetInstancePrivate(aCx, aObj, name)) {
return false;
}
jsval rval;
if (!JS_GetReservedSlot(aCx, aObj, slot, &rval)) {
return false;
}
if (JSVAL_IS_VOID(rval)) {
// Throw an exception.
JS_ReportError(aCx, "Unable to retrieve %s property", name);
return false;
}
*aVp = rval;
return true;
}
static JSBool
GetConstant(JSContext* aCx, JSObject* aObj, jsid idval, jsval* aVp)
{
JS_ASSERT(JSID_IS_INT(idval));
JS_ASSERT(JSID_TO_INT(idval) >= UNSENT &&
JSID_TO_INT(idval) <= DONE);
*aVp = INT_TO_JSVAL(JSID_TO_INT(idval));
return true;
}
static JSBool
GetUpload(JSContext* aCx, JSObject* aObj, jsid aIdval, jsval* aVp)
{
JS_ASSERT(JSID_IS_INT(aIdval));
int32 slot = JSID_TO_INT(aIdval);
XMLHttpRequestPrivate* priv =
GetInstancePrivate(aCx, aObj, sProperties[slot].name);
if (!priv) {
return false;
}
jsval uploadVal;
if (!JS_GetReservedSlot(aCx, aObj, slot, &uploadVal)) {
return false;
}
if (JSVAL_IS_NULL(uploadVal)) {
JSObject* uploadObj = XMLHttpRequestUpload::Create(aCx);
if (!uploadObj) {
return false;
}
uploadVal = OBJECT_TO_JSVAL(uploadObj);
if (!JS_SetReservedSlot(aCx, aObj, slot, uploadVal)) {
return false;
}
priv->SetUploadObject(uploadObj);
}
JS_ASSERT(!JSVAL_IS_PRIMITIVE(uploadVal));
*aVp = uploadVal;
return true;
}
#define IMPL_SETTER(_name) \
static JSBool \
Set##_name (JSContext* aCx, JSObject* aObj, jsid aIdval, JSBool aStrict, \
jsval* aVp) \
{ \
JS_ASSERT(JSID_IS_INT(aIdval)); \
\
int32 slot = JSID_TO_INT(aIdval); \
\
XMLHttpRequestPrivate* priv = \
GetInstancePrivate(aCx, aObj, sProperties[slot].name); \
if (!priv) { \
return false; \
} \
\
jsval rval = *aVp; \
if (!priv->Set##_name (aCx, &rval) || \
!JS_SetReservedSlot(aCx, aObj, slot, rval)) { \
return false; \
} \
\
*aVp = rval; \
return true; \
}
IMPL_SETTER(Multipart)
IMPL_SETTER(MozBackgroundRequest)
IMPL_SETTER(WithCredentials)
#undef IMPL_SETTER
static JSBool
GetEventListener(JSContext* aCx, JSObject* aObj, jsid aIdval, jsval* aVp)
{
JS_ASSERT(JSID_IS_INT(aIdval));
JS_ASSERT(JSID_TO_INT(aIdval) >= 0 && JSID_TO_INT(aIdval) < STRING_COUNT);
const char* name = sEventStrings[JSID_TO_INT(aIdval)];
XMLHttpRequestPrivate* priv = GetInstancePrivate(aCx, aObj, name);
if (!priv) {
return false;
}
return priv->GetEventListenerOnEventTarget(aCx, name + 2, aVp);
}
static JSBool
SetEventListener(JSContext* aCx, JSObject* aObj, jsid aIdval, JSBool aStrict,
jsval* aVp)
{
JS_ASSERT(JSID_IS_INT(aIdval));
JS_ASSERT(JSID_TO_INT(aIdval) >= 0 && JSID_TO_INT(aIdval) < STRING_COUNT);
const char* name = sEventStrings[JSID_TO_INT(aIdval)];
XMLHttpRequestPrivate* priv = GetInstancePrivate(aCx, aObj, name);
if (!priv) {
return false;
}
return priv->SetEventListenerOnEventTarget(aCx, name + 2, aVp);
}
static JSBool
Abort(JSContext* aCx, uintN aArgc, jsval* aVp)
{
JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
XMLHttpRequestPrivate* priv =
GetInstancePrivate(aCx, obj, sFunctions[0].name);
if (!priv) {
return false;
}
return priv->Abort(aCx);
}
static JSBool
GetAllResponseHeaders(JSContext* aCx, uintN aArgc, jsval* aVp)
{
JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
XMLHttpRequestPrivate* priv =
GetInstancePrivate(aCx, obj, sFunctions[1].name);
if (!priv) {
return false;
}
JSString* responseHeaders = priv->GetAllResponseHeaders(aCx);
if (!responseHeaders) {
return false;
}
JS_SET_RVAL(aCx, aVp, STRING_TO_JSVAL(responseHeaders));
return true;
}
static JSBool
GetResponseHeader(JSContext* aCx, uintN aArgc, jsval* aVp)
{
JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
XMLHttpRequestPrivate* priv =
GetInstancePrivate(aCx, obj, sFunctions[2].name);
if (!priv) {
return false;
}
jsval headerVal;
if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "v", &headerVal)) {
return false;
}
JSString* header;
if (JSVAL_IS_NULL(headerVal)) {
header = JSVAL_TO_STRING(JS_GetEmptyStringValue(aCx));
}
else {
header = JS_ValueToString(aCx, headerVal);
if (!header) {
return false;
}
}
JSString* value = priv->GetResponseHeader(aCx, header);
if (!value) {
return false;
}
JS_SET_RVAL(aCx, aVp, STRING_TO_JSVAL(value));
return true;
}
static JSBool
Open(JSContext* aCx, uintN aArgc, jsval* aVp)
{
JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
XMLHttpRequestPrivate* priv =
GetInstancePrivate(aCx, obj, sFunctions[3].name);
if (!priv) {
return false;
}
JSString* method, *url;
JSBool async = true;
JSString* user = JS_GetEmptyString(JS_GetRuntime(aCx));
JSString* password = user;
if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "SS/bSS", &method,
&url, &async, &user, &password)) {
return false;
}
return priv->Open(aCx, method, url, async, user, password);
}
static JSBool
Send(JSContext* aCx, uintN aArgc, jsval* aVp)
{
JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
XMLHttpRequestPrivate* priv =
GetInstancePrivate(aCx, obj, sFunctions[4].name);
if (!priv) {
return false;
}
jsval body = aArgc ? JS_ARGV(aCx, aVp)[0] : JSVAL_VOID;
return priv->Send(aCx, !!aArgc, body);
}
static JSBool
SendAsBinary(JSContext* aCx, uintN aArgc, jsval* aVp)
{
JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
XMLHttpRequestPrivate* priv =
GetInstancePrivate(aCx, obj, sFunctions[5].name);
if (!priv) {
return false;
}
jsval bodyVal;
if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "v", &bodyVal)) {
return false;
}
JSString* body;
if (JSVAL_IS_NULL(bodyVal)) {
body = JSVAL_TO_STRING(JS_GetEmptyStringValue(aCx));
}
else {
body = JS_ValueToString(aCx, bodyVal);
if (!body) {
return false;
}
}
return priv->SendAsBinary(aCx, body);
}
static JSBool
SetRequestHeader(JSContext* aCx, uintN aArgc, jsval* aVp)
{
JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
XMLHttpRequestPrivate* priv =
GetInstancePrivate(aCx, obj, sFunctions[6].name);
if (!priv) {
return false;
}
JSString* header, *value;
if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "SS", &header,
&value)) {
return false;
}
return priv->SetRequestHeader(aCx, header, value);
}
};
JSClass XMLHttpRequest::sClass = {
"XMLHttpRequest",
JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(SLOT_COUNT),
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Finalize,
NULL, NULL, NULL, NULL, NULL, NULL, Trace, NULL
};
JSPropertySpec XMLHttpRequest::sProperties[] = {
#define GENERIC_READONLY_PROPERTY(_name) \
{ #_name, SLOT_##_name, PROPERTY_FLAGS, GetProperty, \
js_GetterOnlyPropertyStub },
GENERIC_READONLY_PROPERTY(channel)
GENERIC_READONLY_PROPERTY(responseXML)
GENERIC_READONLY_PROPERTY(responseText)
GENERIC_READONLY_PROPERTY(mozResponseArrayBuffer)
GENERIC_READONLY_PROPERTY(status)
GENERIC_READONLY_PROPERTY(statusText)
GENERIC_READONLY_PROPERTY(readyState)
{ "multipart", 7, PROPERTY_FLAGS, GetProperty, SetMultipart },
{ "mozBackgroundRequest", 8, PROPERTY_FLAGS, GetProperty,
SetMozBackgroundRequest },
{ "withCredentials", 9, PROPERTY_FLAGS, GetProperty, SetWithCredentials },
{ "upload", SLOT_upload, PROPERTY_FLAGS, GetUpload,
js_GetterOnlyPropertyStub },
{ sEventStrings[STRING_onreadystatechange], STRING_onreadystatechange,
PROPERTY_FLAGS, GetEventListener, SetEventListener },
{ sEventStrings[STRING_onabort], STRING_onabort, PROPERTY_FLAGS,
GetEventListener, SetEventListener },
{ sEventStrings[STRING_onerror], STRING_onerror, PROPERTY_FLAGS,
GetEventListener, SetEventListener },
{ sEventStrings[STRING_onload], STRING_onload, PROPERTY_FLAGS,
GetEventListener, SetEventListener },
{ sEventStrings[STRING_onloadstart], STRING_onloadstart, PROPERTY_FLAGS,
GetEventListener, SetEventListener },
{ sEventStrings[STRING_onprogress], STRING_onprogress, PROPERTY_FLAGS,
GetEventListener, SetEventListener },
{ sEventStrings[STRING_onloadend], STRING_onloadend, PROPERTY_FLAGS,
GetEventListener, SetEventListener },
#undef GENERIC_READONLY_PROPERTY
{ 0, 0, 0, NULL, NULL }
};
JSFunctionSpec XMLHttpRequest::sFunctions[] = {
JS_FN("abort", Abort, 0, FUNCTION_FLAGS),
JS_FN("getAllResponseHeaders", GetAllResponseHeaders, 0, FUNCTION_FLAGS),
JS_FN("getResponseHeader", GetResponseHeader, 1, FUNCTION_FLAGS),
JS_FN("open", Open, 2, FUNCTION_FLAGS),
JS_FN("send", Send, 0, FUNCTION_FLAGS),
JS_FN("sendAsBinary", SendAsBinary, 1, FUNCTION_FLAGS),
JS_FN("setRequestHeader", SetRequestHeader, 2, FUNCTION_FLAGS),
JS_FS_END
};
JSPropertySpec XMLHttpRequest::sStaticProperties[] = {
{ "UNSENT", UNSENT, CONSTANT_FLAGS, GetConstant, NULL },
{ "OPENED", OPENED, CONSTANT_FLAGS, GetConstant, NULL },
{ "HEADERS_RECEIVED", HEADERS_RECEIVED, CONSTANT_FLAGS, GetConstant, NULL },
{ "LOADING", LOADING, CONSTANT_FLAGS, GetConstant, NULL },
{ "DONE", DONE, CONSTANT_FLAGS, GetConstant, NULL },
{ 0, 0, 0, NULL, NULL }
};
const char* const XMLHttpRequest::sEventStrings[STRING_COUNT] = {
"onreadystatechange",
"onabort",
"onerror",
"onload",
"onloadstart",
"onprogress",
"onloadend"
};
} // anonymous namespace
BEGIN_WORKERS_NAMESPACE
namespace xhr {
bool
InitClasses(JSContext* aCx, JSObject* aGlobal, JSObject* aProto)
{
return XMLHttpRequest::InitClass(aCx, aGlobal, aProto) &&
XMLHttpRequestUpload::InitClass(aCx, aGlobal, aProto);
}
bool
UpdateXHRState(JSContext* aCx, JSObject* aObj, const StateData& aNewState)
{
return XMLHttpRequest::UpdateState(aCx, aObj, aNewState);
}
} // namespace xhr
END_WORKERS_NAMESPACE

Просмотреть файл

@ -1,4 +1,4 @@
/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- */
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
@ -12,11 +12,11 @@
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is worker threads.
* The Original Code is Web Workers.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2008
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
@ -36,27 +36,37 @@
*
* ***** END LICENSE BLOCK ***** */
#ifndef __NSDOMWORKERSECURITYMANAGER_H__
#define __NSDOMWORKERSECURITYMANAGER_H__
#ifndef mozilla_dom_workers_xmlhttprequest_h__
#define mozilla_dom_workers_xmlhttprequest_h__
#include "nsIXPCSecurityManager.h"
#include "jsapi.h"
#include "Workers.h"
class nsDOMWorkerSecurityManager : public nsIXPCSecurityManager
#include "jspubtd.h"
BEGIN_WORKERS_NAMESPACE
namespace xhr {
bool
InitClasses(JSContext* aCx, JSObject* aGlobal, JSObject* aProto);
struct StateData
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIXPCSECURITYMANAGER
static JSPrincipals* WorkerPrincipal();
static JSBool JSCheckAccess(JSContext* aCx, JSObject* aObj, jsid aId,
JSAccessMode aMode, jsval* aVp);
static JSPrincipals* JSFindPrincipal(JSContext* aCx, JSObject* aObj);
static JSBool JSTranscodePrincipals(JSXDRState* aXdr,
JSPrincipals** aJsprinp);
jsval mResponseText;
jsval mStatus;
jsval mStatusText;
jsval mReadyState;
bool mResponseTextException;
bool mStatusException;
bool mStatusTextException;
bool mReadyStateException;
};
#endif /* __NSDOMWORKERSECURITYMANAGER_H__ */
bool
UpdateXHRState(JSContext* aCx, JSObject* aObj, const StateData& aNewState);
} // namespace xhr
END_WORKERS_NAMESPACE
#endif /* mozilla_dom_workers_xmlhttprequest_h__ */

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,163 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Web Workers.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef mozilla_dom_workers_xmlhttprequestprivate_h__
#define mozilla_dom_workers_xmlhttprequestprivate_h__
#include "Workers.h"
#include "jspubtd.h"
#include "nsAutoPtr.h"
#include "EventTarget.h"
#include "WorkerFeature.h"
#include "WorkerPrivate.h"
BEGIN_WORKERS_NAMESPACE
namespace xhr {
class Proxy;
class XMLHttpRequestPrivate : public events::EventTarget,
public WorkerFeature
{
JSObject* mJSObject;
JSObject* mUploadJSObject;
WorkerPrivate* mWorkerPrivate;
nsRefPtr<Proxy> mProxy;
PRUint32 mJSObjectRootCount;
bool mMultipart;
bool mBackgroundRequest;
bool mWithCredentials;
bool mCanceled;
public:
XMLHttpRequestPrivate(JSObject* aObj, WorkerPrivate* aWorkerPrivate);
~XMLHttpRequestPrivate();
void
FinalizeInstance(JSContext* aCx)
{
ReleaseProxy();
events::EventTarget::FinalizeInstance(aCx);
}
void
UnrootJSObject(JSContext* aCx);
JSObject*
GetJSObject()
{
mWorkerPrivate->AssertIsOnWorkerThread();
return mJSObject;
}
JSObject*
GetUploadJSObject()
{
mWorkerPrivate->AssertIsOnWorkerThread();
return mUploadJSObject;
}
void
SetUploadObject(JSObject* aUploadObj)
{
mWorkerPrivate->AssertIsOnWorkerThread();
mUploadJSObject = aUploadObj;
}
using events::EventTarget::TraceInstance;
using events::EventTarget::GetEventListenerOnEventTarget;
using events::EventTarget::SetEventListenerOnEventTarget;
bool
Notify(JSContext* aCx, Status aStatus);
bool
SetMultipart(JSContext* aCx, jsval *aVp);
bool
SetMozBackgroundRequest(JSContext* aCx, jsval *aVp);
bool
SetWithCredentials(JSContext* aCx, jsval *aVp);
bool
Abort(JSContext* aCx);
JSString*
GetAllResponseHeaders(JSContext* aCx);
JSString*
GetResponseHeader(JSContext* aCx, JSString* aHeader);
bool
Open(JSContext* aCx, JSString* aMethod, JSString* aURL, bool aAsync,
JSString* aUser, JSString* aPassword);
bool
Send(JSContext* aCx, bool aHasBody, jsval aBody);
bool
SendAsBinary(JSContext* aCx, JSString* aBody);
bool
SetRequestHeader(JSContext* aCx, JSString* aHeader, JSString* aValue);
private:
void
ReleaseProxy();
bool
RootJSObject(JSContext* aCx);
bool
MaybeDispatchPrematureAbortEvents(JSContext* aCx, bool aFromOpen);
bool
DispatchPrematureAbortEvent(JSContext* aCx, JSObject* aTarget,
PRUint64 aEventType, bool aUploadTarget);
};
} // namespace xhr
END_WORKERS_NAMESPACE
#endif // mozilla_dom_workers_xmlhttprequestprivate_h__

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше