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