Merge "Initial support for view state serialization"
This commit is contained in:
80
core/java/android/webkit/ViewStateSerializer.java
Normal file
80
core/java/android/webkit/ViewStateSerializer.java
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 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() {}
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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();
|
||||
@@ -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
|
||||
@@ -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()) {
|
||||
@@ -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:
|
||||
@@ -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.
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user