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