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