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