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