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