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