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