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