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