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