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 idunknown
push userunknown
push dateunknown
reviewersroc, dbaron
bugs240933
milestone2.0b6pre
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