From 64901d4eb0f13b794d9c22ae58f16104b556f9b7 Mon Sep 17 00:00:00 2001 From: Gilles Debunne Date: Fri, 25 Nov 2011 10:23:38 +0100 Subject: Better handles' visibility test Checking if the hotspot position is visible instead of checking if it is part of the clipped visible rectangle. Bug 5638710 Patch set 2: synchronize static variables you will. Patch set 3: renaming and refactored the while loop. Patch set 4: synchronize you will (again) Patch set 5: parent Change-Id: I330510f491c85f910fc61598936113ad07d304e4 --- core/java/android/widget/TextView.java | 78 +++++++++++++++++++++------------- 1 file changed, 48 insertions(+), 30 deletions(-) (limited to 'core/java/android/widget/TextView.java') diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 0f1b43b..de02168 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -9370,40 +9370,57 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener mPositionY = mTempCoords[1]; } - public boolean isVisible(int positionX, int positionY) { - final TextView textView = TextView.this; + public void onScrollChanged() { + mScrollHasChanged = true; + } + } - if (mTempRect == null) mTempRect = new Rect(); - final Rect clip = mTempRect; - clip.left = getCompoundPaddingLeft(); - clip.top = getExtendedPaddingTop(); - clip.right = textView.getWidth() - getCompoundPaddingRight(); - clip.bottom = textView.getHeight() - getExtendedPaddingBottom(); - - final ViewParent parent = textView.getParent(); - if (parent == null || !parent.getChildVisibleRect(textView, clip, null)) { - return false; - } + public boolean isPositionVisible(int positionX, int positionY) { + synchronized (sTmpPosition) { + final float[] position = sTmpPosition; + position[0] = positionX; + position[1] = positionY; + View view = this; - int posX = mPositionX + positionX; - int posY = mPositionY + positionY; + while (view != null) { + if (view != this) { + // Local scroll is already taken into account in positionX/Y + position[0] -= view.getScrollX(); + position[1] -= view.getScrollY(); + } - // Offset by 1 to take into account 0.5 and int rounding around getPrimaryHorizontal. - return posX >= clip.left - 1 && posX <= clip.right + 1 && - posY >= clip.top && posY <= clip.bottom; - } + if (position[0] < 0 || position[1] < 0 || + position[0] > view.getWidth() || position[1] > view.getHeight()) { + return false; + } - public boolean isOffsetVisible(int offset) { - final int line = mLayout.getLineForOffset(offset); - final int lineBottom = mLayout.getLineBottom(line); - final int primaryHorizontal = (int) mLayout.getPrimaryHorizontal(offset); - return isVisible(primaryHorizontal + viewportToContentHorizontalOffset(), - lineBottom + viewportToContentVerticalOffset()); - } + if (!view.getMatrix().isIdentity()) { + view.getMatrix().mapPoints(position); + } - public void onScrollChanged() { - mScrollHasChanged = true; + position[0] += view.getLeft(); + position[1] += view.getTop(); + + final ViewParent parent = view.getParent(); + if (parent instanceof View) { + view = (View) parent; + } else { + // We've reached the ViewRoot, stop iterating + view = null; + } + } } + + // We've been able to walk up the view hierarchy and the position was never clipped + return true; + } + + public boolean isOffsetVisible(int offset) { + final int line = mLayout.getLineForOffset(offset); + final int lineBottom = mLayout.getLineBottom(line); + final int primaryHorizontal = (int) mLayout.getPrimaryHorizontal(offset); + return isPositionVisible(primaryHorizontal + viewportToContentHorizontalOffset(), + lineBottom + viewportToContentVerticalOffset()); } @Override @@ -9504,7 +9521,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener public void updatePosition(int parentPositionX, int parentPositionY, boolean parentPositionChanged, boolean parentScrolled) { // Either parentPositionChanged or parentScrolled is true, check if still visible - if (isShowing() && getPositionListener().isOffsetVisible(getTextOffset())) { + if (isShowing() && isOffsetVisible(getTextOffset())) { if (parentScrolled) computeLocalPosition(); updatePosition(parentPositionX, parentPositionY); } else { @@ -10528,7 +10545,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return false; } - return getPositionListener().isVisible(mPositionX + mHotspotX, mPositionY); + return TextView.this.isPositionVisible(mPositionX + mHotspotX, mPositionY); } public abstract int getCurrentCursorOffset(); @@ -11510,6 +11527,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private Path mHighlightPath; private boolean mHighlightPathBogus = true; private static final RectF sTempRect = new RectF(); + private static final float[] sTmpPosition = new float[2]; // XXX should be much larger private static final int VERY_WIDE = 1024*1024; -- cgit v1.1