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