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