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