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