/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * 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/. */
/* * A class which represents a fragment of text (eg inside a text * node); if only codepoints below 256 are used, the text is stored as * a char*; otherwise the text is stored as a char16_t*
*/
if (aOther.mState.mLength) { if (!aOther.mState.mInHeap) {
MOZ_ASSERT(!aOther.mState.mIs2b);
m1b = aOther.m1b;
} elseif (aOther.mState.mIs2b) {
m2b = aOther.m2b;
NS_ADDREF(m2b);
} else {
m1b = static_cast<char*>(malloc(aOther.mState.mLength)); if (m1b) {
memcpy(const_cast<char*>(m1b), aOther.m1b, aOther.mState.mLength);
} else { // allocate a buffer for a single REPLACEMENT CHARACTER
m2b = StringBuffer::Alloc(sizeof(char16_t) * 2).take(); if (!m2b) {
MOZ_CRASH("OOM!");
}
char16_t* data = static_cast<char16_t*>(m2b->Data());
data[0] = 0xFFFD; // REPLACEMENT CHARACTER
data[1] = char16_t(0);
mState.mIs2b = true;
mState.mInHeap = true;
mState.mLength = 1; return *this;
}
}
mAllBits = aOther.mAllBits;
}
return *this;
}
staticinline int32_t FirstNon8BitUnvectorized(const char16_t* str, const char16_t* end) { using p = Non8BitParameters<sizeof(size_t)>; const size_t mask = p::mask(); const uint32_t alignMask = p::alignMask(); const uint32_t numUnicharsPerWord = p::numUnicharsPerWord(); const int32_t len = end - str;
int32_t i = 0;
// Align ourselves to a word boundary.
int32_t alignLen = std::min(
len, int32_t(((-NS_PTR_TO_INT32(str)) & alignMask) / sizeof(char16_t))); for (; i < alignLen; i++) { if (str[i] > 255) return i;
}
// Check one word at a time. const int32_t wordWalkEnd =
((len - i) / numUnicharsPerWord) * numUnicharsPerWord; for (; i < wordWalkEnd; i += numUnicharsPerWord) { const size_t word = *reinterpret_cast<const size_t*>(str + i); if (word & mask) return i;
}
// Take care of the remainder one character at a time. for (; i < len; i++) { if (str[i] > 255) return i;
}
return -1;
}
#ifdefined(MOZILLA_MAY_SUPPORT_SSE2) # include "nsTextFragmentGenericFwd.h" #endif
/* * This function returns -1 if all characters in str are 8 bit characters. * Otherwise, it returns a value less than or equal to the index of the first * non-8bit character in str. For example, if first non-8bit character is at * position 25, it may return 25, or for example 24, or 16. But it guarantees * there is no non-8bit character before returned value.
*/ staticinline int32_t FirstNon8Bit(const char16_t* str, const char16_t* end) { #ifdef MOZILLA_MAY_SUPPORT_SSE2 if (mozilla::supports_sse2()) { return mozilla::FirstNon8Bit<xsimd::sse2>(str, end);
} #elifdefined(__powerpc__) if (mozilla::supports_vmx()) { return mozilla::VMX::FirstNon8Bit(str, end);
} #endif
// See if we need to store the data in ucs2 or not
int32_t first16bit = aForce2b ? 0 : FirstNon8Bit(ucp, uend);
if (first16bit != -1) { // aBuffer contains no non-8bit character // Use ucs2 storage because we have to
CheckedUint32 size = CheckedUint32(aLength) + 1; if (!size.isValid()) { returnfalse;
}
size *= sizeof(char16_t); if (!size.isValid()) { returnfalse;
}
RefPtr<StringBuffer> newBuffer = StringBuffer::Alloc(size.value()); if (!newBuffer) { returnfalse;
}
// This is a common case because some callsites create a textnode // with a value by creating the node and then calling AppendData. if (mState.mLength == 0) { return SetTo(aBuffer, aLength, aUpdateBidi, aForce2b);
}
// Should we optimize for aData.Length() == 0?
// FYI: Don't use CheckedInt in this method since here is very hot path // in some performance tests. if (NS_MAX_TEXT_FRAGMENT_LENGTH - mState.mLength < aLength) { returnfalse; // Would be overflown if we'd keep handling.
}
if (mState.mIs2b) {
size_t size = mState.mLength + aLength + 1; if (SIZE_MAX / sizeof(char16_t) < size) { returnfalse; // Would be overflown if we'd keep handling.
}
size *= sizeof(char16_t);
// Already a 2-byte string so the result will be too
StringBuffer* buff = nullptr;
StringBuffer* bufferToRelease = nullptr; if (m2b->IsReadonly()) {
buff = StringBuffer::Alloc(size).take(); if (!buff) { returnfalse;
}
bufferToRelease = m2b;
memcpy(static_cast<char16_t*>(buff->Data()), m2b->Data(),
mState.mLength * sizeof(char16_t));
} else {
buff = StringBuffer::Realloc(m2b, size); if (!buff) { returnfalse;
}
}
if (aUpdateBidi) {
UpdateBidiFlag(aBuffer, aLength);
}
returntrue;
}
// Current string is a 1-byte string, check if the new data fits in one byte // too.
int32_t first16bit = aForce2b ? 0 : FirstNon8Bit(aBuffer, aBuffer + aLength);
if (first16bit != -1) { // aBuffer contains no non-8bit character
size_t size = mState.mLength + aLength + 1; if (SIZE_MAX / sizeof(char16_t) < size) { returnfalse; // Would be overflown if we'd keep handling.
}
size *= sizeof(char16_t);
// The old data was 1-byte, but the new is not so we have to expand it // all to 2-byte
StringBuffer* buff = StringBuffer::Alloc(size).take(); if (!buff) { returnfalse;
}
// Copy data into buff
char16_t* data = static_cast<char16_t*>(buff->Data());
ConvertLatin1toUtf16(Span(m1b, mState.mLength), Span(data, mState.mLength));
if (aUpdateBidi) {
UpdateBidiFlag(aBuffer + first16bit, aLength - first16bit);
}
returntrue;
}
// The new and the old data is all 1-byte
size_t size = mState.mLength + aLength;
MOZ_ASSERT(sizeof(char) == 1); char* buff; if (mState.mInHeap) {
buff = static_cast<char*>(realloc(const_cast<char*>(m1b), size)); if (!buff) { returnfalse;
}
} else {
buff = static_cast<char*>(malloc(size)); if (!buff) { returnfalse;
}
if (mState.mInHeap) { return aMallocSizeOf(m1b);
}
return 0;
}
// To save time we only do this when we really want to know, not during // every allocation void nsTextFragment::UpdateBidiFlag(const char16_t* aBuffer, uint32_t aLength) { if (mState.mIs2b && !mState.mIsBidi) { if (HasRTLChars(Span(aBuffer, aLength))) {
mState.mIsBidi = true;
}
}
}
// We're 1-byte, the other thing is 2-byte. Instead of implementing a // separate codepath for this, just use our code below. return aOther.TextEquals(*this);
}
// We can't use EqualsASCII here, because the other string might not // actually be ASCII. Just roll our own compare; do it in the simple way. // Bug 1532356 tracks not having to roll our own. if (GetLength() != aOther.GetLength()) { returnfalse;
}
const char16_t* ourChars = Get2b(); constchar* otherChars = aOther.Get1b(); for (uint32_t i = 0; i < GetLength(); ++i) { if (ourChars[i] != static_cast<char16_t>(otherChars[i])) { returnfalse;
}
}
returntrue;
}
¤ Dauer der Verarbeitung: 0.16 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.