Reduce string copying and allocation in the parser by only copying the scanner buffer when we need to mutate the string. Allow a nsDependentString / nsDependentSubstring to be created without being bound to anything. Move StripChar() onto nsSubstring from nsString. Bug 269853, r=jst, sr=darin.

git-svn-id: svn://10.0.0.236/trunk@165773 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
bryner%brianryner.com
2004-11-25 07:03:20 +00:00
parent 2e6bee01c4
commit 7a461c49a4
17 changed files with 458 additions and 138 deletions

View File

@@ -180,18 +180,20 @@ nsresult CStartToken::Consume(PRUnichar aChar, nsScanner& aScanner,PRInt32 aFlag
//NOTE: We don't Consume the tag attributes here, nor do we eat the ">"
nsresult result=NS_OK;
nsScannerSharedSubstring tagIdent;
if (aFlag & NS_IPARSER_FLAG_HTML) {
nsAutoString theSubstr;
result=aScanner.ReadTagIdentifier(theSubstr);
mTypeID = (PRInt32)nsHTMLTags::LookupTag(theSubstr);
result = aScanner.ReadTagIdentifier(tagIdent);
mTypeID = (PRInt32)nsHTMLTags::LookupTag(tagIdent.str());
// Save the original tag string if this is user-defined or if we
// are viewing source
if(eHTMLTag_userdefined==mTypeID || (aFlag & NS_IPARSER_FLAG_VIEW_SOURCE)) {
mTextValue=theSubstr;
mTextValue = tagIdent.str();
}
}
else {
result=aScanner.ReadTagIdentifier(mTextValue);
result = aScanner.ReadTagIdentifier(tagIdent);
mTextValue = tagIdent.str();
mTypeID = nsHTMLTags::LookupTag(mTextValue);
}
@@ -283,21 +285,22 @@ CEndToken::CEndToken(const nsAString& aName,eHTMLTags aTag) : CHTMLToken(aTag) {
nsresult CEndToken::Consume(PRUnichar aChar, nsScanner& aScanner,PRInt32 aFlag)
{
nsresult result = NS_OK;
nsScannerSharedSubstring tagIdent;
if (aFlag & NS_IPARSER_FLAG_HTML) {
nsAutoString theSubstr;
result=aScanner.ReadTagIdentifier(theSubstr);
result = aScanner.ReadTagIdentifier(tagIdent);
mTypeID = (PRInt32)nsHTMLTags::LookupTag(theSubstr);
mTypeID = (PRInt32)nsHTMLTags::LookupTag(tagIdent.str());
// Save the original tag string if this is user-defined or if we
// are viewing source
if(eHTMLTag_userdefined==mTypeID ||
(aFlag & (NS_IPARSER_FLAG_VIEW_SOURCE | NS_IPARSER_FLAG_PRESERVE_CONTENT))) {
mTextValue=theSubstr;
mTextValue = tagIdent.str();
}
}
else {
result = aScanner.ReadTagIdentifier(mTextValue);
result = aScanner.ReadTagIdentifier(tagIdent);
mTextValue = tagIdent.str();
mTypeID = nsHTMLTags::LookupTag(mTextValue);
}
@@ -1330,7 +1333,7 @@ CAttributeToken::CAttributeToken() : CHTMLToken(eHTMLTag_unknown) {
* @return
*/
CAttributeToken::CAttributeToken(const nsAString& aName) : CHTMLToken(eHTMLTag_unknown) {
mTextValue.Assign(aName);
mTextValue.writable().Assign(aName);
mHasEqualWithoutValue=PR_FALSE;
#ifdef DEBUG
mLastAttribute = PR_FALSE;
@@ -1346,7 +1349,7 @@ CAttributeToken::CAttributeToken(const nsAString& aName) : CHTMLToken(eHTMLTag_u
* @return
*/
CAttributeToken::CAttributeToken(const nsAString& aKey, const nsAString& aName) : CHTMLToken(eHTMLTag_unknown) {
mTextValue.Assign(aName);
mTextValue.writable().Assign(aName);
mTextKey.Rebind(aKey);
mHasEqualWithoutValue=PR_FALSE;
#ifdef DEBUG
@@ -1402,7 +1405,7 @@ void CAttributeToken::SanitizeKey() {
const nsSubstring& CAttributeToken::GetStringValue(void)
{
return mTextValue;
return mTextValue.str();
}
/*
@@ -1426,13 +1429,13 @@ void CAttributeToken::GetSource(nsString& anOutputString){
*/
void CAttributeToken::AppendSourceTo(nsAString& anOutputString){
AppendUnicodeTo(mTextKey, anOutputString);
if(mTextValue.Length() || mHasEqualWithoutValue)
if(mTextValue.str().Length() || mHasEqualWithoutValue)
anOutputString.AppendLiteral("=");
anOutputString.Append(mTextValue);
anOutputString.Append(mTextValue.str());
// anOutputString.AppendLiteral(";");
}
static void AppendNCR(nsString& aString, PRInt32 aNCRValue);
static void AppendNCR(nsSubstring& aString, PRInt32 aNCRValue);
/*
* @param aScanner -- controller of underlying input source
* @param aFlag -- If NS_IPARSER_FLAG_VIEW_SOURCE do not reduce entities...
@@ -1440,7 +1443,7 @@ static void AppendNCR(nsString& aString, PRInt32 aNCRValue);
*
*/
static
nsresult ConsumeAttributeEntity(nsString& aString,
nsresult ConsumeAttributeEntity(nsScannerSharedSubstring& aString,
nsScanner& aScanner,
PRInt32 aFlag)
{
@@ -1464,37 +1467,40 @@ nsresult ConsumeAttributeEntity(nsString& aString,
// Nav 4.x does not treat it as an entity,
// IE treats it as an entity if terminated with a semicolon.
// Resembling IE!!
nsSubstring &writable = aString.writable();
if(theNCRValue < 0 || (theNCRValue > 255 && theTermChar != ';')) {
// Looks like we're not dealing with an entity
aString.Append(kAmpersand);
aString.Append(entity);
writable.Append(kAmpersand);
writable.Append(entity);
}
else {
// A valid entity so reduce it.
aString.Append(PRUnichar(theNCRValue));
writable.Append(PRUnichar(theNCRValue));
}
}
}
else if (ch==kHashsign && !(aFlag & NS_IPARSER_FLAG_VIEW_SOURCE)) {
result=CEntityToken::ConsumeEntity(ch,entity,aScanner);
if (NS_SUCCEEDED(result)) {
nsSubstring &writable = aString.writable();
if (result == NS_HTMLTOKENS_NOT_AN_ENTITY) {
// Looked like an entity but it's not
aScanner.GetChar(amp);
aString.Append(amp);
writable.Append(amp);
result = NS_OK; // just being safe..
}
else {
PRInt32 err;
theNCRValue=entity.ToInteger(&err,kAutoDetect);
AppendNCR(aString, theNCRValue);
AppendNCR(writable, theNCRValue);
}
}
}
else {
// What we thought as entity is not really an entity...
aScanner.GetChar(amp);
aString.Append(amp);
aString.writable().Append(amp);
}//if
}
@@ -1516,7 +1522,7 @@ nsresult ConsumeAttributeEntity(nsString& aString,
* @return error result
*/
static
nsresult ConsumeAttributeValueText(nsString& aString,
nsresult ConsumeAttributeValueText(nsScannerSharedSubstring& aString,
PRInt32& aNewlineCount,
nsScanner& aScanner,
const nsReadEndCondition& aEndCondition,
@@ -1538,19 +1544,20 @@ nsresult ConsumeAttributeValueText(nsString& aString,
aScanner.GetChar(ch);
result = aScanner.Peek(ch);
if (NS_SUCCEEDED(result)) {
nsSubstring &writable = aString.writable();
if(ch == kNewLine) {
aString.AppendLiteral("\r\n");
writable.AppendLiteral("\r\n");
aScanner.GetChar(ch);
}
else {
aString.Append(PRUnichar('\r'));
writable.Append(PRUnichar('\r'));
}
++aNewlineCount;
}
}
else if(ch == kNewLine && aAllowNewlines) {
aScanner.GetChar(ch);
aString.Append(PRUnichar('\n'));
aString.writable().Append(PRUnichar('\n'));
++aNewlineCount;
}
else {
@@ -1573,14 +1580,14 @@ nsresult ConsumeAttributeValueText(nsString& aString,
*/
static
nsresult ConsumeQuotedString(PRUnichar aChar,
nsString& aString,
nsScannerSharedSubstring& aString,
PRInt32& aNewlineCount,
nsScanner& aScanner,
PRInt32 aFlag)
{
NS_ASSERTION(aChar==kQuote || aChar==kApostrophe,"char is neither quote nor apostrophe");
// hold onto this in case this is an unterminated string literal
PRUint32 origLen = aString.Length();
PRUint32 origLen = aString.str().Length();
static const PRUnichar theTerminalCharsQuote[] = {
PRUnichar(kQuote), PRUnichar('&'), PRUnichar(kCR),
@@ -1612,11 +1619,11 @@ nsresult ConsumeQuotedString(PRUnichar aChar,
// Ref: Bug 35806
// A back up measure when disaster strikes...
// Ex <table> <tr d="><td>hello</td></tr></table>
if(!aString.IsEmpty() && aString.Last()!=aChar &&
if(!aString.str().IsEmpty() && aString.str().Last()!=aChar &&
!aScanner.IsIncremental() && result==kEOF) {
static const nsReadEndCondition
theAttributeTerminator(kAttributeTerminalChars);
aString.Truncate(origLen);
aString.writable().Truncate(origLen);
aScanner.SetPosition(theOffset, PR_FALSE, PR_TRUE);
result=ConsumeAttributeValueText(aString,aNewlineCount,aScanner,
theAttributeTerminator,PR_FALSE,aFlag);
@@ -1722,7 +1729,9 @@ nsresult CAttributeToken::Consume(PRUnichar aChar, nsScanner& aScanner,PRInt32 a
result=aScanner.GetChar(aChar); //skip the equal sign...
if (NS_OK==result) {
if (aFlag & NS_IPARSER_FLAG_VIEW_SOURCE) {
result = aScanner.ReadWhitespace(mTextValue, mNewlineCount);
PRBool haveCR;
result = aScanner.ReadWhitespace(mTextValue, mNewlineCount,
haveCR);
}
else {
result = aScanner.SkipWhitespace(mNewlineCount);
@@ -1734,13 +1743,13 @@ nsresult CAttributeToken::Consume(PRUnichar aChar, nsScanner& aScanner,PRInt32 a
if ((kQuote==aChar) || (kApostrophe==aChar)) {
aScanner.GetChar(aChar);
if (aFlag & NS_IPARSER_FLAG_VIEW_SOURCE) {
mTextValue.Append(aChar);
mTextValue.writable().Append(aChar);
}
result=ConsumeQuotedString(aChar,mTextValue,mNewlineCount,
aScanner,aFlag);
if (NS_SUCCEEDED(result) && (aFlag & NS_IPARSER_FLAG_VIEW_SOURCE)) {
mTextValue.Append(aChar);
mTextValue.writable().Append(aChar);
} else if (result == NS_ERROR_HTMLPARSER_UNTERMINATEDSTRINGLITERAL) {
result = NS_OK;
mInError = PR_TRUE;
@@ -1771,7 +1780,9 @@ nsresult CAttributeToken::Consume(PRUnichar aChar, nsScanner& aScanner,PRInt32 a
}//if
if (NS_OK==result) {
if (aFlag & NS_IPARSER_FLAG_VIEW_SOURCE) {
result = aScanner.ReadWhitespace(mTextValue, mNewlineCount);
PRBool haveCR;
result = aScanner.ReadWhitespace(mTextValue, mNewlineCount,
haveCR);
}
else {
result = aScanner.SkipWhitespace(mNewlineCount);
@@ -1818,7 +1829,7 @@ nsresult CAttributeToken::Consume(PRUnichar aChar, nsScanner& aScanner,PRInt32 a
}//if (consume optional value)
if (NS_OK==result) {
if (mTextValue.Length() == 0 && mTextKey.Length() == 0 &&
if (mTextValue.str().Length() == 0 && mTextKey.Length() == 0 &&
mNewlineCount == 0) {
//This attribute contains no useful information for us, so there is no
//use in keeping it around. Attributes that are otherwise empty, but
@@ -1880,7 +1891,7 @@ CWhitespaceToken::CWhitespaceToken() : CHTMLToken(eHTMLTag_whitespace) {
* @return
*/
CWhitespaceToken::CWhitespaceToken(const nsAString& aName) : CHTMLToken(eHTMLTag_whitespace) {
mTextValue.Assign(aName);
mTextValue.writable().Assign(aName);
}
/*
@@ -1904,17 +1915,26 @@ PRInt32 CWhitespaceToken::GetTokenType(void) {
* @return error result
*/
nsresult CWhitespaceToken::Consume(PRUnichar aChar, nsScanner& aScanner,PRInt32 aFlag) {
mTextValue.Assign(aChar);
nsresult result=aScanner.ReadWhitespace(mTextValue, mNewlineCount);
if(NS_OK==result) {
mTextValue.StripChar(kCR);
// If possible, we'd like to just be a dependent substring starting at
// |aChar|. The scanner has already been advanced, so we need to
// back it up to facilitate this.
nsScannerIterator start;
aScanner.CurrentPosition(start);
aScanner.SetPosition(--start);
PRBool haveCR;
nsresult result = aScanner.ReadWhitespace(mTextValue, mNewlineCount, haveCR);
if (NS_OK == result && haveCR) {
mTextValue.writable().StripChar(kCR);
}
return result;
}
const nsSubstring& CWhitespaceToken::GetStringValue(void)
{
return mTextValue;
return mTextValue.str();
}
/*
@@ -2120,7 +2140,7 @@ static const PRUint16 PA_HackTable[] = {
};
#endif /* PA_REMAP_128_TO_160_ILLEGAL_NCR */
static void AppendNCR(nsString& aString, PRInt32 aNCRValue)
static void AppendNCR(nsSubstring& aString, PRInt32 aNCRValue)
{
#ifdef PA_REMAP_128_TO_160_ILLEGAL_NCR
/* for some illegal, but popular usage */