Bug 848594 - Reorganize code related to text input selection management in SelectionHandler. r=mbrubeck
authorJim Mathies <jmathies@mozilla.com>
Mon, 25 Mar 2013 15:54:49 -0500
changeset 126167 12a599069db2cddace0484385d77899903729691
parent 126166 9592881ee7fc25730e65421849074701a66921eb
child 126168 6d94c44aa4d23d98a13c1e364fc6734f54543f99
push id24477
push userryanvm@gmail.com
push dateTue, 26 Mar 2013 14:07:34 +0000
treeherdermozilla-central@8d09f003e087 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmbrubeck
bugs848594
milestone22.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 848594 - Reorganize code related to text input selection management in SelectionHandler. r=mbrubeck
browser/metro/base/content/contenthandlers/SelectionHandler.js
--- a/browser/metro/base/content/contenthandlers/SelectionHandler.js
+++ b/browser/metro/base/content/contenthandlers/SelectionHandler.js
@@ -40,17 +40,16 @@ var SelectionHandler = {
   _debugEvents: false,
   _cache: {},
   _targetElement: null,
   _targetIsEditable: false,
   _contentWindow: null,
   _contentOffset: { x:0, y:0 },
   _domWinUtils: null,
   _selectionMoveActive: false,
-  _lastMarker: "",
   _debugOptions: { dumpRanges: false, displayRanges: false },
   _snap: true,
 
   init: function init() {
     addMessageListener("Browser:SelectionStart", this);
     addMessageListener("Browser:SelectionAttach", this);
     addMessageListener("Browser:SelectionEnd", this);
     addMessageListener("Browser:SelectionMoveStart", this);
@@ -589,81 +588,87 @@ var SelectionHandler = {
     }
 
     // We expect continuous selection ranges.
     if (selection.rangeCount > 1) {
       this._setContinuousSelection();
     }
 
     // Adjust our y position up such that we are sending coordinates on
-    // the text line vs. below it where the monocle is positioned. This
-    // applies to free floating text areas. For text inputs we'll constrain
-    // coordinates further below.
+    // the text line vs. below it where the monocle is positioned.
     let halfLineHeight = this._queryHalfLineHeight(aMarker, selection);
     clientPoint.yPos -= halfLineHeight;
 
+    // Modify selection based on monocle movement
     if (this._targetIsEditable) {
-      // Check to see if we are beyond the bounds of selection in a input
-      // control. If we are we want to add selection and scroll the added
-      // selection into view.
-      let result = this.updateTextEditSelection(clientPoint);
-
-      // If we're targeting a text input of any kind, make sure clientPoint
-      // is contained within the bounds of the text control. For example, if
-      // a user drags up too close to an upper bounds, selectAtPoint might
-      // select the content above the control. This looks crappy and breaks
-      // our selection rect management.
-      clientPoint =
-       this._constrainPointWithinControl(clientPoint, halfLineHeight);
-
-      // If result.trigger is true, the monocle is outside the bounds of the
-      // control. If it's false, fall through to our additive text selection
-      // below.
-      if (result.trigger) {
-        // _handleSelectionPoint is triggered by input movement, so if we've
-        // tested positive for out-of-bounds scrolling here, we need to set a
-        // recurring timer to keep the expected selection behavior going as
-        // long as the user keeps the monocle out of bounds.
-        if (!this._scrollTimer)
-          this._scrollTimer = new Util.Timeout();
-        this._setTextEditUpdateInterval(result.speed);
-
-        // Smooth the selection
-        this._setContinuousSelection();
-
-        // Update the other monocle's position if we've dragged off to one side
-        this._updateSelectionUI(result.start, result.end);
-
-        return;
-      }
-    }
-
-    this._lastMarker = aMarker;
-
-    // If we aren't out-of-bounds, clear the scroll timer if it exists.
-    this._clearTimers();
-
-    // Adjusts the selection based on monocle movement
-    this._adjustSelection(aMarker, clientPoint, aEndOfSelection);
-
-    // Update the other monocle's position. We do this because the dragging
-    // monocle may reset the static monocle to a new position if the dragging
-    // monocle drags ahead or behind the other.
-    if (aMarker == "start") {
-      this._updateSelectionUI(false, true);
+      this._adjustEditableSelection(aMarker, clientPoint,
+                                    halfLineHeight, aEndOfSelection);
     } else {
-      this._updateSelectionUI(true, false);
+      this._adjustSelection(aMarker, clientPoint, aEndOfSelection);
     }
   },
 
   /*
    * _handleSelectionPoint helper methods
    */
 
   /*
+   * _adjustEditableSelection
+   *
+   * Based on a monocle marker and position, adds or subtracts from the
+   * existing selection in editable controls. Handles auto-scroll as well.
+   *
+   * @param the marker currently being manipulated
+   * @param aAdjustedClientPoint client point adjusted for line height.
+   * @param aHalfLineHeight half line height in pixels
+   * @param aEndOfSelection indicates if this is the end of a selection
+   * move, in which case we may want to snap to the end of a word or
+   * sentence.
+   */
+  _adjustEditableSelection: function _adjustEditableSelection(aMarker,
+                                                              aAdjustedClientPoint,
+                                                              aHalfLineHeight,
+                                                              aEndOfSelection) {
+    // Test to see if we need to handle auto-scroll in cases where the
+    // monocle is outside the bounds of the control. This also handles
+    // adjusting selection if out-of-bounds is true.
+    let result = this.updateTextEditSelection(aAdjustedClientPoint);
+
+    // If result.trigger is true, the monocle is outside the bounds of the
+    // control.
+    if (result.trigger) {
+      // _handleSelectionPoint is triggered by input movement, so if we've
+      // tested positive for out-of-bounds scrolling here, we need to set a
+      // recurring timer to keep the expected selection behavior going as
+      // long as the user keeps the monocle out of bounds.
+      this._setTextEditUpdateInterval(result.speed);
+
+      // Smooth the selection
+      this._setContinuousSelection();
+
+      // Update the other monocle's position if we've dragged off to one side
+      this._updateSelectionUI(result.start, result.end);
+    } else {
+      // If we aren't out-of-bounds, clear the scroll timer if it exists.
+      this._clearTimers();
+
+      // Restrict the client point to the interior of the control. Prevents
+      // _adjustSelection from accidentally selecting content outside the
+      // control.
+      let constrainedPoint =
+        this._constrainPointWithinControl(aAdjustedClientPoint, aHalfLineHeight);
+
+      // Add or subtract selection
+      this._adjustSelection(aMarker, constrainedPoint, aEndOfSelection);
+    }
+  },
+
+  /*
+   * _adjustSelection
+   *
    * Based on a monocle marker and position, adds or subtracts from the
    * existing selection.
    *
    * @param the marker currently being manipulated
    * @param aClientPoint the point designating the new start or end
    * position for the selection.
    * @param aEndOfSelection indicates if this is the end of a selection
    * move, in which case we may want to snap to the end of a word or
@@ -702,16 +707,25 @@ var SelectionHandler = {
     if (!selectResult) {
       this._restoreRangeList();
     }
 
     this._freeRangeList();
 
     // Smooth over the selection between all existing ranges.
     this._setContinuousSelection();
+
+    // Update the other monocle's position. We do this because the dragging
+    // monocle may reset the static monocle to a new position if the dragging
+    // monocle drags ahead or behind the other.
+    if (aMarker == "start") {
+      this._updateSelectionUI(false, true);
+    } else {
+      this._updateSelectionUI(true, false);
+    }
   },
 
   /*
    * _backupRangeList, _restoreRangeList, and _freeRangeList
    *
    * Utilities that manage a cloned copy of the existing selection.
    */
 
@@ -818,16 +832,18 @@ var SelectionHandler = {
     if (result.speed < 1)
       result.speed = 1;
     result.speed /= 100;
     return result;
   },
 
   _setTextEditUpdateInterval: function _setTextEditUpdateInterval(aSpeedValue) {
     let timeout = (75 - (aSpeedValue * 75));
+    if (!this._scrollTimer)
+      this._scrollTimer = new Util.Timeout();
     this._scrollTimer.interval(timeout, this.scrollTimerCallback);
   },
 
   _clearTimers: function _clearTimers() {
     if (this._scrollTimer) {
       this._scrollTimer.clear();
     }
   },