Home | History | Annotate | Download | only in jni
      1 /*
      2  * Copyright 2006, The Android Open Source Project
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  *  * Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  *  * Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #define LOG_TAG "webcoreglue"
     27 
     28 #include "config.h"
     29 #include "WebViewCore.h"
     30 
     31 #include "AccessibilityObject.h"
     32 #include "Attribute.h"
     33 #include "BaseLayerAndroid.h"
     34 #include "CachedNode.h"
     35 #include "CachedRoot.h"
     36 #include "Chrome.h"
     37 #include "ChromeClientAndroid.h"
     38 #include "ChromiumIncludes.h"
     39 #include "ClientRect.h"
     40 #include "ClientRectList.h"
     41 #include "Color.h"
     42 #include "CSSPropertyNames.h"
     43 #include "CSSValueKeywords.h"
     44 #include "DatabaseTracker.h"
     45 #include "Document.h"
     46 #include "DOMWindow.h"
     47 #include "DOMSelection.h"
     48 #include "Element.h"
     49 #include "Editor.h"
     50 #include "EditorClientAndroid.h"
     51 #include "EventHandler.h"
     52 #include "EventNames.h"
     53 #include "ExceptionCode.h"
     54 #include "FocusController.h"
     55 #include "Font.h"
     56 #include "Frame.h"
     57 #include "FrameLoader.h"
     58 #include "FrameLoaderClientAndroid.h"
     59 #include "FrameTree.h"
     60 #include "FrameView.h"
     61 #include "Geolocation.h"
     62 #include "GraphicsContext.h"
     63 #include "GraphicsJNI.h"
     64 #include "HTMLAnchorElement.h"
     65 #include "HTMLAreaElement.h"
     66 #include "HTMLElement.h"
     67 #include "HTMLFormControlElement.h"
     68 #include "HTMLImageElement.h"
     69 #include "HTMLInputElement.h"
     70 #include "HTMLLabelElement.h"
     71 #include "HTMLMapElement.h"
     72 #include "HTMLNames.h"
     73 #include "HTMLOptGroupElement.h"
     74 #include "HTMLOptionElement.h"
     75 #include "HTMLSelectElement.h"
     76 #include "HTMLTextAreaElement.h"
     77 #include "HistoryItem.h"
     78 #include "HitTestRequest.h"
     79 #include "HitTestResult.h"
     80 #include "InlineTextBox.h"
     81 #include "MemoryUsage.h"
     82 #include "NamedNodeMap.h"
     83 #include "Navigator.h"
     84 #include "Node.h"
     85 #include "NodeList.h"
     86 #include "Page.h"
     87 #include "PageGroup.h"
     88 #include "PlatformKeyboardEvent.h"
     89 #include "PlatformString.h"
     90 #include "PluginWidgetAndroid.h"
     91 #include "PluginView.h"
     92 #include "Position.h"
     93 #include "ProgressTracker.h"
     94 #include "Range.h"
     95 #include "RenderBox.h"
     96 #include "RenderInline.h"
     97 #include "RenderLayer.h"
     98 #include "RenderPart.h"
     99 #include "RenderText.h"
    100 #include "RenderTextControl.h"
    101 #include "RenderThemeAndroid.h"
    102 #include "RenderView.h"
    103 #include "ResourceRequest.h"
    104 #include "SchemeRegistry.h"
    105 #include "SelectionController.h"
    106 #include "Settings.h"
    107 #include "SkANP.h"
    108 #include "SkTemplates.h"
    109 #include "SkTDArray.h"
    110 #include "SkTypes.h"
    111 #include "SkCanvas.h"
    112 #include "SkPicture.h"
    113 #include "SkUtils.h"
    114 #include "Text.h"
    115 #include "TypingCommand.h"
    116 #include "WebCache.h"
    117 #include "WebCoreFrameBridge.h"
    118 #include "WebFrameView.h"
    119 #include "WindowsKeyboardCodes.h"
    120 #include "android_graphics.h"
    121 #include "autofill/WebAutofill.h"
    122 #include "htmlediting.h"
    123 #include "markup.h"
    124 
    125 #include <JNIHelp.h>
    126 #include <JNIUtility.h>
    127 #include <ui/KeycodeLabels.h>
    128 #include <wtf/CurrentTime.h>
    129 #include <wtf/text/AtomicString.h>
    130 #include <wtf/text/StringImpl.h>
    131 
    132 #if USE(V8)
    133 #include "ScriptController.h"
    134 #include "V8Counters.h"
    135 #include <wtf/text/CString.h>
    136 #endif
    137 
    138 #if DEBUG_NAV_UI
    139 #include "SkTime.h"
    140 #endif
    141 
    142 #if ENABLE(TOUCH_EVENTS) // Android
    143 #include "PlatformTouchEvent.h"
    144 #endif
    145 
    146 #ifdef ANDROID_DOM_LOGGING
    147 #include "AndroidLog.h"
    148 #include "RenderTreeAsText.h"
    149 #include <wtf/text/CString.h>
    150 
    151 FILE* gDomTreeFile = 0;
    152 FILE* gRenderTreeFile = 0;
    153 #endif
    154 
    155 #ifdef ANDROID_INSTRUMENT
    156 #include "TimeCounter.h"
    157 #endif
    158 
    159 #if USE(ACCELERATED_COMPOSITING)
    160 #include "GraphicsLayerAndroid.h"
    161 #include "RenderLayerCompositor.h"
    162 #endif
    163 
    164 #if USE(V8)
    165 #include <v8.h>
    166 #endif
    167 
    168 // In some cases, too many invalidations passed to the UI will slow us down.
    169 // Limit ourselves to 32 rectangles, past this just send the area bounds to the UI.
    170 // see WebViewCore::recordPictureSet().
    171 #define MAX_INVALIDATIONS 32
    172 
    173 /*  We pass this flag when recording the actual content, so that we don't spend
    174     time actually regionizing complex path clips, when all we really want to do
    175     is record them.
    176  */
    177 #define PICT_RECORD_FLAGS   SkPicture::kUsePathBoundsForClip_RecordingFlag
    178 
    179 ////////////////////////////////////////////////////////////////////////////////////////////////
    180 
    181 namespace android {
    182 
    183 static SkTDArray<WebViewCore*> gInstanceList;
    184 
    185 void WebViewCore::addInstance(WebViewCore* inst) {
    186     *gInstanceList.append() = inst;
    187 }
    188 
    189 void WebViewCore::removeInstance(WebViewCore* inst) {
    190     int index = gInstanceList.find(inst);
    191     LOG_ASSERT(index >= 0, "RemoveInstance inst not found");
    192     if (index >= 0) {
    193         gInstanceList.removeShuffle(index);
    194     }
    195 }
    196 
    197 bool WebViewCore::isInstance(WebViewCore* inst) {
    198     return gInstanceList.find(inst) >= 0;
    199 }
    200 
    201 jobject WebViewCore::getApplicationContext() {
    202 
    203     // check to see if there is a valid webviewcore object
    204     if (gInstanceList.isEmpty())
    205         return 0;
    206 
    207     // get the context from the webview
    208     jobject context = gInstanceList[0]->getContext();
    209 
    210     if (!context)
    211         return 0;
    212 
    213     // get the application context using JNI
    214     JNIEnv* env = JSC::Bindings::getJNIEnv();
    215     jclass contextClass = env->GetObjectClass(context);
    216     jmethodID appContextMethod = env->GetMethodID(contextClass, "getApplicationContext", "()Landroid/content/Context;");
    217     env->DeleteLocalRef(contextClass);
    218     jobject result = env->CallObjectMethod(context, appContextMethod);
    219     checkException(env);
    220     return result;
    221 }
    222 
    223 
    224 struct WebViewCoreStaticMethods {
    225     jmethodID    m_isSupportedMediaMimeType;
    226 } gWebViewCoreStaticMethods;
    227 
    228 // Check whether a media mimeType is supported in Android media framework.
    229 bool WebViewCore::isSupportedMediaMimeType(const WTF::String& mimeType) {
    230     JNIEnv* env = JSC::Bindings::getJNIEnv();
    231     jstring jMimeType = wtfStringToJstring(env, mimeType);
    232     jclass webViewCore = env->FindClass("android/webkit/WebViewCore");
    233     bool val = env->CallStaticBooleanMethod(webViewCore,
    234           gWebViewCoreStaticMethods.m_isSupportedMediaMimeType, jMimeType);
    235     checkException(env);
    236     env->DeleteLocalRef(webViewCore);
    237     env->DeleteLocalRef(jMimeType);
    238 
    239     return val;
    240 }
    241 
    242 // ----------------------------------------------------------------------------
    243 
    244 #define GET_NATIVE_VIEW(env, obj) ((WebViewCore*)env->GetIntField(obj, gWebViewCoreFields.m_nativeClass))
    245 
    246 // Field ids for WebViewCore
    247 struct WebViewCoreFields {
    248     jfieldID    m_nativeClass;
    249     jfieldID    m_viewportWidth;
    250     jfieldID    m_viewportHeight;
    251     jfieldID    m_viewportInitialScale;
    252     jfieldID    m_viewportMinimumScale;
    253     jfieldID    m_viewportMaximumScale;
    254     jfieldID    m_viewportUserScalable;
    255     jfieldID    m_viewportDensityDpi;
    256     jfieldID    m_webView;
    257     jfieldID    m_drawIsPaused;
    258     jfieldID    m_lowMemoryUsageMb;
    259     jfieldID    m_highMemoryUsageMb;
    260     jfieldID    m_highUsageDeltaMb;
    261 } gWebViewCoreFields;
    262 
    263 // ----------------------------------------------------------------------------
    264 
    265 struct WebViewCore::JavaGlue {
    266     jweak       m_obj;
    267     jmethodID   m_scrollTo;
    268     jmethodID   m_contentDraw;
    269     jmethodID   m_layersDraw;
    270     jmethodID   m_requestListBox;
    271     jmethodID   m_openFileChooser;
    272     jmethodID   m_requestSingleListBox;
    273     jmethodID   m_jsAlert;
    274     jmethodID   m_jsConfirm;
    275     jmethodID   m_jsPrompt;
    276     jmethodID   m_jsUnload;
    277     jmethodID   m_jsInterrupt;
    278     jmethodID   m_didFirstLayout;
    279     jmethodID   m_updateViewport;
    280     jmethodID   m_sendNotifyProgressFinished;
    281     jmethodID   m_sendViewInvalidate;
    282     jmethodID   m_updateTextfield;
    283     jmethodID   m_updateTextSelection;
    284     jmethodID   m_clearTextEntry;
    285     jmethodID   m_restoreScale;
    286     jmethodID   m_needTouchEvents;
    287     jmethodID   m_requestKeyboard;
    288     jmethodID   m_requestKeyboardWithSelection;
    289     jmethodID   m_exceededDatabaseQuota;
    290     jmethodID   m_reachedMaxAppCacheSize;
    291     jmethodID   m_populateVisitedLinks;
    292     jmethodID   m_geolocationPermissionsShowPrompt;
    293     jmethodID   m_geolocationPermissionsHidePrompt;
    294     jmethodID   m_getDeviceMotionService;
    295     jmethodID   m_getDeviceOrientationService;
    296     jmethodID   m_addMessageToConsole;
    297     jmethodID   m_formDidBlur;
    298     jmethodID   m_getPluginClass;
    299     jmethodID   m_showFullScreenPlugin;
    300     jmethodID   m_hideFullScreenPlugin;
    301     jmethodID   m_createSurface;
    302     jmethodID   m_addSurface;
    303     jmethodID   m_updateSurface;
    304     jmethodID   m_destroySurface;
    305     jmethodID   m_getContext;
    306     jmethodID   m_keepScreenOn;
    307     jmethodID   m_sendFindAgain;
    308     jmethodID   m_showRect;
    309     jmethodID   m_centerFitRect;
    310     jmethodID   m_setScrollbarModes;
    311     jmethodID   m_setInstallableWebApp;
    312     jmethodID   m_enterFullscreenForVideoLayer;
    313     jmethodID   m_setWebTextViewAutoFillable;
    314     jmethodID   m_selectAt;
    315     AutoJObject object(JNIEnv* env) {
    316         // We hold a weak reference to the Java WebViewCore to avoid memeory
    317         // leaks due to circular references when WebView.destroy() is not
    318         // called manually. The WebView and hence the WebViewCore could become
    319         // weakly reachable at any time, after which the GC could null our weak
    320         // reference, so we have to check the return value of this method at
    321         // every use. Note that our weak reference will be nulled before the
    322         // WebViewCore is finalized.
    323         return getRealObject(env, m_obj);
    324     }
    325 };
    326 
    327 /*
    328  * WebViewCore Implementation
    329  */
    330 
    331 static jmethodID GetJMethod(JNIEnv* env, jclass clazz, const char name[], const char signature[])
    332 {
    333     jmethodID m = env->GetMethodID(clazz, name, signature);
    334     LOG_ASSERT(m, "Could not find method %s", name);
    335     return m;
    336 }
    337 
    338 Mutex WebViewCore::gFrameCacheMutex;
    339 Mutex WebViewCore::gButtonMutex;
    340 Mutex WebViewCore::gCursorBoundsMutex;
    341 
    342 WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* mainframe)
    343     : m_frameCacheKit(0)
    344     , m_navPictureKit(0)
    345     , m_moveGeneration(0)
    346     , m_touchGeneration(0)
    347     , m_lastGeneration(0)
    348     , m_updatedFrameCache(true)
    349     , m_findIsUp(false)
    350     , m_hasCursorBounds(false)
    351     , m_cursorBounds(WebCore::IntRect(0, 0, 0, 0))
    352     , m_cursorHitBounds(WebCore::IntRect(0, 0, 0, 0))
    353     , m_cursorFrame(0)
    354     , m_cursorLocation(WebCore::IntPoint(0, 0))
    355     , m_cursorNode(0)
    356     , m_javaGlue(new JavaGlue)
    357     , m_mainFrame(mainframe)
    358     , m_popupReply(0)
    359     , m_lastFocused(0)
    360     , m_lastFocusedBounds(WebCore::IntRect(0,0,0,0))
    361     , m_blurringNodePointer(0)
    362     , m_lastFocusedSelStart(0)
    363     , m_lastFocusedSelEnd(0)
    364     , m_blockTextfieldUpdates(false)
    365     , m_focusBoundsChanged(false)
    366     , m_skipContentDraw(false)
    367     , m_textGeneration(0)
    368     , m_temp(0)
    369     , m_tempPict(0)
    370     , m_maxXScroll(320/4)
    371     , m_maxYScroll(240/4)
    372     , m_scrollOffsetX(0)
    373     , m_scrollOffsetY(0)
    374     , m_mousePos(WebCore::IntPoint(0,0))
    375     , m_frameCacheOutOfDate(true)
    376     , m_progressDone(false)
    377     , m_screenWidth(320)
    378     , m_screenHeight(240)
    379     , m_textWrapWidth(320)
    380     , m_scale(1.0f)
    381     , m_domtree_version(0)
    382     , m_check_domtree_version(true)
    383     , m_groupForVisitedLinks(0)
    384     , m_isPaused(false)
    385     , m_cacheMode(0)
    386     , m_shouldPaintCaret(true)
    387     , m_pluginInvalTimer(this, &WebViewCore::pluginInvalTimerFired)
    388     , m_screenOnCounter(0)
    389     , m_currentNodeDomNavigationAxis(0)
    390     , m_deviceMotionAndOrientationManager(this)
    391 #if ENABLE(TOUCH_EVENTS)
    392     , m_forwardingTouchEvents(false)
    393 #endif
    394 #if USE(CHROME_NETWORK_STACK)
    395     , m_webRequestContext(0)
    396 #endif
    397 {
    398     LOG_ASSERT(m_mainFrame, "Uh oh, somehow a frameview was made without an initial frame!");
    399 
    400     jclass clazz = env->GetObjectClass(javaWebViewCore);
    401     m_javaGlue->m_obj = env->NewWeakGlobalRef(javaWebViewCore);
    402     m_javaGlue->m_scrollTo = GetJMethod(env, clazz, "contentScrollTo", "(IIZZ)V");
    403     m_javaGlue->m_contentDraw = GetJMethod(env, clazz, "contentDraw", "()V");
    404     m_javaGlue->m_layersDraw = GetJMethod(env, clazz, "layersDraw", "()V");
    405     m_javaGlue->m_requestListBox = GetJMethod(env, clazz, "requestListBox", "([Ljava/lang/String;[I[I)V");
    406     m_javaGlue->m_openFileChooser = GetJMethod(env, clazz, "openFileChooser", "(Ljava/lang/String;)Ljava/lang/String;");
    407     m_javaGlue->m_requestSingleListBox = GetJMethod(env, clazz, "requestListBox", "([Ljava/lang/String;[II)V");
    408     m_javaGlue->m_jsAlert = GetJMethod(env, clazz, "jsAlert", "(Ljava/lang/String;Ljava/lang/String;)V");
    409     m_javaGlue->m_jsConfirm = GetJMethod(env, clazz, "jsConfirm", "(Ljava/lang/String;Ljava/lang/String;)Z");
    410     m_javaGlue->m_jsPrompt = GetJMethod(env, clazz, "jsPrompt", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
    411     m_javaGlue->m_jsUnload = GetJMethod(env, clazz, "jsUnload", "(Ljava/lang/String;Ljava/lang/String;)Z");
    412     m_javaGlue->m_jsInterrupt = GetJMethod(env, clazz, "jsInterrupt", "()Z");
    413     m_javaGlue->m_didFirstLayout = GetJMethod(env, clazz, "didFirstLayout", "(Z)V");
    414     m_javaGlue->m_updateViewport = GetJMethod(env, clazz, "updateViewport", "()V");
    415     m_javaGlue->m_sendNotifyProgressFinished = GetJMethod(env, clazz, "sendNotifyProgressFinished", "()V");
    416     m_javaGlue->m_sendViewInvalidate = GetJMethod(env, clazz, "sendViewInvalidate", "(IIII)V");
    417     m_javaGlue->m_updateTextfield = GetJMethod(env, clazz, "updateTextfield", "(IZLjava/lang/String;I)V");
    418     m_javaGlue->m_updateTextSelection = GetJMethod(env, clazz, "updateTextSelection", "(IIII)V");
    419     m_javaGlue->m_clearTextEntry = GetJMethod(env, clazz, "clearTextEntry", "()V");
    420     m_javaGlue->m_restoreScale = GetJMethod(env, clazz, "restoreScale", "(FF)V");
    421     m_javaGlue->m_needTouchEvents = GetJMethod(env, clazz, "needTouchEvents", "(Z)V");
    422     m_javaGlue->m_requestKeyboard = GetJMethod(env, clazz, "requestKeyboard", "(Z)V");
    423     m_javaGlue->m_requestKeyboardWithSelection = GetJMethod(env, clazz, "requestKeyboardWithSelection", "(IIII)V");
    424     m_javaGlue->m_exceededDatabaseQuota = GetJMethod(env, clazz, "exceededDatabaseQuota", "(Ljava/lang/String;Ljava/lang/String;JJ)V");
    425     m_javaGlue->m_reachedMaxAppCacheSize = GetJMethod(env, clazz, "reachedMaxAppCacheSize", "(J)V");
    426     m_javaGlue->m_populateVisitedLinks = GetJMethod(env, clazz, "populateVisitedLinks", "()V");
    427     m_javaGlue->m_geolocationPermissionsShowPrompt = GetJMethod(env, clazz, "geolocationPermissionsShowPrompt", "(Ljava/lang/String;)V");
    428     m_javaGlue->m_geolocationPermissionsHidePrompt = GetJMethod(env, clazz, "geolocationPermissionsHidePrompt", "()V");
    429     m_javaGlue->m_getDeviceMotionService = GetJMethod(env, clazz, "getDeviceMotionService", "()Landroid/webkit/DeviceMotionService;");
    430     m_javaGlue->m_getDeviceOrientationService = GetJMethod(env, clazz, "getDeviceOrientationService", "()Landroid/webkit/DeviceOrientationService;");
    431     m_javaGlue->m_addMessageToConsole = GetJMethod(env, clazz, "addMessageToConsole", "(Ljava/lang/String;ILjava/lang/String;I)V");
    432     m_javaGlue->m_formDidBlur = GetJMethod(env, clazz, "formDidBlur", "(I)V");
    433     m_javaGlue->m_getPluginClass = GetJMethod(env, clazz, "getPluginClass", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Class;");
    434     m_javaGlue->m_showFullScreenPlugin = GetJMethod(env, clazz, "showFullScreenPlugin", "(Landroid/webkit/ViewManager$ChildView;II)V");
    435     m_javaGlue->m_hideFullScreenPlugin = GetJMethod(env, clazz, "hideFullScreenPlugin", "()V");
    436     m_javaGlue->m_createSurface = GetJMethod(env, clazz, "createSurface", "(Landroid/view/View;)Landroid/webkit/ViewManager$ChildView;");
    437     m_javaGlue->m_addSurface = GetJMethod(env, clazz, "addSurface", "(Landroid/view/View;IIII)Landroid/webkit/ViewManager$ChildView;");
    438     m_javaGlue->m_updateSurface = GetJMethod(env, clazz, "updateSurface", "(Landroid/webkit/ViewManager$ChildView;IIII)V");
    439     m_javaGlue->m_destroySurface = GetJMethod(env, clazz, "destroySurface", "(Landroid/webkit/ViewManager$ChildView;)V");
    440     m_javaGlue->m_getContext = GetJMethod(env, clazz, "getContext", "()Landroid/content/Context;");
    441     m_javaGlue->m_keepScreenOn = GetJMethod(env, clazz, "keepScreenOn", "(Z)V");
    442     m_javaGlue->m_sendFindAgain = GetJMethod(env, clazz, "sendFindAgain", "()V");
    443     m_javaGlue->m_showRect = GetJMethod(env, clazz, "showRect", "(IIIIIIFFFF)V");
    444     m_javaGlue->m_centerFitRect = GetJMethod(env, clazz, "centerFitRect", "(IIII)V");
    445     m_javaGlue->m_setScrollbarModes = GetJMethod(env, clazz, "setScrollbarModes", "(II)V");
    446     m_javaGlue->m_setInstallableWebApp = GetJMethod(env, clazz, "setInstallableWebApp", "()V");
    447 #if ENABLE(VIDEO)
    448     m_javaGlue->m_enterFullscreenForVideoLayer = GetJMethod(env, clazz, "enterFullscreenForVideoLayer", "(ILjava/lang/String;)V");
    449 #endif
    450     m_javaGlue->m_setWebTextViewAutoFillable = GetJMethod(env, clazz, "setWebTextViewAutoFillable", "(ILjava/lang/String;)V");
    451     m_javaGlue->m_selectAt = GetJMethod(env, clazz, "selectAt", "(II)V");
    452     env->DeleteLocalRef(clazz);
    453 
    454     env->SetIntField(javaWebViewCore, gWebViewCoreFields.m_nativeClass, (jint)this);
    455 
    456     PageGroup::setShouldTrackVisitedLinks(true);
    457 
    458     clearContent();
    459 
    460     MemoryUsage::setLowMemoryUsageMb(env->GetIntField(javaWebViewCore, gWebViewCoreFields.m_lowMemoryUsageMb));
    461     MemoryUsage::setHighMemoryUsageMb(env->GetIntField(javaWebViewCore, gWebViewCoreFields.m_highMemoryUsageMb));
    462     MemoryUsage::setHighUsageDeltaMb(env->GetIntField(javaWebViewCore, gWebViewCoreFields.m_highUsageDeltaMb));
    463 
    464     WebViewCore::addInstance(this);
    465 
    466 #if USE(CHROME_NETWORK_STACK)
    467     AndroidNetworkLibraryImpl::InitWithApplicationContext(env, 0);
    468 #endif
    469 
    470 #if USE(V8)
    471     // Static initialisation of certain important V8 static data gets performed at system startup when
    472     // libwebcore gets loaded. We now need to associate the WebCore thread with V8 to complete
    473     // initialisation.
    474     v8::V8::Initialize();
    475 #endif
    476 }
    477 
    478 WebViewCore::~WebViewCore()
    479 {
    480     WebViewCore::removeInstance(this);
    481 
    482     // Release the focused view
    483     Release(m_popupReply);
    484 
    485     if (m_javaGlue->m_obj) {
    486         JNIEnv* env = JSC::Bindings::getJNIEnv();
    487         env->DeleteWeakGlobalRef(m_javaGlue->m_obj);
    488         m_javaGlue->m_obj = 0;
    489     }
    490     delete m_javaGlue;
    491     delete m_frameCacheKit;
    492     delete m_navPictureKit;
    493 }
    494 
    495 WebViewCore* WebViewCore::getWebViewCore(const WebCore::FrameView* view)
    496 {
    497     return getWebViewCore(static_cast<const WebCore::ScrollView*>(view));
    498 }
    499 
    500 WebViewCore* WebViewCore::getWebViewCore(const WebCore::ScrollView* view)
    501 {
    502     if (!view)
    503         return 0;
    504 
    505     WebFrameView* webFrameView = static_cast<WebFrameView*>(view->platformWidget());
    506     if (!webFrameView)
    507         return 0;
    508     return webFrameView->webViewCore();
    509 }
    510 
    511 static bool layoutIfNeededRecursive(WebCore::Frame* f)
    512 {
    513     if (!f)
    514         return true;
    515 
    516     WebCore::FrameView* v = f->view();
    517     if (!v)
    518         return true;
    519 
    520     if (v->needsLayout())
    521         v->layout(f->tree()->parent());
    522 
    523     WebCore::Frame* child = f->tree()->firstChild();
    524     bool success = true;
    525     while (child) {
    526         success &= layoutIfNeededRecursive(child);
    527         child = child->tree()->nextSibling();
    528     }
    529 
    530     return success && !v->needsLayout();
    531 }
    532 
    533 CacheBuilder& WebViewCore::cacheBuilder()
    534 {
    535     return FrameLoaderClientAndroid::get(m_mainFrame)->getCacheBuilder();
    536 }
    537 
    538 WebCore::Node* WebViewCore::currentFocus()
    539 {
    540     return cacheBuilder().currentFocus();
    541 }
    542 
    543 void WebViewCore::recordPicture(SkPicture* picture)
    544 {
    545     // if there is no document yet, just return
    546     if (!m_mainFrame->document()) {
    547         DBG_NAV_LOG("no document");
    548         return;
    549     }
    550     // Call layout to ensure that the contentWidth and contentHeight are correct
    551     if (!layoutIfNeededRecursive(m_mainFrame)) {
    552         DBG_NAV_LOG("layout failed");
    553         return;
    554     }
    555     // draw into the picture's recording canvas
    556     WebCore::FrameView* view = m_mainFrame->view();
    557     DBG_NAV_LOGD("view=(w=%d,h=%d)", view->contentsWidth(),
    558         view->contentsHeight());
    559     SkAutoPictureRecord arp(picture, view->contentsWidth(),
    560                             view->contentsHeight(), PICT_RECORD_FLAGS);
    561     SkAutoMemoryUsageProbe mup(__FUNCTION__);
    562 
    563     // Copy m_buttons so we can pass it to our graphics context.
    564     gButtonMutex.lock();
    565     WTF::Vector<Container> buttons(m_buttons);
    566     gButtonMutex.unlock();
    567 
    568     WebCore::PlatformGraphicsContext pgc(arp.getRecordingCanvas(), &buttons);
    569     WebCore::GraphicsContext gc(&pgc);
    570     view->platformWidget()->draw(&gc, WebCore::IntRect(0, 0,
    571         view->contentsWidth(), view->contentsHeight()));
    572 
    573     gButtonMutex.lock();
    574     updateButtonList(&buttons);
    575     gButtonMutex.unlock();
    576 }
    577 
    578 void WebViewCore::recordPictureSet(PictureSet* content)
    579 {
    580     // if there is no document yet, just return
    581     if (!m_mainFrame->document()) {
    582         DBG_SET_LOG("!m_mainFrame->document()");
    583         return;
    584     }
    585     if (m_addInval.isEmpty()) {
    586         DBG_SET_LOG("m_addInval.isEmpty()");
    587         return;
    588     }
    589     // Call layout to ensure that the contentWidth and contentHeight are correct
    590     // it's fine for layout to gather invalidates, but defeat sending a message
    591     // back to java to call webkitDraw, since we're already in the middle of
    592     // doing that
    593     m_skipContentDraw = true;
    594     bool success = layoutIfNeededRecursive(m_mainFrame);
    595     m_skipContentDraw = false;
    596 
    597     // We may be mid-layout and thus cannot draw.
    598     if (!success)
    599         return;
    600 
    601     {   // collect WebViewCoreRecordTimeCounter after layoutIfNeededRecursive
    602 #ifdef ANDROID_INSTRUMENT
    603     TimeCounterAuto counter(TimeCounter::WebViewCoreRecordTimeCounter);
    604 #endif
    605 
    606     // if the webkit page dimensions changed, discard the pictureset and redraw.
    607     WebCore::FrameView* view = m_mainFrame->view();
    608     int width = view->contentsWidth();
    609     int height = view->contentsHeight();
    610 
    611     // Use the contents width and height as a starting point.
    612     SkIRect contentRect;
    613     contentRect.set(0, 0, width, height);
    614     SkIRect total(contentRect);
    615 
    616     // Traverse all the frames and add their sizes if they are in the visible
    617     // rectangle.
    618     for (WebCore::Frame* frame = m_mainFrame->tree()->traverseNext(); frame;
    619             frame = frame->tree()->traverseNext()) {
    620         // If the frame doesn't have an owner then it is the top frame and the
    621         // view size is the frame size.
    622         WebCore::RenderPart* owner = frame->ownerRenderer();
    623         if (owner && owner->style()->visibility() == VISIBLE) {
    624             int x = owner->x();
    625             int y = owner->y();
    626 
    627             // Traverse the tree up to the parent to find the absolute position
    628             // of this frame.
    629             WebCore::Frame* parent = frame->tree()->parent();
    630             while (parent) {
    631                 WebCore::RenderPart* parentOwner = parent->ownerRenderer();
    632                 if (parentOwner) {
    633                     x += parentOwner->x();
    634                     y += parentOwner->y();
    635                 }
    636                 parent = parent->tree()->parent();
    637             }
    638             // Use the owner dimensions so that padding and border are
    639             // included.
    640             int right = x + owner->width();
    641             int bottom = y + owner->height();
    642             SkIRect frameRect = {x, y, right, bottom};
    643             // Ignore a width or height that is smaller than 1. Some iframes
    644             // have small dimensions in order to be hidden. The iframe
    645             // expansion code does not expand in that case so we should ignore
    646             // them here.
    647             if (frameRect.width() > 1 && frameRect.height() > 1
    648                     && SkIRect::Intersects(total, frameRect))
    649                 total.join(x, y, right, bottom);
    650         }
    651     }
    652 
    653     // If the new total is larger than the content, resize the view to include
    654     // all the content.
    655     if (!contentRect.contains(total)) {
    656         // Resize the view to change the overflow clip.
    657         view->resize(total.fRight, total.fBottom);
    658 
    659         // We have to force a layout in order for the clip to change.
    660         m_mainFrame->contentRenderer()->setNeedsLayoutAndPrefWidthsRecalc();
    661         view->forceLayout();
    662 
    663         // Relayout similar to above
    664         m_skipContentDraw = true;
    665         bool success = layoutIfNeededRecursive(m_mainFrame);
    666         m_skipContentDraw = false;
    667         if (!success)
    668             return;
    669 
    670         // Set the computed content width
    671         width = view->contentsWidth();
    672         height = view->contentsHeight();
    673     }
    674 
    675     if (cacheBuilder().pictureSetDisabled())
    676         content->clear();
    677 
    678 #if USE(ACCELERATED_COMPOSITING)
    679     // Detects if the content size has changed
    680     bool contentSizeChanged = false;
    681     if (content->width() != width || content->height() != height)
    682         contentSizeChanged = true;
    683 #endif
    684 
    685     content->setDimensions(width, height, &m_addInval);
    686 
    687     // Add the current inval rects to the PictureSet, and rebuild it.
    688     content->add(m_addInval, 0, 0, false);
    689 
    690     // If we have too many invalidations, just get the area bounds
    691     SkRegion::Iterator iterator(m_addInval);
    692     int nbInvals = 0;
    693     while (!iterator.done()) {
    694         iterator.next();
    695         nbInvals++;
    696         if (nbInvals > MAX_INVALIDATIONS)
    697             break;
    698     }
    699     if (nbInvals > MAX_INVALIDATIONS) {
    700         SkIRect r = m_addInval.getBounds();
    701         m_addInval.setRect(r);
    702     }
    703 
    704     // Rebuild the pictureset (webkit repaint)
    705     rebuildPictureSet(content);
    706 
    707 #if USE(ACCELERATED_COMPOSITING)
    708     // We repainted the pictureset, but the invals are not always correct when
    709     // the content size did change. For now, let's just reset the
    710     // inval we will pass to the UI so that it invalidates the entire
    711     // content -- tiles will be marked dirty and will have to be repainted.
    712     // FIXME: the webkit invals ought to have been enough...
    713     if (contentSizeChanged) {
    714         SkIRect r;
    715         r.fLeft = 0;
    716         r.fTop = 0;
    717         r.fRight = width;
    718         r.fBottom = height;
    719         m_addInval.setRect(r);
    720     }
    721 #endif
    722 
    723     } // WebViewCoreRecordTimeCounter
    724 
    725     WebCore::Node* oldFocusNode = currentFocus();
    726     m_frameCacheOutOfDate = true;
    727     WebCore::IntRect oldBounds;
    728     int oldSelStart = 0;
    729     int oldSelEnd = 0;
    730     if (oldFocusNode) {
    731         oldBounds = oldFocusNode->getRect();
    732         RenderObject* renderer = oldFocusNode->renderer();
    733         if (renderer && (renderer->isTextArea() || renderer->isTextField())) {
    734             WebCore::RenderTextControl* rtc =
    735                 static_cast<WebCore::RenderTextControl*>(renderer);
    736             oldSelStart = rtc->selectionStart();
    737             oldSelEnd = rtc->selectionEnd();
    738         }
    739     } else
    740         oldBounds = WebCore::IntRect(0,0,0,0);
    741     unsigned latestVersion = 0;
    742     if (m_check_domtree_version) {
    743         // as domTreeVersion only increment, we can just check the sum to see
    744         // whether we need to update the frame cache
    745         for (Frame* frame = m_mainFrame; frame; frame = frame->tree()->traverseNext()) {
    746             const Document* doc = frame->document();
    747             latestVersion += doc->domTreeVersion() + doc->styleVersion();
    748         }
    749     }
    750     DBG_NAV_LOGD("m_lastFocused=%p oldFocusNode=%p"
    751         " m_lastFocusedBounds={%d,%d,%d,%d} oldBounds={%d,%d,%d,%d}"
    752         " m_lastFocusedSelection={%d,%d} oldSelection={%d,%d}"
    753         " m_check_domtree_version=%s latestVersion=%d m_domtree_version=%d",
    754         m_lastFocused, oldFocusNode,
    755         m_lastFocusedBounds.x(), m_lastFocusedBounds.y(),
    756         m_lastFocusedBounds.width(), m_lastFocusedBounds.height(),
    757         oldBounds.x(), oldBounds.y(), oldBounds.width(), oldBounds.height(),
    758         m_lastFocusedSelStart, m_lastFocusedSelEnd, oldSelStart, oldSelEnd,
    759         m_check_domtree_version ? "true" : "false",
    760         latestVersion, m_domtree_version);
    761     if (m_lastFocused == oldFocusNode && m_lastFocusedBounds == oldBounds
    762             && m_lastFocusedSelStart == oldSelStart
    763             && m_lastFocusedSelEnd == oldSelEnd
    764             && !m_findIsUp
    765             && (!m_check_domtree_version || latestVersion == m_domtree_version))
    766     {
    767         return;
    768     }
    769     m_focusBoundsChanged |= m_lastFocused == oldFocusNode
    770         && m_lastFocusedBounds != oldBounds;
    771     m_lastFocused = oldFocusNode;
    772     m_lastFocusedBounds = oldBounds;
    773     m_lastFocusedSelStart = oldSelStart;
    774     m_lastFocusedSelEnd = oldSelEnd;
    775     m_domtree_version = latestVersion;
    776     DBG_NAV_LOG("call updateFrameCache");
    777     updateFrameCache();
    778     if (m_findIsUp) {
    779         LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
    780         JNIEnv* env = JSC::Bindings::getJNIEnv();
    781         AutoJObject javaObject = m_javaGlue->object(env);
    782         if (javaObject.get()) {
    783             env->CallVoidMethod(javaObject.get(), m_javaGlue->m_sendFindAgain);
    784             checkException(env);
    785         }
    786     }
    787 }
    788 
    789 void WebViewCore::updateButtonList(WTF::Vector<Container>* buttons)
    790 {
    791     // All the entries in buttons are either updates of previous entries in
    792     // m_buttons or they need to be added to it.
    793     Container* end = buttons->end();
    794     for (Container* updatedContainer = buttons->begin();
    795             updatedContainer != end; updatedContainer++) {
    796         bool updated = false;
    797         // Search for a previous entry that references the same node as our new
    798         // data
    799         Container* lastPossibleMatch = m_buttons.end();
    800         for (Container* possibleMatch = m_buttons.begin();
    801                 possibleMatch != lastPossibleMatch; possibleMatch++) {
    802             if (updatedContainer->matches(possibleMatch->node())) {
    803                 // Update our record, and skip to the next one.
    804                 possibleMatch->setRect(updatedContainer->rect());
    805                 updated = true;
    806                 break;
    807             }
    808         }
    809         if (!updated) {
    810             // This is a brand new button, so append it to m_buttons
    811             m_buttons.append(*updatedContainer);
    812         }
    813     }
    814     size_t i = 0;
    815     // count will decrease each time one is removed, so check count each time.
    816     while (i < m_buttons.size()) {
    817         if (m_buttons[i].canBeRemoved()) {
    818             m_buttons[i] = m_buttons.last();
    819             m_buttons.removeLast();
    820         } else {
    821             i++;
    822         }
    823     }
    824 }
    825 
    826 // note: updateCursorBounds is called directly by the WebView thread
    827 // This needs to be called each time we call CachedRoot::setCursor() with
    828 // non-null CachedNode/CachedFrame, since otherwise the WebViewCore's data
    829 // about the cursor is incorrect.  When we call setCursor(0,0), we need
    830 // to set hasCursorBounds to false.
    831 void WebViewCore::updateCursorBounds(const CachedRoot* root,
    832         const CachedFrame* cachedFrame, const CachedNode* cachedNode)
    833 {
    834     LOG_ASSERT(root, "updateCursorBounds: root cannot be null");
    835     LOG_ASSERT(cachedNode, "updateCursorBounds: cachedNode cannot be null");
    836     LOG_ASSERT(cachedFrame, "updateCursorBounds: cachedFrame cannot be null");
    837     gCursorBoundsMutex.lock();
    838     m_hasCursorBounds = !cachedNode->isHidden();
    839     // If m_hasCursorBounds is false, we never look at the other
    840     // values, so do not bother setting them.
    841     if (m_hasCursorBounds) {
    842         WebCore::IntRect bounds = cachedNode->bounds(cachedFrame);
    843         if (m_cursorBounds != bounds)
    844             DBG_NAV_LOGD("new cursor bounds=(%d,%d,w=%d,h=%d)",
    845                 bounds.x(), bounds.y(), bounds.width(), bounds.height());
    846         m_cursorBounds = bounds;
    847         m_cursorHitBounds = cachedNode->hitBounds(cachedFrame);
    848         m_cursorFrame = cachedFrame->framePointer();
    849         root->getSimulatedMousePosition(&m_cursorLocation);
    850         m_cursorNode = cachedNode->nodePointer();
    851     }
    852     gCursorBoundsMutex.unlock();
    853 }
    854 
    855 void WebViewCore::clearContent()
    856 {
    857     DBG_SET_LOG("");
    858     m_content.clear();
    859     m_addInval.setEmpty();
    860     m_rebuildInval.setEmpty();
    861 }
    862 
    863 bool WebViewCore::focusBoundsChanged()
    864 {
    865     bool result = m_focusBoundsChanged;
    866     m_focusBoundsChanged = false;
    867     return result;
    868 }
    869 
    870 SkPicture* WebViewCore::rebuildPicture(const SkIRect& inval)
    871 {
    872     WebCore::FrameView* view = m_mainFrame->view();
    873     int width = view->contentsWidth();
    874     int height = view->contentsHeight();
    875     SkPicture* picture = new SkPicture();
    876     SkAutoPictureRecord arp(picture, width, height, PICT_RECORD_FLAGS);
    877     SkAutoMemoryUsageProbe mup(__FUNCTION__);
    878     SkCanvas* recordingCanvas = arp.getRecordingCanvas();
    879 
    880     gButtonMutex.lock();
    881     WTF::Vector<Container> buttons(m_buttons);
    882     gButtonMutex.unlock();
    883 
    884     WebCore::PlatformGraphicsContext pgc(recordingCanvas, &buttons);
    885     WebCore::GraphicsContext gc(&pgc);
    886     recordingCanvas->translate(-inval.fLeft, -inval.fTop);
    887     recordingCanvas->save();
    888     view->platformWidget()->draw(&gc, WebCore::IntRect(inval.fLeft,
    889         inval.fTop, inval.width(), inval.height()));
    890     m_rebuildInval.op(inval, SkRegion::kUnion_Op);
    891     DBG_SET_LOGD("m_rebuildInval={%d,%d,r=%d,b=%d}",
    892         m_rebuildInval.getBounds().fLeft, m_rebuildInval.getBounds().fTop,
    893         m_rebuildInval.getBounds().fRight, m_rebuildInval.getBounds().fBottom);
    894 
    895     gButtonMutex.lock();
    896     updateButtonList(&buttons);
    897     gButtonMutex.unlock();
    898 
    899     return picture;
    900 }
    901 
    902 void WebViewCore::rebuildPictureSet(PictureSet* pictureSet)
    903 {
    904     WebCore::FrameView* view = m_mainFrame->view();
    905 
    906 #ifdef FAST_PICTURESET
    907     WTF::Vector<Bucket*>* buckets = pictureSet->bucketsToUpdate();
    908 
    909     for (unsigned int i = 0; i < buckets->size(); i++) {
    910         Bucket* bucket = (*buckets)[i];
    911         for (unsigned int j = 0; j < bucket->size(); j++) {
    912             BucketPicture& bucketPicture = (*bucket)[j];
    913             const SkIRect& inval = bucketPicture.mRealArea;
    914             SkPicture* picture = rebuildPicture(inval);
    915             SkSafeUnref(bucketPicture.mPicture);
    916             bucketPicture.mPicture = picture;
    917         }
    918     }
    919     buckets->clear();
    920 #else
    921     size_t size = pictureSet->size();
    922     for (size_t index = 0; index < size; index++) {
    923         if (pictureSet->upToDate(index))
    924             continue;
    925         const SkIRect& inval = pictureSet->bounds(index);
    926         DBG_SET_LOGD("pictSet=%p [%d] {%d,%d,w=%d,h=%d}", pictureSet, index,
    927             inval.fLeft, inval.fTop, inval.width(), inval.height());
    928         pictureSet->setPicture(index, rebuildPicture(inval));
    929     }
    930 
    931     pictureSet->validate(__FUNCTION__);
    932 #endif
    933 }
    934 
    935 bool WebViewCore::updateLayers(LayerAndroid* layers)
    936 {
    937     // We update the layers
    938     ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(m_mainFrame->page()->chrome()->client());
    939     GraphicsLayerAndroid* root = static_cast<GraphicsLayerAndroid*>(chromeC->layersSync());
    940     if (root) {
    941         root->notifyClientAnimationStarted();
    942         LayerAndroid* updatedLayer = root->contentLayer();
    943         return layers->updateWithTree(updatedLayer);
    944     }
    945     return true;
    946 }
    947 
    948 BaseLayerAndroid* WebViewCore::createBaseLayer(SkRegion* region)
    949 {
    950     BaseLayerAndroid* base = new BaseLayerAndroid();
    951     base->setContent(m_content);
    952 
    953     if (!region->isEmpty()) {
    954         m_skipContentDraw = true;
    955         bool layoutSucceeded = layoutIfNeededRecursive(m_mainFrame);
    956         m_skipContentDraw = false;
    957         // Layout only fails if called during a layout.
    958         LOG_ASSERT(layoutSucceeded, "Can never be called recursively");
    959     }
    960 
    961 #if USE(ACCELERATED_COMPOSITING)
    962     // We set the background color
    963     if (!region->isEmpty() && m_mainFrame && m_mainFrame->document()
    964         && m_mainFrame->document()->body()) {
    965         Document* document = m_mainFrame->document();
    966         RefPtr<RenderStyle> style = document->styleForElementIgnoringPendingStylesheets(document->body());
    967         if (style->hasBackground()) {
    968             Color color = style->visitedDependentColor(CSSPropertyBackgroundColor);
    969             if (color.isValid() && color.alpha() > 0)
    970                 base->setBackgroundColor(color);
    971         }
    972     }
    973 
    974     // We update the layers
    975     ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(m_mainFrame->page()->chrome()->client());
    976     GraphicsLayerAndroid* root = static_cast<GraphicsLayerAndroid*>(chromeC->layersSync());
    977     if (root) {
    978         root->notifyClientAnimationStarted();
    979         LayerAndroid* copyLayer = new LayerAndroid(*root->contentLayer());
    980         base->addChild(copyLayer);
    981         copyLayer->unref();
    982         root->contentLayer()->clearDirtyRegion();
    983     }
    984 #endif
    985 
    986     return base;
    987 }
    988 
    989 BaseLayerAndroid* WebViewCore::recordContent(SkRegion* region, SkIPoint* point)
    990 {
    991     DBG_SET_LOG("start");
    992     // If there is a pending style recalculation, just return.
    993     if (m_mainFrame->document()->isPendingStyleRecalc()) {
    994         DBG_SET_LOGD("recordContent: pending style recalc, ignoring.");
    995         return 0;
    996     }
    997     float progress = (float) m_mainFrame->page()->progress()->estimatedProgress();
    998     m_progressDone = progress <= 0.0f || progress >= 1.0f;
    999     recordPictureSet(&m_content);
   1000     if (!m_progressDone && m_content.isEmpty()) {
   1001         DBG_SET_LOGD("empty (progress=%g)", progress);
   1002         return 0;
   1003     }
   1004     region->set(m_addInval);
   1005     m_addInval.setEmpty();
   1006 #if USE(ACCELERATED_COMPOSITING)
   1007 #else
   1008     region->op(m_rebuildInval, SkRegion::kUnion_Op);
   1009 #endif
   1010     m_rebuildInval.setEmpty();
   1011     point->fX = m_content.width();
   1012     point->fY = m_content.height();
   1013     DBG_SET_LOGD("region={%d,%d,r=%d,b=%d}", region->getBounds().fLeft,
   1014         region->getBounds().fTop, region->getBounds().fRight,
   1015         region->getBounds().fBottom);
   1016     DBG_SET_LOG("end");
   1017 
   1018     return createBaseLayer(region);
   1019 }
   1020 
   1021 void WebViewCore::splitContent(PictureSet* content)
   1022 {
   1023 #ifdef FAST_PICTURESET
   1024 #else
   1025     bool layoutSucceeded = layoutIfNeededRecursive(m_mainFrame);
   1026     LOG_ASSERT(layoutSucceeded, "Can never be called recursively");
   1027     content->split(&m_content);
   1028     rebuildPictureSet(&m_content);
   1029     content->set(m_content);
   1030 #endif // FAST_PICTURESET
   1031 }
   1032 
   1033 void WebViewCore::scrollTo(int x, int y, bool animate)
   1034 {
   1035     LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
   1036 
   1037 //    LOGD("WebViewCore::scrollTo(%d %d)\n", x, y);
   1038 
   1039     JNIEnv* env = JSC::Bindings::getJNIEnv();
   1040     AutoJObject javaObject = m_javaGlue->object(env);
   1041     if (!javaObject.get())
   1042         return;
   1043     env->CallVoidMethod(javaObject.get(), m_javaGlue->m_scrollTo,
   1044             x, y, animate, false);
   1045     checkException(env);
   1046 }
   1047 
   1048 void WebViewCore::sendNotifyProgressFinished()
   1049 {
   1050     LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
   1051     JNIEnv* env = JSC::Bindings::getJNIEnv();
   1052     AutoJObject javaObject = m_javaGlue->object(env);
   1053     if (!javaObject.get())
   1054         return;
   1055     env->CallVoidMethod(javaObject.get(), m_javaGlue->m_sendNotifyProgressFinished);
   1056     checkException(env);
   1057 }
   1058 
   1059 void WebViewCore::viewInvalidate(const WebCore::IntRect& rect)
   1060 {
   1061     LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
   1062     JNIEnv* env = JSC::Bindings::getJNIEnv();
   1063     AutoJObject javaObject = m_javaGlue->object(env);
   1064     if (!javaObject.get())
   1065         return;
   1066     env->CallVoidMethod(javaObject.get(),
   1067                         m_javaGlue->m_sendViewInvalidate,
   1068                         rect.x(), rect.y(), rect.maxX(), rect.maxY());
   1069     checkException(env);
   1070 }
   1071 
   1072 void WebViewCore::contentDraw()
   1073 {
   1074     JNIEnv* env = JSC::Bindings::getJNIEnv();
   1075     AutoJObject javaObject = m_javaGlue->object(env);
   1076     if (!javaObject.get())
   1077         return;
   1078     env->CallVoidMethod(javaObject.get(), m_javaGlue->m_contentDraw);
   1079     checkException(env);
   1080 }
   1081 
   1082 void WebViewCore::layersDraw()
   1083 {
   1084     JNIEnv* env = JSC::Bindings::getJNIEnv();
   1085     AutoJObject javaObject = m_javaGlue->object(env);
   1086     if (!javaObject.get())
   1087         return;
   1088     env->CallVoidMethod(javaObject.get(), m_javaGlue->m_layersDraw);
   1089     checkException(env);
   1090 }
   1091 
   1092 void WebViewCore::contentInvalidate(const WebCore::IntRect &r)
   1093 {
   1094     DBG_SET_LOGD("rect={%d,%d,w=%d,h=%d}", r.x(), r.y(), r.width(), r.height());
   1095     SkIRect rect(r);
   1096     if (!rect.intersect(0, 0, INT_MAX, INT_MAX))
   1097         return;
   1098     m_addInval.op(rect, SkRegion::kUnion_Op);
   1099     DBG_SET_LOGD("m_addInval={%d,%d,r=%d,b=%d}",
   1100         m_addInval.getBounds().fLeft, m_addInval.getBounds().fTop,
   1101         m_addInval.getBounds().fRight, m_addInval.getBounds().fBottom);
   1102     if (!m_skipContentDraw)
   1103         contentDraw();
   1104 }
   1105 
   1106 void WebViewCore::contentInvalidateAll()
   1107 {
   1108     WebCore::FrameView* view = m_mainFrame->view();
   1109     contentInvalidate(WebCore::IntRect(0, 0,
   1110         view->contentsWidth(), view->contentsHeight()));
   1111 }
   1112 
   1113 void WebViewCore::offInvalidate(const WebCore::IntRect &r)
   1114 {
   1115     // FIXME: these invalidates are offscreen, and can be throttled or
   1116     // deferred until the area is visible. For now, treat them as
   1117     // regular invals so that drawing happens (inefficiently) for now.
   1118     contentInvalidate(r);
   1119 }
   1120 
   1121 static int pin_pos(int x, int width, int targetWidth)
   1122 {
   1123     if (x + width > targetWidth)
   1124         x = targetWidth - width;
   1125     if (x < 0)
   1126         x = 0;
   1127     return x;
   1128 }
   1129 
   1130 void WebViewCore::didFirstLayout()
   1131 {
   1132     DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
   1133     LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
   1134 
   1135     JNIEnv* env = JSC::Bindings::getJNIEnv();
   1136     AutoJObject javaObject = m_javaGlue->object(env);
   1137     if (!javaObject.get())
   1138         return;
   1139 
   1140     const WebCore::KURL& url = m_mainFrame->document()->url();
   1141     if (url.isEmpty())
   1142         return;
   1143     LOGV("::WebCore:: didFirstLayout %s", url.string().ascii().data());
   1144 
   1145     WebCore::FrameLoadType loadType = m_mainFrame->loader()->loadType();
   1146 
   1147     env->CallVoidMethod(javaObject.get(), m_javaGlue->m_didFirstLayout,
   1148             loadType == WebCore::FrameLoadTypeStandard
   1149             // When redirect with locked history, we would like to reset the
   1150             // scale factor. This is important for www.yahoo.com as it is
   1151             // redirected to www.yahoo.com/?rs=1 on load.
   1152             || loadType == WebCore::FrameLoadTypeRedirectWithLockedBackForwardList);
   1153     checkException(env);
   1154 
   1155     DBG_NAV_LOG("call updateFrameCache");
   1156     m_check_domtree_version = false;
   1157     updateFrameCache();
   1158     m_history.setDidFirstLayout(true);
   1159 }
   1160 
   1161 void WebViewCore::updateViewport()
   1162 {
   1163     DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
   1164     LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
   1165 
   1166     JNIEnv* env = JSC::Bindings::getJNIEnv();
   1167     AutoJObject javaObject = m_javaGlue->object(env);
   1168     if (!javaObject.get())
   1169         return;
   1170     env->CallVoidMethod(javaObject.get(), m_javaGlue->m_updateViewport);
   1171     checkException(env);
   1172 }
   1173 
   1174 void WebViewCore::restoreScale(float scale, float textWrapScale)
   1175 {
   1176     DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
   1177     LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
   1178 
   1179     JNIEnv* env = JSC::Bindings::getJNIEnv();
   1180     AutoJObject javaObject = m_javaGlue->object(env);
   1181     if (!javaObject.get())
   1182         return;
   1183     env->CallVoidMethod(javaObject.get(), m_javaGlue->m_restoreScale, scale, textWrapScale);
   1184     checkException(env);
   1185 }
   1186 
   1187 void WebViewCore::needTouchEvents(bool need)
   1188 {
   1189     DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
   1190     LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
   1191 
   1192 #if ENABLE(TOUCH_EVENTS)
   1193     JNIEnv* env = JSC::Bindings::getJNIEnv();
   1194     AutoJObject javaObject = m_javaGlue->object(env);
   1195     if (!javaObject.get())
   1196         return;
   1197 
   1198     if (m_forwardingTouchEvents == need)
   1199         return;
   1200 
   1201     env->CallVoidMethod(javaObject.get(), m_javaGlue->m_needTouchEvents, need);
   1202     checkException(env);
   1203 
   1204     m_forwardingTouchEvents = need;
   1205 #endif
   1206 }
   1207 
   1208 void WebViewCore::requestKeyboardWithSelection(const WebCore::Node* node,
   1209         int selStart, int selEnd)
   1210 {
   1211     DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
   1212     LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
   1213 
   1214     JNIEnv* env = JSC::Bindings::getJNIEnv();
   1215     AutoJObject javaObject = m_javaGlue->object(env);
   1216     if (!javaObject.get())
   1217         return;
   1218     env->CallVoidMethod(javaObject.get(),
   1219             m_javaGlue->m_requestKeyboardWithSelection,
   1220             reinterpret_cast<int>(node), selStart, selEnd, m_textGeneration);
   1221     checkException(env);
   1222 }
   1223 
   1224 void WebViewCore::requestKeyboard(bool showKeyboard)
   1225 {
   1226     DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
   1227     LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
   1228 
   1229     JNIEnv* env = JSC::Bindings::getJNIEnv();
   1230     AutoJObject javaObject = m_javaGlue->object(env);
   1231     if (!javaObject.get())
   1232         return;
   1233     env->CallVoidMethod(javaObject.get(), m_javaGlue->m_requestKeyboard, showKeyboard);
   1234     checkException(env);
   1235 }
   1236 
   1237 void WebViewCore::notifyProgressFinished()
   1238 {
   1239     m_check_domtree_version = true;
   1240     sendNotifyProgressFinished();
   1241 }
   1242 
   1243 void WebViewCore::doMaxScroll(CacheBuilder::Direction dir)
   1244 {
   1245     int dx = 0, dy = 0;
   1246 
   1247     switch (dir) {
   1248     case CacheBuilder::LEFT:
   1249         dx = -m_maxXScroll;
   1250         break;
   1251     case CacheBuilder::UP:
   1252         dy = -m_maxYScroll;
   1253         break;
   1254     case CacheBuilder::RIGHT:
   1255         dx = m_maxXScroll;
   1256         break;
   1257     case CacheBuilder::DOWN:
   1258         dy = m_maxYScroll;
   1259         break;
   1260     case CacheBuilder::UNINITIALIZED:
   1261     default:
   1262         LOG_ASSERT(0, "unexpected focus selector");
   1263     }
   1264     WebCore::FrameView* view = m_mainFrame->view();
   1265     this->scrollTo(view->scrollX() + dx, view->scrollY() + dy, true);
   1266 }
   1267 
   1268 void WebViewCore::setScrollOffset(int moveGeneration, bool sendScrollEvent, int dx, int dy)
   1269 {
   1270     DBG_NAV_LOGD("{%d,%d} m_scrollOffset=(%d,%d), sendScrollEvent=%d", dx, dy,
   1271         m_scrollOffsetX, m_scrollOffsetY, sendScrollEvent);
   1272     if (m_scrollOffsetX != dx || m_scrollOffsetY != dy) {
   1273         m_scrollOffsetX = dx;
   1274         m_scrollOffsetY = dy;
   1275         // The visible rect is located within our coordinate space so it
   1276         // contains the actual scroll position. Setting the location makes hit
   1277         // testing work correctly.
   1278         m_mainFrame->view()->platformWidget()->setLocation(m_scrollOffsetX,
   1279                 m_scrollOffsetY);
   1280         if (sendScrollEvent) {
   1281             m_mainFrame->eventHandler()->sendScrollEvent();
   1282 
   1283             // Only update history position if it's user scrolled.
   1284             // Update history item to reflect the new scroll position.
   1285             // This also helps save the history information when the browser goes to
   1286             // background, so scroll position will be restored if browser gets
   1287             // killed while in background.
   1288             WebCore::HistoryController* history = m_mainFrame->loader()->history();
   1289             // Because the history item saving could be heavy for large sites and
   1290             // scrolling can generate lots of small scroll offset, the following code
   1291             // reduces the saving frequency.
   1292             static const int MIN_SCROLL_DIFF = 32;
   1293             if (history->currentItem()) {
   1294                 WebCore::IntPoint currentPoint = history->currentItem()->scrollPoint();
   1295                 if (std::abs(currentPoint.x() - dx) >= MIN_SCROLL_DIFF ||
   1296                     std::abs(currentPoint.y() - dy) >= MIN_SCROLL_DIFF) {
   1297                     history->saveScrollPositionAndViewStateToItem(history->currentItem());
   1298                 }
   1299             }
   1300         }
   1301 
   1302         // update the currently visible screen
   1303         sendPluginVisibleScreen();
   1304     }
   1305     gCursorBoundsMutex.lock();
   1306     bool hasCursorBounds = m_hasCursorBounds;
   1307     Frame* frame = (Frame*) m_cursorFrame;
   1308     IntPoint location = m_cursorLocation;
   1309     gCursorBoundsMutex.unlock();
   1310     if (!hasCursorBounds)
   1311         return;
   1312     moveMouseIfLatest(moveGeneration, frame, location.x(), location.y());
   1313 }
   1314 
   1315 void WebViewCore::setGlobalBounds(int x, int y, int h, int v)
   1316 {
   1317     DBG_NAV_LOGD("{%d,%d}", x, y);
   1318     m_mainFrame->view()->platformWidget()->setWindowBounds(x, y, h, v);
   1319 }
   1320 
   1321 void WebViewCore::setSizeScreenWidthAndScale(int width, int height,
   1322     int textWrapWidth, float scale, int screenWidth, int screenHeight,
   1323     int anchorX, int anchorY, bool ignoreHeight)
   1324 {
   1325     // Ignore the initial empty document.
   1326     const WebCore::KURL& url = m_mainFrame->document()->url();
   1327     if (url.isEmpty())
   1328         return;
   1329 
   1330     WebCoreViewBridge* window = m_mainFrame->view()->platformWidget();
   1331     int ow = window->width();
   1332     int oh = window->height();
   1333     int osw = m_screenWidth;
   1334     int osh = m_screenHeight;
   1335     int otw = m_textWrapWidth;
   1336     float oldScale = m_scale;
   1337     DBG_NAV_LOGD("old:(w=%d,h=%d,sw=%d,scale=%g) new:(w=%d,h=%d,sw=%d,scale=%g)",
   1338         ow, oh, osw, m_scale, width, height, screenWidth, scale);
   1339     m_screenWidth = screenWidth;
   1340     m_screenHeight = screenHeight;
   1341     m_textWrapWidth = textWrapWidth;
   1342     if (scale >= 0) // negative means keep the current scale
   1343         m_scale = scale;
   1344     m_maxXScroll = screenWidth >> 2;
   1345     m_maxYScroll = m_maxXScroll * height / width;
   1346     // Don't reflow if the diff is small.
   1347     const bool reflow = otw && textWrapWidth &&
   1348         ((float) abs(otw - textWrapWidth) / textWrapWidth) >= 0.01f;
   1349 
   1350     // When the screen size change, fixed positioned element should be updated.
   1351     // This is supposed to be light weighted operation without a full layout.
   1352     if (osh != screenHeight || osw != screenWidth)
   1353         m_mainFrame->view()->updatePositionedObjects();
   1354 
   1355     if (ow != width || (!ignoreHeight && oh != height) || reflow) {
   1356         WebCore::RenderObject *r = m_mainFrame->contentRenderer();
   1357         DBG_NAV_LOGD("renderer=%p view=(w=%d,h=%d)", r,
   1358                 screenWidth, screenHeight);
   1359         if (r) {
   1360             WebCore::IntPoint anchorPoint = WebCore::IntPoint(anchorX, anchorY);
   1361             DBG_NAV_LOGD("anchorX=%d anchorY=%d", anchorX, anchorY);
   1362             RefPtr<WebCore::Node> node;
   1363             WebCore::IntRect bounds;
   1364             WebCore::IntPoint offset;
   1365             // If the text wrap changed, it is probably zoom change or
   1366             // orientation change. Try to keep the anchor at the same place.
   1367             if (otw && textWrapWidth && otw != textWrapWidth &&
   1368                 (anchorX != 0 || anchorY != 0)) {
   1369                 WebCore::HitTestResult hitTestResult =
   1370                         m_mainFrame->eventHandler()->hitTestResultAtPoint(
   1371                                 anchorPoint, false);
   1372                 node = hitTestResult.innerNode();
   1373             }
   1374             if (node) {
   1375                 bounds = node->getRect();
   1376                 DBG_NAV_LOGD("ob:(x=%d,y=%d,w=%d,h=%d)",
   1377                     bounds.x(), bounds.y(), bounds.width(), bounds.height());
   1378                 // sites like nytimes.com insert a non-standard tag <nyt_text>
   1379                 // in the html. If it is the HitTestResult, it may have zero
   1380                 // width and height. In this case, use its parent node.
   1381                 if (bounds.width() == 0) {
   1382                     node = node->parentOrHostNode();
   1383                     if (node) {
   1384                         bounds = node->getRect();
   1385                         DBG_NAV_LOGD("found a zero width node and use its parent, whose ob:(x=%d,y=%d,w=%d,h=%d)",
   1386                                 bounds.x(), bounds.y(), bounds.width(), bounds.height());
   1387                     }
   1388                 }
   1389             }
   1390 
   1391             // Set the size after finding the old anchor point as
   1392             // hitTestResultAtPoint causes a layout.
   1393             window->setSize(width, height);
   1394             window->setVisibleSize(screenWidth, screenHeight);
   1395             if (width != screenWidth) {
   1396                 m_mainFrame->view()->setUseFixedLayout(true);
   1397                 m_mainFrame->view()->setFixedLayoutSize(IntSize(width, height));
   1398             } else {
   1399                 m_mainFrame->view()->setUseFixedLayout(false);
   1400             }
   1401             r->setNeedsLayoutAndPrefWidthsRecalc();
   1402             m_mainFrame->view()->forceLayout();
   1403 
   1404             // scroll to restore current screen center
   1405             if (node) {
   1406                 const WebCore::IntRect& newBounds = node->getRect();
   1407                 DBG_NAV_LOGD("nb:(x=%d,y=%d,w=%d,"
   1408                     "h=%d)", newBounds.x(), newBounds.y(),
   1409                     newBounds.width(), newBounds.height());
   1410                 if ((osw && osh && bounds.width() && bounds.height())
   1411                     && (bounds != newBounds)) {
   1412                     WebCore::FrameView* view = m_mainFrame->view();
   1413                     // force left align if width is not changed while height changed.
   1414                     // the anchorPoint is probably at some white space in the node
   1415                     // which is affected by text wrap around the screen width.
   1416                     const bool leftAlign = (otw != textWrapWidth)
   1417                         && (bounds.width() == newBounds.width())
   1418                         && (bounds.height() != newBounds.height());
   1419                     const float xPercentInDoc =
   1420                         leftAlign ? 0.0 : (float) (anchorX - bounds.x()) / bounds.width();
   1421                     const float xPercentInView =
   1422                         leftAlign ? 0.0 : (float) (anchorX - m_scrollOffsetX) / osw;
   1423                     const float yPercentInDoc = (float) (anchorY - bounds.y()) / bounds.height();
   1424                     const float yPercentInView = (float) (anchorY - m_scrollOffsetY) / osh;
   1425                     showRect(newBounds.x(), newBounds.y(), newBounds.width(),
   1426                              newBounds.height(), view->contentsWidth(),
   1427                              view->contentsHeight(),
   1428                              xPercentInDoc, xPercentInView,
   1429                              yPercentInDoc, yPercentInView);
   1430                 }
   1431             }
   1432         }
   1433     } else {
   1434         window->setSize(width, height);
   1435         window->setVisibleSize(screenWidth, screenHeight);
   1436         m_mainFrame->view()->resize(width, height);
   1437         if (width != screenWidth) {
   1438             m_mainFrame->view()->setUseFixedLayout(true);
   1439             m_mainFrame->view()->setFixedLayoutSize(IntSize(width, height));
   1440         } else {
   1441             m_mainFrame->view()->setUseFixedLayout(false);
   1442         }
   1443     }
   1444 
   1445     // update the currently visible screen as perceived by the plugin
   1446     sendPluginVisibleScreen();
   1447 }
   1448 
   1449 void WebViewCore::dumpDomTree(bool useFile)
   1450 {
   1451 #ifdef ANDROID_DOM_LOGGING
   1452     if (useFile)
   1453         gDomTreeFile = fopen(DOM_TREE_LOG_FILE, "w");
   1454     m_mainFrame->document()->showTreeForThis();
   1455     if (gDomTreeFile) {
   1456         fclose(gDomTreeFile);
   1457         gDomTreeFile = 0;
   1458     }
   1459 #endif
   1460 }
   1461 
   1462 void WebViewCore::dumpRenderTree(bool useFile)
   1463 {
   1464 #ifdef ANDROID_DOM_LOGGING
   1465     WTF::CString renderDump = WebCore::externalRepresentation(m_mainFrame).utf8();
   1466     const char* data = renderDump.data();
   1467     if (useFile) {
   1468         gRenderTreeFile = fopen(RENDER_TREE_LOG_FILE, "w");
   1469         DUMP_RENDER_LOGD("%s", data);
   1470         fclose(gRenderTreeFile);
   1471         gRenderTreeFile = 0;
   1472     } else {
   1473         // adb log can only output 1024 characters, so write out line by line.
   1474         // exclude '\n' as adb log adds it for each output.
   1475         int length = renderDump.length();
   1476         for (int i = 0, last = 0; i < length; i++) {
   1477             if (data[i] == '\n') {
   1478                 if (i != last)
   1479                     DUMP_RENDER_LOGD("%.*s", (i - last), &(data[last]));
   1480                 last = i + 1;
   1481             }
   1482         }
   1483     }
   1484 #endif
   1485 }
   1486 
   1487 void WebViewCore::dumpNavTree()
   1488 {
   1489 #if DUMP_NAV_CACHE
   1490     cacheBuilder().mDebug.print();
   1491 #endif
   1492 }
   1493 
   1494 HTMLElement* WebViewCore::retrieveElement(int x, int y,
   1495     const QualifiedName& tagName)
   1496 {
   1497     HitTestResult hitTestResult = m_mainFrame->eventHandler()
   1498         ->hitTestResultAtPoint(IntPoint(x, y), false, false,
   1499         DontHitTestScrollbars, HitTestRequest::Active | HitTestRequest::ReadOnly,
   1500         IntSize(1, 1));
   1501     if (!hitTestResult.innerNode() || !hitTestResult.innerNode()->inDocument()) {
   1502         LOGE("Should not happen: no in document Node found");
   1503         return 0;
   1504     }
   1505     const ListHashSet<RefPtr<Node> >& list = hitTestResult.rectBasedTestResult();
   1506     if (list.isEmpty()) {
   1507         LOGE("Should not happen: no rect-based-test nodes found");
   1508         return 0;
   1509     }
   1510     Node* node = hitTestResult.innerNode();
   1511     Node* element = node;
   1512     while (element && (!element->isElementNode()
   1513         || !element->hasTagName(tagName))) {
   1514         element = element->parentNode();
   1515     }
   1516     DBG_NAV_LOGD("node=%p element=%p x=%d y=%d nodeName=%s tagName=%s", node,
   1517         element, x, y, node->nodeName().utf8().data(),
   1518         element ? ((Element*) element)->tagName().utf8().data() : "<none>");
   1519     return static_cast<WebCore::HTMLElement*>(element);
   1520 }
   1521 
   1522 HTMLAnchorElement* WebViewCore::retrieveAnchorElement(int x, int y)
   1523 {
   1524     return static_cast<HTMLAnchorElement*>
   1525         (retrieveElement(x, y, HTMLNames::aTag));
   1526 }
   1527 
   1528 HTMLImageElement* WebViewCore::retrieveImageElement(int x, int y)
   1529 {
   1530     return static_cast<HTMLImageElement*>
   1531         (retrieveElement(x, y, HTMLNames::imgTag));
   1532 }
   1533 
   1534 WTF::String WebViewCore::retrieveHref(int x, int y)
   1535 {
   1536     WebCore::HTMLAnchorElement* anchor = retrieveAnchorElement(x, y);
   1537     return anchor ? anchor->href() : WTF::String();
   1538 }
   1539 
   1540 WTF::String WebViewCore::retrieveAnchorText(int x, int y)
   1541 {
   1542     WebCore::HTMLAnchorElement* anchor = retrieveAnchorElement(x, y);
   1543     return anchor ? anchor->text() : WTF::String();
   1544 }
   1545 
   1546 WTF::String WebViewCore::retrieveImageSource(int x, int y)
   1547 {
   1548     HTMLImageElement* image = retrieveImageElement(x, y);
   1549     return image ? image->src().string() : WTF::String();
   1550 }
   1551 
   1552 WTF::String WebViewCore::requestLabel(WebCore::Frame* frame,
   1553         WebCore::Node* node)
   1554 {
   1555     if (node && CacheBuilder::validNode(m_mainFrame, frame, node)) {
   1556         RefPtr<WebCore::NodeList> list = node->document()->getElementsByTagName("label");
   1557         unsigned length = list->length();
   1558         for (unsigned i = 0; i < length; i++) {
   1559             WebCore::HTMLLabelElement* label = static_cast<WebCore::HTMLLabelElement*>(
   1560                     list->item(i));
   1561             if (label->control() == node) {
   1562                 Node* node = label;
   1563                 String result;
   1564                 while ((node = node->traverseNextNode(label))) {
   1565                     if (node->isTextNode()) {
   1566                         Text* textNode = static_cast<Text*>(node);
   1567                         result += textNode->dataImpl();
   1568                     }
   1569                 }
   1570                 return result;
   1571             }
   1572         }
   1573     }
   1574     return WTF::String();
   1575 }
   1576 
   1577 static bool isContentEditable(const WebCore::Node* node)
   1578 {
   1579     if (!node) return false;
   1580     return node->document()->frame()->selection()->isContentEditable();
   1581 }
   1582 
   1583 // Returns true if the node is a textfield, textarea, or contentEditable
   1584 static bool isTextInput(const WebCore::Node* node)
   1585 {
   1586     if (isContentEditable(node))
   1587         return true;
   1588     if (!node)
   1589         return false;
   1590     WebCore::RenderObject* renderer = node->renderer();
   1591     return renderer && (renderer->isTextField() || renderer->isTextArea());
   1592 }
   1593 
   1594 void WebViewCore::revealSelection()
   1595 {
   1596     WebCore::Node* focus = currentFocus();
   1597     if (!focus)
   1598         return;
   1599     if (!isTextInput(focus))
   1600         return;
   1601     WebCore::Frame* focusedFrame = focus->document()->frame();
   1602     if (!focusedFrame->page()->focusController()->isActive())
   1603         return;
   1604     focusedFrame->selection()->revealSelection(ScrollAlignment::alignToEdgeIfNeeded);
   1605 }
   1606 
   1607 void WebViewCore::updateCacheOnNodeChange()
   1608 {
   1609     gCursorBoundsMutex.lock();
   1610     bool hasCursorBounds = m_hasCursorBounds;
   1611     Frame* frame = (Frame*) m_cursorFrame;
   1612     Node* node = (Node*) m_cursorNode;
   1613     IntRect bounds = m_cursorHitBounds;
   1614     gCursorBoundsMutex.unlock();
   1615     if (!hasCursorBounds || !node)
   1616         return;
   1617     if (CacheBuilder::validNode(m_mainFrame, frame, node)) {
   1618         RenderObject* renderer = node->renderer();
   1619         if (renderer && renderer->style()->visibility() != HIDDEN) {
   1620             IntRect absBox = renderer->absoluteBoundingBoxRect();
   1621             int globalX, globalY;
   1622             CacheBuilder::GetGlobalOffset(frame, &globalX, &globalY);
   1623             absBox.move(globalX, globalY);
   1624             if (absBox == bounds)
   1625                 return;
   1626             DBG_NAV_LOGD("absBox=(%d,%d,%d,%d) bounds=(%d,%d,%d,%d)",
   1627                 absBox.x(), absBox.y(), absBox.width(), absBox.height(),
   1628                 bounds.x(), bounds.y(), bounds.width(), bounds.height());
   1629         }
   1630     }
   1631     DBG_NAV_LOGD("updateFrameCache node=%p", node);
   1632     updateFrameCache();
   1633 }
   1634 
   1635 void WebViewCore::updateFrameCache()
   1636 {
   1637     if (!m_frameCacheOutOfDate) {
   1638         DBG_NAV_LOG("!m_frameCacheOutOfDate");
   1639         return;
   1640     }
   1641 
   1642     // If there is a pending style recalculation, do not update the frame cache.
   1643     // Until the recalculation is complete, there may be internal objects that
   1644     // are in an inconsistent state (such as font pointers).
   1645     // In any event, there's not much point to updating the cache while a style
   1646     // recalculation is pending, since it will simply have to be updated again
   1647     // once the recalculation is complete.
   1648     // TODO: Do we need to reschedule an update for after the style is recalculated?
   1649     if (m_mainFrame && m_mainFrame->document() && m_mainFrame->document()->isPendingStyleRecalc()) {
   1650         LOGW("updateFrameCache: pending style recalc, ignoring.");
   1651         return;
   1652     }
   1653 #ifdef ANDROID_INSTRUMENT
   1654     TimeCounterAuto counter(TimeCounter::WebViewCoreBuildNavTimeCounter);
   1655 #endif
   1656     m_frameCacheOutOfDate = false;
   1657     m_temp = new CachedRoot();
   1658     m_temp->init(m_mainFrame, &m_history);
   1659 #if USE(ACCELERATED_COMPOSITING)
   1660     GraphicsLayerAndroid* graphicsLayer = graphicsRootLayer();
   1661     if (graphicsLayer)
   1662         m_temp->setRootLayer(graphicsLayer->contentLayer());
   1663 #endif
   1664     CacheBuilder& builder = cacheBuilder();
   1665     WebCore::Settings* settings = m_mainFrame->page()->settings();
   1666     builder.allowAllTextDetection();
   1667 #ifdef ANDROID_META_SUPPORT
   1668     if (settings) {
   1669         if (!settings->formatDetectionAddress())
   1670             builder.disallowAddressDetection();
   1671         if (!settings->formatDetectionEmail())
   1672             builder.disallowEmailDetection();
   1673         if (!settings->formatDetectionTelephone())
   1674             builder.disallowPhoneDetection();
   1675     }
   1676 #endif
   1677     builder.buildCache(m_temp);
   1678     m_tempPict = new SkPicture();
   1679     recordPicture(m_tempPict);
   1680     m_temp->setPicture(m_tempPict);
   1681     m_temp->setTextGeneration(m_textGeneration);
   1682     WebCoreViewBridge* window = m_mainFrame->view()->platformWidget();
   1683     m_temp->setVisibleRect(WebCore::IntRect(m_scrollOffsetX,
   1684         m_scrollOffsetY, window->width(), window->height()));
   1685     gFrameCacheMutex.lock();
   1686     delete m_frameCacheKit;
   1687     delete m_navPictureKit;
   1688     m_frameCacheKit = m_temp;
   1689     m_navPictureKit = m_tempPict;
   1690     m_updatedFrameCache = true;
   1691 #if DEBUG_NAV_UI
   1692     const CachedNode* cachedFocusNode = m_frameCacheKit->currentFocus();
   1693     DBG_NAV_LOGD("cachedFocusNode=%d (nodePointer=%p)",
   1694         cachedFocusNode ? cachedFocusNode->index() : 0,
   1695         cachedFocusNode ? cachedFocusNode->nodePointer() : 0);
   1696 #endif
   1697     gFrameCacheMutex.unlock();
   1698 }
   1699 
   1700 void WebViewCore::updateFrameCacheIfLoading()
   1701 {
   1702     if (!m_check_domtree_version)
   1703         updateFrameCache();
   1704 }
   1705 
   1706 struct TouchNodeData {
   1707     Node* mNode;
   1708     IntRect mBounds;
   1709 };
   1710 
   1711 // get the bounding box of the Node
   1712 static IntRect getAbsoluteBoundingBox(Node* node) {
   1713     IntRect rect;
   1714     RenderObject* render = node->renderer();
   1715     if (render->isRenderInline())
   1716         rect = toRenderInline(render)->linesVisualOverflowBoundingBox();
   1717     else if (render->isBox())
   1718         rect = toRenderBox(render)->visualOverflowRect();
   1719     else if (render->isText())
   1720         rect = toRenderText(render)->linesBoundingBox();
   1721     else
   1722         LOGE("getAbsoluteBoundingBox failed for node %p, name %s", node, render->renderName());
   1723     FloatPoint absPos = render->localToAbsolute();
   1724     rect.move(absPos.x(), absPos.y());
   1725     return rect;
   1726 }
   1727 
   1728 // get the highlight rectangles for the touch point (x, y) with the slop
   1729 Vector<IntRect> WebViewCore::getTouchHighlightRects(int x, int y, int slop)
   1730 {
   1731     Vector<IntRect> rects;
   1732     m_mousePos = IntPoint(x - m_scrollOffsetX, y - m_scrollOffsetY);
   1733     HitTestResult hitTestResult = m_mainFrame->eventHandler()->hitTestResultAtPoint(IntPoint(x, y),
   1734             false, false, DontHitTestScrollbars, HitTestRequest::Active | HitTestRequest::ReadOnly, IntSize(slop, slop));
   1735     if (!hitTestResult.innerNode() || !hitTestResult.innerNode()->inDocument()) {
   1736         LOGE("Should not happen: no in document Node found");
   1737         return rects;
   1738     }
   1739     const ListHashSet<RefPtr<Node> >& list = hitTestResult.rectBasedTestResult();
   1740     if (list.isEmpty()) {
   1741         LOGE("Should not happen: no rect-based-test nodes found");
   1742         return rects;
   1743     }
   1744     Frame* frame = hitTestResult.innerNode()->document()->frame();
   1745     Vector<TouchNodeData> nodeDataList;
   1746     ListHashSet<RefPtr<Node> >::const_iterator last = list.end();
   1747     for (ListHashSet<RefPtr<Node> >::const_iterator it = list.begin(); it != last; ++it) {
   1748         // TODO: it seems reasonable to not search across the frame. Isn't it?
   1749         // if the node is not in the same frame as the innerNode, skip it
   1750         if (it->get()->document()->frame() != frame)
   1751             continue;
   1752         // traverse up the tree to find the first node that needs highlight
   1753         bool found = false;
   1754         Node* eventNode = it->get();
   1755         while (eventNode) {
   1756             RenderObject* render = eventNode->renderer();
   1757             if (render && (render->isBody() || render->isRenderView()))
   1758                 break;
   1759             if (eventNode->supportsFocus()
   1760                     || eventNode->hasEventListeners(eventNames().clickEvent)
   1761                     || eventNode->hasEventListeners(eventNames().mousedownEvent)
   1762                     || eventNode->hasEventListeners(eventNames().mouseupEvent)) {
   1763                 found = true;
   1764                 break;
   1765             }
   1766             // the nodes in the rectBasedTestResult() are ordered based on z-index during hit testing.
   1767             // so do not search for the eventNode across explicit z-index border.
   1768             // TODO: this is a hard one to call. z-index is quite complicated as its value only
   1769             // matters when you compare two RenderLayer in the same hierarchy level. e.g. in
   1770             // the following example, "b" is on the top as its z level is the highest. even "c"
   1771             // has 100 as z-index, it is still below "d" as its parent has the same z-index as
   1772             // "d" and logically before "d". Of course "a" is the lowest in the z level.
   1773             //
   1774             // z-index:auto "a"
   1775             //   z-index:2 "b"
   1776             //   z-index:1
   1777             //     z-index:100 "c"
   1778             //   z-index:1 "d"
   1779             //
   1780             // If the fat point touches everyone, the order in the list should be "b", "d", "c"
   1781             // and "a". When we search for the event node for "b", we really don't want "a" as
   1782             // in the z-order it is behind everything else.
   1783             if (render && !render->style()->hasAutoZIndex())
   1784                 break;
   1785             eventNode = eventNode->parentNode();
   1786         }
   1787         // didn't find any eventNode, skip it
   1788         if (!found)
   1789             continue;
   1790         // first quick check whether it is a duplicated node before computing bounding box
   1791         Vector<TouchNodeData>::const_iterator nlast = nodeDataList.end();
   1792         for (Vector<TouchNodeData>::const_iterator n = nodeDataList.begin(); n != nlast; ++n) {
   1793             // found the same node, skip it
   1794             if (eventNode == n->mNode) {
   1795                 found = false;
   1796                 break;
   1797             }
   1798         }
   1799         if (!found)
   1800             continue;
   1801         // next check whether the node is fully covered by or fully covering another node.
   1802         found = false;
   1803         IntRect rect = getAbsoluteBoundingBox(eventNode);
   1804         if (rect.isEmpty()) {
   1805             // if the node's bounds is empty and it is not a ContainerNode, skip it.
   1806             if (!eventNode->isContainerNode())
   1807                 continue;
   1808             // if the node's children are all positioned objects, its bounds can be empty.
   1809             // Walk through the children to find the bounding box.
   1810             Node* child = static_cast<const ContainerNode*>(eventNode)->firstChild();
   1811             while (child) {
   1812                 IntRect childrect;
   1813                 if (child->renderer())
   1814                     childrect = getAbsoluteBoundingBox(child);
   1815                 if (!childrect.isEmpty()) {
   1816                     rect.unite(childrect);
   1817                     child = child->traverseNextSibling(eventNode);
   1818                 } else
   1819                     child = child->traverseNextNode(eventNode);
   1820             }
   1821         }
   1822         for (int i = nodeDataList.size() - 1; i >= 0; i--) {
   1823             TouchNodeData n = nodeDataList.at(i);
   1824             // the new node is enclosing an existing node, skip it
   1825             if (rect.contains(n.mBounds)) {
   1826                 found = true;
   1827                 break;
   1828             }
   1829             // the new node is fully inside an existing node, remove the existing node
   1830             if (n.mBounds.contains(rect))
   1831                 nodeDataList.remove(i);
   1832         }
   1833         if (!found) {
   1834             TouchNodeData newNode;
   1835             newNode.mNode = eventNode;
   1836             newNode.mBounds = rect;
   1837             nodeDataList.append(newNode);
   1838         }
   1839     }
   1840     if (!nodeDataList.size())
   1841         return rects;
   1842     // finally select the node with the largest overlap with the fat point
   1843     TouchNodeData final;
   1844     final.mNode = 0;
   1845     IntPoint docPos = frame->view()->windowToContents(m_mousePos);
   1846     IntRect testRect(docPos.x() - slop, docPos.y() - slop, 2 * slop + 1, 2 * slop + 1);
   1847     int area = 0;
   1848     Vector<TouchNodeData>::const_iterator nlast = nodeDataList.end();
   1849     for (Vector<TouchNodeData>::const_iterator n = nodeDataList.begin(); n != nlast; ++n) {
   1850         IntRect rect = n->mBounds;
   1851         rect.intersect(testRect);
   1852         int a = rect.width() * rect.height();
   1853         if (a > area) {
   1854             final = *n;
   1855             area = a;
   1856         }
   1857     }
   1858     // now get the node's highlight rectangles in the page coordinate system
   1859     if (final.mNode) {
   1860         IntPoint frameAdjust;
   1861         if (frame != m_mainFrame) {
   1862             frameAdjust = frame->view()->contentsToWindow(IntPoint());
   1863             frameAdjust.move(m_scrollOffsetX, m_scrollOffsetY);
   1864         }
   1865         if (final.mNode->isLink()) {
   1866             // most of the links are inline instead of box style. So the bounding box is not
   1867             // a good representation for the highlights. Get the list of rectangles instead.
   1868             RenderObject* render = final.mNode->renderer();
   1869             IntPoint offset = roundedIntPoint(render->localToAbsolute());
   1870             render->absoluteRects(rects, offset.x() + frameAdjust.x(), offset.y() + frameAdjust.y());
   1871             bool inside = false;
   1872             int distance = INT_MAX;
   1873             int newx = x, newy = y;
   1874             int i = rects.size();
   1875             while (i--) {
   1876                 if (rects[i].isEmpty()) {
   1877                     rects.remove(i);
   1878                     continue;
   1879                 }
   1880                 // check whether the point (x, y) is inside one of the rectangles.
   1881                 if (inside)
   1882                     continue;
   1883                 if (rects[i].contains(x, y)) {
   1884                     inside = true;
   1885                     continue;
   1886                 }
   1887                 if (x >= rects[i].x() && x < rects[i].maxX()) {
   1888                     if (y < rects[i].y()) {
   1889                         if (rects[i].y() - y < distance) {
   1890                             newx = x;
   1891                             newy = rects[i].y();
   1892                             distance = rects[i].y() - y;
   1893                         }
   1894                     } else if (y >= rects[i].maxY()) {
   1895                         if (y - rects[i].maxY() + 1 < distance) {
   1896                             newx = x;
   1897                             newy = rects[i].maxY() - 1;
   1898                             distance = y - rects[i].maxY() + 1;
   1899                         }
   1900                     }
   1901                 } else if (y >= rects[i].y() && y < rects[i].maxY()) {
   1902                     if (x < rects[i].x()) {
   1903                         if (rects[i].x() - x < distance) {
   1904                             newx = rects[i].x();
   1905                             newy = y;
   1906                             distance = rects[i].x() - x;
   1907                         }
   1908                     } else if (x >= rects[i].maxX()) {
   1909                         if (x - rects[i].maxX() + 1 < distance) {
   1910                             newx = rects[i].maxX() - 1;
   1911                             newy = y;
   1912                             distance = x - rects[i].maxX() + 1;
   1913                         }
   1914                     }
   1915                 }
   1916             }
   1917             if (!rects.isEmpty()) {
   1918                 if (!inside) {
   1919                     // if neither x nor y has overlap, just pick the top/left of the first rectangle
   1920                     if (newx == x && newy == y) {
   1921                         newx = rects[0].x();
   1922                         newy = rects[0].y();
   1923                     }
   1924                     m_mousePos.setX(newx - m_scrollOffsetX);
   1925                     m_mousePos.setY(newy - m_scrollOffsetY);
   1926                     DBG_NAV_LOGD("Move x/y from (%d, %d) to (%d, %d) scrollOffset is (%d, %d)",
   1927                             x, y, m_mousePos.x() + m_scrollOffsetX, m_mousePos.y() + m_scrollOffsetY,
   1928                             m_scrollOffsetX, m_scrollOffsetY);
   1929                 }
   1930                 return rects;
   1931             }
   1932         }
   1933         IntRect rect = final.mBounds;
   1934         rect.move(frameAdjust.x(), frameAdjust.y());
   1935         rects.append(rect);
   1936         // adjust m_mousePos if it is not inside the returned highlight rectangle
   1937         testRect.move(frameAdjust.x(), frameAdjust.y());
   1938         testRect.intersect(rect);
   1939         if (!testRect.contains(x, y)) {
   1940             m_mousePos = testRect.center();
   1941             m_mousePos.move(-m_scrollOffsetX, -m_scrollOffsetY);
   1942             DBG_NAV_LOGD("Move x/y from (%d, %d) to (%d, %d) scrollOffset is (%d, %d)",
   1943                     x, y, m_mousePos.x() + m_scrollOffsetX, m_mousePos.y() + m_scrollOffsetY,
   1944                     m_scrollOffsetX, m_scrollOffsetY);
   1945         }
   1946     }
   1947     return rects;
   1948 }
   1949 
   1950 ///////////////////////////////////////////////////////////////////////////////
   1951 
   1952 void WebViewCore::addPlugin(PluginWidgetAndroid* w)
   1953 {
   1954 //    SkDebugf("----------- addPlugin %p", w);
   1955     /* The plugin must be appended to the end of the array. This ensures that if
   1956        the plugin is added while iterating through the array (e.g. sendEvent(...))
   1957        that the iteration process is not corrupted.
   1958      */
   1959     *m_plugins.append() = w;
   1960 }
   1961 
   1962 void WebViewCore::removePlugin(PluginWidgetAndroid* w)
   1963 {
   1964 //    SkDebugf("----------- removePlugin %p", w);
   1965     int index = m_plugins.find(w);
   1966     if (index < 0) {
   1967         SkDebugf("--------------- pluginwindow not found! %p\n", w);
   1968     } else {
   1969         m_plugins.removeShuffle(index);
   1970     }
   1971 }
   1972 
   1973 bool WebViewCore::isPlugin(PluginWidgetAndroid* w) const
   1974 {
   1975     return m_plugins.find(w) >= 0;
   1976 }
   1977 
   1978 void WebViewCore::invalPlugin(PluginWidgetAndroid* w)
   1979 {
   1980     const double PLUGIN_INVAL_DELAY = 1.0 / 60;
   1981 
   1982     if (!m_pluginInvalTimer.isActive()) {
   1983         m_pluginInvalTimer.startOneShot(PLUGIN_INVAL_DELAY);
   1984     }
   1985 }
   1986 
   1987 void WebViewCore::drawPlugins()
   1988 {
   1989     SkRegion inval; // accumualte what needs to be redrawn
   1990     PluginWidgetAndroid** iter = m_plugins.begin();
   1991     PluginWidgetAndroid** stop = m_plugins.end();
   1992 
   1993     for (; iter < stop; ++iter) {
   1994         PluginWidgetAndroid* w = *iter;
   1995         SkIRect dirty;
   1996         if (w->isDirty(&dirty)) {
   1997             w->draw();
   1998             inval.op(dirty, SkRegion::kUnion_Op);
   1999         }
   2000     }
   2001 
   2002     if (!inval.isEmpty()) {
   2003         // inval.getBounds() is our rectangle
   2004         const SkIRect& bounds = inval.getBounds();
   2005         WebCore::IntRect r(bounds.fLeft, bounds.fTop,
   2006                            bounds.width(), bounds.height());
   2007         this->viewInvalidate(r);
   2008     }
   2009 }
   2010 
   2011 void WebViewCore::notifyPluginsOnFrameLoad(const Frame* frame) {
   2012     // if frame is the parent then notify all plugins
   2013     if (!frame->tree()->parent()) {
   2014         // trigger an event notifying the plugins that the page has loaded
   2015         ANPEvent event;
   2016         SkANP::InitEvent(&event, kLifecycle_ANPEventType);
   2017         event.data.lifecycle.action = kOnLoad_ANPLifecycleAction;
   2018         sendPluginEvent(event);
   2019         // trigger the on/off screen notification if the page was reloaded
   2020         sendPluginVisibleScreen();
   2021     }
   2022     // else if frame's parent has completed
   2023     else if (!frame->tree()->parent()->loader()->isLoading()) {
   2024         // send to all plugins who have this frame in their heirarchy
   2025         PluginWidgetAndroid** iter = m_plugins.begin();
   2026         PluginWidgetAndroid** stop = m_plugins.end();
   2027         for (; iter < stop; ++iter) {
   2028             Frame* currentFrame = (*iter)->pluginView()->parentFrame();
   2029             while (currentFrame) {
   2030                 if (frame == currentFrame) {
   2031                     ANPEvent event;
   2032                     SkANP::InitEvent(&event, kLifecycle_ANPEventType);
   2033                     event.data.lifecycle.action = kOnLoad_ANPLifecycleAction;
   2034                     (*iter)->sendEvent(event);
   2035 
   2036                     // trigger the on/off screen notification if the page was reloaded
   2037                     ANPRectI visibleRect;
   2038                     getVisibleScreen(visibleRect);
   2039                     (*iter)->setVisibleScreen(visibleRect, m_scale);
   2040 
   2041                     break;
   2042                 }
   2043                 currentFrame = currentFrame->tree()->parent();
   2044             }
   2045         }
   2046     }
   2047 }
   2048 
   2049 void WebViewCore::getVisibleScreen(ANPRectI& visibleRect)
   2050 {
   2051     visibleRect.left = m_scrollOffsetX;
   2052     visibleRect.top = m_scrollOffsetY;
   2053     visibleRect.right = m_scrollOffsetX + m_screenWidth;
   2054     visibleRect.bottom = m_scrollOffsetY + m_screenHeight;
   2055 }
   2056 
   2057 void WebViewCore::sendPluginVisibleScreen()
   2058 {
   2059     /* We may want to cache the previous values and only send the notification
   2060        to the plugin in the event that one of the values has changed.
   2061      */
   2062 
   2063     ANPRectI visibleRect;
   2064     getVisibleScreen(visibleRect);
   2065 
   2066     PluginWidgetAndroid** iter = m_plugins.begin();
   2067     PluginWidgetAndroid** stop = m_plugins.end();
   2068     for (; iter < stop; ++iter) {
   2069         (*iter)->setVisibleScreen(visibleRect, m_scale);
   2070     }
   2071 }
   2072 
   2073 void WebViewCore::sendPluginSurfaceReady()
   2074 {
   2075     PluginWidgetAndroid** iter = m_plugins.begin();
   2076     PluginWidgetAndroid** stop = m_plugins.end();
   2077     for (; iter < stop; ++iter) {
   2078         (*iter)->checkSurfaceReady();
   2079     }
   2080 }
   2081 
   2082 void WebViewCore::sendPluginEvent(const ANPEvent& evt)
   2083 {
   2084     /* The list of plugins may be manipulated as we iterate through the list.
   2085        This implementation allows for the addition of new plugins during an
   2086        iteration, but may fail if a plugin is removed. Currently, there are not
   2087        any use cases where a plugin is deleted while processing this loop, but
   2088        if it does occur we will have to use an alternate data structure and/or
   2089        iteration mechanism.
   2090      */
   2091     for (int x = 0; x < m_plugins.count(); x++) {
   2092         m_plugins[x]->sendEvent(evt);
   2093     }
   2094 }
   2095 
   2096 PluginWidgetAndroid* WebViewCore::getPluginWidget(NPP npp)
   2097 {
   2098     PluginWidgetAndroid** iter = m_plugins.begin();
   2099     PluginWidgetAndroid** stop = m_plugins.end();
   2100     for (; iter < stop; ++iter) {
   2101         if ((*iter)->pluginView()->instance() == npp) {
   2102             return (*iter);
   2103         }
   2104     }
   2105     return 0;
   2106 }
   2107 
   2108 static PluginView* nodeIsPlugin(Node* node) {
   2109     RenderObject* renderer = node->renderer();
   2110     if (renderer && renderer->isWidget()) {
   2111         Widget* widget = static_cast<RenderWidget*>(renderer)->widget();
   2112         if (widget && widget->isPluginView())
   2113             return static_cast<PluginView*>(widget);
   2114     }
   2115     return 0;
   2116 }
   2117 
   2118 Node* WebViewCore::cursorNodeIsPlugin() {
   2119     gCursorBoundsMutex.lock();
   2120     bool hasCursorBounds = m_hasCursorBounds;
   2121     Frame* frame = (Frame*) m_cursorFrame;
   2122     Node* node = (Node*) m_cursorNode;
   2123     gCursorBoundsMutex.unlock();
   2124     if (hasCursorBounds && CacheBuilder::validNode(m_mainFrame, frame, node)
   2125             && nodeIsPlugin(node)) {
   2126         return node;
   2127     }
   2128     return 0;
   2129 }
   2130 
   2131 ///////////////////////////////////////////////////////////////////////////////
   2132 void WebViewCore::moveMouseIfLatest(int moveGeneration,
   2133     WebCore::Frame* frame, int x, int y)
   2134 {
   2135     DBG_NAV_LOGD("m_moveGeneration=%d moveGeneration=%d"
   2136         " frame=%p x=%d y=%d",
   2137         m_moveGeneration, moveGeneration, frame, x, y);
   2138     if (m_moveGeneration > moveGeneration) {
   2139         DBG_NAV_LOGD("m_moveGeneration=%d > moveGeneration=%d",
   2140             m_moveGeneration, moveGeneration);
   2141         return; // short-circuit if a newer move has already been generated
   2142     }
   2143     m_lastGeneration = moveGeneration;
   2144     moveMouse(frame, x, y);
   2145 }
   2146 
   2147 void WebViewCore::moveFocus(WebCore::Frame* frame, WebCore::Node* node)
   2148 {
   2149     DBG_NAV_LOGD("frame=%p node=%p", frame, node);
   2150     if (!node || !CacheBuilder::validNode(m_mainFrame, frame, node)
   2151             || !node->isElementNode())
   2152         return;
   2153     // Code borrowed from FocusController::advanceFocus
   2154     WebCore::FocusController* focusController
   2155             = m_mainFrame->page()->focusController();
   2156     WebCore::Document* oldDoc
   2157             = focusController->focusedOrMainFrame()->document();
   2158     if (oldDoc->focusedNode() == node)
   2159         return;
   2160     if (node->document() != oldDoc)
   2161         oldDoc->setFocusedNode(0);
   2162     focusController->setFocusedFrame(frame);
   2163     static_cast<WebCore::Element*>(node)->focus(false);
   2164 }
   2165 
   2166 // Update mouse position
   2167 void WebViewCore::moveMouse(WebCore::Frame* frame, int x, int y)
   2168 {
   2169     DBG_NAV_LOGD("frame=%p x=%d y=%d scrollOffset=(%d,%d)", frame,
   2170         x, y, m_scrollOffsetX, m_scrollOffsetY);
   2171     if (!frame || !CacheBuilder::validNode(m_mainFrame, frame, 0))
   2172         frame = m_mainFrame;
   2173     // mouse event expects the position in the window coordinate
   2174     m_mousePos = WebCore::IntPoint(x - m_scrollOffsetX, y - m_scrollOffsetY);
   2175     // validNode will still return true if the node is null, as long as we have
   2176     // a valid frame.  Do not want to make a call on frame unless it is valid.
   2177     WebCore::PlatformMouseEvent mouseEvent(m_mousePos, m_mousePos,
   2178         WebCore::NoButton, WebCore::MouseEventMoved, 1, false, false, false,
   2179         false, WTF::currentTime());
   2180     frame->eventHandler()->handleMouseMoveEvent(mouseEvent);
   2181     updateCacheOnNodeChange();
   2182 }
   2183 
   2184 void WebViewCore::setSelection(int start, int end)
   2185 {
   2186     WebCore::Node* focus = currentFocus();
   2187     if (!focus)
   2188         return;
   2189     WebCore::RenderObject* renderer = focus->renderer();
   2190     if (!renderer || (!renderer->isTextField() && !renderer->isTextArea()))
   2191         return;
   2192     if (start > end) {
   2193         int temp = start;
   2194         start = end;
   2195         end = temp;
   2196     }
   2197     // Tell our EditorClient that this change was generated from the UI, so it
   2198     // does not need to echo it to the UI.
   2199     EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
   2200             m_mainFrame->editor()->client());
   2201     client->setUiGeneratedSelectionChange(true);
   2202     setSelectionRange(focus, start, end);
   2203     if (start != end) {
   2204         // Fire a select event. No event is sent when the selection reduces to
   2205         // an insertion point
   2206         RenderTextControl* control = toRenderTextControl(renderer);
   2207         control->selectionChanged(true);
   2208     }
   2209     client->setUiGeneratedSelectionChange(false);
   2210     WebCore::Frame* focusedFrame = focus->document()->frame();
   2211     bool isPasswordField = false;
   2212     if (focus->isElementNode()) {
   2213         WebCore::Element* element = static_cast<WebCore::Element*>(focus);
   2214         if (WebCore::InputElement* inputElement = element->toInputElement())
   2215             isPasswordField = static_cast<WebCore::HTMLInputElement*>(inputElement)->isPasswordField();
   2216     }
   2217     // For password fields, this is done in the UI side via
   2218     // bringPointIntoView, since the UI does the drawing.
   2219     if (renderer->isTextArea() || !isPasswordField)
   2220         revealSelection();
   2221 }
   2222 
   2223 String WebViewCore::modifySelection(const int direction, const int axis)
   2224 {
   2225     DOMSelection* selection = m_mainFrame->domWindow()->getSelection();
   2226     ASSERT(selection);
   2227     // We've seen crashes where selection is null, but we don't know why
   2228     // See http://b/5244036
   2229     if (!selection)
   2230         return String();
   2231     if (selection->rangeCount() > 1)
   2232         selection->removeAllRanges();
   2233     switch (axis) {
   2234         case AXIS_CHARACTER:
   2235         case AXIS_WORD:
   2236         case AXIS_SENTENCE:
   2237             return modifySelectionTextNavigationAxis(selection, direction, axis);
   2238         case AXIS_HEADING:
   2239         case AXIS_SIBLING:
   2240         case AXIS_PARENT_FIRST_CHILD:
   2241         case AXIS_DOCUMENT:
   2242             return modifySelectionDomNavigationAxis(selection, direction, axis);
   2243         default:
   2244             LOGE("Invalid navigation axis: %d", axis);
   2245             return String();
   2246     }
   2247 }
   2248 
   2249 void WebViewCore::scrollNodeIntoView(Frame* frame, Node* node)
   2250 {
   2251     if (!frame || !node)
   2252         return;
   2253 
   2254     Element* elementNode = 0;
   2255 
   2256     // If not an Element, find a visible predecessor
   2257     // Element to scroll into view.
   2258     if (!node->isElementNode()) {
   2259         HTMLElement* body = frame->document()->body();
   2260         do {
   2261             if (node == body)
   2262                 return;
   2263             node = node->parentNode();
   2264         } while (node && !node->isElementNode() && !isVisible(node));
   2265     }
   2266 
   2267     // Couldn't find a visible predecessor.
   2268     if (!node)
   2269         return;
   2270 
   2271     elementNode = static_cast<Element*>(node);
   2272     elementNode->scrollIntoViewIfNeeded(true);
   2273 }
   2274 
   2275 String WebViewCore::modifySelectionTextNavigationAxis(DOMSelection* selection, int direction, int axis)
   2276 {
   2277     Node* body = m_mainFrame->document()->body();
   2278 
   2279     ExceptionCode ec = 0;
   2280     String markup;
   2281 
   2282     // initialize the selection if necessary
   2283     if (selection->rangeCount() == 0) {
   2284         if (m_currentNodeDomNavigationAxis
   2285                 && CacheBuilder::validNode(m_mainFrame,
   2286                 m_mainFrame, m_currentNodeDomNavigationAxis)) {
   2287             PassRefPtr<Range> rangeRef =
   2288                 selection->frame()->document()->createRange();
   2289             rangeRef->selectNode(m_currentNodeDomNavigationAxis, ec);
   2290             m_currentNodeDomNavigationAxis = 0;
   2291             if (ec)
   2292                 return String();
   2293             selection->addRange(rangeRef.get());
   2294         } else if (currentFocus()) {
   2295             selection->setPosition(currentFocus(), 0, ec);
   2296         } else if (m_cursorNode
   2297                 && CacheBuilder::validNode(m_mainFrame,
   2298                 m_mainFrame, m_cursorNode)) {
   2299             PassRefPtr<Range> rangeRef =
   2300                 selection->frame()->document()->createRange();
   2301             rangeRef->selectNode(reinterpret_cast<Node*>(m_cursorNode), ec);
   2302             if (ec)
   2303                 return String();
   2304             selection->addRange(rangeRef.get());
   2305         } else {
   2306             selection->setPosition(body, 0, ec);
   2307         }
   2308         if (ec)
   2309             return String();
   2310     }
   2311 
   2312     // collapse the selection
   2313     if (direction == DIRECTION_FORWARD)
   2314         selection->collapseToEnd(ec);
   2315     else
   2316         selection->collapseToStart(ec);
   2317     if (ec)
   2318         return String();
   2319 
   2320     // Make sure the anchor node is a text node since we are generating
   2321     // the markup of the selection which includes the anchor, the focus,
   2322     // and any crossed nodes. Forcing the condition that the selection
   2323     // starts and ends on text nodes guarantees symmetric selection markup.
   2324     // Also this way the text content, rather its container, is highlighted.
   2325     Node* anchorNode = selection->anchorNode();
   2326     if (anchorNode->isElementNode()) {
   2327         // Collapsed selection while moving forward points to the
   2328         // next unvisited node and while moving backward to the
   2329         // last visited node.
   2330         if (direction == DIRECTION_FORWARD)
   2331             advanceAnchorNode(selection, direction, markup, false, ec);
   2332         else
   2333             advanceAnchorNode(selection, direction, markup, true, ec);
   2334         if (ec)
   2335             return String();
   2336         if (!markup.isEmpty())
   2337             return markup;
   2338     }
   2339 
   2340     // If the selection is at the end of a non white space text move
   2341     // it to the next visible text node with non white space content.
   2342     // This is a workaround for the selection getting stuck.
   2343     anchorNode = selection->anchorNode();
   2344     if (anchorNode->isTextNode()) {
   2345         if (direction == DIRECTION_FORWARD) {
   2346             String suffix = anchorNode->textContent().substring(
   2347                     selection->anchorOffset(), caretMaxOffset(anchorNode));
   2348             // If at the end of non white space text we advance the
   2349             // anchor node to either an input element or non empty text.
   2350             if (suffix.stripWhiteSpace().isEmpty()) {
   2351                 advanceAnchorNode(selection, direction, markup, true, ec);
   2352             }
   2353         } else {
   2354             String prefix = anchorNode->textContent().substring(0,
   2355                     selection->anchorOffset());
   2356             // If at the end of non white space text we advance the
   2357             // anchor node to either an input element or non empty text.
   2358             if (prefix.stripWhiteSpace().isEmpty()) {
   2359                 advanceAnchorNode(selection, direction, markup, true, ec);
   2360             }
   2361         }
   2362         if (ec)
   2363             return String();
   2364         if (!markup.isEmpty())
   2365             return markup;
   2366     }
   2367 
   2368     // extend the selection
   2369     String directionStr;
   2370     if (direction == DIRECTION_FORWARD)
   2371         directionStr = "forward";
   2372     else
   2373         directionStr = "backward";
   2374 
   2375     String axisStr;
   2376     if (axis == AXIS_CHARACTER)
   2377         axisStr = "character";
   2378     else if (axis == AXIS_WORD)
   2379         axisStr = "word";
   2380     else
   2381         axisStr = "sentence";
   2382 
   2383     selection->modify("extend", directionStr, axisStr);
   2384 
   2385     // Make sure the focus node is a text node in order to have the
   2386     // selection generate symmetric markup because the latter
   2387     // includes all nodes crossed by the selection.  Also this way
   2388     // the text content, rather its container, is highlighted.
   2389     Node* focusNode = selection->focusNode();
   2390     if (focusNode->isElementNode()) {
   2391         focusNode = getImplicitBoundaryNode(selection->focusNode(),
   2392                 selection->focusOffset(), direction);
   2393         if (!focusNode)
   2394             return String();
   2395         if (direction == DIRECTION_FORWARD) {
   2396             focusNode = focusNode->traversePreviousSiblingPostOrder(body);
   2397             if (focusNode && !isContentTextNode(focusNode)) {
   2398                 Node* textNode = traverseNextContentTextNode(focusNode,
   2399                         anchorNode, DIRECTION_BACKWARD);
   2400                 if (textNode)
   2401                     anchorNode = textNode;
   2402             }
   2403             if (focusNode && isContentTextNode(focusNode)) {
   2404                 selection->extend(focusNode, caretMaxOffset(focusNode), ec);
   2405                 if (ec)
   2406                     return String();
   2407             }
   2408         } else {
   2409             focusNode = focusNode->traverseNextSibling();
   2410             if (focusNode && !isContentTextNode(focusNode)) {
   2411                 Node* textNode = traverseNextContentTextNode(focusNode,
   2412                         anchorNode, DIRECTION_FORWARD);
   2413                 if (textNode)
   2414                     anchorNode = textNode;
   2415             }
   2416             if (anchorNode && isContentTextNode(anchorNode)) {
   2417                 selection->extend(focusNode, 0, ec);
   2418                 if (ec)
   2419                     return String();
   2420             }
   2421         }
   2422     }
   2423 
   2424     // Enforce that the selection does not cross anchor boundaries. This is
   2425     // a workaround for the asymmetric behavior of WebKit while crossing
   2426     // anchors.
   2427     anchorNode = getImplicitBoundaryNode(selection->anchorNode(),
   2428             selection->anchorOffset(), direction);
   2429     focusNode = getImplicitBoundaryNode(selection->focusNode(),
   2430             selection->focusOffset(), direction);
   2431     if (anchorNode && focusNode && anchorNode != focusNode) {
   2432         Node* inputControl = getIntermediaryInputElement(anchorNode, focusNode,
   2433                 direction);
   2434         if (inputControl) {
   2435             if (direction == DIRECTION_FORWARD) {
   2436                 if (isDescendantOf(inputControl, anchorNode)) {
   2437                     focusNode = inputControl;
   2438                 } else {
   2439                     focusNode = inputControl->traversePreviousSiblingPostOrder(
   2440                             body);
   2441                     if (!focusNode)
   2442                         focusNode = inputControl;
   2443                 }
   2444                 // We prefer a text node contained in the input element.
   2445                 if (!isContentTextNode(focusNode)) {
   2446                     Node* textNode = traverseNextContentTextNode(focusNode,
   2447                         anchorNode, DIRECTION_BACKWARD);
   2448                     if (textNode)
   2449                         focusNode = textNode;
   2450                 }
   2451                 // If we found text in the input select it.
   2452                 // Otherwise, select the input element itself.
   2453                 if (isContentTextNode(focusNode)) {
   2454                     selection->extend(focusNode, caretMaxOffset(focusNode), ec);
   2455                 } else if (anchorNode != focusNode) {
   2456                     // Note that the focusNode always has parent and that
   2457                     // the offset can be one more that the index of the last
   2458                     // element - this is how WebKit selects such elements.
   2459                     selection->extend(focusNode->parentNode(),
   2460                             focusNode->nodeIndex() + 1, ec);
   2461                 }
   2462                 if (ec)
   2463                     return String();
   2464             } else {
   2465                 if (isDescendantOf(inputControl, anchorNode)) {
   2466                     focusNode = inputControl;
   2467                 } else {
   2468                     focusNode = inputControl->traverseNextSibling();
   2469                     if (!focusNode)
   2470                         focusNode = inputControl;
   2471                 }
   2472                 // We prefer a text node contained in the input element.
   2473                 if (!isContentTextNode(focusNode)) {
   2474                     Node* textNode = traverseNextContentTextNode(focusNode,
   2475                             anchorNode, DIRECTION_FORWARD);
   2476                     if (textNode)
   2477                         focusNode = textNode;
   2478                 }
   2479                 // If we found text in the input select it.
   2480                 // Otherwise, select the input element itself.
   2481                 if (isContentTextNode(focusNode)) {
   2482                     selection->extend(focusNode, caretMinOffset(focusNode), ec);
   2483                 } else if (anchorNode != focusNode) {
   2484                     // Note that the focusNode always has parent and that
   2485                     // the offset can be one more that the index of the last
   2486                     // element - this is how WebKit selects such elements.
   2487                     selection->extend(focusNode->parentNode(),
   2488                             focusNode->nodeIndex() + 1, ec);
   2489                 }
   2490                 if (ec)
   2491                    return String();
   2492             }
   2493         }
   2494     }
   2495 
   2496     // make sure the selection is visible
   2497     if (direction == DIRECTION_FORWARD)
   2498         scrollNodeIntoView(m_mainFrame, selection->focusNode());
   2499     else
   2500         scrollNodeIntoView(m_mainFrame, selection->anchorNode());
   2501 
   2502     // format markup for the visible content
   2503     PassRefPtr<Range> range = selection->getRangeAt(0, ec);
   2504     if (ec)
   2505         return String();
   2506     IntRect bounds = range->boundingBox();
   2507     selectAt(bounds.center().x(), bounds.center().y());
   2508     markup = formatMarkup(selection);
   2509     LOGV("Selection markup: %s", markup.utf8().data());
   2510 
   2511     return markup;
   2512 }
   2513 
   2514 Node* WebViewCore::getImplicitBoundaryNode(Node* node, unsigned offset, int direction)
   2515 {
   2516     if (node->offsetInCharacters())
   2517         return node;
   2518     if (!node->hasChildNodes())
   2519         return node;
   2520     if (offset < node->childNodeCount())
   2521         return node->childNode(offset);
   2522     else
   2523         if (direction == DIRECTION_FORWARD)
   2524             return node->traverseNextSibling();
   2525         else
   2526             return node->traversePreviousNodePostOrder(
   2527                     node->document()->body());
   2528 }
   2529 
   2530 Node* WebViewCore::getNextAnchorNode(Node* anchorNode, bool ignoreFirstNode, int direction)
   2531 {
   2532     Node* body = 0;
   2533     Node* currentNode = 0;
   2534     if (direction == DIRECTION_FORWARD) {
   2535         if (ignoreFirstNode)
   2536             currentNode = anchorNode->traverseNextNode(body);
   2537         else
   2538             currentNode = anchorNode;
   2539     } else {
   2540         body = anchorNode->document()->body();
   2541         if (ignoreFirstNode)
   2542             currentNode = anchorNode->traversePreviousSiblingPostOrder(body);
   2543         else
   2544             currentNode = anchorNode;
   2545     }
   2546     while (currentNode) {
   2547         if (isContentTextNode(currentNode)
   2548                 || isContentInputElement(currentNode))
   2549             return currentNode;
   2550         if (direction == DIRECTION_FORWARD)
   2551             currentNode = currentNode->traverseNextNode();
   2552         else
   2553             currentNode = currentNode->traversePreviousNodePostOrder(body);
   2554     }
   2555     return 0;
   2556 }
   2557 
   2558 void WebViewCore::advanceAnchorNode(DOMSelection* selection, int direction,
   2559         String& markup, bool ignoreFirstNode, ExceptionCode& ec)
   2560 {
   2561     Node* anchorNode = getImplicitBoundaryNode(selection->anchorNode(),
   2562             selection->anchorOffset(), direction);
   2563     if (!anchorNode) {
   2564         ec = NOT_FOUND_ERR;
   2565         return;
   2566     }
   2567     // If the anchor offset is invalid i.e. the anchor node has no
   2568     // child with that index getImplicitAnchorNode returns the next
   2569     // logical node in the current direction. In such a case our
   2570     // position in the DOM tree was has already been advanced,
   2571     // therefore we there is no need to do that again.
   2572     if (selection->anchorNode()->isElementNode()) {
   2573         unsigned anchorOffset = selection->anchorOffset();
   2574         unsigned childNodeCount = selection->anchorNode()->childNodeCount();
   2575         if (anchorOffset >= childNodeCount)
   2576             ignoreFirstNode = false;
   2577     }
   2578     // Find the next anchor node given our position in the DOM and
   2579     // whether we want the current node to be considered as well.
   2580     Node* nextAnchorNode = getNextAnchorNode(anchorNode, ignoreFirstNode,
   2581             direction);
   2582     if (!nextAnchorNode) {
   2583         ec = NOT_FOUND_ERR;
   2584         return;
   2585     }
   2586     if (nextAnchorNode->isElementNode()) {
   2587         // If this is an input element tell the WebView thread
   2588         // to set the cursor to that control.
   2589         if (isContentInputElement(nextAnchorNode)) {
   2590             IntRect bounds = nextAnchorNode->getRect();
   2591             selectAt(bounds.center().x(), bounds.center().y());
   2592         }
   2593         Node* textNode = 0;
   2594         // Treat the text content of links as any other text but
   2595         // for the rest input elements select the control itself.
   2596         if (nextAnchorNode->hasTagName(WebCore::HTMLNames::aTag))
   2597             textNode = traverseNextContentTextNode(nextAnchorNode,
   2598                     nextAnchorNode, direction);
   2599         // We prefer to select the text content of the link if such,
   2600         // otherwise just select the element itself.
   2601         if (textNode) {
   2602             nextAnchorNode = textNode;
   2603         } else {
   2604             if (direction == DIRECTION_FORWARD) {
   2605                 selection->setBaseAndExtent(nextAnchorNode,
   2606                         caretMinOffset(nextAnchorNode), nextAnchorNode,
   2607                         caretMaxOffset(nextAnchorNode), ec);
   2608             } else {
   2609                 selection->setBaseAndExtent(nextAnchorNode,
   2610                         caretMaxOffset(nextAnchorNode), nextAnchorNode,
   2611                         caretMinOffset(nextAnchorNode), ec);
   2612             }
   2613             if (!ec)
   2614                 markup = formatMarkup(selection);
   2615             // make sure the selection is visible
   2616             scrollNodeIntoView(selection->frame(), nextAnchorNode);
   2617             return;
   2618         }
   2619     }
   2620     if (direction == DIRECTION_FORWARD)
   2621         selection->setPosition(nextAnchorNode,
   2622                 caretMinOffset(nextAnchorNode), ec);
   2623     else
   2624         selection->setPosition(nextAnchorNode,
   2625                 caretMaxOffset(nextAnchorNode), ec);
   2626 }
   2627 
   2628 bool WebViewCore::isContentInputElement(Node* node)
   2629 {
   2630   return (isVisible(node)
   2631           && (node->hasTagName(WebCore::HTMLNames::selectTag)
   2632           || node->hasTagName(WebCore::HTMLNames::aTag)
   2633           || node->hasTagName(WebCore::HTMLNames::inputTag)
   2634           || node->hasTagName(WebCore::HTMLNames::buttonTag)));
   2635 }
   2636 
   2637 bool WebViewCore::isContentTextNode(Node* node)
   2638 {
   2639    if (!node || !node->isTextNode())
   2640        return false;
   2641    Text* textNode = static_cast<Text*>(node);
   2642    return (isVisible(textNode) && textNode->length() > 0
   2643        && !textNode->containsOnlyWhitespace());
   2644 }
   2645 
   2646 Text* WebViewCore::traverseNextContentTextNode(Node* fromNode, Node* toNode, int direction)
   2647 {
   2648     Node* currentNode = fromNode;
   2649     do {
   2650         if (direction == DIRECTION_FORWARD)
   2651             currentNode = currentNode->traverseNextNode(toNode);
   2652         else
   2653             currentNode = currentNode->traversePreviousNodePostOrder(toNode);
   2654     } while (currentNode && !isContentTextNode(currentNode));
   2655     return static_cast<Text*>(currentNode);
   2656 }
   2657 
   2658 Node* WebViewCore::getIntermediaryInputElement(Node* fromNode, Node* toNode, int direction)
   2659 {
   2660     if (fromNode == toNode)
   2661         return 0;
   2662     if (direction == DIRECTION_FORWARD) {
   2663         Node* currentNode = fromNode;
   2664         while (currentNode && currentNode != toNode) {
   2665             if (isContentInputElement(currentNode))
   2666                 return currentNode;
   2667             currentNode = currentNode->traverseNextNodePostOrder();
   2668         }
   2669         currentNode = fromNode;
   2670         while (currentNode && currentNode != toNode) {
   2671             if (isContentInputElement(currentNode))
   2672                 return currentNode;
   2673             currentNode = currentNode->traverseNextNode();
   2674         }
   2675     } else {
   2676         Node* currentNode = fromNode->traversePreviousNode();
   2677         while (currentNode && currentNode != toNode) {
   2678             if (isContentInputElement(currentNode))
   2679                 return currentNode;
   2680             currentNode = currentNode->traversePreviousNode();
   2681         }
   2682         currentNode = fromNode->traversePreviousNodePostOrder();
   2683         while (currentNode && currentNode != toNode) {
   2684             if (isContentInputElement(currentNode))
   2685                 return currentNode;
   2686             currentNode = currentNode->traversePreviousNodePostOrder();
   2687         }
   2688     }
   2689     return 0;
   2690 }
   2691 
   2692 bool WebViewCore::isDescendantOf(Node* parent, Node* node)
   2693 {
   2694     Node* currentNode = node;
   2695     while (currentNode) {
   2696         if (currentNode == parent) {
   2697             return true;
   2698         }
   2699         currentNode = currentNode->parentNode();
   2700     }
   2701     return false;
   2702 }
   2703 
   2704 String WebViewCore::modifySelectionDomNavigationAxis(DOMSelection* selection, int direction, int axis)
   2705 {
   2706     HTMLElement* body = m_mainFrame->document()->body();
   2707     if (!m_currentNodeDomNavigationAxis && selection->focusNode()) {
   2708         m_currentNodeDomNavigationAxis = selection->focusNode();
   2709         selection->empty();
   2710         if (m_currentNodeDomNavigationAxis->isTextNode())
   2711             m_currentNodeDomNavigationAxis =
   2712                 m_currentNodeDomNavigationAxis->parentNode();
   2713     }
   2714     if (!m_currentNodeDomNavigationAxis)
   2715         m_currentNodeDomNavigationAxis = currentFocus();
   2716     if (!m_currentNodeDomNavigationAxis
   2717             || !CacheBuilder::validNode(m_mainFrame, m_mainFrame,
   2718                                         m_currentNodeDomNavigationAxis))
   2719         m_currentNodeDomNavigationAxis = body;
   2720     Node* currentNode = m_currentNodeDomNavigationAxis;
   2721     if (axis == AXIS_HEADING) {
   2722         if (currentNode == body && direction == DIRECTION_BACKWARD)
   2723             currentNode = currentNode->lastDescendant();
   2724         do {
   2725             if (direction == DIRECTION_FORWARD)
   2726                 currentNode = currentNode->traverseNextNode(body);
   2727             else
   2728                 currentNode = currentNode->traversePreviousNode(body);
   2729         } while (currentNode && (currentNode->isTextNode()
   2730             || !isVisible(currentNode) || !isHeading(currentNode)));
   2731     } else if (axis == AXIS_PARENT_FIRST_CHILD) {
   2732         if (direction == DIRECTION_FORWARD) {
   2733             currentNode = currentNode->firstChild();
   2734             while (currentNode && (currentNode->isTextNode()
   2735                     || !isVisible(currentNode)))
   2736                 currentNode = currentNode->nextSibling();
   2737         } else {
   2738             do {
   2739                 if (currentNode == body)
   2740                     return String();
   2741                 currentNode = currentNode->parentNode();
   2742             } while (currentNode && (currentNode->isTextNode()
   2743                     || !isVisible(currentNode)));
   2744         }
   2745     } else if (axis == AXIS_SIBLING) {
   2746         do {
   2747             if (direction == DIRECTION_FORWARD)
   2748                 currentNode = currentNode->nextSibling();
   2749             else {
   2750                 if (currentNode == body)
   2751                     return String();
   2752                 currentNode = currentNode->previousSibling();
   2753             }
   2754         } while (currentNode && (currentNode->isTextNode()
   2755                 || !isVisible(currentNode)));
   2756     } else if (axis == AXIS_DOCUMENT) {
   2757         currentNode = body;
   2758         if (direction == DIRECTION_FORWARD)
   2759             currentNode = currentNode->lastDescendant();
   2760     } else {
   2761         LOGE("Invalid axis: %d", axis);
   2762         return String();
   2763     }
   2764     if (currentNode) {
   2765         m_currentNodeDomNavigationAxis = currentNode;
   2766         scrollNodeIntoView(m_mainFrame, currentNode);
   2767         String selectionString = createMarkup(currentNode);
   2768         LOGV("Selection markup: %s", selectionString.utf8().data());
   2769         return selectionString;
   2770     }
   2771     return String();
   2772 }
   2773 
   2774 bool WebViewCore::isHeading(Node* node)
   2775 {
   2776     if (node->hasTagName(WebCore::HTMLNames::h1Tag)
   2777             || node->hasTagName(WebCore::HTMLNames::h2Tag)
   2778             || node->hasTagName(WebCore::HTMLNames::h3Tag)
   2779             || node->hasTagName(WebCore::HTMLNames::h4Tag)
   2780             || node->hasTagName(WebCore::HTMLNames::h5Tag)
   2781             || node->hasTagName(WebCore::HTMLNames::h6Tag)) {
   2782         return true;
   2783     }
   2784 
   2785     if (node->isElementNode()) {
   2786         Element* element = static_cast<Element*>(node);
   2787         String roleAttribute =
   2788             element->getAttribute(WebCore::HTMLNames::roleAttr).string();
   2789         if (equalIgnoringCase(roleAttribute, "heading"))
   2790             return true;
   2791     }
   2792 
   2793     return false;
   2794 }
   2795 
   2796 bool WebViewCore::isVisible(Node* node)
   2797 {
   2798     // start off an element
   2799     Element* element = 0;
   2800     if (node->isElementNode())
   2801         element = static_cast<Element*>(node);
   2802     else
   2803         element = node->parentElement();
   2804     // check renderer
   2805     if (!element->renderer()) {
   2806         return false;
   2807     }
   2808     // check size
   2809     if (element->offsetHeight() == 0 || element->offsetWidth() == 0) {
   2810         return false;
   2811     }
   2812     // check style
   2813     Node* body = m_mainFrame->document()->body();
   2814     Node* currentNode = element;
   2815     while (currentNode && currentNode != body) {
   2816         RenderStyle* style = currentNode->computedStyle();
   2817         if (style &&
   2818                 (style->display() == NONE || style->visibility() == HIDDEN)) {
   2819             return false;
   2820         }
   2821         currentNode = currentNode->parentNode();
   2822     }
   2823     return true;
   2824 }
   2825 
   2826 String WebViewCore::formatMarkup(DOMSelection* selection)
   2827 {
   2828     ExceptionCode ec = 0;
   2829     String markup = String();
   2830     PassRefPtr<Range> wholeRange = selection->getRangeAt(0, ec);
   2831     if (ec)
   2832         return String();
   2833     if (!wholeRange->startContainer() || !wholeRange->startContainer())
   2834         return String();
   2835     // Since formatted markup contains invisible nodes it
   2836     // is created from the concatenation of the visible fragments.
   2837     Node* firstNode = wholeRange->firstNode();
   2838     Node* pastLastNode = wholeRange->pastLastNode();
   2839     Node* currentNode = firstNode;
   2840     PassRefPtr<Range> currentRange;
   2841 
   2842     while (currentNode != pastLastNode) {
   2843         Node* nextNode = currentNode->traverseNextNode();
   2844         if (!isVisible(currentNode)) {
   2845             if (currentRange) {
   2846                 markup = markup + currentRange->toHTML().utf8().data();
   2847                 currentRange = 0;
   2848             }
   2849         } else {
   2850             if (!currentRange) {
   2851                 currentRange = selection->frame()->document()->createRange();
   2852                 if (ec)
   2853                     break;
   2854                 if (currentNode == firstNode) {
   2855                     currentRange->setStart(wholeRange->startContainer(),
   2856                         wholeRange->startOffset(), ec);
   2857                     if (ec)
   2858                         break;
   2859                 } else {
   2860                     currentRange->setStart(currentNode->parentNode(),
   2861                         currentNode->nodeIndex(), ec);
   2862                     if (ec)
   2863                        break;
   2864                 }
   2865             }
   2866             if (nextNode == pastLastNode) {
   2867                 currentRange->setEnd(wholeRange->endContainer(),
   2868                     wholeRange->endOffset(), ec);
   2869                 if (ec)
   2870                     break;
   2871                 markup = markup + currentRange->toHTML().utf8().data();
   2872             } else {
   2873                 if (currentNode->offsetInCharacters())
   2874                     currentRange->setEnd(currentNode,
   2875                         currentNode->maxCharacterOffset(), ec);
   2876                 else
   2877                     currentRange->setEnd(currentNode->parentNode(),
   2878                             currentNode->nodeIndex() + 1, ec);
   2879                 if (ec)
   2880                     break;
   2881             }
   2882         }
   2883         currentNode = nextNode;
   2884     }
   2885     return markup.stripWhiteSpace();
   2886 }
   2887 
   2888 void WebViewCore::selectAt(int x, int y)
   2889 {
   2890     JNIEnv* env = JSC::Bindings::getJNIEnv();
   2891     AutoJObject javaObject = m_javaGlue->object(env);
   2892     if (!javaObject.get())
   2893         return;
   2894     env->CallVoidMethod(javaObject.get(), m_javaGlue->m_selectAt, x, y);
   2895     checkException(env);
   2896 }
   2897 
   2898 void WebViewCore::deleteSelection(int start, int end, int textGeneration)
   2899 {
   2900     setSelection(start, end);
   2901     if (start == end)
   2902         return;
   2903     WebCore::Node* focus = currentFocus();
   2904     if (!focus)
   2905         return;
   2906     // Prevent our editor client from passing a message to change the
   2907     // selection.
   2908     EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
   2909             m_mainFrame->editor()->client());
   2910     client->setUiGeneratedSelectionChange(true);
   2911     PlatformKeyboardEvent down(AKEYCODE_DEL, 0, 0, true, false, false, false);
   2912     PlatformKeyboardEvent up(AKEYCODE_DEL, 0, 0, false, false, false, false);
   2913     key(down);
   2914     key(up);
   2915     client->setUiGeneratedSelectionChange(false);
   2916     m_textGeneration = textGeneration;
   2917     m_shouldPaintCaret = true;
   2918 }
   2919 
   2920 void WebViewCore::replaceTextfieldText(int oldStart,
   2921         int oldEnd, const WTF::String& replace, int start, int end,
   2922         int textGeneration)
   2923 {
   2924     WebCore::Node* focus = currentFocus();
   2925     if (!focus)
   2926         return;
   2927     setSelection(oldStart, oldEnd);
   2928     // Prevent our editor client from passing a message to change the
   2929     // selection.
   2930     EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
   2931             m_mainFrame->editor()->client());
   2932     client->setUiGeneratedSelectionChange(true);
   2933     WebCore::TypingCommand::insertText(focus->document(), replace,
   2934         false);
   2935     client->setUiGeneratedSelectionChange(false);
   2936     // setSelection calls revealSelection, so there is no need to do it here.
   2937     setSelection(start, end);
   2938     m_textGeneration = textGeneration;
   2939     m_shouldPaintCaret = true;
   2940 }
   2941 
   2942 void WebViewCore::passToJs(int generation, const WTF::String& current,
   2943     const PlatformKeyboardEvent& event)
   2944 {
   2945     WebCore::Node* focus = currentFocus();
   2946     if (!focus) {
   2947         DBG_NAV_LOG("!focus");
   2948         clearTextEntry();
   2949         return;
   2950     }
   2951     WebCore::RenderObject* renderer = focus->renderer();
   2952     if (!renderer || (!renderer->isTextField() && !renderer->isTextArea())) {
   2953         DBG_NAV_LOGD("renderer==%p || not text", renderer);
   2954         clearTextEntry();
   2955         return;
   2956     }
   2957     // Block text field updates during a key press.
   2958     m_blockTextfieldUpdates = true;
   2959     // Also prevent our editor client from passing a message to change the
   2960     // selection.
   2961     EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
   2962             m_mainFrame->editor()->client());
   2963     client->setUiGeneratedSelectionChange(true);
   2964     key(event);
   2965     client->setUiGeneratedSelectionChange(false);
   2966     m_blockTextfieldUpdates = false;
   2967     m_textGeneration = generation;
   2968     WebCore::RenderTextControl* renderText =
   2969         static_cast<WebCore::RenderTextControl*>(renderer);
   2970     WTF::String test = renderText->text();
   2971     if (test != current) {
   2972         // If the text changed during the key event, update the UI text field.
   2973         updateTextfield(focus, false, test);
   2974     } else {
   2975         DBG_NAV_LOG("test == current");
   2976     }
   2977     // Now that the selection has settled down, send it.
   2978     updateTextSelection();
   2979     m_shouldPaintCaret = true;
   2980 }
   2981 
   2982 void WebViewCore::scrollFocusedTextInput(float xPercent, int y)
   2983 {
   2984     WebCore::Node* focus = currentFocus();
   2985     if (!focus) {
   2986         DBG_NAV_LOG("!focus");
   2987         clearTextEntry();
   2988         return;
   2989     }
   2990     WebCore::RenderObject* renderer = focus->renderer();
   2991     if (!renderer || (!renderer->isTextField() && !renderer->isTextArea())) {
   2992         DBG_NAV_LOGD("renderer==%p || not text", renderer);
   2993         clearTextEntry();
   2994         return;
   2995     }
   2996     WebCore::RenderTextControl* renderText =
   2997         static_cast<WebCore::RenderTextControl*>(renderer);
   2998     int x = (int) (xPercent * (renderText->scrollWidth() -
   2999         renderText->clientWidth()));
   3000     DBG_NAV_LOGD("x=%d y=%d xPercent=%g scrollW=%d clientW=%d", x, y,
   3001         xPercent, renderText->scrollWidth(), renderText->clientWidth());
   3002     renderText->setScrollLeft(x);
   3003     renderText->setScrollTop(y);
   3004 }
   3005 
   3006 void WebViewCore::setFocusControllerActive(bool active)
   3007 {
   3008     m_mainFrame->page()->focusController()->setActive(active);
   3009 }
   3010 
   3011 void WebViewCore::saveDocumentState(WebCore::Frame* frame)
   3012 {
   3013     if (!CacheBuilder::validNode(m_mainFrame, frame, 0))
   3014         frame = m_mainFrame;
   3015     WebCore::HistoryItem *item = frame->loader()->history()->currentItem();
   3016 
   3017     // item can be null when there is no offical URL for the current page. This happens
   3018     // when the content is loaded using with WebCoreFrameBridge::LoadData() and there
   3019     // is no failing URL (common case is when content is loaded using data: scheme)
   3020     if (item) {
   3021         item->setDocumentState(frame->document()->formElementsState());
   3022     }
   3023 }
   3024 
   3025 // Create an array of java Strings.
   3026 static jobjectArray makeLabelArray(JNIEnv* env, const uint16_t** labels, size_t count)
   3027 {
   3028     jclass stringClass = env->FindClass("java/lang/String");
   3029     LOG_ASSERT(stringClass, "Could not find java/lang/String");
   3030     jobjectArray array = env->NewObjectArray(count, stringClass, 0);
   3031     LOG_ASSERT(array, "Could not create new string array");
   3032 
   3033     for (size_t i = 0; i < count; i++) {
   3034         jobject newString = env->NewString(&labels[i][1], labels[i][0]);
   3035         env->SetObjectArrayElement(array, i, newString);
   3036         env->DeleteLocalRef(newString);
   3037         checkException(env);
   3038     }
   3039     env->DeleteLocalRef(stringClass);
   3040     return array;
   3041 }
   3042 
   3043 void WebViewCore::openFileChooser(PassRefPtr<WebCore::FileChooser> chooser)
   3044 {
   3045     JNIEnv* env = JSC::Bindings::getJNIEnv();
   3046     AutoJObject javaObject = m_javaGlue->object(env);
   3047     if (!javaObject.get())
   3048         return;
   3049 
   3050     if (!chooser)
   3051         return;
   3052 
   3053     WTF::String acceptType = chooser->acceptTypes();
   3054     jstring jAcceptType = wtfStringToJstring(env, acceptType, true);
   3055     jstring jName = (jstring) env->CallObjectMethod(
   3056             javaObject.get(), m_javaGlue->m_openFileChooser, jAcceptType);
   3057     checkException(env);
   3058     env->DeleteLocalRef(jAcceptType);
   3059 
   3060     WTF::String wtfString = jstringToWtfString(env, jName);
   3061     env->DeleteLocalRef(jName);
   3062 
   3063     if (!wtfString.isEmpty())
   3064         chooser->chooseFile(wtfString);
   3065 }
   3066 
   3067 void WebViewCore::listBoxRequest(WebCoreReply* reply, const uint16_t** labels, size_t count, const int enabled[], size_t enabledCount,
   3068         bool multiple, const int selected[], size_t selectedCountOrSelection)
   3069 {
   3070     LOG_ASSERT(m_javaGlue->m_obj, "No java widget associated with this view!");
   3071 
   3072     JNIEnv* env = JSC::Bindings::getJNIEnv();
   3073     AutoJObject javaObject = m_javaGlue->object(env);
   3074     if (!javaObject.get())
   3075         return;
   3076 
   3077     // If m_popupReply is not null, then we already have a list showing.
   3078     if (m_popupReply != 0)
   3079         return;
   3080 
   3081     // Create an array of java Strings for the drop down.
   3082     jobjectArray labelArray = makeLabelArray(env, labels, count);
   3083 
   3084     // Create an array determining whether each item is enabled.
   3085     jintArray enabledArray = env->NewIntArray(enabledCount);
   3086     checkException(env);
   3087     jint* ptrArray = env->GetIntArrayElements(enabledArray, 0);
   3088     checkException(env);
   3089     for (size_t i = 0; i < enabledCount; i++) {
   3090         ptrArray[i] = enabled[i];
   3091     }
   3092     env->ReleaseIntArrayElements(enabledArray, ptrArray, 0);
   3093     checkException(env);
   3094 
   3095     if (multiple) {
   3096         // Pass up an array representing which items are selected.
   3097         jintArray selectedArray = env->NewIntArray(selectedCountOrSelection);
   3098         checkException(env);
   3099         jint* selArray = env->GetIntArrayElements(selectedArray, 0);
   3100         checkException(env);
   3101         for (size_t i = 0; i < selectedCountOrSelection; i++) {
   3102             selArray[i] = selected[i];
   3103         }
   3104         env->ReleaseIntArrayElements(selectedArray, selArray, 0);
   3105 
   3106         env->CallVoidMethod(javaObject.get(),
   3107                 m_javaGlue->m_requestListBox, labelArray, enabledArray,
   3108                 selectedArray);
   3109         env->DeleteLocalRef(selectedArray);
   3110     } else {
   3111         // Pass up the single selection.
   3112         env->CallVoidMethod(javaObject.get(),
   3113                 m_javaGlue->m_requestSingleListBox, labelArray, enabledArray,
   3114                 selectedCountOrSelection);
   3115     }
   3116 
   3117     env->DeleteLocalRef(labelArray);
   3118     env->DeleteLocalRef(enabledArray);
   3119     checkException(env);
   3120 
   3121     Retain(reply);
   3122     m_popupReply = reply;
   3123 }
   3124 
   3125 bool WebViewCore::key(const PlatformKeyboardEvent& event)
   3126 {
   3127     WebCore::EventHandler* eventHandler;
   3128     WebCore::Node* focusNode = currentFocus();
   3129     DBG_NAV_LOGD("keyCode=%s unichar=%d focusNode=%p",
   3130         event.keyIdentifier().utf8().data(), event.unichar(), focusNode);
   3131     if (focusNode) {
   3132         WebCore::Frame* frame = focusNode->document()->frame();
   3133         WebFrame* webFrame = WebFrame::getWebFrame(frame);
   3134         eventHandler = frame->eventHandler();
   3135         VisibleSelection old = frame->selection()->selection();
   3136         bool handled = eventHandler->keyEvent(event);
   3137         if (isContentEditable(focusNode)) {
   3138             // keyEvent will return true even if the contentEditable did not
   3139             // change its selection.  In the case that it does not, we want to
   3140             // return false so that the key will be sent back to our navigation
   3141             // system.
   3142             handled |= frame->selection()->selection() != old;
   3143         }
   3144         return handled;
   3145     } else {
   3146         eventHandler = m_mainFrame->eventHandler();
   3147     }
   3148     return eventHandler->keyEvent(event);
   3149 }
   3150 
   3151 // For when the user clicks the trackball, presses dpad center, or types into an
   3152 // unfocused textfield.  In the latter case, 'fake' will be true
   3153 void WebViewCore::click(WebCore::Frame* frame, WebCore::Node* node, bool fake) {
   3154     if (!node) {
   3155         WebCore::IntPoint pt = m_mousePos;
   3156         pt.move(m_scrollOffsetX, m_scrollOffsetY);
   3157         WebCore::HitTestResult hitTestResult = m_mainFrame->eventHandler()->
   3158                 hitTestResultAtPoint(pt, false);
   3159         node = hitTestResult.innerNode();
   3160         frame = node->document()->frame();
   3161         DBG_NAV_LOGD("m_mousePos=(%d,%d) m_scrollOffset=(%d,%d) pt=(%d,%d)"
   3162             " node=%p", m_mousePos.x(), m_mousePos.y(),
   3163             m_scrollOffsetX, m_scrollOffsetY, pt.x(), pt.y(), node);
   3164     }
   3165     if (node) {
   3166         EditorClientAndroid* client
   3167                 = static_cast<EditorClientAndroid*>(
   3168                 m_mainFrame->editor()->client());
   3169         client->setShouldChangeSelectedRange(false);
   3170         handleMouseClick(frame, node, fake);
   3171         client->setShouldChangeSelectedRange(true);
   3172     }
   3173 }
   3174 
   3175 #if USE(ACCELERATED_COMPOSITING)
   3176 GraphicsLayerAndroid* WebViewCore::graphicsRootLayer() const
   3177 {
   3178     RenderView* contentRenderer = m_mainFrame->contentRenderer();
   3179     if (!contentRenderer)
   3180         return 0;
   3181     return static_cast<GraphicsLayerAndroid*>(
   3182           contentRenderer->compositor()->rootPlatformLayer());
   3183 }
   3184 #endif
   3185 
   3186 bool WebViewCore::handleTouchEvent(int action, Vector<int>& ids, Vector<IntPoint>& points, int actionIndex, int metaState)
   3187 {
   3188     bool preventDefault = false;
   3189 
   3190 #if USE(ACCELERATED_COMPOSITING)
   3191     GraphicsLayerAndroid* rootLayer = graphicsRootLayer();
   3192     if (rootLayer)
   3193       rootLayer->pauseDisplay(true);
   3194 #endif
   3195 
   3196 #if ENABLE(TOUCH_EVENTS) // Android
   3197     #define MOTION_EVENT_ACTION_POINTER_DOWN 5
   3198     #define MOTION_EVENT_ACTION_POINTER_UP 6
   3199 
   3200     WebCore::TouchEventType type = WebCore::TouchStart;
   3201     WebCore::PlatformTouchPoint::State defaultTouchState;
   3202     Vector<WebCore::PlatformTouchPoint::State> touchStates(points.size());
   3203 
   3204     switch (action) {
   3205     case 0: // MotionEvent.ACTION_DOWN
   3206         type = WebCore::TouchStart;
   3207         defaultTouchState = WebCore::PlatformTouchPoint::TouchPressed;
   3208         break;
   3209     case 1: // MotionEvent.ACTION_UP
   3210         type = WebCore::TouchEnd;
   3211         defaultTouchState = WebCore::PlatformTouchPoint::TouchReleased;
   3212         break;
   3213     case 2: // MotionEvent.ACTION_MOVE
   3214         type = WebCore::TouchMove;
   3215         defaultTouchState = WebCore::PlatformTouchPoint::TouchMoved;
   3216         break;
   3217     case 3: // MotionEvent.ACTION_CANCEL
   3218         type = WebCore::TouchCancel;
   3219         defaultTouchState = WebCore::PlatformTouchPoint::TouchCancelled;
   3220         break;
   3221     case 5: // MotionEvent.ACTION_POINTER_DOWN
   3222         type = WebCore::TouchStart;
   3223         defaultTouchState = WebCore::PlatformTouchPoint::TouchStationary;
   3224         break;
   3225     case 6: // MotionEvent.ACTION_POINTER_UP
   3226         type = WebCore::TouchEnd;
   3227         defaultTouchState = WebCore::PlatformTouchPoint::TouchStationary;
   3228         break;
   3229     case 0x100: // WebViewCore.ACTION_LONGPRESS
   3230         type = WebCore::TouchLongPress;
   3231         defaultTouchState = WebCore::PlatformTouchPoint::TouchPressed;
   3232         break;
   3233     case 0x200: // WebViewCore.ACTION_DOUBLETAP
   3234         type = WebCore::TouchDoubleTap;
   3235         defaultTouchState = WebCore::PlatformTouchPoint::TouchPressed;
   3236         break;
   3237     default:
   3238         // We do not support other kinds of touch event inside WebCore
   3239         // at the moment.
   3240         LOGW("Java passed a touch event type that we do not support in WebCore: %d", action);
   3241         return 0;
   3242     }
   3243 
   3244     for (int c = 0; c < static_cast<int>(points.size()); c++) {
   3245         points[c].setX(points[c].x() - m_scrollOffsetX);
   3246         points[c].setY(points[c].y() - m_scrollOffsetY);
   3247 
   3248         // Setting the touch state for each point.
   3249         // Note: actionIndex will be 0 for all actions that are not ACTION_POINTER_DOWN/UP.
   3250         if (action == MOTION_EVENT_ACTION_POINTER_DOWN && c == actionIndex) {
   3251             touchStates[c] = WebCore::PlatformTouchPoint::TouchPressed;
   3252         } else if (action == MOTION_EVENT_ACTION_POINTER_UP && c == actionIndex) {
   3253             touchStates[c] = WebCore::PlatformTouchPoint::TouchReleased;
   3254         } else {
   3255             touchStates[c] = defaultTouchState;
   3256         };
   3257     }
   3258 
   3259     WebCore::PlatformTouchEvent te(ids, points, type, touchStates, metaState);
   3260     preventDefault = m_mainFrame->eventHandler()->handleTouchEvent(te);
   3261 #endif
   3262 
   3263 #if USE(ACCELERATED_COMPOSITING)
   3264     if (rootLayer)
   3265       rootLayer->pauseDisplay(false);
   3266 #endif
   3267     return preventDefault;
   3268 }
   3269 
   3270 void WebViewCore::touchUp(int touchGeneration,
   3271     WebCore::Frame* frame, WebCore::Node* node, int x, int y)
   3272 {
   3273     if (touchGeneration == 0) {
   3274         // m_mousePos should be set in getTouchHighlightRects()
   3275         WebCore::HitTestResult hitTestResult = m_mainFrame->eventHandler()->hitTestResultAtPoint(m_mousePos, false);
   3276         node = hitTestResult.innerNode();
   3277         if (node)
   3278             frame = node->document()->frame();
   3279         else
   3280             frame = 0;
   3281         DBG_NAV_LOGD("touch up on (%d, %d), scrollOffset is (%d, %d), node:%p, frame:%p", m_mousePos.x() + m_scrollOffsetX, m_mousePos.y() + m_scrollOffsetY, m_scrollOffsetX, m_scrollOffsetY, node, frame);
   3282     } else {
   3283         if (m_touchGeneration > touchGeneration) {
   3284             DBG_NAV_LOGD("m_touchGeneration=%d > touchGeneration=%d"
   3285                 " x=%d y=%d", m_touchGeneration, touchGeneration, x, y);
   3286             return; // short circuit if a newer touch has been generated
   3287         }
   3288         // This moves m_mousePos to the correct place, and handleMouseClick uses
   3289         // m_mousePos to determine where the click happens.
   3290         moveMouse(frame, x, y);
   3291         m_lastGeneration = touchGeneration;
   3292     }
   3293     if (frame && CacheBuilder::validNode(m_mainFrame, frame, 0)) {
   3294         frame->loader()->resetMultipleFormSubmissionProtection();
   3295     }
   3296     DBG_NAV_LOGD("touchGeneration=%d handleMouseClick frame=%p node=%p"
   3297         " x=%d y=%d", touchGeneration, frame, node, x, y);
   3298     handleMouseClick(frame, node, false);
   3299 }
   3300 
   3301 // Check for the "x-webkit-soft-keyboard" attribute.  If it is there and
   3302 // set to hidden, do not show the soft keyboard.  Node passed as a parameter
   3303 // must not be null.
   3304 static bool shouldSuppressKeyboard(const WebCore::Node* node) {
   3305     LOG_ASSERT(node, "node passed to shouldSuppressKeyboard cannot be null");
   3306     const NamedNodeMap* attributes = node->attributes();
   3307     if (!attributes) return false;
   3308     size_t length = attributes->length();
   3309     for (size_t i = 0; i < length; i++) {
   3310         const Attribute* a = attributes->attributeItem(i);
   3311         if (a->localName() == "x-webkit-soft-keyboard" && a->value() == "hidden")
   3312             return true;
   3313     }
   3314     return false;
   3315 }
   3316 
   3317 // Common code for both clicking with the trackball and touchUp
   3318 // Also used when typing into a non-focused textfield to give the textfield focus,
   3319 // in which case, 'fake' is set to true
   3320 bool WebViewCore::handleMouseClick(WebCore::Frame* framePtr, WebCore::Node* nodePtr, bool fake)
   3321 {
   3322     bool valid = !framePtr || CacheBuilder::validNode(m_mainFrame, framePtr, nodePtr);
   3323     WebFrame* webFrame = WebFrame::getWebFrame(m_mainFrame);
   3324     if (valid && nodePtr) {
   3325     // Need to special case area tags because an image map could have an area element in the middle
   3326     // so when attempting to get the default, the point chosen would be follow the wrong link.
   3327         if (nodePtr->hasTagName(WebCore::HTMLNames::areaTag)) {
   3328             webFrame->setUserInitiatedAction(true);
   3329             nodePtr->dispatchSimulatedClick(0, true, true);
   3330             webFrame->setUserInitiatedAction(false);
   3331             DBG_NAV_LOG("area");
   3332             return true;
   3333         }
   3334     }
   3335     if (!valid || !framePtr)
   3336         framePtr = m_mainFrame;
   3337     webFrame->setUserInitiatedAction(true);
   3338     WebCore::PlatformMouseEvent mouseDown(m_mousePos, m_mousePos, WebCore::LeftButton,
   3339             WebCore::MouseEventPressed, 1, false, false, false, false,
   3340             WTF::currentTime());
   3341     // ignore the return from as it will return true if the hit point can trigger selection change
   3342     framePtr->eventHandler()->handleMousePressEvent(mouseDown);
   3343     WebCore::PlatformMouseEvent mouseUp(m_mousePos, m_mousePos, WebCore::LeftButton,
   3344             WebCore::MouseEventReleased, 1, false, false, false, false,
   3345             WTF::currentTime());
   3346     bool handled = framePtr->eventHandler()->handleMouseReleaseEvent(mouseUp);
   3347     webFrame->setUserInitiatedAction(false);
   3348 
   3349     // If the user clicked on a textfield, make the focusController active
   3350     // so we show the blinking cursor.
   3351     WebCore::Node* focusNode = currentFocus();
   3352     DBG_NAV_LOGD("m_mousePos={%d,%d} focusNode=%p handled=%s", m_mousePos.x(),
   3353         m_mousePos.y(), focusNode, handled ? "true" : "false");
   3354     if (focusNode) {
   3355         WebCore::RenderObject* renderer = focusNode->renderer();
   3356         if (renderer && (renderer->isTextField() || renderer->isTextArea())) {
   3357             bool ime = !shouldSuppressKeyboard(focusNode)
   3358                     && !(static_cast<WebCore::HTMLInputElement*>(focusNode))->readOnly();
   3359             if (ime) {
   3360 #if ENABLE(WEB_AUTOFILL)
   3361                 if (renderer->isTextField()) {
   3362                     EditorClientAndroid* editorC = static_cast<EditorClientAndroid*>(framePtr->page()->editorClient());
   3363                     WebAutofill* autoFill = editorC->getAutofill();
   3364                     autoFill->formFieldFocused(static_cast<HTMLFormControlElement*>(focusNode));
   3365                 }
   3366 #endif
   3367                 if (!fake) {
   3368                     RenderTextControl* rtc
   3369                             = static_cast<RenderTextControl*> (renderer);
   3370                     // Force an update of the navcache as this will fire off a
   3371                     // message to WebView that *must* have an updated focus.
   3372                     m_frameCacheOutOfDate = true;
   3373                     updateFrameCache();
   3374                     requestKeyboardWithSelection(focusNode, rtc->selectionStart(),
   3375                             rtc->selectionEnd());
   3376                 }
   3377             } else if (!fake) {
   3378                 requestKeyboard(false);
   3379             }
   3380         } else if (!fake){
   3381             // If the selection is contentEditable, show the keyboard so the
   3382             // user can type.  Otherwise hide the keyboard because no text
   3383             // input is needed.
   3384             if (isContentEditable(focusNode)) {
   3385                 requestKeyboard(true);
   3386             } else if (!nodeIsPlugin(focusNode)) {
   3387                 clearTextEntry();
   3388             }
   3389         }
   3390     } else if (!fake) {
   3391         // There is no focusNode, so the keyboard is not needed.
   3392         clearTextEntry();
   3393     }
   3394     return handled;
   3395 }
   3396 
   3397 void WebViewCore::popupReply(int index)
   3398 {
   3399     if (m_popupReply) {
   3400         m_popupReply->replyInt(index);
   3401         Release(m_popupReply);
   3402         m_popupReply = 0;
   3403     }
   3404 }
   3405 
   3406 void WebViewCore::popupReply(const int* array, int count)
   3407 {
   3408     if (m_popupReply) {
   3409         m_popupReply->replyIntArray(array, count);
   3410         Release(m_popupReply);
   3411         m_popupReply = 0;
   3412     }
   3413 }
   3414 
   3415 void WebViewCore::formDidBlur(const WebCore::Node* node)
   3416 {
   3417     // If the blur is on a text input, keep track of the node so we can
   3418     // hide the soft keyboard when the new focus is set, if it is not a
   3419     // text input.
   3420     if (isTextInput(node))
   3421         m_blurringNodePointer = reinterpret_cast<int>(node);
   3422 }
   3423 
   3424 void WebViewCore::focusNodeChanged(const WebCore::Node* newFocus)
   3425 {
   3426     if (isTextInput(newFocus))
   3427         m_shouldPaintCaret = true;
   3428     else if (m_blurringNodePointer) {
   3429         JNIEnv* env = JSC::Bindings::getJNIEnv();
   3430         AutoJObject javaObject = m_javaGlue->object(env);
   3431         if (!javaObject.get())
   3432             return;
   3433         env->CallVoidMethod(javaObject.get(), m_javaGlue->m_formDidBlur, m_blurringNodePointer);
   3434         checkException(env);
   3435         m_blurringNodePointer = 0;
   3436     }
   3437 }
   3438 
   3439 void WebViewCore::addMessageToConsole(const WTF::String& message, unsigned int lineNumber, const WTF::String& sourceID, int msgLevel) {
   3440     JNIEnv* env = JSC::Bindings::getJNIEnv();
   3441     AutoJObject javaObject = m_javaGlue->object(env);
   3442     if (!javaObject.get())
   3443         return;
   3444     jstring jMessageStr = wtfStringToJstring(env, message);
   3445     jstring jSourceIDStr = wtfStringToJstring(env, sourceID);
   3446     env->CallVoidMethod(javaObject.get(),
   3447             m_javaGlue->m_addMessageToConsole, jMessageStr, lineNumber,
   3448             jSourceIDStr, msgLevel);
   3449     env->DeleteLocalRef(jMessageStr);
   3450     env->DeleteLocalRef(jSourceIDStr);
   3451     checkException(env);
   3452 }
   3453 
   3454 void WebViewCore::jsAlert(const WTF::String& url, const WTF::String& text)
   3455 {
   3456     JNIEnv* env = JSC::Bindings::getJNIEnv();
   3457     AutoJObject javaObject = m_javaGlue->object(env);
   3458     if (!javaObject.get())
   3459         return;
   3460     jstring jInputStr = wtfStringToJstring(env, text);
   3461     jstring jUrlStr = wtfStringToJstring(env, url);
   3462     env->CallVoidMethod(javaObject.get(), m_javaGlue->m_jsAlert, jUrlStr, jInputStr);
   3463     env->DeleteLocalRef(jInputStr);
   3464     env->DeleteLocalRef(jUrlStr);
   3465     checkException(env);
   3466 }
   3467 
   3468 bool WebViewCore::exceededDatabaseQuota(const WTF::String& url, const WTF::String& databaseIdentifier, const unsigned long long currentQuota, unsigned long long estimatedSize)
   3469 {
   3470 #if ENABLE(DATABASE)
   3471     JNIEnv* env = JSC::Bindings::getJNIEnv();
   3472     AutoJObject javaObject = m_javaGlue->object(env);
   3473     if (!javaObject.get())
   3474         return false;
   3475     jstring jDatabaseIdentifierStr = wtfStringToJstring(env, databaseIdentifier);
   3476     jstring jUrlStr = wtfStringToJstring(env, url);
   3477     env->CallVoidMethod(javaObject.get(),
   3478             m_javaGlue->m_exceededDatabaseQuota, jUrlStr,
   3479             jDatabaseIdentifierStr, currentQuota, estimatedSize);
   3480     env->DeleteLocalRef(jDatabaseIdentifierStr);
   3481     env->DeleteLocalRef(jUrlStr);
   3482     checkException(env);
   3483     return true;
   3484 #endif
   3485 }
   3486 
   3487 bool WebViewCore::reachedMaxAppCacheSize(const unsigned long long spaceNeeded)
   3488 {
   3489 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
   3490     JNIEnv* env = JSC::Bindings::getJNIEnv();
   3491     AutoJObject javaObject = m_javaGlue->object(env);
   3492     if (!javaObject.get())
   3493         return false;
   3494     env->CallVoidMethod(javaObject.get(), m_javaGlue->m_reachedMaxAppCacheSize, spaceNeeded);
   3495     checkException(env);
   3496     return true;
   3497 #endif
   3498 }
   3499 
   3500 void WebViewCore::populateVisitedLinks(WebCore::PageGroup* group)
   3501 {
   3502     JNIEnv* env = JSC::Bindings::getJNIEnv();
   3503     AutoJObject javaObject = m_javaGlue->object(env);
   3504     if (!javaObject.get())
   3505         return;
   3506     m_groupForVisitedLinks = group;
   3507     env->CallVoidMethod(javaObject.get(), m_javaGlue->m_populateVisitedLinks);
   3508     checkException(env);
   3509 }
   3510 
   3511 void WebViewCore::geolocationPermissionsShowPrompt(const WTF::String& origin)
   3512 {
   3513     JNIEnv* env = JSC::Bindings::getJNIEnv();
   3514     AutoJObject javaObject = m_javaGlue->object(env);
   3515     if (!javaObject.get())
   3516         return;
   3517     jstring originString = wtfStringToJstring(env, origin);
   3518     env->CallVoidMethod(javaObject.get(),
   3519                         m_javaGlue->m_geolocationPermissionsShowPrompt,
   3520                         originString);
   3521     env->DeleteLocalRef(originString);
   3522     checkException(env);
   3523 }
   3524 
   3525 void WebViewCore::geolocationPermissionsHidePrompt()
   3526 {
   3527     JNIEnv* env = JSC::Bindings::getJNIEnv();
   3528     AutoJObject javaObject = m_javaGlue->object(env);
   3529     if (!javaObject.get())
   3530         return;
   3531     env->CallVoidMethod(javaObject.get(), m_javaGlue->m_geolocationPermissionsHidePrompt);
   3532     checkException(env);
   3533 }
   3534 
   3535 jobject WebViewCore::getDeviceMotionService()
   3536 {
   3537     JNIEnv* env = JSC::Bindings::getJNIEnv();
   3538     AutoJObject javaObject = m_javaGlue->object(env);
   3539     if (!javaObject.get())
   3540         return 0;
   3541     jobject object = env->CallObjectMethod(javaObject.get(), m_javaGlue->m_getDeviceMotionService);
   3542     checkException(env);
   3543     return object;
   3544 }
   3545 
   3546 jobject WebViewCore::getDeviceOrientationService()
   3547 {
   3548     JNIEnv* env = JSC::Bindings::getJNIEnv();
   3549     AutoJObject javaObject = m_javaGlue->object(env);
   3550     if (!javaObject.get())
   3551         return 0;
   3552     jobject object = env->CallObjectMethod(javaObject.get(), m_javaGlue->m_getDeviceOrientationService);
   3553     checkException(env);
   3554     return object;
   3555 }
   3556 
   3557 bool WebViewCore::jsConfirm(const WTF::String& url, const WTF::String& text)
   3558 {
   3559     JNIEnv* env = JSC::Bindings::getJNIEnv();
   3560     AutoJObject javaObject = m_javaGlue->object(env);
   3561     if (!javaObject.get())
   3562         return false;
   3563     jstring jInputStr = wtfStringToJstring(env, text);
   3564     jstring jUrlStr = wtfStringToJstring(env, url);
   3565     jboolean result = env->CallBooleanMethod(javaObject.get(), m_javaGlue->m_jsConfirm, jUrlStr, jInputStr);
   3566     env->DeleteLocalRef(jInputStr);
   3567     env->DeleteLocalRef(jUrlStr);
   3568     checkException(env);
   3569     return result;
   3570 }
   3571 
   3572 bool WebViewCore::jsPrompt(const WTF::String& url, const WTF::String& text, const WTF::String& defaultValue, WTF::String& result)
   3573 {
   3574     JNIEnv* env = JSC::Bindings::getJNIEnv();
   3575     AutoJObject javaObject = m_javaGlue->object(env);
   3576     if (!javaObject.get())
   3577         return false;
   3578     jstring jUrlStr = wtfStringToJstring(env, url);
   3579     jstring jInputStr = wtfStringToJstring(env, text);
   3580     jstring jDefaultStr = wtfStringToJstring(env, defaultValue);
   3581     jstring returnVal = static_cast<jstring>(env->CallObjectMethod(javaObject.get(), m_javaGlue->m_jsPrompt, jUrlStr, jInputStr, jDefaultStr));
   3582     env->DeleteLocalRef(jUrlStr);
   3583     env->DeleteLocalRef(jInputStr);
   3584     env->DeleteLocalRef(jDefaultStr);
   3585     checkException(env);
   3586 
   3587     // If returnVal is null, it means that the user cancelled the dialog.
   3588     if (!returnVal)
   3589         return false;
   3590 
   3591     result = jstringToWtfString(env, returnVal);
   3592     env->DeleteLocalRef(returnVal);
   3593     return true;
   3594 }
   3595 
   3596 bool WebViewCore::jsUnload(const WTF::String& url, const WTF::String& message)
   3597 {
   3598     JNIEnv* env = JSC::Bindings::getJNIEnv();
   3599     AutoJObject javaObject = m_javaGlue->object(env);
   3600     if (!javaObject.get())
   3601         return false;
   3602     jstring jInputStr = wtfStringToJstring(env, message);
   3603     jstring jUrlStr = wtfStringToJstring(env, url);
   3604     jboolean result = env->CallBooleanMethod(javaObject.get(), m_javaGlue->m_jsUnload, jUrlStr, jInputStr);
   3605     env->DeleteLocalRef(jInputStr);
   3606     env->DeleteLocalRef(jUrlStr);
   3607     checkException(env);
   3608     return result;
   3609 }
   3610 
   3611 bool WebViewCore::jsInterrupt()
   3612 {
   3613     JNIEnv* env = JSC::Bindings::getJNIEnv();
   3614     AutoJObject javaObject = m_javaGlue->object(env);
   3615     if (!javaObject.get())
   3616         return false;
   3617     jboolean result = env->CallBooleanMethod(javaObject.get(), m_javaGlue->m_jsInterrupt);
   3618     checkException(env);
   3619     return result;
   3620 }
   3621 
   3622 AutoJObject
   3623 WebViewCore::getJavaObject()
   3624 {
   3625     return m_javaGlue->object(JSC::Bindings::getJNIEnv());
   3626 }
   3627 
   3628 jobject
   3629 WebViewCore::getWebViewJavaObject()
   3630 {
   3631     JNIEnv* env = JSC::Bindings::getJNIEnv();
   3632     AutoJObject javaObject = m_javaGlue->object(env);
   3633     if (!javaObject.get())
   3634         return 0;
   3635     return env->GetObjectField(javaObject.get(), gWebViewCoreFields.m_webView);
   3636 }
   3637 
   3638 void WebViewCore::updateTextSelection()
   3639 {
   3640     JNIEnv* env = JSC::Bindings::getJNIEnv();
   3641     AutoJObject javaObject = m_javaGlue->object(env);
   3642     if (!javaObject.get())
   3643         return;
   3644     WebCore::Node* focusNode = currentFocus();
   3645     if (!focusNode)
   3646         return;
   3647     RenderObject* renderer = focusNode->renderer();
   3648     if (!renderer || (!renderer->isTextArea() && !renderer->isTextField()))
   3649         return;
   3650     RenderTextControl* rtc = static_cast<RenderTextControl*>(renderer);
   3651     env->CallVoidMethod(javaObject.get(),
   3652             m_javaGlue->m_updateTextSelection, reinterpret_cast<int>(focusNode),
   3653             rtc->selectionStart(), rtc->selectionEnd(), m_textGeneration);
   3654     checkException(env);
   3655 }
   3656 
   3657 void WebViewCore::updateTextfield(WebCore::Node* ptr, bool changeToPassword,
   3658         const WTF::String& text)
   3659 {
   3660     JNIEnv* env = JSC::Bindings::getJNIEnv();
   3661     AutoJObject javaObject = m_javaGlue->object(env);
   3662     if (!javaObject.get())
   3663         return;
   3664     if (m_blockTextfieldUpdates)
   3665         return;
   3666     if (changeToPassword) {
   3667         env->CallVoidMethod(javaObject.get(), m_javaGlue->m_updateTextfield,
   3668                 (int) ptr, true, 0, m_textGeneration);
   3669         checkException(env);
   3670         return;
   3671     }
   3672     jstring string = wtfStringToJstring(env, text);
   3673     env->CallVoidMethod(javaObject.get(), m_javaGlue->m_updateTextfield,
   3674             (int) ptr, false, string, m_textGeneration);
   3675     env->DeleteLocalRef(string);
   3676     checkException(env);
   3677 }
   3678 
   3679 void WebViewCore::clearTextEntry()
   3680 {
   3681     JNIEnv* env = JSC::Bindings::getJNIEnv();
   3682     AutoJObject javaObject = m_javaGlue->object(env);
   3683     if (!javaObject.get())
   3684         return;
   3685     env->CallVoidMethod(javaObject.get(), m_javaGlue->m_clearTextEntry);
   3686 }
   3687 
   3688 void WebViewCore::setBackgroundColor(SkColor c)
   3689 {
   3690     WebCore::FrameView* view = m_mainFrame->view();
   3691     if (!view)
   3692         return;
   3693 
   3694     // need (int) cast to find the right constructor
   3695     WebCore::Color bcolor((int)SkColorGetR(c), (int)SkColorGetG(c),
   3696                           (int)SkColorGetB(c), (int)SkColorGetA(c));
   3697     view->setBaseBackgroundColor(bcolor);
   3698 
   3699     // Background color of 0 indicates we want a transparent background
   3700     if (c == 0)
   3701         view->setTransparent(true);
   3702 }
   3703 
   3704 jclass WebViewCore::getPluginClass(const WTF::String& libName, const char* className)
   3705 {
   3706     JNIEnv* env = JSC::Bindings::getJNIEnv();
   3707     AutoJObject javaObject = m_javaGlue->object(env);
   3708     if (!javaObject.get())
   3709         return 0;
   3710 
   3711     jstring libString = wtfStringToJstring(env, libName);
   3712     jstring classString = env->NewStringUTF(className);
   3713     jobject pluginClass = env->CallObjectMethod(javaObject.get(),
   3714                                            m_javaGlue->m_getPluginClass,
   3715                                            libString, classString);
   3716     checkException(env);
   3717 
   3718     // cleanup unneeded local JNI references
   3719     env->DeleteLocalRef(libString);
   3720     env->DeleteLocalRef(classString);
   3721 
   3722     if (pluginClass != 0) {
   3723         return static_cast<jclass>(pluginClass);
   3724     } else {
   3725         return 0;
   3726     }
   3727 }
   3728 
   3729 void WebViewCore::showFullScreenPlugin(jobject childView, int32_t orientation, NPP npp)
   3730 {
   3731     JNIEnv* env = JSC::Bindings::getJNIEnv();
   3732     AutoJObject javaObject = m_javaGlue->object(env);
   3733     if (!javaObject.get())
   3734         return;
   3735 
   3736     env->CallVoidMethod(javaObject.get(),
   3737                         m_javaGlue->m_showFullScreenPlugin,
   3738                         childView, orientation, reinterpret_cast<int>(npp));
   3739     checkException(env);
   3740 }
   3741 
   3742 void WebViewCore::hideFullScreenPlugin()
   3743 {
   3744     JNIEnv* env = JSC::Bindings::getJNIEnv();
   3745     AutoJObject javaObject = m_javaGlue->object(env);
   3746     if (!javaObject.get())
   3747         return;
   3748     env->CallVoidMethod(javaObject.get(), m_javaGlue->m_hideFullScreenPlugin);
   3749     checkException(env);
   3750 }
   3751 
   3752 jobject WebViewCore::createSurface(jobject view)
   3753 {
   3754     JNIEnv* env = JSC::Bindings::getJNIEnv();
   3755     AutoJObject javaObject = m_javaGlue->object(env);
   3756     if (!javaObject.get())
   3757         return 0;
   3758     jobject result = env->CallObjectMethod(javaObject.get(), m_javaGlue->m_createSurface, view);
   3759     checkException(env);
   3760     return result;
   3761 }
   3762 
   3763 jobject WebViewCore::addSurface(jobject view, int x, int y, int width, int height)
   3764 {
   3765     JNIEnv* env = JSC::Bindings::getJNIEnv();
   3766     AutoJObject javaObject = m_javaGlue->object(env);
   3767     if (!javaObject.get())
   3768         return 0;
   3769     jobject result = env->CallObjectMethod(javaObject.get(),
   3770                                            m_javaGlue->m_addSurface,
   3771                                            view, x, y, width, height);
   3772     checkException(env);
   3773     return result;
   3774 }
   3775 
   3776 void WebViewCore::updateSurface(jobject childView, int x, int y, int width, int height)
   3777 {
   3778     JNIEnv* env = JSC::Bindings::getJNIEnv();
   3779     AutoJObject javaObject = m_javaGlue->object(env);
   3780     if (!javaObject.get())
   3781         return;
   3782     env->CallVoidMethod(javaObject.get(),
   3783                         m_javaGlue->m_updateSurface, childView,
   3784                         x, y, width, height);
   3785     checkException(env);
   3786 }
   3787 
   3788 void WebViewCore::destroySurface(jobject childView)
   3789 {
   3790     JNIEnv* env = JSC::Bindings::getJNIEnv();
   3791     AutoJObject javaObject = m_javaGlue->object(env);
   3792     if (!javaObject.get())
   3793         return;
   3794     env->CallVoidMethod(javaObject.get(), m_javaGlue->m_destroySurface, childView);
   3795     checkException(env);
   3796 }
   3797 
   3798 jobject WebViewCore::getContext()
   3799 {
   3800     JNIEnv* env = JSC::Bindings::getJNIEnv();
   3801     AutoJObject javaObject = m_javaGlue->object(env);
   3802     if (!javaObject.get())
   3803         return 0;
   3804 
   3805     jobject result = env->CallObjectMethod(javaObject.get(), m_javaGlue->m_getContext);
   3806     checkException(env);
   3807     return result;
   3808 }
   3809 
   3810 void WebViewCore::keepScreenOn(bool screenOn) {
   3811     if ((screenOn && m_screenOnCounter == 0) || (!screenOn && m_screenOnCounter == 1)) {
   3812         JNIEnv* env = JSC::Bindings::getJNIEnv();
   3813         AutoJObject javaObject = m_javaGlue->object(env);
   3814         if (!javaObject.get())
   3815             return;
   3816         env->CallVoidMethod(javaObject.get(), m_javaGlue->m_keepScreenOn, screenOn);
   3817         checkException(env);
   3818     }
   3819 
   3820     // update the counter
   3821     if (screenOn)
   3822         m_screenOnCounter++;
   3823     else if (m_screenOnCounter > 0)
   3824         m_screenOnCounter--;
   3825 }
   3826 
   3827 bool WebViewCore::validNodeAndBounds(Frame* frame, Node* node,
   3828     const IntRect& originalAbsoluteBounds)
   3829 {
   3830     bool valid = CacheBuilder::validNode(m_mainFrame, frame, node);
   3831     if (!valid)
   3832         return false;
   3833     RenderObject* renderer = node->renderer();
   3834     if (!renderer)
   3835         return false;
   3836     IntRect absBounds = node->hasTagName(HTMLNames::areaTag)
   3837         ? CacheBuilder::getAreaRect(static_cast<HTMLAreaElement*>(node))
   3838         : renderer->absoluteBoundingBoxRect();
   3839     return absBounds == originalAbsoluteBounds;
   3840 }
   3841 
   3842 void WebViewCore::showRect(int left, int top, int width, int height,
   3843         int contentWidth, int contentHeight, float xPercentInDoc,
   3844         float xPercentInView, float yPercentInDoc, float yPercentInView)
   3845 {
   3846     JNIEnv* env = JSC::Bindings::getJNIEnv();
   3847     AutoJObject javaObject = m_javaGlue->object(env);
   3848     if (!javaObject.get())
   3849         return;
   3850     env->CallVoidMethod(javaObject.get(), m_javaGlue->m_showRect,
   3851             left, top, width, height, contentWidth, contentHeight,
   3852             xPercentInDoc, xPercentInView, yPercentInDoc, yPercentInView);
   3853     checkException(env);
   3854 }
   3855 
   3856 void WebViewCore::centerFitRect(int x, int y, int width, int height)
   3857 {
   3858     JNIEnv* env = JSC::Bindings::getJNIEnv();
   3859     AutoJObject javaObject = m_javaGlue->object(env);
   3860     if (!javaObject.get())
   3861         return;
   3862     env->CallVoidMethod(javaObject.get(), m_javaGlue->m_centerFitRect, x, y, width, height);
   3863     checkException(env);
   3864 }
   3865 
   3866 void WebViewCore::setScrollbarModes(ScrollbarMode horizontalMode, ScrollbarMode verticalMode)
   3867 {
   3868     JNIEnv* env = JSC::Bindings::getJNIEnv();
   3869     AutoJObject javaObject = m_javaGlue->object(env);
   3870     if (!javaObject.get())
   3871         return;
   3872     env->CallVoidMethod(javaObject.get(), m_javaGlue->m_setScrollbarModes, horizontalMode, verticalMode);
   3873     checkException(env);
   3874 }
   3875 
   3876 void WebViewCore::notifyWebAppCanBeInstalled()
   3877 {
   3878     JNIEnv* env = JSC::Bindings::getJNIEnv();
   3879     AutoJObject javaObject = m_javaGlue->object(env);
   3880     if (!javaObject.get())
   3881         return;
   3882     env->CallVoidMethod(javaObject.get(), m_javaGlue->m_setInstallableWebApp);
   3883     checkException(env);
   3884 }
   3885 
   3886 #if ENABLE(VIDEO)
   3887 void WebViewCore::enterFullscreenForVideoLayer(int layerId, const WTF::String& url)
   3888 {
   3889     JNIEnv* env = JSC::Bindings::getJNIEnv();
   3890     AutoJObject javaObject = m_javaGlue->object(env);
   3891     if (!javaObject.get())
   3892         return;
   3893     jstring jUrlStr = wtfStringToJstring(env, url);
   3894     env->CallVoidMethod(javaObject.get(), m_javaGlue->m_enterFullscreenForVideoLayer, layerId, jUrlStr);
   3895     checkException(env);
   3896 }
   3897 #endif
   3898 
   3899 void WebViewCore::setWebTextViewAutoFillable(int queryId, const string16& previewSummary)
   3900 {
   3901 #if ENABLE(WEB_AUTOFILL)
   3902     JNIEnv* env = JSC::Bindings::getJNIEnv();
   3903     AutoJObject javaObject = m_javaGlue->object(env);
   3904     if (!javaObject.get())
   3905         return;
   3906     jstring preview = env->NewString(previewSummary.data(), previewSummary.length());
   3907     env->CallVoidMethod(javaObject.get(), m_javaGlue->m_setWebTextViewAutoFillable, queryId, preview);
   3908     env->DeleteLocalRef(preview);
   3909 #endif
   3910 }
   3911 
   3912 bool WebViewCore::drawIsPaused() const
   3913 {
   3914     // returning true says scrollview should be offscreen, which pauses
   3915     // gifs. because this is not again queried when we stop scrolling, we don't
   3916     // use the stopping currently.
   3917     return false;
   3918 }
   3919 
   3920 #if USE(CHROME_NETWORK_STACK)
   3921 void WebViewCore::setWebRequestContextUserAgent()
   3922 {
   3923     // We cannot create a WebRequestContext, because we might not know it this is a private tab or not yet
   3924     if (m_webRequestContext)
   3925         m_webRequestContext->setUserAgent(WebFrame::getWebFrame(m_mainFrame)->userAgentForURL(0)); // URL not used
   3926 }
   3927 
   3928 void WebViewCore::setWebRequestContextCacheMode(int cacheMode)
   3929 {
   3930     m_cacheMode = cacheMode;
   3931     // We cannot create a WebRequestContext, because we might not know it this is a private tab or not yet
   3932     if (!m_webRequestContext)
   3933         return;
   3934 
   3935     m_webRequestContext->setCacheMode(cacheMode);
   3936 }
   3937 
   3938 WebRequestContext* WebViewCore::webRequestContext()
   3939 {
   3940     if (!m_webRequestContext) {
   3941         Settings* settings = mainFrame()->settings();
   3942         m_webRequestContext = new WebRequestContext(settings && settings->privateBrowsingEnabled());
   3943         setWebRequestContextUserAgent();
   3944         setWebRequestContextCacheMode(m_cacheMode);
   3945     }
   3946     return m_webRequestContext.get();
   3947 }
   3948 #endif
   3949 
   3950 void WebViewCore::scrollRenderLayer(int layer, const SkRect& rect)
   3951 {
   3952 #if USE(ACCELERATED_COMPOSITING)
   3953     GraphicsLayerAndroid* root = graphicsRootLayer();
   3954     if (!root)
   3955         return;
   3956 
   3957     LayerAndroid* layerAndroid = root->platformLayer();
   3958     if (!layerAndroid)
   3959         return;
   3960 
   3961     LayerAndroid* target = layerAndroid->findById(layer);
   3962     if (!target)
   3963         return;
   3964 
   3965     RenderLayer* owner = target->owningLayer();
   3966     if (!owner)
   3967         return;
   3968 
   3969     if (owner->stackingContext())
   3970         owner->scrollToOffset(rect.fLeft, rect.fTop);
   3971 #endif
   3972 }
   3973 
   3974 //----------------------------------------------------------------------
   3975 // Native JNI methods
   3976 //----------------------------------------------------------------------
   3977 static void RevealSelection(JNIEnv *env, jobject obj)
   3978 {
   3979     GET_NATIVE_VIEW(env, obj)->revealSelection();
   3980 }
   3981 
   3982 static jstring RequestLabel(JNIEnv *env, jobject obj, int framePointer,
   3983         int nodePointer)
   3984 {
   3985     return wtfStringToJstring(env, GET_NATIVE_VIEW(env, obj)->requestLabel(
   3986             (WebCore::Frame*) framePointer, (WebCore::Node*) nodePointer));
   3987 }
   3988 
   3989 static void ClearContent(JNIEnv *env, jobject obj)
   3990 {
   3991 #ifdef ANDROID_INSTRUMENT
   3992     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
   3993 #endif
   3994     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   3995     viewImpl->clearContent();
   3996 }
   3997 
   3998 static void UpdateFrameCacheIfLoading(JNIEnv *env, jobject obj)
   3999 {
   4000     GET_NATIVE_VIEW(env, obj)->updateFrameCacheIfLoading();
   4001 }
   4002 
   4003 static void SetSize(JNIEnv *env, jobject obj, jint width, jint height,
   4004         jint textWrapWidth, jfloat scale, jint screenWidth, jint screenHeight,
   4005         jint anchorX, jint anchorY, jboolean ignoreHeight)
   4006 {
   4007 #ifdef ANDROID_INSTRUMENT
   4008     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
   4009 #endif
   4010     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   4011     LOGV("webviewcore::nativeSetSize(%u %u)\n viewImpl: %p", (unsigned)width, (unsigned)height, viewImpl);
   4012     LOG_ASSERT(viewImpl, "viewImpl not set in nativeSetSize");
   4013     viewImpl->setSizeScreenWidthAndScale(width, height, textWrapWidth, scale,
   4014             screenWidth, screenHeight, anchorX, anchorY, ignoreHeight);
   4015 }
   4016 
   4017 static void SetScrollOffset(JNIEnv *env, jobject obj, jint gen, jboolean sendScrollEvent, jint x, jint y)
   4018 {
   4019 #ifdef ANDROID_INSTRUMENT
   4020     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
   4021 #endif
   4022     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   4023     LOG_ASSERT(viewImpl, "need viewImpl");
   4024 
   4025     viewImpl->setScrollOffset(gen, sendScrollEvent, x, y);
   4026 }
   4027 
   4028 static void SetGlobalBounds(JNIEnv *env, jobject obj, jint x, jint y, jint h,
   4029                             jint v)
   4030 {
   4031 #ifdef ANDROID_INSTRUMENT
   4032     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
   4033 #endif
   4034     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   4035     LOG_ASSERT(viewImpl, "need viewImpl");
   4036 
   4037     viewImpl->setGlobalBounds(x, y, h, v);
   4038 }
   4039 
   4040 static jboolean Key(JNIEnv *env, jobject obj, jint keyCode, jint unichar,
   4041         jint repeatCount, jboolean isShift, jboolean isAlt, jboolean isSym,
   4042         jboolean isDown)
   4043 {
   4044 #ifdef ANDROID_INSTRUMENT
   4045     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
   4046 #endif
   4047     return GET_NATIVE_VIEW(env, obj)->key(PlatformKeyboardEvent(keyCode,
   4048         unichar, repeatCount, isDown, isShift, isAlt, isSym));
   4049 }
   4050 
   4051 static void Click(JNIEnv *env, jobject obj, int framePtr, int nodePtr, jboolean fake)
   4052 {
   4053 #ifdef ANDROID_INSTRUMENT
   4054     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
   4055 #endif
   4056     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   4057     LOG_ASSERT(viewImpl, "viewImpl not set in Click");
   4058 
   4059     viewImpl->click(reinterpret_cast<WebCore::Frame*>(framePtr),
   4060         reinterpret_cast<WebCore::Node*>(nodePtr), fake);
   4061 }
   4062 
   4063 static void ContentInvalidateAll(JNIEnv *env, jobject obj)
   4064 {
   4065     GET_NATIVE_VIEW(env, obj)->contentInvalidateAll();
   4066 }
   4067 
   4068 static void DeleteSelection(JNIEnv *env, jobject obj, jint start, jint end,
   4069         jint textGeneration)
   4070 {
   4071 #ifdef ANDROID_INSTRUMENT
   4072     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
   4073 #endif
   4074     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   4075     viewImpl->deleteSelection(start, end, textGeneration);
   4076 }
   4077 
   4078 static void SetSelection(JNIEnv *env, jobject obj, jint start, jint end)
   4079 {
   4080 #ifdef ANDROID_INSTRUMENT
   4081     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
   4082 #endif
   4083     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   4084     viewImpl->setSelection(start, end);
   4085 }
   4086 
   4087 static jstring ModifySelection(JNIEnv *env, jobject obj, jint direction, jint granularity)
   4088 {
   4089 #ifdef ANDROID_INSTRUMENT
   4090     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
   4091 #endif
   4092     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   4093     String selectionString = viewImpl->modifySelection(direction, granularity);
   4094     return wtfStringToJstring(env, selectionString);
   4095 }
   4096 
   4097 static void ReplaceTextfieldText(JNIEnv *env, jobject obj,
   4098     jint oldStart, jint oldEnd, jstring replace, jint start, jint end,
   4099     jint textGeneration)
   4100 {
   4101 #ifdef ANDROID_INSTRUMENT
   4102     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
   4103 #endif
   4104     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   4105     WTF::String webcoreString = jstringToWtfString(env, replace);
   4106     viewImpl->replaceTextfieldText(oldStart,
   4107             oldEnd, webcoreString, start, end, textGeneration);
   4108 }
   4109 
   4110 static void PassToJs(JNIEnv *env, jobject obj,
   4111     jint generation, jstring currentText, jint keyCode,
   4112     jint keyValue, jboolean down, jboolean cap, jboolean fn, jboolean sym)
   4113 {
   4114 #ifdef ANDROID_INSTRUMENT
   4115     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
   4116 #endif
   4117     WTF::String current = jstringToWtfString(env, currentText);
   4118     GET_NATIVE_VIEW(env, obj)->passToJs(generation, current,
   4119         PlatformKeyboardEvent(keyCode, keyValue, 0, down, cap, fn, sym));
   4120 }
   4121 
   4122 static void ScrollFocusedTextInput(JNIEnv *env, jobject obj, jfloat xPercent,
   4123     jint y)
   4124 {
   4125 #ifdef ANDROID_INSTRUMENT
   4126     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
   4127 #endif
   4128     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   4129     viewImpl->scrollFocusedTextInput(xPercent, y);
   4130 }
   4131 
   4132 static void SetFocusControllerActive(JNIEnv *env, jobject obj, jboolean active)
   4133 {
   4134 #ifdef ANDROID_INSTRUMENT
   4135     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
   4136 #endif
   4137     LOGV("webviewcore::nativeSetFocusControllerActive()\n");
   4138     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   4139     LOG_ASSERT(viewImpl, "viewImpl not set in nativeSetFocusControllerActive");
   4140     viewImpl->setFocusControllerActive(active);
   4141 }
   4142 
   4143 static void SaveDocumentState(JNIEnv *env, jobject obj, jint frame)
   4144 {
   4145 #ifdef ANDROID_INSTRUMENT
   4146     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
   4147 #endif
   4148     LOGV("webviewcore::nativeSaveDocumentState()\n");
   4149     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   4150     LOG_ASSERT(viewImpl, "viewImpl not set in nativeSaveDocumentState");
   4151     viewImpl->saveDocumentState((WebCore::Frame*) frame);
   4152 }
   4153 
   4154 void WebViewCore::addVisitedLink(const UChar* string, int length)
   4155 {
   4156     if (m_groupForVisitedLinks)
   4157         m_groupForVisitedLinks->addVisitedLink(string, length);
   4158 }
   4159 
   4160 static bool UpdateLayers(JNIEnv *env, jobject obj, jint jbaseLayer)
   4161 {
   4162     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   4163     BaseLayerAndroid* baseLayer = (BaseLayerAndroid*)  jbaseLayer;
   4164     if (baseLayer) {
   4165         LayerAndroid* root = static_cast<LayerAndroid*>(baseLayer->getChild(0));
   4166         if (root)
   4167             return viewImpl->updateLayers(root);
   4168     }
   4169     return true;
   4170 }
   4171 
   4172 static jint RecordContent(JNIEnv *env, jobject obj, jobject region, jobject pt)
   4173 {
   4174 #ifdef ANDROID_INSTRUMENT
   4175     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
   4176 #endif
   4177     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   4178     SkRegion* nativeRegion = GraphicsJNI::getNativeRegion(env, region);
   4179     SkIPoint nativePt;
   4180     BaseLayerAndroid* result = viewImpl->recordContent(nativeRegion, &nativePt);
   4181     GraphicsJNI::ipoint_to_jpoint(nativePt, env, pt);
   4182     return reinterpret_cast<jint>(result);
   4183 }
   4184 
   4185 static void SplitContent(JNIEnv *env, jobject obj, jint content)
   4186 {
   4187 #ifdef ANDROID_INSTRUMENT
   4188     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
   4189 #endif
   4190     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   4191     viewImpl->splitContent(reinterpret_cast<PictureSet*>(content));
   4192 }
   4193 
   4194 static void SendListBoxChoice(JNIEnv* env, jobject obj, jint choice)
   4195 {
   4196 #ifdef ANDROID_INSTRUMENT
   4197     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
   4198 #endif
   4199     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   4200     LOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoice");
   4201     viewImpl->popupReply(choice);
   4202 }
   4203 
   4204 // Set aside a predetermined amount of space in which to place the listbox
   4205 // choices, to avoid unnecessary allocations.
   4206 // The size here is arbitrary.  We want the size to be at least as great as the
   4207 // number of items in the average multiple-select listbox.
   4208 #define PREPARED_LISTBOX_STORAGE 10
   4209 
   4210 static void SendListBoxChoices(JNIEnv* env, jobject obj, jbooleanArray jArray,
   4211         jint size)
   4212 {
   4213 #ifdef ANDROID_INSTRUMENT
   4214     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
   4215 #endif
   4216     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   4217     LOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoices");
   4218     jboolean* ptrArray = env->GetBooleanArrayElements(jArray, 0);
   4219     SkAutoSTMalloc<PREPARED_LISTBOX_STORAGE, int> storage(size);
   4220     int* array = storage.get();
   4221     int count = 0;
   4222     for (int i = 0; i < size; i++) {
   4223         if (ptrArray[i]) {
   4224             array[count++] = i;
   4225         }
   4226     }
   4227     env->ReleaseBooleanArrayElements(jArray, ptrArray, JNI_ABORT);
   4228     viewImpl->popupReply(array, count);
   4229 }
   4230 
   4231 static jstring FindAddress(JNIEnv *env, jobject obj, jstring addr,
   4232     jboolean caseInsensitive)
   4233 {
   4234 #ifdef ANDROID_INSTRUMENT
   4235     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
   4236 #endif
   4237     if (!addr)
   4238         return 0;
   4239     int length = env->GetStringLength(addr);
   4240     if (!length)
   4241         return 0;
   4242     const jchar* addrChars = env->GetStringChars(addr, 0);
   4243     int start, end;
   4244     bool success = CacheBuilder::FindAddress(addrChars, length,
   4245         &start, &end, caseInsensitive) == CacheBuilder::FOUND_COMPLETE;
   4246     jstring ret = 0;
   4247     if (success)
   4248         ret = env->NewString(addrChars + start, end - start);
   4249     env->ReleaseStringChars(addr, addrChars);
   4250     return ret;
   4251 }
   4252 
   4253 static jboolean HandleTouchEvent(JNIEnv *env, jobject obj, jint action, jintArray idArray,
   4254                                  jintArray xArray, jintArray yArray,
   4255                                  jint count, jint actionIndex, jint metaState)
   4256 {
   4257 #ifdef ANDROID_INSTRUMENT
   4258     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
   4259 #endif
   4260     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   4261     LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
   4262     jint* ptrIdArray = env->GetIntArrayElements(idArray, 0);
   4263     jint* ptrXArray = env->GetIntArrayElements(xArray, 0);
   4264     jint* ptrYArray = env->GetIntArrayElements(yArray, 0);
   4265     Vector<int> ids(count);
   4266     Vector<IntPoint> points(count);
   4267     for (int c = 0; c < count; c++) {
   4268         ids[c] = ptrIdArray[c];
   4269         points[c].setX(ptrXArray[c]);
   4270         points[c].setY(ptrYArray[c]);
   4271     }
   4272     env->ReleaseIntArrayElements(idArray, ptrIdArray, JNI_ABORT);
   4273     env->ReleaseIntArrayElements(xArray, ptrXArray, JNI_ABORT);
   4274     env->ReleaseIntArrayElements(yArray, ptrYArray, JNI_ABORT);
   4275 
   4276     return viewImpl->handleTouchEvent(action, ids, points, actionIndex, metaState);
   4277 }
   4278 
   4279 static void TouchUp(JNIEnv *env, jobject obj, jint touchGeneration,
   4280         jint frame, jint node, jint x, jint y)
   4281 {
   4282 #ifdef ANDROID_INSTRUMENT
   4283     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
   4284 #endif
   4285     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   4286     LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
   4287     viewImpl->touchUp(touchGeneration,
   4288         (WebCore::Frame*) frame, (WebCore::Node*) node, x, y);
   4289 }
   4290 
   4291 static jstring RetrieveHref(JNIEnv *env, jobject obj, jint x, jint y)
   4292 {
   4293 #ifdef ANDROID_INSTRUMENT
   4294     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
   4295 #endif
   4296     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   4297     LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
   4298     WTF::String result = viewImpl->retrieveHref(x, y);
   4299     if (!result.isEmpty())
   4300         return wtfStringToJstring(env, result);
   4301     return 0;
   4302 }
   4303 
   4304 static jstring RetrieveAnchorText(JNIEnv *env, jobject obj, jint x, jint y)
   4305 {
   4306 #ifdef ANDROID_INSTRUMENT
   4307     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
   4308 #endif
   4309     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   4310     LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
   4311     WTF::String result = viewImpl->retrieveAnchorText(x, y);
   4312     if (!result.isEmpty())
   4313         return wtfStringToJstring(env, result);
   4314     return 0;
   4315 }
   4316 
   4317 static jstring RetrieveImageSource(JNIEnv *env, jobject obj, jint x, jint y)
   4318 {
   4319     WTF::String result = GET_NATIVE_VIEW(env, obj)->retrieveImageSource(x, y);
   4320     return !result.isEmpty() ? wtfStringToJstring(env, result) : 0;
   4321 }
   4322 
   4323 static void StopPaintingCaret(JNIEnv *env, jobject obj)
   4324 {
   4325     GET_NATIVE_VIEW(env, obj)->setShouldPaintCaret(false);
   4326 }
   4327 
   4328 static void MoveFocus(JNIEnv *env, jobject obj, jint framePtr, jint nodePtr)
   4329 {
   4330 #ifdef ANDROID_INSTRUMENT
   4331     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
   4332 #endif
   4333     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   4334     LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
   4335     viewImpl->moveFocus((WebCore::Frame*) framePtr, (WebCore::Node*) nodePtr);
   4336 }
   4337 
   4338 static void MoveMouse(JNIEnv *env, jobject obj, jint frame,
   4339         jint x, jint y)
   4340 {
   4341 #ifdef ANDROID_INSTRUMENT
   4342     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
   4343 #endif
   4344     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   4345     LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
   4346     viewImpl->moveMouse((WebCore::Frame*) frame, x, y);
   4347 }
   4348 
   4349 static void MoveMouseIfLatest(JNIEnv *env, jobject obj, jint moveGeneration,
   4350         jint frame, jint x, jint y)
   4351 {
   4352 #ifdef ANDROID_INSTRUMENT
   4353     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
   4354 #endif
   4355     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   4356     LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
   4357     viewImpl->moveMouseIfLatest(moveGeneration,
   4358         (WebCore::Frame*) frame, x, y);
   4359 }
   4360 
   4361 static void UpdateFrameCache(JNIEnv *env, jobject obj)
   4362 {
   4363 #ifdef ANDROID_INSTRUMENT
   4364     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
   4365 #endif
   4366     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   4367     LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
   4368     viewImpl->updateFrameCache();
   4369 }
   4370 
   4371 static jint GetContentMinPrefWidth(JNIEnv *env, jobject obj)
   4372 {
   4373 #ifdef ANDROID_INSTRUMENT
   4374     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
   4375 #endif
   4376     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   4377     LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
   4378 
   4379     WebCore::Frame* frame = viewImpl->mainFrame();
   4380     if (frame) {
   4381         WebCore::Document* document = frame->document();
   4382         if (document) {
   4383             WebCore::RenderObject* renderer = document->renderer();
   4384             if (renderer && renderer->isRenderView()) {
   4385                 return renderer->minPreferredLogicalWidth();
   4386             }
   4387         }
   4388     }
   4389     return 0;
   4390 }
   4391 
   4392 static void SetViewportSettingsFromNative(JNIEnv *env, jobject obj)
   4393 {
   4394 #ifdef ANDROID_INSTRUMENT
   4395     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
   4396 #endif
   4397     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   4398     LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
   4399 
   4400     WebCore::Settings* s = viewImpl->mainFrame()->page()->settings();
   4401     if (!s)
   4402         return;
   4403 
   4404 #ifdef ANDROID_META_SUPPORT
   4405     env->SetIntField(obj, gWebViewCoreFields.m_viewportWidth, s->viewportWidth());
   4406     env->SetIntField(obj, gWebViewCoreFields.m_viewportHeight, s->viewportHeight());
   4407     env->SetIntField(obj, gWebViewCoreFields.m_viewportInitialScale, s->viewportInitialScale());
   4408     env->SetIntField(obj, gWebViewCoreFields.m_viewportMinimumScale, s->viewportMinimumScale());
   4409     env->SetIntField(obj, gWebViewCoreFields.m_viewportMaximumScale, s->viewportMaximumScale());
   4410     env->SetBooleanField(obj, gWebViewCoreFields.m_viewportUserScalable, s->viewportUserScalable());
   4411     env->SetIntField(obj, gWebViewCoreFields.m_viewportDensityDpi, s->viewportTargetDensityDpi());
   4412 #endif
   4413 }
   4414 
   4415 static void SetBackgroundColor(JNIEnv *env, jobject obj, jint color)
   4416 {
   4417 #ifdef ANDROID_INSTRUMENT
   4418     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
   4419 #endif
   4420     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   4421     LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
   4422 
   4423     viewImpl->setBackgroundColor((SkColor) color);
   4424 }
   4425 
   4426 static void DumpDomTree(JNIEnv *env, jobject obj, jboolean useFile)
   4427 {
   4428     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   4429     LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
   4430 
   4431     viewImpl->dumpDomTree(useFile);
   4432 }
   4433 
   4434 static void DumpRenderTree(JNIEnv *env, jobject obj, jboolean useFile)
   4435 {
   4436     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   4437     LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
   4438 
   4439     viewImpl->dumpRenderTree(useFile);
   4440 }
   4441 
   4442 static void DumpNavTree(JNIEnv *env, jobject obj)
   4443 {
   4444     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   4445     LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
   4446 
   4447     viewImpl->dumpNavTree();
   4448 }
   4449 
   4450 static void DumpV8Counters(JNIEnv*, jobject)
   4451 {
   4452 #if USE(V8)
   4453 #ifdef ANDROID_INSTRUMENT
   4454     V8Counters::dumpCounters();
   4455 #endif
   4456 #endif
   4457 }
   4458 
   4459 static void SetJsFlags(JNIEnv *env, jobject obj, jstring flags)
   4460 {
   4461 #if USE(V8)
   4462     WTF::String flagsString = jstringToWtfString(env, flags);
   4463     WTF::CString utf8String = flagsString.utf8();
   4464     WebCore::ScriptController::setFlags(utf8String.data(), utf8String.length());
   4465 #endif
   4466 }
   4467 
   4468 
   4469 // Called from the Java side to set a new quota for the origin or new appcache
   4470 // max size in response to a notification that the original quota was exceeded or
   4471 // that the appcache has reached its maximum size.
   4472 static void SetNewStorageLimit(JNIEnv* env, jobject obj, jlong quota) {
   4473 #if ENABLE(DATABASE) || ENABLE(OFFLINE_WEB_APPLICATIONS)
   4474     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   4475     Frame* frame = viewImpl->mainFrame();
   4476 
   4477     // The main thread is blocked awaiting this response, so now we can wake it
   4478     // up.
   4479     ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(frame->page()->chrome()->client());
   4480     chromeC->wakeUpMainThreadWithNewQuota(quota);
   4481 #endif
   4482 }
   4483 
   4484 // Called from Java to provide a Geolocation permission state for the specified origin.
   4485 static void GeolocationPermissionsProvide(JNIEnv* env, jobject obj, jstring origin, jboolean allow, jboolean remember) {
   4486     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   4487     Frame* frame = viewImpl->mainFrame();
   4488 
   4489     ChromeClientAndroid* chromeClient = static_cast<ChromeClientAndroid*>(frame->page()->chrome()->client());
   4490     chromeClient->provideGeolocationPermissions(jstringToWtfString(env, origin), allow, remember);
   4491 }
   4492 
   4493 static void RegisterURLSchemeAsLocal(JNIEnv* env, jobject obj, jstring scheme) {
   4494 #ifdef ANDROID_INSTRUMENT
   4495     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
   4496 #endif
   4497     WebCore::SchemeRegistry::registerURLSchemeAsLocal(jstringToWtfString(env, scheme));
   4498 }
   4499 
   4500 static bool FocusBoundsChanged(JNIEnv* env, jobject obj)
   4501 {
   4502     return GET_NATIVE_VIEW(env, obj)->focusBoundsChanged();
   4503 }
   4504 
   4505 static void SetIsPaused(JNIEnv* env, jobject obj, jboolean isPaused)
   4506 {
   4507     // tell the webcore thread to stop thinking while we do other work
   4508     // (selection and scrolling). This has nothing to do with the lifecycle
   4509     // pause and resume.
   4510     GET_NATIVE_VIEW(env, obj)->setIsPaused(isPaused);
   4511 }
   4512 
   4513 static void Pause(JNIEnv* env, jobject obj)
   4514 {
   4515     // This is called for the foreground tab when the browser is put to the
   4516     // background (and also for any tab when it is put to the background of the
   4517     // browser). The browser can only be killed by the system when it is in the
   4518     // background, so saving the Geolocation permission state now ensures that
   4519     // is maintained when the browser is killed.
   4520     ChromeClient* chromeClient = GET_NATIVE_VIEW(env, obj)->mainFrame()->page()->chrome()->client();
   4521     ChromeClientAndroid* chromeClientAndroid = static_cast<ChromeClientAndroid*>(chromeClient);
   4522     chromeClientAndroid->storeGeolocationPermissions();
   4523 
   4524     Frame* mainFrame = GET_NATIVE_VIEW(env, obj)->mainFrame();
   4525     for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext()) {
   4526         Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation();
   4527         if (geolocation)
   4528             geolocation->suspend();
   4529     }
   4530 
   4531     GET_NATIVE_VIEW(env, obj)->deviceMotionAndOrientationManager()->maybeSuspendClients();
   4532 
   4533     ANPEvent event;
   4534     SkANP::InitEvent(&event, kLifecycle_ANPEventType);
   4535     event.data.lifecycle.action = kPause_ANPLifecycleAction;
   4536     GET_NATIVE_VIEW(env, obj)->sendPluginEvent(event);
   4537 
   4538     GET_NATIVE_VIEW(env, obj)->setIsPaused(true);
   4539 }
   4540 
   4541 static void Resume(JNIEnv* env, jobject obj)
   4542 {
   4543     Frame* mainFrame = GET_NATIVE_VIEW(env, obj)->mainFrame();
   4544     for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext()) {
   4545         Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation();
   4546         if (geolocation)
   4547             geolocation->resume();
   4548     }
   4549 
   4550     GET_NATIVE_VIEW(env, obj)->deviceMotionAndOrientationManager()->maybeResumeClients();
   4551 
   4552     ANPEvent event;
   4553     SkANP::InitEvent(&event, kLifecycle_ANPEventType);
   4554     event.data.lifecycle.action = kResume_ANPLifecycleAction;
   4555     GET_NATIVE_VIEW(env, obj)->sendPluginEvent(event);
   4556 
   4557     GET_NATIVE_VIEW(env, obj)->setIsPaused(false);
   4558 }
   4559 
   4560 static void FreeMemory(JNIEnv* env, jobject obj)
   4561 {
   4562     ANPEvent event;
   4563     SkANP::InitEvent(&event, kLifecycle_ANPEventType);
   4564     event.data.lifecycle.action = kFreeMemory_ANPLifecycleAction;
   4565     GET_NATIVE_VIEW(env, obj)->sendPluginEvent(event);
   4566 }
   4567 
   4568 static void ProvideVisitedHistory(JNIEnv *env, jobject obj, jobject hist)
   4569 {
   4570     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   4571     LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
   4572 
   4573     jobjectArray array = static_cast<jobjectArray>(hist);
   4574 
   4575     jsize len = env->GetArrayLength(array);
   4576     for (jsize i = 0; i < len; i++) {
   4577         jstring item = static_cast<jstring>(env->GetObjectArrayElement(array, i));
   4578         const UChar* str = static_cast<const UChar*>(env->GetStringChars(item, 0));
   4579         jsize len = env->GetStringLength(item);
   4580         viewImpl->addVisitedLink(str, len);
   4581         env->ReleaseStringChars(item, str);
   4582         env->DeleteLocalRef(item);
   4583     }
   4584 }
   4585 
   4586 static void PluginSurfaceReady(JNIEnv* env, jobject obj)
   4587 {
   4588     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   4589     if (viewImpl)
   4590         viewImpl->sendPluginSurfaceReady();
   4591 }
   4592 
   4593 // Notification from the UI thread that the plugin's full-screen surface has been discarded
   4594 static void FullScreenPluginHidden(JNIEnv* env, jobject obj, jint npp)
   4595 {
   4596     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   4597     PluginWidgetAndroid* plugin = viewImpl->getPluginWidget((NPP)npp);
   4598     if (plugin)
   4599         plugin->exitFullScreen(false);
   4600 }
   4601 
   4602 static WebCore::IntRect jrect_to_webrect(JNIEnv* env, jobject obj)
   4603 {
   4604     int L, T, R, B;
   4605     GraphicsJNI::get_jrect(env, obj, &L, &T, &R, &B);
   4606     return WebCore::IntRect(L, T, R - L, B - T);
   4607 }
   4608 
   4609 static bool ValidNodeAndBounds(JNIEnv *env, jobject obj, int frame, int node,
   4610     jobject rect)
   4611 {
   4612     IntRect nativeRect = jrect_to_webrect(env, rect);
   4613     return GET_NATIVE_VIEW(env, obj)->validNodeAndBounds(
   4614             reinterpret_cast<Frame*>(frame),
   4615             reinterpret_cast<Node*>(node), nativeRect);
   4616 }
   4617 
   4618 static jobject GetTouchHighlightRects(JNIEnv* env, jobject obj, jint x, jint y, jint slop)
   4619 {
   4620     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   4621     if (!viewImpl)
   4622         return 0;
   4623     Vector<IntRect> rects = viewImpl->getTouchHighlightRects(x, y, slop);
   4624     if (rects.isEmpty())
   4625         return 0;
   4626 
   4627     jclass arrayClass = env->FindClass("java/util/ArrayList");
   4628     LOG_ASSERT(arrayClass, "Could not find java/util/ArrayList");
   4629     jmethodID init = env->GetMethodID(arrayClass, "<init>", "(I)V");
   4630     LOG_ASSERT(init, "Could not find constructor for ArrayList");
   4631     jobject array = env->NewObject(arrayClass, init, rects.size());
   4632     LOG_ASSERT(array, "Could not create a new ArrayList");
   4633     jmethodID add = env->GetMethodID(arrayClass, "add", "(Ljava/lang/Object;)Z");
   4634     LOG_ASSERT(add, "Could not find add method on ArrayList");
   4635     jclass rectClass = env->FindClass("android/graphics/Rect");
   4636     LOG_ASSERT(rectClass, "Could not find android/graphics/Rect");
   4637     jmethodID rectinit = env->GetMethodID(rectClass, "<init>", "(IIII)V");
   4638     LOG_ASSERT(rectinit, "Could not find init method on Rect");
   4639 
   4640     for (size_t i = 0; i < rects.size(); i++) {
   4641         jobject rect = env->NewObject(rectClass, rectinit, rects[i].x(),
   4642                 rects[i].y(), rects[i].maxX(), rects[i].maxY());
   4643         if (rect) {
   4644             env->CallBooleanMethod(array, add, rect);
   4645             env->DeleteLocalRef(rect);
   4646         }
   4647     }
   4648 
   4649     env->DeleteLocalRef(rectClass);
   4650     env->DeleteLocalRef(arrayClass);
   4651     return array;
   4652 }
   4653 
   4654 static void AutoFillForm(JNIEnv* env, jobject obj, jint queryId)
   4655 {
   4656 #if ENABLE(WEB_AUTOFILL)
   4657     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   4658     if (!viewImpl)
   4659         return;
   4660 
   4661     WebCore::Frame* frame = viewImpl->mainFrame();
   4662     if (frame) {
   4663         EditorClientAndroid* editorC = static_cast<EditorClientAndroid*>(frame->page()->editorClient());
   4664         WebAutofill* autoFill = editorC->getAutofill();
   4665         autoFill->fillFormFields(queryId);
   4666     }
   4667 #endif
   4668 }
   4669 
   4670 static void CloseIdleConnections(JNIEnv* env, jobject obj)
   4671 {
   4672 #if USE(CHROME_NETWORK_STACK)
   4673     WebCache::get(true)->closeIdleConnections();
   4674     WebCache::get(false)->closeIdleConnections();
   4675 #endif
   4676 }
   4677 
   4678 static void ScrollRenderLayer(JNIEnv* env, jobject obj, jint layer, jobject jRect)
   4679 {
   4680     SkRect rect;
   4681     GraphicsJNI::jrect_to_rect(env, jRect, &rect);
   4682     GET_NATIVE_VIEW(env, obj)->scrollRenderLayer(layer, rect);
   4683 }
   4684 
   4685 // ----------------------------------------------------------------------------
   4686 
   4687 /*
   4688  * JNI registration.
   4689  */
   4690 static JNINativeMethod gJavaWebViewCoreMethods[] = {
   4691     { "nativeClearContent", "()V",
   4692             (void*) ClearContent },
   4693     { "nativeFocusBoundsChanged", "()Z",
   4694         (void*) FocusBoundsChanged } ,
   4695     { "nativeKey", "(IIIZZZZ)Z",
   4696         (void*) Key },
   4697     { "nativeClick", "(IIZ)V",
   4698         (void*) Click },
   4699     { "nativeContentInvalidateAll", "()V",
   4700         (void*) ContentInvalidateAll },
   4701     { "nativeSendListBoxChoices", "([ZI)V",
   4702         (void*) SendListBoxChoices },
   4703     { "nativeSendListBoxChoice", "(I)V",
   4704         (void*) SendListBoxChoice },
   4705     { "nativeSetSize", "(IIIFIIIIZ)V",
   4706         (void*) SetSize },
   4707     { "nativeSetScrollOffset", "(IZII)V",
   4708         (void*) SetScrollOffset },
   4709     { "nativeSetGlobalBounds", "(IIII)V",
   4710         (void*) SetGlobalBounds },
   4711     { "nativeSetSelection", "(II)V",
   4712         (void*) SetSelection } ,
   4713     { "nativeModifySelection", "(II)Ljava/lang/String;",
   4714         (void*) ModifySelection },
   4715     { "nativeDeleteSelection", "(III)V",
   4716         (void*) DeleteSelection } ,
   4717     { "nativeReplaceTextfieldText", "(IILjava/lang/String;III)V",
   4718         (void*) ReplaceTextfieldText } ,
   4719     { "nativeMoveFocus", "(II)V",
   4720         (void*) MoveFocus },
   4721     { "nativeMoveMouse", "(III)V",
   4722         (void*) MoveMouse },
   4723     { "nativeMoveMouseIfLatest", "(IIII)V",
   4724         (void*) MoveMouseIfLatest },
   4725     { "passToJs", "(ILjava/lang/String;IIZZZZ)V",
   4726         (void*) PassToJs },
   4727     { "nativeScrollFocusedTextInput", "(FI)V",
   4728         (void*) ScrollFocusedTextInput },
   4729     { "nativeSetFocusControllerActive", "(Z)V",
   4730         (void*) SetFocusControllerActive },
   4731     { "nativeSaveDocumentState", "(I)V",
   4732         (void*) SaveDocumentState },
   4733     { "nativeFindAddress", "(Ljava/lang/String;Z)Ljava/lang/String;",
   4734         (void*) FindAddress },
   4735     { "nativeHandleTouchEvent", "(I[I[I[IIII)Z",
   4736             (void*) HandleTouchEvent },
   4737     { "nativeTouchUp", "(IIIII)V",
   4738         (void*) TouchUp },
   4739     { "nativeRetrieveHref", "(II)Ljava/lang/String;",
   4740         (void*) RetrieveHref },
   4741     { "nativeRetrieveAnchorText", "(II)Ljava/lang/String;",
   4742         (void*) RetrieveAnchorText },
   4743     { "nativeRetrieveImageSource", "(II)Ljava/lang/String;",
   4744         (void*) RetrieveImageSource },
   4745     { "nativeStopPaintingCaret", "()V",
   4746         (void*) StopPaintingCaret },
   4747     { "nativeUpdateFrameCache", "()V",
   4748         (void*) UpdateFrameCache },
   4749     { "nativeGetContentMinPrefWidth", "()I",
   4750         (void*) GetContentMinPrefWidth },
   4751     { "nativeUpdateLayers", "(I)Z",
   4752         (void*) UpdateLayers },
   4753     { "nativeRecordContent", "(Landroid/graphics/Region;Landroid/graphics/Point;)I",
   4754         (void*) RecordContent },
   4755     { "setViewportSettingsFromNative", "()V",
   4756         (void*) SetViewportSettingsFromNative },
   4757     { "nativeSplitContent", "(I)V",
   4758         (void*) SplitContent },
   4759     { "nativeSetBackgroundColor", "(I)V",
   4760         (void*) SetBackgroundColor },
   4761     { "nativeRegisterURLSchemeAsLocal", "(Ljava/lang/String;)V",
   4762         (void*) RegisterURLSchemeAsLocal },
   4763     { "nativeDumpDomTree", "(Z)V",
   4764         (void*) DumpDomTree },
   4765     { "nativeDumpRenderTree", "(Z)V",
   4766         (void*) DumpRenderTree },
   4767     { "nativeDumpNavTree", "()V",
   4768         (void*) DumpNavTree },
   4769     { "nativeDumpV8Counters", "()V",
   4770         (void*) DumpV8Counters },
   4771     { "nativeSetNewStorageLimit", "(J)V",
   4772         (void*) SetNewStorageLimit },
   4773     { "nativeGeolocationPermissionsProvide", "(Ljava/lang/String;ZZ)V",
   4774         (void*) GeolocationPermissionsProvide },
   4775     { "nativeSetIsPaused", "(Z)V", (void*) SetIsPaused },
   4776     { "nativePause", "()V", (void*) Pause },
   4777     { "nativeResume", "()V", (void*) Resume },
   4778     { "nativeFreeMemory", "()V", (void*) FreeMemory },
   4779     { "nativeSetJsFlags", "(Ljava/lang/String;)V", (void*) SetJsFlags },
   4780     { "nativeRequestLabel", "(II)Ljava/lang/String;",
   4781         (void*) RequestLabel },
   4782     { "nativeRevealSelection", "()V", (void*) RevealSelection },
   4783     { "nativeUpdateFrameCacheIfLoading", "()V",
   4784         (void*) UpdateFrameCacheIfLoading },
   4785     { "nativeProvideVisitedHistory", "([Ljava/lang/String;)V",
   4786         (void*) ProvideVisitedHistory },
   4787     { "nativeFullScreenPluginHidden", "(I)V",
   4788         (void*) FullScreenPluginHidden },
   4789     { "nativePluginSurfaceReady", "()V",
   4790         (void*) PluginSurfaceReady },
   4791     { "nativeValidNodeAndBounds", "(IILandroid/graphics/Rect;)Z",
   4792         (void*) ValidNodeAndBounds },
   4793     { "nativeGetTouchHighlightRects", "(III)Ljava/util/ArrayList;",
   4794         (void*) GetTouchHighlightRects },
   4795     { "nativeAutoFillForm", "(I)V",
   4796         (void*) AutoFillForm },
   4797     { "nativeScrollLayer", "(ILandroid/graphics/Rect;)V",
   4798         (void*) ScrollRenderLayer },
   4799     { "nativeCloseIdleConnections", "()V",
   4800         (void*) CloseIdleConnections },
   4801 };
   4802 
   4803 int registerWebViewCore(JNIEnv* env)
   4804 {
   4805     jclass widget = env->FindClass("android/webkit/WebViewCore");
   4806     LOG_ASSERT(widget,
   4807             "Unable to find class android/webkit/WebViewCore");
   4808     gWebViewCoreFields.m_nativeClass = env->GetFieldID(widget, "mNativeClass",
   4809             "I");
   4810     LOG_ASSERT(gWebViewCoreFields.m_nativeClass,
   4811             "Unable to find android/webkit/WebViewCore.mNativeClass");
   4812     gWebViewCoreFields.m_viewportWidth = env->GetFieldID(widget,
   4813             "mViewportWidth", "I");
   4814     LOG_ASSERT(gWebViewCoreFields.m_viewportWidth,
   4815             "Unable to find android/webkit/WebViewCore.mViewportWidth");
   4816     gWebViewCoreFields.m_viewportHeight = env->GetFieldID(widget,
   4817             "mViewportHeight", "I");
   4818     LOG_ASSERT(gWebViewCoreFields.m_viewportHeight,
   4819             "Unable to find android/webkit/WebViewCore.mViewportHeight");
   4820     gWebViewCoreFields.m_viewportInitialScale = env->GetFieldID(widget,
   4821             "mViewportInitialScale", "I");
   4822     LOG_ASSERT(gWebViewCoreFields.m_viewportInitialScale,
   4823             "Unable to find android/webkit/WebViewCore.mViewportInitialScale");
   4824     gWebViewCoreFields.m_viewportMinimumScale = env->GetFieldID(widget,
   4825             "mViewportMinimumScale", "I");
   4826     LOG_ASSERT(gWebViewCoreFields.m_viewportMinimumScale,
   4827             "Unable to find android/webkit/WebViewCore.mViewportMinimumScale");
   4828     gWebViewCoreFields.m_viewportMaximumScale = env->GetFieldID(widget,
   4829             "mViewportMaximumScale", "I");
   4830     LOG_ASSERT(gWebViewCoreFields.m_viewportMaximumScale,
   4831             "Unable to find android/webkit/WebViewCore.mViewportMaximumScale");
   4832     gWebViewCoreFields.m_viewportUserScalable = env->GetFieldID(widget,
   4833             "mViewportUserScalable", "Z");
   4834     LOG_ASSERT(gWebViewCoreFields.m_viewportUserScalable,
   4835             "Unable to find android/webkit/WebViewCore.mViewportUserScalable");
   4836     gWebViewCoreFields.m_viewportDensityDpi = env->GetFieldID(widget,
   4837             "mViewportDensityDpi", "I");
   4838     LOG_ASSERT(gWebViewCoreFields.m_viewportDensityDpi,
   4839             "Unable to find android/webkit/WebViewCore.mViewportDensityDpi");
   4840     gWebViewCoreFields.m_webView = env->GetFieldID(widget,
   4841             "mWebView", "Landroid/webkit/WebView;");
   4842     LOG_ASSERT(gWebViewCoreFields.m_webView,
   4843             "Unable to find android/webkit/WebViewCore.mWebView");
   4844     gWebViewCoreFields.m_drawIsPaused = env->GetFieldID(widget,
   4845             "mDrawIsPaused", "Z");
   4846     LOG_ASSERT(gWebViewCoreFields.m_drawIsPaused,
   4847             "Unable to find android/webkit/WebViewCore.mDrawIsPaused");
   4848     gWebViewCoreFields.m_lowMemoryUsageMb = env->GetFieldID(widget, "mLowMemoryUsageThresholdMb", "I");
   4849     gWebViewCoreFields.m_highMemoryUsageMb = env->GetFieldID(widget, "mHighMemoryUsageThresholdMb", "I");
   4850     gWebViewCoreFields.m_highUsageDeltaMb = env->GetFieldID(widget, "mHighUsageDeltaMb", "I");
   4851 
   4852     gWebViewCoreStaticMethods.m_isSupportedMediaMimeType =
   4853         env->GetStaticMethodID(widget, "isSupportedMediaMimeType", "(Ljava/lang/String;)Z");
   4854     LOG_FATAL_IF(!gWebViewCoreStaticMethods.m_isSupportedMediaMimeType,
   4855         "Could not find static method isSupportedMediaMimeType from WebViewCore");
   4856 
   4857     env->DeleteLocalRef(widget);
   4858 
   4859     return jniRegisterNativeMethods(env, "android/webkit/WebViewCore",
   4860             gJavaWebViewCoreMethods, NELEM(gJavaWebViewCoreMethods));
   4861 }
   4862 
   4863 } /* namespace android */
   4864