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