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 259174 a7b9fbe30a22321c273d638e3c1e2891e462066e
parent 259173 3cc4e56ab9ad7acdd07b3a5d50808f0f43004985
child 259175 1b4d785e0473f78a859839d3ece1a04fef5bd1c9
push id721
push userjlund@mozilla.com
push dateTue, 21 Apr 2015 23:03:33 +0000
treeherdermozilla-release@d27c9211ebb3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbzbarsky, lmandel
bugs1125963
milestone38.0a2
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
@@ -7214,17 +7214,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
@@ -1475,17 +1475,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
@@ -1708,17 +1708,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();