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