WebViewCore.cpp revision 773979f92560dd1aead375c82fd75b584a141e5d
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        androidHitResult.searchContentDetectors();
2018        return androidHitResult;
2019    }
2020    // finally select the node with the largest overlap with the fat point
2021    TouchNodeData final;
2022    final.mUrlNode = 0;
2023    IntPoint docPos = frame->view()->windowToContents(m_mousePos);
2024    IntRect testRect(docPos.x() - slop, docPos.y() - slop, 2 * slop + 1, 2 * slop + 1);
2025    int area = 0;
2026    Vector<TouchNodeData>::const_iterator nlast = nodeDataList.end();
2027    for (Vector<TouchNodeData>::const_iterator n = nodeDataList.begin(); n != nlast; ++n) {
2028        IntRect rect = n->mBounds;
2029        rect.intersect(testRect);
2030        int a = rect.width() * rect.height();
2031        if (a > area || !final.mUrlNode) {
2032            final = *n;
2033            area = a;
2034        }
2035    }
2036    // now get the node's highlight rectangles in the page coordinate system
2037    if (final.mUrlNode) {
2038        if (final.mUrlNode->isElementNode()) {
2039            // We found a URL element. Update the hitTestResult
2040            androidHitResult.setURLElement(static_cast<Element*>(final.mUrlNode));
2041        } else {
2042            androidHitResult.setURLElement(0);
2043        }
2044        // Update innerNode and innerNonSharedNode
2045        androidHitResult.hitTestResult().setInnerNode(final.mInnerNode);
2046        androidHitResult.hitTestResult().setInnerNonSharedNode(final.mInnerNode);
2047        IntPoint frameAdjust;
2048        if (frame != m_mainFrame) {
2049            frameAdjust = frame->view()->contentsToWindow(IntPoint());
2050            frameAdjust.move(m_scrollOffsetX, m_scrollOffsetY);
2051        }
2052        IntRect rect = final.mBounds;
2053        rect.move(frameAdjust.x(), frameAdjust.y());
2054        if (doMoveMouse) {
2055            // adjust m_mousePos if it is not inside the returned highlight rectangle
2056            testRect.move(frameAdjust.x(), frameAdjust.y());
2057            testRect.intersect(rect);
2058            if (!testRect.contains(x, y)) {
2059                moveMouse(m_mainFrame, testRect.center().x(), testRect.center().y());
2060                DBG_NAV_LOGD("Move x/y from (%d, %d) to (%d, %d) scrollOffset is (%d, %d)",
2061                        x, y, m_mousePos.x() + m_scrollOffsetX, m_mousePos.y() + m_scrollOffsetY,
2062                        m_scrollOffsetX, m_scrollOffsetY);
2063            }
2064        }
2065    } else {
2066        androidHitResult.searchContentDetectors();
2067    }
2068    return androidHitResult;
2069}
2070
2071///////////////////////////////////////////////////////////////////////////////
2072
2073void WebViewCore::addPlugin(PluginWidgetAndroid* w)
2074{
2075//    SkDebugf("----------- addPlugin %p", w);
2076    /* The plugin must be appended to the end of the array. This ensures that if
2077       the plugin is added while iterating through the array (e.g. sendEvent(...))
2078       that the iteration process is not corrupted.
2079     */
2080    *m_plugins.append() = w;
2081}
2082
2083void WebViewCore::removePlugin(PluginWidgetAndroid* w)
2084{
2085//    SkDebugf("----------- removePlugin %p", w);
2086    int index = m_plugins.find(w);
2087    if (index < 0) {
2088        SkDebugf("--------------- pluginwindow not found! %p\n", w);
2089    } else {
2090        m_plugins.removeShuffle(index);
2091    }
2092}
2093
2094bool WebViewCore::isPlugin(PluginWidgetAndroid* w) const
2095{
2096    return m_plugins.find(w) >= 0;
2097}
2098
2099void WebViewCore::invalPlugin(PluginWidgetAndroid* w)
2100{
2101    const double PLUGIN_INVAL_DELAY = 1.0 / 60;
2102
2103    if (!m_pluginInvalTimer.isActive()) {
2104        m_pluginInvalTimer.startOneShot(PLUGIN_INVAL_DELAY);
2105    }
2106}
2107
2108void WebViewCore::drawPlugins()
2109{
2110    SkRegion inval; // accumualte what needs to be redrawn
2111    PluginWidgetAndroid** iter = m_plugins.begin();
2112    PluginWidgetAndroid** stop = m_plugins.end();
2113
2114    for (; iter < stop; ++iter) {
2115        PluginWidgetAndroid* w = *iter;
2116        SkIRect dirty;
2117        if (w->isDirty(&dirty)) {
2118            w->draw();
2119            inval.op(dirty, SkRegion::kUnion_Op);
2120        }
2121    }
2122
2123    if (!inval.isEmpty()) {
2124        // inval.getBounds() is our rectangle
2125        const SkIRect& bounds = inval.getBounds();
2126        WebCore::IntRect r(bounds.fLeft, bounds.fTop,
2127                           bounds.width(), bounds.height());
2128        this->viewInvalidate(r);
2129    }
2130}
2131
2132void WebViewCore::notifyPluginsOnFrameLoad(const Frame* frame) {
2133    // if frame is the parent then notify all plugins
2134    if (!frame->tree()->parent()) {
2135        // trigger an event notifying the plugins that the page has loaded
2136        ANPEvent event;
2137        SkANP::InitEvent(&event, kLifecycle_ANPEventType);
2138        event.data.lifecycle.action = kOnLoad_ANPLifecycleAction;
2139        sendPluginEvent(event);
2140        // trigger the on/off screen notification if the page was reloaded
2141        sendPluginVisibleScreen();
2142    }
2143    // else if frame's parent has completed
2144    else if (!frame->tree()->parent()->loader()->isLoading()) {
2145        // send to all plugins who have this frame in their heirarchy
2146        PluginWidgetAndroid** iter = m_plugins.begin();
2147        PluginWidgetAndroid** stop = m_plugins.end();
2148        for (; iter < stop; ++iter) {
2149            Frame* currentFrame = (*iter)->pluginView()->parentFrame();
2150            while (currentFrame) {
2151                if (frame == currentFrame) {
2152                    ANPEvent event;
2153                    SkANP::InitEvent(&event, kLifecycle_ANPEventType);
2154                    event.data.lifecycle.action = kOnLoad_ANPLifecycleAction;
2155                    (*iter)->sendEvent(event);
2156
2157                    // trigger the on/off screen notification if the page was reloaded
2158                    ANPRectI visibleRect;
2159                    getVisibleScreen(visibleRect);
2160                    (*iter)->setVisibleScreen(visibleRect, m_scale);
2161
2162                    break;
2163                }
2164                currentFrame = currentFrame->tree()->parent();
2165            }
2166        }
2167    }
2168}
2169
2170void WebViewCore::getVisibleScreen(ANPRectI& visibleRect)
2171{
2172    visibleRect.left = m_scrollOffsetX;
2173    visibleRect.top = m_scrollOffsetY;
2174    visibleRect.right = m_scrollOffsetX + m_screenWidth;
2175    visibleRect.bottom = m_scrollOffsetY + m_screenHeight;
2176}
2177
2178void WebViewCore::sendPluginVisibleScreen()
2179{
2180    /* We may want to cache the previous values and only send the notification
2181       to the plugin in the event that one of the values has changed.
2182     */
2183
2184    ANPRectI visibleRect;
2185    getVisibleScreen(visibleRect);
2186
2187    PluginWidgetAndroid** iter = m_plugins.begin();
2188    PluginWidgetAndroid** stop = m_plugins.end();
2189    for (; iter < stop; ++iter) {
2190        (*iter)->setVisibleScreen(visibleRect, m_scale);
2191    }
2192}
2193
2194void WebViewCore::sendPluginSurfaceReady()
2195{
2196    PluginWidgetAndroid** iter = m_plugins.begin();
2197    PluginWidgetAndroid** stop = m_plugins.end();
2198    for (; iter < stop; ++iter) {
2199        (*iter)->checkSurfaceReady();
2200    }
2201}
2202
2203void WebViewCore::sendPluginEvent(const ANPEvent& evt)
2204{
2205    /* The list of plugins may be manipulated as we iterate through the list.
2206       This implementation allows for the addition of new plugins during an
2207       iteration, but may fail if a plugin is removed. Currently, there are not
2208       any use cases where a plugin is deleted while processing this loop, but
2209       if it does occur we will have to use an alternate data structure and/or
2210       iteration mechanism.
2211     */
2212    for (int x = 0; x < m_plugins.count(); x++) {
2213        m_plugins[x]->sendEvent(evt);
2214    }
2215}
2216
2217PluginWidgetAndroid* WebViewCore::getPluginWidget(NPP npp)
2218{
2219    PluginWidgetAndroid** iter = m_plugins.begin();
2220    PluginWidgetAndroid** stop = m_plugins.end();
2221    for (; iter < stop; ++iter) {
2222        if ((*iter)->pluginView()->instance() == npp) {
2223            return (*iter);
2224        }
2225    }
2226    return 0;
2227}
2228
2229static PluginView* nodeIsPlugin(Node* node) {
2230    RenderObject* renderer = node->renderer();
2231    if (renderer && renderer->isWidget()) {
2232        Widget* widget = static_cast<RenderWidget*>(renderer)->widget();
2233        if (widget && widget->isPluginView())
2234            return static_cast<PluginView*>(widget);
2235    }
2236    return 0;
2237}
2238
2239Node* WebViewCore::cursorNodeIsPlugin() {
2240    gCursorBoundsMutex.lock();
2241    bool hasCursorBounds = m_hasCursorBounds;
2242    Frame* frame = (Frame*) m_cursorFrame;
2243    Node* node = (Node*) m_cursorNode;
2244    gCursorBoundsMutex.unlock();
2245    if (hasCursorBounds && CacheBuilder::validNode(m_mainFrame, frame, node)
2246            && nodeIsPlugin(node)) {
2247        return node;
2248    }
2249    return 0;
2250}
2251
2252///////////////////////////////////////////////////////////////////////////////
2253void WebViewCore::moveMouseIfLatest(int moveGeneration,
2254    WebCore::Frame* frame, int x, int y)
2255{
2256    DBG_NAV_LOGD("m_moveGeneration=%d moveGeneration=%d"
2257        " frame=%p x=%d y=%d",
2258        m_moveGeneration, moveGeneration, frame, x, y);
2259    if (m_moveGeneration > moveGeneration) {
2260        DBG_NAV_LOGD("m_moveGeneration=%d > moveGeneration=%d",
2261            m_moveGeneration, moveGeneration);
2262        return; // short-circuit if a newer move has already been generated
2263    }
2264    m_lastGeneration = moveGeneration;
2265    moveMouse(frame, x, y);
2266}
2267
2268void WebViewCore::moveFocus(WebCore::Frame* frame, WebCore::Node* node)
2269{
2270    DBG_NAV_LOGD("frame=%p node=%p", frame, node);
2271    if (!node || !CacheBuilder::validNode(m_mainFrame, frame, node)
2272            || !node->isElementNode())
2273        return;
2274    // Code borrowed from FocusController::advanceFocus
2275    WebCore::FocusController* focusController
2276            = m_mainFrame->page()->focusController();
2277    WebCore::Document* oldDoc
2278            = focusController->focusedOrMainFrame()->document();
2279    if (oldDoc->focusedNode() == node)
2280        return;
2281    if (node->document() != oldDoc)
2282        oldDoc->setFocusedNode(0);
2283    focusController->setFocusedFrame(frame);
2284    static_cast<WebCore::Element*>(node)->focus(false);
2285}
2286
2287// Update mouse position
2288void WebViewCore::moveMouse(WebCore::Frame* frame, int x, int y, HitTestResult* hoveredNode)
2289{
2290    DBG_NAV_LOGD("frame=%p x=%d y=%d scrollOffset=(%d,%d)", frame,
2291        x, y, m_scrollOffsetX, m_scrollOffsetY);
2292    if (!frame || !CacheBuilder::validNode(m_mainFrame, frame, 0))
2293        frame = m_mainFrame;
2294    // mouse event expects the position in the window coordinate
2295    m_mousePos = WebCore::IntPoint(x - m_scrollOffsetX, y - m_scrollOffsetY);
2296    // validNode will still return true if the node is null, as long as we have
2297    // a valid frame.  Do not want to make a call on frame unless it is valid.
2298    WebCore::PlatformMouseEvent mouseEvent(m_mousePos, m_mousePos,
2299        WebCore::NoButton, WebCore::MouseEventMoved, 1, false, false, false,
2300        false, WTF::currentTime());
2301    frame->eventHandler()->handleMouseMoveEvent(mouseEvent, hoveredNode);
2302#if ENABLE(ANDROID_NAVCACHE)
2303    updateCacheOnNodeChange();
2304#endif
2305}
2306
2307Position WebViewCore::getPositionForOffset(Node* node, int offset)
2308{
2309    Position start = firstPositionInNode(node);
2310    Position end = lastPositionInNode(node);
2311    Document* document = node->document();
2312    PassRefPtr<Range> range = Range::create(document, start, end);
2313    WebCore::CharacterIterator iterator(range.get());
2314    iterator.advance(offset);
2315    return iterator.range()->startPosition();
2316}
2317
2318void WebViewCore::setSelection(Node* node, int start, int end)
2319{
2320    RenderTextControl* control = toRenderTextControl(node);
2321    if (control)
2322        setSelectionRange(node, start, end);
2323    else {
2324        Position startPosition = getPositionForOffset(node, start);
2325        Position endPosition = getPositionForOffset(node, end);
2326        VisibleSelection selection(startPosition, endPosition);
2327        SelectionController* selector = node->document()->frame()->selection();
2328        selector->setSelection(selection);
2329    }
2330}
2331
2332void WebViewCore::setSelection(int start, int end)
2333{
2334    WebCore::Node* focus = currentFocus();
2335    if (!focus)
2336        return;
2337    if (start > end)
2338        swap(start, end);
2339
2340    // Tell our EditorClient that this change was generated from the UI, so it
2341    // does not need to echo it to the UI.
2342    EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
2343            m_mainFrame->editor()->client());
2344    client->setUiGeneratedSelectionChange(true);
2345    setSelection(focus, start, end);
2346    RenderTextControl* control = toRenderTextControl(focus);
2347    if (start != end && control) {
2348        // Fire a select event. No event is sent when the selection reduces to
2349        // an insertion point
2350        control->selectionChanged(true);
2351    }
2352    client->setUiGeneratedSelectionChange(false);
2353    WebCore::Frame* focusedFrame = focus->document()->frame();
2354    bool isPasswordField = false;
2355    if (focus->isElementNode()) {
2356        WebCore::Element* element = static_cast<WebCore::Element*>(focus);
2357        if (WebCore::InputElement* inputElement = element->toInputElement())
2358            isPasswordField = static_cast<WebCore::HTMLInputElement*>(inputElement)->isPasswordField();
2359    }
2360    // For password fields, this is done in the UI side via
2361    // bringPointIntoView, since the UI does the drawing.
2362    if ((control && control->isTextArea()) || !isPasswordField)
2363        revealSelection();
2364}
2365
2366String WebViewCore::modifySelection(const int direction, const int axis)
2367{
2368    DOMSelection* selection = m_mainFrame->domWindow()->getSelection();
2369    ASSERT(selection);
2370    // We've seen crashes where selection is null, but we don't know why
2371    // See http://b/5244036
2372    if (!selection)
2373        return String();
2374    if (selection->rangeCount() > 1)
2375        selection->removeAllRanges();
2376    switch (axis) {
2377        case AXIS_CHARACTER:
2378        case AXIS_WORD:
2379        case AXIS_SENTENCE:
2380            return modifySelectionTextNavigationAxis(selection, direction, axis);
2381        case AXIS_HEADING:
2382        case AXIS_SIBLING:
2383        case AXIS_PARENT_FIRST_CHILD:
2384        case AXIS_DOCUMENT:
2385            return modifySelectionDomNavigationAxis(selection, direction, axis);
2386        default:
2387            ALOGE("Invalid navigation axis: %d", axis);
2388            return String();
2389    }
2390}
2391
2392void WebViewCore::scrollNodeIntoView(Frame* frame, Node* node)
2393{
2394    if (!frame || !node)
2395        return;
2396
2397    Element* elementNode = 0;
2398
2399    // If not an Element, find a visible predecessor
2400    // Element to scroll into view.
2401    if (!node->isElementNode()) {
2402        HTMLElement* body = frame->document()->body();
2403        do {
2404            if (node == body)
2405                return;
2406            node = node->parentNode();
2407        } while (node && !node->isElementNode() && !isVisible(node));
2408    }
2409
2410    // Couldn't find a visible predecessor.
2411    if (!node)
2412        return;
2413
2414    elementNode = static_cast<Element*>(node);
2415    elementNode->scrollIntoViewIfNeeded(true);
2416}
2417
2418String WebViewCore::modifySelectionTextNavigationAxis(DOMSelection* selection, int direction, int axis)
2419{
2420    Node* body = m_mainFrame->document()->body();
2421
2422    ExceptionCode ec = 0;
2423    String markup;
2424
2425    // initialize the selection if necessary
2426    if (selection->rangeCount() == 0) {
2427        if (m_currentNodeDomNavigationAxis
2428                && CacheBuilder::validNode(m_mainFrame,
2429                m_mainFrame, m_currentNodeDomNavigationAxis)) {
2430            RefPtr<Range> rangeRef =
2431                selection->frame()->document()->createRange();
2432            rangeRef->selectNode(m_currentNodeDomNavigationAxis, ec);
2433            m_currentNodeDomNavigationAxis = 0;
2434            if (ec)
2435                return String();
2436            selection->addRange(rangeRef.get());
2437        } else if (currentFocus()) {
2438            selection->setPosition(currentFocus(), 0, ec);
2439        } else if (m_cursorNode
2440                && CacheBuilder::validNode(m_mainFrame,
2441                m_mainFrame, m_cursorNode)) {
2442            RefPtr<Range> rangeRef =
2443                selection->frame()->document()->createRange();
2444            rangeRef->selectNode(reinterpret_cast<Node*>(m_cursorNode), ec);
2445            if (ec)
2446                return String();
2447            selection->addRange(rangeRef.get());
2448        } else {
2449            selection->setPosition(body, 0, ec);
2450        }
2451        if (ec)
2452            return String();
2453    }
2454
2455    // collapse the selection
2456    if (direction == DIRECTION_FORWARD)
2457        selection->collapseToEnd(ec);
2458    else
2459        selection->collapseToStart(ec);
2460    if (ec)
2461        return String();
2462
2463    // Make sure the anchor node is a text node since we are generating
2464    // the markup of the selection which includes the anchor, the focus,
2465    // and any crossed nodes. Forcing the condition that the selection
2466    // starts and ends on text nodes guarantees symmetric selection markup.
2467    // Also this way the text content, rather its container, is highlighted.
2468    Node* anchorNode = selection->anchorNode();
2469    if (anchorNode->isElementNode()) {
2470        // Collapsed selection while moving forward points to the
2471        // next unvisited node and while moving backward to the
2472        // last visited node.
2473        if (direction == DIRECTION_FORWARD)
2474            advanceAnchorNode(selection, direction, markup, false, ec);
2475        else
2476            advanceAnchorNode(selection, direction, markup, true, ec);
2477        if (ec)
2478            return String();
2479        if (!markup.isEmpty())
2480            return markup;
2481    }
2482
2483    // If the selection is at the end of a non white space text move
2484    // it to the next visible text node with non white space content.
2485    // This is a workaround for the selection getting stuck.
2486    anchorNode = selection->anchorNode();
2487    if (anchorNode->isTextNode()) {
2488        if (direction == DIRECTION_FORWARD) {
2489            String suffix = anchorNode->textContent().substring(
2490                    selection->anchorOffset(), caretMaxOffset(anchorNode));
2491            // If at the end of non white space text we advance the
2492            // anchor node to either an input element or non empty text.
2493            if (suffix.stripWhiteSpace().isEmpty()) {
2494                advanceAnchorNode(selection, direction, markup, true, ec);
2495            }
2496        } else {
2497            String prefix = anchorNode->textContent().substring(0,
2498                    selection->anchorOffset());
2499            // If at the end of non white space text we advance the
2500            // anchor node to either an input element or non empty text.
2501            if (prefix.stripWhiteSpace().isEmpty()) {
2502                advanceAnchorNode(selection, direction, markup, true, ec);
2503            }
2504        }
2505        if (ec)
2506            return String();
2507        if (!markup.isEmpty())
2508            return markup;
2509    }
2510
2511    // extend the selection
2512    String directionStr;
2513    if (direction == DIRECTION_FORWARD)
2514        directionStr = "forward";
2515    else
2516        directionStr = "backward";
2517
2518    String axisStr;
2519    if (axis == AXIS_CHARACTER)
2520        axisStr = "character";
2521    else if (axis == AXIS_WORD)
2522        axisStr = "word";
2523    else
2524        axisStr = "sentence";
2525
2526    selection->modify("extend", directionStr, axisStr);
2527
2528    // Make sure the focus node is a text node in order to have the
2529    // selection generate symmetric markup because the latter
2530    // includes all nodes crossed by the selection.  Also this way
2531    // the text content, rather its container, is highlighted.
2532    Node* focusNode = selection->focusNode();
2533    if (focusNode->isElementNode()) {
2534        focusNode = getImplicitBoundaryNode(selection->focusNode(),
2535                selection->focusOffset(), direction);
2536        if (!focusNode)
2537            return String();
2538        if (direction == DIRECTION_FORWARD) {
2539            focusNode = focusNode->traversePreviousSiblingPostOrder(body);
2540            if (focusNode && !isContentTextNode(focusNode)) {
2541                Node* textNode = traverseNextContentTextNode(focusNode,
2542                        anchorNode, DIRECTION_BACKWARD);
2543                if (textNode)
2544                    anchorNode = textNode;
2545            }
2546            if (focusNode && isContentTextNode(focusNode)) {
2547                selection->extend(focusNode, caretMaxOffset(focusNode), ec);
2548                if (ec)
2549                    return String();
2550            }
2551        } else {
2552            focusNode = focusNode->traverseNextSibling();
2553            if (focusNode && !isContentTextNode(focusNode)) {
2554                Node* textNode = traverseNextContentTextNode(focusNode,
2555                        anchorNode, DIRECTION_FORWARD);
2556                if (textNode)
2557                    anchorNode = textNode;
2558            }
2559            if (anchorNode && isContentTextNode(anchorNode)) {
2560                selection->extend(focusNode, 0, ec);
2561                if (ec)
2562                    return String();
2563            }
2564        }
2565    }
2566
2567    // Enforce that the selection does not cross anchor boundaries. This is
2568    // a workaround for the asymmetric behavior of WebKit while crossing
2569    // anchors.
2570    anchorNode = getImplicitBoundaryNode(selection->anchorNode(),
2571            selection->anchorOffset(), direction);
2572    focusNode = getImplicitBoundaryNode(selection->focusNode(),
2573            selection->focusOffset(), direction);
2574    if (anchorNode && focusNode && anchorNode != focusNode) {
2575        Node* inputControl = getIntermediaryInputElement(anchorNode, focusNode,
2576                direction);
2577        if (inputControl) {
2578            if (direction == DIRECTION_FORWARD) {
2579                if (isDescendantOf(inputControl, anchorNode)) {
2580                    focusNode = inputControl;
2581                } else {
2582                    focusNode = inputControl->traversePreviousSiblingPostOrder(
2583                            body);
2584                    if (!focusNode)
2585                        focusNode = inputControl;
2586                }
2587                // We prefer a text node contained in the input element.
2588                if (!isContentTextNode(focusNode)) {
2589                    Node* textNode = traverseNextContentTextNode(focusNode,
2590                        anchorNode, DIRECTION_BACKWARD);
2591                    if (textNode)
2592                        focusNode = textNode;
2593                }
2594                // If we found text in the input select it.
2595                // Otherwise, select the input element itself.
2596                if (isContentTextNode(focusNode)) {
2597                    selection->extend(focusNode, caretMaxOffset(focusNode), ec);
2598                } else if (anchorNode != focusNode) {
2599                    // Note that the focusNode always has parent and that
2600                    // the offset can be one more that the index of the last
2601                    // element - this is how WebKit selects such elements.
2602                    selection->extend(focusNode->parentNode(),
2603                            focusNode->nodeIndex() + 1, ec);
2604                }
2605                if (ec)
2606                    return String();
2607            } else {
2608                if (isDescendantOf(inputControl, anchorNode)) {
2609                    focusNode = inputControl;
2610                } else {
2611                    focusNode = inputControl->traverseNextSibling();
2612                    if (!focusNode)
2613                        focusNode = inputControl;
2614                }
2615                // We prefer a text node contained in the input element.
2616                if (!isContentTextNode(focusNode)) {
2617                    Node* textNode = traverseNextContentTextNode(focusNode,
2618                            anchorNode, DIRECTION_FORWARD);
2619                    if (textNode)
2620                        focusNode = textNode;
2621                }
2622                // If we found text in the input select it.
2623                // Otherwise, select the input element itself.
2624                if (isContentTextNode(focusNode)) {
2625                    selection->extend(focusNode, caretMinOffset(focusNode), ec);
2626                } else if (anchorNode != focusNode) {
2627                    // Note that the focusNode always has parent and that
2628                    // the offset can be one more that the index of the last
2629                    // element - this is how WebKit selects such elements.
2630                    selection->extend(focusNode->parentNode(),
2631                            focusNode->nodeIndex() + 1, ec);
2632                }
2633                if (ec)
2634                   return String();
2635            }
2636        }
2637    }
2638
2639    // make sure the selection is visible
2640    if (direction == DIRECTION_FORWARD)
2641        scrollNodeIntoView(m_mainFrame, selection->focusNode());
2642    else
2643        scrollNodeIntoView(m_mainFrame, selection->anchorNode());
2644
2645    // format markup for the visible content
2646    RefPtr<Range> range = selection->getRangeAt(0, ec);
2647    if (ec)
2648        return String();
2649    IntRect bounds = range->boundingBox();
2650    selectAt(bounds.center().x(), bounds.center().y());
2651    markup = formatMarkup(selection);
2652    ALOGV("Selection markup: %s", markup.utf8().data());
2653
2654    return markup;
2655}
2656
2657Node* WebViewCore::getImplicitBoundaryNode(Node* node, unsigned offset, int direction)
2658{
2659    if (node->offsetInCharacters())
2660        return node;
2661    if (!node->hasChildNodes())
2662        return node;
2663    if (offset < node->childNodeCount())
2664        return node->childNode(offset);
2665    else
2666        if (direction == DIRECTION_FORWARD)
2667            return node->traverseNextSibling();
2668        else
2669            return node->traversePreviousNodePostOrder(
2670                    node->document()->body());
2671}
2672
2673Node* WebViewCore::getNextAnchorNode(Node* anchorNode, bool ignoreFirstNode, int direction)
2674{
2675    Node* body = 0;
2676    Node* currentNode = 0;
2677    if (direction == DIRECTION_FORWARD) {
2678        if (ignoreFirstNode)
2679            currentNode = anchorNode->traverseNextNode(body);
2680        else
2681            currentNode = anchorNode;
2682    } else {
2683        body = anchorNode->document()->body();
2684        if (ignoreFirstNode)
2685            currentNode = anchorNode->traversePreviousSiblingPostOrder(body);
2686        else
2687            currentNode = anchorNode;
2688    }
2689    while (currentNode) {
2690        if (isContentTextNode(currentNode)
2691                || isContentInputElement(currentNode))
2692            return currentNode;
2693        if (direction == DIRECTION_FORWARD)
2694            currentNode = currentNode->traverseNextNode();
2695        else
2696            currentNode = currentNode->traversePreviousNodePostOrder(body);
2697    }
2698    return 0;
2699}
2700
2701void WebViewCore::advanceAnchorNode(DOMSelection* selection, int direction,
2702        String& markup, bool ignoreFirstNode, ExceptionCode& ec)
2703{
2704    Node* anchorNode = getImplicitBoundaryNode(selection->anchorNode(),
2705            selection->anchorOffset(), direction);
2706    if (!anchorNode) {
2707        ec = NOT_FOUND_ERR;
2708        return;
2709    }
2710    // If the anchor offset is invalid i.e. the anchor node has no
2711    // child with that index getImplicitAnchorNode returns the next
2712    // logical node in the current direction. In such a case our
2713    // position in the DOM tree was has already been advanced,
2714    // therefore we there is no need to do that again.
2715    if (selection->anchorNode()->isElementNode()) {
2716        unsigned anchorOffset = selection->anchorOffset();
2717        unsigned childNodeCount = selection->anchorNode()->childNodeCount();
2718        if (anchorOffset >= childNodeCount)
2719            ignoreFirstNode = false;
2720    }
2721    // Find the next anchor node given our position in the DOM and
2722    // whether we want the current node to be considered as well.
2723    Node* nextAnchorNode = getNextAnchorNode(anchorNode, ignoreFirstNode,
2724            direction);
2725    if (!nextAnchorNode) {
2726        ec = NOT_FOUND_ERR;
2727        return;
2728    }
2729    if (nextAnchorNode->isElementNode()) {
2730        // If this is an input element tell the WebView thread
2731        // to set the cursor to that control.
2732        if (isContentInputElement(nextAnchorNode)) {
2733            IntRect bounds = nextAnchorNode->getRect();
2734            selectAt(bounds.center().x(), bounds.center().y());
2735        }
2736        Node* textNode = 0;
2737        // Treat the text content of links as any other text but
2738        // for the rest input elements select the control itself.
2739        if (nextAnchorNode->hasTagName(WebCore::HTMLNames::aTag))
2740            textNode = traverseNextContentTextNode(nextAnchorNode,
2741                    nextAnchorNode, direction);
2742        // We prefer to select the text content of the link if such,
2743        // otherwise just select the element itself.
2744        if (textNode) {
2745            nextAnchorNode = textNode;
2746        } else {
2747            if (direction == DIRECTION_FORWARD) {
2748                selection->setBaseAndExtent(nextAnchorNode,
2749                        caretMinOffset(nextAnchorNode), nextAnchorNode,
2750                        caretMaxOffset(nextAnchorNode), ec);
2751            } else {
2752                selection->setBaseAndExtent(nextAnchorNode,
2753                        caretMaxOffset(nextAnchorNode), nextAnchorNode,
2754                        caretMinOffset(nextAnchorNode), ec);
2755            }
2756            if (!ec)
2757                markup = formatMarkup(selection);
2758            // make sure the selection is visible
2759            scrollNodeIntoView(selection->frame(), nextAnchorNode);
2760            return;
2761        }
2762    }
2763    if (direction == DIRECTION_FORWARD)
2764        selection->setPosition(nextAnchorNode,
2765                caretMinOffset(nextAnchorNode), ec);
2766    else
2767        selection->setPosition(nextAnchorNode,
2768                caretMaxOffset(nextAnchorNode), ec);
2769}
2770
2771bool WebViewCore::isContentInputElement(Node* node)
2772{
2773  return (isVisible(node)
2774          && (node->hasTagName(WebCore::HTMLNames::selectTag)
2775          || node->hasTagName(WebCore::HTMLNames::aTag)
2776          || node->hasTagName(WebCore::HTMLNames::inputTag)
2777          || node->hasTagName(WebCore::HTMLNames::buttonTag)));
2778}
2779
2780bool WebViewCore::isContentTextNode(Node* node)
2781{
2782   if (!node || !node->isTextNode())
2783       return false;
2784   Text* textNode = static_cast<Text*>(node);
2785   return (isVisible(textNode) && textNode->length() > 0
2786       && !textNode->containsOnlyWhitespace());
2787}
2788
2789Text* WebViewCore::traverseNextContentTextNode(Node* fromNode, Node* toNode, int direction)
2790{
2791    Node* currentNode = fromNode;
2792    do {
2793        if (direction == DIRECTION_FORWARD)
2794            currentNode = currentNode->traverseNextNode(toNode);
2795        else
2796            currentNode = currentNode->traversePreviousNodePostOrder(toNode);
2797    } while (currentNode && !isContentTextNode(currentNode));
2798    return static_cast<Text*>(currentNode);
2799}
2800
2801Node* WebViewCore::getIntermediaryInputElement(Node* fromNode, Node* toNode, int direction)
2802{
2803    if (fromNode == toNode)
2804        return 0;
2805    if (direction == DIRECTION_FORWARD) {
2806        Node* currentNode = fromNode;
2807        while (currentNode && currentNode != toNode) {
2808            if (isContentInputElement(currentNode))
2809                return currentNode;
2810            currentNode = currentNode->traverseNextNodePostOrder();
2811        }
2812        currentNode = fromNode;
2813        while (currentNode && currentNode != toNode) {
2814            if (isContentInputElement(currentNode))
2815                return currentNode;
2816            currentNode = currentNode->traverseNextNode();
2817        }
2818    } else {
2819        Node* currentNode = fromNode->traversePreviousNode();
2820        while (currentNode && currentNode != toNode) {
2821            if (isContentInputElement(currentNode))
2822                return currentNode;
2823            currentNode = currentNode->traversePreviousNode();
2824        }
2825        currentNode = fromNode->traversePreviousNodePostOrder();
2826        while (currentNode && currentNode != toNode) {
2827            if (isContentInputElement(currentNode))
2828                return currentNode;
2829            currentNode = currentNode->traversePreviousNodePostOrder();
2830        }
2831    }
2832    return 0;
2833}
2834
2835bool WebViewCore::isDescendantOf(Node* parent, Node* node)
2836{
2837    Node* currentNode = node;
2838    while (currentNode) {
2839        if (currentNode == parent) {
2840            return true;
2841        }
2842        currentNode = currentNode->parentNode();
2843    }
2844    return false;
2845}
2846
2847String WebViewCore::modifySelectionDomNavigationAxis(DOMSelection* selection, int direction, int axis)
2848{
2849    HTMLElement* body = m_mainFrame->document()->body();
2850    if (!m_currentNodeDomNavigationAxis && selection->focusNode()) {
2851        m_currentNodeDomNavigationAxis = selection->focusNode();
2852        selection->empty();
2853        if (m_currentNodeDomNavigationAxis->isTextNode())
2854            m_currentNodeDomNavigationAxis =
2855                m_currentNodeDomNavigationAxis->parentNode();
2856    }
2857    if (!m_currentNodeDomNavigationAxis)
2858        m_currentNodeDomNavigationAxis = currentFocus();
2859    if (!m_currentNodeDomNavigationAxis
2860            || !CacheBuilder::validNode(m_mainFrame, m_mainFrame,
2861                                        m_currentNodeDomNavigationAxis))
2862        m_currentNodeDomNavigationAxis = body;
2863    Node* currentNode = m_currentNodeDomNavigationAxis;
2864    if (axis == AXIS_HEADING) {
2865        if (currentNode == body && direction == DIRECTION_BACKWARD)
2866            currentNode = currentNode->lastDescendant();
2867        do {
2868            if (direction == DIRECTION_FORWARD)
2869                currentNode = currentNode->traverseNextNode(body);
2870            else
2871                currentNode = currentNode->traversePreviousNode(body);
2872        } while (currentNode && (currentNode->isTextNode()
2873            || !isVisible(currentNode) || !isHeading(currentNode)));
2874    } else if (axis == AXIS_PARENT_FIRST_CHILD) {
2875        if (direction == DIRECTION_FORWARD) {
2876            currentNode = currentNode->firstChild();
2877            while (currentNode && (currentNode->isTextNode()
2878                    || !isVisible(currentNode)))
2879                currentNode = currentNode->nextSibling();
2880        } else {
2881            do {
2882                if (currentNode == body)
2883                    return String();
2884                currentNode = currentNode->parentNode();
2885            } while (currentNode && (currentNode->isTextNode()
2886                    || !isVisible(currentNode)));
2887        }
2888    } else if (axis == AXIS_SIBLING) {
2889        do {
2890            if (direction == DIRECTION_FORWARD)
2891                currentNode = currentNode->nextSibling();
2892            else {
2893                if (currentNode == body)
2894                    return String();
2895                currentNode = currentNode->previousSibling();
2896            }
2897        } while (currentNode && (currentNode->isTextNode()
2898                || !isVisible(currentNode)));
2899    } else if (axis == AXIS_DOCUMENT) {
2900        currentNode = body;
2901        if (direction == DIRECTION_FORWARD)
2902            currentNode = currentNode->lastDescendant();
2903    } else {
2904        ALOGE("Invalid axis: %d", axis);
2905        return String();
2906    }
2907    if (currentNode) {
2908        m_currentNodeDomNavigationAxis = currentNode;
2909        scrollNodeIntoView(m_mainFrame, currentNode);
2910        String selectionString = createMarkup(currentNode);
2911        ALOGV("Selection markup: %s", selectionString.utf8().data());
2912        return selectionString;
2913    }
2914    return String();
2915}
2916
2917bool WebViewCore::isHeading(Node* node)
2918{
2919    if (node->hasTagName(WebCore::HTMLNames::h1Tag)
2920            || node->hasTagName(WebCore::HTMLNames::h2Tag)
2921            || node->hasTagName(WebCore::HTMLNames::h3Tag)
2922            || node->hasTagName(WebCore::HTMLNames::h4Tag)
2923            || node->hasTagName(WebCore::HTMLNames::h5Tag)
2924            || node->hasTagName(WebCore::HTMLNames::h6Tag)) {
2925        return true;
2926    }
2927
2928    if (node->isElementNode()) {
2929        Element* element = static_cast<Element*>(node);
2930        String roleAttribute =
2931            element->getAttribute(WebCore::HTMLNames::roleAttr).string();
2932        if (equalIgnoringCase(roleAttribute, "heading"))
2933            return true;
2934    }
2935
2936    return false;
2937}
2938
2939bool WebViewCore::isVisible(Node* node)
2940{
2941    // start off an element
2942    Element* element = 0;
2943    if (node->isElementNode())
2944        element = static_cast<Element*>(node);
2945    else
2946        element = node->parentElement();
2947    // check renderer
2948    if (!element->renderer()) {
2949        return false;
2950    }
2951    // check size
2952    if (element->offsetHeight() == 0 || element->offsetWidth() == 0) {
2953        return false;
2954    }
2955    // check style
2956    Node* body = m_mainFrame->document()->body();
2957    Node* currentNode = element;
2958    while (currentNode && currentNode != body) {
2959        RenderStyle* style = currentNode->computedStyle();
2960        if (style &&
2961                (style->display() == NONE || style->visibility() == HIDDEN)) {
2962            return false;
2963        }
2964        currentNode = currentNode->parentNode();
2965    }
2966    return true;
2967}
2968
2969String WebViewCore::formatMarkup(DOMSelection* selection)
2970{
2971    ExceptionCode ec = 0;
2972    String markup = String();
2973    RefPtr<Range> wholeRange = selection->getRangeAt(0, ec);
2974    if (ec)
2975        return String();
2976    if (!wholeRange->startContainer() || !wholeRange->startContainer())
2977        return String();
2978    // Since formatted markup contains invisible nodes it
2979    // is created from the concatenation of the visible fragments.
2980    Node* firstNode = wholeRange->firstNode();
2981    Node* pastLastNode = wholeRange->pastLastNode();
2982    Node* currentNode = firstNode;
2983    RefPtr<Range> currentRange;
2984
2985    while (currentNode != pastLastNode) {
2986        Node* nextNode = currentNode->traverseNextNode();
2987        if (!isVisible(currentNode)) {
2988            if (currentRange) {
2989                markup = markup + currentRange->toHTML().utf8().data();
2990                currentRange = 0;
2991            }
2992        } else {
2993            if (!currentRange) {
2994                currentRange = selection->frame()->document()->createRange();
2995                if (ec)
2996                    break;
2997                if (currentNode == firstNode) {
2998                    currentRange->setStart(wholeRange->startContainer(),
2999                        wholeRange->startOffset(), ec);
3000                    if (ec)
3001                        break;
3002                } else {
3003                    currentRange->setStart(currentNode->parentNode(),
3004                        currentNode->nodeIndex(), ec);
3005                    if (ec)
3006                       break;
3007                }
3008            }
3009            if (nextNode == pastLastNode) {
3010                currentRange->setEnd(wholeRange->endContainer(),
3011                    wholeRange->endOffset(), ec);
3012                if (ec)
3013                    break;
3014                markup = markup + currentRange->toHTML().utf8().data();
3015            } else {
3016                if (currentNode->offsetInCharacters())
3017                    currentRange->setEnd(currentNode,
3018                        currentNode->maxCharacterOffset(), ec);
3019                else
3020                    currentRange->setEnd(currentNode->parentNode(),
3021                            currentNode->nodeIndex() + 1, ec);
3022                if (ec)
3023                    break;
3024            }
3025        }
3026        currentNode = nextNode;
3027    }
3028    return markup.stripWhiteSpace();
3029}
3030
3031void WebViewCore::selectAt(int x, int y)
3032{
3033    JNIEnv* env = JSC::Bindings::getJNIEnv();
3034    AutoJObject javaObject = m_javaGlue->object(env);
3035    if (!javaObject.get())
3036        return;
3037    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_selectAt, x, y);
3038    checkException(env);
3039}
3040
3041void WebViewCore::deleteSelection(int start, int end, int textGeneration)
3042{
3043    setSelection(start, end);
3044    if (start == end)
3045        return;
3046    WebCore::Node* focus = currentFocus();
3047    if (!focus)
3048        return;
3049    // Prevent our editor client from passing a message to change the
3050    // selection.
3051    EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
3052            m_mainFrame->editor()->client());
3053    client->setUiGeneratedSelectionChange(true);
3054    PlatformKeyboardEvent down(AKEYCODE_DEL, 0, 0, true, false, false, false);
3055    PlatformKeyboardEvent up(AKEYCODE_DEL, 0, 0, false, false, false, false);
3056    key(down);
3057    key(up);
3058    client->setUiGeneratedSelectionChange(false);
3059    m_textGeneration = textGeneration;
3060}
3061
3062void WebViewCore::replaceTextfieldText(int oldStart,
3063        int oldEnd, const WTF::String& replace, int start, int end,
3064        int textGeneration)
3065{
3066    WebCore::Node* focus = currentFocus();
3067    if (!focus)
3068        return;
3069    setSelection(oldStart, oldEnd);
3070    // Prevent our editor client from passing a message to change the
3071    // selection.
3072    EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
3073            m_mainFrame->editor()->client());
3074    client->setUiGeneratedSelectionChange(true);
3075    if (replace.length())
3076        WebCore::TypingCommand::insertText(focus->document(), replace,
3077                false);
3078    else
3079        WebCore::TypingCommand::deleteSelection(focus->document());
3080    client->setUiGeneratedSelectionChange(false);
3081    // setSelection calls revealSelection, so there is no need to do it here.
3082    setSelection(start, end);
3083    m_textGeneration = textGeneration;
3084}
3085
3086void WebViewCore::passToJs(int generation, const WTF::String& current,
3087    const PlatformKeyboardEvent& event)
3088{
3089    WebCore::Node* focus = currentFocus();
3090    if (!focus) {
3091        DBG_NAV_LOG("!focus");
3092        clearTextEntry();
3093        return;
3094    }
3095    // Block text field updates during a key press.
3096    m_blockTextfieldUpdates = true;
3097    // Also prevent our editor client from passing a message to change the
3098    // selection.
3099    EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
3100            m_mainFrame->editor()->client());
3101    client->setUiGeneratedSelectionChange(true);
3102    key(event);
3103    client->setUiGeneratedSelectionChange(false);
3104    m_blockTextfieldUpdates = false;
3105    m_textGeneration = generation;
3106    WTF::String test = getInputText(focus);
3107    if (test != current) {
3108        // If the text changed during the key event, update the UI text field.
3109        updateTextfield(focus, false, test);
3110    } else {
3111        DBG_NAV_LOG("test == current");
3112    }
3113    // Now that the selection has settled down, send it.
3114    updateTextSelection();
3115}
3116
3117void WebViewCore::scrollFocusedTextInput(float xPercent, int y)
3118{
3119    WebCore::Node* focus = currentFocus();
3120    if (!focus) {
3121        DBG_NAV_LOG("!focus");
3122        clearTextEntry();
3123        return;
3124    }
3125    WebCore::RenderTextControl* renderText = toRenderTextControl(focus);
3126    if (!renderText) {
3127        DBG_NAV_LOGD("renderer==%p || not text", renderer);
3128        clearTextEntry();
3129        return;
3130    }
3131
3132    int x = (int) (xPercent * (renderText->scrollWidth() -
3133        renderText->clientWidth()));
3134    DBG_NAV_LOGD("x=%d y=%d xPercent=%g scrollW=%d clientW=%d", x, y,
3135        xPercent, renderText->scrollWidth(), renderText->clientWidth());
3136    renderText->setScrollLeft(x);
3137    renderText->setScrollTop(y);
3138}
3139
3140void WebViewCore::setFocusControllerActive(bool active)
3141{
3142    m_mainFrame->page()->focusController()->setActive(active);
3143}
3144
3145void WebViewCore::saveDocumentState(WebCore::Frame* frame)
3146{
3147    if (!CacheBuilder::validNode(m_mainFrame, frame, 0))
3148        frame = m_mainFrame;
3149    WebCore::HistoryItem *item = frame->loader()->history()->currentItem();
3150
3151    // item can be null when there is no offical URL for the current page. This happens
3152    // when the content is loaded using with WebCoreFrameBridge::LoadData() and there
3153    // is no failing URL (common case is when content is loaded using data: scheme)
3154    if (item) {
3155        item->setDocumentState(frame->document()->formElementsState());
3156    }
3157}
3158
3159// Create an array of java Strings.
3160static jobjectArray makeLabelArray(JNIEnv* env, const uint16_t** labels, size_t count)
3161{
3162    jclass stringClass = env->FindClass("java/lang/String");
3163    ALOG_ASSERT(stringClass, "Could not find java/lang/String");
3164    jobjectArray array = env->NewObjectArray(count, stringClass, 0);
3165    ALOG_ASSERT(array, "Could not create new string array");
3166
3167    for (size_t i = 0; i < count; i++) {
3168        jobject newString = env->NewString(&labels[i][1], labels[i][0]);
3169        env->SetObjectArrayElement(array, i, newString);
3170        env->DeleteLocalRef(newString);
3171        checkException(env);
3172    }
3173    env->DeleteLocalRef(stringClass);
3174    return array;
3175}
3176
3177void WebViewCore::openFileChooser(PassRefPtr<WebCore::FileChooser> chooser)
3178{
3179    JNIEnv* env = JSC::Bindings::getJNIEnv();
3180    AutoJObject javaObject = m_javaGlue->object(env);
3181    if (!javaObject.get())
3182        return;
3183
3184    if (!chooser)
3185        return;
3186
3187    WTF::String acceptType = chooser->acceptTypes();
3188    jstring jAcceptType = wtfStringToJstring(env, acceptType, true);
3189    jstring jName = (jstring) env->CallObjectMethod(
3190            javaObject.get(), m_javaGlue->m_openFileChooser, jAcceptType);
3191    checkException(env);
3192    env->DeleteLocalRef(jAcceptType);
3193
3194    WTF::String wtfString = jstringToWtfString(env, jName);
3195    env->DeleteLocalRef(jName);
3196
3197    if (!wtfString.isEmpty())
3198        chooser->chooseFile(wtfString);
3199}
3200
3201void WebViewCore::listBoxRequest(WebCoreReply* reply, const uint16_t** labels, size_t count, const int enabled[], size_t enabledCount,
3202        bool multiple, const int selected[], size_t selectedCountOrSelection)
3203{
3204    ALOG_ASSERT(m_javaGlue->m_obj, "No java widget associated with this view!");
3205
3206    JNIEnv* env = JSC::Bindings::getJNIEnv();
3207    AutoJObject javaObject = m_javaGlue->object(env);
3208    if (!javaObject.get())
3209        return;
3210
3211    // If m_popupReply is not null, then we already have a list showing.
3212    if (m_popupReply != 0)
3213        return;
3214
3215    // Create an array of java Strings for the drop down.
3216    jobjectArray labelArray = makeLabelArray(env, labels, count);
3217
3218    // Create an array determining whether each item is enabled.
3219    jintArray enabledArray = env->NewIntArray(enabledCount);
3220    checkException(env);
3221    jint* ptrArray = env->GetIntArrayElements(enabledArray, 0);
3222    checkException(env);
3223    for (size_t i = 0; i < enabledCount; i++) {
3224        ptrArray[i] = enabled[i];
3225    }
3226    env->ReleaseIntArrayElements(enabledArray, ptrArray, 0);
3227    checkException(env);
3228
3229    if (multiple) {
3230        // Pass up an array representing which items are selected.
3231        jintArray selectedArray = env->NewIntArray(selectedCountOrSelection);
3232        checkException(env);
3233        jint* selArray = env->GetIntArrayElements(selectedArray, 0);
3234        checkException(env);
3235        for (size_t i = 0; i < selectedCountOrSelection; i++) {
3236            selArray[i] = selected[i];
3237        }
3238        env->ReleaseIntArrayElements(selectedArray, selArray, 0);
3239
3240        env->CallVoidMethod(javaObject.get(),
3241                m_javaGlue->m_requestListBox, labelArray, enabledArray,
3242                selectedArray);
3243        env->DeleteLocalRef(selectedArray);
3244    } else {
3245        // Pass up the single selection.
3246        env->CallVoidMethod(javaObject.get(),
3247                m_javaGlue->m_requestSingleListBox, labelArray, enabledArray,
3248                selectedCountOrSelection);
3249    }
3250
3251    env->DeleteLocalRef(labelArray);
3252    env->DeleteLocalRef(enabledArray);
3253    checkException(env);
3254
3255    Retain(reply);
3256    m_popupReply = reply;
3257}
3258
3259bool WebViewCore::key(const PlatformKeyboardEvent& event)
3260{
3261    WebCore::EventHandler* eventHandler;
3262    WebCore::Node* focusNode = currentFocus();
3263    if (focusNode) {
3264        WebCore::Frame* frame = focusNode->document()->frame();
3265        WebFrame* webFrame = WebFrame::getWebFrame(frame);
3266        eventHandler = frame->eventHandler();
3267        VisibleSelection old = frame->selection()->selection();
3268        EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
3269                m_mainFrame->editor()->client());
3270        client->setUiGeneratedSelectionChange(true);
3271        bool handled = eventHandler->keyEvent(event);
3272        client->setUiGeneratedSelectionChange(false);
3273        if (isContentEditable(focusNode)) {
3274            // keyEvent will return true even if the contentEditable did not
3275            // change its selection.  In the case that it does not, we want to
3276            // return false so that the key will be sent back to our navigation
3277            // system.
3278            handled |= frame->selection()->selection() != old;
3279        }
3280        return handled;
3281    } else {
3282        eventHandler = focusedFrame()->eventHandler();
3283    }
3284    return eventHandler->keyEvent(event);
3285}
3286
3287// For when the user clicks the trackball, presses dpad center, or types into an
3288// unfocused textfield.  In the latter case, 'fake' will be true
3289void WebViewCore::click(WebCore::Frame* frame, WebCore::Node* node, bool fake) {
3290    if (!node) {
3291        WebCore::IntPoint pt = m_mousePos;
3292        pt.move(m_scrollOffsetX, m_scrollOffsetY);
3293        WebCore::HitTestResult hitTestResult = m_mainFrame->eventHandler()->
3294                hitTestResultAtPoint(pt, false);
3295        node = hitTestResult.innerNode();
3296        frame = node->document()->frame();
3297        DBG_NAV_LOGD("m_mousePos=(%d,%d) m_scrollOffset=(%d,%d) pt=(%d,%d)"
3298            " node=%p", m_mousePos.x(), m_mousePos.y(),
3299            m_scrollOffsetX, m_scrollOffsetY, pt.x(), pt.y(), node);
3300    }
3301    if (node) {
3302        EditorClientAndroid* client
3303                = static_cast<EditorClientAndroid*>(
3304                m_mainFrame->editor()->client());
3305        client->setShouldChangeSelectedRange(false);
3306        handleMouseClick(frame, node, fake);
3307        client->setShouldChangeSelectedRange(true);
3308    }
3309}
3310
3311#if USE(ACCELERATED_COMPOSITING)
3312GraphicsLayerAndroid* WebViewCore::graphicsRootLayer() const
3313{
3314    RenderView* contentRenderer = m_mainFrame->contentRenderer();
3315    if (!contentRenderer)
3316        return 0;
3317    return static_cast<GraphicsLayerAndroid*>(
3318          contentRenderer->compositor()->rootPlatformLayer());
3319}
3320#endif
3321
3322bool WebViewCore::handleTouchEvent(int action, Vector<int>& ids, Vector<IntPoint>& points, int actionIndex, int metaState)
3323{
3324    bool preventDefault = false;
3325
3326#if USE(ACCELERATED_COMPOSITING)
3327    GraphicsLayerAndroid* rootLayer = graphicsRootLayer();
3328    if (rootLayer)
3329      rootLayer->pauseDisplay(true);
3330#endif
3331
3332#if ENABLE(TOUCH_EVENTS) // Android
3333    #define MOTION_EVENT_ACTION_POINTER_DOWN 5
3334    #define MOTION_EVENT_ACTION_POINTER_UP 6
3335
3336    WebCore::TouchEventType type = WebCore::TouchStart;
3337    WebCore::PlatformTouchPoint::State defaultTouchState;
3338    Vector<WebCore::PlatformTouchPoint::State> touchStates(points.size());
3339
3340    switch (action) {
3341    case 0: // MotionEvent.ACTION_DOWN
3342        type = WebCore::TouchStart;
3343        defaultTouchState = WebCore::PlatformTouchPoint::TouchPressed;
3344        break;
3345    case 1: // MotionEvent.ACTION_UP
3346        type = WebCore::TouchEnd;
3347        defaultTouchState = WebCore::PlatformTouchPoint::TouchReleased;
3348        break;
3349    case 2: // MotionEvent.ACTION_MOVE
3350        type = WebCore::TouchMove;
3351        defaultTouchState = WebCore::PlatformTouchPoint::TouchMoved;
3352        break;
3353    case 3: // MotionEvent.ACTION_CANCEL
3354        type = WebCore::TouchCancel;
3355        defaultTouchState = WebCore::PlatformTouchPoint::TouchCancelled;
3356        break;
3357    case 5: // MotionEvent.ACTION_POINTER_DOWN
3358        type = WebCore::TouchStart;
3359        defaultTouchState = WebCore::PlatformTouchPoint::TouchStationary;
3360        break;
3361    case 6: // MotionEvent.ACTION_POINTER_UP
3362        type = WebCore::TouchEnd;
3363        defaultTouchState = WebCore::PlatformTouchPoint::TouchStationary;
3364        break;
3365    case 0x100: // WebViewCore.ACTION_LONGPRESS
3366        type = WebCore::TouchLongPress;
3367        defaultTouchState = WebCore::PlatformTouchPoint::TouchPressed;
3368        break;
3369    case 0x200: // WebViewCore.ACTION_DOUBLETAP
3370        type = WebCore::TouchDoubleTap;
3371        defaultTouchState = WebCore::PlatformTouchPoint::TouchPressed;
3372        break;
3373    default:
3374        // We do not support other kinds of touch event inside WebCore
3375        // at the moment.
3376        ALOGW("Java passed a touch event type that we do not support in WebCore: %d", action);
3377        return 0;
3378    }
3379
3380    for (int c = 0; c < static_cast<int>(points.size()); c++) {
3381        points[c].setX(points[c].x() - m_scrollOffsetX);
3382        points[c].setY(points[c].y() - m_scrollOffsetY);
3383
3384        // Setting the touch state for each point.
3385        // Note: actionIndex will be 0 for all actions that are not ACTION_POINTER_DOWN/UP.
3386        if (action == MOTION_EVENT_ACTION_POINTER_DOWN && c == actionIndex) {
3387            touchStates[c] = WebCore::PlatformTouchPoint::TouchPressed;
3388        } else if (action == MOTION_EVENT_ACTION_POINTER_UP && c == actionIndex) {
3389            touchStates[c] = WebCore::PlatformTouchPoint::TouchReleased;
3390        } else {
3391            touchStates[c] = defaultTouchState;
3392        };
3393    }
3394
3395    WebCore::PlatformTouchEvent te(ids, points, type, touchStates, metaState);
3396    preventDefault = m_mainFrame->eventHandler()->handleTouchEvent(te);
3397#endif
3398
3399#if USE(ACCELERATED_COMPOSITING)
3400    if (rootLayer)
3401      rootLayer->pauseDisplay(false);
3402#endif
3403    return preventDefault;
3404}
3405
3406void WebViewCore::touchUp(int touchGeneration,
3407    WebCore::Frame* frame, WebCore::Node* node, int x, int y)
3408{
3409    if (touchGeneration == 0) {
3410        // m_mousePos should be set in getTouchHighlightRects()
3411        WebCore::HitTestResult hitTestResult = m_mainFrame->eventHandler()->hitTestResultAtPoint(m_mousePos, false);
3412        node = hitTestResult.innerNode();
3413        if (node)
3414            frame = node->document()->frame();
3415        else
3416            frame = 0;
3417        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);
3418    } else {
3419        if (m_touchGeneration > touchGeneration) {
3420            DBG_NAV_LOGD("m_touchGeneration=%d > touchGeneration=%d"
3421                " x=%d y=%d", m_touchGeneration, touchGeneration, x, y);
3422            return; // short circuit if a newer touch has been generated
3423        }
3424        // This moves m_mousePos to the correct place, and handleMouseClick uses
3425        // m_mousePos to determine where the click happens.
3426        moveMouse(frame, x, y);
3427        m_lastGeneration = touchGeneration;
3428    }
3429    if (frame && CacheBuilder::validNode(m_mainFrame, frame, 0)) {
3430        frame->loader()->resetMultipleFormSubmissionProtection();
3431    }
3432    DBG_NAV_LOGD("touchGeneration=%d handleMouseClick frame=%p node=%p"
3433        " x=%d y=%d", touchGeneration, frame, node, x, y);
3434    handleMouseClick(frame, node, false);
3435}
3436
3437// Check for the "x-webkit-soft-keyboard" attribute.  If it is there and
3438// set to hidden, do not show the soft keyboard.  Node passed as a parameter
3439// must not be null.
3440static bool shouldSuppressKeyboard(const WebCore::Node* node) {
3441    ALOG_ASSERT(node, "node passed to shouldSuppressKeyboard cannot be null");
3442    const NamedNodeMap* attributes = node->attributes();
3443    if (!attributes) return false;
3444    size_t length = attributes->length();
3445    for (size_t i = 0; i < length; i++) {
3446        const Attribute* a = attributes->attributeItem(i);
3447        if (a->localName() == "x-webkit-soft-keyboard" && a->value() == "hidden")
3448            return true;
3449    }
3450    return false;
3451}
3452
3453// Common code for both clicking with the trackball and touchUp
3454// Also used when typing into a non-focused textfield to give the textfield focus,
3455// in which case, 'fake' is set to true
3456bool WebViewCore::handleMouseClick(WebCore::Frame* framePtr, WebCore::Node* nodePtr, bool fake)
3457{
3458    bool valid = !framePtr || CacheBuilder::validNode(m_mainFrame, framePtr, nodePtr);
3459    WebFrame* webFrame = WebFrame::getWebFrame(m_mainFrame);
3460    if (valid && nodePtr) {
3461    // Need to special case area tags because an image map could have an area element in the middle
3462    // so when attempting to get the default, the point chosen would be follow the wrong link.
3463        if (nodePtr->hasTagName(WebCore::HTMLNames::areaTag)) {
3464            webFrame->setUserInitiatedAction(true);
3465            nodePtr->dispatchSimulatedClick(0, true, true);
3466            webFrame->setUserInitiatedAction(false);
3467            DBG_NAV_LOG("area");
3468            return true;
3469        }
3470    }
3471    if (!valid || !framePtr)
3472        framePtr = m_mainFrame;
3473    webFrame->setUserInitiatedAction(true);
3474    WebCore::PlatformMouseEvent mouseDown(m_mousePos, m_mousePos, WebCore::LeftButton,
3475            WebCore::MouseEventPressed, 1, false, false, false, false,
3476            WTF::currentTime());
3477    // ignore the return from as it will return true if the hit point can trigger selection change
3478    framePtr->eventHandler()->handleMousePressEvent(mouseDown);
3479    WebCore::PlatformMouseEvent mouseUp(m_mousePos, m_mousePos, WebCore::LeftButton,
3480            WebCore::MouseEventReleased, 1, false, false, false, false,
3481            WTF::currentTime());
3482    bool handled = framePtr->eventHandler()->handleMouseReleaseEvent(mouseUp);
3483    webFrame->setUserInitiatedAction(false);
3484
3485    // If the user clicked on a textfield, make the focusController active
3486    // so we show the blinking cursor.
3487    WebCore::Node* focusNode = currentFocus();
3488    DBG_NAV_LOGD("m_mousePos={%d,%d} focusNode=%p handled=%s", m_mousePos.x(),
3489        m_mousePos.y(), focusNode, handled ? "true" : "false");
3490    if (focusNode) {
3491        WebCore::RenderTextControl* rtc = toRenderTextControl(focusNode);
3492        if (rtc) {
3493            bool ime = !shouldSuppressKeyboard(focusNode)
3494                    && !(static_cast<WebCore::HTMLInputElement*>(focusNode))->readOnly();
3495            if (ime) {
3496#if ENABLE(WEB_AUTOFILL)
3497                if (rtc->isTextField()) {
3498                    EditorClientAndroid* editorC = static_cast<EditorClientAndroid*>(framePtr->page()->editorClient());
3499                    WebAutofill* autoFill = editorC->getAutofill();
3500                    autoFill->formFieldFocused(static_cast<HTMLFormControlElement*>(focusNode));
3501                }
3502#endif
3503                if (!fake) {
3504#if ENABLE(ANDROID_NAVCACHE)
3505                    // Force an update of the navcache as this will fire off a
3506                    // message to WebView that *must* have an updated focus.
3507                    m_frameCacheOutOfDate = true;
3508                    updateFrameCache();
3509#endif
3510                    initEditField(focusNode);
3511                }
3512            } else if (!fake) {
3513                requestKeyboard(false);
3514            }
3515        } else if (!fake){
3516            // If the selection is contentEditable, show the keyboard so the
3517            // user can type.  Otherwise hide the keyboard because no text
3518            // input is needed.
3519            if (isContentEditable(focusNode)) {
3520                initEditField(focusNode);
3521            } else if (!nodeIsPlugin(focusNode)) {
3522                clearTextEntry();
3523            }
3524        }
3525    } else if (!fake) {
3526        // There is no focusNode, so the keyboard is not needed.
3527        clearTextEntry();
3528    }
3529    return handled;
3530}
3531
3532WebViewCore::InputType WebViewCore::getInputType(Node* node)
3533{
3534    WebCore::RenderObject* renderer = node->renderer();
3535    if (!renderer)
3536        return WebViewCore::NONE;
3537    if (renderer->isTextArea())
3538        return WebViewCore::TEXT_AREA;
3539
3540    if (node->hasTagName(WebCore::HTMLNames::inputTag)) {
3541        HTMLInputElement* htmlInput = static_cast<HTMLInputElement*>(node);
3542        if (htmlInput->isPasswordField())
3543            return WebViewCore::PASSWORD;
3544        if (htmlInput->isSearchField())
3545            return WebViewCore::SEARCH;
3546        if (htmlInput->isEmailField())
3547            return WebViewCore::EMAIL;
3548        if (htmlInput->isNumberField())
3549            return WebViewCore::NUMBER;
3550        if (htmlInput->isTelephoneField())
3551            return WebViewCore::TELEPHONE;
3552        if (htmlInput->isTextField())
3553            return WebViewCore::NORMAL_TEXT_FIELD;
3554    }
3555
3556    if (node->isContentEditable())
3557        return WebViewCore::TEXT_AREA;
3558
3559    return WebViewCore::NONE;
3560}
3561
3562bool WebViewCore::isSpellCheckEnabled(Node* node)
3563{
3564    bool isEnabled = true;
3565    if (node->isElementNode()) {
3566        WebCore::Element* element = static_cast<WebCore::Element*>(node);
3567        isEnabled = element->isSpellCheckingEnabled();
3568    }
3569    return isEnabled;
3570}
3571
3572void WebViewCore::initEditField(Node* node)
3573{
3574    String text = getInputText(node);
3575    int start = 0;
3576    int end = 0;
3577    getSelectionOffsets(node, start, end);
3578    JNIEnv* env = JSC::Bindings::getJNIEnv();
3579    AutoJObject javaObject = m_javaGlue->object(env);
3580    if (!javaObject.get())
3581        return;
3582    m_textGeneration = 0;
3583    InputType inputType = getInputType(node);
3584    Document* document = node->document();
3585    PlatformKeyboardEvent tab(AKEYCODE_TAB, 0, 0, false, false, false, false);
3586    PassRefPtr<KeyboardEvent> tabEvent =
3587            KeyboardEvent::create(tab, document->defaultView());
3588    Node* nextFocus = document->nextFocusableNode(node, tabEvent.get());
3589    bool isNextText = isTextInput(nextFocus);
3590    bool spellCheckEnabled = isSpellCheckEnabled(node);
3591    String label = requestLabel(document->frame(), node);
3592    jstring fieldText = wtfStringToJstring(env, text, true);
3593    jstring labelText = wtfStringToJstring(env, text, false);
3594    SelectText* selectText = createSelectText(focusedFrame()->selection()->selection());
3595    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_initEditField,
3596            reinterpret_cast<int>(node), fieldText, inputType,
3597            spellCheckEnabled, isNextText, labelText, start, end,
3598            reinterpret_cast<int>(selectText));
3599    checkException(env);
3600}
3601
3602void WebViewCore::popupReply(int index)
3603{
3604    if (m_popupReply) {
3605        m_popupReply->replyInt(index);
3606        Release(m_popupReply);
3607        m_popupReply = 0;
3608    }
3609}
3610
3611void WebViewCore::popupReply(const int* array, int count)
3612{
3613    if (m_popupReply) {
3614        m_popupReply->replyIntArray(array, count);
3615        Release(m_popupReply);
3616        m_popupReply = 0;
3617    }
3618}
3619
3620void WebViewCore::formDidBlur(const WebCore::Node* node)
3621{
3622    // If the blur is on a text input, keep track of the node so we can
3623    // hide the soft keyboard when the new focus is set, if it is not a
3624    // text input.
3625    if (isTextInput(node))
3626        m_blurringNodePointer = reinterpret_cast<int>(node);
3627}
3628
3629// This is a slightly modified Node::nextNodeConsideringAtomicNodes() with the
3630// extra constraint of limiting the search to inside a containing parent
3631WebCore::Node* nextNodeWithinParent(WebCore::Node* parent, WebCore::Node* start)
3632{
3633    if (!isAtomicNode(start) && start->firstChild())
3634        return start->firstChild();
3635    if (start->nextSibling())
3636        return start->nextSibling();
3637    const Node *n = start;
3638    while (n && !n->nextSibling()) {
3639        n = n->parentNode();
3640        if (n == parent)
3641            return 0;
3642    }
3643    if (n)
3644        return n->nextSibling();
3645    return 0;
3646}
3647
3648void WebViewCore::focusNodeChanged(WebCore::Node* newFocus)
3649{
3650    JNIEnv* env = JSC::Bindings::getJNIEnv();
3651    AutoJObject javaObject = m_javaGlue->object(env);
3652    if (!javaObject.get())
3653        return;
3654    if (!isTextInput(newFocus) && m_blurringNodePointer) {
3655        env->CallVoidMethod(javaObject.get(), m_javaGlue->m_formDidBlur, m_blurringNodePointer);
3656        checkException(env);
3657        m_blurringNodePointer = 0;
3658    }
3659    HitTestResult focusHitResult;
3660    focusHitResult.setInnerNode(newFocus);
3661    focusHitResult.setInnerNonSharedNode(newFocus);
3662    if (newFocus && newFocus->isLink() && newFocus->isElementNode()) {
3663        focusHitResult.setURLElement(static_cast<Element*>(newFocus));
3664        if (newFocus->hasChildNodes() && !newFocus->hasTagName(HTMLNames::imgTag)) {
3665            // Check to see if any of the children are images, and if so
3666            // set them as the innerNode and innerNonSharedNode
3667            // This will stop when it hits the first image. I'm not sure what
3668            // should be done in the case of multiple images inside one anchor...
3669            Node* nextNode = newFocus->firstChild();
3670            bool found = false;
3671            while (nextNode) {
3672                if (nextNode->hasTagName(HTMLNames::imgTag)) {
3673                    found = true;
3674                    break;
3675                }
3676                nextNode = nextNodeWithinParent(newFocus, nextNode);
3677            }
3678            if (found) {
3679                focusHitResult.setInnerNode(nextNode);
3680                focusHitResult.setInnerNonSharedNode(nextNode);
3681            }
3682        }
3683    }
3684    AndroidHitTestResult androidHitTest(this, focusHitResult);
3685    jobject jHitTestObj = androidHitTest.createJavaObject(env);
3686    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_focusNodeChanged, jHitTestObj);
3687    env->DeleteLocalRef(jHitTestObj);
3688}
3689
3690void WebViewCore::addMessageToConsole(const WTF::String& message, unsigned int lineNumber, const WTF::String& sourceID, int msgLevel) {
3691    JNIEnv* env = JSC::Bindings::getJNIEnv();
3692    AutoJObject javaObject = m_javaGlue->object(env);
3693    if (!javaObject.get())
3694        return;
3695    jstring jMessageStr = wtfStringToJstring(env, message);
3696    jstring jSourceIDStr = wtfStringToJstring(env, sourceID);
3697    env->CallVoidMethod(javaObject.get(),
3698            m_javaGlue->m_addMessageToConsole, jMessageStr, lineNumber,
3699            jSourceIDStr, msgLevel);
3700    env->DeleteLocalRef(jMessageStr);
3701    env->DeleteLocalRef(jSourceIDStr);
3702    checkException(env);
3703}
3704
3705void WebViewCore::jsAlert(const WTF::String& url, const WTF::String& text)
3706{
3707    JNIEnv* env = JSC::Bindings::getJNIEnv();
3708    AutoJObject javaObject = m_javaGlue->object(env);
3709    if (!javaObject.get())
3710        return;
3711    jstring jInputStr = wtfStringToJstring(env, text);
3712    jstring jUrlStr = wtfStringToJstring(env, url);
3713    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_jsAlert, jUrlStr, jInputStr);
3714    env->DeleteLocalRef(jInputStr);
3715    env->DeleteLocalRef(jUrlStr);
3716    checkException(env);
3717}
3718
3719bool WebViewCore::exceededDatabaseQuota(const WTF::String& url, const WTF::String& databaseIdentifier, const unsigned long long currentQuota, unsigned long long estimatedSize)
3720{
3721#if ENABLE(DATABASE)
3722    JNIEnv* env = JSC::Bindings::getJNIEnv();
3723    AutoJObject javaObject = m_javaGlue->object(env);
3724    if (!javaObject.get())
3725        return false;
3726    jstring jDatabaseIdentifierStr = wtfStringToJstring(env, databaseIdentifier);
3727    jstring jUrlStr = wtfStringToJstring(env, url);
3728    env->CallVoidMethod(javaObject.get(),
3729            m_javaGlue->m_exceededDatabaseQuota, jUrlStr,
3730            jDatabaseIdentifierStr, currentQuota, estimatedSize);
3731    env->DeleteLocalRef(jDatabaseIdentifierStr);
3732    env->DeleteLocalRef(jUrlStr);
3733    checkException(env);
3734    return true;
3735#endif
3736}
3737
3738bool WebViewCore::reachedMaxAppCacheSize(const unsigned long long spaceNeeded)
3739{
3740#if ENABLE(OFFLINE_WEB_APPLICATIONS)
3741    JNIEnv* env = JSC::Bindings::getJNIEnv();
3742    AutoJObject javaObject = m_javaGlue->object(env);
3743    if (!javaObject.get())
3744        return false;
3745    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_reachedMaxAppCacheSize, spaceNeeded);
3746    checkException(env);
3747    return true;
3748#endif
3749}
3750
3751void WebViewCore::populateVisitedLinks(WebCore::PageGroup* group)
3752{
3753    JNIEnv* env = JSC::Bindings::getJNIEnv();
3754    AutoJObject javaObject = m_javaGlue->object(env);
3755    if (!javaObject.get())
3756        return;
3757    m_groupForVisitedLinks = group;
3758    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_populateVisitedLinks);
3759    checkException(env);
3760}
3761
3762void WebViewCore::geolocationPermissionsShowPrompt(const WTF::String& origin)
3763{
3764    JNIEnv* env = JSC::Bindings::getJNIEnv();
3765    AutoJObject javaObject = m_javaGlue->object(env);
3766    if (!javaObject.get())
3767        return;
3768    jstring originString = wtfStringToJstring(env, origin);
3769    env->CallVoidMethod(javaObject.get(),
3770                        m_javaGlue->m_geolocationPermissionsShowPrompt,
3771                        originString);
3772    env->DeleteLocalRef(originString);
3773    checkException(env);
3774}
3775
3776void WebViewCore::geolocationPermissionsHidePrompt()
3777{
3778    JNIEnv* env = JSC::Bindings::getJNIEnv();
3779    AutoJObject javaObject = m_javaGlue->object(env);
3780    if (!javaObject.get())
3781        return;
3782    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_geolocationPermissionsHidePrompt);
3783    checkException(env);
3784}
3785
3786jobject WebViewCore::getDeviceMotionService()
3787{
3788    JNIEnv* env = JSC::Bindings::getJNIEnv();
3789    AutoJObject javaObject = m_javaGlue->object(env);
3790    if (!javaObject.get())
3791        return 0;
3792    jobject object = env->CallObjectMethod(javaObject.get(), m_javaGlue->m_getDeviceMotionService);
3793    checkException(env);
3794    return object;
3795}
3796
3797jobject WebViewCore::getDeviceOrientationService()
3798{
3799    JNIEnv* env = JSC::Bindings::getJNIEnv();
3800    AutoJObject javaObject = m_javaGlue->object(env);
3801    if (!javaObject.get())
3802        return 0;
3803    jobject object = env->CallObjectMethod(javaObject.get(), m_javaGlue->m_getDeviceOrientationService);
3804    checkException(env);
3805    return object;
3806}
3807
3808bool WebViewCore::jsConfirm(const WTF::String& url, const WTF::String& text)
3809{
3810    JNIEnv* env = JSC::Bindings::getJNIEnv();
3811    AutoJObject javaObject = m_javaGlue->object(env);
3812    if (!javaObject.get())
3813        return false;
3814    jstring jInputStr = wtfStringToJstring(env, text);
3815    jstring jUrlStr = wtfStringToJstring(env, url);
3816    jboolean result = env->CallBooleanMethod(javaObject.get(), m_javaGlue->m_jsConfirm, jUrlStr, jInputStr);
3817    env->DeleteLocalRef(jInputStr);
3818    env->DeleteLocalRef(jUrlStr);
3819    checkException(env);
3820    return result;
3821}
3822
3823bool WebViewCore::jsPrompt(const WTF::String& url, const WTF::String& text, const WTF::String& defaultValue, WTF::String& result)
3824{
3825    JNIEnv* env = JSC::Bindings::getJNIEnv();
3826    AutoJObject javaObject = m_javaGlue->object(env);
3827    if (!javaObject.get())
3828        return false;
3829    jstring jUrlStr = wtfStringToJstring(env, url);
3830    jstring jInputStr = wtfStringToJstring(env, text);
3831    jstring jDefaultStr = wtfStringToJstring(env, defaultValue);
3832    jstring returnVal = static_cast<jstring>(env->CallObjectMethod(javaObject.get(), m_javaGlue->m_jsPrompt, jUrlStr, jInputStr, jDefaultStr));
3833    env->DeleteLocalRef(jUrlStr);
3834    env->DeleteLocalRef(jInputStr);
3835    env->DeleteLocalRef(jDefaultStr);
3836    checkException(env);
3837
3838    // If returnVal is null, it means that the user cancelled the dialog.
3839    if (!returnVal)
3840        return false;
3841
3842    result = jstringToWtfString(env, returnVal);
3843    env->DeleteLocalRef(returnVal);
3844    return true;
3845}
3846
3847bool WebViewCore::jsUnload(const WTF::String& url, const WTF::String& message)
3848{
3849    JNIEnv* env = JSC::Bindings::getJNIEnv();
3850    AutoJObject javaObject = m_javaGlue->object(env);
3851    if (!javaObject.get())
3852        return false;
3853    jstring jInputStr = wtfStringToJstring(env, message);
3854    jstring jUrlStr = wtfStringToJstring(env, url);
3855    jboolean result = env->CallBooleanMethod(javaObject.get(), m_javaGlue->m_jsUnload, jUrlStr, jInputStr);
3856    env->DeleteLocalRef(jInputStr);
3857    env->DeleteLocalRef(jUrlStr);
3858    checkException(env);
3859    return result;
3860}
3861
3862bool WebViewCore::jsInterrupt()
3863{
3864    JNIEnv* env = JSC::Bindings::getJNIEnv();
3865    AutoJObject javaObject = m_javaGlue->object(env);
3866    if (!javaObject.get())
3867        return false;
3868    jboolean result = env->CallBooleanMethod(javaObject.get(), m_javaGlue->m_jsInterrupt);
3869    checkException(env);
3870    return result;
3871}
3872
3873AutoJObject
3874WebViewCore::getJavaObject()
3875{
3876    return m_javaGlue->object(JSC::Bindings::getJNIEnv());
3877}
3878
3879jobject
3880WebViewCore::getWebViewJavaObject()
3881{
3882    JNIEnv* env = JSC::Bindings::getJNIEnv();
3883    AutoJObject javaObject = m_javaGlue->object(env);
3884    if (!javaObject.get())
3885        return 0;
3886    return env->GetObjectField(javaObject.get(), gWebViewCoreFields.m_webView);
3887}
3888
3889RenderTextControl* WebViewCore::toRenderTextControl(Node* node)
3890{
3891    RenderTextControl* rtc = 0;
3892    RenderObject* renderer = node->renderer();
3893    if (renderer && renderer->isTextControl()) {
3894        rtc = WebCore::toRenderTextControl(renderer);
3895    }
3896    return rtc;
3897}
3898
3899void WebViewCore::getSelectionOffsets(Node* node, int& start, int& end)
3900{
3901    RenderTextControl* rtc = toRenderTextControl(node);
3902    if (rtc) {
3903        start = rtc->selectionStart();
3904        end = rtc->selectionEnd();
3905    } else {
3906        // It must be content editable field.
3907        Document* document = node->document();
3908        Frame* frame = document->frame();
3909        SelectionController* selector = frame->selection();
3910        Position selectionStart = selector->start();
3911        Position selectionEnd = selector->end();
3912        Position startOfNode = firstPositionInNode(node);
3913        RefPtr<Range> startRange = Range::create(document, startOfNode,
3914                selectionStart);
3915        start = TextIterator::rangeLength(startRange.get(), true);
3916        RefPtr<Range> endRange = Range::create(document, startOfNode,
3917                selectionEnd);
3918        end = TextIterator::rangeLength(endRange.get(), true);
3919    }
3920}
3921
3922String WebViewCore::getInputText(Node* node)
3923{
3924    String text;
3925    WebCore::RenderTextControl* renderText = toRenderTextControl(node);
3926    if (renderText)
3927        text = renderText->text();
3928    else {
3929        // It must be content editable field.
3930        Position inNode(node, 0);
3931        Position start = firstPositionInNode(node);
3932        Position end = lastPositionInNode(node);
3933        VisibleSelection allEditableText(start, end);
3934        text = allEditableText.firstRange()->text();
3935    }
3936    return text;
3937}
3938
3939void WebViewCore::updateTextSelection()
3940{
3941    JNIEnv* env = JSC::Bindings::getJNIEnv();
3942    AutoJObject javaObject = m_javaGlue->object(env);
3943    if (!javaObject.get())
3944        return;
3945    WebCore::Node* focusNode = currentFocus();
3946    int start = 0;
3947    int end = 0;
3948    if (focusNode)
3949        getSelectionOffsets(focusNode, start, end);
3950    SelectText* selectText = createSelectText(focusedFrame()->selection()->selection());
3951    env->CallVoidMethod(javaObject.get(),
3952            m_javaGlue->m_updateTextSelection, reinterpret_cast<int>(focusNode),
3953            start, end, m_textGeneration, reinterpret_cast<int>(selectText));
3954    checkException(env);
3955}
3956
3957void WebViewCore::updateTextfield(WebCore::Node* ptr, bool changeToPassword,
3958        const WTF::String& text)
3959{
3960    JNIEnv* env = JSC::Bindings::getJNIEnv();
3961    AutoJObject javaObject = m_javaGlue->object(env);
3962    if (!javaObject.get())
3963        return;
3964    if (m_blockTextfieldUpdates)
3965        return;
3966    if (changeToPassword) {
3967        env->CallVoidMethod(javaObject.get(), m_javaGlue->m_updateTextfield,
3968                (int) ptr, true, 0, m_textGeneration);
3969        checkException(env);
3970        return;
3971    }
3972    jstring string = wtfStringToJstring(env, text);
3973    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_updateTextfield,
3974            (int) ptr, false, string, m_textGeneration);
3975    env->DeleteLocalRef(string);
3976    checkException(env);
3977}
3978
3979void WebViewCore::clearTextEntry()
3980{
3981    JNIEnv* env = JSC::Bindings::getJNIEnv();
3982    AutoJObject javaObject = m_javaGlue->object(env);
3983    if (!javaObject.get())
3984        return;
3985    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_clearTextEntry);
3986}
3987
3988void WebViewCore::setBackgroundColor(SkColor c)
3989{
3990    WebCore::FrameView* view = m_mainFrame->view();
3991    if (!view)
3992        return;
3993
3994    // need (int) cast to find the right constructor
3995    WebCore::Color bcolor((int)SkColorGetR(c), (int)SkColorGetG(c),
3996                          (int)SkColorGetB(c), (int)SkColorGetA(c));
3997    view->setBaseBackgroundColor(bcolor);
3998
3999    // Background color of 0 indicates we want a transparent background
4000    if (c == 0)
4001        view->setTransparent(true);
4002}
4003
4004jclass WebViewCore::getPluginClass(const WTF::String& libName, const char* className)
4005{
4006    JNIEnv* env = JSC::Bindings::getJNIEnv();
4007    AutoJObject javaObject = m_javaGlue->object(env);
4008    if (!javaObject.get())
4009        return 0;
4010
4011    jstring libString = wtfStringToJstring(env, libName);
4012    jstring classString = env->NewStringUTF(className);
4013    jobject pluginClass = env->CallObjectMethod(javaObject.get(),
4014                                           m_javaGlue->m_getPluginClass,
4015                                           libString, classString);
4016    checkException(env);
4017
4018    // cleanup unneeded local JNI references
4019    env->DeleteLocalRef(libString);
4020    env->DeleteLocalRef(classString);
4021
4022    if (pluginClass != 0) {
4023        return static_cast<jclass>(pluginClass);
4024    } else {
4025        return 0;
4026    }
4027}
4028
4029void WebViewCore::showFullScreenPlugin(jobject childView, int32_t orientation, NPP npp)
4030{
4031    JNIEnv* env = JSC::Bindings::getJNIEnv();
4032    AutoJObject javaObject = m_javaGlue->object(env);
4033    if (!javaObject.get())
4034        return;
4035
4036    env->CallVoidMethod(javaObject.get(),
4037                        m_javaGlue->m_showFullScreenPlugin,
4038                        childView, orientation, reinterpret_cast<int>(npp));
4039    checkException(env);
4040}
4041
4042void WebViewCore::hideFullScreenPlugin()
4043{
4044    JNIEnv* env = JSC::Bindings::getJNIEnv();
4045    AutoJObject javaObject = m_javaGlue->object(env);
4046    if (!javaObject.get())
4047        return;
4048    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_hideFullScreenPlugin);
4049    checkException(env);
4050}
4051
4052jobject WebViewCore::createSurface(jobject view)
4053{
4054    JNIEnv* env = JSC::Bindings::getJNIEnv();
4055    AutoJObject javaObject = m_javaGlue->object(env);
4056    if (!javaObject.get())
4057        return 0;
4058    jobject result = env->CallObjectMethod(javaObject.get(), m_javaGlue->m_createSurface, view);
4059    checkException(env);
4060    return result;
4061}
4062
4063jobject WebViewCore::addSurface(jobject view, int x, int y, int width, int height)
4064{
4065    JNIEnv* env = JSC::Bindings::getJNIEnv();
4066    AutoJObject javaObject = m_javaGlue->object(env);
4067    if (!javaObject.get())
4068        return 0;
4069    jobject result = env->CallObjectMethod(javaObject.get(),
4070                                           m_javaGlue->m_addSurface,
4071                                           view, x, y, width, height);
4072    checkException(env);
4073    return result;
4074}
4075
4076void WebViewCore::updateSurface(jobject childView, int x, int y, int width, int height)
4077{
4078    JNIEnv* env = JSC::Bindings::getJNIEnv();
4079    AutoJObject javaObject = m_javaGlue->object(env);
4080    if (!javaObject.get())
4081        return;
4082    env->CallVoidMethod(javaObject.get(),
4083                        m_javaGlue->m_updateSurface, childView,
4084                        x, y, width, height);
4085    checkException(env);
4086}
4087
4088void WebViewCore::destroySurface(jobject childView)
4089{
4090    JNIEnv* env = JSC::Bindings::getJNIEnv();
4091    AutoJObject javaObject = m_javaGlue->object(env);
4092    if (!javaObject.get())
4093        return;
4094    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_destroySurface, childView);
4095    checkException(env);
4096}
4097
4098jobject WebViewCore::getContext()
4099{
4100    JNIEnv* env = JSC::Bindings::getJNIEnv();
4101    AutoJObject javaObject = m_javaGlue->object(env);
4102    if (!javaObject.get())
4103        return 0;
4104
4105    jobject result = env->CallObjectMethod(javaObject.get(), m_javaGlue->m_getContext);
4106    checkException(env);
4107    return result;
4108}
4109
4110void WebViewCore::keepScreenOn(bool screenOn) {
4111    if ((screenOn && m_screenOnCounter == 0) || (!screenOn && m_screenOnCounter == 1)) {
4112        JNIEnv* env = JSC::Bindings::getJNIEnv();
4113        AutoJObject javaObject = m_javaGlue->object(env);
4114        if (!javaObject.get())
4115            return;
4116        env->CallVoidMethod(javaObject.get(), m_javaGlue->m_keepScreenOn, screenOn);
4117        checkException(env);
4118    }
4119
4120    // update the counter
4121    if (screenOn)
4122        m_screenOnCounter++;
4123    else if (m_screenOnCounter > 0)
4124        m_screenOnCounter--;
4125}
4126
4127bool WebViewCore::validNodeAndBounds(Frame* frame, Node* node,
4128    const IntRect& originalAbsoluteBounds)
4129{
4130    bool valid = CacheBuilder::validNode(m_mainFrame, frame, node);
4131    if (!valid)
4132        return false;
4133    RenderObject* renderer = node->renderer();
4134    if (!renderer)
4135        return false;
4136    IntRect absBounds = node->hasTagName(HTMLNames::areaTag)
4137        ? CacheBuilder::getAreaRect(static_cast<HTMLAreaElement*>(node))
4138        : renderer->absoluteBoundingBoxRect();
4139    return absBounds == originalAbsoluteBounds;
4140}
4141
4142void WebViewCore::showRect(int left, int top, int width, int height,
4143        int contentWidth, int contentHeight, float xPercentInDoc,
4144        float xPercentInView, float yPercentInDoc, float yPercentInView)
4145{
4146    JNIEnv* env = JSC::Bindings::getJNIEnv();
4147    AutoJObject javaObject = m_javaGlue->object(env);
4148    if (!javaObject.get())
4149        return;
4150    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_showRect,
4151            left, top, width, height, contentWidth, contentHeight,
4152            xPercentInDoc, xPercentInView, yPercentInDoc, yPercentInView);
4153    checkException(env);
4154}
4155
4156void WebViewCore::centerFitRect(int x, int y, int width, int height)
4157{
4158    JNIEnv* env = JSC::Bindings::getJNIEnv();
4159    AutoJObject javaObject = m_javaGlue->object(env);
4160    if (!javaObject.get())
4161        return;
4162    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_centerFitRect, x, y, width, height);
4163    checkException(env);
4164}
4165
4166void WebViewCore::setScrollbarModes(ScrollbarMode horizontalMode, ScrollbarMode verticalMode)
4167{
4168    JNIEnv* env = JSC::Bindings::getJNIEnv();
4169    AutoJObject javaObject = m_javaGlue->object(env);
4170    if (!javaObject.get())
4171        return;
4172    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_setScrollbarModes, horizontalMode, verticalMode);
4173    checkException(env);
4174}
4175
4176void WebViewCore::notifyWebAppCanBeInstalled()
4177{
4178    JNIEnv* env = JSC::Bindings::getJNIEnv();
4179    AutoJObject javaObject = m_javaGlue->object(env);
4180    if (!javaObject.get())
4181        return;
4182    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_setInstallableWebApp);
4183    checkException(env);
4184}
4185
4186#if ENABLE(VIDEO)
4187void WebViewCore::enterFullscreenForVideoLayer(int layerId, const WTF::String& url)
4188{
4189    JNIEnv* env = JSC::Bindings::getJNIEnv();
4190    AutoJObject javaObject = m_javaGlue->object(env);
4191    if (!javaObject.get())
4192        return;
4193    jstring jUrlStr = wtfStringToJstring(env, url);
4194    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_enterFullscreenForVideoLayer, layerId, jUrlStr);
4195    m_fullscreenVideoMode = true;
4196    checkException(env);
4197}
4198
4199void WebViewCore::exitFullscreenVideo()
4200{
4201    JNIEnv* env = JSC::Bindings::getJNIEnv();
4202    AutoJObject javaObject = m_javaGlue->object(env);
4203    if (!javaObject.get())
4204        return;
4205    if (m_fullscreenVideoMode) {
4206        env->CallVoidMethod(javaObject.get(), m_javaGlue->m_exitFullscreenVideo);
4207        m_fullscreenVideoMode = false;
4208    }
4209    checkException(env);
4210}
4211#endif
4212
4213void WebViewCore::setWebTextViewAutoFillable(int queryId, const string16& previewSummary)
4214{
4215#if ENABLE(WEB_AUTOFILL)
4216    JNIEnv* env = JSC::Bindings::getJNIEnv();
4217    AutoJObject javaObject = m_javaGlue->object(env);
4218    if (!javaObject.get())
4219        return;
4220    jstring preview = env->NewString(previewSummary.data(), previewSummary.length());
4221    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_setWebTextViewAutoFillable, queryId, preview);
4222    env->DeleteLocalRef(preview);
4223#endif
4224}
4225
4226bool WebViewCore::drawIsPaused() const
4227{
4228    // returning true says scrollview should be offscreen, which pauses
4229    // gifs. because this is not again queried when we stop scrolling, we don't
4230    // use the stopping currently.
4231    return false;
4232}
4233
4234void WebViewCore::setWebRequestContextUserAgent()
4235{
4236    // We cannot create a WebRequestContext, because we might not know it this is a private tab or not yet
4237    if (m_webRequestContext)
4238        m_webRequestContext->setUserAgent(WebFrame::getWebFrame(m_mainFrame)->userAgentForURL(0)); // URL not used
4239}
4240
4241void WebViewCore::setWebRequestContextCacheMode(int cacheMode)
4242{
4243    m_cacheMode = cacheMode;
4244    // We cannot create a WebRequestContext, because we might not know it this is a private tab or not yet
4245    if (!m_webRequestContext)
4246        return;
4247
4248    m_webRequestContext->setCacheMode(cacheMode);
4249}
4250
4251WebRequestContext* WebViewCore::webRequestContext()
4252{
4253    if (!m_webRequestContext) {
4254        Settings* settings = mainFrame()->settings();
4255        m_webRequestContext = new WebRequestContext(settings && settings->privateBrowsingEnabled());
4256        setWebRequestContextUserAgent();
4257        setWebRequestContextCacheMode(m_cacheMode);
4258    }
4259    return m_webRequestContext.get();
4260}
4261
4262void WebViewCore::scrollRenderLayer(int layer, const SkRect& rect)
4263{
4264#if USE(ACCELERATED_COMPOSITING)
4265    GraphicsLayerAndroid* root = graphicsRootLayer();
4266    if (!root)
4267        return;
4268
4269    LayerAndroid* layerAndroid = root->platformLayer();
4270    if (!layerAndroid)
4271        return;
4272
4273    LayerAndroid* target = layerAndroid->findById(layer);
4274    if (!target)
4275        return;
4276
4277    RenderLayer* owner = target->owningLayer();
4278    if (!owner)
4279        return;
4280
4281    if (owner->stackingContext())
4282        owner->scrollToOffset(rect.fLeft, rect.fTop);
4283#endif
4284}
4285
4286Vector<VisibleSelection> WebViewCore::getTextRanges(
4287        int startX, int startY, int endX, int endY)
4288{
4289    // These are the positions of the selection handles,
4290    // which reside below the line that they are selecting.
4291    // Use the vertical position higher, which will include
4292    // the selected text.
4293    startY--;
4294    endY--;
4295    VisiblePosition startSelect = visiblePositionForContentPoint(startX, startY);
4296    VisiblePosition endSelect =  visiblePositionForContentPoint(endX, endY);
4297    Position start = startSelect.deepEquivalent();
4298    Position end = endSelect.deepEquivalent();
4299    Vector<VisibleSelection> ranges;
4300    if (!start.isNull() && !end.isNull()) {
4301        if (comparePositions(start, end) > 0) {
4302            swap(start, end); // RTL start/end positions may be swapped
4303        }
4304        Position nextRangeStart = start;
4305        Position previousRangeEnd;
4306        int i = 0;
4307        do {
4308            VisibleSelection selection(nextRangeStart, end);
4309            ranges.append(selection);
4310            previousRangeEnd = selection.end();
4311            nextRangeStart = nextCandidate(previousRangeEnd);
4312        } while (comparePositions(previousRangeEnd, end) < 0);
4313    }
4314    return ranges;
4315}
4316
4317void WebViewCore::deleteText(int startX, int startY, int endX, int endY)
4318{
4319    Vector<VisibleSelection> ranges =
4320            getTextRanges(startX, startY, endX, endY);
4321
4322    EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
4323            m_mainFrame->editor()->client());
4324    client->setUiGeneratedSelectionChange(true);
4325
4326    SelectionController* selector = m_mainFrame->selection();
4327    for (size_t i = 0; i < ranges.size(); i++) {
4328        const VisibleSelection& selection = ranges[i];
4329        if (selection.isContentEditable()) {
4330            selector->setSelection(selection, CharacterGranularity);
4331            Document* document = selection.start().anchorNode()->document();
4332            WebCore::TypingCommand::deleteSelection(document, 0);
4333        }
4334    }
4335    client->setUiGeneratedSelectionChange(false);
4336}
4337
4338void WebViewCore::insertText(const WTF::String &text)
4339{
4340    WebCore::Node* focus = currentFocus();
4341    if (!focus || !isTextInput(focus))
4342        return;
4343
4344    Document* document = focus->document();
4345    Frame* frame = document->frame();
4346
4347    EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
4348            m_mainFrame->editor()->client());
4349    if (!client)
4350        return;
4351    client->setUiGeneratedSelectionChange(true);
4352    WebCore::TypingCommand::insertText(document, text,
4353            TypingCommand::PreventSpellChecking);
4354    client->setUiGeneratedSelectionChange(false);
4355}
4356
4357void WebViewCore::resetFindOnPage()
4358{
4359    m_searchText.truncate(0);
4360    m_matchCount = 0;
4361    m_activeMatchIndex = 0;
4362    m_activeMatch = 0;
4363}
4364
4365int WebViewCore::findTextOnPage(const WTF::String &text)
4366{
4367    resetFindOnPage(); // reset even if parameters are bad
4368
4369    WebCore::Frame* frame = m_mainFrame;
4370    if (!frame)
4371        return 0;
4372
4373    m_searchText = text;
4374    FindOptions findOptions = WebCore::CaseInsensitive;
4375
4376    do {
4377        frame->document()->markers()->removeMarkers(DocumentMarker::TextMatch);
4378        m_matchCount += frame->editor()->countMatchesForText(text, findOptions,
4379            0, true);
4380        updateMatchCount();
4381        frame->editor()->setMarkedTextMatchesAreHighlighted(true);
4382        frame = frame->tree()->traverseNextWithWrap(false);
4383    } while (frame);
4384
4385    m_activeMatchIndex = m_matchCount - 1; // prime first findNext
4386    findNextOnPage(true);
4387    return m_matchCount;
4388}
4389
4390void WebViewCore::findNextOnPage(bool forward)
4391{
4392    if (!m_mainFrame)
4393        return;
4394    if (!m_matchCount)
4395        return;
4396
4397    EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
4398        m_mainFrame->editor()->client());
4399    client->setUiGeneratedSelectionChange(true);
4400
4401    // Clear previous active match.
4402    if (m_activeMatch) {
4403        m_mainFrame->document()->markers()->setMarkersActive(
4404            m_activeMatch.get(), false);
4405    }
4406
4407    FindOptions findOptions = WebCore::CaseInsensitive
4408        | WebCore::StartInSelection | WebCore::WrapAround;
4409    if (!forward)
4410        findOptions |= WebCore::Backwards;
4411
4412    // Start from the previous active match.
4413    if (m_activeMatch) {
4414        m_mainFrame->selection()->setSelection(m_activeMatch.get());
4415    }
4416
4417    bool found = m_mainFrame->editor()->findString(m_searchText, findOptions);
4418    if (found) {
4419        VisibleSelection selection(m_mainFrame->selection()->selection());
4420        if (selection.isNone() || selection.start() == selection.end()) {
4421            // Temporary workaround for findString() refusing to select text
4422            // marked "-webkit-user-select: none".
4423            m_activeMatchIndex = 0;
4424            m_activeMatch = 0;
4425        } else {
4426            // Mark current match "active".
4427            if (forward) {
4428                ++m_activeMatchIndex;
4429                if (m_activeMatchIndex == m_matchCount)
4430                    m_activeMatchIndex = 0;
4431            } else {
4432                if (m_activeMatchIndex == 0)
4433                    m_activeMatchIndex = m_matchCount;
4434                --m_activeMatchIndex;
4435            }
4436            m_activeMatch = selection.firstRange();
4437            m_mainFrame->document()->markers()->setMarkersActive(
4438                m_activeMatch.get(), true);
4439            m_mainFrame->selection()->revealSelection(
4440                ScrollAlignment::alignCenterIfNeeded, true);
4441        }
4442        updateMatchCount();
4443    }
4444
4445    // Clear selection so it doesn't display.
4446    m_mainFrame->selection()->clear();
4447    client->setUiGeneratedSelectionChange(false);
4448}
4449
4450void WebViewCore::updateMatchCount() const
4451{
4452    JNIEnv* env = JSC::Bindings::getJNIEnv();
4453    AutoJObject javaObject = m_javaGlue->object(env);
4454    if (!javaObject.get())
4455        return;
4456    jstring javaText = wtfStringToJstring(env, m_searchText, true);
4457    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_updateMatchCount,
4458        m_activeMatchIndex, m_matchCount, javaText);
4459    checkException(env);
4460}
4461
4462String WebViewCore::getText(int startX, int startY, int endX, int endY)
4463{
4464    String text;
4465
4466    Vector<VisibleSelection> ranges =
4467            getTextRanges(startX, startY, endX, endY);
4468
4469    for (size_t i = 0; i < ranges.size(); i++) {
4470        const VisibleSelection& selection = ranges[i];
4471        PassRefPtr<Range> range = selection.firstRange();
4472        String textInRange = range->text();
4473        if (textInRange.length() > 0) {
4474            if (text.length() > 0)
4475                text.append('\n');
4476            text.append(textInRange);
4477        }
4478    }
4479
4480    return text;
4481}
4482
4483//----------------------------------------------------------------------
4484// Native JNI methods
4485//----------------------------------------------------------------------
4486static void RevealSelection(JNIEnv* env, jobject obj, jint nativeClass)
4487{
4488    reinterpret_cast<WebViewCore*>(nativeClass)->revealSelection();
4489}
4490
4491static jstring RequestLabel(JNIEnv* env, jobject obj, jint nativeClass,
4492        int framePointer, int nodePointer)
4493{
4494    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4495    return wtfStringToJstring(env, viewImpl->requestLabel(
4496            (WebCore::Frame*) framePointer, (WebCore::Node*) nodePointer));
4497}
4498
4499static void ClearContent(JNIEnv* env, jobject obj, jint nativeClass)
4500{
4501    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4502    viewImpl->clearContent();
4503}
4504
4505static void UpdateFrameCacheIfLoading(JNIEnv* env, jobject obj, jint nativeClass)
4506{
4507#if ENABLE(ANDROID_NAVCACHE)
4508        reinterpret_cast<WebViewCore*>(nativeClass)->updateFrameCacheIfLoading();
4509#endif
4510}
4511
4512static void SetSize(JNIEnv* env, jobject obj, jint nativeClass, jint width,
4513        jint height, jint textWrapWidth, jfloat scale, jint screenWidth,
4514        jint screenHeight, jint anchorX, jint anchorY, jboolean ignoreHeight)
4515{
4516    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4517    ALOGV("webviewcore::nativeSetSize(%u %u)\n viewImpl: %p", (unsigned)width, (unsigned)height, viewImpl);
4518    ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSetSize");
4519    viewImpl->setSizeScreenWidthAndScale(width, height, textWrapWidth, scale,
4520            screenWidth, screenHeight, anchorX, anchorY, ignoreHeight);
4521}
4522
4523static void SetScrollOffset(JNIEnv* env, jobject obj, jint nativeClass,
4524        jint gen, jboolean sendScrollEvent, jint x, jint y)
4525{
4526    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4527    ALOG_ASSERT(viewImpl, "need viewImpl");
4528
4529    viewImpl->setScrollOffset(gen, sendScrollEvent, x, y);
4530}
4531
4532static void SetGlobalBounds(JNIEnv* env, jobject obj, jint nativeClass,
4533        jint x, jint y, jint h, jint v)
4534{
4535    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4536    ALOG_ASSERT(viewImpl, "need viewImpl");
4537
4538    viewImpl->setGlobalBounds(x, y, h, v);
4539}
4540
4541static jboolean Key(JNIEnv* env, jobject obj, jint nativeClass, jint keyCode,
4542        jint unichar, jint repeatCount, jboolean isShift, jboolean isAlt,
4543        jboolean isSym, jboolean isDown)
4544{
4545    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4546    return viewImpl->key(PlatformKeyboardEvent(keyCode,
4547        unichar, repeatCount, isDown, isShift, isAlt, isSym));
4548}
4549
4550static void Click(JNIEnv* env, jobject obj, jint nativeClass, int framePtr,
4551        int nodePtr, jboolean fake)
4552{
4553    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4554    ALOG_ASSERT(viewImpl, "viewImpl not set in Click");
4555
4556    viewImpl->click(reinterpret_cast<WebCore::Frame*>(framePtr),
4557        reinterpret_cast<WebCore::Node*>(nodePtr), fake);
4558}
4559
4560static void ContentInvalidateAll(JNIEnv* env, jobject obj, jint nativeClass)
4561{
4562    reinterpret_cast<WebViewCore*>(nativeClass)->contentInvalidateAll();
4563}
4564
4565static void DeleteSelection(JNIEnv* env, jobject obj, jint nativeClass,
4566        jint start, jint end, jint textGeneration)
4567{
4568    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4569    viewImpl->deleteSelection(start, end, textGeneration);
4570}
4571
4572static void SetSelection(JNIEnv* env, jobject obj, jint nativeClass,
4573        jint start, jint end)
4574{
4575    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4576    viewImpl->setSelection(start, end);
4577}
4578
4579static jstring ModifySelection(JNIEnv* env, jobject obj, jint nativeClass,
4580        jint direction, jint granularity)
4581{
4582    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4583    String selectionString = viewImpl->modifySelection(direction, granularity);
4584    return wtfStringToJstring(env, selectionString);
4585}
4586
4587static void ReplaceTextfieldText(JNIEnv* env, jobject obj, jint nativeClass,
4588    jint oldStart, jint oldEnd, jstring replace, jint start, jint end,
4589    jint textGeneration)
4590{
4591    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4592    WTF::String webcoreString = jstringToWtfString(env, replace);
4593    viewImpl->replaceTextfieldText(oldStart,
4594            oldEnd, webcoreString, start, end, textGeneration);
4595}
4596
4597static void PassToJs(JNIEnv* env, jobject obj, jint nativeClass,
4598    jint generation, jstring currentText, jint keyCode,
4599    jint keyValue, jboolean down, jboolean cap, jboolean fn, jboolean sym)
4600{
4601    WTF::String current = jstringToWtfString(env, currentText);
4602    reinterpret_cast<WebViewCore*>(nativeClass)->passToJs(generation, current,
4603        PlatformKeyboardEvent(keyCode, keyValue, 0, down, cap, fn, sym));
4604}
4605
4606static void ScrollFocusedTextInput(JNIEnv* env, jobject obj, jint nativeClass,
4607        jfloat xPercent, jint y)
4608{
4609    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4610    viewImpl->scrollFocusedTextInput(xPercent, y);
4611}
4612
4613static void SetFocusControllerActive(JNIEnv* env, jobject obj, jint nativeClass,
4614        jboolean active)
4615{
4616    ALOGV("webviewcore::nativeSetFocusControllerActive()\n");
4617    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4618    ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSetFocusControllerActive");
4619    viewImpl->setFocusControllerActive(active);
4620}
4621
4622static void SaveDocumentState(JNIEnv* env, jobject obj, jint nativeClass,
4623        jint frame)
4624{
4625    ALOGV("webviewcore::nativeSaveDocumentState()\n");
4626    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4627    ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSaveDocumentState");
4628    viewImpl->saveDocumentState((WebCore::Frame*) frame);
4629}
4630
4631void WebViewCore::addVisitedLink(const UChar* string, int length)
4632{
4633    if (m_groupForVisitedLinks)
4634        m_groupForVisitedLinks->addVisitedLink(string, length);
4635}
4636
4637static bool UpdateLayers(JNIEnv* env, jobject obj, jint nativeClass,
4638        jint jbaseLayer)
4639{
4640    WebViewCore* viewImpl = (WebViewCore*) nativeClass;
4641    BaseLayerAndroid* baseLayer = (BaseLayerAndroid*)  jbaseLayer;
4642    if (baseLayer) {
4643        LayerAndroid* root = static_cast<LayerAndroid*>(baseLayer->getChild(0));
4644        if (root)
4645            return viewImpl->updateLayers(root);
4646    }
4647    return true;
4648}
4649
4650static void NotifyAnimationStarted(JNIEnv* env, jobject obj, jint nativeClass)
4651{
4652    WebViewCore* viewImpl = (WebViewCore*) nativeClass;
4653    viewImpl->notifyAnimationStarted();
4654}
4655
4656static jint RecordContent(JNIEnv* env, jobject obj, jint nativeClass,
4657        jobject region, jobject pt)
4658{
4659    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4660    SkRegion* nativeRegion = GraphicsJNI::getNativeRegion(env, region);
4661    SkIPoint nativePt;
4662    BaseLayerAndroid* result = viewImpl->recordContent(nativeRegion, &nativePt);
4663    GraphicsJNI::ipoint_to_jpoint(nativePt, env, pt);
4664    return reinterpret_cast<jint>(result);
4665}
4666
4667static void SplitContent(JNIEnv* env, jobject obj, jint nativeClass,
4668        jint content)
4669{
4670    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4671    viewImpl->splitContent(reinterpret_cast<PictureSet*>(content));
4672}
4673
4674static void SendListBoxChoice(JNIEnv* env, jobject obj, jint nativeClass,
4675        jint choice)
4676{
4677    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4678    ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoice");
4679    viewImpl->popupReply(choice);
4680}
4681
4682// Set aside a predetermined amount of space in which to place the listbox
4683// choices, to avoid unnecessary allocations.
4684// The size here is arbitrary.  We want the size to be at least as great as the
4685// number of items in the average multiple-select listbox.
4686#define PREPARED_LISTBOX_STORAGE 10
4687
4688static void SendListBoxChoices(JNIEnv* env, jobject obj, jint nativeClass,
4689        jbooleanArray jArray, jint size)
4690{
4691    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4692    ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoices");
4693    jboolean* ptrArray = env->GetBooleanArrayElements(jArray, 0);
4694    SkAutoSTMalloc<PREPARED_LISTBOX_STORAGE, int> storage(size);
4695    int* array = storage.get();
4696    int count = 0;
4697    for (int i = 0; i < size; i++) {
4698        if (ptrArray[i]) {
4699            array[count++] = i;
4700        }
4701    }
4702    env->ReleaseBooleanArrayElements(jArray, ptrArray, JNI_ABORT);
4703    viewImpl->popupReply(array, count);
4704}
4705
4706static jstring FindAddress(JNIEnv* env, jobject obj, jstring addr,
4707        jboolean caseInsensitive)
4708{
4709    if (!addr)
4710        return 0;
4711    int length = env->GetStringLength(addr);
4712    if (!length)
4713        return 0;
4714    const jchar* addrChars = env->GetStringChars(addr, 0);
4715    int start, end;
4716    bool success = CacheBuilder::FindAddress(addrChars, length,
4717        &start, &end, caseInsensitive) == CacheBuilder::FOUND_COMPLETE;
4718    jstring ret = 0;
4719    if (success)
4720        ret = env->NewString(addrChars + start, end - start);
4721    env->ReleaseStringChars(addr, addrChars);
4722    return ret;
4723}
4724
4725static jboolean HandleTouchEvent(JNIEnv* env, jobject obj, jint nativeClass,
4726        jint action, jintArray idArray, jintArray xArray, jintArray yArray,
4727        jint count, jint actionIndex, jint metaState)
4728{
4729    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4730    ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4731    jint* ptrIdArray = env->GetIntArrayElements(idArray, 0);
4732    jint* ptrXArray = env->GetIntArrayElements(xArray, 0);
4733    jint* ptrYArray = env->GetIntArrayElements(yArray, 0);
4734    Vector<int> ids(count);
4735    Vector<IntPoint> points(count);
4736    for (int c = 0; c < count; c++) {
4737        ids[c] = ptrIdArray[c];
4738        points[c].setX(ptrXArray[c]);
4739        points[c].setY(ptrYArray[c]);
4740    }
4741    env->ReleaseIntArrayElements(idArray, ptrIdArray, JNI_ABORT);
4742    env->ReleaseIntArrayElements(xArray, ptrXArray, JNI_ABORT);
4743    env->ReleaseIntArrayElements(yArray, ptrYArray, JNI_ABORT);
4744
4745    return viewImpl->handleTouchEvent(action, ids, points, actionIndex, metaState);
4746}
4747
4748static void TouchUp(JNIEnv* env, jobject obj, jint nativeClass,
4749        jint touchGeneration, jint frame, jint node, jint x, jint y)
4750{
4751    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4752    ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4753    viewImpl->touchUp(touchGeneration,
4754        (WebCore::Frame*) frame, (WebCore::Node*) node, x, y);
4755}
4756
4757static jstring RetrieveHref(JNIEnv* env, jobject obj, jint nativeClass,
4758        jint x, jint y)
4759{
4760    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4761    ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4762    WTF::String result = viewImpl->retrieveHref(x, y);
4763    if (!result.isEmpty())
4764        return wtfStringToJstring(env, result);
4765    return 0;
4766}
4767
4768static jstring RetrieveAnchorText(JNIEnv* env, jobject obj, jint nativeClass,
4769        jint x, jint y)
4770{
4771    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4772    ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4773    WTF::String result = viewImpl->retrieveAnchorText(x, y);
4774    if (!result.isEmpty())
4775        return wtfStringToJstring(env, result);
4776    return 0;
4777}
4778
4779static jstring RetrieveImageSource(JNIEnv* env, jobject obj, jint nativeClass,
4780        jint x, jint y)
4781{
4782    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4783    WTF::String result = viewImpl->retrieveImageSource(x, y);
4784    return !result.isEmpty() ? wtfStringToJstring(env, result) : 0;
4785}
4786
4787static void MoveFocus(JNIEnv* env, jobject obj, jint nativeClass, jint framePtr,
4788        jint nodePtr)
4789{
4790    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4791    ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4792    viewImpl->moveFocus((WebCore::Frame*) framePtr, (WebCore::Node*) nodePtr);
4793}
4794
4795static void MoveMouse(JNIEnv* env, jobject obj, jint nativeClass, jint frame,
4796        jint x, jint y)
4797{
4798    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4799    ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4800    viewImpl->moveMouse((WebCore::Frame*) frame, x, y);
4801}
4802
4803static void MoveMouseIfLatest(JNIEnv* env, jobject obj, jint nativeClass,
4804        jint moveGeneration, jint frame, jint x, jint y)
4805{
4806    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4807    ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4808    viewImpl->moveMouseIfLatest(moveGeneration,
4809        (WebCore::Frame*) frame, x, y);
4810}
4811
4812static void UpdateFrameCache(JNIEnv* env, jobject obj, jint nativeClass)
4813{
4814#if ENABLE(ANDROID_NAVCACHE)
4815        WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4816    ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4817    viewImpl->updateFrameCache();
4818#endif
4819}
4820
4821static jint GetContentMinPrefWidth(JNIEnv* env, jobject obj, jint nativeClass)
4822{
4823    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4824    ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4825
4826    WebCore::Frame* frame = viewImpl->mainFrame();
4827    if (frame) {
4828        WebCore::Document* document = frame->document();
4829        if (document) {
4830            WebCore::RenderObject* renderer = document->renderer();
4831            if (renderer && renderer->isRenderView()) {
4832                return renderer->minPreferredLogicalWidth();
4833            }
4834        }
4835    }
4836    return 0;
4837}
4838
4839static void SetViewportSettingsFromNative(JNIEnv* env, jobject obj,
4840        jint nativeClass)
4841{
4842    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4843    ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4844
4845    WebCore::Settings* s = viewImpl->mainFrame()->page()->settings();
4846    if (!s)
4847        return;
4848
4849#ifdef ANDROID_META_SUPPORT
4850    env->SetIntField(obj, gWebViewCoreFields.m_viewportWidth, s->viewportWidth());
4851    env->SetIntField(obj, gWebViewCoreFields.m_viewportHeight, s->viewportHeight());
4852    env->SetIntField(obj, gWebViewCoreFields.m_viewportInitialScale, s->viewportInitialScale());
4853    env->SetIntField(obj, gWebViewCoreFields.m_viewportMinimumScale, s->viewportMinimumScale());
4854    env->SetIntField(obj, gWebViewCoreFields.m_viewportMaximumScale, s->viewportMaximumScale());
4855    env->SetBooleanField(obj, gWebViewCoreFields.m_viewportUserScalable, s->viewportUserScalable());
4856    env->SetIntField(obj, gWebViewCoreFields.m_viewportDensityDpi, s->viewportTargetDensityDpi());
4857#endif
4858}
4859
4860static void SetBackgroundColor(JNIEnv* env, jobject obj, jint nativeClass,
4861        jint color)
4862{
4863    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4864    ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4865
4866    viewImpl->setBackgroundColor((SkColor) color);
4867}
4868
4869static void DumpDomTree(JNIEnv* env, jobject obj, jint nativeClass,
4870        jboolean useFile)
4871{
4872    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4873    ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4874
4875    viewImpl->dumpDomTree(useFile);
4876}
4877
4878static void DumpRenderTree(JNIEnv* env, jobject obj, jint nativeClass,
4879        jboolean useFile)
4880{
4881    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4882    ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4883
4884    viewImpl->dumpRenderTree(useFile);
4885}
4886
4887static void DumpNavTree(JNIEnv* env, jobject obj, jint nativeClass)
4888{
4889    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4890    ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4891
4892    viewImpl->dumpNavTree();
4893}
4894
4895static void SetJsFlags(JNIEnv* env, jobject obj, jint nativeClass, jstring flags)
4896{
4897    WTF::String flagsString = jstringToWtfString(env, flags);
4898    WTF::CString utf8String = flagsString.utf8();
4899    WebCore::ScriptController::setFlags(utf8String.data(), utf8String.length());
4900}
4901
4902
4903// Called from the Java side to set a new quota for the origin or new appcache
4904// max size in response to a notification that the original quota was exceeded or
4905// that the appcache has reached its maximum size.
4906static void SetNewStorageLimit(JNIEnv* env, jobject obj, jint nativeClass,
4907        jlong quota)
4908{
4909#if ENABLE(DATABASE) || ENABLE(OFFLINE_WEB_APPLICATIONS)
4910    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4911    Frame* frame = viewImpl->mainFrame();
4912
4913    // The main thread is blocked awaiting this response, so now we can wake it
4914    // up.
4915    ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(frame->page()->chrome()->client());
4916    chromeC->wakeUpMainThreadWithNewQuota(quota);
4917#endif
4918}
4919
4920// Called from Java to provide a Geolocation permission state for the specified origin.
4921static void GeolocationPermissionsProvide(JNIEnv* env, jobject obj,
4922        jint nativeClass, jstring origin, jboolean allow, jboolean remember)
4923{
4924    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4925    Frame* frame = viewImpl->mainFrame();
4926
4927    ChromeClientAndroid* chromeClient = static_cast<ChromeClientAndroid*>(frame->page()->chrome()->client());
4928    chromeClient->provideGeolocationPermissions(jstringToWtfString(env, origin), allow, remember);
4929}
4930
4931static void RegisterURLSchemeAsLocal(JNIEnv* env, jobject obj, jint nativeClass,
4932        jstring scheme)
4933{
4934    WebCore::SchemeRegistry::registerURLSchemeAsLocal(jstringToWtfString(env, scheme));
4935}
4936
4937static bool FocusBoundsChanged(JNIEnv* env, jobject obj, jint nativeClass)
4938{
4939    return reinterpret_cast<WebViewCore*>(nativeClass)->focusBoundsChanged();
4940}
4941
4942static void SetIsPaused(JNIEnv* env, jobject obj, jint nativeClass,
4943        jboolean isPaused)
4944{
4945    // tell the webcore thread to stop thinking while we do other work
4946    // (selection and scrolling). This has nothing to do with the lifecycle
4947    // pause and resume.
4948    reinterpret_cast<WebViewCore*>(nativeClass)->setIsPaused(isPaused);
4949}
4950
4951static void Pause(JNIEnv* env, jobject obj, jint nativeClass)
4952{
4953    // This is called for the foreground tab when the browser is put to the
4954    // background (and also for any tab when it is put to the background of the
4955    // browser). The browser can only be killed by the system when it is in the
4956    // background, so saving the Geolocation permission state now ensures that
4957    // is maintained when the browser is killed.
4958    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4959    ChromeClient* chromeClient = viewImpl->mainFrame()->page()->chrome()->client();
4960    ChromeClientAndroid* chromeClientAndroid = static_cast<ChromeClientAndroid*>(chromeClient);
4961    chromeClientAndroid->storeGeolocationPermissions();
4962
4963    Frame* mainFrame = viewImpl->mainFrame();
4964    for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext()) {
4965        Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation();
4966        if (geolocation)
4967            geolocation->suspend();
4968    }
4969
4970    viewImpl->deviceMotionAndOrientationManager()->maybeSuspendClients();
4971
4972    ANPEvent event;
4973    SkANP::InitEvent(&event, kLifecycle_ANPEventType);
4974    event.data.lifecycle.action = kPause_ANPLifecycleAction;
4975    viewImpl->sendPluginEvent(event);
4976
4977    viewImpl->setIsPaused(true);
4978}
4979
4980static void Resume(JNIEnv* env, jobject obj, jint nativeClass)
4981{
4982    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4983    Frame* mainFrame = viewImpl->mainFrame();
4984    for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext()) {
4985        Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation();
4986        if (geolocation)
4987            geolocation->resume();
4988    }
4989
4990    viewImpl->deviceMotionAndOrientationManager()->maybeResumeClients();
4991
4992    ANPEvent event;
4993    SkANP::InitEvent(&event, kLifecycle_ANPEventType);
4994    event.data.lifecycle.action = kResume_ANPLifecycleAction;
4995    viewImpl->sendPluginEvent(event);
4996
4997    viewImpl->setIsPaused(false);
4998}
4999
5000static void FreeMemory(JNIEnv* env, jobject obj, jint nativeClass)
5001{
5002    ANPEvent event;
5003    SkANP::InitEvent(&event, kLifecycle_ANPEventType);
5004    event.data.lifecycle.action = kFreeMemory_ANPLifecycleAction;
5005    reinterpret_cast<WebViewCore*>(nativeClass)->sendPluginEvent(event);
5006}
5007
5008static void ProvideVisitedHistory(JNIEnv* env, jobject obj, jint nativeClass,
5009        jobject hist)
5010{
5011    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
5012    ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
5013
5014    jobjectArray array = static_cast<jobjectArray>(hist);
5015
5016    jsize len = env->GetArrayLength(array);
5017    for (jsize i = 0; i < len; i++) {
5018        jstring item = static_cast<jstring>(env->GetObjectArrayElement(array, i));
5019        const UChar* str = static_cast<const UChar*>(env->GetStringChars(item, 0));
5020        jsize len = env->GetStringLength(item);
5021        viewImpl->addVisitedLink(str, len);
5022        env->ReleaseStringChars(item, str);
5023        env->DeleteLocalRef(item);
5024    }
5025}
5026
5027static void PluginSurfaceReady(JNIEnv* env, jobject obj, jint nativeClass)
5028{
5029    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
5030    if (viewImpl)
5031        viewImpl->sendPluginSurfaceReady();
5032}
5033
5034// Notification from the UI thread that the plugin's full-screen surface has been discarded
5035static void FullScreenPluginHidden(JNIEnv* env, jobject obj, jint nativeClass,
5036        jint npp)
5037{
5038    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
5039    PluginWidgetAndroid* plugin = viewImpl->getPluginWidget((NPP)npp);
5040    if (plugin)
5041        plugin->exitFullScreen(false);
5042}
5043
5044static WebCore::IntRect jrect_to_webrect(JNIEnv* env, jobject obj)
5045{
5046    int L, T, R, B;
5047    GraphicsJNI::get_jrect(env, obj, &L, &T, &R, &B);
5048    return WebCore::IntRect(L, T, R - L, B - T);
5049}
5050
5051static bool ValidNodeAndBounds(JNIEnv* env, jobject obj, jint nativeClass,
5052        int frame, int node, jobject rect)
5053{
5054    IntRect nativeRect = jrect_to_webrect(env, rect);
5055    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
5056    return viewImpl->validNodeAndBounds(
5057            reinterpret_cast<Frame*>(frame),
5058            reinterpret_cast<Node*>(node), nativeRect);
5059}
5060
5061static jobject HitTest(JNIEnv* env, jobject obj, jint nativeClass, jint x,
5062                       jint y, jint slop, jboolean doMoveMouse)
5063{
5064    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
5065    if (!viewImpl)
5066        return 0;
5067    Node* node = 0;
5068    AndroidHitTestResult result = viewImpl->hitTestAtPoint(x, y, slop, doMoveMouse);
5069    return result.createJavaObject(env);
5070}
5071
5072static void AutoFillForm(JNIEnv* env, jobject obj, jint nativeClass,
5073        jint queryId)
5074{
5075#if ENABLE(WEB_AUTOFILL)
5076    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
5077    if (!viewImpl)
5078        return;
5079
5080    WebCore::Frame* frame = viewImpl->mainFrame();
5081    if (frame) {
5082        EditorClientAndroid* editorC = static_cast<EditorClientAndroid*>(frame->page()->editorClient());
5083        WebAutofill* autoFill = editorC->getAutofill();
5084        autoFill->fillFormFields(queryId);
5085    }
5086#endif
5087}
5088
5089static void CloseIdleConnections(JNIEnv* env, jobject obj, jint nativeClass)
5090{
5091    WebCache::get(true)->closeIdleConnections();
5092    WebCache::get(false)->closeIdleConnections();
5093}
5094
5095static void nativeCertTrustChanged(JNIEnv *env, jobject obj)
5096{
5097#if USE(CHROME_NETWORK_STACK)
5098    WebCache::get(true)->certTrustChanged();
5099    WebCache::get(false)->certTrustChanged();
5100#endif
5101}
5102
5103static void ScrollRenderLayer(JNIEnv* env, jobject obj, jint nativeClass,
5104        jint layer, jobject jRect)
5105{
5106    SkRect rect;
5107    GraphicsJNI::jrect_to_rect(env, jRect, &rect);
5108    reinterpret_cast<WebViewCore*>(nativeClass)->scrollRenderLayer(layer, rect);
5109}
5110
5111static void DeleteText(JNIEnv* env, jobject obj, jint nativeClass,
5112        jint startX, jint startY, jint endX, jint endY)
5113{
5114    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
5115    viewImpl->deleteText(startX, startY, endX, endY);
5116}
5117
5118static void InsertText(JNIEnv* env, jobject obj, jint nativeClass,
5119        jstring text)
5120{
5121    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
5122    WTF::String wtfText = jstringToWtfString(env, text);
5123    viewImpl->insertText(wtfText);
5124}
5125
5126static jobject GetText(JNIEnv* env, jobject obj, jint nativeClass,
5127        jint startX, jint startY, jint endX, jint endY)
5128{
5129    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
5130    WTF::String text = viewImpl->getText(startX, startY, endX, endY);
5131    return text.isEmpty() ? 0 : wtfStringToJstring(env, text);
5132}
5133
5134static void SelectText(JNIEnv* env, jobject obj, jint nativeClass,
5135        jint startX, jint startY, jint endX, jint endY)
5136{
5137    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
5138    viewImpl->selectText(startX, startY, endX, endY);
5139}
5140
5141static void ClearSelection(JNIEnv* env, jobject obj, jint nativeClass)
5142{
5143    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
5144    viewImpl->focusedFrame()->selection()->clear();
5145}
5146
5147static void SelectWordAt(JNIEnv* env, jobject obj, jint nativeClass, jint x, jint y)
5148{
5149    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
5150    viewImpl->selectWordAt(x, y);
5151}
5152
5153static void SelectAll(JNIEnv* env, jobject obj, jint nativeClass)
5154{
5155    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
5156    viewImpl->focusedFrame()->selection()->selectAll();
5157}
5158
5159static int FindAll(JNIEnv* env, jobject obj, jint nativeClass,
5160        jstring text)
5161{
5162    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
5163    WTF::String wtfText = jstringToWtfString(env, text);
5164    return viewImpl->findTextOnPage(wtfText);
5165}
5166
5167static void FindNext(JNIEnv* env, jobject obj, jint nativeClass,
5168        jboolean forward)
5169{
5170    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
5171    viewImpl->findNextOnPage(forward);
5172}
5173
5174// ----------------------------------------------------------------------------
5175
5176/*
5177 * JNI registration.
5178 */
5179static JNINativeMethod gJavaWebViewCoreMethods[] = {
5180    { "nativeClearContent", "(I)V",
5181            (void*) ClearContent },
5182    { "nativeFocusBoundsChanged", "(I)Z",
5183        (void*) FocusBoundsChanged } ,
5184    { "nativeKey", "(IIIIZZZZ)Z",
5185        (void*) Key },
5186    { "nativeClick", "(IIIZ)V",
5187        (void*) Click },
5188    { "nativeContentInvalidateAll", "(I)V",
5189        (void*) ContentInvalidateAll },
5190    { "nativeSendListBoxChoices", "(I[ZI)V",
5191        (void*) SendListBoxChoices },
5192    { "nativeSendListBoxChoice", "(II)V",
5193        (void*) SendListBoxChoice },
5194    { "nativeSetSize", "(IIIIFIIIIZ)V",
5195        (void*) SetSize },
5196    { "nativeSetScrollOffset", "(IIZII)V",
5197        (void*) SetScrollOffset },
5198    { "nativeSetGlobalBounds", "(IIIII)V",
5199        (void*) SetGlobalBounds },
5200    { "nativeSetSelection", "(III)V",
5201        (void*) SetSelection } ,
5202    { "nativeModifySelection", "(III)Ljava/lang/String;",
5203        (void*) ModifySelection },
5204    { "nativeDeleteSelection", "(IIII)V",
5205        (void*) DeleteSelection } ,
5206    { "nativeReplaceTextfieldText", "(IIILjava/lang/String;III)V",
5207        (void*) ReplaceTextfieldText } ,
5208    { "nativeMoveFocus", "(III)V",
5209        (void*) MoveFocus },
5210    { "nativeMoveMouse", "(IIII)V",
5211        (void*) MoveMouse },
5212    { "nativeMoveMouseIfLatest", "(IIIII)V",
5213        (void*) MoveMouseIfLatest },
5214    { "passToJs", "(IILjava/lang/String;IIZZZZ)V",
5215        (void*) PassToJs },
5216    { "nativeScrollFocusedTextInput", "(IFI)V",
5217        (void*) ScrollFocusedTextInput },
5218    { "nativeSetFocusControllerActive", "(IZ)V",
5219        (void*) SetFocusControllerActive },
5220    { "nativeSaveDocumentState", "(II)V",
5221        (void*) SaveDocumentState },
5222    { "nativeFindAddress", "(Ljava/lang/String;Z)Ljava/lang/String;",
5223        (void*) FindAddress },
5224    { "nativeHandleTouchEvent", "(II[I[I[IIII)Z",
5225            (void*) HandleTouchEvent },
5226    { "nativeTouchUp", "(IIIIII)V",
5227        (void*) TouchUp },
5228    { "nativeRetrieveHref", "(III)Ljava/lang/String;",
5229        (void*) RetrieveHref },
5230    { "nativeRetrieveAnchorText", "(III)Ljava/lang/String;",
5231        (void*) RetrieveAnchorText },
5232    { "nativeRetrieveImageSource", "(III)Ljava/lang/String;",
5233        (void*) RetrieveImageSource },
5234    { "nativeUpdateFrameCache", "(I)V",
5235        (void*) UpdateFrameCache },
5236    { "nativeGetContentMinPrefWidth", "(I)I",
5237        (void*) GetContentMinPrefWidth },
5238    { "nativeUpdateLayers", "(II)Z",
5239        (void*) UpdateLayers },
5240    { "nativeNotifyAnimationStarted", "(I)V",
5241        (void*) NotifyAnimationStarted },
5242    { "nativeRecordContent", "(ILandroid/graphics/Region;Landroid/graphics/Point;)I",
5243        (void*) RecordContent },
5244    { "setViewportSettingsFromNative", "(I)V",
5245        (void*) SetViewportSettingsFromNative },
5246    { "nativeSplitContent", "(II)V",
5247        (void*) SplitContent },
5248    { "nativeSetBackgroundColor", "(II)V",
5249        (void*) SetBackgroundColor },
5250    { "nativeRegisterURLSchemeAsLocal", "(ILjava/lang/String;)V",
5251        (void*) RegisterURLSchemeAsLocal },
5252    { "nativeDumpDomTree", "(IZ)V",
5253        (void*) DumpDomTree },
5254    { "nativeDumpRenderTree", "(IZ)V",
5255        (void*) DumpRenderTree },
5256    { "nativeDumpNavTree", "(I)V",
5257        (void*) DumpNavTree },
5258    { "nativeSetNewStorageLimit", "(IJ)V",
5259        (void*) SetNewStorageLimit },
5260    { "nativeGeolocationPermissionsProvide", "(ILjava/lang/String;ZZ)V",
5261        (void*) GeolocationPermissionsProvide },
5262    { "nativeSetIsPaused", "(IZ)V", (void*) SetIsPaused },
5263    { "nativePause", "(I)V", (void*) Pause },
5264    { "nativeResume", "(I)V", (void*) Resume },
5265    { "nativeFreeMemory", "(I)V", (void*) FreeMemory },
5266    { "nativeSetJsFlags", "(ILjava/lang/String;)V", (void*) SetJsFlags },
5267    { "nativeRequestLabel", "(III)Ljava/lang/String;",
5268        (void*) RequestLabel },
5269    { "nativeRevealSelection", "(I)V", (void*) RevealSelection },
5270    { "nativeUpdateFrameCacheIfLoading", "(I)V",
5271        (void*) UpdateFrameCacheIfLoading },
5272    { "nativeProvideVisitedHistory", "(I[Ljava/lang/String;)V",
5273        (void*) ProvideVisitedHistory },
5274    { "nativeFullScreenPluginHidden", "(II)V",
5275        (void*) FullScreenPluginHidden },
5276    { "nativePluginSurfaceReady", "(I)V",
5277        (void*) PluginSurfaceReady },
5278    { "nativeValidNodeAndBounds", "(IIILandroid/graphics/Rect;)Z",
5279        (void*) ValidNodeAndBounds },
5280    { "nativeHitTest", "(IIIIZ)Landroid/webkit/WebViewCore$WebKitHitTest;",
5281        (void*) HitTest },
5282    { "nativeAutoFillForm", "(II)V",
5283        (void*) AutoFillForm },
5284    { "nativeScrollLayer", "(IILandroid/graphics/Rect;)V",
5285        (void*) ScrollRenderLayer },
5286    { "nativeCloseIdleConnections", "(I)V",
5287        (void*) CloseIdleConnections },
5288    { "nativeDeleteText", "(IIIII)V",
5289        (void*) DeleteText },
5290    { "nativeInsertText", "(ILjava/lang/String;)V",
5291        (void*) InsertText },
5292    { "nativeGetText", "(IIIII)Ljava/lang/String;",
5293        (void*) GetText },
5294    { "nativeSelectText", "(IIIII)V",
5295        (void*) SelectText },
5296    { "nativeClearTextSelection", "(I)V",
5297        (void*) ClearSelection },
5298    { "nativeSelectWordAt", "(III)V",
5299        (void*) SelectWordAt },
5300    { "nativeSelectAll", "(I)V",
5301        (void*) SelectAll },
5302    { "nativeCertTrustChanged","()V",
5303        (void*) nativeCertTrustChanged },
5304    { "nativeFindAll", "(ILjava/lang/String;)I",
5305        (void*) FindAll },
5306    { "nativeFindNext", "(IZ)V",
5307        (void*) FindNext },
5308};
5309
5310int registerWebViewCore(JNIEnv* env)
5311{
5312    jclass widget = env->FindClass("android/webkit/WebViewCore");
5313    ALOG_ASSERT(widget,
5314            "Unable to find class android/webkit/WebViewCore");
5315    gWebViewCoreFields.m_nativeClass = env->GetFieldID(widget, "mNativeClass",
5316            "I");
5317    ALOG_ASSERT(gWebViewCoreFields.m_nativeClass,
5318            "Unable to find android/webkit/WebViewCore.mNativeClass");
5319    gWebViewCoreFields.m_viewportWidth = env->GetFieldID(widget,
5320            "mViewportWidth", "I");
5321    ALOG_ASSERT(gWebViewCoreFields.m_viewportWidth,
5322            "Unable to find android/webkit/WebViewCore.mViewportWidth");
5323    gWebViewCoreFields.m_viewportHeight = env->GetFieldID(widget,
5324            "mViewportHeight", "I");
5325    ALOG_ASSERT(gWebViewCoreFields.m_viewportHeight,
5326            "Unable to find android/webkit/WebViewCore.mViewportHeight");
5327    gWebViewCoreFields.m_viewportInitialScale = env->GetFieldID(widget,
5328            "mViewportInitialScale", "I");
5329    ALOG_ASSERT(gWebViewCoreFields.m_viewportInitialScale,
5330            "Unable to find android/webkit/WebViewCore.mViewportInitialScale");
5331    gWebViewCoreFields.m_viewportMinimumScale = env->GetFieldID(widget,
5332            "mViewportMinimumScale", "I");
5333    ALOG_ASSERT(gWebViewCoreFields.m_viewportMinimumScale,
5334            "Unable to find android/webkit/WebViewCore.mViewportMinimumScale");
5335    gWebViewCoreFields.m_viewportMaximumScale = env->GetFieldID(widget,
5336            "mViewportMaximumScale", "I");
5337    ALOG_ASSERT(gWebViewCoreFields.m_viewportMaximumScale,
5338            "Unable to find android/webkit/WebViewCore.mViewportMaximumScale");
5339    gWebViewCoreFields.m_viewportUserScalable = env->GetFieldID(widget,
5340            "mViewportUserScalable", "Z");
5341    ALOG_ASSERT(gWebViewCoreFields.m_viewportUserScalable,
5342            "Unable to find android/webkit/WebViewCore.mViewportUserScalable");
5343    gWebViewCoreFields.m_viewportDensityDpi = env->GetFieldID(widget,
5344            "mViewportDensityDpi", "I");
5345    ALOG_ASSERT(gWebViewCoreFields.m_viewportDensityDpi,
5346            "Unable to find android/webkit/WebViewCore.mViewportDensityDpi");
5347    gWebViewCoreFields.m_webView = env->GetFieldID(widget,
5348            "mWebView", "Landroid/webkit/WebView;");
5349    ALOG_ASSERT(gWebViewCoreFields.m_webView,
5350            "Unable to find android/webkit/WebViewCore.mWebView");
5351    gWebViewCoreFields.m_drawIsPaused = env->GetFieldID(widget,
5352            "mDrawIsPaused", "Z");
5353    ALOG_ASSERT(gWebViewCoreFields.m_drawIsPaused,
5354            "Unable to find android/webkit/WebViewCore.mDrawIsPaused");
5355    gWebViewCoreFields.m_lowMemoryUsageMb = env->GetFieldID(widget, "mLowMemoryUsageThresholdMb", "I");
5356    gWebViewCoreFields.m_highMemoryUsageMb = env->GetFieldID(widget, "mHighMemoryUsageThresholdMb", "I");
5357    gWebViewCoreFields.m_highUsageDeltaMb = env->GetFieldID(widget, "mHighUsageDeltaMb", "I");
5358
5359    gWebViewCoreStaticMethods.m_isSupportedMediaMimeType =
5360        env->GetStaticMethodID(widget, "isSupportedMediaMimeType", "(Ljava/lang/String;)Z");
5361    LOG_FATAL_IF(!gWebViewCoreStaticMethods.m_isSupportedMediaMimeType,
5362        "Could not find static method isSupportedMediaMimeType from WebViewCore");
5363
5364    env->DeleteLocalRef(widget);
5365
5366    return jniRegisterNativeMethods(env, "android/webkit/WebViewCore",
5367            gJavaWebViewCoreMethods, NELEM(gJavaWebViewCoreMethods));
5368}
5369
5370} /* namespace android */
5371