Bug 329974: Share textdata for common textnode values. r/sr=jst

This commit is contained in:
cvshook%sicking.cc 2006-03-24 03:29:52 +00:00
Родитель 3ec83cda52
Коммит ae80239e8f
7 изменённых файлов: 314 добавлений и 414 удалений

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

@ -82,14 +82,10 @@ public:
* Set the text to the given value. If aNotify is PR_TRUE then
* the document is notified of the content change.
*/
virtual void SetText(const nsAString& aStr, PRBool aNotify) = 0;
/**
* Set the text to the given value. If aNotify is PR_TRUE then
* the document is notified of the content change.
*/
virtual void SetText(const char* aBuffer, PRUint32 aLength,
PRBool aNotify) = 0;
void SetText(const nsAString& aStr, PRBool aNotify)
{
return SetText(aStr.BeginReading(), aStr.Length(), aNotify);
}
/**
* Query method to see if the frame is nothing but whitespace

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

@ -439,30 +439,37 @@ nsGenericDOMDataNode::SubstringData(PRUint32 aStart, PRUint32 aCount,
nsresult
nsGenericDOMDataNode::AppendData(const nsAString& aData)
{
PRInt32 length = 0;
// Apparently this is called often enough that we don't want to just simply
// call SetText like ReplaceData does. See bug 77585 and comment in
// ReplaceData.
nsIDocument *document = GetCurrentDoc();
// FIXME, but 330872: We can't call BeginUpdate here because it confuses the
// poor little nsHTMLContentSink.
// mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, PR_TRUE);
// See bugzilla bug 77585.
if (mText.Is2b() || (!IsASCII(aData))) {
nsAutoString old_data;
mText.AppendTo(old_data);
length = old_data.Length();
// XXXjag We'd like to just say |old_data + aData|, but due
// to issues with dependent concatenation and sliding (sub)strings
// we'll just have to copy for now. See bug 121841 for details.
old_data.Append(aData);
SetText(old_data, PR_FALSE);
} else {
// We know aData and the current data is ASCII, so use a
// nsC*String, no need for any fancy unicode stuff here.
nsCAutoString old_data;
mText.AppendTo(old_data);
length = old_data.Length();
LossyAppendUTF16toASCII(aData, old_data);
SetText(old_data.get(), old_data.Length(), PR_FALSE);
PRBool haveMutationListeners =
document && nsGenericElement::HasMutationListeners(this, NS_EVENT_BITS_MUTATION_CHARACTERDATAMODIFIED);
nsCOMPtr<nsIAtom> oldValue;
if (haveMutationListeners) {
oldValue = GetCurrentValueAtom();
}
mText.Append(aData);
SetBidiStatus();
if (haveMutationListeners) {
nsMutationEvent mutation(PR_TRUE, NS_MUTATION_CHARACTERDATAMODIFIED);
mutation.mPrevAttrValue = oldValue;
mutation.mNewAttrValue = GetCurrentValueAtom();
nsEventDispatcher::Dispatch(this, nsnull, &mutation);
}
// Trigger a reflow
nsIDocument *document = GetCurrentDoc();
if (document) {
document->CharacterDataChanged(this, PR_TRUE);
}
@ -1086,110 +1093,26 @@ nsGenericDOMDataNode::SetText(const PRUnichar* aBuffer,
}
}
void
nsGenericDOMDataNode::SetText(const char* aBuffer, PRUint32 aLength,
PRBool aNotify)
{
if (!aBuffer) {
NS_ERROR("Null buffer passed to SetText()!");
return;
}
nsIDocument *document = GetCurrentDoc();
mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, aNotify);
PRBool haveMutationListeners =
document && nsGenericElement::HasMutationListeners(this, NS_EVENT_BITS_MUTATION_CHARACTERDATAMODIFIED);
nsCOMPtr<nsIAtom> oldValue;
if (haveMutationListeners) {
oldValue = GetCurrentValueAtom();
}
mText.SetTo(aBuffer, aLength);
if (haveMutationListeners) {
nsMutationEvent mutation(PR_TRUE, NS_MUTATION_CHARACTERDATAMODIFIED);
mutation.mPrevAttrValue = oldValue;
if (aLength > 0) {
// Must use Substring() since nsDependentCString() requires null
// terminated strings.
mutation.mNewAttrValue =
do_GetAtom(Substring(aBuffer, aBuffer + aLength));
}
nsEventDispatcher::Dispatch(this, nsnull, &mutation);
}
// Trigger a reflow
if (aNotify && document) {
document->CharacterDataChanged(this, PR_FALSE);
}
}
void
nsGenericDOMDataNode::SetText(const nsAString& aStr,
PRBool aNotify)
{
nsIDocument *document = GetCurrentDoc();
mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, aNotify);
PRBool haveMutationListeners =
document && nsGenericElement::HasMutationListeners(this, NS_EVENT_BITS_MUTATION_CHARACTERDATAMODIFIED);
nsCOMPtr<nsIAtom> oldValue;
if (haveMutationListeners) {
oldValue = GetCurrentValueAtom();
}
mText = aStr;
SetBidiStatus();
if (haveMutationListeners) {
nsMutationEvent mutation(PR_TRUE, NS_MUTATION_CHARACTERDATAMODIFIED);
mutation.mPrevAttrValue = oldValue;
if (!aStr.IsEmpty())
mutation.mNewAttrValue = do_GetAtom(aStr);
nsEventDispatcher::Dispatch(this, nsnull, &mutation);
}
// Trigger a reflow
if (aNotify && document) {
document->CharacterDataChanged(this, PR_FALSE);
}
}
PRBool
nsGenericDOMDataNode::IsOnlyWhitespace()
{
nsTextFragment& frag = mText;
if (frag.Is2b()) {
const PRUnichar* cp = frag.Get2b();
const PRUnichar* end = cp + frag.GetLength();
if (mText.Is2b()) {
// The fragment contains non-8bit characters and such characters
// are never considered whitespace.
return PR_FALSE;
}
while (cp < end) {
PRUnichar ch = *cp++;
const char* cp = mText.Get1b();
const char* end = cp + mText.GetLength();
if (!XP_IS_SPACE(ch)) {
return PR_FALSE;
}
while (cp < end) {
char ch = *cp;
if (!XP_IS_SPACE(ch)) {
return PR_FALSE;
}
} else {
const char* cp = frag.Get1b();
const char* end = cp + frag.GetLength();
while (cp < end) {
PRUnichar ch = PRUnichar(*(unsigned char*)cp);
++cp;
if (!XP_IS_SPACE(ch)) {
return PR_FALSE;
}
}
++cp;
}
return PR_TRUE;

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

@ -270,9 +270,11 @@ public:
virtual PRUint32 TextLength();
virtual void SetText(const PRUnichar* aBuffer, PRUint32 aLength,
PRBool aNotify);
virtual void SetText(const nsAString& aStr, PRBool aNotify);
virtual void SetText(const char* aBuffer, PRUint32 aLength,
PRBool aNotify);
// Need to implement this here too to avoid hiding.
void SetText(const nsAString& aStr, PRBool aNotify)
{
return SetText(aStr.BeginReading(), aStr.Length(), aNotify);
}
virtual PRBool IsOnlyWhitespace();
virtual void AppendTextTo(nsAString& aResult);

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

@ -42,9 +42,58 @@
#include "nsBidiUtils.h"
#include "nsUnicharUtils.h"
// Static buffer used for newline fragments
static unsigned char sNewLineCharacter = '\n';
#define TEXTFRAG_WHITE_AFTER_NEWLINE 50
#define TEXTFRAG_MAX_NEWLINES 7
// Static buffer used for common fragments
static char* sSpaceSharedString[TEXTFRAG_MAX_NEWLINES + 1];
static char* sTabSharedString[TEXTFRAG_MAX_NEWLINES + 1];
static char sSingleCharSharedString[256];
// static
nsresult
nsTextFragment::Init()
{
// Create whitespace strings
PRUint32 i;
for (i = 0; i <= TEXTFRAG_MAX_NEWLINES; ++i) {
sSpaceSharedString[i] = new char[1 + i + TEXTFRAG_WHITE_AFTER_NEWLINE];
sTabSharedString[i] = new char[1 + i + TEXTFRAG_WHITE_AFTER_NEWLINE];
NS_ENSURE_TRUE(sSpaceSharedString[i] && sTabSharedString[i],
NS_ERROR_OUT_OF_MEMORY);
sSpaceSharedString[i][0] = ' ';
sTabSharedString[i][0] = ' ';
PRUint32 j;
for (j = 1; j < 1 + i; ++j) {
sSpaceSharedString[i][j] = '\n';
sTabSharedString[i][j] = '\n';
}
for (; j < (1 + i + TEXTFRAG_WHITE_AFTER_NEWLINE); ++j) {
sSpaceSharedString[i][j] = ' ';
sTabSharedString[i][j] = '\t';
}
}
// Create single-char strings
for (i = 0; i < 256; ++i) {
sSingleCharSharedString[i] = i;
}
return NS_OK;
}
// static
void
nsTextFragment::Shutdown()
{
PRUint32 i;
for (i = 0; i <= TEXTFRAG_MAX_NEWLINES; ++i) {
delete [] sSpaceSharedString[i];
delete [] sTabSharedString[i];
sSpaceSharedString[i] = nsnull;
sTabSharedString[i] = nsnull;
}
}
nsTextFragment::~nsTextFragment()
{
@ -55,9 +104,7 @@ void
nsTextFragment::ReleaseText()
{
if (mState.mLength && m1b && mState.mInHeap) {
unsigned char *buf = NS_CONST_CAST(unsigned char *, m1b);
nsMemory::Free(buf); // m1b == m2b as far as nsMemory is concerned
nsMemory::Free(m2b); // m1b == m2b as far as nsMemory is concerned
}
m1b = nsnull;
@ -66,204 +113,129 @@ nsTextFragment::ReleaseText()
mAllBits = 0;
}
nsTextFragment::nsTextFragment(const nsTextFragment& aOther)
: m1b(nsnull), mAllBits(0)
{
if (aOther.Is2b()) {
SetTo(aOther.Get2b(), aOther.GetLength());
} else {
SetTo(aOther.Get1b(), aOther.GetLength());
}
}
nsTextFragment::nsTextFragment(const char *aString)
: m1b(nsnull), mAllBits(0)
{
SetTo(aString, strlen(aString));
}
nsTextFragment::nsTextFragment(const PRUnichar *aString)
: m1b(nsnull), mAllBits(0)
{
SetTo(aString, nsCRT::strlen(aString));
}
nsTextFragment::nsTextFragment(const nsString& aString)
: m1b(nsnull), mAllBits(0)
{
SetTo(aString.get(), aString.Length());
}
nsTextFragment&
nsTextFragment::operator=(const nsTextFragment& aOther)
{
if (aOther.Is2b()) {
SetTo(aOther.Get2b(), aOther.GetLength());
} else {
SetTo(aOther.Get1b(), aOther.GetLength());
}
if (aOther.mState.mIsBidi) {
// Carry over BIDI state from aOther
mState.mIsBidi = PR_TRUE;
}
return *this;
}
nsTextFragment&
nsTextFragment::operator=(const char *aString)
{
SetTo(aString, strlen(aString));
return *this;
}
nsTextFragment&
nsTextFragment::operator=(const PRUnichar *aString)
{
SetTo(aString, nsCRT::strlen(aString));
return *this;
}
nsTextFragment&
nsTextFragment::operator=(const nsAString& aString)
{
ReleaseText();
PRUint32 length = aString.Length();
if (aOther.mState.mLength) {
if (!aOther.mState.mInHeap) {
m1b = aOther.m1b; // This will work even if aOther is using m2b
}
else {
m2b = NS_STATIC_CAST(PRUnichar*,
nsMemory::Clone(aOther.m2b, aOther.mState.mLength *
(aOther.mState.mIs2b ? sizeof(PRUnichar) : sizeof(char)));
if (length > 0) {
PRBool in_heap = PR_TRUE;
if (IsASCII(aString)) {
if (length == 1 && aString.First() == '\n') {
m1b = &sNewLineCharacter;
in_heap = PR_FALSE;
} else {
m1b = (unsigned char *)ToNewCString(aString);
if (aOther.mState.mIs2b) {
}
else {
m1b = NS_STATIC_CAST(char *,
nsMemory::Clone(aOther.m1b, aOther.mState.mLength * sizeof(char)));
}
mState.mIs2b = PR_FALSE;
} else {
m2b = ToNewUnicode(aString);
mState.mIs2b = PR_TRUE;
}
mState.mInHeap = in_heap;
mState.mLength = length;
if (m1b) {
mAllBits = aOther.mAllBits;
}
}
return *this;
}
void
nsTextFragment::SetTo(PRUnichar *aBuffer, PRInt32 aLength, PRBool aRelease)
{
ReleaseText();
m2b = aBuffer;
mState.mIs2b = PR_TRUE;
mState.mInHeap = aRelease;
mState.mLength = aLength;
}
void
nsTextFragment::SetTo(const PRUnichar* aBuffer, PRInt32 aLength)
{
ReleaseText();
if (aLength != 0) {
// See if we need to store the data in ucs2 or not
PRBool need2 = PR_FALSE;
const PRUnichar *ucp = aBuffer;
const PRUnichar *uend = aBuffer + aLength;
while (ucp < uend) {
PRUnichar ch = *ucp++;
if (ch >> 8) {
need2 = PR_TRUE;
break;
}
}
if (need2) {
// Use ucs2 storage because we have to
m2b = (const PRUnichar *)nsMemory::Clone(aBuffer,
aLength * sizeof(PRUnichar));
if (!m2b) {
NS_ERROR("Failed to clone string buffer!");
return;
}
// Setup our fields
mState.mIs2b = PR_TRUE;
mState.mInHeap = PR_TRUE;
mState.mLength = aLength;
} else {
// Use 1 byte storage because we can
PRBool in_heap = PR_TRUE;
if (aLength == 1 && *aBuffer == '\n') {
m1b = &sNewLineCharacter;
in_heap = PR_FALSE;
} else {
unsigned char *nt =
(unsigned char *)nsMemory::Alloc(aLength * sizeof(char));
if (!nt) {
NS_ERROR("Failed to allocate string buffer!");
return;
}
// Copy data
for (PRUint32 i = 0; i < (PRUint32)aLength; ++i) {
nt[i] = (unsigned char)aBuffer[i];
}
m1b = nt;
}
// Setup our fields
mState.mIs2b = PR_FALSE;
mState.mInHeap = in_heap;
mState.mLength = aLength;
}
if (aLength == 0) {
return;
}
}
void
nsTextFragment::SetTo(const char *aBuffer, PRInt32 aLength)
{
ReleaseText();
if (aLength != 0) {
PRBool in_heap = PR_TRUE;
if (aLength == 1 && *aBuffer == '\n') {
m1b = &sNewLineCharacter;
in_heap = PR_FALSE;
} else {
m1b = (unsigned char *)nsMemory::Clone(aBuffer, aLength * sizeof(char));
if (!m1b) {
NS_ERROR("Failed to allocate string buffer!");
return;
}
}
// Setup our fields
PRUnichar firstChar = *aBuffer;
if (aLength == 1 && firstChar < 256) {
m1b = sSingleCharSharedString + firstChar;
mState.mInHeap = PR_FALSE;
mState.mIs2b = PR_FALSE;
mState.mInHeap = in_heap;
mState.mLength = aLength;
mState.mLength = 1;
return;
}
const PRUnichar *ucp = aBuffer;
const PRUnichar *uend = aBuffer + aLength;
// Check if we can use a shared string
if (firstChar == ' ' || firstChar == '\n' || firstChar == '\t') {
if (firstChar == ' ') {
++ucp;
}
const PRUnichar* start = ucp;
while (ucp < uend && *ucp == '\n') {
++ucp;
}
const PRUnichar* endNewLine = ucp;
PRUnichar space = ucp < uend && *ucp == '\t' ? '\t' : ' ';
while (ucp < uend && *ucp == space) {
++ucp;
}
if (ucp == uend &&
endNewLine - start <= TEXTFRAG_MAX_NEWLINES &&
ucp - endNewLine <= TEXTFRAG_WHITE_AFTER_NEWLINE) {
char** strings = space == ' ' ? sSpaceSharedString : sTabSharedString;
m1b = strings[endNewLine - start];
// If we didn't find a space in the beginning, skip it now.
if (firstChar != ' ') {
++m1b;
}
mState.mInHeap = PR_FALSE;
mState.mIs2b = PR_FALSE;
mState.mLength = aLength;
return;
}
}
// See if we need to store the data in ucs2 or not
PRBool need2 = PR_FALSE;
while (ucp < uend) {
PRUnichar ch = *ucp++;
if (ch >= 256) {
need2 = PR_TRUE;
break;
}
}
if (need2) {
// Use ucs2 storage because we have to
m2b = (PRUnichar *)nsMemory::Clone(aBuffer,
aLength * sizeof(PRUnichar));
if (!m2b) {
return;
}
} else {
// Use 1 byte storage because we can
char* buff = (char *)nsMemory::Alloc(aLength * sizeof(char));
if (!buff) {
return;
}
// Copy data
for (PRUint32 i = 0; i < (PRUint32)aLength; ++i) {
buff[i] = (char)aBuffer[i];
}
m1b = buff;
}
// Setup our fields
mState.mInHeap = PR_TRUE;
mState.mIs2b = need2;
mState.mLength = aLength;
}
void
@ -272,23 +244,11 @@ nsTextFragment::AppendTo(nsAString& aString) const
if (mState.mIs2b) {
aString.Append(m2b, mState.mLength);
} else {
AppendASCIItoUTF16(Substring((char *)m1b, ((char *)m1b) + mState.mLength),
AppendASCIItoUTF16(Substring(m1b, m1b + mState.mLength),
aString);
}
}
void
nsTextFragment::AppendTo(nsACString& aCString) const
{
if (mState.mIs2b) {
LossyAppendUTF16toASCII(Substring((PRUnichar *)m2b,
(PRUnichar *)m2b + mState.mLength),
aCString);
} else {
aCString.Append((char *)m1b, mState.mLength);
}
}
void
nsTextFragment::CopyTo(PRUnichar *aDest, PRInt32 aOffset, PRInt32 aCount)
{
@ -307,40 +267,111 @@ nsTextFragment::CopyTo(PRUnichar *aDest, PRInt32 aOffset, PRInt32 aCount)
if (mState.mIs2b) {
memcpy(aDest, m2b + aOffset, sizeof(PRUnichar) * aCount);
} else {
unsigned const char *cp = m1b + aOffset;
unsigned const char *end = cp + aCount;
const char *cp = m1b + aOffset;
const char *end = cp + aCount;
while (cp < end) {
*aDest++ = PRUnichar(*cp++);
*aDest++ = unsigned char(*cp++);
}
}
}
}
void
nsTextFragment::CopyTo(char *aDest, PRInt32 aOffset, PRInt32 aCount)
nsTextFragment::Append(const nsAString& aData)
{
NS_ASSERTION(aOffset >= 0, "Bad offset passed to nsTextFragment::CopyTo()!");
NS_ASSERTION(aCount >= 0, "Bad count passed to nsTextFragment::CopyTo()!");
PRUint32 len = aData.Length();
const PRUnichar* start = aData.BeginReading();
if (aOffset < 0) {
aOffset = 0;
// 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) {
SetTo(start, len);
return;
}
if (aOffset + aCount > GetLength()) {
aCount = mState.mLength - aOffset;
// Should we optimize for aData.Length() == 0?
if (mState.mIs2b) {
// Already a 2-byte string so the result will be too
PRUnichar* buff = (PRUnichar*)nsMemory::Realloc(m2b, (mState.mLength + len) * sizeof(PRUnichar));
if (!buff) {
return;
}
memcpy(buff + mState.mLength, start, len * sizeof(PRUnichar));
mState.mLength += len;
m2b = buff;
return;
}
if (aCount != 0) {
if (mState.mIs2b) {
const PRUnichar *cp = m2b + aOffset;
const PRUnichar *end = cp + aCount;
while (cp < end) {
*aDest++ = (char)(*cp++);
}
} else {
memcpy(aDest, m1b + aOffset, sizeof(char) * aCount);
// Current string is a 1-byte string, check if the new data fits in one byte too.
const PRUnichar* ucp = start;
const PRUnichar* uend = ucp + len;
PRBool need2 = PR_FALSE;
while (ucp < uend) {
PRUnichar ch = *ucp++;
if (ch >= 256) {
need2 = PR_TRUE;
break;
}
}
if (need2) {
// The old data was 1-byte, but the new is not so we have to expand it
// all to 2-byte
PRUnichar* buff = (PRUnichar*)nsMemory::Alloc((mState.mLength + len) *
sizeof(PRUnichar));
if (!buff) {
return;
}
// Copy data
for (PRUint32 i = 0; i < mState.mLength; ++i) {
buff[i] = (unsigned char)m1b[i];
}
memcpy(buff + mState.mLength, start, len * sizeof(PRUnichar));
mState.mLength += len;
mState.mIs2b = PR_TRUE;
if (!mState.mInHeap) {
nsMemory::Free(m2b);
}
m2b = buff;
return;
}
// The new and the old data is all 1-byte
char* buff;
if (mState.mInHeap) {
buff = (char*)nsMemory::Realloc(NS_CONST_CAST(char*, m1b),
(mState.mLength + len) * sizeof(char));
if (!buff) {
return;
}
}
else {
buff = (char*)nsMemory::Alloc((mState.mLength + len) * sizeof(char));
if (!buff) {
return;
}
memcpy(buff, m1b, mState.mLength);
}
for (PRUint32 i = 0; i < len; ++i) {
buff[mState.mLength + i] = (char)start[i];
}
m1b = buff;
mState.mLength += len;
}
// To save time we only do this when we really want to know, not during

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

@ -72,6 +72,9 @@ class nsCString;
*/
class nsTextFragment {
public:
static nsresult Init();
static void Shutdown();
/**
* Default constructor. Initialize the fragment to be empty.
*/
@ -82,54 +85,12 @@ public:
~nsTextFragment();
/**
* Initialize the contents of this fragment to be a copy of
* the argument fragment.
*/
nsTextFragment(const nsTextFragment& aOther);
/**
* Initialize the contents of this fragment to be a copy of
* the argument 7bit ascii string.
*/
nsTextFragment(const char *aString);
/**
* Initialize the contents of this fragment to be a copy of
* the argument ucs2 string.
*/
nsTextFragment(const PRUnichar *aString);
/**
* Initialize the contents of this fragment to be a copy of
* the argument string.
*/
nsTextFragment(const nsString& aString);
/**
* Change the contents of this fragment to be a copy of the
* the argument fragment.
*/
nsTextFragment& operator=(const nsTextFragment& aOther);
/**
* Change the contents of this fragment to be a copy of the
* the argument 7bit ascii string.
*/
nsTextFragment& operator=(const char *aString);
/**
* Change the contents of this fragment to be a copy of the
* the argument ucs2 string.
*/
nsTextFragment& operator=(const PRUnichar *aString);
/**
* Change the contents of this fragment to be a copy of the
* the argument string.
*/
nsTextFragment& operator=(const nsAString& aString);
/**
* Return PR_TRUE if this fragment is represented by PRUnichar data
*/
@ -175,14 +136,6 @@ public:
return PRInt32(mState.mLength);
}
/**
* Change the contents of this fragment to be the given buffer and
* length. The memory becomes owned by the fragment. In addition,
* the memory for aBuffer must have been allocated using the
* nsIMemory interface.
*/
void SetTo(PRUnichar *aBuffer, PRInt32 aLength, PRBool aRelease);
/**
* Change the contents of this fragment to be a copy of the given
* buffer. Like operator= except a length is specified instead of
@ -191,23 +144,15 @@ public:
void SetTo(const PRUnichar* aBuffer, PRInt32 aLength);
/**
* Change the contents of this fragment to be a copy of the given
* buffer. Like operator= except a length is specified instead of
* assuming 0 termination.
* Append aData to the end of this fragment.
*/
void SetTo(const char *aBuffer, PRInt32 aLength);
void Append(const nsAString& aData);
/**
* Append the contents of this string fragment to aString
*/
void AppendTo(nsAString& aString) const;
/**
* Append the contents of this string fragment to aCString. This
* method will do a lossy conversion from UTF-16 to ASCII.
*/
void AppendTo(nsACString& aCString) const;
/**
* Make a copy of the fragments contents starting at offset for
* count characters. The offset and count will be adjusted to
@ -216,14 +161,6 @@ public:
*/
void CopyTo(PRUnichar *aDest, PRInt32 aOffset, PRInt32 aCount);
/**
* Make a copy of the fragments contents starting at offset for
* count characters. The offset and count will be adjusted to
* lie within the fragments data. The fragments data is converted if
* necessary.
*/
void CopyTo(char *aDest, PRInt32 aOffset, PRInt32 aCount);
/**
* Return the character in the text-fragment at the given
* index. This always returns a PRUnichar.
@ -231,7 +168,7 @@ public:
PRUnichar CharAt(PRInt32 aIndex) const
{
NS_ASSERTION(PRUint32(aIndex) < mState.mLength, "bad index");
return mState.mIs2b ? m2b[aIndex] : PRUnichar(m1b[aIndex]);
return mState.mIs2b ? m2b[aIndex] : NS_STATIC_CAST(unsigned char, m1b[aIndex]);
}
/**
@ -247,12 +184,12 @@ public:
PRUint32 mLength : 29;
};
protected:
private:
void ReleaseText();
union {
const PRUnichar *m2b;
const unsigned char *m1b;
PRUnichar *m2b;
const char *m1b; // This is const since it can point to shared data
};
union {

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

@ -300,6 +300,15 @@ Initialize(nsIModule* aSelf)
return rv;
}
rv = nsTextFragment::Init();
if (NS_FAILED(rv)) {
NS_ERROR("Could not initialize nsAttrValue");
Shutdown();
return rv;
}
// Register all of our atoms once
nsCSSAnonBoxes::AddRefAtoms();
nsCSSPseudoClasses::AddRefAtoms();
@ -423,6 +432,7 @@ Shutdown()
NS_IF_RELEASE(nsRuleNode::gLangService);
nsGenericHTMLElement::Shutdown();
nsTextFragment::Shutdown();
nsAttrValue::Shutdown();
nsContentUtils::Shutdown();
nsLayoutStylesheetCache::Shutdown();

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

@ -1723,7 +1723,8 @@ nsTextTransformer::SelfTest(nsPresContext* aPresContext)
cp++;
}
nsTextFragment frag(st->text);
nsTextFragment frag;
frag.SetTo(st->text, nsCRT::strlen(st->text));
nsTextTransformer tx(aPresContext);
for (PRInt32 preMode = 0; preMode < NUM_MODES; preMode++) {