WebViewCore.cpp revision 16e49e63e74d9236b0d8b72846201697a8ebaedc
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;)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    WTF::String capture;
3012
3013#if ENABLE(MEDIA_CAPTURE)
3014    capture = chooser->capture();
3015#endif
3016
3017    jstring jAcceptType = wtfStringToJstring(env, acceptType, true);
3018    jstring jCapture = wtfStringToJstring(env, capture, true);
3019    jstring jName = (jstring) env->CallObjectMethod(
3020            javaObject.get(), m_javaGlue->m_openFileChooser, jAcceptType, jCapture);
3021    checkException(env);
3022    env->DeleteLocalRef(jAcceptType);
3023    env->DeleteLocalRef(jCapture);
3024
3025    WTF::String wtfString = jstringToWtfString(env, jName);
3026    env->DeleteLocalRef(jName);
3027
3028    if (!wtfString.isEmpty())
3029        chooser->chooseFile(wtfString);
3030}
3031
3032void WebViewCore::listBoxRequest(WebCoreReply* reply, const uint16_t** labels, size_t count, const int enabled[], size_t enabledCount,
3033        bool multiple, const int selected[], size_t selectedCountOrSelection)
3034{
3035    ALOG_ASSERT(m_javaGlue->m_obj, "No java widget associated with this view!");
3036
3037    JNIEnv* env = JSC::Bindings::getJNIEnv();
3038    AutoJObject javaObject = m_javaGlue->object(env);
3039    if (!javaObject.get())
3040        return;
3041
3042    // If m_popupReply is not null, then we already have a list showing.
3043    if (m_popupReply != 0)
3044        return;
3045
3046    // Create an array of java Strings for the drop down.
3047    jobjectArray labelArray = makeLabelArray(env, labels, count);
3048
3049    // Create an array determining whether each item is enabled.
3050    jintArray enabledArray = env->NewIntArray(enabledCount);
3051    checkException(env);
3052    jint* ptrArray = env->GetIntArrayElements(enabledArray, 0);
3053    checkException(env);
3054    for (size_t i = 0; i < enabledCount; i++) {
3055        ptrArray[i] = enabled[i];
3056    }
3057    env->ReleaseIntArrayElements(enabledArray, ptrArray, 0);
3058    checkException(env);
3059
3060    if (multiple) {
3061        // Pass up an array representing which items are selected.
3062        jintArray selectedArray = env->NewIntArray(selectedCountOrSelection);
3063        checkException(env);
3064        jint* selArray = env->GetIntArrayElements(selectedArray, 0);
3065        checkException(env);
3066        for (size_t i = 0; i < selectedCountOrSelection; i++) {
3067            selArray[i] = selected[i];
3068        }
3069        env->ReleaseIntArrayElements(selectedArray, selArray, 0);
3070
3071        env->CallVoidMethod(javaObject.get(),
3072                m_javaGlue->m_requestListBox, labelArray, enabledArray,
3073                selectedArray);
3074        env->DeleteLocalRef(selectedArray);
3075    } else {
3076        // Pass up the single selection.
3077        env->CallVoidMethod(javaObject.get(),
3078                m_javaGlue->m_requestSingleListBox, labelArray, enabledArray,
3079                selectedCountOrSelection);
3080    }
3081
3082    env->DeleteLocalRef(labelArray);
3083    env->DeleteLocalRef(enabledArray);
3084    checkException(env);
3085
3086    Retain(reply);
3087    m_popupReply = reply;
3088}
3089
3090bool WebViewCore::key(const PlatformKeyboardEvent& event)
3091{
3092    WebCore::EventHandler* eventHandler;
3093    WebCore::Node* focusNode = currentFocus();
3094    if (focusNode) {
3095        WebCore::Frame* frame = focusNode->document()->frame();
3096        eventHandler = frame->eventHandler();
3097        VisibleSelection old = frame->selection()->selection();
3098        EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
3099                m_mainFrame->editor()->client());
3100        client->setUiGeneratedSelectionChange(true);
3101        bool handled = eventHandler->keyEvent(event);
3102        client->setUiGeneratedSelectionChange(false);
3103        if (isContentEditable(focusNode)) {
3104            // keyEvent will return true even if the contentEditable did not
3105            // change its selection.  In the case that it does not, we want to
3106            // return false so that the key will be sent back to our navigation
3107            // system.
3108            handled |= frame->selection()->selection() != old;
3109        }
3110        return handled;
3111    } else {
3112        eventHandler = focusedFrame()->eventHandler();
3113    }
3114    return eventHandler->keyEvent(event);
3115}
3116
3117bool WebViewCore::chromeCanTakeFocus(FocusDirection direction)
3118{
3119    JNIEnv* env = JSC::Bindings::getJNIEnv();
3120    AutoJObject javaObject = m_javaGlue->object(env);
3121    if (!javaObject.get())
3122        return false;
3123    return env->CallBooleanMethod(javaObject.get(), m_javaGlue->m_chromeCanTakeFocus, direction);
3124}
3125
3126void WebViewCore::chromeTakeFocus(FocusDirection direction)
3127{
3128    JNIEnv* env = JSC::Bindings::getJNIEnv();
3129    AutoJObject javaObject = m_javaGlue->object(env);
3130    if (!javaObject.get())
3131        return;
3132    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_chromeTakeFocus, direction);
3133}
3134
3135#if USE(ACCELERATED_COMPOSITING)
3136GraphicsLayerAndroid* WebViewCore::graphicsRootLayer() const
3137{
3138    RenderView* contentRenderer = m_mainFrame->contentRenderer();
3139    if (!contentRenderer)
3140        return 0;
3141    return static_cast<GraphicsLayerAndroid*>(
3142          contentRenderer->compositor()->rootPlatformLayer());
3143}
3144#endif
3145
3146bool WebViewCore::handleTouchEvent(int action, Vector<int>& ids, Vector<IntPoint>& points, int actionIndex, int metaState)
3147{
3148    bool preventDefault = false;
3149
3150#if USE(ACCELERATED_COMPOSITING)
3151    GraphicsLayerAndroid* rootLayer = graphicsRootLayer();
3152    if (rootLayer)
3153      rootLayer->pauseDisplay(true);
3154#endif
3155
3156#if ENABLE(TOUCH_EVENTS) // Android
3157    #define MOTION_EVENT_ACTION_POINTER_DOWN 5
3158    #define MOTION_EVENT_ACTION_POINTER_UP 6
3159
3160    WebCore::TouchEventType type = WebCore::TouchStart;
3161    WebCore::PlatformTouchPoint::State defaultTouchState;
3162    Vector<WebCore::PlatformTouchPoint::State> touchStates(points.size());
3163
3164    switch (action) {
3165    case 0: // MotionEvent.ACTION_DOWN
3166        type = WebCore::TouchStart;
3167        defaultTouchState = WebCore::PlatformTouchPoint::TouchPressed;
3168        break;
3169    case 1: // MotionEvent.ACTION_UP
3170        type = WebCore::TouchEnd;
3171        defaultTouchState = WebCore::PlatformTouchPoint::TouchReleased;
3172        break;
3173    case 2: // MotionEvent.ACTION_MOVE
3174        type = WebCore::TouchMove;
3175        defaultTouchState = WebCore::PlatformTouchPoint::TouchMoved;
3176        break;
3177    case 3: // MotionEvent.ACTION_CANCEL
3178        type = WebCore::TouchCancel;
3179        defaultTouchState = WebCore::PlatformTouchPoint::TouchCancelled;
3180        break;
3181    case 5: // MotionEvent.ACTION_POINTER_DOWN
3182        type = WebCore::TouchStart;
3183        defaultTouchState = WebCore::PlatformTouchPoint::TouchStationary;
3184        break;
3185    case 6: // MotionEvent.ACTION_POINTER_UP
3186        type = WebCore::TouchEnd;
3187        defaultTouchState = WebCore::PlatformTouchPoint::TouchStationary;
3188        break;
3189    default:
3190        // We do not support other kinds of touch event inside WebCore
3191        // at the moment.
3192        ALOGW("Java passed a touch event type that we do not support in WebCore: %d", action);
3193        return 0;
3194    }
3195
3196    for (int c = 0; c < static_cast<int>(points.size()); c++) {
3197        points[c].setX(points[c].x() - m_scrollOffsetX);
3198        points[c].setY(points[c].y() - m_scrollOffsetY);
3199
3200        // Setting the touch state for each point.
3201        // Note: actionIndex will be 0 for all actions that are not ACTION_POINTER_DOWN/UP.
3202        if (action == MOTION_EVENT_ACTION_POINTER_DOWN && c == actionIndex) {
3203            touchStates[c] = WebCore::PlatformTouchPoint::TouchPressed;
3204        } else if (action == MOTION_EVENT_ACTION_POINTER_UP && c == actionIndex) {
3205            touchStates[c] = WebCore::PlatformTouchPoint::TouchReleased;
3206        } else {
3207            touchStates[c] = defaultTouchState;
3208        };
3209    }
3210
3211    WebCore::PlatformTouchEvent te(ids, points, type, touchStates, metaState);
3212    preventDefault = m_mainFrame->eventHandler()->handleTouchEvent(te);
3213#endif
3214
3215#if USE(ACCELERATED_COMPOSITING)
3216    if (rootLayer)
3217      rootLayer->pauseDisplay(false);
3218#endif
3219    return preventDefault;
3220}
3221
3222bool WebViewCore::performMouseClick()
3223{
3224    WebCore::PlatformMouseEvent mouseDown(m_mousePos, m_mousePos, WebCore::LeftButton,
3225            WebCore::MouseEventPressed, 1, false, false, false, false,
3226            WTF::currentTime());
3227    // ignore the return from as it will return true if the hit point can trigger selection change
3228    m_mainFrame->eventHandler()->handleMousePressEvent(mouseDown);
3229    WebCore::PlatformMouseEvent mouseUp(m_mousePos, m_mousePos, WebCore::LeftButton,
3230            WebCore::MouseEventReleased, 1, false, false, false, false,
3231            WTF::currentTime());
3232    bool handled = m_mainFrame->eventHandler()->handleMouseReleaseEvent(mouseUp);
3233
3234    WebCore::Node* focusNode = currentFocus();
3235    initializeTextInput(focusNode, false);
3236    return handled;
3237}
3238
3239// Check for the "x-webkit-soft-keyboard" attribute.  If it is there and
3240// set to hidden, do not show the soft keyboard.  Node passed as a parameter
3241// must not be null.
3242static bool shouldSuppressKeyboard(const WebCore::Node* node) {
3243    ALOG_ASSERT(node, "node passed to shouldSuppressKeyboard cannot be null");
3244    const NamedNodeMap* attributes = node->attributes();
3245    if (!attributes) return false;
3246    size_t length = attributes->length();
3247    for (size_t i = 0; i < length; i++) {
3248        const Attribute* a = attributes->attributeItem(i);
3249        if (a->localName() == "x-webkit-soft-keyboard" && a->value() == "hidden")
3250            return true;
3251    }
3252    return false;
3253}
3254
3255WebViewCore::InputType WebViewCore::getInputType(Node* node)
3256{
3257    WebCore::RenderObject* renderer = node->renderer();
3258    if (!renderer)
3259        return WebViewCore::NONE;
3260    if (renderer->isTextArea())
3261        return WebViewCore::TEXT_AREA;
3262
3263    if (node->hasTagName(WebCore::HTMLNames::inputTag)) {
3264        HTMLInputElement* htmlInput = static_cast<HTMLInputElement*>(node);
3265        if (htmlInput->isPasswordField())
3266            return WebViewCore::PASSWORD;
3267        if (htmlInput->isSearchField())
3268            return WebViewCore::SEARCH;
3269        if (htmlInput->isEmailField())
3270            return WebViewCore::EMAIL;
3271        if (htmlInput->isNumberField())
3272            return WebViewCore::NUMBER;
3273        if (htmlInput->isTelephoneField())
3274            return WebViewCore::TELEPHONE;
3275        if (htmlInput->isTextField())
3276            return WebViewCore::NORMAL_TEXT_FIELD;
3277    }
3278
3279    if (node->isContentEditable())
3280        return WebViewCore::TEXT_AREA;
3281
3282    return WebViewCore::NONE;
3283}
3284
3285int WebViewCore::getMaxLength(Node* node)
3286{
3287    int maxLength = -1;
3288    if (node->hasTagName(WebCore::HTMLNames::inputTag)) {
3289        HTMLInputElement* htmlInput = static_cast<HTMLInputElement*>(node);
3290        maxLength = htmlInput->maxLength();
3291    }
3292    return maxLength;
3293}
3294
3295String WebViewCore::getFieldName(Node* node)
3296{
3297    String name;
3298    if (node->hasTagName(WebCore::HTMLNames::inputTag)) {
3299        HTMLInputElement* htmlInput = static_cast<HTMLInputElement*>(node);
3300        name = htmlInput->name();
3301    }
3302    return name;
3303}
3304
3305bool WebViewCore::isSpellCheckEnabled(Node* node)
3306{
3307    bool isEnabled = true;
3308    if (node->isElementNode()) {
3309        WebCore::Element* element = static_cast<WebCore::Element*>(node);
3310        isEnabled = element->isSpellCheckingEnabled();
3311    }
3312    return isEnabled;
3313}
3314
3315bool WebViewCore::isAutoCompleteEnabled(Node* node)
3316{
3317    bool isEnabled = false;
3318    if (node->hasTagName(WebCore::HTMLNames::inputTag)) {
3319        HTMLInputElement* htmlInput = static_cast<HTMLInputElement*>(node);
3320        isEnabled = htmlInput->autoComplete();
3321    }
3322    return isEnabled;
3323}
3324
3325WebCore::IntRect WebViewCore::absoluteContentRect(WebCore::Node* node,
3326        LayerAndroid* layer)
3327{
3328    IntRect contentRect;
3329    if (node) {
3330        RenderObject* render = node->renderer();
3331        if (render && render->isBox() && !render->isBody()) {
3332            IntPoint offset = convertGlobalContentToFrameContent(IntPoint(),
3333                    node->document()->frame());
3334            WebViewCore::layerToAbsoluteOffset(layer, offset);
3335
3336            RenderBox* renderBox = toRenderBox(render);
3337            contentRect = renderBox->absoluteContentBox();
3338            contentRect.move(-offset.x(), -offset.y());
3339        }
3340    }
3341    return contentRect;
3342}
3343
3344jobject WebViewCore::createTextFieldInitData(Node* node)
3345{
3346    JNIEnv* env = JSC::Bindings::getJNIEnv();
3347    TextFieldInitDataGlue* classDef = m_textFieldInitDataGlue;
3348    ScopedLocalRef<jclass> clazz(env,
3349            env->FindClass("android/webkit/WebViewCore$TextFieldInitData"));
3350    jobject initData = env->NewObject(clazz.get(), classDef->m_constructor);
3351    env->SetIntField(initData, classDef->m_fieldPointer,
3352            reinterpret_cast<int>(node));
3353    ScopedLocalRef<jstring> inputText(env,
3354            wtfStringToJstring(env, getInputText(node), true));
3355    env->SetObjectField(initData, classDef->m_text, inputText.get());
3356    env->SetIntField(initData, classDef->m_type, getInputType(node));
3357    env->SetBooleanField(initData, classDef->m_isSpellCheckEnabled,
3358            isSpellCheckEnabled(node));
3359    Document* document = node->document();
3360    PlatformKeyboardEvent tab(AKEYCODE_TAB, 0, 0, false, false, false, false);
3361    PassRefPtr<KeyboardEvent> tabEvent =
3362            KeyboardEvent::create(tab, document->defaultView());
3363    env->SetBooleanField(initData, classDef->m_isTextFieldNext,
3364            isTextInput(document->nextFocusableNode(node, tabEvent.get())));
3365    env->SetBooleanField(initData, classDef->m_isTextFieldPrev,
3366            isTextInput(document->previousFocusableNode(node, tabEvent.get())));
3367    env->SetBooleanField(initData, classDef->m_isAutoCompleteEnabled,
3368            isAutoCompleteEnabled(node));
3369    ScopedLocalRef<jstring> fieldName(env,
3370            wtfStringToJstring(env, getFieldName(node), false));
3371    env->SetObjectField(initData, classDef->m_name, fieldName.get());
3372    ScopedLocalRef<jstring> label(env,
3373            wtfStringToJstring(env, requestLabel(document->frame(), node), false));
3374    env->SetObjectField(initData, classDef->m_name, label.get());
3375    env->SetIntField(initData, classDef->m_maxLength, getMaxLength(node));
3376    LayerAndroid* layer = 0;
3377    int layerId = platformLayerIdFromNode(node, &layer);
3378    IntRect bounds = absoluteContentRect(node, layer);
3379    ScopedLocalRef<jobject> jbounds(env, intRectToRect(env, bounds));
3380    env->SetObjectField(initData, classDef->m_contentBounds, jbounds.get());
3381    env->SetIntField(initData, classDef->m_nodeLayerId, layerId);
3382    IntRect contentRect;
3383    RenderTextControl* rtc = toRenderTextControl(node);
3384    if (rtc) {
3385        contentRect.setWidth(rtc->scrollWidth());
3386        contentRect.setHeight(rtc->scrollHeight());
3387        contentRect.move(-rtc->scrollLeft(), -rtc->scrollTop());
3388    }
3389    ScopedLocalRef<jobject> jcontentRect(env, intRectToRect(env, contentRect));
3390    env->SetObjectField(initData, classDef->m_contentRect, jcontentRect.get());
3391    return initData;
3392}
3393
3394void WebViewCore::initEditField(Node* node)
3395{
3396    JNIEnv* env = JSC::Bindings::getJNIEnv();
3397    AutoJObject javaObject = m_javaGlue->object(env);
3398    if (!javaObject.get())
3399        return;
3400    m_textGeneration = 0;
3401    int start = 0;
3402    int end = 0;
3403    getSelectionOffsets(node, start, end);
3404    SelectText* selectText = createSelectText(focusedFrame()->selection()->selection());
3405    ScopedLocalRef<jobject> initData(env, createTextFieldInitData(node));
3406    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_initEditField,
3407            start, end, reinterpret_cast<int>(selectText), initData.get());
3408    checkException(env);
3409}
3410
3411void WebViewCore::popupReply(int index)
3412{
3413    if (m_popupReply) {
3414        m_popupReply->replyInt(index);
3415        Release(m_popupReply);
3416        m_popupReply = 0;
3417    }
3418}
3419
3420void WebViewCore::popupReply(const int* array, int count)
3421{
3422    if (m_popupReply) {
3423        m_popupReply->replyIntArray(array, count);
3424        Release(m_popupReply);
3425        m_popupReply = 0;
3426    }
3427}
3428
3429// This is a slightly modified Node::nextNodeConsideringAtomicNodes() with the
3430// extra constraint of limiting the search to inside a containing parent
3431WebCore::Node* nextNodeWithinParent(WebCore::Node* parent, WebCore::Node* start)
3432{
3433    if (!isAtomicNode(start) && start->firstChild())
3434        return start->firstChild();
3435    if (start->nextSibling())
3436        return start->nextSibling();
3437    const Node *n = start;
3438    while (n && !n->nextSibling()) {
3439        n = n->parentNode();
3440        if (n == parent)
3441            return 0;
3442    }
3443    if (n)
3444        return n->nextSibling();
3445    return 0;
3446}
3447
3448void WebViewCore::initializeTextInput(WebCore::Node* node, bool fake)
3449{
3450    if (node) {
3451        if (isTextInput(node)) {
3452            bool showKeyboard = true;
3453            initEditField(node);
3454            WebCore::RenderTextControl* rtc = toRenderTextControl(node);
3455            if (rtc && node->hasTagName(HTMLNames::inputTag)) {
3456                HTMLInputElement* inputElement = static_cast<HTMLInputElement*>(node);
3457                bool ime = !shouldSuppressKeyboard(node) && !inputElement->readOnly();
3458                if (ime) {
3459#if ENABLE(WEB_AUTOFILL)
3460                    if (rtc->isTextField()) {
3461                        Page* page = node->document()->page();
3462                        EditorClient* editorClient = page->editorClient();
3463                        EditorClientAndroid* androidEditor =
3464                                static_cast<EditorClientAndroid*>(editorClient);
3465                        WebAutofill* autoFill = androidEditor->getAutofill();
3466                        autoFill->formFieldFocused(inputElement);
3467                    }
3468#endif
3469                } else
3470                    showKeyboard = false;
3471            }
3472            if (!fake)
3473                requestKeyboard(showKeyboard);
3474        } else if (!fake && !nodeIsPlugin(node)) {
3475            // not a text entry field, put away the keyboard.
3476            clearTextEntry();
3477        }
3478    } else if (!fake) {
3479        // There is no focusNode, so the keyboard is not needed.
3480        clearTextEntry();
3481    }
3482}
3483
3484void WebViewCore::focusNodeChanged(WebCore::Node* newFocus)
3485{
3486    JNIEnv* env = JSC::Bindings::getJNIEnv();
3487    AutoJObject javaObject = m_javaGlue->object(env);
3488    if (!javaObject.get())
3489        return;
3490    if (isTextInput(newFocus))
3491        initializeTextInput(newFocus, true);
3492    HitTestResult focusHitResult;
3493    focusHitResult.setInnerNode(newFocus);
3494    focusHitResult.setInnerNonSharedNode(newFocus);
3495    if (newFocus && newFocus->isLink() && newFocus->isElementNode()) {
3496        focusHitResult.setURLElement(static_cast<Element*>(newFocus));
3497        if (newFocus->hasChildNodes() && !newFocus->hasTagName(HTMLNames::imgTag)) {
3498            // Check to see if any of the children are images, and if so
3499            // set them as the innerNode and innerNonSharedNode
3500            // This will stop when it hits the first image. I'm not sure what
3501            // should be done in the case of multiple images inside one anchor...
3502            Node* nextNode = newFocus->firstChild();
3503            bool found = false;
3504            while (nextNode) {
3505                if (nextNode->hasTagName(HTMLNames::imgTag)) {
3506                    found = true;
3507                    break;
3508                }
3509                nextNode = nextNodeWithinParent(newFocus, nextNode);
3510            }
3511            if (found) {
3512                focusHitResult.setInnerNode(nextNode);
3513                focusHitResult.setInnerNonSharedNode(nextNode);
3514            }
3515        }
3516    }
3517    AndroidHitTestResult androidHitTest(this, focusHitResult);
3518    jobject jHitTestObj = androidHitTest.createJavaObject(env);
3519    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_focusNodeChanged,
3520            reinterpret_cast<int>(newFocus), jHitTestObj);
3521    env->DeleteLocalRef(jHitTestObj);
3522}
3523
3524void WebViewCore::addMessageToConsole(const WTF::String& message, unsigned int lineNumber, const WTF::String& sourceID, int msgLevel) {
3525    JNIEnv* env = JSC::Bindings::getJNIEnv();
3526    AutoJObject javaObject = m_javaGlue->object(env);
3527    if (!javaObject.get())
3528        return;
3529    jstring jMessageStr = wtfStringToJstring(env, message);
3530    jstring jSourceIDStr = wtfStringToJstring(env, sourceID);
3531    env->CallVoidMethod(javaObject.get(),
3532            m_javaGlue->m_addMessageToConsole, jMessageStr, lineNumber,
3533            jSourceIDStr, msgLevel);
3534    env->DeleteLocalRef(jMessageStr);
3535    env->DeleteLocalRef(jSourceIDStr);
3536    checkException(env);
3537}
3538
3539void WebViewCore::jsAlert(const WTF::String& url, const WTF::String& text)
3540{
3541    JNIEnv* env = JSC::Bindings::getJNIEnv();
3542    AutoJObject javaObject = m_javaGlue->object(env);
3543    if (!javaObject.get())
3544        return;
3545    jstring jInputStr = wtfStringToJstring(env, text);
3546    jstring jUrlStr = wtfStringToJstring(env, url);
3547    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_jsAlert, jUrlStr, jInputStr);
3548    env->DeleteLocalRef(jInputStr);
3549    env->DeleteLocalRef(jUrlStr);
3550    checkException(env);
3551}
3552
3553bool WebViewCore::exceededDatabaseQuota(const WTF::String& url, const WTF::String& databaseIdentifier, const unsigned long long currentQuota, unsigned long long estimatedSize)
3554{
3555#if ENABLE(DATABASE)
3556    JNIEnv* env = JSC::Bindings::getJNIEnv();
3557    AutoJObject javaObject = m_javaGlue->object(env);
3558    if (!javaObject.get())
3559        return false;
3560    jstring jDatabaseIdentifierStr = wtfStringToJstring(env, databaseIdentifier);
3561    jstring jUrlStr = wtfStringToJstring(env, url);
3562    env->CallVoidMethod(javaObject.get(),
3563            m_javaGlue->m_exceededDatabaseQuota, jUrlStr,
3564            jDatabaseIdentifierStr, currentQuota, estimatedSize);
3565    env->DeleteLocalRef(jDatabaseIdentifierStr);
3566    env->DeleteLocalRef(jUrlStr);
3567    checkException(env);
3568    return true;
3569#endif
3570}
3571
3572bool WebViewCore::reachedMaxAppCacheSize(const unsigned long long spaceNeeded)
3573{
3574#if ENABLE(OFFLINE_WEB_APPLICATIONS)
3575    JNIEnv* env = JSC::Bindings::getJNIEnv();
3576    AutoJObject javaObject = m_javaGlue->object(env);
3577    if (!javaObject.get())
3578        return false;
3579    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_reachedMaxAppCacheSize, spaceNeeded);
3580    checkException(env);
3581    return true;
3582#endif
3583}
3584
3585void WebViewCore::populateVisitedLinks(WebCore::PageGroup* group)
3586{
3587    JNIEnv* env = JSC::Bindings::getJNIEnv();
3588    AutoJObject javaObject = m_javaGlue->object(env);
3589    if (!javaObject.get())
3590        return;
3591    m_groupForVisitedLinks = group;
3592    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_populateVisitedLinks);
3593    checkException(env);
3594}
3595
3596void WebViewCore::geolocationPermissionsShowPrompt(const WTF::String& origin)
3597{
3598    JNIEnv* env = JSC::Bindings::getJNIEnv();
3599    AutoJObject javaObject = m_javaGlue->object(env);
3600    if (!javaObject.get())
3601        return;
3602    jstring originString = wtfStringToJstring(env, origin);
3603    env->CallVoidMethod(javaObject.get(),
3604                        m_javaGlue->m_geolocationPermissionsShowPrompt,
3605                        originString);
3606    env->DeleteLocalRef(originString);
3607    checkException(env);
3608}
3609
3610void WebViewCore::geolocationPermissionsHidePrompt()
3611{
3612    JNIEnv* env = JSC::Bindings::getJNIEnv();
3613    AutoJObject javaObject = m_javaGlue->object(env);
3614    if (!javaObject.get())
3615        return;
3616    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_geolocationPermissionsHidePrompt);
3617    checkException(env);
3618}
3619
3620jobject WebViewCore::getDeviceMotionService()
3621{
3622    JNIEnv* env = JSC::Bindings::getJNIEnv();
3623    AutoJObject javaObject = m_javaGlue->object(env);
3624    if (!javaObject.get())
3625        return 0;
3626    jobject object = env->CallObjectMethod(javaObject.get(), m_javaGlue->m_getDeviceMotionService);
3627    checkException(env);
3628    return object;
3629}
3630
3631jobject WebViewCore::getDeviceOrientationService()
3632{
3633    JNIEnv* env = JSC::Bindings::getJNIEnv();
3634    AutoJObject javaObject = m_javaGlue->object(env);
3635    if (!javaObject.get())
3636        return 0;
3637    jobject object = env->CallObjectMethod(javaObject.get(), m_javaGlue->m_getDeviceOrientationService);
3638    checkException(env);
3639    return object;
3640}
3641
3642bool WebViewCore::jsConfirm(const WTF::String& url, const WTF::String& text)
3643{
3644    JNIEnv* env = JSC::Bindings::getJNIEnv();
3645    AutoJObject javaObject = m_javaGlue->object(env);
3646    if (!javaObject.get())
3647        return false;
3648    jstring jInputStr = wtfStringToJstring(env, text);
3649    jstring jUrlStr = wtfStringToJstring(env, url);
3650    jboolean result = env->CallBooleanMethod(javaObject.get(), m_javaGlue->m_jsConfirm, jUrlStr, jInputStr);
3651    env->DeleteLocalRef(jInputStr);
3652    env->DeleteLocalRef(jUrlStr);
3653    checkException(env);
3654    return result;
3655}
3656
3657bool WebViewCore::jsPrompt(const WTF::String& url, const WTF::String& text, const WTF::String& defaultValue, WTF::String& result)
3658{
3659    JNIEnv* env = JSC::Bindings::getJNIEnv();
3660    AutoJObject javaObject = m_javaGlue->object(env);
3661    if (!javaObject.get())
3662        return false;
3663    jstring jUrlStr = wtfStringToJstring(env, url);
3664    jstring jInputStr = wtfStringToJstring(env, text);
3665    jstring jDefaultStr = wtfStringToJstring(env, defaultValue);
3666    jstring returnVal = static_cast<jstring>(env->CallObjectMethod(javaObject.get(), m_javaGlue->m_jsPrompt, jUrlStr, jInputStr, jDefaultStr));
3667    env->DeleteLocalRef(jUrlStr);
3668    env->DeleteLocalRef(jInputStr);
3669    env->DeleteLocalRef(jDefaultStr);
3670    checkException(env);
3671
3672    // If returnVal is null, it means that the user cancelled the dialog.
3673    if (!returnVal)
3674        return false;
3675
3676    result = jstringToWtfString(env, returnVal);
3677    env->DeleteLocalRef(returnVal);
3678    return true;
3679}
3680
3681bool WebViewCore::jsUnload(const WTF::String& url, const WTF::String& message)
3682{
3683    JNIEnv* env = JSC::Bindings::getJNIEnv();
3684    AutoJObject javaObject = m_javaGlue->object(env);
3685    if (!javaObject.get())
3686        return false;
3687    jstring jInputStr = wtfStringToJstring(env, message);
3688    jstring jUrlStr = wtfStringToJstring(env, url);
3689    jboolean result = env->CallBooleanMethod(javaObject.get(), m_javaGlue->m_jsUnload, jUrlStr, jInputStr);
3690    env->DeleteLocalRef(jInputStr);
3691    env->DeleteLocalRef(jUrlStr);
3692    checkException(env);
3693    return result;
3694}
3695
3696bool WebViewCore::jsInterrupt()
3697{
3698    JNIEnv* env = JSC::Bindings::getJNIEnv();
3699    AutoJObject javaObject = m_javaGlue->object(env);
3700    if (!javaObject.get())
3701        return false;
3702    jboolean result = env->CallBooleanMethod(javaObject.get(), m_javaGlue->m_jsInterrupt);
3703    checkException(env);
3704    return result;
3705}
3706
3707AutoJObject
3708WebViewCore::getJavaObject()
3709{
3710    return m_javaGlue->object(JSC::Bindings::getJNIEnv());
3711}
3712
3713jobject
3714WebViewCore::getWebViewJavaObject()
3715{
3716    JNIEnv* env = JSC::Bindings::getJNIEnv();
3717    AutoJObject javaObject = m_javaGlue->object(env);
3718    if (!javaObject.get())
3719        return 0;
3720    return env->CallObjectMethod(javaObject.get(), m_javaGlue->m_getWebView);
3721}
3722
3723RenderTextControl* WebViewCore::toRenderTextControl(Node* node)
3724{
3725    RenderTextControl* rtc = 0;
3726    RenderObject* renderer = node->renderer();
3727    if (renderer && renderer->isTextControl()) {
3728        rtc = WebCore::toRenderTextControl(renderer);
3729    }
3730    return rtc;
3731}
3732
3733void WebViewCore::getSelectionOffsets(Node* node, int& start, int& end)
3734{
3735    RenderTextControl* rtc = toRenderTextControl(node);
3736    if (rtc) {
3737        start = rtc->selectionStart();
3738        end = rtc->selectionEnd();
3739    } else {
3740        // It must be content editable field.
3741        Document* document = node->document();
3742        Frame* frame = document->frame();
3743        SelectionController* selector = frame->selection();
3744        Position selectionStart = selector->start();
3745        Position selectionEnd = selector->end();
3746        Position startOfNode = firstPositionInNode(node);
3747        RefPtr<Range> startRange = Range::create(document, startOfNode,
3748                selectionStart);
3749        start = TextIterator::rangeLength(startRange.get(), true);
3750        RefPtr<Range> endRange = Range::create(document, startOfNode,
3751                selectionEnd);
3752        end = TextIterator::rangeLength(endRange.get(), true);
3753    }
3754}
3755
3756String WebViewCore::getInputText(Node* node)
3757{
3758    String text;
3759    WebCore::RenderTextControl* renderText = toRenderTextControl(node);
3760    if (renderText)
3761        text = renderText->text();
3762    else {
3763        // It must be content editable field.
3764        Position start = firstPositionInNode(node);
3765        Position end = lastPositionInNode(node);
3766        VisibleSelection allEditableText(start, end);
3767        if (allEditableText.isRange())
3768            text = allEditableText.firstRange()->text();
3769    }
3770    return text;
3771}
3772
3773void WebViewCore::updateTextSelection()
3774{
3775    JNIEnv* env = JSC::Bindings::getJNIEnv();
3776    AutoJObject javaObject = m_javaGlue->object(env);
3777    if (!javaObject.get())
3778        return;
3779    VisibleSelection selection = focusedFrame()->selection()->selection();
3780    int start = 0;
3781    int end = 0;
3782    if (selection.isCaretOrRange())
3783        getSelectionOffsets(selection.start().anchorNode(), start, end);
3784    SelectText* selectText = createSelectText(selection);
3785    env->CallVoidMethod(javaObject.get(),
3786            m_javaGlue->m_updateTextSelection, reinterpret_cast<int>(currentFocus()),
3787            start, end, m_textGeneration, reinterpret_cast<int>(selectText));
3788    checkException(env);
3789}
3790
3791void WebViewCore::updateTextSizeAndScroll(WebCore::Node* node)
3792{
3793    JNIEnv* env = JSC::Bindings::getJNIEnv();
3794    AutoJObject javaObject = m_javaGlue->object(env);
3795    if (!javaObject.get())
3796        return;
3797    RenderTextControl* rtc = toRenderTextControl(node);
3798    if (!rtc)
3799        return;
3800    int width = rtc->scrollWidth();
3801    int height = rtc->contentHeight();
3802    int scrollX = rtc->scrollLeft();
3803    int scrollY = rtc->scrollTop();
3804    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_updateTextSizeAndScroll,
3805            reinterpret_cast<int>(node), width, height, scrollX, scrollY);
3806    checkException(env);
3807}
3808
3809void WebViewCore::updateTextfield(WebCore::Node* ptr, bool changeToPassword,
3810        const WTF::String& text)
3811{
3812    JNIEnv* env = JSC::Bindings::getJNIEnv();
3813    AutoJObject javaObject = m_javaGlue->object(env);
3814    if (!javaObject.get())
3815        return;
3816    if (m_blockTextfieldUpdates)
3817        return;
3818    if (changeToPassword) {
3819        env->CallVoidMethod(javaObject.get(), m_javaGlue->m_updateTextfield,
3820                (int) ptr, true, 0, m_textGeneration);
3821        checkException(env);
3822        return;
3823    }
3824    jstring string = wtfStringToJstring(env, text);
3825    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_updateTextfield,
3826            (int) ptr, false, string, m_textGeneration);
3827    env->DeleteLocalRef(string);
3828    checkException(env);
3829}
3830
3831void WebViewCore::clearTextEntry()
3832{
3833    JNIEnv* env = JSC::Bindings::getJNIEnv();
3834    AutoJObject javaObject = m_javaGlue->object(env);
3835    if (!javaObject.get())
3836        return;
3837    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_clearTextEntry);
3838}
3839
3840void WebViewCore::setBackgroundColor(SkColor c)
3841{
3842    WebCore::FrameView* view = m_mainFrame->view();
3843    if (!view)
3844        return;
3845
3846    // need (int) cast to find the right constructor
3847    WebCore::Color bcolor((int)SkColorGetR(c), (int)SkColorGetG(c),
3848                          (int)SkColorGetB(c), (int)SkColorGetA(c));
3849    view->setBaseBackgroundColor(bcolor);
3850
3851    // Background color of 0 indicates we want a transparent background
3852    if (c == 0)
3853        view->setTransparent(true);
3854}
3855
3856jclass WebViewCore::getPluginClass(const WTF::String& libName, const char* className)
3857{
3858    JNIEnv* env = JSC::Bindings::getJNIEnv();
3859    AutoJObject javaObject = m_javaGlue->object(env);
3860    if (!javaObject.get())
3861        return 0;
3862
3863    jstring libString = wtfStringToJstring(env, libName);
3864    jstring classString = env->NewStringUTF(className);
3865    jobject pluginClass = env->CallObjectMethod(javaObject.get(),
3866                                           m_javaGlue->m_getPluginClass,
3867                                           libString, classString);
3868    checkException(env);
3869
3870    // cleanup unneeded local JNI references
3871    env->DeleteLocalRef(libString);
3872    env->DeleteLocalRef(classString);
3873
3874    if (pluginClass != 0) {
3875        return static_cast<jclass>(pluginClass);
3876    } else {
3877        return 0;
3878    }
3879}
3880
3881void WebViewCore::showFullScreenPlugin(jobject childView, int32_t orientation, NPP npp)
3882{
3883    JNIEnv* env = JSC::Bindings::getJNIEnv();
3884    AutoJObject javaObject = m_javaGlue->object(env);
3885    if (!javaObject.get())
3886        return;
3887
3888    env->CallVoidMethod(javaObject.get(),
3889                        m_javaGlue->m_showFullScreenPlugin,
3890                        childView, orientation, reinterpret_cast<int>(npp));
3891    checkException(env);
3892}
3893
3894void WebViewCore::hideFullScreenPlugin()
3895{
3896    JNIEnv* env = JSC::Bindings::getJNIEnv();
3897    AutoJObject javaObject = m_javaGlue->object(env);
3898    if (!javaObject.get())
3899        return;
3900    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_hideFullScreenPlugin);
3901    checkException(env);
3902}
3903
3904jobject WebViewCore::createSurface(jobject view)
3905{
3906    JNIEnv* env = JSC::Bindings::getJNIEnv();
3907    AutoJObject javaObject = m_javaGlue->object(env);
3908    if (!javaObject.get())
3909        return 0;
3910    jobject result = env->CallObjectMethod(javaObject.get(), m_javaGlue->m_createSurface, view);
3911    checkException(env);
3912    return result;
3913}
3914
3915jobject WebViewCore::addSurface(jobject view, int x, int y, int width, int height)
3916{
3917    JNIEnv* env = JSC::Bindings::getJNIEnv();
3918    AutoJObject javaObject = m_javaGlue->object(env);
3919    if (!javaObject.get())
3920        return 0;
3921    jobject result = env->CallObjectMethod(javaObject.get(),
3922                                           m_javaGlue->m_addSurface,
3923                                           view, x, y, width, height);
3924    checkException(env);
3925    return result;
3926}
3927
3928void WebViewCore::updateSurface(jobject childView, int x, int y, int width, int height)
3929{
3930    JNIEnv* env = JSC::Bindings::getJNIEnv();
3931    AutoJObject javaObject = m_javaGlue->object(env);
3932    if (!javaObject.get())
3933        return;
3934    env->CallVoidMethod(javaObject.get(),
3935                        m_javaGlue->m_updateSurface, childView,
3936                        x, y, width, height);
3937    checkException(env);
3938}
3939
3940void WebViewCore::destroySurface(jobject childView)
3941{
3942    JNIEnv* env = JSC::Bindings::getJNIEnv();
3943    AutoJObject javaObject = m_javaGlue->object(env);
3944    if (!javaObject.get())
3945        return;
3946    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_destroySurface, childView);
3947    checkException(env);
3948}
3949
3950jobject WebViewCore::getContext()
3951{
3952    JNIEnv* env = JSC::Bindings::getJNIEnv();
3953    AutoJObject javaObject = m_javaGlue->object(env);
3954    if (!javaObject.get())
3955        return 0;
3956
3957    jobject result = env->CallObjectMethod(javaObject.get(), m_javaGlue->m_getContext);
3958    checkException(env);
3959    return result;
3960}
3961
3962void WebViewCore::keepScreenOn(bool screenOn) {
3963    if ((screenOn && m_screenOnCounter == 0) || (!screenOn && m_screenOnCounter == 1)) {
3964        JNIEnv* env = JSC::Bindings::getJNIEnv();
3965        AutoJObject javaObject = m_javaGlue->object(env);
3966        if (!javaObject.get())
3967            return;
3968        env->CallVoidMethod(javaObject.get(), m_javaGlue->m_keepScreenOn, screenOn);
3969        checkException(env);
3970    }
3971
3972    // update the counter
3973    if (screenOn)
3974        m_screenOnCounter++;
3975    else if (m_screenOnCounter > 0)
3976        m_screenOnCounter--;
3977}
3978
3979void WebViewCore::showRect(int left, int top, int width, int height,
3980        int contentWidth, int contentHeight, float xPercentInDoc,
3981        float xPercentInView, float yPercentInDoc, float yPercentInView)
3982{
3983    JNIEnv* env = JSC::Bindings::getJNIEnv();
3984    AutoJObject javaObject = m_javaGlue->object(env);
3985    if (!javaObject.get())
3986        return;
3987    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_showRect,
3988            left, top, width, height, contentWidth, contentHeight,
3989            xPercentInDoc, xPercentInView, yPercentInDoc, yPercentInView);
3990    checkException(env);
3991}
3992
3993void WebViewCore::centerFitRect(int x, int y, int width, int height)
3994{
3995    JNIEnv* env = JSC::Bindings::getJNIEnv();
3996    AutoJObject javaObject = m_javaGlue->object(env);
3997    if (!javaObject.get())
3998        return;
3999    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_centerFitRect, x, y, width, height);
4000    checkException(env);
4001}
4002
4003void WebViewCore::setScrollbarModes(ScrollbarMode horizontalMode, ScrollbarMode verticalMode)
4004{
4005    JNIEnv* env = JSC::Bindings::getJNIEnv();
4006    AutoJObject javaObject = m_javaGlue->object(env);
4007    if (!javaObject.get())
4008        return;
4009    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_setScrollbarModes, horizontalMode, verticalMode);
4010    checkException(env);
4011}
4012
4013void WebViewCore::notifyWebAppCanBeInstalled()
4014{
4015    JNIEnv* env = JSC::Bindings::getJNIEnv();
4016    AutoJObject javaObject = m_javaGlue->object(env);
4017    if (!javaObject.get())
4018        return;
4019    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_setInstallableWebApp);
4020    checkException(env);
4021}
4022
4023#if ENABLE(VIDEO)
4024void WebViewCore::enterFullscreenForVideoLayer(int layerId, const WTF::String& url)
4025{
4026    JNIEnv* env = JSC::Bindings::getJNIEnv();
4027    AutoJObject javaObject = m_javaGlue->object(env);
4028    if (!javaObject.get())
4029        return;
4030    jstring jUrlStr = wtfStringToJstring(env, url);
4031    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_enterFullscreenForVideoLayer, layerId, jUrlStr);
4032    m_fullscreenVideoMode = true;
4033    checkException(env);
4034}
4035
4036void WebViewCore::exitFullscreenVideo()
4037{
4038    JNIEnv* env = JSC::Bindings::getJNIEnv();
4039    AutoJObject javaObject = m_javaGlue->object(env);
4040    if (!javaObject.get())
4041        return;
4042    if (m_fullscreenVideoMode) {
4043        env->CallVoidMethod(javaObject.get(), m_javaGlue->m_exitFullscreenVideo);
4044        m_fullscreenVideoMode = false;
4045    }
4046    checkException(env);
4047}
4048#endif
4049
4050void WebViewCore::setWebTextViewAutoFillable(int queryId, const string16& previewSummary)
4051{
4052#if ENABLE(WEB_AUTOFILL)
4053    JNIEnv* env = JSC::Bindings::getJNIEnv();
4054    AutoJObject javaObject = m_javaGlue->object(env);
4055    if (!javaObject.get())
4056        return;
4057    jstring preview = env->NewString(previewSummary.data(), previewSummary.length());
4058    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_setWebTextViewAutoFillable, queryId, preview);
4059    env->DeleteLocalRef(preview);
4060#endif
4061}
4062
4063bool WebViewCore::drawIsPaused() const
4064{
4065    // returning true says scrollview should be offscreen, which pauses
4066    // gifs. because this is not again queried when we stop scrolling, we don't
4067    // use the stopping currently.
4068    return false;
4069}
4070
4071void WebViewCore::setWebRequestContextUserAgent()
4072{
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        m_webRequestContext->setUserAgent(WebFrame::getWebFrame(m_mainFrame)->userAgentForURL(0)); // URL not used
4076}
4077
4078void WebViewCore::setWebRequestContextCacheMode(int cacheMode)
4079{
4080    m_cacheMode = cacheMode;
4081    // We cannot create a WebRequestContext, because we might not know it this is a private tab or not yet
4082    if (!m_webRequestContext)
4083        return;
4084
4085    m_webRequestContext->setCacheMode(cacheMode);
4086}
4087
4088WebRequestContext* WebViewCore::webRequestContext()
4089{
4090    if (!m_webRequestContext) {
4091        Settings* settings = mainFrame()->settings();
4092        m_webRequestContext = new WebRequestContext(settings && settings->privateBrowsingEnabled());
4093        setWebRequestContextUserAgent();
4094        setWebRequestContextCacheMode(m_cacheMode);
4095    }
4096    return m_webRequestContext.get();
4097}
4098
4099void WebViewCore::scrollRenderLayer(int layer, const SkRect& rect)
4100{
4101#if USE(ACCELERATED_COMPOSITING)
4102    GraphicsLayerAndroid* root = graphicsRootLayer();
4103    if (!root)
4104        return;
4105
4106    LayerAndroid* layerAndroid = root->platformLayer();
4107    if (!layerAndroid)
4108        return;
4109
4110    LayerAndroid* target = layerAndroid->findById(layer);
4111    if (!target)
4112        return;
4113
4114    RenderLayer* owner = target->owningLayer();
4115    if (!owner)
4116        return;
4117
4118    if (owner->isRootLayer()) {
4119        FrameView* view = owner->renderer()->frame()->view();
4120        IntPoint pt(rect.fLeft, rect.fTop);
4121        view->setScrollPosition(pt);
4122    } else
4123        owner->scrollToOffset(rect.fLeft, rect.fTop);
4124#endif
4125}
4126
4127Vector<VisibleSelection> WebViewCore::getTextRanges(
4128        int startX, int startY, int endX, int endY)
4129{
4130    // These are the positions of the selection handles,
4131    // which reside below the line that they are selecting.
4132    // Use the vertical position higher, which will include
4133    // the selected text.
4134    startY--;
4135    endY--;
4136    VisiblePosition startSelect = visiblePositionForContentPoint(startX, startY);
4137    VisiblePosition endSelect =  visiblePositionForContentPoint(endX, endY);
4138    Position start = startSelect.deepEquivalent();
4139    Position end = endSelect.deepEquivalent();
4140    Vector<VisibleSelection> ranges;
4141    if (!start.isNull() && !end.isNull()) {
4142        if (comparePositions(start, end) > 0) {
4143            swap(start, end); // RTL start/end positions may be swapped
4144        }
4145        Position nextRangeStart = start;
4146        Position previousRangeEnd;
4147        do {
4148            VisibleSelection selection(nextRangeStart, end);
4149            ranges.append(selection);
4150            previousRangeEnd = selection.end();
4151            nextRangeStart = nextCandidate(previousRangeEnd);
4152        } while (comparePositions(previousRangeEnd, end) < 0);
4153    }
4154    return ranges;
4155}
4156
4157void WebViewCore::deleteText(int startX, int startY, int endX, int endY)
4158{
4159    Vector<VisibleSelection> ranges =
4160            getTextRanges(startX, startY, endX, endY);
4161
4162    EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
4163            m_mainFrame->editor()->client());
4164    client->setUiGeneratedSelectionChange(true);
4165
4166    SelectionController* selector = m_mainFrame->selection();
4167    for (size_t i = 0; i < ranges.size(); i++) {
4168        const VisibleSelection& selection = ranges[i];
4169        if (selection.isContentEditable()) {
4170            selector->setSelection(selection, CharacterGranularity);
4171            Document* document = selection.start().anchorNode()->document();
4172            WebCore::TypingCommand::deleteSelection(document, 0);
4173        }
4174    }
4175    client->setUiGeneratedSelectionChange(false);
4176}
4177
4178void WebViewCore::insertText(const WTF::String &text)
4179{
4180    WebCore::Node* focus = currentFocus();
4181    if (!focus || !isTextInput(focus))
4182        return;
4183
4184    Document* document = focus->document();
4185
4186    EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
4187            m_mainFrame->editor()->client());
4188    if (!client)
4189        return;
4190    client->setUiGeneratedSelectionChange(true);
4191    WebCore::TypingCommand::insertText(document, text,
4192            TypingCommand::PreventSpellChecking);
4193    client->setUiGeneratedSelectionChange(false);
4194}
4195
4196void WebViewCore::resetFindOnPage()
4197{
4198    m_searchText.truncate(0);
4199    m_matchCount = 0;
4200    m_activeMatchIndex = 0;
4201    m_activeMatch = 0;
4202}
4203
4204int WebViewCore::findTextOnPage(const WTF::String &text)
4205{
4206    resetFindOnPage(); // reset even if parameters are bad
4207
4208    WebCore::Frame* frame = m_mainFrame;
4209    if (!frame)
4210        return 0;
4211
4212    m_searchText = text;
4213    FindOptions findOptions = WebCore::CaseInsensitive;
4214
4215    do {
4216        frame->document()->markers()->removeMarkers(DocumentMarker::TextMatch);
4217        m_matchCount += frame->editor()->countMatchesForText(text, findOptions,
4218            0, true);
4219        frame->editor()->setMarkedTextMatchesAreHighlighted(true);
4220        frame = frame->tree()->traverseNextWithWrap(false);
4221    } while (frame);
4222    m_activeMatchIndex = m_matchCount - 1; // prime first findNext
4223    return m_matchCount;
4224}
4225
4226int WebViewCore::findNextOnPage(bool forward)
4227{
4228    if (!m_mainFrame)
4229        return -1;
4230    if (!m_matchCount)
4231        return -1;
4232
4233    EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
4234        m_mainFrame->editor()->client());
4235    client->setUiGeneratedSelectionChange(true);
4236
4237    // Clear previous active match.
4238    if (m_activeMatch) {
4239        m_mainFrame->document()->markers()->setMarkersActive(
4240            m_activeMatch.get(), false);
4241    }
4242
4243    FindOptions findOptions = WebCore::CaseInsensitive
4244        | WebCore::StartInSelection | WebCore::WrapAround;
4245    if (!forward)
4246        findOptions |= WebCore::Backwards;
4247
4248    // Start from the previous active match.
4249    if (m_activeMatch) {
4250        m_mainFrame->selection()->setSelection(m_activeMatch.get());
4251    }
4252
4253    bool found = m_mainFrame->editor()->findString(m_searchText, findOptions);
4254    if (found) {
4255        VisibleSelection selection(m_mainFrame->selection()->selection());
4256        if (selection.isNone() || selection.start() == selection.end()) {
4257            // Temporary workaround for findString() refusing to select text
4258            // marked "-webkit-user-select: none".
4259            m_activeMatchIndex = 0;
4260            m_activeMatch = 0;
4261        } else {
4262            // Mark current match "active".
4263            if (forward) {
4264                ++m_activeMatchIndex;
4265                if (m_activeMatchIndex == m_matchCount)
4266                    m_activeMatchIndex = 0;
4267            } else {
4268                if (m_activeMatchIndex == 0)
4269                    m_activeMatchIndex = m_matchCount;
4270                --m_activeMatchIndex;
4271            }
4272            m_activeMatch = selection.firstRange();
4273            m_mainFrame->document()->markers()->setMarkersActive(
4274                m_activeMatch.get(), true);
4275            m_mainFrame->selection()->revealSelection(
4276                ScrollAlignment::alignCenterIfNeeded, true);
4277        }
4278    }
4279
4280    // Clear selection so it doesn't display.
4281    m_mainFrame->selection()->clear();
4282    client->setUiGeneratedSelectionChange(false);
4283    return m_activeMatchIndex;
4284}
4285
4286String WebViewCore::getText(int startX, int startY, int endX, int endY)
4287{
4288    String text;
4289
4290    Vector<VisibleSelection> ranges =
4291            getTextRanges(startX, startY, endX, endY);
4292
4293    for (size_t i = 0; i < ranges.size(); i++) {
4294        const VisibleSelection& selection = ranges[i];
4295        if (selection.isRange()) {
4296            PassRefPtr<Range> range = selection.firstRange();
4297            String textInRange = range->text();
4298            if (textInRange.length() > 0) {
4299                if (text.length() > 0)
4300                    text.append('\n');
4301                text.append(textInRange);
4302            }
4303        }
4304    }
4305
4306    return text;
4307}
4308
4309/**
4310 * Read the persistent locale.
4311 */
4312void WebViewCore::getLocale(String& language, String& region)
4313{
4314    char propLang[PROPERTY_VALUE_MAX], propRegn[PROPERTY_VALUE_MAX];
4315
4316    property_get("persist.sys.language", propLang, "");
4317    property_get("persist.sys.country", propRegn, "");
4318    if (*propLang == 0 && *propRegn == 0) {
4319        /* Set to ro properties, default is en_US */
4320        property_get("ro.product.locale.language", propLang, "en");
4321        property_get("ro.product.locale.region", propRegn, "US");
4322    }
4323    language = String(propLang, 2);
4324    region = String(propRegn, 2);
4325}
4326
4327void WebViewCore::updateLocale()
4328{
4329    static String prevLang;
4330    static String prevRegn;
4331    String language;
4332    String region;
4333
4334    getLocale(language, region);
4335
4336    if ((language != prevLang) || (region != prevRegn)) {
4337        prevLang = language;
4338        prevRegn = region;
4339        GlyphPageTreeNode::resetRoots();
4340        fontCache()->invalidate();
4341    }
4342}
4343
4344//----------------------------------------------------------------------
4345// Native JNI methods
4346//----------------------------------------------------------------------
4347static void RevealSelection(JNIEnv* env, jobject obj, jint nativeClass)
4348{
4349    reinterpret_cast<WebViewCore*>(nativeClass)->revealSelection();
4350}
4351
4352static jstring RequestLabel(JNIEnv* env, jobject obj, jint nativeClass,
4353        int framePointer, int nodePointer)
4354{
4355    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4356    return wtfStringToJstring(env, viewImpl->requestLabel(
4357            (WebCore::Frame*) framePointer, (WebCore::Node*) nodePointer));
4358}
4359
4360static void ClearContent(JNIEnv* env, jobject obj, jint nativeClass)
4361{
4362    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4363    viewImpl->clearContent();
4364}
4365
4366static void SetSize(JNIEnv* env, jobject obj, jint nativeClass, jint width,
4367        jint height, jint textWrapWidth, jfloat scale, jint screenWidth,
4368        jint screenHeight, jint anchorX, jint anchorY, jboolean ignoreHeight)
4369{
4370    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4371    ALOGV("webviewcore::nativeSetSize(%u %u)\n viewImpl: %p", (unsigned)width, (unsigned)height, viewImpl);
4372    ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSetSize");
4373    viewImpl->setSizeScreenWidthAndScale(width, height, textWrapWidth, scale,
4374            screenWidth, screenHeight, anchorX, anchorY, ignoreHeight);
4375}
4376
4377static void SetScrollOffset(JNIEnv* env, jobject obj, jint nativeClass,
4378        jboolean sendScrollEvent, jint x, jint y)
4379{
4380    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4381    ALOG_ASSERT(viewImpl, "need viewImpl");
4382
4383    viewImpl->setScrollOffset(sendScrollEvent, x, y);
4384}
4385
4386static void SetGlobalBounds(JNIEnv* env, jobject obj, jint nativeClass,
4387        jint x, jint y, jint h, jint v)
4388{
4389    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4390    ALOG_ASSERT(viewImpl, "need viewImpl");
4391
4392    viewImpl->setGlobalBounds(x, y, h, v);
4393}
4394
4395static jboolean Key(JNIEnv* env, jobject obj, jint nativeClass, jint keyCode,
4396        jint unichar, jint repeatCount, jboolean isShift, jboolean isAlt,
4397        jboolean isSym, jboolean isDown)
4398{
4399    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4400    return viewImpl->key(PlatformKeyboardEvent(keyCode,
4401        unichar, repeatCount, isDown, isShift, isAlt, isSym));
4402}
4403
4404static void ContentInvalidateAll(JNIEnv* env, jobject obj, jint nativeClass)
4405{
4406    reinterpret_cast<WebViewCore*>(nativeClass)->contentInvalidateAll();
4407}
4408
4409static void DeleteSelection(JNIEnv* env, jobject obj, jint nativeClass,
4410        jint start, jint end, jint textGeneration)
4411{
4412    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4413    viewImpl->deleteSelection(start, end, textGeneration);
4414}
4415
4416static void SetSelection(JNIEnv* env, jobject obj, jint nativeClass,
4417        jint start, jint end)
4418{
4419    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4420    viewImpl->setSelection(start, end);
4421}
4422
4423static jstring ModifySelection(JNIEnv* env, jobject obj, jint nativeClass,
4424        jint direction, jint granularity)
4425{
4426    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4427    String selectionString = viewImpl->modifySelection(direction, granularity);
4428    return wtfStringToJstring(env, selectionString);
4429}
4430
4431static void ReplaceTextfieldText(JNIEnv* env, jobject obj, jint nativeClass,
4432    jint oldStart, jint oldEnd, jstring replace, jint start, jint end,
4433    jint textGeneration)
4434{
4435    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4436    WTF::String webcoreString = jstringToWtfString(env, replace);
4437    viewImpl->replaceTextfieldText(oldStart,
4438            oldEnd, webcoreString, start, end, textGeneration);
4439}
4440
4441static void PassToJs(JNIEnv* env, jobject obj, jint nativeClass,
4442    jint generation, jstring currentText, jint keyCode,
4443    jint keyValue, jboolean down, jboolean cap, jboolean fn, jboolean sym)
4444{
4445    WTF::String current = jstringToWtfString(env, currentText);
4446    reinterpret_cast<WebViewCore*>(nativeClass)->passToJs(generation, current,
4447        PlatformKeyboardEvent(keyCode, keyValue, 0, down, cap, fn, sym));
4448}
4449
4450static void ScrollFocusedTextInput(JNIEnv* env, jobject obj, jint nativeClass,
4451        jfloat xPercent, jint y, jobject contentBounds)
4452{
4453    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4454    IntRect bounds = viewImpl->scrollFocusedTextInput(xPercent, y);
4455    if (contentBounds)
4456        GraphicsJNI::irect_to_jrect(bounds, env, contentBounds);
4457}
4458
4459static void SetFocusControllerActive(JNIEnv* env, jobject obj, jint nativeClass,
4460        jboolean active)
4461{
4462    ALOGV("webviewcore::nativeSetFocusControllerActive()\n");
4463    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4464    ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSetFocusControllerActive");
4465    viewImpl->setFocusControllerActive(active);
4466}
4467
4468static void SaveDocumentState(JNIEnv* env, jobject obj, jint nativeClass)
4469{
4470    ALOGV("webviewcore::nativeSaveDocumentState()\n");
4471    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4472    ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSaveDocumentState");
4473    viewImpl->saveDocumentState(viewImpl->focusedFrame());
4474}
4475
4476void WebViewCore::addVisitedLink(const UChar* string, int length)
4477{
4478    if (m_groupForVisitedLinks)
4479        m_groupForVisitedLinks->addVisitedLink(string, length);
4480}
4481
4482static void NotifyAnimationStarted(JNIEnv* env, jobject obj, jint nativeClass)
4483{
4484    WebViewCore* viewImpl = (WebViewCore*) nativeClass;
4485    viewImpl->notifyAnimationStarted();
4486}
4487
4488static jint RecordContent(JNIEnv* env, jobject obj, jint nativeClass,
4489        jobject region, jobject pt)
4490{
4491    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4492    SkRegion* nativeRegion = GraphicsJNI::getNativeRegion(env, region);
4493    SkIPoint nativePt;
4494    BaseLayerAndroid* result = viewImpl->recordContent(nativeRegion, &nativePt);
4495    GraphicsJNI::ipoint_to_jpoint(nativePt, env, pt);
4496    return reinterpret_cast<jint>(result);
4497}
4498
4499static void SplitContent(JNIEnv* env, jobject obj, jint nativeClass,
4500        jint content)
4501{
4502    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4503    viewImpl->splitContent(reinterpret_cast<PictureSet*>(content));
4504}
4505
4506static void SendListBoxChoice(JNIEnv* env, jobject obj, jint nativeClass,
4507        jint choice)
4508{
4509    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4510    ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoice");
4511    viewImpl->popupReply(choice);
4512}
4513
4514// Set aside a predetermined amount of space in which to place the listbox
4515// choices, to avoid unnecessary allocations.
4516// The size here is arbitrary.  We want the size to be at least as great as the
4517// number of items in the average multiple-select listbox.
4518#define PREPARED_LISTBOX_STORAGE 10
4519
4520static void SendListBoxChoices(JNIEnv* env, jobject obj, jint nativeClass,
4521        jbooleanArray jArray, jint size)
4522{
4523    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4524    ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoices");
4525    jboolean* ptrArray = env->GetBooleanArrayElements(jArray, 0);
4526    SkAutoSTMalloc<PREPARED_LISTBOX_STORAGE, int> storage(size);
4527    int* array = storage.get();
4528    int count = 0;
4529    for (int i = 0; i < size; i++) {
4530        if (ptrArray[i]) {
4531            array[count++] = i;
4532        }
4533    }
4534    env->ReleaseBooleanArrayElements(jArray, ptrArray, JNI_ABORT);
4535    viewImpl->popupReply(array, count);
4536}
4537
4538// TODO: Move this to WebView.cpp since it is only needed there
4539static jstring FindAddress(JNIEnv* env, jobject obj, jstring addr,
4540        jboolean caseInsensitive)
4541{
4542    if (!addr)
4543        return 0;
4544    int length = env->GetStringLength(addr);
4545    if (!length)
4546        return 0;
4547    const jchar* addrChars = env->GetStringChars(addr, 0);
4548    size_t start, end;
4549    AddressDetector detector;
4550    bool success = detector.FindContent(addrChars, addrChars + length, &start, &end);
4551    jstring ret = 0;
4552    if (success)
4553        ret = env->NewString(addrChars + start, end - start);
4554    env->ReleaseStringChars(addr, addrChars);
4555    return ret;
4556}
4557
4558static jboolean HandleTouchEvent(JNIEnv* env, jobject obj, jint nativeClass,
4559        jint action, jintArray idArray, jintArray xArray, jintArray yArray,
4560        jint count, jint actionIndex, jint metaState)
4561{
4562    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4563    ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4564    jint* ptrIdArray = env->GetIntArrayElements(idArray, 0);
4565    jint* ptrXArray = env->GetIntArrayElements(xArray, 0);
4566    jint* ptrYArray = env->GetIntArrayElements(yArray, 0);
4567    Vector<int> ids(count);
4568    Vector<IntPoint> points(count);
4569    for (int c = 0; c < count; c++) {
4570        ids[c] = ptrIdArray[c];
4571        points[c].setX(ptrXArray[c]);
4572        points[c].setY(ptrYArray[c]);
4573    }
4574    env->ReleaseIntArrayElements(idArray, ptrIdArray, JNI_ABORT);
4575    env->ReleaseIntArrayElements(xArray, ptrXArray, JNI_ABORT);
4576    env->ReleaseIntArrayElements(yArray, ptrYArray, JNI_ABORT);
4577
4578    return viewImpl->handleTouchEvent(action, ids, points, actionIndex, metaState);
4579}
4580
4581static bool MouseClick(JNIEnv* env, jobject obj, jint nativeClass)
4582{
4583    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4584    return viewImpl->performMouseClick();
4585}
4586
4587static jstring RetrieveHref(JNIEnv* env, jobject obj, jint nativeClass,
4588        jint x, jint y)
4589{
4590    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4591    ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4592    WTF::String result = viewImpl->retrieveHref(x, y);
4593    if (!result.isEmpty())
4594        return wtfStringToJstring(env, result);
4595    return 0;
4596}
4597
4598static jstring RetrieveAnchorText(JNIEnv* env, jobject obj, jint nativeClass,
4599        jint x, jint y)
4600{
4601    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4602    ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4603    WTF::String result = viewImpl->retrieveAnchorText(x, y);
4604    if (!result.isEmpty())
4605        return wtfStringToJstring(env, result);
4606    return 0;
4607}
4608
4609static jstring RetrieveImageSource(JNIEnv* env, jobject obj, jint nativeClass,
4610        jint x, jint y)
4611{
4612    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4613    WTF::String result = viewImpl->retrieveImageSource(x, y);
4614    return !result.isEmpty() ? wtfStringToJstring(env, result) : 0;
4615}
4616
4617static void MoveMouse(JNIEnv* env, jobject obj, jint nativeClass, jint x, jint y)
4618{
4619    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4620    ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4621    viewImpl->moveMouse(x, y);
4622}
4623
4624static jint GetContentMinPrefWidth(JNIEnv* env, jobject obj, jint nativeClass)
4625{
4626    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4627    ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4628
4629    WebCore::Frame* frame = viewImpl->mainFrame();
4630    if (frame) {
4631        WebCore::Document* document = frame->document();
4632        if (document) {
4633            WebCore::RenderObject* renderer = document->renderer();
4634            if (renderer && renderer->isRenderView()) {
4635                return renderer->minPreferredLogicalWidth();
4636            }
4637        }
4638    }
4639    return 0;
4640}
4641
4642static void SetViewportSettingsFromNative(JNIEnv* env, jobject obj,
4643        jint nativeClass)
4644{
4645    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4646    ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4647
4648    WebCore::Settings* s = viewImpl->mainFrame()->page()->settings();
4649    if (!s)
4650        return;
4651
4652#ifdef ANDROID_META_SUPPORT
4653    env->SetIntField(obj, gWebViewCoreFields.m_viewportWidth, s->viewportWidth());
4654    env->SetIntField(obj, gWebViewCoreFields.m_viewportHeight, s->viewportHeight());
4655    env->SetIntField(obj, gWebViewCoreFields.m_viewportInitialScale, s->viewportInitialScale());
4656    env->SetIntField(obj, gWebViewCoreFields.m_viewportMinimumScale, s->viewportMinimumScale());
4657    env->SetIntField(obj, gWebViewCoreFields.m_viewportMaximumScale, s->viewportMaximumScale());
4658    env->SetBooleanField(obj, gWebViewCoreFields.m_viewportUserScalable, s->viewportUserScalable());
4659    env->SetIntField(obj, gWebViewCoreFields.m_viewportDensityDpi, s->viewportTargetDensityDpi());
4660#endif
4661}
4662
4663static void SetBackgroundColor(JNIEnv* env, jobject obj, jint nativeClass,
4664        jint color)
4665{
4666    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4667    ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4668
4669    viewImpl->setBackgroundColor((SkColor) color);
4670}
4671
4672static void DumpDomTree(JNIEnv* env, jobject obj, jint nativeClass,
4673        jboolean useFile)
4674{
4675    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4676    ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4677
4678    viewImpl->dumpDomTree(useFile);
4679}
4680
4681static void DumpRenderTree(JNIEnv* env, jobject obj, jint nativeClass,
4682        jboolean useFile)
4683{
4684    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4685    ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4686
4687    viewImpl->dumpRenderTree(useFile);
4688}
4689
4690static void SetJsFlags(JNIEnv* env, jobject obj, jint nativeClass, jstring flags)
4691{
4692    WTF::String flagsString = jstringToWtfString(env, flags);
4693    WTF::CString utf8String = flagsString.utf8();
4694    WebCore::ScriptController::setFlags(utf8String.data(), utf8String.length());
4695}
4696
4697
4698// Called from the Java side to set a new quota for the origin or new appcache
4699// max size in response to a notification that the original quota was exceeded or
4700// that the appcache has reached its maximum size.
4701static void SetNewStorageLimit(JNIEnv* env, jobject obj, jint nativeClass,
4702        jlong quota)
4703{
4704#if ENABLE(DATABASE) || ENABLE(OFFLINE_WEB_APPLICATIONS)
4705    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4706    Frame* frame = viewImpl->mainFrame();
4707
4708    // The main thread is blocked awaiting this response, so now we can wake it
4709    // up.
4710    ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(frame->page()->chrome()->client());
4711    chromeC->wakeUpMainThreadWithNewQuota(quota);
4712#endif
4713}
4714
4715// Called from Java to provide a Geolocation permission state for the specified origin.
4716static void GeolocationPermissionsProvide(JNIEnv* env, jobject obj,
4717        jint nativeClass, jstring origin, jboolean allow, jboolean remember)
4718{
4719    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4720    Frame* frame = viewImpl->mainFrame();
4721
4722    ChromeClientAndroid* chromeClient = static_cast<ChromeClientAndroid*>(frame->page()->chrome()->client());
4723    chromeClient->provideGeolocationPermissions(jstringToWtfString(env, origin), allow, remember);
4724}
4725
4726static void RegisterURLSchemeAsLocal(JNIEnv* env, jobject obj, jint nativeClass,
4727        jstring scheme)
4728{
4729    WebCore::SchemeRegistry::registerURLSchemeAsLocal(jstringToWtfString(env, scheme));
4730}
4731
4732static bool FocusBoundsChanged(JNIEnv* env, jobject obj, jint nativeClass)
4733{
4734    return reinterpret_cast<WebViewCore*>(nativeClass)->focusBoundsChanged();
4735}
4736
4737static void SetIsPaused(JNIEnv* env, jobject obj, jint nativeClass,
4738        jboolean isPaused)
4739{
4740    // tell the webcore thread to stop thinking while we do other work
4741    // (selection and scrolling). This has nothing to do with the lifecycle
4742    // pause and resume.
4743    reinterpret_cast<WebViewCore*>(nativeClass)->setIsPaused(isPaused);
4744}
4745
4746static void Pause(JNIEnv* env, jobject obj, jint nativeClass)
4747{
4748    // This is called for the foreground tab when the browser is put to the
4749    // background (and also for any tab when it is put to the background of the
4750    // browser). The browser can only be killed by the system when it is in the
4751    // background, so saving the Geolocation permission state now ensures that
4752    // is maintained when the browser is killed.
4753    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4754    ChromeClient* chromeClient = viewImpl->mainFrame()->page()->chrome()->client();
4755    ChromeClientAndroid* chromeClientAndroid = static_cast<ChromeClientAndroid*>(chromeClient);
4756    chromeClientAndroid->storeGeolocationPermissions();
4757
4758    Frame* mainFrame = viewImpl->mainFrame();
4759    for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext()) {
4760        Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation();
4761        if (geolocation)
4762            geolocation->suspend();
4763    }
4764
4765    viewImpl->deviceMotionAndOrientationManager()->maybeSuspendClients();
4766
4767    ANPEvent event;
4768    SkANP::InitEvent(&event, kLifecycle_ANPEventType);
4769    event.data.lifecycle.action = kPause_ANPLifecycleAction;
4770    viewImpl->sendPluginEvent(event);
4771
4772    viewImpl->setIsPaused(true);
4773}
4774
4775static void Resume(JNIEnv* env, jobject obj, jint nativeClass)
4776{
4777    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4778    Frame* mainFrame = viewImpl->mainFrame();
4779    for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext()) {
4780        Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation();
4781        if (geolocation)
4782            geolocation->resume();
4783    }
4784
4785    viewImpl->deviceMotionAndOrientationManager()->maybeResumeClients();
4786
4787    ANPEvent event;
4788    SkANP::InitEvent(&event, kLifecycle_ANPEventType);
4789    event.data.lifecycle.action = kResume_ANPLifecycleAction;
4790    viewImpl->sendPluginEvent(event);
4791
4792    viewImpl->setIsPaused(false);
4793}
4794
4795static void FreeMemory(JNIEnv* env, jobject obj, jint nativeClass)
4796{
4797    ANPEvent event;
4798    SkANP::InitEvent(&event, kLifecycle_ANPEventType);
4799    event.data.lifecycle.action = kFreeMemory_ANPLifecycleAction;
4800    reinterpret_cast<WebViewCore*>(nativeClass)->sendPluginEvent(event);
4801}
4802
4803static void ProvideVisitedHistory(JNIEnv* env, jobject obj, jint nativeClass,
4804        jobject hist)
4805{
4806    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4807    ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4808
4809    jobjectArray array = static_cast<jobjectArray>(hist);
4810
4811    jsize len = env->GetArrayLength(array);
4812    for (jsize i = 0; i < len; i++) {
4813        jstring item = static_cast<jstring>(env->GetObjectArrayElement(array, i));
4814        const UChar* str = static_cast<const UChar*>(env->GetStringChars(item, 0));
4815        jsize len = env->GetStringLength(item);
4816        viewImpl->addVisitedLink(str, len);
4817        env->ReleaseStringChars(item, str);
4818        env->DeleteLocalRef(item);
4819    }
4820}
4821
4822static void PluginSurfaceReady(JNIEnv* env, jobject obj, jint nativeClass)
4823{
4824    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4825    if (viewImpl)
4826        viewImpl->sendPluginSurfaceReady();
4827}
4828
4829// Notification from the UI thread that the plugin's full-screen surface has been discarded
4830static void FullScreenPluginHidden(JNIEnv* env, jobject obj, jint nativeClass,
4831        jint npp)
4832{
4833    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4834    PluginWidgetAndroid* plugin = viewImpl->getPluginWidget((NPP)npp);
4835    if (plugin)
4836        plugin->exitFullScreen(false);
4837}
4838
4839static WebCore::IntRect jrect_to_webrect(JNIEnv* env, jobject obj)
4840{
4841    int L, T, R, B;
4842    GraphicsJNI::get_jrect(env, obj, &L, &T, &R, &B);
4843    return WebCore::IntRect(L, T, R - L, B - T);
4844}
4845
4846static jobject HitTest(JNIEnv* env, jobject obj, jint nativeClass, jint x,
4847                       jint y, jint slop, jboolean doMoveMouse)
4848{
4849    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4850    if (!viewImpl)
4851        return 0;
4852    AndroidHitTestResult result = viewImpl->hitTestAtPoint(x, y, slop, doMoveMouse);
4853    return result.createJavaObject(env);
4854}
4855
4856static void AutoFillForm(JNIEnv* env, jobject obj, jint nativeClass,
4857        jint queryId)
4858{
4859#if ENABLE(WEB_AUTOFILL)
4860    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4861    if (!viewImpl)
4862        return;
4863
4864    WebCore::Frame* frame = viewImpl->mainFrame();
4865    if (frame) {
4866        EditorClientAndroid* editorC = static_cast<EditorClientAndroid*>(frame->page()->editorClient());
4867        WebAutofill* autoFill = editorC->getAutofill();
4868        autoFill->fillFormFields(queryId);
4869    }
4870#endif
4871}
4872
4873static void CloseIdleConnections(JNIEnv* env, jobject obj, jint nativeClass)
4874{
4875    WebCache::get(true)->closeIdleConnections();
4876    WebCache::get(false)->closeIdleConnections();
4877}
4878
4879static void nativeCertTrustChanged(JNIEnv *env, jobject obj)
4880{
4881#if USE(CHROME_NETWORK_STACK)
4882    WebCache::get(true)->certTrustChanged();
4883    WebCache::get(false)->certTrustChanged();
4884#endif
4885}
4886
4887static void ScrollRenderLayer(JNIEnv* env, jobject obj, jint nativeClass,
4888        jint layer, jobject jRect)
4889{
4890    SkRect rect;
4891    GraphicsJNI::jrect_to_rect(env, jRect, &rect);
4892    reinterpret_cast<WebViewCore*>(nativeClass)->scrollRenderLayer(layer, rect);
4893}
4894
4895static void DeleteText(JNIEnv* env, jobject obj, jint nativeClass,
4896        jint startX, jint startY, jint endX, jint endY)
4897{
4898    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4899    viewImpl->deleteText(startX, startY, endX, endY);
4900}
4901
4902static void InsertText(JNIEnv* env, jobject obj, jint nativeClass,
4903        jstring text)
4904{
4905    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4906    WTF::String wtfText = jstringToWtfString(env, text);
4907    viewImpl->insertText(wtfText);
4908}
4909
4910static jobject GetText(JNIEnv* env, jobject obj, jint nativeClass,
4911        jint startX, jint startY, jint endX, jint endY)
4912{
4913    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4914    WTF::String text = viewImpl->getText(startX, startY, endX, endY);
4915    return text.isEmpty() ? 0 : wtfStringToJstring(env, text);
4916}
4917
4918static void SelectText(JNIEnv* env, jobject obj, jint nativeClass,
4919        jint startX, jint startY, jint endX, jint endY)
4920{
4921    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4922    viewImpl->selectText(startX, startY, endX, endY);
4923}
4924
4925static void ClearSelection(JNIEnv* env, jobject obj, jint nativeClass)
4926{
4927    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4928    viewImpl->focusedFrame()->selection()->clear();
4929}
4930
4931static bool SelectWordAt(JNIEnv* env, jobject obj, jint nativeClass, jint x, jint y)
4932{
4933    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4934    return viewImpl->selectWordAt(x, y);
4935}
4936
4937static void SelectAll(JNIEnv* env, jobject obj, jint nativeClass)
4938{
4939    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4940    viewImpl->focusedFrame()->selection()->selectAll();
4941}
4942
4943static int FindAll(JNIEnv* env, jobject obj, jint nativeClass,
4944        jstring text)
4945{
4946    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4947    WTF::String wtfText = jstringToWtfString(env, text);
4948    return viewImpl->findTextOnPage(wtfText);
4949}
4950
4951static int FindNext(JNIEnv* env, jobject obj, jint nativeClass,
4952        jboolean forward)
4953{
4954    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4955    return viewImpl->findNextOnPage(forward);
4956}
4957
4958// ----------------------------------------------------------------------------
4959
4960/*
4961 * JNI registration.
4962 */
4963static JNINativeMethod gJavaWebViewCoreMethods[] = {
4964    { "nativeClearContent", "(I)V",
4965            (void*) ClearContent },
4966    { "nativeFocusBoundsChanged", "(I)Z",
4967        (void*) FocusBoundsChanged } ,
4968    { "nativeKey", "(IIIIZZZZ)Z",
4969        (void*) Key },
4970    { "nativeContentInvalidateAll", "(I)V",
4971        (void*) ContentInvalidateAll },
4972    { "nativeSendListBoxChoices", "(I[ZI)V",
4973        (void*) SendListBoxChoices },
4974    { "nativeSendListBoxChoice", "(II)V",
4975        (void*) SendListBoxChoice },
4976    { "nativeSetSize", "(IIIIFIIIIZ)V",
4977        (void*) SetSize },
4978    { "nativeSetScrollOffset", "(IZII)V",
4979        (void*) SetScrollOffset },
4980    { "nativeSetGlobalBounds", "(IIIII)V",
4981        (void*) SetGlobalBounds },
4982    { "nativeSetSelection", "(III)V",
4983        (void*) SetSelection } ,
4984    { "nativeModifySelection", "(III)Ljava/lang/String;",
4985        (void*) ModifySelection },
4986    { "nativeDeleteSelection", "(IIII)V",
4987        (void*) DeleteSelection } ,
4988    { "nativeReplaceTextfieldText", "(IIILjava/lang/String;III)V",
4989        (void*) ReplaceTextfieldText } ,
4990    { "nativeMoveMouse", "(III)V",
4991        (void*) MoveMouse },
4992    { "passToJs", "(IILjava/lang/String;IIZZZZ)V",
4993        (void*) PassToJs },
4994    { "nativeScrollFocusedTextInput", "(IFILandroid/graphics/Rect;)V",
4995        (void*) ScrollFocusedTextInput },
4996    { "nativeSetFocusControllerActive", "(IZ)V",
4997        (void*) SetFocusControllerActive },
4998    { "nativeSaveDocumentState", "(I)V",
4999        (void*) SaveDocumentState },
5000    { "nativeFindAddress", "(Ljava/lang/String;Z)Ljava/lang/String;",
5001        (void*) FindAddress },
5002    { "nativeHandleTouchEvent", "(II[I[I[IIII)Z",
5003        (void*) HandleTouchEvent },
5004    { "nativeMouseClick", "(I)Z",
5005        (void*) MouseClick },
5006    { "nativeRetrieveHref", "(III)Ljava/lang/String;",
5007        (void*) RetrieveHref },
5008    { "nativeRetrieveAnchorText", "(III)Ljava/lang/String;",
5009        (void*) RetrieveAnchorText },
5010    { "nativeRetrieveImageSource", "(III)Ljava/lang/String;",
5011        (void*) RetrieveImageSource },
5012    { "nativeGetContentMinPrefWidth", "(I)I",
5013        (void*) GetContentMinPrefWidth },
5014    { "nativeNotifyAnimationStarted", "(I)V",
5015        (void*) NotifyAnimationStarted },
5016    { "nativeRecordContent", "(ILandroid/graphics/Region;Landroid/graphics/Point;)I",
5017        (void*) RecordContent },
5018    { "setViewportSettingsFromNative", "(I)V",
5019        (void*) SetViewportSettingsFromNative },
5020    { "nativeSplitContent", "(II)V",
5021        (void*) SplitContent },
5022    { "nativeSetBackgroundColor", "(II)V",
5023        (void*) SetBackgroundColor },
5024    { "nativeRegisterURLSchemeAsLocal", "(ILjava/lang/String;)V",
5025        (void*) RegisterURLSchemeAsLocal },
5026    { "nativeDumpDomTree", "(IZ)V",
5027        (void*) DumpDomTree },
5028    { "nativeDumpRenderTree", "(IZ)V",
5029        (void*) DumpRenderTree },
5030    { "nativeSetNewStorageLimit", "(IJ)V",
5031        (void*) SetNewStorageLimit },
5032    { "nativeGeolocationPermissionsProvide", "(ILjava/lang/String;ZZ)V",
5033        (void*) GeolocationPermissionsProvide },
5034    { "nativeSetIsPaused", "(IZ)V", (void*) SetIsPaused },
5035    { "nativePause", "(I)V", (void*) Pause },
5036    { "nativeResume", "(I)V", (void*) Resume },
5037    { "nativeFreeMemory", "(I)V", (void*) FreeMemory },
5038    { "nativeSetJsFlags", "(ILjava/lang/String;)V", (void*) SetJsFlags },
5039    { "nativeRequestLabel", "(III)Ljava/lang/String;",
5040        (void*) RequestLabel },
5041    { "nativeRevealSelection", "(I)V", (void*) RevealSelection },
5042    { "nativeProvideVisitedHistory", "(I[Ljava/lang/String;)V",
5043        (void*) ProvideVisitedHistory },
5044    { "nativeFullScreenPluginHidden", "(II)V",
5045        (void*) FullScreenPluginHidden },
5046    { "nativePluginSurfaceReady", "(I)V",
5047        (void*) PluginSurfaceReady },
5048    { "nativeHitTest", "(IIIIZ)Landroid/webkit/WebViewCore$WebKitHitTest;",
5049        (void*) HitTest },
5050    { "nativeAutoFillForm", "(II)V",
5051        (void*) AutoFillForm },
5052    { "nativeScrollLayer", "(IILandroid/graphics/Rect;)V",
5053        (void*) ScrollRenderLayer },
5054    { "nativeCloseIdleConnections", "(I)V",
5055        (void*) CloseIdleConnections },
5056    { "nativeDeleteText", "(IIIII)V",
5057        (void*) DeleteText },
5058    { "nativeInsertText", "(ILjava/lang/String;)V",
5059        (void*) InsertText },
5060    { "nativeGetText", "(IIIII)Ljava/lang/String;",
5061        (void*) GetText },
5062    { "nativeSelectText", "(IIIII)V",
5063        (void*) SelectText },
5064    { "nativeClearTextSelection", "(I)V",
5065        (void*) ClearSelection },
5066    { "nativeSelectWordAt", "(III)Z",
5067        (void*) SelectWordAt },
5068    { "nativeSelectAll", "(I)V",
5069        (void*) SelectAll },
5070    { "nativeCertTrustChanged","()V",
5071        (void*) nativeCertTrustChanged },
5072    { "nativeFindAll", "(ILjava/lang/String;)I",
5073        (void*) FindAll },
5074    { "nativeFindNext", "(IZ)I",
5075        (void*) FindNext },
5076};
5077
5078int registerWebViewCore(JNIEnv* env)
5079{
5080    jclass widget = env->FindClass("android/webkit/WebViewCore");
5081    ALOG_ASSERT(widget,
5082            "Unable to find class android/webkit/WebViewCore");
5083    gWebViewCoreFields.m_nativeClass = env->GetFieldID(widget, "mNativeClass",
5084            "I");
5085    ALOG_ASSERT(gWebViewCoreFields.m_nativeClass,
5086            "Unable to find android/webkit/WebViewCore.mNativeClass");
5087    gWebViewCoreFields.m_viewportWidth = env->GetFieldID(widget,
5088            "mViewportWidth", "I");
5089    ALOG_ASSERT(gWebViewCoreFields.m_viewportWidth,
5090            "Unable to find android/webkit/WebViewCore.mViewportWidth");
5091    gWebViewCoreFields.m_viewportHeight = env->GetFieldID(widget,
5092            "mViewportHeight", "I");
5093    ALOG_ASSERT(gWebViewCoreFields.m_viewportHeight,
5094            "Unable to find android/webkit/WebViewCore.mViewportHeight");
5095    gWebViewCoreFields.m_viewportInitialScale = env->GetFieldID(widget,
5096            "mViewportInitialScale", "I");
5097    ALOG_ASSERT(gWebViewCoreFields.m_viewportInitialScale,
5098            "Unable to find android/webkit/WebViewCore.mViewportInitialScale");
5099    gWebViewCoreFields.m_viewportMinimumScale = env->GetFieldID(widget,
5100            "mViewportMinimumScale", "I");
5101    ALOG_ASSERT(gWebViewCoreFields.m_viewportMinimumScale,
5102            "Unable to find android/webkit/WebViewCore.mViewportMinimumScale");
5103    gWebViewCoreFields.m_viewportMaximumScale = env->GetFieldID(widget,
5104            "mViewportMaximumScale", "I");
5105    ALOG_ASSERT(gWebViewCoreFields.m_viewportMaximumScale,
5106            "Unable to find android/webkit/WebViewCore.mViewportMaximumScale");
5107    gWebViewCoreFields.m_viewportUserScalable = env->GetFieldID(widget,
5108            "mViewportUserScalable", "Z");
5109    ALOG_ASSERT(gWebViewCoreFields.m_viewportUserScalable,
5110            "Unable to find android/webkit/WebViewCore.mViewportUserScalable");
5111    gWebViewCoreFields.m_viewportDensityDpi = env->GetFieldID(widget,
5112            "mViewportDensityDpi", "I");
5113    ALOG_ASSERT(gWebViewCoreFields.m_viewportDensityDpi,
5114            "Unable to find android/webkit/WebViewCore.mViewportDensityDpi");
5115    gWebViewCoreFields.m_drawIsPaused = env->GetFieldID(widget,
5116            "mDrawIsPaused", "Z");
5117    ALOG_ASSERT(gWebViewCoreFields.m_drawIsPaused,
5118            "Unable to find android/webkit/WebViewCore.mDrawIsPaused");
5119    gWebViewCoreFields.m_lowMemoryUsageMb = env->GetFieldID(widget, "mLowMemoryUsageThresholdMb", "I");
5120    gWebViewCoreFields.m_highMemoryUsageMb = env->GetFieldID(widget, "mHighMemoryUsageThresholdMb", "I");
5121    gWebViewCoreFields.m_highUsageDeltaMb = env->GetFieldID(widget, "mHighUsageDeltaMb", "I");
5122
5123    gWebViewCoreStaticMethods.m_isSupportedMediaMimeType =
5124        env->GetStaticMethodID(widget, "isSupportedMediaMimeType", "(Ljava/lang/String;)Z");
5125    LOG_FATAL_IF(!gWebViewCoreStaticMethods.m_isSupportedMediaMimeType,
5126        "Could not find static method isSupportedMediaMimeType from WebViewCore");
5127
5128    env->DeleteLocalRef(widget);
5129
5130    return jniRegisterNativeMethods(env, "android/webkit/WebViewCore",
5131            gJavaWebViewCoreMethods, NELEM(gJavaWebViewCoreMethods));
5132}
5133
5134} /* namespace android */
5135