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