new
git-svn-id: svn://10.0.0.236/trunk@13148 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
213
mozilla/content/base/public/nsTextFragment.h
Normal file
213
mozilla/content/base/public/nsTextFragment.h
Normal file
@@ -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___ */
|
||||
234
mozilla/content/base/src/nsTextFragment.cpp
Normal file
234
mozilla/content/base/src/nsTextFragment.cpp
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
213
mozilla/content/base/src/nsTextFragment.h
Normal file
213
mozilla/content/base/src/nsTextFragment.h
Normal file
@@ -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___ */
|
||||
213
mozilla/content/shared/public/nsTextFragment.h
Normal file
213
mozilla/content/shared/public/nsTextFragment.h
Normal file
@@ -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___ */
|
||||
234
mozilla/content/shared/src/nsTextFragment.cpp
Normal file
234
mozilla/content/shared/src/nsTextFragment.cpp
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
213
mozilla/layout/base/public/nsTextFragment.h
Normal file
213
mozilla/layout/base/public/nsTextFragment.h
Normal file
@@ -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___ */
|
||||
234
mozilla/layout/base/src/nsTextFragment.cpp
Normal file
234
mozilla/layout/base/src/nsTextFragment.cpp
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
442
mozilla/layout/generic/nsTextTransformer.cpp
Normal file
442
mozilla/layout/generic/nsTextTransformer.cpp
Normal file
@@ -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;
|
||||
}
|
||||
138
mozilla/layout/generic/nsTextTransformer.h
Normal file
138
mozilla/layout/generic/nsTextTransformer.h
Normal file
@@ -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:
|
||||
*
|
||||
* <UL>
|
||||
* <LI>whitespace compression
|
||||
* <LI>capitalization
|
||||
* <LI>lowercasing
|
||||
* <LI>uppercasing
|
||||
* </UL>
|
||||
*
|
||||
* Note that no transformations are applied that would impact word
|
||||
* breaking (like mapping into space, for example). In
|
||||
* addition, this logic will not strip leading or trailing whitespace
|
||||
* (across the entire run of text; leading whitespace can be skipped
|
||||
* for a frames text because of whitespace compression).
|
||||
*/
|
||||
class nsTextTransformer {
|
||||
public:
|
||||
nsTextTransformer(PRUnichar* aBuffer, PRInt32 aBufLen);
|
||||
~nsTextTransformer();
|
||||
|
||||
/**
|
||||
* Initialize the text transform. This is when the transformation
|
||||
* occurs. Subsequent calls to GetTransformedTextFor will just
|
||||
* return the result of the single transformation.
|
||||
*/
|
||||
nsresult Init(/*nsTextRun& aTextRun, XXX*/
|
||||
nsIFrame* aFrame,
|
||||
PRInt32 aStartingOffset);
|
||||
|
||||
PRInt32 GetContentLength() const {
|
||||
return mContentLength;
|
||||
}
|
||||
|
||||
PRUnichar* GetNextWord(PRInt32& aWordLenResult,
|
||||
PRInt32& aContentLenResult,
|
||||
PRBool& aIsWhitespaceResult);
|
||||
|
||||
PRUnichar* GetNextSection(PRInt32& aLineLenResult,
|
||||
PRInt32& aContentLenResult);
|
||||
|
||||
PRBool HasMultibyte() const {
|
||||
return mHasMultibyte;
|
||||
}
|
||||
|
||||
PRUnichar* GetTextAt(PRInt32 aOffset);
|
||||
|
||||
protected:
|
||||
|
||||
PRUnichar* mAutoBuffer;
|
||||
PRInt32 mAutoBufferLength;
|
||||
PRUnichar* mBuffer;
|
||||
PRInt32 mBufferLength;
|
||||
PRBool mHasMultibyte;
|
||||
|
||||
PRInt32 mContentLength;
|
||||
PRInt32 mStartingOffset;
|
||||
PRInt32 mOffset;
|
||||
|
||||
const nsTextFragment* mFrags;
|
||||
PRInt32 mNumFrags;
|
||||
const nsTextFragment* mCurrentFrag;
|
||||
PRInt32 mCurrentFragOffset;
|
||||
|
||||
// XXX temporary
|
||||
PRBool mCompressWS;
|
||||
|
||||
PRBool GrowBuffer();
|
||||
|
||||
#if 0
|
||||
// For each piece of content in the text-run we keep track of this
|
||||
// state.
|
||||
struct Text {
|
||||
nsIContent* mContent;
|
||||
nsTransformedTextFragment* mFrags;
|
||||
PRInt32 mNumFrags;
|
||||
Text* mNext;
|
||||
};
|
||||
|
||||
Text* mTextList;
|
||||
|
||||
void ReleaseResources();
|
||||
#endif
|
||||
|
||||
// A little state object used to do bookeeping between the low level
|
||||
// transform calls.
|
||||
struct TransformerState {
|
||||
PRBool mSkipLeadingWS;
|
||||
PRInt32 mContentOffset;
|
||||
};
|
||||
|
||||
nsresult Transform2b(TransformerState& aState,
|
||||
const nsTextFragment& frag);
|
||||
|
||||
nsresult Transform1b(TransformerState& aState,
|
||||
const nsTextFragment& frag);
|
||||
|
||||
nsresult CompressWS2b(TransformerState& aState,
|
||||
const nsTextFragment& frag);
|
||||
|
||||
nsresult CompressWS1b(TransformerState& aState,
|
||||
const nsTextFragment& frag);
|
||||
|
||||
nsresult CompressWSAndTransform2b(TransformerState& aState,
|
||||
const nsTextFragment& frag);
|
||||
|
||||
nsresult CompressWSAndTransform1b(TransformerState& aState,
|
||||
const nsTextFragment& frag);
|
||||
};
|
||||
|
||||
#endif /* nsTextTransformer_h___ */
|
||||
75
mozilla/layout/html/base/src/nsTextReflow.h
Normal file
75
mozilla/layout/html/base/src/nsTextReflow.h
Normal file
@@ -0,0 +1,75 @@
|
||||
/* -*- 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 nsTextReflow_h___
|
||||
#define nsTextReflow_h___
|
||||
|
||||
#include "nslayout.h"
|
||||
#include "nsIFrame.h"
|
||||
#include "nsVoidArray.h"
|
||||
|
||||
class nsIContent;
|
||||
class nsTextFragment;
|
||||
|
||||
// XXX it might be cheaper to have the text-run only contain the
|
||||
// content pointer instead of the frame pointer
|
||||
|
||||
// A run of text. In mText are the nsIFrame's that are considered text
|
||||
// frames.
|
||||
class nsTextRun {
|
||||
public:
|
||||
nsTextRun();
|
||||
~nsTextRun();
|
||||
|
||||
nsIFrame* FindNextText(nsIFrame* aFrame);
|
||||
|
||||
nsTextRun* GetNext() const {
|
||||
return mNext;
|
||||
}
|
||||
|
||||
void SetNext(nsTextRun* aNext) {
|
||||
mNext = aNext;
|
||||
}
|
||||
|
||||
PRInt32 Count() const {
|
||||
return mArray.Count();
|
||||
}
|
||||
|
||||
nsIFrame* operator[](PRInt32 aIndex) const {
|
||||
return (nsIFrame*) mArray[aIndex];
|
||||
}
|
||||
|
||||
void List(FILE* out, PRInt32 aIndent);
|
||||
|
||||
static void DeleteTextRuns(nsTextRun* aRun) {
|
||||
while (nsnull != aRun) {
|
||||
nsTextRun* next = aRun->GetNext();
|
||||
delete aRun;
|
||||
aRun = next;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
nsVoidArray mArray;
|
||||
nsTextRun* mNext;
|
||||
|
||||
// XXX get rid of this
|
||||
friend class nsLineLayout;
|
||||
};
|
||||
|
||||
#endif /* nsTextReflow_h___ */
|
||||
442
mozilla/layout/html/base/src/nsTextTransformer.cpp
Normal file
442
mozilla/layout/html/base/src/nsTextTransformer.cpp
Normal file
@@ -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;
|
||||
}
|
||||
138
mozilla/layout/html/base/src/nsTextTransformer.h
Normal file
138
mozilla/layout/html/base/src/nsTextTransformer.h
Normal file
@@ -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:
|
||||
*
|
||||
* <UL>
|
||||
* <LI>whitespace compression
|
||||
* <LI>capitalization
|
||||
* <LI>lowercasing
|
||||
* <LI>uppercasing
|
||||
* </UL>
|
||||
*
|
||||
* Note that no transformations are applied that would impact word
|
||||
* breaking (like mapping into space, for example). In
|
||||
* addition, this logic will not strip leading or trailing whitespace
|
||||
* (across the entire run of text; leading whitespace can be skipped
|
||||
* for a frames text because of whitespace compression).
|
||||
*/
|
||||
class nsTextTransformer {
|
||||
public:
|
||||
nsTextTransformer(PRUnichar* aBuffer, PRInt32 aBufLen);
|
||||
~nsTextTransformer();
|
||||
|
||||
/**
|
||||
* Initialize the text transform. This is when the transformation
|
||||
* occurs. Subsequent calls to GetTransformedTextFor will just
|
||||
* return the result of the single transformation.
|
||||
*/
|
||||
nsresult Init(/*nsTextRun& aTextRun, XXX*/
|
||||
nsIFrame* aFrame,
|
||||
PRInt32 aStartingOffset);
|
||||
|
||||
PRInt32 GetContentLength() const {
|
||||
return mContentLength;
|
||||
}
|
||||
|
||||
PRUnichar* GetNextWord(PRInt32& aWordLenResult,
|
||||
PRInt32& aContentLenResult,
|
||||
PRBool& aIsWhitespaceResult);
|
||||
|
||||
PRUnichar* GetNextSection(PRInt32& aLineLenResult,
|
||||
PRInt32& aContentLenResult);
|
||||
|
||||
PRBool HasMultibyte() const {
|
||||
return mHasMultibyte;
|
||||
}
|
||||
|
||||
PRUnichar* GetTextAt(PRInt32 aOffset);
|
||||
|
||||
protected:
|
||||
|
||||
PRUnichar* mAutoBuffer;
|
||||
PRInt32 mAutoBufferLength;
|
||||
PRUnichar* mBuffer;
|
||||
PRInt32 mBufferLength;
|
||||
PRBool mHasMultibyte;
|
||||
|
||||
PRInt32 mContentLength;
|
||||
PRInt32 mStartingOffset;
|
||||
PRInt32 mOffset;
|
||||
|
||||
const nsTextFragment* mFrags;
|
||||
PRInt32 mNumFrags;
|
||||
const nsTextFragment* mCurrentFrag;
|
||||
PRInt32 mCurrentFragOffset;
|
||||
|
||||
// XXX temporary
|
||||
PRBool mCompressWS;
|
||||
|
||||
PRBool GrowBuffer();
|
||||
|
||||
#if 0
|
||||
// For each piece of content in the text-run we keep track of this
|
||||
// state.
|
||||
struct Text {
|
||||
nsIContent* mContent;
|
||||
nsTransformedTextFragment* mFrags;
|
||||
PRInt32 mNumFrags;
|
||||
Text* mNext;
|
||||
};
|
||||
|
||||
Text* mTextList;
|
||||
|
||||
void ReleaseResources();
|
||||
#endif
|
||||
|
||||
// A little state object used to do bookeeping between the low level
|
||||
// transform calls.
|
||||
struct TransformerState {
|
||||
PRBool mSkipLeadingWS;
|
||||
PRInt32 mContentOffset;
|
||||
};
|
||||
|
||||
nsresult Transform2b(TransformerState& aState,
|
||||
const nsTextFragment& frag);
|
||||
|
||||
nsresult Transform1b(TransformerState& aState,
|
||||
const nsTextFragment& frag);
|
||||
|
||||
nsresult CompressWS2b(TransformerState& aState,
|
||||
const nsTextFragment& frag);
|
||||
|
||||
nsresult CompressWS1b(TransformerState& aState,
|
||||
const nsTextFragment& frag);
|
||||
|
||||
nsresult CompressWSAndTransform2b(TransformerState& aState,
|
||||
const nsTextFragment& frag);
|
||||
|
||||
nsresult CompressWSAndTransform1b(TransformerState& aState,
|
||||
const nsTextFragment& frag);
|
||||
};
|
||||
|
||||
#endif /* nsTextTransformer_h___ */
|
||||
Reference in New Issue
Block a user