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