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