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