mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 826009 - Move locale callback info, default locale, etc. data and APIs to be JSRuntime-centered. f=bholley, r=jorendorff
--HG-- extra : rebase_source : 35317f4c29e9dd70e7d4fd1292027cfd51ce2675
This commit is contained in:
parent
7d776dcf48
commit
0e302a5094
@ -1133,8 +1133,6 @@ nsFrameScriptExecutor::InitTabChildGlobalInternal(nsISupports* aScope)
|
||||
JS_SetVersion(cx, JSVERSION_LATEST);
|
||||
JS_SetErrorReporter(cx, ContentScriptErrorReporter);
|
||||
|
||||
xpc_LocalizeContext(cx);
|
||||
|
||||
JSAutoRequest ar(cx);
|
||||
nsIXPConnect* xpc = nsContentUtils::XPConnect();
|
||||
const uint32_t flags = nsIXPConnect::INIT_JS_STANDARD_CLASSES;
|
||||
|
@ -1114,8 +1114,6 @@ nsJSContext::nsJSContext(JSRuntime *aRuntime, bool aGCOnDestruction,
|
||||
js_options_dot_str, this);
|
||||
|
||||
::JS_SetOperationCallback(mContext, DOMOperationCallback);
|
||||
|
||||
xpc_LocalizeContext(mContext);
|
||||
}
|
||||
mIsInitialized = false;
|
||||
mTerminations = nullptr;
|
||||
|
@ -1004,8 +1004,6 @@ XPCShellEnvironment::Init()
|
||||
return false;
|
||||
}
|
||||
|
||||
xpc_LocalizeContext(cx);
|
||||
|
||||
nsRefPtr<FullTrustSecMan> secman(new FullTrustSecMan());
|
||||
xpc->SetSecurityManagerForJSContext(cx, secman, 0xFFFF);
|
||||
|
||||
|
@ -248,7 +248,7 @@ MSG_DEF(JSMSG_UNUSED194, 194, 0, JSEXN_NONE, "")
|
||||
MSG_DEF(JSMSG_UNUSED195, 195, 0, JSEXN_NONE, "")
|
||||
MSG_DEF(JSMSG_UNUSED196, 196, 0, JSEXN_NONE, "")
|
||||
MSG_DEF(JSMSG_UNUSED197, 197, 0, JSEXN_NONE, "")
|
||||
MSG_DEF(JSMSG_UNUSED198, 198, 0, JSEXN_NONE, "")
|
||||
MSG_DEF(JSMSG_DEFAULT_LOCALE_ERROR, 198, 0, JSEXN_ERR, "internal error getting the default locale")
|
||||
MSG_DEF(JSMSG_TOO_MANY_LOCALS, 199, 0, JSEXN_SYNTAXERR, "too many local variables")
|
||||
MSG_DEF(JSMSG_ARRAY_INIT_TOO_BIG, 200, 0, JSEXN_INTERNALERR, "array initialiser too large")
|
||||
MSG_DEF(JSMSG_REGEXP_TOO_COMPLEX, 201, 0, JSEXN_INTERNALERR, "regular expression too complex")
|
||||
|
@ -723,6 +723,8 @@ js::PerThreadData::PerThreadData(JSRuntime *runtime)
|
||||
JSRuntime::JSRuntime(JSUseHelperThreads useHelperThreads)
|
||||
: mainThread(this),
|
||||
atomsCompartment(NULL),
|
||||
localeCallbacks(NULL),
|
||||
defaultLocale(NULL),
|
||||
#ifdef JS_THREADSAFE
|
||||
ownerThread_(NULL),
|
||||
#endif
|
||||
@ -1135,6 +1137,7 @@ JS_PUBLIC_API(void)
|
||||
JS_DestroyRuntime(JSRuntime *rt)
|
||||
{
|
||||
Probes::destroyRuntime(rt);
|
||||
js_free(rt->defaultLocale);
|
||||
js_delete(rt);
|
||||
}
|
||||
|
||||
@ -2277,6 +2280,17 @@ JS_strdup(JSContext *cx, const char *s)
|
||||
return (char *)js_memcpy(p, s, n);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(char *)
|
||||
JS_strdup(JSRuntime *rt, const char *s)
|
||||
{
|
||||
AssertHeapIsIdle(rt);
|
||||
size_t n = strlen(s) + 1;
|
||||
void *p = rt->malloc_(n);
|
||||
if (!p)
|
||||
return NULL;
|
||||
return static_cast<char*>(js_memcpy(p, s, n));
|
||||
}
|
||||
|
||||
#undef JS_AddRoot
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
@ -6754,31 +6768,31 @@ JS_GetRegExpSource(JSContext *cx, JSObject *objArg)
|
||||
/************************************************************************/
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_SetDefaultLocale(JSContext *cx, const char *locale)
|
||||
JS_SetDefaultLocale(JSRuntime *rt, const char *locale)
|
||||
{
|
||||
AssertHeapIsIdle(cx);
|
||||
return cx->setDefaultLocale(locale);
|
||||
AssertHeapIsIdle(rt);
|
||||
return rt->setDefaultLocale(locale);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_ResetDefaultLocale(JSContext *cx)
|
||||
JS_ResetDefaultLocale(JSRuntime *rt)
|
||||
{
|
||||
AssertHeapIsIdle(cx);
|
||||
cx->resetDefaultLocale();
|
||||
AssertHeapIsIdle(rt);
|
||||
rt->resetDefaultLocale();
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_SetLocaleCallbacks(JSContext *cx, JSLocaleCallbacks *callbacks)
|
||||
JS_SetLocaleCallbacks(JSRuntime *rt, JSLocaleCallbacks *callbacks)
|
||||
{
|
||||
AssertHeapIsIdle(cx);
|
||||
cx->localeCallbacks = callbacks;
|
||||
AssertHeapIsIdle(rt);
|
||||
rt->localeCallbacks = callbacks;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSLocaleCallbacks *)
|
||||
JS_GetLocaleCallbacks(JSContext *cx)
|
||||
JS_GetLocaleCallbacks(JSRuntime *rt)
|
||||
{
|
||||
/* This function can be called by a finalizer. */
|
||||
return cx->localeCallbacks;
|
||||
return rt->localeCallbacks;
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
|
@ -2498,6 +2498,10 @@ JS_updateMallocCounter(JSContext *cx, size_t nbytes);
|
||||
extern JS_PUBLIC_API(char *)
|
||||
JS_strdup(JSContext *cx, const char *s);
|
||||
|
||||
/* Duplicate a string. Does not report an error on failure. */
|
||||
extern JS_PUBLIC_API(char *)
|
||||
JS_strdup(JSRuntime *rt, const char *s);
|
||||
|
||||
|
||||
/*
|
||||
* A GC root is a pointer to a jsval, JSObject * or JSString * that itself
|
||||
@ -4675,13 +4679,13 @@ JS_WriteTypedArray(JSStructuredCloneWriter *w, jsval v);
|
||||
* The locale string remains owned by the caller.
|
||||
*/
|
||||
extern JS_PUBLIC_API(JSBool)
|
||||
JS_SetDefaultLocale(JSContext *cx, const char *locale);
|
||||
JS_SetDefaultLocale(JSRuntime *rt, const char *locale);
|
||||
|
||||
/*
|
||||
* Reset the default locale to OS defaults.
|
||||
*/
|
||||
extern JS_PUBLIC_API(void)
|
||||
JS_ResetDefaultLocale(JSContext *cx);
|
||||
JS_ResetDefaultLocale(JSRuntime *rt);
|
||||
|
||||
/*
|
||||
* Locale specific string conversion and error message callbacks.
|
||||
@ -4696,17 +4700,17 @@ struct JSLocaleCallbacks {
|
||||
|
||||
/*
|
||||
* Establish locale callbacks. The pointer must persist as long as the
|
||||
* JSContext. Passing NULL restores the default behaviour.
|
||||
* JSRuntime. Passing NULL restores the default behaviour.
|
||||
*/
|
||||
extern JS_PUBLIC_API(void)
|
||||
JS_SetLocaleCallbacks(JSContext *cx, JSLocaleCallbacks *callbacks);
|
||||
JS_SetLocaleCallbacks(JSRuntime *rt, JSLocaleCallbacks *callbacks);
|
||||
|
||||
/*
|
||||
* Return the address of the current locale callbacks struct, which may
|
||||
* be NULL.
|
||||
*/
|
||||
extern JS_PUBLIC_API(JSLocaleCallbacks *)
|
||||
JS_GetLocaleCallbacks(JSContext *cx);
|
||||
JS_GetLocaleCallbacks(JSRuntime *rt);
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
|
@ -1169,9 +1169,7 @@ JSContext::JSContext(JSRuntime *rt)
|
||||
throwing(false),
|
||||
exception(UndefinedValue()),
|
||||
options_(0),
|
||||
defaultLocale(NULL),
|
||||
reportGranularity(JS_DEFAULT_JITREPORT_GRANULARITY),
|
||||
localeCallbacks(NULL),
|
||||
resolvingList(NULL),
|
||||
generatingError(false),
|
||||
enterCompartmentDepth_(0),
|
||||
@ -1215,7 +1213,6 @@ JSContext::JSContext(JSRuntime *rt)
|
||||
JSContext::~JSContext()
|
||||
{
|
||||
/* Free the stuff hanging off of cx. */
|
||||
js_free(defaultLocale);
|
||||
if (parseMapPool_)
|
||||
js_delete(parseMapPool_);
|
||||
|
||||
@ -1223,7 +1220,7 @@ JSContext::~JSContext()
|
||||
}
|
||||
|
||||
bool
|
||||
JSContext::setDefaultLocale(const char *locale)
|
||||
JSRuntime::setDefaultLocale(const char *locale)
|
||||
{
|
||||
if (!locale)
|
||||
return false;
|
||||
@ -1233,14 +1230,14 @@ JSContext::setDefaultLocale(const char *locale)
|
||||
}
|
||||
|
||||
void
|
||||
JSContext::resetDefaultLocale()
|
||||
JSRuntime::resetDefaultLocale()
|
||||
{
|
||||
js_free(defaultLocale);
|
||||
defaultLocale = NULL;
|
||||
}
|
||||
|
||||
const char *
|
||||
JSContext::getDefaultLocale()
|
||||
JSRuntime::getDefaultLocale()
|
||||
{
|
||||
if (defaultLocale)
|
||||
return defaultLocale;
|
||||
@ -1253,7 +1250,7 @@ JSContext::getDefaultLocale()
|
||||
#endif
|
||||
// convert to a well-formed BCP 47 language tag
|
||||
if (!locale || !strcmp(locale, "C"))
|
||||
locale = (char *) "und";
|
||||
locale = const_cast<char*>("und");
|
||||
lang = JS_strdup(this, locale);
|
||||
if (!lang)
|
||||
return NULL;
|
||||
|
@ -593,6 +593,12 @@ struct JSRuntime : js::RuntimeFriendFields,
|
||||
/* List of compartments (protected by the GC lock). */
|
||||
js::CompartmentVector compartments;
|
||||
|
||||
/* Locale-specific callbacks for string conversion. */
|
||||
JSLocaleCallbacks *localeCallbacks;
|
||||
|
||||
/* Default locale for Internationalization API */
|
||||
char *defaultLocale;
|
||||
|
||||
/* See comment for JS_AbortIfWrongThread in jsapi.h. */
|
||||
#ifdef JS_THREADSAFE
|
||||
public:
|
||||
@ -676,6 +682,10 @@ struct JSRuntime : js::RuntimeFriendFields,
|
||||
return ionRuntime_ ? ionRuntime_ : createIonRuntime(cx);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Self-hosting support
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
bool initSelfHosting(JSContext *cx);
|
||||
void markSelfHostingGlobal(JSTracer *trc);
|
||||
bool isSelfHostingGlobal(js::HandleObject global) {
|
||||
@ -686,6 +696,25 @@ struct JSRuntime : js::RuntimeFriendFields,
|
||||
bool cloneSelfHostedValue(JSContext *cx, js::Handle<js::PropertyName*> name,
|
||||
js::MutableHandleValue vp);
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Locale information
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
* Set the default locale for the ECMAScript Internationalization API
|
||||
* (Intl.Collator, Intl.NumberFormat, Intl.DateTimeFormat).
|
||||
* Note that the Internationalization API encourages clients to
|
||||
* specify their own locales.
|
||||
* The locale string remains owned by the caller.
|
||||
*/
|
||||
bool setDefaultLocale(const char *locale);
|
||||
|
||||
/* Reset the default locale to OS defaults. */
|
||||
void resetDefaultLocale();
|
||||
|
||||
/* Gets current default locale. String remains owned by context. */
|
||||
const char *getDefaultLocale();
|
||||
|
||||
/* Base address of the native stack for the current thread. */
|
||||
uintptr_t nativeStackBase;
|
||||
|
||||
@ -1369,30 +1398,9 @@ struct JSContext : js::ContextFriendFields,
|
||||
/* Per-context options. */
|
||||
unsigned options_; /* see jsapi.h for JSOPTION_* */
|
||||
|
||||
/* Default locale for Internationalization API */
|
||||
char *defaultLocale;
|
||||
|
||||
public:
|
||||
int32_t reportGranularity; /* see jsprobes.h */
|
||||
|
||||
/*
|
||||
* Set the default locale for the ECMAScript Internationalization API
|
||||
* (Intl.Collator, Intl.NumberFormat, Intl.DateTimeFormat).
|
||||
* Note that the Internationalization API encourages clients to
|
||||
* specify their own locales.
|
||||
* The locale string remains owned by the caller.
|
||||
*/
|
||||
bool setDefaultLocale(const char *locale);
|
||||
|
||||
/* Reset the default locale to OS defaults. */
|
||||
void resetDefaultLocale();
|
||||
|
||||
/* Gets current default locale. String remains owned by context. */
|
||||
const char *getDefaultLocale();
|
||||
|
||||
/* Locale specific callbacks for string conversion. */
|
||||
JSLocaleCallbacks *localeCallbacks;
|
||||
|
||||
js::AutoResolving *resolvingList;
|
||||
|
||||
/* True if generating an error, to prevent runaway recursion. */
|
||||
|
@ -2761,8 +2761,8 @@ ToLocaleHelper(JSContext *cx, HandleObject obj, const char *format, MutableHandl
|
||||
|
||||
}
|
||||
|
||||
if (cx->localeCallbacks && cx->localeCallbacks->localeToUnicode)
|
||||
return cx->localeCallbacks->localeToUnicode(cx, buf, rval.address());
|
||||
if (cx->runtime->localeCallbacks && cx->runtime->localeCallbacks->localeToUnicode)
|
||||
return cx->runtime->localeCallbacks->localeToUnicode(cx, buf, rval.address());
|
||||
|
||||
UnrootedString str = JS_NewStringCopyZ(cx, buf);
|
||||
if (!str)
|
||||
|
@ -866,8 +866,8 @@ js_GetLocalizedErrorMessage(JSContext* cx, void *userRef, const char *locale,
|
||||
{
|
||||
const JSErrorFormatString *errorString = NULL;
|
||||
|
||||
if (cx->localeCallbacks && cx->localeCallbacks->localeGetErrorMessage) {
|
||||
errorString = cx->localeCallbacks
|
||||
if (cx->runtime->localeCallbacks && cx->runtime->localeCallbacks->localeGetErrorMessage) {
|
||||
errorString = cx->runtime->localeCallbacks
|
||||
->localeGetErrorMessage(userRef, locale, errorNumber);
|
||||
}
|
||||
if (!errorString)
|
||||
|
@ -720,9 +720,9 @@ num_toLocaleString_impl(JSContext *cx, CallArgs args)
|
||||
strcpy(tmpDest, nint);
|
||||
}
|
||||
|
||||
if (cx->localeCallbacks && cx->localeCallbacks->localeToUnicode) {
|
||||
if (cx->runtime->localeCallbacks && cx->runtime->localeCallbacks->localeToUnicode) {
|
||||
Rooted<Value> v(cx, StringValue(str));
|
||||
bool ok = !!cx->localeCallbacks->localeToUnicode(cx, buf, v.address());
|
||||
bool ok = !!cx->runtime->localeCallbacks->localeToUnicode(cx, buf, v.address());
|
||||
if (ok)
|
||||
args.rval().set(v);
|
||||
js_free(buf);
|
||||
|
@ -679,13 +679,13 @@ str_toLocaleLowerCase(JSContext *cx, unsigned argc, Value *vp)
|
||||
* Forcefully ignore the first (or any) argument and return toLowerCase(),
|
||||
* ECMA has reserved that argument, presumably for defining the locale.
|
||||
*/
|
||||
if (cx->localeCallbacks && cx->localeCallbacks->localeToLowerCase) {
|
||||
if (cx->runtime->localeCallbacks && cx->runtime->localeCallbacks->localeToLowerCase) {
|
||||
RootedString str(cx, ThisToStringForStringProto(cx, args));
|
||||
if (!str)
|
||||
return false;
|
||||
|
||||
Value result;
|
||||
if (!cx->localeCallbacks->localeToLowerCase(cx, str, &result))
|
||||
if (!cx->runtime->localeCallbacks->localeToLowerCase(cx, str, &result))
|
||||
return false;
|
||||
|
||||
args.rval().set(result);
|
||||
@ -746,13 +746,13 @@ str_toLocaleUpperCase(JSContext *cx, unsigned argc, Value *vp)
|
||||
* Forcefully ignore the first (or any) argument and return toUpperCase(),
|
||||
* ECMA has reserved that argument, presumably for defining the locale.
|
||||
*/
|
||||
if (cx->localeCallbacks && cx->localeCallbacks->localeToUpperCase) {
|
||||
if (cx->runtime->localeCallbacks && cx->runtime->localeCallbacks->localeToUpperCase) {
|
||||
RootedString str(cx, ThisToStringForStringProto(cx, args));
|
||||
if (!str)
|
||||
return false;
|
||||
|
||||
Value result;
|
||||
if (!cx->localeCallbacks->localeToUpperCase(cx, str, &result))
|
||||
if (!cx->runtime->localeCallbacks->localeToUpperCase(cx, str, &result))
|
||||
return false;
|
||||
|
||||
args.rval().set(result);
|
||||
@ -775,11 +775,11 @@ str_localeCompare(JSContext *cx, unsigned argc, Value *vp)
|
||||
if (!thatStr)
|
||||
return false;
|
||||
|
||||
if (cx->localeCallbacks && cx->localeCallbacks->localeCompare) {
|
||||
if (cx->runtime->localeCallbacks && cx->runtime->localeCallbacks->localeCompare) {
|
||||
args[0].setString(thatStr);
|
||||
|
||||
Value result;
|
||||
if (!cx->localeCallbacks->localeCompare(cx, str, thatStr, &result))
|
||||
if (!cx->runtime->localeCallbacks->localeCompare(cx, str, thatStr, &result))
|
||||
return false;
|
||||
|
||||
args.rval().set(result);
|
||||
|
@ -284,9 +284,11 @@ intrinsic_RuntimeDefaultLocale(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
const char *locale = cx->getDefaultLocale();
|
||||
if (!locale)
|
||||
const char *locale = cx->runtime->getDefaultLocale();
|
||||
if (!locale) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_DEFAULT_LOCALE_ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
RootedString jslocale(cx, JS_NewStringCopyZ(cx, locale));
|
||||
if (!jslocale)
|
||||
|
@ -495,9 +495,6 @@ mozJSComponentLoader::ReallyInit()
|
||||
rv = obsSvc->AddObserver(this, "xpcom-shutdown-loaders", false);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Set up localized comparison and string conversion
|
||||
xpc_LocalizeContext(mContext);
|
||||
|
||||
#ifdef DEBUG_shaver_off
|
||||
fprintf(stderr, "mJCL: ReallyInit success!\n");
|
||||
#endif
|
||||
|
@ -1825,8 +1825,6 @@ main(int argc, char **argv, char **envp)
|
||||
argv++;
|
||||
ProcessArgsForCompartment(cx, argv, argc);
|
||||
|
||||
xpc_LocalizeContext(cx);
|
||||
|
||||
nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID());
|
||||
if (!xpc) {
|
||||
printf("failed to get nsXPConnect service!\n");
|
||||
|
@ -1224,6 +1224,8 @@ XPCJSRuntime::~XPCJSRuntime()
|
||||
|
||||
js::SetGCSliceCallback(mJSRuntime, mPrevGCSliceCallback);
|
||||
|
||||
xpc_DelocalizeRuntime(mJSRuntime);
|
||||
|
||||
if (mWatchdogWakeup) {
|
||||
// If the watchdog thread is running, tell it to terminate waking it
|
||||
// up if necessary and wait until it signals that it finished. As we
|
||||
@ -2598,6 +2600,12 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect)
|
||||
// handlers.
|
||||
JS_SetSourceHook(mJSRuntime, SourceHook);
|
||||
|
||||
// Set up locale information and callbacks for the newly-created runtime so
|
||||
// that the various toLocaleString() methods, localeCompare(), and other
|
||||
// internationalization APIs work as desired.
|
||||
if (!xpc_LocalizeRuntime(mJSRuntime))
|
||||
NS_RUNTIMEABORT("xpc_LocalizeRuntime failed.");
|
||||
|
||||
NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(XPConnectJSGCHeap));
|
||||
NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(XPConnectJSSystemCompartmentCount));
|
||||
NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(XPConnectJSUserCompartmentCount));
|
||||
|
@ -5,7 +5,8 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "prinit.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
|
||||
#include "plstr.h"
|
||||
|
||||
#include "jsapi.h"
|
||||
@ -22,41 +23,79 @@
|
||||
#include "xpcpublic.h"
|
||||
|
||||
/**
|
||||
* JS locale callbacks implemented by XPCOM modules. This
|
||||
* implementation is "safe" up to the following restrictions
|
||||
*
|
||||
* - All JSContexts for which xpc_LocalizeContext() is called belong
|
||||
* to the same JSRuntime
|
||||
*
|
||||
* - Each JSContext is destroyed on the thread on which its locale
|
||||
* functions are called.
|
||||
*
|
||||
* Unfortunately, the intl code underlying these XPCOM modules doesn't
|
||||
* yet support this model, so in practice XPCLocaleCallbacks are
|
||||
* limited to the main thread.
|
||||
* JS locale callbacks implemented by XPCOM modules. These are theoretically
|
||||
* safe for use on multiple threads. Unfortunately, the intl code underlying
|
||||
* these XPCOM modules doesn't yet support this, so in practice
|
||||
* XPCLocaleCallbacks are limited to the main thread.
|
||||
*/
|
||||
struct XPCLocaleCallbacks : public JSLocaleCallbacks
|
||||
{
|
||||
/**
|
||||
* Return the XPCLocaleCallbacks that's hidden away in |cx|, or null
|
||||
* if there isn't one. (This impl uses the locale callbacks struct
|
||||
* to store away its per-context data.)
|
||||
*
|
||||
* NB: If the returned XPCLocaleCallbacks hasn't yet been bound to a
|
||||
* thread, then a side effect of calling MaybeThis() is to bind it
|
||||
* to the calling thread.
|
||||
*/
|
||||
static XPCLocaleCallbacks*
|
||||
MaybeThis(JSContext* cx)
|
||||
XPCLocaleCallbacks()
|
||||
#ifdef DEBUG
|
||||
: mThread(PR_GetCurrentThread())
|
||||
#endif
|
||||
{
|
||||
JSLocaleCallbacks* lc = JS_GetLocaleCallbacks(cx);
|
||||
return (lc &&
|
||||
lc->localeToUpperCase == LocaleToUpperCase &&
|
||||
lc->localeToLowerCase == LocaleToLowerCase &&
|
||||
lc->localeCompare == LocaleCompare &&
|
||||
lc->localeToUnicode == LocaleToUnicode) ? This(cx) : nullptr;
|
||||
MOZ_COUNT_CTOR(XPCLocaleCallbacks);
|
||||
|
||||
localeToUpperCase = LocaleToUpperCase;
|
||||
localeToLowerCase = LocaleToLowerCase;
|
||||
localeCompare = LocaleCompare;
|
||||
localeToUnicode = LocaleToUnicode;
|
||||
localeGetErrorMessage = nullptr;
|
||||
}
|
||||
|
||||
~XPCLocaleCallbacks()
|
||||
{
|
||||
AssertThreadSafety();
|
||||
MOZ_COUNT_DTOR(XPCLocaleCallbacks);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the XPCLocaleCallbacks that's hidden away in |rt|. (This impl uses
|
||||
* the locale callbacks struct to store away its per-runtime data.)
|
||||
*/
|
||||
static XPCLocaleCallbacks*
|
||||
This(JSRuntime *rt)
|
||||
{
|
||||
// Locale information for |rt| was associated using xpc_LocalizeRuntime;
|
||||
// assert and double-check this.
|
||||
JSLocaleCallbacks* lc = JS_GetLocaleCallbacks(rt);
|
||||
MOZ_ASSERT(lc);
|
||||
MOZ_ASSERT(lc->localeToUpperCase == LocaleToUpperCase);
|
||||
MOZ_ASSERT(lc->localeToLowerCase == LocaleToLowerCase);
|
||||
MOZ_ASSERT(lc->localeCompare == LocaleCompare);
|
||||
MOZ_ASSERT(lc->localeToUnicode == LocaleToUnicode);
|
||||
|
||||
XPCLocaleCallbacks* ths = static_cast<XPCLocaleCallbacks*>(lc);
|
||||
ths->AssertThreadSafety();
|
||||
return ths;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
LocaleToUpperCase(JSContext *cx, JSString *src, jsval *rval)
|
||||
{
|
||||
return ChangeCase(cx, src, rval, ToUpperCase);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
LocaleToLowerCase(JSContext *cx, JSString *src, jsval *rval)
|
||||
{
|
||||
return ChangeCase(cx, src, rval, ToLowerCase);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
LocaleToUnicode(JSContext* cx, const char* src, jsval* rval)
|
||||
{
|
||||
return This(JS_GetRuntime(cx))->ToUnicode(cx, src, rval);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
LocaleCompare(JSContext *cx, JSString *src1, JSString *src2, jsval *rval)
|
||||
{
|
||||
return This(JS_GetRuntime(cx))->Compare(cx, src1, src2, rval);
|
||||
}
|
||||
|
||||
private:
|
||||
static JSBool
|
||||
ChangeCase(JSContext* cx, JSString* src, jsval* rval,
|
||||
void(*changeCaseFnc)(const nsAString&, nsAString&))
|
||||
@ -76,70 +115,54 @@ struct XPCLocaleCallbacks : public JSLocaleCallbacks
|
||||
}
|
||||
|
||||
*rval = STRING_TO_JSVAL(ucstr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
LocaleToUpperCase(JSContext *cx, JSString *src, jsval *rval)
|
||||
JSBool
|
||||
Compare(JSContext *cx, JSString *src1, JSString *src2, jsval *rval)
|
||||
{
|
||||
return ChangeCase(cx, src, rval, ToUpperCase);
|
||||
nsresult rv;
|
||||
|
||||
if (!mCollation) {
|
||||
nsCOMPtr<nsILocaleService> localeService =
|
||||
do_GetService(NS_LOCALESERVICE_CONTRACTID, &rv);
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
nsCOMPtr<nsILocale> locale;
|
||||
rv = localeService->GetApplicationLocale(getter_AddRefs(locale));
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
nsCOMPtr<nsICollationFactory> colFactory =
|
||||
do_CreateInstance(NS_COLLATIONFACTORY_CONTRACTID, &rv);
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
rv = colFactory->CreateCollation(locale, getter_AddRefs(mCollation));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static JSBool
|
||||
LocaleToLowerCase(JSContext *cx, JSString *src, jsval *rval)
|
||||
{
|
||||
return ChangeCase(cx, src, rval, ToLowerCase);
|
||||
if (NS_FAILED(rv)) {
|
||||
xpc::Throw(cx, rv);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an XPCLocaleCallbacks out of |cx|. Callers must know that
|
||||
* |cx| has an XPCLocaleCallbacks; i.e., the checks in MaybeThis()
|
||||
* would be pointless to run from the calling context.
|
||||
*
|
||||
* NB: If the returned XPCLocaleCallbacks hasn't yet been bound to a
|
||||
* thread, then a side effect of calling This() is to bind it to the
|
||||
* calling thread.
|
||||
*/
|
||||
static XPCLocaleCallbacks*
|
||||
This(JSContext* cx)
|
||||
{
|
||||
XPCLocaleCallbacks* ths =
|
||||
static_cast<XPCLocaleCallbacks*>(JS_GetLocaleCallbacks(cx));
|
||||
ths->AssertThreadSafety();
|
||||
return ths;
|
||||
nsDependentJSString depStr1, depStr2;
|
||||
if (!depStr1.init(cx, src1) || !depStr2.init(cx, src2)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
LocaleToUnicode(JSContext* cx, const char* src, jsval* rval)
|
||||
{
|
||||
return This(cx)->ToUnicode(cx, src, rval);
|
||||
int32_t result;
|
||||
rv = mCollation->CompareString(nsICollation::kCollationStrengthDefault,
|
||||
depStr1, depStr2, &result);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
xpc::Throw(cx, rv);
|
||||
return false;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
LocaleCompare(JSContext *cx, JSString *src1, JSString *src2, jsval *rval)
|
||||
{
|
||||
return This(cx)->Compare(cx, src1, src2, rval);
|
||||
}
|
||||
|
||||
XPCLocaleCallbacks()
|
||||
#ifdef DEBUG
|
||||
: mThread(nullptr)
|
||||
#endif
|
||||
{
|
||||
MOZ_COUNT_CTOR(XPCLocaleCallbacks);
|
||||
|
||||
localeToUpperCase = LocaleToUpperCase;
|
||||
localeToLowerCase = LocaleToLowerCase;
|
||||
localeCompare = LocaleCompare;
|
||||
localeToUnicode = LocaleToUnicode;
|
||||
localeGetErrorMessage = nullptr;
|
||||
}
|
||||
|
||||
~XPCLocaleCallbacks()
|
||||
{
|
||||
MOZ_COUNT_DTOR(XPCLocaleCallbacks);
|
||||
AssertThreadSafety();
|
||||
*rval = INT_TO_JSVAL(result);
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
@ -217,161 +240,47 @@ struct XPCLocaleCallbacks : public JSLocaleCallbacks
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
Compare(JSContext *cx, JSString *src1, JSString *src2, jsval *rval)
|
||||
void AssertThreadSafety()
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
if (!mCollation) {
|
||||
nsCOMPtr<nsILocaleService> localeService =
|
||||
do_GetService(NS_LOCALESERVICE_CONTRACTID, &rv);
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
nsCOMPtr<nsILocale> locale;
|
||||
rv = localeService->GetApplicationLocale(getter_AddRefs(locale));
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
nsCOMPtr<nsICollationFactory> colFactory =
|
||||
do_CreateInstance(NS_COLLATIONFACTORY_CONTRACTID, &rv);
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
rv = colFactory->CreateCollation(locale, getter_AddRefs(mCollation));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
xpc::Throw(cx, rv);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
nsDependentJSString depStr1, depStr2;
|
||||
if (!depStr1.init(cx, src1) || !depStr2.init(cx, src2)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int32_t result;
|
||||
rv = mCollation->CompareString(nsICollation::kCollationStrengthDefault,
|
||||
depStr1, depStr2, &result);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
xpc::Throw(cx, rv);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
*rval = INT_TO_JSVAL(result);
|
||||
|
||||
return true;
|
||||
MOZ_ASSERT(mThread == PR_GetCurrentThread(),
|
||||
"XPCLocaleCallbacks used unsafely!");
|
||||
}
|
||||
|
||||
nsCOMPtr<nsICollation> mCollation;
|
||||
nsCOMPtr<nsIUnicodeDecoder> mDecoder;
|
||||
|
||||
#ifdef DEBUG
|
||||
PRThread* mThread;
|
||||
|
||||
// Assert that |this| being used in a way consistent with its
|
||||
// restrictions. If |this| hasn't been bound to a thread yet, then
|
||||
// it will be bound to calling thread.
|
||||
void AssertThreadSafety()
|
||||
{
|
||||
NS_ABORT_IF_FALSE(!mThread || mThread == PR_GetCurrentThread(),
|
||||
"XPCLocaleCallbacks used unsafely!");
|
||||
if (!mThread) {
|
||||
mThread = PR_GetCurrentThread();
|
||||
}
|
||||
}
|
||||
#else
|
||||
void AssertThreadSafety() { }
|
||||
#endif // DEBUG
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* There can only be one JSRuntime in which JSContexts are hooked with
|
||||
* XPCLocaleCallbacks. |sHookedRuntime| is it.
|
||||
*
|
||||
* Initializing the JSContextCallback must be thread safe.
|
||||
* |sOldContextCallback| and |sHookedRuntime| are protected by
|
||||
* |sHookRuntime|. After that, however, the context callback itself
|
||||
* doesn't need to be thread safe, since it operates on
|
||||
* JSContext-local data.
|
||||
*/
|
||||
static PRCallOnceType sHookRuntime;
|
||||
static JSContextCallback sOldContextCallback;
|
||||
#ifdef DEBUG
|
||||
static JSRuntime* sHookedRuntime;
|
||||
#endif // DEBUG
|
||||
|
||||
static JSBool
|
||||
DelocalizeContextCallback(JSContext *cx, unsigned contextOp)
|
||||
NS_EXPORT_(bool)
|
||||
xpc_LocalizeRuntime(JSRuntime *rt)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(JS_GetRuntime(cx) == sHookedRuntime, "unknown runtime!");
|
||||
JS_SetLocaleCallbacks(rt, new XPCLocaleCallbacks());
|
||||
|
||||
JSBool ok = true;
|
||||
if (sOldContextCallback && !sOldContextCallback(cx, contextOp)) {
|
||||
ok = false;
|
||||
// Even if the old callback fails, we still have to march on or
|
||||
// else we might leak the intl stuff hooked onto |cx|
|
||||
}
|
||||
// Set the default locale.
|
||||
nsCOMPtr<nsILocaleService> localeService =
|
||||
do_GetService(NS_LOCALESERVICE_CONTRACTID);
|
||||
if (!localeService)
|
||||
return false;
|
||||
|
||||
if (contextOp == JSCONTEXT_DESTROY) {
|
||||
if (XPCLocaleCallbacks* lc = XPCLocaleCallbacks::MaybeThis(cx)) {
|
||||
// This is a JSContext for which xpc_LocalizeContext() was called.
|
||||
JS_SetLocaleCallbacks(cx, nullptr);
|
||||
delete lc;
|
||||
}
|
||||
}
|
||||
nsCOMPtr<nsILocale> appLocale;
|
||||
nsresult rv = localeService->GetApplicationLocale(getter_AddRefs(appLocale));
|
||||
if (NS_FAILED(rv))
|
||||
return false;
|
||||
|
||||
return ok;
|
||||
}
|
||||
nsAutoString localeStr;
|
||||
rv = appLocale->GetCategory(NS_LITERAL_STRING(NSILOCALE_TIME), localeStr);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "failed to get app locale info");
|
||||
NS_LossyConvertUTF16toASCII locale(localeStr);
|
||||
|
||||
static PRStatus
|
||||
HookRuntime(void* arg)
|
||||
{
|
||||
JSRuntime* rt = static_cast<JSRuntime*>(arg);
|
||||
|
||||
NS_ABORT_IF_FALSE(!sHookedRuntime && !sOldContextCallback,
|
||||
"PRCallOnce called twice?");
|
||||
|
||||
// XXX it appears that in practice we only have to worry about
|
||||
// xpconnect's context hook, and it chains properly. However, it
|
||||
// *will* stomp our callback on shutdown.
|
||||
sOldContextCallback = JS_SetContextCallback(rt, DelocalizeContextCallback);
|
||||
#ifdef DEBUG
|
||||
sHookedRuntime = rt;
|
||||
#endif
|
||||
|
||||
return PR_SUCCESS;
|
||||
return !!JS_SetDefaultLocale(rt, locale.get());
|
||||
}
|
||||
|
||||
NS_EXPORT_(void)
|
||||
xpc_LocalizeContext(JSContext *cx)
|
||||
xpc_DelocalizeRuntime(JSRuntime *rt)
|
||||
{
|
||||
JSRuntime* rt = JS_GetRuntime(cx);
|
||||
PR_CallOnceWithArg(&sHookRuntime, HookRuntime, rt);
|
||||
|
||||
NS_ABORT_IF_FALSE(sHookedRuntime == rt, "created multiple JSRuntimes?");
|
||||
|
||||
JS_SetLocaleCallbacks(cx, new XPCLocaleCallbacks());
|
||||
|
||||
// set the context's default locale
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsILocaleService> localeService =
|
||||
do_GetService(NS_LOCALESERVICE_CONTRACTID, &rv);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
nsCOMPtr<nsILocale> appLocale;
|
||||
rv = localeService->GetApplicationLocale(getter_AddRefs(appLocale));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
nsAutoString localeStr;
|
||||
rv = appLocale->
|
||||
GetCategory(NS_LITERAL_STRING(NSILOCALE_TIME), localeStr);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "failed to get app locale info");
|
||||
NS_LossyConvertUTF16toASCII locale(localeStr);
|
||||
JS_SetDefaultLocale(cx, locale.get());
|
||||
}
|
||||
}
|
||||
XPCLocaleCallbacks* lc = XPCLocaleCallbacks::This(rt);
|
||||
JS_SetLocaleCallbacks(rt, nullptr);
|
||||
delete lc;
|
||||
}
|
||||
|
@ -62,9 +62,11 @@ GetXBLScope(JSContext *cx, JSObject *contentScope);
|
||||
void
|
||||
TraceXPCGlobal(JSTracer *trc, JSObject *obj);
|
||||
|
||||
// XXX where should this live?
|
||||
// XXX These should be moved into XPCJSRuntime!
|
||||
NS_EXPORT_(bool)
|
||||
xpc_LocalizeRuntime(JSRuntime *rt);
|
||||
NS_EXPORT_(void)
|
||||
xpc_LocalizeContext(JSContext *cx);
|
||||
xpc_DelocalizeRuntime(JSRuntime *rt);
|
||||
|
||||
nsresult
|
||||
xpc_MorphSlimWrapper(JSContext *cx, nsISupports *tomorph);
|
||||
|
Loading…
Reference in New Issue
Block a user