Bug 871846 - ICU usage and infrastructure bits. r=janv

This commit is contained in:
Reuben Morais 2014-08-04 13:59:57 -07:00
Родитель 54d10b79b5
Коммит dd7ac5dc3c
5 изменённых файлов: 228 добавлений и 8 удалений

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

@ -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']