diff --git a/core/java/android/webkit/DebugFlags.java b/core/java/android/webkit/DebugFlags.java index 8e25395f12010..dca52f62940c3 100644 --- a/core/java/android/webkit/DebugFlags.java +++ b/core/java/android/webkit/DebugFlags.java @@ -32,6 +32,8 @@ class DebugFlags { public static final boolean CALLBACK_PROXY = false; public static final boolean COOKIE_MANAGER = false; public static final boolean COOKIE_SYNC_MANAGER = false; + public static final boolean DRAG_TRACKER = false; + public static final String DRAG_TRACKER_LOGTAG = "skia"; public static final boolean FRAME_LOADER = false; public static final boolean J_WEB_CORE_JAVA_BRIDGE = false;// HIGHLY VERBOSE public static final boolean LOAD_LISTENER = false; diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index d99f9f2bf1777..9ca7adc360c09 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -25,6 +25,7 @@ import android.database.DataSetObserver; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; +import android.graphics.Paint; import android.graphics.Picture; import android.graphics.Point; import android.graphics.Rect; @@ -2867,16 +2868,7 @@ public class WebView extends AbsoluteLayout return super.drawChild(canvas, child, drawingTime); } - @Override - protected void onDraw(Canvas canvas) { - // if mNativeClass is 0, the WebView has been destroyed. Do nothing. - if (mNativeClass == 0) { - return; - } - int saveCount = canvas.save(); - if (mTitleBar != null) { - canvas.translate(0, (int) mTitleBar.getHeight()); - } + private void drawContent(Canvas canvas) { // Update the buttons in the picture, so when we draw the picture // to the screen, they are in the correct state. // Tell the native side if user is a) touching the screen, @@ -2886,9 +2878,25 @@ public class WebView extends AbsoluteLayout // If mNativeClass is 0, we should not reach here, so we do not // need to check it again. nativeRecordButtons(hasFocus() && hasWindowFocus(), - mTouchMode == TOUCH_SHORTPRESS_START_MODE - || mTrackballDown || mGotCenterDown, false); + mTouchMode == TOUCH_SHORTPRESS_START_MODE + || mTrackballDown || mGotCenterDown, false); drawCoreAndCursorRing(canvas, mBackgroundColor, mDrawCursorRing); + } + + @Override + protected void onDraw(Canvas canvas) { + // if mNativeClass is 0, the WebView has been destroyed. Do nothing. + if (mNativeClass == 0) { + return; + } + + int saveCount = canvas.save(); + if (mTitleBar != null) { + canvas.translate(0, (int) mTitleBar.getHeight()); + } + if (mDragTrackerHandler == null || !mDragTrackerHandler.draw(canvas)) { + drawContent(canvas); + } canvas.restoreToCount(saveCount); // Now draw the shadow. @@ -3865,6 +3873,166 @@ public class WebView extends AbsoluteLayout private static final float MAX_SLOPE_FOR_DIAG = 1.5f; private static final int MIN_BREAK_SNAP_CROSS_DISTANCE = 80; + private static int sign(float x) { + return x > 0 ? 1 : (x < 0 ? -1 : 0); + } + + // if the page can scroll <= this value, we won't allow the drag tracker + // to have any effect. + private static final int MIN_SCROLL_AMOUNT_TO_DISABLE_DRAG_TRACKER = 4; + + private class DragTrackerHandler { + private final DragTracker mProxy; + private final float mStartY, mStartX; + private final float mMinDY, mMinDX; + private final float mMaxDY, mMaxDX; + private float mCurrStretchY, mCurrStretchX; + private int mSX, mSY; + + public DragTrackerHandler(float x, float y, DragTracker proxy) { + mProxy = proxy; + + int docBottom = computeVerticalScrollRange() + getTitleHeight(); + int viewTop = getScrollY(); + int viewBottom = viewTop + getHeight(); + + mStartY = y; + mMinDY = -viewTop; + mMaxDY = docBottom - viewBottom; + + if (DebugFlags.DRAG_TRACKER) { + Log.d(DebugFlags.DRAG_TRACKER_LOGTAG, " dragtracker y= " + y + + " up/down= " + mMinDY + " " + mMaxDY); + } + + int docRight = computeHorizontalScrollRange(); + int viewLeft = getScrollX(); + int viewRight = viewLeft + getWidth(); + mStartX = x; + mMinDX = -viewLeft; + mMaxDX = docRight - viewRight; + + mProxy.onStartDrag(x, y); + + // ensure we buildBitmap at least once + mSX = -99999; + } + + private float computeStretch(float delta, float min, float max) { + float stretch = 0; + if (max - min > MIN_SCROLL_AMOUNT_TO_DISABLE_DRAG_TRACKER) { + if (delta < min) { + stretch = delta - min; + } else if (delta > max) { + stretch = delta - max; + } + } + return stretch; + } + + public void dragTo(float x, float y) { + float sy = computeStretch(mStartY - y, mMinDY, mMaxDY); + float sx = computeStretch(mStartX - x, mMinDX, mMaxDX); + + if (mCurrStretchX != sx || mCurrStretchY != sy) { + mCurrStretchX = sx; + mCurrStretchY = sy; + if (DebugFlags.DRAG_TRACKER) { + Log.d(DebugFlags.DRAG_TRACKER_LOGTAG, "---- stretch " + sx + + " " + sy); + } + if (mProxy.onStretchChange(sx, sy)) { + invalidate(); + } + } + } + + public void stopDrag() { + if (DebugFlags.DRAG_TRACKER) { + Log.d(DebugFlags.DRAG_TRACKER_LOGTAG, "----- stopDrag"); + } + mProxy.onStopDrag(); + } + + private int hiddenHeightOfTitleBar() { + return getTitleHeight() - getVisibleTitleHeight(); + } + + // need a way to know if 565 or 8888 is the right config for + // capturing the display and giving it to the drag proxy + private Bitmap.Config offscreenBitmapConfig() { + // hard code 565 for now + return Bitmap.Config.RGB_565; + } + + /* If the tracker draws, then this returns true, otherwise it will + return false, and draw nothing. + */ + public boolean draw(Canvas canvas) { + if (mCurrStretchX != 0 || mCurrStretchY != 0) { + int sx = getScrollX(); + int sy = getScrollY() - hiddenHeightOfTitleBar(); + + if (mSX != sx || mSY != sy) { + buildBitmap(sx, sy); + mSX = sx; + mSY = sy; + } + + int count = canvas.save(Canvas.MATRIX_SAVE_FLAG); + canvas.translate(sx, sy); + mProxy.onDraw(canvas); + canvas.restoreToCount(count); + return true; + } + if (DebugFlags.DRAG_TRACKER) { + Log.d(DebugFlags.DRAG_TRACKER_LOGTAG, " -- draw false " + + mCurrStretchX + " " + mCurrStretchY); + } + return false; + } + + private void buildBitmap(int sx, int sy) { + int w = getWidth(); + int h = getViewHeight(); + Bitmap bm = Bitmap.createBitmap(w, h, offscreenBitmapConfig()); + Canvas canvas = new Canvas(bm); + canvas.translate(-sx, -sy); + drawContent(canvas); + + if (DebugFlags.DRAG_TRACKER) { + Log.d(DebugFlags.DRAG_TRACKER_LOGTAG, "--- buildBitmap " + sx + + " " + sy + " " + w + " " + h); + } + mProxy.onBitmapChange(bm); + } + } + + /** @hide */ + public static class DragTracker { + public void onStartDrag(float x, float y) {} + public boolean onStretchChange(float sx, float sy) { + // return true to have us inval the view + return false; + } + public void onStopDrag() {} + public void onBitmapChange(Bitmap bm) {} + public void onDraw(Canvas canvas) {} + } + + /** @hide */ + public DragTracker getDragTracker() { + return mDragTracker; + } + + /** @hide */ + public void setDragTracker(DragTracker tracker) { + mDragTracker = tracker; + } + + private DragTracker mDragTracker; + private DragTrackerHandler mDragTrackerHandler; + @Override public boolean onTouchEvent(MotionEvent ev) { if (mNativeClass == 0 || !isClickable() || !isLongClickable()) { @@ -3963,6 +4131,10 @@ public class WebView extends AbsoluteLayout mLastTouchTime = eventTime; mVelocityTracker = VelocityTracker.obtain(); mSnapScrollMode = SNAP_NONE; + if (mDragTracker != null) { + mDragTrackerHandler = new DragTrackerHandler(x, y, + mDragTracker); + } break; } case MotionEvent.ACTION_MOVE: { @@ -4132,6 +4304,10 @@ public class WebView extends AbsoluteLayout } } + if (mDragTrackerHandler != null) { + mDragTrackerHandler.dragTo(x, y); + } + if (keepScrollBarsVisible) { if (mHeldMotionless != MOTIONLESS_TRUE) { mHeldMotionless = MOTIONLESS_TRUE; @@ -4147,6 +4323,10 @@ public class WebView extends AbsoluteLayout break; } case MotionEvent.ACTION_UP: { + if (mDragTrackerHandler != null) { + mDragTrackerHandler.stopDrag(); + mDragTrackerHandler = null; + } mLastTouchUpTime = eventTime; switch (mTouchMode) { case TOUCH_DOUBLE_TAP_MODE: // double tap @@ -4237,6 +4417,10 @@ public class WebView extends AbsoluteLayout break; } case MotionEvent.ACTION_CANCEL: { + if (mDragTrackerHandler != null) { + mDragTrackerHandler.stopDrag(); + mDragTrackerHandler = null; + } // we also use mVelocityTracker == null to tell us that we are // not "moving around", so we can take the slower/prettier // mode in the drawing code