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 "AtomicString.h"
     32 #include "CachedNode.h"
     33 #include "CachedRoot.h"
     34 #include "Chrome.h"
     35 #include "ChromeClientAndroid.h"
     36 #include "Color.h"
     37 #include "DatabaseTracker.h"
     38 #include "Document.h"
     39 #include "DOMWindow.h"
     40 #include "Element.h"
     41 #include "Editor.h"
     42 #include "EditorClientAndroid.h"
     43 #include "EventHandler.h"
     44 #include "EventNames.h"
     45 #include "FocusController.h"
     46 #include "Font.h"
     47 #include "Frame.h"
     48 #include "FrameLoader.h"
     49 #include "FrameLoaderClientAndroid.h"
     50 #include "FrameTree.h"
     51 #include "FrameView.h"
     52 #include "Geolocation.h"
     53 #include "GraphicsContext.h"
     54 #include "GraphicsJNI.h"
     55 #include "HTMLAnchorElement.h"
     56 #include "HTMLAreaElement.h"
     57 #include "HTMLElement.h"
     58 #include "HTMLImageElement.h"
     59 #include "HTMLInputElement.h"
     60 #include "HTMLLabelElement.h"
     61 #include "HTMLMapElement.h"
     62 #include "HTMLNames.h"
     63 #include "HTMLOptGroupElement.h"
     64 #include "HTMLOptionElement.h"
     65 #include "HTMLSelectElement.h"
     66 #include "HTMLTextAreaElement.h"
     67 #include "HistoryItem.h"
     68 #include "HitTestResult.h"
     69 #include "InlineTextBox.h"
     70 #include "KeyboardCodes.h"
     71 #include "Navigator.h"
     72 #include "Node.h"
     73 #include "NodeList.h"
     74 #include "Page.h"
     75 #include "PageGroup.h"
     76 #include "PlatformKeyboardEvent.h"
     77 #include "PlatformString.h"
     78 #include "PluginWidgetAndroid.h"
     79 #include "PluginView.h"
     80 #include "Position.h"
     81 #include "ProgressTracker.h"
     82 #include "RenderBox.h"
     83 #include "RenderLayer.h"
     84 #include "RenderPart.h"
     85 #include "RenderText.h"
     86 #include "RenderTextControl.h"
     87 #include "RenderThemeAndroid.h"
     88 #include "RenderView.h"
     89 #include "ResourceRequest.h"
     90 #include "SelectionController.h"
     91 #include "Settings.h"
     92 #include "SkANP.h"
     93 #include "SkTemplates.h"
     94 #include "SkTDArray.h"
     95 #include "SkTypes.h"
     96 #include "SkCanvas.h"
     97 #include "SkPicture.h"
     98 #include "SkUtils.h"
     99 #include "StringImpl.h"
    100 #include "Text.h"
    101 #include "TypingCommand.h"
    102 #include "WebCoreFrameBridge.h"
    103 #include "WebFrameView.h"
    104 #include "android_graphics.h"
    105 
    106 #include <JNIHelp.h>
    107 #include <JNIUtility.h>
    108 #include <ui/KeycodeLabels.h>
    109 #include <wtf/CurrentTime.h>
    110 
    111 #if USE(V8)
    112 #include "CString.h"
    113 #include "ScriptController.h"
    114 #include "V8Counters.h"
    115 #endif
    116 
    117 #if DEBUG_NAV_UI
    118 #include "SkTime.h"
    119 #endif
    120 
    121 #if ENABLE(TOUCH_EVENTS) // Android
    122 #include "PlatformTouchEvent.h"
    123 #endif
    124 
    125 #ifdef ANDROID_DOM_LOGGING
    126 #include "AndroidLog.h"
    127 #include "RenderTreeAsText.h"
    128 #include "CString.h"
    129 
    130 FILE* gDomTreeFile = 0;
    131 FILE* gRenderTreeFile = 0;
    132 #endif
    133 
    134 #ifdef ANDROID_INSTRUMENT
    135 #include "TimeCounter.h"
    136 #endif
    137 
    138 #if USE(ACCELERATED_COMPOSITING)
    139 #include "GraphicsLayerAndroid.h"
    140 #include "RenderLayerCompositor.h"
    141 #endif
    142 
    143 /*  We pass this flag when recording the actual content, so that we don't spend
    144     time actually regionizing complex path clips, when all we really want to do
    145     is record them.
    146  */
    147 #define PICT_RECORD_FLAGS   SkPicture::kUsePathBoundsForClip_RecordingFlag
    148 
    149 ////////////////////////////////////////////////////////////////////////////////////////////////
    150 
    151 namespace android {
    152 
    153 static SkTDArray<WebViewCore*> gInstanceList;
    154 
    155 void WebViewCore::addInstance(WebViewCore* inst) {
    156     *gInstanceList.append() = inst;
    157 }
    158 
    159 void WebViewCore::removeInstance(WebViewCore* inst) {
    160     int index = gInstanceList.find(inst);
    161     LOG_ASSERT(index >= 0, "RemoveInstance inst not found");
    162     if (index >= 0) {
    163         gInstanceList.removeShuffle(index);
    164     }
    165 }
    166 
    167 bool WebViewCore::isInstance(WebViewCore* inst) {
    168     return gInstanceList.find(inst) >= 0;
    169 }
    170 
    171 jobject WebViewCore::getApplicationContext() {
    172 
    173     // check to see if there is a valid webviewcore object
    174     if (gInstanceList.isEmpty())
    175         return 0;
    176 
    177     // get the context from the webview
    178     jobject context = gInstanceList[0]->getContext();
    179 
    180     if (!context)
    181         return 0;
    182 
    183     // get the application context using JNI
    184     JNIEnv* env = JSC::Bindings::getJNIEnv();
    185     jclass contextClass = env->GetObjectClass(context);
    186     jmethodID appContextMethod = env->GetMethodID(contextClass, "getApplicationContext", "()Landroid/content/Context;");
    187     jobject result = env->CallObjectMethod(context, appContextMethod);
    188     checkException(env);
    189     return result;
    190 }
    191 
    192 
    193 struct WebViewCoreStaticMethods {
    194     jmethodID    m_supportsMimeType;
    195 } gWebViewCoreStaticMethods;
    196 
    197 // Check whether a media mimeType is supported in Android media framework.
    198 bool WebViewCore::supportsMimeType(const WebCore::String& mimeType) {
    199     JNIEnv* env = JSC::Bindings::getJNIEnv();
    200     jstring jMimeType = env->NewString(mimeType.characters(), mimeType.length());
    201     jclass webViewCore = env->FindClass("android/webkit/WebViewCore");
    202     bool val = env->CallStaticBooleanMethod(webViewCore,
    203           gWebViewCoreStaticMethods.m_supportsMimeType, jMimeType);
    204     checkException(env);
    205     env->DeleteLocalRef(jMimeType);
    206 
    207     return val;
    208 }
    209 
    210 // ----------------------------------------------------------------------------
    211 
    212 #define GET_NATIVE_VIEW(env, obj) ((WebViewCore*)env->GetIntField(obj, gWebViewCoreFields.m_nativeClass))
    213 
    214 // Field ids for WebViewCore
    215 struct WebViewCoreFields {
    216     jfieldID    m_nativeClass;
    217     jfieldID    m_viewportWidth;
    218     jfieldID    m_viewportHeight;
    219     jfieldID    m_viewportInitialScale;
    220     jfieldID    m_viewportMinimumScale;
    221     jfieldID    m_viewportMaximumScale;
    222     jfieldID    m_viewportUserScalable;
    223     jfieldID    m_viewportDensityDpi;
    224     jfieldID    m_webView;
    225 } gWebViewCoreFields;
    226 
    227 // ----------------------------------------------------------------------------
    228 
    229 struct WebViewCore::JavaGlue {
    230     jweak       m_obj;
    231     jmethodID   m_spawnScrollTo;
    232     jmethodID   m_scrollTo;
    233     jmethodID   m_scrollBy;
    234     jmethodID   m_contentDraw;
    235     jmethodID   m_requestListBox;
    236     jmethodID   m_openFileChooser;
    237     jmethodID   m_requestSingleListBox;
    238     jmethodID   m_jsAlert;
    239     jmethodID   m_jsConfirm;
    240     jmethodID   m_jsPrompt;
    241     jmethodID   m_jsUnload;
    242     jmethodID   m_jsInterrupt;
    243     jmethodID   m_didFirstLayout;
    244     jmethodID   m_updateViewport;
    245     jmethodID   m_sendNotifyProgressFinished;
    246     jmethodID   m_sendViewInvalidate;
    247     jmethodID   m_sendImmediateRepaint;
    248     jmethodID   m_setRootLayer;
    249     jmethodID   m_updateTextfield;
    250     jmethodID   m_updateTextSelection;
    251     jmethodID   m_clearTextEntry;
    252     jmethodID   m_restoreScale;
    253     jmethodID   m_restoreScreenWidthScale;
    254     jmethodID   m_needTouchEvents;
    255     jmethodID   m_requestKeyboard;
    256     jmethodID   m_requestKeyboardWithSelection;
    257     jmethodID   m_exceededDatabaseQuota;
    258     jmethodID   m_reachedMaxAppCacheSize;
    259     jmethodID   m_populateVisitedLinks;
    260     jmethodID   m_geolocationPermissionsShowPrompt;
    261     jmethodID   m_geolocationPermissionsHidePrompt;
    262     jmethodID   m_addMessageToConsole;
    263     jmethodID   m_getPluginClass;
    264     jmethodID   m_showFullScreenPlugin;
    265     jmethodID   m_hideFullScreenPlugin;
    266     jmethodID   m_addSurface;
    267     jmethodID   m_updateSurface;
    268     jmethodID   m_destroySurface;
    269     jmethodID   m_getContext;
    270     jmethodID   m_sendFindAgain;
    271     jmethodID   m_showRect;
    272     jmethodID   m_centerFitRect;
    273     jmethodID   m_setScrollbarModes;
    274     AutoJObject object(JNIEnv* env) {
    275         return getRealObject(env, m_obj);
    276     }
    277 };
    278 
    279 /*
    280  * WebViewCore Implementation
    281  */
    282 
    283 static jmethodID GetJMethod(JNIEnv* env, jclass clazz, const char name[], const char signature[])
    284 {
    285     jmethodID m = env->GetMethodID(clazz, name, signature);
    286     LOG_ASSERT(m, "Could not find method %s", name);
    287     return m;
    288 }
    289 
    290 Mutex WebViewCore::gFrameCacheMutex;
    291 Mutex WebViewCore::gButtonMutex;
    292 Mutex WebViewCore::gCursorBoundsMutex;
    293 Mutex WebViewCore::m_contentMutex;
    294 
    295 WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* mainframe)
    296         : m_pluginInvalTimer(this, &WebViewCore::pluginInvalTimerFired)
    297 {
    298     m_mainFrame = mainframe;
    299 
    300     m_popupReply = 0;
    301     m_moveGeneration = 0;
    302     m_lastGeneration = 0;
    303     m_touchGeneration = 0;
    304     m_blockTextfieldUpdates = false;
    305     // just initial values. These should be set by client
    306     m_maxXScroll = 320/4;
    307     m_maxYScroll = 240/4;
    308     m_textGeneration = 0;
    309     m_screenWidth = 320;
    310     m_scale = 1;
    311     m_screenWidthScale = 1;
    312 #if ENABLE(TOUCH_EVENTS)
    313     m_forwardingTouchEvents = false;
    314 #endif
    315     m_isPaused = false;
    316 
    317     LOG_ASSERT(m_mainFrame, "Uh oh, somehow a frameview was made without an initial frame!");
    318 
    319     jclass clazz = env->GetObjectClass(javaWebViewCore);
    320     m_javaGlue = new JavaGlue;
    321     m_javaGlue->m_obj = env->NewWeakGlobalRef(javaWebViewCore);
    322     m_javaGlue->m_spawnScrollTo = GetJMethod(env, clazz, "contentSpawnScrollTo", "(II)V");
    323     m_javaGlue->m_scrollTo = GetJMethod(env, clazz, "contentScrollTo", "(II)V");
    324     m_javaGlue->m_scrollBy = GetJMethod(env, clazz, "contentScrollBy", "(IIZ)V");
    325     m_javaGlue->m_contentDraw = GetJMethod(env, clazz, "contentDraw", "()V");
    326     m_javaGlue->m_requestListBox = GetJMethod(env, clazz, "requestListBox", "([Ljava/lang/String;[I[I)V");
    327     m_javaGlue->m_openFileChooser = GetJMethod(env, clazz, "openFileChooser", "()Ljava/lang/String;");
    328     m_javaGlue->m_requestSingleListBox = GetJMethod(env, clazz, "requestListBox", "([Ljava/lang/String;[II)V");
    329     m_javaGlue->m_jsAlert = GetJMethod(env, clazz, "jsAlert", "(Ljava/lang/String;Ljava/lang/String;)V");
    330     m_javaGlue->m_jsConfirm = GetJMethod(env, clazz, "jsConfirm", "(Ljava/lang/String;Ljava/lang/String;)Z");
    331     m_javaGlue->m_jsPrompt = GetJMethod(env, clazz, "jsPrompt", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
    332     m_javaGlue->m_jsUnload = GetJMethod(env, clazz, "jsUnload", "(Ljava/lang/String;Ljava/lang/String;)Z");
    333     m_javaGlue->m_jsInterrupt = GetJMethod(env, clazz, "jsInterrupt", "()Z");
    334     m_javaGlue->m_didFirstLayout = GetJMethod(env, clazz, "didFirstLayout", "(Z)V");
    335     m_javaGlue->m_updateViewport = GetJMethod(env, clazz, "updateViewport", "()V");
    336     m_javaGlue->m_sendNotifyProgressFinished = GetJMethod(env, clazz, "sendNotifyProgressFinished", "()V");
    337     m_javaGlue->m_sendViewInvalidate = GetJMethod(env, clazz, "sendViewInvalidate", "(IIII)V");
    338     m_javaGlue->m_sendImmediateRepaint = GetJMethod(env, clazz, "sendImmediateRepaint", "()V");
    339     m_javaGlue->m_setRootLayer = GetJMethod(env, clazz, "setRootLayer", "(I)V");
    340     m_javaGlue->m_updateTextfield = GetJMethod(env, clazz, "updateTextfield", "(IZLjava/lang/String;I)V");
    341     m_javaGlue->m_updateTextSelection = GetJMethod(env, clazz, "updateTextSelection", "(IIII)V");
    342     m_javaGlue->m_clearTextEntry = GetJMethod(env, clazz, "clearTextEntry", "()V");
    343     m_javaGlue->m_restoreScale = GetJMethod(env, clazz, "restoreScale", "(I)V");
    344     m_javaGlue->m_restoreScreenWidthScale = GetJMethod(env, clazz, "restoreScreenWidthScale", "(I)V");
    345     m_javaGlue->m_needTouchEvents = GetJMethod(env, clazz, "needTouchEvents", "(Z)V");
    346     m_javaGlue->m_requestKeyboard = GetJMethod(env, clazz, "requestKeyboard", "(Z)V");
    347     m_javaGlue->m_requestKeyboardWithSelection = GetJMethod(env, clazz, "requestKeyboardWithSelection", "(IIII)V");
    348     m_javaGlue->m_exceededDatabaseQuota = GetJMethod(env, clazz, "exceededDatabaseQuota", "(Ljava/lang/String;Ljava/lang/String;JJ)V");
    349     m_javaGlue->m_reachedMaxAppCacheSize = GetJMethod(env, clazz, "reachedMaxAppCacheSize", "(J)V");
    350     m_javaGlue->m_populateVisitedLinks = GetJMethod(env, clazz, "populateVisitedLinks", "()V");
    351     m_javaGlue->m_geolocationPermissionsShowPrompt = GetJMethod(env, clazz, "geolocationPermissionsShowPrompt", "(Ljava/lang/String;)V");
    352     m_javaGlue->m_geolocationPermissionsHidePrompt = GetJMethod(env, clazz, "geolocationPermissionsHidePrompt", "()V");
    353     m_javaGlue->m_addMessageToConsole = GetJMethod(env, clazz, "addMessageToConsole", "(Ljava/lang/String;ILjava/lang/String;I)V");
    354     m_javaGlue->m_getPluginClass = GetJMethod(env, clazz, "getPluginClass", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Class;");
    355     m_javaGlue->m_showFullScreenPlugin = GetJMethod(env, clazz, "showFullScreenPlugin", "(Landroid/webkit/ViewManager$ChildView;I)V");
    356     m_javaGlue->m_hideFullScreenPlugin = GetJMethod(env, clazz, "hideFullScreenPlugin", "()V");
    357     m_javaGlue->m_addSurface = GetJMethod(env, clazz, "addSurface", "(Landroid/view/View;IIII)Landroid/webkit/ViewManager$ChildView;");
    358     m_javaGlue->m_updateSurface = GetJMethod(env, clazz, "updateSurface", "(Landroid/webkit/ViewManager$ChildView;IIII)V");
    359     m_javaGlue->m_destroySurface = GetJMethod(env, clazz, "destroySurface", "(Landroid/webkit/ViewManager$ChildView;)V");
    360     m_javaGlue->m_getContext = GetJMethod(env, clazz, "getContext", "()Landroid/content/Context;");
    361     m_javaGlue->m_sendFindAgain = GetJMethod(env, clazz, "sendFindAgain", "()V");
    362     m_javaGlue->m_showRect = GetJMethod(env, clazz, "showRect", "(IIIIIIFFFF)V");
    363     m_javaGlue->m_centerFitRect = GetJMethod(env, clazz, "centerFitRect", "(IIII)V");
    364     m_javaGlue->m_setScrollbarModes = GetJMethod(env, clazz, "setScrollbarModes", "(II)V");
    365 
    366     env->SetIntField(javaWebViewCore, gWebViewCoreFields.m_nativeClass, (jint)this);
    367 
    368     m_scrollOffsetX = m_scrollOffsetY = 0;
    369 
    370     PageGroup::setShouldTrackVisitedLinks(true);
    371 
    372     reset(true);
    373 
    374     WebViewCore::addInstance(this);
    375 }
    376 
    377 WebViewCore::~WebViewCore()
    378 {
    379     WebViewCore::removeInstance(this);
    380 
    381     // Release the focused view
    382     Release(m_popupReply);
    383 
    384     if (m_javaGlue->m_obj) {
    385         JNIEnv* env = JSC::Bindings::getJNIEnv();
    386         env->DeleteWeakGlobalRef(m_javaGlue->m_obj);
    387         m_javaGlue->m_obj = 0;
    388     }
    389     delete m_javaGlue;
    390     delete m_frameCacheKit;
    391     delete m_navPictureKit;
    392 }
    393 
    394 WebViewCore* WebViewCore::getWebViewCore(const WebCore::FrameView* view)
    395 {
    396     return getWebViewCore(static_cast<const WebCore::ScrollView*>(view));
    397 }
    398 
    399 WebViewCore* WebViewCore::getWebViewCore(const WebCore::ScrollView* view)
    400 {
    401     if (!view)
    402         return 0;
    403 
    404     WebFrameView* webFrameView = static_cast<WebFrameView*>(view->platformWidget());
    405     if (!webFrameView)
    406         return 0;
    407     return webFrameView->webViewCore();
    408 }
    409 
    410 void WebViewCore::reset(bool fromConstructor)
    411 {
    412     DBG_SET_LOG("");
    413     if (fromConstructor) {
    414         m_frameCacheKit = 0;
    415         m_navPictureKit = 0;
    416     } else {
    417         gFrameCacheMutex.lock();
    418         delete m_frameCacheKit;
    419         delete m_navPictureKit;
    420         m_frameCacheKit = 0;
    421         m_navPictureKit = 0;
    422         gFrameCacheMutex.unlock();
    423     }
    424 
    425     m_lastFocused = 0;
    426     m_lastFocusedBounds = WebCore::IntRect(0,0,0,0);
    427     m_focusBoundsChanged = false;
    428     m_lastFocusedSelStart = 0;
    429     m_lastFocusedSelEnd = 0;
    430     clearContent();
    431     m_updatedFrameCache = true;
    432     m_frameCacheOutOfDate = true;
    433     m_skipContentDraw = false;
    434     m_findIsUp = false;
    435     m_domtree_version = 0;
    436     m_check_domtree_version = true;
    437     m_progressDone = false;
    438     m_hasCursorBounds = false;
    439 
    440     m_scrollOffsetX = 0;
    441     m_scrollOffsetY = 0;
    442     m_screenWidth = 0;
    443     m_screenHeight = 0;
    444     m_groupForVisitedLinks = NULL;
    445 }
    446 
    447 static bool layoutIfNeededRecursive(WebCore::Frame* f)
    448 {
    449     if (!f)
    450         return true;
    451 
    452     WebCore::FrameView* v = f->view();
    453     if (!v)
    454         return true;
    455 
    456     if (v->needsLayout())
    457         v->layout(f->tree()->parent());
    458 
    459     WebCore::Frame* child = f->tree()->firstChild();
    460     bool success = true;
    461     while (child) {
    462         success &= layoutIfNeededRecursive(child);
    463         child = child->tree()->nextSibling();
    464     }
    465 
    466     return success && !v->needsLayout();
    467 }
    468 
    469 CacheBuilder& WebViewCore::cacheBuilder()
    470 {
    471     return FrameLoaderClientAndroid::get(m_mainFrame)->getCacheBuilder();
    472 }
    473 
    474 WebCore::Node* WebViewCore::currentFocus()
    475 {
    476     return cacheBuilder().currentFocus();
    477 }
    478 
    479 void WebViewCore::recordPicture(SkPicture* picture)
    480 {
    481     // if there is no document yet, just return
    482     if (!m_mainFrame->document()) {
    483         DBG_NAV_LOG("no document");
    484         return;
    485     }
    486     // Call layout to ensure that the contentWidth and contentHeight are correct
    487     if (!layoutIfNeededRecursive(m_mainFrame)) {
    488         DBG_NAV_LOG("layout failed");
    489         return;
    490     }
    491     // draw into the picture's recording canvas
    492     WebCore::FrameView* view = m_mainFrame->view();
    493     DBG_NAV_LOGD("view=(w=%d,h=%d)", view->contentsWidth(),
    494         view->contentsHeight());
    495     SkAutoPictureRecord arp(picture, view->contentsWidth(),
    496                             view->contentsHeight(), PICT_RECORD_FLAGS);
    497     SkAutoMemoryUsageProbe mup(__FUNCTION__);
    498 
    499     // Copy m_buttons so we can pass it to our graphics context.
    500     gButtonMutex.lock();
    501     WTF::Vector<Container> buttons(m_buttons);
    502     gButtonMutex.unlock();
    503 
    504     WebCore::PlatformGraphicsContext pgc(arp.getRecordingCanvas(), &buttons);
    505     WebCore::GraphicsContext gc(&pgc);
    506     view->platformWidget()->draw(&gc, WebCore::IntRect(0, 0, INT_MAX, INT_MAX));
    507 
    508     gButtonMutex.lock();
    509     updateButtonList(&buttons);
    510     gButtonMutex.unlock();
    511 }
    512 
    513 void WebViewCore::recordPictureSet(PictureSet* content)
    514 {
    515     // if there is no document yet, just return
    516     if (!m_mainFrame->document()) {
    517         DBG_SET_LOG("!m_mainFrame->document()");
    518         return;
    519     }
    520     if (m_addInval.isEmpty()) {
    521         DBG_SET_LOG("m_addInval.isEmpty()");
    522         return;
    523     }
    524     // Call layout to ensure that the contentWidth and contentHeight are correct
    525     // it's fine for layout to gather invalidates, but defeat sending a message
    526     // back to java to call webkitDraw, since we're already in the middle of
    527     // doing that
    528     m_skipContentDraw = true;
    529     bool success = layoutIfNeededRecursive(m_mainFrame);
    530     m_skipContentDraw = false;
    531 
    532     // We may be mid-layout and thus cannot draw.
    533     if (!success)
    534         return;
    535 
    536     {   // collect WebViewCoreRecordTimeCounter after layoutIfNeededRecursive
    537 #ifdef ANDROID_INSTRUMENT
    538     TimeCounterAuto counter(TimeCounter::WebViewCoreRecordTimeCounter);
    539 #endif
    540 
    541     // if the webkit page dimensions changed, discard the pictureset and redraw.
    542     WebCore::FrameView* view = m_mainFrame->view();
    543     int width = view->contentsWidth();
    544     int height = view->contentsHeight();
    545 
    546     // Use the contents width and height as a starting point.
    547     SkIRect contentRect;
    548     contentRect.set(0, 0, width, height);
    549     SkIRect total(contentRect);
    550 
    551     // Traverse all the frames and add their sizes if they are in the visible
    552     // rectangle.
    553     for (WebCore::Frame* frame = m_mainFrame->tree()->traverseNext(); frame;
    554             frame = frame->tree()->traverseNext()) {
    555         // If the frame doesn't have an owner then it is the top frame and the
    556         // view size is the frame size.
    557         WebCore::RenderPart* owner = frame->ownerRenderer();
    558         if (owner && owner->style()->visibility() == VISIBLE) {
    559             int x = owner->x();
    560             int y = owner->y();
    561 
    562             // Traverse the tree up to the parent to find the absolute position
    563             // of this frame.
    564             WebCore::Frame* parent = frame->tree()->parent();
    565             while (parent) {
    566                 WebCore::RenderPart* parentOwner = parent->ownerRenderer();
    567                 if (parentOwner) {
    568                     x += parentOwner->x();
    569                     y += parentOwner->y();
    570                 }
    571                 parent = parent->tree()->parent();
    572             }
    573             // Use the owner dimensions so that padding and border are
    574             // included.
    575             int right = x + owner->width();
    576             int bottom = y + owner->height();
    577             SkIRect frameRect = {x, y, right, bottom};
    578             // Ignore a width or height that is smaller than 1. Some iframes
    579             // have small dimensions in order to be hidden. The iframe
    580             // expansion code does not expand in that case so we should ignore
    581             // them here.
    582             if (frameRect.width() > 1 && frameRect.height() > 1
    583                     && SkIRect::Intersects(total, frameRect))
    584                 total.join(x, y, right, bottom);
    585         }
    586     }
    587 
    588     // If the new total is larger than the content, resize the view to include
    589     // all the content.
    590     if (!contentRect.contains(total)) {
    591         // Resize the view to change the overflow clip.
    592         view->resize(total.fRight, total.fBottom);
    593 
    594         // We have to force a layout in order for the clip to change.
    595         m_mainFrame->contentRenderer()->setNeedsLayoutAndPrefWidthsRecalc();
    596         view->forceLayout();
    597 
    598         // Relayout similar to above
    599         m_skipContentDraw = true;
    600         bool success = layoutIfNeededRecursive(m_mainFrame);
    601         m_skipContentDraw = false;
    602         if (!success)
    603             return;
    604 
    605         // Set the computed content width
    606         width = view->contentsWidth();
    607         height = view->contentsHeight();
    608     }
    609 
    610     content->checkDimensions(width, height, &m_addInval);
    611 
    612     // The inval region may replace existing pictures. The existing pictures
    613     // may have already been split into pieces. If reuseSubdivided() returns
    614     // true, the split pieces are the last entries in the picture already. They
    615     // are marked as invalid, and are rebuilt by rebuildPictureSet().
    616 
    617     // If the new region doesn't match a set of split pieces, add it to the end.
    618     if (!content->reuseSubdivided(m_addInval)) {
    619         const SkIRect& inval = m_addInval.getBounds();
    620         SkPicture* picture = rebuildPicture(inval);
    621         DBG_SET_LOGD("{%d,%d,w=%d,h=%d}", inval.fLeft,
    622             inval.fTop, inval.width(), inval.height());
    623         content->add(m_addInval, picture, 0, false);
    624         picture->safeUnref();
    625     }
    626     // Remove any pictures already in the set that are obscured by the new one,
    627     // and check to see if any already split pieces need to be redrawn.
    628     if (content->build())
    629         rebuildPictureSet(content);
    630     } // WebViewCoreRecordTimeCounter
    631     WebCore::Node* oldFocusNode = currentFocus();
    632     m_frameCacheOutOfDate = true;
    633     WebCore::IntRect oldBounds;
    634     int oldSelStart = 0;
    635     int oldSelEnd = 0;
    636     if (oldFocusNode) {
    637         oldBounds = oldFocusNode->getRect();
    638         RenderObject* renderer = oldFocusNode->renderer();
    639         if (renderer && (renderer->isTextArea() || renderer->isTextField())) {
    640             WebCore::RenderTextControl* rtc =
    641                 static_cast<WebCore::RenderTextControl*>(renderer);
    642             oldSelStart = rtc->selectionStart();
    643             oldSelEnd = rtc->selectionEnd();
    644         }
    645     } else
    646         oldBounds = WebCore::IntRect(0,0,0,0);
    647     unsigned latestVersion = 0;
    648     if (m_check_domtree_version) {
    649         // as domTreeVersion only increment, we can just check the sum to see
    650         // whether we need to update the frame cache
    651         for (Frame* frame = m_mainFrame; frame; frame = frame->tree()->traverseNext()) {
    652             latestVersion += frame->document()->domTreeVersion();
    653         }
    654     }
    655     DBG_NAV_LOGD("m_lastFocused=%p oldFocusNode=%p"
    656         " m_lastFocusedBounds={%d,%d,%d,%d} oldBounds={%d,%d,%d,%d}"
    657         " m_lastFocusedSelection={%d,%d} oldSelection={%d,%d}"
    658         " m_check_domtree_version=%s latestVersion=%d m_domtree_version=%d",
    659         m_lastFocused, oldFocusNode,
    660         m_lastFocusedBounds.x(), m_lastFocusedBounds.y(),
    661         m_lastFocusedBounds.width(), m_lastFocusedBounds.height(),
    662         oldBounds.x(), oldBounds.y(), oldBounds.width(), oldBounds.height(),
    663         m_lastFocusedSelStart, m_lastFocusedSelEnd, oldSelStart, oldSelEnd,
    664         m_check_domtree_version ? "true" : "false",
    665         latestVersion, m_domtree_version);
    666     if (m_lastFocused == oldFocusNode && m_lastFocusedBounds == oldBounds
    667             && m_lastFocusedSelStart == oldSelStart
    668             && m_lastFocusedSelEnd == oldSelEnd
    669             && !m_findIsUp
    670             && (!m_check_domtree_version || latestVersion == m_domtree_version))
    671     {
    672         return;
    673     }
    674     m_focusBoundsChanged |= m_lastFocused == oldFocusNode
    675         && m_lastFocusedBounds != oldBounds;
    676     m_lastFocused = oldFocusNode;
    677     m_lastFocusedBounds = oldBounds;
    678     m_lastFocusedSelStart = oldSelStart;
    679     m_lastFocusedSelEnd = oldSelEnd;
    680     m_domtree_version = latestVersion;
    681     DBG_NAV_LOG("call updateFrameCache");
    682     updateFrameCache();
    683     if (m_findIsUp) {
    684         LOG_ASSERT(m_javaGlue->m_obj,
    685                 "A Java widget was not associated with this view bridge!");
    686         JNIEnv* env = JSC::Bindings::getJNIEnv();
    687         env->CallVoidMethod(m_javaGlue->object(env).get(),
    688                 m_javaGlue->m_sendFindAgain);
    689         checkException(env);
    690     }
    691 }
    692 
    693 void WebViewCore::updateButtonList(WTF::Vector<Container>* buttons)
    694 {
    695     // All the entries in buttons are either updates of previous entries in
    696     // m_buttons or they need to be added to it.
    697     Container* end = buttons->end();
    698     for (Container* updatedContainer = buttons->begin();
    699             updatedContainer != end; updatedContainer++) {
    700         bool updated = false;
    701         // Search for a previous entry that references the same node as our new
    702         // data
    703         Container* lastPossibleMatch = m_buttons.end();
    704         for (Container* possibleMatch = m_buttons.begin();
    705                 possibleMatch != lastPossibleMatch; possibleMatch++) {
    706             if (updatedContainer->matches(possibleMatch->node())) {
    707                 // Update our record, and skip to the next one.
    708                 possibleMatch->setRect(updatedContainer->rect());
    709                 updated = true;
    710                 break;
    711             }
    712         }
    713         if (!updated) {
    714             // This is a brand new button, so append it to m_buttons
    715             m_buttons.append(*updatedContainer);
    716         }
    717     }
    718     size_t i = 0;
    719     // count will decrease each time one is removed, so check count each time.
    720     while (i < m_buttons.size()) {
    721         if (m_buttons[i].canBeRemoved()) {
    722             m_buttons[i] = m_buttons.last();
    723             m_buttons.removeLast();
    724         } else {
    725             i++;
    726         }
    727     }
    728 }
    729 
    730 // note: updateCursorBounds is called directly by the WebView thread
    731 // This needs to be called each time we call CachedRoot::setCursor() with
    732 // non-null CachedNode/CachedFrame, since otherwise the WebViewCore's data
    733 // about the cursor is incorrect.  When we call setCursor(0,0), we need
    734 // to set hasCursorBounds to false.
    735 void WebViewCore::updateCursorBounds(const CachedRoot* root,
    736         const CachedFrame* cachedFrame, const CachedNode* cachedNode)
    737 {
    738     LOG_ASSERT(root, "updateCursorBounds: root cannot be null");
    739     LOG_ASSERT(cachedNode, "updateCursorBounds: cachedNode cannot be null");
    740     LOG_ASSERT(cachedFrame, "updateCursorBounds: cachedFrame cannot be null");
    741     gCursorBoundsMutex.lock();
    742     m_hasCursorBounds = !cachedNode->isHidden();
    743     // If m_hasCursorBounds is false, we never look at the other
    744     // values, so do not bother setting them.
    745     if (m_hasCursorBounds) {
    746         WebCore::IntRect bounds = cachedNode->bounds(cachedFrame);
    747         if (m_cursorBounds != bounds)
    748             DBG_NAV_LOGD("new cursor bounds=(%d,%d,w=%d,h=%d)",
    749                 bounds.x(), bounds.y(), bounds.width(), bounds.height());
    750         m_cursorBounds = bounds;
    751         m_cursorHitBounds = cachedNode->hitBounds(cachedFrame);
    752         m_cursorFrame = cachedFrame->framePointer();
    753         root->getSimulatedMousePosition(&m_cursorLocation);
    754         m_cursorNode = cachedNode->nodePointer();
    755     }
    756     gCursorBoundsMutex.unlock();
    757 }
    758 
    759 void WebViewCore::clearContent()
    760 {
    761     DBG_SET_LOG("");
    762     m_contentMutex.lock();
    763     m_content.clear();
    764     m_contentMutex.unlock();
    765     m_addInval.setEmpty();
    766     m_rebuildInval.setEmpty();
    767 }
    768 
    769 void WebViewCore::copyContentToPicture(SkPicture* picture)
    770 {
    771     DBG_SET_LOG("start");
    772     m_contentMutex.lock();
    773     PictureSet copyContent = PictureSet(m_content);
    774     m_contentMutex.unlock();
    775 
    776     int w = copyContent.width();
    777     int h = copyContent.height();
    778     copyContent.draw(picture->beginRecording(w, h, PICT_RECORD_FLAGS));
    779     picture->endRecording();
    780     DBG_SET_LOG("end");
    781 }
    782 
    783 bool WebViewCore::drawContent(SkCanvas* canvas, SkColor color)
    784 {
    785 #ifdef ANDROID_INSTRUMENT
    786     TimeCounterAuto counter(TimeCounter::WebViewUIDrawTimeCounter);
    787 #endif
    788     DBG_SET_LOG("start");
    789     m_contentMutex.lock();
    790     PictureSet copyContent = PictureSet(m_content);
    791     m_contentMutex.unlock();
    792     int sc = canvas->save(SkCanvas::kClip_SaveFlag);
    793     SkRect clip;
    794     clip.set(0, 0, copyContent.width(), copyContent.height());
    795     canvas->clipRect(clip, SkRegion::kDifference_Op);
    796     canvas->drawColor(color);
    797     canvas->restoreToCount(sc);
    798     bool tookTooLong = copyContent.draw(canvas);
    799     m_contentMutex.lock();
    800     m_content.setDrawTimes(copyContent);
    801     m_contentMutex.unlock();
    802     DBG_SET_LOG("end");
    803     return tookTooLong;
    804 }
    805 
    806 bool WebViewCore::focusBoundsChanged()
    807 {
    808     bool result = m_focusBoundsChanged;
    809     m_focusBoundsChanged = false;
    810     return result;
    811 }
    812 
    813 bool WebViewCore::pictureReady()
    814 {
    815     bool done;
    816     m_contentMutex.lock();
    817     PictureSet copyContent = PictureSet(m_content);
    818     done = m_progressDone;
    819     m_contentMutex.unlock();
    820     DBG_NAV_LOGD("done=%s empty=%s", done ? "true" : "false",
    821         copyContent.isEmpty() ? "true" : "false");
    822     return done || !copyContent.isEmpty();
    823 }
    824 
    825 SkPicture* WebViewCore::rebuildPicture(const SkIRect& inval)
    826 {
    827     WebCore::FrameView* view = m_mainFrame->view();
    828     int width = view->contentsWidth();
    829     int height = view->contentsHeight();
    830     SkPicture* picture = new SkPicture();
    831     SkAutoPictureRecord arp(picture, width, height, PICT_RECORD_FLAGS);
    832     SkAutoMemoryUsageProbe mup(__FUNCTION__);
    833     SkCanvas* recordingCanvas = arp.getRecordingCanvas();
    834 
    835     gButtonMutex.lock();
    836     WTF::Vector<Container> buttons(m_buttons);
    837     gButtonMutex.unlock();
    838 
    839     WebCore::PlatformGraphicsContext pgc(recordingCanvas, &buttons);
    840     WebCore::GraphicsContext gc(&pgc);
    841     recordingCanvas->translate(-inval.fLeft, -inval.fTop);
    842     recordingCanvas->save();
    843     view->platformWidget()->draw(&gc, WebCore::IntRect(inval.fLeft,
    844         inval.fTop, inval.width(), inval.height()));
    845     m_rebuildInval.op(inval, SkRegion::kUnion_Op);
    846     DBG_SET_LOGD("m_rebuildInval={%d,%d,r=%d,b=%d}",
    847         m_rebuildInval.getBounds().fLeft, m_rebuildInval.getBounds().fTop,
    848         m_rebuildInval.getBounds().fRight, m_rebuildInval.getBounds().fBottom);
    849 
    850     gButtonMutex.lock();
    851     updateButtonList(&buttons);
    852     gButtonMutex.unlock();
    853 
    854     return picture;
    855 }
    856 
    857 void WebViewCore::rebuildPictureSet(PictureSet* pictureSet)
    858 {
    859     WebCore::FrameView* view = m_mainFrame->view();
    860     size_t size = pictureSet->size();
    861     for (size_t index = 0; index < size; index++) {
    862         if (pictureSet->upToDate(index))
    863             continue;
    864         const SkIRect& inval = pictureSet->bounds(index);
    865         DBG_SET_LOGD("pictSet=%p [%d] {%d,%d,w=%d,h=%d}", pictureSet, index,
    866             inval.fLeft, inval.fTop, inval.width(), inval.height());
    867         pictureSet->setPicture(index, rebuildPicture(inval));
    868     }
    869     pictureSet->validate(__FUNCTION__);
    870 }
    871 
    872 bool WebViewCore::recordContent(SkRegion* region, SkIPoint* point)
    873 {
    874     DBG_SET_LOG("start");
    875     float progress = (float) m_mainFrame->page()->progress()->estimatedProgress();
    876     m_contentMutex.lock();
    877     PictureSet contentCopy(m_content);
    878     m_progressDone = progress <= 0.0f || progress >= 1.0f;
    879     m_contentMutex.unlock();
    880     recordPictureSet(&contentCopy);
    881     if (!m_progressDone && contentCopy.isEmpty()) {
    882         DBG_SET_LOGD("empty (progress=%g)", progress);
    883         return false;
    884     }
    885     region->set(m_addInval);
    886     m_addInval.setEmpty();
    887     region->op(m_rebuildInval, SkRegion::kUnion_Op);
    888     m_rebuildInval.setEmpty();
    889     m_contentMutex.lock();
    890     contentCopy.setDrawTimes(m_content);
    891     m_content.set(contentCopy);
    892     point->fX = m_content.width();
    893     point->fY = m_content.height();
    894     m_contentMutex.unlock();
    895     DBG_SET_LOGD("region={%d,%d,r=%d,b=%d}", region->getBounds().fLeft,
    896         region->getBounds().fTop, region->getBounds().fRight,
    897         region->getBounds().fBottom);
    898     DBG_SET_LOG("end");
    899     return true;
    900 }
    901 
    902 void WebViewCore::splitContent()
    903 {
    904     bool layoutSuceeded = layoutIfNeededRecursive(m_mainFrame);
    905     LOG_ASSERT(layoutSuceeded, "Can never be called recursively");
    906     PictureSet tempPictureSet;
    907     m_contentMutex.lock();
    908     m_content.split(&tempPictureSet);
    909     m_contentMutex.unlock();
    910     rebuildPictureSet(&tempPictureSet);
    911     m_contentMutex.lock();
    912     m_content.set(tempPictureSet);
    913     m_contentMutex.unlock();
    914 }
    915 
    916 void WebViewCore::scrollTo(int x, int y, bool animate)
    917 {
    918     LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
    919 
    920 //    LOGD("WebViewCore::scrollTo(%d %d)\n", x, y);
    921 
    922     JNIEnv* env = JSC::Bindings::getJNIEnv();
    923     env->CallVoidMethod(m_javaGlue->object(env).get(),
    924             animate ? m_javaGlue->m_spawnScrollTo : m_javaGlue->m_scrollTo,
    925             x, y);
    926     checkException(env);
    927 }
    928 
    929 void WebViewCore::sendNotifyProgressFinished()
    930 {
    931     LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
    932     JNIEnv* env = JSC::Bindings::getJNIEnv();
    933     env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_sendNotifyProgressFinished);
    934     checkException(env);
    935 }
    936 
    937 void WebViewCore::viewInvalidate(const WebCore::IntRect& rect)
    938 {
    939     LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
    940     JNIEnv* env = JSC::Bindings::getJNIEnv();
    941     env->CallVoidMethod(m_javaGlue->object(env).get(),
    942                         m_javaGlue->m_sendViewInvalidate,
    943                         rect.x(), rect.y(), rect.right(), rect.bottom());
    944     checkException(env);
    945 }
    946 
    947 void WebViewCore::scrollBy(int dx, int dy, bool animate)
    948 {
    949     if (!(dx | dy))
    950         return;
    951     JNIEnv* env = JSC::Bindings::getJNIEnv();
    952     env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_scrollBy,
    953         dx, dy, animate);
    954     checkException(env);
    955 }
    956 
    957 #if USE(ACCELERATED_COMPOSITING)
    958 
    959 void WebViewCore::immediateRepaint()
    960 {
    961     LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
    962     JNIEnv* env = JSC::Bindings::getJNIEnv();
    963     env->CallVoidMethod(m_javaGlue->object(env).get(),
    964                         m_javaGlue->m_sendImmediateRepaint);
    965     checkException(env);
    966 }
    967 
    968 void WebViewCore::setUIRootLayer(const LayerAndroid* layer)
    969 {
    970     JNIEnv* env = JSC::Bindings::getJNIEnv();
    971     env->CallVoidMethod(m_javaGlue->object(env).get(),
    972                         m_javaGlue->m_setRootLayer,
    973                         reinterpret_cast<jint>(layer));
    974     checkException(env);
    975 }
    976 
    977 #endif // USE(ACCELERATED_COMPOSITING)
    978 
    979 void WebViewCore::contentDraw()
    980 {
    981     JNIEnv* env = JSC::Bindings::getJNIEnv();
    982     env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_contentDraw);
    983     checkException(env);
    984 }
    985 
    986 void WebViewCore::contentInvalidate(const WebCore::IntRect &r)
    987 {
    988     DBG_SET_LOGD("rect={%d,%d,w=%d,h=%d}", r.x(), r.y(), r.width(), r.height());
    989     SkIRect rect(r);
    990     if (!rect.intersect(0, 0, INT_MAX, INT_MAX))
    991         return;
    992     m_addInval.op(rect, SkRegion::kUnion_Op);
    993     DBG_SET_LOGD("m_addInval={%d,%d,r=%d,b=%d}",
    994         m_addInval.getBounds().fLeft, m_addInval.getBounds().fTop,
    995         m_addInval.getBounds().fRight, m_addInval.getBounds().fBottom);
    996     if (!m_skipContentDraw)
    997         contentDraw();
    998 }
    999 
   1000 void WebViewCore::offInvalidate(const WebCore::IntRect &r)
   1001 {
   1002     // FIXME: these invalidates are offscreen, and can be throttled or
   1003     // deferred until the area is visible. For now, treat them as
   1004     // regular invals so that drawing happens (inefficiently) for now.
   1005     contentInvalidate(r);
   1006 }
   1007 
   1008 static int pin_pos(int x, int width, int targetWidth)
   1009 {
   1010     if (x + width > targetWidth)
   1011         x = targetWidth - width;
   1012     if (x < 0)
   1013         x = 0;
   1014     return x;
   1015 }
   1016 
   1017 void WebViewCore::didFirstLayout()
   1018 {
   1019     DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
   1020     LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
   1021 
   1022     WebCore::FrameLoader* loader = m_mainFrame->loader();
   1023     const WebCore::KURL& url = loader->url();
   1024     if (url.isEmpty())
   1025         return;
   1026     LOGV("::WebCore:: didFirstLayout %s", url.string().ascii().data());
   1027 
   1028     WebCore::FrameLoadType loadType = loader->loadType();
   1029 
   1030     JNIEnv* env = JSC::Bindings::getJNIEnv();
   1031     env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_didFirstLayout,
   1032             loadType == WebCore::FrameLoadTypeStandard
   1033             // When redirect with locked history, we would like to reset the
   1034             // scale factor. This is important for www.yahoo.com as it is
   1035             // redirected to www.yahoo.com/?rs=1 on load.
   1036             || loadType == WebCore::FrameLoadTypeRedirectWithLockedBackForwardList);
   1037     checkException(env);
   1038 
   1039     DBG_NAV_LOG("call updateFrameCache");
   1040     m_check_domtree_version = false;
   1041     updateFrameCache();
   1042     m_history.setDidFirstLayout(true);
   1043 }
   1044 
   1045 void WebViewCore::updateViewport()
   1046 {
   1047     DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
   1048     LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
   1049 
   1050     JNIEnv* env = JSC::Bindings::getJNIEnv();
   1051     env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_updateViewport);
   1052     checkException(env);
   1053 }
   1054 
   1055 void WebViewCore::restoreScale(int scale)
   1056 {
   1057     DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
   1058     LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
   1059 
   1060     JNIEnv* env = JSC::Bindings::getJNIEnv();
   1061     env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_restoreScale, scale);
   1062     checkException(env);
   1063 }
   1064 
   1065 void WebViewCore::restoreScreenWidthScale(int scale)
   1066 {
   1067     DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
   1068     LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
   1069 
   1070     JNIEnv* env = JSC::Bindings::getJNIEnv();
   1071     env->CallVoidMethod(m_javaGlue->object(env).get(),
   1072             m_javaGlue->m_restoreScreenWidthScale, scale);
   1073     checkException(env);
   1074 }
   1075 
   1076 void WebViewCore::needTouchEvents(bool need)
   1077 {
   1078     DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
   1079     LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
   1080 
   1081 #if ENABLE(TOUCH_EVENTS)
   1082     if (m_forwardingTouchEvents == need)
   1083         return;
   1084 
   1085     JNIEnv* env = JSC::Bindings::getJNIEnv();
   1086     env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_needTouchEvents, need);
   1087     checkException(env);
   1088 
   1089     m_forwardingTouchEvents = need;
   1090 #endif
   1091 }
   1092 
   1093 void WebViewCore::requestKeyboardWithSelection(const WebCore::Node* node,
   1094         int selStart, int selEnd)
   1095 {
   1096     DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
   1097     LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
   1098 
   1099     JNIEnv* env = JSC::Bindings::getJNIEnv();
   1100     env->CallVoidMethod(m_javaGlue->object(env).get(),
   1101             m_javaGlue->m_requestKeyboardWithSelection,
   1102             reinterpret_cast<int>(node), selStart, selEnd, m_textGeneration);
   1103     checkException(env);
   1104 }
   1105 
   1106 void WebViewCore::requestKeyboard(bool showKeyboard)
   1107 {
   1108     DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
   1109     LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
   1110 
   1111     JNIEnv* env = JSC::Bindings::getJNIEnv();
   1112     env->CallVoidMethod(m_javaGlue->object(env).get(),
   1113             m_javaGlue->m_requestKeyboard, showKeyboard);
   1114     checkException(env);
   1115 }
   1116 
   1117 void WebViewCore::notifyProgressFinished()
   1118 {
   1119     DBG_NAV_LOG("call updateFrameCache");
   1120     m_check_domtree_version = true;
   1121     updateFrameCache();
   1122     sendNotifyProgressFinished();
   1123 }
   1124 
   1125 void WebViewCore::doMaxScroll(CacheBuilder::Direction dir)
   1126 {
   1127     int dx = 0, dy = 0;
   1128 
   1129     switch (dir) {
   1130     case CacheBuilder::LEFT:
   1131         dx = -m_maxXScroll;
   1132         break;
   1133     case CacheBuilder::UP:
   1134         dy = -m_maxYScroll;
   1135         break;
   1136     case CacheBuilder::RIGHT:
   1137         dx = m_maxXScroll;
   1138         break;
   1139     case CacheBuilder::DOWN:
   1140         dy = m_maxYScroll;
   1141         break;
   1142     case CacheBuilder::UNINITIALIZED:
   1143     default:
   1144         LOG_ASSERT(0, "unexpected focus selector");
   1145     }
   1146     this->scrollBy(dx, dy, true);
   1147 }
   1148 
   1149 void WebViewCore::setScrollOffset(int moveGeneration, int dx, int dy)
   1150 {
   1151     DBG_NAV_LOGD("{%d,%d} m_scrollOffset=(%d,%d)", dx, dy,
   1152         m_scrollOffsetX, m_scrollOffsetY);
   1153     if (m_scrollOffsetX != dx || m_scrollOffsetY != dy) {
   1154         m_scrollOffsetX = dx;
   1155         m_scrollOffsetY = dy;
   1156         // The visible rect is located within our coordinate space so it
   1157         // contains the actual scroll position. Setting the location makes hit
   1158         // testing work correctly.
   1159         m_mainFrame->view()->platformWidget()->setLocation(m_scrollOffsetX,
   1160                 m_scrollOffsetY);
   1161         m_mainFrame->eventHandler()->sendScrollEvent();
   1162 
   1163         // update the currently visible screen
   1164         sendPluginVisibleScreen();
   1165     }
   1166     gCursorBoundsMutex.lock();
   1167     bool hasCursorBounds = m_hasCursorBounds;
   1168     Frame* frame = (Frame*) m_cursorFrame;
   1169     IntPoint location = m_cursorLocation;
   1170     gCursorBoundsMutex.unlock();
   1171     if (!hasCursorBounds)
   1172         return;
   1173     moveMouseIfLatest(moveGeneration, frame, location.x(), location.y());
   1174 }
   1175 
   1176 void WebViewCore::setGlobalBounds(int x, int y, int h, int v)
   1177 {
   1178     DBG_NAV_LOGD("{%d,%d}", x, y);
   1179     m_mainFrame->view()->platformWidget()->setWindowBounds(x, y, h, v);
   1180 }
   1181 
   1182 void WebViewCore::setSizeScreenWidthAndScale(int width, int height,
   1183     int screenWidth, float scale, int realScreenWidth, int screenHeight,
   1184     int anchorX, int anchorY, bool ignoreHeight)
   1185 {
   1186     WebCoreViewBridge* window = m_mainFrame->view()->platformWidget();
   1187     int ow = window->width();
   1188     int oh = window->height();
   1189     window->setSize(width, height);
   1190     int osw = m_screenWidth;
   1191     int orsw = m_screenWidth * m_screenWidthScale / m_scale;
   1192     int osh = m_screenHeight;
   1193     DBG_NAV_LOGD("old:(w=%d,h=%d,sw=%d,scale=%g) new:(w=%d,h=%d,sw=%d,scale=%g)",
   1194         ow, oh, osw, m_scale, width, height, screenWidth, scale);
   1195     m_screenWidth = screenWidth;
   1196     m_screenHeight = screenHeight;
   1197     if (scale >= 0) { // negative means ignore
   1198         m_scale = scale;
   1199         if (screenWidth != realScreenWidth)
   1200             m_screenWidthScale = realScreenWidth * scale / screenWidth;
   1201         else
   1202             m_screenWidthScale = m_scale;
   1203     }
   1204     m_maxXScroll = screenWidth >> 2;
   1205     m_maxYScroll = (screenWidth * height / width) >> 2;
   1206     if (ow != width || (!ignoreHeight && oh != height) || osw != screenWidth) {
   1207         WebCore::RenderObject *r = m_mainFrame->contentRenderer();
   1208         DBG_NAV_LOGD("renderer=%p view=(w=%d,h=%d)", r,
   1209             realScreenWidth, screenHeight);
   1210         if (r) {
   1211             WebCore::IntPoint anchorPoint = WebCore::IntPoint(anchorX, anchorY);
   1212             DBG_NAV_LOGD("anchorX=%d anchorY=%d", anchorX, anchorY);
   1213             WebCore::Node* node = 0;
   1214             WebCore::IntRect bounds;
   1215             WebCore::IntPoint offset;
   1216             // If the screen width changed, it is probably zoom change or
   1217             // orientation change. Try to keep the anchor at the same place.
   1218             if (osw && screenWidth && osw != screenWidth) {
   1219                 WebCore::HitTestResult hitTestResult =
   1220                         m_mainFrame->eventHandler()-> hitTestResultAtPoint(
   1221                                 anchorPoint, false);
   1222                 node = hitTestResult.innerNode();
   1223             }
   1224             if (node) {
   1225                 bounds = node->getRect();
   1226                 DBG_NAV_LOGD("ob:(x=%d,y=%d,w=%d,h=%d)",
   1227                     bounds.x(), bounds.y(), bounds.width(), bounds.height());
   1228                 // sites like nytimes.com insert a non-standard tag <nyt_text>
   1229                 // in the html. If it is the HitTestResult, it may have zero
   1230                 // width and height. In this case, use its parent node.
   1231                 if (bounds.width() == 0) {
   1232                     node = node->parent();
   1233                     if (node) {
   1234                         bounds = node->getRect();
   1235                         DBG_NAV_LOGD("found a zero width node and use its parent, whose ob:(x=%d,y=%d,w=%d,h=%d)",
   1236                                 bounds.x(), bounds.y(), bounds.width(), bounds.height());
   1237                     }
   1238                 }
   1239             }
   1240             r->setNeedsLayoutAndPrefWidthsRecalc();
   1241             m_mainFrame->view()->forceLayout();
   1242             // scroll to restore current screen center
   1243             if (node) {
   1244                 const WebCore::IntRect& newBounds = node->getRect();
   1245                 DBG_NAV_LOGD("nb:(x=%d,y=%d,w=%d,"
   1246                     "h=%d)", newBounds.x(), newBounds.y(),
   1247                     newBounds.width(), newBounds.height());
   1248                 if ((orsw && osh && bounds.width() && bounds.height())
   1249                     && (bounds != newBounds)) {
   1250                     WebCore::FrameView* view = m_mainFrame->view();
   1251                     // force left align if width is not changed while height changed.
   1252                     // the anchorPoint is probably at some white space in the node
   1253                     // which is affected by text wrap around the screen width.
   1254                     const bool leftAlign = (osw != m_screenWidth)
   1255                         && (bounds.width() == newBounds.width())
   1256                         && (bounds.height() != newBounds.height());
   1257                     const float xPercentInDoc =
   1258                         leftAlign ? 0.0 : (float) (anchorX - bounds.x()) / bounds.width();
   1259                     const float xPercentInView =
   1260                         leftAlign ? 0.0 : (float) (anchorX - m_scrollOffsetX) / orsw;
   1261                     const float yPercentInDoc = (float) (anchorY - bounds.y()) / bounds.height();
   1262                     const float yPercentInView = (float) (anchorY - m_scrollOffsetY) / osh;
   1263                     showRect(newBounds.x(), newBounds.y(), newBounds.width(),
   1264                              newBounds.height(), view->contentsWidth(),
   1265                              view->contentsHeight(),
   1266                              xPercentInDoc, xPercentInView,
   1267                              yPercentInDoc, yPercentInView);
   1268                 }
   1269             }
   1270         }
   1271     }
   1272 
   1273     // update the currently visible screen as perceived by the plugin
   1274     sendPluginVisibleScreen();
   1275 }
   1276 
   1277 void WebViewCore::dumpDomTree(bool useFile)
   1278 {
   1279 #ifdef ANDROID_DOM_LOGGING
   1280     if (useFile)
   1281         gDomTreeFile = fopen(DOM_TREE_LOG_FILE, "w");
   1282     m_mainFrame->document()->showTreeForThis();
   1283     if (gDomTreeFile) {
   1284         fclose(gDomTreeFile);
   1285         gDomTreeFile = 0;
   1286     }
   1287 #endif
   1288 }
   1289 
   1290 void WebViewCore::dumpRenderTree(bool useFile)
   1291 {
   1292 #ifdef ANDROID_DOM_LOGGING
   1293     WebCore::CString renderDump = WebCore::externalRepresentation(m_mainFrame).utf8();
   1294     const char* data = renderDump.data();
   1295     if (useFile) {
   1296         gRenderTreeFile = fopen(RENDER_TREE_LOG_FILE, "w");
   1297         DUMP_RENDER_LOGD("%s", data);
   1298         fclose(gRenderTreeFile);
   1299         gRenderTreeFile = 0;
   1300     } else {
   1301         // adb log can only output 1024 characters, so write out line by line.
   1302         // exclude '\n' as adb log adds it for each output.
   1303         int length = renderDump.length();
   1304         for (int i = 0, last = 0; i < length; i++) {
   1305             if (data[i] == '\n') {
   1306                 if (i != last)
   1307                     DUMP_RENDER_LOGD("%.*s", (i - last), &(data[last]));
   1308                 last = i + 1;
   1309             }
   1310         }
   1311     }
   1312 #endif
   1313 }
   1314 
   1315 void WebViewCore::dumpNavTree()
   1316 {
   1317 #if DUMP_NAV_CACHE
   1318     cacheBuilder().mDebug.print();
   1319 #endif
   1320 }
   1321 
   1322 WebCore::HTMLAnchorElement* WebViewCore::retrieveAnchorElement(WebCore::Frame* frame, WebCore::Node* node)
   1323 {
   1324     if (!CacheBuilder::validNode(m_mainFrame, frame, node))
   1325         return 0;
   1326     if (!node->hasTagName(WebCore::HTMLNames::aTag))
   1327         return 0;
   1328     return static_cast<WebCore::HTMLAnchorElement*>(node);
   1329 }
   1330 
   1331 WebCore::String WebViewCore::retrieveHref(WebCore::Frame* frame, WebCore::Node* node)
   1332 {
   1333     WebCore::HTMLAnchorElement* anchor = retrieveAnchorElement(frame, node);
   1334     return anchor ? anchor->href() : WebCore::String();
   1335 }
   1336 
   1337 WebCore::String WebViewCore::retrieveAnchorText(WebCore::Frame* frame, WebCore::Node* node)
   1338 {
   1339     WebCore::HTMLAnchorElement* anchor = retrieveAnchorElement(frame, node);
   1340     return anchor ? anchor->text() : WebCore::String();
   1341 }
   1342 
   1343 WebCore::String WebViewCore::requestLabel(WebCore::Frame* frame,
   1344         WebCore::Node* node)
   1345 {
   1346     if (node && CacheBuilder::validNode(m_mainFrame, frame, node)) {
   1347         RefPtr<WebCore::NodeList> list = node->document()->getElementsByTagName("label");
   1348         unsigned length = list->length();
   1349         for (unsigned i = 0; i < length; i++) {
   1350             WebCore::HTMLLabelElement* label = static_cast<WebCore::HTMLLabelElement*>(
   1351                     list->item(i));
   1352             if (label->correspondingControl() == node) {
   1353                 Node* node = label;
   1354                 String result;
   1355                 while ((node = node->traverseNextNode(label))) {
   1356                     if (node->isTextNode()) {
   1357                         Text* textNode = static_cast<Text*>(node);
   1358                         result += textNode->dataImpl();
   1359                     }
   1360                 }
   1361                 return result;
   1362             }
   1363         }
   1364     }
   1365     return WebCore::String();
   1366 }
   1367 
   1368 void WebViewCore::updateCacheOnNodeChange()
   1369 {
   1370     gCursorBoundsMutex.lock();
   1371     bool hasCursorBounds = m_hasCursorBounds;
   1372     Frame* frame = (Frame*) m_cursorFrame;
   1373     Node* node = (Node*) m_cursorNode;
   1374     IntRect bounds = m_cursorHitBounds;
   1375     gCursorBoundsMutex.unlock();
   1376     if (!hasCursorBounds || !node)
   1377         return;
   1378     if (CacheBuilder::validNode(m_mainFrame, frame, node)) {
   1379         RenderObject* renderer = node->renderer();
   1380         if (renderer && renderer->style()->visibility() != HIDDEN) {
   1381             IntRect absBox = renderer->absoluteBoundingBoxRect();
   1382             int globalX, globalY;
   1383             CacheBuilder::GetGlobalOffset(frame, &globalX, &globalY);
   1384             absBox.move(globalX, globalY);
   1385             if (absBox == bounds)
   1386                 return;
   1387             DBG_NAV_LOGD("absBox=(%d,%d,%d,%d) bounds=(%d,%d,%d,%d)",
   1388                 absBox.x(), absBox.y(), absBox.width(), absBox.height(),
   1389                 bounds.x(), bounds.y(), bounds.width(), bounds.height());
   1390         }
   1391     }
   1392     DBG_NAV_LOGD("updateFrameCache node=%p", node);
   1393     updateFrameCache();
   1394 }
   1395 
   1396 void WebViewCore::updateFrameCache()
   1397 {
   1398     if (!m_frameCacheOutOfDate) {
   1399         DBG_NAV_LOG("!m_frameCacheOutOfDate");
   1400         return;
   1401     }
   1402 #ifdef ANDROID_INSTRUMENT
   1403     TimeCounterAuto counter(TimeCounter::WebViewCoreBuildNavTimeCounter);
   1404 #endif
   1405     m_frameCacheOutOfDate = false;
   1406 #if DEBUG_NAV_UI
   1407     m_now = SkTime::GetMSecs();
   1408 #endif
   1409     m_temp = new CachedRoot();
   1410     m_temp->init(m_mainFrame, &m_history);
   1411 #if USE(ACCELERATED_COMPOSITING)
   1412     GraphicsLayerAndroid* graphicsLayer = graphicsRootLayer();
   1413     if (graphicsLayer)
   1414         m_temp->setRootLayer(graphicsLayer->contentLayer());
   1415 #endif
   1416     CacheBuilder& builder = cacheBuilder();
   1417     WebCore::Settings* settings = m_mainFrame->page()->settings();
   1418     builder.allowAllTextDetection();
   1419 #ifdef ANDROID_META_SUPPORT
   1420     if (settings) {
   1421         if (!settings->formatDetectionAddress())
   1422             builder.disallowAddressDetection();
   1423         if (!settings->formatDetectionEmail())
   1424             builder.disallowEmailDetection();
   1425         if (!settings->formatDetectionTelephone())
   1426             builder.disallowPhoneDetection();
   1427     }
   1428 #endif
   1429     builder.buildCache(m_temp);
   1430     m_tempPict = new SkPicture();
   1431     recordPicture(m_tempPict);
   1432     m_temp->setPicture(m_tempPict);
   1433     m_temp->setTextGeneration(m_textGeneration);
   1434     WebCoreViewBridge* window = m_mainFrame->view()->platformWidget();
   1435     m_temp->setVisibleRect(WebCore::IntRect(m_scrollOffsetX,
   1436         m_scrollOffsetY, window->width(), window->height()));
   1437     gFrameCacheMutex.lock();
   1438     delete m_frameCacheKit;
   1439     delete m_navPictureKit;
   1440     m_frameCacheKit = m_temp;
   1441     m_navPictureKit = m_tempPict;
   1442     m_updatedFrameCache = true;
   1443 #if DEBUG_NAV_UI
   1444     const CachedNode* cachedFocusNode = m_frameCacheKit->currentFocus();
   1445     DBG_NAV_LOGD("cachedFocusNode=%d (nodePointer=%p)",
   1446         cachedFocusNode ? cachedFocusNode->index() : 0,
   1447         cachedFocusNode ? cachedFocusNode->nodePointer() : 0);
   1448 #endif
   1449     gFrameCacheMutex.unlock();
   1450 }
   1451 
   1452 void WebViewCore::updateFrameCacheIfLoading()
   1453 {
   1454     if (!m_check_domtree_version)
   1455         updateFrameCache();
   1456 }
   1457 
   1458 ///////////////////////////////////////////////////////////////////////////////
   1459 
   1460 void WebViewCore::addPlugin(PluginWidgetAndroid* w)
   1461 {
   1462 //    SkDebugf("----------- addPlugin %p", w);
   1463     /* The plugin must be appended to the end of the array. This ensures that if
   1464        the plugin is added while iterating through the array (e.g. sendEvent(...))
   1465        that the iteration process is not corrupted.
   1466      */
   1467     *m_plugins.append() = w;
   1468 }
   1469 
   1470 void WebViewCore::removePlugin(PluginWidgetAndroid* w)
   1471 {
   1472 //    SkDebugf("----------- removePlugin %p", w);
   1473     int index = m_plugins.find(w);
   1474     if (index < 0) {
   1475         SkDebugf("--------------- pluginwindow not found! %p\n", w);
   1476     } else {
   1477         m_plugins.removeShuffle(index);
   1478     }
   1479 }
   1480 
   1481 bool WebViewCore::isPlugin(PluginWidgetAndroid* w) const
   1482 {
   1483     return m_plugins.find(w) >= 0;
   1484 }
   1485 
   1486 void WebViewCore::invalPlugin(PluginWidgetAndroid* w)
   1487 {
   1488     const double PLUGIN_INVAL_DELAY = 1.0 / 60;
   1489 
   1490     if (!m_pluginInvalTimer.isActive()) {
   1491         m_pluginInvalTimer.startOneShot(PLUGIN_INVAL_DELAY);
   1492     }
   1493 }
   1494 
   1495 void WebViewCore::drawPlugins()
   1496 {
   1497     SkRegion inval; // accumualte what needs to be redrawn
   1498     PluginWidgetAndroid** iter = m_plugins.begin();
   1499     PluginWidgetAndroid** stop = m_plugins.end();
   1500 
   1501     for (; iter < stop; ++iter) {
   1502         PluginWidgetAndroid* w = *iter;
   1503         SkIRect dirty;
   1504         if (w->isDirty(&dirty)) {
   1505             w->draw();
   1506             inval.op(dirty, SkRegion::kUnion_Op);
   1507         }
   1508     }
   1509 
   1510     if (!inval.isEmpty()) {
   1511         // inval.getBounds() is our rectangle
   1512         const SkIRect& bounds = inval.getBounds();
   1513         WebCore::IntRect r(bounds.fLeft, bounds.fTop,
   1514                            bounds.width(), bounds.height());
   1515         this->viewInvalidate(r);
   1516     }
   1517 }
   1518 
   1519 void WebViewCore::notifyPluginsOnFrameLoad(const Frame* frame) {
   1520     // if frame is the parent then notify all plugins
   1521     if (!frame->tree()->parent()) {
   1522         // trigger an event notifying the plugins that the page has loaded
   1523         ANPEvent event;
   1524         SkANP::InitEvent(&event, kLifecycle_ANPEventType);
   1525         event.data.lifecycle.action = kOnLoad_ANPLifecycleAction;
   1526         sendPluginEvent(event);
   1527     }
   1528     // else if frame's parent has completed
   1529     else if (!frame->tree()->parent()->loader()->isLoading()) {
   1530         // send to all plugins who have this frame in their heirarchy
   1531         PluginWidgetAndroid** iter = m_plugins.begin();
   1532         PluginWidgetAndroid** stop = m_plugins.end();
   1533         for (; iter < stop; ++iter) {
   1534             Frame* currentFrame = (*iter)->pluginView()->parentFrame();
   1535             while (currentFrame) {
   1536                 if (frame == currentFrame) {
   1537                     ANPEvent event;
   1538                     SkANP::InitEvent(&event, kLifecycle_ANPEventType);
   1539                     event.data.lifecycle.action = kOnLoad_ANPLifecycleAction;
   1540                     (*iter)->sendEvent(event);
   1541                     break;
   1542                 }
   1543                 currentFrame = currentFrame->tree()->parent();
   1544             }
   1545         }
   1546     }
   1547 }
   1548 
   1549 void WebViewCore::sendPluginVisibleScreen()
   1550 {
   1551     /* We may want to cache the previous values and only send the notification
   1552        to the plugin in the event that one of the values has changed.
   1553      */
   1554 
   1555     ANPRectI visibleRect;
   1556     visibleRect.left = m_scrollOffsetX;
   1557     visibleRect.top = m_scrollOffsetY;
   1558     visibleRect.right = m_scrollOffsetX + m_screenWidth;
   1559     visibleRect.bottom = m_scrollOffsetY + m_screenHeight;
   1560 
   1561     PluginWidgetAndroid** iter = m_plugins.begin();
   1562     PluginWidgetAndroid** stop = m_plugins.end();
   1563     for (; iter < stop; ++iter) {
   1564         (*iter)->setVisibleScreen(visibleRect, m_scale);
   1565     }
   1566 }
   1567 
   1568 void WebViewCore::sendPluginEvent(const ANPEvent& evt)
   1569 {
   1570     /* The list of plugins may be manipulated as we iterate through the list.
   1571        This implementation allows for the addition of new plugins during an
   1572        iteration, but may fail if a plugin is removed. Currently, there are not
   1573        any use cases where a plugin is deleted while processing this loop, but
   1574        if it does occur we will have to use an alternate data structure and/or
   1575        iteration mechanism.
   1576      */
   1577     for (int x = 0; x < m_plugins.count(); x++) {
   1578         m_plugins[x]->sendEvent(evt);
   1579     }
   1580 }
   1581 
   1582 PluginWidgetAndroid* WebViewCore::getPluginWidget(NPP npp)
   1583 {
   1584     PluginWidgetAndroid** iter = m_plugins.begin();
   1585     PluginWidgetAndroid** stop = m_plugins.end();
   1586     for (; iter < stop; ++iter) {
   1587         if ((*iter)->pluginView()->instance() == npp) {
   1588             return (*iter);
   1589         }
   1590     }
   1591     return NULL;
   1592 }
   1593 
   1594 static PluginView* nodeIsPlugin(Node* node) {
   1595     RenderObject* renderer = node->renderer();
   1596     if (renderer && renderer->isWidget()) {
   1597         Widget* widget = static_cast<RenderWidget*>(renderer)->widget();
   1598         if (widget && widget->isPluginView())
   1599             return static_cast<PluginView*>(widget);
   1600     }
   1601     return 0;
   1602 }
   1603 
   1604 Node* WebViewCore::cursorNodeIsPlugin() {
   1605     gCursorBoundsMutex.lock();
   1606     bool hasCursorBounds = m_hasCursorBounds;
   1607     Frame* frame = (Frame*) m_cursorFrame;
   1608     Node* node = (Node*) m_cursorNode;
   1609     gCursorBoundsMutex.unlock();
   1610     if (hasCursorBounds && CacheBuilder::validNode(m_mainFrame, frame, node)
   1611             && nodeIsPlugin(node)) {
   1612         return node;
   1613     }
   1614     return 0;
   1615 }
   1616 
   1617 ///////////////////////////////////////////////////////////////////////////////
   1618 void WebViewCore::moveMouseIfLatest(int moveGeneration,
   1619     WebCore::Frame* frame, int x, int y)
   1620 {
   1621     DBG_NAV_LOGD("m_moveGeneration=%d moveGeneration=%d"
   1622         " frame=%p x=%d y=%d",
   1623         m_moveGeneration, moveGeneration, frame, x, y);
   1624     if (m_moveGeneration > moveGeneration) {
   1625         DBG_NAV_LOGD("m_moveGeneration=%d > moveGeneration=%d",
   1626             m_moveGeneration, moveGeneration);
   1627         return; // short-circuit if a newer move has already been generated
   1628     }
   1629     m_lastGeneration = moveGeneration;
   1630     moveMouse(frame, x, y);
   1631 }
   1632 
   1633 void WebViewCore::moveFocus(WebCore::Frame* frame, WebCore::Node* node)
   1634 {
   1635     DBG_NAV_LOGD("frame=%p node=%p", frame, node);
   1636     if (!node || !CacheBuilder::validNode(m_mainFrame, frame, node)
   1637             || !node->isElementNode())
   1638         return;
   1639     // Code borrowed from FocusController::advanceFocus
   1640     WebCore::FocusController* focusController
   1641             = m_mainFrame->page()->focusController();
   1642     WebCore::Document* oldDoc
   1643             = focusController->focusedOrMainFrame()->document();
   1644     if (oldDoc->focusedNode() == node)
   1645         return;
   1646     if (node->document() != oldDoc)
   1647         oldDoc->setFocusedNode(0);
   1648     focusController->setFocusedFrame(frame);
   1649     static_cast<WebCore::Element*>(node)->focus(false);
   1650 }
   1651 
   1652 // Update mouse position
   1653 void WebViewCore::moveMouse(WebCore::Frame* frame, int x, int y)
   1654 {
   1655     DBG_NAV_LOGD("frame=%p x=%d y=%d scrollOffset=(%d,%d)", frame,
   1656         x, y, m_scrollOffsetX, m_scrollOffsetY);
   1657     if (!frame || CacheBuilder::validNode(m_mainFrame, frame, NULL) == false)
   1658         frame = m_mainFrame;
   1659     // mouse event expects the position in the window coordinate
   1660     m_mousePos = WebCore::IntPoint(x - m_scrollOffsetX, y - m_scrollOffsetY);
   1661     // validNode will still return true if the node is null, as long as we have
   1662     // a valid frame.  Do not want to make a call on frame unless it is valid.
   1663     WebCore::PlatformMouseEvent mouseEvent(m_mousePos, m_mousePos,
   1664         WebCore::NoButton, WebCore::MouseEventMoved, 1, false, false, false,
   1665         false, WTF::currentTime());
   1666     frame->eventHandler()->handleMouseMoveEvent(mouseEvent);
   1667     updateCacheOnNodeChange();
   1668 }
   1669 
   1670 void WebViewCore::setSelection(int start, int end)
   1671 {
   1672     WebCore::Node* focus = currentFocus();
   1673     if (!focus)
   1674         return;
   1675     WebCore::RenderObject* renderer = focus->renderer();
   1676     if (!renderer || (!renderer->isTextField() && !renderer->isTextArea()))
   1677         return;
   1678     WebCore::RenderTextControl* rtc = static_cast<WebCore::RenderTextControl*>(renderer);
   1679     if (start > end) {
   1680         int temp = start;
   1681         start = end;
   1682         end = temp;
   1683     }
   1684     // Tell our EditorClient that this change was generated from the UI, so it
   1685     // does not need to echo it to the UI.
   1686     EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
   1687             m_mainFrame->editor()->client());
   1688     client->setUiGeneratedSelectionChange(true);
   1689     rtc->setSelectionRange(start, end);
   1690     client->setUiGeneratedSelectionChange(false);
   1691     WebCore::Frame* focusedFrame = focus->document()->frame();
   1692     focusedFrame->revealSelection();
   1693     setFocusControllerActive(focusedFrame, true);
   1694 }
   1695 
   1696 void WebViewCore::deleteSelection(int start, int end, int textGeneration)
   1697 {
   1698     setSelection(start, end);
   1699     if (start == end)
   1700         return;
   1701     WebCore::Node* focus = currentFocus();
   1702     if (!focus)
   1703         return;
   1704     // Prevent our editor client from passing a message to change the
   1705     // selection.
   1706     EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
   1707             m_mainFrame->editor()->client());
   1708     client->setUiGeneratedSelectionChange(true);
   1709     PlatformKeyboardEvent down(AKEYCODE_DEL, 0, 0, true, false, false, false);
   1710     PlatformKeyboardEvent up(AKEYCODE_DEL, 0, 0, false, false, false, false);
   1711     key(down);
   1712     key(up);
   1713     client->setUiGeneratedSelectionChange(false);
   1714     m_textGeneration = textGeneration;
   1715 }
   1716 
   1717 void WebViewCore::replaceTextfieldText(int oldStart,
   1718         int oldEnd, const WebCore::String& replace, int start, int end,
   1719         int textGeneration)
   1720 {
   1721     WebCore::Node* focus = currentFocus();
   1722     if (!focus)
   1723         return;
   1724     setSelection(oldStart, oldEnd);
   1725     // Prevent our editor client from passing a message to change the
   1726     // selection.
   1727     EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
   1728             m_mainFrame->editor()->client());
   1729     client->setUiGeneratedSelectionChange(true);
   1730     WebCore::TypingCommand::insertText(focus->document(), replace,
   1731         false);
   1732     client->setUiGeneratedSelectionChange(false);
   1733     setSelection(start, end);
   1734     m_textGeneration = textGeneration;
   1735 }
   1736 
   1737 void WebViewCore::passToJs(int generation, const WebCore::String& current,
   1738     const PlatformKeyboardEvent& event)
   1739 {
   1740     WebCore::Node* focus = currentFocus();
   1741     if (!focus) {
   1742         DBG_NAV_LOG("!focus");
   1743         clearTextEntry();
   1744         return;
   1745     }
   1746     WebCore::RenderObject* renderer = focus->renderer();
   1747     if (!renderer || (!renderer->isTextField() && !renderer->isTextArea())) {
   1748         DBG_NAV_LOGD("renderer==%p || not text", renderer);
   1749         clearTextEntry();
   1750         return;
   1751     }
   1752     // Block text field updates during a key press.
   1753     m_blockTextfieldUpdates = true;
   1754     // Also prevent our editor client from passing a message to change the
   1755     // selection.
   1756     EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
   1757             m_mainFrame->editor()->client());
   1758     client->setUiGeneratedSelectionChange(true);
   1759     key(event);
   1760     client->setUiGeneratedSelectionChange(false);
   1761     m_blockTextfieldUpdates = false;
   1762     m_textGeneration = generation;
   1763     setFocusControllerActive(focus->document()->frame(), true);
   1764     WebCore::RenderTextControl* renderText =
   1765         static_cast<WebCore::RenderTextControl*>(renderer);
   1766     WebCore::String test = renderText->text();
   1767     if (test == current) {
   1768         DBG_NAV_LOG("test == current");
   1769         return;
   1770     }
   1771     // If the text changed during the key event, update the UI text field.
   1772     updateTextfield(focus, false, test);
   1773 }
   1774 
   1775 void WebViewCore::scrollFocusedTextInput(float xPercent, int y)
   1776 {
   1777     WebCore::Node* focus = currentFocus();
   1778     if (!focus) {
   1779         DBG_NAV_LOG("!focus");
   1780         clearTextEntry();
   1781         return;
   1782     }
   1783     WebCore::RenderObject* renderer = focus->renderer();
   1784     if (!renderer || (!renderer->isTextField() && !renderer->isTextArea())) {
   1785         DBG_NAV_LOGD("renderer==%p || not text", renderer);
   1786         clearTextEntry();
   1787         return;
   1788     }
   1789     WebCore::RenderTextControl* renderText =
   1790         static_cast<WebCore::RenderTextControl*>(renderer);
   1791     int x = (int) (xPercent * (renderText->scrollWidth() -
   1792         renderText->clientWidth()));
   1793     DBG_NAV_LOGD("x=%d y=%d xPercent=%g scrollW=%d clientW=%d", x, y,
   1794         xPercent, renderText->scrollWidth(), renderText->clientWidth());
   1795     renderText->setScrollLeft(x);
   1796     renderText->setScrollTop(y);
   1797 }
   1798 
   1799 void WebViewCore::setFocusControllerActive(WebCore::Frame* frame, bool active)
   1800 {
   1801     if (!frame) {
   1802         WebCore::Node* focus = currentFocus();
   1803         if (focus)
   1804             frame = focus->document()->frame();
   1805         else
   1806             frame = m_mainFrame;
   1807     }
   1808     WebCore::FocusController* controller = frame->page()->focusController();
   1809     controller->setActive(active);
   1810     controller->setFocused(active);
   1811 }
   1812 
   1813 void WebViewCore::saveDocumentState(WebCore::Frame* frame)
   1814 {
   1815     if (!CacheBuilder::validNode(m_mainFrame, frame, 0))
   1816         frame = m_mainFrame;
   1817     WebCore::HistoryItem *item = frame->loader()->history()->currentItem();
   1818 
   1819     // item can be null when there is no offical URL for the current page. This happens
   1820     // when the content is loaded using with WebCoreFrameBridge::LoadData() and there
   1821     // is no failing URL (common case is when content is loaded using data: scheme)
   1822     if (item) {
   1823         item->setDocumentState(frame->document()->formElementsState());
   1824     }
   1825 }
   1826 
   1827 // Convert a WebCore::String into an array of characters where the first
   1828 // character represents the length, for easy conversion to java.
   1829 static uint16_t* stringConverter(const WebCore::String& text)
   1830 {
   1831     size_t length = text.length();
   1832     uint16_t* itemName = new uint16_t[length+1];
   1833     itemName[0] = (uint16_t)length;
   1834     uint16_t* firstChar = &(itemName[1]);
   1835     memcpy((void*)firstChar, text.characters(), sizeof(UChar)*length);
   1836     return itemName;
   1837 }
   1838 
   1839 // Response to dropdown created for a listbox.
   1840 class ListBoxReply : public WebCoreReply {
   1841 public:
   1842     ListBoxReply(WebCore::HTMLSelectElement* select, WebCore::Frame* frame, WebViewCore* view)
   1843         : m_select(select)
   1844         , m_frame(frame)
   1845         , m_viewImpl(view)
   1846     {}
   1847 
   1848     // Response used if the listbox only allows single selection.
   1849     // index is listIndex of the selected item, or -1 if nothing is selected.
   1850     virtual void replyInt(int index)
   1851     {
   1852         if (-2 == index) {
   1853             // Special value for cancel. Do nothing.
   1854             return;
   1855         }
   1856         // If the select element no longer exists, due to a page change, etc,
   1857         // silently return.
   1858         if (!m_select || !CacheBuilder::validNode(m_viewImpl->m_mainFrame,
   1859                 m_frame, m_select))
   1860             return;
   1861         // Use a pointer to HTMLSelectElement's superclass, where
   1862         // listToOptionIndex is public.
   1863         SelectElement* selectElement = m_select;
   1864         int optionIndex = selectElement->listToOptionIndex(index);
   1865         m_select->setSelectedIndex(optionIndex, true);
   1866         m_select->dispatchFormControlChangeEvent();
   1867         m_viewImpl->contentInvalidate(m_select->getRect());
   1868     }
   1869 
   1870     // Response if the listbox allows multiple selection.  array stores the listIndices
   1871     // of selected positions.
   1872     virtual void replyIntArray(const int* array, int count)
   1873     {
   1874         // If the select element no longer exists, due to a page change, etc,
   1875         // silently return.
   1876         if (!m_select || !CacheBuilder::validNode(m_viewImpl->m_mainFrame,
   1877                 m_frame, m_select))
   1878             return;
   1879 
   1880         // If count is 1 or 0, use replyInt.
   1881         SkASSERT(count > 1);
   1882 
   1883         const WTF::Vector<Element*>& items = m_select->listItems();
   1884         int totalItems = static_cast<int>(items.size());
   1885         // Keep track of the position of the value we are comparing against.
   1886         int arrayIndex = 0;
   1887         // The value we are comparing against.
   1888         int selection = array[arrayIndex];
   1889         WebCore::HTMLOptionElement* option;
   1890         for (int listIndex = 0; listIndex < totalItems; listIndex++) {
   1891             if (items[listIndex]->hasLocalName(WebCore::HTMLNames::optionTag)) {
   1892                 option = static_cast<WebCore::HTMLOptionElement*>(
   1893                         items[listIndex]);
   1894                 if (listIndex == selection) {
   1895                     option->setSelectedState(true);
   1896                     arrayIndex++;
   1897                     if (arrayIndex == count)
   1898                         selection = -1;
   1899                     else
   1900                         selection = array[arrayIndex];
   1901                 } else
   1902                     option->setSelectedState(false);
   1903             }
   1904         }
   1905         m_select->dispatchFormControlChangeEvent();
   1906         m_viewImpl->contentInvalidate(m_select->getRect());
   1907     }
   1908 private:
   1909     // The select element associated with this listbox.
   1910     WebCore::HTMLSelectElement* m_select;
   1911     // The frame of this select element, to verify that it is valid.
   1912     WebCore::Frame* m_frame;
   1913     // For calling invalidate and checking the select element's validity
   1914     WebViewCore* m_viewImpl;
   1915 };
   1916 
   1917 // Create an array of java Strings.
   1918 static jobjectArray makeLabelArray(JNIEnv* env, const uint16_t** labels, size_t count)
   1919 {
   1920     jclass stringClass = env->FindClass("java/lang/String");
   1921     LOG_ASSERT(stringClass, "Could not find java/lang/String");
   1922     jobjectArray array = env->NewObjectArray(count, stringClass, 0);
   1923     LOG_ASSERT(array, "Could not create new string array");
   1924 
   1925     for (size_t i = 0; i < count; i++) {
   1926         jobject newString = env->NewString(&labels[i][1], labels[i][0]);
   1927         env->SetObjectArrayElement(array, i, newString);
   1928         env->DeleteLocalRef(newString);
   1929         checkException(env);
   1930     }
   1931     env->DeleteLocalRef(stringClass);
   1932     return array;
   1933 }
   1934 
   1935 void WebViewCore::openFileChooser(PassRefPtr<WebCore::FileChooser> chooser) {
   1936     if (!chooser)
   1937         return;
   1938     JNIEnv* env = JSC::Bindings::getJNIEnv();
   1939     jstring jName = (jstring) env->CallObjectMethod(
   1940             m_javaGlue->object(env).get(), m_javaGlue->m_openFileChooser);
   1941     checkException(env);
   1942     const UChar* string = (const UChar*) env->GetStringChars(jName, NULL);
   1943     if (!string)
   1944         return;
   1945     WebCore::String webcoreString = to_string(env, jName);
   1946     env->ReleaseStringChars(jName, string);
   1947     chooser->chooseFile(webcoreString);
   1948 }
   1949 
   1950 void WebViewCore::listBoxRequest(WebCoreReply* reply, const uint16_t** labels, size_t count, const int enabled[], size_t enabledCount,
   1951         bool multiple, const int selected[], size_t selectedCountOrSelection)
   1952 {
   1953     // If m_popupReply is not null, then we already have a list showing.
   1954     if (m_popupReply != 0)
   1955         return;
   1956 
   1957     LOG_ASSERT(m_javaGlue->m_obj, "No java widget associated with this view!");
   1958 
   1959     // Create an array of java Strings for the drop down.
   1960     JNIEnv* env = JSC::Bindings::getJNIEnv();
   1961     jobjectArray labelArray = makeLabelArray(env, labels, count);
   1962 
   1963     // Create an array determining whether each item is enabled.
   1964     jintArray enabledArray = env->NewIntArray(enabledCount);
   1965     checkException(env);
   1966     jint* ptrArray = env->GetIntArrayElements(enabledArray, 0);
   1967     checkException(env);
   1968     for (size_t i = 0; i < enabledCount; i++) {
   1969         ptrArray[i] = enabled[i];
   1970     }
   1971     env->ReleaseIntArrayElements(enabledArray, ptrArray, 0);
   1972     checkException(env);
   1973 
   1974     if (multiple) {
   1975         // Pass up an array representing which items are selected.
   1976         jintArray selectedArray = env->NewIntArray(selectedCountOrSelection);
   1977         checkException(env);
   1978         jint* selArray = env->GetIntArrayElements(selectedArray, 0);
   1979         checkException(env);
   1980         for (size_t i = 0; i < selectedCountOrSelection; i++) {
   1981             selArray[i] = selected[i];
   1982         }
   1983         env->ReleaseIntArrayElements(selectedArray, selArray, 0);
   1984 
   1985         env->CallVoidMethod(m_javaGlue->object(env).get(),
   1986                 m_javaGlue->m_requestListBox, labelArray, enabledArray,
   1987                 selectedArray);
   1988         env->DeleteLocalRef(selectedArray);
   1989     } else {
   1990         // Pass up the single selection.
   1991         env->CallVoidMethod(m_javaGlue->object(env).get(),
   1992                 m_javaGlue->m_requestSingleListBox, labelArray, enabledArray,
   1993                 selectedCountOrSelection);
   1994     }
   1995 
   1996     env->DeleteLocalRef(labelArray);
   1997     env->DeleteLocalRef(enabledArray);
   1998     checkException(env);
   1999 
   2000     Retain(reply);
   2001     m_popupReply = reply;
   2002 }
   2003 
   2004 bool WebViewCore::key(const PlatformKeyboardEvent& event)
   2005 {
   2006     WebCore::EventHandler* eventHandler = m_mainFrame->eventHandler();
   2007     WebCore::Node* focusNode = currentFocus();
   2008     if (focusNode)
   2009         eventHandler = focusNode->document()->frame()->eventHandler();
   2010     DBG_NAV_LOGD("keyCode=%s unichar=%d focusNode=%p",
   2011         event.keyIdentifier().utf8().data(), event.unichar(), focusNode);
   2012     return eventHandler->keyEvent(event);
   2013 }
   2014 
   2015 // For when the user clicks the trackball
   2016 void WebViewCore::click(WebCore::Frame* frame, WebCore::Node* node) {
   2017     if (!node) {
   2018         WebCore::IntPoint pt = m_mousePos;
   2019         pt.move(m_scrollOffsetX, m_scrollOffsetY);
   2020         WebCore::HitTestResult hitTestResult = m_mainFrame->eventHandler()->
   2021                 hitTestResultAtPoint(pt, false);
   2022         node = hitTestResult.innerNode();
   2023         frame = node->document()->frame();
   2024         DBG_NAV_LOGD("m_mousePos=(%d,%d) m_scrollOffset=(%d,%d) pt=(%d,%d)"
   2025             " node=%p", m_mousePos.x(), m_mousePos.y(),
   2026             m_scrollOffsetX, m_scrollOffsetY, pt.x(), pt.y(), node);
   2027     }
   2028     if (node) {
   2029         EditorClientAndroid* client
   2030                 = static_cast<EditorClientAndroid*>(
   2031                 m_mainFrame->editor()->client());
   2032         client->setShouldChangeSelectedRange(false);
   2033         handleMouseClick(frame, node);
   2034         client->setShouldChangeSelectedRange(true);
   2035     }
   2036 }
   2037 
   2038 #if USE(ACCELERATED_COMPOSITING)
   2039 GraphicsLayerAndroid* WebViewCore::graphicsRootLayer() const
   2040 {
   2041     RenderView* contentRenderer = m_mainFrame->contentRenderer();
   2042     if (!contentRenderer)
   2043         return 0;
   2044     return static_cast<GraphicsLayerAndroid*>(
   2045           contentRenderer->compositor()->rootPlatformLayer());
   2046 }
   2047 #endif
   2048 
   2049 bool WebViewCore::handleTouchEvent(int action, int x, int y, int metaState)
   2050 {
   2051     bool preventDefault = false;
   2052 
   2053 #if USE(ACCELERATED_COMPOSITING)
   2054     GraphicsLayerAndroid* rootLayer = graphicsRootLayer();
   2055     if (rootLayer)
   2056       rootLayer->pauseDisplay(true);
   2057 #endif
   2058 
   2059 #if ENABLE(TOUCH_EVENTS) // Android
   2060     WebCore::TouchEventType type = WebCore::TouchStart;
   2061     WebCore::PlatformTouchPoint::State touchState = WebCore::PlatformTouchPoint::TouchPressed;
   2062     switch (action) {
   2063     case 0: // MotionEvent.ACTION_DOWN
   2064         type = WebCore::TouchStart;
   2065         break;
   2066     case 1: // MotionEvent.ACTION_UP
   2067         type = WebCore::TouchEnd;
   2068         touchState = WebCore::PlatformTouchPoint::TouchReleased;
   2069         break;
   2070     case 2: // MotionEvent.ACTION_MOVE
   2071         type = WebCore::TouchMove;
   2072         touchState = WebCore::PlatformTouchPoint::TouchMoved;
   2073         break;
   2074     case 3: // MotionEvent.ACTION_CANCEL
   2075         type = WebCore::TouchCancel;
   2076         touchState = WebCore::PlatformTouchPoint::TouchCancelled;
   2077         break;
   2078     case 0x100: // WebViewCore.ACTION_LONGPRESS
   2079         type = WebCore::TouchLongPress;
   2080         touchState = WebCore::PlatformTouchPoint::TouchPressed;
   2081         break;
   2082     case 0x200: // WebViewCore.ACTION_DOUBLETAP
   2083         type = WebCore::TouchDoubleTap;
   2084         touchState = WebCore::PlatformTouchPoint::TouchPressed;
   2085         break;
   2086     default:
   2087         // We do not support other kinds of touch event inside WebCore
   2088         // at the moment.
   2089         LOGW("Java passed a touch event type that we do not support in WebCore: %d", action);
   2090         return 0;
   2091     }
   2092 
   2093     // Track previous touch and if stationary set the state.
   2094     WebCore::IntPoint pt(x - m_scrollOffsetX, y - m_scrollOffsetY);
   2095 
   2096 //  handleTouchEvent() in EventHandler.cpp doesn't handle TouchStationary, which
   2097 //  causes preventDefault be false when it returns. As our Java side may continue
   2098 //  process the events if WebKit doesn't, it can cause unexpected result.
   2099 //    if (type == WebCore::TouchMove && pt == m_lastTouchPoint)
   2100 //        touchState = WebCore::PlatformTouchPoint::TouchStationary;
   2101 
   2102     m_lastTouchPoint = pt;
   2103 
   2104     WebCore::PlatformTouchEvent te(pt, type, touchState, metaState);
   2105     preventDefault = m_mainFrame->eventHandler()->handleTouchEvent(te);
   2106 #endif
   2107 
   2108 #if USE(ACCELERATED_COMPOSITING)
   2109     if (rootLayer)
   2110       rootLayer->pauseDisplay(false);
   2111 #endif
   2112     return preventDefault;
   2113 }
   2114 
   2115 void WebViewCore::touchUp(int touchGeneration,
   2116     WebCore::Frame* frame, WebCore::Node* node, int x, int y)
   2117 {
   2118     if (m_touchGeneration > touchGeneration) {
   2119         DBG_NAV_LOGD("m_touchGeneration=%d > touchGeneration=%d"
   2120             " x=%d y=%d", m_touchGeneration, touchGeneration, x, y);
   2121         return; // short circuit if a newer touch has been generated
   2122     }
   2123     // This moves m_mousePos to the correct place, and handleMouseClick uses
   2124     // m_mousePos to determine where the click happens.
   2125     moveMouse(frame, x, y);
   2126     m_lastGeneration = touchGeneration;
   2127     if (frame && CacheBuilder::validNode(m_mainFrame, frame, 0)) {
   2128         frame->loader()->resetMultipleFormSubmissionProtection();
   2129     }
   2130     DBG_NAV_LOGD("touchGeneration=%d handleMouseClick frame=%p node=%p"
   2131         " x=%d y=%d", touchGeneration, frame, node, x, y);
   2132     handleMouseClick(frame, node);
   2133 }
   2134 
   2135 // Common code for both clicking with the trackball and touchUp
   2136 bool WebViewCore::handleMouseClick(WebCore::Frame* framePtr, WebCore::Node* nodePtr)
   2137 {
   2138     bool valid = framePtr == NULL
   2139             || CacheBuilder::validNode(m_mainFrame, framePtr, nodePtr);
   2140     WebFrame* webFrame = WebFrame::getWebFrame(m_mainFrame);
   2141     if (valid && nodePtr) {
   2142     // Need to special case area tags because an image map could have an area element in the middle
   2143     // so when attempting to get the default, the point chosen would be follow the wrong link.
   2144         if (nodePtr->hasTagName(WebCore::HTMLNames::areaTag)) {
   2145             webFrame->setUserInitiatedClick(true);
   2146             nodePtr->dispatchSimulatedClick(0, true, true);
   2147             webFrame->setUserInitiatedClick(false);
   2148             DBG_NAV_LOG("area");
   2149             return true;
   2150         }
   2151         WebCore::RenderObject* renderer = nodePtr->renderer();
   2152         if (renderer && (renderer->isMenuList() || renderer->isListBox())) {
   2153             WebCore::HTMLSelectElement* select = static_cast<WebCore::HTMLSelectElement*>(nodePtr);
   2154             const WTF::Vector<WebCore::Element*>& listItems = select->listItems();
   2155             SkTDArray<const uint16_t*> names;
   2156             // Possible values for enabledArray.  Keep in Sync with values in
   2157             // InvokeListBox.Container in WebView.java
   2158             enum OptionStatus {
   2159                 OPTGROUP = -1,
   2160                 OPTION_DISABLED = 0,
   2161                 OPTION_ENABLED = 1,
   2162             };
   2163             SkTDArray<int> enabledArray;
   2164             SkTDArray<int> selectedArray;
   2165             int size = listItems.size();
   2166             bool multiple = select->multiple();
   2167             for (int i = 0; i < size; i++) {
   2168                 if (listItems[i]->hasTagName(WebCore::HTMLNames::optionTag)) {
   2169                     WebCore::HTMLOptionElement* option = static_cast<WebCore::HTMLOptionElement*>(listItems[i]);
   2170                     *names.append() = stringConverter(option->textIndentedToRespectGroupLabel());
   2171                     *enabledArray.append() = option->disabled() ? OPTION_DISABLED : OPTION_ENABLED;
   2172                     if (multiple && option->selected())
   2173                         *selectedArray.append() = i;
   2174                 } else if (listItems[i]->hasTagName(WebCore::HTMLNames::optgroupTag)) {
   2175                     WebCore::HTMLOptGroupElement* optGroup = static_cast<WebCore::HTMLOptGroupElement*>(listItems[i]);
   2176                     *names.append() = stringConverter(optGroup->groupLabelText());
   2177                     *enabledArray.append() = OPTGROUP;
   2178                 }
   2179             }
   2180             WebCoreReply* reply = new ListBoxReply(select, select->document()->frame(), this);
   2181             // Use a pointer to HTMLSelectElement's superclass, where
   2182             // optionToListIndex is public.
   2183             SelectElement* selectElement = select;
   2184             listBoxRequest(reply, names.begin(), size, enabledArray.begin(), enabledArray.count(),
   2185                     multiple, selectedArray.begin(), multiple ? selectedArray.count() :
   2186                     selectElement->optionToListIndex(select->selectedIndex()));
   2187             DBG_NAV_LOG("menu list");
   2188             return true;
   2189         }
   2190     }
   2191     if (!valid || !framePtr)
   2192         framePtr = m_mainFrame;
   2193     webFrame->setUserInitiatedClick(true);
   2194     WebCore::PlatformMouseEvent mouseDown(m_mousePos, m_mousePos, WebCore::LeftButton,
   2195             WebCore::MouseEventPressed, 1, false, false, false, false,
   2196             WTF::currentTime());
   2197     // ignore the return from as it will return true if the hit point can trigger selection change
   2198     framePtr->eventHandler()->handleMousePressEvent(mouseDown);
   2199     WebCore::PlatformMouseEvent mouseUp(m_mousePos, m_mousePos, WebCore::LeftButton,
   2200             WebCore::MouseEventReleased, 1, false, false, false, false,
   2201             WTF::currentTime());
   2202     bool handled = framePtr->eventHandler()->handleMouseReleaseEvent(mouseUp);
   2203     webFrame->setUserInitiatedClick(false);
   2204 
   2205     // If the user clicked on a textfield, make the focusController active
   2206     // so we show the blinking cursor.
   2207     WebCore::Node* focusNode = currentFocus();
   2208     DBG_NAV_LOGD("m_mousePos={%d,%d} focusNode=%p handled=%s", m_mousePos.x(),
   2209         m_mousePos.y(), focusNode, handled ? "true" : "false");
   2210     if (focusNode) {
   2211         WebCore::RenderObject* renderer = focusNode->renderer();
   2212         if (renderer && (renderer->isTextField() || renderer->isTextArea())) {
   2213             bool ime = !(static_cast<WebCore::HTMLInputElement*>(focusNode))
   2214                     ->readOnly();
   2215             setFocusControllerActive(framePtr, ime);
   2216             if (ime) {
   2217                 RenderTextControl* rtc
   2218                         = static_cast<RenderTextControl*> (renderer);
   2219                 requestKeyboardWithSelection(focusNode, rtc->selectionStart(),
   2220                         rtc->selectionEnd());
   2221             } else {
   2222                 requestKeyboard(false);
   2223             }
   2224         }
   2225     }
   2226     return handled;
   2227 }
   2228 
   2229 void WebViewCore::popupReply(int index)
   2230 {
   2231     if (m_popupReply) {
   2232         m_popupReply->replyInt(index);
   2233         Release(m_popupReply);
   2234         m_popupReply = 0;
   2235     }
   2236 }
   2237 
   2238 void WebViewCore::popupReply(const int* array, int count)
   2239 {
   2240     if (m_popupReply) {
   2241         m_popupReply->replyIntArray(array, count);
   2242         Release(m_popupReply);
   2243         m_popupReply = NULL;
   2244     }
   2245 }
   2246 
   2247 void WebViewCore::addMessageToConsole(const WebCore::String& message, unsigned int lineNumber, const WebCore::String& sourceID, int msgLevel) {
   2248     JNIEnv* env = JSC::Bindings::getJNIEnv();
   2249     jstring jMessageStr = env->NewString((unsigned short *)message.characters(), message.length());
   2250     jstring jSourceIDStr = env->NewString((unsigned short *)sourceID.characters(), sourceID.length());
   2251     env->CallVoidMethod(m_javaGlue->object(env).get(),
   2252             m_javaGlue->m_addMessageToConsole, jMessageStr, lineNumber,
   2253             jSourceIDStr, msgLevel);
   2254     env->DeleteLocalRef(jMessageStr);
   2255     env->DeleteLocalRef(jSourceIDStr);
   2256     checkException(env);
   2257 }
   2258 
   2259 void WebViewCore::jsAlert(const WebCore::String& url, const WebCore::String& text)
   2260 {
   2261     JNIEnv* env = JSC::Bindings::getJNIEnv();
   2262     jstring jInputStr = env->NewString((unsigned short *)text.characters(), text.length());
   2263     jstring jUrlStr = env->NewString((unsigned short *)url.characters(), url.length());
   2264     env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_jsAlert, jUrlStr, jInputStr);
   2265     env->DeleteLocalRef(jInputStr);
   2266     env->DeleteLocalRef(jUrlStr);
   2267     checkException(env);
   2268 }
   2269 
   2270 void WebViewCore::exceededDatabaseQuota(const WebCore::String& url, const WebCore::String& databaseIdentifier, const unsigned long long currentQuota, unsigned long long estimatedSize)
   2271 {
   2272 #if ENABLE(DATABASE)
   2273     JNIEnv* env = JSC::Bindings::getJNIEnv();
   2274     jstring jDatabaseIdentifierStr = env->NewString((unsigned short *)databaseIdentifier.characters(), databaseIdentifier.length());
   2275     jstring jUrlStr = env->NewString((unsigned short *)url.characters(), url.length());
   2276     env->CallVoidMethod(m_javaGlue->object(env).get(),
   2277             m_javaGlue->m_exceededDatabaseQuota, jUrlStr,
   2278             jDatabaseIdentifierStr, currentQuota, estimatedSize);
   2279     env->DeleteLocalRef(jDatabaseIdentifierStr);
   2280     env->DeleteLocalRef(jUrlStr);
   2281     checkException(env);
   2282 #endif
   2283 }
   2284 
   2285 void WebViewCore::reachedMaxAppCacheSize(const unsigned long long spaceNeeded)
   2286 {
   2287 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
   2288     JNIEnv* env = JSC::Bindings::getJNIEnv();
   2289     env->CallVoidMethod(m_javaGlue->object(env).get(),
   2290             m_javaGlue->m_reachedMaxAppCacheSize, spaceNeeded);
   2291     checkException(env);
   2292 #endif
   2293 }
   2294 
   2295 void WebViewCore::populateVisitedLinks(WebCore::PageGroup* group)
   2296 {
   2297     m_groupForVisitedLinks = group;
   2298     JNIEnv* env = JSC::Bindings::getJNIEnv();
   2299     env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_populateVisitedLinks);
   2300     checkException(env);
   2301 }
   2302 
   2303 void WebViewCore::geolocationPermissionsShowPrompt(const WebCore::String& origin)
   2304 {
   2305     JNIEnv* env = JSC::Bindings::getJNIEnv();
   2306     jstring originString = env->NewString((unsigned short *)origin.characters(), origin.length());
   2307     env->CallVoidMethod(m_javaGlue->object(env).get(),
   2308                         m_javaGlue->m_geolocationPermissionsShowPrompt,
   2309                         originString);
   2310     env->DeleteLocalRef(originString);
   2311     checkException(env);
   2312 }
   2313 
   2314 void WebViewCore::geolocationPermissionsHidePrompt()
   2315 {
   2316     JNIEnv* env = JSC::Bindings::getJNIEnv();
   2317     env->CallVoidMethod(m_javaGlue->object(env).get(),
   2318                         m_javaGlue->m_geolocationPermissionsHidePrompt);
   2319     checkException(env);
   2320 }
   2321 
   2322 bool WebViewCore::jsConfirm(const WebCore::String& url, const WebCore::String& text)
   2323 {
   2324     JNIEnv* env = JSC::Bindings::getJNIEnv();
   2325     jstring jInputStr = env->NewString((unsigned short *)text.characters(), text.length());
   2326     jstring jUrlStr = env->NewString((unsigned short *)url.characters(), url.length());
   2327     jboolean result = env->CallBooleanMethod(m_javaGlue->object(env).get(), m_javaGlue->m_jsConfirm, jUrlStr, jInputStr);
   2328     env->DeleteLocalRef(jInputStr);
   2329     env->DeleteLocalRef(jUrlStr);
   2330     checkException(env);
   2331     return result;
   2332 }
   2333 
   2334 bool WebViewCore::jsPrompt(const WebCore::String& url, const WebCore::String& text, const WebCore::String& defaultValue, WebCore::String& result)
   2335 {
   2336     JNIEnv* env = JSC::Bindings::getJNIEnv();
   2337     jstring jInputStr = env->NewString((unsigned short *)text.characters(), text.length());
   2338     jstring jDefaultStr = env->NewString((unsigned short *)defaultValue.characters(), defaultValue.length());
   2339     jstring jUrlStr = env->NewString((unsigned short *)url.characters(), url.length());
   2340     jstring returnVal = (jstring) env->CallObjectMethod(m_javaGlue->object(env).get(), m_javaGlue->m_jsPrompt, jUrlStr, jInputStr, jDefaultStr);
   2341     // If returnVal is null, it means that the user cancelled the dialog.
   2342     if (!returnVal)
   2343         return false;
   2344 
   2345     result = to_string(env, returnVal);
   2346     env->DeleteLocalRef(jInputStr);
   2347     env->DeleteLocalRef(jDefaultStr);
   2348     env->DeleteLocalRef(jUrlStr);
   2349     checkException(env);
   2350     return true;
   2351 }
   2352 
   2353 bool WebViewCore::jsUnload(const WebCore::String& url, const WebCore::String& message)
   2354 {
   2355     JNIEnv* env = JSC::Bindings::getJNIEnv();
   2356     jstring jInputStr = env->NewString((unsigned short *)message.characters(), message.length());
   2357     jstring jUrlStr = env->NewString((unsigned short *)url.characters(), url.length());
   2358     jboolean result = env->CallBooleanMethod(m_javaGlue->object(env).get(), m_javaGlue->m_jsUnload, jUrlStr, jInputStr);
   2359     env->DeleteLocalRef(jInputStr);
   2360     env->DeleteLocalRef(jUrlStr);
   2361     checkException(env);
   2362     return result;
   2363 }
   2364 
   2365 bool WebViewCore::jsInterrupt()
   2366 {
   2367     JNIEnv* env = JSC::Bindings::getJNIEnv();
   2368     jboolean result = env->CallBooleanMethod(m_javaGlue->object(env).get(), m_javaGlue->m_jsInterrupt);
   2369     checkException(env);
   2370     return result;
   2371 }
   2372 
   2373 AutoJObject
   2374 WebViewCore::getJavaObject()
   2375 {
   2376     return getRealObject(JSC::Bindings::getJNIEnv(), m_javaGlue->m_obj);
   2377 }
   2378 
   2379 jobject
   2380 WebViewCore::getWebViewJavaObject()
   2381 {
   2382     JNIEnv* env = JSC::Bindings::getJNIEnv();
   2383     return env->GetObjectField(m_javaGlue->object(env).get(), gWebViewCoreFields.m_webView);
   2384 }
   2385 
   2386 void WebViewCore::updateTextSelection() {
   2387     WebCore::Node* focusNode = currentFocus();
   2388     if (!focusNode)
   2389         return;
   2390     RenderObject* renderer = focusNode->renderer();
   2391     if (!renderer || (!renderer->isTextArea() && !renderer->isTextField()))
   2392         return;
   2393     RenderTextControl* rtc = static_cast<RenderTextControl*>(renderer);
   2394     JNIEnv* env = JSC::Bindings::getJNIEnv();
   2395     env->CallVoidMethod(m_javaGlue->object(env).get(),
   2396             m_javaGlue->m_updateTextSelection, reinterpret_cast<int>(focusNode),
   2397             rtc->selectionStart(), rtc->selectionEnd(), m_textGeneration);
   2398     checkException(env);
   2399 }
   2400 
   2401 void WebViewCore::updateTextfield(WebCore::Node* ptr, bool changeToPassword,
   2402         const WebCore::String& text)
   2403 {
   2404     if (m_blockTextfieldUpdates)
   2405         return;
   2406     JNIEnv* env = JSC::Bindings::getJNIEnv();
   2407     if (changeToPassword) {
   2408         env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_updateTextfield,
   2409                 (int) ptr, true, 0, m_textGeneration);
   2410         checkException(env);
   2411         return;
   2412     }
   2413     int length = text.length();
   2414     jstring string = env->NewString((unsigned short *) text.characters(), length);
   2415     env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_updateTextfield,
   2416             (int) ptr, false, string, m_textGeneration);
   2417     env->DeleteLocalRef(string);
   2418     checkException(env);
   2419 }
   2420 
   2421 void WebViewCore::clearTextEntry()
   2422 {
   2423     JNIEnv* env = JSC::Bindings::getJNIEnv();
   2424     env->CallVoidMethod(m_javaGlue->object(env).get(),
   2425         m_javaGlue->m_clearTextEntry);
   2426 }
   2427 
   2428 void WebViewCore::setBackgroundColor(SkColor c)
   2429 {
   2430     WebCore::FrameView* view = m_mainFrame->view();
   2431     if (!view)
   2432         return;
   2433 
   2434     // need (int) cast to find the right constructor
   2435     WebCore::Color bcolor((int)SkColorGetR(c), (int)SkColorGetG(c),
   2436                           (int)SkColorGetB(c), (int)SkColorGetA(c));
   2437     view->setBaseBackgroundColor(bcolor);
   2438 
   2439     // Background color of 0 indicates we want a transparent background
   2440     if (c == 0)
   2441         view->setTransparent(true);
   2442 }
   2443 
   2444 jclass WebViewCore::getPluginClass(const WebCore::String& libName, const char* className)
   2445 {
   2446     JNIEnv* env = JSC::Bindings::getJNIEnv();
   2447 
   2448     jstring libString = env->NewString(libName.characters(), libName.length());
   2449     jstring classString = env->NewStringUTF(className);
   2450     jobject pluginClass = env->CallObjectMethod(m_javaGlue->object(env).get(),
   2451                                            m_javaGlue->m_getPluginClass,
   2452                                            libString, classString);
   2453     checkException(env);
   2454 
   2455     // cleanup unneeded local JNI references
   2456     env->DeleteLocalRef(libString);
   2457     env->DeleteLocalRef(classString);
   2458 
   2459     if (pluginClass != NULL) {
   2460         return static_cast<jclass>(pluginClass);
   2461     } else {
   2462         return NULL;
   2463     }
   2464 }
   2465 
   2466 void WebViewCore::showFullScreenPlugin(jobject childView, NPP npp)
   2467 {
   2468     JNIEnv* env = JSC::Bindings::getJNIEnv();
   2469     AutoJObject obj = m_javaGlue->object(env);
   2470 
   2471     env->CallVoidMethod(obj.get(),
   2472                         m_javaGlue->m_showFullScreenPlugin, childView, (int)npp);
   2473     checkException(env);
   2474 }
   2475 
   2476 void WebViewCore::hideFullScreenPlugin()
   2477 {
   2478     JNIEnv* env = JSC::Bindings::getJNIEnv();
   2479     env->CallVoidMethod(m_javaGlue->object(env).get(),
   2480                         m_javaGlue->m_hideFullScreenPlugin);
   2481     checkException(env);
   2482 }
   2483 
   2484 jobject WebViewCore::addSurface(jobject view, int x, int y, int width, int height)
   2485 {
   2486     JNIEnv* env = JSC::Bindings::getJNIEnv();
   2487     jobject result = env->CallObjectMethod(m_javaGlue->object(env).get(),
   2488                                            m_javaGlue->m_addSurface,
   2489                                            view, x, y, width, height);
   2490     checkException(env);
   2491     return result;
   2492 }
   2493 
   2494 void WebViewCore::updateSurface(jobject childView, int x, int y, int width, int height)
   2495 {
   2496     JNIEnv* env = JSC::Bindings::getJNIEnv();
   2497     env->CallVoidMethod(m_javaGlue->object(env).get(),
   2498                         m_javaGlue->m_updateSurface, childView,
   2499                         x, y, width, height);
   2500     checkException(env);
   2501 }
   2502 
   2503 void WebViewCore::destroySurface(jobject childView)
   2504 {
   2505     JNIEnv* env = JSC::Bindings::getJNIEnv();
   2506     env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_destroySurface, childView);
   2507     checkException(env);
   2508 }
   2509 
   2510 jobject WebViewCore::getContext()
   2511 {
   2512     JNIEnv* env = JSC::Bindings::getJNIEnv();
   2513     AutoJObject obj = m_javaGlue->object(env);
   2514 
   2515     jobject result = env->CallObjectMethod(obj.get(), m_javaGlue->m_getContext);
   2516     checkException(env);
   2517     return result;
   2518 }
   2519 
   2520 bool WebViewCore::validNodeAndBounds(Frame* frame, Node* node,
   2521     const IntRect& originalAbsoluteBounds)
   2522 {
   2523     bool valid = CacheBuilder::validNode(m_mainFrame, frame, node);
   2524     if (!valid)
   2525         return false;
   2526     RenderObject* renderer = node->renderer();
   2527     if (!renderer)
   2528         return false;
   2529     IntRect absBounds = node->hasTagName(HTMLNames::areaTag)
   2530         ? CacheBuilder::getAreaRect(static_cast<HTMLAreaElement*>(node))
   2531         : renderer->absoluteBoundingBoxRect();
   2532     return absBounds == originalAbsoluteBounds;
   2533 }
   2534 
   2535 void WebViewCore::showRect(int left, int top, int width, int height,
   2536         int contentWidth, int contentHeight, float xPercentInDoc,
   2537         float xPercentInView, float yPercentInDoc, float yPercentInView)
   2538 {
   2539     JNIEnv* env = JSC::Bindings::getJNIEnv();
   2540     env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_showRect,
   2541             left, top, width, height, contentWidth, contentHeight,
   2542             xPercentInDoc, xPercentInView, yPercentInDoc, yPercentInView);
   2543     checkException(env);
   2544 }
   2545 
   2546 void WebViewCore::centerFitRect(int x, int y, int width, int height)
   2547 {
   2548     JNIEnv* env = JSC::Bindings::getJNIEnv();
   2549     env->CallVoidMethod(m_javaGlue->object(env).get(),
   2550             m_javaGlue->m_centerFitRect, x, y, width, height);
   2551     checkException(env);
   2552 }
   2553 
   2554 
   2555 void WebViewCore::setScrollbarModes(ScrollbarMode horizontalMode, ScrollbarMode verticalMode)
   2556 {
   2557     JNIEnv* env = JSC::Bindings::getJNIEnv();
   2558     env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_setScrollbarModes,
   2559             horizontalMode, verticalMode);
   2560     checkException(env);
   2561 }
   2562 
   2563 //----------------------------------------------------------------------
   2564 // Native JNI methods
   2565 //----------------------------------------------------------------------
   2566 static jstring WebCoreStringToJString(JNIEnv *env, WebCore::String string)
   2567 {
   2568     int length = string.length();
   2569     if (!length)
   2570         return 0;
   2571     jstring ret = env->NewString((jchar *)string.characters(), length);
   2572     env->DeleteLocalRef(ret);
   2573     return ret;
   2574 }
   2575 
   2576 static jstring RequestLabel(JNIEnv *env, jobject obj, int framePointer,
   2577         int nodePointer)
   2578 {
   2579     return WebCoreStringToJString(env, GET_NATIVE_VIEW(env, obj)->requestLabel(
   2580             (WebCore::Frame*) framePointer, (WebCore::Node*) nodePointer));
   2581 }
   2582 
   2583 static void UpdateFrameCacheIfLoading(JNIEnv *env, jobject obj)
   2584 {
   2585     GET_NATIVE_VIEW(env, obj)->updateFrameCacheIfLoading();
   2586 }
   2587 
   2588 static void SetSize(JNIEnv *env, jobject obj, jint width, jint height,
   2589         jint screenWidth, jfloat scale, jint realScreenWidth, jint screenHeight,
   2590         jint anchorX, jint anchorY, jboolean ignoreHeight)
   2591 {
   2592 #ifdef ANDROID_INSTRUMENT
   2593     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
   2594 #endif
   2595     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   2596     LOGV("webviewcore::nativeSetSize(%u %u)\n viewImpl: %p", (unsigned)width, (unsigned)height, viewImpl);
   2597     LOG_ASSERT(viewImpl, "viewImpl not set in nativeSetSize");
   2598     viewImpl->setSizeScreenWidthAndScale(width, height, screenWidth, scale,
   2599         realScreenWidth, screenHeight, anchorX, anchorY, ignoreHeight);
   2600 }
   2601 
   2602 static void SetScrollOffset(JNIEnv *env, jobject obj, jint gen, jint x, jint y)
   2603 {
   2604 #ifdef ANDROID_INSTRUMENT
   2605     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
   2606 #endif
   2607     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   2608     LOG_ASSERT(viewImpl, "need viewImpl");
   2609 
   2610     viewImpl->setScrollOffset(gen, x, y);
   2611 }
   2612 
   2613 static void SetGlobalBounds(JNIEnv *env, jobject obj, jint x, jint y, jint h,
   2614                             jint v)
   2615 {
   2616 #ifdef ANDROID_INSTRUMENT
   2617     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
   2618 #endif
   2619     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   2620     LOG_ASSERT(viewImpl, "need viewImpl");
   2621 
   2622     viewImpl->setGlobalBounds(x, y, h, v);
   2623 }
   2624 
   2625 static jboolean Key(JNIEnv *env, jobject obj, jint keyCode, jint unichar,
   2626         jint repeatCount, jboolean isShift, jboolean isAlt, jboolean isSym,
   2627         jboolean isDown)
   2628 {
   2629 #ifdef ANDROID_INSTRUMENT
   2630     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
   2631 #endif
   2632     return GET_NATIVE_VIEW(env, obj)->key(PlatformKeyboardEvent(keyCode,
   2633         unichar, repeatCount, isDown, isShift, isAlt, isSym));
   2634 }
   2635 
   2636 static void Click(JNIEnv *env, jobject obj, int framePtr, int nodePtr)
   2637 {
   2638 #ifdef ANDROID_INSTRUMENT
   2639     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
   2640 #endif
   2641     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   2642     LOG_ASSERT(viewImpl, "viewImpl not set in Click");
   2643 
   2644     viewImpl->click(reinterpret_cast<WebCore::Frame*>(framePtr),
   2645         reinterpret_cast<WebCore::Node*>(nodePtr));
   2646 }
   2647 
   2648 static void DeleteSelection(JNIEnv *env, jobject obj, jint start, jint end,
   2649         jint textGeneration)
   2650 {
   2651 #ifdef ANDROID_INSTRUMENT
   2652     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
   2653 #endif
   2654     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   2655     viewImpl->deleteSelection(start, end, textGeneration);
   2656 }
   2657 
   2658 static void SetSelection(JNIEnv *env, jobject obj, jint start, jint end)
   2659 {
   2660 #ifdef ANDROID_INSTRUMENT
   2661     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
   2662 #endif
   2663     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   2664     viewImpl->setSelection(start, end);
   2665 }
   2666 
   2667 
   2668 static void ReplaceTextfieldText(JNIEnv *env, jobject obj,
   2669     jint oldStart, jint oldEnd, jstring replace, jint start, jint end,
   2670     jint textGeneration)
   2671 {
   2672 #ifdef ANDROID_INSTRUMENT
   2673     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
   2674 #endif
   2675     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   2676     WebCore::String webcoreString = to_string(env, replace);
   2677     viewImpl->replaceTextfieldText(oldStart,
   2678             oldEnd, webcoreString, start, end, textGeneration);
   2679 }
   2680 
   2681 static void PassToJs(JNIEnv *env, jobject obj,
   2682     jint generation, jstring currentText, jint keyCode,
   2683     jint keyValue, jboolean down, jboolean cap, jboolean fn, jboolean sym)
   2684 {
   2685 #ifdef ANDROID_INSTRUMENT
   2686     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
   2687 #endif
   2688     WebCore::String current = to_string(env, currentText);
   2689     GET_NATIVE_VIEW(env, obj)->passToJs(generation, current,
   2690         PlatformKeyboardEvent(keyCode, keyValue, 0, down, cap, fn, sym));
   2691 }
   2692 
   2693 static void ScrollFocusedTextInput(JNIEnv *env, jobject obj, jfloat xPercent,
   2694     jint y)
   2695 {
   2696 #ifdef ANDROID_INSTRUMENT
   2697     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
   2698 #endif
   2699     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   2700     viewImpl->scrollFocusedTextInput(xPercent, y);
   2701 }
   2702 
   2703 static void SetFocusControllerActive(JNIEnv *env, jobject obj, jboolean active)
   2704 {
   2705 #ifdef ANDROID_INSTRUMENT
   2706     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
   2707 #endif
   2708     LOGV("webviewcore::nativeSetFocusControllerActive()\n");
   2709     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   2710     LOG_ASSERT(viewImpl, "viewImpl not set in nativeSetFocusControllerActive");
   2711     viewImpl->setFocusControllerActive(0, active);
   2712 }
   2713 
   2714 static void SaveDocumentState(JNIEnv *env, jobject obj, jint frame)
   2715 {
   2716 #ifdef ANDROID_INSTRUMENT
   2717     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
   2718 #endif
   2719     LOGV("webviewcore::nativeSaveDocumentState()\n");
   2720     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   2721     LOG_ASSERT(viewImpl, "viewImpl not set in nativeSaveDocumentState");
   2722     viewImpl->saveDocumentState((WebCore::Frame*) frame);
   2723 }
   2724 
   2725 void WebViewCore::addVisitedLink(const UChar* string, int length)
   2726 {
   2727     if (m_groupForVisitedLinks)
   2728         m_groupForVisitedLinks->addVisitedLink(string, length);
   2729 }
   2730 
   2731 static bool RecordContent(JNIEnv *env, jobject obj, jobject region, jobject pt)
   2732 {
   2733 #ifdef ANDROID_INSTRUMENT
   2734     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
   2735 #endif
   2736     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   2737     SkRegion* nativeRegion = GraphicsJNI::getNativeRegion(env, region);
   2738     SkIPoint nativePt;
   2739     bool result = viewImpl->recordContent(nativeRegion, &nativePt);
   2740     GraphicsJNI::ipoint_to_jpoint(nativePt, env, pt);
   2741     return result;
   2742 }
   2743 
   2744 static void SplitContent(JNIEnv *env, jobject obj)
   2745 {
   2746 #ifdef ANDROID_INSTRUMENT
   2747     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
   2748 #endif
   2749     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   2750     viewImpl->splitContent();
   2751 }
   2752 
   2753 static void SendListBoxChoice(JNIEnv* env, jobject obj, jint choice)
   2754 {
   2755 #ifdef ANDROID_INSTRUMENT
   2756     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
   2757 #endif
   2758     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   2759     LOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoice");
   2760     viewImpl->popupReply(choice);
   2761 }
   2762 
   2763 // Set aside a predetermined amount of space in which to place the listbox
   2764 // choices, to avoid unnecessary allocations.
   2765 // The size here is arbitrary.  We want the size to be at least as great as the
   2766 // number of items in the average multiple-select listbox.
   2767 #define PREPARED_LISTBOX_STORAGE 10
   2768 
   2769 static void SendListBoxChoices(JNIEnv* env, jobject obj, jbooleanArray jArray,
   2770         jint size)
   2771 {
   2772 #ifdef ANDROID_INSTRUMENT
   2773     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
   2774 #endif
   2775     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   2776     LOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoices");
   2777     jboolean* ptrArray = env->GetBooleanArrayElements(jArray, 0);
   2778     SkAutoSTMalloc<PREPARED_LISTBOX_STORAGE, int> storage(size);
   2779     int* array = storage.get();
   2780     int count = 0;
   2781     for (int i = 0; i < size; i++) {
   2782         if (ptrArray[i]) {
   2783             array[count++] = i;
   2784         }
   2785     }
   2786     env->ReleaseBooleanArrayElements(jArray, ptrArray, JNI_ABORT);
   2787     viewImpl->popupReply(array, count);
   2788 }
   2789 
   2790 static jstring FindAddress(JNIEnv *env, jobject obj, jstring addr,
   2791     jboolean caseInsensitive)
   2792 {
   2793 #ifdef ANDROID_INSTRUMENT
   2794     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
   2795 #endif
   2796     if (!addr)
   2797         return 0;
   2798     int length = env->GetStringLength(addr);
   2799     if (!length)
   2800         return 0;
   2801     const jchar* addrChars = env->GetStringChars(addr, 0);
   2802     int start, end;
   2803     bool success = CacheBuilder::FindAddress(addrChars, length,
   2804         &start, &end, caseInsensitive) == CacheBuilder::FOUND_COMPLETE;
   2805     jstring ret = 0;
   2806     if (success) {
   2807         ret = env->NewString((jchar*) addrChars + start, end - start);
   2808         env->DeleteLocalRef(ret);
   2809     }
   2810     env->ReleaseStringChars(addr, addrChars);
   2811     return ret;
   2812 }
   2813 
   2814 static jboolean HandleTouchEvent(JNIEnv *env, jobject obj, jint action, jint x, jint y, jint metaState)
   2815 {
   2816 #ifdef ANDROID_INSTRUMENT
   2817     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
   2818 #endif
   2819     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   2820     LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
   2821     return viewImpl->handleTouchEvent(action, x, y, metaState);
   2822 }
   2823 
   2824 static void TouchUp(JNIEnv *env, jobject obj, jint touchGeneration,
   2825         jint frame, jint node, jint x, jint y)
   2826 {
   2827 #ifdef ANDROID_INSTRUMENT
   2828     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
   2829 #endif
   2830     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   2831     LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
   2832     viewImpl->touchUp(touchGeneration,
   2833         (WebCore::Frame*) frame, (WebCore::Node*) node, x, y);
   2834 }
   2835 
   2836 static jstring RetrieveHref(JNIEnv *env, jobject obj, jint frame,
   2837         jint node)
   2838 {
   2839 #ifdef ANDROID_INSTRUMENT
   2840     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
   2841 #endif
   2842     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   2843     LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
   2844     WebCore::String result = viewImpl->retrieveHref((WebCore::Frame*) frame,
   2845             (WebCore::Node*) node);
   2846     if (!result.isEmpty())
   2847         return WebCoreStringToJString(env, result);
   2848     return 0;
   2849 }
   2850 
   2851 static jstring RetrieveAnchorText(JNIEnv *env, jobject obj, jint frame,
   2852         jint node)
   2853 {
   2854 #ifdef ANDROID_INSTRUMENT
   2855     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
   2856 #endif
   2857     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   2858     LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
   2859     WebCore::String result = viewImpl->retrieveAnchorText((WebCore::Frame*) frame,
   2860             (WebCore::Node*) node);
   2861     if (!result.isEmpty())
   2862         return WebCoreStringToJString(env, result);
   2863     return 0;
   2864 }
   2865 
   2866 
   2867 static void MoveFocus(JNIEnv *env, jobject obj, jint framePtr, jint nodePtr)
   2868 {
   2869 #ifdef ANDROID_INSTRUMENT
   2870     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
   2871 #endif
   2872     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   2873     LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
   2874     viewImpl->moveFocus((WebCore::Frame*) framePtr, (WebCore::Node*) nodePtr);
   2875 }
   2876 
   2877 static void MoveMouse(JNIEnv *env, jobject obj, jint frame,
   2878         jint x, jint y)
   2879 {
   2880 #ifdef ANDROID_INSTRUMENT
   2881     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
   2882 #endif
   2883     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   2884     LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
   2885     viewImpl->moveMouse((WebCore::Frame*) frame, x, y);
   2886 }
   2887 
   2888 static void MoveMouseIfLatest(JNIEnv *env, jobject obj, jint moveGeneration,
   2889         jint frame, jint x, jint y)
   2890 {
   2891 #ifdef ANDROID_INSTRUMENT
   2892     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
   2893 #endif
   2894     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   2895     LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
   2896     viewImpl->moveMouseIfLatest(moveGeneration,
   2897         (WebCore::Frame*) frame, x, y);
   2898 }
   2899 
   2900 static void UpdateFrameCache(JNIEnv *env, jobject obj)
   2901 {
   2902 #ifdef ANDROID_INSTRUMENT
   2903     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
   2904 #endif
   2905     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   2906     LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
   2907     viewImpl->updateFrameCache();
   2908 }
   2909 
   2910 static jint GetContentMinPrefWidth(JNIEnv *env, jobject obj)
   2911 {
   2912 #ifdef ANDROID_INSTRUMENT
   2913     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
   2914 #endif
   2915     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   2916     LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
   2917 
   2918     WebCore::Frame* frame = viewImpl->mainFrame();
   2919     if (frame) {
   2920         WebCore::Document* document = frame->document();
   2921         if (document) {
   2922             WebCore::RenderObject* renderer = document->renderer();
   2923             if (renderer && renderer->isRenderView()) {
   2924                 return renderer->minPrefWidth();
   2925             }
   2926         }
   2927     }
   2928     return 0;
   2929 }
   2930 
   2931 static void SetViewportSettingsFromNative(JNIEnv *env, jobject obj)
   2932 {
   2933 #ifdef ANDROID_INSTRUMENT
   2934     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
   2935 #endif
   2936     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   2937     LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
   2938 
   2939     WebCore::Settings* s = viewImpl->mainFrame()->page()->settings();
   2940     if (!s)
   2941         return;
   2942 
   2943 #ifdef ANDROID_META_SUPPORT
   2944     env->SetIntField(obj, gWebViewCoreFields.m_viewportWidth, s->viewportWidth());
   2945     env->SetIntField(obj, gWebViewCoreFields.m_viewportHeight, s->viewportHeight());
   2946     env->SetIntField(obj, gWebViewCoreFields.m_viewportInitialScale, s->viewportInitialScale());
   2947     env->SetIntField(obj, gWebViewCoreFields.m_viewportMinimumScale, s->viewportMinimumScale());
   2948     env->SetIntField(obj, gWebViewCoreFields.m_viewportMaximumScale, s->viewportMaximumScale());
   2949     env->SetBooleanField(obj, gWebViewCoreFields.m_viewportUserScalable, s->viewportUserScalable());
   2950     env->SetIntField(obj, gWebViewCoreFields.m_viewportDensityDpi, s->viewportTargetDensityDpi());
   2951 #endif
   2952 }
   2953 
   2954 static void SetBackgroundColor(JNIEnv *env, jobject obj, jint color)
   2955 {
   2956 #ifdef ANDROID_INSTRUMENT
   2957     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
   2958 #endif
   2959     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   2960     LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
   2961 
   2962     viewImpl->setBackgroundColor((SkColor) color);
   2963 }
   2964 
   2965 static void DumpDomTree(JNIEnv *env, jobject obj, jboolean useFile)
   2966 {
   2967     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   2968     LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
   2969 
   2970     viewImpl->dumpDomTree(useFile);
   2971 }
   2972 
   2973 static void DumpRenderTree(JNIEnv *env, jobject obj, jboolean useFile)
   2974 {
   2975     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   2976     LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
   2977 
   2978     viewImpl->dumpRenderTree(useFile);
   2979 }
   2980 
   2981 static void DumpNavTree(JNIEnv *env, jobject obj)
   2982 {
   2983     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   2984     LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
   2985 
   2986     viewImpl->dumpNavTree();
   2987 }
   2988 
   2989 static void DumpV8Counters(JNIEnv*, jobject)
   2990 {
   2991 #if USE(V8)
   2992 #ifdef ANDROID_INSTRUMENT
   2993     V8Counters::dumpCounters();
   2994 #endif
   2995 #endif
   2996 }
   2997 
   2998 static void SetJsFlags(JNIEnv *env, jobject obj, jstring flags)
   2999 {
   3000 #if USE(V8)
   3001     WebCore::String flagsString = to_string(env, flags);
   3002     WebCore::CString utf8String = flagsString.utf8();
   3003     WebCore::ScriptController::setFlags(utf8String.data(), utf8String.length());
   3004 #endif
   3005 }
   3006 
   3007 
   3008 // Called from the Java side to set a new quota for the origin or new appcache
   3009 // max size in response to a notification that the original quota was exceeded or
   3010 // that the appcache has reached its maximum size.
   3011 static void SetNewStorageLimit(JNIEnv* env, jobject obj, jlong quota) {
   3012 #if ENABLE(DATABASE) || ENABLE(OFFLINE_WEB_APPLICATIONS)
   3013     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   3014     Frame* frame = viewImpl->mainFrame();
   3015 
   3016     // The main thread is blocked awaiting this response, so now we can wake it
   3017     // up.
   3018     ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(frame->page()->chrome()->client());
   3019     chromeC->wakeUpMainThreadWithNewQuota(quota);
   3020 #endif
   3021 }
   3022 
   3023 // Called from Java to provide a Geolocation permission state for the specified origin.
   3024 static void GeolocationPermissionsProvide(JNIEnv* env, jobject obj, jstring origin, jboolean allow, jboolean remember) {
   3025     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   3026     Frame* frame = viewImpl->mainFrame();
   3027 
   3028     ChromeClientAndroid* chromeClient = static_cast<ChromeClientAndroid*>(frame->page()->chrome()->client());
   3029     chromeClient->provideGeolocationPermissions(to_string(env, origin), allow, remember);
   3030 }
   3031 
   3032 static void RegisterURLSchemeAsLocal(JNIEnv* env, jobject obj, jstring scheme) {
   3033 #ifdef ANDROID_INSTRUMENT
   3034     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
   3035 #endif
   3036     WebCore::SecurityOrigin::registerURLSchemeAsLocal(to_string(env, scheme));
   3037 }
   3038 
   3039 static void ClearContent(JNIEnv *env, jobject obj)
   3040 {
   3041 #ifdef ANDROID_INSTRUMENT
   3042     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
   3043 #endif
   3044     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   3045     viewImpl->clearContent();
   3046 }
   3047 
   3048 static void CopyContentToPicture(JNIEnv *env, jobject obj, jobject pict)
   3049 {
   3050 #ifdef ANDROID_INSTRUMENT
   3051     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
   3052 #endif
   3053     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   3054     if (!viewImpl)
   3055         return;
   3056     SkPicture* picture = GraphicsJNI::getNativePicture(env, pict);
   3057     viewImpl->copyContentToPicture(picture);
   3058 }
   3059 
   3060 static bool DrawContent(JNIEnv *env, jobject obj, jobject canv, jint color)
   3061 {
   3062     // Note: this is called from UI thread, don't count it for WebViewCoreTimeCounter
   3063     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   3064     SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv);
   3065     return viewImpl->drawContent(canvas, color);
   3066 }
   3067 
   3068 static bool FocusBoundsChanged(JNIEnv* env, jobject obj)
   3069 {
   3070     return GET_NATIVE_VIEW(env, obj)->focusBoundsChanged();
   3071 }
   3072 
   3073 static bool PictureReady(JNIEnv* env, jobject obj)
   3074 {
   3075     return GET_NATIVE_VIEW(env, obj)->pictureReady();
   3076 }
   3077 
   3078 static void Pause(JNIEnv* env, jobject obj)
   3079 {
   3080     // This is called for the foreground tab when the browser is put to the
   3081     // background (and also for any tab when it is put to the background of the
   3082     // browser). The browser can only be killed by the system when it is in the
   3083     // background, so saving the Geolocation permission state now ensures that
   3084     // is maintained when the browser is killed.
   3085     ChromeClient* chromeClient = GET_NATIVE_VIEW(env, obj)->mainFrame()->page()->chrome()->client();
   3086     ChromeClientAndroid* chromeClientAndroid = static_cast<ChromeClientAndroid*>(chromeClient);
   3087     chromeClientAndroid->storeGeolocationPermissions();
   3088 
   3089     Frame* mainFrame = GET_NATIVE_VIEW(env, obj)->mainFrame();
   3090     for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext()) {
   3091         Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation();
   3092         if (geolocation)
   3093             geolocation->suspend();
   3094     }
   3095 
   3096     ANPEvent event;
   3097     SkANP::InitEvent(&event, kLifecycle_ANPEventType);
   3098     event.data.lifecycle.action = kPause_ANPLifecycleAction;
   3099     GET_NATIVE_VIEW(env, obj)->sendPluginEvent(event);
   3100 
   3101     GET_NATIVE_VIEW(env, obj)->setIsPaused(true);
   3102 }
   3103 
   3104 static void Resume(JNIEnv* env, jobject obj)
   3105 {
   3106     Frame* mainFrame = GET_NATIVE_VIEW(env, obj)->mainFrame();
   3107     for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext()) {
   3108         Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation();
   3109         if (geolocation)
   3110             geolocation->resume();
   3111     }
   3112 
   3113     ANPEvent event;
   3114     SkANP::InitEvent(&event, kLifecycle_ANPEventType);
   3115     event.data.lifecycle.action = kResume_ANPLifecycleAction;
   3116     GET_NATIVE_VIEW(env, obj)->sendPluginEvent(event);
   3117 
   3118     GET_NATIVE_VIEW(env, obj)->setIsPaused(false);
   3119 }
   3120 
   3121 static void FreeMemory(JNIEnv* env, jobject obj)
   3122 {
   3123     ANPEvent event;
   3124     SkANP::InitEvent(&event, kLifecycle_ANPEventType);
   3125     event.data.lifecycle.action = kFreeMemory_ANPLifecycleAction;
   3126     GET_NATIVE_VIEW(env, obj)->sendPluginEvent(event);
   3127 }
   3128 
   3129 static void ProvideVisitedHistory(JNIEnv *env, jobject obj, jobject hist)
   3130 {
   3131     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   3132     LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
   3133 
   3134     jobjectArray array = static_cast<jobjectArray>(hist);
   3135 
   3136     jsize len = env->GetArrayLength(array);
   3137     for (jsize i = 0; i < len; i++) {
   3138         jstring item = static_cast<jstring>(env->GetObjectArrayElement(array, i));
   3139         const UChar* str = static_cast<const UChar*>(env->GetStringChars(item, NULL));
   3140         jsize len = env->GetStringLength(item);
   3141         viewImpl->addVisitedLink(str, len);
   3142         env->ReleaseStringChars(item, str);
   3143         env->DeleteLocalRef(item);
   3144     }
   3145 }
   3146 
   3147 // Notification from the UI thread that the plugin's full-screen surface has been discarded
   3148 static void FullScreenPluginHidden(JNIEnv* env, jobject obj, jint npp)
   3149 {
   3150     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
   3151     PluginWidgetAndroid* plugin = viewImpl->getPluginWidget((NPP)npp);
   3152     if (plugin)
   3153         plugin->exitFullScreen(false);
   3154 }
   3155 
   3156 static WebCore::IntRect jrect_to_webrect(JNIEnv* env, jobject obj)
   3157 {
   3158     int L, T, R, B;
   3159     GraphicsJNI::get_jrect(env, obj, &L, &T, &R, &B);
   3160     return WebCore::IntRect(L, T, R - L, B - T);
   3161 }
   3162 
   3163 static bool ValidNodeAndBounds(JNIEnv *env, jobject obj, int frame, int node,
   3164     jobject rect)
   3165 {
   3166     IntRect nativeRect = jrect_to_webrect(env, rect);
   3167     return GET_NATIVE_VIEW(env, obj)->validNodeAndBounds(
   3168             reinterpret_cast<Frame*>(frame),
   3169             reinterpret_cast<Node*>(node), nativeRect);
   3170 }
   3171 
   3172 // ----------------------------------------------------------------------------
   3173 
   3174 /*
   3175  * JNI registration.
   3176  */
   3177 static JNINativeMethod gJavaWebViewCoreMethods[] = {
   3178     { "nativeClearContent", "()V",
   3179         (void*) ClearContent },
   3180     { "nativeCopyContentToPicture", "(Landroid/graphics/Picture;)V",
   3181         (void*) CopyContentToPicture },
   3182     { "nativeDrawContent", "(Landroid/graphics/Canvas;I)Z",
   3183         (void*) DrawContent } ,
   3184     { "nativeFocusBoundsChanged", "()Z",
   3185         (void*) FocusBoundsChanged } ,
   3186     { "nativeKey", "(IIIZZZZ)Z",
   3187         (void*) Key },
   3188     { "nativeClick", "(II)V",
   3189         (void*) Click },
   3190     { "nativePictureReady", "()Z",
   3191         (void*) PictureReady } ,
   3192     { "nativeSendListBoxChoices", "([ZI)V",
   3193         (void*) SendListBoxChoices },
   3194     { "nativeSendListBoxChoice", "(I)V",
   3195         (void*) SendListBoxChoice },
   3196     { "nativeSetSize", "(IIIFIIIIZ)V",
   3197         (void*) SetSize },
   3198     { "nativeSetScrollOffset", "(III)V",
   3199         (void*) SetScrollOffset },
   3200     { "nativeSetGlobalBounds", "(IIII)V",
   3201         (void*) SetGlobalBounds },
   3202     { "nativeSetSelection", "(II)V",
   3203         (void*) SetSelection } ,
   3204     { "nativeDeleteSelection", "(III)V",
   3205         (void*) DeleteSelection } ,
   3206     { "nativeReplaceTextfieldText", "(IILjava/lang/String;III)V",
   3207         (void*) ReplaceTextfieldText } ,
   3208     { "nativeMoveFocus", "(II)V",
   3209         (void*) MoveFocus },
   3210     { "nativeMoveMouse", "(III)V",
   3211         (void*) MoveMouse },
   3212     { "nativeMoveMouseIfLatest", "(IIII)V",
   3213         (void*) MoveMouseIfLatest },
   3214     { "passToJs", "(ILjava/lang/String;IIZZZZ)V",
   3215         (void*) PassToJs },
   3216     { "nativeScrollFocusedTextInput", "(FI)V",
   3217         (void*) ScrollFocusedTextInput },
   3218     { "nativeSetFocusControllerActive", "(Z)V",
   3219         (void*) SetFocusControllerActive },
   3220     { "nativeSaveDocumentState", "(I)V",
   3221         (void*) SaveDocumentState },
   3222     { "nativeFindAddress", "(Ljava/lang/String;Z)Ljava/lang/String;",
   3223         (void*) FindAddress },
   3224     { "nativeHandleTouchEvent", "(IIII)Z",
   3225             (void*) HandleTouchEvent },
   3226     { "nativeTouchUp", "(IIIII)V",
   3227         (void*) TouchUp },
   3228     { "nativeRetrieveHref", "(II)Ljava/lang/String;",
   3229         (void*) RetrieveHref },
   3230     { "nativeRetrieveAnchorText", "(II)Ljava/lang/String;",
   3231         (void*) RetrieveAnchorText },
   3232     { "nativeUpdateFrameCache", "()V",
   3233         (void*) UpdateFrameCache },
   3234     { "nativeGetContentMinPrefWidth", "()I",
   3235         (void*) GetContentMinPrefWidth },
   3236     { "nativeRecordContent", "(Landroid/graphics/Region;Landroid/graphics/Point;)Z",
   3237         (void*) RecordContent },
   3238     { "setViewportSettingsFromNative", "()V",
   3239         (void*) SetViewportSettingsFromNative },
   3240     { "nativeSplitContent", "()V",
   3241         (void*) SplitContent },
   3242     { "nativeSetBackgroundColor", "(I)V",
   3243         (void*) SetBackgroundColor },
   3244     { "nativeRegisterURLSchemeAsLocal", "(Ljava/lang/String;)V",
   3245         (void*) RegisterURLSchemeAsLocal },
   3246     { "nativeDumpDomTree", "(Z)V",
   3247         (void*) DumpDomTree },
   3248     { "nativeDumpRenderTree", "(Z)V",
   3249         (void*) DumpRenderTree },
   3250     { "nativeDumpNavTree", "()V",
   3251         (void*) DumpNavTree },
   3252     { "nativeDumpV8Counters", "()V",
   3253         (void*) DumpV8Counters },
   3254     { "nativeSetNewStorageLimit", "(J)V",
   3255         (void*) SetNewStorageLimit },
   3256     { "nativeGeolocationPermissionsProvide", "(Ljava/lang/String;ZZ)V",
   3257         (void*) GeolocationPermissionsProvide },
   3258     { "nativePause", "()V", (void*) Pause },
   3259     { "nativeResume", "()V", (void*) Resume },
   3260     { "nativeFreeMemory", "()V", (void*) FreeMemory },
   3261     { "nativeSetJsFlags", "(Ljava/lang/String;)V", (void*) SetJsFlags },
   3262     { "nativeRequestLabel", "(II)Ljava/lang/String;",
   3263         (void*) RequestLabel },
   3264     { "nativeUpdateFrameCacheIfLoading", "()V",
   3265         (void*) UpdateFrameCacheIfLoading },
   3266     { "nativeProvideVisitedHistory", "([Ljava/lang/String;)V",
   3267         (void*) ProvideVisitedHistory },
   3268     { "nativeFullScreenPluginHidden", "(I)V",
   3269         (void*) FullScreenPluginHidden },
   3270     { "nativeValidNodeAndBounds", "(IILandroid/graphics/Rect;)Z",
   3271         (void*) ValidNodeAndBounds },
   3272 };
   3273 
   3274 int register_webviewcore(JNIEnv* env)
   3275 {
   3276     jclass widget = env->FindClass("android/webkit/WebViewCore");
   3277     LOG_ASSERT(widget,
   3278             "Unable to find class android/webkit/WebViewCore");
   3279     gWebViewCoreFields.m_nativeClass = env->GetFieldID(widget, "mNativeClass",
   3280             "I");
   3281     LOG_ASSERT(gWebViewCoreFields.m_nativeClass,
   3282             "Unable to find android/webkit/WebViewCore.mNativeClass");
   3283     gWebViewCoreFields.m_viewportWidth = env->GetFieldID(widget,
   3284             "mViewportWidth", "I");
   3285     LOG_ASSERT(gWebViewCoreFields.m_viewportWidth,
   3286             "Unable to find android/webkit/WebViewCore.mViewportWidth");
   3287     gWebViewCoreFields.m_viewportHeight = env->GetFieldID(widget,
   3288             "mViewportHeight", "I");
   3289     LOG_ASSERT(gWebViewCoreFields.m_viewportHeight,
   3290             "Unable to find android/webkit/WebViewCore.mViewportHeight");
   3291     gWebViewCoreFields.m_viewportInitialScale = env->GetFieldID(widget,
   3292             "mViewportInitialScale", "I");
   3293     LOG_ASSERT(gWebViewCoreFields.m_viewportInitialScale,
   3294             "Unable to find android/webkit/WebViewCore.mViewportInitialScale");
   3295     gWebViewCoreFields.m_viewportMinimumScale = env->GetFieldID(widget,
   3296             "mViewportMinimumScale", "I");
   3297     LOG_ASSERT(gWebViewCoreFields.m_viewportMinimumScale,
   3298             "Unable to find android/webkit/WebViewCore.mViewportMinimumScale");
   3299     gWebViewCoreFields.m_viewportMaximumScale = env->GetFieldID(widget,
   3300             "mViewportMaximumScale", "I");
   3301     LOG_ASSERT(gWebViewCoreFields.m_viewportMaximumScale,
   3302             "Unable to find android/webkit/WebViewCore.mViewportMaximumScale");
   3303     gWebViewCoreFields.m_viewportUserScalable = env->GetFieldID(widget,
   3304             "mViewportUserScalable", "Z");
   3305     LOG_ASSERT(gWebViewCoreFields.m_viewportUserScalable,
   3306             "Unable to find android/webkit/WebViewCore.mViewportUserScalable");
   3307     gWebViewCoreFields.m_viewportDensityDpi = env->GetFieldID(widget,
   3308             "mViewportDensityDpi", "I");
   3309     LOG_ASSERT(gWebViewCoreFields.m_viewportDensityDpi,
   3310             "Unable to find android/webkit/WebViewCore.mViewportDensityDpi");
   3311     gWebViewCoreFields.m_webView = env->GetFieldID(widget,
   3312             "mWebView", "Landroid/webkit/WebView;");
   3313     LOG_ASSERT(gWebViewCoreFields.m_webView,
   3314             "Unable to find android/webkit/WebViewCore.mWebView");
   3315 
   3316     gWebViewCoreStaticMethods.m_supportsMimeType =
   3317         env->GetStaticMethodID(widget, "supportsMimeType", "(Ljava/lang/String;)Z");
   3318     LOG_ASSERT(gWebViewCoreStaticMethods.m_supportsMimeType == NULL,
   3319         "Could not find static method supportsMimeType from WebViewCore");
   3320 
   3321     return jniRegisterNativeMethods(env, "android/webkit/WebViewCore",
   3322             gJavaWebViewCoreMethods, NELEM(gJavaWebViewCoreMethods));
   3323 }
   3324 
   3325 } /* namespace android */
   3326