diff --git a/mobile/android/chrome/content/browser.js b/mobile/android/chrome/content/browser.js index 549405cfcdc..f3c5cc0eb2d 100644 --- a/mobile/android/chrome/content/browser.js +++ b/mobile/android/chrome/content/browser.js @@ -1500,25 +1500,48 @@ var SelectionHandler = { this._end.style.top = aY + this.cache.offset.y + "px"; } - //XXX bug 765057: Reverse text selection handles if necessary - // Send mouse events to the top-level window let cwu = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils); - if (aIsStartHandle) { - // If we're moving the start handle, we need to re-position the caret using a fake mouse click - let start = this._start.getBoundingClientRect(); - cwu.sendMouseEventToWindow("mousedown", start.right - this.HANDLE_PADDING, start.top - this.HANDLE_VERTICAL_MARGIN, 0, 0, 0, true); - cwu.sendMouseEventToWindow("mouseup", start.right - this.HANDLE_PADDING, start.top - this.HANDLE_VERTICAL_MARGIN, 0, 0, 0, true); - } + // If we're moving the start handle, we need to re-position the carat + if (aIsStartHandle) + this._sendStartMouseEvents(cwu); - // Send a shift+click to select text between the carat at the start and an end point + // We always need to fire events for the end to move the selection + this._sendEndMouseEvents(cwu); + + // Update the cached selection area after firing the mouse events + let selectionReversed = this.updateCacheForSelection(aIsStartHandle); + + // Reverse the handles if necessary + if (selectionReversed) { + let oldStart = this._start; + let oldEnd = this._end; + + oldStart.setAttribute("anonid", "selection-handle-end"); + oldEnd.setAttribute("anonid", "selection-handle-start"); + + this._start = oldEnd; + this._end = oldStart; + + // Re-send mouse events to update the selection corresponding to the new handles + this._sendStartMouseEvents(cwu); + this._sendEndMouseEvents(cwu); + } + }, + + // Positions the caret using a fake mouse click + _sendStartMouseEvents: function sh_sendStartMouseEvents(cwu) { + let start = this._start.getBoundingClientRect(); + cwu.sendMouseEventToWindow("mousedown", start.right - this.HANDLE_PADDING, start.top - this.HANDLE_VERTICAL_MARGIN, 0, 0, 0, true); + cwu.sendMouseEventToWindow("mouseup", start.right - this.HANDLE_PADDING, start.top - this.HANDLE_VERTICAL_MARGIN, 0, 0, 0, true); + }, + + // Selects text between the carat at the start and an end point using a fake shift+click + _sendEndMouseEvents: function sh_sendEndMouseEvents(cwu) { let end = this._end.getBoundingClientRect(); cwu.sendMouseEventToWindow("mousedown", end.left + this.HANDLE_PADDING, end.top - this.HANDLE_VERTICAL_MARGIN, 0, 1, Ci.nsIDOMNSEvent.SHIFT_MASK, true); cwu.sendMouseEventToWindow("mouseup", end.left + this.HANDLE_PADDING, end.top - this.HANDLE_VERTICAL_MARGIN, 0, 1, Ci.nsIDOMNSEvent.SHIFT_MASK, true); - - // Update the cached selection area - this.updateCacheForSelection(); }, // aX/aY are in top-level window browser coordinates @@ -1554,14 +1577,27 @@ var SelectionHandler = { this.cache = null; }, - updateCacheForSelection: function sh_updateCacheForSelection() { + // Returns true if the selection has been reversed. Takes optional aIsStartHandle + // param to decide whether the selection has been reversed. + updateCacheForSelection: function sh_updateCacheForSelection(aIsStartHandle) { let range = this._view.getSelection().getRangeAt(0); + this.cache.rect = range.getBoundingClientRect(); let rects = range.getClientRects(); - this.cache.start = { x: rects[0].left, y: rects[0].bottom }; - this.cache.end = { x: rects[rects.length - 1].right, y: rects[rects.length - 1].bottom }; + let start = { x: rects[0].left, y: rects[0].bottom }; + let end = { x: rects[rects.length - 1].right, y: rects[rects.length - 1].bottom }; - this.cache.rect = range.getBoundingClientRect(); + let selectionReversed = false; + if (this.cache.start) { + // If the end moved past the old end, but we're dragging the start handle, then that handle should become the end handle (and vice versa) + selectionReversed = (aIsStartHandle && (end.y > this.cache.end.y || (end.y == this.cache.end.y && end.x > this.cache.end.x))) || + (!aIsStartHandle && (start.y < this.cache.start.y || (start.y == this.cache.start.y && start.x < this.cache.start.x))); + } + + this.cache.start = start; + this.cache.end = end; + + return selectionReversed; }, updateCacheOffset: function sh_updateCacheOffset() {