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