Loading core/java/android/webkit/ViewStateSerializer.java 0 → 100644 +80 −0 Original line number Diff line number Diff line /* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.webkit; import android.graphics.Point; import android.graphics.Rect; import android.graphics.Region; import android.webkit.WebViewCore.DrawData; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; /** * @hide */ class ViewStateSerializer { private static final int WORKING_STREAM_STORAGE = 16 * 1024; static final int VERSION = 1; static boolean serializeViewState(OutputStream stream, WebView web) throws IOException { DataOutputStream dos = new DataOutputStream(stream); dos.writeInt(VERSION); dos.writeInt(web.getContentWidth()); dos.writeInt(web.getContentHeight()); return nativeSerializeViewState(web.getBaseLayer(), dos, new byte[WORKING_STREAM_STORAGE]); } static DrawData deserializeViewState(InputStream stream, WebView web) throws IOException { DataInputStream dis = new DataInputStream(stream); int version = dis.readInt(); if (version != VERSION) { throw new IOException("Unexpected version: " + version); } int contentWidth = dis.readInt(); int contentHeight = dis.readInt(); int baseLayer = nativeDeserializeViewState(dis, new byte[WORKING_STREAM_STORAGE]); final WebViewCore.DrawData draw = new WebViewCore.DrawData(); draw.mViewState = new WebViewCore.ViewState(); int viewWidth = web.getViewWidth(); int viewHeight = web.getViewHeightWithTitle() - web.getTitleHeight(); draw.mViewSize = new Point(viewWidth, viewHeight); draw.mContentSize = new Point(contentWidth, contentHeight); draw.mViewState.mDefaultScale = web.getDefaultZoomScale(); draw.mBaseLayer = baseLayer; draw.mInvalRegion = new Region(0, 0, contentWidth, contentHeight); return draw; } private static native boolean nativeSerializeViewState(int baseLayer, OutputStream stream, byte[] storage); // Returns a pointer to the BaseLayer private static native int nativeDeserializeViewState( InputStream stream, byte[] storage); private ViewStateSerializer() {} } core/java/android/webkit/WebView.java +110 −61 Original line number Diff line number Diff line Loading @@ -84,6 +84,7 @@ import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputMethodManager; import android.webkit.WebTextView.AutoCompleteAdapter; import android.webkit.WebViewCore.DrawData; import android.webkit.WebViewCore.EventHub; import android.webkit.WebViewCore.TouchEventData; import android.webkit.WebViewCore.TouchHighlightData; Loading @@ -102,6 +103,9 @@ import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.URLDecoder; import java.util.ArrayList; import java.util.HashMap; Loading Loading @@ -1400,7 +1404,7 @@ public class WebView extends AbsoluteLayout return getViewHeightWithTitle() - getVisibleTitleHeight(); } private int getViewHeightWithTitle() { int getViewHeightWithTitle() { int height = getHeight(); if (isHorizontalScrollBarEnabled() && !mOverlayHorizontalScrollbar) { height -= getHorizontalScrollbarHeight(); Loading Loading @@ -1785,6 +1789,42 @@ public class WebView extends AbsoluteLayout return true; } /** * Saves the view data to the output stream. The output is highly * version specific, and may not be able to be loaded by newer versions * of WebView. * @param stream The {@link OutputStream} to save to * @return True if saved successfully * @hide */ public boolean saveViewState(OutputStream stream) { try { return ViewStateSerializer.serializeViewState(stream, this); } catch (IOException e) { Log.w(LOGTAG, "Failed to saveViewState", e); } return false; } /** * Loads the view data from the input stream. See * {@link #saveViewState(OutputStream)} for more information. * @param stream The {@link InputStream} to load from * @return True if loaded successfully * @hide */ public boolean loadViewState(InputStream stream) { try { mWebViewCore.sendMessage(EventHub.CLEAR_CONTENT); DrawData draw = ViewStateSerializer.deserializeViewState(stream, this); setNewPicture(draw); return true; } catch (IOException e) { Log.w(LOGTAG, "Failed to loadViewState", e); } return false; } /** * Restore the state of this WebView from the given map used in * {@link android.app.Activity#onRestoreInstanceState}. This method should Loading Loading @@ -4192,6 +4232,10 @@ public class WebView extends AbsoluteLayout } } int getBaseLayer() { return nativeGetBaseLayer(); } private void onZoomAnimationStart() { // If it is in password mode, turn it off so it does not draw misplaced. if (inEditingMode() && nativeFocusCandidateIsPassword()) { Loading Loading @@ -7966,66 +8010,7 @@ public class WebView extends AbsoluteLayout case NEW_PICTURE_MSG_ID: { // called for new content final WebViewCore.DrawData draw = (WebViewCore.DrawData) msg.obj; WebViewCore.ViewState viewState = draw.mViewState; boolean isPictureAfterFirstLayout = viewState != null; setBaseLayer(draw.mBaseLayer, draw.mInvalRegion, getSettings().getShowVisualIndicator(), isPictureAfterFirstLayout); final Point viewSize = draw.mViewSize; if (isPictureAfterFirstLayout) { // Reset the last sent data here since dealing with new page. mLastWidthSent = 0; mZoomManager.onFirstLayout(draw); if (!mDrawHistory) { // Do not send the scroll event for this particular // scroll message. Note that a scroll event may // still be fired if the user scrolls before the // message can be handled. mSendScrollEvent = false; setContentScrollTo(viewState.mScrollX, viewState.mScrollY); mSendScrollEvent = true; // 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 // WebCore matches the view size of the picture we just // received in the fixed dimension. final boolean updateLayout = viewSize.x == mLastWidthSent && viewSize.y == mLastHeightSent; // Don't send scroll event for picture coming from webkit, // since the new picture may cause a scroll event to override // the saved history scroll position. mSendScrollEvent = false; recordNewContentSize(draw.mContentSize.x, draw.mContentSize.y, updateLayout); mSendScrollEvent = true; if (DebugFlags.WEB_VIEW) { Rect b = draw.mInvalRegion.getBounds(); Log.v(LOGTAG, "NEW_PICTURE_MSG_ID {" + b.left+","+b.top+","+b.right+","+b.bottom+"}"); } invalidateContentRect(draw.mInvalRegion.getBounds()); if (mPictureListener != null) { mPictureListener.onNewPicture(WebView.this, capturePicture()); } // update the zoom information based on the new picture mZoomManager.onNewPicture(draw); if (draw.mFocusSizeChanged && inEditingMode()) { mFocusSizeChanged = true; } if (isPictureAfterFirstLayout) { mViewManager.postReadyToDrawAll(); } setNewPicture(draw); break; } case WEBCORE_INITIALIZED_MSG_ID: Loading Loading @@ -8344,6 +8329,69 @@ public class WebView extends AbsoluteLayout } } void setNewPicture(final WebViewCore.DrawData draw) { WebViewCore.ViewState viewState = draw.mViewState; boolean isPictureAfterFirstLayout = viewState != null; setBaseLayer(draw.mBaseLayer, draw.mInvalRegion, getSettings().getShowVisualIndicator(), isPictureAfterFirstLayout); final Point viewSize = draw.mViewSize; if (isPictureAfterFirstLayout) { // Reset the last sent data here since dealing with new page. mLastWidthSent = 0; mZoomManager.onFirstLayout(draw); if (!mDrawHistory) { // Do not send the scroll event for this particular // scroll message. Note that a scroll event may // still be fired if the user scrolls before the // message can be handled. mSendScrollEvent = false; setContentScrollTo(viewState.mScrollX, viewState.mScrollY); mSendScrollEvent = true; // 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 // WebCore matches the view size of the picture we just // received in the fixed dimension. final boolean updateLayout = viewSize.x == mLastWidthSent && viewSize.y == mLastHeightSent; // Don't send scroll event for picture coming from webkit, // since the new picture may cause a scroll event to override // the saved history scroll position. mSendScrollEvent = false; recordNewContentSize(draw.mContentSize.x, draw.mContentSize.y, updateLayout); mSendScrollEvent = true; if (DebugFlags.WEB_VIEW) { Rect b = draw.mInvalRegion.getBounds(); Log.v(LOGTAG, "NEW_PICTURE_MSG_ID {" + b.left+","+b.top+","+b.right+","+b.bottom+"}"); } invalidateContentRect(draw.mInvalRegion.getBounds()); if (mPictureListener != null) { mPictureListener.onNewPicture(WebView.this, capturePicture()); } // update the zoom information based on the new picture mZoomManager.onNewPicture(draw); if (draw.mFocusSizeChanged && inEditingMode()) { mFocusSizeChanged = true; } if (isPictureAfterFirstLayout) { mViewManager.postReadyToDrawAll(); } } /** * Used when receiving messages for REQUEST_KEYBOARD_WITH_SELECTION_MSG_ID * and UPDATE_TEXT_SELECTION_MSG_ID. Update the selection of WebTextView. Loading Loading @@ -9046,6 +9094,7 @@ public class WebView extends AbsoluteLayout private native void nativeSetHeightCanMeasure(boolean measure); private native void nativeSetBaseLayer(int layer, Region invalRegion, boolean showVisualIndicator, boolean isPictureAfterFirstLayout); private native int nativeGetBaseLayer(); private native void nativeShowCursorTimed(); private native void nativeReplaceBaseContent(int content); private native void nativeCopyBaseContentToPicture(Picture pict); Loading Loading
core/java/android/webkit/ViewStateSerializer.java 0 → 100644 +80 −0 Original line number Diff line number Diff line /* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.webkit; import android.graphics.Point; import android.graphics.Rect; import android.graphics.Region; import android.webkit.WebViewCore.DrawData; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; /** * @hide */ class ViewStateSerializer { private static final int WORKING_STREAM_STORAGE = 16 * 1024; static final int VERSION = 1; static boolean serializeViewState(OutputStream stream, WebView web) throws IOException { DataOutputStream dos = new DataOutputStream(stream); dos.writeInt(VERSION); dos.writeInt(web.getContentWidth()); dos.writeInt(web.getContentHeight()); return nativeSerializeViewState(web.getBaseLayer(), dos, new byte[WORKING_STREAM_STORAGE]); } static DrawData deserializeViewState(InputStream stream, WebView web) throws IOException { DataInputStream dis = new DataInputStream(stream); int version = dis.readInt(); if (version != VERSION) { throw new IOException("Unexpected version: " + version); } int contentWidth = dis.readInt(); int contentHeight = dis.readInt(); int baseLayer = nativeDeserializeViewState(dis, new byte[WORKING_STREAM_STORAGE]); final WebViewCore.DrawData draw = new WebViewCore.DrawData(); draw.mViewState = new WebViewCore.ViewState(); int viewWidth = web.getViewWidth(); int viewHeight = web.getViewHeightWithTitle() - web.getTitleHeight(); draw.mViewSize = new Point(viewWidth, viewHeight); draw.mContentSize = new Point(contentWidth, contentHeight); draw.mViewState.mDefaultScale = web.getDefaultZoomScale(); draw.mBaseLayer = baseLayer; draw.mInvalRegion = new Region(0, 0, contentWidth, contentHeight); return draw; } private static native boolean nativeSerializeViewState(int baseLayer, OutputStream stream, byte[] storage); // Returns a pointer to the BaseLayer private static native int nativeDeserializeViewState( InputStream stream, byte[] storage); private ViewStateSerializer() {} }
core/java/android/webkit/WebView.java +110 −61 Original line number Diff line number Diff line Loading @@ -84,6 +84,7 @@ import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputMethodManager; import android.webkit.WebTextView.AutoCompleteAdapter; import android.webkit.WebViewCore.DrawData; import android.webkit.WebViewCore.EventHub; import android.webkit.WebViewCore.TouchEventData; import android.webkit.WebViewCore.TouchHighlightData; Loading @@ -102,6 +103,9 @@ import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.URLDecoder; import java.util.ArrayList; import java.util.HashMap; Loading Loading @@ -1400,7 +1404,7 @@ public class WebView extends AbsoluteLayout return getViewHeightWithTitle() - getVisibleTitleHeight(); } private int getViewHeightWithTitle() { int getViewHeightWithTitle() { int height = getHeight(); if (isHorizontalScrollBarEnabled() && !mOverlayHorizontalScrollbar) { height -= getHorizontalScrollbarHeight(); Loading Loading @@ -1785,6 +1789,42 @@ public class WebView extends AbsoluteLayout return true; } /** * Saves the view data to the output stream. The output is highly * version specific, and may not be able to be loaded by newer versions * of WebView. * @param stream The {@link OutputStream} to save to * @return True if saved successfully * @hide */ public boolean saveViewState(OutputStream stream) { try { return ViewStateSerializer.serializeViewState(stream, this); } catch (IOException e) { Log.w(LOGTAG, "Failed to saveViewState", e); } return false; } /** * Loads the view data from the input stream. See * {@link #saveViewState(OutputStream)} for more information. * @param stream The {@link InputStream} to load from * @return True if loaded successfully * @hide */ public boolean loadViewState(InputStream stream) { try { mWebViewCore.sendMessage(EventHub.CLEAR_CONTENT); DrawData draw = ViewStateSerializer.deserializeViewState(stream, this); setNewPicture(draw); return true; } catch (IOException e) { Log.w(LOGTAG, "Failed to loadViewState", e); } return false; } /** * Restore the state of this WebView from the given map used in * {@link android.app.Activity#onRestoreInstanceState}. This method should Loading Loading @@ -4192,6 +4232,10 @@ public class WebView extends AbsoluteLayout } } int getBaseLayer() { return nativeGetBaseLayer(); } private void onZoomAnimationStart() { // If it is in password mode, turn it off so it does not draw misplaced. if (inEditingMode() && nativeFocusCandidateIsPassword()) { Loading Loading @@ -7966,66 +8010,7 @@ public class WebView extends AbsoluteLayout case NEW_PICTURE_MSG_ID: { // called for new content final WebViewCore.DrawData draw = (WebViewCore.DrawData) msg.obj; WebViewCore.ViewState viewState = draw.mViewState; boolean isPictureAfterFirstLayout = viewState != null; setBaseLayer(draw.mBaseLayer, draw.mInvalRegion, getSettings().getShowVisualIndicator(), isPictureAfterFirstLayout); final Point viewSize = draw.mViewSize; if (isPictureAfterFirstLayout) { // Reset the last sent data here since dealing with new page. mLastWidthSent = 0; mZoomManager.onFirstLayout(draw); if (!mDrawHistory) { // Do not send the scroll event for this particular // scroll message. Note that a scroll event may // still be fired if the user scrolls before the // message can be handled. mSendScrollEvent = false; setContentScrollTo(viewState.mScrollX, viewState.mScrollY); mSendScrollEvent = true; // 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 // WebCore matches the view size of the picture we just // received in the fixed dimension. final boolean updateLayout = viewSize.x == mLastWidthSent && viewSize.y == mLastHeightSent; // Don't send scroll event for picture coming from webkit, // since the new picture may cause a scroll event to override // the saved history scroll position. mSendScrollEvent = false; recordNewContentSize(draw.mContentSize.x, draw.mContentSize.y, updateLayout); mSendScrollEvent = true; if (DebugFlags.WEB_VIEW) { Rect b = draw.mInvalRegion.getBounds(); Log.v(LOGTAG, "NEW_PICTURE_MSG_ID {" + b.left+","+b.top+","+b.right+","+b.bottom+"}"); } invalidateContentRect(draw.mInvalRegion.getBounds()); if (mPictureListener != null) { mPictureListener.onNewPicture(WebView.this, capturePicture()); } // update the zoom information based on the new picture mZoomManager.onNewPicture(draw); if (draw.mFocusSizeChanged && inEditingMode()) { mFocusSizeChanged = true; } if (isPictureAfterFirstLayout) { mViewManager.postReadyToDrawAll(); } setNewPicture(draw); break; } case WEBCORE_INITIALIZED_MSG_ID: Loading Loading @@ -8344,6 +8329,69 @@ public class WebView extends AbsoluteLayout } } void setNewPicture(final WebViewCore.DrawData draw) { WebViewCore.ViewState viewState = draw.mViewState; boolean isPictureAfterFirstLayout = viewState != null; setBaseLayer(draw.mBaseLayer, draw.mInvalRegion, getSettings().getShowVisualIndicator(), isPictureAfterFirstLayout); final Point viewSize = draw.mViewSize; if (isPictureAfterFirstLayout) { // Reset the last sent data here since dealing with new page. mLastWidthSent = 0; mZoomManager.onFirstLayout(draw); if (!mDrawHistory) { // Do not send the scroll event for this particular // scroll message. Note that a scroll event may // still be fired if the user scrolls before the // message can be handled. mSendScrollEvent = false; setContentScrollTo(viewState.mScrollX, viewState.mScrollY); mSendScrollEvent = true; // 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 // WebCore matches the view size of the picture we just // received in the fixed dimension. final boolean updateLayout = viewSize.x == mLastWidthSent && viewSize.y == mLastHeightSent; // Don't send scroll event for picture coming from webkit, // since the new picture may cause a scroll event to override // the saved history scroll position. mSendScrollEvent = false; recordNewContentSize(draw.mContentSize.x, draw.mContentSize.y, updateLayout); mSendScrollEvent = true; if (DebugFlags.WEB_VIEW) { Rect b = draw.mInvalRegion.getBounds(); Log.v(LOGTAG, "NEW_PICTURE_MSG_ID {" + b.left+","+b.top+","+b.right+","+b.bottom+"}"); } invalidateContentRect(draw.mInvalRegion.getBounds()); if (mPictureListener != null) { mPictureListener.onNewPicture(WebView.this, capturePicture()); } // update the zoom information based on the new picture mZoomManager.onNewPicture(draw); if (draw.mFocusSizeChanged && inEditingMode()) { mFocusSizeChanged = true; } if (isPictureAfterFirstLayout) { mViewManager.postReadyToDrawAll(); } } /** * Used when receiving messages for REQUEST_KEYBOARD_WITH_SELECTION_MSG_ID * and UPDATE_TEXT_SELECTION_MSG_ID. Update the selection of WebTextView. Loading Loading @@ -9046,6 +9094,7 @@ public class WebView extends AbsoluteLayout private native void nativeSetHeightCanMeasure(boolean measure); private native void nativeSetBaseLayer(int layer, Region invalRegion, boolean showVisualIndicator, boolean isPictureAfterFirstLayout); private native int nativeGetBaseLayer(); private native void nativeShowCursorTimed(); private native void nativeReplaceBaseContent(int content); private native void nativeCopyBaseContentToPicture(Picture pict); Loading