WebViewCore.cpp revision 7f1e5ac384d6c663e2cb6b6bb7a58a300d16e1be
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_contentBounds;
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_contentBounds = env->GetFieldID(tfidClazz, "mContentBounds", "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(selection.affinity(), 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(), selection.affinity()));
1702    selectTextContainer->setTextRect(SelectText::EndHandle,
1703            positionToTextRect(selection.end(), selection.affinity()));
1704
1705    return selectTextContainer;
1706}
1707
1708IntRect WebViewCore::positionToTextRect(const Position& position, EAffinity affinity)
1709{
1710    IntRect textRect;
1711    InlineBox* inlineBox;
1712    int offset;
1713    position.getInlineBoxAndOffset(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
2963WebCore::IntRect WebViewCore::scrollFocusedTextInput(float xPercent, int y)
2964{
2965    WebCore::Node* focus = currentFocus();
2966    if (!focus) {
2967        clearTextEntry();
2968        return WebCore::IntRect();
2969    }
2970    WebCore::RenderTextControl* renderText = toRenderTextControl(focus);
2971    if (!renderText) {
2972        clearTextEntry();
2973        return WebCore::IntRect();
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    LayerAndroid* layer = 0;
2982    platformLayerIdFromNode(focus, &layer);
2983    return absoluteContentRect(focus, layer);
2984}
2985
2986void WebViewCore::setFocusControllerActive(bool active)
2987{
2988    m_mainFrame->page()->focusController()->setActive(active);
2989}
2990
2991void WebViewCore::saveDocumentState(WebCore::Frame* frame)
2992{
2993    if (!validNode(m_mainFrame, frame, 0))
2994        frame = m_mainFrame;
2995    WebCore::HistoryItem *item = frame->loader()->history()->currentItem();
2996
2997    // item can be null when there is no offical URL for the current page. This happens
2998    // when the content is loaded using with WebCoreFrameBridge::LoadData() and there
2999    // is no failing URL (common case is when content is loaded using data: scheme)
3000    if (item) {
3001        item->setDocumentState(frame->document()->formElementsState());
3002    }
3003}
3004
3005// Create an array of java Strings.
3006static jobjectArray makeLabelArray(JNIEnv* env, const uint16_t** labels, size_t count)
3007{
3008    jclass stringClass = env->FindClass("java/lang/String");
3009    ALOG_ASSERT(stringClass, "Could not find java/lang/String");
3010    jobjectArray array = env->NewObjectArray(count, stringClass, 0);
3011    ALOG_ASSERT(array, "Could not create new string array");
3012
3013    for (size_t i = 0; i < count; i++) {
3014        jobject newString = env->NewString(&labels[i][1], labels[i][0]);
3015        env->SetObjectArrayElement(array, i, newString);
3016        env->DeleteLocalRef(newString);
3017        checkException(env);
3018    }
3019    env->DeleteLocalRef(stringClass);
3020    return array;
3021}
3022
3023void WebViewCore::openFileChooser(PassRefPtr<WebCore::FileChooser> chooser)
3024{
3025    JNIEnv* env = JSC::Bindings::getJNIEnv();
3026    AutoJObject javaObject = m_javaGlue->object(env);
3027    if (!javaObject.get())
3028        return;
3029
3030    if (!chooser)
3031        return;
3032
3033    WTF::String acceptType = chooser->acceptTypes();
3034    jstring jAcceptType = wtfStringToJstring(env, acceptType, true);
3035    jstring jName = (jstring) env->CallObjectMethod(
3036            javaObject.get(), m_javaGlue->m_openFileChooser, jAcceptType);
3037    checkException(env);
3038    env->DeleteLocalRef(jAcceptType);
3039
3040    WTF::String wtfString = jstringToWtfString(env, jName);
3041    env->DeleteLocalRef(jName);
3042
3043    if (!wtfString.isEmpty())
3044        chooser->chooseFile(wtfString);
3045}
3046
3047void WebViewCore::listBoxRequest(WebCoreReply* reply, const uint16_t** labels, size_t count, const int enabled[], size_t enabledCount,
3048        bool multiple, const int selected[], size_t selectedCountOrSelection)
3049{
3050    ALOG_ASSERT(m_javaGlue->m_obj, "No java widget associated with this view!");
3051
3052    JNIEnv* env = JSC::Bindings::getJNIEnv();
3053    AutoJObject javaObject = m_javaGlue->object(env);
3054    if (!javaObject.get())
3055        return;
3056
3057    // If m_popupReply is not null, then we already have a list showing.
3058    if (m_popupReply != 0)
3059        return;
3060
3061    // Create an array of java Strings for the drop down.
3062    jobjectArray labelArray = makeLabelArray(env, labels, count);
3063
3064    // Create an array determining whether each item is enabled.
3065    jintArray enabledArray = env->NewIntArray(enabledCount);
3066    checkException(env);
3067    jint* ptrArray = env->GetIntArrayElements(enabledArray, 0);
3068    checkException(env);
3069    for (size_t i = 0; i < enabledCount; i++) {
3070        ptrArray[i] = enabled[i];
3071    }
3072    env->ReleaseIntArrayElements(enabledArray, ptrArray, 0);
3073    checkException(env);
3074
3075    if (multiple) {
3076        // Pass up an array representing which items are selected.
3077        jintArray selectedArray = env->NewIntArray(selectedCountOrSelection);
3078        checkException(env);
3079        jint* selArray = env->GetIntArrayElements(selectedArray, 0);
3080        checkException(env);
3081        for (size_t i = 0; i < selectedCountOrSelection; i++) {
3082            selArray[i] = selected[i];
3083        }
3084        env->ReleaseIntArrayElements(selectedArray, selArray, 0);
3085
3086        env->CallVoidMethod(javaObject.get(),
3087                m_javaGlue->m_requestListBox, labelArray, enabledArray,
3088                selectedArray);
3089        env->DeleteLocalRef(selectedArray);
3090    } else {
3091        // Pass up the single selection.
3092        env->CallVoidMethod(javaObject.get(),
3093                m_javaGlue->m_requestSingleListBox, labelArray, enabledArray,
3094                selectedCountOrSelection);
3095    }
3096
3097    env->DeleteLocalRef(labelArray);
3098    env->DeleteLocalRef(enabledArray);
3099    checkException(env);
3100
3101    Retain(reply);
3102    m_popupReply = reply;
3103}
3104
3105bool WebViewCore::key(const PlatformKeyboardEvent& event)
3106{
3107    WebCore::EventHandler* eventHandler;
3108    WebCore::Node* focusNode = currentFocus();
3109    if (focusNode) {
3110        WebCore::Frame* frame = focusNode->document()->frame();
3111        eventHandler = frame->eventHandler();
3112        VisibleSelection old = frame->selection()->selection();
3113        EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
3114                m_mainFrame->editor()->client());
3115        client->setUiGeneratedSelectionChange(true);
3116        bool handled = eventHandler->keyEvent(event);
3117        client->setUiGeneratedSelectionChange(false);
3118        if (isContentEditable(focusNode)) {
3119            // keyEvent will return true even if the contentEditable did not
3120            // change its selection.  In the case that it does not, we want to
3121            // return false so that the key will be sent back to our navigation
3122            // system.
3123            handled |= frame->selection()->selection() != old;
3124        }
3125        return handled;
3126    } else {
3127        eventHandler = focusedFrame()->eventHandler();
3128    }
3129    return eventHandler->keyEvent(event);
3130}
3131
3132bool WebViewCore::chromeCanTakeFocus(FocusDirection direction)
3133{
3134    JNIEnv* env = JSC::Bindings::getJNIEnv();
3135    AutoJObject javaObject = m_javaGlue->object(env);
3136    if (!javaObject.get())
3137        return false;
3138    return env->CallBooleanMethod(javaObject.get(), m_javaGlue->m_chromeCanTakeFocus, direction);
3139}
3140
3141void WebViewCore::chromeTakeFocus(FocusDirection direction)
3142{
3143    JNIEnv* env = JSC::Bindings::getJNIEnv();
3144    AutoJObject javaObject = m_javaGlue->object(env);
3145    if (!javaObject.get())
3146        return;
3147    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_chromeTakeFocus, direction);
3148}
3149
3150// For when the user clicks the trackball, presses dpad center, or types into an
3151// unfocused textfield.  In the latter case, 'fake' will be true
3152void WebViewCore::click(WebCore::Frame* frame, WebCore::Node* node, bool fake) {
3153    if (!node) {
3154        WebCore::IntPoint pt = m_mousePos;
3155        pt.move(m_scrollOffsetX, m_scrollOffsetY);
3156        WebCore::HitTestResult hitTestResult = m_mainFrame->eventHandler()->
3157                hitTestResultAtPoint(pt, false);
3158        node = hitTestResult.innerNode();
3159        frame = node->document()->frame();
3160    }
3161    if (node) {
3162        EditorClientAndroid* client
3163                = static_cast<EditorClientAndroid*>(
3164                m_mainFrame->editor()->client());
3165        client->setShouldChangeSelectedRange(false);
3166        handleMouseClick(frame, node, fake);
3167        client->setShouldChangeSelectedRange(true);
3168    }
3169}
3170
3171#if USE(ACCELERATED_COMPOSITING)
3172GraphicsLayerAndroid* WebViewCore::graphicsRootLayer() const
3173{
3174    RenderView* contentRenderer = m_mainFrame->contentRenderer();
3175    if (!contentRenderer)
3176        return 0;
3177    return static_cast<GraphicsLayerAndroid*>(
3178          contentRenderer->compositor()->rootPlatformLayer());
3179}
3180#endif
3181
3182bool WebViewCore::handleTouchEvent(int action, Vector<int>& ids, Vector<IntPoint>& points, int actionIndex, int metaState)
3183{
3184    bool preventDefault = false;
3185
3186#if USE(ACCELERATED_COMPOSITING)
3187    GraphicsLayerAndroid* rootLayer = graphicsRootLayer();
3188    if (rootLayer)
3189      rootLayer->pauseDisplay(true);
3190#endif
3191
3192#if ENABLE(TOUCH_EVENTS) // Android
3193    #define MOTION_EVENT_ACTION_POINTER_DOWN 5
3194    #define MOTION_EVENT_ACTION_POINTER_UP 6
3195
3196    WebCore::TouchEventType type = WebCore::TouchStart;
3197    WebCore::PlatformTouchPoint::State defaultTouchState;
3198    Vector<WebCore::PlatformTouchPoint::State> touchStates(points.size());
3199
3200    switch (action) {
3201    case 0: // MotionEvent.ACTION_DOWN
3202        type = WebCore::TouchStart;
3203        defaultTouchState = WebCore::PlatformTouchPoint::TouchPressed;
3204        break;
3205    case 1: // MotionEvent.ACTION_UP
3206        type = WebCore::TouchEnd;
3207        defaultTouchState = WebCore::PlatformTouchPoint::TouchReleased;
3208        break;
3209    case 2: // MotionEvent.ACTION_MOVE
3210        type = WebCore::TouchMove;
3211        defaultTouchState = WebCore::PlatformTouchPoint::TouchMoved;
3212        break;
3213    case 3: // MotionEvent.ACTION_CANCEL
3214        type = WebCore::TouchCancel;
3215        defaultTouchState = WebCore::PlatformTouchPoint::TouchCancelled;
3216        break;
3217    case 5: // MotionEvent.ACTION_POINTER_DOWN
3218        type = WebCore::TouchStart;
3219        defaultTouchState = WebCore::PlatformTouchPoint::TouchStationary;
3220        break;
3221    case 6: // MotionEvent.ACTION_POINTER_UP
3222        type = WebCore::TouchEnd;
3223        defaultTouchState = WebCore::PlatformTouchPoint::TouchStationary;
3224        break;
3225    case 0x100: // WebViewCore.ACTION_LONGPRESS
3226        type = WebCore::TouchLongPress;
3227        defaultTouchState = WebCore::PlatformTouchPoint::TouchPressed;
3228        break;
3229    case 0x200: // WebViewCore.ACTION_DOUBLETAP
3230        type = WebCore::TouchDoubleTap;
3231        defaultTouchState = WebCore::PlatformTouchPoint::TouchPressed;
3232        break;
3233    default:
3234        // We do not support other kinds of touch event inside WebCore
3235        // at the moment.
3236        ALOGW("Java passed a touch event type that we do not support in WebCore: %d", action);
3237        return 0;
3238    }
3239
3240    for (int c = 0; c < static_cast<int>(points.size()); c++) {
3241        points[c].setX(points[c].x() - m_scrollOffsetX);
3242        points[c].setY(points[c].y() - m_scrollOffsetY);
3243
3244        // Setting the touch state for each point.
3245        // Note: actionIndex will be 0 for all actions that are not ACTION_POINTER_DOWN/UP.
3246        if (action == MOTION_EVENT_ACTION_POINTER_DOWN && c == actionIndex) {
3247            touchStates[c] = WebCore::PlatformTouchPoint::TouchPressed;
3248        } else if (action == MOTION_EVENT_ACTION_POINTER_UP && c == actionIndex) {
3249            touchStates[c] = WebCore::PlatformTouchPoint::TouchReleased;
3250        } else {
3251            touchStates[c] = defaultTouchState;
3252        };
3253    }
3254
3255    WebCore::PlatformTouchEvent te(ids, points, type, touchStates, metaState);
3256    preventDefault = m_mainFrame->eventHandler()->handleTouchEvent(te);
3257#endif
3258
3259#if USE(ACCELERATED_COMPOSITING)
3260    if (rootLayer)
3261      rootLayer->pauseDisplay(false);
3262#endif
3263    return preventDefault;
3264}
3265
3266void WebViewCore::touchUp(int touchGeneration,
3267    WebCore::Frame* frame, WebCore::Node* node, int x, int y)
3268{
3269    if (touchGeneration == 0) {
3270        // m_mousePos should be set in getTouchHighlightRects()
3271        WebCore::HitTestResult hitTestResult = m_mainFrame->eventHandler()->hitTestResultAtPoint(m_mousePos, false);
3272        node = hitTestResult.innerNode();
3273        if (node)
3274            frame = node->document()->frame();
3275        else
3276            frame = 0;
3277    } else {
3278        if (m_touchGeneration > touchGeneration)
3279            return; // short circuit if a newer touch has been generated
3280        // This moves m_mousePos to the correct place, and handleMouseClick uses
3281        // m_mousePos to determine where the click happens.
3282        moveMouse(x, y);
3283        m_lastGeneration = touchGeneration;
3284    }
3285    if (frame && validNode(m_mainFrame, frame, 0)) {
3286        frame->loader()->resetMultipleFormSubmissionProtection();
3287    }
3288    handleMouseClick(frame, node, false);
3289}
3290
3291// Check for the "x-webkit-soft-keyboard" attribute.  If it is there and
3292// set to hidden, do not show the soft keyboard.  Node passed as a parameter
3293// must not be null.
3294static bool shouldSuppressKeyboard(const WebCore::Node* node) {
3295    ALOG_ASSERT(node, "node passed to shouldSuppressKeyboard cannot be null");
3296    const NamedNodeMap* attributes = node->attributes();
3297    if (!attributes) return false;
3298    size_t length = attributes->length();
3299    for (size_t i = 0; i < length; i++) {
3300        const Attribute* a = attributes->attributeItem(i);
3301        if (a->localName() == "x-webkit-soft-keyboard" && a->value() == "hidden")
3302            return true;
3303    }
3304    return false;
3305}
3306
3307// Common code for both clicking with the trackball and touchUp
3308// Also used when typing into a non-focused textfield to give the textfield focus,
3309// in which case, 'fake' is set to true
3310bool WebViewCore::handleMouseClick(WebCore::Frame* framePtr, WebCore::Node* nodePtr, bool fake)
3311{
3312    bool valid = !framePtr || validNode(m_mainFrame, framePtr, nodePtr);
3313    WebFrame* webFrame = WebFrame::getWebFrame(m_mainFrame);
3314    if (valid && nodePtr) {
3315    // Need to special case area tags because an image map could have an area element in the middle
3316    // so when attempting to get the default, the point chosen would be follow the wrong link.
3317        if (nodePtr->hasTagName(WebCore::HTMLNames::areaTag)) {
3318            webFrame->setUserInitiatedAction(true);
3319            nodePtr->dispatchSimulatedClick(0, true, true);
3320            webFrame->setUserInitiatedAction(false);
3321            return true;
3322        }
3323    }
3324    if (!valid || !framePtr)
3325        framePtr = m_mainFrame;
3326    webFrame->setUserInitiatedAction(true);
3327    WebCore::PlatformMouseEvent mouseDown(m_mousePos, m_mousePos, WebCore::LeftButton,
3328            WebCore::MouseEventPressed, 1, false, false, false, false,
3329            WTF::currentTime());
3330    // ignore the return from as it will return true if the hit point can trigger selection change
3331    framePtr->eventHandler()->handleMousePressEvent(mouseDown);
3332    WebCore::PlatformMouseEvent mouseUp(m_mousePos, m_mousePos, WebCore::LeftButton,
3333            WebCore::MouseEventReleased, 1, false, false, false, false,
3334            WTF::currentTime());
3335    bool handled = framePtr->eventHandler()->handleMouseReleaseEvent(mouseUp);
3336    webFrame->setUserInitiatedAction(false);
3337
3338    WebCore::Node* focusNode = currentFocus();
3339    initializeTextInput(focusNode, fake);
3340    return handled;
3341}
3342
3343WebViewCore::InputType WebViewCore::getInputType(Node* node)
3344{
3345    WebCore::RenderObject* renderer = node->renderer();
3346    if (!renderer)
3347        return WebViewCore::NONE;
3348    if (renderer->isTextArea())
3349        return WebViewCore::TEXT_AREA;
3350
3351    if (node->hasTagName(WebCore::HTMLNames::inputTag)) {
3352        HTMLInputElement* htmlInput = static_cast<HTMLInputElement*>(node);
3353        if (htmlInput->isPasswordField())
3354            return WebViewCore::PASSWORD;
3355        if (htmlInput->isSearchField())
3356            return WebViewCore::SEARCH;
3357        if (htmlInput->isEmailField())
3358            return WebViewCore::EMAIL;
3359        if (htmlInput->isNumberField())
3360            return WebViewCore::NUMBER;
3361        if (htmlInput->isTelephoneField())
3362            return WebViewCore::TELEPHONE;
3363        if (htmlInput->isTextField())
3364            return WebViewCore::NORMAL_TEXT_FIELD;
3365    }
3366
3367    if (node->isContentEditable())
3368        return WebViewCore::TEXT_AREA;
3369
3370    return WebViewCore::NONE;
3371}
3372
3373int WebViewCore::getMaxLength(Node* node)
3374{
3375    int maxLength = -1;
3376    if (node->hasTagName(WebCore::HTMLNames::inputTag)) {
3377        HTMLInputElement* htmlInput = static_cast<HTMLInputElement*>(node);
3378        maxLength = htmlInput->maxLength();
3379    }
3380    return maxLength;
3381}
3382
3383String WebViewCore::getFieldName(Node* node)
3384{
3385    String name;
3386    if (node->hasTagName(WebCore::HTMLNames::inputTag)) {
3387        HTMLInputElement* htmlInput = static_cast<HTMLInputElement*>(node);
3388        name = htmlInput->name();
3389    }
3390    return name;
3391}
3392
3393bool WebViewCore::isSpellCheckEnabled(Node* node)
3394{
3395    bool isEnabled = true;
3396    if (node->isElementNode()) {
3397        WebCore::Element* element = static_cast<WebCore::Element*>(node);
3398        isEnabled = element->isSpellCheckingEnabled();
3399    }
3400    return isEnabled;
3401}
3402
3403bool WebViewCore::isAutoCompleteEnabled(Node* node)
3404{
3405    bool isEnabled = false;
3406    if (node->hasTagName(WebCore::HTMLNames::inputTag)) {
3407        HTMLInputElement* htmlInput = static_cast<HTMLInputElement*>(node);
3408        isEnabled = htmlInput->autoComplete();
3409    }
3410    return isEnabled;
3411}
3412
3413WebCore::IntRect WebViewCore::absoluteContentRect(WebCore::Node* node,
3414        LayerAndroid* layer)
3415{
3416    IntRect contentRect;
3417    if (node) {
3418        RenderObject* render = node->renderer();
3419        if (render && render->isBox() && !render->isBody()) {
3420            IntPoint offset = convertGlobalContentToFrameContent(IntPoint(),
3421                    node->document()->frame());
3422            WebViewCore::layerToAbsoluteOffset(layer, offset);
3423
3424            RenderBox* renderBox = toRenderBox(render);
3425            contentRect = renderBox->absoluteContentBox();
3426            contentRect.move(-offset.x(), -offset.y());
3427        }
3428    }
3429    return contentRect;
3430}
3431
3432jobject WebViewCore::createTextFieldInitData(Node* node)
3433{
3434    JNIEnv* env = JSC::Bindings::getJNIEnv();
3435    TextFieldInitDataGlue* classDef = m_textFieldInitDataGlue;
3436    jclass clazz = env->FindClass("android/webkit/WebViewCore$TextFieldInitData");
3437    jobject initData = env->NewObject(clazz, classDef->m_constructor);
3438    env->SetIntField(initData, classDef->m_fieldPointer,
3439            reinterpret_cast<int>(node));
3440    env->SetObjectField(initData, classDef->m_text,
3441            wtfStringToJstring(env, getInputText(node), true));
3442    env->SetIntField(initData, classDef->m_type, getInputType(node));
3443    env->SetBooleanField(initData, classDef->m_isSpellCheckEnabled,
3444            isSpellCheckEnabled(node));
3445    Document* document = node->document();
3446    PlatformKeyboardEvent tab(AKEYCODE_TAB, 0, 0, false, false, false, false);
3447    PassRefPtr<KeyboardEvent> tabEvent =
3448            KeyboardEvent::create(tab, document->defaultView());
3449    env->SetBooleanField(initData, classDef->m_isTextFieldNext,
3450            isTextInput(document->nextFocusableNode(node, tabEvent.get())));
3451    env->SetBooleanField(initData, classDef->m_isTextFieldPrev,
3452            isTextInput(document->previousFocusableNode(node, tabEvent.get())));
3453    env->SetBooleanField(initData, classDef->m_isAutoCompleteEnabled,
3454            isAutoCompleteEnabled(node));
3455    env->SetObjectField(initData, classDef->m_name,
3456            wtfStringToJstring(env, getFieldName(node), false));
3457    env->SetObjectField(initData, classDef->m_name,
3458            wtfStringToJstring(env, requestLabel(document->frame(), node), false));
3459    env->SetIntField(initData, classDef->m_maxLength, getMaxLength(node));
3460    LayerAndroid* layer = 0;
3461    int layerId = platformLayerIdFromNode(node, &layer);
3462    IntRect bounds = absoluteContentRect(node, layer);
3463    env->SetObjectField(initData, classDef->m_contentBounds,
3464            intRectToRect(env, bounds));
3465    env->SetIntField(initData, classDef->m_nodeLayerId, layerId);
3466    IntRect contentRect;
3467    RenderTextControl* rtc = toRenderTextControl(node);
3468    if (rtc) {
3469        contentRect.setWidth(rtc->scrollWidth());
3470        contentRect.setHeight(rtc->scrollHeight());
3471        contentRect.move(-rtc->scrollLeft(), -rtc->scrollTop());
3472    }
3473    env->SetObjectField(initData, classDef->m_contentRect,
3474            intRectToRect(env, contentRect));
3475    return initData;
3476}
3477
3478void WebViewCore::initEditField(Node* node)
3479{
3480    JNIEnv* env = JSC::Bindings::getJNIEnv();
3481    AutoJObject javaObject = m_javaGlue->object(env);
3482    if (!javaObject.get())
3483        return;
3484    m_textGeneration = 0;
3485    int start = 0;
3486    int end = 0;
3487    getSelectionOffsets(node, start, end);
3488    SelectText* selectText = createSelectText(focusedFrame()->selection()->selection());
3489    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_initEditField,
3490            start, end, reinterpret_cast<int>(selectText),
3491            createTextFieldInitData(node));
3492    checkException(env);
3493}
3494
3495void WebViewCore::popupReply(int index)
3496{
3497    if (m_popupReply) {
3498        m_popupReply->replyInt(index);
3499        Release(m_popupReply);
3500        m_popupReply = 0;
3501    }
3502}
3503
3504void WebViewCore::popupReply(const int* array, int count)
3505{
3506    if (m_popupReply) {
3507        m_popupReply->replyIntArray(array, count);
3508        Release(m_popupReply);
3509        m_popupReply = 0;
3510    }
3511}
3512
3513// This is a slightly modified Node::nextNodeConsideringAtomicNodes() with the
3514// extra constraint of limiting the search to inside a containing parent
3515WebCore::Node* nextNodeWithinParent(WebCore::Node* parent, WebCore::Node* start)
3516{
3517    if (!isAtomicNode(start) && start->firstChild())
3518        return start->firstChild();
3519    if (start->nextSibling())
3520        return start->nextSibling();
3521    const Node *n = start;
3522    while (n && !n->nextSibling()) {
3523        n = n->parentNode();
3524        if (n == parent)
3525            return 0;
3526    }
3527    if (n)
3528        return n->nextSibling();
3529    return 0;
3530}
3531
3532void WebViewCore::initializeTextInput(WebCore::Node* node, bool fake)
3533{
3534    if (node) {
3535        if (isTextInput(node)) {
3536            bool showKeyboard = true;
3537            initEditField(node);
3538            WebCore::RenderTextControl* rtc = toRenderTextControl(node);
3539            if (rtc && node->hasTagName(HTMLNames::inputTag)) {
3540                HTMLInputElement* inputElement = static_cast<HTMLInputElement*>(node);
3541                bool ime = !shouldSuppressKeyboard(node) && !inputElement->readOnly();
3542                if (ime) {
3543#if ENABLE(WEB_AUTOFILL)
3544                    if (rtc->isTextField()) {
3545                        Page* page = node->document()->page();
3546                        EditorClient* editorClient = page->editorClient();
3547                        EditorClientAndroid* androidEditor =
3548                                static_cast<EditorClientAndroid*>(editorClient);
3549                        WebAutofill* autoFill = androidEditor->getAutofill();
3550                        autoFill->formFieldFocused(inputElement);
3551                    }
3552#endif
3553                } else
3554                    showKeyboard = false;
3555            }
3556            if (!fake)
3557                requestKeyboard(showKeyboard);
3558        } else if (!fake && !nodeIsPlugin(node)) {
3559            // not a text entry field, put away the keyboard.
3560            clearTextEntry();
3561        }
3562    } else if (!fake) {
3563        // There is no focusNode, so the keyboard is not needed.
3564        clearTextEntry();
3565    }
3566}
3567
3568void WebViewCore::focusNodeChanged(WebCore::Node* newFocus)
3569{
3570    JNIEnv* env = JSC::Bindings::getJNIEnv();
3571    AutoJObject javaObject = m_javaGlue->object(env);
3572    if (!javaObject.get())
3573        return;
3574    if (isTextInput(newFocus))
3575        initializeTextInput(newFocus, true);
3576    HitTestResult focusHitResult;
3577    focusHitResult.setInnerNode(newFocus);
3578    focusHitResult.setInnerNonSharedNode(newFocus);
3579    if (newFocus && newFocus->isLink() && newFocus->isElementNode()) {
3580        focusHitResult.setURLElement(static_cast<Element*>(newFocus));
3581        if (newFocus->hasChildNodes() && !newFocus->hasTagName(HTMLNames::imgTag)) {
3582            // Check to see if any of the children are images, and if so
3583            // set them as the innerNode and innerNonSharedNode
3584            // This will stop when it hits the first image. I'm not sure what
3585            // should be done in the case of multiple images inside one anchor...
3586            Node* nextNode = newFocus->firstChild();
3587            bool found = false;
3588            while (nextNode) {
3589                if (nextNode->hasTagName(HTMLNames::imgTag)) {
3590                    found = true;
3591                    break;
3592                }
3593                nextNode = nextNodeWithinParent(newFocus, nextNode);
3594            }
3595            if (found) {
3596                focusHitResult.setInnerNode(nextNode);
3597                focusHitResult.setInnerNonSharedNode(nextNode);
3598            }
3599        }
3600    }
3601    AndroidHitTestResult androidHitTest(this, focusHitResult);
3602    jobject jHitTestObj = androidHitTest.createJavaObject(env);
3603    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_focusNodeChanged,
3604            reinterpret_cast<int>(newFocus), jHitTestObj);
3605    env->DeleteLocalRef(jHitTestObj);
3606}
3607
3608void WebViewCore::addMessageToConsole(const WTF::String& message, unsigned int lineNumber, const WTF::String& sourceID, int msgLevel) {
3609    JNIEnv* env = JSC::Bindings::getJNIEnv();
3610    AutoJObject javaObject = m_javaGlue->object(env);
3611    if (!javaObject.get())
3612        return;
3613    jstring jMessageStr = wtfStringToJstring(env, message);
3614    jstring jSourceIDStr = wtfStringToJstring(env, sourceID);
3615    env->CallVoidMethod(javaObject.get(),
3616            m_javaGlue->m_addMessageToConsole, jMessageStr, lineNumber,
3617            jSourceIDStr, msgLevel);
3618    env->DeleteLocalRef(jMessageStr);
3619    env->DeleteLocalRef(jSourceIDStr);
3620    checkException(env);
3621}
3622
3623void WebViewCore::jsAlert(const WTF::String& url, const WTF::String& text)
3624{
3625    JNIEnv* env = JSC::Bindings::getJNIEnv();
3626    AutoJObject javaObject = m_javaGlue->object(env);
3627    if (!javaObject.get())
3628        return;
3629    jstring jInputStr = wtfStringToJstring(env, text);
3630    jstring jUrlStr = wtfStringToJstring(env, url);
3631    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_jsAlert, jUrlStr, jInputStr);
3632    env->DeleteLocalRef(jInputStr);
3633    env->DeleteLocalRef(jUrlStr);
3634    checkException(env);
3635}
3636
3637bool WebViewCore::exceededDatabaseQuota(const WTF::String& url, const WTF::String& databaseIdentifier, const unsigned long long currentQuota, unsigned long long estimatedSize)
3638{
3639#if ENABLE(DATABASE)
3640    JNIEnv* env = JSC::Bindings::getJNIEnv();
3641    AutoJObject javaObject = m_javaGlue->object(env);
3642    if (!javaObject.get())
3643        return false;
3644    jstring jDatabaseIdentifierStr = wtfStringToJstring(env, databaseIdentifier);
3645    jstring jUrlStr = wtfStringToJstring(env, url);
3646    env->CallVoidMethod(javaObject.get(),
3647            m_javaGlue->m_exceededDatabaseQuota, jUrlStr,
3648            jDatabaseIdentifierStr, currentQuota, estimatedSize);
3649    env->DeleteLocalRef(jDatabaseIdentifierStr);
3650    env->DeleteLocalRef(jUrlStr);
3651    checkException(env);
3652    return true;
3653#endif
3654}
3655
3656bool WebViewCore::reachedMaxAppCacheSize(const unsigned long long spaceNeeded)
3657{
3658#if ENABLE(OFFLINE_WEB_APPLICATIONS)
3659    JNIEnv* env = JSC::Bindings::getJNIEnv();
3660    AutoJObject javaObject = m_javaGlue->object(env);
3661    if (!javaObject.get())
3662        return false;
3663    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_reachedMaxAppCacheSize, spaceNeeded);
3664    checkException(env);
3665    return true;
3666#endif
3667}
3668
3669void WebViewCore::populateVisitedLinks(WebCore::PageGroup* group)
3670{
3671    JNIEnv* env = JSC::Bindings::getJNIEnv();
3672    AutoJObject javaObject = m_javaGlue->object(env);
3673    if (!javaObject.get())
3674        return;
3675    m_groupForVisitedLinks = group;
3676    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_populateVisitedLinks);
3677    checkException(env);
3678}
3679
3680void WebViewCore::geolocationPermissionsShowPrompt(const WTF::String& origin)
3681{
3682    JNIEnv* env = JSC::Bindings::getJNIEnv();
3683    AutoJObject javaObject = m_javaGlue->object(env);
3684    if (!javaObject.get())
3685        return;
3686    jstring originString = wtfStringToJstring(env, origin);
3687    env->CallVoidMethod(javaObject.get(),
3688                        m_javaGlue->m_geolocationPermissionsShowPrompt,
3689                        originString);
3690    env->DeleteLocalRef(originString);
3691    checkException(env);
3692}
3693
3694void WebViewCore::geolocationPermissionsHidePrompt()
3695{
3696    JNIEnv* env = JSC::Bindings::getJNIEnv();
3697    AutoJObject javaObject = m_javaGlue->object(env);
3698    if (!javaObject.get())
3699        return;
3700    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_geolocationPermissionsHidePrompt);
3701    checkException(env);
3702}
3703
3704jobject WebViewCore::getDeviceMotionService()
3705{
3706    JNIEnv* env = JSC::Bindings::getJNIEnv();
3707    AutoJObject javaObject = m_javaGlue->object(env);
3708    if (!javaObject.get())
3709        return 0;
3710    jobject object = env->CallObjectMethod(javaObject.get(), m_javaGlue->m_getDeviceMotionService);
3711    checkException(env);
3712    return object;
3713}
3714
3715jobject WebViewCore::getDeviceOrientationService()
3716{
3717    JNIEnv* env = JSC::Bindings::getJNIEnv();
3718    AutoJObject javaObject = m_javaGlue->object(env);
3719    if (!javaObject.get())
3720        return 0;
3721    jobject object = env->CallObjectMethod(javaObject.get(), m_javaGlue->m_getDeviceOrientationService);
3722    checkException(env);
3723    return object;
3724}
3725
3726bool WebViewCore::jsConfirm(const WTF::String& url, const WTF::String& text)
3727{
3728    JNIEnv* env = JSC::Bindings::getJNIEnv();
3729    AutoJObject javaObject = m_javaGlue->object(env);
3730    if (!javaObject.get())
3731        return false;
3732    jstring jInputStr = wtfStringToJstring(env, text);
3733    jstring jUrlStr = wtfStringToJstring(env, url);
3734    jboolean result = env->CallBooleanMethod(javaObject.get(), m_javaGlue->m_jsConfirm, jUrlStr, jInputStr);
3735    env->DeleteLocalRef(jInputStr);
3736    env->DeleteLocalRef(jUrlStr);
3737    checkException(env);
3738    return result;
3739}
3740
3741bool WebViewCore::jsPrompt(const WTF::String& url, const WTF::String& text, const WTF::String& defaultValue, WTF::String& result)
3742{
3743    JNIEnv* env = JSC::Bindings::getJNIEnv();
3744    AutoJObject javaObject = m_javaGlue->object(env);
3745    if (!javaObject.get())
3746        return false;
3747    jstring jUrlStr = wtfStringToJstring(env, url);
3748    jstring jInputStr = wtfStringToJstring(env, text);
3749    jstring jDefaultStr = wtfStringToJstring(env, defaultValue);
3750    jstring returnVal = static_cast<jstring>(env->CallObjectMethod(javaObject.get(), m_javaGlue->m_jsPrompt, jUrlStr, jInputStr, jDefaultStr));
3751    env->DeleteLocalRef(jUrlStr);
3752    env->DeleteLocalRef(jInputStr);
3753    env->DeleteLocalRef(jDefaultStr);
3754    checkException(env);
3755
3756    // If returnVal is null, it means that the user cancelled the dialog.
3757    if (!returnVal)
3758        return false;
3759
3760    result = jstringToWtfString(env, returnVal);
3761    env->DeleteLocalRef(returnVal);
3762    return true;
3763}
3764
3765bool WebViewCore::jsUnload(const WTF::String& url, const WTF::String& message)
3766{
3767    JNIEnv* env = JSC::Bindings::getJNIEnv();
3768    AutoJObject javaObject = m_javaGlue->object(env);
3769    if (!javaObject.get())
3770        return false;
3771    jstring jInputStr = wtfStringToJstring(env, message);
3772    jstring jUrlStr = wtfStringToJstring(env, url);
3773    jboolean result = env->CallBooleanMethod(javaObject.get(), m_javaGlue->m_jsUnload, jUrlStr, jInputStr);
3774    env->DeleteLocalRef(jInputStr);
3775    env->DeleteLocalRef(jUrlStr);
3776    checkException(env);
3777    return result;
3778}
3779
3780bool WebViewCore::jsInterrupt()
3781{
3782    JNIEnv* env = JSC::Bindings::getJNIEnv();
3783    AutoJObject javaObject = m_javaGlue->object(env);
3784    if (!javaObject.get())
3785        return false;
3786    jboolean result = env->CallBooleanMethod(javaObject.get(), m_javaGlue->m_jsInterrupt);
3787    checkException(env);
3788    return result;
3789}
3790
3791AutoJObject
3792WebViewCore::getJavaObject()
3793{
3794    return m_javaGlue->object(JSC::Bindings::getJNIEnv());
3795}
3796
3797jobject
3798WebViewCore::getWebViewJavaObject()
3799{
3800    JNIEnv* env = JSC::Bindings::getJNIEnv();
3801    AutoJObject javaObject = m_javaGlue->object(env);
3802    if (!javaObject.get())
3803        return 0;
3804    return env->CallObjectMethod(javaObject.get(), m_javaGlue->m_getWebView);
3805}
3806
3807RenderTextControl* WebViewCore::toRenderTextControl(Node* node)
3808{
3809    RenderTextControl* rtc = 0;
3810    RenderObject* renderer = node->renderer();
3811    if (renderer && renderer->isTextControl()) {
3812        rtc = WebCore::toRenderTextControl(renderer);
3813    }
3814    return rtc;
3815}
3816
3817void WebViewCore::getSelectionOffsets(Node* node, int& start, int& end)
3818{
3819    RenderTextControl* rtc = toRenderTextControl(node);
3820    if (rtc) {
3821        start = rtc->selectionStart();
3822        end = rtc->selectionEnd();
3823    } else {
3824        // It must be content editable field.
3825        Document* document = node->document();
3826        Frame* frame = document->frame();
3827        SelectionController* selector = frame->selection();
3828        Position selectionStart = selector->start();
3829        Position selectionEnd = selector->end();
3830        Position startOfNode = firstPositionInNode(node);
3831        RefPtr<Range> startRange = Range::create(document, startOfNode,
3832                selectionStart);
3833        start = TextIterator::rangeLength(startRange.get(), true);
3834        RefPtr<Range> endRange = Range::create(document, startOfNode,
3835                selectionEnd);
3836        end = TextIterator::rangeLength(endRange.get(), true);
3837    }
3838}
3839
3840String WebViewCore::getInputText(Node* node)
3841{
3842    String text;
3843    WebCore::RenderTextControl* renderText = toRenderTextControl(node);
3844    if (renderText)
3845        text = renderText->text();
3846    else {
3847        // It must be content editable field.
3848        Position start = firstPositionInNode(node);
3849        Position end = lastPositionInNode(node);
3850        VisibleSelection allEditableText(start, end);
3851        if (allEditableText.isRange())
3852            text = allEditableText.firstRange()->text();
3853    }
3854    return text;
3855}
3856
3857void WebViewCore::updateTextSelection()
3858{
3859    JNIEnv* env = JSC::Bindings::getJNIEnv();
3860    AutoJObject javaObject = m_javaGlue->object(env);
3861    if (!javaObject.get())
3862        return;
3863    VisibleSelection selection = focusedFrame()->selection()->selection();
3864    int start = 0;
3865    int end = 0;
3866    if (selection.isCaretOrRange())
3867        getSelectionOffsets(selection.start().anchorNode(), start, end);
3868    SelectText* selectText = createSelectText(selection);
3869    env->CallVoidMethod(javaObject.get(),
3870            m_javaGlue->m_updateTextSelection, reinterpret_cast<int>(currentFocus()),
3871            start, end, m_textGeneration, reinterpret_cast<int>(selectText));
3872    checkException(env);
3873}
3874
3875void WebViewCore::updateTextSizeAndScroll(WebCore::Node* node)
3876{
3877    JNIEnv* env = JSC::Bindings::getJNIEnv();
3878    AutoJObject javaObject = m_javaGlue->object(env);
3879    if (!javaObject.get())
3880        return;
3881    RenderTextControl* rtc = toRenderTextControl(node);
3882    if (!rtc)
3883        return;
3884    int width = rtc->scrollWidth();
3885    int height = rtc->contentHeight();
3886    int scrollX = rtc->scrollLeft();
3887    int scrollY = rtc->scrollTop();
3888    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_updateTextSizeAndScroll,
3889            reinterpret_cast<int>(node), width, height, scrollX, scrollY);
3890    checkException(env);
3891}
3892
3893void WebViewCore::updateTextfield(WebCore::Node* ptr, bool changeToPassword,
3894        const WTF::String& text)
3895{
3896    JNIEnv* env = JSC::Bindings::getJNIEnv();
3897    AutoJObject javaObject = m_javaGlue->object(env);
3898    if (!javaObject.get())
3899        return;
3900    if (m_blockTextfieldUpdates)
3901        return;
3902    if (changeToPassword) {
3903        env->CallVoidMethod(javaObject.get(), m_javaGlue->m_updateTextfield,
3904                (int) ptr, true, 0, m_textGeneration);
3905        checkException(env);
3906        return;
3907    }
3908    jstring string = wtfStringToJstring(env, text);
3909    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_updateTextfield,
3910            (int) ptr, false, string, m_textGeneration);
3911    env->DeleteLocalRef(string);
3912    checkException(env);
3913}
3914
3915void WebViewCore::clearTextEntry()
3916{
3917    JNIEnv* env = JSC::Bindings::getJNIEnv();
3918    AutoJObject javaObject = m_javaGlue->object(env);
3919    if (!javaObject.get())
3920        return;
3921    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_clearTextEntry);
3922}
3923
3924void WebViewCore::setBackgroundColor(SkColor c)
3925{
3926    WebCore::FrameView* view = m_mainFrame->view();
3927    if (!view)
3928        return;
3929
3930    // need (int) cast to find the right constructor
3931    WebCore::Color bcolor((int)SkColorGetR(c), (int)SkColorGetG(c),
3932                          (int)SkColorGetB(c), (int)SkColorGetA(c));
3933    view->setBaseBackgroundColor(bcolor);
3934
3935    // Background color of 0 indicates we want a transparent background
3936    if (c == 0)
3937        view->setTransparent(true);
3938}
3939
3940jclass WebViewCore::getPluginClass(const WTF::String& libName, const char* className)
3941{
3942    JNIEnv* env = JSC::Bindings::getJNIEnv();
3943    AutoJObject javaObject = m_javaGlue->object(env);
3944    if (!javaObject.get())
3945        return 0;
3946
3947    jstring libString = wtfStringToJstring(env, libName);
3948    jstring classString = env->NewStringUTF(className);
3949    jobject pluginClass = env->CallObjectMethod(javaObject.get(),
3950                                           m_javaGlue->m_getPluginClass,
3951                                           libString, classString);
3952    checkException(env);
3953
3954    // cleanup unneeded local JNI references
3955    env->DeleteLocalRef(libString);
3956    env->DeleteLocalRef(classString);
3957
3958    if (pluginClass != 0) {
3959        return static_cast<jclass>(pluginClass);
3960    } else {
3961        return 0;
3962    }
3963}
3964
3965void WebViewCore::showFullScreenPlugin(jobject childView, int32_t orientation, NPP npp)
3966{
3967    JNIEnv* env = JSC::Bindings::getJNIEnv();
3968    AutoJObject javaObject = m_javaGlue->object(env);
3969    if (!javaObject.get())
3970        return;
3971
3972    env->CallVoidMethod(javaObject.get(),
3973                        m_javaGlue->m_showFullScreenPlugin,
3974                        childView, orientation, reinterpret_cast<int>(npp));
3975    checkException(env);
3976}
3977
3978void WebViewCore::hideFullScreenPlugin()
3979{
3980    JNIEnv* env = JSC::Bindings::getJNIEnv();
3981    AutoJObject javaObject = m_javaGlue->object(env);
3982    if (!javaObject.get())
3983        return;
3984    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_hideFullScreenPlugin);
3985    checkException(env);
3986}
3987
3988jobject WebViewCore::createSurface(jobject view)
3989{
3990    JNIEnv* env = JSC::Bindings::getJNIEnv();
3991    AutoJObject javaObject = m_javaGlue->object(env);
3992    if (!javaObject.get())
3993        return 0;
3994    jobject result = env->CallObjectMethod(javaObject.get(), m_javaGlue->m_createSurface, view);
3995    checkException(env);
3996    return result;
3997}
3998
3999jobject WebViewCore::addSurface(jobject view, int x, int y, int width, int height)
4000{
4001    JNIEnv* env = JSC::Bindings::getJNIEnv();
4002    AutoJObject javaObject = m_javaGlue->object(env);
4003    if (!javaObject.get())
4004        return 0;
4005    jobject result = env->CallObjectMethod(javaObject.get(),
4006                                           m_javaGlue->m_addSurface,
4007                                           view, x, y, width, height);
4008    checkException(env);
4009    return result;
4010}
4011
4012void WebViewCore::updateSurface(jobject childView, int x, int y, int width, int height)
4013{
4014    JNIEnv* env = JSC::Bindings::getJNIEnv();
4015    AutoJObject javaObject = m_javaGlue->object(env);
4016    if (!javaObject.get())
4017        return;
4018    env->CallVoidMethod(javaObject.get(),
4019                        m_javaGlue->m_updateSurface, childView,
4020                        x, y, width, height);
4021    checkException(env);
4022}
4023
4024void WebViewCore::destroySurface(jobject childView)
4025{
4026    JNIEnv* env = JSC::Bindings::getJNIEnv();
4027    AutoJObject javaObject = m_javaGlue->object(env);
4028    if (!javaObject.get())
4029        return;
4030    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_destroySurface, childView);
4031    checkException(env);
4032}
4033
4034jobject WebViewCore::getContext()
4035{
4036    JNIEnv* env = JSC::Bindings::getJNIEnv();
4037    AutoJObject javaObject = m_javaGlue->object(env);
4038    if (!javaObject.get())
4039        return 0;
4040
4041    jobject result = env->CallObjectMethod(javaObject.get(), m_javaGlue->m_getContext);
4042    checkException(env);
4043    return result;
4044}
4045
4046void WebViewCore::keepScreenOn(bool screenOn) {
4047    if ((screenOn && m_screenOnCounter == 0) || (!screenOn && m_screenOnCounter == 1)) {
4048        JNIEnv* env = JSC::Bindings::getJNIEnv();
4049        AutoJObject javaObject = m_javaGlue->object(env);
4050        if (!javaObject.get())
4051            return;
4052        env->CallVoidMethod(javaObject.get(), m_javaGlue->m_keepScreenOn, screenOn);
4053        checkException(env);
4054    }
4055
4056    // update the counter
4057    if (screenOn)
4058        m_screenOnCounter++;
4059    else if (m_screenOnCounter > 0)
4060        m_screenOnCounter--;
4061}
4062
4063void WebViewCore::showRect(int left, int top, int width, int height,
4064        int contentWidth, int contentHeight, float xPercentInDoc,
4065        float xPercentInView, float yPercentInDoc, float yPercentInView)
4066{
4067    JNIEnv* env = JSC::Bindings::getJNIEnv();
4068    AutoJObject javaObject = m_javaGlue->object(env);
4069    if (!javaObject.get())
4070        return;
4071    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_showRect,
4072            left, top, width, height, contentWidth, contentHeight,
4073            xPercentInDoc, xPercentInView, yPercentInDoc, yPercentInView);
4074    checkException(env);
4075}
4076
4077void WebViewCore::centerFitRect(int x, int y, int width, int height)
4078{
4079    JNIEnv* env = JSC::Bindings::getJNIEnv();
4080    AutoJObject javaObject = m_javaGlue->object(env);
4081    if (!javaObject.get())
4082        return;
4083    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_centerFitRect, x, y, width, height);
4084    checkException(env);
4085}
4086
4087void WebViewCore::setScrollbarModes(ScrollbarMode horizontalMode, ScrollbarMode verticalMode)
4088{
4089    JNIEnv* env = JSC::Bindings::getJNIEnv();
4090    AutoJObject javaObject = m_javaGlue->object(env);
4091    if (!javaObject.get())
4092        return;
4093    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_setScrollbarModes, horizontalMode, verticalMode);
4094    checkException(env);
4095}
4096
4097void WebViewCore::notifyWebAppCanBeInstalled()
4098{
4099    JNIEnv* env = JSC::Bindings::getJNIEnv();
4100    AutoJObject javaObject = m_javaGlue->object(env);
4101    if (!javaObject.get())
4102        return;
4103    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_setInstallableWebApp);
4104    checkException(env);
4105}
4106
4107#if ENABLE(VIDEO)
4108void WebViewCore::enterFullscreenForVideoLayer(int layerId, const WTF::String& url)
4109{
4110    JNIEnv* env = JSC::Bindings::getJNIEnv();
4111    AutoJObject javaObject = m_javaGlue->object(env);
4112    if (!javaObject.get())
4113        return;
4114    jstring jUrlStr = wtfStringToJstring(env, url);
4115    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_enterFullscreenForVideoLayer, layerId, jUrlStr);
4116    m_fullscreenVideoMode = true;
4117    checkException(env);
4118}
4119
4120void WebViewCore::exitFullscreenVideo()
4121{
4122    JNIEnv* env = JSC::Bindings::getJNIEnv();
4123    AutoJObject javaObject = m_javaGlue->object(env);
4124    if (!javaObject.get())
4125        return;
4126    if (m_fullscreenVideoMode) {
4127        env->CallVoidMethod(javaObject.get(), m_javaGlue->m_exitFullscreenVideo);
4128        m_fullscreenVideoMode = false;
4129    }
4130    checkException(env);
4131}
4132#endif
4133
4134void WebViewCore::setWebTextViewAutoFillable(int queryId, const string16& previewSummary)
4135{
4136#if ENABLE(WEB_AUTOFILL)
4137    JNIEnv* env = JSC::Bindings::getJNIEnv();
4138    AutoJObject javaObject = m_javaGlue->object(env);
4139    if (!javaObject.get())
4140        return;
4141    jstring preview = env->NewString(previewSummary.data(), previewSummary.length());
4142    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_setWebTextViewAutoFillable, queryId, preview);
4143    env->DeleteLocalRef(preview);
4144#endif
4145}
4146
4147bool WebViewCore::drawIsPaused() const
4148{
4149    // returning true says scrollview should be offscreen, which pauses
4150    // gifs. because this is not again queried when we stop scrolling, we don't
4151    // use the stopping currently.
4152    return false;
4153}
4154
4155void WebViewCore::setWebRequestContextUserAgent()
4156{
4157    // We cannot create a WebRequestContext, because we might not know it this is a private tab or not yet
4158    if (m_webRequestContext)
4159        m_webRequestContext->setUserAgent(WebFrame::getWebFrame(m_mainFrame)->userAgentForURL(0)); // URL not used
4160}
4161
4162void WebViewCore::setWebRequestContextCacheMode(int cacheMode)
4163{
4164    m_cacheMode = cacheMode;
4165    // We cannot create a WebRequestContext, because we might not know it this is a private tab or not yet
4166    if (!m_webRequestContext)
4167        return;
4168
4169    m_webRequestContext->setCacheMode(cacheMode);
4170}
4171
4172WebRequestContext* WebViewCore::webRequestContext()
4173{
4174    if (!m_webRequestContext) {
4175        Settings* settings = mainFrame()->settings();
4176        m_webRequestContext = new WebRequestContext(settings && settings->privateBrowsingEnabled());
4177        setWebRequestContextUserAgent();
4178        setWebRequestContextCacheMode(m_cacheMode);
4179    }
4180    return m_webRequestContext.get();
4181}
4182
4183void WebViewCore::scrollRenderLayer(int layer, const SkRect& rect)
4184{
4185#if USE(ACCELERATED_COMPOSITING)
4186    GraphicsLayerAndroid* root = graphicsRootLayer();
4187    if (!root)
4188        return;
4189
4190    LayerAndroid* layerAndroid = root->platformLayer();
4191    if (!layerAndroid)
4192        return;
4193
4194    LayerAndroid* target = layerAndroid->findById(layer);
4195    if (!target)
4196        return;
4197
4198    RenderLayer* owner = target->owningLayer();
4199    if (!owner)
4200        return;
4201
4202    if (owner->isRootLayer()) {
4203        FrameView* view = owner->renderer()->frame()->view();
4204        IntPoint pt(rect.fLeft, rect.fTop);
4205        view->setScrollPosition(pt);
4206    } else
4207        owner->scrollToOffset(rect.fLeft, rect.fTop);
4208#endif
4209}
4210
4211Vector<VisibleSelection> WebViewCore::getTextRanges(
4212        int startX, int startY, int endX, int endY)
4213{
4214    // These are the positions of the selection handles,
4215    // which reside below the line that they are selecting.
4216    // Use the vertical position higher, which will include
4217    // the selected text.
4218    startY--;
4219    endY--;
4220    VisiblePosition startSelect = visiblePositionForContentPoint(startX, startY);
4221    VisiblePosition endSelect =  visiblePositionForContentPoint(endX, endY);
4222    Position start = startSelect.deepEquivalent();
4223    Position end = endSelect.deepEquivalent();
4224    Vector<VisibleSelection> ranges;
4225    if (!start.isNull() && !end.isNull()) {
4226        if (comparePositions(start, end) > 0) {
4227            swap(start, end); // RTL start/end positions may be swapped
4228        }
4229        Position nextRangeStart = start;
4230        Position previousRangeEnd;
4231        do {
4232            VisibleSelection selection(nextRangeStart, end);
4233            ranges.append(selection);
4234            previousRangeEnd = selection.end();
4235            nextRangeStart = nextCandidate(previousRangeEnd);
4236        } while (comparePositions(previousRangeEnd, end) < 0);
4237    }
4238    return ranges;
4239}
4240
4241void WebViewCore::deleteText(int startX, int startY, int endX, int endY)
4242{
4243    Vector<VisibleSelection> ranges =
4244            getTextRanges(startX, startY, endX, endY);
4245
4246    EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
4247            m_mainFrame->editor()->client());
4248    client->setUiGeneratedSelectionChange(true);
4249
4250    SelectionController* selector = m_mainFrame->selection();
4251    for (size_t i = 0; i < ranges.size(); i++) {
4252        const VisibleSelection& selection = ranges[i];
4253        if (selection.isContentEditable()) {
4254            selector->setSelection(selection, CharacterGranularity);
4255            Document* document = selection.start().anchorNode()->document();
4256            WebCore::TypingCommand::deleteSelection(document, 0);
4257        }
4258    }
4259    client->setUiGeneratedSelectionChange(false);
4260}
4261
4262void WebViewCore::insertText(const WTF::String &text)
4263{
4264    WebCore::Node* focus = currentFocus();
4265    if (!focus || !isTextInput(focus))
4266        return;
4267
4268    Document* document = focus->document();
4269
4270    EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
4271            m_mainFrame->editor()->client());
4272    if (!client)
4273        return;
4274    client->setUiGeneratedSelectionChange(true);
4275    WebCore::TypingCommand::insertText(document, text,
4276            TypingCommand::PreventSpellChecking);
4277    client->setUiGeneratedSelectionChange(false);
4278}
4279
4280void WebViewCore::resetFindOnPage()
4281{
4282    m_searchText.truncate(0);
4283    m_matchCount = 0;
4284    m_activeMatchIndex = 0;
4285    m_activeMatch = 0;
4286}
4287
4288int WebViewCore::findTextOnPage(const WTF::String &text)
4289{
4290    resetFindOnPage(); // reset even if parameters are bad
4291
4292    WebCore::Frame* frame = m_mainFrame;
4293    if (!frame)
4294        return 0;
4295
4296    m_searchText = text;
4297    FindOptions findOptions = WebCore::CaseInsensitive;
4298
4299    do {
4300        frame->document()->markers()->removeMarkers(DocumentMarker::TextMatch);
4301        m_matchCount += frame->editor()->countMatchesForText(text, findOptions,
4302            0, true);
4303        frame->editor()->setMarkedTextMatchesAreHighlighted(true);
4304        frame = frame->tree()->traverseNextWithWrap(false);
4305    } while (frame);
4306    m_activeMatchIndex = m_matchCount - 1; // prime first findNext
4307    return m_matchCount;
4308}
4309
4310int WebViewCore::findNextOnPage(bool forward)
4311{
4312    if (!m_mainFrame)
4313        return -1;
4314    if (!m_matchCount)
4315        return -1;
4316
4317    EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
4318        m_mainFrame->editor()->client());
4319    client->setUiGeneratedSelectionChange(true);
4320
4321    // Clear previous active match.
4322    if (m_activeMatch) {
4323        m_mainFrame->document()->markers()->setMarkersActive(
4324            m_activeMatch.get(), false);
4325    }
4326
4327    FindOptions findOptions = WebCore::CaseInsensitive
4328        | WebCore::StartInSelection | WebCore::WrapAround;
4329    if (!forward)
4330        findOptions |= WebCore::Backwards;
4331
4332    // Start from the previous active match.
4333    if (m_activeMatch) {
4334        m_mainFrame->selection()->setSelection(m_activeMatch.get());
4335    }
4336
4337    bool found = m_mainFrame->editor()->findString(m_searchText, findOptions);
4338    if (found) {
4339        VisibleSelection selection(m_mainFrame->selection()->selection());
4340        if (selection.isNone() || selection.start() == selection.end()) {
4341            // Temporary workaround for findString() refusing to select text
4342            // marked "-webkit-user-select: none".
4343            m_activeMatchIndex = 0;
4344            m_activeMatch = 0;
4345        } else {
4346            // Mark current match "active".
4347            if (forward) {
4348                ++m_activeMatchIndex;
4349                if (m_activeMatchIndex == m_matchCount)
4350                    m_activeMatchIndex = 0;
4351            } else {
4352                if (m_activeMatchIndex == 0)
4353                    m_activeMatchIndex = m_matchCount;
4354                --m_activeMatchIndex;
4355            }
4356            m_activeMatch = selection.firstRange();
4357            m_mainFrame->document()->markers()->setMarkersActive(
4358                m_activeMatch.get(), true);
4359            m_mainFrame->selection()->revealSelection(
4360                ScrollAlignment::alignCenterIfNeeded, true);
4361        }
4362    }
4363
4364    // Clear selection so it doesn't display.
4365    m_mainFrame->selection()->clear();
4366    client->setUiGeneratedSelectionChange(false);
4367    return m_activeMatchIndex;
4368}
4369
4370String WebViewCore::getText(int startX, int startY, int endX, int endY)
4371{
4372    String text;
4373
4374    Vector<VisibleSelection> ranges =
4375            getTextRanges(startX, startY, endX, endY);
4376
4377    for (size_t i = 0; i < ranges.size(); i++) {
4378        const VisibleSelection& selection = ranges[i];
4379        if (selection.isRange()) {
4380            PassRefPtr<Range> range = selection.firstRange();
4381            String textInRange = range->text();
4382            if (textInRange.length() > 0) {
4383                if (text.length() > 0)
4384                    text.append('\n');
4385                text.append(textInRange);
4386            }
4387        }
4388    }
4389
4390    return text;
4391}
4392
4393/**
4394 * Read the persistent locale.
4395 */
4396void WebViewCore::getLocale(String& language, String& region)
4397{
4398    char propLang[PROPERTY_VALUE_MAX], propRegn[PROPERTY_VALUE_MAX];
4399
4400    property_get("persist.sys.language", propLang, "");
4401    property_get("persist.sys.country", propRegn, "");
4402    if (*propLang == 0 && *propRegn == 0) {
4403        /* Set to ro properties, default is en_US */
4404        property_get("ro.product.locale.language", propLang, "en");
4405        property_get("ro.product.locale.region", propRegn, "US");
4406    }
4407    language = String(propLang, 2);
4408    region = String(propRegn, 2);
4409}
4410
4411void WebViewCore::updateLocale()
4412{
4413    static String prevLang;
4414    static String prevRegn;
4415    String language;
4416    String region;
4417
4418    getLocale(language, region);
4419
4420    if ((language != prevLang) || (region != prevRegn)) {
4421        prevLang = language;
4422        prevRegn = region;
4423        GlyphPageTreeNode::resetRoots();
4424        fontCache()->invalidate();
4425    }
4426}
4427
4428//----------------------------------------------------------------------
4429// Native JNI methods
4430//----------------------------------------------------------------------
4431static void RevealSelection(JNIEnv* env, jobject obj, jint nativeClass)
4432{
4433    reinterpret_cast<WebViewCore*>(nativeClass)->revealSelection();
4434}
4435
4436static jstring RequestLabel(JNIEnv* env, jobject obj, jint nativeClass,
4437        int framePointer, int nodePointer)
4438{
4439    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4440    return wtfStringToJstring(env, viewImpl->requestLabel(
4441            (WebCore::Frame*) framePointer, (WebCore::Node*) nodePointer));
4442}
4443
4444static void ClearContent(JNIEnv* env, jobject obj, jint nativeClass)
4445{
4446    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4447    viewImpl->clearContent();
4448}
4449
4450static void SetSize(JNIEnv* env, jobject obj, jint nativeClass, jint width,
4451        jint height, jint textWrapWidth, jfloat scale, jint screenWidth,
4452        jint screenHeight, jint anchorX, jint anchorY, jboolean ignoreHeight)
4453{
4454    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4455    ALOGV("webviewcore::nativeSetSize(%u %u)\n viewImpl: %p", (unsigned)width, (unsigned)height, viewImpl);
4456    ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSetSize");
4457    viewImpl->setSizeScreenWidthAndScale(width, height, textWrapWidth, scale,
4458            screenWidth, screenHeight, anchorX, anchorY, ignoreHeight);
4459}
4460
4461static void SetScrollOffset(JNIEnv* env, jobject obj, jint nativeClass,
4462        jboolean sendScrollEvent, jint x, jint y)
4463{
4464    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4465    ALOG_ASSERT(viewImpl, "need viewImpl");
4466
4467    viewImpl->setScrollOffset(sendScrollEvent, x, y);
4468}
4469
4470static void SetGlobalBounds(JNIEnv* env, jobject obj, jint nativeClass,
4471        jint x, jint y, jint h, jint v)
4472{
4473    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4474    ALOG_ASSERT(viewImpl, "need viewImpl");
4475
4476    viewImpl->setGlobalBounds(x, y, h, v);
4477}
4478
4479static jboolean Key(JNIEnv* env, jobject obj, jint nativeClass, jint keyCode,
4480        jint unichar, jint repeatCount, jboolean isShift, jboolean isAlt,
4481        jboolean isSym, jboolean isDown)
4482{
4483    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4484    return viewImpl->key(PlatformKeyboardEvent(keyCode,
4485        unichar, repeatCount, isDown, isShift, isAlt, isSym));
4486}
4487
4488static void Click(JNIEnv* env, jobject obj, jint nativeClass, int framePtr,
4489        int nodePtr, jboolean fake)
4490{
4491    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4492    ALOG_ASSERT(viewImpl, "viewImpl not set in Click");
4493
4494    viewImpl->click(reinterpret_cast<WebCore::Frame*>(framePtr),
4495        reinterpret_cast<WebCore::Node*>(nodePtr), fake);
4496}
4497
4498static void ContentInvalidateAll(JNIEnv* env, jobject obj, jint nativeClass)
4499{
4500    reinterpret_cast<WebViewCore*>(nativeClass)->contentInvalidateAll();
4501}
4502
4503static void DeleteSelection(JNIEnv* env, jobject obj, jint nativeClass,
4504        jint start, jint end, jint textGeneration)
4505{
4506    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4507    viewImpl->deleteSelection(start, end, textGeneration);
4508}
4509
4510static void SetSelection(JNIEnv* env, jobject obj, jint nativeClass,
4511        jint start, jint end)
4512{
4513    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4514    viewImpl->setSelection(start, end);
4515}
4516
4517static jstring ModifySelection(JNIEnv* env, jobject obj, jint nativeClass,
4518        jint direction, jint granularity)
4519{
4520    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4521    String selectionString = viewImpl->modifySelection(direction, granularity);
4522    return wtfStringToJstring(env, selectionString);
4523}
4524
4525static void ReplaceTextfieldText(JNIEnv* env, jobject obj, jint nativeClass,
4526    jint oldStart, jint oldEnd, jstring replace, jint start, jint end,
4527    jint textGeneration)
4528{
4529    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4530    WTF::String webcoreString = jstringToWtfString(env, replace);
4531    viewImpl->replaceTextfieldText(oldStart,
4532            oldEnd, webcoreString, start, end, textGeneration);
4533}
4534
4535static void PassToJs(JNIEnv* env, jobject obj, jint nativeClass,
4536    jint generation, jstring currentText, jint keyCode,
4537    jint keyValue, jboolean down, jboolean cap, jboolean fn, jboolean sym)
4538{
4539    WTF::String current = jstringToWtfString(env, currentText);
4540    reinterpret_cast<WebViewCore*>(nativeClass)->passToJs(generation, current,
4541        PlatformKeyboardEvent(keyCode, keyValue, 0, down, cap, fn, sym));
4542}
4543
4544static void ScrollFocusedTextInput(JNIEnv* env, jobject obj, jint nativeClass,
4545        jfloat xPercent, jint y, jobject contentBounds)
4546{
4547    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4548    IntRect bounds = viewImpl->scrollFocusedTextInput(xPercent, y);
4549    if (contentBounds)
4550        GraphicsJNI::irect_to_jrect(bounds, env, contentBounds);
4551}
4552
4553static void SetFocusControllerActive(JNIEnv* env, jobject obj, jint nativeClass,
4554        jboolean active)
4555{
4556    ALOGV("webviewcore::nativeSetFocusControllerActive()\n");
4557    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4558    ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSetFocusControllerActive");
4559    viewImpl->setFocusControllerActive(active);
4560}
4561
4562static void SaveDocumentState(JNIEnv* env, jobject obj, jint nativeClass)
4563{
4564    ALOGV("webviewcore::nativeSaveDocumentState()\n");
4565    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4566    ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSaveDocumentState");
4567    viewImpl->saveDocumentState(viewImpl->focusedFrame());
4568}
4569
4570void WebViewCore::addVisitedLink(const UChar* string, int length)
4571{
4572    if (m_groupForVisitedLinks)
4573        m_groupForVisitedLinks->addVisitedLink(string, length);
4574}
4575
4576static bool UpdateLayers(JNIEnv* env, jobject obj, jint nativeClass,
4577        jint jbaseLayer)
4578{
4579    WebViewCore* viewImpl = (WebViewCore*) nativeClass;
4580    BaseLayerAndroid* baseLayer = (BaseLayerAndroid*)  jbaseLayer;
4581    if (baseLayer) {
4582        LayerAndroid* root = static_cast<LayerAndroid*>(baseLayer->getChild(0));
4583        if (root)
4584            return viewImpl->updateLayers(root);
4585    }
4586    return true;
4587}
4588
4589static void NotifyAnimationStarted(JNIEnv* env, jobject obj, jint nativeClass)
4590{
4591    WebViewCore* viewImpl = (WebViewCore*) nativeClass;
4592    viewImpl->notifyAnimationStarted();
4593}
4594
4595static jint RecordContent(JNIEnv* env, jobject obj, jint nativeClass,
4596        jobject region, jobject pt)
4597{
4598    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4599    SkRegion* nativeRegion = GraphicsJNI::getNativeRegion(env, region);
4600    SkIPoint nativePt;
4601    BaseLayerAndroid* result = viewImpl->recordContent(nativeRegion, &nativePt);
4602    GraphicsJNI::ipoint_to_jpoint(nativePt, env, pt);
4603    return reinterpret_cast<jint>(result);
4604}
4605
4606static void SplitContent(JNIEnv* env, jobject obj, jint nativeClass,
4607        jint content)
4608{
4609    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4610    viewImpl->splitContent(reinterpret_cast<PictureSet*>(content));
4611}
4612
4613static void SendListBoxChoice(JNIEnv* env, jobject obj, jint nativeClass,
4614        jint choice)
4615{
4616    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4617    ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoice");
4618    viewImpl->popupReply(choice);
4619}
4620
4621// Set aside a predetermined amount of space in which to place the listbox
4622// choices, to avoid unnecessary allocations.
4623// The size here is arbitrary.  We want the size to be at least as great as the
4624// number of items in the average multiple-select listbox.
4625#define PREPARED_LISTBOX_STORAGE 10
4626
4627static void SendListBoxChoices(JNIEnv* env, jobject obj, jint nativeClass,
4628        jbooleanArray jArray, jint size)
4629{
4630    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4631    ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoices");
4632    jboolean* ptrArray = env->GetBooleanArrayElements(jArray, 0);
4633    SkAutoSTMalloc<PREPARED_LISTBOX_STORAGE, int> storage(size);
4634    int* array = storage.get();
4635    int count = 0;
4636    for (int i = 0; i < size; i++) {
4637        if (ptrArray[i]) {
4638            array[count++] = i;
4639        }
4640    }
4641    env->ReleaseBooleanArrayElements(jArray, ptrArray, JNI_ABORT);
4642    viewImpl->popupReply(array, count);
4643}
4644
4645// TODO: Move this to WebView.cpp since it is only needed there
4646static jstring FindAddress(JNIEnv* env, jobject obj, jstring addr,
4647        jboolean caseInsensitive)
4648{
4649    if (!addr)
4650        return 0;
4651    int length = env->GetStringLength(addr);
4652    if (!length)
4653        return 0;
4654    const jchar* addrChars = env->GetStringChars(addr, 0);
4655    size_t start, end;
4656    AddressDetector detector;
4657    bool success = detector.FindContent(addrChars, addrChars + length, &start, &end);
4658    jstring ret = 0;
4659    if (success)
4660        ret = env->NewString(addrChars + start, end - start);
4661    env->ReleaseStringChars(addr, addrChars);
4662    return ret;
4663}
4664
4665static jboolean HandleTouchEvent(JNIEnv* env, jobject obj, jint nativeClass,
4666        jint action, jintArray idArray, jintArray xArray, jintArray yArray,
4667        jint count, jint actionIndex, jint metaState)
4668{
4669    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4670    ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4671    jint* ptrIdArray = env->GetIntArrayElements(idArray, 0);
4672    jint* ptrXArray = env->GetIntArrayElements(xArray, 0);
4673    jint* ptrYArray = env->GetIntArrayElements(yArray, 0);
4674    Vector<int> ids(count);
4675    Vector<IntPoint> points(count);
4676    for (int c = 0; c < count; c++) {
4677        ids[c] = ptrIdArray[c];
4678        points[c].setX(ptrXArray[c]);
4679        points[c].setY(ptrYArray[c]);
4680    }
4681    env->ReleaseIntArrayElements(idArray, ptrIdArray, JNI_ABORT);
4682    env->ReleaseIntArrayElements(xArray, ptrXArray, JNI_ABORT);
4683    env->ReleaseIntArrayElements(yArray, ptrYArray, JNI_ABORT);
4684
4685    return viewImpl->handleTouchEvent(action, ids, points, actionIndex, metaState);
4686}
4687
4688static void TouchUp(JNIEnv* env, jobject obj, jint nativeClass,
4689        jint touchGeneration, jint frame, jint node, jint x, jint y)
4690{
4691    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4692    ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4693    viewImpl->touchUp(touchGeneration,
4694        (WebCore::Frame*) frame, (WebCore::Node*) node, x, y);
4695}
4696
4697static jstring RetrieveHref(JNIEnv* env, jobject obj, jint nativeClass,
4698        jint x, jint y)
4699{
4700    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4701    ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4702    WTF::String result = viewImpl->retrieveHref(x, y);
4703    if (!result.isEmpty())
4704        return wtfStringToJstring(env, result);
4705    return 0;
4706}
4707
4708static jstring RetrieveAnchorText(JNIEnv* env, jobject obj, jint nativeClass,
4709        jint x, jint y)
4710{
4711    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4712    ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4713    WTF::String result = viewImpl->retrieveAnchorText(x, y);
4714    if (!result.isEmpty())
4715        return wtfStringToJstring(env, result);
4716    return 0;
4717}
4718
4719static jstring RetrieveImageSource(JNIEnv* env, jobject obj, jint nativeClass,
4720        jint x, jint y)
4721{
4722    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4723    WTF::String result = viewImpl->retrieveImageSource(x, y);
4724    return !result.isEmpty() ? wtfStringToJstring(env, result) : 0;
4725}
4726
4727static void MoveMouse(JNIEnv* env, jobject obj, jint nativeClass, jint x, jint y)
4728{
4729    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4730    ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4731    viewImpl->moveMouse(x, y);
4732}
4733
4734static jint GetContentMinPrefWidth(JNIEnv* env, jobject obj, jint nativeClass)
4735{
4736    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4737    ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4738
4739    WebCore::Frame* frame = viewImpl->mainFrame();
4740    if (frame) {
4741        WebCore::Document* document = frame->document();
4742        if (document) {
4743            WebCore::RenderObject* renderer = document->renderer();
4744            if (renderer && renderer->isRenderView()) {
4745                return renderer->minPreferredLogicalWidth();
4746            }
4747        }
4748    }
4749    return 0;
4750}
4751
4752static void SetViewportSettingsFromNative(JNIEnv* env, jobject obj,
4753        jint nativeClass)
4754{
4755    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4756    ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4757
4758    WebCore::Settings* s = viewImpl->mainFrame()->page()->settings();
4759    if (!s)
4760        return;
4761
4762#ifdef ANDROID_META_SUPPORT
4763    env->SetIntField(obj, gWebViewCoreFields.m_viewportWidth, s->viewportWidth());
4764    env->SetIntField(obj, gWebViewCoreFields.m_viewportHeight, s->viewportHeight());
4765    env->SetIntField(obj, gWebViewCoreFields.m_viewportInitialScale, s->viewportInitialScale());
4766    env->SetIntField(obj, gWebViewCoreFields.m_viewportMinimumScale, s->viewportMinimumScale());
4767    env->SetIntField(obj, gWebViewCoreFields.m_viewportMaximumScale, s->viewportMaximumScale());
4768    env->SetBooleanField(obj, gWebViewCoreFields.m_viewportUserScalable, s->viewportUserScalable());
4769    env->SetIntField(obj, gWebViewCoreFields.m_viewportDensityDpi, s->viewportTargetDensityDpi());
4770#endif
4771}
4772
4773static void SetBackgroundColor(JNIEnv* env, jobject obj, jint nativeClass,
4774        jint color)
4775{
4776    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4777    ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4778
4779    viewImpl->setBackgroundColor((SkColor) color);
4780}
4781
4782static void DumpDomTree(JNIEnv* env, jobject obj, jint nativeClass,
4783        jboolean useFile)
4784{
4785    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4786    ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4787
4788    viewImpl->dumpDomTree(useFile);
4789}
4790
4791static void DumpRenderTree(JNIEnv* env, jobject obj, jint nativeClass,
4792        jboolean useFile)
4793{
4794    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4795    ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4796
4797    viewImpl->dumpRenderTree(useFile);
4798}
4799
4800static void SetJsFlags(JNIEnv* env, jobject obj, jint nativeClass, jstring flags)
4801{
4802    WTF::String flagsString = jstringToWtfString(env, flags);
4803    WTF::CString utf8String = flagsString.utf8();
4804    WebCore::ScriptController::setFlags(utf8String.data(), utf8String.length());
4805}
4806
4807
4808// Called from the Java side to set a new quota for the origin or new appcache
4809// max size in response to a notification that the original quota was exceeded or
4810// that the appcache has reached its maximum size.
4811static void SetNewStorageLimit(JNIEnv* env, jobject obj, jint nativeClass,
4812        jlong quota)
4813{
4814#if ENABLE(DATABASE) || ENABLE(OFFLINE_WEB_APPLICATIONS)
4815    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4816    Frame* frame = viewImpl->mainFrame();
4817
4818    // The main thread is blocked awaiting this response, so now we can wake it
4819    // up.
4820    ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(frame->page()->chrome()->client());
4821    chromeC->wakeUpMainThreadWithNewQuota(quota);
4822#endif
4823}
4824
4825// Called from Java to provide a Geolocation permission state for the specified origin.
4826static void GeolocationPermissionsProvide(JNIEnv* env, jobject obj,
4827        jint nativeClass, jstring origin, jboolean allow, jboolean remember)
4828{
4829    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4830    Frame* frame = viewImpl->mainFrame();
4831
4832    ChromeClientAndroid* chromeClient = static_cast<ChromeClientAndroid*>(frame->page()->chrome()->client());
4833    chromeClient->provideGeolocationPermissions(jstringToWtfString(env, origin), allow, remember);
4834}
4835
4836static void RegisterURLSchemeAsLocal(JNIEnv* env, jobject obj, jint nativeClass,
4837        jstring scheme)
4838{
4839    WebCore::SchemeRegistry::registerURLSchemeAsLocal(jstringToWtfString(env, scheme));
4840}
4841
4842static bool FocusBoundsChanged(JNIEnv* env, jobject obj, jint nativeClass)
4843{
4844    return reinterpret_cast<WebViewCore*>(nativeClass)->focusBoundsChanged();
4845}
4846
4847static void SetIsPaused(JNIEnv* env, jobject obj, jint nativeClass,
4848        jboolean isPaused)
4849{
4850    // tell the webcore thread to stop thinking while we do other work
4851    // (selection and scrolling). This has nothing to do with the lifecycle
4852    // pause and resume.
4853    reinterpret_cast<WebViewCore*>(nativeClass)->setIsPaused(isPaused);
4854}
4855
4856static void Pause(JNIEnv* env, jobject obj, jint nativeClass)
4857{
4858    // This is called for the foreground tab when the browser is put to the
4859    // background (and also for any tab when it is put to the background of the
4860    // browser). The browser can only be killed by the system when it is in the
4861    // background, so saving the Geolocation permission state now ensures that
4862    // is maintained when the browser is killed.
4863    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4864    ChromeClient* chromeClient = viewImpl->mainFrame()->page()->chrome()->client();
4865    ChromeClientAndroid* chromeClientAndroid = static_cast<ChromeClientAndroid*>(chromeClient);
4866    chromeClientAndroid->storeGeolocationPermissions();
4867
4868    Frame* mainFrame = viewImpl->mainFrame();
4869    for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext()) {
4870        Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation();
4871        if (geolocation)
4872            geolocation->suspend();
4873    }
4874
4875    viewImpl->deviceMotionAndOrientationManager()->maybeSuspendClients();
4876
4877    ANPEvent event;
4878    SkANP::InitEvent(&event, kLifecycle_ANPEventType);
4879    event.data.lifecycle.action = kPause_ANPLifecycleAction;
4880    viewImpl->sendPluginEvent(event);
4881
4882    viewImpl->setIsPaused(true);
4883}
4884
4885static void Resume(JNIEnv* env, jobject obj, jint nativeClass)
4886{
4887    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4888    Frame* mainFrame = viewImpl->mainFrame();
4889    for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext()) {
4890        Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation();
4891        if (geolocation)
4892            geolocation->resume();
4893    }
4894
4895    viewImpl->deviceMotionAndOrientationManager()->maybeResumeClients();
4896
4897    ANPEvent event;
4898    SkANP::InitEvent(&event, kLifecycle_ANPEventType);
4899    event.data.lifecycle.action = kResume_ANPLifecycleAction;
4900    viewImpl->sendPluginEvent(event);
4901
4902    viewImpl->setIsPaused(false);
4903}
4904
4905static void FreeMemory(JNIEnv* env, jobject obj, jint nativeClass)
4906{
4907    ANPEvent event;
4908    SkANP::InitEvent(&event, kLifecycle_ANPEventType);
4909    event.data.lifecycle.action = kFreeMemory_ANPLifecycleAction;
4910    reinterpret_cast<WebViewCore*>(nativeClass)->sendPluginEvent(event);
4911}
4912
4913static void ProvideVisitedHistory(JNIEnv* env, jobject obj, jint nativeClass,
4914        jobject hist)
4915{
4916    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4917    ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4918
4919    jobjectArray array = static_cast<jobjectArray>(hist);
4920
4921    jsize len = env->GetArrayLength(array);
4922    for (jsize i = 0; i < len; i++) {
4923        jstring item = static_cast<jstring>(env->GetObjectArrayElement(array, i));
4924        const UChar* str = static_cast<const UChar*>(env->GetStringChars(item, 0));
4925        jsize len = env->GetStringLength(item);
4926        viewImpl->addVisitedLink(str, len);
4927        env->ReleaseStringChars(item, str);
4928        env->DeleteLocalRef(item);
4929    }
4930}
4931
4932static void PluginSurfaceReady(JNIEnv* env, jobject obj, jint nativeClass)
4933{
4934    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4935    if (viewImpl)
4936        viewImpl->sendPluginSurfaceReady();
4937}
4938
4939// Notification from the UI thread that the plugin's full-screen surface has been discarded
4940static void FullScreenPluginHidden(JNIEnv* env, jobject obj, jint nativeClass,
4941        jint npp)
4942{
4943    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4944    PluginWidgetAndroid* plugin = viewImpl->getPluginWidget((NPP)npp);
4945    if (plugin)
4946        plugin->exitFullScreen(false);
4947}
4948
4949static WebCore::IntRect jrect_to_webrect(JNIEnv* env, jobject obj)
4950{
4951    int L, T, R, B;
4952    GraphicsJNI::get_jrect(env, obj, &L, &T, &R, &B);
4953    return WebCore::IntRect(L, T, R - L, B - T);
4954}
4955
4956static jobject HitTest(JNIEnv* env, jobject obj, jint nativeClass, jint x,
4957                       jint y, jint slop, jboolean doMoveMouse)
4958{
4959    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4960    if (!viewImpl)
4961        return 0;
4962    AndroidHitTestResult result = viewImpl->hitTestAtPoint(x, y, slop, doMoveMouse);
4963    return result.createJavaObject(env);
4964}
4965
4966static void AutoFillForm(JNIEnv* env, jobject obj, jint nativeClass,
4967        jint queryId)
4968{
4969#if ENABLE(WEB_AUTOFILL)
4970    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4971    if (!viewImpl)
4972        return;
4973
4974    WebCore::Frame* frame = viewImpl->mainFrame();
4975    if (frame) {
4976        EditorClientAndroid* editorC = static_cast<EditorClientAndroid*>(frame->page()->editorClient());
4977        WebAutofill* autoFill = editorC->getAutofill();
4978        autoFill->fillFormFields(queryId);
4979    }
4980#endif
4981}
4982
4983static void CloseIdleConnections(JNIEnv* env, jobject obj, jint nativeClass)
4984{
4985    WebCache::get(true)->closeIdleConnections();
4986    WebCache::get(false)->closeIdleConnections();
4987}
4988
4989static void nativeCertTrustChanged(JNIEnv *env, jobject obj)
4990{
4991#if USE(CHROME_NETWORK_STACK)
4992    WebCache::get(true)->certTrustChanged();
4993    WebCache::get(false)->certTrustChanged();
4994#endif
4995}
4996
4997static void ScrollRenderLayer(JNIEnv* env, jobject obj, jint nativeClass,
4998        jint layer, jobject jRect)
4999{
5000    SkRect rect;
5001    GraphicsJNI::jrect_to_rect(env, jRect, &rect);
5002    reinterpret_cast<WebViewCore*>(nativeClass)->scrollRenderLayer(layer, rect);
5003}
5004
5005static void DeleteText(JNIEnv* env, jobject obj, jint nativeClass,
5006        jint startX, jint startY, jint endX, jint endY)
5007{
5008    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
5009    viewImpl->deleteText(startX, startY, endX, endY);
5010}
5011
5012static void InsertText(JNIEnv* env, jobject obj, jint nativeClass,
5013        jstring text)
5014{
5015    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
5016    WTF::String wtfText = jstringToWtfString(env, text);
5017    viewImpl->insertText(wtfText);
5018}
5019
5020static jobject GetText(JNIEnv* env, jobject obj, jint nativeClass,
5021        jint startX, jint startY, jint endX, jint endY)
5022{
5023    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
5024    WTF::String text = viewImpl->getText(startX, startY, endX, endY);
5025    return text.isEmpty() ? 0 : wtfStringToJstring(env, text);
5026}
5027
5028static void SelectText(JNIEnv* env, jobject obj, jint nativeClass,
5029        jint startX, jint startY, jint endX, jint endY)
5030{
5031    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
5032    viewImpl->selectText(startX, startY, endX, endY);
5033}
5034
5035static void ClearSelection(JNIEnv* env, jobject obj, jint nativeClass)
5036{
5037    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
5038    viewImpl->focusedFrame()->selection()->clear();
5039}
5040
5041static bool SelectWordAt(JNIEnv* env, jobject obj, jint nativeClass, jint x, jint y)
5042{
5043    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
5044    return viewImpl->selectWordAt(x, y);
5045}
5046
5047static void SelectAll(JNIEnv* env, jobject obj, jint nativeClass)
5048{
5049    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
5050    viewImpl->focusedFrame()->selection()->selectAll();
5051}
5052
5053static int FindAll(JNIEnv* env, jobject obj, jint nativeClass,
5054        jstring text)
5055{
5056    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
5057    WTF::String wtfText = jstringToWtfString(env, text);
5058    return viewImpl->findTextOnPage(wtfText);
5059}
5060
5061static int FindNext(JNIEnv* env, jobject obj, jint nativeClass,
5062        jboolean forward)
5063{
5064    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
5065    return viewImpl->findNextOnPage(forward);
5066}
5067
5068// ----------------------------------------------------------------------------
5069
5070/*
5071 * JNI registration.
5072 */
5073static JNINativeMethod gJavaWebViewCoreMethods[] = {
5074    { "nativeClearContent", "(I)V",
5075            (void*) ClearContent },
5076    { "nativeFocusBoundsChanged", "(I)Z",
5077        (void*) FocusBoundsChanged } ,
5078    { "nativeKey", "(IIIIZZZZ)Z",
5079        (void*) Key },
5080    { "nativeClick", "(IIIZ)V",
5081        (void*) Click },
5082    { "nativeContentInvalidateAll", "(I)V",
5083        (void*) ContentInvalidateAll },
5084    { "nativeSendListBoxChoices", "(I[ZI)V",
5085        (void*) SendListBoxChoices },
5086    { "nativeSendListBoxChoice", "(II)V",
5087        (void*) SendListBoxChoice },
5088    { "nativeSetSize", "(IIIIFIIIIZ)V",
5089        (void*) SetSize },
5090    { "nativeSetScrollOffset", "(IZII)V",
5091        (void*) SetScrollOffset },
5092    { "nativeSetGlobalBounds", "(IIIII)V",
5093        (void*) SetGlobalBounds },
5094    { "nativeSetSelection", "(III)V",
5095        (void*) SetSelection } ,
5096    { "nativeModifySelection", "(III)Ljava/lang/String;",
5097        (void*) ModifySelection },
5098    { "nativeDeleteSelection", "(IIII)V",
5099        (void*) DeleteSelection } ,
5100    { "nativeReplaceTextfieldText", "(IIILjava/lang/String;III)V",
5101        (void*) ReplaceTextfieldText } ,
5102    { "nativeMoveMouse", "(III)V",
5103        (void*) MoveMouse },
5104    { "passToJs", "(IILjava/lang/String;IIZZZZ)V",
5105        (void*) PassToJs },
5106    { "nativeScrollFocusedTextInput", "(IFILandroid/graphics/Rect;)V",
5107        (void*) ScrollFocusedTextInput },
5108    { "nativeSetFocusControllerActive", "(IZ)V",
5109        (void*) SetFocusControllerActive },
5110    { "nativeSaveDocumentState", "(I)V",
5111        (void*) SaveDocumentState },
5112    { "nativeFindAddress", "(Ljava/lang/String;Z)Ljava/lang/String;",
5113        (void*) FindAddress },
5114    { "nativeHandleTouchEvent", "(II[I[I[IIII)Z",
5115            (void*) HandleTouchEvent },
5116    { "nativeTouchUp", "(IIIIII)V",
5117        (void*) TouchUp },
5118    { "nativeRetrieveHref", "(III)Ljava/lang/String;",
5119        (void*) RetrieveHref },
5120    { "nativeRetrieveAnchorText", "(III)Ljava/lang/String;",
5121        (void*) RetrieveAnchorText },
5122    { "nativeRetrieveImageSource", "(III)Ljava/lang/String;",
5123        (void*) RetrieveImageSource },
5124    { "nativeGetContentMinPrefWidth", "(I)I",
5125        (void*) GetContentMinPrefWidth },
5126    { "nativeUpdateLayers", "(II)Z",
5127        (void*) UpdateLayers },
5128    { "nativeNotifyAnimationStarted", "(I)V",
5129        (void*) NotifyAnimationStarted },
5130    { "nativeRecordContent", "(ILandroid/graphics/Region;Landroid/graphics/Point;)I",
5131        (void*) RecordContent },
5132    { "setViewportSettingsFromNative", "(I)V",
5133        (void*) SetViewportSettingsFromNative },
5134    { "nativeSplitContent", "(II)V",
5135        (void*) SplitContent },
5136    { "nativeSetBackgroundColor", "(II)V",
5137        (void*) SetBackgroundColor },
5138    { "nativeRegisterURLSchemeAsLocal", "(ILjava/lang/String;)V",
5139        (void*) RegisterURLSchemeAsLocal },
5140    { "nativeDumpDomTree", "(IZ)V",
5141        (void*) DumpDomTree },
5142    { "nativeDumpRenderTree", "(IZ)V",
5143        (void*) DumpRenderTree },
5144    { "nativeSetNewStorageLimit", "(IJ)V",
5145        (void*) SetNewStorageLimit },
5146    { "nativeGeolocationPermissionsProvide", "(ILjava/lang/String;ZZ)V",
5147        (void*) GeolocationPermissionsProvide },
5148    { "nativeSetIsPaused", "(IZ)V", (void*) SetIsPaused },
5149    { "nativePause", "(I)V", (void*) Pause },
5150    { "nativeResume", "(I)V", (void*) Resume },
5151    { "nativeFreeMemory", "(I)V", (void*) FreeMemory },
5152    { "nativeSetJsFlags", "(ILjava/lang/String;)V", (void*) SetJsFlags },
5153    { "nativeRequestLabel", "(III)Ljava/lang/String;",
5154        (void*) RequestLabel },
5155    { "nativeRevealSelection", "(I)V", (void*) RevealSelection },
5156    { "nativeProvideVisitedHistory", "(I[Ljava/lang/String;)V",
5157        (void*) ProvideVisitedHistory },
5158    { "nativeFullScreenPluginHidden", "(II)V",
5159        (void*) FullScreenPluginHidden },
5160    { "nativePluginSurfaceReady", "(I)V",
5161        (void*) PluginSurfaceReady },
5162    { "nativeHitTest", "(IIIIZ)Landroid/webkit/WebViewCore$WebKitHitTest;",
5163        (void*) HitTest },
5164    { "nativeAutoFillForm", "(II)V",
5165        (void*) AutoFillForm },
5166    { "nativeScrollLayer", "(IILandroid/graphics/Rect;)V",
5167        (void*) ScrollRenderLayer },
5168    { "nativeCloseIdleConnections", "(I)V",
5169        (void*) CloseIdleConnections },
5170    { "nativeDeleteText", "(IIIII)V",
5171        (void*) DeleteText },
5172    { "nativeInsertText", "(ILjava/lang/String;)V",
5173        (void*) InsertText },
5174    { "nativeGetText", "(IIIII)Ljava/lang/String;",
5175        (void*) GetText },
5176    { "nativeSelectText", "(IIIII)V",
5177        (void*) SelectText },
5178    { "nativeClearTextSelection", "(I)V",
5179        (void*) ClearSelection },
5180    { "nativeSelectWordAt", "(III)Z",
5181        (void*) SelectWordAt },
5182    { "nativeSelectAll", "(I)V",
5183        (void*) SelectAll },
5184    { "nativeCertTrustChanged","()V",
5185        (void*) nativeCertTrustChanged },
5186    { "nativeFindAll", "(ILjava/lang/String;)I",
5187        (void*) FindAll },
5188    { "nativeFindNext", "(IZ)I",
5189        (void*) FindNext },
5190};
5191
5192int registerWebViewCore(JNIEnv* env)
5193{
5194    jclass widget = env->FindClass("android/webkit/WebViewCore");
5195    ALOG_ASSERT(widget,
5196            "Unable to find class android/webkit/WebViewCore");
5197    gWebViewCoreFields.m_nativeClass = env->GetFieldID(widget, "mNativeClass",
5198            "I");
5199    ALOG_ASSERT(gWebViewCoreFields.m_nativeClass,
5200            "Unable to find android/webkit/WebViewCore.mNativeClass");
5201    gWebViewCoreFields.m_viewportWidth = env->GetFieldID(widget,
5202            "mViewportWidth", "I");
5203    ALOG_ASSERT(gWebViewCoreFields.m_viewportWidth,
5204            "Unable to find android/webkit/WebViewCore.mViewportWidth");
5205    gWebViewCoreFields.m_viewportHeight = env->GetFieldID(widget,
5206            "mViewportHeight", "I");
5207    ALOG_ASSERT(gWebViewCoreFields.m_viewportHeight,
5208            "Unable to find android/webkit/WebViewCore.mViewportHeight");
5209    gWebViewCoreFields.m_viewportInitialScale = env->GetFieldID(widget,
5210            "mViewportInitialScale", "I");
5211    ALOG_ASSERT(gWebViewCoreFields.m_viewportInitialScale,
5212            "Unable to find android/webkit/WebViewCore.mViewportInitialScale");
5213    gWebViewCoreFields.m_viewportMinimumScale = env->GetFieldID(widget,
5214            "mViewportMinimumScale", "I");
5215    ALOG_ASSERT(gWebViewCoreFields.m_viewportMinimumScale,
5216            "Unable to find android/webkit/WebViewCore.mViewportMinimumScale");
5217    gWebViewCoreFields.m_viewportMaximumScale = env->GetFieldID(widget,
5218            "mViewportMaximumScale", "I");
5219    ALOG_ASSERT(gWebViewCoreFields.m_viewportMaximumScale,
5220            "Unable to find android/webkit/WebViewCore.mViewportMaximumScale");
5221    gWebViewCoreFields.m_viewportUserScalable = env->GetFieldID(widget,
5222            "mViewportUserScalable", "Z");
5223    ALOG_ASSERT(gWebViewCoreFields.m_viewportUserScalable,
5224            "Unable to find android/webkit/WebViewCore.mViewportUserScalable");
5225    gWebViewCoreFields.m_viewportDensityDpi = env->GetFieldID(widget,
5226            "mViewportDensityDpi", "I");
5227    ALOG_ASSERT(gWebViewCoreFields.m_viewportDensityDpi,
5228            "Unable to find android/webkit/WebViewCore.mViewportDensityDpi");
5229    gWebViewCoreFields.m_drawIsPaused = env->GetFieldID(widget,
5230            "mDrawIsPaused", "Z");
5231    ALOG_ASSERT(gWebViewCoreFields.m_drawIsPaused,
5232            "Unable to find android/webkit/WebViewCore.mDrawIsPaused");
5233    gWebViewCoreFields.m_lowMemoryUsageMb = env->GetFieldID(widget, "mLowMemoryUsageThresholdMb", "I");
5234    gWebViewCoreFields.m_highMemoryUsageMb = env->GetFieldID(widget, "mHighMemoryUsageThresholdMb", "I");
5235    gWebViewCoreFields.m_highUsageDeltaMb = env->GetFieldID(widget, "mHighUsageDeltaMb", "I");
5236
5237    gWebViewCoreStaticMethods.m_isSupportedMediaMimeType =
5238        env->GetStaticMethodID(widget, "isSupportedMediaMimeType", "(Ljava/lang/String;)Z");
5239    LOG_FATAL_IF(!gWebViewCoreStaticMethods.m_isSupportedMediaMimeType,
5240        "Could not find static method isSupportedMediaMimeType from WebViewCore");
5241
5242    env->DeleteLocalRef(widget);
5243
5244    return jniRegisterNativeMethods(env, "android/webkit/WebViewCore",
5245            gJavaWebViewCoreMethods, NELEM(gJavaWebViewCoreMethods));
5246}
5247
5248} /* namespace android */
5249