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