зеркало из https://github.com/mozilla/gecko-dev.git
Bug 871846 - ICU usage and infrastructure bits. r=janv
This commit is contained in:
Родитель
54d10b79b5
Коммит
dd7ac5dc3c
|
@ -52,6 +52,11 @@
|
|||
#include "mozilla/dom/IDBTransactionBinding.h"
|
||||
#include "mozilla/dom/IDBVersionChangeEventBinding.h"
|
||||
|
||||
#ifdef ENABLE_INTL_API
|
||||
#include "nsCharSeparatedTokenizer.h"
|
||||
#include "unicode/locid.h"
|
||||
#endif
|
||||
|
||||
#define IDB_STR "indexedDB"
|
||||
|
||||
// The two possible values for the data argument when receiving the disk space
|
||||
|
@ -394,6 +399,27 @@ IndexedDatabaseManager::Init()
|
|||
Preferences::RegisterCallbackAndCall(LoggingModePrefChangedCallback,
|
||||
kPrefLoggingEnabled);
|
||||
|
||||
#ifdef ENABLE_INTL_API
|
||||
const nsAdoptingCString& acceptLang =
|
||||
Preferences::GetLocalizedCString("intl.accept_languages");
|
||||
|
||||
// Split values on commas.
|
||||
nsCCharSeparatedTokenizer langTokenizer(acceptLang, ',');
|
||||
while (langTokenizer.hasMoreTokens()) {
|
||||
nsAutoCString lang(langTokenizer.nextToken());
|
||||
icu::Locale locale = icu::Locale::createCanonical(lang.get());
|
||||
if (!locale.isBogus()) {
|
||||
// icu::Locale::getBaseName is always ASCII as per BCP 47
|
||||
mLocale.AssignASCII(locale.getBaseName());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (mLocale.IsEmpty()) {
|
||||
mLocale.AssignLiteral("en-US");
|
||||
}
|
||||
#endif
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -953,6 +979,18 @@ IndexedDatabaseManager::LoggingModePrefChangedCallback(
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef ENABLE_INTL_API
|
||||
// static
|
||||
const nsCString&
|
||||
IndexedDatabaseManager::GetLocale()
|
||||
{
|
||||
IndexedDatabaseManager* idbManager = Get();
|
||||
MOZ_ASSERT(idbManager, "IDBManager is not ready!");
|
||||
|
||||
return idbManager->mLocale;
|
||||
}
|
||||
#endif
|
||||
|
||||
NS_IMPL_ADDREF(IndexedDatabaseManager)
|
||||
NS_IMPL_RELEASE_WITH_DESTROY(IndexedDatabaseManager, Destroy())
|
||||
NS_IMPL_QUERY_INTERFACE(IndexedDatabaseManager, nsIObserver, nsITimerCallback)
|
||||
|
|
|
@ -158,6 +158,11 @@ public:
|
|||
nsresult
|
||||
FlushPendingFileDeletions();
|
||||
|
||||
#ifdef ENABLE_INTL_API
|
||||
static const nsCString&
|
||||
GetLocale();
|
||||
#endif
|
||||
|
||||
static mozilla::Mutex&
|
||||
FileMutex()
|
||||
{
|
||||
|
@ -200,6 +205,10 @@ private:
|
|||
// and FileInfo.mSliceRefCnt
|
||||
mozilla::Mutex mFileMutex;
|
||||
|
||||
#ifdef ENABLE_INTL_API
|
||||
nsCString mLocale;
|
||||
#endif
|
||||
|
||||
static bool sIsMainProcess;
|
||||
static bool sFullSynchronousMode;
|
||||
static PRLogModuleInfo* sLoggingModule;
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "Key.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include "IndexedDatabaseManager.h"
|
||||
#include "js/Date.h"
|
||||
#include "js/Value.h"
|
||||
#include "jsfriendapi.h"
|
||||
|
@ -20,6 +21,10 @@
|
|||
#include "ReportInternalError.h"
|
||||
#include "xpcpublic.h"
|
||||
|
||||
#ifdef ENABLE_INTL_API
|
||||
#include "unicode/ucol.h"
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace indexedDB {
|
||||
|
@ -98,6 +103,101 @@ namespace indexedDB {
|
|||
[1, 2] // 0x60 bf f0 0 0 0 0 0 0 0x10 c0
|
||||
[[]] // 0x80
|
||||
*/
|
||||
#ifdef ENABLE_INTL_API
|
||||
nsresult
|
||||
Key::ToLocaleBasedKey(Key& aTarget, const nsCString& aLocale) const
|
||||
{
|
||||
if (IsUnset()) {
|
||||
aTarget.Unset();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (IsFloat() || IsDate()) {
|
||||
aTarget.mBuffer = mBuffer;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
aTarget.mBuffer.Truncate();
|
||||
aTarget.mBuffer.SetCapacity(mBuffer.Length());
|
||||
|
||||
auto* it = reinterpret_cast<const unsigned char*>(mBuffer.BeginReading());
|
||||
auto* end = reinterpret_cast<const unsigned char*>(mBuffer.EndReading());
|
||||
|
||||
// First we do a pass and see if there are any strings in this key. We only
|
||||
// want to copy/decode when necessary.
|
||||
bool canShareBuffers = true;
|
||||
while (it < end) {
|
||||
auto type = *it % eMaxType;
|
||||
if (type == eTerminator || type == eArray) {
|
||||
it++;
|
||||
} else if (type == eFloat || type == eDate) {
|
||||
it++;
|
||||
it += std::min(sizeof(uint64_t), size_t(end - it));
|
||||
} else {
|
||||
// We have a string!
|
||||
canShareBuffers = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (canShareBuffers) {
|
||||
MOZ_ASSERT(it == end);
|
||||
aTarget.mBuffer = mBuffer;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// A string was found, so we need to copy the data we've read so far
|
||||
auto* start = reinterpret_cast<const unsigned char*>(mBuffer.BeginReading());
|
||||
if (it > start) {
|
||||
char* buffer;
|
||||
if (!aTarget.mBuffer.GetMutableData(&buffer, it-start)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
while (start < it) {
|
||||
*(buffer++) = *(start++);
|
||||
}
|
||||
}
|
||||
|
||||
// Now continue decoding
|
||||
while (it < end) {
|
||||
char* buffer;
|
||||
uint32_t oldLen = aTarget.mBuffer.Length();
|
||||
auto type = *it % eMaxType;
|
||||
|
||||
if (type == eTerminator || type == eArray) {
|
||||
// Copy array TypeID and terminator from raw key
|
||||
if (!aTarget.mBuffer.GetMutableData(&buffer, oldLen + 1)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
*(buffer + oldLen) = *(it++);
|
||||
} else if (type == eFloat || type == eDate) {
|
||||
// Copy number from raw key
|
||||
if (!aTarget.mBuffer.GetMutableData(&buffer,
|
||||
oldLen + 1 + sizeof(uint64_t))) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
buffer += oldLen;
|
||||
*(buffer++) = *(it++);
|
||||
|
||||
const size_t byteCount = std::min(sizeof(uint64_t), size_t(end - it));
|
||||
for (size_t count = 0; count < byteCount; count++) {
|
||||
*(buffer++) = (*it++);
|
||||
}
|
||||
} else {
|
||||
// Decode string and reencode
|
||||
uint8_t typeOffset = *it - eString;
|
||||
MOZ_ASSERT((typeOffset % eArray == 0) && (typeOffset / eArray <= 2));
|
||||
|
||||
nsDependentString str;
|
||||
DecodeString(it, end, str);
|
||||
aTarget.EncodeLocaleString(str, typeOffset, aLocale);
|
||||
}
|
||||
}
|
||||
aTarget.TrimBuffer();
|
||||
return NS_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
nsresult
|
||||
Key::EncodeJSValInternal(JSContext* aCx, JS::Handle<JS::Value> aVal,
|
||||
|
@ -277,18 +377,27 @@ Key::EncodeJSVal(JSContext* aCx,
|
|||
|
||||
void
|
||||
Key::EncodeString(const nsAString& aString, uint8_t aTypeOffset)
|
||||
{
|
||||
const char16_t* start = aString.BeginReading();
|
||||
const char16_t* end = aString.EndReading();
|
||||
EncodeString(start, end, aTypeOffset);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
Key::EncodeString(const T* aStart, const T* aEnd, uint8_t aTypeOffset)
|
||||
{
|
||||
// First measure how long the encoded string will be.
|
||||
|
||||
// The +2 is for initial 3 and trailing 0. We'll compensate for multi-byte
|
||||
// chars below.
|
||||
uint32_t size = aString.Length() + 2;
|
||||
uint32_t size = (aEnd - aStart) + 2;
|
||||
|
||||
const char16_t* start = aString.BeginReading();
|
||||
const char16_t* end = aString.EndReading();
|
||||
for (const char16_t* iter = start; iter < end; ++iter) {
|
||||
const T* start = aStart;
|
||||
const T* end = aEnd;
|
||||
for (const T* iter = start; iter < end; ++iter) {
|
||||
if (*iter > ONE_BYTE_LIMIT) {
|
||||
size += *iter > TWO_BYTE_LIMIT ? 2 : 1;
|
||||
size += char16_t(*iter) > TWO_BYTE_LIMIT ? 2 : 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -304,11 +413,11 @@ Key::EncodeString(const nsAString& aString, uint8_t aTypeOffset)
|
|||
*(buffer++) = eString + aTypeOffset;
|
||||
|
||||
// Encode string
|
||||
for (const char16_t* iter = start; iter < end; ++iter) {
|
||||
for (const T* iter = start; iter < end; ++iter) {
|
||||
if (*iter <= ONE_BYTE_LIMIT) {
|
||||
*(buffer++) = *iter + ONE_BYTE_ADJUST;
|
||||
}
|
||||
else if (*iter <= TWO_BYTE_LIMIT) {
|
||||
else if (char16_t(*iter) <= TWO_BYTE_LIMIT) {
|
||||
char16_t c = char16_t(*iter) + TWO_BYTE_ADJUST + 0x8000;
|
||||
*(buffer++) = (char)(c >> 8);
|
||||
*(buffer++) = (char)(c & 0xFF);
|
||||
|
@ -327,6 +436,47 @@ Key::EncodeString(const nsAString& aString, uint8_t aTypeOffset)
|
|||
NS_ASSERTION(buffer == mBuffer.EndReading(), "Wrote wrong number of bytes");
|
||||
}
|
||||
|
||||
#ifdef ENABLE_INTL_API
|
||||
nsresult
|
||||
Key::EncodeLocaleString(const nsDependentString& aString, uint8_t aTypeOffset,
|
||||
const nsCString& aLocale)
|
||||
{
|
||||
const int length = aString.Length();
|
||||
if (length == 0) {
|
||||
return NS_OK;
|
||||
}
|
||||
const UChar* ustr = reinterpret_cast<const UChar*>(aString.BeginReading());
|
||||
|
||||
UErrorCode uerror = U_ZERO_ERROR;
|
||||
UCollator* collator = ucol_open(aLocale.get(), &uerror);
|
||||
if (NS_WARN_IF(U_FAILURE(uerror))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
MOZ_ASSERT(collator);
|
||||
|
||||
nsAutoTArray<uint8_t, 128> keyBuffer;
|
||||
int32_t sortKeyLength = ucol_getSortKey(collator, ustr, length,
|
||||
keyBuffer.Elements(),
|
||||
keyBuffer.Length());
|
||||
if (sortKeyLength > (int32_t)keyBuffer.Length()) {
|
||||
keyBuffer.SetLength(sortKeyLength);
|
||||
sortKeyLength = ucol_getSortKey(collator, ustr, length,
|
||||
keyBuffer.Elements(),
|
||||
sortKeyLength);
|
||||
}
|
||||
|
||||
ucol_close(collator);
|
||||
if (NS_WARN_IF(sortKeyLength == 0)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
EncodeString(keyBuffer.Elements(),
|
||||
keyBuffer.Elements()+sortKeyLength,
|
||||
aTypeOffset);
|
||||
return NS_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
// static
|
||||
nsresult
|
||||
Key::DecodeJSVal(const unsigned char*& aPos,
|
||||
|
|
|
@ -207,6 +207,11 @@ public:
|
|||
nsresult
|
||||
AppendItem(JSContext* aCx, bool aFirstOfArray, JS::Handle<JS::Value> aVal);
|
||||
|
||||
#ifdef ENABLE_INTL_API
|
||||
nsresult
|
||||
ToLocaleBasedKey(Key& aTarget, const nsCString& aLocale) const;
|
||||
#endif
|
||||
|
||||
void
|
||||
FinishArray()
|
||||
{
|
||||
|
@ -278,6 +283,16 @@ private:
|
|||
void
|
||||
EncodeString(const nsAString& aString, uint8_t aTypeOffset);
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
EncodeString(const T* aStart, const T* aEnd, uint8_t aTypeOffset);
|
||||
|
||||
#ifdef ENABLE_INTL_API
|
||||
nsresult
|
||||
EncodeLocaleString(const nsDependentString& aString, uint8_t aTypeOffset,
|
||||
const nsCString& aLocale);
|
||||
#endif
|
||||
|
||||
void
|
||||
EncodeNumber(double aFloat, uint8_t aType);
|
||||
|
||||
|
|
|
@ -60,7 +60,6 @@ UNIFIED_SOURCES += [
|
|||
'IDBTransaction.cpp',
|
||||
'IDBWrapperCache.cpp',
|
||||
'IndexedDatabaseManager.cpp',
|
||||
'Key.cpp',
|
||||
'KeyPath.cpp',
|
||||
'PermissionRequestBase.cpp',
|
||||
'ReportInternalError.cpp',
|
||||
|
@ -68,6 +67,7 @@ UNIFIED_SOURCES += [
|
|||
|
||||
SOURCES += [
|
||||
'ActorsParent.cpp', # This file is huge.
|
||||
'Key.cpp', # We disable a warning on this file only
|
||||
]
|
||||
|
||||
IPDL_SOURCES += [
|
||||
|
@ -87,6 +87,11 @@ include('/ipc/chromium/chromium-config.mozbuild')
|
|||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
if CONFIG['GNU_CC']:
|
||||
# Suppress gcc warning about a comparison being always false due to the
|
||||
# range of the data type
|
||||
SOURCES['Key.cpp'].flags += ['-Wno-error=type-limits']
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
'/db/sqlite3/src',
|
||||
'/dom/base',
|
||||
|
@ -96,3 +101,6 @@ LOCAL_INCLUDES += [
|
|||
'/xpcom/build',
|
||||
'/xpcom/threads',
|
||||
]
|
||||
|
||||
if CONFIG['ENABLE_INTL_API']:
|
||||
CXXFLAGS += CONFIG['MOZ_ICU_CFLAGS']
|
||||
|
|
Загрузка…
Ссылка в новой задаче