Index: content/public/android/java/src/org/chromium/content/browser/input/HandleView.java |
diff --git a/content/public/android/java/src/org/chromium/content/browser/input/HandleView.java b/content/public/android/java/src/org/chromium/content/browser/input/HandleView.java |
index 88a6deaefea4fe0c835e75c433730ccf3a24636d..2310726ea8fbb8416459bd91f79b7cb8b6457551 100644 |
--- a/content/public/android/java/src/org/chromium/content/browser/input/HandleView.java |
+++ b/content/public/android/java/src/org/chromium/content/browser/input/HandleView.java |
@@ -24,27 +24,40 @@ import android.view.ViewGroup.LayoutParams; |
import android.widget.PopupWindow; |
import android.widget.TextView; |
+import org.chromium.content.browser.PositionObserver; |
+ |
/** |
* View that displays a selection or insertion handle for text editing. |
+ * |
+ * While a HandleView is logically a child of some other view, it does not exist in that View's |
+ * hierarchy. |
+ * |
*/ |
public class HandleView extends View { |
private static final float FADE_DURATION = 200.f; |
private Drawable mDrawable; |
private final PopupWindow mContainer; |
+ |
+ // The position of the handle relative to the parent view. |
private int mPositionX; |
private int mPositionY; |
+ |
+ // The position of the parent relative to the application's root view. |
+ private int mParentPositionX; |
+ private int mParentPositionY; |
+ |
+ // The offset from this handles position to the "tip" of the handle. |
+ private float mHotspotX; |
+ private float mHotspotY; |
+ |
private final CursorController mController; |
private boolean mIsDragging; |
private float mTouchToWindowOffsetX; |
private float mTouchToWindowOffsetY; |
- private float mHotspotX; |
- private float mHotspotY; |
+ |
private int mLineOffsetY; |
- private int mLastParentX; |
- private int mLastParentY; |
private float mDownPositionX, mDownPositionY; |
- private int mContainerPositionX, mContainerPositionY; |
private long mTouchTimer; |
private boolean mIsInsertionHandle = false; |
private float mAlpha; |
@@ -61,13 +74,15 @@ public class HandleView extends View { |
private Drawable mSelectHandleRight; |
private Drawable mSelectHandleCenter; |
- private final int[] mTempCoords = new int[2]; |
private final Rect mTempRect = new Rect(); |
static final int LEFT = 0; |
static final int CENTER = 1; |
static final int RIGHT = 2; |
+ private PositionObserver mParentPositionObserver; |
+ private PositionObserver.Listener mParentPositionListener; |
+ |
// Number of dips to subtract from the handle's y position to give a suitable |
// y coordinate for the corresponding text position. This is to compensate for the fact |
// that the handle position is at the base of the line of text. |
@@ -79,7 +94,8 @@ public class HandleView extends View { |
android.R.attr.textSelectHandleRight, |
}; |
- HandleView(CursorController controller, int pos, View parent) { |
+ HandleView(CursorController controller, int pos, View parent, |
+ PositionObserver parentPositionObserver) { |
super(parent.getContext()); |
Context context = parent.getContext(); |
mParent = parent; |
@@ -101,6 +117,14 @@ public class HandleView extends View { |
LINE_OFFSET_Y_DIP, context.getResources().getDisplayMetrics()); |
mAlpha = 1.f; |
+ |
+ mParentPositionListener = new PositionObserver.Listener() { |
+ @Override |
+ public void onPositionChanged(int x, int y) { |
+ updateParentPosition(x, y); |
+ } |
+ }; |
+ mParentPositionObserver = parentPositionObserver; |
} |
void setOrientation(int pos) { |
@@ -152,21 +176,46 @@ public class HandleView extends View { |
mDrawable.getIntrinsicHeight()); |
} |
- private void updateContainerPosition() { |
- final int[] coords = mTempCoords; |
- mParent.getLocationInWindow(coords); |
- mContainerPositionX = coords[0] + mPositionX; |
- mContainerPositionY = coords[1] + mPositionY; |
+ private void updateParentPosition(int parentPositionX, int parentPositionY) { |
+ // Hide paste popup window as soon as a scroll occurs. |
+ if (mPastePopupWindow != null) mPastePopupWindow.hide(); |
+ |
+ mTouchToWindowOffsetX += parentPositionX - mParentPositionX; |
+ mTouchToWindowOffsetY += parentPositionY - mParentPositionY; |
+ mParentPositionX = parentPositionX; |
+ mParentPositionY = parentPositionY; |
+ onPositionChanged(); |
+ } |
+ |
+ private int getContainerPositionX() { |
+ return mParentPositionX + mPositionX; |
+ } |
+ |
+ private int getContainerPositionY() { |
+ return mParentPositionY + mPositionY; |
+ } |
+ |
+ private void onPositionChanged() { |
+ mContainer.update(getContainerPositionX(), getContainerPositionY(), |
+ getRight() - getLeft(), getBottom() - getTop()); |
+ } |
+ |
+ private void showContainer() { |
+ mContainer.showAtLocation(mParent, 0, getContainerPositionX(), getContainerPositionY()); |
} |
void show() { |
+ // While hidden, the parent position may have become stale. It must be updated before |
+ // checking isPositionVisible(). |
+ updateParentPosition(mParentPositionObserver.getPositionX(), |
+ mParentPositionObserver.getPositionY()); |
if (!isPositionVisible()) { |
hide(); |
return; |
} |
+ mParentPositionObserver.addListener(mParentPositionListener); |
mContainer.setContentView(this); |
- updateContainerPosition(); |
- mContainer.showAtLocation(mParent, 0, mContainerPositionX, mContainerPositionY); |
+ showContainer(); |
// Hide paste view when handle is moved on screen. |
if (mPastePopupWindow != null) { |
@@ -177,6 +226,7 @@ public class HandleView extends View { |
void hide() { |
mIsDragging = false; |
mContainer.dismiss(); |
+ mParentPositionObserver.removeListener(mParentPositionListener); |
if (mPastePopupWindow != null) { |
mPastePopupWindow.hide(); |
} |
@@ -203,10 +253,8 @@ public class HandleView extends View { |
return false; |
} |
- final int[] coords = mTempCoords; |
- mParent.getLocationInWindow(coords); |
- final int posX = coords[0] + mPositionX + (int) mHotspotX; |
- final int posY = coords[1] + mPositionY + (int) mHotspotY; |
+ final int posX = getContainerPositionX() + (int) mHotspotX; |
+ final int posY = getContainerPositionY() + (int) mHotspotY; |
return posX >= clip.left && posX <= clip.right && |
posY >= clip.top && posY <= clip.bottom; |
@@ -214,44 +262,24 @@ public class HandleView extends View { |
// x and y are in physical pixels. |
void moveTo(int x, int y) { |
+ int previousPositionX = mPositionX; |
+ int previousPositionY = mPositionY; |
+ |
mPositionX = x; |
mPositionY = y; |
if (isPositionVisible()) { |
- int[] coords = null; |
if (mContainer.isShowing()) { |
- coords = mTempCoords; |
- mParent.getLocationInWindow(coords); |
- final int containerPositionX = coords[0] + mPositionX; |
- final int containerPositionY = coords[1] + mPositionY; |
- |
- if (containerPositionX != mContainerPositionX || |
- containerPositionY != mContainerPositionY) { |
- mContainerPositionX = containerPositionX; |
- mContainerPositionY = containerPositionY; |
- |
- mContainer.update(mContainerPositionX, mContainerPositionY, |
- getRight() - getLeft(), getBottom() - getTop()); |
- |
- // Hide paste popup window as soon as a scroll occurs. |
- if (mPastePopupWindow != null) { |
- mPastePopupWindow.hide(); |
- } |
+ onPositionChanged(); |
+ // Hide paste popup window as soon as the handle is dragged. |
+ if (mPastePopupWindow != null && |
+ (previousPositionX != mPositionX || previousPositionY != mPositionY)) { |
+ mPastePopupWindow.hide(); |
} |
} else { |
show(); |
} |
if (mIsDragging) { |
- if (coords == null) { |
- coords = mTempCoords; |
- mParent.getLocationInWindow(coords); |
- } |
- if (coords[0] != mLastParentX || coords[1] != mLastParentY) { |
- mTouchToWindowOffsetX += coords[0] - mLastParentX; |
- mTouchToWindowOffsetY += coords[1] - mLastParentY; |
- mLastParentX = coords[0]; |
- mLastParentY = coords[1]; |
- } |
// Hide paste popup window as soon as the handle is dragged. |
if (mPastePopupWindow != null) { |
mPastePopupWindow.hide(); |
@@ -265,9 +293,6 @@ public class HandleView extends View { |
@Override |
protected void onDraw(Canvas c) { |
updateAlpha(); |
- updateContainerPosition(); |
- mContainer.update(mContainerPositionX, mContainerPositionY, |
- getRight() - getLeft(), getBottom() - getTop()); |
mDrawable.setBounds(0, 0, getRight() - getLeft(), getBottom() - getTop()); |
mDrawable.draw(c); |
} |
@@ -280,10 +305,6 @@ public class HandleView extends View { |
mDownPositionY = ev.getRawY(); |
mTouchToWindowOffsetX = mDownPositionX - mPositionX; |
mTouchToWindowOffsetY = mDownPositionY - mPositionY; |
- final int[] coords = mTempCoords; |
- mParent.getLocationInWindow(coords); |
- mLastParentX = coords[0]; |
- mLastParentY = coords[1]; |
mIsDragging = true; |
mController.beforeStartUpdatingPosition(this); |
mTouchTimer = SystemClock.uptimeMillis(); |
@@ -347,17 +368,31 @@ public class HandleView extends View { |
// x and y are in physical pixels. |
void positionAt(int x, int y) { |
- moveTo((int)(x - mHotspotX), (int)(y - mHotspotY)); |
+ moveTo(x - Math.round(mHotspotX), y - Math.round(mHotspotY)); |
} |
- // Returns the x coordinate of the position that the handle appears to be pointing to. |
+ // Returns the x coordinate of the position that the handle appears to be pointing to relative |
+ // to the handles "parent" view. |
int getAdjustedPositionX() { |
- return (int) (mPositionX + mHotspotX); |
+ return mPositionX + Math.round(mHotspotX); |
} |
- // Returns the y coordinate of the position that the handle appears to be pointing to. |
+ // Returns the y coordinate of the position that the handle appears to be pointing to relative |
+ // to the handles "parent" view. |
int getAdjustedPositionY() { |
- return (int) (mPositionY + mHotspotY); |
+ return mPositionY + Math.round(mHotspotY); |
+ } |
+ |
+ // Returns the x coordinate of the postion that the handle appears to be pointing to relative to |
+ // the root view of the application. |
+ int getRootViewRelativePositionX() { |
+ return getContainerPositionX() + Math.round(mHotspotX); |
+ } |
+ |
+ // Returns the y coordinate of the postion that the handle appears to be pointing to relative to |
+ // the root view of the application. |
+ int getRootViewRelativePositionY() { |
+ return getContainerPositionY() + Math.round(mHotspotY); |
} |
// Returns a suitable y coordinate for the text position corresponding to the handle. |