Bug 864589 - Show/hide text selection handles if a selection is programatically added/removed, r=margaret, ehsan
authorMark Capella <markcapella@twcny.rr.com>
Fri, 16 Aug 2013 21:51:41 -0400
changeset 143030 5a5d5ebec1fc0d025b8fa30817387cd0c2080e49
parent 143029 dd9d2871a6f2886d0a411d7fc9c8aab01fbef6ab
child 143031 e1210bbb856de6b58378316bd1ece6915dbdb8e6
push id32605
push userphilringnalda@gmail.com
push dateMon, 19 Aug 2013 00:51:46 +0000
treeherdermozilla-inbound@7f882e063eaf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmargaret, ehsan
bugs864589
milestone26.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 864589 - Show/hide text selection handles if a selection is programatically added/removed, r=margaret, ehsan
content/base/public/nsISelectionListener.idl
layout/generic/nsSelection.cpp
mobile/android/chrome/content/SelectionHandler.js
--- a/content/base/public/nsISelectionListener.idl
+++ b/content/base/public/nsISelectionListener.idl
@@ -3,22 +3,24 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 
 interface nsIDOMDocument;
 interface nsISelection;
 
-[scriptable, uuid(A6CF90E2-15B3-11d2-932E-00805F8ADD32)]
+[scriptable, uuid(280cd784-23c2-468d-8624-354e0b3804bd)]
 interface nsISelectionListener : nsISupports
 {
   const short NO_REASON=0;
   const short DRAG_REASON=1;
   const short MOUSEDOWN_REASON=2;/*bitflags*/
   const short MOUSEUP_REASON=4;/*bitflags*/
   const short KEYPRESS_REASON=8;/*bitflags*/
   const short SELECTALL_REASON=16;
+  const short COLLAPSETOSTART_REASON=32;
+  const short COLLAPSETOEND_REASON=64;
 
 	void			notifySelectionChanged(in nsIDOMDocument doc, in nsISelection sel, in short reason);
 };
 
 
--- a/layout/generic/nsSelection.cpp
+++ b/layout/generic/nsSelection.cpp
@@ -4439,16 +4439,20 @@ Selection::CollapseToStart()
   if (NS_FAILED(rv) || cnt <= 0)
     return NS_ERROR_DOM_INVALID_STATE_ERR;
 
   // Get the first range
   nsRange* firstRange = mRanges[0].mRange;
   if (!firstRange)
     return NS_ERROR_FAILURE;
 
+  if (mFrameSelection) {
+    int16_t reason = mFrameSelection->PopReason() | nsISelectionListener::COLLAPSETOSTART_REASON;
+    mFrameSelection->PostReason(reason);
+  }
   return Collapse(firstRange->GetStartParent(), firstRange->StartOffset());
 }
 
 /*
  * Sets the whole selection to be one point
  * at the end of the current selection
  */
 NS_IMETHODIMP
@@ -4459,16 +4463,20 @@ Selection::CollapseToEnd()
   if (NS_FAILED(rv) || cnt <= 0)
     return NS_ERROR_DOM_INVALID_STATE_ERR;
 
   // Get the last range
   nsRange* lastRange = mRanges[cnt - 1].mRange;
   if (!lastRange)
     return NS_ERROR_FAILURE;
 
+  if (mFrameSelection) {
+    int16_t reason = mFrameSelection->PopReason() | nsISelectionListener::COLLAPSETOEND_REASON;
+    mFrameSelection->PostReason(reason);
+  }
   return Collapse(lastRange->GetEndParent(), lastRange->EndOffset());
 }
 
 /*
  * IsCollapsed -- is the whole selection just one point, or unset?
  */
 bool
 Selection::IsCollapsed()
--- a/mobile/android/chrome/content/SelectionHandler.js
+++ b/mobile/android/chrome/content/SelectionHandler.js
@@ -169,16 +169,24 @@ var SelectionHandler = {
     this._contentWindow.top.QueryInterface(Ci.nsIInterfaceRequestor).
                             getInterface(Ci.nsIDOMWindowUtils).getScrollXY(false, scrollX, scrollY);
     return {
       X: scrollX.value,
       Y: scrollY.value
     };
   },
 
+  notifySelectionChanged: function sh_notifySelectionChanged(aDocument, aSelection, aReason) {
+    // If the selection was collapsed to Start or to End, always close it
+    if ((aReason & Ci.nsISelectionListener.COLLAPSETOSTART_REASON) ||
+        (aReason & Ci.nsISelectionListener.COLLAPSETOEND_REASON)) {
+      this._closeSelection();
+    }
+  },
+
   /*
    * Called from browser.js when the user long taps on text or chooses
    * the "Select Word" context menu item. Initializes SelectionHandler,
    * starts a selection, and positions the text selection handles.
    *
    * @param aX, aY tap location in client coordinates.
    */
   startSelection: function sh_startSelection(aElement, aX, aY) {
@@ -198,16 +206,19 @@ var SelectionHandler = {
 
     let selection = this._getSelection();
     // If the range didn't have any text, let's bail
     if (!selection || selection.rangeCount == 0) {
       this._closeSelection();
       return;
     }
 
+    // Add a listener to end the selection if it's removed programatically
+    selection.QueryInterface(Ci.nsISelectionPrivate).addSelectionListener(this);
+
     // Initialize the cache
     this._cache = { start: {}, end: {}};
     this._updateCacheForSelection();
 
     let scroll = this._getScrollPos();
     // Figure out the distance between the selection and the click
     let positions = this._getHandlePositions(scroll);
     let clickX = scroll.X + aX;
@@ -458,16 +469,18 @@ var SelectionHandler = {
   _closeSelection: function sh_closeSelection() {
     // Bail if there's no active selection
     if (this._activeType == this.TYPE_NONE)
       return;
 
     if (this._activeType == this.TYPE_SELECTION) {
       let selection = this._getSelection();
       if (selection) {
+        // Remove our listener before we removeAllRanges()
+        selection.QueryInterface(Ci.nsISelectionPrivate).removeSelectionListener(this);
         selection.removeAllRanges();
       }
     }
 
     this._activeType = this.TYPE_NONE;
 
     sendMessageToJava({ type: "TextSelection:HideHandles" });