зеркало из https://github.com/mozilla/gecko-dev.git
Bug 616841, part 1: Refactor use of JSLocaleCallbacks to make them easier to share among various JSContexts. r=bz sr=mrbkap
This commit is contained in:
Родитель
6392eab70e
Коммит
1fa69fd283
|
@ -84,14 +84,6 @@
|
|||
#include "nsXPCOMCIDInternal.h"
|
||||
#include "nsIXULRuntime.h"
|
||||
|
||||
// For locale aware string methods
|
||||
#include "plstr.h"
|
||||
#include "nsIPlatformCharset.h"
|
||||
#include "nsICharsetConverterManager.h"
|
||||
#include "nsUnicharUtils.h"
|
||||
#include "nsILocaleService.h"
|
||||
#include "nsICollation.h"
|
||||
#include "nsCollationCID.h"
|
||||
#include "nsDOMClassInfo.h"
|
||||
|
||||
#include "jsdbgapi.h" // for JS_ClearWatchPointsForObject
|
||||
|
@ -224,10 +216,6 @@ static PRTime sMaxChromeScriptRunTime;
|
|||
|
||||
static nsIScriptSecurityManager *sSecurityManager;
|
||||
|
||||
static nsICollation *gCollation;
|
||||
|
||||
static nsIUnicodeDecoder *gDecoder;
|
||||
|
||||
// nsUserActivityObserver observes user-interaction-active and
|
||||
// user-interaction-inactive notifications. It counts the number of
|
||||
// notifications and if the number is bigger than NS_CC_SOFT_LIMIT_ACTIVE
|
||||
|
@ -644,166 +632,6 @@ NS_ScriptErrorReporter(JSContext *cx,
|
|||
#endif
|
||||
}
|
||||
|
||||
static JSBool
|
||||
LocaleToUnicode(JSContext *cx, const char *src, jsval *rval)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
if (!gDecoder) {
|
||||
// use app default locale
|
||||
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");
|
||||
|
||||
nsCOMPtr<nsIPlatformCharset> platformCharset =
|
||||
do_GetService(NS_PLATFORMCHARSET_CONTRACTID, &rv);
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
nsCAutoString charset;
|
||||
rv = platformCharset->GetDefaultCharsetForLocale(localeStr, charset);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// get/create unicode decoder for charset
|
||||
nsCOMPtr<nsICharsetConverterManager> ccm =
|
||||
do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
ccm->GetUnicodeDecoder(charset.get(), &gDecoder);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JSString *str = nsnull;
|
||||
PRInt32 srcLength = PL_strlen(src);
|
||||
|
||||
if (gDecoder) {
|
||||
PRInt32 unicharLength = srcLength;
|
||||
PRUnichar *unichars =
|
||||
(PRUnichar *)JS_malloc(cx, (srcLength + 1) * sizeof(PRUnichar));
|
||||
if (unichars) {
|
||||
rv = gDecoder->Convert(src, &srcLength, unichars, &unicharLength);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// terminate the returned string
|
||||
unichars[unicharLength] = 0;
|
||||
|
||||
// nsIUnicodeDecoder::Convert may use fewer than srcLength PRUnichars
|
||||
if (unicharLength + 1 < srcLength + 1) {
|
||||
PRUnichar *shrunkUnichars =
|
||||
(PRUnichar *)JS_realloc(cx, unichars,
|
||||
(unicharLength + 1) * sizeof(PRUnichar));
|
||||
if (shrunkUnichars)
|
||||
unichars = shrunkUnichars;
|
||||
}
|
||||
str = JS_NewUCString(cx,
|
||||
reinterpret_cast<jschar*>(unichars),
|
||||
unicharLength);
|
||||
}
|
||||
if (!str)
|
||||
JS_free(cx, unichars);
|
||||
}
|
||||
}
|
||||
|
||||
if (!str) {
|
||||
nsDOMClassInfo::ThrowJSException(cx, NS_ERROR_OUT_OF_MEMORY);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
*rval = STRING_TO_JSVAL(str);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
|
||||
static JSBool
|
||||
ChangeCase(JSContext *cx, JSString *src, jsval *rval,
|
||||
void(* changeCaseFnc)(const nsAString&, nsAString&))
|
||||
{
|
||||
nsDependentJSString depStr;
|
||||
if (!depStr.init(cx, src)) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
nsAutoString result;
|
||||
changeCaseFnc(depStr, result);
|
||||
|
||||
JSString *ucstr = JS_NewUCStringCopyN(cx, (jschar*)result.get(), result.Length());
|
||||
if (!ucstr) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
*rval = STRING_TO_JSVAL(ucstr);
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
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
|
||||
LocaleCompare(JSContext *cx, JSString *src1, JSString *src2, jsval *rval)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
if (!gCollation) {
|
||||
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, &gCollation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
nsDOMClassInfo::ThrowJSException(cx, rv);
|
||||
|
||||
return JS_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
nsDependentJSString depStr1, depStr2;
|
||||
if (!depStr1.init(cx, src1) || !depStr2.init(cx, src2)) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
PRInt32 result;
|
||||
rv = gCollation->CompareString(nsICollation::kCollationStrengthDefault,
|
||||
depStr1, depStr2, &result);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
nsDOMClassInfo::ThrowJSException(cx, rv);
|
||||
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
*rval = INT_TO_JSVAL(result);
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
// A couple of useful functions to call when you're debugging.
|
||||
nsGlobalWindow *
|
||||
|
@ -1311,15 +1139,7 @@ nsJSContext::nsJSContext(JSRuntime *aRuntime)
|
|||
|
||||
::JS_SetOperationCallback(mContext, DOMOperationCallback);
|
||||
|
||||
static JSLocaleCallbacks localeCallbacks =
|
||||
{
|
||||
LocaleToUpperCase,
|
||||
LocaleToLowerCase,
|
||||
LocaleCompare,
|
||||
LocaleToUnicode
|
||||
};
|
||||
|
||||
::JS_SetLocaleCallbacks(mContext, &localeCallbacks);
|
||||
xpc_LocalizeContext(mContext);
|
||||
}
|
||||
mIsInitialized = PR_FALSE;
|
||||
mTerminations = nsnull;
|
||||
|
@ -1350,8 +1170,6 @@ nsJSContext::~nsJSContext()
|
|||
|
||||
NS_IF_RELEASE(sRuntimeService);
|
||||
NS_IF_RELEASE(sSecurityManager);
|
||||
NS_IF_RELEASE(gCollation);
|
||||
NS_IF_RELEASE(gDecoder);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3952,7 +3770,6 @@ nsJSRuntime::Startup()
|
|||
sDidShutdown = PR_FALSE;
|
||||
sContextCount = 0;
|
||||
sSecurityManager = nsnull;
|
||||
gCollation = nsnull;
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -4240,8 +4057,6 @@ nsJSRuntime::Shutdown()
|
|||
}
|
||||
NS_IF_RELEASE(sRuntimeService);
|
||||
NS_IF_RELEASE(sSecurityManager);
|
||||
NS_IF_RELEASE(gCollation);
|
||||
NS_IF_RELEASE(gDecoder);
|
||||
}
|
||||
|
||||
sDidShutdown = PR_TRUE;
|
||||
|
|
|
@ -78,6 +78,7 @@
|
|||
#include "nsCOMPtr.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsIXPCSecurityManager.h"
|
||||
#include "xpcpublic.h"
|
||||
#ifdef XP_MACOSX
|
||||
#include "xpcshellMacUtils.h"
|
||||
#endif
|
||||
|
@ -1902,6 +1903,8 @@ main(int argc, char **argv)
|
|||
return 1;
|
||||
}
|
||||
|
||||
xpc_LocalizeContext(cx);
|
||||
|
||||
nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID());
|
||||
if (!xpc) {
|
||||
printf("failed to get nsXPConnect service!\n");
|
||||
|
|
|
@ -75,6 +75,7 @@ CPPSRCS = \
|
|||
xpcexception.cpp \
|
||||
xpcjsid.cpp \
|
||||
xpcjsruntime.cpp \
|
||||
xpclocale.cpp \
|
||||
xpclog.cpp \
|
||||
xpcmaps.cpp \
|
||||
xpcmodule.cpp \
|
||||
|
|
|
@ -0,0 +1,392 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: sw=2 ts=8 et :
|
||||
*/
|
||||
/* ***** 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 Mozilla Code.
|
||||
*
|
||||
* 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):
|
||||
* Chris Jones <jones.chris.g@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 "prinit.h"
|
||||
#include "plstr.h"
|
||||
|
||||
#include "jsapi.h"
|
||||
|
||||
#include "nsCollationCID.h"
|
||||
#include "nsDOMClassInfo.h"
|
||||
#include "nsJSUtils.h"
|
||||
#include "nsICharsetConverterManager.h"
|
||||
#include "nsIPlatformCharset.h"
|
||||
#include "nsILocaleService.h"
|
||||
#include "nsICollation.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsUnicharUtils.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.
|
||||
*/
|
||||
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)
|
||||
{
|
||||
JSLocaleCallbacks* lc = JS_GetLocaleCallbacks(cx);
|
||||
return (lc &&
|
||||
lc->localeToUpperCase == LocaleToUpperCase &&
|
||||
lc->localeToLowerCase == LocaleToLowerCase &&
|
||||
lc->localeCompare == LocaleCompare &&
|
||||
lc->localeToUnicode == LocaleToUnicode) ? This(cx) : nsnull;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
ChangeCase(JSContext* cx, JSString* src, jsval* rval,
|
||||
void(*changeCaseFnc)(const nsAString&, nsAString&))
|
||||
{
|
||||
nsDependentJSString depStr;
|
||||
if (!depStr.init(cx, src)) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
nsAutoString result;
|
||||
changeCaseFnc(depStr, result);
|
||||
|
||||
JSString *ucstr =
|
||||
JS_NewUCStringCopyN(cx, (jschar*)result.get(), result.Length());
|
||||
if (!ucstr) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
*rval = STRING_TO_JSVAL(ucstr);
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
LocaleToUnicode(JSContext* cx, const char* src, jsval* rval)
|
||||
{
|
||||
return This(cx)->ToUnicode(cx, src, rval);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
LocaleCompare(JSContext *cx, JSString *src1, JSString *src2, jsval *rval)
|
||||
{
|
||||
return This(cx)->Compare(cx, src1, src2, rval);
|
||||
}
|
||||
|
||||
XPCLocaleCallbacks()
|
||||
#ifdef DEBUG
|
||||
: mThread(nsnull)
|
||||
#endif
|
||||
{
|
||||
MOZ_COUNT_CTOR(XPCLocaleCallbacks);
|
||||
|
||||
localeToUpperCase = LocaleToUpperCase;
|
||||
localeToLowerCase = LocaleToLowerCase;
|
||||
localeCompare = LocaleCompare;
|
||||
localeToUnicode = LocaleToUnicode;
|
||||
localeGetErrorMessage = nsnull;
|
||||
}
|
||||
|
||||
~XPCLocaleCallbacks()
|
||||
{
|
||||
MOZ_COUNT_DTOR(XPCLocaleCallbacks);
|
||||
AssertThreadSafety();
|
||||
}
|
||||
|
||||
JSBool
|
||||
ToUnicode(JSContext* cx, const char* src, jsval* rval)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
if (!mDecoder) {
|
||||
// use app default locale
|
||||
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");
|
||||
|
||||
nsCOMPtr<nsIPlatformCharset> platformCharset =
|
||||
do_GetService(NS_PLATFORMCHARSET_CONTRACTID, &rv);
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
nsCAutoString charset;
|
||||
rv = platformCharset->GetDefaultCharsetForLocale(localeStr, charset);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// get/create unicode decoder for charset
|
||||
nsCOMPtr<nsICharsetConverterManager> ccm =
|
||||
do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
ccm->GetUnicodeDecoder(charset.get(), getter_AddRefs(mDecoder));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JSString *str = nsnull;
|
||||
PRInt32 srcLength = PL_strlen(src);
|
||||
|
||||
if (mDecoder) {
|
||||
PRInt32 unicharLength = srcLength;
|
||||
PRUnichar *unichars =
|
||||
(PRUnichar *)JS_malloc(cx, (srcLength + 1) * sizeof(PRUnichar));
|
||||
if (unichars) {
|
||||
rv = mDecoder->Convert(src, &srcLength, unichars, &unicharLength);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// terminate the returned string
|
||||
unichars[unicharLength] = 0;
|
||||
|
||||
// nsIUnicodeDecoder::Convert may use fewer than srcLength PRUnichars
|
||||
if (unicharLength + 1 < srcLength + 1) {
|
||||
PRUnichar *shrunkUnichars =
|
||||
(PRUnichar *)JS_realloc(cx, unichars,
|
||||
(unicharLength + 1) * sizeof(PRUnichar));
|
||||
if (shrunkUnichars)
|
||||
unichars = shrunkUnichars;
|
||||
}
|
||||
str = JS_NewUCString(cx,
|
||||
reinterpret_cast<jschar*>(unichars),
|
||||
unicharLength);
|
||||
}
|
||||
if (!str)
|
||||
JS_free(cx, unichars);
|
||||
}
|
||||
}
|
||||
|
||||
if (!str) {
|
||||
nsDOMClassInfo::ThrowJSException(cx, NS_ERROR_OUT_OF_MEMORY);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
*rval = STRING_TO_JSVAL(str);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
JSBool
|
||||
Compare(JSContext *cx, JSString *src1, JSString *src2, jsval *rval)
|
||||
{
|
||||
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)) {
|
||||
nsDOMClassInfo::ThrowJSException(cx, rv);
|
||||
|
||||
return JS_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
nsDependentJSString depStr1, depStr2;
|
||||
if (!depStr1.init(cx, src1) || !depStr2.init(cx, src2)) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
PRInt32 result;
|
||||
rv = mCollation->CompareString(nsICollation::kCollationStrengthDefault,
|
||||
depStr1, depStr2, &result);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
nsDOMClassInfo::ThrowJSException(cx, rv);
|
||||
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
*rval = INT_TO_JSVAL(result);
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* 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, uintN contextOp)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(JS_GetRuntime(cx) == sHookedRuntime, "unknown runtime!");
|
||||
|
||||
JSBool ok = JS_TRUE;
|
||||
if (sOldContextCallback && !sOldContextCallback(cx, contextOp)) {
|
||||
ok = JS_FALSE;
|
||||
// Even if the old callback fails, we still have to march on or
|
||||
// else we might leak the intl stuff hooked onto |cx|
|
||||
}
|
||||
|
||||
if (contextOp == JSCONTEXT_DESTROY) {
|
||||
if (XPCLocaleCallbacks* lc = XPCLocaleCallbacks::MaybeThis(cx)) {
|
||||
// This is a JSContext for which xpc_LocalizeContext() was called.
|
||||
JS_SetLocaleCallbacks(cx, nsnull);
|
||||
delete lc;
|
||||
}
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
NS_EXPORT_(void)
|
||||
xpc_LocalizeContext(JSContext *cx)
|
||||
{
|
||||
JSRuntime* rt = JS_GetRuntime(cx);
|
||||
PR_CallOnceWithArg(&sHookRuntime, HookRuntime, rt);
|
||||
|
||||
NS_ABORT_IF_FALSE(sHookedRuntime == rt, "created multiple JSRuntimes?");
|
||||
|
||||
JS_SetLocaleCallbacks(cx, new XPCLocaleCallbacks());
|
||||
}
|
|
@ -43,7 +43,6 @@
|
|||
#include "jsapi.h"
|
||||
#include "nsISupports.h"
|
||||
#include "jsobj.h"
|
||||
#include "nsAString.h"
|
||||
#include "nsIPrincipal.h"
|
||||
#include "nsWrapperCache.h"
|
||||
|
||||
|
@ -60,6 +59,10 @@ xpc_CreateMTGlobalObject(JSContext *cx, JSClass *clasp,
|
|||
nsISupports *ptr, JSObject **global,
|
||||
JSCompartment **compartment);
|
||||
|
||||
// XXX where should this live?
|
||||
NS_EXPORT_(void)
|
||||
xpc_LocalizeContext(JSContext *cx);
|
||||
|
||||
nsresult
|
||||
xpc_MorphSlimWrapper(JSContext *cx, nsISupports *tomorph);
|
||||
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
function run_test() {
|
||||
do_check_true("C".localeCompare("D") < 0);
|
||||
do_check_true("D".localeCompare("C") > 0);
|
||||
do_check_true("\u010C".localeCompare("D") < 0);
|
||||
do_check_true("D".localeCompare("\u010C") > 0);
|
||||
}
|
Загрузка…
Ссылка в новой задаче