Bug 1125963 - Part 1: Fix serialization of the pre-wrap elements that Thunderbird relies on. r=bzbarsky, a=lmandel
authorEhsan Akhgari <ehsan@mozilla.com>
Thu, 26 Feb 2015 15:26:12 -0500
changeset 250257 50aed8247f5c
parent 250256 e969067d440d
child 250258 151a86ff6ae8
push id4527
push userryanvm@gmail.com
push date2015-03-05 16:09 +0000
treeherdermozilla-beta@00bad6e2ffbc [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbzbarsky, lmandel
bugs1125963
milestone37.0
Bug 1125963 - Part 1: Fix serialization of the pre-wrap elements that Thunderbird relies on. r=bzbarsky, a=lmandel This ensures that the plaintext serializer doesn't use the preformatted text code path if we have encountered a pre-wrap element that Thunderbird uses (which means setting white-space: pre-wrap and width: NNch on the body element.) It also ensures that we use 0 as the wrap column number passed down to the plaintext serializer, instead of -1, which this code seems to be unable to handle properly.
dom/base/nsPlainTextSerializer.cpp
dom/base/test/TestPlainTextSerializer.cpp
dom/html/HTMLInputElement.cpp
dom/html/HTMLTextAreaElement.cpp
dom/html/nsTextEditorState.cpp
--- a/dom/base/nsPlainTextSerializer.cpp
+++ b/dom/base/nsPlainTextSerializer.cpp
@@ -1551,24 +1551,24 @@ nsPlainTextSerializer::Write(const nsASt
       else
         break;
     }
   }
 
   // We have two major codepaths here. One that does preformatted text and one
   // that does normal formatted text. The one for preformatted text calls
   // Output directly while the other code path goes through AddToLine.
-  if ((mPreFormatted && !mWrapColumn) || IsInPre()
+  if ((mPreFormatted && !mWrapColumn) || (IsInPre() && !mPreFormatted)
       || ((mSpanLevel > 0 || mDontWrapAnyQuotes)
           && mEmptyLines >= 0 && str.First() == char16_t('>'))) {
     // No intelligent wrapping.
 
     // This mustn't be mixed with intelligent wrapping without clearing
     // the mCurrentLine buffer before!!!
-    NS_ASSERTION(mCurrentLine.IsEmpty() || IsInPre(),
+    NS_ASSERTION(mCurrentLine.IsEmpty() || (IsInPre() && !mPreFormatted),
                  "Mixed wrapping data and nonwrapping data on the same line");
     if (!mCurrentLine.IsEmpty()) {
       FlushLine();
     }
 
     // Put the mail quote "> " chars in, if appropriate.
     // Have to put it in before every line.
     while(bol<totLen) {
--- a/dom/base/test/TestPlainTextSerializer.cpp
+++ b/dom/base/test/TestPlainTextSerializer.cpp
@@ -158,16 +158,49 @@ TestBlockElement()
     return NS_ERROR_FAILURE;
   }
 
   passed("prettyprinted HTML to text serialization test");
   return NS_OK;
 }
 
 nsresult
+TestPreWrapElementForThunderbird()
+{
+  // This test examines the magic pre-wrap setup that Thunderbird relies on.
+  nsString test;
+  test.AppendLiteral(
+    "<html>" NS_LINEBREAK
+    "<body style=\"white-space: pre-wrap; width: 10ch;\">" NS_LINEBREAK
+    "<pre>" NS_LINEBREAK
+    "  first line is too long" NS_LINEBREAK
+    "  second line is even loooonger  " NS_LINEBREAK
+    "</pre>" NS_LINEBREAK
+    "</body>" NS_LINEBREAK "</html>");
+
+  ConvertBufToPlainText(test, nsIDocumentEncoder::OutputWrap);
+  // "\n\n  first\nline is\ntoo long\n  second\nline is\neven\nloooonger\n\n\n"
+  if (!test.EqualsLiteral(NS_LINEBREAK NS_LINEBREAK
+                          "  first" NS_LINEBREAK
+                          "line is" NS_LINEBREAK
+                          "too long" NS_LINEBREAK
+                          "  second" NS_LINEBREAK
+                          "line is" NS_LINEBREAK
+                          "even" NS_LINEBREAK
+                          "loooonger" NS_LINEBREAK
+                          NS_LINEBREAK NS_LINEBREAK)) {
+    fail("Wrong prettyprinted html to text serialization");
+    return NS_ERROR_FAILURE;
+  }
+
+  passed("prettyprinted HTML to text serialization test");
+  return NS_OK;
+}
+
+nsresult
 TestPlainTextSerializer()
 {
   nsString test;
   test.AppendLiteral("<html><base>base</base><head><span>span</span></head>"
                      "<body>body</body></html>");
   ConvertBufToPlainText(test, 0);
   if (!test.EqualsLiteral("basespanbody")) {
     fail("Wrong html to text serialization");
@@ -186,16 +219,19 @@ TestPlainTextSerializer()
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = TestPreElement();
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = TestBlockElement();
   NS_ENSURE_SUCCESS(rv, rv);
 
+  rv = TestPreWrapElementForThunderbird();
+  NS_ENSURE_SUCCESS(rv, rv);
+
   // Add new tests here...
   return NS_OK;
 }
 
 int main(int argc, char** argv)
 {
   ScopedXPCOM xpcom("PlainTextSerializer");
   if (xpcom.failed())
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -7163,17 +7163,17 @@ HTMLInputElement::GetCols()
   }
 
   return DEFAULT_COLS;
 }
 
 NS_IMETHODIMP_(int32_t)
 HTMLInputElement::GetWrapCols()
 {
-  return -1; // only textarea's can have wrap cols
+  return 0; // only textarea's can have wrap cols
 }
 
 NS_IMETHODIMP_(int32_t)
 HTMLInputElement::GetRows()
 {
   return DEFAULT_ROWS;
 }
 
--- a/dom/html/HTMLTextAreaElement.cpp
+++ b/dom/html/HTMLTextAreaElement.cpp
@@ -1467,17 +1467,17 @@ HTMLTextAreaElement::GetCols()
 NS_IMETHODIMP_(int32_t)
 HTMLTextAreaElement::GetWrapCols()
 {
   // wrap=off means -1 for wrap width no matter what cols is
   nsHTMLTextWrap wrapProp;
   nsITextControlElement::GetWrapPropertyEnum(this, wrapProp);
   if (wrapProp == nsITextControlElement::eHTMLTextWrap_Off) {
     // do not wrap when wrap=off
-    return -1;
+    return 0;
   }
 
   // Otherwise we just wrap at the given number of columns
   return GetCols();
 }
 
 
 NS_IMETHODIMP_(int32_t)
--- a/dom/html/nsTextEditorState.cpp
+++ b/dom/html/nsTextEditorState.cpp
@@ -1707,17 +1707,17 @@ nsTextEditorState::InitializeRootNode()
   mRootNode->SetFlags(NODE_IS_EDITABLE);
 
   // Set the necessary classes on the text control. We use class values
   // instead of a 'style' attribute so that the style comes from a user-agent
   // style sheet and is still applied even if author styles are disabled.
   nsAutoString classValue;
   classValue.AppendLiteral("anonymous-div");
   int32_t wrapCols = GetWrapCols();
-  if (wrapCols >= 0) {
+  if (wrapCols > 0) {
     classValue.AppendLiteral(" wrap");
   }
   if (!IsSingleLineTextControl()) {
     // We can't just inherit the overflow because setting visible overflow will
     // crash when the number of lines exceeds the height of the textarea and
     // setting -moz-hidden-unscrollable overflow (NS_STYLE_OVERFLOW_CLIP)
     // doesn't paint the caret for some reason.
     const nsStyleDisplay* disp = mBoundFrame->StyleDisplay();