From 6f4b49e0307d91ad0d8d71e77825a6e69acb9996 Mon Sep 17 00:00:00 2001 From: "akkana%netscape.com" Date: Wed, 10 Nov 1999 23:50:45 +0000 Subject: [PATCH] 17564, 17871, 17883, 18249, 13753, 18012, 16800, maybe 17565 and 13278: Integrate contributions from Ben Bucksch (mozilla@bucksch.org) and Daniel Brattell (bratell@lysator.liu.se) to improve formatted plaintext output, including adding text style indicators, improving table output and wrapping, and fixing several wrapping/whitespace bugs. Also update the auto tests to reflect some of the bugs recently fixed. r=myself,mozilla@bucksch.org,bratell@lysator.liu.se git-svn-id: svn://10.0.0.236/trunk@53104 18797224-902f-48f8-a5cc-f745e15eee43 --- .../htmlparser/src/nsHTMLToTXTSinkStream.cpp | 336 +++++++++++------- .../htmlparser/src/nsHTMLToTXTSinkStream.h | 2 + mozilla/htmlparser/tests/outsinks/Makefile.in | 1 + .../htmlparser/tests/outsinks/TestOutSinks | 11 +- .../htmlparser/tests/outsinks/htmltable.out | 2 - .../htmlparser/tests/outsinks/mailquote.html | 2 +- .../htmlparser/tests/outsinks/mailquote.out | 15 +- .../htmlparser/tests/outsinks/makefile.win | 1 + .../htmlparser/tests/outsinks/plainnowrap.out | 5 + mozilla/htmlparser/tests/outsinks/simple.html | 17 + .../htmlparser/tests/outsinks/simplecopy.out | 12 +- .../htmlparser/tests/outsinks/simplefmt.out | 23 ++ .../htmlparser/src/nsHTMLToTXTSinkStream.cpp | 336 +++++++++++------- .../htmlparser/src/nsHTMLToTXTSinkStream.h | 2 + .../htmlparser/tests/outsinks/Makefile.in | 1 + .../htmlparser/tests/outsinks/TestOutSinks | 11 +- .../htmlparser/tests/outsinks/htmltable.out | 2 - .../htmlparser/tests/outsinks/mailquote.html | 2 +- .../htmlparser/tests/outsinks/mailquote.out | 15 +- .../htmlparser/tests/outsinks/makefile.win | 1 + .../htmlparser/tests/outsinks/plainnowrap.out | 5 + .../htmlparser/tests/outsinks/simple.html | 17 + .../htmlparser/tests/outsinks/simplecopy.out | 12 +- .../htmlparser/tests/outsinks/simplefmt.out | 23 ++ 24 files changed, 584 insertions(+), 270 deletions(-) create mode 100644 mozilla/htmlparser/tests/outsinks/simplefmt.out create mode 100644 mozilla/parser/htmlparser/tests/outsinks/simplefmt.out diff --git a/mozilla/htmlparser/src/nsHTMLToTXTSinkStream.cpp b/mozilla/htmlparser/src/nsHTMLToTXTSinkStream.cpp index 0e01dbca0db..52a192519d1 100644 --- a/mozilla/htmlparser/src/nsHTMLToTXTSinkStream.cpp +++ b/mozilla/htmlparser/src/nsHTMLToTXTSinkStream.cpp @@ -29,7 +29,6 @@ * model. */ - #include "nsHTMLToTXTSinkStream.h" #include "nsHTMLTokens.h" #include "nsString.h" @@ -45,15 +44,16 @@ #include "nsIOutputStream.h" #include "nsFileStream.h" - static NS_DEFINE_CID(kCharsetConverterManagerCID, NS_ICHARSETCONVERTERMANAGER_CID); -const PRInt32 gTabSize=2; +const PRInt32 gTabSize=4; +const PRInt32 gOLNumberWidth = 3; +const PRInt32 gIndentSizeList = MaxInt(gTabSize, gOLNumberWidth + 3); + // Indention of non-first lines of ul and ol static PRBool IsInline(eHTMLTags aTag); static PRBool IsBlockLevel(eHTMLTags aTag); - /** * Inits the encoder instance variable for the sink based on the charset * @@ -72,7 +72,6 @@ nsresult nsHTMLToTXTSinkStream::InitEncoder(const nsString& aCharset) return res; } - nsICharsetAlias* calias = nsnull; res = nsServiceManager::GetService(kCharsetAliasCID, kICharsetAliasIID, @@ -110,7 +109,6 @@ nsresult nsHTMLToTXTSinkStream::InitEncoder(const nsString& aCharset) return res; } - /** * This method gets called as part of our COM-like interfaces. * Its purpose is to create an interface to parser object @@ -147,18 +145,16 @@ nsHTMLToTXTSinkStream::QueryInterface(const nsIID& aIID, void** aInstancePtr) return NS_OK; } - NS_IMPL_ADDREF(nsHTMLToTXTSinkStream) NS_IMPL_RELEASE(nsHTMLToTXTSinkStream) - // Someday may want to make this non-const: static const PRUint32 TagStackSize = 500; static const PRUint32 OLStackSize = 100; /** * Construct a content sink stream. - * @update gpk02/03/99 + * @update gpk02/03/99 * @param * @return */ @@ -191,10 +187,9 @@ nsHTMLToTXTSinkStream::nsHTMLToTXTSinkStream() mOLStackIndex = 0; } - /** * - * @update gpk02/03/99 + * @update gpk02/03/99 * @param * @return */ @@ -211,7 +206,7 @@ nsHTMLToTXTSinkStream::~nsHTMLToTXTSinkStream() /** * - * @update gpk04/30/99 + * @update gpk04/30/99 * @param * @return */ @@ -229,11 +224,10 @@ nsHTMLToTXTSinkStream::Initialize(nsIOutputStream* aOutStream, /** * - * @update gpk04/30/99 + * @update gpk04/30/99 * @param * @return */ - NS_IMETHODIMP nsHTMLToTXTSinkStream::SetCharsetOverride(const nsString* aCharset) { @@ -245,8 +239,6 @@ nsHTMLToTXTSinkStream::SetCharsetOverride(const nsString* aCharset) return NS_OK; } - - /** * This method gets called by the parser when it encounters * a title tag and wants to set the document title in the sink. @@ -254,9 +246,10 @@ nsHTMLToTXTSinkStream::SetCharsetOverride(const nsString* aCharset) * @update gpk02/03/99 * @param nsString reference to new title value * @return PR_TRUE if successful. - */ + */ NS_IMETHODIMP -nsHTMLToTXTSinkStream::SetTitle(const nsString& aValue){ +nsHTMLToTXTSinkStream::SetTitle(const nsString& aValue) +{ return NS_OK; } @@ -279,7 +272,6 @@ NS_IMETHODIMP \ nsHTMLToTXTSinkStream::closetag(const nsIParserNode& aNode) \ { return CloseContainer(aNode); } - USE_GENERAL_OPEN_METHOD(OpenHTML) USE_GENERAL_CLOSE_METHOD(CloseHTML) USE_GENERAL_OPEN_METHOD(OpenHead) @@ -344,7 +336,6 @@ nsHTMLToTXTSinkStream::AddProcessingInstruction(const nsIParserNode& aNode){ * This gets called by the parser when it encounters * a DOCTYPE declaration in the HTML document. */ - NS_IMETHODIMP nsHTMLToTXTSinkStream::AddDocTypeDecl(const nsIParserNode& aNode, PRInt32 aMode) { @@ -405,6 +396,15 @@ PRBool nsHTMLToTXTSinkStream::DoOutput() return mDoFragment || inBody; } +nsAutoString +Spaces(PRInt32 count) +{ + nsAutoString result; + while (result.Length() < count) + result += ' '; + return result; +} + /** * This method is used to a general container. * This includes: OL,UL,DIR,SPAN,TABLE,H[1..6],etc. @@ -416,7 +416,6 @@ PRBool nsHTMLToTXTSinkStream::DoOutput() NS_IMETHODIMP nsHTMLToTXTSinkStream::OpenContainer(const nsIParserNode& aNode) { - eHTMLTags type = (eHTMLTags)aNode.GetNodeType(); #ifdef DEBUG_bratell printf("OpenContainer: %d ", type); @@ -440,18 +439,16 @@ nsHTMLToTXTSinkStream::OpenContainer(const nsIParserNode& aNode) if (type == eHTMLTag_body) { - // body -> can turn on cacheing unless it's already preformatted if(!(mFlags & nsIDocumentEncoder::OutputPreformatted) && ((mFlags & nsIDocumentEncoder::OutputFormatted) || (mFlags & nsIDocumentEncoder::OutputWrap))) { mCacheLine = PR_TRUE; } - // Would be cool to figure out here whether we have a // preformatted style attribute. It's hard, though. - + // // Trigger on the presence of a "-moz-pre-wrap" in the // style attribute. That's a very simplistic way to do // it, but better than nothing. @@ -471,29 +468,53 @@ nsHTMLToTXTSinkStream::OpenContainer(const nsIParserNode& aNode) if (!DoOutput()) return NS_OK; - if (type == eHTMLTag_ol) + if (type == eHTMLTag_p) + EnsureVerticalSpace(1); // Should this be 0 in unformatted case? + // Else make sure we'll separate block level tags, + // even if we're about to leave before doing any other formatting. + // Oddly, I can't find a case where this actually makes any difference. + //else if (IsBlockLevel(type)) + // EnsureVerticalSpace(0); + + // The rest of this routine is formatted output stuff, + // which we should skip if we're not formatted: + if (!(mFlags & nsIDocumentEncoder::OutputFormatted)) + return NS_OK; + + if (type == eHTMLTag_ul) + { + // Indent here to support nested list, which aren't included in li :-( + mIndent += gIndentSizeList; + EnsureVerticalSpace(1); + } + else if (type == eHTMLTag_ol) { if (mOLStackIndex < OLStackSize) mOLStack[mOLStackIndex++] = 1; // XXX should get it from the node! + mIndent += gIndentSizeList; // see ul + EnsureVerticalSpace(1); } - - if (type == eHTMLTag_li) + else if (type == eHTMLTag_li) { - nsAutoString temp("*"); + nsAutoString temp = Spaces(gIndentSizeList - gOLNumberWidth - 2); if (mTagStackIndex > 1 && mTagStack[mTagStackIndex-2] == eHTMLTag_ol) { + nsAutoString number; if (mOLStackIndex > 0) - { // This is what nsBulletFrame does for OLs: - char cbuf[40]; - PR_snprintf(cbuf, sizeof(cbuf), "%ld.", (mOLStack[mOLStackIndex-1])++); - temp = cbuf; - } + number.Append(mOLStack[mOLStackIndex-1]++, 10); else - temp = "#"; + number += "#"; + temp += Spaces(gOLNumberWidth - number.Length()) + number + '.'; } - Write(temp); - // mColPos++; This is done in Write(temp) above + else + temp += Spaces(gOLNumberWidth) + "*"; + temp += ' '; + + + mIndent -= gIndentSizeList; // don't indent first line so much + Write(temp); //CHANGE: does not work as intended. waiting for bug #17883 + mIndent += gIndentSizeList; } else if (type == eHTMLTag_blockquote) { @@ -515,26 +536,50 @@ nsHTMLToTXTSinkStream::OpenContainer(const nsIParserNode& aNode) { EnsureVerticalSpace(0); } - - // Finally, the list of tags before which we want some vertical space: - switch (type) + else if (type == eHTMLTag_a) { - case eHTMLTag_table: - case eHTMLTag_ul: - case eHTMLTag_ol: - case eHTMLTag_p: - { - EnsureVerticalSpace((mFlags & nsIDocumentEncoder::OutputFormatted) ? 1 : 0); - break; - } - default: - break; + nsAutoString url; + if (NS_SUCCEEDED(GetValueOfAttribute(aNode, "href", url))) + mURL = url; + else + mURL.Truncate(); } + else if (type == eHTMLTag_img) + { + nsAutoString url; + if (NS_SUCCEEDED(GetValueOfAttribute(aNode, "src", url))) + { + nsAutoString temp, desc; + if (NS_SUCCEEDED(GetValueOfAttribute(aNode, "alt", desc))) + { + temp += " ("; + temp += desc; + temp += " 0) --mTagStackIndex; - if (type == eHTMLTag_ol) + // End current line if we're ending a block level tag + if (IsBlockLevel(type)) { + if((type == eHTMLTag_body) || (type == eHTMLTag_html)) { + // We want the output to end with a new line, + // but in preformatted areas like text fields, + // we can't emit newlines that weren't there. + if (mPreFormatted || (mFlags & nsIDocumentEncoder::OutputPreformatted)) + FlushLine(); + else + EnsureVerticalSpace(0); + } else if ((type == eHTMLTag_tr) || + (type == eHTMLTag_li) || + (type == eHTMLTag_blockquote)) { + EnsureVerticalSpace(0); + } else { + // All other blocks get 1 vertical space after them + // in formatted mode, otherwise 0. + // This is hard. Sometimes 0 is a better number, but + // how to know? + EnsureVerticalSpace((mFlags & nsIDocumentEncoder::OutputFormatted) ? 1 : 0); + } + } + + // The rest of this routine is formatted output stuff, + // which we should skip if we're not formatted: + if (!(mFlags & nsIDocumentEncoder::OutputFormatted)) + return NS_OK; + + if (type == eHTMLTag_ul) + { + mIndent -= gIndentSizeList; + } + else if (type == eHTMLTag_ol) + { + FlushLine(); // Doing this after decreasing OLStackIndex would be wrong. --mOLStackIndex; + mIndent -= gIndentSizeList; + } else if (type == eHTMLTag_blockquote) { + FlushLine(); if (mCiteQuoteLevel>0) mCiteQuoteLevel--; else if(mIndent >= gTabSize) @@ -580,33 +662,29 @@ nsHTMLToTXTSinkStream::CloseContainer(const nsIParserNode& aNode) mInWhitespace = PR_TRUE; } } - - // End current line if we're ending a block level tag - if(IsBlockLevel(type)) { - if((type == eHTMLTag_body) || (type == eHTMLTag_html)) { - // We want the output to end with a new line, - // but in preformatted areas like text fields, - // we can't emit newlines that weren't there. - if (mPreFormatted || (mFlags & nsIDocumentEncoder::OutputPreformatted)) - FlushLine(); - else - EnsureVerticalSpace(0); - - } else if((type == eHTMLTag_tr) || - (type == eHTMLTag_blockquote)) { - EnsureVerticalSpace(0); - } else { - // All other blocks get 1 vertical space after them - // in formatted mode, otherwise 0. - // This is hard. Sometimes 0 is a better number, but - // how to know? - EnsureVerticalSpace((mFlags & nsIDocumentEncoder::OutputFormatted) ? 1 : 0); + else if (type == eHTMLTag_a) + { // these brackets must stay here + if (!mURL.IsEmpty()) + { + nsAutoString temp(" 0 ? mWrapColumn : 25); + while (line.Length() < width) + line += '-'; + Write(line); + } return NS_OK; } void nsHTMLToTXTSinkStream::EnsureBufferSize(PRInt32 aNewSize) { - if (mBufferSize < aNewSize) + if (mBufferSize < aNewSize) { nsAllocator::Free(mBuffer); mBufferSize = 2*aNewSize+1; // make the twice as large @@ -706,8 +787,6 @@ void nsHTMLToTXTSinkStream::EnsureBufferSize(PRInt32 aNewSize) } } - - void nsHTMLToTXTSinkStream::EncodeToBuffer(const nsString& aSrc) { if (mUnicodeEncoder == nsnull) @@ -718,8 +797,6 @@ void nsHTMLToTXTSinkStream::EncodeToBuffer(const nsString& aSrc) return; } -#define CH_NBSP 160 - PRInt32 length = aSrc.Length(); nsresult result; @@ -735,17 +812,16 @@ void nsHTMLToTXTSinkStream::EncodeToBuffer(const nsString& aSrc) if (NS_SUCCEEDED(result)) result = mUnicodeEncoder->Finish(mBuffer,&temp); - +// XXX UGH! This is awful and needs to be removed. +#define CH_NBSP 160 for (PRInt32 i = 0; i < mBufferLength; i++) { if (mBuffer[i] == char(CH_NBSP)) mBuffer[i] = ' '; } } - } - void nsHTMLToTXTSinkStream::EnsureVerticalSpace(PRInt32 noOfRows) { @@ -753,19 +829,23 @@ nsHTMLToTXTSinkStream::EnsureVerticalSpace(PRInt32 noOfRows) EndLine(PR_FALSE); } - // This empties the current line cache without adding a NEWLINE. // Should not be used if line wrapping is of importance since // this function destroys the cache information. void nsHTMLToTXTSinkStream::FlushLine() { - WriteSimple(mCurrentLine); - mCurrentLine.SetString(""); + if(mCurrentLine.Length()>0) { + if(0 == mColPos) + WriteQuotesAndIndent(); + + + WriteSimple(mCurrentLine); + mColPos += mCurrentLine.Length(); + mCurrentLine.SetString(""); + } } - - /** * WriteSimple places the contents of aString into either the output stream * or the output string. @@ -840,8 +920,8 @@ nsHTMLToTXTSinkStream::AddToLine(const nsString &linefragment) // Wrap? if(mWrapColumn && ((mFlags & nsIDocumentEncoder::OutputFormatted) || - (mFlags & nsIDocumentEncoder::OutputWrap))) { - + (mFlags & nsIDocumentEncoder::OutputWrap))) + { // Yes, wrap! // The "+4" is to avoid wrap lines that only should be a couple // of letters too long. @@ -869,7 +949,19 @@ nsHTMLToTXTSinkStream::AddToLine(const nsString &linefragment) mCurrentLine.Right(restOfLine, linelength-goodSpace-1); mCurrentLine.Cut(goodSpace, linelength-goodSpace); EndLine(PR_TRUE); - mCurrentLine.SetString(restOfLine); + mCurrentLine.SetString(""); + // Space stuff new line? + if(mFlags & nsIDocumentEncoder::OutputFormatFlowed) { + if((restOfLine[0] == '>') || + (restOfLine[0] == ' ') || + (!restOfLine.Compare("From ",PR_FALSE,5))) { + // Space stuffing a la RFC 2646 if this will be used in a mail, + // but how can I know that??? Now space stuffing is done always + // when formatting text as HTML and that is wrong! XXX: Fix this! + mCurrentLine.Append(' '); + } + } + mCurrentLine.Append(restOfLine); linelength = mCurrentLine.Length(); mEmptyLines = -1; } else { @@ -892,8 +984,9 @@ nsHTMLToTXTSinkStream::EndLine(PRBool softlinebreak) return; } WriteQuotesAndIndent(); - // Remove whitespace from the end of the line. - mCurrentLine.CompressWhitespace(PR_FALSE,PR_TRUE); + // Remove SPACE from the end of the line. + while(' ' == mCurrentLine[mCurrentLine.Length()-1]) + mCurrentLine.SetLength(mCurrentLine.Length()-1); if(mFlags & nsIDocumentEncoder::OutputFormatFlowed) { // Add the soft part of the soft linebreak (RFC 2646 4.1) mCurrentLine.Append(' '); @@ -912,7 +1005,9 @@ nsHTMLToTXTSinkStream::EndLine(PRBool softlinebreak) if(mCurrentLine.Length()>0) mEmptyLines=-1; // Output current line - mCurrentLine.CompressWhitespace(PR_FALSE,PR_TRUE); + // Remove SPACE from the end of the line. + while(' ' == mCurrentLine[mCurrentLine.Length()-1]) + mCurrentLine.SetLength(mCurrentLine.Length()-1); mCurrentLine.Append(NS_LINEBREAK); WriteSimple(mCurrentLine); mCurrentLine.SetString(""); @@ -952,7 +1047,6 @@ nsHTMLToTXTSinkStream::WriteQuotesAndIndent() } } - #ifdef DEBUG_akkana_not #define DEBUG_wrapping 1 #endif @@ -971,8 +1065,6 @@ nsHTMLToTXTSinkStream::Write(const nsString& aString) nsAllocator::Free(foo); #endif - - PRInt32 bol = 0; PRInt32 newline; @@ -981,10 +1073,8 @@ nsHTMLToTXTSinkStream::Write(const nsString& aString) // Don't wrap mail-quoted text // Yes do! /Daniel Bratell // PRUint32 wrapcol = (mCiteQuote ? 0 : mWrapColumn); - // PRInt32 prefixwidth = (mCiteQuoteLevel>0?mCiteQuoteLevel+1:0)+mIndent; - // PRInt32 linewidth = mWrapColumn-prefixwidth; - + // PRInt32 linewidth = mWrapColumn-prefixwidth; // if ((!(mFlags & nsIDocumentEncoder::OutputFormatted) // && !(mFlags & nsIDocumentEncoder::OutputWrap)) || // ((mTagStackIndex > 0) && @@ -997,7 +1087,8 @@ nsHTMLToTXTSinkStream::Write(const nsString& aString) // intelligent wrapping without clearing the mCurrentLine // buffer before!!! - NS_ASSERTION(mCurrentLine.Length() == 0, "Mixed wrapping data and nonwrapping data on the same line"); + NS_ASSERTION(mCurrentLine.Length() == 0, + "Mixed wrapping data and nonwrapping data on the same line"); // Put the mail quote "> " chars in, if appropriate. // Have to put it in before every line. @@ -1057,10 +1148,9 @@ nsHTMLToTXTSinkStream::Write(const nsString& aString) return; } - // Intelligent handling of text - // Strip out all "end of lines" and multiple whitespace between words - + // If needed, strip out all "end of lines" + // and multiple whitespace between words PRInt32 nextpos; nsAutoString tempstr; @@ -1086,7 +1176,8 @@ nsHTMLToTXTSinkStream::Write(const nsString& aString) bol=totLen; mInWhitespace=PR_FALSE; } else { - if(mInWhitespace && (nextpos == bol)) { + if(mInWhitespace && (nextpos == bol) && + !(mFlags & nsIDocumentEncoder::OutputPreformatted)) { // Skip whitespace bol++; continue; @@ -1095,24 +1186,30 @@ nsHTMLToTXTSinkStream::Write(const nsString& aString) if(nextpos == bol) { // Note that we are in whitespace. mInWhitespace = PR_TRUE; + nsAutoString whitestring=aString[nextpos]; if(!mCacheLine) { - WriteSimple(" "); + WriteSimple(whitestring); } else { - AddToLine(" "); + AddToLine(whitestring); } bol++; continue; } aString.Mid(tempstr,bol,nextpos-bol); - tempstr.Append(" "); + if(mFlags & nsIDocumentEncoder::OutputPreformatted) { + bol = nextpos; + } else { + tempstr.Append(" "); + bol = nextpos + 1; + mInWhitespace = PR_TRUE; + } + if(!mCacheLine) { WriteSimple(tempstr); } else { AddToLine(tempstr); } - mInWhitespace = PR_TRUE; - bol = nextpos + 1; } } // Continue looping over the string } @@ -1128,7 +1225,6 @@ nsHTMLToTXTSinkStream::WillBuildModel(void){ return NS_OK; } - /** * This method gets called when the parser concludes the process * of building the content model via the content sink. @@ -1142,7 +1238,6 @@ nsHTMLToTXTSinkStream::DidBuildModel(PRInt32 aQualityLevel) { return NS_OK; } - /** * This method gets called when the parser gets i/o blocked, * and wants to notify the sink that it may be a while before @@ -1155,7 +1250,6 @@ nsHTMLToTXTSinkStream::WillInterrupt(void) { return NS_OK; } - /** * This method gets called when the parser i/o gets unblocked, * and we're about to start dumping content again to the sink. @@ -1178,7 +1272,6 @@ nsHTMLToTXTSinkStream::NotifyError(const nsParserError* aError) return NS_OK; } - PRBool IsInline(eHTMLTags aTag) { PRBool result = PR_FALSE; @@ -1215,13 +1308,11 @@ PRBool IsInline(eHTMLTags aTag) case eHTMLTag_u: case eHTMLTag_var: case eHTMLTag_wbr: - result = PR_TRUE; break; default: break; - } return result; } @@ -1230,4 +1321,3 @@ PRBool IsBlockLevel(eHTMLTags aTag) { return !IsInline(aTag); } - diff --git a/mozilla/htmlparser/src/nsHTMLToTXTSinkStream.h b/mozilla/htmlparser/src/nsHTMLToTXTSinkStream.h index d626887cdbb..5b281dd7bd9 100644 --- a/mozilla/htmlparser/src/nsHTMLToTXTSinkStream.h +++ b/mozilla/htmlparser/src/nsHTMLToTXTSinkStream.h @@ -174,6 +174,8 @@ protected: PRBool mPreFormatted; PRBool mCacheLine; // If the line should be cached before output. This makes it possible to do smarter wrapping. + nsString mURL; + // The tag stack: the stack of tags we're operating on, so we can nest: nsHTMLTag *mTagStack; PRUint32 mTagStackIndex; diff --git a/mozilla/htmlparser/tests/outsinks/Makefile.in b/mozilla/htmlparser/tests/outsinks/Makefile.in index 160614a057c..2f0961f6ea6 100644 --- a/mozilla/htmlparser/tests/outsinks/Makefile.in +++ b/mozilla/htmlparser/tests/outsinks/Makefile.in @@ -45,6 +45,7 @@ TEST_FILES = \ plainnowrap.out \ simple.html \ simplecopy.out \ + simplefmt.out \ entityxif.xif \ entityxif.out \ mailquote.html \ diff --git a/mozilla/htmlparser/tests/outsinks/TestOutSinks b/mozilla/htmlparser/tests/outsinks/TestOutSinks index 3fc4d9969c2..6887f90ef08 100755 --- a/mozilla/htmlparser/tests/outsinks/TestOutSinks +++ b/mozilla/htmlparser/tests/outsinks/TestOutSinks @@ -41,6 +41,13 @@ if ($status != 0) then set errmsg = ($errmsg "simplecopy.out") endif +echo "Testing simple html to plaintext formatting ..." +TestOutput -i text/html -o text/plain -f 34 -w 70 -c OutTestData/simplefmt.out OutTestData/simple.html +if ($status != 0) then + echo "Simple copy test failed.\n" + set errmsg = ($errmsg "simplefmt.out") +endif + echo "Testing non-wrapped plaintext ..." TestOutput -i text/html -o text/plain -f 0 -w 0 -c OutTestData/plainnowrap.out OutTestData/plain.html if ($status != 0) then @@ -48,7 +55,7 @@ if ($status != 0) then set errmsg = ($errmsg "plainnowrap.out") endif -echo "Testing wrapped bug unformatted plaintext ..." +echo "Testing wrapped but unformatted plaintext ..." TestOutput -i text/html -o text/plain -f 32 -w 50 -c OutTestData/plainwrap.out OutTestData/plain.html if ($status != 0) then echo "Wrapped plaintext test failed." @@ -56,7 +63,7 @@ if ($status != 0) then endif echo "Testing mail quoting ..." -TestOutput -i text/html -o text/plain -c OutTestData/mailquote.out OutTestData/mailquote.html +TestOutput -i text/html -o text/plain -f 2 -w 50 -c OutTestData/mailquote.out OutTestData/mailquote.html if ($status != 0) then echo "Mail quoting test failed." set errmsg = ($errmsg "mailquote.out") diff --git a/mozilla/htmlparser/tests/outsinks/htmltable.out b/mozilla/htmlparser/tests/outsinks/htmltable.out index 7d19794925f..7d17268018c 100644 --- a/mozilla/htmlparser/tests/outsinks/htmltable.out +++ b/mozilla/htmlparser/tests/outsinks/htmltable.out @@ -1,7 +1,5 @@ Below is a table. - Row 1 Col 1 Row 1 Col 2 Row 1 Col 3 Row 2 Col 1 Row 2 Col 2 Row 2 Col 3 Row 3 Col 1 Row 3 Col 2 Row 3 Col 3 - Here is after table. diff --git a/mozilla/htmlparser/tests/outsinks/mailquote.html b/mozilla/htmlparser/tests/outsinks/mailquote.html index 5882c2054b8..8ffa5bfe3a0 100644 --- a/mozilla/htmlparser/tests/outsinks/mailquote.html +++ b/mozilla/htmlparser/tests/outsinks/mailquote.html @@ -37,7 +37,7 @@ I hope you will enjoy these quotes from Hamlet, introduced by a fairly To be, or not to be, that is the question
Whether 'tis nobler in the mind to suffer
The slings and fortunes of outrageous fortune
-Or to take arms against a sea of troubles
+Or to take arms against a sea of troubles, And by opposing end them.
diff --git a/mozilla/htmlparser/tests/outsinks/mailquote.out b/mozilla/htmlparser/tests/outsinks/mailquote.out index dd29ea59344..ec4bacc5598 100644 --- a/mozilla/htmlparser/tests/outsinks/mailquote.out +++ b/mozilla/htmlparser/tests/outsinks/mailquote.out @@ -1,19 +1,22 @@ This page is a test of mail quoting. -I hope you will enjoy these quotes from Hamlet, introduced by a fairly long line to see how quotations get wrapped: +I hope you will enjoy these quotes from /Hamlet/, +introduced by a fairly long line to see how +quotations get wrapped: ->> (These have br tags after them. +>> /(These have *br* tags after them./ >> To be, or not to be, that is the question >> Whether 'tis nobler in the mind to suffer >> The slings and fortunes of outrageous fortune ->> Or to take arms against a sea of troubles ->> And by opposing end them. +>> Or to take arms against a sea of troubles, And +>> by opposing end them. > > Oh, what a mind is here o'erthrown. > ->> (The next line does not end with a br tag.). +>> /(The next line does not end with a *br* tag.)./ >> Oh, what a rogue and peasant slave am I. -> (Neither does the next line:) +> /(Neither does the next line:)/ > The observed of all observers, quite, quite down! Now we're outside all blockquotes. + diff --git a/mozilla/htmlparser/tests/outsinks/makefile.win b/mozilla/htmlparser/tests/outsinks/makefile.win index 4274e2502e2..80885f31ce3 100644 --- a/mozilla/htmlparser/tests/outsinks/makefile.win +++ b/mozilla/htmlparser/tests/outsinks/makefile.win @@ -37,6 +37,7 @@ TEST_FILES = \ plainnowrap.out \ simple.html \ simplecopy.out \ + simplefmt.out \ entityxif.xif \ entityxif.out \ mailquote.html \ diff --git a/mozilla/htmlparser/tests/outsinks/plainnowrap.out b/mozilla/htmlparser/tests/outsinks/plainnowrap.out index d87bca54633..3db8241fd2c 100644 --- a/mozilla/htmlparser/tests/outsinks/plainnowrap.out +++ b/mozilla/htmlparser/tests/outsinks/plainnowrap.out @@ -1,8 +1,13 @@ + + 80 char width (for reference only): ---------|---------|---------|---------|---------|---------|---------|---------| Here is a link to mozilla.org. Here is some underlined and boldenedified text. This is a test to make sure the output converters pick up the moz-pre-wrap style. They don't necessarily have to pick up the exact wrap setting. + - This should be tested with wrapping on. - This should be tested with wrapping off. + This is the end. + diff --git a/mozilla/htmlparser/tests/outsinks/simple.html b/mozilla/htmlparser/tests/outsinks/simple.html index 9211c2eace8..5a787db1a51 100644 --- a/mozilla/htmlparser/tests/outsinks/simple.html +++ b/mozilla/htmlparser/tests/outsinks/simple.html @@ -37,5 +37,22 @@ followed by a line break. Plaintext output should contain only one space (and no line breaks) between "space" and "followed".

+

+Here is a list: +

+ +
    +
  • An item
  • +
  • A nested ordered list:
  • +
    1. +
    2. item one
    3. +
    4. item two
    5. +
    +
  • +
  • last item
  • +
+ +

Here is a paragraph after the list.

+ diff --git a/mozilla/htmlparser/tests/outsinks/simplecopy.out b/mozilla/htmlparser/tests/outsinks/simplecopy.out index 38227545f15..0b380583181 100644 --- a/mozilla/htmlparser/tests/outsinks/simplecopy.out +++ b/mozilla/htmlparser/tests/outsinks/simplecopy.out @@ -1,3 +1,13 @@ -Simple html page Here is a link to mozilla.org. Here is some underlined and boldenedified text. +Simple html page +Here is a link to the mozilla.org page. Here is some underlined and boldenedified text plus some . + Here is a line ending with a space followed by a line break. Plaintext output should contain only one space (and no line breaks) between "space" and "followed". +Here is a list: +An item +A nested ordered list: +item one +item two +last item + +Here is a paragraph after the list. diff --git a/mozilla/htmlparser/tests/outsinks/simplefmt.out b/mozilla/htmlparser/tests/outsinks/simplefmt.out new file mode 100644 index 00000000000..4de7ade36a5 --- /dev/null +++ b/mozilla/htmlparser/tests/outsinks/simplefmt.out @@ -0,0 +1,23 @@ +Simple html page + +Here is a link to the mozilla.org page. +Here is some _underlined and *bold*ened_ified text plus some . + +Here is a line ending with a space followed by a line break. Plaintext +output should contain only one space (and no line breaks) between +"space" and "followed". + +Here is a /list/: + + * An item + * A nested ordered list: + * + + 1. item one + 2. item two + + * last item + +Here is a paragraph after the list. + diff --git a/mozilla/parser/htmlparser/src/nsHTMLToTXTSinkStream.cpp b/mozilla/parser/htmlparser/src/nsHTMLToTXTSinkStream.cpp index 0e01dbca0db..52a192519d1 100644 --- a/mozilla/parser/htmlparser/src/nsHTMLToTXTSinkStream.cpp +++ b/mozilla/parser/htmlparser/src/nsHTMLToTXTSinkStream.cpp @@ -29,7 +29,6 @@ * model. */ - #include "nsHTMLToTXTSinkStream.h" #include "nsHTMLTokens.h" #include "nsString.h" @@ -45,15 +44,16 @@ #include "nsIOutputStream.h" #include "nsFileStream.h" - static NS_DEFINE_CID(kCharsetConverterManagerCID, NS_ICHARSETCONVERTERMANAGER_CID); -const PRInt32 gTabSize=2; +const PRInt32 gTabSize=4; +const PRInt32 gOLNumberWidth = 3; +const PRInt32 gIndentSizeList = MaxInt(gTabSize, gOLNumberWidth + 3); + // Indention of non-first lines of ul and ol static PRBool IsInline(eHTMLTags aTag); static PRBool IsBlockLevel(eHTMLTags aTag); - /** * Inits the encoder instance variable for the sink based on the charset * @@ -72,7 +72,6 @@ nsresult nsHTMLToTXTSinkStream::InitEncoder(const nsString& aCharset) return res; } - nsICharsetAlias* calias = nsnull; res = nsServiceManager::GetService(kCharsetAliasCID, kICharsetAliasIID, @@ -110,7 +109,6 @@ nsresult nsHTMLToTXTSinkStream::InitEncoder(const nsString& aCharset) return res; } - /** * This method gets called as part of our COM-like interfaces. * Its purpose is to create an interface to parser object @@ -147,18 +145,16 @@ nsHTMLToTXTSinkStream::QueryInterface(const nsIID& aIID, void** aInstancePtr) return NS_OK; } - NS_IMPL_ADDREF(nsHTMLToTXTSinkStream) NS_IMPL_RELEASE(nsHTMLToTXTSinkStream) - // Someday may want to make this non-const: static const PRUint32 TagStackSize = 500; static const PRUint32 OLStackSize = 100; /** * Construct a content sink stream. - * @update gpk02/03/99 + * @update gpk02/03/99 * @param * @return */ @@ -191,10 +187,9 @@ nsHTMLToTXTSinkStream::nsHTMLToTXTSinkStream() mOLStackIndex = 0; } - /** * - * @update gpk02/03/99 + * @update gpk02/03/99 * @param * @return */ @@ -211,7 +206,7 @@ nsHTMLToTXTSinkStream::~nsHTMLToTXTSinkStream() /** * - * @update gpk04/30/99 + * @update gpk04/30/99 * @param * @return */ @@ -229,11 +224,10 @@ nsHTMLToTXTSinkStream::Initialize(nsIOutputStream* aOutStream, /** * - * @update gpk04/30/99 + * @update gpk04/30/99 * @param * @return */ - NS_IMETHODIMP nsHTMLToTXTSinkStream::SetCharsetOverride(const nsString* aCharset) { @@ -245,8 +239,6 @@ nsHTMLToTXTSinkStream::SetCharsetOverride(const nsString* aCharset) return NS_OK; } - - /** * This method gets called by the parser when it encounters * a title tag and wants to set the document title in the sink. @@ -254,9 +246,10 @@ nsHTMLToTXTSinkStream::SetCharsetOverride(const nsString* aCharset) * @update gpk02/03/99 * @param nsString reference to new title value * @return PR_TRUE if successful. - */ + */ NS_IMETHODIMP -nsHTMLToTXTSinkStream::SetTitle(const nsString& aValue){ +nsHTMLToTXTSinkStream::SetTitle(const nsString& aValue) +{ return NS_OK; } @@ -279,7 +272,6 @@ NS_IMETHODIMP \ nsHTMLToTXTSinkStream::closetag(const nsIParserNode& aNode) \ { return CloseContainer(aNode); } - USE_GENERAL_OPEN_METHOD(OpenHTML) USE_GENERAL_CLOSE_METHOD(CloseHTML) USE_GENERAL_OPEN_METHOD(OpenHead) @@ -344,7 +336,6 @@ nsHTMLToTXTSinkStream::AddProcessingInstruction(const nsIParserNode& aNode){ * This gets called by the parser when it encounters * a DOCTYPE declaration in the HTML document. */ - NS_IMETHODIMP nsHTMLToTXTSinkStream::AddDocTypeDecl(const nsIParserNode& aNode, PRInt32 aMode) { @@ -405,6 +396,15 @@ PRBool nsHTMLToTXTSinkStream::DoOutput() return mDoFragment || inBody; } +nsAutoString +Spaces(PRInt32 count) +{ + nsAutoString result; + while (result.Length() < count) + result += ' '; + return result; +} + /** * This method is used to a general container. * This includes: OL,UL,DIR,SPAN,TABLE,H[1..6],etc. @@ -416,7 +416,6 @@ PRBool nsHTMLToTXTSinkStream::DoOutput() NS_IMETHODIMP nsHTMLToTXTSinkStream::OpenContainer(const nsIParserNode& aNode) { - eHTMLTags type = (eHTMLTags)aNode.GetNodeType(); #ifdef DEBUG_bratell printf("OpenContainer: %d ", type); @@ -440,18 +439,16 @@ nsHTMLToTXTSinkStream::OpenContainer(const nsIParserNode& aNode) if (type == eHTMLTag_body) { - // body -> can turn on cacheing unless it's already preformatted if(!(mFlags & nsIDocumentEncoder::OutputPreformatted) && ((mFlags & nsIDocumentEncoder::OutputFormatted) || (mFlags & nsIDocumentEncoder::OutputWrap))) { mCacheLine = PR_TRUE; } - // Would be cool to figure out here whether we have a // preformatted style attribute. It's hard, though. - + // // Trigger on the presence of a "-moz-pre-wrap" in the // style attribute. That's a very simplistic way to do // it, but better than nothing. @@ -471,29 +468,53 @@ nsHTMLToTXTSinkStream::OpenContainer(const nsIParserNode& aNode) if (!DoOutput()) return NS_OK; - if (type == eHTMLTag_ol) + if (type == eHTMLTag_p) + EnsureVerticalSpace(1); // Should this be 0 in unformatted case? + // Else make sure we'll separate block level tags, + // even if we're about to leave before doing any other formatting. + // Oddly, I can't find a case where this actually makes any difference. + //else if (IsBlockLevel(type)) + // EnsureVerticalSpace(0); + + // The rest of this routine is formatted output stuff, + // which we should skip if we're not formatted: + if (!(mFlags & nsIDocumentEncoder::OutputFormatted)) + return NS_OK; + + if (type == eHTMLTag_ul) + { + // Indent here to support nested list, which aren't included in li :-( + mIndent += gIndentSizeList; + EnsureVerticalSpace(1); + } + else if (type == eHTMLTag_ol) { if (mOLStackIndex < OLStackSize) mOLStack[mOLStackIndex++] = 1; // XXX should get it from the node! + mIndent += gIndentSizeList; // see ul + EnsureVerticalSpace(1); } - - if (type == eHTMLTag_li) + else if (type == eHTMLTag_li) { - nsAutoString temp("*"); + nsAutoString temp = Spaces(gIndentSizeList - gOLNumberWidth - 2); if (mTagStackIndex > 1 && mTagStack[mTagStackIndex-2] == eHTMLTag_ol) { + nsAutoString number; if (mOLStackIndex > 0) - { // This is what nsBulletFrame does for OLs: - char cbuf[40]; - PR_snprintf(cbuf, sizeof(cbuf), "%ld.", (mOLStack[mOLStackIndex-1])++); - temp = cbuf; - } + number.Append(mOLStack[mOLStackIndex-1]++, 10); else - temp = "#"; + number += "#"; + temp += Spaces(gOLNumberWidth - number.Length()) + number + '.'; } - Write(temp); - // mColPos++; This is done in Write(temp) above + else + temp += Spaces(gOLNumberWidth) + "*"; + temp += ' '; + + + mIndent -= gIndentSizeList; // don't indent first line so much + Write(temp); //CHANGE: does not work as intended. waiting for bug #17883 + mIndent += gIndentSizeList; } else if (type == eHTMLTag_blockquote) { @@ -515,26 +536,50 @@ nsHTMLToTXTSinkStream::OpenContainer(const nsIParserNode& aNode) { EnsureVerticalSpace(0); } - - // Finally, the list of tags before which we want some vertical space: - switch (type) + else if (type == eHTMLTag_a) { - case eHTMLTag_table: - case eHTMLTag_ul: - case eHTMLTag_ol: - case eHTMLTag_p: - { - EnsureVerticalSpace((mFlags & nsIDocumentEncoder::OutputFormatted) ? 1 : 0); - break; - } - default: - break; + nsAutoString url; + if (NS_SUCCEEDED(GetValueOfAttribute(aNode, "href", url))) + mURL = url; + else + mURL.Truncate(); } + else if (type == eHTMLTag_img) + { + nsAutoString url; + if (NS_SUCCEEDED(GetValueOfAttribute(aNode, "src", url))) + { + nsAutoString temp, desc; + if (NS_SUCCEEDED(GetValueOfAttribute(aNode, "alt", desc))) + { + temp += " ("; + temp += desc; + temp += " 0) --mTagStackIndex; - if (type == eHTMLTag_ol) + // End current line if we're ending a block level tag + if (IsBlockLevel(type)) { + if((type == eHTMLTag_body) || (type == eHTMLTag_html)) { + // We want the output to end with a new line, + // but in preformatted areas like text fields, + // we can't emit newlines that weren't there. + if (mPreFormatted || (mFlags & nsIDocumentEncoder::OutputPreformatted)) + FlushLine(); + else + EnsureVerticalSpace(0); + } else if ((type == eHTMLTag_tr) || + (type == eHTMLTag_li) || + (type == eHTMLTag_blockquote)) { + EnsureVerticalSpace(0); + } else { + // All other blocks get 1 vertical space after them + // in formatted mode, otherwise 0. + // This is hard. Sometimes 0 is a better number, but + // how to know? + EnsureVerticalSpace((mFlags & nsIDocumentEncoder::OutputFormatted) ? 1 : 0); + } + } + + // The rest of this routine is formatted output stuff, + // which we should skip if we're not formatted: + if (!(mFlags & nsIDocumentEncoder::OutputFormatted)) + return NS_OK; + + if (type == eHTMLTag_ul) + { + mIndent -= gIndentSizeList; + } + else if (type == eHTMLTag_ol) + { + FlushLine(); // Doing this after decreasing OLStackIndex would be wrong. --mOLStackIndex; + mIndent -= gIndentSizeList; + } else if (type == eHTMLTag_blockquote) { + FlushLine(); if (mCiteQuoteLevel>0) mCiteQuoteLevel--; else if(mIndent >= gTabSize) @@ -580,33 +662,29 @@ nsHTMLToTXTSinkStream::CloseContainer(const nsIParserNode& aNode) mInWhitespace = PR_TRUE; } } - - // End current line if we're ending a block level tag - if(IsBlockLevel(type)) { - if((type == eHTMLTag_body) || (type == eHTMLTag_html)) { - // We want the output to end with a new line, - // but in preformatted areas like text fields, - // we can't emit newlines that weren't there. - if (mPreFormatted || (mFlags & nsIDocumentEncoder::OutputPreformatted)) - FlushLine(); - else - EnsureVerticalSpace(0); - - } else if((type == eHTMLTag_tr) || - (type == eHTMLTag_blockquote)) { - EnsureVerticalSpace(0); - } else { - // All other blocks get 1 vertical space after them - // in formatted mode, otherwise 0. - // This is hard. Sometimes 0 is a better number, but - // how to know? - EnsureVerticalSpace((mFlags & nsIDocumentEncoder::OutputFormatted) ? 1 : 0); + else if (type == eHTMLTag_a) + { // these brackets must stay here + if (!mURL.IsEmpty()) + { + nsAutoString temp(" 0 ? mWrapColumn : 25); + while (line.Length() < width) + line += '-'; + Write(line); + } return NS_OK; } void nsHTMLToTXTSinkStream::EnsureBufferSize(PRInt32 aNewSize) { - if (mBufferSize < aNewSize) + if (mBufferSize < aNewSize) { nsAllocator::Free(mBuffer); mBufferSize = 2*aNewSize+1; // make the twice as large @@ -706,8 +787,6 @@ void nsHTMLToTXTSinkStream::EnsureBufferSize(PRInt32 aNewSize) } } - - void nsHTMLToTXTSinkStream::EncodeToBuffer(const nsString& aSrc) { if (mUnicodeEncoder == nsnull) @@ -718,8 +797,6 @@ void nsHTMLToTXTSinkStream::EncodeToBuffer(const nsString& aSrc) return; } -#define CH_NBSP 160 - PRInt32 length = aSrc.Length(); nsresult result; @@ -735,17 +812,16 @@ void nsHTMLToTXTSinkStream::EncodeToBuffer(const nsString& aSrc) if (NS_SUCCEEDED(result)) result = mUnicodeEncoder->Finish(mBuffer,&temp); - +// XXX UGH! This is awful and needs to be removed. +#define CH_NBSP 160 for (PRInt32 i = 0; i < mBufferLength; i++) { if (mBuffer[i] == char(CH_NBSP)) mBuffer[i] = ' '; } } - } - void nsHTMLToTXTSinkStream::EnsureVerticalSpace(PRInt32 noOfRows) { @@ -753,19 +829,23 @@ nsHTMLToTXTSinkStream::EnsureVerticalSpace(PRInt32 noOfRows) EndLine(PR_FALSE); } - // This empties the current line cache without adding a NEWLINE. // Should not be used if line wrapping is of importance since // this function destroys the cache information. void nsHTMLToTXTSinkStream::FlushLine() { - WriteSimple(mCurrentLine); - mCurrentLine.SetString(""); + if(mCurrentLine.Length()>0) { + if(0 == mColPos) + WriteQuotesAndIndent(); + + + WriteSimple(mCurrentLine); + mColPos += mCurrentLine.Length(); + mCurrentLine.SetString(""); + } } - - /** * WriteSimple places the contents of aString into either the output stream * or the output string. @@ -840,8 +920,8 @@ nsHTMLToTXTSinkStream::AddToLine(const nsString &linefragment) // Wrap? if(mWrapColumn && ((mFlags & nsIDocumentEncoder::OutputFormatted) || - (mFlags & nsIDocumentEncoder::OutputWrap))) { - + (mFlags & nsIDocumentEncoder::OutputWrap))) + { // Yes, wrap! // The "+4" is to avoid wrap lines that only should be a couple // of letters too long. @@ -869,7 +949,19 @@ nsHTMLToTXTSinkStream::AddToLine(const nsString &linefragment) mCurrentLine.Right(restOfLine, linelength-goodSpace-1); mCurrentLine.Cut(goodSpace, linelength-goodSpace); EndLine(PR_TRUE); - mCurrentLine.SetString(restOfLine); + mCurrentLine.SetString(""); + // Space stuff new line? + if(mFlags & nsIDocumentEncoder::OutputFormatFlowed) { + if((restOfLine[0] == '>') || + (restOfLine[0] == ' ') || + (!restOfLine.Compare("From ",PR_FALSE,5))) { + // Space stuffing a la RFC 2646 if this will be used in a mail, + // but how can I know that??? Now space stuffing is done always + // when formatting text as HTML and that is wrong! XXX: Fix this! + mCurrentLine.Append(' '); + } + } + mCurrentLine.Append(restOfLine); linelength = mCurrentLine.Length(); mEmptyLines = -1; } else { @@ -892,8 +984,9 @@ nsHTMLToTXTSinkStream::EndLine(PRBool softlinebreak) return; } WriteQuotesAndIndent(); - // Remove whitespace from the end of the line. - mCurrentLine.CompressWhitespace(PR_FALSE,PR_TRUE); + // Remove SPACE from the end of the line. + while(' ' == mCurrentLine[mCurrentLine.Length()-1]) + mCurrentLine.SetLength(mCurrentLine.Length()-1); if(mFlags & nsIDocumentEncoder::OutputFormatFlowed) { // Add the soft part of the soft linebreak (RFC 2646 4.1) mCurrentLine.Append(' '); @@ -912,7 +1005,9 @@ nsHTMLToTXTSinkStream::EndLine(PRBool softlinebreak) if(mCurrentLine.Length()>0) mEmptyLines=-1; // Output current line - mCurrentLine.CompressWhitespace(PR_FALSE,PR_TRUE); + // Remove SPACE from the end of the line. + while(' ' == mCurrentLine[mCurrentLine.Length()-1]) + mCurrentLine.SetLength(mCurrentLine.Length()-1); mCurrentLine.Append(NS_LINEBREAK); WriteSimple(mCurrentLine); mCurrentLine.SetString(""); @@ -952,7 +1047,6 @@ nsHTMLToTXTSinkStream::WriteQuotesAndIndent() } } - #ifdef DEBUG_akkana_not #define DEBUG_wrapping 1 #endif @@ -971,8 +1065,6 @@ nsHTMLToTXTSinkStream::Write(const nsString& aString) nsAllocator::Free(foo); #endif - - PRInt32 bol = 0; PRInt32 newline; @@ -981,10 +1073,8 @@ nsHTMLToTXTSinkStream::Write(const nsString& aString) // Don't wrap mail-quoted text // Yes do! /Daniel Bratell // PRUint32 wrapcol = (mCiteQuote ? 0 : mWrapColumn); - // PRInt32 prefixwidth = (mCiteQuoteLevel>0?mCiteQuoteLevel+1:0)+mIndent; - // PRInt32 linewidth = mWrapColumn-prefixwidth; - + // PRInt32 linewidth = mWrapColumn-prefixwidth; // if ((!(mFlags & nsIDocumentEncoder::OutputFormatted) // && !(mFlags & nsIDocumentEncoder::OutputWrap)) || // ((mTagStackIndex > 0) && @@ -997,7 +1087,8 @@ nsHTMLToTXTSinkStream::Write(const nsString& aString) // intelligent wrapping without clearing the mCurrentLine // buffer before!!! - NS_ASSERTION(mCurrentLine.Length() == 0, "Mixed wrapping data and nonwrapping data on the same line"); + NS_ASSERTION(mCurrentLine.Length() == 0, + "Mixed wrapping data and nonwrapping data on the same line"); // Put the mail quote "> " chars in, if appropriate. // Have to put it in before every line. @@ -1057,10 +1148,9 @@ nsHTMLToTXTSinkStream::Write(const nsString& aString) return; } - // Intelligent handling of text - // Strip out all "end of lines" and multiple whitespace between words - + // If needed, strip out all "end of lines" + // and multiple whitespace between words PRInt32 nextpos; nsAutoString tempstr; @@ -1086,7 +1176,8 @@ nsHTMLToTXTSinkStream::Write(const nsString& aString) bol=totLen; mInWhitespace=PR_FALSE; } else { - if(mInWhitespace && (nextpos == bol)) { + if(mInWhitespace && (nextpos == bol) && + !(mFlags & nsIDocumentEncoder::OutputPreformatted)) { // Skip whitespace bol++; continue; @@ -1095,24 +1186,30 @@ nsHTMLToTXTSinkStream::Write(const nsString& aString) if(nextpos == bol) { // Note that we are in whitespace. mInWhitespace = PR_TRUE; + nsAutoString whitestring=aString[nextpos]; if(!mCacheLine) { - WriteSimple(" "); + WriteSimple(whitestring); } else { - AddToLine(" "); + AddToLine(whitestring); } bol++; continue; } aString.Mid(tempstr,bol,nextpos-bol); - tempstr.Append(" "); + if(mFlags & nsIDocumentEncoder::OutputPreformatted) { + bol = nextpos; + } else { + tempstr.Append(" "); + bol = nextpos + 1; + mInWhitespace = PR_TRUE; + } + if(!mCacheLine) { WriteSimple(tempstr); } else { AddToLine(tempstr); } - mInWhitespace = PR_TRUE; - bol = nextpos + 1; } } // Continue looping over the string } @@ -1128,7 +1225,6 @@ nsHTMLToTXTSinkStream::WillBuildModel(void){ return NS_OK; } - /** * This method gets called when the parser concludes the process * of building the content model via the content sink. @@ -1142,7 +1238,6 @@ nsHTMLToTXTSinkStream::DidBuildModel(PRInt32 aQualityLevel) { return NS_OK; } - /** * This method gets called when the parser gets i/o blocked, * and wants to notify the sink that it may be a while before @@ -1155,7 +1250,6 @@ nsHTMLToTXTSinkStream::WillInterrupt(void) { return NS_OK; } - /** * This method gets called when the parser i/o gets unblocked, * and we're about to start dumping content again to the sink. @@ -1178,7 +1272,6 @@ nsHTMLToTXTSinkStream::NotifyError(const nsParserError* aError) return NS_OK; } - PRBool IsInline(eHTMLTags aTag) { PRBool result = PR_FALSE; @@ -1215,13 +1308,11 @@ PRBool IsInline(eHTMLTags aTag) case eHTMLTag_u: case eHTMLTag_var: case eHTMLTag_wbr: - result = PR_TRUE; break; default: break; - } return result; } @@ -1230,4 +1321,3 @@ PRBool IsBlockLevel(eHTMLTags aTag) { return !IsInline(aTag); } - diff --git a/mozilla/parser/htmlparser/src/nsHTMLToTXTSinkStream.h b/mozilla/parser/htmlparser/src/nsHTMLToTXTSinkStream.h index d626887cdbb..5b281dd7bd9 100644 --- a/mozilla/parser/htmlparser/src/nsHTMLToTXTSinkStream.h +++ b/mozilla/parser/htmlparser/src/nsHTMLToTXTSinkStream.h @@ -174,6 +174,8 @@ protected: PRBool mPreFormatted; PRBool mCacheLine; // If the line should be cached before output. This makes it possible to do smarter wrapping. + nsString mURL; + // The tag stack: the stack of tags we're operating on, so we can nest: nsHTMLTag *mTagStack; PRUint32 mTagStackIndex; diff --git a/mozilla/parser/htmlparser/tests/outsinks/Makefile.in b/mozilla/parser/htmlparser/tests/outsinks/Makefile.in index 160614a057c..2f0961f6ea6 100644 --- a/mozilla/parser/htmlparser/tests/outsinks/Makefile.in +++ b/mozilla/parser/htmlparser/tests/outsinks/Makefile.in @@ -45,6 +45,7 @@ TEST_FILES = \ plainnowrap.out \ simple.html \ simplecopy.out \ + simplefmt.out \ entityxif.xif \ entityxif.out \ mailquote.html \ diff --git a/mozilla/parser/htmlparser/tests/outsinks/TestOutSinks b/mozilla/parser/htmlparser/tests/outsinks/TestOutSinks index 3fc4d9969c2..6887f90ef08 100755 --- a/mozilla/parser/htmlparser/tests/outsinks/TestOutSinks +++ b/mozilla/parser/htmlparser/tests/outsinks/TestOutSinks @@ -41,6 +41,13 @@ if ($status != 0) then set errmsg = ($errmsg "simplecopy.out") endif +echo "Testing simple html to plaintext formatting ..." +TestOutput -i text/html -o text/plain -f 34 -w 70 -c OutTestData/simplefmt.out OutTestData/simple.html +if ($status != 0) then + echo "Simple copy test failed.\n" + set errmsg = ($errmsg "simplefmt.out") +endif + echo "Testing non-wrapped plaintext ..." TestOutput -i text/html -o text/plain -f 0 -w 0 -c OutTestData/plainnowrap.out OutTestData/plain.html if ($status != 0) then @@ -48,7 +55,7 @@ if ($status != 0) then set errmsg = ($errmsg "plainnowrap.out") endif -echo "Testing wrapped bug unformatted plaintext ..." +echo "Testing wrapped but unformatted plaintext ..." TestOutput -i text/html -o text/plain -f 32 -w 50 -c OutTestData/plainwrap.out OutTestData/plain.html if ($status != 0) then echo "Wrapped plaintext test failed." @@ -56,7 +63,7 @@ if ($status != 0) then endif echo "Testing mail quoting ..." -TestOutput -i text/html -o text/plain -c OutTestData/mailquote.out OutTestData/mailquote.html +TestOutput -i text/html -o text/plain -f 2 -w 50 -c OutTestData/mailquote.out OutTestData/mailquote.html if ($status != 0) then echo "Mail quoting test failed." set errmsg = ($errmsg "mailquote.out") diff --git a/mozilla/parser/htmlparser/tests/outsinks/htmltable.out b/mozilla/parser/htmlparser/tests/outsinks/htmltable.out index 7d19794925f..7d17268018c 100644 --- a/mozilla/parser/htmlparser/tests/outsinks/htmltable.out +++ b/mozilla/parser/htmlparser/tests/outsinks/htmltable.out @@ -1,7 +1,5 @@ Below is a table. - Row 1 Col 1 Row 1 Col 2 Row 1 Col 3 Row 2 Col 1 Row 2 Col 2 Row 2 Col 3 Row 3 Col 1 Row 3 Col 2 Row 3 Col 3 - Here is after table. diff --git a/mozilla/parser/htmlparser/tests/outsinks/mailquote.html b/mozilla/parser/htmlparser/tests/outsinks/mailquote.html index 5882c2054b8..8ffa5bfe3a0 100644 --- a/mozilla/parser/htmlparser/tests/outsinks/mailquote.html +++ b/mozilla/parser/htmlparser/tests/outsinks/mailquote.html @@ -37,7 +37,7 @@ I hope you will enjoy these quotes from Hamlet, introduced by a fairly To be, or not to be, that is the question
Whether 'tis nobler in the mind to suffer
The slings and fortunes of outrageous fortune
-Or to take arms against a sea of troubles
+Or to take arms against a sea of troubles, And by opposing end them.
diff --git a/mozilla/parser/htmlparser/tests/outsinks/mailquote.out b/mozilla/parser/htmlparser/tests/outsinks/mailquote.out index dd29ea59344..ec4bacc5598 100644 --- a/mozilla/parser/htmlparser/tests/outsinks/mailquote.out +++ b/mozilla/parser/htmlparser/tests/outsinks/mailquote.out @@ -1,19 +1,22 @@ This page is a test of mail quoting. -I hope you will enjoy these quotes from Hamlet, introduced by a fairly long line to see how quotations get wrapped: +I hope you will enjoy these quotes from /Hamlet/, +introduced by a fairly long line to see how +quotations get wrapped: ->> (These have br tags after them. +>> /(These have *br* tags after them./ >> To be, or not to be, that is the question >> Whether 'tis nobler in the mind to suffer >> The slings and fortunes of outrageous fortune ->> Or to take arms against a sea of troubles ->> And by opposing end them. +>> Or to take arms against a sea of troubles, And +>> by opposing end them. > > Oh, what a mind is here o'erthrown. > ->> (The next line does not end with a br tag.). +>> /(The next line does not end with a *br* tag.)./ >> Oh, what a rogue and peasant slave am I. -> (Neither does the next line:) +> /(Neither does the next line:)/ > The observed of all observers, quite, quite down! Now we're outside all blockquotes. + diff --git a/mozilla/parser/htmlparser/tests/outsinks/makefile.win b/mozilla/parser/htmlparser/tests/outsinks/makefile.win index 4274e2502e2..80885f31ce3 100644 --- a/mozilla/parser/htmlparser/tests/outsinks/makefile.win +++ b/mozilla/parser/htmlparser/tests/outsinks/makefile.win @@ -37,6 +37,7 @@ TEST_FILES = \ plainnowrap.out \ simple.html \ simplecopy.out \ + simplefmt.out \ entityxif.xif \ entityxif.out \ mailquote.html \ diff --git a/mozilla/parser/htmlparser/tests/outsinks/plainnowrap.out b/mozilla/parser/htmlparser/tests/outsinks/plainnowrap.out index d87bca54633..3db8241fd2c 100644 --- a/mozilla/parser/htmlparser/tests/outsinks/plainnowrap.out +++ b/mozilla/parser/htmlparser/tests/outsinks/plainnowrap.out @@ -1,8 +1,13 @@ + + 80 char width (for reference only): ---------|---------|---------|---------|---------|---------|---------|---------| Here is a link to mozilla.org. Here is some underlined and boldenedified text. This is a test to make sure the output converters pick up the moz-pre-wrap style. They don't necessarily have to pick up the exact wrap setting. + - This should be tested with wrapping on. - This should be tested with wrapping off. + This is the end. + diff --git a/mozilla/parser/htmlparser/tests/outsinks/simple.html b/mozilla/parser/htmlparser/tests/outsinks/simple.html index 9211c2eace8..5a787db1a51 100644 --- a/mozilla/parser/htmlparser/tests/outsinks/simple.html +++ b/mozilla/parser/htmlparser/tests/outsinks/simple.html @@ -37,5 +37,22 @@ followed by a line break. Plaintext output should contain only one space (and no line breaks) between "space" and "followed".

+

+Here is a list: +

+ +
    +
  • An item
  • +
  • A nested ordered list:
  • +
    1. +
    2. item one
    3. +
    4. item two
    5. +
    +
  • +
  • last item
  • +
+ +

Here is a paragraph after the list.

+ diff --git a/mozilla/parser/htmlparser/tests/outsinks/simplecopy.out b/mozilla/parser/htmlparser/tests/outsinks/simplecopy.out index 38227545f15..0b380583181 100644 --- a/mozilla/parser/htmlparser/tests/outsinks/simplecopy.out +++ b/mozilla/parser/htmlparser/tests/outsinks/simplecopy.out @@ -1,3 +1,13 @@ -Simple html page Here is a link to mozilla.org. Here is some underlined and boldenedified text. +Simple html page +Here is a link to the mozilla.org page. Here is some underlined and boldenedified text plus some . + Here is a line ending with a space followed by a line break. Plaintext output should contain only one space (and no line breaks) between "space" and "followed". +Here is a list: +An item +A nested ordered list: +item one +item two +last item + +Here is a paragraph after the list. diff --git a/mozilla/parser/htmlparser/tests/outsinks/simplefmt.out b/mozilla/parser/htmlparser/tests/outsinks/simplefmt.out new file mode 100644 index 00000000000..4de7ade36a5 --- /dev/null +++ b/mozilla/parser/htmlparser/tests/outsinks/simplefmt.out @@ -0,0 +1,23 @@ +Simple html page + +Here is a link to the mozilla.org page. +Here is some _underlined and *bold*ened_ified text plus some . + +Here is a line ending with a space followed by a line break. Plaintext +output should contain only one space (and no line breaks) between +"space" and "followed". + +Here is a /list/: + + * An item + * A nested ordered list: + * + + 1. item one + 2. item two + + * last item + +Here is a paragraph after the list. +