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