Bug 1066515 - Part 1: Set selection range directly when replacing within current text node. r=yxl
authorTing-Yu Chou <janus926@gmail.com>
Fri, 03 Oct 2014 14:09:53 +0800
changeset 234112 f589902d878343e52b2acfed6b07128aba4138be
parent 234111 c5a41dac572942ed2c1ed14d218529852477c305
child 234113 986b480432804bee64cb9c8bd75bb01f22ade9c8
push id611
push userraliiev@mozilla.com
push dateMon, 05 Jan 2015 23:23:16 +0000
treeherdermozilla-release@345cd3b9c445 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersyxl
bugs1066515
milestone35.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 1066515 - Part 1: Set selection range directly when replacing within current text node. r=yxl
dom/inputmethod/forms.js
--- a/dom/inputmethod/forms.js
+++ b/dom/inputmethod/forms.js
@@ -580,21 +580,18 @@ let FormAssistant = {
           });
         }
         break;
       }
 
       case "Forms:ReplaceSurroundingText": {
         CompositionManager.endComposition('');
 
-        let selectionRange = getSelectionRange(target);
         if (!replaceSurroundingText(target,
                                     json.text,
-                                    selectionRange[0],
-                                    selectionRange[1],
                                     json.offset,
                                     json.length)) {
           if (json.requestId) {
             sendAsyncMessage("Forms:ReplaceSurroundingText:Result:Error", {
               requestId: json.requestId,
               error: "failed"
             });
           }
@@ -1134,41 +1131,60 @@ function getPlaintextEditor(element) {
     }
   }
   if (editor) {
     editor.QueryInterface(Ci.nsIPlaintextEditor);
   }
   return editor;
 }
 
-function replaceSurroundingText(element, text, selectionStart, selectionEnd,
-                                offset, length) {
+function replaceSurroundingText(element, text, offset, length) {
   let editor = FormAssistant.editor;
   if (!editor) {
     return false;
   }
 
   // Check the parameters.
-  let start = selectionStart + offset;
-  if (start < 0) {
-    start = 0;
-  }
   if (length < 0) {
     length = 0;
   }
-  let end = start + length;
 
-  if (selectionStart != start || selectionEnd != end) {
-    // Change selection range before replacing.
-    if (!setSelectionRange(element, start, end)) {
-      return false;
+  // Change selection range before replacing. For content editable element,
+  // searching the node for setting selection range is not needed when the
+  // selection is collapsed within a text node.
+  let fastPathHit = false;
+  if (!isPlainTextField(element)) {
+    let sel = element.ownerDocument.defaultView.getSelection();
+    let node = sel.anchorNode;
+    if (sel.isCollapsed && node && node.nodeType == 3 /* TEXT_NODE */) {
+      let start = sel.anchorOffset + offset;
+      let end = start + length;
+      // Fallback to setSelectionRange() if the replacement span multiple nodes.
+      if (start >= 0 && end <= node.textContent.length) {
+        fastPathHit = true;
+        sel.collapse(node, start);
+        sel.extend(node, end);
+      }
+    }
+  }
+  if (!fastPathHit) {
+    let range = getSelectionRange(element);
+    let start = range[0] + offset;
+    if (start < 0) {
+      start = 0;
+    }
+    let end = start + length;
+    if (start != range[0] || end != range[1]) {
+      if (!setSelectionRange(element, start, end)) {
+        return false;
+      }
     }
   }
 
-  if (start != end) {
+  if (length) {
     // Delete the selected text.
     editor.deleteSelection(Ci.nsIEditor.ePrevious, Ci.nsIEditor.eStrip);
   }
 
   if (text) {
     // We don't use CR but LF
     // see https://bugzilla.mozilla.org/show_bug.cgi?id=902847
     text = text.replace(/\r/g, '\n');