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