diff --git a/mobile/android/base/TextSelection.java b/mobile/android/base/TextSelection.java index 8a4a2c689241..988474244027 100644 --- a/mobile/android/base/TextSelection.java +++ b/mobile/android/base/TextSelection.java @@ -111,12 +111,13 @@ class TextSelection extends Layer implements GeckoEventListener { try { for (int i=0; i < positions.length(); i++) { JSONObject position = positions.getJSONObject(i); - String handle = position.getString("handle"); int left = position.getInt("left"); int top = position.getInt("top"); - getHandle(handle).positionFromGecko(left, top); - } + TextSelectionHandle handle = getHandle(position.getString("handle")); + handle.setVisibility(position.getBoolean("hidden") ? View.GONE : View.VISIBLE); + handle.positionFromGecko(left, top); + } } catch (Exception e) { } } }); diff --git a/mobile/android/chrome/content/browser.js b/mobile/android/chrome/content/browser.js index a9589f8d8b03..6ac03b8c00a2 100644 --- a/mobile/android/chrome/content/browser.js +++ b/mobile/android/chrome/content/browser.js @@ -2035,19 +2035,42 @@ var SelectionHandler = { let scrollX = {}, scrollY = {}; this._view.top.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils).getScrollXY(false, scrollX, scrollY); + // the checkHidden function tests to see if the given point is hidden inside an + // iframe/subdocument. this is so that if we select some text inside an iframe and + // scroll the iframe so the selection is out of view, we hide the handles rather + // than having them float on top of the main page content. + let checkHidden = function(x, y) { + return false; + }; + if (this._view.frameElement) { + let bounds = this._view.frameElement.getBoundingClientRect(); + checkHidden = function(x, y) { + return x < 0 || y < 0 || x > bounds.width || y > bounds.height; + } + } + let positions = null; if (this._activeType == this.TYPE_CURSOR) { let cursor = this._cwu.sendQueryContentEvent(this._cwu.QUERY_CARET_RECT, this._target.selectionEnd, 0, 0, 0); + let x = cursor.left; + let y = cursor.top + cursor.height; positions = [ { handle: this.HANDLE_TYPE_MIDDLE, - left: cursor.left + offset.x + scrollX.value, - top: cursor.top + cursor.height + offset.y + scrollY.value } ]; + left: x + offset.x + scrollX.value, + top: y + offset.y + scrollY.value, + hidden: checkHidden(x, y) } ]; } else { + let sx = this.cache.start.x; + let sy = this.cache.start.y; + let ex = this.cache.end.x; + let ey = this.cache.end.y; positions = [ { handle: this.HANDLE_TYPE_START, - left: this.cache.start.x + offset.x + scrollX.value, - top: this.cache.start.y + offset.y + scrollY.value }, + left: sx + offset.x + scrollX.value, + top: sy + offset.y + scrollY.value, + hidden: checkHidden(sx, sy) }, { handle: this.HANDLE_TYPE_END, - left: this.cache.end.x + offset.x + scrollX.value, - top: this.cache.end.y + offset.y + scrollY.value } ]; + left: ex + offset.x + scrollX.value, + top: ey + offset.y + scrollY.value, + hidden: checkHidden(ex, ey) } ]; } sendMessageToJava({