diff --git a/dom/workers/RuntimeService.cpp b/dom/workers/RuntimeService.cpp index 78ffcb8728b1..6211d5818939 100644 --- a/dom/workers/RuntimeService.cpp +++ b/dom/workers/RuntimeService.cpp @@ -752,6 +752,18 @@ InitJSContextForWorker(WorkerPrivate* aWorkerPrivate, JSContext* aWorkerCx) JSSettings settings; aWorkerPrivate->CopyJSSettings(settings); + { + JS::UniqueChars defaultLocale = aWorkerPrivate->AdoptDefaultLocale(); + MOZ_ASSERT(defaultLocale, + "failure of a WorkerPrivate to have a default locale should " + "have made the worker fail to spawn"); + + if (!JS_SetDefaultLocale(aWorkerCx, defaultLocale.get())) { + NS_WARNING("failed to set workerCx's default locale"); + return nullptr; + } + } + JS::ContextOptionsRef(aWorkerCx) = settings.contextOptions; JSSettings::JSGCSettingsArray& gcSettings = settings.gcSettings; diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp index f61c803602d0..a7faafa21094 100644 --- a/dom/workers/WorkerPrivate.cpp +++ b/dom/workers/WorkerPrivate.cpp @@ -42,6 +42,7 @@ #include "mozilla/EventDispatcher.h" #include "mozilla/Likely.h" #include "mozilla/LoadContext.h" +#include "mozilla/Move.h" #include "mozilla/dom/BindingUtils.h" #include "mozilla/dom/Console.h" #include "mozilla/dom/ErrorEvent.h" @@ -4196,6 +4197,18 @@ WorkerPrivate::Constructor(JSContext* aCx, new WorkerPrivate(parent, aScriptURL, aIsChromeWorker, aWorkerType, aWorkerName, *aLoadInfo); + // Gecko contexts always have an explicitly-set default locale (set by + // XPJSRuntime::Initialize for the main thread, set by + // WorkerThreadPrimaryRunnable::Run for workers just before running worker + // code), so this is never SpiderMonkey's builtin default locale. + JS::UniqueChars defaultLocale = JS_GetDefaultLocale(aCx); + if (NS_WARN_IF(!defaultLocale)) { + aRv.Throw(NS_ERROR_UNEXPECTED); + return nullptr; + } + + worker->mDefaultLocale = Move(defaultLocale); + if (!runtimeService->RegisterWorker(worker)) { aRv.Throw(NS_ERROR_UNEXPECTED); return nullptr; diff --git a/dom/workers/WorkerPrivate.h b/dom/workers/WorkerPrivate.h index 80209fd6ad11..82bec54d604f 100644 --- a/dom/workers/WorkerPrivate.h +++ b/dom/workers/WorkerPrivate.h @@ -15,8 +15,11 @@ #include "nsIWorkerDebugger.h" #include "nsPIDOMWindow.h" +#include "mozilla/Assertions.h" +#include "mozilla/Attributes.h" #include "mozilla/CondVar.h" #include "mozilla/DOMEventTargetHelper.h" +#include "mozilla/Move.h" #include "mozilla/TimeStamp.h" #include "mozilla/dom/BindingDeclarations.h" #include "nsAutoPtr.h" @@ -938,6 +941,7 @@ class WorkerPrivate : public WorkerPrivateParent // fired on the main thread if the worker script fails to load nsCOMPtr mLoadFailedRunnable; + JS::UniqueChars mDefaultLocale; // nulled during worker JSContext init TimeStamp mKillTime; uint32_t mErrorHandlerRecursionCount; uint32_t mNextTimeoutId; @@ -1049,6 +1053,15 @@ public: mDebugger = aDebugger; } + JS::UniqueChars + AdoptDefaultLocale() + { + MOZ_ASSERT(mDefaultLocale, + "the default locale must have been successfully set for anyone " + "to be trying to adopt it"); + return Move(mDefaultLocale); + } + void DoRunLoop(JSContext* aCx); diff --git a/intl/locale/tests/unit/data/chrome.manifest b/intl/locale/tests/unit/data/chrome.manifest new file mode 100644 index 000000000000..a8678deef398 --- /dev/null +++ b/intl/locale/tests/unit/data/chrome.manifest @@ -0,0 +1 @@ +content locale ./ diff --git a/intl/locale/tests/unit/data/intl_on_workers_worker.js b/intl/locale/tests/unit/data/intl_on_workers_worker.js new file mode 100644 index 000000000000..98aeeb5c0b29 --- /dev/null +++ b/intl/locale/tests/unit/data/intl_on_workers_worker.js @@ -0,0 +1,4 @@ +self.onmessage = function (data) { + let myLocale = Intl.NumberFormat().resolvedOptions().locale; + self.postMessage(myLocale); +}; diff --git a/intl/locale/tests/unit/test_intl_on_workers.js b/intl/locale/tests/unit/test_intl_on_workers.js new file mode 100644 index 000000000000..899e39d389da --- /dev/null +++ b/intl/locale/tests/unit/test_intl_on_workers.js @@ -0,0 +1,23 @@ +function run_test() { + do_load_manifest("data/chrome.manifest"); + + if (typeof Intl !== "object") { + dump("Intl not enabled, skipping test\n"); + equal(true, true); + return; + } + + let mainThreadLocale = Intl.NumberFormat().resolvedOptions().locale; + let testWorker = new Worker("chrome://locale/content/intl_on_workers_worker.js"); + testWorker.onmessage = function (e) { + try { + let workerLocale = e.data; + equal(mainThreadLocale, workerLocale, "Worker should inherit Intl locale from main thread."); + } finally { + do_test_finished(); + } + }; + + do_test_pending(); + testWorker.postMessage("go!"); +} diff --git a/intl/locale/tests/unit/xpcshell.ini b/intl/locale/tests/unit/xpcshell.ini index 88302be5e999..bde7384d2fb4 100644 --- a/intl/locale/tests/unit/xpcshell.ini +++ b/intl/locale/tests/unit/xpcshell.ini @@ -2,6 +2,9 @@ head = tail = skip-if = toolkit == 'gonk' +support-files = + data/intl_on_workers_worker.js + data/chrome.manifest [test_bug22310.js] skip-if = toolkit != "windows" && toolkit != "cocoa" @@ -14,6 +17,7 @@ skip-if = toolkit == "windows" || toolkit == "cocoa" skip-if = toolkit != "cocoa" [test_bug1086527.js] +[test_intl_on_workers.js] [test_pluralForm.js] [test_pluralForm_english.js] [test_pluralForm_makeGetter.js] diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index eabc1c869b23..678833d331e2 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -5856,6 +5856,16 @@ JS_SetDefaultLocale(JSContext* cx, const char* locale) return cx->setDefaultLocale(locale); } +JS_PUBLIC_API(UniqueChars) +JS_GetDefaultLocale(JSContext* cx) +{ + AssertHeapIsIdle(cx); + if (const char* locale = cx->getDefaultLocale()) + return UniqueChars(JS_strdup(cx, locale)); + + return nullptr; +} + JS_PUBLIC_API(void) JS_ResetDefaultLocale(JSContext* cx) { diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 90f940bc4c1d..140b6e4ec32c 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -5060,6 +5060,12 @@ JS_ParseJSONWithReviver(JSContext* cx, JS::HandleString str, JS::HandleValue rev extern JS_PUBLIC_API(bool) JS_SetDefaultLocale(JSContext* cx, const char* locale); +/** + * Look up the default locale for the ECMAScript Internationalization API. + */ +extern JS_PUBLIC_API(JS::UniqueChars) +JS_GetDefaultLocale(JSContext* cx); + /** * Reset the default locale to OS defaults. */