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