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