Bug 204114 - "nsUnicharUtils need to be threadsafe". r=bsmedberg.

This commit is contained in:
bent.mozilla%gmail.com 2006-09-27 17:44:27 +00:00
Родитель f6951f1107
Коммит 97a1e5a9e2
2 изменённых файлов: 247 добавлений и 204 удалений

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

@ -22,6 +22,7 @@
* Contributor(s):
* Alec Flett <alecf@netscape.com>
* Benjamin Smedberg <benjamin@smedbergs.us>
* Ben Turner <mozilla@songbirdnest.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
@ -39,180 +40,218 @@
#include "nsUnicharUtils.h"
#include "nsUnicharUtilCIID.h"
#include "nsICaseConversion.h"
#include "nsIServiceManager.h"
#include "nsServiceManagerUtils.h"
#include "nsCOMPtr.h"
#include "nsCRTGlue.h"
#include "nsXPCOMStrings.h"
#include "nsICaseConversion.h"
#include "nsIObserver.h"
#include "nsIObserverService.h"
#include "nsIServiceManager.h"
#include "nsServiceManagerUtils.h"
#include "nsThreadUtils.h"
#include "nsXPCOMCID.h"
#include "nsXPCOMStrings.h"
#include <ctype.h>
// global cache of the case conversion service
// global cache of the case conversion service, set only on the main thread
static nsICaseConversion *gCaseConv = nsnull;
class nsShutdownObserver : public nsIObserver
{
public:
nsShutdownObserver() { }
virtual ~nsShutdownObserver() {}
NS_DECL_ISUPPORTS
NS_IMETHOD Observe(nsISupports *aSubject, const char *aTopic,
const PRUnichar *aData)
{
if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)==0) {
NS_IF_RELEASE(gCaseConv);
}
return NS_OK;
}
nsShutdownObserver() { }
virtual ~nsShutdownObserver() {}
NS_DECL_ISUPPORTS
NS_IMETHOD Observe(nsISupports *aSubject,
const char *aTopic,
const PRUnichar *aData)
{
if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)==0)
NS_IF_RELEASE(gCaseConv);
return NS_OK;
}
};
NS_IMPL_THREADSAFE_ISUPPORTS1(nsShutdownObserver, nsIObserver)
static nsresult NS_InitCaseConversion() {
if (gCaseConv)
return NS_OK;
nsresult rv = CallGetService(NS_UNICHARUTIL_CONTRACTID, &gCaseConv);
if (NS_FAILED(rv)) {
gCaseConv = nsnull;
return rv;
}
already_AddRefed<nsICaseConversion>
NS_GetCaseConversion()
{
// If we've already cached the conversion service then return it
if (gCaseConv) {
NS_ADDREF(gCaseConv);
return gCaseConv;
}
nsCOMPtr<nsIObserverService> obs =
do_GetService("@mozilla.org/observer-service;1", &rv);
if (NS_SUCCEEDED(rv)) {
nsCOMPtr<nsIObserver> observer;
NS_NEWXPCOM(observer, nsShutdownObserver);
if (observer)
obs->AddObserver(observer, NS_XPCOM_SHUTDOWN_OBSERVER_ID,
PR_FALSE);
}
return NS_OK;
// If we're on a non-main thread then just return the service manager's copy
nsresult rv;
if (!NS_IsMainThread()) {
nsICaseConversion* caseConv;
rv = CallGetService(NS_UNICHARUTIL_CONTRACTID, &caseConv);
if (NS_FAILED(rv)) {
NS_WARNING("Failed to get the case conversion service");
return nsnull;
}
return caseConv;
}
// We must be on the main thread so try to cache the service and register a
// shutdown observer.
// Return null if we can't get the service
rv = CallGetService(NS_UNICHARUTIL_CONTRACTID, &gCaseConv);
if (NS_FAILED(rv)) {
NS_WARNING("Failed to get the case conversion service");
return gCaseConv = nsnull;
}
NS_ADDREF(gCaseConv);
nsCOMPtr<nsIObserverService> obs =
do_GetService(NS_OBSERVERSERVICE_CONTRACTID, &rv);
// Try to register for shutdown notification, but we'll return a valid
// pointer even if that fails.
if (NS_SUCCEEDED(rv)) {
nsCOMPtr<nsIObserver> observer;
NS_NEWXPCOM(observer, nsShutdownObserver);
if (observer)
obs->AddObserver(observer, NS_XPCOM_SHUTDOWN_OBSERVER_ID, PR_FALSE);
else
NS_WARNING("Failed to create an nsShutdownObserver");
}
else
NS_WARNING("Failed to get the observer service");
return gCaseConv;
}
void
ToLowerCase( nsAString& aString )
{
NS_InitCaseConversion();
if (gCaseConv) {
PRUnichar *buf = aString.BeginWriting();
gCaseConv->ToLower(buf, buf, aString.Length());
}
else
NS_WARNING("No case converter: no conversion done");
ToLowerCase(nsAString& aString)
{
nsCOMPtr<nsICaseConversion> caseConv = NS_GetCaseConversion();
if (caseConv) {
PRUnichar *buf = aString.BeginWriting();
caseConv->ToLower(buf, buf, aString.Length());
}
else
NS_WARNING("No case converter: no conversion done");
}
void
ToLowerCase( const nsAString& aSource, nsAString& aDest )
{
NS_InitCaseConversion();
ToLowerCase(const nsAString& aSource,
nsAString& aDest)
{
const PRUnichar *in;
PRUint32 len = NS_StringGetData(aSource, &in);
const PRUnichar *in;
PRUint32 len = NS_StringGetData(aSource, &in);
PRUnichar *out;
NS_StringGetMutableData(aDest, len, &out);
PRUnichar *out;
NS_StringGetMutableData(aDest, len, &out);
if (out && gCaseConv) {
gCaseConv->ToLower(in, out, len);
}
else {
NS_WARNING("No case converter: only copying");
aDest.Assign(aSource);
}
nsCOMPtr<nsICaseConversion> caseConv = NS_GetCaseConversion();
if (out && caseConv)
caseConv->ToLower(in, out, len);
else {
NS_WARNING("No case converter: only copying");
aDest.Assign(aSource);
}
}
void
ToUpperCase( nsAString& aString )
{
NS_InitCaseConversion();
if (gCaseConv) {
PRUnichar *buf = aString.BeginWriting();
gCaseConv->ToUpper(buf, buf, aString.Length());
}
else
NS_WARNING("No case converter: no conversion done");
ToUpperCase(nsAString& aString)
{
nsCOMPtr<nsICaseConversion> caseConv = NS_GetCaseConversion();
if (caseConv) {
PRUnichar *buf = aString.BeginWriting();
caseConv->ToUpper(buf, buf, aString.Length());
}
else
NS_WARNING("No case converter: no conversion done");
}
void
ToUpperCase( const nsAString& aSource, nsAString& aDest )
{
NS_InitCaseConversion();
ToUpperCase(const nsAString& aSource,
nsAString& aDest)
{
const PRUnichar *in;
PRUint32 len = NS_StringGetData(aSource, &in);
const PRUnichar *in;
PRUint32 len = NS_StringGetData(aSource, &in);
PRUnichar *out;
NS_StringGetMutableData(aDest, len, &out);
PRUnichar *out;
NS_StringGetMutableData(aDest, len, &out);
if (out && gCaseConv) {
gCaseConv->ToUpper(in, out, len);
}
else {
NS_WARNING("No case converter: only copying");
aDest.Assign(aSource);
}
nsCOMPtr<nsICaseConversion> caseConv = NS_GetCaseConversion();
if (out && caseConv)
caseConv->ToUpper(in, out, len);
else {
NS_WARNING("No case converter: only copying");
aDest.Assign(aSource);
}
}
#ifdef MOZILLA_INTERNAL_API
int
nsCaseInsensitiveStringComparator::operator()( const PRUnichar* lhs, const PRUnichar* rhs, PRUint32 aLength ) const
{
NS_InitCaseConversion();
PRInt32 result;
if (gCaseConv) {
gCaseConv->CaseInsensitiveCompare(lhs, rhs, aLength, &result);
}
else {
NS_WARNING("No case converter: using default");
nsDefaultStringComparator comparator;
result = comparator(lhs, rhs, aLength);
}
return result;
}
int
nsCaseInsensitiveStringComparator::operator()( PRUnichar lhs, PRUnichar rhs ) const
{
// see if they're an exact match first
if (lhs == rhs) return 0;
NS_InitCaseConversion();
if (gCaseConv) {
gCaseConv->ToLower(lhs, &lhs);
gCaseConv->ToLower(rhs, &rhs);
} else {
if (lhs < 256)
lhs = tolower(char(lhs));
if (rhs < 256)
rhs = tolower(char(rhs));
NS_WARNING("No case converter: no conversion done");
}
if (lhs == rhs) return 0;
if (lhs < rhs) return -1;
return 1;
}
#else
PRInt32
CaseInsensitiveCompare(const PRUnichar *a, const PRUnichar *b, PRUint32 len)
nsCaseInsensitiveStringComparator::operator()(const PRUnichar* lhs,
const PRUnichar* rhs,
PRUint32 aLength) const
{
if (NS_FAILED(NS_InitCaseConversion()))
return NS_strcmp(a, b);
PRInt32 result;
nsCOMPtr<nsICaseConversion> caseConv = NS_GetCaseConversion();
if (caseConv)
caseConv->CaseInsensitiveCompare(lhs, rhs, aLength, &result);
else {
NS_WARNING("No case converter: using default");
nsDefaultStringComparator comparator;
result = comparator(lhs, rhs, aLength);
}
return result;
}
PRInt32 result;
gCaseConv->CaseInsensitiveCompare(a, b, len, &result);
return result;
PRInt32
nsCaseInsensitiveStringComparator::operator()(PRUnichar lhs,
PRUnichar rhs) const
{
// see if they're an exact match first
if (lhs == rhs)
return 0;
nsCOMPtr<nsICaseConversion> caseConv = NS_GetCaseConversion();
if (caseConv) {
caseConv->ToLower(lhs, &lhs);
caseConv->ToLower(rhs, &rhs);
}
else {
if (lhs < 256)
lhs = tolower(char(lhs));
if (rhs < 256)
rhs = tolower(char(rhs));
NS_WARNING("No case converter: no conversion done");
}
if (lhs == rhs)
return 0;
else if (lhs < rhs)
return -1;
else
return 1;
}
#else // MOZILLA_INTERNAL_API
PRInt32
CaseInsensitiveCompare(const PRUnichar *a,
const PRUnichar *b,
PRUint32 len)
{
nsCOMPtr<nsICaseConversion> caseConv = NS_GetCaseConversion();
if (!caseConv)
return NS_strcmp(a, b);
PRInt32 result;
caseConv->CaseInsensitiveCompare(a, b, len, &result);
return result;
}
#endif // MOZILLA_INTERNAL_API
@ -220,38 +259,33 @@ CaseInsensitiveCompare(const PRUnichar *a, const PRUnichar *b, PRUint32 len)
PRUnichar
ToLowerCase(PRUnichar aChar)
{
PRUnichar result;
if (NS_FAILED(NS_InitCaseConversion()))
return aChar;
if (gCaseConv)
gCaseConv->ToLower(aChar, &result);
else {
NS_WARNING("No case converter: no conversion done");
if (aChar < 256)
result = tolower(char(aChar));
else
result = aChar;
}
return result;
PRUnichar result;
nsCOMPtr<nsICaseConversion> caseConv = NS_GetCaseConversion();
if (caseConv)
caseConv->ToLower(aChar, &result);
else {
NS_WARNING("No case converter: no conversion done");
if (aChar < 256)
result = tolower(char(aChar));
else
result = aChar;
}
return result;
}
PRUnichar
ToUpperCase(PRUnichar aChar)
{
PRUnichar result;
if (NS_FAILED(NS_InitCaseConversion()))
return aChar;
if (gCaseConv)
gCaseConv->ToUpper(aChar, &result);
else {
NS_WARNING("No case converter: no conversion done");
if (aChar < 256)
result = toupper(char(aChar));
else
result = aChar;
}
return result;
PRUnichar result;
nsCOMPtr<nsICaseConversion> caseConv = NS_GetCaseConversion();
if (caseConv)
caseConv->ToUpper(aChar, &result);
else {
NS_WARNING("No case converter: no conversion done");
if (aChar < 256)
result = toupper(char(aChar));
else
result = aChar;
}
return result;
}

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

@ -42,58 +42,67 @@
#include "nsStringGlue.h"
void ToLowerCase( nsAString& );
void ToUpperCase( nsAString& );
/* (0x3131u <= (u) && (u) <= 0x318eu) => Hangul Compatibility Jamo */
/* (0xac00u <= (u) && (u) <= 0xd7a3u) => Hangul Syllables */
#define IS_CJ_CHAR(u) \
((0x2e80u <= (u) && (u) <= 0x312fu) || \
(0x3190u <= (u) && (u) <= 0xabffu) || \
(0xf900u <= (u) && (u) <= 0xfaffu) || \
(0xff00u <= (u) && (u) <= 0xffefu) )
void ToLowerCase( const nsAString& aSource, nsAString& aDest );
void ToUpperCase( const nsAString& aSource, nsAString& aDest );
void ToLowerCase(nsAString&);
void ToUpperCase(nsAString&);
#ifdef MOZILLA_INTERNAL_API
class nsCaseInsensitiveStringComparator
: public nsStringComparator
{
public:
virtual int operator()( const PRUnichar*, const PRUnichar*, PRUint32 aLength ) const;
virtual int operator()( PRUnichar, PRUnichar ) const;
};
inline PRBool CaseInsensitiveFindInReadable( const nsAString& aPattern,
nsAString::const_iterator& aSearchStart,
nsAString::const_iterator& aSearchEnd ) {
return FindInReadable(aPattern, aSearchStart, aSearchEnd,
nsCaseInsensitiveStringComparator());
}
inline PRBool CaseInsensitiveFindInReadable( const nsAString& aPattern,
const nsAString& aHay ) {
nsAString::const_iterator searchBegin, searchEnd;
return FindInReadable(aPattern,
aHay.BeginReading(searchBegin),
aHay.EndReading(searchEnd),
nsCaseInsensitiveStringComparator());
}
#else
NS_HIDDEN_(PRInt32)
CaseInsensitiveCompare(const PRUnichar *a, const PRUnichar *b, PRUint32 len);
#endif // MOZILLA_INTERNAL_API
void ToLowerCase(const nsAString& aSource, nsAString& aDest);
void ToUpperCase(const nsAString& aSource, nsAString& aDest);
PRUnichar ToUpperCase(PRUnichar);
PRUnichar ToLowerCase(PRUnichar);
inline PRBool IsUpperCase(PRUnichar c) {
return ToLowerCase(c) != c;
return ToLowerCase(c) != c;
}
inline PRBool IsLowerCase(PRUnichar c) {
return ToUpperCase(c) != c;
return ToUpperCase(c) != c;
}
/* (0x3131u <= (u) && (u) <= 0x318eu) => Hangul Compatibility Jamo */
/* (0xac00u <= (u) && (u) <= 0xd7a3u) => Hangul Syllables */
#define IS_CJ_CHAR(u) \
((0x2e80u <= (u) && (u) <= 0x312fu) || \
(0x3190u <= (u) && (u) <= 0xabffu) || \
(0xf900u <= (u) && (u) <= 0xfaffu) || \
(0xff00u <= (u) && (u) <= 0xffefu) )
#ifdef MOZILLA_INTERNAL_API
class nsCaseInsensitiveStringComparator : public nsStringComparator
{
public:
virtual int operator() (const PRUnichar*,
const PRUnichar*,
PRUint32 aLength) const;
virtual int operator() (PRUnichar,
PRUnichar) const;
};
inline PRBool
CaseInsensitiveFindInReadable(const nsAString& aPattern,
nsAString::const_iterator& aSearchStart,
nsAString::const_iterator& aSearchEnd)
{
return FindInReadable(aPattern, aSearchStart, aSearchEnd,
nsCaseInsensitiveStringComparator());
}
inline PRBool
CaseInsensitiveFindInReadable(const nsAString& aPattern,
const nsAString& aHay)
{
nsAString::const_iterator searchBegin, searchEnd;
return FindInReadable(aPattern, aHay.BeginReading(searchBegin),
aHay.EndReading(searchEnd),
nsCaseInsensitiveStringComparator());
}
#else // MOZILLA_INTERNAL_API
NS_HIDDEN_(PRInt32)
CaseInsensitiveCompare(const PRUnichar *a, const PRUnichar *b, PRUint32 len);
#endif // MOZILLA_INTERNAL_API
#endif /* nsUnicharUtils_h__ */