From 7796c1500df4b305199e39ad001957048008da5a Mon Sep 17 00:00:00 2001 From: "mozilla.BenB%bucksch.org" Date: Fri, 28 Jul 2000 23:18:12 +0000 Subject: [PATCH] 44439: Support headers (3 modes),
/
, , , . Improved , . Improved "unknown" block and (some) inline tags. Pref for structured phrases. r=akk, a=waterson git-svn-id: svn://10.0.0.236/trunk@75106 18797224-902f-48f8-a5cc-f745e15eee43 --- .../htmlparser/src/nsHTMLToTXTSinkStream.cpp | 227 ++++++++++++++---- .../htmlparser/src/nsHTMLToTXTSinkStream.h | 11 + .../htmlparser/tests/outsinks/simplefmt.out | 3 +- mozilla/modules/libpref/src/init/all.js | 2 + .../htmlparser/src/nsHTMLToTXTSinkStream.cpp | 227 ++++++++++++++---- .../htmlparser/src/nsHTMLToTXTSinkStream.h | 11 + .../htmlparser/tests/outsinks/simplefmt.out | 3 +- 7 files changed, 400 insertions(+), 84 deletions(-) diff --git a/mozilla/htmlparser/src/nsHTMLToTXTSinkStream.cpp b/mozilla/htmlparser/src/nsHTMLToTXTSinkStream.cpp index 17d1187af0b..b1ce5c254f3 100644 --- a/mozilla/htmlparser/src/nsHTMLToTXTSinkStream.cpp +++ b/mozilla/htmlparser/src/nsHTMLToTXTSinkStream.cpp @@ -52,17 +52,31 @@ #include "nsLWBrkCIID.h" #include "nsIOutputStream.h" #include "nsFileStream.h" +#include "nsIPref.h" static NS_DEFINE_CID(kCharsetConverterManagerCID, NS_ICHARSETCONVERTERMANAGER_CID); static NS_DEFINE_CID(kLWBrkCID, NS_LWBRK_CID); +static NS_DEFINE_CID(kPrefServiceCID, NS_PREF_CID); +#define PREF_STRUCTS "converter.html2txt.structs" +#define PREF_HEADER_STRATEGY "converter.html2txt.header_strategy" const PRInt32 gTabSize=4; const PRInt32 gOLNumberWidth = 3; +const PRInt32 gIndentSizeHeaders = 2; /* Indention of h1, if + mHeaderStrategy = 1 or = 2. + Indention of other headers + is derived from that. + XXX center h1? */ +const PRInt32 gIndentIncrementHeaders = 2; /* If mHeaderStrategy = 1, + indent h(x+1) this many + columns more than h(x) */ const PRInt32 gIndentSizeList = (gTabSize > gOLNumberWidth+3) ? gTabSize: gOLNumberWidth+3; // Indention of non-first lines of ul and ol +const PRInt32 gIndentSizeDD = gTabSize; // Indention of
static PRBool IsInline(eHTMLTags aTag); static PRBool IsBlockLevel(eHTMLTags aTag); +static PRInt32 HeaderLevel(eHTMLTags aTag); static PRInt32 unicharwidth(PRUnichar ucs); static PRInt32 unicharwidth(const PRUnichar* pwcs, PRInt32 n); @@ -181,6 +195,10 @@ nsHTMLToTXTSinkStream::nsHTMLToTXTSinkStream() mBufferLength = 0; mBuffer = nsnull; mUnicodeEncoder = nsnull; + mStructs = PR_TRUE; // will be read from prefs later + mHeaderStrategy = 1 /*indent increasingly*/; // ditto + for (PRInt32 i = 0; i <= 6; i++) + mHeaderCounter[i] = 0; // Line breaker mLineBreaker = nsnull; @@ -273,6 +291,15 @@ nsHTMLToTXTSinkStream::Initialize(nsIOutputStream* aOutStream, else mLineBreak.AssignWithConversion(NS_LINEBREAK); // Platform/default + // Get some prefs + nsresult rv; + NS_WITH_SERVICE(nsIPref, prefs, NS_PREF_PROGID, &rv); + if (NS_SUCCEEDED(rv) && prefs) + { + rv = prefs->GetBoolPref(PREF_STRUCTS, &mStructs); + rv = prefs->GetIntPref(PREF_HEADER_STRATEGY, &mHeaderStrategy); + } + return result; } @@ -514,7 +541,6 @@ nsHTMLToTXTSinkStream::OpenContainer(const nsIParserNode& aNode) PRInt32 whitespace; if(NS_SUCCEEDED(GetValueOfAttribute(aNode, "style", style)) && (-1 != (whitespace = style.Find("white-space:")))) - /* DELETEME: What, if the style is defined in an external stylesheet? */ { if (-1 != style.Find("-moz-pre-wrap", PR_TRUE, whitespace)) { @@ -569,19 +595,51 @@ nsHTMLToTXTSinkStream::OpenContainer(const nsIParserNode& aNode) if (type == eHTMLTag_p || type == eHTMLTag_pre) 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); + // even if we're about to leave, before doing any other formatting. + 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) + if (type == eHTMLTag_h1 || type == eHTMLTag_h2 || + type == eHTMLTag_h3 || type == eHTMLTag_h4 || + type == eHTMLTag_h5 || type == eHTMLTag_h6) + { + EnsureVerticalSpace(2); + if (mHeaderStrategy == 2) // numbered + { + mIndent += gIndentSizeHeaders; + // Caching + nsCAutoString leadup; + PRInt32 level = HeaderLevel(type); + // Increase counter for current level + mHeaderCounter[level]++; + // Reset all lower levels + PRInt32 i; + for (i = level + 1; i <= 6; i++) + mHeaderCounter[i] = 0; + // Construct numbers + for (i = 1; i <= level; i++) + { + leadup.AppendInt(mHeaderCounter[i]); + leadup += "."; + } + leadup += " "; + Write(NS_ConvertASCIItoUCS2(leadup.GetBuffer())); + } + else if (mHeaderStrategy == 1) // indent increasingly + { + mIndent += gIndentSizeHeaders; + for (PRInt32 i = HeaderLevel(type); i > 1; i--) + // for h(x), run x-1 times + mIndent += gIndentIncrementHeaders; + } + } + else if (type == eHTMLTag_ul) { // Indent here to support nested list, which aren't included in li :-( EnsureVerticalSpace(1); // Must end the current line before we change indent. @@ -612,7 +670,11 @@ nsHTMLToTXTSinkStream::OpenContainer(const nsIParserNode& aNode) mInIndentString.AppendWithConversion(' '); } - else if (type == eHTMLTag_td) + else if (type == eHTMLTag_dl) + EnsureVerticalSpace(1); + else if (type == eHTMLTag_dd) + mIndent += gIndentSizeDD; + else if (type == eHTMLTag_td || type == eHTMLTag_th) { // We must make sure that the content of two table cells get a // space between them. @@ -653,30 +715,39 @@ nsHTMLToTXTSinkStream::OpenContainer(const nsIParserNode& aNode) } else if (type == eHTMLTag_img) { - nsAutoString url; - if (NS_SUCCEEDED(GetValueOfAttribute(aNode, "src", url)) && !url.IsEmpty()) + /* Output (in decreasing order of preference) + alt, title or src (URI) attribute */ + // See + nsAutoString desc, temp; + if (NS_SUCCEEDED(GetValueOfAttribute(aNode, "alt", desc))) { - nsAutoString temp, desc; - if (NS_SUCCEEDED(GetValueOfAttribute(aNode, "alt", desc)) - && !desc.IsEmpty()) + if (!desc.IsEmpty()) { - temp.AppendWithConversion(" ("); + temp.AppendWithConversion(" ["); // Should we output chars at all here? desc.StripChars("\""); temp += desc; - temp.AppendWithConversion(" <"); - url.StripChars("\""); - temp += url; - temp.AppendWithConversion(">) "); + temp.AppendWithConversion(" ]"); } - else - { - temp.AppendWithConversion(" <"); - url.StripChars("\""); - temp += url; - temp.AppendWithConversion("> "); - } - Write(temp); + // If the alt attribute has an empty value (|alt=""|), output nothing } + else if (NS_SUCCEEDED(GetValueOfAttribute(aNode, "title", desc)) + && !desc.IsEmpty()) + { + temp.AppendWithConversion(" ["); + desc.StripChars("\""); + temp += desc; + temp.AppendWithConversion("] "); + } + else if (NS_SUCCEEDED(GetValueOfAttribute(aNode, "src", desc)) + && !desc.IsEmpty()) + { + temp.AppendWithConversion(" <"); + desc.StripChars("\""); + temp += desc; + temp.AppendWithConversion("> "); + } + if (!temp.IsEmpty()) + Write(temp); } else if (type == eHTMLTag_a && !IsConverted(aNode)) { @@ -688,15 +759,21 @@ nsHTMLToTXTSinkStream::OpenContainer(const nsIParserNode& aNode) mURL = url; } } - else if (type == eHTMLTag_sup && !IsConverted(aNode)) + else if (type == eHTMLTag_q) + Write(NS_ConvertASCIItoUCS2("\"")); + else if (type == eHTMLTag_sup && mStructs && !IsConverted(aNode)) Write(NS_ConvertASCIItoUCS2("^")); - else if (type == eHTMLTag_sub && !IsConverted(aNode)) + else if (type == eHTMLTag_sub && mStructs && !IsConverted(aNode)) Write(NS_ConvertASCIItoUCS2("_")); - else if ((type ==eHTMLTag_strong || type==eHTMLTag_b) && !IsConverted(aNode)) + else if (type == eHTMLTag_code && mStructs && !IsConverted(aNode)) + Write(NS_ConvertASCIItoUCS2("|")); + else if ((type == eHTMLTag_strong || type == eHTMLTag_b) + && mStructs && !IsConverted(aNode)) Write(NS_ConvertASCIItoUCS2("*")); - else if ((type == eHTMLTag_em || type == eHTMLTag_i) && !IsConverted(aNode)) + else if ((type == eHTMLTag_em || type == eHTMLTag_i) + && mStructs && !IsConverted(aNode)) Write(NS_ConvertASCIItoUCS2("/")); - else if (type == eHTMLTag_u && !IsConverted(aNode)) + else if (type == eHTMLTag_u && mStructs && !IsConverted(aNode)) Write(NS_ConvertASCIItoUCS2("_")); return NS_OK; @@ -729,6 +806,8 @@ nsHTMLToTXTSinkStream::CloseContainer(const nsIParserNode& aNode) FlushLine(); } else if ((type == eHTMLTag_tr) || (type == eHTMLTag_li) || + (type == eHTMLTag_dt) || + (type == eHTMLTag_dd) || (type == eHTMLTag_pre) || (type == eHTMLTag_blockquote)) { EnsureVerticalSpace(0); @@ -737,7 +816,8 @@ nsHTMLToTXTSinkStream::CloseContainer(const nsIParserNode& aNode) // in formatted mode, otherwise 0. // This is hard. Sometimes 0 is a better number, but // how to know? - EnsureVerticalSpace((mFlags & nsIDocumentEncoder::OutputFormatted) ? 1 : 0); + EnsureVerticalSpace((mFlags & nsIDocumentEncoder::OutputFormatted) + ? 1 : 0); } } @@ -746,7 +826,21 @@ nsHTMLToTXTSinkStream::CloseContainer(const nsIParserNode& aNode) if (!(mFlags & nsIDocumentEncoder::OutputFormatted)) return NS_OK; - if (type == eHTMLTag_ul) + if (type == eHTMLTag_h1 || type == eHTMLTag_h2 || + type == eHTMLTag_h3 || type == eHTMLTag_h4 || + type == eHTMLTag_h5 || type == eHTMLTag_h6) + { + if (mHeaderStrategy /*numbered or indent increasingly*/ ) + mIndent -= gIndentSizeHeaders; + if (mHeaderStrategy == 1 /*indent increasingly*/ ) + { + for (PRInt32 i = HeaderLevel(type); i > 1; i--) + // for h(x), run x-1 times + mIndent -= gIndentIncrementHeaders; + } + EnsureVerticalSpace(1); + } + else if (type == eHTMLTag_ul) { mIndent -= gIndentSizeList; } @@ -756,12 +850,21 @@ nsHTMLToTXTSinkStream::CloseContainer(const nsIParserNode& aNode) --mOLStackIndex; mIndent -= gIndentSizeList; } + else if (type == eHTMLTag_dd) + { + mIndent -= gIndentSizeDD; + } else if (type == eHTMLTag_blockquote) { FlushLine(); - if (mCiteQuoteLevel>0) + nsString value; + nsresult rv = GetValueOfAttribute(aNode, "type", value); + if ( NS_SUCCEEDED(rv) ) + value.StripChars("\""); + + if (NS_SUCCEEDED(rv) && value.EqualsWithConversion("cite", PR_TRUE)) mCiteQuoteLevel--; - else if(mIndent >= gTabSize) + else mIndent -= gTabSize; } else if (type == eHTMLTag_a && !IsConverted(aNode) && !mURL.IsEmpty()) @@ -772,13 +875,20 @@ nsHTMLToTXTSinkStream::CloseContainer(const nsIParserNode& aNode) Write(temp); mURL.Truncate(); } - else if ((type== eHTMLTag_sup || type== eHTMLTag_sub) && !IsConverted(aNode)) + else if (type == eHTMLTag_q) + Write(NS_ConvertASCIItoUCS2("\"")); + else if ((type == eHTMLTag_sup || type == eHTMLTag_sub) + && mStructs && !IsConverted(aNode)) Write(NS_ConvertASCIItoUCS2(" ")); - else if ((type== eHTMLTag_strong || type==eHTMLTag_b) && !IsConverted(aNode)) + else if (type == eHTMLTag_code && mStructs && !IsConverted(aNode)) + Write(NS_ConvertASCIItoUCS2("|")); + else if ((type == eHTMLTag_strong || type == eHTMLTag_b) + && mStructs && !IsConverted(aNode)) Write(NS_ConvertASCIItoUCS2("*")); - else if ((type == eHTMLTag_em || type == eHTMLTag_i) && !IsConverted(aNode)) + else if ((type == eHTMLTag_em || type == eHTMLTag_i) + && mStructs && !IsConverted(aNode)) Write(NS_ConvertASCIItoUCS2("/")); - else if (type == eHTMLTag_u && !IsConverted(aNode)) + else if (type == eHTMLTag_u && mStructs && !IsConverted(aNode)) Write(NS_ConvertASCIItoUCS2("_")); return NS_OK; @@ -887,6 +997,7 @@ nsHTMLToTXTSinkStream::AddLeaf(const nsIParserNode& aNode) EnsureVerticalSpace(0); // Make a line of dashes as wide as the wrap width + // XXX honoring percentage would be nice nsAutoString line; PRUint32 width = (mWrapColumn > 0 ? mWrapColumn : 25); while (line.Length() < width) @@ -1483,20 +1594,23 @@ PRBool IsInline(eHTMLTags aTag) { case eHTMLTag_a: case eHTMLTag_address: + case eHTMLTag_b: case eHTMLTag_big: case eHTMLTag_blink: - case eHTMLTag_b: case eHTMLTag_br: case eHTMLTag_cite: case eHTMLTag_code: case eHTMLTag_dfn: + case eHTMLTag_del: case eHTMLTag_em: case eHTMLTag_font: - case eHTMLTag_img: case eHTMLTag_i: + case eHTMLTag_img: + case eHTMLTag_ins: case eHTMLTag_kbd: case eHTMLTag_keygen: case eHTMLTag_nobr: + case eHTMLTag_q: case eHTMLTag_samp: case eHTMLTag_small: case eHTMLTag_spacer: @@ -1507,6 +1621,7 @@ PRBool IsInline(eHTMLTags aTag) case eHTMLTag_sup: case eHTMLTag_td: case eHTMLTag_textarea: + case eHTMLTag_th: case eHTMLTag_tt: case eHTMLTag_u: case eHTMLTag_var: @@ -1523,6 +1638,36 @@ PRBool IsInline(eHTMLTags aTag) PRBool IsBlockLevel(eHTMLTags aTag) { return !IsInline(aTag); + /* XXX Note: We output linebreaks for blocks. + I.e. we output linebreaks for "unknown" inline tags. + I just hunted such a bug for , same for , etc.. + Better fallback to inline. /BenB */ +} + +/* + @return 0 = no header, 1 = h1, ..., 6 = h6 +*/ +PRInt32 HeaderLevel(eHTMLTags aTag) +{ + PRInt32 result; + switch (aTag) + { + case eHTMLTag_h1: + result = 1; break; + case eHTMLTag_h2: + result = 2; break; + case eHTMLTag_h3: + result = 3; break; + case eHTMLTag_h4: + result = 4; break; + case eHTMLTag_h5: + result = 5; break; + case eHTMLTag_h6: + result = 6; break; + default: + result = 0; break; + } + return result; } PRBool nsHTMLToTXTSinkStream::MayWrap() diff --git a/mozilla/htmlparser/src/nsHTMLToTXTSinkStream.h b/mozilla/htmlparser/src/nsHTMLToTXTSinkStream.h index c544b0e5a93..eb7ded47e6e 100644 --- a/mozilla/htmlparser/src/nsHTMLToTXTSinkStream.h +++ b/mozilla/htmlparser/src/nsHTMLToTXTSinkStream.h @@ -189,6 +189,17 @@ protected: PRBool mStartedOutput; // we've produced at least a character nsString mURL; + PRInt32 mStructs; // Output structs (pref) + PRBool mHeaderStrategy; /* Header strategy (pref) + 0 = no indention + 1 = indention, increased with + header level (default) + 2 = numbering and slight indention */ + PRInt32 mHeaderCounter[7]; /* For header-numbering: + Number of previous headers of + the same depth and in the same + section. + mHeaderCounter[1] for

etc. */ // The tag stack: the stack of tags we're operating on, so we can nest: nsHTMLTag *mTagStack; diff --git a/mozilla/htmlparser/tests/outsinks/simplefmt.out b/mozilla/htmlparser/tests/outsinks/simplefmt.out index 8848438c595..030a38c7192 100644 --- a/mozilla/htmlparser/tests/outsinks/simplefmt.out +++ b/mozilla/htmlparser/tests/outsinks/simplefmt.out @@ -1,5 +1,6 @@ -Simple html page + Simple html page + Here is a link to the mozilla.org page. Here is some _underlined and *bold*ened_ified text plus some . diff --git a/mozilla/modules/libpref/src/init/all.js b/mozilla/modules/libpref/src/init/all.js index e9ee05ffd44..c84861c8b52 100644 --- a/mozilla/modules/libpref/src/init/all.js +++ b/mozilla/modules/libpref/src/init/all.js @@ -301,6 +301,8 @@ pref("signon.rememberSignons", true); pref("network.sendRefererHeader", 2); // 0=don't send any, 1=send only on clicks, 2=send on image requests as well pref("network.enablePad", false); // Allow client to do proxy autodiscovery pref("network.padPacURL", ""); // The proxy autodiscovery url +pref("converter.html2txt.structs", true); // Output structured phrases (strong, em, code, sub, sup, b, i, u) +pref("converter.html2txt.header_strategy", 1); // 0 = no indention; 1 = indention, increased with header level; 2 = numbering and slight indention pref("wallet.captureForms", true); pref("wallet.notified", false); pref("wallet.fetchPatches", false); diff --git a/mozilla/parser/htmlparser/src/nsHTMLToTXTSinkStream.cpp b/mozilla/parser/htmlparser/src/nsHTMLToTXTSinkStream.cpp index 17d1187af0b..b1ce5c254f3 100644 --- a/mozilla/parser/htmlparser/src/nsHTMLToTXTSinkStream.cpp +++ b/mozilla/parser/htmlparser/src/nsHTMLToTXTSinkStream.cpp @@ -52,17 +52,31 @@ #include "nsLWBrkCIID.h" #include "nsIOutputStream.h" #include "nsFileStream.h" +#include "nsIPref.h" static NS_DEFINE_CID(kCharsetConverterManagerCID, NS_ICHARSETCONVERTERMANAGER_CID); static NS_DEFINE_CID(kLWBrkCID, NS_LWBRK_CID); +static NS_DEFINE_CID(kPrefServiceCID, NS_PREF_CID); +#define PREF_STRUCTS "converter.html2txt.structs" +#define PREF_HEADER_STRATEGY "converter.html2txt.header_strategy" const PRInt32 gTabSize=4; const PRInt32 gOLNumberWidth = 3; +const PRInt32 gIndentSizeHeaders = 2; /* Indention of h1, if + mHeaderStrategy = 1 or = 2. + Indention of other headers + is derived from that. + XXX center h1? */ +const PRInt32 gIndentIncrementHeaders = 2; /* If mHeaderStrategy = 1, + indent h(x+1) this many + columns more than h(x) */ const PRInt32 gIndentSizeList = (gTabSize > gOLNumberWidth+3) ? gTabSize: gOLNumberWidth+3; // Indention of non-first lines of ul and ol +const PRInt32 gIndentSizeDD = gTabSize; // Indention of
static PRBool IsInline(eHTMLTags aTag); static PRBool IsBlockLevel(eHTMLTags aTag); +static PRInt32 HeaderLevel(eHTMLTags aTag); static PRInt32 unicharwidth(PRUnichar ucs); static PRInt32 unicharwidth(const PRUnichar* pwcs, PRInt32 n); @@ -181,6 +195,10 @@ nsHTMLToTXTSinkStream::nsHTMLToTXTSinkStream() mBufferLength = 0; mBuffer = nsnull; mUnicodeEncoder = nsnull; + mStructs = PR_TRUE; // will be read from prefs later + mHeaderStrategy = 1 /*indent increasingly*/; // ditto + for (PRInt32 i = 0; i <= 6; i++) + mHeaderCounter[i] = 0; // Line breaker mLineBreaker = nsnull; @@ -273,6 +291,15 @@ nsHTMLToTXTSinkStream::Initialize(nsIOutputStream* aOutStream, else mLineBreak.AssignWithConversion(NS_LINEBREAK); // Platform/default + // Get some prefs + nsresult rv; + NS_WITH_SERVICE(nsIPref, prefs, NS_PREF_PROGID, &rv); + if (NS_SUCCEEDED(rv) && prefs) + { + rv = prefs->GetBoolPref(PREF_STRUCTS, &mStructs); + rv = prefs->GetIntPref(PREF_HEADER_STRATEGY, &mHeaderStrategy); + } + return result; } @@ -514,7 +541,6 @@ nsHTMLToTXTSinkStream::OpenContainer(const nsIParserNode& aNode) PRInt32 whitespace; if(NS_SUCCEEDED(GetValueOfAttribute(aNode, "style", style)) && (-1 != (whitespace = style.Find("white-space:")))) - /* DELETEME: What, if the style is defined in an external stylesheet? */ { if (-1 != style.Find("-moz-pre-wrap", PR_TRUE, whitespace)) { @@ -569,19 +595,51 @@ nsHTMLToTXTSinkStream::OpenContainer(const nsIParserNode& aNode) if (type == eHTMLTag_p || type == eHTMLTag_pre) 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); + // even if we're about to leave, before doing any other formatting. + 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) + if (type == eHTMLTag_h1 || type == eHTMLTag_h2 || + type == eHTMLTag_h3 || type == eHTMLTag_h4 || + type == eHTMLTag_h5 || type == eHTMLTag_h6) + { + EnsureVerticalSpace(2); + if (mHeaderStrategy == 2) // numbered + { + mIndent += gIndentSizeHeaders; + // Caching + nsCAutoString leadup; + PRInt32 level = HeaderLevel(type); + // Increase counter for current level + mHeaderCounter[level]++; + // Reset all lower levels + PRInt32 i; + for (i = level + 1; i <= 6; i++) + mHeaderCounter[i] = 0; + // Construct numbers + for (i = 1; i <= level; i++) + { + leadup.AppendInt(mHeaderCounter[i]); + leadup += "."; + } + leadup += " "; + Write(NS_ConvertASCIItoUCS2(leadup.GetBuffer())); + } + else if (mHeaderStrategy == 1) // indent increasingly + { + mIndent += gIndentSizeHeaders; + for (PRInt32 i = HeaderLevel(type); i > 1; i--) + // for h(x), run x-1 times + mIndent += gIndentIncrementHeaders; + } + } + else if (type == eHTMLTag_ul) { // Indent here to support nested list, which aren't included in li :-( EnsureVerticalSpace(1); // Must end the current line before we change indent. @@ -612,7 +670,11 @@ nsHTMLToTXTSinkStream::OpenContainer(const nsIParserNode& aNode) mInIndentString.AppendWithConversion(' '); } - else if (type == eHTMLTag_td) + else if (type == eHTMLTag_dl) + EnsureVerticalSpace(1); + else if (type == eHTMLTag_dd) + mIndent += gIndentSizeDD; + else if (type == eHTMLTag_td || type == eHTMLTag_th) { // We must make sure that the content of two table cells get a // space between them. @@ -653,30 +715,39 @@ nsHTMLToTXTSinkStream::OpenContainer(const nsIParserNode& aNode) } else if (type == eHTMLTag_img) { - nsAutoString url; - if (NS_SUCCEEDED(GetValueOfAttribute(aNode, "src", url)) && !url.IsEmpty()) + /* Output (in decreasing order of preference) + alt, title or src (URI) attribute */ + // See + nsAutoString desc, temp; + if (NS_SUCCEEDED(GetValueOfAttribute(aNode, "alt", desc))) { - nsAutoString temp, desc; - if (NS_SUCCEEDED(GetValueOfAttribute(aNode, "alt", desc)) - && !desc.IsEmpty()) + if (!desc.IsEmpty()) { - temp.AppendWithConversion(" ("); + temp.AppendWithConversion(" ["); // Should we output chars at all here? desc.StripChars("\""); temp += desc; - temp.AppendWithConversion(" <"); - url.StripChars("\""); - temp += url; - temp.AppendWithConversion(">) "); + temp.AppendWithConversion(" ]"); } - else - { - temp.AppendWithConversion(" <"); - url.StripChars("\""); - temp += url; - temp.AppendWithConversion("> "); - } - Write(temp); + // If the alt attribute has an empty value (|alt=""|), output nothing } + else if (NS_SUCCEEDED(GetValueOfAttribute(aNode, "title", desc)) + && !desc.IsEmpty()) + { + temp.AppendWithConversion(" ["); + desc.StripChars("\""); + temp += desc; + temp.AppendWithConversion("] "); + } + else if (NS_SUCCEEDED(GetValueOfAttribute(aNode, "src", desc)) + && !desc.IsEmpty()) + { + temp.AppendWithConversion(" <"); + desc.StripChars("\""); + temp += desc; + temp.AppendWithConversion("> "); + } + if (!temp.IsEmpty()) + Write(temp); } else if (type == eHTMLTag_a && !IsConverted(aNode)) { @@ -688,15 +759,21 @@ nsHTMLToTXTSinkStream::OpenContainer(const nsIParserNode& aNode) mURL = url; } } - else if (type == eHTMLTag_sup && !IsConverted(aNode)) + else if (type == eHTMLTag_q) + Write(NS_ConvertASCIItoUCS2("\"")); + else if (type == eHTMLTag_sup && mStructs && !IsConverted(aNode)) Write(NS_ConvertASCIItoUCS2("^")); - else if (type == eHTMLTag_sub && !IsConverted(aNode)) + else if (type == eHTMLTag_sub && mStructs && !IsConverted(aNode)) Write(NS_ConvertASCIItoUCS2("_")); - else if ((type ==eHTMLTag_strong || type==eHTMLTag_b) && !IsConverted(aNode)) + else if (type == eHTMLTag_code && mStructs && !IsConverted(aNode)) + Write(NS_ConvertASCIItoUCS2("|")); + else if ((type == eHTMLTag_strong || type == eHTMLTag_b) + && mStructs && !IsConverted(aNode)) Write(NS_ConvertASCIItoUCS2("*")); - else if ((type == eHTMLTag_em || type == eHTMLTag_i) && !IsConverted(aNode)) + else if ((type == eHTMLTag_em || type == eHTMLTag_i) + && mStructs && !IsConverted(aNode)) Write(NS_ConvertASCIItoUCS2("/")); - else if (type == eHTMLTag_u && !IsConverted(aNode)) + else if (type == eHTMLTag_u && mStructs && !IsConverted(aNode)) Write(NS_ConvertASCIItoUCS2("_")); return NS_OK; @@ -729,6 +806,8 @@ nsHTMLToTXTSinkStream::CloseContainer(const nsIParserNode& aNode) FlushLine(); } else if ((type == eHTMLTag_tr) || (type == eHTMLTag_li) || + (type == eHTMLTag_dt) || + (type == eHTMLTag_dd) || (type == eHTMLTag_pre) || (type == eHTMLTag_blockquote)) { EnsureVerticalSpace(0); @@ -737,7 +816,8 @@ nsHTMLToTXTSinkStream::CloseContainer(const nsIParserNode& aNode) // in formatted mode, otherwise 0. // This is hard. Sometimes 0 is a better number, but // how to know? - EnsureVerticalSpace((mFlags & nsIDocumentEncoder::OutputFormatted) ? 1 : 0); + EnsureVerticalSpace((mFlags & nsIDocumentEncoder::OutputFormatted) + ? 1 : 0); } } @@ -746,7 +826,21 @@ nsHTMLToTXTSinkStream::CloseContainer(const nsIParserNode& aNode) if (!(mFlags & nsIDocumentEncoder::OutputFormatted)) return NS_OK; - if (type == eHTMLTag_ul) + if (type == eHTMLTag_h1 || type == eHTMLTag_h2 || + type == eHTMLTag_h3 || type == eHTMLTag_h4 || + type == eHTMLTag_h5 || type == eHTMLTag_h6) + { + if (mHeaderStrategy /*numbered or indent increasingly*/ ) + mIndent -= gIndentSizeHeaders; + if (mHeaderStrategy == 1 /*indent increasingly*/ ) + { + for (PRInt32 i = HeaderLevel(type); i > 1; i--) + // for h(x), run x-1 times + mIndent -= gIndentIncrementHeaders; + } + EnsureVerticalSpace(1); + } + else if (type == eHTMLTag_ul) { mIndent -= gIndentSizeList; } @@ -756,12 +850,21 @@ nsHTMLToTXTSinkStream::CloseContainer(const nsIParserNode& aNode) --mOLStackIndex; mIndent -= gIndentSizeList; } + else if (type == eHTMLTag_dd) + { + mIndent -= gIndentSizeDD; + } else if (type == eHTMLTag_blockquote) { FlushLine(); - if (mCiteQuoteLevel>0) + nsString value; + nsresult rv = GetValueOfAttribute(aNode, "type", value); + if ( NS_SUCCEEDED(rv) ) + value.StripChars("\""); + + if (NS_SUCCEEDED(rv) && value.EqualsWithConversion("cite", PR_TRUE)) mCiteQuoteLevel--; - else if(mIndent >= gTabSize) + else mIndent -= gTabSize; } else if (type == eHTMLTag_a && !IsConverted(aNode) && !mURL.IsEmpty()) @@ -772,13 +875,20 @@ nsHTMLToTXTSinkStream::CloseContainer(const nsIParserNode& aNode) Write(temp); mURL.Truncate(); } - else if ((type== eHTMLTag_sup || type== eHTMLTag_sub) && !IsConverted(aNode)) + else if (type == eHTMLTag_q) + Write(NS_ConvertASCIItoUCS2("\"")); + else if ((type == eHTMLTag_sup || type == eHTMLTag_sub) + && mStructs && !IsConverted(aNode)) Write(NS_ConvertASCIItoUCS2(" ")); - else if ((type== eHTMLTag_strong || type==eHTMLTag_b) && !IsConverted(aNode)) + else if (type == eHTMLTag_code && mStructs && !IsConverted(aNode)) + Write(NS_ConvertASCIItoUCS2("|")); + else if ((type == eHTMLTag_strong || type == eHTMLTag_b) + && mStructs && !IsConverted(aNode)) Write(NS_ConvertASCIItoUCS2("*")); - else if ((type == eHTMLTag_em || type == eHTMLTag_i) && !IsConverted(aNode)) + else if ((type == eHTMLTag_em || type == eHTMLTag_i) + && mStructs && !IsConverted(aNode)) Write(NS_ConvertASCIItoUCS2("/")); - else if (type == eHTMLTag_u && !IsConverted(aNode)) + else if (type == eHTMLTag_u && mStructs && !IsConverted(aNode)) Write(NS_ConvertASCIItoUCS2("_")); return NS_OK; @@ -887,6 +997,7 @@ nsHTMLToTXTSinkStream::AddLeaf(const nsIParserNode& aNode) EnsureVerticalSpace(0); // Make a line of dashes as wide as the wrap width + // XXX honoring percentage would be nice nsAutoString line; PRUint32 width = (mWrapColumn > 0 ? mWrapColumn : 25); while (line.Length() < width) @@ -1483,20 +1594,23 @@ PRBool IsInline(eHTMLTags aTag) { case eHTMLTag_a: case eHTMLTag_address: + case eHTMLTag_b: case eHTMLTag_big: case eHTMLTag_blink: - case eHTMLTag_b: case eHTMLTag_br: case eHTMLTag_cite: case eHTMLTag_code: case eHTMLTag_dfn: + case eHTMLTag_del: case eHTMLTag_em: case eHTMLTag_font: - case eHTMLTag_img: case eHTMLTag_i: + case eHTMLTag_img: + case eHTMLTag_ins: case eHTMLTag_kbd: case eHTMLTag_keygen: case eHTMLTag_nobr: + case eHTMLTag_q: case eHTMLTag_samp: case eHTMLTag_small: case eHTMLTag_spacer: @@ -1507,6 +1621,7 @@ PRBool IsInline(eHTMLTags aTag) case eHTMLTag_sup: case eHTMLTag_td: case eHTMLTag_textarea: + case eHTMLTag_th: case eHTMLTag_tt: case eHTMLTag_u: case eHTMLTag_var: @@ -1523,6 +1638,36 @@ PRBool IsInline(eHTMLTags aTag) PRBool IsBlockLevel(eHTMLTags aTag) { return !IsInline(aTag); + /* XXX Note: We output linebreaks for blocks. + I.e. we output linebreaks for "unknown" inline tags. + I just hunted such a bug for , same for , etc.. + Better fallback to inline. /BenB */ +} + +/* + @return 0 = no header, 1 = h1, ..., 6 = h6 +*/ +PRInt32 HeaderLevel(eHTMLTags aTag) +{ + PRInt32 result; + switch (aTag) + { + case eHTMLTag_h1: + result = 1; break; + case eHTMLTag_h2: + result = 2; break; + case eHTMLTag_h3: + result = 3; break; + case eHTMLTag_h4: + result = 4; break; + case eHTMLTag_h5: + result = 5; break; + case eHTMLTag_h6: + result = 6; break; + default: + result = 0; break; + } + return result; } PRBool nsHTMLToTXTSinkStream::MayWrap() diff --git a/mozilla/parser/htmlparser/src/nsHTMLToTXTSinkStream.h b/mozilla/parser/htmlparser/src/nsHTMLToTXTSinkStream.h index c544b0e5a93..eb7ded47e6e 100644 --- a/mozilla/parser/htmlparser/src/nsHTMLToTXTSinkStream.h +++ b/mozilla/parser/htmlparser/src/nsHTMLToTXTSinkStream.h @@ -189,6 +189,17 @@ protected: PRBool mStartedOutput; // we've produced at least a character nsString mURL; + PRInt32 mStructs; // Output structs (pref) + PRBool mHeaderStrategy; /* Header strategy (pref) + 0 = no indention + 1 = indention, increased with + header level (default) + 2 = numbering and slight indention */ + PRInt32 mHeaderCounter[7]; /* For header-numbering: + Number of previous headers of + the same depth and in the same + section. + mHeaderCounter[1] for

etc. */ // The tag stack: the stack of tags we're operating on, so we can nest: nsHTMLTag *mTagStack; diff --git a/mozilla/parser/htmlparser/tests/outsinks/simplefmt.out b/mozilla/parser/htmlparser/tests/outsinks/simplefmt.out index 8848438c595..030a38c7192 100644 --- a/mozilla/parser/htmlparser/tests/outsinks/simplefmt.out +++ b/mozilla/parser/htmlparser/tests/outsinks/simplefmt.out @@ -1,5 +1,6 @@ -Simple html page + Simple html page + Here is a link to the mozilla.org page. Here is some _underlined and *bold*ened_ified text plus some .