diff --git a/mozilla/content/base/src/nsHTMLContentSerializer.cpp b/mozilla/content/base/src/nsHTMLContentSerializer.cpp index 64e5988f718..148c9f6533a 100644 --- a/mozilla/content/base/src/nsHTMLContentSerializer.cpp +++ b/mozilla/content/base/src/nsHTMLContentSerializer.cpp @@ -83,6 +83,7 @@ nsHTMLContentSerializer::nsHTMLContentSerializer() { mColPos = 0; mIndent = 0; + mAddSpace = PR_FALSE; mInBody = PR_FALSE; mInCDATA = PR_FALSE; } @@ -456,6 +457,11 @@ nsHTMLContentSerializer::AppendElementStart(nsIDOMElement *aElement, if (LineBreakBeforeOpen(name, hasDirtyAttr)) { AppendToString(mLineBreak, aStr); mColPos = 0; + mAddSpace = PR_FALSE; + } + else if (mAddSpace) { + AppendToString(PRUnichar(' '), aStr); + mAddSpace = PR_FALSE; } StartIndentation(name, hasDirtyAttr, aStr); @@ -584,6 +590,11 @@ nsHTMLContentSerializer::AppendElementEnd(nsIDOMElement *aElement, if (LineBreakBeforeClose(name, hasDirtyAttr)) { AppendToString(mLineBreak, aStr); mColPos = 0; + mAddSpace = PR_FALSE; + } + else if (mAddSpace) { + AppendToString(PRUnichar(' '), aStr); + mAddSpace = PR_FALSE; } EndIndentation(name, hasDirtyAttr, aStr); @@ -632,101 +643,146 @@ nsHTMLContentSerializer::AppendToString(const PRUnichar aChar, } void -nsHTMLContentSerializer::AppendToStringWrapped(const nsAString& aStr, +nsHTMLContentSerializer::AppendToStringWrapped(const nsASingleFragmentString& aStr, nsAString& aOutputStr, PRBool aTranslateEntities) { - PRInt32 length = aStr.Length(); + // indicates a space has been seen, position is stored in lastSpace + PRBool spaceSeen = PR_FALSE; - nsAutoString line; - PRBool done = PR_FALSE; - PRInt32 indx = 0; - PRInt32 strOffset = 0; - PRInt32 lineLength, oldLineEnd; - PRBool addSpace = PR_FALSE; - - // Find the end of the first old line - oldLineEnd = aStr.FindChar(PRUnichar('\n'), 0); - - while ((!done) && (strOffset < length)) { - if (addSpace) { - AppendToString(NS_LITERAL_STRING(" "), aOutputStr); - addSpace = PR_FALSE; - } - - // This is how much is needed to fill up the new line - PRInt32 leftInLine = mMaxColumn - mColPos; - - // This is the last position in the current old line - PRInt32 oldLineLimit; - if (oldLineEnd == kNotFound) { - oldLineLimit = length; - } - else { - oldLineLimit = oldLineEnd; - } - - PRBool addLineBreak = PR_FALSE; + // indicates non-whitespace has been seen, position is stored in lastChar + PRBool charSeen = PR_FALSE; - // if we can fill up the new line with less than what's - // in the current old line... - if (((strOffset + leftInLine) < oldLineLimit) || (leftInLine < 0)) { + PRBool addLineBreak = PR_FALSE; + + nsASingleFragmentString::const_char_iterator pos, end, segStart, lastSpace, lastChar; + + aStr.BeginReading(pos); + aStr.EndReading(end); + if (pos == end) { + return; + } + + // if the current line already has text on it, such as a tag, + // leading whitespace is significant, so add a space back + // after skipping over the whitespace + if ((mColPos > 0) && (*pos == ' ' || *pos == '\n')) { + mAddSpace = PR_TRUE; + } + + for (;;) { + + // skip leading spaces + while (*pos == ' ' || *pos == '\n') { + ++pos; + if (pos == end) { + return; + } + } + segStart = pos; + lastChar = pos; + spaceSeen = PR_FALSE; + charSeen = PR_TRUE; + + if (addLineBreak) { + aOutputStr.Append(mLineBreak); + mAddSpace = PR_FALSE; + mColPos = 0; + } + + while (mColPos < mMaxColumn) { + PRUnichar c = *pos; + + if (c == ' ') { + lastSpace = pos; + spaceSeen = PR_TRUE; + } + else if (c == '\n') { + if (charSeen) { + if (mAddSpace) { + aOutputStr.Append(PRUnichar(' ')); + } + + aOutputStr.Append(segStart, lastChar - segStart + 1); + charSeen = PR_FALSE; + } + mAddSpace = PR_TRUE; + segStart = pos; + spaceSeen = PR_FALSE; + ++segStart; + } + else { + lastChar = pos; + charSeen = PR_TRUE; + } + + ++pos; + ++mColPos; + + if (pos == end) { + if (!charSeen || pos == segStart) { + // nothing to append, or nothing meaningful to append + return; + } + if (mAddSpace) { + aOutputStr.Append(PRUnichar(' ')); + mAddSpace = PR_FALSE; + } + + aOutputStr.Append(segStart, lastChar - segStart + 1); + + // if the string ended in whitespace, set mAddSpace to true + if (pos != lastChar+1) { + mAddSpace = PR_TRUE; + } + return; + } + } + + if (spaceSeen) { + if (mAddSpace) { + aOutputStr.Append(PRUnichar(' ')); + mAddSpace = PR_FALSE; + } + + // write up to the last space encountered + aOutputStr.Append(segStart, lastSpace - segStart); + + // back up to that wrapping point for the next run through the loop + pos = lastSpace; + // add a line break before any more text addLineBreak = PR_TRUE; - - // Look for the next word end to break - if (leftInLine < 0) { - //if we have already crossed the limit of 72 columns, immediately start searching for next white space. - indx = aStr.FindChar(PRUnichar(' '), strOffset); - } - else { - //if the limit of 72 chars is not yet reached, start looking for next appropriate break only after 72 column. - indx = aStr.FindChar(PRUnichar(' '), strOffset + leftInLine); - } - // If it's after the end of the current line, then break at - // the current line - if ((indx == kNotFound) || - ((oldLineEnd != kNotFound) && (oldLineEnd < indx))) { - indx = oldLineEnd; - } } else { - indx = oldLineEnd; - } - - // if there was no place to break, then just add the entire string - if (indx == kNotFound) { - if (strOffset == 0) { - AppendToString(aStr, aOutputStr, aTranslateEntities); + + // if we're past the wrapping width with no place to wrap at, + // find the next whitespace and wrap there + while (pos != end && *pos != ' ' && *pos != '\n') { + ++pos; } - else { - lineLength = length - strOffset; - line = Substring(aStr, strOffset, lineLength); - AppendToString(line, aOutputStr, aTranslateEntities); - } - done = PR_TRUE; - } - else { - // Add the part of the current old line that's part of the - // new line - lineLength = indx - strOffset; - line = Substring(aStr, strOffset, lineLength); - AppendToString(line, aOutputStr, aTranslateEntities); - - // if we've reached the end of an old line, don't add the - // old line break and find the end of the next old line. - if (indx == oldLineEnd) { - oldLineEnd = aStr.FindChar(PRUnichar('\n'), indx+1); - if (lineLength > 0) { - addSpace = PR_TRUE; + + if (mAddSpace) { + // whitespace was needed before the next segment, so we can put + // a newline instead of a space, and avoid getting a lone line + aOutputStr.Append(mLineBreak); + addLineBreak = PR_FALSE; + + mColPos = pos - segStart; + + // if the string doesn't end in whitespace, set mAddSpace to false + if (pos == end) { + mAddSpace = PR_FALSE; } } - - if (addLineBreak) { - AppendToString(mLineBreak, aOutputStr); - mColPos = 0; - addSpace = PR_FALSE; + else { + // no choice but to write a long line and wrap immediately after it + addLineBreak = PR_TRUE; + } + aOutputStr.Append(segStart, pos - segStart); + + if (pos == end) { + return; } - strOffset = indx+1; } } } diff --git a/mozilla/content/base/src/nsHTMLContentSerializer.h b/mozilla/content/base/src/nsHTMLContentSerializer.h index 125dd760f79..ebbe66b3280 100644 --- a/mozilla/content/base/src/nsHTMLContentSerializer.h +++ b/mozilla/content/base/src/nsHTMLContentSerializer.h @@ -98,7 +98,7 @@ class nsHTMLContentSerializer : public nsXMLContentSerializer { PRBool aIncrColumn = PR_TRUE); virtual void AppendToStringConvertLF(const nsAString& aStr, nsAString& aOutputStr); - virtual void AppendToStringWrapped(const nsAString& aStr, + virtual void AppendToStringWrapped(const nsASingleFragmentString& aStr, nsAString& aOutputStr, PRBool aTranslateEntities); PRBool HasLongLines(const nsString& text, PRInt32& aLastNewlineOffset); @@ -118,6 +118,11 @@ class nsHTMLContentSerializer : public nsXMLContentSerializer { PRPackedBool mBodyOnly; PRPackedBool mIsCopying; // Set to PR_TRUE only while copying + // Indicates that a space will be added if and only if content is + // continued on the same line while serializing source. Otherwise, + // the newline character acts as the whitespace and no space is needed. + PRPackedBool mAddSpace; + // To keep track of First LI child of OL in selected range PRPackedBool mIsFirstChildOfOL; PRInt32 mPreLevel;