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