Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 396dbf45 authored by Android (Google) Code Review's avatar Android (Google) Code Review
Browse files

Merge change 9175

* changes:
  Fix 2016808. We used to send the new scale/scroll info to the UI thread after WebCore finish the first layout. As the picture in the UI thread is still the previous one, if there is a UI update happened before we generate the new picture, the new scale/scroll will be applied to the old picture.
parents 5483c506 ef347ef9
Loading
Loading
Loading
Loading
+49 −94
Original line number Diff line number Diff line
@@ -206,11 +206,6 @@ public class WebView extends AbsoluteLayout

    static final String LOGTAG = "webview";

    static class ScaleLimitData {
        int mMinScale;
        int mMaxScale;
    }

    private static class ExtendedZoomControls extends FrameLayout {
        public ExtendedZoomControls(Context context, AttributeSet attrs) {
            super(context, attrs);
@@ -472,7 +467,6 @@ public class WebView extends AbsoluteLayout
    static final int UPDATE_TEXT_ENTRY_MSG_ID           = 15;
    static final int WEBCORE_INITIALIZED_MSG_ID         = 16;
    static final int UPDATE_TEXTFIELD_TEXT_MSG_ID       = 17;
    static final int DID_FIRST_LAYOUT_MSG_ID            = 18;
    static final int MOVE_OUT_OF_PLUGIN                 = 19;
    static final int CLEAR_TEXT_ENTRY                   = 20;

@@ -502,7 +496,7 @@ public class WebView extends AbsoluteLayout
        "UPDATE_TEXT_ENTRY_MSG_ID", //       = 15;
        "WEBCORE_INITIALIZED_MSG_ID", //     = 16;
        "UPDATE_TEXTFIELD_TEXT_MSG_ID", //   = 17;
        "DID_FIRST_LAYOUT_MSG_ID", //        = 18;
        "18", //        = 18;
        "MOVE_OUT_OF_PLUGIN", //             = 19;
        "CLEAR_TEXT_ENTRY", //               = 20;
        "21", //                             = 21;
@@ -1892,6 +1886,13 @@ public class WebView extends AbsoluteLayout
        r.bottom = viewToContent(r.bottom);
    }

    static class ViewSizeData {
        int mWidth;
        int mHeight;
        int mTextWrapWidth;
        float mScale;
    }

    /**
     * Compute unzoomed width and height, and if they differ from the last
     * values we sent, send them to webkit (to be used has new viewport)
@@ -1899,7 +1900,8 @@ public class WebView extends AbsoluteLayout
     * @return true if new values were sent
     */
    private boolean sendViewSizeZoom() {
        int newWidth = Math.round(getViewWidth() * mInvActualScale);
        int viewWidth = getViewWidth();
        int newWidth = Math.round(viewWidth * mInvActualScale);
        int newHeight = Math.round(getViewHeight() * mInvActualScale);
        /*
         * Because the native side may have already done a layout before the
@@ -1914,8 +1916,16 @@ public class WebView extends AbsoluteLayout
        }
        // Avoid sending another message if the dimensions have not changed.
        if (newWidth != mLastWidthSent || newHeight != mLastHeightSent) {
            mWebViewCore.sendMessage(EventHub.VIEW_SIZE_CHANGED,
                    newWidth, newHeight, new Float(mActualScale));
            ViewSizeData data = new ViewSizeData();
            data.mWidth = newWidth;
            data.mHeight = newHeight;
            // while in zoom overview mode, the text are wrapped to the screen
            // width matching mLastScale. So that we don't trigger re-flow while
            // toggling between overview mode and normal mode.
            data.mTextWrapWidth = mInZoomOverview ? Math.round(viewWidth
                    / mLastScale) : newWidth;
            data.mScale = mActualScale;
            mWebViewCore.sendMessage(EventHub.VIEW_SIZE_CHANGED, data);
            mLastWidthSent = newWidth;
            mLastHeightSent = newHeight;
            return true;
@@ -3877,11 +3887,6 @@ public class WebView extends AbsoluteLayout
                    if (!mDragFromTextInput) {
                        nativeHideCursor();
                    }
                    // remove the zoom anchor if there is any
                    if (mZoomScale != 0) {
                        mWebViewCore
                                .sendMessage(EventHub.SET_SNAP_ANCHOR, 0, 0);
                    }
                    WebSettings settings = getSettings();
                    if (settings.supportZoom() && !mInZoomOverview
                            && settings.getBuiltInZoomControls()
@@ -4982,15 +4987,35 @@ public class WebView extends AbsoluteLayout
                    final WebViewCore.DrawData draw =
                            (WebViewCore.DrawData) msg.obj;
                    final Point viewSize = draw.mViewPoint;
                    if (mZoomScale > 0) {
                        // use the same logic in sendViewSizeZoom() to make sure
                        // the mZoomScale has matched the viewSize so that we
                        // can clear mZoomScale
                        if (Math.round(viewWidth / mZoomScale) == viewSize.x) {
                            mZoomScale = 0;
                            mWebViewCore.sendMessage(EventHub.SET_SNAP_ANCHOR,
                                    0, 0);
                    boolean useWideViewport =
                            mWebViewCore.getSettings().getUseWideViewPort();
                    WebViewCore.RestoreState restoreState = draw.mRestoreState;
                    if (restoreState != null) {
                        mInZoomOverview = false;
                        mLastScale = restoreState.mTextWrapScale;
                        if (restoreState.mMinScale == 0) {
                            mMinZoomScale = DEFAULT_MIN_ZOOM_SCALE;
                            mMinZoomScaleFixed = false;
                        } else {
                            mMinZoomScale = restoreState.mMinScale;
                            mMinZoomScaleFixed = true;
                        }
                        if (restoreState.mMaxScale == 0) {
                            mMaxZoomScale = DEFAULT_MAX_ZOOM_SCALE;
                        } else {
                            mMaxZoomScale = restoreState.mMaxScale;
                        }
                        if (useWideViewport && restoreState.mViewScale == 0) {
                            mInZoomOverview = ENABLE_DOUBLETAP_ZOOM;
                        }
                        setNewZoomScale(mLastScale, false);
                        setContentScrollTo(restoreState.mScrollX,
                                restoreState.mScrollY);
                        // As we are on a new page, remove the WebTextView. This
                        // is necessary for page loads driven by webkit, and in
                        // particular when the user was on a password field, so
                        // the WebTextView was visible.
                        clearTextEntry();
                    }
                    // We update the layout (i.e. request a layout from the
                    // view system) if the last view size that we sent to
@@ -5009,7 +5034,7 @@ public class WebView extends AbsoluteLayout
                    if (mPictureListener != null) {
                        mPictureListener.onNewPicture(WebView.this, capturePicture());
                    }
                    if (mWebViewCore.getSettings().getUseWideViewPort()) {
                    if (useWideViewport) {
                        mZoomOverviewWidth = Math.max(draw.mMinPrefWidth,
                                draw.mViewPoint.x);
                    }
@@ -5056,76 +5081,6 @@ public class WebView extends AbsoluteLayout
                        }
                    }
                    break;
                case DID_FIRST_LAYOUT_MSG_ID: {
                    if (mNativeClass == 0) {
                        break;
                    }
                    ScaleLimitData scaleLimit = (ScaleLimitData) msg.obj;
                    int minScale = scaleLimit.mMinScale;
                    if (minScale == 0) {
                        mMinZoomScale = DEFAULT_MIN_ZOOM_SCALE;
                        mMinZoomScaleFixed = false;
                    } else {
                        mMinZoomScale = (float) (minScale / 100.0);
                        mMinZoomScaleFixed = true;
                    }
                    int maxScale = scaleLimit.mMaxScale;
                    if (maxScale == 0) {
                        mMaxZoomScale = DEFAULT_MAX_ZOOM_SCALE;
                    } else {
                        mMaxZoomScale = (float) (maxScale / 100.0);
                    }
                    // If history Picture is drawn, don't update zoomWidth
                    if (mDrawHistory) {
                        break;
                    }
                    int width = getViewWidth();
                    if (width == 0) {
                        break;
                    }
                    final WebSettings settings = mWebViewCore.getSettings();
                    int initialScale = msg.arg1;
                    int viewportWidth = msg.arg2;
                    // start a new page with DEFAULT_SCALE zoom scale.
                    float scale = mDefaultScale;
                    mInZoomOverview = false;
                    if (mInitialScale > 0) {
                        scale = mInitialScale / 100.0f;
                    } else  {
                        if (initialScale == -1) break;
                        if (settings.getUseWideViewPort()) {
                            // force viewSizeChanged by setting mLastWidthSent
                            // to 0
                            mLastWidthSent = 0;
                        }
                        if (initialScale == 0) {
                            // if viewportWidth is defined and it is smaller
                            // than the view width, zoom in to fill the view
                            if (viewportWidth > 0 && viewportWidth < width) {
                                scale = (float) width / viewportWidth;
                            } else {
                                if (settings.getUseWideViewPort()) {
                                    mInZoomOverview = ENABLE_DOUBLETAP_ZOOM;
                                }
                            }
                        } else if (initialScale < 0) {
                            // this should only happen when
                            // ENABLE_DOUBLETAP_ZOOM is true
                            mInZoomOverview = true;
                            scale = -initialScale / 100.0f;
                        } else {
                            scale = initialScale / 100.0f;
                        }
                    }
                    mLastScale = scale;
                    setNewZoomScale(scale, false);
                    // As we are on a new page, remove the WebTextView.  This
                    // is necessary for page loads driven by webkit, and in
                    // particular when the user was on a password field, so
                    // the WebTextView was visible.
                    clearTextEntry();
                    break;
                }
                case MOVE_OUT_OF_PLUGIN:
                    if (nativePluginEatsNavKey()) {
                        navHandledKey(msg.arg1, 1, false, 0, true);
+111 −82
Original line number Diff line number Diff line
@@ -443,10 +443,6 @@ final class WebViewCore {

    private native void nativeUpdateFrameCache();

    private native void nativeSetSnapAnchor(int x, int y);

    private native void nativeSnapToAnchor();

    private native void nativeSetBackgroundColor(int color);

    private native void nativeDumpDomTree(boolean useFile);
@@ -674,7 +670,7 @@ final class WebViewCore {
            "CLICK", // = 118;
            "SET_NETWORK_STATE", // = 119;
            "DOC_HAS_IMAGES", // = 120;
            "SET_SNAP_ANCHOR", // = 121;
            "121", // = 121;
            "DELETE_SELECTION", // = 122;
            "LISTBOX_CHOICES", // = 123;
            "SINGLE_LISTBOX_CHOICE", // = 124;
@@ -725,7 +721,6 @@ final class WebViewCore {
        static final int CLICK = 118;
        static final int SET_NETWORK_STATE = 119;
        static final int DOC_HAS_IMAGES = 120;
        static final int SET_SNAP_ANCHOR = 121;
        static final int DELETE_SELECTION = 122;
        static final int LISTBOX_CHOICES = 123;
        static final int SINGLE_LISTBOX_CHOICE = 124;
@@ -904,11 +899,13 @@ final class WebViewCore {
                            nativeClick(msg.arg1, msg.arg2);
                            break;

                        case VIEW_SIZE_CHANGED:
                            viewSizeChanged(msg.arg1, msg.arg2,
                                    ((Float) msg.obj).floatValue());
                        case VIEW_SIZE_CHANGED: {
                            WebView.ViewSizeData data =
                                    (WebView.ViewSizeData) msg.obj;
                            viewSizeChanged(data.mWidth, data.mHeight,
                                    data.mTextWrapWidth, data.mScale);
                            break;

                        }
                        case SET_SCROLL_OFFSET:
                            // note: these are in document coordinates
                            // (inv-zoom)
@@ -1107,10 +1104,6 @@ final class WebViewCore {
                            imageResult.sendToTarget();
                            break;

                        case SET_SNAP_ANCHOR:
                            nativeSetSnapAnchor(msg.arg1, msg.arg2);
                            break;

                        case DELETE_SELECTION:
                            DeleteSelectionData deleteSelectionData
                                    = (DeleteSelectionData) msg.obj;
@@ -1401,16 +1394,20 @@ final class WebViewCore {
    // These values are used to avoid requesting a layout based on old values
    private int mCurrentViewWidth = 0;
    private int mCurrentViewHeight = 0;
    private float mCurrentViewScale = 1.0f;

    // notify webkit that our virtual view size changed size (after inv-zoom)
    private void viewSizeChanged(int w, int h, float scale) {
        if (DebugFlags.WEB_VIEW_CORE) Log.v(LOGTAG, "CORE onSizeChanged");
    private void viewSizeChanged(int w, int h, int textwrapWidth, float scale) {
        if (DebugFlags.WEB_VIEW_CORE) {
            Log.v(LOGTAG, "viewSizeChanged w=" + w + "; h=" + h
                    + "; textwrapWidth=" + textwrapWidth + "; scale=" + scale);
        }
        if (w == 0) {
            Log.w(LOGTAG, "skip viewSizeChanged as w is 0");
            return;
        }
        int width = w;
        if (mSettings.getUseWideViewPort()) {
            int width;
            if (mViewportWidth == -1) {
                if (mSettings.getLayoutAlgorithm() ==
                        WebSettings.LayoutAlgorithm.NORMAL) {
@@ -1433,19 +1430,14 @@ final class WebViewCore {
            } else {
                width = Math.max(w, mViewportWidth);
            }
            // while in zoom overview mode, the text are wrapped to the screen
            // width matching mWebView.mLastScale. So that we don't trigger
            // re-flow while toggling between overview mode and normal mode.
            nativeSetSize(width, Math.round((float) width * h / w),
                    Math.round(mWebView.mInZoomOverview ? w * scale
                            / mWebView.mLastScale : w), scale, w, h);
        } else {
            nativeSetSize(w, h, w, scale, w, h);
        }
        nativeSetSize(width, width == w ? h : Math.round((float) width * h / w),
                textwrapWidth, scale, w, h);
        // Remember the current width and height
        boolean needInvalidate = (mCurrentViewWidth == 0);
        mCurrentViewWidth = w;
        mCurrentViewHeight = h;
        mCurrentViewScale = scale;
        if (needInvalidate) {
            // ensure {@link #webkitDraw} is called as we were blocking in
            // {@link #contentDraw} when mCurrentViewWidth is 0
@@ -1490,15 +1482,30 @@ final class WebViewCore {
    // Used to end scale+scroll mode, accessed by both threads
    boolean mEndScaleZoom = false;

    public class DrawData {
        public DrawData() {
    // mRestoreState is set in didFirstLayout(), and reset in the next
    // webkitDraw after passing it to the UI thread.
    private RestoreState mRestoreState = null;

    static class RestoreState {
        float mMinScale;
        float mMaxScale;
        float mViewScale;
        float mTextWrapScale;
        int mScrollX;
        int mScrollY;
    }

    static class DrawData {
        DrawData() {
            mInvalRegion = new Region();
            mWidthHeight = new Point();
        }
        public Region mInvalRegion;
        public Point mViewPoint;
        public Point mWidthHeight;
        public int mMinPrefWidth;
        Region mInvalRegion;
        Point mViewPoint;
        Point mWidthHeight;
        int mMinPrefWidth;
        RestoreState mRestoreState; // only non-null if it is for the first
                                    // picture set after the first layout
    }

    private void webkitDraw() {
@@ -1517,6 +1524,10 @@ final class WebViewCore {
            if (WebView.ENABLE_DOUBLETAP_ZOOM && mSettings.getUseWideViewPort()) {
                draw.mMinPrefWidth = nativeGetContentMinPrefWidth();
            }
            if (mRestoreState != null) {
                draw.mRestoreState = mRestoreState;
                mRestoreState = null;
            }
            if (DebugFlags.WEB_VIEW_CORE) Log.v(LOGTAG, "webkitDraw NEW_PICTURE_MSG_ID");
            Message.obtain(mWebView.mPrivateHandler,
                    WebView.NEW_PICTURE_MSG_ID, draw).sendToTarget();
@@ -1527,9 +1538,6 @@ final class WebViewCore {
                        mWebkitScrollY).sendToTarget();
                mWebkitScrollX = mWebkitScrollY = 0;
            }
            // nativeSnapToAnchor() needs to be called after NEW_PICTURE_MSG_ID
            // is sent, so that scroll will be based on the new content size.
            nativeSnapToAnchor();
        }
    }

@@ -1751,17 +1759,8 @@ final class WebViewCore {

    // called by JNI
    private void didFirstLayout(boolean standardLoad) {
        // Trick to ensure that the Picture has the exact height for the content
        // by forcing to layout with 0 height after the page is ready, which is
        // indicated by didFirstLayout. This is essential to get rid of the
        // white space in the GMail which uses WebView for message view.
        if (mWebView != null && mWebView.mHeightCanMeasure) {
            mWebView.mLastHeightSent = 0;
            // Send a negative scale to indicate that WebCore should reuse the
            // current scale
            mEventHub.sendMessage(Message.obtain(null,
                    EventHub.VIEW_SIZE_CHANGED, mWebView.mLastWidthSent,
                    mWebView.mLastHeightSent, -1.0f));
        if (DebugFlags.WEB_VIEW_CORE) {
            Log.v(LOGTAG, "didFirstLayout standardLoad =" + standardLoad);
        }

        mBrowserFrame.didFirstLayout();
@@ -1769,6 +1768,9 @@ final class WebViewCore {
        // reset the scroll position as it is a new page now
        mWebkitScrollX = mWebkitScrollY = 0;

        // for non-standard load, we only adjust scale if mRestoredScale > 0
        if (mWebView == null || (mRestoredScale == 0 && !standardLoad)) return;

        // set the viewport settings from WebKit
        setViewportSettingsFromNative();

@@ -1820,48 +1822,75 @@ final class WebViewCore {
        }

        // now notify webview
        if (mWebView != null) {
            WebView.ScaleLimitData scaleLimit = new WebView.ScaleLimitData();
            scaleLimit.mMinScale = mViewportMinimumScale;
            scaleLimit.mMaxScale = mViewportMaximumScale;

        int webViewWidth = Math.round(mCurrentViewWidth * mCurrentViewScale);
        mRestoreState = new RestoreState();
        mRestoreState.mMinScale = mViewportMinimumScale / 100.0f;
        mRestoreState.mMaxScale = mViewportMaximumScale / 100.0f;
        mRestoreState.mScrollX = mRestoredX;
        mRestoreState.mScrollY = mRestoredY;
        if (mRestoredScale > 0) {
                Message.obtain(mWebView.mPrivateHandler,
                        WebView.DID_FIRST_LAYOUT_MSG_ID,
                        mRestoredScreenWidthScale > 0 ?
                        -mRestoredScreenWidthScale : mRestoredScale, 0,
                        scaleLimit).sendToTarget();
            if (mRestoredScreenWidthScale > 0) {
                mRestoreState.mTextWrapScale =
                        mRestoredScreenWidthScale / 100.0f;
                // 0 will trigger WebView to turn on zoom overview mode
                mRestoreState.mViewScale = 0;
            } else {
                // if standardLoad is true, use mViewportInitialScale, otherwise
                // pass -1 to the WebView to indicate no change of the scale.
                Message.obtain(mWebView.mPrivateHandler,
                        WebView.DID_FIRST_LAYOUT_MSG_ID,
                        standardLoad ? mViewportInitialScale : -1,
                        mViewportWidth, scaleLimit).sendToTarget();
                mRestoreState.mViewScale = mRestoreState.mTextWrapScale =
                        mRestoredScale / 100.0f;
            }

            // force an early draw for quick feedback after the first layout
            if (mCurrentViewWidth != 0) {
                synchronized (this) {
                    if (mDrawIsScheduled) {
                        mEventHub.removeMessages(EventHub.WEBKIT_DRAW);
        } else {
            if (mViewportInitialScale > 0) {
                mRestoreState.mViewScale = mRestoreState.mTextWrapScale =
                        mViewportInitialScale / 100.0f;
            } else if (mViewportWidth > 0 && mViewportWidth < webViewWidth) {
                mRestoreState.mViewScale = mRestoreState.mTextWrapScale =
                        (float) webViewWidth / mViewportWidth;
            } else {
                mRestoreState.mTextWrapScale =
                        WebView.DEFAULT_SCALE_PERCENT / 100.0f;
                // 0 will trigger WebView to turn on zoom overview mode
                mRestoreState.mViewScale = 0;
            }
                    mDrawIsScheduled = true;
                    // if no restored offset, move the new page to (0, 0)
        }

        if (mWebView.mHeightCanMeasure) {
            // Trick to ensure that the Picture has the exact height for the
            // content by forcing to layout with 0 height after the page is
            // ready, which is indicated by didFirstLayout. This is essential to
            // get rid of the white space in the GMail which uses WebView for
            // message view.
            mWebView.mLastHeightSent = 0;
            // Send a negative scale to indicate that WebCore should reuse
            // the current scale
            WebView.ViewSizeData data = new WebView.ViewSizeData();
            data.mWidth = mWebView.mLastWidthSent;
            data.mHeight = 0;
            // if mHeightCanMeasure is true, getUseWideViewPort() can't be
            // true. It is safe to use mWidth for mTextWrapWidth.
            data.mTextWrapWidth = data.mWidth;
            data.mScale = -1.0f;
            mEventHub.sendMessageAtFrontOfQueue(Message.obtain(null,
                            EventHub.MESSAGE_RELAY, Message.obtain(
                                    mWebView.mPrivateHandler,
                                    WebView.SCROLL_TO_MSG_ID, mRestoredX,
                                    mRestoredY)));
                    EventHub.VIEW_SIZE_CHANGED, data));
        } else if (mSettings.getUseWideViewPort() && mCurrentViewWidth > 0) {
            WebView.ViewSizeData data = new WebView.ViewSizeData();
            // mViewScale as 0 means it is in zoom overview mode. So we don't
            // know the exact scale. If mRestoredScale is non-zero, use it;
            // otherwise just use mTextWrapScale as the initial scale.
            data.mScale = mRestoreState.mViewScale == 0
                    ? (mRestoredScale > 0 ? mRestoredScale
                            : mRestoreState.mTextWrapScale)
                    : mRestoreState.mViewScale;
            data.mWidth = Math.round(webViewWidth / data.mScale);
            data.mHeight = mCurrentViewHeight * data.mWidth
                    / mCurrentViewWidth;
            data.mTextWrapWidth = Math.round(webViewWidth
                    / mRestoreState.mTextWrapScale);
            mEventHub.sendMessageAtFrontOfQueue(Message.obtain(null,
                            EventHub.WEBKIT_DRAW));
                }
                    EventHub.VIEW_SIZE_CHANGED, data));
        }

        // reset restored offset, scale
        mRestoredX = mRestoredY = mRestoredScale = mRestoredScreenWidthScale = 0;
    }
    }

    // called by JNI
    private void restoreScale(int scale) {