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