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