diff --git a/mozilla/content/base/public/nsTextFragment.h b/mozilla/content/base/public/nsTextFragment.h new file mode 100644 index 00000000000..8c953e2c680 --- /dev/null +++ b/mozilla/content/base/public/nsTextFragment.h @@ -0,0 +1,213 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Mozilla Communicator client code. + * + * The Initial Developer of the Original Code is Netscape Communications + * Corporation. Portions created by Netscape are Copyright (C) 1998 + * Netscape Communications Corporation. All Rights Reserved. + */ +#ifndef nsTextFragment_h___ +#define nsTextFragment_h___ + +#include "nslayout.h" +class nsString; + +// XXX should this normalize the code to keep a \u0000 at the end? + +// XXX nsTextFragmentPool? + +/** + * A fragment of text. If mIs2b is 1 then the m2b pointer is valid + * otherwise the m1b pointer is valid. If m1b is used then each byte + * of data represents a single ucs2 character with the high byte being + * zero. + * + * This class does not have a virtual destructor therefore it is not + * meant to be subclassed. + */ +class NS_LAYOUT nsTextFragment { +public: + /** + * Default constructor. Initialize the fragment to be empty. + */ + nsTextFragment() { + m1b = nsnull; + mInHeap = 0; + mIs2b = 0; + mLength = 0; + } + + ~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 nsString& aString); + + /** + * Return PR_TRUE if this fragment is represented by PRUnichar data + */ + PRBool Is2b() const { + return mIs2b; + } + + /** + * Get a pointer to constant PRUnichar data. + */ + const PRUnichar* Get2b() const { + NS_ASSERTION(Is2b(), "not 2b text"); + return m2b; + } + + /** + * Get a pointer to constant char data. + */ + const char* Get1b() const { + NS_ASSERTION(!Is2b(), "not 1b text"); + return (const char*) m1b; + } + + /** + * Get the length of the fragment. The length is the number of logical + * characters, not the number of bytes to store the characters. + */ + PRInt32 GetLength() const { + return PRInt32(mLength); + } + + /** + * Mutable version of Get2b. Only works for a non-const object. + * Returns a pointer to the PRUnichar data. + */ + PRUnichar* Get2b() { + NS_ASSERTION(Is2b(), "not 2b text"); + return m2b; + } + + /** + * Mutable version of Get1b. Only works for a non-const object. + * Returns a pointer to the char data. + */ + char* Get1b() { + NS_ASSERTION(!Is2b(), "not 1b text"); + return (char*) m1b; + } + + /** + * 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 "new[]" + * because it will be released with "delete []". + */ + 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 + * assuming 0 termination. + */ + 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. + */ + void SetTo(const char* aBuffer, PRInt32 aLength); + + /** + * Append the contents of this string fragment to aString + */ + void AppendTo(nsString& aString) const; + + /** + * 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(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. + */ + PRUnichar CharAt(PRInt32 aIndex) const { + NS_ASSERTION(PRUint32(aIndex) < mLength, "bad index"); + return mIs2b ? m2b[aIndex] : PRUnichar(m1b[aIndex]); + } + +protected: + union { + PRUnichar* m2b; + unsigned char* m1b; + }; + PRUint32 mInHeap : 1; + PRUint32 mIs2b : 1; + PRUint32 mLength : 30; + + void ReleaseText(); +}; + +#endif /* nsTextFragment_h___ */ diff --git a/mozilla/content/base/src/nsTextFragment.cpp b/mozilla/content/base/src/nsTextFragment.cpp new file mode 100644 index 00000000000..9d3af945eda --- /dev/null +++ b/mozilla/content/base/src/nsTextFragment.cpp @@ -0,0 +1,234 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Mozilla Communicator client code. + * + * The Initial Developer of the Original Code is Netscape Communications + * Corporation. Portions created by Netscape are Copyright (C) 1998 + * Netscape Communications Corporation. All Rights Reserved. + */ +#include "nsTextFragment.h" +#include "nsString.h" +#include "nsCRT.h" + +nsTextFragment::~nsTextFragment() +{ + ReleaseText(); +} + +void +nsTextFragment::ReleaseText() +{ + if (mLength && m1b && mInHeap) { + if (mIs2b) { + delete [] m2b; + } + else { + delete [] m1b; + } + } + m1b = nsnull; + mIs2b = 0; + mInHeap = 0; + mLength = 0; +} + +nsTextFragment::nsTextFragment(const nsTextFragment& aOther) +{ + if (aOther.Is2b()) { + SetTo(aOther.Get2b(), aOther.GetLength()); + } + else { + SetTo(aOther.Get1b(), aOther.GetLength()); + } +} + +nsTextFragment::nsTextFragment(const char* aString) +{ + SetTo(aString, strlen(aString)); +} + +nsTextFragment::nsTextFragment(const PRUnichar* aString) +{ + SetTo(aString, nsCRT::strlen(aString)); +} + +nsTextFragment::nsTextFragment(const nsString& aString) +{ + SetTo(aString.GetUnicode(), aString.Length()); +} + +nsTextFragment& +nsTextFragment::operator=(const nsTextFragment& aOther) +{ + if (aOther.Is2b()) { + SetTo(aOther.Get2b(), aOther.GetLength()); + } + else { + SetTo(aOther.Get1b(), aOther.GetLength()); + } + return *this; +} + +nsTextFragment& +nsTextFragment::operator=(const char* aString) +{ + SetTo(aString, nsCRT::strlen(aString)); + return *this; +} + +nsTextFragment& +nsTextFragment::operator=(const PRUnichar* aString) +{ + SetTo(aString, nsCRT::strlen(aString)); + return *this; +} + +nsTextFragment& +nsTextFragment::operator=(const nsString& aString) +{ + SetTo(aString.GetUnicode(), aString.Length()); + return *this; +} + +void +nsTextFragment::SetTo(PRUnichar* aBuffer, PRInt32 aLength, PRBool aRelease) +{ + ReleaseText(); + + m2b = aBuffer; + mIs2b = 1; + mInHeap = aRelease ? 1 : 0; + mLength = aLength; +} + +void +nsTextFragment::SetTo(const PRUnichar* aBuffer, PRInt32 aLength) +{ + ReleaseText(); + if (0 != aLength) { + // See if we need to store the data in ucs2 or not + PRBool need2 = PR_FALSE; + const PRUnichar* cp = aBuffer; + const PRUnichar* end = aBuffer + aLength; + while (cp < end) { + PRUnichar ch = *cp++; + if (ch >> 8) { + need2 = PR_TRUE; + break; + } + } + + if (need2) { + // Use ucs2 storage because we have to + PRUnichar* nt = new PRUnichar[aLength]; + if (nsnull != nt) { + // Copy data + nsCRT::memcpy(nt, aBuffer, sizeof(PRUnichar) * aLength); + + // Setup our fields + m2b = nt; + mIs2b = 1; + mInHeap = 1; + mLength = aLength; + } + } + else { + // Use 1 byte storage because we can + unsigned char* nt = new unsigned char[aLength]; + if (nsnull != nt) { + // Copy data + unsigned char* cp = nt; + unsigned char* end = nt + aLength; + while (cp < end) { + *cp++ = (unsigned char) *aBuffer++; + } + + // Setup our fields + m1b = nt; + mIs2b = 0; + mInHeap = 1; + mLength = aLength; + } + } + } +} + +void +nsTextFragment::SetTo(const char* aBuffer, PRInt32 aLength) +{ + ReleaseText(); + if (0 != aLength) { + unsigned char* nt = new unsigned char[aLength]; + if (nsnull != nt) { + nsCRT::memcpy(nt, aBuffer, sizeof(unsigned char) * aLength); + + m1b = nt; + mIs2b = 0; + mInHeap = 1; + mLength = aLength; + } + } +} + +void +nsTextFragment::AppendTo(nsString& aString) const +{ + if (mIs2b) { + aString.Append(m2b, mLength); + } + else { + aString.Append((char*)m1b, mLength); + } +} + +void +nsTextFragment::CopyTo(PRUnichar* aDest, PRInt32 aOffset, PRInt32 aCount) +{ + if (aOffset < 0) aOffset = 0; + if (aOffset + aCount > GetLength()) { + aCount = mLength - aOffset; + } + if (0 != aCount) { + if (mIs2b) { + nsCRT::memcpy(aDest, m2b + aOffset, sizeof(PRUnichar) * aCount); + } + else { + unsigned char* cp = m1b + aOffset; + unsigned char* end = cp + aCount; + while (cp < end) { + *aDest = PRUnichar(*cp++); + } + } + } +} + +void +nsTextFragment::CopyTo(char* aDest, PRInt32 aOffset, PRInt32 aCount) +{ + if (aOffset < 0) aOffset = 0; + if (aOffset + aCount > GetLength()) { + aCount = mLength - aOffset; + } + if (0 != aCount) { + if (mIs2b) { + PRUnichar* cp = m2b + aOffset; + PRUnichar* end = cp + aCount; + while (cp < end) { + *aDest = (unsigned char) (*cp++); + } + } + else { + nsCRT::memcpy(aDest, m1b + aOffset, sizeof(char) * aCount); + } + } +} diff --git a/mozilla/content/base/src/nsTextFragment.h b/mozilla/content/base/src/nsTextFragment.h new file mode 100644 index 00000000000..8c953e2c680 --- /dev/null +++ b/mozilla/content/base/src/nsTextFragment.h @@ -0,0 +1,213 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Mozilla Communicator client code. + * + * The Initial Developer of the Original Code is Netscape Communications + * Corporation. Portions created by Netscape are Copyright (C) 1998 + * Netscape Communications Corporation. All Rights Reserved. + */ +#ifndef nsTextFragment_h___ +#define nsTextFragment_h___ + +#include "nslayout.h" +class nsString; + +// XXX should this normalize the code to keep a \u0000 at the end? + +// XXX nsTextFragmentPool? + +/** + * A fragment of text. If mIs2b is 1 then the m2b pointer is valid + * otherwise the m1b pointer is valid. If m1b is used then each byte + * of data represents a single ucs2 character with the high byte being + * zero. + * + * This class does not have a virtual destructor therefore it is not + * meant to be subclassed. + */ +class NS_LAYOUT nsTextFragment { +public: + /** + * Default constructor. Initialize the fragment to be empty. + */ + nsTextFragment() { + m1b = nsnull; + mInHeap = 0; + mIs2b = 0; + mLength = 0; + } + + ~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 nsString& aString); + + /** + * Return PR_TRUE if this fragment is represented by PRUnichar data + */ + PRBool Is2b() const { + return mIs2b; + } + + /** + * Get a pointer to constant PRUnichar data. + */ + const PRUnichar* Get2b() const { + NS_ASSERTION(Is2b(), "not 2b text"); + return m2b; + } + + /** + * Get a pointer to constant char data. + */ + const char* Get1b() const { + NS_ASSERTION(!Is2b(), "not 1b text"); + return (const char*) m1b; + } + + /** + * Get the length of the fragment. The length is the number of logical + * characters, not the number of bytes to store the characters. + */ + PRInt32 GetLength() const { + return PRInt32(mLength); + } + + /** + * Mutable version of Get2b. Only works for a non-const object. + * Returns a pointer to the PRUnichar data. + */ + PRUnichar* Get2b() { + NS_ASSERTION(Is2b(), "not 2b text"); + return m2b; + } + + /** + * Mutable version of Get1b. Only works for a non-const object. + * Returns a pointer to the char data. + */ + char* Get1b() { + NS_ASSERTION(!Is2b(), "not 1b text"); + return (char*) m1b; + } + + /** + * 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 "new[]" + * because it will be released with "delete []". + */ + 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 + * assuming 0 termination. + */ + 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. + */ + void SetTo(const char* aBuffer, PRInt32 aLength); + + /** + * Append the contents of this string fragment to aString + */ + void AppendTo(nsString& aString) const; + + /** + * 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(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. + */ + PRUnichar CharAt(PRInt32 aIndex) const { + NS_ASSERTION(PRUint32(aIndex) < mLength, "bad index"); + return mIs2b ? m2b[aIndex] : PRUnichar(m1b[aIndex]); + } + +protected: + union { + PRUnichar* m2b; + unsigned char* m1b; + }; + PRUint32 mInHeap : 1; + PRUint32 mIs2b : 1; + PRUint32 mLength : 30; + + void ReleaseText(); +}; + +#endif /* nsTextFragment_h___ */ diff --git a/mozilla/content/shared/public/nsTextFragment.h b/mozilla/content/shared/public/nsTextFragment.h new file mode 100644 index 00000000000..8c953e2c680 --- /dev/null +++ b/mozilla/content/shared/public/nsTextFragment.h @@ -0,0 +1,213 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Mozilla Communicator client code. + * + * The Initial Developer of the Original Code is Netscape Communications + * Corporation. Portions created by Netscape are Copyright (C) 1998 + * Netscape Communications Corporation. All Rights Reserved. + */ +#ifndef nsTextFragment_h___ +#define nsTextFragment_h___ + +#include "nslayout.h" +class nsString; + +// XXX should this normalize the code to keep a \u0000 at the end? + +// XXX nsTextFragmentPool? + +/** + * A fragment of text. If mIs2b is 1 then the m2b pointer is valid + * otherwise the m1b pointer is valid. If m1b is used then each byte + * of data represents a single ucs2 character with the high byte being + * zero. + * + * This class does not have a virtual destructor therefore it is not + * meant to be subclassed. + */ +class NS_LAYOUT nsTextFragment { +public: + /** + * Default constructor. Initialize the fragment to be empty. + */ + nsTextFragment() { + m1b = nsnull; + mInHeap = 0; + mIs2b = 0; + mLength = 0; + } + + ~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 nsString& aString); + + /** + * Return PR_TRUE if this fragment is represented by PRUnichar data + */ + PRBool Is2b() const { + return mIs2b; + } + + /** + * Get a pointer to constant PRUnichar data. + */ + const PRUnichar* Get2b() const { + NS_ASSERTION(Is2b(), "not 2b text"); + return m2b; + } + + /** + * Get a pointer to constant char data. + */ + const char* Get1b() const { + NS_ASSERTION(!Is2b(), "not 1b text"); + return (const char*) m1b; + } + + /** + * Get the length of the fragment. The length is the number of logical + * characters, not the number of bytes to store the characters. + */ + PRInt32 GetLength() const { + return PRInt32(mLength); + } + + /** + * Mutable version of Get2b. Only works for a non-const object. + * Returns a pointer to the PRUnichar data. + */ + PRUnichar* Get2b() { + NS_ASSERTION(Is2b(), "not 2b text"); + return m2b; + } + + /** + * Mutable version of Get1b. Only works for a non-const object. + * Returns a pointer to the char data. + */ + char* Get1b() { + NS_ASSERTION(!Is2b(), "not 1b text"); + return (char*) m1b; + } + + /** + * 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 "new[]" + * because it will be released with "delete []". + */ + 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 + * assuming 0 termination. + */ + 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. + */ + void SetTo(const char* aBuffer, PRInt32 aLength); + + /** + * Append the contents of this string fragment to aString + */ + void AppendTo(nsString& aString) const; + + /** + * 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(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. + */ + PRUnichar CharAt(PRInt32 aIndex) const { + NS_ASSERTION(PRUint32(aIndex) < mLength, "bad index"); + return mIs2b ? m2b[aIndex] : PRUnichar(m1b[aIndex]); + } + +protected: + union { + PRUnichar* m2b; + unsigned char* m1b; + }; + PRUint32 mInHeap : 1; + PRUint32 mIs2b : 1; + PRUint32 mLength : 30; + + void ReleaseText(); +}; + +#endif /* nsTextFragment_h___ */ diff --git a/mozilla/content/shared/src/nsTextFragment.cpp b/mozilla/content/shared/src/nsTextFragment.cpp new file mode 100644 index 00000000000..9d3af945eda --- /dev/null +++ b/mozilla/content/shared/src/nsTextFragment.cpp @@ -0,0 +1,234 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Mozilla Communicator client code. + * + * The Initial Developer of the Original Code is Netscape Communications + * Corporation. Portions created by Netscape are Copyright (C) 1998 + * Netscape Communications Corporation. All Rights Reserved. + */ +#include "nsTextFragment.h" +#include "nsString.h" +#include "nsCRT.h" + +nsTextFragment::~nsTextFragment() +{ + ReleaseText(); +} + +void +nsTextFragment::ReleaseText() +{ + if (mLength && m1b && mInHeap) { + if (mIs2b) { + delete [] m2b; + } + else { + delete [] m1b; + } + } + m1b = nsnull; + mIs2b = 0; + mInHeap = 0; + mLength = 0; +} + +nsTextFragment::nsTextFragment(const nsTextFragment& aOther) +{ + if (aOther.Is2b()) { + SetTo(aOther.Get2b(), aOther.GetLength()); + } + else { + SetTo(aOther.Get1b(), aOther.GetLength()); + } +} + +nsTextFragment::nsTextFragment(const char* aString) +{ + SetTo(aString, strlen(aString)); +} + +nsTextFragment::nsTextFragment(const PRUnichar* aString) +{ + SetTo(aString, nsCRT::strlen(aString)); +} + +nsTextFragment::nsTextFragment(const nsString& aString) +{ + SetTo(aString.GetUnicode(), aString.Length()); +} + +nsTextFragment& +nsTextFragment::operator=(const nsTextFragment& aOther) +{ + if (aOther.Is2b()) { + SetTo(aOther.Get2b(), aOther.GetLength()); + } + else { + SetTo(aOther.Get1b(), aOther.GetLength()); + } + return *this; +} + +nsTextFragment& +nsTextFragment::operator=(const char* aString) +{ + SetTo(aString, nsCRT::strlen(aString)); + return *this; +} + +nsTextFragment& +nsTextFragment::operator=(const PRUnichar* aString) +{ + SetTo(aString, nsCRT::strlen(aString)); + return *this; +} + +nsTextFragment& +nsTextFragment::operator=(const nsString& aString) +{ + SetTo(aString.GetUnicode(), aString.Length()); + return *this; +} + +void +nsTextFragment::SetTo(PRUnichar* aBuffer, PRInt32 aLength, PRBool aRelease) +{ + ReleaseText(); + + m2b = aBuffer; + mIs2b = 1; + mInHeap = aRelease ? 1 : 0; + mLength = aLength; +} + +void +nsTextFragment::SetTo(const PRUnichar* aBuffer, PRInt32 aLength) +{ + ReleaseText(); + if (0 != aLength) { + // See if we need to store the data in ucs2 or not + PRBool need2 = PR_FALSE; + const PRUnichar* cp = aBuffer; + const PRUnichar* end = aBuffer + aLength; + while (cp < end) { + PRUnichar ch = *cp++; + if (ch >> 8) { + need2 = PR_TRUE; + break; + } + } + + if (need2) { + // Use ucs2 storage because we have to + PRUnichar* nt = new PRUnichar[aLength]; + if (nsnull != nt) { + // Copy data + nsCRT::memcpy(nt, aBuffer, sizeof(PRUnichar) * aLength); + + // Setup our fields + m2b = nt; + mIs2b = 1; + mInHeap = 1; + mLength = aLength; + } + } + else { + // Use 1 byte storage because we can + unsigned char* nt = new unsigned char[aLength]; + if (nsnull != nt) { + // Copy data + unsigned char* cp = nt; + unsigned char* end = nt + aLength; + while (cp < end) { + *cp++ = (unsigned char) *aBuffer++; + } + + // Setup our fields + m1b = nt; + mIs2b = 0; + mInHeap = 1; + mLength = aLength; + } + } + } +} + +void +nsTextFragment::SetTo(const char* aBuffer, PRInt32 aLength) +{ + ReleaseText(); + if (0 != aLength) { + unsigned char* nt = new unsigned char[aLength]; + if (nsnull != nt) { + nsCRT::memcpy(nt, aBuffer, sizeof(unsigned char) * aLength); + + m1b = nt; + mIs2b = 0; + mInHeap = 1; + mLength = aLength; + } + } +} + +void +nsTextFragment::AppendTo(nsString& aString) const +{ + if (mIs2b) { + aString.Append(m2b, mLength); + } + else { + aString.Append((char*)m1b, mLength); + } +} + +void +nsTextFragment::CopyTo(PRUnichar* aDest, PRInt32 aOffset, PRInt32 aCount) +{ + if (aOffset < 0) aOffset = 0; + if (aOffset + aCount > GetLength()) { + aCount = mLength - aOffset; + } + if (0 != aCount) { + if (mIs2b) { + nsCRT::memcpy(aDest, m2b + aOffset, sizeof(PRUnichar) * aCount); + } + else { + unsigned char* cp = m1b + aOffset; + unsigned char* end = cp + aCount; + while (cp < end) { + *aDest = PRUnichar(*cp++); + } + } + } +} + +void +nsTextFragment::CopyTo(char* aDest, PRInt32 aOffset, PRInt32 aCount) +{ + if (aOffset < 0) aOffset = 0; + if (aOffset + aCount > GetLength()) { + aCount = mLength - aOffset; + } + if (0 != aCount) { + if (mIs2b) { + PRUnichar* cp = m2b + aOffset; + PRUnichar* end = cp + aCount; + while (cp < end) { + *aDest = (unsigned char) (*cp++); + } + } + else { + nsCRT::memcpy(aDest, m1b + aOffset, sizeof(char) * aCount); + } + } +} diff --git a/mozilla/layout/base/public/nsTextFragment.h b/mozilla/layout/base/public/nsTextFragment.h new file mode 100644 index 00000000000..8c953e2c680 --- /dev/null +++ b/mozilla/layout/base/public/nsTextFragment.h @@ -0,0 +1,213 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Mozilla Communicator client code. + * + * The Initial Developer of the Original Code is Netscape Communications + * Corporation. Portions created by Netscape are Copyright (C) 1998 + * Netscape Communications Corporation. All Rights Reserved. + */ +#ifndef nsTextFragment_h___ +#define nsTextFragment_h___ + +#include "nslayout.h" +class nsString; + +// XXX should this normalize the code to keep a \u0000 at the end? + +// XXX nsTextFragmentPool? + +/** + * A fragment of text. If mIs2b is 1 then the m2b pointer is valid + * otherwise the m1b pointer is valid. If m1b is used then each byte + * of data represents a single ucs2 character with the high byte being + * zero. + * + * This class does not have a virtual destructor therefore it is not + * meant to be subclassed. + */ +class NS_LAYOUT nsTextFragment { +public: + /** + * Default constructor. Initialize the fragment to be empty. + */ + nsTextFragment() { + m1b = nsnull; + mInHeap = 0; + mIs2b = 0; + mLength = 0; + } + + ~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 nsString& aString); + + /** + * Return PR_TRUE if this fragment is represented by PRUnichar data + */ + PRBool Is2b() const { + return mIs2b; + } + + /** + * Get a pointer to constant PRUnichar data. + */ + const PRUnichar* Get2b() const { + NS_ASSERTION(Is2b(), "not 2b text"); + return m2b; + } + + /** + * Get a pointer to constant char data. + */ + const char* Get1b() const { + NS_ASSERTION(!Is2b(), "not 1b text"); + return (const char*) m1b; + } + + /** + * Get the length of the fragment. The length is the number of logical + * characters, not the number of bytes to store the characters. + */ + PRInt32 GetLength() const { + return PRInt32(mLength); + } + + /** + * Mutable version of Get2b. Only works for a non-const object. + * Returns a pointer to the PRUnichar data. + */ + PRUnichar* Get2b() { + NS_ASSERTION(Is2b(), "not 2b text"); + return m2b; + } + + /** + * Mutable version of Get1b. Only works for a non-const object. + * Returns a pointer to the char data. + */ + char* Get1b() { + NS_ASSERTION(!Is2b(), "not 1b text"); + return (char*) m1b; + } + + /** + * 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 "new[]" + * because it will be released with "delete []". + */ + 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 + * assuming 0 termination. + */ + 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. + */ + void SetTo(const char* aBuffer, PRInt32 aLength); + + /** + * Append the contents of this string fragment to aString + */ + void AppendTo(nsString& aString) const; + + /** + * 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(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. + */ + PRUnichar CharAt(PRInt32 aIndex) const { + NS_ASSERTION(PRUint32(aIndex) < mLength, "bad index"); + return mIs2b ? m2b[aIndex] : PRUnichar(m1b[aIndex]); + } + +protected: + union { + PRUnichar* m2b; + unsigned char* m1b; + }; + PRUint32 mInHeap : 1; + PRUint32 mIs2b : 1; + PRUint32 mLength : 30; + + void ReleaseText(); +}; + +#endif /* nsTextFragment_h___ */ diff --git a/mozilla/layout/base/src/nsTextFragment.cpp b/mozilla/layout/base/src/nsTextFragment.cpp new file mode 100644 index 00000000000..9d3af945eda --- /dev/null +++ b/mozilla/layout/base/src/nsTextFragment.cpp @@ -0,0 +1,234 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Mozilla Communicator client code. + * + * The Initial Developer of the Original Code is Netscape Communications + * Corporation. Portions created by Netscape are Copyright (C) 1998 + * Netscape Communications Corporation. All Rights Reserved. + */ +#include "nsTextFragment.h" +#include "nsString.h" +#include "nsCRT.h" + +nsTextFragment::~nsTextFragment() +{ + ReleaseText(); +} + +void +nsTextFragment::ReleaseText() +{ + if (mLength && m1b && mInHeap) { + if (mIs2b) { + delete [] m2b; + } + else { + delete [] m1b; + } + } + m1b = nsnull; + mIs2b = 0; + mInHeap = 0; + mLength = 0; +} + +nsTextFragment::nsTextFragment(const nsTextFragment& aOther) +{ + if (aOther.Is2b()) { + SetTo(aOther.Get2b(), aOther.GetLength()); + } + else { + SetTo(aOther.Get1b(), aOther.GetLength()); + } +} + +nsTextFragment::nsTextFragment(const char* aString) +{ + SetTo(aString, strlen(aString)); +} + +nsTextFragment::nsTextFragment(const PRUnichar* aString) +{ + SetTo(aString, nsCRT::strlen(aString)); +} + +nsTextFragment::nsTextFragment(const nsString& aString) +{ + SetTo(aString.GetUnicode(), aString.Length()); +} + +nsTextFragment& +nsTextFragment::operator=(const nsTextFragment& aOther) +{ + if (aOther.Is2b()) { + SetTo(aOther.Get2b(), aOther.GetLength()); + } + else { + SetTo(aOther.Get1b(), aOther.GetLength()); + } + return *this; +} + +nsTextFragment& +nsTextFragment::operator=(const char* aString) +{ + SetTo(aString, nsCRT::strlen(aString)); + return *this; +} + +nsTextFragment& +nsTextFragment::operator=(const PRUnichar* aString) +{ + SetTo(aString, nsCRT::strlen(aString)); + return *this; +} + +nsTextFragment& +nsTextFragment::operator=(const nsString& aString) +{ + SetTo(aString.GetUnicode(), aString.Length()); + return *this; +} + +void +nsTextFragment::SetTo(PRUnichar* aBuffer, PRInt32 aLength, PRBool aRelease) +{ + ReleaseText(); + + m2b = aBuffer; + mIs2b = 1; + mInHeap = aRelease ? 1 : 0; + mLength = aLength; +} + +void +nsTextFragment::SetTo(const PRUnichar* aBuffer, PRInt32 aLength) +{ + ReleaseText(); + if (0 != aLength) { + // See if we need to store the data in ucs2 or not + PRBool need2 = PR_FALSE; + const PRUnichar* cp = aBuffer; + const PRUnichar* end = aBuffer + aLength; + while (cp < end) { + PRUnichar ch = *cp++; + if (ch >> 8) { + need2 = PR_TRUE; + break; + } + } + + if (need2) { + // Use ucs2 storage because we have to + PRUnichar* nt = new PRUnichar[aLength]; + if (nsnull != nt) { + // Copy data + nsCRT::memcpy(nt, aBuffer, sizeof(PRUnichar) * aLength); + + // Setup our fields + m2b = nt; + mIs2b = 1; + mInHeap = 1; + mLength = aLength; + } + } + else { + // Use 1 byte storage because we can + unsigned char* nt = new unsigned char[aLength]; + if (nsnull != nt) { + // Copy data + unsigned char* cp = nt; + unsigned char* end = nt + aLength; + while (cp < end) { + *cp++ = (unsigned char) *aBuffer++; + } + + // Setup our fields + m1b = nt; + mIs2b = 0; + mInHeap = 1; + mLength = aLength; + } + } + } +} + +void +nsTextFragment::SetTo(const char* aBuffer, PRInt32 aLength) +{ + ReleaseText(); + if (0 != aLength) { + unsigned char* nt = new unsigned char[aLength]; + if (nsnull != nt) { + nsCRT::memcpy(nt, aBuffer, sizeof(unsigned char) * aLength); + + m1b = nt; + mIs2b = 0; + mInHeap = 1; + mLength = aLength; + } + } +} + +void +nsTextFragment::AppendTo(nsString& aString) const +{ + if (mIs2b) { + aString.Append(m2b, mLength); + } + else { + aString.Append((char*)m1b, mLength); + } +} + +void +nsTextFragment::CopyTo(PRUnichar* aDest, PRInt32 aOffset, PRInt32 aCount) +{ + if (aOffset < 0) aOffset = 0; + if (aOffset + aCount > GetLength()) { + aCount = mLength - aOffset; + } + if (0 != aCount) { + if (mIs2b) { + nsCRT::memcpy(aDest, m2b + aOffset, sizeof(PRUnichar) * aCount); + } + else { + unsigned char* cp = m1b + aOffset; + unsigned char* end = cp + aCount; + while (cp < end) { + *aDest = PRUnichar(*cp++); + } + } + } +} + +void +nsTextFragment::CopyTo(char* aDest, PRInt32 aOffset, PRInt32 aCount) +{ + if (aOffset < 0) aOffset = 0; + if (aOffset + aCount > GetLength()) { + aCount = mLength - aOffset; + } + if (0 != aCount) { + if (mIs2b) { + PRUnichar* cp = m2b + aOffset; + PRUnichar* end = cp + aCount; + while (cp < end) { + *aDest = (unsigned char) (*cp++); + } + } + else { + nsCRT::memcpy(aDest, m1b + aOffset, sizeof(char) * aCount); + } + } +} diff --git a/mozilla/layout/generic/nsTextTransformer.cpp b/mozilla/layout/generic/nsTextTransformer.cpp new file mode 100644 index 00000000000..e5ccf0d7936 --- /dev/null +++ b/mozilla/layout/generic/nsTextTransformer.cpp @@ -0,0 +1,442 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Mozilla Communicator client code. + * + * The Initial Developer of the Original Code is Netscape Communications + * Corporation. Portions created by Netscape are Copyright (C) 1998 + * Netscape Communications Corporation. All Rights Reserved. + */ +#include "nsTextTransformer.h" +#include "nsIContent.h" +#include "nsIFrame.h" +#include "nsIStyleContext.h" +#include "nsITextContent.h" +#include "nsStyleConsts.h" + +// XXX put a copy in nsHTMLIIDs +static NS_DEFINE_IID(kITextContentIID, NS_ITEXT_CONTENT_IID); + +// XXX temporary +#define XP_IS_SPACE(_ch) \ + (((_ch) == ' ') || ((_ch) == '\t') || ((_ch) == '\n')) + +// XXX need more of this in nsIRenderingContext.GetWidth +#define CH_NBSP 160 + +#define MAX_UNIBYTE 127 + +nsTextTransformer::nsTextTransformer(PRUnichar* aBuffer, PRInt32 aBufLen) + : mAutoBuffer(aBuffer), + mBuffer(aBuffer), + mBufferLength(aBufLen < 0 ? 0 : aBufLen), + mHasMultibyte(PR_FALSE) +{ +} + +nsTextTransformer::~nsTextTransformer() +{ + if (mBuffer != mAutoBuffer) { + delete [] mBuffer; + } +} + +nsresult +nsTextTransformer::Init(/*nsTextRun& aTextRun, XXX*/ + nsIFrame* aFrame, + PRInt32 aStartingOffset) +{ + // Make sure we have *some* space in case arguments to the ctor were + // bizzare. + if (mBufferLength < 100) { + if (!GrowBuffer()) { + return NS_ERROR_OUT_OF_MEMORY; + } + } + + // Get the frames text content + nsIContent* content; + aFrame->GetContent(content); + nsITextContent* tc; + if (NS_OK != content->QueryInterface(kITextContentIID, (void**) &tc)) { + NS_RELEASE(content); + return NS_OK; + } + tc->GetText(mFrags, mNumFrags); + NS_RELEASE(tc); + NS_RELEASE(content); + mStartingOffset = aStartingOffset; + mOffset = mStartingOffset; + + // Compute the total length of the text content. + PRInt32 sum = 0; + PRInt32 n = mNumFrags; + const nsTextFragment* frag = mFrags; + for (; --n >= 0; frag++) { + sum += frag->GetLength(); + } + mContentLength = sum; + + // Set current fragment and current fragment offset + mCurrentFrag = mFrags; + mCurrentFragOffset = 0; + PRInt32 offset = 0; + n = mNumFrags; + for (frag = mFrags; --n >= 0; frag++) { + if (aStartingOffset < offset + frag->GetLength()) { + mCurrentFrag = frag; + mCurrentFragOffset = aStartingOffset - offset; + break; + } + offset += frag->GetLength(); + } + + // Get the frames style and choose a transform proc + const nsStyleText* styleText; + aFrame->GetStyleData(eStyleStruct_Text, (const nsStyleStruct*&) styleText); + mCompressWS = NS_STYLE_WHITESPACE_PRE != styleText->mWhiteSpace; + + return NS_OK; +} + +PRBool +nsTextTransformer::GrowBuffer() +{ + PRInt32 newLen = mBufferLength * 2; + if (newLen <= 100) { + newLen = 100; + } + PRUnichar* newBuffer = new PRUnichar[newLen]; + if (nsnull == newBuffer) { + return PR_FALSE; + } + if (0 != mBufferLength) { + nsCRT::memcpy(newBuffer, mBuffer, sizeof(PRUnichar) * mBufferLength); + if (mBuffer != mAutoBuffer) { + delete [] mBuffer; + } + } + mBuffer = newBuffer; + return PR_TRUE; +} + +PRUnichar* +nsTextTransformer::GetNextWord(PRInt32& aWordLenResult, + PRInt32& aContentLenResult, + PRBool& aIsWhitespaceResult) +{ + NS_PRECONDITION(mOffset <= mContentLength, "bad offset"); + + // See if the content has been exhausted + if (mOffset == mContentLength) { + aWordLenResult = 0; + aContentLenResult = 0; + return nsnull; + } + + PRUnichar* bp = mBuffer; + PRUnichar* bufEnd = mBuffer + mBufferLength; + + const nsTextFragment* frag = mCurrentFrag; + const nsTextFragment* lastFrag = frag + mNumFrags; + + // Set the isWhitespace flag by examining the next character in the + // text fragment. + PRInt32 offset = mCurrentFragOffset; + PRUnichar firstChar; + if (frag->Is2b()) { + const PRUnichar* up = frag->Get2b(); + firstChar = up[offset]; + } + else { + const unsigned char* cp = (const unsigned char*) frag->Get1b(); + firstChar = PRUnichar(cp[offset]); + } + PRBool isWhitespace = XP_IS_SPACE(firstChar); + offset++; + if (isWhitespace || (CH_NBSP == firstChar)) { + *bp++ = ' '; + } + else { + *bp++ = firstChar; + } + PRInt32 contentLen = 1; + PRInt32 wordLen = 1; + if (offset == frag->GetLength()) { + mCurrentFrag = ++frag; + offset = 0; + } + mCurrentFragOffset = offset; + + // XXX here is where we switch out to type specific handlers; this + // code assumes mCompressWS is PR_TRUE + + // Now that we know what we are looking for, scan through the text + // content and find the end of it. + PRInt32 numChars; + while (frag < lastFrag) { + PRInt32 fragLen = frag->GetLength(); + + // Scan characters in this fragment that are the same kind as the + // isWhitespace flag indicates. + if (frag->Is2b()) { + const PRUnichar* cp0 = frag->Get2b(); + const PRUnichar* end = cp0 + fragLen; + const PRUnichar* cp = cp0 + offset; + if (isWhitespace) { + while (cp < end) { + PRUnichar ch = *cp; + if (XP_IS_SPACE(ch)) { + cp++; + continue; + } + numChars = (cp - offset) - cp0; + contentLen += numChars; + mCurrentFragOffset += numChars; + goto done; + } + numChars = (cp - offset) - cp0; + contentLen += numChars; + } + else { + while (cp < end) { + PRUnichar ch = *cp; + if (!XP_IS_SPACE(ch)) { + if (CH_NBSP == ch) ch = ' '; + if (ch > MAX_UNIBYTE) mHasMultibyte = PR_TRUE; + cp++; + // Store character in buffer; grow buffer if we have to + *bp++ = ch; + if (bp == bufEnd) { + PRInt32 delta = bp - mBuffer; + if (!GrowBuffer()) { + goto done; + } + bp = mBuffer + delta; + bufEnd = mBuffer + mBufferLength; + } + continue; + } + numChars = (cp - offset) - cp0; + wordLen += numChars; + contentLen += numChars; + mCurrentFragOffset += numChars; + goto done; + } + numChars = (cp - offset) - cp0; + wordLen += numChars; + contentLen += numChars; + } + } + else { + const unsigned char* cp0 = (const unsigned char*) frag->Get1b(); + const unsigned char* end = cp0 + fragLen; + const unsigned char* cp = cp0 + offset; + if (isWhitespace) { + while (cp < end) { + PRUnichar ch = PRUnichar(*cp); + if (XP_IS_SPACE(ch)) { + cp++; + continue; + } + numChars = (cp - offset) - cp0; + contentLen += numChars; + mCurrentFragOffset += numChars; + goto done; + } + numChars = (cp - offset) - cp0; + contentLen += numChars; + } + else { + while (cp < end) { + PRUnichar ch = PRUnichar(*cp); + if (!XP_IS_SPACE(ch)) { + if (CH_NBSP == ch) ch = ' '; + if (ch > MAX_UNIBYTE) mHasMultibyte = PR_TRUE; + cp++; + // Store character in buffer; grow buffer if we have to + *bp++ = ch; + if (bp == bufEnd) { + PRInt32 delta = bp - mBuffer; + if (!GrowBuffer()) { + goto done; + } + bp = mBuffer + delta; + bufEnd = mBuffer + mBufferLength; + } + continue; + } + numChars = (cp - offset) - cp0; + wordLen += numChars; + contentLen += numChars; + mCurrentFragOffset += numChars; + goto done; + } + numChars = (cp - offset) - cp0; + wordLen += numChars; + contentLen += numChars; + } + } + + // Advance to next text fragment + frag++; + mCurrentFrag = frag; + mCurrentFragOffset = 0; + offset = 0; + } + + done:; + mOffset += contentLen; + NS_ASSERTION(mOffset <= mContentLength, "whoops"); + aWordLenResult = wordLen; + aContentLenResult = contentLen; + aIsWhitespaceResult = isWhitespace; + return mBuffer; +} + +PRUnichar* +nsTextTransformer::GetNextSection(PRInt32& aLineLenResult, + PRInt32& aContentLenResult) +{ + NS_PRECONDITION(mOffset <= mContentLength, "bad offset"); + + // See if the content has been exhausted + if (mOffset == mContentLength) { + aLineLenResult = 0; + aContentLenResult = 0; + return nsnull; + } + + PRUnichar* bp = mBuffer; + PRUnichar* bufEnd = mBuffer + mBufferLength; + + const nsTextFragment* frag = mCurrentFrag; + const nsTextFragment* lastFrag = frag + mNumFrags; + PRInt32 contentLen = 0; + PRInt32 lineLen = 0; + + while (frag < lastFrag) { + PRInt32 fragLen = frag->GetLength(); + + // Scan characters in the fragment until we run out or we hit a + // newline. + if (frag->Is2b()) { + const PRUnichar* cp0 = frag->Get2b(); + const PRUnichar* end = cp0 + fragLen; + const PRUnichar* cp = cp0 + mCurrentFragOffset; + while (cp < end) { + PRUnichar ch = *cp++; + if ('\t' == ch) { + // Keep tabs seperate from other content + if (0 != lineLen) { + goto done; + } + *bp++ = ch; + lineLen++; + contentLen++; + mCurrentFragOffset++; + goto done; + } + else if ('\n' == ch) { + // Keep newlines seperate from other content + if (0 != lineLen) { + goto done; + } + // Include newline in content-len but not in line-len + contentLen++; + mCurrentFragOffset++; + goto done; + } + else if (CH_NBSP == ch) { + ch = ' '; + } + if (ch > MAX_UNIBYTE) mHasMultibyte = PR_TRUE; + *bp++ = ch; + if (bp == bufEnd) { + PRInt32 delta = bp - mBuffer; + if (!GrowBuffer()) { + goto done; + } + bp = mBuffer + delta; + bufEnd = mBuffer + mBufferLength; + } + lineLen++; + contentLen++; + mCurrentFragOffset++; + } + } + else { + const unsigned char* cp0 = (const unsigned char*) frag->Get1b(); + const unsigned char* end = cp0 + fragLen; + const unsigned char* cp = cp0 + mCurrentFragOffset; + while (cp < end) { + PRUnichar ch = PRUnichar(*cp++); + if ('\t' == ch) { + // Keep tabs seperate from other content + if (0 != lineLen) { + goto done; + } + *bp++ = ch; + lineLen++; + contentLen++; + mCurrentFragOffset++; + goto done; + } + else if ('\n' == ch) { + // Keep newlines seperate from other content + if (0 != lineLen) { + goto done; + } + // Include newline in content-len but not in line-len + contentLen++; + mCurrentFragOffset++; + goto done; + } + else if (CH_NBSP == ch) { + ch = ' '; + } + if (ch > MAX_UNIBYTE) mHasMultibyte = PR_TRUE; + *bp++ = ch; + if (bp == bufEnd) { + PRInt32 delta = bp - mBuffer; + if (!GrowBuffer()) { + goto done; + } + bp = mBuffer + delta; + bufEnd = mBuffer + mBufferLength; + } + lineLen++; + contentLen++; + mCurrentFragOffset++; + } + } + + // Advance to next text fragment + frag++; + mCurrentFrag = frag; + mCurrentFragOffset = 0; + } + + done:; + mOffset += contentLen; + NS_ASSERTION(mOffset <= mContentLength, "whoops"); + aLineLenResult = lineLen; + aContentLenResult = contentLen; + return mBuffer; +} + +PRUnichar* +nsTextTransformer::GetTextAt(PRInt32 aOffset) +{ + // XXX + return mBuffer + aOffset; +} diff --git a/mozilla/layout/generic/nsTextTransformer.h b/mozilla/layout/generic/nsTextTransformer.h new file mode 100644 index 00000000000..46dac8ca235 --- /dev/null +++ b/mozilla/layout/generic/nsTextTransformer.h @@ -0,0 +1,138 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Mozilla Communicator client code. + * + * The Initial Developer of the Original Code is Netscape Communications + * Corporation. Portions created by Netscape are Copyright (C) 1998 + * Netscape Communications Corporation. All Rights Reserved. + */ +#ifndef nsTextTransformer_h___ +#define nsTextTransformer_h___ + +#include "nsTextFragment.h" +#include "nsISupports.h" + +class nsIFrame; +class nsTextRun; + +/** + * This object manages the transformation of text: + * + *