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