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