Bug 240933 - Part 1: Do not split multiline text into textframes separated by BR elements; r=roc a=dbaron
authorEhsan Akhgari <ehsan@mozilla.com>
Sun, 11 Jul 2010 16:26:26 -0400
changeset 51902 b73bb8fcce79b39da8ec7f1b3315828817885ea0
parent 51901 01cbf9182f77e2b5e470743441c47c6c14bdb938
child 51903 612cf52bab79f515c6b1d06a666c1eebf5fa3ec0
push id15468
push usereakhgari@mozilla.com
push dateThu, 02 Sep 2010 19:10:57 +0000
treeherdermozilla-central@f2f217290bd0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc, dbaron
bugs240933
milestone2.0b6pre
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 240933 - Part 1: Do not split multiline text into textframes separated by BR elements; r=roc a=dbaron
editor/libeditor/text/nsTextEditRules.cpp
layout/reftests/editor/caret_on_textarea_lastline-ref.html
layout/reftests/editor/caret_on_textarea_lastline.html
layout/reftests/editor/reftest.list
--- a/editor/libeditor/text/nsTextEditRules.cpp
+++ b/editor/libeditor/text/nsTextEditRules.cpp
@@ -751,93 +751,30 @@ nsTextEditRules::WillInsertText(PRInt32 
     // is our text going to be PREformatted?  
     // We remember this so that we know how to handle tabs.
     PRBool isPRE;
     res = mEditor->IsPreformatted(selNode, &isPRE);
     NS_ENSURE_SUCCESS(res, res);    
 
     // don't spaz my selection in subtransactions
     nsAutoTxnsConserveSelection dontSpazMySelection(mEditor);
-    nsString tString(*outString);
-    const PRUnichar *unicodeBuf = tString.get();
-    nsCOMPtr<nsIDOMNode> unused;
-    PRInt32 pos = 0;
 
-    // for efficiency, break out the pre case separately.  This is because
-    // it's a lot cheaper to search the input string for only newlines than
-    // it is to search for both tabs and newlines.
     if (isPRE)
     {
-      while (unicodeBuf && (pos != -1) && ((PRUint32)pos < tString.Length()))
-      {
-        PRInt32 oldPos = pos;
-        PRInt32 subStrLen;
-        pos = tString.FindChar(nsCRT::LF, oldPos);
-        
-        if (pos != -1) 
-        {
-          subStrLen = pos - oldPos;
-          // if first char is newline, then use just it
-          if (subStrLen == 0)
-            subStrLen = 1;
-        }
-        else
-        {
-          subStrLen = tString.Length() - oldPos;
-          pos = tString.Length();
-        }
-
-        nsDependentSubstring subStr(tString, oldPos, subStrLen);
-        
-        // is it a return?
-        if (subStr.EqualsLiteral(LFSTR))
-        {
-          if (IsSingleLineEditor())
-          {
-            NS_ASSERTION((mEditor->mNewlineHandling == nsIPlaintextEditor::eNewlinesPasteIntact),
-                  "Newline improperly getting into single-line edit field!");
-            res = mEditor->InsertTextImpl(subStr, address_of(curNode), &curOffset, doc);
-          }
-          else
-          {
-            res = mEditor->CreateBRImpl(address_of(curNode), &curOffset, address_of(unused), nsIEditor::eNone);
-
-            // If the newline is the last character in the string, and the BR we
-            // just inserted is the last node in the content tree, we need to add
-            // a mozBR so that a blank line is created.
-
-            if (NS_SUCCEEDED(res) && curNode && pos == (PRInt32)(tString.Length() - 1))
-            {
-              nsCOMPtr<nsIDOMNode> nextChild = mEditor->GetChildAt(curNode, curOffset);
-
-              if (!nextChild)
-              {
-                // We must be at the end since there isn't a nextChild.
-                //
-                // curNode and curOffset should be set to the position after
-                // the BR we added above, so just create a mozBR at that position.
-                //
-                // Note that we don't update curOffset after we've created/inserted
-                // the mozBR since we never want the selection to be placed after it.
-
-                res = CreateMozBR(curNode, curOffset, address_of(unused));
-              }
-            }
-          }
-          pos++;
-        }
-        else
-        {
-          res = mEditor->InsertTextImpl(subStr, address_of(curNode), &curOffset, doc);
-        }
-        NS_ENSURE_SUCCESS(res, res);
-      }
+      res = mEditor->InsertTextImpl(*outString, address_of(curNode),
+                                    &curOffset, doc);
+      NS_ENSURE_SUCCESS(res, res);
     }
     else
     {
+      const nsString& tString = PromiseFlatString(*outString);
+      const PRUnichar *unicodeBuf = tString.get();
+      nsCOMPtr<nsIDOMNode> unused;
+      PRInt32 pos = 0;
+
       char specialChars[] = {TAB, nsCRT::LF, 0};
       while (unicodeBuf && (pos != -1) && ((PRUint32)pos < tString.Length()))
       {
         PRInt32 oldPos = pos;
         PRInt32 subStrLen;
         pos = tString.FindCharInSet(specialChars, oldPos);
         
         if (pos != -1) 
@@ -868,28 +805,38 @@ nsTextEditRules::WillInsertText(PRInt32 
           pos++;
         }
         else
         {
           res = mEditor->InsertTextImpl(subStr, address_of(curNode), &curOffset, doc);
         }
         NS_ENSURE_SUCCESS(res, res);
       }
+      outString->Assign(tString);
     }
-    outString->Assign(tString);
 
     if (curNode) 
     {
-      aSelection->Collapse(curNode, curOffset);
-      
       // Make the caret attach to the inserted text, unless this text ends with a LF, 
       // in which case make the caret attach to the next line.
-      PRBool endsWithLF = !tString.IsEmpty() && tString.get()[tString.Length() - 1] == nsCRT::LF;
+      PRBool endsWithLF =
+        !outString->IsEmpty() && outString->Last() == nsCRT::LF;
       nsCOMPtr<nsISelectionPrivate>selPrivate(do_QueryInterface(aSelection));
       selPrivate->SetInterlinePosition(endsWithLF);
+
+      // If the last character is a linefeed character, make sure that we inject
+      // a BR element for correct caret positioning.
+      if (endsWithLF) {
+        nsCOMPtr<nsIDOMNode> mozBR;
+        res = CreateMozBR(curNode, curOffset, address_of(mozBR));
+        NS_ENSURE_SUCCESS(res, res);
+        curNode = mozBR;
+        curOffset = 0;
+      }
+      aSelection->Collapse(curNode, curOffset);
     }
   }
   ASSERT_PASSWORD_LENGTHS_EQUAL()
   return res;
 }
 
 nsresult
 nsTextEditRules::DidInsertText(nsISelection *aSelection, 
new file mode 100644
--- /dev/null
+++ b/layout/reftests/editor/caret_on_textarea_lastline-ref.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<html>
+<body onload="document.querySelector('textarea').focus();">
+<textarea>foo</textarea>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/editor/caret_on_textarea_lastline.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<html>
+<body onload="document.querySelector('textarea').focus();">
+<textarea>foo
+</textarea>
+</body>
+</html>
--- a/layout/reftests/editor/reftest.list
+++ b/layout/reftests/editor/reftest.list
@@ -13,8 +13,9 @@ include xul/reftest.list
 == passwd-1.html passwd-ref.html
 != passwd-2.html passwd-ref.html
 == passwd-3.html passwd-ref.html
 == passwd-4.html passwd-ref.html
 == emptypasswd-1.html emptypasswd-ref.html
 == emptypasswd-2.html emptypasswd-ref.html
 == caret_on_positioned.html caret_on_positioned-ref.html
 == spellcheck-1.html spellcheck-ref.html
+!= caret_on_textarea_lastline.html caret_on_textarea_lastline-ref.html