--- a/mobile/android/base/GeckoApp.java
+++ b/mobile/android/base/GeckoApp.java
@@ -1608,16 +1608,17 @@ abstract public class GeckoApp
mBatteryReceiver.registerFor(mAppContext);
mConnectivityReceiver = new GeckoConnectivityReceiver();
mConnectivityReceiver.registerFor(mAppContext);
mPromptService = new PromptService();
mTextSelection = new TextSelection((TextSelectionHandle) findViewById(R.id.start_handle),
+ (TextSelectionHandle) findViewById(R.id.middle_handle),
(TextSelectionHandle) findViewById(R.id.end_handle),
GeckoAppShell.getEventDispatcher());
GeckoNetworkManager.getInstance().init();
GeckoNetworkManager.getInstance().start();
UpdateServiceHelper.registerForUpdates(this);
--- a/mobile/android/base/Makefile.in
+++ b/mobile/android/base/Makefile.in
@@ -499,16 +499,17 @@ RES_DRAWABLE_BASE = \
res/drawable/reader.png \
res/drawable/reading_list.png \
res/drawable/validation_arrow.png \
res/drawable/validation_arrow_inverted.png \
res/drawable/validation_bg.9.png \
res/drawable/bookmarkdefaults_favicon_support.png \
res/drawable/bookmarkdefaults_favicon_addons.png \
res/drawable/handle_end.png \
+ res/drawable/handle_middle.png \
res/drawable/handle_start.png \
$(addprefix res/drawable-mdpi/,$(notdir $(SYNC_RES_DRAWABLE_MDPI))) \
$(NULL)
RES_DRAWABLE_LDPI = \
$(addprefix res/drawable-ldpi/,$(notdir $(SYNC_RES_DRAWABLE_LDPI))) \
$(NULL)
@@ -567,16 +568,17 @@ RES_DRAWABLE_HDPI = \
res/drawable-hdpi/site_security_verified.png \
res/drawable-hdpi/urlbar_stop.png \
res/drawable-hdpi/reader.png \
res/drawable-hdpi/reading_list.png \
res/drawable-hdpi/validation_arrow.png \
res/drawable-hdpi/validation_arrow_inverted.png \
res/drawable-hdpi/validation_bg.9.png \
res/drawable-hdpi/handle_end.png \
+ res/drawable-hdpi/handle_middle.png \
res/drawable-hdpi/handle_start.png \
$(addprefix res/drawable-hdpi/,$(notdir $(SYNC_RES_DRAWABLE_HDPI))) \
$(NULL)
RES_DRAWABLE_XHDPI = \
res/drawable-xhdpi/favicon.png \
res/drawable-xhdpi/folder.png \
res/drawable-xhdpi/abouthome_icon.png \
@@ -629,16 +631,17 @@ RES_DRAWABLE_XHDPI = \
res/drawable-xhdpi/remote_tabs_off.png \
res/drawable-xhdpi/remote_tabs_on.png \
res/drawable-xhdpi/site_security_identified.png \
res/drawable-xhdpi/site_security_verified.png \
res/drawable-xhdpi/validation_arrow.png \
res/drawable-xhdpi/validation_arrow_inverted.png \
res/drawable-xhdpi/validation_bg.9.png \
res/drawable-xhdpi/handle_end.png \
+ res/drawable-xhdpi/handle_middle.png \
res/drawable-xhdpi/handle_start.png \
$(NULL)
RES_DRAWABLE_MDPI_V11 = \
res/drawable-mdpi-v11/alert_addon.png \
res/drawable-mdpi-v11/alert_app.png \
res/drawable-mdpi-v11/alert_download.png \
res/drawable-mdpi-v11/ic_menu_back.png \
--- a/mobile/android/base/TextSelection.java
+++ b/mobile/android/base/TextSelection.java
@@ -6,40 +6,45 @@ package org.mozilla.gecko;
import org.mozilla.gecko.gfx.Layer;
import org.mozilla.gecko.gfx.Layer.RenderContext;
import org.mozilla.gecko.gfx.LayerView;
import org.mozilla.gecko.util.EventDispatcher;
import org.mozilla.gecko.util.FloatUtils;
import org.mozilla.gecko.util.GeckoEventListener;
+import org.json.JSONArray;
import org.json.JSONObject;
import android.util.Log;
import android.view.View;
class TextSelection extends Layer implements GeckoEventListener {
private static final String LOGTAG = "GeckoTextSelection";
private final TextSelectionHandle mStartHandle;
+ private final TextSelectionHandle mMiddleHandle;
private final TextSelectionHandle mEndHandle;
private final EventDispatcher mEventDispatcher;
private float mViewLeft;
private float mViewTop;
private float mViewZoom;
- TextSelection(TextSelectionHandle startHandle, TextSelectionHandle endHandle,
+ TextSelection(TextSelectionHandle startHandle,
+ TextSelectionHandle middleHandle,
+ TextSelectionHandle endHandle,
EventDispatcher eventDispatcher) {
mStartHandle = startHandle;
+ mMiddleHandle = middleHandle;
mEndHandle = endHandle;
mEventDispatcher = eventDispatcher;
- // Only register listeners if we have valid start/end handles
- if (mStartHandle == null || mEndHandle == null) {
+ // Only register listeners if we have valid start/middle/end handles
+ if (mStartHandle == null || mMiddleHandle == null || mEndHandle == null) {
Log.e(LOGTAG, "Failed to initialize text selection because at least one handle is null");
} else {
registerEventListener("TextSelection:ShowHandles");
registerEventListener("TextSelection:HideHandles");
registerEventListener("TextSelection:PositionHandles");
}
}
@@ -47,52 +52,83 @@ class TextSelection extends Layer implem
unregisterEventListener("TextSelection:ShowHandles");
unregisterEventListener("TextSelection:HideHandles");
unregisterEventListener("TextSelection:PositionHandles");
}
public void handleMessage(String event, JSONObject message) {
try {
if (event.equals("TextSelection:ShowHandles")) {
+ final JSONArray handles = message.getJSONArray("handles");
GeckoApp.mAppContext.mMainHandler.post(new Runnable() {
public void run() {
- mStartHandle.setVisibility(View.VISIBLE);
- mEndHandle.setVisibility(View.VISIBLE);
+ try {
+ for (int i=0; i < handles.length(); i++) {
+ String handle = handles.getString(i);
- mViewLeft = 0.0f;
- mViewTop = 0.0f;
- mViewZoom = 0.0f;
- LayerView layerView = GeckoApp.mAppContext.getLayerView();
- if (layerView != null) {
- layerView.addLayer(TextSelection.this);
- }
+ if (handle.equals("START"))
+ mStartHandle.setVisibility(View.VISIBLE);
+ else if (handle.equals("MIDDLE"))
+ mMiddleHandle.setVisibility(View.VISIBLE);
+ else
+ mEndHandle.setVisibility(View.VISIBLE);
+ }
+
+ mViewLeft = 0.0f;
+ mViewTop = 0.0f;
+ mViewZoom = 0.0f;
+ LayerView layerView = GeckoApp.mAppContext.getLayerView();
+ if (layerView != null) {
+ layerView.addLayer(TextSelection.this);
+ }
+ } catch(Exception e) {}
}
});
} else if (event.equals("TextSelection:HideHandles")) {
+ final JSONArray handles = message.getJSONArray("handles");
GeckoApp.mAppContext.mMainHandler.post(new Runnable() {
public void run() {
- LayerView layerView = GeckoApp.mAppContext.getLayerView();
- if (layerView != null) {
- layerView.removeLayer(TextSelection.this);
- }
+ try {
+ LayerView layerView = GeckoApp.mAppContext.getLayerView();
+ if (layerView != null) {
+ layerView.removeLayer(TextSelection.this);
+ }
- mStartHandle.setVisibility(View.GONE);
- mEndHandle.setVisibility(View.GONE);
+ for (int i=0; i < handles.length(); i++) {
+ String handle = handles.getString(i);
+ if (handle.equals("START"))
+ mStartHandle.setVisibility(View.GONE);
+ else if (handle.equals("MIDDLE"))
+ mMiddleHandle.setVisibility(View.GONE);
+ else
+ mEndHandle.setVisibility(View.GONE);
+ }
+
+ } catch(Exception e) {}
}
});
} else if (event.equals("TextSelection:PositionHandles")) {
- final int startLeft = message.getInt("startLeft");
- final int startTop = message.getInt("startTop");
- final int endLeft = message.getInt("endLeft");
- final int endTop = message.getInt("endTop");
-
+ final JSONArray positions = message.getJSONArray("positions");
GeckoApp.mAppContext.mMainHandler.post(new Runnable() {
public void run() {
- mStartHandle.positionFromGecko(startLeft, startTop);
- mEndHandle.positionFromGecko(endLeft, endTop);
+ 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");
+
+ if (handle.equals("START"))
+ mStartHandle.positionFromGecko(left, top);
+ else if (handle.equals("MIDDLE"))
+ mMiddleHandle.positionFromGecko(left, top);
+ else
+ mEndHandle.positionFromGecko(left, top);
+ }
+ } catch (Exception e) { }
}
});
}
} catch (Exception e) {
Log.e(LOGTAG, "Exception handling message \"" + event + "\":", e);
}
}
@@ -108,16 +144,17 @@ class TextSelection extends Layer implem
}
mViewLeft = context.viewport.left;
mViewTop = context.viewport.top;
mViewZoom = context.zoomFactor;
GeckoApp.mAppContext.mMainHandler.post(new Runnable() {
public void run() {
mStartHandle.repositionWithViewport(context.viewport.left, context.viewport.top, context.zoomFactor);
+ mMiddleHandle.repositionWithViewport(context.viewport.left, context.viewport.top, context.zoomFactor);
mEndHandle.repositionWithViewport(context.viewport.left, context.viewport.top, context.zoomFactor);
}
});
}
private void registerEventListener(String event) {
mEventDispatcher.registerEventListener(event, this);
}
--- a/mobile/android/base/TextSelectionHandle.java
+++ b/mobile/android/base/TextSelectionHandle.java
@@ -17,17 +17,17 @@ import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
import android.widget.RelativeLayout;
class TextSelectionHandle extends ImageView implements View.OnTouchListener {
private static final String LOGTAG = "GeckoTextSelectionHandle";
- private enum HandleType { START, END };
+ private enum HandleType { START, MIDDLE, END };
private final HandleType mHandleType;
private final int mWidth;
private final int mHeight;
private final int mShadow;
private int mLeft;
private int mTop;
@@ -37,18 +37,26 @@ class TextSelectionHandle extends ImageV
private RelativeLayout.LayoutParams mLayoutParams;
TextSelectionHandle(Context context, AttributeSet attrs) {
super(context, attrs);
setOnTouchListener(this);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TextSelectionHandle);
- String handleType = a.getString(R.styleable.TextSelectionHandle_handleType);
- mHandleType = handleType.equals("START") ? HandleType.START : HandleType.END;
+ int handleType = a.getInt(R.styleable.TextSelectionHandle_handleType, 0x01);
+
+ if (handleType == 0x01)
+ mHandleType = HandleType.START;
+ else if (handleType == 0x02)
+ mHandleType = HandleType.MIDDLE;
+ else
+ mHandleType = HandleType.END;
+
+ mGeckoPoint = new PointF(0.0f, 0.0f);
mWidth = getResources().getDimensionPixelSize(R.dimen.text_selection_handle_width);
mHeight = getResources().getDimensionPixelSize(R.dimen.text_selection_handle_height);
mShadow = getResources().getDimensionPixelSize(R.dimen.text_selection_handle_shadow);
}
public boolean onTouch(View v, MotionEvent event) {
switch (event.getActionMasked()) {
@@ -84,17 +92,24 @@ class TextSelectionHandle extends ImageV
mTop = mTop + newY - mTouchStartY;
LayerView layerView = GeckoApp.mAppContext.getLayerView();
if (layerView == null) {
Log.e(LOGTAG, "Can't move selection because layerView is null");
return;
}
// Send x coordinate on the right side of the start handle, left side of the end handle.
- float left = (float) mLeft + (mHandleType.equals(HandleType.START) ? mWidth - mShadow : mShadow);
+ float left = (float) mLeft;
+ if (mHandleType.equals(HandleType.START))
+ left += mWidth - mShadow;
+ else if (mHandleType.equals(HandleType.MIDDLE))
+ left += (float) ((mWidth - mShadow) / 2);
+ else
+ left += mShadow;
+
PointF geckoPoint = new PointF(left, (float) mTop);
geckoPoint = layerView.convertViewPointToLayerPoint(geckoPoint);
JSONObject args = new JSONObject();
try {
args.put("handleType", mHandleType.toString());
args.put("x", Math.round(geckoPoint.x));
args.put("y", Math.round(geckoPoint.y));
@@ -117,17 +132,24 @@ class TextSelectionHandle extends ImageV
ImmutableViewportMetrics metrics = layerView.getViewportMetrics();
repositionWithViewport(metrics.viewportRectLeft, metrics.viewportRectTop, metrics.zoomFactor);
}
void repositionWithViewport(float x, float y, float zoom) {
PointF viewPoint = new PointF((mGeckoPoint.x * zoom) - x,
(mGeckoPoint.y * zoom) - y);
- mLeft = Math.round(viewPoint.x) - (mHandleType.equals(HandleType.START) ? mWidth - mShadow : mShadow);
+ mLeft = Math.round(viewPoint.x);
+ if (mHandleType.equals(HandleType.START))
+ mLeft -= mWidth - mShadow;
+ else if (mHandleType.equals(HandleType.MIDDLE))
+ mLeft -= (float) ((mWidth - mShadow) / 2);
+ else
+ mLeft -= mShadow;
+
mTop = Math.round(viewPoint.y);
setLayoutPosition();
}
private void setLayoutPosition() {
if (mLayoutParams == null) {
mLayoutParams = (RelativeLayout.LayoutParams) getLayoutParams();
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..5dcee14f7a70c720d23716cef4cae3c399c7f96b
GIT binary patch
literal 2517
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
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..2a1774ff98a51d11cef6932d315261eec239ed3c
GIT binary patch
literal 3034
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
VnLvWU!kXp3Z8wUSYZZx^{BQTt{73)*
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..751eb898b136ab9814248a83df833d43f0e778dc
GIT binary patch
literal 1850
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
--- a/mobile/android/base/resources/layout/text_selection_handles.xml.in
+++ b/mobile/android/base/resources/layout/text_selection_handles.xml.in
@@ -7,17 +7,24 @@
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:gecko="http://schemas.android.com/apk/res/@ANDROID_PACKAGE_NAME@">
<org.mozilla.gecko.TextSelectionHandle android:id="@+id/start_handle"
android:layout_width="@dimen/text_selection_handle_width"
android:layout_height="@dimen/text_selection_handle_height"
android:src="@drawable/handle_start"
android:visibility="gone"
- gecko:handleType="START"/>
+ gecko:handleType="start"/>
+
+ <org.mozilla.gecko.TextSelectionHandle android:id="@+id/middle_handle"
+ android:layout_width="@dimen/text_selection_handle_width"
+ android:layout_height="@dimen/text_selection_handle_height"
+ android:src="@drawable/handle_middle"
+ android:visibility="gone"
+ gecko:handleType="middle"/>
<org.mozilla.gecko.TextSelectionHandle android:id="@+id/end_handle"
android:layout_width="@dimen/text_selection_handle_width"
android:layout_height="@dimen/text_selection_handle_height"
android:src="@drawable/handle_end"
android:visibility="gone"
- gecko:handleType="END"/>
+ gecko:handleType="end"/>
</merge>
--- a/mobile/android/base/resources/values/attrs.xml
+++ b/mobile/android/base/resources/values/attrs.xml
@@ -45,13 +45,17 @@
<attr name="cropped" format="boolean"/>
</declare-styleable>
<declare-styleable name="TabsPanel">
<attr name="sidebar" format="boolean"/>
</declare-styleable>
<declare-styleable name="TextSelectionHandle">
- <attr name="handleType" format="string"/>
+ <attr name="handleType">
+ <flag name="start" value="0x01" />
+ <flag name="middle" value="0x02" />
+ <flag name="end" value="0x03" />
+ </attr>
</declare-styleable>
</resources>
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -1539,22 +1539,27 @@ var NativeWindow = {
_stripScheme: function(aString) {
return aString.slice(aString.indexOf(":") + 1);
}
}
};
var SelectionHandler = {
HANDLE_TYPE_START: "START",
+ HANDLE_TYPE_MIDDLE: "MIDDLE",
HANDLE_TYPE_END: "END",
+ TYPE_NONE: 0,
+ TYPE_CURSOR: 1,
+ TYPE_SELECTION: 2,
+
// Keeps track of data about the dimensions of the selection. Coordinates
// stored here are relative to the _view window.
cache: null,
- _active: false,
+ _activeType: this.TYPE_NONE,
// The window that holds the selection (can be a sub-frame)
get _view() {
if (this._viewRef)
return this._viewRef.get();
return null;
},
@@ -1594,72 +1599,91 @@ var SelectionHandler = {
Services.obs.removeObserver(this, "Window:Resize");
Services.obs.removeObserver(this, "Tab:Selected");
Services.obs.removeObserver(this, "after-viewport-change");
Services.obs.removeObserver(this, "TextSelection:Move");
Services.obs.removeObserver(this, "TextSelection:Position");
},
observe: function sh_observe(aSubject, aTopic, aData) {
- if (!this._active)
- return;
-
switch (aTopic) {
case "Gesture:SingleTap": {
- let data = JSON.parse(aData);
- this.endSelection(data.x, data.y);
+ if (this._activeType == this.TYPE_SELECTION) {
+ let data = JSON.parse(aData);
+ this.endSelection(data.x, data.y);
+ }
break;
}
case "Tab:Selected":
case "Window:Resize": {
- // Knowing when the page is done drawing is hard, so let's just cancel
- // the selection when the window changes. We should fix this later.
- this.endSelection();
+ if (this._activeType == this.TYPE_SELECTION) {
+ // Knowing when the page is done drawing is hard, so let's just cancel
+ // the selection when the window changes. We should fix this later.
+ this.endSelection();
+ } else if (this._activeType == this.TYPE_CURSOR) {
+ this.hideThumb();
+ }
break;
}
case "after-viewport-change": {
- // Update the cache after the viewport changes (e.g. panning, zooming).
- this.updateCacheForSelection();
+ if (this._activeType == this.TYPE_SELECTION) {
+ // Update the cache after the viewport changes (e.g. panning, zooming).
+ this.updateCacheForSelection();
+ } else if (this._activeType == this.TYPE_CURSOR) {
+ this.hideThumb();
+ }
break;
}
case "TextSelection:Move": {
let data = JSON.parse(aData);
- this.moveSelection(data.handleType == this.HANDLE_TYPE_START, data.x, data.y);
+ if (this._activeType == this.TYPE_SELECTION)
+ this.moveSelection(data.handleType == this.HANDLE_TYPE_START, data.x, data.y);
+ else if (this._activeType == this.TYPE_CURSOR)
+ this._sendMouseEvents(data.x, data.y);
break;
}
case "TextSelection:Position": {
- let data = JSON.parse(aData);
-
- // Reverse the handles if necessary.
- let selectionReversed = this.updateCacheForSelection(data.handleType == this.HANDLE_TYPE_START);
- if (selectionReversed) {
- // Re-send mouse events to update the selection corresponding to the new handles.
- if (this._isRTL) {
- this._sendMouseEvents(this.cache.end.x, this.cache.end.y, false);
- this._sendMouseEvents(this.cache.start.x, this.cache.start.y, true);
- } else {
- this._sendMouseEvents(this.cache.start.x, this.cache.start.y, false);
- this._sendMouseEvents(this.cache.end.x, this.cache.end.y, true);
+ if (this._activeType == this.TYPE_SELECTION) {
+ let data = JSON.parse(aData);
+
+ // Reverse the handles if necessary.
+ let selectionReversed = this.updateCacheForSelection(data.handleType == this.HANDLE_TYPE_START);
+ if (selectionReversed) {
+ // Re-send mouse events to update the selection corresponding to the new handles.
+ if (this._isRTL) {
+ this._sendMouseEvents(this.cache.end.x, this.cache.end.y, false);
+ this._sendMouseEvents(this.cache.start.x, this.cache.start.y, true);
+ } else {
+ this._sendMouseEvents(this.cache.start.x, this.cache.start.y, false);
+ this._sendMouseEvents(this.cache.end.x, this.cache.end.y, true);
+ }
}
+
+ // Position the handles to align with the edges of the selection.
+ this.positionHandles();
+ } else if (this._activeType == this.TYPE_CURSOR) {
+ this.positionHandles();
}
-
- // Position the handles to align with the edges of the selection.
- this.positionHandles();
break;
}
}
},
handleEvent: function sh_handleEvent(aEvent) {
- if (!this._active)
- return;
-
switch (aEvent.type) {
case "pagehide":
- this.endSelection();
+ if (this._activeType == this.TYPE_SELECTION)
+ this.endSelection();
+ else
+ this.hideThumb();
+ break;
+
+ case "keydown":
+ if (this._activeType == this.TYPE_CURSOR)
+ this.hideThumb();
break;
}
},
_ignoreCollapsedSelection: false,
notifySelectionChanged: function sh_notifySelectionChanged(aDoc, aSel, aReason) {
if (aSel.isCollapsed) {
@@ -1687,18 +1711,22 @@ var SelectionHandler = {
aElement instanceof Ci.nsIDOMHTMLEmbedElement ||
aElement instanceof Ci.nsIDOMHTMLImageElement ||
aElement instanceof Ci.nsIDOMHTMLMediaElement);
},
// aX/aY are in top-level window browser coordinates
startSelection: function sh_startSelection(aElement, aX, aY) {
// Clear out any existing selection
- if (this._active)
+ if (this._activeType == this.TYPE_SELECTION) {
this.endSelection();
+ } else if (this._activeType == this.TYPE_CURSOR) {
+ // Hide the cursor handles.
+ this.hideThumb();
+ }
// Get the element's view
this._view = aElement.ownerDocument.defaultView;
if (aElement instanceof Ci.nsIDOMNSEditableElement)
this._target = aElement;
else
this._target = this._view;
@@ -1737,18 +1765,25 @@ var SelectionHandler = {
// 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();
- this.showHandles();
- this._active = true;
+ this._activeType = this.TYPE_SELECTION;
+ this.positionHandles();
+
+ sendMessageToJava({
+ gecko: {
+ type: "TextSelection:ShowHandles",
+ handles: [this.HANDLE_TYPE_START, this.HANDLE_TYPE_END]
+ }
+ });
if (aElement instanceof Ci.nsIDOMNSEditableElement)
aElement.focus();
},
getSelection: function sh_getSelection() {
if (this._target instanceof Ci.nsIDOMNSEditableElement)
return this._target.QueryInterface(Ci.nsIDOMNSEditableElement).editor.selection;
@@ -1764,17 +1799,17 @@ var SelectionHandler = {
getInterface(Ci.nsIWebNavigation).
QueryInterface(Ci.nsIInterfaceRequestor).
getInterface(Ci.nsISelectionDisplay).
QueryInterface(Ci.nsISelectionController);
},
// Used by the contextmenu "matches" functions in ClipboardHelper
shouldShowContextMenu: function sh_shouldShowContextMenu(aX, aY) {
- return this._active && this._pointInSelection(aX, aY);
+ return (this._active != this.TYPE_NONE) && this._pointInSelection(aX, aY);
},
selectAll: function sh_selectAll(aElement, aX, aY) {
if (!this._active)
this.startSelection(aElement, aX, aY);
let selectionController = this.getSelectionController();
selectionController.selectAll();
@@ -1816,21 +1851,27 @@ var SelectionHandler = {
_sendMouseEvents: function sh_sendMouseEvents(aX, aY, useShift) {
// Send mouse event 1px too high to prevent selection from entering the line below where it should be
this._cwu.sendMouseEventToWindow("mousedown", aX, aY - 1, 0, 0, useShift ? Ci.nsIDOMNSEvent.SHIFT_MASK : 0, true);
this._cwu.sendMouseEventToWindow("mouseup", aX, aY - 1, 0, 0, useShift ? Ci.nsIDOMNSEvent.SHIFT_MASK : 0, true);
},
// aX/aY are in top-level window browser coordinates
endSelection: function sh_endSelection(aX, aY) {
- if (!this._active)
+ if (this._activeType != this.TYPE_SELECTION)
return "";
-
- this._active = false;
- this.hideHandles();
+
+ this._activeType = this.TYPE_NONE;
+ sendMessageToJava({
+ gecko: {
+ type: "TextSelection:HideHandles",
+ handles: [this.HANDLE_TYPE_START, this.HANDLE_TYPE_END]
+ }
+ });
+
let selectedText = "";
let pointInSelection = false;
if (this._view) {
let selection = this.getSelection();
if (selection) {
// Get the text before we clear the selection!
selectedText = selection.toString().trim();
@@ -1910,54 +1951,81 @@ var SelectionHandler = {
}
this.cache.start = start;
this.cache.end = end;
return selectionReversed;
},
+ showThumb: function sh_showThumb(aElement) {
+ if (!aElement)
+ return;
+
+ // Get the element's view
+ this._view = aElement.ownerDocument.defaultView;
+ this._target = aElement;
+
+ this._view.addEventListener("pagehide", this, false);
+ this._view.addEventListener("keydown", this, false);
+
+ this._activeType = this.TYPE_CURSOR;
+ this.positionHandles();
+
+ sendMessageToJava({
+ gecko: {
+ type: "TextSelection:ShowHandles",
+ handles: [this.HANDLE_TYPE_MIDDLE]
+ }
+ });
+ },
+
+ hideThumb: function sh_hideThumb() {
+ this._activeType = this.TYPE_NONE;
+ this._cleanUp();
+
+ sendMessageToJava({
+ gecko: {
+ type: "TextSelection:HideHandles",
+ handles: [this.HANDLE_TYPE_MIDDLE]
+ }
+ });
+ },
+
positionHandles: function sh_positionHandles() {
// Translate coordinates to account for selections in sub-frames. We can't cache
// this because the top-level page may have scrolled since selection started.
let offset = this._getViewOffset();
let scrollX = {}, scrollY = {};
this._view.top.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils).getScrollXY(false, scrollX, scrollY);
+ 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);
+ positions = [ { handle: this.HANDLE_TYPE_MIDDLE,
+ left: cursor.left + offset.x + scrollX.value,
+ top: cursor.top + cursor.height + offset.y + scrollY.value } ];
+ } else {
+ positions = [ { handle: this.HANDLE_TYPE_START,
+ left: this.cache.start.x + offset.x + scrollX.value,
+ top: this.cache.start.y + offset.y + scrollY.value },
+ { handle: this.HANDLE_TYPE_END,
+ left: this.cache.end.x + offset.x + scrollX.value,
+ top: this.cache.end.y + offset.y + scrollY.value } ];
+ }
+
sendMessageToJava({
gecko: {
type: "TextSelection:PositionHandles",
- startLeft: this.cache.start.x + offset.x + scrollX.value,
- startTop: this.cache.start.y + offset.y + scrollY.value,
- endLeft: this.cache.end.x + offset.x + scrollX.value,
- endTop: this.cache.end.y + offset.y + scrollY.value
- }
- });
- },
-
- showHandles: function sh_showHandles() {
- this.positionHandles();
-
- sendMessageToJava({
- gecko: {
- type: "TextSelection:ShowHandles"
- }
- });
- },
-
- hideHandles: function sh_hideHandles() {
- sendMessageToJava({
- gecko: {
- type: "TextSelection:HideHandles"
+ positions: positions
}
});
}
};
-
var UserAgent = {
DESKTOP_UA: null,
init: function ua_init() {
Services.obs.addObserver(this, "DesktopMode:Change", false);
Services.obs.addObserver(this, "http-on-modify-request", false);
// See https://developer.mozilla.org/en/Gecko_user_agent_string_reference
@@ -3514,16 +3582,20 @@ var BrowserEventHandler = {
[data.x, data.y] = this._moveClickPoint(element, data.x, data.y);
element = ElementTouchHelper.anyElementFromPoint(data.x, data.y);
isClickable = ElementTouchHelper.isElementClickable(element);
}
this._sendMouseEvent("mousemove", element, data.x, data.y);
this._sendMouseEvent("mousedown", element, data.x, data.y);
this._sendMouseEvent("mouseup", element, data.x, data.y);
+
+ // See if its a input element
+ if ((element instanceof HTMLInputElement && element.mozIsTextField(false)) || (element instanceof HTMLTextAreaElement))
+ SelectionHandler.showThumb(element);
if (isClickable)
Haptic.performSimpleAction(Haptic.LongPress);
} catch(e) {
Cu.reportError(e);
}
}
this._cancelTapHighlight();