Bug 1119503 - Part 2: Insert a line break between preformatted block boundaries when creating raw output; r=bzbarsky
☠☠ backed out by b2b10231606b ☠ ☠
authorEhsan Akhgari <ehsan@mozilla.com>
Sat, 17 Jan 2015 17:31:59 -0500
changeset 254854 ff9012ee428a7de3ab2fa3c28ad30c36895888b6
parent 254853 af9f4a6a7b78ea51ad419708bf78e8368c6394a8
child 254855 8c2129ff88976e02da6b3ce53fc6a09ceb93d0e1
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
bugs1119503
milestone38.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1119503 - Part 2: Insert a line break between preformatted block boundaries when creating raw output; r=bzbarsky
dom/base/nsCopySupport.cpp
dom/base/nsIDocumentEncoder.idl
dom/base/nsPlainTextSerializer.cpp
dom/base/nsPlainTextSerializer.h
dom/base/test/test_bug116083.html
--- a/dom/base/nsCopySupport.cpp
+++ b/dom/base/nsCopySupport.cpp
@@ -92,17 +92,18 @@ SelectionCopyHelper(nsISelection *aSel, 
   // is. if it is a selection into input/textarea element or in a html content
   // with pre-wrap style : text/plain. Otherwise text/html.
   // see nsHTMLCopyEncoder::SetSelection
   nsAutoString mimeType;
   mimeType.AssignLiteral(kUnicodeMime);
 
   // Do the first and potentially trial encoding as preformatted and raw.
   uint32_t flags = aFlags | nsIDocumentEncoder::OutputPreformatted
-                          | nsIDocumentEncoder::OutputRaw;
+                          | nsIDocumentEncoder::OutputRaw
+                          | nsIDocumentEncoder::OutputForPlainTextClipboardCopy;
 
   nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(aDoc);
   NS_ASSERTION(domDoc, "Need a document");
 
   rv = docEncoder->Init(domDoc, mimeType, flags);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = docEncoder->SetSelection(aSel);
--- a/dom/base/nsIDocumentEncoder.idl
+++ b/dom/base/nsIDocumentEncoder.idl
@@ -223,16 +223,23 @@ interface nsIDocumentEncoder : nsISuppor
   const unsigned long OutputNonTextContentAsPlaceholder = (1 << 23);
 
   /**
    * Don't Strip ending spaces from a line (only for serializing to plaintext).
    */
   const unsigned long OutputDontRemoveLineEndingSpaces = (1 << 24);
 
   /**
+   * Serialize in a way that is suitable for copying a plaintext version of the
+   * document to the clipboard.  This can for example cause line endings to be
+   * injected at preformatted block element boundaries.
+   */
+  const unsigned long OutputForPlainTextClipboardCopy = (1 << 25);
+
+  /**
    * Initialize with a pointer to the document and the mime type.
    * @param aDocument Document to encode.
    * @param aMimeType MimeType to use. May also be set by SetMimeType.
    * @param aFlags Flags to use while encoding. May also be set by SetFlags.
    */
   void init(in nsIDOMDocument aDocument,
             in AString aMimeType,
             in unsigned long aFlags);
--- a/dom/base/nsPlainTextSerializer.cpp
+++ b/dom/base/nsPlainTextSerializer.cpp
@@ -86,16 +86,18 @@ nsPlainTextSerializer::nsPlainTextSerial
   mCurrentLineWidth = 0;
 
   // Flow
   mEmptyLines = 1; // The start of the document is an "empty line" in itself,
   mInWhitespace = false;
   mPreFormatted = false;
   mStartedOutput = false;
 
+  mPreformattedBlockBoundary = false;
+
   // initialize the tag stack to zero:
   // The stack only ever contains pointers to static atoms, so they don't
   // need refcounting.
   mTagStack = new nsIAtom*[TagStackSize];
   mTagStackIndex = 0;
   mIgnoreAboveIndex = (uint32_t)kNotFound;
 
   // initialize the OL stack, where numbers for ordered lists are kept
@@ -162,16 +164,18 @@ nsPlainTextSerializer::Init(uint32_t aFl
   else {
     // Platform/default
     mLineBreak.AssignLiteral(NS_LINEBREAK);
   }
 
   mLineBreakDue = false;
   mFloatingLines = -1;
 
+  mPreformattedBlockBoundary = false;
+
   if (mFlags & nsIDocumentEncoder::OutputFormatted) {
     // Get some prefs that controls how we do formatted output
     mStructs = Preferences::GetBool(PREF_STRUCTS, mStructs);
 
     mHeaderStrategy =
       Preferences::GetInt(PREF_HEADER_STRATEGY, mHeaderStrategy);
 
     // DontWrapAnyQuotes is set according to whether plaintext mail
@@ -432,16 +436,26 @@ nsPlainTextSerializer::DoOpenContainer(n
       // Serialize current node as placeholder character
       Write(NS_LITERAL_STRING("\xFFFC"));
     }
     // Ignore child nodes.
     mIgnoredChildNodeLevel++;
     return NS_OK;
   }
 
+  if (mFlags & nsIDocumentEncoder::OutputForPlainTextClipboardCopy) {
+    if (mPreformattedBlockBoundary && DoOutput()) {
+      // Should always end a line, but get no more whitespace
+      if (mFloatingLines < 0)
+        mFloatingLines = 0;
+      mLineBreakDue = true;
+    }
+    mPreformattedBlockBoundary = false;
+  }
+
   if (mFlags & nsIDocumentEncoder::OutputRaw) {
     // Raw means raw.  Don't even think about doing anything fancy
     // here like indenting, adding line breaks or any other
     // characters such as list item bullets, quote characters
     // around <q>, etc.  I mean it!  Don't make me smack you!
 
     return NS_OK;
   }
@@ -762,16 +776,24 @@ nsPlainTextSerializer::DoOpenContainer(n
 nsresult
 nsPlainTextSerializer::DoCloseContainer(nsIAtom* aTag)
 {
   if (ShouldReplaceContainerWithPlaceholder(mElement->Tag())) {
     mIgnoredChildNodeLevel--;
     return NS_OK;
   }
 
+  if (mFlags & nsIDocumentEncoder::OutputForPlainTextClipboardCopy) {
+    if (DoOutput() && IsInPre() && IsElementBlock(mElement)) {
+      // If we're closing a preformatted block element, output a line break
+      // when we find a new container.
+      mPreformattedBlockBoundary = true;
+    }
+  }
+
   if (mFlags & nsIDocumentEncoder::OutputRaw) {
     // Raw means raw.  Don't even think about doing anything fancy
     // here like indenting, adding line breaks or any other
     // characters such as list item bullets, quote characters
     // around <q>, etc.  I mean it!  Don't make me smack you!
 
     return NS_OK;
   }
@@ -1031,16 +1053,18 @@ nsPlainTextSerializer::DoAddText(bool aI
     mURL.Truncate();
   }
   Write(aText);
 }
 
 nsresult
 nsPlainTextSerializer::DoAddLeaf(nsIAtom* aTag)
 {
+  mPreformattedBlockBoundary = false;
+
   // If we don't want any output, just return
   if (!DoOutput()) {
     return NS_OK;
   }
 
   if (mLineBreakDue)
     EnsureVerticalSpace(mFloatingLines);
 
--- a/dom/base/nsPlainTextSerializer.h
+++ b/dom/base/nsPlainTextSerializer.h
@@ -165,17 +165,19 @@ private:
 
   bool             mInWhitespace;
   bool             mPreFormatted;
   bool             mStartedOutput; // we've produced at least a character
 
   // While handling a new tag, this variable should remind if any line break
   // is due because of a closing tag. Setting it to "TRUE" while closing the tags.
   // Hence opening tags are guaranteed to start with appropriate line breaks.
-  bool             mLineBreakDue; 
+  bool             mLineBreakDue;
+
+  bool             mPreformattedBlockBoundary;
 
   nsString         mURL;
   int32_t          mHeaderStrategy;    /* Header strategy (pref)
                                           0 = no indention
                                           1 = indention, increased with
                                               header level (default)
                                           2 = numbering and slight indention */
   int32_t          mHeaderCounter[7];  /* For header-numbering:
--- a/dom/base/test/test_bug116083.html
+++ b/dom/base/test/test_bug116083.html
@@ -15,16 +15,24 @@ https://bugzilla.mozilla.org/show_bug.cg
 <div style="white-space: pre">foo  bar</div>
 <div style="white-space: pre-wrap">foo  bar</div>
 <div style="white-space: pre-line">foo  bar</div>
 <div style="white-space: -moz-pre-space">foo  bar</div>
 <div data-result="bar  baz"><span style="white-space: pre">bar  </span>baz</div>
 <div data-result="bar  baz"><span style="white-space: pre-wrap">bar  </span>baz</div>
 <div data-result="bar  baz"><span style="white-space: pre-line">bar  </span>baz</div>
 <div data-result="bar  baz"><span style="white-space: -moz-pre-space">bar  </span>baz</div>
+<div data-result="foo  &#10;  bar&#10;&#10;!&#10;&#10;&#10;baz" style="white-space: pre"><div>foo  </div><div>  bar</div><div><br></div><div>!</div><div><br><br></div><div>baz</div></div>
+<div data-result="foo &#10; bar&#10;&#10;!&#10;&#10;&#10;baz" style="white-space: pre" contenteditable><div>foo </div><div> bar</div><div><br></div><div>!</div><div><br><br></div><div>baz</div></div>
+<div data-result="foo  &#10;  bar&#10;&#10;!&#10;&#10;&#10;baz" style="white-space: pre-wrap"><div>foo  </div><div>  bar</div><div><br></div><div>!</div><div><br><br></div><div>baz</div></div>
+<div data-result="foo &#10; bar&#10;&#10;!&#10;&#10;&#10;baz" style="white-space: pre-wrap" contenteditable><div>foo </div><div> bar</div><div><br></div><div>!</div><div><br><br></div><div>baz</div></div>
+<div data-result="foo  &#10;  bar&#10;&#10;!&#10;&#10;&#10;baz" style="white-space: pre-line"><div>foo  </div><div>  bar</div><div><br></div><div>!</div><div><br><br></div><div>baz</div></div>
+<div data-result="foo &#10; bar&#10;&#10;!&#10;&#10;&#10;baz" style="white-space: pre-line" contenteditable><div>foo </div><div> bar</div><div><br></div><div>!</div><div><br><br></div><div>baz</div></div>
+<div data-result="foo  &#10;  bar&#10;&#10;!&#10;&#10;&#10;baz" style="white-space: -moz-pre-space"><div>foo  </div><div>  bar</div><div><br></div><div>!</div><div><br><br></div><div>baz</div></div>
+<div data-result="foo &#10; bar&#10;&#10;!&#10;&#10;&#10;baz" style="white-space: -moz-pre-space" contenteditable><div>foo </div><div> bar</div><div><br></div><div>!</div><div><br><br></div><div>baz</div></div>
 <div data-result="&#10;foo bar&#10;">foo  bar</div>
 </div>
 <script type="application/javascript">
 
 SimpleTest.waitForExplicitFinish();
 SimpleTest.waitForFocus(function nextTest() {
   var div = document.querySelector("#content>div");
   if (!div) {