FileDocCategorySizeDatePackage
WebViewCore.javaAPI DocAndroid 1.5 API66050Wed May 06 22:41:56 BST 2009android.webkit

WebViewCore

public final class WebViewCore extends Object

Fields Summary
private static final String
LOGTAG
static final boolean
DEBUG
static final boolean
LOGV_ENABLED
private WebView
mWebView
private final CallbackProxy
mCallbackProxy
private final WebSettings
mSettings
private final android.content.Context
mContext
private int
mNativeClass
private BrowserFrame
mBrowserFrame
private int
mViewportWidth
private int
mViewportHeight
private int
mViewportInitialScale
private int
mViewportMinimumScale
private int
mViewportMaximumScale
private boolean
mViewportUserScalable
private int
mRestoredScale
private int
mRestoredX
private int
mRestoredY
private int
mWebkitScrollX
private int
mWebkitScrollY
static final String
THREAD_NAME
private final EventHub
mEventHub
private static android.os.Handler
sWebCoreHandler
static final String[]
HandlerDebugString
private int
mCurrentViewWidth
private int
mCurrentViewHeight
private boolean
mDrawIsScheduled
private boolean
mSplitPictureIsScheduled
private boolean
mDrawIsPaused
boolean
mEndScaleZoom
static final int
ZOOM_BITS
static final int
SCROLL_BITS
final android.graphics.DrawFilter
mZoomFilter
final android.graphics.DrawFilter
mScrollFilter
Constructors Summary
public WebViewCore(android.content.Context context, WebView w, CallbackProxy proxy)


           
        // No need to assign this in the WebCore thread.
        mCallbackProxy = proxy;
        mWebView = w;
        // This context object is used to initialize the WebViewCore during
        // subwindow creation.
        mContext = context;

        // We need to wait for the initial thread creation before sending
        // a message to the WebCore thread.
        // XXX: This is the only time the UI thread will wait for the WebCore
        // thread!
        synchronized (WebViewCore.class) {
            if (sWebCoreHandler == null) {
                // Create a global thread and start it.
                Thread t = new Thread(new WebCoreThread());
                t.setName(THREAD_NAME);
                t.start();
                try {
                    WebViewCore.class.wait();
                } catch (InterruptedException e) {
                    Log.e(LOGTAG, "Caught exception while waiting for thread " +
                           "creation.");
                    Log.e(LOGTAG, Log.getStackTraceString(e));
                }
            }
        }
        // Create an EventHub to handle messages before and after the thread is
        // ready.
        mEventHub = new EventHub();
        // Create a WebSettings object for maintaining all settings
        mSettings = new WebSettings(mContext);
        // The WebIconDatabase needs to be initialized within the UI thread so
        // just request the instance here.
        WebIconDatabase.getInstance();
        // Send a message to initialize the WebViewCore.
        Message init = sWebCoreHandler.obtainMessage(
                WebCoreThread.INITIALIZE, this);
        sWebCoreHandler.sendMessage(init);
    
Methods Summary
voidcontentDraw()

        // don't update the Picture until we have an initial width and finish
        // the first layout
        if (mCurrentViewWidth == 0 || !mBrowserFrame.firstLayoutDone()) {
            return;
        }
        // only fire an event if this is our first request
        synchronized (this) {
            if (mDrawIsPaused || mDrawIsScheduled) {
                return;
            }
            mDrawIsScheduled = true;
            mEventHub.sendMessage(Message.obtain(null, EventHub.WEBKIT_DRAW));
        }
    
private voidcontentScrollBy(int dx, int dy, boolean animate)

        if (!mBrowserFrame.firstLayoutDone()) {
            // Will this happen? If yes, we need to do something here.
            return;
        }
        if (mWebView != null) {
            Message.obtain(mWebView.mPrivateHandler,
                    WebView.SCROLL_BY_MSG_ID, dx, dy, 
                    new Boolean(animate)).sendToTarget();
        }
    
private voidcontentScrollTo(int x, int y)

        if (!mBrowserFrame.firstLayoutDone()) {
            /*
             * WebKit restore state will be called before didFirstLayout(),
             * remember the position as it has to be applied after restoring
             * zoom factor which is controlled by screenWidth.
             */
            mRestoredX = x;
            mRestoredY = y;
            return;
        }
        if (mWebView != null) {
            Message.obtain(mWebView.mPrivateHandler,
                    WebView.SCROLL_TO_MSG_ID, x, y).sendToTarget();
        }
    
private voidcontentSpawnScrollTo(int x, int y)

        if (!mBrowserFrame.firstLayoutDone()) {
            /*
             * WebKit restore state will be called before didFirstLayout(),
             * remember the position as it has to be applied after restoring
             * zoom factor which is controlled by screenWidth.
             */
            mRestoredX = x;
            mRestoredY = y;
            return;
        }
        if (mWebView != null) {
            Message.obtain(mWebView.mPrivateHandler,
                    WebView.SPAWN_SCROLL_TO_MSG_ID, x, y).sendToTarget();
        }
    
android.graphics.PicturecopyContentPicture()

        Picture result = new Picture();
        nativeCopyContentToPicture(result);
        return result;
    
voiddestroy()
Removes pending messages and trigger a DESTROY message to send to WebCore. Called from UI thread.

        // We don't want anyone to post a message between removing pending
        // messages and sending the destroy message.
        synchronized (mEventHub) {
            mEventHub.removeMessages();
            mEventHub.sendMessageAtFrontOfQueue(
                    Message.obtain(null, EventHub.DESTROY));
            mEventHub.blockMessages();
            mWebView = null;
        }
    
private voiddidFirstLayout()

        // 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));
        }

        mBrowserFrame.didFirstLayout();

        // reset the scroll position as it is a new page now
        mWebkitScrollX = mWebkitScrollY = 0;

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

        // infer the values if they are not defined.
        if (mViewportWidth == 0) {
            if (mViewportInitialScale == 0) {
                mViewportInitialScale = 100;
            }
            if (mViewportMinimumScale == 0) {
                mViewportMinimumScale = 100;
            }
        }
        if (mViewportUserScalable == false) {
            mViewportInitialScale = 100;
            mViewportMinimumScale = 100;
            mViewportMaximumScale = 100;
        }
        if (mViewportMinimumScale > mViewportInitialScale) {
            if (mViewportInitialScale == 0) {
                mViewportInitialScale = mViewportMinimumScale;
            } else {
                mViewportMinimumScale = mViewportInitialScale;
            }
        }
        if (mViewportMaximumScale > 0) {
            if (mViewportMaximumScale < mViewportInitialScale) {
                mViewportMaximumScale = mViewportInitialScale;
            } else if (mViewportInitialScale == 0) {
                mViewportInitialScale = mViewportMaximumScale;
            }            
        }
        if (mViewportWidth < 0 && mViewportInitialScale == 100) {
            mViewportWidth = 0;
        }

        // now notify webview
        if (mWebView != null) {
            HashMap scaleLimit = new HashMap();
            scaleLimit.put("minScale", mViewportMinimumScale);
            scaleLimit.put("maxScale", mViewportMaximumScale);

            if (mRestoredScale > 0) {
                Message.obtain(mWebView.mPrivateHandler,
                        WebView.DID_FIRST_LAYOUT_MSG_ID, mRestoredScale, 0,
                        scaleLimit).sendToTarget();
                mRestoredScale = 0;
            } else {
                Message.obtain(mWebView.mPrivateHandler,
                        WebView.DID_FIRST_LAYOUT_MSG_ID, mViewportInitialScale,
                        mViewportWidth, scaleLimit).sendToTarget();
            }

            // if no restored offset, move the new page to (0, 0)
            Message.obtain(mWebView.mPrivateHandler, WebView.SCROLL_TO_MSG_ID,
                    mRestoredX, mRestoredY).sendToTarget();
            mRestoredX = mRestoredY = 0;

            // force an early draw for quick feedback after the first layout
            if (mCurrentViewWidth != 0) {
                synchronized (this) {
                    if (mDrawIsScheduled) {
                        mEventHub.removeMessages(EventHub.WEBKIT_DRAW);
                    }
                    mDrawIsScheduled = true;
                    mEventHub.sendMessageAtFrontOfQueue(Message.obtain(null,
                            EventHub.WEBKIT_DRAW));
                }
            }
        }
    
voiddrawContentPicture(android.graphics.Canvas canvas, int color, boolean animatingZoom, boolean animatingScroll)


    /* package */     
                                           
                                            
        DrawFilter df = null;
        if (animatingZoom) {
            df = mZoomFilter;
        } else if (animatingScroll) {
            df = mScrollFilter;
        }
        canvas.setDrawFilter(df);
        boolean tookTooLong = nativeDrawContent(canvas, color);
        canvas.setDrawFilter(null);
        if (tookTooLong && mSplitPictureIsScheduled == false) {
            mSplitPictureIsScheduled = true;
            sendMessage(EventHub.SPLIT_PICTURE_SET);
        }
    
static voidendCacheTransaction()

        sWebCoreHandler.sendMessage(sWebCoreHandler
                .obtainMessage(WebCoreThread.BLOCK_CACHE_TICKER));
    
BrowserFramegetBrowserFrame()

        return mBrowserFrame;
    
public WebSettingsgetSettings()

        return mSettings;
    
WebViewgetWebView()

        return mWebView;
    
private voidinitialize()

        /* Initialize our private BrowserFrame class to handle all
         * frame-related functions. We need to create a new view which
         * in turn creates a C level FrameView and attaches it to the frame.
         */
        mBrowserFrame = new BrowserFrame(mContext, this, mCallbackProxy,
                mSettings);
        // Sync the native settings and also create the WebCore thread handler.
        mSettings.syncSettingsAndCreateHandler(mBrowserFrame);
        // Create the handler and transfer messages for the IconDatabase
        WebIconDatabase.getInstance().createHandler();
        // The transferMessages call will transfer all pending messages to the
        // WebCore thread handler.
        mEventHub.transferMessages();

        // Send a message back to WebView to tell it that we have set up the
        // WebCore thread.
        if (mWebView != null) {
            Message.obtain(mWebView.mPrivateHandler,
                    WebView.WEBCORE_INITIALIZED_MSG_ID,
                    mNativeClass, 0).sendToTarget();
        }

    
voidinitializeSubwindow()

        // Go ahead and initialize the core components.
        initialize();
        // Remove the INITIALIZE method so we don't try to initialize twice.
        sWebCoreHandler.removeMessages(WebCoreThread.INITIALIZE, this);
    
protected voidjsAlert(java.lang.String url, java.lang.String message)
Invoke a javascript alert.

param
message The message displayed in the alert.

        mCallbackProxy.onJsAlert(url, message);
    
protected booleanjsConfirm(java.lang.String url, java.lang.String message)
Invoke a javascript confirm dialog.

param
message The message displayed in the dialog.
return
True if the user confirmed or false if the user cancelled.

        return mCallbackProxy.onJsConfirm(url, message);
    
protected java.lang.StringjsPrompt(java.lang.String url, java.lang.String message, java.lang.String defaultValue)
Invoke a javascript prompt dialog.

param
message The message to be displayed in the dialog.
param
defaultValue The default value in the prompt input.
return
The input from the user or null to indicate the user cancelled the dialog.

        return mCallbackProxy.onJsPrompt(url, message, defaultValue);
    
protected booleanjsUnload(java.lang.String url, java.lang.String message)
Invoke a javascript before unload dialog.

param
url The url that is requesting the dialog.
param
message The message displayed in the dialog.
return
True if the user confirmed or false if the user cancelled. False will cancel the navigation.

        return mCallbackProxy.onJsBeforeUnload(url, message);
    
private voidkey(android.view.KeyEvent evt, boolean isDown)

        if (LOGV_ENABLED) {
            Log.v(LOGTAG, "CORE key at " + System.currentTimeMillis() + ", "
                    + evt);
        }
        if (!nativeKey(evt.getKeyCode(), evt.getUnicodeChar(),
                evt.getRepeatCount(), evt.isShiftPressed(), evt.isAltPressed(),
                isDown)) {
            // bubble up the event handling
            mCallbackProxy.onUnhandledKeyEvent(evt);
        }
    
private voidloadUrl(java.lang.String url)

        if (LOGV_ENABLED) Log.v(LOGTAG, " CORE loadUrl " + url);
        mBrowserFrame.loadUrl(url);
    
private native voidnativeClearContent()
Empty the picture set.

private native booleannativeClick()

private native voidnativeCopyContentToPicture(android.graphics.Picture picture)
Create a flat picture from the set of pictures.

private native voidnativeDeleteSelection(int frame, int node, int x, int y, int start, int end)
Delete text from start to end in the focused textfield. If there is no focus, or if start == end, silently fail. If start and end are out of order, swap them.

param
start Beginning of selection to delete.
param
end End of selection to delete.

private native booleannativeDrawContent(android.graphics.Canvas canvas, int color)
Draw the picture set with a background color. Returns true if some individual picture took too long to draw and can be split into parts. Called from the UI thread.

private native voidnativeDumpDomTree(boolean useFile)

private native voidnativeDumpNavTree()

private native voidnativeDumpRenderTree(boolean useFile)

static native java.lang.StringnativeFindAddress(java.lang.String addr)

private native intnativeGetContentMinPrefWidth()

private native java.lang.StringnativeGetSelection(android.graphics.Region sel)

private native booleannativeHandleTouchEvent(int action, int x, int y)

private native booleannativeKey(int keyCode, int unichar, int repeatCount, boolean isShift, boolean isAlt, boolean isDown)

private native booleannativeRecordContent(android.graphics.Region invalRegion, android.graphics.Point wh)
Redraw a portion of the picture set. The Point wh returns the width and height of the overall picture.

private native voidnativeRefreshPlugins(boolean reloadOpenPages)

private native voidnativeRegisterURLSchemeAsLocal(java.lang.String scheme)

private native voidnativeReplaceTextfieldText(int frame, int node, int x, int y, int oldStart, int oldEnd, java.lang.String replace, int newStart, int newEnd)

private native java.lang.StringnativeRetrieveHref(int framePtr, int nodePtr)

private native voidnativeSaveDocumentState(int frame)

private native voidnativeSendListBoxChoice(int choice)

private native voidnativeSendListBoxChoices(boolean[] choices, int size)

private native voidnativeSetBackgroundColor(int color)

private native voidnativeSetFinalFocus(int framePtr, int nodePtr, int x, int y, boolean block)

private native voidnativeSetGlobalBounds(int x, int y, int w, int h)

private native voidnativeSetKitFocus(int moveGeneration, int buildGeneration, int framePtr, int nodePtr, int x, int y, boolean ignoreNullFocus)

private native voidnativeSetScrollOffset(int dx, int dy)

private native voidnativeSetSelection(int frame, int node, int x, int y, int start, int end)
Set the selection to (start, end) in the focused textfield. If start and end are out of order, swap them.

param
start Beginning of selection.
param
end End of selection.

private native voidnativeSetSize(int width, int height, int screenWidth, float scale, int realScreenWidth, int screenHeight)

private native voidnativeSetSnapAnchor(int x, int y)

private native voidnativeSnapToAnchor()

private native voidnativeSplitContent()
Splits slow parts of the picture set. Called from the webkit thread after nativeDrawContent returns true.

private native voidnativeTouchUp(int touchGeneration, int buildGeneration, int framePtr, int nodePtr, int x, int y, int size, boolean isClick, boolean retry)

private native voidnativeUnblockFocus()

private native voidnativeUpdateFrameCache()

private voidneedTouchEvents(boolean need)

        if (mWebView != null) {
            Message.obtain(mWebView.mPrivateHandler,
                    WebView.WEBCORE_NEED_TOUCH_EVENTS, need ? 1 : 0, 0)
                    .sendToTarget();
        }
    
private native voidpassToJs(int frame, int node, int x, int y, int gen, java.lang.String currentText, int keyCode, int keyValue, boolean down, boolean cap, boolean fn, boolean sym)

public static voidpauseTimers()
Causes all timers to pause. This applies to all WebViews in the current app process.

        if (BrowserFrame.sJavaBridge == null) {
            throw new IllegalStateException(
                    "No WebView has been created in this process!");
        }
        BrowserFrame.sJavaBridge.pause();
    
static voidpauseUpdate(android.webkit.WebViewCore core)

        // remove the pending REDUCE_PRIORITY and RESUME_PRIORITY messages
        sWebCoreHandler.removeMessages(WebCoreThread.REDUCE_PRIORITY);
        sWebCoreHandler.removeMessages(WebCoreThread.RESUME_PRIORITY);
        sWebCoreHandler.sendMessageAtFrontOfQueue(sWebCoreHandler
                .obtainMessage(WebCoreThread.REDUCE_PRIORITY));
        // Note: there is one possible failure mode. If pauseUpdate() is called
        // from UI thread while in webcore thread WEBKIT_DRAW is just pulled out 
        // of the queue and about to be executed. mDrawIsScheduled may be set to 
        // false in webkitDraw(). So update won't be blocked. But at least the 
        // webcore thread priority is still lowered.
        if (core != null) {
            synchronized (core) {
                core.mDrawIsPaused = true;
                core.mEventHub.removeMessages(EventHub.WEBKIT_DRAW);
            }
        }
    
voidremoveMessages(int what)

        mEventHub.removeMessages(what);
    
voidremoveMessages()

        mEventHub.removeMessages();
    
private voidrequestListBox(java.lang.String[] array, boolean[] enabledArray, int[] selectedArray)

        if (mWebView != null) {
            mWebView.requestListBox(array, enabledArray, selectedArray);
        }
    
private voidrequestListBox(java.lang.String[] array, boolean[] enabledArray, int selection)

        if (mWebView != null) {
            mWebView.requestListBox(array, enabledArray, selection);
        }
        
    
private voidrestoreScale(int scale)

        if (mBrowserFrame.firstLayoutDone() == false) {
            mRestoredScale = scale;
        }
    
private voidrestoreState(int index)

        WebBackForwardList list = mCallbackProxy.getBackForwardList();
        int size = list.getSize();
        for (int i = 0; i < size; i++) {
            list.getItemAtIndex(i).inflate(mBrowserFrame.mNativeFrame);
        }
        mBrowserFrame.mLoadInitFromJava = true;
        list.restoreIndex(mBrowserFrame.mNativeFrame, index);
        mBrowserFrame.mLoadInitFromJava = false;
    
public static voidresumeTimers()
Resume all timers. This applies to all WebViews in the current process.

        if (BrowserFrame.sJavaBridge == null) {
            throw new IllegalStateException(
                    "No WebView has been created in this process!");
        }
        BrowserFrame.sJavaBridge.resume();
    
static voidresumeUpdate(android.webkit.WebViewCore core)

        // remove the pending REDUCE_PRIORITY and RESUME_PRIORITY messages
        sWebCoreHandler.removeMessages(WebCoreThread.REDUCE_PRIORITY);
        sWebCoreHandler.removeMessages(WebCoreThread.RESUME_PRIORITY);
        sWebCoreHandler.sendMessageAtFrontOfQueue(sWebCoreHandler
                .obtainMessage(WebCoreThread.RESUME_PRIORITY));
        if (core != null) {
            synchronized (core) {
                core.mDrawIsScheduled = false;
                core.mDrawIsPaused = false;
                if (LOGV_ENABLED) Log.v(LOGTAG, "resumeUpdate");
                core.contentDraw();
            }
        }
    
private voidsendMarkNodeInvalid(int node)

        if (mWebView != null) {
            Message.obtain(mWebView.mPrivateHandler,
                    WebView.MARK_NODE_INVALID_ID, node, 0).sendToTarget();
        }
    
voidsendMessage(android.os.Message msg)

        mEventHub.sendMessage(msg);
    
voidsendMessage(int what)

        mEventHub.sendMessage(Message.obtain(null, what));
    
voidsendMessage(int what, java.lang.Object obj)

        mEventHub.sendMessage(Message.obtain(null, what, obj));
    
voidsendMessage(int what, int arg1)

        // just ignore the second argument (make it 0)
        mEventHub.sendMessage(Message.obtain(null, what, arg1, 0));
    
voidsendMessage(int what, int arg1, int arg2)

        mEventHub.sendMessage(Message.obtain(null, what, arg1, arg2));
    
voidsendMessage(int what, int arg1, java.lang.Object obj)

        // just ignore the second argument (make it 0)
        mEventHub.sendMessage(Message.obtain(null, what, arg1, 0, obj));
    
voidsendMessage(int what, int arg1, int arg2, java.lang.Object obj)

        mEventHub.sendMessage(Message.obtain(null, what, arg1, arg2, obj));
    
voidsendMessageDelayed(int what, java.lang.Object obj, long delay)

        mEventHub.sendMessageDelayed(Message.obtain(null, what, obj), delay);
    
private voidsendNotifyFocusSet()

        if (mWebView != null) {
            Message.obtain(mWebView.mPrivateHandler,
                    WebView.NOTIFY_FOCUS_SET_MSG_ID).sendToTarget();
        }
    
private voidsendNotifyProgressFinished()

        sendUpdateTextEntry();
        // as CacheManager can behave based on database transaction, we need to
        // call tick() to trigger endTransaction
        sWebCoreHandler.removeMessages(WebCoreThread.CACHE_TICKER);
        sWebCoreHandler.sendMessage(sWebCoreHandler
                .obtainMessage(WebCoreThread.CACHE_TICKER));
        contentDraw();
    
private voidsendRecomputeFocus()

        if (mWebView != null) {
            Message.obtain(mWebView.mPrivateHandler,
                    WebView.RECOMPUTE_FOCUS_MSG_ID).sendToTarget();
        }
    
private voidsendUpdateTextEntry()

        if (mWebView != null) {
            Message.obtain(mWebView.mPrivateHandler,
                    WebView.UPDATE_TEXT_ENTRY_MSG_ID).sendToTarget();
        }
    
private voidsendViewInvalidate(int left, int top, int right, int bottom)

        if (mWebView != null) {
            Message.obtain(mWebView.mPrivateHandler,
                           WebView.INVAL_RECT_MSG_ID,
                           new Rect(left, top, right, bottom)).sendToTarget();
        }
    
private native voidsetViewportSettingsFromNative()

static voidstartCacheTransaction()

        sWebCoreHandler.sendMessage(sWebCoreHandler
                .obtainMessage(WebCoreThread.RESUME_CACHE_TICKER));
    
voidstopLoading()

        if (LOGV_ENABLED) Log.v(LOGTAG, "CORE stopLoading");
        if (mBrowserFrame != null) {
            mBrowserFrame.stopLoading();
        }
    
private voidupdateTextfield(int ptr, boolean changeToPassword, java.lang.String text, int textGeneration)

        if (mWebView != null) {
            Message msg = Message.obtain(mWebView.mPrivateHandler,
                    WebView.UPDATE_TEXTFIELD_TEXT_MSG_ID, ptr, 
                    textGeneration, text);
            msg.getData().putBoolean("password", changeToPassword);
            msg.sendToTarget();
        }
    
private voidviewSizeChanged(int w, int h, float scale)


    // notify webkit that our virtual view size changed size (after inv-zoom)
            
        if (LOGV_ENABLED) Log.v(LOGTAG, "CORE onSizeChanged");
        if (w == 0) {
            Log.w(LOGTAG, "skip viewSizeChanged as w is 0");
            return;
        }
        if (mSettings.getUseWideViewPort()
                && (w < mViewportWidth || mViewportWidth == -1)) {
            int width = mViewportWidth;
            if (mViewportWidth == -1) {
                if (mSettings.getLayoutAlgorithm() == 
                        WebSettings.LayoutAlgorithm.NORMAL) {
                    width = WebView.ZOOM_OUT_WIDTH;
                } else {
                    /*
                     * if a page's minimum preferred width is wider than the
                     * given "w", use it instead to get better layout result. If
                     * we start a page with MAX_ZOOM_WIDTH, "w" will be always
                     * wider. If we start a page with screen width, due to the
                     * delay between {@link #didFirstLayout} and
                     * {@link #viewSizeChanged},
                     * {@link #nativeGetContentMinPrefWidth} will return a more
                     * accurate value than initial 0 to result a better layout.
                     * In the worse case, the native width will be adjusted when
                     * next zoom or screen orientation change happens.
                     */
                    width = Math.max(w, nativeGetContentMinPrefWidth());
                }
            }
            nativeSetSize(width, Math.round((float) width * h / w), w, scale,
                    w, h);
        } else {
            nativeSetSize(w, h, w, scale, w, h);
        }
        // Remember the current width and height
        boolean needInvalidate = (mCurrentViewWidth == 0);
        mCurrentViewWidth = w;
        mCurrentViewHeight = h;
        if (needInvalidate) {
            // ensure {@link #webkitDraw} is called as we were blocking in
            // {@link #contentDraw} when mCurrentViewWidth is 0
            if (LOGV_ENABLED) Log.v(LOGTAG, "viewSizeChanged");
            contentDraw();
        }
        mEventHub.sendMessage(Message.obtain(null,
                EventHub.UPDATE_CACHE_AND_TEXT_ENTRY));
    
private voidwebkitDraw()

        mDrawIsScheduled = false;
        DrawData draw = new DrawData();
        if (LOGV_ENABLED) Log.v(LOGTAG, "webkitDraw start");
        if (nativeRecordContent(draw.mInvalRegion, draw.mWidthHeight) 
                == false) {
            if (LOGV_ENABLED) Log.v(LOGTAG, "webkitDraw abort");
            return;
        }
        if (mWebView != null) {
            // Send the native view size that was used during the most recent
            // layout.
            draw.mViewPoint = new Point(mCurrentViewWidth, mCurrentViewHeight);
            if (LOGV_ENABLED) Log.v(LOGTAG, "webkitDraw NEW_PICTURE_MSG_ID");
            Message.obtain(mWebView.mPrivateHandler,
                    WebView.NEW_PICTURE_MSG_ID, draw).sendToTarget();
            if (mWebkitScrollX != 0 || mWebkitScrollY != 0) {
                // as we have the new picture, try to sync the scroll position
                Message.obtain(mWebView.mPrivateHandler,
                        WebView.SYNC_SCROLL_TO_MSG_ID, mWebkitScrollX,
                        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();
        }