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